Bug 862115 - Use Rooted<JSPropertyDescriptor> in favor of JSPropertyDescriptor::AutoRooter r=terrence r=smaug r=bholley
authorTerrence Cole <terrence@mozilla.com>
Tue, 30 Apr 2013 10:29:40 -0700
changeset 149975 db34065a8666ff7d7f460056b28282619830e33c
parent 149974 ef5be82e9690dfa9a38afbaf9998dd7bffdacab1
child 149976 abc52298ea07780cee25979f6835e14324d955eb
push idunknown
push userunknown
push dateunknown
reviewersterrence, smaug, bholley
bugs862115
milestone26.0a1
Bug 862115 - Use Rooted<JSPropertyDescriptor> in favor of JSPropertyDescriptor::AutoRooter r=terrence r=smaug r=bholley
dom/base/nsGlobalWindow.cpp
dom/bindings/BindingUtils.cpp
dom/bindings/BindingUtils.h
dom/bindings/Codegen.py
dom/bindings/DOMJSClass.h
dom/bindings/DOMJSProxyHandler.cpp
dom/bindings/DOMJSProxyHandler.h
js/ipc/JavaScriptChild.cpp
js/ipc/JavaScriptParent.cpp
js/ipc/JavaScriptParent.h
js/ipc/JavaScriptShared.cpp
js/ipc/JavaScriptShared.h
js/src/builtin/Object.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscompartment.cpp
js/src/jscompartment.h
js/src/jsfriendapi.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsproxy.cpp
js/src/jsproxy.h
js/src/jswrapper.cpp
js/src/jswrapper.h
js/src/shell/js.cpp
js/src/vm/Debugger.cpp
js/src/vm/ObjectImpl.h
js/src/vm/ScopeObject.cpp
js/xpconnect/src/XPCComponents.cpp
js/xpconnect/wrappers/ChromeObjectWrapper.cpp
js/xpconnect/wrappers/ChromeObjectWrapper.h
js/xpconnect/wrappers/FilteringWrapper.cpp
js/xpconnect/wrappers/FilteringWrapper.h
js/xpconnect/wrappers/WaiveXrayWrapper.cpp
js/xpconnect/wrappers/WaiveXrayWrapper.h
js/xpconnect/wrappers/XrayWrapper.cpp
js/xpconnect/wrappers/XrayWrapper.h
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -570,27 +570,27 @@ public:
   // Fundamental traps
   virtual bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible)
                            MOZ_OVERRIDE;
   virtual bool preventExtensions(JSContext *cx,
                                  JS::Handle<JSObject*> proxy) MOZ_OVERRIDE;
   virtual bool getPropertyDescriptor(JSContext* cx,
                                      JS::Handle<JSObject*> proxy,
                                      JS::Handle<jsid> id,
-                                     JSPropertyDescriptor* desc,
+                                     JS::MutableHandle<JSPropertyDescriptor> desc,
                                      unsigned flags) MOZ_OVERRIDE;
   virtual bool getOwnPropertyDescriptor(JSContext* cx,
                                         JS::Handle<JSObject*> proxy,
                                         JS::Handle<jsid> id,
-                                        JSPropertyDescriptor* desc,
+                                        JS::MutableHandle<JSPropertyDescriptor> desc,
                                         unsigned flags) MOZ_OVERRIDE;
   virtual bool defineProperty(JSContext* cx,
                               JS::Handle<JSObject*> proxy,
                               JS::Handle<jsid> id,
-                              JSPropertyDescriptor* desc) MOZ_OVERRIDE;
+                              JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE;
   virtual bool getOwnPropertyNames(JSContext *cx,
                                    JS::Handle<JSObject*> proxy,
                                    JS::AutoIdVector &props) MOZ_OVERRIDE;
   virtual bool delete_(JSContext *cx, JS::Handle<JSObject*> proxy,
                        JS::Handle<jsid> id,
                        bool *bp) MOZ_OVERRIDE;
   virtual bool enumerate(JSContext *cx, JS::Handle<JSObject*> proxy,
                          JS::AutoIdVector &props) MOZ_OVERRIDE;
@@ -683,59 +683,59 @@ nsOuterWindowProxy::finalize(JSFreeOp *f
     global->PoisonOuterWindowProxy(proxy);
   }
 }
 
 bool
 nsOuterWindowProxy::getPropertyDescriptor(JSContext* cx,
                                           JS::Handle<JSObject*> proxy,
                                           JS::Handle<jsid> id,
-                                          JSPropertyDescriptor* desc,
+                                          JS::MutableHandle<JSPropertyDescriptor> desc,
                                           unsigned flags)
 {
   // The only thing we can do differently from js::Wrapper is shadow stuff with
   // our indexed properties, so we can just try getOwnPropertyDescriptor and if
   // that gives us nothing call on through to js::Wrapper.
-  desc->obj = nullptr;
+  desc.object().set(nullptr);
   if (!getOwnPropertyDescriptor(cx, proxy, id, desc, flags)) {
     return false;
   }
 
-  if (desc->obj) {
+  if (desc.object()) {
     return true;
   }
 
   return js::Wrapper::getPropertyDescriptor(cx, proxy, id, desc, flags);
 }
 
 bool
 nsOuterWindowProxy::getOwnPropertyDescriptor(JSContext* cx,
                                              JS::Handle<JSObject*> proxy,
                                              JS::Handle<jsid> id,
-                                             JSPropertyDescriptor* desc,
+                                             JS::MutableHandle<JSPropertyDescriptor> desc,
                                              unsigned flags)
 {
   bool found;
-  if (!GetSubframeWindow(cx, proxy, id, &desc->value, found)) {
+  if (!GetSubframeWindow(cx, proxy, id, desc.value().address(), found)) {
     return false;
   }
   if (found) {
     FillPropertyDescriptor(desc, proxy, true);
     return true;
   }
   // else fall through to js::Wrapper
 
   return js::Wrapper::getOwnPropertyDescriptor(cx, proxy, id, desc, flags);
 }
 
 bool
 nsOuterWindowProxy::defineProperty(JSContext* cx,
                                    JS::Handle<JSObject*> proxy,
                                    JS::Handle<jsid> id,
-                                   JSPropertyDescriptor* desc)
+                                   JS::MutableHandle<JSPropertyDescriptor> desc)
 {
   int32_t index = GetArrayIndexFromId(cx, id);
   if (IsArrayIndex(index)) {
     // Spec says to Reject whether this is a supported index or not,
     // since we have no indexed setter or indexed creator.  That means
     // throwing in strict mode (FIXME: Bug 828137), doing nothing in
     // non-strict mode.
     return true;
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -810,25 +810,24 @@ GetNativePropertyHooks(JSContext *cx, JS
     DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj));
   type = ifaceAndProtoJSClass->mType;
   return ifaceAndProtoJSClass->mNativeHooks;
 }
 
 bool
 XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
                        JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
-                       JSPropertyDescriptor* desc, unsigned flags)
+                       JS::MutableHandle<JSPropertyDescriptor> desc, unsigned flags)
 {
   DOMObjectType type;
   const NativePropertyHooks *nativePropertyHooks =
     GetNativePropertyHooks(cx, obj, type);
 
   return type != eInstance || !nativePropertyHooks->mResolveOwnProperty ||
-         nativePropertyHooks->mResolveOwnProperty(cx, wrapper, obj, id, desc,
-                                                  flags);
+         nativePropertyHooks->mResolveOwnProperty(cx, wrapper, obj, id, desc, flags);
 }
 
 static bool
 XrayResolveAttribute(JSContext* cx, JS::Handle<JSObject*> wrapper,
                      JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
                      const Prefable<const JSPropertySpec>* attributes, jsid* attributeIds,
                      const JSPropertySpec* attributeSpecs, JSPropertyDescriptor* desc)
 {
@@ -1083,17 +1082,17 @@ XrayResolveNativeProperty(JSContext* cx,
 
   return XrayResolveNativeProperty(cx, wrapper, nativePropertyHooks, type, obj,
                                    id, desc);
 }
 
 bool
 XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
                    JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
-                   JSPropertyDescriptor* desc, bool* defined)
+                   JS::MutableHandle<JSPropertyDescriptor> desc, bool* defined)
 {
   if (!js::IsProxy(obj))
       return true;
 
   MOZ_ASSERT(IsDOMProxy(obj), "What kind of proxy is this?");
 
   DOMProxyHandler* handler =
     static_cast<DOMProxyHandler*>(js::GetProxyHandler(obj));
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -1896,17 +1896,17 @@ AddStringToIDVector(JSContext* cx, JS::A
  * wrapper is the Xray JS object.
  * obj is the target object of the Xray, a binding's instance object or a
  *     interface or interface prototype object.
  */
 bool
 XrayResolveOwnProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
                        JS::Handle<JSObject*> obj,
                        JS::Handle<jsid> id,
-                       JSPropertyDescriptor* desc, unsigned flags);
+                       JS::MutableHandle<JSPropertyDescriptor> desc, unsigned flags);
 
 /**
  * This resolves operations, attributes and constants of the interfaces for obj.
  *
  * wrapper is the Xray JS object.
  * obj is the target object of the Xray, a binding's instance object or a
  *     interface or interface prototype object.
  */
@@ -1919,19 +1919,19 @@ XrayResolveNativeProperty(JSContext* cx,
  * Define a property on obj through an Xray wrapper.
  *
  * wrapper is the Xray JS object.
  * obj is the target object of the Xray, a binding's instance object or a
  *     interface or interface prototype object.
  * defined will be set to true if a property was set as a result of this call.
  */
 bool
-XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper, 
+XrayDefineProperty(JSContext* cx, JS::Handle<JSObject*> wrapper,
                    JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
-                   JSPropertyDescriptor* desc, bool* defined);
+                   JS::MutableHandle<JSPropertyDescriptor> desc, bool* defined);
 
 /**
  * This enumerates indexed or named properties of obj and operations, attributes
  * and constants of the interfaces for obj.
  *
  * wrapper is the Xray JS object.
  * obj is the target object of the Xray, a binding's instance object or a
  *     interface or interface prototype object.
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -6925,17 +6925,18 @@ class CGClass(CGThing):
         return result
 
 class CGResolveOwnProperty(CGAbstractStaticMethod):
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'),
                 Argument('JS::Handle<JSObject*>', 'wrapper'),
                 Argument('JS::Handle<JSObject*>', 'obj'),
                 Argument('JS::Handle<jsid>', 'id'),
-                Argument('JSPropertyDescriptor*', 'desc'), Argument('unsigned', 'flags'),
+                Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc'),
+                Argument('unsigned', 'flags'),
                 ]
         CGAbstractStaticMethod.__init__(self, descriptor, "ResolveOwnProperty",
                                         "bool", args)
     def definition_body(self):
         return """  return js::GetProxyHandler(obj)->getOwnPropertyDescriptor(cx, wrapper, id, desc, flags);
 """
 
 class CGResolveOwnPropertyViaNewresolve(CGAbstractBindingMethod):
@@ -6943,17 +6944,18 @@ class CGResolveOwnPropertyViaNewresolve(
     An implementation of Xray ResolveOwnProperty stuff for things that have a
     newresolve hook.
     """
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'),
                 Argument('JS::Handle<JSObject*>', 'wrapper'),
                 Argument('JS::Handle<JSObject*>', 'obj'),
                 Argument('JS::Handle<jsid>', 'id'),
-                Argument('JSPropertyDescriptor*', 'desc'), Argument('unsigned', 'flags'),
+                Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc'),
+                Argument('unsigned', 'flags'),
                 ]
         CGAbstractBindingMethod.__init__(self, descriptor,
                                          "ResolveOwnPropertyViaNewresolve",
                                          args, getThisObj="",
                                          callArgs="")
     def generate_code(self):
         return CGIndenter(CGGeneric(
                 "JS::Rooted<JS::Value> value(cx);\n"
@@ -7071,18 +7073,18 @@ class CGProxySpecialOperation(CGPerSigna
                 argument.type, descriptor,
                 treatNullAs=argument.treatNullAs,
                 treatUndefinedAs=argument.treatUndefinedAs,
                 sourceDescription=("value being assigned to %s setter" %
                                    descriptor.interface.identifier.name))
             templateValues = {
                 "declName": argument.identifier.name,
                 "holderName": argument.identifier.name + "_holder",
-                "val" : "JS::Handle<JS::Value>::fromMarkedLocation(&desc->value)",
-                "mutableVal" : "JS::MutableHandle<JS::Value>::fromMarkedLocation(&desc->value)",
+                "val": "desc.value()",
+                "mutableVal" : "desc.value()",
                 "obj": "obj"
             }
             self.cgRoot.prepend(instantiateJSToNativeConversion(info, templateValues))
         elif operation.isGetter() or operation.isDeleter():
             self.cgRoot.prepend(CGGeneric("bool found;"))
 
     def getArguments(self):
         args = [(a, a.identifier.name) for a in self.arguments]
@@ -7277,45 +7279,45 @@ class CGDOMJSProxyHandler_CGDOMJSProxyHa
     def __init__(self):
         ClassConstructor.__init__(self, [], inline=True, visibility="private",
                                   baseConstructors=["mozilla::dom::DOMProxyHandler(Class)"])
 
 class CGDOMJSProxyHandler_getOwnPropertyDescriptor(ClassMethod):
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'), Argument('JS::Handle<JSObject*>', 'proxy'),
                 Argument('JS::Handle<jsid>', 'id'),
-                Argument('JSPropertyDescriptor*', 'desc'), Argument('unsigned', 'flags')]
+                Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc'),
+                Argument('unsigned', 'flags')]
         ClassMethod.__init__(self, "getOwnPropertyDescriptor", "bool", args)
         self.descriptor = descriptor
     def getBody(self):
         indexedGetter = self.descriptor.operations['IndexedGetter']
         indexedSetter = self.descriptor.operations['IndexedSetter']
 
         setOrIndexedGet = "bool isXray = xpc::WrapperFactory::IsXrayWrapper(proxy);\n"
         if self.descriptor.supportsIndexedProperties():
             setOrIndexedGet += "int32_t index = GetArrayIndexFromId(cx, id);\n"
             readonly = toStringBool(indexedSetter is None)
             fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;" % readonly
-            templateValues = {'jsvalRef': 'JS::MutableHandle<JS::Value>::fromMarkedLocation(&desc->value)',
-                              'jsvalHandle': 'JS::MutableHandle<JS::Value>::fromMarkedLocation(&desc->value)',
+            templateValues = {'jsvalRef': 'desc.value()', 'jsvalHandle': 'desc.value()',
                               'obj': 'proxy', 'successCode': fillDescriptor}
             get = ("if (IsArrayIndex(index)) {\n" +
                    CGIndenter(CGProxyIndexedGetter(self.descriptor, templateValues)).define() + "\n" +
                    "}\n") % (self.descriptor.nativeType)
 
         if UseHolderForUnforgeable(self.descriptor):
-            getUnforgeable = """if (!JS_GetPropertyDescriptorById(cx, ${holder}, id, flags, desc)) {
+            getUnforgeable = """if (!JS_GetPropertyDescriptorById(cx, ${holder}, id, flags, desc.address())) {
   return false;
 }
-MOZ_ASSERT_IF(desc->obj, desc->obj == ${holder});"""
+MOZ_ASSERT_IF(desc.object(), desc.object() == ${holder});"""
             getUnforgeable = CallOnUnforgeableHolder(self.descriptor,
                                                      getUnforgeable, "isXray")
-            getUnforgeable += """if (desc->obj) {
-  desc->obj = proxy;
-  return !isXray || JS_WrapPropertyDescriptor(cx, desc);
+            getUnforgeable += """if (desc.object()) {
+  desc.object().set(proxy);
+  return !isXray || JS_WrapPropertyDescriptor(cx, desc.address());
 }
 
 """
         else:
             getUnforgeable = ""
 
         if indexedSetter or self.descriptor.operations['NamedSetter']:
             setOrIndexedGet += "if (flags & JSRESOLVE_ASSIGNING) {\n"
@@ -7357,52 +7359,52 @@ MOZ_ASSERT_IF(desc->obj, desc->obj == ${
                 setOrIndexedGet += ("if (!(flags & JSRESOLVE_ASSIGNING)) {\n" +
                                     CGIndenter(CGGeneric(get)).define() +
                                     "}\n\n")
             setOrIndexedGet += getUnforgeable
 
         if self.descriptor.supportsNamedProperties():
             readonly = toStringBool(self.descriptor.operations['NamedSetter'] is None)
             fillDescriptor = "FillPropertyDescriptor(desc, proxy, %s);\nreturn true;" % readonly
-            templateValues = {'jsvalRef': 'JS::MutableHandle<JS::Value>::fromMarkedLocation(&desc->value)',
-                              'jsvalHandle': 'JS::MutableHandle<JS::Value>::fromMarkedLocation(&desc->value)',
+            templateValues = {'jsvalRef': 'desc.value()', 'jsvalHandle': 'desc.value()',
                               'obj': 'proxy', 'successCode': fillDescriptor}
             condition = "!HasPropertyOnPrototype(cx, proxy, this, id)"
             if self.descriptor.interface.getExtendedAttribute('OverrideBuiltins'):
                 condition = "(!isXray || %s)" % condition
             condition = "!(flags & JSRESOLVE_ASSIGNING) && " + condition
             if self.descriptor.supportsIndexedProperties():
                 condition = "!IsArrayIndex(index) && " + condition
             namedGet = ("\n" +
                         CGIfWrapper(CGProxyNamedGetter(self.descriptor, templateValues),
                                     condition).define() +
                         "\n")
         else:
             namedGet = ""
 
         return setOrIndexedGet + """JS::Rooted<JSObject*> expando(cx);
 if (!isXray && (expando = GetExpandoObject(proxy))) {
-  if (!JS_GetPropertyDescriptorById(cx, expando, id, flags, desc)) {
+  if (!JS_GetPropertyDescriptorById(cx, expando, id, flags, desc.address())) {
     return false;
   }
-  if (desc->obj) {
+  if (desc.object()) {
     // Pretend the property lives on the wrapper.
-    desc->obj = proxy;
+    desc.object().set(proxy);
     return true;
   }
 }
 """ + namedGet + """
-desc->obj = nullptr;
+desc.object().set(nullptr);
 return true;"""
 
 class CGDOMJSProxyHandler_defineProperty(ClassMethod):
     def __init__(self, descriptor):
         args = [Argument('JSContext*', 'cx'), Argument('JS::Handle<JSObject*>', 'proxy'),
                 Argument('JS::Handle<jsid>', 'id'),
-                Argument('JSPropertyDescriptor*', 'desc'), Argument('bool*', 'defined')]
+                Argument('JS::MutableHandle<JSPropertyDescriptor>', 'desc'),
+                Argument('bool*', 'defined')]
         ClassMethod.__init__(self, "defineProperty", "bool", args, virtual=True, override=True)
         self.descriptor = descriptor
     def getBody(self):
         set = ""
 
         indexedSetter = self.descriptor.operations['IndexedSetter']
         if indexedSetter:
             if not (self.descriptor.operations['IndexedCreator'] is indexedSetter):
@@ -7424,17 +7426,17 @@ class CGDOMJSProxyHandler_defineProperty
         if UseHolderForUnforgeable(self.descriptor):
             defineOnUnforgeable = ("bool hasUnforgeable;\n"
                                    "if (!JS_HasPropertyById(cx, ${holder}, id, &hasUnforgeable)) {\n"
                                    "  return false;\n"
                                    "}\n"
                                    "if (hasUnforgeable) {\n"
                                    "  *defined = true;" +
                                    "  bool unused;\n"
-                                   "  return js_DefineOwnProperty(cx, ${holder}, id, *desc, &unused);\n"
+                                   "  return js_DefineOwnProperty(cx, ${holder}, id, desc, &unused);\n"
                                    "}\n")
             set += CallOnUnforgeableHolder(self.descriptor,
                                            defineOnUnforgeable,
                                            "xpc::WrapperFactory::IsXrayWrapper(proxy)")
 
         namedSetter = self.descriptor.operations['NamedSetter']
         if namedSetter:
             if not self.descriptor.operations['NamedCreator'] is namedSetter:
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -55,17 +55,17 @@ static_assert(DOM_PROTO_INSTANCE_CLASS_S
               "not be the same slot.");
 
 namespace mozilla {
 namespace dom {
 
 typedef bool
 (* ResolveOwnProperty)(JSContext* cx, JS::Handle<JSObject*> wrapper,
                        JS::Handle<JSObject*> obj, JS::Handle<jsid> id,
-                       JSPropertyDescriptor* desc, unsigned flags);
+                       JS::MutableHandle<JSPropertyDescriptor> desc, unsigned flags);
 
 typedef bool
 (* EnumerateOwnProperties)(JSContext* cx, JS::Handle<JSObject*> wrapper,
                            JS::Handle<JSObject*> obj,
                            JS::AutoIdVector& props);
 
 struct ConstantSpec
 {
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -156,42 +156,42 @@ DOMProxyHandler::preventExtensions(JSCon
 {
   // Throw a TypeError, per WebIDL.
   JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CHANGE_EXTENSIBILITY);
   return false;
 }
 
 bool
 DOMProxyHandler::getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
-                                       JSPropertyDescriptor* desc, unsigned flags)
+                                       MutableHandle<JSPropertyDescriptor> desc, unsigned flags)
 {
   if (!getOwnPropertyDescriptor(cx, proxy, id, desc, flags)) {
     return false;
   }
-  if (desc->obj) {
+  if (desc.object()) {
     return true;
   }
 
   JS::Rooted<JSObject*> proto(cx);
   if (!js::GetObjectProto(cx, proxy, &proto)) {
     return false;
   }
   if (!proto) {
-    desc->obj = NULL;
+    desc.object().set(nullptr);
     return true;
   }
 
-  return JS_GetPropertyDescriptorById(cx, proto, id, 0, desc);
+  return JS_GetPropertyDescriptorById(cx, proto, id, 0, desc.address());
 }
 
 bool
 DOMProxyHandler::defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
-                                JSPropertyDescriptor* desc, bool* defined)
+                                MutableHandle<JSPropertyDescriptor> desc, bool* defined)
 {
-  if ((desc->attrs & JSPROP_GETTER) && desc->setter == JS_StrictPropertyStub) {
+  if (desc.hasGetterObject() && desc.setter() == JS_StrictPropertyStub) {
     return JS_ReportErrorFlagsAndNumber(cx,
                                         JSREPORT_WARNING | JSREPORT_STRICT |
                                         JSREPORT_STRICT_MODE_ERROR,
                                         js_GetErrorMessage, NULL,
                                         JSMSG_GETTER_ONLY);
   }
 
   if (xpc::WrapperFactory::IsXrayWrapper(proxy)) {
@@ -199,17 +199,17 @@ DOMProxyHandler::defineProperty(JSContex
   }
 
   JSObject* expando = EnsureExpandoObject(cx, proxy);
   if (!expando) {
     return false;
   }
 
   bool dummy;
-  return js_DefineOwnProperty(cx, expando, id, *desc, &dummy);
+  return js_DefineOwnProperty(cx, expando, id, desc, &dummy);
 }
 
 bool
 DOMProxyHandler::delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
                          JS::Handle<jsid> id, bool* bp)
 {
   JS::Rooted<JSObject*> expando(cx);
   if (!xpc::WrapperFactory::IsXrayWrapper(proxy) && (expando = GetExpandoObject(proxy))) {
--- a/dom/bindings/DOMJSProxyHandler.h
+++ b/dom/bindings/DOMJSProxyHandler.h
@@ -33,25 +33,25 @@ public:
   DOMProxyHandler(const DOMClass& aClass)
     : js::BaseProxyHandler(ProxyFamily()),
       mClass(aClass)
   {
   }
 
   bool preventExtensions(JSContext *cx, JS::Handle<JSObject*> proxy) MOZ_OVERRIDE;
   bool getPropertyDescriptor(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
-                            JSPropertyDescriptor* desc, unsigned flags) MOZ_OVERRIDE;
+                             JS::MutableHandle<JSPropertyDescriptor> desc, unsigned flags) MOZ_OVERRIDE;
   bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
-                      JSPropertyDescriptor* desc) MOZ_OVERRIDE
+                      JS::MutableHandle<JSPropertyDescriptor> desc) MOZ_OVERRIDE
   {
     bool unused;
     return defineProperty(cx, proxy, id, desc, &unused);
   }
   virtual bool defineProperty(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
-                              JSPropertyDescriptor* desc, bool* defined);
+                              JS::MutableHandle<JSPropertyDescriptor> desc, bool* defined);
   bool delete_(JSContext* cx, JS::Handle<JSObject*> proxy,
                JS::Handle<jsid> id, bool* bp) MOZ_OVERRIDE;
   bool enumerate(JSContext* cx, JS::Handle<JSObject*> proxy, JS::AutoIdVector& props) MOZ_OVERRIDE;
   bool has(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id, bool* bp) MOZ_OVERRIDE;
   bool isExtensible(JSContext *cx, JS::Handle<JSObject*> proxy, bool *extensible) MOZ_OVERRIDE;
 
   static JSObject* GetExpandoObject(JSObject* obj)
   {
@@ -118,28 +118,29 @@ GetArrayIndexFromId(JSContext* cx, JS::H
 
 inline bool
 IsArrayIndex(int32_t index)
 {
   return index >= 0;
 }
 
 inline void
-FillPropertyDescriptor(JSPropertyDescriptor* desc, JSObject* obj, bool readonly)
+FillPropertyDescriptor(JS::MutableHandle<JSPropertyDescriptor> desc, JSObject* obj, bool readonly)
 {
-  desc->obj = obj;
-  desc->attrs = (readonly ? JSPROP_READONLY : 0) | JSPROP_ENUMERATE;
-  desc->getter = NULL;
-  desc->setter = NULL;
-  desc->shortid = 0;
+  desc.object().set(obj);
+  desc.setAttributes((readonly ? JSPROP_READONLY : 0) | JSPROP_ENUMERATE);
+  desc.setGetter(nullptr);
+  desc.setSetter(nullptr);
+  desc.setShortId(0);
 }
 
 inline void
-FillPropertyDescriptor(JSPropertyDescriptor* desc, JSObject* obj, JS::Value v, bool readonly)
+FillPropertyDescriptor(JS::MutableHandle<JSPropertyDescriptor> desc, JSObject* obj, JS::Value v,
+                       bool readonly)
 {
-  desc->value = v;
+  desc.value().set(v);
   FillPropertyDescriptor(desc, obj, readonly);
 }
 
 } // namespace dom
 } // namespace mozilla
 
 #endif /* mozilla_dom_DOMProxyHandler_h */
