Mark frame types correctly. (Bug 685099, r=dvander)
authorSean Stangl <sstangl@mozilla.com>
Wed, 14 Sep 2011 11:13:50 -0700
changeset 77313 23edb5d4dea53215c5bc46015e237cb3a9f468c5
parent 77312 31641ffb0e9d5550b58fea50d32c8abb942add38
child 77418 587ade985b16db665c9da8d95d32d5227dbc8937
push id201
push usersean.stangl@gmail.com
push dateThu, 15 Sep 2011 00:47:07 +0000
reviewersdvander
bugs685099
milestone9.0a1
Mark frame types correctly. (Bug 685099, r=dvander)
js/src/ion/IonFrames.h
js/src/ion/shared/CodeGenerator-x86-shared.cpp
js/src/ion/x64/Trampoline-x64.cpp
js/src/ion/x86/Trampoline-x86.cpp
--- a/js/src/ion/IonFrames.h
+++ b/js/src/ion/IonFrames.h
@@ -52,40 +52,51 @@ namespace js {
 namespace ion {
 
 // The layout of an Ion frame on the C stack:
 //   argN     _ 
 //   ...       \ - These are jsvals
 //   arg0      /
 //   this    _/
 //   calleeToken - Encodes script or JSFunction
-//   descriptor  - Size of the parent frame 
+//   sizeDescriptor  - Size of the parent frame, with lower bits for FrameType.
 //   returnAddr - Return address, entering into the next call.
 //   .. locals ..
 
 // Layout of the frame prefix. This assumes the stack architecture grows down.
 // If this is ever not the case, we'll have to refactor.
 struct IonFrameData
 {
     void *returnAddress_;
     uintptr_t sizeDescriptor_;
     void *calleeToken_;
 };
 
 class IonFramePrefix : protected IonFrameData
 {
   public:
+    enum FrameType {
+        JSFrame,
+        EntryFrame,
+        RectifierFrame
+    };
+
+    // The FrameType is packed into the sizeDescriptor by left-shifting the
+    // sizeDescriptor by FrameTypeBits, then ORing in the FrameType.
+    static const unsigned FrameTypeBits = 2;
+
+  public:
     // True if this is the frame passed into EnterIonCode.
     bool isEntryFrame() const {
-        return !(sizeDescriptor_ & 1);
+        return !!(sizeDescriptor_ & EntryFrame);
     }
     // The depth of the parent frame.
     size_t prevFrameDepth() const {
         JS_ASSERT(!isEntryFrame());
-        return sizeDescriptor_ >> 1;
+        return sizeDescriptor_ >> FrameTypeBits;
     }
     IonFramePrefix *prev() const {
         JS_ASSERT(!isEntryFrame());
         return (IonFramePrefix *)((uint8 *)this - prevFrameDepth());
     }
     void *calleeToken() const {
         return calleeToken_;
     }
--- a/js/src/ion/shared/CodeGenerator-x86-shared.cpp
+++ b/js/src/ion/shared/CodeGenerator-x86-shared.cpp
@@ -722,19 +722,19 @@ CodeGeneratorX86Shared::visitCallGeneric
     masm.movePtr(Operand(objreg, offsetof(JSScript, ion)), objreg);
 
     // Bail if the callee has not yet been JITted.
     masm.testPtr(objreg, objreg);
     if (!bailoutIf(Assembler::Zero, call->snapshot()))
         return false;
 
     // Remember the size of the frame above this point, in case of bailout.
+    JS_STATIC_ASSERT(IonFramePrefix::JSFrame == 0x0);
     uint32 stack_size = masm.framePushed() - unused_stack;
-    // Mark !IonFramePrefix::isEntryFrame().
-    uint32 size_descriptor = stack_size << 1;
+    uint32 size_descriptor = stack_size << IonFramePrefix::FrameTypeBits;
 
     // Nestle %esp up to the argument vector.
     if (unused_stack)
         masm.addPtr(Imm32(unused_stack), StackPointer);
 
     // Construct the IonFramePrefix.
     masm.push(tokreg);
     masm.push(Imm32(size_descriptor));
--- a/js/src/ion/x64/Trampoline-x64.cpp
+++ b/js/src/ion/x64/Trampoline-x64.cpp
@@ -149,24 +149,27 @@ IonCompartment::generateEnterJIT(JSConte
     // Push the callee token. Remember on win64, there are 32 bytes of shadow
     // stack space.
     masm.push(token);
 
     /*****************************************************************
     Push the number of bytes we've pushed so far on the stack and call
     *****************************************************************/
     masm.subq(rsp, r14);
+    // Safe to not shift sizeDescriptor: no other consumers.
+    masm.orl(Imm32(0x1), r14); // Mark EntryFrame.
     masm.push(r14);
 
     // Call function.
     masm.call(reg_code);
 
     // Pop arguments and padding from stack.
-    masm.pop(r14);
-    masm.addq(r14, rsp);
+    masm.pop(r14);              // sizeDescriptor.
+    masm.xorl(Imm32(0x1), r14); // Unmark EntryFrame.
+    masm.addq(r14, rsp);        // Remove arguments.
 
     /*****************************************************************
     Place return value where it belongs, pop all saved registers
     *****************************************************************/
     masm.pop(r12); // vp
     masm.movq(JSReturnReg, Operand(r12, 0));
 
     GenerateReturn(masm, JS_TRUE);
@@ -175,23 +178,20 @@ IonCompartment::generateEnterJIT(JSConte
     return linker.newCode(cx);
 }
 
 IonCode *
 IonCompartment::generateReturnError(JSContext *cx)
 {
     MacroAssembler masm(cx);
 
-    // Pop arguments off the stack.
-    // eax <- 8*argc (size of all arguments we pushed on the stack)
-    masm.pop(r14);
-    masm.addq(r14, rsp);
-
-    // Discard pushed vp.
-    masm.pop(r11);
+    masm.pop(r14);              // sizeDescriptor.
+    masm.xorl(Imm32(0x1), r14); // Unmark EntryFrame.
+    masm.addq(r14, rsp);        // Remove arguments.
+    masm.pop(r11);              // Discard |vp|: returning from error.
 
     GenerateReturn(masm, JS_FALSE);
     
     Linker linker(masm);
     return linker.newCode(cx);
 }
 
 IonCode *
@@ -245,36 +245,38 @@ IonCompartment::generateArgumentsRectifi
 
         masm.mov(Operand(rcx, 0x0), rdx);
         masm.push(rdx);
 
         masm.testl(r8, r8);
         masm.j(Assembler::NonZero, &copyLoopTop);
     }
 
+    // Construct sizeDescriptor.
     masm.subq(rsp, rbp);
-    masm.shll(Imm32(1), rbp); // construct sizeDescriptor.
+    masm.shll(Imm32(IonFramePrefix::FrameTypeBits), rbp);
+    masm.orl(Imm32(IonFramePrefix::RectifierFrame), rbp);
 
     // Construct IonFrameData.
     masm.push(rax); // calleeToken.
     masm.push(rbp); // sizeDescriptor.
 
     // Call the target function.
     // Note that this code assumes the function is JITted.
     masm.movq(Operand(rax, offsetof(JSFunction, u.i.script)), rax);
     masm.movq(Operand(rax, offsetof(JSScript, ion)), rax);
     masm.movq(Operand(rax, offsetof(IonScript, method_)), rax);
     masm.movq(Operand(rax, IonCode::OffsetOfCode()), rax);
     masm.call(rax);
 
     // Remove the rectifier frame.
-    masm.pop(rbx);            // rbx <- sizeDescriptor_
-    masm.shrl(Imm32(1), rbx); // rbx <- size of pushed arguments
-    masm.pop(r11);            // Discard calleeToken_
-    masm.addq(rbx, rsp);      // Discard pushed arguments.
+    masm.pop(rbp);            // rbp <- sizeDescriptor with FrameType.
+    masm.shrl(Imm32(IonFramePrefix::FrameTypeBits), rbp); // rbp <- size of pushed arguments.
+    masm.pop(r11);            // Discard calleeToken.
+    masm.addq(rbp, rsp);      // Discard pushed arguments.
 
     masm.ret();
 
     Linker linker(masm);
     return linker.newCode(cx);
 }
 
 static void
--- a/js/src/ion/x86/Trampoline-x86.cpp
+++ b/js/src/ion/x86/Trampoline-x86.cpp
@@ -136,28 +136,32 @@ IonCompartment::generateEnterJIT(JSConte
     masm.push(Operand(ebp, 24));
 
     // Save the stack size so we can remove arguments and alignment after the
     // call.
     masm.movl(Operand(ebp, 12), eax);
     masm.shll(Imm32(3), eax);
     masm.addl(eax, ecx);
     masm.addl(Imm32(4), ecx);
+
+    // Safe to take lowest bit without shifting: aligned, and no other consumers.
+    masm.orl(Imm32(0x1), ecx); // Mark EntryFrame.
     masm.push(ecx);
 
     /***************************************************************
         Call passed-in code, get return value and fill in the
         passed in return value pointer
     ***************************************************************/
     // Call code  --code pointer is in ebp + 8
     masm.call(Operand(ebp, 8));
 
     // Pop arguments off the stack.
     // eax <- 8*argc (size of all arugments we pushed on the stack)
     masm.pop(eax);
+    masm.xorl(Imm32(0x1), eax); // Unmark EntryFrame.
     masm.addl(eax, esp);
 
     // |ebp| could have been clobbered by the inner function. For now, re-grab
     // |vp| directly off the stack:
     //
     //  +32 vp
     //  +28 argv
     //  +24 argc
@@ -180,20 +184,19 @@ IonCompartment::generateEnterJIT(JSConte
     return linker.newCode(cx);
 }
 
 IonCode *
 IonCompartment::generateReturnError(JSContext *cx)
 {
     MacroAssembler masm(cx);
 
-    // Pop arguments off the stack.
-    // eax <- 8*argc (size of all arugments we pushed on the stack)
-    masm.pop(eax);
-    masm.addl(eax, esp);
+    masm.pop(eax);              // sizeDescriptor.
+    masm.xorl(Imm32(0x1), eax); // Unmark EntryFrame.
+    masm.addl(eax, esp);        // Remove arguments.
 
     GenerateReturn(masm, JS_FALSE);
     
     Linker linker(masm);
     return linker.newCode(cx);
 }
 
 IonCode *
@@ -250,36 +253,38 @@ IonCompartment::generateArgumentsRectifi
         masm.push(edx);
         masm.mov(Operand(ecx, 0x0), edx);
         masm.push(edx);
 
         masm.testl(esi, esi);
         masm.j(Assembler::NonZero, &copyLoopTop);
     }
 
+    // Construct sizeDescriptor.
     masm.subl(esp, ebp);
-    masm.shll(Imm32(1), ebp); // construct sizeDescriptor.
+    masm.shll(Imm32(IonFramePrefix::FrameTypeBits), ebp);
+    masm.orl(Imm32(IonFramePrefix::RectifierFrame), ebp);
 
     // Construct IonFrameData.
     masm.push(eax); // calleeToken
     masm.push(ebp); // sizeDescriptor
 
     // Call the target function.
     // Note that this assumes the function is JITted.
     masm.movl(Operand(eax, offsetof(JSFunction, u.i.script)), eax);
     masm.movl(Operand(eax, offsetof(JSScript, ion)), eax);
     masm.movl(Operand(eax, offsetof(IonScript, method_)), eax);
     masm.movl(Operand(eax, IonCode::OffsetOfCode()), eax);
     masm.call(eax);
 
     // Remove the rectifier frame.
-    masm.pop(ebx);            // ebx <- sizeDescriptor
-    masm.shrl(Imm32(1), ebx); // ebx <- size of pushed arguments
-    masm.pop(edi);            // Discard calleeToken
-    masm.addl(ebx, esp);      // Discard pushed arguments.
+    masm.pop(ebp);            // ebp <- sizeDescriptor with FrameType.
+    masm.shrl(Imm32(IonFramePrefix::FrameTypeBits), ebp); // ebp <- sizeDescriptor.
+    masm.pop(edi);            // Discard calleeToken.
+    masm.addl(ebp, esp);      // Discard pushed arguments.
 
     masm.ret();
 
     Linker linker(masm);
     return linker.newCode(cx);
 }
 
 static void