aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp2
-rw-r--r--src/qml/compiler/qv4codegen.cpp13
-rw-r--r--src/qml/compiler/qv4compilercontext.cpp76
-rw-r--r--src/qml/compiler/qv4compilerscanfunctions.cpp30
-rw-r--r--src/qml/compiler/qv4instr_moth.cpp7
-rw-r--r--src/qml/compiler/qv4instr_moth_p.h4
-rw-r--r--src/qml/jit/qv4jit.cpp34
-rw-r--r--src/qml/jit/qv4jit_p.h2
-rw-r--r--src/qml/jsruntime/qv4context.cpp10
-rw-r--r--src/qml/jsruntime/qv4engine.cpp1
-rw-r--r--src/qml/jsruntime/qv4engine_p.h3
-rw-r--r--src/qml/jsruntime/qv4functionobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4generatorobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4globalobject.cpp2
-rw-r--r--src/qml/jsruntime/qv4runtime.cpp16
-rw-r--r--src/qml/jsruntime/qv4runtimeapi_p.h2
-rw-r--r--src/qml/jsruntime/qv4vme_moth.cpp14
-rw-r--r--tests/auto/qml/ecmascripttests/TestExpectations20
19 files changed, 165 insertions, 77 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
index a00454758e..70f71de6ca 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
@@ -65,7 +65,7 @@ void JavaScriptJob::run()
QV4::Scope scope(engine);
QV4::ScopedContext ctx(scope, engine->currentStackFrame ? engine->currentContext()
- : engine->rootContext());
+ : engine->scriptContext());
QObject scopeObject;
QV4::CppStackFrame *frame = engine->currentStackFrame;
diff --git a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp
index 298608b63e..36390a3ea5 100644
--- a/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_nativedebugger/qqmlnativedebugservice.cpp
@@ -253,7 +253,7 @@ QV4::ReturnedValue NativeDebugger::evaluateExpression(const QString &expression)
m_runningJob = true;
QV4::ExecutionContext *ctx = m_engine->currentStackFrame ? m_engine->currentContext()
- : m_engine->rootContext();
+ : m_engine->scriptContext();
QV4::Script script(ctx, QV4::Compiler::ContextType::Eval, expression);
if (const QV4::Function *function = m_engine->currentStackFrame
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)
diff --git a/tests/auto/qml/ecmascripttests/TestExpectations b/tests/auto/qml/ecmascripttests/TestExpectations
index 8dbf0d4157..1fcf546792 100644
--- a/tests/auto/qml/ecmascripttests/TestExpectations
+++ b/tests/auto/qml/ecmascripttests/TestExpectations
@@ -3048,10 +3048,6 @@ built-ins/WeakSet/symbol-disallowed-as-weakset-key.js fails
built-ins/WeakSet/undefined-newtarget.js fails
built-ins/WeakSet/weakset.js fails
built-ins/eval/length-non-configurable.js fails
-built-ins/global/S10.2.3_A2.3_T1.js strictFails
-built-ins/global/S10.2.3_A2.3_T2.js strictFails
-built-ins/global/S10.2.3_A2.3_T3.js strictFails
-built-ins/global/S10.2.3_A2.3_T4.js strictFails
built-ins/global/global-object.js fails
built-ins/global/property-descriptor.js fails
built-ins/isFinite/toprimitive-not-callable-throws.js fails
@@ -3162,8 +3158,6 @@ language/computed-property-names/to-name-side-effects/object.js fails
language/destructuring/binding/syntax/array-rest-elements.js fails
language/destructuring/binding/syntax/recursive-array-and-object-patterns.js fails
language/eval-code/direct/lex-env-distinct-cls.js fails
-language/eval-code/direct/lex-env-distinct-const.js sloppyFails
-language/eval-code/direct/lex-env-distinct-let.js sloppyFails
language/eval-code/direct/lex-env-no-init-cls.js fails
language/eval-code/direct/lex-env-no-init-const.js fails
language/eval-code/direct/lex-env-no-init-let.js fails
@@ -3172,21 +3166,14 @@ language/eval-code/direct/non-definable-function-with-function.js sloppyFails
language/eval-code/direct/non-definable-function-with-variable.js sloppyFails
language/eval-code/direct/non-definable-global-function.js sloppyFails
language/eval-code/direct/non-definable-global-generator.js sloppyFails
-language/eval-code/direct/non-definable-global-var.js sloppyFails
language/eval-code/direct/super-prop-method.js fails
language/eval-code/direct/this-value-func-strict-source.js sloppyFails
-language/eval-code/direct/var-env-func-init-global-new.js sloppyFails
language/eval-code/direct/var-env-func-init-global-update-configurable.js sloppyFails
-language/eval-code/direct/var-env-func-init-local-new-delete.js sloppyFails
language/eval-code/direct/var-env-global-lex-non-strict.js sloppyFails
language/eval-code/direct/var-env-lower-lex-catch-non-strict.js sloppyFails
language/eval-code/direct/var-env-lower-lex-non-strict.js sloppyFails
-language/eval-code/direct/var-env-var-init-global-new.js sloppyFails
-language/eval-code/direct/var-env-var-init-local-new-delete.js sloppyFails
language/eval-code/indirect/always-non-strict.js strictFails
language/eval-code/indirect/lex-env-distinct-cls.js fails
-language/eval-code/indirect/lex-env-distinct-const.js sloppyFails
-language/eval-code/indirect/lex-env-distinct-let.js sloppyFails
language/eval-code/indirect/lex-env-no-init-cls.js fails
language/eval-code/indirect/lex-env-no-init-const.js fails
language/eval-code/indirect/lex-env-no-init-let.js fails
@@ -3196,13 +3183,13 @@ language/eval-code/indirect/non-definable-global-function.js fails
language/eval-code/indirect/non-definable-global-generator.js fails
language/eval-code/indirect/realm.js fails
language/eval-code/indirect/this-value-func.js strictFails
-language/eval-code/indirect/var-env-func-init-global-new.js fails
+language/eval-code/indirect/var-env-func-init-global-new.js strictFails
language/eval-code/indirect/var-env-func-init-global-update-configurable.js fails
language/eval-code/indirect/var-env-func-init-multi.js strictFails
language/eval-code/indirect/var-env-func-non-strict.js strictFails
language/eval-code/indirect/var-env-global-lex-non-strict.js fails
language/eval-code/indirect/var-env-var-init-global-exstng.js strictFails
-language/eval-code/indirect/var-env-var-init-global-new.js fails
+language/eval-code/indirect/var-env-var-init-global-new.js strictFails
language/eval-code/indirect/var-env-var-non-strict.js strictFails
language/expressions/addition/coerce-symbol-to-prim-err.js fails
language/expressions/addition/coerce-symbol-to-prim-invocation.js fails
@@ -4898,7 +4885,6 @@ language/function-code/eval-param-env-with-computed-key.js sloppyFails
language/function-code/eval-param-env-with-prop-initializer.js sloppyFails
language/function-code/switch-case-decl-strict.js strictFails
language/function-code/switch-dflt-decl-strict.js strictFails
-language/global-code/decl-lex-configurable-global.js fails
language/global-code/decl-lex-deletion.js sloppyFails
language/global-code/decl-lex-restricted-global.js fails
language/global-code/decl-lex.js fails
@@ -5001,7 +4987,6 @@ language/statements/async-function/evaluation-body.js fails
language/statements/async-function/syntax-declaration-line-terminators-allowed.js fails
language/statements/block/tco-stmt-list.js strictFails
language/statements/block/tco-stmt.js strictFails
-language/statements/break/S12.8_A2.js strictFails
language/statements/class/accessor-name-inst-computed-err-evaluation.js fails
language/statements/class/accessor-name-inst-computed-err-to-prop-key.js fails
language/statements/class/accessor-name-inst-computed-err-unresolvable.js fails
@@ -5971,7 +5956,6 @@ language/statements/const/syntax/const-invalid-assignment-next-expression-for.js
language/statements/const/syntax/const-invalid-assignment-statement-body-for-in.js fails
language/statements/const/syntax/const-invalid-assignment-statement-body-for-of.js fails
language/statements/const/syntax/const-outer-inner-let-bindings.js fails
-language/statements/continue/S12.7_A2.js strictFails
language/statements/do-while/tco-body.js strictFails
language/statements/empty/cptn-value.js fails
language/statements/for-in/head-const-bound-names-fordecl-tdz.js fails