Bug 1015798 - Improve ClassSpec depedent behavior especially with inheritance. r=bz
authorTom Schuster <evilpies@gmail.com>
Tue, 08 Nov 2016 22:08:28 +0100
changeset 321559 d09c525ca67505ccddc16e4ddda5ccecd8e0d7df
parent 321558 ec8ee3aeecac15c000996ef173b0cece19b0641f
child 321560 546dbaaff8e90cda29a5b539fde989e0970eca02
push id83644
push userevilpies@gmail.com
push dateTue, 08 Nov 2016 21:08:42 +0000
treeherdermozilla-inbound@138f4cfcbd9d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1015798
milestone52.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 1015798 - Improve ClassSpec depedent behavior especially with inheritance. r=bz
js/public/Class.h
js/src/jsfriendapi.h
js/src/vm/GlobalObject.cpp
js/src/vm/GlobalObject.h
js/xpconnect/wrappers/XrayWrapper.h
--- a/js/public/Class.h
+++ b/js/public/Class.h
@@ -549,36 +549,38 @@ struct ClassSpec
     ClassObjectCreationOp createPrototype_;
     const JSFunctionSpec* constructorFunctions_;
     const JSPropertySpec* constructorProperties_;
     const JSFunctionSpec* prototypeFunctions_;
     const JSPropertySpec* prototypeProperties_;
     FinishClassInitOp finishInit_;
     uintptr_t flags;
 
-    static const size_t ParentKeyWidth = JSCLASS_CACHED_PROTO_WIDTH;
+    static const size_t ProtoKeyWidth = JSCLASS_CACHED_PROTO_WIDTH;
 
-    static const uintptr_t ParentKeyMask = (1 << ParentKeyWidth) - 1;
-    static const uintptr_t DontDefineConstructor = 1 << ParentKeyWidth;
-    static const uintptr_t IsDelegated = 1 << (ParentKeyWidth + 1);
+    static const uintptr_t ProtoKeyMask = (1 << ProtoKeyWidth) - 1;
+    static const uintptr_t DontDefineConstructor = 1 << ProtoKeyWidth;
+    static const uintptr_t IsDelegated = 1 << (ProtoKeyWidth + 1);
 
     bool defined() const { return !!createConstructor_; }
 
     bool delegated() const {
         return (flags & IsDelegated);
     }
 
