Bug 1112160 - Baseline Stubs: Align the stack when the number of argument is statically known. r=jandem
authorNicolas B. Pierron <nicolas.b.pierron@mozilla.com>
Thu, 12 Feb 2015 14:53:06 +0100
changeset 228812 25c0f57abbdb02343609db99e72339a405841c4e
parent 228811 2eca2e88f8e319adaec6955b6337f95f479bf48c
child 228813 e7e6e82492cb8156e0e217aae3312c3f6785d76e
push id55536
push usernpierron@mozilla.com
push dateThu, 12 Feb 2015 13:53:23 +0000
treeherdermozilla-inbound@e7e6e82492cb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1112160
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1112160 - Baseline Stubs: Align the stack when the number of argument is statically known. r=jandem
js/src/jit/BaselineIC.cpp
js/src/jit/MacroAssembler.cpp
js/src/jit/MacroAssembler.h
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -4094,16 +4094,20 @@ ICGetElemNativeCompiler::emitCallScripte
 {
     GeneralRegisterSet regs = availableGeneralRegs(0);
     regs.takeUnchecked(objReg);
     regs.takeUnchecked(BaselineTailCallReg);
 
     // Enter stub frame.
     enterStubFrame(masm, regs.getAny());
 
+    // Align the stack such that the JitFrameLayout is aligned on
+    // JitStackAlignment.
+    masm.alignJitStackBasedOnNArgs(0);
+
     // Push |this| for getter (target object).
     {
         ValueOperand val = regs.takeAnyValue();
         masm.tagValue(JSVAL_TYPE_OBJECT, objReg, val);
         masm.Push(val);
         regs.add(val);
     }
 
@@ -7367,16 +7371,20 @@ ICGetProp_CallScripted::Compiler::genera
         callee = regs.takeAny();
     }
     Register code = regs.takeAny();
     masm.loadPtr(Address(BaselineStubReg, ICGetProp_CallScripted::offsetOfGetter()), callee);
     masm.branchIfFunctionHasNoScript(callee, &failureLeaveStubFrame);
     masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), code);
     masm.loadBaselineOrIonRaw(code, code, &failureLeaveStubFrame);
 
+    // Align the stack such that the JitFrameLayout is aligned on
+    // JitStackAlignment.
+    masm.alignJitStackBasedOnNArgs(0);
+
     // Getter is called with 0 arguments, just |obj| as thisv.
     // Note that we use Push, not push, so that callJit will align the stack
     // properly on ARM.
     masm.Push(R0);
     EmitCreateStubFrameDescriptor(masm, scratch);
     masm.Push(Imm32(0));  // ActualArgc is 0
     masm.Push(callee);
     masm.Push(scratch);
@@ -8861,24 +8869,27 @@ ICSetProp_CallScripted::Compiler::genera
         callee = regs.takeAny();
     }
     Register code = regs.takeAny();
     masm.loadPtr(Address(BaselineStubReg, ICSetProp_CallScripted::offsetOfSetter()), callee);
     masm.branchIfFunctionHasNoScript(callee, &failureLeaveStubFrame);
     masm.loadPtr(Address(callee, JSFunction::offsetOfNativeOrScript()), code);
     masm.loadBaselineOrIonRaw(code, code, &failureLeaveStubFrame);
 
+    // Align the stack such that the JitFrameLayout is aligned on
+    // JitStackAlignment.
+    masm.alignJitStackBasedOnNArgs(1);
+
     // Setter is called with the new value as the only argument, and |obj| as thisv.
     // Note that we use Push, not push, so that callJit will align the stack
     // properly on ARM.
 
     // To Push R1, read it off of the stowed values on stack.
-    // Stack: [ ..., R0, R1, ..STUBFRAME-HEADER.. ]
-    masm.movePtr(BaselineStackReg, scratch);
-    masm.PushValue(Address(scratch, STUB_FRAME_SIZE));
+    // Stack: [ ..., R0, R1, ..STUBFRAME-HEADER.., padding? ]
+    masm.PushValue(Address(BaselineFrameReg, STUB_FRAME_SIZE));
     masm.Push(R0);
     EmitCreateStubFrameDescriptor(masm, scratch);
     masm.Push(Imm32(1));  // ActualArgc is 1
     masm.Push(callee);
     masm.Push(scratch);
 
     // Handle arguments underflow.
     Label noUnderflow;
@@ -10830,35 +10841,44 @@ ICCall_ScriptedFunCall::Compiler::genera
     // We no longer need R1.
     regs.add(R1);
 
     // Push a stub frame so that we can perform a non-tail call.
     enterStubFrame(masm, regs.getAny());
     if (canUseTailCallReg)
         regs.add(BaselineTailCallReg);
 
+    // Decrement argc if argc > 0. If argc == 0, push |undefined| as |this|.
+    Label zeroArgs, done;
+    masm.branchTest32(Assembler::Zero, argcReg, argcReg, &zeroArgs);
+
+    // Avoid the copy of the callee (function.call).
+    masm.sub32(Imm32(1), argcReg);
+
     // Values are on the stack left-to-right. Calling convention wants them
     // right-to-left so duplicate them on the stack in reverse order.
     pushCallArguments(masm, regs, argcReg, /* isJitCall = */ true);
 
