Bug 945223 - Ensure correct baseline stack when calling out to noSuchMethod, so that decompiler works. r=efaust, a=lsblakk
authorKannan Vijayan <kvijayan@mozilla.com>
Thu, 19 Dec 2013 09:51:03 -0500
changeset 168907 ce854959b0a0358029f6fa42d6645789ecb9a9e5
parent 168906 7a42668c79b014fd8cb74375fbaf7a94bfa6ca70
child 168908 9901690374a73983dcbb227fd72f740374e4b133
push id4789
push userryanvm@gmail.com
push dateThu, 19 Dec 2013 14:53:09 +0000
treeherdermozilla-aurora@88a797bd34de [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust, lsblakk
bugs945223
milestone28.0a2
Bug 945223 - Ensure correct baseline stack when calling out to noSuchMethod, so that decompiler works. r=efaust, a=lsblakk
js/src/jit-test/tests/baseline/bug945223.js
js/src/jit/BaselineIC.cpp
js/src/jit/arm/BaselineHelpers-arm.h
js/src/jit/x64/BaselineHelpers-x64.h
js/src/jit/x86/BaselineHelpers-x86.h
new file mode 100644
--- /dev/null
+++ b/js/src/jit-test/tests/baseline/bug945223.js
@@ -0,0 +1,12 @@
+// |jit-test| error: InternalError
+
+Array.prototype.__proto__ = Proxy.create({
+    getPropertyDescriptor: function(name) {
+	return (560566);
+    },
+}, null);
+function f() {}
+function g() {  }    
+var x = [f,f,f,undefined,g];
+for (var i = 0; i < 5; ++i)
+  y = x[i]("x");
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -4272,29 +4272,41 @@ ICGetElemNativeCompiler::generateStubCod
 #if JS_HAS_NO_SUCH_METHOD
         if (isCallElem_) {
             Label afterNoSuchMethod;
             Label skipNoSuchMethod;
 
             masm.branchTestUndefined(Assembler::NotEqual, valAddr, &skipNoSuchMethod);
 
             GeneralRegisterSet regs = availableGeneralRegs(0);
+            regs.take(R1);
+            regs.take(R0);
             regs.takeUnchecked(objReg);
-            regs.take(R1);
-            Register scratch = regs.takeAnyExcluding(BaselineTailCallReg);
             if (popR1)
                 masm.pop(R1.scratchReg());
-            enterStubFrame(masm, scratch);
+
+            // Box and push obj and key onto baseline frame stack for decompiler.
+            masm.tagValue(JSVAL_TYPE_OBJECT, objReg, R0);
+            EmitStowICValues(masm, 2);
+
+            regs.add(R0);
+            regs.takeUnchecked(objReg);
+
+            enterStubFrame(masm, regs.getAnyExcluding(BaselineTailCallReg));
 
             masm.pushValue(R1);
             masm.push(objReg);
             if (!callVM(LookupNoSuchMethodHandlerInfo, masm))
                 return false;
 
             leaveStubFrame(masm);
+
+            // Pop pushed obj and key from baseline stack.
+            EmitUnstowICValues(masm, 2, /* discard = */ true);
+
             // Result is already in R0
             masm.jump(&afterNoSuchMethod);
             masm.bind(&skipNoSuchMethod);
 
             if (popR1)
                 masm.pop(R1.scratchReg());
             masm.loadValue(valAddr, R0);
             masm.bind(&afterNoSuchMethod);
@@ -4448,34 +4460,48 @@ ICGetElem_Dense::Compiler::generateStubC
 #if JS_HAS_NO_SUCH_METHOD
     entersStubFrame_ = true;
     if (isCallElem_) {
         Label afterNoSuchMethod;
         Label skipNoSuchMethod;
         regs = availableGeneralRegs(0);
         regs.takeUnchecked(obj);
         regs.takeUnchecked(key);
+        regs.takeUnchecked(BaselineTailCallReg);
         ValueOperand val = regs.takeValueOperand();
 
         masm.loadValue(element, val);
         masm.branchTestUndefined(Assembler::NotEqual, val, &skipNoSuchMethod);
+
+        // Box and push obj and key onto baseline frame stack for decompiler.
+        EmitRestoreTailCallReg(masm);
+        masm.tagValue(JSVAL_TYPE_OBJECT, obj, val);
+        masm.pushValue(val);
+        masm.tagValue(JSVAL_TYPE_INT32, key, val);
+        masm.pushValue(val);
+        EmitRepushTailCallReg(masm);
+
         regs.add(val);
 
         // Call __noSuchMethod__ checker.  Object pointer is in objReg.
         enterStubFrame(masm, regs.getAnyExcluding(BaselineTailCallReg));
 
         regs.take(val);
 
         masm.tagValue(JSVAL_TYPE_INT32, key, val);
         masm.pushValue(val);
         masm.push(obj);
         if (!callVM(LookupNoSuchMethodHandlerInfo, masm))
             return false;
 
         leaveStubFrame(masm);
+
+        // Pop pushed obj and key from baseline stack.
+        EmitUnstowICValues(masm, 2, /* discard = */ true);
+
         // Result is already in R0
         masm.jump(&afterNoSuchMethod);
         masm.bind(&skipNoSuchMethod);
 
         masm.moveValue(val, R0);
         masm.bind(&afterNoSuchMethod);
     } else {
         masm.loadValue(element, R0);
@@ -4679,29 +4705,43 @@ ICGetElem_Arguments::Compiler::generateS
     if (isCallElem_) {
         Label afterNoSuchMethod;
         Label skipNoSuchMethod;
 
         masm.branchTestUndefined(Assembler::NotEqual, tempVal, &skipNoSuchMethod);
 
         // Call __noSuchMethod__ checker.  Object pointer is in objReg.
         regs = availableGeneralRegs(0);
-        // R1 and objReg are guaranteed not to overlap.
         regs.takeUnchecked(objReg);
-        regs.take(R1);
-        masm.tagValue(JSVAL_TYPE_INT32, idxReg, R1);
-        scratchReg = regs.takeAnyExcluding(BaselineTailCallReg);
-        enterStubFrame(masm, scratchReg);
-
-        masm.pushValue(R1);
+        regs.takeUnchecked(idxReg);
+        regs.takeUnchecked(BaselineTailCallReg);
+        ValueOperand val = regs.takeValueOperand();
+
+        // Box and push obj and key onto baseline frame stack for decompiler.
+        EmitRestoreTailCallReg(masm);
+        masm.tagValue(JSVAL_TYPE_OBJECT, objReg, val);
+        masm.pushValue(val);
+        masm.tagValue(JSVAL_TYPE_INT32, idxReg, val);
+        masm.pushValue(val);
+        EmitRepushTailCallReg(masm);
+
+        regs.add(val);
+        enterStubFrame(masm, regs.getAnyExcluding(BaselineTailCallReg));
+        regs.take(val);
+
+        masm.pushValue(val);
         masm.push(objReg);
         if (!callVM(LookupNoSuchMethodHandlerInfo, masm))
             return false;
 
         leaveStubFrame(masm);
+
+        // Pop pushed obj and key from baseline stack.
+        EmitUnstowICValues(masm, 2, /* discard = */ true);
+
         // Result is already in R0
         masm.jump(&afterNoSuchMethod);
         masm.bind(&skipNoSuchMethod);
 
         masm.moveValue(tempVal, R0);
         masm.bind(&afterNoSuchMethod);
     } else {
         masm.moveValue(tempVal, R0);
@@ -6509,26 +6549,43 @@ ICGetPropNativeCompiler::generateStubCod
         Label afterNoSuchMethod;
         Label skipNoSuchMethod;
 
         masm.push(objReg);
         masm.loadValue(result, R0);
         masm.branchTestUndefined(Assembler::NotEqual, R0, &skipNoSuchMethod);
 
         masm.pop(objReg);
-        enterStubFrame(masm, scratch);
-
-        masm.movePtr(ImmGCPtr(propName_.get()), R1.scratchReg());
-        masm.tagValue(JSVAL_TYPE_STRING, R1.scratchReg(), R1);
-        masm.pushValue(R1);
+
+        // Call __noSuchMethod__ checker.  Object pointer is in objReg.
+        regs = availableGeneralRegs(0);
+        regs.takeUnchecked(objReg);
+        regs.takeUnchecked(BaselineTailCallReg);
+        ValueOperand val = regs.takeValueOperand();
+
+        // Box and push obj onto baseline frame stack for decompiler.
+        EmitRestoreTailCallReg(masm);
+        masm.tagValue(JSVAL_TYPE_OBJECT, objReg, val);
+        masm.pushValue(val);
+        EmitRepushTailCallReg(masm);
+
+        enterStubFrame(masm, regs.getAnyExcluding(BaselineTailCallReg));
+
+        masm.movePtr(ImmGCPtr(propName_.get()), val.scratchReg());
+        masm.tagValue(JSVAL_TYPE_STRING, val.scratchReg(), val);
+        masm.pushValue(val);
         masm.push(objReg);
         if (!callVM(LookupNoSuchMethodHandlerInfo, masm))
             return false;
 
         leaveStubFrame(masm);
+
+        // Pop pushed obj from baseline stack.
+        EmitUnstowICValues(masm, 1, /* discard = */ true);
+
         masm.jump(&afterNoSuchMethod);
         masm.bind(&skipNoSuchMethod);
 
         // Pop pushed objReg.
         masm.addPtr(Imm32(sizeof(void *)), BaselineStackReg);
         masm.bind(&afterNoSuchMethod);
     } else {
         masm.loadValue(result, R0);
--- a/js/src/jit/arm/BaselineHelpers-arm.h
+++ b/js/src/jit/arm/BaselineHelpers-arm.h
@@ -21,16 +21,22 @@ static const size_t ICStackValueOffset =
 
 inline void
 EmitRestoreTailCallReg(MacroAssembler &masm)
 {
     // No-op on ARM because link register is always holding the return address.
 }
 
 inline void
+EmitRepushTailCallReg(MacroAssembler &masm)
+{
+    // No-op on ARM because link register is always holding the return address.
+}
+
+inline void
 EmitCallIC(CodeOffsetLabel *patchOffset, MacroAssembler &masm)
 {
     // Move ICEntry offset into BaselineStubReg
     CodeOffsetLabel offset = masm.movWithPatch(ImmWord(-1), BaselineStubReg);
     *patchOffset = offset;
 
     // Load stub pointer into BaselineStubReg
     masm.loadPtr(Address(BaselineStubReg, ICEntry::offsetOfFirstStub()), BaselineStubReg);
@@ -191,28 +197,35 @@ EmitStowICValues(MacroAssembler &masm, i
         // Stow R0 and R1
         masm.pushValue(R0);
         masm.pushValue(R1);
         break;
     }
 }
 
 inline void
-EmitUnstowICValues(MacroAssembler &masm, int values)
+EmitUnstowICValues(MacroAssembler &masm, int values, bool discard = false)
 {
     JS_ASSERT(values >= 0 && values <= 2);
     switch(values) {
       case 1:
         // Unstow R0
-        masm.popValue(R0);
+        if (discard)
+            masm.addPtr(Imm32(sizeof(Value)), BaselineStackReg);
+        else
+            masm.popValue(R0);
         break;
       case 2:
         // Unstow R0 and R1
-        masm.popValue(R1);
-        masm.popValue(R0);
+        if (discard) {
+            masm.addPtr(Imm32(sizeof(Value) * 2), BaselineStackReg);
+        } else {
+            masm.popValue(R1);
+            masm.popValue(R0);
+        }
         break;
     }
 }
 
 inline void
 EmitCallTypeUpdateIC(MacroAssembler &masm, IonCode *code, uint32_t objectOffset)
 {
     JS_ASSERT(R2 == ValueOperand(r1, r0));
--- a/js/src/jit/x64/BaselineHelpers-x64.h
+++ b/js/src/jit/x64/BaselineHelpers-x64.h
@@ -21,16 +21,22 @@ static const size_t ICStackValueOffset =
 
 inline void
 EmitRestoreTailCallReg(MacroAssembler &masm)
 {
     masm.pop(BaselineTailCallReg);
 }
 
 inline void
+EmitRepushTailCallReg(MacroAssembler &masm)
+{
+    masm.push(BaselineTailCallReg);
+}
+
+inline void
 EmitCallIC(CodeOffsetLabel *patchOffset, MacroAssembler &masm)
 {
     // Move ICEntry offset into BaselineStubReg
     CodeOffsetLabel offset = masm.movWithPatch(ImmWord(-1), BaselineStubReg);
     *patchOffset = offset;
 
     // Load stub pointer into BaselineStubReg
     masm.loadPtr(Address(BaselineStubReg, (int32_t) ICEntry::offsetOfFirstStub()),
@@ -177,31 +183,38 @@ EmitStowICValues(MacroAssembler &masm, i
         masm.pushValue(R0);
         masm.pushValue(R1);
         masm.push(BaselineTailCallReg);
         break;
     }
 }
 
 inline void
-EmitUnstowICValues(MacroAssembler &masm, int values)
+EmitUnstowICValues(MacroAssembler &masm, int values, bool discard = false)
 {
     JS_ASSERT(values >= 0 && values <= 2);
     switch(values) {
       case 1:
         // Unstow R0
         masm.pop(BaselineTailCallReg);
-        masm.popValue(R0);
+        if (discard)
+            masm.addPtr(Imm32(sizeof(Value)), BaselineStackReg);
+        else
+            masm.popValue(R0);
         masm.push(BaselineTailCallReg);
         break;
       case 2:
         // Unstow R0 and R1
         masm.pop(BaselineTailCallReg);
-        masm.popValue(R1);
-        masm.popValue(R0);
+        if (discard) {
+            masm.addPtr(Imm32(sizeof(Value) * 2), BaselineStackReg);
+        } else {
+            masm.popValue(R1);
+            masm.popValue(R0);
+        }
         masm.push(BaselineTailCallReg);
         break;
     }
 }
 
 inline void
 EmitCallTypeUpdateIC(MacroAssembler &masm, IonCode *code, uint32_t objectOffset)
 {
--- a/js/src/jit/x86/BaselineHelpers-x86.h
+++ b/js/src/jit/x86/BaselineHelpers-x86.h
@@ -21,16 +21,22 @@ static const size_t ICStackValueOffset =
 
 inline void
 EmitRestoreTailCallReg(MacroAssembler &masm)
 {
     masm.pop(BaselineTailCallReg);
 }
 
 inline void
+EmitRepushTailCallReg(MacroAssembler &masm)
+{
+    masm.push(BaselineTailCallReg);
+}
+
+inline void
 EmitCallIC(CodeOffsetLabel *patchOffset, MacroAssembler &masm)
 {
     // Move ICEntry offset into BaselineStubReg
     CodeOffsetLabel offset = masm.movWithPatch(ImmWord(-1), BaselineStubReg);
     *patchOffset = offset;
 
     // Load stub pointer into BaselineStubReg
     masm.loadPtr(Address(BaselineStubReg, (int32_t) ICEntry::offsetOfFirstStub()),
@@ -183,31 +189,38 @@ EmitStowICValues(MacroAssembler &masm, i
         masm.pushValue(R0);
         masm.pushValue(R1);
         masm.push(BaselineTailCallReg);
         break;
     }
 }
 
 inline void
-EmitUnstowICValues(MacroAssembler &masm, int values)
+EmitUnstowICValues(MacroAssembler &masm, int values, bool discard = false)
 {
     JS_ASSERT(values >= 0 && values <= 2);
     switch(values) {
       case 1:
         // Unstow R0
         masm.pop(BaselineTailCallReg);
-        masm.popValue(R0);
+        if (discard)
+            masm.addPtr(Imm32(sizeof(Value)), BaselineStackReg);
+        else
+            masm.popValue(R0);
         masm.push(BaselineTailCallReg);
         break;
       case 2:
         // Unstow R0 and R1
         masm.pop(BaselineTailCallReg);
-        masm.popValue(R1);
-        masm.popValue(R0);
+        if (discard) {
+            masm.addPtr(Imm32(sizeof(Value) * 2), BaselineStackReg);
+        } else {
+            masm.popValue(R1);
+            masm.popValue(R0);
+        }
         masm.push(BaselineTailCallReg);
         break;
     }
 }
 
 inline void
 EmitCallTypeUpdateIC(MacroAssembler &masm, IonCode *code, uint32_t objectOffset)
 {