--- a/js/ipc/JavaScriptChild.cpp
+++ b/js/ipc/JavaScriptChild.cpp
@@ -183,21 +183,21 @@ JavaScriptChild::AnswerGetPropertyDescri
         return false;
 
     JSAutoCompartment comp(cx, obj);
 
     RootedId internedId(cx);
     if (!convertGeckoStringToId(cx, id, &internedId))
         return fail(cx, rs);
 
-    JSPropertyDescriptor desc;
-    if (!JS_GetPropertyDescriptorById(cx, obj, internedId, flags, &desc))
+    Rooted<JSPropertyDescriptor> desc(cx);
+    if (!JS_GetPropertyDescriptorById(cx, obj, internedId, flags, desc.address()))
         return fail(cx, rs);
 
-    if (!desc.obj)
+    if (!desc.object())
         return ok(rs);
 
     if (!fromDescriptor(cx, desc, out))
         return fail(cx, rs);
 
     return ok(rs);
 }
 
@@ -216,21 +216,21 @@ JavaScriptChild::AnswerGetOwnPropertyDes
         return false;
 
     JSAutoCompartment comp(cx, obj);
 
     RootedId internedId(cx);
     if (!convertGeckoStringToId(cx, id, &internedId))
         return fail(cx, rs);
 
-    JSPropertyDescriptor desc;
-    if (!JS_GetPropertyDescriptorById(cx, obj, internedId, flags, &desc))
+    Rooted<JSPropertyDescriptor> desc(cx);
+    if (!JS_GetPropertyDescriptorById(cx, obj, internedId, flags, desc.address()))
         return fail(cx, rs);
 
-    if (desc.obj != obj)
+    if (desc.object() != obj)
         return ok(rs);
 
     if (!fromDescriptor(cx, desc, out))
         return fail(cx, rs);
 
     return ok(rs);
 }
 
@@ -247,17 +247,17 @@ JavaScriptChild::AnswerDefineProperty(co
 
     JSAutoCompartment comp(cx, obj);
 
     RootedId internedId(cx);
     if (!convertGeckoStringToId(cx, id, &internedId))
         return fail(cx, rs);
 
     Rooted<JSPropertyDescriptor> desc(cx);
-    if (!toDescriptor(cx, descriptor, desc.address()))
+    if (!toDescriptor(cx, descriptor, &desc))
         return false;
 
     if (!js::CheckDefineProperty(cx, obj, internedId, desc.value(), desc.getter(),
                                  desc.setter(), desc.attributes()))
     {
         return fail(cx, rs);
     }
 
--- a/js/ipc/JavaScriptParent.cpp
+++ b/js/ipc/JavaScriptParent.cpp
@@ -57,21 +57,23 @@ class CPOWProxyHandler : public BaseProx
     virtual ~CPOWProxyHandler() {}
 
     virtual bool finalizeInBackground(Value priv) MOZ_OVERRIDE {
         return false;
     }
 
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                       PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
+                                       MutableHandle<PropertyDescriptor> desc,
+                                       unsigned flags) MOZ_OVERRIDE;
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy,
-                                          HandleId id, PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
+                                          HandleId id, MutableHandle<PropertyDescriptor> desc,
+                                          unsigned flags) MOZ_OVERRIDE;
     virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                PropertyDescriptor *desc) MOZ_OVERRIDE;
+                                MutableHandle<PropertyDescriptor> desc) MOZ_OVERRIDE;
     virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy,
                                      AutoIdVector &props) MOZ_OVERRIDE;
     virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
     virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) MOZ_OVERRIDE;
 
     virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
     virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,
@@ -106,24 +108,24 @@ JavaScriptParent::preventExtensions(JSCo
     if (!CallPreventExtensions(objId, &status))
         return ipcfail(cx);
 
     return ok(cx, status);
 }
 
 bool
 CPOWProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                        PropertyDescriptor *desc, unsigned flags)
+                                        MutableHandle<PropertyDescriptor> desc, unsigned flags)
 {
     return ParentOf(proxy)->getPropertyDescriptor(cx, proxy, id, desc, flags);
 }
 
 bool
 JavaScriptParent::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                        PropertyDescriptor *desc, unsigned flags)
+                                        MutableHandle<PropertyDescriptor> desc, unsigned flags)
 {
     ObjectId objId = idOf(proxy);
 
     nsString idstr;
     if (!convertIdToGeckoString(cx, id, &idstr))
         return false;
 
     ReturnStatus status;
@@ -133,24 +135,25 @@ JavaScriptParent::getPropertyDescriptor(
     if (!ok(cx, status))
         return false;
 
     return toDescriptor(cx, result, desc);
 }
 
 bool
 CPOWProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy,
-                                           HandleId id, PropertyDescriptor *desc, unsigned flags)
+                                           HandleId id, MutableHandle<PropertyDescriptor> desc,
+                                           unsigned flags)
 {
     return ParentOf(proxy)->getOwnPropertyDescriptor(cx, proxy, id, desc, flags);
 }
 
 bool
 JavaScriptParent::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                           PropertyDescriptor *desc, unsigned flags)
+                                           MutableHandle<PropertyDescriptor> desc, unsigned flags)
 {
     ObjectId objId = idOf(proxy);
 
     nsString idstr;
     if (!convertIdToGeckoString(cx, id, &idstr))
         return false;
 
     ReturnStatus status;
@@ -160,33 +163,33 @@ JavaScriptParent::getOwnPropertyDescript
     if (!ok(cx, status))
         return false;
 
     return toDescriptor(cx, result, desc);
 }
 
 bool
 CPOWProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                 PropertyDescriptor *desc)
+                                 MutableHandle<PropertyDescriptor> desc)
 {
     return ParentOf(proxy)->defineProperty(cx, proxy, id, desc);
 }
 
 bool
 JavaScriptParent::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                 PropertyDescriptor *desc)
+                                 MutableHandle<PropertyDescriptor> desc)
 {
     ObjectId objId = idOf(proxy);
 
     nsString idstr;
     if (!convertIdToGeckoString(cx, id, &idstr))
         return false;
 
     PPropertyDescriptor descriptor;
-    if (!fromDescriptor(cx, *desc, &descriptor))
+    if (!fromDescriptor(cx, desc, &descriptor))
         return false;
 
     ReturnStatus status;
     if (!CallDefineProperty(objId, idstr, descriptor, &status))
         return ipcfail(cx);
 
     return ok(cx, status);
 }
--- a/js/ipc/JavaScriptParent.h
+++ b/js/ipc/JavaScriptParent.h
@@ -29,21 +29,21 @@ class JavaScriptParent
 
     bool init();
 
   public:
     // Fundamental proxy traps. These are required.
     // (The traps should be in the same order like js/src/jsproxy.h)
     bool preventExtensions(JSContext *cx, JS::HandleObject proxy);
     bool getPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
