Bug 1234702 - Part 3: Self-host default derived class constructor. (r=till)

This commit is contained in:
Eric Faust 2016-01-06 14:26:14 -08:00
Родитель d92fe405f6
Коммит b108999aa3
14 изменённых файлов: 135 добавлений и 43 удалений

Просмотреть файл

@ -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;

11
js/src/builtin/Classes.js Normal file
Просмотреть файл

@ -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, &REGS.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();