Bug 1319437 part 5 - Use CustomAutoRooter for CacheIRWriter. r=jonco
authorJan de Mooij <jdemooij@mozilla.com>
Sat, 26 Nov 2016 21:19:23 +0100
changeset 324359 873a10f77413394e7e4c2374ffb966e96b533ca6
parent 324358 90bd5f622e2954d96b6c1272caa2d8f214f93054
child 324360 2a0abcff5cfce087c12f3e4820b5e8b773cffaca
push id24
push usermaklebus@msu.edu
push dateTue, 20 Dec 2016 03:11:33 +0000
reviewersjonco
bugs1319437
milestone53.0a1
Bug 1319437 part 5 - Use CustomAutoRooter for CacheIRWriter. r=jonco
js/src/jit/CacheIR.cpp
js/src/jit/CacheIR.h
js/src/jit/SharedIC.cpp
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -17,17 +17,18 @@ using namespace js;
 using namespace js::jit;
 
 using mozilla::Maybe;
 
 GetPropIRGenerator::GetPropIRGenerator(JSContext* cx, jsbytecode* pc, ICStubEngine engine,
                                        bool* isTemporarilyUnoptimizable,
                                        HandleValue val, HandlePropertyName name,
                                        MutableHandleValue res)
-  : cx_(cx),
+  : writer(cx),
+    cx_(cx),
     pc_(pc),
     val_(val),
     name_(name),
     res_(res),
     engine_(engine),
     isTemporarilyUnoptimizable_(isTemporarilyUnoptimizable),
     emitted_(false),
     preliminaryObjectAction_(PreliminaryObjectAction::None)
@@ -41,50 +42,48 @@ EmitLoadSlotResult(CacheIRWriter& writer
         writer.loadFixedSlotResult(holderOp, NativeObject::getFixedSlotOffset(shape->slot()));
     } else {
         size_t dynamicSlotOffset = holder->dynamicSlotIndex(shape->slot()) * sizeof(Value);
         writer.loadDynamicSlotResult(holderOp, dynamicSlotOffset);
     }
 }
 
 bool
-GetPropIRGenerator::tryAttachStub(Maybe<CacheIRWriter>& writer)
+GetPropIRGenerator::tryAttachStub()
 {
     AutoAssertNoPendingException aanpe(cx_);
-    JS::AutoCheckCannotGC nogc;
 
     MOZ_ASSERT(!emitted_);
 
-    writer.emplace();
-    ValOperandId valId(writer->setInputOperandId(0));
+    ValOperandId valId(writer.setInputOperandId(0));
 
     if (val_.isObject()) {
         RootedObject obj(cx_, &val_.toObject());
-        ObjOperandId objId = writer->guardIsObject(valId);
+        ObjOperandId objId = writer.guardIsObject(valId);
 
-        if (!emitted_ && !tryAttachObjectLength(*writer, obj, objId))
+        if (!emitted_ && !tryAttachObjectLength(obj, objId))
             return false;
-        if (!emitted_ && !tryAttachNative(*writer, obj, objId))
+        if (!emitted_ && !tryAttachNative(obj, objId))
             return false;
-        if (!emitted_ && !tryAttachUnboxed(*writer, obj, objId))
+        if (!emitted_ && !tryAttachUnboxed(obj, objId))
             return false;
-        if (!emitted_ && !tryAttachUnboxedExpando(*writer, obj, objId))
+        if (!emitted_ && !tryAttachUnboxedExpando(obj, objId))
             return false;
-        if (!emitted_ && !tryAttachTypedObject(*writer, obj, objId))
+        if (!emitted_ && !tryAttachTypedObject(obj, objId))
             return false;
-        if (!emitted_ && !tryAttachModuleNamespace(*writer, obj, objId))
+        if (!emitted_ && !tryAttachModuleNamespace(obj, objId))
             return false;
-        if (!emitted_ && !tryAttachWindowProxy(*writer, obj, objId))
+        if (!emitted_ && !tryAttachWindowProxy(obj, objId))
             return false;
-        if (!emitted_ && !tryAttachProxy(*writer, obj, objId))
+        if (!emitted_ && !tryAttachProxy(obj, objId))
             return false;
         return true;
     }
 
-    if (!emitted_ && !tryAttachPrimitive(*writer, valId))
+    if (!emitted_ && !tryAttachPrimitive(valId))
         return false;
 
     return true;
 }
 
 static bool
 IsCacheableNoProperty(JSContext* cx, JSObject* obj, JSObject* holder, Shape* shape, jsid id,
                       jsbytecode* pc)