-                               JSPropertyDescriptor *desc, unsigned flags);
+                               JS::MutableHandle<JSPropertyDescriptor> desc, unsigned flags);
     bool getOwnPropertyDescriptor(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
-                                  JSPropertyDescriptor *desc, unsigned flags);
+                                  JS::MutableHandle<JSPropertyDescriptor> desc, unsigned flags);
     bool defineProperty(JSContext *cx, JS::HandleObject proxy, JS::HandleId id,
-                        JSPropertyDescriptor *desc);
+                        JS::MutableHandle<JSPropertyDescriptor> desc);
     bool getOwnPropertyNames(JSContext *cx, JS::HandleObject proxy, js::AutoIdVector &props);
     bool delete_(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
     bool enumerate(JSContext *cx, JS::HandleObject proxy, js::AutoIdVector &props);
 
     // Derived proxy traps. Implementing these is useful for perfomance.
     bool has(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
     bool hasOwn(JSContext *cx, JS::HandleObject proxy, JS::HandleId id, bool *bp);
     bool get(JSContext *cx, JS::HandleObject proxy, JS::HandleObject receiver,
--- a/js/ipc/JavaScriptShared.cpp
+++ b/js/ipc/JavaScriptShared.cpp
@@ -308,49 +308,50 @@ JavaScriptShared::ConvertID(const JSIID 
     to->m3[7] = from.m3_7();
 }
 
 static const uint32_t DefaultPropertyOp = 1;
 static const uint32_t GetterOnlyPropertyStub = 2;
 static const uint32_t UnknownPropertyOp = 3;
 
 bool
-JavaScriptShared::fromDescriptor(JSContext *cx, const JSPropertyDescriptor &desc, PPropertyDescriptor *out)
+JavaScriptShared::fromDescriptor(JSContext *cx, Handle<JSPropertyDescriptor> desc,
+                                 PPropertyDescriptor *out)
 {
-    out->attrs() = desc.attrs;
-    out->shortid() = desc.shortid;
-    if (!toVariant(cx, desc.value, &out->value()))
+    out->attrs() = desc.attributes();
+    out->shortid() = desc.shortid();
+    if (!toVariant(cx, desc.value(), &out->value()))
         return false;
 
-    if (!makeId(cx, desc.obj, &out->objId()))
+    if (!makeId(cx, desc.object(), &out->objId()))
         return false;
 
-    if (!desc.getter) {
+    if (!desc.getter()) {
         out->getter() = 0;
-    } else if (desc.attrs & JSPROP_GETTER) {
-        JSObject *getter = JS_FUNC_TO_DATA_PTR(JSObject *, desc.getter);
+    } else if (desc.hasGetterObject()) {
+        JSObject *getter = desc.getterObject();
         if (!makeId(cx, getter, &out->getter()))
             return false;
     } else {
-        if (desc.getter == JS_PropertyStub)
+        if (desc.getter() == JS_PropertyStub)
             out->getter() = DefaultPropertyOp;
         else
             out->getter() = UnknownPropertyOp;
     }
 
-    if (!desc.setter) {
+    if (!desc.setter()) {
         out->setter() = 0;
-    } else if (desc.attrs & JSPROP_SETTER) {
-        JSObject *setter = JS_FUNC_TO_DATA_PTR(JSObject  *, desc.setter);
+    } else if (desc.hasSetterObject()) {
+        JSObject *setter = desc.setterObject();
         if (!makeId(cx, setter, &out->setter()))
             return false;
     } else {
-        if (desc.setter == JS_StrictPropertyStub)
+        if (desc.setter() == JS_StrictPropertyStub)
             out->setter() = DefaultPropertyOp;
-        else if (desc.setter == js_GetterOnlyPropertyStub)
+        else if (desc.setter() == js_GetterOnlyPropertyStub)
             out->setter() = GetterOnlyPropertyStub;
         else
             out->setter() = UnknownPropertyOp;
     }
 
     return true;
 }
 
@@ -364,55 +365,56 @@ UnknownPropertyStub(JSContext *cx, Handl
 bool
 UnknownStrictPropertyStub(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp)
 {
     JS_ReportError(cx, "setter could not be wrapped via CPOWs");
     return false;
 }
 
 bool
-JavaScriptShared::toDescriptor(JSContext *cx, const PPropertyDescriptor &in, JSPropertyDescriptor *out)
+JavaScriptShared::toDescriptor(JSContext *cx, const PPropertyDescriptor &in,
+                               MutableHandle<JSPropertyDescriptor> out)
 {
-    out->attrs = in.attrs();
-    out->shortid = in.shortid();
-    if (!toValue(cx, in.value(), &out->value))
+    out.setAttributes(in.attrs());
+    out.setShortId(in.shortid());
+    if (!toValue(cx, in.value(), out.value()))
         return false;
     Rooted<JSObject*> obj(cx);
     if (!unwrap(cx, in.objId(), &obj))
         return false;
-    out->obj = obj;
+    out.object().set(obj);
 
     if (!in.getter()) {
-        out->getter = NULL;
+        out.setGetter(nullptr);
     } else if (in.attrs() & JSPROP_GETTER) {
         Rooted<JSObject*> getter(cx);
         if (!unwrap(cx, in.getter(), &getter))
             return false;
-        out->getter = JS_DATA_TO_FUNC_PTR(JSPropertyOp, getter.get());
+        out.setGetter(JS_DATA_TO_FUNC_PTR(JSPropertyOp, getter.get()));
     } else {
         if (in.getter() == DefaultPropertyOp)
-            out->getter = JS_PropertyStub;
+            out.setGetter(JS_PropertyStub);
         else
-            out->getter = UnknownPropertyStub;
+            out.setGetter(UnknownPropertyStub);
     }
 
     if (!in.setter()) {
-        out->setter = NULL;
+        out.setSetter(nullptr);
     } else if (in.attrs() & JSPROP_SETTER) {
         Rooted<JSObject*> setter(cx);
         if (!unwrap(cx, in.setter(), &setter))
             return false;
-        out->setter = JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, setter.get());
+        out.setSetter(JS_DATA_TO_FUNC_PTR(JSStrictPropertyOp, setter.get()));
     } else {
         if (in.setter() == DefaultPropertyOp)
-            out->setter = JS_StrictPropertyStub;
+            out.setSetter(JS_StrictPropertyStub);
         else if (in.setter() == GetterOnlyPropertyStub)
-            out->setter = js_GetterOnlyPropertyStub;
+            out.setSetter(js_GetterOnlyPropertyStub);
         else
-            out->setter = UnknownStrictPropertyStub;
+            out.setSetter(UnknownStrictPropertyStub);
     }
 
     return true;
 }
 
 bool
 CpowIdHolder::ToObject(JSContext *cx, JSObject **objp)
 {
--- a/js/ipc/JavaScriptShared.h
+++ b/js/ipc/JavaScriptShared.h
@@ -91,18 +91,19 @@ class JavaScriptShared
     static const uint32_t OBJECT_IS_CALLABLE = (1 << 0);
 
     bool Unwrap(JSContext *cx, const InfallibleTArray<CpowEntry> &aCpows, JSObject **objp);
     bool Wrap(JSContext *cx, JS::HandleObject aObj, InfallibleTArray<CpowEntry> *outCpows);
 
   protected:
     bool toVariant(JSContext *cx, jsval from, JSVariant *to);
     bool toValue(JSContext *cx, const JSVariant &from, JS::MutableHandleValue to);
-    bool fromDescriptor(JSContext *cx, const JSPropertyDescriptor &desc, PPropertyDescriptor *out);
-    bool toDescriptor(JSContext *cx, const PPropertyDescriptor &in, JSPropertyDescriptor *out);
+    bool fromDescriptor(JSContext *cx, JS::Handle<JSPropertyDescriptor> desc, PPropertyDescriptor *out);
+    bool toDescriptor(JSContext *cx, const PPropertyDescriptor &in,
+                      JS::MutableHandle<JSPropertyDescriptor> out);
     bool convertIdToGeckoString(JSContext *cx, JS::HandleId id, nsString *to);
     bool convertGeckoStringToId(JSContext *cx, const nsString &from, JS::MutableHandleId id);
 
     bool toValue(JSContext *cx, const JSVariant &from, jsval *to) {
         JS::RootedValue v(cx);
         if (!toValue(cx, from, &v))
             return false;
         *to = v;
--- a/js/src/builtin/Object.cpp
+++ b/js/src/builtin/Object.cpp
@@ -419,21 +419,21 @@ obj_lookupGetter(JSContext *cx, unsigned
         return false;
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
     if (obj->is<ProxyObject>()) {
         // The vanilla getter lookup code below requires that the object is
         // native. Handle proxies separately.
         args.rval().setUndefined();
-        AutoPropertyDescriptorRooter desc(cx);
+        Rooted<PropertyDescriptor> desc(cx);
         if (!Proxy::getPropertyDescriptor(cx, obj, id, &desc, 0))
             return false;
-        if (desc.obj && (desc.attrs & JSPROP_GETTER) && desc.getter)
-            args.rval().set(CastAsObjectJsval(desc.getter));
+        if (desc.object() && desc.hasGetterObject() && desc.getterObject())
+            args.rval().setObject(*desc.getterObject());
         return true;
     }
     RootedObject pobj(cx);
     RootedShape shape(cx);
     if (!JSObject::lookupGeneric(cx, obj, id, &pobj, &shape))
         return false;
     args.rval().setUndefined();
     if (shape) {
@@ -455,21 +455,21 @@ obj_lookupSetter(JSContext *cx, unsigned
         return false;
     RootedObject obj(cx, ToObject(cx, args.thisv()));
     if (!obj)
         return false;
     if (obj->is<ProxyObject>()) {
         // The vanilla setter lookup code below requires that the object is
         // native. Handle proxies separately.
         args.rval().setUndefined();
-        AutoPropertyDescriptorRooter desc(cx);
+        Rooted<PropertyDescriptor> desc(cx);
         if (!Proxy::getPropertyDescriptor(cx, obj, id, &desc, 0))
             return false;
-        if (desc.obj && (desc.attrs & JSPROP_SETTER) && desc.setter)
-            args.rval().set(CastAsObjectJsval(desc.setter));
+        if (desc.object() && desc.hasSetterObject() && desc.setterObject())
+            args.rval().setObject(*desc.setterObject());
         return true;
     }
     RootedObject pobj(cx);
     RootedShape shape(cx);
     if (!JSObject::lookupGeneric(cx, obj, id, &pobj, &shape))
         return false;
     args.rval().setUndefined();
     if (shape) {
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3112,21 +3112,21 @@ LookupResult(JSContext *cx, HandleObject
     if (!shape) {
         /* XXX bad API: no way to tell "not defined" from "void value" */
         vp.setUndefined();
         return true;
     }
 
     if (!obj2->isNative()) {
         if (obj2->is<ProxyObject>()) {
-            AutoPropertyDescriptorRooter desc(cx);
+            Rooted<PropertyDescriptor> desc(cx);
             if (!Proxy::getPropertyDescriptor(cx, obj2, id, &desc, 0))
                 return false;
-            if (!(desc.attrs & JSPROP_SHARED)) {
-                vp.set(desc.value);
+            if (!desc.isShared()) {
+                vp.set(desc.value());
                 return true;
             }
         }
     } else if (IsImplicitDenseElement(shape)) {
         vp.set(obj2->getDenseElement(JSID_TO_INT(id)));
         return true;
     } else {
         /* Peek at the native property's slot value, without doing a Get. */
@@ -3590,95 +3590,87 @@ JS_DefineProperties(JSContext *cx, JSObj
         if (!ok)
             break;
     }
     return ok;
 }
 
 static bool
 GetPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-                          bool own, PropertyDescriptor *desc)
+                          bool own, MutableHandle<PropertyDescriptor> desc)
 {
     RootedObject obj2(cx);
     RootedShape shape(cx);
 
     if (!LookupPropertyById(cx, obj, id, flags, &obj2, &shape))
         return false;
 
-    if (!shape || (own && obj != obj2)) {
-        desc->obj = NULL;
-        desc->attrs = 0;
-        desc->getter = NULL;
-        desc->setter = NULL;
-        desc->value.setUndefined();
+    JS_ASSERT(desc.isClear());
+    if (!shape || (own && obj != obj2))
         return true;
-    }
-
-    desc->obj = obj2;
+
+    desc.object().set(obj2);
     if (obj2->isNative()) {
         if (IsImplicitDenseElement(shape)) {
-            desc->attrs = JSPROP_ENUMERATE;
-            desc->getter = NULL;
-            desc->setter = NULL;
-            desc->value = obj2->getDenseElement(JSID_TO_INT(id));
+            desc.setEnumerable();
+            desc.value().set(obj2->getDenseElement(JSID_TO_INT(id)));
         } else {
-            desc->attrs = shape->attributes();
-            desc->getter = shape->getter();
-            desc->setter = shape->setter();
+            desc.setAttributes(shape->attributes());
+            desc.setGetter(shape->getter());
+            desc.setSetter(shape->setter());
+            JS_ASSERT(desc.value().isUndefined());
             if (shape->hasSlot())
-                desc->value = obj2->nativeGetSlot(shape->slot());
-            else
-                desc->value.setUndefined();
+                desc.value().set(obj2->nativeGetSlot(shape->slot()));
         }
     } else {
         if (obj2->is<ProxyObject>()) {
             JSAutoResolveFlags rf(cx, flags);
             return own
                    ? Proxy::getOwnPropertyDescriptor(cx, obj2, id, desc, 0)
                    : Proxy::getPropertyDescriptor(cx, obj2, id, desc, 0);
         }
-        if (!JSObject::getGenericAttributes(cx, obj2, id, &desc->attrs))
+        if (!JSObject::getGenericAttributes(cx, obj2, id, &desc.attributesRef()))
             return false;
-        desc->getter = NULL;
-        desc->setter = NULL;
-        desc->value.setUndefined();
+        JS_ASSERT(desc.getter() == NULL);
+        JS_ASSERT(desc.setter() == NULL);
+        JS_ASSERT(desc.value().isUndefined());
     }
     return true;
 }
 
 JS_PUBLIC_API(bool)
 JS_GetPropertyDescriptorById(JSContext *cx, JSObject *objArg, jsid idArg, unsigned flags,
                              JSPropertyDescriptor *desc_)
 {
     RootedObject obj(cx, objArg);
     RootedId id(cx, idArg);
-    AutoPropertyDescriptorRooter desc(cx);
+    Rooted<PropertyDescriptor> desc(cx);
     if (!GetPropertyDescriptorById(cx, obj, id, flags, false, &desc))
         return false;
     *desc_ = desc;
     return true;
 }
 
 JS_PUBLIC_API(bool)
 JS_GetPropertyAttrsGetterAndSetterById(JSContext *cx, JSObject *objArg, jsid idArg,
                                        unsigned *attrsp, bool *foundp,
                                        JSPropertyOp *getterp, JSStrictPropertyOp *setterp)
 {
     RootedObject obj(cx, objArg);
     RootedId id(cx, idArg);
-    AutoPropertyDescriptorRooter desc(cx);
+    Rooted<PropertyDescriptor> desc(cx);
     if (!GetPropertyDescriptorById(cx, obj, id, 0, false, &desc))
         return false;
 
-    *attrsp = desc.attrs;
-    *foundp = (desc.obj != NULL);
+    *attrsp = desc.attributes();
+    *foundp = !!desc.object();
     if (getterp)
-        *getterp = desc.getter;
+        *getterp = desc.getter();
     if (setterp)
-        *setterp = desc.setter;
+        *setterp = desc.setter();
     return true;
 }
 
 JS_PUBLIC_API(bool)
 JS_GetPropertyAttributes(JSContext *cx, JSObject *objArg, const char *name,
                          unsigned *attrsp, bool *foundp)
 {
     RootedObject obj(cx, objArg);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3425,55 +3425,76 @@ struct JSPropertyDescriptor {
 };
 
 namespace JS {
 
 template <typename Outer>
 class PropertyDescriptorOperations
 {
     const JSPropertyDescriptor * desc() const { return static_cast<const Outer*>(this)->extract(); }
-    JSPropertyDescriptor * desc() { return static_cast<Outer*>(this)->extract(); }
 
   public:
     bool isEnumerable() const { return desc()->attrs & JSPROP_ENUMERATE; }
     bool isReadonly() const { return desc()->attrs & JSPROP_READONLY; }
     bool isPermanent() const { return desc()->attrs & JSPROP_PERMANENT; }
     bool hasNativeAccessors() const { return desc()->attrs & JSPROP_NATIVE_ACCESSORS; }
     bool hasGetterObject() const { return desc()->attrs & JSPROP_GETTER; }
     bool hasSetterObject() const { return desc()->attrs & JSPROP_SETTER; }
+    bool hasGetterOrSetterObject() const { return desc()->attrs & (JSPROP_GETTER | JSPROP_SETTER); }
     bool isShared() const { return desc()->attrs & JSPROP_SHARED; }
     bool isIndex() const { return desc()->attrs & JSPROP_INDEX; }
     bool hasShortId() const { return desc()->attrs & JSPROP_SHORTID; }
     bool hasAttributes(unsigned attrs) const { return desc()->attrs & attrs; }
 
-    JS::MutableHandle<JSObject*> object() {
-        return JS::MutableHandle<JSObject*>::fromMarkedLocation(&desc()->obj);
+    JS::Handle<JSObject*> object() const {
+        return JS::Handle<JSObject*>::fromMarkedLocation(&desc()->obj);
     }
     unsigned attributes() const { return desc()->attrs; }
-    unsigned shortid() const {
-        MOZ_ASSERT(hasShortId());
-        return desc()->shortid;
-    }
+    unsigned shortid() const { return desc()->shortid; }
     JSPropertyOp getter() const { return desc()->getter; }
     JSStrictPropertyOp setter() const { return desc()->setter; }
     JS::Handle<JSObject*> getterObject() const {
         MOZ_ASSERT(hasGetterObject());
         return JS::Handle<JSObject*>::fromMarkedLocation(
                 reinterpret_cast<JSObject *const *>(&desc()->getter));
     }
     JS::Handle<JSObject*> setterObject() const {
         MOZ_ASSERT(hasSetterObject());
         return JS::Handle<JSObject*>::fromMarkedLocation(
                 reinterpret_cast<JSObject *const *>(&desc()->setter));
     }
+    JS::Handle<Value> value() const {
+        return JS::Handle<Value>::fromMarkedLocation(&desc()->value);
+    }
+
+    bool isClear() const {
+        return desc()->obj == NULL && desc()->attrs == 0 && desc()->getter == NULL &&
+               desc()->setter == NULL && desc()->value.isUndefined();
+    }
+};
+
+template <typename Outer>
+class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations<Outer>
+{
+    JSPropertyDescriptor * desc() { return static_cast<Outer*>(this)->extractMutable(); }
+
+  public:
+    JS::MutableHandle<JSObject*> object() {
+        return JS::MutableHandle<JSObject*>::fromMarkedLocation(&desc()->obj);
+    }
+    unsigned &attributesRef() { return desc()->attrs; }
+    JSPropertyOp &getter() { return desc()->getter; }
+    JSStrictPropertyOp &setter() { return desc()->setter; }
     JS::MutableHandle<Value> value() {
         return JS::MutableHandle<Value>::fromMarkedLocation(&desc()->value);
     }
 
+    void setEnumerable() { desc()->attrs |= JSPROP_ENUMERATE; }
     void setAttributes(unsigned attrs) { desc()->attrs = attrs; }
+
     void setShortId(unsigned id) { desc()->shortid = id; }
     void setGetter(JSPropertyOp op) { desc()->getter = op; }
     void setSetter(JSStrictPropertyOp op) { desc()->setter = op; }
     void setGetterObject(JSObject *obj) { desc()->getter = reinterpret_cast<JSPropertyOp>(obj); }
     void setSetterObject(JSObject *obj) { desc()->setter = reinterpret_cast<JSStrictPropertyOp>(obj); }
 };
 
 } /* namespace JS */
@@ -3489,53 +3510,48 @@ struct GCMethods<JSPropertyDescriptor> {
                (desc.attrs & JSPROP_GETTER && desc.getter && JS::IsPoisonedPtr(desc.getter)) ||
                (desc.attrs & JSPROP_SETTER && desc.setter && JS::IsPoisonedPtr(desc.setter)) ||
                (desc.value.isGCThing() && JS::IsPoisonedPtr(desc.value.toGCThing()));
     }
 };
 
 template <>
 class RootedBase<JSPropertyDescriptor>
-  : public JS::PropertyDescriptorOperations<JS::Rooted<JSPropertyDescriptor> >
+  : public JS::MutablePropertyDescriptorOperations<JS::Rooted<JSPropertyDescriptor> >
 {
     friend class JS::PropertyDescriptorOperations<JS::Rooted<JSPropertyDescriptor> >;
+    friend class JS::MutablePropertyDescriptorOperations<JS::Rooted<JSPropertyDescriptor> >;
     const JSPropertyDescriptor *extract() const {
         return static_cast<const JS::Rooted<JSPropertyDescriptor>*>(this)->address();
     }
-    JSPropertyDescriptor *extract() {
+    JSPropertyDescriptor *extractMutable() {
         return static_cast<JS::Rooted<JSPropertyDescriptor>*>(this)->address();
     }
 };
 
 template <>
 class HandleBase<JSPropertyDescriptor>
   : public JS::PropertyDescriptorOperations<JS::Handle<JSPropertyDescriptor> >
 {
     friend class JS::PropertyDescriptorOperations<JS::Handle<JSPropertyDescriptor> >;
     const JSPropertyDescriptor *extract() const {
         return static_cast<const JS::Handle<JSPropertyDescriptor>*>(this)->address();
     }
-  public:
-    JS::Handle<JS::Value> value() const {
-        return JS::Handle<JS::Value>::fromMarkedLocation(&extract()->value);
-    }
-    JS::Handle<JSObject*> obj() const {
-        return JS::Handle<JSObject*>::fromMarkedLocation(&extract()->obj);
-    }
 };
 
 template <>
 class MutableHandleBase<JSPropertyDescriptor>
-  : public JS::PropertyDescriptorOperations<JS::MutableHandle<JSPropertyDescriptor> >
+  : public JS::MutablePropertyDescriptorOperations<JS::MutableHandle<JSPropertyDescriptor> >
 {
     friend class JS::PropertyDescriptorOperations<JS::MutableHandle<JSPropertyDescriptor> >;
+    friend class JS::MutablePropertyDescriptorOperations<JS::MutableHandle<JSPropertyDescriptor> >;
     const JSPropertyDescriptor *extract() const {
         return static_cast<const JS::MutableHandle<JSPropertyDescriptor>*>(this)->address();
     }
-    JSPropertyDescriptor *extract() {
+    JSPropertyDescriptor *extractMutable() {
         return static_cast<JS::MutableHandle<JSPropertyDescriptor>*>(this)->address();
     }
 };
 
 } /* namespace js */
 
 /*
  * Like JS_GetPropertyAttrsGetterAndSetterById but will return a property on
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -413,35 +413,31 @@ JSCompartment::wrap(JSContext *cx, Stric
     RootedValue value(cx, CastAsObjectJsval(*propp));
     if (!wrap(cx, &value))
         return false;
     *propp = CastAsStrictPropertyOp(value.toObjectOrNull());
     return true;
 }
 
 bool
-JSCompartment::wrap(JSContext *cx, PropertyDescriptor *desc)
+JSCompartment::wrap(JSContext *cx, MutableHandle<PropertyDescriptor> desc)
 {
-    if (!wrap(cx, &desc->obj))
+    if (!wrap(cx, desc.object().address()))
         return false;
 
-    if (desc->attrs & JSPROP_GETTER) {
-        if (!wrap(cx, &desc->getter))
+    if (desc.hasGetterObject()) {
+        if (!wrap(cx, &desc.getter()))
             return false;
     }
-    if (desc->attrs & JSPROP_SETTER) {
-        if (!wrap(cx, &desc->setter))
+    if (desc.hasSetterObject()) {
+        if (!wrap(cx, &desc.setter()))
             return false;
     }
 
-    RootedValue value(cx, desc->value);
-    if (!wrap(cx, &value))
-        return false;
-    desc->value = value.get();
-    return true;
+    return wrap(cx, desc.value());
 }
 
 bool
 JSCompartment::wrap(JSContext *cx, AutoIdVector &props)
 {
     jsid *vector = props.begin();
     int length = props.length();
     for (size_t n = 0; n < size_t(length); ++n) {
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -290,17 +290,17 @@ struct JSCompartment
 
     bool wrap(JSContext *cx, JS::MutableHandleValue vp, JS::HandleObject existing = js::NullPtr());
     bool wrap(JSContext *cx, JSString **strp);
     bool wrap(JSContext *cx, js::HeapPtrString *strp);
     bool wrap(JSContext *cx, JSObject **objp, JSObject *existing = NULL);
     bool wrapId(JSContext *cx, jsid *idp);
     bool wrap(JSContext *cx, js::PropertyOp *op);
     bool wrap(JSContext *cx, js::StrictPropertyOp *op);
-    bool wrap(JSContext *cx, js::PropertyDescriptor *desc);
+    bool wrap(JSContext *cx, JS::MutableHandle<js::PropertyDescriptor> desc);
     bool wrap(JSContext *cx, js::AutoIdVector &props);
 
     bool putWrapper(const js::CrossCompartmentKey& wrapped, const js::Value& wrapper);
 
     js::WrapperMap::Ptr lookupWrapper(const js::Value& wrapped) {
         return crossCompartmentWrappers.lookup(wrapped);
     }
 
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -238,19 +238,22 @@ JS_SetCompartmentPrincipals(JSCompartmen
         compartment->principals = principals;
     }
 
     // Update the system flag.
     compartment->isSystem = isSystem;
 }
 
 JS_FRIEND_API(bool)
-JS_WrapPropertyDescriptor(JSContext *cx, js::PropertyDescriptor *desc)
+JS_WrapPropertyDescriptor(JSContext *cx, js::PropertyDescriptor *descArg)
 {
-    return cx->compartment()->wrap(cx, desc);
+    Rooted<PropertyDescriptor> desc(cx, *descArg);
+    bool status = cx->compartment()->wrap(cx, &desc);
+    *descArg = desc;
+    return status;
 }
 
 JS_FRIEND_API(bool)
 JS_WrapAutoIdVector(JSContext *cx, js::AutoIdVector &props)
 {
     return cx->compartment()->wrap(cx, props);
 }
 
@@ -1099,27 +1102,28 @@ js::SetObjectMetadata(JSContext *cx, Han
 JS_FRIEND_API(JSObject *)
 js::GetObjectMetadata(JSObject *obj)
 {
     return obj->getMetadata();
 }
 
 JS_FRIEND_API(bool)
 js_DefineOwnProperty(JSContext *cx, JSObject *objArg, jsid idArg,
-                     const js::PropertyDescriptor& descriptor, bool *bp)
+                     const js::PropertyDescriptor& descriptorArg, bool *bp)
 {
     RootedObject obj(cx, objArg);
     RootedId id(cx, idArg);
+    Rooted<PropertyDescriptor> descriptor(cx, descriptorArg);
     JS_ASSERT(cx->runtime()->heapState == js::Idle);
     CHECK_REQUEST(cx);
-    assertSameCompartment(cx, obj, id, descriptor.value);
-    if (descriptor.attrs & JSPROP_GETTER)
-        assertSameCompartment(cx, CastAsObjectJsval(descriptor.getter));
-    if (descriptor.attrs & JSPROP_SETTER)
-        assertSameCompartment(cx, CastAsObjectJsval(descriptor.setter));
+    assertSameCompartment(cx, obj, id, descriptor.value());
+    if (descriptor.hasGetterObject())
+        assertSameCompartment(cx, descriptor.getterObject());
+    if (descriptor.hasSetterObject())
+        assertSameCompartment(cx, descriptor.setterObject());
 
     return DefineOwnProperty(cx, HandleObject(obj), id, descriptor, bp);
 }
 
 JS_FRIEND_API(bool)
 js_ReportIsNotFunction(JSContext *cx, const JS::Value& v)
 {
     return ReportIsNotFunction(cx, v);
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -180,60 +180,60 @@ js::HasOwnProperty<CanGC>(JSContext *cx,
                           MutableHandleObject objp, MutableHandleShape propp);
 
 template bool
 js::HasOwnProperty<NoGC>(JSContext *cx, LookupGenericOp lookup,
                          JSObject *obj, jsid id,
                          FakeMutableHandle<JSObject*> objp, FakeMutableHandle<Shape*> propp);
 
 bool
-js::NewPropertyDescriptorObject(JSContext *cx, const PropertyDescriptor *desc,
+js::NewPropertyDescriptorObject(JSContext *cx, Handle<PropertyDescriptor> desc,
                                 MutableHandleValue vp)
 {
-    if (!desc->obj) {
+    if (!desc.object()) {
         vp.setUndefined();
         return true;
     }
 
     /* We have our own property, so start creating the descriptor. */
     AutoPropDescRooter d(cx);
 
-    d.initFromPropertyDescriptor(*desc);
+    d.initFromPropertyDescriptor(desc);
     if (!d.makeObject(cx))
         return false;
     vp.set(d.pd());
     return true;
 }
 
 void
-PropDesc::initFromPropertyDescriptor(const PropertyDescriptor &desc)
+PropDesc::initFromPropertyDescriptor(Handle<PropertyDescriptor> desc)
 {
     isUndefined_ = false;
     pd_.setUndefined();
-    attrs = uint8_t(desc.attrs);
+    attrs = uint8_t(desc.attributes());
     JS_ASSERT_IF(attrs & JSPROP_READONLY, !(attrs & (JSPROP_GETTER | JSPROP_SETTER)));
-    if (desc.attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
+    if (desc.hasGetterOrSetterObject()) {
         hasGet_ = true;
-        get_ = ((desc.attrs & JSPROP_GETTER) && desc.getter)
-               ? CastAsObjectJsval(desc.getter)
+        get_ = desc.hasGetterObject() && desc.getterObject()
+               ? ObjectValue(*desc.getterObject())
                : UndefinedValue();
         hasSet_ = true;
-        set_ = ((desc.attrs & JSPROP_SETTER) && desc.setter)
-               ? CastAsObjectJsval(desc.setter)
+        set_ = desc.hasSetterObject() && desc.setterObject()
+               ? ObjectValue(*desc.setterObject())
                : UndefinedValue();
         hasValue_ = false;
         value_.setUndefined();
         hasWritable_ = false;
     } else {
         hasGet_ = false;
         get_.setUndefined();
         hasSet_ = false;
         set_.setUndefined();
         hasValue_ = true;
-        value_ = desc.value;
+        value_ = desc.value();
         hasWritable_ = true;
     }
     hasEnumerable_ = true;
     hasConfigurable_ = true;
 }
 
 bool
 PropDesc::makeObject(JSContext *cx)
@@ -265,61 +265,61 @@ PropDesc::makeObject(JSContext *cx)
     }
 
     pd_.setObject(*obj);
     return true;
 }
 
 bool
 js::GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
-                             PropertyDescriptor *desc)
+                             MutableHandle<PropertyDescriptor> desc)
 {
     // FIXME: Call TrapGetOwnProperty directly once ScriptedIndirectProxies is removed
     if (obj->is<ProxyObject>())
         return Proxy::getOwnPropertyDescriptor(cx, obj, id, desc, 0);
 
     RootedObject pobj(cx);
     RootedShape shape(cx);
     if (!HasOwnProperty<CanGC>(cx, obj->getOps()->lookupGeneric, obj, id, &pobj, &shape))
         return false;
     if (!shape) {
-        desc->obj = NULL;
+        desc.object().set(NULL);
         return true;
     }
 
     bool doGet = true;
     if (pobj->isNative()) {
-        desc->attrs = GetShapeAttributes(shape);
-        if (desc->attrs & (JSPROP_GETTER | JSPROP_SETTER)) {
+        desc.setAttributes(GetShapeAttributes(shape));
+        if (desc.hasGetterOrSetterObject()) {
             doGet = false;
-            if (desc->attrs & JSPROP_GETTER)
-                desc->getter = CastAsPropertyOp(shape->getterObject());
-            if (desc->attrs & JSPROP_SETTER)
-                desc->setter = CastAsStrictPropertyOp(shape->setterObject());
+            if (desc.hasGetterObject())
+                desc.setGetterObject(shape->getterObject());
+            if (desc.hasSetterObject())
+                desc.setSetterObject(shape->setterObject());
         }
     } else {
-        if (!JSObject::getGenericAttributes(cx, pobj, id, &desc->attrs))
+        if (!JSObject::getGenericAttributes(cx, pobj, id, &desc.attributesRef()))
             return false;
     }
 
     RootedValue value(cx);
     if (doGet && !JSObject::getGeneric(cx, obj, obj, id, &value))
         return false;
 
-    desc->value = value;
-    desc->obj = obj;
+    desc.value().set(value);
+    desc.object().set(obj);
     return true;
 }
 
 bool
 js::GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
 {
-    AutoPropertyDescriptorRooter desc(cx);
+    Rooted<PropertyDescriptor> desc(cx);
     return GetOwnPropertyDescriptor(cx, obj, id, &desc) &&
-           NewPropertyDescriptorObject(cx, &desc, vp);
+           NewPropertyDescriptorObject(cx, desc, vp);
 }
 
 bool
 js::GetFirstArgumentAsObject(JSContext *cx, const CallArgs &args, const char *method,
                              MutableHandleObject objp)
 {
     if (args.length() == 0) {
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MORE_ARGS_NEEDED,
@@ -563,39 +563,39 @@ JS_FRIEND_API(bool)
 js::CheckDefineProperty(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
                         PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
     if (!obj->isNative())
         return true;
 
     // ES5 8.12.9 Step 1. Even though we know obj is native, we use generic
     // APIs for shorter, more readable code.
-    AutoPropertyDescriptorRooter desc(cx);
+    Rooted<PropertyDescriptor> desc(cx);
     if (!GetOwnPropertyDescriptor(cx, obj, id, &desc))
         return false;
 
     // This does not have to check obj's extensibility when !desc.obj (steps
     // 2-3) because the low-level methods JSObject::{add,put}Property check
     // for that.
-    if (desc.obj && (desc.attrs & JSPROP_PERMANENT)) {
+    if (desc.object() && desc.isPermanent()) {
         // Steps 6-11, skipping step 10.a.ii. Prohibit redefining a permanent
         // property with different metadata, except to make a writable property
         // non-writable.
-        if (getter != desc.getter ||
-            setter != desc.setter ||
-            (attrs != desc.attrs && attrs != (desc.attrs | JSPROP_READONLY)))
+        if (getter != desc.getter() ||
+            setter != desc.setter() ||
+            (attrs != desc.attributes() && attrs != (desc.attributes() | JSPROP_READONLY)))
         {
             return Throw(cx, id, JSMSG_CANT_REDEFINE_PROP);
         }
 
         // Step 10.a.ii. Prohibit changing the value of a non-configurable,
         // non-writable data property.
-        if ((desc.attrs & (JSPROP_GETTER | JSPROP_SETTER | JSPROP_READONLY)) == JSPROP_READONLY) {
+        if ((desc.attributes() & (JSPROP_GETTER | JSPROP_SETTER | JSPROP_READONLY)) == JSPROP_READONLY) {
             bool same;
-            if (!SameValue(cx, value, desc.value, &same))
+            if (!SameValue(cx, value, desc.value(), &same))
                 return false;
             if (!same)
                 return JSObject::reportReadOnly(cx, id);
         }
     }
     return true;
 }
 
@@ -1019,17 +1019,17 @@ js::DefineOwnProperty(JSContext *cx, Han
     if (!DefineProperty(cx, obj, id, *desc, true, &rval))
         return false;
     *bp = !!rval;
     return true;
 }
 
 bool
 js::DefineOwnProperty(JSContext *cx, HandleObject obj, HandleId id,
-                      const PropertyDescriptor &descriptor, bool *bp)
+                      Handle<PropertyDescriptor> descriptor, bool *bp)
 {
     AutoPropDescArrayRooter descs(cx);
     PropDesc *desc = descs.append();
     if (!desc)
         return false;
 
     desc->initFromPropertyDescriptor(descriptor);
 
@@ -4543,27 +4543,27 @@ baseops::SetPropertyHelper(JSContext *cx
 
     RootedObject pobj(cx);
     RootedShape shape(cx);
     if (!LookupPropertyWithFlags(cx, obj, id, cx->resolveFlags, &pobj, &shape))
         return false;
     if (shape) {
         if (!pobj->isNative()) {
             if (pobj->is<ProxyObject>()) {
-                AutoPropertyDescriptorRooter pd(cx);
+                Rooted<PropertyDescriptor> pd(cx);
                 if (!Proxy::getPropertyDescriptor(cx, pobj, id, &pd, JSRESOLVE_ASSIGNING))
                     return false;
 
-                if ((pd.attrs & (JSPROP_SHARED | JSPROP_SHADOWABLE)) == JSPROP_SHARED) {
-                    return !pd.setter ||
-                           CallSetter(cx, receiver, id, pd.setter, pd.attrs, pd.shortid, strict,
-                                      vp);
+                if ((pd.attributes() & (JSPROP_SHARED | JSPROP_SHADOWABLE)) == JSPROP_SHARED) {
+                    return !pd.setter() ||
+                           CallSetter(cx, receiver, id, pd.setter(), pd.attributes(),
+                                      pd.shortid(), strict, vp);
                 }
 
-                if (pd.attrs & JSPROP_READONLY) {
+                if (pd.isReadonly()) {
                     if (strict)
                         return JSObject::reportReadOnly(cx, id, JSREPORT_ERROR);
                     if (cx->hasExtraWarningsOption())
                         return JSObject::reportReadOnly(cx, id, JSREPORT_STRICT | JSREPORT_WARNING);
                     return true;
                 }
             }
 
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1163,17 +1163,17 @@ js_AddNativeProperty(JSContext *cx, JS::
 namespace js {
 
 extern bool
 DefineOwnProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                   JS::HandleValue descriptor, bool *bp);
 
 extern bool
 DefineOwnProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
-                  const js::PropertyDescriptor &descriptor, bool *bp);
+                  JS::Handle<js::PropertyDescriptor> descriptor, bool *bp);
 
 /*
  * The NewObjectKind allows an allocation site to specify the type properties
  * and lifetime requirements that must be fixed at allocation time.
  */
 enum NewObjectKind {
     /* This is the default. Most objects are generic. */
     GenericObject,
@@ -1338,23 +1338,24 @@ GetPropertyPure(ThreadSafeContext *cx, J
 
 inline bool
 GetPropertyPure(ThreadSafeContext *cx, JSObject *obj, PropertyName *name, Value *vp)
 {
     return GetPropertyPure(cx, obj, NameToId(name), vp);
 }
 
 bool
-GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, PropertyDescriptor *desc);
+GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id,
+                         MutableHandle<PropertyDescriptor> desc);
 
 bool
 GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp);
 
 bool
-NewPropertyDescriptorObject(JSContext *cx, const PropertyDescriptor *desc, MutableHandleValue vp);
+NewPropertyDescriptorObject(JSContext *cx, Handle<PropertyDescriptor> desc, MutableHandleValue vp);
 
 /*
  * If obj has an already-resolved data property for id, return true and
  * store the property value in *vp.
  */
 extern bool
 HasDataProperty(JSContext *cx, JSObject *obj, jsid id, Value *vp);
 
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -90,64 +90,65 @@ BaseProxyHandler::enter(JSContext *cx, H
     *bp = true;
     return true;
 }
 
 bool
 BaseProxyHandler::has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
 {
     assertEnteredPolicy(cx, proxy, id);
-    AutoPropertyDescriptorRooter desc(cx);
+    Rooted<PropertyDescriptor> desc(cx);
     if (!getPropertyDescriptor(cx, proxy, id, &desc, 0))
         return false;
-    *bp = !!desc.obj;
+    *bp = !!desc.object();
     return true;
 }
 
 bool
 BaseProxyHandler::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
 {
     assertEnteredPolicy(cx, proxy, id);
-    AutoPropertyDescriptorRooter desc(cx);
+    Rooted<PropertyDescriptor> desc(cx);
     if (!getOwnPropertyDescriptor(cx, proxy, id, &desc, 0))
         return false;
-    *bp = !!desc.obj;
+    *bp = !!desc.object();
     return true;
 }
 
 bool
 BaseProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
                       HandleId id, MutableHandleValue vp)
 {
     assertEnteredPolicy(cx, proxy, id);
 
-    AutoPropertyDescriptorRooter desc(cx);
+    Rooted<PropertyDescriptor> desc(cx);
     if (!getPropertyDescriptor(cx, proxy, id, &desc, 0))
         return false;
-    if (!desc.obj) {
+    if (!desc.object()) {
         vp.setUndefined();
         return true;
     }
-    if (!desc.getter ||
-        (!(desc.attrs & JSPROP_GETTER) && desc.getter == JS_PropertyStub)) {
-        vp.set(desc.value);
+    if (!desc.getter() ||
+        (!desc.hasGetterObject() && desc.getter() == JS_PropertyStub))
+    {
+        vp.set(desc.value());
         return true;
     }
-    if (desc.attrs & JSPROP_GETTER)
-        return InvokeGetterOrSetter(cx, receiver, CastAsObjectJsval(desc.getter), 0, NULL, vp);
-    if (!(desc.attrs & JSPROP_SHARED))
-        vp.set(desc.value);
+    if (desc.hasGetterObject())
+        return InvokeGetterOrSetter(cx, receiver, ObjectValue(*desc.getterObject()), 0, NULL, vp);
+    if (!desc.isShared())
+        vp.set(desc.value());
     else
         vp.setUndefined();
 
-    if (desc.attrs & JSPROP_SHORTID) {
-        RootedId id(cx, INT_TO_JSID(desc.shortid));
-        return CallJSPropertyOp(cx, desc.getter, receiver, id, vp);
+    if (desc.hasShortId()) {
+        RootedId id(cx, INT_TO_JSID(desc.shortid()));
+        return CallJSPropertyOp(cx, desc.getter(), receiver, id, vp);
     }
-    return CallJSPropertyOp(cx, desc.getter, receiver, id, vp);
+    return CallJSPropertyOp(cx, desc.getter(), receiver, id, vp);
 }
 
 bool
 BaseProxyHandler::getElementIfPresent(JSContext *cx, HandleObject proxy, HandleObject receiver,
                                       uint32_t index, MutableHandleValue vp, bool *present)
 {
     RootedId id(cx);
     if (!IndexToId(cx, index, &id))
@@ -167,102 +168,102 @@ BaseProxyHandler::getElementIfPresent(JS
 }
 
 bool
 BaseProxyHandler::set(JSContext *cx, HandleObject proxy, HandleObject receiver,
                       HandleId id, bool strict, MutableHandleValue vp)
 {
     assertEnteredPolicy(cx, proxy, id);
 
-    AutoPropertyDescriptorRooter desc(cx);
+    Rooted<PropertyDescriptor> desc(cx);
     if (!getOwnPropertyDescriptor(cx, proxy, id, &desc, JSRESOLVE_ASSIGNING))
         return false;
     /* The control-flow here differs from ::get() because of the fall-through case below. */
-    if (desc.obj) {
+    if (desc.object()) {
         // Check for read-only properties.
-        if (desc.attrs & JSPROP_READONLY)
+        if (desc.isReadonly())
             return strict ? Throw(cx, id, JSMSG_CANT_REDEFINE_PROP) : true;
-        if (!desc.setter) {
+        if (!desc.setter()) {
             // Be wary of the odd explicit undefined setter case possible through
             // Object.defineProperty.
-            if (!(desc.attrs & JSPROP_SETTER))
-                desc.setter = JS_StrictPropertyStub;
-        } else if ((desc.attrs & JSPROP_SETTER) || desc.setter != JS_StrictPropertyStub) {
-            if (!CallSetter(cx, receiver, id, desc.setter, desc.attrs, desc.shortid, strict, vp))
+            if (!desc.hasSetterObject())
+                desc.setSetter(JS_StrictPropertyStub);
+        } else if (desc.hasSetterObject() || desc.setter() != JS_StrictPropertyStub) {
+            if (!CallSetter(cx, receiver, id, desc.setter(), desc.attributes(), desc.shortid(), strict, vp))
                 return false;
             if (!proxy->is<ProxyObject>() || proxy->as<ProxyObject>().handler() != this)
                 return true;
-            if (desc.attrs & JSPROP_SHARED)
+            if (desc.isShared())
                 return true;
         }
-        if (!desc.getter) {
+        if (!desc.getter()) {
             // Same as above for the null setter case.
-            if (!(desc.attrs & JSPROP_GETTER))
-                desc.getter = JS_PropertyStub;
+            if (!desc.hasGetterObject())
+                desc.setGetter(JS_PropertyStub);
         }
-        desc.value = vp.get();
+        desc.value().set(vp.get());
         return defineProperty(cx, receiver, id, &desc);
     }
     if (!getPropertyDescriptor(cx, proxy, id, &desc, JSRESOLVE_ASSIGNING))
         return false;
-    if (desc.obj) {
+    if (desc.object()) {
         // Check for read-only properties.
-        if (desc.attrs & JSPROP_READONLY)
+        if (desc.isReadonly())
             return strict ? Throw(cx, id, JSMSG_CANT_REDEFINE_PROP) : true;
-        if (!desc.setter) {
+        if (!desc.setter()) {
             // Be wary of the odd explicit undefined setter case possible through
             // Object.defineProperty.
-            if (!(desc.attrs & JSPROP_SETTER))
-                desc.setter = JS_StrictPropertyStub;
-        } else if ((desc.attrs & JSPROP_SETTER) || desc.setter != JS_StrictPropertyStub) {
-            if (!CallSetter(cx, receiver, id, desc.setter, desc.attrs, desc.shortid, strict, vp))
+            if (!desc.hasSetterObject())
+                desc.setSetter(JS_StrictPropertyStub);
+        } else if (desc.hasSetterObject() || desc.setter() != JS_StrictPropertyStub) {
+            if (!CallSetter(cx, receiver, id, desc.setter(), desc.attributes(), desc.shortid(), strict, vp))
                 return false;
             if (!proxy->is<ProxyObject>() || proxy->as<ProxyObject>().handler() != this)
                 return true;
-            if (desc.attrs & JSPROP_SHARED)
+            if (desc.isShared())
                 return true;
         }
-        if (!desc.getter) {
+        if (!desc.getter()) {
             // Same as above for the null setter case.
-            if (!(desc.attrs & JSPROP_GETTER))
-                desc.getter = JS_PropertyStub;
+            if (!desc.hasGetterObject())
+                desc.setGetter(JS_PropertyStub);
         }
-        desc.value = vp.get();
+        desc.value().set(vp.get());
         return defineProperty(cx, receiver, id, &desc);
     }
 
-    desc.obj = receiver;
-    desc.value = vp.get();
-    desc.attrs = JSPROP_ENUMERATE;
-    desc.shortid = 0;
-    desc.getter = NULL;
-    desc.setter = NULL; // Pick up the class getter/setter.
+    desc.object().set(receiver);
+    desc.value().set(vp.get());
+    desc.setAttributes(JSPROP_ENUMERATE);
+    desc.setShortId(0);
+    desc.setGetter(NULL);
+    desc.setSetter(NULL); // Pick up the class getter/setter.
     return defineProperty(cx, receiver, id, &desc);
 }
 
 bool
 BaseProxyHandler::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
 {
     assertEnteredPolicy(cx, proxy, JSID_VOID);
     JS_ASSERT(props.length() == 0);
 
     if (!getOwnPropertyNames(cx, proxy, props))
         return false;
 
     /* Select only the enumerable properties through in-place iteration. */
-    AutoPropertyDescriptorRooter desc(cx);
+    Rooted<PropertyDescriptor> desc(cx);
     RootedId id(cx);
     size_t i = 0;
     for (size_t j = 0, len = props.length(); j < len; j++) {
         JS_ASSERT(i <= j);
         id = props[j];
         AutoWaivePolicy policy(cx, proxy, id);
         if (!getOwnPropertyDescriptor(cx, proxy, id, &desc, 0))
             return false;
-        if (desc.obj && (desc.attrs & JSPROP_ENUMERATE))
+        if (desc.object() && desc.isEnumerable())
             props[i++] = id;
     }
 
     JS_ASSERT(i <= props.length());
     props.resize(i);
 
     return true;
 }
@@ -360,58 +361,59 @@ BaseProxyHandler::getPrototypeOf(JSConte
     // The default implementation here just uses proto of the proxy object.
     protop.set(proxy->getTaggedProto().toObjectOrNull());
     return true;
 }
 
 
 bool
 DirectProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                          PropertyDescriptor *desc, unsigned flags)
+                                          MutableHandle<PropertyDescriptor> desc, unsigned flags)
 {
     assertEnteredPolicy(cx, proxy, id);
     JS_ASSERT(!hasPrototype()); // Should never be called if there's a prototype.
     RootedObject target(cx, proxy->as<ProxyObject>().target());
-    return JS_GetPropertyDescriptorById(cx, target, id, 0, desc);
+    return JS_GetPropertyDescriptorById(cx, target, id, 0, desc.address());
 }
 
 static bool
 GetOwnPropertyDescriptor(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
-                         JSPropertyDescriptor *desc)
+                         MutableHandle<PropertyDescriptor> desc)
 {
     // If obj is a proxy, we can do better than just guessing. This is
     // important for certain types of wrappers that wrap other wrappers.
     if (obj->is<ProxyObject>())
         return Proxy::getOwnPropertyDescriptor(cx, obj, id, desc, flags);
 
-    if (!JS_GetPropertyDescriptorById(cx, obj, id, flags, desc))
+    if (!JS_GetPropertyDescriptorById(cx, obj, id, flags, desc.address()))
         return false;
-    if (desc->obj != obj)
-        desc->obj = NULL;
+    if (desc.object() != obj)
+        desc.object().set(NULL);
     return true;
 }
 
 bool
 DirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy,
-                                             HandleId id, PropertyDescriptor *desc, unsigned flags)
+                                             HandleId id, MutableHandle<PropertyDescriptor> desc,
+                                             unsigned flags)
 {
     assertEnteredPolicy(cx, proxy, id);
     RootedObject target(cx, proxy->as<ProxyObject>().target());
     return GetOwnPropertyDescriptor(cx, target, id, 0, desc);
 }
 
 bool
 DirectProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                   PropertyDescriptor *desc)
+                                   MutableHandle<PropertyDescriptor> desc)
 {
     assertEnteredPolicy(cx, proxy, id);
     RootedObject target(cx, proxy->as<ProxyObject>().target());
-    RootedValue v(cx, desc->value);
-    return CheckDefineProperty(cx, target, id, v, desc->getter, desc->setter, desc->attrs) &&
-           JS_DefinePropertyById(cx, target, id, v, desc->getter, desc->setter, desc->attrs);
+    RootedValue v(cx, desc.value());
+    return CheckDefineProperty(cx, target, id, v, desc.getter(), desc.setter(), desc.attributes()) &&
+           JS_DefinePropertyById(cx, target, id, v, desc.getter(), desc.setter(), desc.attributes());
 }
 
 bool
 DirectProxyHandler::getOwnPropertyNames(JSContext *cx, HandleObject proxy,
                                         AutoIdVector &props)
 {
     assertEnteredPolicy(cx, proxy, JSID_VOID);
     RootedObject target(cx, proxy->as<ProxyObject>().target());
@@ -546,20 +548,20 @@ DirectProxyHandler::has(JSContext *cx, H
     return true;
 }
 
 bool
 DirectProxyHandler::hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp)
 {
     assertEnteredPolicy(cx, proxy, id);
     RootedObject target(cx, proxy->as<ProxyObject>().target());
-    AutoPropertyDescriptorRooter desc(cx);
-    if (!JS_GetPropertyDescriptorById(cx, target, id, 0, &desc))
+    Rooted<PropertyDescriptor> desc(cx);
+    if (!JS_GetPropertyDescriptorById(cx, target, id, 0, desc.address()))
         return false;
-    *bp = (desc.obj == target);
+    *bp = (desc.object() == target);
     return true;
 }
 
 bool
 DirectProxyHandler::get(JSContext *cx, HandleObject proxy, HandleObject receiver,
                         HandleId id, MutableHandleValue vp)
 {
     assertEnteredPolicy(cx, proxy, id);
@@ -661,38 +663,38 @@ Trap2(JSContext *cx, HandleObject handle
     rval.setString(str);
     Value argv[2] = { rval.get(), v };
     AutoValueArray ava(cx, argv, 2);
     return Trap(cx, handler, fval, 2, argv, rval);
 }
 
 static bool
 ParsePropertyDescriptorObject(JSContext *cx, HandleObject obj, const Value &v,
-                              PropertyDescriptor *desc, bool complete = false)
+                              MutableHandle<PropertyDescriptor> desc, bool complete = false)
 {
     AutoPropDescArrayRooter descs(cx);
     PropDesc *d = descs.append();
     if (!d || !d->initialize(cx, v))
         return false;
     if (complete)
         d->complete();
-    desc->obj = obj;
-    desc->value = d->hasValue() ? d->value() : UndefinedValue();
+    desc.object().set(obj);
+    desc.value().set(d->hasValue() ? d->value() : UndefinedValue());
     JS_ASSERT(!(d->attributes() & JSPROP_SHORTID));
-    desc->attrs = d->attributes();
-    desc->getter = d->getter();
-    desc->setter = d->setter();
-    desc->shortid = 0;
+    desc.setAttributes(d->attributes());
+    desc.setGetter(d->getter());
+    desc.setSetter(d->setter());
+    desc.setShortId(0);
     return true;
 }
 
 static bool
-IndicatePropertyNotFound(PropertyDescriptor *desc)
+IndicatePropertyNotFound(MutableHandle<PropertyDescriptor> desc)
 {
-    desc->obj = NULL;
+    desc.object().set(NULL);
     return true;
 }
 
 static bool
 ValueToBool(const Value &v, bool *bp)
 {
     *bp = ToBoolean(v);
     return true;
@@ -747,21 +749,23 @@ class ScriptedIndirectProxyHandler : pub
 {
   public:
     ScriptedIndirectProxyHandler();
     virtual ~ScriptedIndirectProxyHandler();
 
     /* ES5 Harmony fundamental proxy traps. */
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                       PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
+                                       MutableHandle<PropertyDescriptor> desc,
+                                       unsigned flags) MOZ_OVERRIDE;
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                          PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
+                                          MutableHandle<PropertyDescriptor> desc,
+                                          unsigned flags) MOZ_OVERRIDE;
     virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                PropertyDescriptor *desc) MOZ_OVERRIDE;
+                                MutableHandle<PropertyDescriptor> desc) MOZ_OVERRIDE;
     virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props);
     virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
     virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) MOZ_OVERRIDE;
 
     /* ES5 Harmony derived proxy traps. */
     virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
     virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
@@ -830,43 +834,45 @@ ReturnedValueMustNotBePrimitive(JSContex
 static JSObject *
 GetIndirectProxyHandlerObject(JSObject *proxy)
 {
     return proxy->as<ProxyObject>().private_().toObjectOrNull();
 }
 
 bool
 ScriptedIndirectProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                                    PropertyDescriptor *desc, unsigned flags)
+                                                    MutableHandle<PropertyDescriptor> desc,
+                                                    unsigned flags)
 {
     RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
     RootedValue fval(cx), value(cx);
     return GetFundamentalTrap(cx, handler, cx->names().getPropertyDescriptor, &fval) &&
            Trap1(cx, handler, fval, id, &value) &&
            ((value.get().isUndefined() && IndicatePropertyNotFound(desc)) ||
             (ReturnedValueMustNotBePrimitive(cx, proxy, cx->names().getPropertyDescriptor, value) &&
              ParsePropertyDescriptorObject(cx, proxy, value, desc)));
 }
 
 bool
 ScriptedIndirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                                       PropertyDescriptor *desc, unsigned flags)
+                                                       MutableHandle<PropertyDescriptor> desc,
+                                                       unsigned flags)
 {
     RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
     RootedValue fval(cx), value(cx);
     return GetFundamentalTrap(cx, handler, cx->names().getOwnPropertyDescriptor, &fval) &&
            Trap1(cx, handler, fval, id, &value) &&
            ((value.get().isUndefined() && IndicatePropertyNotFound(desc)) ||
             (ReturnedValueMustNotBePrimitive(cx, proxy, cx->names().getPropertyDescriptor, value) &&
              ParsePropertyDescriptorObject(cx, proxy, value, desc)));
 }
 
 bool
 ScriptedIndirectProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                             PropertyDescriptor *desc)
+                                             MutableHandle<PropertyDescriptor> desc)
 {
     RootedObject handler(cx, GetIndirectProxyHandlerObject(proxy));
     RootedValue fval(cx), value(cx);
     return GetFundamentalTrap(cx, handler, cx->names().defineProperty, &fval) &&
            NewPropertyDescriptorObject(cx, desc, &value) &&
            Trap2(cx, handler, fval, id, value, &value);
 }
 
@@ -1058,21 +1064,23 @@ GetDirectProxyHandlerObject(JSObject *pr
 class ScriptedDirectProxyHandler : public DirectProxyHandler {
   public:
     ScriptedDirectProxyHandler();
     virtual ~ScriptedDirectProxyHandler();
 
     /* ES5 Harmony fundamental proxy traps. */
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                       PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
+                                       MutableHandle<PropertyDescriptor> desc,
+                                       unsigned flags) MOZ_OVERRIDE;
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                          PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
+                                          MutableHandle<PropertyDescriptor> desc,
+                                          unsigned flags) MOZ_OVERRIDE;
     virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                PropertyDescriptor *desc) MOZ_OVERRIDE;
+                                MutableHandle<PropertyDescriptor> desc) MOZ_OVERRIDE;
     virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props);
     virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
     virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) MOZ_OVERRIDE;
 
     /* ES5 Harmony derived proxy traps. */
     virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx,HandleObject proxy, HandleId id, bool *bp) MOZ_OVERRIDE;
     virtual bool get(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id,
@@ -1193,135 +1201,135 @@ IsAccessorDescriptor(const PropertyDescr
     return desc.obj && desc.attrs & (JSPROP_GETTER | JSPROP_SETTER);
 }
 
 // Aux.5 ValidateProperty(O, P, Desc)
 static bool
 ValidateProperty(JSContext *cx, HandleObject obj, HandleId id, PropDesc *desc, bool *bp)
 {
     // step 1
-    AutoPropertyDescriptorRooter current(cx);
+    Rooted<PropertyDescriptor> current(cx);
     if (!GetOwnPropertyDescriptor(cx, obj, id, 0, &current))
         return false;
 
     /*
      * steps 2-4 are redundant since ValidateProperty is never called unless
      * target.[[HasOwn]](P) is true
      */
-    JS_ASSERT(current.obj);
+    JS_ASSERT(current.object());
 
     // step 5
     if (!desc->hasValue() && !desc->hasWritable() && !desc->hasGet() && !desc->hasSet() &&
         !desc->hasEnumerable() && !desc->hasConfigurable())
     {
         *bp = true;
         return true;
     }
 
     // step 6
-    if ((!desc->hasWritable() || desc->writable() == !(current.attrs & JSPROP_READONLY)) &&
-        (!desc->hasGet() || desc->getter() == current.getter) &&
-        (!desc->hasSet() || desc->setter() == current.setter) &&
-        (!desc->hasEnumerable() || desc->enumerable() == bool(current.attrs & JSPROP_ENUMERATE)) &&
-        (!desc->hasConfigurable() || desc->configurable() == !(current.attrs & JSPROP_PERMANENT)))
+    if ((!desc->hasWritable() || desc->writable() == !current.isReadonly()) &&
+        (!desc->hasGet() || desc->getter() == current.getter()) &&
+        (!desc->hasSet() || desc->setter() == current.setter()) &&
+        (!desc->hasEnumerable() || desc->enumerable() == current.isEnumerable()) &&
+        (!desc->hasConfigurable() || desc->configurable() == !current.isPermanent()))
     {
         if (!desc->hasValue()) {
             *bp = true;
             return true;
         }
         bool same = false;
-        if (!SameValue(cx, desc->value(), current.value, &same))
+        if (!SameValue(cx, desc->value(), current.value(), &same))
             return false;
         if (same) {
             *bp = true;
             return true;
         }
     }
 
     // step 7
-    if (current.attrs & JSPROP_PERMANENT) {
+    if (current.isPermanent()) {
         if (desc->hasConfigurable() && desc->configurable()) {
             *bp = false;
             return true;
         }
 
         if (desc->hasEnumerable() &&
-            desc->enumerable() != bool(current.attrs & JSPROP_ENUMERATE))
+            desc->enumerable() != current.isEnumerable())
         {
             *bp = false;
             return true;
         }
     }
 
     // step 8
     if (desc->isGenericDescriptor()) {
         *bp = true;
         return true;
     }
 
     // step 9
     if (IsDataDescriptor(current) != desc->isDataDescriptor()) {
-        *bp = !(current.attrs & JSPROP_PERMANENT);
+        *bp = !current.isPermanent();
         return true;
     }
 
     // step 10
     if (IsDataDescriptor(current)) {
         JS_ASSERT(desc->isDataDescriptor()); // by step 9
-        if ((current.attrs & JSPROP_PERMANENT) && (current.attrs & JSPROP_READONLY)) {
+        if (current.isPermanent() && current.isReadonly()) {
             if (desc->hasWritable() && desc->writable()) {
                 *bp = false;
                 return true;
             }
 
             if (desc->hasValue()) {
                 bool same;
-                if (!SameValue(cx, desc->value(), current.value, &same))
+                if (!SameValue(cx, desc->value(), current.value(), &same))
                     return false;
                 if (!same) {
                     *bp = false;
                     return true;
                 }
             }
         }
 
         *bp = true;
         return true;
     }
 
     // steps 11-12
     JS_ASSERT(IsAccessorDescriptor(current)); // by step 10
     JS_ASSERT(desc->isAccessorDescriptor()); // by step 9
-    *bp = (!(current.attrs & JSPROP_PERMANENT) ||
-           ((!desc->hasSet() || desc->setter() == current.setter) &&
-            (!desc->hasGet() || desc->getter() == current.getter)));
+    *bp = (!current.isPermanent() ||
+           ((!desc->hasSet() || desc->setter() == current.setter()) &&
+            (!desc->hasGet() || desc->getter() == current.getter())));
     return true;
 }
 
 // Aux.6 IsSealed(O, P)
 static bool
 IsSealed(JSContext* cx, HandleObject obj, HandleId id, bool *bp)
 {
     // step 1
-    AutoPropertyDescriptorRooter desc(cx);
+    Rooted<PropertyDescriptor> desc(cx);
     if (!GetOwnPropertyDescriptor(cx, obj, id, 0, &desc))
         return false;
 
     // steps 2-3
-    *bp = desc.obj && (desc.attrs & JSPROP_PERMANENT);
+    *bp = desc.object() && desc.isPermanent();
     return true;
 }
 
 static bool
 HasOwn(JSContext *cx, HandleObject obj, HandleId id, bool *bp)
 {
-    AutoPropertyDescriptorRooter desc(cx);
-    if (!JS_GetPropertyDescriptorById(cx, obj, id, 0, &desc))
+    Rooted<PropertyDescriptor> desc(cx);
+    if (!JS_GetPropertyDescriptorById(cx, obj, id, 0, desc.address()))
         return false;
-    *bp = (desc.obj == obj);
+    *bp = (desc.object() == obj);
     return true;
 }
 
 static bool
 IdToValue(JSContext *cx, HandleId id, MutableHandleValue value)
 {
     value.set(IdToValue(id)); // Re-use out-param to avoid Rooted overhead.
     JSString *name = ToString<CanGC>(cx, value);
@@ -1343,20 +1351,20 @@ TrapGetOwnProperty(JSContext *cx, Handle
 
     // step 3
     RootedValue trap(cx);
     if (!JSObject::getProperty(cx, handler, handler, cx->names().getOwnPropertyDescriptor, &trap))
         return false;
 
     // step 4
     if (trap.isUndefined()) {
-        AutoPropertyDescriptorRooter desc(cx);
+        Rooted<PropertyDescriptor> desc(cx);
         if (!GetOwnPropertyDescriptor(cx, target, id, &desc))
             return false;
-        return NewPropertyDescriptorObject(cx, &desc, rval);
+        return NewPropertyDescriptorObject(cx, desc, rval);
     }
 
     // step 5
     RootedValue value(cx);
     if (!IdToValue(cx, id, &value))
         return false;
     Value argv[] = {
         ObjectValue(*target),
@@ -1451,21 +1459,21 @@ TrapDefineOwnProperty(JSContext *cx, Han
 
     // step 3
     RootedValue trap(cx);
     if (!JSObject::getProperty(cx, handler, handler, cx->names().defineProperty, &trap))
         return false;
 
     // step 4
     if (trap.isUndefined()) {
-        AutoPropertyDescriptorRooter desc(cx);
+        Rooted<PropertyDescriptor> desc(cx);
         if (!ParsePropertyDescriptorObject(cx, proxy, vp, &desc))
             return false;
-        return JS_DefinePropertyById(cx, target, id, desc.value, desc.getter, desc.setter,
-                                     desc.attrs);
+        return JS_DefinePropertyById(cx, target, id, desc.value(), desc.getter(), desc.setter(),
+                                     desc.attributes());
     }
 
     // step 5
     RootedValue normalizedDesc(cx, vp);
     if (!NormalizePropertyDescriptor(cx, &normalizedDesc))
         return false;
 
     // step 6
@@ -1688,61 +1696,63 @@ ScriptedDirectProxyHandler::preventExten
     // step h
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CHANGE_EXTENSIBILITY);
     return false;
 }
 
 // FIXME: Move to Proxy::getPropertyDescriptor once ScriptedIndirectProxy is removed
 bool
 ScriptedDirectProxyHandler::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                                  PropertyDescriptor *desc, unsigned flags)
+                                                  MutableHandle<PropertyDescriptor> desc,
+                                                  unsigned flags)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     if (!GetOwnPropertyDescriptor(cx, proxy, id, desc))
         return false;
-    if (desc->obj)
+    if (desc.object())
         return true;
     RootedObject proto(cx);
     if (!JSObject::getProto(cx, proxy, &proto))
         return false;
     if (!proto) {
-        JS_ASSERT(!desc->obj);
+        JS_ASSERT(!desc.object());
         return true;
     }
-    return JS_GetPropertyDescriptorById(cx, proto, id, 0, desc);
+    return JS_GetPropertyDescriptorById(cx, proto, id, 0, desc.address());
 }
 
 bool
 ScriptedDirectProxyHandler::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                                     PropertyDescriptor *desc, unsigned flags)
+                                                     MutableHandle<PropertyDescriptor> desc,
+                                                     unsigned flags)
 {
     // step 1
     RootedValue v(cx);
     if (!TrapGetOwnProperty(cx, proxy, id, &v))
         return false;
 
     // step 2
     if (v.isUndefined()) {
-        desc->obj = NULL;
+        desc.object().set(NULL);
         return true;
     }
 
     // steps 3-4
     return ParsePropertyDescriptorObject(cx, proxy, v, desc, true);
 }
 
 bool
 ScriptedDirectProxyHandler::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                           PropertyDescriptor *desc)
+                                           MutableHandle<PropertyDescriptor> desc)
 {
     // step 1
     AutoPropDescArrayRooter descs(cx);
     PropDesc *d = descs.append();
-    d->initFromPropertyDescriptor(*desc);
+    d->initFromPropertyDescriptor(desc);
     RootedValue v(cx);
     if (!FromGenericPropertyDescriptor(cx, d, &v))
         return false;
 
     // step 2
     return TrapDefineOwnProperty(cx, proxy, id, &v);
 }
 
@@ -2047,39 +2057,33 @@ ScriptedDirectProxyHandler::get(JSContex
         value,
         ObjectOrNullValue(receiver)
     };
     RootedValue trapResult(cx);
     if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult))
         return false;
 
     // step 6
