diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-08-30 13:16:28 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-08-31 06:08:48 +0000 |
commit | ac3a9fd8f352b1d717334d16111d22d6c155e4e2 (patch) | |
tree | 17c12dbc09143103d060da062a5d9102d7c50f57 /src/qml/jsruntime/qv4runtime.cpp | |
parent | d457b919885fdbcc07f3414de64b0b50ebe8b263 (diff) |
Fix super property access
Super properties work in a rather special way by
accessing a 'home object' on the function object,
and reading from it's prototype.
Change-Id: I666334c9c27048c6c2ba6770dd8c9f56aecbee14
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml/jsruntime/qv4runtime.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 64 |
1 files changed, 43 insertions, 21 deletions
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index fbddcb6ee1..1a201a5d37 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -875,38 +875,60 @@ ReturnedValue Runtime::method_loadName(ExecutionEngine *engine, int nameIndex) return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name); } +static Object *getSuperBase(Scope &scope) +{ + ScopedFunctionObject f(scope, scope.engine->currentStackFrame->jsFrame->function); + MemberFunction *m = f->as<MemberFunction>(); + if (!m) { + ScopedContext ctx(scope, static_cast<ExecutionContext *>(&scope.engine->currentStackFrame->jsFrame->context)); + Q_ASSERT(ctx); + while (ctx) { + if (CallContext *c = ctx->asCallContext()) { + f = c->d()->function; + QV4::Function *fn = f->function(); + if (fn && !fn->isArrowFunction() && !fn->isEval) + break; + } + ctx = ctx->d()->outer; + } + m = f->as<MemberFunction>(); + } + if (!m) { + scope.engine->throwTypeError(); + return nullptr; + } + ScopedObject homeObject(scope, m->d()->homeObject); + Q_ASSERT(homeObject); + ScopedObject proto(scope, homeObject->getPrototypeOf()); + if (!proto) { + scope.engine->throwTypeError(); + return nullptr; + } + return proto; +} + ReturnedValue Runtime::method_loadSuperProperty(ExecutionEngine *engine, const Value &property) { Scope scope(engine); - ScopedObject base(scope, engine->currentStackFrame->thisObject()); + Object *base = getSuperBase(scope); if (!base) - return engine->throwTypeError(); - ScopedObject proto(scope, base->getPrototypeOf()); - if (!proto) - return engine->throwTypeError(); + return Encode::undefined(); ScopedPropertyKey key(scope, property.toPropertyKey(engine)); if (engine->hasException) return Encode::undefined(); - return proto->get(key, base); + return base->get(key, &engine->currentStackFrame->jsFrame->thisObject); } 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(); + Object *base = getSuperBase(scope); + if (!base) return; - } ScopedPropertyKey key(scope, property.toPropertyKey(engine)); if (engine->hasException) return; - bool result = proto->put(key, value, base); + bool result = base->put(key, value, &engine->currentStackFrame->jsFrame->thisObject); if (!result && engine->currentStackFrame->v4Function->isStrict()) engine->throwTypeError(); } @@ -1554,9 +1576,9 @@ ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, int classId ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context); if (clos->isGenerator()) - value = MemberGeneratorFunction::create(current, clos, fnName)->asReturnedValue(); + value = MemberGeneratorFunction::create(current, clos, o, fnName)->asReturnedValue(); else - value = FunctionObject::createMemberFunction(current, clos, fnName)->asReturnedValue(); + value = FunctionObject::createMemberFunction(current, clos, o, fnName)->asReturnedValue(); } else if (args[2].isFunctionObject()) { fn = static_cast<const FunctionObject &>(args[2]); @@ -1612,7 +1634,7 @@ ReturnedValue Runtime::method_createClass(ExecutionEngine *engine, int classInde ScopedFunctionObject constructor(scope); QV4::Function *f = cls->constructorFunction != UINT_MAX ? unit->runtimeFunctions[cls->constructorFunction] : nullptr; - constructor = FunctionObject::createConstructorFunction(current, f, !superClass.isEmpty())->asReturnedValue(); + constructor = FunctionObject::createConstructorFunction(current, f, proto, !superClass.isEmpty())->asReturnedValue(); constructor->setPrototypeUnchecked(constructorParent); Value argCount = Primitive::fromInt32(f ? f->nFormals : 0); constructor->defineReadonlyConfigurableProperty(scope.engine->id_length(), argCount); @@ -1655,9 +1677,9 @@ ReturnedValue Runtime::method_createClass(ExecutionEngine *engine, int classInde name = propertyName->asFunctionName(engine, prefix); if (f->isGenerator()) - function = MemberGeneratorFunction::create(current, f, name); + function = MemberGeneratorFunction::create(current, f, receiver, name); else - function = FunctionObject::createMemberFunction(current, f, name); + function = FunctionObject::createMemberFunction(current, f, receiver, name); Q_ASSERT(function); PropertyAttributes attributes; switch (methods[i].type) { |