aboutsummaryrefslogtreecommitdiffstats
path: root/src
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
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')
-rw-r--r--src/qml/jsruntime/qv4function_p.h1
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp9
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h28
-rw-r--r--src/qml/jsruntime/qv4generatorobject.cpp10
-rw-r--r--src/qml/jsruntime/qv4generatorobject_p.h10
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp1
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp64
7 files changed, 80 insertions, 43 deletions
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index d542ce752f..029dd7786b 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -81,6 +81,7 @@ struct Q_QML_EXPORT Function {
uint nFormals;
int interpreterCallCount = 0;
bool hasQmlDependencies;
+ bool isEval = false;
Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function);
~Function();
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index f7bea9a5f0..fe1ebbd556 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -175,7 +175,7 @@ Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *sco
return scope->engine()->memoryManager->allocate<ScriptFunction>(scope, function);
}
-Heap::FunctionObject *FunctionObject::createConstructorFunction(ExecutionContext *scope, Function *function, bool isDerivedConstructor)
+Heap::FunctionObject *FunctionObject::createConstructorFunction(ExecutionContext *scope, Function *function, Object *homeObject, bool isDerivedConstructor)
{
if (!function) {
Heap::DefaultClassConstructorFunction *c = scope->engine()->memoryManager->allocate<DefaultClassConstructorFunction>(scope);
@@ -183,13 +183,16 @@ Heap::FunctionObject *FunctionObject::createConstructorFunction(ExecutionContext
return c;
}
Heap::ConstructorFunction *c = scope->engine()->memoryManager->allocate<ConstructorFunction>(scope, function);
+ c->homeObject.set(scope->engine(), homeObject->d());
c->isDerivedConstructor = isDerivedConstructor;
return c;
}
-Heap::FunctionObject *FunctionObject::createMemberFunction(ExecutionContext *scope, Function *function, QV4::String *name)
+Heap::FunctionObject *FunctionObject::createMemberFunction(ExecutionContext *scope, Function *function, Object *homeObject, QV4::String *name)
{
- return scope->engine()->memoryManager->allocate<MemberFunction>(scope, function, name);
+ Heap::MemberFunction *m = scope->engine()->memoryManager->allocate<MemberFunction>(scope, function, name);
+ m->homeObject.set(scope->engine(), homeObject->d());
+ return m;
}
Heap::FunctionObject *FunctionObject::createBuiltinFunction(ExecutionEngine *engine, StringOrSymbol *nameOrSymbol, VTable::Call code, int argumentCount)
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 54964b9bbd..766960d2ac 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -122,13 +122,16 @@ DECLARE_HEAP_OBJECT(ScriptFunction, FunctionObject) {
void init(QV4::ExecutionContext *scope, Function *function, QV4::String *name = nullptr);
};
-struct ConstructorFunction : ScriptFunction
-{
- bool isDerivedConstructor;
+#define MemberFunctionMembers(class, Member) \
+ Member(class, Pointer, Object *, homeObject)
+
+DECLARE_HEAP_OBJECT(MemberFunction, ScriptFunction) {
+ DECLARE_MARKOBJECTS(MemberFunction)
};
-struct MemberFunction : ScriptFunction
+struct ConstructorFunction : MemberFunction
{
+ bool isDerivedConstructor;
};
struct DefaultClassConstructorFunction : FunctionObject
@@ -187,8 +190,8 @@ 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, bool isDerivedConstructor);
- static Heap::FunctionObject *createMemberFunction(ExecutionContext *scope, Function *function, String *name);
+ static Heap::FunctionObject *createConstructorFunction(ExecutionContext *scope, Function *function, Object *homeObject, bool isDerivedConstructor);
+ static Heap::FunctionObject *createMemberFunction(ExecutionContext *scope, Function *function, Object *homeObject, String *name);
static Heap::FunctionObject *createBuiltinFunction(ExecutionEngine *engine, StringOrSymbol *nameOrSymbol, VTable::Call code, int argumentCount);
bool strictMode() const { return d()->function ? d()->function->isStrict() : false; }
@@ -261,18 +264,17 @@ struct ScriptFunction : FunctionObject {
Heap::InternalClass *classForConstructor() const;
};
-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);
-};
-
struct MemberFunction : ScriptFunction {
V4_OBJECT2(MemberFunction, ScriptFunction)
V4_INTERNALCLASS(MemberFunction)
};
+struct ConstructorFunction : MemberFunction {
+ V4_OBJECT2(ConstructorFunction, MemberFunction)
+ 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);
+};
struct DefaultClassConstructorFunction : FunctionObject {
V4_OBJECT2(DefaultClassConstructorFunction, FunctionObject)
diff --git a/src/qml/jsruntime/qv4generatorobject.cpp b/src/qml/jsruntime/qv4generatorobject.cpp
index bab0cfbfb1..82d8d88882 100644
--- a/src/qml/jsruntime/qv4generatorobject.cpp
+++ b/src/qml/jsruntime/qv4generatorobject.cpp
@@ -230,13 +230,19 @@ ReturnedValue GeneratorObject::resume(ExecutionEngine *engine, const Value &arg)
DEFINE_OBJECT_VTABLE(MemberGeneratorFunction);
-Heap::FunctionObject *MemberGeneratorFunction::create(ExecutionContext *context, Function *function, String *name)
+Heap::FunctionObject *MemberGeneratorFunction::create(ExecutionContext *context, Function *function, Object *homeObject, String *name)
{
Scope scope(context);
- Scoped<GeneratorFunction> g(scope, context->engine()->memoryManager->allocate<MemberGeneratorFunction>(context, function, name));
+ Scoped<MemberGeneratorFunction> g(scope, context->engine()->memoryManager->allocate<MemberGeneratorFunction>(context, function, name));
+ g->d()->homeObject.set(scope.engine, homeObject->d());
ScopedObject proto(scope, scope.engine->newObject());
proto->setPrototypeOf(scope.engine->generatorPrototype());
g->defineDefaultProperty(scope.engine->id_prototype(), proto, Attr_NotConfigurable|Attr_NotEnumerable);
g->setPrototypeOf(ScopedObject(scope, scope.engine->generatorFunctionCtor()->get(scope.engine->id_prototype())));
return g->d();
}
+
+ReturnedValue MemberGeneratorFunction::virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc)
+{
+ return GeneratorFunction::virtualCall(f, thisObject, argv, argc);
+}
diff --git a/src/qml/jsruntime/qv4generatorobject_p.h b/src/qml/jsruntime/qv4generatorobject_p.h
index f00f730344..55e6091ad5 100644
--- a/src/qml/jsruntime/qv4generatorobject_p.h
+++ b/src/qml/jsruntime/qv4generatorobject_p.h
@@ -75,7 +75,7 @@ struct GeneratorFunctionCtor : FunctionObject {
struct GeneratorFunction : ScriptFunction {
};
-struct MemberGeneratorFunction : ScriptFunction {
+struct MemberGeneratorFunction : MemberFunction {
};
struct GeneratorPrototype : FunctionObject {
@@ -113,12 +113,14 @@ struct GeneratorFunction : ScriptFunction
static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
-struct MemberGeneratorFunction : GeneratorFunction
+struct MemberGeneratorFunction : MemberFunction
{
- V4_OBJECT2(MemberGeneratorFunction, GeneratorFunction)
+ V4_OBJECT2(MemberGeneratorFunction, MemberFunction)
V4_INTERNALCLASS(MemberGeneratorFunction)
- static Heap::FunctionObject *create(ExecutionContext *scope, Function *function, String *name);
+ static Heap::FunctionObject *create(ExecutionContext *scope, Function *function, Object *homeObject, String *name);
+ static constexpr VTable::CallAsConstructor virtualCallAsConstructor = nullptr;
+ static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
};
struct GeneratorPrototype : Object
diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp
index 43895011f3..1f747b62d7 100644
--- a/src/qml/jsruntime/qv4globalobject.cpp
+++ b/src/qml/jsruntime/qv4globalobject.cpp
@@ -371,6 +371,7 @@ ReturnedValue EvalFunction::evalCall(const Value *, const Value *argv, int argc,
Function *function = script.function();
if (!function)
return Encode::undefined();
+ function->isEval = true;
if (function->isStrict() || isStrict) {
ScopedFunctionObject e(scope, FunctionObject::createScriptFunction(ctx, function));
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) {