forked from mirrors/gecko-dev
Backed out 5 changesets (bug 1882127) for causing wpt failures in builtin-function-properties.any.html.
Backed out changeset c7c1e3e34508 (bug 1882127) Backed out changeset 10710fd2c819 (bug 1882127) Backed out changeset 3633dba5d35a (bug 1882127) Backed out changeset 4d3e3b1fa2ba (bug 1882127) Backed out changeset f537b9d36bb2 (bug 1882127)
This commit is contained in:
parent
0f55b905b9
commit
ddeb6da7d8
14 changed files with 490 additions and 653 deletions
|
|
@ -310,7 +310,7 @@ add_task(async function () {
|
|||
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown");
|
||||
// Navigates to the XMLDocument item in the popup
|
||||
await waitForEagerEvaluationResult(hud, `function XMLDocument()`);
|
||||
await waitForEagerEvaluationResult(hud, `function ()`);
|
||||
|
||||
onPopupClose = popup.once("popup-closed");
|
||||
EventUtils.sendString(" ");
|
||||
|
|
|
|||
|
|
@ -758,30 +758,42 @@ bool DefineLegacyUnforgeableAttributes(
|
|||
return DefinePrefable(cx, obj, props);
|
||||
}
|
||||
|
||||
bool InterfaceObjectJSNative(JSContext* cx, unsigned argc, JS::Value* vp) {
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
return NativeHolderFromInterfaceObject(&args.callee())->mNative(cx, argc, vp);
|
||||
// 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 LegacyFactoryFunctionJSNative(JSContext* cx, unsigned argc,
|
||||
JS::Value* vp) {
|
||||
bool Constructor(JSContext* cx, unsigned argc, JS::Value* vp) {
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
return NativeHolderFromLegacyFactoryFunction(&args.callee())
|
||||
->mNative(cx, 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* CreateLegacyFactoryFunction(JSContext* cx, jsid name,
|
||||
static JSObject* CreateConstructor(JSContext* cx, JS::Handle<JSObject*> global,
|
||||
const char* name,
|
||||
const JSNativeHolder* nativeHolder,
|
||||
unsigned ctorNargs) {
|
||||
JSFunction* fun = js::NewFunctionByIdWithReserved(
|
||||
cx, LegacyFactoryFunctionJSNative, ctorNargs, JSFUN_CONSTRUCTOR, name);
|
||||
JSFunction* fun = js::NewFunctionWithReserved(cx, Constructor, ctorNargs,
|
||||
JSFUN_CONSTRUCTOR, name);
|
||||
if (!fun) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
JSObject* constructor = JS_GetFunctionObject(fun);
|
||||
js::SetFunctionNativeReserved(
|
||||
constructor, LEGACY_FACTORY_FUNCTION_NATIVE_HOLDER_RESERVED_SLOT,
|
||||
constructor, CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT,
|
||||
JS::PrivateValue(const_cast<JSNativeHolder*>(nativeHolder)));
|
||||
return constructor;
|
||||
}
|
||||
|
|
@ -834,11 +846,11 @@ static bool InterfaceIsInstance(JSContext* cx, unsigned argc, JS::Value* vp) {
|
|||
return true;
|
||||
}
|
||||
|
||||
// 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.
|
||||
// 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.
|
||||
JS::Rooted<JSObject*> thisObj(
|
||||
cx, js::CheckedUnwrapStatic(&args.thisv().toObject()));
|
||||
if (!thisObj) {
|
||||
|
|
@ -847,16 +859,20 @@ static bool InterfaceIsInstance(JSContext* cx, unsigned argc, JS::Value* vp) {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (!IsInterfaceObject(thisObj)) {
|
||||
const JSClass* thisClass = JS::GetClass(thisObj);
|
||||
|
||||
if (!IsDOMIfaceAndProtoClass(thisClass)) {
|
||||
args.rval().setBoolean(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
const DOMInterfaceInfo* interfaceInfo = InterfaceInfoFromObject(thisObj);
|
||||
const DOMIfaceAndProtoJSClass* clasp =
|
||||
DOMIfaceAndProtoJSClass::FromJSClass(thisClass);
|
||||
|
||||
// If "this" is a constructor for an interface without a prototype, just fall
|
||||
// back.
|
||||
if (interfaceInfo->mPrototypeID == prototypes::id::_ID_Count) {
|
||||
// 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) {
|
||||
args.rval().setBoolean(false);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -865,13 +881,13 @@ static bool InterfaceIsInstance(JSContext* cx, unsigned argc, JS::Value* vp) {
|
|||
const DOMJSClass* domClass = GetDOMClass(
|
||||
js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false));
|
||||
|
||||
if (domClass && domClass->mInterfaceChain[interfaceInfo->mDepth] ==
|
||||
interfaceInfo->mPrototypeID) {
|
||||
if (domClass &&
|
||||
domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID) {
|
||||
args.rval().setBoolean(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsRemoteObjectProxy(instance, interfaceInfo->mPrototypeID)) {
|
||||
if (IsRemoteObjectProxy(instance, clasp->mPrototypeID)) {
|
||||
args.rval().setBoolean(true);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -880,82 +896,80 @@ static bool InterfaceIsInstance(JSContext* cx, unsigned argc, JS::Value* vp) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool InitInterfaceOrNamespaceObject(
|
||||
JSContext* cx, JS::Handle<JSObject*> obj,
|
||||
const NativeProperties* properties,
|
||||
const NativeProperties* chromeOnlyProperties, bool isChrome) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (properties) {
|
||||
if (properties->HasStaticMethods() &&
|
||||
!DefinePrefable(cx, obj, properties->StaticMethods())) {
|
||||
return false;
|
||||
!DefinePrefable(cx, constructor, properties->StaticMethods())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (properties->HasStaticAttributes() &&
|
||||
!DefinePrefable(cx, obj, properties->StaticAttributes())) {
|
||||
return false;
|
||||
!DefinePrefable(cx, constructor, properties->StaticAttributes())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (properties->HasConstants() &&
|
||||
!DefinePrefable(cx, obj, properties->Constants())) {
|
||||
return false;
|
||||
!DefinePrefable(cx, constructor, properties->Constants())) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (chromeOnlyProperties && isChrome) {
|
||||
if (chromeOnlyProperties->HasStaticMethods() &&
|
||||
!DefinePrefable(cx, obj, chromeOnlyProperties->StaticMethods())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chromeOnlyProperties->HasStaticAttributes() &&
|
||||
!DefinePrefable(cx, obj, chromeOnlyProperties->StaticAttributes())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (chromeOnlyProperties->HasConstants() &&
|
||||
!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) {
|
||||
!DefinePrefable(cx, constructor,
|
||||
chromeOnlyProperties->StaticMethods())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
constructor = JS_GetFunctionObject(fun);
|
||||
if (chromeOnlyProperties->HasStaticAttributes() &&
|
||||
!DefinePrefable(cx, constructor,
|
||||
chromeOnlyProperties->StaticAttributes())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
js::SetFunctionNativeReserved(
|
||||
constructor, INTERFACE_OBJECT_INFO_RESERVED_SLOT,
|
||||
JS::PrivateValue(const_cast<DOMInterfaceInfo*>(interfaceInfo)));
|
||||
if (chromeOnlyProperties->HasConstants() &&
|
||||
!DefinePrefable(cx, constructor, chromeOnlyProperties->Constants())) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (interfaceInfo->wantsInterfaceIsInstance && isChrome &&
|
||||
!JS_DefineFunction(cx, constructor, "isInstance", InterfaceIsInstance, 1,
|
||||
// Don't bother making it enumerable
|
||||
0)) {
|
||||
if (isNamespace && !DefineToStringTag(cx, constructor, name)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -963,12 +977,8 @@ static JSObject* CreateInterfaceObject(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (!InitInterfaceOrNamespaceObject(cx, constructor, properties,
|
||||
chromeOnlyProperties, isChrome)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (defineOnGlobal && !DefineConstructor(cx, global, nameId, constructor)) {
|
||||
JS::Rooted<jsid> nameStr(cx, JS::PropertyKey::NonIntAtom(name));
|
||||
if (defineOnGlobal && !DefineConstructor(cx, global, nameStr, constructor)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -980,28 +990,25 @@ static JSObject* CreateInterfaceObject(
|
|||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (legacyFactoryFunctions) {
|
||||
int legacyFactoryFunctionSlot = DOM_INTERFACE_SLOTS_BASE;
|
||||
while (legacyFactoryFunctions->mName) {
|
||||
JS::Rooted<JSObject*> legacyFactoryFunction(
|
||||
cx, CreateLegacyFactoryFunction(cx, nameId, &lff.mHolder, lff.mNargs));
|
||||
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, nameId, legacyFactoryFunction))) {
|
||||
!DefineConstructor(cx, global, legacyFactoryFunctions->mName,
|
||||
legacyFactoryFunction))) {
|
||||
return nullptr;
|
||||
}
|
||||
js::SetFunctionNativeReserved(constructor, legacyFactoryFunctionSlot,
|
||||
JS::SetReservedSlot(constructor, legacyFactoryFunctionSlot++,
|
||||
JS::ObjectValue(*legacyFactoryFunction));
|
||||
++legacyFactoryFunctionSlot;
|
||||
++legacyFactoryFunctions;
|
||||
}
|
||||
}
|
||||
|
||||
return constructor;
|
||||
|
|
@ -1094,20 +1101,18 @@ 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*> interfaceProto,
|
||||
const DOMInterfaceInfo* interfaceInfo, unsigned ctorNargs,
|
||||
JS::Heap<JSObject*>* protoCache, JS::Handle<JSObject*> constructorProto,
|
||||
const DOMIfaceJSClass* constructorClass, unsigned ctorNargs,
|
||||
bool isConstructorChromeOnly,
|
||||
const Span<const LegacyFactoryFunction>& legacyFactoryFunctions,
|
||||
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) {
|
||||
MOZ_ASSERT(protoClass || interfaceInfo, "Need at least a class or info!");
|
||||
const char* const* legacyWindowAliases, bool isNamespace) {
|
||||
MOZ_ASSERT(protoClass || constructorClass, "Need at least one class!");
|
||||
MOZ_ASSERT(
|
||||
!((properties &&
|
||||
(properties->HasMethods() || properties->HasAttributes())) ||
|
||||
|
|
@ -1120,16 +1125,16 @@ void CreateInterfaceObjects(
|
|||
(chromeOnlyProperties &&
|
||||
(chromeOnlyProperties->HasStaticMethods() ||
|
||||
chromeOnlyProperties->HasStaticAttributes()))) ||
|
||||
interfaceInfo,
|
||||
"Static methods but no info!");
|
||||
constructorClass,
|
||||
"Static methods but no constructorClass!");
|
||||
MOZ_ASSERT(!protoClass == !protoCache,
|
||||
"If, and only if, there is an interface prototype object we need "
|
||||
"to cache it");
|
||||
MOZ_ASSERT(bool(interfaceInfo) == bool(constructorCache),
|
||||
MOZ_ASSERT(bool(constructorClass) == bool(constructorCache),
|
||||
"If, and only if, there is an interface object we need to cache "
|
||||
"it");
|
||||
MOZ_ASSERT(interfaceProto || !interfaceInfo,
|
||||
"Must have a interface proto if we plan to create an interface "
|
||||
MOZ_ASSERT(constructorProto || !constructorClass,
|
||||
"Must have a constructor proto if we plan to create a constructor "
|
||||
"object");
|
||||
|
||||
bool isChrome = nsContentUtils::ThreadsafeIsSystemCaller(cx);
|
||||
|
|
@ -1155,12 +1160,12 @@ void CreateInterfaceObjects(
|
|||
}
|
||||
|
||||
JSObject* interface;
|
||||
if (interfaceInfo) {
|
||||
if (constructorClass) {
|
||||
interface = CreateInterfaceObject(
|
||||
cx, global, interfaceProto, interfaceInfo,
|
||||
cx, global, constructorProto, constructorClass,
|
||||
(isChrome || !isConstructorChromeOnly) ? ctorNargs : 0,
|
||||
legacyFactoryFunctions, proto, properties, chromeOnlyProperties,
|
||||
nameStr, isChrome, defineOnGlobal, legacyWindowAliases);
|
||||
nameStr, isChrome, defineOnGlobal, legacyWindowAliases, isNamespace);
|
||||
if (!interface) {
|
||||
if (protoCache) {
|
||||
// If we fail we need to make sure to clear the value of protoCache we
|
||||
|
|
@ -1173,45 +1178,6 @@ 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(
|
||||
|
|
@ -1495,9 +1461,14 @@ bool ThrowConstructorWithoutNew(JSContext* cx, const char* name) {
|
|||
return ThrowErrorMessage<MSG_CONSTRUCTOR_WITHOUT_NEW>(cx, name);
|
||||
}
|
||||
|
||||
inline const NativePropertyHooks* GetNativePropertyHooksFromJSNative(
|
||||
inline const NativePropertyHooks* GetNativePropertyHooksFromConstructorFunction(
|
||||
JS::Handle<JSObject*> obj) {
|
||||
return NativeHolderFromObject(obj)->mPropertyHooks;
|
||||
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;
|
||||
}
|
||||
|
||||
inline const NativePropertyHooks* GetNativePropertyHooks(
|
||||
|
|
@ -1513,7 +1484,7 @@ inline const NativePropertyHooks* GetNativePropertyHooks(
|
|||
|
||||
if (JS_ObjectIsFunction(obj)) {
|
||||
type = eInterface;
|
||||
return GetNativePropertyHooksFromJSNative(obj);
|
||||
return GetNativePropertyHooksFromConstructorFunction(obj);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(IsDOMIfaceAndProtoClass(JS::GetClass(obj)));
|
||||
|
|
@ -1884,8 +1855,10 @@ static bool ResolvePrototypeOrConstructor(
|
|||
}
|
||||
|
||||
if (id.get() == GetJSIDByIndex(cx, XPCJSContext::IDX_ISINSTANCE)) {
|
||||
if (IsInterfaceObject(obj) &&
|
||||
InterfaceInfoFromObject(obj)->wantsInterfaceIsInstance) {
|
||||
const JSClass* objClass = JS::GetClass(obj);
|
||||
if (IsDOMIfaceAndProtoClass(objClass)) {
|
||||
const DOMIfaceJSClass* clazz = DOMIfaceJSClass::FromJSClass(objClass);
|
||||
if (clazz->wantsInterfaceIsInstance) {
|
||||
cacheOnHolder = true;
|
||||
|
||||
JSObject* funObj = XrayCreateFunction(
|
||||
|
|
@ -1900,6 +1873,7 @@ static bool ResolvePrototypeOrConstructor(
|
|||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (type == eNamespace) {
|
||||
if (id.isWellKnownSymbol(JS::SymbolCode::toStringTag)) {
|
||||
JS::Rooted<JSString*> nameStr(
|
||||
|
|
@ -2213,6 +2187,31 @@ 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) {
|
||||
|
|
@ -3573,8 +3572,16 @@ bool ForEachHandler(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
|
|||
|
||||
static inline prototypes::ID GetProtoIdForNewtarget(
|
||||
JS::Handle<JSObject*> aNewTarget) {
|
||||
if (IsDOMConstructor(aNewTarget)) {
|
||||
return GetNativePropertyHooksFromJSNative(aNewTarget)->mPrototypeID;
|
||||
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;
|
||||
}
|
||||
|
||||
return prototypes::id::_ID_Count;
|
||||
|
|
|
|||
|
|
@ -698,45 +698,12 @@ 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
|
||||
|
|
@ -745,20 +712,24 @@ void CreateInterfaceObjects(
|
|||
* 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.
|
||||
* 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.
|
||||
* 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.
|
||||
* 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.
|
||||
|
|
@ -790,66 +761,23 @@ void CreateInterfaceObjects(
|
|||
* char* names of the legacy window aliases for this
|
||||
* interface.
|
||||
*
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
// clang-format on
|
||||
template <size_t N>
|
||||
inline void CreateInterfaceObjects(
|
||||
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,
|
||||
JS::Heap<JSObject*>* protoCache, JS::Handle<JSObject*> constructorProto,
|
||||
const DOMIfaceJSClass* constructorClass, unsigned ctorNargs,
|
||||
bool isConstructorChromeOnly,
|
||||
const Span<const LegacyFactoryFunction, N>& legacyFactoryFunctions,
|
||||
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) {
|
||||
// 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);
|
||||
const char* const* legacyWindowAliases, bool isNamespace);
|
||||
|
||||
/**
|
||||
* Define the properties (regular and chrome-only) on obj.
|
||||
|
|
@ -2339,53 +2267,18 @@ inline bool AddStringToIDVector(JSContext* cx,
|
|||
name);
|
||||
}
|
||||
|
||||
// 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);
|
||||
// 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.
|
||||
|
||||
inline bool IsInterfaceObject(JSObject* obj) {
|
||||
return JS_IsNativeFunction(obj, InterfaceObjectJSNative);
|
||||
}
|
||||
enum { CONSTRUCTOR_NATIVE_HOLDER_RESERVED_SLOT = 0 };
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
inline const JSNativeHolder* NativeHolderFromInterfaceObject(JSObject* obj) {
|
||||
MOZ_ASSERT(IsInterfaceObject(obj));
|
||||
return &InterfaceInfoFromObject(obj)->nativeHolder;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
bool Constructor(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
// Implementation of the bits that XrayWrapper needs
|
||||
|
||||
|
|
@ -2457,11 +2350,8 @@ inline bool XrayGetNativeProto(JSContext* cx, JS::Handle<JSObject*> obj,
|
|||
protop.set(JS::GetRealmObjectPrototype(cx));
|
||||
}
|
||||
} else if (JS_ObjectIsFunction(obj)) {
|
||||
if (IsLegacyFactoryFunction(obj)) {
|
||||
MOZ_ASSERT(JS_IsNativeFunction(obj, Constructor));
|
||||
protop.set(JS::GetRealmFunctionPrototype(cx));
|
||||
} else {
|
||||
protop.set(InterfaceInfoFromObject(obj)->mGetParentProto(cx));
|
||||
}
|
||||
} else {
|
||||
const JSClass* clasp = JS::GetClass(obj);
|
||||
MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));
|
||||
|
|
@ -2536,16 +2426,36 @@ inline JSObject* GetCachedSlotStorageObject(JSContext* cx,
|
|||
|
||||
extern NativePropertyHooks sEmptyNativePropertyHooks;
|
||||
|
||||
inline bool IsDOMConstructor(JSObject* obj) {
|
||||
return IsInterfaceObject(obj) || IsLegacyFactoryFunction(obj);
|
||||
}
|
||||
extern const JSClassOps sBoringInterfaceObjectClassClassOps;
|
||||
|
||||
extern const js::ObjectOps sInterfaceObjectClassObjectOps;
|
||||
|
||||
inline bool UseDOMXray(JSObject* obj) {
|
||||
const JSClass* clasp = JS::GetClass(obj);
|
||||
return IsDOMClass(clasp) || IsDOMConstructor(obj) ||
|
||||
return IsDOMClass(clasp) || JS_IsNativeFunction(obj, Constructor) ||
|
||||
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) {
|
||||
|
|
@ -3297,6 +3207,10 @@ 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
|
||||
|
|
|
|||
|
|
@ -1890,16 +1890,6 @@ 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,
|
||||
|
|
|
|||
|
|
@ -926,51 +926,11 @@ def InterfaceObjectProtoGetter(descriptor, forXrays=False):
|
|||
return (protoGetter, protoHandleGetter)
|
||||
|
||||
|
||||
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):
|
||||
class CGInterfaceObjectJSClass(CGThing):
|
||||
def __init__(self, descriptor, properties):
|
||||
CGThing.__init__(self)
|
||||
self.descriptor = descriptor
|
||||
self.properties = properties
|
||||
|
||||
def declare(self):
|
||||
# We're purely for internal consumption
|
||||
|
|
@ -978,31 +938,104 @@ class CGInterfaceObjectInfo(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)
|
||||
|
||||
return fill(
|
||||
if ctorname == "ThrowingConstructor":
|
||||
ret = ""
|
||||
classOpsPtr = "&sBoringInterfaceObjectClassClassOps"
|
||||
elif ctorname == "nullptr":
|
||||
ret = ""
|
||||
classOpsPtr = "JS_NULL_CLASS_OPS"
|
||||
else:
|
||||
ret = fill(
|
||||
"""
|
||||
static const DOMInterfaceInfo sInterfaceObjectInfo = {
|
||||
{ ${ctorname}, ${hooks} },
|
||||
${protoGetter},
|
||||
${prototypeID},
|
||||
${depth},
|
||||
${wantsIsInstance},
|
||||
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(
|
||||
"""
|
||||
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}
|
||||
},
|
||||
${wantsIsInstance},
|
||||
${funToString}
|
||||
};
|
||||
""",
|
||||
classString=classString,
|
||||
slotCount=slotCount,
|
||||
classOpsPtr=classOpsPtr,
|
||||
hooks=NativePropertyHooks(self.descriptor),
|
||||
protoGetter=protoGetter,
|
||||
objectOps=objectOps,
|
||||
type="eNamespace"
|
||||
if self.descriptor.interface.isNamespace()
|
||||
else "eInterface",
|
||||
prototypeID=prototypeID,
|
||||
depth=depth,
|
||||
protoGetter=protoGetter,
|
||||
wantsIsInstance=toStringBool(wantsIsInstance),
|
||||
funToString=funToString,
|
||||
)
|
||||
return ret
|
||||
|
||||
|
||||
class CGList(CGThing):
|
||||
|
|
@ -2290,6 +2323,7 @@ class CGLegacyFactoryFunctions(CGThing):
|
|||
|
||||
static const LegacyFactoryFunction legacyFactoryFunctions[] = {
|
||||
$*{legacyFactoryFunctions}
|
||||
{ nullptr, { nullptr, nullptr }, 0 }
|
||||
};
|
||||
""",
|
||||
name=self.descriptor.name,
|
||||
|
|
@ -3504,21 +3538,48 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
|||
self.haveLegacyWindowAliases = haveLegacyWindowAliases
|
||||
|
||||
def definition_body(self):
|
||||
needInterfaceObject = self.descriptor.interface.hasInterfaceObject()
|
||||
if needInterfaceObject:
|
||||
(protoGetter, protoHandleGetter) = InterfaceObjectProtoGetter(
|
||||
(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}(aCx));
|
||||
JS::${type}<JSObject*> constructorProto(${getConstructorProto});
|
||||
if (!constructorProto) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -3527,7 +3588,33 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
|||
getConstructorProto=getConstructorProto,
|
||||
)
|
||||
|
||||
interfaceInfo = "&sInterfaceObjectInfo"
|
||||
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 needInterfacePrototypeObject:
|
||||
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 needInterfaceObject:
|
||||
interfaceClass = "&sInterfaceObjectClass"
|
||||
interfaceCache = (
|
||||
"&aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::%s)"
|
||||
% self.descriptor.name
|
||||
|
|
@ -3537,11 +3624,12 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
|||
else:
|
||||
# We don't have slots to store the legacy factory functions.
|
||||
assert len(self.descriptor.interface.legacyFactoryFunctions) == 0
|
||||
interfaceInfo = "nullptr"
|
||||
interfaceClass = "nullptr"
|
||||
interfaceCache = "nullptr"
|
||||
getConstructorProto = None
|
||||
constructorProto = "nullptr"
|
||||
|
||||
isGlobal = self.descriptor.isGlobal() is not None
|
||||
if self.properties.hasNonChromeOnly():
|
||||
properties = "sNativeProperties.Upcast()"
|
||||
else:
|
||||
|
|
@ -3560,109 +3648,27 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
|||
name = self.descriptor.interface.getClassName()
|
||||
assert not (needInterfaceObject and " " in name)
|
||||
|
||||
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
|
||||
|
||||
call = fill(
|
||||
"""
|
||||
JS::Heap<JSObject*>* protoCache = ${protoCache};
|
||||
JS::Heap<JSObject*>* interfaceCache = ${interfaceCache};
|
||||
dom::CreateInterfaceObjects(aCx, aGlobal, ${parentProto},
|
||||
${protoClass}, protoCache,
|
||||
${constructorProto}, ${interfaceInfo}, ${constructArgs}, ${isConstructorChromeOnly}, ${legacyFactoryFunctions},
|
||||
${constructorProto}, ${interfaceClass}, ${constructArgs}, ${isConstructorChromeOnly}, ${legacyFactoryFunctions},
|
||||
interfaceCache,
|
||||
${properties},
|
||||
${chromeProperties},
|
||||
"${name}", aDefineOnGlobal,
|
||||
${unscopableNames},
|
||||
${isGlobal},
|
||||
${legacyWindowAliases});
|
||||
${legacyWindowAliases},
|
||||
${isNamespace});
|
||||
""",
|
||||
protoClass=protoClass,
|
||||
parentProto=parentProto,
|
||||
protoCache=protoCache,
|
||||
constructorProto=constructorProto,
|
||||
interfaceInfo=interfaceInfo,
|
||||
interfaceClass=interfaceClass,
|
||||
constructArgs=constructArgs,
|
||||
isConstructorChromeOnly=toStringBool(isConstructorChromeOnly),
|
||||
legacyFactoryFunctions=legacyFactoryFunctions,
|
||||
|
|
@ -3675,6 +3681,7 @@ 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
|
||||
|
|
@ -16948,11 +16955,9 @@ class CGDescriptor(CGThing):
|
|||
# done, set up our NativePropertyHooks.
|
||||
cgThings.append(CGNativePropertyHooks(descriptor, properties))
|
||||
|
||||
if descriptor.interface.isNamespace():
|
||||
cgThings.append(CGNamespaceObjectJSClass(descriptor))
|
||||
elif descriptor.interface.hasInterfaceObject():
|
||||
if descriptor.interface.hasInterfaceObject():
|
||||
cgThings.append(CGClassConstructor(descriptor, descriptor.interface.ctor()))
|
||||
cgThings.append(CGInterfaceObjectInfo(descriptor))
|
||||
cgThings.append(CGInterfaceObjectJSClass(descriptor, properties))
|
||||
cgThings.append(CGLegacyFactoryFunctions(descriptor))
|
||||
|
||||
cgThings.append(CGLegacyCallHook(descriptor))
|
||||
|
|
|
|||
|
|
@ -570,7 +570,7 @@ struct DOMIfaceAndProtoJSClass {
|
|||
// initialization for aggregate/POD types.
|
||||
const JSClass mBase;
|
||||
|
||||
// Either eNamespace, eInterfacePrototype,
|
||||
// Either eInterface, eNamespace, eInterfacePrototype,
|
||||
// eGlobalInterfacePrototype or eNamedPropertiesObject.
|
||||
DOMObjectType mType; // uint8_t
|
||||
|
||||
|
|
@ -589,6 +589,25 @@ 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) {
|
||||
|
|
|
|||
|
|
@ -23,21 +23,8 @@
|
|||
#define DOM_INSTANCE_RESERVED_SLOTS 1
|
||||
|
||||
// Interface objects store a number of reserved slots equal to
|
||||
// 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 };
|
||||
// DOM_INTERFACE_SLOTS_BASE + number of legacy factory functions.
|
||||
#define DOM_INTERFACE_SLOTS_BASE 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
|
||||
|
|
|
|||
|
|
@ -38,23 +38,18 @@ static JSObject* FindNamedConstructorForXray(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
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();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// None of the legacy factory functions match, so the caller must want the
|
||||
// interface object itself.
|
||||
|
|
|
|||
|
|
@ -131,6 +131,29 @@ 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();
|
||||
|
|
@ -1371,48 +1394,6 @@ 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
|
||||
|
|
|
|||
|
|
@ -162,6 +162,10 @@ 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();
|
||||
|
|
@ -1086,18 +1090,6 @@ interface TestInterface {
|
|||
// If you add things here, add them to TestExampleGen and TestJSImplGen 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]
|
||||
interface TestParentInterface {
|
||||
};
|
||||
|
|
|
|||
|
|
@ -176,27 +176,6 @@ 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");
|
||||
|
|
@ -379,7 +358,7 @@ function test() {
|
|||
// legacyCaller should work.
|
||||
ok(win.HTMLAllCollection.isInstance(doc.all),
|
||||
"HTMLDocument.all should be an instance of HTMLAllCollection");
|
||||
let element;
|
||||
let element, threw;
|
||||
try {
|
||||
threw = false;
|
||||
element = doc.all(0);
|
||||
|
|
|
|||
|
|
@ -420,23 +420,6 @@ JS_PUBLIC_API JSFunction* js::NewFunctionByIdWithReserved(
|
|||
gc::AllocKind::FUNCTION_EXTENDED);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API JSFunction* js::NewFunctionByIdWithReservedAndProto(
|
||||
JSContext* cx, JSNative native, HandleObject proto, unsigned nargs,
|
||||
unsigned flags, jsid id) {
|
||||
MOZ_ASSERT(id.isAtom());
|
||||
MOZ_ASSERT(!cx->zone()->isAtomsZone());
|
||||
MOZ_ASSERT(native);
|
||||
CHECK_THREAD(cx);
|
||||
cx->check(id);
|
||||
|
||||
Rooted<JSAtom*> atom(cx, id.toAtom());
|
||||
FunctionFlags funflags = (flags & JSFUN_CONSTRUCTOR)
|
||||
? FunctionFlags::NATIVE_CTOR
|
||||
: FunctionFlags::NATIVE_FUN;
|
||||
return NewFunctionWithProto(cx, native, nargs, funflags, nullptr, atom, proto,
|
||||
gc::AllocKind::FUNCTION_EXTENDED, TenuredObject);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API const Value& js::GetFunctionNativeReserved(JSObject* fun,
|
||||
size_t which) {
|
||||
MOZ_ASSERT(fun->as<JSFunction>().isNativeFun());
|
||||
|
|
|
|||
|
|
@ -395,10 +395,6 @@ JS_PUBLIC_API JSFunction* NewFunctionByIdWithReserved(JSContext* cx,
|
|||
unsigned nargs,
|
||||
unsigned flags, jsid id);
|
||||
|
||||
JS_PUBLIC_API JSFunction* NewFunctionByIdWithReservedAndProto(
|
||||
JSContext* cx, JSNative native, JS::Handle<JSObject*> proto, unsigned nargs,
|
||||
unsigned flags, jsid id);
|
||||
|
||||
/**
|
||||
* Get or set function's reserved slot value.
|
||||
* `fun` should be a function created with `*WithReserved` API above.
|
||||
|
|
|
|||
|
|
@ -1799,11 +1799,6 @@ bool DOMXrayTraits::call(JSContext* cx, HandleObject wrapper,
|
|||
// using "legacycaller". At this time for all the legacycaller users it makes
|
||||
// more sense to invoke on the xray compartment, so we just go ahead and do
|
||||
// that for everything.
|
||||
if (IsDOMConstructor(obj)) {
|
||||
const JSNativeHolder* holder = NativeHolderFromObject(obj);
|
||||
return holder->mNative(cx, args.length(), args.base());
|
||||
}
|
||||
|
||||
if (js::IsProxy(obj)) {
|
||||
if (JS::IsCallable(obj)) {
|
||||
// Passing obj here, but it doesn't really matter because legacycaller
|
||||
|
|
@ -1827,14 +1822,9 @@ bool DOMXrayTraits::construct(JSContext* cx, HandleObject wrapper,
|
|||
const JS::CallArgs& args,
|
||||
const js::Wrapper& baseInstance) {
|
||||
RootedObject obj(cx, getTargetObject(wrapper));
|
||||
// See comments in DOMXrayTraits::call() explaining what's going on here.
|
||||
if (IsDOMConstructor(obj)) {
|
||||
const JSNativeHolder* holder = NativeHolderFromObject(obj);
|
||||
if (!holder->mNative(cx, args.length(), args.base())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(mozilla::dom::HasConstructor(obj));
|
||||
const JSClass* clasp = JS::GetClass(obj);
|
||||
// See comments in DOMXrayTraits::call() explaining what's going on here.
|
||||
if (clasp->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS) {
|
||||
if (JSNative construct = clasp->getConstruct()) {
|
||||
if (!construct(cx, args.length(), args.base())) {
|
||||
|
|
@ -1850,7 +1840,6 @@ bool DOMXrayTraits::construct(JSContext* cx, HandleObject wrapper,
|
|||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!args.rval().isObject() || !JS_WrapValue(cx, args.rval())) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue