Bug #807824: Don't restore register in oolcall when it is used as a return value, r=nbp
authorHannes Verschore <hv1989@gmail.com>
Mon, 05 Nov 2012 17:14:50 +0100
changeset 120247 516370bc10b7e8ed685b00d115067935d27c9e8c
parent 120246 6f8cee47bcd3969144e7c1fd5557578f80775dba
child 120248 041c8232bdcbc829664cf92541eb2feaf73aa9f1
push id1997
push userakeybl@mozilla.com
push dateMon, 07 Jan 2013 21:25:26 +0000
treeherdermozilla-beta@4baf45cdcf21 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnbp
bugs807824
milestone19.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 #807824: Don't restore register in oolcall when it is used as a return value, r=nbp
js/src/ion/IonMacroAssembler.cpp
js/src/ion/IonMacroAssembler.h
js/src/ion/RegisterSets.h
js/src/ion/shared/CodeGenerator-shared-inl.h
js/src/ion/shared/CodeGenerator-shared.h
--- a/js/src/ion/IonMacroAssembler.cpp
+++ b/js/src/ion/IonMacroAssembler.cpp
@@ -83,29 +83,31 @@ MacroAssembler::PushRegsInMask(RegisterS
     }
     for (FloatRegisterIterator iter(set.fpus()); iter.more(); iter++) {
         diff -= sizeof(double);
         storeDouble(*iter, Address(StackPointer, diff));
     }
 }
 
 void
-MacroAssembler::PopRegsInMask(RegisterSet set)
+MacroAssembler::PopRegsInMaskIgnore(RegisterSet set, RegisterSet ignore)
 {
     size_t diff = set.gprs().size() * STACK_SLOT_SIZE +
                   set.fpus().size() * sizeof(double);
     size_t reserved = diff;
 
     for (GeneralRegisterIterator iter(set.gprs()); iter.more(); iter++) {
         diff -= STACK_SLOT_SIZE;
-        loadPtr(Address(StackPointer, diff), *iter);
+        if (!ignore.has(*iter))
+            loadPtr(Address(StackPointer, diff), *iter);
     }
     for (FloatRegisterIterator iter(set.fpus()); iter.more(); iter++) {
         diff -= sizeof(double);
-        loadDouble(Address(StackPointer, diff), *iter);
+        if (!ignore.has(*iter))
+            loadDouble(Address(StackPointer, diff), *iter);
     }
 
     freeStack(reserved);
 }
 
 void
 MacroAssembler::branchTestValueTruthy(const ValueOperand &value, Label *ifTrue, FloatRegister fr)
 {
--- a/js/src/ion/IonMacroAssembler.h
+++ b/js/src/ion/IonMacroAssembler.h
@@ -253,20 +253,23 @@ class MacroAssembler : public MacroAssem
         else
             storeCallResultValue(dest.typedReg());
     }
 
     void PushRegsInMask(RegisterSet set);
     void PushRegsInMask(GeneralRegisterSet set) {
         PushRegsInMask(RegisterSet(set, FloatRegisterSet()));
     }
-    void PopRegsInMask(RegisterSet set);
+    void PopRegsInMask(RegisterSet set) {
+        PopRegsInMaskIgnore(set, RegisterSet());
+    }
     void PopRegsInMask(GeneralRegisterSet set) {
         PopRegsInMask(RegisterSet(set, FloatRegisterSet()));
     }