-    AutoPropertyDescriptorRooter desc(cx);
+    Rooted<PropertyDescriptor> desc(cx);
     if (!GetOwnPropertyDescriptor(cx, target, id, &desc))
         return false;
 
     // step 7
-    if (desc.obj) {
-        if (IsDataDescriptor(desc) &&
-            (desc.attrs & JSPROP_PERMANENT) &&
-            (desc.attrs & JSPROP_READONLY))
-        {
+    if (desc.object()) {
+        if (IsDataDescriptor(desc) && desc.isPermanent() && desc.isReadonly()) {
             bool same;
-            if (!SameValue(cx, vp, desc.value, &same))
+            if (!SameValue(cx, vp, desc.value(), &same))
                 return false;
             if (!same) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MUST_REPORT_SAME_VALUE);
                 return false;
             }
         }
 
-        if (IsAccessorDescriptor(desc) &&
-            (desc.attrs & JSPROP_PERMANENT) &&
-            !(desc.attrs & JSPROP_GETTER))
-        {
+        if (IsAccessorDescriptor(desc) && desc.isPermanent() && !desc.hasGetterObject()) {
             if (!trapResult.isUndefined()) {
                 JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_MUST_REPORT_UNDEFINED);
                 return false;
             }
         }
     }
 
     // step 8
