diff options
author | Lars Knoll <lars.knoll@qt.io> | 2018-05-04 15:16:08 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@qt.io> | 2018-05-11 07:17:05 +0000 |
commit | 4cf7e80c5740912804383e4d866ba12b2520d0e6 (patch) | |
tree | 143d960492aa166a7f3d7111b64151c42234a81f /src/qml | |
parent | 2fc50421c86134b5b42a4ba68aa7f6b87cfd7d74 (diff) |
Ensure we have a lexical scope for global code
This requires a bit more work than simply pushing a
new BlockContext for the lexically declared variables,
as eval() and the Function constructor operate on the
global scope (including the lexically declared names).
To fix this introduce Push/PopScriptContext instructions,
that create a BlockContext for the lexically declared
vars and pushes that one as a global script context that
eval and friends use.
Change-Id: I0fd0b0f682f82e250545e874fe93978449fe5e46
Reviewed-by: Simon Hausmann <simon.hausmann@qt.io>
Diffstat (limited to 'src/qml')
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 13 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilercontext.cpp | 76 | ||||
-rw-r--r-- | src/qml/compiler/qv4compilerscanfunctions.cpp | 30 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth.cpp | 7 | ||||
-rw-r--r-- | src/qml/compiler/qv4instr_moth_p.h | 4 | ||||
-rw-r--r-- | src/qml/jit/qv4jit.cpp | 34 | ||||
-rw-r--r-- | src/qml/jit/qv4jit_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4context.cpp | 10 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine.cpp | 1 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4engine_p.h | 3 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4functionobject.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4generatorobject.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4globalobject.cpp | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtime.cpp | 16 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4runtimeapi_p.h | 2 | ||||
-rw-r--r-- | src/qml/jsruntime/qv4vme_moth.cpp | 14 |
16 files changed, 161 insertions, 57 deletions
diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 837649a7dc..f55e6205dc 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -2343,6 +2343,11 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, ControlFlow *savedControlFlow = controlFlow; controlFlow = nullptr; + if (_context->contextType == ContextType::Global) { + _module->blocks.append(_context); + _context->blockIndex = _module->blocks.count() - 1; + } + _context->hasDirectEval |= (_context->contextType == ContextType::Eval || _context->contextType == ContextType::Global || _module->debugMode); // Conditional breakpoints are like eval in the function // When a user writes the following QML signal binding: @@ -2372,6 +2377,12 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, returnAddress = bytecodeGenerator->newRegister(); qSwap(_returnAddress, returnAddress); + // register the lexical scope for global code + if (!_context->parent && _context->requiresExecutionContext) { + _module->blocks.append(_context); + _context->blockIndex = _module->blocks.count() - 1; + } + RegisterScope registerScope(this); _context->emitBlockHeader(this); @@ -2414,6 +2425,8 @@ int Codegen::defineFunction(const QString &name, AST::Node *ast, statementList(body); + _context->emitBlockFooter(this, -1); + if (hasError || !endsWithReturn(_module, body)) { bytecodeGenerator->setLocation(ast->lastSourceLocation()); if (requiresReturnValue) { diff --git a/src/qml/compiler/qv4compilercontext.cpp b/src/qml/compiler/qv4compilercontext.cpp index 7dc8b68d78..67afea28ab 100644 --- a/src/qml/compiler/qv4compilercontext.cpp +++ b/src/qml/compiler/qv4compilercontext.cpp @@ -113,11 +113,14 @@ Context::ResolvedName Context::resolveName(const QString &name) ResolvedName result; - while (c->parent) { + while (c) { if (c->isWithBlock) return result; Context::Member m = c->findMember(name); + if (!c->parent && m.index < 0) + break; + if (m.type != Context::UndefinedMember) { result.type = m.canEscape ? ResolvedName::Local : ResolvedName::Stack; result.scope = scope; @@ -164,9 +167,13 @@ int Context::emitBlockHeader(Codegen *codegen) setupFunctionIndices(bytecodeGenerator); int contextReg = -1; - if (requiresExecutionContext || + if (requiresExecutionContext && contextType == ContextType::Global) { + Instruction::PushScriptContext scriptContext; + scriptContext.index = blockIndex; + bytecodeGenerator->addInstruction(scriptContext); + } else if (requiresExecutionContext || contextType == ContextType::Binding) { // we don't really need this for bindings, but we do for signal handlers, and we don't know if the code is a signal handler or not. - if (contextType == ContextType::Block) { + if (contextType == ContextType::Block || (contextType == ContextType::Eval && !isStrict)) { if (isCatchBlock) { Instruction::PushCatchContext catchContext; catchContext.index = blockIndex; @@ -190,10 +197,21 @@ int Context::emitBlockHeader(Codegen *codegen) bytecodeGenerator->addInstruction(convert); } - switch (contextType) { - case ContextType::Block: - case ContextType::Function: - case ContextType::Binding: { + if (contextType == ContextType::Global || (contextType == ContextType::Eval && !isStrict)) { + // variables in global code are properties of the global context object, not locals as with other functions. + for (Context::MemberMap::const_iterator it = members.constBegin(), cend = members.constEnd(); it != cend; ++it) { + if (it->isLexicallyScoped()) + continue; + const QString &local = it.key(); + + Instruction::DeclareVar declareVar; + declareVar.isDeletable = (contextType == ContextType::Eval); + declareVar.varName = codegen->registerString(local); + bytecodeGenerator->addInstruction(declareVar); + } + } + + if (contextType == ContextType::Function || contextType == ContextType::Binding) { for (Context::MemberMap::iterator it = members.begin(), end = members.end(); it != end; ++it) { if (it->canEscape && it->type == Context::ThisFunctionName) { // move the function from the stack to the call context @@ -205,20 +223,6 @@ int Context::emitBlockHeader(Codegen *codegen) bytecodeGenerator->addInstruction(store); } } - break; - } - case ContextType::Global: - case ContextType::Eval: { - // variables in global code are properties of the global context object, not locals as with other functions. - for (Context::MemberMap::const_iterator it = members.constBegin(), cend = members.constEnd(); it != cend; ++it) { - const QString &local = it.key(); - - Instruction::DeclareVar declareVar; - declareVar.isDeletable = false; - declareVar.varName = codegen->registerString(local); - bytecodeGenerator->addInstruction(declareVar); - } - } } if (usesArgumentsObject == Context::ArgumentsObjectUsed) { @@ -237,20 +241,11 @@ int Context::emitBlockHeader(Codegen *codegen) if (member.function) { const int function = codegen->defineFunction(member.function->name.toString(), member.function, member.function->formals, member.function->body); codegen->loadClosure(function); - if (!parent) { - Codegen::Reference::fromName(codegen, member.function->name.toString()).storeConsumeAccumulator(); - } else { - int idx = member.index; - Q_ASSERT(idx >= 0); - Codegen::Reference local = member.canEscape ? Codegen::Reference::fromScopedLocal(codegen, idx, 0) - : Codegen::Reference::fromStackSlot(codegen, idx, true); - local.storeConsumeAccumulator(); - } + Codegen::Reference r = codegen->referenceForName(member.function->name.toString(), true); + r.storeConsumeAccumulator(); } } - - return contextReg; } @@ -259,7 +254,12 @@ void Context::emitBlockFooter(Codegen *codegen, int oldContextReg) using Instruction = Moth::Instruction; Moth::BytecodeGenerator *bytecodeGenerator = codegen->generator(); - if (oldContextReg != -1) { + if (requiresExecutionContext && contextType == ContextType::Global) { +QT_WARNING_PUSH +QT_WARNING_DISABLE_GCC("-Wmaybe-uninitialized") // the loads below are empty structs. + bytecodeGenerator->addInstruction(Instruction::PopScriptContext()); +QT_WARNING_POP + } else if (oldContextReg != -1) { Instruction::PopContext popContext; popContext.reg = oldContextReg; bytecodeGenerator->addInstruction(popContext); @@ -292,6 +292,16 @@ void Context::setupFunctionIndices(Moth::BytecodeGenerator *bytecodeGenerator) } case ContextType::Global: case ContextType::Eval: + for (Context::MemberMap::iterator it = members.begin(), end = members.end(); it != end; ++it) { + if (!it->isLexicallyScoped() && (contextType == ContextType::Global || !isStrict)) + continue; + if (it->canEscape) { + it->index = locals.size(); + locals.append(it.key()); + } else { + it->index = bytecodeGenerator->newRegister(); + } + } break; } nRegisters = bytecodeGenerator->registerCount() - registerOffset; diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp index 47329e978b..f7100a1d1a 100644 --- a/src/qml/compiler/qv4compilerscanfunctions.cpp +++ b/src/qml/compiler/qv4compilerscanfunctions.cpp @@ -522,20 +522,19 @@ void ScanFunctions::calcEscapingVariables() if (current->isWithBlock || current->contextType != ContextType::Block) break; } + Q_ASSERT(c != inner); while (c) { Context::MemberMap::const_iterator it = c->members.find(var); if (it != c->members.end()) { - if (c != inner) { + if (c->parent || it->isLexicallyScoped()) { it->canEscape = true; c->requiresExecutionContext = true; } break; } if (c->findArgument(var) != -1) { - if (c != inner) { - c->argumentsCanEscape = true; - c->requiresExecutionContext = true; - } + c->argumentsCanEscape = true; + c->requiresExecutionContext = true; break; } c = c->parent; @@ -551,18 +550,21 @@ void ScanFunctions::calcEscapingVariables() bool allVarsEscape = c->hasDirectEval; if (allVarsEscape && c->contextType == ContextType::Block && c->members.isEmpty()) allVarsEscape = false; - if (m->debugMode) + if (!c->parent || m->debugMode) allVarsEscape = true; if (allVarsEscape) { - c->requiresExecutionContext = true; - c->argumentsCanEscape = true; + if (c->parent) { + c->requiresExecutionContext = true; + c->argumentsCanEscape = true; + } else { + for (const auto &m : qAsConst(c->members)) { + if (m.isLexicallyScoped()) { + c->requiresExecutionContext = true; + break; + } + } + } } - // ### for now until we have lexically scoped vars that'll require it - if (c->contextType == ContextType::Global) - c->requiresExecutionContext = false; - // ### Shouldn't be required, we could probably rather change the ContextType to FunctionCode for strict eval - if (c->contextType == ContextType::Eval && c->isStrict) - c->requiresExecutionContext = true; if (c->contextType == ContextType::Block && c->isCatchBlock) { c->requiresExecutionContext = true; auto m = c->members.find(c->catchedVariable); diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp index 6ef4e79344..d4abc59a8b 100644 --- a/src/qml/compiler/qv4instr_moth.cpp +++ b/src/qml/compiler/qv4instr_moth.cpp @@ -415,6 +415,13 @@ void dumpBytecode(const char *code, int len, int nLocals, int nFormals, int /*st d << dumpRegister(reg, nFormals) << ", " << index; MOTH_END_INSTR(PushBlockContext) + MOTH_BEGIN_INSTR(PushScriptContext) + d << index; + MOTH_END_INSTR(PushScriptContext) + + MOTH_BEGIN_INSTR(PopScriptContext) + MOTH_END_INSTR(PopScriptContext) + MOTH_BEGIN_INSTR(PopContext) d << dumpRegister(reg, nFormals); MOTH_END_INSTR(PopContext) diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index 546e8fd2de..d12d1a53cc 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -117,6 +117,8 @@ QT_BEGIN_NAMESPACE #define INSTR_PushCatchContext(op) INSTRUCTION(op, PushCatchContext, 3, reg, index, name) #define INSTR_PushWithContext(op) INSTRUCTION(op, PushWithContext, 1, reg) #define INSTR_PushBlockContext(op) INSTRUCTION(op, PushBlockContext, 2, reg, index) +#define INSTR_PushScriptContext(op) INSTRUCTION(op, PushScriptContext, 1, index) +#define INSTR_PopScriptContext(op) INSTRUCTION(op, PopScriptContext, 0) #define INSTR_PopContext(op) INSTRUCTION(op, PopContext, 1, reg) #define INSTR_GetIterator(op) INSTRUCTION(op, GetIterator, 1, iterator) #define INSTR_DeleteMember(op) INSTRUCTION(op, DeleteMember, 2, member, base) @@ -240,6 +242,8 @@ QT_BEGIN_NAMESPACE F(PushCatchContext) \ F(PushWithContext) \ F(PushBlockContext) \ + F(PushScriptContext) \ + F(PopScriptContext) \ F(PopContext) \ F(GetIterator) \ F(DeleteMember) \ diff --git a/src/qml/jit/qv4jit.cpp b/src/qml/jit/qv4jit.cpp index 16b6b5fb94..f659ddfb00 100644 --- a/src/qml/jit/qv4jit.cpp +++ b/src/qml/jit/qv4jit.cpp @@ -659,6 +659,34 @@ void BaselineJIT::generate_PushBlockContext(int reg, int index) JIT_GENERATE_RUNTIME_CALL(pushBlockContextHelper, Assembler::IgnoreResult); } +static void pushScriptContextHelper(QV4::Value *stack, ExecutionEngine *engine, int index) +{ + stack[CallData::Context] = Runtime::method_createScriptContext(engine, index); +} + +void BaselineJIT::generate_PushScriptContext(int index) +{ + as->saveAccumulatorInFrame(); + as->prepareCallWithArgCount(3); + as->passInt32AsArg(index, 2); + as->passEngineAsArg(1); + as->passRegAsArg(0, 0); + JIT_GENERATE_RUNTIME_CALL(pushScriptContextHelper, Assembler::IgnoreResult); +} + +static void popScriptContextHelper(QV4::Value *stack, ExecutionEngine *engine) +{ + stack[CallData::Context] = Runtime::method_popScriptContext(engine); +} + +void BaselineJIT::generate_PopScriptContext() +{ + as->saveAccumulatorInFrame(); + as->prepareCallWithArgCount(2); + as->passEngineAsArg(1); + as->passRegAsArg(0, 0); + JIT_GENERATE_RUNTIME_CALL(popScriptContextHelper, Assembler::IgnoreResult); +} void BaselineJIT::generate_PopContext(int reg) { as->popContext(reg); } @@ -1208,6 +1236,12 @@ void BaselineJIT::collectLabelsInBytecode() MOTH_BEGIN_INSTR(PushBlockContext) MOTH_END_INSTR(PushBlockContext) + MOTH_BEGIN_INSTR(PushScriptContext) + MOTH_END_INSTR(PushScriptContext) + + MOTH_BEGIN_INSTR(PopScriptContext) + MOTH_END_INSTR(PopScriptContext) + MOTH_BEGIN_INSTR(PopContext) MOTH_END_INSTR(PopContext) diff --git a/src/qml/jit/qv4jit_p.h b/src/qml/jit/qv4jit_p.h index 157fbffeb1..97dd2ef2a5 100644 --- a/src/qml/jit/qv4jit_p.h +++ b/src/qml/jit/qv4jit_p.h @@ -181,6 +181,8 @@ public: void generate_PushCatchContext(int reg, int index, int name) override; void generate_PushWithContext(int reg) override; void generate_PushBlockContext(int reg, int index) override; + void generate_PushScriptContext(int index) override; + void generate_PopScriptContext() override; void generate_PopContext(int reg) override; void generate_GetIterator(int iterator) override; void generate_DeleteMember(int member, int base) override; diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index c81af767fa..8a6f1044b9 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -57,17 +57,17 @@ DEFINE_MANAGED_VTABLE(CallContext); Heap::CallContext *ExecutionContext::newBlockContext(CppStackFrame *frame, int blockIndex) { Function *function = frame->v4Function; - Heap::ExecutionContext *outer = static_cast<Heap::ExecutionContext *>(frame->context()->m()); Heap::InternalClass *ic = function->compilationUnit->runtimeBlocks.at(blockIndex); int nLocals = ic->size; size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + sizeof(Value) * nLocals; - ExecutionEngine *v4 = outer->internalClass->engine; + ExecutionEngine *v4 = function->internalClass->engine; Heap::CallContext *c = v4->memoryManager->allocManaged<CallContext>(requiredMemory, ic); c->init(); c->type = Heap::ExecutionContext::Type_BlockContext; + Heap::ExecutionContext *outer = static_cast<Heap::ExecutionContext *>(frame->context()->m()); c->outer.set(v4, outer); c->function.set(v4, static_cast<Heap::FunctionObject *>(frame->jsFrame->function.m())); @@ -137,7 +137,6 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) ScopedContext ctx(scope, this); while (ctx) { switch (ctx->d()->type) { - case Heap::ExecutionContext::Type_BlockContext: case Heap::ExecutionContext::Type_CallContext: if (!activation) { Heap::CallContext *c = static_cast<Heap::CallContext *>(ctx->d()); @@ -158,6 +157,8 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) activation = ctx->d()->activation; break; } + case Heap::ExecutionContext::Type_BlockContext: + // never create activation records on block contexts default: break; } @@ -169,7 +170,8 @@ void ExecutionContext::createMutableBinding(String *name, bool deletable) ScopedProperty desc(scope); PropertyAttributes attrs(Attr_Data); attrs.setConfigurable(deletable); - activation->__defineOwnProperty__(scope.engine, name, desc, attrs); + if (!activation->__defineOwnProperty__(scope.engine, name, desc, attrs)) + scope.engine->throwTypeError(); } bool ExecutionContext::deleteProperty(String *name) diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index 2a37f3ee47..b703f6e4f3 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -585,6 +585,7 @@ void ExecutionEngine::initRootContext() r->d_unchecked()->init(Heap::ExecutionContext::Type_GlobalContext); r->d()->activation.set(this, globalObject->d()); jsObjects[RootContext] = r; + jsObjects[ScriptContext] = r; jsObjects[IntegerNull] = Encode((int)0); } diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index e1b1ba38ca..e8218d0d1c 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -161,6 +161,7 @@ public: enum JSObjects { RootContext, + ScriptContext, IntegerNull, // Has to come after the RootContext to make the context stack safe ObjectProto, SymbolProto, @@ -223,6 +224,8 @@ public: enum { NTypedArrayTypes = 9 }; // == TypedArray::NValues, avoid header dependency ExecutionContext *rootContext() const { return reinterpret_cast<ExecutionContext *>(jsObjects + RootContext); } + ExecutionContext *scriptContext() const { return reinterpret_cast<ExecutionContext *>(jsObjects + ScriptContext); } + void setScriptContext(ReturnedValue c) { jsObjects[ScriptContext] = c; } FunctionObject *objectCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Object_Ctor); } FunctionObject *stringCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + String_Ctor); } FunctionObject *symbolCtor() const { return reinterpret_cast<FunctionObject *>(jsObjects + Symbol_Ctor); } diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index c556bdb008..8a70715728 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -270,7 +270,7 @@ ReturnedValue FunctionCtor::callAsConstructor(const FunctionObject *f, const Val return Encode::undefined(); Function *vmf = compilationUnit->linkToEngine(engine); - ExecutionContext *global = engine->rootContext(); + ExecutionContext *global = engine->scriptContext(); return Encode(FunctionObject::createScriptFunction(global, vmf)); } diff --git a/src/qml/jsruntime/qv4generatorobject.cpp b/src/qml/jsruntime/qv4generatorobject.cpp index 4339a95f45..c91e182b54 100644 --- a/src/qml/jsruntime/qv4generatorobject.cpp +++ b/src/qml/jsruntime/qv4generatorobject.cpp @@ -63,7 +63,7 @@ ReturnedValue GeneratorFunctionCtor::callAsConstructor(const FunctionObject *f, return Encode::undefined(); Function *vmf = compilationUnit->linkToEngine(engine); - ExecutionContext *global = engine->rootContext(); + ExecutionContext *global = engine->scriptContext(); return Encode(GeneratorFunction::create(global, vmf)); } diff --git a/src/qml/jsruntime/qv4globalobject.cpp b/src/qml/jsruntime/qv4globalobject.cpp index b68f3db3cf..47a6734eda 100644 --- a/src/qml/jsruntime/qv4globalobject.cpp +++ b/src/qml/jsruntime/qv4globalobject.cpp @@ -351,7 +351,7 @@ ReturnedValue EvalFunction::evalCall(const Value *, const Value *argv, int argc, if (!directCall) { // the context for eval should be the global scope - ctx = v4->rootContext(); + ctx = v4->scriptContext(); } String *scode = argv[0].stringValue(); diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 05b0ddf753..8bf6d6b73f 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1230,6 +1230,22 @@ ReturnedValue Runtime::method_createBlockContext(ExecutionContext *parent, int i return parent->newBlockContext(e->currentStackFrame, index)->asReturnedValue(); } +ReturnedValue Runtime::method_createScriptContext(ExecutionEngine *engine, int index) +{ + Q_ASSERT(engine->currentStackFrame->context()->d()->type == Heap::ExecutionContext::Type_GlobalContext || + engine->currentStackFrame->context()->d()->type == Heap::ExecutionContext::Type_QmlContext); + ReturnedValue c = ExecutionContext::newBlockContext(engine->currentStackFrame, index)->asReturnedValue(); + engine->setScriptContext(c); + return c; +} + +ReturnedValue Runtime::method_popScriptContext(ExecutionEngine *engine) +{ + ReturnedValue root = engine->rootContext()->asReturnedValue(); + engine->setScriptContext(root); + return root; +} + void Runtime::method_declareVar(ExecutionEngine *engine, bool deletable, int nameIndex) { diff --git a/src/qml/jsruntime/qv4runtimeapi_p.h b/src/qml/jsruntime/qv4runtimeapi_p.h index 4d4112bf0c..f707de00f8 100644 --- a/src/qml/jsruntime/qv4runtimeapi_p.h +++ b/src/qml/jsruntime/qv4runtimeapi_p.h @@ -127,6 +127,8 @@ struct ExceptionCheck<void (*)(QV4::NoThrowEngine *, A, B, C)> { F(ReturnedValue, createWithContext, (ExecutionContext *parent, const Value &o)) \ F(ReturnedValue, createCatchContext, (ExecutionContext *parent, int blockIndex, int exceptionVarNameIndex)) \ F(ReturnedValue, createBlockContext, (ExecutionContext *parent, int index)) \ + F(ReturnedValue, createScriptContext, (ExecutionEngine *engine, int index)) \ + F(ReturnedValue, popScriptContext, (ExecutionEngine *engine)) \ \ /* closures */ \ F(ReturnedValue, closure, (ExecutionEngine *engine, int functionId)) \ diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index 7f27619d08..3fadb6e670 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -929,11 +929,19 @@ QV4::ReturnedValue VME::interpret(CppStackFrame &frame, const uchar *code) MOTH_END_INSTR(PushWithContext) MOTH_BEGIN_INSTR(PushBlockContext) - STACK_VALUE(reg) = STACK_VALUE(CallData::Context); - ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context); - STACK_VALUE(CallData::Context) = Runtime::method_createBlockContext(c, index); + STACK_VALUE(reg) = STACK_VALUE(CallData::Context); + ExecutionContext *c = static_cast<ExecutionContext *>(stack + CallData::Context); + STACK_VALUE(CallData::Context) = Runtime::method_createBlockContext(c, index); MOTH_END_INSTR(PushBlockContext) + MOTH_BEGIN_INSTR(PushScriptContext) + STACK_VALUE(CallData::Context) = Runtime::method_createScriptContext(engine, index); + MOTH_END_INSTR(PushScriptContext) + + MOTH_BEGIN_INSTR(PopScriptContext) + STACK_VALUE(CallData::Context) = Runtime::method_popScriptContext(engine); + MOTH_END_INSTR(PopScriptContext) + MOTH_BEGIN_INSTR(PopContext) STACK_VALUE(CallData::Context) = STACK_VALUE(reg); MOTH_END_INSTR(PopContext) |