Bug 1510105 - Save/restore JSReturnOperand when doing debug mode OSR after a VM call returns, r=tcampbell.
authorBrian Hackett <bhackett1024@gmail.com>
Tue, 27 Nov 2018 05:57:15 -1000
changeset 507887 9a1c57557089eec2d1256912c983ae8d63440fbb
parent 507886 4b16437f699949761edf056ff97c967bae28340e
child 507888 e17e9b14a4349edc70178cf8d9fe49ea537ef6d3
push id1905
push userffxbld-merge
push dateMon, 21 Jan 2019 12:33:13 +0000
treeherdermozilla-release@c2fca1944d8c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstcampbell
bugs1510105
milestone65.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 1510105 - Save/restore JSReturnOperand when doing debug mode OSR after a VM call returns, r=tcampbell.
js/src/jit/BaselineDebugModeOSR.cpp
--- a/js/src/jit/BaselineDebugModeOSR.cpp
+++ b/js/src/jit/BaselineDebugModeOSR.cpp
@@ -1099,99 +1099,124 @@ JitRuntime::getBaselineDebugModeOSRHandl
         return nullptr;
     }
     return popFrameReg
            ? baselineDebugModeOSRHandler_->raw()
            : baselineDebugModeOSRHandlerNoFrameRegPopAddr_.ref();
 }
 
 static void
+PushCallVMOutputRegisters(MacroAssembler& masm)
+{
+    // callVMs can use several different output registers, depending on the
+    // type of their outparam.
+    masm.push(ReturnReg);
+    masm.push(ReturnDoubleReg);
+    masm.Push(JSReturnOperand);
+}
+
+static void
+PopCallVMOutputRegisters(MacroAssembler& masm)
+{
+    masm.Pop(JSReturnOperand);
+    masm.pop(ReturnDoubleReg);
+    masm.pop(ReturnReg);
+}
+
+static void
+TakeCallVMOutputRegisters(AllocatableGeneralRegisterSet& regs)
+{
+    regs.take(ReturnReg);
+    regs.take(JSReturnOperand);
+}
+
+static void
 EmitBaselineDebugModeOSRHandlerTail(MacroAssembler& masm, Register temp, bool returnFromCallVM)
 {
     // Save real return address on the stack temporarily.
     //
     // If we're returning from a callVM, we don't need to worry about R0 and
-    // R1 but do need to propagate the original ReturnReg value. Otherwise we
-    // need to worry about R0 and R1 but can clobber ReturnReg. Indeed, on
-    // x86, R1 contains ReturnReg.
+    // R1 but do need to propagate the registers the call might write to.
+    // Otherwise we need to worry about R0 and R1 but can clobber ReturnReg.
+    // Indeed, on x86, R1 contains ReturnReg.
     if (returnFromCallVM) {
-        masm.push(ReturnReg);
+        PushCallVMOutputRegisters(masm);
     } else {
         masm.pushValue(Address(temp, offsetof(BaselineDebugModeOSRInfo, valueR0)));
         masm.pushValue(Address(temp, offsetof(BaselineDebugModeOSRInfo, valueR1)));
     }
     masm.push(BaselineFrameReg);
     masm.push(Address(temp, offsetof(BaselineDebugModeOSRInfo, resumeAddr)));
 
     // Call a stub to free the allocated info.
     masm.setupUnalignedABICall(temp);
     masm.loadBaselineFramePtr(BaselineFrameReg, temp);
     masm.passABIArg(temp);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, FinishBaselineDebugModeOSR));
 
     // Restore saved values.
     AllocatableGeneralRegisterSet jumpRegs(GeneralRegisterSet::All());
     if (returnFromCallVM) {
-        jumpRegs.take(ReturnReg);
+        TakeCallVMOutputRegisters(jumpRegs);
     } else {
         jumpRegs.take(R0);
         jumpRegs.take(R1);
     }
     jumpRegs.take(BaselineFrameReg);
     Register target = jumpRegs.takeAny();
 
     masm.pop(target);
     masm.pop(BaselineFrameReg);
     if (returnFromCallVM) {
-        masm.pop(ReturnReg);
+        PopCallVMOutputRegisters(masm);
     } else {
         masm.popValue(R1);
         masm.popValue(R0);
     }
 
     masm.jump(target);
 }
 
 JitCode*
 JitRuntime::generateBaselineDebugModeOSRHandler(JSContext* cx, uint32_t* noFrameRegPopOffsetOut)
 {
     StackMacroAssembler masm(cx);
 
     AllocatableGeneralRegisterSet regs(GeneralRegisterSet::All());
     regs.take(BaselineFrameReg);
-    regs.take(ReturnReg);
+    TakeCallVMOutputRegisters(regs);
     Register temp = regs.takeAny();
     Register syncedStackStart = regs.takeAny();
 
     // Pop the frame reg.
     masm.pop(BaselineFrameReg);
 
     // Not all patched baseline frames are returning from a situation where
     // the frame reg is already fixed up.
     CodeOffset noFrameRegPopOffset(masm.currentOffset());
 
     // Record the stack pointer for syncing.
     masm.moveStackPtrTo(syncedStackStart);
-    masm.push(ReturnReg);
+    PushCallVMOutputRegisters(masm);
     masm.push(BaselineFrameReg);
 
     // Call a stub to fully initialize the info.
     masm.setupUnalignedABICall(temp);
     masm.loadBaselineFramePtr(BaselineFrameReg, temp);
     masm.passABIArg(temp);
     masm.passABIArg(syncedStackStart);
     masm.passABIArg(ReturnReg);
     masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, SyncBaselineDebugModeOSRInfo));
 
     // Discard stack values depending on how many were unsynced, as we always
     // have a fully synced stack in the recompile handler. We arrive here via
     // a callVM, and prepareCallVM in BaselineCompiler always fully syncs the
     // stack.
     masm.pop(BaselineFrameReg);
-    masm.pop(ReturnReg);
+    PopCallVMOutputRegisters(masm);
     masm.loadPtr(Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfScratchValue()), temp);
     masm.addToStackPtr(Address(temp, offsetof(BaselineDebugModeOSRInfo, stackAdjust)));
 
     // Emit two tails for the case of returning from a callVM and all other
     // cases, as the state we need to restore differs depending on the case.
     Label returnFromCallVM, end;
     EmitBranchIsReturningFromCallVM(masm, temp, &returnFromCallVM);