Back out bug 1131802 (changesets 80e90f586329 and 35c268f162db) and patch 2 from bug 1131805 (changeset 4139522bf814) on a CLOSED TREE for assertion failures.
authorL. David Baron <dbaron@dbaron.org>
Fri, 06 Mar 2015 15:14:52 -0800
changeset 232339 dc86a4e16519d1cf511dedbd1d043a49149a8ac8
parent 232338 5921ef66656c06fa72fdda88f6c49c6ba4dbd301
child 232340 39488bb38d8da22a1aed3888ffb4a1d9a1328add
push id56519
push userdbaron@mozilla.com
push dateFri, 06 Mar 2015 23:15:07 +0000
treeherdermozilla-inbound@dc86a4e16519 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1131802, 1131805
milestone39.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
Back out bug 1131802 (changesets 80e90f586329 and 35c268f162db) and patch 2 from bug 1131805 (changeset 4139522bf814) on a CLOSED TREE for assertion failures. Assertion failure: (ptrBits & 1) == 0, at ../../dist/include/js/Value.h :871 called from XrayCreateFunction
dom/bindings/BindingUtils.cpp
js/src/jsapi-tests/selfTest.cpp
js/src/jsapi-tests/testTypedArrays.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jsfriendapi.cpp
js/src/jsfriendapi.h
js/src/shell/js.cpp
js/xpconnect/wrappers/XrayWrapper.cpp
js/xpconnect/wrappers/XrayWrapper.h
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -976,38 +976,16 @@ GetNativePropertyHooks(JSContext *cx, JS
 
   MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(obj)));
   const DOMIfaceAndProtoJSClass* ifaceAndProtoJSClass =
     DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj));
   type = ifaceAndProtoJSClass->mType;
   return ifaceAndProtoJSClass->mNativeHooks;
 }
 
