Bug 1133081, part 4 - Reimplement the remaining PropDesc methods and delete PropDesc. r=efaust.
authorJason Orendorff <jorendorff@mozilla.com>
Sat, 14 Feb 2015 07:37:13 -0600
changeset 233537 63dbcc4fd0f02324f31e55c69409d61bc10116c0
parent 233536 fd31041fe5d6fe0dca57841c0f055be2f8570a19
child 233538 c78a9d1273c5d4ddf7a804eab41a92ff90ce0ec5
push id14482
push userryanvm@gmail.com
push dateFri, 13 Mar 2015 20:14:13 +0000
treeherderb2g-inbound@d14bd865880c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersefaust
bugs1133081
milestone39.0a1
Bug 1133081, part 4 - Reimplement the remaining PropDesc methods and delete PropDesc. r=efaust.
js/src/builtin/Object.cpp
js/src/gc/RootMarking.cpp
js/src/jsapi.cpp
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/proxy/ScriptedDirectProxyHandler.cpp
js/src/proxy/ScriptedIndirectProxyHandler.cpp
js/src/vm/Debugger.cpp
js/src/vm/NativeObject.cpp
js/src/vm/PropDesc.h
js/src/vm/Shape.h
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -703,17 +703,17 @@ js::obj_getOwnPropertyDescriptor(JSConte
     // Steps 3-4.
     RootedId id(cx);
     if (!ValueToId<CanGC>(cx, args.get(1), &id))
         return false;
 
     // Steps 5-7.
     Rooted<PropertyDescriptor> desc(cx);
     return GetOwnPropertyDescriptor(cx, obj, id, &desc) &&
-           NewPropertyDescriptorObject(cx, desc, args.rval());
+           FromPropertyDescriptor(cx, desc, args.rval());
 }
 
 // ES6 draft rev27 (2014/08/24) 19.1.2.14 Object.keys(O)
 static bool
 obj_keys(JSContext *cx, unsigned argc, Value *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     return GetOwnPropertyKeys(cx, args, JSITER_OWNONLY);
--- a/js/src/gc/RootMarking.cpp
+++ b/js/src/gc/RootMarking.cpp
@@ -19,17 +19,16 @@
 #include "builtin/MapObject.h"
 #include "frontend/BytecodeCompiler.h"
 #include "gc/GCInternals.h"
 #include "gc/Marking.h"
 #include "jit/MacroAssembler.h"
 #include "js/HashTable.h"
 #include "vm/Debugger.h"
 #include "vm/JSONParser.h"
-#include "vm/PropDesc.h"
 
 #include "jsgcinlines.h"
 #include "jsobjinlines.h"
 
 using namespace js;
 using namespace js::gc;
 
 using mozilla::ArrayEnd;
@@ -51,22 +50,16 @@ MarkBindingsRoot(JSTracer *trc, Bindings
 }
 
 void
 MarkPropertyDescriptorRoot(JSTracer *trc, JSPropertyDescriptor *pd, const char *name)
 {
     pd->trace(trc);
 }
 
-void
-MarkPropDescRoot(JSTracer *trc, PropDesc *pd, const char *name)
-{
-    pd->trace(trc);
-}
-
 template <class T>
 static inline bool
 IgnoreExactRoot(T *thingp)
 {
     return false;
 }
 
 template <class T>
@@ -111,17 +104,16 @@ MarkExactStackRootsAcrossTypes(T context
     MarkExactStackRootList<JSScript *, MarkScriptRoot>(trc, context, "exact-script");
     MarkExactStackRootList<LazyScript *, MarkLazyScriptRoot>(trc, context, "exact-lazy-script");
     MarkExactStackRootList<jsid, MarkIdRoot>(trc, context, "exact-id");
     MarkExactStackRootList<Value, MarkValueRoot>(trc, context, "exact-value");
     MarkExactStackRootList<TypeSet::Type, TypeSet::MarkTypeRoot>(trc, context, "TypeSet::Type");
     MarkExactStackRootList<Bindings, MarkBindingsRoot>(trc, context, "Bindings");
     MarkExactStackRootList<JSPropertyDescriptor, MarkPropertyDescriptorRoot>(
         trc, context, "JSPropertyDescriptor");
-    MarkExactStackRootList<PropDesc, MarkPropDescRoot>(trc, context, "PropDesc");
 }
 
 static void
 MarkExactStackRoots(JSRuntime* rt, JSTracer *trc)
 {
     for (ContextIter cx(rt); !cx.done(); cx.next())
         MarkExactStackRootsAcrossTypes<JSContext*>(cx.get(), trc);
     MarkExactStackRootsAcrossTypes<PerThreadData*>(&rt->mainThread, trc);
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -2720,21 +2720,20 @@ JS_DefineProperties(JSContext *cx, Handl
 }
 
 JS_PUBLIC_API(bool)
 JS::ObjectToCompletePropertyDescriptor(JSContext *cx,
                                        HandleObject obj,
                                        HandleValue descObj,
                                        MutableHandle<JSPropertyDescriptor> desc)
 {
-    Rooted<PropDesc> d(cx);
-    if (!d.initialize(cx, descObj))
+    if (!ToPropertyDescriptor(cx, descObj, true, desc))
         return false;
-    d.complete();
-    d.populatePropertyDescriptor(obj, desc);
+    CompletePropertyDescriptor(desc);
+    desc.object().set(obj);
     return true;
 }
 
 JS_PUBLIC_API(bool)
 JS_GetOwnPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id,
                                 MutableHandle<JSPropertyDescriptor> desc)
 {
     AssertHeapIsIdle(cx);
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -470,45 +470,16 @@ JSCompartment::wrap(JSContext *cx, Mutab
     if (desc.hasSetterObject()) {
         if (!wrap(cx, desc.setterObject()))
             return false;
     }
 
     return wrap(cx, desc.value());
 }
 
-bool
-JSCompartment::wrap(JSContext *cx, MutableHandle<PropDesc> desc)
-{
-    if (desc.isUndefined())
-        return true;
-
-    JSCompartment *comp = cx->compartment();
-
-    if (desc.hasValue()) {
-        RootedValue value(cx, desc.value());
-        if (!comp->wrap(cx, &value))
-            return false;
-        desc.setValue(value);
-    }
-    if (desc.hasGet()) {
-        RootedValue get(cx, desc.getterValue());
-        if (!comp->wrap(cx, &get))
-            return false;
-        desc.setGetter(get);
-    }
-    if (desc.hasSet()) {
-        RootedValue set(cx, desc.setterValue());
-        if (!comp->wrap(cx, &set))
-            return false;
-        desc.setSetter(set);
-    }
-    return true;
-}
-
 /*
  * This method marks pointers that cross compartment boundaries. It is called in
  * per-zone GCs (since full GCs naturally follow pointers across compartments)
  * and when compacting to update cross-compartment pointers.
  */
 void
 JSCompartment::markCrossCompartmentWrappers(JSTracer *trc)
 {
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -343,17 +343,16 @@ struct JSCompartment
 
     inline bool wrap(JSContext *cx, JS::MutableHandleValue vp,
                      JS::HandleObject existing = js::NullPtr());
 
     bool wrap(JSContext *cx, js::MutableHandleString strp);
     bool wrap(JSContext *cx, JS::MutableHandleObject obj,
               JS::HandleObject existingArg = js::NullPtr());
     bool wrap(JSContext *cx, JS::MutableHandle<js::PropertyDescriptor> desc);
-    bool wrap(JSContext *cx, JS::MutableHandle<js::PropDesc> desc);
 
     template<typename T> bool wrap(JSContext *cx, JS::AutoVectorRooter<T> &vec) {
         for (size_t i = 0; i < vec.length(); ++i) {
             if (!wrap(cx, vec[i]))
                 return false;
         }
         return true;
     };
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -122,124 +122,66 @@ js::InformalValueTypeName(const Value &v
     if (v.isNull())
         return "null";
     if (v.isUndefined())
         return "undefined";
     return "value";
 }
 
 bool
-js::NewPropertyDescriptorObject(JSContext *cx, Handle<PropertyDescriptor> desc,
-                                MutableHandleValue vp)
+js::FromPropertyDescriptor(JSContext *cx, Handle<PropertyDescriptor> desc,
+                           MutableHandleValue vp)
 {
     if (!desc.object()) {
         vp.setUndefined();
         return true;
     }
 
-    Rooted<PropDesc> d(cx);
-    d.initFromPropertyDescriptor(desc);
-    RootedObject descObj(cx);
-    if (!d.makeObject(cx, &descObj))
-        return false;
-    vp.setObject(*descObj);
-    return true;
-}
-
-void
-PropDesc::initFromPropertyDescriptor(Handle<PropertyDescriptor> desc)
-{
-    MOZ_ASSERT(isUndefined());
-
-    isUndefined_ = false;
-    attrs = uint8_t(desc.attributes());
-    MOZ_ASSERT_IF(attrs & JSPROP_READONLY, !(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
-    if (desc.hasGetterOrSetterObject()) {
-        hasGet_ = desc.hasGetterObject();
-        get_ = hasGet_ && desc.getterObject()
-               ? ObjectValue(*desc.getterObject())
-               : UndefinedValue();
-        hasSet_ = desc.hasSetterObject();
-        set_ = hasSet_ && desc.setterObject()
-               ? ObjectValue(*desc.setterObject())
-               : UndefinedValue();
-        hasValue_ = false;
-        value_.setUndefined();
-        hasWritable_ = false;
-    } else {
-        hasGet_ = false;
-        get_.setUndefined();
-        hasSet_ = false;
-        set_.setUndefined();
-        hasValue_ = !(desc.attributes() & JSPROP_IGNORE_VALUE);
-        value_ = hasValue_ ? desc.value() : UndefinedValue();
-        hasWritable_ = !(desc.attributes() & JSPROP_IGNORE_READONLY);
-    }
-    hasEnumerable_ = !(desc.attributes() & JSPROP_IGNORE_ENUMERATE);
-    hasConfigurable_ = !(desc.attributes() & JSPROP_IGNORE_PERMANENT);
-}
-
-void
-PropDesc::populatePropertyDescriptor(HandleObject obj, MutableHandle<PropertyDescriptor> desc) const
-{
-    if (isUndefined()) {
-        desc.object().set(nullptr);
-        return;
-    }
-
-    desc.value().set(hasValue() ? value() : UndefinedValue());
-    desc.setGetter(getter());
-    desc.setSetter(setter());
-
-    // Make sure we honor the "has" notions in some way.
-    unsigned attrs = attributes();
-    if (!hasEnumerable())
-        attrs |= JSPROP_IGNORE_ENUMERATE;
-    if (!hasConfigurable())
-        attrs |= JSPROP_IGNORE_PERMANENT;
-    if (!isAccessorDescriptor()) {
-        if (!hasWritable())
-            attrs |= JSPROP_IGNORE_READONLY;
-        if (!hasValue())
-            attrs |= JSPROP_IGNORE_VALUE;
-    }
-    desc.setAttributes(attrs);
-
-    desc.object().set(obj);
-}
-
-bool
-PropDesc::makeObject(JSContext *cx, MutableHandleObject obj)
-{
-    MOZ_ASSERT(!isUndefined());
-
-    obj.set(NewBuiltinClassInstance<PlainObject>(cx));
+    RootedObject obj(cx, NewBuiltinClassInstance<PlainObject>(cx));
     if (!obj)
         return false;
 
     const JSAtomState &names = cx->names();
-    RootedValue configurableVal(cx, BooleanValue((attrs & JSPROP_PERMANENT) == 0));
-    RootedValue enumerableVal(cx, BooleanValue((attrs & JSPROP_ENUMERATE) != 0));
-    RootedValue writableVal(cx, BooleanValue((attrs & JSPROP_READONLY) == 0));
-    if ((hasConfigurable() &&
-         !DefineProperty(cx, obj, names.configurable, configurableVal)) ||
-        (hasEnumerable() &&
-         !DefineProperty(cx, obj, names.enumerable, enumerableVal)) ||
-        (hasGet() &&
-         !DefineProperty(cx, obj, names.get, getterValue())) ||
-        (hasSet() &&
-         !DefineProperty(cx, obj, names.set, setterValue())) ||
-        (hasValue() &&
-         !DefineProperty(cx, obj, names.value, value())) ||
-        (hasWritable() &&
-         !DefineProperty(cx, obj, names.writable, writableVal)))
-    {
-        return false;
+    RootedValue v(cx);
+    if (desc.hasConfigurable()) {
+        v.setBoolean(desc.configurable());
+        if (!DefineProperty(cx, obj, names.configurable, v))
+            return false;
+    }
+    if (desc.hasEnumerable()) {
+        v.setBoolean(desc.enumerable());
+        if (!DefineProperty(cx, obj, names.enumerable, v))
+            return false;
+    }
+    if (desc.hasValue()) {
+        if (!DefineProperty(cx, obj, names.value, desc.value()))
+            return false;
     }
-
+    if (desc.hasWritable()) {
+        v.setBoolean(desc.writable());
+        if (!DefineProperty(cx, obj, names.writable, v))
+            return false;
+    }
+    if (desc.hasGetterObject()) {
+        if (JSObject *get = desc.getterObject())
+            v.setObject(*get);
+        else
+            v.setUndefined();
+        if (!DefineProperty(cx, obj, names.get, v))
+            return false;
+    }
+    if (desc.hasSetterObject()) {
+        if (JSObject *set = desc.setterObject())
+            v.setObject(*set);
+        else
+            v.setUndefined();
+        if (!DefineProperty(cx, obj, names.set, v))
+            return false;
+    }
+    vp.setObject(*obj);
     return true;
 }
 
 bool
 js::GetFirstArgumentAsObject(JSContext *cx, const CallArgs &args, const char *method,
                              MutableHandleObject objp)
 {
     if (args.length() == 0) {
@@ -273,163 +215,16 @@ GetPropertyIfPresent(JSContext *cx, Hand
         vp.setUndefined();
         return true;
     }
 
     return GetProperty(cx, obj, obj, id, vp);
 }
 
 bool
-PropDesc::initialize(JSContext *cx, const Value &origval, bool checkAccessors)
-{
-    MOZ_ASSERT(isUndefined());
-
-    RootedValue v(cx, origval);
-
-    /* 8.10.5 step 1 */
-    if (v.isPrimitive()) {
-        UniquePtr<char[], JS::FreePolicy> bytes =
-            DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, v, NullPtr());
-        if (!bytes)
-            return false;
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT, bytes.get());
-        return false;
-    }
-    RootedObject desc(cx, &v.toObject());
-
-    isUndefined_ = false;
-
-    attrs = 0;
-
-    bool found = false;
-    RootedId id(cx);
-
-    /* 8.10.5 step 3 */
-    id = NameToId(cx->names().enumerable);
-    if (!GetPropertyIfPresent(cx, desc, id, &v, &found))
-        return false;
-    if (found) {
-        hasEnumerable_ = true;
-        if (ToBoolean(v))
-            attrs |= JSPROP_ENUMERATE;
-    }
-
-    /* 8.10.5 step 4 */
-    id = NameToId(cx->names().configurable);
-    if (!GetPropertyIfPresent(cx, desc, id, &v, &found))
-        return false;
-    if (found) {
-        hasConfigurable_ = true;
-        if (!ToBoolean(v))
-            attrs |= JSPROP_PERMANENT;
-    }
-
-    /* 8.10.5 step 5 */
-    id = NameToId(cx->names().value);
-    if (!GetPropertyIfPresent(cx, desc, id, &v, &found))
-        return false;
-    if (found) {
-        hasValue_ = true;
-        value_ = v;
-    }
-
-    /* 8.10.6 step 6 */
-    id = NameToId(cx->names().writable);
-    if (!GetPropertyIfPresent(cx, desc, id, &v, &found))
-        return false;
-    if (found) {
-        hasWritable_ = true;
-        if (!ToBoolean(v))
-            attrs |= JSPROP_READONLY;
-    }
-
-    /* 8.10.7 step 7 */
-    id = NameToId(cx->names().get);
-    if (!GetPropertyIfPresent(cx, desc, id, &v, &found))
-        return false;
-    if (found) {
-        // Enforce the rule that getters and setters must be objects, even if
-        // checkAccessors is false, because JSPropertyDescriptor's getter and
-        // setter fields can't hold arbitrary Values.
-        if (!v.isObject() && !v.isUndefined()) {
-            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_GET_SET_FIELD,
-                                 js_getter_str);
-            return false;
-        }
-        hasGet_ = true;
-        get_ = v;
-        attrs |= JSPROP_GETTER | JSPROP_SHARED;
-        if (checkAccessors && !checkGetter(cx))
-            return false;
-    }
-
-    /* 8.10.7 step 8 */
-    id = NameToId(cx->names().set);
-    if (!GetPropertyIfPresent(cx, desc, id, &v, &found))
-        return false;
-    if (found) {
-        // See comment above.
-        if (!v.isObject() && !v.isUndefined()) {
-            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_GET_SET_FIELD,
-                                 js_setter_str);
-            return false;
-        }
-        hasSet_ = true;
-        set_ = v;
-        attrs |= JSPROP_SETTER | JSPROP_SHARED;
-        if (checkAccessors && !checkSetter(cx))
-            return false;
-    }
-
-    /* 8.10.7 step 9 */
-    if ((hasGet() || hasSet()) && (hasValue() || hasWritable())) {
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INVALID_DESCRIPTOR);
-        return false;
-    }
-
-    MOZ_ASSERT_IF(attrs & JSPROP_READONLY, !(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
-
-    return true;
-}
-
-void
-PropDesc::complete()
-{
-    MOZ_ASSERT(!isUndefined());
-
-    if (isGenericDescriptor() || isDataDescriptor()) {
-        if (!hasValue_) {
-            hasValue_ = true;
-            value_.setUndefined();
-        }
-        if (!hasWritable_) {
-            hasWritable_ = true;
-            attrs |= JSPROP_READONLY;
-        }
-    } else {
-        if (!hasGet_) {
-            hasGet_ = true;
-            get_.setUndefined();
-        }
-        if (!hasSet_) {
-            hasSet_ = true;
-            set_.setUndefined();
-        }
-    }
-    if (!hasEnumerable_) {
-        hasEnumerable_ = true;
-        attrs &= ~JSPROP_ENUMERATE;
-    }
-    if (!hasConfigurable_) {
-        hasConfigurable_ = true;
-        attrs |= JSPROP_PERMANENT;
-    }
-}
-
-bool
 js::Throw(JSContext *cx, jsid id, unsigned errorNumber)
 {
     MOZ_ASSERT(js_ErrorFormatString[errorNumber].argCount == 1);
 
     RootedValue idVal(cx, IdToValue(id));
     JSString *idstr = ValueToSource(cx, idVal);
     if (!idstr)
        return false;
@@ -907,38 +702,152 @@ js::StandardDefineProperty(JSContext *cx
                            Handle<PropertyDescriptor> desc)
 {
     ObjectOpResult success;
     return StandardDefineProperty(cx, obj, id, desc, success) &&
            success.checkStrict(cx, obj, id);
 }
 
 bool
-js::ToPropertyDescriptor(JSContext *cx, HandleValue v, bool checkAccessors,
+CheckCallable(JSContext *cx, JSObject *obj, const char *fieldName)
+{
+    if (obj && !obj->isCallable()) {
+        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_GET_SET_FIELD,
+                             fieldName);
+        return false;
+    }
+    return true;
+}
+
+bool
+js::ToPropertyDescriptor(JSContext *cx, HandleValue descval, bool checkAccessors,
                          MutableHandle<PropertyDescriptor> desc)
 {
-    Rooted<PropDesc> pd(cx);
-    if (!pd.initialize(cx, v, checkAccessors))
+    // step 2
+    if (!descval.isObject()) {
+        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT,
+                             InformalValueTypeName(descval));
+        return false;
+    }
+    RootedObject obj(cx, &descval.toObject());
+
+    // step 3
+    desc.clear();
+
+    bool found = false;
+    RootedId id(cx);
+    RootedValue v(cx);
+    unsigned attrs = 0;
+
+    // step 4
+    id = NameToId(cx->names().enumerable);
+    if (!GetPropertyIfPresent(cx, obj, id, &v, &found))
+        return false;
+    if (found) {
+        if (ToBoolean(v))
+            attrs |= JSPROP_ENUMERATE;
+    } else {
+        attrs |= JSPROP_IGNORE_ENUMERATE;
+    }
+
+    // step 5
+    id = NameToId(cx->names().configurable);
+    if (!GetPropertyIfPresent(cx, obj, id, &v, &found))
+        return false;
+    if (found) {
+        if (!ToBoolean(v))
+            attrs |= JSPROP_PERMANENT;
+    } else {
+        attrs |= JSPROP_IGNORE_PERMANENT;
+    }
+
+    // step 6
+    id = NameToId(cx->names().value);
+    if (!GetPropertyIfPresent(cx, obj, id, &v, &found))
+        return false;
+    if (found)
+        desc.value().set(v);
+    else
+        attrs |= JSPROP_IGNORE_VALUE;
+
+    // step 7
+    id = NameToId(cx->names().writable);
+    if (!GetPropertyIfPresent(cx, obj, id, &v, &found))
         return false;
-    pd.populatePropertyDescriptor(NullPtr(), desc);
+    if (found) {
+        if (!ToBoolean(v))
+            attrs |= JSPROP_READONLY;
+    } else {
+        attrs |= JSPROP_IGNORE_READONLY;
+    }
+
+    // step 8
+    bool hasGetOrSet;
+    id = NameToId(cx->names().get);
+    if (!GetPropertyIfPresent(cx, obj, id, &v, &found))
+        return false;
+    hasGetOrSet = found;
+    if (found) {
+        if (v.isObject()) {
+            if (checkAccessors && !CheckCallable(cx, &v.toObject(), js_getter_str))
+                return false;
+            desc.setGetterObject(&v.toObject());
+        } else if (!v.isUndefined()) {
+            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_GET_SET_FIELD,
+                                 js_getter_str);
+            return false;
+        }
+        attrs |= JSPROP_GETTER | JSPROP_SHARED;
+    }
+
+    // step 9
+    id = NameToId(cx->names().set);
+    if (!GetPropertyIfPresent(cx, obj, id, &v, &found))
+        return false;
+    hasGetOrSet |= found;
+    if (found) {
+        if (v.isObject()) {
+            if (checkAccessors && !CheckCallable(cx, &v.toObject(), js_setter_str))
+                return false;
+            desc.setSetterObject(&v.toObject());
+        } else if (!v.isUndefined()) {
+            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_GET_SET_FIELD,
+                                 js_setter_str);
+            return false;
+        }
+        attrs |= JSPROP_SETTER | JSPROP_SHARED;
+    }
+
+    // step 10
+    if (hasGetOrSet) {
+        if (!(attrs & JSPROP_IGNORE_READONLY) || !(attrs & JSPROP_IGNORE_VALUE)) {
+            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INVALID_DESCRIPTOR);
+            return false;
+        }
+
+        // By convention, these bits are not used on accessor descriptors.
+        attrs &= ~(JSPROP_IGNORE_READONLY | JSPROP_IGNORE_VALUE);
+    }
+
+    desc.setAttributes(attrs);
+    MOZ_ASSERT_IF(attrs & JSPROP_READONLY, !(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
+    MOZ_ASSERT_IF(attrs & (JSPROP_GETTER | JSPROP_SETTER), attrs & JSPROP_SHARED);
     return true;
 }
 
 bool
 js::CheckPropertyDescriptorAccessors(JSContext *cx, Handle<PropertyDescriptor> desc)
 {
-    if (desc.hasGetterObject() && !IsCallable(desc.getterObject())) {
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_GET_SET_FIELD,
-                             js_getter_str);
-        return false;
+    if (desc.hasGetterObject()) {
+        if (!CheckCallable(cx, desc.getterObject(), js_getter_str))
+            return false;
     }
-    if (desc.hasSetterObject() && !IsCallable(desc.setterObject())) {
-        JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_GET_SET_FIELD,
-                             js_setter_str);
-        return false;
+    if (desc.hasSetterObject()) {
+        if (!CheckCallable(cx, desc.setterObject(), js_setter_str))
+            return false;
     }
     return true;
 }
 
 void
 js::CompletePropertyDescriptor(MutableHandle<PropertyDescriptor> desc)
 {
     if (desc.isGenericDescriptor() || desc.isDataDescriptor()) {
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -65,18 +65,16 @@ CastAsObjectJsval(GetterOp op)
 inline Value
 CastAsObjectJsval(SetterOp op)
 {
     return ObjectOrNullValue(CastAsObject(op));
 }
 
 /******************************************************************************/
 
-typedef Vector<PropDesc, 1> PropDescArray;
-
 extern const Class IntlClass;
 extern const Class JSONClass;
 extern const Class MathClass;
 
 class GlobalObject;
 class MapObject;
 class NewObjectCache;
 class NormalArgumentsObject;
@@ -1138,19 +1136,31 @@ extern JSObject *
 CloneObject(JSContext *cx, HandleObject obj, Handle<js::TaggedProto> proto);
 
 extern JSObject *
 DeepCloneObjectLiteral(JSContext *cx, HandleObject obj, NewObjectKind newKind = GenericObject);
 
 extern bool
 DefineProperties(JSContext *cx, HandleObject obj, HandleObject props);
 
+inline JSGetterOp
+CastAsGetterOp(JSObject *object)
+{
+    return JS_DATA_TO_FUNC_PTR(JSGetterOp, object);
+}
+
+inline JSSetterOp
+CastAsSetterOp(JSObject *object)
+{
+    return JS_DATA_TO_FUNC_PTR(JSSetterOp, object);
+}
+
 /* ES6 draft rev 32 (2015 Feb 2) 6.2.4.5 ToPropertyDescriptor(Obj) */
 bool
-ToPropertyDescriptor(JSContext *cx, HandleValue v, bool checkAccessors,
+ToPropertyDescriptor(JSContext *cx, HandleValue descval, bool checkAccessors,
                      MutableHandle<PropertyDescriptor> desc);
 
 /*
  * Throw a TypeError if desc.getterObject() or setterObject() is not
  * callable. This performs exactly the checks omitted by ToPropertyDescriptor
  * when checkAccessors is false.
  */
 bool
@@ -1215,18 +1225,19 @@ GetPropertyPure(ExclusiveContext *cx, JS
 
 bool
 GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
                          MutableHandle<PropertyDescriptor> desc);
 
 bool
 GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp);
 
+/* ES6 draft rev 32 (2015 Feb 2) 6.2.4.4 FromPropertyDescriptor(Desc) */
 bool
-NewPropertyDescriptorObject(JSContext *cx, Handle<PropertyDescriptor> desc, MutableHandleValue vp);
+FromPropertyDescriptor(JSContext *cx, Handle<PropertyDescriptor> desc, MutableHandleValue vp);
 
 extern bool
 IsDelegate(JSContext *cx, HandleObject obj, const Value &v, bool *result);
 
 // obj is a JSObject*, but we root it immediately up front. We do it
 // that way because we need a Rooted temporary in this method anyway.
 extern bool
 IsDelegateOfObject(JSContext *cx, HandleObject protoObj, JSObject* obj, bool *result);
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -415,31 +415,16 @@ JSObject::isNewGroupUnknown() const
 inline bool
 JSObject::wasNewScriptCleared() const
 {
     return hasAllFlags(js::BaseShape::NEW_SCRIPT_CLEARED);
 }
 
 namespace js {
 
-PropDesc::PropDesc(const Value &getter, const Value &setter,
-                   Enumerability enumerable, Configurability configurable)
-  : value_(UndefinedValue()),
-    get_(getter), set_(setter),
-    attrs(JSPROP_GETTER | JSPROP_SETTER | JSPROP_SHARED |
-          (enumerable ? JSPROP_ENUMERATE : 0) |
-          (configurable ? 0 : JSPROP_PERMANENT)),
-    hasGet_(true), hasSet_(true),
-    hasValue_(false), hasWritable_(false), hasEnumerable_(true), hasConfigurable_(true),
-    isUndefined_(false)
-{
-    MOZ_ASSERT(getter.isUndefined() || IsCallable(getter));
-    MOZ_ASSERT(setter.isUndefined() || IsCallable(setter));
-}
-
 static MOZ_ALWAYS_INLINE bool
 IsFunctionObject(const js::Value &v)
 {
     return v.isObject() && v.toObject().is<JSFunction>();
 }
 
 static MOZ_ALWAYS_INLINE bool
 IsFunctionObject(const js::Value &v, JSFunction **fun)
--- a/js/src/proxy/ScriptedDirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedDirectProxyHandler.cpp
@@ -3,18 +3,16 @@
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "proxy/ScriptedDirectProxyHandler.h"
 
 #include "jsapi.h"
 
-#include "vm/PropDesc.h"
-
 #include "jsobjinlines.h"
 
 using namespace js;
 using mozilla::ArrayLength;
 
 static inline bool
 IsDataDescriptor(const PropertyDescriptor &desc)
 {
@@ -570,17 +568,17 @@ ScriptedDirectProxyHandler::defineProper
         return false;
 
     // step 8
     if (trap.isUndefined())
         return DirectProxyHandler::defineProperty(cx, proxy, id, desc, result);
 
     // step 9
     RootedValue descObj(cx);
-    if (!NewPropertyDescriptorObject(cx, desc, &descObj))
+    if (!FromPropertyDescriptor(cx, desc, &descObj))
         return false;
 
     // steps 10-11
     RootedValue propKey(cx);
     if (!IdToStringOrSymbol(cx, id, &propKey))
         return false;
 
     Value argv[] = {
--- a/js/src/proxy/ScriptedIndirectProxyHandler.cpp
+++ b/js/src/proxy/ScriptedIndirectProxyHandler.cpp
@@ -197,17 +197,17 @@ ScriptedIndirectProxyHandler::getOwnProp
 bool
 ScriptedIndirectProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
                                              MutableHandle<PropertyDescriptor> desc,
                                              ObjectOpResult &result) const
 {
     RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
     RootedValue fval(cx), value(cx);
     return GetFundamentalTrap(cx, handler, cx->names().defineProperty, &fval) &&
-           NewPropertyDescriptorObject(cx, desc, &value) &&
+           FromPropertyDescriptor(cx, desc, &value) &&
            Trap2(cx, handler, fval, id, value, &value) &&
            result.succeed();
 }
 
 bool
 ScriptedIndirectProxyHandler::ownPropertyKeys(JSContext *cx, HandleObject proxy,
                                               AutoIdVector &props) const
 {
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -6683,17 +6683,17 @@ DebuggerObject_getOwnPropertyDescriptor(
         if (desc.hasSetterObject()) {
             RootedValue set(cx, ObjectOrNullValue(desc.setterObject()));
             if (!dbg->wrapDebuggeeValue(cx, &set))
                 return false;
             desc.setSetterObject(set.toObjectOrNull());
         }
     }
 
-    return NewPropertyDescriptorObject(cx, desc, args.rval());
+    return FromPropertyDescriptor(cx, desc, args.rval());
 }
 
 static bool
 DebuggerObject_getOwnPropertyNames(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGOBJECT_REFERENT(cx, argc, vp, "getOwnPropertyNames", args, obj);
 
     AutoIdVector keys(cx);
--- a/js/src/vm/NativeObject.cpp
+++ b/js/src/vm/NativeObject.cpp
@@ -21,64 +21,16 @@
 #include "vm/Shape-inl.h"
 
 using namespace js;
 
 using JS::GenericNaN;
 using mozilla::DebugOnly;
 using mozilla::RoundUpPow2;
 
-PropDesc::PropDesc()
-{
-    setUndefined();
-}
-
-void
-PropDesc::setUndefined()
-{
-    value_ = UndefinedValue();
-    get_ = UndefinedValue();
-    set_ = UndefinedValue();
-    attrs = 0;
-    hasGet_ = false;
-    hasSet_ = false;
-    hasValue_ = false;
-    hasWritable_ = false;
-    hasEnumerable_ = false;
-    hasConfigurable_ = false;
-
-    isUndefined_ = true;
-}
-
-bool
-PropDesc::checkGetter(JSContext *cx)
-{
-    if (hasGet_) {
-        if (!IsCallable(get_) && !get_.isUndefined()) {
-            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_GET_SET_FIELD,
-                                 js_getter_str);
-            return false;
-        }
-    }
-    return true;
-}
-
-bool
-PropDesc::checkSetter(JSContext *cx)
-{
-    if (hasSet_) {
-        if (!IsCallable(set_) && !set_.isUndefined()) {
-            JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_BAD_GET_SET_FIELD,
-                                 js_setter_str);
-            return false;
-        }
-    }
-    return true;
-}
-
 static const ObjectElements emptyElementsHeader(0, 0);
 
 /* Objects with no elements share one empty set of elements. */
 HeapSlot *const js::emptyObjectElements =
     reinterpret_cast<HeapSlot *>(uintptr_t(&emptyElementsHeader) + sizeof(ObjectElements));
 
 #ifdef DEBUG
 
@@ -283,24 +235,16 @@ js::NativeObject::dynamicSlotsCount(uint
     if (clasp != &ArrayObject::class_ && span <= SLOT_CAPACITY_MIN)
         return SLOT_CAPACITY_MIN;
 
     uint32_t slots = mozilla::RoundUpPow2(span);
     MOZ_ASSERT(slots >= span);
     return slots;
 }
 
-void
-PropDesc::trace(JSTracer *trc)
-{
-    gc::MarkValueRoot(trc, &value_, "PropDesc value");
-    gc::MarkValueRoot(trc, &get_, "PropDesc get");
-    gc::MarkValueRoot(trc, &set_, "PropDesc set");
-}
-
 inline bool
 NativeObject::updateSlotsForSpan(ExclusiveContext *cx, size_t oldSpan, size_t newSpan)
 {
     MOZ_ASSERT(oldSpan != newSpan);
 
     size_t oldCount = dynamicSlotsCount(numFixedSlots(), oldSpan, getClass());
     size_t newCount = dynamicSlotsCount(numFixedSlots(), newSpan, getClass());
 
--- a/js/src/vm/PropDesc.h
+++ b/js/src/vm/PropDesc.h
@@ -1,366 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- * vim: set ts=8 sts=4 et sw=4 tw=99:
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef vm_PropDesc_h
-#define vm_PropDesc_h
-
-#include "jsapi.h"
-#include "NamespaceImports.h"
-
-namespace js {
-
-static inline JSGetterOp
-CastAsGetterOp(JSObject *object)
-{
-    return JS_DATA_TO_FUNC_PTR(JSGetterOp, object);
-}
-
-static inline JSSetterOp
-CastAsSetterOp(JSObject *object)
-{
-    return JS_DATA_TO_FUNC_PTR(JSSetterOp, object);
-}
-
-/*
- * A representation of ECMA-262 ed. 5's internal Property Descriptor data
- * structure.
- */
-struct PropDesc {
-  private:
-    Value value_, get_, set_;
-
-    /* Property descriptor boolean fields. */
-    uint8_t attrs;
-
-    /* Bits indicating which values are set. */
-    bool hasGet_ : 1;
-    bool hasSet_ : 1;
-    bool hasValue_ : 1;
-    bool hasWritable_ : 1;
-    bool hasEnumerable_ : 1;
-    bool hasConfigurable_ : 1;
-
-    /* Or maybe this represents a property's absence, and it's undefined. */
-    bool isUndefined_ : 1;
-
-    explicit PropDesc(const Value &v)
-      : value_(v),
-        get_(UndefinedValue()), set_(UndefinedValue()),
-        attrs(0),
-        hasGet_(false), hasSet_(false),
-        hasValue_(true), hasWritable_(false), hasEnumerable_(false), hasConfigurable_(false),
-        isUndefined_(false)
-    {
-    }
-
-  public:
-    friend struct GCMethods<PropDesc>;
-
-    void trace(JSTracer *trc);
-    static ThingRootKind rootKind() { return THING_ROOT_PROP_DESC; }
-
-    enum Enumerability { Enumerable = true, NonEnumerable = false };
-    enum Configurability { Configurable = true, NonConfigurable = false };
-    enum Writability { Writable = true, NonWritable = false };
-
-    PropDesc();
-
-    static PropDesc undefined() { return PropDesc(); }
-    static PropDesc valueOnly(const Value &v) { return PropDesc(v); }
-
-    PropDesc(const Value &v, Writability writable,
-             Enumerability enumerable, Configurability configurable)
-      : value_(v),
-        get_(UndefinedValue()), set_(UndefinedValue()),
-        attrs((writable ? 0 : JSPROP_READONLY) |
-              (enumerable ? JSPROP_ENUMERATE : 0) |
-              (configurable ? 0 : JSPROP_PERMANENT)),
-        hasGet_(false), hasSet_(false),
-        hasValue_(true), hasWritable_(true), hasEnumerable_(true), hasConfigurable_(true),
-        isUndefined_(false)
-    {}
-
-    inline PropDesc(const Value &getter, const Value &setter,
-                    Enumerability enumerable, Configurability configurable);
-
-    /*
-     * 8.10.5 ToPropertyDescriptor(Obj)
-     *
-     * If checkAccessors is false, skip steps 7.b and 8.b, which throw a
-     * TypeError if .get or .set is neither a callable object nor undefined.
-     *
-     * (DebuggerObject_defineProperty uses this: the .get and .set properties
-     * are expected to be Debugger.Object wrappers of functions, which are not
-     * themselves callable.)
-     */
-    bool initialize(JSContext *cx, const Value &v, bool checkAccessors = true);
-
-    /*
-     * If IsGenericDescriptor(desc) or IsDataDescriptor(desc) is true, then if
-     * the value of an attribute field of desc, considered as a data
-     * descriptor, is absent, set it to its default value. Else if the value of
-     * an attribute field of desc, considered as an attribute descriptor, is
-     * absent, set it to its default value.
-     */
-    void complete();
-
-    /*
-     * 8.10.4 FromPropertyDescriptor(Desc)
-     *
-     * initFromPropertyDescriptor sets pd to undefined and populates all the
-     * other fields of this PropDesc from desc.
-     *
-     * makeObject populates pd based on the other fields of *this, creating a
-     * new property descriptor JSObject and defining properties on it.
-     */
-    void initFromPropertyDescriptor(Handle<JSPropertyDescriptor> desc);
-    void populatePropertyDescriptor(HandleObject obj, MutableHandle<JSPropertyDescriptor> desc) const;
-    bool makeObject(JSContext *cx, MutableHandleObject objp);
-
-    /* Reset the descriptor entirely. */
-    void setUndefined();
-    bool isUndefined() const { return isUndefined_; }
-
-    bool hasGet() const { MOZ_ASSERT(!isUndefined()); return hasGet_; }
-    bool hasSet() const { MOZ_ASSERT(!isUndefined()); return hasSet_; }
-    bool hasValue() const { MOZ_ASSERT(!isUndefined()); return hasValue_; }
-    bool hasWritable() const { MOZ_ASSERT(!isUndefined()); return hasWritable_; }
-    bool hasEnumerable() const { MOZ_ASSERT(!isUndefined()); return hasEnumerable_; }
-    bool hasConfigurable() const { MOZ_ASSERT(!isUndefined()); return hasConfigurable_; }
-
-    uint8_t attributes() const { MOZ_ASSERT(!isUndefined()); return attrs; }
-
-    /* 8.10.1 IsAccessorDescriptor(desc) */
-    bool isAccessorDescriptor() const {
-        return !isUndefined() && (hasGet() || hasSet());
-    }
-
-    /* 8.10.2 IsDataDescriptor(desc) */
-    bool isDataDescriptor() const {
-        return !isUndefined() && (hasValue() || hasWritable());
-    }
-
-    /* 8.10.3 IsGenericDescriptor(desc) */
-    bool isGenericDescriptor() const {
-        return !isUndefined() && !isAccessorDescriptor() && !isDataDescriptor();
-    }
-
-    bool configurable() const {
-        MOZ_ASSERT(!isUndefined());
-        MOZ_ASSERT(hasConfigurable());
-        return (attrs & JSPROP_PERMANENT) == 0;
-    }
-
-    bool enumerable() const {
-        MOZ_ASSERT(!isUndefined());
-        MOZ_ASSERT(hasEnumerable());
-        return (attrs & JSPROP_ENUMERATE) != 0;
-    }
-
-    bool writable() const {
-        MOZ_ASSERT(!isUndefined());
-        MOZ_ASSERT(hasWritable());
-        return (attrs & JSPROP_READONLY) == 0;
-    }
-
-    HandleValue value() const {
-        MOZ_ASSERT(hasValue());
-        return HandleValue::fromMarkedLocation(&value_);
-    }
-    void setValue(const Value &value) {
-        MOZ_ASSERT(!isUndefined());
-        value_ = value;
-        hasValue_ = true;
-    }
-
-    JSObject * getterObject() const {
-        MOZ_ASSERT(!isUndefined());
-        MOZ_ASSERT(hasGet());
-        return get_.isUndefined() ? nullptr : &get_.toObject();
-    }
-    JSObject * setterObject() const {
-        MOZ_ASSERT(!isUndefined());
-        MOZ_ASSERT(hasSet());
-        return set_.isUndefined() ? nullptr : &set_.toObject();
-    }
-
-    HandleValue getterValue() const {
-        MOZ_ASSERT(!isUndefined());
-        MOZ_ASSERT(hasGet());
-        return HandleValue::fromMarkedLocation(&get_);
-    }
-    HandleValue setterValue() const {
-        MOZ_ASSERT(!isUndefined());
-        MOZ_ASSERT(hasSet());
-        return HandleValue::fromMarkedLocation(&set_);
-    }
-
-    void setGetter(const Value &getter) {
-        MOZ_ASSERT(!isUndefined());
-        get_ = getter;
-        hasGet_ = true;
-    }
-    void setSetter(const Value &setter) {
-        MOZ_ASSERT(!isUndefined());
-        set_ = setter;
-        hasSet_ = true;
-    }
-
-    /*
-     * Unfortunately the values produced by these methods are used such that
-     * we can't assert anything here.  :-(
-     */
-    JSGetterOp getter() const {
-        return CastAsGetterOp(get_.isUndefined() ? nullptr : &get_.toObject());
-    }
-    JSSetterOp setter() const {
-        return CastAsSetterOp(set_.isUndefined() ? nullptr : &set_.toObject());
-    }
-
-    /*
-     * Throw a TypeError if a getter/setter is present and is neither callable
-     * nor undefined. These methods do exactly the type checks that are skipped
-     * by passing false as the checkAccessors parameter of initialize.
-     */
-    bool checkGetter(JSContext *cx);
-    bool checkSetter(JSContext *cx);
-};
-
-} /* namespace js */
-
-namespace JS {
-
-template <typename Outer>
-class PropDescOperations
-{
-    const js::PropDesc * desc() const { return static_cast<const Outer*>(this)->extract(); }
-
-  public:
-    bool isUndefined() const { return desc()->isUndefined(); }
-
-    bool hasGet() const { return desc()->hasGet(); }
-    bool hasSet() const { return desc()->hasSet(); }
-    bool hasValue() const { return desc()->hasValue(); }
-    bool hasWritable() const { return desc()->hasWritable(); }
-    bool hasEnumerable() const { return desc()->hasEnumerable(); }
-    bool hasConfigurable() const { return desc()->hasConfigurable(); }
-
-    uint8_t attributes() const { return desc()->attributes(); }
-
-    bool isAccessorDescriptor() const { return desc()->isAccessorDescriptor(); }
-    bool isDataDescriptor() const { return desc()->isDataDescriptor(); }
-    bool isGenericDescriptor() const { return desc()->isGenericDescriptor(); }
-    bool configurable() const { return desc()->configurable(); }
-    bool enumerable() const { return desc()->enumerable(); }
-    bool writable() const { return desc()->writable(); }
-
-    HandleValue value() const { return desc()->value(); }
-    JSObject *getterObject() const { return desc()->getterObject(); }
-    JSObject *setterObject() const { return desc()->setterObject(); }
-    HandleValue getterValue() const { return desc()->getterValue(); }
-    HandleValue setterValue() const { return desc()->setterValue(); }
-
-    JSGetterOp getter() const { return desc()->getter(); }
-    JSSetterOp setter() const { return desc()->setter(); }
-
-    void populatePropertyDescriptor(HandleObject obj,
-                                    MutableHandle<JSPropertyDescriptor> descriptor) const {
-        desc()->populatePropertyDescriptor(obj, descriptor);
-    }
-};
-
-template <typename Outer>
-class MutablePropDescOperations : public PropDescOperations<Outer>
-{
-    js::PropDesc * desc() { return static_cast<Outer*>(this)->extractMutable(); }
-
-  public:
-
-    bool initialize(JSContext *cx, const Value &v, bool checkAccessors = true) {
-        return desc()->initialize(cx, v, checkAccessors);
-    }
-    void complete() {
-        desc()->complete();
-    }
-
-    bool checkGetter(JSContext *cx) { return desc()->checkGetter(cx); }
-    bool checkSetter(JSContext *cx) { return desc()->checkSetter(cx); }
-
-    void initFromPropertyDescriptor(Handle<JSPropertyDescriptor> descriptor) {
-        desc()->initFromPropertyDescriptor(descriptor);
-    }
-    bool makeObject(JSContext *cx, MutableHandleObject objp) {
-        return desc()->makeObject(cx, objp);
-    }
-
-    void setValue(const Value &value) {
-        desc()->setValue(value);
-    }
-    void setGetter(const Value &getter) {
-        desc()->setGetter(getter);
-    }
-    void setSetter(const Value &setter) {
-        desc()->setSetter(setter);
-    }
-
-    void setUndefined() { desc()->setUndefined(); }
-};
-
-} /* namespace JS */
-
-namespace js {
-
-template <>
-struct GCMethods<PropDesc> {
-    static PropDesc initial() { return PropDesc(); }
-    static bool poisoned(const PropDesc &desc) {
-        return JS::IsPoisonedValue(desc.value_) ||
-               JS::IsPoisonedValue(desc.get_) ||
-               JS::IsPoisonedValue(desc.set_);
-    }
-};
-
-template <>
-class RootedBase<PropDesc>
-  : public JS::MutablePropDescOperations<JS::Rooted<PropDesc> >
-{
-    friend class JS::PropDescOperations<JS::Rooted<PropDesc> >;
-    friend class JS::MutablePropDescOperations<JS::Rooted<PropDesc> >;
-    const PropDesc *extract() const {
-        return static_cast<const JS::Rooted<PropDesc>*>(this)->address();
-    }
-    PropDesc *extractMutable() {
-        return static_cast<JS::Rooted<PropDesc>*>(this)->address();
-    }
-};
-
-template <>
-class HandleBase<PropDesc>
-  : public JS::PropDescOperations<JS::Handle<PropDesc> >
-{
-    friend class JS::PropDescOperations<JS::Handle<PropDesc> >;
-    const PropDesc *extract() const {
-        return static_cast<const JS::Handle<PropDesc>*>(this)->address();
-    }
-};
-
-template <>
-class MutableHandleBase<PropDesc>
-  : public JS::MutablePropDescOperations<JS::MutableHandle<PropDesc> >
-{
-    friend class JS::PropDescOperations<JS::MutableHandle<PropDesc> >;
-    friend class JS::MutablePropDescOperations<JS::MutableHandle<PropDesc> >;
-    const PropDesc *extract() const {
-        return static_cast<const JS::MutableHandle<PropDesc>*>(this)->address();
-    }
-    PropDesc *extractMutable() {
-        return static_cast<JS::MutableHandle<PropDesc>*>(this)->address();
-    }
-};
-
-} /* namespace js */
-
-#endif /* vm_PropDesc_h */
--- a/js/src/vm/Shape.h
+++ b/js/src/vm/Shape.h
@@ -24,17 +24,16 @@
 #include "gc/Heap.h"
 #include "gc/Marking.h"
 #include "gc/Rooting.h"
 #include "js/HashTable.h"
 #include "js/MemoryMetrics.h"
 #include "js/RootingAPI.h"
 #include "js/UbiNode.h"
 #include "vm/ObjectGroup.h"
-#include "vm/PropDesc.h"
 
 #ifdef _MSC_VER
 #pragma warning(push)
 #pragma warning(disable:4800)
 #pragma warning(push)
 #pragma warning(disable:4100) /* Silence unreferenced formal parameter warnings */
 #endif
 
@@ -1033,26 +1032,16 @@ class Shape : public gc::TenuredCell
 
     bool isDataDescriptor() const {
         return (attrs & (JSPROP_SETTER | JSPROP_GETTER)) == 0;
     }
     bool isAccessorDescriptor() const {
         return (attrs & (JSPROP_SETTER | JSPROP_GETTER)) != 0;
     }
 
-    PropDesc::Writability writability() const {
-        return (attrs & JSPROP_READONLY) ? PropDesc::NonWritable : PropDesc::Writable;
-    }
-    PropDesc::Enumerability enumerability() const {
-        return (attrs & JSPROP_ENUMERATE) ? PropDesc::Enumerable : PropDesc::NonEnumerable;
-    }
-    PropDesc::Configurability configurability() const {
-        return (attrs & JSPROP_PERMANENT) ? PropDesc::NonConfigurable : PropDesc::Configurable;
-    }
-
     /*
      * For ES5 compatibility, we allow properties with SetterOp-flavored
      * setters to be shadowed when set. The "own" property thereby created in
      * the directly referenced object will have the same getter and setter as
      * the prototype property. See bug 552432.
      */
     bool shadowable() const {
         MOZ_ASSERT_IF(isDataDescriptor(), writable());