@@ -2121,37 +2125,34 @@ ScriptedDirectProxyHandler::set(JSContex
     if (!Invoke(cx, ObjectValue(*handler), trap, ArrayLength(argv), argv, &trapResult))
         return false;
 
     // step 6
     bool success = ToBoolean(trapResult);
 
     // step 7
     if (success) {
-        AutoPropertyDescriptorRooter desc(cx);
+        Rooted<PropertyDescriptor> desc(cx);
         if (!GetOwnPropertyDescriptor(cx, target, id, &desc))
             return false;
 
-        if (desc.obj) {
-            if (IsDataDescriptor(desc) && (desc.attrs & JSPROP_PERMANENT) &&
-                (desc.attrs & JSPROP_READONLY)) {
+        if (desc.object()) {
+            if (IsDataDescriptor(desc) && desc.isPermanent() && desc.isReadonly()) {
                 bool same;
-                if (!SameValue(cx, vp, desc.value, &same))
+                if (!SameValue(cx, vp, desc.value(), &same))
                     return false;
                 if (!same) {
                     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_NW_NC);
                     return false;
                 }
             }
 
-            if (IsAccessorDescriptor(desc) && (desc.attrs & JSPROP_PERMANENT)) {
-                if (!(desc.attrs & JSPROP_SETTER)) {
-                    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_WO_SETTER);
-                    return false;
-                }
+            if (IsAccessorDescriptor(desc) && desc.isPermanent() && !desc.hasSetterObject()) {
+                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_SET_WO_SETTER);
+                return false;
             }
         }
     }
 
     // step 8
     vp.set(BooleanValue(success));
     return true;
 }
@@ -2291,88 +2292,89 @@ ScriptedDirectProxyHandler ScriptedDirec
         if (!proto)                                                          \
             return true;                                                     \
         assertSameCompartment(cx, proxy, proto);                             \
         return protoCall;                                                    \
     JS_END_MACRO                                                             \
 
 bool
 Proxy::getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                             PropertyDescriptor *desc, unsigned flags)
+                             MutableHandle<PropertyDescriptor> desc, unsigned flags)
 {
     JS_CHECK_RECURSION(cx, return false);
     BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
-    desc->obj = NULL; // default result if we refuse to perform this action
+    desc.object().set(NULL); // default result if we refuse to perform this action
     AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
     if (!policy.allowed())
         return policy.returnValue();
     if (!handler->hasPrototype())
         return handler->getPropertyDescriptor(cx, proxy, id, desc, flags);
     if (!handler->getOwnPropertyDescriptor(cx, proxy, id, desc, flags))
         return false;
-    if (desc->obj)
+    if (desc.object())
         return true;
     INVOKE_ON_PROTOTYPE(cx, handler, proxy,
-                        JS_GetPropertyDescriptorById(cx, proto, id, 0, desc));
+                        JS_GetPropertyDescriptorById(cx, proto, id, 0, desc.address()));
 }
 
 bool
 Proxy::getPropertyDescriptor(JSContext *cx, HandleObject proxy, unsigned flags,
                              HandleId id, MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
-    AutoPropertyDescriptorRooter desc(cx);
+    Rooted<PropertyDescriptor> desc(cx);
     if (!Proxy::getPropertyDescriptor(cx, proxy, id, &desc, flags))
         return false;
-    return NewPropertyDescriptorObject(cx, &desc, vp);
+    return NewPropertyDescriptorObject(cx, desc, vp);
 }
 
 bool
 Proxy::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                PropertyDescriptor *desc, unsigned flags)
+                                MutableHandle<PropertyDescriptor> desc, unsigned flags)
 {
     JS_CHECK_RECURSION(cx, return false);
 
     BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
-    desc->obj = NULL; // default result if we refuse to perform this action
+    desc.object().set(NULL); // default result if we refuse to perform this action
     AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::GET, true);
     if (!policy.allowed())
         return policy.returnValue();
     return handler->getOwnPropertyDescriptor(cx, proxy, id, desc, flags);
 }
 
 bool
 Proxy::getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, unsigned flags, HandleId id,
                                 MutableHandleValue vp)
 {
     JS_CHECK_RECURSION(cx, return false);
 
-    AutoPropertyDescriptorRooter desc(cx);
+    Rooted<PropertyDescriptor> desc(cx);
     if (!Proxy::getOwnPropertyDescriptor(cx, proxy, id, &desc, flags))
         return false;
-    return NewPropertyDescriptorObject(cx, &desc, vp);
+    return NewPropertyDescriptorObject(cx, desc, vp);
 }
 
 bool
-Proxy::defineProperty(JSContext *cx, HandleObject proxy, HandleId id, PropertyDescriptor *desc)
+Proxy::defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
+                      MutableHandle<PropertyDescriptor> desc)
 {
     JS_CHECK_RECURSION(cx, return false);
     BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
     AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true);
     if (!policy.allowed())
         return policy.returnValue();
     return proxy->as<ProxyObject>().handler()->defineProperty(cx, proxy, id, desc);
 }
 
 bool
 Proxy::defineProperty(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v)
 {
     JS_CHECK_RECURSION(cx, return false);
-    AutoPropertyDescriptorRooter desc(cx);
+    Rooted<PropertyDescriptor> desc(cx);
     return ParsePropertyDescriptorObject(cx, proxy, v, &desc) &&
            Proxy::defineProperty(cx, proxy, id, &desc);
 }
 
 bool
 Proxy::getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props)
 {
     JS_CHECK_RECURSION(cx, return false);
@@ -2537,20 +2539,20 @@ Proxy::set(JSContext *cx, HandleObject p
         bool hasOwn;
         if (!handler->hasOwn(cx, proxy, id, &hasOwn))
             return false;
         if (!hasOwn) {
             RootedObject proto(cx);
             if (!handler->getPrototypeOf(cx, proxy, &proto))
                 return false;
             if (proto) {
-                AutoPropertyDescriptorRooter desc(cx);
-                if (!JS_GetPropertyDescriptorById(cx, proto, id, 0, &desc))
+                Rooted<PropertyDescriptor> desc(cx);
+                if (!JS_GetPropertyDescriptorById(cx, proto, id, 0, desc.address()))
                     return false;
-                if (desc.obj && desc.setter)
+                if (desc.object() && desc.setter())
                     return JSObject::setGeneric(cx, proto, receiver, id, vp, strict);
             }
         }
     }
     return handler->set(cx, proxy, receiver, id, strict, vp);
 }
 
 bool
@@ -2783,23 +2785,23 @@ proxy_LookupSpecial(JSContext *cx, Handl
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return proxy_LookupGeneric(cx, obj, id, objp, propp);
 }
 
 static bool
 proxy_DefineGeneric(JSContext *cx, HandleObject obj, HandleId id, HandleValue value,
                     PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
-    AutoPropertyDescriptorRooter desc(cx);
-    desc.obj = obj;
-    desc.value = value;
-    desc.attrs = (attrs & (~JSPROP_SHORTID));
-    desc.getter = getter;
-    desc.setter = setter;
-    desc.shortid = 0;
+    Rooted<PropertyDescriptor> desc(cx);
+    desc.object().set(obj);
+    desc.value().set(value);
+    desc.setAttributes(attrs & (~JSPROP_SHORTID));
+    desc.setGetter(getter);
+    desc.setSetter(setter);
+    desc.setShortId(0);
     return Proxy::defineProperty(cx, obj, id, &desc);
 }
 
 static bool
 proxy_DefineProperty(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value,
                      PropertyOp getter, StrictPropertyOp setter, unsigned attrs)
 {
     Rooted<jsid> id(cx, NameToId(name));
@@ -2895,20 +2897,20 @@ proxy_SetSpecial(JSContext *cx, HandleOb
 {
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return proxy_SetGeneric(cx, obj, id, vp, strict);
 }
 
 static bool
 proxy_GetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
-    AutoPropertyDescriptorRooter desc(cx);
+    Rooted<PropertyDescriptor> desc(cx);
     if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, &desc, 0))
         return false;
-    *attrsp = desc.attrs;
+    *attrsp = desc.attributes();
     return true;
 }
 
 static bool
 proxy_GetPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return proxy_GetGenericAttributes(cx, obj, id, attrsp);
@@ -2929,20 +2931,20 @@ proxy_GetSpecialAttributes(JSContext *cx
     Rooted<jsid> id(cx, SPECIALID_TO_JSID(sid));
     return proxy_GetGenericAttributes(cx, obj, id, attrsp);
 }
 
 static bool
 proxy_SetGenericAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *attrsp)
 {
     /* Lookup the current property descriptor so we have setter/getter/value. */
-    AutoPropertyDescriptorRooter desc(cx);
+    Rooted<PropertyDescriptor> desc(cx);
     if (!Proxy::getOwnPropertyDescriptor(cx, obj, id, &desc, JSRESOLVE_ASSIGNING))
         return false;
-    desc.attrs = (*attrsp & (~JSPROP_SHORTID));
+    desc.setAttributes(*attrsp & (~JSPROP_SHORTID));
     return Proxy::defineProperty(cx, obj, id, &desc);
 }
 
 static bool
 proxy_SetPropertyAttributes(JSContext *cx, HandleObject obj, HandlePropertyName name, unsigned *attrsp)
 {
     Rooted<jsid> id(cx, NameToId(name));
     return proxy_SetGenericAttributes(cx, obj, id, attrsp);
--- a/js/src/jsproxy.h
+++ b/js/src/jsproxy.h
@@ -101,22 +101,23 @@ class JS_FRIEND_API(BaseProxyHandler)
         CALL
     };
     virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id, Action act,
                        bool *bp);
 
     /* ES5 Harmony fundamental proxy traps. */
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy) = 0;
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                       PropertyDescriptor *desc, unsigned flags) = 0;
+                                       MutableHandle<PropertyDescriptor> desc,
+                                       unsigned flags) = 0;
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy,
-                                          HandleId id, PropertyDescriptor *desc,
+                                          HandleId id, MutableHandle<PropertyDescriptor> desc,
                                           unsigned flags) = 0;
     virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                PropertyDescriptor *desc) = 0;
+                                MutableHandle<PropertyDescriptor> desc) = 0;
     virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy,
                                      AutoIdVector &props) = 0;
     virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp) = 0;
     virtual bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props) = 0;
 
     /* ES5 Harmony derived proxy traps. */
     virtual bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
     virtual bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
@@ -157,22 +158,22 @@ class JS_FRIEND_API(BaseProxyHandler)
 class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler
 {
   public:
     explicit DirectProxyHandler(void *family);
 
     /* ES5 Harmony fundamental proxy traps. */
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                       PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
+                                       MutableHandle<PropertyDescriptor> desc, unsigned flags) MOZ_OVERRIDE;
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy,
-                                          HandleId id, PropertyDescriptor *desc,
+                                          HandleId id, MutableHandle<PropertyDescriptor> desc,
                                           unsigned flags) MOZ_OVERRIDE;
     virtual bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                                PropertyDescriptor *desc) MOZ_OVERRIDE;
+                                MutableHandle<PropertyDescriptor> desc) MOZ_OVERRIDE;
     virtual bool getOwnPropertyNames(JSContext *cx, HandleObject proxy,
                                      AutoIdVector &props) MOZ_OVERRIDE;
     virtual bool delete_(JSContext *cx, HandleObject proxy, HandleId id,
                          bool *bp) MOZ_OVERRIDE;
     virtual bool enumerate(JSContext *cx, HandleObject proxy,
                            AutoIdVector &props) MOZ_OVERRIDE;
 
     /* ES5 Harmony derived proxy traps. */
@@ -211,24 +212,25 @@ class JS_PUBLIC_API(DirectProxyHandler) 
 
 /* Dispatch point for handlers that executes the appropriate C++ or scripted traps. */
 class Proxy
 {
   public:
     /* ES5 Harmony fundamental proxy traps. */
     static bool preventExtensions(JSContext *cx, HandleObject proxy);
     static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                      PropertyDescriptor *desc, unsigned flags);
+                                      MutableHandle<PropertyDescriptor> desc, unsigned flags);
     static bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, unsigned flags, HandleId id,
                                       MutableHandleValue vp);
     static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                         PropertyDescriptor *desc, unsigned flags);
+                                         MutableHandle<PropertyDescriptor> desc, unsigned flags);
     static bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, unsigned flags, HandleId id,
                                          MutableHandleValue vp);
-    static bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, PropertyDescriptor *desc);
+    static bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
+                               MutableHandle<PropertyDescriptor> desc);
     static bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v);
     static bool getOwnPropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props);
     static bool delete_(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
     static bool enumerate(JSContext *cx, HandleObject proxy, AutoIdVector &props);
 
     /* ES5 Harmony derived proxy traps. */
     static bool has(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
     static bool hasOwn(JSContext *cx, HandleObject proxy, HandleId id, bool *bp);
--- a/js/src/jswrapper.cpp
+++ b/js/src/jswrapper.cpp
@@ -198,43 +198,43 @@ CrossCompartmentWrapper::preventExtensio
     PIERCE(cx, wrapper,
            NOTHING,
            Wrapper::preventExtensions(cx, wrapper),
            NOTHING);
 }
 
 bool
 CrossCompartmentWrapper::getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
-                                               PropertyDescriptor *desc, unsigned flags)
+                                               MutableHandle<PropertyDescriptor> desc, unsigned flags)
 {
     RootedId idCopy(cx, id);
     PIERCE(cx, wrapper,
            cx->compartment()->wrapId(cx, idCopy.address()),
            Wrapper::getPropertyDescriptor(cx, wrapper, idCopy, desc, flags),
            cx->compartment()->wrap(cx, desc));
 }
 
 bool
 CrossCompartmentWrapper::getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper,
