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-06-02 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         3299174 : js::mjit::CompilerAllocPolicy::CompilerAllocPolicy(JSContext *cx, Compiler &compiler)
      73                 : : TempAllocPolicy(cx),
      74         3299174 :   oomFlag(&compiler.oomInVector)
      75                 : {
      76         3299174 : }
      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         4229345 : PushActiveVMFrame(VMFrame &f)
     145                 : {
     146         4229345 :     f.oldregs = &f.cx->stack.regs();
     147         4229345 :     f.cx->stack.repointRegs(&f.regs);
     148         4229345 :     f.entryfp->script()->compartment()->jaegerCompartment()->pushActiveFrame(&f);
     149         4229345 :     f.entryfp->setNativeReturnAddress(JS_FUNC_TO_DATA_PTR(void*, JaegerTrampolineReturn));
     150         4229345 :     f.regs.clearInlined();
     151         4229345 : }
     152                 : 
     153                 : // Called from JaegerTrampolineReturn, JaegerThrowpoline, JaegerInterpoline
     154                 : extern "C" void JS_FASTCALL
     155         4229345 : PopActiveVMFrame(VMFrame &f)
     156                 : {
     157         4229345 :     f.entryfp->script()->compartment()->jaegerCompartment()->popActiveFrame();
     158         4229345 :     f.cx->stack.repointRegs(f.oldregs);
     159         4229345 : }
     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           11826 : JaegerCompartment::JaegerCompartment()
     987           11826 :     : orphanedNativeFrames(SystemAllocPolicy()), orphanedNativePools(SystemAllocPolicy())
     988           11826 : {}
     989                 : 
     990                 : bool
     991           11826 : JaegerCompartment::Initialize(JSContext *cx)
     992                 : {
     993                 :     execAlloc_ = js::OffTheBooks::new_<JSC::ExecutableAllocator>(
     994           11826 :         cx->runtime->getJitHardening() ? JSC::AllocationCanRandomize : JSC::AllocationDeterministic);
     995           11826 :     if (!execAlloc_)
     996               0 :         return false;
     997                 :     
     998           11826 :     TrampolineCompiler tc(execAlloc_, &trampolines);
     999           11826 :     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           11826 :     activeFrame_ = NULL;
    1011           11826 :     lastUnfinished_ = (JaegerStatus) 0;
    1012                 : 
    1013           11826 :     return true;
    1014                 : }
    1015                 : 
    1016                 : void
    1017           11826 : JaegerCompartment::Finish()
    1018                 : {
    1019           11826 :     TrampolineCompiler::release(&trampolines);
    1020           11826 :     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           11826 : }
    1030                 : 
    1031                 : extern "C" JSBool
    1032                 : JaegerTrampoline(JSContext *cx, StackFrame *fp, void *code, Value *stackLimit);
    1033                 : 
    1034                 : JaegerStatus
    1035         4229345 : mjit::EnterMethodJIT(JSContext *cx, StackFrame *fp, void *code, Value *stackLimit, bool partial)
    1036                 : {
    1037                 : #ifdef JS_METHODJIT_SPEW
    1038                 :     Profiler prof;
    1039         4229345 :     JSScript *script = fp->script();
    1040                 : 
    1041                 :     JaegerSpew(JSpew_Prof, "%s jaeger script, line %d\n",
    1042         4229345 :                script->filename, script->lineno);
    1043         4229345 :     prof.start();
    1044                 : #endif
    1045                 : 
    1046         4229345 :     JS_ASSERT(cx->fp() == fp);
    1047                 : 
    1048                 :     JSBool ok;
    1049                 :     {
    1050         8458690 :         AssertCompartmentUnchanged pcc(cx);
    1051         8458690 :         JSAutoResolveFlags rf(cx, RESOLVE_INFER);
    1052         4229345 :         ok = JaegerTrampoline(cx, fp, code, stackLimit);
    1053                 :     }
    1054                 : 
    1055                 : #ifdef JS_METHODJIT_SPEW
    1056         4229345 :     prof.stop();
    1057         4229345 :     JaegerSpew(JSpew_Prof, "script run took %d ms\n", prof.time_ms());
    1058                 : #endif
    1059                 : 
    1060         4229345 :     JaegerStatus status = cx->compartment->jaegerCompartment()->lastUnfinished();
    1061         4229345 :     if (status) {
    1062           49073 :         if (partial) {
    1063                 :             /*
    1064                 :              * Being called from the interpreter, which will resume execution
    1065                 :              * where the JIT left off.
    1066                 :              */
    1067           34661 :             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           14412 :             : JSINTERP_REJOIN;
    1079           14412 :         ok = Interpret(cx, fp, mode);
    1080                 : 
    1081           14412 :         return ok ? Jaeger_Returned : Jaeger_Throwing;
    1082                 :     }
    1083                 : 
    1084                 :     /* The entry frame should have finished. */
    1085         4180272 :     JS_ASSERT(fp == cx->fp());
    1086                 : 
    1087         4180272 :     if (ok) {
    1088                 :         /* The trampoline wrote the return value but did not set the HAS_RVAL flag. */
    1089         4164695 :         fp->markReturnValue();
    1090                 :     }
    1091                 : 
    1092                 :     /* See comment in mjit::Compiler::emitReturn. */
    1093         4180272 :     if (fp->isFunctionFrame())
    1094         4155420 :         fp->updateEpilogueFlags();
    1095                 : 
    1096         4180272 :     return ok ? Jaeger_Returned : Jaeger_Throwing;
    1097                 : }
    1098                 : 
    1099                 : static inline JaegerStatus
    1100         4229414 : CheckStackAndEnterMethodJIT(JSContext *cx, StackFrame *fp, void *code, bool partial)
    1101                 : {
    1102         4229414 :     JS_CHECK_RECURSION(cx, return Jaeger_Throwing);
    1103                 : 
    1104         4229345 :     JS_ASSERT(!cx->compartment->activeAnalysis);
    1105         4229345 :     JS_ASSERT(code);
    1106                 : 
    1107         4229345 :     Value *stackLimit = cx->stack.space().getStackLimit(cx, REPORT_ERROR);
    1108         4229345 :     if (!stackLimit)
    1109               0 :         return Jaeger_ThrowBeforeEnter;
    1110                 : 
    1111         4229345 :     return EnterMethodJIT(cx, fp, code, stackLimit, partial);
    1112                 : }
    1113                 : 
    1114                 : JaegerStatus
    1115         4195920 : mjit::JaegerShot(JSContext *cx, bool partial)
    1116                 : {
    1117         4195920 :     StackFrame *fp = cx->fp();
    1118         4195920 :     JSScript *script = fp->script();
    1119         4195920 :     JITScript *jit = script->getJIT(fp->isConstructing());
    1120                 : 
    1121         4195920 :     JS_ASSERT(cx->regs().pc == script->code);
    1122                 : 
    1123         4195920 :     return CheckStackAndEnterMethodJIT(cx, cx->fp(), jit->invokeEntry, partial);
    1124                 : }
    1125                 : 
    1126                 : JaegerStatus
    1127           33494 : js::mjit::JaegerShotAtSafePoint(JSContext *cx, void *safePoint, bool partial)
    1128                 : {
    1129           33494 :     return CheckStackAndEnterMethodJIT(cx, cx->fp(), safePoint, partial);
    1130                 : }
    1131                 : 
    1132                 : NativeMapEntry *
    1133         1961788 : JITChunk::nmap() const
    1134                 : {
    1135         1961788 :     return (NativeMapEntry *)((char*)this + sizeof(*this));
    1136                 : }
    1137                 : 
    1138                 : js::mjit::InlineFrame *
    1139         1921505 : JITChunk::inlineFrames() const
    1140                 : {
    1141         1921505 :     return (js::mjit::InlineFrame *)((char *)nmap() + sizeof(NativeMapEntry) * nNmapPairs);
    1142                 : }
    1143                 : 
    1144                 : js::mjit::CallSite *
    1145         1903457 : JITChunk::callSites() const
    1146                 : {
    1147         1903457 :     return (js::mjit::CallSite *)&inlineFrames()[nInlineFrames];
    1148                 : }
    1149                 : 
    1150                 : char *
    1151         1793452 : JITChunk::commonSectionLimit() const
    1152                 : {
    1153         1793452 :     return (char *)&callSites()[nCallSites];
    1154                 : }
    1155                 : 
    1156                 : #ifdef JS_MONOIC
    1157                 : ic::GetGlobalNameIC *
    1158         1793452 : JITChunk::getGlobalNames() const
    1159                 : {
    1160         1793452 :     return (ic::GetGlobalNameIC *) commonSectionLimit();
    1161                 : }
    1162                 : 
    1163                 : ic::SetGlobalNameIC *
    1164         1793452 : JITChunk::setGlobalNames() const
    1165                 : {
    1166         1793452 :     return (ic::SetGlobalNameIC *)((char *)getGlobalNames() +
    1167         1793452 :             sizeof(ic::GetGlobalNameIC) * nGetGlobalNames);
    1168                 : }
    1169                 : 
    1170                 : ic::CallICInfo *
    1171         1793452 : JITChunk::callICs() const
    1172                 : {
    1173         1793452 :     return (ic::CallICInfo *)&setGlobalNames()[nSetGlobalNames];
    1174                 : }
    1175                 : 
    1176                 : ic::EqualityICInfo *
    1177          386481 : JITChunk::equalityICs() const
    1178                 : {
    1179          386481 :     return (ic::EqualityICInfo *)&callICs()[nCallICs];
    1180                 : }
    1181                 : 
    1182                 : char *
    1183          386481 : JITChunk::monoICSectionsLimit() const
    1184                 : {
    1185          386481 :     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          386481 : JITChunk::getElems() const
    1198                 : {
    1199          386481 :     return (ic::GetElementIC *)monoICSectionsLimit();
    1200                 : }
    1201                 : 
    1202                 : ic::SetElementIC *
    1203          257654 : JITChunk::setElems() const
    1204                 : {
    1205          257654 :     return (ic::SetElementIC *)((char *)getElems() + sizeof(ic::GetElementIC) * nGetElems);
    1206                 : }
    1207                 : 
    1208                 : ic::PICInfo *
    1209          128827 : JITChunk::pics() const
    1210                 : {
    1211          128827 :     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            5160 : JITScript::patchEdge(const CrossChunkEdge &edge, void *label)
    1229                 : {
    1230            5160 :     if (edge.sourceJump1 || edge.sourceJump2) {
    1231            3683 :         JITChunk *sourceChunk = chunk(script->code + edge.source);
    1232            7366 :         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            3683 :         JSC::CodeLocationLabel targetLabel(label);
    1255            3683 :         if (edge.sourceJump1)
    1256            3683 :             repatch.relink(JSC::CodeLocationJump(edge.sourceJump1), targetLabel);
    1257            3683 :         if (edge.sourceJump2)
    1258             827 :             repatch.relink(JSC::CodeLocationJump(edge.sourceJump2), targetLabel);
    1259                 : #endif
    1260                 :     }
    1261            5160 :     if (edge.jumpTableEntries) {
    1262               8 :         for (unsigned i = 0; i < edge.jumpTableEntries->length(); i++)
    1263               4 :             *(*edge.jumpTableEntries)[i] = label;
    1264                 :     }
    1265            5160 : }
    1266                 : 
    1267                 : template <typename T>
    1268          850596 : static inline void Destroy(T &t)
    1269                 : {
    1270          850596 :     t.~T();
    1271          850596 : }
    1272                 : 
    1273          257654 : JITChunk::~JITChunk()
    1274                 : {
    1275          128827 :     code.release();
    1276                 : 
    1277          128827 :     if (pcLengths)
    1278               0 :         Foreground::free_(pcLengths);
    1279                 : 
    1280                 : #if defined JS_POLYIC
    1281          128827 :     ic::GetElementIC *getElems_ = getElems();
    1282          128827 :     ic::SetElementIC *setElems_ = setElems();
    1283          128827 :     ic::PICInfo *pics_ = pics();
    1284          150522 :     for (uint32_t i = 0; i < nGetElems; i++)
    1285           21695 :         Destroy(getElems_[i]);
    1286          134519 :     for (uint32_t i = 0; i < nSetElems; i++)
    1287            5692 :         Destroy(setElems_[i]);
    1288          952036 :     for (uint32_t i = 0; i < nPICs; i++)
    1289          823209 :         Destroy(pics_[i]);
    1290                 : #endif
    1291                 : 
    1292                 : #if defined JS_MONOIC
    1293          265950 :     for (JSC::ExecutablePool **pExecPool = execPools.begin();
    1294          132975 :          pExecPool != execPools.end();
    1295                 :          ++pExecPool)
    1296                 :     {
    1297            4148 :         (*pExecPool)->release();
    1298                 :     }
    1299                 : 
    1300          164348 :     for (unsigned i = 0; i < nativeCallStubs.length(); i++) {
    1301           35521 :         JSC::ExecutablePool *pool = nativeCallStubs[i].pool;
    1302           35521 :         if (pool)
    1303           34658 :             pool->release();
    1304                 :     }
    1305                 : 
    1306          128827 :     ic::CallICInfo *callICs_ = callICs();
    1307          276163 :     for (uint32_t i = 0; i < nCallICs; i++) {
    1308          147336 :         callICs_[i].releasePools();
    1309          147336 :         if (callICs_[i].fastGuardedObject)
    1310            6502 :             callICs_[i].purgeGuardedObject();
    1311                 :     }
    1312                 : #endif
    1313          128827 : }
    1314                 : 
    1315                 : void
    1316          113898 : JITScript::destroy(JSContext *cx)
    1317                 : {
    1318          230996 :     for (unsigned i = 0; i < nchunks; i++)
    1319          117098 :         destroyChunk(cx, i);
    1320                 : 
    1321          113898 :     if (shimPool)
    1322             234 :         shimPool->release();
    1323          113898 : }
    1324                 : 
    1325                 : void
    1326          150529 : JITScript::destroyChunk(JSContext *cx, unsigned chunkIndex, bool resetUses)
    1327                 : {
    1328          150529 :     ChunkDescriptor &desc = chunkDescriptor(chunkIndex);
    1329                 : 
    1330          150529 :     if (desc.chunk) {
    1331          128827 :         Probes::discardMJITCode(cx, this, script, desc.chunk->code.m_code.executableAddress());
    1332          128827 :         cx->delete_(desc.chunk);
    1333          128827 :         desc.chunk = NULL;
    1334                 : 
    1335          128827 :         CrossChunkEdge *edges = this->edges();
    1336          152748 :         for (unsigned i = 0; i < nedges; i++) {
    1337           23921 :             CrossChunkEdge &edge = edges[i];
    1338           23921 :             if (edge.source >= desc.begin && edge.source < desc.end) {
    1339            1816 :                 edge.sourceJump1 = edge.sourceJump2 = NULL;
    1340                 : #ifdef JS_CPU_X64
    1341                 :                 edge.sourceTrampoline = NULL;
    1342                 : #endif
    1343            3632 :                 if (edge.jumpTableEntries) {
    1344              10 :                     cx->delete_(edge.jumpTableEntries);
    1345              10 :                     edge.jumpTableEntries = NULL;
    1346                 :                 }
    1347           22105 :             } else if (edge.target >= desc.begin && edge.target < desc.end) {
    1348            1681 :                 edge.targetLabel = NULL;
    1349            1681 :                 patchEdge(edge, edge.shimLabel);
    1350                 :             }
    1351                 :         }
    1352                 :     }
    1353                 : 
    1354          150529 :     if (resetUses)
    1355          150436 :         desc.counter = 0;
    1356                 : 
    1357          150529 :     if (chunkIndex == 0) {
    1358          146648 :         if (argsCheckPool) {
    1359             575 :             argsCheckPool->release();
    1360             575 :             argsCheckPool = NULL;
    1361                 :         }
    1362                 : 
    1363          146648 :         invokeEntry = NULL;
    1364          146648 :         fastEntry = NULL;
    1365          146648 :         arityCheckEntry = NULL;
    1366          146648 :         argsCheckEntry = NULL;
    1367                 : 
    1368          146648 :         if (script->jitNormal == this)
    1369          144719 :             script->jitArityCheckNormal = NULL;
    1370                 :         else
    1371            1929 :             script->jitArityCheckCtor = NULL;
    1372                 : 
    1373                 :         // Fixup any ICs still referring to this chunk.
    1374          299798 :         while (!JS_CLIST_IS_EMPTY(&callers)) {
    1375                 :             JS_STATIC_ASSERT(offsetof(ic::CallICInfo, links) == 0);
    1376            6502 :             ic::CallICInfo *ic = (ic::CallICInfo *) callers.next;
    1377                 : 
    1378            6502 :             uint8_t *start = (uint8_t *)ic->funGuard.executableAddress();
    1379           13004 :             JSC::RepatchBuffer repatch(JSC::JITCode(start - 32, 64));
    1380                 : 
    1381            6502 :             repatch.repatch(ic->funGuard, NULL);
    1382            6502 :             repatch.relink(ic->funJump, ic->slowPathStart);
    1383            6502 :             ic->purgeGuardedObject();
    1384                 :         }
    1385                 :     }
    1386          150529 : }
    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          128827 : 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          128827 :            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          113898 : 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          113898 :     JITScript **pjit = construct ? &script->jitCtor : &script->jitNormal;
    1448          113898 :     void **parity = construct ? &script->jitArityCheckCtor : &script->jitArityCheckNormal;
    1449                 : 
    1450          113898 :     if (*pjit) {
    1451          113898 :         (*pjit)->destroy(cx);
    1452          113898 :         cx->free_(*pjit);
    1453          113898 :         *pjit = NULL;
    1454          113898 :         *parity = NULL;
    1455                 :     }
    1456          113898 : }
    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         1393862 : JITScript::findCodeChunk(void *addr)
    1469                 : {
    1470         1404816 :     for (unsigned i = 0; i < nchunks; i++) {
    1471         1399103 :         ChunkDescriptor &desc = chunkDescriptor(i);
    1472         1399103 :         if (desc.chunk && desc.chunk->isValidCode(addr))
    1473         1388149 :             return desc.chunk;
    1474                 :     }
    1475            5713 :     return NULL;
    1476                 : }
    1477                 : 
    1478                 : jsbytecode *
    1479         1278144 : JITScript::nativeToPC(void *returnAddress, CallSite **pinline)
    1480                 : {
    1481         1278144 :     JITChunk *chunk = findCodeChunk(returnAddress);
    1482         1278144 :     JS_ASSERT(chunk);
    1483                 : 
    1484         1278144 :     size_t low = 0;
    1485         1278144 :     size_t high = chunk->nCallICs;
    1486         1278144 :     js::mjit::ic::CallICInfo *callICs_ = chunk->callICs();
    1487         3418677 :     while (high > low + 1) {
    1488                 :         /* Could overflow here on a script with 2 billion calls. Oh well. */
    1489          862389 :         size_t mid = (high + low) / 2;
    1490          862389 :         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          862389 :         if (entry >= returnAddress)
    1497          435839 :             high = mid;
    1498                 :         else
    1499          426550 :             low = mid;
    1500                 :     }
    1501                 : 
    1502         1278144 :     js::mjit::ic::CallICInfo &ic = callICs_[low];
    1503         1278144 :     JS_ASSERT((uint8_t*)ic.funGuard.executableAddress() + ic.joinPointOffset == returnAddress);
    1504                 : 
    1505         1278144 :     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         1278105 :     if (pinline)
    1515         1278105 :         *pinline = NULL;
    1516         1278105 :     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