Bug 959787 - Handlify JS_GetProperty and related APIs r=terrence r=bz
authorJon Coppeard <jcoppeard@mozilla.com>
Fri, 31 Jan 2014 09:55:20 +0000
changeset 182526 0c194a7651a53aa67438b02f2cbbb74a2f6de61f
parent 182525 02302b3cdd847b428fdce428e2dbce3ae56b75b1
child 182527 a9930b656941c2f7917dcb6d329d951af912d2ce
push id3343
push userffxbld
push dateMon, 17 Mar 2014 21:55:32 +0000
treeherdermozilla-beta@2f7d3415f79f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersterrence, bz
bugs959787
milestone29.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 959787 - Handlify JS_GetProperty and related APIs r=terrence r=bz
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/bindings/BindingUtils.h
dom/bindings/CallbackInterface.cpp
dom/bindings/Codegen.py
dom/bluetooth/BluetoothService.cpp
dom/media/MediaManager.cpp
dom/network/src/TCPSocketParent.cpp
dom/plugins/base/nsJSNPRuntime.cpp
dom/system/gonk/AutoMounterSetting.cpp
dom/system/gonk/TimeZoneSettingObserver.cpp
js/src/jsapi-tests/testException.cpp
js/src/jsapi-tests/testStructuredClone.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/src/XPCWrappedJSClass.cpp
js/xpconnect/src/XPCWrappedNative.cpp
toolkit/components/ctypes/ctypes.cpp
toolkit/components/perf/PerfMeasurement.cpp
toolkit/components/places/History.cpp
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -3615,17 +3615,17 @@ nsGenericArraySH::NewResolve(nsIXPConnec
     }
   }
 
   return NS_OK;
 }
 
 nsresult
 nsGenericArraySH::GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
