Bug 885607 - Store the correct IonCode in the store buffer; r=bhackett
authorTerrence Cole <terrence@mozilla.com>
Fri, 21 Jun 2013 19:25:17 -0700
changeset 136063 3df4624381b76cb5fc8254e0604f42d8702a2c33
parent 136062 b96decc34910e5cd995b921d32aaf53a2a9a0106
child 136064 0211a7e4bec6471fdaa6046b5db569cfa0567212
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersbhackett
bugs885607
milestone24.0a1
Bug 885607 - Store the correct IonCode in the store buffer; r=bhackett
js/src/ion/IonCaches.cpp
js/src/ion/IonLinker.h
js/src/ion/IonMacroAssembler.cpp
js/src/ion/IonMacroAssembler.h
js/src/ion/shared/Assembler-shared.h
--- a/js/src/ion/IonCaches.cpp
+++ b/js/src/ion/IonCaches.cpp
@@ -445,29 +445,29 @@ GeneratePrototypeGuards(JSContext *cx, I
 {
     JS_ASSERT(obj != holder);
 
     if (obj->hasUncacheableProto()) {
         // Note: objectReg and scratchReg may be the same register, so we cannot
         // use objectReg in the rest of this function.
         masm.loadPtr(Address(objectReg, JSObject::offsetOfType()), scratchReg);
         Address proto(scratchReg, offsetof(types::TypeObject, proto));
-        masm.branchPtr(Assembler::NotEqual, proto,
-                       ImmMaybeNurseryPtr(ion->method(), obj->getProto()), failures);
+        masm.branchNurseryPtr(Assembler::NotEqual, proto,
+                              ImmMaybeNurseryPtr(obj->getProto()), failures);
     }
 
     JSObject *pobj = IsCacheableDOMProxy(obj)
                      ? obj->getTaggedProto().toObjectOrNull()
                      : obj->getProto();
     if (!pobj)
         return;
     while (pobj != holder) {
         if (pobj->hasUncacheableProto()) {
             JS_ASSERT(!pobj->hasSingletonType());
-            masm.movePtr(ImmMaybeNurseryPtr(ion->method(), pobj), scratchReg);
+            masm.moveNurseryPtr(ImmMaybeNurseryPtr(pobj), scratchReg);
             Address objType(scratchReg, JSObject::offsetOfType());
             masm.branchPtr(Assembler::NotEqual, objType, ImmGCPtr(pobj->type()), failures);
         }
         pobj = pobj->getProto();
     }
 }
 
 static bool
@@ -763,17 +763,17 @@ GenerateReadSlot(JSContext *cx, IonScrip
     if (obj != holder) {
         // Note: this may clobber the object register if it's used as scratch.
         GeneratePrototypeGuards(cx, ion, masm, obj, holder, object, scratchReg,
                                 failures);
 
         if (holder) {
             // Guard on the holder's shape.
             holderReg = scratchReg;
-            masm.movePtr(ImmMaybeNurseryPtr(ion->method(), holder), holderReg);
+            masm.moveNurseryPtr(ImmMaybeNurseryPtr(holder), holderReg);
             masm.branchPtr(Assembler::NotEqual,
                            Address(holderReg, JSObject::offsetOfShape()),
                            ImmGCPtr(holder->lastProperty()),
                            &prototypeFailures);
         } else {
             // The property does not exist. Guard on everything in the
             // prototype chain.
             JSObject *proto = obj->getTaggedProto().toObjectOrNull();
@@ -847,17 +847,17 @@ GenerateCallGetter(JSContext *cx, IonScr
     Register scratchReg = output.valueReg().scratchReg();
 
     // Note: this may clobber the object register if it's used as scratch.
     if (obj != holder)
         GeneratePrototypeGuards(cx, ion, masm, obj, holder, object, scratchReg, &stubFailure);
 
     // Guard on the holder's shape.
     Register holderReg = scratchReg;
-    masm.movePtr(ImmMaybeNurseryPtr(ion->method(), holder), holderReg);
+    masm.moveNurseryPtr(ImmMaybeNurseryPtr(holder), holderReg);
     masm.branchPtr(Assembler::NotEqual,
                    Address(holderReg, JSObject::offsetOfShape()),
                    ImmGCPtr(holder->lastProperty()),
                    &stubFailure);
 
     // Now we're good to go to invoke the native call.
 
     // saveLive()
@@ -1794,17 +1794,17 @@ SetPropertyIC::attachSetterCall(JSContex
 
         Label protoFailure;
         Label protoSuccess;
 
         // Generate prototype/shape guards.
         if (obj != holder)
             GeneratePrototypeGuards(cx, ion, masm, obj, holder, object(), scratchReg, &protoFailure);
 
-        masm.movePtr(ImmMaybeNurseryPtr(ion->method(), holder), scratchReg);
+        masm.moveNurseryPtr(ImmMaybeNurseryPtr(holder), scratchReg);
         masm.branchPtr(Assembler::NotEqual,
                        Address(scratchReg, JSObject::offsetOfShape()),
                        ImmGCPtr(holder->lastProperty()),
                        &protoFailure);
 
         masm.jump(&protoSuccess);
 
         masm.bind(&protoFailure);
--- a/js/src/ion/IonLinker.h
+++ b/js/src/ion/IonLinker.h
@@ -53,16 +53,20 @@ class Linker
         IonCode *code = IonCode::New(cx, codeStart,
                                      bytesNeeded - headerSize, pool);
         if (!code)
             return NULL;
         if (masm.oom())
             return fail(cx);
         code->copyFrom(masm);
         masm.link(code);
+#ifdef JSGC_GENERATIONAL
+        if (masm.embedsNurseryPointers())
+            cx->runtime()->gcStoreBuffer.putWholeCell(code);
+#endif
         return code;
     }
 
   public:
     Linker(MacroAssembler &masm)
       : masm(masm)
     {
         masm.finish();
--- a/js/src/ion/IonMacroAssembler.cpp
+++ b/js/src/ion/IonMacroAssembler.cpp
@@ -13,16 +13,17 @@
 #include "ion/BaselineIC.h"
 #include "ion/BaselineJIT.h"
 #include "ion/BaselineRegisters.h"
 #include "ion/IonMacroAssembler.h"
 #include "ion/MIR.h"
 #include "js/RootingAPI.h"
 #include "vm/ForkJoin.h"
 
+#include "jsgcinlines.h"
 #include "jsinferinlines.h"
 
 using namespace js;
 using namespace js::ion;
 
 // Emulate a TypeSet logic from a Type object to avoid duplicating the guard
 // logic.
 class TypeWrapper {
@@ -215,16 +216,37 @@ MacroAssembler::PopRegsInMaskIgnore(Regi
             if (!ignore.has(*iter))
                 loadPtr(Address(StackPointer, diffG), *iter);
         }
         freeStack(reservedG);
     }
     JS_ASSERT(diffG == 0);
 }
 
+void
+MacroAssembler::branchNurseryPtr(Condition cond, const Address &ptr1, const ImmMaybeNurseryPtr &ptr2,
+                                 Label *label)
+{
+#ifdef JSGC_GENERATIONAL
+    if (ptr2.value && gc::IsInsideNursery(GetIonContext()->cx->runtime(), (void *)ptr2.value))
+        embedsNurseryPointers_ = true;
+#endif
+    branchPtr(cond, ptr1, ptr2, label);
+}
+
+void
+MacroAssembler::moveNurseryPtr(const ImmMaybeNurseryPtr &ptr, const Register &reg)
+{
+#ifdef JSGC_GENERATIONAL
+    if (ptr.value && gc::IsInsideNursery(GetIonContext()->cx->runtime(), (void *)ptr.value))
+        embedsNurseryPointers_ = true;
+#endif
+    movePtr(ptr, reg);
+}
+
 template<typename T>
 void
 MacroAssembler::loadFromTypedArray(int arrayType, const T &src, AnyRegister dest, Register temp,
                                    Label *fail)
 {
     switch (arrayType) {
       case TypedArray::TYPE_INT8:
         load8SignExtend(src, dest.gpr());
--- a/js/src/ion/IonMacroAssembler.h
+++ b/js/src/ion/IonMacroAssembler.h
@@ -54,31 +54,33 @@ class MacroAssembler : public MacroAssem
             return masm_;
         }
     };
 
     mozilla::Maybe<AutoRooter> autoRooter_;
     mozilla::Maybe<IonContext> ionContext_;
     mozilla::Maybe<AutoIonContextAlloc> alloc_;
     bool enoughMemory_;
+    bool embedsNurseryPointers_;
 
   private:
     // This field is used to manage profiling instrumentation output. If
     // provided and enabled, then instrumentation will be emitted around call
     // sites. The IonInstrumentation instance is hosted inside of
     // CodeGeneratorShared and is the manager of when instrumentation is
     // actually emitted or not. If NULL, then no instrumentation is emitted.
     IonInstrumentation *sps_;
 
   public:
     // If instrumentation should be emitted, then the sps parameter should be
     // provided, but otherwise it can be safely omitted to prevent all
     // instrumentation from being emitted.
     MacroAssembler()
       : enoughMemory_(true),
+        embedsNurseryPointers_(false),
         sps_(NULL)
     {
         JSContext *cx = GetIonContext()->cx;
         if (cx)
             constructRoot(cx);
 
         if (!GetIonContext()->temp) {
             JS_ASSERT(cx);
@@ -90,16 +92,17 @@ class MacroAssembler : public MacroAssem
         m_buffer.id = GetIonContext()->getNextAssemblerId();
 #endif
     }
 
     // This constructor should only be used when there is no IonContext active
     // (for example, Trampoline-$(ARCH).cpp and IonCaches.cpp).
     MacroAssembler(JSContext *cx)
       : enoughMemory_(true),
+        embedsNurseryPointers_(false),
         sps_(NULL)
     {
         constructRoot(cx);
         ionContext_.construct(cx, (js::ion::TempAllocator *)NULL);
         alloc_.construct(cx);
 #ifdef JS_CPU_ARM
         initWithAllocator();
         m_buffer.id = GetIonContext()->getNextAssemblerId();
@@ -129,16 +132,20 @@ class MacroAssembler : public MacroAssem
 
     void propagateOOM(bool success) {
         enoughMemory_ &= success;
     }
     bool oom() const {
         return !enoughMemory_ || MacroAssemblerSpecific::oom();
     }
 
+    bool embedsNurseryPointers() const {
+        return embedsNurseryPointers_;
+    }
+
     // Emits a test of a value against all types in a TypeSet. A scratch
     // register is required.
     template <typename Source, typename TypeSet>
     void guardTypeSet(const Source &address, const TypeSet *types, Register scratch,
                       Label *matched, Label *miss);
     template <typename Source>
     void guardType(const Source &address, types::Type type, Register scratch,
                    Label *matched, Label *miss);
@@ -498,16 +505,20 @@ class MacroAssembler : public MacroAssem
 
         callPreBarrier(address, type);
         jump(&done);
 
         align(8);
         bind(&done);
     }
 
+    void branchNurseryPtr(Condition cond, const Address &ptr1, const ImmMaybeNurseryPtr &ptr2,
+                          Label *label);
+    void moveNurseryPtr(const ImmMaybeNurseryPtr &ptr, const Register &reg);
+
     void canonicalizeDouble(FloatRegister reg) {
         Label notNaN;
         branchDouble(DoubleOrdered, reg, reg, &notNaN);
         loadStaticDouble(&js_NaN, reg);
         bind(&notNaN);
     }
 
     template<typename T>
--- a/js/src/ion/shared/Assembler-shared.h
+++ b/js/src/ion/shared/Assembler-shared.h
@@ -126,24 +126,20 @@ struct ImmGCPtr
 
   protected:
     ImmGCPtr() : value(0) {}
 };
 
 // Used for immediates which require relocation and may be traced during minor GC.
 struct ImmMaybeNurseryPtr : public ImmGCPtr
 {
-    explicit ImmMaybeNurseryPtr(IonCode *code, gc::Cell *ptr)
+    explicit ImmMaybeNurseryPtr(gc::Cell *ptr)
     {
         this->value = reinterpret_cast<uintptr_t>(ptr);
         JS_ASSERT(!IsPoisonedPtr(ptr));
-#ifdef JSGC_GENERATIONAL
-        if (ptr && ptr->runtime()->gcNursery.isInside(ptr))
-            ptr->runtime()->gcStoreBuffer.putWholeCell(code);
-#endif
     }
 };
 
 // Specifies a hardcoded, absolute address.
 struct AbsoluteAddress {
     void *addr;
 
     explicit AbsoluteAddress(void *addr)