Bug 959012 - Clean up and separate the semantics of js_{Get,Find}Class{Prototype,Object}. r=jorendorff
authorBobby Holley <bobbyholley@gmail.com>
Thu, 30 Jan 2014 07:45:16 -0800
changeset 181992 8d236f70c2d4268fe6e897d290bd92f3d9cb2b0b
parent 181991 185004086e8c01932ebe4c33c813a820490eb511
child 181993 1a4489b84a4e940e6b40548af14a150334203932
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)
reviewersjorendorff
bugs959012
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 959012 - Clean up and separate the semantics of js_{Get,Find}Class{Prototype,Object}. r=jorendorff
js/src/jsapi.cpp
js/src/jsapi.h
js/src/jscompartment.cpp
js/src/jsiter.cpp
js/src/jsobj.cpp
js/src/jsobj.h
js/src/jsobjinlines.h
js/src/jsworkers.cpp
js/src/vm/TypedArrayObject.cpp
js/xpconnect/wrappers/XrayWrapper.cpp
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1352,22 +1352,21 @@ JS_EnumerateStandardClasses(JSContext *c
                 return false;
         }
     }
 
     return true;
 }
 
 JS_PUBLIC_API(bool)
-JS_GetClassObject(JSContext *cx, HandleObject obj, JSProtoKey key, MutableHandleObject objp)
+JS_GetClassObject(JSContext *cx, JSProtoKey key, MutableHandleObject objp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
-    assertSameCompartment(cx, obj);
-    return js_GetClassObject(cx, obj, key, objp);
+    return js_GetClassObject(cx, key, objp);
 }
 
 JS_PUBLIC_API(bool)
 JS_GetClassPrototype(JSContext *cx, JSProtoKey key, MutableHandleObject objp)
 {
     AssertHeapIsIdle(cx);
     CHECK_REQUEST(cx);
     return js_GetClassPrototype(cx, key, objp);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1784,18 +1784,17 @@ JS_InitStandardClasses(JSContext *cx, JS
 extern JS_PUBLIC_API(bool)
 JS_ResolveStandardClass(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                         bool *resolved);
 
 extern JS_PUBLIC_API(bool)
 JS_EnumerateStandardClasses(JSContext *cx, JS::HandleObject obj);
 
 extern JS_PUBLIC_API(bool)
-JS_GetClassObject(JSContext *cx, JS::Handle<JSObject*> obj, JSProtoKey key,
-                  JS::MutableHandle<JSObject*> objp);
+JS_GetClassObject(JSContext *cx, JSProtoKey key, JS::MutableHandle<JSObject*> objp);
 
 extern JS_PUBLIC_API(bool)
 JS_GetClassPrototype(JSContext *cx, JSProtoKey key, JS::MutableHandle<JSObject*> objp);
 
 extern JS_PUBLIC_API(JSProtoKey)
 JS_IdentifyClassPrototype(JSObject *obj);
 
 extern JS_PUBLIC_API(JSProtoKey)
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -381,20 +381,20 @@ JSCompartment::wrap(JSContext *cx, Mutab
     unsigned flags = 0;
     obj.set(UncheckedUnwrap(obj, /* stopAtOuter = */ true, &flags));
 
     if (obj->compartment() == this)
         return WrapForSameCompartment(cx, obj, cb);
 
     /* Translate StopIteration singleton. */
     if (obj->is<StopIterationObject>()) {
-        RootedValue v(cx);
-        if (!js_FindClassObject(cx, JSProto_StopIteration, &v))
+        RootedObject stopIteration(cx);
+        if (!js_GetClassObject(cx, JSProto_StopIteration, &stopIteration))
             return false;
-        obj.set(&v.toObject());
+        obj.set(stopIteration);
         return true;
     }
 
     /* Invoke the prewrap callback. We're a bit worried about infinite
      * recursion here, so we do a check - see bug 809295. */
     JS_CHECK_CHROME_RECURSION(cx, return false);
     if (cb->preWrap) {
         obj.set(cb->preWrap(cx, global, obj, flags));
--- a/js/src/jsiter.cpp
+++ b/js/src/jsiter.cpp
@@ -725,19 +725,19 @@ js::CreateItrResultObject(JSContext *cx,
 
     return obj;
 }
 
 bool
 js_ThrowStopIteration(JSContext *cx)
 {
     JS_ASSERT(!JS_IsExceptionPending(cx));
-    RootedValue v(cx);
-    if (js_FindClassObject(cx, JSProto_StopIteration, &v))
-        cx->setPendingException(v);
+    RootedObject ctor(cx);
+    if (js_GetClassObject(cx, JSProto_StopIteration, &ctor) && ctor)
+        cx->setPendingException(ObjectValue(*ctor));
     return false;
 }
 
 /*** Iterator objects ****************************************************************************/
 
 bool
 js::IteratorConstructor(JSContext *cx, unsigned argc, Value *vp)
 {
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3249,31 +3249,33 @@ MaybeResolveConstructor(ExclusiveContext
     RootedId name(cx, NameToId(ClassName(key, cx)));
     AutoResolving resolving(cx, global, name);
     if (resolving.alreadyStarted())
        return true;
     return global->ensureConstructor(cx, key);
 }
 
 bool
-js_GetClassObject(ExclusiveContext *cx, JSObject *obj, JSProtoKey key, MutableHandleObject objp)
-{
-    Rooted<GlobalObject*> global(cx, &obj->global());
+js_GetClassObject(ExclusiveContext *cx, JSProtoKey key, MutableHandleObject objp)
+{
+    MOZ_ASSERT(key != JSProto_Null);
+    Rooted<GlobalObject*> global(cx, cx->global());
     if (!MaybeResolveConstructor(cx, global, key))
         return false;
 
     Value v = global->getConstructor(key);
     if (v.isObject())
         objp.set(&v.toObject());
     return true;
 }
 
 bool
 js_GetClassPrototype(ExclusiveContext *cx, JSProtoKey key, MutableHandleObject protop)
 {
+    MOZ_ASSERT(key != JSProto_Null);
     Rooted<GlobalObject*> global(cx, cx->global());
     if (!MaybeResolveConstructor(cx, global, key))
         return false;
 
     Value v = global->getPrototype(key);
     if (v.isObject())
         protop.set(&v.toObject());
     return true;
@@ -3298,51 +3300,48 @@ js_IdentifyClassPrototype(JSObject *obj)
     if (v.isObject() && obj == &v.toObject())
         return key;
 
     // False alarm - just an instance.
     return JSProto_Null;
 }
 
 bool
-js_FindClassObject(ExclusiveContext *cx, JSProtoKey protoKey, MutableHandleValue vp, const Class *clasp)
-{
+js_FindClassObject(ExclusiveContext *cx, MutableHandleObject protop, const Class *clasp)
+{
+    MOZ_ASSERT(clasp);
+    JSProtoKey protoKey = GetClassProtoKey(clasp);
     RootedId id(cx);
-
     if (protoKey != JSProto_Null) {
         JS_ASSERT(JSProto_Null < protoKey);
         JS_ASSERT(protoKey < JSProto_LIMIT);
         RootedObject cobj(cx);
-        if (!js_GetClassObject(cx, cx->global(), protoKey, &cobj))
+        if (!js_GetClassObject(cx, protoKey, protop))
             return false;
-        if (cobj) {
-            vp.set(ObjectValue(*cobj));
+        if (cobj)
             return true;
-        }
         id = NameToId(ClassName(protoKey, cx));
     } else {
         JSAtom *atom = Atomize(cx, clasp->name, strlen(clasp->name));
         if (!atom)
             return false;
         id = AtomToId(atom);
     }
 
     RootedObject pobj(cx);
     RootedShape shape(cx);
     if (!LookupPropertyWithFlags(cx, cx->global(), id, 0, &pobj, &shape))
         return false;
     RootedValue v(cx, UndefinedValue());
     if (shape && pobj->isNative()) {
-        if (shape->hasSlot()) {
+        if (shape->hasSlot())
             v = pobj->nativeGetSlot(shape->slot());
-            if (v.get().isPrimitive())
-                v.get().setUndefined();
-        }
-    }
-    vp.set(v);
+    }
+    if (v.isObject())
+        protop.set(&v.toObject());
     return true;
 }
 
 /* static */ bool
 JSObject::allocSlot(ThreadSafeContext *cx, HandleObject obj, uint32_t *slotp)
 {
     JS_ASSERT(cx->isThreadLocal(obj));
 
@@ -5443,46 +5442,47 @@ js::GetClassPrototypePure(GlobalObject *
     return nullptr;
 }
 
 /*
  * The first part of this function has been hand-expanded and optimized into
  * NewBuiltinClassInstance in jsobjinlines.h.
  */
 bool
-js_FindClassPrototype(ExclusiveContext *cx, JSProtoKey protoKey,
-                      MutableHandleObject protop, const Class *clasp)
-{
+js_FindClassPrototype(ExclusiveContext *cx, MutableHandleObject protop, const Class *clasp)
+{
+    protop.set(nullptr);
+    JSProtoKey protoKey = GetClassProtoKey(clasp);
     if (protoKey != JSProto_Null) {
         if (!js_GetClassPrototype(cx, protoKey, protop))
             return false;
         if (protop)
             return true;
     }
 
-    RootedValue v(cx);
-    if (!js_FindClassObject(cx, protoKey, &v, clasp))
+    RootedObject ctor(cx);
+    if (!js_FindClassObject(cx, &ctor, clasp))
         return false;
 
-    if (IsFunctionObject(v)) {
-        RootedObject ctor(cx, &v.get().toObject());
+    if (ctor && ctor->is<JSFunction>()) {
+        RootedValue v(cx);
         if (cx->isJSContext()) {
             if (!JSObject::getProperty(cx->asJSContext(),
                                        ctor, ctor, cx->names().prototype, &v))
             {
                 return false;
             }
         } else {
             Shape *shape = ctor->nativeLookup(cx, cx->names().prototype);
             if (!shape || !NativeGetPureInline(ctor, shape, v.address()))
                 return false;
         }
-    }
-
-    protop.set(v.get().isObject() ? &v.get().toObject() : nullptr);
+        if (v.isObject())
+            protop.set(&v.toObject());
+    }
     return true;
 }
 
 JSObject *
 js::PrimitiveToObject(JSContext *cx, const Value &v)
 {
     if (v.isString()) {
         Rooted<JSString*> str(cx, v.toString());
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1316,48 +1316,43 @@ extern const char js_lookupSetter_str[];
 
 extern bool
 js_PopulateObject(JSContext *cx, js::HandleObject newborn, js::HandleObject props);
 
 /*
  * Fast access to immutable standard objects (constructors and prototypes).
  */
 extern bool
-js_GetClassObject(js::ExclusiveContext *cx, JSObject *obj, JSProtoKey key,
+js_GetClassObject(js::ExclusiveContext *cx, JSProtoKey key,
                   js::MutableHandleObject objp);
 
 extern bool
 js_GetClassPrototype(js::ExclusiveContext *cx, JSProtoKey key,
                      js::MutableHandleObject objp);
 
 /*
  * Determine if the given object is a prototype for a standard class. If so,
  * return the associated JSProtoKey. If not, return JSProto_Null.
  */
 extern JSProtoKey
 js_IdentifyClassPrototype(JSObject *obj);
 
 /*
- * If protoKey is not JSProto_Null, then clasp is ignored. If protoKey is
- * JSProto_Null, clasp must non-null.
+ * Property-lookup-based access to interface and prototype objects for classes.
+ * If the class is built-in (and has a non-null JSProtoKey), these forward to
+ * js_GetClass{Object,Prototype}.
  */
-bool
-js_FindClassObject(js::ExclusiveContext *cx, JSProtoKey protoKey, js::MutableHandleValue vp,
-                   const js::Class *clasp = nullptr);
 
-/*
- * If protoKey is not JSProto_Null, then clasp is ignored. If protoKey is
- * JSProto_Null, clasp must non-null.
- *
- * If protoKey is constant and scope is non-null, use GlobalObject's prototype
- * methods instead.
- */
+bool
+js_FindClassObject(js::ExclusiveContext *cx, js::MutableHandleObject protop,
+                   const js::Class *clasp);
+
 extern bool
-js_FindClassPrototype(js::ExclusiveContext *cx, JSProtoKey protoKey, js::MutableHandleObject protop,
-                      const js::Class *clasp = nullptr);
+js_FindClassPrototype(js::ExclusiveContext *cx, js::MutableHandleObject protop,
+                      const js::Class *clasp);
 
 
 namespace js {
 
 extern bool
 DefineOwnProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id,
                   JS::HandleValue descriptor, bool *bp);
 
--- a/js/src/jsobjinlines.h
+++ b/js/src/jsobjinlines.h
@@ -871,18 +871,17 @@ GetClassProtoKey(const js::Class *clasp)
     if (clasp->flags & JSCLASS_IS_ANONYMOUS)
         return JSProto_Object;
     return JSProto_Null;
 }
 
 inline bool
 FindProto(ExclusiveContext *cx, const js::Class *clasp, MutableHandleObject proto)
 {
-    JSProtoKey protoKey = GetClassProtoKey(clasp);
-    if (!js_FindClassPrototype(cx, protoKey, proto, clasp))
+    if (!js_FindClassPrototype(cx, proto, clasp))
         return false;
     if (!proto && !js_GetClassPrototype(cx, JSProto_Object, proto))
         return false;
     return true;
 }
 
 /*
  * Make an object with the prototype set according to the specified prototype or class:
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -276,29 +276,29 @@ js::StartOffThreadParseScript(JSContext 
     global->zone()->types.inferenceEnabled = cx->typeInferenceEnabled();
     JS_SetCompartmentPrincipals(global->compartment(), cx->compartment()->principals);
 
     RootedObject obj(cx);
 
     // Initialize all classes needed for parsing while we are still on the main
     // thread. Do this for both the target and the new global so that prototype
     // pointers can be changed infallibly after parsing finishes.
-    if (!js_GetClassObject(cx, cx->global(), JSProto_Function, &obj) ||
-        !js_GetClassObject(cx, cx->global(), JSProto_Array, &obj) ||
-        !js_GetClassObject(cx, cx->global(), JSProto_RegExp, &obj) ||
-        !js_GetClassObject(cx, cx->global(), JSProto_Iterator, &obj))
+    if (!js_GetClassObject(cx, JSProto_Function, &obj) ||
+        !js_GetClassObject(cx, JSProto_Array, &obj) ||
+        !js_GetClassObject(cx, JSProto_RegExp, &obj) ||
+        !js_GetClassObject(cx, JSProto_Iterator, &obj))
     {
         return false;
     }
     {
         AutoCompartment ac(cx, global);
-        if (!js_GetClassObject(cx, global, JSProto_Function, &obj) ||
-            !js_GetClassObject(cx, global, JSProto_Array, &obj) ||
-            !js_GetClassObject(cx, global, JSProto_RegExp, &obj) ||
-            !js_GetClassObject(cx, global, JSProto_Iterator, &obj))
+        if (!js_GetClassObject(cx, JSProto_Function, &obj) ||
+            !js_GetClassObject(cx, JSProto_Array, &obj) ||
+            !js_GetClassObject(cx, JSProto_RegExp, &obj) ||
+            !js_GetClassObject(cx, JSProto_Iterator, &obj))
         {
             return false;
         }
     }
 
     ScopedJSDeletePtr<ExclusiveContext> workercx(
         cx->new_<ExclusiveContext>(cx->runtime(), (PerThreadData *) nullptr,
                                    ThreadSafeContext::Context_Exclusive));
--- a/js/src/vm/TypedArrayObject.cpp
+++ b/js/src/vm/TypedArrayObject.cpp
@@ -3950,21 +3950,22 @@ DataViewObject::neuter()
     setSlot(BYTEOFFSET_SLOT, Int32Value(0));
     setPrivate(nullptr);
 }
 
 JSObject *
 js_InitTypedArrayClasses(JSContext *cx, HandleObject obj)
 {
     JS_ASSERT(obj->isNative());
+    assertSameCompartment(cx, obj);
     Rooted<GlobalObject*> global(cx, &obj->as<GlobalObject>());
 
     /* Idempotency required: we initialize several things, possibly lazily. */
     RootedObject stop(cx);
-    if (!js_GetClassObject(cx, global, JSProto_ArrayBuffer, &stop))
+    if (!js_GetClassObject(cx, JSProto_ArrayBuffer, &stop))
         return nullptr;
     if (stop)
         return stop;
 
     if (!InitTypedArrayClass<Int8ArrayObject>(cx) ||
         !InitTypedArrayClass<Uint8ArrayObject>(cx) ||
         !InitTypedArrayClass<Int16ArrayObject>(cx) ||
         !InitTypedArrayClass<Uint16ArrayObject>(cx) ||
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -853,17 +853,17 @@ XrayTraits::resolveOwnProperty(JSContext
 
     // Next, check for ES builtins.
     if (!found && JS_IsGlobalObject(target)) {
         JSProtoKey key = JS_IdToProtoKey(cx, id);
         JSAutoCompartment ac(cx, target);
         if (key != JSProto_Null) {
             MOZ_ASSERT(key < JSProto_LIMIT);
             RootedObject constructor(cx);
-            if (!JS_GetClassObject(cx, target, key, &constructor))
+            if (!JS_GetClassObject(cx, key, &constructor))
                 return false;
             MOZ_ASSERT(constructor);
             desc.value().set(ObjectValue(*constructor));
             found = true;
         } else if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_EVAL)) {
             RootedObject eval(cx);
             if (!js::GetOriginalEval(cx, target, &eval))
                 return false;