Bug 787856 - Convert js::GetObjectProto to support lazy protos (r=bhackett)
authorBill McCloskey <wmccloskey@mozilla.com>
Mon, 03 Sep 2012 16:42:10 -0700
changeset 108154 c372439f0aad42d3dd73306c59035f2450d2e1b7
parent 108153 a0853ae2ee0fc5e79847bdaf08be31451088eab8
child 108155 fd398d69d052954dc376c64f1e17dbbc05579037
push id23539
push userryanvm@gmail.com
push dateWed, 26 Sep 2012 22:55:55 +0000
treeherderautoland@ec079fd92224 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs787856
milestone18.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 787856 - Convert js::GetObjectProto to support lazy protos (r=bhackett)
dom/base/nsDOMClassInfo.cpp
dom/base/nsGlobalWindow.cpp
dom/bindings/BindingUtils.cpp
dom/bindings/Codegen.py
dom/bindings/DOMJSProxyHandler.cpp
js/ipc/ObjectWrapperParent.cpp
js/ipc/ObjectWrapperParent.h
js/src/jsfriendapi.h
js/xpconnect/src/XPCDebug.cpp
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/dombindings.cpp
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/wrappers/WrapperFactory.cpp
js/xpconnect/wrappers/XrayWrapper.cpp
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1900,24 +1900,24 @@ jsid nsDOMClassInfo::sOnload_id         
 jsid nsDOMClassInfo::sOnerror_id         = JSID_VOID;
 
 static const JSClass *sObjectClass = nullptr;
 
 /**
  * Set our JSClass pointer for the Object class
  */
 static void
