LCOV - app.info - js/src/methodjit/MethodJIT.cpp

LCOV - code coverage report
| Current view: | directory - js/src/methodjit - MethodJIT.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 246 | 236 | 95.9 %
| Date: | 2012-04-21 | Functions: | 39 | 37 | 94.9 %

           1                 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
           2                 :  * vim: set ts=4 sw=4 et tw=99:
           3                 :  *
           4                 :  * ***** BEGIN LICENSE BLOCK *****
           5                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           6                 :  *
           7                 :  * The contents of this file are subject to the Mozilla Public License Version
           8                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           9                 :  * the License. You may obtain a copy of the License at
          10                 :  * http://www.mozilla.org/MPL/
          11                 :  *
          12                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          13                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          14                 :  * for the specific language governing rights and limitations under the
          15                 :  * License.
          16                 :  *
          17                 :  * The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
          18                 :  * May 28, 2008.
          19                 :  *
          20                 :  * The Initial Developer of the Original Code is
          21                 :  *   Brendan Eich <brendan@mozilla.org>
          22                 :  *
          23                 :  * Contributor(s):
          24                 :  *
          25                 :  * Alternatively, the contents of this file may be used under the terms of
          26                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          27                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          28                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          29                 :  * of those above. If you wish to allow use of your version of this file only
          30                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          31                 :  * use your version of this file under the terms of the MPL, indicate your
          32                 :  * decision by deleting the provisions above and replace them with the notice
          33                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          34                 :  * the provisions above, a recipient may use your version of this file under
          35                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          36                 :  *
          37                 :  * ***** END LICENSE BLOCK ***** */
          38                 :
          39                 : #include "MethodJIT.h"
          40                 : #include "Logging.h"
          41                 : #include "assembler/jit/ExecutableAllocator.h"
          42                 : #include "assembler/assembler/RepatchBuffer.h"
          43                 : #include "js/MemoryMetrics.h"
          44                 : #include "jsgcmark.h"
          45                 : #include "BaseAssembler.h"
          46                 : #include "Compiler.h"
          47                 : #include "MonoIC.h"
          48                 : #include "PolyIC.h"
          49                 : #include "TrampolineCompiler.h"
          50                 : #include "jscntxtinlines.h"
          51                 : #include "jscompartment.h"
          52                 : #include "jsscope.h"
          53                 :
          54                 : #include "jsgcinlines.h"
          55                 : #include "jsinterpinlines.h"
          56                 :
          57                 : using namespace js;
          58                 : using namespace js::mjit;
          59                 :
          60                 : #ifdef __GCC_HAVE_DWARF2_CFI_ASM
          61                 : # define CFI(str) str
          62                 : #else
          63                 : # define CFI(str)
          64                 : #endif
          65                 :
          66                 : // Put manually-inserted call frame unwinding information into .debug_frame
          67                 : // rather than .eh_frame, because we compile with -fno-exceptions which might
          68                 : // discard the .eh_frame section. (See
          69                 : // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=43232).
          70                 : CFI(asm(".cfi_sections .debug_frame");)
          71                 :
          72         3302207 : js::mjit::CompilerAllocPolicy::CompilerAllocPolicy(JSContext *cx, Compiler &compiler)
          73                 : : TempAllocPolicy(cx),
          74         3302207 :   oomFlag(&compiler.oomInVector)
          75                 : {
          76         3302207 : }
          77                 : void
          78               0 : StackFrame::methodjitStaticAsserts()
          79                 : {
          80                 :         /* Static assert for x86 trampolines in MethodJIT.cpp. */
          81                 : #if defined(JS_CPU_X86)
          82                 :         JS_STATIC_ASSERT(offsetof(StackFrame, rval_)     == 0x18);
          83                 :         JS_STATIC_ASSERT(offsetof(StackFrame, rval_) + 4 == 0x1C);
          84                 :         JS_STATIC_ASSERT(offsetof(StackFrame, ncode_)    == 0x14);
          85                 :         /* ARM uses decimal literals. */
          86                 :         JS_STATIC_ASSERT(offsetof(StackFrame, rval_)     == 24);
          87                 :         JS_STATIC_ASSERT(offsetof(StackFrame, rval_) + 4 == 28);
          88                 :         JS_STATIC_ASSERT(offsetof(StackFrame, ncode_)    == 20);
          89                 : #elif defined(JS_CPU_X64)
          90                 :         JS_STATIC_ASSERT(offsetof(StackFrame, rval_)     == 0x30);
          91                 :         JS_STATIC_ASSERT(offsetof(StackFrame, ncode_)    == 0x28);
          92                 : #endif
          93               0 : }
          94                 :
          95                 : /*
          96                 :  * Explanation of VMFrame activation and various helper thunks below.
          97                 :  *
          98                 :  * JaegerTrampoline  - Executes a method JIT-compiled JSFunction. This function
          99                 :  *    creates a VMFrame on the machine stack and jumps into JIT'd code. The JIT'd
         100                 :  *    code will eventually jump back to JaegerTrampolineReturn, clean up the
         101                 :  *    VMFrame and return into C++.
         102                 :  *
         103                 :  *  - Called from C++ function EnterMethodJIT.
         104                 :  *  - Parameters: cx, fp, code, stackLimit
         105                 :  *
         106                 :  * JaegerThrowpoline - Calls into an exception handler from JIT'd code, and if a
         107                 :  *    scripted exception handler is not found, unwinds the VMFrame and returns
         108                 :  *    to C++.
         109                 :  *
         110                 :  *  - To start exception handling, we return from a stub call to the throwpoline.
         111                 :  *  - On entry to the throwpoline, the normal conditions of the jit-code ABI
         112                 :  *    are satisfied.
         113                 :  *  - To do the unwinding and find out where to continue executing, we call
         114                 :  *    js_InternalThrow.
         115                 :  *  - js_InternalThrow may return 0, which means the place to continue, if any,
         116                 :  *    is above this JaegerShot activation, so we just return, in the same way
         117                 :  *    the trampoline does.
         118                 :  *  - Otherwise, js_InternalThrow returns a jit-code address to continue execution
         119                 :  *    at. Because the jit-code ABI conditions are satisfied, we can just jump to
         120                 :  *    that point.
         121                 :  *
         122                 :  * JaegerInterpoline - After returning from a stub or scripted call made by JIT'd
         123                 :  *    code, calls into Interpret and has it finish execution of the JIT'd script.
         124                 :  *    If we have to throw away the JIT code for a script for some reason (either
         125                 :  *    a new trap is added for debug code, or assumptions made by the JIT code
         126                 :  *    have broken and forced its invalidation), the call returns into the
         127                 :  *    Interpoline which calls Interpret to finish the JIT frame. The Interpret
         128                 :  *    call may eventually recompile the script, in which case it will join into
         129                 :  *    that code with a new VMFrame activation and JaegerTrampoline.
         130                 :  *
         131                 :  *  - Returned into from stub calls originally made from JIT code.
         132                 :  *  - An alternate version, JaegerInterpolineScripted, returns from scripted
         133                 :  *    calls originally made from JIT code, and fixes up state to match the
         134                 :  *    stub call ABI.
         135                 :  */
         136                 :
         137                 : #ifdef JS_METHODJIT_PROFILE_STUBS
         138                 : static const size_t STUB_CALLS_FOR_OP_COUNT = 255;
         139                 : static uint32_t StubCallsForOp[STUB_CALLS_FOR_OP_COUNT];
         140                 : #endif
         141                 :
         142                 : // Called from JaegerTrampoline only
         143                 : extern "C" void JS_FASTCALL
         144         4318354 : PushActiveVMFrame(VMFrame &f)
         145                 : {
         146         4318354 :     f.oldregs = &f.cx->stack.regs();
         147         4318354 :     f.cx->stack.repointRegs(&f.regs);
         148         4318354 :     f.entryfp->script()->compartment()->jaegerCompartment()->pushActiveFrame(&f);
         149         4318354 :     f.entryfp->setNativeReturnAddress(JS_FUNC_TO_DATA_PTR(void*, JaegerTrampolineReturn));
         150         4318354 :     f.regs.clearInlined();
         151         4318354 : }
         152                 :
         153                 : // Called from JaegerTrampolineReturn, JaegerThrowpoline, JaegerInterpoline
         154                 : extern "C" void JS_FASTCALL
         155         4318354 : PopActiveVMFrame(VMFrame &f)
         156                 : {
         157         4318354 :     f.entryfp->script()->compartment()->jaegerCompartment()->popActiveFrame();
         158         4318354 :     f.cx->stack.repointRegs(f.oldregs);
         159         4318354 : }
         160                 :
         161                 : #if defined(__APPLE__) || (defined(XP_WIN) && !defined(JS_CPU_X64)) || defined(XP_OS2)
         162                 : # define SYMBOL_STRING(name) "_" #name
         163                 : #else
         164                 : # define SYMBOL_STRING(name) #name
         165                 : #endif
         166                 :
         167                 : JS_STATIC_ASSERT(offsetof(FrameRegs, sp) == 0);
         168                 :
         169                 : #if defined(__linux__) && defined(JS_CPU_X64)
         170                 : # define SYMBOL_STRING_RELOC(name) #name "@plt"
         171                 : #else
         172                 : # define SYMBOL_STRING_RELOC(name) SYMBOL_STRING(name)
         173                 : #endif
         174                 :
         175                 : #if (defined(XP_WIN) || defined(XP_OS2)) && defined(JS_CPU_X86)
         176                 : # define SYMBOL_STRING_VMFRAME(name) "@" #name "@4"
         177                 : #else
         178                 : # define SYMBOL_STRING_VMFRAME(name) SYMBOL_STRING_RELOC(name)
         179                 : #endif
         180                 :
         181                 : #if defined(XP_MACOSX)
         182                 : # define HIDE_SYMBOL(name) ".private_extern _" #name
         183                 : #elif defined(__linux__)
         184                 : # define HIDE_SYMBOL(name) ".hidden" #name
         185                 : #else
         186                 : # define HIDE_SYMBOL(name)
         187                 : #endif
         188                 :
         189                 : /*
         190                 :  * Notes about DWARF Call Frame Information (CFI) annotations:
         191                 :  *
         192                 :  * A .cfi directive placed in assembly code describes how to recover the
         193                 :  * caller's registers when control is at or after that directive. That is,
         194                 :  * they describe the states that hold between one instruction and the next,
         195                 :  * not the instructions themselves. Later directives override earlier
         196                 :  * directives.
         197                 :  *
         198                 :  * In DWARF CFI, each stack frame has a Canonical Frame Address (CFA) that
         199                 :  * remains constant throughout the frame's lifetime. Exactly where it is is
         200                 :  * a matter of convention; on the x86 and x86_64, for example, the CFA
         201                 :  * points just after the end of the current stack frame: the address of the
         202                 :  * next word after the return address. The CFI annotations describe 1) how
         203                 :  * to compute the CFA at each point in the function, and 2) given the CFA,
         204                 :  * where the caller's value of each register has been saved. (CFI specifies
         205                 :  * saved registers' locations relative to the CFA, instead of the stack
         206                 :  * pointer, so that when we push or pop the stack, we need only adjust our
         207                 :  * rule for computing the CFA, not the rule for each saved register.)
         208                 :  *
         209                 :  * Quick reference:
         210                 :  *
         211                 :  * .cfi_startproc, .cfi_endproc
         212                 :  *   Put these at the beginning and end of the block of code you're
         213                 :  *   annotating.
         214                 :  *
         215                 :  * (The following directives apply starting at the point they appear until
         216                 :  * they are overridden or until the .cfi_endproc.)
         217                 :  *
         218                 :  * .cfi_def_cfa REGISTER, OFFSET
         219                 :  *   The CFA is the value of REGISTER plus OFFSET.
         220                 :  *
         221                 :  * .cfi_def_cfa_offset OFFSET
         222                 :  *   The CFA is the value of the same register as before, but now adding OFFSET.
         223                 :  *
         224                 :  * .cfi_def_cfa_register REGISTER
         225                 :  *   The CFA is now the value of REGISTER, adding the same offset as before.
         226                 :  *
         227                 :  * .cfi_offset REGISTER, OFFSET
         228                 :  *   The caller's value of REGISTER is saved at OFFSET from the current CFA.
         229                 :  *   (This is the directive that actually says something interesting.)
         230                 :  *
         231                 :  * There are other directives that compute the CFA, a saved register's address,
         232                 :  * or a saved register's value, in more complex ways, but the above are the ones
         233                 :  * we use here.
         234                 :  *
         235                 :  * Special rules for JaegerThrowpoline and friends:
         236                 :  *
         237                 :  * In ordinary code, return addresses always point directly after a call
         238                 :  * instruction. When GDB looks up the CFI for a return address it got from the
         239                 :  * stack (as opposed to the current PC), it uses the CFI just before the return
         240                 :  * address --- the CFI associated with the call instruction --- to do the
         241                 :  * unwinding. However, JaegerMonkey uses hacks that edit return addresses to
         242                 :  * point directly at the first instruction of JaegerThrowpoline,
         243                 :  * JaegerInterpoline, and their ilk, so GDB ends up trying to use the CFI
         244                 :  * associated with whatever instruction lies immediately *before* the given
         245                 :  * entry point.
         246                 :  *
         247                 :  * We make sure our CFI covers the code address GDB will actually use, by
         248                 :  * placing a 'nop' *before* the entry point --- it is never executed --- and
         249                 :  * having our CFI apply starting at that nop.
         250                 :  */
         251                 :
         252                 : #if defined(__GNUC__) && !defined(_WIN64)
         253                 :
         254                 : /* If this assert fails, you need to realign VMFrame to 16 bytes. */
         255                 : #if defined(JS_CPU_ARM) || defined(JS_CPU_MIPS) || defined(JS_CPU_SPARC)
         256                 : JS_STATIC_ASSERT(sizeof(VMFrame) % 8 == 0);
         257                 : #else
         258                 : JS_STATIC_ASSERT(sizeof(VMFrame) % 16 == 0);
         259                 : #endif
         260                 :
         261                 : # if defined(JS_CPU_X64)
         262                 :
         263                 : /*
         264                 :  *    *** DANGER ***
         265                 :  * If these assertions break, update the constants below.
         266                 :  *    *** DANGER ***
         267                 :  */
         268                 : JS_STATIC_ASSERT(offsetof(VMFrame, savedRBX) == 0x68);
         269                 : JS_STATIC_ASSERT(offsetof(VMFrame, scratch) == 0x18);
         270                 : JS_STATIC_ASSERT(VMFrame::offsetOfFp == 0x38);
         271                 :
         272                 : JS_STATIC_ASSERT(JSVAL_TAG_MASK == 0xFFFF800000000000LL);
         273                 : JS_STATIC_ASSERT(JSVAL_PAYLOAD_MASK == 0x00007FFFFFFFFFFFLL);
         274                 :
         275                 : asm (
         276                 : ".text\n"
         277                 : ".globl " SYMBOL_STRING(JaegerTrampoline) "\n"
         278                 : SYMBOL_STRING(JaegerTrampoline) ":"       "\n"
         279                 :     /* Prologue. */
         280                 :     CFI(".cfi_startproc"                 "\n")
         281                 :     CFI(".cfi_def_cfa rsp, 8"            "\n")
         282                 :     "pushq %rbp"                         "\n"
         283                 :     CFI(".cfi_def_cfa_offset 16"         "\n")
         284                 :     CFI(".cfi_offset rbp, -16"           "\n")
         285                 :     "movq %rsp, %rbp"                    "\n"
         286                 :     CFI(".cfi_def_cfa_register rbp"      "\n")
         287                 :     /* Save non-volatile registers. */
         288                 :     "pushq %r12"                         "\n"
         289                 :     CFI(".cfi_offset r12, -24"           "\n")
         290                 :     "pushq %r13"                         "\n"
         291                 :     CFI(".cfi_offset r13, -32"           "\n")
         292                 :     "pushq %r14"                         "\n"
         293                 :     CFI(".cfi_offset r14, -40"           "\n")
         294                 :     "pushq %r15"                         "\n"
         295                 :     CFI(".cfi_offset r15, -48"           "\n")
         296                 :     "pushq %rbx"                         "\n"
         297                 :     CFI(".cfi_offset rbx, -56"           "\n")
         298                 :
         299                 :     /* Load mask registers. */
         300                 :     "movq $0xFFFF800000000000, %r13"     "\n"
         301                 :     "movq $0x00007FFFFFFFFFFF, %r14"     "\n"
         302                 :
         303                 :     /* Build the JIT frame.
         304                 :      * rdi = cx
         305                 :      * rsi = fp
         306                 :      * rcx = inlineCallCount
         307                 :      * fp must go into rbx
         308                 :      */
         309                 :     "pushq $0x0"                         "\n" /* stubRejoin */
         310                 :     "pushq %rsi"                         "\n" /* entryncode */
         311                 :     "pushq %rsi"                         "\n" /* entryfp */
         312                 :     "pushq %rcx"                         "\n" /* inlineCallCount */
         313                 :     "pushq %rdi"                         "\n" /* cx */
         314                 :     "pushq %rsi"                         "\n" /* fp */
         315                 :     "movq  %rsi, %rbx"                   "\n"
         316                 :
         317                 :     /* Space for the rest of the VMFrame. */
         318                 :     "subq  $0x28, %rsp"                  "\n"
         319                 :
         320                 :     /* This is actually part of the VMFrame. */
         321                 :     "pushq %r8"                          "\n"
         322                 :
         323                 :     /* Set cx->regs and set the active frame. Save rdx and align frame in one. */
         324                 :     "pushq %rdx"                         "\n"
         325                 :     "movq  %rsp, %rdi"                   "\n"
         326                 :     "call " SYMBOL_STRING_VMFRAME(PushActiveVMFrame) "\n"
         327                 :
         328                 :     /* Jump into the JIT'd code. */
         329                 :     "jmp *0(%rsp)"                      "\n"
         330                 :     CFI(".cfi_endproc"                  "\n")
         331                 : );
         332                 :
         333                 : asm (
         334                 : ".text\n"
         335                 :     /* See "Special rules for JaegerThrowpoline and friends", above. */
         336                 :     CFI(".cfi_startproc"                 "\n")
         337                 :     CFI(".cfi_def_cfa rbp, 16"           "\n")
         338                 :     CFI(".cfi_offset rbp, -16"           "\n")
         339                 :     CFI(".cfi_offset r12, -24"           "\n")
         340                 :     CFI(".cfi_offset r13, -32"           "\n")
         341                 :     CFI(".cfi_offset r14, -40"           "\n")
         342                 :     CFI(".cfi_offset r15, -48"           "\n")
         343                 :     CFI(".cfi_offset rbx, -56"           "\n")
         344                 :     CFI("nop"                            "\n")
         345                 : ".globl " SYMBOL_STRING(JaegerTrampolineReturn) "\n"
         346                 : SYMBOL_STRING(JaegerTrampolineReturn) ":"       "\n"
         347                 :     "or   %rdi, %rsi"                    "\n"
         348                 :     "movq %rsi, 0x30(%rbx)"              "\n"
         349                 :     "movq %rsp, %rdi"                    "\n"
         350                 :     "call " SYMBOL_STRING_VMFRAME(PopActiveVMFrame) "\n"
         351                 :
         352                 :     "addq $0x68, %rsp"                   "\n"
         353                 :     "popq %rbx"                          "\n"
         354                 :     "popq %r15"                          "\n"
         355                 :     "popq %r14"                          "\n"
         356                 :     "popq %r13"                          "\n"
         357                 :     "popq %r12"                          "\n"
         358                 :     "popq %rbp"                          "\n"
         359                 :     CFI(".cfi_def_cfa rsp, 8"            "\n")
         360                 :     "movq $1, %rax"                      "\n"
         361                 :     "ret"                                "\n"
         362                 :     CFI(".cfi_endproc"                   "\n")
         363                 : );
         364                 :
         365                 : asm (
         366                 : ".text\n"
         367                 :     /* See "Special rules for JaegerThrowpoline and friends", above. */
         368                 :     CFI(".cfi_startproc"                    "\n")
         369                 :     CFI(".cfi_def_cfa rbp, 16"              "\n")
         370                 :     CFI(".cfi_offset rbp, -16"              "\n")
         371                 :     CFI(".cfi_offset r12, -24"              "\n")
         372                 :     CFI(".cfi_offset r13, -32"              "\n")
         373                 :     CFI(".cfi_offset r14, -40"              "\n")
         374                 :     CFI(".cfi_offset r15, -48"              "\n")
         375                 :     CFI(".cfi_offset rbx, -56"              "\n")
         376                 :     CFI("nop"                               "\n")
         377                 : ".globl " SYMBOL_STRING(JaegerThrowpoline)  "\n"
         378                 : SYMBOL_STRING(JaegerThrowpoline) ":"        "\n"
         379                 :     "movq %rsp, %rdi"                       "\n"
         380                 :     "call " SYMBOL_STRING_RELOC(js_InternalThrow) "\n"
         381                 :     "testq %rax, %rax"                      "\n"
         382                 :     "je   throwpoline_exit"                 "\n"
         383                 :     "jmp  *%rax"                            "\n"
         384                 :   "throwpoline_exit:"                       "\n"
         385                 :     "movq %rsp, %rdi"                       "\n"
         386                 :     "call " SYMBOL_STRING_VMFRAME(PopActiveVMFrame) "\n"
         387                 :     "addq $0x68, %rsp"                      "\n"
         388                 :     "popq %rbx"                             "\n"
         389                 :     "popq %r15"                             "\n"
         390                 :     "popq %r14"                             "\n"
         391                 :     "popq %r13"                             "\n"
         392                 :     "popq %r12"                             "\n"
         393                 :     "popq %rbp"                             "\n"
         394                 :     CFI(".cfi_def_cfa rsp, 8"               "\n")
         395                 :     "xorq %rax,%rax"                        "\n"
         396                 :     "ret"                                   "\n"
         397                 :     CFI(".cfi_endproc"                      "\n")
         398                 : );
         399                 :
         400                 : asm (
         401                 : ".text\n"
         402                 :     /* See "Special rules for JaegerThrowpoline and friends", above. */
         403                 :     CFI(".cfi_startproc"                    "\n")
         404                 :     CFI(".cfi_def_cfa rbp, 16"              "\n")
         405                 :     CFI(".cfi_offset rbp, -16"              "\n")
         406                 :     CFI(".cfi_offset r12, -24"              "\n")
         407                 :     CFI(".cfi_offset r13, -32"              "\n")
         408                 :     CFI(".cfi_offset r14, -40"              "\n")
         409                 :     CFI(".cfi_offset r15, -48"              "\n")
         410                 :     CFI(".cfi_offset rbx, -56"              "\n")
         411                 :     CFI("nop"                               "\n")
         412                 : ".globl " SYMBOL_STRING(JaegerInterpoline)  "\n"
         413                 : SYMBOL_STRING(JaegerInterpoline) ":"        "\n"
         414                 :     "movq %rsp, %rcx"                       "\n"
         415                 :     "movq %rax, %rdx"                       "\n"
         416                 :     "call " SYMBOL_STRING_RELOC(js_InternalInterpret) "\n"
         417                 :     "movq 0x38(%rsp), %rbx"                 "\n" /* Load frame */
         418                 :     "movq 0x30(%rbx), %rsi"                 "\n" /* Load rval payload */
         419                 :     "and %r14, %rsi"                        "\n" /* Mask rval payload */
         420                 :     "movq 0x30(%rbx), %rdi"                 "\n" /* Load rval type */
         421                 :     "and %r13, %rdi"                        "\n" /* Mask rval type */
         422                 :     "movq 0x18(%rsp), %rcx"                 "\n" /* Load scratch -> argc */
         423                 :     "testq %rax, %rax"                      "\n"
         424                 :     "je   interpoline_exit"                 "\n"
         425                 :     "jmp  *%rax"                            "\n"
         426                 :   "interpoline_exit:"                       "\n"
         427                 :     "movq %rsp, %rdi"                       "\n"
         428                 :     "call " SYMBOL_STRING_VMFRAME(PopActiveVMFrame) "\n"
         429                 :     "addq $0x68, %rsp"                      "\n"
         430                 :     "popq %rbx"                             "\n"
         431                 :     "popq %r15"                             "\n"
         432                 :     "popq %r14"                             "\n"
         433                 :     "popq %r13"                             "\n"
         434                 :     "popq %r12"                             "\n"
         435                 :     "popq %rbp"                             "\n"
         436                 :     CFI(".cfi_def_cfa rsp, 8"               "\n")
         437                 :     "xorq %rax,%rax"                        "\n"
         438                 :     "ret"                                   "\n"
         439                 :     CFI(".cfi_endproc"                      "\n")
         440                 : );
         441                 :
         442                 : asm (
         443                 : ".text\n"
         444                 :     /* See "Special rules for JaegerThrowpoline and friends", above. */
         445                 :     CFI(".cfi_startproc"                            "\n")
         446                 :     CFI(".cfi_def_cfa rbp, 16"                      "\n")
         447                 :     CFI(".cfi_offset rbp, -16"                      "\n")
         448                 :     CFI(".cfi_offset r12, -24"                      "\n")
         449                 :     CFI(".cfi_offset r13, -32"                      "\n")
         450                 :     CFI(".cfi_offset r14, -40"                      "\n")
         451                 :     CFI(".cfi_offset r15, -48"                      "\n")
         452                 :     CFI(".cfi_offset rbx, -56"                      "\n")
         453                 :     CFI("nop"                                       "\n")
         454                 : ".globl " SYMBOL_STRING(JaegerInterpolineScripted)  "\n"
         455                 : SYMBOL_STRING(JaegerInterpolineScripted) ":"        "\n"
         456                 :     "movq 0x20(%rbx), %rbx"                         "\n" /* load prev */
         457                 :     "movq %rbx, 0x38(%rsp)"                         "\n"
         458                 :     "jmp " SYMBOL_STRING_RELOC(JaegerInterpoline)   "\n"
         459                 :     CFI(".cfi_endproc"                              "\n")
         460                 : );
         461                 :
         462                 : # elif defined(JS_CPU_X86)
         463                 :
         464                 : /*
         465                 :  *    *** DANGER ***
         466                 :  * If these assertions break, update the constants below. The throwpoline
         467                 :  * should have the offset of savedEBX plus 4, because it needs to clean
         468                 :  * up the argument.
         469                 :  *    *** DANGER ***
         470                 :  */
         471                 : JS_STATIC_ASSERT(offsetof(VMFrame, savedEBX) == 0x3C);
         472                 : JS_STATIC_ASSERT(offsetof(VMFrame, scratch) == 0xC);
         473                 : JS_STATIC_ASSERT(VMFrame::offsetOfFp == 0x1C);
         474                 :
         475                 : asm (
         476                 : ".text\n"
         477                 : ".globl " SYMBOL_STRING(JaegerTrampoline) "\n"
         478                 : SYMBOL_STRING(JaegerTrampoline) ":"       "\n"
         479                 :     /* Prologue. */
         480                 :     CFI(".cfi_startproc"                 "\n")
         481                 :     CFI(".cfi_def_cfa esp, 4"            "\n")
         482                 :     "pushl %ebp"                         "\n"
         483                 :     CFI(".cfi_def_cfa_offset 8"          "\n")
         484                 :     CFI(".cfi_offset ebp, -8"            "\n")
         485                 :     "movl %esp, %ebp"                    "\n"
         486                 :     CFI(".cfi_def_cfa_register ebp"      "\n")
         487                 :     /* Save non-volatile registers. */
         488                 :     "pushl %esi"                         "\n"
         489                 :     CFI(".cfi_offset esi, -12"           "\n")
         490                 :     "pushl %edi"                         "\n"
         491                 :     CFI(".cfi_offset edi, -16"           "\n")
         492                 :     "pushl %ebx"                         "\n"
         493                 :     CFI(".cfi_offset ebx, -20"           "\n")
         494                 :
         495                 :     /* Build the JIT frame. Push fields in order,
         496                 :      * then align the stack to form esp == VMFrame. */
         497                 :     "movl  12(%ebp), %ebx"               "\n"   /* load fp */
         498                 :     "pushl %ebx"                         "\n"   /* unused1 */
         499                 :     "pushl %ebx"                         "\n"   /* unused0 */
         500                 :     "pushl $0x0"                         "\n"   /* stubRejoin */
         501                 :     "pushl %ebx"                         "\n"   /* entryncode */
         502                 :     "pushl %ebx"                         "\n"   /* entryfp */
         503                 :     "pushl 20(%ebp)"                     "\n"   /* stackLimit */
         504                 :     "pushl 8(%ebp)"                      "\n"   /* cx */
         505                 :     "pushl %ebx"                         "\n"   /* fp */
         506                 :     "subl $0x1C, %esp"                   "\n"
         507                 :
         508                 :     /* Jump into the JIT'd code. */
         509                 :     "movl  %esp, %ecx"                   "\n"
         510                 :     "call " SYMBOL_STRING_VMFRAME(PushActiveVMFrame) "\n"
         511                 :
         512                 :     "movl 28(%esp), %ebp"                "\n"   /* load fp for JIT code */
         513                 :     "jmp *88(%esp)"                      "\n"
         514                 :     CFI(".cfi_endproc"                   "\n")
         515                 : );
         516                 :
         517                 : asm (
         518                 : ".text\n"
         519                 :     /* See "Special rules for JaegerThrowpoline and friends", above. */
         520                 :     CFI(".cfi_startproc"                 "\n")
         521                 :     CFI(".cfi_def_cfa ebp, 8"            "\n")
         522                 :     CFI(".cfi_offset ebp, -8"            "\n")
         523                 :     CFI(".cfi_offset esi, -12"           "\n")
         524                 :     CFI(".cfi_offset edi, -16"           "\n")
         525                 :     CFI(".cfi_offset ebx, -20"           "\n")
         526                 :     CFI("nop"                            "\n")
         527                 : ".globl " SYMBOL_STRING(JaegerTrampolineReturn) "\n"
         528                 : SYMBOL_STRING(JaegerTrampolineReturn) ":" "\n"
         529                 :     "movl  %esi, 0x18(%ebp)"             "\n"
         530                 :     "movl  %edi, 0x1C(%ebp)"             "\n"
         531                 :     "movl  %esp, %ebp"                   "\n"
         532                 :     "addl  $0x48, %ebp"                  "\n" /* Restore stack at STACK_BASE_DIFFERENCE */
         533                 :     "movl  %esp, %ecx"                   "\n"
         534                 :     "call " SYMBOL_STRING_VMFRAME(PopActiveVMFrame) "\n"
         535                 :
         536                 :     "addl $0x3C, %esp"                   "\n"
         537                 :     "popl %ebx"                          "\n"
         538                 :     "popl %edi"                          "\n"
         539                 :     "popl %esi"                          "\n"
         540                 :     "popl %ebp"                          "\n"
         541                 :     CFI(".cfi_def_cfa esp, 4"            "\n")
         542                 :     "movl $1, %eax"                      "\n"
         543                 :     "ret"                                "\n"
         544                 :     CFI(".cfi_endproc"                   "\n")
         545                 : );
         546                 :
         547                 : asm (
         548                 : ".text\n"
         549                 :     /* See "Special rules for JaegerThrowpoline and friends", above. */
         550                 :     CFI(".cfi_startproc"                 "\n")
         551                 :     CFI(".cfi_def_cfa ebp, 8"            "\n")
         552                 :     CFI(".cfi_offset ebp, -8"            "\n")
         553                 :     CFI(".cfi_offset esi, -12"           "\n")
         554                 :     CFI(".cfi_offset edi, -16"           "\n")
         555                 :     CFI(".cfi_offset ebx, -20"           "\n")
         556                 :     CFI("nop"                            "\n")
         557                 : ".globl " SYMBOL_STRING(JaegerThrowpoline)  "\n"
         558                 : SYMBOL_STRING(JaegerThrowpoline) ":"        "\n"
         559                 :     /* Align the stack to 16 bytes. */
         560                 :     "pushl %esp"                         "\n"
         561                 :     "pushl (%esp)"                       "\n"
         562                 :     "pushl (%esp)"                       "\n"
         563                 :     "pushl (%esp)"                       "\n"
         564                 :     "call " SYMBOL_STRING_RELOC(js_InternalThrow) "\n"
         565                 :     /* Bump the stack by 0x2c, as in the basic trampoline, but
         566                 :      * also one more word to clean up the stack for js_InternalThrow,
         567                 :      * and another to balance the alignment above. */
         568                 :     "addl $0x10, %esp"                   "\n"
         569                 :     "testl %eax, %eax"                   "\n"
         570                 :     "je   throwpoline_exit"              "\n"
         571                 :     "jmp  *%eax"                         "\n"
         572                 :   "throwpoline_exit:"                    "\n"
         573                 :     "movl %esp, %ecx"                    "\n"
         574                 :     "call " SYMBOL_STRING_VMFRAME(PopActiveVMFrame) "\n"
         575                 :     "addl $0x3c, %esp"                   "\n"
         576                 :     "popl %ebx"                          "\n"
         577                 :     "popl %edi"                          "\n"
         578                 :     "popl %esi"                          "\n"
         579                 :     "popl %ebp"                          "\n"
         580                 :     CFI(".cfi_def_cfa esp, 4"            "\n")
         581                 :     "xorl %eax, %eax"                    "\n"
         582                 :     "ret"                                "\n"
         583                 :     CFI(".cfi_endproc"                   "\n")
         584                 : );
         585                 :
         586                 : asm (
         587                 : ".text\n"
         588                 :     /* See "Special rules for JaegerThrowpoline and friends", above. */
         589                 :     CFI(".cfi_startproc"                 "\n")
         590                 :     CFI(".cfi_def_cfa ebp, 8"            "\n")
         591                 :     CFI(".cfi_offset ebp, -8"            "\n")
         592                 :     CFI(".cfi_offset esi, -12"           "\n")
         593                 :     CFI(".cfi_offset edi, -16"           "\n")
         594                 :     CFI(".cfi_offset ebx, -20"           "\n")
         595                 :     CFI("nop"                            "\n")
         596                 : ".globl " SYMBOL_STRING(JaegerInterpoline)  "\n"
         597                 : SYMBOL_STRING(JaegerInterpoline) ":"        "\n"
         598                 :     /* Align the stack to 16 bytes. */
         599                 :     "pushl %esp"                         "\n"
         600                 :     "pushl %eax"                         "\n"
         601                 :     "pushl %edi"                         "\n"
         602                 :     "pushl %esi"                         "\n"
         603                 :     "call " SYMBOL_STRING_RELOC(js_InternalInterpret) "\n"
         604                 :     "addl $0x10, %esp"                   "\n"
         605                 :     "movl 0x1C(%esp), %ebp"              "\n" /* Load frame */
         606                 :     "movl 0x18(%ebp), %esi"              "\n" /* Load rval payload */
         607                 :     "movl 0x1C(%ebp), %edi"              "\n" /* Load rval type */
         608                 :     "movl 0xC(%esp), %ecx"               "\n" /* Load scratch -> argc, for any scripted call */
         609                 :     "testl %eax, %eax"                   "\n"
         610                 :     "je   interpoline_exit"              "\n"
         611                 :     "jmp  *%eax"                         "\n"
         612                 :   "interpoline_exit:"                    "\n"
         613                 :     "movl %esp, %ecx"                    "\n"
         614                 :     "call " SYMBOL_STRING_VMFRAME(PopActiveVMFrame) "\n"
         615                 :     "addl $0x3c, %esp"                   "\n"
         616                 :     "popl %ebx"                          "\n"
         617                 :     "popl %edi"                          "\n"
         618                 :     "popl %esi"                          "\n"
         619                 :     "popl %ebp"                          "\n"
         620                 :     CFI(".cfi_def_cfa esp, 4"            "\n")
         621                 :     "xorl %eax, %eax"                    "\n"
         622                 :     "ret"                                "\n"
         623                 :     CFI(".cfi_endproc"                   "\n")
         624                 : );
         625                 :
         626                 : asm (
         627                 : ".text\n"
         628                 :     /* See "Special rules for JaegerThrowpoline and friends", above. */
         629                 :     CFI(".cfi_startproc"                            "\n")
         630                 :     CFI(".cfi_def_cfa ebp, 8"                       "\n")
         631                 :     CFI(".cfi_offset ebp, -8"                       "\n")
         632                 :     CFI(".cfi_offset esi, -12"                      "\n")
         633                 :     CFI(".cfi_offset edi, -16"                      "\n")
         634                 :     CFI(".cfi_offset ebx, -20"                      "\n")
         635                 :     CFI("nop"                                       "\n")
         636                 : ".globl " SYMBOL_STRING(JaegerInterpolineScripted)  "\n"
         637                 : SYMBOL_STRING(JaegerInterpolineScripted) ":"        "\n"
         638                 :     "movl 0x10(%ebp), %ebp"                         "\n" /* load prev. :XXX: STATIC_ASSERT this */
         639                 :     "movl  %ebp, 0x1C(%esp)"                        "\n"
         640                 :     "jmp " SYMBOL_STRING_RELOC(JaegerInterpoline)   "\n"
         641                 :     CFI(".cfi_endproc"                              "\n")
         642                 : );
         643                 :
         644                 : # elif defined(JS_CPU_ARM)
         645                 :
         646                 : JS_STATIC_ASSERT(sizeof(VMFrame) == 88);
         647                 : JS_STATIC_ASSERT(sizeof(VMFrame)%8 == 0);   /* We need 8-byte stack alignment for EABI. */
         648                 : JS_STATIC_ASSERT(offsetof(VMFrame, savedLR) ==          (4*21));
         649                 : JS_STATIC_ASSERT(offsetof(VMFrame, entryfp) ==          (4*10));
         650                 : JS_STATIC_ASSERT(offsetof(VMFrame, stackLimit) ==       (4*9));
         651                 : JS_STATIC_ASSERT(offsetof(VMFrame, cx) ==               (4*8));
         652                 : JS_STATIC_ASSERT(VMFrame::offsetOfFp ==                 (4*7));
         653                 : JS_STATIC_ASSERT(offsetof(VMFrame, scratch) ==          (4*3));
         654                 : JS_STATIC_ASSERT(offsetof(VMFrame, previous) ==         (4*2));
         655                 :
         656                 : JS_STATIC_ASSERT(JSFrameReg == JSC::ARMRegisters::r10);
         657                 : JS_STATIC_ASSERT(JSReturnReg_Type == JSC::ARMRegisters::r5);
         658                 : JS_STATIC_ASSERT(JSReturnReg_Data == JSC::ARMRegisters::r4);
         659                 :
         660                 : #ifdef MOZ_THUMB2
         661                 : #define FUNCTION_HEADER_EXTRA \
         662                 :   ".align 2\n" \
         663                 :   ".thumb\n" \
         664                 :   ".thumb_func\n"
         665                 : #else
         666                 : #define FUNCTION_HEADER_EXTRA
         667                 : #endif
         668                 :
         669                 : asm (
         670                 : ".text\n"
         671                 : FUNCTION_HEADER_EXTRA
         672                 : ".globl " SYMBOL_STRING(JaegerTrampoline)   "\n"
         673                 : SYMBOL_STRING(JaegerTrampoline) ":"         "\n"
         674                 :     /*
         675                 :      * On entry to JaegerTrampoline:
         676                 :      *         r0 = cx
         677                 :      *         r1 = fp
         678                 :      *         r2 = code
         679                 :      *         r3 = stackLimit
         680                 :      *
         681                 :      * The VMFrame for ARM looks like this:
         682                 :      *  [ lr           ]   \
         683                 :      *  [ r11          ]   |
         684                 :      *  [ r10          ]   |
         685                 :      *  [ r9           ]   | Callee-saved registers.
         686                 :      *  [ r8           ]   | VFP registers d8-d15 may be required here too, but
         687                 :      *  [ r7           ]   | unconditionally preserving them might be expensive
         688                 :      *  [ r6           ]   | considering that we might not use them anyway.
         689                 :      *  [ r5           ]   |
         690                 :      *  [ r4           ]   /
         691                 :      *  [ stubRejoin   ]
         692                 :      *  [ entryncode   ]
         693                 :      *  [ entryfp      ]
         694                 :      *  [ stkLimit     ]
         695                 :      *  [ cx           ]
         696                 :      *  [ regs.fp      ]
         697                 :      *  [ regs.inlined ]
         698                 :      *  [ regs.pc      ]
         699                 :      *  [ regs.sp      ]
         700                 :      *  [ scratch      ]
         701                 :      *  [ previous     ]
         702                 :      *  [ args.ptr2    ]  [ dynamicArgc ]  (union)
         703                 :      *  [ args.ptr     ]  [ lazyArgsObj ]  (union)
         704                 :      */
         705                 :
         706                 :     /* Push callee-saved registers. */
         707                 : "   push    {r4-r11,lr}"                        "\n"
         708                 :     /* Push interesting VMFrame content. */
         709                 : "   mov     ip, #0"                             "\n"
         710                 : "   push    {ip}"                               "\n"    /* stubRejoin */
         711                 : "   push    {r1}"                               "\n"    /* entryncode */
         712                 : "   push    {r1}"                               "\n"    /* entryfp */
         713                 : "   push    {r3}"                               "\n"    /* stackLimit */
         714                 : "   push    {r0}"                               "\n"    /* cx */
         715                 : "   push    {r1}"                               "\n"    /* regs.fp */
         716                 :     /* Remaining fields are set elsewhere, but we need to leave space for them. */
         717                 : "   sub     sp, sp, #(4*7)"                     "\n"
         718                 :
         719                 :     /* Preserve 'code' (r2) in an arbitrary callee-saved register. */
         720                 : "   mov     r4, r2"                             "\n"
         721                 :     /* Preserve 'fp' (r1) in r10 (JSFrameReg). */
         722                 : "   mov     r10, r1"                            "\n"
         723                 :
         724                 : "   mov     r0, sp"                             "\n"
         725                 : "   blx  " SYMBOL_STRING_VMFRAME(PushActiveVMFrame)"\n"
         726                 :
         727                 :     /* Call the compiled JavaScript function. */
         728                 : "   bx     r4"                                  "\n"
         729                 : );
         730                 :
         731                 : asm (
         732                 : ".text\n"
         733                 : FUNCTION_HEADER_EXTRA
         734                 : ".globl " SYMBOL_STRING(JaegerTrampolineReturn)   "\n"
         735                 : SYMBOL_STRING(JaegerTrampolineReturn) ":"         "\n"
         736                 : "   strd    r4, r5, [r10, #24]"             "\n" /* fp->rval type,data */
         737                 :
         738                 :     /* Tidy up. */
         739                 : "   mov     r0, sp"                         "\n"
         740                 : "   blx  " SYMBOL_STRING_VMFRAME(PopActiveVMFrame) "\n"
         741                 :
         742                 :     /* Skip past the parameters we pushed (such as cx and the like). */
         743                 : "   add     sp, sp, #(4*7 + 4*6)"           "\n"
         744                 :
         745                 :     /* Set a 'true' return value to indicate successful completion. */
         746                 : "   mov     r0, #1"                         "\n"
         747                 : "   pop     {r4-r11,pc}"                    "\n"
         748                 : );
         749                 :
         750                 : asm (
         751                 : ".text\n"
         752                 : FUNCTION_HEADER_EXTRA
         753                 : ".globl " SYMBOL_STRING(JaegerThrowpoline)  "\n"
         754                 : SYMBOL_STRING(JaegerThrowpoline) ":"        "\n"
         755                 :     /* Find the VMFrame pointer for js_InternalThrow. */
         756                 : "   mov     r0, sp"                         "\n"
         757                 :
         758                 :     /* Call the utility function that sets up the internal throw routine. */
         759                 : "   blx  " SYMBOL_STRING_RELOC(js_InternalThrow) "\n"
         760                 :
         761                 :     /* If js_InternalThrow found a scripted handler, jump to it. Otherwise, tidy
         762                 :      * up and return. */
         763                 : "   cmp     r0, #0"                         "\n"
         764                 : "   it      ne"                             "\n"
         765                 : "   bxne    r0"                             "\n"
         766                 :
         767                 :     /* Tidy up, then return '0' to represent an unhandled exception. */
         768                 : "   mov     r0, sp"                         "\n"
         769                 : "   blx  " SYMBOL_STRING_VMFRAME(PopActiveVMFrame) "\n"
         770                 : "   add     sp, sp, #(4*7 + 4*6)"           "\n"
         771                 : "   mov     r0, #0"                         "\n"
         772                 : "   pop     {r4-r11,pc}"                    "\n"
         773                 : );
         774                 :
         775                 : asm (
         776                 : ".text\n"
         777                 : FUNCTION_HEADER_EXTRA
         778                 : ".globl " SYMBOL_STRING(JaegerInterpolineScripted)  "\n"
         779                 : SYMBOL_STRING(JaegerInterpolineScripted) ":"        "\n"
         780                 :     /* The only difference between JaegerInterpoline and JaegerInpolineScripted is that the
         781                 :      * scripted variant has to walk up to the previous StackFrame first. */
         782                 : "   ldr     r10, [r10, #(4*4)]"             "\n"    /* Load f->prev_ */
         783                 : "   str     r10, [sp, #(4*7)]"              "\n"    /* Update f->regs->fp_ */
         784                 :     /* Fall through into JaegerInterpoline. */
         785                 :
         786                 : FUNCTION_HEADER_EXTRA
         787                 : ".globl " SYMBOL_STRING(JaegerInterpoline)  "\n"
         788                 : SYMBOL_STRING(JaegerInterpoline) ":"        "\n"
         789                 : "   mov     r3, sp"                         "\n"    /* f */
         790                 : "   mov     r2, r0"                         "\n"    /* returnReg */
         791                 : "   mov     r1, r5"                         "\n"    /* returnType */
         792                 : "   mov     r0, r4"                         "\n"    /* returnData */
         793                 : "   blx  " SYMBOL_STRING_RELOC(js_InternalInterpret) "\n"
         794                 : "   cmp     r0, #0"                         "\n"
         795                 : "   ldr     r10, [sp, #(4*7)]"              "\n"    /* Load (StackFrame*)f->regs->fp_ */
         796                 : "   ldrd    r4, r5, [r10, #(4*6)]"          "\n"    /* Load rval payload and type. */
         797                 : "   ldr     r1, [sp, #(4*3)]"               "\n"    /* Load scratch. */
         798                 : "   it      ne"                             "\n"
         799                 : "   bxne    r0"                             "\n"
         800                 :     /* Tidy up, then return 0. */
         801                 : "   mov     r0, sp"                         "\n"
         802                 : "   blx  " SYMBOL_STRING_VMFRAME(PopActiveVMFrame) "\n"
         803                 : "   add     sp, sp, #(4*7 + 4*6)"           "\n"
         804                 : "   mov     r0, #0"                         "\n"
         805                 : "   pop     {r4-r11,pc}"                    "\n"
         806                 : );
         807                 :
         808                 : asm (
         809                 : ".text\n"
         810                 : FUNCTION_HEADER_EXTRA
         811                 : ".globl " SYMBOL_STRING(JaegerStubVeneer)   "\n"
         812                 : SYMBOL_STRING(JaegerStubVeneer) ":"         "\n"
         813                 :     /* We enter this function as a veneer between a compiled method and one of the js_ stubs. We
         814                 :      * need to store the LR somewhere (so it can be modified in case on an exception) and then
         815                 :      * branch to the js_ stub as if nothing had happened.
         816                 :      * The arguments are identical to those for js_* except that the target function should be in
         817                 :      * 'ip'. */
         818                 : "   push    {ip,lr}"                        "\n"
         819                 : "   blx     ip"                             "\n"
         820                 : "   pop     {ip,pc}"                        "\n"
         821                 : );
         822                 :
         823                 : # elif defined(JS_CPU_SPARC)
         824                 : # elif defined(JS_CPU_MIPS)
         825                 : # else
         826                 : #  error "Unsupported CPU!"
         827                 : # endif
         828                 : #elif defined(_MSC_VER) && defined(JS_CPU_X86)
         829                 :
         830                 : /*
         831                 :  *    *** DANGER ***
         832                 :  * If these assertions break, update the constants below. The throwpoline
         833                 :  * should have the offset of savedEBX plus 4, because it needs to clean
         834                 :  * up the argument.
         835                 :  *    *** DANGER ***
         836                 :  */
         837                 : JS_STATIC_ASSERT(offsetof(VMFrame, savedEBX) == 0x3C);
         838                 : JS_STATIC_ASSERT(offsetof(VMFrame, scratch) == 0xC);
         839                 : JS_STATIC_ASSERT(VMFrame::offsetOfFp == 0x1C);
         840                 :
         841                 : extern "C" {
         842                 :
         843                 :     __declspec(naked) JSBool JaegerTrampoline(JSContext *cx, StackFrame *fp, void *code,
         844                 :                                               Value *stackLimit)
         845                 :     {
         846                 :         __asm {
         847                 :             /* Prologue. */
         848                 :             push ebp;
         849                 :             mov ebp, esp;
         850                 :             /* Save non-volatile registers. */
         851                 :             push esi;
         852                 :             push edi;
         853                 :             push ebx;
         854                 :
         855                 :             /* Build the JIT frame. Push fields in order,
         856                 :              * then align the stack to form esp == VMFrame. */
         857                 :             mov  ebx, [ebp + 12];
         858                 :             push ebx;
         859                 :             push ebx;
         860                 :             push 0x0;
         861                 :             push ebx;
         862                 :             push ebx;
         863                 :             push [ebp + 20];
         864                 :             push [ebp + 8];
         865                 :             push ebx;
         866                 :             sub  esp, 0x1C;
         867                 :
         868                 :             /* Jump into into the JIT'd code. */
         869                 :             mov  ecx, esp;
         870                 :             call PushActiveVMFrame;
         871                 :
         872                 :             mov ebp, [esp + 28];  /* load fp for JIT code */
         873                 :             jmp dword ptr [esp + 88];
         874                 :         }
         875                 :     }
         876                 :
         877                 :     __declspec(naked) void JaegerTrampolineReturn()
         878                 :     {
         879                 :         __asm {
         880                 :             mov [ebp + 0x18], esi;
         881                 :             mov [ebp + 0x1C], edi;
         882                 :             mov  ebp, esp;
         883                 :             add  ebp, 0x48; /* Restore stack at STACK_BASE_DIFFERENCE */
         884                 :             mov  ecx, esp;
         885                 :             call PopActiveVMFrame;
         886                 :
         887                 :             add esp, 0x3C;
         888                 :
         889                 :             pop ebx;
         890                 :             pop edi;
         891                 :             pop esi;
         892                 :             pop ebp;
         893                 :             mov eax, 1;
         894                 :             ret;
         895                 :         }
         896                 :     }
         897                 :
         898                 :     extern "C" void *js_InternalThrow(js::VMFrame &f);
         899                 :
         900                 :     __declspec(naked) void *JaegerThrowpoline(js::VMFrame *vmFrame) {
         901                 :         __asm {
         902                 :             /* Align the stack to 16 bytes. */
         903                 :             push esp;
         904                 :             push [esp];
         905                 :             push [esp];
         906                 :             push [esp];
         907                 :             call js_InternalThrow;
         908                 :             /* Bump the stack by 0x2c, as in the basic trampoline, but
         909                 :              * also one more word to clean up the stack for js_InternalThrow,
         910                 :              * and another to balance the alignment above. */
         911                 :             add esp, 0x10;
         912                 :             test eax, eax;
         913                 :             je throwpoline_exit;
         914                 :             jmp eax;
         915                 :         throwpoline_exit:
         916                 :             mov ecx, esp;
         917                 :             call PopActiveVMFrame;
         918                 :             add esp, 0x3c;
         919                 :             pop ebx;
         920                 :             pop edi;
         921                 :             pop esi;
         922                 :             pop ebp;
         923                 :             xor eax, eax
         924                 :             ret;
         925                 :         }
         926                 :     }
         927                 :
         928                 :     extern "C" void *
         929                 :     js_InternalInterpret(void *returnData, void *returnType, void *returnReg, js::VMFrame &f);
         930                 :
         931                 :     __declspec(naked) void JaegerInterpoline() {
         932                 :         __asm {
         933                 :             /* Align the stack to 16 bytes. */
         934                 :             push esp;
         935                 :             push eax;
         936                 :             push edi;
         937                 :             push esi;
         938                 :             call js_InternalInterpret;
         939                 :             add esp, 0x10;
         940                 :             mov ebp, [esp + 0x1C];  /* Load frame */
         941                 :             mov esi, [ebp + 0x18];  /* Load rval payload */
         942                 :             mov edi, [ebp + 0x1C];  /* Load rval type */
         943                 :             mov ecx, [esp + 0xC];   /* Load scratch -> argc */
         944                 :             test eax, eax;
         945                 :             je interpoline_exit;
         946                 :             jmp eax;
         947                 :         interpoline_exit:
         948                 :             mov ecx, esp;
         949                 :             call PopActiveVMFrame;
         950                 :             add esp, 0x3c;
         951                 :             pop ebx;
         952                 :             pop edi;
         953                 :             pop esi;
         954                 :             pop ebp;
         955                 :             xor eax, eax
         956                 :             ret;
         957                 :         }
         958                 :     }
         959                 :
         960                 :     __declspec(naked) void JaegerInterpolineScripted() {
         961                 :         __asm {
         962                 :             mov ebp, [ebp + 0x10];  /* Load prev */
         963                 :             mov [esp + 0x1C], ebp;  /* fp -> regs.fp */
         964                 :             jmp JaegerInterpoline;
         965                 :         }
         966                 :     }
         967                 : }
         968                 :
         969                 : // Windows x64 uses assembler version since compiler doesn't support
         970                 : // inline assembler
         971                 : #elif defined(_WIN64)
         972                 :
         973                 : /*
         974                 :  *    *** DANGER ***
         975                 :  * If these assertions break, update the constants below.
         976                 :  *    *** DANGER ***
         977                 :  */
         978                 : JS_STATIC_ASSERT(offsetof(VMFrame, savedRBX) == 0x68);
         979                 : JS_STATIC_ASSERT(offsetof(VMFrame, scratch) == 0x18);
         980                 : JS_STATIC_ASSERT(VMFrame::offsetOfFp == 0x38);
         981                 : JS_STATIC_ASSERT(JSVAL_TAG_MASK == 0xFFFF800000000000LL);
         982                 : JS_STATIC_ASSERT(JSVAL_PAYLOAD_MASK == 0x00007FFFFFFFFFFFLL);
         983                 :
         984                 : #endif                   /* _WIN64 */
         985                 :
         986           11829 : JaegerCompartment::JaegerCompartment()
         987           11829 :     : orphanedNativeFrames(SystemAllocPolicy()), orphanedNativePools(SystemAllocPolicy())
         988           11829 : {}
         989                 :
         990                 : bool
         991           11829 : JaegerCompartment::Initialize(JSContext *cx)
         992                 : {
         993                 :     execAlloc_ = js::OffTheBooks::new_<JSC::ExecutableAllocator>(
         994           11829 :         cx->runtime->getJitHardening() ? JSC::AllocationCanRandomize : JSC::AllocationDeterministic);
         995           11829 :     if (!execAlloc_)
         996               0 :         return false;
         997                 :
         998           11829 :     TrampolineCompiler tc(execAlloc_, &trampolines);
         999           11829 :     if (!tc.compile()) {
        1000               0 :         js::Foreground::delete_(execAlloc_);
        1001               0 :         execAlloc_ = NULL;
        1002               0 :         return false;
        1003                 :     }
        1004                 :
        1005                 : #ifdef JS_METHODJIT_PROFILE_STUBS
        1006                 :     for (size_t i = 0; i < STUB_CALLS_FOR_OP_COUNT; ++i)
        1007                 :         StubCallsForOp[i] = 0;
        1008                 : #endif
        1009                 :
        1010           11829 :     activeFrame_ = NULL;
        1011           11829 :     lastUnfinished_ = (JaegerStatus) 0;
        1012                 :
        1013           11829 :     return true;
        1014                 : }
        1015                 :
        1016                 : void
        1017           11829 : JaegerCompartment::Finish()
        1018                 : {
        1019           11829 :     TrampolineCompiler::release(&trampolines);
        1020           11829 :     Foreground::delete_(execAlloc_);
        1021                 : #ifdef JS_METHODJIT_PROFILE_STUBS
        1022                 :     FILE *fp = fopen("/tmp/stub-profiling", "wt");
        1023                 : # define OPDEF(op,val,name,image,length,nuses,ndefs,prec,format) \
        1024                 :     fprintf(fp, "%03d %s %d\n", val, #op, StubCallsForOp[val]);
        1025                 : # include "jsopcode.tbl"
        1026                 : # undef OPDEF
        1027                 :     fclose(fp);
        1028                 : #endif
        1029           11829 : }
        1030                 :
        1031                 : extern "C" JSBool
        1032                 : JaegerTrampoline(JSContext *cx, StackFrame *fp, void *code, Value *stackLimit);
        1033                 :
        1034                 : JaegerStatus
        1035         4318354 : mjit::EnterMethodJIT(JSContext *cx, StackFrame *fp, void *code, Value *stackLimit, bool partial)
        1036                 : {
        1037                 : #ifdef JS_METHODJIT_SPEW
        1038                 :     Profiler prof;
        1039         4318354 :     JSScript *script = fp->script();
        1040                 :
        1041                 :     JaegerSpew(JSpew_Prof, "%s jaeger script, line %d\n",
        1042         4318354 :                script->filename, script->lineno);
        1043         4318354 :     prof.start();
        1044                 : #endif
        1045                 :
        1046         4318354 :     JS_ASSERT(cx->fp() == fp);
        1047                 :
        1048                 :     JSBool ok;
        1049                 :     {
        1050         8636708 :         AssertCompartmentUnchanged pcc(cx);
        1051         8636708 :         JSAutoResolveFlags rf(cx, RESOLVE_INFER);
        1052         4318354 :         ok = JaegerTrampoline(cx, fp, code, stackLimit);
        1053                 :     }
        1054                 :
        1055                 : #ifdef JS_METHODJIT_SPEW
        1056         4318354 :     prof.stop();
        1057         4318354 :     JaegerSpew(JSpew_Prof, "script run took %d ms\n", prof.time_ms());
        1058                 : #endif
        1059                 :
        1060         4318354 :     JaegerStatus status = cx->compartment->jaegerCompartment()->lastUnfinished();
        1061         4318354 :     if (status) {
        1062           49088 :         if (partial) {
        1063                 :             /*
        1064                 :              * Being called from the interpreter, which will resume execution
        1065                 :              * where the JIT left off.
        1066                 :              */
        1067           34659 :             return status;
        1068                 :         }
        1069                 :
        1070                 :         /*
        1071                 :          * Call back into the interpreter to finish the initial frame. This may
        1072                 :          * invoke EnterMethodJIT again, but will allow partial execution for
        1073                 :          * that recursive invocation, so we can have at most two VM frames for
        1074                 :          * a range of inline frames.
        1075                 :          */
        1076                 :         InterpMode mode = (status == Jaeger_UnfinishedAtTrap)
        1077                 :             ? JSINTERP_SKIP_TRAP
        1078           14429 :             : JSINTERP_REJOIN;
        1079           14429 :         ok = Interpret(cx, fp, mode);
        1080                 :
        1081           14429 :         return ok ? Jaeger_Returned : Jaeger_Throwing;
        1082                 :     }
        1083                 :
        1084                 :     /* The entry frame should have finished. */
        1085         4269266 :     JS_ASSERT(fp == cx->fp());
        1086                 :
        1087         4269266 :     if (ok) {
        1088                 :         /* The trampoline wrote the return value but did not set the HAS_RVAL flag. */
        1089         4253669 :         fp->markReturnValue();
        1090                 :     }
        1091                 :
        1092                 :     /* See comment in mjit::Compiler::emitReturn. */
        1093         4269266 :     if (fp->isFunctionFrame())
        1094         4244412 :         fp->updateEpilogueFlags();
        1095                 :
        1096         4269266 :     return ok ? Jaeger_Returned : Jaeger_Throwing;
        1097                 : }
        1098                 :
        1099                 : static inline JaegerStatus
        1100         4318419 : CheckStackAndEnterMethodJIT(JSContext *cx, StackFrame *fp, void *code, bool partial)
        1101                 : {
        1102         4318419 :     JS_CHECK_RECURSION(cx, return Jaeger_Throwing);
        1103                 :
        1104         4318354 :     JS_ASSERT(!cx->compartment->activeAnalysis);
        1105         4318354 :     JS_ASSERT(code);
        1106                 :
        1107         4318354 :     Value *stackLimit = cx->stack.space().getStackLimit(cx, REPORT_ERROR);
        1108         4318354 :     if (!stackLimit)
        1109               0 :         return Jaeger_ThrowBeforeEnter;
        1110                 :
        1111         4318354 :     return EnterMethodJIT(cx, fp, code, stackLimit, partial);
        1112                 : }
        1113                 :
        1114                 : JaegerStatus
        1115         4284829 : mjit::JaegerShot(JSContext *cx, bool partial)
        1116                 : {
        1117         4284829 :     StackFrame *fp = cx->fp();
        1118         4284829 :     JSScript *script = fp->script();
        1119         4284829 :     JITScript *jit = script->getJIT(fp->isConstructing());
        1120                 :
        1121         4284829 :     JS_ASSERT(cx->regs().pc == script->code);
        1122                 :
        1123         4284829 :     return CheckStackAndEnterMethodJIT(cx, cx->fp(), jit->invokeEntry, partial);
        1124                 : }
        1125                 :
        1126                 : JaegerStatus
        1127           33590 : js::mjit::JaegerShotAtSafePoint(JSContext *cx, void *safePoint, bool partial)
        1128                 : {
        1129           33590 :     return CheckStackAndEnterMethodJIT(cx, cx->fp(), safePoint, partial);
        1130                 : }
        1131                 :
        1132                 : NativeMapEntry *
        1133         1955335 : JITChunk::nmap() const
        1134                 : {
        1135         1955335 :     return (NativeMapEntry *)((char*)this + sizeof(*this));
        1136                 : }
        1137                 :
        1138                 : js::mjit::InlineFrame *
        1139         1914957 : JITChunk::inlineFrames() const
        1140                 : {
        1141         1914957 :     return (js::mjit::InlineFrame *)((char *)nmap() + sizeof(NativeMapEntry) * nNmapPairs);
        1142                 : }
        1143                 :
        1144                 : js::mjit::CallSite *
        1145         1904176 : JITChunk::callSites() const
        1146                 : {
        1147         1904176 :     return (js::mjit::CallSite *)&inlineFrames()[nInlineFrames];
        1148                 : }
        1149                 :
        1150                 : char *
        1151         1794055 : JITChunk::commonSectionLimit() const
        1152                 : {
        1153         1794055 :     return (char *)&callSites()[nCallSites];
        1154                 : }
        1155                 :
        1156                 : #ifdef JS_MONOIC
        1157                 : ic::GetGlobalNameIC *
        1158         1794055 : JITChunk::getGlobalNames() const
        1159                 : {
        1160         1794055 :     return (ic::GetGlobalNameIC *) commonSectionLimit();
        1161                 : }
        1162                 :
        1163                 : ic::SetGlobalNameIC *
        1164         1794055 : JITChunk::setGlobalNames() const
        1165                 : {
        1166         1794055 :     return (ic::SetGlobalNameIC *)((char *)getGlobalNames() +
        1167         1794055 :             sizeof(ic::GetGlobalNameIC) * nGetGlobalNames);
        1168                 : }
        1169                 :
        1170                 : ic::CallICInfo *
        1171         1794055 : JITChunk::callICs() const
        1172                 : {
        1173         1794055 :     return (ic::CallICInfo *)&setGlobalNames()[nSetGlobalNames];
        1174                 : }
        1175                 :
        1176                 : ic::EqualityICInfo *
        1177          387045 : JITChunk::equalityICs() const
        1178                 : {
        1179          387045 :     return (ic::EqualityICInfo *)&callICs()[nCallICs];
        1180                 : }
        1181                 :
        1182                 : char *
        1183          387045 : JITChunk::monoICSectionsLimit() const
        1184                 : {
        1185          387045 :     return (char *)&equalityICs()[nEqualityICs];
        1186                 : }
        1187                 : #else   // JS_MONOIC
        1188                 : char *
        1189                 : JITChunk::monoICSectionsLimit() const
        1190                 : {
        1191                 :     return commonSectionLimit();
        1192                 : }
        1193                 : #endif  // JS_MONOIC
        1194                 :
        1195                 : #ifdef JS_POLYIC
        1196                 : ic::GetElementIC *
        1197          387045 : JITChunk::getElems() const
        1198                 : {
        1199          387045 :     return (ic::GetElementIC *)monoICSectionsLimit();
        1200                 : }
        1201                 :
        1202                 : ic::SetElementIC *
        1203          258030 : JITChunk::setElems() const
        1204                 : {
        1205          258030 :     return (ic::SetElementIC *)((char *)getElems() + sizeof(ic::GetElementIC) * nGetElems);
        1206                 : }
        1207                 :
        1208                 : ic::PICInfo *
        1209          129015 : JITChunk::pics() const
        1210                 : {
        1211          129015 :     return (ic::PICInfo *)((char *)setElems() + sizeof(ic::SetElementIC) * nSetElems);
        1212                 : }
        1213                 :
        1214                 : char *
        1215               0 : JITChunk::polyICSectionsLimit() const
        1216                 : {
        1217               0 :     return (char *)pics() + sizeof(ic::PICInfo) * nPICs;
        1218                 : }
        1219                 : #else   // JS_POLYIC
        1220                 : char *
        1221                 : JITChunk::polyICSectionsLimit() const
        1222                 : {
        1223                 :     return monoICSectionsLimit();
        1224                 : }
        1225                 : #endif  // JS_POLYIC
        1226                 :
        1227                 : void
        1228            5094 : JITScript::patchEdge(const CrossChunkEdge &edge, void *label)
        1229                 : {
        1230            5094 :     if (edge.sourceJump1 || edge.sourceJump2) {
        1231            3676 :         JITChunk *sourceChunk = chunk(script->code + edge.source);
        1232            7352 :         ic::Repatcher repatch(sourceChunk);
        1233                 :
        1234                 : #ifdef JS_CPU_X64
        1235                 :         JS_ASSERT(edge.sourceTrampoline);
        1236                 :
        1237                 :         static const uint32_t JUMP_LENGTH = 10;
        1238                 :
        1239                 :         if (edge.sourceJump1) {
        1240                 :             JSC::CodeLocationLabel targetLabel(VerifyRange(edge.sourceJump1, JUMP_LENGTH, label, 0)
        1241                 :                                                ? label
        1242                 :                                                : edge.sourceTrampoline);
        1243                 :             repatch.relink(JSC::CodeLocationJump(edge.sourceJump1), targetLabel);
        1244                 :         }
        1245                 :         if (edge.sourceJump2) {
        1246                 :             JSC::CodeLocationLabel targetLabel(VerifyRange(edge.sourceJump2, JUMP_LENGTH, label, 0)
        1247                 :                                                ? label
        1248                 :                                                : edge.sourceTrampoline);
        1249                 :             repatch.relink(JSC::CodeLocationJump(edge.sourceJump2), targetLabel);
        1250                 :         }
        1251                 :         JSC::CodeLocationDataLabelPtr sourcePatch((char*)edge.sourceTrampoline + JUMP_LENGTH);
        1252                 :         repatch.repatch(sourcePatch, label);
        1253                 : #else
        1254            3676 :         JSC::CodeLocationLabel targetLabel(label);
        1255            3676 :         if (edge.sourceJump1)
        1256            3676 :             repatch.relink(JSC::CodeLocationJump(edge.sourceJump1), targetLabel);
        1257            3676 :         if (edge.sourceJump2)
        1258             851 :             repatch.relink(JSC::CodeLocationJump(edge.sourceJump2), targetLabel);
        1259                 : #endif
        1260                 :     }
        1261            5094 :     if (edge.jumpTableEntries) {
        1262               8 :         for (unsigned i = 0; i < edge.jumpTableEntries->length(); i++)
        1263               4 :             *(*edge.jumpTableEntries)[i] = label;
        1264                 :     }
        1265            5094 : }
        1266                 :
        1267                 : template <typename T>
        1268          854633 : static inline void Destroy(T &t)
        1269                 : {
        1270          854633 :     t.~T();
        1271          854633 : }
        1272                 :
        1273          258030 : JITChunk::~JITChunk()
        1274                 : {
        1275          129015 :     code.release();
        1276                 :
        1277          129015 :     if (pcLengths)
        1278               0 :         Foreground::free_(pcLengths);
        1279                 :
        1280                 : #if defined JS_POLYIC
        1281          129015 :     ic::GetElementIC *getElems_ = getElems();
        1282          129015 :     ic::SetElementIC *setElems_ = setElems();
        1283          129015 :     ic::PICInfo *pics_ = pics();
        1284          150755 :     for (uint32_t i = 0; i < nGetElems; i++)
        1285           21740 :         Destroy(getElems_[i]);
        1286          134722 :     for (uint32_t i = 0; i < nSetElems; i++)
        1287            5707 :         Destroy(setElems_[i]);
        1288          956201 :     for (uint32_t i = 0; i < nPICs; i++)
        1289          827186 :         Destroy(pics_[i]);
        1290                 : #endif
        1291                 :
        1292                 : #if defined JS_MONOIC
        1293          266386 :     for (JSC::ExecutablePool **pExecPool = execPools.begin();
        1294          133193 :          pExecPool != execPools.end();
        1295                 :          ++pExecPool)
        1296                 :     {
        1297            4178 :         (*pExecPool)->release();
        1298                 :     }
        1299                 :
        1300          164576 :     for (unsigned i = 0; i < nativeCallStubs.length(); i++) {
        1301           35561 :         JSC::ExecutablePool *pool = nativeCallStubs[i].pool;
        1302           35561 :         if (pool)
        1303           34771 :             pool->release();
        1304                 :     }
        1305                 :
        1306          129015 :     ic::CallICInfo *callICs_ = callICs();
        1307          276721 :     for (uint32_t i = 0; i < nCallICs; i++) {
        1308          147706 :         callICs_[i].releasePools();
        1309          147706 :         if (callICs_[i].fastGuardedObject)
        1310            6498 :             callICs_[i].purgeGuardedObject();
        1311                 :     }
        1312                 : #endif
        1313          129015 : }
        1314                 :
        1315                 : void
        1316          114059 : JITScript::destroy(JSContext *cx)
        1317                 : {
        1318          231318 :     for (unsigned i = 0; i < nchunks; i++)
        1319          117259 :         destroyChunk(cx, i);
        1320                 :
        1321          114059 :     if (shimPool)
        1322             234 :         shimPool->release();
        1323          114059 : }
        1324                 :
        1325                 : void
        1326          150670 : JITScript::destroyChunk(JSContext *cx, unsigned chunkIndex, bool resetUses)
        1327                 : {
        1328          150670 :     ChunkDescriptor &desc = chunkDescriptor(chunkIndex);
        1329                 :
        1330          150670 :     if (desc.chunk) {
        1331          129015 :         Probes::discardMJITCode(cx, this, script, desc.chunk->code.m_code.executableAddress());
        1332          129015 :         cx->delete_(desc.chunk);
        1333          129015 :         desc.chunk = NULL;
        1334                 :
        1335          129015 :         CrossChunkEdge *edges = this->edges();
        1336          152696 :         for (unsigned i = 0; i < nedges; i++) {
        1337           23681 :             CrossChunkEdge &edge = edges[i];
        1338           23681 :             if (edge.source >= desc.begin && edge.source < desc.end) {
        1339            1794 :                 edge.sourceJump1 = edge.sourceJump2 = NULL;
        1340                 : #ifdef JS_CPU_X64
        1341                 :                 edge.sourceTrampoline = NULL;
        1342                 : #endif
        1343            3588 :                 if (edge.jumpTableEntries) {
        1344              10 :                     cx->delete_(edge.jumpTableEntries);
        1345              10 :                     edge.jumpTableEntries = NULL;
        1346                 :                 }
        1347           21887 :             } else if (edge.target >= desc.begin && edge.target < desc.end) {
        1348            1659 :                 edge.targetLabel = NULL;
        1349            1659 :                 patchEdge(edge, edge.shimLabel);
        1350                 :             }
        1351                 :         }
        1352                 :     }
        1353                 :
        1354          150670 :     if (resetUses)
        1355          150575 :         desc.counter = 0;
        1356                 :
        1357          150670 :     if (chunkIndex == 0) {
        1358          146799 :         if (argsCheckPool) {
        1359             575 :             argsCheckPool->release();
        1360             575 :             argsCheckPool = NULL;
        1361                 :         }
        1362                 :
        1363          146799 :         invokeEntry = NULL;
        1364          146799 :         fastEntry = NULL;
        1365          146799 :         arityCheckEntry = NULL;
        1366          146799 :         argsCheckEntry = NULL;
        1367                 :
        1368          146799 :         if (script->jitNormal == this)
        1369          144872 :             script->jitArityCheckNormal = NULL;
        1370                 :         else
        1371            1927 :             script->jitArityCheckCtor = NULL;
        1372                 :
        1373                 :         // Fixup any ICs still referring to this chunk.
        1374          300125 :         while (!JS_CLIST_IS_EMPTY(&callers)) {
        1375                 :             JS_STATIC_ASSERT(offsetof(ic::CallICInfo, links) == 0);
        1376            6527 :             ic::CallICInfo *ic = (ic::CallICInfo *) callers.next;
        1377                 :
        1378            6527 :             uint8_t *start = (uint8_t *)ic->funGuard.executableAddress();
        1379           13054 :             JSC::RepatchBuffer repatch(JSC::JITCode(start - 32, 64));
        1380                 :
        1381            6527 :             repatch.repatch(ic->funGuard, NULL);
        1382            6527 :             repatch.relink(ic->funJump, ic->slowPathStart);
        1383            6527 :             ic->purgeGuardedObject();
        1384                 :         }
        1385                 :     }
        1386          150670 : }
        1387                 :
        1388                 : size_t
        1389            3818 : JSScript::sizeOfJitScripts(JSMallocSizeOfFun mallocSizeOf)
        1390                 : {
        1391            3818 :     size_t n = 0;
        1392            3818 :     if (jitNormal)
        1393              49 :         n += jitNormal->sizeOfIncludingThis(mallocSizeOf);
        1394            3818 :     if (jitCtor)
        1395               3 :         n += jitCtor->sizeOfIncludingThis(mallocSizeOf);
        1396            3818 :     return n;
        1397                 : }
        1398                 :
        1399                 : size_t
        1400              52 : mjit::JITScript::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf)
        1401                 : {
        1402              52 :     size_t n = mallocSizeOf(this);
        1403             104 :     for (unsigned i = 0; i < nchunks; i++) {
        1404              52 :         const ChunkDescriptor &desc = chunkDescriptor(i);
        1405              52 :         if (desc.chunk)
        1406              42 :             n += desc.chunk->sizeOfIncludingThis(mallocSizeOf);
        1407                 :     }
        1408              52 :     return n;
        1409                 : }
        1410                 :
        1411                 : /* Please keep in sync with Compiler::finishThisUp! */
        1412                 : size_t
        1413          129015 : mjit::JITChunk::computedSizeOfIncludingThis()
        1414                 : {
        1415                 :     return sizeof(JITChunk) +
        1416                 :            sizeof(NativeMapEntry) * nNmapPairs +
        1417                 :            sizeof(InlineFrame) * nInlineFrames +
        1418                 :            sizeof(CallSite) * nCallSites +
        1419                 : #if defined JS_MONOIC
        1420                 :            sizeof(ic::GetGlobalNameIC) * nGetGlobalNames +
        1421                 :            sizeof(ic::SetGlobalNameIC) * nSetGlobalNames +
        1422                 :            sizeof(ic::CallICInfo) * nCallICs +
        1423                 :            sizeof(ic::EqualityICInfo) * nEqualityICs +
        1424                 : #endif
        1425                 : #if defined JS_POLYIC
        1426                 :            sizeof(ic::PICInfo) * nPICs +
        1427                 :            sizeof(ic::GetElementIC) * nGetElems +
        1428                 :            sizeof(ic::SetElementIC) * nSetElems +
        1429                 : #endif
        1430          129015 :            0;
        1431                 : }
        1432                 :
        1433                 : /* Please keep in sync with Compiler::finishThisUp! */
        1434                 : size_t
        1435              42 : mjit::JITChunk::sizeOfIncludingThis(JSMallocSizeOfFun mallocSizeOf)
        1436                 : {
        1437              42 :     return mallocSizeOf(this);
        1438                 : }
        1439                 :
        1440                 : void
        1441          114059 : mjit::ReleaseScriptCode(JSContext *cx, JSScript *script, bool construct)
        1442                 : {
        1443                 :     // NB: The recompiler may call ReleaseScriptCode, in which case it
        1444                 :     // will get called again when the script is destroyed, so we
        1445                 :     // must protect against calling ReleaseScriptCode twice.
        1446                 :
        1447          114059 :     JITScript **pjit = construct ? &script->jitCtor : &script->jitNormal;
        1448          114059 :     void **parity = construct ? &script->jitArityCheckCtor : &script->jitArityCheckNormal;
        1449                 :
        1450          114059 :     if (*pjit) {
        1451          114059 :         (*pjit)->destroy(cx);
        1452          114059 :         cx->free_(*pjit);
        1453          114059 :         *pjit = NULL;
        1454          114059 :         *parity = NULL;
        1455                 :     }
        1456          114059 : }
        1457                 :
        1458                 : #ifdef JS_METHODJIT_PROFILE_STUBS
        1459                 : void JS_FASTCALL
        1460                 : mjit::ProfileStubCall(VMFrame &f)
        1461                 : {
        1462                 :     JSOp op = JSOp(*f.regs.pc);
        1463                 :     StubCallsForOp[op]++;
        1464                 : }
        1465                 : #endif
        1466                 :
        1467                 : JITChunk *
        1468         1393794 : JITScript::findCodeChunk(void *addr)
        1469                 : {
        1470         1404605 :     for (unsigned i = 0; i < nchunks; i++) {
        1471         1398927 :         ChunkDescriptor &desc = chunkDescriptor(i);
        1472         1398927 :         if (desc.chunk && desc.chunk->isValidCode(addr))
        1473         1388116 :             return desc.chunk;
        1474                 :     }
        1475            5678 :     return NULL;
        1476                 : }
        1477                 :
        1478                 : jsbytecode *
        1479         1277995 : JITScript::nativeToPC(void *returnAddress, CallSite **pinline)
        1480                 : {
        1481         1277995 :     JITChunk *chunk = findCodeChunk(returnAddress);
        1482         1277995 :     JS_ASSERT(chunk);
        1483                 :
        1484         1277995 :     size_t low = 0;
        1485         1277995 :     size_t high = chunk->nCallICs;
        1486         1277995 :     js::mjit::ic::CallICInfo *callICs_ = chunk->callICs();
        1487         3417831 :     while (high > low + 1) {
        1488                 :         /* Could overflow here on a script with 2 billion calls. Oh well. */
        1489          861841 :         size_t mid = (high + low) / 2;
        1490          861841 :         void *entry = callICs_[mid].funGuard.executableAddress();
        1491                 :
        1492                 :         /*
        1493                 :          * Use >= here as the return address of the call is likely to be
        1494                 :          * the start address of the next (possibly IC'ed) operation.
        1495                 :          */
        1496          861841 :         if (entry >= returnAddress)
        1497          435890 :             high = mid;
        1498                 :         else
        1499          425951 :             low = mid;
        1500                 :     }
        1501                 :
        1502         1277995 :     js::mjit::ic::CallICInfo &ic = callICs_[low];
        1503         1277995 :     JS_ASSERT((uint8_t*)ic.funGuard.executableAddress() + ic.joinPointOffset == returnAddress);
        1504                 :
        1505         1277995 :     if (ic.call->inlineIndex != UINT32_MAX) {
        1506              39 :         if (pinline)
        1507              39 :             *pinline = ic.call;
        1508              39 :         InlineFrame *frame = &chunk->inlineFrames()[ic.call->inlineIndex];
        1509              83 :         while (frame && frame->parent)
        1510               5 :             frame = frame->parent;
        1511              39 :         return frame->parentpc;
        1512                 :     }
        1513                 :
        1514         1277956 :     if (pinline)
        1515         1277956 :         *pinline = NULL;
        1516         1277956 :     return script->code + ic.call->pcOffset;
        1517                 : }
        1518                 :
        1519                 : jsbytecode *
        1520              12 : mjit::NativeToPC(JITScript *jit, void *ncode, mjit::CallSite **pinline)
        1521                 : {
        1522              12 :     return jit->nativeToPC(ncode, pinline);
        1523                 : }
        1524                 :
        1525                 : /* static */ const double mjit::Assembler::oneDouble = 1.0;

Generated by: LCOV version 1.7