forked from mirrors/gecko-dev
Bug 1882127 - Use plain JS functions for WebIDL interface objects. r=saschanaz,devtools-reviewers,nchevobbe
Differential Revision: https://phabricator.services.mozilla.com/D202824
This commit is contained in:
parent
37b3f13f6a
commit
891eaf1ede
9 changed files with 227 additions and 275 deletions
|
|
@ -310,7 +310,7 @@ add_task(async function () {
|
||||||
|
|
||||||
EventUtils.synthesizeKey("KEY_ArrowDown");
|
EventUtils.synthesizeKey("KEY_ArrowDown");
|
||||||
// Navigates to the XMLDocument item in the popup
|
// Navigates to the XMLDocument item in the popup
|
||||||
await waitForEagerEvaluationResult(hud, `function ()`);
|
await waitForEagerEvaluationResult(hud, `function XMLDocument()`);
|
||||||
|
|
||||||
onPopupClose = popup.once("popup-closed");
|
onPopupClose = popup.once("popup-closed");
|
||||||
EventUtils.sendString(" ");
|
EventUtils.sendString(" ");
|
||||||
|
|
|
||||||
|
|
@ -758,18 +758,9 @@ bool DefineLegacyUnforgeableAttributes(
|
||||||
return DefinePrefable(cx, obj, props);
|
return DefinePrefable(cx, obj, props);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should use JSFunction objects for interface objects, but we need a custom
|
bool InterfaceObjectJSNative(JSContext* cx, unsigned argc, JS::Value* vp) {
|
||||||
// hasInstance hook because we have new interface objects on prototype chains of
|
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||||
// old (XPConnect-based) bindings. We also need Xrays and arbitrary numbers of
|
return NativeHolderFromInterfaceObject(&args.callee())->mNative(cx, argc, vp);
|
||||||
// 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,
|
bool LegacyFactoryFunctionJSNative(JSContext* cx, unsigned argc,
|
||||||
|
|
@ -843,11 +834,11 @@ static bool InterfaceIsInstance(JSContext* cx, unsigned argc, JS::Value* vp) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If "this" doesn't have a DOMIfaceAndProtoJSClass, it's not a DOM
|
// If "this" is not an interface object, likewise return false (again, like
|
||||||
// constructor, so just fall back. But note that we should
|
// OrdinaryHasInstance). But note that we should CheckedUnwrapStatic here,
|
||||||
// CheckedUnwrapStatic here, because otherwise we won't get the right answers.
|
// because otherwise we won't get the right answers.
|
||||||
// The static version is OK, because we're looking for DOM constructors, which
|
// The static version is OK, because we're looking for interface objects,
|
||||||
// are not cross-origin objects.
|
// which are not cross-origin objects.
|
||||||
JS::Rooted<JSObject*> thisObj(
|
JS::Rooted<JSObject*> thisObj(
|
||||||
cx, js::CheckedUnwrapStatic(&args.thisv().toObject()));
|
cx, js::CheckedUnwrapStatic(&args.thisv().toObject()));
|
||||||
if (!thisObj) {
|
if (!thisObj) {
|
||||||
|
|
@ -856,20 +847,16 @@ static bool InterfaceIsInstance(JSContext* cx, unsigned argc, JS::Value* vp) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const JSClass* thisClass = JS::GetClass(thisObj);
|
if (!IsInterfaceObject(thisObj)) {
|
||||||
|
|
||||||
if (!IsDOMIfaceAndProtoClass(thisClass)) {
|
|
||||||
args.rval().setBoolean(false);
|
args.rval().setBoolean(false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DOMIfaceAndProtoJSClass* clasp =
|
const DOMInterfaceInfo* interfaceInfo = InterfaceInfoFromObject(thisObj);
|
||||||
DOMIfaceAndProtoJSClass::FromJSClass(thisClass);
|
|
||||||
|
|
||||||
// If "this" isn't a DOM constructor or is a constructor for an interface
|
// If "this" is a constructor for an interface without a prototype, just fall
|
||||||
// without a prototype, just fall back.
|
// back.
|
||||||
if (clasp->mType != eInterface ||
|
if (interfaceInfo->mPrototypeID == prototypes::id::_ID_Count) {
|
||||||
clasp->mPrototypeID == prototypes::id::_ID_Count) {
|
|
||||||
args.rval().setBoolean(false);
|
args.rval().setBoolean(false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -878,13 +865,13 @@ static bool InterfaceIsInstance(JSContext* cx, unsigned argc, JS::Value* vp) {
|
||||||
const DOMJSClass* domClass = GetDOMClass(
|
const DOMJSClass* domClass = GetDOMClass(
|
||||||
js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false));
|
js::UncheckedUnwrap(instance, /* stopAtWindowProxy = */ false));
|
||||||
|
|
||||||
if (domClass &&
|
if (domClass && domClass->mInterfaceChain[interfaceInfo->mDepth] ==
|
||||||
domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID) {
|
interfaceInfo->mPrototypeID) {
|
||||||
args.rval().setBoolean(true);
|
args.rval().setBoolean(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsRemoteObjectProxy(instance, clasp->mPrototypeID)) {
|
if (IsRemoteObjectProxy(instance, interfaceInfo->mPrototypeID)) {
|
||||||
args.rval().setBoolean(true);
|
args.rval().setBoolean(true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -937,32 +924,35 @@ bool InitInterfaceOrNamespaceObject(
|
||||||
// name must be an atom (or JS::PropertyKey::NonIntAtom will assert).
|
// name must be an atom (or JS::PropertyKey::NonIntAtom will assert).
|
||||||
static JSObject* CreateInterfaceObject(
|
static JSObject* CreateInterfaceObject(
|
||||||
JSContext* cx, JS::Handle<JSObject*> global,
|
JSContext* cx, JS::Handle<JSObject*> global,
|
||||||
JS::Handle<JSObject*> constructorProto,
|
JS::Handle<JSObject*> interfaceProto, const DOMInterfaceInfo* interfaceInfo,
|
||||||
const DOMIfaceJSClass* constructorClass, unsigned ctorNargs,
|
unsigned ctorNargs,
|
||||||
const Span<const LegacyFactoryFunction>& legacyFactoryFunctions,
|
const Span<const LegacyFactoryFunction>& legacyFactoryFunctions,
|
||||||
JS::Handle<JSObject*> proto, const NativeProperties* properties,
|
JS::Handle<JSObject*> proto, const NativeProperties* properties,
|
||||||
const NativeProperties* chromeOnlyProperties, JS::Handle<JSString*> name,
|
const NativeProperties* chromeOnlyProperties, JS::Handle<JSString*> name,
|
||||||
bool isChrome, bool defineOnGlobal,
|
bool isChrome, bool defineOnGlobal,
|
||||||
const char* const* legacyWindowAliases) {
|
const char* const* legacyWindowAliases) {
|
||||||
|
MOZ_ASSERT(interfaceProto);
|
||||||
|
MOZ_ASSERT(interfaceInfo);
|
||||||
|
|
||||||
|
JS::Rooted<jsid> nameId(cx, JS::PropertyKey::NonIntAtom(name));
|
||||||
|
|
||||||
JS::Rooted<JSObject*> constructor(cx);
|
JS::Rooted<JSObject*> constructor(cx);
|
||||||
MOZ_ASSERT(constructorProto);
|
{
|
||||||
MOZ_ASSERT(constructorClass);
|
JSFunction* fun = js::NewFunctionByIdWithReservedAndProto(
|
||||||
constructor = JS_NewObjectWithGivenProto(cx, constructorClass->ToJSClass(),
|
cx, InterfaceObjectJSNative, interfaceProto, ctorNargs,
|
||||||
constructorProto);
|
JSFUN_CONSTRUCTOR, nameId);
|
||||||
if (!constructor) {
|
if (!fun) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!JS_DefineProperty(cx, constructor, "length", ctorNargs,
|
constructor = JS_GetFunctionObject(fun);
|
||||||
JSPROP_READONLY)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!JS_DefineProperty(cx, constructor, "name", name, JSPROP_READONLY)) {
|
js::SetFunctionNativeReserved(
|
||||||
return nullptr;
|
constructor, INTERFACE_OBJECT_INFO_RESERVED_SLOT,
|
||||||
}
|
JS::PrivateValue(const_cast<DOMInterfaceInfo*>(interfaceInfo)));
|
||||||
|
|
||||||
if (constructorClass->wantsInterfaceIsInstance && isChrome &&
|
if (interfaceInfo->wantsInterfaceIsInstance && isChrome &&
|
||||||
!JS_DefineFunction(cx, constructor, "isInstance", InterfaceIsInstance, 1,
|
!JS_DefineFunction(cx, constructor, "isInstance", InterfaceIsInstance, 1,
|
||||||
// Don't bother making it enumerable
|
// Don't bother making it enumerable
|
||||||
0)) {
|
0)) {
|
||||||
|
|
@ -978,7 +968,6 @@ static JSObject* CreateInterfaceObject(
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::Rooted<jsid> nameId(cx, JS::PropertyKey::NonIntAtom(name));
|
|
||||||
if (defineOnGlobal && !DefineConstructor(cx, global, nameId, constructor)) {
|
if (defineOnGlobal && !DefineConstructor(cx, global, nameId, constructor)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
@ -1010,7 +999,7 @@ static JSObject* CreateInterfaceObject(
|
||||||
!DefineConstructor(cx, global, nameId, legacyFactoryFunction))) {
|
!DefineConstructor(cx, global, nameId, legacyFactoryFunction))) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
JS::SetReservedSlot(constructor, legacyFactoryFunctionSlot,
|
js::SetFunctionNativeReserved(constructor, legacyFactoryFunctionSlot,
|
||||||
JS::ObjectValue(*legacyFactoryFunction));
|
JS::ObjectValue(*legacyFactoryFunction));
|
||||||
++legacyFactoryFunctionSlot;
|
++legacyFactoryFunctionSlot;
|
||||||
}
|
}
|
||||||
|
|
@ -1110,15 +1099,15 @@ namespace binding_detail {
|
||||||
void CreateInterfaceObjects(
|
void CreateInterfaceObjects(
|
||||||
JSContext* cx, JS::Handle<JSObject*> global,
|
JSContext* cx, JS::Handle<JSObject*> global,
|
||||||
JS::Handle<JSObject*> protoProto, const DOMIfaceAndProtoJSClass* protoClass,
|
JS::Handle<JSObject*> protoProto, const DOMIfaceAndProtoJSClass* protoClass,
|
||||||
JS::Heap<JSObject*>* protoCache, JS::Handle<JSObject*> constructorProto,
|
JS::Heap<JSObject*>* protoCache, JS::Handle<JSObject*> interfaceProto,
|
||||||
const DOMIfaceJSClass* constructorClass, unsigned ctorNargs,
|
const DOMInterfaceInfo* interfaceInfo, unsigned ctorNargs,
|
||||||
bool isConstructorChromeOnly,
|
bool isConstructorChromeOnly,
|
||||||
const Span<const LegacyFactoryFunction>& legacyFactoryFunctions,
|
const Span<const LegacyFactoryFunction>& legacyFactoryFunctions,
|
||||||
JS::Heap<JSObject*>* constructorCache, const NativeProperties* properties,
|
JS::Heap<JSObject*>* constructorCache, const NativeProperties* properties,
|
||||||
const NativeProperties* chromeOnlyProperties, const char* name,
|
const NativeProperties* chromeOnlyProperties, const char* name,
|
||||||
bool defineOnGlobal, const char* const* unscopableNames, bool isGlobal,
|
bool defineOnGlobal, const char* const* unscopableNames, bool isGlobal,
|
||||||
const char* const* legacyWindowAliases) {
|
const char* const* legacyWindowAliases) {
|
||||||
MOZ_ASSERT(protoClass || constructorClass, "Need at least one class!");
|
MOZ_ASSERT(protoClass || interfaceInfo, "Need at least a class or info!");
|
||||||
MOZ_ASSERT(
|
MOZ_ASSERT(
|
||||||
!((properties &&
|
!((properties &&
|
||||||
(properties->HasMethods() || properties->HasAttributes())) ||
|
(properties->HasMethods() || properties->HasAttributes())) ||
|
||||||
|
|
@ -1131,16 +1120,16 @@ void CreateInterfaceObjects(
|
||||||
(chromeOnlyProperties &&
|
(chromeOnlyProperties &&
|
||||||
(chromeOnlyProperties->HasStaticMethods() ||
|
(chromeOnlyProperties->HasStaticMethods() ||
|
||||||
chromeOnlyProperties->HasStaticAttributes()))) ||
|
chromeOnlyProperties->HasStaticAttributes()))) ||
|
||||||
constructorClass,
|
interfaceInfo,
|
||||||
"Static methods but no constructorClass!");
|
"Static methods but no info!");
|
||||||
MOZ_ASSERT(!protoClass == !protoCache,
|
MOZ_ASSERT(!protoClass == !protoCache,
|
||||||
"If, and only if, there is an interface prototype object we need "
|
"If, and only if, there is an interface prototype object we need "
|
||||||
"to cache it");
|
"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 "
|
"If, and only if, there is an interface object we need to cache "
|
||||||
"it");
|
"it");
|
||||||
MOZ_ASSERT(constructorProto || !constructorClass,
|
MOZ_ASSERT(interfaceProto || !interfaceInfo,
|
||||||
"Must have a constructor proto if we plan to create a constructor "
|
"Must have a interface proto if we plan to create an interface "
|
||||||
"object");
|
"object");
|
||||||
|
|
||||||
bool isChrome = nsContentUtils::ThreadsafeIsSystemCaller(cx);
|
bool isChrome = nsContentUtils::ThreadsafeIsSystemCaller(cx);
|
||||||
|
|
@ -1166,9 +1155,9 @@ void CreateInterfaceObjects(
|
||||||
}
|
}
|
||||||
|
|
||||||
JSObject* interface;
|
JSObject* interface;
|
||||||
if (constructorClass) {
|
if (interfaceInfo) {
|
||||||
interface = CreateInterfaceObject(
|
interface = CreateInterfaceObject(
|
||||||
cx, global, constructorProto, constructorClass,
|
cx, global, interfaceProto, interfaceInfo,
|
||||||
(isChrome || !isConstructorChromeOnly) ? ctorNargs : 0,
|
(isChrome || !isConstructorChromeOnly) ? ctorNargs : 0,
|
||||||
legacyFactoryFunctions, proto, properties, chromeOnlyProperties,
|
legacyFactoryFunctions, proto, properties, chromeOnlyProperties,
|
||||||
nameStr, isChrome, defineOnGlobal, legacyWindowAliases);
|
nameStr, isChrome, defineOnGlobal, legacyWindowAliases);
|
||||||
|
|
@ -1508,7 +1497,7 @@ bool ThrowConstructorWithoutNew(JSContext* cx, const char* name) {
|
||||||
|
|
||||||
inline const NativePropertyHooks* GetNativePropertyHooksFromJSNative(
|
inline const NativePropertyHooks* GetNativePropertyHooksFromJSNative(
|
||||||
JS::Handle<JSObject*> obj) {
|
JS::Handle<JSObject*> obj) {
|
||||||
return NativeHolderFromLegacyFactoryFunction(obj)->mPropertyHooks;
|
return NativeHolderFromObject(obj)->mPropertyHooks;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const NativePropertyHooks* GetNativePropertyHooks(
|
inline const NativePropertyHooks* GetNativePropertyHooks(
|
||||||
|
|
@ -1895,10 +1884,8 @@ static bool ResolvePrototypeOrConstructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (id.get() == GetJSIDByIndex(cx, XPCJSContext::IDX_ISINSTANCE)) {
|
if (id.get() == GetJSIDByIndex(cx, XPCJSContext::IDX_ISINSTANCE)) {
|
||||||
const JSClass* objClass = JS::GetClass(obj);
|
if (IsInterfaceObject(obj) &&
|
||||||
if (IsDOMIfaceAndProtoClass(objClass)) {
|
InterfaceInfoFromObject(obj)->wantsInterfaceIsInstance) {
|
||||||
const DOMIfaceJSClass* clazz = DOMIfaceJSClass::FromJSClass(objClass);
|
|
||||||
if (clazz->wantsInterfaceIsInstance) {
|
|
||||||
cacheOnHolder = true;
|
cacheOnHolder = true;
|
||||||
|
|
||||||
JSObject* funObj = XrayCreateFunction(
|
JSObject* funObj = XrayCreateFunction(
|
||||||
|
|
@ -1913,7 +1900,6 @@ static bool ResolvePrototypeOrConstructor(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if (type == eNamespace) {
|
} else if (type == eNamespace) {
|
||||||
if (id.isWellKnownSymbol(JS::SymbolCode::toStringTag)) {
|
if (id.isWellKnownSymbol(JS::SymbolCode::toStringTag)) {
|
||||||
JS::Rooted<JSString*> nameStr(
|
JS::Rooted<JSString*> nameStr(
|
||||||
|
|
@ -2227,31 +2213,6 @@ NativePropertyHooks sEmptyNativePropertyHooks = {
|
||||||
constructors::id::_ID_Count,
|
constructors::id::_ID_Count,
|
||||||
nullptr};
|
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,
|
bool GetPropertyOnPrototype(JSContext* cx, JS::Handle<JSObject*> proxy,
|
||||||
JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
|
JS::Handle<JS::Value> receiver, JS::Handle<jsid> id,
|
||||||
bool* found, JS::MutableHandle<JS::Value> vp) {
|
bool* found, JS::MutableHandle<JS::Value> vp) {
|
||||||
|
|
@ -3612,14 +3573,7 @@ bool ForEachHandler(JSContext* aCx, unsigned aArgc, JS::Value* aVp) {
|
||||||
|
|
||||||
static inline prototypes::ID GetProtoIdForNewtarget(
|
static inline prototypes::ID GetProtoIdForNewtarget(
|
||||||
JS::Handle<JSObject*> aNewTarget) {
|
JS::Handle<JSObject*> aNewTarget) {
|
||||||
const JSClass* newTargetClass = JS::GetClass(aNewTarget);
|
if (IsDOMConstructor(aNewTarget)) {
|
||||||
if (IsDOMIfaceAndProtoClass(newTargetClass)) {
|
|
||||||
const DOMIfaceAndProtoJSClass* newTargetIfaceClass =
|
|
||||||
DOMIfaceAndProtoJSClass::FromJSClass(newTargetClass);
|
|
||||||
if (newTargetIfaceClass->mType == eInterface) {
|
|
||||||
return newTargetIfaceClass->mPrototypeID;
|
|
||||||
}
|
|
||||||
} else if (IsLegacyFactoryFunction(aNewTarget)) {
|
|
||||||
return GetNativePropertyHooksFromJSNative(aNewTarget)->mPrototypeID;
|
return GetNativePropertyHooksFromJSNative(aNewTarget)->mPrototypeID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -698,6 +698,23 @@ struct JSNativeHolder {
|
||||||
const NativePropertyHooks* mPropertyHooks;
|
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 {
|
struct LegacyFactoryFunction {
|
||||||
const char* mName;
|
const char* mName;
|
||||||
const JSNativeHolder mHolder;
|
const JSNativeHolder mHolder;
|
||||||
|
|
@ -709,8 +726,8 @@ namespace binding_detail {
|
||||||
void CreateInterfaceObjects(
|
void CreateInterfaceObjects(
|
||||||
JSContext* cx, JS::Handle<JSObject*> global,
|
JSContext* cx, JS::Handle<JSObject*> global,
|
||||||
JS::Handle<JSObject*> protoProto, const DOMIfaceAndProtoJSClass* protoClass,
|
JS::Handle<JSObject*> protoProto, const DOMIfaceAndProtoJSClass* protoClass,
|
||||||
JS::Heap<JSObject*>* protoCache, JS::Handle<JSObject*> constructorProto,
|
JS::Heap<JSObject*>* protoCache, JS::Handle<JSObject*> interfaceProto,
|
||||||
const DOMIfaceJSClass* constructorClass, unsigned ctorNargs,
|
const DOMInterfaceInfo* interfaceInfo, unsigned ctorNargs,
|
||||||
bool isConstructorChromeOnly,
|
bool isConstructorChromeOnly,
|
||||||
const Span<const LegacyFactoryFunction>& legacyFactoryFunctions,
|
const Span<const LegacyFactoryFunction>& legacyFactoryFunctions,
|
||||||
JS::Heap<JSObject*>* constructorCache, const NativeProperties* properties,
|
JS::Heap<JSObject*>* constructorCache, const NativeProperties* properties,
|
||||||
|
|
@ -728,24 +745,20 @@ void CreateInterfaceObjects(
|
||||||
* global is used as the parent of the interface object and the interface
|
* global is used as the parent of the interface object and the interface
|
||||||
* prototype object
|
* prototype object
|
||||||
* protoProto is the prototype to use for 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.
|
* protoClass is the JSClass to use for the interface prototype object.
|
||||||
* This is null if we should not create an interface prototype
|
* This is null if we should not create an interface prototype
|
||||||
* object.
|
* object.
|
||||||
* protoCache a pointer to a JSObject pointer where we should cache the
|
* protoCache a pointer to a JSObject pointer where we should cache the
|
||||||
* interface prototype object. This must be null if protoClass is and
|
* interface prototype object. This must be null if protoClass is and
|
||||||
* vice versa.
|
* vice versa.
|
||||||
* constructorClass is the JSClass to use for the interface object.
|
* interfaceProto is the prototype to use for the interface object. This can be
|
||||||
* This is null if we should not create an interface object or
|
* null if interfaceInfo is null (as in, if we're not creating an
|
||||||
* if it should be a function object.
|
* interface object at all).
|
||||||
* constructor holds the JSNative to back the interface object which should be a
|
* interfaceInfo is the info to use for the interface object. This can be null
|
||||||
* Function, unless constructorClass is non-null in which case it is
|
* if we're not creating an interface object.
|
||||||
* 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
|
* ctorNargs is the length of the constructor function; 0 if no constructor
|
||||||
* isConstructorChromeOnly if true, the constructor is ChromeOnly.
|
* 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
|
* constructorCache a pointer to a JSObject pointer where we should cache the
|
||||||
* interface object. This must be null if both constructorClass
|
* interface object. This must be null if both constructorClass
|
||||||
* and constructor are null, and non-null otherwise.
|
* and constructor are null, and non-null otherwise.
|
||||||
|
|
@ -777,32 +790,33 @@ void CreateInterfaceObjects(
|
||||||
* char* names of the legacy window aliases for this
|
* char* names of the legacy window aliases for this
|
||||||
* interface.
|
* interface.
|
||||||
*
|
*
|
||||||
* At least one of protoClass, constructorClass or constructor should be
|
* At least one of protoClass or interfaceInfo should be non-null. If
|
||||||
* non-null. If constructorClass or constructor are non-null, the resulting
|
* interfaceInfo is non-null, the resulting interface object will be defined on
|
||||||
* interface object will be defined on the given global with property name
|
* the given global with property name |name|, which must also be non-null.
|
||||||
* |name|, which must also be non-null.
|
|
||||||
*/
|
*/
|
||||||
// clang-format on
|
// clang-format on
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
inline void CreateInterfaceObjects(
|
inline void CreateInterfaceObjects(
|
||||||
JSContext* cx, JS::Handle<JSObject*> global,
|
JSContext* cx, JS::Handle<JSObject*> global,
|
||||||
JS::Handle<JSObject*> protoProto, const DOMIfaceAndProtoJSClass* protoClass,
|
JS::Handle<JSObject*> protoProto, const DOMIfaceAndProtoJSClass* protoClass,
|
||||||
JS::Heap<JSObject*>* protoCache, JS::Handle<JSObject*> constructorProto,
|
JS::Heap<JSObject*>* protoCache, JS::Handle<JSObject*> interfaceProto,
|
||||||
const DOMIfaceJSClass* constructorClass, unsigned ctorNargs,
|
const DOMInterfaceInfo* interfaceInfo, unsigned ctorNargs,
|
||||||
bool isConstructorChromeOnly,
|
bool isConstructorChromeOnly,
|
||||||
const Span<const LegacyFactoryFunction, N>& legacyFactoryFunctions,
|
const Span<const LegacyFactoryFunction, N>& legacyFactoryFunctions,
|
||||||
JS::Heap<JSObject*>* constructorCache, const NativeProperties* properties,
|
JS::Heap<JSObject*>* constructorCache, const NativeProperties* properties,
|
||||||
const NativeProperties* chromeOnlyProperties, const char* name,
|
const NativeProperties* chromeOnlyProperties, const char* name,
|
||||||
bool defineOnGlobal, const char* const* unscopableNames, bool isGlobal,
|
bool defineOnGlobal, const char* const* unscopableNames, bool isGlobal,
|
||||||
const char* const* legacyWindowAliases) {
|
const char* const* legacyWindowAliases) {
|
||||||
static_assert(N < 3);
|
// 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(
|
return binding_detail::CreateInterfaceObjects(
|
||||||
cx, global, protoProto, protoClass, protoCache, constructorProto,
|
cx, global, protoProto, protoClass, protoCache, interfaceProto,
|
||||||
constructorClass, ctorNargs, isConstructorChromeOnly,
|
interfaceInfo, ctorNargs, isConstructorChromeOnly, legacyFactoryFunctions,
|
||||||
legacyFactoryFunctions, constructorCache, properties,
|
constructorCache, properties, chromeOnlyProperties, name, defineOnGlobal,
|
||||||
chromeOnlyProperties, name, defineOnGlobal, unscopableNames, isGlobal,
|
unscopableNames, isGlobal, legacyWindowAliases);
|
||||||
legacyWindowAliases);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -2325,11 +2339,35 @@ inline bool AddStringToIDVector(JSContext* cx,
|
||||||
name);
|
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);
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
// 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
|
// 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
|
// real JSNative and the NativeProperties in a JSNativeHolder in the
|
||||||
// LEGACY_FACTORY_FUNCTION_NATIVE_HOLDER_RESERVED_SLOT slot of the JSFunction
|
// LEGACY_FACTORY_FUNCTION_NATIVE_HOLDER_RESERVED_SLOT slot of the JSFunction
|
||||||
// object. We also store the NativeProperties in the JSNativeHolder.
|
// object.
|
||||||
bool LegacyFactoryFunctionJSNative(JSContext* cx, unsigned argc, JS::Value* vp);
|
bool LegacyFactoryFunctionJSNative(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||||
|
|
||||||
inline bool IsLegacyFactoryFunction(JSObject* obj) {
|
inline bool IsLegacyFactoryFunction(JSObject* obj) {
|
||||||
|
|
@ -2344,6 +2382,11 @@ inline const JSNativeHolder* NativeHolderFromLegacyFactoryFunction(
|
||||||
return static_cast<const JSNativeHolder*>(v.toPrivate());
|
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
|
// Implementation of the bits that XrayWrapper needs
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -2414,8 +2457,11 @@ inline bool XrayGetNativeProto(JSContext* cx, JS::Handle<JSObject*> obj,
|
||||||
protop.set(JS::GetRealmObjectPrototype(cx));
|
protop.set(JS::GetRealmObjectPrototype(cx));
|
||||||
}
|
}
|
||||||
} else if (JS_ObjectIsFunction(obj)) {
|
} else if (JS_ObjectIsFunction(obj)) {
|
||||||
MOZ_ASSERT(IsLegacyFactoryFunction(obj));
|
if (IsLegacyFactoryFunction(obj)) {
|
||||||
protop.set(JS::GetRealmFunctionPrototype(cx));
|
protop.set(JS::GetRealmFunctionPrototype(cx));
|
||||||
|
} else {
|
||||||
|
protop.set(InterfaceInfoFromObject(obj)->mGetParentProto(cx));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const JSClass* clasp = JS::GetClass(obj);
|
const JSClass* clasp = JS::GetClass(obj);
|
||||||
MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));
|
MOZ_ASSERT(IsDOMIfaceAndProtoClass(clasp));
|
||||||
|
|
@ -2490,35 +2536,16 @@ inline JSObject* GetCachedSlotStorageObject(JSContext* cx,
|
||||||
|
|
||||||
extern NativePropertyHooks sEmptyNativePropertyHooks;
|
extern NativePropertyHooks sEmptyNativePropertyHooks;
|
||||||
|
|
||||||
extern const JSClassOps sBoringInterfaceObjectClassClassOps;
|
inline bool IsDOMConstructor(JSObject* obj) {
|
||||||
|
return IsInterfaceObject(obj) || IsLegacyFactoryFunction(obj);
|
||||||
extern const js::ObjectOps sInterfaceObjectClassObjectOps;
|
}
|
||||||
|
|
||||||
inline bool UseDOMXray(JSObject* obj) {
|
inline bool UseDOMXray(JSObject* obj) {
|
||||||
const JSClass* clasp = JS::GetClass(obj);
|
const JSClass* clasp = JS::GetClass(obj);
|
||||||
return IsDOMClass(clasp) || IsLegacyFactoryFunction(obj) ||
|
return IsDOMClass(clasp) || IsDOMConstructor(obj) ||
|
||||||
IsDOMIfaceAndProtoClass(clasp);
|
IsDOMIfaceAndProtoClass(clasp);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool IsDOMConstructor(JSObject* obj) {
|
|
||||||
if (IsLegacyFactoryFunction(obj)) {
|
|
||||||
// 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 IsLegacyFactoryFunction(obj) || JS::GetClass(obj)->getConstruct();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Helpers for creating a const version of a type.
|
// Helpers for creating a const version of a type.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
const T& Constify(T& arg) {
|
const T& Constify(T& arg) {
|
||||||
|
|
@ -3270,10 +3297,6 @@ void DeprecationWarning(JSContext* aCx, JSObject* aObject,
|
||||||
void DeprecationWarning(const GlobalObject& aGlobal,
|
void DeprecationWarning(const GlobalObject& aGlobal,
|
||||||
DeprecatedOperations aOperation);
|
DeprecatedOperations aOperation);
|
||||||
|
|
||||||
// A callback to perform funToString on an interface object
|
|
||||||
JSString* InterfaceObjectToString(JSContext* aCx, JS::Handle<JSObject*> aObject,
|
|
||||||
unsigned /* indent */);
|
|
||||||
|
|
||||||
namespace binding_detail {
|
namespace binding_detail {
|
||||||
// Get a JS global object that can be used for some temporary allocations. The
|
// 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
|
// idea is that this should be used for situations when you need to operate in
|
||||||
|
|
|
||||||
|
|
@ -967,7 +967,7 @@ class CGNamespaceObjectJSClass(CGThing):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class CGInterfaceObjectJSClass(CGThing):
|
class CGInterfaceObjectInfo(CGThing):
|
||||||
def __init__(self, descriptor):
|
def __init__(self, descriptor):
|
||||||
CGThing.__init__(self)
|
CGThing.__init__(self)
|
||||||
self.descriptor = descriptor
|
self.descriptor = descriptor
|
||||||
|
|
@ -984,74 +984,25 @@ class CGInterfaceObjectJSClass(CGThing):
|
||||||
wantsIsInstance = self.descriptor.interface.hasInterfacePrototypeObject()
|
wantsIsInstance = self.descriptor.interface.hasInterfacePrototypeObject()
|
||||||
|
|
||||||
prototypeID, depth = PrototypeIDAndDepth(self.descriptor)
|
prototypeID, depth = PrototypeIDAndDepth(self.descriptor)
|
||||||
slotCount = "INTERFACE_OBJECT_FIRST_LEGACY_FACTORY_FUNCTION"
|
|
||||||
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)
|
(protoGetter, _) = InterfaceObjectProtoGetter(self.descriptor, forXrays=True)
|
||||||
|
|
||||||
if ctorname == "ThrowingConstructor":
|
return fill(
|
||||||
ret = ""
|
|
||||||
classOpsPtr = "&sBoringInterfaceObjectClassClassOps"
|
|
||||||
else:
|
|
||||||
ret = fill(
|
|
||||||
"""
|
"""
|
||||||
static const JSClassOps sInterfaceObjectClassOps = {
|
static const DOMInterfaceInfo sInterfaceObjectInfo = {
|
||||||
nullptr, /* addProperty */
|
{ ${ctorname}, ${hooks} },
|
||||||
nullptr, /* delProperty */
|
${protoGetter},
|
||||||
nullptr, /* enumerate */
|
|
||||||
nullptr, /* newEnumerate */
|
|
||||||
nullptr, /* resolve */
|
|
||||||
nullptr, /* mayResolve */
|
|
||||||
nullptr, /* finalize */
|
|
||||||
${ctorname}, /* call */
|
|
||||||
${ctorname}, /* construct */
|
|
||||||
nullptr, /* trace */
|
|
||||||
};
|
|
||||||
|
|
||||||
""",
|
|
||||||
ctorname=ctorname,
|
|
||||||
)
|
|
||||||
classOpsPtr = "&sInterfaceObjectClassOps"
|
|
||||||
|
|
||||||
funToString = (
|
|
||||||
'"function %s() {\\n [native code]\\n}"'
|
|
||||||
% self.descriptor.interface.identifier.name
|
|
||||||
)
|
|
||||||
|
|
||||||
ret = ret + fill(
|
|
||||||
"""
|
|
||||||
static const DOMIfaceJSClass sInterfaceObjectClass = {
|
|
||||||
{
|
|
||||||
{
|
|
||||||
"Function",
|
|
||||||
JSCLASS_IS_DOMIFACEANDPROTOJSCLASS | JSCLASS_HAS_RESERVED_SLOTS(${slotCount}),
|
|
||||||
${classOpsPtr},
|
|
||||||
JS_NULL_CLASS_SPEC,
|
|
||||||
JS_NULL_CLASS_EXT,
|
|
||||||
&sInterfaceObjectClassObjectOps
|
|
||||||
},
|
|
||||||
eInterface,
|
|
||||||
${prototypeID},
|
${prototypeID},
|
||||||
${depth},
|
${depth},
|
||||||
${hooks},
|
|
||||||
${protoGetter}
|
|
||||||
},
|
|
||||||
${wantsIsInstance},
|
${wantsIsInstance},
|
||||||
${funToString}
|
|
||||||
};
|
};
|
||||||
""",
|
""",
|
||||||
slotCount=slotCount,
|
ctorname=ctorname,
|
||||||
classOpsPtr=classOpsPtr,
|
|
||||||
hooks=NativePropertyHooks(self.descriptor),
|
hooks=NativePropertyHooks(self.descriptor),
|
||||||
|
protoGetter=protoGetter,
|
||||||
prototypeID=prototypeID,
|
prototypeID=prototypeID,
|
||||||
depth=depth,
|
depth=depth,
|
||||||
protoGetter=protoGetter,
|
|
||||||
wantsIsInstance=toStringBool(wantsIsInstance),
|
wantsIsInstance=toStringBool(wantsIsInstance),
|
||||||
funToString=funToString,
|
|
||||||
)
|
)
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
class CGList(CGThing):
|
class CGList(CGThing):
|
||||||
|
|
@ -3576,7 +3527,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
||||||
getConstructorProto=getConstructorProto,
|
getConstructorProto=getConstructorProto,
|
||||||
)
|
)
|
||||||
|
|
||||||
interfaceClass = "&sInterfaceObjectClass"
|
interfaceInfo = "&sInterfaceObjectInfo"
|
||||||
interfaceCache = (
|
interfaceCache = (
|
||||||
"&aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::%s)"
|
"&aProtoAndIfaceCache.EntrySlotOrCreate(constructors::id::%s)"
|
||||||
% self.descriptor.name
|
% self.descriptor.name
|
||||||
|
|
@ -3586,7 +3537,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
||||||
else:
|
else:
|
||||||
# We don't have slots to store the legacy factory functions.
|
# We don't have slots to store the legacy factory functions.
|
||||||
assert len(self.descriptor.interface.legacyFactoryFunctions) == 0
|
assert len(self.descriptor.interface.legacyFactoryFunctions) == 0
|
||||||
interfaceClass = "nullptr"
|
interfaceInfo = "nullptr"
|
||||||
interfaceCache = "nullptr"
|
interfaceCache = "nullptr"
|
||||||
getConstructorProto = None
|
getConstructorProto = None
|
||||||
constructorProto = "nullptr"
|
constructorProto = "nullptr"
|
||||||
|
|
@ -3641,7 +3592,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
||||||
self.descriptor.interface.hasInterfacePrototypeObject()
|
self.descriptor.interface.hasInterfacePrototypeObject()
|
||||||
)
|
)
|
||||||
|
|
||||||
# if we don't need to create anything, why are we generating this?
|
# If we don't need to create anything, why are we generating this?
|
||||||
assert needInterfaceObject or needInterfacePrototypeObject
|
assert needInterfaceObject or needInterfacePrototypeObject
|
||||||
|
|
||||||
if needInterfacePrototypeObject:
|
if needInterfacePrototypeObject:
|
||||||
|
|
@ -3698,7 +3649,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
||||||
JS::Heap<JSObject*>* interfaceCache = ${interfaceCache};
|
JS::Heap<JSObject*>* interfaceCache = ${interfaceCache};
|
||||||
dom::CreateInterfaceObjects(aCx, aGlobal, ${parentProto},
|
dom::CreateInterfaceObjects(aCx, aGlobal, ${parentProto},
|
||||||
${protoClass}, protoCache,
|
${protoClass}, protoCache,
|
||||||
${constructorProto}, ${interfaceClass}, ${constructArgs}, ${isConstructorChromeOnly}, ${legacyFactoryFunctions},
|
${constructorProto}, ${interfaceInfo}, ${constructArgs}, ${isConstructorChromeOnly}, ${legacyFactoryFunctions},
|
||||||
interfaceCache,
|
interfaceCache,
|
||||||
${properties},
|
${properties},
|
||||||
${chromeProperties},
|
${chromeProperties},
|
||||||
|
|
@ -3711,7 +3662,7 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
||||||
parentProto=parentProto,
|
parentProto=parentProto,
|
||||||
protoCache=protoCache,
|
protoCache=protoCache,
|
||||||
constructorProto=constructorProto,
|
constructorProto=constructorProto,
|
||||||
interfaceClass=interfaceClass,
|
interfaceInfo=interfaceInfo,
|
||||||
constructArgs=constructArgs,
|
constructArgs=constructArgs,
|
||||||
isConstructorChromeOnly=toStringBool(isConstructorChromeOnly),
|
isConstructorChromeOnly=toStringBool(isConstructorChromeOnly),
|
||||||
legacyFactoryFunctions=legacyFactoryFunctions,
|
legacyFactoryFunctions=legacyFactoryFunctions,
|
||||||
|
|
@ -3724,7 +3675,6 @@ class CGCreateInterfaceObjectsMethod(CGAbstractMethod):
|
||||||
legacyWindowAliases="legacyWindowAliases"
|
legacyWindowAliases="legacyWindowAliases"
|
||||||
if self.haveLegacyWindowAliases
|
if self.haveLegacyWindowAliases
|
||||||
else "nullptr",
|
else "nullptr",
|
||||||
isNamespace=toStringBool(self.descriptor.interface.isNamespace()),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# If we fail after here, we must clear interface and prototype caches
|
# If we fail after here, we must clear interface and prototype caches
|
||||||
|
|
@ -17002,7 +16952,7 @@ class CGDescriptor(CGThing):
|
||||||
cgThings.append(CGNamespaceObjectJSClass(descriptor))
|
cgThings.append(CGNamespaceObjectJSClass(descriptor))
|
||||||
elif descriptor.interface.hasInterfaceObject():
|
elif descriptor.interface.hasInterfaceObject():
|
||||||
cgThings.append(CGClassConstructor(descriptor, descriptor.interface.ctor()))
|
cgThings.append(CGClassConstructor(descriptor, descriptor.interface.ctor()))
|
||||||
cgThings.append(CGInterfaceObjectJSClass(descriptor))
|
cgThings.append(CGInterfaceObjectInfo(descriptor))
|
||||||
cgThings.append(CGLegacyFactoryFunctions(descriptor))
|
cgThings.append(CGLegacyFactoryFunctions(descriptor))
|
||||||
|
|
||||||
cgThings.append(CGLegacyCallHook(descriptor))
|
cgThings.append(CGLegacyCallHook(descriptor))
|
||||||
|
|
|
||||||
|
|
@ -570,7 +570,7 @@ struct DOMIfaceAndProtoJSClass {
|
||||||
// initialization for aggregate/POD types.
|
// initialization for aggregate/POD types.
|
||||||
const JSClass mBase;
|
const JSClass mBase;
|
||||||
|
|
||||||
// Either eInterface, eNamespace, eInterfacePrototype,
|
// Either eNamespace, eInterfacePrototype,
|
||||||
// eGlobalInterfacePrototype or eNamedPropertiesObject.
|
// eGlobalInterfacePrototype or eNamedPropertiesObject.
|
||||||
DOMObjectType mType; // uint8_t
|
DOMObjectType mType; // uint8_t
|
||||||
|
|
||||||
|
|
@ -589,25 +589,6 @@ struct DOMIfaceAndProtoJSClass {
|
||||||
const JSClass* ToJSClass() const { return &mBase; }
|
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;
|
class ProtoAndIfaceCache;
|
||||||
|
|
||||||
inline bool DOMGlobalHasProtoAndIFaceCache(JSObject* global) {
|
inline bool DOMGlobalHasProtoAndIFaceCache(JSObject* global) {
|
||||||
|
|
|
||||||
|
|
@ -22,11 +22,18 @@
|
||||||
// Specific objects may have more for storing cached values.
|
// Specific objects may have more for storing cached values.
|
||||||
#define DOM_INSTANCE_RESERVED_SLOTS 1
|
#define DOM_INSTANCE_RESERVED_SLOTS 1
|
||||||
|
|
||||||
// Interface objects store a number of reserved slots equal to the number of
|
// Interface objects store a number of reserved slots equal to
|
||||||
// legacy factory functions.
|
// 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 {
|
enum {
|
||||||
INTERFACE_OBJECT_FIRST_LEGACY_FACTORY_FUNCTION = 0,
|
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 functions store a JSNativeHolder in the
|
||||||
// LEGACY_FACTORY_FUNCTION_NATIVE_HOLDER_RESERVED_SLOT slot.
|
// LEGACY_FACTORY_FUNCTION_NATIVE_HOLDER_RESERVED_SLOT slot.
|
||||||
|
|
|
||||||
|
|
@ -38,18 +38,23 @@ static JSObject* FindNamedConstructorForXray(
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsInterfaceObject(interfaceObject)) {
|
||||||
// This is a call over Xrays, so we will actually use the return value
|
// 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
|
// (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.
|
// constructors with this id, in case that's what the caller is asking for.
|
||||||
for (unsigned slot = INTERFACE_OBJECT_FIRST_LEGACY_FACTORY_FUNCTION;
|
for (unsigned slot = INTERFACE_OBJECT_FIRST_LEGACY_FACTORY_FUNCTION;
|
||||||
slot < JSCLASS_RESERVED_SLOTS(JS::GetClass(interfaceObject)); ++slot) {
|
slot < INTERFACE_OBJECT_MAX_SLOTS; ++slot) {
|
||||||
JSObject* constructor =
|
const JS::Value& v = js::GetFunctionNativeReserved(interfaceObject, slot);
|
||||||
&JS::GetReservedSlot(interfaceObject, slot).toObject();
|
if (!v.isObject()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
JSObject* constructor = &v.toObject();
|
||||||
if (JS_GetMaybePartialFunctionId(JS_GetObjectFunction(constructor)) ==
|
if (JS_GetMaybePartialFunctionId(JS_GetObjectFunction(constructor)) ==
|
||||||
aId.toString()) {
|
aId.toString()) {
|
||||||
return constructor;
|
return constructor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// None of the legacy factory functions match, so the caller must want the
|
// None of the legacy factory functions match, so the caller must want the
|
||||||
// interface object itself.
|
// interface object itself.
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,27 @@ function test() {
|
||||||
// ECMAScript-defined properties live on the prototype, overriding any named properties.
|
// ECMAScript-defined properties live on the prototype, overriding any named properties.
|
||||||
checkXrayProperty(coll, "toString", [ undefined, undefined, win.Object.prototype.toString ]);
|
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.
|
// Frozen arrays should come from our compartment, not the target one.
|
||||||
var languages1 = win.navigator.languages;
|
var languages1 = win.navigator.languages;
|
||||||
isnot(languages1, undefined, "Must have .languages");
|
isnot(languages1, undefined, "Must have .languages");
|
||||||
|
|
@ -358,7 +379,7 @@ function test() {
|
||||||
// legacyCaller should work.
|
// legacyCaller should work.
|
||||||
ok(win.HTMLAllCollection.isInstance(doc.all),
|
ok(win.HTMLAllCollection.isInstance(doc.all),
|
||||||
"HTMLDocument.all should be an instance of HTMLAllCollection");
|
"HTMLDocument.all should be an instance of HTMLAllCollection");
|
||||||
let element, threw;
|
let element;
|
||||||
try {
|
try {
|
||||||
threw = false;
|
threw = false;
|
||||||
element = doc.all(0);
|
element = doc.all(0);
|
||||||
|
|
|
||||||
|
|
@ -1799,6 +1799,11 @@ bool DOMXrayTraits::call(JSContext* cx, HandleObject wrapper,
|
||||||
// using "legacycaller". At this time for all the legacycaller users it makes
|
// 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
|
// more sense to invoke on the xray compartment, so we just go ahead and do
|
||||||
// that for everything.
|
// 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::IsProxy(obj)) {
|
||||||
if (JS::IsCallable(obj)) {
|
if (JS::IsCallable(obj)) {
|
||||||
// Passing obj here, but it doesn't really matter because legacycaller
|
// Passing obj here, but it doesn't really matter because legacycaller
|
||||||
|
|
@ -1822,9 +1827,14 @@ bool DOMXrayTraits::construct(JSContext* cx, HandleObject wrapper,
|
||||||
const JS::CallArgs& args,
|
const JS::CallArgs& args,
|
||||||
const js::Wrapper& baseInstance) {
|
const js::Wrapper& baseInstance) {
|
||||||
RootedObject obj(cx, getTargetObject(wrapper));
|
RootedObject obj(cx, getTargetObject(wrapper));
|
||||||
MOZ_ASSERT(mozilla::dom::HasConstructor(obj));
|
|
||||||
const JSClass* clasp = JS::GetClass(obj);
|
|
||||||
// See comments in DOMXrayTraits::call() explaining what's going on here.
|
// 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 {
|
||||||
|
const JSClass* clasp = JS::GetClass(obj);
|
||||||
if (clasp->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS) {
|
if (clasp->flags & JSCLASS_IS_DOMIFACEANDPROTOJSCLASS) {
|
||||||
if (JSNative construct = clasp->getConstruct()) {
|
if (JSNative construct = clasp->getConstruct()) {
|
||||||
if (!construct(cx, args.length(), args.base())) {
|
if (!construct(cx, args.length(), args.base())) {
|
||||||
|
|
@ -1840,6 +1850,7 @@ bool DOMXrayTraits::construct(JSContext* cx, HandleObject wrapper,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!args.rval().isObject() || !JS_WrapValue(cx, args.rval())) {
|
if (!args.rval().isObject() || !JS_WrapValue(cx, args.rval())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue