Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Source to Binary - journey of V8 javascript engine

Source to Binary - journey of V8 javascript engine

V8 javascript engineについて
パーサー、AST、Ignition/TurboFan、最適化周り等

More Decks by Taketoshi Aono(青野健利 a.k.a brn)

Other Decks in Programming

Transcript

  1. Name @brn (ꫬꅿ⨳ⵃ) Occupation ؿٗٝزؒٝسؒٝآص،٥ط؎ذ؍ـؒٝآص، Company Cyberagent ،سذؙأةآؔ AI Messenger

    Blog http://abcdef.gets.b6n.ch/ Twitter https://twitter.com/brn227 GitHub https://github.com/brn
  2. Agenda •  What is V8? •  Execution flow of V8

    •  Parsing •  Abstract Syntax Tree •  Ignition – BytecodeInterpreter •  CodeStubAssembler •  Builtins / Runtime •  Optimization / Hidden Class / Inline Caching •  TurboFan / Deoptimization
  3. function x(a, b) { return a + b; } FUNCTION(X)

    parameter-count: 2 start-position: 1 end-position: 34 use-super-property: false …
  4. constructor() {! super();! return expr! }! ! constructor() {! super();!

    var tmp;! return (temp = expr) === undefined?! this: temp;! }!
  5. {! var temp;! for (temp of e) {! const x

    = temp;! ...! }! let x! }!
  6. const Bytecodes = [0,1,2,3,4,5];! let index = 0;! function dispatch(next)

    {BytecodeHandlers[next] ();}! const BytecodeHandlers = [! () => {...; dispatch(Bytecodes[index++])},! () => {...; dispatch(Bytecodes[index++])},! () => {...; dispatch(Bytecodes[index++])},! () => {...; dispatch(Bytecodes[index++])},! () => {...; dispatch(Bytecodes[index++])},! () => {...; dispatch(Bytecodes[index++])},! ]! dispatch(Bytecodes[index++]);!
  7. IGNITION_HANDLER(JumpIfToBooleanFalse, InterpreterAssembler) {! Node* value = GetAccumulator();! // Accumulatorの値を取得! Node*

    relative_jump = BytecodeOperandUImmWord(0);! // 引数のoperandを取得! Label if_true(this), if_false(this);! BranchIfToBooleanIsTrue(value, &if_true, &if_false);! // valueがtrueならif_true、falseならif_false! Bind(&if_true);! Dispatch();! Bind(&if_false);! // operandのbytecodeまでjump! Jump(relative_jump);! }!
  8. Dispatch Table 00 01 02 04 08 0f 10 10

    Node Node Node Operator Operator IGNITION_HANDLER Stub (Mahine Code Fragment) グラフからコードを生成 生成したコードを、 DispatchTableの対応する バイトコードのインデックスへ 登録 Assemble
  9. void Assembler::jmp(! Handle<Code> target,! RelocInfo::Mode rmode! ) {! EnsureSpace ensure_space(this);!

    // 1110 1001 #32-bit disp.! // ここでメモリ上にアセンブラを書き出す! emit(0xE9);! emit_code_target(target, rmode);! }!
  10. •  Hidden Class const point1 = {x: 0, y: 0};!

    const point2 = {x: 0, y: 0};! Map FixedArray [ {x: {offset: 0}}, {y: {offset: 1}} ]
  11. const pointA = {x: 0, y: 0};! const pointB =

    {x: 0, y: 0};! // pointA.Map === pointB.Map;! ! const pointC = {y: 0, x: 0};! // pointA.Map !== pointC.Map! ! const point3D = {x: 0, y: 0, z: 0};! // point3D.Map !== pointA.Map!
  12. class PointA {! constructor() {! this.x = 0;! this.y =

    0;! }! }! const pointAInstance = new PointA();! ! class PointB {! constructor() {! this.y = 0;! this.x = 0;! }! }! const pointBInstance = new PointB();! // PointAInstance.Map !== PointBInstance.Map!
  13. function Point(x, y) { this.x = x; this.y = y;

    } Map FixedArray [ {x: {offset: 0}}, {y: {offset: 1}}, ] var x = new Point(1, 1); x.z = 1; Map FixedArray [ {z: {offset: 2}} ] transition {z: transi>on(address)}
  14. function x(obj) {! return obj.x + obj.y;! }! ! x({x:

    0, y: 0});! x({x: 1, y: 1});! x({x: 2, y: 2});!
  15. x({x: 0, y: 0});! // uninitialized! x({x: 1, y: 1});!

    // stub_call! x({x: 2, y: 2});! // found ic! x({x: 1, y: 1, z: 1})! // load ic miss! x({x: 1, y: 1, foo() {}});! // load ic miss!
  16. function id(v) {return v;}! function x(v) {! for (var i

    = 0; i < 10000; i++) {! id(v + i);! }! }! x(1);!
  17. 0x1bb9e5e2935e LdaSmi.Wide [1000] 0x1bb9e5e2937e JumpLoop [32], [0] (0x1bb9e5e2935e @ 4)

    Bytecode length = 100 if (budget –= 100 < 0) { OptimizeAndOSR(); }
  18. CompilationQueue CompilationJob CompilationJob CompilationJob Hot Function Bytecode Called Hot Function(Queued)

    Bytecode Called Hot Function(Queued) Bytecode Called Optimized Function Assembly Called
  19. const x = x => x;! const y = ()

    => {! for (let i = 0; i < 1000; i++) {! x(i);! }! ! for (let i = 0; i < 1000; i++) {! x(i);! }! };! y();!
  20. 0x13b567fa924e LdaSmi.Wide [1000] 0x13b567fa9268 JumpLoop [26], [0] (0x13b567fa924e @ 4)

    Bytecode length 26 budget –= 26 0x13b567fa926e LdaSmi.Wide [1000] 0x13b567fa9288 JumpLoop [26], [0] (0x13b567fa926e @ 36) Bytecode length 26 budget –= 26 0x13b567fa928c Return budget –= all_bytecode_length
  21. #22:Branch[None](#21:SpeculativeNumberLessThan, #9:Loop) #28:IfTrue(#22:Branch) #30:JSStackCheck(#11:Phi, #32:FrameState, #21:SpeculativeNumberLessThan, #28:IfTrue) #33:JSLoadGlobal[0x2f3e1c607881 <String[1]: a>,

    1] (#11:Phi, #34:FrameState, #30:JSStackCheck, #30:JSStackCheck) #2:HeapConstant[0x2f3e1c6022e1 <undefined>]() #39:FrameState #36:StateValues[sparse:^^](#12:Phi, #33:JSLoadGlobal) #37:FrameState#35:Checkpoint(#37:FrameState, #33:JSLoadGlobal, #33:JSLoadGlobal) #38:JSCall[2, 15256, NULL_OR_UNDEFINED] (#33:JSLoadGlobal, #2:HeapConstant, #11:Phi, #39:FrameState, #35:Checkpoint, #33:JSLoadGlobal) #9:Loop(#0:Start, #38:JSCall)
  22. const id = x => x;! const test = obj

    => {! for (let i = 0; i < 100000; i++) {! id(obj.x);! }! };! ! test({x: 1});! test({x: 1, y: 1});!
  23. 0x451eb30464c 8c 48b9f1c7d830391e0000 REX.W movq rcx, 0x1e3930d8c7f1 0x451eb304656 96 483bca

    REX.W cmpq rcx,rdx 0x451eb304659 99 0f8591000000 jnz 0x451eb3046f0 ;; Check Map!! ... 0x451eb3046f0 130 e81ff9cfff call 0x451eb004014 ;; deoptimization bailout 2