aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@qt.io>2018-06-27 17:23:39 +0200
committerLars Knoll <lars.knoll@qt.io>2018-07-03 08:08:53 +0000
commitdeaa99f66ddedc2ea79e6902c665925b04665e68 (patch)
treeaf0cb554eb40d9138f9cf723f0aa982991205635 /src
parent2666fe4a1440cc798b9db68fcc807450d46069c2 (diff)
Refactor initialization code for JS stack frames
Move code into qv4stackframe_p.h, so that it can be re-used from different places. Clean up VME::exec and the generatorfunctions using this. Change-Id: Ib4f7eceeb5f55d98dd6ccf2584d13a3b864caea1 Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/qml/jsruntime/qv4function.cpp25
-rw-r--r--src/qml/jsruntime/qv4function_p.h5
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp30
-rw-r--r--src/qml/jsruntime/qv4generatorobject.cpp32
-rw-r--r--src/qml/jsruntime/qv4stackframe_p.h52
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp65
-rw-r--r--src/qml/jsruntime/qv4vme_moth_p.h7
7 files changed, 112 insertions, 104 deletions
diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp
index 9f442d1d68..5e3860a660 100644
--- a/src/qml/jsruntime/qv4function.cpp
+++ b/src/qml/jsruntime/qv4function.cpp
@@ -47,16 +47,35 @@
#include <private/qv4mm_p.h>
#include <private/qv4identifiertable_p.h>
#include <assembler/MacroAssemblerCodeRef.h>
+#include <private/qv4vme_moth_p.h>
#include <private/qqmlglobal_p.h>
QT_BEGIN_NAMESPACE
using namespace QV4;
+ReturnedValue Function::call(const Value *thisObject, const Value *argv, int argc, const ExecutionContext *context) {
+ ExecutionEngine *engine = context->engine();
+ CppStackFrame frame;
+ frame.init(engine, this, argv, argc);
+ frame.setupJSFrame(engine->jsStackTop, Primitive::undefinedValue(), context->d(),
+ thisObject ? *thisObject : Primitive::undefinedValue(),
+ Primitive::undefinedValue());
+
+ frame.push();
+ engine->jsStackTop += frame.requiredJSStackFrameSize();
+
+ ReturnedValue result = Moth::VME::exec(&frame, engine);
+
+ frame.pop();
+
+ return result;
+}
+
Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function)
- : compiledFunction(function)
- , compilationUnit(unit)
- , codeData(function->code())
+ : compiledFunction(function)
+ , compilationUnit(unit)
+ , codeData(function->code())
, jittedCode(nullptr)
, codeRef(nullptr)
, hasQmlDependencies(function->hasQmlDependencies())
diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h
index 9deccaf72a..d542ce752f 100644
--- a/src/qml/jsruntime/qv4function_p.h
+++ b/src/qml/jsruntime/qv4function_p.h
@@ -53,7 +53,6 @@
#include "qv4global_p.h"
#include <private/qv4compileddata_p.h>
#include <private/qv4context_p.h>
-#include <private/qv4vme_moth_p.h>
namespace JSC {
class MacroAssemblerCodeRef;
@@ -69,9 +68,7 @@ struct Q_QML_EXPORT Function {
const CompiledData::Function *compiledFunction;
CompiledData::CompilationUnit *compilationUnit;
- ReturnedValue call(const Value *thisObject, const Value *argv, int argc, const ExecutionContext *context) {
- return Moth::VME::exec(this, thisObject, argv, argc, 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 27bdc7dd44..e88b81bd29 100644
--- a/src/qml/jsruntime/qv4functionobject.cpp
+++ b/src/qml/jsruntime/qv4functionobject.cpp
@@ -58,6 +58,7 @@
#include "private/qlocale_tools_p.h"
#include "private/qqmlbuiltinfunctions_p.h"
#include <private/qv4jscall_p.h>
+#include <private/qv4vme_moth_p.h>
#include <QtCore/QDebug>
#include <algorithm>
@@ -458,7 +459,18 @@ ReturnedValue ScriptFunction::virtualCallAsConstructor(const FunctionObject *fo,
Scope scope(v4);
ScopedValue thisObject(scope, v4->memoryManager->allocObject<Object>(f->classForConstructor()));
- ReturnedValue result = Moth::VME::exec(fo, thisObject, argv, argc, newTarget);
+ CppStackFrame frame;
+ frame.init(v4, f->function(), argv, argc);
+ frame.setupJSFrame(v4->jsStackTop, *f, f->scope(),
+ thisObject,
+ newTarget ? *newTarget : Primitive::undefinedValue());
+
+ frame.push();
+ v4->jsStackTop += frame.requiredJSStackFrameSize();
+
+ ReturnedValue result = Moth::VME::exec(&frame, v4);
+
+ frame.pop();
if (Q_UNLIKELY(v4->hasException))
return Encode::undefined();
@@ -469,7 +481,21 @@ ReturnedValue ScriptFunction::virtualCallAsConstructor(const FunctionObject *fo,
ReturnedValue ScriptFunction::virtualCall(const FunctionObject *fo, const Value *thisObject, const Value *argv, int argc)
{
- return Moth::VME::exec(fo, thisObject, argv, argc);
+ ExecutionEngine *engine = fo->engine();
+ CppStackFrame frame;
+ frame.init(engine, fo->function(), argv, argc);
+ frame.setupJSFrame(engine->jsStackTop, *fo, fo->scope(),
+ thisObject ? *thisObject : Primitive::undefinedValue(),
+ Primitive::undefinedValue());
+
+ frame.push();
+ engine->jsStackTop += frame.requiredJSStackFrameSize();
+
+ ReturnedValue result = Moth::VME::exec(&frame, engine);
+
+ frame.pop();
+
+ return result;
}
void Heap::ScriptFunction::init(QV4::ExecutionContext *scope, Function *function)
diff --git a/src/qml/jsruntime/qv4generatorobject.cpp b/src/qml/jsruntime/qv4generatorobject.cpp
index d5ae863856..bfc27954c4 100644
--- a/src/qml/jsruntime/qv4generatorobject.cpp
+++ b/src/qml/jsruntime/qv4generatorobject.cpp
@@ -96,9 +96,8 @@ ReturnedValue GeneratorFunction::virtualCall(const FunctionObject *f, const Valu
ExecutionEngine *engine = gf->engine();
// We need to set up a separate stack for the generator, as it's being re-entered
- uint stackSize = argc; // space for the original arguments
- int jsStackFrameSize = offsetof(CallData, args)/sizeof(Value) + function->compiledFunction->nRegisters;
- stackSize += jsStackFrameSize;
+ uint stackSize = argc // space for the original arguments
+ + CppStackFrame::requiredJSStackFrameSize(function); // space for the JS stack frame
size_t requiredMemory = sizeof(GeneratorObject::Data) - sizeof(Value) + sizeof(Value) * stackSize;
@@ -112,30 +111,17 @@ ReturnedValue GeneratorFunction::virtualCall(const FunctionObject *f, const Valu
// copy original arguments
memcpy(gp->stack.values, argv, argc*sizeof(Value));
- gp->cppFrame.originalArguments = gp->stack.values;
- gp->cppFrame.originalArgumentsCount = argc;
-
- // setup JS stack frame
- CallData *callData = reinterpret_cast<CallData *>(&gp->stack.values[argc]);
- callData->function = *gf;
- callData->context = gf->scope();
- callData->accumulator = Encode::undefined();
- callData->thisObject = thisObject ? *thisObject : Primitive::undefinedValue();
- if (argc > int(function->nFormals))
- argc = int(function->nFormals);
- callData->setArgc(argc);
- memcpy(callData->args, argv, argc*sizeof(Value));
-
- gp->cppFrame.v4Function = function;
- gp->cppFrame.instructionPointer = 0;
- gp->cppFrame.jsFrame = callData;
- gp->cppFrame.parent = engine->currentStackFrame;
- engine->currentStackFrame = &gp->cppFrame;
+ gp->cppFrame.init(engine, function, gp->stack.values, argc);
+ gp->cppFrame.setupJSFrame(&gp->stack.values[argc], *gf, gf->scope(),
+ thisObject ? *thisObject : Primitive::undefinedValue(),
+ Primitive::undefinedValue());
+
+ gp->cppFrame.push();
Moth::VME::interpret(&gp->cppFrame, engine, function->codeData);
gp->state = GeneratorState::SuspendedStart;
- engine->currentStackFrame = gp->cppFrame.parent;
+ gp->cppFrame.pop();
return g->asReturnedValue();
}
diff --git a/src/qml/jsruntime/qv4stackframe_p.h b/src/qml/jsruntime/qv4stackframe_p.h
index 1735d020e0..68301eb097 100644
--- a/src/qml/jsruntime/qv4stackframe_p.h
+++ b/src/qml/jsruntime/qv4stackframe_p.h
@@ -40,6 +40,7 @@
#define QV4STACKFRAME_H
#include <private/qv4context_p.h>
+#include <private/qv4enginebase_p.h>
#ifndef V4_BOOTSTRAP
#include <private/qv4function_p.h>
#endif
@@ -90,6 +91,8 @@ Q_STATIC_ASSERT(offsetof(CallData, thisObject) == CallData::This*sizeof(Value));
Q_STATIC_ASSERT(offsetof(CallData, args) == 6*sizeof(Value));
struct Q_QML_EXPORT CppStackFrame {
+ EngineBase *engine;
+ Value *savedStackTop;
CppStackFrame *parent;
Function *v4Function;
CallData *jsFrame;
@@ -101,10 +104,57 @@ struct Q_QML_EXPORT CppStackFrame {
const char *unwindLabel;
int unwindLevel;
+ void init(EngineBase *engine, Function *v4Function, const Value *argv, int argc) {
+ this->engine = engine;
+
+ this->v4Function = v4Function;
+ originalArguments = argv;
+ originalArgumentsCount = argc;
+ instructionPointer = 0;
+ yield = nullptr;
+ unwindHandler = nullptr;
+ unwindLabel = nullptr;
+ unwindLevel = 0;
+ }
+
+ void push() {
+ parent = engine->currentStackFrame;
+ engine->currentStackFrame = this;
+ savedStackTop = engine->jsStackTop;
+ }
+
+ void pop() {
+ engine->currentStackFrame = parent;
+ engine->jsStackTop = savedStackTop;
+ }
+
#ifndef V4_BOOTSTRAP
- uint requiredJSStackFrameSize() {
+ static uint requiredJSStackFrameSize(Function *v4Function) {
return CallData::HeaderSize() + v4Function->compiledFunction->nRegisters;
}
+ uint requiredJSStackFrameSize() const {
+ return requiredJSStackFrameSize(v4Function);
+ }
+ void setupJSFrame(Value *stackSpace, const Value &function, const Heap::ExecutionContext *scope,
+ const Value &thisObject, const Value &newTarget = Primitive::undefinedValue())
+ {
+ jsFrame = reinterpret_cast<CallData *>(stackSpace);
+ jsFrame->function = function;
+ jsFrame->context = scope->asReturnedValue();
+ jsFrame->accumulator = Encode::undefined();
+ jsFrame->thisObject = thisObject;
+ jsFrame->newTarget = newTarget;
+
+ uint argc = uint(originalArgumentsCount);
+ if (argc > v4Function->nFormals)
+ argc = v4Function->nFormals;
+ jsFrame->setArgc(argc);
+
+ memcpy(jsFrame->args, originalArguments, argc*sizeof(Value));
+ const Value *end = jsFrame->args + v4Function->compiledFunction->nRegisters;
+ for (Value *v = jsFrame->args + argc; v < end; ++v)
+ *v = Encode::undefined();
+ }
#endif
QString source() const;
diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp
index ade2a36ad1..4f0f9f27ec 100644
--- a/src/qml/jsruntime/qv4vme_moth.cpp
+++ b/src/qml/jsruntime/qv4vme_moth.cpp
@@ -414,6 +414,7 @@ static bool compareEqualInt(QV4::Value &accumulator, QV4::Value lhs, int rhs)
ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine)
{
+ qt_v4ResolvePendingBreakpointsHook();
CHECK_STACK_LIMITS(engine);
Function *function = frame->v4Function;
@@ -445,70 +446,6 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine)
return result;
}
-QV4::ReturnedValue VME::exec(const FunctionObject *fo, const QV4::Value *thisObject, const QV4::Value *argv, int argc, const Value *newTarget)
-{
- qt_v4ResolvePendingBreakpointsHook();
- ExecutionEngine *engine;
- QV4::Value *stack;
- CppStackFrame frame;
- frame.originalArguments = argv;
- frame.originalArgumentsCount = argc;
- frame.yield = nullptr;
- frame.unwindHandler = nullptr;
- frame.unwindLabel = nullptr;
- frame.unwindLevel = 0;
-
- Function *function;
-
- {
- Heap::ExecutionContext *scope;
-
- quintptr d = reinterpret_cast<quintptr>(fo);
- if (d & 0x1) {
- // we don't have a FunctionObject, but a ExecData
- ExecData *data = reinterpret_cast<ExecData *>(d - 1);
- function = data->function;
- scope = data->scope->d();
- fo = nullptr;
- } else {
- function = fo->function();
- scope = fo->scope();
- }
-
- engine = function->internalClass->engine;
-
- stack = engine->jsStackTop;
- CallData *callData = reinterpret_cast<CallData *>(stack);
- callData->function = fo ? fo->asReturnedValue() : Encode::undefined();
- callData->context = scope;
- callData->accumulator = Encode::undefined();
- callData->newTarget = newTarget ? *newTarget : Primitive::undefinedValue();
- callData->thisObject = thisObject ? *thisObject : Primitive::undefinedValue();
- if (argc > int(function->nFormals))
- argc = int(function->nFormals);
- callData->setArgc(argc);
-
- int jsStackFrameSize = offsetof(CallData, args)/sizeof(Value) + function->compiledFunction->nRegisters;
- engine->jsStackTop += jsStackFrameSize;
- memcpy(callData->args, argv, argc*sizeof(Value));
- for (Value *v = callData->args + argc; v < engine->jsStackTop; ++v)
- *v = Encode::undefined();
-
- frame.parent = engine->currentStackFrame;
- frame.v4Function = function;
- frame.instructionPointer = 0;
- frame.jsFrame = callData;
- engine->currentStackFrame = &frame;
- }
-
- ReturnedValue result = exec(&frame, engine);
-
- engine->currentStackFrame = frame.parent;
- engine->jsStackTop = stack;
-
- return result;
-}
-
QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, const char *code)
{
QV4::Function *function = frame->v4Function;
diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h
index 0167e6f5b0..8a76e60f20 100644
--- a/src/qml/jsruntime/qv4vme_moth_p.h
+++ b/src/qml/jsruntime/qv4vme_moth_p.h
@@ -65,14 +65,7 @@ public:
QV4::Function *function;
const QV4::ExecutionContext *scope;
};
- static inline
- QV4::ReturnedValue exec(Function *v4Function, const Value *thisObject, const Value *argv, int argc, const ExecutionContext *context) {
- ExecData data{v4Function, context};
- quintptr d = reinterpret_cast<quintptr>(&data) | 0x1;
- return exec(reinterpret_cast<const FunctionObject *>(d), thisObject, argv, argc);
- }
static QV4::ReturnedValue exec(CppStackFrame *frame, ExecutionEngine *engine);
- static QV4::ReturnedValue exec(const FunctionObject *fo, const Value *thisObject, const Value *argv, int argc, const Value *newTarget = nullptr);
static QV4::ReturnedValue interpret(CppStackFrame *frame, ExecutionEngine *engine, const char *codeEntry);
};