Date post: | 14-Jan-2015 |
Category: |
Technology |
Upload: | parashuram-n |
View: | 4,789 times |
Download: | 0 times |
JavaScript EnginesPop the hood
z = x + y
1. Read operation from memory2. Get location of x and y3. Read values for x and y 4. Unbox x and y.5. Choose meaning of “+”, perform
“+”6. Save z to memory7. Do garbage.
Executing z = x + y
1. String “z = x + y” is passed into tokenizer.– Webkit uses Flex (LEX)– Accommodate semi colon insertion, etc.
2. Tokenizer output fed to parser – Webkit uses Bison, bottom up shift
reduce parser– Gecko has top down parser
3. Statement now available as Abstract Syntax Tree (AST)
1. Read operation from memory…
• X & Y could be number, string, object, null, undefined, array, etc. – Offsets directly available for primitives
• Values also depend on context of execution– Closures (activation contexts)– Local Variables– Object properties– Scope modifiers – eval, with, etc.
2. Get locations of x and y
• If x is a actually array - obj[x]– Dense array have offsets– Created using 0..N or push– Gecko creates sparse array on N..0– Adding obj[“name”] fails optimization
2. Get values of x – Array
• If X is an object property (obj.x)– Looks up current object or up the prototype
chain– Inline Cache (IC) the value
• Objects have shape – {x:1} is different from {x:1,y:2}
• Webkit stores memory offsets in hidden classes• New shape created for every new property.• IC can read from prototype without walking tree• Closures only save path, still have to walk every
time.
– OpCodes generated for each shape• Obj.x ==> read shape1[member1]
2. Get values of x – Object
• JavaScript variable assignments are un-typed. • Assignments stored as boxed inputs– x could be (int32 | 100) – indicating type and
value
• Javascript numbers are IEEE-754 floating point.– Who cares, just use 32 bit to optimize. – Overflow to doubles.
• Ways to Box values (ref)– Tagging the LSBs (ref)– Nan Boxing (ref) – 51 bit of NaN space for non-
doubles (Webkit)– Nun Boxing (favor doubles in NAN – Mozilla pun)
3. Read boxed input …
From box, infer type and value, represent it in native type Int32 x = 100;
From NunBoxed Values 0x400c 0000 | 0x0000 0000 = not a nan, so
double (3.5) 0xFFFF0001 | 0x0000 0040 = Nan space, so
Int32 (0x0000 0040) From NanBoxed Values (0xFFFF80
00000040) Mask to get pointer, shift to get double X64 portability, fits in register, but harder to
decode
4. Unbox x and y
If (typeof x == int32 && typeof y == int32) result = x <operator> y If (result overflows), result = float If (result Nan), result = NaN.
If (typeof x == int32 && typeof y === float) result = CoarceToFloat(x) + y // Same sanity checks
….. If (typeof x === Object) ….
5. Perform “+” : Interpreter
If type of x and y are known, generate opcodes Fall to opcode when routine is hit. Save cost of boxing, unboxing.
Determined opcode Paths for each shape Multiple shapes mean multiple if-else
branches Still have to check for validity/dirtiness of
opcpdes Typical JagerMonkey JITing
5. Perform “+” : Basic JIT
Observe and identify hot code 70 iterations Crankshaft – according to profiler Other heuristics
Execute opcode routine for specific type Initial compilation cost OpCodes may be thrown away if types
change Fallback to non-optimized version
(Performance fault) Classic Tracemonkey
5. Perform “+” : Typed JIT
Static analysis of code to “prove” types
Reduce checks, ensure only one path taken at all times.
Type stable Javascript IonMonkey Internals. Use multicore processors
To box/unbox values To generate compiled opcodes (Chakra)
5. Perform “+” : Next Gen JIT
Used by WebGL and Canvas render computation routines
Shaders and alpha channel (no direct JS code)
Super fast floating point math Note that variables is strongly typed
as Blobs
5. Perform “+” : GPU Enabled
Strings Substring is O(1), Concat also optimized Concat fault on Opera, Chrome
Array Denser the better Named property is sparse in FF, IE Iterate using index, not for:in or
functional Functions
F() faster than f.call(), f.apply(). Using arguments slows down execution
5. Perform “+” : Datatypes
Objects Prototypes are better than closures
Exceptions Try is mostly free, catch is expensive May cause optimizer to stop
Eval and With Cause scope sudden change, prevent JIT
5. Perform “+” : Datatypes
Box “z” and put it on heap if required. Leave “z” in register if used
subsequently Create shape for “z” if object
6. Save Z
Mark and Sweep Causes GC to pause main routine Jittery animation, unresponsive UI thread
Incremental GC Mark and sweep only parts
Generational GC Separate objects in nursery and tenured
areas Promoting young to old is expensive
Combine Generational and Incremental Frequent young cleanup, occasional old
cleanup
7. Garbage Collection
Block Scope reduces variable lookups (let, var)
“Yeild” may need to save current context
Blob Data type – boxing/unboxing issues
Classes === Concrete Shapes ? Syntactic sugar, no impact
Assignment de-structuring Promises, modules, etc.
Changes due to ECMA.next
Don’t write any code Practice type safety Leave hot loops alone – don’t create
shapes in them Make arrays dense Avoid operations that require different
type coercion every time.
Conclusions
@nparashuramhttp://nparashuram.com