diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-07-01 12:00:57 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-07-03 08:09:17 +0000 |
commit | d31541fd9d7d52ef3eae29e7e5d36733d7f55375 (patch) | |
tree | c5d17bea0119c9f0eb26e97eb523b281e9900783 /src | |
parent | 6e79a00cad2f5dd09bdf40e594a65af58b370d9d (diff) |
Add support for super properties
Those are mostly working now, but when calling super properties
the this object is not setup correctly.
Change-Id: Ib42129ae6e729eeca00275f707f480371b7e42a5
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/compiler/qv4bytecodehandler.cpp | 6 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 35 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen_p.h | 9 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth.cpp | 8 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 6 | ||||
-rw-r--r-- | src/qml/jit/qv4baselinejit.cpp | 24 | ||||
-rw-r--r-- | src/qml/jit/qv4baselinejit_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 36 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtimeapi_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 17 |
10 files changed, 141 insertions, 4 deletions
diff --git a/src/qml/compiler/qv4bytecodehandler.cpp b/src/qml/compiler/qv4bytecodehandler.cpp index 45968570d0..23f7051718 100644 --- a/src/qml/compiler/qv4bytecodehandler.cpp +++ b/src/qml/compiler/qv4bytecodehandler.cpp @@ -212,6 +212,12 @@ std::vector<int> ByteCodeHandler::collectLabelsInBytecode(const char *code, uint COLLECTOR_BEGIN_INSTR(SetLookup) COLLECTOR_END_INSTR(SetLookup) + COLLECTOR_BEGIN_INSTR(LoadSuperProperty) + COLLECTOR_END_INSTR(LoadSuperProperty) + + COLLECTOR_BEGIN_INSTR(StoreSuperProperty) + COLLECTOR_END_INSTR(StoreSuperProperty) + COLLECTOR_BEGIN_INSTR(StoreScopeObjectProperty) COLLECTOR_END_INSTR(StoreScopeObjectProperty) diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 7e22966302..2f28320697 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -1109,6 +1109,11 @@ bool Codegen::visit(ArrayMemberExpression *ast) Reference base = expression(ast->base); if (hasError) return false; + if (base.isSuper()) { + Reference index = expression(ast->expression).storeOnStack(); + _expr.setResult(Reference::fromSuperProperty(index)); + return false; + } base = base.storeOnStack(); if (hasError) return false; @@ -1957,6 +1962,9 @@ bool Codegen::visit(DeleteExpression *ast) return false; switch (expr.type) { + case Reference::SuperProperty: + // ### this should throw a reference error at runtime. + return false; case Reference::StackSlot: if (!expr.stackSlotIsLocalOrArgument) break; @@ -2052,6 +2060,14 @@ bool Codegen::visit(FieldMemberExpression *ast) Reference base = expression(ast->base); if (hasError) return false; + if (base.isSuper()) { + Instruction::LoadRuntimeString load; + load.stringId = registerString(ast->name.toString()); + bytecodeGenerator->addInstruction(load); + Reference property = Reference::fromAccumulator(this).storeOnStack(); + _expr.setResult(Reference::fromSuperProperty(property)); + return false; + } _expr.setResult(Reference::fromMember(base, ast->name.toString())); return false; } @@ -3710,6 +3726,9 @@ Codegen::Reference &Codegen::Reference::operator =(const Reference &other) break; case Super: break; + case SuperProperty: + property = other.property; + break; case StackSlot: theStackSlot = other.theStackSlot; break; @@ -3761,6 +3780,8 @@ bool Codegen::Reference::operator==(const Codegen::Reference &other) const break; case Super: return true; + case SuperProperty: + return property == other.property; case StackSlot: return theStackSlot == other.theStackSlot; case ScopedLocal: @@ -3941,7 +3962,12 @@ void Codegen::Reference::storeAccumulator() const } switch (type) { case Super: - codegen->throwSyntaxError(SourceLocation(), QStringLiteral("storing super properties not implemented.")); + Q_UNREACHABLE(); + return; + case SuperProperty: + Instruction::StoreSuperProperty store; + store.property = property.stackSlot(); + codegen->bytecodeGenerator->addInstruction(store); return; case StackSlot: { Instruction::StoreReg store; @@ -4021,7 +4047,12 @@ void Codegen::Reference::loadInAccumulator() const case Accumulator: return; case Super: - codegen->throwSyntaxError(AST::SourceLocation(), QStringLiteral("Super property access not implemented.")); + Q_UNREACHABLE(); + return; + case SuperProperty: + Instruction::LoadSuperProperty load; + load.property = property.stackSlot(); + codegen->bytecodeGenerator->addInstruction(load); return; case Const: { QT_WARNING_PUSH diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 814754aea2..337c4dbfe3 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -180,6 +180,7 @@ public: Invalid, Accumulator, Super, + SuperProperty, StackSlot, ScopedLocal, Name, @@ -217,6 +218,7 @@ public: bool isConstant() const { return type == Const; } bool isAccumulator() const { return type == Accumulator; } bool isSuper() const { return type == Super; } + bool isSuperProperty() const { return type == SuperProperty; } bool isStackSlot() const { return type == StackSlot; } bool isRegister() const { return isStackSlot(); @@ -282,6 +284,12 @@ public: r.propertyNameIndex = r.codegen->registerString(name); return r; } + static Reference fromSuperProperty(const Reference &property) { + Q_ASSERT(property.isStackSlot()); + Reference r(property.codegen, SuperProperty); + r.property = property.stackSlot(); + return r; + } static Reference fromSubscript(const Reference &baseRef, const Reference &subscript) { Q_ASSERT(baseRef.isStackSlot()); Reference r(baseRef.codegen, Subscript); @@ -368,6 +376,7 @@ public: qint16 qmlNotifyIndex; PropertyCapturePolicy capturePolicy; }; + Moth::StackSlot property; // super property }; QString name; mutable bool isArgOrEval = false; diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp index 56da14b098..5621b456d5 100644 --- a/src/qml/compiler/qv4instr_moth.cpp +++ b/src/qml/compiler/qv4instr_moth.cpp @@ -312,6 +312,14 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st d << dumpRegister(base, nFormals) << "(" << index << ")"; MOTH_END_INSTR(SetLookup) + MOTH_BEGIN_INSTR(LoadSuperProperty) + d << dumpRegister(property, nFormals); + MOTH_END_INSTR(LoadSuperProperty) + + MOTH_BEGIN_INSTR(StoreSuperProperty) + d << dumpRegister(property, nFormals); + MOTH_END_INSTR(StoreSuperProperty) + MOTH_BEGIN_INSTR(StoreScopeObjectProperty) d << dumpRegister(base, nFormals) << "[" << propertyIndex << "]"; MOTH_END_INSTR(StoreScopeObjectProperty) diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index f0a3332ee1..7c1d4db4ca 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -95,6 +95,8 @@ QT_BEGIN_NAMESPACE #define INSTR_Resume(op) INSTRUCTION(op, Resume, 1, offset) #define INSTR_StoreProperty(op) INSTRUCTION(op, StoreProperty, 2, name, base) #define INSTR_SetLookup(op) INSTRUCTION(op, SetLookup, 2, index, base) +#define INSTR_LoadSuperProperty(op) INSTRUCTION(op, LoadSuperProperty, 1, property) +#define INSTR_StoreSuperProperty(op) INSTRUCTION(op, StoreSuperProperty, 1, property) #define INSTR_StoreScopeObjectProperty(op) INSTRUCTION(op, StoreScopeObjectProperty, 2, base, propertyIndex) #define INSTR_StoreContextObjectProperty(op) INSTRUCTION(op, StoreContextObjectProperty, 2, base, propertyIndex) #define INSTR_LoadElement(op) INSTRUCTION(op, LoadElement, 1, base) @@ -221,6 +223,8 @@ QT_BEGIN_NAMESPACE F(GetLookup) \ F(StoreProperty) \ F(SetLookup) \ + F(LoadSuperProperty) \ + F(StoreSuperProperty) \ F(StoreScopeObjectProperty) \ F(StoreContextObjectProperty) \ F(LoadScopeObjectProperty) \ @@ -516,7 +520,7 @@ struct InstrInfo static int size(Instr::Type type); }; -Q_STATIC_ASSERT(MOTH_NUM_INSTRUCTIONS() < 128); +Q_STATIC_ASSERT(MOTH_NUM_INSTRUCTIONS() <= 128); template<int N> struct InstrMeta { diff --git a/src/qml/jit/qv4baselinejit.cpp b/src/qml/jit/qv4baselinejit.cpp index 1df7223936..9132b194a5 100644 --- a/src/qml/jit/qv4baselinejit.cpp +++ b/src/qml/jit/qv4baselinejit.cpp @@ -304,6 +304,30 @@ void BaselineJIT::generate_SetLookup(int index, int base) as->checkException(); } +void BaselineJIT::generate_LoadSuperProperty(int property) +{ + STORE_IP(); + STORE_ACC(); + as->prepareCallWithArgCount(2); + as->passRegAsArg(property, 1); + as->passEngineAsArg(0); + JIT_GENERATE_RUNTIME_CALL(Runtime::method_loadSuperProperty, Assembler::ResultInAccumulator); + as->checkException(); +} + +void BaselineJIT::generate_StoreSuperProperty(int property) +{ + STORE_IP(); + STORE_ACC(); + as->prepareCallWithArgCount(3); + as->passAccumulatorAsArg(2); + as->passRegAsArg(property, 1); + as->passFunctionAsArg(0); + JIT_GENERATE_RUNTIME_CALL(Runtime::method_storeSuperProperty, Assembler::IgnoreResult); + as->checkException(); +} + + void BaselineJIT::generate_StoreScopeObjectProperty(int base, int propertyIndex) { STORE_ACC(); diff --git a/src/qml/jit/qv4baselinejit_p.h b/src/qml/jit/qv4baselinejit_p.h index d953d86a06..d96fd6ea6a 100644 --- a/src/qml/jit/qv4baselinejit_p.h +++ b/src/qml/jit/qv4baselinejit_p.h @@ -104,6 +104,8 @@ public: void generate_GetLookup(int index) override; void generate_StoreProperty(int name, int base) override; void generate_SetLookup(int index, int base) override; + void generate_LoadSuperProperty(int property) override; + void generate_StoreSuperProperty(int property) override; void generate_StoreScopeObjectProperty(int base, int propertyIndex) override; void generate_StoreContextObjectProperty(int base, diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index eeb66509e3..7b2fd07f0b 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -856,6 +856,42 @@ ReturnedValue Runtime::method_loadName(ExecutionEngine *engine, int nameIndex) return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name); } +ReturnedValue Runtime::method_loadSuperProperty(ExecutionEngine *engine, const Value &property) +{ + Scope scope(engine); + ScopedObject base(scope, engine->currentStackFrame->thisObject()); + if (!base) + return engine->throwTypeError(); + ScopedObject proto(scope, base->getPrototypeOf()); + if (!proto) + return engine->throwTypeError(); + ScopedPropertyKey key(scope, property.toPropertyKey(engine)); + if (engine->hasException) + return Encode::undefined(); + return proto->get(key, base); +} + +void Runtime::method_storeSuperProperty(ExecutionEngine *engine, const Value &property, const Value &value) +{ + Scope scope(engine); + ScopedObject base(scope, engine->currentStackFrame->thisObject()); + if (!base) { + engine->throwTypeError(); + return; + } + ScopedObject proto(scope, base->getPrototypeOf()); + if (!proto) { + engine->throwTypeError(); + return; + } + ScopedPropertyKey key(scope, property.toPropertyKey(engine)); + if (engine->hasException) + return; + bool result = proto->put(key, value, base); + if (!result && engine->currentStackFrame->v4Function->isStrict()) + engine->throwTypeError(); +} + #endif // V4_BOOTSTRAP uint RuntimeHelpers::equalHelper(const Value &x, const Value &y) diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h index b4d9d329c4..3f65e6c6d6 100644 --- a/src/qml/jsruntime/qv4runtimeapi_p.h +++ b/src/qml/jsruntime/qv4runtimeapi_p.h @@ -113,6 +113,8 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> { F(ReturnedValue, loadProperty, (ExecutionEngine *engine, const Value &object, int nameIndex)) \ F(ReturnedValue, loadName, (ExecutionEngine *engine, int nameIndex)) \ F(ReturnedValue, loadElement, (ExecutionEngine *engine, const Value &object, const Value &index)) \ + F(ReturnedValue, loadSuperProperty, (ExecutionEngine *engine, const Value &property)) \ + F(void, storeSuperProperty, (ExecutionEngine *engine, const Value &property, const Value &value)) \ \ /* typeof */ \ F(ReturnedValue, typeofValue, (ExecutionEngine *engine, const Value &val)) \ diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 83d1aa3250..6c667110a9 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -610,6 +610,20 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, CHECK_EXCEPTION; MOTH_END_INSTR(SetLookup) + MOTH_BEGIN_INSTR(LoadSuperProperty) + STORE_IP(); + STORE_ACC(); + acc = Runtime::method_loadSuperProperty(engine, STACK_VALUE(property)); + CHECK_EXCEPTION; + MOTH_END_INSTR(LoadSuperProperty) + + MOTH_BEGIN_INSTR(StoreSuperProperty) + STORE_IP(); + STORE_ACC(); + Runtime::method_storeSuperProperty(engine, STACK_VALUE(property), accumulator); + CHECK_EXCEPTION; + MOTH_END_INSTR(StoreSuperProperty) + MOTH_BEGIN_INSTR(StoreScopeObjectProperty) STORE_ACC(); Runtime::method_storeQmlScopeObjectProperty(engine, STACK_VALUE(base), propertyIndex, accumulator); @@ -666,7 +680,8 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, acc = engine->throwTypeError(QStringLiteral("%1 is not a function").arg(func.toQStringNoThrow())); goto handleUnwind; } - acc = static_cast<const FunctionObject &>(func).call(nullptr, stack + argv, argc); + Value undef = Primitive::undefinedValue(); + acc = static_cast<const FunctionObject &>(func).call(&undef, stack + argv, argc); CHECK_EXCEPTION; MOTH_END_INSTR(CallValue) |