summaryrefslogtreecommitdiff
path: root/src/qml/compiler/qv4compilercontext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/compiler/qv4compilercontext.cpp')
-rw-r--r--src/qml/compiler/qv4compilercontext.cpp76
1 files changed, 43 insertions, 33 deletions
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;