Add incremental barriers to addprop ICs (bug 811058, r=billm, a=lsblakk).
authorDavid Anderson <danderson@mozilla.com>
Fri, 07 Dec 2012 16:11:58 -0800
changeset 117429 7141360c43bbf4081e4ef91dd5b8f431cfbb9866
parent 117428 74ae3b96de9749865c845c275d8612b331ace11a
child 117430 b675946f1fd307a3331fec8b364f6e5539fcb7eb
push id1878
push userdanderson@mozilla.com
push dateSat, 08 Dec 2012 00:40:55 +0000
treeherdermozilla-beta@7141360c43bb [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm, lsblakk
bugs811058
milestone18.0
Add incremental barriers to addprop ICs (bug 811058, r=billm, a=lsblakk).
js/src/ion/Ion.cpp
js/src/ion/Ion.h
js/src/ion/IonCaches.cpp
js/src/ion/IonCompartment.h
js/src/ion/IonMacroAssembler.h
js/src/ion/IonTypes.h
js/src/ion/TypeOracle.h
js/src/ion/arm/Trampoline-arm.cpp
js/src/ion/x64/Trampoline-x64.cpp
js/src/ion/x86/Trampoline-x86.cpp
--- a/js/src/ion/Ion.cpp
+++ b/js/src/ion/Ion.cpp
@@ -209,18 +209,20 @@ IonCompartment::sweep(FreeOp *fop)
     if (enterJIT_ && !IsIonCodeMarked(enterJIT_.unsafeGet()))
         enterJIT_ = NULL;
     if (bailoutHandler_ && !IsIonCodeMarked(bailoutHandler_.unsafeGet()))
         bailoutHandler_ = NULL;
     if (argumentsRectifier_ && !IsIonCodeMarked(argumentsRectifier_.unsafeGet()))
         argumentsRectifier_ = NULL;
     if (invalidator_ && !IsIonCodeMarked(invalidator_.unsafeGet()))
         invalidator_ = NULL;
-    if (preBarrier_ && !IsIonCodeMarked(preBarrier_.unsafeGet()))
-        preBarrier_ = NULL;
+    if (valuePreBarrier_ && !IsIonCodeMarked(valuePreBarrier_.unsafeGet()))
+        valuePreBarrier_ = NULL;
+    if (shapePreBarrier_ && !IsIonCodeMarked(shapePreBarrier_.unsafeGet()))
+        shapePreBarrier_ = NULL;
 
     for (size_t i = 0; i < bailoutTables_.length(); i++) {
         if (bailoutTables_[i] && !IsIonCodeMarked(bailoutTables_[i].unsafeGet()))
             bailoutTables_[i] = NULL;
     }
 
     // Sweep cache of VM function implementations.
     functionWrappers_->sweep(fop);
@@ -1756,22 +1758,28 @@ ion::FinishInvalidation(FreeOp *fop, JSS
         ion::IonScript::Destroy(fop, script->ion);
     }
 
     /* In all cases, NULL out script->ion to avoid re-entry. */
     script->ion = NULL;
 }
 
 void
-ion::MarkFromIon(JSCompartment *comp, Value *vp)
+ion::MarkValueFromIon(JSCompartment *comp, Value *vp)
 {
     gc::MarkValueUnbarriered(comp->barrierTracer(), vp, "write barrier");
 }
 
 void
