diff options
Diffstat (limited to 'src/qml/jsruntime/qv4vme_moth.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 243 |
1 files changed, 122 insertions, 121 deletions
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index f606f8152d..db17a7141c 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -1,41 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qv4vme_moth_p.h" @@ -60,6 +24,7 @@ #include <private/qv4alloca_p.h> #include <private/qqmljavascriptexpression_p.h> #include <private/qv4qmlcontext_p.h> +#include <QtQml/private/qv4runtime_p.h> #include <iostream> #if QT_CONFIG(qml_jit) @@ -70,6 +35,9 @@ #undef COUNT_INSTRUCTIONS +Q_TRACE_POINT(qtqml, QQmlV4_function_call_entry, const QV4::ExecutionEngine *engine, const QString &function, const QString &fileName, int line, int column) +Q_TRACE_POINT(qtqml, QQmlV4_function_call_exit) + enum { ShowWhenDeoptimiationHappens = 0 }; extern "C" { @@ -343,7 +311,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() @@ -360,7 +328,7 @@ static inline QV4::Value &stackValue(QV4::Value *stack, size_t slot, const CppSt #undef CHECK_EXCEPTION #endif #define CHECK_EXCEPTION \ - if (engine->hasException || engine->isInterrupted.loadAcquire()) \ + if (engine->hasException || engine->isInterrupted.loadRelaxed()) \ goto handleUnwind static inline Heap::CallContext *getScope(QV4::Value *stack, int level) @@ -382,20 +350,18 @@ static inline const QV4::Value &constant(Function *function, int index) static bool compareEqualInt(QV4::Value &accumulator, QV4::Value lhs, int rhs) { redo: - switch (lhs.quickType()) { - case QV4::Value::QT_ManagedOrUndefined: - if (lhs.isUndefined()) - return false; - Q_FALLTHROUGH(); - case QV4::Value::QT_ManagedOrUndefined1: - case QV4::Value::QT_ManagedOrUndefined2: - case QV4::Value::QT_ManagedOrUndefined3: + if (lhs.isUndefined()) + return false; + if (lhs.isManagedOrUndefined()) { // LHS: Managed if (lhs.m()->internalClass->vtable->isString) return RuntimeHelpers::stringToNumber(static_cast<String &>(lhs).toQString()) == rhs; accumulator = lhs; lhs = QV4::Value::fromReturnedValue(RuntimeHelpers::objectDefaultValue(&static_cast<QV4::Object &>(accumulator), PREFERREDTYPE_HINT)); goto redo; + } + + switch (lhs.quickType()) { case QV4::Value::QT_Empty: Q_UNREACHABLE(); case QV4::Value::QT_Null: @@ -429,7 +395,59 @@ static bool compareEqualInt(QV4::Value &accumulator, QV4::Value lhs, int rhs) } \ } while (false) -ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine) +struct AOTCompiledMetaMethod +{ +public: + AOTCompiledMetaMethod(const QQmlPrivate::AOTCompiledFunction *aotCompiledFunction) + : aotCompiledFunction(aotCompiledFunction) + {} + + int parameterCount() const { return aotCompiledFunction->argumentTypes.size(); } + QMetaType returnMetaType() const { return aotCompiledFunction->returnType; } + QMetaType parameterMetaType(int i) const { return aotCompiledFunction->argumentTypes[i]; } + +private: + const QQmlPrivate::AOTCompiledFunction *aotCompiledFunction = nullptr; +}; + +void VME::exec(MetaTypesStackFrame *frame, ExecutionEngine *engine) +{ + qt_v4ResolvePendingBreakpointsHook(); + if (engine->checkStackLimits()) { + frame->setReturnValueUndefined(); + return; + } + ExecutionEngineCallDepthRecorder executionEngineCallDepthRecorder(engine); + + Function *function = frame->v4Function; + Q_ASSERT(function->aotCompiledFunction); + Q_TRACE_SCOPE(QQmlV4_function_call, engine, function->name()->toQString(), + function->executableCompilationUnit()->fileName(), + function->compiledFunction->location.line(), + function->compiledFunction->location.column()); + Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling + + const AOTCompiledMetaMethod method(function->aotCompiledFunction); + QV4::coerceAndCall( + engine, &method, frame->returnAndArgValues(), + frame->returnAndArgTypes(), frame->argc(), + [frame, engine, function](void **argv, int argc) { + Q_UNUSED(argc); + + QQmlPrivate::AOTCompiledContext aotContext; + if (auto context = QV4::ExecutionEngine::qmlContext(frame->context()->d())) { + QV4::Heap::QQmlContextWrapper *wrapper = static_cast<Heap::QmlContext *>(context)->qml(); + aotContext.qmlScopeObject = wrapper->scopeObject; + aotContext.qmlContext = wrapper->context; + } + + aotContext.engine = engine->jsEngine(); + aotContext.compilationUnit = function->executableCompilationUnit(); + function->aotCompiledFunction->functionPtr(&aotContext, argv); + }); +} + +ReturnedValue VME::exec(JSTypesStackFrame *frame, ExecutionEngine *engine) { qt_v4ResolvePendingBreakpointsHook(); CHECK_STACK_LIMITS(engine); @@ -437,8 +455,8 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine) Function *function = frame->v4Function; Q_TRACE_SCOPE(QQmlV4_function_call, engine, function->name()->toQString(), function->executableCompilationUnit()->fileName(), - function->compiledFunction->location.line, - function->compiledFunction->location.column); + function->compiledFunction->location.line(), + function->compiledFunction->location.column()); Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling QV4::Debugging::Debugger *debugger = engine->debugger(); @@ -461,53 +479,9 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine) debugger->enteringFunction(); ReturnedValue result; + Q_ASSERT(function->kind != Function::AotCompiled); if (function->jittedCode != nullptr && debugger == nullptr) { result = function->jittedCode(frame, engine); - } else if (function->aotFunction) { - const qsizetype numFunctionArguments = function->aotFunction->argumentTypes.size(); - Q_ALLOCA_DECLARE(void *, argumentPtrs); - - if (numFunctionArguments > 0) { - Q_ALLOCA_ASSIGN(void *, argumentPtrs, numFunctionArguments * sizeof(void *)); - for (qsizetype i = 0; i < numFunctionArguments; ++i) { - const QMetaType argumentType = function->aotFunction->argumentTypes[i]; - if (const qsizetype argumentSize = argumentType.sizeOf()) { - Q_ALLOCA_VAR(void, argument, argumentSize); - argumentType.construct(argument); - if (i < frame->originalArgumentsCount) { - engine->metaTypeFromJS(frame->originalArguments[i], argumentType.id(), - argument); - } - argumentPtrs[i] = argument; - } else { - argumentPtrs[i] = nullptr; - } - } - } - - Q_ALLOCA_DECLARE(void, returnValue); - const QMetaType returnType = function->aotFunction->returnType; - if (const qsizetype returnSize = returnType.sizeOf()) - Q_ALLOCA_ASSIGN(void, returnValue, returnSize); - - Scope scope(engine); - Scoped<QmlContext> qmlContext(scope, engine->qmlContext()); - QQmlPrivate::AOTCompiledContext aotContext; - aotContext.qmlContext = qmlContext ? qmlContext->qmlContext()->asQQmlContext() : nullptr; - aotContext.qmlScopeObject = qmlContext ? qmlContext->qmlScope() : nullptr; - aotContext.engine = engine->jsEngine(); - aotContext.compilationUnit = function->executableCompilationUnit(); - function->aotFunction->functionPtr(&aotContext, returnValue, argumentPtrs); - - if (returnValue) { - result = engine->metaTypeToJS(returnType, returnValue); - returnType.destruct(returnValue); - } else { - result = Encode::undefined(); - } - - for (qsizetype i = 0; i < numFunctionArguments; ++i) - function->aotFunction->argumentTypes[i].destruct(argumentPtrs[i]); } else { // interpreter result = interpret(frame, engine, function->codeData); @@ -519,7 +493,7 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine) return result; } -QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, const char *code) +QV4::ReturnedValue VME::interpret(JSTypesStackFrame *frame, ExecutionEngine *engine, const char *code) { QV4::Function *function = frame->v4Function; QV4::Value &accumulator = frame->jsFrame->accumulator.asValue<Value>(); @@ -671,6 +645,18 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, CHECK_EXCEPTION; MOTH_END_INSTR(LoadProperty) + MOTH_BEGIN_INSTR(LoadOptionalProperty) + STORE_IP(); + STORE_ACC(); + if (accumulator.isNullOrUndefined()) { + acc = Encode::undefined(); + code += offset; + } else { + acc = Runtime::LoadProperty::call(engine, accumulator, name); + } + CHECK_EXCEPTION; + MOTH_END_INSTR(LoadOptionalProperty) + MOTH_BEGIN_INSTR(GetLookup) STORE_IP(); STORE_ACC(); @@ -689,6 +675,20 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, CHECK_EXCEPTION; MOTH_END_INSTR(GetLookup) + MOTH_BEGIN_INSTR(GetOptionalLookup) + STORE_IP(); + STORE_ACC(); + + QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index; + + if (accumulator.isNullOrUndefined()) { + code += offset; + } else { + acc = l->getter(l, engine, accumulator); + } + CHECK_EXCEPTION; + MOTH_END_INSTR(GetOptionalLookup) + MOTH_BEGIN_INSTR(StoreProperty) STORE_IP(); STORE_ACC(); @@ -719,14 +719,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_END_INSTR(StoreSuperProperty) MOTH_BEGIN_INSTR(Yield) - frame->yield = code; - frame->yieldIsIterator = false; + frame->setYield(code); + frame->setYieldIsIterator(false); return acc; MOTH_END_INSTR(Yield) MOTH_BEGIN_INSTR(YieldStar) - frame->yield = code; - frame->yieldIsIterator = true; + frame->setYield(code); + frame->setYieldIsIterator(true); return acc; MOTH_END_INSTR(YieldStar) @@ -746,7 +746,8 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(IteratorNextForYieldStar) STORE_ACC(); acc = Runtime::IteratorNextForYieldStar::call(engine, accumulator, STACK_VALUE(iterator), &STACK_VALUE(object)); - CHECK_EXCEPTION; + if (ACC.toBoolean()) + code += offset; MOTH_END_INSTR(IteratorNextForYieldStar) MOTH_BEGIN_INSTR(CallValue) @@ -793,24 +794,22 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, // ok to have the value on the stack here Value f = Value::fromReturnedValue(l->getter(l, engine, STACK_VALUE(base))); - if (Q_UNLIKELY(!f.isFunctionObject())) { - QString message = QStringLiteral("Property '%1' of object %2 is not a function") - .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString()) + if (Q_LIKELY(f.isFunctionObject())) { + acc = static_cast<FunctionObject &>(f).call(stack + base, stack + argv, argc); + } else if (QmlSignalHandler *handler = f.as<QmlSignalHandler>()) { + acc = handler->call(stack + base, stack + argv, argc); + } else { + const QString message = QStringLiteral("Property '%1' of object %2 is not a function") + .arg(engine->currentStackFrame->v4Function->compilationUnit + ->runtimeStrings[l->nameIndex]->toQString()) .arg(STACK_VALUE(base).toQStringNoThrow()); acc = engine->throwTypeError(message); goto handleUnwind; } - acc = static_cast<FunctionObject &>(f).call(stack + base, stack + argv, argc); CHECK_EXCEPTION; MOTH_END_INSTR(CallPropertyLookup) - MOTH_BEGIN_INSTR(CallElement) - STORE_IP(); - acc = Runtime::CallElement::call(engine, STACK_VALUE(base), STACK_VALUE(index), stack + argv, argc); - CHECK_EXCEPTION; - MOTH_END_INSTR(CallElement) - MOTH_BEGIN_INSTR(CallName) STORE_IP(); acc = Runtime::CallName::call(engine, name, stack + argv, argc); @@ -962,15 +961,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, STORE_IP(); STORE_ACC(); acc = Runtime::IteratorNext::call(engine, accumulator, &STACK_VALUE(value)); - STACK_VALUE(done) = acc; - CHECK_EXCEPTION; + if (ACC.toBoolean()) + code += offset; MOTH_END_INSTR(IteratorNext) MOTH_BEGIN_INSTR(IteratorClose) STORE_IP(); STORE_ACC(); - acc = Runtime::IteratorClose::call(engine, accumulator, STACK_VALUE(done)); - CHECK_EXCEPTION; + acc = Runtime::IteratorClose::call(engine, accumulator); MOTH_END_INSTR(IteratorClose) MOTH_BEGIN_INSTR(DestructureRestElement) @@ -1306,14 +1304,17 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, } MOTH_END_INSTR(Sub) + MOTH_BEGIN_INSTR(As) + const Value left = STACK_VALUE(lhs); + STORE_ACC(); + acc = Runtime::As::call(engine, left, accumulator); + MOTH_END_INSTR(As) + MOTH_BEGIN_INSTR(Exp) const Value left = STACK_VALUE(lhs); double base = left.toNumber(); double exp = ACC.toNumber(); - if (qIsInf(exp) && (base == 1 || base == -1)) - acc = Encode(qQNaN()); - else - acc = Encode(pow(base,exp)); + acc = Encode(QQmlPrivate::jsExponentiate(base, exp)); MOTH_END_INSTR(Exp) MOTH_BEGIN_INSTR(Mul) @@ -1439,7 +1440,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, // We do start the exception handler in case of isInterrupted. The exception handler will // immediately abort, due to the same isInterrupted. We don't skip the exception handler // because the current behavior is easier to implement in the JIT. - Q_ASSERT(engine->hasException || engine->isInterrupted.loadAcquire() || frame->unwindLevel); + Q_ASSERT(engine->hasException || engine->isInterrupted.loadRelaxed() || frame->unwindLevel); if (!frame->unwindHandler) { acc = Encode::undefined(); return acc; |