-                                                  HandleId id, PropertyDescriptor *desc,
+                                                  HandleId id, MutableHandle<PropertyDescriptor> desc,
                                                   unsigned flags)
 {
     RootedId idCopy(cx, id);
     PIERCE(cx, wrapper,
            cx->compartment()->wrapId(cx, idCopy.address()),
            Wrapper::getOwnPropertyDescriptor(cx, wrapper, idCopy, desc, flags),
            cx->compartment()->wrap(cx, desc));
 }
 
 bool
 CrossCompartmentWrapper::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                                        PropertyDescriptor *desc)
+                                        MutableHandle<PropertyDescriptor> desc)
 {
     RootedId idCopy(cx, id);
-    AutoPropertyDescriptorRooter desc2(cx, desc);
+    Rooted<PropertyDescriptor> desc2(cx, desc);
     PIERCE(cx, wrapper,
            cx->compartment()->wrapId(cx, idCopy.address()) && cx->compartment()->wrap(cx, &desc2),
            Wrapper::defineProperty(cx, wrapper, idCopy, &desc2),
            NOTHING);
 }
 
 bool
 CrossCompartmentWrapper::getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
@@ -652,19 +652,19 @@ bool
 SecurityWrapper<Base>::regexp_toShared(JSContext *cx, HandleObject obj, RegExpGuard *g)
 {
     return Base::regexp_toShared(cx, obj, g);
 }
 
 template <class Base>
 bool
 SecurityWrapper<Base>::defineProperty(JSContext *cx, HandleObject wrapper,
-                                      HandleId id, PropertyDescriptor *desc)
+                                      HandleId id, MutableHandle<PropertyDescriptor> desc)
 {
-    if (desc->getter || desc->setter) {
+    if (desc.getter() || desc.setter()) {
         JSString *str = IdToString(cx, id);
         const jschar *prop = str ? str->getCharsZ(cx) : NULL;
         JS_ReportErrorNumberUC(cx, js_GetErrorMessage, NULL,
                                JSMSG_ACCESSOR_DEF_DENIED, prop);
         return false;
     }
 
     return Base::defineProperty(cx, wrapper, id, desc);
@@ -691,33 +691,33 @@ bool
 DeadObjectProxy::preventExtensions(JSContext *cx, HandleObject proxy)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEAD_OBJECT);
     return false;
 }
 
 bool
 DeadObjectProxy::getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
-                                       PropertyDescriptor *desc, unsigned flags)
+                                       MutableHandle<PropertyDescriptor> desc, unsigned flags)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEAD_OBJECT);
     return false;
 }
 
 bool
 DeadObjectProxy::getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
-                                          PropertyDescriptor *desc, unsigned flags)
+                                          MutableHandle<PropertyDescriptor> desc, unsigned flags)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEAD_OBJECT);
     return false;
 }
 
 bool
 DeadObjectProxy::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                                PropertyDescriptor *desc)
+                                MutableHandle<PropertyDescriptor> desc)
 {
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_DEAD_OBJECT);
     return false;
 }
 
 bool
 DeadObjectProxy::getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
                                      AutoIdVector &props)
--- a/js/src/jswrapper.h
+++ b/js/src/jswrapper.h
@@ -76,21 +76,23 @@ class JS_FRIEND_API(CrossCompartmentWrap
 
     virtual ~CrossCompartmentWrapper();
 
     virtual bool finalizeInBackground(Value priv) MOZ_OVERRIDE;
 
     /* ES5 Harmony fundamental wrapper traps. */
     virtual bool preventExtensions(JSContext *cx, HandleObject wrapper) MOZ_OVERRIDE;
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
-                                       PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
+                                       MutableHandle<PropertyDescriptor> desc,
+                                       unsigned flags) MOZ_OVERRIDE;
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
-                                          PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
+                                          MutableHandle<PropertyDescriptor> desc,
+                                          unsigned flags) MOZ_OVERRIDE;
     virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                                PropertyDescriptor *desc) MOZ_OVERRIDE;
+                                MutableHandle<PropertyDescriptor> desc) MOZ_OVERRIDE;
     virtual bool getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
                                      AutoIdVector &props) MOZ_OVERRIDE;
     virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) MOZ_OVERRIDE;
     virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) MOZ_OVERRIDE;
 
     /* ES5 Harmony derived wrapper traps. */
     virtual bool has(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) MOZ_OVERRIDE;
@@ -144,17 +146,17 @@ class JS_FRIEND_API(SecurityWrapper) : p
     virtual bool nativeCall(JSContext *cx, IsAcceptableThis test, NativeImpl impl,
                             CallArgs args) MOZ_OVERRIDE;
     virtual bool defaultValue(JSContext *cx, HandleObject wrapper, JSType hint,
                               MutableHandleValue vp) MOZ_OVERRIDE;
     virtual bool objectClassIs(HandleObject obj, ESClassValue classValue,
                                JSContext *cx) MOZ_OVERRIDE;
     virtual bool regexp_toShared(JSContext *cx, HandleObject proxy, RegExpGuard *g) MOZ_OVERRIDE;
     virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                                PropertyDescriptor *desc) MOZ_OVERRIDE;
+                                MutableHandle<PropertyDescriptor> desc) MOZ_OVERRIDE;
 
     /*
      * Allow our subclasses to select the superclass behavior they want without
      * needing to specify an exact superclass.
      */
     typedef Base Permissive;
     typedef SecurityWrapper<Base> Restrictive;
 };
@@ -167,21 +169,23 @@ class JS_FRIEND_API(DeadObjectProxy) : p
   public:
     static int sDeadObjectFamily;
 
     explicit DeadObjectProxy();
 
     /* ES5 Harmony fundamental wrapper traps. */
     virtual bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE;
     virtual bool getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
-                                       PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
+                                       MutableHandle<PropertyDescriptor> desc,
+                                       unsigned flags) MOZ_OVERRIDE;
     virtual bool getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
-                                          PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE;
+                                          MutableHandle<PropertyDescriptor> desc,
+                                          unsigned flags) MOZ_OVERRIDE;
     virtual bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                                PropertyDescriptor *desc) MOZ_OVERRIDE;
+                                MutableHandle<PropertyDescriptor> desc) MOZ_OVERRIDE;
     virtual bool getOwnPropertyNames(JSContext *cx, HandleObject wrapper,
                                      AutoIdVector &props) MOZ_OVERRIDE;
     virtual bool delete_(JSContext *cx, HandleObject wrapper, HandleId id, bool *bp) MOZ_OVERRIDE;
     virtual bool enumerate(JSContext *cx, HandleObject wrapper, AutoIdVector &props) MOZ_OVERRIDE;
 
     /* Spidermonkey extensions. */
     virtual bool isExtensible(JSContext *cx, HandleObject proxy, bool *extensible) MOZ_OVERRIDE;
     virtual bool call(JSContext *cx, HandleObject proxy, const CallArgs &args) MOZ_OVERRIDE;
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2674,69 +2674,68 @@ ShapeOf(JSContext *cx, unsigned argc, JS
  * Since obj is native, this isn't totally transparent; properties of a
  * non-native referent may be simplified to data properties.
  */
 static bool
 CopyProperty(JSContext *cx, HandleObject obj, HandleObject referent, HandleId id,
              unsigned lookupFlags, MutableHandleObject objp)
 {
     RootedShape shape(cx);
-    AutoPropertyDescriptorRooter desc(cx);
+    Rooted<PropertyDescriptor> desc(cx);
     unsigned propFlags = 0;
     RootedObject obj2(cx);
 
     objp.set(NULL);
     if (referent->isNative()) {
         if (!LookupPropertyWithFlags(cx, referent, id, lookupFlags, &obj2, &shape))
             return false;
         if (obj2 != referent)
             return true;
 
         if (shape->hasSlot()) {
-            desc.value = referent->nativeGetSlot(shape->slot());
+            desc.value().set(referent->nativeGetSlot(shape->slot()));
         } else {
-            desc.value.setUndefined();
+            desc.value().setUndefined();
         }
 
-        desc.attrs = shape->attributes();
-        desc.getter = shape->getter();
-        if (!desc.getter && !(desc.attrs & JSPROP_GETTER))
-            desc.getter = JS_PropertyStub;
-        desc.setter = shape->setter();
-        if (!desc.setter && !(desc.attrs & JSPROP_SETTER))
-            desc.setter = JS_StrictPropertyStub;
-        desc.shortid = shape->shortid();
+        desc.setAttributes(shape->attributes());
+        desc.setGetter(shape->getter());
+        if (!desc.getter() && !desc.hasGetterObject())
+            desc.setGetter(JS_PropertyStub);
+        desc.setSetter(shape->setter());
+        if (!desc.setter() && !desc.hasSetterObject())
+            desc.setSetter(JS_StrictPropertyStub);
+        desc.setShortId(shape->shortid());
         propFlags = shape->getFlags();
     } else if (referent->is<ProxyObject>()) {
         if (!Proxy::getOwnPropertyDescriptor(cx, referent, id, &desc, 0))
             return false;
-        if (!desc.obj)
+        if (!desc.object())
             return true;
     } else {
         if (!JSObject::lookupGeneric(cx, referent, id, objp, &shape))
             return false;
         if (objp != referent)
             return true;
         RootedValue value(cx);
         if (!JSObject::getGeneric(cx, referent, referent, id, &value) ||
-            !JSObject::getGenericAttributes(cx, referent, id, &desc.attrs))
+            !JSObject::getGenericAttributes(cx, referent, id, &desc.attributesRef()))
         {
             return false;
         }
-        desc.value = value;
-        desc.attrs &= JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT;
-        desc.getter = JS_PropertyStub;
-        desc.setter = JS_StrictPropertyStub;
-        desc.shortid = 0;
-    }
-
-    RootedValue value(cx, desc.value);
+        desc.value().set(value);
+        desc.attributesRef() &= JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT;
+        desc.setGetter(JS_PropertyStub);
+        desc.setSetter(JS_StrictPropertyStub);
+        desc.setShortId(0);
+    }
+
     objp.set(obj);
