diff options
30 files changed, 245 insertions, 308 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index 6686e61a1c..76d5315004 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -55,47 +55,37 @@ QT_BEGIN_NAMESPACE -QV4::CallContext *QV4DataCollector::findContext(int frame) +QV4::Heap::CallContext *QV4DataCollector::findContext(int frame) { - QV4::ExecutionContext *ctx = engine()->currentContext; - while (ctx) { - QV4::CallContext *cCtxt = ctx->asCallContext(); - if (cCtxt && cCtxt->d()->v4Function) { - if (frame < 1) - return cCtxt; - --frame; - } - ctx = engine()->parentContext(ctx); + QV4::EngineBase::StackFrame *f = engine()->currentStackFrame; + while (f && frame) { + --frame; + f = f->parent; } - return 0; + return f ? f->callContext() : 0; } -QV4::Heap::CallContext *QV4DataCollector::findScope(QV4::ExecutionContext *ctxt, int scope) +QV4::Heap::CallContext *QV4DataCollector::findScope(QV4::Heap::ExecutionContext *ctx, int scope) { - if (!ctxt) + if (!ctx) return 0; - QV4::Scope s(ctxt); - QV4::ScopedContext ctx(s, ctxt); for (; scope > 0 && ctx; --scope) - ctx = ctx->d()->outer; + ctx = ctx->outer; - return (ctx && ctx->d()) ? ctx->asCallContext()->d() : 0; + return (ctx && ctx->type == QV4::Heap::ExecutionContext::Type_CallContext) ? + static_cast<QV4::Heap::CallContext *>(ctx) : 0; } QVector<QV4::Heap::ExecutionContext::ContextType> QV4DataCollector::getScopeTypes(int frame) { QVector<QV4::Heap::ExecutionContext::ContextType> types; - QV4::Scope scope(engine()); - QV4::CallContext *sctxt = findContext(frame); - if (!sctxt || sctxt->d()->type < QV4::Heap::ExecutionContext::Type_QmlContext) - return types; + QV4::Heap::ExecutionContext *it = findContext(frame); - QV4::ScopedContext it(scope, sctxt); - for (; it; it = it->d()->outer) - types.append(QV4::Heap::ExecutionContext::ContextType(it->d()->type)); + for (; it; it = it->outer) + types.append(QV4::Heap::ExecutionContext::ContextType(it->type)); return types; } diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h index 2c2514a1b3..c924f10d8c 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h @@ -58,11 +58,11 @@ public: typedef uint Ref; typedef QVector<uint> Refs; - static QV4::Heap::CallContext *findScope(QV4::ExecutionContext *ctxt, int scope); + static QV4::Heap::CallContext *findScope(QV4::Heap::ExecutionContext *ctxt, int scope); static int encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType); QVector<QV4::Heap::ExecutionContext::ContextType> getScopeTypes(int frame); - QV4::CallContext *findContext(int frame); + QV4::Heap::CallContext *findContext(int frame); QV4DataCollector(QV4::ExecutionEngine *engine); diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp index 1bd8581fbb..c95d4ea99f 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp @@ -115,7 +115,7 @@ void QV4Debugger::resume(Speed speed) if (!m_returnedValue.isUndefined()) m_returnedValue.set(m_engine, QV4::Encode::undefined()); - m_currentContext.set(m_engine, *m_engine->currentContext); + m_currentFrame = m_engine->currentStackFrame; m_stepping = speed; m_runningCondition.wakeAll(); } @@ -187,7 +187,7 @@ void QV4Debugger::maybeBreakAtInstruction() switch (m_stepping) { case StepOver: - if (m_currentContext.asManaged()->d() != m_engine->current) + if (m_currentFrame != m_engine->currentStackFrame) break; // fall through case StepIn: @@ -216,9 +216,8 @@ void QV4Debugger::enteringFunction() return; QMutexLocker locker(&m_lock); - if (m_stepping == StepIn) { - m_currentContext.set(m_engine, *m_engine->currentContext); - } + if (m_stepping == StepIn) + m_currentFrame = m_engine->currentStackFrame; } void QV4Debugger::leavingFunction(const QV4::ReturnedValue &retVal) @@ -229,13 +228,8 @@ void QV4Debugger::leavingFunction(const QV4::ReturnedValue &retVal) QMutexLocker locker(&m_lock); - if (m_stepping != NotStepping && m_currentContext.asManaged()->d() == m_engine->current) { - if (QV4::ExecutionContext *parentContext - = m_engine->parentContext(m_engine->currentContext)) { - m_currentContext.set(m_engine, *parentContext); - } else { - m_currentContext.clear(); - } + if (m_stepping != NotStepping && m_currentFrame == m_engine->currentStackFrame) { + m_currentFrame = m_currentFrame->parent; m_stepping = StepOver; m_returnedValue.set(m_engine, retVal); } @@ -255,10 +249,8 @@ void QV4Debugger::aboutToThrow() QV4::Function *QV4Debugger::getFunction() const { - QV4::Scope scope(m_engine); - QV4::ExecutionContext *context = m_engine->currentContext; - if (QV4::Function *function = context->getFunction()) - return function; + if (m_engine->currentStackFrame) + return m_engine->currentStackFrame->v4Function; else return m_engine->globalCode; } diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h index cd412e573d..b2200c47fc 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h @@ -150,7 +150,7 @@ private: void runJobUnpaused(); QV4::ExecutionEngine *m_engine; - QV4::PersistentValue m_currentContext; + QV4::EngineBase::StackFrame *m_currentFrame = 0; QMutex m_lock; QWaitCondition m_runningCondition; State m_state; diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp index 80ead1516a..45af1f44a5 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp @@ -63,26 +63,20 @@ void JavaScriptJob::run() { QV4::Scope scope(engine); - QV4::ExecutionContextSaver saver(engine); - - QV4::ExecutionContext *ctx = engine->currentContext; + QV4::ScopedContext ctx(scope, engine->currentContext()); QObject scopeObject; if (frameNr > 0) { - for (int i = 0; i < frameNr; ++i) { - ctx = engine->parentContext(ctx); - } - engine->pushContext(ctx); - ctx = engine->currentContext; + QV4::EngineBase::StackFrame *f = engine->currentStackFrame; + for (int i = 0; i < frameNr; ++i) + f = f->parent; + ctx = static_cast<QV4::ExecutionContext *>(&f->jsFrame->context); } if (context >= 0) { QQmlContext *extraContext = qmlContext(QQmlDebugService::objectForId(context)); - if (extraContext) { - engine->pushContext(QV4::QmlContext::create(ctx, QQmlContextData::get(extraContext), - &scopeObject)); - ctx = engine->currentContext; - } + if (extraContext) + ctx = QV4::QmlContext::create(ctx, QQmlContextData::get(extraContext), &scopeObject); } else if (frameNr < 0) { // Use QML context if available QQmlEngine *qmlEngine = engine->qmlEngine(); if (qmlEngine) { @@ -102,13 +96,8 @@ void JavaScriptJob::run() } } } - if (!engine->qmlContext()) { - engine->pushContext(QV4::QmlContext::create(ctx, QQmlContextData::get(qmlRootContext), - &scopeObject)); - ctx = engine->currentContext; - } - engine->pushContext(ctx->newWithContext(withContext->toObject(engine))); - ctx = engine->currentContext; + if (!engine->qmlContext()) + ctx = QV4::QmlContext::create(ctx, QQmlContextData::get(qmlRootContext), &scopeObject); } } @@ -214,12 +203,15 @@ void ValueLookupJob::run() // set if the engine is currently executing QML code. QScopedPointer<QObject> scopeObject; QV4::ExecutionEngine *engine = collector->engine(); + QV4::Scope scope(engine); + QV4::Heap::ExecutionContext *qmlContext = 0; if (engine->qmlEngine() && !engine->qmlContext()) { scopeObject.reset(new QObject); - engine->pushContext(QV4::QmlContext::create(engine->currentContext, + qmlContext = QV4::QmlContext::create(engine->currentContext(), QQmlContextData::get(engine->qmlEngine()->rootContext()), - scopeObject.data())); + scopeObject.data()); } + QV4::ScopedStackFrame frame(scope, qmlContext); for (const QJsonValue &handle : handles) { QV4DataCollector::Ref ref = handle.toInt(); if (!collector->isValidRef(ref)) { @@ -229,8 +221,6 @@ void ValueLookupJob::run() result[QString::number(ref)] = collector->lookupRef(ref, true); } flushRedundantRefs(); - if (scopeObject) - engine->popContext(); } const QString &ValueLookupJob::exceptionMessage() const diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp index 7f11cea9ab..32c67b3986 100644 --- a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp @@ -229,7 +229,7 @@ private: QV4::ExecutionEngine *m_engine; QQmlNativeDebugServiceImpl *m_service; - QV4::PersistentValue m_currentContext; + QV4::EngineBase::StackFrame *m_currentFrame = 0; Speed m_stepping; bool m_pauseRequested; bool m_runningJob; @@ -249,10 +249,7 @@ QV4::ReturnedValue NativeDebugger::evaluateExpression(const QString &expression) QV4::Scope scope(m_engine); m_runningJob = true; - QV4::ExecutionContextSaver saver(m_engine); - - QV4::ExecutionContext *ctx = m_engine->currentContext; - m_engine->pushContext(ctx); + QV4::ExecutionContext *ctx = m_engine->currentContext(); QV4::Script script(ctx, expression); script.strictMode = ctx->d()->v4Function->isStrict(); @@ -594,7 +591,7 @@ void NativeDebugger::handleContinue(QJsonObject *response, Speed speed) if (!m_returnedValue.isUndefined()) m_returnedValue.set(m_engine, QV4::Encode::undefined()); - m_currentContext.set(m_engine, *m_engine->currentContext); + m_currentFrame = m_engine->currentStackFrame; m_stepping = speed; } @@ -604,7 +601,7 @@ void NativeDebugger::maybeBreakAtInstruction() return; if (m_stepping == StepOver) { - if (m_currentContext.asManaged()->d() == m_engine->current) + if (m_currentFrame == m_engine->currentStackFrame) pauseAndWait(); return; } @@ -635,7 +632,7 @@ void NativeDebugger::enteringFunction() return; if (m_stepping == StepIn) { - m_currentContext.set(m_engine, *m_engine->currentContext); + m_currentFrame = m_engine->currentStackFrame; } } @@ -644,8 +641,8 @@ void NativeDebugger::leavingFunction(const QV4::ReturnedValue &retVal) if (m_runningJob) return; - if (m_stepping != NotStepping && m_currentContext.asManaged()->d() == m_engine->current) { - m_currentContext.set(m_engine, *m_engine->parentContext(m_engine->currentContext)); + if (m_stepping != NotStepping && m_currentFrame == m_engine->currentStackFrame) { + m_currentFrame = m_currentFrame->parent; m_stepping = StepOver; m_returnedValue.set(m_engine, retVal); } @@ -667,7 +664,7 @@ void NativeDebugger::aboutToThrow() QV4::Function *NativeDebugger::getFunction() const { - QV4::ExecutionContext *context = m_engine->currentContext; + QV4::ExecutionContext *context = m_engine->currentContext(); if (QV4::Function *function = context->getFunction()) return function; else diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 2a474eaad5..a0f1ce5879 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -2466,13 +2466,10 @@ bool Codegen::visit(WithStatement *ast) if (hasError) return false; src = src.storeOnStack(); // trigger load before we setup the exception handler, so exceptions here go to the right place + src.loadInAccumulator(); ControlFlowWith flow(this); - src.loadInAccumulator(); - Instruction::CallBuiltinPushScope pushScope; - bytecodeGenerator->addInstruction(pushScope); - statement(ast->statement); return false; diff --git a/src/qml/compiler/qv4compilercontrolflow_p.h b/src/qml/compiler/qv4compilercontrolflow_p.h index 2735761246..bbfe9e2deb 100644 --- a/src/qml/compiler/qv4compilercontrolflow_p.h +++ b/src/qml/compiler/qv4compilercontrolflow_p.h @@ -274,6 +274,13 @@ struct ControlFlowWith : public ControlFlowUnwind : ControlFlowUnwind(cg, With) { needsLookupByName = true; + + savedContextRegister = Moth::StackSlot::createRegister(generator()->newRegister()); + + // assumes the with object is in the accumulator + Instruction::CallBuiltinPushWithContext pushScope; + pushScope.reg = savedContextRegister; + generator()->addInstruction(pushScope); generator()->setExceptionHandler(&unwindLabel); } @@ -282,11 +289,13 @@ struct ControlFlowWith : public ControlFlowUnwind unwindLabel.link(); generator()->setExceptionHandler(parentExceptionHandler()); - Instruction::CallBuiltinPopScope pop; + Instruction::CallBuiltinPopContext pop; + pop.reg = savedContextRegister; generator()->addInstruction(pop); emitUnwindHandler(); } + Moth::StackSlot savedContextRegister; }; struct ControlFlowCatch : public ControlFlowUnwind @@ -330,12 +339,16 @@ struct ControlFlowCatch : public ControlFlowUnwind needsLookupByName = true; insideCatch = true; + Codegen::RegisterScope scope(cg); + // exceptions inside the try block go here exceptionLabel.link(); Reference name = Reference::fromName(cg, catchExpression->name.toString()); - Instruction::CallBuiltinPushCatchScope pushCatchScope; - pushCatchScope.name = name.unqualifiedNameIndex; - generator()->addInstruction(pushCatchScope); + Moth::StackSlot savedContextReg = Moth::StackSlot::createRegister(generator()->newRegister()); + Instruction::CallBuiltinPushCatchContext pushCatch; + pushCatch.name = name.unqualifiedNameIndex; + pushCatch.reg = savedContextReg; + generator()->addInstruction(pushCatch); // clear the unwind temp for exceptions, we want to resume normal code flow afterwards Reference::storeConstOnStack(cg, QV4::Encode::undefined(), controlFlowTemp); generator()->setExceptionHandler(&catchUnwindLabel); @@ -347,7 +360,8 @@ struct ControlFlowCatch : public ControlFlowUnwind // exceptions inside catch and break/return statements go here catchUnwindLabel.link(); - Instruction::CallBuiltinPopScope pop; + Instruction::CallBuiltinPopContext pop; + pop.reg = savedContextReg; generator()->addInstruction(pop); // break/continue/return statements in try go here diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp index ea351dcc76..db68c2d76f 100644 --- a/src/qml/compiler/qv4instr_moth.cpp +++ b/src/qml/compiler/qv4instr_moth.cpp @@ -276,15 +276,17 @@ void dumpBytecode(const char *code, int len, int nFormals) MOTH_BEGIN_INSTR(CallBuiltinUnwindException) MOTH_END_INSTR(CallBuiltinUnwindException) - MOTH_BEGIN_INSTR(CallBuiltinPushCatchScope) - d << instr.name; - MOTH_END_INSTR(CallBuiltinPushCatchScope) + MOTH_BEGIN_INSTR(CallBuiltinPushCatchContext) + d << instr.reg.dump(nFormals) << ", " << instr.name; + MOTH_END_INSTR(CallBuiltinPushCatchContext) - MOTH_BEGIN_INSTR(CallBuiltinPushScope) - MOTH_END_INSTR(CallBuiltinPushScope) + MOTH_BEGIN_INSTR(CallBuiltinPushWithContext) + d << instr.reg.dump(nFormals); + MOTH_END_INSTR(CallBuiltinPushWithContext) - MOTH_BEGIN_INSTR(CallBuiltinPopScope) - MOTH_END_INSTR(CallBuiltinPopScope) + MOTH_BEGIN_INSTR(CallBuiltinPopContext) + d << instr.reg.dump(nFormals); + MOTH_END_INSTR(CallBuiltinPopContext) MOTH_BEGIN_INSTR(CallBuiltinForeachIteratorObject) MOTH_END_INSTR(CallBuiltinForeachIteratorObject) diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index 54d085e820..52d0497926 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -111,9 +111,9 @@ QT_BEGIN_NAMESPACE F(GetException, getException) \ F(SetException, setException) \ F(CallBuiltinUnwindException, callBuiltinUnwindException) \ - F(CallBuiltinPushCatchScope, callBuiltinPushCatchScope) \ - F(CallBuiltinPushScope, callBuiltinPushScope) \ - F(CallBuiltinPopScope, callBuiltinPopScope) \ + F(CallBuiltinPushCatchContext, callBuiltinPushCatchContext) \ + F(CallBuiltinPushWithContext, callBuiltinPushWithContext) \ + F(CallBuiltinPopContext, callBuiltinPopContext) \ F(CallBuiltinForeachIteratorObject, callBuiltinForeachIteratorObject) \ F(CallBuiltinForeachNextPropertyName, callBuiltinForeachNextPropertyName) \ F(CallBuiltinDeleteMember, callBuiltinDeleteMember) \ @@ -443,15 +443,18 @@ union Instr struct instr_callBuiltinUnwindException { MOTH_INSTR_HEADER }; - struct instr_callBuiltinPushCatchScope { + struct instr_callBuiltinPushCatchContext { MOTH_INSTR_HEADER int name; + StackSlot reg; }; - struct instr_callBuiltinPushScope { + struct instr_callBuiltinPushWithContext { MOTH_INSTR_HEADER + StackSlot reg; }; - struct instr_callBuiltinPopScope { + struct instr_callBuiltinPopContext { MOTH_INSTR_HEADER + StackSlot reg; }; struct instr_callBuiltinForeachIteratorObject { MOTH_INSTR_HEADER @@ -729,9 +732,9 @@ union Instr instr_setException setException; instr_setExceptionHandler setExceptionHandler; instr_callBuiltinUnwindException callBuiltinUnwindException; - instr_callBuiltinPushCatchScope callBuiltinPushCatchScope; - instr_callBuiltinPushScope callBuiltinPushScope; - instr_callBuiltinPopScope callBuiltinPopScope; + instr_callBuiltinPushCatchContext callBuiltinPushCatchContext; + instr_callBuiltinPushWithContext callBuiltinPushWithContext; + instr_callBuiltinPopContext callBuiltinPopContext; instr_callBuiltinForeachIteratorObject callBuiltinForeachIteratorObject; instr_callBuiltinForeachNextPropertyName callBuiltinForeachNextPropertyName; instr_callBuiltinDeleteMember callBuiltinDeleteMember; diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index 5027975d84..16aa5dc728 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -438,14 +438,9 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in { QV4::ExecutionEngine *v4 = d->m_v4Engine; QV4::Scope scope(v4); - QV4::ExecutionContextSaver saver(v4); - - QV4::ExecutionContext *ctx = v4->currentContext; - if (ctx->d() != v4->rootContext()->d()) - ctx = v4->pushGlobalContext(); QV4::ScopedValue result(scope); - QV4::Script script(ctx, program, fileName, lineNumber); + QV4::Script script(v4->rootContext(), program, fileName, lineNumber); script.strictMode = false; if (v4->currentStackFrame) script.strictMode = v4->currentStackFrame->v4Function->isStrict(); @@ -458,7 +453,9 @@ QJSValue QJSEngine::evaluate(const QString& program, const QString& fileName, in if (scope.engine->hasException) result = v4->catchException(); - return QJSValue(v4, result->asReturnedValue()); + QJSValue retval(v4, result->asReturnedValue()); + + return retval; } /*! diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index ddb5dc4ea5..c9565468ad 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -232,18 +232,16 @@ bool ExecutionContext::deleteProperty(String *name) // Do a standard call with this execution context as the outer scope ReturnedValue ExecutionContext::call(ExecutionEngine *engine, CallData *callData, Function *function, const FunctionObject *f) { - Scope scope(engine); - ExecutionContextSaver ctxSaver(engine); - - Scoped<CallContext> ctx(scope, newCallContext(function, callData)); + Heap::CallContext *ctx = newCallContext(function, callData); if (f) - ctx->d()->function.set(engine, f->d()); - engine->pushContext(ctx); + ctx->function.set(engine, f->d()); - ReturnedValue res = Q_V4_PROFILE(engine, function, f); + ReturnedValue res = Q_V4_PROFILE(engine, ctx, function, f); - if (function->hasQmlDependencies) - QQmlPropertyCapture::registerQmlDependencies(engine, function->compiledFunction); + if (function->hasQmlDependencies) { + Q_ASSERT(d()->type == Heap::ExecutionContext::Type_QmlContext); + QQmlPropertyCapture::registerQmlDependencies(static_cast<QmlContext *>(this), engine, function->compiledFunction); + } return res; } @@ -258,17 +256,12 @@ ReturnedValue QV4::ExecutionContext::simpleCall(ExecutionEngine *engine, CallDat for (int i = callData->argc; i < (int)function->nFormals; ++i) callData->args[i] = Encode::undefined(); - ExecutionContext *old = engine->currentContext; - engine->currentContext = this; - engine->current = d(); - - ReturnedValue res = Q_V4_PROFILE(engine, function, 0); + ReturnedValue res = Q_V4_PROFILE(engine, d(), function, 0); - if (function->hasQmlDependencies) - QQmlPropertyCapture::registerQmlDependencies(engine, function->compiledFunction); - - engine->currentContext = old; - engine->current = old->d(); + if (function->hasQmlDependencies) { + Q_ASSERT(d()->type == Heap::ExecutionContext::Type_QmlContext); + QQmlPropertyCapture::registerQmlDependencies(static_cast<QmlContext *>(this), engine, function->compiledFunction); + } engine->jsStackTop = jsStackTop; diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 08f4f29763..d10d1d0413 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -527,9 +527,6 @@ void ExecutionEngine::initRootContext() r->d()->callData->args[0] = Encode::undefined(); jsObjects[RootContext] = r; jsObjects[IntegerNull] = Encode((int)0); - - currentContext = static_cast<ExecutionContext *>(jsObjects + RootContext); - current = currentContext->d(); } InternalClass *ExecutionEngine::newClass(const InternalClass &other) @@ -537,12 +534,10 @@ InternalClass *ExecutionEngine::newClass(const InternalClass &other) return new (classPool) InternalClass(other); } -ExecutionContext *ExecutionEngine::pushGlobalContext() +Heap::ExecutionContext *ExecutionEngine::pushGlobalContext() { - pushContext(rootContext()->d()); - - Q_ASSERT(current == rootContext()->d()); - return currentContext; + setCurrentContext(rootContext()->d()); + return currentContext()->d(); } InternalClass *ExecutionEngine::newInternalClass(const VTable *vtable, Object *prototype) @@ -746,11 +741,9 @@ Heap::Object *ExecutionEngine::newForEachIteratorObject(Object *o) Heap::QmlContext *ExecutionEngine::qmlContext() const { - Heap::ExecutionContext *ctx = current; - - // get the correct context when we're within a builtin function - if (ctx->type == Heap::ExecutionContext::Type_SimpleCallContext && !ctx->outer) - ctx = parentContext(currentContext)->d(); + if (!currentStackFrame) + return 0; + Heap::ExecutionContext *ctx = currentContext()->d(); if (ctx->type != Heap::ExecutionContext::Type_QmlContext && !ctx->outer) return 0; diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index a628af94cd..3fc79fd67d 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -354,11 +354,11 @@ public: void setProfiler(Profiling::Profiler *profiler); #endif // QT_NO_QML_DEBUGGER - ExecutionContext *pushGlobalContext(); - void pushContext(Heap::ExecutionContext *context); - void pushContext(ExecutionContext *context); - void popContext(); - ExecutionContext *parentContext(ExecutionContext *context) const; + Heap::ExecutionContext *pushGlobalContext(); + void setCurrentContext(Heap::ExecutionContext *context); + ExecutionContext *currentContext() const { + return static_cast<ExecutionContext *>(¤tStackFrame->jsFrame->context); + } InternalClass *newInternalClass(const VTable *vtable, Object *prototype); @@ -469,39 +469,9 @@ struct NoThrowEngine; #endif -inline void ExecutionEngine::pushContext(Heap::ExecutionContext *context) +inline void ExecutionEngine::setCurrentContext(Heap::ExecutionContext *context) { - Q_ASSERT(currentContext && context); - Value *v = jsAlloca(2); - v[0] = Encode(context); - v[1] = Encode((int)(v - static_cast<Value *>(currentContext))); - currentContext = static_cast<ExecutionContext *>(v); - current = currentContext->d(); -} - -inline void ExecutionEngine::pushContext(ExecutionContext *context) -{ - pushContext(context->d()); -} - - -inline void ExecutionEngine::popContext() -{ - Q_ASSERT(jsStackTop > currentContext); - QV4::Value *offset = (currentContext + 1); - Q_ASSERT(offset->isInteger()); - int o = offset->integerValue(); - Q_ASSERT(o); - currentContext -= o; - current = currentContext->d(); -} - -inline ExecutionContext *ExecutionEngine::parentContext(ExecutionContext *context) const -{ - Value *offset = static_cast<Value *>(context) + 1; - Q_ASSERT(offset->isInteger()); - int o = offset->integerValue(); - return o ? context - o : 0; + currentStackFrame->jsFrame->context = context; } inline @@ -554,6 +524,19 @@ inline bool ExecutionEngine::checkStackLimits() return false; } +inline QV4::ExecutionContext *EngineBase::StackFrame::context() const +{ + return static_cast<ExecutionContext *>(&jsFrame->context); +} + +inline QV4::Heap::CallContext *EngineBase::StackFrame::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); +} + } // namespace QV4 QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h index 2aa6910a1c..71cedfd093 100644 --- a/src/qml/jsruntime/qv4enginebase_p.h +++ b/src/qml/jsruntime/qv4enginebase_p.h @@ -62,7 +62,7 @@ namespace QV4 { #if defined(Q_CC_MSVC) || defined(Q_CC_GNU) #pragma pack(push, 1) #endif -struct EngineBase { +struct Q_QML_EXPORT EngineBase { struct JSStackFrame { // callData is directly before this Value jsFunction; @@ -80,9 +80,10 @@ struct EngineBase { QString source() const; QString function() const; + QV4::ExecutionContext *context() const; + QV4::Heap::CallContext *callContext() const; }; - Heap::ExecutionContext *current = 0; StackFrame *currentStackFrame = 0; Value *jsStackTop = 0; @@ -99,7 +100,6 @@ struct EngineBase { Value *jsStackLimit = 0; Value *jsStackBase = 0; - ExecutionContext *currentContext = 0; IdentifierTable *identifierTable = 0; Object *globalObject = 0; @@ -135,8 +135,7 @@ struct EngineBase { #endif Q_STATIC_ASSERT(std::is_standard_layout<EngineBase>::value); -Q_STATIC_ASSERT(offsetof(EngineBase, current) == 0); -Q_STATIC_ASSERT(offsetof(EngineBase, currentStackFrame) == offsetof(EngineBase, current) + QT_POINTER_SIZE); +Q_STATIC_ASSERT(offsetof(EngineBase, currentStackFrame) == 0); Q_STATIC_ASSERT(offsetof(EngineBase, jsStackTop) == offsetof(EngineBase, currentStackFrame) + QT_POINTER_SIZE); Q_STATIC_ASSERT(offsetof(EngineBase, hasException) == offsetof(EngineBase, jsStackTop) + QT_POINTER_SIZE); Q_STATIC_ASSERT(offsetof(EngineBase, memoryManager) == offsetof(EngineBase, hasException) + QT_POINTER_SIZE); diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index a6b2c0c5d0..0976d22550 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -63,7 +63,7 @@ struct Q_QML_EXPORT Function { const CompiledData::Function *compiledFunction; CompiledData::CompilationUnit *compilationUnit; - typedef ReturnedValue (*Code)(Function *, const FunctionObject *); + typedef ReturnedValue (*Code)(Heap::ExecutionContext *c, Function *, const FunctionObject *); Code code; const uchar *codeData; diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index f210ff2659..761a8282ae 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -343,16 +343,14 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const return Encode::undefined(); ExecutionEngine *v4 = engine(); - Scope scope(v4); - ExecutionContextSaver ctxSaver(scope.engine); + bool isStrict = v4->currentContext()->d()->v4Function->isStrict(); - ExecutionContext *currentContext = v4->currentContext; - ExecutionContext *ctx = currentContext; + Scope scope(v4); + ScopedContext ctx(scope, v4->currentContext()); if (!directCall) { - // the context for eval should be the global scope, so we fake a root - // context - ctx = v4->pushGlobalContext(); + // the context for eval should be the global scope + ctx = v4->rootContext(); } String *scode = callData->args[0].stringValue(); @@ -363,7 +361,7 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const bool inheritContext = !ctx->d()->v4Function->isStrict(); Script script(ctx, code, QStringLiteral("eval code")); - script.strictMode = (directCall && currentContext->d()->v4Function->isStrict()); + script.strictMode = (directCall && isStrict); script.inheritContext = inheritContext; script.parse(); if (v4->hasException) @@ -385,7 +383,7 @@ ReturnedValue EvalFunction::evalCall(CallData *callData, bool directCall) const // set the correct v4 function for the context ctx->d()->v4Function = function; - return Q_V4_PROFILE(ctx->engine(), function, 0); + return Q_V4_PROFILE(v4, ctx->d(), function, 0); } diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h index adf9853f62..be38690a49 100644 --- a/src/qml/jsruntime/qv4profiling_p.h +++ b/src/qml/jsruntime/qv4profiling_p.h @@ -61,7 +61,7 @@ #define Q_V4_PROFILE_ALLOC(engine, size, type) (!engine) #define Q_V4_PROFILE_DEALLOC(engine, size, type) (!engine) -#define Q_V4_PROFILE(engine, function, jsFunction) (function->code(function, jsFunction)) +#define Q_V4_PROFILE(engine, context, function, jsFunction) (function->code(context, function, jsFunction)) QT_BEGIN_NAMESPACE @@ -85,11 +85,11 @@ QT_END_NAMESPACE (engine->profiler()->featuresEnabled & (1 << Profiling::FeatureMemoryAllocation)) ?\ engine->profiler()->trackDealloc(size, type) : false) -#define Q_V4_PROFILE(engine, function, jsFunction)\ +#define Q_V4_PROFILE(engine, context, function, jsFunction)\ (Q_UNLIKELY(engine->profiler()) &&\ (engine->profiler()->featuresEnabled & (1 << Profiling::FeatureFunctionCall)) ?\ - Profiling::FunctionCallProfiler::profileCall(engine->profiler(), function, jsFunction) :\ - function->code(function, jsFunction)) + Profiling::FunctionCallProfiler::profileCall(engine->profiler(), context, function, jsFunction) :\ + function->code(context, function, jsFunction)) QT_BEGIN_NAMESPACE @@ -279,10 +279,10 @@ public: profiler->m_data.append(FunctionCall(function, startTime, profiler->m_timer.nsecsElapsed())); } - static ReturnedValue profileCall(Profiler *profiler, Function *function, const FunctionObject *jsFunction) + static ReturnedValue profileCall(Profiler *profiler, Heap::ExecutionContext *context, Function *function, const FunctionObject *jsFunction) { FunctionCallProfiler callProfiler(profiler, function); - return function->code(function, jsFunction); + return function->code(context, function, jsFunction); } Profiler *profiler; diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index d7f10ece97..84b3571069 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -1848,7 +1848,7 @@ const QMetaObject *Heap::QObjectMethod::metaObject() return object()->metaObject(); } -QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) const +QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionEngine *engine) const { QString result; if (const QMetaObject *metaObject = d()->metaObject()) { @@ -1867,15 +1867,15 @@ QV4::ReturnedValue QObjectMethod::method_toString(QV4::ExecutionContext *ctx) co result = QLatin1String("null"); } - return ctx->engine()->newString(result)->asReturnedValue(); + return engine->newString(result)->asReturnedValue(); } -QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) const +QV4::ReturnedValue QObjectMethod::method_destroy(QV4::ExecutionEngine *engine, const Value *args, int argc) const { if (!d()->object()) return Encode::undefined(); if (QQmlData::keepAliveDuringGarbageCollection(d()->object())) - return ctx->engine()->throwError(QStringLiteral("Invalid attempt to destroy() an indestructible object")); + return engine->throwError(QStringLiteral("Invalid attempt to destroy() an indestructible object")); int delay = 0; if (argc > 0) @@ -1898,11 +1898,10 @@ ReturnedValue QObjectMethod::call(const Managed *m, CallData *callData) ReturnedValue QObjectMethod::callInternal(CallData *callData) const { ExecutionEngine *v4 = engine(); - ExecutionContext *context = v4->currentContext; if (d()->index == DestroyMethod) - return method_destroy(context, callData->args, callData->argc); + return method_destroy(v4, callData->args, callData->argc); else if (d()->index == ToStringMethod) - return method_toString(context); + return method_toString(v4); QQmlObjectOrGadget object(d()->object()); if (!d()->object()) { diff --git a/src/qml/jsruntime/qv4qobjectwrapper_p.h b/src/qml/jsruntime/qv4qobjectwrapper_p.h index 3999b641f9..d7cc91925b 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper_p.h +++ b/src/qml/jsruntime/qv4qobjectwrapper_p.h @@ -234,8 +234,8 @@ struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject int methodIndex() const { return d()->index; } QObject *object() const { return d()->object(); } - QV4::ReturnedValue method_toString(QV4::ExecutionContext *ctx) const; - QV4::ReturnedValue method_destroy(QV4::ExecutionContext *ctx, const Value *args, int argc) const; + QV4::ReturnedValue method_toString(QV4::ExecutionEngine *engine) const; + QV4::ReturnedValue method_destroy(QV4::ExecutionEngine *ctx, const Value *args, int argc) const; static ReturnedValue call(const Managed *, CallData *callData); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 81f1efbff0..cbe8de4d28 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -310,7 +310,8 @@ ReturnedValue Runtime::method_closure(ExecutionEngine *engine, int functionId) { QV4::Function *clos = static_cast<CompiledData::CompilationUnit*>(engine->currentStackFrame->v4Function->compilationUnit)->runtimeFunctions[functionId]; Q_ASSERT(clos); - return FunctionObject::createScriptFunction(engine->currentContext, clos)->asReturnedValue(); + ExecutionContext *current = static_cast<ExecutionContext *>(&engine->currentStackFrame->jsFrame->context); + return FunctionObject::createScriptFunction(current, clos)->asReturnedValue(); } bool Runtime::method_deleteElement(ExecutionEngine *engine, const Value &base, const Value &index) @@ -347,7 +348,7 @@ bool Runtime::method_deleteName(ExecutionEngine *engine, int nameIndex) { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); - return engine->currentContext->deleteProperty(name); + return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).deleteProperty(name); } QV4::ReturnedValue Runtime::method_instanceof(ExecutionEngine *engine, const Value &lval, const Value &rval) @@ -742,7 +743,7 @@ bool Runtime::method_setActivationProperty(ExecutionEngine *engine, int nameInde { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); - return engine->currentContext->setProperty(name, value); + return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).setProperty(name, value); } ReturnedValue Runtime::method_getProperty(ExecutionEngine *engine, const Value &object, int nameIndex) @@ -769,7 +770,7 @@ ReturnedValue Runtime::method_getActivationProperty(ExecutionEngine *engine, int { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); - return engine->currentContext->getProperty(name); + return static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name); } #endif // V4_BOOTSTRAP @@ -1023,7 +1024,7 @@ ReturnedValue Runtime::method_callActivationProperty(ExecutionEngine *engine, in ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); ScopedObject base(scope); - ScopedValue func(scope, engine->currentContext->getPropertyAndBase(name, base.getRef())); + ScopedValue func(scope, static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getPropertyAndBase(name, base.getRef())); if (scope.engine->hasException) return Encode::undefined(); @@ -1129,7 +1130,7 @@ ReturnedValue Runtime::method_constructActivationProperty(ExecutionEngine *engin { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); - ScopedValue func(scope, engine->currentContext->getProperty(name)); + ScopedValue func(scope, static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name)); if (scope.engine->hasException) return Encode::undefined(); @@ -1216,7 +1217,7 @@ QV4::ReturnedValue Runtime::method_typeofName(ExecutionEngine *engine, int nameI { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); - ScopedValue prop(scope, engine->currentContext->getProperty(name)); + ScopedValue prop(scope, static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).getProperty(name)); // typeof doesn't throw. clear any possible exception scope.engine->hasException = false; return method_typeofValue(engine, prop); @@ -1234,35 +1235,34 @@ ReturnedValue Runtime::method_unwindException(ExecutionEngine *engine) * * Instead the push/pop pair acts as a non local scope. */ -void Runtime::method_pushWithScope(const Value &o, NoThrowEngine *engine) +ReturnedValue Runtime::method_pushWithContext(const Value &o, NoThrowEngine *engine) { - QV4::Value *v = engine->jsAlloca(1); - Heap::Object *withObject = o.toObject(engine); - *v = withObject; - engine->pushContext(engine->currentContext->newWithContext(withObject)); - Q_ASSERT(engine->jsStackTop == engine->currentContext + 2); + Q_ASSERT(o.isObject()); + ExecutionContext *c = engine->currentContext(); + ReturnedValue oldContext = c->asReturnedValue(); + const Object &obj = static_cast<const Object &>(o); + engine->setCurrentContext(c->newWithContext(obj.d())); + return oldContext; } -void Runtime::method_pushCatchScope(NoThrowEngine *engine, int exceptionVarNameIndex) +ReturnedValue Runtime::method_pushCatchContext(NoThrowEngine *engine, int exceptionVarNameIndex) { - engine->jsAlloca(1); // keep this symmetric with pushWithScope - ExecutionContext *c = engine->currentContext; - engine->pushContext(c->newCatchContext(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[exceptionVarNameIndex], engine->catchException(0))); - Q_ASSERT(engine->jsStackTop == engine->currentContext + 2); + ExecutionContext *c = engine->currentContext(); + ReturnedValue oldContext = c->asReturnedValue(); + engine->setCurrentContext(c->newCatchContext(engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[exceptionVarNameIndex], engine->catchException(0))); + return oldContext; } -void Runtime::method_popScope(NoThrowEngine *engine) +void Runtime::method_popContext(NoThrowEngine *engine, const Value &oldContext) { - Q_ASSERT(engine->jsStackTop == engine->currentContext + 2); - engine->popContext(); - engine->jsStackTop -= 3; + engine->setCurrentContext(static_cast<const ExecutionContext &>(oldContext).d()); } void Runtime::method_declareVar(ExecutionEngine *engine, bool deletable, int nameIndex) { Scope scope(engine); ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); - engine->currentContext->createMutableBinding(name, deletable); + static_cast<ExecutionContext &>(engine->currentStackFrame->jsFrame->context).createMutableBinding(name, deletable); } ReturnedValue Runtime::method_arrayLiteral(ExecutionEngine *engine, Value *values, uint length) @@ -1314,16 +1314,16 @@ ReturnedValue Runtime::method_objectLiteral(ExecutionEngine *engine, const QV4:: QV4::ReturnedValue Runtime::method_createMappedArgumentsObject(ExecutionEngine *engine) { - Q_ASSERT(engine->current->type == Heap::ExecutionContext::Type_CallContext); - QV4::CallContext *c = static_cast<QV4::CallContext *>(engine->currentContext); + Q_ASSERT(engine->currentContext()->d()->type == Heap::ExecutionContext::Type_CallContext); + QV4::CallContext *c = static_cast<QV4::CallContext *>(&engine->currentStackFrame->jsFrame->context); QV4::InternalClass *ic = engine->internalClasses[EngineBase::Class_ArgumentsObject]; return engine->memoryManager->allocObject<ArgumentsObject>(ic, engine->objectPrototype(), c, false)->asReturnedValue(); } QV4::ReturnedValue Runtime::method_createUnmappedArgumentsObject(ExecutionEngine *engine) { - Q_ASSERT(engine->current->type == Heap::ExecutionContext::Type_CallContext); - QV4::CallContext *c = static_cast<QV4::CallContext *>(engine->currentContext); + Q_ASSERT(engine->currentContext()->d()->type == Heap::ExecutionContext::Type_CallContext); + QV4::CallContext *c = static_cast<QV4::CallContext *>(&engine->currentStackFrame->jsFrame->context); QV4::InternalClass *ic = engine->internalClasses[EngineBase::Class_StrictArgumentsObject]; return engine->memoryManager->allocObject<ArgumentsObject>(ic, engine->objectPrototype(), c, true)->asReturnedValue(); } @@ -1427,7 +1427,7 @@ QV4::ReturnedValue Runtime::method_getQmlSingleton(QV4::NoThrowEngine *engine, i void Runtime::method_convertThisToObject(ExecutionEngine *engine) { - Value *t = &engine->current->callData->thisObject; + Value *t = &engine->currentContext()->d()->callData->thisObject; if (t->isObject()) return; if (t->isNullOrUndefined()) { diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h index d67761ccfc..3e448eb02b 100644 --- a/src/qml/jsruntime/qv4runtimeapi_p.h +++ b/src/qml/jsruntime/qv4runtimeapi_p.h @@ -127,9 +127,9 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> { /* exceptions & scopes */ \ F(void, throwException, (ExecutionEngine *engine, const Value &value)) \ F(ReturnedValue, unwindException, (ExecutionEngine *engine)) \ - F(void, pushWithScope, (const Value &o, NoThrowEngine *engine)) \ - F(void, pushCatchScope, (NoThrowEngine *engine, int exceptionVarNameIndex)) \ - F(void, popScope, (NoThrowEngine *engine)) \ + F(ReturnedValue, pushWithContext, (const Value &o, NoThrowEngine *engine)) \ + F(ReturnedValue, pushCatchContext, (NoThrowEngine *engine, int exceptionVarNameIndex)) \ + F(void, popContext, (NoThrowEngine *engine, const Value &oldContext)) \ \ /* closures */ \ F(ReturnedValue, closure, (ExecutionEngine *engine, int functionId)) \ diff --git a/src/qml/jsruntime/qv4scopedvalue_p.h b/src/qml/jsruntime/qv4scopedvalue_p.h index 5e3e71a30f..26b15838f3 100644 --- a/src/qml/jsruntime/qv4scopedvalue_p.h +++ b/src/qml/jsruntime/qv4scopedvalue_p.h @@ -371,6 +371,25 @@ struct ScopedCallData { CallData *ptr; }; +struct ScopedStackFrame { + Scope &scope; + EngineBase::StackFrame frame; + + ScopedStackFrame(Scope &scope, Heap::ExecutionContext *context) + : scope(scope) + { + frame.parent = scope.engine->currentStackFrame; + if (!context) + return; + frame.jsFrame = reinterpret_cast<EngineBase::JSStackFrame *>(scope.alloc(sizeof(EngineBase::JSStackFrame)/sizeof(Value))); + frame.jsFrame->context = context; + frame.v4Function = frame.parent ? frame.parent->v4Function : 0; + scope.engine->currentStackFrame = &frame; + } + ~ScopedStackFrame() { + scope.engine->currentStackFrame = frame.parent; + } +}; inline Value &Value::operator =(const ScopedValue &v) { @@ -399,25 +418,6 @@ struct ScopedProperty Property *property; }; -struct ExecutionContextSaver -{ - ExecutionEngine *engine; - ExecutionContext *savedContext; - - ExecutionContextSaver(ExecutionEngine *engine) - : engine(engine) - { - savedContext = engine->currentContext; - } - ~ExecutionContextSaver() - { - Q_ASSERT(engine->jsStackTop > engine->currentContext); - engine->currentContext = savedContext; - engine->current = savedContext->d(); - } -}; - - } QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 1b28882280..ef85ce43de 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -148,11 +148,10 @@ ReturnedValue Script::run() if (qmlContext.isUndefined()) { TemporaryAssignment<Function*> savedGlobalCode(engine->globalCode, vmFunction); - ExecutionContextSaver ctxSaver(valueScope.engine); ContextStateSaver stateSaver(valueScope, scope); scope->d()->v4Function = vmFunction; - return Q_V4_PROFILE(engine, vmFunction, 0); + return Q_V4_PROFILE(engine, scope->d(), vmFunction, 0); } else { Scoped<QmlContext> qml(valueScope, qmlContext.value()); ScopedCallData callData(valueScope); diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 97e9a90b5a..20c4f2ece6 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -373,10 +373,9 @@ static struct InstrCount { if (engine->hasException) \ goto catchException -static inline QV4::Heap::ExecutionContext *getScope(QV4::Heap::ExecutionContext *functionScope, - int level) +static inline QV4::Heap::ExecutionContext *getScope(EngineBase::JSStackFrame *frame, int level) { - QV4::Heap::ExecutionContext *scope = functionScope; + QV4::Heap::ExecutionContext *scope = static_cast<ExecutionContext &>(frame->context).d(); while (level > 0) { --level; scope = scope->outer; @@ -385,46 +384,40 @@ static inline QV4::Heap::ExecutionContext *getScope(QV4::Heap::ExecutionContext return scope; } -static inline ReturnedValue loadScopedLocal(ExecutionEngine *engine, int index, int scope) +static inline ReturnedValue loadScopedLocal(EngineBase::StackFrame &frame, int index, int scope) { - auto ctxt = getScope(engine->current, scope); + auto ctxt = getScope(frame.jsFrame, scope); Q_ASSERT(ctxt->type == QV4::Heap::ExecutionContext::Type_CallContext); auto cc = static_cast<Heap::CallContext *>(ctxt); return cc->locals[index].asReturnedValue(); } -static inline void storeScopedLocal(ExecutionEngine *engine, int index, int scope, +static inline void storeScopedLocal(ExecutionEngine *engine, EngineBase::StackFrame &frame, int index, int scope, const QV4::Value &value) { - auto ctxt = getScope(engine->current, scope); + auto ctxt = getScope(frame.jsFrame, scope); Q_ASSERT(ctxt->type == QV4::Heap::ExecutionContext::Type_CallContext); auto cc = static_cast<Heap::CallContext *>(ctxt); - if (Q_UNLIKELY(engine->writeBarrierActive)) - QV4::WriteBarrier::write(engine, cc, cc->locals.values + index, value); - else - *(cc->locals.values + index) = value; + QV4::WriteBarrier::write(engine, cc, cc->locals.values + index, value); } -static inline ReturnedValue loadScopedArg(ExecutionEngine *engine, int index, int scope) +static inline ReturnedValue loadScopedArg(EngineBase::StackFrame &frame, int index, int scope) { - auto ctxt = getScope(engine->current, scope); + auto ctxt = getScope(frame.jsFrame, scope); Q_ASSERT(ctxt->type == QV4::Heap::ExecutionContext::Type_CallContext); auto cc = static_cast<Heap::CallContext *>(ctxt); return cc->callData->args[index].asReturnedValue(); } -static inline void storeScopedArg(ExecutionEngine *engine, int index, int scope, +static inline void storeScopedArg(ExecutionEngine *engine, EngineBase::StackFrame &frame, int index, int scope, const QV4::Value &value) { - auto ctxt = getScope(engine->current, scope); + auto ctxt = getScope(frame.jsFrame, scope); Q_ASSERT(ctxt->type == QV4::Heap::ExecutionContext::Type_CallContext); auto cc = static_cast<Heap::CallContext *>(ctxt); - if (Q_UNLIKELY(engine->writeBarrierActive)) - QV4::WriteBarrier::write(engine, cc, cc->callData->args + index, value); - else - *(cc->callData->args + index) = value; + QV4::WriteBarrier::write(engine, cc, cc->callData->args + index, value); } static inline const QV4::Value &constant(Function *function, int index) @@ -432,7 +425,7 @@ static inline const QV4::Value &constant(Function *function, int index) return function->compilationUnit->constants[index]; } -QV4::ReturnedValue VME::exec(Function *function, const FunctionObject *jsFunction) +QV4::ReturnedValue VME::exec(Heap::ExecutionContext *context, Function *function, const FunctionObject *jsFunction) { qt_v4ResolvePendingBreakpointsHook(); @@ -458,13 +451,14 @@ QV4::ReturnedValue VME::exec(Function *function, const FunctionObject *jsFunctio if (!function->canUseSimpleFunction()) { int nFormals = function->nFormals; stack = scope.alloc(nFormals + 1 + function->compiledFunction->nRegisters + sizeof(EngineBase::JSStackFrame)/sizeof(QV4::Value)); - memcpy(stack, &engine->current->callData->thisObject, (nFormals + 1)*sizeof(Value)); +// ### why copy those on the stack again? + memcpy(stack, &context->callData->thisObject, (nFormals + 1)*sizeof(Value)); stack += nFormals + 1; } else { stack = scope.alloc(function->compiledFunction->nRegisters + sizeof(EngineBase::JSStackFrame)/sizeof(QV4::Value)); } frame.jsFrame = reinterpret_cast<EngineBase::JSStackFrame *>(stack); - frame.jsFrame->context = engine->current; + frame.jsFrame->context = context; if (jsFunction) frame.jsFrame->jsFunction = *jsFunction; @@ -504,21 +498,21 @@ QV4::ReturnedValue VME::exec(Function *function, const FunctionObject *jsFunctio MOTH_END_INSTR(MoveReg) MOTH_BEGIN_INSTR(LoadScopedLocal) - accumulator = loadScopedLocal(engine, instr.index, instr.scope); + accumulator = loadScopedLocal(frame, instr.index, instr.scope); MOTH_END_INSTR(LoadScopedLocal) MOTH_BEGIN_INSTR(StoreScopedLocal) CHECK_EXCEPTION; - storeScopedLocal(engine, instr.index, instr.scope, accumulator); + storeScopedLocal(engine, frame, instr.index, instr.scope, accumulator); MOTH_END_INSTR(StoreScopedLocal) MOTH_BEGIN_INSTR(LoadScopedArgument) - accumulator = loadScopedArg(engine, instr.index, instr.scope); + accumulator = loadScopedArg(frame, instr.index, instr.scope); MOTH_END_INSTR(LoadScopedArgument) MOTH_BEGIN_INSTR(StoreScopedArgument) CHECK_EXCEPTION; - storeScopedArg(engine, instr.index, instr.scope, accumulator); + storeScopedArg(engine, frame, instr.index, instr.scope, accumulator); MOTH_END_INSTR(StoreScopedArgument) MOTH_BEGIN_INSTR(LoadRuntimeString) @@ -675,18 +669,19 @@ QV4::ReturnedValue VME::exec(Function *function, const FunctionObject *jsFunctio STORE_ACCUMULATOR(Runtime::method_unwindException(engine)); MOTH_END_INSTR(CallBuiltinUnwindException) - MOTH_BEGIN_INSTR(CallBuiltinPushCatchScope) - Runtime::method_pushCatchScope(static_cast<QV4::NoThrowEngine*>(engine), instr.name); - MOTH_END_INSTR(CallBuiltinPushCatchScope) + MOTH_BEGIN_INSTR(CallBuiltinPushCatchContext) + STACK_VALUE(instr.reg) = Runtime::method_pushCatchContext(static_cast<QV4::NoThrowEngine*>(engine), instr.name); + MOTH_END_INSTR(CallBuiltinPushCatchContext) - MOTH_BEGIN_INSTR(CallBuiltinPushScope) - Runtime::method_pushWithScope(accumulator, static_cast<QV4::NoThrowEngine*>(engine)); + MOTH_BEGIN_INSTR(CallBuiltinPushWithContext) + accumulator = accumulator.toObject(engine); CHECK_EXCEPTION; - MOTH_END_INSTR(CallBuiltinPushScope) + STACK_VALUE(instr.reg) = Runtime::method_pushWithContext(accumulator, static_cast<QV4::NoThrowEngine*>(engine)); + MOTH_END_INSTR(CallBuiltinPushWithContext) - MOTH_BEGIN_INSTR(CallBuiltinPopScope) - Runtime::method_popScope(static_cast<QV4::NoThrowEngine*>(engine)); - MOTH_END_INSTR(CallBuiltinPopScope) + MOTH_BEGIN_INSTR(CallBuiltinPopContext) + Runtime::method_popContext(static_cast<QV4::NoThrowEngine*>(engine), STACK_VALUE(instr.reg)); + MOTH_END_INSTR(CallBuiltinPopContext) MOTH_BEGIN_INSTR(CallBuiltinForeachIteratorObject) STORE_ACCUMULATOR(Runtime::method_foreachIterator(engine, accumulator)); @@ -1101,7 +1096,7 @@ QV4::ReturnedValue VME::exec(Function *function, const FunctionObject *jsFunctio #endif // QT_NO_QML_DEBUGGER MOTH_BEGIN_INSTR(LoadThis) - STORE_ACCUMULATOR(engine->currentContext->thisObject()); + STORE_ACCUMULATOR(static_cast<ExecutionContext &>(frame.jsFrame->context).thisObject()); MOTH_END_INSTR(LoadThis) MOTH_BEGIN_INSTR(LoadQmlContext) diff --git a/src/qml/jsruntime/qv4vme_moth_p.h b/src/qml/jsruntime/qv4vme_moth_p.h index 5055af65fd..04efb2cb06 100644 --- a/src/qml/jsruntime/qv4vme_moth_p.h +++ b/src/qml/jsruntime/qv4vme_moth_p.h @@ -65,7 +65,7 @@ namespace Moth { class VME { public: - static QV4::ReturnedValue exec(QV4::Function *, const FunctionObject *jsFunction = 0); + static QV4::ReturnedValue exec(Heap::ExecutionContext *context, QV4::Function *, const FunctionObject *jsFunction = 0); }; } // namespace Moth diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 3b15157ff5..0ebeb48ea4 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -1210,8 +1210,7 @@ void QQmlComponentPrivate::setInitialProperties(QV4::ExecutionEngine *engine, QV if (engine->hasException) return; - QV4::ExecutionContextSaver saver(scope.engine); - engine->pushContext(qmlContext); + QV4::ScopedStackFrame frame(scope, qmlContext->d()); while (1) { name = it.nextPropertyNameAsString(val); diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 231708da70..417698b5e8 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -339,7 +339,7 @@ void QQmlPropertyCapture::captureProperty(QObject *o, int c, int n, Duration dur } } -void QQmlPropertyCapture::registerQmlDependencies(const QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction) +void QQmlPropertyCapture::registerQmlDependencies(QV4::QmlContext *context, const QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction) { // Let the caller check and avoid the function call :) Q_ASSERT(compiledFunction->hasQmlDependencies()); @@ -356,8 +356,8 @@ void QQmlPropertyCapture::registerQmlDependencies(const QV4::ExecutionEngine *en capture->expression->m_permanentDependenciesRegistered = true; - QV4::Heap::QmlContext *context = engine->qmlContext(); - QQmlContextData *qmlContext = context->qml()->context->contextData(); + QV4::Heap::QQmlContextWrapper *wrapper = context->d()->qml(); + QQmlContextData *qmlContext = wrapper->context->contextData(); const QV4::CompiledData::LEUInt32 *idObjectDependency = compiledFunction->qmlIdObjectDependencyTable(); const int idObjectDependencyCount = compiledFunction->nDependingIdObjects; @@ -377,7 +377,7 @@ void QQmlPropertyCapture::registerQmlDependencies(const QV4::ExecutionEngine *en QQmlPropertyCapture::Permanently); } - QObject *scopeObject = context->qml()->scopeObject; + QObject *scopeObject = wrapper->scopeObject; const QV4::CompiledData::LEUInt32 *scopePropertyDependency = compiledFunction->qmlScopePropertiesDependencyTable(); const int scopePropertyDependencyCount = compiledFunction->nDependingScopeProperties; for (int i = 0; i < scopePropertyDependencyCount; ++i) { diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index 84be5b673f..f6993436f1 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -203,7 +203,7 @@ public: Permanently }; - static void registerQmlDependencies(const QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction); + static void registerQmlDependencies(QV4::QmlContext *context, const QV4::ExecutionEngine *engine, const QV4::CompiledData::Function *compiledFunction); void captureProperty(QQmlNotifier *, Duration duration = OnlyOnce); void captureProperty(QObject *, int, int, Duration duration = OnlyOnce); diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 0672618225..eebf6ccd1e 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -224,8 +224,6 @@ public: void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e) { - QV4::ExecutionEngine *v4 = QV8Engine::getV4(e->handle()); - v4->pushGlobalContext(); if (scriptCallback && scriptApi(e).isUndefined()) { setScriptApi(e, scriptCallback(e, e)); } else if (qobjectCallback && !qobjectApi(e)) { @@ -241,7 +239,6 @@ void QQmlType::SingletonInstanceInfo::init(QQmlEngine *e) QObject *o = component.create(); setQObjectApi(e, o); } - v4->popContext(); } void QQmlType::SingletonInstanceInfo::destroy(QQmlEngine *e) |