+ion::MarkShapeFromIon(JSCompartment *comp, Shape **shapep)
+{
+    gc::MarkShapeUnbarriered(comp->barrierTracer(), shapep, "write barrier");
+}
+
+void
 ion::ForbidCompilation(JSContext *cx, JSScript *script)
 {
     IonSpew(IonSpew_Abort, "Disabling Ion compilation of script %s:%d",
             script->filename, script->lineno);
 
     if (script->hasIonScript()) {
         // It is only safe to modify script->ion if the script is not currently
         // running, because IonFrameIterator needs to tell what ionScript to
--- a/js/src/ion/Ion.h
+++ b/js/src/ion/Ion.h
@@ -259,17 +259,18 @@ IonExecStatus SideCannon(JSContext *cx, 
 IonExecStatus FastInvoke(JSContext *cx, HandleFunction fun, CallArgsList &args);
 
 // Walk the stack and invalidate active Ion frames for the invalid scripts.
 void Invalidate(types::TypeCompartment &types, FreeOp *fop,
                 const Vector<types::RecompileInfo> &invalid, bool resetUses = true);
 void Invalidate(JSContext *cx, const Vector<types::RecompileInfo> &invalid, bool resetUses = true);
 bool Invalidate(JSContext *cx, JSScript *script, bool resetUses = true);
 
-void MarkFromIon(JSCompartment *comp, Value *vp);
+void MarkValueFromIon(JSCompartment *comp, Value *vp);
+void MarkShapeFromIon(JSCompartment *comp, Shape **shapep);
 
 void ToggleBarriers(JSCompartment *comp, bool needs);
 
 class IonBuilder;
 
 bool CompileBackEnd(IonBuilder *builder);
 void AttachFinishedCompilations(JSContext *cx);
 void FinishOffThreadBuilder(IonBuilder *builder);
--- a/js/src/ion/IonCaches.cpp
+++ b/js/src/ion/IonCaches.cpp
@@ -1173,17 +1173,20 @@ IonCacheSetProperty::attachNativeAdding(
         masm.branchTestObjShape(Assembler::NotEqual, protoReg, protoShape, &protoFailures);
 
         proto = proto->getProto();
     }
 
     masm.pop(object());     // restore object reg
 
     /* Changing object shape.  Write the object's new shape. */
-    masm.storePtr(ImmGCPtr(newShape), Address(object(), JSObject::offsetOfShape()));
+    Address shapeAddr(object(), JSObject::offsetOfShape());
+    if (cx->compartment->needsBarrier())
+        masm.callPreBarrier(shapeAddr, MIRType_Shape);
+    masm.storePtr(ImmGCPtr(newShape), shapeAddr);
 
     /* Set the value on the object. */
     if (obj->isFixedSlot(propShape->slot())) {
         Address addr(object(), JSObject::getFixedSlotOffset(propShape->slot()));
         masm.storeConstantOrRegister(value(), addr);
     } else {
         Register slotsReg = object();
 
--- a/js/src/ion/IonCompartment.h
+++ b/js/src/ion/IonCompartment.h
@@ -48,17 +48,18 @@ class IonCompartment
     // Argument-rectifying thunk, in the case of insufficient arguments passed
     // to a function call site. Pads with |undefined|.
     ReadBarriered<IonCode> argumentsRectifier_;
 
     // Thunk that invalides an (Ion compiled) caller on the Ion stack.
     ReadBarriered<IonCode> invalidator_;
 
     // Thunk that calls the GC pre barrier.
-    ReadBarriered<IonCode> preBarrier_;
+    ReadBarriered<IonCode> valuePreBarrier_;
+    ReadBarriered<IonCode> shapePreBarrier_;
 
     // Map VMFunction addresses to the IonCode of the wrapper.
     VMWrapperMap *functionWrappers_;
 
     // Any scripts for which off thread compilation has successfully finished,
     // failed, or been cancelled. All off thread compilations which are started
     // will eventually appear in this list asynchronously. Protected by the
     // runtime's analysis lock.
@@ -69,17 +70,17 @@ class IonCompartment
 
   private:
     IonCode *generateEnterJIT(JSContext *cx);
     IonCode *generateReturnError(JSContext *cx);
     IonCode *generateArgumentsRectifier(JSContext *cx);
     IonCode *generateBailoutTable(JSContext *cx, uint32 frameClass);
     IonCode *generateBailoutHandler(JSContext *cx);
     IonCode *generateInvalidator(JSContext *cx);
-    IonCode *generatePreBarrier(JSContext *cx);
+    IonCode *generatePreBarrier(JSContext *cx, MIRType type);
 
   public:
     IonCode *generateVMWrapper(JSContext *cx, const VMFunction &f);
 
     OffThreadCompilationVector &finishedOffThreadCompilations() {
         return finishedOffThreadCompilations_;
     }
 
@@ -142,23 +143,31 @@ class IonCompartment
         if (!enterJIT_) {
             enterJIT_ = generateEnterJIT(cx);
             if (!enterJIT_)
                 return NULL;
         }
         return enterJIT_.get()->as<EnterIonCode>();
     }
 
-    IonCode *preBarrier(JSContext *cx) {
-        if (!preBarrier_) {
-            preBarrier_ = generatePreBarrier(cx);
-            if (!preBarrier_)
+    IonCode *valuePreBarrier(JSContext *cx) {
+        if (!valuePreBarrier_) {
+            valuePreBarrier_ = generatePreBarrier(cx, MIRType_Value);
+            if (!valuePreBarrier_)
                 return NULL;
         }
-        return preBarrier_;
+        return valuePreBarrier_;
+    }
+    IonCode *shapePreBarrier(JSContext *cx) {
+        if (!shapePreBarrier_) {
+            shapePreBarrier_ = generatePreBarrier(cx, MIRType_Shape);
+            if (!shapePreBarrier_)
+                return NULL;
+        }
+        return shapePreBarrier_;
     }
     AutoFlushCache *flusher() {
         return flusher_;
     }
     void setFlusher(AutoFlushCache *fl) {
         if (!flusher_ || !fl)
             flusher_ = fl;
     }
--- a/js/src/ion/IonMacroAssembler.h
+++ b/js/src/ion/IonMacroAssembler.h
@@ -363,21 +363,26 @@ class MacroAssembler : public MacroAssem
         JSCompartment *comp = GetIonContext()->cx->compartment;
         movePtr(ImmWord(comp), scratch);
         Address needsBarrierAddr(scratch, JSCompartment::OffsetOfNeedsBarrier());
         branchTest32(cond, needsBarrierAddr, Imm32(0x1), label);
     }
 
     template <typename T>
     void callPreBarrier(const T &address, MIRType type) {
-        JS_ASSERT(type == MIRType_Value || type == MIRType_String || type == MIRType_Object);
+        JS_ASSERT(type == MIRType_Value ||
+                  type == MIRType_String ||
+                  type == MIRType_Object ||
+                  type == MIRType_Shape);
         Label done;
 
         JSContext *cx = GetIonContext()->cx;
-        IonCode *preBarrier = cx->compartment->ionCompartment()->preBarrier(cx);
+        IonCode *preBarrier = (type == MIRType_Shape)
+                              ? cx->compartment->ionCompartment()->shapePreBarrier(cx)
+                              : cx->compartment->ionCompartment()->valuePreBarrier(cx);
         if (!preBarrier) {
             enoughMemory_ = false;
             return;
         }
 
         if (type == MIRType_Value)
             branchTestGCThing(Assembler::NotEqual, address, &done);
 
--- a/js/src/ion/IonTypes.h
+++ b/js/src/ion/IonTypes.h
@@ -54,16 +54,37 @@ enum BailoutKind
 
     // Like Bailout_Normal, but invalidate the current IonScript.
     Bailout_Invalidate,
 
     // A shape guard based on JM ICs failed.
     Bailout_CachedShapeGuard
 };
 
+// The ordering of this enumeration is important: Anything < Value is a
+// specialized type. Furthermore, anything < String has trivial conversion to
+// a number.
+enum MIRType
+{
+    MIRType_Undefined,
+    MIRType_Null,
+    MIRType_Boolean,
+    MIRType_Int32,
+    MIRType_Double,
+    MIRType_String,
+    MIRType_Object,
+    MIRType_Magic,
+    MIRType_Value,
+    MIRType_None,       // Invalid, used as a placeholder.
+    MIRType_Slots,      // A slots vector
+    MIRType_Elements,   // An elements vector
+    MIRType_StackFrame, // StackFrame pointer for OSR.
+    MIRType_Shape       // A Shape pointer.
+};
+
 #ifdef DEBUG
 // Track the pipeline of opcodes which has produced a snapshot.
 #define TRACK_SNAPSHOTS 1
 #endif
 
 } // namespace ion
 } // namespace js
 
--- a/js/src/ion/TypeOracle.h
+++ b/js/src/ion/TypeOracle.h
@@ -8,37 +8,16 @@
 #ifndef js_ion_type_oracle_h__
 #define js_ion_type_oracle_h__
 
 #include "jsscript.h"
 #include "IonTypes.h"
 
 namespace js {
 namespace ion {
-
-// The ordering of this enumeration is important: Anything < Value is a
-// specialized type. Furthermore, anything < String has trivial conversion to
-// a number.
-enum MIRType
-{
-    MIRType_Undefined,
-    MIRType_Null,
-    MIRType_Boolean,
-    MIRType_Int32,
-    MIRType_Double,
-    MIRType_String,
-    MIRType_Object,
-    MIRType_Magic,
-    MIRType_Value,
-    MIRType_None,       // Invalid, used as a placeholder.
-    MIRType_Slots,      // A slots vector
-    MIRType_Elements,   // An elements vector
-    MIRType_StackFrame  // StackFrame pointer for OSR.
-};
-
 enum LazyArgumentsType {
     MaybeArguments = 0,
     DefinitelyArguments,
     NotArguments
 };
 
 class TypeOracle
 {
--- a/js/src/ion/arm/Trampoline-arm.cpp
+++ b/js/src/ion/arm/Trampoline-arm.cpp
@@ -619,31 +619,35 @@ IonCompartment::generateVMWrapper(JSCont
     // use relookupOrAdd instead of add.
     if (!functionWrappers_->relookupOrAdd(p, &f, wrapper))
         return NULL;
 
     return wrapper;
 }
 
 IonCode *
-IonCompartment::generatePreBarrier(JSContext *cx)
+IonCompartment::generatePreBarrier(JSContext *cx, MIRType type)
 {
     MacroAssembler masm;
 
     RegisterSet save = RegisterSet(GeneralRegisterSet(Registers::VolatileMask),
                                    FloatRegisterSet(FloatRegisters::VolatileMask));
     masm.PushRegsInMask(save);
 
     JS_ASSERT(PreBarrierReg == r1);
     masm.movePtr(ImmWord(cx->compartment), r0);
 
     masm.setupUnalignedABICall(2, r2);
     masm.passABIArg(r0);
     masm.passABIArg(r1);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, MarkFromIon));
-
+    if (type == MIRType_Value) {
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, MarkValueFromIon));
+    } else {
+        JS_ASSERT(type == MIRType_Shape);
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, MarkShapeFromIon));
+    }
     masm.PopRegsInMask(save);
     masm.ret();
 
     Linker linker(masm);
     return linker.newCode(cx);
 }
 
