From 6d8dbba4624c8a453ba13ff009f011f2946422bb Mon Sep 17 00:00:00 2001 From: Lars Knoll Date: Sat, 30 Jun 2018 19:19:18 +0200 Subject: Add support for super calls Implement super call support for class constructor functions. Change-Id: I3c64276234689cf4f644b095e0fc8ca1c634ac53 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4bytecodehandler.cpp | 3 + src/qml/compiler/qv4codegen.cpp | 97 +++++++++++++++++-------- src/qml/compiler/qv4codegen_p.h | 6 ++ src/qml/compiler/qv4instr_moth.cpp | 3 + src/qml/compiler/qv4instr_moth_p.h | 2 + src/qml/jit/qv4baselinejit.cpp | 9 +++ src/qml/jit/qv4baselinejit_p.h | 1 + src/qml/jit/qv4jithelpers.cpp | 9 +++ src/qml/jit/qv4jithelpers_p.h | 1 + src/qml/jsruntime/qv4functionobject.cpp | 97 ++++++++++++++++++++++--- src/qml/jsruntime/qv4functionobject_p.h | 5 +- src/qml/jsruntime/qv4objectproto.cpp | 6 +- src/qml/jsruntime/qv4runtime.cpp | 11 +-- src/qml/jsruntime/qv4stackframe_p.h | 16 +++- src/qml/jsruntime/qv4vme_moth.cpp | 10 +++ tests/auto/qml/ecmascripttests/TestExpectations | 69 ++---------------- 16 files changed, 225 insertions(+), 120 deletions(-) diff --git a/src/qml/compiler/qv4bytecodehandler.cpp b/src/qml/compiler/qv4bytecodehandler.cpp index 3e683cc8bf..b96c04dc01 100644 --- a/src/qml/compiler/qv4bytecodehandler.cpp +++ b/src/qml/compiler/qv4bytecodehandler.cpp @@ -364,6 +364,9 @@ std::vector ByteCodeHandler::collectLabelsInBytecode(const char *code, uint COLLECTOR_BEGIN_INSTR(ConvertThisToObject) COLLECTOR_END_INSTR(ConvertThisToObject) + COLLECTOR_BEGIN_INSTR(LoadSuperConstructor) + COLLECTOR_END_INSTR(LoadSuperConstructor) + COLLECTOR_BEGIN_INSTR(ToObject) COLLECTOR_END_INSTR(ToObject) diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 40aac8f7bb..36f959b301 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -1108,6 +1108,8 @@ bool Codegen::visit(ArrayMemberExpression *ast) if (hasError) return false; base = base.storeOnStack(); + if (hasError) + return false; if (AST::StringLiteral *str = AST::cast(ast->expression)) { QString s = str->value.toString(); uint arrayIndex = QV4::String::toArrayIndex(s); @@ -1736,6 +1738,9 @@ bool Codegen::visit(CallExpression *ast) break; case Reference::Name: break; + case Reference::Super: + handleConstruct(base, ast->arguments); + return false; default: base = base.storeOnStack(); break; @@ -2015,12 +2020,12 @@ bool Codegen::visit(FalseLiteral *) return false; } -bool Codegen::visit(SuperLiteral *ast) +bool Codegen::visit(SuperLiteral *) { if (hasError) return false; - throwSyntaxError(ast->superToken, QLatin1String("Support for 'super' keyword not implemented")); + _expr.setResult(Reference::fromSuper(this)); return false; } @@ -2207,6 +2212,43 @@ bool Codegen::visit(NestedExpression *ast) return false; } +void Codegen::handleConstruct(const Reference &base, ArgumentList *arguments) +{ + Reference constructor; + if (base.isSuper()) { + Instruction::LoadSuperConstructor super; + bytecodeGenerator->addInstruction(super); + constructor = Reference::fromAccumulator(this).storeOnStack(); + } else { + constructor = base.storeOnStack(); + } + + auto calldata = pushArgs(arguments); + if (hasError) + return; + + if (base.isSuper()) { + Reference::fromStackSlot(this, CallData::Function).loadInAccumulator(); + } else { + constructor.loadInAccumulator(); + } + + if (calldata.hasSpread) { + Instruction::ConstructWithSpread create; + create.func = constructor.stackSlot(); + create.argc = calldata.argc; + create.argv = calldata.argv; + bytecodeGenerator->addInstruction(create); + } else { + Instruction::Construct create; + create.func = constructor.stackSlot(); + create.argc = calldata.argc; + create.argv = calldata.argv; + bytecodeGenerator->addInstruction(create); + } + _expr.setResult(Reference::fromAccumulator(this)); +} + bool Codegen::visit(NewExpression *ast) { if (hasError) @@ -2217,16 +2259,12 @@ bool Codegen::visit(NewExpression *ast) Reference base = expression(ast->expression); if (hasError) return false; + if (base.isSuper()) { + throwSyntaxError(ast->expression->firstSourceLocation(), QStringLiteral("Cannot use new with super.")); + return false; + } - base = base.storeOnStack(); - base.loadInAccumulator(); - - Instruction::Construct create; - create.func = base.stackSlot(); - create.argc = 0; - create.argv = 0; - bytecodeGenerator->addInstruction(create); - _expr.setResult(Reference::fromAccumulator(this)); + handleConstruct(base, nullptr); return false; } @@ -2240,28 +2278,12 @@ bool Codegen::visit(NewMemberExpression *ast) Reference base = expression(ast->base); if (hasError) return false; - base = base.storeOnStack(); - - auto calldata = pushArgs(ast->arguments); - if (hasError) + if (base.isSuper()) { + throwSyntaxError(ast->base->firstSourceLocation(), QStringLiteral("Cannot use new with super.")); return false; - - base.loadInAccumulator(); - - if (calldata.hasSpread) { - Instruction::ConstructWithSpread create; - create.func = base.stackSlot(); - create.argc = calldata.argc; - create.argv = calldata.argv; - bytecodeGenerator->addInstruction(create); - } else { - Instruction::Construct create; - create.func = base.stackSlot(); - create.argc = calldata.argc; - create.argv = calldata.argv; - bytecodeGenerator->addInstruction(create); } - _expr.setResult(Reference::fromAccumulator(this)); + + handleConstruct(base, ast->arguments); return false; } @@ -3684,6 +3706,8 @@ Codegen::Reference &Codegen::Reference::operator =(const Reference &other) case Invalid: case Accumulator: break; + case Super: + break; case StackSlot: theStackSlot = other.theStackSlot; break; @@ -3733,6 +3757,8 @@ bool Codegen::Reference::operator==(const Codegen::Reference &other) const case Invalid: case Accumulator: break; + case Super: + return true; case StackSlot: return theStackSlot == other.theStackSlot; case ScopedLocal: @@ -3776,6 +3802,9 @@ Codegen::Reference Codegen::Reference::asLValue() const case Invalid: case Accumulator: Q_UNREACHABLE(); + case Super: + codegen->throwSyntaxError(AST::SourceLocation(), QStringLiteral("Super lvalues not implemented.")); + return *this; case Member: if (!propertyBase.isStackSlot()) { Reference r = *this; @@ -3909,6 +3938,9 @@ void Codegen::Reference::storeAccumulator() const return; } switch (type) { + case Super: + codegen->throwSyntaxError(SourceLocation(), QStringLiteral("storing super properties not implemented.")); + return; case StackSlot: { Instruction::StoreReg store; store.reg = theStackSlot; @@ -3986,6 +4018,9 @@ void Codegen::Reference::loadInAccumulator() const switch (type) { case Accumulator: return; + case Super: + codegen->throwSyntaxError(AST::SourceLocation(), QStringLiteral("Super property access not implemented.")); + return; case Const: { QT_WARNING_PUSH QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // the loads below are empty structs. diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index cac8da4e71..814754aea2 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -179,6 +179,7 @@ public: enum Type { Invalid, Accumulator, + Super, StackSlot, ScopedLocal, Name, @@ -215,6 +216,7 @@ public: } bool isConstant() const { return type == Const; } bool isAccumulator() const { return type == Accumulator; } + bool isSuper() const { return type == Super; } bool isStackSlot() const { return type == StackSlot; } bool isRegister() const { return isStackSlot(); @@ -245,6 +247,9 @@ public: static Reference fromAccumulator(Codegen *cg) { return Reference(cg, Accumulator); } + static Reference fromSuper(Codegen *cg) { + return Reference(cg, Super); + } static Reference fromStackSlot(Codegen *cg, int tempIndex = -1, bool isLocal = false) { Reference r(cg, StackSlot); if (tempIndex == -1) @@ -704,6 +709,7 @@ protected: private: VolatileMemoryLocations scanVolatileMemoryLocations(AST::Node *ast) const; + void handleConstruct(const Reference &base, AST::ArgumentList *args); }; } diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp index 2d2f7bc27f..2ce06c9552 100644 --- a/src/qml/compiler/qv4instr_moth.cpp +++ b/src/qml/compiler/qv4instr_moth.cpp @@ -504,6 +504,9 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st MOTH_BEGIN_INSTR(ConvertThisToObject) MOTH_END_INSTR(ConvertThisToObject) + MOTH_BEGIN_INSTR(LoadSuperConstructor) + MOTH_END_INSTR(LoadSuperConstructor) + MOTH_BEGIN_INSTR(ToObject) MOTH_END_INSTR(ToObject) diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index 3bd60288c3..00ed76e6c2 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -142,6 +142,7 @@ QT_BEGIN_NAMESPACE #define INSTR_CreateUnmappedArgumentsObject(op) INSTRUCTION(op, CreateUnmappedArgumentsObject, 0) #define INSTR_CreateRestParameter(op) INSTRUCTION(op, CreateRestParameter, 1, argIndex) #define INSTR_ConvertThisToObject(op) INSTRUCTION(op, ConvertThisToObject, 0) +#define INSTR_LoadSuperConstructor(op) INSTRUCTION(op, LoadSuperConstructor, 0) #define INSTR_ToObject(op) INSTRUCTION(op, ToObject, 0) #define INSTR_Jump(op) INSTRUCTION(op, Jump, 1, offset) #define INSTR_JumpTrue(op) INSTRUCTION(op, JumpTrue, 1, offset) @@ -271,6 +272,7 @@ QT_BEGIN_NAMESPACE F(CreateUnmappedArgumentsObject) \ F(CreateRestParameter) \ F(ConvertThisToObject) \ + F(LoadSuperConstructor) \ F(ToObject) \ F(Jump) \ F(JumpTrue) \ diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp index 23df04f127..b52350a729 100644 --- a/src/qml/jit/qv4baselinejit.cpp +++ b/src/qml/jit/qv4baselinejit.cpp @@ -787,6 +787,15 @@ void BaselineJIT::generate_ConvertThisToObject() as->checkException(); } +void BaselineJIT::generate_LoadSuperConstructor() +{ + as->prepareCallWithArgCount(2); + as->passRegAsArg(CallData::Function, 1); + as->passEngineAsArg(0); + JIT_GENERATE_RUNTIME_CALL(Helpers::loadSuperConstructor, Assembler::ResultInAccumulator); + as->checkException(); +} + void BaselineJIT::generate_ToObject() { STORE_ACC(); diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h index 9fa4aa2cda..26da3d5da3 100644 --- a/src/qml/jit/qv4baselinejit_p.h +++ b/src/qml/jit/qv4baselinejit_p.h @@ -159,6 +159,7 @@ public: void generate_CreateUnmappedArgumentsObject() override; void generate_CreateRestParameter(int argIndex) override; void generate_ConvertThisToObject() override; + void generate_LoadSuperConstructor() override; void generate_ToObject() override; void generate_Jump(int offset) override; void generate_JumpTrue(int offset) override; diff --git a/src/qml/jit/qv4jithelpers.cpp b/src/qml/jit/qv4jithelpers.cpp index f644d8c782..23e3095a85 100644 --- a/src/qml/jit/qv4jithelpers.cpp +++ b/src/qml/jit/qv4jithelpers.cpp @@ -69,6 +69,15 @@ ReturnedValue loadGlobalLookup(ExecutionEngine *engine, Function *f, int index) return l->globalGetter(l, engine); } +ReturnedValue loadSuperConstructor(ExecutionEngine *engine, const Value *t) +{ + if (!t->isObject()) { + engine->throwTypeError(); + return Encode::undefined(); + } + return static_cast(t)->getPrototypeOf()->asReturnedValue(); +} + ReturnedValue toObject(ExecutionEngine *engine, const Value &obj) { if (obj.isObject()) diff --git a/src/qml/jit/qv4jithelpers_p.h b/src/qml/jit/qv4jithelpers_p.h index bb10d5722b..e0dfdc47d9 100644 --- a/src/qml/jit/qv4jithelpers_p.h +++ b/src/qml/jit/qv4jithelpers_p.h @@ -66,6 +66,7 @@ namespace Helpers { void convertThisToObject(ExecutionEngine *engine, Value *t); ReturnedValue loadGlobalLookup(ExecutionEngine *engine, Function *f, int index); +ReturnedValue loadSuperConstructor(ExecutionEngine *engine, const Value *t); ReturnedValue toObject(ExecutionEngine *engine, const Value &obj); ReturnedValue exp(const Value &base, const Value &exp); ReturnedValue getLookup(ExecutionEngine *engine, Function *f, int index, const Value &base); diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index e88b81bd29..2aca7c2849 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -184,9 +184,16 @@ Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *sco return scope->engine()->memoryManager->allocate(scope, function); } -Heap::FunctionObject *FunctionObject::createConstructorFunction(ExecutionContext *scope, Function *function) +Heap::FunctionObject *FunctionObject::createConstructorFunction(ExecutionContext *scope, Function *function, bool isDerivedConstructor) { - return scope->engine()->memoryManager->allocate(scope, function); + if (!function) { + Heap::DefaultClassConstructorFunction *c = scope->engine()->memoryManager->allocate(scope); + c->isDerivedConstructor = isDerivedConstructor; + return c; + } + Heap::ConstructorFunction *c = scope->engine()->memoryManager->allocate(scope, function); + c->isDerivedConstructor = isDerivedConstructor; + return c; } Heap::FunctionObject *FunctionObject::createMemberFunction(ExecutionContext *scope, Function *function) @@ -455,9 +462,20 @@ ReturnedValue ScriptFunction::virtualCallAsConstructor(const FunctionObject *fo, { ExecutionEngine *v4 = fo->engine(); const ScriptFunction *f = static_cast(fo); + Q_ASSERT(newTarget->isFunctionObject()); + const FunctionObject *nt = static_cast(newTarget); Scope scope(v4); - ScopedValue thisObject(scope, v4->memoryManager->allocObject(f->classForConstructor())); + Scoped ic(scope); + if (nt->d() == f->d()) { + ic = f->classForConstructor(); + } else { + const Object *o = nt->d()->protoProperty(); + ic = scope.engine->internalClasses(EngineBase::Class_Object); + if (o) + ic = ic->changePrototype(o->d()); + } + ScopedValue thisObject(scope, v4->memoryManager->allocObject(ic)); CppStackFrame frame; frame.init(v4, f->function(), argv, argc); @@ -535,6 +553,36 @@ Heap::InternalClass *ScriptFunction::classForConstructor() const DEFINE_OBJECT_VTABLE(ConstructorFunction); +ReturnedValue ConstructorFunction::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) +{ + const ConstructorFunction *c = static_cast(f); + if (!c->d()->isDerivedConstructor) + return ScriptFunction::virtualCallAsConstructor(f, argv, argc, newTarget); + + ExecutionEngine *v4 = f->engine(); + + CppStackFrame frame; + frame.init(v4, f->function(), argv, argc); + frame.setupJSFrame(v4->jsStackTop, *f, f->scope(), + Primitive::undefinedValue(), + newTarget ? *newTarget : Primitive::undefinedValue()); + + frame.push(); + v4->jsStackTop += frame.requiredJSStackFrameSize(); + + ReturnedValue result = Moth::VME::exec(&frame, v4); + + frame.pop(); + + if (Q_UNLIKELY(v4->hasException)) + return Encode::undefined(); + else if (Value::fromReturnedValue(result).isObject()) + return result; + else if (!Value::fromReturnedValue(result).isUndefined()) + return v4->throwTypeError(); + return frame.jsFrame->thisObject.asReturnedValue(); +} + ReturnedValue ConstructorFunction::virtualCall(const FunctionObject *f, const Value *, const Value *, int) { return f->engine()->throwTypeError(QStringLiteral("Cannot call a class constructor without |new|")); @@ -549,13 +597,44 @@ ReturnedValue MemberFunction::virtualCallAsConstructor(const FunctionObject *f, DEFINE_OBJECT_VTABLE(DefaultClassConstructorFunction); -ReturnedValue DefaultClassConstructorFunction::virtualCallAsConstructor(const FunctionObject *f, const Value *, int, const Value *) +ReturnedValue DefaultClassConstructorFunction::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) { - Scope scope(f); - ScopedObject proto(scope, f->get(scope.engine->id_prototype())); - ScopedObject c(scope, scope.engine->newObject()); - c->setPrototypeUnchecked(proto); - return c->asReturnedValue(); + const DefaultClassConstructorFunction *c = static_cast(f); + ExecutionEngine *v4 = f->engine(); + + Scope scope(v4); + + if (!c->d()->isDerivedConstructor) { + ScopedObject proto(scope, static_cast(newTarget) ->get(scope.engine->id_prototype())); + ScopedObject c(scope, scope.engine->newObject()); + c->setPrototypeUnchecked(proto); + return c->asReturnedValue(); + } + + ScopedFunctionObject super(scope, f->getPrototypeOf()); + Q_ASSERT(super->isFunctionObject()); + + CppStackFrame frame; + frame.init(v4, nullptr, argv, argc); + frame.setupJSFrame(v4->jsStackTop, *f, f->scope(), + Primitive::undefinedValue(), + newTarget ? *newTarget : Primitive::undefinedValue(), argc, argc); + + frame.push(); + v4->jsStackTop += frame.requiredJSStackFrameSize(argc); + + // Do a super call + ReturnedValue result = super->callAsConstructor(argv, argc, newTarget); + + frame.pop(); + + if (Q_UNLIKELY(v4->hasException)) + return Encode::undefined(); + else if (Value::fromReturnedValue(result).isObject()) + return result; + else if (!Value::fromReturnedValue(result).isUndefined()) + return v4->throwTypeError(); + return frame.jsFrame->thisObject.asReturnedValue(); } ReturnedValue DefaultClassConstructorFunction::virtualCall(const FunctionObject *f, const Value *, const Value *, int) diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index d2af7fa432..1acb1df0b4 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -122,6 +122,7 @@ DECLARE_HEAP_OBJECT(ScriptFunction, FunctionObject) { struct ConstructorFunction : ScriptFunction { + bool isDerivedConstructor; }; struct MemberFunction : ScriptFunction @@ -130,6 +131,7 @@ struct MemberFunction : ScriptFunction struct DefaultClassConstructorFunction : FunctionObject { + bool isDerivedConstructor; }; #define BoundFunctionMembers(class, Member) \ @@ -180,7 +182,7 @@ struct Q_QML_EXPORT FunctionObject: Object { static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function); - static Heap::FunctionObject *createConstructorFunction(ExecutionContext *scope, Function *function); + static Heap::FunctionObject *createConstructorFunction(ExecutionContext *scope, Function *function, bool isDerivedConstructor); static Heap::FunctionObject *createMemberFunction(ExecutionContext *scope, Function *function); static Heap::FunctionObject *createBuiltinFunction(ExecutionEngine *engine, StringOrSymbol *nameOrSymbol, VTable::Call code, int argumentCount); @@ -252,6 +254,7 @@ struct ScriptFunction : FunctionObject { struct ConstructorFunction : ScriptFunction { V4_OBJECT2(ConstructorFunction, ScriptFunction) V4_INTERNALCLASS(ConstructorFunction) + static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *); static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); }; diff --git a/src/qml/jsruntime/qv4objectproto.cpp b/src/qml/jsruntime/qv4objectproto.cpp index 2c8227887f..65e9b836d1 100644 --- a/src/qml/jsruntime/qv4objectproto.cpp +++ b/src/qml/jsruntime/qv4objectproto.cpp @@ -63,14 +63,14 @@ void Heap::ObjectCtor::init(QV4::ExecutionContext *scope) Heap::FunctionObject::init(scope, QStringLiteral("Object")); } -ReturnedValue ObjectCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *) +ReturnedValue ObjectCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) { ExecutionEngine *v4 = f->engine(); - const ObjectCtor *ctor = static_cast(f); + const ObjectCtor *nt = static_cast(newTarget); if (!argc || argv[0].isUndefined() || argv[0].isNull()) { Scope scope(v4); ScopedObject obj(scope, scope.engine->newObject()); - ScopedObject proto(scope, ctor->get(scope.engine->id_prototype())); + ScopedObject proto(scope, nt->get(scope.engine->id_prototype())); if (!!proto) obj->setPrototypeOf(proto); return obj.asReturnedValue(); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 0fd3787730..eeb66509e3 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1306,7 +1306,6 @@ ReturnedValue Runtime::method_construct(ExecutionEngine *engine, const Value &fu { if (!function.isFunctionObject()) return engine->throwTypeError(); - Q_ASSERT(function.sameValue(newTarget)); return static_cast(function).callAsConstructor(argv, argc, &newTarget); } @@ -1316,7 +1315,6 @@ ReturnedValue Runtime::method_constructWithSpread(ExecutionEngine *engine, const Q_UNIMPLEMENTED(); if (!function.isFunctionObject()) return engine->throwTypeError(); - Q_ASSERT(function.sameValue(newTarget)); Scope scope(engine); CallArgs arguments = createSpreadArguments(scope, argv, argc); @@ -1508,13 +1506,8 @@ ReturnedValue Runtime::method_createClass(ExecutionEngine *engine, int classInde ExecutionContext *current = static_cast(&engine->currentStackFrame->jsFrame->context); ScopedFunctionObject constructor(scope); - if (cls->constructorFunction != UINT_MAX) { - QV4::Function *f = unit->runtimeFunctions[cls->constructorFunction]; - Q_ASSERT(f); - constructor = FunctionObject::createConstructorFunction(current, f)->asReturnedValue(); - } else { - constructor = engine->memoryManager->allocate(); - } + QV4::Function *f = cls->constructorFunction != UINT_MAX ? unit->runtimeFunctions[cls->constructorFunction] : nullptr; + constructor = FunctionObject::createConstructorFunction(current, f, !superClass.isEmpty())->asReturnedValue(); constructor->setPrototypeUnchecked(constructorParent); constructor->defineDefaultProperty(engine->id_prototype(), proto); proto->defineDefaultProperty(engine->id_constructor(), constructor); diff --git a/src/qml/jsruntime/qv4stackframe_p.h b/src/qml/jsruntime/qv4stackframe_p.h index 68301eb097..4966a5637d 100644 --- a/src/qml/jsruntime/qv4stackframe_p.h +++ b/src/qml/jsruntime/qv4stackframe_p.h @@ -129,6 +129,9 @@ struct Q_QML_EXPORT CppStackFrame { } #ifndef V4_BOOTSTRAP + static uint requiredJSStackFrameSize(uint nRegisters) { + return CallData::HeaderSize() + nRegisters; + } static uint requiredJSStackFrameSize(Function *v4Function) { return CallData::HeaderSize() + v4Function->compiledFunction->nRegisters; } @@ -136,7 +139,12 @@ struct Q_QML_EXPORT CppStackFrame { return requiredJSStackFrameSize(v4Function); } void setupJSFrame(Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope, - const Value &thisObject, const Value &newTarget = Primitive::undefinedValue()) + const Value &thisObject, const Value &newTarget = Primitive::undefinedValue()) { + setupJSFrame(stackSpace, function, scope, thisObject, newTarget, + v4Function->nFormals, v4Function->compiledFunction->nRegisters); + } + void setupJSFrame(Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope, + const Value &thisObject, const Value &newTarget, uint nFormals, uint nRegisters) { jsFrame = reinterpret_cast(stackSpace); jsFrame->function = function; @@ -146,12 +154,12 @@ struct Q_QML_EXPORT CppStackFrame { jsFrame->newTarget = newTarget; uint argc = uint(originalArgumentsCount); - if (argc > v4Function->nFormals) - argc = v4Function->nFormals; + if (argc > nFormals) + argc = nFormals; jsFrame->setArgc(argc); memcpy(jsFrame->args, originalArguments, argc*sizeof(Value)); - const Value *end = jsFrame->args + v4Function->compiledFunction->nRegisters; + const Value *end = jsFrame->args + nRegisters; for (Value *v = jsFrame->args + argc; v < end; ++v) *v = Encode::undefined(); } diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 4f0f9f27ec..39eaa3a25c 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -936,6 +936,16 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, } MOTH_END_INSTR(ConvertThisToObject) + MOTH_BEGIN_INSTR(LoadSuperConstructor) + const Value *f = &stack[CallData::Function]; + if (!f->isFunctionObject()) { + engine->throwTypeError(); + } else { + acc = static_cast(f)->getPrototypeOf()->asReturnedValue(); + } + CHECK_EXCEPTION; + MOTH_END_INSTR(LoadSuperConstructor) + MOTH_BEGIN_INSTR(ToObject) acc = ACC.toObject(engine)->asReturnedValue(); CHECK_EXCEPTION; diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations index cb35aaa3c7..ba69e76a1a 100644 --- a/tests/auto/qml/ecmascripttests/TestExpectations +++ b/tests/auto/qml/ecmascripttests/TestExpectations @@ -130,8 +130,6 @@ built-ins/Array/prototype/unshift/clamps-to-integer-limit.js fails built-ins/Array/prototype/unshift/length-near-integer-limit.js fails built-ins/Array/prototype/unshift/throws-if-integer-limit-exceeded.js fails built-ins/ArrayBuffer/data-allocation-after-object-creation.js fails -built-ins/ArrayBuffer/isView/arg-is-dataview-subclass-instance.js fails -built-ins/ArrayBuffer/isView/arg-is-typedarray-subclass-instance.js fails built-ins/ArrayBuffer/proto-from-ctor-realm.js fails built-ins/ArrayBuffer/prototype-from-newtarget.js fails built-ins/ArrayBuffer/prototype/byteLength/detached-buffer.js fails @@ -407,7 +405,6 @@ built-ins/Function/internals/Call/class-ctor-realm.js fails built-ins/Function/internals/Construct/base-ctor-revoked-proxy-realm.js fails built-ins/Function/internals/Construct/base-ctor-revoked-proxy.js fails built-ins/Function/internals/Construct/derived-return-val-realm.js fails -built-ins/Function/internals/Construct/derived-return-val.js fails built-ins/Function/internals/Construct/derived-this-uninitialized-realm.js fails built-ins/Function/internals/Construct/derived-this-uninitialized.js fails built-ins/Function/proto-from-ctor-realm.js fails @@ -1962,6 +1959,10 @@ language/eval-code/direct/non-definable-function-with-function.js sloppyFails language/eval-code/direct/non-definable-function-with-variable.js sloppyFails language/eval-code/direct/non-definable-global-function.js sloppyFails language/eval-code/direct/non-definable-global-generator.js sloppyFails +language/eval-code/direct/super-call-arrow.js fails +language/eval-code/direct/super-call-fn.js fails +language/eval-code/direct/super-call-method.js fails +language/eval-code/direct/super-call.js fails language/eval-code/direct/super-prop-method.js fails language/eval-code/direct/this-value-func-strict-source.js sloppyFails language/eval-code/direct/var-env-func-init-global-update-configurable.js sloppyFails @@ -1978,6 +1979,7 @@ language/eval-code/indirect/non-definable-function-with-variable.js sloppyFails language/eval-code/indirect/non-definable-global-function.js fails language/eval-code/indirect/non-definable-global-generator.js fails language/eval-code/indirect/realm.js fails +language/eval-code/indirect/super-call.js fails language/eval-code/indirect/this-value-func.js strictFails language/eval-code/indirect/var-env-func-init-global-new.js strictFails language/eval-code/indirect/var-env-func-init-global-update-configurable.js fails @@ -3045,35 +3047,10 @@ language/expressions/prefix-increment/S11.4.4_A5_T3.js sloppyFails language/expressions/prefix-increment/S11.4.4_A5_T4.js sloppyFails language/expressions/prefix-increment/S11.4.4_A5_T5.js fails language/expressions/prefix-increment/S11.4.4_A6_T3.js fails -language/expressions/super/call-arg-evaluation-err.js fails language/expressions/super/call-bind-this-value-twice.js fails language/expressions/super/call-bind-this-value.js fails -language/expressions/super/call-construct-error.js fails language/expressions/super/call-construct-invocation.js fails -language/expressions/super/call-expr-value.js fails language/expressions/super/call-proto-not-ctor.js fails -language/expressions/super/call-spread-err-mult-err-expr-throws.js fails -language/expressions/super/call-spread-err-mult-err-iter-get-value.js fails -language/expressions/super/call-spread-err-mult-err-itr-get-call.js fails -language/expressions/super/call-spread-err-mult-err-itr-get-get.js fails -language/expressions/super/call-spread-err-mult-err-itr-step.js fails -language/expressions/super/call-spread-err-mult-err-itr-value.js fails -language/expressions/super/call-spread-err-mult-err-unresolvable.js fails -language/expressions/super/call-spread-err-sngl-err-expr-throws.js fails -language/expressions/super/call-spread-err-sngl-err-itr-get-call.js fails -language/expressions/super/call-spread-err-sngl-err-itr-get-get.js fails -language/expressions/super/call-spread-err-sngl-err-itr-get-value.js fails -language/expressions/super/call-spread-err-sngl-err-itr-step.js fails -language/expressions/super/call-spread-err-sngl-err-itr-value.js fails -language/expressions/super/call-spread-err-sngl-err-unresolvable.js fails -language/expressions/super/call-spread-mult-empty.js fails -language/expressions/super/call-spread-mult-expr.js fails -language/expressions/super/call-spread-mult-iter.js fails -language/expressions/super/call-spread-mult-literal.js fails -language/expressions/super/call-spread-sngl-empty.js fails -language/expressions/super/call-spread-sngl-expr.js fails -language/expressions/super/call-spread-sngl-iter.js fails -language/expressions/super/call-spread-sngl-literal.js fails language/expressions/super/prop-dot-cls-null-proto.js fails language/expressions/super/prop-dot-cls-ref-strict.js fails language/expressions/super/prop-dot-cls-ref-this.js fails @@ -3273,8 +3250,6 @@ language/statements/async-function/evaluation-body.js fails language/statements/async-function/syntax-declaration-line-terminators-allowed.js fails language/statements/block/tco-stmt-list.js strictFails language/statements/block/tco-stmt.js strictFails -language/statements/class/arguments/access.js fails -language/statements/class/arguments/default-constructor.js fails language/statements/class/constructor-inferred-observable-iteration.js fails language/statements/class/cptn-decl.js fails language/statements/class/definition/accessors.js fails @@ -3588,30 +3563,18 @@ language/statements/class/static-method-gen-non-configurable-err.js fails language/statements/class/static-method-non-configurable-err.js fails language/statements/class/strict-mode/arguments-callee.js fails language/statements/class/subclass/binding.js fails +language/statements/class/subclass/bound-function.js fails language/statements/class/subclass/builtin-objects/Array/contructor-calls-super-multiple-arguments.js fails language/statements/class/subclass/builtin-objects/Array/contructor-calls-super-single-argument.js fails -language/statements/class/subclass/builtin-objects/Array/length.js fails -language/statements/class/subclass/builtin-objects/Array/regular-subclassing.js fails language/statements/class/subclass/builtin-objects/Array/super-must-be-called.js fails language/statements/class/subclass/builtin-objects/ArrayBuffer/regular-subclassing.js fails language/statements/class/subclass/builtin-objects/ArrayBuffer/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/Boolean/regular-subclassing.js fails language/statements/class/subclass/builtin-objects/Boolean/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/DataView/regular-subclassing.js fails language/statements/class/subclass/builtin-objects/DataView/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/Date/regular-subclassing.js fails language/statements/class/subclass/builtin-objects/Date/super-must-be-called.js fails language/statements/class/subclass/builtin-objects/Error/message-property-assignment.js fails -language/statements/class/subclass/builtin-objects/Error/regular-subclassing.js fails language/statements/class/subclass/builtin-objects/Error/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/Function/instance-length.js fails -language/statements/class/subclass/builtin-objects/Function/instance-name.js fails -language/statements/class/subclass/builtin-objects/Function/regular-subclassing.js fails language/statements/class/subclass/builtin-objects/Function/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/GeneratorFunction/instance-length.js fails -language/statements/class/subclass/builtin-objects/GeneratorFunction/instance-name.js fails -language/statements/class/subclass/builtin-objects/GeneratorFunction/instance-prototype.js fails -language/statements/class/subclass/builtin-objects/GeneratorFunction/regular-subclassing.js fails language/statements/class/subclass/builtin-objects/GeneratorFunction/super-must-be-called.js fails language/statements/class/subclass/builtin-objects/Map/regular-subclassing.js fails language/statements/class/subclass/builtin-objects/Map/super-must-be-called.js fails @@ -3627,43 +3590,24 @@ language/statements/class/subclass/builtin-objects/NativeError/TypeError-message language/statements/class/subclass/builtin-objects/NativeError/TypeError-super.js fails language/statements/class/subclass/builtin-objects/NativeError/URIError-message.js fails language/statements/class/subclass/builtin-objects/NativeError/URIError-super.js fails -language/statements/class/subclass/builtin-objects/Number/regular-subclassing.js fails language/statements/class/subclass/builtin-objects/Number/super-must-be-called.js fails language/statements/class/subclass/builtin-objects/Object/constructor-return-undefined-throws.js fails -language/statements/class/subclass/builtin-objects/Object/constructor-returns-non-object.js fails language/statements/class/subclass/builtin-objects/Promise/regular-subclassing.js fails language/statements/class/subclass/builtin-objects/Promise/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/RegExp/lastIndex.js fails -language/statements/class/subclass/builtin-objects/RegExp/regular-subclassing.js fails language/statements/class/subclass/builtin-objects/RegExp/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/Set/regular-subclassing.js fails language/statements/class/subclass/builtin-objects/Set/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/String/length.js fails -language/statements/class/subclass/builtin-objects/String/regular-subclassing.js fails language/statements/class/subclass/builtin-objects/String/super-must-be-called.js fails -language/statements/class/subclass/builtin-objects/Symbol/new-symbol-with-super-throws.js fails -language/statements/class/subclass/builtin-objects/TypedArray/regular-subclassing.js fails language/statements/class/subclass/builtin-objects/TypedArray/super-must-be-called.js fails language/statements/class/subclass/builtin-objects/WeakMap/regular-subclassing.js fails language/statements/class/subclass/builtin-objects/WeakMap/super-must-be-called.js fails language/statements/class/subclass/builtin-objects/WeakSet/regular-subclassing.js fails language/statements/class/subclass/builtin-objects/WeakSet/super-must-be-called.js fails language/statements/class/subclass/builtins.js fails -language/statements/class/subclass/class-definition-evaluation-empty-constructor-heritage-present.js fails language/statements/class/subclass/class-definition-null-proto-super.js fails language/statements/class/subclass/class-definition-null-proto-this.js fails -language/statements/class/subclass/class-definition-parent-proto-null.js fails language/statements/class/subclass/class-definition-superclass-generator.js fails -language/statements/class/subclass/default-constructor-2.js fails language/statements/class/subclass/default-constructor-spread-override.js fails -language/statements/class/subclass/default-constructor.js fails -language/statements/class/subclass/derived-class-return-override-with-boolean.js fails language/statements/class/subclass/derived-class-return-override-with-empty.js fails -language/statements/class/subclass/derived-class-return-override-with-null.js fails -language/statements/class/subclass/derived-class-return-override-with-number.js fails -language/statements/class/subclass/derived-class-return-override-with-object.js fails -language/statements/class/subclass/derived-class-return-override-with-string.js fails -language/statements/class/subclass/derived-class-return-override-with-symbol.js fails language/statements/class/subclass/derived-class-return-override-with-this.js fails language/statements/class/subclass/derived-class-return-override-with-undefined.js fails language/statements/class/super/in-constructor.js fails @@ -3673,7 +3617,6 @@ language/statements/class/super/in-setter.js fails language/statements/class/super/in-static-getter.js fails language/statements/class/super/in-static-methods.js fails language/statements/class/super/in-static-setter.js fails -language/statements/class/syntax/class-body-has-direct-super-class-heritage.js fails language/statements/class/syntax/class-body-method-definition-super-property.js fails language/statements/class/syntax/class-expression-heritage-identifier-reference.js fails language/statements/class/syntax/class-expression.js fails -- cgit v1.2.3