diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 4b2f1a271eb..d30dd63f5b9 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2226,6 +2226,30 @@ JS_GetClassObject(JSContext *cx, JSObject *obj_, JSProtoKey key, JSObject **objp return result; } +JS_PUBLIC_API(JSBool) +JS_GetClassPrototype(JSContext *cx, JSProtoKey key, JSObject **objp_) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + RootedObject global(cx, cx->compartment->maybeGlobal()); + if (!global) + return false; + RootedObject objp(cx); + bool result = js_GetClassPrototype(cx, global, key, &objp); + *objp_ = objp; + return result; +} + +JS_PUBLIC_API(JSProtoKey) +JS_IdentifyClassPrototype(JSContext *cx, JSObject *obj) +{ + AssertHeapIsIdle(cx); + CHECK_REQUEST(cx); + assertSameCompartment(cx, obj); + JS_ASSERT(!IsCrossCompartmentWrapper(obj)); + return js_IdentifyClassPrototype(obj); +} + JS_PUBLIC_API(JSObject *) JS_GetObjectPrototype(JSContext *cx, JSObject *forObj) { diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 3ef69d3c26d..bf80b34d80e 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -3284,6 +3284,12 @@ extern JS_PUBLIC_API(JSBool) JS_GetClassObject(JSContext *cx, JSObject *obj, JSProtoKey key, JSObject **objp); +extern JS_PUBLIC_API(JSBool) +JS_GetClassPrototype(JSContext *cx, JSProtoKey key, JSObject **objp); + +extern JS_PUBLIC_API(JSProtoKey) +JS_IdentifyClassPrototype(JSContext *cx, JSObject *obj); + /* * Returns the original value of |Function.prototype| from the global object in * which |forObj| was created. diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 2922065a663..54826b30212 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -3829,6 +3829,29 @@ js_GetClassObject(JSContext *cx, HandleObject obj, JSProtoKey key, return true; } +JSProtoKey +js_IdentifyClassPrototype(JSObject *obj) +{ + // First, get the key off the JSClass. This tells us which prototype we + // _might_ be. But we still don't know for sure, since the prototype shares + // its JSClass with instances. + JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass()); + if (key == JSProto_Null) + return JSProto_Null; + + // Now, see if the cached object matches |obj|. + // + // Note that standard class objects are cached in the range [0, JSProto_LIMIT), + // and the prototypes are cached in [JSProto_LIMIT, 2*JSProto_LIMIT). + JSObject &global = obj->global(); + Value v = global.getReservedSlot(JSProto_LIMIT + key); + if (v.isObject() && obj == &v.toObject()) + return key; + + // False alarm - just an instance. + return JSProto_Null; +} + bool js_FindClassObject(JSContext *cx, HandleObject start, JSProtoKey protoKey, MutableHandleValue vp, Class *clasp) diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 639b67154e3..156bde1f79b 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -1110,6 +1110,13 @@ extern bool js_GetClassObject(JSContext *cx, js::HandleObject obj, 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.