aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4runtime.cpp
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-08-30 13:16:28 +0200
committerLars Knoll <lars.knoll@qt.io>2018-08-31 06:08:48 +0000
commitac3a9fd8f352b1d717334d16111d22d6c155e4e2 (patch)
tree17c12dbc09143103d060da062a5d9102d7c50f57 /src/qml/jsruntime/qv4runtime.cpp
parentd457b919885fdbcc07f3414de64b0b50ebe8b263 (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.cpp64
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) {