Bug 1122619 - Remove getPropertyAttributes object ops. r=jorendorff
authorTom Schuster <evilpies@gmail.com>
Sat, 24 Jan 2015 16:38:08 +0100
changeset 225554 ff99308cdefcf27899ce53d9198a11140f66a3ed
parent 225553 0509d8753ae8c05dbde9bff25f865ee7606c1a8d
child 225555 11540adce3b616c36314a7d278deed6c73fdc68a
push id28167
push userryanvm@gmail.com
push dateSun, 25 Jan 2015 00:24:46 +0000
treeherdermozilla-central@c18776175a69 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjorendorff
bugs1122619
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 1122619 - Remove getPropertyAttributes object ops. r=jorendorff
dom/bindings/Codegen.py
dom/plugins/base/nsJSNPRuntime.cpp
js/public/Class.h
js/src/builtin/TypedObject.cpp
js/src/builtin/TypedObject.h
js/src/jsapi.cpp
js/src/jsfriendapi.h
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/proxy/Proxy.cpp
js/src/vm/ArgumentsObject.cpp
js/src/vm/Interpreter-inl.h
js/src/vm/NativeObject.cpp
js/src/vm/NativeObject.h
js/src/vm/ScopeObject.cpp
js/xpconnect/src/XPCWrappedNativeJSOps.cpp
js/xpconnect/src/xpcprivate.h
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -400,17 +400,16 @@ class CGDOMJSClass(CGThing):
                       nullptr, /* defineElement */
                       nullptr, /* getGeneric  */
                       nullptr, /* getProperty */
                       nullptr, /* getElement */
                       nullptr, /* setGeneric */
                       nullptr, /* setProperty */
                       nullptr, /* setElement */
                       nullptr, /* getOwnPropertyDescriptor */
-                      nullptr, /* getGenericAttributes */
                       nullptr, /* setGenericAttributes */
                       nullptr, /* deleteGeneric */
                       nullptr, /* watch */
                       nullptr, /* unwatch */
                       nullptr, /* getElements */
                       nullptr, /* enumerate */
                       JS_ObjectToOuterObject /* thisObject */
                     }
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -230,17 +230,16 @@ const static js::Class sNPObjectJSWrappe
         nullptr, // defineElement
         nullptr, // getGeneric
         nullptr, // getProperty
         nullptr, // getElement
         nullptr, // setGeneric
         nullptr, // setProperty
         nullptr, // setElement
         nullptr, // getOwnPropertyDescriptor
-        nullptr, // getGenericAttributes
         nullptr, // setGenericAttributes
         nullptr, // deleteGeneric
         nullptr, nullptr, // watch/unwatch
         nullptr, // getElements
         NPObjWrapper_Enumerate,
         nullptr,
     }
   };
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -199,19 +199,16 @@ typedef bool
 (* StrictElementIdOp)(JSContext *cx, JS::HandleObject obj, uint32_t index,
                       JS::MutableHandleValue vp, bool strict);
 typedef bool
 (* GetOwnPropertyOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                      JS::MutableHandle<JSPropertyDescriptor> desc);
 typedef bool
 (* GenericAttributesOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned *attrsp);
 typedef bool
-(* PropertyAttributesOp)(JSContext *cx, JS::HandleObject obj, JS::Handle<PropertyName*> name,
-                         unsigned *attrsp);
-typedef bool
 (* DeleteGenericOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *succeeded);
 
 typedef bool
 (* WatchOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject callable);
 
 typedef bool
 (* UnwatchOp)(JSContext *cx, JS::HandleObject obj, JS::HandleId id);
 
@@ -377,17 +374,16 @@ struct ObjectOps
     DefineElementOp     defineElement;
     GenericIdOp         getGeneric;
     PropertyIdOp        getProperty;
     ElementIdOp         getElement;
     StrictGenericIdOp   setGeneric;
     StrictPropertyIdOp  setProperty;
     StrictElementIdOp   setElement;
     GetOwnPropertyOp    getOwnPropertyDescriptor;
-    GenericAttributesOp getGenericAttributes;
     GenericAttributesOp setGenericAttributes;
     DeleteGenericOp     deleteGeneric;
     WatchOp             watch;
     UnwatchOp           unwatch;
     GetElementsOp       getElements;
     JSNewEnumerateOp    enumerate;
     ObjectOp            thisObject;
 };