--- a/js/src/ion/x64/Trampoline-x64.cpp
+++ b/js/src/ion/x64/Trampoline-x64.cpp
@@ -526,31 +526,35 @@ IonCompartment::generateVMWrapper(JSCont
     // use relookupOrAdd instead of add.
     if (!functionWrappers_->relookupOrAdd(p, &f, wrapper))
         return NULL;
 
     return wrapper;
 }
 
 IonCode *
-IonCompartment::generatePreBarrier(JSContext *cx)
+IonCompartment::generatePreBarrier(JSContext *cx, MIRType type)
 {
     MacroAssembler masm;
 
     RegisterSet regs = RegisterSet(GeneralRegisterSet(Registers::VolatileMask),
                                    FloatRegisterSet(FloatRegisters::VolatileMask));
     masm.PushRegsInMask(regs);
 
     JS_ASSERT(PreBarrierReg == rdx);
     masm.movq(ImmWord(cx->compartment), rcx);
 
     masm.setupUnalignedABICall(2, rax);
     masm.passABIArg(rcx);
     masm.passABIArg(rdx);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, MarkFromIon));
-
+    if (type == MIRType_Value) {
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, MarkValueFromIon));
+    } else {
+        JS_ASSERT(type == MIRType_Shape);
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, MarkShapeFromIon));
+    }
     masm.PopRegsInMask(regs);
     masm.ret();
 
     Linker linker(masm);
     return linker.newCode(cx);
 }
 
