diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-06-27 17:23:39 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-07-03 08:08:53 +0000 |
commit | deaa99f66ddedc2ea79e6902c665925b04665e68 (patch) | |
tree | af0cb554eb40d9138f9cf723f0aa982991205635 /src | |
parent | 2666fe4a1440cc798b9db68fcc807450d46069c2 (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.cpp | 25 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4function_p.h | 5 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 30 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4generatorobject.cpp | 32 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4stackframe_p.h | 52 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 65 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth_p.h | 7 |
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); }; |