Commit 43570fce authored by Luca Bruno's avatar Luca Bruno

Enable flow analysis for out parameters

Fixes bug 638363.
parent 7d1332dd
......@@ -536,16 +536,19 @@ public class Vala.Assignment : Expression {
codegen.visit_expression (this);
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
right.get_defined_variables (collection);
left.get_defined_variables (collection);
var local = left.symbol_reference as LocalVariable;
var param = left.symbol_reference as Parameter;
if (local != null) {
collection.add (local);
} else if (param != null && param.direction == ParameterDirection.OUT) {
collection.add (param);
}
}
public override void get_used_variables (Collection<LocalVariable> collection) {
public override void get_used_variables (Collection<Variable> collection) {
var ma = left as MemberAccess;
var ea = left as ElementAccess;
if (ma != null && ma.inner != null) {
......
......@@ -507,12 +507,12 @@ public class Vala.BinaryExpression : Expression {
codegen.visit_expression (this);
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
left.get_defined_variables (collection);
right.get_defined_variables (collection);
}
public override void get_used_variables (Collection<LocalVariable> collection) {
public override void get_used_variables (Collection<Variable> collection) {
left.get_used_variables (collection);
right.get_used_variables (collection);
}
......
......@@ -165,11 +165,11 @@ public class Vala.CastExpression : Expression {
codegen.visit_expression (this);
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
inner.get_defined_variables (collection);
}
public override void get_used_variables (Collection<LocalVariable> collection) {
public override void get_used_variables (Collection<Variable> collection) {
inner.get_used_variables (collection);
}
......
......@@ -149,7 +149,7 @@ public class Vala.CatchClause : CodeNode {
codegen.visit_catch_clause (this);
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
if (error_variable != null) {
collection.add (error_variable);
}
......
......@@ -168,10 +168,10 @@ public abstract class Vala.CodeNode {
return str.append (" */").str;
}
public virtual void get_defined_variables (Collection<LocalVariable> collection) {
public virtual void get_defined_variables (Collection<Variable> collection) {
}
public virtual void get_used_variables (Collection<LocalVariable> collection) {
public virtual void get_used_variables (Collection<Variable> collection) {
}
public static string get_temp_name () {
......
......@@ -89,7 +89,7 @@ public class Vala.DeclarationStatement : CodeNode, Statement {
codegen.visit_declaration_statement (this);
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
var local = declaration as LocalVariable;
if (local != null) {
var array_type = local.variable_type as ArrayType;
......@@ -102,7 +102,7 @@ public class Vala.DeclarationStatement : CodeNode, Statement {
}
}
public override void get_used_variables (Collection<LocalVariable> collection) {
public override void get_used_variables (Collection<Variable> collection) {
var local = declaration as LocalVariable;
if (local != null && local.initializer != null) {
local.initializer.get_used_variables (collection);
......
......@@ -238,14 +238,14 @@ public class Vala.ElementAccess : Expression {
codegen.visit_expression (this);
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
container.get_defined_variables (collection);
foreach (Expression index in indices) {
index.get_defined_variables (collection);
}
}
public override void get_used_variables (Collection<LocalVariable> collection) {
public override void get_used_variables (Collection<Variable> collection) {
container.get_used_variables (collection);
foreach (Expression index in indices) {
index.get_used_variables (collection);
......
......@@ -91,11 +91,11 @@ public class Vala.ExpressionStatement : CodeNode, Statement {
codegen.visit_expression_statement (this);
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
expression.get_defined_variables (collection);
}
public override void get_used_variables (Collection<LocalVariable> collection) {
public override void get_used_variables (Collection<Variable> collection) {
expression.get_used_variables (collection);
}
}
......@@ -90,9 +90,9 @@ public class Vala.FlowAnalyzer : CodeVisitor {
private bool unreachable_reported;
private List<JumpTarget> jump_stack = new ArrayList<JumpTarget> ();
Map<Symbol, List<LocalVariable>> var_map;
Set<LocalVariable> used_vars;
Map<LocalVariable, PhiFunction> phi_functions;
Map<Symbol, List<Variable>> var_map;
Set<Variable> used_vars;
Map<Variable, PhiFunction> phi_functions;
public FlowAnalyzer () {
}
......@@ -199,6 +199,16 @@ public class Vala.FlowAnalyzer : CodeVisitor {
result_ma.symbol_reference = m.result_var;
m.return_block.add_node (result_ma);
}
if (m is Method) {
// ensure out parameters are defined at end of method
foreach (var param in ((Method) m).get_parameters ()) {
if (param.direction == ParameterDirection.OUT) {
var param_ma = new MemberAccess.simple (param.name, param.source_reference);
param_ma.symbol_reference = param;
m.return_block.add_node (param_ma);
}
}
}
current_block = new BasicBlock ();
m.entry_block.connect (current_block);
......@@ -330,19 +340,19 @@ public class Vala.FlowAnalyzer : CodeVisitor {
}
}
Map<LocalVariable, Set<BasicBlock>> get_assignment_map (List<BasicBlock> block_list, BasicBlock entry_block) {
var map = new HashMap<LocalVariable, Set<BasicBlock>> ();
Map<Variable, Set<BasicBlock>> get_assignment_map (List<BasicBlock> block_list, BasicBlock entry_block) {
var map = new HashMap<Variable, Set<BasicBlock>> ();
foreach (BasicBlock block in block_list) {
var defined_variables = new ArrayList<LocalVariable> ();
var defined_variables = new ArrayList<Variable> ();
foreach (CodeNode node in block.get_nodes ()) {
node.get_defined_variables (defined_variables);
}
foreach (LocalVariable local in defined_variables) {
var block_set = map.get (local);
foreach (Variable variable in defined_variables) {
var block_set = map.get (variable);
if (block_set == null) {
block_set = new HashSet<BasicBlock> ();
map.set (local, block_set);
map.set (variable, block_set);
}
block_set.add (block);
}
......@@ -363,9 +373,9 @@ public class Vala.FlowAnalyzer : CodeVisitor {
phi.set (block, 0);
}
foreach (LocalVariable local in assign.get_keys ()) {
foreach (Variable variable in assign.get_keys ()) {
counter++;
foreach (BasicBlock block in assign.get (local)) {
foreach (BasicBlock block in assign.get (variable)) {
work_list.add (block);
added.set (block, counter);
}
......@@ -375,7 +385,7 @@ public class Vala.FlowAnalyzer : CodeVisitor {
foreach (BasicBlock frontier in block.get_dominator_frontier ()) {
int blockPhi = phi.get (frontier);
if (blockPhi < counter) {
frontier.add_phi_function (new PhiFunction (local, frontier.get_predecessors ().size));
frontier.add_phi_function (new PhiFunction (variable, frontier.get_predecessors ().size));
phi.set (frontier, counter);
int block_added = added.get (frontier);
if (block_added < counter) {
......@@ -389,32 +399,37 @@ public class Vala.FlowAnalyzer : CodeVisitor {
}
void check_variables (BasicBlock entry_block) {
var_map = new HashMap<Symbol, List<LocalVariable>>();
used_vars = new HashSet<LocalVariable> ();
phi_functions = new HashMap<LocalVariable, PhiFunction> ();
var_map = new HashMap<Symbol, List<Variable>>();
used_vars = new HashSet<Variable> ();
phi_functions = new HashMap<Variable, PhiFunction> ();
check_block_variables (entry_block);
// check for variables used before initialization
var used_vars_queue = new ArrayList<LocalVariable> ();
foreach (LocalVariable local in used_vars) {
used_vars_queue.add (local);
var used_vars_queue = new ArrayList<Variable> ();
foreach (Variable variable in used_vars) {
used_vars_queue.add (variable);
}
while (used_vars_queue.size > 0) {
LocalVariable used_var = used_vars_queue[0];
Variable used_var = used_vars_queue[0];
used_vars_queue.remove_at (0);
PhiFunction phi = phi_functions.get (used_var);
if (phi != null) {
foreach (LocalVariable local in phi.operands) {
if (local == null) {
Report.error (used_var.source_reference, "use of possibly unassigned local variable `%s'".printf (used_var.name));
foreach (Variable variable in phi.operands) {
if (variable == null) {
if (used_var is LocalVariable) {
Report.error (used_var.source_reference, "use of possibly unassigned local variable `%s'".printf (used_var.name));
} else {
// parameter
Report.warning (used_var.source_reference, "use of possibly unassigned parameter `%s'".printf (used_var.name));
}
continue;
}
if (!(local in used_vars)) {
local.source_reference = used_var.source_reference;
used_vars.add (local);
used_vars_queue.add (local);
if (!(variable in used_vars)) {
variable.source_reference = used_var.source_reference;
used_vars.add (variable);
used_vars_queue.add (variable);
}
}
}
......@@ -423,33 +438,38 @@ public class Vala.FlowAnalyzer : CodeVisitor {
void check_block_variables (BasicBlock block) {
foreach (PhiFunction phi in block.get_phi_functions ()) {
LocalVariable versioned_var = process_assignment (var_map, phi.original_variable);
Variable versioned_var = process_assignment (var_map, phi.original_variable);
phi_functions.set (versioned_var, phi);
}
foreach (CodeNode node in block.get_nodes ()) {
var used_variables = new ArrayList<LocalVariable> ();
var used_variables = new ArrayList<Variable> ();
node.get_used_variables (used_variables);
foreach (LocalVariable var_symbol in used_variables) {
foreach (Variable var_symbol in used_variables) {
var variable_stack = var_map.get (var_symbol);
if (variable_stack == null || variable_stack.size == 0) {
Report.error (node.source_reference, "use of possibly unassigned local variable `%s'".printf (var_symbol.name));
if (var_symbol is LocalVariable) {
Report.error (node.source_reference, "use of possibly unassigned local variable `%s'".printf (var_symbol.name));
} else {
// parameter
Report.warning (node.source_reference, "use of possibly unassigned parameter `%s'".printf (var_symbol.name));
}
continue;
}
var versioned_local = variable_stack.get (variable_stack.size - 1);
if (!(versioned_local in used_vars)) {
versioned_local.source_reference = node.source_reference;
var versioned_variable = variable_stack.get (variable_stack.size - 1);
if (!(versioned_variable in used_vars)) {
versioned_variable.source_reference = node.source_reference;
}
used_vars.add (versioned_local);
used_vars.add (versioned_variable);
}
var defined_variables = new ArrayList<LocalVariable> ();
var defined_variables = new ArrayList<Variable> ();
node.get_defined_variables (defined_variables);
foreach (LocalVariable local in defined_variables) {
process_assignment (var_map, local);
foreach (Variable variable in defined_variables) {
process_assignment (var_map, variable);
}
}
......@@ -479,23 +499,29 @@ public class Vala.FlowAnalyzer : CodeVisitor {
variable_stack.remove_at (variable_stack.size - 1);
}
foreach (CodeNode node in block.get_nodes ()) {
var defined_variables = new ArrayList<LocalVariable> ();
var defined_variables = new ArrayList<Variable> ();
node.get_defined_variables (defined_variables);
foreach (LocalVariable local in defined_variables) {
var variable_stack = var_map.get (local);
foreach (Variable variable in defined_variables) {
var variable_stack = var_map.get (variable);
variable_stack.remove_at (variable_stack.size - 1);
}
}
}
LocalVariable process_assignment (Map<Symbol, List<LocalVariable>> var_map, LocalVariable var_symbol) {
Variable process_assignment (Map<Symbol, List<Variable>> var_map, Variable var_symbol) {
var variable_stack = var_map.get (var_symbol);
if (variable_stack == null) {
variable_stack = new ArrayList<LocalVariable> ();
variable_stack = new ArrayList<Variable> ();
var_map.set (var_symbol, variable_stack);
}
LocalVariable versioned_var = new LocalVariable (var_symbol.variable_type, var_symbol.name, null, var_symbol.source_reference);
Variable versioned_var;
if (var_symbol is LocalVariable) {
versioned_var = new LocalVariable (var_symbol.variable_type, var_symbol.name, null, var_symbol.source_reference);
} else {
// parameter
versioned_var = new Parameter (var_symbol.name, var_symbol.variable_type, var_symbol.source_reference);
}
variable_stack.add (versioned_var);
return versioned_var;
}
......
......@@ -403,7 +403,7 @@ public class Vala.ForeachStatement : Block {
codegen.visit_foreach_statement (this);
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
collection.add (element_variable);
}
}
......@@ -255,10 +255,10 @@ public class Vala.LambdaExpression : Expression {
codegen.visit_expression (this);
}
public override void get_used_variables (Collection<LocalVariable> collection) {
public override void get_used_variables (Collection<Variable> collection) {
// require captured variables to be initialized
if (method.closure) {
method.get_captured_variables (collection);
method.get_captured_variables ((Collection<LocalVariable>) collection);
}
}
}
......@@ -847,19 +847,22 @@ public class Vala.MemberAccess : Expression {
codegen.visit_expression (this);
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
if (inner != null) {
inner.get_defined_variables (collection);
}
}
public override void get_used_variables (Collection<LocalVariable> collection) {
public override void get_used_variables (Collection<Variable> collection) {
if (inner != null) {
inner.get_used_variables (collection);
}
var local = symbol_reference as LocalVariable;
var param = symbol_reference as Parameter;
if (local != null) {
collection.add (local);
} else if (param != null && param.direction == ParameterDirection.OUT) {
collection.add (param);
}
}
}
......@@ -1164,11 +1164,11 @@ public class Vala.Method : Subroutine {
}
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
// capturing variables is only supported if they are initialized
// therefore assume that captured variables are initialized
if (closure) {
get_captured_variables (collection);
get_captured_variables ((Collection<LocalVariable>) collection);
}
}
}
......
......@@ -791,7 +791,7 @@ public class Vala.MethodCall : Expression {
codegen.visit_expression (this);
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
call.get_defined_variables (collection);
foreach (Expression arg in argument_list) {
......@@ -799,7 +799,7 @@ public class Vala.MethodCall : Expression {
}
}
public override void get_used_variables (Collection<LocalVariable> collection) {
public override void get_used_variables (Collection<Variable> collection) {
call.get_used_variables (collection);
foreach (Expression arg in argument_list) {
......
......@@ -89,11 +89,11 @@ public class Vala.NamedArgument : Expression {
codegen.visit_expression (this);
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
inner.get_defined_variables (collection);
}
public override void get_used_variables (Collection<LocalVariable> collection) {
public override void get_used_variables (Collection<Variable> collection) {
inner.get_used_variables (collection);
}
}
......@@ -443,13 +443,13 @@ public class Vala.ObjectCreationExpression : Expression {
codegen.visit_expression (this);
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
foreach (Expression arg in argument_list) {
arg.get_defined_variables (collection);
}
}
public override void get_used_variables (Collection<LocalVariable> collection) {
public override void get_used_variables (Collection<Variable> collection) {
foreach (Expression arg in argument_list) {
arg.get_used_variables (collection);
}
......
......@@ -22,15 +22,15 @@
public class Vala.PhiFunction {
public LocalVariable original_variable { get; private set; }
public Variable original_variable { get; private set; }
public List<LocalVariable?> operands { get; private set; }
public List<Variable?> operands { get; private set; }
public PhiFunction (LocalVariable variable, int num_of_ops) {
public PhiFunction (Variable variable, int num_of_ops) {
this.original_variable = variable;
this.operands = new ArrayList<LocalVariable?> ();
this.operands = new ArrayList<Variable?> ();
for (int i = 0; i < num_of_ops; i++) {
this.operands.add ((LocalVariable) null);
this.operands.add ((Variable) null);
}
}
}
......@@ -109,11 +109,11 @@ public class Vala.PointerIndirection : Expression {
codegen.visit_expression (this);
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
inner.get_defined_variables (collection);
}
public override void get_used_variables (Collection<LocalVariable> collection) {
public override void get_used_variables (Collection<Variable> collection) {
inner.get_used_variables (collection);
}
}
......@@ -72,15 +72,18 @@ public class Vala.PostfixExpression : Expression {
return false;
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
inner.get_defined_variables (collection);
var local = inner.symbol_reference as LocalVariable;
var param = inner.symbol_reference as Parameter;
if (local != null) {
collection.add (local);
} else if (param != null && param.direction == ParameterDirection.OUT) {
collection.add (param);
}
}
public override void get_used_variables (Collection<LocalVariable> collection) {
public override void get_used_variables (Collection<Variable> collection) {
inner.get_used_variables (collection);
}
......
......@@ -115,11 +115,11 @@ public class Vala.ReferenceTransferExpression : Expression {
codegen.visit_expression (this);
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
inner.get_defined_variables (collection);
}
public override void get_used_variables (Collection<LocalVariable> collection) {
public override void get_used_variables (Collection<Variable> collection) {
inner.get_used_variables (collection);
}
}
......@@ -158,13 +158,13 @@ public class Vala.ReturnStatement : CodeNode, Statement {
codegen.visit_return_statement (this);
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
if (return_expression != null) {
return_expression.get_defined_variables (collection);
}
}
public override void get_used_variables (Collection<LocalVariable> collection) {
public override void get_used_variables (Collection<Variable> collection) {
if (return_expression != null) {
return_expression.get_used_variables (collection);
}
......
......@@ -174,13 +174,13 @@ public class Vala.SliceExpression : Expression {
codegen.visit_expression (this);
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
container.get_defined_variables (collection);
start.get_defined_variables (collection);
stop.get_defined_variables (collection);
}
public override void get_used_variables (Collection<LocalVariable> collection) {
public override void get_used_variables (Collection<Variable> collection) {
container.get_used_variables (collection);
start.get_used_variables (collection);
stop.get_used_variables (collection);
......
......@@ -123,11 +123,11 @@ public class Vala.ThrowStatement : CodeNode, Statement {
codegen.visit_throw_statement (this);
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
error_expression.get_defined_variables (collection);
}
public override void get_used_variables (Collection<LocalVariable> collection) {
public override void get_used_variables (Collection<Variable> collection) {
error_expression.get_used_variables (collection);
}
}
......@@ -253,17 +253,21 @@ public class Vala.UnaryExpression : Expression {
codegen.visit_expression (this);
}
public override void get_defined_variables (Collection<LocalVariable> collection) {
public override void get_defined_variables (Collection<Variable> collection) {
inner.get_defined_variables (collection);
if (operator == UnaryOperator.OUT || operator == UnaryOperator.REF) {
var local = inner.symbol_reference as LocalVariable;
var param = inner.symbol_reference as Parameter;
if (local != null) {
collection.add (local);
}
if (param != null && param.direction == ParameterDirection.OUT) {
collection.add (param);
}
}
}
public override void get_used_variables (Collection<LocalVariable> collection) {
public override void get_used_variables (Collection<Variable> collection) {
if (operator != UnaryOperator.OUT) {
inner.get_used_variables (collection);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment