Bug 1112778, part 9 - Rename JSObject::freeze -> FreezeObject and others. r=Waldo.
authorJason Orendorff <jorendorff@mozilla.com>
Thu, 18 Dec 2014 10:48:42 -0600
changeset 251153 8330481355e1cb6908038732eae0f5a326950bf0
parent 251152 373c4f89625ef99ce1a685d28a1206d4cca3fb51
child 251154 f1aa2f649c70258d34164242781b6be95c3aa0c8
push id4610
push userjlund@mozilla.com
push dateMon, 30 Mar 2015 18:32:55 +0000
treeherdermozilla-beta@4df54044d9ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersWaldo
bugs1112778
milestone38.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 1112778, part 9 - Rename JSObject::freeze -> FreezeObject and others. r=Waldo. Some of the bits of implementation added for ES5 have been given names in ES6, so JSObject::sealOrFreeze -> js::SetIntegrityLevel JSObject::isSealedOrFrozen -> js::TestIntegrityLevel JSObject::ImmutabilityType -> js::IntegrityLevel
js/src/builtin/Object.cpp
js/src/builtin/TypedObject.cpp
js/src/jsapi.cpp
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/vm/Debugger.cpp
js/src/vm/Interpreter-inl.h
js/src/vm/NativeObject.h
js/src/vm/SavedStacks.cpp
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -908,32 +908,32 @@ obj_freeze(JSContext *cx, unsigned argc,
     args.rval().set(args.get(0));
 
     // Step 1.
     if (!args.get(0).isObject())
         return true;
 
     // Steps 2-5.
     RootedObject obj(cx, &args.get(0).toObject());
-    return JSObject::freeze(cx, obj);
+    return SetIntegrityLevel(cx, obj, IntegrityLevel::Frozen);
 }
 
 // ES6 draft rev27 (2014/08/24) 19.1.2.12 Object.isFrozen(O)
 static bool
 obj_isFrozen(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Step 1.
     bool frozen = true;
 
     // Step 2.
     if (args.get(0).isObject()) {
         RootedObject obj(cx, &args.get(0).toObject());
-        if (!JSObject::isFrozen(cx, obj, &frozen))
+        if (!TestIntegrityLevel(cx, obj, IntegrityLevel::Frozen, &frozen))
             return false;
     }
     args.rval().setBoolean(frozen);
     return true;
 }
 
 // ES6 draft rev27 (2014/08/24) 19.1.2.17 Object.seal(O)
 static bool
@@ -943,32 +943,32 @@ obj_seal(JSContext *cx, unsigned argc, V
     args.rval().set(args.get(0));
 
     // Step 1.
     if (!args.get(0).isObject())
         return true;
 
     // Steps 2-5.
     RootedObject obj(cx, &args.get(0).toObject());
-    return JSObject::seal(cx, obj);
+    return SetIntegrityLevel(cx, obj, IntegrityLevel::Sealed);
 }
 
 // ES6 draft rev27 (2014/08/24) 19.1.2.13 Object.isSealed(O)
 static bool
 obj_isSealed(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
 
     // Step 1.
     bool sealed = true;
 
     // Step 2.
     if (args.get(0).isObject()) {
         RootedObject obj(cx, &args.get(0).toObject());
-        if (!JSObject::isSealed(cx, obj, &sealed))
+        if (!TestIntegrityLevel(cx, obj, IntegrityLevel::Sealed, &sealed))
             return false;
     }
     args.rval().setBoolean(sealed);
     return true;
 }
 
 static bool
 ProtoGetter(JSContext *cx, unsigned argc, Value *vp)
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -942,19 +942,19 @@ StructMetaTypeDescr::create(JSContext *c
                                               TenuredObject);
         if (!fieldOffsetsVec)
             return nullptr;
         descr->initReservedSlot(JS_DESCR_SLOT_STRUCT_FIELD_OFFSETS,
                                      ObjectValue(*fieldOffsetsVec));
     }
 
     // Create data properties fieldOffsets and fieldTypes
-    if (!JSObject::freeze(cx, userFieldOffsets))
+    if (!FreezeObject(cx, userFieldOffsets))
         return nullptr;
