summaryrefslogtreecommitdiffstats
path: root/dom/bindings
diff options
context:
space:
mode:
Diffstat (limited to 'dom/bindings')
-rw-r--r--dom/bindings/BindingUtils.cpp377
-rw-r--r--dom/bindings/BindingUtils.h204
-rw-r--r--dom/bindings/Bindings.conf14
-rw-r--r--dom/bindings/CallbackObject.cpp2
-rw-r--r--dom/bindings/Codegen.py345
-rw-r--r--dom/bindings/Configuration.py91
-rw-r--r--dom/bindings/DOMJSClass.h21
-rw-r--r--dom/bindings/JSSlots.h17
-rw-r--r--dom/bindings/WebIDLGlobalNameHash.cpp25
-rw-r--r--dom/bindings/mozwebidlcodegen/__init__.py79
-rw-r--r--dom/bindings/mozwebidlcodegen/test/test_mozwebidlcodegen.py9
-rw-r--r--dom/bindings/nsIScriptError.idl12
-rw-r--r--dom/bindings/parser/WebIDL.py234
-rw-r--r--dom/bindings/test/TestBindingHeader.h65
-rw-r--r--dom/bindings/test/TestCodeGen.webidl18
-rw-r--r--dom/bindings/test/TestExampleGen.webidl5
-rw-r--r--dom/bindings/test/test_dom_xrays.html23
17 files changed, 995 insertions, 546 deletions
diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp
index 4cccda7a4b..11d12dd364 100644
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -758,42 +758,30 @@ bool DefineLegacyUnforgeableAttributes(
return DefinePrefable(cx, obj, props);
}
-// We should use JSFunction objects for interface objects, but we need a custom
-// hasInstance hook because we have new interface objects on prototype chains of
-// old (XPConnect-based) bindings. We also need Xrays and arbitrary numbers of
-// reserved slots (e.g. for legacy factory functions). So we define a custom
-// funToString ObjectOps member for interface objects.
-JSString* InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
- bool /* isToSource */) {
- const JSClass* clasp = JS::GetClass(aObject);
- MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));
-
- const DOMIfaceJSClass* ifaceJSClass = DOMIfaceJSClass::FromJSClass(clasp);
- return JS_NewStringCopyZ(aCx, ifaceJSClass->mFunToString);
+bool InterfaceObjectJSNative(JSContext* cx, unsigned argc, JS::Value* vp) {
+ JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
+ return NativeHolderFromInterfaceObject(&args.callee())->mNative(cx, argc, vp);
}
-bool Constructor(JSContext* cx, unsigned argc, JS::Value* vp) {
+bool LegacyFactoryFunctionJSNative(JSContext* cx, unsigned argc,
+ JS::Value* vp) {
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
- const JS::Value& v = js::GetFunctionNativeReserved(
- &args.callee(), CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT);
- const JSNativeHolder* nativeHolder =
- static_cast<const JSNativeHolder*>(v.toPrivate());
- return (nativeHolder->mNative)(cx, argc, vp);
-}
-
-static JSObject* CreateConstructor(JSContext* cx, JS::Handle<JSObject*> global,
- const char* name,
- const JSNativeHolder* nativeHolder,
- unsigned ctorNargs) {
- JSFunction* fun = js::NewFunctionWithReserved(cx, Constructor, ctorNargs,
- JSFUN_CONSTRUCTOR, name);
+ return NativeHolderFromLegacyFactoryFunction(&args.callee())
+ ->mNative(cx, argc, vp);
+}
+
+static JSObject* CreateLegacyFactoryFunction(JSContext* cx, jsid name,
+ const JSNativeHolder* nativeHolder,
+ unsigned ctorNargs) {
+ JSFunction* fun = js::NewFunctionByIdWithReserved(
+ cx, LegacyFactoryFunctionJSNative, ctorNargs, JSFUN_CONSTRUCTOR, name);
if (!fun) {
return nullptr;
}
JSObject* constructor = JS_GetFunctionObject(fun);
js::SetFunctionNativeReserved(
- constructor, CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT,
+ constructor, LEGACY_FACTORY_FUNCTION_NATIVE_HOLDER_RESERVED_SLOT,
JS::PrivateValue(const_cast<JSNativeHolder*>(nativeHolder)));
return constructor;
}
@@ -846,11 +834,11 @@ static bool InterfaceIsInstance(JSContext* cx, unsigned argc, JS::Value* vp) {
return true;
}
- // If "this" doesn't have a DOMIfaceAndProtoJSClass, it's not a DOM
- // constructor, so just fall back. But note that we should
- // CheckedUnwrapStatic here, because otherwise we won't get the right answers.
- // The static version is OK, because we're looking for DOM constructors, which
- // are not cross-origin objects.
+ // If "this" is not an interface object, likewise return false (again, like
+ // OrdinaryHasInstance). But note that we should CheckedUnwrapStatic here,
+ // because otherwise we won't get the right answers.
+ // The static version is OK, because we're looking for interface objects,
+ // which are not cross-origin objects.
JS::Rooted<JSObject*> thisObj(
cx, js::CheckedUnwrapStatic(&args.thisv().toObject()));
if (!thisObj) {
@@ -859,20 +847,16 @@ static bool InterfaceIsInstance(JSContext* cx, unsigned argc, JS::Value* vp) {
return true;
}
- const JSClass* thisClass = JS::GetClass(thisObj);
-
- if (!IsDOMIfaceAndProtoClass(thisClass)) {
+ if (!IsInterfaceObject(thisObj)) {
args.rval().setBoolean(false);
return true;
}
- const DOMIfaceAndProtoJSClass* clasp =
- DOMIfaceAndProtoJSClass::FromJSClass(thisClass);
+ const DOMInterfaceInfo* interfaceInfo = InterfaceInfoFromObject(thisObj);
- // If "this" isn't a DOM constructor or is a constructor for an interface
- // without a prototype, just fall back.
- if (clasp->mType != eInterface ||
- clasp->mPrototypeID == prototypes::id::_ID_Count) {
+ // If "this" is a constructor for an interface without a prototype, just fall
+ // back.
+ if (interfaceInfo->mPrototypeID == prototypes::id::_ID_Count) {
args.rval().setBoolean(false);
return true;
}
@@ -881,13 +865,13 @@ static bool InterfaceIsInstance(JSContext* cx, unsigned argc, JS::Value* vp) {
const DOMJSClass* domClass = GetDOMClass(
js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false));
- if (domClass &&
- domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID) {
+ if (domClass && domClass->mInterfaceChain[interfaceInfo->mDepth] ==
+ interfaceInfo->mPrototypeID) {
args.rval().setBoolean(true);
return true;
}
- if (IsRemoteObjectProxy(instance, clasp->mPrototypeID)) {
+ if (IsRemoteObjectProxy(instance, interfaceInfo->mPrototypeID)) {
args.rval().setBoolean(true);
return true;
}
@@ -896,80 +880,85 @@ static bool InterfaceIsInstance(JSContext* cx, unsigned argc, JS::Value* vp) {
return true;
}
-// name must be an atom (or JS::PropertyKey::NonIntAtom will assert).
-static JSObject* CreateInterfaceObject(
- JSContext* cx, JS::Handle<JSObject*> global,
- JS::Handle<JSObject*> constructorProto,
- const DOMIfaceJSClass* constructorClass, unsigned ctorNargs,
- const LegacyFactoryFunction* legacyFactoryFunctions,
- JS::Handle<JSObject*> proto, const NativeProperties* properties,
- const NativeProperties* chromeOnlyProperties, JS::Handle<JSString*> name,
- bool isChrome, bool defineOnGlobal, const char* const* legacyWindowAliases,
- bool isNamespace) {
- JS::Rooted<JSObject*> constructor(cx);
- MOZ_ASSERT(constructorProto);
- MOZ_ASSERT(constructorClass);
- constructor = JS_NewObjectWithGivenProto(cx, constructorClass->ToJSClass(),
- constructorProto);
- if (!constructor) {
- return nullptr;
- }
-
- if (!isNamespace) {
- if (!JS_DefineProperty(cx, constructor, "length", ctorNargs,
- JSPROP_READONLY)) {
- return nullptr;
- }
-
- if (!JS_DefineProperty(cx, constructor, "name", name, JSPROP_READONLY)) {
- return nullptr;
- }
- }
-
- if (constructorClass->wantsInterfaceIsInstance && isChrome &&
- !JS_DefineFunction(cx, constructor, "isInstance", InterfaceIsInstance, 1,
- // Don't bother making it enumerable
- 0)) {
- return nullptr;
- }
-
+bool InitInterfaceOrNamespaceObject(
+ JSContext* cx, JS::Handle<JSObject*> obj,
+ const NativeProperties* properties,
+ const NativeProperties* chromeOnlyProperties, bool isChrome) {
if (properties) {
if (properties->HasStaticMethods() &&
- !DefinePrefable(cx, constructor, properties->StaticMethods())) {
- return nullptr;
+ !DefinePrefable(cx, obj, properties->StaticMethods())) {
+ return false;
}
if (properties->HasStaticAttributes() &&
- !DefinePrefable(cx, constructor, properties->StaticAttributes())) {
- return nullptr;
+ !DefinePrefable(cx, obj, properties->StaticAttributes())) {
+ return false;
}
if (properties->HasConstants() &&
- !DefinePrefable(cx, constructor, properties->Constants())) {
- return nullptr;
+ !DefinePrefable(cx, obj, properties->Constants())) {
+ return false;
}
}
if (chromeOnlyProperties && isChrome) {
if (chromeOnlyProperties->HasStaticMethods() &&
- !DefinePrefable(cx, constructor,
- chromeOnlyProperties->StaticMethods())) {
- return nullptr;
+ !DefinePrefable(cx, obj, chromeOnlyProperties->StaticMethods())) {
+ return false;
}
if (chromeOnlyProperties->HasStaticAttributes() &&
- !DefinePrefable(cx, constructor,
- chromeOnlyProperties->StaticAttributes())) {
- return nullptr;
+ !DefinePrefable(cx, obj, chromeOnlyProperties->StaticAttributes())) {
+ return false;
}
if (chromeOnlyProperties->HasConstants() &&
- !DefinePrefable(cx, constructor, chromeOnlyProperties->Constants())) {
+ !DefinePrefable(cx, obj, chromeOnlyProperties->Constants())) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// name must be an atom (or JS::PropertyKey::NonIntAtom will assert).
+static JSObject* CreateInterfaceObject(
+ JSContext* cx, JS::Handle<JSObject*> global,
+ JS::Handle<JSObject*> interfaceProto, const DOMInterfaceInfo* interfaceInfo,
+ unsigned ctorNargs,
+ const Span<const LegacyFactoryFunction>& legacyFactoryFunctions,
+ JS::Handle<JSObject*> proto, const NativeProperties* properties,
+ const NativeProperties* chromeOnlyProperties, JS::Handle<JSString*> name,
+ bool isChrome, bool defineOnGlobal,
+ const char* const* legacyWindowAliases) {
+ MOZ_ASSERT(interfaceProto);
+ MOZ_ASSERT(interfaceInfo);
+
+ JS::Rooted<jsid> nameId(cx, JS::PropertyKey::NonIntAtom(name));
+
+ JS::Rooted<JSObject*> constructor(cx);
+ {
+ JSFunction* fun = js::NewFunctionByIdWithReservedAndProto(
+ cx, InterfaceObjectJSNative, interfaceProto, ctorNargs,
+ JSFUN_CONSTRUCTOR, nameId);
+ if (!fun) {
return nullptr;
}
+
+ constructor = JS_GetFunctionObject(fun);
}
- if (isNamespace && !DefineToStringTag(cx, constructor, name)) {
+ js::SetFunctionNativeReserved(
+ constructor, INTERFACE_OBJECT_INFO_RESERVED_SLOT,
+ JS::PrivateValue(const_cast<DOMInterfaceInfo*>(interfaceInfo)));
+
+ // Eagerly force creation of the .length and .name properties, because they
+ // need to be defined before the .prototype property (CreateBuiltinFunction
+ // called from the WebIDL spec sets them, and then the .prototype property is
+ // defined in the WebIDL spec itself).
+ bool unused;
+ if (!JS_HasProperty(cx, constructor, "length", &unused) ||
+ !JS_HasProperty(cx, constructor, "name", &unused)) {
return nullptr;
}
@@ -977,8 +966,19 @@ static JSObject* CreateInterfaceObject(
return nullptr;
}
- JS::Rooted<jsid> nameStr(cx, JS::PropertyKey::NonIntAtom(name));
- if (defineOnGlobal && !DefineConstructor(cx, global, nameStr, constructor)) {
+ if (!InitInterfaceOrNamespaceObject(cx, constructor, properties,
+ chromeOnlyProperties, isChrome)) {
+ return nullptr;
+ }
+
+ if (defineOnGlobal && !DefineConstructor(cx, global, nameId, constructor)) {
+ return nullptr;
+ }
+
+ if (interfaceInfo->wantsInterfaceIsInstance && isChrome &&
+ !JS_DefineFunction(cx, constructor, "isInstance", InterfaceIsInstance, 1,
+ // Don't bother making it enumerable
+ 0)) {
return nullptr;
}
@@ -990,25 +990,28 @@ static JSObject* CreateInterfaceObject(
}
}
- if (legacyFactoryFunctions) {
- int legacyFactoryFunctionSlot = DOM_INTERFACE_SLOTS_BASE;
- while (legacyFactoryFunctions->mName) {
- JS::Rooted<JSObject*> legacyFactoryFunction(
- cx, CreateConstructor(cx, global, legacyFactoryFunctions->mName,
- &legacyFactoryFunctions->mHolder,
- legacyFactoryFunctions->mNargs));
- if (!legacyFactoryFunction ||
- !JS_DefineProperty(cx, legacyFactoryFunction, "prototype", proto,
- JSPROP_PERMANENT | JSPROP_READONLY) ||
- (defineOnGlobal &&
- !DefineConstructor(cx, global, legacyFactoryFunctions->mName,
- legacyFactoryFunction))) {
- return nullptr;
- }
- JS::SetReservedSlot(constructor, legacyFactoryFunctionSlot++,
- JS::ObjectValue(*legacyFactoryFunction));
- ++legacyFactoryFunctions;
+ int legacyFactoryFunctionSlot =
+ INTERFACE_OBJECT_FIRST_LEGACY_FACTORY_FUNCTION;
+ for (const LegacyFactoryFunction& lff : legacyFactoryFunctions) {
+ JSString* fname = JS_AtomizeString(cx, lff.mName);
+ if (!fname) {
+ return nullptr;
+ }
+
+ nameId = JS::PropertyKey::NonIntAtom(fname);
+
+ JS::Rooted<JSObject*> legacyFactoryFunction(
+ cx, CreateLegacyFactoryFunction(cx, nameId, &lff.mHolder, lff.mNargs));
+ if (!legacyFactoryFunction ||
+ !JS_DefineProperty(cx, legacyFactoryFunction, "prototype", proto,
+ JSPROP_PERMANENT | JSPROP_READONLY) ||
+ (defineOnGlobal &&
+ !DefineConstructor(cx, global, nameId, legacyFactoryFunction))) {
+ return nullptr;
}
+ js::SetFunctionNativeReserved(constructor, legacyFactoryFunctionSlot,
+ JS::ObjectValue(*legacyFactoryFunction));
+ ++legacyFactoryFunctionSlot;
}
return constructor;
@@ -1101,18 +1104,20 @@ bool DefineProperties(JSContext* cx, JS::Handle<JSObject*> obj,
return true;
}
+namespace binding_detail {
+
void CreateInterfaceObjects(
JSContext* cx, JS::Handle<JSObject*> global,
JS::Handle<JSObject*> protoProto, const DOMIfaceAndProtoJSClass* protoClass,
- JS::Heap<JSObject*>* protoCache, JS::Handle<JSObject*> constructorProto,
- const DOMIfaceJSClass* constructorClass, unsigned ctorNargs,
+ JS::Heap<JSObject*>* protoCache, JS::Handle<JSObject*> interfaceProto,
+ const DOMInterfaceInfo* interfaceInfo, unsigned ctorNargs,
bool isConstructorChromeOnly,
- const LegacyFactoryFunction* legacyFactoryFunctions,
+ const Span<const LegacyFactoryFunction>& legacyFactoryFunctions,
JS::Heap<JSObject*>* constructorCache, const NativeProperties* properties,
const NativeProperties* chromeOnlyProperties, const char* name,
bool defineOnGlobal, const char* const* unscopableNames, bool isGlobal,
- const char* const* legacyWindowAliases, bool isNamespace) {
- MOZ_ASSERT(protoClass || constructorClass, "Need at least one class!");
+ const char* const* legacyWindowAliases) {
+ MOZ_ASSERT(protoClass || interfaceInfo, "Need at least a class or info!");
MOZ_ASSERT(
!((properties &&
(properties->HasMethods() || properties->HasAttributes())) ||
@@ -1125,16 +1130,16 @@ void CreateInterfaceObjects(
(chromeOnlyProperties &&
(chromeOnlyProperties->HasStaticMethods() ||
chromeOnlyProperties->HasStaticAttributes()))) ||
- constructorClass,
- "Static methods but no constructorClass!");
+ interfaceInfo,
+ "Static methods but no info!");
MOZ_ASSERT(!protoClass == !protoCache,
"If, and only if, there is an interface prototype object we need "
"to cache it");
- MOZ_ASSERT(bool(constructorClass) == bool(constructorCache),
+ MOZ_ASSERT(bool(interfaceInfo) == bool(constructorCache),
"If, and only if, there is an interface object we need to cache "
"it");
- MOZ_ASSERT(constructorProto || !constructorClass,
- "Must have a constructor proto if we plan to create a constructor "
+ MOZ_ASSERT(interfaceProto || !interfaceInfo,
+ "Must have a interface proto if we plan to create an interface "
"object");
bool isChrome = nsContentUtils::ThreadsafeIsSystemCaller(cx);
@@ -1160,12 +1165,12 @@ void CreateInterfaceObjects(
}
JSObject* interface;
- if (constructorClass) {
+ if (interfaceInfo) {
interface = CreateInterfaceObject(
- cx, global, constructorProto, constructorClass,
+ cx, global, interfaceProto, interfaceInfo,
(isChrome || !isConstructorChromeOnly) ? ctorNargs : 0,
legacyFactoryFunctions, proto, properties, chromeOnlyProperties,
- nameStr, isChrome, defineOnGlobal, legacyWindowAliases, isNamespace);
+ nameStr, isChrome, defineOnGlobal, legacyWindowAliases);
if (!interface) {
if (protoCache) {
// If we fail we need to make sure to clear the value of protoCache we
@@ -1178,6 +1183,45 @@ void CreateInterfaceObjects(
}
}
+} // namespace binding_detail
+
+void CreateNamespaceObject(JSContext* cx, JS::Handle<JSObject*> global,
+ JS::Handle<JSObject*> namespaceProto,
+ const DOMIfaceAndProtoJSClass& namespaceClass,
+ JS::Heap<JSObject*>* namespaceCache,
+ const NativeProperties* properties,
+ const NativeProperties* chromeOnlyProperties,
+ const char* name, bool defineOnGlobal) {
+ JS::Rooted<JSString*> nameStr(cx, JS_AtomizeString(cx, name));
+ if (!nameStr) {
+ return;
+ }
+ JS::Rooted<jsid> nameId(cx, JS::PropertyKey::NonIntAtom(nameStr));
+
+ JS::Rooted<JSObject*> namespaceObj(
+ cx, JS_NewObjectWithGivenProto(cx, namespaceClass.ToJSClass(),
+ namespaceProto));
+ if (!namespaceObj) {
+ return;
+ }
+
+ if (!InitInterfaceOrNamespaceObject(
+ cx, namespaceObj, properties, chromeOnlyProperties,
+ nsContentUtils::ThreadsafeIsSystemCaller(cx))) {
+ return;
+ }
+
+ if (defineOnGlobal && !DefineConstructor(cx, global, nameId, namespaceObj)) {
+ return;
+ }
+
+ if (!DefineToStringTag(cx, namespaceObj, nameStr)) {
+ return;
+ }
+
+ *namespaceCache = namespaceObj;
+}
+
// Only set aAllowNativeWrapper to false if you really know you need it; if in
// doubt use true. Setting it to false disables security wrappers.
static bool NativeInterface2JSObjectAndThrowIfFailed(
@@ -1461,14 +1505,9 @@ bool ThrowConstructorWithoutNew(JSContext* cx, const char* name) {
return ThrowErrorMessage<MSG_CONSTRUCTOR_WITHOUT_NEW>(cx, name);
}
-inline const NativePropertyHooks* GetNativePropertyHooksFromConstructorFunction(
+inline const NativePropertyHooks* GetNativePropertyHooksFromJSNative(
JS::Handle<JSObject*> obj) {
- MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
- const JS::Value& v = js::GetFunctionNativeReserved(
- obj, CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT);
- const JSNativeHolder* nativeHolder =
- static_cast<const JSNativeHolder*>(v.toPrivate());
- return nativeHolder->mPropertyHooks;
+ return NativeHolderFromObject(obj)->mPropertyHooks;
}
inline const NativePropertyHooks* GetNativePropertyHooks(
@@ -1484,7 +1523,7 @@ inline const NativePropertyHooks* GetNativePropertyHooks(
if (JS_ObjectIsFunction(obj)) {
type = eInterface;
- return GetNativePropertyHooksFromConstructorFunction(obj);
+ return GetNativePropertyHooksFromJSNative(obj);
}
MOZ_ASSERT(IsDOMIfaceAndProtoClass(JS::GetClass(obj)));
@@ -1855,23 +1894,20 @@ static bool ResolvePrototypeOrConstructor(
}
if (id.get() == GetJSIDByIndex(cx, XPCJSContext::IDX_ISINSTANCE)) {
- const JSClass* objClass = JS::GetClass(obj);
- if (IsDOMIfaceAndProtoClass(objClass)) {
- const DOMIfaceJSClass* clazz = DOMIfaceJSClass::FromJSClass(objClass);
- if (clazz->wantsInterfaceIsInstance) {
- cacheOnHolder = true;
-
- JSObject* funObj = XrayCreateFunction(
- cx, wrapper, {InterfaceIsInstance, nullptr}, 1, id);
- if (!funObj) {
- return false;
- }
-
- desc.set(Some(JS::PropertyDescriptor::Data(
- JS::ObjectValue(*funObj), {JS::PropertyAttribute::Configurable,
- JS::PropertyAttribute::Writable})));
- return true;
+ if (IsInterfaceObject(obj) &&
+ InterfaceInfoFromObject(obj)->wantsInterfaceIsInstance) {
+ cacheOnHolder = true;
+
+ JSObject* funObj = XrayCreateFunction(
+ cx, wrapper, {InterfaceIsInstance, nullptr}, 1, id);
+ if (!funObj) {
+ return false;
}
+
+ desc.set(Some(JS::PropertyDescriptor::Data(
+ JS::ObjectValue(*funObj), {JS::PropertyAttribute::Configurable,
+ JS::PropertyAttribute::Writable})));
+ return true;
}
}
} else if (type == eNamespace) {
@@ -2187,31 +2223,6 @@ NativePropertyHooks sEmptyNativePropertyHooks = {
constructors::id::_ID_Count,
nullptr};
-const JSClassOps sBoringInterfaceObjectClassClassOps = {
- nullptr, /* addProperty */
- nullptr, /* delProperty */
- nullptr, /* enumerate */
- nullptr, /* newEnumerate */
- nullptr, /* resolve */
- nullptr, /* mayResolve */
- nullptr, /* finalize */
- ThrowingConstructor, /* call */
- ThrowingConstructor, /* construct */
- nullptr, /* trace */
-};
-
-const js::ObjectOps sInterfaceObjectClassObjectOps = {
- nullptr, /* lookupProperty */
- nullptr, /* defineProperty */
- nullptr, /* hasProperty */
- nullptr, /* getProperty */
- nullptr, /* setProperty */
- nullptr, /* getOwnPropertyDescriptor */
- nullptr, /* deleteProperty */
- nullptr, /* getElements */
- InterfaceObjectToString, /* funToString */
-};
-
bool GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
bool* found, JS::MutableHandle<JS::Value> vp) {
@@ -3572,16 +3583,8 @@ bool ForEachHandler(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
static inline prototypes::ID GetProtoIdForNewtarget(
JS::Handle<JSObject*> aNewTarget) {
- const JSClass* newTargetClass = JS::GetClass(aNewTarget);
- if (IsDOMIfaceAndProtoClass(newTargetClass)) {
- const DOMIfaceAndProtoJSClass* newTargetIfaceClass =
- DOMIfaceAndProtoJSClass::FromJSClass(newTargetClass);
- if (newTargetIfaceClass->mType == eInterface) {
- return newTargetIfaceClass->mPrototypeID;
- }
- } else if (JS_IsNativeFunction(aNewTarget, Constructor)) {
- return GetNativePropertyHooksFromConstructorFunction(aNewTarget)
- ->mPrototypeID;
+ if (IsDOMConstructor(aNewTarget)) {
+ return GetNativePropertyHooksFromJSNative(aNewTarget)->mPrototypeID;
}
return prototypes::id::_ID_Count;
diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h
index dd7a42b670..1e3049d456 100644
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -698,12 +698,45 @@ struct JSNativeHolder {
const NativePropertyHooks* mPropertyHooks;
};
+// Struct for holding information for WebIDL interface objects (which are
+// function objects). A pointer to this struct is held in the first reserved
+// slot of the function object.
+struct DOMInterfaceInfo {
+ JSNativeHolder nativeHolder;
+
+ ProtoGetter mGetParentProto;
+
+ const prototypes::ID mPrototypeID; // uint16_t
+ const uint32_t mDepth;
+
+ // Boolean indicating whether this object wants a isInstance property
+ // pointing to InterfaceIsInstance defined on it. Only ever true for
+ // interfaces.
+ bool wantsInterfaceIsInstance;
+};
+
struct LegacyFactoryFunction {
const char* mName;
const JSNativeHolder mHolder;
unsigned mNargs;
};
+namespace binding_detail {
+
+void CreateInterfaceObjects(
+ JSContext* cx, JS::Handle<JSObject*> global,
+ JS::Handle<JSObject*> protoProto, const DOMIfaceAndProtoJSClass* protoClass,
+ JS::Heap<JSObject*>* protoCache, JS::Handle<JSObject*> interfaceProto,
+ const DOMInterfaceInfo* interfaceInfo, unsigned ctorNargs,
+ bool isConstructorChromeOnly,
+ const Span<const LegacyFactoryFunction>& legacyFactoryFunctions,
+ JS::Heap<JSObject*>* constructorCache, const NativeProperties* properties,
+ const NativeProperties* chromeOnlyProperties, const char* name,
+ bool defineOnGlobal, const char* const* unscopableNames, bool isGlobal,
+ const char* const* legacyWindowAliases);
+
+} // namespace binding_detail
+
// clang-format off
/*
* Create a DOM interface object (if constructorClass is non-null) and/or a
@@ -712,24 +745,20 @@ struct LegacyFactoryFunction {
* global is used as the parent of the interface object and the interface
* prototype object
* protoProto is the prototype to use for the interface prototype object.
- * interfaceProto is the prototype to use for the interface object. This can be
- * null if both constructorClass and constructor are null (as in,
- * if we're not creating an interface object at all).
* protoClass is the JSClass to use for the interface prototype object.
* This is null if we should not create an interface prototype
* object.
* protoCache a pointer to a JSObject pointer where we should cache the
* interface prototype object. This must be null if protoClass is and
* vice versa.
- * constructorClass is the JSClass to use for the interface object.
- * This is null if we should not create an interface object or
- * if it should be a function object.
- * constructor holds the JSNative to back the interface object which should be a
- * Function, unless constructorClass is non-null in which case it is
- * ignored. If this is null and constructorClass is also null then
- * we should not create an interface object at all.
+ * interfaceProto is the prototype to use for the interface object. This can be
+ * null if interfaceInfo is null (as in, if we're not creating an
+ * interface object at all).
+ * interfaceInfo is the info to use for the interface object. This can be null
+ * if we're not creating an interface object.
* ctorNargs is the length of the constructor function; 0 if no constructor
* isConstructorChromeOnly if true, the constructor is ChromeOnly.
+ * legacyFactoryFunctions the legacy factory functions (can be empty)
* constructorCache a pointer to a JSObject pointer where we should cache the
* interface object. This must be null if both constructorClass
* and constructor are null, and non-null otherwise.
@@ -761,23 +790,66 @@ struct LegacyFactoryFunction {
* char* names of the legacy window aliases for this
* interface.
*
- * At least one of protoClass, constructorClass or constructor should be
- * non-null. If constructorClass or constructor are non-null, the resulting
- * interface object will be defined on the given global with property name
- * |name|, which must also be non-null.
+ * At least one of protoClass or interfaceInfo should be non-null. If
+ * interfaceInfo is non-null, the resulting interface object will be defined on
+ * the given global with property name |name|, which must also be non-null.
*/
// clang-format on
-void CreateInterfaceObjects(
+template <size_t N>
+inline void CreateInterfaceObjects(
JSContext* cx, JS::Handle<JSObject*> global,
JS::Handle<JSObject*> protoProto, const DOMIfaceAndProtoJSClass* protoClass,
- JS::Heap<JSObject*>* protoCache, JS::Handle<JSObject*> constructorProto,
- const DOMIfaceJSClass* constructorClass, unsigned ctorNargs,
+ JS::Heap<JSObject*>* protoCache, JS::Handle<JSObject*> interfaceProto,
+ const DOMInterfaceInfo* interfaceInfo, unsigned ctorNargs,
bool isConstructorChromeOnly,
- const LegacyFactoryFunction* legacyFactoryFunctions,
+ const Span<const LegacyFactoryFunction, N>& legacyFactoryFunctions,
JS::Heap<JSObject*>* constructorCache, const NativeProperties* properties,
const NativeProperties* chromeOnlyProperties, const char* name,
bool defineOnGlobal, const char* const* unscopableNames, bool isGlobal,
- const char* const* legacyWindowAliases, bool isNamespace);
+ const char* const* legacyWindowAliases) {
+ // We're using 1 slot for the interface info already, so we only have
+ // INTERFACE_OBJECT_MAX_SLOTS - 1 slots for legacy factory functions.
+ static_assert(N <= INTERFACE_OBJECT_MAX_SLOTS -
+ INTERFACE_OBJECT_FIRST_LEGACY_FACTORY_FUNCTION);
+
+ return binding_detail::CreateInterfaceObjects(
+ cx, global, protoProto, protoClass, protoCache, interfaceProto,
+ interfaceInfo, ctorNargs, isConstructorChromeOnly, legacyFactoryFunctions,
+ constructorCache, properties, chromeOnlyProperties, name, defineOnGlobal,
+ unscopableNames, isGlobal, legacyWindowAliases);
+}
+
+/*
+ * Create a namespace object.
+ *
+ * global the global on which to install a property named with name pointing to
+ * the namespace object if defineOnGlobal is true.
+ * namespaceProto is the prototype to use for the namespace object.
+ * namespaceClass is the JSClass to use for the namespace object.
+ * namespaceCache a pointer to a JSObject pointer where we should cache the
+ * namespace object.
+ * properties contains the methods, attributes and constants to be defined on
+ * objects in any compartment.
+ * chromeProperties contains the methods, attributes and constants to be defined
+ * on objects in chrome compartments. This must be null if the
+ * namespace doesn't have any ChromeOnly properties or if the
+ * object is being created in non-chrome compartment.
+ * name the name to use for the WebIDL class string, which is the value
+ * that's used for @@toStringTag, and the name of the property on the
+ * global object that would be set to the namespace object.
+ * defineOnGlobal controls whether properties should be defined on the given
+ * global for the namespace object. This can be false in
+ * situations where we want the properties to only appear on
+ * privileged Xrays but not on the unprivileged underlying
+ * global.
+ */
+void CreateNamespaceObject(JSContext* cx, JS::Handle<JSObject*> global,
+ JS::Handle<JSObject*> namespaceProto,
+ const DOMIfaceAndProtoJSClass& namespaceClass,
+ JS::Heap<JSObject*>* namespaceCache,
+ const NativeProperties* properties,
+ const NativeProperties* chromeOnlyProperties,
+ const char* name, bool defineOnGlobal);
/**
* Define the properties (regular and chrome-only) on obj.
@@ -2267,18 +2339,53 @@ inline bool AddStringToIDVector(JSContext* cx,
name);
}
-// We use one constructor JSNative to represent all DOM interface objects (so
-// we can easily detect when we need to wrap them in an Xray wrapper). We store
-// the real JSNative in the mNative member of a JSNativeHolder in the
-// CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT slot of the JSFunction object for a
-// specific interface object. We also store the NativeProperties in the
-// JSNativeHolder.
-// Note that some interface objects are not yet a JSFunction but a normal
-// JSObject with a DOMJSClass, those do not use these slots.
+// We use one JSNative to represent all DOM interface objects (so we can easily
+// detect when we need to wrap them in an Xray wrapper). A pointer to the
+// relevant DOMInterfaceInfo is stored in the
+// INTERFACE_OBJECT_INFO_RESERVED_SLOT slot of the JSFunction object for a
+// specific interface object. We store the real JSNative and the
+// NativeProperties in a JSNativeHolder, held by the DOMInterfaceInfo.
+bool InterfaceObjectJSNative(JSContext* cx, unsigned argc, JS::Value* vp);
+
+inline bool IsInterfaceObject(JSObject* obj) {
+ return JS_IsNativeFunction(obj, InterfaceObjectJSNative);
+}
+
+inline const DOMInterfaceInfo* InterfaceInfoFromObject(JSObject* obj) {
+ MOZ_ASSERT(IsInterfaceObject(obj));
+ const JS::Value& v =
+ js::GetFunctionNativeReserved(obj, INTERFACE_OBJECT_INFO_RESERVED_SLOT);
+ return static_cast<const DOMInterfaceInfo*>(v.toPrivate());
+}
-enum { CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT = 0 };
+inline const JSNativeHolder* NativeHolderFromInterfaceObject(JSObject* obj) {
+ MOZ_ASSERT(IsInterfaceObject(obj));
+ return &InterfaceInfoFromObject(obj)->nativeHolder;
+}
-bool Constructor(JSContext* cx, unsigned argc, JS::Value* vp);
+// We use one JSNative to represent all legacy factory functions (so we can
+// easily detect when we need to wrap them in an Xray wrapper). We store the
+// real JSNative and the NativeProperties in a JSNativeHolder in the
+// LEGACY_FACTORY_FUNCTION_NATIVE_HOLDER_RESERVED_SLOT slot of the JSFunction
+// object.
+bool LegacyFactoryFunctionJSNative(JSContext* cx, unsigned argc, JS::Value* vp);
+
+inline bool IsLegacyFactoryFunction(JSObject* obj) {
+ return JS_IsNativeFunction(obj, LegacyFactoryFunctionJSNative);
+}
+
+inline const JSNativeHolder* NativeHolderFromLegacyFactoryFunction(
+ JSObject* obj) {
+ MOZ_ASSERT(IsLegacyFactoryFunction(obj));
+ const JS::Value& v = js::GetFunctionNativeReserved(
+ obj, LEGACY_FACTORY_FUNCTION_NATIVE_HOLDER_RESERVED_SLOT);
+ return static_cast<const JSNativeHolder*>(v.toPrivate());
+}
+
+inline const JSNativeHolder* NativeHolderFromObject(JSObject* obj) {
+ return IsInterfaceObject(obj) ? NativeHolderFromInterfaceObject(obj)
+ : NativeHolderFromLegacyFactoryFunction(obj);
+}
// Implementation of the bits that XrayWrapper needs
@@ -2350,8 +2457,11 @@ inline bool XrayGetNativeProto(JSContext* cx, JS::Handle<JSObject*> obj,
protop.set(JS::GetRealmObjectPrototype(cx));
}
} else if (JS_ObjectIsFunction(obj)) {
- MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
- protop.set(JS::GetRealmFunctionPrototype(cx));
+ if (IsLegacyFactoryFunction(obj)) {
+ protop.set(JS::GetRealmFunctionPrototype(cx));
+ } else {
+ protop.set(InterfaceInfoFromObject(obj)->mGetParentProto(cx));
+ }
} else {
const JSClass* clasp = JS::GetClass(obj);
MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));
@@ -2426,36 +2536,16 @@ inline JSObject* GetCachedSlotStorageObject(JSContext* cx,
extern NativePropertyHooks sEmptyNativePropertyHooks;
-extern const JSClassOps sBoringInterfaceObjectClassClassOps;
-
-extern const js::ObjectOps sInterfaceObjectClassObjectOps;
+inline bool IsDOMConstructor(JSObject* obj) {
+ return IsInterfaceObject(obj) || IsLegacyFactoryFunction(obj);
+}
inline bool UseDOMXray(JSObject* obj) {
const JSClass* clasp = JS::GetClass(obj);
- return IsDOMClass(clasp) || JS_IsNativeFunction(obj, Constructor) ||
+ return IsDOMClass(clasp) || IsDOMConstructor(obj) ||
IsDOMIfaceAndProtoClass(clasp);
}
-inline bool IsDOMConstructor(JSObject* obj) {
- if (JS_IsNativeFunction(obj, dom::Constructor)) {
- // LegacyFactoryFunction, like Image
- return true;
- }
-
- const JSClass* clasp = JS::GetClass(obj);
- // Check for a DOM interface object.
- return dom::IsDOMIfaceAndProtoClass(clasp) &&
- dom::DOMIfaceAndProtoJSClass::FromJSClass(clasp)->mType ==
- dom::eInterface;
-}
-
-#ifdef DEBUG
-inline bool HasConstructor(JSObject* obj) {
- return JS_IsNativeFunction(obj, Constructor) ||
- JS::GetClass(obj)->getConstruct();
-}
-#endif
-
// Helpers for creating a const version of a type.
template <typename T>
const T& Constify(T& arg) {
@@ -3207,10 +3297,6 @@ void DeprecationWarning(JSContext* aCx, JSObject* aObject,
void DeprecationWarning(const GlobalObject& aGlobal,
DeprecatedOperations aOperation);
-// A callback to perform funToString on an interface object
-JSString* InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
- unsigned /* indent */);
-
namespace binding_detail {
// Get a JS global object that can be used for some temporary allocations. The
// idea is that this should be used for situations when you need to operate in
diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf
index 7eed2593aa..d735bcc2ee 100644
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -382,8 +382,8 @@ DOMInterfaces = {
},
'IDBFactory': {
- 'implicitJSContext': [ 'open', 'deleteDatabase', 'openForPrincipal',
- 'deleteForPrincipal' ],
+ 'implicitJSContext': [ 'open', 'deleteDatabase', 'databases',
+ 'openForPrincipal', 'deleteForPrincipal' ],
},
'IDBKeyRange': {
@@ -1890,6 +1890,16 @@ if buildconfig.substs.get("ENABLE_TESTS", False):
'register': False,
},
+ 'TestLegacyFactoryFunctionInterface' : {
+ 'headerFile': 'TestBindingHeader.h',
+ 'register': False,
+ },
+
+ 'TestLegacyFactoryFunctionInterface2' : {
+ 'headerFile': 'TestBindingHeader.h',
+ 'register': False,
+ },
+
'TestNamedDeleterInterface' : {
'headerFile': 'TestBindingHeader.h',
'register': False,
diff --git a/dom/bindings/CallbackObject.cpp b/dom/bindings/CallbackObject.cpp
index 484bba06c0..19370666fd 100644
--- a/dom/bindings/CallbackObject.cpp
+++ b/dom/bindings/CallbackObject.cpp
@@ -29,7 +29,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CallbackObject)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(CallbackObject)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(CallbackObject)
+NS_IMPL_CYCLE_COLLECTING_RELEASE_WITH_LAST_RELEASE(CallbackObject, Reset())
NS_IMPL_CYCLE_COLLECTION_CLASS(CallbackObject)
diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py
index 7a6a28bffc..a6a49f9b2f 100644
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -926,11 +926,51 @@ def InterfaceObjectProtoGetter(descriptor, forXrays=False):
return (protoGetter, protoHandleGetter)
-class CGInterfaceObjectJSClass(CGThing):
- def __init__(self, descriptor, properties):
+class CGNamespaceObjectJSClass(CGThing):
+ def __init__(self, descriptor):
+ CGThing.__init__(self)
+ self.descriptor = descriptor
+
+ def declare(self):
+ # We're purely for internal consumption
+ return ""
+
+ def define(self):
+ (protoGetter, _) = InterfaceObjectProtoGetter(self.descriptor, forXrays=True)
+
+ classString = self.descriptor.interface.getExtendedAttribute("ClassString")
+ if classString is None:
+ classString = self.descriptor.interface.identifier.name
+ else:
+ classString = classString[0]
+ return fill(
+ """
+ static const DOMIfaceAndProtoJSClass sNamespaceObjectClass = {
+ {
+ "${classString}",
+ JSCLASS_IS_DOMIFACEANDPROTOJSCLASS,
+ JS_NULL_CLASS_OPS,
+ JS_NULL_CLASS_SPEC,
+ JS_NULL_CLASS_EXT,
+ JS_NULL_OBJECT_OPS
+ },
+ eNamespace,
+ prototypes::id::_ID_Count,
+ 0,
+ ${hooks},
+ ${protoGetter}
+ };
+ """,
+ classString=classString,
+ hooks=NativePropertyHooks(self.descriptor),
+ protoGetter=protoGetter,
+ )
+
+
+class CGInterfaceObjectInfo(CGThing):
+ def __init__(self, descriptor):
CGThing.__init__(self)
self.descriptor = descriptor
- self.properties = properties
def declare(self):
# We're purely for internal consumption
@@ -938,104 +978,31 @@ class CGInterfaceObjectJSClass(CGThing):
def define(self):
if self.descriptor.interface.ctor():
- assert not self.descriptor.interface.isNamespace()
ctorname = CONSTRUCT_HOOK_NAME
- elif self.descriptor.interface.isNamespace():
- ctorname = "nullptr"
else:
ctorname = "ThrowingConstructor"
wantsIsInstance = self.descriptor.interface.hasInterfacePrototypeObject()
prototypeID, depth = PrototypeIDAndDepth(self.descriptor)
- slotCount = "DOM_INTERFACE_SLOTS_BASE"
- if len(self.descriptor.interface.legacyFactoryFunctions) > 0:
- slotCount += " + %i /* slots for the legacy factory functions */" % len(
- self.descriptor.interface.legacyFactoryFunctions
- )
(protoGetter, _) = InterfaceObjectProtoGetter(self.descriptor, forXrays=True)
- if ctorname == "ThrowingConstructor":
- ret = ""
- classOpsPtr = "&sBoringInterfaceObjectClassClassOps"
- elif ctorname == "nullptr":
- ret = ""
- classOpsPtr = "JS_NULL_CLASS_OPS"
- else:
- ret = fill(
- """
- static const JSClassOps sInterfaceObjectClassOps = {
- nullptr, /* addProperty */
- nullptr, /* delProperty */
- nullptr, /* enumerate */
- nullptr, /* newEnumerate */
- nullptr, /* resolve */
- nullptr, /* mayResolve */
- nullptr, /* finalize */
- ${ctorname}, /* call */
- ${ctorname}, /* construct */
- nullptr, /* trace */
- };
-
- """,
- ctorname=ctorname,
- )
- classOpsPtr = "&sInterfaceObjectClassOps"
-
- if self.descriptor.interface.isNamespace():
- classString = self.descriptor.interface.getExtendedAttribute("ClassString")
- if classString is None:
- classString = self.descriptor.interface.identifier.name
- else:
- classString = classString[0]
- funToString = "nullptr"
- objectOps = "JS_NULL_OBJECT_OPS"
- else:
- classString = "Function"
- funToString = (
- '"function %s() {\\n [native code]\\n}"'
- % self.descriptor.interface.identifier.name
- )
- # We need non-default ObjectOps so we can actually make
- # use of our funToString.
- objectOps = "&sInterfaceObjectClassObjectOps"
-
- ret = ret + fill(
+ return fill(
"""
- static const DOMIfaceJSClass sInterfaceObjectClass = {
- {
- {
- "${classString}",
- JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}),
- ${classOpsPtr},
- JS_NULL_CLASS_SPEC,
- JS_NULL_CLASS_EXT,
- ${objectOps}
- },
- ${type},
- ${prototypeID},
- ${depth},
- ${hooks},
- ${protoGetter}
- },
+ static const DOMInterfaceInfo sInterfaceObjectInfo = {
+ { ${ctorname}, ${hooks} },
+ ${protoGetter},
+ ${prototypeID},
+ ${depth},
${wantsIsInstance},
- ${funToString}
};
""",
- classString=classString,
- slotCount=slotCount,
- classOpsPtr=classOpsPtr,
+ ctorname=ctorname,
hooks=NativePropertyHooks(self.descriptor),
- objectOps=objectOps,
- type="eNamespace"
- if self.descriptor.interface.isNamespace()
- else "eInterface",
+ protoGetter=protoGetter,
prototypeID=prototypeID,
depth=depth,
- protoGetter=protoGetter,
wantsIsInstance=toStringBool(wantsIsInstance),
- funToString=funToString,
)
- return ret
class CGList(CGThing):
@@ -2323,7 +2290,6 @@ class CGLegacyFactoryFunctions(CGThing):
static const LegacyFactoryFunction legacyFactoryFunctions[] = {
$*{legacyFactoryFunctions}
- { nullptr, { nullptr, nullptr }, 0 }
};
""",
name=self.descriptor.name,
@@ -3538,83 +3504,30 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
self.haveLegacyWindowAliases = haveLegacyWindowAliases
def definition_body(self):
- (protoGetter, protoHandleGetter) = InterfacePrototypeObjectProtoGetter(
- self.descriptor
- )
- if protoHandleGetter is None:
- parentProtoType = "Rooted"
- getParentProto = "aCx, " + protoGetter
- else:
- parentProtoType = "Handle"
- getParentProto = protoHandleGetter
- getParentProto = getParentProto + "(aCx)"
-
- (protoGetter, protoHandleGetter) = InterfaceObjectProtoGetter(self.descriptor)
- if protoHandleGetter is None:
- getConstructorProto = "aCx, " + protoGetter
- constructorProtoType = "Rooted"
- else:
- getConstructorProto = protoHandleGetter
- constructorProtoType = "Handle"
- getConstructorProto += "(aCx)"
-
needInterfaceObject = self.descriptor.interface.hasInterfaceObject()
- needInterfacePrototypeObject = (
- self.descriptor.interface.hasInterfacePrototypeObject()
- )
-
- # if we don't need to create anything, why are we generating this?
- assert needInterfaceObject or needInterfacePrototypeObject
-
- getParentProto = fill(
- """
- JS::${type}<JSObject*> parentProto(${getParentProto});
- if (!parentProto) {
- return;
- }
- """,
- type=parentProtoType,
- getParentProto=getParentProto,
- )
-
- getConstructorProto = fill(
- """
- JS::${type}<JSObject*> constructorProto(${getConstructorProto});
- if (!constructorProto) {
- return;
- }
- """,
- type=constructorProtoType,
- getConstructorProto=getConstructorProto,
- )
-
- if self.descriptor.interface.ctor():
- constructArgs = methodLength(self.descriptor.interface.ctor())
- isConstructorChromeOnly = isChromeOnly(self.descriptor.interface.ctor())
- else:
- constructArgs = 0
- isConstructorChromeOnly = False
- if len(self.descriptor.interface.legacyFactoryFunctions) > 0:
- legacyFactoryFunctions = "legacyFactoryFunctions"
- else:
- legacyFactoryFunctions = "nullptr"
+ if needInterfaceObject:
+ (protoGetter, protoHandleGetter) = InterfaceObjectProtoGetter(
+ self.descriptor
+ )
+ if protoHandleGetter is None:
+ getConstructorProto = "aCx, " + protoGetter
+ constructorProtoType = "Rooted"
+ else:
+ getConstructorProto = protoHandleGetter
+ constructorProtoType = "Handle"
- if needInterfacePrototypeObject:
- protoClass = "&sPrototypeClass"
- protoCache = (
- "&aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::%s)"
- % self.descriptor.name
+ getConstructorProto = fill(
+ """
+ JS::${type}<JSObject*> constructorProto(${getConstructorProto}(aCx));
+ if (!constructorProto) {
+ return;
+ }
+ """,
+ type=constructorProtoType,
+ getConstructorProto=getConstructorProto,
)
- parentProto = "parentProto"
- getParentProto = CGGeneric(getParentProto)
- else:
- protoClass = "nullptr"
- protoCache = "nullptr"
- parentProto = "nullptr"
- getParentProto = None
- if needInterfaceObject:
- interfaceClass = "&sInterfaceObjectClass"
+ interfaceInfo = "&sInterfaceObjectInfo"
interfaceCache = (
"&aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::%s)"
% self.descriptor.name
@@ -3624,12 +3537,11 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
else:
# We don't have slots to store the legacy factory functions.
assert len(self.descriptor.interface.legacyFactoryFunctions) == 0
- interfaceClass = "nullptr"
+ interfaceInfo = "nullptr"
interfaceCache = "nullptr"
getConstructorProto = None
constructorProto = "nullptr"
- isGlobal = self.descriptor.isGlobal() is not None
if self.properties.hasNonChromeOnly():
properties = "sNativeProperties.Upcast()"
else:
@@ -3648,31 +3560,117 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
name = self.descriptor.interface.getClassName()
assert not (needInterfaceObject and " " in name)
- call = fill(
+ if self.descriptor.interface.isNamespace():
+ # If we don't need to create anything, why are we generating this?
+ assert needInterfaceObject
+
+ call = fill(
+ """
+ JS::Heap<JSObject*>* interfaceCache = ${interfaceCache};
+ dom::CreateNamespaceObject(aCx, aGlobal, ${constructorProto},
+ sNamespaceObjectClass,
+ interfaceCache,
+ ${properties},
+ ${chromeProperties},
+ "${name}", aDefineOnGlobal);
+ """,
+ interfaceCache=interfaceCache,
+ constructorProto=constructorProto,
+ properties=properties,
+ chromeProperties=chromeProperties,
+ name=name,
+ )
+ return CGList(
+ [
+ getConstructorProto,
+ CGGeneric(call),
+ ],
+ "\n",
+ ).define()
+
+ needInterfacePrototypeObject = (
+ self.descriptor.interface.hasInterfacePrototypeObject()
+ )
+
+ # If we don't need to create anything, why are we generating this?
+ assert needInterfaceObject or needInterfacePrototypeObject
+
+ if needInterfacePrototypeObject:
+ (protoGetter, protoHandleGetter) = InterfacePrototypeObjectProtoGetter(
+ self.descriptor
+ )
+ if protoHandleGetter is None:
+ parentProtoType = "Rooted"
+ getParentProto = "aCx, " + protoGetter
+ else:
+ parentProtoType = "Handle"
+ getParentProto = protoHandleGetter
+
+ getParentProto = fill(
+ """
+ JS::${type}<JSObject*> parentProto(${getParentProto}(aCx));
+ if (!parentProto) {
+ return;
+ }
+ """,
+ type=parentProtoType,
+ getParentProto=getParentProto,
+ )
+
+ protoClass = "&sPrototypeClass"
+ protoCache = (
+ "&aProtoAndIfaceCache.EntrySlotOrCreate(prototypes::id::%s)"
+ % self.descriptor.name
+ )
+ parentProto = "parentProto"
+ getParentProto = CGGeneric(getParentProto)
+ else:
+ protoClass = "nullptr"
+ protoCache = "nullptr"
+ parentProto = "nullptr"
+ getParentProto = None
+
+ if self.descriptor.interface.ctor():
+ constructArgs = methodLength(self.descriptor.interface.ctor())
+ isConstructorChromeOnly = isChromeOnly(self.descriptor.interface.ctor())
+ else:
+ constructArgs = 0
+ isConstructorChromeOnly = False
+ if len(self.descriptor.interface.legacyFactoryFunctions) > 0:
+ legacyFactoryFunctions = "Span(legacyFactoryFunctions)"
+ else:
+ legacyFactoryFunctions = "Span<const LegacyFactoryFunction, 0>{}"
+
+ isGlobal = self.descriptor.isGlobal() is not None
+
+ ensureCaches = fill(
"""
JS::Heap<JSObject*>* protoCache = ${protoCache};
JS::Heap<JSObject*>* interfaceCache = ${interfaceCache};
+ """,
+ protoCache=protoCache,
+ interfaceCache=interfaceCache,
+ )
+ call = fill(
+ """
dom::CreateInterfaceObjects(aCx, aGlobal, ${parentProto},
${protoClass}, protoCache,
- ${constructorProto}, ${interfaceClass}, ${constructArgs}, ${isConstructorChromeOnly}, ${legacyFactoryFunctions},
+ ${constructorProto}, ${interfaceInfo}, ${constructArgs}, ${isConstructorChromeOnly}, ${legacyFactoryFunctions},
interfaceCache,
${properties},
${chromeProperties},
"${name}", aDefineOnGlobal,
${unscopableNames},
${isGlobal},
- ${legacyWindowAliases},
- ${isNamespace});
+ ${legacyWindowAliases});
""",
protoClass=protoClass,
parentProto=parentProto,
- protoCache=protoCache,
constructorProto=constructorProto,
- interfaceClass=interfaceClass,
+ interfaceInfo=interfaceInfo,
constructArgs=constructArgs,
isConstructorChromeOnly=toStringBool(isConstructorChromeOnly),
legacyFactoryFunctions=legacyFactoryFunctions,
- interfaceCache=interfaceCache,
properties=properties,
chromeProperties=chromeProperties,
name=name,
@@ -3681,7 +3679,6 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
legacyWindowAliases="legacyWindowAliases"
if self.haveLegacyWindowAliases
else "nullptr",
- isNamespace=toStringBool(self.descriptor.interface.isNamespace()),
)
# If we fail after here, we must clear interface and prototype caches
@@ -3896,8 +3893,14 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
)
else:
defineProtoVar = None
+
+ # ensureCaches needs to come first as it crashes on failure (like OOM).
+ # We want to make sure that the caches do exist before we try to return
+ # to the caller, so it can rely on that (and detect other failures by
+ # checking for null in the caches).
return CGList(
[
+ CGGeneric(ensureCaches),
getParentProto,
getConstructorProto,
CGGeneric(call),
@@ -16955,9 +16958,11 @@ class CGDescriptor(CGThing):
# done, set up our NativePropertyHooks.
cgThings.append(CGNativePropertyHooks(descriptor, properties))
- if descriptor.interface.hasInterfaceObject():
+ if descriptor.interface.isNamespace():
+ cgThings.append(CGNamespaceObjectJSClass(descriptor))
+ elif descriptor.interface.hasInterfaceObject():
cgThings.append(CGClassConstructor(descriptor, descriptor.interface.ctor()))
- cgThings.append(CGInterfaceObjectJSClass(descriptor, properties))
+ cgThings.append(CGInterfaceObjectInfo(descriptor))
cgThings.append(CGLegacyFactoryFunctions(descriptor))
cgThings.append(CGLegacyCallHook(descriptor))
diff --git a/dom/bindings/Configuration.py b/dom/bindings/Configuration.py
index 354a450de6..cfcb2dcf39 100644
--- a/dom/bindings/Configuration.py
+++ b/dom/bindings/Configuration.py
@@ -43,6 +43,52 @@ class Configuration(DescriptorProvider):
the configuration file.
"""
+ class IDLAttrGetterOrSetterTemplate:
+ class TemplateAdditionalArg:
+ def __init__(self, type, name, value=None):
+ self.type = type
+ self.name = name
+ self.value = value
+
+ def __init__(self, template, getter, setter, argument, attrName):
+ self.descriptor = None
+ self.usedInOtherInterfaces = False
+ self.getter = getter
+ self.setter = setter
+ self.argument = (
+ Configuration.IDLAttrGetterOrSetterTemplate.TemplateAdditionalArg(
+ *argument
+ )
+ )
+ self.attrNameString = attrName
+ self.attr = None
+
+ class TemplateIDLAttribute:
+ def __init__(self, attr):
+ assert attr.isAttr()
+ assert not attr.isMaplikeOrSetlikeAttr()
+ assert not attr.slotIndices
+
+ self.identifier = attr.identifier
+ self.type = attr.type
+ self.extendedAttributes = attr.getExtendedAttributes()
+ self.slotIndices = None
+
+ def getExtendedAttribute(self, name):
+ return self.extendedAttributes.get(name)
+
+ def isAttr(self):
+ return True
+
+ def isMaplikeOrSetlikeAttr(self):
+ return False
+
+ def isMethod(self):
+ return False
+
+ def isStatic(self):
+ return False
+
def __init__(self, filename, webRoots, parseData, generatedEvents=[]):
DescriptorProvider.__init__(self)
@@ -51,28 +97,12 @@ class Configuration(DescriptorProvider):
exec(io.open(filename, encoding="utf-8").read(), glbl)
config = glbl["DOMInterfaces"]
- class IDLAttrGetterOrSetterTemplate:
- def __init__(self, template, getter, setter, argument, attrName):
- class TemplateAdditionalArg:
- def __init__(self, type, name, value=None):
- self.type = type
- self.name = name
- self.value = value
-
- self.descriptor = None
- self.usedInOtherInterfaces = False
- self.getter = getter
- self.setter = setter
- self.argument = TemplateAdditionalArg(*argument)
- self.attrNameString = attrName
- self.attr = None
-
self.attributeTemplates = dict()
attributeTemplatesByInterface = dict()
for interface, templates in glbl["TemplatedAttributes"].items():
for template in templates:
name = template.get("template")
- t = IDLAttrGetterOrSetterTemplate(**template)
+ t = Configuration.IDLAttrGetterOrSetterTemplate(**template)
self.attributeTemplates[name] = t
attributeTemplatesByInterface.setdefault(interface, list()).append(t)
@@ -351,33 +381,8 @@ class Configuration(DescriptorProvider):
)
# This mimics a real IDL attribute for templated bindings.
- class TemplateIDLAttribute:
- def __init__(self, attr):
- assert attr.isAttr()
- assert not attr.isMaplikeOrSetlikeAttr()
- assert not attr.slotIndices
-
- self.identifier = attr.identifier
- self.type = attr.type
- self.extendedAttributes = attr.getExtendedAttributes()
- self.slotIndices = None
-
- def getExtendedAttribute(self, name):
- return self.extendedAttributes.get(name)
-
- def isAttr(self):
- return True
-
- def isMaplikeOrSetlikeAttr(self):
- return False
-
- def isMethod(self):
- return False
-
- def isStatic(self):
- return False
- template.attr = TemplateIDLAttribute(firstAttribute)
+ template.attr = Configuration.TemplateIDLAttribute(firstAttribute)
def filterExtendedAttributes(extendedAttributes):
# These are the extended attributes that we allow to have
diff --git a/dom/bindings/DOMJSClass.h b/dom/bindings/DOMJSClass.h
index 12055fe6ba..3d8a734140 100644
--- a/dom/bindings/DOMJSClass.h
+++ b/dom/bindings/DOMJSClass.h
@@ -570,7 +570,7 @@ struct DOMIfaceAndProtoJSClass {
// initialization for aggregate/POD types.
const JSClass mBase;
- // Either eInterface, eNamespace, eInterfacePrototype,
+ // Either eNamespace, eInterfacePrototype,
// eGlobalInterfacePrototype or eNamedPropertiesObject.
DOMObjectType mType; // uint8_t
@@ -589,25 +589,6 @@ struct DOMIfaceAndProtoJSClass {
const JSClass* ToJSClass() const { return &mBase; }
};
-// Special JSClass for DOM interface objects.
-struct DOMIfaceJSClass : public DOMIfaceAndProtoJSClass {
- // Boolean indicating whether this object wants an isInstance property
- // pointing to InterfaceIsInstance defined on it. Only ever true for the
- // eInterface case.
- bool wantsInterfaceIsInstance;
-
- // The value to return for Function.prototype.toString on this interface
- // object.
- const char* mFunToString;
-
- static const DOMIfaceJSClass* FromJSClass(const JSClass* base) {
- const DOMIfaceAndProtoJSClass* clazz =
- DOMIfaceAndProtoJSClass::FromJSClass(base);
- MOZ_ASSERT(clazz->mType == eInterface || clazz->mType == eNamespace);
- return static_cast<const DOMIfaceJSClass*>(clazz);
- }
-};
-
class ProtoAndIfaceCache;
inline bool DOMGlobalHasProtoAndIFaceCache(JSObject* global) {
diff --git a/dom/bindings/JSSlots.h b/dom/bindings/JSSlots.h
index c9e9ffed07..54aed1289d 100644
--- a/dom/bindings/JSSlots.h
+++ b/dom/bindings/JSSlots.h
@@ -23,8 +23,21 @@
#define DOM_INSTANCE_RESERVED_SLOTS 1
// Interface objects store a number of reserved slots equal to
-// DOM_INTERFACE_SLOTS_BASE + number of legacy factory functions.
-#define DOM_INTERFACE_SLOTS_BASE 0
+// INTERFACE_OBJECT_INFO_RESERVED_SLOT + number of legacy factory functions,
+// with a maximum of js::FunctionExtended::NUM_EXTENDED_SLOTS.
+// INTERFACE_OBJECT_INFO_RESERVED_SLOT contains the DOMInterfaceInfo.
+// INTERFACE_OBJECT_FIRST_LEGACY_FACTORY_FUNCTION and higher contain the
+// JSObjects for the legacy factory functions.
+enum {
+ INTERFACE_OBJECT_INFO_RESERVED_SLOT = 0,
+ INTERFACE_OBJECT_FIRST_LEGACY_FACTORY_FUNCTION,
+};
+// See js::FunctionExtended::NUM_EXTENDED_SLOTS.
+#define INTERFACE_OBJECT_MAX_SLOTS 3
+
+// Legacy factory functions store a JSNativeHolder in the
+// LEGACY_FACTORY_FUNCTION_NATIVE_HOLDER_RESERVED_SLOT slot.
+enum { LEGACY_FACTORY_FUNCTION_NATIVE_HOLDER_RESERVED_SLOT = 0 };
// Interface prototype objects store a number of reserved slots equal to
// DOM_INTERFACE_PROTO_SLOTS_BASE or DOM_INTERFACE_PROTO_SLOTS_BASE + 1 if a
diff --git a/dom/bindings/WebIDLGlobalNameHash.cpp b/dom/bindings/WebIDLGlobalNameHash.cpp
index 3201f71ffd..24e48a343f 100644
--- a/dom/bindings/WebIDLGlobalNameHash.cpp
+++ b/dom/bindings/WebIDLGlobalNameHash.cpp
@@ -38,16 +38,21 @@ static JSObject* FindNamedConstructorForXray(
return nullptr;
}
- // This is a call over Xrays, so we will actually use the return value
- // (instead of just having it defined on the global now). Check for named
- // constructors with this id, in case that's what the caller is asking for.
- for (unsigned slot = DOM_INTERFACE_SLOTS_BASE;
- slot < JSCLASS_RESERVED_SLOTS(JS::GetClass(interfaceObject)); ++slot) {
- JSObject* constructor =
- &JS::GetReservedSlot(interfaceObject, slot).toObject();
- if (JS_GetMaybePartialFunctionId(JS_GetObjectFunction(constructor)) ==
- aId.toString()) {
- return constructor;
+ if (IsInterfaceObject(interfaceObject)) {
+ // This is a call over Xrays, so we will actually use the return value
+ // (instead of just having it defined on the global now). Check for named
+ // constructors with this id, in case that's what the caller is asking for.
+ for (unsigned slot = INTERFACE_OBJECT_FIRST_LEGACY_FACTORY_FUNCTION;
+ slot < INTERFACE_OBJECT_MAX_SLOTS; ++slot) {
+ const JS::Value& v = js::GetFunctionNativeReserved(interfaceObject, slot);
+ if (!v.isObject()) {
+ break;
+ }
+ JSObject* constructor = &v.toObject();
+ if (JS_GetMaybePartialFunctionId(JS_GetObjectFunction(constructor)) ==
+ aId.toString()) {
+ return constructor;
+ }
}
}
diff --git a/dom/bindings/mozwebidlcodegen/__init__.py b/dom/bindings/mozwebidlcodegen/__init__.py
index 3e8c6aa420..bba95edb78 100644
--- a/dom/bindings/mozwebidlcodegen/__init__.py
+++ b/dom/bindings/mozwebidlcodegen/__init__.py
@@ -11,7 +11,8 @@ import io
import json
import logging
import os
-from copy import deepcopy
+import sys
+from multiprocessing import Pool
import mozpack.path as mozpath
from mach.mixin.logging import LoggingMixin
@@ -22,6 +23,50 @@ from mozbuild.util import FileAvoidWrite
# There are various imports in this file in functions to avoid adding
# dependencies to config.status. See bug 949875.
+# Limit the count on Windows, because of bug 1889842 and also the
+# inefficiency of fork on Windows.
+DEFAULT_PROCESS_COUNT = 4 if sys.platform == "win32" else os.cpu_count()
+
+
+class WebIDLPool:
+ """
+ Distribute generation load across several processes, avoiding redundant state
+ copies.
+ """
+
+ GeneratorState = None
+
+ def __init__(self, GeneratorState, *, processes=None):
+ if processes is None:
+ processes = DEFAULT_PROCESS_COUNT
+
+ # As a special case, don't spawn an extra process if processes=1
+ if processes == 1:
+ WebIDLPool._init(GeneratorState)
+
+ class SeqPool:
+ def map(self, *args):
+ return list(map(*args))
+
+ self.pool = SeqPool()
+ else:
+ self.pool = Pool(
+ initializer=WebIDLPool._init,
+ initargs=(GeneratorState,),
+ processes=processes,
+ )
+
+ def run(self, filenames):
+ return self.pool.map(WebIDLPool._run, filenames)
+
+ @staticmethod
+ def _init(GeneratorState):
+ WebIDLPool.GeneratorState = GeneratorState
+
+ @staticmethod
+ def _run(filename):
+ return WebIDLPool.GeneratorState._generate_build_files_for_webidl(filename)
+
class BuildResult(object):
"""Represents the result of processing WebIDL files.
@@ -50,6 +95,9 @@ class WebIDLCodegenManagerState(dict):
state should be considered a black box to everyone except
WebIDLCodegenManager. But we'll still document it.
+ Any set stored in this dict should be copied and sorted in the `dump()`
+ method.
+
Fields:
version
@@ -117,12 +165,15 @@ class WebIDLCodegenManagerState(dict):
def dump(self, fh):
"""Dump serialized state to a file handle."""
- normalized = deepcopy(self)
+ normalized = self.copy()
+ webidls = normalized["webidls"] = self["webidls"].copy()
for k, v in self["webidls"].items():
+ webidls_k = webidls[k] = v.copy()
+
# Convert sets to lists because JSON doesn't support sets.
- normalized["webidls"][k]["outputs"] = sorted(v["outputs"])
- normalized["webidls"][k]["inputs"] = sorted(v["inputs"])
+ webidls_k["outputs"] = sorted(v["outputs"])
+ webidls_k["inputs"] = sorted(v["inputs"])
normalized["dictionaries_convertible_to_js"] = sorted(
self["dictionaries_convertible_to_js"]
@@ -251,7 +302,7 @@ class WebIDLCodegenManager(LoggingMixin):
return self._config
- def generate_build_files(self):
+ def generate_build_files(self, *, processes=None):
"""Generate files required for the build.
This function is in charge of generating all the .h/.cpp files derived
@@ -279,6 +330,9 @@ class WebIDLCodegenManager(LoggingMixin):
file.
3. If an output file is missing, ensure it is present by performing
necessary regeneration.
+
+ if `processes` is set to None, run in parallel using the
+ multiprocess.Pool default. If set to 1, don't use extra processes.
"""
# Despite #1 above, we assume the build system is smart enough to not
# invoke us if nothing has changed. Therefore, any invocation means
@@ -311,11 +365,20 @@ class WebIDLCodegenManager(LoggingMixin):
d.identifier.name for d in self._config.getDictionariesConvertibleFromJS()
)
+ # Distribute the generation load across several processes. This requires
+ # a) that `self' is serializable and b) that `self' is unchanged by
+ # _generate_build_files_for_webidl(...)
+ ordered_changed_inputs = sorted(changed_inputs)
+ pool = WebIDLPool(self, processes=processes)
+ generation_results = pool.run(ordered_changed_inputs)
+
# Generate bindings from .webidl files.
- for filename in sorted(changed_inputs):
+ for filename, generation_result in zip(
+ ordered_changed_inputs, generation_results
+ ):
basename = mozpath.basename(filename)
result.inputs.add(filename)
- written, deps = self._generate_build_files_for_webidl(filename)
+ written, deps = generation_result
result.created |= written[0]
result.updated |= written[1]
result.unchanged |= written[2]
@@ -560,6 +623,8 @@ class WebIDLCodegenManager(LoggingMixin):
return paths
+ # Parallelization of the generation step relies on this method not changing
+ # the internal state of the object
def _generate_build_files_for_webidl(self, filename):
from Codegen import CGBindingRoot, CGEventRoot
diff --git a/dom/bindings/mozwebidlcodegen/test/test_mozwebidlcodegen.py b/dom/bindings/mozwebidlcodegen/test/test_mozwebidlcodegen.py
index cd822af538..46a3ab6239 100644
--- a/dom/bindings/mozwebidlcodegen/test/test_mozwebidlcodegen.py
+++ b/dom/bindings/mozwebidlcodegen/test/test_mozwebidlcodegen.py
@@ -247,18 +247,21 @@ class TestWebIDLCodegenManager(unittest.TestCase):
args = self._get_manager_args()
m1 = WebIDLCodegenManager(**args)
with MockedOpen({fake_path: "# Original content"}):
+ # MockedOpen is not compatible with distributed filesystem
+ # access, so force the number of processes used to generate
+ # files to 1.
try:
- result = m1.generate_build_files()
+ result = m1.generate_build_files(processes=1)
l = len(result.inputs)
with io.open(fake_path, "wt", newline="\n") as fh:
fh.write("# Modified content")
m2 = WebIDLCodegenManager(**args)
- result = m2.generate_build_files()
+ result = m2.generate_build_files(processes=1)
self.assertEqual(len(result.inputs), l)
- result = m2.generate_build_files()
+ result = m2.generate_build_files(processes=1)
self.assertEqual(len(result.inputs), 0)
finally:
del sys.modules["mozwebidlcodegen.fakemodule"]
diff --git a/dom/bindings/nsIScriptError.idl b/dom/bindings/nsIScriptError.idl
index 3d7925a08d..b650de181c 100644
--- a/dom/bindings/nsIScriptError.idl
+++ b/dom/bindings/nsIScriptError.idl
@@ -91,7 +91,7 @@ interface nsIScriptError : nsIConsoleMessage
// Error created from a Promise rejection.
readonly attribute boolean isPromiseRejection;
- [noscript] void initIsPromiseRejection(in bool isPromiseRejection);
+ [noscript] void initIsPromiseRejection(in boolean isPromiseRejection);
// The "exception" value generated when an uncaught exception is thrown
// by JavaScript. This can be any value, e.g.
@@ -135,8 +135,8 @@ interface nsIScriptError : nsIConsoleMessage
in uint32_t columnNumber,
in uint32_t flags,
in ACString category,
- [optional] in bool fromPrivateWindow,
- [optional] in bool fromChromeContext);
+ [optional] in boolean fromPrivateWindow,
+ [optional] in boolean fromChromeContext);
/* This should be called instead of nsIScriptError.init to
* initialize with a window id. The window id should be for the
@@ -158,7 +158,7 @@ interface nsIScriptError : nsIConsoleMessage
in uint32_t flags,
in ACString category,
in unsigned long long innerWindowID,
- [optional] in bool fromChromeContext);
+ [optional] in boolean fromChromeContext);
/* This is the same function as initWithWindowID, but it expects an already
* sanitized sourceName.
@@ -172,7 +172,7 @@ interface nsIScriptError : nsIConsoleMessage
in uint32_t flags,
in ACString category,
in unsigned long long innerWindowID,
- [optional] in bool fromChromeContext);
+ [optional] in boolean fromChromeContext);
/* This is the same function as initWithWindowID with an uri as a source parameter.
*/
@@ -184,7 +184,7 @@ interface nsIScriptError : nsIConsoleMessage
in uint32_t flags,
in ACString category,
in unsigned long long innerWindowID,
- [optional] in bool fromChromeContext);
+ [optional] in boolean fromChromeContext);
/* Initialize the script source ID in a new error. */
void initSourceId(in uint32_t sourceId);
diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py
index 43f9ec12f1..9a3a77f075 100644
--- a/dom/bindings/parser/WebIDL.py
+++ b/dom/bindings/parser/WebIDL.py
@@ -121,6 +121,8 @@ class Location(object):
class BuiltinLocation(object):
+ __slots__ = "msg", "filename"
+
def __init__(self, text):
self.msg = text + "\n"
self.filename = "<builtin>"
@@ -142,9 +144,11 @@ class BuiltinLocation(object):
class IDLObject(object):
+ __slots__ = "location", "userData", "filename"
+
def __init__(self, location):
self.location = location
- self.userData = dict()
+ self.userData = {}
self.filename = location and location.filename
def isInterface(self):
@@ -220,6 +224,8 @@ class IDLObject(object):
class IDLScope(IDLObject):
+ __slots__ = "parentScope", "_name", "_dict", "globalNames", "globalNameMapping"
+
def __init__(self, location, parentScope, identifier):
IDLObject.__init__(self, location)
@@ -349,6 +355,8 @@ class IDLScope(IDLObject):
class IDLIdentifier(IDLObject):
+ __slots__ = "name", "scope"
+
def __init__(self, location, scope, name):
IDLObject.__init__(self, location)
@@ -373,12 +381,14 @@ class IDLIdentifier(IDLObject):
class IDLUnresolvedIdentifier(IDLObject):
+ __slots__ = ("name",)
+
def __init__(
self, location, name, allowDoubleUnderscore=False, allowForbidden=False
):
IDLObject.__init__(self, location)
- assert len(name) > 0
+ assert name
if name == "__noSuchMethod__":
raise WebIDLError("__noSuchMethod__ is deprecated", [location])
@@ -417,6 +427,7 @@ class IDLUnresolvedIdentifier(IDLObject):
class IDLObjectWithIdentifier(IDLObject):
+ # no slots, incompatible with multiple inheritance
def __init__(self, location, parentScope, identifier):
IDLObject.__init__(self, location)
@@ -434,6 +445,8 @@ class IDLObjectWithIdentifier(IDLObject):
class IDLObjectWithScope(IDLObjectWithIdentifier, IDLScope):
+ __slots__ = ()
+
def __init__(self, location, parentScope, identifier):
assert isinstance(identifier, IDLUnresolvedIdentifier)
@@ -442,6 +455,8 @@ class IDLObjectWithScope(IDLObjectWithIdentifier, IDLScope):
class IDLIdentifierPlaceholder(IDLObjectWithIdentifier):
+ __slots__ = ()
+
def __init__(self, location, identifier):
assert isinstance(identifier, IDLUnresolvedIdentifier)
IDLObjectWithIdentifier.__init__(self, location, None, identifier)
@@ -459,6 +474,7 @@ class IDLIdentifierPlaceholder(IDLObjectWithIdentifier):
class IDLExposureMixins:
+ # no slots, incompatible with multiple inheritance
def __init__(self, location):
# _exposureGlobalNames are the global names listed in our [Exposed]
# extended attribute. exposureSet is the exposure set as defined in the
@@ -541,6 +557,8 @@ class IDLExposureMixins:
class IDLExternalInterface(IDLObjectWithIdentifier):
+ __slots__ = ("parent",)
+
def __init__(self, location, parentScope, identifier):
assert isinstance(identifier, IDLUnresolvedIdentifier)
assert isinstance(parentScope, IDLScope)
@@ -591,6 +609,8 @@ class IDLExternalInterface(IDLObjectWithIdentifier):
class IDLPartialDictionary(IDLObject):
+ __slots__ = "identifier", "members", "_nonPartialDictionary", "_finished"
+
def __init__(self, location, name, members, nonPartialDictionary):
assert isinstance(name, IDLUnresolvedIdentifier)
@@ -619,6 +639,15 @@ class IDLPartialDictionary(IDLObject):
class IDLPartialInterfaceOrNamespace(IDLObject):
+ __slots__ = (
+ "identifier",
+ "members",
+ "propagatedExtendedAttrs",
+ "_haveSecureContextExtendedAttribute",
+ "_nonPartialInterfaceOrNamespace",
+ "_finished",
+ )
+
def __init__(self, location, name, members, nonPartialInterfaceOrNamespace):
assert isinstance(name, IDLUnresolvedIdentifier)
@@ -726,12 +755,22 @@ def globalNameSetToExposureSet(globalScope, nameSet, exposureSet):
# we use a special class to be able to store them both in the scope for the
# same identifier.
class IDLOperations:
+ __slots__ = "static", "regular"
+
def __init__(self, static=None, regular=None):
self.static = static
self.regular = regular
class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMixins):
+ __slots__ = (
+ "_finished",
+ "members",
+ "_partials",
+ "_extendedAttrDict",
+ "_isKnownNonPartial",
+ )
+
def __init__(self, location, parentScope, name):
assert isinstance(parentScope, IDLScope)
assert isinstance(name, IDLUnresolvedIdentifier)
@@ -897,10 +936,12 @@ class IDLInterfaceOrInterfaceMixinOrNamespace(IDLObjectWithScope, IDLExposureMix
class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace):
+ __slots__ = ("actualExposureGlobalNames",)
+
def __init__(self, location, parentScope, name, members, isKnownNonPartial):
self.actualExposureGlobalNames = set()
- assert isKnownNonPartial or len(members) == 0
+ assert isKnownNonPartial or not members
IDLInterfaceOrInterfaceMixinOrNamespace.__init__(
self, location, parentScope, name
)
@@ -1001,9 +1042,27 @@ class IDLInterfaceMixin(IDLInterfaceOrInterfaceMixinOrNamespace):
class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
+ __slots__ = (
+ "parent",
+ "_callback",
+ "maplikeOrSetlikeOrIterable",
+ "legacyFactoryFunctions",
+ "legacyWindowAliases",
+ "includedMixins",
+ "interfacesBasedOnSelf",
+ "_hasChildInterfaces",
+ "_isOnGlobalProtoChain",
+ "totalMembersInSlots",
+ "_ownMembersInSlots",
+ "iterableInterface",
+ "asyncIterableInterface",
+ "hasCrossOriginMembers",
+ "hasDescendantWithCrossOriginMembers",
+ )
+
def __init__(self, location, parentScope, name, parent, members, isKnownNonPartial):
assert isKnownNonPartial or not parent
- assert isKnownNonPartial or len(members) == 0
+ assert isKnownNonPartial or not members
self.parent = None
self._callback = False
@@ -1011,13 +1070,13 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
# legacyFactoryFunctions needs deterministic ordering because bindings code
# outputs the constructs in the order that legacyFactoryFunctions enumerates
# them.
- self.legacyFactoryFunctions = list()
+ self.legacyFactoryFunctions = []
self.legacyWindowAliases = []
self.includedMixins = set()
# self.interfacesBasedOnSelf is the set of interfaces that inherit from
# self, including self itself.
# Used for distinguishability checking.
- self.interfacesBasedOnSelf = set([self])
+ self.interfacesBasedOnSelf = {self}
self._hasChildInterfaces = False
self._isOnGlobalProtoChain = False
@@ -1885,6 +1944,8 @@ class IDLInterfaceOrNamespace(IDLInterfaceOrInterfaceMixinOrNamespace):
class IDLInterface(IDLInterfaceOrNamespace):
+ __slots__ = ("classNameOverride",)
+
def __init__(
self,
location,
@@ -2103,6 +2164,8 @@ class IDLInterface(IDLInterfaceOrNamespace):
class IDLNamespace(IDLInterfaceOrNamespace):
+ __slots__ = ()
+
def __init__(self, location, parentScope, name, members, isKnownNonPartial):
IDLInterfaceOrNamespace.__init__(
self, location, parentScope, name, None, members, isKnownNonPartial
@@ -2161,6 +2224,16 @@ class IDLNamespace(IDLInterfaceOrNamespace):
class IDLDictionary(IDLObjectWithScope):
+ __slots__ = (
+ "parent",
+ "_finished",
+ "members",
+ "_partialDictionaries",
+ "_extendedAttrDict",
+ "needsConversionToJS",
+ "needsConversionFromJS",
+ )
+
def __init__(self, location, parentScope, name, parent, members):
assert isinstance(parentScope, IDLScope)
assert isinstance(name, IDLUnresolvedIdentifier)
@@ -2388,6 +2461,8 @@ class IDLDictionary(IDLObjectWithScope):
class IDLEnum(IDLObjectWithIdentifier):
+ __slots__ = ("_values",)
+
def __init__(self, location, parentScope, name, values):
assert isinstance(parentScope, IDLScope)
assert isinstance(name, IDLUnresolvedIdentifier)
@@ -2462,6 +2537,16 @@ class IDLType(IDLObject):
"observablearray",
)
+ __slots__ = (
+ "name",
+ "builtin",
+ "legacyNullToEmptyString",
+ "_clamp",
+ "_enforceRange",
+ "_allowShared",
+ "_extendedAttrDict",
+ )
+
def __init__(self, location, name):
IDLObject.__init__(self, location)
self.name = name
@@ -2662,6 +2747,8 @@ class IDLUnresolvedType(IDLType):
Unresolved types are interface types
"""
+ __slots__ = ("extraTypeAttributes",)
+
def __init__(self, location, name, attrs=[]):
IDLType.__init__(self, location, name)
self.extraTypeAttributes = attrs
@@ -2702,6 +2789,8 @@ class IDLUnresolvedType(IDLType):
class IDLParametrizedType(IDLType):
+ __slots__ = "builtin", "inner"
+
def __init__(self, location, name, innerType):
IDLType.__init__(self, location, name)
self.builtin = False
@@ -2725,6 +2814,8 @@ class IDLParametrizedType(IDLType):
class IDLNullableType(IDLParametrizedType):
+ __slots__ = ()
+
def __init__(self, location, innerType):
assert not innerType == BuiltinTypes[IDLBuiltinType.Types.any]
@@ -2900,6 +2991,8 @@ class IDLNullableType(IDLParametrizedType):
class IDLSequenceType(IDLParametrizedType):
+ __slots__ = ("name",)
+
def __init__(self, location, parameterType):
assert not parameterType.isUndefined()
@@ -2960,6 +3053,8 @@ class IDLSequenceType(IDLParametrizedType):
class IDLRecordType(IDLParametrizedType):
+ __slots__ = "keyType", "name"
+
def __init__(self, location, keyType, valueType):
assert keyType.isString()
assert keyType.isComplete()
@@ -3038,6 +3133,8 @@ class IDLRecordType(IDLParametrizedType):
class IDLObservableArrayType(IDLParametrizedType):
+ __slots__ = ()
+
def __init__(self, location, innerType):
assert not innerType.isUndefined()
IDLParametrizedType.__init__(self, location, None, innerType)
@@ -3104,6 +3201,14 @@ class IDLObservableArrayType(IDLParametrizedType):
class IDLUnionType(IDLType):
+ __slots__ = (
+ "memberTypes",
+ "hasNullableType",
+ "_dictionaryType",
+ "flatMemberTypes",
+ "builtin",
+ )
+
def __init__(self, location, memberTypes):
IDLType.__init__(self, location, "")
self.memberTypes = memberTypes
@@ -3247,6 +3352,8 @@ class IDLUnionType(IDLType):
class IDLTypedefType(IDLType):
+ __slots__ = "inner", "builtin"
+
def __init__(self, location, innerType, name):
IDLType.__init__(self, location, name)
self.inner = innerType
@@ -3354,6 +3461,8 @@ class IDLTypedefType(IDLType):
class IDLTypedef(IDLObjectWithIdentifier):
+ __slots__ = ("innerType",)
+
def __init__(self, location, parentScope, innerType, name):
# Set self.innerType first, because IDLObjectWithIdentifier.__init__
# will call our __str__, which wants to use it.
@@ -3386,6 +3495,8 @@ class IDLTypedef(IDLObjectWithIdentifier):
class IDLWrapperType(IDLType):
+ __slots__ = "inner", "_identifier", "builtin"
+
def __init__(self, location, inner):
IDLType.__init__(self, location, inner.identifier.name)
self.inner = inner
@@ -3582,6 +3693,8 @@ class IDLWrapperType(IDLType):
class IDLPromiseType(IDLParametrizedType):
+ __slots__ = ()
+
def __init__(self, location, innerType):
IDLParametrizedType.__init__(self, location, "Promise", innerType)
@@ -3745,6 +3858,14 @@ class IDLBuiltinType(IDLType):
Types.Float64Array: "Float64Array",
}
+ __slots__ = (
+ "_typeTag",
+ "_clamped",
+ "_rangeEnforced",
+ "_withLegacyNullToEmptyString",
+ "_withAllowShared",
+ )
+
def __init__(
self,
location,
@@ -4242,6 +4363,11 @@ class NoCoercionFoundError(WebIDLError):
class IDLValue(IDLObject):
+ __slots__ = (
+ "type",
+ "value",
+ )
+
def __init__(self, location, type, value):
IDLObject.__init__(self, location)
self.type = type
@@ -4374,6 +4500,8 @@ class IDLValue(IDLObject):
class IDLNullValue(IDLObject):
+ __slots__ = "type", "value"
+
def __init__(self, location):
IDLObject.__init__(self, location)
self.type = None
@@ -4403,6 +4531,8 @@ class IDLNullValue(IDLObject):
class IDLEmptySequenceValue(IDLObject):
+ __slots__ = "type", "value"
+
def __init__(self, location):
IDLObject.__init__(self, location)
self.type = None
@@ -4433,6 +4563,8 @@ class IDLEmptySequenceValue(IDLObject):
class IDLDefaultDictionaryValue(IDLObject):
+ __slots__ = "type", "value"
+
def __init__(self, location):
IDLObject.__init__(self, location)
self.type = None
@@ -4463,6 +4595,8 @@ class IDLDefaultDictionaryValue(IDLObject):
class IDLUndefinedValue(IDLObject):
+ __slots__ = "type", "value"
+
def __init__(self, location):
IDLObject.__init__(self, location)
self.type = None
@@ -4492,6 +4626,7 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
AffectsValues = ("Nothing", "Everything")
DependsOnValues = ("Nothing", "DOMState", "DeviceState", "Everything")
+ # no slots : multiple inheritance
def __init__(self, location, identifier, tag, extendedAttrDict=None):
IDLObjectWithIdentifier.__init__(self, location, None, identifier)
IDLExposureMixins.__init__(self, location)
@@ -4611,6 +4746,14 @@ class IDLInterfaceMember(IDLObjectWithIdentifier, IDLExposureMixins):
class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember):
+ __slots__ = (
+ "keyType",
+ "valueType",
+ "maplikeOrSetlikeOrIterableType",
+ "disallowedMemberNames",
+ "disallowedNonMethodNames",
+ )
+
def __init__(self, location, identifier, ifaceType, keyType, valueType, ifaceKind):
IDLInterfaceMember.__init__(self, location, identifier, ifaceKind)
if keyType is not None:
@@ -4827,6 +4970,8 @@ class IDLMaplikeOrSetlikeOrIterableBase(IDLInterfaceMember):
# Iterable adds ES6 iterator style functions and traits
# (keys/values/entries/@@iterator) to an interface.
class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase):
+ __slots__ = ("iteratorType",)
+
def __init__(self, location, identifier, keyType, valueType, scope):
IDLMaplikeOrSetlikeOrIterableBase.__init__(
self,
@@ -4902,6 +5047,8 @@ class IDLIterable(IDLMaplikeOrSetlikeOrIterableBase):
class IDLAsyncIterable(IDLMaplikeOrSetlikeOrIterableBase):
+ __slots__ = "iteratorType", "argList"
+
def __init__(self, location, identifier, keyType, valueType, argList, scope):
for arg in argList:
if not arg.optional:
@@ -4986,6 +5133,8 @@ class IDLAsyncIterable(IDLMaplikeOrSetlikeOrIterableBase):
# MaplikeOrSetlike adds ES6 map-or-set-like traits to an interface.
class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase):
+ __slots__ = "readonly", "slotIndices", "prefix"
+
def __init__(
self, location, identifier, maplikeOrSetlikeType, readonly, keyType, valueType
):
@@ -5153,6 +5302,8 @@ class IDLMaplikeOrSetlike(IDLMaplikeOrSetlikeOrIterableBase):
class IDLConst(IDLInterfaceMember):
+ __slots__ = "type", "value"
+
def __init__(self, location, identifier, type, value):
IDLInterfaceMember.__init__(
self, location, identifier, IDLInterfaceMember.Tags.Const
@@ -5225,6 +5376,21 @@ class IDLConst(IDLInterfaceMember):
class IDLAttribute(IDLInterfaceMember):
+ __slots__ = (
+ "type",
+ "readonly",
+ "inherit",
+ "_static",
+ "legacyLenientThis",
+ "_legacyUnforgeable",
+ "stringifier",
+ "slotIndices",
+ "maplikeOrSetlike",
+ "dependsOn",
+ "affects",
+ "bindingAliases",
+ )
+
def __init__(
self,
location,
@@ -5827,6 +5993,18 @@ class IDLAttribute(IDLInterfaceMember):
class IDLArgument(IDLObjectWithIdentifier):
+ __slots__ = (
+ "type",
+ "optional",
+ "defaultValue",
+ "variadic",
+ "dictionaryMember",
+ "_isComplete",
+ "_allowTreatNonCallableAsNull",
+ "_extendedAttrDict",
+ "allowTypeAttributes",
+ )
+
def __init__(
self,
location,
@@ -5970,6 +6148,15 @@ class IDLArgument(IDLObjectWithIdentifier):
class IDLCallback(IDLObjectWithScope):
+ __slots__ = (
+ "_returnType",
+ "_arguments",
+ "_treatNonCallableAsNull",
+ "_treatNonObjectAsNull",
+ "_isRunScriptBoundary",
+ "_isConstructor",
+ )
+
def __init__(
self, location, parentScope, identifier, returnType, arguments, isConstructor
):
@@ -6067,6 +6254,8 @@ class IDLCallback(IDLObjectWithScope):
class IDLCallbackType(IDLType):
+ __slots__ = ("callback",)
+
def __init__(self, location, callback):
IDLType.__init__(self, location, callback.identifier.name)
self.callback = callback
@@ -6109,6 +6298,8 @@ class IDLMethodOverload:
the full set of overloads.
"""
+ __slots__ = "returnType", "arguments", "location"
+
def __init__(self, returnType, arguments, location):
self.returnType = returnType
# Clone the list of arguments, just in case
@@ -6131,6 +6322,25 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
NamedOrIndexed = enum("Neither", "Named", "Indexed")
+ __slots__ = (
+ "_hasOverloads",
+ "_overloads",
+ "_static",
+ "_getter",
+ "_setter",
+ "_deleter",
+ "_legacycaller",
+ "_stringifier",
+ "maplikeOrSetlikeOrIterable",
+ "_htmlConstructor",
+ "underlyingAttr",
+ "_specialType",
+ "_legacyUnforgeable",
+ "dependsOn",
+ "affects",
+ "aliases",
+ )
+
def __init__(
self,
location,
@@ -6797,6 +7007,14 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
class IDLConstructor(IDLMethod):
+ __slots__ = (
+ "_initLocation",
+ "_initArgs",
+ "_initName",
+ "_inited",
+ "_initExtendedAttrs",
+ )
+
def __init__(self, location, args, name):
# We can't actually init our IDLMethod yet, because we do not know the
# return type yet. Just save the info we have for now and we will init
@@ -6866,6 +7084,8 @@ class IDLConstructor(IDLMethod):
class IDLIncludesStatement(IDLObject):
+ __slots__ = ("interface", "mixin", "_finished")
+
def __init__(self, location, interface, mixin):
IDLObject.__init__(self, location)
self.interface = interface
@@ -6922,6 +7142,8 @@ class IDLExtendedAttribute(IDLObject):
A class to represent IDL extended attributes so we can give them locations
"""
+ __slots__ = ("_tuple",)
+
def __init__(self, location, tuple):
IDLObject.__init__(self, location)
self._tuple = tuple
diff --git a/dom/bindings/test/TestBindingHeader.h b/dom/bindings/test/TestBindingHeader.h
index 77053d9ba6..2e8c496758 100644
--- a/dom/bindings/test/TestBindingHeader.h
+++ b/dom/bindings/test/TestBindingHeader.h
@@ -131,29 +131,6 @@ class TestInterface : public nsISupports, public nsWrapperCache {
JS::Handle<JS::Value>, const Optional<JS::Handle<JSObject*>>&,
const Optional<JS::Handle<JSObject*>>&, ErrorResult&);
- static already_AddRefed<TestInterface> Test3(const GlobalObject&,
- const LongOrStringAnyRecord&,
- ErrorResult&);
-
- static already_AddRefed<TestInterface> Test4(
- const GlobalObject&, const Record<nsString, Record<nsString, JS::Value>>&,
- ErrorResult&);
-
- static already_AddRefed<TestInterface> Test5(
- const GlobalObject&,
- const Record<
- nsString,
- Sequence<Record<nsString,
- Record<nsString, Sequence<Sequence<JS::Value>>>>>>&,
- ErrorResult&);
-
- static already_AddRefed<TestInterface> Test6(
- const GlobalObject&,
- const Sequence<Record<
- nsCString,
- Sequence<Sequence<Record<nsCString, Record<nsString, JS::Value>>>>>>&,
- ErrorResult&);
-
// Integer types
int8_t ReadonlyByte();
int8_t WritableByte();
@@ -1394,6 +1371,48 @@ class TestInterface : public nsISupports, public nsWrapperCache {
void PassString(OwningNonNull<nsAString>&) = delete;
};
+class TestLegacyFactoryFunctionInterface : public nsISupports,
+ public nsWrapperCache {
+ public:
+ NS_DECL_ISUPPORTS
+
+ // We need a GetParentObject to make binding codegen happy
+ virtual nsISupports* GetParentObject();
+
+ // And now our actual WebIDL API
+ static already_AddRefed<TestLegacyFactoryFunctionInterface> Test3(
+ const GlobalObject&, const LongOrStringAnyRecord&, ErrorResult&);
+
+ static already_AddRefed<TestLegacyFactoryFunctionInterface> Test4(
+ const GlobalObject&, const Record<nsString, Record<nsString, JS::Value>>&,
+ ErrorResult&);
+};
+
+class TestLegacyFactoryFunctionInterface2 : public nsISupports,
+ public nsWrapperCache {
+ public:
+ NS_DECL_ISUPPORTS
+
+ // We need a GetParentObject to make binding codegen happy
+ virtual nsISupports* GetParentObject();
+
+ // And now our actual WebIDL API
+ static already_AddRefed<TestLegacyFactoryFunctionInterface2> Test5(
+ const GlobalObject&,
+ const Record<
+ nsString,
+ Sequence<Record<nsString,
+ Record<nsString, Sequence<Sequence<JS::Value>>>>>>&,
+ ErrorResult&);
+
+ static already_AddRefed<TestLegacyFactoryFunctionInterface2> Test6(
+ const GlobalObject&,
+ const Sequence<Record<
+ nsCString,
+ Sequence<Sequence<Record<nsCString, Record<nsString, JS::Value>>>>>>&,
+ ErrorResult&);
+};
+
class TestIndexedGetterInterface : public nsISupports, public nsWrapperCache {
public:
NS_DECL_ISUPPORTS
diff --git a/dom/bindings/test/TestCodeGen.webidl b/dom/bindings/test/TestCodeGen.webidl
index 827d9c35a7..0d186cd682 100644
--- a/dom/bindings/test/TestCodeGen.webidl
+++ b/dom/bindings/test/TestCodeGen.webidl
@@ -162,10 +162,6 @@ enum OnlyForUseInInnerUnion {
LegacyFactoryFunction=Test2(DictForConstructor dict, any any1, object obj1,
object? obj2, sequence<Dict> seq, optional any any2,
optional object obj3, optional object? obj4),
- LegacyFactoryFunction=Test3((long or record<DOMString, any>) arg1),
- LegacyFactoryFunction=Test4(record<DOMString, record<DOMString, any>> arg1),
- LegacyFactoryFunction=Test5(record<DOMString, sequence<record<DOMString, record<DOMString, sequence<sequence<any>>>>>> arg1),
- LegacyFactoryFunction=Test6(sequence<record<ByteString, sequence<sequence<record<ByteString, record<USVString, any>>>>>> arg1),
Exposed=Window]
interface TestInterface {
constructor();
@@ -1087,7 +1083,19 @@ interface TestInterface {
undefined passUnionArrayBuffer((DOMString or ArrayBuffer) foo);
undefined passUnionAllowSharedArrayBuffer((DOMString or [AllowShared] ArrayBuffer) foo);
- // If you add things here, add them to TestExampleGen and TestJSImplGen as well
+ // If you add things here, add them to TestExampleGen as well
+};
+
+[LegacyFactoryFunction=Test3((long or record<DOMString, any>) arg1),
+ LegacyFactoryFunction=Test4(record<DOMString, record<DOMString, any>> arg1),
+ Exposed=Window]
+interface TestLegacyFactoryFunctionInterface {
+};
+
+[LegacyFactoryFunction=Test5(record<DOMString, sequence<record<DOMString, record<DOMString, sequence<sequence<any>>>>>> arg1),
+ LegacyFactoryFunction=Test6(sequence<record<ByteString, sequence<sequence<record<ByteString, record<USVString, any>>>>>> arg1),
+ Exposed=Window]
+interface TestLegacyFactoryFunctionInterface2 {
};
[Exposed=Window]
diff --git a/dom/bindings/test/TestExampleGen.webidl b/dom/bindings/test/TestExampleGen.webidl
index 3d90e2bf9b..65e9840cec 100644
--- a/dom/bindings/test/TestExampleGen.webidl
+++ b/dom/bindings/test/TestExampleGen.webidl
@@ -870,7 +870,10 @@ interface TestExampleInterface {
undefined passUnionArrayBuffer((DOMString or ArrayBuffer) foo);
undefined passUnionAllowSharedArrayBuffer((DOMString or [AllowShared] ArrayBuffer) foo);
- // If you add things here, add them to TestCodeGen and TestJSImplGen as well
+ // If you add things here, add them to TestExampleGen. If they need to be
+ // supported in JS-implemented WebIDL then you need to add them to
+ // TestJSImplGen as well, if they are not supported in JS-implemented WebIDL
+ // then the codegen should throw for that specific case.
};
[Exposed=Window]
diff --git a/dom/bindings/test/test_dom_xrays.html b/dom/bindings/test/test_dom_xrays.html
index 6d65ab7315..eafa0c632c 100644
--- a/dom/bindings/test/test_dom_xrays.html
+++ b/dom/bindings/test/test_dom_xrays.html
@@ -176,6 +176,27 @@ function test() {
// ECMAScript-defined properties live on the prototype, overriding any named properties.
checkXrayProperty(coll, "toString", [ undefined, undefined, win.Object.prototype.toString ]);
+ // Constructors
+ img = new win.Image();
+ ok(win.HTMLImageElement.isInstance(img), "Constructor created the right type of object");
+
+ let threw;
+ try {
+ threw = false;
+ win.Image();
+ } catch (e) {
+ threw = true;
+ }
+ ok(threw, "Constructors should throw when called without new");
+
+ try {
+ threw = false;
+ new win.Node();
+ } catch (e) {
+ threw = true;
+ }
+ ok(threw, "Constructing an interface without a constructor should throw");
+
// Frozen arrays should come from our compartment, not the target one.
var languages1 = win.navigator.languages;
isnot(languages1, undefined, "Must have .languages");
@@ -358,7 +379,7 @@ function test() {
// legacyCaller should work.
ok(win.HTMLAllCollection.isInstance(doc.all),
"HTMLDocument.all should be an instance of HTMLAllCollection");
- let element, threw;
+ let element;
try {
threw = false;
element = doc.all(0);