diff options
Diffstat (limited to 'src/qml/jsruntime/qv4vme_moth.cpp')
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 243 |
1 files changed, 153 insertions, 90 deletions
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 27d518f5c6..096b9a6299 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -1,47 +1,12 @@ -/**************************************************************************** -** -** 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" #include <QtCore/qjsondocument.h> #include <QtCore/qjsonobject.h> +#include <private/qv4alloca_p.h> #include <private/qv4instr_moth_p.h> #include <private/qv4value_p.h> #include <private/qv4debugging_p.h> @@ -58,6 +23,8 @@ #include <private/qv4generatorobject_p.h> #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) @@ -68,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" { @@ -341,14 +311,24 @@ static struct InstrCount { } #endif -#define STACK_VALUE(temp) stack[temp] +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() + + frame->v4Function->compiledFunction->nRegisters); + Q_UNUSED(frame); + + return stack[slot]; +} + +#define STACK_VALUE(temp) stackValue(stack, temp, frame) // qv4scopedvalue_p.h also defines a CHECK_EXCEPTION macro #ifdef CHECK_EXCEPTION #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) @@ -364,26 +344,24 @@ static inline Heap::CallContext *getScope(QV4::Value *stack, int level) static inline const QV4::Value &constant(Function *function, int index) { - return function->compilationUnit->constants[index].asValue<Value>(); + return function->compilationUnit->constants[index].asValue<QV4::Value>(); } 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: @@ -413,26 +391,81 @@ static bool compareEqualInt(QV4::Value &accumulator, QV4::Value lhs, int rhs) d = val.toNumberImpl(); \ CHECK_EXCEPTION; \ } \ - i = Double::toInt32(d); \ + i = QJSNumberCoercion::toInteger(d); \ } \ } while (false) -ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine) +struct AOTCompiledMetaMethod +{ +public: + AOTCompiledMetaMethod(const Function::AOTCompiledFunction *aotCompiledFunction) + : aotCompiledFunction(aotCompiledFunction) + {} + + int parameterCount() const { return aotCompiledFunction->types.size() - 1; } + QMetaType returnMetaType() const { return aotCompiledFunction->types[0]; } + QMetaType parameterMetaType(int i) const { return aotCompiledFunction->types[i + 1]; } + +private: + const Function::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->aotCompiledCode); + 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->aotCompiledCode(&aotContext, argv); + }); +} + +ReturnedValue VME::exec(JSTypesStackFrame *frame, ExecutionEngine *engine) { qt_v4ResolvePendingBreakpointsHook(); CHECK_STACK_LIMITS(engine); Function *function = frame->v4Function; Q_TRACE_SCOPE(QQmlV4_function_call, engine, function->name()->toQString(), - function->compilationUnit->fileName(), - function->compiledFunction->location.line, - function->compiledFunction->location.column); + function->executableCompilationUnit()->fileName(), + function->compiledFunction->location.line(), + function->compiledFunction->location.column()); Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling QV4::Debugging::Debugger *debugger = engine->debugger(); #if QT_CONFIG(qml_jit) if (debugger == nullptr) { - if (function->jittedCode == nullptr) { + // Check for codeRef here. In rare cases the JIT compilation may fail, which leaves us + // with a (useless) codeRef, but no jittedCode. In that case, don't try to JIT again every + // time we execute the function, but just interpret instead. + if (function->codeRef == nullptr) { if (engine->canJIT(function)) QV4::JIT::BaselineJIT(function).generate(); else @@ -446,6 +479,7 @@ 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 { @@ -459,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>(); @@ -521,14 +555,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_END_INSTR(LoadImport) MOTH_BEGIN_INSTR(LoadLocal) - auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m()); + auto cc = static_cast<Heap::CallContext *>(STACK_VALUE(CallData::Context).m()); Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext); acc = cc->locals[index].asReturnedValue(); MOTH_END_INSTR(LoadLocal) MOTH_BEGIN_INSTR(StoreLocal) CHECK_EXCEPTION; - auto cc = static_cast<Heap::CallContext *>(stack[CallData::Context].m()); + auto cc = static_cast<Heap::CallContext *>(STACK_VALUE(CallData::Context).m()); Q_ASSERT(cc->type != QV4::Heap::CallContext::Type_GlobalContext); QV4::WriteBarrier::write(engine, cc, cc->locals.values[index].data_ptr(), acc); MOTH_END_INSTR(StoreLocal) @@ -611,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(); @@ -629,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(); @@ -659,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) @@ -686,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) @@ -714,7 +775,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(CallProperty) STORE_IP(); - acc = Runtime::CallProperty::call(engine, stack[base], name, stack + argv, argc); + acc = Runtime::CallProperty::call(engine, STACK_VALUE(base), name, stack + argv, argc); CHECK_EXCEPTION; MOTH_END_INSTR(CallProperty) @@ -722,35 +783,33 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, STORE_IP(); Lookup *l = function->executableCompilationUnit()->runtimeLookups + lookupIndex; - if (stack[base].isNullOrUndefined()) { + if (STACK_VALUE(base).isNullOrUndefined()) { QString message = QStringLiteral("Cannot call method '%1' of %2") .arg(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString()) - .arg(stack[base].toQStringNoThrow()); + .arg(STACK_VALUE(base).toQStringNoThrow()); acc = engine->throwTypeError(message); goto handleUnwind; } // ok to have the value on the stack here - Value f = Value::fromReturnedValue(l->getter(l, engine, stack[base])); + 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()) - .arg(stack[base].toQStringNoThrow()); + 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[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); @@ -864,7 +923,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(PushWithContext) STORE_IP(); STORE_ACC(); - acc = Runtime::PushWithContext::call(engine, stack[CallData::Accumulator]); + acc = Runtime::PushWithContext::call(engine, STACK_VALUE(CallData::Accumulator)); CHECK_EXCEPTION; MOTH_END_INSTR(PushWithContext) @@ -902,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) @@ -971,12 +1029,13 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(ConvertThisToObject) STORE_ACC(); - stack[CallData::This] = Runtime::ConvertThisToObject::call(engine, stack[CallData::This]); + stack[CallData::This] = Runtime::ConvertThisToObject::call( + engine, STACK_VALUE(CallData::This)); CHECK_EXCEPTION; MOTH_END_INSTR(ConvertThisToObject) MOTH_BEGIN_INSTR(LoadSuperConstructor) - acc = Runtime::LoadSuperConstructor::call(engine, stack[CallData::Function]); + acc = Runtime::LoadSuperConstructor::call(engine, STACK_VALUE(CallData::Function)); CHECK_EXCEPTION; MOTH_END_INSTR(LoadSuperConstructor) @@ -1149,6 +1208,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_END_INSTR(CmpStrictNotEqual) MOTH_BEGIN_INSTR(CmpIn) + STORE_IP(); STORE_ACC(); acc = Runtime::In::call(engine, STACK_VALUE(lhs), accumulator); CHECK_EXCEPTION; @@ -1244,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) @@ -1377,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; |