-    return DefineNativeProperty(cx, obj, id, value, desc.getter, desc.setter,
-                                desc.attrs, propFlags, desc.shortid);
+    return DefineNativeProperty(cx, obj, id, desc.value(), desc.getter(), desc.setter(),
+                                desc.attributes(), propFlags, desc.shortid());
 }
 
 static bool
 resolver_resolve(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
                  MutableHandleObject objp)
 {
     jsval v = JS_GetReservedSlot(obj, 0);
     Rooted<JSObject*> vobj(cx, &v.toObject());
--- a/js/src/vm/Debugger.cpp
+++ b/js/src/vm/Debugger.cpp
@@ -4626,50 +4626,48 @@ DebuggerObject_getOwnPropertyDescriptor(
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "getOwnPropertyDescriptor", args, dbg, obj);
 
     RootedId id(cx);
     if (!ValueToId<CanGC>(cx, args.get(0), &id))
         return false;
 
     /* Bug: This can cause the debuggee to run! */
-    AutoPropertyDescriptorRooter desc(cx);
+    Rooted<PropertyDescriptor> desc(cx);
     {
         Maybe<AutoCompartment> ac;
         ac.construct(cx, obj);
         if (!cx->compartment()->wrapId(cx, id.address()))
             return false;
 
         ErrorCopier ec(ac, dbg->toJSObject());
         if (!GetOwnPropertyDescriptor(cx, obj, id, &desc))
             return false;
     }
 
-    if (desc.obj) {
+    if (desc.object()) {
         /* Rewrap the debuggee values in desc for the debugger. */
-        RootedValue value(cx, desc.value);
-        if (!dbg->wrapDebuggeeValue(cx, &value))
+        if (!dbg->wrapDebuggeeValue(cx, desc.value()))
             return false;
-        desc.value = value;
-
-        if (desc.attrs & JSPROP_GETTER) {
-            RootedValue get(cx, ObjectOrNullValue(CastAsObject(desc.getter)));
+
+        if (desc.hasGetterObject()) {
+            RootedValue get(cx, ObjectOrNullValue(desc.getterObject()));
             if (!dbg->wrapDebuggeeValue(cx, &get))
                 return false;
-            desc.getter = CastAsPropertyOp(get.toObjectOrNull());
+            desc.setGetterObject(get.toObjectOrNull());
         }
-        if (desc.attrs & JSPROP_SETTER) {
-            RootedValue set(cx, ObjectOrNullValue(CastAsObject(desc.setter)));
+        if (desc.hasSetterObject()) {
+            RootedValue set(cx, ObjectOrNullValue(desc.setterObject()));
             if (!dbg->wrapDebuggeeValue(cx, &set))
                 return false;
-            desc.setter = CastAsStrictPropertyOp(set.toObjectOrNull());
+            desc.setSetterObject(set.toObjectOrNull());
         }
     }
 
-    return NewPropertyDescriptorObject(cx, &desc, args.rval());
+    return NewPropertyDescriptorObject(cx, desc, args.rval());
 }
 
 static bool
 DebuggerObject_getOwnPropertyNames(JSContext *cx, unsigned argc, Value *vp)
 {
     THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, "getOwnPropertyNames", args, dbg, obj);
 
     AutoIdVector keys(cx);
--- a/js/src/vm/ObjectImpl.h
+++ b/js/src/vm/ObjectImpl.h
@@ -233,17 +233,17 @@ struct PropDesc {
      * 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(const PropertyDescriptor &desc);
+    void initFromPropertyDescriptor(Handle<PropertyDescriptor> desc);
     bool makeObject(JSContext *cx);
 
     void setUndefined() { isUndefined_ = true; }
 
     bool isUndefined() const { return isUndefined_; }
 
     bool hasGet() const { MOZ_ASSERT(!isUndefined()); return hasGet_; }
     bool hasSet() const { MOZ_ASSERT(!isUndefined()); return hasSet_; }
@@ -350,17 +350,17 @@ class AutoPropDescRooter : private JS::C
                                 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
       : CustomAutoRooter(cx), skip(cx, &propDesc)
     {
         MOZ_GUARD_OBJECT_NOTIFIER_INIT;
     }
 
     PropDesc& getPropDesc() { return propDesc; }
 
-    void initFromPropertyDescriptor(const PropertyDescriptor &desc) {
+    void initFromPropertyDescriptor(Handle<PropertyDescriptor> desc) {
         propDesc.initFromPropertyDescriptor(desc);
     }
 
     bool makeObject(JSContext *cx) {
         return propDesc.makeObject(cx);
     }
 
     void setUndefined() { propDesc.setUndefined(); }
--- a/js/src/vm/ScopeObject.cpp
+++ b/js/src/vm/ScopeObject.cpp
@@ -1369,50 +1369,56 @@ class DebugScopeProxy : public BaseProxy
 
     bool preventExtensions(JSContext *cx, HandleObject proxy) MOZ_OVERRIDE
     {
         // See above.
         JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CHANGE_EXTENSIBILITY);
         return false;
     }
 
-    bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id, PropertyDescriptor *desc,
+    bool getPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
+                               MutableHandle<PropertyDescriptor> desc,
                                unsigned flags) MOZ_OVERRIDE
     {
         return getOwnPropertyDescriptor(cx, proxy, id, desc, flags);
     }
 
     bool getOwnPropertyDescriptor(JSContext *cx, HandleObject proxy, HandleId id,
-                                  PropertyDescriptor *desc, unsigned flags) MOZ_OVERRIDE
+                                  MutableHandle<PropertyDescriptor> desc,
+                                  unsigned flags) MOZ_OVERRIDE
     {
         Rooted<DebugScopeObject*> debugScope(cx, &proxy->as<DebugScopeObject>());
         Rooted<ScopeObject*> scope(cx, &debugScope->scope());
 
         RootedArgumentsObject maybeArgsObj(cx);
         if (!checkForMissingArguments(cx, id, *scope, maybeArgsObj.address()))
             return false;
 
         if (maybeArgsObj) {
-            PodZero(desc);
-            desc->obj = debugScope;
-            desc->attrs = JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT;
-            desc->value = ObjectValue(*maybeArgsObj);
+            desc.object().set(debugScope);
+            desc.setAttributes(JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT);
+            desc.value().setObject(*maybeArgsObj);
+            desc.setShortId(0);
+            desc.setGetter(NULL);
+            desc.setSetter(NULL);
             return true;
         }
 
         RootedValue v(cx);
         if (handleUnaliasedAccess(cx, debugScope, scope, id, GET, &v)) {
-            PodZero(desc);
-            desc->obj = debugScope;
-            desc->attrs = JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT;
-            desc->value = v;
+            desc.object().set(debugScope);
+            desc.setAttributes(JSPROP_READONLY | JSPROP_ENUMERATE | JSPROP_PERMANENT);
+            desc.value().set(v);
+            desc.setShortId(0);
+            desc.setGetter(NULL);
+            desc.setSetter(NULL);
             return true;
         }
 
-        return JS_GetPropertyDescriptorById(cx, scope, id, 0, desc);
+        return JS_GetPropertyDescriptorById(cx, scope, id, 0, desc.address());
     }
 
     bool get(JSContext *cx, HandleObject proxy, HandleObject receiver,  HandleId id,
              MutableHandleValue vp) MOZ_OVERRIDE
     {
         Rooted<DebugScopeObject*> debugScope(cx, &proxy->as<DebugScopeObject>());
         Rooted<ScopeObject*> scope(cx, &proxy->as<DebugScopeObject>().scope());
 
@@ -1437,28 +1443,28 @@ class DebugScopeProxy : public BaseProxy
         Rooted<DebugScopeObject*> debugScope(cx, &proxy->as<DebugScopeObject>());
         Rooted<ScopeObject*> scope(cx, &proxy->as<DebugScopeObject>().scope());
         if (handleUnaliasedAccess(cx, debugScope, scope, id, SET, vp))
             return true;
         return JSObject::setGeneric(cx, scope, scope, id, vp, strict);
     }
 
     bool defineProperty(JSContext *cx, HandleObject proxy, HandleId id,
-                        PropertyDescriptor *desc) MOZ_OVERRIDE
+                        MutableHandle<PropertyDescriptor> desc) MOZ_OVERRIDE
     {
         Rooted<ScopeObject*> scope(cx, &proxy->as<DebugScopeObject>().scope());
 
         bool found;
         if (!has(cx, proxy, id, &found))
             return false;
         if (found)
             return Throw(cx, id, JSMSG_CANT_REDEFINE_PROP);
 
-        return JS_DefinePropertyById(cx, scope, id, desc->value, desc->getter, desc->setter,
-                                     desc->attrs);
+        return JS_DefinePropertyById(cx, scope, id, desc.value(), desc.getter(), desc.setter(),
+                                     desc.attributes());
     }
 
     bool getScopePropertyNames(JSContext *cx, HandleObject proxy, AutoIdVector &props,
                                unsigned flags)
     {
         Rooted<ScopeObject*> scope(cx, &proxy->as<DebugScopeObject>().scope());
 
         if (isMissingArgumentsBinding(*scope)) {
--- a/js/xpconnect/src/XPCComponents.cpp
+++ b/js/xpconnect/src/XPCComponents.cpp
@@ -3129,72 +3129,72 @@ extern bool
 XPC_WN_Helper_GetProperty(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp);
 extern bool
 XPC_WN_Helper_SetProperty(JSContext *cx, HandleObject obj, HandleId id, bool strict, MutableHandleValue vp);
 
 bool
 xpc::SandboxProxyHandler::getPropertyDescriptor(JSContext *cx,
                                                 JS::Handle<JSObject*> proxy,
                                                 JS::Handle<jsid> id,
-                                                PropertyDescriptor *desc,
+                                                JS::MutableHandle<PropertyDescriptor> desc,
                                                 unsigned flags)
 {
     JS::RootedObject obj(cx, wrappedObject(proxy));
 
     MOZ_ASSERT(js::GetObjectCompartment(obj) == js::GetObjectCompartment(proxy));
     if (!JS_GetPropertyDescriptorById(cx, obj, id,
-                                      flags, desc))
+                                      flags, desc.address()))
         return false;
 
-    if (!desc->obj)
+    if (!desc.object())
         return true; // No property, nothing to do
 
     // Now fix up the getter/setter/value as needed to be bound to desc->obj
     // Don't mess with holder_get and holder_set, though, because those rely on
     // the "vp is prefilled with the value in the slot" behavior that property
     // ops can in theory rely on, but our property op forwarder doesn't know how
     // to make that happen.  Since we really only need to rebind the DOM methods
     // here, not rebindings holder_get and holder_set is OK.
     //
     // Similarly, don't mess with XPC_WN_Helper_GetProperty and
     // XPC_WN_Helper_SetProperty, for the same reasons: that could confuse our
     // access to expandos when we're not doing Xrays.
-    if (desc->getter != xpc::holder_get &&
-        desc->getter != XPC_WN_Helper_GetProperty &&
-        !BindPropertyOp(cx, desc->getter, desc, id, JSPROP_GETTER, proxy))
+    if (desc.getter() != xpc::holder_get &&
+        desc.getter() != XPC_WN_Helper_GetProperty &&
+        !BindPropertyOp(cx, desc.getter(), desc.address(), id, JSPROP_GETTER, proxy))
         return false;
-    if (desc->setter != xpc::holder_set &&
-        desc->setter != XPC_WN_Helper_SetProperty &&
-        !BindPropertyOp(cx, desc->setter, desc, id, JSPROP_SETTER, proxy))
+    if (desc.setter() != xpc::holder_set &&
+        desc.setter() != XPC_WN_Helper_SetProperty &&
+        !BindPropertyOp(cx, desc.setter(), desc.address(), id, JSPROP_SETTER, proxy))
         return false;
-    if (desc->value.isObject()) {
-        JSObject* val = &desc->value.toObject();
+    if (desc.value().isObject()) {
+        JSObject* val = &desc.value().toObject();
         if (JS_ObjectIsCallable(cx, val)) {
             val = WrapCallable(cx, val, proxy);
             if (!val)
                 return false;
-            desc->value = ObjectValue(*val);
+            desc.value().setObject(*val);
         }
     }
 
     return true;
 }
 
 bool
 xpc::SandboxProxyHandler::getOwnPropertyDescriptor(JSContext *cx,
                                                    JS::Handle<JSObject*> proxy,
                                                    JS::Handle<jsid> id,
-                                                   PropertyDescriptor *desc,
+                                                   JS::MutableHandle<PropertyDescriptor> desc,
                                                    unsigned flags)
 {
     if (!getPropertyDescriptor(cx, proxy, id, desc, flags))
         return false;
 
-    if (desc->obj != wrappedObject(proxy))
-        desc->obj = nullptr;
+    if (desc.object() != wrappedObject(proxy))
+        desc.object().set(nullptr);
 
     return true;
 }
 
 /*
  * Reuse the BaseProxyHandler versions of the derived traps that are implemented
  * in terms of the fundamental traps.
  */
--- a/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
+++ b/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
@@ -25,20 +25,20 @@ AllowedByBase(JSContext *cx, HandleObjec
     MOZ_ASSERT(js::Wrapper::wrapperHandler(wrapper) ==
                &ChromeObjectWrapper::singleton);
     bool bp;
     ChromeObjectWrapper *handler = &ChromeObjectWrapper::singleton;
     return handler->ChromeObjectWrapperBase::enter(cx, wrapper, id, act, &bp);
 }
 
 static bool
-PropIsFromStandardPrototype(JSContext *cx, JSPropertyDescriptor *desc)
+PropIsFromStandardPrototype(JSContext *cx, JS::MutableHandle<js::PropertyDescriptor> desc)
 {
-    MOZ_ASSERT(desc->obj);
-    RootedObject unwrapped(cx, js::UncheckedUnwrap(desc->obj));
+    MOZ_ASSERT(desc.object());
+    RootedObject unwrapped(cx, js::UncheckedUnwrap(desc.object()));
     JSAutoCompartment ac(cx, unwrapped);
     return JS_IdentifyClassPrototype(cx, unwrapped) != JSProto_Null;
 }
 
 // Note that we're past the policy enforcement stage, here, so we can query
 // ChromeObjectWrapperBase and get an unfiltered view of the underlying object.
 // This lets us determine whether the property we would have found (given a
 // transparent wrapper) would have come off a standard prototype.
@@ -46,56 +46,56 @@ static bool
 PropIsFromStandardPrototype(JSContext *cx, HandleObject wrapper,
                             HandleId id)
 {
     MOZ_ASSERT(js::Wrapper::wrapperHandler(wrapper) ==
                &ChromeObjectWrapper::singleton);
     Rooted<JSPropertyDescriptor> desc(cx);
     ChromeObjectWrapper *handler = &ChromeObjectWrapper::singleton;
     if (!handler->ChromeObjectWrapperBase::getPropertyDescriptor(cx, wrapper, id,
-                                                                 desc.address(), 0) ||
+                                                                 &desc, 0) ||
         !desc.object())
     {
         return false;
     }
-    return PropIsFromStandardPrototype(cx, desc.address());
+    return PropIsFromStandardPrototype(cx, &desc);
 }
 
 bool
 ChromeObjectWrapper::getPropertyDescriptor(JSContext *cx,
                                            HandleObject wrapper,
                                            HandleId id,
-                                           js::PropertyDescriptor *desc,
+                                           JS::MutableHandle<js::PropertyDescriptor> desc,
                                            unsigned flags)
 {
     assertEnteredPolicy(cx, wrapper, id);
     // First, try a lookup on the base wrapper if permitted.
-    desc->obj = NULL;
+    desc.object().set(NULL);
     if (AllowedByBase(cx, wrapper, id, Wrapper::GET) &&
         !ChromeObjectWrapperBase::getPropertyDescriptor(cx, wrapper, id,
                                                         desc, flags)) {
         return false;
     }
 
     // If the property is something that can be found on a standard prototype,
     // prefer the one we'll get via the prototype chain in the content
     // compartment.
-    if (desc->obj && PropIsFromStandardPrototype(cx, desc))
-        desc->obj = NULL;
+    if (desc.object() && PropIsFromStandardPrototype(cx, desc))
+        desc.object().set(NULL);
 
     // If we found something or have no proto, we're done.
     RootedObject wrapperProto(cx);
     if (!JS_GetPrototype(cx, wrapper, &wrapperProto))
       return false;
-    if (desc->obj || !wrapperProto)
+    if (desc.object() || !wrapperProto)
         return true;
 
     // If not, try doing the lookup on the prototype.
     MOZ_ASSERT(js::IsObjectInContextCompartment(wrapper, cx));
-    return JS_GetPropertyDescriptorById(cx, wrapperProto, id, 0, desc);
+    return JS_GetPropertyDescriptorById(cx, wrapperProto, id, 0, desc.address());
 }
 
 bool
 ChromeObjectWrapper::has(JSContext *cx, HandleObject wrapper,
                          HandleId id, bool *bp)
 {
     assertEnteredPolicy(cx, wrapper, id);
     // Try the lookup on the base wrapper if permitted.
@@ -123,17 +123,16 @@ ChromeObjectWrapper::has(JSContext *cx, 
 
 bool
 ChromeObjectWrapper::get(JSContext *cx, HandleObject wrapper,
                          HandleObject receiver, HandleId id,
                          MutableHandleValue vp)
 {
     assertEnteredPolicy(cx, wrapper, id);
     vp.setUndefined();
-    JSPropertyDescriptor desc;
     // Only call through to the get trap on the underlying object if we're
     // allowed to see the property, and if what we'll find is not on a standard
     // prototype.
     if (AllowedByBase(cx, wrapper, id, js::Wrapper::GET) &&
         !PropIsFromStandardPrototype(cx, wrapper, id))
     {
         // Call the get trap.
         if (!ChromeObjectWrapperBase::get(cx, wrapper, receiver, id, vp))
--- a/js/xpconnect/wrappers/ChromeObjectWrapper.h
+++ b/js/xpconnect/wrappers/ChromeObjectWrapper.h
@@ -25,17 +25,18 @@ namespace xpc {
 
 class ChromeObjectWrapper : public ChromeObjectWrapperBase
 {
   public:
     ChromeObjectWrapper() : ChromeObjectWrapperBase(0) {}
 
     /* Custom traps. */
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
-                                       JS::Handle<jsid> id, js::PropertyDescriptor *desc,
+                                       JS::Handle<jsid> id,
+                                       JS::MutableHandle<js::PropertyDescriptor> desc,
                                        unsigned flags) MOZ_OVERRIDE;
     virtual bool has(JSContext *cx, JS::Handle<JSObject*> wrapper,
                      JS::Handle<jsid> id, bool *bp) MOZ_OVERRIDE;
     virtual bool get(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> receiver,
                      JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) MOZ_OVERRIDE;
 
     virtual bool objectClassIs(JS::Handle<JSObject*> obj, js::ESClassValue classValue,
                                JSContext *cx) MOZ_OVERRIDE;
--- a/js/xpconnect/wrappers/FilteringWrapper.cpp
+++ b/js/xpconnect/wrappers/FilteringWrapper.cpp
@@ -43,44 +43,45 @@ Filter(JSContext *cx, HandleObject wrapp
             return false;
     }
     props.resize(w);
     return true;
 }
 
 template <typename Policy>
 static bool
-FilterSetter(JSContext *cx, JSObject *wrapper, jsid id, js::PropertyDescriptor *desc)
+FilterSetter(JSContext *cx, JSObject *wrapper, jsid id, JS::MutableHandle<js::PropertyDescriptor> desc)
 {
     bool setAllowed = Policy::check(cx, wrapper, id, Wrapper::SET);
     if (!setAllowed) {
         if (JS_IsExceptionPending(cx))
             return false;
-        desc->setter = nullptr;
+        desc.setSetter(nullptr);
     }
     return true;
 }
 
 template <typename Base, typename Policy>
 bool
 FilteringWrapper<Base, Policy>::getPropertyDescriptor(JSContext *cx, HandleObject wrapper,
                                                       HandleId id,
-                                                      js::PropertyDescriptor *desc, unsigned flags)
+                                                      JS::MutableHandle<js::PropertyDescriptor> desc,
+                                                      unsigned flags)
 {
     assertEnteredPolicy(cx, wrapper, id);
     if (!Base::getPropertyDescriptor(cx, wrapper, id, desc, flags))
         return false;
     return FilterSetter<Policy>(cx, wrapper, id, desc);
 }
 
 template <typename Base, typename Policy>
 bool
 FilteringWrapper<Base, Policy>::getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper,
                                                          HandleId id,
-                                                         js::PropertyDescriptor *desc,
+                                                         JS::MutableHandle<js::PropertyDescriptor> desc,
                                                          unsigned flags)
 {
     assertEnteredPolicy(cx, wrapper, id);
     if (!Base::getOwnPropertyDescriptor(cx, wrapper, id, desc, flags))
         return false;
     return FilterSetter<Policy>(cx, wrapper, id, desc);
 }
 
--- a/js/xpconnect/wrappers/FilteringWrapper.h
+++ b/js/xpconnect/wrappers/FilteringWrapper.h
@@ -15,20 +15,22 @@ namespace xpc {
 
 template <typename Base, typename Policy>
 class FilteringWrapper : public Base {
   public:
     FilteringWrapper(unsigned flags);
     virtual ~FilteringWrapper();
 
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
-                                       JS::Handle<jsid> id, js::PropertyDescriptor *desc,
+                                       JS::Handle<jsid> id,
+                                       JS::MutableHandle<js::PropertyDescriptor> desc,
                                        unsigned flags) MOZ_OVERRIDE;
     virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
-                                          JS::Handle<jsid> id, js::PropertyDescriptor *desc,
+                                          JS::Handle<jsid> id,
+                                          JS::MutableHandle<js::PropertyDescriptor> desc,
                                           unsigned flags) MOZ_OVERRIDE;
     virtual bool getOwnPropertyNames(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                      js::AutoIdVector &props) MOZ_OVERRIDE;
     virtual bool enumerate(JSContext *cx, JS::Handle<JSObject*> wrapper,
                            js::AutoIdVector &props) MOZ_OVERRIDE;
     virtual bool keys(JSContext *cx, JS::Handle<JSObject*> wrapper,
                       js::AutoIdVector &props) MOZ_OVERRIDE;
     virtual bool iterate(JSContext *cx, JS::Handle<JSObject*> wrapper, unsigned flags,
--- a/js/xpconnect/wrappers/WaiveXrayWrapper.cpp
+++ b/js/xpconnect/wrappers/WaiveXrayWrapper.cpp
@@ -13,58 +13,58 @@
 #include "AccessCheck.h"
 #include "WrapperFactory.h"
 
 using namespace JS;
 
 namespace xpc {
 
 static bool
-WaiveAccessors(JSContext *cx, js::PropertyDescriptor *desc)
+WaiveAccessors(JSContext *cx, JS::MutableHandle<js::PropertyDescriptor> desc)
 {
-    if ((desc->attrs & JSPROP_GETTER) && desc->getter) {
-        RootedValue v(cx, JS::ObjectValue(*JS_FUNC_TO_DATA_PTR(JSObject *, desc->getter)));
+    if (desc.hasGetterObject() && desc.getterObject()) {
+        RootedValue v(cx, JS::ObjectValue(*desc.getterObject()));
         if (!WrapperFactory::WaiveXrayAndWrap(cx, v.address()))
             return false;
-        desc->getter = js::CastAsJSPropertyOp(&v.toObject());
+        desc.setGetterObject(&v.toObject());
     }
 
-    if ((desc->attrs & JSPROP_SETTER) && desc->setter) {
-        RootedValue v(cx, JS::ObjectValue(*JS_FUNC_TO_DATA_PTR(JSObject *, desc->setter)));
+    if (desc.hasSetterObject() && desc.setterObject()) {
+        RootedValue v(cx, JS::ObjectValue(*desc.setterObject()));
         if (!WrapperFactory::WaiveXrayAndWrap(cx, v.address()))
             return false;
-        desc->setter = js::CastAsJSStrictPropertyOp(&v.toObject());
+        desc.setSetterObject(&v.toObject());
     }
     return true;
 }
 
 WaiveXrayWrapper::WaiveXrayWrapper(unsigned flags) : js::CrossCompartmentWrapper(flags)
 {
 }
 
 WaiveXrayWrapper::~WaiveXrayWrapper()
 {
 }
 
 bool
 WaiveXrayWrapper::getPropertyDescriptor(JSContext *cx, HandleObject wrapper,
-                                        HandleId id, js::PropertyDescriptor *desc,
+                                        HandleId id, JS::MutableHandle<js::PropertyDescriptor> desc,
                                         unsigned flags)
 {
     return CrossCompartmentWrapper::getPropertyDescriptor(cx, wrapper, id, desc, flags) &&
-           WrapperFactory::WaiveXrayAndWrap(cx, &desc->value) && WaiveAccessors(cx, desc);
+           WrapperFactory::WaiveXrayAndWrap(cx, desc.value().address()) && WaiveAccessors(cx, desc);
 }
 
 bool
 WaiveXrayWrapper::getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper,
-                                           HandleId id, js::PropertyDescriptor *desc,
+                                           HandleId id, JS::MutableHandle<js::PropertyDescriptor> desc,
                                            unsigned flags)
 {
     return CrossCompartmentWrapper::getOwnPropertyDescriptor(cx, wrapper, id, desc, flags) &&
-           WrapperFactory::WaiveXrayAndWrap(cx, &desc->value) && WaiveAccessors(cx, desc);
+           WrapperFactory::WaiveXrayAndWrap(cx, desc.value().address()) && WaiveAccessors(cx, desc);
 }
 
 bool
 WaiveXrayWrapper::get(JSContext *cx, HandleObject wrapper,
                       HandleObject receiver, HandleId id,
                       MutableHandleValue vp)
 {
     return CrossCompartmentWrapper::get(cx, wrapper, receiver, id, vp) &&
--- a/js/xpconnect/wrappers/WaiveXrayWrapper.h
+++ b/js/xpconnect/wrappers/WaiveXrayWrapper.h
@@ -16,21 +16,22 @@
 namespace xpc {
 
 class WaiveXrayWrapper : public js::CrossCompartmentWrapper {
   public:
     WaiveXrayWrapper(unsigned flags);
     virtual ~WaiveXrayWrapper();
 
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
-                                       JS::Handle<jsid> id, js::PropertyDescriptor *desc,
+                                       JS::Handle<jsid> id,
+                                       JS::MutableHandle<js::PropertyDescriptor> desc,
                                        unsigned flags) MOZ_OVERRIDE;
     virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                           JS::Handle<jsid> id,
-                                          js::PropertyDescriptor *desc,
+                                          JS::MutableHandle<js::PropertyDescriptor> desc,
                                           unsigned flags) MOZ_OVERRIDE;
     virtual bool get(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> receiver,
                      JS::Handle<jsid> id, JS::MutableHandle<JS::Value> vp) MOZ_OVERRIDE;
 
     virtual bool call(JSContext *cx, JS::Handle<JSObject*> wrapper,
                       const JS::CallArgs &args) MOZ_OVERRIDE;
     virtual bool construct(JSContext *cx, JS::Handle<JSObject*> wrapper,
                            const JS::CallArgs &args) MOZ_OVERRIDE;
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -129,24 +129,26 @@ class XrayTraits
 {
 public:
     static JSObject* getTargetObject(JSObject *wrapper) {
         return js::UncheckedUnwrap(wrapper, /* stopAtOuter = */ false);
     }
 
     virtual bool resolveNativeProperty(JSContext *cx, HandleObject wrapper,
                                        HandleObject holder, HandleId id,
-                                       JSPropertyDescriptor *desc, unsigned flags) = 0;
+                                       MutableHandle<PropertyDescriptor> desc,
+                                       unsigned flags) = 0;
     // NB: resolveOwnProperty may decide whether or not to cache what it finds
     // on the holder. If the result is not cached, the lookup will happen afresh
     // for each access, which is the right thing for things like dynamic NodeList
     // properties.
     virtual bool resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper,
                                     HandleObject wrapper, HandleObject holder,
-                                    HandleId id, JSPropertyDescriptor *desc, unsigned flags);
+                                    HandleId id, MutableHandle<PropertyDescriptor> desc,
+                                    unsigned flags);
 
     static bool call(JSContext *cx, HandleObject wrapper,
                      const JS::CallArgs &args, js::Wrapper& baseInstance)
     {
         MOZ_ASSUME_UNREACHABLE("Call trap currently implemented only for XPCWNs");
     }
     static bool construct(JSContext *cx, HandleObject wrapper,
                           const JS::CallArgs &args, js::Wrapper& baseInstance)
@@ -183,22 +185,22 @@ private:
 
 class XPCWrappedNativeXrayTraits : public XrayTraits
 {
 public:
     static const XrayType Type = XrayForWrappedNative;
 
     virtual bool resolveNativeProperty(JSContext *cx, HandleObject wrapper,
                                        HandleObject holder, HandleId id,
-                                       JSPropertyDescriptor *desc, unsigned flags);
+                                       MutableHandle<JSPropertyDescriptor> desc, unsigned flags);
     virtual bool resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper, HandleObject wrapper,
                                     HandleObject holder, HandleId id,
-                                    JSPropertyDescriptor *desc, unsigned flags);
+                                    MutableHandle<PropertyDescriptor> desc, unsigned flags);
     static bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                               PropertyDescriptor *desc,
+                               MutableHandle<PropertyDescriptor> desc,
                                Handle<PropertyDescriptor> existingDesc, bool *defined);
     static bool enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags,
                                AutoIdVector &props);
     static bool call(JSContext *cx, HandleObject wrapper,
                      const JS::CallArgs &args, js::Wrapper& baseInstance);
     static bool construct(JSContext *cx, HandleObject wrapper,
                           const JS::CallArgs &args, js::Wrapper& baseInstance);
 
@@ -229,22 +231,22 @@ public:
 
 class DOMXrayTraits : public XrayTraits
 {
 public:
     static const XrayType Type = XrayForDOMObject;
 
     virtual bool resolveNativeProperty(JSContext *cx, HandleObject wrapper,
                                        HandleObject holder, HandleId id,
-                                       JSPropertyDescriptor *desc, unsigned flags);
+                                       MutableHandle<PropertyDescriptor> desc, unsigned flags);
     virtual bool resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper, HandleObject wrapper,
                                     HandleObject holder, HandleId id,
-                                    JSPropertyDescriptor *desc, unsigned flags);
+                                    MutableHandle<PropertyDescriptor> desc, unsigned flags);
     static bool defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                               PropertyDescriptor *desc,
+                               MutableHandle<PropertyDescriptor> desc,
                                Handle<PropertyDescriptor> existingDesc, bool *defined);
     static bool enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags,
                                AutoIdVector &props);
     static bool call(JSContext *cx, HandleObject wrapper,
                      const JS::CallArgs &args, js::Wrapper& baseInstance);
     static bool construct(JSContext *cx, HandleObject wrapper,
                           const JS::CallArgs &args, js::Wrapper& baseInstance);
 
@@ -687,102 +689,104 @@ XPCWrappedNativeXrayTraits::preserveWrap
     CallQueryInterface(wn->Native(), getter_AddRefs(ci));
     if (ci)
         ci->PreserveWrapper(wn->Native());
 }
 
 bool
 XPCWrappedNativeXrayTraits::resolveNativeProperty(JSContext *cx, HandleObject wrapper,
                                                   HandleObject holder, HandleId id,
-                                                  JSPropertyDescriptor *desc, unsigned flags)
+                                                  MutableHandle<PropertyDescriptor> desc, unsigned flags)
 {
     MOZ_ASSERT(js::GetObjectJSClass(holder) == &HolderClass);
 
-    desc->obj = NULL;
+    desc.object().set(NULL);
 
     // This will do verification and the method lookup for us.
     RootedObject target(cx, getTargetObject(wrapper));
     XPCCallContext ccx(JS_CALLER, cx, target, NullPtr(), id);
 
     // There are no native numeric properties, so we can shortcut here. We will
     // not find the property. However we want to support non shadowing dom
     // specific collection properties like window.frames, so we still have to
     // check for those.
     if (!JSID_IS_STRING(id)) {
         /* Not found */
-        return resolveDOMCollectionProperty(cx, wrapper, holder, id, desc, flags);
+        return resolveDOMCollectionProperty(cx, wrapper, holder, id, desc.address(), flags);
     }
 
     XPCNativeInterface *iface;
     XPCNativeMember *member;
     XPCWrappedNative *wn = getWN(wrapper);
 
     if (ccx.GetWrapper() != wn || !wn->IsValid()) {
         // Something is wrong. If the wrapper is not even valid let's not risk
         // calling resolveDOMCollectionProperty.
         return true;
     } else if (!(iface = ccx.GetInterface()) ||
                !(member = ccx.GetMember())) {
         /* Not found */
-        return resolveDOMCollectionProperty(cx, wrapper, holder, id, desc, flags);
+        return resolveDOMCollectionProperty(cx, wrapper, holder, id, desc.address(), flags);
     }
 
-    desc->obj = holder;
-    desc->attrs = JSPROP_ENUMERATE;
-    desc->getter = NULL;
-    desc->setter = NULL;
-    desc->shortid = 0;
-    desc->value = JSVAL_VOID;
+    desc.object().set(holder);
+    desc.setAttributes(JSPROP_ENUMERATE);
+    desc.setGetter(NULL);
+    desc.setSetter(NULL);
+    desc.setShortId(0);
+    desc.value().set(JSVAL_VOID);
 
     RootedValue fval(cx, JSVAL_VOID);
     if (member->IsConstant()) {
-        if (!member->GetConstantValue(ccx, iface, &desc->value)) {
+        if (!member->GetConstantValue(ccx, iface, desc.value().address())) {
             JS_ReportError(cx, "Failed to convert constant native property to JS value");
             return false;
         }
     } else if (member->IsAttribute()) {
         // This is a getter/setter. Clone a function for it.
         if (!member->NewFunctionObject(ccx, iface, wrapper, fval.address())) {
             JS_ReportError(cx, "Failed to clone function object for native getter/setter");
             return false;
         }
 
-        desc->attrs |= JSPROP_GETTER;
+        unsigned attrs = desc.attributes();
+        attrs |= JSPROP_GETTER;
         if (member->IsWritableAttribute())
-            desc->attrs |= JSPROP_SETTER;
+            attrs |= JSPROP_SETTER;
 
         // Make the property shared on the holder so no slot is allocated
         // for it. This avoids keeping garbage alive through that slot.
-        desc->attrs |= JSPROP_SHARED;
+        attrs |= JSPROP_SHARED;
+        desc.setAttributes(attrs);
     } else {
         // This is a method. Clone a function for it.
-        if (!member->NewFunctionObject(ccx, iface, wrapper, &desc->value)) {
+        if (!member->NewFunctionObject(ccx, iface, wrapper, desc.value().address())) {
             JS_ReportError(cx, "Failed to clone function object for native function");
             return false;
         }
 
         // Without a wrapper the function would live on the prototype. Since we
         // don't have one, we have to avoid calling the scriptable helper's
         // GetProperty method for this property, so stub out the getter and
         // setter here explicitly.
-        desc->getter = JS_PropertyStub;
-        desc->setter = JS_StrictPropertyStub;
+        desc.setGetter(JS_PropertyStub);
+        desc.setSetter(JS_StrictPropertyStub);
     }
 
-    if (!JS_WrapValue(cx, &desc->value) || !JS_WrapValue(cx, fval.address()))
+    if (!JS_WrapValue(cx, desc.value().address()) || !JS_WrapValue(cx, fval.address()))
         return false;
 
-    if (desc->attrs & JSPROP_GETTER)
-        desc->getter = js::CastAsJSPropertyOp(JSVAL_TO_OBJECT(fval));
-    if (desc->attrs & JSPROP_SETTER)
-        desc->setter = js::CastAsJSStrictPropertyOp(JSVAL_TO_OBJECT(fval));
+    if (desc.hasGetterObject())
+        desc.setGetterObject(&fval.toObject());
+    if (desc.hasSetterObject())
+        desc.setSetterObject(&fval.toObject());
 
     // Define the property.
-    return JS_DefinePropertyById(cx, holder, id, desc->value,
-                                 desc->getter, desc->setter, desc->attrs);
+    return JS_DefinePropertyById(cx, holder, id, desc.value(),
+                                 desc.getter(), desc.setter(), desc.attributes());
 }
 
 static bool
 wrappedJSObject_getter(JSContext *cx, HandleObject wrapper, HandleId id, MutableHandleValue vp)
 {
     if (!IsWrapper(wrapper) || !WrapperFactory::IsXrayWrapper(wrapper)) {
         JS_ReportError(cx, "Unexpected object");
         return false;
@@ -791,48 +795,49 @@ wrappedJSObject_getter(JSContext *cx, Ha
     vp.set(OBJECT_TO_JSVAL(wrapper));
 
     return WrapperFactory::WaiveXrayAndWrap(cx, vp.address());
 }
 
 bool
 XrayTraits::resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper,
                                HandleObject wrapper, HandleObject holder, HandleId id,
-                               PropertyDescriptor *desc, unsigned flags)
+                               MutableHandle<PropertyDescriptor> desc, unsigned flags)
 {
-    desc->obj = NULL;
+    desc.object().set(NULL);
     RootedObject target(cx, getTargetObject(wrapper));
     RootedObject expando(cx, getExpandoObject(cx, target, wrapper));
 
     // Check for expando properties first. Note that the expando object lives
     // in the target compartment.
     if (expando) {
         JSAutoCompartment ac(cx, expando);
-        if (!JS_GetPropertyDescriptorById(cx, expando, id, 0, desc))
+        if (!JS_GetPropertyDescriptorById(cx, expando, id, 0, desc.address()))
             return false;
     }
-    if (desc->obj) {
-        if (!JS_WrapPropertyDescriptor(cx, desc))
+    if (desc.object()) {
+        if (!JS_WrapPropertyDescriptor(cx, desc.address()))
             return false;
         // Pretend the property lives on the wrapper.
-        desc->obj = wrapper;
+        desc.object().set(wrapper);
         return true;
     }
     return true;
 }
 
 bool
 XPCWrappedNativeXrayTraits::resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper,
                                                HandleObject wrapper, HandleObject holder,
-                                               HandleId id, PropertyDescriptor *desc, unsigned flags)
+                                               HandleId id, MutableHandle<PropertyDescriptor> desc,
+                                               unsigned flags)
 {
     // Call the common code.
     bool ok = XrayTraits::resolveOwnProperty(cx, jsWrapper, wrapper, holder,
                                              id, desc, flags);
-    if (!ok || desc->obj)
+    if (!ok || desc.object())
         return ok;
 
     // Check for indexed access on a window.
     int32_t index = GetArrayIndexFromId(cx, id);
     if (IsArrayIndex(index)) {
         nsGlobalWindow* win =
             static_cast<nsGlobalWindow*>(As<nsPIDOMWindow>(wrapper));
         // Note: As() unwraps outer windows to get to the inner window.
@@ -842,19 +847,19 @@ XPCWrappedNativeXrayTraits::resolveOwnPr
             if (subframe) {
                 nsGlobalWindow* global = static_cast<nsGlobalWindow*>(subframe.get());
                 global->EnsureInnerWindow();
                 JSObject* obj = global->FastGetGlobalJSObject();
                 if (MOZ_UNLIKELY(!obj)) {
                     // It's gone?
                     return xpc::Throw(cx, NS_ERROR_FAILURE);
                 }
-                desc->value = ObjectValue(*obj);
+                desc.value().setObject(*obj);
                 mozilla::dom::FillPropertyDescriptor(desc, wrapper, true);
-                return JS_WrapPropertyDescriptor(cx, desc);
+                return JS_WrapPropertyDescriptor(cx, desc.address());
             }
         }
     }
 
     // Xray wrappers don't use the regular wrapper hierarchy, so we should be
     // in the wrapper's compartment here, not the wrappee.
     MOZ_ASSERT(js::IsObjectInContextCompartment(wrapper, cx));
 
@@ -892,37 +897,37 @@ XPCWrappedNativeXrayTraits::resolveOwnPr
     // we have to use it. But we have no way of knowing if it corresponded to an
     // |own| or non-|own| property, since both get cached on the holder and the
     // |own|-ness information is lost.
     //
     // So we just over-zealously call things |own| here. This can cause us to
     // return non-|own| properties from Object.getOwnPropertyDescriptor if
     // lookups are performed in a certain order, but we can probably live with
     // that until XPCWN Xrays go away with the new DOM bindings.
-    return JS_GetPropertyDescriptorById(cx, holder, id, 0, desc);
+    return JS_GetPropertyDescriptorById(cx, holder, id, 0, desc.address());
 }
 
 bool
 XPCWrappedNativeXrayTraits::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                                           PropertyDescriptor *desc,
