From 201e79d435f53d1926f077cbdd591606ea7e40b6 Mon Sep 17 00:00:00 2001 From: Tom Schuster Date: Thu, 29 Jan 2015 19:52:01 +0100 Subject: [PATCH] Bug 1125567 - Simplify FindClassPrototype/FindClassObject machinery. r=Waldo --- js/src/jsobj.cpp | 160 ++++++++++++++++++++++-------------------- js/src/jsobj.h | 12 ---- js/src/jsobjinlines.h | 17 ----- 3 files changed, 84 insertions(+), 105 deletions(-) diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 5b4af322493b..b09673609fb4 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1404,6 +1404,90 @@ ClassProtoKeyOrAnonymousOrNull(const js::Class *clasp) return JSProto_Null; } +static inline bool +NativeGetPureInline(NativeObject *pobj, Shape *shape, MutableHandleValue vp) +{ + if (shape->hasSlot()) { + vp.set(pobj->getSlot(shape->slot())); + MOZ_ASSERT(!vp.isMagic()); + } else { + vp.setUndefined(); + } + + /* Fail if we have a custom getter. */ + return shape->hasDefaultGetter(); +} + +static bool +FindClassPrototype(ExclusiveContext *cx, MutableHandleObject protop, const Class *clasp) +{ + protop.set(nullptr); + + JSAtom *atom = Atomize(cx, clasp->name, strlen(clasp->name)); + if (!atom) + return false; + RootedId id(cx, AtomToId(atom)); + + RootedObject pobj(cx); + RootedShape shape(cx); + if (!NativeLookupProperty(cx, cx->global(), id, &pobj, &shape)) + return false; + + RootedObject ctor(cx); + if (shape && pobj->isNative()) { + if (shape->hasSlot()) { + RootedValue v(cx, pobj->as().getSlot(shape->slot())); + if (v.isObject()) + ctor.set(&v.toObject()); + } + } + + if (ctor && ctor->is()) { + JSFunction *nctor = &ctor->as(); + RootedValue v(cx); + if (cx->isJSContext()) { + if (!GetProperty(cx->asJSContext(), ctor, ctor, cx->names().prototype, &v)) + return false; + } else { + Shape *shape = nctor->lookup(cx, cx->names().prototype); + if (!shape || !NativeGetPureInline(nctor, shape, &v)) + return false; + } + if (v.isObject()) + protop.set(&v.toObject()); + } + return true; +} + +// Find the appropriate proto for a class. There are three different ways to achieve this: +// 1. Built-in classes have a cached proto and anonymous classes get Object.prototype. +// 2. Lookup global[clasp->name].prototype +// 3. Fallback to Object.prototype +// +// Step 2 is in some circumstances an observable operation, which is probably wrong +// as a matter of specifications. It's legacy garbage that we're working to remove eventually. +static bool +FindProto(ExclusiveContext *cx, const js::Class *clasp, MutableHandleObject proto) +{ + JSProtoKey protoKey = ClassProtoKeyOrAnonymousOrNull(clasp); + if (protoKey != JSProto_Null) + return GetBuiltinPrototype(cx, protoKey, proto); + + if (!FindClassPrototype(cx, proto, clasp)) + return false; + + if (!proto) { + // We're looking for the prototype of a class that is currently being + // resolved; the global object's resolve hook is on the + // stack. js::FindClassPrototype detects this goofy case and returns + // true with proto null. Fall back on Object.prototype. + MOZ_ASSERT(JSCLASS_CACHED_PROTO_KEY(clasp) == JSProto_Null); + return GetBuiltinPrototype(cx, JSProto_Object, proto); + } + return true; +} + + JSObject * js::NewObjectWithClassProtoCommon(ExclusiveContext *cxArg, const js::Class *clasp, JSObject *protoArg, JSObject *parentArg, @@ -2779,35 +2863,6 @@ JS::IdentifyStandardConstructor(JSObject *obj) return JSProto_Null; } -bool -js::FindClassObject(ExclusiveContext *cx, MutableHandleObject protop, const Class *clasp) -{ - JSProtoKey protoKey = ClassProtoKeyOrAnonymousOrNull(clasp); - if (protoKey != JSProto_Null) { - MOZ_ASSERT(JSProto_Null < protoKey); - MOZ_ASSERT(protoKey < JSProto_LIMIT); - return GetBuiltinConstructor(cx, protoKey, protop); - } - - JSAtom *atom = Atomize(cx, clasp->name, strlen(clasp->name)); - if (!atom) - return false; - RootedId id(cx, AtomToId(atom)); - - RootedObject pobj(cx); - RootedShape shape(cx); - if (!NativeLookupProperty(cx, cx->global(), id, &pobj, &shape)) - return false; - RootedValue v(cx); - if (shape && pobj->isNative()) { - if (shape->hasSlot()) - v = pobj->as().getSlot(shape->slot()); - } - if (v.isObject()) - protop.set(&v.toObject()); - return true; -} - bool JSObject::isCallable() const { @@ -3050,20 +3105,6 @@ LookupPropertyPureInline(ExclusiveContext *cx, JSObject *obj, jsid id, NativeObj return true; } -static MOZ_ALWAYS_INLINE bool -NativeGetPureInline(NativeObject *pobj, Shape *shape, Value *vp) -{ - if (shape->hasSlot()) { - *vp = pobj->getSlot(shape->slot()); - MOZ_ASSERT(!vp->isMagic()); - } else { - vp->setUndefined(); - } - - /* Fail if we have a custom getter. */ - return shape->hasDefaultGetter(); -} - bool js::LookupPropertyPure(ExclusiveContext *cx, JSObject *obj, jsid id, NativeObject **objp, Shape **propp) @@ -3571,39 +3612,6 @@ js::GetBuiltinPrototypePure(GlobalObject *global, JSProtoKey protoKey) return nullptr; } -/* - * The first part of this function has been hand-expanded and optimized into - * NewBuiltinClassInstance in jsobjinlines.h. - */ -bool -js::FindClassPrototype(ExclusiveContext *cx, MutableHandleObject protop, const Class *clasp) -{ - protop.set(nullptr); - JSProtoKey protoKey = ClassProtoKeyOrAnonymousOrNull(clasp); - if (protoKey != JSProto_Null) - return GetBuiltinPrototype(cx, protoKey, protop); - - RootedObject ctor(cx); - if (!FindClassObject(cx, &ctor, clasp)) - return false; - - if (ctor && ctor->is()) { - JSFunction *nctor = &ctor->as(); - RootedValue v(cx); - if (cx->isJSContext()) { - if (!GetProperty(cx->asJSContext(), ctor, ctor, cx->names().prototype, &v)) - return false; - } else { - Shape *shape = nctor->lookup(cx, cx->names().prototype); - if (!shape || !NativeGetPureInline(nctor, shape, v.address())) - return false; - } - if (v.isObject()) - protop.set(&v.toObject()); - } - return true; -} - JSObject * js::PrimitiveToObject(JSContext *cx, const Value &v) { diff --git a/js/src/jsobj.h b/js/src/jsobj.h index c0b7b6c1f547..8ba36040a62f 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -1092,18 +1092,6 @@ extern bool SetClassAndProto(JSContext *cx, HandleObject obj, const Class *clasp, Handle proto); -/* - * Property-lookup-based access to interface and prototype objects for classes. - * If the class is built-in (hhas a non-null JSProtoKey), these forward to - * GetClass{Object,Prototype}. - */ - -bool -FindClassObject(ExclusiveContext *cx, MutableHandleObject protop, const Class *clasp); - -extern bool -FindClassPrototype(ExclusiveContext *cx, MutableHandleObject protop, const Class *clasp); - } /* namespace js */ /* diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index 1643cb339cad..68af35c7f242 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -554,23 +554,6 @@ NewObjectWithGivenProto(ExclusiveContext *cx, JSObject *proto, JSObject *parent, return obj ? &obj->as() : nullptr; } -inline bool -FindProto(ExclusiveContext *cx, const js::Class *clasp, MutableHandleObject proto) -{ - if (!FindClassPrototype(cx, proto, clasp)) - return false; - - if (!proto) { - // We're looking for the prototype of a class that is currently being - // resolved; the global object's resolve hook is on the - // stack. js::FindClassPrototype detects this goofy case and returns - // true with proto null. Fall back on Object.prototype. - MOZ_ASSERT(JSCLASS_CACHED_PROTO_KEY(clasp) == JSProto_Null); - return GetBuiltinPrototype(cx, JSProto_Object, proto); - } - return true; -} - /* * Make an object with the prototype set according to the specified prototype or class: *