| Index: runtime/vm/flow_graph_compiler.cc | 
| diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc | 
| index e1c8a0113e9743421e959d5441295684503e5f4a..665afa336d641d194ad1c16fae6ce58b00088237 100644 | 
| --- a/runtime/vm/flow_graph_compiler.cc | 
| +++ b/runtime/vm/flow_graph_compiler.cc | 
| @@ -196,6 +196,7 @@ FlowGraphCompiler::FlowGraphCompiler( | 
| pc_descriptors_list_(NULL), | 
| stackmap_table_builder_(NULL), | 
| code_source_map_builder_(NULL), | 
| +      catch_entry_state_maps_builder_(NULL), | 
| block_info_(block_order_.length()), | 
| deopt_infos_(), | 
| static_calls_target_table_(), | 
| @@ -267,6 +268,7 @@ bool FlowGraphCompiler::IsPotentialUnboxedField(const Field& field) { | 
| void FlowGraphCompiler::InitCompiler() { | 
| pc_descriptors_list_ = new (zone()) DescriptorList(64); | 
| exception_handlers_list_ = new (zone()) ExceptionHandlerList(); | 
| +  catch_entry_state_maps_builder_ = new (zone()) CatchEntryStateMapBuilder(); | 
| block_info_.Clear(); | 
| // Conservative detection of leaf routines used to remove the stack check | 
| // on function entry. | 
| @@ -412,6 +414,91 @@ void FlowGraphCompiler::CompactBlocks() { | 
| } | 
|  | 
|  | 
| +void FlowGraphCompiler::EmitCatchEntryState(Environment* env, | 
| +                                            intptr_t try_index) { | 
| +#if defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME) | 
| +  env = env ? env : pending_deoptimization_env_; | 
| +  try_index = try_index != CatchClauseNode::kInvalidTryIndex | 
| +                  ? try_index | 
| +                  : CurrentTryIndex(); | 
| +  if (is_optimizing() && env != NULL && | 
| +      (try_index != CatchClauseNode::kInvalidTryIndex)) { | 
| +    env = env->Outermost(); | 
| +    CatchBlockEntryInstr* catch_block = | 
| +        flow_graph().graph_entry()->GetCatchEntry(try_index); | 
| +    const GrowableArray<Definition*>* idefs = | 
| +        catch_block->initial_definitions(); | 
| +    catch_entry_state_maps_builder_->NewMapping(assembler()->CodeSize()); | 
| +    // Parameters first. | 
| +    intptr_t i = 0; | 
| +    const intptr_t num_non_copied_params = flow_graph().num_non_copied_params(); | 
| +    for (; i < num_non_copied_params; ++i) { | 
| +      // Don't sync captured parameters. They are not in the environment. | 
| +      if (flow_graph().captured_parameters()->Contains(i)) continue; | 
| +      if ((*idefs)[i]->IsConstant()) continue;  // Common constants. | 
| +      Location src = env->LocationAt(i); | 
| +      intptr_t dest_index = i - num_non_copied_params; | 
| +      if (!src.IsStackSlot()) { | 
| +        ASSERT(src.IsConstant()); | 
| +        // Skip dead locations. | 
| +        if (src.constant().raw() == Symbols::OptimizedOut().raw()) { | 
| +          continue; | 
| +        } | 
| +        intptr_t id = | 
| +            assembler()->object_pool_wrapper().FindObject(src.constant()); | 
| +        catch_entry_state_maps_builder_->AppendConstant(id, dest_index); | 
| +        continue; | 
| +      } | 
| +      if (src.stack_index() != dest_index) { | 
| +        catch_entry_state_maps_builder_->AppendMove(src.stack_index(), | 
| +                                                    dest_index); | 
| +      } | 
| +    } | 
| + | 
| +    // Process locals. Skip exception_var and stacktrace_var. | 
| +    intptr_t local_base = kFirstLocalSlotFromFp + num_non_copied_params; | 
| +    intptr_t ex_idx = local_base - catch_block->exception_var().index(); | 
| +    intptr_t st_idx = local_base - catch_block->stacktrace_var().index(); | 
| +    for (; i < flow_graph().variable_count(); ++i) { | 
| +      // Don't sync captured parameters. They are not in the environment. | 
| +      if (flow_graph().captured_parameters()->Contains(i)) continue; | 
| +      if (i == ex_idx || i == st_idx) continue; | 
| +      if ((*idefs)[i]->IsConstant()) continue;  // Common constants. | 
| +      Location src = env->LocationAt(i); | 
| +      if (src.IsInvalid()) continue; | 
| +      intptr_t dest_index = i - num_non_copied_params; | 
| +      if (!src.IsStackSlot()) { | 
| +        ASSERT(src.IsConstant()); | 
| +        // Skip dead locations. | 
| +        if (src.constant().raw() == Symbols::OptimizedOut().raw()) { | 
| +          continue; | 
| +        } | 
| +        intptr_t id = | 
| +            assembler()->object_pool_wrapper().FindObject(src.constant()); | 
| +        catch_entry_state_maps_builder_->AppendConstant(id, dest_index); | 
| +        continue; | 
| +      } | 
| +      if (src.stack_index() != dest_index) { | 
| +        catch_entry_state_maps_builder_->AppendMove(src.stack_index(), | 
| +                                                    dest_index); | 
| +      } | 
| +    } | 
| +    catch_entry_state_maps_builder_->EndMapping(); | 
| +  } | 
| +#endif  // defined(DART_PRECOMPILER) || defined(DART_PRECOMPILED_RUNTIME) | 
| +} | 
| + | 
| + | 
| +void FlowGraphCompiler::EmitCallsiteMetaData(TokenPosition token_pos, | 
| +                                             intptr_t deopt_id, | 
| +                                             RawPcDescriptors::Kind kind, | 
| +                                             LocationSummary* locs) { | 
| +  AddCurrentDescriptor(kind, deopt_id, token_pos); | 
| +  RecordSafepoint(locs); | 
| +  EmitCatchEntryState(); | 
| +} | 
| + | 
| + | 
| void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) { | 
| if (!is_optimizing()) { | 
| if (instr->CanBecomeDeoptimizationTarget() && !instr->IsGoto()) { | 
| @@ -422,10 +509,6 @@ void FlowGraphCompiler::EmitInstructionPrologue(Instruction* instr) { | 
| instr->token_pos()); | 
| } | 
| AllocateRegistersLocally(instr); | 
| -  } else if (instr->MayThrow() && | 
| -             (CurrentTryIndex() != CatchClauseNode::kInvalidTryIndex)) { | 
| -    // Optimized try-block: Sync locals to fixed stack locations. | 
| -    EmitTrySync(instr, CurrentTryIndex()); | 
| } | 
| } | 
|  | 
| @@ -544,69 +627,6 @@ void FlowGraphCompiler::Bailout(const char* reason) { | 
| } | 
|  | 
|  | 
| -void FlowGraphCompiler::EmitTrySync(Instruction* instr, intptr_t try_index) { | 
| -  ASSERT(is_optimizing()); | 
| -  Environment* env = instr->env()->Outermost(); | 
| -  CatchBlockEntryInstr* catch_block = | 
| -      flow_graph().graph_entry()->GetCatchEntry(try_index); | 
| -  const GrowableArray<Definition*>* idefs = catch_block->initial_definitions(); | 
| - | 
| -  // Construct a ParallelMove instruction for parameters and locals. Skip the | 
| -  // special locals exception_var and stacktrace_var since they will be filled | 
| -  // when an exception is thrown. Constant locations are known to be the same | 
| -  // at all instructions that may throw, and do not need to be materialized. | 
| - | 
| -  // Parameters first. | 
| -  intptr_t i = 0; | 
| -  const intptr_t num_non_copied_params = flow_graph().num_non_copied_params(); | 
| -  ParallelMoveInstr* move_instr = new (zone()) ParallelMoveInstr(); | 
| -  for (; i < num_non_copied_params; ++i) { | 
| -    // Don't sync captured parameters. They are not in the environment. | 
| -    if (flow_graph().captured_parameters()->Contains(i)) continue; | 
| -    if ((*idefs)[i]->IsConstant()) continue;  // Common constants | 
| -    Location src = env->LocationAt(i); | 
| -#if defined(TARGET_ARCH_DBC) | 
| -    intptr_t dest_index = kNumberOfCpuRegisters - 1 - i; | 
| -    Location dest = Location::RegisterLocation(dest_index); | 
| -    // Update safepoint bitmap to indicate that the target location | 
| -    // now contains a pointer. With DBC parameters are copied into | 
| -    // the locals area. | 
| -    instr->locs()->SetStackBit(dest_index); | 
| -#else | 
| -    intptr_t dest_index = i - num_non_copied_params; | 
| -    Location dest = Location::StackSlot(dest_index); | 
| -#endif | 
| -    move_instr->AddMove(dest, src); | 
| -  } | 
| - | 
| -  // Process locals. Skip exception_var and stacktrace_var. | 
| -  intptr_t local_base = kFirstLocalSlotFromFp + num_non_copied_params; | 
| -  intptr_t ex_idx = local_base - catch_block->exception_var().index(); | 
| -  intptr_t st_idx = local_base - catch_block->stacktrace_var().index(); | 
| -  for (; i < flow_graph().variable_count(); ++i) { | 
| -    // Don't sync captured parameters. They are not in the environment. | 
| -    if (flow_graph().captured_parameters()->Contains(i)) continue; | 
| -    if (i == ex_idx || i == st_idx) continue; | 
| -    if ((*idefs)[i]->IsConstant()) continue; | 
| -    Location src = env->LocationAt(i); | 
| -    ASSERT(!src.IsFpuRegister()); | 
| -    ASSERT(!src.IsDoubleStackSlot()); | 
| -#if defined(TARGET_ARCH_DBC) | 
| -    intptr_t dest_index = kNumberOfCpuRegisters - 1 - i; | 
| -    Location dest = Location::RegisterLocation(dest_index); | 
| -#else | 
| -    intptr_t dest_index = i - num_non_copied_params; | 
| -    Location dest = Location::StackSlot(dest_index); | 
| -#endif | 
| -    move_instr->AddMove(dest, src); | 
| -    // Update safepoint bitmap to indicate that the target location | 
| -    // now contains a pointer. | 
| -    instr->locs()->SetStackBit(dest_index); | 
| -  } | 
| -  parallel_move_resolver()->EmitNativeCode(move_instr); | 
| -} | 
| - | 
| - | 
| intptr_t FlowGraphCompiler::StackSize() const { | 
| if (is_optimizing_) { | 
| return flow_graph_.graph_entry()->spill_slot_count(); | 
| @@ -1015,6 +1035,15 @@ void FlowGraphCompiler::FinalizeVarDescriptors(const Code& code) { | 
| code.set_var_descriptors(var_descs); | 
| } | 
|  | 
| +void FlowGraphCompiler::FinalizeCatchEntryStateMap(const Code& code) { | 
| +#if defined(DART_PRECOMPILED_RUNTIME) || defined(DART_PRECOMPILER) | 
| +  TypedData& maps = TypedData::Handle( | 
| +      catch_entry_state_maps_builder_->FinalizeCatchEntryStateMap()); | 
| +  code.set_catch_entry_state_maps(maps); | 
| +#else | 
| +  code.set_variables(Smi::Handle(Smi::New(flow_graph().variable_count()))); | 
| +#endif | 
| +} | 
|  | 
| void FlowGraphCompiler::FinalizeStaticCallTargetsTable(const Code& code) { | 
| ASSERT(code.static_calls_target_table() == Array::null()); | 
| @@ -1123,6 +1152,23 @@ bool FlowGraphCompiler::TryIntrinsify() { | 
| // DBC is very different from other architectures in how it performs instance | 
| // and static calls because it does not use stubs. | 
| #if !defined(TARGET_ARCH_DBC) | 
| +void FlowGraphCompiler::GenerateCallWithDeopt(TokenPosition token_pos, | 
| +                                              intptr_t deopt_id, | 
| +                                              const StubEntry& stub_entry, | 
| +                                              RawPcDescriptors::Kind kind, | 
| +                                              LocationSummary* locs) { | 
| +  GenerateCall(token_pos, stub_entry, kind, locs); | 
| +  const intptr_t deopt_id_after = Thread::ToDeoptAfter(deopt_id); | 
| +  if (is_optimizing()) { | 
| +    AddDeoptIndexAtCall(deopt_id_after); | 
| +  } else { | 
| +    // Add deoptimization continuation point after the call and before the | 
| +    // arguments are removed. | 
| +    AddCurrentDescriptor(RawPcDescriptors::kDeopt, deopt_id_after, token_pos); | 
| +  } | 
| +} | 
| + | 
| + | 
| void FlowGraphCompiler::GenerateInstanceCall(intptr_t deopt_id, | 
| TokenPosition token_pos, | 
| intptr_t argument_count, | 
|  |