-FindObjectClass(JSObject* aGlobalObject)
+FindObjectClass(JSContext* cx, JSObject* aGlobalObject)
 {
   NS_ASSERTION(!sObjectClass,
                "Double set of sObjectClass");
   JSObject *obj, *proto = aGlobalObject;
   do {
     obj = proto;
-    proto = js::GetObjectProto(obj);
+    js::GetObjectProto(cx, obj, &proto);
   } while (proto);
 
   sObjectClass = js::GetObjectJSClass(obj);
 }
 
 static void
 PrintWarningOnConsole(JSContext *cx, const char *stringBundleProperty)
 {
@@ -5121,17 +5121,17 @@ nsDOMClassInfo::PostCreatePrototype(JSCo
   if (!xpc::DOM_DefineQuickStubs(cx, proto, flags, count, mData->mInterfaces)) {
     JS_ClearPendingException(cx);
   }
 
   // This is called before any other location that requires
   // sObjectClass, so compute it here. We assume that nobody has had a
   // chance to monkey around with proto's prototype chain before this.
   if (!sObjectClass) {
-    FindObjectClass(proto);
+    FindObjectClass(cx, proto);
     NS_ASSERTION(sObjectClass && !strcmp(sObjectClass->name, "Object"),
                  "Incorrect object class!");
   }
 
   NS_ASSERTION(::JS_GetPrototype(proto) &&
                JS_GetClass(::JS_GetPrototype(proto)) == sObjectClass,
                "Hmm, somebody did something evil?");
 
@@ -7495,17 +7495,21 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
   // binding a name) a new undefined property that's not already
   // defined on our prototype chain. This way we can access this
   // expando w/o ever getting back into XPConnect.
   if (flags & JSRESOLVE_ASSIGNING) {
     JSObject *realObj;
     wrapper->GetJSObject(&realObj);
 
     if (obj == realObj) {
-      JSObject *proto = js::GetObjectProto(obj);
+      JSObject *proto;
+      if (!js::GetObjectProto(cx, obj, &proto)) {
+          *_retval = JS_FALSE;
+          return NS_OK;
+      }
       if (proto) {
         JSObject *pobj = NULL;
         jsval val;
 
         if (!::JS_LookupPropertyWithFlagsById(cx, proto, id, flags,
                                               &pobj, &val)) {
           *_retval = JS_FALSE;
 
@@ -8934,17 +8938,19 @@ nsHTMLDocumentSH::DocumentAllGetProperty
   // newResolve hook, so nothing to do for those properties here. And
   // we need to return early to prevent <div id="item"> from shadowing
   // document.all.item(), etc.
   if (sItem_id == id || sNamedItem_id == id) {
     return JS_TRUE;
   }
 
   while (js::GetObjectJSClass(obj) != &sHTMLDocumentAllClass) {
-    obj = js::GetObjectProto(obj);
+    if (!js::GetObjectProto(cx, obj, &obj)) {
+      return JS_FALSE;
+    }
 
     if (!obj) {
       NS_ERROR("The JS engine lies!");
 
       return JS_TRUE;
     }
   }
 
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -620,17 +620,21 @@ nsOuterWindowProxy::finalize(JSFreeOp *f
 
 nsOuterWindowProxy
 nsOuterWindowProxy::singleton;
 
 static JSObject*
 NewOuterWindowProxy(JSContext *cx, JSObject *parent)
 {
   JSAutoCompartment ac(cx, parent);
-  JSObject *obj = js::Wrapper::New(cx, parent, js::GetObjectProto(parent), parent,
+  JSObject *proto;
+  if (!js::GetObjectProto(cx, parent, &proto))
+    return nullptr;
+
+  JSObject *obj = js::Wrapper::New(cx, parent, proto, parent,
                                    &nsOuterWindowProxy::singleton);
   NS_ASSERTION(js::GetObjectClass(obj)->ext.innerObject, "bad class");
   return obj;
 }
 
 //*****************************************************************************
 //***    nsGlobalWindow: Object Management
 //*****************************************************************************
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -586,17 +586,20 @@ XrayEnumerateProperties(JS::AutoIdVector
 
   return true;
 }
 
 bool
 GetPropertyOnPrototype(JSContext* cx, JSObject* proxy, jsid id, bool* found,
                        JS::Value* vp)
 {
-  JSObject* proto = js::GetObjectProto(proxy);
+  JSObject* proto;
+  if (!js::GetObjectProto(cx, proxy, &proto)) {
+    return false;
+  }
   if (!proto) {
     *found = false;
     return true;
   }
 
   JSBool hasProp;
   if (!JS_HasPropertyById(cx, proto, id, &hasProp)) {
     return false;
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -5012,17 +5012,20 @@ if (expando) {
 """
 
         return """MOZ_ASSERT(!xpc::WrapperFactory::IsXrayWrapper(proxy),
              "Should not have a XrayWrapper here");
 
 """ + get + """
 // No need to worry about name getters here, so just check the proto.
 
-JSObject *proto = js::GetObjectProto(proxy);
+JSObject *proto;
+if (!js::GetObjectProto(cx, proxy, &proto)) {
+  return false;
+}
 if (proto) {
   JSBool isPresent;
   if (!JS_GetElementIfPresent(cx, proto, index, proxy, vp, &isPresent)) {
     return false;
   }
   *present = isPresent;
   return true;
 }
--- a/dom/bindings/DOMJSProxyHandler.cpp
+++ b/dom/bindings/DOMJSProxyHandler.cpp
@@ -92,17 +92,20 @@ DOMProxyHandler::getPropertyDescriptor(J
 {
   if (!getOwnPropertyDescriptor(cx, proxy, id, set, desc)) {
     return false;
   }
   if (desc->obj) {
     return true;
   }
 
-  JSObject* proto = js::GetObjectProto(proxy);
+  JSObject* proto;
+  if (!js::GetObjectProto(cx, proxy, &proto)) {
+    return false;
+  }
   if (!proto) {
     desc->obj = NULL;
     return true;
   }
 
   return JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, desc);
 }
 
@@ -146,17 +149,20 @@ DOMProxyHandler::delete_(JSContext* cx, 
 
   *bp = !!b;
   return true;
 }
 
 bool
 DOMProxyHandler::enumerate(JSContext* cx, JSObject* proxy, AutoIdVector& props)
 {
-  JSObject* proto = JS_GetPrototype(proxy);
+  JSObject* proto;
+  if (!JS_GetPrototype(cx, proxy, &proto)) {
+    return false;
+  }
   return getOwnPropertyNames(cx, proxy, props) &&
          (!proto || js::GetPropertyNames(cx, proto, 0, &props));
 }
 
 bool
 DOMProxyHandler::fix(JSContext* cx, JSObject* proxy, Value* vp)
 {
   vp->setUndefined();
@@ -172,17 +178,20 @@ DOMProxyHandler::has(JSContext* cx, JSOb
 
   if (*bp) {
     // We have the property ourselves; no need to worry about our prototype
     // chain.
     return true;
   }
 
   // OK, now we have to look at the proto
-  JSObject *proto = js::GetObjectProto(proxy);
+  JSObject *proto;
+  if (!js::GetObjectProto(cx, proxy, &proto)) {
+    return false;
+  }
   if (!proto) {
     return true;
   }
   JSBool protoHasProp;
   bool ok = JS_HasPropertyById(cx, proto, id, &protoHasProp);
   if (ok) {
     *bp = protoHasProp;
   }
--- a/js/ipc/ObjectWrapperParent.cpp
+++ b/js/ipc/ObjectWrapperParent.cpp
@@ -179,22 +179,23 @@ ObjectWrapperParent::GetJSObject(JSConte
             JS_SetPrivate(mObj, (void*)this);
             JS_SetReservedSlot(mObj, sFlagsSlot, JSVAL_ZERO);
         }
     }
     return mObj;
 }
 
 static ObjectWrapperParent*
-Unwrap(JSObject* obj)
+Unwrap(JSContext* cx, JSObject* obj)
 {
-    while (js::GetObjectClass(obj) != &ObjectWrapperParent::sCPOW_JSClass)
-        if (!(obj = js::GetObjectProto(obj)))
+    while (js::GetObjectClass(obj) != &ObjectWrapperParent::sCPOW_JSClass) {
+        if (!js::GetObjectProto(cx, obj, &obj) || !obj)
             return NULL;
-    
+    }
+
     ObjectWrapperParent* self =
         static_cast<ObjectWrapperParent*>(JS_GetPrivate(obj));
 
     NS_ASSERTION(!self || self->GetJSObjectOrNull() == obj,
                  "Wrapper and wrapped object disagree?");
     
     return self;
 }
@@ -213,17 +214,17 @@ ObjectWrapperParent::jsval_to_JSVariant(
         // fall through
     case JSTYPE_FUNCTION:
         // CPOWs can fool JS_TypeOfValue into returning JSTYPE_FUNCTION
         // because they have a call hook, but CPOWs are really objects, so
         // fall through to the JSTYPE_OBJECT case:
     case JSTYPE_OBJECT:
         {
             PObjectWrapperParent* powp;
-            if (!JSObject_to_PObjectWrapperParent(JSVAL_TO_OBJECT(from), &powp))
+            if (!JSObject_to_PObjectWrapperParent(cx, JSVAL_TO_OBJECT(from), &powp))
                 return with_error(cx, false, "Cannot pass parent-created object to child");
             *to = powp;
         }
         return true;
     case JSTYPE_STRING:
         {
             nsDependentJSString depStr;
             if (!depStr.init(cx, from))
@@ -277,23 +278,23 @@ ObjectWrapperParent::jsval_from_JSVarian
         return true;
     default:
         return false;
     }
 }
 
 /*static*/ bool
 ObjectWrapperParent::
-JSObject_to_PObjectWrapperParent(JSObject* from, PObjectWrapperParent** to)
+JSObject_to_PObjectWrapperParent(JSContext* cx, JSObject* from, PObjectWrapperParent** to)
 {
     if (!from) {
         *to = NULL;
         return true;
     }
-    ObjectWrapperParent* owp = Unwrap(from);
+    ObjectWrapperParent* owp = Unwrap(cx, from);
     if (!owp)
         return false;
     *to = owp;
     return true;
 }
 
 /*static*/ bool
 ObjectWrapperParent::
@@ -355,17 +356,17 @@ jsval_to_nsString(JSContext* cx, jsid fr
 
 /*static*/ JSBool
 ObjectWrapperParent::CPOW_AddProperty(JSContext *cx, JSHandleObject obj, JSHandleId id,
                                       JSMutableHandleValue vp)
 {
     CPOW_LOG(("Calling CPOW_AddProperty (%s)...",
               JSVAL_TO_CSTR(cx, id)));
 
-    ObjectWrapperParent* self = Unwrap(obj);
+    ObjectWrapperParent* self = Unwrap(cx, obj);
     if (!self)
         return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_AddProperty");
 
     if (AutoResolveFlag::IsSet(obj))
         return JS_TRUE;
 
     AutoCheckOperation aco(cx, self);
 
@@ -382,17 +383,17 @@ ObjectWrapperParent::CPOW_AddProperty(JS
 
 /*static*/ JSBool
 ObjectWrapperParent::CPOW_GetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id,
                                       JSMutableHandleValue vp)
 {
     CPOW_LOG(("Calling CPOW_GetProperty (%s)...",
               JSVAL_TO_CSTR(cx, id)));
 
-    ObjectWrapperParent* self = Unwrap(obj);
+    ObjectWrapperParent* self = Unwrap(cx, obj);
     if (!self)
         return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_GetProperty");
 
     AutoCheckOperation aco(cx, self);
 
     nsString in_id;
 
     if (!jsval_to_nsString(cx, id, &in_id))
@@ -409,17 +410,17 @@ ObjectWrapperParent::CPOW_GetProperty(JS
 
 /*static*/ JSBool
 ObjectWrapperParent::CPOW_SetProperty(JSContext *cx, JSHandleObject obj, JSHandleId id, 
                                       JSBool strict, JSMutableHandleValue vp)
 {
     CPOW_LOG(("Calling CPOW_SetProperty (%s)...",
               JSVAL_TO_CSTR(cx, id)));
 
-    ObjectWrapperParent* self = Unwrap(obj);
+    ObjectWrapperParent* self = Unwrap(cx, obj);
     if (!self)
         return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_SetProperty");
 
     AutoCheckOperation aco(cx, self);
 
     nsString in_id;
     JSVariant in_v;
 
@@ -438,17 +439,17 @@ ObjectWrapperParent::CPOW_SetProperty(JS
     
 /*static*/ JSBool
 ObjectWrapperParent::CPOW_DelProperty(JSContext *cx, JSHandleObject obj, JSHandleId id,
                                       JSMutableHandleValue vp)
 {
     CPOW_LOG(("Calling CPOW_DelProperty (%s)...",
               JSVAL_TO_CSTR(cx, id)));
 
-    ObjectWrapperParent* self = Unwrap(obj);
+    ObjectWrapperParent* self = Unwrap(cx, obj);
     if (!self)
         return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_DelProperty");
 
     AutoCheckOperation aco(cx, self);
 
     nsString in_id;
 
     if (!jsval_to_nsString(cx, id, &in_id))
@@ -519,17 +520,17 @@ ObjectWrapperParent::NewEnumerateDestroy
 
 /*static*/ JSBool
 ObjectWrapperParent::CPOW_NewEnumerate(JSContext *cx, JSHandleObject obj,
                                        JSIterateOp enum_op, jsval *statep,
                                        jsid *idp)
 {
     CPOW_LOG(("Calling CPOW_NewEnumerate..."));
 
-    ObjectWrapperParent* self = Unwrap(obj);
+    ObjectWrapperParent* self = Unwrap(cx, obj);
     if (!self)
         return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_NewEnumerate");
 
     switch (enum_op) {
     case JSENUMERATE_INIT:
     case JSENUMERATE_INIT_ALL:
         self->Manager()->RequestRunToCompletion();
         return self->NewEnumerateInit(cx, statep, idp);
@@ -545,17 +546,17 @@ ObjectWrapperParent::CPOW_NewEnumerate(J
 
 /*static*/ JSBool
 ObjectWrapperParent::CPOW_NewResolve(JSContext *cx, JSHandleObject obj, JSHandleId id,
                                      unsigned flags, JSMutableHandleObject objp)
 {
     CPOW_LOG(("Calling CPOW_NewResolve (%s)...",
               JSVAL_TO_CSTR(cx, id)));
 
-    ObjectWrapperParent* self = Unwrap(obj);
+    ObjectWrapperParent* self = Unwrap(cx, obj);
     if (!self)
         return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_NewResolve");
 
     AutoCheckOperation aco(cx, self);
 
     nsString in_id;
 
     if (!jsval_to_nsString(cx, id, &in_id))
@@ -581,54 +582,56 @@ ObjectWrapperParent::CPOW_NewResolve(JSC
 
 /*static*/ JSBool
 ObjectWrapperParent::CPOW_Convert(JSContext *cx, JSHandleObject obj, JSType type,
                                   JSMutableHandleValue vp)
 {
     CPOW_LOG(("Calling CPOW_Convert (to %s)...",
               JS_GetTypeName(cx, type)));
 
-    ObjectWrapperParent* self = Unwrap(obj);
+    ObjectWrapperParent* self = Unwrap(cx, obj);
     if (!self)
         return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_Convert");
 
     vp.set(OBJECT_TO_JSVAL(obj));
 
     return JS_TRUE;
 }
 
 /*static*/ void
 ObjectWrapperParent::CPOW_Finalize(js::FreeOp* fop, JSObject* obj)
 {
     CPOW_LOG(("Calling CPOW_Finalize..."));
-    
-    ObjectWrapperParent* self = Unwrap(obj);
+
+    MOZ_ASSERT(js::GetObjectClass(obj) == &ObjectWrapperParent::sCPOW_JSClass);
+    ObjectWrapperParent* self =
+        static_cast<ObjectWrapperParent*>(JS_GetPrivate(obj));
     if (self) {
         self->mObj = NULL;
         unused << ObjectWrapperParent::Send__delete__(self);
     }
 }
 
 /*static*/ JSBool
 ObjectWrapperParent::CPOW_Call(JSContext* cx, unsigned argc, jsval* vp)
 {
     CPOW_LOG(("Calling CPOW_Call..."));
 
     JSObject* thisobj = JS_THIS_OBJECT(cx, vp);
     if (!thisobj)
         return JS_FALSE;
 
     ObjectWrapperParent* function =
-        Unwrap(JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
+        Unwrap(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
     if (!function)
         return with_error(cx, JS_FALSE, "Could not unwrap CPOW function");
 
     AutoCheckOperation aco(cx, function);
 
-    ObjectWrapperParent* receiver = Unwrap(thisobj);
+    ObjectWrapperParent* receiver = Unwrap(cx, thisobj);
     if (!receiver) {
         // Substitute child global for parent global object.
         // TODO First make sure we're really replacing the global object?
         ContextWrapperParent* manager =
             static_cast<ContextWrapperParent*>(function->Manager());
         receiver = manager->GetGlobalObjectWrapper();
     }
 
@@ -647,17 +650,17 @@ ObjectWrapperParent::CPOW_Call(JSContext
             jsval_from_JSVariant(cx, out_rval, vp));
 }
 
 /*static*/ JSBool
 ObjectWrapperParent::CPOW_Construct(JSContext* cx, unsigned argc, jsval* vp)
 {
     CPOW_LOG(("Calling CPOW_Construct..."));
     
-    ObjectWrapperParent* constructor = Unwrap(JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
+    ObjectWrapperParent* constructor = Unwrap(cx, JSVAL_TO_OBJECT(JS_CALLEE(cx, vp)));
     if (!constructor)
         return with_error(cx, JS_FALSE, "Could not unwrap CPOW constructor function");
 
     AutoCheckOperation aco(cx, constructor);
 
     InfallibleTArray<JSVariant> in_argv(argc);
     jsval* argv = JS_ARGV(cx, vp);
     for (unsigned i = 0; i < argc; i++)
@@ -675,17 +678,17 @@ ObjectWrapperParent::CPOW_Construct(JSCo
 /*static*/ JSBool
 ObjectWrapperParent::CPOW_HasInstance(JSContext *cx, JSHandleObject obj, JSMutableHandleValue v,
                                       JSBool *bp)
 {
     CPOW_LOG(("Calling CPOW_HasInstance..."));
 
     *bp = JS_FALSE;
 
-    ObjectWrapperParent* self = Unwrap(obj);
+    ObjectWrapperParent* self = Unwrap(cx, obj);
     if (!self)
         return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_HasInstance");
 
     AutoCheckOperation aco(cx, self);
 
     JSVariant in_v;
 
     if (!jsval_to_JSVariant(cx, v, &in_v))
@@ -700,23 +703,23 @@ ObjectWrapperParent::CPOW_HasInstance(JS
 /*static*/ JSBool
 ObjectWrapperParent::CPOW_Equality(JSContext *cx, JSHandleObject obj, JSHandleValue v,
                                    JSBool *bp)
 {
     CPOW_LOG(("Calling CPOW_Equality..."));
 
     *bp = JS_FALSE;
     
-    ObjectWrapperParent* self = Unwrap(obj);
+    ObjectWrapperParent* self = Unwrap(cx, obj);
     if (!self)
         return with_error(cx, JS_FALSE, "Unwrapping failed in CPOW_Equality");
 
     if (JSVAL_IS_PRIMITIVE(v))
         return JS_TRUE;
 
-    ObjectWrapperParent* other = Unwrap(JSVAL_TO_OBJECT(v));
+    ObjectWrapperParent* other = Unwrap(cx, JSVAL_TO_OBJECT(v));
     if (!other)
         return JS_TRUE;
 
     *bp = (self == other);
     
     return JS_TRUE;
 }
--- a/js/ipc/ObjectWrapperParent.h
+++ b/js/ipc/ObjectWrapperParent.h
@@ -99,17 +99,17 @@ private:
 
     static JSBool
     CPOW_Equality(JSContext *cx, JSHandleObject obj, JSHandleValue v, JSBool *bp);
 
     static bool jsval_to_JSVariant(JSContext* cx, jsval from, JSVariant* to);
     static bool jsval_from_JSVariant(JSContext* cx, const JSVariant& from,
                                      jsval* to);
     static bool
-    JSObject_to_PObjectWrapperParent(JSObject* from, PObjectWrapperParent** to);
+    JSObject_to_PObjectWrapperParent(JSContext* cx, JSObject* from, PObjectWrapperParent** to);
     static bool
     JSObject_from_PObjectWrapperParent(JSContext* cx,
                                        const PObjectWrapperParent* from,
                                        JSMutableHandleObject to);
     static bool
     jsval_from_PObjectWrapperParent(JSContext* cx,
                                     const PObjectWrapperParent* from,
                                     jsval* to);
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -392,21 +392,30 @@ InitClassWithReserved(JSContext *cx, JSO
                       JSPropertySpec *static_ps, JSFunctionSpec *static_fs);
 
 JS_FRIEND_API(const Value &)
 GetFunctionNativeReserved(RawObject fun, size_t which);
 
 JS_FRIEND_API(void)
 SetFunctionNativeReserved(RawObject fun, size_t which, const Value &val);
 
-inline JSObject *
-GetObjectProto(RawObject obj)
+inline bool
+GetObjectProto(JSContext *cx, JSObject *obj, JSObject **proto)
 {
-    /* FIXME */
-    return reinterpret_cast<const shadow::Object*>(obj)->type->proto;
+    js::Class *clasp = GetObjectClass(obj);
+    if (clasp == &js::ObjectProxyClass ||
+        clasp == &js::OuterWindowProxyClass ||
+        clasp == &js::FunctionProxyClass)
+    {
+        /* FIXME */
+        *proto = reinterpret_cast<const shadow::Object*>(obj)->type->proto;
+    } else {
+        *proto = reinterpret_cast<const shadow::Object*>(obj)->type->proto;
+    }
+    return true;
 }
 
 inline void *
 GetObjectPrivate(RawObject obj)
 {
     const shadow::Object *nobj = reinterpret_cast<const shadow::Object*>(obj);
     void **addr = reinterpret_cast<void**>(&nobj->fixedSlots()[nobj->numFixedSlots()]);
     return *addr;
--- a/js/xpconnect/src/XPCDebug.cpp
+++ b/js/xpconnect/src/XPCDebug.cpp
@@ -163,78 +163,16 @@ private:
     JSObject* array[max_count];
     int member_count;
 };
 
 
 static const int tab_width = 2;
 #define INDENT(_d) (_d)*tab_width, " "
 
-static void PrintObjectBasics(JSObject* obj)
-{
-    if (JS_IsNative(obj))
-        DebugDump("%p 'native' <%s>",
-                  (void *)obj, js::GetObjectClass(obj)->name);
-    else
-        DebugDump("%p 'host'", (void *)obj);
-}
-
-static void PrintObject(JSObject* obj, int depth, ObjectPile* pile)
-{
-    PrintObjectBasics(obj);
-
-    switch (pile->Visit(obj)) {
-    case ObjectPile::primary:
-        DebugDump("%s", "\n");
-        break;
-    case ObjectPile::seen:
-        DebugDump("%s", " (SEE ABOVE)\n");
-        return;
-    case ObjectPile::overflow:
-        DebugDump("%s", " (TOO MANY OBJECTS)\n");
-        return;
-    }
-
-    if (!JS_IsNative(obj))
-        return;
-
-    JSObject* parent = js::GetObjectParent(obj);
-    JSObject* proto  = js::GetObjectProto(obj);
-
-    DebugDump("%*sparent: ", INDENT(depth+1));
-    if (parent)
-        PrintObject(parent, depth+1, pile);
-    else
-        DebugDump("%s", "null\n");
-    DebugDump("%*sproto: ", INDENT(depth+1));
-    if (proto)
-        PrintObject(proto, depth+1, pile);
-    else
-        DebugDump("%s", "null\n");
-}
-
-JSBool
-xpc_DumpJSObject(JSObject* obj)
-{
-    ObjectPile pile;
-
-    DebugDump("%s", "Debugging reminders...\n");
-    DebugDump("%s", "  class:  (JSClass*)(obj->fslots[2]-1)\n");
-    DebugDump("%s", "  parent: (JSObject*)(obj->fslots[1])\n");
-    DebugDump("%s", "  proto:  (JSObject*)(obj->fslots[0])\n");
-    DebugDump("%s", "\n");
-
-    if (obj)
-        PrintObject(obj, 0, &pile);
-    else
-        DebugDump("%s", "xpc_DumpJSObject passed null!\n");
-
-    return true;
-}
-
 #ifdef DEBUG
 void
 xpc_PrintAllReferencesTo(void *p)
 {
     /* p must be a JS object */
     XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
     JS_DumpHeap(rt->GetJSRuntime(), stdout, nullptr, JSTRACE_OBJECT, p, 0x7fffffff, nullptr);
 }
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -1830,66 +1830,71 @@ XPCWrappedNative::GetWrappedNativeOfJSOb
             goto return_tearoff;
         } else {
             NS_ERROR("function object has parent of unknown class!");
             return nullptr;
         }
     }
 
   restart:
-    for (cur = obj; cur; cur = js::GetObjectProto(cur)) {
+    for (cur = obj; cur; ) {
         // this is on two lines to make the compiler happy given the goto.
         js::Class* clazz;
         clazz = js::GetObjectClass(cur);
 
         if (IS_WRAPPER_CLASS(clazz)) {
 return_wrapper:
             JSBool isWN = IS_WN_WRAPPER_OBJECT(cur);
             XPCWrappedNative* wrapper =
                 isWN ? (XPCWrappedNative*) js::GetObjectPrivate(cur) : nullptr;
             if (proto) {
                 XPCWrappedNativeProto* wrapper_proto =
                     isWN ? wrapper->GetProto() : GetSlimWrapperProto(cur);
                 if (proto != wrapper_proto &&
                     (!protoClassInfo || !wrapper_proto ||
                      protoClassInfo != wrapper_proto->GetClassInfo()))
-                    continue;
+                    goto next;
             }
             if (pobj2)
                 *pobj2 = isWN ? nullptr : cur;
             return wrapper;
         }
 
         if (IS_TEAROFF_CLASS(clazz)) {
 return_tearoff:
             XPCWrappedNative* wrapper =
                 (XPCWrappedNative*) js::GetObjectPrivate(js::GetObjectParent(cur));
             if (proto && proto != wrapper->GetProto() &&
                 (proto->GetScope() != wrapper->GetScope() ||
                  !protoClassInfo || !wrapper->GetProto() ||
                  protoClassInfo != wrapper->GetProto()->GetClassInfo()))
-                continue;
+                goto next;
             if (pobj2)
                 *pobj2 = nullptr;
             XPCWrappedNativeTearOff* to = (XPCWrappedNativeTearOff*) js::GetObjectPrivate(cur);
             if (!to)
                 return nullptr;
             if (pTearOff)
                 *pTearOff = to;
             return wrapper;
         }
 
         // Unwrap any wrapper wrappers.
-        JSObject *unsafeObj = cx
-                              ? XPCWrapper::Unwrap(cx, cur, /* stopAtOuter = */ false)
-                              : js::UnwrapObject(cur, /* stopAtOuter = */ false);
+        JSObject *unsafeObj;
+        unsafeObj = cx
+                  ? XPCWrapper::Unwrap(cx, cur, /* stopAtOuter = */ false)
+                  : js::UnwrapObject(cur, /* stopAtOuter = */ false);
         if (unsafeObj) {
             obj = unsafeObj;
             goto restart;
         }
+
+      next:
+        if (!js::GetObjectProto(cx, cur, &cur))
+            return nullptr;
     }
 
     if (pobj2)
         *pobj2 = nullptr;
     return nullptr;
 }
 
 JSBool
--- a/js/xpconnect/src/dombindings.cpp
+++ b/js/xpconnect/src/dombindings.cpp
@@ -557,17 +557,19 @@ ListBase<LC>::getPropertyDescriptor(JSCo
                                     JSPropertyDescriptor *desc)
 {
     if (!getOwnPropertyDescriptor(cx, proxy, id, set, desc))
         return false;
     if (desc->obj)
         return true;
     if (xpc::WrapperFactory::IsXrayWrapper(proxy))
         return resolveNativeName(cx, proxy, id, desc);
-    JSObject *proto = js::GetObjectProto(proxy);
+    JSObject *proto;
+    if (!js::GetObjectProto(cx, proxy, &proto))
+        return false;
     if (!proto) {
         desc->obj = NULL;
         return true;
     }
     return JS_GetPropertyDescriptorById(cx, proto, id, JSRESOLVE_QUALIFIED, desc);
 }
 
 JSClass ExpandoClass = {
@@ -739,17 +741,19 @@ ListBase<LC>::has(JSContext *cx, JSObjec
     if (!hasOwn(cx, proxy, id, bp))
         return false;
     // We have the property ourselves; no need to worry about our
     // prototype chain.
     if (*bp)
         return true;
 
     // OK, now we have to look at the proto
-    JSObject *proto = js::GetObjectProto(proxy);
+    JSObject *proto;
+    if (!js::GetObjectProto(cx, proxy, &proto))
+        return false;
     if (!proto)
         return true;
 
     JSBool protoHasProp;
     bool ok = JS_HasPropertyById(cx, proto, id, &protoHasProp);
     if (ok)
         *bp = protoHasProp;
     return ok;
@@ -792,17 +796,19 @@ ListBase<LC>::resolveNativeName(JSContex
     return Base::resolveNativeName(cx, proxy, id, desc);
 }
 
 template<class LC>
 bool
 ListBase<LC>::getPropertyOnPrototype(JSContext *cx, JSObject *proxy, jsid id, bool *found,
                                      JS::Value *vp)
 {
-    JSObject *proto = js::GetObjectProto(proxy);
+    JSObject *proto;
+    if (!js::GetObjectProto(cx, proxy, &proto))
+        return false;
     if (!proto)
         return true;
 
     JSBool hasProp;
     if (!JS_HasPropertyById(cx, proto, id, &hasProp))
         return false;
 
     *found = hasProp;
@@ -913,17 +919,19 @@ ListBase<LC>::getElementIfPresent(JSCont
                 *present = true;
                 return true;
             }
         }
     }
 
     // No need to worry about name getters here, so just check the proto.
 
-    JSObject *proto = js::GetObjectProto(proxy);
+    JSObject *proto;
+    if (!js::GetObjectProto(cx, proxy, &proto))
+        return false;
     if (proto) {
         JSBool isPresent;
         if (!JS_GetElementIfPresent(cx, proto, index, proxy, vp, &isPresent))
             return false;
         *present = isPresent;
         return true;
     }
 
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -2924,50 +2924,16 @@ JS_EXPORT_API(void) DumpJSEval(uint32_t 
     nsresult rv;
     nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
     if (NS_SUCCEEDED(rv) && xpc)
         xpc->DebugDumpEvalInJSStackFrame(frameno, text);
     else
         printf("failed to get XPConnect service!\n");
 }
 
-JS_EXPORT_API(void) DumpJSObject(JSObject* obj)
-{
-    xpc_DumpJSObject(obj);
-}
-
-JS_EXPORT_API(void) DumpJSValue(JS::Value val)
-{
-    printf("Dumping 0x%llu.\n", (long long) val.asRawBits());
-    if (val.isNull()) {
-        printf("Value is null\n");
-    } else if (val.isObject()) {
-        printf("Value is an object\n");
-        DumpJSObject(&val.toObject());
-    } else if (val.isNumber()) {
-        printf("Value is a number: ");
-        if (val.isInt32())
-          printf("Integer %i\n", val.toInt32());
-        else if (val.isDouble())
-          printf("Floating-point value %f\n", val.toDouble());
-    } else if (val.isString()) {
-        printf("Value is a string: ");
-        putc('<', stdout);
-        JS_FileEscapedString(stdout, val.toString(), 0);
-        fputs(">\n", stdout);
-    } else if (val.isBoolean()) {
-        printf("Value is boolean: ");
-        printf(val.isTrue() ? "true" : "false");
-    } else if (val.isUndefined()) {
-        printf("Value is undefined\n");
-    } else {
-        printf("No idea what this value is.\n");
-    }
-}
-
 JS_EXPORT_API(void) DumpCompleteHeap()
 {
     nsCOMPtr<nsICycleCollectorListener> listener =
       do_CreateInstance("@mozilla.org/cycle-collector-logger;1");
     if (!listener) {
       NS_WARNING("Failed to create CC logger");
       return;
     }
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -72,17 +72,19 @@ JSObject *
 WrapperFactory::CreateXrayWaiver(JSContext *cx, JSObject *obj)
 {
     // The caller is required to have already done a lookup.
     // NB: This implictly performs the assertions of GetXrayWaiver.
     MOZ_ASSERT(!GetXrayWaiver(obj));
     CompartmentPrivate *priv = GetCompartmentPrivate(obj);
 
     // Get a waiver for the proto.
-    JSObject *proto = js::GetObjectProto(obj);
+    JSObject *proto;
+    if (!js::GetObjectProto(cx, obj, &proto))
+        return nullptr;
     if (proto && !(proto = WaiveXray(cx, proto)))
         return nullptr;
 
     // Create the waiver.
     JSAutoCompartment ac(cx, obj);
     if (!JS_WrapObject(cx, &proto))
         return nullptr;
     JSObject *waiver = Wrapper::New(cx, obj, proto,
@@ -523,17 +525,20 @@ WrapperFactory::IsLocationObject(JSObjec
 }
 
 JSObject *
 WrapperFactory::WrapLocationObject(JSContext *cx, JSObject *obj)
 {
     JSObject *xrayHolder = XrayUtils::createHolder(cx, obj, js::GetObjectParent(obj));
     if (!xrayHolder)
         return nullptr;
-    JSObject *wrapperObj = Wrapper::New(cx, obj, js::GetObjectProto(obj), js::GetObjectParent(obj),
+    JSObject *proto;
+    if (!js::GetObjectProto(cx, obj, &proto))
+        return nullptr;
+    JSObject *wrapperObj = Wrapper::New(cx, obj, proto, js::GetObjectParent(obj),
                                         &LW::singleton);
     if (!wrapperObj)
         return nullptr;
     js::SetProxyExtra(wrapperObj, 0, js::ObjectValue(*xrayHolder));
     return wrapperObj;
 }
 
 // Call WaiveXrayAndWrap when you have a JS object that you don't want to be
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -485,26 +485,27 @@ GetWrappedNativeFromHolder(JSObject *hol
 
 static JSObject *
 GetWrappedNativeObjectFromHolder(JSObject *holder)
 {
     return GetWrappedNativeFromHolder(holder)->GetFlatJSObject();
 }
 
 static inline JSObject *
-FindWrapper(JSObject *wrapper)
+FindWrapper(JSContext *cx, JSObject *wrapper)
 {
     while (!js::IsWrapper(wrapper) ||
            !(Wrapper::wrapperHandler(wrapper)->flags() &
              WrapperFactory::IS_XRAY_WRAPPER_FLAG)) {
         if (js::IsWrapper(wrapper) &&
             js::GetProxyHandler(wrapper) == &sandboxProxyHandler) {
             wrapper = SandboxProxyHandler::wrappedObject(wrapper);
         } else {
-            wrapper = js::GetObjectProto(wrapper);
+            if (!js::GetObjectProto(cx, wrapper, &wrapper))
+                return nullptr;
         }
         // NB: we must eventually hit our wrapper.
     }
 
     return wrapper;
 }
 
 JSObject*
@@ -521,17 +522,19 @@ XPCWrappedNativeXrayTraits::isResolving(
 }
 
 // Some DOM objects have shared properties that don't have an explicit
 // getter/setter and rely on the class getter/setter. We install a
 // class getter/setter on the holder object to trigger them.
 JSBool
 holder_get(JSContext *cx, JSHandleObject wrapper_, JSHandleId id, JSMutableHandleValue vp)
 {
-    JSObject *wrapper = FindWrapper(wrapper_);
+    JSObject *wrapper = FindWrapper(cx, wrapper_);
+    if (!wrapper)
+        return false;
 
     JSObject *holder = GetHolder(wrapper);
 
     XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder);
     if (NATIVE_HAS_FLAG(wn, WantGetProperty)) {
         JSAutoCompartment ac(cx, holder);
         bool retval = true;
         nsresult rv = wn->GetScriptableCallback()->GetProperty(wn, cx, wrapper,
@@ -543,17 +546,19 @@ holder_get(JSContext *cx, JSHandleObject
         }
     }
     return true;
 }
 
 JSBool
 holder_set(JSContext *cx, JSHandleObject wrapper_, JSHandleId id, JSBool strict, JSMutableHandleValue vp)
 {
-    JSObject *wrapper = FindWrapper(wrapper_);
+    JSObject *wrapper = FindWrapper(cx, wrapper_);
+    if (!wrapper)
+        return false;
 
     JSObject *holder = GetHolder(wrapper);
     if (XPCWrappedNativeXrayTraits::isResolving(cx, holder, id)) {
         return true;
     }
 
     XPCWrappedNative *wn = GetWrappedNativeFromHolder(holder);
     if (NATIVE_HAS_FLAG(wn, WantSetProperty)) {