-    bool dependent() const {
+    // The ProtoKey this class inherits from.
+    JSProtoKey inheritanceProtoKey() const {
         MOZ_ASSERT(defined());
-        return (flags & ParentKeyMask);
-    }
+        static_assert(JSProto_Null == 0, "zeroed key must be null");
 
-    JSProtoKey parentKey() const {
-        static_assert(JSProto_Null == 0, "zeroed key must be null");
-        return JSProtoKey(flags & ParentKeyMask);
+        // Default: Inherit from Object.
+        if (!(flags & ProtoKeyMask))
+            return JSProto_Object;
+
+        return JSProtoKey(flags & ProtoKeyMask);
     }
 
     bool shouldDefineConstructor() const {
         MOZ_ASSERT(defined());
         return !(flags & DontDefineConstructor);
     }
 
     const ClassSpec* delegatedClassSpec() const {
@@ -860,18 +862,18 @@ struct Class
 
     bool isWrappedNative() const {
         return flags & JSCLASS_IS_WRAPPED_NATIVE;
     }
 
     static size_t offsetOfFlags() { return offsetof(Class, flags); }
 
     bool specDefined()         const { return spec ? spec->defined()   : false; }
-    bool specDependent()       const { return spec ? spec->dependent() : false; }
-    JSProtoKey specParentKey() const { return spec ? spec->parentKey() : JSProto_Null; }
+    JSProtoKey specInheritanceProtoKey()
+                               const { return spec ? spec->inheritanceProtoKey() : JSProto_Null; }
     bool specShouldDefineConstructor()
                                const { return spec ? spec->shouldDefineConstructor() : true; }
     ClassObjectCreationOp specCreateConstructorHook()
                                const { return spec ? spec->createConstructorHook()   : nullptr; }
     ClassObjectCreationOp specCreatePrototypeHook()
                                const { return spec ? spec->createPrototypeHook()     : nullptr; }
     const JSFunctionSpec* specConstructorFunctions()
                                const { return spec ? spec->constructorFunctions()    : nullptr; }
--- a/js/src/jsfriendapi.h
+++ b/js/src/jsfriendapi.h
@@ -639,44 +639,33 @@ inline const JSClass*
 GetObjectJSClass(JSObject* obj)
 {
     return js::Jsvalify(GetObjectClass(obj));
 }
 
 JS_FRIEND_API(const Class*)
 ProtoKeyToClass(JSProtoKey key);
 
-// Returns true if the standard class identified by |key| inherits from
-// another standard class (in addition to Object) along its proto chain.
-//
-// In practice, this only returns true for Error subtypes.
-inline bool
-StandardClassIsDependent(JSProtoKey key)
-{
-    const Class* clasp = ProtoKeyToClass(key);
-    return clasp && clasp->specDefined() && clasp->specDependent();
-}
-
 // Returns the key for the class inherited by a given standard class (that
 // is to say, the prototype of this standard class's prototype).
 //
 // You must be sure that this corresponds to a standard class with a cached
 // JSProtoKey before calling this function. In general |key| will match the
 // cached proto key, except in cases where multiple JSProtoKeys share a
 // JSClass.
 inline JSProtoKey
-ParentKeyForStandardClass(JSProtoKey key)
+InheritanceProtoKeyForStandardClass(JSProtoKey key)
 {
     // [Object] has nothing to inherit from.
     if (key == JSProto_Object)
         return JSProto_Null;
 
-    // If we're dependent, return the key of the class we depend on.
-    if (StandardClassIsDependent(key))
-        return ProtoKeyToClass(key)->specParentKey();
+    // If we're ClassSpec defined return the proto key from that
+    if (ProtoKeyToClass(key)->specDefined())
+        return ProtoKeyToClass(key)->specInheritanceProtoKey();
 
     // Otherwise, we inherit [Object].
     return JSProto_Object;
 }
 
 JS_FRIEND_API(bool)
 IsFunctionObject(JSObject* obj);
 
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -223,21 +223,19 @@ GlobalObject::resolveConstructor(JSConte
             RootedValue ctorValue(cx, ObjectValue(*ctor));
             if (!DefineProperty(cx, global, id, ctorValue, nullptr, nullptr, JSPROP_RESOLVING))
                 return false;
         }
 
         global->setConstructor(key, ObjectValue(*ctor));
     }
 
-    // Define any specified functions and properties, unless we're a dependent
-    // standard class (in which case they live on the prototype), or we're
-    // operating on the self-hosting global, in which case we don't want any
+    // If we're operating on the self-hosting global, we don't want any
     // functions and properties on the builtins and their prototypes.
-    if (!StandardClassIsDependent(key) && !cx->runtime()->isSelfHostingGlobal(global)) {
+    if (!cx->runtime()->isSelfHostingGlobal(global)) {
         if (const JSFunctionSpec* funs = clasp->specPrototypeFunctions()) {
             if (!JS_DefineFunctions(cx, proto, funs))
                 return false;
         }
         if (const JSPropertySpec* props = clasp->specPrototypeProperties()) {
             if (!JS_DefineProperties(cx, proto, props))
                 return false;
         }
--- a/js/src/vm/GlobalObject.h
+++ b/js/src/vm/GlobalObject.h
@@ -981,20 +981,20 @@ GenericCreateConstructor(JSContext* cx, 
 }
 
 inline JSObject*
 GenericCreatePrototype(JSContext* cx, JSProtoKey key)
 {
     MOZ_ASSERT(key != JSProto_Object);
     const Class* clasp = ProtoKeyToClass(key);
     MOZ_ASSERT(clasp);
-    JSProtoKey parentKey = ParentKeyForStandardClass(key);
-    if (!GlobalObject::ensureConstructor(cx, cx->global(), parentKey))
+    JSProtoKey protoKey = InheritanceProtoKeyForStandardClass(key);
+    if (!GlobalObject::ensureConstructor(cx, cx->global(), protoKey))
         return nullptr;
-    RootedObject parentProto(cx, &cx->global()->getPrototype(parentKey).toObject());
+    RootedObject parentProto(cx, &cx->global()->getPrototype(protoKey).toObject());
     return cx->global()->createBlankPrototypeInheriting(cx, clasp, parentProto);
 }
 
 inline JSProtoKey
 StandardProtoKeyOrNull(const JSObject* obj)
 {
     JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
     if (key == JSProto_Error)
--- a/js/xpconnect/wrappers/XrayWrapper.h
+++ b/js/xpconnect/wrappers/XrayWrapper.h
@@ -272,22 +272,22 @@ public:
 
     bool getPrototype(JSContext* cx, JS::HandleObject wrapper,
                       JS::HandleObject target,
                       JS::MutableHandleObject protop)
     {
         JS::RootedObject holder(cx, ensureHolder(cx, wrapper));
         JSProtoKey key = getProtoKey(holder);
         if (isPrototype(holder)) {
-            JSProtoKey parentKey = js::ParentKeyForStandardClass(key);
-            if (parentKey == JSProto_Null) {
+            JSProtoKey protoKey = js::InheritanceProtoKeyForStandardClass(key);
+            if (protoKey == JSProto_Null) {
                 protop.set(nullptr);
                 return true;
             }
-            key = parentKey;
+            key = protoKey;
         }
 
         {
             JSAutoCompartment ac(cx, target);
             if (!JS_GetClassPrototype(cx, key, protop))
                 return false;
         }
         return JS_WrapObject(cx, protop);