@@ -401,17 +397,17 @@ struct ObjectOps
 
 // Classes, objects, and properties.
 
 typedef void (*JSClassInternal)();
 
 struct JSClass {
     JS_CLASS_MEMBERS(JSFinalizeOp);
 
-    void                *reserved[33];
+    void                *reserved[32];
 };
 
 #define JSCLASS_HAS_PRIVATE             (1<<0)  // objects have private slot
 #define JSCLASS_PRIVATE_IS_NSISUPPORTS  (1<<3)  // private is (nsISupports *)
 #define JSCLASS_IS_DOMJSCLASS           (1<<4)  // objects are DOM
 #define JSCLASS_IMPLEMENTS_BARRIERS     (1<<5)  // Correctly implements GC read
                                                 // and write barriers
 #define JSCLASS_EMULATES_UNDEFINED      (1<<6)  // objects of this class act
--- a/js/src/builtin/TypedObject.cpp
+++ b/js/src/builtin/TypedObject.cpp
@@ -2058,59 +2058,16 @@ TypedObject::obj_getOwnPropertyDescripto
         return true;
       }
     }
 
     desc.object().set(nullptr);
     return true;
 }
 
-bool
-TypedObject::obj_getGenericAttributes(JSContext *cx, HandleObject obj,
-                                     HandleId id, unsigned *attrsp)
-{
-    uint32_t index;
-    Rooted<TypedObject *> typedObj(cx, &obj->as<TypedObject>());
-    switch (typedObj->typeDescr().kind()) {
-      case type::Scalar:
-      case type::Reference:
-        break;
-
-      case type::Simd:
-        break;
-
-      case type::Array:
-        if (js_IdIsIndex(id, &index)) {
-            *attrsp = JSPROP_ENUMERATE | JSPROP_PERMANENT;
-            return true;
-        }
-        if (JSID_IS_ATOM(id, cx->names().length)) {
-            *attrsp = JSPROP_READONLY | JSPROP_PERMANENT;
-            return true;
-        }
-        break;
-
-      case type::Struct:
-        size_t index;
-        if (typedObj->typeDescr().as<StructTypeDescr>().fieldIndex(id, &index)) {
-            *attrsp = JSPROP_ENUMERATE | JSPROP_PERMANENT;
-            return true;
-        }
-        break;
-    }
-
-    RootedObject proto(cx, obj->getProto());
-    if (!proto) {
-        *attrsp = 0;
-        return true;
-    }
-
-    return GetPropertyAttributes(cx, proto, id, attrsp);
-}
-
 static bool
 IsOwnId(JSContext *cx, HandleObject obj, HandleId id)
 {
     uint32_t index;
     Rooted<TypedObject *> typedObj(cx, &obj->as<TypedObject>());
     switch (typedObj->typeDescr().kind()) {
       case type::Scalar:
       case type::Reference:
@@ -2421,17 +2378,16 @@ LazyArrayBufferTable::sizeOfIncludingThi
             TypedObject::obj_defineElement,              \
             TypedObject::obj_getGeneric,                 \
             TypedObject::obj_getProperty,                \
             TypedObject::obj_getElement,                 \
             TypedObject::obj_setGeneric,                 \
             TypedObject::obj_setProperty,                \
             TypedObject::obj_setElement,                 \
             TypedObject::obj_getOwnPropertyDescriptor,   \
-            TypedObject::obj_getGenericAttributes,       \
             TypedObject::obj_setGenericAttributes,       \
             TypedObject::obj_deleteGeneric,              \
             nullptr, nullptr, /* watch/unwatch */        \
             nullptr,   /* getElements */                 \
             TypedObject::obj_enumerate,                  \
             nullptr, /* thisObject */                    \
         }                                                \
     }
--- a/js/src/builtin/TypedObject.h
+++ b/js/src/builtin/TypedObject.h
@@ -562,18 +562,16 @@ class TypedObject : public JSObject
     static bool obj_setProperty(JSContext *cx, HandleObject obj, HandlePropertyName name,
                                 MutableHandleValue vp, bool strict);
     static bool obj_setElement(JSContext *cx, HandleObject obj, uint32_t index,
                                MutableHandleValue vp, bool strict);
 
     static bool obj_getOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
                                              MutableHandle<JSPropertyDescriptor> desc);
 
