зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1234702 - Part 3: Self-host default derived class constructor. (r=till)
This commit is contained in:
Родитель
d92fe405f6
Коммит
b108999aa3
|
@ -6896,7 +6896,7 @@ ParseFunction(ModuleValidator& m, ParseNode** fnOut, unsigned* line, unsigned* c
|
|||
// This flows into FunctionBox, so must be tenured.
|
||||
RootedFunction fun(m.cx(),
|
||||
NewScriptedFunction(m.cx(), 0, JSFunction::INTERPRETED,
|
||||
name, gc::AllocKind::FUNCTION,
|
||||
name, /* proto = */ nullptr, gc::AllocKind::FUNCTION,
|
||||
TenuredObject));
|
||||
if (!fun)
|
||||
return false;
|
||||
|
@ -7831,7 +7831,7 @@ HandleDynamicLinkFailure(JSContext* cx, const CallArgs& args, AsmJSModule& modul
|
|||
return false;
|
||||
|
||||
RootedFunction fun(cx, NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL,
|
||||
name, gc::AllocKind::FUNCTION,
|
||||
name, /* proto = */ nullptr, gc::AllocKind::FUNCTION,
|
||||
TenuredObject));
|
||||
if (!fun)
|
||||
return false;
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
// Give a builtin constructor that we can use as the default. When we give
|
||||
// it to our newly made class, we will be sure to set it up with the correct name
|
||||
// and .prototype, so that everything works properly.
|
||||
|
||||
var DefaultDerivedClassConstructor =
|
||||
class extends null {
|
||||
constructor(...args) {
|
||||
super(...allowContentSpread(args));
|
||||
}
|
||||
};
|
||||
MakeDefaultConstructor(DefaultDerivedClassConstructor);
|
|
@ -4239,6 +4239,7 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
|
|||
}
|
||||
|
||||
fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, funAtom,
|
||||
/* proto = */ nullptr,
|
||||
gc::AllocKind::FUNCTION, TenuredObject,
|
||||
enclosingDynamicScope));
|
||||
if (!fun)
|
||||
|
|
|
@ -1082,7 +1082,7 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
|
|||
} else {
|
||||
MOZ_ASSERT(!fun->isExprBody());
|
||||
|
||||
if (fun->isNative() && fun->native() == js::DefaultDerivedClassConstructor) {
|
||||
if (fun->infallibleIsDefaultClassConstructor(cx) && fun->isDerivedClassConstructor()) {
|
||||
if (!out.append("(...args) {\n ") ||
|
||||
!out.append("super(...args);\n}"))
|
||||
{
|
||||
|
@ -1268,6 +1268,25 @@ js::fun_apply(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
JSFunction::infallibleIsDefaultClassConstructor(JSContext* cx) const
|
||||
{
|
||||
if (!isSelfHostedBuiltin())
|
||||
return false;
|
||||
|
||||
bool isDefault = false;
|
||||
if (isInterpretedLazy()) {
|
||||
JSAtom* name = &getExtendedSlot(LAZY_FUNCTION_NAME_SLOT).toString()->asAtom();
|
||||
isDefault = name == cx->names().DefaultDerivedClassConstructor;
|
||||
} else {
|
||||
isDefault = nonLazyScript()->isDefaultClassConstructor();
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(isDefault, isConstructor());
|
||||
MOZ_ASSERT_IF(isDefault, isClassConstructor());
|
||||
return isDefault;
|
||||
}
|
||||
|
||||
static const uint32_t JSSLOT_BOUND_FUNCTION_TARGET = 0;
|
||||
static const uint32_t JSSLOT_BOUND_FUNCTION_THIS = 1;
|
||||
static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS_COUNT = 2;
|
||||
|
@ -2008,6 +2027,7 @@ js::NewNativeConstructor(ExclusiveContext* cx, Native native, unsigned nargs, Ha
|
|||
JSFunction*
|
||||
js::NewScriptedFunction(ExclusiveContext* cx, unsigned nargs,
|
||||
JSFunction::Flags flags, HandleAtom atom,
|
||||
HandleObject proto /* = nullptr */,
|
||||
gc::AllocKind allocKind /* = AllocKind::FUNCTION */,
|
||||
NewObjectKind newKind /* = GenericObject */,
|
||||
HandleObject enclosingDynamicScopeArg /* = nullptr */)
|
||||
|
@ -2016,7 +2036,7 @@ js::NewScriptedFunction(ExclusiveContext* cx, unsigned nargs,
|
|||
if (!enclosingDynamicScope)
|
||||
enclosingDynamicScope = &cx->global()->lexicalScope();
|
||||
return NewFunctionWithProto(cx, nullptr, nargs, flags, enclosingDynamicScope,
|
||||
atom, nullptr, allocKind, newKind);
|
||||
atom, proto, allocKind, newKind);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -2313,6 +2333,7 @@ js::DefineFunction(JSContext* cx, HandleObject obj, HandleId id, Native native,
|
|||
if (!native)
|
||||
fun = NewScriptedFunction(cx, nargs,
|
||||
JSFunction::INTERPRETED_LAZY, atom,
|
||||
/* proto = */ nullptr,
|
||||
allocKind, GenericObject, obj);
|
||||
else if (flags & JSFUN_CONSTRUCTOR)
|
||||
fun = NewNativeConstructor(cx, native, nargs, atom, allocKind);
|
||||
|
|
|
@ -192,6 +192,8 @@ class JSFunction : public js::NativeObject
|
|||
bool hasScript() const { return flags() & INTERPRETED; }
|
||||
bool isBeingParsed() const { return flags() & BEING_PARSED; }
|
||||
|
||||
bool infallibleIsDefaultClassConstructor(JSContext* cx) const;
|
||||
|
||||
// Arrow functions store their lexical new.target in the first extended slot.
|
||||
bool isArrow() const { return kind() == Arrow; }
|
||||
// Every class-constructor is also a method.
|
||||
|
@ -255,6 +257,13 @@ class JSFunction : public js::NativeObject
|
|||
flags_ |= CONSTRUCTOR;
|
||||
}
|
||||
|
||||
void setIsClassConstructor() {
|
||||
MOZ_ASSERT(!isClassConstructor());
|
||||
MOZ_ASSERT(isConstructor());
|
||||
|
||||
setKind(ClassConstructor);
|
||||
}
|
||||
|
||||
// Can be called multiple times by the parser.
|
||||
void setArgCount(uint16_t nargs) {
|
||||
this->nargs_ = nargs;
|
||||
|
@ -643,7 +652,8 @@ NewNativeConstructor(ExclusiveContext* cx, JSNative native, unsigned nargs, Hand
|
|||
// the global.
|
||||
extern JSFunction*
|
||||
NewScriptedFunction(ExclusiveContext* cx, unsigned nargs, JSFunction::Flags flags,
|
||||
HandleAtom atom, gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
|
||||
HandleAtom atom, HandleObject proto = nullptr,
|
||||
gc::AllocKind allocKind = gc::AllocKind::FUNCTION,
|
||||
NewObjectKind newKind = GenericObject,
|
||||
HandleObject enclosingDynamicScope = nullptr);
|
||||
|
||||
|
|
|
@ -623,6 +623,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
|
|||
HasInnerFunctions,
|
||||
NeedsHomeObject,
|
||||
IsDerivedClassConstructor,
|
||||
IsDefaultClassConstructor,
|
||||
};
|
||||
|
||||
uint32_t length, lineno, column, nslots;
|
||||
|
@ -768,6 +769,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
|
|||
scriptBits |= (1 << NeedsHomeObject);
|
||||
if (script->isDerivedClassConstructor())
|
||||
scriptBits |= (1 << IsDerivedClassConstructor);
|
||||
if (script->isDefaultClassConstructor())
|
||||
scriptBits |= (1 << IsDefaultClassConstructor);
|
||||
}
|
||||
|
||||
if (!xdr->codeUint32(&prologueLength))
|
||||
|
@ -912,6 +915,8 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
|
|||
script->needsHomeObject_ = true;
|
||||
if (scriptBits & (1 << IsDerivedClassConstructor))
|
||||
script->isDerivedClassConstructor_ = true;
|
||||
if (scriptBits & (1 << IsDefaultClassConstructor))
|
||||
script->isDefaultClassConstructor_ = true;
|
||||
|
||||
if (scriptBits & (1 << IsLegacyGenerator)) {
|
||||
MOZ_ASSERT(!(scriptBits & (1 << IsStarGenerator)));
|
||||
|
@ -3584,6 +3589,7 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
|
|||
dst->setGeneratorKind(src->generatorKind());
|
||||
dst->isDerivedClassConstructor_ = src->isDerivedClassConstructor();
|
||||
dst->needsHomeObject_ = src->needsHomeObject();
|
||||
dst->isDefaultClassConstructor_ = src->isDefaultClassConstructor();
|
||||
|
||||
if (nconsts != 0) {
|
||||
HeapValue* vector = Rebase<HeapValue>(dst, src, src->consts()->vector);
|
||||
|
|
|
@ -1188,6 +1188,7 @@ class JSScript : public js::gc::TenuredCell
|
|||
bool needsHomeObject_:1;
|
||||
|
||||
bool isDerivedClassConstructor_:1;
|
||||
bool isDefaultClassConstructor_:1;
|
||||
|
||||
// Add padding so JSScript is gc::Cell aligned. Make padding protected
|
||||
// instead of private to suppress -Wunused-private-field compiler warnings.
|
||||
|
@ -1419,6 +1420,9 @@ class JSScript : public js::gc::TenuredCell
|
|||
bool failedLexicalCheck() const {
|
||||
return failedLexicalCheck_;
|
||||
}
|
||||
bool isDefaultClassConstructor() const {
|
||||
return isDefaultClassConstructor_;
|
||||
}
|
||||
|
||||
void setFailedBoundsCheck() { failedBoundsCheck_ = true; }
|
||||
void setFailedShapeGuard() { failedShapeGuard_ = true; }
|
||||
|
@ -1427,6 +1431,7 @@ class JSScript : public js::gc::TenuredCell
|
|||
void setUninlineable() { uninlineable_ = true; }
|
||||
void setInvalidatedIdempotentCache() { invalidatedIdempotentCache_ = true; }
|
||||
void setFailedLexicalCheck() { failedLexicalCheck_ = true; }
|
||||
void setIsDefaultClassConstructor() { isDefaultClassConstructor_ = true; }
|
||||
|
||||
bool hasScriptCounts() const { return hasScriptCounts_; }
|
||||
|
||||
|
|
|
@ -691,6 +691,7 @@ selfhosted.inputs = [
|
|||
'builtin/SelfHostingDefines.h',
|
||||
'builtin/Utilities.js',
|
||||
'builtin/Array.js',
|
||||
'builtin/Classes.js',
|
||||
'builtin/Date.js',
|
||||
'builtin/Error.js',
|
||||
'builtin/Generator.js',
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/* Make sure that the default derived class constructor has the required spread semantics.
|
||||
*
|
||||
* Test credit André Bargull
|
||||
*/
|
||||
|
||||
Array.prototype[Symbol.iterator] = function*() { yield 1; yield 2; };
|
||||
|
||||
class Base {
|
||||
constructor(a, b) {
|
||||
assertEq(a, 1);
|
||||
assertEq(b, 2);
|
||||
}
|
||||
};
|
||||
class Derived extends Base {};
|
||||
|
||||
new Derived();
|
||||
|
||||
if (typeof reportCompare === 'function')
|
||||
reportCompare(0,0,"OK");
|
|
@ -66,6 +66,7 @@
|
|||
macro(decodeURI, decodeURI, "decodeURI") \
|
||||
macro(decodeURIComponent, decodeURIComponent, "decodeURIComponent") \
|
||||
macro(default_, default_, "default") \
|
||||
macro(DefaultDerivedClassConstructor, DefaultDerivedClassConstructor, "DefaultDerivedClassConstructor") \
|
||||
macro(defineProperty, defineProperty, "defineProperty") \
|
||||
macro(defineGetter, defineGetter, "__defineGetter__") \
|
||||
macro(defineSetter, defineSetter, "__defineSetter__") \
|
||||
|
|
|
@ -687,8 +687,12 @@ GlobalObject::getSelfHostedFunction(JSContext* cx, Handle<GlobalObject*> global,
|
|||
}
|
||||
|
||||
RootedFunction fun(cx);
|
||||
if (!cx->runtime()->createLazySelfHostedFunctionClone(cx, selfHostedName, name, nargs, &fun))
|
||||
if (!cx->runtime()->createLazySelfHostedFunctionClone(cx, selfHostedName, name, nargs,
|
||||
/* proto = */ nullptr,
|
||||
SingletonObject, &fun))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
funVal.setObject(*fun);
|
||||
|
||||
return GlobalObject::addIntrinsicValue(cx, global, selfHostedName, funVal);
|
||||
|
|
|
@ -291,14 +291,32 @@ SetPropertyOperation(JSContext* cx, JSOp op, HandleValue lval, HandleId id, Hand
|
|||
}
|
||||
|
||||
static JSFunction*
|
||||
MakeDefaultConstructor(JSContext* cx, JSOp op, JSAtom* atom, HandleObject proto)
|
||||
MakeDefaultConstructor(JSContext* cx, JSOp op, JSAtom* atom)
|
||||
{
|
||||
bool derived = op == JSOP_DERIVEDCONSTRUCTOR;
|
||||
MOZ_ASSERT(derived == !!proto);
|
||||
|
||||
RootedAtom name(cx, atom == cx->names().empty ? nullptr : atom);
|
||||
JSNative native = derived ? DefaultDerivedClassConstructor : DefaultClassConstructor;
|
||||
return NewFunctionWithProto(cx, native, 0, JSFunction::NATIVE_CLASS_CTOR, nullptr, name, proto);
|
||||
JSNative native = DefaultClassConstructor;
|
||||
return NewFunctionWithProto(cx, native, 0, JSFunction::NATIVE_CLASS_CTOR, nullptr, name, nullptr);
|
||||
}
|
||||
|
||||
static JSFunction*
|
||||
MakeDerivedDefaultConstructor(JSContext* cx, JSAtom* atom, HandleObject proto)
|
||||
{
|
||||
RootedPropertyName selfHostedName(cx, cx->names().DefaultDerivedClassConstructor);
|
||||
RootedAtom name(cx, atom == cx->names().empty ? nullptr : atom);
|
||||
|
||||
RootedFunction ctor(cx);
|
||||
if (!cx->runtime()->createLazySelfHostedFunctionClone(cx, selfHostedName, name, /* nargs = */ 1,
|
||||
proto, TenuredObject, &ctor))
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ctor->setIsConstructor();
|
||||
ctor->setIsClassConstructor();
|
||||
|
||||
MOZ_ASSERT(ctor->infallibleIsDefaultClassConstructor(cx));
|
||||
|
||||
return ctor;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -3884,8 +3902,7 @@ CASE(JSOP_DERIVEDCONSTRUCTOR)
|
|||
MOZ_ASSERT(REGS.sp[-1].isObject());
|
||||
ReservedRooted<JSObject*> proto(&rootObject0, ®S.sp[-1].toObject());
|
||||
|
||||
JSFunction* constructor = MakeDefaultConstructor(cx, JSOp(*REGS.pc), script->getAtom(REGS.pc),
|
||||
proto);
|
||||
JSFunction* constructor = MakeDerivedDefaultConstructor(cx, script->getAtom(REGS.pc), proto);
|
||||
if (!constructor)
|
||||
goto error;
|
||||
|
||||
|
@ -3895,8 +3912,7 @@ END_CASE(JSOP_DERIVEDCONSTRUCTOR)
|
|||
|
||||
CASE(JSOP_CLASSCONSTRUCTOR)
|
||||
{
|
||||
JSFunction* constructor = MakeDefaultConstructor(cx, JSOp(*REGS.pc), script->getAtom(REGS.pc),
|
||||
nullptr);
|
||||
JSFunction* constructor = MakeDefaultConstructor(cx, JSOp(*REGS.pc), script->getAtom(REGS.pc));
|
||||
if (!constructor)
|
||||
goto error;
|
||||
PUSH_OBJECT(*constructor);
|
||||
|
@ -4815,32 +4831,6 @@ js::DefaultClassConstructor(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
js::DefaultDerivedClassConstructor(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
if (!args.isConstructing()) {
|
||||
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_CALL_CLASS_CONSTRUCTOR);
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedObject fun(cx, &args.callee());
|
||||
RootedObject superFun(cx);
|
||||
if (!GetPrototype(cx, fun, &superFun))
|
||||
return false;
|
||||
|
||||
RootedValue fval(cx, ObjectOrNullValue(superFun));
|
||||
if (!IsConstructor(fval)) {
|
||||
ReportValueError(cx, JSMSG_NOT_CONSTRUCTOR, JSDVG_IGNORE_STACK, fval, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
ConstructArgs constArgs(cx);
|
||||
if (!FillArgumentsFromArraylike(cx, constArgs, args))
|
||||
return false;
|
||||
return Construct(cx, fval, constArgs, args.newTarget(), args.rval());
|
||||
}
|
||||
|
||||
void
|
||||
js::ReportRuntimeRedeclaration(JSContext* cx, HandlePropertyName name,
|
||||
frontend::Definition::Kind declKind)
|
||||
|
|
|
@ -989,6 +989,8 @@ struct JSRuntime : public JS::shadow::Runtime,
|
|||
bool isSelfHostingZone(const JS::Zone* zone) const;
|
||||
bool createLazySelfHostedFunctionClone(JSContext* cx, js::HandlePropertyName selfHostedName,
|
||||
js::HandleAtom name, unsigned nargs,
|
||||
js::HandleObject proto,
|
||||
js::NewObjectKind newKind,
|
||||
js::MutableHandleFunction fun);
|
||||
bool cloneSelfHostedFunctionScript(JSContext* cx, js::Handle<js::PropertyName*> name,
|
||||
js::Handle<JSFunction*> targetFun);
|
||||
|
|
|
@ -292,6 +292,21 @@ intrinsic_MakeConstructible(JSContext* cx, unsigned argc, Value* vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
intrinsic_MakeDefaultConstructor(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 1);
|
||||
MOZ_ASSERT(args[0].toObject().as<JSFunction>().isSelfHostedBuiltin());
|
||||
|
||||
RootedFunction ctor(cx, &args[0].toObject().as<JSFunction>());
|
||||
|
||||
ctor->nonLazyScript()->setIsDefaultClassConstructor();
|
||||
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Used to decompile values in the nearest non-builtin stack frame, falling
|
||||
* back to decompiling in the current frame. Helpful for printing higher-order
|
||||
|
@ -1503,6 +1518,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
|||
JS_FN("ThrowSyntaxError", intrinsic_ThrowSyntaxError, 4,0),
|
||||
JS_FN("AssertionFailed", intrinsic_AssertionFailed, 1,0),
|
||||
JS_FN("MakeConstructible", intrinsic_MakeConstructible, 2,0),
|
||||
JS_FN("MakeDefaultConstructor", intrinsic_MakeDefaultConstructor, 2,0),
|
||||
JS_FN("_ConstructorForTypedArray", intrinsic_ConstructorForTypedArray, 1,0),
|
||||
JS_FN("DecompileArg", intrinsic_DecompileArg, 2,0),
|
||||
JS_FN("RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0,0),
|
||||
|
@ -1996,6 +2012,7 @@ CloneObject(JSContext* cx, HandleNativeObject selfHostedObject)
|
|||
if (selfHostedObject->is<JSFunction>()) {
|
||||
RootedFunction selfHostedFunction(cx, &selfHostedObject->as<JSFunction>());
|
||||
bool hasName = selfHostedFunction->atom() != nullptr;
|
||||
|
||||
// Arrow functions use the first extended slot for their lexical |this| value.
|
||||
MOZ_ASSERT(!selfHostedFunction->isArrow());
|
||||
js::gc::AllocKind kind = hasName
|
||||
|
@ -2041,6 +2058,7 @@ CloneObject(JSContext* cx, HandleNativeObject selfHostedObject)
|
|||
}
|
||||
if (!clone)
|
||||
return nullptr;
|
||||
|
||||
if (!CloneProperties(cx, selfHostedObject, clone))
|
||||
return nullptr;
|
||||
return clone;
|
||||
|
@ -2081,8 +2099,11 @@ CloneValue(JSContext* cx, HandleValue selfHostedValue, MutableHandleValue vp)
|
|||
bool
|
||||
JSRuntime::createLazySelfHostedFunctionClone(JSContext* cx, HandlePropertyName selfHostedName,
|
||||
HandleAtom name, unsigned nargs,
|
||||
HandleObject proto, NewObjectKind newKind,
|
||||
MutableHandleFunction fun)
|
||||
{
|
||||
MOZ_ASSERT(newKind != GenericObject);
|
||||
|
||||
RootedAtom funName(cx, name);
|
||||
JSFunction* selfHostedFun = getUnclonedSelfHostedFunction(cx, selfHostedName);
|
||||
if (!selfHostedFun)
|
||||
|
@ -2094,7 +2115,7 @@ JSRuntime::createLazySelfHostedFunctionClone(JSContext* cx, HandlePropertyName s
|
|||
}
|
||||
|
||||
fun.set(NewScriptedFunction(cx, nargs, JSFunction::INTERPRETED_LAZY,
|
||||
funName, gc::AllocKind::FUNCTION_EXTENDED, SingletonObject));
|
||||
funName, proto, gc::AllocKind::FUNCTION_EXTENDED, newKind));
|
||||
if (!fun)
|
||||
return false;
|
||||
fun->setIsSelfHostedBuiltin();
|
||||
|
|
Загрузка…
Ссылка в новой задаче