Contenu connexe Similaire à V8 by example: A journey through the compilation pipeline by Ujjwas Sharma at FrontCon 2019 (20) V8 by example: A journey through the compilation pipeline by Ujjwas Sharma at FrontCon 20192. @ryzokuken
Ujjwal Sharma (@ryzokuken)
● Node.js – Core Collaborator
● Electron.js – Maintainer
● Contribute to the JS/Node.js ecosystem
○ V8
○ TC39
○ libuv
○ …
● Student
● Google Summer of Code
● Speaker
2
46. @ryzokuken@ryzokuken46
[generating bytecode for function: add]
--- AST ---
FUNC at 12
. KIND 0
. SUSPEND COUNT 0
. NAME "add"
. PARAMS
. . VAR (...) (mode = VAR) "x"
. . VAR (...) (mode = VAR) "y"
. RETURN at 22
. . ADD at 31
. . . VAR PROXY parameter[0] (...) (mode = VAR) "x"
. . . VAR PROXY parameter[1] (...) (mode = VAR) "y"
47. @ryzokuken@ryzokuken47
[generating bytecode for function: add]
--- AST ---
FUNC at 12
. KIND 0
. SUSPEND COUNT 0
. NAME "add"
. PARAMS
. . VAR (...) (mode = VAR) "x"
. . VAR (...) (mode = VAR) "y"
. RETURN at 22
. . ADD at 31
. . . VAR PROXY parameter[0] (...) (mode = VAR) "x"
. . . VAR PROXY parameter[1] (...) (mode = VAR) "y"
FUNC
48. @ryzokuken@ryzokuken48
[generating bytecode for function: add]
--- AST ---
FUNC at 12
. KIND 0
. SUSPEND COUNT 0
. NAME "add"
. PARAMS
. . VAR (...) (mode = VAR) "x"
. . VAR (...) (mode = VAR) "y"
. RETURN at 22
. . ADD at 31
. . . VAR PROXY parameter[0] (...) (mode = VAR) "x"
. . . VAR PROXY parameter[1] (...) (mode = VAR) "y"
FUNC
49. @ryzokuken@ryzokuken49
[generating bytecode for function: add]
--- AST ---
FUNC at 12
. KIND 0
. SUSPEND COUNT 0
. NAME "add"
. PARAMS
. . VAR (...) (mode = VAR) "x"
. . VAR (...) (mode = VAR) "y"
. RETURN at 22
. . ADD at 31
. . . VAR PROXY parameter[0] (...) (mode = VAR) "x"
. . . VAR PROXY parameter[1] (...) (mode = VAR) "y"
FUNC
NAME “add”
50. @ryzokuken@ryzokuken50
[generating bytecode for function: add]
--- AST ---
FUNC at 12
. KIND 0
. SUSPEND COUNT 0
. NAME "add"
. PARAMS
. . VAR (...) (mode = VAR) "x"
. . VAR (...) (mode = VAR) "y"
. RETURN at 22
. . ADD at 31
. . . VAR PROXY parameter[0] (...) (mode = VAR) "x"
. . . VAR PROXY parameter[1] (...) (mode = VAR) "y"
FUNC
NAME “add” PARAMS
51. @ryzokuken@ryzokuken51
[generating bytecode for function: add]
--- AST ---
FUNC at 12
. KIND 0
. SUSPEND COUNT 0
. NAME "add"
. PARAMS
. . VAR (...) (mode = VAR) "x"
. . VAR (...) (mode = VAR) "y"
. RETURN at 22
. . ADD at 31
. . . VAR PROXY parameter[0] (...) (mode = VAR) "x"
. . . VAR PROXY parameter[1] (...) (mode = VAR) "y"
FUNC
NAME “add” PARAMS
VAR “x”
52. @ryzokuken@ryzokuken52
[generating bytecode for function: add]
--- AST ---
FUNC at 12
. KIND 0
. SUSPEND COUNT 0
. NAME "add"
. PARAMS
. . VAR (...) (mode = VAR) "x"
. . VAR (...) (mode = VAR) "y"
. RETURN at 22
. . ADD at 31
. . . VAR PROXY parameter[0] (...) (mode = VAR) "x"
. . . VAR PROXY parameter[1] (...) (mode = VAR) "y"
FUNC
NAME “add” PARAMS
VAR “x” VAR “y”
53. @ryzokuken@ryzokuken53
[generating bytecode for function: add]
--- AST ---
FUNC at 12
. KIND 0
. SUSPEND COUNT 0
. NAME "add"
. PARAMS
. . VAR (...) (mode = VAR) "x"
. . VAR (...) (mode = VAR) "y"
. RETURN at 22
. . ADD at 31
. . . VAR PROXY parameter[0] (...) (mode = VAR) "x"
. . . VAR PROXY parameter[1] (...) (mode = VAR) "y"
FUNC
NAME “add” PARAMS RETURN
VAR “x” VAR “y”
54. @ryzokuken@ryzokuken54
[generating bytecode for function: add]
--- AST ---
FUNC at 12
. KIND 0
. SUSPEND COUNT 0
. NAME "add"
. PARAMS
. . VAR (...) (mode = VAR) "x"
. . VAR (...) (mode = VAR) "y"
. RETURN at 22
. . ADD at 31
. . . VAR PROXY parameter[0] (...) (mode = VAR) "x"
. . . VAR PROXY parameter[1] (...) (mode = VAR) "y"
FUNC
NAME “add” PARAMS RETURN
VAR “x” VAR “y” ADD
55. @ryzokuken@ryzokuken55
[generating bytecode for function: add]
--- AST ---
FUNC at 12
. KIND 0
. SUSPEND COUNT 0
. NAME "add"
. PARAMS
. . VAR (...) (mode = VAR) "x"
. . VAR (...) (mode = VAR) "y"
. RETURN at 22
. . ADD at 31
. . . VAR PROXY parameter[0] (...) (mode = VAR) "x"
. . . VAR PROXY parameter[1] (...) (mode = VAR) "y"
FUNC
NAME “add” PARAMS RETURN
VAR “x” VAR “y” ADD
PROXY “x”
56. @ryzokuken@ryzokuken56
[generating bytecode for function: add]
--- AST ---
FUNC at 12
. KIND 0
. SUSPEND COUNT 0
. NAME "add"
. PARAMS
. . VAR (...) (mode = VAR) "x"
. . VAR (...) (mode = VAR) "y"
. RETURN at 22
. . ADD at 31
. . . VAR PROXY parameter[0] (...) (mode = VAR) "x"
. . . VAR PROXY parameter[1] (...) (mode = VAR) "y"
FUNC
NAME “add” PARAMS RETURN
VAR “x” VAR “y” ADD
PROXY “x” PROXY “y”
59. @ryzokuken@ryzokuken59
[generated bytecode for function: add]
Parameter count 3
Frame size 0
12 E> 0x38d5f59df42 @ 0 : a5 StackCheck
22 S> 0x38d5f59df43 @ 1 : 25 02 Ldar a1
31 E> 0x38d5f59df45 @ 3 : 34 03 00 Add a0, [0]
35 S> 0x38d5f59df48 @ 6 : a9 Return
Constant pool (size = 0)
Handler Table (size = 0)
60. @ryzokuken@ryzokuken60
[generated bytecode for function: add]
Parameter count 3
Frame size 0
12 E> 0x38d5f59df42 @ 0 : a5 StackCheck
22 S> 0x38d5f59df43 @ 1 : 25 02 Ldar a1
31 E> 0x38d5f59df45 @ 3 : 34 03 00 Add a0, [0]
35 S> 0x38d5f59df48 @ 6 : a9 Return
Constant pool (size = 0)
Handler Table (size = 0)
61. @ryzokuken@ryzokuken61
[generated bytecode for function: add]
Parameter count 3
Frame size 0
12 E> 0x38d5f59df42 @ 0 : a5 StackCheck
22 S> 0x38d5f59df43 @ 1 : 25 02 Ldar a1
31 E> 0x38d5f59df45 @ 3 : 34 03 00 Add a0, [0]
35 S> 0x38d5f59df48 @ 6 : a9 Return
Constant pool (size = 0)
Handler Table (size = 0)
62. @ryzokuken@ryzokuken62
[generated bytecode for function: add]
Parameter count 3
Frame size 0
12 E> 0x38d5f59df42 @ 0 : a5 StackCheck
22 S> 0x38d5f59df43 @ 1 : 25 02 Ldar a1
31 E> 0x38d5f59df45 @ 3 : 34 03 00 Add a0, [0]
35 S> 0x38d5f59df48 @ 6 : a9 Return
Constant pool (size = 0)
Handler Table (size = 0)
69. @ryzokuken@ryzokuken69
What about that Speculative Optimization thingie he
was talking about earlier?
Now that we finally have the baseline code running,
let’s put that profiling data to good use.
But wait...
78. @ryzokuken@ryzokuken78
...
- feedback vector: 0x18bc7711df89: [FeedbackVector] in OldSpace
- map: 0x18bc38c00bc1 <Map>
- length: 1
- shared function info: 0x18bc7711dc59 <SharedFunctionInfo add>
- optimized code/marker: OptimizationMarker::kNone
- invocation count: 1
- profiler ticks: 0
- slot #0 BinaryOp BinaryOp:SignedSmall {
[0]: 1
}
...
81. @ryzokuken@ryzokuken81
...
- feedback vector: 0xcbd92d1dfe1: [FeedbackVector] in OldSpace
- map: 0x0cbd4f880bc1 <Map>
- length: 1
- shared function info: 0x0cbd92d1dc59 <SharedFunctionInfo add>
- optimized code/marker: OptimizationMarker::kNone
- invocation count: 2
- profiler ticks: 0
- slot #0 BinaryOp BinaryOp:Number {
[0]: 7
}
...
92. @ryzokuken@ryzokuken92
This data in the Feedback Vectors is used to finally optimize
your code once a function is hot.
When is a function “hot”?
Let’s see what actually happens by explicitly triggering
optimization.
98. @ryzokuken@ryzokuken98
leaq rbx,[rip+0xfffffff9]
movq rbx,[rcx-0x20]
testb [rbx+0xf],0x1
jz 0x198104882dfb <+0x3b>
movq r10,0x10efbfde0 (CompileLazyDeoptimizedCode)
jmp r10
push rbp
movq rbp,rsp
push rsi
push rdi
cmpq rsp,[r13+0x11e8] (root (stack_limit))
jna 0x198104882e55 <+0x95>
movq rdx,[rbp+0x18]
testb rdx,0x1
jnz 0x198104882e7b <+0xbb>
movq rcx,[rbp+0x10]
testb rcx,0x1
jnz 0x198104882e87 <+0xc7>
movq rdi,rcx
shrq rdi, 32
movq r8,rdx
shrq r8, 32
addl rdi,r8
jo 0x198104882e93 <+0xd3>
shlq rdi, 32
movq rax,rdi
movq rsp,rbp
pop rbp
ret 0x18
99. @ryzokuken@ryzokuken99
leaq rbx,[rip+0xfffffff9]
movq rbx,[rcx-0x20]
testb [rbx+0xf],0x1
jz 0x198104882dfb <+0x3b>
movq r10,0x10efbfde0 (CompileLazyDeoptimizedCode)
jmp r10
push rbp
movq rbp,rsp
push rsi
push rdi
cmpq rsp,[r13+0x11e8] (root (stack_limit))
jna 0x198104882e55 <+0x95>
movq rdx,[rbp+0x18]
testb rdx,0x1
jnz 0x198104882e7b <+0xbb>
movq rcx,[rbp+0x10]
testb rcx,0x1
jnz 0x198104882e87 <+0xc7>
movq rdi,rcx
shrq rdi, 32
movq r8,rdx
shrq r8, 32
addl rdi,r8
jo 0x198104882e93 <+0xd3>
shlq rdi, 32
movq rax,rdi
movq rsp,rbp
pop rbp
ret 0x18
Prologue
100. @ryzokuken@ryzokuken100
leaq rbx,[rip+0xfffffff9]
movq rbx,[rcx-0x20]
testb [rbx+0xf],0x1
jz 0x198104882dfb <+0x3b>
movq r10,0x10efbfde0 (CompileLazyDeoptimizedCode)
jmp r10
push rbp
movq rbp,rsp
push rsi
push rdi
cmpq rsp,[r13+0x11e8] (root (stack_limit))
jna 0x198104882e55 <+0x95>
movq rdx,[rbp+0x18]
testb rdx,0x1
jnz 0x198104882e7b <+0xbb>
movq rcx,[rbp+0x10]
testb rcx,0x1
jnz 0x198104882e87 <+0xc7>
movq rdi,rcx
shrq rdi, 32
movq r8,rdx
shrq r8, 32
addl rdi,r8
jo 0x198104882e93 <+0xd3>
shlq rdi, 32
movq rax,rdi
movq rsp,rbp
pop rbp
ret 0x18
Check x is Smi
101. @ryzokuken@ryzokuken101
leaq rbx,[rip+0xfffffff9]
movq rbx,[rcx-0x20]
testb [rbx+0xf],0x1
jz 0x198104882dfb <+0x3b>
movq r10,0x10efbfde0 (CompileLazyDeoptimizedCode)
jmp r10
push rbp
movq rbp,rsp
push rsi
push rdi
cmpq rsp,[r13+0x11e8] (root (stack_limit))
jna 0x198104882e55 <+0x95>
movq rdx,[rbp+0x18]
testb rdx,0x1
jnz 0x198104882e7b <+0xbb>
movq rcx,[rbp+0x10]
testb rcx,0x1
jnz 0x198104882e87 <+0xc7>
movq rdi,rcx
shrq rdi, 32
movq r8,rdx
shrq r8, 32
addl rdi,r8
jo 0x198104882e93 <+0xd3>
shlq rdi, 32
movq rax,rdi
movq rsp,rbp
pop rbp
ret 0x18
Check y is Smi
102. @ryzokuken@ryzokuken102
leaq rbx,[rip+0xfffffff9]
movq rbx,[rcx-0x20]
testb [rbx+0xf],0x1
jz 0x198104882dfb <+0x3b>
movq r10,0x10efbfde0 (CompileLazyDeoptimizedCode)
jmp r10
push rbp
movq rbp,rsp
push rsi
push rdi
cmpq rsp,[r13+0x11e8] (root (stack_limit))
jna 0x198104882e55 <+0x95>
movq rdx,[rbp+0x18]
testb rdx,0x1
jnz 0x198104882e7b <+0xbb>
movq rcx,[rbp+0x10]
testb rcx,0x1
jnz 0x198104882e87 <+0xc7>
movq rdi,rcx
shrq rdi, 32
movq r8,rdx
shrq r8, 32
addl rdi,r8
jo 0x198104882e93 <+0xd3>
shlq rdi, 32
movq rax,rdi
movq rsp,rbp
pop rbp
ret 0x18
Smi → Word32 (x)
103. @ryzokuken@ryzokuken103
leaq rbx,[rip+0xfffffff9]
movq rbx,[rcx-0x20]
testb [rbx+0xf],0x1
jz 0x198104882dfb <+0x3b>
movq r10,0x10efbfde0 (CompileLazyDeoptimizedCode)
jmp r10
push rbp
movq rbp,rsp
push rsi
push rdi
cmpq rsp,[r13+0x11e8] (root (stack_limit))
jna 0x198104882e55 <+0x95>
movq rdx,[rbp+0x18]
testb rdx,0x1
jnz 0x198104882e7b <+0xbb>
movq rcx,[rbp+0x10]
testb rcx,0x1
jnz 0x198104882e87 <+0xc7>
movq rdi,rcx
shrq rdi, 32
movq r8,rdx
shrq r8, 32
addl rdi,r8
jo 0x198104882e93 <+0xd3>
shlq rdi, 32
movq rax,rdi
movq rsp,rbp
pop rbp
ret 0x18
Smi → Word32 (y)
104. @ryzokuken@ryzokuken104
leaq rbx,[rip+0xfffffff9]
movq rbx,[rcx-0x20]
testb [rbx+0xf],0x1
jz 0x198104882dfb <+0x3b>
movq r10,0x10efbfde0 (CompileLazyDeoptimizedCode)
jmp r10
push rbp
movq rbp,rsp
push rsi
push rdi
cmpq rsp,[r13+0x11e8] (root (stack_limit))
jna 0x198104882e55 <+0x95>
movq rdx,[rbp+0x18]
testb rdx,0x1
jnz 0x198104882e7b <+0xbb>
movq rcx,[rbp+0x10]
testb rcx,0x1
jnz 0x198104882e87 <+0xc7>
movq rdi,rcx
shrq rdi, 32
movq r8,rdx
shrq r8, 32
addl rdi,r8
jo 0x198104882e93 <+0xd3>
shlq rdi, 32
movq rax,rdi
movq rsp,rbp
pop rbp
ret 0x18
Add x and y
Overflow Check
105. @ryzokuken@ryzokuken105
leaq rbx,[rip+0xfffffff9]
movq rbx,[rcx-0x20]
testb [rbx+0xf],0x1
jz 0x198104882dfb <+0x3b>
movq r10,0x10efbfde0 (CompileLazyDeoptimizedCode)
jmp r10
push rbp
movq rbp,rsp
push rsi
push rdi
cmpq rsp,[r13+0x11e8] (root (stack_limit))
jna 0x198104882e55 <+0x95>
movq rdx,[rbp+0x18]
testb rdx,0x1
jnz 0x198104882e7b <+0xbb>
movq rcx,[rbp+0x10]
testb rcx,0x1
jnz 0x198104882e87 <+0xc7>
movq rdi,rcx
shrq rdi, 32
movq r8,rdx
shrq r8, 32
addl rdi,r8
jo 0x198104882e93 <+0xd3>
shlq rdi, 32
movq rax,rdi
movq rsp,rbp
pop rbp
ret 0x18
Result to Smi
106. @ryzokuken@ryzokuken106
leaq rbx,[rip+0xfffffff9]
movq rbx,[rcx-0x20]
testb [rbx+0xf],0x1
jz 0x198104882dfb <+0x3b>
movq r10,0x10efbfde0 (CompileLazyDeoptimizedCode)
jmp r10
push rbp
movq rbp,rsp
push rsi
push rdi
cmpq rsp,[r13+0x11e8] (root (stack_limit))
jna 0x198104882e55 <+0x95>
movq rdx,[rbp+0x18]
testb rdx,0x1
jnz 0x198104882e7b <+0xbb>
movq rcx,[rbp+0x10]
testb rcx,0x1
jnz 0x198104882e87 <+0xc7>
movq rdi,rcx
shrq rdi, 32
movq r8,rdx
shrq r8, 32
addl rdi,r8
jo 0x198104882e93 <+0xd3>
shlq rdi, 32
movq rax,rdi
movq rsp,rbp
pop rbp
ret 0x18
Epilogue
109. @ryzokuken@ryzokuken109
function add(x, y) {
return x + y;
}
add(1, 2); // Warm up with SignedSmall feedback.
%OptimizeFunctionOnNextCall(add);
add(1, 2); // Optimize and run generated code.
add(1.1, 2.2) // DEOPTIMIZE!
113. @ryzokuken@ryzokuken113
[deoptimizing (DEOPT eager): begin 0x08d97929dbc1 <JSFunction add (sfi = 0x8d97929d999)> (opt #0)
@0, FP to SP delta: 24, caller sp: 0x7ffee7bee248]
;;; deoptimize at <add.js:2:12>, not a Smi
reading input frame add => bytecode_offset=0, args=3, height=1, retval=0(#0); inputs:
0: 0x08d97929dbc1 ; [fp - 16] 0x08d97929dbc1 <JSFunction add (sfi = 0x8d97929d999)>
1: 0x08d9c6b81521 ; [fp + 32] 0x08d9c6b81521 <JSGlobal Object>
2: 0x08d97929da31 ; rdx 0x08d97929da31 <HeapNumber 1.1>
3: 0x08d97929da41 ; [fp + 16] 0x08d97929da41 <HeapNumber 2.2>
4: 0x08d979281749 ; [fp - 24] 0x08d979281749 <NativeContext[247]>
5: 0x08d92b080e19 ; (literal 2) 0x08d92b080e19 <Odd Oddball: optimized_out>
translating interpreted frame add => bytecode_offset=0, height=8
0x7ffee7bee240: [top + 72] <- 0x08d9c6b81521 <JSGlobal Object> ; stack parameter (input #1)
0x7ffee7bee238: [top + 64] <- 0x08d97929da31 <HeapNumber 1.1> ; stack parameter (input #2)
0x7ffee7bee230: [top + 56] <- 0x08d97929da41 <HeapNumber 2.2> ; stack parameter (input #3)
-------------------------
0x7ffee7bee228: [top + 48] <- 0x00010d2881e8 ; caller's pc
0x7ffee7bee220: [top + 40] <- 0x7ffee7bee290 ; caller's fp
0x7ffee7bee218: [top + 32] <- 0x08d979281749 <NativeContext[247]> ; context (input #4)
0x7ffee7bee210: [top + 24] <- 0x08d97929dbc1 <JSFunction add (sfi = 0x8d97929d999)> ;
function (input #0)
0x7ffee7bee208: [top + 16] <- 0x08d97929dca1 <BytecodeArray[7]> ; bytecode array
0x7ffee7bee200: [top + 8] <- 0x003900000000 <Smi 57> ; bytecode offset
-------------------------
0x7ffee7bee1f8: [top + 0] <- 0x08d92b080e19 <Odd Oddball: optimized_out> ; accumulator
(input #5)
[deoptimizing (eager): end 0x08d97929dbc1 <JSFunction add (sfi = 0x8d97929d999)> @0 => node=0,
pc=0x00010d2886c0, caller sp=0x7ffee7bee248, took 1.163 ms]
115. @ryzokuken@ryzokuken115
[deoptimizing (DEOPT eager): begin 0x08d97929dbc1 <JSFunction add (sfi = 0x8d97929d999)> (opt #0)
@0, FP to SP delta: 24, caller sp: 0x7ffee7bee248]
;;; deoptimize at <add.js:2:12>, not a Smi
reading input frame add => bytecode_offset=0, args=3, height=1, retval=0(#0); inputs:
0: 0x08d97929dbc1 ; [fp - 16] 0x08d97929dbc1 <JSFunction add (sfi = 0x8d97929d999)>
1: 0x08d9c6b81521 ; [fp + 32] 0x08d9c6b81521 <JSGlobal Object>
2: 0x08d97929da31 ; rdx 0x08d97929da31 <HeapNumber 1.1>
3: 0x08d97929da41 ; [fp + 16] 0x08d97929da41 <HeapNumber 2.2>
4: 0x08d979281749 ; [fp - 24] 0x08d979281749 <NativeContext[247]>
5: 0x08d92b080e19 ; (literal 2) 0x08d92b080e19 <Odd Oddball: optimized_out>
translating interpreted frame add => bytecode_offset=0, height=8
0x7ffee7bee240: [top + 72] <- 0x08d9c6b81521 <JSGlobal Object> ; stack parameter (input #1)
0x7ffee7bee238: [top + 64] <- 0x08d97929da31 <HeapNumber 1.1> ; stack parameter (input #2)
0x7ffee7bee230: [top + 56] <- 0x08d97929da41 <HeapNumber 2.2> ; stack parameter (input #3)
-------------------------
0x7ffee7bee228: [top + 48] <- 0x00010d2881e8 ; caller's pc
0x7ffee7bee220: [top + 40] <- 0x7ffee7bee290 ; caller's fp
0x7ffee7bee218: [top + 32] <- 0x08d979281749 <NativeContext[247]> ; context (input #4)
0x7ffee7bee210: [top + 24] <- 0x08d97929dbc1 <JSFunction add (sfi = 0x8d97929d999)> ;
function (input #0)
0x7ffee7bee208: [top + 16] <- 0x08d97929dca1 <BytecodeArray[7]> ; bytecode array
0x7ffee7bee200: [top + 8] <- 0x003900000000 <Smi 57> ; bytecode offset
-------------------------
0x7ffee7bee1f8: [top + 0] <- 0x08d92b080e19 <Odd Oddball: optimized_out> ; accumulator
(input #5)
[deoptimizing (eager): end 0x08d97929dbc1 <JSFunction add (sfi = 0x8d97929d999)> @0 => node=0,
pc=0x00010d2886c0, caller sp=0x7ffee7bee248, took 1.163 ms]
116. @ryzokuken@ryzokuken116
[deoptimizing (DEOPT eager): begin 0x08d97929dbc1 <JSFunction add (sfi = 0x8d97929d999)> (opt #0)
@0, FP to SP delta: 24, caller sp: 0x7ffee7bee248]
;;; deoptimize at <add.js:2:12>, not a Smi
reading input frame add => bytecode_offset=0, args=3, height=1, retval=0(#0); inputs:
0: 0x08d97929dbc1 ; [fp - 16] 0x08d97929dbc1 <JSFunction add (sfi = 0x8d97929d999)>
1: 0x08d9c6b81521 ; [fp + 32] 0x08d9c6b81521 <JSGlobal Object>
2: 0x08d97929da31 ; rdx 0x08d97929da31 <HeapNumber 1.1>
3: 0x08d97929da41 ; [fp + 16] 0x08d97929da41 <HeapNumber 2.2>
4: 0x08d979281749 ; [fp - 24] 0x08d979281749 <NativeContext[247]>
5: 0x08d92b080e19 ; (literal 2) 0x08d92b080e19 <Odd Oddball: optimized_out>
translating interpreted frame add => bytecode_offset=0, height=8
0x7ffee7bee240: [top + 72] <- 0x08d9c6b81521 <JSGlobal Object> ; stack parameter (input #1)
0x7ffee7bee238: [top + 64] <- 0x08d97929da31 <HeapNumber 1.1> ; stack parameter (input #2)
0x7ffee7bee230: [top + 56] <- 0x08d97929da41 <HeapNumber 2.2> ; stack parameter (input #3)
-------------------------
0x7ffee7bee228: [top + 48] <- 0x00010d2881e8 ; caller's pc
0x7ffee7bee220: [top + 40] <- 0x7ffee7bee290 ; caller's fp
0x7ffee7bee218: [top + 32] <- 0x08d979281749 <NativeContext[247]> ; context (input #4)
0x7ffee7bee210: [top + 24] <- 0x08d97929dbc1 <JSFunction add (sfi = 0x8d97929d999)> ;
function (input #0)
0x7ffee7bee208: [top + 16] <- 0x08d97929dca1 <BytecodeArray[7]> ; bytecode array
0x7ffee7bee200: [top + 8] <- 0x003900000000 <Smi 57> ; bytecode offset
-------------------------
0x7ffee7bee1f8: [top + 0] <- 0x08d92b080e19 <Odd Oddball: optimized_out> ; accumulator
(input #5)
[deoptimizing (eager): end 0x08d97929dbc1 <JSFunction add (sfi = 0x8d97929d999)> @0 => node=0,
pc=0x00010d2886c0, caller sp=0x7ffee7bee248, took 1.163 ms]
117. @ryzokuken@ryzokuken117
[deoptimizing (DEOPT eager): begin 0x08d97929dbc1 <JSFunction add (sfi = 0x8d97929d999)> (opt #0)
@0, FP to SP delta: 24, caller sp: 0x7ffee7bee248]
;;; deoptimize at <add.js:2:12>, not a Smi
reading input frame add => bytecode_offset=0, args=3, height=1, retval=0(#0); inputs:
0: 0x08d97929dbc1 ; [fp - 16] 0x08d97929dbc1 <JSFunction add (sfi = 0x8d97929d999)>
1: 0x08d9c6b81521 ; [fp + 32] 0x08d9c6b81521 <JSGlobal Object>
2: 0x08d97929da31 ; rdx 0x08d97929da31 <HeapNumber 1.1>
3: 0x08d97929da41 ; [fp + 16] 0x08d97929da41 <HeapNumber 2.2>
4: 0x08d979281749 ; [fp - 24] 0x08d979281749 <NativeContext[247]>
5: 0x08d92b080e19 ; (literal 2) 0x08d92b080e19 <Odd Oddball: optimized_out>
translating interpreted frame add => bytecode_offset=0, height=8
0x7ffee7bee240: [top + 72] <- 0x08d9c6b81521 <JSGlobal Object> ; stack parameter (input #1)
0x7ffee7bee238: [top + 64] <- 0x08d97929da31 <HeapNumber 1.1> ; stack parameter (input #2)
0x7ffee7bee230: [top + 56] <- 0x08d97929da41 <HeapNumber 2.2> ; stack parameter (input #3)
-------------------------
0x7ffee7bee228: [top + 48] <- 0x00010d2881e8 ; caller's pc
0x7ffee7bee220: [top + 40] <- 0x7ffee7bee290 ; caller's fp
0x7ffee7bee218: [top + 32] <- 0x08d979281749 <NativeContext[247]> ; context (input #4)
0x7ffee7bee210: [top + 24] <- 0x08d97929dbc1 <JSFunction add (sfi = 0x8d97929d999)> ;
function (input #0)
0x7ffee7bee208: [top + 16] <- 0x08d97929dca1 <BytecodeArray[7]> ; bytecode array
0x7ffee7bee200: [top + 8] <- 0x003900000000 <Smi 57> ; bytecode offset
-------------------------
0x7ffee7bee1f8: [top + 0] <- 0x08d92b080e19 <Odd Oddball: optimized_out> ; accumulator
(input #5)
[deoptimizing (eager): end 0x08d97929dbc1 <JSFunction add (sfi = 0x8d97929d999)> @0 => node=0,
pc=0x00010d2886c0, caller sp=0x7ffee7bee248, took 1.163 ms]
119. @ryzokuken
Special Thanks
● Benedikt Meurer (@bmeurer)
● Yang Guo (@hashseed)
● Sathya Gunasekaran (@_gsathya)
● Jakob Gruber (@schuay)
● Sigurd Schneider (@sigurdschn)
● ...and everyone else from the V8 team.
● The organizers.
119
Notes de l'éditeur V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
It is used in Chormium, the open source browser from Google and it’s derivatives, and in Node.js, among others. Here we explicitly warm up the x+y site with SignedSmall feedback by passing in two integer values whose sum also fits into the small integer range. Then we tell V8 that it should optimize the function add (with TurboFan) when it’s called the next time, and eventually we call add, which triggers TurboFan and then runs the generated machine code. The prologue checks whether the code object is still valid or whether some condition changed which requires us to throw away the code object. Once we know that the code is still valid, we build the stack frame and check that there’s enough space left on the stack to execute the code. Then we start with the body of the function. We load the values of the parameters x and y from the stack (relative to the frame pointer in rbp) and check if both values have Smi representation (since feedback for + says that both inputs have always been Smi so far). This is done by testing the least significant bit. Once we know that they are both represented as Smi, we need to convert them to 32-bit representation, which is done by shifting the value by 32 bit to the right.
If either x or y is not a Smi the execution of the optimized code aborts immediately and the deoptimizer restores the state of the function in the interpreter right before the Add. Then we go on to perform the integer addition on the inputs. We need to test explicitly for overflow, since the result of the addition might be outside the range of 32-bit integers, in which case we’d need to go back to the interpreter, which will then learn Number feedback on the Add. Finally we convert the result back to Smi representation by shifting the signed 32-bit value up by 32 bit, and then we return the value in the accumulator register rax. As said before, this is not yet the perfect code for this case, since here it would be beneficial to just perform the addition on Smi representation directly, instead of going to Word32, which would save us three shift instructions. But even putting aside this minor aspect, you can see that the generated code is highly optimized and specialized to the profiling feedback. It doesn’t even try to deal with other numbers, strings, big ints or arbitrary JavaScript objects here, but focuses only on the kind of values we’ve seen so far. This is the key ingredient to peak performance for many JavaScript applications.