-    static bool obj_getGenericAttributes(JSContext *cx, HandleObject obj,
-                                         HandleId id, unsigned *attrsp);
     static bool obj_setGenericAttributes(JSContext *cx, HandleObject obj,
                                          HandleId id, unsigned *attrsp);
 
     static bool obj_deleteGeneric(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded);
 
     static bool obj_enumerate(JSContext *cx, HandleObject obj, AutoIdVector &properties);
 
   public:
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2834,26 +2834,27 @@ GetPropertyDescriptorById(JSContext *cx,
         } else {
             desc.setAttributes(shape->attributes());
             desc.setGetter(shape->getter());
             desc.setSetter(shape->setter());
             MOZ_ASSERT(desc.value().isUndefined());
             if (shape->hasSlot())
                 desc.value().set(obj2->as<NativeObject>().getSlot(shape->slot()));
         }
-    } else {
-        if (obj2->is<ProxyObject>())
-            return Proxy::getPropertyDescriptor(cx, obj2, id, desc);
-        if (!GetPropertyAttributes(cx, obj2, id, &desc.attributesRef()))
-            return false;
-        MOZ_ASSERT(desc.getter() == nullptr);
-        MOZ_ASSERT(desc.setter() == nullptr);
-        MOZ_ASSERT(desc.value().isUndefined());
+
+        return true;
     }
-    return true;
+
+    // When we hit a proxy during lookup, the property might be
+    // on the prototype of the proxy, thus use getPropertyDescriptor.
+    if (obj2->is<ProxyObject>())
+        return Proxy::getPropertyDescriptor(cx, obj2, id, desc);
+
+    // Assume other non-natives (i.e. TypedObjects) behave in a sane way.
+    return GetOwnPropertyDescriptor(cx, obj2, id, desc);
 }
 
 JS_PUBLIC_API(bool)
 JS_GetOwnPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id,
                                 MutableHandle<JSPropertyDescriptor> desc)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -306,17 +306,16 @@ namespace js {
             js::proxy_DefineElement,                                                    \
             js::proxy_GetGeneric,                                                       \
             js::proxy_GetProperty,                                                      \
             js::proxy_GetElement,                                                       \
             js::proxy_SetGeneric,                                                       \
             js::proxy_SetProperty,                                                      \
             js::proxy_SetElement,                                                       \
             js::proxy_GetOwnPropertyDescriptor,                                         \
-            js::proxy_GetGenericAttributes,                                             \
             js::proxy_SetGenericAttributes,                                             \
             js::proxy_DeleteGeneric,                                                    \
             js::proxy_Watch, js::proxy_Unwatch,                                         \
             js::proxy_GetElements,                                                      \
             nullptr,             /* enumerate       */                                  \
             nullptr,             /* thisObject      */                                  \
         }                                                                               \
     }
@@ -372,18 +371,16 @@ proxy_SetProperty(JSContext *cx, JS::Han
                   JS::MutableHandleValue bp, bool strict);
 extern JS_FRIEND_API(bool)
 proxy_SetElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp,
                  bool strict);
 extern JS_FRIEND_API(bool)
 proxy_GetOwnPropertyDescriptor(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                                JS::MutableHandle<JSPropertyDescriptor> desc);
 extern JS_FRIEND_API(bool)
