Bug 1029933 - Introduce the concept of "dependent" standard classes and handle them in the ClassSpec infrastructure. r=Waldo

This commit is contained in:
Bobby Holley 2014-07-04 12:41:28 -07:00
parent cc28be1f79
commit 98413afdad
4 changed files with 50 additions and 21 deletions

View File

@ -609,6 +609,23 @@ 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 with the same js::Class. This basically means
// that the various properties described by our js::Class are intended
// to live higher up on the proto chain.
//
// In practice, this only returns true for Error subtypes.
inline bool
StandardClassIsDependent(JSProtoKey key)
{
JSProtoKey keyFromClass = JSCLASS_CACHED_PROTO_KEY(ProtoKeyToClass(key));
MOZ_ASSERT(keyFromClass);
return key != keyFromClass;
}
inline bool
IsInnerObject(JSObject *obj) {
return !!GetObjectClass(obj)->ext.outerObject;

View File

@ -1249,9 +1249,6 @@ GetBuiltinConstructor(ExclusiveContext *cx, JSProtoKey key, MutableHandleObject
bool
GetBuiltinPrototype(ExclusiveContext *cx, JSProtoKey key, MutableHandleObject objp);
const Class *
ProtoKeyToClass(JSProtoKey key);
JSObject *
GetBuiltinPrototypePure(GlobalObject *global, JSProtoKey protoKey);

View File

@ -63,7 +63,7 @@ static const ProtoTableEntry protoTable[JSProto_LIMIT] = {
#undef INIT_FUNC
};
const js::Class *
JS_FRIEND_API(const js::Class *)
js::ProtoKeyToClass(JSProtoKey key)
{
MOZ_ASSERT(key < JSProto_LIMIT);
@ -166,18 +166,21 @@ GlobalObject::resolveConstructor(JSContext *cx, Handle<GlobalObject*> global, JS
global->setConstructor(key, ObjectValue(*ctor));
global->setConstructorPropertySlot(key, ObjectValue(*ctor));
// Define any specified functions and properties.
if (const JSFunctionSpec *funs = clasp->spec.prototypeFunctions) {
if (!JS_DefineFunctions(cx, proto, funs))
return false;
}
if (const JSPropertySpec *props = clasp->spec.prototypeProperties) {
if (!JS_DefineProperties(cx, proto, props))
return false;
}
if (const JSFunctionSpec *funs = clasp->spec.constructorFunctions) {
if (!JS_DefineFunctions(cx, ctor, funs))
return false;
// Define any specified functions and properties, unless we're a dependent
// standard class (in which case they live on the prototype).
if (!StandardClassIsDependent(key)) {
if (const JSFunctionSpec *funs = clasp->spec.prototypeFunctions) {
if (!JS_DefineFunctions(cx, proto, funs))
return false;
}
if (const JSPropertySpec *props = clasp->spec.prototypeProperties) {
if (!JS_DefineProperties(cx, proto, props))
return false;
}
if (const JSFunctionSpec *funs = clasp->spec.constructorFunctions) {
if (!JS_DefineFunctions(cx, ctor, funs))
return false;
}
}
// If the prototype exists, link it with the constructor.

View File

@ -616,9 +616,8 @@ JSXrayTraits::resolveOwnProperty(JSContext *cx, const Wrapper &jsWrapper,
// Grab the JSClass. We require all Xrayable classes to have a ClassSpec.
const js::Class *clasp = js::GetObjectClass(target);
JSProtoKey protoKey = JSCLASS_CACHED_PROTO_KEY(clasp);
MOZ_ASSERT(protoKey == getProtoKey(holder));
MOZ_ASSERT(clasp->spec.defined());
JSProtoKey protoKey = getProtoKey(holder);
// Handle the 'constructor' property.
if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_CONSTRUCTOR)) {
@ -638,6 +637,11 @@ JSXrayTraits::resolveOwnProperty(JSContext *cx, const Wrapper &jsWrapper,
return true;
}
// Bail out for dependent classes, since all the rest of the properties we'll
// resolve here will live on the parent prototype.
if (js::StandardClassIsDependent(protoKey))
return true;
// Compute the property name we're looking for. We'll handle indexed
// properties when we start supporting arrays.
if (!JSID_IS_STRING(id))
@ -867,8 +871,17 @@ JSXrayTraits::enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags
// Grab the JSClass. We require all Xrayable classes to have a ClassSpec.
const js::Class *clasp = js::GetObjectClass(target);
MOZ_ASSERT(JSCLASS_CACHED_PROTO_KEY(clasp) == getProtoKey(holder));
MOZ_ASSERT(clasp->spec.defined());
JSProtoKey protoKey = getProtoKey(holder);
// Add the 'constructor' property.
if (!props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_CONSTRUCTOR)))
return false;
// Bail out for dependent classes, since all the rest of the properties we'll
// resolve here will live on the parent prototype.
if (js::StandardClassIsDependent(protoKey))
return true;
// Intern all the strings, and pass theme to the caller.
for (const JSFunctionSpec *fs = clasp->spec.prototypeFunctions; fs && fs->name; ++fs) {
@ -893,8 +906,7 @@ JSXrayTraits::enumerateNames(JSContext *cx, HandleObject wrapper, unsigned flags
return false;
}
// Add the 'constructor' property.
return props.append(GetRTIdByIndex(cx, XPCJSRuntime::IDX_CONSTRUCTOR));
return true;
}
JSObject*