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, 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;