diff options
author | Ulf Hermann <[email protected]> | 2021-05-17 16:38:25 +0200 |
---|---|---|
committer | Ulf Hermann <[email protected]> | 2021-06-10 11:53:19 +0200 |
commit | e20650e0702259b4be79be85a3d27e45db42efc1 (patch) | |
tree | 7536cee98f4cc502774f807d1a609940cd20d4f5 /src | |
parent | 7fa28f98824a94396106eadfc028b329985a0cfc (diff) |
Eliminate JS call frame from metatypes calls
If we call an AOT-compiled function we never need the JavaScript call
frame. We can just skip its setup and save some overhead.
Change-Id: I39dc2ca6eea5b5a66f3b87b642a310534cecf6cd
Reviewed-by: Fabian Kosmale <[email protected]>
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4context.cpp | 9 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4function.cpp | 14 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4function_p.h | 7 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 23 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject_p.h | 6 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4generatorobject.cpp | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4jscall_p.h | 53 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 127 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4stackframe.cpp | 13 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4stackframe_p.h | 157 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vtable_p.h | 3 | ||||
-rw-r--r-- | src/qml/qml/qqml.cpp | 7 | ||||
-rw-r--r-- | src/qml/qml/qqmlcomponent.cpp | 2 | ||||
-rw-r--r-- | src/qml/qml/qqmljavascriptexpression.cpp | 24 | ||||
-rw-r--r-- | src/qml/qml/qqmlvmemetaobject.cpp | 4 |
19 files changed, 296 insertions, 173 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp index e0c24979a9..7e05769941 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp @@ -72,7 +72,7 @@ void JavaScriptJob::run() for (int i = 0; frame && i < frameNr; ++i) frame = frame->parentFrame(); if (frameNr > 0 && frame) - ctx = static_cast<QV4::ExecutionContext *>(&frame->jsFrame->context); + ctx = frame->context(); if (context >= 0) { QObject *forId = QQmlDebugService::objectForId(context); @@ -218,7 +218,8 @@ void ValueLookupJob::run() QQmlContextData::get(engine->qmlEngine()->rootContext()), scopeObject.data()); } - QV4::ScopedStackFrame frame(scope, qmlContext); + QV4::Scoped<QV4::ExecutionContext> scopedContext(scope, qmlContext); + QV4::ScopedStackFrame frame(scope, scopedContext); for (const QJsonValue handle : handles) { QV4DataCollector::Ref ref = handle.toInt(); if (!collector->isValidRef(ref)) { diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index 282046f3fa..fb002ec48d 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -71,8 +71,13 @@ Heap::CallContext *ExecutionContext::newBlockContext(CppStackFrame *frame, int b Heap::ExecutionContext *outer = static_cast<Heap::ExecutionContext *>(frame->context()->m()); c->outer.set(v4, outer); - c->function.set(v4, static_cast<Heap::FunctionObject *>( - Value::fromStaticValue(frame->jsFrame->function).m())); + if (frame->isJSTypesFrame()) { + c->function.set(v4, static_cast<Heap::FunctionObject *>( + Value::fromStaticValue( + static_cast<JSTypesStackFrame *>(frame)->jsFrame->function).m())); + } else { + c->function.set(v4, nullptr); + } c->locals.size = nLocals; c->locals.alloc = nLocals; diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index fb5f5802f8..6b4fc81bf3 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -2112,12 +2112,11 @@ void ExecutionEngine::callInContext(Function *function, QObject *self, QV4::Scope scope(this); ExecutionContext *ctx = currentStackFrame ? currentContext() : scriptContext(); QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(ctx, ctxtdata, self)); - QV4::ScopedValue selfValue(scope, QV4::QObjectWrapper::wrap(this, self)); if (!args) { Q_ASSERT(argc == 0); void *dummyArgs[] = { nullptr }; QMetaType dummyTypes[] = { QMetaType::fromType<void>() }; - function->call(selfValue, dummyArgs, dummyTypes, argc, qmlContext); + function->call(self, dummyArgs, dummyTypes, argc, qmlContext); return; } @@ -2125,7 +2124,7 @@ void ExecutionEngine::callInContext(Function *function, QObject *self, return; // implicitly sets the return value, which is args[0] - function->call(selfValue, args, types, argc, qmlContext); + function->call(self, args, types, argc, qmlContext); } void ExecutionEngine::initQmlGlobalObject() diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 3120261a94..be115cb064 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -561,10 +561,7 @@ public: void setProfiler(Profiling::Profiler *profiler); #endif // QT_CONFIG(qml_debug) - ExecutionContext *currentContext() const - { - return static_cast<ExecutionContext *>(¤tStackFrame->jsFrame->context); - } + ExecutionContext *currentContext() const { return currentStackFrame->context(); } // ensure we always get odd prototype IDs. This helps make marking in QV4::Lookup fast quintptr newProtoId() { return (protoIdCount += 2); } diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index db767085da..7b5685a2a0 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -57,8 +57,8 @@ QT_BEGIN_NAMESPACE using namespace QV4; -bool Function::call(const Value *thisObject, void **a, const QMetaType *types, int argc, - const ExecutionContext *context) +bool Function::call(QObject *thisObject, void **a, const QMetaType *types, int argc, + ExecutionContext *context) { if (!aotFunction) { return QV4::convertAndCall( @@ -70,21 +70,19 @@ bool Function::call(const Value *thisObject, void **a, const QMetaType *types, i ExecutionEngine *engine = context->engine(); MetaTypesStackFrame frame; - frame.init(this, a, types, argc); - frame.setupJSFrame(engine->jsStackTop, Value::undefinedValue(), context->d(), - thisObject ? *thisObject : Value::undefinedValue()); + frame.init(this, thisObject, context, a, types, argc); frame.push(engine); - engine->jsStackTop += frame.requiredJSStackFrameSize(); Moth::VME::exec(&frame, engine); frame.pop(engine); return true; } -ReturnedValue Function::call(const Value *thisObject, const Value *argv, int argc, const ExecutionContext *context) { +ReturnedValue Function::call( + const Value *thisObject, const Value *argv, int argc, ExecutionContext *context) { if (aotFunction) { return QV4::convertAndCall( context->engine(), aotFunction, thisObject, argv, argc, - [this, context](const Value *thisObject, + [this, context](QObject *thisObject, void **a, const QMetaType *types, int argc) { call(thisObject, a, types, argc, context); }); diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index 7577161c01..45f2a6263a 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -100,9 +100,10 @@ public: return compilationUnit->runtimeStrings[i]; } - bool call(const Value *thisObject, void **a, const QMetaType *types, int argc, - const ExecutionContext *context); - ReturnedValue call(const Value *thisObject, const Value *argv, int argc, const ExecutionContext *context); + bool call(QObject *thisObject, void **a, const QMetaType *types, int argc, + ExecutionContext *context); + ReturnedValue call(const Value *thisObject, const Value *argv, int argc, + ExecutionContext *context); const char *codeData; diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index d3bafbe055..779d975cba 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -161,7 +161,7 @@ void FunctionObject::createDefaultPrototypeProperty(uint protoConstructorSlot) defineDefaultProperty(s.engine->id_prototype(), proto, Attr_NotEnumerable|Attr_NotConfigurable); } -void FunctionObject::call(const Value *thisObject, void **a, const QMetaType *types, int argc) +void FunctionObject::call(QObject *thisObject, void **a, const QMetaType *types, int argc) { if (const auto callWithMetaTypes = d()->jsCallWithMetaTypes) { callWithMetaTypes(this, thisObject, a, types, argc); @@ -185,7 +185,7 @@ ReturnedValue FunctionObject::virtualCall(const FunctionObject *, const Value *, } void FunctionObject::virtualCallWithMetaTypes( - const FunctionObject *, const Value *, void **, const QMetaType *, int) + const FunctionObject *, QObject *, void **, const QMetaType *, int) { } @@ -532,7 +532,7 @@ ReturnedValue ScriptFunction::virtualCallAsConstructor(const FunctionObject *fo, DEFINE_OBJECT_VTABLE(ArrowFunction); -void ArrowFunction::virtualCallWithMetaTypes(const FunctionObject *fo, const Value *thisObject, +void ArrowFunction::virtualCallWithMetaTypes(const FunctionObject *fo, QObject *thisObject, void **a, const QMetaType *types, int argc) { if (!fo->function()->aotFunction) { @@ -543,16 +543,13 @@ void ArrowFunction::virtualCallWithMetaTypes(const FunctionObject *fo, const Val return; } - ExecutionEngine *engine = fo->engine(); + QV4::Scope scope(fo->engine()); + QV4::Scoped<ExecutionContext> context(scope, fo->scope()); MetaTypesStackFrame frame; - frame.init(fo->function(), a, types, argc); - frame.setupJSFrame(engine->jsStackTop, *fo, fo->scope(), - thisObject ? *thisObject : Value::undefinedValue()); - - frame.push(engine); - engine->jsStackTop += frame.requiredJSStackFrameSize(); - Moth::VME::exec(&frame, engine); - frame.pop(engine); + frame.init(fo->function(), thisObject, context, a, types, argc); + frame.push(scope.engine); + Moth::VME::exec(&frame, scope.engine); + frame.pop(scope.engine); } ReturnedValue ArrowFunction::virtualCall(const FunctionObject *fo, const Value *thisObject, const Value *argv, int argc) @@ -560,7 +557,7 @@ ReturnedValue ArrowFunction::virtualCall(const FunctionObject *fo, const Value * if (const auto *aotFunction = fo->function()->aotFunction) { return QV4::convertAndCall( fo->engine(), aotFunction, thisObject, argv, argc, - [fo](const Value *thisObject, void **a, const QMetaType *types, int argc) { + [fo](QObject *thisObject, void **a, const QMetaType *types, int argc) { ArrowFunction::virtualCallWithMetaTypes(fo, thisObject, a, types, argc); }); } diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 741519389e..f831b569b9 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -205,8 +205,8 @@ struct Q_QML_EXPORT FunctionObject: Object { return d()->jsCall(this, thisObject, argv, argc); } static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); - void call(const Value *thisObject, void **a, const QMetaType *types, int argc); - static void virtualCallWithMetaTypes(const FunctionObject *f, const Value *thisObject, + void call(QObject *thisObject, void **a, const QMetaType *types, int argc); + static void virtualCallWithMetaTypes(const FunctionObject *f, QObject *thisObject, void **a, const QMetaType *types, int argc); static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function); @@ -283,7 +283,7 @@ struct ArrowFunction : FunctionObject { V4_INTERNALCLASS(ArrowFunction) enum { NInlineProperties = 3 }; - static void virtualCallWithMetaTypes(const FunctionObject *f, const Value *thisObject, + static void virtualCallWithMetaTypes(const FunctionObject *f, QObject *thisObject, void **a, const QMetaType *types, int argc); static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); }; diff --git a/src/qml/jsruntime/qv4generatorobject.cpp b/src/qml/jsruntime/qv4generatorobject.cpp index d13b0e1ce1..0319e263e1 100644 --- a/src/qml/jsruntime/qv4generatorobject.cpp +++ b/src/qml/jsruntime/qv4generatorobject.cpp @@ -104,7 +104,8 @@ ReturnedValue GeneratorFunction::virtualCall(const FunctionObject *f, const Valu // We need to set up a separate JSFrame for the generator, as it's being re-entered Heap::GeneratorObject *gp = g->d(); gp->values.set(engine, engine->newArrayObject(argc)); - gp->jsFrame.set(engine, engine->newArrayObject(CppStackFrame::requiredJSStackFrameSize(function))); + gp->jsFrame.set(engine, engine->newArrayObject( + JSTypesStackFrame::requiredJSStackFrameSize(function))); // copy original arguments for (int i = 0; i < argc; i++) diff --git a/src/qml/jsruntime/qv4jscall_p.h b/src/qml/jsruntime/qv4jscall_p.h index c6d320ac20..337b86dbc0 100644 --- a/src/qml/jsruntime/qv4jscall_p.h +++ b/src/qml/jsruntime/qv4jscall_p.h @@ -56,6 +56,7 @@ #include "qv4context_p.h" #include "qv4scopedvalue_p.h" #include "qv4stackframe_p.h" +#include "qv4qobjectwrapper_p.h" #include <private/qv4alloca_p.h> QT_BEGIN_NAMESPACE @@ -134,27 +135,24 @@ ReturnedValue FunctionObject::call(const JSCallData &data) const void populateJSCallArguments(ExecutionEngine *v4, JSCallArguments &jsCall, int argc, void **args, const QMetaType *types); -struct ScopedStackFrame { - Scope &scope; - CppStackFrame frame; - - ScopedStackFrame(Scope &scope, Heap::ExecutionContext *context) - : scope(scope) +struct ScopedStackFrame +{ + ScopedStackFrame(const Scope &scope, ExecutionContext *context) + : engine(scope.engine) { - frame.setParentFrame(scope.engine->currentStackFrame); - if (!context) - return; - frame.jsFrame = reinterpret_cast<CallData *>(scope.alloc(sizeof(CallData)/sizeof(Value))); - frame.jsFrame->context = context; - if (auto *parent = frame.parentFrame()) - frame.v4Function = parent->v4Function; - else - frame.v4Function = nullptr; - scope.engine->currentStackFrame = &frame; + frame.init(engine->currentStackFrame ? engine->currentStackFrame->v4Function : nullptr, + nullptr, context, nullptr, nullptr, 0); + frame.push(engine); } - ~ScopedStackFrame() { - scope.engine->currentStackFrame = frame.parentFrame(); + + ~ScopedStackFrame() + { + frame.pop(engine); } + +private: + ExecutionEngine *engine = nullptr; + MetaTypesStackFrame frame; }; template<typename Callable> @@ -189,7 +187,10 @@ ReturnedValue convertAndCall( values[0] = nullptr; } - call(thisObject, values, types, argc); + if (const QV4::QObjectWrapper *cppThisObject = thisObject->as<QV4::QObjectWrapper>()) + call(cppThisObject->object(), values, types, argc); + else + call(nullptr, values, types, argc); ReturnedValue result; if (values[0]) { @@ -206,7 +207,7 @@ ReturnedValue convertAndCall( } template<typename Callable> -bool convertAndCall(ExecutionEngine *engine, const Value *thisObject, +bool convertAndCall(ExecutionEngine *engine, QObject *thisObject, void **a, const QMetaType *types, int argc, Callable call) { Scope scope(engine); @@ -215,7 +216,17 @@ bool convertAndCall(ExecutionEngine *engine, const Value *thisObject, for (int ii = 0; ii < argc; ++ii) jsCallData.args[ii] = engine->metaTypeToJS(types[ii + 1], a[ii + 1]); - ScopedValue jsResult(scope, call(thisObject, jsCallData.args, argc)); + ScopedObject jsThisObject(scope); + if (thisObject) { + // The result of wrap() can only be null, undefined, or an object. + jsThisObject = QV4::QObjectWrapper::wrap(engine, thisObject); + if (!jsThisObject) + jsThisObject = engine->globalObject; + } else { + jsThisObject = engine->globalObject; + } + + ScopedValue jsResult(scope, call(jsThisObject, jsCallData.args, argc)); void *result = a[0]; if (!result) return !jsResult->isUndefined(); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 01a7878dae..a168b0e580 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -320,7 +320,7 @@ ReturnedValue Runtime::Closure::call(ExecutionEngine *engine, int functionId) QV4::Function *clos = engine->currentStackFrame->v4Function->executableCompilationUnit() ->runtimeFunctions[functionId]; Q_ASSERT(clos); - ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context); + ExecutionContext *current = engine->currentContext(); if (clos->isGenerator()) return GeneratorFunction::create(current, clos)->asReturnedValue(); return FunctionObject::createScriptFunction(current, clos)->asReturnedValue(); @@ -355,7 +355,7 @@ Bool Runtime::DeleteName_NoThrow::call(ExecutionEngine *engine, int nameIndex) { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); - return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).deleteProperty(name); + return engine->currentContext()->deleteProperty(name); } ReturnedValue Runtime::DeleteName::call(ExecutionEngine *engine, Function *function, int name) @@ -1001,7 +1001,7 @@ void Runtime::StoreNameSloppy::call(ExecutionEngine *engine, int nameIndex, cons { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); - ExecutionContext::Error e = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).setProperty(name, value); + ExecutionContext::Error e = engine->currentContext()->setProperty(name, value); if (e == ExecutionContext::RangeError) engine->globalObject->put(name, value); @@ -1011,7 +1011,7 @@ void Runtime::StoreNameStrict::call(ExecutionEngine *engine, int nameIndex, cons { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); - ExecutionContext::Error e = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).setProperty(name, value); + ExecutionContext::Error e = engine->currentContext()->setProperty(name, value); if (e == ExecutionContext::TypeError) engine->throwTypeError(); else if (e == ExecutionContext::RangeError) @@ -1042,21 +1042,38 @@ ReturnedValue Runtime::LoadName::call(ExecutionEngine *engine, int nameIndex) { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); - return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name); + return engine->currentContext()->getProperty(name); } static Object *getSuperBase(Scope &scope) { - if (scope.engine->currentStackFrame->jsFrame->thisObject.isEmpty()) { - scope.engine->throwReferenceError(QStringLiteral("Missing call to super()."), QString(), 0, 0); - return nullptr; + ScopedFunctionObject f(scope); + ScopedObject homeObject(scope); + if (scope.engine->currentStackFrame->isJSTypesFrame()) { + JSTypesStackFrame *frame = static_cast<JSTypesStackFrame *>( + scope.engine->currentStackFrame); + + if (frame->jsFrame->thisObject.isEmpty()) { + scope.engine->throwReferenceError( + QStringLiteral("Missing call to super()."), QString(), 0, 0); + return nullptr; + } + + f = Value::fromStaticValue(frame->jsFrame->function); + homeObject = f->getHomeObject(); + } else { + Q_ASSERT(scope.engine->currentStackFrame->isMetaTypesFrame()); + MetaTypesStackFrame *frame = static_cast<MetaTypesStackFrame *>( + scope.engine->currentStackFrame); + if (frame->thisObject() == nullptr) { + scope.engine->throwReferenceError( + QStringLiteral("Missing call to super()."), QString(), 0, 0); + return nullptr; + } } - ScopedFunctionObject f( - scope, Value::fromStaticValue(scope.engine->currentStackFrame->jsFrame->function)); - ScopedObject homeObject(scope, f->getHomeObject()); if (!homeObject) { - ScopedContext ctx(scope, static_cast<ExecutionContext *>(&scope.engine->currentStackFrame->jsFrame->context)); + ScopedContext ctx(scope, scope.engine->currentContext()); Q_ASSERT(ctx); while (ctx) { if (CallContext *c = ctx->asCallContext()) { @@ -1067,7 +1084,8 @@ static Object *getSuperBase(Scope &scope) } ctx = ctx->d()->outer; } - homeObject = f->getHomeObject(); + if (f) + homeObject = f->getHomeObject(); } if (!homeObject) { scope.engine->throwTypeError(); @@ -1091,8 +1109,18 @@ ReturnedValue Runtime::LoadSuperProperty::call(ExecutionEngine *engine, const Va ScopedPropertyKey key(scope, property.toPropertyKey(engine)); if (engine->hasException) return Encode::undefined(); - return base->get( - key, &(engine->currentStackFrame->jsFrame->thisObject.asValue<Value>())); + + if (scope.engine->currentStackFrame->isJSTypesFrame()) { + JSTypesStackFrame *frame = static_cast<JSTypesStackFrame *>( + scope.engine->currentStackFrame); + return base->get(key, &(frame->jsFrame->thisObject.asValue<Value>())); + } else { + Q_ASSERT(scope.engine->currentStackFrame->isMetaTypesFrame()); + MetaTypesStackFrame *frame = static_cast<MetaTypesStackFrame *>( + scope.engine->currentStackFrame); + Scoped<QObjectWrapper> wrapper(scope, QObjectWrapper::wrap(engine, frame->thisObject())); + return base->get(key, wrapper); + } } void Runtime::StoreSuperProperty::call(ExecutionEngine *engine, const Value &property, const Value &value) @@ -1104,8 +1132,20 @@ void Runtime::StoreSuperProperty::call(ExecutionEngine *engine, const Value &pro ScopedPropertyKey key(scope, property.toPropertyKey(engine)); if (engine->hasException) return; - bool result = base->put( - key, value, &(engine->currentStackFrame->jsFrame->thisObject.asValue<Value>())); + + bool result; + if (scope.engine->currentStackFrame->isJSTypesFrame()) { + JSTypesStackFrame *frame = static_cast<JSTypesStackFrame *>( + scope.engine->currentStackFrame); + result = base->put(key, value, &(frame->jsFrame->thisObject.asValue<Value>())); + } else { + Q_ASSERT(scope.engine->currentStackFrame->isMetaTypesFrame()); + MetaTypesStackFrame *frame = static_cast<MetaTypesStackFrame *>( + scope.engine->currentStackFrame); + Scoped<QObjectWrapper> wrapper(scope, QObjectWrapper::wrap(engine, frame->thisObject())); + result = base->put(key, value, wrapper); + } + if (!result && engine->currentStackFrame->v4Function->isStrict()) engine->throwTypeError(); } @@ -1145,9 +1185,23 @@ void Runtime::SetLookupStrict::call(Function *f, const Value &base, int index, c ReturnedValue Runtime::LoadSuperConstructor::call(ExecutionEngine *engine, const Value &t) { - if (engine->currentStackFrame->thisObject() != Value::emptyValue().asReturnedValue()) { - return engine->throwReferenceError(QStringLiteral("super() already called."), QString(), 0, 0); // ### fix line number + if (engine->currentStackFrame->isJSTypesFrame()) { + JSTypesStackFrame *frame = static_cast<JSTypesStackFrame *>(engine->currentStackFrame); + if (frame->thisObject() != Value::emptyValue().asReturnedValue()) { + // ### TODO: fix line number + return engine->throwReferenceError( + QStringLiteral("super() already called."), QString(), 0, 0); + } + } else { + Q_ASSERT(engine->currentStackFrame->isMetaTypesFrame()); + MetaTypesStackFrame *frame = static_cast<MetaTypesStackFrame *>(engine->currentStackFrame); + if (frame->thisObject() != nullptr) { + // ### TODO: fix line number + return engine->throwReferenceError( + QStringLiteral("super() already called."), QString(), 0, 0); + } } + const FunctionObject *f = t.as<FunctionObject>(); if (!f) return engine->throwTypeError(); @@ -1386,8 +1440,8 @@ ReturnedValue Runtime::CallPossiblyDirectEval::call(ExecutionEngine *engine, Val Scope scope(engine); ScopedValue thisObject(scope); - ExecutionContext &ctx = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context); - ScopedFunctionObject function(scope, ctx.getPropertyAndBase(engine->id_eval(), thisObject)); + ScopedFunctionObject function( + scope, engine->currentContext()->getPropertyAndBase(engine->id_eval(), thisObject)); if (engine->hasException) return Encode::undefined(); @@ -1406,8 +1460,7 @@ ReturnedValue Runtime::CallName::call(ExecutionEngine *engine, int nameIndex, Va ScopedValue thisObject(scope); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); - ExecutionContext &ctx = static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context); - ScopedFunctionObject f(scope, ctx.getPropertyAndBase(name, thisObject)); + ScopedFunctionObject f(scope, engine->currentContext()->getPropertyAndBase(name, thisObject)); if (engine->hasException) return Encode::undefined(); @@ -1659,7 +1712,7 @@ QV4::ReturnedValue Runtime::TypeofName::call(ExecutionEngine *engine, int nameIn { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); - ScopedValue prop(scope, static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name)); + ScopedValue prop(scope, engine->currentContext()->getProperty(name)); // typeof doesn't throw. clear any possible exception scope.engine->hasException = false; return TypeofValue::call(engine, prop); @@ -1672,7 +1725,8 @@ void Runtime::PushCallContext::call(JSTypesStackFrame *frame) ReturnedValue Runtime::PushWithContext::call(ExecutionEngine *engine, const Value &acc) { - CallData *jsFrame = engine->currentStackFrame->jsFrame; + Q_ASSERT(engine->currentStackFrame->isJSTypesFrame()); + CallData *jsFrame = static_cast<JSTypesStackFrame *>(engine->currentStackFrame)->jsFrame; Value &newAcc = jsFrame->accumulator.asValue<Value>(); newAcc = Value::fromHeapObject(acc.toObject(engine)); if (!engine->hasException) { @@ -1687,18 +1741,23 @@ ReturnedValue Runtime::PushWithContext::call(ExecutionEngine *engine, const Valu void Runtime::PushCatchContext::call(ExecutionEngine *engine, int blockIndex, int exceptionVarNameIndex) { + Q_ASSERT(engine->currentStackFrame->isJSTypesFrame()); auto name = engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[exceptionVarNameIndex]; - engine->currentStackFrame->jsFrame->context = ExecutionContext::newCatchContext(engine->currentStackFrame, blockIndex, name)->asReturnedValue(); + static_cast<JSTypesStackFrame *>(engine->currentStackFrame)->jsFrame->context + = ExecutionContext::newCatchContext(engine->currentStackFrame, blockIndex, name)->asReturnedValue(); } void Runtime::PushBlockContext::call(ExecutionEngine *engine, int index) { - engine->currentStackFrame->jsFrame->context = ExecutionContext::newBlockContext(engine->currentStackFrame, index)->asReturnedValue(); + Q_ASSERT(engine->currentStackFrame->isJSTypesFrame()); + static_cast<JSTypesStackFrame *>(engine->currentStackFrame)->jsFrame->context + = ExecutionContext::newBlockContext(engine->currentStackFrame, index)->asReturnedValue(); } void Runtime::CloneBlockContext::call(ExecutionEngine *engine) { - auto frame = engine->currentStackFrame; + Q_ASSERT(engine->currentStackFrame->isJSTypesFrame()); + auto frame = static_cast<JSTypesStackFrame *>(engine->currentStackFrame); auto context = static_cast<Heap::CallContext *>( Value::fromStaticValue(frame->jsFrame->context).m()); frame->jsFrame->context = @@ -1707,18 +1766,20 @@ void Runtime::CloneBlockContext::call(ExecutionEngine *engine) void Runtime::PushScriptContext::call(ExecutionEngine *engine, int index) { + Q_ASSERT(engine->currentStackFrame->isJSTypesFrame()); Q_ASSERT(engine->currentStackFrame->context()->d()->type == Heap::ExecutionContext::Type_GlobalContext || engine->currentStackFrame->context()->d()->type == Heap::ExecutionContext::Type_QmlContext); ReturnedValue c = ExecutionContext::newBlockContext(engine->currentStackFrame, index)->asReturnedValue(); engine->setScriptContext(c); - engine->currentStackFrame->jsFrame->context = c; + static_cast<JSTypesStackFrame *>(engine->currentStackFrame)->jsFrame->context = c; } void Runtime::PopScriptContext::call(ExecutionEngine *engine) { + Q_ASSERT(engine->currentStackFrame->isJSTypesFrame()); ReturnedValue root = engine->rootContext()->asReturnedValue(); engine->setScriptContext(root); - engine->currentStackFrame->jsFrame->context = root; + static_cast<JSTypesStackFrame *>(engine->currentStackFrame)->jsFrame->context = root; } void Runtime::ThrowReferenceError::call(ExecutionEngine *engine, int nameIndex) @@ -1750,7 +1811,7 @@ void Runtime::DeclareVar::call(ExecutionEngine *engine, Bool deletable, int name { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); - static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).createMutableBinding(name, deletable); + engine->currentContext()->createMutableBinding(name, deletable); } ReturnedValue Runtime::ArrayLiteral::call(ExecutionEngine *engine, Value *values, uint length) @@ -1803,7 +1864,7 @@ ReturnedValue Runtime::ObjectLiteral::call(ExecutionEngine *engine, int classId, arg = ObjectLiteralArgument::Value; fnName = name->asFunctionName(engine, prefix); - ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context); + ExecutionContext *current = engine->currentContext(); if (clos->isGenerator()) value = MemberGeneratorFunction::create(current, clos, o, fnName)->asReturnedValue(); else @@ -1861,7 +1922,7 @@ ReturnedValue Runtime::CreateClass::call(ExecutionEngine *engine, int classIndex ScopedObject proto(scope, engine->newObject()); proto->setPrototypeUnchecked(protoParent); - ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context); + ExecutionContext *current = engine->currentContext(); ScopedFunctionObject constructor(scope); QV4::Function *f = cls->constructorFunction != UINT_MAX ? unit->runtimeFunctions[cls->constructorFunction] : nullptr; diff --git a/src/qml/jsruntime/qv4stackframe.cpp b/src/qml/jsruntime/qv4stackframe.cpp index a716c53aea..e99dda591f 100644 --- a/src/qml/jsruntime/qv4stackframe.cpp +++ b/src/qml/jsruntime/qv4stackframe.cpp @@ -36,7 +36,9 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ + #include "qv4stackframe_p.h" +#include <private/qv4qobjectwrapper_p.h> #include <QtCore/qstring.h> using namespace QV4; @@ -68,7 +70,12 @@ int CppStackFrame::lineNumber() const return line->line; } -ReturnedValue CppStackFrame::thisObject() const { - return jsFrame->thisObject.asReturnedValue(); -} +ReturnedValue QV4::CppStackFrame::thisObject() const +{ + if (isJSTypesFrame()) + return static_cast<const JSTypesStackFrame *>(this)->thisObject(); + Q_ASSERT(isMetaTypesFrame()); + const auto metaTypesFrame = static_cast<const MetaTypesStackFrame *>(this); + return QObjectWrapper::wrap(metaTypesFrame->context()->engine(), metaTypesFrame->thisObject()); +} diff --git a/src/qml/jsruntime/qv4stackframe_p.h b/src/qml/jsruntime/qv4stackframe_p.h index ebe3b762af..1439e9f677 100644 --- a/src/qml/jsruntime/qv4stackframe_p.h +++ b/src/qml/jsruntime/qv4stackframe_p.h @@ -64,17 +64,17 @@ namespace QV4 { struct CppStackFrame; struct Q_QML_PRIVATE_EXPORT CppStackFrameBase { - enum class Kind : quint8 { Bare, JS, Meta }; + enum class Kind : quint8 { JS, Meta }; - Value *savedStackTop; CppStackFrame *parent; Function *v4Function; - CallData *jsFrame; int originalArgumentsCount; int instructionPointer; union { struct { + Value *savedStackTop; + CallData *jsFrame; const Value *originalArguments; const char *yield; const char *unwindHandler; @@ -86,6 +86,8 @@ struct Q_QML_PRIVATE_EXPORT CppStackFrameBase bool isTailCalling; }; struct { + ExecutionContext *context; + QObject *thisObject; const QMetaType *metaTypes; void **returnAndArgs; }; @@ -100,88 +102,67 @@ struct Q_QML_PRIVATE_EXPORT CppStackFrame : protected CppStackFrameBase // non-standard layout. So we have this other struct with "using" in between. using CppStackFrameBase::instructionPointer; using CppStackFrameBase::v4Function; - using CppStackFrameBase::jsFrame; - void init(Function *v4Function, int argc, Kind kind = Kind::Bare) { + void init(Function *v4Function, int argc, Kind kind) { this->v4Function = v4Function; originalArgumentsCount = argc; instructionPointer = 0; this->kind = kind; } - bool isBareStackFrame() const { return kind == Kind::Bare; } bool isJSTypesFrame() const { return kind == Kind::JS; } bool isMetaTypesFrame() const { return kind == Kind::Meta; } - static uint requiredJSStackFrameSize(uint nRegisters) { - return CallData::HeaderSize() + nRegisters; - } - static uint requiredJSStackFrameSize(Function *v4Function) { - return CallData::HeaderSize() + v4Function->compiledFunction->nRegisters; - } - uint requiredJSStackFrameSize() const { - return requiredJSStackFrameSize(v4Function); - } - - void setupJSFrame(Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope, - const Value &thisObject, const Value &newTarget = Value::undefinedValue()) - { - jsFrame = reinterpret_cast<CallData *>(stackSpace); - jsFrame->function = function; - jsFrame->context = scope->asReturnedValue(); - jsFrame->accumulator = Encode::undefined(); - jsFrame->thisObject = thisObject; - jsFrame->newTarget = newTarget; - } - QString source() const; QString function() const; int lineNumber() const; + + CppStackFrame *parentFrame() const { return parent; } + void setParentFrame(CppStackFrame *parentFrame) { parent = parentFrame; } + + int argc() const { return originalArgumentsCount; } + + inline ExecutionContext *context() const; + + Heap::CallContext *callContext() const { return callContext(context()->d()); } ReturnedValue thisObject() const; - ExecutionContext *context() const +protected: + CppStackFrame() = default; + + void push(EngineBase *engine) { - return static_cast<ExecutionContext *>(&jsFrame->context); + Q_ASSERT(kind == Kind::JS || kind == Kind::Meta); + parent = engine->currentStackFrame; + engine->currentStackFrame = this; } - void setContext(ExecutionContext *context) + void pop(EngineBase *engine) { - jsFrame->context = context; + engine->currentStackFrame = parent; } - Heap::CallContext *callContext() const + Heap::CallContext *callContext(Heap::ExecutionContext *ctx) const { - Heap::ExecutionContext *ctx = static_cast<ExecutionContext &>(jsFrame->context).d();\ while (ctx->type != Heap::ExecutionContext::Type_CallContext) ctx = ctx->outer; return static_cast<Heap::CallContext *>(ctx); } - - CppStackFrame *parentFrame() const { return parent; } - void setParentFrame(CppStackFrame *parentFrame) { parent = parentFrame; } - - int argc() const { return originalArgumentsCount; } - Value *framePointer() const { return savedStackTop; } - - void push(EngineBase *engine) { - parent = engine->currentStackFrame; - engine->currentStackFrame = this; - savedStackTop = engine->jsStackTop; - } - - void pop(EngineBase *engine) { - engine->currentStackFrame = parent; - engine->jsStackTop = savedStackTop; - } }; struct Q_QML_PRIVATE_EXPORT MetaTypesStackFrame : public CppStackFrame { - void init(Function *v4Function, void **a, const QMetaType *types, int argc) + using CppStackFrame::push; + using CppStackFrame::pop; + + void init(Function *v4Function, QObject *thisObject, ExecutionContext *context, + void **returnAndArgs, const QMetaType *metaTypes, int argc) { CppStackFrame::init(v4Function, argc, Kind::Meta); - metaTypes = types; - returnAndArgs = a; + CppStackFrameBase::thisObject = thisObject; + CppStackFrameBase::context = context; + CppStackFrameBase::metaTypes = metaTypes; + CppStackFrameBase::returnAndArgs = returnAndArgs; } QMetaType returnType() const { return metaTypes[0]; } @@ -189,10 +170,22 @@ struct Q_QML_PRIVATE_EXPORT MetaTypesStackFrame : public CppStackFrame const QMetaType *argTypes() const { return metaTypes + 1; } void **argv() const { return returnAndArgs + 1; } + + QObject *thisObject() const { return CppStackFrameBase::thisObject; } + + ExecutionContext *context() const { return CppStackFrameBase::context; } + void setContext(ExecutionContext *context) { CppStackFrameBase::context = context; } + + Heap::CallContext *callContext() const + { + return CppStackFrame::callContext(CppStackFrameBase::context->d()); + } }; struct Q_QML_PRIVATE_EXPORT JSTypesStackFrame : public CppStackFrame { + using CppStackFrame::jsFrame; + // The JIT needs to poke directly into those using offsetof using CppStackFrame::unwindHandler; using CppStackFrame::unwindLabel; @@ -215,6 +208,16 @@ struct Q_QML_PRIVATE_EXPORT JSTypesStackFrame : public CppStackFrame const Value *argv() const { return originalArguments; } + static uint requiredJSStackFrameSize(uint nRegisters) { + return CallData::HeaderSize() + nRegisters; + } + static uint requiredJSStackFrameSize(Function *v4Function) { + return CallData::HeaderSize() + v4Function->compiledFunction->nRegisters; + } + uint requiredJSStackFrameSize() const { + return requiredJSStackFrameSize(v4Function); + } + void setupJSFrame(Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope, const Value &thisObject, const Value &newTarget = Value::undefinedValue()) { setupJSFrame(stackSpace, function, scope, thisObject, newTarget, @@ -226,7 +229,12 @@ struct Q_QML_PRIVATE_EXPORT JSTypesStackFrame : public CppStackFrame Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope, const Value &thisObject, const Value &newTarget, uint nFormals, uint nRegisters) { - CppStackFrame::setupJSFrame(stackSpace, function, scope, thisObject, newTarget); + jsFrame = reinterpret_cast<CallData *>(stackSpace); + jsFrame->function = function; + jsFrame->context = scope->asReturnedValue(); + jsFrame->accumulator = Encode::undefined(); + jsFrame->thisObject = thisObject; + jsFrame->newTarget = newTarget; uint argc = uint(originalArgumentsCount); if (argc > nFormals) @@ -251,6 +259,21 @@ struct Q_QML_PRIVATE_EXPORT JSTypesStackFrame : public CppStackFrame } } + ExecutionContext *context() const + { + return static_cast<ExecutionContext *>(&jsFrame->context); + } + + void setContext(ExecutionContext *context) + { + jsFrame->context = context; + } + + Heap::CallContext *callContext() const + { + return CppStackFrame::callContext(static_cast<ExecutionContext &>(jsFrame->context).d()); + } + bool isTailCalling() const { return CppStackFrame::isTailCalling; } void setTailCalling(bool tailCalling) { CppStackFrame::isTailCalling = tailCalling; } @@ -264,8 +287,34 @@ struct Q_QML_PRIVATE_EXPORT JSTypesStackFrame : public CppStackFrame void setYieldIsIterator(bool isIter) { CppStackFrame::yieldIsIterator = isIter; } bool callerCanHandleTailCall() const { return CppStackFrame::callerCanHandleTailCall; } + + ReturnedValue thisObject() const + { + return jsFrame->thisObject.asReturnedValue(); + } + + Value *framePointer() const { return savedStackTop; } + + void push(EngineBase *engine) { + CppStackFrame::push(engine); + savedStackTop = engine->jsStackTop; + } + + void pop(EngineBase *engine) { + CppStackFrame::pop(engine); + engine->jsStackTop = savedStackTop; + } }; +inline ExecutionContext *CppStackFrame::context() const +{ + if (isJSTypesFrame()) + return static_cast<const JSTypesStackFrame *>(this)->context(); + + Q_ASSERT(isMetaTypesFrame()); + return static_cast<const MetaTypesStackFrame *>(this)->context(); +} + Q_STATIC_ASSERT(sizeof(CppStackFrame) == sizeof(JSTypesStackFrame)); Q_STATIC_ASSERT(sizeof(CppStackFrame) == sizeof(MetaTypesStackFrame)); Q_STATIC_ASSERT(std::is_standard_layout_v<CppStackFrame>); diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 88bb309b7d..009cff067a 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -343,7 +343,7 @@ static struct InstrCount { } #endif -static inline QV4::Value &stackValue(QV4::Value *stack, size_t slot, const CppStackFrame *frame) +static inline QV4::Value &stackValue(QV4::Value *stack, size_t slot, const JSTypesStackFrame *frame) { Q_ASSERT(slot < CallData::HeaderSize() / sizeof(QV4::StaticValue) + frame->jsFrame->argc() diff --git a/src/qml/jsruntime/qv4vtable_p.h b/src/qml/jsruntime/qv4vtable_p.h index a71c9da691..ba44baae1a 100644 --- a/src/qml/jsruntime/qv4vtable_p.h +++ b/src/qml/jsruntime/qv4vtable_p.h @@ -54,6 +54,7 @@ QT_BEGIN_NAMESPACE +class QObject; namespace QV4 { struct Lookup; @@ -84,7 +85,7 @@ struct VTable typedef ReturnedValue (*InstanceOf)(const Object *typeObject, const Value &var); typedef ReturnedValue (*Call)(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); - typedef void (*CallWithMetaTypes)(const FunctionObject *, const Value *, void **, const QMetaType *, int); + typedef void (*CallWithMetaTypes)(const FunctionObject *, QObject *, void **, const QMetaType *, int); typedef ReturnedValue (*CallAsConstructor)(const FunctionObject *, const Value *argv, int argc, const Value *newTarget); typedef ReturnedValue (*ResolveLookupGetter)(const Object *, ExecutionEngine *, Lookup *); diff --git a/src/qml/qml/qqml.cpp b/src/qml/qml/qqml.cpp index 3a0f2b8b3e..d8bbc93129 100644 --- a/src/qml/qml/qqml.cpp +++ b/src/qml/qml/qqml.cpp @@ -940,7 +940,7 @@ bool AOTCompiledContext::callQmlContextPropertyLookup( return false; } - function->call(thisObject, args, types, argc); + function->call(nullptr, args, types, argc); return !scope.engine->hasException; } @@ -1022,7 +1022,7 @@ bool AOTCompiledContext::callObjectPropertyLookup( return false; } - function->call(thisObject, args, types, argc); + function->call(object, args, types, argc); return !scope.engine->hasException; } @@ -1046,8 +1046,7 @@ bool AOTCompiledContext::callGlobalLookup( return false; } - QV4::ScopedValue thisObject(scope, QV4::Encode::undefined()); - function->call(thisObject, args, types, argc); + function->call(nullptr, args, types, argc); return true; } diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 64698444ff..5a814b16c5 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1392,7 +1392,7 @@ void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV return; // js modules (mjs) have no qmlContext - QV4::ScopedStackFrame frame(scope, qmlContext ? qmlContext->d() : engine->scriptContext()->d()); + QV4::ScopedStackFrame frame(scope, qmlContext ? qmlContext : engine->scriptContext()); while (1) { name = it.nextPropertyNameAsString(val); diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 75bc944fee..9ab46953f1 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -249,17 +249,6 @@ private: QQmlPropertyCapture *lastPropertyCapture; }; -static inline QV4::ReturnedValue thisObject(QObject *scopeObject, QV4::ExecutionEngine *v4) -{ - if (scopeObject) { - // The result of wrap() can only be null, undefined, or an object. - const QV4::ReturnedValue scope = QV4::QObjectWrapper::wrap(v4, scopeObject); - if (QV4::Value::fromReturnedValue(scope).isManaged()) - return scope; - } - return v4->globalObject->asReturnedValue(); -} - QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, bool *isUndefined) { QQmlEngine *qmlEngine = engine(); @@ -275,7 +264,14 @@ QV4::ReturnedValue QQmlJavaScriptExpression::evaluate(QV4::CallData *callData, b QQmlJavaScriptExpressionCapture capture(this, qmlEngine); QV4::Scope scope(qmlEngine->handle()); - callData->thisObject = thisObject(scopeObject(), scope.engine); + + if (QObject *thisObject = scopeObject()) { + callData->thisObject = QV4::QObjectWrapper::wrap(scope.engine, thisObject); + if (callData->thisObject.isNullOrUndefined()) + callData->thisObject = scope.engine->globalObject; + } else { + callData->thisObject = scope.engine->globalObject; + } Q_ASSERT(m_qmlScope.valueRef()); QV4::ScopedValue result(scope, v4Function->call( @@ -307,12 +303,12 @@ bool QQmlJavaScriptExpression::evaluate(void **a, const QMetaType *types, int ar QQmlJavaScriptExpressionCapture capture(this, qmlEngine); QV4::Scope scope(qmlEngine->handle()); - QV4::ScopedValue self(scope, thisObject(scopeObject(), scope.engine)); Q_ASSERT(m_qmlScope.valueRef()); Q_ASSERT(function()); const bool isUndefined = !function()->call( - self, a, types, argc, static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef())); + scopeObject(), a, types, argc, + static_cast<QV4::ExecutionContext *>(m_qmlScope.valueRef())); return !capture.catchException(scope) && !isUndefined; } diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index f7c9fbbbfb..f591f209b5 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -1012,13 +1012,13 @@ int QQmlVMEMetaObject::metaCall(QObject *o, QMetaObject::Call c, int _id, void * Q_ASSERT(parameterCount == function->formalParameterCount()); if (void *result = a[0]) arguments->types[0].destruct(result); - function->call(v4->globalObject, a, arguments->types, parameterCount); + function->call(nullptr, a, arguments->types, parameterCount); } else { Q_ASSERT(function->formalParameterCount() == 0); const QMetaType returnType = methodData->propType(); if (void *result = a[0]) returnType.destruct(result); - function->call(v4->globalObject, a, &returnType, 0); + function->call(nullptr, a, &returnType, 0); } if (scope.hasException()) { |