Chromium Code Reviews| 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 |