+                                           MutableHandle<PropertyDescriptor> desc,
                                            Handle<PropertyDescriptor> existingDesc, bool *defined)
 {
     *defined = false;
     JSObject *holder = singleton.ensureHolder(cx, wrapper);
     if (isResolving(cx, holder, id)) {
-        if (!(desc->attrs & (JSPROP_GETTER | JSPROP_SETTER))) {
-            if (!desc->getter)
-                desc->getter = holder_get;
-            if (!desc->setter)
-                desc->setter = holder_set;
+        if (!desc.hasAttributes(JSPROP_GETTER | JSPROP_SETTER)) {
+            if (!desc.getter())
+                desc.setGetter(holder_get);
+            if (!desc.setter())
+                desc.setSetter(holder_set);
         }
 
         *defined = true;
-        return JS_DefinePropertyById(cx, holder, id, desc->value, desc->getter, desc->setter,
-                                     desc->attrs);
+        return JS_DefinePropertyById(cx, holder, id, desc.value(), desc.getter(), desc.setter(),
+                                     desc.attributes());
     }
 
     // Check for an indexed property on a Window.  If that's happening, do
     // nothing but claim we defined it so it won't get added as an expando.
     int32_t index = GetArrayIndexFromId(cx, id);
     if (IsArrayIndex(index) && Is<nsIDOMWindow>(wrapper)) {
         *defined = true;
         return true;
@@ -1019,55 +1024,55 @@ XPCWrappedNativeXrayTraits::construct(JS
 
     return true;
 
 }
 
 bool
 DOMXrayTraits::resolveNativeProperty(JSContext *cx, HandleObject wrapper,
                                      HandleObject holder, HandleId id,
-                                     JSPropertyDescriptor *desc, unsigned flags)
+                                     MutableHandle<PropertyDescriptor> desc, unsigned flags)
 {
     RootedObject obj(cx, getTargetObject(wrapper));
-    if (!XrayResolveNativeProperty(cx, wrapper, obj, id, desc))
+    if (!XrayResolveNativeProperty(cx, wrapper, obj, id, desc.address()))
         return false;
 
-    NS_ASSERTION(!desc->obj || desc->obj == wrapper,
+    NS_ASSERTION(!desc.object() || desc.object() == wrapper,
                  "What did we resolve this on?");
 
     return true;
 }
 
 bool
 DOMXrayTraits::resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper, HandleObject wrapper,
                                   HandleObject holder, HandleId id,
-                                  JSPropertyDescriptor *desc, unsigned flags)
+                                  MutableHandle<PropertyDescriptor> desc, unsigned flags)
 {
     // Call the common code.
     bool ok = XrayTraits::resolveOwnProperty(cx, jsWrapper, wrapper, holder,
                                              id, desc, flags);
-    if (!ok || desc->obj)
+    if (!ok || desc.object())
         return ok;
 
     RootedObject obj(cx, getTargetObject(wrapper));
     if (!XrayResolveOwnProperty(cx, wrapper, obj, id, desc, flags))
         return false;
 
-    NS_ASSERTION(!desc->obj || desc->obj == wrapper,
+    NS_ASSERTION(!desc.object() || desc.object() == wrapper,
                  "What did we resolve this on?");
 
     return true;
 }
 
 bool
 DOMXrayTraits::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id,
-                              PropertyDescriptor *desc,
+                              MutableHandle<PropertyDescriptor> desc,
                               Handle<PropertyDescriptor> existingDesc, bool *defined)
 {
-    if (!existingDesc.obj())
+    if (!existingDesc.object())
         return true;
 
     JS::Rooted<JSObject*> obj(cx, getTargetObject(wrapper));
     return XrayDefineProperty(cx, wrapper, obj, id, desc, defined);
 }
 
 bool
 DOMXrayTraits::enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags,
@@ -1197,34 +1202,34 @@ HasNativeProperty(JSContext *cx, HandleO
     *hasProp = false;
     Rooted<PropertyDescriptor> desc(cx);
     Wrapper *handler = Wrapper::wrapperHandler(wrapper);
 
     // Try resolveOwnProperty.
     Maybe<ResolvingId> resolvingId;
     if (traits == &XPCWrappedNativeXrayTraits::singleton)
         resolvingId.construct(cx, wrapper, id);
-    if (!traits->resolveOwnProperty(cx, *handler, wrapper, holder, id, desc.address(), 0))
+    if (!traits->resolveOwnProperty(cx, *handler, wrapper, holder, id, &desc, 0))
         return false;
     if (desc.object()) {
         *hasProp = true;
         return true;
     }
 
     // Try the holder.
     bool found = false;
     if (!JS_AlreadyHasOwnPropertyById(cx, holder, id, &found))
         return false;
     if (found) {
         *hasProp = true;
         return true;
     }
 
     // Try resolveNativeProperty.
-    if (!traits->resolveNativeProperty(cx, wrapper, holder, id, desc.address(), 0))
+    if (!traits->resolveNativeProperty(cx, wrapper, holder, id, &desc, 0))
         return false;
     *hasProp = !!desc.object();
     return true;
 }
 
 } // namespace XrayUtils
 
 static bool
@@ -1330,42 +1335,43 @@ XrayWrapper<Base, Traits>::preventExtens
     // See above.
     JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_CANT_CHANGE_EXTENSIBILITY);
     return false;
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::getPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
-                                                 PropertyDescriptor *desc, unsigned flags)
+                                                 JS::MutableHandle<PropertyDescriptor> desc,
+                                                 unsigned flags)
 {
     assertEnteredPolicy(cx, wrapper, id);
     RootedObject holder(cx, Traits::singleton.ensureHolder(cx, wrapper));
     if (Traits::isResolving(cx, holder, id)) {
-        desc->obj = NULL;
+        desc.object().set(NULL);
         return true;
     }
 
     typename Traits::ResolvingIdImpl resolving(cx, wrapper, id);
 
     if (!holder)
         return false;
 
     // Only chrome wrappers and same-origin xrays (used by jetpack sandboxes)
     // get .wrappedJSObject. We can check this by determining if the compartment
     // of the wrapper subsumes that of the wrappee.
     XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
     if (AccessCheck::wrapperSubsumes(wrapper) &&
         id == rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT)) {
-        desc->obj = wrapper;
-        desc->attrs = JSPROP_ENUMERATE|JSPROP_SHARED;
-        desc->getter = wrappedJSObject_getter;
-        desc->setter = NULL;
-        desc->shortid = 0;
-        desc->value = JSVAL_VOID;
+        desc.object().set(wrapper);
+        desc.setAttributes(JSPROP_ENUMERATE|JSPROP_SHARED);
+        desc.setGetter(wrappedJSObject_getter);
+        desc.setSetter(NULL);
+        desc.setShortId(0);
+        desc.value().set(JSVAL_VOID);
         return true;
     }
 
     // Ordering is important here.
     //
     // We first need to call resolveOwnProperty, even before checking the holder,
     // because there might be a new dynamic |own| property that appears and
     // shadows a previously-resolved non-own property that we cached on the
@@ -1383,65 +1389,65 @@ XrayWrapper<Base, Traits>::getPropertyDe
     // Finally, we call resolveNativeProperty, which checks non-own properties,
     // and unconditionally caches what it finds on the holder.
 
     // Check resolveOwnProperty.
     if (!Traits::singleton.resolveOwnProperty(cx, *this, wrapper, holder, id, desc, flags))
         return false;
 
     // Check the holder.
-    if (!desc->obj && !JS_GetPropertyDescriptorById(cx, holder, id, 0, desc))
+    if (!desc.object() && !JS_GetPropertyDescriptorById(cx, holder, id, 0, desc.address()))
         return false;
-    if (desc->obj) {
-        desc->obj = wrapper;
+    if (desc.object()) {
+        desc.object().set(wrapper);
         return true;
     }
 
     // Nothing in the cache. Call through, and cache the result.
     if (!Traits::singleton.resolveNativeProperty(cx, wrapper, holder, id, desc, flags))
         return false;
 
     // We need to handle named access on the Window somewhere other than
     // Traits::resolveOwnProperty, because per spec it happens on the Global
     // Scope Polluter and thus the resulting properties are non-|own|. However,
     // we're set up (above) to cache (on the holder) anything that comes out of
     // resolveNativeProperty, which we don't want for something dynamic like
     // named access. So we just handle it separately here.
     nsGlobalWindow *win;
-    if (!desc->obj && Traits::Type == XrayForWrappedNative && JSID_IS_STRING(id) &&
+    if (!desc.object() && Traits::Type == XrayForWrappedNative && JSID_IS_STRING(id) &&
         (win = static_cast<nsGlobalWindow*>(As<nsPIDOMWindow>(wrapper))))
     {
         nsDependentJSString name(id);
         nsCOMPtr<nsIDOMWindow> childDOMWin = win->GetChildWindow(name);
         if (childDOMWin) {
             nsGlobalWindow *cwin = static_cast<nsGlobalWindow*>(childDOMWin.get());
             JSObject *childObj = cwin->FastGetGlobalJSObject();
             if (MOZ_UNLIKELY(!childObj))
                 return xpc::Throw(cx, NS_ERROR_FAILURE);
             mozilla::dom::FillPropertyDescriptor(desc, wrapper,
                                                  ObjectValue(*childObj),
                                                  /* readOnly = */ true);
-            return JS_WrapPropertyDescriptor(cx, desc);
+            return JS_WrapPropertyDescriptor(cx, desc.address());
         }
     }
 
-    if (!desc->obj &&
+    if (!desc.object() &&
         id == nsXPConnect::GetRuntimeInstance()->GetStringID(XPCJSRuntime::IDX_TO_STRING))
     {
 
         JSFunction *toString = JS_NewFunction(cx, XrayToString, 0, 0, holder, "toString");
         if (!toString)
             return false;
 
-        desc->obj = wrapper;
-        desc->attrs = 0;
-        desc->getter = NULL;
-        desc->setter = NULL;
-        desc->shortid = 0;
-        desc->value.setObject(*JS_GetFunctionObject(toString));
+        desc.object().set(wrapper);
+        desc.setAttributes(0);
+        desc.setGetter(NULL);
+        desc.setSetter(NULL);
+        desc.setShortId(0);
+        desc.value().setObject(*JS_GetFunctionObject(toString));
     }
 
     // If we're a special scope for in-content XBL, our script expects to see
     // the bound XBL methods and attributes when accessing content. However,
     // these members are implemented in content via custom-spliced prototypes,
     // and thus aren't visible through Xray wrappers unless we handle them
     // explicitly. So we check if we're running in such a scope, and if so,
     // whether the wrappee is a bound element. If it is, we do a lookup via
@@ -1449,61 +1455,62 @@ XrayWrapper<Base, Traits>::getPropertyDe
     //
     // While we have to do some sketchy walking through content land, we should
     // be protected by read-only/non-configurable properties, and any functions
     // we end up with should _always_ be living in an XBL scope (usually ours,
     // but could be another if the node has been adopted).
     //
     // Make sure to assert this.
     nsCOMPtr<nsIContent> content;
-    if (!desc->obj &&
+    if (!desc.object() &&
         EnsureCompartmentPrivate(wrapper)->scope->IsXBLScope() &&
         (content = do_QueryInterfaceNative(cx, wrapper)))
     {
-        if (!nsContentUtils::LookupBindingMember(cx, content, id, desc))
+        if (!nsContentUtils::LookupBindingMember(cx, content, id, desc.address()))
             return false;
-        DEBUG_CheckXBLLookup(cx, desc);
+        DEBUG_CheckXBLLookup(cx, desc.address());
     }
 
     // If we still have nothing, we're done.
-    if (!desc->obj)
+    if (!desc.object())
         return true;
 
-    if (!JS_DefinePropertyById(cx, holder, id, desc->value, desc->getter,
-                               desc->setter, desc->attrs) ||
-        !JS_GetPropertyDescriptorById(cx, holder, id, flags, desc))
+    if (!JS_DefinePropertyById(cx, holder, id, desc.value(), desc.getter(),
+                               desc.setter(), desc.attributes()) ||
+        !JS_GetPropertyDescriptorById(cx, holder, id, flags, desc.address()))
     {
         return false;
     }
-    MOZ_ASSERT(desc->obj);
-    desc->obj = wrapper;
+    MOZ_ASSERT(desc.object());
+    desc.object().set(wrapper);
     return true;
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::getOwnPropertyDescriptor(JSContext *cx, HandleObject wrapper, HandleId id,
-                                                    PropertyDescriptor *desc, unsigned flags)
+                                                    JS::MutableHandle<PropertyDescriptor> desc,
+                                                    unsigned flags)
 {
     assertEnteredPolicy(cx, wrapper, id);
     RootedObject holder(cx, Traits::singleton.ensureHolder(cx, wrapper));
     if (Traits::isResolving(cx, holder, id)) {
-        desc->obj = NULL;
+        desc.object().set(NULL);
         return true;
     }
 
     typename Traits::ResolvingIdImpl resolving(cx, wrapper, id);
 
     // NB: Nothing we do here acts on the wrapped native itself, so we don't
     // enter our policy.
 
     if (!Traits::singleton.resolveOwnProperty(cx, *this, wrapper, holder, id, desc, flags))
         return false;
-    if (desc->obj)
-        desc->obj = wrapper;
+    if (desc.object())
+        desc.object().set(wrapper);
     return true;
 }
 
 // Consider what happens when chrome does |xray.expando = xray.wrappedJSObject|.
 //
 // Since the expando comes from the target compartment, wrapping it back into
 // the target compartment to define it on the expando object ends up stripping
 // off the Xray waiver that gives |xray| and |xray.wrappedJSObject| different
@@ -1557,24 +1564,24 @@ RecreateLostWaivers(JSContext *cx, Prope
     }
 
     return true;
 }
 
 template <typename Base, typename Traits>
 bool
 XrayWrapper<Base, Traits>::defineProperty(JSContext *cx, HandleObject wrapper,
-                                          HandleId id, PropertyDescriptor *desc)
+                                          HandleId id, MutableHandle<PropertyDescriptor> desc)
 {
     assertEnteredPolicy(cx, wrapper, id);
 
     // NB: We still need JSRESOLVE_ASSIGNING here for the time being, because it
     // tells things like nodelists whether they should create the property or not.
     Rooted<PropertyDescriptor> existing_desc(cx);
-    if (!getOwnPropertyDescriptor(cx, wrapper, id, existing_desc.address(), JSRESOLVE_ASSIGNING))
+    if (!getOwnPropertyDescriptor(cx, wrapper, id, &existing_desc, JSRESOLVE_ASSIGNING))
         return false;
 
     if (existing_desc.object() && existing_desc.isPermanent())
         return true; // silently ignore attempt to overwrite native property
 
     bool defined = false;
     if (!Traits::defineProperty(cx, wrapper, id, desc, existing_desc, &defined))
         return false;
@@ -1588,22 +1595,22 @@ XrayWrapper<Base, Traits>::definePropert
 
     // Grab the relevant expando object.
     RootedObject expandoObject(cx, Traits::singleton.ensureExpandoObject(cx, wrapper,
                                                                          target));
     if (!expandoObject)
         return false;
 
     // Wrap the property descriptor for the target compartment.
-    Rooted<PropertyDescriptor> wrappedDesc(cx, *desc);
+    Rooted<PropertyDescriptor> wrappedDesc(cx, desc);
     if (!JS_WrapPropertyDescriptor(cx, wrappedDesc.address()))
         return false;
 
     // Fix up Xray waivers.
-    if (!RecreateLostWaivers(cx, desc, &wrappedDesc))
+    if (!RecreateLostWaivers(cx, desc.address(), &wrappedDesc))
         return false;
 
     return JS_DefinePropertyById(cx, expandoObject, id, wrappedDesc.value(),
                                  wrappedDesc.getter(), wrappedDesc.setter(),
                                  wrappedDesc.get().attrs);
 }
 
 template <typename Base, typename Traits>
--- a/js/xpconnect/wrappers/XrayWrapper.h
+++ b/js/xpconnect/wrappers/XrayWrapper.h
@@ -68,22 +68,22 @@ class XrayWrapper : public Base {
   public:
     XrayWrapper(unsigned flags);
     virtual ~XrayWrapper();
 
     /* Fundamental proxy traps. */
     virtual bool isExtensible(JSContext *cx, JS::Handle<JSObject*> wrapper, bool *extensible) MOZ_OVERRIDE;
     virtual bool preventExtensions(JSContext *cx, JS::Handle<JSObject*> wrapper) MOZ_OVERRIDE;
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
-                                       js::PropertyDescriptor *desc, unsigned flags);
+                                       JS::MutableHandle<js::PropertyDescriptor> desc, unsigned flags);
     virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
-                                          js::PropertyDescriptor *desc,
+                                          JS::MutableHandle<js::PropertyDescriptor> desc,
                                           unsigned flags);
     virtual bool defineProperty(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<jsid> id,
-                                js::PropertyDescriptor *desc);
+                                JS::MutableHandle<js::PropertyDescriptor> desc);
     virtual bool getOwnPropertyNames(JSContext *cx, JS::Handle<JSObject*> wrapper,
                                      js::AutoIdVector &props);
     virtual bool delete_(JSContext *cx, JS::Handle<JSObject*> wrapper,
                          JS::Handle<jsid> id, bool *bp);
     virtual bool enumerate(JSContext *cx, JS::Handle<JSObject*> wrapper, js::AutoIdVector &props);
 
     /* Derived proxy traps. */
     virtual bool get(JSContext *cx, JS::Handle<JSObject*> wrapper, JS::Handle<JSObject*> receiver,
@@ -125,20 +125,22 @@ class XrayWrapper : public Base {
 
 class SandboxProxyHandler : public js::Wrapper {
 public:
     SandboxProxyHandler() : js::Wrapper(0)
     {
     }
 
     virtual bool getPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> proxy,
-                                       JS::Handle<jsid> id, js::PropertyDescriptor *desc,
+                                       JS::Handle<jsid> id,
+                                       JS::MutableHandle<js::PropertyDescriptor> desc,
                                        unsigned flags) MOZ_OVERRIDE;
     virtual bool getOwnPropertyDescriptor(JSContext *cx, JS::Handle<JSObject*> proxy,
-                                          JS::Handle<jsid> id, js::PropertyDescriptor *desc,
+                                          JS::Handle<jsid> id,
+                                          JS::MutableHandle<js::PropertyDescriptor> desc,
                                           unsigned flags) MOZ_OVERRIDE;
 
     // We just forward the derived traps to the BaseProxyHandler versions which
     // implement them in terms of the fundamental traps.
     virtual bool has(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
                      bool *bp) MOZ_OVERRIDE;
     virtual bool hasOwn(JSContext *cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
                         bool *bp) MOZ_OVERRIDE;