Index: runtime/vm/flow_graph.cc |
=================================================================== |
--- runtime/vm/flow_graph.cc (revision 41393) |
+++ runtime/vm/flow_graph.cc (working copy) |
@@ -8,6 +8,7 @@ |
#include "vm/flow_graph_builder.h" |
#include "vm/intermediate_language.h" |
#include "vm/growable_array.h" |
+#include "vm/object_store.h" |
#include "vm/report.h" |
namespace dart { |
@@ -36,6 +37,7 @@ |
optimized_block_order_(), |
constant_null_(NULL), |
constant_dead_(NULL), |
+ constant_empty_context_(NULL), |
block_effects_(NULL), |
licm_allowed_(true), |
loop_headers_(NULL), |
@@ -465,10 +467,13 @@ |
// Returns true if the value set by the given store reaches any load from the |
// same local variable. |
bool IsStoreAlive(BlockEntryInstr* block, StoreLocalInstr* store) { |
+ if (store->local().Equals(*flow_graph_->CurrentContextVar())) { |
+ return true; |
+ } |
+ |
if (store->is_dead()) { |
return false; |
} |
- |
if (store->is_last()) { |
const intptr_t index = store->local().BitIndexIn(num_non_copied_params_); |
return GetLiveOutSet(block)->Contains(index); |
@@ -480,6 +485,9 @@ |
// Returns true if the given load is the last for the local and the value |
// of the local will not flow into another one. |
bool IsLastLoad(BlockEntryInstr* block, LoadLocalInstr* load) { |
+ if (load->local().Equals(*flow_graph_->CurrentContextVar())) { |
+ return false; |
+ } |
const intptr_t index = load->local().BitIndexIn(num_non_copied_params_); |
return load->is_last() && !GetLiveOutSet(block)->Contains(index); |
} |
@@ -565,11 +573,13 @@ |
VariableLivenessAnalysis variable_liveness(this); |
variable_liveness.Analyze(); |
+ GrowableArray<PhiInstr*> live_phis; |
+ |
InsertPhis(preorder_, |
variable_liveness.ComputeAssignedVars(), |
- dominance_frontier); |
+ dominance_frontier, |
+ &live_phis); |
- GrowableArray<PhiInstr*> live_phis; |
// Rename uses to reference inserted phis where appropriate. |
// Collect phis that reach a non-environment use. |
@@ -702,7 +712,8 @@ |
void FlowGraph::InsertPhis( |
const GrowableArray<BlockEntryInstr*>& preorder, |
const GrowableArray<BitVector*>& assigned_vars, |
- const GrowableArray<BitVector*>& dom_frontier) { |
+ const GrowableArray<BitVector*>& dom_frontier, |
+ GrowableArray<PhiInstr*>* live_phis) { |
const intptr_t block_count = preorder.length(); |
// Map preorder block number to the highest variable index that has a phi |
// in that block. Use it to avoid inserting multiple phis for the same |
@@ -722,6 +733,7 @@ |
// Insert phis for each variable in turn. |
GrowableArray<BlockEntryInstr*> worklist; |
for (intptr_t var_index = 0; var_index < variable_count(); ++var_index) { |
+ const bool always_live = var_index == CurrentContextEnvIndex(); |
// Add to the worklist each block containing an assignment. |
for (intptr_t block_index = 0; block_index < block_count; ++block_index) { |
if (assigned_vars[block_index]->Contains(var_index)) { |
@@ -740,7 +752,12 @@ |
if (has_already[index] < var_index) { |
BlockEntryInstr* block = preorder[index]; |
ASSERT(block->IsJoinEntry()); |
- block->AsJoinEntry()->InsertPhi(var_index, variable_count()); |
+ PhiInstr* phi = block->AsJoinEntry()->InsertPhi(var_index, |
+ variable_count()); |
+ if (always_live) { |
+ phi->mark_alive(); |
+ live_phis->Add(phi); |
+ } |
has_already[index] = var_index; |
if (work[index] < var_index) { |
work[index] = var_index; |
@@ -764,6 +781,8 @@ |
// Add global constants to the initial definitions. |
constant_null_ = GetConstant(Object::ZoneHandle()); |
constant_dead_ = GetConstant(Symbols::OptimizedOut()); |
+ constant_empty_context_ = GetConstant(Context::Handle( |
+ isolate()->object_store()->empty_context())); |
// Add parameters to the initial definitions and renaming environment. |
if (inlining_parameters != NULL) { |
@@ -787,11 +806,22 @@ |
} |
} |
- // Initialize all locals with #null in the renaming environment. For OSR, |
- // the locals have already been handled as parameters. |
+ // Initialize all locals in the renaming environment For OSR, the locals have |
+ // already been handled as parameters. |
if (!IsCompiledForOsr()) { |
for (intptr_t i = parameter_count(); i < variable_count(); ++i) { |
- env.Add(constant_null()); |
+ if (i == CurrentContextEnvIndex()) { |
+ if (parsed_function().function().IsClosureFunction()) { |
+ CurrentContextInstr* context = new CurrentContextInstr(); |
+ context->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp. |
+ AddToInitialDefinitions(context); |
+ env.Add(context); |
+ } else { |
+ env.Add(constant_empty_context()); |
+ } |
+ } else { |
+ env.Add(constant_null()); |
+ } |
} |
} |
@@ -812,12 +842,6 @@ |
*env, |
num_non_copied_params_, |
&parsed_function_); |
- // TODO(fschneider): Add predicates CanEagerlyDeoptimize and |
- // CanLazilyDeoptimize to instructions to generally deal with instructions |
- // that have pushed arguments and input operands. |
- // Right now, closure calls are the only instructions that have both. They |
- // also don't have an eager deoptimziation point, so the environment attached |
- // here is only used for after the call. |
if (instr->IsClosureCall()) { |
deopt_env = deopt_env->DeepCopy(isolate(), |
deopt_env->Length() - instr->InputCount()); |
@@ -846,7 +870,7 @@ |
if (phi != NULL) { |
(*env)[i] = phi; |
phi->set_ssa_temp_index(alloc_ssa_temp_index()); // New SSA temp. |
- if (block_entry->InsideTryBlock()) { |
+ if (block_entry->InsideTryBlock() && !phi->is_alive()) { |
// This is a safe approximation. Inside try{} all locals are |
// used at every call implicitly, so we mark all phis as live |
// from the start. |
@@ -872,7 +896,9 @@ |
// slots with null. |
BitVector* live_in = variable_liveness->GetLiveInSet(block_entry); |
for (intptr_t i = 0; i < variable_count(); i++) { |
- if (!live_in->Contains(i)) { |
+ // TODO(fschneider): Make sure that live_in always contains the |
+ // CurrentContext variable to avoid the special case here. |
+ if (!live_in->Contains(i) && (i != CurrentContextEnvIndex())) { |
(*env)[i] = constant_dead(); |
} |
} |