Changes between Version 9 and Version 10 of FTLJIT


Ignore:
Timestamp:
Jan 28, 2016 12:46:44 PM (6 years ago)
Author:
fpizlo@apple.com
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • FTLJIT

    v9 v10  
    1 JavaScriptCore uses LLVM for a top-tier high-throughput optimizing JIT, which we call the FTL (Fourth Tier LLVM).  See https://bugs.webkit.org/show_bug.cgi?id=112840 for the bug that tracked this work.  This was done as part of our effort to increase our latency-throughput adaptability range, and included other things like our concurrent JIT implementation; all of the tasks involved can be seen
    2 in https://bugs.webkit.org/showdependencytree.cgi?id=112836&hide_resolved=0.  A lot of the future work to further improve the FTL JIT is tracked under https://bugs.webkit.org/show_bug.cgi?id=132356.
     1The FTL JIT is JavaScriptCore's top-tier optimizing compiler.  It's a combination of our DFG compiler for doing high-level optimizations and type inference, and a lowering phase that turns that code into C-like SSA.  Currently it can be configured to use either B3 or LLVM as the backend:
    32
    4 The FTL JIT is now enabled by default on the Mac port.
     3- The FTL JIT started out as a marriage of the DFG and LLVM.  We are phasing out LLVM support, but it's currently still possible to configure FTL to use LLVM.
     4- We are moving the FTL JIT to use the B3 backend instead of LLVM.  B3 is WebKit's own creation.  WebKit tends to perform better with the B3 backend, and we are transitioning to making this the only available FTL JIT configuration.
     5
     6See https://bugs.webkit.org/show_bug.cgi?id=112840 for the bug that tracked the original FTL JIT work.  This was done as part of our effort to increase our latency-throughput adaptability range, and included other things like our concurrent JIT implementation; all of the tasks involved can be seen
     7in https://bugs.webkit.org/showdependencytree.cgi?id=112836&hide_resolved=0.  A lot of the future work to further improve the FTL JIT is tracked under https://bugs.webkit.org/show_bug.cgi?id=132356.  The work to transition the FTL JIT to B3 is tracked by https://bugs.webkit.org/show_bug.cgi?id=150279.
     8
     9The FTL JIT is enabled by default on the Mac and iOS ports.
    510
    611Two detailed blog posts have been written about the FTL; they currently serve as the best documentation of the FTL's architecture; see: https://www.webkit.org/blog/3362/introducing-the-webkit-ftl-jit/ and http://blog.llvm.org/2014/07/ftl-webkits-llvm-based-jit.html.
     
    1015The FTL is integrated as an alternative backend for the DFG JIT but largely reuses existing DFG functionality.  The FTL differs from the DFG as follows:
    1116
    12 - Instead of generating machine code directly from the DFG IR, the DFG IR is lowered to LLVM IR and then the LLVM optimization pipeline and backend are invoked to generate machine code.  That machine code is then managed by the JSC executable memory manager no differently than if it were generated by our own backends.
     17- Instead of generating machine code directly from the DFG IR, the DFG IR is lowered to a C-like SSA IR.  The IR is abstracted by the FTL.  We refer to it as "FTL output".  FTL output can be configured to abstract over either LLVM IR or B3 IR.  When configured to use LLVM, the FTL invokes the LLVM optimization pipeline and backend to generate machine code.  That machine code is then managed by the JSC executable memory manager no differently than if it were generated by our own backends.  When configured to use B3, the FTL tells B3 to optimize and generate the code using WebKit's MacroAssembler API.  This leads to a natural integration between B3 and JSC executable memory management.
    1318- Additional DFG phases are used.  Running in FTL mode causes the DFG to lower to SSA even before lowering to LLVM IR.  Additional optimizations like LICM are performed on the DFG-SSA IR.
    1419
    1520The FTL JIT supports key DFG concepts like OSR entry, OSR exit, concurrent compilation, and self-modifying code for inline caches that we use for things like GetById (i.e. v = o.f), PutById (i.e. o.f = v), Call/Construct, and In (i.e. "foo" in o).
    16 
    17 = Try it out
    18 
    19 == Building
    20 
    21 The FTL JIT is enabled by default, so you shouldn't have to do anything special to build it.  All of the Apple WebKit ports' build modes support the FTL: it will be built and enabled via build-jsc, build-webkit, make, and building from Xcode.  This is made possible by including binary drops of known-good LLVM versions in the WebKit repository (more on that below).
    22 
    23 On non-"Apple WebKit" platforms, the FTL JIT is disabled, but the --ftl-jit flag will force it enabled.  Your mileage may vary, though, since currently only Mac and iOS is supported by the FTL JIT.  Here's an example of using the --ftl-jit flag:
    24 
    25 {{{
    26 Tools/Scripts/build-jsc --ftl-jit --debug
    27 }}}
    28 
    29 or:
    30 
    31 {{{
    32 Tools/Scripts/build-jsc --ftl-jit --release
    33 }}}
    34 
    35 === Building from binary drops
    36 
    37 The WebKit repository includes LLVM binary drops for Mountain Lion and Mavericks in trunk/WebKitLibraries.  On those systems, the build system will automatically pull LLVM from those binary drops.  This is done in Tools/Scripts/copy-webkitlibraries-to-product-directory.
    38 
    39 === Building from your own LLVM checkout
    40 
    41 The easiest way to build with your own LLVM checkout is to check out llvm into a directory called 'llvm' directly inside your checkout of WebKit.  If you do this, build-jsc and friends will automatically configure and make this LLVM tree and pull the binaries into WebKit's build.  LLVM's configure script is only run if we detect that you hadn't already run it.  The default configuration parameters are kept in Tools/Scripts/copy-webkitlibraries-to-product-directory.  You can configure LLVM yourself, so long as you follow the same build directory structure as that script expects: within the llvm directory, we expect a "wkLLVMBuild" subdirectory.  This will be used as the build directory.
    42 
    43 Note that this handles dependencies pretty well.  For example, if you make changes in LLVM that lead to some libraries that WebKit depends on being recompiled, but don't change any LLVM headers, this will still cause the JavaScriptCore framework to be relinked.
    44 
    45 There are two alternatives that give you varying degrees of control over how WebKit builds LLVM.
    46 
    47 - You can put your LLVM checkout wherever you like and then make sure that the LLVM_SOURCE_PATH environment variable to tell WebKit's build system where the checkout is.  WebKit's build system will still configure/make LLVM as necessary every time you build WebKit.
    48 
    49 - You can build LLVM yourself and opt out of WebKit building it for you.  The process for this is a bit convoluted, but it does work.  After you build LLVM, use the Tools/Scripts/export-llvm-build script to create tarballs of LLVM's headers and libraries.  Then use the LLVM_LIBRARY_PACKAGE and LLVM_INCLUDE_PACKAGE environment variables to tell us where you put those tarballs.
    50 
    51 For further information, consult the Tools/Scripts/copy-webkitlibraries-to-product-directory script, which handles all of this magic.
    52 
    53 == Running and Testing
    54 
    55 The FTL JIT is runtime-enabled on those platforms where it is build-time-enabled.  The --useFTLJIT flag can be used to disable it.  Note that the FTL only kicks in for functions that run many times - 100,000 executions is typically required to ensure that the function is FTL-compiled.  Because FTL compilation is queued up and done concurrently, for simple programs even 100,000 executions may not be enough to really trigger the FTL: the program may exit while the FTL compilation task is still queued or on-going.  You can disable this by doing:
    56 
    57 {{{
    58 DYLD_FRAMEWORK_PATH=WebKitBuild/Debug WebKitBuild/Debug/jsc --enableConcurrentJIT=false <my JS program>
    59 }}}
    60 
    61 Note that all jsc command-line options can also be passed as environment variables, which is useful if you're running an application that deeply embeds JavaScriptCore (for example, a browser).  In this case you would do:
    62 
    63 {{{
    64 export JSC_enableConcurrentJIT=false
    65 }}}
    66 
    67 == Looking at IR
    68 
    69 Additional options allow for inspecting the IR that the FTL generates.
    70 
    71 === See if LLVM is being used to compile a function
    72 
    73 {{{
    74 DYLD_FRAMEWORK_PATH=WebKitBuild/Debug WebKitBuild/Debug/jsc --reportCompileTimes=true <my JS program>
    75 }}}
    76 
    77 === Dump all LLVM IR
    78 
    79 {{{
    80 DYLD_FRAMEWORK_PATH=WebKitBuild/Debug WebKitBuild/Debug/jsc --dumpLLVMIR=true <my JS program>
    81 }}}
    82 
    83 === Dump DFG IR and LLVM IR before and after LLVM optimization
    84 
    85 {{{
    86 DYLD_FRAMEWORK_PATH=WebKitBuild/Debug WebKitBuild/Debug/jsc --verboseFTLCompilation=true <my JS program>
    87 }}}
    88 
    89 This will also tell if why some functions don't get FTL compiled.  The FTL doesn't have full coverage over DFG IR yet.  If JSC chooses not to use the FTL JIT for a code block, you will see a dump explaining why.
    90 
    91 === Dump all machine code
    92 
    93 {{{
    94 DYLD_FRAMEWORK_PATH=WebKitBuild/Debug WebKitBuild/Debug/jsc --showDFGDisassembly=true <my JS program>
    95 }}}
    96 
    97 This will also dump FTL disassembly, using the LLVM disassembler.