Changes between Version 9 and Version 10 of JavaScriptCore


Ignore:
Timestamp:
Jul 20, 2014 11:31:05 AM (3 years ago)
Author:
fpizlo@apple.com
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • JavaScriptCore

    v9 v10  
    2424'''DFG JIT''' kicks in for functions that are invoked at least 60 times, or that took a loop at least 1000 times.  Again, these numbers are approximate and are subject to additional heuristics.  The DFG performs aggressive type speculation based on profiling information collected by the lower tiers.  This allows it to forward-propagate type information, eliding many type checks.  Sometimes the DFG goes further and speculates on values themselves - for example it may speculate that a value loaded from the heap is always some known function in order to enable inlining.  The DFG uses deoptimization (we call it "OSR exit") to handle cases where speculation fails.  Deoptimization may be synchronous (for example, a branch that checks that the type of a value is that which was expected) or asynchronous (for example, the runtime may observe that the shape or value of some object or variable has changed in a way that contravenes assumptions made by the DFG).  The latter is referred to as "watchpointing" in the DFG codebase.  Altogether, the Baseline JIT and the DFG JIT share a two-way OSR relationship: the Baseline JIT may OSR into the DFG when a function gets hot, and the DFG may OSR to the Baseline JIT in the case of deoptimization.  Repeated OSR exits from the DFG serve as an additional profiling hint: the DFG OSR exit machinery records the reason of the exit (including potentially the values that failed speculation) as well as the frequency with which it occurred; if an exit is taken often enough then reoptimization kicks in: callers are relinked to the Baseline JIT for the affected function, more profiling is gathered, and then the DFG may be later reinvoked.  Reoptimization uses exponential back-off to defend against pathological code.  The DFG is in [http://trac.webkit.org/browser/trunk/Source/JavaScriptCore/dfg dfg/].
    2525
    26 '''FTL JIT''' kicks in for functions that are invoked thousands of times, or loop tens of thousands of times.  It is still a work in progress and is disabled by default.  See [wiki:FTLJIT] for more information.
     26'''FTL JIT''' kicks in for functions that are invoked thousands of times, or loop tens of thousands of times.  See [wiki:FTLJIT] for more information.
    2727
    28 At any time, functions, eval blocks, and global code in JavaScriptCore may be executing in a mix of the LLInt, Baseline JIT, and DFG.  In the extreme case of a recursive function, there may even be multiple stack frames where one frame is in the LLInt, another is in the Baseline JIT, while another still is in the DFG; even more extreme are cases where one stack frame is executing an old DFG compilation and another is executing a new DFG compilation because recompilation kicked in but execution did not yet return to the old DFG code.  These three engines are designed to maintain identical execution semantics, and so even if multiple functions in a JavaScript program are executing in a mix of these engines the only perceptible effect ought to be execution performance.
     28At any time, functions, eval blocks, and global code in JavaScriptCore may be executing in a mix of the LLInt, Baseline JIT, DFG, and FTL.  In the extreme case of a recursive function, there may even be multiple stack frames where one frame is in the LLInt, another is in the Baseline JIT, while another still is in the DFG or even FTL; even more extreme are cases where one stack frame is executing an old DFG or FTL compilation and another is executing a new DFG or FTL compilation because recompilation kicked in but execution did not yet return to the old DFG/FTL code.  These four engines are designed to maintain identical execution semantics, and so even if multiple functions in a JavaScript program are executing in a mix of these engines the only perceptible effect ought to be execution performance.
    2929
    3030== Type Inference ==
     
    6767* the result is an integer.
    6868
    69 Any subsequent operations on either 'a' or 'b' do not need to check their types.  Likewise for operations on the result.  The elimination of subsequent checks is achieved by a second data flow analysis, called simply the DFG CFA.  Unlike the prediction propagation phase, which is concerned with constructing ''type predictions'', the CFA is concerned with constructing ''type proofs''.  The CFA, found in [http://trac.webkit.org/browser/trunk/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp DFGCFAPhase.cpp] and [http://trac.webkit.org/browser/trunk/Source/JavaScriptCore/dfg/DFGAbstractState.cpp DFGAbstractState.cpp], follows a ''flow-sensitive'' forward data flow formulation.  It also implements sparse conditional constant propagation, which gives it the ability to sometimes prove that values are constants, as well as proving their types.
     69Any subsequent operations on either 'a' or 'b' do not need to check their types.  Likewise for operations on the result.  The elimination of subsequent checks is achieved by a second data flow analysis, called simply the DFG CFA.  Unlike the prediction propagation phase, which is concerned with constructing ''type predictions'', the CFA is concerned with constructing ''type proofs''.  The CFA, found in [http://trac.webkit.org/browser/trunk/Source/JavaScriptCore/dfg/DFGCFAPhase.cpp DFGCFAPhase.cpp] and [http://trac.webkit.org/browser/trunk/Source/JavaScriptCore/dfg/DFGAbstractInterpreterInlines.cpp DFGAbstractInterpreterInlines.cpp], follows a ''flow-sensitive'' forward data flow formulation.  It also implements sparse conditional constant propagation, which gives it the ability to sometimes prove that values are constants, as well as proving their types.
    7070
    7171Putting this together, the expression 'o.x * o.x + o.y * o.y' will only require type checks on the value loaded from 'o.x' and the value loaded from 'o.y'.  After that, we know that the values are doubles, and we know that we only have to emit a double multiply path followed by a double addition.  When combined with type check hoisting, DFG code will usually execute a type check at most once per heap load.
     
    7575(to be written)
    7676
     77Note that a pretty good summary of how we optimize code is in https://www.webkit.org/blog/3362/introducing-the-webkit-ftl-jit/.
     78
    7779Attached are some slides from a recent talk about JavaScriptCore.