Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(98)

Side by Side Diff: runtime/vm/flow_graph_builder.cc

Issue 2603383004: Sane asynchronous debugging and stack traces (Closed)
Patch Set: rebase Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/flow_graph_builder.h ('k') | runtime/vm/intrinsifier_x64.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_builder.h ('k') | runtime/vm/intrinsifier_x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698