-proxy_GetGenericAttributes(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned *attrsp);
-extern JS_FRIEND_API(bool)
 proxy_SetGenericAttributes(JSContext *cx, JS::HandleObject obj, JS::HandleId id, unsigned *attrsp);
 extern JS_FRIEND_API(bool)
 proxy_DeleteGeneric(JSContext *cx, JS::HandleObject obj, JS::HandleId id, bool *succeeded);
 
 extern JS_FRIEND_API(void)
 proxy_Trace(JSTracer *trc, JSObject *obj);
 extern JS_FRIEND_API(JSObject *)
 proxy_WeakmapKeyDelegate(JSObject *obj);
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -1161,38 +1161,33 @@ SuppressDeletedPropertyHelper(JSContext 
                     /*
                      * Check whether another property along the prototype chain
                      * became visible as a result of this deletion.
                      */
                     RootedObject proto(cx);
                     if (!GetPrototype(cx, obj, &proto))
                         return false;
                     if (proto) {
-                        RootedObject obj2(cx);
-                        RootedShape prop(cx);
                         RootedId id(cx);
                         RootedValue idv(cx, StringValue(*idp));
                         if (!ValueToId<CanGC>(cx, idv, &id))
                             return false;
-                        if (!LookupProperty(cx, proto, id, &obj2, &prop))
+
+                        Rooted<PropertyDescriptor> desc(cx);
+                        if (!JS_GetPropertyDescriptorById(cx, proto, id, &desc))
                             return false;
-                        if (prop) {
-                            unsigned attrs;
-                            if (obj2->isNative())
-                                attrs = GetShapeAttributes(obj2, prop);
-                            else if (!GetPropertyAttributes(cx, obj2, id, &attrs))
-                                return false;
 
-                            if (attrs & JSPROP_ENUMERATE)
+                        if (desc.object()) {
+                            if (desc.isEnumerable())
                                 continue;
                         }
                     }
 
                     /*
-                     * If lookupProperty or getAttributes above removed a property from
+                     * If JS_GetPropertyDescriptorById above removed a property from
                      * ni, start over.
                      */
                     if (props_end != ni->props_end || props_cursor != ni->props_cursor)
                         goto again;
 
                     /*
                      * No property along the prototype chain stepped in to take the
                      * property's place, so go ahead and delete id from the list.
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -1072,23 +1072,27 @@ js::SetIntegrityLevel(JSContext *cx, Han
             if (!last)
                 return false;
         }
 
         MOZ_ASSERT(nobj->lastProperty()->slotSpan() == last->slotSpan());
         JS_ALWAYS_TRUE(NativeObject::setLastProperty(cx, nobj, last));
     } else {
         RootedId id(cx);
+        Rooted<PropertyDescriptor> desc(cx);
         for (size_t i = 0; i < keys.length(); i++) {
             id = keys[i];
 
-            unsigned attrs;
-            if (!GetPropertyAttributes(cx, obj, id, &attrs))
+            if (!GetOwnPropertyDescriptor(cx, obj, id, &desc))
                 return false;
 
+            if (!desc.object())
+                continue;
+
+            unsigned attrs = desc.attributes();
             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 (!SetPropertyAttributes(cx, obj, id, &attrs))
@@ -1142,29 +1146,31 @@ js::TestIntegrityLevel(JSContext *cx, Ha
     // 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);
+    Rooted<PropertyDescriptor> desc(cx);
     for (size_t i = 0, len = props.length(); i < len; i++) {
         id = props[i];
 
-        unsigned attrs;
-        if (!GetPropertyAttributes(cx, obj, id, &attrs))
+        if (!GetOwnPropertyDescriptor(cx, obj, id, &desc))
             return false;
 
+        if (!desc.object())
+            continue;
+
         // 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) ||
-            (level == IntegrityLevel::Frozen &&
-             !(attrs & (JSPROP_READONLY | JSPROP_GETTER | JSPROP_SETTER))))
+        if (!desc.isPermanent() ||
+            (level == IntegrityLevel::Frozen && desc.isDataDescriptor() && desc.isWritable()))
         {
             *result = false;
             return true;
         }
     }
 
     // All properties checked out. This object is sealed/frozen.
     *result = true;
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -945,23 +945,16 @@ LookupProperty(JSContext *cx, HandleObje
     return LookupProperty(cx, obj, id, objp, propp);
 }
 
 /* Set *result to tell whether obj has an own property with the given id. */
 extern bool
 HasOwnProperty(JSContext *cx, HandleObject obj, HandleId id, bool *result);
 
 /*
- * Deprecated. An easier-to-use version of LookupProperty that returns only the
- * property attributes.
- */
-inline bool
-GetPropertyAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp);
-
-/*
  * Deprecated. Search the prototype chain for `obj[id]` and redefine it to have
  * the given property attributes.
  */
 inline bool
 SetPropertyAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp);
 
 /*
  * Set a watchpoint: a synchronous callback when the given property of the
--- a/js/src/proxy/Proxy.cpp
+++ b/js/src/proxy/Proxy.cpp
@@ -670,26 +670,16 @@ js::proxy_SetElement(JSContext *cx, Hand
 bool
 js::proxy_GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
                                    MutableHandle<JSPropertyDescriptor> desc)
 {
     return Proxy::getOwnPropertyDescriptor(cx, obj, id, desc);
 }
 
 bool
-js::proxy_GetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
-{
-    Rooted<PropertyDescriptor> desc(cx);
-    if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, &desc))
-        return false;
-    *attrsp = desc.attributes();
-    return true;
-}
-
-bool
 js::proxy_SetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
     /* Lookup the current property descriptor so we have setter/getter/value. */
     Rooted<PropertyDescriptor> desc(cx);
     if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, &desc))
         return false;
     desc.setAttributes(*attrsp);
     return Proxy::defineProperty(cx, obj, id, &desc);
