Bug 1260984 (part 3) - Separate js::ClassSpec from js::Class. r=jorendorff.

js::ClassSpec is often all null. When it's not all null, it's often duplicated
among classes. By pulling it out into its own struct, and using a (possibly
null) pointer in js::Class, we can save 138 KiB per process on 64-bit, and half
that on 32-bit.

--HG--
extra : rebase_source : 852ac6770ace46958d018107e78c5c44ebd6528a
This commit is contained in:
Nicholas Nethercote 2016-04-01 10:59:54 +11:00
Родитель 394034a83e
Коммит 3e563eab78
15 изменённых файлов: 282 добавлений и 211 удалений

Просмотреть файл

@ -624,7 +624,7 @@ inline ClassObjectCreationOp DELEGATED_CLASSSPEC(const ClassSpec* spec) {
return reinterpret_cast<ClassObjectCreationOp>(const_cast<ClassSpec*>(spec));
}
#define JS_NULL_CLASS_SPEC {nullptr,nullptr,nullptr,nullptr,nullptr,nullptr}
#define JS_NULL_CLASS_SPEC nullptr
#define JS_NULL_CLASS_EXT {false,nullptr}
struct ObjectOps
@ -654,7 +654,7 @@ typedef void (*JSClassInternal)();
struct JSClass {
JS_CLASS_MEMBERS(JSFinalizeOp);
void* reserved[12];
void* reserved[5];
};
#define JSCLASS_HAS_PRIVATE (1<<0) // objects have private slot
@ -756,7 +756,7 @@ namespace js {
struct Class
{
JS_CLASS_MEMBERS(FinalizeOp);
ClassSpec spec;
const ClassSpec* spec;
ClassExtension ext;
const ObjectOps* ops;
@ -804,6 +804,26 @@ struct Class
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; }
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; }
const JSPropertySpec* specConstructorProperties()
const { return spec ? spec->constructorProperties() : nullptr; }
const JSFunctionSpec* specPrototypeFunctions()
const { return spec ? spec->prototypeFunctions() : nullptr; }
const JSPropertySpec* specPrototypeProperties()
const { return spec ? spec->prototypeProperties() : nullptr; }
FinishClassInitOp specFinishInitHook()
const { return spec ? spec->finishInitHook() : nullptr; }
LookupPropertyOp getOpsLookupProperty() const { return ops ? ops->lookupProperty : nullptr; }
DefinePropertyOp getOpsDefineProperty() const { return ops ? ops->defineProperty : nullptr; }
HasPropertyOp getOpsHasProperty() const { return ops ? ops->hasProperty : nullptr; }

Просмотреть файл

