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 |