--- a/js/src/vm/ArgumentsObject.cpp
+++ b/js/src/vm/ArgumentsObject.cpp
@@ -320,19 +320,21 @@ ArgGetter(JSContext *cx, HandleObject ob
 
 static bool
 ArgSetter(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
 {
     if (!obj->is<NormalArgumentsObject>())
         return true;
     Handle<NormalArgumentsObject*> argsobj = obj.as<NormalArgumentsObject>();
 
-    unsigned attrs;
-    if (!NativeGetPropertyAttributes(cx, argsobj, id, &attrs))
+    Rooted<PropertyDescriptor> desc(cx);
+    if (!GetOwnPropertyDescriptor(cx, argsobj, id, &desc))
         return false;
+    MOZ_ASSERT(desc.object());
+    unsigned attrs = desc.attributes();
     MOZ_ASSERT(!(attrs & JSPROP_READONLY));
     attrs &= (JSPROP_ENUMERATE | JSPROP_PERMANENT); /* only valid attributes */
 
     RootedScript script(cx, argsobj->containingScript());
 
     if (JSID_IS_INT(id)) {
         unsigned arg = unsigned(JSID_TO_INT(id));
         if (arg < argsobj->initialLength() && !argsobj->isElementDeleted(arg)) {
@@ -439,19 +441,21 @@ StrictArgGetter(JSContext *cx, HandleObj
 
 static bool
 StrictArgSetter(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
 {
     if (!obj->is<StrictArgumentsObject>())
         return true;
     Handle<StrictArgumentsObject*> argsobj = obj.as<StrictArgumentsObject>();
 
-    unsigned attrs;
-    if (!NativeGetPropertyAttributes(cx, argsobj, id, &attrs))
+    Rooted<PropertyDescriptor> desc(cx);
+    if (!GetOwnPropertyDescriptor(cx, argsobj, id, &desc))
         return false;
+    MOZ_ASSERT(desc.object());
+    unsigned attrs = desc.attributes();
     MOZ_ASSERT(!(attrs & JSPROP_READONLY));
     attrs &= (JSPROP_ENUMERATE | JSPROP_PERMANENT); /* only valid attributes */
 
     if (JSID_IS_INT(id)) {
         unsigned arg = unsigned(JSID_TO_INT(id));
         if (arg < argsobj->initialLength()) {
             argsobj->setElement(cx, arg, vp);
             return true;
--- a/js/src/vm/Interpreter-inl.h
+++ b/js/src/vm/Interpreter-inl.h
@@ -344,29 +344,27 @@ DefVarOrConstOperation(JSContext *cx, Ha
     if (!prop || (obj2 != varobj && varobj->is<GlobalObject>())) {
         if (!DefineProperty(cx, varobj, dn, UndefinedHandleValue, nullptr, nullptr, attrs))
             return false;
     } else if (attrs & JSPROP_READONLY) {
         /*
          * Extension: ordinarily we'd be done here -- but for |const|.  If we
          * see a redeclaration that's |const|, we consider it a conflict.
          */
-        unsigned oldAttrs;
         RootedId id(cx, NameToId(dn));
-        if (!GetPropertyAttributes(cx, varobj, id, &oldAttrs))
+        Rooted<PropertyDescriptor> desc(cx);
+        if (!GetOwnPropertyDescriptor(cx, obj2, id, &desc))
             return false;
 
         JSAutoByteString bytes;
         if (AtomToPrintableString(cx, dn, &bytes)) {
             JS_ALWAYS_FALSE(JS_ReportErrorFlagsAndNumber(cx, JSREPORT_ERROR,
                                                          js_GetErrorMessage,
                                                          nullptr, JSMSG_REDECLARED_VAR,
-                                                         (oldAttrs & JSPROP_READONLY)
-                                                         ? "const"
-                                                         : "var",
+                                                         desc.isReadonly() ? "const" : "var",
                                                          bytes.ptr()));
         }
         return false;
     }
 
     return true;
 }
 
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -2124,34 +2124,16 @@ js::NativeSetElement(JSContext *cx, Hand
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
         return false;
     return NativeSetProperty(cx, obj, receiver, id, Qualified, vp, strict);
 }
 
 bool
-js::NativeGetPropertyAttributes(JSContext *cx, HandleNativeObject obj, HandleId id, unsigned *attrsp)
-{
-    RootedObject nobj(cx);
-    RootedShape shape(cx);
-    if (!NativeLookupProperty<CanGC>(cx, obj, id, &nobj, &shape))
-        return false;
-    if (!shape) {
-        *attrsp = 0;
-        return true;
-    }
-    if (!nobj->isNative())
-        return GetPropertyAttributes(cx, nobj, id, attrsp);
-
-    *attrsp = GetShapeAttributes(nobj, shape);
-    return true;
-}
-
-bool
 js::NativeSetPropertyAttributes(JSContext *cx, HandleNativeObject obj, HandleId id,
                                 unsigned *attrsp)
 {
     RootedObject nobj(cx);
     RootedShape shape(cx);
     if (!NativeLookupProperty<CanGC>(cx, obj, id, &nobj, &shape))
         return false;
     if (!shape)
--- a/js/src/vm/NativeObject.h
+++ b/js/src/vm/NativeObject.h
@@ -1322,19 +1322,16 @@ extern bool
 NativeLookupElement(JSContext *cx, HandleNativeObject obj, uint32_t index,
                     MutableHandleObject objp, MutableHandleShape propp);
 
 extern bool
 NativeGetExistingProperty(JSContext *cx, HandleObject obj, HandleNativeObject pobj,
                           HandleShape shape, MutableHandle<Value> vp);
 
 extern bool
-NativeGetPropertyAttributes(JSContext *cx, HandleNativeObject obj, HandleId id, unsigned *attrsp);
-
-extern bool
 NativeSetPropertyAttributes(JSContext *cx, HandleNativeObject obj, HandleId id, unsigned *attrsp);
 
 
 /* * */
 
 /*
  * If obj has an already-resolved data property for id, return true and
  * store the property value in *vp.
@@ -1399,17 +1396,9 @@ inline bool
 js::SetElement(JSContext *cx, HandleObject obj, HandleObject receiver, uint32_t index,
                MutableHandleValue vp, bool strict)
 {
     if (obj->getOps()->setElement)
         return JSObject::nonNativeSetElement(cx, obj, receiver, index, vp, strict);
     return NativeSetElement(cx, obj.as<NativeObject>(), receiver, index, vp, strict);
 }
 
-inline bool
-js::GetPropertyAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
-{
-    if (GenericAttributesOp op = obj->getOps()->getGenericAttributes)
-        return op(cx, obj, id, attrsp);
-    return NativeGetPropertyAttributes(cx, obj.as<NativeObject>(), id, attrsp);
-}
-
 #endif /* vm_NativeObject_h */
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -566,23 +566,16 @@ static bool
 with_GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
                               MutableHandle<JSPropertyDescriptor> desc)
 {
     RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
     return GetOwnPropertyDescriptor(cx, actual, id, desc);
 }
 
 static bool
-with_GetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
-{
-    RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
-    return GetPropertyAttributes(cx, actual, id, attrsp);
-}
-
-static bool
 with_SetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
     RootedObject actual(cx, &obj->as<DynamicWithObject>().object());
     return SetPropertyAttributes(cx, actual, id, attrsp);
 }
 
 static bool
 with_DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded)
@@ -631,17 +624,16 @@ const Class DynamicWithObject::class_ = 
         with_DefineElement,
         with_GetGeneric,
         with_GetProperty,
         with_GetElement,
         with_SetGeneric,
         with_SetProperty,
         with_SetElement,
         with_GetOwnPropertyDescriptor,
-        with_GetGenericAttributes,
         with_SetGenericAttributes,
         with_DeleteGeneric,
         nullptr, nullptr,    /* watch/unwatch */
         nullptr,             /* getElements */
         nullptr,             /* enumerate (native enumeration of target doesn't work) */
         with_ThisObject,
     }
 };
@@ -1077,23 +1069,16 @@ static bool
 uninitialized_GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
                                        MutableHandle<JSPropertyDescriptor> desc)
 {
     ReportUninitializedLexicalId(cx, id);
     return false;
 }
 
 static bool
-uninitialized_GetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
-{
-    ReportUninitializedLexicalId(cx, id);
-    return false;
-}
-
-static bool
 uninitialized_SetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
     ReportUninitializedLexicalId(cx, id);
     return false;
 }
 
 static bool
 uninitialized_DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, bool *succeeded)
@@ -1129,17 +1114,16 @@ const Class UninitializedLexicalObject::
         nullptr,             /* defineElement */
         uninitialized_GetGeneric,
         uninitialized_GetProperty,
         uninitialized_GetElement,
         uninitialized_SetGeneric,
         uninitialized_SetProperty,
         uninitialized_SetElement,
         uninitialized_GetOwnPropertyDescriptor,
-        uninitialized_GetGenericAttributes,
         uninitialized_SetGenericAttributes,
         uninitialized_DeleteGeneric,
         nullptr, nullptr,    /* watch/unwatch */
         nullptr,             /* getElements */
         nullptr,             /* enumerate (native enumeration of target doesn't work) */
         nullptr,             /* this */
     }
 };
--- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp
@@ -689,17 +689,16 @@ const XPCWrappedNativeJSClass XPC_WN_NoH
         nullptr, // defineElement
         nullptr, // getGeneric
         nullptr, // getProperty
         nullptr, // getElement
         nullptr, // setGeneric
         nullptr, // setProperty
         nullptr, // setElement
         nullptr, // getOwnPropertyDescriptor
-        nullptr, // getGenericAttributes
         nullptr, // setGenericAttributes
         nullptr, // deleteGeneric
         nullptr, nullptr, // watch/unwatch
         nullptr, // getElements
         nullptr, // enumerate
         XPC_WN_JSOp_ThisObject,
     }
   }
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -981,17 +981,16 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS
         nullptr, /* defineElement */                                          \
         nullptr, /* getGeneric    */                                          \
         nullptr, /* getProperty    */                                         \
         nullptr, /* getElement    */                                          \
         nullptr, /* setGeneric    */                                          \
         nullptr, /* setProperty    */                                         \
         nullptr, /* setElement    */                                          \
         nullptr, /* getOwnPropertyDescriptor */                               \
