| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/flow_graph_builder.h" | 5 #include "vm/flow_graph_builder.h" |
| 6 | 6 |
| 7 #include "lib/invocation_mirror.h" | 7 #include "lib/invocation_mirror.h" |
| 8 #include "vm/ast_printer.h" | 8 #include "vm/ast_printer.h" |
| 9 #include "vm/bit_vector.h" | 9 #include "vm/bit_vector.h" |
| 10 #include "vm/class_finalizer.h" | 10 #include "vm/class_finalizer.h" |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 318 last_used_block_id_(0), // 0 is used for the graph entry. | 318 last_used_block_id_(0), // 0 is used for the graph entry. |
| 319 try_index_(CatchClauseNode::kInvalidTryIndex), | 319 try_index_(CatchClauseNode::kInvalidTryIndex), |
| 320 catch_try_index_(CatchClauseNode::kInvalidTryIndex), | 320 catch_try_index_(CatchClauseNode::kInvalidTryIndex), |
| 321 loop_depth_(0), | 321 loop_depth_(0), |
| 322 graph_entry_(NULL), | 322 graph_entry_(NULL), |
| 323 temp_count_(0), | 323 temp_count_(0), |
| 324 args_pushed_(0), | 324 args_pushed_(0), |
| 325 nesting_stack_(NULL), | 325 nesting_stack_(NULL), |
| 326 osr_id_(osr_id), | 326 osr_id_(osr_id), |
| 327 jump_count_(0), | 327 jump_count_(0), |
| 328 await_joins_(new(Z) ZoneGrowableArray<JoinEntryInstr*>()), | 328 await_joins_(new(Z) ZoneGrowableArray<JoinEntryInstr*>()) { } |
| 329 await_levels_(new(Z) ZoneGrowableArray<intptr_t>()) { } | |
| 330 | 329 |
| 331 | 330 |
| 332 void FlowGraphBuilder::AddCatchEntry(CatchBlockEntryInstr* entry) { | 331 void FlowGraphBuilder::AddCatchEntry(CatchBlockEntryInstr* entry) { |
| 333 graph_entry_->AddCatchEntry(entry); | 332 graph_entry_->AddCatchEntry(entry); |
| 334 } | 333 } |
| 335 | 334 |
| 336 | 335 |
| 337 void InlineExitCollector::PrepareGraphs(FlowGraph* callee_graph) { | 336 void InlineExitCollector::PrepareGraphs(FlowGraph* callee_graph) { |
| 338 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1); | 337 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1); |
| 339 ASSERT(callee_graph->max_block_id() > caller_graph_->max_block_id()); | 338 ASSERT(callee_graph->max_block_id() > caller_graph_->max_block_id()); |
| (...skipping 1271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1611 return new(Z) AssertAssignableInstr(token_pos, | 1610 return new(Z) AssertAssignableInstr(token_pos, |
| 1612 value, | 1611 value, |
| 1613 instantiator, | 1612 instantiator, |
| 1614 instantiator_type_arguments, | 1613 instantiator_type_arguments, |
| 1615 dst_type, | 1614 dst_type, |
| 1616 dst_name, | 1615 dst_name, |
| 1617 deopt_id); | 1616 deopt_id); |
| 1618 } | 1617 } |
| 1619 | 1618 |
| 1620 | 1619 |
| 1621 void EffectGraphVisitor::BuildSyncYieldJump(LocalVariable* old_context, | |
| 1622 LocalVariable* iterator_param, | |
| 1623 const intptr_t old_ctx_level, | |
| 1624 JoinEntryInstr* target) { | |
| 1625 // Building a jump consists of the following actions: | |
| 1626 // * Load the generator body's iterator parameter (:iterator) | |
| 1627 // from the current context into a temporary. | |
| 1628 // * Restore the old context from :await_cxt_var. | |
| 1629 // * Copy the iterator saved above into the restored context. | |
| 1630 // * Append a Goto to the target's join. | |
| 1631 ASSERT((iterator_param != NULL) && iterator_param->is_captured()); | |
| 1632 ASSERT((old_context != NULL) && old_context->is_captured()); | |
| 1633 // Before restoring the context we need to temporarily save the | |
| 1634 // iterator parameter. | |
| 1635 LocalVariable* temp_iterator_var = | |
| 1636 EnterTempLocalScope(Bind(BuildLoadLocal(*iterator_param))); | |
| 1637 | |
| 1638 // Restore the saved continuation context, i.e. the context that was | |
| 1639 // saved into :await_ctx_var before the closure suspended. | |
| 1640 BuildRestoreContext(*old_context); | |
| 1641 | |
| 1642 // Store the continuation result and continuation error values into | |
| 1643 // the restored context. | |
| 1644 | |
| 1645 // FlowGraphBuilder is at top context level, but the continuation | |
| 1646 // target has possibly been recorded in a nested context (old_ctx_level). | |
| 1647 // We need to unroll manually here. | |
| 1648 intptr_t delta = | |
| 1649 old_ctx_level - iterator_param->owner()->context_level(); | |
| 1650 ASSERT(delta >= 0); | |
| 1651 Value* context = Bind(BuildCurrentContext()); | |
| 1652 while (delta-- > 0) { | |
| 1653 context = Bind(new(Z) LoadFieldInstr( | |
| 1654 context, Context::parent_offset(), Type::ZoneHandle(Z, Type::null()), | |
| 1655 Scanner::kNoSourcePos)); | |
| 1656 } | |
| 1657 LocalVariable* temp_context_var = EnterTempLocalScope(context); | |
| 1658 | |
| 1659 Value* context_val = Bind(new(Z) LoadLocalInstr(*temp_context_var)); | |
| 1660 Value* store_val = Bind(new(Z) LoadLocalInstr(*temp_iterator_var)); | |
| 1661 StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr( | |
| 1662 Context::variable_offset(iterator_param->index()), | |
| 1663 context_val, | |
| 1664 store_val, | |
| 1665 kEmitStoreBarrier, | |
| 1666 Scanner::kNoSourcePos); | |
| 1667 Do(store); | |
| 1668 | |
| 1669 Do(ExitTempLocalScope(temp_context_var)); | |
| 1670 Do(ExitTempLocalScope(temp_iterator_var)); | |
| 1671 | |
| 1672 // Goto saved join. | |
| 1673 Goto(target); | |
| 1674 } | |
| 1675 | |
| 1676 | |
| 1677 void EffectGraphVisitor::BuildAsyncJump(LocalVariable* old_context, | |
| 1678 LocalVariable* continuation_result, | |
| 1679 LocalVariable* continuation_error, | |
| 1680 LocalVariable* continuation_stack_trace, | |
| 1681 const intptr_t old_ctx_level, | |
| 1682 JoinEntryInstr* target) { | |
| 1683 // Building a jump consists of the following actions: | |
| 1684 // * Load the current continuation result parameter (:async_result) | |
| 1685 // and continuation error parameter (:async_error_param) from | |
| 1686 // the current context into temporaries. | |
| 1687 // * Restore the old context from :await_cxt_var. | |
| 1688 // * Copy the result and error parameters saved above into the restored | |
| 1689 // context. | |
| 1690 // * Append a Goto to the target's join. | |
| 1691 ASSERT((continuation_result != NULL) && continuation_result->is_captured()); | |
| 1692 ASSERT((continuation_error != NULL) && continuation_error->is_captured()); | |
| 1693 ASSERT((old_context != NULL) && old_context->is_captured()); | |
| 1694 // Before restoring the continuation context we need to temporary save the | |
| 1695 // result and error parameter. | |
| 1696 LocalVariable* temp_result_var = | |
| 1697 EnterTempLocalScope(Bind(BuildLoadLocal(*continuation_result))); | |
| 1698 LocalVariable* temp_error_var = | |
| 1699 EnterTempLocalScope(Bind(BuildLoadLocal(*continuation_error))); | |
| 1700 LocalVariable* temp_stack_trace_var = | |
| 1701 EnterTempLocalScope(Bind(BuildLoadLocal(*continuation_stack_trace))); | |
| 1702 | |
| 1703 // Restore the saved continuation context, i.e. the context that was | |
| 1704 // saved into :await_ctx_var before the closure suspended. | |
| 1705 BuildRestoreContext(*old_context); | |
| 1706 | |
| 1707 // Store the continuation result and continuation error values into | |
| 1708 // the restored context. | |
| 1709 | |
| 1710 // FlowGraphBuilder is at top context level, but the await target has possibly | |
| 1711 // been recorded in a nested context (old_ctx_level). We need to unroll | |
| 1712 // manually here. | |
| 1713 intptr_t delta = | |
| 1714 old_ctx_level - continuation_result->owner()->context_level(); | |
| 1715 ASSERT(delta >= 0); | |
| 1716 Value* context = Bind(BuildCurrentContext()); | |
| 1717 while (delta-- > 0) { | |
| 1718 context = Bind(new(Z) LoadFieldInstr( | |
| 1719 context, Context::parent_offset(), Type::ZoneHandle(Z, Type::null()), | |
| 1720 Scanner::kNoSourcePos)); | |
| 1721 } | |
| 1722 LocalVariable* temp_context_var = EnterTempLocalScope(context); | |
| 1723 | |
| 1724 Value* context_val = Bind(new(Z) LoadLocalInstr(*temp_context_var)); | |
| 1725 Value* store_val = Bind(new(Z) LoadLocalInstr(*temp_result_var)); | |
| 1726 StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr( | |
| 1727 Context::variable_offset(continuation_result->index()), | |
| 1728 context_val, | |
| 1729 store_val, | |
| 1730 kEmitStoreBarrier, | |
| 1731 Scanner::kNoSourcePos); | |
| 1732 Do(store); | |
| 1733 context_val = Bind(new(Z) LoadLocalInstr(*temp_context_var)); | |
| 1734 store_val = Bind(new(Z) LoadLocalInstr(*temp_error_var)); | |
| 1735 StoreInstanceFieldInstr* store2 = new(Z) StoreInstanceFieldInstr( | |
| 1736 Context::variable_offset(continuation_error->index()), | |
| 1737 context_val, | |
| 1738 store_val, | |
| 1739 kEmitStoreBarrier, | |
| 1740 Scanner::kNoSourcePos); | |
| 1741 Do(store2); | |
| 1742 | |
| 1743 context_val = Bind(new(Z) LoadLocalInstr(*temp_context_var)); | |
| 1744 store_val = Bind(new(Z) LoadLocalInstr(*temp_stack_trace_var)); | |
| 1745 StoreInstanceFieldInstr* store3 = new(Z) StoreInstanceFieldInstr( | |
| 1746 Context::variable_offset(continuation_stack_trace->index()), | |
| 1747 context_val, | |
| 1748 store_val, | |
| 1749 kEmitStoreBarrier, | |
| 1750 Scanner::kNoSourcePos); | |
| 1751 Do(store3); | |
| 1752 | |
| 1753 Do(ExitTempLocalScope(temp_context_var)); | |
| 1754 Do(ExitTempLocalScope(temp_stack_trace_var)); | |
| 1755 Do(ExitTempLocalScope(temp_error_var)); | |
| 1756 Do(ExitTempLocalScope(temp_result_var)); | |
| 1757 | |
| 1758 // Goto saved join. | |
| 1759 Goto(target); | |
| 1760 } | |
| 1761 | |
| 1762 | |
| 1763 // Used for type casts and to test assignments. | 1620 // Used for type casts and to test assignments. |
| 1764 Value* EffectGraphVisitor::BuildAssignableValue(intptr_t token_pos, | 1621 Value* EffectGraphVisitor::BuildAssignableValue(intptr_t token_pos, |
| 1765 Value* value, | 1622 Value* value, |
| 1766 const AbstractType& dst_type, | 1623 const AbstractType& dst_type, |
| 1767 const String& dst_name) { | 1624 const String& dst_name) { |
| 1768 if (CanSkipTypeCheck(token_pos, value, dst_type, dst_name)) { | 1625 if (CanSkipTypeCheck(token_pos, value, dst_type, dst_name)) { |
| 1769 return value; | 1626 return value; |
| 1770 } | 1627 } |
| 1771 return Bind(BuildAssertAssignable(token_pos, value, dst_type, dst_name)); | 1628 return Bind(BuildAssertAssignable(token_pos, value, dst_type, dst_name)); |
| 1772 } | 1629 } |
| (...skipping 712 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2485 ASSERT(jump_count >= 0); | 2342 ASSERT(jump_count >= 0); |
| 2486 // Sanity check that we always add a JoinEntryInstr before adding a new | 2343 // Sanity check that we always add a JoinEntryInstr before adding a new |
| 2487 // state. | 2344 // state. |
| 2488 ASSERT(jump_count == owner()->await_joins()->length()); | 2345 ASSERT(jump_count == owner()->await_joins()->length()); |
| 2489 // Store the counter in :await_jump_var. | 2346 // Store the counter in :await_jump_var. |
| 2490 Value* jump_val = Bind(new(Z) ConstantInstr( | 2347 Value* jump_val = Bind(new(Z) ConstantInstr( |
| 2491 Smi::ZoneHandle(Z, Smi::New(jump_count)))); | 2348 Smi::ZoneHandle(Z, Smi::New(jump_count)))); |
| 2492 Do(BuildStoreLocal(*jump_var, jump_val)); | 2349 Do(BuildStoreLocal(*jump_var, jump_val)); |
| 2493 // Save the current context for resuming. | 2350 // Save the current context for resuming. |
| 2494 BuildSaveContext(*ctx_var); | 2351 BuildSaveContext(*ctx_var); |
| 2495 owner()->await_levels()->Add(owner()->context_level()); | |
| 2496 } | 2352 } |
| 2497 | 2353 |
| 2498 | 2354 |
| 2499 intptr_t EffectGraphVisitor::GetCurrentTempLocalIndex() const { | 2355 intptr_t EffectGraphVisitor::GetCurrentTempLocalIndex() const { |
| 2500 return kFirstLocalSlotFromFp | 2356 return kFirstLocalSlotFromFp |
| 2501 - owner()->num_stack_locals() | 2357 - owner()->num_stack_locals() |
| 2502 - owner()->num_copied_params() | 2358 - owner()->num_copied_params() |
| 2503 - owner()->args_pushed() | 2359 - owner()->args_pushed() |
| 2504 - owner()->temp_count() + 1; | 2360 - owner()->temp_count() + 1; |
| 2505 } | 2361 } |
| (...skipping 1886 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4392 Scanner::kNoSourcePos, | 4248 Scanner::kNoSourcePos, |
| 4393 Token::kEQ, | 4249 Token::kEQ, |
| 4394 load_jump_count, | 4250 load_jump_count, |
| 4395 new(Z) LiteralNode( | 4251 new(Z) LiteralNode( |
| 4396 Scanner::kNoSourcePos, Smi::ZoneHandle(Z, Smi::New(i)))); | 4252 Scanner::kNoSourcePos, Smi::ZoneHandle(Z, Smi::New(i)))); |
| 4397 TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos); | 4253 TestGraphVisitor for_test(owner(), Scanner::kNoSourcePos); |
| 4398 check_jump_count->Visit(&for_test); | 4254 check_jump_count->Visit(&for_test); |
| 4399 EffectGraphVisitor for_true(owner()); | 4255 EffectGraphVisitor for_true(owner()); |
| 4400 EffectGraphVisitor for_false(owner()); | 4256 EffectGraphVisitor for_false(owner()); |
| 4401 | 4257 |
| 4402 if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) { | 4258 // Build async jump or sync yield jump. |
| 4403 LocalVariable* result_param = | 4259 ASSERT(function.IsAsyncClosure() || |
| 4404 top_scope->LookupVariable(Symbols::AsyncOperationParam(), false); | 4260 function.IsAsyncGenClosure() || |
| 4405 LocalVariable* error_param = | 4261 function.IsSyncGenClosure()); |
| 4406 top_scope->LookupVariable(Symbols::AsyncOperationErrorParam(), | 4262 |
| 4407 false); | 4263 // Restore the saved continuation context, i.e. the context that was |
| 4408 LocalVariable* stack_trace_param = | 4264 // saved into :await_ctx_var before the closure suspended. |
| 4409 top_scope->LookupVariable(Symbols::AsyncOperationStackTraceParam(), | 4265 for_true.BuildRestoreContext(*old_context); |
| 4410 false); | 4266 |
| 4411 for_true.BuildAsyncJump(old_context, | 4267 // Goto saved join. |
| 4412 result_param, | 4268 for_true.Goto((*owner()->await_joins())[i]); |
| 4413 error_param, | |
| 4414 stack_trace_param, | |
| 4415 (*owner()->await_levels())[i], | |
| 4416 (*owner()->await_joins())[i]); | |
| 4417 } else { | |
| 4418 ASSERT(function.IsSyncGenClosure()); | |
| 4419 LocalVariable* iterator_param = | |
| 4420 top_scope->LookupVariable(Symbols::IteratorParameter(), false); | |
| 4421 for_true.BuildSyncYieldJump(old_context, | |
| 4422 iterator_param, | |
| 4423 (*owner()->await_levels())[i], | |
| 4424 (*owner()->await_joins())[i]); | |
| 4425 } | |
| 4426 | 4269 |
| 4427 Join(for_test, for_true, for_false); | 4270 Join(for_test, for_true, for_false); |
| 4428 if (i == 0) { | 4271 if (i == 0) { |
| 4429 // Manually link up the preamble start. | 4272 // Manually link up the preamble start. |
| 4430 preamble_start->previous()->set_next(for_test.entry()); | 4273 preamble_start->previous()->set_next(for_test.entry()); |
| 4431 for_test.entry()->set_previous(preamble_start->previous()); | 4274 for_test.entry()->set_previous(preamble_start->previous()); |
| 4432 } | 4275 } |
| 4433 if (i == (num_await_states - 1)) { | 4276 if (i == (num_await_states - 1)) { |
| 4434 // Link up preamble end. | 4277 // Link up preamble end. |
| 4435 if (exit_ == NULL) { | 4278 if (exit_ == NULL) { |
| (...skipping 396 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4832 Report::MessageF(Report::kBailout, | 4675 Report::MessageF(Report::kBailout, |
| 4833 Script::Handle(function.script()), | 4676 Script::Handle(function.script()), |
| 4834 function.token_pos(), | 4677 function.token_pos(), |
| 4835 "FlowGraphBuilder Bailout: %s %s", | 4678 "FlowGraphBuilder Bailout: %s %s", |
| 4836 String::Handle(function.name()).ToCString(), | 4679 String::Handle(function.name()).ToCString(), |
| 4837 reason); | 4680 reason); |
| 4838 UNREACHABLE(); | 4681 UNREACHABLE(); |
| 4839 } | 4682 } |
| 4840 | 4683 |
| 4841 } // namespace dart | 4684 } // namespace dart |
| OLD | NEW |