aboutsummaryrefslogtreecommitdiffstats
path: root/qv4codegen.cpp
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2012-12-17 21:56:19 +0100
committerSimon Hausmann <simon.hausmann@digia.com>2012-12-18 08:19:36 +0100
commit97625f03a660f0caf7960e9bad2c2fc792abc296 (patch)
tree9093af52dd715b11f74ed553c2c964dc48521dc0 /qv4codegen.cpp
parent2522d2d3ff8a8dbd2e45bad1d8dc7cb1f45dd10b (diff)
ensure correct initialization order for local variables
section 10.5 requires that function definitions get initialized at the beginning of the method. variable declarations do not override the function definitions. assignments to variables happen when they appear in the source code. Also remove a duplicated intializations of variables to undefined. This is already being done by initCallContext or builtin_declare_vars, so no need to do it in the generated code again. Change-Id: I63805b97017f8676d57e0662073689e852b6ac23 Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
Diffstat (limited to 'qv4codegen.cpp')
-rw-r--r--qv4codegen.cpp68
1 files changed, 36 insertions, 32 deletions
diff --git a/qv4codegen.cpp b/qv4codegen.cpp
index a15ba22ca4..0e5eedb5bf 100644
--- a/qv4codegen.cpp
+++ b/qv4codegen.cpp
@@ -308,7 +308,7 @@ protected:
checkName(ast->name, ast->identifierToken);
if (ast->name == QLatin1String("arguments"))
_env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
- _env->enter(ast->name.toString());
+ _env->enter(ast->name.toString(), ast->expression ? Environment::VariableDefinition : Environment::VariableDeclaration);
return true;
}
@@ -324,7 +324,7 @@ protected:
{
if (_env) {
_env->hasNestedFunctions = true;
- _env->enter(ast->name.toString());
+ _env->enter(ast->name.toString(), Environment::FunctionDefinition);
}
enterEnvironment(ast);
checkForArguments(ast->formals);
@@ -340,9 +340,8 @@ protected:
virtual bool visit(FunctionDeclaration *ast)
{
- _env->functions.append(ast);
_env->hasNestedFunctions = true;
- _env->enter(ast->name.toString());
+ _env->enter(ast->name.toString(), Environment::FunctionDefinition, ast);
if (ast->name == QLatin1String("arguments"))
_env->usesArgumentsObject = Environment::ArgumentsObjectNotUsed;
enterEnvironment(ast);
@@ -771,14 +770,11 @@ void Codegen::sourceElements(SourceElements *ast)
void Codegen::variableDeclaration(VariableDeclaration *ast)
{
IR::Expr *initializer = 0;
- if (ast->expression) {
- Result expr = expression(ast->expression);
- assert(expr.code);
- initializer = *expr;
- }
-
- if (! initializer)
- initializer = _block->CONST(IR::UndefinedType, 0);
+ if (!ast->expression)
+ return;
+ Result expr = expression(ast->expression);
+ assert(expr.code);
+ initializer = *expr;
if (! _env->parent || _function->insideWith) {
// it's global code.
@@ -1250,7 +1246,7 @@ IR::Expr *Codegen::identifier(const QString &name, int line, int col)
}
}
- if (index >= _env->vars.size()) {
+ if (index >= _env->members.size()) {
// named local variable, e.g. in a catch statement
return _block->TEMP(index);
}
@@ -1695,16 +1691,16 @@ IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
// variables in global code are properties of the global context object, not locals as with other functions.
if (_mode == FunctionCode) {
- for (int i = 0; i < _env->vars.size(); ++i) {
- const QString &local = _env->vars.at(i);
+ for (Environment::MemberMap::iterator it = _env->members.begin(); it != _env->members.end(); ++it) {
+ const QString &local = it.key();
function->LOCAL(local);
unsigned t = entryBlock->newTemp();
- assert(t == unsigned(i));
+ (*it).index = t;
}
} else {
IR::ExprList *args = 0;
- for (int i = 0; i < _env->vars.size(); ++i) {
- const QString &local = _env->vars.at(i);
+ for (Environment::MemberMap::const_iterator it = _env->members.constBegin(); it != _env->members.constEnd(); ++it) {
+ const QString &local = it.key();
IR::ExprList *next = function->New<IR::ExprList>();
next->expr = entryBlock->NAME(local, 0, 0);
next->next = args;
@@ -1739,17 +1735,20 @@ IR::Function *Codegen::defineFunction(const QString &name, AST::Node *ast,
_function->RECEIVE(it->name.toString());
}
- foreach (AST::FunctionDeclaration *f, _env->functions) {
- IR::Function *function = defineFunction(f->name.toString(), f, f->formals,
- f->body ? f->body->elements : 0);
- if (_debugger)
- _debugger->setSourceLocation(function, f->functionToken.startLine, f->functionToken.startColumn);
- if (! _env->parent)
- move(_block->NAME(f->name.toString(), f->identifierToken.startLine, f->identifierToken.startColumn),
- _block->CLOSURE(function));
- else
- move(_block->TEMP(_env->findMember(f->name.toString())),
- _block->CLOSURE(function));
+ foreach (const Environment::Member &member, _env->members) {
+ if (member.function) {
+ IR::Function *function = defineFunction(member.function->name.toString(), member.function, member.function->formals,
+ member.function->body ? member.function->body->elements : 0);
+ if (_debugger)
+ _debugger->setSourceLocation(function, member.function->functionToken.startLine, member.function->functionToken.startColumn);
+ if (! _env->parent) {
+ move(_block->NAME(member.function->name.toString(), member.function->identifierToken.startLine, member.function->identifierToken.startColumn),
+ _block->CLOSURE(function));
+ } else {
+ assert(member.index >= 0);
+ move(_block->TEMP(member.index), _block->CLOSURE(function));
+ }
+ }
}
sourceElements(body);
@@ -2209,13 +2208,18 @@ bool Codegen::visit(TryStatement *ast)
// the variable used in the catch statement is local and hides any global
// variable with the same name.
- int hiddenIndex = _env->findMember(ast->catchExpression->name.toString());
- _env->members.insert(ast->catchExpression->name.toString(), exception);
+ const Environment::Member undefinedMember = { Environment::UndefinedMember, -1 , 0 };
+ const Environment::Member catchMember = { Environment::VariableDefinition, exception, 0 };
+ Environment::Member m = _env->members.value(ast->catchExpression->name.toString(), undefinedMember);
+ _env->members.insert(ast->catchExpression->name.toString(), catchMember);
statement(ast->catchExpression->statement);
// reset the variable name to the one from the outer scope
- _env->members.insert(ast->catchExpression->name.toString(), hiddenIndex);
+ if (m.type == Environment::UndefinedMember)
+ _env->members.remove(ast->catchExpression->name.toString());
+ else
+ _env->members.insert(ast->catchExpression->name.toString(), m);
_block->JUMP(finallyBody);
}