@ -1211,6 +1211,16 @@ FinishObjectClassInit(JSContext* cx, JS::HandleObject ctor, JS::HandleObject pro
return true;
}
static const ClassSpec PlainObjectClassSpec = {
CreateObjectConstructor,
CreateObjectPrototype,
object_static_methods,
nullptr,
object_methods,
object_properties,
FinishObjectClassInit
};
const Class PlainObject::class_ = {
js_Object_str,
JSCLASS_HAS_CACHED_PROTO(JSProto_Object),
@ -1226,15 +1236,7 @@ const Class PlainObject::class_ = {
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
{
CreateObjectConstructor,
CreateObjectPrototype,
object_static_methods,
nullptr,
object_methods,
object_properties,
FinishObjectClassInit
}
&PlainObjectClassSpec
};
const Class* const js::ObjectClassPtr = &PlainObject::class_;

Просмотреть файл

@ -397,6 +397,14 @@ CreatePromisePrototype(JSContext* cx, JSProtoKey key)
return cx->global()->createBlankPrototype(cx, &PromiseObject::protoClass_);
}
static const ClassSpec PromiseObjectClassSpec = {
GenericCreateConstructor<PromiseConstructor, 1, gc::AllocKind::FUNCTION>,
CreatePromisePrototype,
promise_static_methods,
promise_static_properties,
promise_methods
};
const Class PromiseObject::class_ = {
"Promise",
JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Promise) |
@ -413,13 +421,18 @@ const Class PromiseObject::class_ = {
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
{
GenericCreateConstructor<PromiseConstructor, 1, gc::AllocKind::FUNCTION>,
CreatePromisePrototype,
promise_static_methods,
promise_static_properties,
promise_methods
}
&PromiseObjectClassSpec
};
static const ClassSpec PromiseObjectProtoClassSpec = {
DELEGATED_CLASSSPEC(PromiseObject::class_.spec),
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
ClassSpec::IsDelegated
};
const Class PromiseObject::protoClass_ = {
@ -437,14 +450,5 @@ const Class PromiseObject::protoClass_ = {
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
{
DELEGATED_CLASSSPEC(&PromiseObject::class_.spec),
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
ClassSpec::IsDelegated
}
&PromiseObjectProtoClassSpec
};

Просмотреть файл

@ -3262,6 +3262,16 @@ array_proto_finish(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto)
return DefineProperty(cx, proto, id, value, nullptr, nullptr, JSPROP_READONLY);
}
static const ClassSpec ArrayObjectClassSpec = {
GenericCreateConstructor<ArrayConstructor, 1, AllocKind::FUNCTION, &jit::JitInfo_Array>,
CreateArrayPrototype,
array_static_methods,
nullptr,
array_methods,
nullptr,
array_proto_finish
};
const Class ArrayObject::class_ = {
"Array",
JSCLASS_HAS_CACHED_PROTO(JSProto_Array) | JSCLASS_DELAY_METADATA_CALLBACK,
@ -3277,15 +3287,7 @@ const Class ArrayObject::class_ = {
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
{
GenericCreateConstructor<ArrayConstructor, 1, AllocKind::FUNCTION, &jit::JitInfo_Array>,
CreateArrayPrototype,
array_static_methods,
nullptr,
array_methods,
nullptr,
array_proto_finish
}
&ArrayObjectClassSpec
};
/*

Просмотреть файл

@ -3272,6 +3272,16 @@ FinishDateClassInit(JSContext* cx, HandleObject ctor, HandleObject proto)
nullptr, nullptr, 0);
}
static const ClassSpec DateObjectClassSpec = {
GenericCreateConstructor<DateConstructor, 7, gc::AllocKind::FUNCTION>,
CreateDatePrototype,
date_static_methods,
nullptr,
date_methods,
nullptr,
FinishDateClassInit
};
const Class DateObject::class_ = {
js_Date_str,
JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) |
@ -3288,15 +3298,18 @@ const Class DateObject::class_ = {
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
{
GenericCreateConstructor<DateConstructor, 7, gc::AllocKind::FUNCTION>,
CreateDatePrototype,
date_static_methods,
nullptr,
date_methods,
nullptr,
FinishDateClassInit
}
&DateObjectClassSpec
};
static const ClassSpec DateObjectProtoClassSpec = {
DELEGATED_CLASSSPEC(DateObject::class_.spec),
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
ClassSpec::IsDelegated
};
const Class DateObject::protoClass_ = {
@ -3314,16 +3327,7 @@ const Class DateObject::protoClass_ = {
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
{
DELEGATED_CLASSSPEC(&DateObject::class_.spec),
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
ClassSpec::IsDelegated
}
&DateObjectProtoClassSpec
};
JSObject*

Просмотреть файл

@ -65,7 +65,7 @@ static const JSFunctionSpec exception_methods[] = {
JS_FS_END
};
#define IMPLEMENT_ERROR_SUBCLASS_EXTRA_FLAGS(name, extraClassSpecFlags) \
#define IMPLEMENT_ERROR_CLASS(name, classSpecPtr) \
{ \
js_Error_str, /* yes, really */ \
JSCLASS_HAS_CACHED_PROTO(JSProto_##name) | \
@ -82,60 +82,59 @@ static const JSFunctionSpec exception_methods[] = {
nullptr, /* hasInstance */ \
nullptr, /* construct */ \
nullptr, /* trace */ \
{ \
ErrorObject::createConstructor, \
ErrorObject::createProto, \
nullptr, \
nullptr, \
exception_methods, \
exception_properties, \
nullptr, \
JSProto_Error | extraClassSpecFlags \
} \
classSpecPtr \
}
#define IMPLEMENT_ERROR_SUBCLASS(name) \
IMPLEMENT_ERROR_SUBCLASS_EXTRA_FLAGS(name, 0)
const ClassSpec
ErrorObject::errorClassSpec_ = {
ErrorObject::createConstructor,
ErrorObject::createProto,
nullptr,
nullptr,
exception_methods,
exception_properties,
nullptr,
0
};
const ClassSpec
ErrorObject::subErrorClassSpec_ = {
ErrorObject::createConstructor,
ErrorObject::createProto,
nullptr,
nullptr,
exception_methods,
exception_properties,
nullptr,
JSProto_Error
};
const ClassSpec
ErrorObject::debuggeeWouldRunClassSpec_ = {
ErrorObject::createConstructor,
ErrorObject::createProto,
nullptr,
nullptr,
exception_methods,
exception_properties,
nullptr,
JSProto_Error | ClassSpec::DontDefineConstructor
};
const Class
ErrorObject::classes[JSEXN_LIMIT] = {
{
js_Error_str,
JSCLASS_HAS_CACHED_PROTO(JSProto_Error) |
JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS),
nullptr, /* addProperty */
nullptr, /* delProperty */
nullptr, /* getProperty */
nullptr, /* setProperty */
nullptr, /* enumerate */
nullptr, /* resolve */
nullptr, /* mayResolve */
exn_finalize,
nullptr, /* call */
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
{
ErrorObject::createConstructor,
ErrorObject::createProto,
nullptr,
nullptr,
exception_methods,
exception_properties,
nullptr
}
},
IMPLEMENT_ERROR_SUBCLASS(InternalError),
IMPLEMENT_ERROR_SUBCLASS(EvalError),
IMPLEMENT_ERROR_SUBCLASS(RangeError),
IMPLEMENT_ERROR_SUBCLASS(ReferenceError),
IMPLEMENT_ERROR_SUBCLASS(SyntaxError),
IMPLEMENT_ERROR_SUBCLASS(TypeError),
IMPLEMENT_ERROR_SUBCLASS(URIError),
IMPLEMENT_ERROR_CLASS(Error, &ErrorObject::errorClassSpec_),
IMPLEMENT_ERROR_CLASS(InternalError, &ErrorObject::subErrorClassSpec_),
IMPLEMENT_ERROR_CLASS(EvalError, &ErrorObject::subErrorClassSpec_),
IMPLEMENT_ERROR_CLASS(RangeError, &ErrorObject::subErrorClassSpec_),
IMPLEMENT_ERROR_CLASS(ReferenceError, &ErrorObject::subErrorClassSpec_),
IMPLEMENT_ERROR_CLASS(SyntaxError, &ErrorObject::subErrorClassSpec_),
IMPLEMENT_ERROR_CLASS(TypeError, &ErrorObject::subErrorClassSpec_),
IMPLEMENT_ERROR_CLASS(URIError, &ErrorObject::subErrorClassSpec_),
// DebuggeeWouldRun is a subclass of Error but is accessible via the
// Debugger constructor, not the global.
IMPLEMENT_ERROR_SUBCLASS_EXTRA_FLAGS(DebuggeeWouldRun, ClassSpec::DontDefineConstructor),
IMPLEMENT_ERROR_CLASS(DebuggeeWouldRun, &ErrorObject::debuggeeWouldRunClassSpec_)
};
JSErrorReport*

Просмотреть файл

@ -643,7 +643,7 @@ inline bool
StandardClassIsDependent(JSProtoKey key)
{
const Class* clasp = ProtoKeyToClass(key);
return clasp && clasp->spec.defined() && clasp->spec.dependent();
return clasp && clasp->specDefined() && clasp->specDependent();
}
// Returns the key for the class inherited by a given standard class (that
@ -662,7 +662,7 @@ ParentKeyForStandardClass(JSProtoKey key)
// If we're dependent, return the key of the class we depend on.
if (StandardClassIsDependent(key))
return ProtoKeyToClass(key)->spec.parentKey();
return ProtoKeyToClass(key)->specParentKey();
// Otherwise, we inherit [Object].
return JSProto_Object;

Просмотреть файл

@ -834,6 +834,15 @@ CreateFunctionPrototype(JSContext* cx, JSProtoKey key)
return functionProto;
}
static const ClassSpec JSFunctionClassSpec = {
CreateFunctionConstructor,
CreateFunctionPrototype,
nullptr,
nullptr,
function_methods,
function_properties
};
const Class JSFunction::class_ = {
js_Function_str,
JSCLASS_HAS_CACHED_PROTO(JSProto_Function),
@ -849,14 +858,7 @@ const Class JSFunction::class_ = {
fun_hasInstance,
nullptr, /* construct */
fun_trace,
{
CreateFunctionConstructor,
CreateFunctionPrototype,
nullptr,
nullptr,
function_methods,
function_properties
}
&JSFunctionClassSpec
};
const Class* const js::FunctionClassPtr = &JSFunction::class_;

Просмотреть файл

@ -41,6 +41,10 @@ class ErrorObject : public NativeObject
static bool checkAndUnwrapThis(JSContext* cx, CallArgs& args, const char* fnName,
MutableHandle<ErrorObject*> error);
static const ClassSpec errorClassSpec_;
static const ClassSpec subErrorClassSpec_;
static const ClassSpec debuggeeWouldRunClassSpec_;
protected:
static const uint32_t EXNTYPE_SLOT = 0;
static const uint32_t STACK_SLOT = EXNTYPE_SLOT + 1;

Просмотреть файл

@ -162,7 +162,7 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JS
// GlobalObject::initStandardClasses that want to just carpet-bomb-call
// ensureConstructor with every JSProtoKey. So it's easier to just handle
// it here.
bool haveSpec = clasp && clasp->spec.defined();
bool haveSpec = clasp && clasp->specDefined();
if (!init && !haveSpec)
return true;
@ -195,8 +195,8 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JS
// |createPrototype|, |prototypeFunctions|, and |prototypeProperties|
// should all be null.
RootedObject proto(cx);
if (clasp->spec.createPrototypeHook()) {
proto = clasp->spec.createPrototypeHook()(cx, key);
if (ClassObjectCreationOp createPrototype = clasp->specCreatePrototypeHook()) {
proto = createPrototype(cx, key);
if (!proto)
return false;
@ -211,12 +211,12 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JS
}
// Create the constructor.
RootedObject ctor(cx, clasp->spec.createConstructorHook()(cx, key));
RootedObject ctor(cx, clasp->specCreateConstructorHook()(cx, key));
if (!ctor)
return false;
RootedId id(cx, NameToId(ClassName(key, cx)));
if (clasp->spec.shouldDefineConstructor()) {
if (clasp->specShouldDefineConstructor()) {
if (!global->addDataProperty(cx, id, constructorPropertySlot(key), 0))
return false;
}
@ -229,19 +229,19 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JS
// operating on the self-hosting global, in which case we don't want any
// functions and properties on the builtins and their prototypes.
if (!StandardClassIsDependent(key) && !cx->runtime()->isSelfHostingGlobal(global)) {
if (const JSFunctionSpec* funs = clasp->spec.prototypeFunctions()) {
if (const JSFunctionSpec* funs = clasp->specPrototypeFunctions()) {
if (!JS_DefineFunctions(cx, proto, funs))
return false;
}
if (const JSPropertySpec* props = clasp->spec.prototypeProperties()) {
if (const JSPropertySpec* props = clasp->specPrototypeProperties()) {
if (!JS_DefineProperties(cx, proto, props))
return false;
}
if (const JSFunctionSpec* funs = clasp->spec.constructorFunctions()) {
if (const JSFunctionSpec* funs = clasp->specConstructorFunctions()) {
if (!JS_DefineFunctions(cx, ctor, funs))
return false;
}
if (const JSPropertySpec* props = clasp->spec.constructorProperties()) {
if (const JSPropertySpec* props = clasp->specConstructorProperties()) {
if (!JS_DefineProperties(cx, ctor, props))
return false;
}
@ -252,10 +252,12 @@ GlobalObject::resolveConstructor(JSContext* cx, Handle<GlobalObject*> global, JS
return false;
// Call the post-initialization hook, if provided.
if (clasp->spec.finishInitHook() && !clasp->spec.finishInitHook()(cx, ctor, proto))
return false;
if (FinishClassInitOp finishInit = clasp->specFinishInitHook()) {
if (!finishInit(cx, ctor, proto))
return false;
}
if (clasp->spec.shouldDefineConstructor()) {
if (clasp->specShouldDefineConstructor()) {
// Stash type information, so that what we do here is equivalent to
// initBuiltinConstructor.
AddTypePropertyId(cx, global, id, ObjectValue(*ctor));
@ -416,11 +418,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.createPrototypeHook()(cx, protoKey);
proto = clasp->specCreatePrototypeHook()(cx, protoKey);
if (!proto)
return false;
RootedObject ctor(cx, clasp->spec.createConstructorHook()(cx, protoKey));
RootedObject ctor(cx, clasp->specCreateConstructorHook()(cx, protoKey));
if (!ctor)
return false;

Просмотреть файл

@ -185,6 +185,15 @@ RegExpObject::trace(JSTracer* trc, JSObject* obj)
}
}
static const ClassSpec RegExpObjectClassSpec = {
GenericCreateConstructor<js::regexp_construct, 2, gc::AllocKind::FUNCTION>,
CreateRegExpPrototype,
nullptr,
js::regexp_static_props,
js::regexp_methods,
js::regexp_properties
};
const Class RegExpObject::class_ = {
js_RegExp_str,
JSCLASS_HAS_PRIVATE |
@ -202,16 +211,7 @@ const Class RegExpObject::class_ = {
nullptr, /* hasInstance */
nullptr, /* construct */
RegExpObject::trace,
// ClassSpec
{
GenericCreateConstructor<js::regexp_construct, 2, gc::AllocKind::FUNCTION>,
CreateRegExpPrototype,
nullptr,
js::regexp_static_props,
js::regexp_methods,
js::regexp_properties
}
&RegExpObjectClassSpec
};
RegExpObject*

Просмотреть файл

@ -18,6 +18,8 @@ class SavedFrame : public NativeObject {
friend class SavedStacks;
friend struct ::JSStructuredCloneReader;
static const ClassSpec classSpec_;
public:
static const Class class_;
static const JSPropertySpec protoAccessors[];

Просмотреть файл

@ -289,6 +289,17 @@ SavedFrame::finishSavedFrameInit(JSContext* cx, HandleObject ctor, HandleObject
return FreezeObject(cx, proto);
}
const ClassSpec SavedFrame::classSpec_ = {
GenericCreateConstructor<SavedFrame::construct, 0, gc::AllocKind::FUNCTION>,
GenericCreatePrototype,
SavedFrame::staticFunctions,
nullptr,
SavedFrame::protoFunctions,
SavedFrame::protoAccessors,
SavedFrame::finishSavedFrameInit,
ClassSpec::DontDefineConstructor
};
/* static */ const Class SavedFrame::class_ = {
"SavedFrame",
JSCLASS_HAS_PRIVATE |
@ -307,18 +318,7 @@ SavedFrame::finishSavedFrameInit(JSContext* cx, HandleObject ctor, HandleObject
nullptr, // hasInstance
nullptr, // construct
nullptr, // trace
// ClassSpec
{
GenericCreateConstructor<SavedFrame::construct, 0, gc::AllocKind::FUNCTION>,
GenericCreatePrototype,
SavedFrame::staticFunctions,
nullptr,
SavedFrame::protoFunctions,
SavedFrame::protoAccessors,
SavedFrame::finishSavedFrameInit,
ClassSpec::DontDefineConstructor
}
&SavedFrame::classSpec_
};
/* static */ const JSFunctionSpec

Просмотреть файл

@ -861,6 +861,18 @@ TypedArrayObject::staticFunctions[] = {
JS_FS_END
};
static const ClassSpec
TypedArrayObjectSharedTypedArrayPrototypeClassSpec = {
GenericCreateConstructor<TypedArrayConstructor, 3, gc::AllocKind::FUNCTION>,
GenericCreatePrototype,
TypedArrayObject::staticFunctions,
nullptr,
TypedArrayObject::protoFunctions,
TypedArrayObject::protoAccessors,
nullptr,
ClassSpec::DontDefineConstructor
};
/* static */ const Class
TypedArrayObject::sharedTypedArrayPrototypeClass = {
// Actually ({}).toString.call(%TypedArray%.prototype) should throw,
@ -883,16 +895,7 @@ TypedArrayObject::sharedTypedArrayPrototypeClass = {
nullptr, /* hasInstance */
nullptr, /* construct */
nullptr, /* trace */
{
GenericCreateConstructor<TypedArrayConstructor, 3, gc::AllocKind::FUNCTION>,
GenericCreatePrototype,
TypedArrayObject::staticFunctions,
nullptr,
TypedArrayObject::protoFunctions,
TypedArrayObject::protoAccessors,
nullptr,
ClassSpec::DontDefineConstructor
}
&TypedArrayObjectSharedTypedArrayPrototypeClassSpec
};
template<typename T>
@ -1905,24 +1908,36 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Uint32, uint32_t, uint32_t)
IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float32, float, float)
IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double)
#define TYPED_ARRAY_CLASS_SPEC(_typedArray) \
#define IMPL_TYPED_ARRAY_CLASS_SPEC(_type) \
{ \
_typedArray::createConstructor, \
_typedArray::createPrototype, \
_type##Array::createConstructor, \
_type##Array::createPrototype, \
nullptr, \
nullptr, \
nullptr, \
nullptr, \
_typedArray::finishClassInit, \
_type##Array::finishClassInit, \
JSProto_TypedArray \
}
#define IMPL_TYPED_ARRAY_CLASS(_typedArray) \
static const ClassSpec TypedArrayObjectClassSpecs[Scalar::MaxTypedArrayViewType] = {
IMPL_TYPED_ARRAY_CLASS_SPEC(Int8),
IMPL_TYPED_ARRAY_CLASS_SPEC(Uint8),
IMPL_TYPED_ARRAY_CLASS_SPEC(Int16),
IMPL_TYPED_ARRAY_CLASS_SPEC(Uint16),
IMPL_TYPED_ARRAY_CLASS_SPEC(Int32),
IMPL_TYPED_ARRAY_CLASS_SPEC(Uint32),
IMPL_TYPED_ARRAY_CLASS_SPEC(Float32),
IMPL_TYPED_ARRAY_CLASS_SPEC(Float64),
IMPL_TYPED_ARRAY_CLASS_SPEC(Uint8Clamped)
};
#define IMPL_TYPED_ARRAY_CLASS(_type) \
{ \
#_typedArray, \
#_type "Array", \
JSCLASS_HAS_RESERVED_SLOTS(TypedArrayObject::RESERVED_SLOTS) | \
JSCLASS_HAS_PRIVATE | \
JSCLASS_HAS_CACHED_PROTO(JSProto_##_typedArray) | \
JSCLASS_HAS_CACHED_PROTO(JSProto_##_type##Array) | \
JSCLASS_DELAY_METADATA_CALLBACK, \
nullptr, /* addProperty */ \
nullptr, /* delProperty */ \
@ -1936,19 +1951,43 @@ IMPL_TYPED_ARRAY_COMBINED_UNWRAPPERS(Float64, double, double)
nullptr, /* hasInstance */ \
nullptr, /* construct */ \
TypedArrayObject::trace, /* trace */ \
TYPED_ARRAY_CLASS_SPEC(_typedArray) \
&TypedArrayObjectClassSpecs[Scalar::Type::_type] \
}
const Class TypedArrayObject::classes[Scalar::MaxTypedArrayViewType] = {
IMPL_TYPED_ARRAY_CLASS(Int8Array),
IMPL_TYPED_ARRAY_CLASS(Uint8Array),
IMPL_TYPED_ARRAY_CLASS(Int16Array),
IMPL_TYPED_ARRAY_CLASS(Uint16Array),
IMPL_TYPED_ARRAY_CLASS(Int32Array),
IMPL_TYPED_ARRAY_CLASS(Uint32Array),
IMPL_TYPED_ARRAY_CLASS(Float32Array),
IMPL_TYPED_ARRAY_CLASS(Float64Array),
IMPL_TYPED_ARRAY_CLASS(Uint8ClampedArray)
IMPL_TYPED_ARRAY_CLASS(Int8),
IMPL_TYPED_ARRAY_CLASS(Uint8),
IMPL_TYPED_ARRAY_CLASS(Int16),
IMPL_TYPED_ARRAY_CLASS(Uint16),
IMPL_TYPED_ARRAY_CLASS(Int32),
IMPL_TYPED_ARRAY_CLASS(Uint32),
IMPL_TYPED_ARRAY_CLASS(Float32),
IMPL_TYPED_ARRAY_CLASS(Float64),
IMPL_TYPED_ARRAY_CLASS(Uint8Clamped)
};
#define IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(_type) \
{ \
DELEGATED_CLASSSPEC(TypedArrayObject::classes[Scalar::Type::_type].spec), \
nullptr, \
nullptr, \
nullptr, \
nullptr, \
nullptr, \
nullptr, \
JSProto_TypedArray | ClassSpec::IsDelegated \
}
static const ClassSpec TypedArrayObjectProtoClassSpecs[Scalar::MaxTypedArrayViewType] = {
IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Int8),
IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint8),
IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Int16),
IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint16),
IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Int32),
IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint32),
IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Float32),
IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Float64),
IMPL_TYPED_ARRAY_PROTO_CLASS_SPEC(Uint8Clamped)
};
// The various typed array prototypes are supposed to 1) be normal objects,
@ -1958,7 +1997,7 @@ const Class TypedArrayObject::classes[Scalar::MaxTypedArrayViewType] = {
// 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
// delegated ClassSpec.
#define IMPL_TYPED_ARRAY_PROTO_CLASS(typedArray, i) \
#define IMPL_TYPED_ARRAY_PROTO_CLASS(_type) \
{ \
/*
* Actually ({}).toString.call(Uint8Array.prototype) should throw, because
@ -1967,8 +2006,8 @@ const Class TypedArrayObject::classes[Scalar::MaxTypedArrayViewType] = {
* above), but it's what we've always done, so keep doing it till we
* implement @@toStringTag or ES6 changes.
*/ \
#typedArray "Prototype", \
JSCLASS_HAS_CACHED_PROTO(JSProto_##typedArray), \
#_type "ArrayPrototype", \
JSCLASS_HAS_CACHED_PROTO(JSProto_##_type##Array), \
nullptr, /* addProperty */ \
nullptr, /* delProperty */ \
nullptr, /* getProperty */ \
@ -1981,28 +2020,19 @@ const Class TypedArrayObject::classes[Scalar::MaxTypedArrayViewType] = {
nullptr, /* hasInstance */ \
nullptr, /* construct */ \
nullptr, /* trace */ \
{ \
DELEGATED_CLASSSPEC(&TypedArrayObject::classes[i].spec), \
nullptr, \
nullptr, \
nullptr, \
nullptr, \
nullptr, \
nullptr, \
JSProto_TypedArray | ClassSpec::IsDelegated \
} \
&TypedArrayObjectProtoClassSpecs[Scalar::Type::_type] \
}
const Class TypedArrayObject::protoClasses[Scalar::MaxTypedArrayViewType] = {
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)
IMPL_TYPED_ARRAY_PROTO_CLASS(Int8),
IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8),
IMPL_TYPED_ARRAY_PROTO_CLASS(Int16),
IMPL_TYPED_ARRAY_PROTO_CLASS(Uint16),
IMPL_TYPED_ARRAY_PROTO_CLASS(Int32),
IMPL_TYPED_ARRAY_PROTO_CLASS(Uint32),
IMPL_TYPED_ARRAY_PROTO_CLASS(Float32),
IMPL_TYPED_ARRAY_PROTO_CLASS(Float64),
IMPL_TYPED_ARRAY_PROTO_CLASS(Uint8Clamped)
};
/* static */ bool

Просмотреть файл

@ -573,11 +573,11 @@ JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper,
if (ShouldResolveStaticProperties(standardConstructor)) {
const js::Class* clasp = js::ProtoKeyToClass(standardConstructor);
MOZ_ASSERT(clasp->spec.defined());
MOZ_ASSERT(clasp->specDefined());
if (!TryResolvePropertyFromSpecs(cx, id, holder,
clasp->spec.constructorFunctions(),
clasp->spec.constructorProperties(), desc)) {
clasp->specConstructorFunctions(),
clasp->specConstructorProperties(), desc)) {
return false;
}
@ -656,13 +656,13 @@ 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);
MOZ_ASSERT(clasp->spec.defined());
MOZ_ASSERT(clasp->specDefined());
// Indexed array properties are handled above, so we can just work with the
// class spec here.
if (!TryResolvePropertyFromSpecs(cx, id, holder,
clasp->spec.prototypeFunctions(),
clasp->spec.prototypeProperties(),
clasp->specPrototypeFunctions(),
clasp->specPrototypeProperties(),
desc)) {
return false;
}
@ -864,11 +864,11 @@ JSXrayTraits::enumerateNames(JSContext* cx, HandleObject wrapper, unsigned flags
if (ShouldResolveStaticProperties(standardConstructor)) {
const js::Class* clasp = js::ProtoKeyToClass(standardConstructor);
MOZ_ASSERT(clasp->spec.defined());
MOZ_ASSERT(clasp->specDefined());
if (!AppendNamesFromFunctionAndPropertySpecs(
cx, clasp->spec.constructorFunctions(),
clasp->spec.constructorProperties(), flags, props)) {
cx, clasp->specConstructorFunctions(),
clasp->specConstructorProperties(), flags, props)) {
return false;
}
}
@ -905,11 +905,11 @@ 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(clasp->spec.defined());
MOZ_ASSERT(clasp->specDefined());
return AppendNamesFromFunctionAndPropertySpecs(
cx, clasp->spec.prototypeFunctions(),
clasp->spec.prototypeProperties(), flags, props);
cx, clasp->specPrototypeFunctions(),
clasp->specPrototypeProperties(), flags, props);
}
bool