@@ -296,17 +295,17 @@ EmitCallGetterResult(CacheIRWriter& writ
         ObjOperandId holderId = writer.loadObject(holder);
         writer.guardShape(holderId, holder->as<NativeObject>().lastProperty());
     }
 
     EmitCallGetterResultNoGuards(writer, obj, holder, shape, objId);
 }
 
 bool
-GetPropIRGenerator::tryAttachNative(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId)
+GetPropIRGenerator::tryAttachNative(HandleObject obj, ObjOperandId objId)
 {
     MOZ_ASSERT(!emitted_);
 
     RootedShape shape(cx_);
     RootedNativeObject holder(cx_);
 
     RootedId id(cx_, NameToId(name_));
     NativeGetPropCacheability type = CanAttachNativeGetProp(cx_, obj, id, &holder, &shape, pc_,
@@ -337,18 +336,17 @@ GetPropIRGenerator::tryAttachNative(Cach
       default:
         MOZ_CRASH("Bad NativeGetPropCacheability");
     }
 
     return true;
 }
 
 bool
-GetPropIRGenerator::tryAttachWindowProxy(CacheIRWriter& writer, HandleObject obj,
-                                         ObjOperandId objId)
+GetPropIRGenerator::tryAttachWindowProxy(HandleObject obj, ObjOperandId objId)
 {
     // Attach a stub when the receiver is a WindowProxy and we are calling some
     // kinds of JSNative getters on the Window object (the global object).
 
     MOZ_ASSERT(!emitted_);
 
     if (!IsWindowProxy(obj))
         return true;
@@ -386,18 +384,17 @@ GetPropIRGenerator::tryAttachWindowProxy
     // on the Window object.
     writer.guardClass(objId, GuardClassKind::WindowProxy);
     ObjOperandId windowObjId = writer.loadObject(windowObj);
     EmitCallGetterResult(writer, windowObj, holder, shape, windowObjId);
     return true;
 }
 
 bool
-GetPropIRGenerator::tryAttachGenericProxy(CacheIRWriter& writer, HandleObject obj,
-                                          ObjOperandId objId)
+GetPropIRGenerator::tryAttachGenericProxy(HandleObject obj, ObjOperandId objId)
 {
     MOZ_ASSERT(!emitted_);
     MOZ_ASSERT(obj->is<ProxyObject>());
 
     emitted_ = true;
 
     writer.guardIsProxy(objId);
 
@@ -406,18 +403,17 @@ GetPropIRGenerator::tryAttachGenericProx
     writer.guardNotDOMProxy(objId);
 
     writer.callProxyGetResult(objId, NameToId(name_));
     writer.typeMonitorResult();
     return true;
 }
 
 bool
-GetPropIRGenerator::tryAttachDOMProxyShadowed(CacheIRWriter& writer, HandleObject obj,
-                                              ObjOperandId objId)
+GetPropIRGenerator::tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId)
 {
     MOZ_ASSERT(!emitted_);
     MOZ_ASSERT(IsCacheableDOMProxy(obj));
 
     emitted_ = true;
 
     writer.guardShape(objId, obj->maybeShape());
 
@@ -459,18 +455,17 @@ CheckDOMProxyExpandoDoesNotShadow(CacheI
         MOZ_ASSERT(!expandoObj.containsPure(id));
         writer.guardDOMExpandoObject(expandoId, expandoObj.lastProperty());
     } else {
         MOZ_CRASH("Invalid expando value");
     }
 }
 
 bool
