mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-08-15 08:53:07 +09:00
Bug 1318017: Call GetPrototypeFromConstructor for generator/async function and Intl constructors
[Depends on] Bug 755821: Function() should use the parser's argument parsing code
This commit is contained in:
parent
093e83da1a
commit
e7fdd26fde
11 changed files with 586 additions and 53 deletions
|
|
@ -765,42 +765,53 @@ static const JSFunctionSpec collator_methods[] = {
|
|||
};
|
||||
|
||||
/**
|
||||
* Collator constructor.
|
||||
* Spec: ECMAScript Internationalization API Specification, 10.1
|
||||
* 10.1.2 Intl.Collator([ locales [, options]])
|
||||
*
|
||||
* ES2017 Intl draft rev 94045d234762ad107a3d09bb6f7381a65f1a2f9b
|
||||
*/
|
||||
static bool
|
||||
Collator(JSContext* cx, const CallArgs& args, bool construct)
|
||||
{
|
||||
RootedObject obj(cx);
|
||||
|
||||
// We're following ECMA-402 1st Edition when Collator is called because of
|
||||
// backward compatibility issues.
|
||||
// See https://github.com/tc39/ecma402/issues/57
|
||||
if (!construct) {
|
||||
// 10.1.2.1 step 3
|
||||
// ES Intl 1st ed., 10.1.2.1 step 3
|
||||
JSObject* intl = cx->global()->getOrCreateIntlObject(cx);
|
||||
if (!intl)
|
||||
return false;
|
||||
RootedValue self(cx, args.thisv());
|
||||
if (!self.isUndefined() && (!self.isObject() || self.toObject() != *intl)) {
|
||||
// 10.1.2.1 step 4
|
||||
// ES Intl 1st ed., 10.1.2.1 step 4
|
||||
obj = ToObject(cx, self);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
// 10.1.2.1 step 5
|
||||
// ES Intl 1st ed., 10.1.2.1 step 5
|
||||
bool extensible;
|
||||
if (!IsExtensible(cx, obj, &extensible))
|
||||
return false;
|
||||
if (!extensible)
|
||||
return Throw(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE);
|
||||
} else {
|
||||
// 10.1.2.1 step 3.a
|
||||
// ES Intl 1st ed., 10.1.2.1 step 3.a
|
||||
construct = true;
|
||||
}
|
||||
}
|
||||
if (construct) {
|
||||
// 10.1.3.1 paragraph 2
|
||||
RootedObject proto(cx, cx->global()->getOrCreateCollatorPrototype(cx));
|
||||
if (!proto)
|
||||
// Steps 2-5 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
||||
RootedObject proto(cx);
|
||||
if (args.isConstructing() && !GetPrototypeFromCallableConstructor(cx, args, &proto))
|
||||
return false;
|
||||
|
||||
if (!proto) {
|
||||
proto = cx->global()->getOrCreateCollatorPrototype(cx);
|
||||
if (!proto)
|
||||
return false;
|
||||
}
|
||||
|
||||
obj = NewObjectWithGivenProto(cx, &CollatorClass, proto);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
|
@ -808,15 +819,13 @@ Collator(JSContext* cx, const CallArgs& args, bool construct)
|
|||
obj->as<NativeObject>().setReservedSlot(UCOLLATOR_SLOT, PrivateValue(nullptr));
|
||||
}
|
||||
|
||||
// 10.1.2.1 steps 1 and 2; 10.1.3.1 steps 1 and 2
|
||||
RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
|
||||
RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
|
||||
|
||||
// 10.1.2.1 step 6; 10.1.3.1 step 3
|
||||
// Step 6.
|
||||
if (!IntlInitialize(cx, obj, cx->names().InitializeCollator, locales, options))
|
||||
return false;
|
||||
|
||||
// 10.1.2.1 steps 3.a and 7
|
||||
args.rval().setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -833,6 +842,7 @@ js::intl_Collator(JSContext* cx, unsigned argc, Value* vp)
|
|||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 2);
|
||||
MOZ_ASSERT(!args.isConstructing());
|
||||
// intl_Collator is an intrinsic for self-hosted JavaScript, so it cannot
|
||||
// be used with "new", but it still has to be treated as a constructor.
|
||||
return Collator(cx, args, true);
|
||||
|
|
@ -1257,42 +1267,53 @@ static const JSFunctionSpec numberFormat_methods[] = {
|
|||
};
|
||||
|
||||
/**
|
||||
* NumberFormat constructor.
|
||||
* Spec: ECMAScript Internationalization API Specification, 11.1
|
||||
* 11.2.1 Intl.NumberFormat([ locales [, options]])
|
||||
*
|
||||
* ES2017 Intl draft rev 94045d234762ad107a3d09bb6f7381a65f1a2f9b
|
||||
*/
|
||||
static bool
|
||||
NumberFormat(JSContext* cx, const CallArgs& args, bool construct)
|
||||
{
|
||||
RootedObject obj(cx);
|
||||
|
||||
// We're following ECMA-402 1st Edition when NumberFormat is called
|
||||
// because of backward compatibility issues.
|
||||
// See https://github.com/tc39/ecma402/issues/57
|
||||
if (!construct) {
|
||||
// 11.1.2.1 step 3
|
||||
// ES Intl 1st ed., 11.1.2.1 step 3
|
||||
JSObject* intl = cx->global()->getOrCreateIntlObject(cx);
|
||||
if (!intl)
|
||||
return false;
|
||||
RootedValue self(cx, args.thisv());
|
||||
if (!self.isUndefined() && (!self.isObject() || self.toObject() != *intl)) {
|
||||
// 11.1.2.1 step 4
|
||||
// ES Intl 1st ed., 11.1.2.1 step 4
|
||||
obj = ToObject(cx, self);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
// 11.1.2.1 step 5
|
||||
// ES Intl 1st ed., 11.1.2.1 step 5
|
||||
bool extensible;
|
||||
if (!IsExtensible(cx, obj, &extensible))
|
||||
return false;
|
||||
if (!extensible)
|
||||
return Throw(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE);
|
||||
} else {
|
||||
// 11.1.2.1 step 3.a
|
||||
// ES Intl 1st ed., 11.1.2.1 step 3.a
|
||||
construct = true;
|
||||
}
|
||||
}
|
||||
if (construct) {
|
||||
// 11.1.3.1 paragraph 2
|
||||
RootedObject proto(cx, cx->global()->getOrCreateNumberFormatPrototype(cx));
|
||||
if (!proto)
|
||||
// Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
||||
RootedObject proto(cx);
|
||||
if (args.isConstructing() && !GetPrototypeFromCallableConstructor(cx, args, &proto))
|
||||
return false;
|
||||
|
||||
if (!proto) {
|
||||
proto = cx->global()->getOrCreateNumberFormatPrototype(cx);
|
||||
if (!proto)
|
||||
return false;
|
||||
}
|
||||
|
||||
obj = NewObjectWithGivenProto(cx, &NumberFormatClass, proto);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
|
@ -1300,15 +1321,13 @@ NumberFormat(JSContext* cx, const CallArgs& args, bool construct)
|
|||
obj->as<NativeObject>().setReservedSlot(UNUMBER_FORMAT_SLOT, PrivateValue(nullptr));
|
||||
}
|
||||
|
||||
// 11.1.2.1 steps 1 and 2; 11.1.3.1 steps 1 and 2
|
||||
RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
|
||||
RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
|
||||
|
||||
// 11.1.2.1 step 6; 11.1.3.1 step 3
|
||||
// Step 3.
|
||||
if (!IntlInitialize(cx, obj, cx->names().InitializeNumberFormat, locales, options))
|
||||
return false;
|
||||
|
||||
// 11.1.2.1 steps 3.a and 7
|
||||
args.rval().setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1325,6 +1344,7 @@ js::intl_NumberFormat(JSContext* cx, unsigned argc, Value* vp)
|
|||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 2);
|
||||
MOZ_ASSERT(!args.isConstructing());
|
||||
// intl_NumberFormat is an intrinsic for self-hosted JavaScript, so it
|
||||
// cannot be used with "new", but it still has to be treated as a
|
||||
// constructor.
|
||||
|
|
@ -1725,42 +1745,53 @@ static const JSFunctionSpec dateTimeFormat_methods[] = {
|
|||
};
|
||||
|
||||
/**
|
||||
* DateTimeFormat constructor.
|
||||
* Spec: ECMAScript Internationalization API Specification, 12.1
|
||||
* 12.2.1 Intl.DateTimeFormat([ locales [, options]])
|
||||
*
|
||||
* ES2017 Intl draft rev 94045d234762ad107a3d09bb6f7381a65f1a2f9b
|
||||
*/
|
||||
static bool
|
||||
DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct)
|
||||
{
|
||||
RootedObject obj(cx);
|
||||
|
||||
// We're following ECMA-402 1st Edition when DateTimeFormat is called
|
||||
// because of backward compatibility issues.
|
||||
// See https://github.com/tc39/ecma402/issues/57
|
||||
if (!construct) {
|
||||
// 12.1.2.1 step 3
|
||||
// ES Intl 1st ed., 12.1.2.1 step 3
|
||||
JSObject* intl = cx->global()->getOrCreateIntlObject(cx);
|
||||
if (!intl)
|
||||
return false;
|
||||
RootedValue self(cx, args.thisv());
|
||||
if (!self.isUndefined() && (!self.isObject() || self.toObject() != *intl)) {
|
||||
// 12.1.2.1 step 4
|
||||
// ES Intl 1st ed., 12.1.2.1 step 4
|
||||
obj = ToObject(cx, self);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
// 12.1.2.1 step 5
|
||||
// ES Intl 1st ed., 12.1.2.1 step 5
|
||||
bool extensible;
|
||||
if (!IsExtensible(cx, obj, &extensible))
|
||||
return false;
|
||||
if (!extensible)
|
||||
return Throw(cx, obj, JSMSG_OBJECT_NOT_EXTENSIBLE);
|
||||
} else {
|
||||
// 12.1.2.1 step 3.a
|
||||
// ES Intl 1st ed., 12.1.2.1 step 3.a
|
||||
construct = true;
|
||||
}
|
||||
}
|
||||
if (construct) {
|
||||
// 12.1.3.1 paragraph 2
|
||||
RootedObject proto(cx, cx->global()->getOrCreateDateTimeFormatPrototype(cx));
|
||||
if (!proto)
|
||||
// Step 2 (Inlined 9.1.14, OrdinaryCreateFromConstructor).
|
||||
RootedObject proto(cx);
|
||||
if (args.isConstructing() && !GetPrototypeFromCallableConstructor(cx, args, &proto))
|
||||
return false;
|
||||
|
||||
if (!proto) {
|
||||
proto = cx->global()->getOrCreateDateTimeFormatPrototype(cx);
|
||||
if (!proto)
|
||||
return false;
|
||||
}
|
||||
|
||||
obj = NewObjectWithGivenProto(cx, &DateTimeFormatClass, proto);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
|
@ -1768,15 +1799,13 @@ DateTimeFormat(JSContext* cx, const CallArgs& args, bool construct)
|
|||
obj->as<NativeObject>().setReservedSlot(UDATE_FORMAT_SLOT, PrivateValue(nullptr));
|
||||
}
|
||||
|
||||
// 12.1.2.1 steps 1 and 2; 12.1.3.1 steps 1 and 2
|
||||
RootedValue locales(cx, args.length() > 0 ? args[0] : UndefinedValue());
|
||||
RootedValue options(cx, args.length() > 1 ? args[1] : UndefinedValue());
|
||||
|
||||
// 12.1.2.1 step 6; 12.1.3.1 step 3
|
||||
// Step 3.
|
||||
if (!IntlInitialize(cx, obj, cx->names().InitializeDateTimeFormat, locales, options))
|
||||
return false;
|
||||
|
||||
// 12.1.2.1 steps 3.a and 7
|
||||
args.rval().setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -1793,6 +1822,7 @@ js::intl_DateTimeFormat(JSContext* cx, unsigned argc, Value* vp)
|
|||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 2);
|
||||
MOZ_ASSERT(!args.isConstructing());
|
||||
// intl_DateTimeFormat is an intrinsic for self-hosted JavaScript, so it
|
||||
// cannot be used with "new", but it still has to be treated as a
|
||||
// constructor.
|
||||
|
|
|
|||
|
|
@ -1682,11 +1682,9 @@ const JSFunctionSpec js::function_methods[] = {
|
|||
};
|
||||
|
||||
static bool
|
||||
FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind generatorKind,
|
||||
FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generatorKind,
|
||||
FunctionAsyncKind asyncKind)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
/* Block this call if security callbacks forbid it. */
|
||||
Rooted<GlobalObject*> global(cx, &args.callee().global());
|
||||
if (!GlobalObject::isRuntimeCodeGenEnabled(cx, global)) {
|
||||
|
|
@ -1803,16 +1801,23 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
|
|||
* and so would a call to f from another top-level's script or function.
|
||||
*/
|
||||
RootedAtom anonymousAtom(cx, cx->names().anonymous);
|
||||
|
||||
// ES2017, draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077
|
||||
// 19.2.1.1.1 Runtime Semantics: CreateDynamicFunction, step 24.
|
||||
RootedObject proto(cx);
|
||||
if (isStarGenerator) {
|
||||
if (!isAsync) {
|
||||
if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
|
||||
return false;
|
||||
}
|
||||
|
||||
// 19.2.1.1.1, step 4.d, use %Generator% as the fallback prototype.
|
||||
// Also use %Generator% for the unwrapped function of async functions.
|
||||
if (!proto && isStarGenerator) {
|
||||
// Unwrapped function of async function should use GeneratorFunction,
|
||||
// while wrapped function isn't generator.
|
||||
proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global);
|
||||
if (!proto)
|
||||
return false;
|
||||
} else {
|
||||
if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject globalLexical(cx, &global->lexicalEnvironment());
|
||||
|
|
@ -1921,24 +1926,47 @@ FunctionConstructor(JSContext* cx, unsigned argc, Value* vp, GeneratorKind gener
|
|||
bool
|
||||
js::Function(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
return FunctionConstructor(cx, argc, vp, NotGenerator, SyncFunction);
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return FunctionConstructor(cx, args, NotGenerator, SyncFunction);
|
||||
}
|
||||
|
||||
bool
|
||||
js::Generator(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
return FunctionConstructor(cx, argc, vp, StarGenerator, SyncFunction);
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
return FunctionConstructor(cx, args, StarGenerator, SyncFunction);
|
||||
}
|
||||
|
||||
bool
|
||||
js::AsyncFunctionConstructor(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (!FunctionConstructor(cx, argc, vp, StarGenerator, AsyncFunction))
|
||||
|
||||
// Save the callee before its reset in FunctionConstructor().
|
||||
RootedObject newTarget(cx);
|
||||
if (args.isConstructing())
|
||||
newTarget = &args.newTarget().toObject();
|
||||
else
|
||||
newTarget = &args.callee();
|
||||
|
||||
if (!FunctionConstructor(cx, args, StarGenerator, AsyncFunction))
|
||||
return false;
|
||||
|
||||
// ES2017, draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077
|
||||
// 19.2.1.1.1 Runtime Semantics: CreateDynamicFunction, step 24.
|
||||
RootedObject proto(cx);
|
||||
if (!GetPrototypeFromConstructor(cx, newTarget, &proto))
|
||||
return false;
|
||||
|
||||
// 19.2.1.1.1, step 4.d, use %AsyncFunctionPrototype% as the fallback.
|
||||
if (!proto) {
|
||||
proto = GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global());
|
||||
if (!proto)
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedFunction unwrapped(cx, &args.rval().toObject().as<JSFunction>());
|
||||
RootedObject wrapped(cx, WrapAsyncFunction(cx, unwrapped));
|
||||
RootedObject wrapped(cx, WrapAsyncFunctionWithProto(cx, unwrapped, proto));
|
||||
if (!wrapped)
|
||||
return false;
|
||||
|
||||
|
|
|
|||
81
js/src/tests/Intl/Collator/construct-newtarget.js
Normal file
81
js/src/tests/Intl/Collator/construct-newtarget.js
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
// |reftest| skip-if(!this.hasOwnProperty("Intl"))
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
// Test subclassing %Intl.Collator% works correctly.
|
||||
class MyCollator extends Intl.Collator {}
|
||||
|
||||
var obj = new MyCollator();
|
||||
assertEq(obj instanceof MyCollator, true);
|
||||
assertEq(obj instanceof Intl.Collator, true);
|
||||
assertEq(Object.getPrototypeOf(obj), MyCollator.prototype);
|
||||
|
||||
obj = Reflect.construct(MyCollator, []);
|
||||
assertEq(obj instanceof MyCollator, true);
|
||||
assertEq(obj instanceof Intl.Collator, true);
|
||||
assertEq(Object.getPrototypeOf(obj), MyCollator.prototype);
|
||||
|
||||
obj = Reflect.construct(MyCollator, [], MyCollator);
|
||||
assertEq(obj instanceof MyCollator, true);
|
||||
assertEq(obj instanceof Intl.Collator, true);
|
||||
assertEq(Object.getPrototypeOf(obj), MyCollator.prototype);
|
||||
|
||||
obj = Reflect.construct(MyCollator, [], Intl.Collator);
|
||||
assertEq(obj instanceof MyCollator, false);
|
||||
assertEq(obj instanceof Intl.Collator, true);
|
||||
assertEq(Object.getPrototypeOf(obj), Intl.Collator.prototype);
|
||||
|
||||
|
||||
// Set a different constructor as NewTarget.
|
||||
obj = Reflect.construct(MyCollator, [], Array);
|
||||
assertEq(obj instanceof MyCollator, false);
|
||||
assertEq(obj instanceof Intl.Collator, false);
|
||||
assertEq(obj instanceof Array, true);
|
||||
assertEq(Object.getPrototypeOf(obj), Array.prototype);
|
||||
|
||||
obj = Reflect.construct(Intl.Collator, [], Array);
|
||||
assertEq(obj instanceof Intl.Collator, false);
|
||||
assertEq(obj instanceof Array, true);
|
||||
assertEq(Object.getPrototypeOf(obj), Array.prototype);
|
||||
|
||||
|
||||
// The prototype defaults to %CollatorPrototype% if null.
|
||||
function NewTargetNullPrototype() {}
|
||||
NewTargetNullPrototype.prototype = null;
|
||||
|
||||
obj = Reflect.construct(Intl.Collator, [], NewTargetNullPrototype);
|
||||
assertEq(obj instanceof Intl.Collator, true);
|
||||
assertEq(Object.getPrototypeOf(obj), Intl.Collator.prototype);
|
||||
|
||||
obj = Reflect.construct(MyCollator, [], NewTargetNullPrototype);
|
||||
assertEq(obj instanceof MyCollator, false);
|
||||
assertEq(obj instanceof Intl.Collator, true);
|
||||
assertEq(Object.getPrototypeOf(obj), Intl.Collator.prototype);
|
||||
|
||||
|
||||
// "prototype" property is retrieved exactly once.
|
||||
var trapLog = [], getLog = [];
|
||||
var ProxiedConstructor = new Proxy(Intl.Collator, new Proxy({
|
||||
get(target, propertyKey, receiver) {
|
||||
getLog.push(propertyKey);
|
||||
return Reflect.get(target, propertyKey, receiver);
|
||||
}
|
||||
}, {
|
||||
get(target, propertyKey, receiver) {
|
||||
trapLog.push(propertyKey);
|
||||
return Reflect.get(target, propertyKey, receiver);
|
||||
}
|
||||
}));
|
||||
|
||||
obj = Reflect.construct(Intl.Collator, [], ProxiedConstructor);
|
||||
assertEqArray(trapLog, ["get"]);
|
||||
assertEqArray(getLog, ["prototype"]);
|
||||
assertEq(obj instanceof Intl.Collator, true);
|
||||
assertEq(Object.getPrototypeOf(obj), Intl.Collator.prototype);
|
||||
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
||||
81
js/src/tests/Intl/DateTimeFormat/construct-newtarget.js
Normal file
81
js/src/tests/Intl/DateTimeFormat/construct-newtarget.js
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
// |reftest| skip-if(!this.hasOwnProperty("Intl"))
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
// Test subclassing %Intl.DateTimeFormat% works correctly.
|
||||
class MyDateTimeFormat extends Intl.DateTimeFormat {}
|
||||
|
||||
var obj = new MyDateTimeFormat();
|
||||
assertEq(obj instanceof MyDateTimeFormat, true);
|
||||
assertEq(obj instanceof Intl.DateTimeFormat, true);
|
||||
assertEq(Object.getPrototypeOf(obj), MyDateTimeFormat.prototype);
|
||||
|
||||
obj = Reflect.construct(MyDateTimeFormat, []);
|
||||
assertEq(obj instanceof MyDateTimeFormat, true);
|
||||
assertEq(obj instanceof Intl.DateTimeFormat, true);
|
||||
assertEq(Object.getPrototypeOf(obj), MyDateTimeFormat.prototype);
|
||||
|
||||
obj = Reflect.construct(MyDateTimeFormat, [], MyDateTimeFormat);
|
||||
assertEq(obj instanceof MyDateTimeFormat, true);
|
||||
assertEq(obj instanceof Intl.DateTimeFormat, true);
|
||||
assertEq(Object.getPrototypeOf(obj), MyDateTimeFormat.prototype);
|
||||
|
||||
obj = Reflect.construct(MyDateTimeFormat, [], Intl.DateTimeFormat);
|
||||
assertEq(obj instanceof MyDateTimeFormat, false);
|
||||
assertEq(obj instanceof Intl.DateTimeFormat, true);
|
||||
assertEq(Object.getPrototypeOf(obj), Intl.DateTimeFormat.prototype);
|
||||
|
||||
|
||||
// Set a different constructor as NewTarget.
|
||||
obj = Reflect.construct(MyDateTimeFormat, [], Array);
|
||||
assertEq(obj instanceof MyDateTimeFormat, false);
|
||||
assertEq(obj instanceof Intl.DateTimeFormat, false);
|
||||
assertEq(obj instanceof Array, true);
|
||||
assertEq(Object.getPrototypeOf(obj), Array.prototype);
|
||||
|
||||
obj = Reflect.construct(Intl.DateTimeFormat, [], Array);
|
||||
assertEq(obj instanceof Intl.DateTimeFormat, false);
|
||||
assertEq(obj instanceof Array, true);
|
||||
assertEq(Object.getPrototypeOf(obj), Array.prototype);
|
||||
|
||||
|
||||
// The prototype defaults to %DateTimeFormatPrototype% if null.
|
||||
function NewTargetNullPrototype() {}
|
||||
NewTargetNullPrototype.prototype = null;
|
||||
|
||||
obj = Reflect.construct(Intl.DateTimeFormat, [], NewTargetNullPrototype);
|
||||
assertEq(obj instanceof Intl.DateTimeFormat, true);
|
||||
assertEq(Object.getPrototypeOf(obj), Intl.DateTimeFormat.prototype);
|
||||
|
||||
obj = Reflect.construct(MyDateTimeFormat, [], NewTargetNullPrototype);
|
||||
assertEq(obj instanceof MyDateTimeFormat, false);
|
||||
assertEq(obj instanceof Intl.DateTimeFormat, true);
|
||||
assertEq(Object.getPrototypeOf(obj), Intl.DateTimeFormat.prototype);
|
||||
|
||||
|
||||
// "prototype" property is retrieved exactly once.
|
||||
var trapLog = [], getLog = [];
|
||||
var ProxiedConstructor = new Proxy(Intl.DateTimeFormat, new Proxy({
|
||||
get(target, propertyKey, receiver) {
|
||||
getLog.push(propertyKey);
|
||||
return Reflect.get(target, propertyKey, receiver);
|
||||
}
|
||||
}, {
|
||||
get(target, propertyKey, receiver) {
|
||||
trapLog.push(propertyKey);
|
||||
return Reflect.get(target, propertyKey, receiver);
|
||||
}
|
||||
}));
|
||||
|
||||
obj = Reflect.construct(Intl.DateTimeFormat, [], ProxiedConstructor);
|
||||
assertEqArray(trapLog, ["get"]);
|
||||
assertEqArray(getLog, ["prototype"]);
|
||||
assertEq(obj instanceof Intl.DateTimeFormat, true);
|
||||
assertEq(Object.getPrototypeOf(obj), Intl.DateTimeFormat.prototype);
|
||||
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
||||
81
js/src/tests/Intl/NumberFormat/construct-newtarget.js
Normal file
81
js/src/tests/Intl/NumberFormat/construct-newtarget.js
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
// |reftest| skip-if(!this.hasOwnProperty("Intl"))
|
||||
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
// Test subclassing %Intl.NumberFormat% works correctly.
|
||||
class MyNumberFormat extends Intl.NumberFormat {}
|
||||
|
||||
var obj = new MyNumberFormat();
|
||||
assertEq(obj instanceof MyNumberFormat, true);
|
||||
assertEq(obj instanceof Intl.NumberFormat, true);
|
||||
assertEq(Object.getPrototypeOf(obj), MyNumberFormat.prototype);
|
||||
|
||||
obj = Reflect.construct(MyNumberFormat, []);
|
||||
assertEq(obj instanceof MyNumberFormat, true);
|
||||
assertEq(obj instanceof Intl.NumberFormat, true);
|
||||
assertEq(Object.getPrototypeOf(obj), MyNumberFormat.prototype);
|
||||
|
||||
obj = Reflect.construct(MyNumberFormat, [], MyNumberFormat);
|
||||
assertEq(obj instanceof MyNumberFormat, true);
|
||||
assertEq(obj instanceof Intl.NumberFormat, true);
|
||||
assertEq(Object.getPrototypeOf(obj), MyNumberFormat.prototype);
|
||||
|
||||
obj = Reflect.construct(MyNumberFormat, [], Intl.NumberFormat);
|
||||
assertEq(obj instanceof MyNumberFormat, false);
|
||||
assertEq(obj instanceof Intl.NumberFormat, true);
|
||||
assertEq(Object.getPrototypeOf(obj), Intl.NumberFormat.prototype);
|
||||
|
||||
|
||||
// Set a different constructor as NewTarget.
|
||||
obj = Reflect.construct(MyNumberFormat, [], Array);
|
||||
assertEq(obj instanceof MyNumberFormat, false);
|
||||
assertEq(obj instanceof Intl.NumberFormat, false);
|
||||
assertEq(obj instanceof Array, true);
|
||||
assertEq(Object.getPrototypeOf(obj), Array.prototype);
|
||||
|
||||
obj = Reflect.construct(Intl.NumberFormat, [], Array);
|
||||
assertEq(obj instanceof Intl.NumberFormat, false);
|
||||
assertEq(obj instanceof Array, true);
|
||||
assertEq(Object.getPrototypeOf(obj), Array.prototype);
|
||||
|
||||
|
||||
// The prototype defaults to %NumberFormatPrototype% if null.
|
||||
function NewTargetNullPrototype() {}
|
||||
NewTargetNullPrototype.prototype = null;
|
||||
|
||||
obj = Reflect.construct(Intl.NumberFormat, [], NewTargetNullPrototype);
|
||||
assertEq(obj instanceof Intl.NumberFormat, true);
|
||||
assertEq(Object.getPrototypeOf(obj), Intl.NumberFormat.prototype);
|
||||
|
||||
obj = Reflect.construct(MyNumberFormat, [], NewTargetNullPrototype);
|
||||
assertEq(obj instanceof MyNumberFormat, false);
|
||||
assertEq(obj instanceof Intl.NumberFormat, true);
|
||||
assertEq(Object.getPrototypeOf(obj), Intl.NumberFormat.prototype);
|
||||
|
||||
|
||||
// "prototype" property is retrieved exactly once.
|
||||
var trapLog = [], getLog = [];
|
||||
var ProxiedConstructor = new Proxy(Intl.NumberFormat, new Proxy({
|
||||
get(target, propertyKey, receiver) {
|
||||
getLog.push(propertyKey);
|
||||
return Reflect.get(target, propertyKey, receiver);
|
||||
}
|
||||
}, {
|
||||
get(target, propertyKey, receiver) {
|
||||
trapLog.push(propertyKey);
|
||||
return Reflect.get(target, propertyKey, receiver);
|
||||
}
|
||||
}));
|
||||
|
||||
obj = Reflect.construct(Intl.NumberFormat, [], ProxiedConstructor);
|
||||
assertEqArray(trapLog, ["get"]);
|
||||
assertEqArray(getLog, ["prototype"]);
|
||||
assertEq(obj instanceof Intl.NumberFormat, true);
|
||||
assertEq(Object.getPrototypeOf(obj), Intl.NumberFormat.prototype);
|
||||
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
||||
79
js/src/tests/ecma_2017/AsyncFunctions/construct-newtarget.js
Normal file
79
js/src/tests/ecma_2017/AsyncFunctions/construct-newtarget.js
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const AsyncFunction = async function(){}.constructor;
|
||||
|
||||
|
||||
// Test subclassing %AsyncFunction% works correctly.
|
||||
class MyAsync extends AsyncFunction {}
|
||||
|
||||
var fn = new MyAsync();
|
||||
assertEq(fn instanceof MyAsync, true);
|
||||
assertEq(fn instanceof AsyncFunction, true);
|
||||
assertEq(Object.getPrototypeOf(fn), MyAsync.prototype);
|
||||
|
||||
fn = Reflect.construct(MyAsync, []);
|
||||
assertEq(fn instanceof MyAsync, true);
|
||||
assertEq(fn instanceof AsyncFunction, true);
|
||||
assertEq(Object.getPrototypeOf(fn), MyAsync.prototype);
|
||||
|
||||
fn = Reflect.construct(MyAsync, [], MyAsync);
|
||||
assertEq(fn instanceof MyAsync, true);
|
||||
assertEq(fn instanceof AsyncFunction, true);
|
||||
assertEq(Object.getPrototypeOf(fn), MyAsync.prototype);
|
||||
|
||||
fn = Reflect.construct(MyAsync, [], AsyncFunction);
|
||||
assertEq(fn instanceof MyAsync, false);
|
||||
assertEq(fn instanceof AsyncFunction, true);
|
||||
assertEq(Object.getPrototypeOf(fn), AsyncFunction.prototype);
|
||||
|
||||
|
||||
// Set a different constructor as NewTarget.
|
||||
fn = Reflect.construct(MyAsync, [], Array);
|
||||
assertEq(fn instanceof MyAsync, false);
|
||||
assertEq(fn instanceof AsyncFunction, false);
|
||||
assertEq(Object.getPrototypeOf(fn), Array.prototype);
|
||||
|
||||
fn = Reflect.construct(AsyncFunction, [], Array);
|
||||
assertEq(fn instanceof AsyncFunction, false);
|
||||
assertEq(Object.getPrototypeOf(fn), Array.prototype);
|
||||
|
||||
|
||||
// The prototype defaults to %AsyncFunctionPrototype% if null.
|
||||
function NewTargetNullPrototype() {}
|
||||
NewTargetNullPrototype.prototype = null;
|
||||
|
||||
fn = Reflect.construct(AsyncFunction, [], NewTargetNullPrototype);
|
||||
assertEq(fn instanceof AsyncFunction, true);
|
||||
assertEq(Object.getPrototypeOf(fn), AsyncFunction.prototype);
|
||||
|
||||
fn = Reflect.construct(MyAsync, [], NewTargetNullPrototype);
|
||||
assertEq(fn instanceof MyAsync, false);
|
||||
assertEq(fn instanceof AsyncFunction, true);
|
||||
assertEq(Object.getPrototypeOf(fn), AsyncFunction.prototype);
|
||||
|
||||
|
||||
// "prototype" property is retrieved exactly once.
|
||||
var trapLog = [], getLog = [];
|
||||
var ProxiedConstructor = new Proxy(AsyncFunction, new Proxy({
|
||||
get(target, propertyKey, receiver) {
|
||||
getLog.push(propertyKey);
|
||||
return Reflect.get(target, propertyKey, receiver);
|
||||
}
|
||||
}, {
|
||||
get(target, propertyKey, receiver) {
|
||||
trapLog.push(propertyKey);
|
||||
return Reflect.get(target, propertyKey, receiver);
|
||||
}
|
||||
}));
|
||||
|
||||
fn = Reflect.construct(AsyncFunction, [], ProxiedConstructor);
|
||||
assertEqArray(trapLog, ["get"]);
|
||||
assertEqArray(getLog, ["prototype"]);
|
||||
assertEq(fn instanceof AsyncFunction, true);
|
||||
assertEq(Object.getPrototypeOf(fn), AsyncFunction.prototype);
|
||||
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
||||
31
js/src/tests/ecma_2017/AsyncFunctions/subclass.js
Normal file
31
js/src/tests/ecma_2017/AsyncFunctions/subclass.js
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// |reftest| skip-if(!xulRuntime.shell) -- needs drainJobQueue
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const AsyncFunction = async function(){}.constructor;
|
||||
|
||||
class MyAsync extends AsyncFunction {}
|
||||
|
||||
// MyGen inherits from %AsyncFunction%.
|
||||
assertEq(Object.getPrototypeOf(MyAsync), AsyncFunction);
|
||||
|
||||
// MyGen.prototype inherits from %AsyncFunctionPrototype%.
|
||||
assertEq(Object.getPrototypeOf(MyAsync.prototype), AsyncFunction.prototype);
|
||||
|
||||
var fn = new MyAsync("return await 'ok';");
|
||||
|
||||
// fn inherits from MyAsync.prototype.
|
||||
assertEq(Object.getPrototypeOf(fn), MyAsync.prototype);
|
||||
|
||||
// Ensure the new async function can be executed.
|
||||
var promise = fn();
|
||||
|
||||
// promise inherits from %Promise.prototype%.
|
||||
assertEq(Object.getPrototypeOf(promise), Promise.prototype);
|
||||
|
||||
// Computes the expected result.
|
||||
assertEventuallyEq(promise, "ok");
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
||||
79
js/src/tests/ecma_6/Generators/construct-newtarget.js
Normal file
79
js/src/tests/ecma_6/Generators/construct-newtarget.js
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const GeneratorFunction = function*(){}.constructor;
|
||||
|
||||
|
||||
// Test subclassing %GeneratorFunction% works correctly.
|
||||
class MyGenerator extends GeneratorFunction {}
|
||||
|
||||
var fn = new MyGenerator();
|
||||
assertEq(fn instanceof MyGenerator, true);
|
||||
assertEq(fn instanceof GeneratorFunction, true);
|
||||
assertEq(Object.getPrototypeOf(fn), MyGenerator.prototype);
|
||||
|
||||
fn = Reflect.construct(MyGenerator, []);
|
||||
assertEq(fn instanceof MyGenerator, true);
|
||||
assertEq(fn instanceof GeneratorFunction, true);
|
||||
assertEq(Object.getPrototypeOf(fn), MyGenerator.prototype);
|
||||
|
||||
fn = Reflect.construct(MyGenerator, [], MyGenerator);
|
||||
assertEq(fn instanceof MyGenerator, true);
|
||||
assertEq(fn instanceof GeneratorFunction, true);
|
||||
assertEq(Object.getPrototypeOf(fn), MyGenerator.prototype);
|
||||
|
||||
fn = Reflect.construct(MyGenerator, [], GeneratorFunction);
|
||||
assertEq(fn instanceof MyGenerator, false);
|
||||
assertEq(fn instanceof GeneratorFunction, true);
|
||||
assertEq(Object.getPrototypeOf(fn), GeneratorFunction.prototype);
|
||||
|
||||
|
||||
// Set a different constructor as NewTarget.
|
||||
fn = Reflect.construct(MyGenerator, [], Array);
|
||||
assertEq(fn instanceof MyGenerator, false);
|
||||
assertEq(fn instanceof GeneratorFunction, false);
|
||||
assertEq(Object.getPrototypeOf(fn), Array.prototype);
|
||||
|
||||
fn = Reflect.construct(GeneratorFunction, [], Array);
|
||||
assertEq(fn instanceof GeneratorFunction, false);
|
||||
assertEq(Object.getPrototypeOf(fn), Array.prototype);
|
||||
|
||||
|
||||
// The prototype defaults to %GeneratorFunctionPrototype% if null.
|
||||
function NewTargetNullPrototype() {}
|
||||
NewTargetNullPrototype.prototype = null;
|
||||
|
||||
fn = Reflect.construct(GeneratorFunction, [], NewTargetNullPrototype);
|
||||
assertEq(fn instanceof GeneratorFunction, true);
|
||||
assertEq(Object.getPrototypeOf(fn), GeneratorFunction.prototype);
|
||||
|
||||
fn = Reflect.construct(MyGenerator, [], NewTargetNullPrototype);
|
||||
assertEq(fn instanceof MyGenerator, false);
|
||||
assertEq(fn instanceof GeneratorFunction, true);
|
||||
assertEq(Object.getPrototypeOf(fn), GeneratorFunction.prototype);
|
||||
|
||||
|
||||
// "prototype" property is retrieved exactly once.
|
||||
var trapLog = [], getLog = [];
|
||||
var ProxiedConstructor = new Proxy(GeneratorFunction, new Proxy({
|
||||
get(target, propertyKey, receiver) {
|
||||
getLog.push(propertyKey);
|
||||
return Reflect.get(target, propertyKey, receiver);
|
||||
}
|
||||
}, {
|
||||
get(target, propertyKey, receiver) {
|
||||
trapLog.push(propertyKey);
|
||||
return Reflect.get(target, propertyKey, receiver);
|
||||
}
|
||||
}));
|
||||
|
||||
fn = Reflect.construct(GeneratorFunction, [], ProxiedConstructor);
|
||||
assertEqArray(trapLog, ["get"]);
|
||||
assertEqArray(getLog, ["prototype"]);
|
||||
assertEq(fn instanceof GeneratorFunction, true);
|
||||
assertEq(Object.getPrototypeOf(fn), GeneratorFunction.prototype);
|
||||
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
||||
33
js/src/tests/ecma_6/Generators/subclass.js
Normal file
33
js/src/tests/ecma_6/Generators/subclass.js
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const GeneratorFunction = function*(){}.constructor;
|
||||
|
||||
class MyGen extends GeneratorFunction {}
|
||||
|
||||
// MyGen inherits from %GeneratorFunction%.
|
||||
assertEq(Object.getPrototypeOf(MyGen), GeneratorFunction);
|
||||
|
||||
// MyGen.prototype inherits from %Generator%.
|
||||
assertEq(Object.getPrototypeOf(MyGen.prototype), GeneratorFunction.prototype);
|
||||
|
||||
var fn = new MyGen("yield* [1, 2, 3]");
|
||||
|
||||
// fn inherits from MyGen.prototype.
|
||||
assertEq(Object.getPrototypeOf(fn), MyGen.prototype);
|
||||
|
||||
// fn.prototype inherits from %GeneratorPrototype%.
|
||||
assertEq(Object.getPrototypeOf(fn.prototype), GeneratorFunction.prototype.prototype);
|
||||
|
||||
// Ensure the new generator function can be executed.
|
||||
var it = fn();
|
||||
|
||||
// it inherits from fn.prototype.
|
||||
assertEq(Object.getPrototypeOf(it), fn.prototype);
|
||||
|
||||
// Computes the expected result.
|
||||
assertEqArray([...it], [1, 2, 3]);
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
||||
|
|
@ -107,18 +107,15 @@ WrappedAsyncFunction(JSContext* cx, unsigned argc, Value* vp)
|
|||
// the async function's body, replacing `await` with `yield`. `wrapped` is a
|
||||
// function that is visible to the outside, and handles yielded values.
|
||||
JSObject*
|
||||
js::WrapAsyncFunction(JSContext* cx, HandleFunction unwrapped)
|
||||
js::WrapAsyncFunctionWithProto(JSContext* cx, HandleFunction unwrapped, HandleObject proto)
|
||||
{
|
||||
MOZ_ASSERT(unwrapped->isStarGenerator());
|
||||
MOZ_ASSERT(proto, "We need an explicit prototype to avoid the default"
|
||||
"%FunctionPrototype% fallback in NewFunctionWithProto().");
|
||||
|
||||
// Create a new function with AsyncFunctionPrototype, reusing the name and
|
||||
// the length of `unwrapped`.
|
||||
|
||||
// Step 1.
|
||||
RootedObject proto(cx, GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global()));
|
||||
if (!proto)
|
||||
return nullptr;
|
||||
|
||||
RootedAtom funName(cx, unwrapped->name());
|
||||
uint16_t length;
|
||||
if (!unwrapped->getLength(cx, &length))
|
||||
|
|
@ -141,6 +138,16 @@ js::WrapAsyncFunction(JSContext* cx, HandleFunction unwrapped)
|
|||
return wrapped;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
js::WrapAsyncFunction(JSContext* cx, HandleFunction unwrapped)
|
||||
{
|
||||
RootedObject proto(cx, GlobalObject::getOrCreateAsyncFunctionPrototype(cx, cx->global()));
|
||||
if (!proto)
|
||||
return nullptr;
|
||||
|
||||
return WrapAsyncFunctionWithProto(cx, unwrapped, proto);
|
||||
}
|
||||
|
||||
enum class ResumeKind {
|
||||
Normal,
|
||||
Throw
|
||||
|
|
|
|||
|
|
@ -21,6 +21,9 @@ GetUnwrappedAsyncFunction(JSFunction* wrapped);
|
|||
bool
|
||||
IsWrappedAsyncFunction(JSFunction* fun);
|
||||
|
||||
JSObject*
|
||||
WrapAsyncFunctionWithProto(JSContext* cx, HandleFunction unwrapped, HandleObject proto);
|
||||
|
||||
JSObject*
|
||||
WrapAsyncFunction(JSContext* cx, HandleFunction unwrapped);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue