Bug 782659: Fix assertions about empty registers when profiling is enabled on ARM. r=bhackett
authorAlex Crichton <acrichton@mozilla.com>
Tue, 21 Aug 2012 17:57:28 -0700
changeset 105072 2a9b3c766512e7841b7393be8f425e7c78738997
parent 105071 cd82204dcb678c08b63a7774c7af0bbda292dcf8
child 105073 0f34437ce5332e039d7ecb37ee9f8b754971e0f0
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewersbhackett
bugs782659
milestone17.0a1
Bug 782659: Fix assertions about empty registers when profiling is enabled on ARM. r=bhackett
js/src/methodjit/BaseAssembler.h
--- a/js/src/methodjit/BaseAssembler.h
+++ b/js/src/methodjit/BaseAssembler.h
@@ -531,16 +531,19 @@ static const JSC::MacroAssembler::Regist
     // is assumed to be aligned to 16-bytes plus any pushes that occured via
     // saveRegs().
     //
     // During a call sequence all registers are "owned" by the Assembler.
     // Attempts to perform loads, nested calls, or anything that can clobber
     // a register, is asking for breaking on some platform or some situation.
     // Be careful to limit to storeArg() during setupABICall.
     void setupABICall(Registers::CallConvention convention, uint32_t generalArgs) {
+        if (sps && sps->enabled())
+            leaveBeforeCall();
+
         JS_ASSERT(!callIsAligned);
 
         uint32_t numArgRegs = Registers::numArgRegs(convention);
         uint32_t pushCount = (generalArgs > numArgRegs)
                            ? generalArgs - numArgRegs
                            : 0;
 
         // Assume all temporary regs are available to clobber.
@@ -674,16 +677,43 @@ static const JSC::MacroAssembler::Regist
         if (Registers::regForArg(callConvention, i, &to)) {
             move(imm, to);
             availInCall.takeRegUnchecked(to);
         } else {
             store32(imm, addressOfArg(i));
         }
     }
 
+  private:
+    // When profiling is enabled, we need to run an epilogue and a prologue to
+    // every call. These two functions manage this code generation and are
+    // called from callWithABI below.
+    void leaveBeforeCall() {
+        if (availInCall.empty()) {
+            RegisterID reg = Registers(Registers::TempRegs).peekReg().reg();
+            saveReg(reg);
+            sps->leave(*this, reg);
+            restoreReg(reg);
+        } else {
+            sps->leave(*this, availInCall.peekReg().reg());
+        }
+    }
+
+    void reenterAfterCall() {
+        if (availInCall.empty()) {
+            RegisterID reg = Registers(Registers::TempRegs).peekReg().reg();
+            saveReg(reg);
+            sps->reenter(*this, reg);
+            restoreReg(reg);
+        } else {
+            sps->reenter(*this, availInCall.peekReg().reg());
+        }
+    }
+
+  public:
     // High-level call helper, given an optional function pointer and a
     // calling convention. setupABICall() must have been called beforehand,
     // as well as each numbered argument stored with storeArg().
     //
     // After callWithABI(), the call state is reset, so a new call may begin.
     Call callWithABI(void *fun, bool canThrow) {
 #ifdef JS_CPU_ARM
         // the repatcher requires that these instructions are adjacent in
@@ -702,31 +732,25 @@ static const JSC::MacroAssembler::Regist
             // Some platforms (such as ARM) require a call veneer if the target
             // might THROW. For other platforms, getFallibleCallTarget does
             // nothing.
             fun = getFallibleCallTarget(fun);
         //}
 
         JS_ASSERT(callIsAligned);
 
-        Call cl;
-        if (sps && sps->enabled()) {
-            RegisterID reg = availInCall.takeAnyReg().reg();
-            sps->leave(*this, reg);
-            cl = call();
-            sps->reenter(*this, reg);
-            availInCall.putReg(reg);
-        } else {
-            cl = call();
-        }
+        Call cl = call();
 
         callPatches.append(CallPatch(cl, fun));
+
 #ifdef JS_CPU_ARM
         JS_ASSERT(initFlushCount == flushCount());
 #endif
+        if (sps && sps->enabled())
+            reenterAfterCall();
         if (stackAdjust)
             addPtr(Imm32(stackAdjust), stackPointerRegister);
 
         stackAdjust = 0;
 
 #ifdef DEBUG
         callIsAligned = false;
 #endif