-    // Discard callee (function.call).
-    masm.addPtr(Imm32(sizeof(Value)), StackPointer);
-
     // Pop scripted callee (the original |this|).
     ValueOperand val = regs.takeAnyValue();
     masm.popValue(val);
 
-    // Decrement argc if argc > 0. If argc == 0, push |undefined| as |this|.
-    Label zeroArgs, done;
-    masm.branchTest32(Assembler::Zero, argcReg, argcReg, &zeroArgs);
-    masm.sub32(Imm32(1), argcReg);
     masm.jump(&done);
-
     masm.bind(&zeroArgs);
+
+    // Copy scripted callee (the original |this|).
+    Address thisSlotFromStubFrame(BaselineFrameReg, STUB_FRAME_SIZE);
+    masm.loadValue(thisSlotFromStubFrame, val);
+
+    // Align the stack.
+    masm.alignJitStackBasedOnNArgs(0);
+
+    // Store the new |this|.
     masm.pushValue(UndefinedValue());
+
     masm.bind(&done);
 
     // Unbox scripted callee.
     callee = masm.extractObject(val, ExtractTemp0);
 
     Register scratch = regs.takeAny();
     EmitCreateStubFrameDescriptor(masm, scratch);
 
--- a/js/src/jit/MacroAssembler.cpp
+++ b/js/src/jit/MacroAssembler.cpp
@@ -2327,20 +2327,55 @@ MacroAssembler::alignJitStackBasedOnNArg
     //     sp = sp & ~(JitStackAlignment - 1);
     // }
     Label odd, end;
     Label *maybeAssert = &end;
 #ifdef DEBUG
     Label assert;
     maybeAssert = &assert;
 #endif
+    assertStackAlignment(sizeof(Value), 0);
     branchTestPtr(Assembler::NonZero, nargs, Imm32(1), &odd);
     branchTestPtr(Assembler::NonZero, StackPointer, Imm32(JitStackAlignment - 1), maybeAssert);
     subPtr(Imm32(sizeof(Value)), StackPointer);
 #ifdef DEBUG
     bind(&assert);
 #endif
     assertStackAlignment(JitStackAlignment, sizeof(Value));
     jump(&end);
     bind(&odd);
     andPtr(Imm32(~(JitStackAlignment - 1)), StackPointer);
     bind(&end);
 }
+
+void
+MacroAssembler::alignJitStackBasedOnNArgs(uint32_t nargs)
+{
+    const uint32_t alignment = JitStackAlignment / sizeof(Value);
+    if (alignment == 1)
+        return;
+
+    // A JitFrameLayout is composed of the following:
+    // [padding?] [argN] .. [arg1] [this] [[argc] [callee] [descr] [raddr]]
+    //
+    // We want to ensure that the |raddr| address is aligned.
+    // Which implies that we want to ensure that |this| is aligned.
+    static_assert(sizeof(JitFrameLayout) % JitStackAlignment == 0,
+      "No need to consider the JitFrameLayout for aligning the stack");
+
+    // Which implies that |argN| is aligned if |nargs| is even, and offset by
+    // |sizeof(Value)| if |nargs| is odd.
+    MOZ_ASSERT(alignment == 2);
+
+    // Thus the |padding| is offset by |sizeof(Value)| if |nargs| is even, and
+    // aligned if |nargs| is odd.
+
+    assertStackAlignment(sizeof(Value), 0);
+    if (nargs % 2 == 0) {
+        Label end;
+        branchTestPtr(Assembler::NonZero, StackPointer, Imm32(JitStackAlignment - 1), &end);
+        subPtr(Imm32(sizeof(Value)), StackPointer);
+        bind(&end);
+        assertStackAlignment(JitStackAlignment, sizeof(Value));
+    } else {
+        andPtr(Imm32(~(JitStackAlignment - 1)), StackPointer);
+    }
+}
--- a/js/src/jit/MacroAssembler.h
+++ b/js/src/jit/MacroAssembler.h
@@ -1251,16 +1251,17 @@ class MacroAssembler : public MacroAssem
         MOZ_ASSERT(framePushed() == aic.initialStack);
         PopRegsInMask(liveRegs);
     }
 
     // Align the stack pointer based on the number of arguments which are pushed
     // on the stack, such that the JitFrameLayout would be correctly aligned on
     // the JitStackAlignment.
     void alignJitStackBasedOnNArgs(Register nargs);
+    void alignJitStackBasedOnNArgs(uint32_t nargs);
 
     void assertStackAlignment(uint32_t alignment, int32_t offset = 0) {
 #ifdef DEBUG
         Label ok, bad;
         MOZ_ASSERT(IsPowerOfTwo(alignment));
 
         // Wrap around the offset to be a non-negative number.
         offset %= alignment;