Skip to content

Commit a7f54a9

Browse files
Bug 1887721 - Use correct order when defining length/name/prototype on legacy factory functions. r=saschanaz
Implements whatwg/webidl#914 for legacy factory functions. https://bugzilla.mozilla.org/show_bug.cgi?id=1629803 is the bug that would fix this in SpiderMonkey, working around that for now. Differential Revision: https://phabricator.services.mozilla.com/D205805
1 parent 93d0f5c commit a7f54a9

File tree

2 files changed

+38
-33
lines changed

2 files changed

+38
-33
lines changed

dom/bindings/BindingUtils.cpp

+32-33
Original file line numberDiff line numberDiff line change
@@ -770,19 +770,31 @@ bool LegacyFactoryFunctionJSNative(JSContext* cx, unsigned argc,
770770
->mNative(cx, argc, vp);
771771
}
772772

773-
static JSObject* CreateLegacyFactoryFunction(JSContext* cx, jsid name,
774-
const JSNativeHolder* nativeHolder,
775-
unsigned ctorNargs) {
776-
JSFunction* fun = js::NewFunctionByIdWithReserved(
777-
cx, LegacyFactoryFunctionJSNative, ctorNargs, JSFUN_CONSTRUCTOR, name);
773+
// This creates a JSFunction and sets its length and name properties in the
774+
// order that ECMAScript's CreateBuiltinFunction does.
775+
static JSObject* CreateBuiltinFunctionForConstructor(
776+
JSContext* aCx, JSNative aNative, size_t aNativeReservedSlot,
777+
void* aNativeReserved, unsigned int aNargs, jsid aName,
778+
JS::Handle<JSObject*> aProto) {
779+
JSFunction* fun = js::NewFunctionByIdWithReservedAndProto(
780+
aCx, aNative, aProto, aNargs, JSFUN_CONSTRUCTOR, aName);
778781
if (!fun) {
779782
return nullptr;
780783
}
781784

782-
JSObject* constructor = JS_GetFunctionObject(fun);
783-
js::SetFunctionNativeReserved(
784-
constructor, LEGACY_FACTORY_FUNCTION_NATIVE_HOLDER_RESERVED_SLOT,
785-
JS::PrivateValue(const_cast<JSNativeHolder*>(nativeHolder)));
785+
JS::Rooted<JSObject*> constructor(aCx, JS_GetFunctionObject(fun));
786+
js::SetFunctionNativeReserved(constructor, aNativeReservedSlot,
787+
JS::PrivateValue(aNativeReserved));
788+
789+
// Eagerly force creation of the .length and .name properties, because
790+
// SpiderMonkey creates them lazily (see
791+
// https://bugzilla.mozilla.org/show_bug.cgi?id=1629803).
792+
bool unused;
793+
if (!JS_HasProperty(aCx, constructor, "length", &unused) ||
794+
!JS_HasProperty(aCx, constructor, "name", &unused)) {
795+
return nullptr;
796+
}
797+
786798
return constructor;
787799
}
788800

@@ -936,29 +948,12 @@ static JSObject* CreateInterfaceObject(
936948

937949
JS::Rooted<jsid> nameId(cx, JS::PropertyKey::NonIntAtom(name));
938950

939-
JS::Rooted<JSObject*> constructor(cx);
940-
{
941-
JSFunction* fun = js::NewFunctionByIdWithReservedAndProto(
942-
cx, InterfaceObjectJSNative, interfaceProto, ctorNargs,
943-
JSFUN_CONSTRUCTOR, nameId);
944-
if (!fun) {
945-
return nullptr;
946-
}
947-
948-
constructor = JS_GetFunctionObject(fun);
949-
}
950-
951-
js::SetFunctionNativeReserved(
952-
constructor, INTERFACE_OBJECT_INFO_RESERVED_SLOT,
953-
JS::PrivateValue(const_cast<DOMInterfaceInfo*>(interfaceInfo)));
954-
955-
// Eagerly force creation of the .length and .name properties, because they
956-
// need to be defined before the .prototype property (CreateBuiltinFunction
957-
// called from the WebIDL spec sets them, and then the .prototype property is
958-
// defined in the WebIDL spec itself).
959-
bool unused;
960-
if (!JS_HasProperty(cx, constructor, "length", &unused) ||
961-
!JS_HasProperty(cx, constructor, "name", &unused)) {
951+
JS::Rooted<JSObject*> constructor(
952+
cx, CreateBuiltinFunctionForConstructor(
953+
cx, InterfaceObjectJSNative, INTERFACE_OBJECT_INFO_RESERVED_SLOT,
954+
const_cast<DOMInterfaceInfo*>(interfaceInfo), ctorNargs, nameId,
955+
interfaceProto));
956+
if (!constructor) {
962957
return nullptr;
963958
}
964959

@@ -1001,7 +996,11 @@ static JSObject* CreateInterfaceObject(
1001996
nameId = JS::PropertyKey::NonIntAtom(fname);
1002997

1003998
JS::Rooted<JSObject*> legacyFactoryFunction(
1004-
cx, CreateLegacyFactoryFunction(cx, nameId, &lff.mHolder, lff.mNargs));
999+
cx, CreateBuiltinFunctionForConstructor(
1000+
cx, LegacyFactoryFunctionJSNative,
1001+
LEGACY_FACTORY_FUNCTION_NATIVE_HOLDER_RESERVED_SLOT,
1002+
const_cast<JSNativeHolder*>(&lff.mHolder), lff.mNargs, nameId,
1003+
nullptr));
10051004
if (!legacyFactoryFunction ||
10061005
!JS_DefineProperty(cx, legacyFactoryFunction, "prototype", proto,
10071006
JSPROP_PERMANENT | JSPROP_READONLY) ||
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
"use strict";
2+
3+
test(() => {
4+
const ownPropKeys = Reflect.ownKeys(Image).slice(0, 3);
5+
assert_array_equals(ownPropKeys, ["length", "name", "prototype"]);
6+
}, 'Legacy factory function property enumeration order of "length", "name", and "prototype"');

0 commit comments

Comments
 (0)