Add incremental barriers to addprop ICs (bug 811058, r=billm, a=lsblakk).
☠☠ backed out by 74ae3b96de97 ☠ ☠
authorDavid Anderson <danderson@mozilla.com>
Fri, 07 Dec 2012 16:11:58 -0800
changeset 117426 70d6b6426802ab16fd5262599417b25e42303b06
parent 117425 46a3bb37188b730040286551fa140c86660d4ce0
child 117427 4c7d9835228080926c6dea931da5f5871e425088
push id1876
push userdanderson@mozilla.com
push dateSat, 08 Dec 2012 00:17:01 +0000
treeherdermozilla-beta@70d6b6426802 [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/IonCaches.cpp
js/src/ion/IonCompartment.h
js/src/ion/IonMacroAssembler.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/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/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);
 }