aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsruntime
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/jsruntime')
-rw-r--r--src/qml/jsruntime/qv4argumentsobject.cpp10
-rw-r--r--src/qml/jsruntime/qv4argumentsobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4context.cpp10
-rw-r--r--src/qml/jsruntime/qv4context_p.h2
-rw-r--r--src/qml/jsruntime/qv4engine.cpp14
-rw-r--r--src/qml/jsruntime/qv4function.cpp47
-rw-r--r--src/qml/jsruntime/qv4function_p.h2
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp97
-rw-r--r--src/qml/jsruntime/qv4functionobject_p.h10
-rw-r--r--src/qml/jsruntime/qv4generatorobject.cpp22
-rw-r--r--src/qml/jsruntime/qv4generatorobject_p.h2
-rw-r--r--src/qml/jsruntime/qv4global_p.h2
-rw-r--r--src/qml/jsruntime/qv4jscall_p.h92
-rw-r--r--src/qml/jsruntime/qv4module.cpp10
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp27
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h4
-rw-r--r--src/qml/jsruntime/qv4stackframe_p.h219
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp131
-rw-r--r--src/qml/jsruntime/qv4vme_moth_p.h6
-rw-r--r--src/qml/jsruntime/qv4vtable_p.h65
20 files changed, 576 insertions, 198 deletions
diff --git a/src/qml/jsruntime/qv4argumentsobject.cpp b/src/qml/jsruntime/qv4argumentsobject.cpp
index 206e2b9aa4..46d0b511ca 100644
--- a/src/qml/jsruntime/qv4argumentsobject.cpp
+++ b/src/qml/jsruntime/qv4argumentsobject.cpp
@@ -51,7 +51,7 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(ArgumentsObject);
DEFINE_OBJECT_VTABLE(StrictArgumentsObject);
-void Heap::StrictArgumentsObject::init(QV4::CppStackFrame *frame)
+void Heap::StrictArgumentsObject::init(QV4::JSTypesStackFrame *frame)
{
Q_ASSERT(vtable() == QV4::StrictArgumentsObject::staticVTable());
@@ -68,11 +68,11 @@ void Heap::StrictArgumentsObject::init(QV4::CppStackFrame *frame)
Scope scope(v4);
Scoped<QV4::StrictArgumentsObject> args(scope, this);
- args->arrayReserve(frame->originalArgumentsCount);
- args->arrayPut(0, frame->originalArguments, frame->originalArgumentsCount);
+ args->arrayReserve(frame->argc());
+ args->arrayPut(0, frame->argv(), frame->argc());
Q_ASSERT(args->internalClass()->verifyIndex(v4->id_length()->propertyKey(), LengthPropertyIndex));
- setProperty(v4, LengthPropertyIndex, Value::fromInt32(frame->originalArgumentsCount));
+ setProperty(v4, LengthPropertyIndex, Value::fromInt32(frame->argc()));
}
void Heap::ArgumentsObject::init(QV4::CppStackFrame *frame)
@@ -93,7 +93,7 @@ void Heap::ArgumentsObject::init(QV4::CppStackFrame *frame)
setProperty(v4, SymbolIteratorPropertyIndex, *v4->arrayProtoValues());
fullyCreated = false;
- argCount = frame->originalArgumentsCount;
+ argCount = frame->argc();
uint nFormals = frame->v4Function->nFormals;
mapped = nFormals > 63 ? std::numeric_limits<quint64>::max() : (1ull << nFormals) - 1;
}
diff --git a/src/qml/jsruntime/qv4argumentsobject_p.h b/src/qml/jsruntime/qv4argumentsobject_p.h
index f0e2192c7e..9e1fe10965 100644
--- a/src/qml/jsruntime/qv4argumentsobject_p.h
+++ b/src/qml/jsruntime/qv4argumentsobject_p.h
@@ -84,7 +84,7 @@ DECLARE_HEAP_OBJECT(StrictArgumentsObject, Object) {
CalleePropertyIndex = 2,
CalleeSetterPropertyIndex = 3
};
- void init(CppStackFrame *frame);
+ void init(JSTypesStackFrame *frame);
};
}
diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp
index 018571e325..282046f3fa 100644
--- a/src/qml/jsruntime/qv4context.cpp
+++ b/src/qml/jsruntime/qv4context.cpp
@@ -95,12 +95,12 @@ Heap::CallContext *ExecutionContext::cloneBlockContext(ExecutionEngine *engine,
return c;
}
-Heap::CallContext *ExecutionContext::newCallContext(CppStackFrame *frame)
+Heap::CallContext *ExecutionContext::newCallContext(JSTypesStackFrame *frame)
{
Function *function = frame->v4Function;
Heap::ExecutionContext *outer = static_cast<Heap::ExecutionContext *>(frame->context()->m());
- uint nFormals = qMax(static_cast<uint>(frame->originalArgumentsCount), function->nFormals);
+ uint nFormals = qMax(static_cast<uint>(frame->argc()), function->nFormals);
uint localsAndFormals = function->compiledFunction->nLocals + nFormals;
size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + sizeof(Value) * (localsAndFormals);
@@ -122,9 +122,9 @@ Heap::CallContext *ExecutionContext::newCallContext(CppStackFrame *frame)
c->setupLocalTemporalDeadZone(compiledFunction);
Value *args = c->locals.values + nLocals;
- ::memcpy(args, frame->originalArguments, frame->originalArgumentsCount * sizeof(Value));
- c->nArgs = frame->originalArgumentsCount;
- for (uint i = frame->originalArgumentsCount; i < function->nFormals; ++i)
+ ::memcpy(args, frame->argv(), frame->argc() * sizeof(Value));
+ c->nArgs = frame->argc();
+ for (uint i = frame->argc(); i < function->nFormals; ++i)
args[i] = Encode::undefined();
return c;
diff --git a/src/qml/jsruntime/qv4context_p.h b/src/qml/jsruntime/qv4context_p.h
index 75fa2d08e6..cc27d20fd4 100644
--- a/src/qml/jsruntime/qv4context_p.h
+++ b/src/qml/jsruntime/qv4context_p.h
@@ -152,7 +152,7 @@ struct Q_QML_EXPORT ExecutionContext : public Managed
static Heap::CallContext *newBlockContext(QV4::CppStackFrame *frame, int blockIndex);
static Heap::CallContext *cloneBlockContext(ExecutionEngine *engine,
Heap::CallContext *callContext);
- static Heap::CallContext *newCallContext(QV4::CppStackFrame *frame);
+ static Heap::CallContext *newCallContext(JSTypesStackFrame *frame);
Heap::ExecutionContext *newWithContext(Heap::Object *with) const;
static Heap::ExecutionContext *newCatchContext(CppStackFrame *frame, int blockIndex, Heap::String *exceptionVarName);
diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp
index 182e131c9e..8c4277a682 100644
--- a/src/qml/jsruntime/qv4engine.cpp
+++ b/src/qml/jsruntime/qv4engine.cpp
@@ -1258,13 +1258,15 @@ StackTrace ExecutionEngine::stackTrace(int frameLimit) const
frame.line = qAbs(f->lineNumber());
frame.column = -1;
stack.append(frame);
- if (f->isTailCalling) {
- QV4::StackFrame frame;
- frame.function = QStringLiteral("[elided tail calls]");
- stack.append(frame);
+ if (f->isJSTypesFrame()) {
+ if (static_cast<JSTypesStackFrame *>(f)->isTailCalling()) {
+ QV4::StackFrame frame;
+ frame.function = QStringLiteral("[elided tail calls]");
+ stack.append(frame);
+ }
}
--frameLimit;
- f = f->parent;
+ f = f->parentFrame();
}
return stack;
@@ -1322,7 +1324,7 @@ QUrl ExecutionEngine::resolvedUrl(const QString &file)
base = f->v4Function->finalUrl();
break;
}
- f = f->parent;
+ f = f->parentFrame();
}
if (base.isEmpty() && globalCode)
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 8164bae549..348837c3a5 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -51,26 +51,53 @@
#include <assembler/MacroAssemblerCodeRef.h>
#include <private/qv4vme_moth_p.h>
#include <private/qqmlglobal_p.h>
+#include <private/qv4jscall_p.h>
QT_BEGIN_NAMESPACE
using namespace QV4;
-ReturnedValue Function::call(const Value *thisObject, const Value *argv, int argc, const ExecutionContext *context) {
+void Function::call(const Value *thisObject, void **a, const QMetaType *types, int argc,
+ const ExecutionContext *context)
+{
+ if (!aotFunction) {
+ QV4::convertAndCall(context->engine(), thisObject, a, types, argc,
+ [this, context](const Value *thisObject, const Value *argv, int argc) {
+ return call(thisObject, argv, argc, context);
+ });
+ return;
+ }
+
ExecutionEngine *engine = context->engine();
- CppStackFrame frame;
- frame.init(engine, this, argv, argc);
+ MetaTypesStackFrame frame;
+ frame.init(this, a, types, argc);
frame.setupJSFrame(engine->jsStackTop, Value::undefinedValue(), context->d(),
- thisObject ? *thisObject : Value::undefinedValue(),
- Value::undefinedValue());
-
- frame.push();
+ thisObject ? *thisObject : Value::undefinedValue());
+ frame.push(engine);
engine->jsStackTop += frame.requiredJSStackFrameSize();
+ Moth::VME::exec(&frame, engine);
+ frame.pop(engine);
+}
- ReturnedValue result = Moth::VME::exec(&frame, engine);
-
- frame.pop();
+ReturnedValue Function::call(const Value *thisObject, const Value *argv, int argc, const ExecutionContext *context) {
+ if (aotFunction) {
+ return QV4::convertAndCall(
+ context->engine(), aotFunction, thisObject, argv, argc,
+ [this, context](const Value *thisObject,
+ void **a, const QMetaType *types, int argc) {
+ call(thisObject, a, types, argc, context);
+ });
+ }
+ ExecutionEngine *engine = context->engine();
+ JSTypesStackFrame frame;
+ frame.init(this, argv, argc);
+ frame.setupJSFrame(engine->jsStackTop, Value::undefinedValue(), context->d(),
+ thisObject ? *thisObject : Value::undefinedValue());
+ engine->jsStackTop += frame.requiredJSStackFrameSize();
+ frame.push(engine);
+ ReturnedValue result = Moth::VME::exec(&frame, engine);
+ frame.pop(engine);
return result;
}
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index c022f84205..a15344dacd 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -100,6 +100,8 @@ public:
return compilationUnit->runtimeStrings[i];
}
+ void 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);
const char *codeData;
diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp
index 9701e0e9ca..d3bafbe055 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -70,9 +70,11 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(FunctionObject);
-void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name, VTable::Call call)
+void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name,
+ VTable::Call call, VTable::CallWithMetaTypes callWithMetaTypes)
{
jsCall = call;
+ jsCallWithMetaTypes = callWithMetaTypes;
jsConstruct = nullptr;
Object::init();
@@ -88,6 +90,7 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name)
ExecutionEngine *e = scope->engine();
jsCall = vtable()->call;
+ jsCallWithMetaTypes = vtable()->callWithMetaTypes;
jsConstruct = vtable()->callAsConstructor;
Object::init();
@@ -103,6 +106,7 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, QV4::String *name)
void Heap::FunctionObject::init(QV4::ExecutionContext *scope, Function *function, QV4::String *n)
{
jsCall = vtable()->call;
+ jsCallWithMetaTypes = vtable()->callWithMetaTypes;
jsConstruct = vtable()->callAsConstructor;
Object::init();
@@ -125,6 +129,7 @@ void Heap::FunctionObject::init(QV4::ExecutionContext *scope, const QString &nam
void Heap::FunctionObject::init()
{
jsCall = vtable()->call;
+ jsCallWithMetaTypes = vtable()->callWithMetaTypes;
jsConstruct = vtable()->callAsConstructor;
Object::init();
@@ -156,6 +161,19 @@ 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)
+{
+ if (const auto callWithMetaTypes = d()->jsCallWithMetaTypes) {
+ callWithMetaTypes(this, thisObject, a, types, argc);
+ return;
+ }
+
+ QV4::convertAndCall(engine(), thisObject, a, types, argc,
+ [this](const Value *thisObject, const Value *argv, int argc) {
+ return call(thisObject, argv, argc);
+ });
+}
+
ReturnedValue FunctionObject::name() const
{
return get(scope()->internalClass->engine->id_name());
@@ -166,6 +184,11 @@ ReturnedValue FunctionObject::virtualCall(const FunctionObject *, const Value *,
return Encode::undefined();
}
+void FunctionObject::virtualCallWithMetaTypes(
+ const FunctionObject *, const Value *, void **, const QMetaType *, int)
+{
+}
+
Heap::FunctionObject *FunctionObject::createScriptFunction(ExecutionContext *scope, Function *function)
{
if (function->isArrowFunction())
@@ -487,18 +510,18 @@ ReturnedValue ScriptFunction::virtualCallAsConstructor(const FunctionObject *fo,
}
ScopedValue thisObject(scope, v4->memoryManager->allocObject<Object>(ic));
- CppStackFrame frame;
- frame.init(v4, f->function(), argv, argc);
+ JSTypesStackFrame frame;
+ frame.init(f->function(), argv, argc);
frame.setupJSFrame(v4->jsStackTop, *f, f->scope(),
thisObject,
newTarget ? *newTarget : Value::undefinedValue());
- frame.push();
+ frame.push(v4);
v4->jsStackTop += frame.requiredJSStackFrameSize();
ReturnedValue result = Moth::VME::exec(&frame, v4);
- frame.pop();
+ frame.pop(v4);
if (Q_UNLIKELY(v4->hasException))
return Encode::undefined();
@@ -509,27 +532,57 @@ ReturnedValue ScriptFunction::virtualCallAsConstructor(const FunctionObject *fo,
DEFINE_OBJECT_VTABLE(ArrowFunction);
+void ArrowFunction::virtualCallWithMetaTypes(const FunctionObject *fo, const Value *thisObject,
+ void **a, const QMetaType *types, int argc)
+{
+ if (!fo->function()->aotFunction) {
+ QV4::convertAndCall(fo->engine(), thisObject, a, types, argc,
+ [fo](const Value *thisObject, const Value *argv, int argc) {
+ return ArrowFunction::virtualCall(fo, thisObject, argv, argc);
+ });
+ return;
+ }
+
+ ExecutionEngine *engine = fo->engine();
+ 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);
+}
+
ReturnedValue ArrowFunction::virtualCall(const FunctionObject *fo, const Value *thisObject, const Value *argv, int argc)
{
+ 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) {
+ ArrowFunction::virtualCallWithMetaTypes(fo, thisObject, a, types, argc);
+ });
+ }
+
ExecutionEngine *engine = fo->engine();
- CppStackFrame frame;
- frame.init(engine, fo->function(), argv, argc, true);
+ JSTypesStackFrame frame;
+ frame.init(fo->function(), argv, argc, true);
frame.setupJSFrame(engine->jsStackTop, *fo, fo->scope(),
- thisObject ? *thisObject : Value::undefinedValue(),
- Value::undefinedValue());
+ thisObject ? *thisObject : Value::undefinedValue());
- frame.push();
+ frame.push(engine);
engine->jsStackTop += frame.requiredJSStackFrameSize();
ReturnedValue result;
do {
- frame.pendingTailCall = false;
+ frame.setPendingTailCall(false);
result = Moth::VME::exec(&frame, engine);
- frame.isTailCalling = true;
- } while (frame.pendingTailCall);
+ frame.setTailCalling(true);
+ } while (frame.pendingTailCall());
- frame.pop();
+ frame.pop(engine);
return result;
}
@@ -590,19 +643,19 @@ ReturnedValue ConstructorFunction::virtualCallAsConstructor(const FunctionObject
ExecutionEngine *v4 = f->engine();
- CppStackFrame frame;
- frame.init(v4, f->function(), argv, argc);
+ JSTypesStackFrame frame;
+ frame.init(f->function(), argv, argc);
frame.setupJSFrame(v4->jsStackTop, *f, f->scope(),
Value::emptyValue(),
newTarget ? *newTarget : Value::undefinedValue());
- frame.push();
+ frame.push(v4);
v4->jsStackTop += frame.requiredJSStackFrameSize();
ReturnedValue result = Moth::VME::exec(&frame, v4);
ReturnedValue thisObject = frame.jsFrame->thisObject.asReturnedValue();
- frame.pop();
+ frame.pop(v4);
if (Q_UNLIKELY(v4->hasException))
return Encode::undefined();
@@ -644,20 +697,20 @@ ReturnedValue DefaultClassConstructorFunction::virtualCallAsConstructor(const Fu
ScopedFunctionObject super(scope, f->getPrototypeOf());
Q_ASSERT(super->isFunctionObject());
- CppStackFrame frame;
- frame.init(v4, nullptr, argv, argc);
+ JSTypesStackFrame frame;
+ frame.init(nullptr, argv, argc);
frame.setupJSFrame(v4->jsStackTop, *f, f->scope(),
Value::undefinedValue(),
newTarget ? *newTarget : Value::undefinedValue(), argc, argc);
- frame.push();
+ frame.push(v4);
v4->jsStackTop += frame.requiredJSStackFrameSize(argc);
// Do a super call
ReturnedValue result = super->callAsConstructor(argv, argc, newTarget);
ReturnedValue thisObject = frame.jsFrame->thisObject.asReturnedValue();
- frame.pop();
+ frame.pop(v4);
if (Q_UNLIKELY(v4->hasException))
return Encode::undefined();
diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h
index 78be58c60a..741519389e 100644
--- a/src/qml/jsruntime/qv4functionobject_p.h
+++ b/src/qml/jsruntime/qv4functionobject_p.h
@@ -72,6 +72,7 @@ namespace Heap {
Member(class, NoMark, Function *, function) \
Member(class, NoMark, VTable::Call, jsCall) \
Member(class, NoMark, VTable::CallAsConstructor, jsConstruct) \
+ Member(class, NoMark, VTable::CallWithMetaTypes, jsCallWithMetaTypes) \
Member(class, NoMark, bool, canBeTailCalled)
DECLARE_HEAP_OBJECT(FunctionObject, Object) {
@@ -86,7 +87,9 @@ DECLARE_HEAP_OBJECT(FunctionObject, Object) {
return jsConstruct != nullptr;
}
- Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name, VTable::Call call);
+ Q_QML_PRIVATE_EXPORT void init(
+ QV4::ExecutionContext *scope, QV4::String *name,
+ VTable::Call call, VTable::CallWithMetaTypes callWithMetaTypes = nullptr);
Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name = nullptr);
Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr);
Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, const QString &name);
@@ -202,6 +205,9 @@ 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 **a, const QMetaType *types, int argc);
static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function);
static Heap::FunctionObject *createConstructorFunction(ExecutionContext *scope, Function *function, Object *homeObject, bool isDerivedConstructor);
@@ -277,6 +283,8 @@ struct ArrowFunction : FunctionObject {
V4_INTERNALCLASS(ArrowFunction)
enum { NInlineProperties = 3 };
+ static void virtualCallWithMetaTypes(const FunctionObject *f, const Value *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 5077bf1d2b..d13b0e1ce1 100644
--- a/src/qml/jsruntime/qv4generatorobject.cpp
+++ b/src/qml/jsruntime/qv4generatorobject.cpp
@@ -110,17 +110,17 @@ ReturnedValue GeneratorFunction::virtualCall(const FunctionObject *f, const Valu
for (int i = 0; i < argc; i++)
gp->values->arrayData->setArrayData(engine, i, argv[i]);
- gp->cppFrame.init(engine, function, gp->values->arrayData->values.values, argc);
+ gp->cppFrame.init(function, gp->values->arrayData->values.values, argc);
gp->cppFrame.setupJSFrame(gp->jsFrame->arrayData->values.values, *gf, gf->scope(),
thisObject ? *thisObject : Value::undefinedValue(),
Value::undefinedValue());
- gp->cppFrame.push();
+ gp->cppFrame.push(engine);
Moth::VME::interpret(&gp->cppFrame, engine, function->codeData);
gp->state = GeneratorState::SuspendedStart;
- gp->cppFrame.pop();
+ gp->cppFrame.pop(engine);
return g->asReturnedValue();
}
@@ -214,25 +214,25 @@ ReturnedValue GeneratorObject::resume(ExecutionEngine *engine, const Value &arg)
{
Heap::GeneratorObject *gp = d();
gp->state = GeneratorState::Executing;
- gp->cppFrame.parent = engine->currentStackFrame;
+ gp->cppFrame.setParentFrame(engine->currentStackFrame);
engine->currentStackFrame = &gp->cppFrame;
- Q_ASSERT(gp->cppFrame.yield != nullptr);
- const char *code = gp->cppFrame.yield;
- gp->cppFrame.yield = nullptr;
+ Q_ASSERT(gp->cppFrame.yield() != nullptr);
+ const char *code = gp->cppFrame.yield();
+ gp->cppFrame.setYield(nullptr);
gp->cppFrame.jsFrame->accumulator = arg;
- gp->cppFrame.yieldIsIterator = false;
+ gp->cppFrame.setYieldIsIterator(false);
Scope scope(engine);
ScopedValue result(scope, Moth::VME::interpret(&gp->cppFrame, engine, code));
- engine->currentStackFrame = gp->cppFrame.parent;
+ engine->currentStackFrame = gp->cppFrame.parentFrame();
- bool done = (gp->cppFrame.yield == nullptr);
+ bool done = (gp->cppFrame.yield() == nullptr);
gp->state = done ? GeneratorState::Completed : GeneratorState::SuspendedYield;
if (engine->hasException)
return Encode::undefined();
- if (gp->cppFrame.yieldIsIterator)
+ if (gp->cppFrame.yieldIsIterator())
return result->asReturnedValue();
return IteratorPrototype::createIterResultObject(engine, result, done);
}
diff --git a/src/qml/jsruntime/qv4generatorobject_p.h b/src/qml/jsruntime/qv4generatorobject_p.h
index 10eea5e46b..6eb7b306e0 100644
--- a/src/qml/jsruntime/qv4generatorobject_p.h
+++ b/src/qml/jsruntime/qv4generatorobject_p.h
@@ -89,7 +89,7 @@ struct GeneratorPrototype : FunctionObject {
Member(class, Pointer, ExecutionContext *, context) \
Member(class, Pointer, GeneratorFunction *, function) \
Member(class, NoMark, GeneratorState, state) \
- Member(class, NoMark, CppStackFrame, cppFrame) \
+ Member(class, NoMark, JSTypesStackFrame, cppFrame) \
Member(class, Pointer, ArrayObject *, values) \
Member(class, Pointer, ArrayObject *, jsFrame)
diff --git a/src/qml/jsruntime/qv4global_p.h b/src/qml/jsruntime/qv4global_p.h
index 77f8fe75d0..1493456853 100644
--- a/src/qml/jsruntime/qv4global_p.h
+++ b/src/qml/jsruntime/qv4global_p.h
@@ -146,6 +146,8 @@ namespace Heap {
}
struct CppStackFrame;
+struct JSTypesStackFrame;
+struct MetaTypesStackFrame;
class MemoryManager;
class ExecutableAllocator;
struct PropertyKey;
diff --git a/src/qml/jsruntime/qv4jscall_p.h b/src/qml/jsruntime/qv4jscall_p.h
index 15ede20be3..285164604c 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 <private/qv4alloca_p.h>
QT_BEGIN_NAMESPACE
@@ -140,19 +141,104 @@ struct ScopedStackFrame {
ScopedStackFrame(Scope &scope, Heap::ExecutionContext *context)
: scope(scope)
{
- frame.parent = scope.engine->currentStackFrame;
+ frame.setParentFrame(scope.engine->currentStackFrame);
if (!context)
return;
frame.jsFrame = reinterpret_cast<CallData *>(scope.alloc(sizeof(CallData)/sizeof(Value)));
frame.jsFrame->context = context;
- frame.v4Function = frame.parent ? frame.parent->v4Function : nullptr;
+ if (auto *parent = frame.parentFrame())
+ frame.v4Function = parent->v4Function;
+ else
+ frame.v4Function = nullptr;
scope.engine->currentStackFrame = &frame;
}
~ScopedStackFrame() {
- scope.engine->currentStackFrame = frame.parent;
+ scope.engine->currentStackFrame = frame.parentFrame();
}
};
+template<typename Callable>
+ReturnedValue convertAndCall(
+ ExecutionEngine *engine, const QQmlPrivate::AOTCompiledFunction *aotFunction,
+ const Value *thisObject, const Value *argv, int argc, Callable call)
+{
+ const qsizetype numFunctionArguments = aotFunction->argumentTypes.size();
+ Q_ALLOCA_VAR(void *, values, (numFunctionArguments + 1) * sizeof(void *));
+ Q_ALLOCA_VAR(QMetaType, types, (numFunctionArguments + 1) * sizeof(QMetaType));
+
+ for (qsizetype i = 0; i < numFunctionArguments; ++i) {
+ const QMetaType argumentType = aotFunction->argumentTypes[i];
+ types[i + 1] = argumentType;
+ if (const qsizetype argumentSize = argumentType.sizeOf()) {
+ Q_ALLOCA_VAR(void, argument, argumentSize);
+ argumentType.construct(argument);
+ if (i < argc)
+ engine->metaTypeFromJS(argv[i], argumentType.id(), argument);
+ values[i + 1] = argument;
+ } else {
+ values[i + 1] = nullptr;
+ }
+ }
+
+ Q_ALLOCA_DECLARE(void, returnValue);
+ types[0] = aotFunction->returnType;
+ if (const qsizetype returnSize = types[0].sizeOf()) {
+ Q_ALLOCA_ASSIGN(void, returnValue, returnSize);
+ types[0].construct(returnValue);
+ values[0] = returnValue;
+ } else {
+ values[0] = nullptr;
+ }
+
+ call(thisObject, values, types, argc);
+
+ ReturnedValue result;
+ if (values[0]) {
+ result = engine->metaTypeToJS(types[0], values[0]);
+ types[0].destruct(values[0]);
+ } else {
+ result = Encode::undefined();
+ }
+
+ for (qsizetype i = 1, end = numFunctionArguments + 1; i < end; ++i)
+ types[i].destruct(values[i]);
+
+ return result;
+}
+
+template<typename Callable>
+void convertAndCall(ExecutionEngine *engine, const Value *thisObject,
+ void **a, const QMetaType *types, int argc, Callable call)
+{
+ Scope scope(engine);
+ QV4::JSCallArguments jsCallData(scope, argc);
+
+ for (int ii = 0; ii < argc; ++ii)
+ jsCallData.args[ii] = engine->metaTypeToJS(types[ii + 1], a[ii + 1]);
+
+ void *result = a[0];
+ if (!result) {
+ call(thisObject, jsCallData.args, argc);
+ return;
+ }
+
+ ScopedValue jsResult(scope, call(thisObject, jsCallData.args, argc));
+
+ const QMetaType resultType = types[0];
+ if (scope.hasException()) {
+ // Clear the return value
+ resultType.destruct(result);
+ resultType.construct(result, nullptr);
+ } else {
+ // When the return type is QVariant, JS objects are to be returned as
+ // QJSValue wrapped in QVariant. metaTypeFromJS unwraps them, unfortunately.
+ if (resultType == QMetaType::fromType<QVariant>())
+ *static_cast<QVariant *>(result) = scope.engine->toVariant(jsResult, 0);
+ else
+ scope.engine->metaTypeFromJS(jsResult, resultType.id(), result);
+ }
+}
+
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4module.cpp b/src/qml/jsruntime/qv4module.cpp
index 08a1900383..26bef9cd37 100644
--- a/src/qml/jsruntime/qv4module.cpp
+++ b/src/qml/jsruntime/qv4module.cpp
@@ -112,15 +112,15 @@ void Module::evaluate()
ExecutionEngine *v4 = engine();
Function *moduleFunction = unit->runtimeFunctions[unit->data->indexOfRootFunction];
- CppStackFrame frame;
- frame.init(v4, moduleFunction, nullptr, 0);
+ JSTypesStackFrame frame;
+ frame.init(moduleFunction, nullptr, 0);
frame.setupJSFrame(v4->jsStackTop, Value::undefinedValue(), d()->scope,
Value::undefinedValue(), Value::undefinedValue());
- frame.push();
+ frame.push(v4);
v4->jsStackTop += frame.requiredJSStackFrameSize();
- auto frameCleanup = qScopeGuard([&frame]() {
- frame.pop();
+ auto frameCleanup = qScopeGuard([&frame, v4]() {
+ frame.pop(v4);
});
Moth::VME::exec(&frame, v4);
}
diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp
index 46c6ce4854..a3b1a52535 100644
--- a/src/qml/jsruntime/qv4runtime.cpp
+++ b/src/qml/jsruntime/qv4runtime.cpp
@@ -1572,7 +1572,7 @@ ReturnedValue Runtime::ConstructWithSpread::call(ExecutionEngine *engine, const
return static_cast<const FunctionObject &>(function).callAsConstructor(arguments.argv, arguments.argc, &newTarget);
}
-ReturnedValue Runtime::TailCall::call(CppStackFrame *frame, ExecutionEngine *engine)
+ReturnedValue Runtime::TailCall::call(JSTypesStackFrame *frame, ExecutionEngine *engine)
{
// IMPORTANT! The JIT assumes that this method has the same amount (or less) arguments than
// the jitted function, so it can safely do a tail call.
@@ -1588,18 +1588,19 @@ ReturnedValue Runtime::TailCall::call(CppStackFrame *frame, ExecutionEngine *eng
return engine->throwTypeError();
const FunctionObject &fo = static_cast<const FunctionObject &>(function);
- if (!frame->callerCanHandleTailCall || !fo.canBeTailCalled() || engine->debugger()
+ if (!frame->callerCanHandleTailCall() || !fo.canBeTailCalled() || engine->debugger()
|| unsigned(argc) > fo.formalParameterCount()) {
// Cannot tailcall, do a normal call:
return checkedResult(engine, fo.call(&thisObject, argv, argc));
}
memcpy(frame->jsFrame->args, argv, argc * sizeof(Value));
- frame->init(engine, fo.function(), frame->jsFrame->argValues<Value>(), argc,
- frame->callerCanHandleTailCall);
- frame->setupJSFrame(frame->savedStackTop, fo, fo.scope(), thisObject, Primitive::undefinedValue());
- engine->jsStackTop = frame->savedStackTop + frame->requiredJSStackFrameSize();
- frame->pendingTailCall = true;
+ frame->init(fo.function(), frame->jsFrame->argValues<Value>(), argc,
+ frame->callerCanHandleTailCall());
+ frame->setupJSFrame(frame->framePointer(), fo, fo.scope(), thisObject,
+ Primitive::undefinedValue());
+ engine->jsStackTop = frame->framePointer() + frame->requiredJSStackFrameSize();
+ frame->setPendingTailCall(true);
return Encode::undefined();
}
@@ -1650,7 +1651,7 @@ QV4::ReturnedValue Runtime::TypeofName::call(ExecutionEngine *engine, int nameIn
return TypeofValue::call(engine, prop);
}
-void Runtime::PushCallContext::call(CppStackFrame *frame)
+void Runtime::PushCallContext::call(JSTypesStackFrame *frame)
{
frame->jsFrame->context = ExecutionContext::newCallContext(frame)->asReturnedValue();
}
@@ -1930,14 +1931,18 @@ QV4::ReturnedValue Runtime::CreateMappedArgumentsObject::call(ExecutionEngine *e
QV4::ReturnedValue Runtime::CreateUnmappedArgumentsObject::call(ExecutionEngine *engine)
{
+ Q_ASSERT(engine->currentStackFrame->isJSTypesFrame());
Heap::InternalClass *ic = engine->internalClasses(EngineBase::Class_StrictArgumentsObject);
- return engine->memoryManager->allocObject<StrictArgumentsObject>(ic, engine->currentStackFrame)->asReturnedValue();
+ return engine->memoryManager->allocObject<StrictArgumentsObject>(
+ ic, static_cast<JSTypesStackFrame *>(engine->currentStackFrame))->asReturnedValue();
}
QV4::ReturnedValue Runtime::CreateRestParameter::call(ExecutionEngine *engine, int argIndex)
{
- const Value *values = engine->currentStackFrame->originalArguments + argIndex;
- int nValues = engine->currentStackFrame->originalArgumentsCount - argIndex;
+ Q_ASSERT(engine->currentStackFrame->isJSTypesFrame());
+ JSTypesStackFrame *frame = static_cast<JSTypesStackFrame *>(engine->currentStackFrame);
+ const Value *values = frame->argv() + argIndex;
+ int nValues = frame->argc() - argIndex;
if (nValues <= 0)
return engine->newArrayObject(0)->asReturnedValue();
return engine->newArrayObject(values, nValues)->asReturnedValue();
diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h
index d155187e48..012a43251a 100644
--- a/src/qml/jsruntime/qv4runtimeapi_p.h
+++ b/src/qml/jsruntime/qv4runtimeapi_p.h
@@ -125,7 +125,7 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
};
struct Q_QML_PRIVATE_EXPORT TailCall : Method<Throws::Yes>
{
- static ReturnedValue call(CppStackFrame *, ExecutionEngine *);
+ static ReturnedValue call(JSTypesStackFrame *, ExecutionEngine *engine);
};
/* construct */
@@ -235,7 +235,7 @@ struct Q_QML_PRIVATE_EXPORT Runtime {
};
struct Q_QML_PRIVATE_EXPORT PushCallContext : Method<Throws::No, ChangesContext::Yes>
{
- static void call(CppStackFrame *);
+ static void call(JSTypesStackFrame *);
};
struct Q_QML_PRIVATE_EXPORT PushWithContext : Method<Throws::Yes, ChangesContext::Yes>
{
diff --git a/src/qml/jsruntime/qv4stackframe_p.h b/src/qml/jsruntime/qv4stackframe_p.h
index a78aacf509..5423ae35a8 100644
--- a/src/qml/jsruntime/qv4stackframe_p.h
+++ b/src/qml/jsruntime/qv4stackframe_p.h
@@ -55,55 +55,63 @@
#include <private/qv4calldata_p.h>
#include <private/qv4function_p.h>
+#include <type_traits>
+
QT_BEGIN_NAMESPACE
namespace QV4 {
-struct Q_QML_EXPORT CppStackFrame {
- EngineBase *engine;
+struct CppStackFrame;
+struct Q_QML_PRIVATE_EXPORT CppStackFrameBase
+{
+ enum class Kind : quint8 { Bare, JS, Meta };
+
Value *savedStackTop;
CppStackFrame *parent;
Function *v4Function;
CallData *jsFrame;
- const Value *originalArguments;
int originalArgumentsCount;
int instructionPointer;
- const char *yield;
- const char *unwindHandler;
- const char *unwindLabel;
- int unwindLevel;
- bool yieldIsIterator;
- bool callerCanHandleTailCall;
- bool pendingTailCall;
- bool isTailCalling;
-
- void init(EngineBase *engine, Function *v4Function, const Value *argv, int argc, bool callerCanHandleTailCall = false) {
- this->engine = engine;
+ union {
+ struct {
+ const Value *originalArguments;
+ const char *yield;
+ const char *unwindHandler;
+ const char *unwindLabel;
+ int unwindLevel;
+ bool yieldIsIterator;
+ bool callerCanHandleTailCall;
+ bool pendingTailCall;
+ bool isTailCalling;
+ };
+ struct {
+ const QMetaType *metaTypes;
+ void **returnAndArgs;
+ };
+ };
+
+ Kind kind;
+};
+
+struct Q_QML_PRIVATE_EXPORT CppStackFrame : protected CppStackFrameBase
+{
+ // We want to have those public but we can't declare them as public without making the struct
+ // 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) {
this->v4Function = v4Function;
- originalArguments = argv;
originalArgumentsCount = argc;
instructionPointer = 0;
- yield = nullptr;
- unwindHandler = nullptr;
- unwindLabel = nullptr;
- unwindLevel = 0;
- yieldIsIterator = false;
- this->callerCanHandleTailCall = callerCanHandleTailCall;
- pendingTailCall = false;
- isTailCalling = false;
+ this->kind = kind;
}
- void push() {
- parent = engine->currentStackFrame;
- engine->currentStackFrame = this;
- savedStackTop = engine->jsStackTop;
- }
-
- void pop() {
- engine->currentStackFrame = parent;
- engine->jsStackTop = savedStackTop;
- }
+ 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;
@@ -114,13 +122,9 @@ struct Q_QML_EXPORT CppStackFrame {
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,
- v4Function->compiledFunction->nFormals, v4Function->compiledFunction->nRegisters);
- }
- void setupJSFrame(Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope,
- const Value &thisObject, const Value &newTarget, uint nFormals, uint nRegisters)
+ const Value &thisObject, const Value &newTarget = Value::undefinedValue())
{
jsFrame = reinterpret_cast<CallData *>(stackSpace);
jsFrame->function = function;
@@ -128,22 +132,116 @@ struct Q_QML_EXPORT CppStackFrame {
jsFrame->accumulator = Encode::undefined();
jsFrame->thisObject = thisObject;
jsFrame->newTarget = newTarget;
+ }
+
+ QString source() const;
+ QString function() const;
+ int lineNumber() const;
+ ReturnedValue thisObject() const;
- if (v4Function && v4Function->aotFunction)
- return;
+ ExecutionContext *context() const
+ {
+ return static_cast<ExecutionContext *>(&jsFrame->context);
+ }
+
+ void setContext(ExecutionContext *context)
+ {
+ jsFrame->context = context;
+ }
+
+ Heap::CallContext *callContext() 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)
+ {
+ CppStackFrame::init(v4Function, argc, Kind::Meta);
+ metaTypes = types;
+ returnAndArgs = a;
+ }
+
+ QMetaType returnType() const { return metaTypes[0]; }
+ void *returnValue() const { return returnAndArgs[0]; }
+
+ const QMetaType *argTypes() const { return metaTypes + 1; }
+ void **argv() const { return returnAndArgs + 1; }
+};
+
+struct Q_QML_PRIVATE_EXPORT JSTypesStackFrame : public CppStackFrame
+{
+ // The JIT needs to poke directly into those using offsetof
+ using CppStackFrame::unwindHandler;
+ using CppStackFrame::unwindLabel;
+ using CppStackFrame::unwindLevel;
+
+ void init(Function *v4Function, const Value *argv, int argc,
+ bool callerCanHandleTailCall = false)
+ {
+ CppStackFrame::init(v4Function, argc, Kind::JS);
+ CppStackFrame::originalArguments = argv;
+ CppStackFrame::yield = nullptr;
+ CppStackFrame::unwindHandler = nullptr;
+ CppStackFrame::yieldIsIterator = false;
+ CppStackFrame::callerCanHandleTailCall = callerCanHandleTailCall;
+ CppStackFrame::pendingTailCall = false;
+ CppStackFrame::isTailCalling = false;
+ CppStackFrame::unwindLabel = nullptr;
+ CppStackFrame::unwindLevel = 0;
+ }
+
+ const Value *argv() const { return originalArguments; }
+
+ 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,
+ v4Function->compiledFunction->nFormals,
+ v4Function->compiledFunction->nRegisters);
+ }
+
+ void setupJSFrame(
+ 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);
uint argc = uint(originalArgumentsCount);
if (argc > nFormals)
argc = nFormals;
jsFrame->setArgc(argc);
- memcpy(jsFrame->args, originalArguments, argc*sizeof(Value));
+ memcpy(jsFrame->args, originalArguments, argc * sizeof(Value));
Q_STATIC_ASSERT(Encode::undefined() == 0);
- memset(jsFrame->args + argc, 0, (nRegisters - argc)*sizeof(Value));
+ memset(jsFrame->args + argc, 0, (nRegisters - argc) * sizeof(Value));
if (v4Function && v4Function->compiledFunction) {
- const int firstDeadZoneRegister = v4Function->compiledFunction->firstTemporalDeadZoneRegister;
- const int registerDeadZoneSize = v4Function->compiledFunction->sizeOfRegisterTemporalDeadZone;
+ const int firstDeadZoneRegister
+ = v4Function->compiledFunction->firstTemporalDeadZoneRegister;
+ const int registerDeadZoneSize
+ = v4Function->compiledFunction->sizeOfRegisterTemporalDeadZone;
const Value * tdzEnd = stackSpace + firstDeadZoneRegister + registerDeadZoneSize;
for (Value *v = stackSpace + firstDeadZoneRegister; v < tdzEnd; ++v)
@@ -151,22 +249,27 @@ struct Q_QML_EXPORT CppStackFrame {
}
}
- QString source() const;
- QString function() const;
- inline QV4::ExecutionContext *context() const {
- return static_cast<ExecutionContext *>(&jsFrame->context);
- }
- int lineNumber() const;
+ bool isTailCalling() const { return CppStackFrame::isTailCalling; }
+ void setTailCalling(bool tailCalling) { CppStackFrame::isTailCalling = tailCalling; }
- inline QV4::Heap::CallContext *callContext() 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);
- }
- ReturnedValue thisObject() const;
+ bool pendingTailCall() const { return CppStackFrame::pendingTailCall; }
+ void setPendingTailCall(bool pending) { CppStackFrame::pendingTailCall = pending; }
+
+ const char *yield() const { return CppStackFrame::yield; }
+ void setYield(const char *yield) { CppStackFrame::yield = yield; }
+
+ bool yieldIsIterator() const { return CppStackFrame::yieldIsIterator; }
+ void setYieldIsIterator(bool isIter) { CppStackFrame::yieldIsIterator = isIter; }
+
+ bool callerCanHandleTailCall() const { return CppStackFrame::callerCanHandleTailCall; }
};
+Q_STATIC_ASSERT(sizeof(CppStackFrame) == sizeof(JSTypesStackFrame));
+Q_STATIC_ASSERT(sizeof(CppStackFrame) == sizeof(MetaTypesStackFrame));
+Q_STATIC_ASSERT(std::is_standard_layout_v<CppStackFrame>);
+Q_STATIC_ASSERT(std::is_standard_layout_v<JSTypesStackFrame>);
+Q_STATIC_ASSERT(std::is_standard_layout_v<MetaTypesStackFrame>);
+
}
QT_END_NAMESPACE
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index 739dc4b7ba..47d7f277e6 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -429,7 +429,79 @@ static bool compareEqualInt(QV4::Value &accumulator, QV4::Value lhs, int rhs)
} \
} while (false)
-ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine)
+void VME::exec(MetaTypesStackFrame *frame, ExecutionEngine *engine)
+{
+ qt_v4ResolvePendingBreakpointsHook();
+ if (engine->checkStackLimits())
+ return;
+ ExecutionEngineCallDepthRecorder executionEngineCallDepthRecorder(engine);
+
+ Function *function = frame->v4Function;
+ Q_ASSERT(function->aotFunction);
+ 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 qsizetype numFunctionArguments = function->aotFunction->argumentTypes.size();
+
+ Q_ALLOCA_DECLARE(void, *transformedArguments);
+ for (qsizetype i = 0; i < numFunctionArguments; ++i) {
+ const QMetaType argumentType = function->aotFunction->argumentTypes[i];
+ if (frame->argc() > i && argumentType == frame->argTypes()[i])
+ continue;
+
+ if (transformedArguments == nullptr) {
+ Q_ALLOCA_ASSIGN(void *, transformedArguments, numFunctionArguments * sizeof(void *));
+ memcpy(transformedArguments, frame->argv(), frame->argc() * sizeof(void *));
+ }
+
+ Q_ALLOCA_VAR(void, arg, argumentType.sizeOf());
+ argumentType.construct(arg);
+ if (frame->argc() > i)
+ QMetaType::convert(frame->argTypes()[i], frame->argv()[i], argumentType, arg);
+
+ transformedArguments[i] = arg;
+ }
+
+ const QMetaType returnType = function->aotFunction->returnType;
+ Q_ALLOCA_DECLARE(void, transformedResult);
+ if (frame->returnValue()) {
+ if (returnType == frame->returnType())
+ returnType.destruct(frame->returnValue());
+ else
+ Q_ALLOCA_ASSIGN(void, transformedResult, returnType.sizeOf());
+ }
+
+ QQmlPrivate::AOTCompiledContext aotContext;
+ if (QV4::Heap::QmlContext *qmlContext = engine->qmlContext()) {
+ QV4::Heap::QQmlContextWrapper *wrapper = qmlContext->qml();
+ aotContext.qmlScopeObject = wrapper->scopeObject;
+ aotContext.qmlContext = wrapper->context->asQQmlContext();
+ }
+
+ aotContext.engine = engine->jsEngine();
+ aotContext.compilationUnit = function->executableCompilationUnit();
+ function->aotFunction->functionPtr(
+ &aotContext, transformedResult ? transformedResult : frame->returnValue(),
+ transformedArguments ? transformedArguments : frame->argv());
+
+ if (transformedResult) {
+ QMetaType::convert(returnType, transformedResult,
+ frame->returnType(), frame->returnValue());
+ returnType.destruct(transformedResult);
+ }
+
+ if (transformedArguments) {
+ for (int i = 0; i < numFunctionArguments; ++i) {
+ if (i >= frame->argc() || transformedArguments[i] != frame->argv()[i])
+ function->aotFunction->argumentTypes[i].destruct(transformedArguments[i]);
+ }
+ }
+}
+
+ReturnedValue VME::exec(JSTypesStackFrame *frame, ExecutionEngine *engine)
{
qt_v4ResolvePendingBreakpointsHook();
CHECK_STACK_LIMITS(engine);
@@ -461,54 +533,9 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine)
debugger->enteringFunction();
ReturnedValue result;
+ Q_ASSERT(!function->aotFunction);
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);
-
- QQmlPrivate::AOTCompiledContext aotContext;
- if (QV4::Heap::QmlContext *qmlContext = engine->qmlContext()) {
- QV4::Heap::QQmlContextWrapper *wrapper = qmlContext->qml();
- aotContext.qmlScopeObject = wrapper->scopeObject;
- aotContext.qmlContext = wrapper->context->asQQmlContext();
- }
- 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);
@@ -520,7 +547,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>();
@@ -720,14 +747,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)
diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h
index b3944f5454..1ccb6bb2ed 100644
--- a/src/qml/jsruntime/qv4vme_moth_p.h
+++ b/src/qml/jsruntime/qv4vme_moth_p.h
@@ -66,8 +66,10 @@ public:
QV4::Function *function;
const QV4::ExecutionContext *scope;
};
- static QV4::ReturnedValue exec(CppStackFrame *frame, ExecutionEngine *engine);
- static QV4::ReturnedValue interpret(CppStackFrame *frame, ExecutionEngine *engine, const char *codeEntry);
+
+ static void exec(MetaTypesStackFrame *frame, ExecutionEngine *engine);
+ static QV4::ReturnedValue exec(JSTypesStackFrame *frame, ExecutionEngine *engine);
+ static QV4::ReturnedValue interpret(JSTypesStackFrame *frame, ExecutionEngine *engine, const char *codeEntry);
};
} // namespace Moth
diff --git a/src/qml/jsruntime/qv4vtable_p.h b/src/qml/jsruntime/qv4vtable_p.h
index 588205f046..a71c9da691 100644
--- a/src/qml/jsruntime/qv4vtable_p.h
+++ b/src/qml/jsruntime/qv4vtable_p.h
@@ -84,6 +84,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 ReturnedValue (*CallAsConstructor)(const FunctionObject *, const Value *argv, int argc, const Value *newTarget);
typedef ReturnedValue (*ResolveLookupGetter)(const Object *, ExecutionEngine *, Lookup *);
@@ -123,11 +124,63 @@ struct VTable
Call call;
CallAsConstructor callAsConstructor;
+ CallWithMetaTypes callWithMetaTypes;
ResolveLookupGetter resolveLookupGetter;
ResolveLookupSetter resolveLookupSetter;
};
+template<VTable::CallWithMetaTypes call>
+struct VTableCallWithMetaTypesWrapper { constexpr static VTable::CallWithMetaTypes c = call; };
+
+template<VTable::Call call>
+struct VTableCallWrapper { constexpr static VTable::Call c = call; };
+
+template<class Class>
+constexpr VTable::CallWithMetaTypes vtableMetaTypesCallEntry()
+{
+ // If Class overrides virtualCallWithMetaTypes, return that.
+ // Otherwise, if it overrides virtualCall, return nullptr so that we convert calls.
+ // Otherwise, just return whatever the base class had.
+
+ // A simple != is not considered constexpr, so we have to jump through some hoops.
+ if constexpr (!std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
+ VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>) {
+ return Class::virtualCallWithMetaTypes;
+ }
+
+ if constexpr (!std::is_same_v<
+ VTableCallWrapper<Class::virtualCall>,
+ VTableCallWrapper<Class::SuperClass::virtualCall>>) {
+ return nullptr;
+ }
+
+ return Class::virtualCallWithMetaTypes;
+}
+
+template<class Class>
+constexpr VTable::Call vtableJsTypesCallEntry()
+{
+ // If Class overrides virtualCall, return that.
+ // Otherwise, if it overrides virtualCallWithMetaTypes, return nullptr so that we convert calls.
+ // Otherwise, just return whatever the base class had.
+
+ // A simple != is not considered constexpr, so we have to jump through some hoops.
+ if constexpr (!std::is_same_v<
+ VTableCallWrapper<Class::virtualCall>,
+ VTableCallWrapper<Class::SuperClass::virtualCall>>) {
+ return Class::virtualCall;
+ }
+
+ if constexpr (!std::is_same_v<
+ VTableCallWithMetaTypesWrapper<Class::virtualCallWithMetaTypes>,
+ VTableCallWithMetaTypesWrapper<Class::SuperClass::virtualCallWithMetaTypes>>) {
+ return nullptr;
+ }
+
+ return Class::virtualCall;
+}
struct VTableBase {
protected:
@@ -150,9 +203,16 @@ protected:
static constexpr VTable::Call virtualCall = nullptr;
static constexpr VTable::CallAsConstructor virtualCallAsConstructor = nullptr;
+ static constexpr VTable::CallWithMetaTypes virtualCallWithMetaTypes = nullptr;
static constexpr VTable::ResolveLookupGetter virtualResolveLookupGetter = nullptr;
static constexpr VTable::ResolveLookupSetter virtualResolveLookupSetter = nullptr;
+
+ template<class Class>
+ friend constexpr VTable::CallWithMetaTypes vtableMetaTypesCallEntry();
+
+ template<class Class>
+ friend constexpr VTable::Call vtableJsTypesCallEntry();
};
#define DEFINE_MANAGED_VTABLE_INT(classname, parentVTable) \
@@ -190,8 +250,9 @@ protected:
classname::virtualOwnPropertyKeys, \
classname::virtualInstanceOf, \
\
- classname::virtualCall, \
- classname::virtualCallAsConstructor, \
+ QV4::vtableJsTypesCallEntry<classname>(), \
+ classname::virtualCallAsConstructor, \
+ QV4::vtableMetaTypesCallEntry<classname>(), \
\
classname::virtualResolveLookupGetter, \
classname::virtualResolveLookupSetter \