-GetPropIRGenerator::tryAttachDOMProxyUnshadowed(CacheIRWriter& writer, HandleObject obj,
-                                                ObjOperandId objId)
+GetPropIRGenerator::tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId objId)
 {
     MOZ_ASSERT(!emitted_);
     MOZ_ASSERT(IsCacheableDOMProxy(obj));
 
     RootedObject checkObj(cx_, obj->staticPrototype());
     RootedNativeObject holder(cx_);
     RootedShape shape(cx_);
 
@@ -514,43 +509,43 @@ GetPropIRGenerator::tryAttachDOMProxyUns
         writer.callProxyGetResult(objId, id);
         writer.typeMonitorResult();
     }
 
     return true;
 }
 
 bool
-GetPropIRGenerator::tryAttachProxy(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId)
+GetPropIRGenerator::tryAttachProxy(HandleObject obj, ObjOperandId objId)
 {
     MOZ_ASSERT(!emitted_);
 
     if (!obj->is<ProxyObject>())
         return true;
 
     // Skim off DOM proxies.
     if (IsCacheableDOMProxy(obj)) {
         RootedId id(cx_, NameToId(name_));
         DOMProxyShadowsResult shadows = GetDOMProxyShadowsCheck()(cx_, obj, id);
         if (shadows == ShadowCheckFailed) {
             cx_->clearPendingException();
             return false;
         }
         if (DOMProxyIsShadowing(shadows))
-            return tryAttachDOMProxyShadowed(writer, obj, objId);
+            return tryAttachDOMProxyShadowed(obj, objId);
 
         MOZ_ASSERT(shadows == DoesntShadow || shadows == DoesntShadowUnique);
-        return tryAttachDOMProxyUnshadowed(writer, obj, objId);
+        return tryAttachDOMProxyUnshadowed(obj, objId);
     }
 
-    return tryAttachGenericProxy(writer, obj, objId);
+    return tryAttachGenericProxy(obj, objId);
 }
 
 bool