-                             JSObject *obj, uint32_t *length)
+                            JS::Handle<JSObject*> obj, uint32_t *length)
 {
   *length = 0;
 
   JS::Rooted<JS::Value> lenval(cx);
   if (!JS_GetProperty(cx, obj, "length", &lenval)) {
     return NS_ERROR_UNEXPECTED;
   }
 
@@ -3990,17 +3990,17 @@ nsHTMLDocumentSH::CallToGetPropMapper(JS
   // Convert all types to string.
   JS::Rooted<JSString*> str(cx, JS::ToString(cx, args[0]));
   if (!str) {
     return false;
   }
 
   // If we are called via document.all(id) instead of document.all.item(i) or
   // another method, use the document.all callee object as self.
-  JSObject *self;
+  JS::Rooted<JSObject*> self(cx);
   if (args.calleev().isObject() &&
       JS_GetClass(&args.calleev().toObject()) == &sHTMLDocumentAllClass) {
     self = &args.calleev().toObject();
   } else {
     self = JS_THIS_OBJECT(cx, vp);
     if (!self)
       return false;
   }
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -323,26 +323,26 @@ class nsGenericArraySH : public nsDOMCla
 protected:
   nsGenericArraySH(nsDOMClassInfoData* aData) : nsDOMClassInfo(aData)
   {
   }
 
   virtual ~nsGenericArraySH()
   {
   }
-  
+
 public:
   NS_IMETHOD NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                         JSObject *obj, jsid id, uint32_t flags,
                         JSObject **objp, bool *_retval) MOZ_OVERRIDE;
   NS_IMETHOD Enumerate(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                        JSObject *obj, bool *_retval) MOZ_OVERRIDE;
-  
+
   virtual nsresult GetLength(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
-                             JSObject *obj, uint32_t *length);
+                             JS::Handle<JSObject*> obj, uint32_t *length);
 
   static nsIClassInfo *doCreate(nsDOMClassInfoData* aData)
   {
     return new nsGenericArraySH(aData);
   }
 };
 
 
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -2422,17 +2422,16 @@ CreateGlobal(JSContext* aCx, T* aObject,
 class InternedStringId
 {
   jsid id;
 
  public:
   InternedStringId() : id(JSID_VOID) {}
 
   bool init(JSContext *cx, const char *string) {
-    MOZ_ASSERT(id == JSID_VOID);
     JSString* str = JS_InternString(cx, string);
     if (!str)
       return false;
     id = INTERNED_STRING_TO_JSID(cx, str);
     return true;
   }
 
   operator const jsid& () {
--- a/dom/bindings/CallbackInterface.cpp
+++ b/dom/bindings/CallbackInterface.cpp
@@ -11,17 +11,17 @@
 
 namespace mozilla {
 namespace dom {
 
 bool
 CallbackInterface::GetCallableProperty(JSContext* cx, const char* aPropName,
                                        JS::MutableHandle<JS::Value> aCallable)
 {
-  if (!JS_GetProperty(cx, mCallback, aPropName, aCallable)) {
+  if (!JS_GetProperty(cx, CallbackPreserveColor(), aPropName, aCallable)) {
     return false;
   }
   if (!aCallable.isObject() ||
       !JS_ObjectIsCallable(cx, &aCallable.toObject())) {
     nsPrintfCString description("Property '%s'", aPropName);
     ThrowErrorMessage(cx, MSG_NOT_CALLABLE, description.get());
     return false;
   }
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -9100,19 +9100,21 @@ if (cx) {
                 "}\n"
                 "\n")
 
         memberInits = [self.getMemberConversion(m).define()
                        for m in self.memberInfo]
         if memberInits:
             body += (
                 "bool isNull = val.isNullOrUndefined();\n"
-                "// We only need |temp| if !isNull, in which case we have |cx|.\n"
+                "// We only need these if !isNull, in which case we have |cx|.\n"
+                "Maybe<JS::Rooted<JSObject *> > object;\n"
                 "Maybe<JS::Rooted<JS::Value> > temp;\n"
                 "if (!isNull) {\n"
+                "  object.construct(cx, &val.toObject());\n"
                 "  temp.construct(cx);\n"
                 "}\n")
             body += "\n\n".join(memberInits) + "\n"
 
         body += "return true;"
 
         return ClassMethod("Init", "bool", [
             Argument('JSContext*', 'cx'),
@@ -9168,17 +9170,17 @@ if (!*reinterpret_cast<jsid**>(atomsCach
         return ClassMethod("ToObject", "bool", [
             Argument('JSContext*', 'cx'),
             Argument('JS::Handle<JSObject*>', 'parentObject'),
             Argument('JS::MutableHandle<JS::Value>', 'rval'),
         ], const=True, body=body)
 
     def initIdsMethod(self):
         assert self.needToInitIds
-        idinit = [CGGeneric('!InternJSString(cx, atomsCache->%s, "%s")' %
+        idinit = [CGGeneric('!atomsCache->%s.init(cx, "%s")' %
                             (m.identifier.name + "_id", m.identifier.name))
                   for m in self.dictionary.members]
         idinit.reverse();
         idinit = CGList(idinit, " ||\n")
         idinit = CGWrapper(idinit, pre="""
 // Initialize these in reverse order so that any failure leaves the first one
 // uninitialized.
 if (""",
@@ -9353,17 +9355,17 @@ if (""",
         # We can't handle having a holderType here
         assert conversionInfo.holderType is None
         if conversionInfo.dealWithOptional:
             replacements["declName"] = "(" + replacements["declName"] + ".Value())"
         if member.defaultValue:
             replacements["haveValue"] = "!isNull && !temp.ref().isUndefined()"
 
         propId = self.makeIdName(member.identifier.name);
-        propGet = ("JS_GetPropertyById(cx, &val.toObject(), atomsCache->%s, &temp.ref())" %
+        propGet = ("JS_GetPropertyById(cx, object.ref(), atomsCache->%s, &temp.ref())" %
                    propId)
 
         conversionReplacements = {
             "prop": self.makeMemberName(member.identifier.name),
             "convert": string.Template(conversionInfo.template).substitute(replacements),
             "propGet": propGet
             }
         conversion = ("if (!isNull && !${propGet}) {\n"
@@ -11430,17 +11432,18 @@ class CallbackGetter(CallbackAccessor):
 
     def getCall(self):
         replacements = {
             "errorReturn" : self.getDefaultRetval(),
             "attrName": self.descriptorProvider.binaryNames.get(self.attrName,
                                                                 self.attrName)
             }
         return string.Template(
-            'if (!JS_GetProperty(cx, mCallback, "${attrName}", &rval)) {\n'
+            'JS::Rooted<JSObject *> callback(cx, mCallback);\n'
+            'if (!JS_GetProperty(cx, callback, "${attrName}", &rval)) {\n'
             '  aRv.Throw(NS_ERROR_UNEXPECTED);\n'
             '  return${errorReturn};\n'
             '}\n').substitute(replacements);
 
 class CallbackSetter(CallbackAccessor):
     def __init__(self, attr, descriptor):
         CallbackAccessor.__init__(self, attr,
                                   (BuiltinTypes[IDLBuiltinType.Types.void],
@@ -11497,19 +11500,18 @@ class GlobalGenRoots():
         structs = []
 
         for dict in dictionaries:
             dictMembers = dict.members
             if len(dictMembers) == 0:
                 continue
 
             classMembers = [ClassMember(m.identifier.name + "_id",
-                                        "jsid",
-                                        visibility="public",
-                                        body="JSID_VOID") for m in dictMembers]
+                                        "InternedStringId",
+                                        visibility="public") for m in dictMembers]
 
             structName = dict.identifier.name + "Atoms"
             structs.append((structName,
                             CGWrapper(CGClass(structName,
                 bases=None,
                 isStruct=True,
                 members=classMembers), post='\n')))
 
@@ -11523,16 +11525,21 @@ class GlobalGenRoots():
 
         structs = CGList(generatedStructs + [mainStruct])
 
         # Wrap all of that in our namespaces.
         curr = CGNamespace.build(['mozilla', 'dom'],
                                   CGWrapper(structs, pre='\n'))
         curr = CGWrapper(curr, post='\n')
 
+        # Add include statement for InternedStringId.
+        declareIncludes = ['mozilla/dom/BindingUtils.h']
+        curr = CGHeaders([], [], [], [], declareIncludes, [], 'GeneratedAtomList',
+                         curr)
+
         # Add include guards.
         curr = CGIncludeGuard('GeneratedAtomList', curr)
 
         # Add the auto-generated comment.
         curr = CGWrapper(curr, pre=AUTOGENERATED_WARNING_COMMENT)
 
         # Done.
         return curr
--- a/dom/bluetooth/BluetoothService.cpp
+++ b/dom/bluetooth/BluetoothService.cpp
@@ -600,20 +600,20 @@ BluetoothService::HandleSettingsChanged(
   if (!JS_ParseJSON(cx, aData.BeginReading(), aData.Length(), &val)) {
     return JS_ReportPendingException(cx) ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
   }
 
   if (!val.isObject()) {
     return NS_OK;
   }
 
-  JSObject& obj(val.toObject());
+  JS::Rooted<JSObject*> obj(cx, &val.toObject());
 
   JS::Rooted<JS::Value> key(cx);
-  if (!JS_GetProperty(cx, &obj, "key", &key)) {
+  if (!JS_GetProperty(cx, obj, "key", &key)) {
     MOZ_ASSERT(!JS_IsExceptionPending(cx));
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   if (!key.isString()) {
     return NS_OK;
   }
 
@@ -621,17 +621,17 @@ BluetoothService::HandleSettingsChanged(
   bool match;
   if (!JS_StringEqualsAscii(cx, key.toString(), BLUETOOTH_DEBUGGING_SETTING, &match)) {
     MOZ_ASSERT(!JS_IsExceptionPending(cx));
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   if (match) {
     JS::Rooted<JS::Value> value(cx);
-    if (!JS_GetProperty(cx, &obj, "value", &value)) {
+    if (!JS_GetProperty(cx, obj, "value", &value)) {
       MOZ_ASSERT(!JS_IsExceptionPending(cx));
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     if (!value.isBoolean()) {
       MOZ_ASSERT(false, "Expecting a boolean for 'bluetooth.debugging.enabled'!");
       return NS_ERROR_UNEXPECTED;
     }
@@ -644,17 +644,17 @@ BluetoothService::HandleSettingsChanged(
   // Second, check if the string is BLUETOOTH_ENABLED_SETTING
   if (!JS_StringEqualsAscii(cx, key.toString(), BLUETOOTH_ENABLED_SETTING, &match)) {
     MOZ_ASSERT(!JS_IsExceptionPending(cx));
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   if (match) {
     JS::Rooted<JS::Value> value(cx);
-    if (!JS_GetProperty(cx, &obj, "value", &value)) {
+    if (!JS_GetProperty(cx, obj, "value", &value)) {
       MOZ_ASSERT(!JS_IsExceptionPending(cx));
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     if (!value.isBoolean()) {
       MOZ_ASSERT(false, "Expecting a boolean for 'bluetooth.enabled'!");
       return NS_ERROR_UNEXPECTED;
     }
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -93,17 +93,18 @@ static nsresult CompareDictionaries(JSCo
   JS::Rooted<JSObject*> b(aCx, &bval.toObject());
 
   // Iterate over each property in A, and check if it is in B
 
   JS::AutoIdArray props(aCx, JS_Enumerate(aCx, a));
 
   for (size_t i = 0; i < props.length(); i++) {
     JS::Rooted<JS::Value> bprop(aCx);
-    if (!JS_GetPropertyById(aCx, b, props[i], &bprop)) {
+    JS::Rooted<jsid> id(aCx, props[i]);
+    if (!JS_GetPropertyById(aCx, b, id, &bprop)) {
       LOG(("Error parsing dictionary!\n"));
       return NS_ERROR_UNEXPECTED;
     }
     if (bprop.isUndefined()) {
       // Unknown property found in A. Bail with name
       JS::Rooted<JS::Value> nameval(aCx);
       bool success = JS_IdToValue(aCx, props[i], &nameval);
       NS_ENSURE_TRUE(success, NS_ERROR_UNEXPECTED);
--- a/dom/network/src/TCPSocketParent.cpp
+++ b/dom/network/src/TCPSocketParent.cpp
@@ -212,17 +212,17 @@ TCPSocketParent::SendEvent(const nsAStri
       return NS_ERROR_OUT_OF_MEMORY;
     }
     data = SendableData(str);
 
   } else if (aDataVal.isUndefined() || aDataVal.isNull()) {
     data = mozilla::void_t();
 
   } else if (aDataVal.isObject()) {
-    JSObject* obj = &aDataVal.toObject();
+    JS::Rooted<JSObject *> obj(aCx, &aDataVal.toObject());
     if (JS_IsArrayBufferObject(obj)) {
       uint32_t nbytes = JS_GetArrayBufferByteLength(obj);
       uint8_t* buffer = JS_GetArrayBufferData(obj);
       if (!buffer) {
         FireInteralError(this, __LINE__);
         return NS_ERROR_OUT_OF_MEMORY;
       }
       FallibleTArray<uint8_t> fallibleArr;
--- a/dom/plugins/base/nsJSNPRuntime.cpp
+++ b/dom/plugins/base/nsJSNPRuntime.cpp
@@ -552,21 +552,23 @@ nsJSObjWrapper::NP_Invalidate(NPObject *
     nsJSObjWrapperKey key(jsnpobj->mJSObj, jsnpobj->mNpp);
     sJSObjWrappers.remove(key);
 
     jsnpobj->ClearJSObject();
   }
 }
 
 static bool
-GetProperty(JSContext *cx, JSObject *obj, NPIdentifier id, JS::MutableHandle<JS::Value> rval)
+GetProperty(JSContext *cx, JSObject *objArg, NPIdentifier npid, JS::MutableHandle<JS::Value> rval)
 {
-  NS_ASSERTION(NPIdentifierIsInt(id) || NPIdentifierIsString(id),
+  NS_ASSERTION(NPIdentifierIsInt(npid) || NPIdentifierIsString(npid),
                "id must be either string or int!\n");
-  return ::JS_GetPropertyById(cx, obj, NPIdentifierToJSId(id), rval);
+  JS::Rooted<JSObject *> obj(cx, objArg);
+  JS::Rooted<jsid> id(cx, NPIdentifierToJSId(npid));
+  return ::JS_GetPropertyById(cx, obj, id, rval);
 }
 
 // static
 bool
 nsJSObjWrapper::NP_HasMethod(NPObject *npobj, NPIdentifier id)
 {
   NPP npp = NPPStack::Peek();
   JSContext *cx = GetJSContext(npp);
--- a/dom/system/gonk/AutoMounterSetting.cpp
+++ b/dom/system/gonk/AutoMounterSetting.cpp
@@ -237,31 +237,31 @@ AutoMounterSetting::Observe(nsISupports*
 
   mozilla::AutoSafeJSContext cx;
   nsDependentString dataStr(aData);
   JS::Rooted<JS::Value> val(cx);
   if (!JS_ParseJSON(cx, dataStr.get(), dataStr.Length(), &val) ||
       !val.isObject()) {
     return NS_OK;
   }
-  JSObject& obj(val.toObject());
+  JS::Rooted<JSObject*> obj(cx, &val.toObject());
   JS::Rooted<JS::Value> key(cx);
-  if (!JS_GetProperty(cx, &obj, "key", &key) ||
+  if (!JS_GetProperty(cx, obj, "key", &key) ||
       !key.isString()) {
     return NS_OK;
   }
 
   JSString *jsKey = JS::ToString(cx, key);
   nsDependentJSString keyStr;
   if (!keyStr.init(cx, jsKey)) {
     return NS_OK;
   }
 
   JS::Rooted<JS::Value> value(cx);
-  if (!JS_GetProperty(cx, &obj, "value", &value)) {
+  if (!JS_GetProperty(cx, obj, "value", &value)) {
     return NS_OK;
   }
 
   // Check for ums.mode changes
   if (keyStr.EqualsLiteral(UMS_MODE)) {
     if (!value.isInt32()) {
       return NS_OK;
     }
--- a/dom/system/gonk/TimeZoneSettingObserver.cpp
+++ b/dom/system/gonk/TimeZoneSettingObserver.cpp
@@ -204,31 +204,31 @@ TimeZoneSettingObserver::Observe(nsISupp
   nsDependentString dataStr(aData);
   JS::Rooted<JS::Value> val(cx);
   if (!JS_ParseJSON(cx, dataStr.get(), dataStr.Length(), &val) ||
       !val.isObject()) {
     return NS_OK;
   }
 
   // Get the key, which should be the JS string "time.timezone".
-  JSObject &obj(val.toObject());
+  JS::Rooted<JSObject*> obj(cx, &val.toObject());
   JS::Rooted<JS::Value> key(cx);
-  if (!JS_GetProperty(cx, &obj, "key", &key) ||
+  if (!JS_GetProperty(cx, obj, "key", &key) ||
       !key.isString()) {
     return NS_OK;
   }
   bool match;
   if (!JS_StringEqualsAscii(cx, key.toString(), TIME_TIMEZONE, &match) ||
       !match) {
     return NS_OK;
   }
 
   // Get the value, which should be a JS string like "America/Chicago".
   JS::Rooted<JS::Value> value(cx);
-  if (!JS_GetProperty(cx, &obj, "value", &value) ||
+  if (!JS_GetProperty(cx, obj, "value", &value) ||
       !value.isString()) {
     return NS_OK;
   }
 
   // Set the system timezone.
   return SetTimeZone(value, cx);
 }
 
--- a/js/src/jsapi-tests/testException.cpp
+++ b/js/src/jsapi-tests/testException.cpp
@@ -12,14 +12,15 @@ BEGIN_TEST(testException_bug860435)
     JS::RootedValue fun(cx);
 
     EVAL("ReferenceError", fun.address());
     CHECK(fun.isObject());
 
     JS::RootedValue v(cx);
     JS_CallFunctionValue(cx, global, fun, 0, v.address(), v.address());
     CHECK(v.isObject());
+    JS::RootedObject obj(cx, &v.toObject());
 
-    JS_GetProperty(cx, &v.toObject(), "stack", &v);
+    JS_GetProperty(cx, obj, "stack", &v);
     CHECK(v.isString());
     return true;
 }
 END_TEST(testException_bug860435)
--- a/js/src/jsapi-tests/testStructuredClone.cpp
+++ b/js/src/jsapi-tests/testStructuredClone.cpp
@@ -26,21 +26,22 @@ BEGIN_TEST(testStructuredClone_object)
     }
 
     {
         JSAutoCompartment ac(cx, g2);
         JS::RootedValue v2(cx);
 
         CHECK(JS_StructuredClone(cx, v1, &v2, nullptr, nullptr));
         CHECK(v2.isObject());
+        JS::RootedObject obj(cx, &v2.toObject());
 
         JS::RootedValue prop(cx);
-        CHECK(JS_GetProperty(cx, &v2.toObject(), "prop", &prop));
+        CHECK(JS_GetProperty(cx, obj, "prop", &prop));
         CHECK(prop.isInt32());
-        CHECK(&v1.toObject() != &v2.toObject());
+        CHECK(&v1.toObject() != obj);
         CHECK_EQUAL(prop.toInt32(), 1337);
     }
 
     return true;
 }
 END_TEST(testStructuredClone_object)
 
 BEGIN_TEST(testStructuredClone_string)
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -3327,21 +3327,18 @@ JS_GetPropertyDescriptor(JSContext *cx, 
                          MutableHandle<JSPropertyDescriptor> desc)
 {
     RootedObject obj(cx, objArg);
     JSAtom *atom = Atomize(cx, name, strlen(name));
     return atom && JS_GetPropertyDescriptorById(cx, obj, AtomToId(atom), flags, desc);
 }
 
 JS_PUBLIC_API(bool)
-JS_GetPropertyById(JSContext *cx, JSObject *objArg, jsid idArg, MutableHandleValue vp)
-{
-    RootedObject obj(cx, objArg);
-    RootedId id(cx, idArg);
-
+JS_GetPropertyById(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
+{
     return JS_ForwardGetPropertyTo(cx, obj, id, obj, vp);
 }
 
 JS_PUBLIC_API(bool)
 JS_ForwardGetPropertyTo(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject onBehalfOf,
                         JS::MutableHandleValue vp)
 {
     AssertHeapIsIdle(cx);
@@ -3349,17 +3346,17 @@ JS_ForwardGetPropertyTo(JSContext *cx, J
     assertSameCompartment(cx, obj, id);
     assertSameCompartment(cx, onBehalfOf);
     JSAutoResolveFlags rf(cx, 0);
 
     return JSObject::getGeneric(cx, obj, onBehalfOf, id, vp);
 }
 
 JS_PUBLIC_API(bool)
-JS_GetElement(JSContext *cx, JSObject *objArg, uint32_t index, MutableHandleValue vp)
+JS_GetElement(JSContext *cx, HandleObject objArg, uint32_t index, MutableHandleValue vp)
 {
     return JS_ForwardGetElementTo(cx, objArg, index, objArg, vp);
 }
 
 JS_PUBLIC_API(bool)
 JS_ForwardGetElementTo(JSContext *cx, JSObject *objArg, uint32_t index, JSObject *onBehalfOfArg,
                        MutableHandleValue vp)
 {
@@ -3369,30 +3366,34 @@ JS_ForwardGetElementTo(JSContext *cx, JS
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JSAutoResolveFlags rf(cx, 0);
 
     return JSObject::getElement(cx, obj, onBehalfOf, index, vp);
 }
 
 JS_PUBLIC_API(bool)
-JS_GetProperty(JSContext *cx, JSObject *objArg, const char *name, MutableHandleValue vp)
-{
-    RootedObject obj(cx, objArg);
+JS_GetProperty(JSContext *cx, HandleObject obj, const char *name, MutableHandleValue vp)
+{
     JSAtom *atom = Atomize(cx, name, strlen(name));
-    return atom && JS_GetPropertyById(cx, obj, AtomToId(atom), vp);
+    if (!atom)
+        return false;
+    RootedId id(cx, AtomToId(atom));
+    return JS_GetPropertyById(cx, obj, id, vp);
 }
 
 JS_PUBLIC_API(bool)
-JS_GetUCProperty(JSContext *cx, JSObject *objArg, const jschar *name, size_t namelen,
+JS_GetUCProperty(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen,
                  MutableHandleValue vp)
 {
-    RootedObject obj(cx, objArg);
     JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
-    return atom && JS_GetPropertyById(cx, obj, AtomToId(atom), vp);
+    if (!atom)
+        return false;
+    RootedId id(cx, AtomToId(atom));
+    return JS_GetPropertyById(cx, obj, id, vp);
 }
 
 JS_PUBLIC_API(bool)
 JS_SetPropertyById(JSContext *cx, HandleObject obj, HandleId id, HandleValue v)
 {
     RootedValue value(cx, v);
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
@@ -3511,20 +3512,19 @@ JS_DeleteProperty2(JSContext *cx, Handle
 
     JSAtom *atom = Atomize(cx, name, strlen(name));
     if (!atom)
         return false;
     return JSObject::deleteByValue(cx, obj, StringValue(atom), result);
 }
 
 JS_PUBLIC_API(bool)
-JS_DeleteUCProperty2(JSContext *cx, JSObject *objArg, const jschar *name, size_t namelen,
+JS_DeleteUCProperty2(JSContext *cx, HandleObject obj, const jschar *name, size_t namelen,
                      bool *result)
 {
-    RootedObject obj(cx, objArg);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, obj);
     JSAutoResolveFlags rf(cx, 0);
 
     JSAtom *atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen));
     if (!atom)
         return false;
     return JSObject::deleteByValue(cx, obj, StringValue(atom), result);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -3022,20 +3022,20 @@ extern JS_PUBLIC_API(bool)
 JS_GetPropertyDescriptorById(JSContext *cx, JSObject *obj, jsid id, unsigned flags,
                              JS::MutableHandle<JSPropertyDescriptor> desc);
 
 extern JS_PUBLIC_API(bool)
 JS_GetPropertyDescriptor(JSContext *cx, JSObject *obj, const char *name, unsigned flags,
                          JS::MutableHandle<JSPropertyDescriptor> desc);
 
 extern JS_PUBLIC_API(bool)
-JS_GetProperty(JSContext *cx, JSObject *obj, const char *name, JS::MutableHandleValue vp);
+JS_GetProperty(JSContext *cx, JS::HandleObject obj, const char *name, JS::MutableHandleValue vp);
 
 extern JS_PUBLIC_API(bool)
-JS_GetPropertyById(JSContext *cx, JSObject *obj, jsid id, JS::MutableHandleValue vp);
+JS_GetPropertyById(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp);
 
 extern JS_PUBLIC_API(bool)
 JS_ForwardGetPropertyTo(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::HandleObject onBehalfOf,
                         JS::MutableHandleValue vp);
 
 extern JS_PUBLIC_API(bool)
 JS_SetProperty(JSContext *cx, JS::HandleObject obj, const char *name, JS::HandleValue v);
 
@@ -3077,27 +3077,27 @@ JS_HasUCProperty(JSContext *cx, JS::Hand
                  bool *vp);
 
 extern JS_PUBLIC_API(bool)
 JS_LookupUCProperty(JSContext *cx, JS::HandleObject obj,
                     const jschar *name, size_t namelen,
                     JS::MutableHandleValue vp);
 
 extern JS_PUBLIC_API(bool)
-JS_GetUCProperty(JSContext *cx, JSObject *obj,
+JS_GetUCProperty(JSContext *cx, JS::HandleObject obj,
                  const jschar *name, size_t namelen,
                  JS::MutableHandleValue vp);
 
 extern JS_PUBLIC_API(bool)
 JS_SetUCProperty(JSContext *cx, JS::HandleObject obj,
                  const jschar *name, size_t namelen,
                  JS::HandleValue v);
 
 extern JS_PUBLIC_API(bool)
-JS_DeleteUCProperty2(JSContext *cx, JSObject *obj, const jschar *name, size_t namelen,
+JS_DeleteUCProperty2(JSContext *cx, JS::HandleObject obj, const jschar *name, size_t namelen,
                      bool *succeeded);
 
 extern JS_PUBLIC_API(JSObject *)
 JS_NewArrayObject(JSContext *cx, int length, jsval *vector);
 
 extern JS_PUBLIC_API(bool)
 JS_IsArrayObject(JSContext *cx, JS::HandleValue value);
 
@@ -3119,17 +3119,17 @@ JS_AlreadyHasOwnElement(JSContext *cx, J
 
 extern JS_PUBLIC_API(bool)
 JS_HasElement(JSContext *cx, JS::HandleObject obj, uint32_t index, bool *foundp);
 
 extern JS_PUBLIC_API(bool)
 JS_LookupElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp);
 
 extern JS_PUBLIC_API(bool)
-JS_GetElement(JSContext *cx, JSObject *obj, uint32_t index, JS::MutableHandleValue vp);
+JS_GetElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::MutableHandleValue vp);
 
 extern JS_PUBLIC_API(bool)
 JS_ForwardGetElementTo(JSContext *cx, JSObject *obj, uint32_t index, JSObject *onBehalfOf,
                        JS::MutableHandleValue vp);
 
 extern JS_PUBLIC_API(bool)
 JS_SetElement(JSContext *cx, JS::HandleObject obj, uint32_t index, JS::HandleValue v);
 
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -451,33 +451,34 @@ mozJSComponentLoader::LoadModule(FileLoc
     }
 
     JSObject* cm_jsobj = cm_holder->GetJSObject();
     if (!cm_jsobj) {
         return nullptr;
     }
 
     nsCOMPtr<nsIXPConnectJSObjectHolder> file_holder;
-    rv = xpc->WrapNative(cx, entry->obj, file,
+    RootedObject entryObj(cx, entry->obj);
+    rv = xpc->WrapNative(cx, entryObj, file,
                          NS_GET_IID(nsIFile),
                          getter_AddRefs(file_holder));
 
     if (NS_FAILED(rv)) {
         return nullptr;
     }
 
     JSObject* file_jsobj = file_holder->GetJSObject();
     if (!file_jsobj) {
         return nullptr;
     }
 
     JSCLAutoErrorReporterSetter aers(cx, xpc::SystemErrorReporter);
 
     RootedValue NSGetFactory_val(cx);
-    if (!JS_GetProperty(cx, entry->obj, "NSGetFactory", &NSGetFactory_val) ||
+    if (!JS_GetProperty(cx, entryObj, "NSGetFactory", &NSGetFactory_val) ||
         JSVAL_IS_VOID(NSGetFactory_val)) {
         return nullptr;
     }
 
     if (JS_TypeOfValue(cx, NSGetFactory_val) != JSTYPE_FUNCTION) {
         nsAutoCString spec;
         uri->GetSpec(spec);
         JS_ReportError(cx, "%s has NSGetFactory property that is not a function",
@@ -503,17 +504,17 @@ mozJSComponentLoader::LoadModule(FileLoc
     }
 
     // Cache this module for later
     mModules.Put(spec, entry);
 
     // Set the location information for the new global, so that tools like
     // about:memory may use that information
     if (!mReuseLoaderGlobal) {
-        xpc::SetLocationForGlobal(entry->obj, spec);
+        xpc::SetLocationForGlobal(entryObj, spec);
     }
 
     // The hash owns the ModuleEntry now, forget about it
     return entry.forget();
 }
 
 nsresult
 mozJSComponentLoader::FindTargetObject(JSContext* aCx,
@@ -1260,17 +1261,18 @@ mozJSComponentLoader::ImportInto(const n
     MOZ_ASSERT(mod->obj, "Import table contains entry with no object");
     vp.set(mod->obj);
 
     if (targetObj) {
         JSCLContextHelper cxhelper(mContext);
         JSAutoCompartment ac(mContext, mod->obj);
 
         RootedValue symbols(mContext);
-        if (!JS_GetProperty(mContext, mod->obj,
+        RootedObject modObj(mContext, mod->obj);
+        if (!JS_GetProperty(mContext, modObj,
                             "EXPORTED_SYMBOLS", &symbols)) {
             return ReportOnCaller(cxhelper, ERROR_NOT_PRESENT,
                                   PromiseFlatCString(aLocation).get());
         }
 
         if (!JS_IsArrayObject(mContext, symbols)) {
             return ReportOnCaller(cxhelper, ERROR_NOT_AN_ARRAY,
                                   PromiseFlatCString(aLocation).get());
@@ -1295,17 +1297,18 @@ mozJSComponentLoader::ImportInto(const n
         for (uint32_t i = 0; i < symbolCount; ++i) {
             if (!JS_GetElement(mContext, symbolsObj, i, &value) ||
                 !value.isString() ||
                 !JS_ValueToId(mContext, value, &symbolId)) {
                 return ReportOnCaller(cxhelper, ERROR_ARRAY_ELEMENT,
                                       PromiseFlatCString(aLocation).get(), i);
             }
 
-            if (!JS_GetPropertyById(mContext, mod->obj, symbolId, &value)) {
+            RootedObject modObj(mContext, mod->obj);
+            if (!JS_GetPropertyById(mContext, modObj, symbolId, &value)) {
                 JSAutoByteString bytes(mContext, JSID_TO_STRING(symbolId));
                 if (!bytes)
                     return NS_ERROR_FAILURE;
                 return ReportOnCaller(cxhelper, ERROR_GETTING_SYMBOL,
                                       PromiseFlatCString(aLocation).get(),
                                       bytes.ptr());
             }
 
--- a/js/xpconnect/src/XPCWrappedJSClass.cpp
+++ b/js/xpconnect/src/XPCWrappedJSClass.cpp
@@ -183,17 +183,16 @@ nsXPCWrappedJSClass::CallQueryInterfaceO
                                                   JSObject* jsobjArg,
                                                   REFNSIID aIID)
 {
     RootedObject jsobj(cx, jsobjArg);
     JSObject* id;
     RootedValue retval(cx);
     RootedObject retObj(cx);
     bool success = false;
-    jsid funid;
     RootedValue fun(cx);
 
     // Don't call the actual function on a content object. We'll determine
     // whether or not a content object is capable of implementing the
     // interface (i.e. whether the interface is scriptable) and most content
     // objects don't have QI implementations anyway. Also see bug 503926.
     if (!xpc::AccessCheck::isChrome(js::GetObjectCompartment(jsobj))) {
         return nullptr;
@@ -203,17 +202,17 @@ nsXPCWrappedJSClass::CallQueryInterfaceO
     AutoScriptEvaluate scriptEval(cx);
 
     // XXX we should install an error reporter that will send reports to
     // the JS error console service.
     if (!scriptEval.StartEvaluating(jsobj))
         return nullptr;
 
     // check upfront for the existence of the function property
-    funid = mRuntime->GetStringID(XPCJSRuntime::IDX_QUERY_INTERFACE);
+    HandleId funid = mRuntime->GetStringID(XPCJSRuntime::IDX_QUERY_INTERFACE);
     if (!JS_GetPropertyById(cx, jsobj, funid, &fun) || JSVAL_IS_PRIMITIVE(fun))
         return nullptr;
 
     // Ensure that we are asking for a scriptable interface.
     // NB:  It's important for security that this check is here rather
     // than later, since it prevents untrusted objects from implementing
     // some interfaces in JS and aggregating a trusted object to
     // implement intentionally (for security) unscriptable interfaces.
@@ -290,18 +289,18 @@ nsXPCWrappedJSClass::CallQueryInterfaceO
 
     return success ? retObj.get() : nullptr;
 }
 
 /***************************************************************************/
 
 static bool
 GetNamedPropertyAsVariantRaw(XPCCallContext& ccx,
-                             JSObject* aJSObj,
-                             jsid aName,
+                             HandleObject aJSObj,
+                             HandleId aName,
                              nsIVariant** aResult,
                              nsresult* pErr)
 {
     nsXPTType type = nsXPTType((uint8_t)TD_INTERFACE_TYPE);
     RootedValue val(ccx);
 
     return JS_GetPropertyById(ccx, aJSObj, aName, &val) &&
            // Note that this always takes the T_INTERFACE path through
@@ -1355,21 +1354,25 @@ pre_call_clean_up:
 
         if (param.IsDipper())
             pv = (nsXPTCMiniVariant*) &nativeParams[i].val.p;
         else
             pv = (nsXPTCMiniVariant*) nativeParams[i].val.p;
 
         if (param.IsRetval())
             val = rval;
-        else if (JSVAL_IS_PRIMITIVE(argv[i]) ||
-                 !JS_GetPropertyById(cx, JSVAL_TO_OBJECT(argv[i]),
-                                     mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
-                                     &val))
+        else if (argv[i].isPrimitive())
             break;
+        else {
+            RootedObject obj(cx, &argv[i].toObject());
+            if (!JS_GetPropertyById(cx, obj,
+                                    mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
+                                    &val))
+                break;
+        }
 
         // setup allocator and/or iid
 
         if (type_tag == nsXPTType::T_INTERFACE) {
             if (NS_FAILED(GetInterfaceInfo()->
                           GetIIDForParamNoAlloc(methodIndex, &param,
                                                 &param_iid)))
                 break;
@@ -1400,20 +1403,23 @@ pre_call_clean_up:
                     false :
                     type.TagPart() == nsXPTType::T_PSTRING_SIZE_IS ||
                     type.TagPart() == nsXPTType::T_PWSTRING_SIZE_IS;
 
             pv = (nsXPTCMiniVariant*) nativeParams[i].val.p;
 
             if (param.IsRetval())
                 val = rval;
-            else if (!JS_GetPropertyById(cx, JSVAL_TO_OBJECT(argv[i]),
-                                         mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
-                                         &val))
-                break;
+            else {
+                RootedObject obj(cx, &argv[i].toObject());
+                if (!JS_GetPropertyById(cx, obj,
+                                        mRuntime->GetStringID(XPCJSRuntime::IDX_VALUE),
+                                        &val))
+                    break;
+            }
 
             // setup allocator and/or iid
 
             if (isArray) {
                 if (NS_FAILED(mInfo->GetTypeForParam(methodIndex, &param, 1,
                                                      &datum_type)))
                     break;
             } else
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -1849,28 +1849,28 @@ CallMethodHelper::GetOutParamSource(uint
 {
     const nsXPTParamInfo& paramInfo = mMethodInfo->GetParam(paramIndex);
 
     if ((paramInfo.IsOut() || paramInfo.IsDipper()) &&
         !paramInfo.IsRetval()) {
         MOZ_ASSERT(paramIndex < mArgc || paramInfo.IsOptional(),
                    "Expected either enough arguments or an optional argument");
         jsval arg = paramIndex < mArgc ? mArgv[paramIndex] : JSVAL_NULL;
-        if (paramIndex < mArgc &&
-            (JSVAL_IS_PRIMITIVE(arg) ||
-             !JS_GetPropertyById(mCallContext,
-                                 JSVAL_TO_OBJECT(arg),
-                                 mIdxValueId,
-                                 srcp))) {
-            // Explicitly passed in unusable value for out param.  Note
-            // that if i >= mArgc we already know that |arg| is JSVAL_NULL,
-            // and that's ok.
-            ThrowBadParam(NS_ERROR_XPC_NEED_OUT_OBJECT, paramIndex,
-                          mCallContext);
-            return false;
+        if (paramIndex < mArgc) {
+            RootedObject obj(mCallContext);
+            if (!arg.isPrimitive())
+                obj = &arg.toObject();
+            if (!obj || !JS_GetPropertyById(mCallContext, obj, mIdxValueId, srcp)) {
+                // Explicitly passed in unusable value for out param.  Note
+                // that if i >= mArgc we already know that |arg| is JSVAL_NULL,
+                // and that's ok.
+                ThrowBadParam(NS_ERROR_XPC_NEED_OUT_OBJECT, paramIndex,
+                              mCallContext);
+                return false;
+            }
         }
     }
 
     return true;
 }
 
 bool
 CallMethodHelper::GatherAndConvertResults()
--- a/toolkit/components/ctypes/ctypes.cpp
+++ b/toolkit/components/ctypes/ctypes.cpp
@@ -60,17 +60,17 @@ Module::~Module()
 
 #define XPC_MAP_CLASSNAME Module
 #define XPC_MAP_QUOTED_CLASSNAME "Module"
 #define XPC_MAP_WANT_CALL
 #define XPC_MAP_FLAGS nsIXPCScriptable::WANT_CALL
 #include "xpc_map_end.h"
 
 static bool
-SealObjectAndPrototype(JSContext* cx, JSObject* parent, const char* name)
+SealObjectAndPrototype(JSContext* cx, JS::Handle<JSObject *> parent, const char* name)
 {
   JS::Rooted<JS::Value> prop(cx);
   if (!JS_GetProperty(cx, parent, name, &prop))
     return false;
 
   if (prop.isUndefined()) {
     // Pretend we sealed the object.
     return true;
--- a/toolkit/components/perf/PerfMeasurement.cpp
+++ b/toolkit/components/perf/PerfMeasurement.cpp
@@ -35,17 +35,17 @@ Module::~Module()
 
 #define XPC_MAP_CLASSNAME Module
 #define XPC_MAP_QUOTED_CLASSNAME "Module"
 #define XPC_MAP_WANT_CALL
 #define XPC_MAP_FLAGS nsIXPCScriptable::WANT_CALL
 #include "xpc_map_end.h"
 
 static bool
-SealObjectAndPrototype(JSContext* cx, JSObject* parent, const char* name)
+SealObjectAndPrototype(JSContext* cx, JS::Handle<JSObject *> parent, const char* name)
 {
   JS::Rooted<JS::Value> prop(cx);
   if (!JS_GetProperty(cx, parent, name, &prop))
     return false;
 
   if (prop.isUndefined()) {
     // Pretend we sealed the object.
     return true;
--- a/toolkit/components/places/History.cpp
+++ b/toolkit/components/places/History.cpp
@@ -288,17 +288,17 @@ GetJSValueAsURI(JSContext* aCtx,
  * @param aObject
  *        The JSObject to get the URI from.
  * @param aProperty
  *        The name of the property to get the URI from.
  * @return the URI if it exists.
  */
 already_AddRefed<nsIURI>
 GetURIFromJSObject(JSContext* aCtx,
-                   JSObject* aObject,
+                   JS::Handle<JSObject *> aObject,
                    const char* aProperty)
 {
   JS::Rooted<JS::Value> uriVal(aCtx);
   bool rc = JS_GetProperty(aCtx, aObject, aProperty, &uriVal);
   NS_ENSURE_TRUE(rc, nullptr);
   return GetJSValueAsURI(aCtx, uriVal);
 }
 
@@ -345,17 +345,17 @@ GetJSValueAsString(JSContext* aCtx,
  *        The JSObject to get the string from.
  * @param aProperty
  *        The property to get the value from.
  * @param _string
  *        The string to populate with the value, or set it to void.
  */
 void
 GetStringFromJSObject(JSContext* aCtx,
-                      JSObject* aObject,
+                      JS::Handle<JSObject *> aObject,
                       const char* aProperty,
                       nsString& _string)
 {
   JS::Rooted<JS::Value> val(aCtx);
   bool rc = JS_GetProperty(aCtx, aObject, aProperty, &val);
   if (!rc) {
     _string.SetIsVoid(true);
     return;
@@ -375,17 +375,17 @@ GetStringFromJSObject(JSContext* aCtx,
  * @param aProperty
  *        The property to get the value from.
  * @param _int
  *        The integer to populate with the value on success.
  */
 template <typename IntType>
 nsresult
 GetIntFromJSObject(JSContext* aCtx,
-                   JSObject* aObject,
+                   JS::Handle<JSObject *> aObject,
                    const char* aProperty,
                    IntType* _int)
 {
   JS::Rooted<JS::Value> value(aCtx);
   bool rc = JS_GetProperty(aCtx, aObject, aProperty, &value);
   NS_ENSURE_TRUE(rc, NS_ERROR_UNEXPECTED);
   if (JSVAL_IS_VOID(value)) {
     return NS_ERROR_INVALID_ARG;