Chromium Code Reviews| 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); |
|
jgruber
2017/01/30 15:42:17
Is TCE now enabled by default? Or why is this now
Yang
2017/01/30 19:47:19
If TCE is not enabled, the emitted code will not h
| |
| 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::IsCallOrNew(bytecode)) { | 317 } else if (interpreter::Bytecodes::IsCallOrNew(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_ = Handle<Object>(); | 390 thread_local_.return_value_ = Handle<Object>(); |
| 405 thread_local_.async_task_count_ = 0; | 391 thread_local_.async_task_count_ = 0; |
| 406 clear_suspended_generator(); | 392 clear_suspended_generator(); |
| 407 // TODO(isolates): frames_are_dropped_? | 393 // TODO(isolates): frames_are_dropped_? |
| 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 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 507 // Enter the debugger. | 493 // Enter the debugger. |
| 508 DebugScope debug_scope(this); | 494 DebugScope debug_scope(this); |
| 509 if (debug_scope.failed()) return; | 495 if (debug_scope.failed()) return; |
| 510 | 496 |
| 511 // Postpone interrupt during breakpoint processing. | 497 // Postpone interrupt during breakpoint processing. |
| 512 PostponeInterruptsScope postpone(isolate_); | 498 PostponeInterruptsScope postpone(isolate_); |
| 513 | 499 |
| 514 // Return if we fail to retrieve debug info. | 500 // Return if we fail to retrieve debug info. |
| 515 Handle<JSFunction> function(frame->function()); | 501 Handle<JSFunction> function(frame->function()); |
| 516 Handle<SharedFunctionInfo> shared(function->shared()); | 502 Handle<SharedFunctionInfo> shared(function->shared()); |
| 517 if (!EnsureDebugInfo(shared, function)) return; | 503 if (!EnsureDebugInfo(shared)) return; |
| 518 Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_); | 504 Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_); |
| 519 | 505 |
| 520 // Find the break location where execution has stopped. | 506 // Find the break location where execution has stopped. |
| 521 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); | 507 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); |
| 522 | 508 |
| 523 // Find actual break points, if any, and trigger debug break event. | 509 // Find actual break points, if any, and trigger debug break event. |
| 524 MaybeHandle<FixedArray> break_points_hit = | 510 MaybeHandle<FixedArray> break_points_hit = |
| 525 CheckBreakPoints(debug_info, &location); | 511 CheckBreakPoints(debug_info, &location); |
| 526 if (!break_points_hit.is_null()) { | 512 if (!break_points_hit.is_null()) { |
| 527 // Clear all current stepping setup. | 513 // Clear all current stepping setup. |
| 528 ClearStepping(); | 514 ClearStepping(); |
| 529 // Notify the debug event listeners. | 515 // Notify the debug event listeners. |
| 530 Handle<JSArray> jsarr = isolate_->factory()->NewJSArrayWithElements( | 516 Handle<JSArray> jsarr = isolate_->factory()->NewJSArrayWithElements( |
| 531 break_points_hit.ToHandleChecked()); | 517 break_points_hit.ToHandleChecked()); |
| 532 OnDebugBreak(jsarr); | 518 OnDebugBreak(jsarr); |
| 533 return; | 519 return; |
| 534 } | 520 } |
| 535 | 521 |
| 536 // No break point. Check for stepping. | 522 // No break point. Check for stepping. |
| 537 StepAction step_action = last_step_action(); | 523 StepAction step_action = last_step_action(); |
| 538 Address current_fp = frame->UnpaddedFP(); | 524 int current_frame_count = CurrentFrameCount(); |
| 539 Address target_fp = thread_local_.target_fp_; | 525 int target_frame_count = thread_local_.target_frame_count_; |
| 540 Address last_fp = thread_local_.last_fp_; | 526 int last_frame_count = thread_local_.last_frame_count_; |
| 541 | 527 |
| 542 bool step_break = false; | 528 bool step_break = false; |
| 543 switch (step_action) { | 529 switch (step_action) { |
| 544 case StepNone: | 530 case StepNone: |
| 545 return; | 531 return; |
| 546 case StepOut: | 532 case StepOut: |
| 547 // Step out has not reached the target frame yet. | 533 // Step out should not break in a deeper frame than target frame. |
| 548 if (current_fp < target_fp) return; | 534 if (current_frame_count > target_frame_count) return; |
| 549 step_break = true; | 535 step_break = true; |
| 550 break; | 536 break; |
| 551 case StepNext: | 537 case StepNext: |
| 552 // Step next should not break in a deeper frame. | 538 // Step next should not break in a deeper frame than target frame. |
| 553 if (current_fp < target_fp) return; | 539 if (current_frame_count > target_frame_count) return; |
| 554 // For step-next, a tail call is like a return and should break. | 540 // For step-next, a tail call is like a return and should break. |
| 555 step_break = location.IsTailCall(); | 541 step_break = location.IsTailCall(); |
| 556 // Fall through. | 542 // Fall through. |
| 557 case StepIn: { | 543 case StepIn: { |
| 558 FrameSummary summary = FrameSummary::GetTop(frame); | 544 FrameSummary summary = FrameSummary::GetTop(frame); |
| 559 step_break = step_break || location.IsReturn() || current_fp != last_fp || | 545 step_break = step_break || location.IsReturn() || |
| 546 current_frame_count != last_frame_count || | |
| 560 thread_local_.last_statement_position_ != | 547 thread_local_.last_statement_position_ != |
| 561 summary.SourceStatementPosition(); | 548 summary.SourceStatementPosition(); |
| 562 break; | 549 break; |
| 563 } | 550 } |
| 564 } | 551 } |
| 565 | 552 |
| 566 // Clear all current stepping setup. | 553 // Clear all current stepping setup. |
| 567 ClearStepping(); | 554 ClearStepping(); |
| 568 | 555 |
| 569 if (step_break) { | 556 if (step_break) { |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 587 if (has_break_points) *has_break_points = has_break_points_to_check; | 574 if (has_break_points) *has_break_points = has_break_points_to_check; |
| 588 if (!has_break_points_to_check) return {}; | 575 if (!has_break_points_to_check) return {}; |
| 589 | 576 |
| 590 Handle<Object> break_point_objects = | 577 Handle<Object> break_point_objects = |
| 591 debug_info->GetBreakPointObjects(location->position()); | 578 debug_info->GetBreakPointObjects(location->position()); |
| 592 return Debug::GetHitBreakPointObjects(break_point_objects); | 579 return Debug::GetHitBreakPointObjects(break_point_objects); |
| 593 } | 580 } |
| 594 | 581 |
| 595 | 582 |
| 596 bool Debug::IsMutedAtCurrentLocation(JavaScriptFrame* frame) { | 583 bool Debug::IsMutedAtCurrentLocation(JavaScriptFrame* frame) { |
| 584 HandleScope scope(isolate_); | |
| 597 // A break location is considered muted if break locations on the current | 585 // A break location is considered muted if break locations on the current |
| 598 // statement have at least one break point, and all of these break points | 586 // statement have at least one break point, and all of these break points |
| 599 // evaluate to false. Aside from not triggering a debug break event at the | 587 // evaluate to false. Aside from not triggering a debug break event at the |
| 600 // break location, we also do not trigger one for debugger statements, nor | 588 // break location, we also do not trigger one for debugger statements, nor |
| 601 // an exception event on exception at this location. | 589 // an exception event on exception at this location. |
| 602 Object* fun = frame->function(); | 590 FrameSummary summary = FrameSummary::GetTop(frame); |
| 603 if (!fun->IsJSFunction()) return false; | 591 DCHECK(!summary.IsWasm()); |
| 604 JSFunction* function = JSFunction::cast(fun); | 592 Handle<JSFunction> function = summary.AsJavaScript().function(); |
| 605 if (!function->shared()->HasDebugInfo()) return false; | 593 if (!function->shared()->HasDebugInfo()) return false; |
| 606 HandleScope scope(isolate_); | |
| 607 Handle<DebugInfo> debug_info(function->shared()->GetDebugInfo()); | 594 Handle<DebugInfo> debug_info(function->shared()->GetDebugInfo()); |
| 608 // Enter the debugger. | 595 // Enter the debugger. |
| 609 DebugScope debug_scope(this); | 596 DebugScope debug_scope(this); |
| 610 if (debug_scope.failed()) return false; | 597 if (debug_scope.failed()) return false; |
| 611 List<BreakLocation> break_locations; | 598 List<BreakLocation> break_locations; |
| 612 BreakLocation::AllAtCurrentStatement(debug_info, frame, &break_locations); | 599 BreakLocation::AllAtCurrentStatement(debug_info, frame, &break_locations); |
| 613 bool has_break_points_at_all = false; | 600 bool has_break_points_at_all = false; |
| 614 for (int i = 0; i < break_locations.length(); i++) { | 601 for (int i = 0; i < break_locations.length(); i++) { |
| 615 bool has_break_points; | 602 bool has_break_points; |
| 616 MaybeHandle<FixedArray> check_result = | 603 MaybeHandle<FixedArray> check_result = |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 662 } | 649 } |
| 663 | 650 |
| 664 | 651 |
| 665 bool Debug::SetBreakPoint(Handle<JSFunction> function, | 652 bool Debug::SetBreakPoint(Handle<JSFunction> function, |
| 666 Handle<Object> break_point_object, | 653 Handle<Object> break_point_object, |
| 667 int* source_position) { | 654 int* source_position) { |
| 668 HandleScope scope(isolate_); | 655 HandleScope scope(isolate_); |
| 669 | 656 |
| 670 // Make sure the function is compiled and has set up the debug info. | 657 // Make sure the function is compiled and has set up the debug info. |
| 671 Handle<SharedFunctionInfo> shared(function->shared()); | 658 Handle<SharedFunctionInfo> shared(function->shared()); |
| 672 if (!EnsureDebugInfo(shared, function)) { | 659 if (!EnsureDebugInfo(shared)) return true; |
| 673 // Return if retrieving debug info failed. | |
| 674 return true; | |
| 675 } | |
| 676 | |
| 677 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 660 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 678 // Source positions starts with zero. | 661 // Source positions starts with zero. |
| 679 DCHECK(*source_position >= 0); | 662 DCHECK(*source_position >= 0); |
| 680 | 663 |
| 681 // Find the break point and change it. | 664 // Find the break point and change it. |
| 682 *source_position = | 665 *source_position = |
| 683 FindBreakablePosition(debug_info, *source_position, STATEMENT_ALIGNED); | 666 FindBreakablePosition(debug_info, *source_position, STATEMENT_ALIGNED); |
| 684 DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object); | 667 DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object); |
| 685 // At least one active break point now. | 668 // At least one active break point now. |
| 686 DCHECK(debug_info->GetBreakPointCount() > 0); | 669 DCHECK(debug_info->GetBreakPointCount() > 0); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 706 | 689 |
| 707 HandleScope scope(isolate_); | 690 HandleScope scope(isolate_); |
| 708 | 691 |
| 709 // Obtain shared function info for the function. | 692 // Obtain shared function info for the function. |
| 710 Handle<Object> result = | 693 Handle<Object> result = |
| 711 FindSharedFunctionInfoInScript(script, *source_position); | 694 FindSharedFunctionInfoInScript(script, *source_position); |
| 712 if (result->IsUndefined(isolate_)) return false; | 695 if (result->IsUndefined(isolate_)) return false; |
| 713 | 696 |
| 714 // Make sure the function has set up the debug info. | 697 // Make sure the function has set up the debug info. |
| 715 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(result); | 698 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(result); |
| 716 if (!EnsureDebugInfo(shared, Handle<JSFunction>::null())) { | 699 if (!EnsureDebugInfo(shared)) return false; |
| 717 // Return if retrieving debug info failed. | |
| 718 return false; | |
| 719 } | |
| 720 | 700 |
| 721 // Find position within function. The script position might be before the | 701 // Find position within function. The script position might be before the |
| 722 // source position of the first function. | 702 // source position of the first function. |
| 723 if (shared->start_position() > *source_position) { | 703 if (shared->start_position() > *source_position) { |
| 724 *source_position = shared->start_position(); | 704 *source_position = shared->start_position(); |
| 725 } | 705 } |
| 726 | 706 |
| 727 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 707 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 728 | 708 |
| 729 // Find the break point and change it. | 709 // Find the break point and change it. |
| 730 *source_position = | 710 *source_position = |
| 731 FindBreakablePosition(debug_info, *source_position, alignment); | 711 FindBreakablePosition(debug_info, *source_position, alignment); |
| 732 DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object); | 712 DebugInfo::SetBreakPoint(debug_info, *source_position, break_point_object); |
| 733 // At least one active break point now. | 713 // At least one active break point now. |
| 734 DCHECK(debug_info->GetBreakPointCount() > 0); | 714 DCHECK(debug_info->GetBreakPointCount() > 0); |
| 735 | 715 |
| 736 ClearBreakPoints(debug_info); | 716 ClearBreakPoints(debug_info); |
| 737 ApplyBreakPoints(debug_info); | 717 ApplyBreakPoints(debug_info); |
| 738 | 718 |
| 739 feature_tracker()->Track(DebugFeatureTracker::kBreakPoint); | 719 feature_tracker()->Track(DebugFeatureTracker::kBreakPoint); |
| 740 return true; | 720 return true; |
| 741 } | 721 } |
| 742 | 722 |
| 743 int Debug::FindBreakablePosition(Handle<DebugInfo> debug_info, | 723 int Debug::FindBreakablePosition(Handle<DebugInfo> debug_info, |
| 744 int source_position, | 724 int source_position, |
| 745 BreakPositionAlignment alignment) { | 725 BreakPositionAlignment alignment) { |
| 746 int statement_position; | 726 int statement_position; |
| 747 int position; | 727 int position; |
| 748 if (debug_info->HasDebugCode()) { | 728 if (debug_info->HasDebugCode()) { |
| 749 CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 729 CodeBreakIterator it(debug_info); |
| 750 it.SkipToPosition(source_position, alignment); | 730 it.SkipToPosition(source_position, alignment); |
| 751 statement_position = it.statement_position(); | 731 statement_position = it.statement_position(); |
| 752 position = it.position(); | 732 position = it.position(); |
| 753 } else { | 733 } else { |
| 754 DCHECK(debug_info->HasDebugBytecodeArray()); | 734 DCHECK(debug_info->HasDebugBytecodeArray()); |
| 755 BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 735 BytecodeArrayBreakIterator it(debug_info); |
| 756 it.SkipToPosition(source_position, alignment); | 736 it.SkipToPosition(source_position, alignment); |
| 757 statement_position = it.statement_position(); | 737 statement_position = it.statement_position(); |
| 758 position = it.position(); | 738 position = it.position(); |
| 759 } | 739 } |
| 760 return alignment == STATEMENT_ALIGNED ? statement_position : position; | 740 return alignment == STATEMENT_ALIGNED ? statement_position : position; |
| 761 } | 741 } |
| 762 | 742 |
| 763 void Debug::ApplyBreakPoints(Handle<DebugInfo> debug_info) { | 743 void Debug::ApplyBreakPoints(Handle<DebugInfo> debug_info) { |
| 764 DisallowHeapAllocation no_gc; | 744 DisallowHeapAllocation no_gc; |
| 765 if (debug_info->break_points()->IsUndefined(isolate_)) return; | 745 if (debug_info->break_points()->IsUndefined(isolate_)) return; |
| 766 FixedArray* break_points = debug_info->break_points(); | 746 FixedArray* break_points = debug_info->break_points(); |
| 767 for (int i = 0; i < break_points->length(); i++) { | 747 for (int i = 0; i < break_points->length(); i++) { |
| 768 if (break_points->get(i)->IsUndefined(isolate_)) continue; | 748 if (break_points->get(i)->IsUndefined(isolate_)) continue; |
| 769 BreakPointInfo* info = BreakPointInfo::cast(break_points->get(i)); | 749 BreakPointInfo* info = BreakPointInfo::cast(break_points->get(i)); |
| 770 if (info->GetBreakPointCount() == 0) continue; | 750 if (info->GetBreakPointCount() == 0) continue; |
| 771 if (debug_info->HasDebugCode()) { | 751 if (debug_info->HasDebugCode()) { |
| 772 CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 752 CodeBreakIterator it(debug_info); |
| 773 it.SkipToPosition(info->source_position(), BREAK_POSITION_ALIGNED); | 753 it.SkipToPosition(info->source_position(), BREAK_POSITION_ALIGNED); |
| 774 it.SetDebugBreak(); | 754 it.SetDebugBreak(); |
| 775 } | 755 } |
| 776 if (debug_info->HasDebugBytecodeArray()) { | 756 if (debug_info->HasDebugBytecodeArray()) { |
| 777 BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 757 BytecodeArrayBreakIterator it(debug_info); |
| 778 it.SkipToPosition(info->source_position(), BREAK_POSITION_ALIGNED); | 758 it.SkipToPosition(info->source_position(), BREAK_POSITION_ALIGNED); |
| 779 it.SetDebugBreak(); | 759 it.SetDebugBreak(); |
| 780 } | 760 } |
| 781 } | 761 } |
| 782 } | 762 } |
| 783 | 763 |
| 784 void Debug::ClearBreakPoints(Handle<DebugInfo> debug_info) { | 764 void Debug::ClearBreakPoints(Handle<DebugInfo> debug_info) { |
| 785 DisallowHeapAllocation no_gc; | 765 DisallowHeapAllocation no_gc; |
| 786 if (debug_info->HasDebugCode()) { | 766 if (debug_info->HasDebugCode()) { |
| 787 for (CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); !it.Done(); | 767 for (CodeBreakIterator it(debug_info); !it.Done(); it.Next()) { |
| 788 it.Next()) { | |
| 789 it.ClearDebugBreak(); | 768 it.ClearDebugBreak(); |
| 790 } | 769 } |
| 791 } | 770 } |
| 792 if (debug_info->HasDebugBytecodeArray()) { | 771 if (debug_info->HasDebugBytecodeArray()) { |
| 793 for (BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 772 for (BytecodeArrayBreakIterator it(debug_info); !it.Done(); it.Next()) { |
| 794 !it.Done(); it.Next()) { | |
| 795 it.ClearDebugBreak(); | 773 it.ClearDebugBreak(); |
| 796 } | 774 } |
| 797 } | 775 } |
| 798 } | 776 } |
| 799 | 777 |
| 800 void Debug::ClearBreakPoint(Handle<Object> break_point_object) { | 778 void Debug::ClearBreakPoint(Handle<Object> break_point_object) { |
| 801 HandleScope scope(isolate_); | 779 HandleScope scope(isolate_); |
| 802 | 780 |
| 803 for (DebugInfoListNode* node = debug_info_list_; node != NULL; | 781 for (DebugInfoListNode* node = debug_info_list_; node != NULL; |
| 804 node = node->next()) { | 782 node = node->next()) { |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 825 for (DebugInfoListNode* node = debug_info_list_; node != NULL; | 803 for (DebugInfoListNode* node = debug_info_list_; node != NULL; |
| 826 node = node->next()) { | 804 node = node->next()) { |
| 827 ClearBreakPoints(node->debug_info()); | 805 ClearBreakPoints(node->debug_info()); |
| 828 } | 806 } |
| 829 // Remove all debug info. | 807 // Remove all debug info. |
| 830 while (debug_info_list_ != NULL) { | 808 while (debug_info_list_ != NULL) { |
| 831 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info()); | 809 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info()); |
| 832 } | 810 } |
| 833 } | 811 } |
| 834 | 812 |
| 835 void Debug::FloodWithOneShot(Handle<JSFunction> function, | 813 void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) { |
| 836 BreakLocatorType type) { | 814 if (!shared->IsSubjectToDebugging() || IsBlackboxed(shared)) return; |
| 837 // Debug utility functions are not subject to debugging. | |
| 838 if (function->native_context() == *debug_context()) return; | |
| 839 | |
| 840 if (!function->shared()->IsSubjectToDebugging() || | |
| 841 IsBlackboxed(function->shared())) { | |
| 842 // Builtin functions are not subject to stepping, but need to be | |
| 843 // deoptimized, because optimized code does not check for debug | |
| 844 // step in at call sites. | |
| 845 Deoptimizer::DeoptimizeFunction(*function); | |
| 846 return; | |
| 847 } | |
| 848 // Make sure the function is compiled and has set up the debug info. | 815 // Make sure the function is compiled and has set up the debug info. |
| 849 Handle<SharedFunctionInfo> shared(function->shared()); | 816 if (!EnsureDebugInfo(shared)) return; |
| 850 if (!EnsureDebugInfo(shared, function)) { | 817 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 851 // Return if we failed to retrieve the debug info. | |
| 852 return; | |
| 853 } | |
| 854 | |
| 855 // Flood the function with break points. | 818 // Flood the function with break points. |
| 856 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | |
| 857 if (debug_info->HasDebugCode()) { | 819 if (debug_info->HasDebugCode()) { |
| 858 for (CodeBreakIterator it(debug_info, type); !it.Done(); it.Next()) { | 820 for (CodeBreakIterator it(debug_info); !it.Done(); it.Next()) { |
| 859 it.SetDebugBreak(); | 821 it.SetDebugBreak(); |
| 860 } | 822 } |
| 861 } | 823 } |
| 862 if (debug_info->HasDebugBytecodeArray()) { | 824 if (debug_info->HasDebugBytecodeArray()) { |
| 863 for (BytecodeArrayBreakIterator it(debug_info, type); !it.Done(); | 825 for (BytecodeArrayBreakIterator it(debug_info); !it.Done(); it.Next()) { |
| 864 it.Next()) { | |
| 865 it.SetDebugBreak(); | 826 it.SetDebugBreak(); |
| 866 } | 827 } |
| 867 } | 828 } |
| 868 } | 829 } |
| 869 | 830 |
| 870 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) { | 831 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) { |
| 871 if (type == BreakUncaughtException) { | 832 if (type == BreakUncaughtException) { |
| 872 break_on_uncaught_exception_ = enable; | 833 break_on_uncaught_exception_ = enable; |
| 873 } else { | 834 } else { |
| 874 break_on_exception_ = enable; | 835 break_on_exception_ = enable; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 908 if (break_points_hit_count == 0) return {}; | 869 if (break_points_hit_count == 0) return {}; |
| 909 break_points_hit->Shrink(break_points_hit_count); | 870 break_points_hit->Shrink(break_points_hit_count); |
| 910 return break_points_hit; | 871 return break_points_hit; |
| 911 } | 872 } |
| 912 | 873 |
| 913 void Debug::PrepareStepIn(Handle<JSFunction> function) { | 874 void Debug::PrepareStepIn(Handle<JSFunction> function) { |
| 914 CHECK(last_step_action() >= StepIn); | 875 CHECK(last_step_action() >= StepIn); |
| 915 if (ignore_events()) return; | 876 if (ignore_events()) return; |
| 916 if (in_debug_scope()) return; | 877 if (in_debug_scope()) return; |
| 917 if (break_disabled()) return; | 878 if (break_disabled()) return; |
| 918 FloodWithOneShot(function); | 879 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared(), isolate_)); |
| 919 } | 880 } |
| 920 | 881 |
| 921 void Debug::PrepareStepInSuspendedGenerator() { | 882 void Debug::PrepareStepInSuspendedGenerator() { |
| 922 CHECK(has_suspended_generator()); | 883 CHECK(has_suspended_generator()); |
| 923 if (ignore_events()) return; | 884 if (ignore_events()) return; |
| 924 if (in_debug_scope()) return; | 885 if (in_debug_scope()) return; |
| 925 if (break_disabled()) return; | 886 if (break_disabled()) return; |
| 926 thread_local_.last_step_action_ = StepIn; | 887 thread_local_.last_step_action_ = StepIn; |
| 927 UpdateHookOnFunctionCall(); | 888 UpdateHookOnFunctionCall(); |
| 928 Handle<JSFunction> function( | 889 Handle<JSFunction> function( |
| 929 JSGeneratorObject::cast(thread_local_.suspended_generator_)->function()); | 890 JSGeneratorObject::cast(thread_local_.suspended_generator_)->function()); |
| 930 FloodWithOneShot(function); | 891 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared(), isolate_)); |
| 931 clear_suspended_generator(); | 892 clear_suspended_generator(); |
| 932 } | 893 } |
| 933 | 894 |
| 934 void Debug::PrepareStepOnThrow() { | 895 void Debug::PrepareStepOnThrow() { |
| 935 if (last_step_action() == StepNone) return; | 896 if (last_step_action() == StepNone) return; |
| 936 if (ignore_events()) return; | 897 if (ignore_events()) return; |
| 937 if (in_debug_scope()) return; | 898 if (in_debug_scope()) return; |
| 938 if (break_disabled()) return; | 899 if (break_disabled()) return; |
| 939 | 900 |
| 940 ClearOneShot(); | 901 ClearOneShot(); |
| 941 | 902 |
| 903 int current_frame_count = CurrentFrameCount(); | |
| 904 | |
| 942 // Iterate through the JavaScript stack looking for handlers. | 905 // Iterate through the JavaScript stack looking for handlers. |
| 943 JavaScriptFrameIterator it(isolate_); | 906 JavaScriptFrameIterator it(isolate_); |
| 944 while (!it.done()) { | 907 while (!it.done()) { |
| 945 JavaScriptFrame* frame = it.frame(); | 908 JavaScriptFrame* frame = it.frame(); |
| 946 if (frame->LookupExceptionHandlerInTable(nullptr, nullptr) > 0) break; | 909 if (frame->LookupExceptionHandlerInTable(nullptr, nullptr) > 0) break; |
| 910 List<SharedFunctionInfo*> infos; | |
| 911 frame->GetFunctions(&infos); | |
| 912 current_frame_count -= infos.length(); | |
| 947 it.Advance(); | 913 it.Advance(); |
| 948 } | 914 } |
| 949 | 915 |
| 950 if (last_step_action() == StepNext || last_step_action() == StepOut) { | 916 // No handler found. Nothing to instrument. |
| 951 while (!it.done()) { | 917 if (it.done()) return; |
| 952 Address current_fp = it.frame()->UnpaddedFP(); | 918 |
| 953 if (current_fp >= thread_local_.target_fp_) break; | 919 bool found_handler = false; |
| 954 it.Advance(); | 920 // Iterate frames, including inlined frames. First, find the handler frame. |
| 921 // Then skip to the frame we want to break in, then instrument for stepping. | |
| 922 for (; !it.done(); it.Advance()) { | |
| 923 JavaScriptFrame* frame = JavaScriptFrame::cast(it.frame()); | |
| 924 if (last_step_action() == StepIn) { | |
| 925 // Deoptimize frame to ensure calls are checked for step-in. | |
| 926 Deoptimizer::DeoptimizeFunction(frame->function()); | |
| 927 } | |
| 928 List<FrameSummary> summaries; | |
| 929 frame->Summarize(&summaries); | |
| 930 for (int i = summaries.length() - 1; i >= 0; i--, current_frame_count--) { | |
| 931 if (!found_handler) { | |
| 932 // We have yet to find the handler. If the frame inlines multiple | |
| 933 // functions, we have to check each one for the handler. | |
| 934 // If it only contains one function, we already found the handler. | |
| 935 if (summaries.length() > 1) { | |
| 936 Handle<AbstractCode> code = | |
| 937 summaries[i].AsJavaScript().abstract_code(); | |
| 938 CHECK_EQ(AbstractCode::INTERPRETED_FUNCTION, code->kind()); | |
| 939 BytecodeArray* bytecode = code->GetBytecodeArray(); | |
| 940 HandlerTable* table = HandlerTable::cast(bytecode->handler_table()); | |
| 941 int code_offset = summaries[i].code_offset(); | |
| 942 HandlerTable::CatchPrediction prediction; | |
| 943 int index = table->LookupRange(code_offset, nullptr, &prediction); | |
| 944 if (index > 0) found_handler = true; | |
| 945 } else { | |
| 946 found_handler = true; | |
| 947 } | |
| 948 } | |
| 949 | |
| 950 if (found_handler) { | |
| 951 // We found the handler. If we are stepping next or out, we need to | |
| 952 // iterate until we found the suitable target frame to break in. | |
| 953 if ((last_step_action() == StepNext || last_step_action() == StepOut) && | |
| 954 current_frame_count > thread_local_.target_frame_count_) { | |
| 955 continue; | |
| 956 } | |
| 957 Handle<SharedFunctionInfo> info( | |
| 958 summaries[i].AsJavaScript().function()->shared()); | |
| 959 if (!info->IsSubjectToDebugging() || IsBlackboxed(info)) continue; | |
| 960 FloodWithOneShot(info); | |
| 961 return; | |
| 962 } | |
| 955 } | 963 } |
| 956 } | 964 } |
| 957 | |
| 958 // Find the closest Javascript frame we can flood with one-shots. | |
| 959 while (!it.done() && | |
| 960 (!it.frame()->function()->shared()->IsSubjectToDebugging() || | |
| 961 IsBlackboxed(it.frame()->function()->shared()))) { | |
| 962 it.Advance(); | |
| 963 } | |
| 964 | |
| 965 if (it.done()) return; // No suitable Javascript catch handler. | |
| 966 | |
| 967 FloodWithOneShot(Handle<JSFunction>(it.frame()->function())); | |
| 968 } | 965 } |
| 969 | 966 |
| 970 | 967 |
| 971 void Debug::PrepareStep(StepAction step_action) { | 968 void Debug::PrepareStep(StepAction step_action) { |
| 972 HandleScope scope(isolate_); | 969 HandleScope scope(isolate_); |
| 973 | 970 |
| 974 DCHECK(in_debug_scope()); | 971 DCHECK(in_debug_scope()); |
| 975 | 972 |
| 976 // Get the frame where the execution has stopped and skip the debug frame if | 973 // Get the frame where the execution has stopped and skip the debug frame if |
| 977 // any. The debug frame will only be present if execution was stopped due to | 974 // any. The debug frame will only be present if execution was stopped due to |
| 978 // hitting a break point. In other situations (e.g. unhandled exception) the | 975 // hitting a break point. In other situations (e.g. unhandled exception) the |
| 979 // debug frame is not present. | 976 // debug frame is not present. |
| 980 StackFrame::Id frame_id = break_frame_id(); | 977 StackFrame::Id frame_id = break_frame_id(); |
| 981 // If there is no JavaScript stack don't do anything. | 978 // If there is no JavaScript stack don't do anything. |
| 982 if (frame_id == StackFrame::NO_ID) return; | 979 if (frame_id == StackFrame::NO_ID) return; |
| 983 | 980 |
| 984 StackTraceFrameIterator frames_it(isolate_, frame_id); | |
| 985 StandardFrame* frame = frames_it.frame(); | |
| 986 | |
| 987 feature_tracker()->Track(DebugFeatureTracker::kStepping); | 981 feature_tracker()->Track(DebugFeatureTracker::kStepping); |
| 988 | 982 |
| 989 thread_local_.last_step_action_ = step_action; | 983 thread_local_.last_step_action_ = step_action; |
| 990 UpdateHookOnFunctionCall(); | 984 UpdateHookOnFunctionCall(); |
| 991 | 985 |
| 986 StackTraceFrameIterator frames_it(isolate_, frame_id); | |
| 987 StandardFrame* frame = frames_it.frame(); | |
| 988 | |
| 992 // Handle stepping in wasm functions via the wasm interpreter. | 989 // Handle stepping in wasm functions via the wasm interpreter. |
| 993 if (frame->is_wasm()) { | 990 if (frame->is_wasm()) { |
| 994 // If the top frame is compiled, we cannot step. | 991 // If the top frame is compiled, we cannot step. |
| 995 if (frame->is_wasm_compiled()) return; | 992 if (frame->is_wasm_compiled()) return; |
| 996 WasmInterpreterEntryFrame* wasm_frame = | 993 WasmInterpreterEntryFrame* wasm_frame = |
| 997 WasmInterpreterEntryFrame::cast(frame); | 994 WasmInterpreterEntryFrame::cast(frame); |
| 998 wasm_frame->wasm_instance()->debug_info()->PrepareStep(step_action); | 995 wasm_frame->wasm_instance()->debug_info()->PrepareStep(step_action); |
| 999 return; | 996 return; |
| 1000 } | 997 } |
| 1001 | 998 |
| 1002 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); | 999 JavaScriptFrame* js_frame = JavaScriptFrame::cast(frame); |
| 1003 | 1000 DCHECK(js_frame->function()->IsJSFunction()); |
| 1004 // If the function on the top frame is unresolved perform step out. This will | |
| 1005 // be the case when calling unknown function and having the debugger stopped | |
| 1006 // in an unhandled exception. | |
| 1007 if (!js_frame->function()->IsJSFunction()) { | |
| 1008 // Step out: Find the calling JavaScript frame and flood it with | |
| 1009 // breakpoints. | |
| 1010 frames_it.Advance(); | |
| 1011 // Fill the function to return to with one-shot break points. | |
| 1012 JSFunction* function = JavaScriptFrame::cast(frames_it.frame())->function(); | |
| 1013 FloodWithOneShot(handle(function, isolate_)); | |
| 1014 return; | |
| 1015 } | |
| 1016 | 1001 |
| 1017 // Get the debug info (create it if it does not exist). | 1002 // Get the debug info (create it if it does not exist). |
| 1018 auto summary = FrameSummary::GetTop(frame).AsJavaScript(); | 1003 auto summary = FrameSummary::GetTop(frame).AsJavaScript(); |
| 1019 Handle<JSFunction> function(summary.function()); | 1004 Handle<JSFunction> function(summary.function()); |
| 1020 Handle<SharedFunctionInfo> shared(function->shared()); | 1005 Handle<SharedFunctionInfo> shared(function->shared()); |
| 1021 if (!EnsureDebugInfo(shared, function)) { | 1006 if (!EnsureDebugInfo(shared)) return; |
| 1022 // Return if ensuring debug info failed. | 1007 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 1023 return; | |
| 1024 } | |
| 1025 | 1008 |
| 1026 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | |
| 1027 BreakLocation location = BreakLocation::FromFrame(debug_info, js_frame); | 1009 BreakLocation location = BreakLocation::FromFrame(debug_info, js_frame); |
| 1028 | 1010 |
| 1029 // Any step at a return is a step-out. | 1011 // Any step at a return is a step-out. |
| 1030 if (location.IsReturn()) step_action = StepOut; | 1012 if (location.IsReturn()) step_action = StepOut; |
| 1031 // A step-next at a tail call is a step-out. | 1013 // A step-next at a tail call is a step-out. |
| 1032 if (location.IsTailCall() && step_action == StepNext) step_action = StepOut; | 1014 if (location.IsTailCall() && step_action == StepNext) step_action = StepOut; |
| 1033 // A step-next in blackboxed function is a step-out. | 1015 // A step-next in blackboxed function is a step-out. |
| 1034 if (step_action == StepNext && IsBlackboxed(shared)) step_action = StepOut; | 1016 if (step_action == StepNext && IsBlackboxed(shared)) step_action = StepOut; |
| 1035 | 1017 |
| 1036 thread_local_.last_statement_position_ = | 1018 thread_local_.last_statement_position_ = |
| 1037 summary.abstract_code()->SourceStatementPosition(summary.code_offset()); | 1019 summary.abstract_code()->SourceStatementPosition(summary.code_offset()); |
| 1038 thread_local_.last_fp_ = frame->UnpaddedFP(); | 1020 int current_frame_count = CurrentFrameCount(); |
| 1021 thread_local_.last_frame_count_ = current_frame_count; | |
| 1039 // No longer perform the current async step. | 1022 // No longer perform the current async step. |
| 1040 clear_suspended_generator(); | 1023 clear_suspended_generator(); |
| 1041 | 1024 |
| 1042 switch (step_action) { | 1025 switch (step_action) { |
| 1043 case StepNone: | 1026 case StepNone: |
| 1044 UNREACHABLE(); | 1027 UNREACHABLE(); |
| 1045 break; | 1028 break; |
| 1046 case StepOut: | 1029 case StepOut: { |
| 1047 // Advance to caller frame. | |
| 1048 frames_it.Advance(); | |
| 1049 // Find top-most function which is subject to debugging. | |
| 1050 while (!frames_it.done()) { | |
| 1051 StandardFrame* caller_frame = frames_it.frame(); | |
| 1052 if (caller_frame->is_wasm()) { | |
| 1053 // TODO(clemensh): Implement stepping out from JS to WASM. | |
| 1054 break; | |
| 1055 } | |
| 1056 Handle<JSFunction> js_caller_function( | |
| 1057 JavaScriptFrame::cast(caller_frame)->function(), isolate_); | |
| 1058 if (js_caller_function->shared()->IsSubjectToDebugging() && | |
| 1059 !IsBlackboxed(js_caller_function->shared())) { | |
| 1060 // Fill the caller function to return to with one-shot break points. | |
| 1061 FloodWithOneShot(js_caller_function); | |
| 1062 thread_local_.target_fp_ = frames_it.frame()->UnpaddedFP(); | |
| 1063 break; | |
| 1064 } | |
| 1065 // Builtin functions are not subject to stepping, but need to be | |
| 1066 // deoptimized to include checks for step-in at call sites. | |
| 1067 Deoptimizer::DeoptimizeFunction(*js_caller_function); | |
| 1068 frames_it.Advance(); | |
| 1069 } | |
| 1070 // Clear last position info. For stepping out it does not matter. | 1030 // Clear last position info. For stepping out it does not matter. |
| 1071 thread_local_.last_statement_position_ = kNoSourcePosition; | 1031 thread_local_.last_statement_position_ = kNoSourcePosition; |
| 1072 thread_local_.last_fp_ = 0; | 1032 thread_local_.last_frame_count_ = -1; |
| 1033 // Skip the current frame, find the first frame we want to step out to | |
| 1034 // and deoptimize every frame along the way. | |
| 1035 bool in_current_frame = true; | |
| 1036 for (; !frames_it.done(); frames_it.Advance()) { | |
| 1037 // TODO(clemensh): Implement stepping out from JS to WASM. | |
| 1038 if (frames_it.frame()->is_wasm()) continue; | |
| 1039 JavaScriptFrame* frame = JavaScriptFrame::cast(frames_it.frame()); | |
| 1040 if (last_step_action() == StepIn) { | |
| 1041 // Deoptimize frame to ensure calls are checked for step-in. | |
| 1042 Deoptimizer::DeoptimizeFunction(frame->function()); | |
| 1043 } | |
| 1044 HandleScope scope(isolate_); | |
| 1045 List<Handle<SharedFunctionInfo>> infos; | |
| 1046 frame->GetFunctions(&infos); | |
| 1047 for (; !infos.is_empty(); current_frame_count--) { | |
| 1048 Handle<SharedFunctionInfo> info = infos.RemoveLast(); | |
| 1049 if (in_current_frame) { | |
| 1050 // We want to skip out, so skip the current frame. | |
| 1051 in_current_frame = false; | |
| 1052 continue; | |
| 1053 } | |
| 1054 if (!info->IsSubjectToDebugging() || IsBlackboxed(info)) continue; | |
| 1055 FloodWithOneShot(info); | |
| 1056 thread_local_.target_frame_count_ = current_frame_count; | |
| 1057 return; | |
| 1058 } | |
| 1059 } | |
| 1073 break; | 1060 break; |
| 1061 } | |
| 1074 case StepNext: | 1062 case StepNext: |
| 1075 thread_local_.target_fp_ = frame->UnpaddedFP(); | 1063 thread_local_.target_frame_count_ = current_frame_count; |
| 1076 FloodWithOneShot(function); | 1064 // Fall through. |
| 1077 break; | |
| 1078 case StepIn: | 1065 case StepIn: |
| 1079 // TODO(clemensh): Implement stepping from JS into WASM. | 1066 // TODO(clemensh): Implement stepping from JS into WASM. |
| 1080 FloodWithOneShot(function); | 1067 FloodWithOneShot(shared); |
| 1081 break; | 1068 break; |
| 1082 } | 1069 } |
| 1083 } | 1070 } |
| 1084 | 1071 |
| 1085 // Simple function for returning the source positions for active break points. | 1072 // Simple function for returning the source positions for active break points. |
| 1086 Handle<Object> Debug::GetSourceBreakLocations( | 1073 Handle<Object> Debug::GetSourceBreakLocations( |
| 1087 Handle<SharedFunctionInfo> shared, | 1074 Handle<SharedFunctionInfo> shared, |
| 1088 BreakPositionAlignment position_alignment) { | 1075 BreakPositionAlignment position_alignment) { |
| 1089 Isolate* isolate = shared->GetIsolate(); | 1076 Isolate* isolate = shared->GetIsolate(); |
| 1090 if (!shared->HasDebugInfo()) { | 1077 if (!shared->HasDebugInfo()) { |
| 1091 return isolate->factory()->undefined_value(); | 1078 return isolate->factory()->undefined_value(); |
| 1092 } | 1079 } |
| 1093 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); | 1080 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); |
| 1094 if (debug_info->GetBreakPointCount() == 0) { | 1081 if (debug_info->GetBreakPointCount() == 0) { |
| 1095 return isolate->factory()->undefined_value(); | 1082 return isolate->factory()->undefined_value(); |
| 1096 } | 1083 } |
| 1097 Handle<FixedArray> locations = | 1084 Handle<FixedArray> locations = |
| 1098 isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount()); | 1085 isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount()); |
| 1099 int count = 0; | 1086 int count = 0; |
| 1100 for (int i = 0; i < debug_info->break_points()->length(); ++i) { | 1087 for (int i = 0; i < debug_info->break_points()->length(); ++i) { |
| 1101 if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) { | 1088 if (!debug_info->break_points()->get(i)->IsUndefined(isolate)) { |
| 1102 BreakPointInfo* break_point_info = | 1089 BreakPointInfo* break_point_info = |
| 1103 BreakPointInfo::cast(debug_info->break_points()->get(i)); | 1090 BreakPointInfo::cast(debug_info->break_points()->get(i)); |
| 1104 int break_points = break_point_info->GetBreakPointCount(); | 1091 int break_points = break_point_info->GetBreakPointCount(); |
| 1105 if (break_points == 0) continue; | 1092 if (break_points == 0) continue; |
| 1106 Smi* position = NULL; | 1093 Smi* position = NULL; |
| 1107 if (position_alignment == STATEMENT_ALIGNED) { | 1094 if (position_alignment == STATEMENT_ALIGNED) { |
| 1108 if (debug_info->HasDebugCode()) { | 1095 if (debug_info->HasDebugCode()) { |
| 1109 CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 1096 CodeBreakIterator it(debug_info); |
| 1110 it.SkipToPosition(break_point_info->source_position(), | 1097 it.SkipToPosition(break_point_info->source_position(), |
| 1111 BREAK_POSITION_ALIGNED); | 1098 BREAK_POSITION_ALIGNED); |
| 1112 position = Smi::FromInt(it.statement_position()); | 1099 position = Smi::FromInt(it.statement_position()); |
| 1113 } else { | 1100 } else { |
| 1114 DCHECK(debug_info->HasDebugBytecodeArray()); | 1101 DCHECK(debug_info->HasDebugBytecodeArray()); |
| 1115 BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 1102 BytecodeArrayBreakIterator it(debug_info); |
| 1116 it.SkipToPosition(break_point_info->source_position(), | 1103 it.SkipToPosition(break_point_info->source_position(), |
| 1117 BREAK_POSITION_ALIGNED); | 1104 BREAK_POSITION_ALIGNED); |
| 1118 position = Smi::FromInt(it.statement_position()); | 1105 position = Smi::FromInt(it.statement_position()); |
| 1119 } | 1106 } |
| 1120 } else { | 1107 } else { |
| 1121 DCHECK_EQ(BREAK_POSITION_ALIGNED, position_alignment); | 1108 DCHECK_EQ(BREAK_POSITION_ALIGNED, position_alignment); |
| 1122 position = Smi::FromInt(break_point_info->source_position()); | 1109 position = Smi::FromInt(break_point_info->source_position()); |
| 1123 } | 1110 } |
| 1124 for (int j = 0; j < break_points; ++j) locations->set(count++, position); | 1111 for (int j = 0; j < break_points; ++j) locations->set(count++, position); |
| 1125 } | 1112 } |
| 1126 } | 1113 } |
| 1127 return locations; | 1114 return locations; |
| 1128 } | 1115 } |
| 1129 | 1116 |
| 1130 void Debug::ClearStepping() { | 1117 void Debug::ClearStepping() { |
| 1131 // Clear the various stepping setup. | 1118 // Clear the various stepping setup. |
| 1132 ClearOneShot(); | 1119 ClearOneShot(); |
| 1133 | 1120 |
| 1134 thread_local_.last_step_action_ = StepNone; | 1121 thread_local_.last_step_action_ = StepNone; |
| 1135 thread_local_.last_statement_position_ = kNoSourcePosition; | 1122 thread_local_.last_statement_position_ = kNoSourcePosition; |
| 1136 thread_local_.last_fp_ = 0; | 1123 thread_local_.last_frame_count_ = -1; |
| 1137 thread_local_.target_fp_ = 0; | 1124 thread_local_.target_frame_count_ = -1; |
| 1138 UpdateHookOnFunctionCall(); | 1125 UpdateHookOnFunctionCall(); |
| 1139 } | 1126 } |
| 1140 | 1127 |
| 1141 | 1128 |
| 1142 // Clears all the one-shot break points that are currently set. Normally this | 1129 // Clears all the one-shot break points that are currently set. Normally this |
| 1143 // function is called each time a break point is hit as one shot break points | 1130 // function is called each time a break point is hit as one shot break points |
| 1144 // are used to support stepping. | 1131 // are used to support stepping. |
| 1145 void Debug::ClearOneShot() { | 1132 void Debug::ClearOneShot() { |
| 1146 // The current implementation just runs through all the breakpoints. When the | 1133 // The current implementation just runs through all the breakpoints. When the |
| 1147 // last break point for a function is removed that function is automatically | 1134 // last break point for a function is removed that function is automatically |
| (...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1345 positions->insert(alignment == STATEMENT_ALIGNED ? it->statement_position() | 1332 positions->insert(alignment == STATEMENT_ALIGNED ? it->statement_position() |
| 1346 : it->position()); | 1333 : it->position()); |
| 1347 it->Next(); | 1334 it->Next(); |
| 1348 } | 1335 } |
| 1349 } | 1336 } |
| 1350 | 1337 |
| 1351 void FindBreakablePositions(Handle<DebugInfo> debug_info, int start_position, | 1338 void FindBreakablePositions(Handle<DebugInfo> debug_info, int start_position, |
| 1352 int end_position, BreakPositionAlignment alignment, | 1339 int end_position, BreakPositionAlignment alignment, |
| 1353 std::set<int>* positions) { | 1340 std::set<int>* positions) { |
| 1354 if (debug_info->HasDebugCode()) { | 1341 if (debug_info->HasDebugCode()) { |
| 1355 CodeBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 1342 CodeBreakIterator it(debug_info); |
| 1356 GetBreakablePositions(&it, start_position, end_position, alignment, | 1343 GetBreakablePositions(&it, start_position, end_position, alignment, |
| 1357 positions); | 1344 positions); |
| 1358 } else { | 1345 } else { |
| 1359 DCHECK(debug_info->HasDebugBytecodeArray()); | 1346 DCHECK(debug_info->HasDebugBytecodeArray()); |
| 1360 BytecodeArrayBreakIterator it(debug_info, ALL_BREAK_LOCATIONS); | 1347 BytecodeArrayBreakIterator it(debug_info); |
| 1361 GetBreakablePositions(&it, start_position, end_position, alignment, | 1348 GetBreakablePositions(&it, start_position, end_position, alignment, |
| 1362 positions); | 1349 positions); |
| 1363 } | 1350 } |
| 1364 } | 1351 } |
| 1365 } // namespace | 1352 } // namespace |
| 1366 | 1353 |
| 1367 bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position, | 1354 bool Debug::GetPossibleBreakpoints(Handle<Script> script, int start_position, |
| 1368 int end_position, std::set<int>* positions) { | 1355 int end_position, std::set<int>* positions) { |
| 1369 while (true) { | 1356 while (true) { |
| 1370 HandleScope scope(isolate_); | 1357 HandleScope scope(isolate_); |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 1385 for (int i = 0; i < candidates.length(); ++i) { | 1372 for (int i = 0; i < candidates.length(); ++i) { |
| 1386 // Code that cannot be compiled lazily are internal and not debuggable. | 1373 // Code that cannot be compiled lazily are internal and not debuggable. |
| 1387 DCHECK(candidates[i]->allows_lazy_compilation()); | 1374 DCHECK(candidates[i]->allows_lazy_compilation()); |
| 1388 if (!candidates[i]->HasDebugCode()) { | 1375 if (!candidates[i]->HasDebugCode()) { |
| 1389 if (!Compiler::CompileDebugCode(candidates[i])) { | 1376 if (!Compiler::CompileDebugCode(candidates[i])) { |
| 1390 return false; | 1377 return false; |
| 1391 } else { | 1378 } else { |
| 1392 was_compiled = true; | 1379 was_compiled = true; |
| 1393 } | 1380 } |
| 1394 } | 1381 } |
| 1395 if (!EnsureDebugInfo(candidates[i], Handle<JSFunction>::null())) | 1382 if (!EnsureDebugInfo(candidates[i])) return false; |
| 1396 return false; | |
| 1397 } | 1383 } |
| 1398 if (was_compiled) continue; | 1384 if (was_compiled) continue; |
| 1399 | 1385 |
| 1400 for (int i = 0; i < candidates.length(); ++i) { | 1386 for (int i = 0; i < candidates.length(); ++i) { |
| 1401 CHECK(candidates[i]->HasDebugInfo()); | 1387 CHECK(candidates[i]->HasDebugInfo()); |
| 1402 Handle<DebugInfo> debug_info(candidates[i]->GetDebugInfo()); | 1388 Handle<DebugInfo> debug_info(candidates[i]->GetDebugInfo()); |
| 1403 FindBreakablePositions(debug_info, start_position, end_position, | 1389 FindBreakablePositions(debug_info, start_position, end_position, |
| 1404 STATEMENT_ALIGNED, positions); | 1390 STATEMENT_ALIGNED, positions); |
| 1405 } | 1391 } |
| 1406 return true; | 1392 return true; |
| 1407 } | 1393 } |
| 1408 UNREACHABLE(); | 1394 UNREACHABLE(); |
| 1409 return false; | 1395 return false; |
| 1410 } | 1396 } |
| 1411 | 1397 |
| 1412 void Debug::RecordGenerator(Handle<JSGeneratorObject> generator_object) { | 1398 void Debug::RecordGenerator(Handle<JSGeneratorObject> generator_object) { |
| 1413 if (last_step_action() <= StepOut) return; | 1399 if (last_step_action() <= StepOut) return; |
| 1414 | 1400 |
| 1415 if (last_step_action() == StepNext) { | 1401 if (last_step_action() == StepNext) { |
| 1416 // Only consider this generator a step-next target if not stepping in. | 1402 // Only consider this generator a step-next target if not stepping in. |
| 1417 JavaScriptFrameIterator stack_iterator(isolate_); | 1403 if (thread_local_.target_frame_count_ < CurrentFrameCount()) return; |
| 1418 JavaScriptFrame* frame = stack_iterator.frame(); | |
| 1419 if (frame->UnpaddedFP() < thread_local_.target_fp_) return; | |
| 1420 } | 1404 } |
| 1421 | 1405 |
| 1422 DCHECK(!has_suspended_generator()); | 1406 DCHECK(!has_suspended_generator()); |
| 1423 thread_local_.suspended_generator_ = *generator_object; | 1407 thread_local_.suspended_generator_ = *generator_object; |
| 1424 ClearStepping(); | 1408 ClearStepping(); |
| 1425 } | 1409 } |
| 1426 | 1410 |
| 1427 class SharedFunctionInfoFinder { | 1411 class SharedFunctionInfoFinder { |
| 1428 public: | 1412 public: |
| 1429 explicit SharedFunctionInfoFinder(int target_position) | 1413 explicit SharedFunctionInfoFinder(int target_position) |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1517 HandleScope scope(isolate_); | 1501 HandleScope scope(isolate_); |
| 1518 // Code that cannot be compiled lazily are internal and not debuggable. | 1502 // Code that cannot be compiled lazily are internal and not debuggable. |
| 1519 DCHECK(shared->allows_lazy_compilation()); | 1503 DCHECK(shared->allows_lazy_compilation()); |
| 1520 if (!Compiler::CompileDebugCode(handle(shared))) break; | 1504 if (!Compiler::CompileDebugCode(handle(shared))) break; |
| 1521 } | 1505 } |
| 1522 return isolate_->factory()->undefined_value(); | 1506 return isolate_->factory()->undefined_value(); |
| 1523 } | 1507 } |
| 1524 | 1508 |
| 1525 | 1509 |
| 1526 // Ensures the debug information is present for shared. | 1510 // Ensures the debug information is present for shared. |
| 1527 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared, | 1511 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) { |
| 1528 Handle<JSFunction> function) { | |
| 1529 if (!shared->IsSubjectToDebugging()) return false; | |
| 1530 | |
| 1531 // Return if we already have the debug info for shared. | 1512 // Return if we already have the debug info for shared. |
| 1532 if (shared->HasDebugInfo()) return true; | 1513 if (shared->HasDebugInfo()) return true; |
| 1533 | 1514 if (!shared->IsSubjectToDebugging()) return false; |
| 1534 if (function.is_null()) { | 1515 if (!shared->is_compiled() && !Compiler::CompileDebugCode(shared)) { |
| 1535 DCHECK(shared->HasDebugCode()); | |
| 1536 } else if (!Compiler::Compile(function, Compiler::CLEAR_EXCEPTION)) { | |
| 1537 return false; | 1516 return false; |
| 1538 } | 1517 } |
| 1539 | 1518 |
| 1540 // To prepare bytecode for debugging, we already need to have the debug | 1519 // To prepare bytecode for debugging, we already need to have the debug |
| 1541 // info (containing the debug copy) upfront, but since we do not recompile, | 1520 // info (containing the debug copy) upfront, but since we do not recompile, |
| 1542 // preparing for break points cannot fail. | 1521 // preparing for break points cannot fail. |
| 1543 CreateDebugInfo(shared); | 1522 CreateDebugInfo(shared); |
| 1544 CHECK(PrepareFunctionForBreakPoints(shared)); | 1523 CHECK(PrepareFunctionForBreakPoints(shared)); |
| 1545 return true; | 1524 return true; |
| 1546 } | 1525 } |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1692 Handle<Smi> id) { | 1671 Handle<Smi> id) { |
| 1693 DCHECK(id->IsNumber()); | 1672 DCHECK(id->IsNumber()); |
| 1694 // Create the async task event object. | 1673 // Create the async task event object. |
| 1695 Handle<Object> argv[] = {type, id}; | 1674 Handle<Object> argv[] = {type, id}; |
| 1696 return CallFunction("MakeAsyncTaskEvent", arraysize(argv), argv); | 1675 return CallFunction("MakeAsyncTaskEvent", arraysize(argv), argv); |
| 1697 } | 1676 } |
| 1698 | 1677 |
| 1699 | 1678 |
| 1700 void Debug::OnThrow(Handle<Object> exception) { | 1679 void Debug::OnThrow(Handle<Object> exception) { |
| 1701 if (in_debug_scope() || ignore_events()) return; | 1680 if (in_debug_scope() || ignore_events()) return; |
| 1702 PrepareStepOnThrow(); | |
| 1703 // Temporarily clear any scheduled_exception to allow evaluating | 1681 // Temporarily clear any scheduled_exception to allow evaluating |
| 1704 // JavaScript from the debug event handler. | 1682 // JavaScript from the debug event handler. |
| 1705 HandleScope scope(isolate_); | 1683 HandleScope scope(isolate_); |
| 1706 Handle<Object> scheduled_exception; | 1684 Handle<Object> scheduled_exception; |
| 1707 if (isolate_->has_scheduled_exception()) { | 1685 if (isolate_->has_scheduled_exception()) { |
| 1708 scheduled_exception = handle(isolate_->scheduled_exception(), isolate_); | 1686 scheduled_exception = handle(isolate_->scheduled_exception(), isolate_); |
| 1709 isolate_->clear_scheduled_exception(); | 1687 isolate_->clear_scheduled_exception(); |
| 1710 } | 1688 } |
| 1711 OnException(exception, isolate_->GetPromiseOnStackOnThrow()); | 1689 OnException(exception, isolate_->GetPromiseOnStackOnThrow()); |
| 1712 if (!scheduled_exception.is_null()) { | 1690 if (!scheduled_exception.is_null()) { |
| 1713 isolate_->thread_local_top()->scheduled_exception_ = *scheduled_exception; | 1691 isolate_->thread_local_top()->scheduled_exception_ = *scheduled_exception; |
| 1714 } | 1692 } |
| 1693 PrepareStepOnThrow(); | |
| 1715 } | 1694 } |
| 1716 | 1695 |
| 1717 void Debug::OnPromiseReject(Handle<Object> promise, Handle<Object> value) { | 1696 void Debug::OnPromiseReject(Handle<Object> promise, Handle<Object> value) { |
| 1718 if (in_debug_scope() || ignore_events()) return; | 1697 if (in_debug_scope() || ignore_events()) return; |
| 1719 HandleScope scope(isolate_); | 1698 HandleScope scope(isolate_); |
| 1720 // Check whether the promise has been marked as having triggered a message. | 1699 // Check whether the promise has been marked as having triggered a message. |
| 1721 Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol(); | 1700 Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol(); |
| 1722 if (!promise->IsJSObject() || | 1701 if (!promise->IsJSObject() || |
| 1723 JSReceiver::GetDataProperty(Handle<JSObject>::cast(promise), key) | 1702 JSReceiver::GetDataProperty(Handle<JSObject>::cast(promise), key) |
| 1724 ->IsUndefined(isolate_)) { | 1703 ->IsUndefined(isolate_)) { |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 1748 while (!it.done()) { | 1727 while (!it.done()) { |
| 1749 if (!IsFrameBlackboxed(it.frame())) return false; | 1728 if (!IsFrameBlackboxed(it.frame())) return false; |
| 1750 it.Advance(); | 1729 it.Advance(); |
| 1751 } | 1730 } |
| 1752 return true; | 1731 return true; |
| 1753 } | 1732 } |
| 1754 | 1733 |
| 1755 bool Debug::IsFrameBlackboxed(JavaScriptFrame* frame) { | 1734 bool Debug::IsFrameBlackboxed(JavaScriptFrame* frame) { |
| 1756 HandleScope scope(isolate_); | 1735 HandleScope scope(isolate_); |
| 1757 if (!frame->HasInlinedFrames()) { | 1736 if (!frame->HasInlinedFrames()) { |
| 1758 return IsBlackboxed(frame->function()->shared()); | 1737 Handle<SharedFunctionInfo> shared(frame->function()->shared(), isolate_); |
| 1738 return IsBlackboxed(shared); | |
| 1759 } | 1739 } |
| 1760 List<SharedFunctionInfo*> raw_shareds; | 1740 List<Handle<SharedFunctionInfo>> infos; |
| 1761 frame->GetFunctions(&raw_shareds); | 1741 frame->GetFunctions(&infos); |
| 1762 List<Handle<SharedFunctionInfo>> shareds; | 1742 for (const auto& info : infos) |
| 1763 for (int i = 0; i < raw_shareds.length(); ++i) { | 1743 if (!IsBlackboxed(info)) return false; |
| 1764 shareds.Add(handle(raw_shareds[i])); | |
| 1765 } | |
| 1766 for (int i = 0; i < shareds.length(); ++i) { | |
| 1767 if (!IsBlackboxed(shareds[i])) return false; | |
| 1768 } | |
| 1769 return true; | 1744 return true; |
| 1770 } | 1745 } |
| 1771 | 1746 |
| 1772 void Debug::OnException(Handle<Object> exception, Handle<Object> promise) { | 1747 void Debug::OnException(Handle<Object> exception, Handle<Object> promise) { |
| 1773 // We cannot generate debug events when JS execution is disallowed. | 1748 // We cannot generate debug events when JS execution is disallowed. |
| 1774 // TODO(5530): Reenable debug events within DisallowJSScopes once relevant | 1749 // TODO(5530): Reenable debug events within DisallowJSScopes once relevant |
| 1775 // code (MakeExceptionEvent and ProcessDebugEvent) have been moved to C++. | 1750 // code (MakeExceptionEvent and ProcessDebugEvent) have been moved to C++. |
| 1776 if (!AllowJavascriptExecution::IsAllowed(isolate_)) return; | 1751 if (!AllowJavascriptExecution::IsAllowed(isolate_)) return; |
| 1777 | 1752 |
| 1778 Isolate::CatchType catch_type = isolate_->PredictExceptionCatcher(); | 1753 Isolate::CatchType catch_type = isolate_->PredictExceptionCatcher(); |
| (...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1999 } | 1974 } |
| 2000 | 1975 |
| 2001 namespace { | 1976 namespace { |
| 2002 debug::Location GetDebugLocation(Handle<Script> script, int source_position) { | 1977 debug::Location GetDebugLocation(Handle<Script> script, int source_position) { |
| 2003 Script::PositionInfo info; | 1978 Script::PositionInfo info; |
| 2004 Script::GetPositionInfo(script, source_position, &info, Script::WITH_OFFSET); | 1979 Script::GetPositionInfo(script, source_position, &info, Script::WITH_OFFSET); |
| 2005 return debug::Location(info.line, info.column); | 1980 return debug::Location(info.line, info.column); |
| 2006 } | 1981 } |
| 2007 } // namespace | 1982 } // namespace |
| 2008 | 1983 |
| 2009 bool Debug::IsBlackboxed(SharedFunctionInfo* shared) { | |
| 2010 HandleScope scope(isolate_); | |
| 2011 Handle<SharedFunctionInfo> shared_function_info(shared); | |
| 2012 return IsBlackboxed(shared_function_info); | |
| 2013 } | |
| 2014 | |
| 2015 bool Debug::IsBlackboxed(Handle<SharedFunctionInfo> shared) { | 1984 bool Debug::IsBlackboxed(Handle<SharedFunctionInfo> shared) { |
| 2016 if (!debug_delegate_) return false; | 1985 if (!debug_delegate_) return false; |
| 2017 if (!shared->computed_debug_is_blackboxed()) { | 1986 if (!shared->computed_debug_is_blackboxed()) { |
| 2018 bool is_blackboxed = false; | 1987 bool is_blackboxed = false; |
| 2019 if (shared->script()->IsScript()) { | 1988 if (shared->script()->IsScript()) { |
| 2020 HandleScope handle_scope(isolate_); | 1989 HandleScope handle_scope(isolate_); |
| 2021 Handle<Script> script(Script::cast(shared->script())); | 1990 Handle<Script> script(Script::cast(shared->script())); |
| 2022 if (script->type() == i::Script::TYPE_NORMAL) { | 1991 if (script->type() == i::Script::TYPE_NORMAL) { |
| 2023 debug::Location start = | 1992 debug::Location start = |
| 2024 GetDebugLocation(script, shared->start_position()); | 1993 GetDebugLocation(script, shared->start_position()); |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2148 // Set new entry. | 2117 // Set new entry. |
| 2149 if (!callback->IsNullOrUndefined(isolate_)) { | 2118 if (!callback->IsNullOrUndefined(isolate_)) { |
| 2150 event_listener_ = global_handles->Create(*callback); | 2119 event_listener_ = global_handles->Create(*callback); |
| 2151 if (data.is_null()) data = isolate_->factory()->undefined_value(); | 2120 if (data.is_null()) data = isolate_->factory()->undefined_value(); |
| 2152 event_listener_data_ = global_handles->Create(*data); | 2121 event_listener_data_ = global_handles->Create(*data); |
| 2153 } | 2122 } |
| 2154 | 2123 |
| 2155 UpdateState(); | 2124 UpdateState(); |
| 2156 } | 2125 } |
| 2157 | 2126 |
| 2127 int Debug::CurrentFrameCount() { | |
| 2128 StackTraceFrameIterator it(isolate_); | |
| 2129 if (break_frame_id() != StackFrame::NO_ID) { | |
| 2130 // Skip to break frame. | |
| 2131 DCHECK(in_debug_scope()); | |
| 2132 while (!it.done() && it.frame()->id() != break_frame_id()) it.Advance(); | |
| 2133 } | |
| 2134 int counter = 0; | |
| 2135 while (!it.done()) { | |
| 2136 if (it.frame()->is_optimized()) { | |
| 2137 List<SharedFunctionInfo*> infos; | |
| 2138 OptimizedFrame::cast(it.frame())->GetFunctions(&infos); | |
| 2139 counter += infos.length(); | |
| 2140 } else { | |
| 2141 counter++; | |
| 2142 } | |
| 2143 it.Advance(); | |
| 2144 } | |
| 2145 return counter; | |
| 2146 } | |
| 2147 | |
| 2158 void Debug::SetDebugDelegate(debug::DebugDelegate* delegate) { | 2148 void Debug::SetDebugDelegate(debug::DebugDelegate* delegate) { |
| 2159 debug_delegate_ = delegate; | 2149 debug_delegate_ = delegate; |
| 2160 UpdateState(); | 2150 UpdateState(); |
| 2161 } | 2151 } |
| 2162 | 2152 |
| 2163 void Debug::UpdateState() { | 2153 void Debug::UpdateState() { |
| 2164 bool is_active = !event_listener_.is_null() || debug_delegate_ != nullptr; | 2154 bool is_active = !event_listener_.is_null() || debug_delegate_ != nullptr; |
| 2165 if (is_active || in_debug_scope()) { | 2155 if (is_active || in_debug_scope()) { |
| 2166 // Note that the debug context could have already been loaded to | 2156 // Note that the debug context could have already been loaded to |
| 2167 // bootstrap test cases. | 2157 // bootstrap test cases. |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2209 // Ignore debug break if debugger is not active. | 2199 // Ignore debug break if debugger is not active. |
| 2210 if (!is_active()) return; | 2200 if (!is_active()) return; |
| 2211 | 2201 |
| 2212 StackLimitCheck check(isolate_); | 2202 StackLimitCheck check(isolate_); |
| 2213 if (check.HasOverflowed()) return; | 2203 if (check.HasOverflowed()) return; |
| 2214 | 2204 |
| 2215 { JavaScriptFrameIterator it(isolate_); | 2205 { JavaScriptFrameIterator it(isolate_); |
| 2216 DCHECK(!it.done()); | 2206 DCHECK(!it.done()); |
| 2217 Object* fun = it.frame()->function(); | 2207 Object* fun = it.frame()->function(); |
| 2218 if (fun && fun->IsJSFunction()) { | 2208 if (fun && fun->IsJSFunction()) { |
| 2209 HandleScope scope(isolate_); | |
| 2219 // Don't stop in builtin and blackboxed functions. | 2210 // Don't stop in builtin and blackboxed functions. |
| 2220 if (!JSFunction::cast(fun)->shared()->IsSubjectToDebugging() || | 2211 Handle<SharedFunctionInfo> shared(JSFunction::cast(fun)->shared(), |
| 2221 IsBlackboxed(JSFunction::cast(fun)->shared())) { | 2212 isolate_); |
| 2213 if (!shared->IsSubjectToDebugging() || IsBlackboxed(shared)) { | |
| 2222 // Inspector uses pause on next statement for asynchronous breakpoints. | 2214 // Inspector uses pause on next statement for asynchronous breakpoints. |
| 2223 // When breakpoint is fired we try to break on first not blackboxed | 2215 // When breakpoint is fired we try to break on first not blackboxed |
| 2224 // statement. To achieve this goal we need to deoptimize current | 2216 // statement. To achieve this goal we need to deoptimize current |
| 2225 // function and don't clear requested DebugBreak even if it's blackboxed | 2217 // function and don't clear requested DebugBreak even if it's blackboxed |
| 2226 // to be able to break on not blackboxed function call. | 2218 // to be able to break on not blackboxed function call. |
| 2227 // TODO(yangguo): introduce break_on_function_entry since current | 2219 // TODO(yangguo): introduce break_on_function_entry since current |
| 2228 // implementation is slow. | 2220 // implementation is slow. |
| 2229 Deoptimizer::DeoptimizeFunction(JSFunction::cast(fun)); | 2221 Deoptimizer::DeoptimizeFunction(JSFunction::cast(fun)); |
| 2230 return; | 2222 return; |
| 2231 } | 2223 } |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2419 return v8::Utils::ToLocal(callback_data_); | 2411 return v8::Utils::ToLocal(callback_data_); |
| 2420 } | 2412 } |
| 2421 | 2413 |
| 2422 | 2414 |
| 2423 v8::Isolate* EventDetailsImpl::GetIsolate() const { | 2415 v8::Isolate* EventDetailsImpl::GetIsolate() const { |
| 2424 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate()); | 2416 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate()); |
| 2425 } | 2417 } |
| 2426 | 2418 |
| 2427 } // namespace internal | 2419 } // namespace internal |
| 2428 } // namespace v8 | 2420 } // namespace v8 |
| OLD | NEW |