-GetPropIRGenerator::tryAttachUnboxed(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId)
+GetPropIRGenerator::tryAttachUnboxed(HandleObject obj, ObjOperandId objId)
 {
     MOZ_ASSERT(!emitted_);
 
     if (!obj->is<UnboxedPlainObject>())
         return true;
 
     const UnboxedLayout::Property* property = obj->as<UnboxedPlainObject>().layout().lookup(name_);
     if (!property)
@@ -568,17 +563,17 @@ GetPropIRGenerator::tryAttachUnboxed(Cac
         writer.returnFromIC();
 
     emitted_ = true;
     preliminaryObjectAction_ = PreliminaryObjectAction::Unlink;
     return true;
 }
 
 bool
-GetPropIRGenerator::tryAttachUnboxedExpando(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId)
+GetPropIRGenerator::tryAttachUnboxedExpando(HandleObject obj, ObjOperandId objId)
 {
     MOZ_ASSERT(!emitted_);
 
     if (!obj->is<UnboxedPlainObject>())
         return true;
 
     UnboxedExpandoObject* expando = obj->as<UnboxedPlainObject>().maybeExpando();
     if (!expando)
@@ -591,17 +586,17 @@ GetPropIRGenerator::tryAttachUnboxedExpa
     emitted_ = true;
 
     EmitReadSlotResult(writer, obj, obj, shape, objId);
     EmitReadSlotReturn(writer, obj, obj, shape);
     return true;
 }
 
 bool
-GetPropIRGenerator::tryAttachTypedObject(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId)
+GetPropIRGenerator::tryAttachTypedObject(HandleObject obj, ObjOperandId objId)
 {
     MOZ_ASSERT(!emitted_);
 
     if (!obj->is<TypedObject>() ||
         !cx_->runtime()->jitSupportsFloatingPoint ||
         cx_->compartment()->detachedTypedObjects)
     {
         return true;
@@ -645,17 +640,17 @@ GetPropIRGenerator::tryAttachTypedObject
     else
         writer.returnFromIC();
 
     emitted_ = true;
     return true;
 }
 
 bool
-GetPropIRGenerator::tryAttachObjectLength(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId)
+GetPropIRGenerator::tryAttachObjectLength(HandleObject obj, ObjOperandId objId)
 {
     MOZ_ASSERT(!emitted_);
 
     if (name_ != cx_->names().length)
         return true;
 
     if (obj->is<ArrayObject>()) {
         // Make sure int32 is added to the TypeSet before we attach a stub, so
@@ -690,18 +685,17 @@ GetPropIRGenerator::tryAttachObjectLengt
         emitted_ = true;
         return true;
     }
 
     return true;
 }
 
 bool
-GetPropIRGenerator::tryAttachModuleNamespace(CacheIRWriter& writer, HandleObject obj,
-                                             ObjOperandId objId)
+GetPropIRGenerator::tryAttachModuleNamespace(HandleObject obj, ObjOperandId objId)
 {
     MOZ_ASSERT(!emitted_);
 
     if (!obj->is<ModuleNamespaceObject>())
         return true;
 
     Rooted<ModuleNamespaceObject*> ns(cx_, &obj->as<ModuleNamespaceObject>());
     RootedModuleEnvironmentObject env(cx_);
@@ -723,17 +717,17 @@ GetPropIRGenerator::tryAttachModuleNames
 
     ObjOperandId envId = writer.loadObject(env);
     EmitLoadSlotResult(writer, envId, env, shape);
     writer.typeMonitorResult();
     return true;
 }
 
 bool
-GetPropIRGenerator::tryAttachPrimitive(CacheIRWriter& writer, ValOperandId valId)
+GetPropIRGenerator::tryAttachPrimitive(ValOperandId valId)
 {
     MOZ_ASSERT(!emitted_);
 
     JSValueType primitiveType;
     RootedNativeObject proto(cx_);
     if (val_.isString()) {
         if (name_ == cx_->names().length) {
             // String length is special-cased, see js::GetProperty.
--- a/js/src/jit/CacheIR.h
+++ b/js/src/jit/CacheIR.h
@@ -171,31 +171,31 @@ class StubField
     {
         MOZ_ASSERT_IF(sizeIsWord(), data <= UINTPTR_MAX);
     }
 
     Type type() const { return type_; }
 
     uintptr_t asWord() const { MOZ_ASSERT(sizeIsWord()); return dataWord_; }
     uint64_t asInt64() const { MOZ_ASSERT(sizeIsInt64()); return dataInt64_; }
-};
+} JS_HAZ_GC_POINTER;
 
 // We use this enum as GuardClass operand, instead of storing Class* pointers
 // in the IR, to keep the IR compact and the same size on all platforms.
 enum class GuardClassKind : uint8_t
 {
     Array,
     UnboxedArray,
     MappedArguments,
     UnmappedArguments,
     WindowProxy,
 };
 
 // Class to record CacheIR + some additional metadata for code generation.
-class MOZ_RAII CacheIRWriter
+class MOZ_RAII CacheIRWriter : public JS::CustomAutoRooter
 {
     CompactBufferWriter buffer_;
 
     uint32_t nextOperandId_;
     uint32_t nextInstructionId_;
     uint32_t numInputOperands_;
 
     // The data (shapes, slot offsets, etc.) that will be stored in the ICStub.
@@ -207,20 +207,16 @@ class MOZ_RAII CacheIRWriter
     Vector<uint32_t, 8, SystemAllocPolicy> operandLastUsed_;
 
     // OperandId and stub offsets are stored in a single byte, so make sure
     // this doesn't overflow. We use a very conservative limit for now.
     static const size_t MaxOperandIds = 20;
     static const size_t MaxStubDataSizeInBytes = 20 * sizeof(uintptr_t);
     bool tooLarge_;
 
-    // stubFields_ contains unrooted pointers, so ensure we cannot GC in
-    // our scope.
-    JS::AutoCheckCannotGC nogc;
-
     void writeOp(CacheOp op) {
         MOZ_ASSERT(uint32_t(op) <= UINT8_MAX);
         buffer_.writeByte(uint32_t(op));
         nextInstructionId_++;
     }
 
     void writeOperandId(OperandId opId) {
         if (opId.id() < MaxOperandIds) {
@@ -255,18 +251,19 @@ class MOZ_RAII CacheIRWriter
             tooLarge_ = true;
         }
     }
 
     CacheIRWriter(const CacheIRWriter&) = delete;
     CacheIRWriter& operator=(const CacheIRWriter&) = delete;
 
   public:
-    CacheIRWriter()
-      : nextOperandId_(0),
+    explicit CacheIRWriter(JSContext* cx)
+      : CustomAutoRooter(cx),
+        nextOperandId_(0),
         nextInstructionId_(0),
         numInputOperands_(0),
         stubDataSize_(0),
         tooLarge_(false)
     {}
 
     bool failed() const { return buffer_.oom() || tooLarge_; }
 
@@ -279,16 +276,21 @@ class MOZ_RAII CacheIRWriter
 
     uint32_t setInputOperandId(uint32_t op) {
         MOZ_ASSERT(op == nextOperandId_);
         nextOperandId_++;
         numInputOperands_++;
         return op;
     }
 
+    void trace(JSTracer* trc) override {
+        // For now, assert we only GC before we append stub fields.
+        MOZ_RELEASE_ASSERT(stubFields_.empty());
+    }
+
     size_t stubDataSize() const {
         return stubDataSize_;
     }
     void copyStubData(uint8_t* dest) const;
 
     bool operandIsDead(uint32_t operandId, uint32_t currentInstruction) const {
         if (operandId >= operandLastUsed_.length())
             return false;
@@ -504,69 +506,65 @@ class MOZ_RAII CacheIRReader
         buffer_.seek(pos, 0);
         return false;
     }
 };
 
 // GetPropIRGenerator generates CacheIR for a GetProp IC.
 class MOZ_RAII GetPropIRGenerator
 {
+    CacheIRWriter writer;
     JSContext* cx_;
     jsbytecode* pc_;
     HandleValue val_;
     HandlePropertyName name_;
     MutableHandleValue res_;
     ICStubEngine engine_;
     bool* isTemporarilyUnoptimizable_;
     bool emitted_;
 
     enum class PreliminaryObjectAction { None, Unlink, NotePreliminary };
     PreliminaryObjectAction preliminaryObjectAction_;
 
-    MOZ_MUST_USE bool tryAttachNative(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId);
-    MOZ_MUST_USE bool tryAttachUnboxed(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId);
-    MOZ_MUST_USE bool tryAttachUnboxedExpando(CacheIRWriter& writer, HandleObject obj,
-                                              ObjOperandId objId);
-    MOZ_MUST_USE bool tryAttachTypedObject(CacheIRWriter& writer, HandleObject obj,
-                                           ObjOperandId objId);
-    MOZ_MUST_USE bool tryAttachObjectLength(CacheIRWriter& writer, HandleObject obj,
-                                            ObjOperandId objId);
-    MOZ_MUST_USE bool tryAttachModuleNamespace(CacheIRWriter& writer, HandleObject obj,
-                                               ObjOperandId objId);
-    MOZ_MUST_USE bool tryAttachWindowProxy(CacheIRWriter& writer, HandleObject obj,
-                                           ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachNative(HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachUnboxed(HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachUnboxedExpando(HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachTypedObject(HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachObjectLength(HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachModuleNamespace(HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachWindowProxy(HandleObject obj, ObjOperandId objId);
 
-    MOZ_MUST_USE bool tryAttachGenericProxy(CacheIRWriter& writer, HandleObject obj,
-                                            ObjOperandId objId);
-    MOZ_MUST_USE bool tryAttachDOMProxyShadowed(CacheIRWriter& writer, HandleObject obj,
-                                                ObjOperandId objId);
-    MOZ_MUST_USE bool tryAttachDOMProxyUnshadowed(CacheIRWriter& writer, HandleObject obj,
-                                                  ObjOperandId objId);
-    MOZ_MUST_USE bool tryAttachProxy(CacheIRWriter& writer, HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachGenericProxy(HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachDOMProxyShadowed(HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachDOMProxyUnshadowed(HandleObject obj, ObjOperandId objId);
+    MOZ_MUST_USE bool tryAttachProxy(HandleObject obj, ObjOperandId objId);
 
-    MOZ_MUST_USE bool tryAttachPrimitive(CacheIRWriter& writer, ValOperandId valId);
+    MOZ_MUST_USE bool tryAttachPrimitive(ValOperandId valId);
 
     GetPropIRGenerator(const GetPropIRGenerator&) = delete;
     GetPropIRGenerator& operator=(const GetPropIRGenerator&) = delete;
 
   public:
     GetPropIRGenerator(JSContext* cx, jsbytecode* pc, ICStubEngine engine,
                        bool* isTemporarilyUnoptimizable,
                        HandleValue val, HandlePropertyName name, MutableHandleValue res);
 
     bool emitted() const { return emitted_; }
 
-    MOZ_MUST_USE bool tryAttachStub(mozilla::Maybe<CacheIRWriter>& writer);
+    MOZ_MUST_USE bool tryAttachStub();
 
     bool shouldUnlinkPreliminaryObjectStubs() const {
         return preliminaryObjectAction_ == PreliminaryObjectAction::Unlink;
     }
     bool shouldNotePreliminaryObjectStub() const {
         return preliminaryObjectAction_ == PreliminaryObjectAction::NotePreliminary;
     }
+    const CacheIRWriter& writerRef() const {
+        return writer;
+    }
 };
 
 enum class CacheKind : uint8_t
 {
     GetProp
 };
 
 } // namespace jit
--- a/js/src/jit/SharedIC.cpp
+++ b/js/src/jit/SharedIC.cpp
@@ -2466,22 +2466,21 @@ DoGetPropFallback(JSContext* cx, void* p
         ICStub* newStub = compiler.getStub(compiler.getStubSpace(info.outerScript(cx)));
         if (!newStub)
             return false;
         stub->addNewStub(newStub);
         attached = true;
     }
 
     if (!attached && !JitOptions.disableCacheIR) {
-        mozilla::Maybe<CacheIRWriter> writer;
         GetPropIRGenerator gen(cx, pc, engine, &isTemporarilyUnoptimizable, val, name, res);
-        if (!gen.tryAttachStub(writer))
+        if (!gen.tryAttachStub())
             return false;
         if (gen.emitted()) {
-            ICStub* newStub = AttachBaselineCacheIRStub(cx, writer.ref(), CacheKind::GetProp,
+            ICStub* newStub = AttachBaselineCacheIRStub(cx, gen.writerRef(), CacheKind::GetProp,
                                                         engine, info.outerScript(cx), stub);
             if (newStub) {
                 JitSpew(JitSpew_BaselineIC, "  Attached CacheIR stub");
                 attached = true;
                 if (gen.shouldNotePreliminaryObjectStub())
                     newStub->toCacheIR_Monitored()->notePreliminaryObject();
                 else if (gen.shouldUnlinkPreliminaryObjectStubs())
                     StripPreliminaryObjectStubs(cx, stub);