JS is a strange language
Many implementations
Multiple platforms
JIT (Just In Time) Compiler
function addA(a,b) {
const weirdConstant = 10
return a + b + weirdConstant
}
const c = addA(4,5)
forEach polyfill in JS
forEach polyfill in JS
Array.prototype.forEach = function (callback, thisArg) {
var T, k
if (this == null) {
throw new TypeError(' this is null or not defined')
}
var O = Object(this)
var len = O.length >>> 0
if (typeof callback !== 'function') {
throw new TypeError(callback + ' is not a function')
}
if (arguments.length > 1) {
T = thisArg
}
k = 0
while (k < len) {
var kValue
if (k in O) {
kValue = O[k]
callback.call(T, kValue, k, O)
}
k++
}
}
Fast and generate bytecode
Used only for "HOT" functions
Before dinosaurs => 2008
2010 - First optimizing compiler
2014 - Lets add more of them?
Crankshaft and full codegen
Other engines follow using even more than 2 compilers per engine
2016 - Interpreter idea
2017 - Back to the future
Property access
const getXProp = obj => obj.x
function getXProp (obj) {
return obj.x
}
9.1.8.1 OrdinaryGet ( O, P, Receiver ) When the abstract operation OrdinaryGet is called with Object O, property key P, and
ECMAScript language value Receiver, the following steps are taken:
Assert :IsPropertyKey (P) istrue .- Let desc be ? O.[[GetOwnProperty]](P).
- If desc is
undefined , then
- Let parent be ? O.[[GetPrototypeOf]]().
- If parent is
null , returnundefined .- Return ? parent.[[Get]](P, Receiver).
- If
IsDataDescriptor (desc) istrue , return desc.[[Value]].Assert :IsAccessorDescriptor (desc) istrue .- Let getter be desc.[[Get]].
- If getter is
undefined , returnundefined .- Return ?
Call (getter, Receiver).
const getXProp = obj => obj.x
getXProp({ x: 1 })
SET
{ x:int } => get from offset 1 in IC (Inline Cache)
getXProp({ x: 2 })
{ x: 2 } type of { x:int }
GET from offset 1
const firstX = { x: 2 }
const secondX = { x: 12 }
console.log(%HaveSameMap(firstX, secondX))
--allow-native-syntax
Let TurboFan do the work
const getPropX = obj => obj.x
for(var i=0; i<10000; i++) {
getPropX({ x: i })
}
0xc0abb749632 18 488bf0 REX.W movq rsi,rax
;;; <@18,#13> stack-check
0xc0abb749635 21 493ba5880a0000 REX.W cmpq rsp,[r13+0xa88]
0xc0abb74963c 28 7305 jnc 35 (0xc0abb749643)
0xc0abb74963e 30 e89d35efff call StackCheck (0xc0abb63cbe0)
;; code: BUILTIN
;;; <@20,#13> lazy-bailout
;;; <@21,#13> gap
0xc0abb749643 35 488b4510 REX.W movq rax,[rbp+0x10]
;;; <@22,#15> check-non-smi
0xc0abb749647 39 a801 test al,0x1
0xc0abb749649 41 0f8427000000 jz 86 (0xc0abb749676)
;;; <@24,#16> check-maps
0xc0abb74964f 47 49bad9bde1bd02370000 REX.W movq r10,0x3702bde1bdd9
;; object: 0x3702bde1bdd9
Map(FAST_HOLEY_ELEMENTS)
0xc0abb749659 57 4c3950ff REX.W cmpq [rax-0x1],r10
0xc0abb74965d 61 0f8518000000 jnz 91 (0xc0abb74967b)
;;; <@26,#17> load-named-field
0xc0abb749663 67 8b401b movl rax,[rax+0x1b]
;;; <@28,#21> smi-tag
0xc0abb749666 70 8bd8 movl rbx,rax
0xc0abb749668 72 48c1e320 REX.W shlq rbx, 32
;;; <@29,#21> gap
0xc0abb74966c 76 488bc3 REX.W movq rax,rbx
;;; <@30,#19> return
0xc0abb74966f 79 488be5 REX.W movq rsp,rbp
0xc0abb749672 82 5d pop rbp
0xc0abb749673 83 c21000 ret 0x10
;;; -------------------- Jump table --------------------
0xc0abb749676 86 e88fc9bbff call 0xc0abb30600a ;; deoptimization bailout 1
0xc0abb74967b 91 e894c9bbff call 0xc0abb306014 ;; deoptimization bailout 2
Let TurboFan do the work
const getPropX = obj => obj.x
for(var i=0; i<10000; i++) {
getPropX({ x: i })
}
0xc0abb749632 18 488bf0 REX.W movq rsi,rax
;;; <@18,#13> stack-check
0xc0abb749635 21 493ba5880a0000 REX.W cmpq rsp,[r13+0xa88]
0xc0abb74963c 28 7305 jnc 35 (0xc0abb749643)
0xc0abb74963e 30 e89d35efff call StackCheck (0xc0abb63cbe0)
;; code: BUILTIN
;;; <@20,#13> lazy-bailout
;;; <@21,#13> gap
0xc0abb749643 35 488b4510 REX.W movq rax,[rbp+0x10]
;;; <@22,#15> check-non-smi
0xc0abb749647 39 a801 test al,0x1
0xc0abb749649 41 0f8427000000 jz 86 (0xc0abb749676)
;;; <@24,#16> check-maps
0xc0abb74964f 47 49bad9bde1bd02370000 REX.W movq r10,0x3702bde1bdd9
;; object: 0x3702bde1bdd9
Map(FAST_HOLEY_ELEMENTS)
0xc0abb749659 57 4c3950ff REX.W cmpq [rax-0x1],r10
0xc0abb74965d 61 0f8518000000 jnz 91 (0xc0abb74967b)
;;; <@26,#17> load-named-field
0xc0abb749663 67 8b401b movl rax,[rax+0x1b]
;;; <@28,#21> smi-tag
0xc0abb749666 70 8bd8 movl rbx,rax
0xc0abb749668 72 48c1e320 REX.W shlq rbx, 32
;;; <@29,#21> gap
0xc0abb74966c 76 488bc3 REX.W movq rax,rbx
;;; <@30,#19> return
0xc0abb74966f 79 488be5 REX.W movq rsp,rbp
0xc0abb749672 82 5d pop rbp
0xc0abb749673 83 c21000 ret 0x10
;;; -------------------- Jump table --------------------
0xc0abb749676 86 e88fc9bbff call 0xc0abb30600a ;; deoptimization bailout 1
0xc0abb74967b 91 e894c9bbff call 0xc0abb306014 ;; deoptimization bailout 2
Let TurboFan do the work
const getPropX = obj => obj.x
for(var i=0; i<10000; i++) {
getPropX({ x: i })
}
0xc0abb749632 18 488bf0 REX.W movq rsi,rax
;;; <@18,#13> stack-check
0xc0abb749635 21 493ba5880a0000 REX.W cmpq rsp,[r13+0xa88]
0xc0abb74963c 28 7305 jnc 35 (0xc0abb749643)
0xc0abb74963e 30 e89d35efff call StackCheck (0xc0abb63cbe0)
;; code: BUILTIN
;;; <@20,#13> lazy-bailout
;;; <@21,#13> gap
0xc0abb749643 35 488b4510 REX.W movq rax,[rbp+0x10]
;;; <@22,#15> check-non-smi
0xc0abb749647 39 a801 test al,0x1
0xc0abb749649 41 0f8427000000 jz 86 (0xc0abb749676)
;;; <@24,#16> check-maps<
0xc0abb74964f 47 49bad9bde1bd02370000 REX.W movq r10,0x3702bde1bdd9
;; object: 0x3702bde1bdd9
Map(FAST_HOLEY_ELEMENTS)
0xc0abb749659 57 4c3950ff REX.W cmpq [rax-0x1],r10
0xc0abb74965d 61 0f8518000000 jnz 91 (0xc0abb74967b)
;;; <@26,#17> load-named-field
0xc0abb749663 67 8b401b movl rax,[rax+0x1b]
;;; <@28,#21> smi-tag
0xc0abb749666 70 8bd8 movl rbx,rax
0xc0abb749668 72 48c1e320 REX.W shlq rbx, 32
;;; <@29,#21> gap
0xc0abb74966c 76 488bc3 REX.W movq rax,rbx
;;; <@30,#19> return
0xc0abb74966f 79 488be5 REX.W movq rsp,rbp
0xc0abb749672 82 5d pop rbp
0xc0abb749673 83 c21000 ret 0x10
;;; -------------------- Jump table --------------------
0xc0abb749676 86 e88fc9bbff call 0xc0abb30600a
;; deoptimization bailout 1
0xc0abb74967b 91 e894c9bbff call 0xc0abb306014 ;; deoptimization bailout 2
Let TurboFan do the work
const getPropX = obj => obj.x
for(var i=0; i<10000; i++) {
getPropX({ x: i })
}
0xc0abb749632 18 488bf0 REX.W movq rsi,rax
;;; <@18,#13> stack-check
0xc0abb749635 21 493ba5880a0000 REX.W cmpq rsp,[r13+0xa88]
0xc0abb74963c 28 7305 jnc 35 (0xc0abb749643)
0xc0abb74963e 30 e89d35efff call StackCheck (0xc0abb63cbe0)
;; code: BUILTIN
;;; <@20,#13> lazy-bailout
;;; <@21,#13> gap
0xc0abb749643 35 488b4510 REX.W movq rax,[rbp+0x10]
;;; <@22,#15> check-non-smi
0xc0abb749647 39 a801 test al,0x1
0xc0abb749649 41 0f8427000000 jz 86 (0xc0abb749676)
;;; <@24,#16> check-maps
0xc0abb74964f 47 49bad9bde1bd02370000 REX.W movq r10,0x3702bde1bdd9
;; object: 0x3702bde1bdd9
Map(FAST_HOLEY_ELEMENTS)
0xc0abb749659 57 4c3950ff REX.W cmpq [rax-0x1],r10
0xc0abb74965d 61 0f8518000000 jnz 91 (0xc0abb74967b)
;;; <@26,#17> load-named-field
0xc0abb749663 67 8b401b movl rax,[rax+0x1b]
;;; <@28,#21> smi-tag
0xc0abb749666 70 8bd8 movl rbx,rax
0xc0abb749668 72 48c1e320 REX.W shlq rbx, 32
;;; <@29,#21> gap
0xc0abb74966c 76 488bc3 REX.W movq rax,rbx
;;; <@30,#19> return
0xc0abb74966f 79 488be5 REX.W movq rsp,rbp
0xc0abb749672 82 5d pop rbp
0xc0abb749673 83 c21000 ret 0x10
;;; -------------------- Jump table --------------------
0xc0abb749676 86 e88fc9bbff call 0xc0abb30600a ;; deoptimization bailout 1
0xc0abb74967b 91 e894c9bbff call 0xc0abb306014 ;; deoptimization bailout 2
Let TurboFan do the work
const getPropX = obj => obj.x
for(var i=0; i<10000; i++) {
getPropX({ x: i })
}
0xc0abb749632 18 488bf0 REX.W movq rsi,rax
;;; <@18,#13> stack-check
0xc0abb749635 21 493ba5880a0000 REX.W cmpq rsp,[r13+0xa88]
0xc0abb74963c 28 7305 jnc 35 (0xc0abb749643)
0xc0abb74963e 30 e89d35efff call StackCheck (0xc0abb63cbe0)
;; code: BUILTIN
;;; <@20,#13> lazy-bailout
;;; <@21,#13> gap
0xc0abb749643 35 488b4510 REX.W movq rax,[rbp+0x10]
;;; <@22,#15> check-non-smi
0xc0abb749647 39 a801 test al,0x1
0xc0abb749649 41 0f8427000000 jz 86 (0xc0abb749676)
;;; <@24,#16> check-maps
0xc0abb74964f 47 49bad9bde1bd02370000 REX.W movq r10,0x3702bde1bdd9
;; object: 0x3702bde1bdd9
Map(FAST_HOLEY_ELEMENTS)
0xc0abb749659 57 4c3950ff REX.W cmpq [rax-0x1],r10
0xc0abb74965d 61 0f8518000000 jnz 91 (0xc0abb74967b)
;;; <@26,#17> load-named-field
0xc0abb749663 67 8b401b movl rax,[rax+0x1b]
;;; <@28,#21> smi-tag
0xc0abb749666 70 8bd8 movl rbx,rax
0xc0abb749668 72 48c1e320 REX.W shlq rbx, 32
;;; <@29,#21> gap
0xc0abb74966c 76 488bc3 REX.W movq rax,rbx
;;; <@30,#19> return
0xc0abb74966f 79 488be5 REX.W movq rsp,rbp
0xc0abb749672 82 5d pop rbp
0xc0abb749673 83 c21000 ret 0x10
;;; -------------------- Jump table --------------------
0xc0abb749676 86 e88fc9bbff call 0xc0abb30600a ;; deoptimization bailout 1
0xc0abb74967b 91 e894c9bbff call 0xc0abb306014 ;; deoptimization bailout 2
Let TurboFan do the work
const getPropX = obj => obj.x
for(var i=0; i<10000; i++) {
getPropX({ x: i })
}
0xc0abb749632 18 488bf0 REX.W movq rsi,rax
;;; <@18,#13> stack-check
0xc0abb749635 21 493ba5880a0000 REX.W cmpq rsp,[r13+0xa88]
0xc0abb74963c 28 7305 jnc 35 (0xc0abb749643)
0xc0abb74963e 30 e89d35efff call StackCheck (0xc0abb63cbe0)
;; code: BUILTIN
;;; <@20,#13> lazy-bailout
;;; <@21,#13> gap
0xc0abb749643 35 488b4510 REX.W movq rax,[rbp+0x10]
;;; <@22,#15> check-non-smi
0xc0abb749647 39 a801 test al,0x1
0xc0abb749649 41 0f8427000000 jz 86 (0xc0abb749676)
;;; <@24,#16> check-maps
0xc0abb74964f 47 49bad9bde1bd02370000 REX.W movq r10,0x3702bde1bdd9
;; object: 0x3702bde1bdd9
Map(FAST_HOLEY_ELEMENTS)
0xc0abb749659 57 4c3950ff REX.W cmpq [rax-0x1],r10
0xc0abb74965d 61 0f8518000000 jnz 91 (0xc0abb74967b)
;;; <@26,#17> load-named-field
0xc0abb749663 67 8b401b movl rax,[rax+0x1b]
;;; <@28,#21> smi-tag
0xc0abb749666 70 8bd8 movl rbx,rax
0xc0abb749668 72 48c1e320 REX.W shlq rbx, 32
;;; <@29,#21> gap
0xc0abb74966c 76 488bc3 REX.W movq rax,rbx
;;; <@30,#19> return
0xc0abb74966f 79 488be5 REX.W movq rsp,rbp
0xc0abb749672 82 5d pop rbp
0xc0abb749673 83 c21000 ret 0x10
;;; -------------------- Jump table --------------------
0xc0abb749676 86 e88fc9bbff call 0xc0abb30600a ;; deoptimization bailout 1
0xc0abb74967b 91 e894c9bbff call 0xc0abb306014 ;; deoptimization bailout 2
getPropX({ x: 13, y: 20 })
Try it again...
const getPropX = obj => obj.x
for(var i=0; i<10000; i++) {
getPropX({ x: i })
getPropX({ x: i, y: i })
getPropX({ x: i, z: i })
}
0x18eb24149772 18 488bf0 REX.W movq rsi,rax
;;; <@18,#13> stack-check
0x18eb24149775 21 493ba5880a0000 REX.W cmpq rsp,[r13+0xa88]
0x18eb2414977c 28 7305 jnc 35 (0x18eb24149783)
0x18eb2414977e 30 e85d34efff call StackCheck (0x18eb2403cbe0) ;; code: BUILTIN
;;; <@20,#13> lazy-bailout
;;; <@21,#13> gap
0x18eb24149783 35 488b4510 REX.W movq rax,[rbp+0x10]
;;; <@22,#15> check-non-smi
0x18eb24149787 39 a801 test al,0x1
0x18eb24149789 41 0f8447000000 jz 118 (0x18eb241497d6)
;;; <@24,#16> check-maps
0x18eb2414978f 47 49bad9bd9144b9130000 REX.W movq r10,0x13b94491bdd9 ;; object: 0x13b94491bdd9
Map(FAST_HOLEY_ELEMENTS)>
0x18eb24149799 57 4c3950ff REX.W cmpq [rax-0x1],r10
0x18eb2414979d 61 7424 jz 99 (0x18eb241497c3)
0x18eb2414979f 63 49ba89be9144b9130000 REX.W movq r10,0x13b94491be89 ;; object: 0x13b94491be89
Map(FAST_HOLEY_ELEMENTS)>
0x18eb241497a9 73 4c3950ff REX.W cmpq [rax-0x1],r10
0x18eb241497ad 77 7414 jz 99 (0x18eb241497c3)
0x18eb241497af 79 49bae1be9144b9130000 REX.W movq r10,0x13b94491bee1 ;; object: 0x13b94491bee1
Map(FAST_HOLEY_ELEMENTS)>
0x18eb241497b9 89 4c3950ff REX.W cmpq [rax-0x1],r10
0x18eb241497bd 93 0f8518000000 jnz 123 (0x18eb241497db)
;;; <@26,#17> load-named-field
0x18eb241497c3 99 8b401b movl rax,[rax+0x1b]
;;; <@28,#21> smi-tag
0x18eb241497c6 102 8bd8 movl rbx,rax
0x18eb241497c8 104 48c1e320 REX.W shlq rbx, 32
;;; <@29,#21> gap
0x18eb241497cc 108 488bc3 REX.W movq rax,rbx
;;; <@30,#19> return
0x18eb241497cf 111 488be5 REX.W movq rsp,rbp
0x18eb241497d2 114 5d pop rbp
0x18eb241497d3 115 c21000 ret 0x10
;;; -------------------- Jump table --------------------
0x18eb241497d6 118 e82fc8bbff call 0x18eb23d0600a ;; deoptimization bailout 1
0x18eb241497db 123 e834c8bbff call 0x18eb23d06014 ;; deoptimization bailout 2
9.1.9.1 OrdinarySet ( O, P, V, Receiver ) When the abstract operation OrdinarySet is called with Object O, property key P, value V, and
ECMAScript language value Receiver, the following steps are taken:
Assert :IsPropertyKey (P) istrue .- Let ownDesc be ? O.[[GetOwnProperty]](P).
- If ownDesc is
undefined , then
- Let parent be ? O.[[GetPrototypeOf]]().
- If parent is not
null , then
- Return ? parent.[[Set]](P, V, Receiver).
- Else,
- Set ownDesc to the PropertyDescriptor{[[Value]]:
undefined , [[Writable]]:true , [[Enumerable]]:true , [[Configurable]]:true }.- If
IsDataDescriptor (ownDesc) istrue , then
- If ownDesc.[[Writable]] is
false , returnfalse .- If
Type (Receiver) is not Object, returnfalse .- Let existingDescriptor be ? Receiver.[[GetOwnProperty]](P).
- If existingDescriptor is not
undefined , then
- If
IsAccessorDescriptor (existingDescriptor) istrue , returnfalse .- If existingDescriptor.[[Writable]] is
false , returnfalse .- Let valueDesc be the PropertyDescriptor{[[Value]]: V}.
- Return ? Receiver.[[DefineOwnProperty]](P, valueDesc).
- Else Receiver does not currently have a property P,
- Return ?
CreateDataProperty (Receiver, P, V).Assert :IsAccessorDescriptor (ownDesc) istrue .- Let setter be ownDesc.[[Set]].
- If setter is
undefined , returnfalse .- Perform ?
Call (setter, Receiver, « V »).- Return
true .
Property access
if (obj) { return obj.x }
... ...........
27 cmpq [r13-0x40],rax
31 jz 128
37 test al,0x1
39 setzl bl
42 movzxbl rbx,rbx
45 cmpl rbx,0x0
48 jnz 185
54 cmpq [r13-0x38],rax
58 jz 128
64 movq rdx,[rax-0x1]
68 testb [rdx+0xc],0x10
72 jnz 128
78 cmpq [r13+0x50],rdx
82 jz 160
160 vmovsd xmm0,[rax+0x7]
165 movq [rbp-0x18],rbx
169 vxorpd xmm1,xmm1,xmm1
173 vucomisd xmm1,xmm0
177 jz 128
179 movq rbx,[rbp-0x18]
183 jmp 88
185 movq [rbp-0x18],rbx
189 cmpq rax,0x0
193 jz 128
195 movq rbx,[rbp-0x18]
199 jmp 88
... ...........
Property access
if (obj !== undefined) { return obj.x }
... ...........
23 cmpq [r13-0x60],rax
27 jz 72
... ...........
Try it
node --v8-options
node --print_opt_code test.js > nodejsOut.txt
node --print_opt_code --turbo test.js > nodejsOut.txt
d8 --print-opt-code text.js > d8Out.txt
Code readability gets worse
Each engine is different
V8 is changing on daily basis :D
Users use different engines either way