Index: runtime/vm/kernel_to_il.cc |
diff --git a/runtime/vm/kernel_to_il.cc b/runtime/vm/kernel_to_il.cc |
index 11a84e2ffe6f9bbc55a57a82685f8b6ff037a375..5c2da64386508f519533c888b9a1b2bbeda37f15 100644 |
--- a/runtime/vm/kernel_to_il.cc |
+++ b/runtime/vm/kernel_to_il.cc |
@@ -366,6 +366,20 @@ ScopeBuildingResult* ScopeBuilder::BuildScopes() { |
// will forward the call to the real function. |
// -> see BuildGraphOfImplicitClosureFunction |
if (!function.IsImplicitClosureFunction()) { |
+ // TODO(jensj): HACK: Push the begin token to after any parameters to |
+ // avoid crash when breaking on definition line of async method in |
+ // debugger. It seems that another scope needs to be added |
+ // in which captures are made, but I can't make that work. |
+ // This 'solution' doesn't crash, but I cannot see the parameters at |
+ // that particular breakpoint either. |
+ // Also push the end token to after the "}" to avoid crashing on |
+ // stepping past the last line (to the "}" character). |
+ if (node->body() != NULL && node->body()->position().IsReal()) { |
+ scope_->set_begin_token_pos(node->body()->position()); |
+ } |
+ if (scope_->end_token_pos().IsReal()) { |
+ scope_->set_end_token_pos(scope_->end_token_pos().Next()); |
+ } |
node_->AcceptVisitor(this); |
} |
break; |
@@ -2535,10 +2549,20 @@ Fragment FlowGraphBuilder::PushArgument() { |
Fragment FlowGraphBuilder::Return(TokenPosition position) { |
Value* value = Pop(); |
ASSERT(stack_ == NULL); |
- ReturnInstr* return_instr = |
- new (Z) ReturnInstr(TokenPosition::kNoSource, value); |
+ |
+ Fragment fragment; |
+ |
+ const Function& function = parsed_function_->function(); |
+ if (FLAG_support_debugger && position.IsDebugPause() && |
+ !function.is_native()) { |
+ fragment <<= |
+ new (Z) DebugStepCheckInstr(position, RawPcDescriptors::kRuntimeCall); |
+ } |
+ |
+ ReturnInstr* return_instr = new (Z) ReturnInstr(position, value); |
if (exit_collector_ != NULL) exit_collector_->AddExit(return_instr); |
- return Fragment(return_instr).closed(); |
+ fragment <<= return_instr; |
+ return fragment.closed(); |
} |
@@ -2662,6 +2686,17 @@ Fragment FlowGraphBuilder::StoreLocal(TokenPosition position, |
StoreInstanceField(Context::variable_offset(variable->index())); |
} else { |
Value* value = Pop(); |
+ if (FLAG_support_debugger && position.IsDebugPause() && |
+ !variable->IsInternal()) { |
+ if (value->definition()->IsConstant() || |
+ value->definition()->IsAllocateObject() || |
+ (value->definition()->IsLoadLocal() && |
+ !value->definition()->AsLoadLocal()->local().IsInternal())) { |
+ instructions <<= new (Z) |
+ DebugStepCheckInstr(position, RawPcDescriptors::kRuntimeCall); |
+ } |
+ } |
+ |
StoreLocalInstr* store = |
new (Z) StoreLocalInstr(*variable, value, position); |
instructions <<= store; |
@@ -3175,6 +3210,32 @@ FlowGraph* FlowGraphBuilder::BuildGraphOfFunction(FunctionNode* function, |
context_depth_ = current_context_depth; |
} |
+ if (FLAG_support_debugger && function->position().IsDebugPause() && |
+ !dart_function.is_native() && dart_function.is_debuggable()) { |
+ // If a switch was added above: Start the switch by injecting a debugable |
+ // safepoint so stepping over an await works. |
+ // If not, still start the body with a debugable safepoint to ensure |
+ // breaking on a method always happens, even if there are no |
+ // assignments/calls/runtimecalls in the first basic block. |
+ // Place this check at the last parameter to ensure parameters |
+ // are in scope in the debugger at method entry. |
+ const int num_params = dart_function.NumParameters(); |
+ TokenPosition check_pos = TokenPosition::kNoSource; |
+ if (num_params > 0) { |
+ LocalScope* scope = parsed_function_->node_sequence()->scope(); |
+ const LocalVariable& parameter = *scope->VariableAt(num_params - 1); |
+ check_pos = parameter.token_pos(); |
+ } |
+ if (!check_pos.IsDebugPause()) { |
+ // No parameters or synthetic parameters. |
+ check_pos = function->position(); |
+ ASSERT(check_pos.IsDebugPause()); |
+ } |
+ Fragment check( |
+ new (Z) DebugStepCheckInstr(check_pos, RawPcDescriptors::kRuntimeCall)); |
+ body = check + body; |
+ } |
+ |
normal_entry->LinkTo(body.entry); |
// When compiling for OSR, use a depth first search to prune instructions |