aboutsummaryrefslogtreecommitdiffstats
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.cpp95
1 files changed, 71 insertions, 24 deletions
diff --git a/src/qml/compiler/qv4compilercontext.cpp b/src/qml/compiler/qv4compilercontext.cpp
index e2e978be7c..4893a06af8 100644
--- a/src/qml/compiler/qv4compilercontext.cpp
+++ b/src/qml/compiler/qv4compilercontext.cpp
@@ -71,19 +71,12 @@ Context *Module::newContext(Node *node, Context *parent, ContextType contextType
return c;
}
-bool Context::forceLookupByName()
-{
- ControlFlow *flow = controlFlow;
- while (flow) {
- if (flow->needsLookupByName)
- return true;
- flow = flow->parent;
- }
- return false;
-}
-
bool Context::addLocalVar(const QString &name, Context::MemberType type, VariableScope scope, FunctionExpression *function)
{
+ // hoist var declarations to the function level
+ if (contextType == ContextType::Block && (scope == VariableScope::Var && type != MemberType::FunctionDefinition))
+ return parent->addLocalVar(name, type, scope, function);
+
if (name.isEmpty())
return true;
@@ -117,7 +110,7 @@ Context::ResolvedName Context::resolveName(const QString &name)
ResolvedName result;
while (c->parent) {
- if (c->forceLookupByName())
+ if (c->forceLookupByName)
return result;
Context::Member m = c->findMember(name);
@@ -128,7 +121,6 @@ Context::ResolvedName Context::resolveName(const QString &name)
if (c->isStrict && (name == QLatin1String("arguments") || name == QLatin1String("eval")))
result.isArgOrEval = true;
return result;
- Q_ASSERT(result.type != ResolvedName::Stack || result.scope == 0);
}
const int argIdx = c->findArgument(name);
if (argIdx != -1) {
@@ -145,7 +137,7 @@ Context::ResolvedName Context::resolveName(const QString &name)
return result;
}
}
- if (!c->isStrict && c->hasDirectEval)
+ if (!c->isStrict && c->hasDirectEval && c->contextType != ContextType::Block)
return result;
if (c->requiresExecutionContext)
@@ -154,25 +146,32 @@ Context::ResolvedName Context::resolveName(const QString &name)
}
// ### can we relax the restrictions here?
- if (c->forceLookupByName() || type == ContextType::Eval || c->type == ContextType::Binding)
+ if (c->forceLookupByName || contextType == ContextType::Eval || c->contextType == ContextType::Binding)
return result;
result.type = ResolvedName::Global;
return result;
}
-void Context::emitHeaderBytecode(Codegen *codegen)
+int Context::emitBlockHeader(Codegen *codegen)
{
-
using Instruction = Moth::Instruction;
Moth::BytecodeGenerator *bytecodeGenerator = codegen->generator();
setupFunctionIndices(bytecodeGenerator);
+ int contextReg = -1;
if (requiresExecutionContext ||
- type == 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.
- Instruction::CreateCallContext createContext;
- bytecodeGenerator->addInstruction(createContext);
+ 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) {
+ Instruction::PushBlockContext blockContext;
+ blockContext.index = blockIndex;
+ blockContext.reg = contextReg = bytecodeGenerator->newRegister();
+ bytecodeGenerator->addInstruction(blockContext);
+ } else {
+ Instruction::CreateCallContext createContext;
+ bytecodeGenerator->addInstruction(createContext);
+ }
}
if (usesThis && !isStrict) {
// make sure we convert this to an object
@@ -180,8 +179,10 @@ void Context::emitHeaderBytecode(Codegen *codegen)
bytecodeGenerator->addInstruction(convert);
}
- // variables in global code are properties of the global context object, not locals as with other functions.
- if (type == ContextType::Function || type == ContextType::Binding) {
+ switch (contextType) {
+ case ContextType::Block:
+ case ContextType::Function:
+ case 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
@@ -193,7 +194,11 @@ void Context::emitHeaderBytecode(Codegen *codegen)
bytecodeGenerator->addInstruction(store);
}
}
- } else {
+ 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();
@@ -203,8 +208,10 @@ void Context::emitHeaderBytecode(Codegen *codegen)
bytecodeGenerator->addInstruction(declareVar);
}
}
+ }
if (usesArgumentsObject == Context::ArgumentsObjectUsed) {
+ Q_ASSERT(contextType != ContextType::Block);
if (isStrict || (formals && !formals->isSimpleParameterList())) {
Instruction::CreateUnmappedArgumentsObject setup;
bytecodeGenerator->addInstruction(setup);
@@ -214,6 +221,38 @@ void Context::emitHeaderBytecode(Codegen *codegen)
}
codegen->referenceForName(QStringLiteral("arguments"), false).storeConsumeAccumulator();
}
+
+ for (const Context::Member &member : qAsConst(members)) {
+ 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();
+ }
+ }
+ }
+
+
+
+ return contextReg;
+}
+
+void Context::emitBlockFooter(Codegen *codegen, int oldContextReg)
+{
+ using Instruction = Moth::Instruction;
+ Moth::BytecodeGenerator *bytecodeGenerator = codegen->generator();
+
+ if (oldContextReg != -1) {
+ Instruction::PopContext popContext;
+ popContext.reg = oldContextReg;
+ bytecodeGenerator->addInstruction(popContext);
+ }
}
void Context::setupFunctionIndices(Moth::BytecodeGenerator *bytecodeGenerator)
@@ -222,7 +261,10 @@ void Context::setupFunctionIndices(Moth::BytecodeGenerator *bytecodeGenerator)
Q_ASSERT(nRegisters == 0);
registerOffset = bytecodeGenerator->registerCount();
- if (type == ContextType::Function || type == ContextType::Binding) {
+ switch (contextType) {
+ case ContextType::Block:
+ case ContextType::Function:
+ case ContextType::Binding: {
for (Context::MemberMap::iterator it = members.begin(), end = members.end(); it != end; ++it) {
const QString &local = it.key();
if (it->canEscape) {
@@ -235,6 +277,11 @@ void Context::setupFunctionIndices(Moth::BytecodeGenerator *bytecodeGenerator)
it->index = bytecodeGenerator->newRegister();
}
}
+ break;
+ }
+ case ContextType::Global:
+ case ContextType::Eval:
+ break;
}
nRegisters = bytecodeGenerator->registerCount() - registerOffset;
}