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 + 5 files changed, 80 insertions(+), 31 deletions(-) (limited to 'src/qml/compiler') 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) \ -- cgit v1.2.3