-    if (!JSObject::freeze(cx, userFieldTypes))
+    if (!FreezeObject(cx, userFieldTypes))
         return nullptr;
     RootedValue userFieldOffsetsValue(cx, ObjectValue(*userFieldOffsets));
     if (!DefineProperty(cx, descr, cx->names().fieldOffsets, userFieldOffsetsValue,
                         nullptr, nullptr, JSPROP_READONLY | JSPROP_PERMANENT))
     {
         return nullptr;
     }
     RootedValue userFieldTypesValue(cx, ObjectValue(*userFieldTypes));
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2243,34 +2243,34 @@ JS_GetObjectRuntime(JSObject *obj)
 }
 
 JS_PUBLIC_API(bool)
 JS_FreezeObject(JSContext *cx, HandleObject obj)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
-    return JSObject::freeze(cx, obj);
+    return FreezeObject(cx, obj);
 }
 
 JS_PUBLIC_API(bool)
 JS_DeepFreezeObject(JSContext *cx, HandleObject obj)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
 
     /* Assume that non-extensible objects are already deep-frozen, to avoid divergence. */
     bool extensible;
     if (!IsExtensible(cx, obj, &extensible))
         return false;
     if (!extensible)
         return true;
 
-    if (!JSObject::freeze(cx, obj))
+    if (!FreezeObject(cx, obj))
         return false;
 
     /* Walk slots in obj and if any value is a non-null object, seal it. */
     if (obj->isNative()) {
         for (uint32_t i = 0, n = obj->as<NativeObject>().slotSpan(); i < n; ++i) {
             const Value &v = obj->as<NativeObject>().getSlot(i);
             if (v.isPrimitive())
                 continue;
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -1435,17 +1435,17 @@ GlobalObject::initIteratorClasses(JSCont
 
 /* static */ bool
 GlobalObject::initStopIterationClass(JSContext *cx, Handle<GlobalObject *> global)
 {
     if (!global->getPrototype(JSProto_StopIteration).isUndefined())
         return true;
 
     RootedObject proto(cx, global->createBlankPrototype(cx, &StopIterationObject::class_));
-    if (!proto || !JSObject::freeze(cx, proto))
+    if (!proto || !FreezeObject(cx, proto))
         return false;
 
     // This should use a non-JSProtoKey'd slot, but this is easier for now.
     if (!GlobalObject::initBuiltinConstructor(cx, global, JSProto_StopIteration, proto, proto))
         return false;
 
     global->setConstructor(JSProto_StopIteration, ObjectValue(*proto));
 
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1002,180 +1002,190 @@ JSObject::uninlinedGetType(JSContext *cx
 }
 
 void
 JSObject::uninlinedSetType(js::types::TypeObject *newType)
 {
     setType(newType);
 }
 
-/* static */ inline unsigned
-JSObject::getSealedOrFrozenAttributes(unsigned attrs, ImmutabilityType it)
+
+/*** Seal and freeze *****************************************************************************/
+
+static unsigned
+GetSealedOrFrozenAttributes(unsigned attrs, IntegrityLevel level)
 {
     /* Make all attributes permanent; if freezing, make data attributes read-only. */
-    if (it == FREEZE && !(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
+    if (level == IntegrityLevel::Frozen && !(attrs & (JSPROP_GETTER | JSPROP_SETTER)))
         return JSPROP_PERMANENT | JSPROP_READONLY;
     return JSPROP_PERMANENT;
 }
 
-/* static */ bool
-JSObject::sealOrFreeze(JSContext *cx, HandleObject obj, ImmutabilityType it)
+/* ES6 draft rev 29 (6 Dec 2014) 7.3.13. */
+bool
+js::SetIntegrityLevel(JSContext *cx, HandleObject obj, IntegrityLevel level)
 {
     assertSameCompartment(cx, obj);
-    MOZ_ASSERT(it == SEAL || it == FREEZE);
-
-    bool succeeded;
-    if (!PreventExtensions(cx, obj, &succeeded))
+
+    // Steps 3-5. (Steps 1-2 are redundant assertions.)
+    bool status;
+    if (!PreventExtensions(cx, obj, &status))
         return false;
-    if (!succeeded) {
+    if (!status) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CHANGE_EXTENSIBILITY);
         return false;
     }
 
-    AutoIdVector props(cx);
-    if (!GetPropertyKeys(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY | JSITER_SYMBOLS, &props))
+    // Steps 6-7.
+    AutoIdVector keys(cx);
+    if (!GetPropertyKeys(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY | JSITER_SYMBOLS, &keys))
         return false;
 
-    /* preventExtensions must sparsify dense objects, so we can assign to holes without checks. */
+    // PreventExtensions must sparsify dense objects, so we can assign to holes
+    // without checks.
     MOZ_ASSERT_IF(obj->isNative(), obj->as<NativeObject>().getDenseCapacity() == 0);
 
+    // Steps 8-9, loosely interpreted.
     if (obj->isNative() && !obj->as<NativeObject>().inDictionaryMode() && !IsAnyTypedArray(obj)) {
         HandleNativeObject nobj = obj.as<NativeObject>();
 
-        /*
-         * Seal/freeze non-dictionary objects by constructing a new shape
-         * hierarchy mirroring the original one, which can be shared if many
-         * objects with the same structure are sealed/frozen. If we use the
-         * generic path below then any non-empty object will be converted to
-         * dictionary mode.
-         */
+        // Seal/freeze non-dictionary objects by constructing a new shape
+        // hierarchy mirroring the original one, which can be shared if many
+        // objects with the same structure are sealed/frozen. If we use the
+        // generic path below then any non-empty object will be converted to
+        // dictionary mode.
         RootedShape last(cx, EmptyShape::getInitialShape(cx, nobj->getClass(),
                                                          nobj->getTaggedProto(),
                                                          nobj->getParent(),
                                                          nobj->getMetadata(),
                                                          nobj->numFixedSlots(),
                                                          nobj->lastProperty()->getObjectFlags()));
         if (!last)
             return false;
 
-        /* Get an in order list of the shapes in this object. */
+        // Get an in-order list of the shapes in this object.
         AutoShapeVector shapes(cx);
         for (Shape::Range<NoGC> r(nobj->lastProperty()); !r.empty(); r.popFront()) {
             if (!shapes.append(&r.front()))
                 return false;
         }
         Reverse(shapes.begin(), shapes.end());
 
         for (size_t i = 0; i < shapes.length(); i++) {
             StackShape unrootedChild(shapes[i]);
             RootedGeneric<StackShape*> child(cx, &unrootedChild);
-            child->attrs |= getSealedOrFrozenAttributes(child->attrs, it);
-
-            if (!JSID_IS_EMPTY(child->propid) && it == FREEZE)
+            child->attrs |= GetSealedOrFrozenAttributes(child->attrs, level);
+
+            if (!JSID_IS_EMPTY(child->propid) && level == IntegrityLevel::Frozen)
                 MarkTypePropertyNonWritable(cx, nobj, child->propid);
 
             last = cx->compartment()->propertyTree.getChild(cx, last, *child);
             if (!last)
                 return false;
         }
 
         MOZ_ASSERT(nobj->lastProperty()->slotSpan() == last->slotSpan());
         JS_ALWAYS_TRUE(NativeObject::setLastProperty(cx, nobj, last));
     } else {
         RootedId id(cx);
-        for (size_t i = 0; i < props.length(); i++) {
-            id = props[i];
+        for (size_t i = 0; i < keys.length(); i++) {
+            id = keys[i];
 
             unsigned attrs;
-            if (!getGenericAttributes(cx, obj, id, &attrs))
+            if (!JSObject::getGenericAttributes(cx, obj, id, &attrs))
                 return false;
 
-            unsigned new_attrs = getSealedOrFrozenAttributes(attrs, it);
-
-            /* If we already have the attributes we need, skip the setAttributes call. */
+            unsigned new_attrs = GetSealedOrFrozenAttributes(attrs, level);
+
+            // If we already have the attributes we need, skip the setAttributes call.
             if ((attrs | new_attrs) == attrs)
                 continue;
 
             attrs |= new_attrs;
-            if (!setGenericAttributes(cx, obj, id, &attrs))
+            if (!JSObject::setGenericAttributes(cx, obj, id, &attrs))
                 return false;
         }
     }
 
     // Ordinarily ArraySetLength handles this, but we're going behind its back
     // right now, so we must do this manually.  Neither the custom property
     // tree mutations nor the setGenericAttributes call in the above code will
     // do this for us.
     //
     // ArraySetLength also implements the capacity <= length invariant for
     // arrays with non-writable length.  We don't need to do anything special
     // for that, because capacity was zeroed out by preventExtensions.  (See
     // the assertion before the if-else above.)
-    if (it == FREEZE && obj->is<ArrayObject>()) {
+    if (level == IntegrityLevel::Frozen && obj->is<ArrayObject>()) {
         if (!obj->as<ArrayObject>().maybeCopyElementsForWrite(cx))
             return false;
         obj->as<ArrayObject>().getElementsHeader()->setNonwritableArrayLength();
     }
 
     return true;
 }
 
-/* static */ bool
-JSObject::isSealedOrFrozen(JSContext *cx, HandleObject obj, ImmutabilityType it, bool *resultp)
+/* ES6 rev 29 (6 Dec 2014) 7.3.14. */
+bool
+js::TestIntegrityLevel(JSContext *cx, HandleObject obj, IntegrityLevel level, bool *result)
 {
-    bool extensible;
-    if (!IsExtensible(cx, obj, &extensible))
+    // Steps 3-6. (Steps 1-2 are redundant assertions.)
+    bool status;
+    if (!IsExtensible(cx, obj, &status))
         return false;
-    if (extensible) {
-        *resultp = false;
+    if (status) {
+        *result = false;
         return true;
     }
 
     if (IsAnyTypedArray(obj)) {
-        if (it == SEAL) {
-            // Typed arrays are always sealed.
-            *resultp = true;
+        if (level == IntegrityLevel::Sealed) {
+            // Typed arrays are considered sealed (bug 1120503).
+            *result = true;
         } else {
             // Typed arrays cannot be frozen, but an empty typed array is
-            // trivially frozen.
-            *resultp = (AnyTypedArrayLength(obj) == 0);
+            // considered frozen (bug 1120503).
+            *result = (AnyTypedArrayLength(obj) == 0);
         }
         return true;
     }
 
+    // Steps 7-8.
     AutoIdVector props(cx);
     if (!GetPropertyKeys(cx, obj, JSITER_HIDDEN | JSITER_OWNONLY | JSITER_SYMBOLS, &props))
         return false;
 
+    // Steps 9-11. The spec does not permit stopping as soon as we find out the
+    // answer is false, so we are cheating a little here (bug 1120512).
     RootedId id(cx);
     for (size_t i = 0, len = props.length(); i < len; i++) {
         id = props[i];
 
         unsigned attrs;
-        if (!getGenericAttributes(cx, obj, id, &attrs))
+        if (!JSObject::getGenericAttributes(cx, obj, id, &attrs))
             return false;
 
-        /*
-         * If the property is configurable, this object is neither sealed nor
-         * frozen. If the property is a writable data property, this object is
-         * not frozen.
-         */
+        // If the property is configurable, this object is neither sealed nor
+        // frozen. If the property is a writable data property, this object is
+        // not frozen.
         if (!(attrs & JSPROP_PERMANENT) ||
-            (it == FREEZE && !(attrs & (JSPROP_READONLY | JSPROP_GETTER | JSPROP_SETTER))))
+            (level == IntegrityLevel::Frozen &&
+             !(attrs & (JSPROP_READONLY | JSPROP_GETTER | JSPROP_SETTER))))
         {
-            *resultp = false;
+            *result = false;
             return true;
         }
     }
 
-    /* All properties checked out. This object is sealed/frozen. */
-    *resultp = true;
+    // All properties checked out. This object is sealed/frozen.
+    *result = true;
     return true;
 }
 
+
 /* static */
 const char *
 JSObject::className(JSContext *cx, HandleObject obj)
 {
     assertSameCompartment(cx, obj);
 
     if (obj->is<ProxyObject>())
         return Proxy::className(cx, obj);
@@ -2075,17 +2085,17 @@ js::XDRObjectLiteral(XDRState<mode> *xdr
         if (mode == XDR_ENCODE) {
             if (!IsExtensible(cx, obj, &extensible))
                 return false;
             frozen = extensible ? 0 : 1;
         }
         if (!xdr->codeUint32(&frozen))
             return false;
         if (mode == XDR_DECODE && frozen == 1) {
-            if (!JSObject::freeze(cx, obj))
+            if (!FreezeObject(cx, obj))
                 return false;
         }
     }
 
     if (isArray) {
         uint32_t copyOnWrite;
         if (mode == XDR_ENCODE)
             copyOnWrite = obj->denseElementsAreCopyOnWrite();
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -493,44 +493,16 @@ class JSObject : public js::gc::Cell
     // all as friends.
     bool nonProxyIsExtensible() const {
         MOZ_ASSERT(!uninlinedIsProxy());
 
         // [[Extensible]] for ordinary non-proxy objects is an object flag.
         return !lastProperty()->hasObjectFlag(js::BaseShape::NOT_EXTENSIBLE);
     }
 
-  private:
-    enum ImmutabilityType { SEAL, FREEZE };
-
-    /*
-     * The guts of Object.seal (ES5 15.2.3.8) and Object.freeze (ES5 15.2.3.9): mark the
-     * object as non-extensible, and adjust each property's attributes appropriately: each
-     * property becomes non-configurable, and if |freeze|, data properties become
-     * read-only as well.
-     */
-    static bool sealOrFreeze(JSContext *cx, js::HandleObject obj, ImmutabilityType it);
-
-    static bool isSealedOrFrozen(JSContext *cx, js::HandleObject obj, ImmutabilityType it, bool *resultp);
-
-    static inline unsigned getSealedOrFrozenAttributes(unsigned attrs, ImmutabilityType it);
-
-  public:
-    /* ES5 15.2.3.8: non-extensible, all props non-configurable */
-    static inline bool seal(JSContext *cx, js::HandleObject obj) { return sealOrFreeze(cx, obj, SEAL); }
-    /* ES5 15.2.3.9: non-extensible, all properties non-configurable, all data props read-only */
-    static inline bool freeze(JSContext *cx, js::HandleObject obj) { return sealOrFreeze(cx, obj, FREEZE); }
-
-    static inline bool isSealed(JSContext *cx, js::HandleObject obj, bool *resultp) {
-        return isSealedOrFrozen(cx, obj, SEAL, resultp);
-    }
-    static inline bool isFrozen(JSContext *cx, js::HandleObject obj, bool *resultp) {
-        return isSealedOrFrozen(cx, obj, FREEZE, resultp);
-    }
-
     /* toString support. */
     static const char *className(JSContext *cx, js::HandleObject obj);
 
   public:
     /*
      * Iterator-specific getters and setters.
      */
 
@@ -1261,11 +1233,38 @@ extern bool
 Throw(JSContext *cx, JSObject *obj, unsigned errorNumber);
 
 extern bool
 NativeWatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable);
 
 extern bool
 NativeUnwatch(JSContext *cx, JS::HandleObject obj, JS::HandleId id);
 
+enum class IntegrityLevel {
+    Sealed,
+    Frozen
+};
+
+/*
+ * ES6 rev 29 (6 Dec 2014) 7.3.13. Mark obj as non-extensible, and adjust each
+ * of obj's own properties' attributes appropriately: each property becomes
+ * non-configurable, and if level == Frozen, data properties become
+ * non-writable as well.
+ */
+extern bool
+SetIntegrityLevel(JSContext *cx, HandleObject obj, IntegrityLevel level);
+
+inline bool
+FreezeObject(JSContext *cx, HandleObject obj)
+{
+    return SetIntegrityLevel(cx, obj, IntegrityLevel::Frozen);
+}
+
+/*
+ * ES6 rev 29 (6 Dec 2014) 7.3.14. Code shared by Object.isSealed and
+ * Object.isFrozen.
+ */
+extern bool
+TestIntegrityLevel(JSContext *cx, HandleObject obj, IntegrityLevel level, bool *resultp);
+
 }  /* namespace js */
 
 #endif /* jsobj_h */
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -6715,19 +6715,19 @@ DebuggerObject_sealHelper(JSContext *cx,
 {
     THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, name, args, obj);
 
     Maybe<AutoCompartment> ac;
     ac.emplace(cx, obj);
     ErrorCopier ec(ac);
     bool ok;
     if (op == OpSeal) {
-        ok = JSObject::seal(cx, obj);
+        ok = SetIntegrityLevel(cx, obj, IntegrityLevel::Sealed);
     } else if (op == OpFreeze) {
-        ok = JSObject::freeze(cx, obj);
+        ok = SetIntegrityLevel(cx, obj, IntegrityLevel::Frozen);
     } else {
         MOZ_ASSERT(op == OpPreventExtensions);
         bool succeeded;
         ok = PreventExtensions(cx, obj, &succeeded);
         if (!ok)
             return false;
         if (!succeeded) {
             JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_CANT_CHANGE_EXTENSIBILITY);
@@ -6764,20 +6764,20 @@ DebuggerObject_isSealedHelper(JSContext 
 {
     THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, name, args, obj);
 
     Maybe<AutoCompartment> ac;
     ac.emplace(cx, obj);
     ErrorCopier ec(ac);
     bool r;
     if (op == OpSeal) {
-        if (!JSObject::isSealed(cx, obj, &r))
+        if (!TestIntegrityLevel(cx, obj, IntegrityLevel::Sealed, &r))
             return false;
     } else if (op == OpFreeze) {
-        if (!JSObject::isFrozen(cx, obj, &r))
+        if (!TestIntegrityLevel(cx, obj, IntegrityLevel::Frozen, &r))
             return false;
     } else {
         if (!IsExtensible(cx, obj, &r))
             return false;
     }
     args.rval().setBoolean(r);
     return true;
 }
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -653,19 +653,19 @@ ProcessCallSiteObjOperation(JSContext *c
 {
     bool extensible;
     if (!IsExtensible(cx, cso, &extensible))
         return false;
     if (extensible) {
         JSAtom *name = cx->names().raw;
         if (!DefineProperty(cx, cso, name->asPropertyName(), rawValue, nullptr, nullptr, 0))
             return false;
-        if (!JSObject::freeze(cx, raw))
+        if (!FreezeObject(cx, raw))
             return false;
-        if (!JSObject::freeze(cx, cso))
+        if (!FreezeObject(cx, cso))
             return false;
     }
     return true;
 }
 
 #define RELATIONAL_OP(OP)                                                     \
     JS_BEGIN_MACRO                                                            \
         /* Optimize for two int-tagged operands (typical loop control). */    \
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -180,16 +180,18 @@ class ObjectElements
     };
 
   private:
     friend class ::JSObject;
     friend class NativeObject;
     friend class ArrayObject;
     friend class Nursery;
 
+    friend bool js::SetIntegrityLevel(JSContext *cx, HandleObject obj, IntegrityLevel level);
+
     friend bool
     ArraySetLength(JSContext *cx, Handle<ArrayObject*> obj, HandleId id,
                    unsigned attrs, HandleValue value, bool setterIsStrict);
 
     /* See Flags enum above. */
     uint32_t flags;
 
     /*
--- a/js/src/vm/SavedStacks.cpp
+++ b/js/src/vm/SavedStacks.cpp
@@ -597,17 +597,17 @@ SavedStacks::getOrCreateSavedFrameProtot
     if (!global)
         return nullptr;
 
     Rooted<SavedFrame *> proto(cx,
         NewObjectWithGivenProto<SavedFrame>(cx, global->getOrCreateObjectPrototype(cx), global));
     if (!proto
         || !JS_DefineProperties(cx, proto, SavedFrame::properties)
         || !JS_DefineFunctions(cx, proto, SavedFrame::methods)
-        || !JSObject::freeze(cx, proto))
+        || !FreezeObject(cx, proto))
     {
         return nullptr;
     }
 
     // The only object with the SavedFrame::class_ that doesn't have a source
     // should be the prototype.
     proto->setReservedSlot(SavedFrame::JSSLOT_SOURCE, NullValue());
 
@@ -632,17 +632,17 @@ SavedStacks::createFrameFromLookup(JSCon
 
     RootedObject frameObj(cx, NewObjectWithGivenProto(cx, &SavedFrame::class_, proto, global));
     if (!frameObj)
         return nullptr;
 
     RootedSavedFrame f(cx, &frameObj->as<SavedFrame>());
     f->initFromLookup(lookup);
 
-    if (!JSObject::freeze(cx, frameObj))
+    if (!FreezeObject(cx, frameObj))
         return nullptr;
 
     return f.get();
 }
 
 /*
  * Remove entries from the table whose JSScript is being collected.
  */