Bug 1320408 - Part 9: Change JSObject::setFlags and depending methods to static method. r=jandem
authorTooru Fujisawa <arai_a@mac.com>
Sat, 21 Jan 2017 17:25:44 +0900
changeset 330541 43ac5e5b71937a4cbad6dcc525be975a37f84a95
parent 330540 513d1e41b5940e9b2d6978ff25d6dab0f5579e53
child 330542 81f6417e94c4bfc6812225a22d8599a09c5cd8ce
push id36330
push userphilringnalda@gmail.com
push dateSat, 21 Jan 2017 23:26:41 +0000
treeherderautoland@5f0652e323af [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjandem
bugs1320408
milestone53.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 1320408 - Part 9: Change JSObject::setFlags and depending methods to static method. r=jandem
js/src/jsapi.cpp
js/src/jsarray.cpp
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jswatchpoint.cpp
js/src/proxy/CrossCompartmentWrapper.cpp
js/src/vm/EnvironmentObject.cpp
js/src/vm/GeneratorObject.cpp
js/src/vm/GlobalObject.cpp
js/src/vm/Interpreter.cpp
js/src/vm/ObjectGroup.cpp
js/src/vm/Shape.cpp
js/src/vm/TypeInference.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3480,17 +3480,17 @@ CreateNonSyntacticEnvironmentChain(JSCon
 
         // The XPConnect subscript loader, which may pass in its own
         // environments to load scripts in, expects the environment chain to
         // be the holder of "var" declarations. In SpiderMonkey, such objects
         // are called "qualified varobjs", the "qualified" part meaning the
         // declaration was qualified by "var". There is only sadness.
         //
         // See JSObject::isQualifiedVarObj.
-        if (!env->setQualifiedVarObj(cx))
+        if (!JSObject::setQualifiedVarObj(cx, env))
             return false;
 
         // Also get a non-syntactic lexical environment to capture 'let' and
         // 'const' bindings. To persist lexical bindings, we have a 1-1
         // mapping with the final unwrapped environment object (the
         // environment that stores the 'var' bindings) and the lexical
         // environment.
         //
--- a/js/src/jsarray.cpp
+++ b/js/src/jsarray.cpp
@@ -3276,17 +3276,17 @@ CreateArrayPrototype(JSContext* cx, JSPr
         return nullptr;
 
     AutoSetNewObjectMetadata metadata(cx);
     RootedArrayObject arrayProto(cx, ArrayObject::createArray(cx, gc::AllocKind::OBJECT4,
                                                               gc::TenuredHeap, shape, group, 0,
                                                               metadata));
     if (!arrayProto ||
         !JSObject::setSingleton(cx, arrayProto) ||
-        !arrayProto->setDelegate(cx) ||
+        !JSObject::setDelegate(cx, arrayProto) ||
         !AddLengthProperty(cx, arrayProto))
     {
         return nullptr;
     }
 
     /*
      * The default 'new' group of Array.prototype is required by type inference
      * to have unknown properties, to simplify handling of e.g. heterogenous
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -666,17 +666,17 @@ RegisterEnumerator(JSContext* cx, Proper
 }
 
 static inline bool
 VectorToKeyIterator(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVector& keys,
                     uint32_t numGuards, uint32_t key, MutableHandleObject objp)
 {
     MOZ_ASSERT(!(flags & JSITER_FOREACH));
 
-    if (obj->isSingleton() && !obj->setIteratedSingleton(cx))
+    if (obj->isSingleton() && !JSObject::setIteratedSingleton(cx, obj))
         return false;
     MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_ITERATED);
 
     Rooted<PropertyIteratorObject*> iterobj(cx, NewPropertyIteratorObject(cx, flags));
     if (!iterobj)
         return false;
 
     NativeIterator* ni = NativeIterator::allocateIterator(cx, numGuards, keys.length());
@@ -710,17 +710,17 @@ VectorToKeyIterator(JSContext* cx, Handl
 }
 
 static bool
 VectorToValueIterator(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVector& keys,
                       MutableHandleObject objp)
 {
     MOZ_ASSERT(flags & JSITER_FOREACH);
 
-    if (obj->isSingleton() && !obj->setIteratedSingleton(cx))
+    if (obj->isSingleton() && !JSObject::setIteratedSingleton(cx, obj))
         return false;
     MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_ITERATED);
 
     Rooted<PropertyIteratorObject*> iterobj(cx, NewPropertyIteratorObject(cx, flags));
     if (!iterobj)
         return false;
 
     NativeIterator* ni = NativeIterator::allocateIterator(cx, 0, keys.length());
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1855,30 +1855,33 @@ js::SetClassAndProto(JSContext* cx, Hand
     while (oldproto && oldproto->isNative()) {
         if (oldproto->isSingleton()) {
             // We always generate a new shape if the object is a singleton,
             // regardless of the uncacheable-proto flag. ICs may rely on
             // this.
             if (!oldproto->as<NativeObject>().generateOwnShape(cx))
                 return false;
         } else {
-            if (!oldproto->setUncacheableProto(cx))
+            if (!JSObject::setUncacheableProto(cx, oldproto))
                 return false;
         }
         if (!obj->isDelegate()) {
             // If |obj| is not a proto of another object, we don't need to
             // reshape the whole proto chain.
             MOZ_ASSERT(obj == oldproto);
             break;
         }
         oldproto = oldproto->staticPrototype();
     }
 
-    if (proto.isObject() && !proto.toObject()->setDelegate(cx))
-        return false;
+    if (proto.isObject()) {
+        RootedObject protoObj(cx, proto.toObject());
+        if (!JSObject::setDelegate(cx, protoObj))
+            return false;
+    }
 
     if (obj->isSingleton()) {
         /*
          * Just splice the prototype, but mark the properties as unknown for
          * consistent behavior.
          */
         if (!JSObject::splicePrototype(cx, obj, clasp, proto))
             return false;
@@ -2644,17 +2647,17 @@ js::PreventExtensions(JSContext* cx, Han
             MarkObjectGroupFlags(cx, obj, OBJECT_FLAG_FROZEN);
             if (!ObjectElements::FreezeElements(cx, obj.as<NativeObject>()))
                 return false;
         } else if (!NativeObject::sparsifyDenseElements(cx, obj.as<NativeObject>())) {
             return false;
         }
     }
 
-    if (!obj->setFlags(cx, BaseShape::NOT_EXTENSIBLE, JSObject::GENERATE_SHAPE)) {
+    if (!JSObject::setFlags(cx, obj, BaseShape::NOT_EXTENSIBLE, JSObject::GENERATE_SHAPE)) {
         // We failed to mark the object non-extensible, so reset the frozen
         // flag on the elements.
         MOZ_ASSERT(obj->nonProxyIsExtensible());
         if (obj->isNative() && obj->as<NativeObject>().getElementsHeader()->isFrozen())
             obj->as<NativeObject>().getElementsHeader()->markNotFrozen();
         return false;
     }
 
@@ -2784,17 +2787,17 @@ bool
 js::SetImmutablePrototype(ExclusiveContext* cx, HandleObject obj, bool* succeeded)
 {
     if (obj->hasDynamicPrototype()) {
         if (!cx->shouldBeJSContext())
             return false;
         return Proxy::setImmutablePrototype(cx->asJSContext(), obj, succeeded);
     }
 
-    if (!obj->setFlags(cx, BaseShape::IMMUTABLE_PROTOTYPE))
+    if (!JSObject::setFlags(cx, obj, BaseShape::IMMUTABLE_PROTOTYPE))
         return false;
     *succeeded = true;
     return true;
 }
 
 bool
 js::GetPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id,
                           MutableHandle<PropertyDescriptor> desc)
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -193,40 +193,40 @@ class JSObject : public js::gc::Cell
     inline void setInitialSlotsMaybeNonNative(js::HeapSlot* slots);
     inline void setInitialElementsMaybeNonNative(js::HeapSlot* elements);
 
     enum GenerateShape {
         GENERATE_NONE,
         GENERATE_SHAPE
     };
 
-    bool setFlags(js::ExclusiveContext* cx, js::BaseShape::Flag flags,
-                  GenerateShape generateShape = GENERATE_NONE);
+    static bool setFlags(js::ExclusiveContext* cx, JS::HandleObject obj, js::BaseShape::Flag flags,
+                         GenerateShape generateShape = GENERATE_NONE);
     inline bool hasAllFlags(js::BaseShape::Flag flags) const;
 
     /*
      * An object is a delegate if it is on another object's prototype or scope
      * chain, and therefore the delegate might be asked implicitly to get or
      * set a property on behalf of another object. Delegates may be accessed
      * directly too, as may any object, but only those objects linked after the
      * head of any prototype or scope chain are flagged as delegates. This
      * definition helps to optimize shape-based property cache invalidation
      * (see Purge{Scope,Proto}Chain in jsobj.cpp).
      */
     inline bool isDelegate() const;
-    bool setDelegate(js::ExclusiveContext* cx) {
-        return setFlags(cx, js::BaseShape::DELEGATE, GENERATE_SHAPE);
+    static bool setDelegate(js::ExclusiveContext* cx, JS::HandleObject obj) {
+        return setFlags(cx, obj, js::BaseShape::DELEGATE, GENERATE_SHAPE);
     }
 
     inline bool isBoundFunction() const;
     inline bool hasSpecialEquality() const;
 
     inline bool watched() const;
-    bool setWatched(js::ExclusiveContext* cx) {
-        return setFlags(cx, js::BaseShape::WATCHED, GENERATE_SHAPE);
+    static bool setWatched(js::ExclusiveContext* cx, JS::HandleObject obj) {
+        return setFlags(cx, obj, js::BaseShape::WATCHED, GENERATE_SHAPE);
     }
 
     // A "qualified" varobj is the object on which "qualified" variable
     // declarations (i.e., those defined with "var") are kept.
     //
     // Conceptually, when a var binding is defined, it is defined on the
     // innermost qualified varobj on the scope chain.
     //
@@ -240,45 +240,45 @@ class JSObject : public js::gc::Cell
     // Global scopes are also qualified varobjs. It is possible to statically
     // know, for a given script, that are no more inner qualified varobjs, so
     // free variable references can be statically bound to the global.
     //
     // Finally, there are non-syntactic qualified varobjs used by embedders
     // (e.g., Gecko and XPConnect), as they often wish to run scripts under a
     // scope that captures var bindings.
     inline bool isQualifiedVarObj() const;
-    bool setQualifiedVarObj(js::ExclusiveContext* cx) {
-        return setFlags(cx, js::BaseShape::QUALIFIED_VAROBJ);
+    static bool setQualifiedVarObj(js::ExclusiveContext* cx, JS::HandleObject obj) {
+        return setFlags(cx, obj, js::BaseShape::QUALIFIED_VAROBJ);
     }
 
     // An "unqualified" varobj is the object on which "unqualified"
     // assignments (i.e., bareword assignments for which the LHS does not
     // exist on the scope chain) are kept.
     inline bool isUnqualifiedVarObj() const;
 
     // Objects with an uncacheable proto can have their prototype mutated
     // without inducing a shape change on the object. JIT inline caches should
     // do an explicit group guard to guard against this. Singletons always
     // generate a new shape when their prototype changes, regardless of this
     // hasUncacheableProto flag.
     inline bool hasUncacheableProto() const;
-    bool setUncacheableProto(js::ExclusiveContext* cx) {
-        MOZ_ASSERT(hasStaticPrototype(),
+    static bool setUncacheableProto(js::ExclusiveContext* cx, JS::HandleObject obj) {
+        MOZ_ASSERT(obj->hasStaticPrototype(),
                    "uncacheability as a concept is only applicable to static "
                    "(not dynamically-computed) prototypes");
-        return setFlags(cx, js::BaseShape::UNCACHEABLE_PROTO, GENERATE_SHAPE);
+        return setFlags(cx, obj, js::BaseShape::UNCACHEABLE_PROTO, GENERATE_SHAPE);
     }
 
     /*
      * Whether SETLELEM was used to access this object. See also the comment near
      * PropertyTree::MAX_HEIGHT.
      */
     inline bool hadElementsAccess() const;
-    bool setHadElementsAccess(js::ExclusiveContext* cx) {
-        return setFlags(cx, js::BaseShape::HAD_ELEMENTS_ACCESS);
+    static bool setHadElementsAccess(js::ExclusiveContext* cx, JS::HandleObject obj) {
+        return setFlags(cx, obj, js::BaseShape::HAD_ELEMENTS_ACCESS);
     }
 
     /*
      * Whether there may be indexed properties on this object, excluding any in
      * the object's elements.
      */
     inline bool isIndexed() const;
 
@@ -414,31 +414,31 @@ class JSObject : public js::gc::Cell
     inline void setGroup(js::ObjectGroup* group);
 
     /*
      * Mark an object that has been iterated over and is a singleton. We need
      * to recover this information in the object's type information after it
      * is purged on GC.
      */
     inline bool isIteratedSingleton() const;
-    bool setIteratedSingleton(js::ExclusiveContext* cx) {
-        return setFlags(cx, js::BaseShape::ITERATED_SINGLETON);
+    static bool setIteratedSingleton(js::ExclusiveContext* cx, JS::HandleObject obj) {
+        return setFlags(cx, obj, js::BaseShape::ITERATED_SINGLETON);
     }
 
     /*
      * Mark an object as requiring its default 'new' type to have unknown
      * properties.
      */
     inline bool isNewGroupUnknown() const;
     static bool setNewGroupUnknown(JSContext* cx, const js::Class* clasp, JS::HandleObject obj);
 
     // Mark an object as having its 'new' script information cleared.
     inline bool wasNewScriptCleared() const;
-    bool setNewScriptCleared(js::ExclusiveContext* cx) {
-        return setFlags(cx, js::BaseShape::NEW_SCRIPT_CLEARED);
+    static bool setNewScriptCleared(js::ExclusiveContext* cx, JS::HandleObject obj) {
+        return setFlags(cx, obj, js::BaseShape::NEW_SCRIPT_CLEARED);
     }
 
     /* Set a new prototype for an object with a singleton type. */
     static bool splicePrototype(JSContext* cx, js::HandleObject obj, const js::Class* clasp,
                                 js::Handle<js::TaggedProto> proto);
 
     /*
      * For bootstrapping, whether to splice a prototype for Function.prototype
--- a/js/src/jswatchpoint.cpp
+++ b/js/src/jswatchpoint.cpp
@@ -59,17 +59,17 @@ WatchpointMap::init()
 }
 
 bool
 WatchpointMap::watch(JSContext* cx, HandleObject obj, HandleId id,
                      JSWatchPointHandler handler, HandleObject closure)
 {
     MOZ_ASSERT(JSID_IS_STRING(id) || JSID_IS_INT(id) || JSID_IS_SYMBOL(id));
 
-    if (!obj->setWatched(cx))
+    if (!JSObject::setWatched(cx, obj))
         return false;
 
     Watchpoint w(handler, closure, false);
     if (!map.put(WatchKey(obj, id), w)) {
         ReportOutOfMemory(cx);
         return false;
     }
     /*
--- a/js/src/proxy/CrossCompartmentWrapper.cpp
+++ b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -84,17 +84,17 @@ CrossCompartmentWrapper::getPrototype(JS
                                       MutableHandleObject protop) const
 {
     {
         RootedObject wrapped(cx, wrappedObject(wrapper));
         AutoCompartment call(cx, wrapped);
         if (!GetPrototype(cx, wrapped, protop))
             return false;
         if (protop) {
-            if (!protop->setDelegate(cx))
+            if (!JSObject::setDelegate(cx, protop))
                 return false;
         }
     }
 
     return cx->compartment()->wrap(cx, protop);
 }
 
 bool
@@ -117,17 +117,17 @@ CrossCompartmentWrapper::getPrototypeIfO
         AutoCompartment call(cx, wrapped);
         if (!GetPrototypeIfOrdinary(cx, wrapped, isOrdinary, protop))
             return false;
 
         if (!*isOrdinary)
             return true;
 
         if (protop) {
-            if (!protop->setDelegate(cx))
+            if (!JSObject::setDelegate(cx, protop))
                 return false;
         }
     }
 
     return cx->compartment()->wrap(cx, protop);
 }
 
 bool
--- a/js/src/vm/EnvironmentObject.cpp
+++ b/js/src/vm/EnvironmentObject.cpp
@@ -840,17 +840,17 @@ NonSyntacticVariablesObject::create(JSCo
 {
     Rooted<NonSyntacticVariablesObject*> obj(cx,
         NewObjectWithNullTaggedProto<NonSyntacticVariablesObject>(cx, TenuredObject,
                                                                   BaseShape::DELEGATE));
     if (!obj)
         return nullptr;
 
     MOZ_ASSERT(obj->isUnqualifiedVarObj());
-    if (!obj->setQualifiedVarObj(cx))
+    if (!JSObject::setQualifiedVarObj(cx, obj))
         return nullptr;
 
     obj->initEnclosingEnvironment(&cx->global()->lexicalEnvironment());
     return obj;
 }
 
 const Class NonSyntacticVariablesObject::class_ = {
     "NonSyntacticVariablesObject",
@@ -980,17 +980,17 @@ LexicalEnvironmentObject::createHollowFo
     RootedValue optimizedOut(cx, MagicValue(JS_OPTIMIZED_OUT));
     RootedId id(cx);
     for (Rooted<BindingIter> bi(cx, BindingIter(scope)); bi; bi++) {
         id = NameToId(bi.name()->asPropertyName());
         if (!SetProperty(cx, env, id, optimizedOut))
             return nullptr;
     }
 
-    if (!env->setFlags(cx, BaseShape::NOT_EXTENSIBLE, JSObject::GENERATE_SHAPE))
+    if (!JSObject::setFlags(cx, env, BaseShape::NOT_EXTENSIBLE, JSObject::GENERATE_SHAPE))
         return nullptr;
 
     env->initScopeUnchecked(scope);
     return env;
 }
 
 /* static */ LexicalEnvironmentObject*
 LexicalEnvironmentObject::clone(JSContext* cx, Handle<LexicalEnvironmentObject*> env)
--- a/js/src/vm/GeneratorObject.cpp
+++ b/js/src/vm/GeneratorObject.cpp
@@ -273,17 +273,17 @@ js::NewSingletonObjectWithFunctionProtot
 
 /* static */ bool
 GlobalObject::initLegacyGeneratorProto(JSContext* cx, Handle<GlobalObject*> global)
 {
     if (global->getReservedSlot(LEGACY_GENERATOR_OBJECT_PROTO).isObject())
         return true;
 
     RootedObject proto(cx, NewSingletonObjectWithObjectPrototype(cx, global));
-    if (!proto || !proto->setDelegate(cx))
+    if (!proto || !JSObject::setDelegate(cx, proto))
         return false;
     if (!DefinePropertiesAndFunctions(cx, proto, nullptr, legacy_generator_methods))
         return false;
 
     global->setReservedSlot(LEGACY_GENERATOR_OBJECT_PROTO, ObjectValue(*proto));
     return true;
 }
 
@@ -304,17 +304,17 @@ GlobalObject::initStarGenerators(JSConte
         return false;
     if (!DefinePropertiesAndFunctions(cx, genObjectProto, nullptr, star_generator_methods) ||
         !DefineToStringTag(cx, genObjectProto, cx->names().Generator))
     {
         return false;
     }
 
     RootedObject genFunctionProto(cx, NewSingletonObjectWithFunctionPrototype(cx, global));
-    if (!genFunctionProto || !genFunctionProto->setDelegate(cx))
+    if (!genFunctionProto || !JSObject::setDelegate(cx, genFunctionProto))
         return false;
     if (!LinkConstructorAndPrototype(cx, genFunctionProto, genObjectProto, JSPROP_READONLY,
                                      JSPROP_READONLY) ||
         !DefineToStringTag(cx, genFunctionProto, cx->names().GeneratorFunction))
     {
         return false;
     }
 
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -324,19 +324,19 @@ GlobalObject::createInternal(JSContext* 
 
     Rooted<GlobalScope*> emptyGlobalScope(cx, GlobalScope::createEmpty(cx, ScopeKind::Global));
     if (!emptyGlobalScope)
         return nullptr;
     global->setReservedSlot(EMPTY_GLOBAL_SCOPE, PrivateGCThingValue(emptyGlobalScope));
 
     cx->compartment()->initGlobal(*global);
 
-    if (!global->setQualifiedVarObj(cx))
+    if (!JSObject::setQualifiedVarObj(cx, global))
         return nullptr;
-    if (!global->setDelegate(cx))
+    if (!JSObject::setDelegate(cx, global))
         return nullptr;
 
     return global;
 }
 
 GlobalObject*
 GlobalObject::new_(JSContext* cx, const Class* clasp, JSPrincipals* principals,
                    JS::OnNewGlobalHookOption hookOption,
@@ -590,17 +590,17 @@ GlobalObject::createConstructor(JSContex
 
 static NativeObject*
 CreateBlankProto(JSContext* cx, const Class* clasp, HandleObject proto, HandleObject global)
 {
     MOZ_ASSERT(clasp != &JSFunction::class_);
 
     RootedNativeObject blankProto(cx, NewNativeObjectWithGivenProto(cx, clasp, proto,
                                                                     SingletonObject));
-    if (!blankProto || !blankProto->setDelegate(cx))
+    if (!blankProto || !JSObject::setDelegate(cx, blankProto))
         return nullptr;
 
     return blankProto;
 }
 
 NativeObject*
 GlobalObject::createBlankPrototype(JSContext* cx, const Class* clasp)
 {
--- a/js/src/vm/Interpreter.cpp
+++ b/js/src/vm/Interpreter.cpp
@@ -1516,17 +1516,17 @@ SetObjectElementOperation(JSContext* cx,
         int32_t i = JSID_TO_INT(id);
         if ((uint32_t)i >= length) {
             // Annotate script if provided with information (e.g. baseline)
             if (script && script->hasBaselineScript() && IsSetElemPC(pc))
                 script->baselineScript()->noteArrayWriteHole(script->pcToOffset(pc));
         }
     }
 
-    if (obj->isNative() && !JSID_IS_INT(id) && !obj->setHadElementsAccess(cx))
+    if (obj->isNative() && !JSID_IS_INT(id) && !JSObject::setHadElementsAccess(cx, obj))
         return false;
 
     ObjectOpResult result;
     return SetProperty(cx, obj, id, value, receiver, result) &&
            result.checkStrictErrorOrWarning(cx, obj, id, strict);
 }
 
 /*
--- a/js/src/vm/ObjectGroup.cpp
+++ b/js/src/vm/ObjectGroup.cpp
@@ -277,18 +277,21 @@ JSObject::splicePrototype(JSContext* cx,
      * can be rearranged as needed without destroying type information for
      * the old or new types.
      */
     MOZ_ASSERT(obj->isSingleton());
 
     // Windows may not appear on prototype chains.
     MOZ_ASSERT_IF(proto.isObject(), !IsWindow(proto.toObject()));
 
-    if (proto.isObject() && !proto.toObject()->setDelegate(cx))
-        return false;
+    if (proto.isObject()) {
+        RootedObject protoObj(cx, proto.toObject());
+        if (!JSObject::setDelegate(cx, protoObj))
+            return false;
+    }
 
     // Force type instantiation when splicing lazy group.
     RootedObjectGroup group(cx, JSObject::getGroup(cx, obj));
     if (!group)
         return false;
     RootedObjectGroup protoGroup(cx, nullptr);
     if (proto.isObject()) {
         RootedObject protoObj(cx, proto.toObject());
@@ -345,17 +348,17 @@ JSObject::makeLazyGroup(JSContext* cx, H
 
     return group;
 }
 
 /* static */ bool
 JSObject::setNewGroupUnknown(JSContext* cx, const js::Class* clasp, JS::HandleObject obj)
 {
     ObjectGroup::setDefaultNewGroupUnknown(cx, clasp, obj);
-    return obj->setFlags(cx, BaseShape::NEW_GROUP_UNKNOWN);
+    return JSObject::setFlags(cx, obj, BaseShape::NEW_GROUP_UNKNOWN);
 }
 
 /////////////////////////////////////////////////////////////////////
 // ObjectGroupCompartment NewTable
 /////////////////////////////////////////////////////////////////////
 
 /*
  * Entries for the per-compartment set of groups which are the default
@@ -513,17 +516,17 @@ ObjectGroup::defaultNewGroup(ExclusiveCo
         }
 
         if (!associated)
             clasp = &PlainObject::class_;
     }
 
     if (proto.isObject() && !proto.toObject()->isDelegate()) {
         RootedObject protoObj(cx, proto.toObject());
-        if (!protoObj->setDelegate(cx))
+        if (!JSObject::setDelegate(cx, protoObj))
             return nullptr;
 
         // Objects which are prototypes of one another should be singletons, so
         // that their type information can be tracked more precisely. Limit
         // this group change to plain objects, to avoid issues with other types
         // of singletons like typed arrays.
         if (protoObj->is<PlainObject>() && !protoObj->isSingleton()) {
             if (!JSObject::changeToSingleton(cx->asJSContext(), protoObj))
--- a/js/src/vm/Shape.cpp
+++ b/js/src/vm/Shape.cpp
@@ -1201,48 +1201,47 @@ NativeObject::replaceWithNewEquivalentSh
 }
 
 bool
 NativeObject::shadowingShapeChange(ExclusiveContext* cx, const Shape& shape)
 {
     return generateOwnShape(cx);
 }
 
-bool
-JSObject::setFlags(ExclusiveContext* cx, BaseShape::Flag flags, GenerateShape generateShape)
+/* static */ bool
+JSObject::setFlags(ExclusiveContext* cx, HandleObject obj, BaseShape::Flag flags,
+                   GenerateShape generateShape)
 {
-    if (hasAllFlags(flags))
+    if (obj->hasAllFlags(flags))
         return true;
 
-    RootedObject self(cx, this);
-
-    if (isNative() && as<NativeObject>().inDictionaryMode()) {
-        if (generateShape == GENERATE_SHAPE && !as<NativeObject>().generateOwnShape(cx))
+    if (obj->isNative() && obj->as<NativeObject>().inDictionaryMode()) {
+        if (generateShape == GENERATE_SHAPE && !obj->as<NativeObject>().generateOwnShape(cx))
             return false;
-        StackBaseShape base(self->as<NativeObject>().lastProperty());
+        StackBaseShape base(obj->as<NativeObject>().lastProperty());
         base.flags |= flags;
         UnownedBaseShape* nbase = BaseShape::getUnowned(cx, base);
         if (!nbase)
             return false;
 
-        self->as<NativeObject>().lastProperty()->base()->adoptUnowned(nbase);
+        obj->as<NativeObject>().lastProperty()->base()->adoptUnowned(nbase);
         return true;
     }
 
-    Shape* existingShape = self->ensureShape(cx);
+    Shape* existingShape = obj->ensureShape(cx);
     if (!existingShape)
         return false;
 
-    Shape* newShape = Shape::setObjectFlags(cx, flags, self->taggedProto(), existingShape);
+    Shape* newShape = Shape::setObjectFlags(cx, flags, obj->taggedProto(), existingShape);
     if (!newShape)
         return false;
 
-    // The success of the |JSObject::ensureShape| call above means that |self|
+    // The success of the |JSObject::ensureShape| call above means that |obj|
     // can be assumed to have a shape.
-    self->as<ShapedObject>().setShape(newShape);
+    obj->as<ShapedObject>().setShape(newShape);
 
     return true;
 }
 
 bool
 NativeObject::clearFlag(ExclusiveContext* cx, BaseShape::Flag flag)
 {
     MOZ_ASSERT(inDictionaryMode());
--- a/js/src/vm/TypeInference.cpp
+++ b/js/src/vm/TypeInference.cpp
@@ -3031,17 +3031,18 @@ ObjectGroup::clearNewScript(ExclusiveCon
     AutoEnterAnalysis enter(cx);
 
     if (!replacement) {
         // Invalidate any Ion code constructing objects of this type.
         setFlags(cx, OBJECT_FLAG_NEW_SCRIPT_CLEARED);
 
         // Mark the constructing function as having its 'new' script cleared, so we
         // will not try to construct another one later.
-        if (!newScript->function()->setNewScriptCleared(cx))
+        RootedFunction fun(cx, newScript->function());
+        if (!JSObject::setNewScriptCleared(cx, fun))
             cx->recoverFromOutOfMemory();
     }
 
     detachNewScript(/* writeBarrier = */ true, replacement);
 
     if (cx->isJSContext()) {
         bool found = newScript->rollbackPartiallyInitializedObjects(cx->asJSContext(), this);