| 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/compiler.h" | 10 #include "vm/compiler.h" |
| (...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 316 last_used_block_id_(0), // 0 is used for the graph entry. | 316 last_used_block_id_(0), // 0 is used for the graph entry. |
| 317 try_index_(CatchClauseNode::kInvalidTryIndex), | 317 try_index_(CatchClauseNode::kInvalidTryIndex), |
| 318 catch_try_index_(CatchClauseNode::kInvalidTryIndex), | 318 catch_try_index_(CatchClauseNode::kInvalidTryIndex), |
| 319 loop_depth_(0), | 319 loop_depth_(0), |
| 320 graph_entry_(NULL), | 320 graph_entry_(NULL), |
| 321 temp_count_(0), | 321 temp_count_(0), |
| 322 args_pushed_(0), | 322 args_pushed_(0), |
| 323 nesting_stack_(NULL), | 323 nesting_stack_(NULL), |
| 324 osr_id_(osr_id), | 324 osr_id_(osr_id), |
| 325 jump_count_(0), | 325 jump_count_(0), |
| 326 await_joins_(new (Z) ZoneGrowableArray<JoinEntryInstr*>()) {} | 326 await_joins_(new (Z) ZoneGrowableArray<JoinEntryInstr*>()), |
| 327 await_token_positions_(new (Z) ZoneGrowableArray<TokenPosition>()) {} |
| 327 | 328 |
| 328 | 329 |
| 329 void FlowGraphBuilder::AddCatchEntry(CatchBlockEntryInstr* entry) { | 330 void FlowGraphBuilder::AddCatchEntry(CatchBlockEntryInstr* entry) { |
| 330 graph_entry_->AddCatchEntry(entry); | 331 graph_entry_->AddCatchEntry(entry); |
| 331 } | 332 } |
| 332 | 333 |
| 333 | 334 |
| 334 void InlineExitCollector::PrepareGraphs(FlowGraph* callee_graph) { | 335 void InlineExitCollector::PrepareGraphs(FlowGraph* callee_graph) { |
| 335 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1); | 336 ASSERT(callee_graph->graph_entry()->SuccessorCount() == 1); |
| 336 ASSERT(callee_graph->max_block_id() > caller_graph_->max_block_id()); | 337 ASSERT(callee_graph->max_block_id() > caller_graph_->max_block_id()); |
| (...skipping 802 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1139 // However, factories may create an instance of the wrong type. | 1140 // However, factories may create an instance of the wrong type. |
| 1140 if (!is_implicit_dynamic_getter && !function.IsGenerativeConstructor()) { | 1141 if (!is_implicit_dynamic_getter && !function.IsGenerativeConstructor()) { |
| 1141 const AbstractType& dst_type = | 1142 const AbstractType& dst_type = |
| 1142 AbstractType::ZoneHandle(Z, function.result_type()); | 1143 AbstractType::ZoneHandle(Z, function.result_type()); |
| 1143 return_value = | 1144 return_value = |
| 1144 BuildAssignableValue(node->value()->token_pos(), return_value, | 1145 BuildAssignableValue(node->value()->token_pos(), return_value, |
| 1145 dst_type, Symbols::FunctionResult()); | 1146 dst_type, Symbols::FunctionResult()); |
| 1146 } | 1147 } |
| 1147 } | 1148 } |
| 1148 | 1149 |
| 1150 if (function.IsAsyncClosure() || function.IsAsyncGenClosure()) { |
| 1151 // We are returning from an asynchronous closure. Before we do that, be |
| 1152 // sure to clear the thread's asynchronous stack trace. |
| 1153 const Library& async_lib = Library::Handle(Library::AsyncLibrary()); |
| 1154 ASSERT(!async_lib.IsNull()); |
| 1155 const String& private_name = String::ZoneHandle( |
| 1156 async_lib.PrivateName(Symbols::ClearAsyncThreadStackTrace())); |
| 1157 ASSERT(!private_name.IsNull()); |
| 1158 const Function& async_clear_thread_stack_trace = Function::ZoneHandle( |
| 1159 Z, |
| 1160 Resolver::ResolveStatic(async_lib, String::ZoneHandle(String::null()), |
| 1161 private_name, 0, Object::null_array())); |
| 1162 ASSERT(!async_clear_thread_stack_trace.IsNull()); |
| 1163 // Mark that this function is not debuggable. |
| 1164 async_clear_thread_stack_trace.set_is_debuggable(false); |
| 1165 ZoneGrowableArray<PushArgumentInstr*>* no_arguments = |
| 1166 new (Z) ZoneGrowableArray<PushArgumentInstr*>(0); |
| 1167 StaticCallInstr* call_async_clear_thread_stack_trace = new (Z) |
| 1168 StaticCallInstr(node->token_pos().ToSynthetic(), |
| 1169 async_clear_thread_stack_trace, Object::null_array(), |
| 1170 no_arguments, owner()->ic_data_array()); |
| 1171 Do(call_async_clear_thread_stack_trace); |
| 1172 } |
| 1173 |
| 1149 // Async functions contain two types of return statements: | 1174 // Async functions contain two types of return statements: |
| 1150 // 1) Returns that should complete the completer once all finally blocks have | 1175 // 1) Returns that should complete the completer once all finally blocks have |
| 1151 // been inlined (call: :async_completer.complete(return_value)). These | 1176 // been inlined (call: :async_completer.complete(return_value)). These |
| 1152 // returns end up returning null in the end. | 1177 // returns end up returning null in the end. |
| 1153 // 2) "Continuation" returns that should not complete the completer but return | 1178 // 2) "Continuation" returns that should not complete the completer but return |
| 1154 // the value. | 1179 // the value. |
| 1155 // | 1180 // |
| 1156 // We distinguish those kinds of nodes via is_regular_return(). | 1181 // We distinguish those kinds of nodes via is_regular_return(). |
| 1157 // | 1182 // |
| 1158 if (function.IsAsyncClosure() && | 1183 if (function.IsAsyncClosure() && |
| 1159 (node->return_type() == ReturnNode::kRegular)) { | 1184 (node->return_type() == ReturnNode::kRegular)) { |
| 1160 // Temporary store the computed return value. | 1185 // Temporary store the computed return value. |
| 1161 Do(BuildStoreExprTemp(return_value, node->token_pos())); | 1186 Do(BuildStoreExprTemp(return_value, node->token_pos())); |
| 1162 | 1187 |
| 1163 LocalVariable* rcv_var = | 1188 LocalVariable* rcv_var = |
| 1164 node->scope()->LookupVariable(Symbols::AsyncCompleter(), false); | 1189 node->scope()->LookupVariable(Symbols::AsyncCompleter(), false); |
| 1165 ASSERT(rcv_var != NULL && rcv_var->is_captured()); | 1190 ASSERT(rcv_var != NULL && rcv_var->is_captured()); |
| 1166 ZoneGrowableArray<PushArgumentInstr*>* arguments = | 1191 ZoneGrowableArray<PushArgumentInstr*>* arguments = |
| 1167 new (Z) ZoneGrowableArray<PushArgumentInstr*>(2); | 1192 new (Z) ZoneGrowableArray<PushArgumentInstr*>(2); |
| 1168 Value* rcv_value = Bind(BuildLoadLocal(*rcv_var, node->token_pos())); | 1193 Value* rcv_value = Bind(BuildLoadLocal(*rcv_var, node->token_pos())); |
| 1169 arguments->Add(PushArgument(rcv_value)); | 1194 arguments->Add(PushArgument(rcv_value)); |
| 1170 Value* returned_value = Bind(BuildLoadExprTemp(node->token_pos())); | 1195 Value* returned_value = Bind(BuildLoadExprTemp(node->token_pos())); |
| 1171 arguments->Add(PushArgument(returned_value)); | 1196 arguments->Add(PushArgument(returned_value)); |
| 1172 InstanceCallInstr* call = new (Z) InstanceCallInstr( | 1197 |
| 1173 node->token_pos(), Symbols::CompleterComplete(), Token::kILLEGAL, | 1198 const Library& async_library = Library::Handle(Library::AsyncLibrary()); |
| 1174 arguments, Object::null_array(), 1, owner()->ic_data_array()); | 1199 ASSERT(!async_library.IsNull()); |
| 1200 |
| 1201 const Function& complete_on_async_return_function = |
| 1202 Function::ZoneHandle(async_library.LookupFunctionAllowPrivate( |
| 1203 Symbols::CompleterCompleteOnAsyncReturn())); |
| 1204 ASSERT(!complete_on_async_return_function.IsNull()); |
| 1205 |
| 1206 StaticCallInstr* call = new (Z) StaticCallInstr( |
| 1207 node->token_pos().ToSynthetic(), complete_on_async_return_function, |
| 1208 Object::null_array(), arguments, owner()->ic_data_array()); |
| 1175 Do(call); | 1209 Do(call); |
| 1176 | 1210 |
| 1177 // Rebind the return value for the actual return call to be null. | 1211 // Rebind the return value for the actual return call to be null. |
| 1178 return_value = BuildNullValue(node->token_pos()); | 1212 return_value = BuildNullValue(node->token_pos()); |
| 1179 } | 1213 } |
| 1180 | 1214 |
| 1181 intptr_t current_context_level = owner()->context_level(); | 1215 intptr_t current_context_level = owner()->context_level(); |
| 1182 ASSERT(current_context_level >= 0); | 1216 ASSERT(current_context_level >= 0); |
| 1183 if (HasContextScope()) { | 1217 if (HasContextScope()) { |
| 1184 UnchainContexts(current_context_level); | 1218 UnchainContexts(current_context_level); |
| (...skipping 989 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2174 ASSERT((ctx_var != NULL) && ctx_var->is_captured()); | 2208 ASSERT((ctx_var != NULL) && ctx_var->is_captured()); |
| 2175 const intptr_t jump_count = owner()->next_await_counter(); | 2209 const intptr_t jump_count = owner()->next_await_counter(); |
| 2176 ASSERT(jump_count >= 0); | 2210 ASSERT(jump_count >= 0); |
| 2177 // Sanity check that we always add a JoinEntryInstr before adding a new | 2211 // Sanity check that we always add a JoinEntryInstr before adding a new |
| 2178 // state. | 2212 // state. |
| 2179 ASSERT(jump_count == owner()->await_joins()->length()); | 2213 ASSERT(jump_count == owner()->await_joins()->length()); |
| 2180 // Store the counter in :await_jump_var. | 2214 // Store the counter in :await_jump_var. |
| 2181 Value* jump_val = Bind(new (Z) ConstantInstr( | 2215 Value* jump_val = Bind(new (Z) ConstantInstr( |
| 2182 Smi::ZoneHandle(Z, Smi::New(jump_count)), node->token_pos())); | 2216 Smi::ZoneHandle(Z, Smi::New(jump_count)), node->token_pos())); |
| 2183 Do(BuildStoreLocal(*jump_var, jump_val, node->token_pos())); | 2217 Do(BuildStoreLocal(*jump_var, jump_val, node->token_pos())); |
| 2218 // Add a mapping from jump_count -> token_position. |
| 2219 owner()->AppendAwaitTokenPosition(node->token_pos()); |
| 2184 // Save the current context for resuming. | 2220 // Save the current context for resuming. |
| 2185 BuildSaveContext(*ctx_var, node->token_pos()); | 2221 BuildSaveContext(*ctx_var, node->token_pos()); |
| 2186 } | 2222 } |
| 2187 | 2223 |
| 2188 | 2224 |
| 2189 intptr_t EffectGraphVisitor::GetCurrentTempLocalIndex() const { | 2225 intptr_t EffectGraphVisitor::GetCurrentTempLocalIndex() const { |
| 2190 return kFirstLocalSlotFromFp - owner()->num_stack_locals() - | 2226 return kFirstLocalSlotFromFp - owner()->num_stack_locals() - |
| 2191 owner()->num_copied_params() - owner()->args_pushed() - | 2227 owner()->num_copied_params() - owner()->args_pushed() - |
| 2192 owner()->temp_count() + 1; | 2228 owner()->temp_count() + 1; |
| 2193 } | 2229 } |
| (...skipping 1601 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3795 // the function. | 3831 // the function. |
| 3796 Value* null_constant = Bind( | 3832 Value* null_constant = Bind( |
| 3797 new (Z) ConstantInstr(Object::ZoneHandle(Z, Object::null()))); | 3833 new (Z) ConstantInstr(Object::ZoneHandle(Z, Object::null()))); |
| 3798 Do(BuildStoreLocal(*temp_local, null_constant, | 3834 Do(BuildStoreLocal(*temp_local, null_constant, |
| 3799 ST(node->token_pos()))); | 3835 ST(node->token_pos()))); |
| 3800 } | 3836 } |
| 3801 } | 3837 } |
| 3802 } | 3838 } |
| 3803 } | 3839 } |
| 3804 | 3840 |
| 3841 if (is_top_level_sequence && |
| 3842 (function.IsAsyncClosure() || function.IsAsyncGenClosure())) { |
| 3843 LocalScope* top_scope = node->scope(); |
| 3844 // Fetch the :async_stack_trace variable and store it into the thread. |
| 3845 LocalVariable* async_stack_trace_var = |
| 3846 top_scope->LookupVariable(Symbols::AsyncStackTraceVar(), false); |
| 3847 ASSERT((async_stack_trace_var != NULL) && |
| 3848 async_stack_trace_var->is_captured()); |
| 3849 // Load :async_stack_trace |
| 3850 Value* async_stack_trace_value = Bind(BuildLoadLocal( |
| 3851 *async_stack_trace_var, node->token_pos().ToSynthetic())); |
| 3852 // Setup arguments for _asyncSetThreadStackTrace. |
| 3853 ZoneGrowableArray<PushArgumentInstr*>* arguments = |
| 3854 new (Z) ZoneGrowableArray<PushArgumentInstr*>(1); |
| 3855 arguments->Add(PushArgument(async_stack_trace_value)); |
| 3856 |
| 3857 // Lookup _asyncSetThreadStackTrace |
| 3858 const Library& async_lib = Library::Handle(Library::AsyncLibrary()); |
| 3859 ASSERT(!async_lib.IsNull()); |
| 3860 const String& private_name = String::ZoneHandle( |
| 3861 async_lib.PrivateName(Symbols::SetAsyncThreadStackTrace())); |
| 3862 ASSERT(!private_name.IsNull()); |
| 3863 const Function& async_set_thread_stack_trace = Function::ZoneHandle( |
| 3864 Z, |
| 3865 Resolver::ResolveStatic(async_lib, String::ZoneHandle(String::null()), |
| 3866 private_name, 1, Object::null_array())); |
| 3867 ASSERT(!async_set_thread_stack_trace.IsNull()); |
| 3868 // Mark that this function is not debuggable. |
| 3869 async_set_thread_stack_trace.set_is_debuggable(false); |
| 3870 // Call _asyncSetThreadStackTrace |
| 3871 StaticCallInstr* call_async_set_thread_stack_trace = new (Z) |
| 3872 StaticCallInstr(node->token_pos().ToSynthetic(), |
| 3873 async_set_thread_stack_trace, Object::null_array(), |
| 3874 arguments, owner()->ic_data_array()); |
| 3875 Do(call_async_set_thread_stack_trace); |
| 3876 } |
| 3877 |
| 3805 if (FLAG_support_debugger && is_top_level_sequence && | 3878 if (FLAG_support_debugger && is_top_level_sequence && |
| 3806 function.is_debuggable()) { | 3879 function.is_debuggable()) { |
| 3807 // Place a debug check at method entry to ensure breaking on a method always | 3880 // Place a debug check at method entry to ensure breaking on a method always |
| 3808 // happens, even if there are no assignments/calls/runtimecalls in the first | 3881 // happens, even if there are no assignments/calls/runtimecalls in the first |
| 3809 // basic block. Place this check at the last parameter to ensure parameters | 3882 // basic block. Place this check at the last parameter to ensure parameters |
| 3810 // are in scope in the debugger at method entry. | 3883 // are in scope in the debugger at method entry. |
| 3811 const int num_params = function.NumParameters(); | 3884 const int num_params = function.NumParameters(); |
| 3812 TokenPosition check_pos = TokenPosition::kNoSource; | 3885 TokenPosition check_pos = TokenPosition::kNoSource; |
| 3813 if (num_params > 0) { | 3886 if (num_params > 0) { |
| 3814 const LocalVariable& parameter = *scope->VariableAt(num_params - 1); | 3887 const LocalVariable& parameter = *scope->VariableAt(num_params - 1); |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3903 // We are at the top level. Fetch the corresponding scope. | 3976 // We are at the top level. Fetch the corresponding scope. |
| 3904 LocalScope* top_scope = node->scope(); | 3977 LocalScope* top_scope = node->scope(); |
| 3905 LocalVariable* jump_var = | 3978 LocalVariable* jump_var = |
| 3906 top_scope->LookupVariable(Symbols::AwaitJumpVar(), false); | 3979 top_scope->LookupVariable(Symbols::AwaitJumpVar(), false); |
| 3907 ASSERT(jump_var != NULL && jump_var->is_captured()); | 3980 ASSERT(jump_var != NULL && jump_var->is_captured()); |
| 3908 Instruction* saved_entry = entry_; | 3981 Instruction* saved_entry = entry_; |
| 3909 Instruction* saved_exit = exit_; | 3982 Instruction* saved_exit = exit_; |
| 3910 entry_ = NULL; | 3983 entry_ = NULL; |
| 3911 exit_ = NULL; | 3984 exit_ = NULL; |
| 3912 | 3985 |
| 3986 // Load the jump counter. |
| 3913 LoadLocalNode* load_jump_count = | 3987 LoadLocalNode* load_jump_count = |
| 3914 new (Z) LoadLocalNode(node->token_pos(), jump_var); | 3988 new (Z) LoadLocalNode(node->token_pos(), jump_var); |
| 3915 ComparisonNode* check_jump_count; | 3989 ComparisonNode* check_jump_count; |
| 3916 const intptr_t num_await_states = owner()->await_joins()->length(); | 3990 const intptr_t num_await_states = owner()->await_joins()->length(); |
| 3917 | 3991 |
| 3918 LocalVariable* old_context = | 3992 LocalVariable* old_context = |
| 3919 top_scope->LookupVariable(Symbols::AwaitContextVar(), false); | 3993 top_scope->LookupVariable(Symbols::AwaitContextVar(), false); |
| 3920 for (intptr_t i = 0; i < num_await_states; i++) { | 3994 for (intptr_t i = 0; i < num_await_states; i++) { |
| 3921 check_jump_count = new (Z) | 3995 check_jump_count = new (Z) |
| 3922 ComparisonNode(ST(node->token_pos()), Token::kEQ, load_jump_count, | 3996 ComparisonNode(ST(node->token_pos()), Token::kEQ, load_jump_count, |
| (...skipping 407 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4330 | 4404 |
| 4331 // When compiling for OSR, use a depth first search to prune instructions | 4405 // When compiling for OSR, use a depth first search to prune instructions |
| 4332 // unreachable from the OSR entry. Catch entries are always considered | 4406 // unreachable from the OSR entry. Catch entries are always considered |
| 4333 // reachable, even if they become unreachable after OSR. | 4407 // reachable, even if they become unreachable after OSR. |
| 4334 if (osr_id_ != Compiler::kNoOSRDeoptId) { | 4408 if (osr_id_ != Compiler::kNoOSRDeoptId) { |
| 4335 PruneUnreachable(); | 4409 PruneUnreachable(); |
| 4336 } | 4410 } |
| 4337 | 4411 |
| 4338 FlowGraph* graph = | 4412 FlowGraph* graph = |
| 4339 new (Z) FlowGraph(parsed_function(), graph_entry_, last_used_block_id_); | 4413 new (Z) FlowGraph(parsed_function(), graph_entry_, last_used_block_id_); |
| 4414 graph->set_await_token_positions(await_token_positions_); |
| 4340 return graph; | 4415 return graph; |
| 4341 } | 4416 } |
| 4342 | 4417 |
| 4343 | 4418 |
| 4419 void FlowGraphBuilder::AppendAwaitTokenPosition(TokenPosition token_pos) { |
| 4420 await_token_positions_->Add(token_pos); |
| 4421 } |
| 4422 |
| 4423 |
| 4344 void FlowGraphBuilder::PruneUnreachable() { | 4424 void FlowGraphBuilder::PruneUnreachable() { |
| 4345 ASSERT(osr_id_ != Compiler::kNoOSRDeoptId); | 4425 ASSERT(osr_id_ != Compiler::kNoOSRDeoptId); |
| 4346 BitVector* block_marks = new (Z) BitVector(Z, last_used_block_id_ + 1); | 4426 BitVector* block_marks = new (Z) BitVector(Z, last_used_block_id_ + 1); |
| 4347 bool found = | 4427 bool found = |
| 4348 graph_entry_->PruneUnreachable(graph_entry_, NULL, osr_id_, block_marks); | 4428 graph_entry_->PruneUnreachable(graph_entry_, NULL, osr_id_, block_marks); |
| 4349 ASSERT(found); | 4429 ASSERT(found); |
| 4350 } | 4430 } |
| 4351 | 4431 |
| 4352 | 4432 |
| 4353 void FlowGraphBuilder::Bailout(const char* reason) const { | 4433 void FlowGraphBuilder::Bailout(const char* reason) const { |
| 4354 parsed_function_.Bailout("FlowGraphBuilder", reason); | 4434 parsed_function_.Bailout("FlowGraphBuilder", reason); |
| 4355 } | 4435 } |
| 4356 | 4436 |
| 4357 } // namespace dart | 4437 } // namespace dart |
| OLD | NEW |