diff --git a/devtools/shared/heapsnapshot/tests/gtest/DevTools.h b/devtools/shared/heapsnapshot/tests/gtest/DevTools.h index 1be1fdfd7d0a..dc6a43f48fb7 100644 --- a/devtools/shared/heapsnapshot/tests/gtest/DevTools.h +++ b/devtools/shared/heapsnapshot/tests/gtest/DevTools.h @@ -98,13 +98,16 @@ struct DevTools : public ::testing::Test { } static const JSClass* getGlobalClass() { - static const JSClass globalClass = { - "global", JSCLASS_GLOBAL_FLAGS, + static const JSClassOps globalClassOps = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook }; + static const JSClass globalClass = { + "global", JSCLASS_GLOBAL_FLAGS, + &globalClassOps + }; return &globalClass; } diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index 739547f7b7e8..0d30971425a4 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -1806,6 +1806,21 @@ NativePropertyHooks sEmptyNativePropertyHooks = { nullptr }; +const js::ClassOps sBoringInterfaceObjectClassClassOps = { + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + nullptr, /* finalize */ + ThrowingConstructor, /* call */ + InterfaceHasInstance, /* hasInstance */ + ThrowingConstructor, /* construct */ + nullptr, /* trace */ +}; + const js::ObjectOps sInterfaceObjectClassObjectOps = { nullptr, /* lookupProperty */ nullptr, /* defineProperty */ diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index 197debcfd8e4..19900a77ca51 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -2508,6 +2508,8 @@ XrayGetNativeProto(JSContext* cx, JS::Handle obj, extern NativePropertyHooks sEmptyNativePropertyHooks; +extern const js::ClassOps sBoringInterfaceObjectClassClassOps; + extern const js::ObjectOps sInterfaceObjectClassObjectOps; // We use one constructor JSNative to represent all DOM interface objects (so @@ -2540,7 +2542,7 @@ inline bool HasConstructor(JSObject* obj) { return JS_IsNativeFunction(obj, Constructor) || - js::GetObjectClass(obj)->construct; + js::GetObjectClass(obj)->getConstruct(); } #endif diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 867b3a1b4ca2..73fce575aeeb 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -440,6 +440,21 @@ class CGDOMJSClass(CGThing): return fill( """ + static const js::ClassOps sClassOps = { + ${addProperty}, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + ${enumerate}, /* enumerate */ + ${resolve}, /* resolve */ + ${mayResolve}, /* mayResolve */ + ${finalize}, /* finalize */ + ${call}, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + ${trace}, /* trace */ + }; + static const js::ClassExtension sClassExtension = { nullptr, /* weakmapKeyDelegateOp */ ${objectMoved} /* objectMovedOp */ @@ -448,18 +463,7 @@ class CGDOMJSClass(CGThing): static const DOMJSClass sClass = { { "${name}", ${flags}, - ${addProperty}, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - ${enumerate}, /* enumerate */ - ${resolve}, /* resolve */ - ${mayResolve}, /* mayResolve */ - ${finalize}, /* finalize */ - ${call}, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - ${trace}, /* trace */ + &sClassOps, JS_NULL_CLASS_SPEC, &sClassExtension, JS_NULL_OBJECT_OPS @@ -594,18 +598,7 @@ class CGPrototypeJSClass(CGThing): { "${name}Prototype", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}), - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - nullptr, /* trace */ + JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS @@ -684,24 +677,39 @@ class CGInterfaceObjectJSClass(CGThing): len(self.descriptor.interface.namedConstructors)) (protoGetter, _) = InterfaceObjectProtoGetter(self.descriptor) - return fill( + if ctorname == "ThrowingConstructor" and hasinstance == "InterfaceHasInstance": + ret = "" + classOpsPtr = "&sBoringInterfaceObjectClassClassOps" + else: + ret = fill( + """ + static const js::ClassOps sInterfaceObjectClassOps = { + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + nullptr, /* finalize */ + ${ctorname}, /* call */ + ${hasInstance}, /* hasInstance */ + ${ctorname}, /* construct */ + nullptr, /* trace */ + }; + + """, + ctorname=ctorname, + hasInstance=hasinstance) + classOpsPtr = "&sInterfaceObjectClassOps" + + ret = ret + fill( """ static const DOMIfaceAndProtoJSClass sInterfaceObjectClass = { { "Function", JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}), - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - ${ctorname}, /* call */ - ${hasInstance}, /* hasInstance */ - ${ctorname}, /* construct */ - nullptr, /* trace */ + ${classOpsPtr}, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, &sInterfaceObjectClassObjectOps @@ -717,12 +725,13 @@ class CGInterfaceObjectJSClass(CGThing): slotCount=slotCount, ctorname=ctorname, hasInstance=hasinstance, + classOpsPtr=classOpsPtr, hooks=NativePropertyHooks(self.descriptor), name=self.descriptor.interface.identifier.name, prototypeID=prototypeID, depth=depth, protoGetter=protoGetter) - + return ret class CGList(CGThing): """ diff --git a/dom/bindings/SimpleGlobalObject.cpp b/dom/bindings/SimpleGlobalObject.cpp index 7be678f45d52..9019ade2f128 100644 --- a/dom/bindings/SimpleGlobalObject.cpp +++ b/dom/bindings/SimpleGlobalObject.cpp @@ -70,14 +70,7 @@ SimpleGlobal_moved(JSObject *obj, const JSObject *old) globalObject->UpdateWrapper(obj, old); } -static const js::ClassExtension SimpleGlobalClassExtension = { - nullptr, - SimpleGlobal_moved -}; - -const js::Class SimpleGlobalClass = { - "", - JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS, +static const js::ClassOps SimpleGlobalClassOps = { nullptr, nullptr, nullptr, @@ -90,6 +83,17 @@ const js::Class SimpleGlobalClass = { nullptr, nullptr, JS_GlobalObjectTraceHook, +}; + +static const js::ClassExtension SimpleGlobalClassExtension = { + nullptr, + SimpleGlobal_moved +}; + +const js::Class SimpleGlobalClass = { + "", + JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS, + &SimpleGlobalClassOps, JS_NULL_CLASS_SPEC, &SimpleGlobalClassExtension, JS_NULL_OBJECT_OPS diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp index b7795b08882f..98d527b8423d 100644 --- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -7792,7 +7792,7 @@ class NormalJSRuntime { friend class nsAutoPtr; - static const JSClass kGlobalClass; + static const JSClass sGlobalClass; static const uint32_t kRuntimeHeapSize = 768 * 1024; JSRuntime* mRuntime; @@ -23761,9 +23761,7 @@ CreateIndexOp::DoDatabaseWork(DatabaseConnection* aConnection) return NS_OK; } -const JSClass NormalJSRuntime::kGlobalClass = { - "IndexedDBTransactionThreadGlobal", - JSCLASS_GLOBAL_FLAGS, +static const JSClassOps sNormalJSRuntimeGlobalClassOps = { /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ nullptr, @@ -23778,6 +23776,12 @@ const JSClass NormalJSRuntime::kGlobalClass = { /* trace */ JS_GlobalObjectTraceHook }; +const JSClass NormalJSRuntime::sGlobalClass = { + "IndexedDBTransactionThreadGlobal", + JSCLASS_GLOBAL_FLAGS, + &sNormalJSRuntimeGlobalClassOps +}; + bool NormalJSRuntime::Init() { @@ -23799,7 +23803,7 @@ NormalJSRuntime::Init() JSAutoRequest ar(mContext); JS::CompartmentOptions options; - mGlobal = JS_NewGlobalObject(mContext, &kGlobalClass, nullptr, + mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, nullptr, JS::FireOnNewGlobalHook, options); if (NS_WARN_IF(!mGlobal)) { return false; diff --git a/dom/plugins/base/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp index 5221ff579cbc..4f430c408138 100644 --- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -218,8 +218,23 @@ CreateNPObjectMember(NPP npp, JSContext *cx, JSObject *obj, NPObject* npobj, JS::Handle id, NPVariant* getPropertyResult, JS::MutableHandle vp); +const static js::ClassOps sNPObjectJSWrapperClassOps = { + NPObjWrapper_AddProperty, + NPObjWrapper_DelProperty, + NPObjWrapper_GetProperty, + NPObjWrapper_SetProperty, + nullptr, + NPObjWrapper_Resolve, + nullptr, /* mayResolve */ + NPObjWrapper_Finalize, + NPObjWrapper_Call, + nullptr, /* hasInstance */ + NPObjWrapper_Construct, + nullptr, /* trace */ +}; + const static js::ClassExtension sNPObjectJSWrapperClassExtension = { - nullptr, /* weakmapKeyDelegateOp */ + nullptr, /* weakmapKeyDelegateOp */ NPObjWrapper_ObjectMoved }; @@ -237,26 +252,14 @@ const static js::ObjectOps sNPObjectJSWrapperObjectOps = { nullptr, }; -const static js::Class sNPObjectJSWrapperClass = - { +const static js::Class sNPObjectJSWrapperClass = { NPRUNTIME_JSCLASS_NAME, JSCLASS_HAS_PRIVATE, - NPObjWrapper_AddProperty, - NPObjWrapper_DelProperty, - NPObjWrapper_GetProperty, - NPObjWrapper_SetProperty, - nullptr, - NPObjWrapper_Resolve, - nullptr, /* mayResolve */ - NPObjWrapper_Finalize, - NPObjWrapper_Call, - nullptr, /* hasInstance */ - NPObjWrapper_Construct, - nullptr, /* trace */ + &sNPObjectJSWrapperClassOps, JS_NULL_CLASS_SPEC, &sNPObjectJSWrapperClassExtension, &sNPObjectJSWrapperObjectOps - }; +}; typedef struct NPObjectMemberPrivate { JS::Heap npobjWrapper; @@ -281,14 +284,17 @@ NPObjectMember_Trace(JSTracer *trc, JSObject *obj); static bool NPObjectMember_toPrimitive(JSContext *cx, unsigned argc, JS::Value *vp); -static const JSClass sNPObjectMemberClass = - { - "NPObject Ambiguous Member class", JSCLASS_HAS_PRIVATE, - nullptr, nullptr, NPObjectMember_GetProperty, nullptr, - nullptr, nullptr, nullptr, - NPObjectMember_Finalize, NPObjectMember_Call, - nullptr, nullptr, NPObjectMember_Trace - }; +static const JSClassOps sNPObjectMemberClassOps = { + nullptr, nullptr, NPObjectMember_GetProperty, nullptr, + nullptr, nullptr, nullptr, + NPObjectMember_Finalize, NPObjectMember_Call, + nullptr, nullptr, NPObjectMember_Trace +}; + +static const JSClass sNPObjectMemberClass = { + "NPObject Ambiguous Member class", JSCLASS_HAS_PRIVATE, + &sNPObjectMemberClassOps +}; static void OnWrapperDestroyed(); diff --git a/dom/xbl/nsXBLBinding.cpp b/dom/xbl/nsXBLBinding.cpp index 945ecbdfb16c..004db9d01847 100644 --- a/dom/xbl/nsXBLBinding.cpp +++ b/dom/xbl/nsXBLBinding.cpp @@ -86,15 +86,19 @@ XBLEnumerate(JSContext *cx, JS::Handle obj) return protoBinding->ResolveAllFields(cx, obj); } +static const JSClassOps gPrototypeJSClassOps = { + nullptr, nullptr, nullptr, nullptr, + XBLEnumerate, nullptr, + nullptr, XBLFinalize, + nullptr, nullptr, nullptr, nullptr +}; + static const JSClass gPrototypeJSClass = { "XBL prototype JSClass", JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | // Our one reserved slot holds the relevant nsXBLPrototypeBinding JSCLASS_HAS_RESERVED_SLOTS(1), - nullptr, nullptr, nullptr, nullptr, - XBLEnumerate, nullptr, - nullptr, XBLFinalize, - nullptr, nullptr, nullptr, nullptr + &gPrototypeJSClassOps }; // Implementation ///////////////////////////////////////////////////////////////// diff --git a/js/public/Class.h b/js/public/Class.h index 186c19732b83..1f1a8a7d0ea4 100644 --- a/js/public/Class.h +++ b/js/public/Class.h @@ -477,23 +477,55 @@ typedef bool typedef void (* FinalizeOp)(FreeOp* fop, JSObject* obj); -#define JS_CLASS_MEMBERS(FinalizeOpType) \ - const char* name; \ - uint32_t flags; \ - \ - /* Function pointer members (may be null). */ \ - JSAddPropertyOp addProperty; \ - JSDeletePropertyOp delProperty; \ - JSGetterOp getProperty; \ - JSSetterOp setProperty; \ - JSEnumerateOp enumerate; \ - JSResolveOp resolve; \ - JSMayResolveOp mayResolve; \ - FinalizeOpType finalize; \ - JSNative call; \ - JSHasInstanceOp hasInstance; \ - JSNative construct; \ - JSTraceOp trace +// The special treatment of |finalize| and |trace| is necessary because if we +// assign either of those hooks to a local variable and then call it -- as is +// done with the other hooks -- the GC hazard analysis gets confused. +#define JS_CLASS_MEMBERS(ClassOpsType, FinalizeOpType, FreeOpType) \ + const char* name; \ + uint32_t flags; \ + const ClassOpsType* cOps; \ + \ + JSAddPropertyOp getAddProperty() const { return cOps ? cOps->addProperty : nullptr; } \ + JSDeletePropertyOp getDelProperty() const { return cOps ? cOps->delProperty : nullptr; } \ + JSGetterOp getGetProperty() const { return cOps ? cOps->getProperty : nullptr; } \ + JSSetterOp getSetProperty() const { return cOps ? cOps->setProperty : nullptr; } \ + JSEnumerateOp getEnumerate() const { return cOps ? cOps->enumerate : nullptr; } \ + JSResolveOp getResolve() const { return cOps ? cOps->resolve : nullptr; } \ + JSMayResolveOp getMayResolve() const { return cOps ? cOps->mayResolve : nullptr; } \ + JSNative getCall() const { return cOps ? cOps->call : nullptr; } \ + JSHasInstanceOp getHasInstance() const { return cOps ? cOps->hasInstance : nullptr; } \ + JSNative getConstruct() const { return cOps ? cOps->construct : nullptr; } \ + \ + bool hasFinalize() const { return cOps && cOps->finalize; } \ + bool hasTrace() const { return cOps && cOps->trace; } \ + \ + bool isTrace(JSTraceOp trace) const { return cOps && cOps->trace == trace; } \ + \ + void doFinalize(FreeOpType* fop, JSObject* obj) const { \ + MOZ_ASSERT(cOps && cOps->finalize); \ + cOps->finalize(fop, obj); \ + } \ + void doTrace(JSTracer* trc, JSObject* obj) const { \ + MOZ_ASSERT(cOps && cOps->trace); \ + cOps->trace(trc, obj); \ + } + +struct ClassOps +{ + /* Function pointer members (may be null). */ + JSAddPropertyOp addProperty; + JSDeletePropertyOp delProperty; + JSGetterOp getProperty; + JSSetterOp setProperty; + JSEnumerateOp enumerate; + JSResolveOp resolve; + JSMayResolveOp mayResolve; + FinalizeOp finalize; + JSNative call; + JSHasInstanceOp hasInstance; + JSNative construct; + JSTraceOp trace; +}; /** Callback for the creation of constructor and prototype objects. */ typedef JSObject* (*ClassObjectCreationOp)(JSContext* cx, JSProtoKey key); @@ -645,8 +677,27 @@ struct ObjectOps typedef void (*JSClassInternal)(); +struct JSClassOps +{ + /* Function pointer members (may be null). */ + JSAddPropertyOp addProperty; + JSDeletePropertyOp delProperty; + JSGetterOp getProperty; + JSSetterOp setProperty; + JSEnumerateOp enumerate; + JSResolveOp resolve; + JSMayResolveOp mayResolve; + JSFinalizeOp finalize; + JSNative call; + JSHasInstanceOp hasInstance; + JSNative construct; + JSTraceOp trace; +}; + +#define JS_NULL_CLASS_OPS nullptr + struct JSClass { - JS_CLASS_MEMBERS(JSFinalizeOp); + JS_CLASS_MEMBERS(JSClassOps, JSFinalizeOp, JSFreeOp); void* reserved[3]; }; @@ -753,7 +804,7 @@ namespace js { struct Class { - JS_CLASS_MEMBERS(FinalizeOp); + JS_CLASS_MEMBERS(js::ClassOps, FinalizeOp, FreeOp); const ClassSpec* spec; const ClassExtension* ext; const ObjectOps* oOps; @@ -785,7 +836,7 @@ struct Class bool nonProxyCallable() const { MOZ_ASSERT(!isProxy()); - return isJSFunction() || call; + return isJSFunction() || getCall(); } bool isProxy() const { @@ -847,33 +898,38 @@ struct Class JSFunToStringOp getOpsFunToString() const { return oOps ? oOps->funToString : nullptr; } }; +static_assert(offsetof(JSClassOps, addProperty) == offsetof(ClassOps, addProperty), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, delProperty) == offsetof(ClassOps, delProperty), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, getProperty) == offsetof(ClassOps, getProperty), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, setProperty) == offsetof(ClassOps, setProperty), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, enumerate) == offsetof(ClassOps, enumerate), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, resolve) == offsetof(ClassOps, resolve), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, mayResolve) == offsetof(ClassOps, mayResolve), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, finalize) == offsetof(ClassOps, finalize), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, call) == offsetof(ClassOps, call), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, construct) == offsetof(ClassOps, construct), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, hasInstance) == offsetof(ClassOps, hasInstance), + "ClassOps and JSClassOps must be consistent"); +static_assert(offsetof(JSClassOps, trace) == offsetof(ClassOps, trace), + "ClassOps and JSClassOps must be consistent"); +static_assert(sizeof(JSClassOps) == sizeof(ClassOps), + "ClassOps and JSClassOps must be consistent"); + static_assert(offsetof(JSClass, name) == offsetof(Class, name), "Class and JSClass must be consistent"); static_assert(offsetof(JSClass, flags) == offsetof(Class, flags), "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, addProperty) == offsetof(Class, addProperty), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, delProperty) == offsetof(Class, delProperty), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, getProperty) == offsetof(Class, getProperty), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, setProperty) == offsetof(Class, setProperty), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, enumerate) == offsetof(Class, enumerate), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, resolve) == offsetof(Class, resolve), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, mayResolve) == offsetof(Class, mayResolve), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, finalize) == offsetof(Class, finalize), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, call) == offsetof(Class, call), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, construct) == offsetof(Class, construct), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, hasInstance) == offsetof(Class, hasInstance), - "Class and JSClass must be consistent"); -static_assert(offsetof(JSClass, trace) == offsetof(Class, trace), +static_assert(offsetof(JSClass, cOps) == offsetof(Class, cOps), "Class and JSClass must be consistent"); static_assert(sizeof(JSClass) == sizeof(Class), "Class and JSClass must be consistent"); diff --git a/js/src/asmjs/WasmModule.cpp b/js/src/asmjs/WasmModule.cpp index 3e922e8dd468..395968dbde19 100644 --- a/js/src/asmjs/WasmModule.cpp +++ b/js/src/asmjs/WasmModule.cpp @@ -1563,10 +1563,7 @@ Module::profilingLabel(uint32_t funcIndex) const return funcLabels_[funcIndex].get(); } -const Class WasmModuleObject::class_ = { - "WasmModuleObject", - JSCLASS_IS_ANONYMOUS | JSCLASS_DELAY_METADATA_BUILDER | - JSCLASS_HAS_RESERVED_SLOTS(WasmModuleObject::RESERVED_SLOTS), +const ClassOps WasmModuleObject::classOps_ = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -1581,6 +1578,13 @@ const Class WasmModuleObject::class_ = { WasmModuleObject::trace }; +const Class WasmModuleObject::class_ = { + "WasmModuleObject", + JSCLASS_IS_ANONYMOUS | JSCLASS_DELAY_METADATA_BUILDER | + JSCLASS_HAS_RESERVED_SLOTS(WasmModuleObject::RESERVED_SLOTS), + &WasmModuleObject::classOps_, +}; + bool WasmModuleObject::hasModule() const { diff --git a/js/src/asmjs/WasmModule.h b/js/src/asmjs/WasmModule.h index 0ef20e849ae6..2aa00177c93c 100644 --- a/js/src/asmjs/WasmModule.h +++ b/js/src/asmjs/WasmModule.h @@ -657,6 +657,8 @@ ExportedFunctionToIndex(JSFunction* fun); class WasmModuleObject : public NativeObject { static const unsigned MODULE_SLOT = 0; + static const ClassOps classOps_; + bool hasModule() const; static void finalize(FreeOp* fop, JSObject* obj); static void trace(JSTracer* trc, JSObject* obj); diff --git a/js/src/builtin/Intl.cpp b/js/src/builtin/Intl.cpp index 9f093e0de396..9e9171cbdaba 100644 --- a/js/src/builtin/Intl.cpp +++ b/js/src/builtin/Intl.cpp @@ -628,9 +628,7 @@ static void collator_finalize(FreeOp* fop, JSObject* obj); static const uint32_t UCOLLATOR_SLOT = 0; static const uint32_t COLLATOR_SLOTS_COUNT = 1; -static const Class CollatorClass = { - js_Object_str, - JSCLASS_HAS_RESERVED_SLOTS(COLLATOR_SLOTS_COUNT), +static const ClassOps CollatorClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -641,6 +639,12 @@ static const Class CollatorClass = { collator_finalize }; +static const Class CollatorClass = { + js_Object_str, + JSCLASS_HAS_RESERVED_SLOTS(COLLATOR_SLOTS_COUNT), + &CollatorClassOps +}; + #if JS_HAS_TOSOURCE static bool collator_toSource(JSContext* cx, unsigned argc, Value* vp) @@ -1122,9 +1126,7 @@ static void numberFormat_finalize(FreeOp* fop, JSObject* obj); static const uint32_t UNUMBER_FORMAT_SLOT = 0; static const uint32_t NUMBER_FORMAT_SLOTS_COUNT = 1; -static const Class NumberFormatClass = { - js_Object_str, - JSCLASS_HAS_RESERVED_SLOTS(NUMBER_FORMAT_SLOTS_COUNT), +static const ClassOps NumberFormatClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -1135,6 +1137,12 @@ static const Class NumberFormatClass = { numberFormat_finalize }; +static const Class NumberFormatClass = { + js_Object_str, + JSCLASS_HAS_RESERVED_SLOTS(NUMBER_FORMAT_SLOTS_COUNT), + &NumberFormatClassOps +}; + #if JS_HAS_TOSOURCE static bool numberFormat_toSource(JSContext* cx, unsigned argc, Value* vp) @@ -1591,9 +1599,7 @@ static void dateTimeFormat_finalize(FreeOp* fop, JSObject* obj); static const uint32_t UDATE_FORMAT_SLOT = 0; static const uint32_t DATE_TIME_FORMAT_SLOTS_COUNT = 1; -static const Class DateTimeFormatClass = { - js_Object_str, - JSCLASS_HAS_RESERVED_SLOTS(DATE_TIME_FORMAT_SLOTS_COUNT), +static const ClassOps DateTimeFormatClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -1604,6 +1610,12 @@ static const Class DateTimeFormatClass = { dateTimeFormat_finalize }; +static const Class DateTimeFormatClass = { + js_Object_str, + JSCLASS_HAS_RESERVED_SLOTS(DATE_TIME_FORMAT_SLOTS_COUNT), + &DateTimeFormatClassOps +}; + #if JS_HAS_TOSOURCE static bool dateTimeFormat_toSource(JSContext* cx, unsigned argc, Value* vp) diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index a5ff86975fbc..7c0990073112 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -104,9 +104,7 @@ namespace { } /* anonymous namespace */ -const Class MapIteratorObject::class_ = { - "Map Iterator", - JSCLASS_HAS_RESERVED_SLOTS(MapIteratorObject::SlotCount), +static const ClassOps MapIteratorObjectClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -117,6 +115,12 @@ const Class MapIteratorObject::class_ = { MapIteratorObject::finalize }; +const Class MapIteratorObject::class_ = { + "Map Iterator", + JSCLASS_HAS_RESERVED_SLOTS(MapIteratorObject::SlotCount), + &MapIteratorObjectClassOps +}; + const JSFunctionSpec MapIteratorObject::methods[] = { JS_SELF_HOSTED_FN("next", "MapIteratorNext", 0, 0), JS_FS_END @@ -259,10 +263,7 @@ MapIteratorObject::createResultPair(JSContext* cx) /*** Map *****************************************************************************************/ -const Class MapObject::class_ = { - "Map", - JSCLASS_HAS_PRIVATE | - JSCLASS_HAS_CACHED_PROTO(JSProto_Map), +const ClassOps MapObject::classOps_ = { nullptr, // addProperty nullptr, // delProperty nullptr, // getProperty @@ -277,6 +278,13 @@ const Class MapObject::class_ = { mark }; +const Class MapObject::class_ = { + "Map", + JSCLASS_HAS_PRIVATE | + JSCLASS_HAS_CACHED_PROTO(JSProto_Map), + &MapObject::classOps_ +}; + const JSPropertySpec MapObject::properties[] = { JS_PSG("size", size, 0), JS_PS_END @@ -870,9 +878,7 @@ class SetIteratorObject : public NativeObject } /* anonymous namespace */ -const Class SetIteratorObject::class_ = { - "Set Iterator", - JSCLASS_HAS_RESERVED_SLOTS(SetIteratorObject::SlotCount), +static const ClassOps SetIteratorObjectClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -883,6 +889,12 @@ const Class SetIteratorObject::class_ = { SetIteratorObject::finalize }; +const Class SetIteratorObject::class_ = { + "Set Iterator", + JSCLASS_HAS_RESERVED_SLOTS(SetIteratorObject::SlotCount), + &SetIteratorObjectClassOps +}; + const JSFunctionSpec SetIteratorObject::methods[] = { JS_FN("next", next, 0, 0), JS_FS_END @@ -1006,10 +1018,7 @@ SetIteratorObject::next(JSContext* cx, unsigned argc, Value* vp) /*** Set *****************************************************************************************/ -const Class SetObject::class_ = { - "Set", - JSCLASS_HAS_PRIVATE | - JSCLASS_HAS_CACHED_PROTO(JSProto_Set), +const ClassOps SetObject::classOps_ = { nullptr, // addProperty nullptr, // delProperty nullptr, // getProperty @@ -1024,6 +1033,13 @@ const Class SetObject::class_ = { mark }; +const Class SetObject::class_ = { + "Set", + JSCLASS_HAS_PRIVATE | + JSCLASS_HAS_CACHED_PROTO(JSProto_Set), + &SetObject::classOps_ +}; + const JSPropertySpec SetObject::properties[] = { JS_PSG("size", size, 0), JS_PS_END diff --git a/js/src/builtin/MapObject.h b/js/src/builtin/MapObject.h index 47a23ec4d5b0..90cd096cd033 100644 --- a/js/src/builtin/MapObject.h +++ b/js/src/builtin/MapObject.h @@ -109,6 +109,8 @@ class MapObject : public NativeObject { static bool iterator(JSContext *cx, IteratorKind kind, HandleObject obj, MutableHandleValue iter); private: + static const ClassOps classOps_; + static const JSPropertySpec properties[]; static const JSFunctionSpec methods[]; static const JSPropertySpec staticProperties[]; @@ -191,9 +193,12 @@ class SetObject : public NativeObject { static bool delete_(JSContext *cx, HandleObject obj, HandleValue key, bool *rval); private: + static const ClassOps classOps_; + static const JSPropertySpec properties[]; static const JSFunctionSpec methods[]; static const JSPropertySpec staticProperties[]; + ValueSet* getData() { return static_cast(getPrivate()); } static ValueSet & extract(HandleObject o); static ValueSet & extract(CallReceiver call); diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index eefe54f6e053..03300f598f59 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -529,11 +529,8 @@ void FunctionDeclaration::trace(JSTracer* trc) /////////////////////////////////////////////////////////////////////////// // ModuleObject -/* static */ const Class -ModuleObject::class_ = { - "Module", - JSCLASS_HAS_RESERVED_SLOTS(ModuleObject::SlotCount) | - JSCLASS_IS_ANONYMOUS, +/* static */ const ClassOps +ModuleObject::classOps_ = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -548,6 +545,14 @@ ModuleObject::class_ = { ModuleObject::trace }; +/* static */ const Class +ModuleObject::class_ = { + "Module", + JSCLASS_HAS_RESERVED_SLOTS(ModuleObject::SlotCount) | + JSCLASS_IS_ANONYMOUS, + &ModuleObject::classOps_ +}; + #define DEFINE_ARRAY_SLOT_ACCESSOR(cls, name, slot) \ ArrayObject& \ cls::name() const \ diff --git a/js/src/builtin/ModuleObject.h b/js/src/builtin/ModuleObject.h index a9ed0e2f5135..0d2c2e436ebf 100644 --- a/js/src/builtin/ModuleObject.h +++ b/js/src/builtin/ModuleObject.h @@ -264,6 +264,8 @@ class ModuleObject : public NativeObject HandleObject exports); private: + static const ClassOps classOps_; + static void trace(JSTracer* trc, JSObject* obj); static void finalize(js::FreeOp* fop, JSObject* obj); diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index 973deb6239ea..9c79161133af 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -1224,18 +1224,7 @@ static const ClassSpec PlainObjectClassSpec = { const Class PlainObject::class_ = { js_Object_str, JSCLASS_HAS_CACHED_PROTO(JSProto_Object), - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - nullptr, /* trace */ + JS_NULL_CLASS_OPS, &PlainObjectClassSpec }; diff --git a/js/src/builtin/Promise.cpp b/js/src/builtin/Promise.cpp index fe0c83237bee..f8679d51752a 100644 --- a/js/src/builtin/Promise.cpp +++ b/js/src/builtin/Promise.cpp @@ -409,18 +409,7 @@ const Class PromiseObject::class_ = { "Promise", JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Promise) | JSCLASS_HAS_XRAYED_CONSTRUCTOR, - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - nullptr, /* trace */ + JS_NULL_CLASS_OPS, &PromiseObjectClassSpec }; @@ -438,17 +427,6 @@ static const ClassSpec PromiseObjectProtoClassSpec = { const Class PromiseObject::protoClass_ = { "PromiseProto", JSCLASS_HAS_CACHED_PROTO(JSProto_Promise), - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - nullptr, /* trace */ + JS_NULL_CLASS_OPS, &PromiseObjectProtoClassSpec }; diff --git a/js/src/builtin/SIMD.cpp b/js/src/builtin/SIMD.cpp index d833b83a7e89..a9ac39762fec 100644 --- a/js/src/builtin/SIMD.cpp +++ b/js/src/builtin/SIMD.cpp @@ -189,9 +189,7 @@ TypedObjectMemory(HandleValue v) return reinterpret_cast(obj.typedMem()); } -const Class SimdTypeDescr::class_ = { - "SIMD", - JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE, +static const ClassOps SimdTypeDescrClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -200,7 +198,13 @@ const Class SimdTypeDescr::class_ = { nullptr, /* resolve */ nullptr, /* mayResolve */ TypeDescr::finalize, - call + SimdTypeDescr::call +}; + +const Class SimdTypeDescr::class_ = { + "SIMD", + JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE, + &SimdTypeDescrClassOps }; namespace { @@ -424,15 +428,19 @@ SimdTypeDescr::call(JSContext* cx, unsigned argc, Value* vp) /////////////////////////////////////////////////////////////////////////// // SIMD class -const Class SimdObject::class_ = { - "SIMD", - JSCLASS_HAS_RESERVED_SLOTS(uint32_t(SimdType::Count)), +static const ClassOps SimdObjectClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ nullptr, /* setProperty */ nullptr, /* enumerate */ - resolve /* resolve */ + SimdObject::resolve +}; + +const Class SimdObject::class_ = { + "SIMD", + JSCLASS_HAS_RESERVED_SLOTS(uint32_t(SimdType::Count)), + &SimdObjectClassOps }; bool diff --git a/js/src/builtin/TestingFunctions.cpp b/js/src/builtin/TestingFunctions.cpp index 68a62d29638b..b2d8fc9dacba 100644 --- a/js/src/builtin/TestingFunctions.cpp +++ b/js/src/builtin/TestingFunctions.cpp @@ -1410,8 +1410,7 @@ finalize_counter_finalize(JSFreeOp* fop, JSObject* obj) ++finalizeCount; } -static const JSClass FinalizeCounterClass = { - "FinalizeCounter", JSCLASS_IS_ANONYMOUS, +static const JSClassOps FinalizeCounterClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -1422,6 +1421,11 @@ static const JSClass FinalizeCounterClass = { finalize_counter_finalize }; +static const JSClass FinalizeCounterClass = { + "FinalizeCounter", JSCLASS_IS_ANONYMOUS, + &FinalizeCounterClassOps +}; + static bool MakeFinalizeObserver(JSContext* cx, unsigned argc, Value* vp) { @@ -2113,8 +2117,7 @@ class CloneBufferObject : public NativeObject { } }; -const Class CloneBufferObject::class_ = { - "CloneBuffer", JSCLASS_HAS_RESERVED_SLOTS(CloneBufferObject::NUM_SLOTS), +static const ClassOps CloneBufferObjectClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -2122,7 +2125,12 @@ const Class CloneBufferObject::class_ = { nullptr, /* enumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ - Finalize + CloneBufferObject::Finalize +}; + +const Class CloneBufferObject::class_ = { + "CloneBuffer", JSCLASS_HAS_RESERVED_SLOTS(CloneBufferObject::NUM_SLOTS), + &CloneBufferObjectClassOps }; const JSPropertySpec CloneBufferObject::props_[] = { diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index e3c077b05fa3..d8cc68adbd44 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -215,9 +215,7 @@ const Class js::TypedProto::class_ = { * distinguish which scalar type object this actually is. */ -const Class js::ScalarTypeDescr::class_ = { - "Scalar", - JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE, +static const ClassOps ScalarTypeDescrClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -229,6 +227,12 @@ const Class js::ScalarTypeDescr::class_ = { ScalarTypeDescr::call }; +const Class js::ScalarTypeDescr::class_ = { + "Scalar", + JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE, + &ScalarTypeDescrClassOps +}; + const JSFunctionSpec js::ScalarTypeDescr::typeObjectMethods[] = { JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0), JS_SELF_HOSTED_FN("array", "ArrayShorthand", 1, JSFUN_HAS_REST), @@ -312,9 +316,7 @@ ScalarTypeDescr::call(JSContext* cx, unsigned argc, Value* vp) * reference type object this actually is. */ -const Class js::ReferenceTypeDescr::class_ = { - "Reference", - JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE, +static const ClassOps ReferenceTypeDescrClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -326,6 +328,12 @@ const Class js::ReferenceTypeDescr::class_ = { ReferenceTypeDescr::call }; +const Class js::ReferenceTypeDescr::class_ = { + "Reference", + JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE, + &ReferenceTypeDescrClassOps +}; + const JSFunctionSpec js::ReferenceTypeDescr::typeObjectMethods[] = { JS_SELF_HOSTED_FN("toSource", "DescrToSource", 0, 0), {"array", {nullptr, nullptr}, 1, 0, "ArrayShorthand"}, @@ -497,9 +505,7 @@ CreatePrototypeObjectForComplexTypeInstance(JSContext* cx, HandleObject ctorProt return NewObjectWithGivenProto(cx, ctorPrototypePrototype, SingletonObject); } -const Class ArrayTypeDescr::class_ = { - "ArrayType", - JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE, +static const ClassOps ArrayTypeDescrClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -513,6 +519,12 @@ const Class ArrayTypeDescr::class_ = { TypedObject::construct }; +const Class ArrayTypeDescr::class_ = { + "ArrayType", + JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE, + &ArrayTypeDescrClassOps +}; + const JSPropertySpec ArrayMetaTypeDescr::typeObjectProperties[] = { JS_PS_END }; @@ -722,9 +734,7 @@ js::IsTypedObjectArray(JSObject& obj) * StructType class */ -const Class StructTypeDescr::class_ = { - "StructType", - JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE, +static const ClassOps StructTypeDescrClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -738,6 +748,12 @@ const Class StructTypeDescr::class_ = { TypedObject::construct }; +const Class StructTypeDescr::class_ = { + "StructType", + JSCLASS_HAS_RESERVED_SLOTS(JS_DESCR_SLOTS) | JSCLASS_BACKGROUND_FINALIZE, + &StructTypeDescrClassOps +}; + const JSPropertySpec StructMetaTypeDescr::typeObjectProperties[] = { JS_PS_END }; @@ -2261,9 +2277,7 @@ const ObjectOps TypedObject::objectOps_ = { }; #define DEFINE_TYPEDOBJ_CLASS(Name, Trace, flag) \ - const Class Name::class_ = { \ - # Name, \ - Class::NON_NATIVE | flag, \ + static const ClassOps Name##ClassOps = { \ nullptr, /* addProperty */ \ nullptr, /* delProperty */ \ nullptr, /* getProperty */ \ @@ -2276,6 +2290,11 @@ const ObjectOps TypedObject::objectOps_ = { nullptr, /* hasInstance */ \ nullptr, /* construct */ \ Trace, \ + }; \ + const Class Name::class_ = { \ + # Name, \ + Class::NON_NATIVE | flag, \ + &Name##ClassOps, \ JS_NULL_CLASS_SPEC, \ JS_NULL_CLASS_EXT, \ &TypedObject::objectOps_ \ diff --git a/js/src/builtin/WeakMapObject.cpp b/js/src/builtin/WeakMapObject.cpp index 1cafde916234..9f5f7b8d5731 100644 --- a/js/src/builtin/WeakMapObject.cpp +++ b/js/src/builtin/WeakMapObject.cpp @@ -383,10 +383,7 @@ WeakMap_construct(JSContext* cx, unsigned argc, Value* vp) return true; } -const Class WeakMapObject::class_ = { - "WeakMap", - JSCLASS_HAS_PRIVATE | - JSCLASS_HAS_CACHED_PROTO(JSProto_WeakMap), +static const ClassOps WeakMapObjectClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -401,6 +398,13 @@ const Class WeakMapObject::class_ = { WeakMap_mark }; +const Class WeakMapObject::class_ = { + "WeakMap", + JSCLASS_HAS_PRIVATE | + JSCLASS_HAS_CACHED_PROTO(JSProto_WeakMap), + &WeakMapObjectClassOps +}; + static const JSFunctionSpec weak_map_methods[] = { JS_FN("has", WeakMap_has, 1, 0), JS_FN("get", WeakMap_get, 1, 0), diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp index d1c714dee196..bbe3da17fc83 100644 --- a/js/src/ctypes/CTypes.cpp +++ b/js/src/ctypes/CTypes.cpp @@ -546,13 +546,16 @@ static const JSClass sCABIClass = { // Class representing ctypes.{C,Pointer,Array,Struct,Function}Type.prototype. // This exists to give said prototypes a class of "CType", and to provide // reserved slots for stashing various other prototype objects. -static const JSClass sCTypeProtoClass = { - "CType", - JSCLASS_HAS_RESERVED_SLOTS(CTYPEPROTO_SLOTS), +static const JSClassOps sCTypeProtoClassOps = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, ConstructAbstract, nullptr, ConstructAbstract }; +static const JSClass sCTypeProtoClass = { + "CType", + JSCLASS_HAS_RESERVED_SLOTS(CTYPEPROTO_SLOTS), + &sCTypeProtoClassOps +}; // Class representing ctypes.CData.prototype and the 'prototype' properties // of CTypes. This exists to give said prototypes a class of "CData". @@ -561,30 +564,39 @@ static const JSClass sCDataProtoClass = { 0 }; -static const JSClass sCTypeClass = { - "CType", - JSCLASS_HAS_RESERVED_SLOTS(CTYPE_SLOTS), +static const JSClassOps sCTypeClassOps = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, CType::Finalize, CType::ConstructData, CType::HasInstance, CType::ConstructData, CType::Trace }; +static const JSClass sCTypeClass = { + "CType", + JSCLASS_HAS_RESERVED_SLOTS(CTYPE_SLOTS), + &sCTypeClassOps +}; -static const JSClass sCDataClass = { - "CData", - JSCLASS_HAS_RESERVED_SLOTS(CDATA_SLOTS), +static const JSClassOps sCDataClassOps = { nullptr, nullptr, ArrayType::Getter, ArrayType::Setter, nullptr, nullptr, nullptr, CData::Finalize, FunctionType::Call, nullptr, FunctionType::Call }; +static const JSClass sCDataClass = { + "CData", + JSCLASS_HAS_RESERVED_SLOTS(CDATA_SLOTS), + &sCDataClassOps +}; -static const JSClass sCClosureClass = { - "CClosure", - JSCLASS_HAS_RESERVED_SLOTS(CCLOSURE_SLOTS), +static const JSClassOps sCClosureClassOps = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, CClosure::Finalize, nullptr, nullptr, nullptr, CClosure::Trace }; +static const JSClass sCClosureClass = { + "CClosure", + JSCLASS_HAS_RESERVED_SLOTS(CCLOSURE_SLOTS), + &sCClosureClassOps +}; /* * Class representing the prototype of CDataFinalizer. @@ -600,11 +612,14 @@ static const JSClass sCDataFinalizerProtoClass = { * Instances of CDataFinalizer have both private data (with type * |CDataFinalizer::Private|) and slots (see |CDataFinalizerSlots|). */ +static const JSClassOps sCDataFinalizerClassOps = { + nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, CDataFinalizer::Finalize +}; static const JSClass sCDataFinalizerClass = { "CDataFinalizer", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(CDATAFINALIZER_SLOTS), - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, CDataFinalizer::Finalize + &sCDataFinalizerClassOps }; @@ -786,18 +801,21 @@ static const JSClass sUInt64ProtoClass = { 0 }; +static const JSClassOps sInt64ClassOps = { + nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, Int64Base::Finalize +}; + static const JSClass sInt64Class = { "Int64", JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS), - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, Int64Base::Finalize + &sInt64ClassOps }; static const JSClass sUInt64Class = { "UInt64", JSCLASS_HAS_RESERVED_SLOTS(INT64_SLOTS), - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, Int64Base::Finalize + &sInt64ClassOps }; static const JSFunctionSpec sInt64StaticFunctions[] = { diff --git a/js/src/ctypes/Library.cpp b/js/src/ctypes/Library.cpp index 5ddaa68a3967..df38d2257789 100644 --- a/js/src/ctypes/Library.cpp +++ b/js/src/ctypes/Library.cpp @@ -32,11 +32,15 @@ namespace Library typedef Rooted RootedFlatString; +static const JSClassOps sLibraryClassOps = { + nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, Library::Finalize +}; + static const JSClass sLibraryClass = { "Library", JSCLASS_HAS_RESERVED_SLOTS(LIBRARY_SLOTS), - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, Library::Finalize + &sLibraryClassOps }; #define CTYPESFN_FLAGS \ diff --git a/js/src/devtools/rootAnalysis/annotations.js b/js/src/devtools/rootAnalysis/annotations.js index 1176c417005c..4c89c6da9d56 100644 --- a/js/src/devtools/rootAnalysis/annotations.js +++ b/js/src/devtools/rootAnalysis/annotations.js @@ -68,8 +68,8 @@ var ignoreClasses = { // Ignore calls through TYPE.FIELD, where TYPE is the class or struct name containing // a function pointer field named FIELD. var ignoreCallees = { - "js::Class.trace" : true, - "js::Class.finalize" : true, + "js::ClassOps.trace" : true, + "js::ClassOps.finalize" : true, "JSRuntime.destroyPrincipals" : true, "icu_50::UObject.__deleting_dtor" : true, // destructors in ICU code can't cause GC "mozilla::CycleCollectedJSRuntime.DescribeCustomObjects" : true, // During tracing, cannot GC. diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index adf9700e5639..756116834510 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -1268,10 +1268,10 @@ CallTraceHook(Functor f, JSTracer* trc, JSObject* obj, CheckGeneration check, Ar MOZ_ASSERT(clasp); MOZ_ASSERT(obj->isNative() == clasp->isNative()); - if (!clasp->trace) + if (!clasp->hasTrace()) return &obj->as(); - if (clasp->trace == InlineTypedObject::obj_trace) { + if (clasp->isTrace(InlineTypedObject::obj_trace)) { Shape** pshape = obj->as().addressOfShapeFromGC(); f(pshape, mozilla::Forward(args)...); @@ -1301,7 +1301,7 @@ CallTraceHook(Functor f, JSTracer* trc, JSObject* obj, CheckGeneration check, Ar return nullptr; } - clasp->trace(trc, obj); + clasp->doTrace(trc, obj); if (!clasp->isNative()) return nullptr; diff --git a/js/src/gc/Nursery.cpp b/js/src/gc/Nursery.cpp index 9e98f99bccb8..10c683f74b32 100644 --- a/js/src/gc/Nursery.cpp +++ b/js/src/gc/Nursery.cpp @@ -175,7 +175,7 @@ js::Nursery::allocateObject(JSContext* cx, size_t size, size_t numDynamic, const * heap. The finalizers for these classes must do nothing except free data * which was allocated via Nursery::allocateBuffer. */ - MOZ_ASSERT_IF(clasp->finalize, clasp->flags & JSCLASS_SKIP_NURSERY_FINALIZE); + MOZ_ASSERT_IF(clasp->hasFinalize(), clasp->flags & JSCLASS_SKIP_NURSERY_FINALIZE); /* Make the object allocation. */ JSObject* obj = static_cast(allocate(size)); diff --git a/js/src/gdb/gdb-tests.cpp b/js/src/gdb/gdb-tests.cpp index 414cf8a1865f..3d701fd58405 100644 --- a/js/src/gdb/gdb-tests.cpp +++ b/js/src/gdb/gdb-tests.cpp @@ -13,15 +13,19 @@ using namespace JS; -/* The class of the global object. */ -const JSClass global_class = { - "global", JSCLASS_GLOBAL_FLAGS, +static const JSClassOps global_classOps = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook }; +/* The class of the global object. */ +static const JSClass global_class = { + "global", JSCLASS_GLOBAL_FLAGS, + &global_classOps +}; + template static inline T* checkPtr(T* ptr) diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index b76be70c0e01..9f8b75b9cdd2 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -927,7 +927,7 @@ IsCacheableSetPropAddSlot(JSContext* cx, JSObject* obj, Shape* oldShape, // Watch out for resolve or addProperty hooks. if (ClassMayResolveId(cx->names(), obj->getClass(), id, obj) || - obj->getClass()->addProperty) + obj->getClass()->getAddProperty()) { return false; } diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index ee726d2f835e..258a4281584f 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -10699,19 +10699,28 @@ CodeGenerator::visitIsCallable(LIsCallable* ins) OutOfLineIsCallable* ool = new(alloc()) OutOfLineIsCallable(ins); addOutOfLineCode(ool, ins->mir()); - Label notFunction, done; + Label notFunction, hasCOps, done; masm.loadObjClass(object, output); // Just skim proxies off. Their notion of isCallable() is more complicated. masm.branchTestClassIsProxy(true, output, ool->entry()); - // An object is callable iff (is() || getClass()->call. + // An object is callable iff: + // is() || (getClass()->cOps && getClass()->cOps->call). masm.branchPtr(Assembler::NotEqual, output, ImmPtr(&JSFunction::class_), ¬Function); masm.move32(Imm32(1), output); masm.jump(&done); masm.bind(¬Function); - masm.cmpPtrSet(Assembler::NonZero, Address(output, offsetof(js::Class, call)), ImmPtr(nullptr), output); + masm.branchPtr(Assembler::NonZero, Address(output, offsetof(js::Class, cOps)), + ImmPtr(nullptr), &hasCOps); + masm.move32(Imm32(0), output); + masm.jump(&done); + + masm.bind(&hasCOps); + masm.cmpPtrSet(Assembler::NonZero, Address(output, offsetof(js::ClassOps, call)), + ImmPtr(nullptr), output); + masm.bind(&done); masm.bind(ool->rejoin()); } @@ -10761,7 +10770,7 @@ CodeGenerator::visitIsConstructor(LIsConstructor* ins) OutOfLineIsConstructor* ool = new(alloc()) OutOfLineIsConstructor(ins); addOutOfLineCode(ool, ins->mir()); - Label notFunction, notConstructor, done; + Label notFunction, notConstructor, hasCOps, done; masm.loadObjClass(object, output); // Just skim proxies off. Their notion of isConstructor() is more complicated. @@ -10769,7 +10778,7 @@ CodeGenerator::visitIsConstructor(LIsConstructor* ins) // An object is constructor iff // ((is() && as().isConstructor) || - // getClass()->construct). + // (getClass()->cOps && getClass()->cOps->construct)). masm.branchPtr(Assembler::NotEqual, output, ImmPtr(&JSFunction::class_), ¬Function); masm.load16ZeroExtend(Address(object, JSFunction::offsetOfFlags()), output); masm.and32(Imm32(JSFunction::CONSTRUCTOR), output); @@ -10781,7 +10790,15 @@ CodeGenerator::visitIsConstructor(LIsConstructor* ins) masm.jump(&done); masm.bind(¬Function); - masm.cmpPtrSet(Assembler::NonZero, Address(output, offsetof(js::Class, construct)), ImmPtr(nullptr), output); + masm.branchPtr(Assembler::NonZero, Address(output, offsetof(js::Class, cOps)), + ImmPtr(nullptr), &hasCOps); + masm.move32(Imm32(0), output); + masm.jump(&done); + + masm.bind(&hasCOps); + masm.cmpPtrSet(Assembler::NonZero, Address(output, offsetof(js::ClassOps, construct)), + ImmPtr(nullptr), output); + masm.bind(&done); masm.bind(ool->rejoin()); } diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 5a3a5b505b2d..51d3af8784ab 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -484,7 +484,7 @@ IsCacheableNoProperty(JSObject* obj, JSObject* holder, Shape* shape, jsbytecode* // Just because we didn't find the property on the object doesn't mean it // won't magically appear through various engine hacks. - if (obj->getClass()->getProperty) + if (obj->getClass()->getGetProperty()) return false; // Don't generate missing property ICs if we skipped a non-native object, as @@ -3280,7 +3280,7 @@ IsPropertyAddInlineable(JSContext* cx, NativeObject* obj, HandleId id, ConstantO return false; // Likewise for an addProperty hook, since we'll need to invoke it. - if (obj->getClass()->addProperty) + if (obj->getClass()->getAddProperty()) return false; if (!obj->nonProxyIsExtensible() || !shape->writable()) diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index 20950503a025..7d546cb86613 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -2744,7 +2744,7 @@ CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, PropertyName* name, return false; if (curObj->as().contains(cx, NameToId(name))) return false; - if (curObj->getClass()->getProperty) + if (curObj->getClass()->getGetProperty()) return false; } else if (curObj != obj) { // Non-native objects are only handled as the original receiver. diff --git a/js/src/jsapi-tests/testAddPropertyPropcache.cpp b/js/src/jsapi-tests/testAddPropertyPropcache.cpp index a079c8c437d4..b9e109f9ca76 100644 --- a/js/src/jsapi-tests/testAddPropertyPropcache.cpp +++ b/js/src/jsapi-tests/testAddPropertyPropcache.cpp @@ -16,10 +16,14 @@ AddProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValu return true; } +static const JSClassOps AddPropertyClassOps = { + AddProperty +}; + static const JSClass AddPropertyClass = { "AddPropertyTester", 0, - AddProperty + &AddPropertyClassOps }; BEGIN_TEST(testAddPropertyHook) diff --git a/js/src/jsapi-tests/testChromeBuffer.cpp b/js/src/jsapi-tests/testChromeBuffer.cpp index d199ba9883e0..f6a4fb8fba69 100644 --- a/js/src/jsapi-tests/testChromeBuffer.cpp +++ b/js/src/jsapi-tests/testChromeBuffer.cpp @@ -8,9 +8,7 @@ static TestJSPrincipals system_principals(1); -static const JSClass global_class = { - "global", - JSCLASS_IS_GLOBAL | JSCLASS_GLOBAL_FLAGS, +static const JSClassOps global_classOps = { nullptr, nullptr, nullptr, @@ -25,6 +23,12 @@ static const JSClass global_class = { JS_GlobalObjectTraceHook }; +static const JSClass global_class = { + "global", + JSCLASS_IS_GLOBAL | JSCLASS_GLOBAL_FLAGS, + &global_classOps +}; + static JS::PersistentRootedObject trusted_glob; static JS::PersistentRootedObject trusted_fun; diff --git a/js/src/jsapi-tests/testClassGetter.cpp b/js/src/jsapi-tests/testClassGetter.cpp index ef21848a8803..64b4ee5bf3ef 100644 --- a/js/src/jsapi-tests/testClassGetter.cpp +++ b/js/src/jsapi-tests/testClassGetter.cpp @@ -21,15 +21,19 @@ static bool test_prop_get( JSContext* cx, JS::HandleObject obj, JS::HandleId id, static bool PTest(JSContext* cx, unsigned argc, JS::Value* vp); -static const JSClass ptestClass = { - "PTest", - JSCLASS_HAS_PRIVATE, +static const JSClassOps ptestClassOps = { nullptr, // addProperty nullptr, // delProperty test_prop_get, nullptr // setProperty }; +static const JSClass ptestClass = { + "PTest", + JSCLASS_HAS_PRIVATE, + &ptestClassOps +}; + static bool PTest(JSContext* cx, unsigned argc, JS::Value* vp) { diff --git a/js/src/jsapi-tests/testFreshGlobalEvalRedefinition.cpp b/js/src/jsapi-tests/testFreshGlobalEvalRedefinition.cpp index 9faf3f4638b3..e9744a24a25d 100644 --- a/js/src/jsapi-tests/testFreshGlobalEvalRedefinition.cpp +++ b/js/src/jsapi-tests/testFreshGlobalEvalRedefinition.cpp @@ -21,14 +21,18 @@ GlobalResolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolv BEGIN_TEST(testRedefineGlobalEval) { - static const JSClass cls = { - "global", JSCLASS_GLOBAL_FLAGS, + static const JSClassOps clsOps = { nullptr, nullptr, nullptr, nullptr, GlobalEnumerate, GlobalResolve, nullptr, nullptr, nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook }; + static const JSClass cls = { + "global", JSCLASS_GLOBAL_FLAGS, + &clsOps + }; + /* Create the global object. */ JS::CompartmentOptions options; JS::Rooted g(cx, JS_NewGlobalObject(cx, &cls, nullptr, JS::FireOnNewGlobalHook, options)); diff --git a/js/src/jsapi-tests/testLookup.cpp b/js/src/jsapi-tests/testLookup.cpp index 178d1cf520ee..22fb16185f96 100644 --- a/js/src/jsapi-tests/testLookup.cpp +++ b/js/src/jsapi-tests/testLookup.cpp @@ -73,12 +73,16 @@ document_resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* res return true; } -static const JSClass document_class = { - "document", 0, +static const JSClassOps document_classOps = { nullptr, nullptr, nullptr, nullptr, nullptr, document_resolve, nullptr }; +static const JSClass document_class = { + "document", 0, + &document_classOps +}; + BEGIN_TEST(testLookup_bug570195) { JS::RootedObject obj(cx, JS_NewObject(cx, &document_class)); diff --git a/js/src/jsapi-tests/testNewObject.cpp b/js/src/jsapi-tests/testNewObject.cpp index 4289313f5916..ef39ca67a314 100644 --- a/js/src/jsapi-tests/testNewObject.cpp +++ b/js/src/jsapi-tests/testNewObject.cpp @@ -98,13 +98,16 @@ BEGIN_TEST(testNewObject_1) CHECK(v.isInt32(N - 1)); // With JSClass.construct. - static const JSClass cls = { - "testNewObject_1", - 0, + static const JSClassOps clsOps = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, constructHook }; + static const JSClass cls = { + "testNewObject_1", + 0, + &clsOps + }; JS::RootedObject ctor(cx, JS_NewObject(cx, &cls)); CHECK(ctor); JS::RootedValue rt2(cx, JS::ObjectValue(*ctor)); diff --git a/js/src/jsapi-tests/testPersistentRooted.cpp b/js/src/jsapi-tests/testPersistentRooted.cpp index 4543872b5f13..9dbdbd3465e3 100644 --- a/js/src/jsapi-tests/testPersistentRooted.cpp +++ b/js/src/jsapi-tests/testPersistentRooted.cpp @@ -20,21 +20,25 @@ struct BarkWhenTracedClass { int BarkWhenTracedClass::finalizeCount; int BarkWhenTracedClass::traceCount; +static const JSClassOps BarkWhenTracedClassClassOps = { + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + BarkWhenTracedClass::finalize, + nullptr, + nullptr, + nullptr, + BarkWhenTracedClass::trace +}; + const JSClass BarkWhenTracedClass::class_ = { "BarkWhenTracedClass", 0, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - finalize, - nullptr, - nullptr, - nullptr, - trace + &BarkWhenTracedClassClassOps }; struct Kennel { diff --git a/js/src/jsapi-tests/testPropCache.cpp b/js/src/jsapi-tests/testPropCache.cpp index 8c802f96b6c6..e36163ecfd00 100644 --- a/js/src/jsapi-tests/testPropCache.cpp +++ b/js/src/jsapi-tests/testPropCache.cpp @@ -16,10 +16,14 @@ CounterAdd(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue return true; } +static const JSClassOps CounterClassOps = { + CounterAdd +}; + static const JSClass CounterClass = { "Counter", /* name */ 0, /* flags */ - CounterAdd + &CounterClassOps }; BEGIN_TEST(testPropCache_bug505798) diff --git a/js/src/jsapi-tests/testResolveRecursion.cpp b/js/src/jsapi-tests/testResolveRecursion.cpp index 29ddab99cd1f..5c8ee734aa88 100644 --- a/js/src/jsapi-tests/testResolveRecursion.cpp +++ b/js/src/jsapi-tests/testResolveRecursion.cpp @@ -13,9 +13,7 @@ */ BEGIN_TEST(testResolveRecursion) { - static const JSClass my_resolve_class = { - "MyResolve", - JSCLASS_HAS_PRIVATE, + static const JSClassOps my_resolve_classOps = { nullptr, // add nullptr, // delete nullptr, // get @@ -24,6 +22,12 @@ BEGIN_TEST(testResolveRecursion) my_resolve }; + static const JSClass my_resolve_class = { + "MyResolve", + JSCLASS_HAS_PRIVATE, + &my_resolve_classOps + }; + obj1.init(cx, JS_NewObject(cx, &my_resolve_class)); CHECK(obj1); obj2.init(cx, JS_NewObject(cx, &my_resolve_class)); @@ -150,9 +154,7 @@ BEGIN_TEST(testResolveRecursion_InitStandardClasses) } const JSClass* getGlobalClass() override { - static const JSClass myGlobalClass = { - "testResolveRecursion_InitStandardClasses_myGlobalClass", - JSCLASS_GLOBAL_FLAGS, + static const JSClassOps myGlobalClassOps = { nullptr, // add nullptr, // delete nullptr, // get @@ -167,6 +169,12 @@ const JSClass* getGlobalClass() override { JS_GlobalObjectTraceHook }; + static const JSClass myGlobalClass = { + "testResolveRecursion_InitStandardClasses_myGlobalClass", + JSCLASS_GLOBAL_FLAGS, + &myGlobalClassOps + }; + return &myGlobalClass; } diff --git a/js/src/jsapi-tests/testSetProperty.cpp b/js/src/jsapi-tests/testSetProperty.cpp index a3c65c6b8e0e..e4ba0174e311 100644 --- a/js/src/jsapi-tests/testSetProperty.cpp +++ b/js/src/jsapi-tests/testSetProperty.cpp @@ -68,7 +68,7 @@ BEGIN_TEST(testSetProperty_InheritedGlobalSetter) // This is a JSAPI test because jsapi-test globals do not have a resolve // hook and therefore can use the property cache in some cases where the // shell can't. - MOZ_RELEASE_ASSERT(!JS_GetClass(global)->resolve); + MOZ_RELEASE_ASSERT(!JS_GetClass(global)->getResolve()); CHECK(JS_DefineProperty(cx, global, "HOTLOOP", 8, 0)); EXEC("var n = 0;\n" diff --git a/js/src/jsapi-tests/testWeakMap.cpp b/js/src/jsapi-tests/testWeakMap.cpp index 5ad46492d250..70145aa35866 100644 --- a/js/src/jsapi-tests/testWeakMap.cpp +++ b/js/src/jsapi-tests/testWeakMap.cpp @@ -159,18 +159,7 @@ JSObject* newKey() static const js::Class keyClass = { "keyWithDelegate", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(1), - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - nullptr, /* trace */ + JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, &keyClassExtension, JS_NULL_OBJECT_OPS @@ -207,14 +196,7 @@ JSObject* newCCW(JS::HandleObject sourceZone, JS::HandleObject destZone) JSObject* newDelegate() { - static const js::ClassExtension delegateClassExtension = { - nullptr, - DelegateObjectMoved - }; - - static const js::Class delegateClass = { - "delegate", - JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_RESERVED_SLOTS(1), + static const js::ClassOps delegateClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -227,6 +209,17 @@ JSObject* newDelegate() nullptr, /* hasInstance */ nullptr, /* construct */ JS_GlobalObjectTraceHook, + }; + + static const js::ClassExtension delegateClassExtension = { + nullptr, + DelegateObjectMoved + }; + + static const js::Class delegateClass = { + "delegate", + JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_RESERVED_SLOTS(1), + &delegateClassOps, JS_NULL_CLASS_SPEC, &delegateClassExtension, JS_NULL_OBJECT_OPS diff --git a/js/src/jsapi-tests/tests.h b/js/src/jsapi-tests/tests.h index b8f4f8e2fe36..0bdb622fe831 100644 --- a/js/src/jsapi-tests/tests.h +++ b/js/src/jsapi-tests/tests.h @@ -226,13 +226,16 @@ class JSAPITest JSAPITestString messages() const { return msgs; } static const JSClass * basicGlobalClass() { - static const JSClass c = { - "global", JSCLASS_GLOBAL_FLAGS, + static const JSClassOps cOps = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook }; + static const JSClass c = { + "global", JSCLASS_GLOBAL_FLAGS, + &cOps + }; return &c; } diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 01f93f892929..b27a44717b97 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2196,9 +2196,9 @@ DefinePropertyById(JSContext* cx, HandleObject obj, HandleId id, HandleValue val // setProperty ops". if (!(attrs & (JSPROP_GETTER | JSPROP_SETTER))) { if (!getter) - getter = obj->getClass()->getProperty; + getter = obj->getClass()->getGetProperty(); if (!setter) - setter = obj->getClass()->setProperty; + setter = obj->getClass()->getSetProperty(); } if (getter == JS_PropertyStub) getter = nullptr; diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index ef688ada6597..6a33155759c3 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -498,7 +498,8 @@ array_length_setter(JSContext* cx, HandleObject obj, HandleId id, MutableHandleV // we're here, do an impression of SetPropertyByDefining. const Class* clasp = obj->getClass(); return DefineProperty(cx, obj, cx->names().length, vp, - clasp->getProperty, clasp->setProperty, JSPROP_ENUMERATE, result); + clasp->getGetProperty(), clasp->getSetProperty(), + JSPROP_ENUMERATE, result); } Rooted arr(cx, &obj->as()); @@ -2700,7 +2701,7 @@ GetIndexedPropertiesInRange(JSContext* cx, HandleObject obj, uint32_t begin, uin // properties. JSObject* pobj = obj; do { - if (!pobj->isNative() || pobj->getClass()->resolve || pobj->getOpsLookupProperty()) + if (!pobj->isNative() || pobj->getClass()->getResolve() || pobj->getOpsLookupProperty()) return true; } while ((pobj = pobj->getProto())); @@ -3285,6 +3286,21 @@ array_proto_finish(JSContext* cx, JS::HandleObject ctor, JS::HandleObject proto) return DefineProperty(cx, proto, id, value, nullptr, nullptr, JSPROP_READONLY); } +static const ClassOps ArrayObjectClassOps = { + array_addProperty, + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + nullptr, /* finalize */ + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + nullptr, /* trace */ +}; + static const ClassSpec ArrayObjectClassSpec = { GenericCreateConstructor, CreateArrayPrototype, @@ -3298,18 +3314,7 @@ static const ClassSpec ArrayObjectClassSpec = { const Class ArrayObject::class_ = { "Array", JSCLASS_HAS_CACHED_PROTO(JSProto_Array) | JSCLASS_DELAY_METADATA_BUILDER, - array_addProperty, - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - nullptr, /* trace */ + &ArrayObjectClassOps, &ArrayObjectClassSpec }; diff --git a/js/src/jsdate.cpp b/js/src/jsdate.cpp index 1f3ae9654f9e..32ddd2aefa8d 100644 --- a/js/src/jsdate.cpp +++ b/js/src/jsdate.cpp @@ -3286,18 +3286,7 @@ const Class DateObject::class_ = { js_Date_str, JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_Date), - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - nullptr, /* trace */ + JS_NULL_CLASS_OPS, &DateObjectClassSpec }; @@ -3315,18 +3304,7 @@ static const ClassSpec DateObjectProtoClassSpec = { const Class DateObject::protoClass_ = { js_Object_str, JSCLASS_HAS_CACHED_PROTO(JSProto_Date), - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - nullptr, /* trace */ + JS_NULL_CLASS_OPS, &DateObjectProtoClassSpec }; diff --git a/js/src/jsexn.cpp b/js/src/jsexn.cpp index aa5d56392419..24cda3595eb7 100644 --- a/js/src/jsexn.cpp +++ b/js/src/jsexn.cpp @@ -65,23 +65,27 @@ static const JSFunctionSpec exception_methods[] = { JS_FS_END }; +static const ClassOps ErrorObjectClassOps = { + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + exn_finalize, + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + nullptr, /* trace */ +}; + #define IMPLEMENT_ERROR_CLASS(name, classSpecPtr) \ { \ js_Error_str, /* yes, really */ \ JSCLASS_HAS_CACHED_PROTO(JSProto_##name) | \ 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 */ \ + &ErrorObjectClassOps, \ classSpecPtr \ } diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 1e92bb7df6e8..b6b5b357e47e 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -314,6 +314,7 @@ JS_DefineFunctionsWithHelp(JSContext* cx, JS::HandleObject obj, const JSFunction namespace js { +extern JS_FRIEND_DATA(const js::ClassOps) ProxyClassOps; extern JS_FRIEND_DATA(const js::ClassExtension) ProxyClassExtension; extern JS_FRIEND_DATA(const js::ObjectOps) ProxyObjectOps; @@ -336,18 +337,7 @@ extern JS_FRIEND_DATA(const js::ObjectOps) ProxyObjectOps; JSCLASS_IS_PROXY | \ JSCLASS_DELAY_METADATA_BUILDER | \ flags, \ - nullptr, /* addProperty */ \ - nullptr, /* delProperty */ \ - nullptr, /* getProperty */ \ - nullptr, /* setProperty */ \ - nullptr, /* enumerate */ \ - nullptr, /* resolve */ \ - nullptr, /* mayResolve */ \ - js::proxy_Finalize, /* finalize */ \ - nullptr, /* call */ \ - js::proxy_HasInstance, /* hasInstance */ \ - nullptr, /* construct */ \ - js::proxy_Trace, /* trace */ \ + &js::ProxyClassOps, \ JS_NULL_CLASS_SPEC, \ extPtr, \ &js::ProxyObjectOps \ diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 606830435afa..ec13ae191c40 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -834,18 +834,7 @@ 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), +static const ClassOps JSFunctionClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -858,6 +847,21 @@ const Class JSFunction::class_ = { fun_hasInstance, nullptr, /* construct */ fun_trace, +}; + +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), + &JSFunctionClassOps, &JSFunctionClassSpec }; @@ -2110,8 +2114,8 @@ js::DefineFunction(JSContext* cx, HandleObject obj, HandleId id, Native native, gop = nullptr; sop = nullptr; } else { - gop = obj->getClass()->getProperty; - sop = obj->getClass()->setProperty; + gop = obj->getClass()->getGetProperty(); + sop = obj->getClass()->getSetProperty(); MOZ_ASSERT(gop != JS_PropertyStub); MOZ_ASSERT(sop != JS_StrictPropertyStub); } diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index a3695f7c349d..ea24f368c87f 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -7200,7 +7200,8 @@ JS_FRIEND_API(void) JS::AssertGCThingMustBeTenured(JSObject* obj) { MOZ_ASSERT(obj->isTenured() && - (!IsNurseryAllocable(obj->asTenured().getAllocKind()) || obj->getClass()->finalize)); + (!IsNurseryAllocable(obj->asTenured().getAllocKind()) || + obj->getClass()->hasFinalize())); } JS_FRIEND_API(void) diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 51e90939a5a0..58b02420aa21 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -155,7 +155,7 @@ CanBeFinalizedInBackground(AllocKind kind, const Class* clasp) * the alloc kind; kind may already be a background finalize kind. */ return (!IsBackgroundFinalized(kind) && - (!clasp->finalize || (clasp->flags & JSCLASS_BACKGROUND_FINALIZE))); + (!clasp->hasFinalize() || (clasp->flags & JSCLASS_BACKGROUND_FINALIZE))); } /* Capacity for slotsToThingKind */ diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index b30e00960cbb..4a27632b3854 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -381,7 +381,7 @@ Snapshot(JSContext* cx, HandleObject pobj_, unsigned flags, AutoIdVector* props) } } else if (pobj->isNative()) { // Give the object a chance to resolve all lazy properties - if (JSEnumerateOp enumerate = pobj->getClass()->enumerate) { + if (JSEnumerateOp enumerate = pobj->getClass()->getEnumerate()) { if (!enumerate(cx, pobj.as())) return false; } @@ -798,7 +798,7 @@ CanCacheIterableObject(JSContext* cx, JSObject* obj) if (obj->is() || obj->hasUncacheableProto() || obj->getOpsEnumerate() || - obj->getClass()->enumerate || + obj->getClass()->getEnumerate() || obj->as().containsPure(cx->names().iteratorIntrinsic)) { return false; @@ -1084,11 +1084,7 @@ PropertyIteratorObject::finalize(FreeOp* fop, JSObject* obj) fop->free_(ni); } -const Class PropertyIteratorObject::class_ = { - "Iterator", - JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator) | - JSCLASS_HAS_PRIVATE | - JSCLASS_BACKGROUND_FINALIZE, +const ClassOps PropertyIteratorObject::classOps_ = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -1103,6 +1099,14 @@ const Class PropertyIteratorObject::class_ = { trace }; +const Class PropertyIteratorObject::class_ = { + "Iterator", + JSCLASS_HAS_CACHED_PROTO(JSProto_Iterator) | + JSCLASS_HAS_PRIVATE | + JSCLASS_BACKGROUND_FINALIZE, + &PropertyIteratorObject::classOps_ +}; + static const Class ArrayIteratorPrototypeClass = { "Array Iterator", 0 @@ -1425,9 +1429,7 @@ stopiter_hasInstance(JSContext* cx, HandleObject obj, MutableHandleValue v, bool return true; } -const Class StopIterationObject::class_ = { - "StopIteration", - JSCLASS_HAS_CACHED_PROTO(JSProto_StopIteration), +static const ClassOps StopIterationObjectClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -1440,6 +1442,12 @@ const Class StopIterationObject::class_ = { stopiter_hasInstance }; +const Class StopIterationObject::class_ = { + "StopIteration", + JSCLASS_HAS_CACHED_PROTO(JSProto_StopIteration), + &StopIterationObjectClassOps +}; + static const JSFunctionSpec iterator_proto_methods[] = { JS_SELF_HOSTED_SYM_FN(iterator, "IteratorIdentity", 0, 0), JS_FS_END diff --git a/js/src/jsiter.h b/js/src/jsiter.h index 304e22391d24..2c2d7fb480e3 100644 --- a/js/src/jsiter.h +++ b/js/src/jsiter.h @@ -120,6 +120,8 @@ struct NativeIterator class PropertyIteratorObject : public NativeObject { + static const ClassOps classOps_; + public: static const Class class_; diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index ed31c8f7e798..2d95f3b9f55a 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1855,8 +1855,8 @@ js::InitClass(JSContext* cx, HandleObject obj, HandleObject protoProto_, RootedObject protoProto(cx, protoProto_); /* Check function pointer members. */ - MOZ_ASSERT(clasp->getProperty != JS_PropertyStub); - MOZ_ASSERT(clasp->setProperty != JS_StrictPropertyStub); + MOZ_ASSERT(clasp->getGetProperty() != JS_PropertyStub); + MOZ_ASSERT(clasp->getSetProperty() != JS_StrictPropertyStub); RootedAtom atom(cx, Atomize(cx, clasp->name, strlen(clasp->name))); if (!atom) @@ -2112,8 +2112,8 @@ JSObject::callHook() const { const js::Class* clasp = getClass(); - if (clasp->call) - return clasp->call; + if (JSNative call = clasp->getCall()) + return call; if (is()) { const js::ProxyObject& p = as(); @@ -2128,8 +2128,8 @@ JSObject::constructHook() const { const js::Class* clasp = getClass(); - if (clasp->construct) - return clasp->construct; + if (JSNative construct = clasp->getConstruct()) + return construct; if (is()) { const js::ProxyObject& p = as(); @@ -2944,8 +2944,8 @@ DefineFunctionFromSpec(JSContext* cx, HandleObject obj, const JSFunctionSpec* fs gop = nullptr; sop = nullptr; } else { - gop = obj->getClass()->getProperty; - sop = obj->getClass()->setProperty; + gop = obj->getClass()->getGetProperty(); + sop = obj->getClass()->getSetProperty(); MOZ_ASSERT(gop != JS_PropertyStub); MOZ_ASSERT(sop != JS_StrictPropertyStub); } @@ -3909,8 +3909,8 @@ JSObject::traceChildren(JSTracer* trc) // Call the trace hook at the end so that during a moving GC the trace hook // will see updated fields and slots. - if (clasp->trace) - clasp->trace(trc, this); + if (clasp->hasTrace()) + clasp->doTrace(trc, this); } static JSAtom* diff --git a/js/src/jsobj.h b/js/src/jsobj.h index fce001ebc811..78da71a506c5 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -1098,7 +1098,7 @@ GetInitialHeap(NewObjectKind newKind, const Class* clasp) { if (newKind != GenericObject) return gc::TenuredHeap; - if (clasp->finalize && !(clasp->flags & JSCLASS_SKIP_NURSERY_FINALIZE)) + if (clasp->hasFinalize() && !(clasp->flags & JSCLASS_SKIP_NURSERY_FINALIZE)) return gc::TenuredHeap; return gc::DefaultHeap; } diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index f2bb74debe74..05379af10f2a 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -78,8 +78,8 @@ JSObject::finalize(js::FreeOp* fop) #endif const js::Class* clasp = getClass(); - if (clasp->finalize) - clasp->finalize(fop, this); + if (clasp->hasFinalize()) + clasp->doFinalize(fop, this); if (!clasp->isNative()) return; @@ -321,7 +321,7 @@ JSObject::create(js::ExclusiveContext* cx, js::gc::AllocKind kind, js::gc::Initi js::gc::GetGCKindSlots(kind, group->clasp()) == shape->numFixedSlots()); MOZ_ASSERT_IF(group->clasp()->flags & JSCLASS_BACKGROUND_FINALIZE, IsBackgroundFinalized(kind)); - MOZ_ASSERT_IF(group->clasp()->finalize, + MOZ_ASSERT_IF(group->clasp()->hasFinalize(), heap == js::gc::TenuredHeap || (group->clasp()->flags & JSCLASS_SKIP_NURSERY_FINALIZE)); MOZ_ASSERT_IF(group->hasUnanalyzedPreliminaryObjects(), diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 595469cae5bc..c331ff07a882 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -1702,10 +1702,7 @@ ScriptSourceObject::finalize(FreeOp* fop, JSObject* obj) sso->setReservedSlot(SOURCE_SLOT, PrivateValue(nullptr)); } -const Class ScriptSourceObject::class_ = { - "ScriptSource", - JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | - JSCLASS_IS_ANONYMOUS, +static const ClassOps ScriptSourceObjectClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -1713,11 +1710,18 @@ const Class ScriptSourceObject::class_ = { nullptr, /* enumerate */ nullptr, /* resolve */ nullptr, /* mayResolve */ - finalize, + ScriptSourceObject::finalize, nullptr, /* call */ nullptr, /* hasInstance */ nullptr, /* construct */ - trace + ScriptSourceObject::trace +}; + +const Class ScriptSourceObject::class_ = { + "ScriptSource", + JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | + JSCLASS_IS_ANONYMOUS, + &ScriptSourceObjectClassOps }; ScriptSourceObject* diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 6e6564a4339b..b9803bc8530d 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -880,6 +880,8 @@ typedef HashSet Compre class ScriptSourceObject : public NativeObject { + static const ClassOps classOps_; + public: static const Class class_; diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index a5fb93f1b017..ddf3da0d27e6 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -430,10 +430,7 @@ str_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp) return true; } -const Class StringObject::class_ = { - js_String_str, - JSCLASS_HAS_RESERVED_SLOTS(StringObject::RESERVED_SLOTS) | - JSCLASS_HAS_CACHED_PROTO(JSProto_String), +static const ClassOps StringObjectClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -443,6 +440,13 @@ const Class StringObject::class_ = { str_mayResolve }; +const Class StringObject::class_ = { + js_String_str, + JSCLASS_HAS_RESERVED_SLOTS(StringObject::RESERVED_SLOTS) | + JSCLASS_HAS_CACHED_PROTO(JSProto_String), + &StringObjectClassOps +}; + /* * Returns a JSString * for the |this| value associated with 'call', or throws * a TypeError if |this| is null or undefined. This algorithm is the same as diff --git a/js/src/perf/jsperf.cpp b/js/src/perf/jsperf.cpp index ddb9d6256408..3f51b2a996f9 100644 --- a/js/src/perf/jsperf.cpp +++ b/js/src/perf/jsperf.cpp @@ -159,10 +159,21 @@ static const struct pm_const { static bool pm_construct(JSContext* cx, unsigned argc, Value* vp); static void pm_finalize(JSFreeOp* fop, JSObject* obj); +static const JSClassOps pm_classOps = { + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + pm_finalize +}; + static const JSClass pm_class = { - "PerfMeasurement", JSCLASS_HAS_PRIVATE, - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, pm_finalize + "PerfMeasurement", + JSCLASS_HAS_PRIVATE, + &pm_classOps }; // Constructor and destructor diff --git a/js/src/proxy/BaseProxyHandler.cpp b/js/src/proxy/BaseProxyHandler.cpp index 4099255f52eb..1fa146817b92 100644 --- a/js/src/proxy/BaseProxyHandler.cpp +++ b/js/src/proxy/BaseProxyHandler.cpp @@ -228,10 +228,10 @@ js::SetPropertyIgnoringNamedGetter(JSContext* cx, HandleObject obj, HandleId id, // A very old nonstandard SpiderMonkey extension: default to the Class // getter and setter ops. const Class* clasp = receiverObj->getClass(); - MOZ_ASSERT(clasp->getProperty != JS_PropertyStub); - MOZ_ASSERT(clasp->setProperty != JS_StrictPropertyStub); - return DefineProperty(cx, receiverObj, id, v, clasp->getProperty, clasp->setProperty, - attrs, result); + MOZ_ASSERT(clasp->getGetProperty() != JS_PropertyStub); + MOZ_ASSERT(clasp->getSetProperty() != JS_StrictPropertyStub); + return DefineProperty(cx, receiverObj, id, v, + clasp->getGetProperty(), clasp->getSetProperty(), attrs, result); } // Step 6. diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index e30f693cc112..b8ae33a981f1 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -716,6 +716,21 @@ js::proxy_FunToString(JSContext* cx, HandleObject proxy, unsigned indent) return Proxy::fun_toString(cx, proxy, indent); } +const ClassOps js::ProxyClassOps = { + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + js::proxy_Finalize, /* finalize */ + nullptr, /* call */ + js::proxy_HasInstance, /* hasInstance */ + nullptr, /* construct */ + js::proxy_Trace, /* trace */ +}; + const ClassExtension js::ProxyClassExtension = PROXY_MAKE_EXT( js::proxy_ObjectMoved ); diff --git a/js/src/shell/OSObject.cpp b/js/src/shell/OSObject.cpp index 1777d6f59ded..dd3fdd068626 100644 --- a/js/src/shell/OSObject.cpp +++ b/js/src/shell/OSObject.cpp @@ -395,9 +395,7 @@ class FileObject : public JSObject { } }; -const js::Class FileObject::class_ = { - "File", - JSCLASS_HAS_RESERVED_SLOTS(FileObject::NUM_SLOTS), +static const js::ClassOps FileObjectClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -412,6 +410,12 @@ const js::Class FileObject::class_ = { nullptr /* trace */ }; +const js::Class FileObject::class_ = { + "File", + JSCLASS_HAS_RESERVED_SLOTS(FileObject::NUM_SLOTS), + &FileObjectClassOps +}; + static FileObject* redirect(JSContext* cx, HandleString relFilename, RCFile** globalFile) { diff --git a/js/src/shell/js.cpp b/js/src/shell/js.cpp index efb17c70b85e..b1bb8d067afe 100644 --- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -2746,9 +2746,7 @@ sandbox_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp) return true; } -static const JSClass sandbox_class = { - "sandbox", - JSCLASS_GLOBAL_FLAGS, +static const JSClassOps sandbox_classOps = { nullptr, nullptr, nullptr, nullptr, sandbox_enumerate, sandbox_resolve, nullptr, nullptr, @@ -2756,6 +2754,12 @@ static const JSClass sandbox_class = { JS_GlobalObjectTraceHook }; +static const JSClass sandbox_class = { + "sandbox", + JSCLASS_GLOBAL_FLAGS, + &sandbox_classOps +}; + static void SetStandardCompartmentOptions(JS::CompartmentOptions& options) { @@ -6026,8 +6030,7 @@ global_mayResolve(const JSAtomState& names, jsid id, JSObject* maybeObj) return JS_MayResolveStandardClass(names, id, maybeObj); } -static const JSClass global_class = { - "global", JSCLASS_GLOBAL_FLAGS, +static const JSClassOps global_classOps = { nullptr, nullptr, nullptr, nullptr, global_enumerate, global_resolve, global_mayResolve, nullptr, @@ -6035,6 +6038,11 @@ static const JSClass global_class = { JS_GlobalObjectTraceHook }; +static const JSClass global_class = { + "global", JSCLASS_GLOBAL_FLAGS, + &global_classOps +}; + /* * Define a FakeDOMObject constructor. It returns an object with a getter, * setter and method with attached JitInfo. This object can be used to test diff --git a/js/src/vm/ArgumentsObject.cpp b/js/src/vm/ArgumentsObject.cpp index b1c231c69446..f8e2f6c82956 100644 --- a/js/src/vm/ArgumentsObject.cpp +++ b/js/src/vm/ArgumentsObject.cpp @@ -675,13 +675,7 @@ ArgumentsObject::objectMovedDuringMinorGC(JSTracer* trc, JSObject* dst, JSObject * stack frame with their corresponding property values in the frame's * arguments object. */ -const Class MappedArgumentsObject::class_ = { - "Arguments", - JSCLASS_DELAY_METADATA_BUILDER | - JSCLASS_HAS_RESERVED_SLOTS(MappedArgumentsObject::RESERVED_SLOTS) | - JSCLASS_HAS_CACHED_PROTO(JSProto_Object) | - JSCLASS_SKIP_NURSERY_FINALIZE | - JSCLASS_BACKGROUND_FINALIZE, +const ClassOps MappedArgumentsObject::classOps_ = { nullptr, /* addProperty */ ArgumentsObject::obj_delProperty, nullptr, /* getProperty */ @@ -696,17 +690,21 @@ const Class MappedArgumentsObject::class_ = { ArgumentsObject::trace }; +const Class MappedArgumentsObject::class_ = { + "Arguments", + JSCLASS_DELAY_METADATA_BUILDER | + JSCLASS_HAS_RESERVED_SLOTS(MappedArgumentsObject::RESERVED_SLOTS) | + JSCLASS_HAS_CACHED_PROTO(JSProto_Object) | + JSCLASS_SKIP_NURSERY_FINALIZE | + JSCLASS_BACKGROUND_FINALIZE, + &MappedArgumentsObject::classOps_ +}; + /* * Unmapped arguments is significantly less magical than mapped arguments, so * it is represented by a different class while sharing some functionality. */ -const Class UnmappedArgumentsObject::class_ = { - "Arguments", - JSCLASS_DELAY_METADATA_BUILDER | - JSCLASS_HAS_RESERVED_SLOTS(UnmappedArgumentsObject::RESERVED_SLOTS) | - JSCLASS_HAS_CACHED_PROTO(JSProto_Object) | - JSCLASS_SKIP_NURSERY_FINALIZE | - JSCLASS_BACKGROUND_FINALIZE, +const ClassOps UnmappedArgumentsObject::classOps_ = { nullptr, /* addProperty */ ArgumentsObject::obj_delProperty, nullptr, /* getProperty */ @@ -720,3 +718,13 @@ const Class UnmappedArgumentsObject::class_ = { nullptr, /* construct */ ArgumentsObject::trace }; + +const Class UnmappedArgumentsObject::class_ = { + "Arguments", + JSCLASS_DELAY_METADATA_BUILDER | + JSCLASS_HAS_RESERVED_SLOTS(UnmappedArgumentsObject::RESERVED_SLOTS) | + JSCLASS_HAS_CACHED_PROTO(JSProto_Object) | + JSCLASS_SKIP_NURSERY_FINALIZE | + JSCLASS_BACKGROUND_FINALIZE, + &UnmappedArgumentsObject::classOps_ +}; diff --git a/js/src/vm/ArgumentsObject.h b/js/src/vm/ArgumentsObject.h index 636b7a79b788..e02938486346 100644 --- a/js/src/vm/ArgumentsObject.h +++ b/js/src/vm/ArgumentsObject.h @@ -329,6 +329,8 @@ class ArgumentsObject : public NativeObject class MappedArgumentsObject : public ArgumentsObject { + static const ClassOps classOps_; + public: static const Class class_; @@ -352,6 +354,8 @@ class MappedArgumentsObject : public ArgumentsObject class UnmappedArgumentsObject : public ArgumentsObject { + static const ClassOps classOps_; + public: static const Class class_; diff --git a/js/src/vm/ArrayBufferObject.cpp b/js/src/vm/ArrayBufferObject.cpp index 92bcad3aa27d..b3e0c80548eb 100644 --- a/js/src/vm/ArrayBufferObject.cpp +++ b/js/src/vm/ArrayBufferObject.cpp @@ -96,6 +96,21 @@ const Class ArrayBufferObject::protoClass = { JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer) }; +const ClassOps ArrayBufferObject::classOps_ = { + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + ArrayBufferObject::finalize, + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + ArrayBufferObject::trace, +}; + static const ClassExtension ArrayBufferObjectClassExtension = { nullptr, /* weakmapKeyDelegateOp */ ArrayBufferObject::objectMoved @@ -107,18 +122,7 @@ const Class ArrayBufferObject::class_ = { JSCLASS_HAS_RESERVED_SLOTS(RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_ArrayBuffer) | JSCLASS_BACKGROUND_FINALIZE, - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - ArrayBufferObject::finalize, - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - ArrayBufferObject::trace, + &ArrayBufferObject::classOps_, JS_NULL_CLASS_SPEC, &ArrayBufferObjectClassExtension }; diff --git a/js/src/vm/ArrayBufferObject.h b/js/src/vm/ArrayBufferObject.h index 3fb9b7d32cbe..f8f97f32f043 100644 --- a/js/src/vm/ArrayBufferObject.h +++ b/js/src/vm/ArrayBufferObject.h @@ -102,6 +102,8 @@ class ArrayBufferObject : public ArrayBufferObjectMaybeShared static bool byteLengthGetterImpl(JSContext* cx, const CallArgs& args); static bool fun_slice_impl(JSContext* cx, const CallArgs& args); + static const ClassOps classOps_; + public: static const uint8_t DATA_SLOT = 0; static const uint8_t BYTE_LENGTH_SLOT = 1; diff --git a/js/src/vm/ArrayObject-inl.h b/js/src/vm/ArrayObject-inl.h index ff50aa49b312..c83e7b676033 100644 --- a/js/src/vm/ArrayObject-inl.h +++ b/js/src/vm/ArrayObject-inl.h @@ -41,7 +41,7 @@ ArrayObject::createArrayInternal(ExclusiveContext* cx, gc::AllocKind kind, gc::I MOZ_ASSERT(shape && group); MOZ_ASSERT(group->clasp() == shape->getObjectClass()); MOZ_ASSERT(group->clasp() == &ArrayObject::class_); - MOZ_ASSERT_IF(group->clasp()->finalize, heap == gc::TenuredHeap); + MOZ_ASSERT_IF(group->clasp()->hasFinalize(), heap == gc::TenuredHeap); MOZ_ASSERT_IF(group->hasUnanalyzedPreliminaryObjects(), heap == js::gc::TenuredHeap); MOZ_ASSERT(group->clasp()->shouldDelayMetadataBuilder()); diff --git a/js/src/vm/Debugger-inl.h b/js/src/vm/Debugger-inl.h index 82aeb4beb76c..230669816467 100644 --- a/js/src/vm/Debugger-inl.h +++ b/js/src/vm/Debugger-inl.h @@ -29,7 +29,7 @@ js::Debugger::onLeaveFrame(JSContext* cx, AbstractFramePtr frame, jsbytecode* pc /* static */ inline js::Debugger* js::Debugger::fromJSObject(const JSObject* obj) { - MOZ_ASSERT(js::GetObjectClass(obj) == &jsclass); + MOZ_ASSERT(js::GetObjectClass(obj) == &class_); return (Debugger*) obj->as().getPrivate(); } diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 9a0fb07b6e96..f80f8759c81e 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -59,9 +59,13 @@ using mozilla::Variant; using mozilla::AsVariant; -/*** Forward declarations ************************************************************************/ +/*** Forward declarations, ClassOps and Classes **************************************************/ -extern const Class DebuggerFrame_class; +static void DebuggerFrame_finalize(FreeOp* fop, JSObject* obj); +static void DebuggerEnv_trace(JSTracer* trc, JSObject* obj); +static void DebuggerObject_trace(JSTracer* trc, JSObject* obj); +static void DebuggerScript_trace(JSTracer* trc, JSObject* obj); +static void DebuggerSource_trace(JSTracer* trc, JSObject* obj); enum { JSSLOT_DEBUGFRAME_OWNER, @@ -71,35 +75,117 @@ enum { JSSLOT_DEBUGFRAME_COUNT }; -extern const Class DebuggerArguments_class; +static const ClassOps DebuggerFrame_classOps = { + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + DebuggerFrame_finalize, + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + nullptr, /* trace */ +}; + +static const Class DebuggerFrame_class = { + "Frame", + JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGFRAME_COUNT), + &DebuggerFrame_classOps +}; enum { JSSLOT_DEBUGARGUMENTS_FRAME, JSSLOT_DEBUGARGUMENTS_COUNT }; -extern const Class DebuggerEnv_class; +static const Class DebuggerArguments_class = { + "Arguments", + JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGARGUMENTS_COUNT) +}; enum { JSSLOT_DEBUGENV_OWNER, JSSLOT_DEBUGENV_COUNT }; -extern const Class DebuggerObject_class; +static const ClassOps DebuggerEnv_classOps = { + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + nullptr, /* finalize */ + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + DebuggerEnv_trace +}; + +static const Class DebuggerEnv_class = { + "Environment", + JSCLASS_HAS_PRIVATE | + JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGENV_COUNT), + &DebuggerEnv_classOps +}; enum { JSSLOT_DEBUGOBJECT_OWNER, JSSLOT_DEBUGOBJECT_COUNT }; -extern const Class DebuggerScript_class; +static const ClassOps DebuggerObject_classOps = { + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + nullptr, /* finalize */ + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + DebuggerObject_trace +}; + +static const Class DebuggerObject_class = { + "Object", + JSCLASS_HAS_PRIVATE | + JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGOBJECT_COUNT), + &DebuggerObject_classOps +}; enum { JSSLOT_DEBUGSCRIPT_OWNER, JSSLOT_DEBUGSCRIPT_COUNT }; -extern const Class DebuggerSource_class; +static const ClassOps DebuggerScript_classOps = { + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + nullptr, /* finalize */ + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + DebuggerScript_trace +}; + +static const Class DebuggerScript_class = { + "Script", + JSCLASS_HAS_PRIVATE | + JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGSCRIPT_COUNT), + &DebuggerScript_classOps +}; enum { JSSLOT_DEBUGSOURCE_OWNER, @@ -107,10 +193,27 @@ enum { JSSLOT_DEBUGSOURCE_COUNT }; -void DebuggerObject_trace(JSTracer* trc, JSObject* obj); -void DebuggerEnv_trace(JSTracer* trc, JSObject* obj); -void DebuggerScript_trace(JSTracer* trc, JSObject* obj); -void DebuggerSource_trace(JSTracer* trc, JSObject* obj); +static const ClassOps DebuggerSource_classOps = { + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + nullptr, /* finalize */ + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + DebuggerSource_trace +}; + +static const Class DebuggerSource_class = { + "Source", + JSCLASS_HAS_PRIVATE | + JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGSOURCE_COUNT), + &DebuggerSource_classOps +}; /*** Utils ***************************************************************************************/ @@ -2790,16 +2893,26 @@ Debugger::finalize(FreeOp* fop, JSObject* obj) fop->delete_(dbg); } -const Class Debugger::jsclass = { +const ClassOps Debugger::classOps_ = { + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + Debugger::finalize, + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + Debugger::traceObject +}; + +const Class Debugger::class_ = { "Debugger", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUG_COUNT), - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, Debugger::finalize, - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - Debugger::traceObject + &Debugger::classOps_ }; /* static */ Debugger* @@ -2808,7 +2921,7 @@ Debugger::fromThisValue(JSContext* cx, const CallArgs& args, const char* fnname) JSObject* thisobj = NonNullObject(cx, args.thisv()); if (!thisobj) return nullptr; - if (thisobj->getClass() != &Debugger::jsclass) { + if (thisobj->getClass() != &Debugger::class_) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_INCOMPATIBLE_PROTO, "Debugger", fnname, thisobj->getClass()->name); return nullptr; @@ -3395,13 +3508,13 @@ Debugger::construct(JSContext* cx, unsigned argc, Value* vp) if (!GetProperty(cx, callee, callee, cx->names().prototype, &v)) return false; RootedNativeObject proto(cx, &v.toObject().as()); - MOZ_ASSERT(proto->getClass() == &Debugger::jsclass); + MOZ_ASSERT(proto->getClass() == &Debugger::class_); /* * Make the new Debugger object. Each one has a reference to * Debugger.{Frame,Object,Script,Memory}.prototype in reserved slots. The * rest of the reserved slots are for hooks; they default to undefined. */ - RootedNativeObject obj(cx, NewNativeObjectWithGivenProto(cx, &Debugger::jsclass, proto)); + RootedNativeObject obj(cx, NewNativeObjectWithGivenProto(cx, &Debugger::class_, proto)); if (!obj) return false; for (unsigned slot = JSSLOT_DEBUG_PROTO_START; slot < JSSLOT_DEBUG_PROTO_STOP; slot++) @@ -4884,18 +4997,6 @@ DebuggerScript_trace(JSTracer* trc, JSObject* obj) } } -const Class DebuggerScript_class = { - "Script", - JSCLASS_HAS_PRIVATE | - JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGSCRIPT_COUNT), - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - DebuggerScript_trace -}; - class DebuggerScriptSetPrivateMatcher { NativeObject* obj_; @@ -6157,18 +6258,6 @@ DebuggerSource_trace(JSTracer* trc, JSObject* obj) } } -const Class DebuggerSource_class = { - "Source", - JSCLASS_HAS_PRIVATE | - JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGSOURCE_COUNT), - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - DebuggerSource_trace -}; - class SetDebuggerSourcePrivateMatcher { NativeObject* obj_; @@ -6720,12 +6809,6 @@ DebuggerFrame_finalize(FreeOp* fop, JSObject* obj) DebuggerFrame_freeScriptFrameIterData(fop, obj); } -const Class DebuggerFrame_class = { - "Frame", JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGFRAME_COUNT), - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, DebuggerFrame_finalize -}; - static NativeObject* CheckThisFrame(JSContext* cx, const CallArgs& args, const char* fnname, bool checkLive) { @@ -6949,10 +7032,6 @@ DebuggerFrame_getOlder(JSContext* cx, unsigned argc, Value* vp) return true; } -const Class DebuggerArguments_class = { - "Arguments", JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGARGUMENTS_COUNT) -}; - /* The getter used for each element of frame.arguments. See DebuggerFrame_getArguments. */ static bool DebuggerArguments_getArg(JSContext* cx, unsigned argc, Value* vp) @@ -7489,18 +7568,6 @@ DebuggerObject_trace(JSTracer* trc, JSObject* obj) } } -const Class DebuggerObject_class = { - "Object", - JSCLASS_HAS_PRIVATE | - JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGOBJECT_COUNT), - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - DebuggerObject_trace -}; - static NativeObject* DebuggerObject_checkThis(JSContext* cx, const CallArgs& args, const char* fnname) { @@ -8710,18 +8777,6 @@ DebuggerEnv_trace(JSTracer* trc, JSObject* obj) } } -const Class DebuggerEnv_class = { - "Environment", - JSCLASS_HAS_PRIVATE | - JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_DEBUGENV_COUNT), - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, nullptr, - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - DebuggerEnv_trace -}; - static NativeObject* DebuggerEnv_checkThis(JSContext* cx, const CallArgs& args, const char* fnname, bool requireDebuggee = true) @@ -9206,7 +9261,7 @@ JS_DefineDebuggerObject(JSContext* cx, HandleObject obj) if (!objProto) return false; debugProto = InitClass(cx, obj, - objProto, &Debugger::jsclass, Debugger::construct, + objProto, &Debugger::class_, Debugger::construct, 1, Debugger::properties, Debugger::methods, nullptr, Debugger::static_methods, debugCtor.address()); if (!debugProto) @@ -9310,7 +9365,7 @@ JS::dbg::IsDebugger(JSObject& obj) { JSObject* unwrapped = CheckedUnwrap(&obj); return unwrapped && - js::GetObjectClass(unwrapped) == &Debugger::jsclass && + js::GetObjectClass(unwrapped) == &Debugger::class_ && js::Debugger::fromJSObject(unwrapped) != nullptr; } diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index 3768200a5d4d..e833e084bb97 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -559,7 +559,8 @@ class Debugger : private mozilla::LinkedListElement static void finalize(FreeOp* fop, JSObject* obj); void markCrossCompartmentEdges(JSTracer* tracer); - static const Class jsclass; + static const ClassOps classOps_; + static const Class class_; static bool getHookImpl(JSContext* cx, CallArgs& args, Debugger& dbg, Hook which); static bool setHookImpl(JSContext* cx, CallArgs& args, Debugger& dbg, Hook which); diff --git a/js/src/vm/GlobalObject.cpp b/js/src/vm/GlobalObject.cpp index 46595339627d..651f0a29734b 100644 --- a/js/src/vm/GlobalObject.cpp +++ b/js/src/vm/GlobalObject.cpp @@ -293,7 +293,7 @@ GlobalObject* GlobalObject::createInternal(JSContext* cx, const Class* clasp) { MOZ_ASSERT(clasp->flags & JSCLASS_IS_GLOBAL); - MOZ_ASSERT(clasp->trace == JS_GlobalObjectTraceHook); + MOZ_ASSERT(clasp->isTrace(JS_GlobalObjectTraceHook)); JSObject* obj = NewObjectWithGivenProto(cx, clasp, nullptr, SingletonObject); if (!obj) @@ -620,11 +620,22 @@ GlobalDebuggees_finalize(FreeOp* fop, JSObject* obj) fop->delete_((GlobalObject::DebuggerVector*) obj->as().getPrivate()); } +static const ClassOps +GlobalDebuggees_classOps = { + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + GlobalDebuggees_finalize +}; + static const Class GlobalDebuggees_class = { "GlobalDebuggee", JSCLASS_HAS_PRIVATE, - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, GlobalDebuggees_finalize + &GlobalDebuggees_classOps }; GlobalObject::DebuggerVector* diff --git a/js/src/vm/HelperThreads.cpp b/js/src/vm/HelperThreads.cpp index 255845b0d379..e27ebe346fb5 100644 --- a/js/src/vm/HelperThreads.cpp +++ b/js/src/vm/HelperThreads.cpp @@ -187,14 +187,18 @@ js::CancelOffThreadIonCompile(JSCompartment* compartment, JSScript* script) } } -static const JSClass parseTaskGlobalClass = { - "internal-parse-task-global", JSCLASS_GLOBAL_FLAGS, +static const JSClassOps parseTaskGlobalClassOps = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook }; +static const JSClass parseTaskGlobalClass = { + "internal-parse-task-global", JSCLASS_GLOBAL_FLAGS, + &parseTaskGlobalClassOps +}; + ParseTask::ParseTask(ParseTaskKind kind, ExclusiveContext* cx, JSObject* exclusiveContextGlobal, JSContext* initCx, const char16_t* chars, size_t length, JS::OffThreadCompileCallback callback, void* callbackData) diff --git a/js/src/vm/Interpreter-inl.h b/js/src/vm/Interpreter-inl.h index 7498ac0d273b..62c72f0ef745 100644 --- a/js/src/vm/Interpreter-inl.h +++ b/js/src/vm/Interpreter-inl.h @@ -576,8 +576,8 @@ static MOZ_ALWAYS_INLINE bool InitElemOperation(JSContext* cx, jsbytecode* pc, HandleObject obj, HandleValue idval, HandleValue val) { MOZ_ASSERT(!val.isMagic(JS_ELEMENTS_HOLE)); - MOZ_ASSERT(!obj->getClass()->getProperty); - MOZ_ASSERT(!obj->getClass()->setProperty); + MOZ_ASSERT(!obj->getClass()->getGetProperty()); + MOZ_ASSERT(!obj->getClass()->getSetProperty()); RootedId id(cx); if (!ToPropertyKey(cx, idval, &id)) diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 1755cd4678cf..11cf415e4dfc 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -537,7 +537,7 @@ InternalConstruct(JSContext* cx, const AnyConstructArgs& args) { MOZ_ASSERT(args.array() + args.length() + 1 == args.end(), "must pass constructing arguments to a construction attempt"); - MOZ_ASSERT(!JSFunction::class_.construct); + MOZ_ASSERT(!JSFunction::class_.getConstruct()); // Callers are responsible for enforcing these preconditions. MOZ_ASSERT(IsConstructor(args.calleev()), @@ -720,8 +720,8 @@ js::HasInstance(JSContext* cx, HandleObject obj, HandleValue v, bool* bp) { const Class* clasp = obj->getClass(); RootedValue local(cx, v); - if (clasp->hasInstance) - return clasp->hasInstance(cx, obj, &local, bp); + if (JSHasInstanceOp hasInstance = clasp->getHasInstance()) + return hasInstance(cx, obj, &local, bp); RootedValue val(cx, ObjectValue(*obj)); ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h index 23aeb3d7bbd2..177256834f6b 100644 --- a/js/src/vm/NativeObject-inl.h +++ b/js/src/vm/NativeObject-inl.h @@ -394,7 +394,7 @@ CallResolveOp(JSContext* cx, HandleNativeObject obj, HandleId id, MutableHandleS *recursedp = false; bool resolved = false; - if (!obj->getClass()->resolve(cx, obj, id, &resolved)) + if (!obj->getClass()->getResolve()(cx, obj, id, &resolved)) return false; if (!resolved) @@ -402,8 +402,8 @@ CallResolveOp(JSContext* cx, HandleNativeObject obj, HandleId id, MutableHandleS // Assert the mayResolve hook, if there is one, returns true for this // property. - MOZ_ASSERT_IF(obj->getClass()->mayResolve, - obj->getClass()->mayResolve(cx->names(), id, obj)); + MOZ_ASSERT_IF(obj->getClass()->getMayResolve(), + obj->getClass()->getMayResolve()(cx->names(), id, obj)); if (JSID_IS_INT(id) && obj->containsDenseElement(JSID_TO_INT(id))) { MarkDenseOrTypedArrayElementFound(propp); @@ -421,17 +421,17 @@ ClassMayResolveId(const JSAtomState& names, const Class* clasp, jsid id, JSObjec { MOZ_ASSERT_IF(maybeObj, maybeObj->getClass() == clasp); - if (!clasp->resolve) { + if (!clasp->getResolve()) { // Sanity check: we should only have a mayResolve hook if we have a // resolve hook. - MOZ_ASSERT(!clasp->mayResolve, "Class with mayResolve hook but no resolve hook"); + MOZ_ASSERT(!clasp->getMayResolve(), "Class with mayResolve hook but no resolve hook"); return false; } - if (clasp->mayResolve) { + if (JSMayResolveOp mayResolve = clasp->getMayResolve()) { // Tell the analysis our mayResolve hooks won't trigger GC. JS::AutoSuppressGCAnalysis nogc; - if (!clasp->mayResolve(names, id, maybeObj)) + if (!mayResolve(names, id, maybeObj)) return false; } @@ -477,8 +477,7 @@ LookupOwnPropertyInline(ExclusiveContext* cx, } // id was not found in obj. Try obj's resolve hook, if any. - if (obj->getClass()->resolve) - { + if (obj->getClass()->getResolve()) { if (!cx->shouldBeJSContext() || !allowGC) return false; diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index 9e42e7ea97f1..a08dbe6ebe28 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -1000,7 +1000,7 @@ static inline bool CallAddPropertyHook(ExclusiveContext* cx, HandleNativeObject obj, HandleShape shape, HandleValue value) { - if (JSAddPropertyOp addProperty = obj->getClass()->addProperty) { + if (JSAddPropertyOp addProperty = obj->getClass()->getAddProperty()) { if (!cx->shouldBeJSContext()) return false; @@ -1026,7 +1026,7 @@ CallAddPropertyHookDense(ExclusiveContext* cx, HandleNativeObject obj, uint32_t return true; } - if (JSAddPropertyOp addProperty = obj->getClass()->addProperty) { + if (JSAddPropertyOp addProperty = obj->getClass()->getAddProperty()) { if (!cx->shouldBeJSContext()) return false; @@ -1873,7 +1873,7 @@ GetNonexistentProperty(JSContext* cx, HandleNativeObject obj, HandleId id, // Non-standard extension: Call the getProperty hook. If it sets vp to a // value other than undefined, we're done. If not, fall through to the // warning/error checks below. - if (JSGetterOp getProperty = obj->getClass()->getProperty) { + if (JSGetterOp getProperty = obj->getClass()->getGetProperty()) { if (!CallJSGetterOp(cx, getProperty, obj, id, vp)) return false; @@ -2180,8 +2180,8 @@ js::SetPropertyByDefining(JSContext* cx, HandleId id, HandleValue v, HandleValue existing ? JSPROP_IGNORE_ENUMERATE | JSPROP_IGNORE_READONLY | JSPROP_IGNORE_PERMANENT : JSPROP_ENUMERATE; - JSGetterOp getter = clasp->getProperty; - JSSetterOp setter = clasp->setProperty; + JSGetterOp getter = clasp->getGetProperty(); + JSSetterOp setter = clasp->getSetProperty(); MOZ_ASSERT(getter != JS_PropertyStub); MOZ_ASSERT(setter != JS_StrictPropertyStub); if (!DefineProperty(cx, receiver, id, v, getter, setter, attrs, result)) @@ -2451,7 +2451,7 @@ js::NativeDeleteProperty(JSContext* cx, HandleNativeObject obj, HandleId id, if (!shape) { // If no property call the class's delProperty hook, passing succeeded // as the result parameter. This always succeeds when there is no hook. - return CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, id, result); + return CallJSDeletePropertyOp(cx, obj->getClass()->getDelProperty(), obj, id, result); } cx->runtime()->gc.poke(); @@ -2460,7 +2460,7 @@ js::NativeDeleteProperty(JSContext* cx, HandleNativeObject obj, HandleId id, if (GetShapeAttributes(obj, shape) & JSPROP_PERMANENT) return result.failCantDelete(); - if (!CallJSDeletePropertyOp(cx, obj->getClass()->delProperty, obj, id, result)) + if (!CallJSDeletePropertyOp(cx, obj->getClass()->getDelProperty(), obj, id, result)) return false; if (!result) return true; diff --git a/js/src/vm/NativeObject.h b/js/src/vm/NativeObject.h index 0239a3d264cb..79c755a3310e 100644 --- a/js/src/vm/NativeObject.h +++ b/js/src/vm/NativeObject.h @@ -1280,10 +1280,8 @@ inline void NativeObject::privateWriteBarrierPre(void** oldval) { JS::shadow::Zone* shadowZone = this->shadowZoneFromAnyThread(); - if (shadowZone->needsIncrementalBarrier()) { - if (*oldval && getClass()->trace) - getClass()->trace(shadowZone->barrierTracer(), this); - } + if (shadowZone->needsIncrementalBarrier() && *oldval && getClass()->hasTrace()) + getClass()->doTrace(shadowZone->barrierTracer(), this); } #ifdef DEBUG diff --git a/js/src/vm/PIC.cpp b/js/src/vm/PIC.cpp index 92572aab6f0b..86da0b9e795d 100644 --- a/js/src/vm/PIC.cpp +++ b/js/src/vm/PIC.cpp @@ -294,8 +294,7 @@ ForOfPIC_traceObject(JSTracer* trc, JSObject* obj) chain->mark(trc); } -const Class ForOfPIC::jsclass = { - "ForOfPIC", JSCLASS_HAS_PRIVATE, +static const ClassOps ForOfPICClassOps = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, ForOfPIC_finalize, nullptr, /* call */ @@ -304,11 +303,16 @@ const Class ForOfPIC::jsclass = { ForOfPIC_traceObject }; +const Class ForOfPIC::class_ = { + "ForOfPIC", JSCLASS_HAS_PRIVATE, + &ForOfPICClassOps +}; + /* static */ NativeObject* js::ForOfPIC::createForOfPICObject(JSContext* cx, Handle global) { assertSameCompartment(cx, global); - NativeObject* obj = NewNativeObjectWithGivenProto(cx, &ForOfPIC::jsclass, nullptr); + NativeObject* obj = NewNativeObjectWithGivenProto(cx, &ForOfPIC::class_, nullptr); if (!obj) return nullptr; ForOfPIC::Chain* chain = cx->new_(); diff --git a/js/src/vm/PIC.h b/js/src/vm/PIC.h index 371bb6253841..c50d68d8ece4 100644 --- a/js/src/vm/PIC.h +++ b/js/src/vm/PIC.h @@ -253,12 +253,12 @@ struct ForOfPIC }; // Class for object that holds ForOfPIC chain. - static const Class jsclass; + static const Class class_; static NativeObject* createForOfPICObject(JSContext* cx, Handle global); static inline Chain* fromJSObject(NativeObject* obj) { - MOZ_ASSERT(js::GetObjectClass(obj) == &ForOfPIC::jsclass); + MOZ_ASSERT(js::GetObjectClass(obj) == &ForOfPIC::class_); return (ForOfPIC::Chain*) obj->getPrivate(); } static inline Chain* getOrCreate(JSContext* cx) { diff --git a/js/src/vm/ProxyObject.h b/js/src/vm/ProxyObject.h index f945e37ddc72..ac4ac4061af4 100644 --- a/js/src/vm/ProxyObject.h +++ b/js/src/vm/ProxyObject.h @@ -91,8 +91,8 @@ class ProxyObject : public JSObject // Proxy classes are not allowed to have call or construct hooks directly. Their // callability is instead decided by handler()->isCallable(). return clasp->isProxy() && - clasp->trace == proxy_Trace && - !clasp->call && !clasp->construct; + clasp->isTrace(proxy_Trace) && + !clasp->getCall() && !clasp->getConstruct(); } public: diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index b2b6a3654830..b78e932d9823 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -185,6 +185,21 @@ RegExpObject::trace(JSTracer* trc, JSObject* obj) } } +static const ClassOps RegExpObjectClassOps = { + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + nullptr, /* finalize */ + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + RegExpObject::trace, +}; + static const ClassSpec RegExpObjectClassSpec = { GenericCreateConstructor, CreateRegExpPrototype, @@ -199,18 +214,7 @@ const Class RegExpObject::class_ = { JSCLASS_HAS_PRIVATE | JSCLASS_HAS_RESERVED_SLOTS(RegExpObject::RESERVED_SLOTS) | JSCLASS_HAS_CACHED_PROTO(JSProto_RegExp), - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - RegExpObject::trace, + &RegExpObjectClassOps, &RegExpObjectClassSpec }; diff --git a/js/src/vm/RegExpStatics.cpp b/js/src/vm/RegExpStatics.cpp index c19dc63a959d..0eb1762ab022 100644 --- a/js/src/vm/RegExpStatics.cpp +++ b/js/src/vm/RegExpStatics.cpp @@ -34,9 +34,7 @@ resc_trace(JSTracer* trc, JSObject* obj) static_cast(pdata)->mark(trc); } -const Class RegExpStaticsObject::class_ = { - "RegExpStatics", - JSCLASS_HAS_PRIVATE, +static const ClassOps RegExpStaticsObjectClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -51,6 +49,12 @@ const Class RegExpStaticsObject::class_ = { resc_trace }; +const Class RegExpStaticsObject::class_ = { + "RegExpStatics", + JSCLASS_HAS_PRIVATE, + &RegExpStaticsObjectClassOps +}; + RegExpStaticsObject* RegExpStatics::create(ExclusiveContext* cx, Handle parent) { diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp index 808a2b4cd7e0..488cfdc463ad 100644 --- a/js/src/vm/SavedStacks.cpp +++ b/js/src/vm/SavedStacks.cpp @@ -289,6 +289,21 @@ SavedFrame::finishSavedFrameInit(JSContext* cx, HandleObject ctor, HandleObject return FreezeObject(cx, proto); } +static const ClassOps SavedFrameClassOps = { + nullptr, // addProperty + nullptr, // delProperty + nullptr, // getProperty + nullptr, // setProperty + nullptr, // enumerate + nullptr, // resolve + nullptr, // mayResolve + SavedFrame::finalize, // finalize + nullptr, // call + nullptr, // hasInstance + nullptr, // construct + nullptr, // trace +}; + const ClassSpec SavedFrame::classSpec_ = { GenericCreateConstructor, GenericCreatePrototype, @@ -306,18 +321,7 @@ const ClassSpec SavedFrame::classSpec_ = { JSCLASS_HAS_RESERVED_SLOTS(SavedFrame::JSSLOT_COUNT) | JSCLASS_HAS_CACHED_PROTO(JSProto_SavedFrame) | JSCLASS_IS_ANONYMOUS, - nullptr, // addProperty - nullptr, // delProperty - nullptr, // getProperty - nullptr, // setProperty - nullptr, // enumerate - nullptr, // resolve - nullptr, // mayResolve - SavedFrame::finalize, // finalize - nullptr, // call - nullptr, // hasInstance - nullptr, // construct - nullptr, // trace + &SavedFrameClassOps, &SavedFrame::classSpec_ }; diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 352cd8b000ce..8cff9f711ccc 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -458,18 +458,7 @@ const Class ModuleEnvironmentObject::class_ = { "ModuleEnvironmentObject", JSCLASS_HAS_RESERVED_SLOTS(ModuleEnvironmentObject::RESERVED_SLOTS) | JSCLASS_IS_ANONYMOUS, - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - nullptr, /* trace */ + JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, &ModuleEnvironmentObject::objectOps_ @@ -698,8 +687,8 @@ DeclEnvObject::createTemplateObject(JSContext* cx, HandleFunction fun, NewObject const Class* clasp = obj->getClass(); unsigned attrs = JSPROP_ENUMERATE | JSPROP_PERMANENT | JSPROP_READONLY; - JSGetterOp getter = clasp->getProperty; - JSSetterOp setter = clasp->setProperty; + JSGetterOp getter = clasp->getGetProperty(); + JSSetterOp setter = clasp->getSetProperty(); MOZ_ASSERT(getter != JS_PropertyStub); MOZ_ASSERT(setter != JS_StrictPropertyStub); @@ -886,18 +875,7 @@ const Class DynamicWithObject::class_ = { "With", JSCLASS_HAS_RESERVED_SLOTS(DynamicWithObject::RESERVED_SLOTS) | JSCLASS_IS_ANONYMOUS, - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - nullptr, /* trace */ + JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, &DynamicWithObjectObjectOps @@ -1128,18 +1106,7 @@ const Class ClonedBlockObject::class_ = { "Block", JSCLASS_HAS_RESERVED_SLOTS(ClonedBlockObject::RESERVED_SLOTS) | JSCLASS_IS_ANONYMOUS, - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - nullptr, /* trace */ + JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, JS_NULL_OBJECT_OPS @@ -1401,18 +1368,7 @@ const Class RuntimeLexicalErrorObject::class_ = { "RuntimeLexicalError", JSCLASS_HAS_RESERVED_SLOTS(RuntimeLexicalErrorObject::RESERVED_SLOTS) | JSCLASS_IS_ANONYMOUS, - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - nullptr, /* trace */ + JS_NULL_CLASS_OPS, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, &RuntimeLexicalErrorObjectObjectOps diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index a45249726ee5..8cb265203fd3 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -2643,14 +2643,18 @@ JSRuntime::createSelfHostingGlobal(JSContext* cx) if (!compartment) return nullptr; - static const Class shgClass = { - "self-hosting-global", JSCLASS_GLOBAL_FLAGS, + static const ClassOps shgClassOps = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook }; + static const Class shgClass = { + "self-hosting-global", JSCLASS_GLOBAL_FLAGS, + &shgClassOps + }; + AutoCompartment ac(cx, compartment); Rooted shg(cx, GlobalObject::createInternal(cx, &shgClass)); if (!shg) diff --git a/js/src/vm/SharedArrayObject.cpp b/js/src/vm/SharedArrayObject.cpp index 18dc11d1f856..079f36ed2253 100644 --- a/js/src/vm/SharedArrayObject.cpp +++ b/js/src/vm/SharedArrayObject.cpp @@ -346,11 +346,7 @@ const Class SharedArrayBufferObject::protoClass = { JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer) }; -const Class SharedArrayBufferObject::class_ = { - "SharedArrayBuffer", - JSCLASS_DELAY_METADATA_BUILDER | - JSCLASS_HAS_RESERVED_SLOTS(SharedArrayBufferObject::RESERVED_SLOTS) | - JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer), +static const ClassOps SharedArrayBufferObjectClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -363,6 +359,14 @@ const Class SharedArrayBufferObject::class_ = { nullptr, /* hasInstance */ nullptr, /* construct */ nullptr, /* trace */ +}; + +const Class SharedArrayBufferObject::class_ = { + "SharedArrayBuffer", + JSCLASS_DELAY_METADATA_BUILDER | + JSCLASS_HAS_RESERVED_SLOTS(SharedArrayBufferObject::RESERVED_SLOTS) | + JSCLASS_HAS_CACHED_PROTO(JSProto_SharedArrayBuffer), + &SharedArrayBufferObjectClassOps, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT }; diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 0e6845887690..db0568aea7bc 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -2466,7 +2466,7 @@ js::ClassCanHaveExtraProperties(const Class* clasp) { if (clasp == &UnboxedPlainObject::class_ || clasp == &UnboxedArrayObject::class_) return false; - return clasp->resolve + return clasp->getResolve() || clasp->getOpsLookupProperty() || clasp->getOpsGetProperty() || IsTypedArrayClass(clasp); @@ -3409,7 +3409,7 @@ PreliminaryObjectArray::sweep() obj->setGroup(objectProto->groupRaw()); MOZ_ASSERT(obj->is()); MOZ_ASSERT(obj->getClass() == objectProto->getClass()); - MOZ_ASSERT(!obj->getClass()->finalize); + MOZ_ASSERT(!obj->getClass()->hasFinalize()); } *ptr = nullptr; diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index 8374187a8941..c19b22240779 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -1144,18 +1144,7 @@ TypedArrayObject::sharedTypedArrayPrototypeClass = { // until we implement @@toStringTag. "???", JSCLASS_HAS_CACHED_PROTO(JSProto_TypedArray), - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - nullptr, /* trace */ + JS_NULL_CLASS_OPS, &TypedArrayObjectSharedTypedArrayPrototypeClassSpec }; @@ -2169,6 +2158,21 @@ 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) +static const ClassOps TypedArrayClassOps = { + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + nullptr, /* finalize */ + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + TypedArrayObject::trace, /* trace */ +}; + #define IMPL_TYPED_ARRAY_CLASS_SPEC(_type) \ { \ _type##Array::createConstructor, \ @@ -2200,18 +2204,7 @@ static const ClassSpec TypedArrayObjectClassSpecs[Scalar::MaxTypedArrayViewType] JSCLASS_HAS_PRIVATE | \ JSCLASS_HAS_CACHED_PROTO(JSProto_##_type##Array) | \ JSCLASS_DELAY_METADATA_BUILDER, \ - nullptr, /* addProperty */ \ - nullptr, /* delProperty */ \ - nullptr, /* getProperty */ \ - nullptr, /* setProperty */ \ - nullptr, /* enumerate */ \ - nullptr, /* resolve */ \ - nullptr, /* mayResolve */ \ - nullptr, /* finalize */ \ - nullptr, /* call */ \ - nullptr, /* hasInstance */ \ - nullptr, /* construct */ \ - TypedArrayObject::trace, /* trace */ \ + &TypedArrayClassOps, \ &TypedArrayObjectClassSpecs[Scalar::Type::_type] \ } @@ -2269,18 +2262,7 @@ static const ClassSpec TypedArrayObjectProtoClassSpecs[Scalar::MaxTypedArrayView */ \ #_type "ArrayPrototype", \ JSCLASS_HAS_CACHED_PROTO(JSProto_##_type##Array), \ - nullptr, /* addProperty */ \ - nullptr, /* delProperty */ \ - nullptr, /* getProperty */ \ - nullptr, /* setProperty */ \ - nullptr, /* enumerate */ \ - nullptr, /* resolve */ \ - nullptr, /* mayResolve */ \ - nullptr, /* finalize */ \ - nullptr, /* call */ \ - nullptr, /* hasInstance */ \ - nullptr, /* construct */ \ - nullptr, /* trace */ \ + JS_NULL_CLASS_OPS, \ &TypedArrayObjectProtoClassSpecs[Scalar::Type::_type] \ } @@ -2309,11 +2291,7 @@ const Class DataViewObject::protoClass = { JSCLASS_HAS_CACHED_PROTO(JSProto_DataView) }; -const Class DataViewObject::class_ = { - "DataView", - JSCLASS_HAS_PRIVATE | - JSCLASS_HAS_RESERVED_SLOTS(TypedArrayObject::RESERVED_SLOTS) | - JSCLASS_HAS_CACHED_PROTO(JSProto_DataView), +static const ClassOps DataViewObjectClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -2328,6 +2306,14 @@ const Class DataViewObject::class_ = { ArrayBufferViewObject::trace }; +const Class DataViewObject::class_ = { + "DataView", + JSCLASS_HAS_PRIVATE | + JSCLASS_HAS_RESERVED_SLOTS(TypedArrayObject::RESERVED_SLOTS) | + JSCLASS_HAS_CACHED_PROTO(JSProto_DataView), + &DataViewObjectClassOps +}; + const JSFunctionSpec DataViewObject::jsfuncs[] = { JS_FN("getInt8", DataViewObject::fun_getInt8, 1,0), JS_FN("getUint8", DataViewObject::fun_getUint8, 1,0), diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index 2b5609f5abf2..1b5d0a914c4b 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -905,6 +905,21 @@ const Class UnboxedExpandoObject::class_ = { 0 }; +static const ClassOps UnboxedPlainObjectClassOps = { + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + nullptr, /* finalize */ + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + UnboxedPlainObject::trace, +}; + static const ObjectOps UnboxedPlainObjectObjectOps = { UnboxedPlainObject::obj_lookupProperty, UnboxedPlainObject::obj_defineProperty, @@ -925,18 +940,7 @@ const Class UnboxedPlainObject::class_ = { Class::NON_NATIVE | JSCLASS_HAS_CACHED_PROTO(JSProto_Object) | JSCLASS_DELAY_METADATA_BUILDER, - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - nullptr, /* finalize */ - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - UnboxedPlainObject::trace, + &UnboxedPlainObjectClassOps, JS_NULL_CLASS_SPEC, JS_NULL_CLASS_EXT, &UnboxedPlainObjectObjectOps @@ -1591,6 +1595,21 @@ UnboxedArrayObject::obj_enumerate(JSContext* cx, HandleObject obj, AutoIdVector& return true; } +static const ClassOps UnboxedArrayObjectClassOps = { + nullptr, /* addProperty */ + nullptr, /* delProperty */ + nullptr, /* getProperty */ + nullptr, /* setProperty */ + nullptr, /* enumerate */ + nullptr, /* resolve */ + nullptr, /* mayResolve */ + UnboxedArrayObject::finalize, + nullptr, /* call */ + nullptr, /* hasInstance */ + nullptr, /* construct */ + UnboxedArrayObject::trace, +}; + static const ClassExtension UnboxedArrayObjectClassExtension = { nullptr, /* weakmapKeyDelegateOp */ UnboxedArrayObject::objectMoved @@ -1616,18 +1635,7 @@ const Class UnboxedArrayObject::class_ = { Class::NON_NATIVE | JSCLASS_SKIP_NURSERY_FINALIZE | JSCLASS_BACKGROUND_FINALIZE, - nullptr, /* addProperty */ - nullptr, /* delProperty */ - nullptr, /* getProperty */ - nullptr, /* setProperty */ - nullptr, /* enumerate */ - nullptr, /* resolve */ - nullptr, /* mayResolve */ - UnboxedArrayObject::finalize, - nullptr, /* call */ - nullptr, /* hasInstance */ - nullptr, /* construct */ - UnboxedArrayObject::trace, + &UnboxedArrayObjectClassOps, JS_NULL_CLASS_SPEC, &UnboxedArrayObjectClassExtension, &UnboxedArrayObjectObjectOps diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index 8944b02354f3..b0755affe7f0 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -550,6 +550,14 @@ sandbox_addProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v) #define XPCONNECT_SANDBOX_CLASS_METADATA_SLOT (XPCONNECT_GLOBAL_EXTRA_SLOT_OFFSET) +static const js::ClassOps SandboxClassOps = { + nullptr, nullptr, nullptr, nullptr, + sandbox_enumerate, sandbox_resolve, + nullptr, /* mayResolve */ + sandbox_finalize, + nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook, +}; + static const js::ClassExtension SandboxClassExtension = { nullptr, /* weakmapKeyDelegateOp */ sandbox_moved /* objectMovedOp */ @@ -558,11 +566,7 @@ static const js::ClassExtension SandboxClassExtension = { static const js::Class SandboxClass = { "Sandbox", XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(1), - nullptr, nullptr, nullptr, nullptr, - sandbox_enumerate, sandbox_resolve, - nullptr, /* mayResolve */ - sandbox_finalize, - nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook, + &SandboxClassOps, JS_NULL_CLASS_SPEC, &SandboxClassExtension, JS_NULL_OBJECT_OPS @@ -570,14 +574,18 @@ static const js::Class SandboxClass = { // Note to whomever comes here to remove addProperty hooks: billm has promised // to do the work for this class. -static const js::Class SandboxWriteToProtoClass = { - "Sandbox", - XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(1), +static const js::ClassOps SandboxWriteToProtoClassOps = { sandbox_addProperty, nullptr, nullptr, nullptr, sandbox_enumerate, sandbox_resolve, nullptr, /* mayResolve */ sandbox_finalize, nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook, +}; + +static const js::Class SandboxWriteToProtoClass = { + "Sandbox", + XPCONNECT_GLOBAL_FLAGS_WITH_EXTRA_SLOTS(1), + &SandboxWriteToProtoClassOps, JS_NULL_CLASS_SPEC, &SandboxClassExtension, JS_NULL_OBJECT_OPS diff --git a/js/xpconnect/src/XPCShellImpl.cpp b/js/xpconnect/src/XPCShellImpl.cpp index 74972dea86be..624d1dd3a4d7 100644 --- a/js/xpconnect/src/XPCShellImpl.cpp +++ b/js/xpconnect/src/XPCShellImpl.cpp @@ -794,12 +794,16 @@ env_resolve(JSContext* cx, HandleObject obj, HandleId id, bool* resolvedp) return true; } -static const JSClass env_class = { - "environment", JSCLASS_HAS_PRIVATE, +static const JSClassOps env_classOps = { nullptr, nullptr, nullptr, env_setProperty, env_enumerate, env_resolve }; +static const JSClass env_class = { + "environment", JSCLASS_HAS_PRIVATE, + &env_classOps +}; + /***************************************************************************/ typedef enum JSShellErrNum { diff --git a/js/xpconnect/src/XPCWrappedJSClass.cpp b/js/xpconnect/src/XPCWrappedJSClass.cpp index 41fec005cbf3..4ee4b6a67da1 100644 --- a/js/xpconnect/src/XPCWrappedJSClass.cpp +++ b/js/xpconnect/src/XPCWrappedJSClass.cpp @@ -1428,9 +1428,7 @@ FinalizeStub(JSFreeOp* fop, JSObject* obj) { } -static const JSClass XPCOutParamClass = { - "XPCOutParam", - 0, +static const JSClassOps XPCOutParamClassOps = { nullptr, /* addProperty */ nullptr, /* delProperty */ nullptr, /* getProperty */ @@ -1445,6 +1443,12 @@ static const JSClass XPCOutParamClass = { nullptr /* trace */ }; +static const JSClass XPCOutParamClass = { + "XPCOutParam", + 0, + &XPCOutParamClassOps +}; + bool xpc::IsOutObject(JSContext* cx, JSObject* obj) { diff --git a/js/xpconnect/src/XPCWrappedNative.cpp b/js/xpconnect/src/XPCWrappedNative.cpp index 04d03c39e8d5..5bbcee0ceb1b 100644 --- a/js/xpconnect/src/XPCWrappedNative.cpp +++ b/js/xpconnect/src/XPCWrappedNative.cpp @@ -775,8 +775,8 @@ XPCWrappedNative::Init(const XPCNativeScriptableCreateInfo* sci) MOZ_ASSERT(jsclazz && jsclazz->name && jsclazz->flags && - jsclazz->resolve && - jsclazz->finalize, "bad class"); + jsclazz->getResolve() && + jsclazz->hasFinalize(), "bad class"); // XXXbz JS_GetObjectPrototype wants an object, even though it then asserts // that this object is same-compartment with cx, which means it could just diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp index 5403c75ccac1..f03cea471203 100644 --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp @@ -620,39 +620,34 @@ XPC_WN_NoHelper_Resolve(JSContext* cx, HandleObject obj, HandleId id, bool* reso resolvedp); } +static const js::ClassOps XPC_WN_NoHelper_JSClassOps = { + XPC_WN_OnlyIWrite_AddPropertyStub, // addProperty + XPC_WN_CantDeletePropertyStub, // delProperty + nullptr, // getProperty + nullptr, // setProperty + XPC_WN_Shared_Enumerate, // enumerate + XPC_WN_NoHelper_Resolve, // resolve + nullptr, // mayResolve + XPC_WN_NoHelper_Finalize, // finalize + nullptr, // call + nullptr, // construct + nullptr, // hasInstance + XPCWrappedNative::Trace, // trace +}; + static const js::ClassExtension XPC_WN_JSClassExtension = { nullptr, // weakmapKeyDelegateOp WrappedNativeObjectMoved }; const js::Class XPC_WN_NoHelper_JSClass = { - "XPCWrappedNative_NoHelper", // name; + "XPCWrappedNative_NoHelper", WRAPPER_FLAGS | JSCLASS_IS_WRAPPED_NATIVE | - JSCLASS_PRIVATE_IS_NSISUPPORTS, // flags - - /* Mandatory non-null function pointer members. */ - XPC_WN_OnlyIWrite_AddPropertyStub, // addProperty - XPC_WN_CantDeletePropertyStub, // delProperty - nullptr, // getProperty - nullptr, // setProperty - - XPC_WN_Shared_Enumerate, // enumerate - XPC_WN_NoHelper_Resolve, // resolve - nullptr, // mayResolve - XPC_WN_NoHelper_Finalize, // finalize - - /* Optionally non-null members start here. */ - nullptr, // call - nullptr, // construct - nullptr, // hasInstance - XPCWrappedNative::Trace, // trace + JSCLASS_PRIVATE_IS_NSISUPPORTS, + &XPC_WN_NoHelper_JSClassOps, JS_NULL_CLASS_SPEC, - - // ClassExtension &XPC_WN_JSClassExtension, - - // ObjectOps JS_NULL_OBJECT_OPS }; @@ -984,73 +979,75 @@ XPCNativeScriptableShared::XPCNativeScriptableShared(uint32_t aFlags, if (mFlags.IsGlobalObject()) mJSClass.flags |= XPCONNECT_GLOBAL_FLAGS; - JSAddPropertyOp addProperty; - if (mFlags.WantAddProperty()) - addProperty = XPC_WN_Helper_AddProperty; - else if (mFlags.UseJSStubForAddProperty()) - addProperty = nullptr; - else if (mFlags.AllowPropModsDuringResolve()) - addProperty = XPC_WN_MaybeResolvingPropertyStub; - else - addProperty = XPC_WN_CannotModifyPropertyStub; - mJSClass.addProperty = addProperty; + // Initialize the js::ClassExtension. - JSDeletePropertyOp delProperty; - if (mFlags.UseJSStubForDelProperty()) - delProperty = nullptr; + // This is an unusual js::ClassOps: it is heap-allocated and belongs to + // |this|. + js::ClassOps* cOps = new js::ClassOps; + memset(cOps, 0, sizeof(js::ClassOps)); + mJSClass.cOps = cOps; + + if (mFlags.WantAddProperty()) + cOps->addProperty = XPC_WN_Helper_AddProperty; + else if (mFlags.UseJSStubForAddProperty()) + cOps->addProperty = nullptr; else if (mFlags.AllowPropModsDuringResolve()) - delProperty = XPC_WN_MaybeResolvingDeletePropertyStub; + cOps->addProperty = XPC_WN_MaybeResolvingPropertyStub; else - delProperty = XPC_WN_CantDeletePropertyStub; - mJSClass.delProperty = delProperty; + cOps->addProperty = XPC_WN_CannotModifyPropertyStub; + + if (mFlags.UseJSStubForDelProperty()) + cOps->delProperty = nullptr; + else if (mFlags.AllowPropModsDuringResolve()) + cOps->delProperty = XPC_WN_MaybeResolvingDeletePropertyStub; + else + cOps->delProperty = XPC_WN_CantDeletePropertyStub; if (mFlags.WantGetProperty()) - mJSClass.getProperty = XPC_WN_Helper_GetProperty; + cOps->getProperty = XPC_WN_Helper_GetProperty; else - mJSClass.getProperty = nullptr; + cOps->getProperty = nullptr; - JSSetterOp setProperty; if (mFlags.WantSetProperty()) - setProperty = XPC_WN_Helper_SetProperty; + cOps->setProperty = XPC_WN_Helper_SetProperty; else if (mFlags.UseJSStubForSetProperty()) - setProperty = nullptr; + cOps->setProperty = nullptr; else if (mFlags.AllowPropModsDuringResolve()) - setProperty = XPC_WN_MaybeResolvingSetPropertyStub; + cOps->setProperty = XPC_WN_MaybeResolvingSetPropertyStub; else - setProperty = XPC_WN_CannotModifySetPropertyStub; - mJSClass.setProperty = setProperty; + cOps->setProperty = XPC_WN_CannotModifySetPropertyStub; MOZ_ASSERT_IF(mFlags.WantEnumerate(), !mFlags.WantNewEnumerate()); MOZ_ASSERT_IF(mFlags.WantNewEnumerate(), !mFlags.WantEnumerate()); // We will use ops->enumerate set below for NewEnumerate if (mFlags.WantNewEnumerate()) - mJSClass.enumerate = nullptr; + cOps->enumerate = nullptr; else if (mFlags.WantEnumerate()) - mJSClass.enumerate = XPC_WN_Helper_Enumerate; + cOps->enumerate = XPC_WN_Helper_Enumerate; else - mJSClass.enumerate = XPC_WN_Shared_Enumerate; + cOps->enumerate = XPC_WN_Shared_Enumerate; // We have to figure out resolve strategy at call time - mJSClass.resolve = XPC_WN_Helper_Resolve; + cOps->resolve = XPC_WN_Helper_Resolve; if (mFlags.WantFinalize()) - mJSClass.finalize = XPC_WN_Helper_Finalize; + cOps->finalize = XPC_WN_Helper_Finalize; else - mJSClass.finalize = XPC_WN_NoHelper_Finalize; + cOps->finalize = XPC_WN_NoHelper_Finalize; if (mFlags.WantCall()) - mJSClass.call = XPC_WN_Helper_Call; + cOps->call = XPC_WN_Helper_Call; if (mFlags.WantConstruct()) - mJSClass.construct = XPC_WN_Helper_Construct; + cOps->construct = XPC_WN_Helper_Construct; if (mFlags.WantHasInstance()) - mJSClass.hasInstance = XPC_WN_Helper_HasInstance; + cOps->hasInstance = XPC_WN_Helper_HasInstance; if (mFlags.IsGlobalObject()) - mJSClass.trace = JS_GlobalObjectTraceHook; + cOps->trace = JS_GlobalObjectTraceHook; else - mJSClass.trace = XPCWrappedNative::Trace; + cOps->trace = XPCWrappedNative::Trace; // Initialize the js::ClassExtension. @@ -1259,56 +1256,39 @@ XPC_WN_ModsAllowed_Proto_Resolve(JSContext* cx, HandleObject obj, HandleId id, b JSPROP_ENUMERATE, resolvep); } +static const js::ClassOps XPC_WN_ModsAllowed_Proto_JSClassOps = { + nullptr, // addProperty + nullptr, // delProperty + nullptr, // getProperty + nullptr, // setProperty + XPC_WN_Shared_Proto_Enumerate, // enumerate + XPC_WN_ModsAllowed_Proto_Resolve, // resolve + nullptr, // mayResolve + XPC_WN_Shared_Proto_Finalize, // finalize + nullptr, // call + nullptr, // construct + nullptr, // hasInstance + XPC_WN_Shared_Proto_Trace, // trace +}; + static const js::ClassExtension XPC_WN_Shared_Proto_ClassExtension = { nullptr, /* weakmapKeyDelegateOp */ XPC_WN_Shared_Proto_ObjectMoved }; const js::Class XPC_WN_ModsAllowed_WithCall_Proto_JSClass = { - "XPC_WN_ModsAllowed_WithCall_Proto_JSClass", // name; - WRAPPER_FLAGS, // flags; - - /* Function pointer members. */ - nullptr, // addProperty; - nullptr, // delProperty; - nullptr, // getProperty; - nullptr, // setProperty; - XPC_WN_Shared_Proto_Enumerate, // enumerate; - XPC_WN_ModsAllowed_Proto_Resolve, // resolve; - nullptr, // mayResolve; - XPC_WN_Shared_Proto_Finalize, // finalize; - - /* Optionally non-null members start here. */ - nullptr, // call; - nullptr, // construct; - nullptr, // hasInstance; - XPC_WN_Shared_Proto_Trace, // trace; - + "XPC_WN_ModsAllowed_WithCall_Proto_JSClass", + WRAPPER_FLAGS, + &XPC_WN_ModsAllowed_Proto_JSClassOps, JS_NULL_CLASS_SPEC, &XPC_WN_Shared_Proto_ClassExtension, XPC_WN_WithCall_ObjectOps }; const js::Class XPC_WN_ModsAllowed_NoCall_Proto_JSClass = { - "XPC_WN_ModsAllowed_NoCall_Proto_JSClass", // name; - WRAPPER_FLAGS, // flags; - - /* Function pointer members. */ - nullptr, // addProperty; - nullptr, // delProperty; - nullptr, // getProperty; - nullptr, // setProperty; - XPC_WN_Shared_Proto_Enumerate, // enumerate; - XPC_WN_ModsAllowed_Proto_Resolve, // resolve; - nullptr, // mayResolve; - XPC_WN_Shared_Proto_Finalize, // finalize; - - /* Optionally non-null members start here. */ - nullptr, // call; - nullptr, // construct; - nullptr, // hasInstance; - XPC_WN_Shared_Proto_Trace, // trace; - + "XPC_WN_ModsAllowed_NoCall_Proto_JSClass", + WRAPPER_FLAGS, + &XPC_WN_ModsAllowed_Proto_JSClassOps, JS_NULL_CLASS_SPEC, &XPC_WN_Shared_Proto_ClassExtension, XPC_WN_NoCall_ObjectOps @@ -1367,51 +1347,34 @@ XPC_WN_NoMods_Proto_Resolve(JSContext* cx, HandleObject obj, HandleId id, bool* JSPROP_ENUMERATE, resolvedp); } +static const js::ClassOps XPC_WN_NoMods_Proto_JSClassOps = { + XPC_WN_OnlyIWrite_Proto_AddPropertyStub, // addProperty + XPC_WN_CantDeletePropertyStub, // delProperty + nullptr, // getProperty + nullptr, // setProperty + XPC_WN_Shared_Proto_Enumerate, // enumerate + XPC_WN_NoMods_Proto_Resolve, // resolve + nullptr, // mayResolve + XPC_WN_Shared_Proto_Finalize, // finalize + nullptr, // call + nullptr, // construct + nullptr, // hasInstance + XPC_WN_Shared_Proto_Trace, // trace +}; + const js::Class XPC_WN_NoMods_WithCall_Proto_JSClass = { - "XPC_WN_NoMods_WithCall_Proto_JSClass", // name; - WRAPPER_FLAGS, // flags; - - /* Mandatory non-null function pointer members. */ - XPC_WN_OnlyIWrite_Proto_AddPropertyStub, // addProperty; - XPC_WN_CantDeletePropertyStub, // delProperty; - nullptr, // getProperty; - nullptr, // setProperty; - XPC_WN_Shared_Proto_Enumerate, // enumerate; - XPC_WN_NoMods_Proto_Resolve, // resolve; - nullptr, // mayResolve; - XPC_WN_Shared_Proto_Finalize, // finalize; - - /* Optionally non-null members start here. */ - nullptr, // call; - nullptr, // construct; - nullptr, // hasInstance; - XPC_WN_Shared_Proto_Trace, // trace; - + "XPC_WN_NoMods_WithCall_Proto_JSClass", + WRAPPER_FLAGS, + &XPC_WN_NoMods_Proto_JSClassOps, JS_NULL_CLASS_SPEC, &XPC_WN_Shared_Proto_ClassExtension, XPC_WN_WithCall_ObjectOps }; const js::Class XPC_WN_NoMods_NoCall_Proto_JSClass = { - "XPC_WN_NoMods_NoCall_Proto_JSClass", // name; - WRAPPER_FLAGS, // flags; - - /* Mandatory non-null function pointer members. */ - XPC_WN_OnlyIWrite_Proto_AddPropertyStub, // addProperty; - XPC_WN_CantDeletePropertyStub, // delProperty; - nullptr, // getProperty; - nullptr, // setProperty; - XPC_WN_Shared_Proto_Enumerate, // enumerate; - XPC_WN_NoMods_Proto_Resolve, // resolve; - nullptr, // mayResolve; - XPC_WN_Shared_Proto_Finalize, // finalize; - - /* Optionally non-null members start here. */ - nullptr, // call; - nullptr, // construct; - nullptr, // hasInstance; - XPC_WN_Shared_Proto_Trace, // trace; - + "XPC_WN_NoMods_NoCall_Proto_JSClass", + WRAPPER_FLAGS, + &XPC_WN_NoMods_Proto_JSClassOps, JS_NULL_CLASS_SPEC, &XPC_WN_Shared_Proto_ClassExtension, XPC_WN_NoCall_ObjectOps @@ -1488,31 +1451,31 @@ static_assert(((WRAPPER_FLAGS >> JSCLASS_RESERVED_SLOTS_SHIFT) & JSCLASS_RESERVED_SLOTS_MASK) == 0, "WRAPPER_FLAGS should not include any reserved slots"); +static const js::ClassOps XPC_WN_Tearoff_JSClassOps = { + XPC_WN_OnlyIWrite_AddPropertyStub, // addProperty + XPC_WN_CantDeletePropertyStub, // delProperty + nullptr, // getProperty + nullptr, // setProperty + XPC_WN_TearOff_Enumerate, // enumerate + XPC_WN_TearOff_Resolve, // resolve + nullptr, // mayResolve + XPC_WN_TearOff_Finalize, // finalize + nullptr, // call + nullptr, // construct + nullptr, // hasInstance + nullptr, // trace +}; + static const js::ClassExtension XPC_WN_Tearoff_JSClassExtension = { - nullptr, // weakmapKeyDelegateOp + nullptr, // weakmapKeyDelegateOp XPC_WN_TearOff_ObjectMoved }; const js::Class XPC_WN_Tearoff_JSClass = { - "WrappedNative_TearOff", // name; + "WrappedNative_TearOff", WRAPPER_FLAGS | - JSCLASS_HAS_RESERVED_SLOTS(XPC_WN_TEAROFF_RESERVED_SLOTS), // flags; - XPC_WN_OnlyIWrite_AddPropertyStub, // addProperty; - XPC_WN_CantDeletePropertyStub, // delProperty; - nullptr, // getProperty; - nullptr, // setProperty; - XPC_WN_TearOff_Enumerate, // enumerate; - XPC_WN_TearOff_Resolve, // resolve; - nullptr, // mayResolve; - XPC_WN_TearOff_Finalize, // finalize; - - /* Optionally non-null members start here. */ - nullptr, // call - nullptr, // construct - nullptr, // hasInstance - nullptr, // trace + JSCLASS_HAS_RESERVED_SLOTS(XPC_WN_TEAROFF_RESERVED_SLOTS), + &XPC_WN_Tearoff_JSClassOps, JS_NULL_CLASS_SPEC, - - // ClassExtension &XPC_WN_Tearoff_JSClassExtension }; diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index ab0d328f6ddf..852a5b59fdc9 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -1650,8 +1650,8 @@ public: XPCNativeScriptableShared(uint32_t aFlags, char* aName, bool aPopulate); ~XPCNativeScriptableShared() { - if (mJSClass.name) - free((void*)mJSClass.name); + free((void*)mJSClass.name); + free((void*)mJSClass.cOps); MOZ_COUNT_DTOR(XPCNativeScriptableShared); } @@ -1667,6 +1667,10 @@ public: private: XPCNativeScriptableFlags mFlags; + + // This is an unusual js::Class instance: its name and cOps members are + // heap-allocated, unlike all other instances for which they are statically + // allocated. So we must free them in the destructor. js::Class mJSClass; }; diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index 149d513fcd7f..2195ec29978f 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -1055,11 +1055,15 @@ ExpandoObjectFinalize(JSFreeOp* fop, JSObject* obj) NS_RELEASE(principal); } +static const JSClassOps ExpandoObjectClassOps = { + nullptr, nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, ExpandoObjectFinalize +}; + const JSClass ExpandoObjectClass = { "XrayExpandoObject", JSCLASS_HAS_RESERVED_SLOTS(JSSLOT_EXPANDO_COUNT), - nullptr, nullptr, nullptr, nullptr, - nullptr, nullptr, nullptr, ExpandoObjectFinalize + &ExpandoObjectClassOps }; bool @@ -1706,14 +1710,15 @@ DOMXrayTraits::call(JSContext* cx, HandleObject wrapper, // are using "legacycaller", which basically means plug-ins. We want to // call those on the content compartment. if (clasp->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS) { - if (!clasp->call) { + if (JSNative call = clasp->getCall()) { + // call it on the Xray compartment + if (!call(cx, args.length(), args.base())) + return false; + } else { RootedValue v(cx, ObjectValue(*wrapper)); js::ReportIsNotFunction(cx, v); return false; } - // call it on the Xray compartment - if (!clasp->call(cx, args.length(), args.base())) - return false; } else { // This is only reached for WebIDL instance objects, and in practice // only for plugins. Just call them on the content compartment. @@ -1732,13 +1737,14 @@ DOMXrayTraits::construct(JSContext* cx, HandleObject wrapper, const js::Class* clasp = js::GetObjectClass(obj); // See comments in DOMXrayTraits::call() explaining what's going on here. if (clasp->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS) { - if (!clasp->construct) { + if (JSNative construct = clasp->getConstruct()) { + if (!construct(cx, args.length(), args.base())) + return false; + } else { RootedValue v(cx, ObjectValue(*wrapper)); js::ReportIsNotFunction(cx, v); return false; } - if (!clasp->construct(cx, args.length(), args.base())) - return false; } else { if (!baseInstance.construct(cx, wrapper, args)) return false; diff --git a/netwerk/base/ProxyAutoConfig.cpp b/netwerk/base/ProxyAutoConfig.cpp index a93c798ca170..7509e1a98b40 100644 --- a/netwerk/base/ProxyAutoConfig.cpp +++ b/netwerk/base/ProxyAutoConfig.cpp @@ -666,15 +666,19 @@ private: } }; -const JSClass JSRuntimeWrapper::sGlobalClass = { - "PACResolutionThreadGlobal", - JSCLASS_GLOBAL_FLAGS, +static const JSClassOps sJSRuntimeWrapperGlobalClassOps = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook }; +const JSClass JSRuntimeWrapper::sGlobalClass = { + "PACResolutionThreadGlobal", + JSCLASS_GLOBAL_FLAGS, + &sJSRuntimeWrapperGlobalClassOps +}; + void ProxyAutoConfig::SetThreadLocalIndex(uint32_t index) { diff --git a/toolkit/components/finalizationwitness/FinalizationWitnessService.cpp b/toolkit/components/finalizationwitness/FinalizationWitnessService.cpp index febe5f6d284c..1cee9dd3c840 100644 --- a/toolkit/components/finalizationwitness/FinalizationWitnessService.cpp +++ b/toolkit/components/finalizationwitness/FinalizationWitnessService.cpp @@ -116,9 +116,7 @@ void Finalize(JSFreeOp *fop, JSObject *objSelf) // during shutdown. In that case, there is not much we can do. } -static const JSClass sWitnessClass = { - "FinalizationWitness", - JSCLASS_HAS_RESERVED_SLOTS(WITNESS_INSTANCES_SLOTS), +static const JSClassOps sWitnessClassOps = { nullptr /* addProperty */, nullptr /* delProperty */, nullptr /* getProperty */, @@ -129,6 +127,12 @@ static const JSClass sWitnessClass = { Finalize /* finalize */ }; +static const JSClass sWitnessClass = { + "FinalizationWitness", + JSCLASS_HAS_RESERVED_SLOTS(WITNESS_INSTANCES_SLOTS), + &sWitnessClassOps +}; + bool IsWitness(JS::Handle v) { return v.isObject() && JS_GetClass(&v.toObject()) == &sWitnessClass; diff --git a/xpcom/base/CycleCollectedJSRuntime.cpp b/xpcom/base/CycleCollectedJSRuntime.cpp index ef13f08b0944..391677616c3b 100644 --- a/xpcom/base/CycleCollectedJSRuntime.cpp +++ b/xpcom/base/CycleCollectedJSRuntime.cpp @@ -1249,7 +1249,7 @@ CycleCollectedJSRuntime::JSObjectsTenured() if (!JS::ObjectIsTenured(wrapper)) { MOZ_ASSERT(!cache->PreservingWrapper()); const JSClass* jsClass = js::GetObjectJSClass(wrapper); - jsClass->finalize(nullptr, wrapper); + jsClass->doFinalize(nullptr, wrapper); } } diff --git a/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp b/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp index 56a6013d9139..4bf4f0958264 100644 --- a/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp +++ b/xpcom/glue/tests/gtest/TestGCPostBarriers.cpp @@ -84,14 +84,18 @@ RunTest(JSRuntime* rt, JSContext* cx, ArrayT* array) static void CreateGlobalAndRunTest(JSRuntime* rt, JSContext* cx) { - static const JSClass GlobalClass = { - "global", JSCLASS_GLOBAL_FLAGS, + static const JSClassOps GlobalClassOps = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, JS_GlobalObjectTraceHook }; + static const JSClass GlobalClass = { + "global", JSCLASS_GLOBAL_FLAGS, + &GlobalClassOps + }; + JS::CompartmentOptions options; options.behaviors().setVersion(JSVERSION_LATEST); JS::PersistentRootedObject global(cx);