OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/debug/debug.h" | 5 #include "src/debug/debug.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "src/api.h" | 9 #include "src/api.h" |
10 #include "src/arguments.h" | 10 #include "src/arguments.h" |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
109 } | 109 } |
110 | 110 |
111 bool BreakLocation::HasBreakPoint(Handle<DebugInfo> debug_info) const { | 111 bool BreakLocation::HasBreakPoint(Handle<DebugInfo> debug_info) const { |
112 // First check whether there is a break point with the same source position. | 112 // First check whether there is a break point with the same source position. |
113 if (!debug_info->HasBreakPoint(position_)) return false; | 113 if (!debug_info->HasBreakPoint(position_)) return false; |
114 // Then check whether a break point at that source position would have | 114 // Then check whether a break point at that source position would have |
115 // the same code offset. Otherwise it's just a break location that we can | 115 // the same code offset. Otherwise it's just a break location that we can |
116 // step to, but not actually a location where we can put a break point. | 116 // step to, but not actually a location where we can put a break point. |
117 if (abstract_code_->IsCode()) { | 117 if (abstract_code_->IsCode()) { |
118 DCHECK_EQ(debug_info->DebugCode(), abstract_code_->GetCode()); | 118 DCHECK_EQ(debug_info->DebugCode(), abstract_code_->GetCode()); |
119 CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 119 CodeBreakIterator it(debug_info); |
120 it.SkipToPosition(position_, BREAK_POSITION_ALIGNED); | 120 it.SkipToPosition(position_, BREAK_POSITION_ALIGNED); |
121 return it.code_offset() == code_offset_; | 121 return it.code_offset() == code_offset_; |
122 } else { | 122 } else { |
123 DCHECK(abstract_code_->IsBytecodeArray()); | 123 DCHECK(abstract_code_->IsBytecodeArray()); |
124 BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 124 BytecodeArrayBreakIterator it(debug_info); |
125 it.SkipToPosition(position_, BREAK_POSITION_ALIGNED); | 125 it.SkipToPosition(position_, BREAK_POSITION_ALIGNED); |
126 return it.code_offset() == code_offset_; | 126 return it.code_offset() == code_offset_; |
127 } | 127 } |
128 } | 128 } |
129 | 129 |
130 std::unique_ptr<BreakIterator> BreakIterator::GetIterator( | 130 std::unique_ptr<BreakIterator> BreakIterator::GetIterator( |
131 Handle<DebugInfo> debug_info, Handle<AbstractCode> abstract_code, | 131 Handle<DebugInfo> debug_info, Handle<AbstractCode> abstract_code) { |
132 BreakLocatorType type) { | |
133 if (abstract_code->IsBytecodeArray()) { | 132 if (abstract_code->IsBytecodeArray()) { |
134 DCHECK(debug_info->HasDebugBytecodeArray()); | 133 DCHECK(debug_info->HasDebugBytecodeArray()); |
135 return std::unique_ptr<BreakIterator>( | 134 return std::unique_ptr<BreakIterator>( |
136 new BytecodeArrayBreakIterator(debug_info, type)); | 135 new BytecodeArrayBreakIterator(debug_info)); |
137 } else { | 136 } else { |
138 DCHECK(abstract_code->IsCode()); | 137 DCHECK(abstract_code->IsCode()); |
139 DCHECK(debug_info->HasDebugCode()); | 138 DCHECK(debug_info->HasDebugCode()); |
140 return std::unique_ptr<BreakIterator>( | 139 return std::unique_ptr<BreakIterator>(new CodeBreakIterator(debug_info)); |
141 new CodeBreakIterator(debug_info, type)); | |
142 } | 140 } |
143 } | 141 } |
144 | 142 |
145 BreakIterator::BreakIterator(Handle<DebugInfo> debug_info, | 143 BreakIterator::BreakIterator(Handle<DebugInfo> debug_info) |
146 BreakLocatorType type) | 144 : debug_info_(debug_info), break_index_(-1) { |
147 : debug_info_(debug_info), break_index_(-1), break_locator_type_(type) { | |
148 position_ = debug_info->shared()->start_position(); | 145 position_ = debug_info->shared()->start_position(); |
149 statement_position_ = position_; | 146 statement_position_ = position_; |
150 } | 147 } |
151 | 148 |
152 int BreakIterator::BreakIndexFromPosition(int source_position, | 149 int BreakIterator::BreakIndexFromPosition(int source_position, |
153 BreakPositionAlignment alignment) { | 150 BreakPositionAlignment alignment) { |
154 int distance = kMaxInt; | 151 int distance = kMaxInt; |
155 int closest_break = break_index(); | 152 int closest_break = break_index(); |
156 while (!Done()) { | 153 while (!Done()) { |
157 int next_position; | 154 int next_position; |
158 if (alignment == STATEMENT_ALIGNED) { | 155 if (alignment == STATEMENT_ALIGNED) { |
159 next_position = statement_position(); | 156 next_position = statement_position(); |
160 } else { | 157 } else { |
161 DCHECK(alignment == BREAK_POSITION_ALIGNED); | 158 DCHECK(alignment == BREAK_POSITION_ALIGNED); |
162 next_position = position(); | 159 next_position = position(); |
163 } | 160 } |
164 if (source_position <= next_position && | 161 if (source_position <= next_position && |
165 next_position - source_position < distance) { | 162 next_position - source_position < distance) { |
166 closest_break = break_index(); | 163 closest_break = break_index(); |
167 distance = next_position - source_position; | 164 distance = next_position - source_position; |
168 // Check whether we can't get any closer. | 165 // Check whether we can't get any closer. |
169 if (distance == 0) break; | 166 if (distance == 0) break; |
170 } | 167 } |
171 Next(); | 168 Next(); |
172 } | 169 } |
173 return closest_break; | 170 return closest_break; |
174 } | 171 } |
175 | 172 |
176 CodeBreakIterator::CodeBreakIterator(Handle<DebugInfo> debug_info, | 173 CodeBreakIterator::CodeBreakIterator(Handle<DebugInfo> debug_info) |
177 BreakLocatorType type) | 174 : BreakIterator(debug_info), |
178 : BreakIterator(debug_info, type), | 175 reloc_iterator_(debug_info->DebugCode(), GetModeMask()), |
179 reloc_iterator_(debug_info->DebugCode(), GetModeMask(type)), | |
180 source_position_iterator_( | 176 source_position_iterator_( |
181 debug_info->DebugCode()->source_position_table()) { | 177 debug_info->DebugCode()->source_position_table()) { |
182 // There is at least one break location. | 178 // There is at least one break location. |
183 DCHECK(!Done()); | 179 DCHECK(!Done()); |
184 Next(); | 180 Next(); |
185 } | 181 } |
186 | 182 |
187 int CodeBreakIterator::GetModeMask(BreakLocatorType type) { | 183 int CodeBreakIterator::GetModeMask() { |
188 int mask = 0; | 184 int mask = 0; |
189 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN); | 185 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN); |
190 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_CALL); | 186 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_CALL); |
191 if (isolate()->is_tail_call_elimination_enabled()) { | 187 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL); |
192 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL); | 188 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION); |
193 } | 189 mask |= RelocInfo::ModeMask(RelocInfo::DEBUGGER_STATEMENT); |
194 if (type == ALL_BREAK_LOCATIONS) { | |
195 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION); | |
196 mask |= RelocInfo::ModeMask(RelocInfo::DEBUGGER_STATEMENT); | |
197 } | |
198 return mask; | 190 return mask; |
199 } | 191 } |
200 | 192 |
201 void CodeBreakIterator::Next() { | 193 void CodeBreakIterator::Next() { |
202 DisallowHeapAllocation no_gc; | 194 DisallowHeapAllocation no_gc; |
203 DCHECK(!Done()); | 195 DCHECK(!Done()); |
204 | 196 |
205 // Iterate through reloc info stopping at each breakable code target. | 197 // Iterate through reloc info stopping at each breakable code target. |
206 bool first = break_index_ == -1; | 198 bool first = break_index_ == -1; |
207 | 199 |
(...skipping 29 matching lines...) Expand all Loading... |
237 return DEBUGGER_STATEMENT; | 229 return DEBUGGER_STATEMENT; |
238 } else if (RelocInfo::IsDebugBreakSlot(rmode())) { | 230 } else if (RelocInfo::IsDebugBreakSlot(rmode())) { |
239 return DEBUG_BREAK_SLOT; | 231 return DEBUG_BREAK_SLOT; |
240 } else { | 232 } else { |
241 return NOT_DEBUG_BREAK; | 233 return NOT_DEBUG_BREAK; |
242 } | 234 } |
243 } | 235 } |
244 | 236 |
245 void CodeBreakIterator::SkipToPosition(int position, | 237 void CodeBreakIterator::SkipToPosition(int position, |
246 BreakPositionAlignment alignment) { | 238 BreakPositionAlignment alignment) { |
247 CodeBreakIterator it(debug_info_, break_locator_type_); | 239 CodeBreakIterator it(debug_info_); |
248 SkipTo(it.BreakIndexFromPosition(position, alignment)); | 240 SkipTo(it.BreakIndexFromPosition(position, alignment)); |
249 } | 241 } |
250 | 242 |
251 void CodeBreakIterator::SetDebugBreak() { | 243 void CodeBreakIterator::SetDebugBreak() { |
252 DebugBreakType debug_break_type = GetDebugBreakType(); | 244 DebugBreakType debug_break_type = GetDebugBreakType(); |
253 if (debug_break_type == DEBUGGER_STATEMENT) return; | 245 if (debug_break_type == DEBUGGER_STATEMENT) return; |
254 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); | 246 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); |
255 Builtins* builtins = isolate()->builtins(); | 247 Builtins* builtins = isolate()->builtins(); |
256 Handle<Code> target = debug_break_type == DEBUG_BREAK_SLOT_AT_RETURN | 248 Handle<Code> target = debug_break_type == DEBUG_BREAK_SLOT_AT_RETURN |
257 ? builtins->Return_DebugBreak() | 249 ? builtins->Return_DebugBreak() |
(...skipping 14 matching lines...) Expand all Loading... |
272 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); | 264 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); |
273 return DebugCodegen::DebugBreakSlotIsPatched(rinfo()->pc()); | 265 return DebugCodegen::DebugBreakSlotIsPatched(rinfo()->pc()); |
274 } | 266 } |
275 | 267 |
276 BreakLocation CodeBreakIterator::GetBreakLocation() { | 268 BreakLocation CodeBreakIterator::GetBreakLocation() { |
277 Handle<AbstractCode> code(AbstractCode::cast(debug_info_->DebugCode())); | 269 Handle<AbstractCode> code(AbstractCode::cast(debug_info_->DebugCode())); |
278 return BreakLocation(code, GetDebugBreakType(), code_offset(), position_); | 270 return BreakLocation(code, GetDebugBreakType(), code_offset(), position_); |
279 } | 271 } |
280 | 272 |
281 BytecodeArrayBreakIterator::BytecodeArrayBreakIterator( | 273 BytecodeArrayBreakIterator::BytecodeArrayBreakIterator( |
282 Handle<DebugInfo> debug_info, BreakLocatorType type) | 274 Handle<DebugInfo> debug_info) |
283 : BreakIterator(debug_info, type), | 275 : BreakIterator(debug_info), |
284 source_position_iterator_( | 276 source_position_iterator_( |
285 debug_info->DebugBytecodeArray()->source_position_table()) { | 277 debug_info->DebugBytecodeArray()->source_position_table()) { |
286 // There is at least one break location. | 278 // There is at least one break location. |
287 DCHECK(!Done()); | 279 DCHECK(!Done()); |
288 Next(); | 280 Next(); |
289 } | 281 } |
290 | 282 |
291 void BytecodeArrayBreakIterator::Next() { | 283 void BytecodeArrayBreakIterator::Next() { |
292 DisallowHeapAllocation no_gc; | 284 DisallowHeapAllocation no_gc; |
293 DCHECK(!Done()); | 285 DCHECK(!Done()); |
294 bool first = break_index_ == -1; | 286 bool first = break_index_ == -1; |
295 while (!Done()) { | 287 while (!Done()) { |
296 if (!first) source_position_iterator_.Advance(); | 288 if (!first) source_position_iterator_.Advance(); |
297 first = false; | 289 first = false; |
298 if (Done()) return; | 290 if (Done()) return; |
299 position_ = source_position_iterator_.source_position().ScriptOffset(); | 291 position_ = source_position_iterator_.source_position().ScriptOffset(); |
300 if (source_position_iterator_.is_statement()) { | 292 if (source_position_iterator_.is_statement()) { |
301 statement_position_ = position_; | 293 statement_position_ = position_; |
302 } | 294 } |
303 DCHECK(position_ >= 0); | 295 DCHECK(position_ >= 0); |
304 DCHECK(statement_position_ >= 0); | 296 DCHECK(statement_position_ >= 0); |
305 | 297 |
306 DebugBreakType type = GetDebugBreakType(); | 298 DebugBreakType type = GetDebugBreakType(); |
307 if (type == NOT_DEBUG_BREAK) continue; | 299 if (type != NOT_DEBUG_BREAK) break; |
308 | |
309 if (break_locator_type_ == ALL_BREAK_LOCATIONS) break; | |
310 | |
311 DCHECK_EQ(CALLS_AND_RETURNS, break_locator_type_); | |
312 if (type == DEBUG_BREAK_SLOT_AT_CALL) break; | |
313 if (type == DEBUG_BREAK_SLOT_AT_RETURN) break; | |
314 } | 300 } |
315 break_index_++; | 301 break_index_++; |
316 } | 302 } |
317 | 303 |
318 DebugBreakType BytecodeArrayBreakIterator::GetDebugBreakType() { | 304 DebugBreakType BytecodeArrayBreakIterator::GetDebugBreakType() { |
319 BytecodeArray* bytecode_array = debug_info_->OriginalBytecodeArray(); | 305 BytecodeArray* bytecode_array = debug_info_->OriginalBytecodeArray(); |
320 interpreter::Bytecode bytecode = | 306 interpreter::Bytecode bytecode = |
321 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); | 307 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); |
322 | 308 |
323 if (bytecode == interpreter::Bytecode::kDebugger) { | 309 if (bytecode == interpreter::Bytecode::kDebugger) { |
324 return DEBUGGER_STATEMENT; | 310 return DEBUGGER_STATEMENT; |
325 } else if (bytecode == interpreter::Bytecode::kReturn) { | 311 } else if (bytecode == interpreter::Bytecode::kReturn) { |
326 return DEBUG_BREAK_SLOT_AT_RETURN; | 312 return DEBUG_BREAK_SLOT_AT_RETURN; |
327 } else if (bytecode == interpreter::Bytecode::kTailCall) { | 313 } else if (bytecode == interpreter::Bytecode::kTailCall) { |
328 return isolate()->is_tail_call_elimination_enabled() | 314 return isolate()->is_tail_call_elimination_enabled() |
329 ? DEBUG_BREAK_SLOT_AT_TAIL_CALL | 315 ? DEBUG_BREAK_SLOT_AT_TAIL_CALL |
330 : DEBUG_BREAK_SLOT_AT_CALL; | 316 : DEBUG_BREAK_SLOT_AT_CALL; |
331 } else if (interpreter::Bytecodes::IsCallOrConstruct(bytecode)) { | 317 } else if (interpreter::Bytecodes::IsCallOrConstruct(bytecode)) { |
332 return DEBUG_BREAK_SLOT_AT_CALL; | 318 return DEBUG_BREAK_SLOT_AT_CALL; |
333 } else if (source_position_iterator_.is_statement()) { | 319 } else if (source_position_iterator_.is_statement()) { |
334 return DEBUG_BREAK_SLOT; | 320 return DEBUG_BREAK_SLOT; |
335 } else { | 321 } else { |
336 return NOT_DEBUG_BREAK; | 322 return NOT_DEBUG_BREAK; |
337 } | 323 } |
338 } | 324 } |
339 | 325 |
340 void BytecodeArrayBreakIterator::SkipToPosition( | 326 void BytecodeArrayBreakIterator::SkipToPosition( |
341 int position, BreakPositionAlignment alignment) { | 327 int position, BreakPositionAlignment alignment) { |
342 BytecodeArrayBreakIterator it(debug_info_, break_locator_type_); | 328 BytecodeArrayBreakIterator it(debug_info_); |
343 SkipTo(it.BreakIndexFromPosition(position, alignment)); | 329 SkipTo(it.BreakIndexFromPosition(position, alignment)); |
344 } | 330 } |
345 | 331 |
346 void BytecodeArrayBreakIterator::SetDebugBreak() { | 332 void BytecodeArrayBreakIterator::SetDebugBreak() { |
347 DebugBreakType debug_break_type = GetDebugBreakType(); | 333 DebugBreakType debug_break_type = GetDebugBreakType(); |
348 if (debug_break_type == DEBUGGER_STATEMENT) return; | 334 if (debug_break_type == DEBUGGER_STATEMENT) return; |
349 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); | 335 DCHECK(debug_break_type >= DEBUG_BREAK_SLOT); |
350 BytecodeArray* bytecode_array = debug_info_->DebugBytecodeArray(); | 336 BytecodeArray* bytecode_array = debug_info_->DebugBytecodeArray(); |
351 interpreter::Bytecode bytecode = | 337 interpreter::Bytecode bytecode = |
352 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); | 338 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset())); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
392 } | 378 } |
393 | 379 |
394 | 380 |
395 // Threading support. | 381 // Threading support. |
396 void Debug::ThreadInit() { | 382 void Debug::ThreadInit() { |
397 thread_local_.break_count_ = 0; | 383 thread_local_.break_count_ = 0; |
398 thread_local_.break_id_ = 0; | 384 thread_local_.break_id_ = 0; |
399 thread_local_.break_frame_id_ = StackFrame::NO_ID; | 385 thread_local_.break_frame_id_ = StackFrame::NO_ID; |
400 thread_local_.last_step_action_ = StepNone; | 386 thread_local_.last_step_action_ = StepNone; |
401 thread_local_.last_statement_position_ = kNoSourcePosition; | 387 thread_local_.last_statement_position_ = kNoSourcePosition; |
402 thread_local_.last_fp_ = 0; | 388 thread_local_.last_frame_count_ = -1; |
403 thread_local_.target_fp_ = 0; | 389 thread_local_.target_frame_count_ = -1; |
404 thread_local_.return_value_ = Smi::kZero; | 390 thread_local_.return_value_ = Smi::kZero; |
405 thread_local_.async_task_count_ = 0; | 391 thread_local_.async_task_count_ = 0; |
406 clear_suspended_generator(); | 392 clear_suspended_generator(); |
407 thread_local_.restart_fp_ = nullptr; | 393 thread_local_.restart_fp_ = nullptr; |
408 base::NoBarrier_Store(&thread_local_.current_debug_scope_, | 394 base::NoBarrier_Store(&thread_local_.current_debug_scope_, |
409 static_cast<base::AtomicWord>(0)); | 395 static_cast<base::AtomicWord>(0)); |
410 UpdateHookOnFunctionCall(); | 396 UpdateHookOnFunctionCall(); |
411 } | 397 } |
412 | 398 |
413 | 399 |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
508 // Enter the debugger. | 494 // Enter the debugger. |
509 DebugScope debug_scope(this); | 495 DebugScope debug_scope(this); |
510 if (debug_scope.failed()) return; | 496 if (debug_scope.failed()) return; |
511 | 497 |
512 // Postpone interrupt during breakpoint processing. | 498 // Postpone interrupt during breakpoint processing. |
513 PostponeInterruptsScope postpone(isolate_); | 499 PostponeInterruptsScope postpone(isolate_); |
514 | 500 |
515 // Return if we fail to retrieve debug info. | 501 // Return if we fail to retrieve debug info. |
516 Handle<JSFunction> function(frame->function()); | 502 Handle<JSFunction> function(frame->function()); |
517 Handle<SharedFunctionInfo> shared(function->shared()); | 503 Handle<SharedFunctionInfo> shared(function->shared()); |
518 if (!EnsureDebugInfo(shared, function)) return; | 504 if (!EnsureDebugInfo(shared)) return; |
519 Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_); | 505 Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_); |
520 | 506 |
521 // Find the break location where execution has stopped. | 507 // Find the break location where execution has stopped. |
522 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); | 508 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); |
523 | 509 |
524 // Find actual break points, if any, and trigger debug break event. | 510 // Find actual break points, if any, and trigger debug break event. |
525 MaybeHandle<FixedArray> break_points_hit = | 511 MaybeHandle<FixedArray> break_points_hit = |
526 CheckBreakPoints(debug_info, &location); | 512 CheckBreakPoints(debug_info, &location); |
527 if (!break_points_hit.is_null()) { | 513 if (!break_points_hit.is_null()) { |
528 // Clear all current stepping setup. | 514 // Clear all current stepping setup. |
529 ClearStepping(); | 515 ClearStepping(); |
530 // Notify the debug event listeners. | 516 // Notify the debug event listeners. |
531 Handle<JSArray> jsarr = isolate_->factory()->NewJSArrayWithElements( | 517 Handle<JSArray> jsarr = isolate_->factory()->NewJSArrayWithElements( |
532 break_points_hit.ToHandleChecked()); | 518 break_points_hit.ToHandleChecked()); |
533 OnDebugBreak(jsarr); | 519 OnDebugBreak(jsarr); |
534 return; | 520 return; |
535 } | 521 } |
536 | 522 |
537 // No break point. Check for stepping. | 523 // No break point. Check for stepping. |
538 StepAction step_action = last_step_action(); | 524 StepAction step_action = last_step_action(); |
539 Address current_fp = frame->UnpaddedFP(); | 525 int current_frame_count = CurrentFrameCount(); |
540 Address target_fp = thread_local_.target_fp_; | 526 int target_frame_count = thread_local_.target_frame_count_; |
541 Address last_fp = thread_local_.last_fp_; | 527 int last_frame_count = thread_local_.last_frame_count_; |
542 | 528 |
543 bool step_break = false; | 529 bool step_break = false; |
544 switch (step_action) { | 530 switch (step_action) { |
545 case StepNone: | 531 case StepNone: |
546 return; | 532 return; |
547 case StepOut: | 533 case StepOut: |
548 // Step out has not reached the target frame yet. | 534 // Step out should not break in a deeper frame than target frame. |
549 if (current_fp < target_fp) return; | 535 if (current_frame_count > target_frame_count) return; |
550 step_break = true; | 536 step_break = true; |
551 break; | 537 break; |
552 case StepNext: | 538 case StepNext: |
553 // Step next should not break in a deeper frame. | 539 // Step next should not break in a deeper frame than target frame. |
554 if (current_fp < target_fp) return; | 540 if (current_frame_count > target_frame_count) return; |
555 // For step-next, a tail call is like a return and should break. | 541 // For step-next, a tail call is like a return and should break. |
556 step_break = location.IsTailCall(); | 542 step_break = location.IsTailCall(); |
557 // Fall through. | 543 // Fall through. |
558 case StepIn: { | 544 case StepIn: { |
559 FrameSummary summary = FrameSummary::GetTop(frame); | 545 FrameSummary summary = FrameSummary::GetTop(frame); |
560 step_break = step_break || location.IsReturn() || current_fp != last_fp || | 546 step_break = step_break || location.IsReturn() || |
| 547 current_frame_count != last_frame_count || |
561 thread_local_.last_statement_position_ != | 548 thread_local_.last_statement_position_ != |
562 summary.SourceStatementPosition(); | 549 summary.SourceStatementPosition(); |
563 break; | 550 break; |
564 } | 551 } |
565 } | 552 } |
566 | 553 |
567 // Clear all current stepping setup. | 554 // Clear all current stepping setup. |
568 ClearStepping(); | 555 ClearStepping(); |
569 | 556 |
570 if (step_break) { | 557 if (step_break) { |
(...skipping 17 matching lines...) Expand all Loading... |
588 if (has_break_points) *has_break_points = has_break_points_to_check; | 575 if (has_break_points) *has_break_points = has_break_points_to_check; |
589 if (!has_break_points_to_check) return {}; | 576 if (!has_break_points_to_check) return {}; |
590 | 577 |
591 Handle<Object> break_point_objects = | 578 Handle<Object> break_point_objects = |
592 debug_info->GetBreakPointObjects(location->position()); | 579 debug_info->GetBreakPointObjects(location->position()); |
593 return Debug::GetHitBreakPointObjects(break_point_objects); | 580 return Debug::GetHitBreakPointObjects(break_point_objects); |
594 } | 581 } |
595 | 582 |
596 | 583 |
597 bool Debug::IsMutedAtCurrentLocation(JavaScriptFrame* frame) { | 584 bool Debug::IsMutedAtCurrentLocation(JavaScriptFrame* frame) { |
| 585 HandleScope scope(isolate_); |
598 // A break location is considered muted if break locations on the current | 586 // A break location is considered muted if break locations on the current |
599 // statement have at least one break point, and all of these break points | 587 // statement have at least one break point, and all of these break points |
600 // evaluate to false. Aside from not triggering a debug break event at the | 588 // evaluate to false. Aside from not triggering a debug break event at the |
601 // break location, we also do not trigger one for debugger statements, nor | 589 // break location, we also do not trigger one for debugger statements, nor |
602 // an exception event on exception at this location. | 590 // an exception event on exception at this location. |
603 Object* fun = frame->function(); | 591 FrameSummary summary = FrameSummary::GetTop(frame); |
604 if (!fun->IsJSFunction()) return false; | 592 DCHECK(!summary.IsWasm()); |
605 JSFunction* function = JSFunction::cast(fun); | 593 Handle<JSFunction> function = summary.AsJavaScript().function(); |
606 if (!function->shared()->HasDebugInfo()) return false; | 594 if (!function->shared()->HasDebugInfo()) return false; |
607 HandleScope scope(isolate_); | |
608 Handle<DebugInfo> debug_info(function->shared()->GetDebugInfo()); | 595 Handle<DebugInfo> debug_info(function->shared()->GetDebugInfo()); |
609 // Enter the debugger. | 596 // Enter the debugger. |
610 DebugScope debug_scope(this); | 597 DebugScope debug_scope(this); |
611 if (debug_scope.failed()) return false; | 598 if (debug_scope.failed()) return false; |
612 List<BreakLocation> break_locations; | 599 List<BreakLocation> break_locations; |
613 BreakLocation::AllAtCurrentStatement(debug_info, frame, &break_locations); | 600 BreakLocation::AllAtCurrentStatement(debug_info, frame, &break_locations); |
614 bool has_break_points_at_all = false; | 601 bool has_break_points_at_all = false; |
615 for (int i = 0; i < break_locations.length(); i++) { | 602 for (int i = 0; i < break_locations.length(); i++) { |
616 bool has_break_points; | 603 bool has_break_points; |
617 MaybeHandle<FixedArray> check_result = | 604 MaybeHandle<FixedArray> check_result = |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
663 } | 650 } |
664 | 651 |
665 | 652 |
666 bool Debug::SetBreakPoint(Handle<JSFunction> function, | 653 bool Debug::SetBreakPoint(Handle<JSFunction> function, |
667 Handle<Object> break_point_object, | 654 Handle<Object> break_point_object, |
668 int* source_position) { | 655 int* source_position) { |
669 HandleScope scope(isolate_); | 656 HandleScope scope(isolate_); |
670 | 657 |
671 // Make sure the function is compiled and has set up the debug info. | 658 // Make sure the function is compiled and has set up the debug info. |
672 Handle<SharedFunctionInfo> shared(function->shared()); | 659 Handle<SharedFunctionInfo> shared(function->shared()); |
673 if (!EnsureDebugInfo(shared, function)) { | 660 if (!EnsureDebugInfo(shared)) return true; |
674 // Return if retrieving debug info failed. | |
675 return true; | |
676 } | |
677 | |
678 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 661 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
679 // Source positions starts with zero. | 662 // Source positions starts with zero. |
680 DCHECK(*source_position >= 0); | 663 DCHECK(*source_position >= 0); |
681 | 664 |
682 // Find the break point and change it. | 665 // Find the break point and change it. |
683 *source_position = | 666 *source_position = |
684 FindBreakablePosition(debug_info, *source_position, STATEMENT_ALIGNED); | 667 FindBreakablePosition(debug_info, *source_position, STATEMENT_ALIGNED); |
685 DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object); | 668 DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object); |
686 // At least one active break point now. | 669 // At least one active break point now. |
687 DCHECK(debug_info->GetBreakPointCount() > 0); | 670 DCHECK(debug_info->GetBreakPointCount() > 0); |
(...skipping 19 matching lines...) Expand all Loading... |
707 | 690 |
708 HandleScope scope(isolate_); | 691 HandleScope scope(isolate_); |
709 | 692 |
710 // Obtain shared function info for the function. | 693 // Obtain shared function info for the function. |
711 Handle<Object> result = | 694 Handle<Object> result = |
712 FindSharedFunctionInfoInScript(script, *source_position); | 695 FindSharedFunctionInfoInScript(script, *source_position); |
713 if (result->IsUndefined(isolate_)) return false; | 696 if (result->IsUndefined(isolate_)) return false; |
714 | 697 |
715 // Make sure the function has set up the debug info. | 698 // Make sure the function has set up the debug info. |
716 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(result); | 699 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(result); |
717 if (!EnsureDebugInfo(shared, Handle<JSFunction>::null())) { | 700 if (!EnsureDebugInfo(shared)) return false; |
718 // Return if retrieving debug info failed. | |
719 return false; | |
720 } | |
721 | 701 |
722 // Find position within function. The script position might be before the | 702 // Find position within function. The script position might be before the |
723 // source position of the first function. | 703 // source position of the first function. |
724 if (shared->start_position() > *source_position) { | 704 if (shared->start_position() > *source_position) { |
725 *source_position = shared->start_position(); | 705 *source_position = shared->start_position(); |
726 } | 706 } |
727 | 707 |
728 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 708 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
729 | 709 |
730 // Find the break point and change it. | 710 // Find the break point and change it. |
731 *source_position = | 711 *source_position = |
732 FindBreakablePosition(debug_info, *source_position, alignment); | 712 FindBreakablePosition(debug_info, *source_position, alignment); |
733 DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object); | 713 DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object); |
734 // At least one active break point now. | 714 // At least one active break point now. |
735 DCHECK(debug_info->GetBreakPointCount() > 0); | 715 DCHECK(debug_info->GetBreakPointCount() > 0); |
736 | 716 |
737 ClearBreakPoints(debug_info); | 717 ClearBreakPoints(debug_info); |
738 ApplyBreakPoints(debug_info); | 718 ApplyBreakPoints(debug_info); |
739 | 719 |
740 feature_tracker()->Track(DebugFeatureTracker::kBreakPoint); | 720 feature_tracker()->Track(DebugFeatureTracker::kBreakPoint); |
741 return true; | 721 return true; |
742 } | 722 } |
743 | 723 |
744 int Debug::FindBreakablePosition(Handle<DebugInfo> debug_info, | 724 int Debug::FindBreakablePosition(Handle<DebugInfo> debug_info, |
745 int source_position, | 725 int source_position, |
746 BreakPositionAlignment alignment) { | 726 BreakPositionAlignment alignment) { |
747 int statement_position; | 727 int statement_position; |
748 int position; | 728 int position; |
749 if (debug_info->HasDebugCode()) { | 729 if (debug_info->HasDebugCode()) { |
750 CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 730 CodeBreakIterator it(debug_info); |
751 it.SkipToPosition(source_position, alignment); | 731 it.SkipToPosition(source_position, alignment); |
752 statement_position = it.statement_position(); | 732 statement_position = it.statement_position(); |
753 position = it.position(); | 733 position = it.position(); |
754 } else { | 734 } else { |
755 DCHECK(debug_info->HasDebugBytecodeArray()); | 735 DCHECK(debug_info->HasDebugBytecodeArray()); |
756 BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 736 BytecodeArrayBreakIterator it(debug_info); |
757 it.SkipToPosition(source_position, alignment); | 737 it.SkipToPosition(source_position, alignment); |
758 statement_position = it.statement_position(); | 738 statement_position = it.statement_position(); |
759 position = it.position(); | 739 position = it.position(); |
760 } | 740 } |
761 return alignment == STATEMENT_ALIGNED ? statement_position : position; | 741 return alignment == STATEMENT_ALIGNED ? statement_position : position; |
762 } | 742 } |
763 | 743 |
764 void Debug::ApplyBreakPoints(Handle<DebugInfo> debug_info) { | 744 void Debug::ApplyBreakPoints(Handle<DebugInfo> debug_info) { |
765 DisallowHeapAllocation no_gc; | 745 DisallowHeapAllocation no_gc; |
766 if (debug_info->break_points()->IsUndefined(isolate_)) return; | 746 if (debug_info->break_points()->IsUndefined(isolate_)) return; |
767 FixedArray* break_points = debug_info->break_points(); | 747 FixedArray* break_points = debug_info->break_points(); |
768 for (int i = 0; i < break_points->length(); i++) { | 748 for (int i = 0; i < break_points->length(); i++) { |
769 if (break_points->get(i)->IsUndefined(isolate_)) continue; | 749 if (break_points->get(i)->IsUndefined(isolate_)) continue; |
770 BreakPointInfo* info = BreakPointInfo::cast(break_points->get(i)); | 750 BreakPointInfo* info = BreakPointInfo::cast(break_points->get(i)); |
771 if (info->GetBreakPointCount() == 0) continue; | 751 if (info->GetBreakPointCount() == 0) continue; |
772 if (debug_info->HasDebugCode()) { | 752 if (debug_info->HasDebugCode()) { |
773 CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 753 CodeBreakIterator it(debug_info); |
774 it.SkipToPosition(info->source_position(), BREAK_POSITION_ALIGNED); | 754 it.SkipToPosition(info->source_position(), BREAK_POSITION_ALIGNED); |
775 it.SetDebugBreak(); | 755 it.SetDebugBreak(); |
776 } | 756 } |
777 if (debug_info->HasDebugBytecodeArray()) { | 757 if (debug_info->HasDebugBytecodeArray()) { |
778 BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 758 BytecodeArrayBreakIterator it(debug_info); |
779 it.SkipToPosition(info->source_position(), BREAK_POSITION_ALIGNED); | 759 it.SkipToPosition(info->source_position(), BREAK_POSITION_ALIGNED); |
780 it.SetDebugBreak(); | 760 it.SetDebugBreak(); |
781 } | 761 } |
782 } | 762 } |
783 } | 763 } |
784 | 764 |
785 void Debug::ClearBreakPoints(Handle<DebugInfo> debug_info) { | 765 void Debug::ClearBreakPoints(Handle<DebugInfo> debug_info) { |
786 DisallowHeapAllocation no_gc; | 766 DisallowHeapAllocation no_gc; |
787 if (debug_info->HasDebugCode()) { | 767 if (debug_info->HasDebugCode()) { |
788 for (CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); !it.Done(); | 768 for (CodeBreakIterator it(debug_info); !it.Done(); it.Next()) { |
789 it.Next()) { | |
790 it.ClearDebugBreak(); | 769 it.ClearDebugBreak(); |
791 } | 770 } |
792 } | 771 } |
793 if (debug_info->HasDebugBytecodeArray()) { | 772 if (debug_info->HasDebugBytecodeArray()) { |
794 for (BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 773 for (BytecodeArrayBreakIterator it(debug_info); !it.Done(); it.Next()) { |
795 !it.Done(); it.Next()) { | |
796 it.ClearDebugBreak(); | 774 it.ClearDebugBreak(); |
797 } | 775 } |
798 } | 776 } |
799 } | 777 } |
800 | 778 |
801 void Debug::ClearBreakPoint(Handle<Object> break_point_object) { | 779 void Debug::ClearBreakPoint(Handle<Object> break_point_object) { |
802 HandleScope scope(isolate_); | 780 HandleScope scope(isolate_); |
803 | 781 |
804 for (DebugInfoListNode* node = debug_info_list_; node != NULL; | 782 for (DebugInfoListNode* node = debug_info_list_; node != NULL; |
805 node = node->next()) { | 783 node = node->next()) { |
(...skipping 20 matching lines...) Expand all Loading... |
826 for (DebugInfoListNode* node = debug_info_list_; node != NULL; | 804 for (DebugInfoListNode* node = debug_info_list_; node != NULL; |
827 node = node->next()) { | 805 node = node->next()) { |
828 ClearBreakPoints(node->debug_info()); | 806 ClearBreakPoints(node->debug_info()); |
829 } | 807 } |
830 // Remove all debug info. | 808 // Remove all debug info. |
831 while (debug_info_list_ != NULL) { | 809 while (debug_info_list_ != NULL) { |
832 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info()); | 810 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info()); |
833 } | 811 } |
834 } | 812 } |
835 | 813 |
836 void Debug::FloodWithOneShot(Handle<JSFunction> function, | 814 void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) { |
837 BreakLocatorType type) { | 815 if (!shared->IsSubjectToDebugging() || IsBlackboxed(shared)) return; |
838 // Debug utility functions are not subject to debugging. | |
839 if (function->native_context() == *debug_context()) return; | |
840 | |
841 if (!function->shared()->IsSubjectToDebugging() || | |
842 IsBlackboxed(function->shared())) { | |
843 // Builtin functions are not subject to stepping, but need to be | |
844 // deoptimized, because optimized code does not check for debug | |
845 // step in at call sites. | |
846 Deoptimizer::DeoptimizeFunction(*function); | |
847 return; | |
848 } | |
849 // Make sure the function is compiled and has set up the debug info. | 816 // Make sure the function is compiled and has set up the debug info. |
850 Handle<SharedFunctionInfo> shared(function->shared()); | 817 if (!EnsureDebugInfo(shared)) return; |
851 if (!EnsureDebugInfo(shared, function)) { | 818 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
852 // Return if we failed to retrieve the debug info. | |
853 return; | |
854 } | |
855 | |
856 // Flood the function with break points. | 819 // Flood the function with break points. |
857 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | |
858 if (debug_info->HasDebugCode()) { | 820 if (debug_info->HasDebugCode()) { |
859 for (CodeBreakIterator it(debug_info, type); !it.Done(); it.Next()) { | 821 for (CodeBreakIterator it(debug_info); !it.Done(); it.Next()) { |
860 it.SetDebugBreak(); | 822 it.SetDebugBreak(); |
861 } | 823 } |
862 } | 824 } |
863 if (debug_info->HasDebugBytecodeArray()) { | 825 if (debug_info->HasDebugBytecodeArray()) { |
864 for (BytecodeArrayBreakIterator it(debug_info, type); !it.Done(); | 826 for (BytecodeArrayBreakIterator it(debug_info); !it.Done(); it.Next()) { |
865 it.Next()) { | |
866 it.SetDebugBreak(); | 827 it.SetDebugBreak(); |
867 } | 828 } |
868 } | 829 } |
869 } | 830 } |
870 | 831 |
871 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) { | 832 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) { |
872 if (type == BreakUncaughtException) { | 833 if (type == BreakUncaughtException) { |
873 break_on_uncaught_exception_ = enable; | 834 break_on_uncaught_exception_ = enable; |
874 } else { | 835 } else { |
875 break_on_exception_ = enable; | 836 break_on_exception_ = enable; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
909 if (break_points_hit_count == 0) return {}; | 870 if (break_points_hit_count == 0) return {}; |
910 break_points_hit->Shrink(break_points_hit_count); | 871 break_points_hit->Shrink(break_points_hit_count); |
911 return break_points_hit; | 872 return break_points_hit; |
912 } | 873 } |
913 | 874 |
914 void Debug::PrepareStepIn(Handle<JSFunction> function) { | 875 void Debug::PrepareStepIn(Handle<JSFunction> function) { |
915 CHECK(last_step_action() >= StepIn); | 876 CHECK(last_step_action() >= StepIn); |
916 if (ignore_events()) return; | 877 if (ignore_events()) return; |
917 if (in_debug_scope()) return; | 878 if (in_debug_scope()) return; |
918 if (break_disabled()) return; | 879 if (break_disabled()) return; |
919 FloodWithOneShot(function); | 880 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared(), isolate_)); |
920 } | 881 } |
921 | 882 |
922 void Debug::PrepareStepInSuspendedGenerator() { | 883 void Debug::PrepareStepInSuspendedGenerator() { |
923 CHECK(has_suspended_generator()); | 884 CHECK(has_suspended_generator()); |
924 if (ignore_events()) return; | 885 if (ignore_events()) return; |
925 if (in_debug_scope()) return; | 886 if (in_debug_scope()) return; |
926 if (break_disabled()) return; | 887 if (break_disabled()) return; |
927 thread_local_.last_step_action_ = StepIn; | 888 thread_local_.last_step_action_ = StepIn; |
928 UpdateHookOnFunctionCall(); | 889 UpdateHookOnFunctionCall(); |
929 Handle<JSFunction> function( | 890 Handle<JSFunction> function( |
930 JSGeneratorObject::cast(thread_local_.suspended_generator_)->function()); | 891 JSGeneratorObject::cast(thread_local_.suspended_generator_)->function()); |
931 FloodWithOneShot(function); | 892 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared(), isolate_)); |
932 clear_suspended_generator(); | 893 clear_suspended_generator(); |
933 } | 894 } |
934 | 895 |
935 void Debug::PrepareStepOnThrow() { | 896 void Debug::PrepareStepOnThrow() { |
936 if (last_step_action() == StepNone) return; | 897 if (last_step_action() == StepNone) return; |
937 if (ignore_events()) return; | 898 if (ignore_events()) return; |
938 if (in_debug_scope()) return; | 899 if (in_debug_scope()) return; |
939 if (break_disabled()) return; | 900 if (break_disabled()) return; |
940 | 901 |
941 ClearOneShot(); | 902 ClearOneShot(); |
942 | 903 |
| 904 int current_frame_count = CurrentFrameCount(); |
| 905 |
943 // Iterate through the JavaScript stack looking for handlers. | 906 // Iterate through the JavaScript stack looking for handlers. |
944 JavaScriptFrameIterator it(isolate_); | 907 JavaScriptFrameIterator it(isolate_); |
945 while (!it.done()) { | 908 while (!it.done()) { |
946 JavaScriptFrame* frame = it.frame(); | 909 JavaScriptFrame* frame = it.frame(); |
947 if (frame->LookupExceptionHandlerInTable(nullptr, nullptr) > 0) break; | 910 if (frame->LookupExceptionHandlerInTable(nullptr, nullptr) > 0) break; |
| 911 List<SharedFunctionInfo*> infos; |
| 912 frame->GetFunctions(&infos); |
| 913 current_frame_count -= infos.length(); |
948 it.Advance(); | 914 it.Advance(); |
949 } | 915 } |
950 | 916 |
951 if (last_step_action() == StepNext || last_step_action() == StepOut) { | 917 // No handler found. Nothing to instrument. |
952 while (!it.done()) { | 918 if (it.done()) return; |
953 Address current_fp = it.frame()->UnpaddedFP(); | 919 |
954 if (current_fp >= thread_local_.target_fp_) break; | 920 bool found_handler = false; |
955 it.Advance(); | 921 // Iterate frames, including inlined frames. First, find the handler frame. |
| 922 // Then skip to the frame we want to break in, then instrument for stepping. |
| 923 for (; !it.done(); it.Advance()) { |
| 924 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame()); |
| 925 if (last_step_action() == StepIn) { |
| 926 // Deoptimize frame to ensure calls are checked for step-in. |
| 927 Deoptimizer::DeoptimizeFunction(frame->function()); |
| 928 } |
| 929 List<FrameSummary> summaries; |
| 930 frame->Summarize(&summaries); |
| 931 for (int i = summaries.length() - 1; i >= 0; i--, current_frame_count--) { |
| 932 if (!found_handler) { |
| 933 // We have yet to find the handler. If the frame inlines multiple |
| 934 // functions, we have to check each one for the handler. |
| 935 // If it only contains one function, we already found the handler. |
| 936 if (summaries.length() > 1) { |
| 937 Handle<AbstractCode> code = |
| 938 summaries[i].AsJavaScript().abstract_code(); |
| 939 CHECK_EQ(AbstractCode::INTERPRETED_FUNCTION, code->kind()); |
| 940 BytecodeArray* bytecode = code->GetBytecodeArray(); |
| 941 HandlerTable* table = HandlerTable::cast(bytecode->handler_table()); |
| 942 int code_offset = summaries[i].code_offset(); |
| 943 HandlerTable::CatchPrediction prediction; |
| 944 int index = table->LookupRange(code_offset, nullptr, &prediction); |
| 945 if (index > 0) found_handler = true; |
| 946 } else { |
| 947 found_handler = true; |
| 948 } |
| 949 } |
| 950 |
| 951 if (found_handler) { |
| 952 // We found the handler. If we are stepping next or out, we need to |
| 953 // iterate until we found the suitable target frame to break in. |
| 954 if ((last_step_action() == StepNext || last_step_action() == StepOut) && |
| 955 current_frame_count > thread_local_.target_frame_count_) { |
| 956 continue; |
| 957 } |
| 958 Handle<SharedFunctionInfo> info( |
| 959 summaries[i].AsJavaScript().function()->shared()); |
| 960 if (!info->IsSubjectToDebugging() || IsBlackboxed(info)) continue; |
| 961 FloodWithOneShot(info); |
| 962 return; |
| 963 } |
956 } | 964 } |
957 } | 965 } |
958 | |
959 // Find the closest Javascript frame we can flood with one-shots. | |
960 while (!it.done() && | |
961 (!it.frame()->function()->shared()->IsSubjectToDebugging() || | |
962 IsBlackboxed(it.frame()->function()->shared()))) { | |
963 it.Advance(); | |
964 } | |
965 | |
966 if (it.done()) return; // No suitable Javascript catch handler. | |
967 | |
968 FloodWithOneShot(Handle<JSFunction>(it.frame()->function())); | |
969 } | 966 } |
970 | 967 |
971 | 968 |
972 void Debug::PrepareStep(StepAction step_action) { | 969 void Debug::PrepareStep(StepAction step_action) { |
973 HandleScope scope(isolate_); | 970 HandleScope scope(isolate_); |
974 | 971 |
975 DCHECK(in_debug_scope()); | 972 DCHECK(in_debug_scope()); |
976 | 973 |
977 // Get the frame where the execution has stopped and skip the debug frame if | 974 // Get the frame where the execution has stopped and skip the debug frame if |
978 // any. The debug frame will only be present if execution was stopped due to | 975 // any. The debug frame will only be present if execution was stopped due to |
979 // hitting a break point. In other situations (e.g. unhandled exception) the | 976 // hitting a break point. In other situations (e.g. unhandled exception) the |
980 // debug frame is not present. | 977 // debug frame is not present. |
981 StackFrame::Id frame_id = break_frame_id(); | 978 StackFrame::Id frame_id = break_frame_id(); |
982 // If there is no JavaScript stack don't do anything. | 979 // If there is no JavaScript stack don't do anything. |
983 if (frame_id == StackFrame::NO_ID) return; | 980 if (frame_id == StackFrame::NO_ID) return; |
984 | 981 |
985 StackTraceFrameIterator frames_it(isolate_, frame_id); | |
986 StandardFrame* frame = frames_it.frame(); | |
987 | |
988 feature_tracker()->Track(DebugFeatureTracker::kStepping); | 982 feature_tracker()->Track(DebugFeatureTracker::kStepping); |
989 | 983 |
990 thread_local_.last_step_action_ = step_action; | 984 thread_local_.last_step_action_ = step_action; |
991 UpdateHookOnFunctionCall(); | 985 UpdateHookOnFunctionCall(); |
992 | 986 |
| 987 StackTraceFrameIterator frames_it(isolate_, frame_id); |
| 988 StandardFrame* frame = frames_it.frame(); |
| 989 |
993 // Handle stepping in wasm functions via the wasm interpreter. | 990 // Handle stepping in wasm functions via the wasm interpreter. |
994 if (frame->is_wasm()) { | 991 if (frame->is_wasm()) { |
995 // If the top frame is compiled, we cannot step. | 992 // If the top frame is compiled, we cannot step. |
996 if (frame->is_wasm_compiled()) return; | 993 if (frame->is_wasm_compiled()) return; |
997 WasmInterpreterEntryFrame* wasm_frame = | 994 WasmInterpreterEntryFrame* wasm_frame = |
998 WasmInterpreterEntryFrame::cast(frame); | 995 WasmInterpreterEntryFrame::cast(frame); |
999 wasm_frame->wasm_instance()->debug_info()->PrepareStep(step_action); | 996 wasm_frame->wasm_instance()->debug_info()->PrepareStep(step_action); |
1000 return; | 997 return; |
1001 } | 998 } |
1002 | 999 |
1003 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); | 1000 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); |
1004 | 1001 DCHECK(js_frame->function()->IsJSFunction()); |
1005 // If the function on the top frame is unresolved perform step out. This will | |
1006 // be the case when calling unknown function and having the debugger stopped | |
1007 // in an unhandled exception. | |
1008 if (!js_frame->function()->IsJSFunction()) { | |
1009 // Step out: Find the calling JavaScript frame and flood it with | |
1010 // breakpoints. | |
1011 frames_it.Advance(); | |
1012 // Fill the function to return to with one-shot break points. | |
1013 JSFunction* function = JavaScriptFrame::cast(frames_it.frame())->function(); | |
1014 FloodWithOneShot(handle(function, isolate_)); | |
1015 return; | |
1016 } | |
1017 | 1002 |
1018 // Get the debug info (create it if it does not exist). | 1003 // Get the debug info (create it if it does not exist). |
1019 auto summary = FrameSummary::GetTop(frame).AsJavaScript(); | 1004 auto summary = FrameSummary::GetTop(frame).AsJavaScript(); |
1020 Handle<JSFunction> function(summary.function()); | 1005 Handle<JSFunction> function(summary.function()); |
1021 Handle<SharedFunctionInfo> shared(function->shared()); | 1006 Handle<SharedFunctionInfo> shared(function->shared()); |
1022 if (!EnsureDebugInfo(shared, function)) { | 1007 if (!EnsureDebugInfo(shared)) return; |
1023 // Return if ensuring debug info failed. | 1008 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
1024 return; | |
1025 } | |
1026 | 1009 |
1027 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | |
1028 BreakLocation location = BreakLocation::FromFrame(debug_info, js_frame); | 1010 BreakLocation location = BreakLocation::FromFrame(debug_info, js_frame); |
1029 | 1011 |
1030 // Any step at a return is a step-out. | 1012 // Any step at a return is a step-out. |
1031 if (location.IsReturn()) step_action = StepOut; | 1013 if (location.IsReturn()) step_action = StepOut; |
1032 // A step-next at a tail call is a step-out. | 1014 // A step-next at a tail call is a step-out. |
1033 if (location.IsTailCall() && step_action == StepNext) step_action = StepOut; | 1015 if (location.IsTailCall() && step_action == StepNext) step_action = StepOut; |
1034 // A step-next in blackboxed function is a step-out. | 1016 // A step-next in blackboxed function is a step-out. |
1035 if (step_action == StepNext && IsBlackboxed(shared)) step_action = StepOut; | 1017 if (step_action == StepNext && IsBlackboxed(shared)) step_action = StepOut; |
1036 | 1018 |
1037 thread_local_.last_statement_position_ = | 1019 thread_local_.last_statement_position_ = |
1038 summary.abstract_code()->SourceStatementPosition(summary.code_offset()); | 1020 summary.abstract_code()->SourceStatementPosition(summary.code_offset()); |
1039 thread_local_.last_fp_ = frame->UnpaddedFP(); | 1021 int current_frame_count = CurrentFrameCount(); |
| 1022 thread_local_.last_frame_count_ = current_frame_count; |
1040 // No longer perform the current async step. | 1023 // No longer perform the current async step. |
1041 clear_suspended_generator(); | 1024 clear_suspended_generator(); |
1042 | 1025 |
1043 switch (step_action) { | 1026 switch (step_action) { |
1044 case StepNone: | 1027 case StepNone: |
1045 UNREACHABLE(); | 1028 UNREACHABLE(); |
1046 break; | 1029 break; |
1047 case StepOut: | 1030 case StepOut: { |
1048 // Advance to caller frame. | |
1049 frames_it.Advance(); | |
1050 // Find top-most function which is subject to debugging. | |
1051 while (!frames_it.done()) { | |
1052 StandardFrame* caller_frame = frames_it.frame(); | |
1053 if (caller_frame->is_wasm()) { | |
1054 // TODO(clemensh): Implement stepping out from JS to WASM. | |
1055 break; | |
1056 } | |
1057 Handle<JSFunction> js_caller_function( | |
1058 JavaScriptFrame::cast(caller_frame)->function(), isolate_); | |
1059 if (js_caller_function->shared()->IsSubjectToDebugging() && | |
1060 !IsBlackboxed(js_caller_function->shared())) { | |
1061 // Fill the caller function to return to with one-shot break points. | |
1062 FloodWithOneShot(js_caller_function); | |
1063 thread_local_.target_fp_ = frames_it.frame()->UnpaddedFP(); | |
1064 break; | |
1065 } | |
1066 // Builtin functions are not subject to stepping, but need to be | |
1067 // deoptimized to include checks for step-in at call sites. | |
1068 Deoptimizer::DeoptimizeFunction(*js_caller_function); | |
1069 frames_it.Advance(); | |
1070 } | |
1071 // Clear last position info. For stepping out it does not matter. | 1031 // Clear last position info. For stepping out it does not matter. |
1072 thread_local_.last_statement_position_ = kNoSourcePosition; | 1032 thread_local_.last_statement_position_ = kNoSourcePosition; |
1073 thread_local_.last_fp_ = 0; | 1033 thread_local_.last_frame_count_ = -1; |
| 1034 // Skip the current frame, find the first frame we want to step out to |
| 1035 // and deoptimize every frame along the way. |
| 1036 bool in_current_frame = true; |
| 1037 for (; !frames_it.done(); frames_it.Advance()) { |
| 1038 // TODO(clemensh): Implement stepping out from JS to WASM. |
| 1039 if (frames_it.frame()->is_wasm()) continue; |
| 1040 JavaScriptFrame* frame = JavaScriptFrame::cast(frames_it.frame()); |
| 1041 if (last_step_action() == StepIn) { |
| 1042 // Deoptimize frame to ensure calls are checked for step-in. |
| 1043 Deoptimizer::DeoptimizeFunction(frame->function()); |
| 1044 } |
| 1045 HandleScope scope(isolate_); |
| 1046 List<Handle<SharedFunctionInfo>> infos; |
| 1047 frame->GetFunctions(&infos); |
| 1048 for (; !infos.is_empty(); current_frame_count--) { |
| 1049 Handle<SharedFunctionInfo> info = infos.RemoveLast(); |
| 1050 if (in_current_frame) { |
| 1051 // We want to skip out, so skip the current frame. |
| 1052 in_current_frame = false; |
| 1053 continue; |
| 1054 } |
| 1055 if (!info->IsSubjectToDebugging() || IsBlackboxed(info)) continue; |
| 1056 FloodWithOneShot(info); |
| 1057 thread_local_.target_frame_count_ = current_frame_count; |
| 1058 return; |
| 1059 } |
| 1060 } |
1074 break; | 1061 break; |
| 1062 } |
1075 case StepNext: | 1063 case StepNext: |
1076 thread_local_.target_fp_ = frame->UnpaddedFP(); | 1064 thread_local_.target_frame_count_ = current_frame_count; |
1077 FloodWithOneShot(function); | 1065 // Fall through. |
1078 break; | |
1079 case StepIn: | 1066 case StepIn: |
1080 // TODO(clemensh): Implement stepping from JS into WASM. | 1067 // TODO(clemensh): Implement stepping from JS into WASM. |
1081 FloodWithOneShot(function); | 1068 FloodWithOneShot(shared); |
1082 break; | 1069 break; |
1083 } | 1070 } |
1084 } | 1071 } |
1085 | 1072 |
1086 // Simple function for returning the source positions for active break points. | 1073 // Simple function for returning the source positions for active break points. |
1087 Handle<Object> Debug::GetSourceBreakLocations( | 1074 Handle<Object> Debug::GetSourceBreakLocations( |
1088 Handle<SharedFunctionInfo> shared, | 1075 Handle<SharedFunctionInfo> shared, |
1089 BreakPositionAlignment position_alignment) { | 1076 BreakPositionAlignment position_alignment) { |
1090 Isolate* isolate = shared->GetIsolate(); | 1077 Isolate* isolate = shared->GetIsolate(); |
1091 if (!shared->HasDebugInfo()) { | 1078 if (!shared->HasDebugInfo()) { |
1092 return isolate->factory()->undefined_value(); | 1079 return isolate->factory()->undefined_value(); |
1093 } | 1080 } |
1094 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 1081 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
1095 if (debug_info->GetBreakPointCount() == 0) { | 1082 if (debug_info->GetBreakPointCount() == 0) { |
1096 return isolate->factory()->undefined_value(); | 1083 return isolate->factory()->undefined_value(); |
1097 } | 1084 } |
1098 Handle<FixedArray> locations = | 1085 Handle<FixedArray> locations = |
1099 isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount()); | 1086 isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount()); |
1100 int count = 0; | 1087 int count = 0; |
1101 for (int i = 0; i < debug_info->break_points()->length(); ++i) { | 1088 for (int i = 0; i < debug_info->break_points()->length(); ++i) { |
1102 if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) { | 1089 if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) { |
1103 BreakPointInfo* break_point_info = | 1090 BreakPointInfo* break_point_info = |
1104 BreakPointInfo::cast(debug_info->break_points()->get(i)); | 1091 BreakPointInfo::cast(debug_info->break_points()->get(i)); |
1105 int break_points = break_point_info->GetBreakPointCount(); | 1092 int break_points = break_point_info->GetBreakPointCount(); |
1106 if (break_points == 0) continue; | 1093 if (break_points == 0) continue; |
1107 Smi* position = NULL; | 1094 Smi* position = NULL; |
1108 if (position_alignment == STATEMENT_ALIGNED) { | 1095 if (position_alignment == STATEMENT_ALIGNED) { |
1109 if (debug_info->HasDebugCode()) { | 1096 if (debug_info->HasDebugCode()) { |
1110 CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 1097 CodeBreakIterator it(debug_info); |
1111 it.SkipToPosition(break_point_info->source_position(), | 1098 it.SkipToPosition(break_point_info->source_position(), |
1112 BREAK_POSITION_ALIGNED); | 1099 BREAK_POSITION_ALIGNED); |
1113 position = Smi::FromInt(it.statement_position()); | 1100 position = Smi::FromInt(it.statement_position()); |
1114 } else { | 1101 } else { |
1115 DCHECK(debug_info->HasDebugBytecodeArray()); | 1102 DCHECK(debug_info->HasDebugBytecodeArray()); |
1116 BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 1103 BytecodeArrayBreakIterator it(debug_info); |
1117 it.SkipToPosition(break_point_info->source_position(), | 1104 it.SkipToPosition(break_point_info->source_position(), |
1118 BREAK_POSITION_ALIGNED); | 1105 BREAK_POSITION_ALIGNED); |
1119 position = Smi::FromInt(it.statement_position()); | 1106 position = Smi::FromInt(it.statement_position()); |
1120 } | 1107 } |
1121 } else { | 1108 } else { |
1122 DCHECK_EQ(BREAK_POSITION_ALIGNED, position_alignment); | 1109 DCHECK_EQ(BREAK_POSITION_ALIGNED, position_alignment); |
1123 position = Smi::FromInt(break_point_info->source_position()); | 1110 position = Smi::FromInt(break_point_info->source_position()); |
1124 } | 1111 } |
1125 for (int j = 0; j < break_points; ++j) locations->set(count++, position); | 1112 for (int j = 0; j < break_points; ++j) locations->set(count++, position); |
1126 } | 1113 } |
1127 } | 1114 } |
1128 return locations; | 1115 return locations; |
1129 } | 1116 } |
1130 | 1117 |
1131 void Debug::ClearStepping() { | 1118 void Debug::ClearStepping() { |
1132 // Clear the various stepping setup. | 1119 // Clear the various stepping setup. |
1133 ClearOneShot(); | 1120 ClearOneShot(); |
1134 | 1121 |
1135 thread_local_.last_step_action_ = StepNone; | 1122 thread_local_.last_step_action_ = StepNone; |
1136 thread_local_.last_statement_position_ = kNoSourcePosition; | 1123 thread_local_.last_statement_position_ = kNoSourcePosition; |
1137 thread_local_.last_fp_ = 0; | 1124 thread_local_.last_frame_count_ = -1; |
1138 thread_local_.target_fp_ = 0; | 1125 thread_local_.target_frame_count_ = -1; |
1139 UpdateHookOnFunctionCall(); | 1126 UpdateHookOnFunctionCall(); |
1140 } | 1127 } |
1141 | 1128 |
1142 | 1129 |
1143 // Clears all the one-shot break points that are currently set. Normally this | 1130 // Clears all the one-shot break points that are currently set. Normally this |
1144 // function is called each time a break point is hit as one shot break points | 1131 // function is called each time a break point is hit as one shot break points |
1145 // are used to support stepping. | 1132 // are used to support stepping. |
1146 void Debug::ClearOneShot() { | 1133 void Debug::ClearOneShot() { |
1147 // The current implementation just runs through all the breakpoints. When the | 1134 // The current implementation just runs through all the breakpoints. When the |
1148 // last break point for a function is removed that function is automatically | 1135 // last break point for a function is removed that function is automatically |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1347 positions->insert(alignment == STATEMENT_ALIGNED ? it->statement_position() | 1334 positions->insert(alignment == STATEMENT_ALIGNED ? it->statement_position() |
1348 : it->position()); | 1335 : it->position()); |
1349 it->Next(); | 1336 it->Next(); |
1350 } | 1337 } |
1351 } | 1338 } |
1352 | 1339 |
1353 void FindBreakablePositions(Handle<DebugInfo> debug_info, int start_position, | 1340 void FindBreakablePositions(Handle<DebugInfo> debug_info, int start_position, |
1354 int end_position, BreakPositionAlignment alignment, | 1341 int end_position, BreakPositionAlignment alignment, |
1355 std::set<int>* positions) { | 1342 std::set<int>* positions) { |
1356 if (debug_info->HasDebugCode()) { | 1343 if (debug_info->HasDebugCode()) { |
1357 CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 1344 CodeBreakIterator it(debug_info); |
1358 GetBreakablePositions(&it, start_position, end_position, alignment, | 1345 GetBreakablePositions(&it, start_position, end_position, alignment, |
1359 positions); | 1346 positions); |
1360 } else { | 1347 } else { |
1361 DCHECK(debug_info->HasDebugBytecodeArray()); | 1348 DCHECK(debug_info->HasDebugBytecodeArray()); |
1362 BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 1349 BytecodeArrayBreakIterator it(debug_info); |
1363 GetBreakablePositions(&it, start_position, end_position, alignment, | 1350 GetBreakablePositions(&it, start_position, end_position, alignment, |
1364 positions); | 1351 positions); |
1365 } | 1352 } |
1366 } | 1353 } |
1367 } // namespace | 1354 } // namespace |
1368 | 1355 |
1369 bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position, | 1356 bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position, |
1370 int end_position, std::set<int>* positions) { | 1357 int end_position, std::set<int>* positions) { |
1371 while (true) { | 1358 while (true) { |
1372 HandleScope scope(isolate_); | 1359 HandleScope scope(isolate_); |
(...skipping 14 matching lines...) Expand all Loading... |
1387 for (int i = 0; i < candidates.length(); ++i) { | 1374 for (int i = 0; i < candidates.length(); ++i) { |
1388 // Code that cannot be compiled lazily are internal and not debuggable. | 1375 // Code that cannot be compiled lazily are internal and not debuggable. |
1389 DCHECK(candidates[i]->allows_lazy_compilation()); | 1376 DCHECK(candidates[i]->allows_lazy_compilation()); |
1390 if (!candidates[i]->HasDebugCode()) { | 1377 if (!candidates[i]->HasDebugCode()) { |
1391 if (!Compiler::CompileDebugCode(candidates[i])) { | 1378 if (!Compiler::CompileDebugCode(candidates[i])) { |
1392 return false; | 1379 return false; |
1393 } else { | 1380 } else { |
1394 was_compiled = true; | 1381 was_compiled = true; |
1395 } | 1382 } |
1396 } | 1383 } |
1397 if (!EnsureDebugInfo(candidates[i], Handle<JSFunction>::null())) | 1384 if (!EnsureDebugInfo(candidates[i])) return false; |
1398 return false; | |
1399 } | 1385 } |
1400 if (was_compiled) continue; | 1386 if (was_compiled) continue; |
1401 | 1387 |
1402 for (int i = 0; i < candidates.length(); ++i) { | 1388 for (int i = 0; i < candidates.length(); ++i) { |
1403 CHECK(candidates[i]->HasDebugInfo()); | 1389 CHECK(candidates[i]->HasDebugInfo()); |
1404 Handle<DebugInfo> debug_info(candidates[i]->GetDebugInfo()); | 1390 Handle<DebugInfo> debug_info(candidates[i]->GetDebugInfo()); |
1405 FindBreakablePositions(debug_info, start_position, end_position, | 1391 FindBreakablePositions(debug_info, start_position, end_position, |
1406 STATEMENT_ALIGNED, positions); | 1392 STATEMENT_ALIGNED, positions); |
1407 } | 1393 } |
1408 return true; | 1394 return true; |
1409 } | 1395 } |
1410 UNREACHABLE(); | 1396 UNREACHABLE(); |
1411 return false; | 1397 return false; |
1412 } | 1398 } |
1413 | 1399 |
1414 void Debug::RecordGenerator(Handle<JSGeneratorObject> generator_object) { | 1400 void Debug::RecordGenerator(Handle<JSGeneratorObject> generator_object) { |
1415 if (last_step_action() <= StepOut) return; | 1401 if (last_step_action() <= StepOut) return; |
1416 | 1402 |
1417 if (last_step_action() == StepNext) { | 1403 if (last_step_action() == StepNext) { |
1418 // Only consider this generator a step-next target if not stepping in. | 1404 // Only consider this generator a step-next target if not stepping in. |
1419 JavaScriptFrameIterator stack_iterator(isolate_); | 1405 if (thread_local_.target_frame_count_ < CurrentFrameCount()) return; |
1420 JavaScriptFrame* frame = stack_iterator.frame(); | |
1421 if (frame->UnpaddedFP() < thread_local_.target_fp_) return; | |
1422 } | 1406 } |
1423 | 1407 |
1424 DCHECK(!has_suspended_generator()); | 1408 DCHECK(!has_suspended_generator()); |
1425 thread_local_.suspended_generator_ = *generator_object; | 1409 thread_local_.suspended_generator_ = *generator_object; |
1426 ClearStepping(); | 1410 ClearStepping(); |
1427 } | 1411 } |
1428 | 1412 |
1429 class SharedFunctionInfoFinder { | 1413 class SharedFunctionInfoFinder { |
1430 public: | 1414 public: |
1431 explicit SharedFunctionInfoFinder(int target_position) | 1415 explicit SharedFunctionInfoFinder(int target_position) |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1519 HandleScope scope(isolate_); | 1503 HandleScope scope(isolate_); |
1520 // Code that cannot be compiled lazily are internal and not debuggable. | 1504 // Code that cannot be compiled lazily are internal and not debuggable. |
1521 DCHECK(shared->allows_lazy_compilation()); | 1505 DCHECK(shared->allows_lazy_compilation()); |
1522 if (!Compiler::CompileDebugCode(handle(shared))) break; | 1506 if (!Compiler::CompileDebugCode(handle(shared))) break; |
1523 } | 1507 } |
1524 return isolate_->factory()->undefined_value(); | 1508 return isolate_->factory()->undefined_value(); |
1525 } | 1509 } |
1526 | 1510 |
1527 | 1511 |
1528 // Ensures the debug information is present for shared. | 1512 // Ensures the debug information is present for shared. |
1529 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared, | 1513 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) { |
1530 Handle<JSFunction> function) { | |
1531 if (!shared->IsSubjectToDebugging()) return false; | |
1532 | |
1533 // Return if we already have the debug info for shared. | 1514 // Return if we already have the debug info for shared. |
1534 if (shared->HasDebugInfo()) return true; | 1515 if (shared->HasDebugInfo()) return true; |
1535 | 1516 if (!shared->IsSubjectToDebugging()) return false; |
1536 if (function.is_null()) { | 1517 if (!shared->is_compiled() && !Compiler::CompileDebugCode(shared)) { |
1537 DCHECK(shared->HasDebugCode()); | |
1538 } else if (!Compiler::Compile(function, Compiler::CLEAR_EXCEPTION)) { | |
1539 return false; | 1518 return false; |
1540 } | 1519 } |
1541 | 1520 |
1542 // To prepare bytecode for debugging, we already need to have the debug | 1521 // To prepare bytecode for debugging, we already need to have the debug |
1543 // info (containing the debug copy) upfront, but since we do not recompile, | 1522 // info (containing the debug copy) upfront, but since we do not recompile, |
1544 // preparing for break points cannot fail. | 1523 // preparing for break points cannot fail. |
1545 CreateDebugInfo(shared); | 1524 CreateDebugInfo(shared); |
1546 CHECK(PrepareFunctionForBreakPoints(shared)); | 1525 CHECK(PrepareFunctionForBreakPoints(shared)); |
1547 return true; | 1526 return true; |
1548 } | 1527 } |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1699 Handle<Smi> id) { | 1678 Handle<Smi> id) { |
1700 DCHECK(id->IsNumber()); | 1679 DCHECK(id->IsNumber()); |
1701 // Create the async task event object. | 1680 // Create the async task event object. |
1702 Handle<Object> argv[] = {type, id}; | 1681 Handle<Object> argv[] = {type, id}; |
1703 return CallFunction("MakeAsyncTaskEvent", arraysize(argv), argv); | 1682 return CallFunction("MakeAsyncTaskEvent", arraysize(argv), argv); |
1704 } | 1683 } |
1705 | 1684 |
1706 | 1685 |
1707 void Debug::OnThrow(Handle<Object> exception) { | 1686 void Debug::OnThrow(Handle<Object> exception) { |
1708 if (in_debug_scope() || ignore_events()) return; | 1687 if (in_debug_scope() || ignore_events()) return; |
1709 PrepareStepOnThrow(); | |
1710 // Temporarily clear any scheduled_exception to allow evaluating | 1688 // Temporarily clear any scheduled_exception to allow evaluating |
1711 // JavaScript from the debug event handler. | 1689 // JavaScript from the debug event handler. |
1712 HandleScope scope(isolate_); | 1690 HandleScope scope(isolate_); |
1713 Handle<Object> scheduled_exception; | 1691 Handle<Object> scheduled_exception; |
1714 if (isolate_->has_scheduled_exception()) { | 1692 if (isolate_->has_scheduled_exception()) { |
1715 scheduled_exception = handle(isolate_->scheduled_exception(), isolate_); | 1693 scheduled_exception = handle(isolate_->scheduled_exception(), isolate_); |
1716 isolate_->clear_scheduled_exception(); | 1694 isolate_->clear_scheduled_exception(); |
1717 } | 1695 } |
1718 OnException(exception, isolate_->GetPromiseOnStackOnThrow()); | 1696 OnException(exception, isolate_->GetPromiseOnStackOnThrow()); |
1719 if (!scheduled_exception.is_null()) { | 1697 if (!scheduled_exception.is_null()) { |
1720 isolate_->thread_local_top()->scheduled_exception_ = *scheduled_exception; | 1698 isolate_->thread_local_top()->scheduled_exception_ = *scheduled_exception; |
1721 } | 1699 } |
| 1700 PrepareStepOnThrow(); |
1722 } | 1701 } |
1723 | 1702 |
1724 void Debug::OnPromiseReject(Handle<Object> promise, Handle<Object> value) { | 1703 void Debug::OnPromiseReject(Handle<Object> promise, Handle<Object> value) { |
1725 if (in_debug_scope() || ignore_events()) return; | 1704 if (in_debug_scope() || ignore_events()) return; |
1726 HandleScope scope(isolate_); | 1705 HandleScope scope(isolate_); |
1727 // Check whether the promise has been marked as having triggered a message. | 1706 // Check whether the promise has been marked as having triggered a message. |
1728 Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol(); | 1707 Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol(); |
1729 if (!promise->IsJSObject() || | 1708 if (!promise->IsJSObject() || |
1730 JSReceiver::GetDataProperty(Handle<JSObject>::cast(promise), key) | 1709 JSReceiver::GetDataProperty(Handle<JSObject>::cast(promise), key) |
1731 ->IsUndefined(isolate_)) { | 1710 ->IsUndefined(isolate_)) { |
(...skipping 23 matching lines...) Expand all Loading... |
1755 while (!it.done()) { | 1734 while (!it.done()) { |
1756 if (!IsFrameBlackboxed(it.frame())) return false; | 1735 if (!IsFrameBlackboxed(it.frame())) return false; |
1757 it.Advance(); | 1736 it.Advance(); |
1758 } | 1737 } |
1759 return true; | 1738 return true; |
1760 } | 1739 } |
1761 | 1740 |
1762 bool Debug::IsFrameBlackboxed(JavaScriptFrame* frame) { | 1741 bool Debug::IsFrameBlackboxed(JavaScriptFrame* frame) { |
1763 HandleScope scope(isolate_); | 1742 HandleScope scope(isolate_); |
1764 if (!frame->HasInlinedFrames()) { | 1743 if (!frame->HasInlinedFrames()) { |
1765 return IsBlackboxed(frame->function()->shared()); | 1744 Handle<SharedFunctionInfo> shared(frame->function()->shared(), isolate_); |
| 1745 return IsBlackboxed(shared); |
1766 } | 1746 } |
1767 List<SharedFunctionInfo*> raw_shareds; | 1747 List<Handle<SharedFunctionInfo>> infos; |
1768 frame->GetFunctions(&raw_shareds); | 1748 frame->GetFunctions(&infos); |
1769 List<Handle<SharedFunctionInfo>> shareds; | 1749 for (const auto& info : infos) |
1770 for (int i = 0; i < raw_shareds.length(); ++i) { | 1750 if (!IsBlackboxed(info)) return false; |
1771 shareds.Add(handle(raw_shareds[i])); | |
1772 } | |
1773 for (int i = 0; i < shareds.length(); ++i) { | |
1774 if (!IsBlackboxed(shareds[i])) return false; | |
1775 } | |
1776 return true; | 1751 return true; |
1777 } | 1752 } |
1778 | 1753 |
1779 void Debug::OnException(Handle<Object> exception, Handle<Object> promise) { | 1754 void Debug::OnException(Handle<Object> exception, Handle<Object> promise) { |
1780 // We cannot generate debug events when JS execution is disallowed. | 1755 // We cannot generate debug events when JS execution is disallowed. |
1781 // TODO(5530): Reenable debug events within DisallowJSScopes once relevant | 1756 // TODO(5530): Reenable debug events within DisallowJSScopes once relevant |
1782 // code (MakeExceptionEvent and ProcessDebugEvent) have been moved to C++. | 1757 // code (MakeExceptionEvent and ProcessDebugEvent) have been moved to C++. |
1783 if (!AllowJavascriptExecution::IsAllowed(isolate_)) return; | 1758 if (!AllowJavascriptExecution::IsAllowed(isolate_)) return; |
1784 | 1759 |
1785 Isolate::CatchType catch_type = isolate_->PredictExceptionCatcher(); | 1760 Isolate::CatchType catch_type = isolate_->PredictExceptionCatcher(); |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2006 } | 1981 } |
2007 | 1982 |
2008 namespace { | 1983 namespace { |
2009 debug::Location GetDebugLocation(Handle<Script> script, int source_position) { | 1984 debug::Location GetDebugLocation(Handle<Script> script, int source_position) { |
2010 Script::PositionInfo info; | 1985 Script::PositionInfo info; |
2011 Script::GetPositionInfo(script, source_position, &info, Script::WITH_OFFSET); | 1986 Script::GetPositionInfo(script, source_position, &info, Script::WITH_OFFSET); |
2012 return debug::Location(info.line, info.column); | 1987 return debug::Location(info.line, info.column); |
2013 } | 1988 } |
2014 } // namespace | 1989 } // namespace |
2015 | 1990 |
2016 bool Debug::IsBlackboxed(SharedFunctionInfo* shared) { | |
2017 HandleScope scope(isolate_); | |
2018 Handle<SharedFunctionInfo> shared_function_info(shared); | |
2019 return IsBlackboxed(shared_function_info); | |
2020 } | |
2021 | |
2022 bool Debug::IsBlackboxed(Handle<SharedFunctionInfo> shared) { | 1991 bool Debug::IsBlackboxed(Handle<SharedFunctionInfo> shared) { |
2023 if (!debug_delegate_) return false; | 1992 if (!debug_delegate_) return false; |
2024 if (!shared->computed_debug_is_blackboxed()) { | 1993 if (!shared->computed_debug_is_blackboxed()) { |
2025 bool is_blackboxed = false; | 1994 bool is_blackboxed = false; |
2026 if (shared->script()->IsScript()) { | 1995 if (shared->script()->IsScript()) { |
2027 HandleScope handle_scope(isolate_); | 1996 HandleScope handle_scope(isolate_); |
2028 Handle<Script> script(Script::cast(shared->script())); | 1997 Handle<Script> script(Script::cast(shared->script())); |
2029 if (script->type() == i::Script::TYPE_NORMAL) { | 1998 if (script->type() == i::Script::TYPE_NORMAL) { |
2030 debug::Location start = | 1999 debug::Location start = |
2031 GetDebugLocation(script, shared->start_position()); | 2000 GetDebugLocation(script, shared->start_position()); |
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2155 // Set new entry. | 2124 // Set new entry. |
2156 if (!callback->IsNullOrUndefined(isolate_)) { | 2125 if (!callback->IsNullOrUndefined(isolate_)) { |
2157 event_listener_ = global_handles->Create(*callback); | 2126 event_listener_ = global_handles->Create(*callback); |
2158 if (data.is_null()) data = isolate_->factory()->undefined_value(); | 2127 if (data.is_null()) data = isolate_->factory()->undefined_value(); |
2159 event_listener_data_ = global_handles->Create(*data); | 2128 event_listener_data_ = global_handles->Create(*data); |
2160 } | 2129 } |
2161 | 2130 |
2162 UpdateState(); | 2131 UpdateState(); |
2163 } | 2132 } |
2164 | 2133 |
| 2134 int Debug::CurrentFrameCount() { |
| 2135 StackTraceFrameIterator it(isolate_); |
| 2136 if (break_frame_id() != StackFrame::NO_ID) { |
| 2137 // Skip to break frame. |
| 2138 DCHECK(in_debug_scope()); |
| 2139 while (!it.done() && it.frame()->id() != break_frame_id()) it.Advance(); |
| 2140 } |
| 2141 int counter = 0; |
| 2142 while (!it.done()) { |
| 2143 if (it.frame()->is_optimized()) { |
| 2144 List<SharedFunctionInfo*> infos; |
| 2145 OptimizedFrame::cast(it.frame())->GetFunctions(&infos); |
| 2146 counter += infos.length(); |
| 2147 } else { |
| 2148 counter++; |
| 2149 } |
| 2150 it.Advance(); |
| 2151 } |
| 2152 return counter; |
| 2153 } |
| 2154 |
2165 void Debug::SetDebugDelegate(debug::DebugDelegate* delegate) { | 2155 void Debug::SetDebugDelegate(debug::DebugDelegate* delegate) { |
2166 debug_delegate_ = delegate; | 2156 debug_delegate_ = delegate; |
2167 UpdateState(); | 2157 UpdateState(); |
2168 } | 2158 } |
2169 | 2159 |
2170 void Debug::UpdateState() { | 2160 void Debug::UpdateState() { |
2171 bool is_active = !event_listener_.is_null() || debug_delegate_ != nullptr; | 2161 bool is_active = !event_listener_.is_null() || debug_delegate_ != nullptr; |
2172 if (is_active || in_debug_scope()) { | 2162 if (is_active || in_debug_scope()) { |
2173 // Note that the debug context could have already been loaded to | 2163 // Note that the debug context could have already been loaded to |
2174 // bootstrap test cases. | 2164 // bootstrap test cases. |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2218 // Ignore debug break if debugger is not active. | 2208 // Ignore debug break if debugger is not active. |
2219 if (!is_active()) return; | 2209 if (!is_active()) return; |
2220 | 2210 |
2221 StackLimitCheck check(isolate_); | 2211 StackLimitCheck check(isolate_); |
2222 if (check.HasOverflowed()) return; | 2212 if (check.HasOverflowed()) return; |
2223 | 2213 |
2224 { JavaScriptFrameIterator it(isolate_); | 2214 { JavaScriptFrameIterator it(isolate_); |
2225 DCHECK(!it.done()); | 2215 DCHECK(!it.done()); |
2226 Object* fun = it.frame()->function(); | 2216 Object* fun = it.frame()->function(); |
2227 if (fun && fun->IsJSFunction()) { | 2217 if (fun && fun->IsJSFunction()) { |
| 2218 HandleScope scope(isolate_); |
2228 // Don't stop in builtin and blackboxed functions. | 2219 // Don't stop in builtin and blackboxed functions. |
2229 if (!JSFunction::cast(fun)->shared()->IsSubjectToDebugging() || | 2220 Handle<SharedFunctionInfo> shared(JSFunction::cast(fun)->shared(), |
2230 IsBlackboxed(JSFunction::cast(fun)->shared())) { | 2221 isolate_); |
| 2222 if (!shared->IsSubjectToDebugging() || IsBlackboxed(shared)) { |
2231 // Inspector uses pause on next statement for asynchronous breakpoints. | 2223 // Inspector uses pause on next statement for asynchronous breakpoints. |
2232 // When breakpoint is fired we try to break on first not blackboxed | 2224 // When breakpoint is fired we try to break on first not blackboxed |
2233 // statement. To achieve this goal we need to deoptimize current | 2225 // statement. To achieve this goal we need to deoptimize current |
2234 // function and don't clear requested DebugBreak even if it's blackboxed | 2226 // function and don't clear requested DebugBreak even if it's blackboxed |
2235 // to be able to break on not blackboxed function call. | 2227 // to be able to break on not blackboxed function call. |
2236 // TODO(yangguo): introduce break_on_function_entry since current | 2228 // TODO(yangguo): introduce break_on_function_entry since current |
2237 // implementation is slow. | 2229 // implementation is slow. |
2238 Deoptimizer::DeoptimizeFunction(JSFunction::cast(fun)); | 2230 Deoptimizer::DeoptimizeFunction(JSFunction::cast(fun)); |
2239 return; | 2231 return; |
2240 } | 2232 } |
(...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2428 return v8::Utils::ToLocal(callback_data_); | 2420 return v8::Utils::ToLocal(callback_data_); |
2429 } | 2421 } |
2430 | 2422 |
2431 | 2423 |
2432 v8::Isolate* EventDetailsImpl::GetIsolate() const { | 2424 v8::Isolate* EventDetailsImpl::GetIsolate() const { |
2433 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate()); | 2425 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate()); |
2434 } | 2426 } |
2435 | 2427 |
2436 } // namespace internal | 2428 } // namespace internal |
2437 } // namespace v8 | 2429 } // namespace v8 |
OLD | NEW |