зеркало из https://github.com/mozilla/gecko-dev.git
Bug 861219 - Part 0: Make ClassSpec be able to delegate to another ClassSpec. r=bholley
This commit is contained in:
Родитель
d84f510fb3
Коммит
259232ac04
|
@ -454,13 +454,14 @@ const size_t JSCLASS_CACHED_PROTO_WIDTH = 6;
|
|||
|
||||
struct ClassSpec
|
||||
{
|
||||
ClassObjectCreationOp createConstructor;
|
||||
ClassObjectCreationOp createPrototype;
|
||||
const JSFunctionSpec* constructorFunctions;
|
||||
const JSPropertySpec* constructorProperties;
|
||||
const JSFunctionSpec* prototypeFunctions;
|
||||
const JSPropertySpec* prototypeProperties;
|
||||
FinishClassInitOp finishInit;
|
||||
// All properties except flags should be accessed through get* accessor.
|
||||
ClassObjectCreationOp createConstructor_;
|
||||
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;
|
||||
|
@ -468,7 +469,13 @@ struct ClassSpec
|
|||
static const uintptr_t ParentKeyMask = (1 << ParentKeyWidth) - 1;
|
||||
static const uintptr_t DontDefineConstructor = 1 << ParentKeyWidth;
|
||||
|
||||
bool defined() const { return !!createConstructor; }
|
||||
static const uintptr_t DelegatedTag = 1;
|
||||
|
||||
bool defined() const { return !!createConstructor_; }
|
||||
|
||||
bool delegated() const {
|
||||
return !!(reinterpret_cast<uintptr_t>(createConstructor_) & DelegatedTag);
|
||||
}
|
||||
|
||||
bool dependent() const {
|
||||
MOZ_ASSERT(defined());
|
||||
|
@ -484,6 +491,48 @@ struct ClassSpec
|
|||
MOZ_ASSERT(defined());
|
||||
return !(flags & DontDefineConstructor);
|
||||
}
|
||||
|
||||
const ClassSpec* delegatedClassSpec() const {
|
||||
MOZ_ASSERT(delegated());
|
||||
return reinterpret_cast<ClassSpec*>(reinterpret_cast<uintptr_t>(createConstructor_) &
|
||||
~DelegatedTag);
|
||||
}
|
||||
|
||||
ClassObjectCreationOp createConstructorHook() const {
|
||||
if (delegated())
|
||||
return delegatedClassSpec()->createConstructorHook();
|
||||
return createConstructor_;
|
||||
}
|
||||
ClassObjectCreationOp createPrototypeHook() const {
|
||||
if (delegated())
|
||||
return delegatedClassSpec()->createPrototypeHook();
|
||||
return createPrototype_;
|
||||
}
|
||||
const JSFunctionSpec* constructorFunctions() const {
|
||||
if (delegated())
|
||||
return delegatedClassSpec()->constructorFunctions();
|
||||
return constructorFunctions_;
|
||||
}
|
||||
const JSPropertySpec* constructorProperties() const {
|
||||
if (delegated())
|
||||
return delegatedClassSpec()->constructorProperties();
|
||||
return constructorProperties_;
|
||||
}
|
||||
const JSFunctionSpec* prototypeFunctions() const {
|
||||
if (delegated())
|
||||
return delegatedClassSpec()->prototypeFunctions();
|
||||
return prototypeFunctions_;
|
||||
}
|
||||
const JSPropertySpec* prototypeProperties() const {
|
||||
if (delegated())
|
||||
return delegatedClassSpec()->prototypeProperties();
|
||||
return prototypeProperties_;
|
||||
}
|
||||
FinishClassInitOp finishInitHook() const {
|
||||
if (delegated())
|
||||
return delegatedClassSpec()->finishInitHook();
|
||||
return finishInit_;
|
||||
}
|
||||
};
|
||||
|
||||
struct ClassExtension
|
||||
|
@ -524,6 +573,11 @@ struct ClassExtension
|
|||
JSObjectMovedOp objectMovedOp;
|
||||
};
|
||||
|
||||
inline ClassObjectCreationOp DELEGATED_CLASSSPEC(const ClassSpec* spec) {
|
||||
return reinterpret_cast<ClassObjectCreationOp>(reinterpret_cast<uintptr_t>(spec) |
|
||||
ClassSpec::DelegatedTag);
|
||||
}
|
||||
|
||||
#define JS_NULL_CLASS_SPEC {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr,nullptr}
|
||||
#define JS_NULL_CLASS_EXT {nullptr,nullptr,false,nullptr,nullptr}
|
||||
|
||||
|
|
|
@ -153,8 +153,8 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JS
|
|||
// |createPrototype|, |prototypeFunctions|, and |prototypeProperties|
|
||||
// should all be null.
|
||||
RootedObject proto(cx);
|
||||
if (clasp->spec.createPrototype) {
|
||||
proto = clasp->spec.createPrototype(cx, key);
|
||||
if (clasp->spec.createPrototypeHook()) {
|
||||
proto = clasp->spec.createPrototypeHook()(cx, key);
|
||||
if (!proto)
|
||||
return false;
|
||||
|
||||
|
@ -162,7 +162,7 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JS
|
|||
}
|
||||
|
||||
// Create the constructor.
|
||||
RootedObject ctor(cx, clasp->spec.createConstructor(cx, key));
|
||||
RootedObject ctor(cx, clasp->spec.createConstructorHook()(cx, key));
|
||||
if (!ctor)
|
||||
return false;
|
||||
|
||||
|
@ -178,19 +178,19 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JS
|
|||
// 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 (const JSFunctionSpec* funs = clasp->spec.prototypeFunctions()) {
|
||||
if (!JS_DefineFunctions(cx, proto, funs, DontDefineLateProperties))
|
||||
return false;
|
||||
}
|
||||
if (const JSPropertySpec* props = clasp->spec.prototypeProperties) {
|
||||
if (const JSPropertySpec* props = clasp->spec.prototypeProperties()) {
|
||||
if (!JS_DefineProperties(cx, proto, props))
|
||||
return false;
|
||||
}
|
||||
if (const JSFunctionSpec* funs = clasp->spec.constructorFunctions) {
|
||||
if (const JSFunctionSpec* funs = clasp->spec.constructorFunctions()) {
|
||||
if (!JS_DefineFunctions(cx, ctor, funs, DontDefineLateProperties))
|
||||
return false;
|
||||
}
|
||||
if (const JSPropertySpec* props = clasp->spec.constructorProperties) {
|
||||
if (const JSPropertySpec* props = clasp->spec.constructorProperties()) {
|
||||
if (!JS_DefineProperties(cx, ctor, props))
|
||||
return false;
|
||||
}
|
||||
|
@ -201,7 +201,7 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JS
|
|||
return false;
|
||||
|
||||
// Call the post-initialization hook, if provided.
|
||||
if (clasp->spec.finishInit && !clasp->spec.finishInit(cx, ctor, proto))
|
||||
if (clasp->spec.finishInitHook() && !clasp->spec.finishInitHook()(cx, ctor, proto))
|
||||
return false;
|
||||
|
||||
if (clasp->spec.shouldDefineConstructor()) {
|
||||
|
@ -354,11 +354,11 @@ InitBareBuiltinCtor(JSContext* cx, Handle<GlobalObject*> global, JSProtoKey prot
|
|||
MOZ_ASSERT(cx->runtime()->isSelfHostingGlobal(global));
|
||||
const Class* clasp = ProtoKeyToClass(protoKey);
|
||||
RootedObject proto(cx);
|
||||
proto = clasp->spec.createPrototype(cx, protoKey);
|
||||
proto = clasp->spec.createPrototypeHook()(cx, protoKey);
|
||||
if (!proto)
|
||||
return false;
|
||||
|
||||
RootedObject ctor(cx, clasp->spec.createConstructor(cx, protoKey));
|
||||
RootedObject ctor(cx, clasp->spec.createConstructorHook()(cx, protoKey));
|
||||
if (!ctor)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -1833,8 +1833,8 @@ const Class TypedArrayObject::classes[Scalar::MaxTypedArrayViewType] = {
|
|||
// @@toStringTag) a custom class. The third requirement mandates that each
|
||||
// prototype's class have the relevant typed array's cached JSProtoKey in them.
|
||||
// Thus we need one class with cached prototype per kind of typed array, with a
|
||||
// dummy createConstructor to placate js::ClassSpec::defined().
|
||||
#define IMPL_TYPED_ARRAY_PROTO_CLASS(typedArray) \
|
||||
// delegated ClassSpec.
|
||||
#define IMPL_TYPED_ARRAY_PROTO_CLASS(typedArray, i) \
|
||||
{ \
|
||||
/*
|
||||
* Actually ({}).toString.call(Uint8Array.prototype) should throw, because
|
||||
|
@ -1859,8 +1859,8 @@ const Class TypedArrayObject::classes[Scalar::MaxTypedArrayViewType] = {
|
|||
nullptr, /* construct */ \
|
||||
nullptr, /* trace */ \
|
||||
{ \
|
||||
typedArray::createConstructor, \
|
||||
typedArray::createPrototype, \
|
||||
DELEGATED_CLASSSPEC(&TypedArrayObject::classes[i].spec), \
|
||||
nullptr, \
|
||||
nullptr, \
|
||||
nullptr, \
|
||||
nullptr, \
|
||||
|
@ -1871,15 +1871,15 @@ const Class TypedArrayObject::classes[Scalar::MaxTypedArrayViewType] = {
|
|||
}
|
||||
|
||||
const Class TypedArrayObject::protoClasses[Scalar::MaxTypedArrayViewType] = {
|
||||
IMPL_TYPED_ARRAY_PROTO_CLASS(Int8Array),
|
||||
IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8Array),
|
||||
IMPL_TYPED_ARRAY_PROTO_CLASS(Int16Array),
|
||||
IMPL_TYPED_ARRAY_PROTO_CLASS(Uint16Array),
|
||||
IMPL_TYPED_ARRAY_PROTO_CLASS(Int32Array),
|
||||
IMPL_TYPED_ARRAY_PROTO_CLASS(Uint32Array),
|
||||
IMPL_TYPED_ARRAY_PROTO_CLASS(Float32Array),
|
||||
IMPL_TYPED_ARRAY_PROTO_CLASS(Float64Array),
|
||||
IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8ClampedArray)
|
||||
IMPL_TYPED_ARRAY_PROTO_CLASS(Int8Array, 0),
|
||||
IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8Array, 1),
|
||||
IMPL_TYPED_ARRAY_PROTO_CLASS(Int16Array, 2),
|
||||
IMPL_TYPED_ARRAY_PROTO_CLASS(Uint16Array, 3),
|
||||
IMPL_TYPED_ARRAY_PROTO_CLASS(Int32Array, 4),
|
||||
IMPL_TYPED_ARRAY_PROTO_CLASS(Uint32Array, 5),
|
||||
IMPL_TYPED_ARRAY_PROTO_CLASS(Float32Array, 6),
|
||||
IMPL_TYPED_ARRAY_PROTO_CLASS(Float64Array, 7),
|
||||
IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8ClampedArray, 8)
|
||||
};
|
||||
|
||||
/* static */ bool
|
||||
|
|
|
@ -504,7 +504,7 @@ JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper,
|
|||
|
||||
// Scan through the functions. Indexed array properties are handled above.
|
||||
const JSFunctionSpec* fsMatch = nullptr;
|
||||
for (const JSFunctionSpec* fs = clasp->spec.prototypeFunctions; fs && fs->name; ++fs) {
|
||||
for (const JSFunctionSpec* fs = clasp->spec.prototypeFunctions(); fs && fs->name; ++fs) {
|
||||
if (PropertySpecNameEqualsId(fs->name, id)) {
|
||||
fsMatch = fs;
|
||||
break;
|
||||
|
@ -532,7 +532,7 @@ JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper,
|
|||
|
||||
// Scan through the properties.
|
||||
const JSPropertySpec* psMatch = nullptr;
|
||||
for (const JSPropertySpec* ps = clasp->spec.prototypeProperties; ps && ps->name; ++ps) {
|
||||
for (const JSPropertySpec* ps = clasp->spec.prototypeProperties(); ps && ps->name; ++ps) {
|
||||
if (PropertySpecNameEqualsId(ps->name, id)) {
|
||||
psMatch = ps;
|
||||
break;
|
||||
|
@ -765,14 +765,14 @@ JSXrayTraits::enumerateNames(JSContext* cx, HandleObject wrapper, unsigned flags
|
|||
MOZ_ASSERT(clasp->spec.defined());
|
||||
|
||||
// Convert the method and property names to jsids and pass them to the caller.
|
||||
for (const JSFunctionSpec* fs = clasp->spec.prototypeFunctions; fs && fs->name; ++fs) {
|
||||
for (const JSFunctionSpec* fs = clasp->spec.prototypeFunctions(); fs && fs->name; ++fs) {
|
||||
jsid id;
|
||||
if (!PropertySpecNameToPermanentId(cx, fs->name, &id))
|
||||
return false;
|
||||
if (!MaybeAppend(id, flags, props))
|
||||
return false;
|
||||
}
|
||||
for (const JSPropertySpec* ps = clasp->spec.prototypeProperties; ps && ps->name; ++ps) {
|
||||
for (const JSPropertySpec* ps = clasp->spec.prototypeProperties(); ps && ps->name; ++ps) {
|
||||
jsid id;
|
||||
if (!PropertySpecNameToPermanentId(cx, ps->name, &id))
|
||||
return false;
|
||||
|
|
Загрузка…
Ссылка в новой задаче