Index: runtime/vm/kernel_to_il.cc |
diff --git a/runtime/vm/kernel_to_il.cc b/runtime/vm/kernel_to_il.cc |
index 22299a884a28e0ae894af03c3b33e69ebe3f63a8..e53f031015fde7f2b4fb4926346379100edc9ece 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; |
@@ -2525,10 +2539,27 @@ 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; |
+ |
+ // Doing what's done in EffectGraphVisitor::VisitReturnNode. |
Kevin Millikin (Google)
2017/01/24 13:44:13
This kind of comment isn't useful.
It won't even
jensj
2017/01/25 12:52:22
I will remove the comment.
|
+ |
+ // Call to stub that checks whether the debugger is in single |
+ // step mode. This call must happen before the contexts are |
+ // unchained so that captured variables can be inspected. |
+ // No debugger check is done in native functions or for return |
+ // statements for which there is no associated source position. |
+ const Function& function = parsed_function_->function(); |
Kevin Millikin (Google)
2017/01/24 13:44:13
Note that we are not doing the same thing as the c
jensj
2017/01/25 12:52:22
I don't think that's the issue (in regards to the
|
+ 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(); |
} |
@@ -2648,6 +2679,18 @@ Fragment FlowGraphBuilder::StoreLocal(TokenPosition position, |
StoreInstanceField(Context::variable_offset(variable->index())); |
} else { |
Value* value = Pop(); |
+ // Do approximately as in EffectGraphVisitor::VisitStoreLocalNode. |
Kevin Millikin (Google)
2017/01/24 13:44:13
Again, this comment isn't useful.
This seems some
jensj
2017/01/25 12:52:22
I will remove the comment.
I would suggest going
|
+ 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; |
@@ -3161,6 +3204,35 @@ 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. |
+ // Basically copied from EffectGraphVisitor::VisitSequenceNode. |
+ Fragment dispatch; |
+ 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()); |
+ } |
+ dispatch <<= |
Kevin Millikin (Google)
2017/01/24 13:44:13
I'm not sure why this is called dispatch. I don't
jensj
2017/01/25 12:52:22
Done.
|
+ new (Z) DebugStepCheckInstr(check_pos, RawPcDescriptors::kRuntimeCall); |
+ dispatch.entry->LinkTo(body.entry); |
+ body = dispatch; |
+ } |
+ |
normal_entry->LinkTo(body.entry); |
// When compiling for OSR, use a depth first search to prune instructions |