-static JSObject*
-XrayCreateFunction(JSContext* cx, JS::Handle<JSObject*> wrapper,
-                   JSNativeWrapper native, unsigned nargs, JS::Handle<jsid> id)
-{
-  JSFunction* fun = js::NewFunctionByIdWithReserved(cx, native.op, nargs, 0,
-                                                    /* parent = */nullptr, id);
-  if (!fun) {
-    return nullptr;
-  }
-
-  SET_JITINFO(fun, native.info);
-  JSObject* obj = JS_GetFunctionObject(fun);
-  js::SetFunctionNativeReserved(obj, XRAY_DOM_FUNCTION_PARENT_WRAPPER_SLOT,
-                                JS::ObjectValue(*wrapper));
-#ifdef DEBUG
-  js::SetFunctionNativeReserved(obj, XRAY_DOM_FUNCTION_NATIVE_SLOT_FOR_ASSERT,
-                                JS::PrivateValue(JS_FUNC_TO_DATA_PTR(void *,
-                                                                     native.op)));
-#endif
-  return obj;
-}
-
 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, JS::MutableHandle<JSPropertyDescriptor> desc,
                      bool& cacheOnHolder)
 {
   for (; attributes->specs; ++attributes) {
@@ -1020,28 +998,33 @@ XrayResolveAttribute(JSContext* cx, JS::
           cacheOnHolder = true;
 
           const JSPropertySpec& attrSpec = attributeSpecs[i];
           // Because of centralization, we need to make sure we fault in the
           // JitInfos as well. At present, until the JSAPI changes, the easiest
           // way to do this is wrap them up as functions ourselves.
           desc.setAttributes(attrSpec.flags);
           // They all have getters, so we can just make it.
-          JS::Rooted<JSObject*> funobj(cx,
-            XrayCreateFunction(cx, wrapper, attrSpec.getter.native, 0, id));
-          if (!funobj)
+          JS::Rooted<JSFunction*> fun(cx,
+                                      JS_NewFunctionById(cx, attrSpec.getter.native.op,
+                                                         0, 0, wrapper, id));
+          if (!fun)
             return false;
+          SET_JITINFO(fun, attrSpec.getter.native.info);
+          JSObject *funobj = JS_GetFunctionObject(fun);
           desc.setGetterObject(funobj);
           desc.attributesRef() |= JSPROP_GETTER;
           if (attrSpec.setter.native.op) {
             // We have a setter! Make it.
-            funobj =
-              XrayCreateFunction(cx, wrapper, attrSpec.setter.native, 1, id);
-            if (!funobj)
+            fun = JS_NewFunctionById(cx, attrSpec.setter.native.op, 1, 0,
+                                     wrapper, id);
+            if (!fun)
               return false;
+            SET_JITINFO(fun, attrSpec.setter.native.info);
+            funobj = JS_GetFunctionObject(fun);
             desc.setSetterObject(funobj);
             desc.attributesRef() |= JSPROP_SETTER;
           } else {
             desc.setSetter(nullptr);
           }
           desc.object().set(wrapper);
           return true;
         }
@@ -1066,34 +1049,32 @@ XrayResolveMethod(JSContext* cx, JS::Han
       // Set i to be the index into our full list of ids/specs that we're
       // looking at now.
       size_t i = method->specs - methodSpecs;
       for ( ; methodIds[i] != JSID_VOID; ++i) {
         if (id == methodIds[i]) {
           cacheOnHolder = true;
 
           const JSFunctionSpec& methodSpec = methodSpecs[i];
-          JSObject *funobj;
+          JSFunction *fun;
           if (methodSpec.selfHostedName) {
-            JSFunction* fun =
-              JS::GetSelfHostedFunction(cx, methodSpec.selfHostedName, id,
-                                        methodSpec.nargs);
+            fun = JS::GetSelfHostedFunction(cx, methodSpec.selfHostedName, id, methodSpec.nargs);
             if (!fun) {
               return false;
             }
             MOZ_ASSERT(!methodSpec.call.op, "Bad FunctionSpec declaration: non-null native");
             MOZ_ASSERT(!methodSpec.call.info, "Bad FunctionSpec declaration: non-null jitinfo");
-            funobj = JS_GetFunctionObject(fun);
           } else {
-            funobj = XrayCreateFunction(cx, wrapper, methodSpec.call,
-                                        methodSpec.nargs, id);
-            if (!funobj) {
+            fun = JS_NewFunctionById(cx, methodSpec.call.op, methodSpec.nargs, 0, wrapper, id);
+            if (!fun) {
               return false;
             }
+            SET_JITINFO(fun, methodSpec.call.info);
           }
+          JSObject *funobj = JS_GetFunctionObject(fun);
           desc.value().setObject(*funobj);
           desc.setAttributes(methodSpec.flags);
           desc.object().set(wrapper);
           desc.setSetter(nullptr);
           desc.setGetter(nullptr);
           return true;
         }
       }
--- a/js/src/jsapi-tests/selfTest.cpp
+++ b/js/src/jsapi-tests/selfTest.cpp
@@ -13,8 +13,15 @@ BEGIN_TEST(selfTest_NaNsAreSame)
     EVAL("0/0", &v1);  // NaN
     CHECK_SAME(v1, v1);
 
     EVAL("Math.sin('no')", &v2);  // also NaN
     CHECK_SAME(v1, v2);
     return true;
 }
 END_TEST(selfTest_NaNsAreSame)
+
+BEGIN_TEST(selfTest_globalHasNoParent)
+{
+    CHECK(JS_GetParent(global) == nullptr);
+    return true;
+}
+END_TEST(selfTest_globalHasNoParent)
--- a/js/src/jsapi-tests/testTypedArrays.cpp
+++ b/js/src/jsapi-tests/testTypedArrays.cpp
@@ -28,16 +28,18 @@ BEGIN_TEST(testTypedArrays)
 
     size_t nbytes = sizeof(double) * 8;
     RootedObject buffer(cx, JS_NewArrayBuffer(cx, nbytes));
     CHECK(JS_IsArrayBufferObject(buffer));
 
     RootedObject proto(cx);
     JS_GetPrototype(cx, buffer, &proto);
     CHECK(!JS_IsArrayBufferObject(proto));
+    RootedObject dummy(cx, JS_GetParent(proto));
+    CHECK(!JS_IsArrayBufferObject(dummy));
 
     {
         JS::AutoCheckCannotGC nogc;
         CHECK_EQUAL(JS_GetArrayBufferByteLength(buffer), nbytes);
         memset(JS_GetArrayBufferData(buffer, nogc), 1, nbytes);
     }
 
     ok = ok &&
@@ -65,16 +67,18 @@ TestPlainTypedArray(JSContext *cx)
         CHECK(!notArray);
     }
 
     RootedObject array(cx, Create(cx, 7));
     CHECK(JS_IsTypedArrayObject(array));
     RootedObject proto(cx);
     JS_GetPrototype(cx, array, &proto);
     CHECK(!JS_IsTypedArrayObject(proto));
+    RootedObject dummy(cx, JS_GetParent(proto));
+    CHECK(!JS_IsTypedArrayObject(dummy));
 
     CHECK_EQUAL(JS_GetTypedArrayLength(array), 7u);
     CHECK_EQUAL(JS_GetTypedArrayByteOffset(array), 0u);
     CHECK_EQUAL(JS_GetTypedArrayByteLength(array), sizeof(Element) * 7);
 
     {
         JS::AutoCheckCannotGC nogc;
         Element *data;
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1713,16 +1713,23 @@ JS_IsExtensible(JSContext *cx, HandleObj
 
 JS_PUBLIC_API(bool)
 JS_PreventExtensions(JSContext *cx, JS::HandleObject obj, bool *succeeded)
 {
     return PreventExtensions(cx, obj, succeeded);
 }
 
 JS_PUBLIC_API(JSObject *)
+JS_GetParent(JSObject *obj)
+{
+    MOZ_ASSERT(!obj->is<ScopeObject>());
+    return obj->getParent();
+}
+
+JS_PUBLIC_API(JSObject *)
 JS_GetConstructor(JSContext *cx, HandleObject proto)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     assertSameCompartment(cx, proto);
 
     RootedValue cval(cx);
     if (!GetProperty(cx, proto, proto, cx->names().constructor, &cval))
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -2238,16 +2238,19 @@ JS_GetInstancePrivate(JSContext *cx, JS:
 
 extern JS_PUBLIC_API(bool)
 JS_GetPrototype(JSContext *cx, JS::HandleObject obj, JS::MutableHandleObject protop);
 
 extern JS_PUBLIC_API(bool)
 JS_SetPrototype(JSContext *cx, JS::HandleObject obj, JS::HandleObject proto);
 
 extern JS_PUBLIC_API(JSObject *)
+JS_GetParent(JSObject *obj);
+
+extern JS_PUBLIC_API(JSObject *)
 JS_GetConstructor(JSContext *cx, JS::Handle<JSObject*> proto);
 
 namespace JS {
 
 enum ZoneSpecifier {
     FreshZone = 0,
     SystemZone = 1
 };
--- a/js/src/jsfriendapi.cpp
+++ b/js/src/jsfriendapi.cpp
@@ -469,23 +469,16 @@ JS_FRIEND_API(void)
 js::SetFunctionNativeReserved(JSObject *fun, size_t which, const Value &val)
 {
     MOZ_ASSERT(fun->as<JSFunction>().isNative());
     MOZ_ASSERT_IF(val.isObject(), val.toObject().compartment() == fun->compartment());
     fun->as<JSFunction>().setExtendedSlot(which, val);
 }
 
 JS_FRIEND_API(bool)
-js::FunctionHasNativeReserved(JSObject *fun)
-{
-    MOZ_ASSERT(fun->as<JSFunction>().isNative());
-    return fun->as<JSFunction>().isExtended();
-}
-
-JS_FRIEND_API(bool)
 js::GetObjectProto(JSContext *cx, JS::Handle<JSObject*> obj, JS::MutableHandle<JSObject*> proto)
 {
     if (IsProxy(obj))
         return JS_GetPrototype(cx, obj, proto);
 
     proto.set(reinterpret_cast<const shadow::Object*>(obj.get())->group->proto);
     return true;
 }
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -682,16 +682,24 @@ JS_FRIEND_API(bool)
 IsScopeObject(JSObject *obj);
 
 JS_FRIEND_API(bool)
 IsCallObject(JSObject *obj);
 
 JS_FRIEND_API(bool)
 CanAccessObjectShape(JSObject *obj);
 
+inline JSObject *
+GetObjectParent(JSObject *obj)
+{
+    MOZ_ASSERT(!IsScopeObject(obj));
+    MOZ_ASSERT(CanAccessObjectShape(obj));
+    return reinterpret_cast<shadow::Object*>(obj)->shape->base->parent;
+}
+
 static MOZ_ALWAYS_INLINE JSCompartment *
 GetObjectCompartment(JSObject *obj)
 {
     return reinterpret_cast<shadow::Object*>(obj)->group->compartment;
 }
 
 JS_FRIEND_API(JSObject *)
 GetGlobalForObjectCrossCompartment(JSObject *obj);
@@ -743,19 +751,16 @@ NewFunctionByIdWithReserved(JSContext *c
 
 JS_FRIEND_API(const JS::Value &)
 GetFunctionNativeReserved(JSObject *fun, size_t which);
 
 JS_FRIEND_API(void)
 SetFunctionNativeReserved(JSObject *fun, size_t which, const JS::Value &val);
 
 JS_FRIEND_API(bool)
-FunctionHasNativeReserved(JSObject *fun);
-
-JS_FRIEND_API(bool)
 GetObjectProto(JSContext *cx, JS::HandleObject obj, JS::MutableHandleObject proto);
 
 JS_FRIEND_API(bool)
 GetOriginalEval(JSContext *cx, JS::HandleObject scope,
                 JS::MutableHandleObject eval);
 
 inline void *
 GetObjectPrivate(JSObject *obj)
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -2579,17 +2579,17 @@ Clone(JSContext *cx, unsigned argc, jsva
             return false;
         }
     }
 
     if (args.length() > 1) {
         if (!JS_ValueToObject(cx, args[1], &parent))
             return false;
     } else {
-        parent = js::GetGlobalForObjectCrossCompartment(&args.callee());
+        parent = JS_GetParent(&args.callee());
     }
 
     // Should it worry us that we might be getting with wrappers
     // around with wrappers here?
     JS::AutoObjectVector scopeChain(cx);
     if (!parent->is<GlobalObject>() && !scopeChain.append(parent))
         return false;
     JSObject *clone = JS::CloneFunctionObject(cx, funobj, scopeChain);
@@ -3233,16 +3233,44 @@ Elapsed(JSContext *cx, unsigned argc, js
         args.rval().setDouble(d);
         return true;
     }
     JS_ReportError(cx, "Wrong number of arguments");
     return false;
 }
 
 static bool
+Parent(JSContext *cx, unsigned argc, jsval *vp)
+{
+    CallArgs args = CallArgsFromVp(argc, vp);
+    if (args.length() != 1) {
+        JS_ReportError(cx, "Wrong number of arguments");
+        return false;
+    }
+
+    Value v = args[0];
+    if (v.isPrimitive()) {
+        JS_ReportError(cx, "Only objects have parents!");
+        return false;
+    }
+
+    Rooted<JSObject*> parent(cx, JS_GetParent(&v.toObject()));
+
+    /* Outerize if necessary. */
+    if (parent) {
+        parent = GetOuterObject(cx, parent);
+        if (!parent)
+            return false;
+    }
+
+    args.rval().setObjectOrNull(parent);
+    return true;
+}
+
+static bool
 Compile(JSContext *cx, unsigned argc, jsval *vp)
 {
     CallArgs args = CallArgsFromVp(argc, vp);
     if (args.length() < 1) {
         JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
                              "compile", "0", "s");
         return false;
     }
@@ -4899,16 +4927,20 @@ static const JSFunctionSpecWithHelp fuzz
 "clone(fun[, scope])",
 "  Clone function object."),
 
     JS_FN_HELP("getSelfHostedValue", GetSelfHostedValue, 1, 0,
 "getSelfHostedValue()",
 "  Get a self-hosted value by its name. Note that these values don't get \n"
 "  cached, so repeatedly getting the same value creates multiple distinct clones."),
 
+    JS_FN_HELP("parent", Parent, 1, 0,
+"parent(obj)",
+"  Returns the parent of obj."),
+
     JS_FN_HELP("line2pc", LineToPC, 0, 0,
 "line2pc([fun,] line)",
 "  Map line number to PC."),
 
     JS_FN_HELP("pc2line", PCToLine, 0, 0,
 "pc2line(fun[, pc])",
 "  Map PC to line number."),
 
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -114,35 +114,20 @@ GetXrayType(JSObject *obj)
 
     return XrayForOpaqueObject;
 }
 
 JSObject *
 XrayAwareCalleeGlobal(JSObject *fun)
 {
   MOZ_ASSERT(js::IsFunctionObject(fun));
-
-  if (!js::FunctionHasNativeReserved(fun)) {
-      // Just a normal function, no Xrays involved.
-      return js::GetGlobalForObjectCrossCompartment(fun);
-  }
-
-  // The functions we expect here have the Xray wrapper they're associated with
-  // in their XRAY_DOM_FUNCTION_PARENT_WRAPPER_SLOT and, in a debug build, their
-  // JSNative in their XRAY_DOM_FUNCTION_NATIVE_SLOT_FOR_ASSERT.  Assert that
-  // last bit.
-  MOZ_ASSERT(js::GetFunctionNativeReserved(fun, XRAY_DOM_FUNCTION_NATIVE_SLOT_FOR_ASSERT).toPrivate() ==
-             js::GetFunctionObjectNative(fun));
-
-  Value v =
-      js::GetFunctionNativeReserved(fun, XRAY_DOM_FUNCTION_PARENT_WRAPPER_SLOT);
-  MOZ_ASSERT(IsXrayWrapper(&v.toObject()));
-
-  JSObject *xrayTarget = js::UncheckedUnwrap(&v.toObject());
-  return js::GetGlobalForObjectCrossCompartment(xrayTarget);
+  JSObject *scope = js::GetObjectParent(fun);
+  if (IsXrayWrapper(scope))
+    scope = js::UncheckedUnwrap(scope);
+  return js::GetGlobalForObjectCrossCompartment(scope);
 }
 
 JSObject *
 XrayTraits::getExpandoChain(HandleObject obj)
 {
     return ObjectScope(obj)->GetExpandoChain(obj);
 }
 
--- a/js/xpconnect/wrappers/XrayWrapper.h
+++ b/js/xpconnect/wrappers/XrayWrapper.h
@@ -9,24 +9,16 @@
 
 #include "mozilla/Attributes.h"
 
 #include "WrapperFactory.h"
 
 #include "jswrapper.h"
 #include "js/Proxy.h"
 
-// Slot where Xray functions for Web IDL methods store a pointer to
-// the Xray wrapper they're associated with.
-#define XRAY_DOM_FUNCTION_PARENT_WRAPPER_SLOT 0
-// Slot where in debug builds Xray functions for Web IDL methods store
-// a pointer to their JSNative, just so we can assert that they're the
-// sort of functions we expect.
-#define XRAY_DOM_FUNCTION_NATIVE_SLOT_FOR_ASSERT 1
-
 // Xray wrappers re-resolve the original native properties on the native
 // object and always directly access to those properties.
 // Because they work so differently from the rest of the wrapper hierarchy,
 // we pull them out of the Wrapper inheritance hierarchy and create a
 // little world around them.
 
 class nsIPrincipal;
 class XPCWrappedNative;