aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime/qv4vme_moth.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime/qv4vme_moth.cpp')
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp243
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;