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 147554 3df4624381b76cb5fc8254e0604f42d8702a2c33
parent 147553 b96decc34910e5cd995b921d32aaf53a2a9a0106
child 147555 0211a7e4bec6471fdaa6046b5db569cfa0567212
push id2697
push userbbajaj@mozilla.com
push dateMon, 05 Aug 2013 18:49:53 +0000
treeherdermozilla-beta@dfec938c7b63 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs885607
milestone24.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 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)