--- a/js/src/ion/x86/Trampoline-x86.cpp
+++ b/js/src/ion/x86/Trampoline-x86.cpp
@@ -538,31 +538,35 @@ IonCompartment::generateVMWrapper(JSCont
     // use relookupOrAdd instead of add.
     if (!functionWrappers_->relookupOrAdd(p, &f, wrapper))
         return NULL;
 
     return wrapper;
 }
 
 IonCode *
-IonCompartment::generatePreBarrier(JSContext *cx)
+IonCompartment::generatePreBarrier(JSContext *cx, MIRType type)
 {
     MacroAssembler masm;
 
     RegisterSet save = RegisterSet(GeneralRegisterSet(Registers::VolatileMask),
                                    FloatRegisterSet(FloatRegisters::VolatileMask));
     masm.PushRegsInMask(save);
 
     JS_ASSERT(PreBarrierReg == edx);
     masm.movl(ImmWord(cx->compartment), ecx);
 
     masm.setupUnalignedABICall(2, eax);
     masm.passABIArg(ecx);
     masm.passABIArg(edx);
-    masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, MarkFromIon));
-
+    if (type == MIRType_Value) {
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, MarkValueFromIon));
+    } else {
+        JS_ASSERT(type == MIRType_Shape);
+        masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, MarkShapeFromIon));
+    }
     masm.PopRegsInMask(save);
     masm.ret();
 
     Linker linker(masm);
     return linker.newCode(cx);
 }