[JAEGER] Backed out changeset b88bab8e77c5: prerequisite to backing out 04bc789f7a43
authorDavid Mandelin <dmandelin@mozilla.com>
Thu, 19 Aug 2010 16:25:54 -0700
changeset 53462 8acd89c26786f36090cbbed5d58c49dd0591500d
parent 53457 b88bab8e77c5b3710db92f166c8e7187b68f7ea6
child 53463 b0fa07efbce2cc488adf62335bb5c28e0f378d0a
push idunknown
push userunknown
push dateunknown
milestone2.0b4pre
[JAEGER] Backed out changeset b88bab8e77c5: prerequisite to backing out 04bc789f7a43
js/src/methodjit/BaseAssembler.h
js/src/methodjit/Compiler.cpp
js/src/methodjit/MethodJIT.cpp
js/src/methodjit/TrampolineCompiler.cpp
--- a/js/src/methodjit/BaseAssembler.h
+++ b/js/src/methodjit/BaseAssembler.h
@@ -308,27 +308,27 @@ static const JSC::MacroAssembler::Regist
         callPatches.append(CallPatch(differenceBetween(startLabel, cl), fun));
         return cl;
     }
 
     Call call(RegisterID reg) {
         return MacroAssembler::call(reg);
     }
 
-    void restoreReturnAddress()
-    {
-#ifndef JS_CPU_ARM
-        /* X86 and X64's "ret" instruction expects a return address on the stack. */
-        push(Address(JSFrameReg, offsetof(JSStackFrame, ncode)));
-#else
-        /* ARM returns either using its link register (LR) or directly from the stack, but masm.ret()
-         * always emits a return to LR. */
-        load32(Address(JSFrameReg, offsetof(JSStackFrame, ncode)), JSC::ARMRegisters::lr);
+#if defined(JS_CPU_ARM)
+    void ret() {
+        /* The return sequence emitted by the ARM macro-assembler assumes that the return address
+         * is in LR. We could load it into LR before calling it, but it's probably better to simply
+         * pop into the PC. (Note that JaegerTrampoline expects the return sequence to pop this
+         * single word from the stack, so the stack will be unaligned on return from JIT code.
+         * JaegerTrampoline fixes this up.) */
+        MacroAssembler::pop(JSC::ARMRegisters::pc);
+    }
+    // #else fall back to the inherited implementation in MacroAssembler::ret().
 #endif
-    }
 
     void finalize(uint8 *ncode) {
         JSC::JITCode jc(ncode, size());
         JSC::CodeBlock cb(jc);
         JSC::RepatchBuffer repatchBuffer(&cb);
 
         for (size_t i = 0; i < callPatches.length(); i++) {
             JSC::MacroAssemblerCodePtr cp(ncode + callPatches[i].distance);
--- a/js/src/methodjit/Compiler.cpp
+++ b/js/src/methodjit/Compiler.cpp
@@ -1569,27 +1569,37 @@ mjit::Compiler::jsop_getglobal(uint32 in
 
     RegisterID reg = frame.allocReg();
     Address address = masm.objSlotRef(globalObj, reg, slot);
     frame.freeReg(reg);
     frame.push(address);
 }
 
 void
+mjit::Compiler::restoreReturnAddress(Assembler &masm)
+{
+#ifndef JS_CPU_ARM
+    masm.push(Address(JSFrameReg, offsetof(JSStackFrame, ncode)));
+#else
+    masm.move(Address(JSFrameReg, offsetof(JSStackFrame, ncode)), JSC::ARMRegisters::lr);
+#endif
+}
+
+void
 mjit::Compiler::emitReturn()
 {
     /*
      * if (!f.inlineCallCount)
      *     return;
      */
     Jump noInlineCalls = masm.branchPtr(Assembler::Equal,
                                         FrameAddress(offsetof(VMFrame, entryFp)),
                                         JSFrameReg);
     stubcc.linkExit(noInlineCalls, Uses(frame.frameDepth()));
-    stubcc.masm.restoreReturnAddress();
+    restoreReturnAddress(stubcc.masm);
     stubcc.masm.ret();
 
     JS_ASSERT_IF(!fun, JSOp(*PC) == JSOP_STOP);
 
     /*
      * If there's a function object, deal with the fact that it can escape.
      * Note that after we've placed the call object, all tracked state can
      * be thrown away. This will happen anyway because the next live opcode
@@ -1640,17 +1650,17 @@ mjit::Compiler::emitReturn()
     masm.storePtr(Registers::ReturnReg, Address(Registers::ArgReg1, offsetof(JSContext, fp)));
 
     JS_STATIC_ASSERT(Registers::ReturnReg != JSReturnReg_Data);
     JS_STATIC_ASSERT(Registers::ReturnReg != JSReturnReg_Type);
 
     Address rval(JSFrameReg, JSStackFrame::offsetReturnValue());
     masm.loadPayload(rval, JSReturnReg_Data);
     masm.loadTypeTag(rval, JSReturnReg_Type);
-    masm.restoreReturnAddress();
+    restoreReturnAddress(masm);
     masm.move(Registers::ReturnReg, JSFrameReg);
 #ifdef DEBUG
     masm.storePtr(ImmPtr(JSStackFrame::sInvalidPC),
                   Address(JSFrameReg, offsetof(JSStackFrame, savedPC)));
 #endif
     masm.ret();
 }
 
--- a/js/src/methodjit/MethodJIT.cpp
+++ b/js/src/methodjit/MethodJIT.cpp
@@ -51,47 +51,48 @@ using namespace js::mjit;
 
 /*
  * Explanation of VMFrame activation and various helper thunks below.
  *
  * JaegerTrampoline  - Executes a method JIT-compiled JSFunction. This function
  *    creates a VMFrame on the machine stack and calls into JIT'd code. The JIT'd
  *    code will eventually return to the VMFrame.
  *
- *  - Called from C++ function EnterMethodJIT.
+ *  - Called from C++ functions JaegerShot and JaegerBomb.
  *  - Parameters: cx, fp, code, stackLimit, safePoint
  *  - Notes: safePoint is used in combination with SafePointTrampoline,
  *           explained further down.
  *
  * JaegerThrowpoline - Calls into an exception handler from JIT'd code, and if a
  *    scripted exception handler is not found, unwinds the VMFrame and returns
  *    to C++.
  *
  *  - To start exception handling, we return from a stub call to the throwpoline.
  *  - On entry to the throwpoline, the normal conditions of the jit-code ABI
  *    are satisfied.
  *  - To do the unwinding and find out where to continue executing, we call
  *    js_InternalThrow.
  *  - js_InternalThrow may return 0, which means the place to continue, if any,
  *    is above this JaegerShot activation, so we just return, in the same way
  *    the trampoline does.
- *  - Otherwise, js_InternalThrow returns a jit-code address to continue execution
- *    at. Because the jit-code ABI conditions are satisfied, we can just jump to
- *    that point.
+ *  - Otherwise, js_InternalThrow returns a jit-code address to continue
+ *    execution
+ *    at. Because the jit-code ABI conditions are satisfied, we can just jump
+ *    to that point.
  *
  *
  * SafePointTrampoline  - Inline script calls link their return addresses through
  *    JSStackFrame::ncode. This includes the return address that unwinds back
  *    to JaegerTrampoline. However, the tracer integration code often wants to
  *    enter a method JIT'd function at an arbitrary safe point. Safe points
  *    do not have the return address linking code that the method prologue has.
  *    SafePointTrampoline is a thunk which correctly links the initial return
- *    address. It is used in JaegerShotAtSafePoint, and passed as the "script
- *    code" parameter. Using the "safePoint" parameter to JaegerTrampoline, it
- *    correctly jumps to the intended point in the method.
+ *    address. It is used in JaegerBomb, and passed as the "script code"
+ *    parameter. Using the "safePoint" parameter to JaegerTrampoline, it correctly
+ *    jumps to the intended point in the method.
  *
  *  - Used by JaegerTrampoline()
  *
  * InjectJaegerReturn - Implements the tail of InlineReturn. This is needed for
  *    tracer integration, where a "return" opcode might not be a safe-point,
  *    and thus the return path must be injected by hijacking the stub return
  *    address.
  *
@@ -210,17 +211,18 @@ SYMBOL_STRING(JaegerTrampoline) ":"     
     /* Set cx->regs and set the active frame. Save rdx and align frame in one. */
     "pushq %rdx"                         "\n"
     "movq  %rsp, %rdi"                   "\n"
     "call " SYMBOL_STRING_RELOC(SetVMFrameRegs) "\n"
     "movq  %rsp, %rdi"                   "\n"
     "call " SYMBOL_STRING_RELOC(PushActiveVMFrame) "\n"
 
     /*
-     * Jump into into the JIT'd code.
+     * Jump into into the JIT'd code. The call implicitly fills in
+     * the precious f.scriptedReturn member of VMFrame.
      */
     "call *0(%rsp)"                      "\n"
     "movq %rsp, %rdi"                    "\n"
     "call " SYMBOL_STRING_RELOC(PopActiveVMFrame) "\n"
     "movq %rsp, %rdi"                    "\n"
     "call " SYMBOL_STRING_RELOC(UnsetVMFrameRegs) "\n"
 
     "addq $0x58, %rsp"                   "\n"
@@ -406,17 +408,19 @@ SYMBOL_STRING(SafePointTrampoline) ":"  
 JS_STATIC_ASSERT(sizeof(VMFrame) == 80);
 JS_STATIC_ASSERT(offsetof(VMFrame, savedLR) ==          (4*19));
 JS_STATIC_ASSERT(offsetof(VMFrame, entryFp) ==          (4*10));
 JS_STATIC_ASSERT(offsetof(VMFrame, stackLimit) ==       (4*9));
 JS_STATIC_ASSERT(offsetof(VMFrame, cx) ==               (4*8));
 JS_STATIC_ASSERT(offsetof(VMFrame, fp) ==               (4*7));
 JS_STATIC_ASSERT(offsetof(VMFrame, oldRegs) ==          (4*4));
 JS_STATIC_ASSERT(offsetof(VMFrame, previous) ==         (4*3));
+JS_STATIC_ASSERT(offsetof(VMFrame, scriptedReturn) ==   (4*0));
 JS_STATIC_ASSERT(offsetof(JSStackFrame, ncode) == 60);
+JS_STATIC_ASSERT(offsetof(JSStackFrame, rval) == 40);
 
 asm volatile (
 ".text\n"
 ".globl " SYMBOL_STRING(InjectJaegerReturn)   "\n"
 SYMBOL_STRING(InjectJaegerReturn) ":"         "\n"
     /* Restore frame regs. */
     "ldr r1, [r11, #40]"                    "\n" /* fp->rval data */
     "ldr r2, [r11, #44]"                    "\n" /* fp->rval type */
@@ -424,40 +428,31 @@ SYMBOL_STRING(InjectJaegerReturn) ":"   
     "ldr r11, [sp, #28]"                    "\n" /* load f.fp */
     "bx  r0"                                "\n"
 );
 
 asm volatile (
 ".text\n"
 ".globl " SYMBOL_STRING(SafePointTrampoline)  "\n"
 SYMBOL_STRING(SafePointTrampoline) ":"
-    /*
-     * On entry to SafePointTrampoline:
-     *         r11 = fp
-     *      sp[80] = safePoint
-     */
-    "ldr    ip, [sp, #80]"                  "\n"
-    /* Save the return address (in JaegerTrampoline) to fp->ncode. */
-    "str    lr, [r11, #60]"                 "\n"
-    /* Jump to 'safePoint' via 'ip' because a load into the PC from an address on
-     * the stack looks like a return, and may upset return stack prediction. */
-    "bx     ip"                             "\n"
+    "str lr, [r11, #60]"                    "\n"
+    /* This should load the fifth parameter from JaegerTrampoline and jump to it. */
+    ""                                 "\n"
 );
 
 asm volatile (
 ".text\n"
 ".globl " SYMBOL_STRING(JaegerTrampoline)   "\n"
 SYMBOL_STRING(JaegerTrampoline) ":"         "\n"
     /*
      * On entry to JaegerTrampoline:
-     *         r0 = cx
-     *         r1 = fp
-     *         r2 = code
-     *         r3 = stackLimit
-     *      sp[0] = safePoint
+     *      r0 = cx
+     *      r1 = fp
+     *      r2 = code
+     *      r3 = inlineCallCount
      *
      * The VMFrame for ARM looks like this:
      *  [ lr        ]   \
      *  [ r11       ]   |
      *  [ r10       ]   |
      *  [ r9        ]   | Callee-saved registers.                             
      *  [ r8        ]   | VFP registers d8-d15 may be required here too, but  
      *  [ r7        ]   | unconditionally preserving them might be expensive
@@ -467,37 +462,35 @@ SYMBOL_STRING(JaegerTrampoline) ":"     
      *  [ entryFp   ]
      *  [ stkLimit  ]
      *  [ cx        ]
      *  [ fp        ]
      *  [ regs.sp   ]
      *  [ regs.pc   ]
      *  [ oldRegs   ]
      *  [ previous  ]
-     *  [ args.ptr3 ]
+     *  [ args.ptr  ]
      *  [ args.ptr2 ]
-     *  [ args.ptr  ]
+     *  [ srpt. ret ]   } Scripted return.
      */
     
-    /* Push callee-saved registers. */
+    /* Push callee-saved registers. TODO: Do we actually need to push all of them? If the
+     * compiled JavaScript function is EABI-compliant, we only need to push what we use in
+     * JaegerTrampoline. */
 "   push    {r4-r11,lr}"                        "\n"
     /* Push interesting VMFrame content. */
 "   push    {r1}"                               "\n"    /* entryFp */
 "   push    {r3}"                               "\n"    /* stackLimit */
 "   push    {r0}"                               "\n"    /* cx */
 "   push    {r1}"                               "\n"    /* fp */
     /* Remaining fields are set elsewhere, but we need to leave space for them. */
 "   sub     sp, sp, #(4*7)"                     "\n"
 
-    /* Preserve 'code' (r2) in an arbitrary callee-saved register. */
-"   mov     r4, r2"                             "\n"
-    /* Preserve 'fp' (r1) in r11 (JSFrameReg) for SafePointTrampoline. */
-"   mov     r11, r1"                            "\n"
-
 "   mov     r0, sp"                             "\n"
+"   mov     r4, r2"                             "\n"    /* Preserve r2 ('code') in a callee-saved register. */
 "   bl  " SYMBOL_STRING_RELOC(SetVMFrameRegs)   "\n"
 "   mov     r0, sp"                             "\n"
 "   bl  " SYMBOL_STRING_RELOC(PushActiveVMFrame)"\n"
 
     /* Call the compiled JavaScript function. */
 "   blx     r4"                                 "\n"
 
     /* Tidy up. */
@@ -513,32 +506,30 @@ SYMBOL_STRING(JaegerTrampoline) ":"     
 "   mov     r0, #1"                         "\n"
 "   pop     {r4-r11,pc}"                    "\n"
 );
 
 asm volatile (
 ".text\n"
 ".globl " SYMBOL_STRING(JaegerThrowpoline)  "\n"
 SYMBOL_STRING(JaegerThrowpoline) ":"        "\n"
-    /* Find the VMFrame pointer for js_InternalThrow. */
+    /* Restore 'f', as it will have been clobbered. */
 "   mov     r0, sp"                         "\n"
 
     /* Call the utility function that sets up the internal throw routine. */
 "   bl  " SYMBOL_STRING_RELOC(js_InternalThrow) "\n"
     
-    /* If js_InternalThrow found a scripted handler, jump to it. Otherwise, tidy
-     * up and return. */
+    /* If 0 was returned, just bail out as normal. Otherwise, we have a 'catch' or 'finally' clause
+     * to execute. */
 "   cmp     r0, #0"                         "\n"
 "   bxne    r0"                             "\n"
 
-    /* Tidy up, then return '0' to represent an unhandled exception. */
-"   mov     r0, sp"                             "\n"
-"   bl  " SYMBOL_STRING_RELOC(PopActiveVMFrame) "\n"
-"   add     sp, sp, #(4*7 + 4*4)"               "\n"
-"   mov     r0, #0"                         "\n"
+    /* Skip past the parameters we pushed (such as cx and the like). */
+"   add     sp, sp, #(4*7 + 4*4)"           "\n"
+
 "   pop     {r4-r11,pc}"                    "\n"
 );
 
 asm volatile (
 ".text\n"
 ".globl " SYMBOL_STRING(JaegerStubVeneer)   "\n"
 SYMBOL_STRING(JaegerStubVeneer) ":"         "\n"
     /* We enter this function as a veneer between a compiled method and one of the js_ stubs. We
--- a/js/src/methodjit/TrampolineCompiler.cpp
+++ b/js/src/methodjit/TrampolineCompiler.cpp
@@ -133,17 +133,21 @@ TrampolineCompiler::generateForceReturn(
     masm.loadPtr(FrameAddress(offsetof(VMFrame, cx)), Registers::ArgReg1);
     masm.storePtr(Registers::ReturnReg, FrameAddress(offsetof(VMFrame, fp)));
     masm.storePtr(Registers::ReturnReg, Address(Registers::ArgReg1, offsetof(JSContext, fp)));
 
     Address rval(JSFrameReg, JSStackFrame::offsetReturnValue());
     masm.loadPayload(rval, JSReturnReg_Data);
     masm.loadTypeTag(rval, JSReturnReg_Type);
 
-    masm.restoreReturnAddress();
+#ifndef JS_CPU_ARM
+    masm.push(Address(JSFrameReg, offsetof(JSStackFrame, ncode)));
+#else
+    masm.move(Address(JSFrameReg, offsetof(JSStackFrame, ncode)), JSC::ARMRegisters::lr);
+#endif
 
     masm.move(Registers::ReturnReg, JSFrameReg);
 #ifdef DEBUG
     masm.storePtr(ImmPtr(JSStackFrame::sInvalidPC),
                   Address(JSFrameReg, offsetof(JSStackFrame, savedPC)));
 #endif
 
     masm.ret();