+    void PopRegsInMaskIgnore(RegisterSet set, RegisterSet ignore);
 
     void branchTestValueTruthy(const ValueOperand &value, Label *ifTrue, FloatRegister fr);
 
     using MacroAssemblerSpecific::Push;
 
     void Push(jsid id, Register scratchReg) {
         if (JSID_IS_GCTHING(id)) {
             // If we're pushing a gcthing, then we can't just push the tagged jsid
--- a/js/src/ion/RegisterSets.h
+++ b/js/src/ion/RegisterSets.h
@@ -118,16 +118,17 @@ class ValueOperand
 
     Register valueReg() const {
         return value_;
     }
 
     Register scratchReg() const {
         return valueReg();
     }
+
 #endif
 
     ValueOperand() {}
 };
 
 // Registers to hold either either a typed or untyped value.
 class TypedOrValueRegister
 {
@@ -423,16 +424,32 @@ class RegisterSet {
         fpu_.add(reg);
     }
     void add(const AnyRegister &any) {
         if (any.isFloat())
             add(any.fpu());
         else
             add(any.gpr());
     }
+    void add(ValueOperand value) {
+#if defined(JS_NUNBOX32)
+        add(value.payloadReg());
+        add(value.typeReg());
+#elif defined(JS_PUNBOX64)
+        add(value.valueReg());
+#else
+#error "Bad architecture"
+#endif
+    }
+    void add(TypedOrValueRegister reg) {
+        if (reg.hasValue())
+            add(reg.valueReg());
+        else if (reg.hasTyped())
+            add(reg.typedReg());
+    }
     void addUnchecked(Register reg) {
         gpr_.addUnchecked(reg);
     }
     void addUnchecked(FloatRegister reg) {
         fpu_.addUnchecked(reg);
     }
     void addUnchecked(const AnyRegister &any) {
         if (any.isFloat())
--- a/js/src/ion/shared/CodeGenerator-shared-inl.h
+++ b/js/src/ion/shared/CodeGenerator-shared-inl.h
@@ -180,13 +180,21 @@ CodeGeneratorShared::saveLive(LInstructi
 void
 CodeGeneratorShared::restoreLive(LInstruction *ins)
 {
     JS_ASSERT(!ins->isCall());
     LSafepoint *safepoint = ins->safepoint();
     masm.PopRegsInMask(safepoint->liveRegs());
 }
 
+void
+CodeGeneratorShared::restoreLiveIgnore(LInstruction *ins, RegisterSet ignore)
+{
+    JS_ASSERT(!ins->isCall());
+    LSafepoint *safepoint = ins->safepoint();
+    masm.PopRegsInMaskIgnore(safepoint->liveRegs(), ignore);
+}
+
 } // ion
 } // js
 
 #endif // jsion_codegen_inl_h__
 
--- a/js/src/ion/shared/CodeGenerator-shared.h
+++ b/js/src/ion/shared/CodeGenerator-shared.h
@@ -241,16 +241,17 @@ class CodeGeneratorShared : public LInst
     }
 
     // These functions have to be called before and after any callVM and before
     // any modifications of the stack.  Modification of the stack made after
     // these calls should update the framePushed variable, needed by the exit
     // frame produced by callVM.
     inline void saveLive(LInstruction *ins);
     inline void restoreLive(LInstruction *ins);
+    inline void restoreLiveIgnore(LInstruction *ins, RegisterSet reg);
 
     template <typename T>
     void pushArg(const T &t) {
         masm.Push(t);
 #ifdef DEBUG
         pushedArgs_++;
 #endif
     }
@@ -423,47 +424,60 @@ ArgList()
 }
 
 // Store wrappers, to generate the right move of data after the VM call.
 
 struct StoreNothing
 {
     inline void generate(CodeGeneratorShared *codegen) const {
     }
+    inline RegisterSet clobbered() const {
+        return RegisterSet(); // No register gets clobbered
+    }
 };
 
 class StoreRegisterTo
 {
   private:
     Register out_;
 
   public:
     StoreRegisterTo(const Register &out)
       : out_(out)
     { }
 
     inline void generate(CodeGeneratorShared *codegen) const {
         codegen->storeResultTo(out_);
     }
+    inline RegisterSet clobbered() const {
+        RegisterSet set = RegisterSet();
+        set.add(out_);
+        return set;
+    }
 };
 
 template <typename Output>
 class StoreValueTo_
 {
   private:
     Output out_;
 
   public:
     StoreValueTo_(const Output &out)
       : out_(out)
     { }
 
     inline void generate(CodeGeneratorShared *codegen) const {
         codegen->storeResultValueTo(out_);
     }
+    inline RegisterSet clobbered() const {
+        RegisterSet set = RegisterSet();
+        set.add(out_);
+        return set;
+    }
 };
 
 template <typename Output>
 StoreValueTo_<Output> StoreValueTo(const Output &out)
 {
     return StoreValueTo_<Output>(out);
 }
 
@@ -513,17 +527,17 @@ CodeGeneratorShared::visitOutOfLineCallV
     AssertCanGC();
     LInstruction *lir = ool->lir();
 
     saveLive(lir);
     ool->args().generate(this);
     if (!callVM(ool->function(), lir))
         return false;
     ool->out().generate(this);
-    restoreLive(lir);
+    restoreLiveIgnore(lir, ool->out().clobbered());
     masm.jump(ool->rejoin());
     return true;
 }
 
 } // namespace ion
 } // namespace js
 
 #endif // jsion_codegen_shared_h__