-        nullptr, /* getGenericAttributes  */                                  \
         nullptr, /* setGenericAttributes  */                                  \
         nullptr, /* deleteGeneric */                                          \
         nullptr, nullptr, /* watch/unwatch */                                 \
         nullptr, /* getElements */                                            \
         nullptr, /* enumerate */                                              \
         XPC_WN_JSOp_ThisObject,                                               \
     }
 
@@ -1005,17 +1004,16 @@ XPC_WN_JSOp_ThisObject(JSContext *cx, JS
         nullptr, /* defineElement */                                          \
         nullptr, /* getGeneric    */                                          \
         nullptr, /* getProperty    */                                         \
         nullptr, /* getElement    */                                          \
         nullptr, /* setGeneric    */                                          \
         nullptr, /* setProperty    */                                         \
         nullptr, /* setElement    */                                          \
         nullptr, /* getOwnPropertyDescriptor */                               \
-        nullptr, /* getGenericAttributes  */                                  \
         nullptr, /* setGenericAttributes  */                                  \
         nullptr, /* deleteGeneric */                                          \
         nullptr, nullptr, /* watch/unwatch */                                 \
         nullptr, /* getElements */                                            \
         nullptr, /* enumerate */                                              \
         XPC_WN_JSOp_ThisObject,                                               \
     }