| 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 "v8.h" | 5 #include "v8.h" |
| 6 | 6 |
| 7 #include "api.h" | 7 #include "api.h" |
| 8 #include "arguments.h" | 8 #include "arguments.h" |
| 9 #include "bootstrapper.h" | 9 #include "bootstrapper.h" |
| 10 #include "code-stubs.h" | 10 #include "code-stubs.h" |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 #include "natives.h" | 24 #include "natives.h" |
| 25 #include "stub-cache.h" | 25 #include "stub-cache.h" |
| 26 #include "log.h" | 26 #include "log.h" |
| 27 | 27 |
| 28 #include "../include/v8-debug.h" | 28 #include "../include/v8-debug.h" |
| 29 | 29 |
| 30 namespace v8 { | 30 namespace v8 { |
| 31 namespace internal { | 31 namespace internal { |
| 32 | 32 |
| 33 Debug::Debug(Isolate* isolate) | 33 Debug::Debug(Isolate* isolate) |
| 34 : has_break_points_(false), | 34 : debug_context_(Handle<Context>()), |
| 35 event_listener_(Handle<Object>()), |
| 36 event_listener_data_(Handle<Object>()), |
| 37 message_handler_(NULL), |
| 38 command_received_(0), |
| 39 command_queue_(isolate->logger(), kQueueInitialSize), |
| 40 event_command_queue_(isolate->logger(), kQueueInitialSize), |
| 41 is_active_(false), |
| 42 is_suppressed_(false), |
| 43 live_edit_enabled_(true), // TODO(yangguo): set to false by default. |
| 44 has_break_points_(false), |
| 45 break_disabled_(false), |
| 46 break_on_exception_(false), |
| 47 break_on_uncaught_exception_(false), |
| 35 script_cache_(NULL), | 48 script_cache_(NULL), |
| 36 debug_info_list_(NULL), | 49 debug_info_list_(NULL), |
| 37 disable_break_(false), | |
| 38 break_on_exception_(false), | |
| 39 break_on_uncaught_exception_(false), | |
| 40 isolate_(isolate) { | 50 isolate_(isolate) { |
| 41 ThreadInit(); | 51 ThreadInit(); |
| 42 } | 52 } |
| 43 | 53 |
| 44 | 54 |
| 45 static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) { | 55 static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) { |
| 46 Handle<Context> context = isolate->debug()->debugger_entry()->GetContext(); | 56 Handle<Context> context = isolate->debug()->debugger_entry()->GetContext(); |
| 47 // Isolate::context() may have been NULL when "script collected" event | 57 // Isolate::context() may have been NULL when "script collected" event |
| 48 // occured. | 58 // occured. |
| 49 if (context.is_null()) return v8::Local<v8::Context>(); | 59 if (context.is_null()) return v8::Local<v8::Context>(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 63 | 73 |
| 64 | 74 |
| 65 BreakLocationIterator::~BreakLocationIterator() { | 75 BreakLocationIterator::~BreakLocationIterator() { |
| 66 ASSERT(reloc_iterator_ != NULL); | 76 ASSERT(reloc_iterator_ != NULL); |
| 67 ASSERT(reloc_iterator_original_ != NULL); | 77 ASSERT(reloc_iterator_original_ != NULL); |
| 68 delete reloc_iterator_; | 78 delete reloc_iterator_; |
| 69 delete reloc_iterator_original_; | 79 delete reloc_iterator_original_; |
| 70 } | 80 } |
| 71 | 81 |
| 72 | 82 |
| 83 // Check whether a code stub with the specified major key is a possible break |
| 84 // point location when looking for source break locations. |
| 85 static bool IsSourceBreakStub(Code* code) { |
| 86 CodeStub::Major major_key = CodeStub::GetMajorKey(code); |
| 87 return major_key == CodeStub::CallFunction; |
| 88 } |
| 89 |
| 90 |
| 91 // Check whether a code stub with the specified major key is a possible break |
| 92 // location. |
| 93 static bool IsBreakStub(Code* code) { |
| 94 CodeStub::Major major_key = CodeStub::GetMajorKey(code); |
| 95 return major_key == CodeStub::CallFunction; |
| 96 } |
| 97 |
| 98 |
| 73 void BreakLocationIterator::Next() { | 99 void BreakLocationIterator::Next() { |
| 74 DisallowHeapAllocation no_gc; | 100 DisallowHeapAllocation no_gc; |
| 75 ASSERT(!RinfoDone()); | 101 ASSERT(!RinfoDone()); |
| 76 | 102 |
| 77 // Iterate through reloc info for code and original code stopping at each | 103 // Iterate through reloc info for code and original code stopping at each |
| 78 // breakable code target. | 104 // breakable code target. |
| 79 bool first = break_point_ == -1; | 105 bool first = break_point_ == -1; |
| 80 while (!RinfoDone()) { | 106 while (!RinfoDone()) { |
| 81 if (!first) RinfoNext(); | 107 if (!first) RinfoNext(); |
| 82 first = false; | 108 first = false; |
| (...skipping 29 matching lines...) Expand all Loading... |
| 112 !code->is_compare_ic_stub() && | 138 !code->is_compare_ic_stub() && |
| 113 !code->is_to_boolean_ic_stub()) || | 139 !code->is_to_boolean_ic_stub()) || |
| 114 RelocInfo::IsConstructCall(rmode())) { | 140 RelocInfo::IsConstructCall(rmode())) { |
| 115 break_point_++; | 141 break_point_++; |
| 116 return; | 142 return; |
| 117 } | 143 } |
| 118 if (code->kind() == Code::STUB) { | 144 if (code->kind() == Code::STUB) { |
| 119 if (IsDebuggerStatement()) { | 145 if (IsDebuggerStatement()) { |
| 120 break_point_++; | 146 break_point_++; |
| 121 return; | 147 return; |
| 122 } | 148 } else if (type_ == ALL_BREAK_LOCATIONS) { |
| 123 if (type_ == ALL_BREAK_LOCATIONS) { | 149 if (IsBreakStub(code)) { |
| 124 if (Debug::IsBreakStub(code)) { | |
| 125 break_point_++; | 150 break_point_++; |
| 126 return; | 151 return; |
| 127 } | 152 } |
| 128 } else { | 153 } else { |
| 129 ASSERT(type_ == SOURCE_BREAK_LOCATIONS); | 154 ASSERT(type_ == SOURCE_BREAK_LOCATIONS); |
| 130 if (Debug::IsSourceBreakStub(code)) { | 155 if (IsSourceBreakStub(code)) { |
| 131 break_point_++; | 156 break_point_++; |
| 132 return; | 157 return; |
| 133 } | 158 } |
| 134 } | 159 } |
| 135 } | 160 } |
| 136 } | 161 } |
| 137 | 162 |
| 138 // Check for break at return. | 163 // Check for break at return. |
| 139 if (RelocInfo::IsJSReturn(rmode())) { | 164 if (RelocInfo::IsJSReturn(rmode())) { |
| 140 // Set the positions to the end of the function. | 165 // Set the positions to the end of the function. |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 | 265 |
| 241 | 266 |
| 242 bool BreakLocationIterator::Done() const { | 267 bool BreakLocationIterator::Done() const { |
| 243 return RinfoDone(); | 268 return RinfoDone(); |
| 244 } | 269 } |
| 245 | 270 |
| 246 | 271 |
| 247 void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) { | 272 void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) { |
| 248 // If there is not already a real break point here patch code with debug | 273 // If there is not already a real break point here patch code with debug |
| 249 // break. | 274 // break. |
| 250 if (!HasBreakPoint()) { | 275 if (!HasBreakPoint()) SetDebugBreak(); |
| 251 SetDebugBreak(); | |
| 252 } | |
| 253 ASSERT(IsDebugBreak() || IsDebuggerStatement()); | 276 ASSERT(IsDebugBreak() || IsDebuggerStatement()); |
| 254 // Set the break point information. | 277 // Set the break point information. |
| 255 DebugInfo::SetBreakPoint(debug_info_, code_position(), | 278 DebugInfo::SetBreakPoint(debug_info_, code_position(), |
| 256 position(), statement_position(), | 279 position(), statement_position(), |
| 257 break_point_object); | 280 break_point_object); |
| 258 } | 281 } |
| 259 | 282 |
| 260 | 283 |
| 261 void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) { | 284 void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) { |
| 262 // Clear the break point information. | 285 // Clear the break point information. |
| 263 DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object); | 286 DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object); |
| 264 // If there are no more break points here remove the debug break. | 287 // If there are no more break points here remove the debug break. |
| 265 if (!HasBreakPoint()) { | 288 if (!HasBreakPoint()) { |
| 266 ClearDebugBreak(); | 289 ClearDebugBreak(); |
| 267 ASSERT(!IsDebugBreak()); | 290 ASSERT(!IsDebugBreak()); |
| 268 } | 291 } |
| 269 } | 292 } |
| 270 | 293 |
| 271 | 294 |
| 272 void BreakLocationIterator::SetOneShot() { | 295 void BreakLocationIterator::SetOneShot() { |
| 273 // Debugger statement always calls debugger. No need to modify it. | 296 // Debugger statement always calls debugger. No need to modify it. |
| 274 if (IsDebuggerStatement()) { | 297 if (IsDebuggerStatement()) return; |
| 275 return; | |
| 276 } | |
| 277 | 298 |
| 278 // If there is a real break point here no more to do. | 299 // If there is a real break point here no more to do. |
| 279 if (HasBreakPoint()) { | 300 if (HasBreakPoint()) { |
| 280 ASSERT(IsDebugBreak()); | 301 ASSERT(IsDebugBreak()); |
| 281 return; | 302 return; |
| 282 } | 303 } |
| 283 | 304 |
| 284 // Patch code with debug break. | 305 // Patch code with debug break. |
| 285 SetDebugBreak(); | 306 SetDebugBreak(); |
| 286 } | 307 } |
| 287 | 308 |
| 288 | 309 |
| 289 void BreakLocationIterator::ClearOneShot() { | 310 void BreakLocationIterator::ClearOneShot() { |
| 290 // Debugger statement always calls debugger. No need to modify it. | 311 // Debugger statement always calls debugger. No need to modify it. |
| 291 if (IsDebuggerStatement()) { | 312 if (IsDebuggerStatement()) return; |
| 292 return; | |
| 293 } | |
| 294 | 313 |
| 295 // If there is a real break point here no more to do. | 314 // If there is a real break point here no more to do. |
| 296 if (HasBreakPoint()) { | 315 if (HasBreakPoint()) { |
| 297 ASSERT(IsDebugBreak()); | 316 ASSERT(IsDebugBreak()); |
| 298 return; | 317 return; |
| 299 } | 318 } |
| 300 | 319 |
| 301 // Patch code removing debug break. | 320 // Patch code removing debug break. |
| 302 ClearDebugBreak(); | 321 ClearDebugBreak(); |
| 303 ASSERT(!IsDebugBreak()); | 322 ASSERT(!IsDebugBreak()); |
| 304 } | 323 } |
| 305 | 324 |
| 306 | 325 |
| 307 void BreakLocationIterator::SetDebugBreak() { | 326 void BreakLocationIterator::SetDebugBreak() { |
| 308 // Debugger statement always calls debugger. No need to modify it. | 327 // Debugger statement always calls debugger. No need to modify it. |
| 309 if (IsDebuggerStatement()) { | 328 if (IsDebuggerStatement()) return; |
| 310 return; | |
| 311 } | |
| 312 | 329 |
| 313 // If there is already a break point here just return. This might happen if | 330 // If there is already a break point here just return. This might happen if |
| 314 // the same code is flooded with break points twice. Flooding the same | 331 // the same code is flooded with break points twice. Flooding the same |
| 315 // function twice might happen when stepping in a function with an exception | 332 // function twice might happen when stepping in a function with an exception |
| 316 // handler as the handler and the function is the same. | 333 // handler as the handler and the function is the same. |
| 317 if (IsDebugBreak()) { | 334 if (IsDebugBreak()) return; |
| 318 return; | |
| 319 } | |
| 320 | 335 |
| 321 if (RelocInfo::IsJSReturn(rmode())) { | 336 if (RelocInfo::IsJSReturn(rmode())) { |
| 322 // Patch the frame exit code with a break point. | 337 // Patch the frame exit code with a break point. |
| 323 SetDebugBreakAtReturn(); | 338 SetDebugBreakAtReturn(); |
| 324 } else if (IsDebugBreakSlot()) { | 339 } else if (IsDebugBreakSlot()) { |
| 325 // Patch the code in the break slot. | 340 // Patch the code in the break slot. |
| 326 SetDebugBreakAtSlot(); | 341 SetDebugBreakAtSlot(); |
| 327 } else { | 342 } else { |
| 328 // Patch the IC call. | 343 // Patch the IC call. |
| 329 SetDebugBreakAtIC(); | 344 SetDebugBreakAtIC(); |
| 330 } | 345 } |
| 331 ASSERT(IsDebugBreak()); | 346 ASSERT(IsDebugBreak()); |
| 332 } | 347 } |
| 333 | 348 |
| 334 | 349 |
| 335 void BreakLocationIterator::ClearDebugBreak() { | 350 void BreakLocationIterator::ClearDebugBreak() { |
| 336 // Debugger statement always calls debugger. No need to modify it. | 351 // Debugger statement always calls debugger. No need to modify it. |
| 337 if (IsDebuggerStatement()) { | 352 if (IsDebuggerStatement()) return; |
| 338 return; | |
| 339 } | |
| 340 | 353 |
| 341 if (RelocInfo::IsJSReturn(rmode())) { | 354 if (RelocInfo::IsJSReturn(rmode())) { |
| 342 // Restore the frame exit code. | 355 // Restore the frame exit code. |
| 343 ClearDebugBreakAtReturn(); | 356 ClearDebugBreakAtReturn(); |
| 344 } else if (IsDebugBreakSlot()) { | 357 } else if (IsDebugBreakSlot()) { |
| 345 // Restore the code in the break slot. | 358 // Restore the code in the break slot. |
| 346 ClearDebugBreakAtSlot(); | 359 ClearDebugBreakAtSlot(); |
| 347 } else { | 360 } else { |
| 348 // Patch the IC call. | 361 // Patch the IC call. |
| 349 ClearDebugBreakAtIC(); | 362 ClearDebugBreakAtIC(); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 417 if (RelocInfo::IsJSReturn(rmode())) { | 430 if (RelocInfo::IsJSReturn(rmode())) { |
| 418 return IsDebugBreakAtReturn(); | 431 return IsDebugBreakAtReturn(); |
| 419 } else if (IsDebugBreakSlot()) { | 432 } else if (IsDebugBreakSlot()) { |
| 420 return IsDebugBreakAtSlot(); | 433 return IsDebugBreakAtSlot(); |
| 421 } else { | 434 } else { |
| 422 return Debug::IsDebugBreak(rinfo()->target_address()); | 435 return Debug::IsDebugBreak(rinfo()->target_address()); |
| 423 } | 436 } |
| 424 } | 437 } |
| 425 | 438 |
| 426 | 439 |
| 440 // Find the builtin to use for invoking the debug break |
| 441 static Handle<Code> DebugBreakForIC(Handle<Code> code, RelocInfo::Mode mode) { |
| 442 Isolate* isolate = code->GetIsolate(); |
| 443 |
| 444 // Find the builtin debug break function matching the calling convention |
| 445 // used by the call site. |
| 446 if (code->is_inline_cache_stub()) { |
| 447 switch (code->kind()) { |
| 448 case Code::CALL_IC: |
| 449 return isolate->builtins()->CallICStub_DebugBreak(); |
| 450 |
| 451 case Code::LOAD_IC: |
| 452 return isolate->builtins()->LoadIC_DebugBreak(); |
| 453 |
| 454 case Code::STORE_IC: |
| 455 return isolate->builtins()->StoreIC_DebugBreak(); |
| 456 |
| 457 case Code::KEYED_LOAD_IC: |
| 458 return isolate->builtins()->KeyedLoadIC_DebugBreak(); |
| 459 |
| 460 case Code::KEYED_STORE_IC: |
| 461 return isolate->builtins()->KeyedStoreIC_DebugBreak(); |
| 462 |
| 463 case Code::COMPARE_NIL_IC: |
| 464 return isolate->builtins()->CompareNilIC_DebugBreak(); |
| 465 |
| 466 default: |
| 467 UNREACHABLE(); |
| 468 } |
| 469 } |
| 470 if (RelocInfo::IsConstructCall(mode)) { |
| 471 if (code->has_function_cache()) { |
| 472 return isolate->builtins()->CallConstructStub_Recording_DebugBreak(); |
| 473 } else { |
| 474 return isolate->builtins()->CallConstructStub_DebugBreak(); |
| 475 } |
| 476 } |
| 477 if (code->kind() == Code::STUB) { |
| 478 ASSERT(code->major_key() == CodeStub::CallFunction); |
| 479 return isolate->builtins()->CallFunctionStub_DebugBreak(); |
| 480 } |
| 481 |
| 482 UNREACHABLE(); |
| 483 return Handle<Code>::null(); |
| 484 } |
| 485 |
| 486 |
| 427 void BreakLocationIterator::SetDebugBreakAtIC() { | 487 void BreakLocationIterator::SetDebugBreakAtIC() { |
| 428 // Patch the original code with the current address as the current address | 488 // Patch the original code with the current address as the current address |
| 429 // might have changed by the inline caching since the code was copied. | 489 // might have changed by the inline caching since the code was copied. |
| 430 original_rinfo()->set_target_address(rinfo()->target_address()); | 490 original_rinfo()->set_target_address(rinfo()->target_address()); |
| 431 | 491 |
| 432 RelocInfo::Mode mode = rmode(); | 492 RelocInfo::Mode mode = rmode(); |
| 433 if (RelocInfo::IsCodeTarget(mode)) { | 493 if (RelocInfo::IsCodeTarget(mode)) { |
| 434 Address target = rinfo()->target_address(); | 494 Address target = rinfo()->target_address(); |
| 435 Handle<Code> target_code(Code::GetCodeFromTargetAddress(target)); | 495 Handle<Code> target_code(Code::GetCodeFromTargetAddress(target)); |
| 436 | 496 |
| 437 // Patch the code to invoke the builtin debug break function matching the | 497 // Patch the code to invoke the builtin debug break function matching the |
| 438 // calling convention used by the call site. | 498 // calling convention used by the call site. |
| 439 Handle<Code> dbgbrk_code(Debug::FindDebugBreak(target_code, mode)); | 499 Handle<Code> dbgbrk_code = DebugBreakForIC(target_code, mode); |
| 440 rinfo()->set_target_address(dbgbrk_code->entry()); | 500 rinfo()->set_target_address(dbgbrk_code->entry()); |
| 441 } | 501 } |
| 442 } | 502 } |
| 443 | 503 |
| 444 | 504 |
| 445 void BreakLocationIterator::ClearDebugBreakAtIC() { | 505 void BreakLocationIterator::ClearDebugBreakAtIC() { |
| 446 // Patch the code to the original invoke. | 506 // Patch the code to the original invoke. |
| 447 rinfo()->set_target_address(original_rinfo()->target_address()); | 507 rinfo()->set_target_address(original_rinfo()->target_address()); |
| 448 } | 508 } |
| 449 | 509 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 497 thread_local_.break_count_ = 0; | 557 thread_local_.break_count_ = 0; |
| 498 thread_local_.break_id_ = 0; | 558 thread_local_.break_id_ = 0; |
| 499 thread_local_.break_frame_id_ = StackFrame::NO_ID; | 559 thread_local_.break_frame_id_ = StackFrame::NO_ID; |
| 500 thread_local_.last_step_action_ = StepNone; | 560 thread_local_.last_step_action_ = StepNone; |
| 501 thread_local_.last_statement_position_ = RelocInfo::kNoPosition; | 561 thread_local_.last_statement_position_ = RelocInfo::kNoPosition; |
| 502 thread_local_.step_count_ = 0; | 562 thread_local_.step_count_ = 0; |
| 503 thread_local_.last_fp_ = 0; | 563 thread_local_.last_fp_ = 0; |
| 504 thread_local_.queued_step_count_ = 0; | 564 thread_local_.queued_step_count_ = 0; |
| 505 thread_local_.step_into_fp_ = 0; | 565 thread_local_.step_into_fp_ = 0; |
| 506 thread_local_.step_out_fp_ = 0; | 566 thread_local_.step_out_fp_ = 0; |
| 507 thread_local_.after_break_target_ = 0; | |
| 508 // TODO(isolates): frames_are_dropped_? | 567 // TODO(isolates): frames_are_dropped_? |
| 509 thread_local_.debugger_entry_ = NULL; | 568 thread_local_.current_debug_scope_ = NULL; |
| 510 thread_local_.has_pending_interrupt_ = false; | |
| 511 thread_local_.restarter_frame_function_pointer_ = NULL; | 569 thread_local_.restarter_frame_function_pointer_ = NULL; |
| 512 thread_local_.promise_on_stack_ = NULL; | 570 thread_local_.promise_on_stack_ = NULL; |
| 513 } | 571 } |
| 514 | 572 |
| 515 | 573 |
| 516 char* Debug::ArchiveDebug(char* storage) { | 574 char* Debug::ArchiveDebug(char* storage) { |
| 517 char* to = storage; | 575 char* to = storage; |
| 518 OS::MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal)); | 576 OS::MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal)); |
| 519 ThreadInit(); | 577 ThreadInit(); |
| 520 return storage + ArchiveSpacePerThread(); | 578 return storage + ArchiveSpacePerThread(); |
| 521 } | 579 } |
| 522 | 580 |
| 523 | 581 |
| 524 char* Debug::RestoreDebug(char* storage) { | 582 char* Debug::RestoreDebug(char* storage) { |
| 525 char* from = storage; | 583 char* from = storage; |
| 526 OS::MemCopy( | 584 OS::MemCopy( |
| 527 reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal)); | 585 reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal)); |
| 528 return storage + ArchiveSpacePerThread(); | 586 return storage + ArchiveSpacePerThread(); |
| 529 } | 587 } |
| 530 | 588 |
| 531 | 589 |
| 532 int Debug::ArchiveSpacePerThread() { | 590 int Debug::ArchiveSpacePerThread() { |
| 533 return sizeof(ThreadLocal); | 591 return sizeof(ThreadLocal); |
| 534 } | 592 } |
| 535 | 593 |
| 536 | 594 |
| 537 // Frame structure (conforms InternalFrame structure): | 595 ScriptCache::ScriptCache(Isolate* isolate) : HashMap(HashMap::PointersMatch), |
| 538 // -- code | 596 isolate_(isolate), |
| 539 // -- SMI maker | 597 collected_scripts_(10) { |
| 540 // -- function (slot is called "context") | 598 Heap* heap = isolate_->heap(); |
| 541 // -- frame base | 599 HandleScope scope(isolate_); |
| 542 Object** Debug::SetUpFrameDropperFrame(StackFrame* bottom_js_frame, | |
| 543 Handle<Code> code) { | |
| 544 ASSERT(bottom_js_frame->is_java_script()); | |
| 545 | 600 |
| 546 Address fp = bottom_js_frame->fp(); | 601 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets |
| 602 // rid of all the cached script wrappers and the second gets rid of the |
| 603 // scripts which are no longer referenced. The second also sweeps precisely, |
| 604 // which saves us doing yet another GC to make the heap iterable. |
| 605 heap->CollectAllGarbage(Heap::kNoGCFlags, "Debug::CreateScriptCache"); |
| 547 | 606 |
| 548 // Move function pointer into "context" slot. | 607 // Scan heap for Script objects. |
| 549 Memory::Object_at(fp + StandardFrameConstants::kContextOffset) = | 608 HeapIterator iterator(heap); |
| 550 Memory::Object_at(fp + JavaScriptFrameConstants::kFunctionOffset); | 609 DisallowHeapAllocation no_allocation; |
| 551 | 610 |
| 552 Memory::Object_at(fp + InternalFrameConstants::kCodeOffset) = *code; | 611 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { |
| 553 Memory::Object_at(fp + StandardFrameConstants::kMarkerOffset) = | 612 if (obj->IsScript() && Script::cast(obj)->HasValidSource()) { |
| 554 Smi::FromInt(StackFrame::INTERNAL); | 613 Add(Handle<Script>(Script::cast(obj))); |
| 555 | 614 } |
| 556 return reinterpret_cast<Object**>(&Memory::Object_at( | 615 } |
| 557 fp + StandardFrameConstants::kContextOffset)); | |
| 558 } | 616 } |
| 559 | 617 |
| 560 const int Debug::kFrameDropperFrameSize = 4; | |
| 561 | |
| 562 | 618 |
| 563 void ScriptCache::Add(Handle<Script> script) { | 619 void ScriptCache::Add(Handle<Script> script) { |
| 564 GlobalHandles* global_handles = isolate_->global_handles(); | 620 GlobalHandles* global_handles = isolate_->global_handles(); |
| 565 // Create an entry in the hash map for the script. | 621 // Create an entry in the hash map for the script. |
| 566 int id = script->id()->value(); | 622 int id = script->id()->value(); |
| 567 HashMap::Entry* entry = | 623 HashMap::Entry* entry = |
| 568 HashMap::Lookup(reinterpret_cast<void*>(id), Hash(id), true); | 624 HashMap::Lookup(reinterpret_cast<void*>(id), Hash(id), true); |
| 569 if (entry->value != NULL) { | 625 if (entry->value != NULL) { |
| 570 ASSERT(*script == *reinterpret_cast<Script**>(entry->value)); | 626 ASSERT(*script == *reinterpret_cast<Script**>(entry->value)); |
| 571 return; | 627 return; |
| (...skipping 18 matching lines...) Expand all Loading... |
| 590 if (entry->value != NULL) { | 646 if (entry->value != NULL) { |
| 591 instances->set(count, *reinterpret_cast<Script**>(entry->value)); | 647 instances->set(count, *reinterpret_cast<Script**>(entry->value)); |
| 592 count++; | 648 count++; |
| 593 } | 649 } |
| 594 } | 650 } |
| 595 return instances; | 651 return instances; |
| 596 } | 652 } |
| 597 | 653 |
| 598 | 654 |
| 599 void ScriptCache::ProcessCollectedScripts() { | 655 void ScriptCache::ProcessCollectedScripts() { |
| 600 Debugger* debugger = isolate_->debugger(); | 656 Debug* debug = isolate_->debug(); |
| 601 for (int i = 0; i < collected_scripts_.length(); i++) { | 657 for (int i = 0; i < collected_scripts_.length(); i++) { |
| 602 debugger->OnScriptCollected(collected_scripts_[i]); | 658 debug->OnScriptCollected(collected_scripts_[i]); |
| 603 } | 659 } |
| 604 collected_scripts_.Clear(); | 660 collected_scripts_.Clear(); |
| 605 } | 661 } |
| 606 | 662 |
| 607 | 663 |
| 608 void ScriptCache::Clear() { | 664 void ScriptCache::Clear() { |
| 609 // Iterate the script cache to get rid of all the weak handles. | 665 // Iterate the script cache to get rid of all the weak handles. |
| 610 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) { | 666 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) { |
| 611 ASSERT(entry != NULL); | 667 ASSERT(entry != NULL); |
| 612 Object** location = reinterpret_cast<Object**>(entry->value); | 668 Object** location = reinterpret_cast<Object**>(entry->value); |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 739 | 795 |
| 740 // Mark this script as native and return successfully. | 796 // Mark this script as native and return successfully. |
| 741 Handle<Script> script(Script::cast(function->shared()->script())); | 797 Handle<Script> script(Script::cast(function->shared()->script())); |
| 742 script->set_type(Smi::FromInt(Script::TYPE_NATIVE)); | 798 script->set_type(Smi::FromInt(Script::TYPE_NATIVE)); |
| 743 return true; | 799 return true; |
| 744 } | 800 } |
| 745 | 801 |
| 746 | 802 |
| 747 bool Debug::Load() { | 803 bool Debug::Load() { |
| 748 // Return if debugger is already loaded. | 804 // Return if debugger is already loaded. |
| 749 if (IsLoaded()) return true; | 805 if (is_loaded()) return true; |
| 750 | 806 |
| 751 // Bail out if we're already in the process of compiling the native | 807 // Bail out if we're already in the process of compiling the native |
| 752 // JavaScript source code for the debugger. | 808 // JavaScript source code for the debugger. |
| 753 if (isolate_->debugger()->ignore_debugger()) return false; | 809 if (is_suppressed_) return false; |
| 754 Debugger::IgnoreScope during_create(isolate_->debugger()); | 810 SuppressDebug while_loading(this); |
| 755 | 811 |
| 756 // Disable breakpoints and interrupts while compiling and running the | 812 // Disable breakpoints and interrupts while compiling and running the |
| 757 // debugger scripts including the context creation code. | 813 // debugger scripts including the context creation code. |
| 758 DisableBreak disable(isolate_, true); | 814 DisableBreak disable(this, true); |
| 759 PostponeInterruptsScope postpone(isolate_); | 815 PostponeInterruptsScope postpone(isolate_); |
| 760 | 816 |
| 761 // Create the debugger context. | 817 // Create the debugger context. |
| 762 HandleScope scope(isolate_); | 818 HandleScope scope(isolate_); |
| 763 ExtensionConfiguration no_extensions; | 819 ExtensionConfiguration no_extensions; |
| 764 Handle<Context> context = | 820 Handle<Context> context = |
| 765 isolate_->bootstrapper()->CreateEnvironment( | 821 isolate_->bootstrapper()->CreateEnvironment( |
| 766 Handle<Object>::null(), | 822 Handle<Object>::null(), |
| 767 v8::Handle<ObjectTemplate>(), | 823 v8::Handle<ObjectTemplate>(), |
| 768 &no_extensions); | 824 &no_extensions); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 799 if (caught_exception) return false; | 855 if (caught_exception) return false; |
| 800 | 856 |
| 801 debug_context_ = Handle<Context>::cast( | 857 debug_context_ = Handle<Context>::cast( |
| 802 isolate_->global_handles()->Create(*context)); | 858 isolate_->global_handles()->Create(*context)); |
| 803 return true; | 859 return true; |
| 804 } | 860 } |
| 805 | 861 |
| 806 | 862 |
| 807 void Debug::Unload() { | 863 void Debug::Unload() { |
| 808 // Return debugger is not loaded. | 864 // Return debugger is not loaded. |
| 809 if (!IsLoaded()) return; | 865 if (!is_loaded()) return; |
| 810 | 866 |
| 811 // Clear the script cache. | 867 // Clear the script cache. |
| 812 DestroyScriptCache(); | 868 if (script_cache_ != NULL) { |
| 869 delete script_cache_; |
| 870 script_cache_ = NULL; |
| 871 } |
| 813 | 872 |
| 814 // Clear debugger context global handle. | 873 // Clear debugger context global handle. |
| 815 GlobalHandles::Destroy(Handle<Object>::cast(debug_context_).location()); | 874 GlobalHandles::Destroy(Handle<Object>::cast(debug_context_).location()); |
| 816 debug_context_ = Handle<Context>(); | 875 debug_context_ = Handle<Context>(); |
| 817 } | 876 } |
| 818 | 877 |
| 819 | 878 |
| 820 Object* Debug::Break(Arguments args) { | 879 void Debug::Break(Arguments args, JavaScriptFrame* frame) { |
| 821 Heap* heap = isolate_->heap(); | 880 Heap* heap = isolate_->heap(); |
| 822 HandleScope scope(isolate_); | 881 HandleScope scope(isolate_); |
| 823 ASSERT(args.length() == 0); | 882 ASSERT(args.length() == 0); |
| 824 | 883 |
| 825 thread_local_.frame_drop_mode_ = FRAMES_UNTOUCHED; | 884 if (live_edit_enabled()) { |
| 826 | 885 thread_local_.frame_drop_mode_ = LiveEdit::FRAMES_UNTOUCHED; |
| 827 // Get the top-most JavaScript frame. | 886 } |
| 828 JavaScriptFrameIterator it(isolate_); | |
| 829 JavaScriptFrame* frame = it.frame(); | |
| 830 | 887 |
| 831 // Just continue if breaks are disabled or debugger cannot be loaded. | 888 // Just continue if breaks are disabled or debugger cannot be loaded. |
| 832 if (disable_break()) { | 889 if (break_disabled_) return; |
| 833 SetAfterBreakTarget(frame); | |
| 834 return heap->undefined_value(); | |
| 835 } | |
| 836 | 890 |
| 837 // Enter the debugger. | 891 // Enter the debugger. |
| 838 EnterDebugger debugger(isolate_); | 892 DebugScope debug_scope(this); |
| 839 if (debugger.FailedToEnter()) { | 893 if (debug_scope.failed()) return; |
| 840 return heap->undefined_value(); | |
| 841 } | |
| 842 | 894 |
| 843 // Postpone interrupt during breakpoint processing. | 895 // Postpone interrupt during breakpoint processing. |
| 844 PostponeInterruptsScope postpone(isolate_); | 896 PostponeInterruptsScope postpone(isolate_); |
| 845 | 897 |
| 846 // Get the debug info (create it if it does not exist). | 898 // Get the debug info (create it if it does not exist). |
| 847 Handle<SharedFunctionInfo> shared = | 899 Handle<SharedFunctionInfo> shared = |
| 848 Handle<SharedFunctionInfo>(frame->function()->shared()); | 900 Handle<SharedFunctionInfo>(frame->function()->shared()); |
| 849 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | 901 Handle<DebugInfo> debug_info = GetDebugInfo(shared); |
| 850 | 902 |
| 851 // Find the break point where execution has stopped. | 903 // Find the break point where execution has stopped. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 867 // triggered. | 919 // triggered. |
| 868 Handle<Object> break_points_hit(heap->undefined_value(), isolate_); | 920 Handle<Object> break_points_hit(heap->undefined_value(), isolate_); |
| 869 if (break_location_iterator.HasBreakPoint()) { | 921 if (break_location_iterator.HasBreakPoint()) { |
| 870 Handle<Object> break_point_objects = | 922 Handle<Object> break_point_objects = |
| 871 Handle<Object>(break_location_iterator.BreakPointObjects(), isolate_); | 923 Handle<Object>(break_location_iterator.BreakPointObjects(), isolate_); |
| 872 break_points_hit = CheckBreakPoints(break_point_objects); | 924 break_points_hit = CheckBreakPoints(break_point_objects); |
| 873 } | 925 } |
| 874 | 926 |
| 875 // If step out is active skip everything until the frame where we need to step | 927 // If step out is active skip everything until the frame where we need to step |
| 876 // out to is reached, unless real breakpoint is hit. | 928 // out to is reached, unless real breakpoint is hit. |
| 877 if (StepOutActive() && frame->fp() != step_out_fp() && | 929 if (StepOutActive() && |
| 930 frame->fp() != thread_local_.step_out_fp_ && |
| 878 break_points_hit->IsUndefined() ) { | 931 break_points_hit->IsUndefined() ) { |
| 879 // Step count should always be 0 for StepOut. | 932 // Step count should always be 0 for StepOut. |
| 880 ASSERT(thread_local_.step_count_ == 0); | 933 ASSERT(thread_local_.step_count_ == 0); |
| 881 } else if (!break_points_hit->IsUndefined() || | 934 } else if (!break_points_hit->IsUndefined() || |
| 882 (thread_local_.last_step_action_ != StepNone && | 935 (thread_local_.last_step_action_ != StepNone && |
| 883 thread_local_.step_count_ == 0)) { | 936 thread_local_.step_count_ == 0)) { |
| 884 // Notify debugger if a real break point is triggered or if performing | 937 // Notify debugger if a real break point is triggered or if performing |
| 885 // single stepping with no more steps to perform. Otherwise do another step. | 938 // single stepping with no more steps to perform. Otherwise do another step. |
| 886 | 939 |
| 887 // Clear all current stepping setup. | 940 // Clear all current stepping setup. |
| 888 ClearStepping(); | 941 ClearStepping(); |
| 889 | 942 |
| 890 if (thread_local_.queued_step_count_ > 0) { | 943 if (thread_local_.queued_step_count_ > 0) { |
| 891 // Perform queued steps | 944 // Perform queued steps |
| 892 int step_count = thread_local_.queued_step_count_; | 945 int step_count = thread_local_.queued_step_count_; |
| 893 | 946 |
| 894 // Clear queue | 947 // Clear queue |
| 895 thread_local_.queued_step_count_ = 0; | 948 thread_local_.queued_step_count_ = 0; |
| 896 | 949 |
| 897 PrepareStep(StepNext, step_count, StackFrame::NO_ID); | 950 PrepareStep(StepNext, step_count, StackFrame::NO_ID); |
| 898 } else { | 951 } else { |
| 899 // Notify the debug event listeners. | 952 // Notify the debug event listeners. |
| 900 isolate_->debugger()->OnDebugBreak(break_points_hit, false); | 953 OnDebugBreak(break_points_hit, false); |
| 901 } | 954 } |
| 902 } else if (thread_local_.last_step_action_ != StepNone) { | 955 } else if (thread_local_.last_step_action_ != StepNone) { |
| 903 // Hold on to last step action as it is cleared by the call to | 956 // Hold on to last step action as it is cleared by the call to |
| 904 // ClearStepping. | 957 // ClearStepping. |
| 905 StepAction step_action = thread_local_.last_step_action_; | 958 StepAction step_action = thread_local_.last_step_action_; |
| 906 int step_count = thread_local_.step_count_; | 959 int step_count = thread_local_.step_count_; |
| 907 | 960 |
| 908 // If StepNext goes deeper in code, StepOut until original frame | 961 // If StepNext goes deeper in code, StepOut until original frame |
| 909 // and keep step count queued up in the meantime. | 962 // and keep step count queued up in the meantime. |
| 910 if (step_action == StepNext && frame->fp() < thread_local_.last_fp_) { | 963 if (step_action == StepNext && frame->fp() < thread_local_.last_fp_) { |
| (...skipping 16 matching lines...) Expand all Loading... |
| 927 step_action = StepOut; | 980 step_action = StepOut; |
| 928 step_count = count; | 981 step_count = count; |
| 929 } | 982 } |
| 930 | 983 |
| 931 // Clear all current stepping setup. | 984 // Clear all current stepping setup. |
| 932 ClearStepping(); | 985 ClearStepping(); |
| 933 | 986 |
| 934 // Set up for the remaining steps. | 987 // Set up for the remaining steps. |
| 935 PrepareStep(step_action, step_count, StackFrame::NO_ID); | 988 PrepareStep(step_action, step_count, StackFrame::NO_ID); |
| 936 } | 989 } |
| 937 | |
| 938 if (thread_local_.frame_drop_mode_ == FRAMES_UNTOUCHED) { | |
| 939 SetAfterBreakTarget(frame); | |
| 940 } else if (thread_local_.frame_drop_mode_ == | |
| 941 FRAME_DROPPED_IN_IC_CALL) { | |
| 942 // We must have been calling IC stub. Do not go there anymore. | |
| 943 Code* plain_return = isolate_->builtins()->builtin( | |
| 944 Builtins::kPlainReturn_LiveEdit); | |
| 945 thread_local_.after_break_target_ = plain_return->entry(); | |
| 946 } else if (thread_local_.frame_drop_mode_ == | |
| 947 FRAME_DROPPED_IN_DEBUG_SLOT_CALL) { | |
| 948 // Debug break slot stub does not return normally, instead it manually | |
| 949 // cleans the stack and jumps. We should patch the jump address. | |
| 950 Code* plain_return = isolate_->builtins()->builtin( | |
| 951 Builtins::kFrameDropper_LiveEdit); | |
| 952 thread_local_.after_break_target_ = plain_return->entry(); | |
| 953 } else if (thread_local_.frame_drop_mode_ == | |
| 954 FRAME_DROPPED_IN_DIRECT_CALL) { | |
| 955 // Nothing to do, after_break_target is not used here. | |
| 956 } else if (thread_local_.frame_drop_mode_ == | |
| 957 FRAME_DROPPED_IN_RETURN_CALL) { | |
| 958 Code* plain_return = isolate_->builtins()->builtin( | |
| 959 Builtins::kFrameDropper_LiveEdit); | |
| 960 thread_local_.after_break_target_ = plain_return->entry(); | |
| 961 } else { | |
| 962 UNREACHABLE(); | |
| 963 } | |
| 964 | |
| 965 return heap->undefined_value(); | |
| 966 } | 990 } |
| 967 | 991 |
| 968 | 992 |
| 969 RUNTIME_FUNCTION(Debug_Break) { | 993 RUNTIME_FUNCTION(Debug_Break) { |
| 970 return isolate->debug()->Break(args); | 994 // Get the top-most JavaScript frame. |
| 995 JavaScriptFrameIterator it(isolate); |
| 996 isolate->debug()->Break(args, it.frame()); |
| 997 isolate->debug()->SetAfterBreakTarget(it.frame()); |
| 998 return isolate->heap()->undefined_value(); |
| 971 } | 999 } |
| 972 | 1000 |
| 973 | 1001 |
| 974 // Check the break point objects for whether one or more are actually | 1002 // Check the break point objects for whether one or more are actually |
| 975 // triggered. This function returns a JSArray with the break point objects | 1003 // triggered. This function returns a JSArray with the break point objects |
| 976 // which is triggered. | 1004 // which is triggered. |
| 977 Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) { | 1005 Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) { |
| 978 Factory* factory = isolate_->factory(); | 1006 Factory* factory = isolate_->factory(); |
| 979 | 1007 |
| 980 // Count the number of break points hit. If there are multiple break points | 1008 // Count the number of break points hit. If there are multiple break points |
| (...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1241 | 1269 |
| 1242 bool Debug::IsBreakOnException(ExceptionBreakType type) { | 1270 bool Debug::IsBreakOnException(ExceptionBreakType type) { |
| 1243 if (type == BreakUncaughtException) { | 1271 if (type == BreakUncaughtException) { |
| 1244 return break_on_uncaught_exception_; | 1272 return break_on_uncaught_exception_; |
| 1245 } else { | 1273 } else { |
| 1246 return break_on_exception_; | 1274 return break_on_exception_; |
| 1247 } | 1275 } |
| 1248 } | 1276 } |
| 1249 | 1277 |
| 1250 | 1278 |
| 1251 Debug::PromiseOnStack::PromiseOnStack(Isolate* isolate, | 1279 PromiseOnStack::PromiseOnStack(Isolate* isolate, |
| 1252 PromiseOnStack* prev, | 1280 PromiseOnStack* prev, |
| 1253 Handle<JSFunction> getter) | 1281 Handle<JSFunction> getter) |
| 1254 : isolate_(isolate), prev_(prev) { | 1282 : isolate_(isolate), prev_(prev) { |
| 1255 handler_ = StackHandler::FromAddress( | 1283 handler_ = StackHandler::FromAddress( |
| 1256 Isolate::handler(isolate->thread_local_top())); | 1284 Isolate::handler(isolate->thread_local_top())); |
| 1257 getter_ = Handle<JSFunction>::cast( | 1285 getter_ = Handle<JSFunction>::cast( |
| 1258 isolate->global_handles()->Create(*getter)); | 1286 isolate->global_handles()->Create(*getter)); |
| 1259 } | 1287 } |
| 1260 | 1288 |
| 1261 | 1289 |
| 1262 Debug::PromiseOnStack::~PromiseOnStack() { | 1290 PromiseOnStack::~PromiseOnStack() { |
| 1263 isolate_->global_handles()->Destroy(Handle<Object>::cast(getter_).location()); | 1291 isolate_->global_handles()->Destroy(Handle<Object>::cast(getter_).location()); |
| 1264 } | 1292 } |
| 1265 | 1293 |
| 1266 | 1294 |
| 1267 void Debug::PromiseHandlePrologue(Handle<JSFunction> promise_getter) { | 1295 void Debug::PromiseHandlePrologue(Handle<JSFunction> promise_getter) { |
| 1268 PromiseOnStack* prev = thread_local_.promise_on_stack_; | 1296 PromiseOnStack* prev = thread_local_.promise_on_stack_; |
| 1269 thread_local_.promise_on_stack_ = | 1297 thread_local_.promise_on_stack_ = |
| 1270 new PromiseOnStack(isolate_, prev, promise_getter); | 1298 new PromiseOnStack(isolate_, prev, promise_getter); |
| 1271 } | 1299 } |
| 1272 | 1300 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1308 } | 1336 } |
| 1309 | 1337 |
| 1310 | 1338 |
| 1311 void Debug::PrepareStep(StepAction step_action, | 1339 void Debug::PrepareStep(StepAction step_action, |
| 1312 int step_count, | 1340 int step_count, |
| 1313 StackFrame::Id frame_id) { | 1341 StackFrame::Id frame_id) { |
| 1314 HandleScope scope(isolate_); | 1342 HandleScope scope(isolate_); |
| 1315 | 1343 |
| 1316 PrepareForBreakPoints(); | 1344 PrepareForBreakPoints(); |
| 1317 | 1345 |
| 1318 ASSERT(Debug::InDebugger()); | 1346 ASSERT(in_debug_scope()); |
| 1319 | 1347 |
| 1320 // Remember this step action and count. | 1348 // Remember this step action and count. |
| 1321 thread_local_.last_step_action_ = step_action; | 1349 thread_local_.last_step_action_ = step_action; |
| 1322 if (step_action == StepOut) { | 1350 if (step_action == StepOut) { |
| 1323 // For step out target frame will be found on the stack so there is no need | 1351 // For step out target frame will be found on the stack so there is no need |
| 1324 // to set step counter for it. It's expected to always be 0 for StepOut. | 1352 // to set step counter for it. It's expected to always be 0 for StepOut. |
| 1325 thread_local_.step_count_ = 0; | 1353 thread_local_.step_count_ = 0; |
| 1326 } else { | 1354 } else { |
| 1327 thread_local_.step_count_ = step_count; | 1355 thread_local_.step_count_ = step_count; |
| 1328 } | 1356 } |
| (...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1579 | 1607 |
| 1580 | 1608 |
| 1581 // Check whether the code object at the specified address is a debug break code | 1609 // Check whether the code object at the specified address is a debug break code |
| 1582 // object. | 1610 // object. |
| 1583 bool Debug::IsDebugBreak(Address addr) { | 1611 bool Debug::IsDebugBreak(Address addr) { |
| 1584 Code* code = Code::GetCodeFromTargetAddress(addr); | 1612 Code* code = Code::GetCodeFromTargetAddress(addr); |
| 1585 return code->is_debug_stub() && code->extra_ic_state() == DEBUG_BREAK; | 1613 return code->is_debug_stub() && code->extra_ic_state() == DEBUG_BREAK; |
| 1586 } | 1614 } |
| 1587 | 1615 |
| 1588 | 1616 |
| 1589 // Check whether a code stub with the specified major key is a possible break | |
| 1590 // point location when looking for source break locations. | |
| 1591 bool Debug::IsSourceBreakStub(Code* code) { | |
| 1592 CodeStub::Major major_key = CodeStub::GetMajorKey(code); | |
| 1593 return major_key == CodeStub::CallFunction; | |
| 1594 } | |
| 1595 | 1617 |
| 1596 | 1618 |
| 1597 // Check whether a code stub with the specified major key is a possible break | |
| 1598 // location. | |
| 1599 bool Debug::IsBreakStub(Code* code) { | |
| 1600 CodeStub::Major major_key = CodeStub::GetMajorKey(code); | |
| 1601 return major_key == CodeStub::CallFunction; | |
| 1602 } | |
| 1603 | |
| 1604 | |
| 1605 // Find the builtin to use for invoking the debug break | |
| 1606 Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) { | |
| 1607 Isolate* isolate = code->GetIsolate(); | |
| 1608 | |
| 1609 // Find the builtin debug break function matching the calling convention | |
| 1610 // used by the call site. | |
| 1611 if (code->is_inline_cache_stub()) { | |
| 1612 switch (code->kind()) { | |
| 1613 case Code::CALL_IC: | |
| 1614 return isolate->builtins()->CallICStub_DebugBreak(); | |
| 1615 | |
| 1616 case Code::LOAD_IC: | |
| 1617 return isolate->builtins()->LoadIC_DebugBreak(); | |
| 1618 | |
| 1619 case Code::STORE_IC: | |
| 1620 return isolate->builtins()->StoreIC_DebugBreak(); | |
| 1621 | |
| 1622 case Code::KEYED_LOAD_IC: | |
| 1623 return isolate->builtins()->KeyedLoadIC_DebugBreak(); | |
| 1624 | |
| 1625 case Code::KEYED_STORE_IC: | |
| 1626 return isolate->builtins()->KeyedStoreIC_DebugBreak(); | |
| 1627 | |
| 1628 case Code::COMPARE_NIL_IC: | |
| 1629 return isolate->builtins()->CompareNilIC_DebugBreak(); | |
| 1630 | |
| 1631 default: | |
| 1632 UNREACHABLE(); | |
| 1633 } | |
| 1634 } | |
| 1635 if (RelocInfo::IsConstructCall(mode)) { | |
| 1636 if (code->has_function_cache()) { | |
| 1637 return isolate->builtins()->CallConstructStub_Recording_DebugBreak(); | |
| 1638 } else { | |
| 1639 return isolate->builtins()->CallConstructStub_DebugBreak(); | |
| 1640 } | |
| 1641 } | |
| 1642 if (code->kind() == Code::STUB) { | |
| 1643 ASSERT(code->major_key() == CodeStub::CallFunction); | |
| 1644 return isolate->builtins()->CallFunctionStub_DebugBreak(); | |
| 1645 } | |
| 1646 | |
| 1647 UNREACHABLE(); | |
| 1648 return Handle<Code>::null(); | |
| 1649 } | |
| 1650 | |
| 1651 | 1619 |
| 1652 // Simple function for returning the source positions for active break points. | 1620 // Simple function for returning the source positions for active break points. |
| 1653 Handle<Object> Debug::GetSourceBreakLocations( | 1621 Handle<Object> Debug::GetSourceBreakLocations( |
| 1654 Handle<SharedFunctionInfo> shared, | 1622 Handle<SharedFunctionInfo> shared, |
| 1655 BreakPositionAlignment position_alignment) { | 1623 BreakPositionAlignment position_alignment) { |
| 1656 Isolate* isolate = shared->GetIsolate(); | 1624 Isolate* isolate = shared->GetIsolate(); |
| 1657 Heap* heap = isolate->heap(); | 1625 Heap* heap = isolate->heap(); |
| 1658 if (!HasDebugInfo(shared)) { | 1626 if (!HasDebugInfo(shared)) { |
| 1659 return Handle<Object>(heap->undefined_value(), isolate); | 1627 return Handle<Object>(heap->undefined_value(), isolate); |
| 1660 } | 1628 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 1684 } | 1652 } |
| 1685 | 1653 |
| 1686 locations->set(count++, position); | 1654 locations->set(count++, position); |
| 1687 } | 1655 } |
| 1688 } | 1656 } |
| 1689 } | 1657 } |
| 1690 return locations; | 1658 return locations; |
| 1691 } | 1659 } |
| 1692 | 1660 |
| 1693 | 1661 |
| 1694 void Debug::NewBreak(StackFrame::Id break_frame_id) { | |
| 1695 thread_local_.break_frame_id_ = break_frame_id; | |
| 1696 thread_local_.break_id_ = ++thread_local_.break_count_; | |
| 1697 } | |
| 1698 | |
| 1699 | |
| 1700 void Debug::SetBreak(StackFrame::Id break_frame_id, int break_id) { | |
| 1701 thread_local_.break_frame_id_ = break_frame_id; | |
| 1702 thread_local_.break_id_ = break_id; | |
| 1703 } | |
| 1704 | |
| 1705 | |
| 1706 // Handle stepping into a function. | 1662 // Handle stepping into a function. |
| 1707 void Debug::HandleStepIn(Handle<JSFunction> function, | 1663 void Debug::HandleStepIn(Handle<JSFunction> function, |
| 1708 Handle<Object> holder, | 1664 Handle<Object> holder, |
| 1709 Address fp, | 1665 Address fp, |
| 1710 bool is_constructor) { | 1666 bool is_constructor) { |
| 1711 Isolate* isolate = function->GetIsolate(); | 1667 Isolate* isolate = function->GetIsolate(); |
| 1712 // If the frame pointer is not supplied by the caller find it. | 1668 // If the frame pointer is not supplied by the caller find it. |
| 1713 if (fp == 0) { | 1669 if (fp == 0) { |
| 1714 StackFrameIterator it(isolate); | 1670 StackFrameIterator it(isolate); |
| 1715 it.Advance(); | 1671 it.Advance(); |
| 1716 // For constructor functions skip another frame. | 1672 // For constructor functions skip another frame. |
| 1717 if (is_constructor) { | 1673 if (is_constructor) { |
| 1718 ASSERT(it.frame()->is_construct()); | 1674 ASSERT(it.frame()->is_construct()); |
| 1719 it.Advance(); | 1675 it.Advance(); |
| 1720 } | 1676 } |
| 1721 fp = it.frame()->fp(); | 1677 fp = it.frame()->fp(); |
| 1722 } | 1678 } |
| 1723 | 1679 |
| 1724 // Flood the function with one-shot break points if it is called from where | 1680 // Flood the function with one-shot break points if it is called from where |
| 1725 // step into was requested. | 1681 // step into was requested. |
| 1726 if (fp == step_in_fp()) { | 1682 if (fp == thread_local_.step_into_fp_) { |
| 1727 if (function->shared()->bound()) { | 1683 if (function->shared()->bound()) { |
| 1728 // Handle Function.prototype.bind | 1684 // Handle Function.prototype.bind |
| 1729 Debug::FloodBoundFunctionWithOneShot(function); | 1685 Debug::FloodBoundFunctionWithOneShot(function); |
| 1730 } else if (!function->IsBuiltin()) { | 1686 } else if (!function->IsBuiltin()) { |
| 1731 // Don't allow step into functions in the native context. | 1687 // Don't allow step into functions in the native context. |
| 1732 if (function->shared()->code() == | 1688 if (function->shared()->code() == |
| 1733 isolate->builtins()->builtin(Builtins::kFunctionApply) || | 1689 isolate->builtins()->builtin(Builtins::kFunctionApply) || |
| 1734 function->shared()->code() == | 1690 function->shared()->code() == |
| 1735 isolate->builtins()->builtin(Builtins::kFunctionCall)) { | 1691 isolate->builtins()->builtin(Builtins::kFunctionCall)) { |
| 1736 // Handle function.apply and function.call separately to flood the | 1692 // Handle function.apply and function.call separately to flood the |
| (...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1973 | 1929 |
| 1974 | 1930 |
| 1975 class ActiveFunctionsRedirector : public ThreadVisitor { | 1931 class ActiveFunctionsRedirector : public ThreadVisitor { |
| 1976 public: | 1932 public: |
| 1977 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { | 1933 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { |
| 1978 RedirectActivationsToRecompiledCodeOnThread(isolate, top); | 1934 RedirectActivationsToRecompiledCodeOnThread(isolate, top); |
| 1979 } | 1935 } |
| 1980 }; | 1936 }; |
| 1981 | 1937 |
| 1982 | 1938 |
| 1983 void Debug::EnsureFunctionHasDebugBreakSlots(Handle<JSFunction> function) { | 1939 static void EnsureFunctionHasDebugBreakSlots(Handle<JSFunction> function) { |
| 1984 if (function->code()->kind() == Code::FUNCTION && | 1940 if (function->code()->kind() == Code::FUNCTION && |
| 1985 function->code()->has_debug_break_slots()) { | 1941 function->code()->has_debug_break_slots()) { |
| 1986 // Nothing to do. Function code already had debug break slots. | 1942 // Nothing to do. Function code already had debug break slots. |
| 1987 return; | 1943 return; |
| 1988 } | 1944 } |
| 1989 // Make sure that the shared full code is compiled with debug | 1945 // Make sure that the shared full code is compiled with debug |
| 1990 // break slots. | 1946 // break slots. |
| 1991 if (!function->shared()->code()->has_debug_break_slots()) { | 1947 if (!function->shared()->code()->has_debug_break_slots()) { |
| 1992 MaybeHandle<Code> code = Compiler::GetCodeForDebugging(function); | 1948 MaybeHandle<Code> code = Compiler::GetCodeForDebugging(function); |
| 1993 // Recompilation can fail. In that case leave the code as it was. | 1949 // Recompilation can fail. In that case leave the code as it was. |
| 1994 if (!code.is_null()) function->ReplaceCode(*code.ToHandleChecked()); | 1950 if (!code.is_null()) function->ReplaceCode(*code.ToHandleChecked()); |
| 1995 } else { | 1951 } else { |
| 1996 // Simply use shared code if it has debug break slots. | 1952 // Simply use shared code if it has debug break slots. |
| 1997 function->ReplaceCode(function->shared()->code()); | 1953 function->ReplaceCode(function->shared()->code()); |
| 1998 } | 1954 } |
| 1999 } | 1955 } |
| 2000 | 1956 |
| 2001 | 1957 |
| 2002 void Debug::RecompileAndRelocateSuspendedGenerators( | 1958 static void RecompileAndRelocateSuspendedGenerators( |
| 2003 const List<Handle<JSGeneratorObject> > &generators) { | 1959 const List<Handle<JSGeneratorObject> > &generators) { |
| 2004 for (int i = 0; i < generators.length(); i++) { | 1960 for (int i = 0; i < generators.length(); i++) { |
| 2005 Handle<JSFunction> fun(generators[i]->function()); | 1961 Handle<JSFunction> fun(generators[i]->function()); |
| 2006 | 1962 |
| 2007 EnsureFunctionHasDebugBreakSlots(fun); | 1963 EnsureFunctionHasDebugBreakSlots(fun); |
| 2008 | 1964 |
| 2009 int code_offset = generators[i]->continuation(); | 1965 int code_offset = generators[i]->continuation(); |
| 2010 int pc_offset = ComputePcOffsetFromCodeOffset(fun->code(), code_offset); | 1966 int pc_offset = ComputePcOffsetFromCodeOffset(fun->code(), code_offset); |
| 2011 generators[i]->set_continuation(pc_offset); | 1967 generators[i]->set_continuation(pc_offset); |
| 2012 } | 1968 } |
| (...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2339 } | 2295 } |
| 2340 // Move to next in list. | 2296 // Move to next in list. |
| 2341 prev = current; | 2297 prev = current; |
| 2342 current = current->next(); | 2298 current = current->next(); |
| 2343 } | 2299 } |
| 2344 UNREACHABLE(); | 2300 UNREACHABLE(); |
| 2345 } | 2301 } |
| 2346 | 2302 |
| 2347 | 2303 |
| 2348 void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) { | 2304 void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) { |
| 2305 if (live_edit_enabled()) { |
| 2306 after_break_target_ = |
| 2307 LiveEdit::AfterBreakTarget(thread_local_.frame_drop_mode_, isolate_); |
| 2308 if (after_break_target_ != NULL) return; // LiveEdit did the job. |
| 2309 } |
| 2310 |
| 2349 HandleScope scope(isolate_); | 2311 HandleScope scope(isolate_); |
| 2350 | |
| 2351 PrepareForBreakPoints(); | 2312 PrepareForBreakPoints(); |
| 2352 | 2313 |
| 2353 // Get the executing function in which the debug break occurred. | 2314 // Get the executing function in which the debug break occurred. |
| 2354 Handle<JSFunction> function(JSFunction::cast(frame->function())); | 2315 Handle<JSFunction> function(JSFunction::cast(frame->function())); |
| 2355 Handle<SharedFunctionInfo> shared(function->shared()); | 2316 Handle<SharedFunctionInfo> shared(function->shared()); |
| 2356 if (!EnsureDebugInfo(shared, function)) { | 2317 if (!EnsureDebugInfo(shared, function)) { |
| 2357 // Return if we failed to retrieve the debug info. | 2318 // Return if we failed to retrieve the debug info. |
| 2358 return; | 2319 return; |
| 2359 } | 2320 } |
| 2360 Handle<DebugInfo> debug_info = GetDebugInfo(shared); | 2321 Handle<DebugInfo> debug_info = GetDebugInfo(shared); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2389 it.next(); | 2350 it.next(); |
| 2390 } | 2351 } |
| 2391 | 2352 |
| 2392 // Handle the jump to continue execution after break point depending on the | 2353 // Handle the jump to continue execution after break point depending on the |
| 2393 // break location. | 2354 // break location. |
| 2394 if (at_js_return) { | 2355 if (at_js_return) { |
| 2395 // If the break point as return is still active jump to the corresponding | 2356 // If the break point as return is still active jump to the corresponding |
| 2396 // place in the original code. If not the break point was removed during | 2357 // place in the original code. If not the break point was removed during |
| 2397 // break point processing. | 2358 // break point processing. |
| 2398 if (break_at_js_return_active) { | 2359 if (break_at_js_return_active) { |
| 2399 addr += original_code->instruction_start() - code->instruction_start(); | 2360 addr += original_code->instruction_start() - code->instruction_start(); |
| 2400 } | 2361 } |
| 2401 | 2362 |
| 2402 // Move back to where the call instruction sequence started. | 2363 // Move back to where the call instruction sequence started. |
| 2403 thread_local_.after_break_target_ = | 2364 after_break_target_ = addr - Assembler::kPatchReturnSequenceAddressOffset; |
| 2404 addr - Assembler::kPatchReturnSequenceAddressOffset; | |
| 2405 } else if (at_debug_break_slot) { | 2365 } else if (at_debug_break_slot) { |
| 2406 // Address of where the debug break slot starts. | 2366 // Address of where the debug break slot starts. |
| 2407 addr = addr - Assembler::kPatchDebugBreakSlotAddressOffset; | 2367 addr = addr - Assembler::kPatchDebugBreakSlotAddressOffset; |
| 2408 | 2368 |
| 2409 // Continue just after the slot. | 2369 // Continue just after the slot. |
| 2410 thread_local_.after_break_target_ = addr + Assembler::kDebugBreakSlotLength; | 2370 after_break_target_ = addr + Assembler::kDebugBreakSlotLength; |
| 2411 } else if (IsDebugBreak(Assembler::target_address_at(addr, *code))) { | 2371 } else if (IsDebugBreak(Assembler::target_address_at(addr, *code))) { |
| 2412 // We now know that there is still a debug break call at the target address, | 2372 // We now know that there is still a debug break call at the target address, |
| 2413 // so the break point is still there and the original code will hold the | 2373 // so the break point is still there and the original code will hold the |
| 2414 // address to jump to in order to complete the call which is replaced by a | 2374 // address to jump to in order to complete the call which is replaced by a |
| 2415 // call to DebugBreakXXX. | 2375 // call to DebugBreakXXX. |
| 2416 | 2376 |
| 2417 // Find the corresponding address in the original code. | 2377 // Find the corresponding address in the original code. |
| 2418 addr += original_code->instruction_start() - code->instruction_start(); | 2378 addr += original_code->instruction_start() - code->instruction_start(); |
| 2419 | 2379 |
| 2420 // Install jump to the call address in the original code. This will be the | 2380 // Install jump to the call address in the original code. This will be the |
| 2421 // call which was overwritten by the call to DebugBreakXXX. | 2381 // call which was overwritten by the call to DebugBreakXXX. |
| 2422 thread_local_.after_break_target_ = | 2382 after_break_target_ = Assembler::target_address_at(addr, *original_code); |
| 2423 Assembler::target_address_at(addr, *original_code); | |
| 2424 } else { | 2383 } else { |
| 2425 // There is no longer a break point present. Don't try to look in the | 2384 // There is no longer a break point present. Don't try to look in the |
| 2426 // original code as the running code will have the right address. This takes | 2385 // original code as the running code will have the right address. This takes |
| 2427 // care of the case where the last break point is removed from the function | 2386 // care of the case where the last break point is removed from the function |
| 2428 // and therefore no "original code" is available. | 2387 // and therefore no "original code" is available. |
| 2429 thread_local_.after_break_target_ = | 2388 after_break_target_ = Assembler::target_address_at(addr, *code); |
| 2430 Assembler::target_address_at(addr, *code); | |
| 2431 } | 2389 } |
| 2432 } | 2390 } |
| 2433 | 2391 |
| 2434 | 2392 |
| 2435 bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { | 2393 bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) { |
| 2436 HandleScope scope(isolate_); | 2394 HandleScope scope(isolate_); |
| 2437 | 2395 |
| 2438 // If there are no break points this cannot be break at return, as | 2396 // If there are no break points this cannot be break at return, as |
| 2439 // the debugger statement and stack guard bebug break cannot be at | 2397 // the debugger statement and stack guard bebug break cannot be at |
| 2440 // return. | 2398 // return. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2469 return (it.rinfo()->pc() == | 2427 return (it.rinfo()->pc() == |
| 2470 addr - Assembler::kPatchReturnSequenceAddressOffset); | 2428 addr - Assembler::kPatchReturnSequenceAddressOffset); |
| 2471 } | 2429 } |
| 2472 it.next(); | 2430 it.next(); |
| 2473 } | 2431 } |
| 2474 return false; | 2432 return false; |
| 2475 } | 2433 } |
| 2476 | 2434 |
| 2477 | 2435 |
| 2478 void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id, | 2436 void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id, |
| 2479 FrameDropMode mode, | 2437 LiveEdit::FrameDropMode mode, |
| 2480 Object** restarter_frame_function_pointer) { | 2438 Object** restarter_frame_function_pointer) { |
| 2481 if (mode != CURRENTLY_SET_MODE) { | 2439 if (mode != LiveEdit::CURRENTLY_SET_MODE) { |
| 2482 thread_local_.frame_drop_mode_ = mode; | 2440 thread_local_.frame_drop_mode_ = mode; |
| 2483 } | 2441 } |
| 2484 thread_local_.break_frame_id_ = new_break_frame_id; | 2442 thread_local_.break_frame_id_ = new_break_frame_id; |
| 2485 thread_local_.restarter_frame_function_pointer_ = | 2443 thread_local_.restarter_frame_function_pointer_ = |
| 2486 restarter_frame_function_pointer; | 2444 restarter_frame_function_pointer; |
| 2487 } | 2445 } |
| 2488 | 2446 |
| 2489 | 2447 |
| 2490 const int Debug::FramePaddingLayout::kInitialSize = 1; | |
| 2491 | |
| 2492 | |
| 2493 // Any even value bigger than kInitialSize as needed for stack scanning. | |
| 2494 const int Debug::FramePaddingLayout::kPaddingValue = kInitialSize + 1; | |
| 2495 | |
| 2496 | |
| 2497 bool Debug::IsDebugGlobal(GlobalObject* global) { | 2448 bool Debug::IsDebugGlobal(GlobalObject* global) { |
| 2498 return IsLoaded() && global == debug_context()->global_object(); | 2449 return is_loaded() && global == debug_context()->global_object(); |
| 2499 } | 2450 } |
| 2500 | 2451 |
| 2501 | 2452 |
| 2502 void Debug::ClearMirrorCache() { | 2453 void Debug::ClearMirrorCache() { |
| 2503 PostponeInterruptsScope postpone(isolate_); | 2454 PostponeInterruptsScope postpone(isolate_); |
| 2504 HandleScope scope(isolate_); | 2455 HandleScope scope(isolate_); |
| 2505 ASSERT(isolate_->context() == *Debug::debug_context()); | 2456 AssertDebugContext(); |
| 2506 | 2457 |
| 2507 // Clear the mirror cache. | 2458 // Clear the mirror cache. |
| 2508 Handle<String> function_name = isolate_->factory()->InternalizeOneByteString( | |
| 2509 STATIC_ASCII_VECTOR("ClearMirrorCache")); | |
| 2510 Handle<Object> fun = Object::GetProperty( | 2459 Handle<Object> fun = Object::GetProperty( |
| 2511 isolate_->global_object(), function_name).ToHandleChecked(); | 2460 isolate_, |
| 2461 isolate_->global_object(), |
| 2462 "ClearMirrorCache").ToHandleChecked(); |
| 2512 ASSERT(fun->IsJSFunction()); | 2463 ASSERT(fun->IsJSFunction()); |
| 2513 Execution::TryCall( | 2464 Execution::TryCall(Handle<JSFunction>::cast(fun), |
| 2514 Handle<JSFunction>::cast(fun), | 2465 Handle<JSObject>(Debug::debug_context()->global_object()), |
| 2515 Handle<JSObject>(Debug::debug_context()->global_object()), | 2466 0, |
| 2516 0, | 2467 NULL); |
| 2517 NULL); | |
| 2518 } | |
| 2519 | |
| 2520 | |
| 2521 void Debug::CreateScriptCache() { | |
| 2522 Heap* heap = isolate_->heap(); | |
| 2523 HandleScope scope(isolate_); | |
| 2524 | |
| 2525 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets | |
| 2526 // rid of all the cached script wrappers and the second gets rid of the | |
| 2527 // scripts which are no longer referenced. The second also sweeps precisely, | |
| 2528 // which saves us doing yet another GC to make the heap iterable. | |
| 2529 heap->CollectAllGarbage(Heap::kNoGCFlags, "Debug::CreateScriptCache"); | |
| 2530 | |
| 2531 ASSERT(script_cache_ == NULL); | |
| 2532 script_cache_ = new ScriptCache(isolate_); | |
| 2533 | |
| 2534 // Scan heap for Script objects. | |
| 2535 int count = 0; | |
| 2536 HeapIterator iterator(heap); | |
| 2537 | |
| 2538 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { | |
| 2539 if (obj->IsScript() && Script::cast(obj)->HasValidSource()) { | |
| 2540 script_cache_->Add(Handle<Script>(Script::cast(obj))); | |
| 2541 count++; | |
| 2542 } | |
| 2543 } | |
| 2544 } | |
| 2545 | |
| 2546 | |
| 2547 void Debug::DestroyScriptCache() { | |
| 2548 // Get rid of the script cache if it was created. | |
| 2549 if (script_cache_ != NULL) { | |
| 2550 delete script_cache_; | |
| 2551 script_cache_ = NULL; | |
| 2552 } | |
| 2553 } | |
| 2554 | |
| 2555 | |
| 2556 void Debug::AddScriptToScriptCache(Handle<Script> script) { | |
| 2557 if (script_cache_ != NULL) { | |
| 2558 script_cache_->Add(script); | |
| 2559 } | |
| 2560 } | 2468 } |
| 2561 | 2469 |
| 2562 | 2470 |
| 2563 Handle<FixedArray> Debug::GetLoadedScripts() { | 2471 Handle<FixedArray> Debug::GetLoadedScripts() { |
| 2564 // Create and fill the script cache when the loaded scripts is requested for | 2472 // Create and fill the script cache when the loaded scripts is requested for |
| 2565 // the first time. | 2473 // the first time. |
| 2566 if (script_cache_ == NULL) { | 2474 if (script_cache_ == NULL) script_cache_ = new ScriptCache(isolate_); |
| 2567 CreateScriptCache(); | |
| 2568 } | |
| 2569 | |
| 2570 // If the script cache is not active just return an empty array. | |
| 2571 ASSERT(script_cache_ != NULL); | |
| 2572 if (script_cache_ == NULL) { | |
| 2573 isolate_->factory()->NewFixedArray(0); | |
| 2574 } | |
| 2575 | 2475 |
| 2576 // Perform GC to get unreferenced scripts evicted from the cache before | 2476 // Perform GC to get unreferenced scripts evicted from the cache before |
| 2577 // returning the content. | 2477 // returning the content. |
| 2578 isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags, | 2478 isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags, |
| 2579 "Debug::GetLoadedScripts"); | 2479 "Debug::GetLoadedScripts"); |
| 2580 | 2480 |
| 2581 // Get the scripts from the cache. | 2481 // Get the scripts from the cache. |
| 2582 return script_cache_->GetScripts(); | 2482 return script_cache_->GetScripts(); |
| 2583 } | 2483 } |
| 2584 | 2484 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2599 | 2499 |
| 2600 | 2500 |
| 2601 void Debug::AfterGarbageCollection() { | 2501 void Debug::AfterGarbageCollection() { |
| 2602 // Generate events for collected scripts. | 2502 // Generate events for collected scripts. |
| 2603 if (script_cache_ != NULL) { | 2503 if (script_cache_ != NULL) { |
| 2604 script_cache_->ProcessCollectedScripts(); | 2504 script_cache_->ProcessCollectedScripts(); |
| 2605 } | 2505 } |
| 2606 } | 2506 } |
| 2607 | 2507 |
| 2608 | 2508 |
| 2609 Debugger::Debugger(Isolate* isolate) | 2509 MaybeHandle<Object> Debug::MakeJSObject(const char* constructor_name, |
| 2610 : event_listener_(Handle<Object>()), | 2510 int argc, |
| 2611 event_listener_data_(Handle<Object>()), | 2511 Handle<Object> argv[]) { |
| 2612 is_active_(false), | 2512 AssertDebugContext(); |
| 2613 ignore_debugger_(false), | 2513 // Create the execution state object. |
| 2614 live_edit_enabled_(true), | 2514 Handle<Object> constructor = Object::GetProperty( |
| 2615 message_handler_(NULL), | 2515 isolate_, isolate_->global_object(), constructor_name).ToHandleChecked(); |
| 2616 command_queue_(isolate->logger(), kQueueInitialSize), | 2516 ASSERT(constructor->IsJSFunction()); |
| 2617 command_received_(0), | 2517 if (!constructor->IsJSFunction()) return MaybeHandle<Object>(); |
| 2618 event_command_queue_(isolate->logger(), kQueueInitialSize), | 2518 return Execution::TryCall(Handle<JSFunction>::cast(constructor), |
| 2619 isolate_(isolate) { | 2519 Handle<JSObject>(debug_context()->global_object()), |
| 2520 argc, |
| 2521 argv); |
| 2620 } | 2522 } |
| 2621 | 2523 |
| 2622 | 2524 |
| 2623 Debugger::~Debugger() {} | 2525 MaybeHandle<Object> Debug::MakeExecutionState() { |
| 2624 | |
| 2625 | |
| 2626 MaybeHandle<Object> Debugger::MakeJSObject( | |
| 2627 Vector<const char> constructor_name, | |
| 2628 int argc, | |
| 2629 Handle<Object> argv[]) { | |
| 2630 ASSERT(isolate_->context() == *isolate_->debug()->debug_context()); | |
| 2631 | |
| 2632 // Create the execution state object. | 2526 // Create the execution state object. |
| 2633 Handle<String> constructor_str = | 2527 Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()) }; |
| 2634 isolate_->factory()->InternalizeUtf8String(constructor_name); | 2528 return MakeJSObject("MakeExecutionState", ARRAY_SIZE(argv), argv); |
| 2635 ASSERT(!constructor_str.is_null()); | |
| 2636 Handle<Object> constructor = Object::GetProperty( | |
| 2637 isolate_->global_object(), constructor_str).ToHandleChecked(); | |
| 2638 ASSERT(constructor->IsJSFunction()); | |
| 2639 if (!constructor->IsJSFunction()) return MaybeHandle<Object>(); | |
| 2640 return Execution::TryCall( | |
| 2641 Handle<JSFunction>::cast(constructor), | |
| 2642 Handle<JSObject>(isolate_->debug()->debug_context()->global_object()), | |
| 2643 argc, | |
| 2644 argv); | |
| 2645 } | 2529 } |
| 2646 | 2530 |
| 2647 | 2531 |
| 2648 MaybeHandle<Object> Debugger::MakeExecutionState() { | 2532 MaybeHandle<Object> Debug::MakeBreakEvent(Handle<Object> break_points_hit) { |
| 2649 // Create the execution state object. | |
| 2650 Handle<Object> break_id = isolate_->factory()->NewNumberFromInt( | |
| 2651 isolate_->debug()->break_id()); | |
| 2652 Handle<Object> argv[] = { break_id }; | |
| 2653 return MakeJSObject(CStrVector("MakeExecutionState"), ARRAY_SIZE(argv), argv); | |
| 2654 } | |
| 2655 | |
| 2656 | |
| 2657 MaybeHandle<Object> Debugger::MakeBreakEvent(Handle<Object> break_points_hit) { | |
| 2658 Handle<Object> exec_state; | 2533 Handle<Object> exec_state; |
| 2659 if (!MakeExecutionState().ToHandle(&exec_state)) return MaybeHandle<Object>(); | 2534 if (!MakeExecutionState().ToHandle(&exec_state)) return MaybeHandle<Object>(); |
| 2660 // Create the new break event object. | 2535 // Create the new break event object. |
| 2661 Handle<Object> argv[] = { exec_state, break_points_hit }; | 2536 Handle<Object> argv[] = { exec_state, break_points_hit }; |
| 2662 return MakeJSObject(CStrVector("MakeBreakEvent"), ARRAY_SIZE(argv), argv); | 2537 return MakeJSObject("MakeBreakEvent", ARRAY_SIZE(argv), argv); |
| 2663 } | 2538 } |
| 2664 | 2539 |
| 2665 | 2540 |
| 2666 MaybeHandle<Object> Debugger::MakeExceptionEvent(Handle<Object> exception, | 2541 MaybeHandle<Object> Debug::MakeExceptionEvent(Handle<Object> exception, |
| 2667 bool uncaught, | 2542 bool uncaught, |
| 2668 Handle<Object> promise) { | 2543 Handle<Object> promise) { |
| 2669 Handle<Object> exec_state; | 2544 Handle<Object> exec_state; |
| 2670 if (!MakeExecutionState().ToHandle(&exec_state)) return MaybeHandle<Object>(); | 2545 if (!MakeExecutionState().ToHandle(&exec_state)) return MaybeHandle<Object>(); |
| 2671 // Create the new exception event object. | 2546 // Create the new exception event object. |
| 2672 Handle<Object> argv[] = { exec_state, | 2547 Handle<Object> argv[] = { exec_state, |
| 2673 exception, | 2548 exception, |
| 2674 isolate_->factory()->ToBoolean(uncaught), | 2549 isolate_->factory()->ToBoolean(uncaught), |
| 2675 promise }; | 2550 promise }; |
| 2676 return MakeJSObject(CStrVector("MakeExceptionEvent"), ARRAY_SIZE(argv), argv); | 2551 return MakeJSObject("MakeExceptionEvent", ARRAY_SIZE(argv), argv); |
| 2677 } | 2552 } |
| 2678 | 2553 |
| 2679 | 2554 |
| 2680 MaybeHandle<Object> Debugger::MakeCompileEvent(Handle<Script> script, | 2555 MaybeHandle<Object> Debug::MakeCompileEvent(Handle<Script> script, |
| 2681 bool before) { | 2556 bool before) { |
| 2682 Handle<Object> exec_state; | 2557 Handle<Object> exec_state; |
| 2683 if (!MakeExecutionState().ToHandle(&exec_state)) return MaybeHandle<Object>(); | 2558 if (!MakeExecutionState().ToHandle(&exec_state)) return MaybeHandle<Object>(); |
| 2684 // Create the compile event object. | 2559 // Create the compile event object. |
| 2685 Handle<Object> script_wrapper = Script::GetWrapper(script); | 2560 Handle<Object> script_wrapper = Script::GetWrapper(script); |
| 2686 Handle<Object> argv[] = { exec_state, | 2561 Handle<Object> argv[] = { exec_state, |
| 2687 script_wrapper, | 2562 script_wrapper, |
| 2688 isolate_->factory()->ToBoolean(before) }; | 2563 isolate_->factory()->ToBoolean(before) }; |
| 2689 return MakeJSObject(CStrVector("MakeCompileEvent"), ARRAY_SIZE(argv), argv); | 2564 return MakeJSObject("MakeCompileEvent", ARRAY_SIZE(argv), argv); |
| 2690 } | 2565 } |
| 2691 | 2566 |
| 2692 | 2567 |
| 2693 MaybeHandle<Object> Debugger::MakeScriptCollectedEvent(int id) { | 2568 MaybeHandle<Object> Debug::MakeScriptCollectedEvent(int id) { |
| 2694 Handle<Object> exec_state; | 2569 Handle<Object> exec_state; |
| 2695 if (!MakeExecutionState().ToHandle(&exec_state)) return MaybeHandle<Object>(); | 2570 if (!MakeExecutionState().ToHandle(&exec_state)) return MaybeHandle<Object>(); |
| 2696 // Create the script collected event object. | 2571 // Create the script collected event object. |
| 2697 Handle<Object> id_object = Handle<Smi>(Smi::FromInt(id), isolate_); | 2572 Handle<Object> id_object = Handle<Smi>(Smi::FromInt(id), isolate_); |
| 2698 Handle<Object> argv[] = { exec_state, id_object }; | 2573 Handle<Object> argv[] = { exec_state, id_object }; |
| 2699 | 2574 return MakeJSObject("MakeScriptCollectedEvent", ARRAY_SIZE(argv), argv); |
| 2700 return MakeJSObject( | |
| 2701 CStrVector("MakeScriptCollectedEvent"), ARRAY_SIZE(argv), argv); | |
| 2702 } | 2575 } |
| 2703 | 2576 |
| 2704 | 2577 |
| 2705 void Debugger::OnException(Handle<Object> exception, bool uncaught) { | 2578 void Debug::OnException(Handle<Object> exception, bool uncaught) { |
| 2579 if (in_debug_scope() || ignore_events()) return; |
| 2580 |
| 2706 HandleScope scope(isolate_); | 2581 HandleScope scope(isolate_); |
| 2707 Debug* debug = isolate_->debug(); | 2582 Handle<Object> promise = GetPromiseForUncaughtException(); |
| 2708 | |
| 2709 // Bail out based on state or if there is no listener for this event | |
| 2710 if (debug->InDebugger()) return; | |
| 2711 if (!Debugger::EventActive()) return; | |
| 2712 | |
| 2713 Handle<Object> promise = debug->GetPromiseForUncaughtException(); | |
| 2714 uncaught |= !promise->IsUndefined(); | 2583 uncaught |= !promise->IsUndefined(); |
| 2715 | 2584 |
| 2716 // Bail out if exception breaks are not active | 2585 // Bail out if exception breaks are not active |
| 2717 if (uncaught) { | 2586 if (uncaught) { |
| 2718 // Uncaught exceptions are reported by either flags. | 2587 // Uncaught exceptions are reported by either flags. |
| 2719 if (!(debug->break_on_uncaught_exception() || | 2588 if (!(break_on_uncaught_exception_ || break_on_exception_)) return; |
| 2720 debug->break_on_exception())) return; | |
| 2721 } else { | 2589 } else { |
| 2722 // Caught exceptions are reported is activated. | 2590 // Caught exceptions are reported is activated. |
| 2723 if (!debug->break_on_exception()) return; | 2591 if (!break_on_exception_) return; |
| 2724 } | 2592 } |
| 2725 | 2593 |
| 2726 // Enter the debugger. | 2594 DebugScope debug_scope(this); |
| 2727 EnterDebugger debugger(isolate_); | 2595 if (debug_scope.failed()) return; |
| 2728 if (debugger.FailedToEnter()) return; | |
| 2729 | 2596 |
| 2730 // Clear all current stepping setup. | 2597 // Clear all current stepping setup. |
| 2731 debug->ClearStepping(); | 2598 ClearStepping(); |
| 2732 | 2599 |
| 2733 // Create the event data object. | 2600 // Create the event data object. |
| 2734 Handle<Object> event_data; | 2601 Handle<Object> event_data; |
| 2735 // Bail out and don't call debugger if exception. | 2602 // Bail out and don't call debugger if exception. |
| 2736 if (!MakeExceptionEvent( | 2603 if (!MakeExceptionEvent( |
| 2737 exception, uncaught, promise).ToHandle(&event_data)) { | 2604 exception, uncaught, promise).ToHandle(&event_data)) { |
| 2738 return; | 2605 return; |
| 2739 } | 2606 } |
| 2740 | 2607 |
| 2741 // Process debug event. | 2608 // Process debug event. |
| 2742 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false); | 2609 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false); |
| 2743 // Return to continue execution from where the exception was thrown. | 2610 // Return to continue execution from where the exception was thrown. |
| 2744 } | 2611 } |
| 2745 | 2612 |
| 2746 | 2613 |
| 2747 void Debugger::OnDebugBreak(Handle<Object> break_points_hit, | 2614 void Debug::OnDebugBreak(Handle<Object> break_points_hit, |
| 2748 bool auto_continue) { | 2615 bool auto_continue) { |
| 2616 // The caller provided for DebugScope. |
| 2617 AssertDebugContext(); |
| 2618 // Bail out if there is no listener for this event |
| 2619 if (ignore_events()) return; |
| 2620 |
| 2749 HandleScope scope(isolate_); | 2621 HandleScope scope(isolate_); |
| 2750 | |
| 2751 // Debugger has already been entered by caller. | |
| 2752 ASSERT(isolate_->context() == *isolate_->debug()->debug_context()); | |
| 2753 | |
| 2754 // Bail out if there is no listener for this event | |
| 2755 if (!Debugger::EventActive()) return; | |
| 2756 | |
| 2757 // Debugger must be entered in advance. | |
| 2758 ASSERT(isolate_->context() == *isolate_->debug()->debug_context()); | |
| 2759 | |
| 2760 // Create the event data object. | 2622 // Create the event data object. |
| 2761 Handle<Object> event_data; | 2623 Handle<Object> event_data; |
| 2762 // Bail out and don't call debugger if exception. | 2624 // Bail out and don't call debugger if exception. |
| 2763 if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return; | 2625 if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return; |
| 2764 | 2626 |
| 2765 // Process debug event. | 2627 // Process debug event. |
| 2766 ProcessDebugEvent(v8::Break, | 2628 ProcessDebugEvent(v8::Break, |
| 2767 Handle<JSObject>::cast(event_data), | 2629 Handle<JSObject>::cast(event_data), |
| 2768 auto_continue); | 2630 auto_continue); |
| 2769 } | 2631 } |
| 2770 | 2632 |
| 2771 | 2633 |
| 2772 void Debugger::OnBeforeCompile(Handle<Script> script) { | 2634 void Debug::OnBeforeCompile(Handle<Script> script) { |
| 2635 if (in_debug_scope() || ignore_events()) return; |
| 2636 |
| 2773 HandleScope scope(isolate_); | 2637 HandleScope scope(isolate_); |
| 2774 | 2638 DebugScope debug_scope(this); |
| 2775 // Bail out based on state or if there is no listener for this event | 2639 if (debug_scope.failed()) return; |
| 2776 if (isolate_->debug()->InDebugger()) return; | |
| 2777 if (!EventActive()) return; | |
| 2778 | |
| 2779 // Enter the debugger. | |
| 2780 EnterDebugger debugger(isolate_); | |
| 2781 if (debugger.FailedToEnter()) return; | |
| 2782 | 2640 |
| 2783 // Create the event data object. | 2641 // Create the event data object. |
| 2784 Handle<Object> event_data; | 2642 Handle<Object> event_data; |
| 2785 // Bail out and don't call debugger if exception. | 2643 // Bail out and don't call debugger if exception. |
| 2786 if (!MakeCompileEvent(script, true).ToHandle(&event_data)) return; | 2644 if (!MakeCompileEvent(script, true).ToHandle(&event_data)) return; |
| 2787 | 2645 |
| 2788 // Process debug event. | 2646 // Process debug event. |
| 2789 ProcessDebugEvent(v8::BeforeCompile, | 2647 ProcessDebugEvent(v8::BeforeCompile, |
| 2790 Handle<JSObject>::cast(event_data), | 2648 Handle<JSObject>::cast(event_data), |
| 2791 true); | 2649 true); |
| 2792 } | 2650 } |
| 2793 | 2651 |
| 2794 | 2652 |
| 2795 // Handle debugger actions when a new script is compiled. | 2653 // Handle debugger actions when a new script is compiled. |
| 2796 void Debugger::OnAfterCompile(Handle<Script> script, | 2654 void Debug::OnAfterCompile(Handle<Script> script, |
| 2797 AfterCompileFlags after_compile_flags) { | 2655 AfterCompileFlags after_compile_flags) { |
| 2798 HandleScope scope(isolate_); | |
| 2799 Debug* debug = isolate_->debug(); | |
| 2800 | |
| 2801 // Add the newly compiled script to the script cache. | 2656 // Add the newly compiled script to the script cache. |
| 2802 debug->AddScriptToScriptCache(script); | 2657 if (script_cache_ != NULL) script_cache_->Add(script); |
| 2803 | 2658 |
| 2804 // No more to do if not debugging. | 2659 // No more to do if not debugging. |
| 2805 if (!Debugger::EventActive()) return; | 2660 if (in_debug_scope() || ignore_events()) return; |
| 2806 | 2661 |
| 2662 HandleScope scope(isolate_); |
| 2807 // Store whether in debugger before entering debugger. | 2663 // Store whether in debugger before entering debugger. |
| 2808 bool in_debugger = debug->InDebugger(); | 2664 bool was_in_scope = in_debug_scope(); |
| 2809 | 2665 |
| 2810 // Enter the debugger. | 2666 DebugScope debug_scope(this); |
| 2811 EnterDebugger debugger(isolate_); | 2667 if (debug_scope.failed()) return; |
| 2812 if (debugger.FailedToEnter()) return; | |
| 2813 | 2668 |
| 2814 // If debugging there might be script break points registered for this | 2669 // If debugging there might be script break points registered for this |
| 2815 // script. Make sure that these break points are set. | 2670 // script. Make sure that these break points are set. |
| 2816 | 2671 |
| 2817 // Get the function UpdateScriptBreakPoints (defined in debug-debugger.js). | 2672 // Get the function UpdateScriptBreakPoints (defined in debug-debugger.js). |
| 2818 Handle<String> update_script_break_points_string = | 2673 Handle<String> update_script_break_points_string = |
| 2819 isolate_->factory()->InternalizeOneByteString( | 2674 isolate_->factory()->InternalizeOneByteString( |
| 2820 STATIC_ASCII_VECTOR("UpdateScriptBreakPoints")); | 2675 STATIC_ASCII_VECTOR("UpdateScriptBreakPoints")); |
| 2821 Handle<GlobalObject> debug_global(debug->debug_context()->global_object()); | 2676 Handle<GlobalObject> debug_global(debug_context()->global_object()); |
| 2822 Handle<Object> update_script_break_points = | 2677 Handle<Object> update_script_break_points = |
| 2823 Object::GetProperty( | 2678 Object::GetProperty( |
| 2824 debug_global, update_script_break_points_string).ToHandleChecked(); | 2679 debug_global, update_script_break_points_string).ToHandleChecked(); |
| 2825 if (!update_script_break_points->IsJSFunction()) { | 2680 if (!update_script_break_points->IsJSFunction()) { |
| 2826 return; | 2681 return; |
| 2827 } | 2682 } |
| 2828 ASSERT(update_script_break_points->IsJSFunction()); | 2683 ASSERT(update_script_break_points->IsJSFunction()); |
| 2829 | 2684 |
| 2830 // Wrap the script object in a proper JS object before passing it | 2685 // Wrap the script object in a proper JS object before passing it |
| 2831 // to JavaScript. | 2686 // to JavaScript. |
| 2832 Handle<Object> wrapper = Script::GetWrapper(script); | 2687 Handle<Object> wrapper = Script::GetWrapper(script); |
| 2833 | 2688 |
| 2834 // Call UpdateScriptBreakPoints expect no exceptions. | 2689 // Call UpdateScriptBreakPoints expect no exceptions. |
| 2835 Handle<Object> argv[] = { wrapper }; | 2690 Handle<Object> argv[] = { wrapper }; |
| 2836 if (Execution::TryCall(Handle<JSFunction>::cast(update_script_break_points), | 2691 if (Execution::TryCall(Handle<JSFunction>::cast(update_script_break_points), |
| 2837 isolate_->js_builtins_object(), | 2692 isolate_->js_builtins_object(), |
| 2838 ARRAY_SIZE(argv), | 2693 ARRAY_SIZE(argv), |
| 2839 argv).is_null()) { | 2694 argv).is_null()) { |
| 2840 return; | 2695 return; |
| 2841 } | 2696 } |
| 2842 // Bail out based on state or if there is no listener for this event | 2697 // Bail out based on state or if there is no listener for this event |
| 2843 if (in_debugger && (after_compile_flags & SEND_WHEN_DEBUGGING) == 0) return; | 2698 if (was_in_scope && (after_compile_flags & SEND_WHEN_DEBUGGING) == 0) return; |
| 2844 | 2699 |
| 2845 // Create the compile state object. | 2700 // Create the compile state object. |
| 2846 Handle<Object> event_data; | 2701 Handle<Object> event_data; |
| 2847 // Bail out and don't call debugger if exception. | 2702 // Bail out and don't call debugger if exception. |
| 2848 if (!MakeCompileEvent(script, false).ToHandle(&event_data)) return; | 2703 if (!MakeCompileEvent(script, false).ToHandle(&event_data)) return; |
| 2849 | 2704 |
| 2850 // Process debug event. | 2705 // Process debug event. |
| 2851 ProcessDebugEvent(v8::AfterCompile, Handle<JSObject>::cast(event_data), true); | 2706 ProcessDebugEvent(v8::AfterCompile, Handle<JSObject>::cast(event_data), true); |
| 2852 } | 2707 } |
| 2853 | 2708 |
| 2854 | 2709 |
| 2855 void Debugger::OnScriptCollected(int id) { | 2710 void Debug::OnScriptCollected(int id) { |
| 2711 if (in_debug_scope() || ignore_events()) return; |
| 2712 |
| 2856 HandleScope scope(isolate_); | 2713 HandleScope scope(isolate_); |
| 2857 | 2714 DebugScope debug_scope(this); |
| 2858 // No more to do if not debugging. | 2715 if (debug_scope.failed()) return; |
| 2859 if (isolate_->debug()->InDebugger()) return; | |
| 2860 if (!Debugger::EventActive()) return; | |
| 2861 | |
| 2862 // Enter the debugger. | |
| 2863 EnterDebugger debugger(isolate_); | |
| 2864 if (debugger.FailedToEnter()) return; | |
| 2865 | 2716 |
| 2866 // Create the script collected state object. | 2717 // Create the script collected state object. |
| 2867 Handle<Object> event_data; | 2718 Handle<Object> event_data; |
| 2868 // Bail out and don't call debugger if exception. | 2719 // Bail out and don't call debugger if exception. |
| 2869 if (!MakeScriptCollectedEvent(id).ToHandle(&event_data)) return; | 2720 if (!MakeScriptCollectedEvent(id).ToHandle(&event_data)) return; |
| 2870 | 2721 |
| 2871 // Process debug event. | 2722 // Process debug event. |
| 2872 ProcessDebugEvent(v8::ScriptCollected, | 2723 ProcessDebugEvent(v8::ScriptCollected, |
| 2873 Handle<JSObject>::cast(event_data), | 2724 Handle<JSObject>::cast(event_data), |
| 2874 true); | 2725 true); |
| 2875 } | 2726 } |
| 2876 | 2727 |
| 2877 | 2728 |
| 2878 void Debugger::ProcessDebugEvent(v8::DebugEvent event, | 2729 void Debug::ProcessDebugEvent(v8::DebugEvent event, |
| 2879 Handle<JSObject> event_data, | 2730 Handle<JSObject> event_data, |
| 2880 bool auto_continue) { | 2731 bool auto_continue) { |
| 2881 HandleScope scope(isolate_); | 2732 HandleScope scope(isolate_); |
| 2882 | 2733 |
| 2883 // Clear any pending debug break if this is a real break. | |
| 2884 if (!auto_continue) { | |
| 2885 isolate_->debug()->set_has_pending_interrupt(false); | |
| 2886 } | |
| 2887 | |
| 2888 // Create the execution state. | 2734 // Create the execution state. |
| 2889 Handle<Object> exec_state; | 2735 Handle<Object> exec_state; |
| 2890 // Bail out and don't call debugger if exception. | 2736 // Bail out and don't call debugger if exception. |
| 2891 if (!MakeExecutionState().ToHandle(&exec_state)) return; | 2737 if (!MakeExecutionState().ToHandle(&exec_state)) return; |
| 2892 | 2738 |
| 2893 // First notify the message handler if any. | 2739 // First notify the message handler if any. |
| 2894 if (message_handler_ != NULL) { | 2740 if (message_handler_ != NULL) { |
| 2895 NotifyMessageHandler(event, | 2741 NotifyMessageHandler(event, |
| 2896 Handle<JSObject>::cast(exec_state), | 2742 Handle<JSObject>::cast(exec_state), |
| 2897 event_data, | 2743 event_data, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 2912 exec_state, | 2758 exec_state, |
| 2913 event_data, | 2759 event_data, |
| 2914 command.client_data()); | 2760 command.client_data()); |
| 2915 } | 2761 } |
| 2916 command.Dispose(); | 2762 command.Dispose(); |
| 2917 } | 2763 } |
| 2918 } | 2764 } |
| 2919 } | 2765 } |
| 2920 | 2766 |
| 2921 | 2767 |
| 2922 void Debugger::CallEventCallback(v8::DebugEvent event, | 2768 void Debug::CallEventCallback(v8::DebugEvent event, |
| 2923 Handle<Object> exec_state, | 2769 Handle<Object> exec_state, |
| 2924 Handle<Object> event_data, | 2770 Handle<Object> event_data, |
| 2925 v8::Debug::ClientData* client_data) { | 2771 v8::Debug::ClientData* client_data) { |
| 2926 if (event_listener_->IsForeign()) { | 2772 if (event_listener_->IsForeign()) { |
| 2927 CallCEventCallback(event, exec_state, event_data, client_data); | 2773 // Invoke the C debug event listener. |
| 2774 v8::Debug::EventCallback2 callback = |
| 2775 FUNCTION_CAST<v8::Debug::EventCallback2>( |
| 2776 Handle<Foreign>::cast(event_listener_)->foreign_address()); |
| 2777 EventDetailsImpl event_details(event, |
| 2778 Handle<JSObject>::cast(exec_state), |
| 2779 Handle<JSObject>::cast(event_data), |
| 2780 event_listener_data_, |
| 2781 client_data); |
| 2782 callback(event_details); |
| 2783 ASSERT(!isolate_->has_scheduled_exception()); |
| 2928 } else { | 2784 } else { |
| 2929 CallJSEventCallback(event, exec_state, event_data); | 2785 // Invoke the JavaScript debug event listener. |
| 2786 ASSERT(event_listener_->IsJSFunction()); |
| 2787 Handle<Object> argv[] = { Handle<Object>(Smi::FromInt(event), isolate_), |
| 2788 exec_state, |
| 2789 event_data, |
| 2790 event_listener_data_ }; |
| 2791 Execution::TryCall(Handle<JSFunction>::cast(event_listener_), |
| 2792 isolate_->global_object(), |
| 2793 ARRAY_SIZE(argv), |
| 2794 argv); |
| 2930 } | 2795 } |
| 2931 } | 2796 } |
| 2932 | 2797 |
| 2933 | 2798 |
| 2934 void Debugger::CallCEventCallback(v8::DebugEvent event, | 2799 Handle<Context> Debug::GetDebugContext() { |
| 2935 Handle<Object> exec_state, | 2800 DebugScope debug_scope(this); |
| 2936 Handle<Object> event_data, | 2801 // The global handle may be destroyed soon after. Return it reboxed. |
| 2937 v8::Debug::ClientData* client_data) { | 2802 return handle(*debug_context(), isolate_); |
| 2938 Handle<Foreign> callback_obj(Handle<Foreign>::cast(event_listener_)); | |
| 2939 v8::Debug::EventCallback2 callback = | |
| 2940 FUNCTION_CAST<v8::Debug::EventCallback2>( | |
| 2941 callback_obj->foreign_address()); | |
| 2942 EventDetailsImpl event_details( | |
| 2943 event, | |
| 2944 Handle<JSObject>::cast(exec_state), | |
| 2945 Handle<JSObject>::cast(event_data), | |
| 2946 event_listener_data_, | |
| 2947 client_data); | |
| 2948 callback(event_details); | |
| 2949 } | 2803 } |
| 2950 | 2804 |
| 2951 | 2805 |
| 2952 void Debugger::CallJSEventCallback(v8::DebugEvent event, | 2806 void Debug::NotifyMessageHandler(v8::DebugEvent event, |
| 2953 Handle<Object> exec_state, | 2807 Handle<JSObject> exec_state, |
| 2954 Handle<Object> event_data) { | 2808 Handle<JSObject> event_data, |
| 2955 ASSERT(event_listener_->IsJSFunction()); | 2809 bool auto_continue) { |
| 2956 Handle<JSFunction> fun(Handle<JSFunction>::cast(event_listener_)); | |
| 2957 | |
| 2958 // Invoke the JavaScript debug event listener. | |
| 2959 Handle<Object> argv[] = { Handle<Object>(Smi::FromInt(event), isolate_), | |
| 2960 exec_state, | |
| 2961 event_data, | |
| 2962 event_listener_data_ }; | |
| 2963 Execution::TryCall(fun, | |
| 2964 isolate_->global_object(), | |
| 2965 ARRAY_SIZE(argv), | |
| 2966 argv); | |
| 2967 // Silently ignore exceptions from debug event listeners. | |
| 2968 } | |
| 2969 | |
| 2970 | |
| 2971 Handle<Context> Debugger::GetDebugContext() { | |
| 2972 EnterDebugger debugger(isolate_); | |
| 2973 // The global handle may be destroyed soon after. Return it reboxed. | |
| 2974 return handle(*isolate_->debug()->debug_context(), isolate_); | |
| 2975 } | |
| 2976 | |
| 2977 | |
| 2978 void Debugger::NotifyMessageHandler(v8::DebugEvent event, | |
| 2979 Handle<JSObject> exec_state, | |
| 2980 Handle<JSObject> event_data, | |
| 2981 bool auto_continue) { | |
| 2982 ASSERT(is_active_); | 2810 ASSERT(is_active_); |
| 2983 HandleScope scope(isolate_); | 2811 HandleScope scope(isolate_); |
| 2984 // Process the individual events. | 2812 // Process the individual events. |
| 2985 bool sendEventMessage = false; | 2813 bool sendEventMessage = false; |
| 2986 switch (event) { | 2814 switch (event) { |
| 2987 case v8::Break: | 2815 case v8::Break: |
| 2988 case v8::BreakForCommand: | 2816 case v8::BreakForCommand: |
| 2989 sendEventMessage = !auto_continue; | 2817 sendEventMessage = !auto_continue; |
| 2990 break; | 2818 break; |
| 2991 case v8::Exception: | 2819 case v8::Exception: |
| 2992 sendEventMessage = true; | 2820 sendEventMessage = true; |
| 2993 break; | 2821 break; |
| 2994 case v8::BeforeCompile: | 2822 case v8::BeforeCompile: |
| 2995 break; | 2823 break; |
| 2996 case v8::AfterCompile: | 2824 case v8::AfterCompile: |
| 2997 sendEventMessage = true; | 2825 sendEventMessage = true; |
| 2998 break; | 2826 break; |
| 2999 case v8::ScriptCollected: | 2827 case v8::ScriptCollected: |
| 3000 sendEventMessage = true; | 2828 sendEventMessage = true; |
| 3001 break; | 2829 break; |
| 3002 case v8::NewFunction: | 2830 case v8::NewFunction: |
| 3003 break; | 2831 break; |
| 3004 default: | 2832 default: |
| 3005 UNREACHABLE(); | 2833 UNREACHABLE(); |
| 3006 } | 2834 } |
| 3007 | 2835 |
| 3008 // The debug command interrupt flag might have been set when the command was | 2836 // The debug command interrupt flag might have been set when the command was |
| 3009 // added. It should be enough to clear the flag only once while we are in the | 2837 // added. It should be enough to clear the flag only once while we are in the |
| 3010 // debugger. | 2838 // debugger. |
| 3011 ASSERT(isolate_->debug()->InDebugger()); | 2839 ASSERT(in_debug_scope()); |
| 3012 isolate_->stack_guard()->ClearDebugCommand(); | 2840 isolate_->stack_guard()->ClearDebugCommand(); |
| 3013 | 2841 |
| 3014 // Notify the debugger that a debug event has occurred unless auto continue is | 2842 // Notify the debugger that a debug event has occurred unless auto continue is |
| 3015 // active in which case no event is send. | 2843 // active in which case no event is send. |
| 3016 if (sendEventMessage) { | 2844 if (sendEventMessage) { |
| 3017 MessageImpl message = MessageImpl::NewEvent( | 2845 MessageImpl message = MessageImpl::NewEvent( |
| 3018 event, | 2846 event, |
| 3019 auto_continue, | 2847 auto_continue, |
| 3020 Handle<JSObject>::cast(exec_state), | 2848 Handle<JSObject>::cast(exec_state), |
| 3021 Handle<JSObject>::cast(event_data)); | 2849 Handle<JSObject>::cast(event_data)); |
| 3022 InvokeMessageHandler(message); | 2850 InvokeMessageHandler(message); |
| 3023 } | 2851 } |
| 3024 | 2852 |
| 3025 // If auto continue don't make the event cause a break, but process messages | 2853 // If auto continue don't make the event cause a break, but process messages |
| 3026 // in the queue if any. For script collected events don't even process | 2854 // in the queue if any. For script collected events don't even process |
| 3027 // messages in the queue as the execution state might not be what is expected | 2855 // messages in the queue as the execution state might not be what is expected |
| 3028 // by the client. | 2856 // by the client. |
| 3029 if ((auto_continue && !HasCommands()) || event == v8::ScriptCollected) { | 2857 if ((auto_continue && !has_commands()) || event == v8::ScriptCollected) { |
| 3030 return; | 2858 return; |
| 3031 } | 2859 } |
| 3032 | 2860 |
| 3033 // DebugCommandProcessor goes here. | 2861 // DebugCommandProcessor goes here. |
| 3034 bool running = auto_continue; | 2862 bool running = auto_continue; |
| 3035 | 2863 |
| 3036 Handle<Object> cmd_processor_ctor = Object::GetProperty( | 2864 Handle<Object> cmd_processor_ctor = Object::GetProperty( |
| 3037 isolate_, exec_state, "debugCommandProcessor").ToHandleChecked(); | 2865 isolate_, exec_state, "debugCommandProcessor").ToHandleChecked(); |
| 3038 Handle<Object> ctor_args[] = { isolate_->factory()->ToBoolean(running) }; | 2866 Handle<Object> ctor_args[] = { isolate_->factory()->ToBoolean(running) }; |
| 3039 Handle<Object> cmd_processor = Execution::Call( | 2867 Handle<Object> cmd_processor = Execution::Call( |
| 3040 isolate_, cmd_processor_ctor, exec_state, 1, ctor_args).ToHandleChecked(); | 2868 isolate_, cmd_processor_ctor, exec_state, 1, ctor_args).ToHandleChecked(); |
| 3041 Handle<JSFunction> process_debug_request = Handle<JSFunction>::cast( | 2869 Handle<JSFunction> process_debug_request = Handle<JSFunction>::cast( |
| 3042 Object::GetProperty( | 2870 Object::GetProperty( |
| 3043 isolate_, cmd_processor, "processDebugRequest").ToHandleChecked()); | 2871 isolate_, cmd_processor, "processDebugRequest").ToHandleChecked()); |
| 3044 Handle<Object> is_running = Object::GetProperty( | 2872 Handle<Object> is_running = Object::GetProperty( |
| 3045 isolate_, cmd_processor, "isRunning").ToHandleChecked(); | 2873 isolate_, cmd_processor, "isRunning").ToHandleChecked(); |
| 3046 | 2874 |
| 3047 // Process requests from the debugger. | 2875 // Process requests from the debugger. |
| 3048 do { | 2876 do { |
| 3049 // Wait for new command in the queue. | 2877 // Wait for new command in the queue. |
| 3050 command_received_.Wait(); | 2878 command_received_.Wait(); |
| 3051 | 2879 |
| 3052 // Get the command from the queue. | 2880 // Get the command from the queue. |
| 3053 CommandMessage command = command_queue_.Get(); | 2881 CommandMessage command = command_queue_.Get(); |
| 3054 isolate_->logger()->DebugTag( | 2882 isolate_->logger()->DebugTag( |
| 3055 "Got request from command queue, in interactive loop."); | 2883 "Got request from command queue, in interactive loop."); |
| 3056 if (!Debugger::is_active()) { | 2884 if (!is_active()) { |
| 3057 // Delete command text and user data. | 2885 // Delete command text and user data. |
| 3058 command.Dispose(); | 2886 command.Dispose(); |
| 3059 return; | 2887 return; |
| 3060 } | 2888 } |
| 3061 | 2889 |
| 3062 Vector<const uc16> command_text( | 2890 Vector<const uc16> command_text( |
| 3063 const_cast<const uc16*>(command.text().start()), | 2891 const_cast<const uc16*>(command.text().start()), |
| 3064 command.text().length()); | 2892 command.text().length()); |
| 3065 Handle<String> request_text = isolate_->factory()->NewStringFromTwoByte( | 2893 Handle<String> request_text = isolate_->factory()->NewStringFromTwoByte( |
| 3066 command_text).ToHandleChecked(); | 2894 command_text).ToHandleChecked(); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 3095 | 2923 |
| 3096 // Return the result. | 2924 // Return the result. |
| 3097 MessageImpl message = MessageImpl::NewResponse( | 2925 MessageImpl message = MessageImpl::NewResponse( |
| 3098 event, running, exec_state, event_data, answer, command.client_data()); | 2926 event, running, exec_state, event_data, answer, command.client_data()); |
| 3099 InvokeMessageHandler(message); | 2927 InvokeMessageHandler(message); |
| 3100 command.Dispose(); | 2928 command.Dispose(); |
| 3101 | 2929 |
| 3102 // Return from debug event processing if either the VM is put into the | 2930 // Return from debug event processing if either the VM is put into the |
| 3103 // running state (through a continue command) or auto continue is active | 2931 // running state (through a continue command) or auto continue is active |
| 3104 // and there are no more commands queued. | 2932 // and there are no more commands queued. |
| 3105 } while (!running || HasCommands()); | 2933 } while (!running || has_commands()); |
| 3106 } | 2934 } |
| 3107 | 2935 |
| 3108 | 2936 |
| 3109 void Debugger::SetEventListener(Handle<Object> callback, | 2937 void Debug::SetEventListener(Handle<Object> callback, |
| 3110 Handle<Object> data) { | 2938 Handle<Object> data) { |
| 3111 GlobalHandles* global_handles = isolate_->global_handles(); | 2939 GlobalHandles* global_handles = isolate_->global_handles(); |
| 3112 | 2940 |
| 3113 // Remove existing entry. | 2941 // Remove existing entry. |
| 3114 GlobalHandles::Destroy(event_listener_.location()); | 2942 GlobalHandles::Destroy(event_listener_.location()); |
| 3115 event_listener_ = Handle<Object>(); | 2943 event_listener_ = Handle<Object>(); |
| 3116 GlobalHandles::Destroy(event_listener_data_.location()); | 2944 GlobalHandles::Destroy(event_listener_data_.location()); |
| 3117 event_listener_data_ = Handle<Object>(); | 2945 event_listener_data_ = Handle<Object>(); |
| 3118 | 2946 |
| 3119 // Set new entry. | 2947 // Set new entry. |
| 3120 if (!callback->IsUndefined() && !callback->IsNull()) { | 2948 if (!callback->IsUndefined() && !callback->IsNull()) { |
| 3121 event_listener_ = global_handles->Create(*callback); | 2949 event_listener_ = global_handles->Create(*callback); |
| 3122 if (data.is_null()) data = isolate_->factory()->undefined_value(); | 2950 if (data.is_null()) data = isolate_->factory()->undefined_value(); |
| 3123 event_listener_data_ = global_handles->Create(*data); | 2951 event_listener_data_ = global_handles->Create(*data); |
| 3124 } | 2952 } |
| 3125 | 2953 |
| 3126 UpdateState(); | 2954 UpdateState(); |
| 3127 } | 2955 } |
| 3128 | 2956 |
| 3129 | 2957 |
| 3130 void Debugger::SetMessageHandler(v8::Debug::MessageHandler handler) { | 2958 void Debug::SetMessageHandler(v8::Debug::MessageHandler handler) { |
| 3131 message_handler_ = handler; | 2959 message_handler_ = handler; |
| 3132 UpdateState(); | 2960 UpdateState(); |
| 3133 if (handler == NULL && isolate_->debug()->InDebugger()) { | 2961 if (handler == NULL && in_debug_scope()) { |
| 3134 // Send an empty command to the debugger if in a break to make JavaScript | 2962 // Send an empty command to the debugger if in a break to make JavaScript |
| 3135 // run again if the debugger is closed. | 2963 // run again if the debugger is closed. |
| 3136 EnqueueCommandMessage(Vector<const uint16_t>::empty()); | 2964 EnqueueCommandMessage(Vector<const uint16_t>::empty()); |
| 3137 } | 2965 } |
| 3138 } | 2966 } |
| 3139 | 2967 |
| 3140 | 2968 |
| 3141 void Debugger::UpdateState() { | 2969 void Debug::UpdateState() { |
| 3142 bool activate = message_handler_ != NULL || | 2970 is_active_ = message_handler_ != NULL || !event_listener_.is_null(); |
| 3143 !event_listener_.is_null() || | 2971 if (is_active_ || in_debug_scope()) { |
| 3144 isolate_->debug()->InDebugger(); | |
| 3145 if (!is_active_ && activate) { | |
| 3146 // Note that the debug context could have already been loaded to | 2972 // Note that the debug context could have already been loaded to |
| 3147 // bootstrap test cases. | 2973 // bootstrap test cases. |
| 3148 isolate_->compilation_cache()->Disable(); | 2974 isolate_->compilation_cache()->Disable(); |
| 3149 activate = isolate_->debug()->Load(); | 2975 is_active_ = Load(); |
| 3150 } else if (is_active_ && !activate) { | 2976 } else if (is_loaded()) { |
| 3151 isolate_->compilation_cache()->Enable(); | 2977 isolate_->compilation_cache()->Enable(); |
| 3152 isolate_->debug()->ClearAllBreakPoints(); | 2978 ClearAllBreakPoints(); |
| 3153 isolate_->debug()->Unload(); | 2979 Unload(); |
| 3154 } | 2980 } |
| 3155 is_active_ = activate; | |
| 3156 // At this point the debug context is loaded iff the debugger is active. | |
| 3157 ASSERT(isolate_->debug()->IsLoaded() == is_active_); | |
| 3158 } | 2981 } |
| 3159 | 2982 |
| 3160 | 2983 |
| 3161 // Calls the registered debug message handler. This callback is part of the | 2984 // Calls the registered debug message handler. This callback is part of the |
| 3162 // public API. | 2985 // public API. |
| 3163 void Debugger::InvokeMessageHandler(MessageImpl message) { | 2986 void Debug::InvokeMessageHandler(MessageImpl message) { |
| 3164 if (message_handler_ != NULL) message_handler_(message); | 2987 if (message_handler_ != NULL) message_handler_(message); |
| 3165 } | 2988 } |
| 3166 | 2989 |
| 3167 | 2990 |
| 3168 // Puts a command coming from the public API on the queue. Creates | 2991 // Puts a command coming from the public API on the queue. Creates |
| 3169 // a copy of the command string managed by the debugger. Up to this | 2992 // a copy of the command string managed by the debugger. Up to this |
| 3170 // point, the command data was managed by the API client. Called | 2993 // point, the command data was managed by the API client. Called |
| 3171 // by the API client thread. | 2994 // by the API client thread. |
| 3172 void Debugger::EnqueueCommandMessage(Vector<const uint16_t> command, | 2995 void Debug::EnqueueCommandMessage(Vector<const uint16_t> command, |
| 3173 v8::Debug::ClientData* client_data) { | 2996 v8::Debug::ClientData* client_data) { |
| 3174 // Need to cast away const. | 2997 // Need to cast away const. |
| 3175 CommandMessage message = CommandMessage::New( | 2998 CommandMessage message = CommandMessage::New( |
| 3176 Vector<uint16_t>(const_cast<uint16_t*>(command.start()), | 2999 Vector<uint16_t>(const_cast<uint16_t*>(command.start()), |
| 3177 command.length()), | 3000 command.length()), |
| 3178 client_data); | 3001 client_data); |
| 3179 isolate_->logger()->DebugTag("Put command on command_queue."); | 3002 isolate_->logger()->DebugTag("Put command on command_queue."); |
| 3180 command_queue_.Put(message); | 3003 command_queue_.Put(message); |
| 3181 command_received_.Signal(); | 3004 command_received_.Signal(); |
| 3182 | 3005 |
| 3183 // Set the debug command break flag to have the command processed. | 3006 // Set the debug command break flag to have the command processed. |
| 3184 if (!isolate_->debug()->InDebugger()) { | 3007 if (!in_debug_scope()) isolate_->stack_guard()->RequestDebugCommand(); |
| 3185 isolate_->stack_guard()->RequestDebugCommand(); | |
| 3186 } | |
| 3187 } | 3008 } |
| 3188 | 3009 |
| 3189 | 3010 |
| 3190 bool Debugger::HasCommands() { | 3011 void Debug::EnqueueDebugCommand(v8::Debug::ClientData* client_data) { |
| 3191 return !command_queue_.IsEmpty(); | |
| 3192 } | |
| 3193 | |
| 3194 | |
| 3195 void Debugger::EnqueueDebugCommand(v8::Debug::ClientData* client_data) { | |
| 3196 CommandMessage message = CommandMessage::New(Vector<uint16_t>(), client_data); | 3012 CommandMessage message = CommandMessage::New(Vector<uint16_t>(), client_data); |
| 3197 event_command_queue_.Put(message); | 3013 event_command_queue_.Put(message); |
| 3198 | 3014 |
| 3199 // Set the debug command break flag to have the command processed. | 3015 // Set the debug command break flag to have the command processed. |
| 3200 if (!isolate_->debug()->InDebugger()) { | 3016 if (!in_debug_scope()) isolate_->stack_guard()->RequestDebugCommand(); |
| 3201 isolate_->stack_guard()->RequestDebugCommand(); | |
| 3202 } | |
| 3203 } | 3017 } |
| 3204 | 3018 |
| 3205 | 3019 |
| 3206 MaybeHandle<Object> Debugger::Call(Handle<JSFunction> fun, | 3020 MaybeHandle<Object> Debug::Call(Handle<JSFunction> fun, Handle<Object> data) { |
| 3207 Handle<Object> data) { | 3021 DebugScope debug_scope(this); |
| 3208 // Enter the debugger. | 3022 if (debug_scope.failed()) return isolate_->factory()->undefined_value(); |
| 3209 EnterDebugger debugger(isolate_); | |
| 3210 if (debugger.FailedToEnter()) { | |
| 3211 return isolate_->factory()->undefined_value(); | |
| 3212 } | |
| 3213 | 3023 |
| 3214 // Create the execution state. | 3024 // Create the execution state. |
| 3215 Handle<Object> exec_state; | 3025 Handle<Object> exec_state; |
| 3216 if (!MakeExecutionState().ToHandle(&exec_state)) { | 3026 if (!MakeExecutionState().ToHandle(&exec_state)) { |
| 3217 return isolate_->factory()->undefined_value(); | 3027 return isolate_->factory()->undefined_value(); |
| 3218 } | 3028 } |
| 3219 | 3029 |
| 3220 Handle<Object> argv[] = { exec_state, data }; | 3030 Handle<Object> argv[] = { exec_state, data }; |
| 3221 return Execution::Call( | 3031 return Execution::Call( |
| 3222 isolate_, | 3032 isolate_, |
| 3223 fun, | 3033 fun, |
| 3224 Handle<Object>(isolate_->debug()->debug_context_->global_proxy(), | 3034 Handle<Object>(debug_context()->global_proxy(), isolate_), |
| 3225 isolate_), | |
| 3226 ARRAY_SIZE(argv), | 3035 ARRAY_SIZE(argv), |
| 3227 argv); | 3036 argv); |
| 3228 } | 3037 } |
| 3229 | 3038 |
| 3230 | 3039 |
| 3231 EnterDebugger::EnterDebugger(Isolate* isolate) | 3040 void Debug::HandleDebugBreak() { |
| 3232 : isolate_(isolate), | 3041 // Ignore debug break during bootstrapping. |
| 3233 prev_(isolate_->debug()->debugger_entry()), | 3042 if (isolate_->bootstrapper()->IsActive()) return; |
| 3234 save_(isolate_) { | 3043 // Just continue if breaks are disabled. |
| 3235 Debug* debug = isolate_->debug(); | 3044 if (break_disabled_) return; |
| 3045 // Ignore debug break if debugger is not active. |
| 3046 if (!is_active()) return; |
| 3236 | 3047 |
| 3048 StackLimitCheck check(isolate_); |
| 3049 if (check.HasOverflowed()) return; |
| 3050 |
| 3051 { JavaScriptFrameIterator it(isolate_); |
| 3052 ASSERT(!it.done()); |
| 3053 Object* fun = it.frame()->function(); |
| 3054 if (fun && fun->IsJSFunction()) { |
| 3055 // Don't stop in builtin functions. |
| 3056 if (JSFunction::cast(fun)->IsBuiltin()) return; |
| 3057 GlobalObject* global = JSFunction::cast(fun)->context()->global_object(); |
| 3058 // Don't stop in debugger functions. |
| 3059 if (IsDebugGlobal(global)) return; |
| 3060 } |
| 3061 } |
| 3062 |
| 3063 // Collect the break state before clearing the flags. |
| 3064 bool debug_command_only = isolate_->stack_guard()->CheckDebugCommand() && |
| 3065 !isolate_->stack_guard()->CheckDebugBreak(); |
| 3066 |
| 3067 isolate_->stack_guard()->ClearDebugBreak(); |
| 3068 |
| 3069 ProcessDebugMessages(debug_command_only); |
| 3070 } |
| 3071 |
| 3072 |
| 3073 void Debug::ProcessDebugMessages(bool debug_command_only) { |
| 3074 isolate_->stack_guard()->ClearDebugCommand(); |
| 3075 |
| 3076 StackLimitCheck check(isolate_); |
| 3077 if (check.HasOverflowed()) return; |
| 3078 |
| 3079 HandleScope scope(isolate_); |
| 3080 DebugScope debug_scope(this); |
| 3081 if (debug_scope.failed()) return; |
| 3082 |
| 3083 // Notify the debug event listeners. Indicate auto continue if the break was |
| 3084 // a debug command break. |
| 3085 OnDebugBreak(isolate_->factory()->undefined_value(), debug_command_only); |
| 3086 } |
| 3087 |
| 3088 |
| 3089 DebugScope::DebugScope(Debug* debug) : debug_(debug), |
| 3090 prev_(debug->debugger_entry()), |
| 3091 save_(debug_->isolate_) { |
| 3237 // Link recursive debugger entry. | 3092 // Link recursive debugger entry. |
| 3238 debug->set_debugger_entry(this); | 3093 debug_->thread_local_.current_debug_scope_ = this; |
| 3239 | 3094 |
| 3240 // Store the previous break id and frame id. | 3095 // Store the previous break id and frame id. |
| 3241 break_id_ = debug->break_id(); | 3096 break_id_ = debug_->break_id(); |
| 3242 break_frame_id_ = debug->break_frame_id(); | 3097 break_frame_id_ = debug_->break_frame_id(); |
| 3243 | 3098 |
| 3244 // Create the new break info. If there is no JavaScript frames there is no | 3099 // Create the new break info. If there is no JavaScript frames there is no |
| 3245 // break frame id. | 3100 // break frame id. |
| 3246 JavaScriptFrameIterator it(isolate_); | 3101 JavaScriptFrameIterator it(isolate()); |
| 3247 has_js_frames_ = !it.done(); | 3102 bool has_js_frames = !it.done(); |
| 3248 debug->NewBreak(has_js_frames_ ? it.frame()->id() : StackFrame::NO_ID); | 3103 debug_->thread_local_.break_frame_id_ = has_js_frames ? it.frame()->id() |
| 3104 : StackFrame::NO_ID; |
| 3105 debug_->SetNextBreakId(); |
| 3249 | 3106 |
| 3250 isolate_->debugger()->UpdateState(); | 3107 debug_->UpdateState(); |
| 3251 // Make sure that debugger is loaded and enter the debugger context. | 3108 // Make sure that debugger is loaded and enter the debugger context. |
| 3252 // The previous context is kept in save_. | 3109 // The previous context is kept in save_. |
| 3253 load_failed_ = !debug->IsLoaded(); | 3110 failed_ = !debug_->is_loaded(); |
| 3254 if (!load_failed_) isolate_->set_context(*debug->debug_context()); | 3111 if (!failed_) isolate()->set_context(*debug->debug_context()); |
| 3255 } | 3112 } |
| 3256 | 3113 |
| 3257 | 3114 |
| 3258 EnterDebugger::~EnterDebugger() { | 3115 DebugScope::~DebugScope() { |
| 3259 Debug* debug = isolate_->debug(); | |
| 3260 | |
| 3261 // Leaving this debugger entry. | 3116 // Leaving this debugger entry. |
| 3262 debug->set_debugger_entry(prev_); | 3117 debug_->thread_local_.current_debug_scope_ = prev_; |
| 3263 | 3118 |
| 3264 // Restore to the previous break state. | 3119 // Restore to the previous break state. |
| 3265 debug->SetBreak(break_frame_id_, break_id_); | 3120 debug_->thread_local_.break_frame_id_ = break_frame_id_; |
| 3121 debug_->thread_local_.break_id_ = break_id_; |
| 3266 | 3122 |
| 3267 // Check for leaving the debugger. | 3123 // Check for leaving the debugger. |
| 3268 if (!load_failed_ && prev_ == NULL) { | 3124 if (!failed_ && prev_ == NULL) { |
| 3269 // Clear mirror cache when leaving the debugger. Skip this if there is a | 3125 // Clear mirror cache when leaving the debugger. Skip this if there is a |
| 3270 // pending exception as clearing the mirror cache calls back into | 3126 // pending exception as clearing the mirror cache calls back into |
| 3271 // JavaScript. This can happen if the v8::Debug::Call is used in which | 3127 // JavaScript. This can happen if the v8::Debug::Call is used in which |
| 3272 // case the exception should end up in the calling code. | 3128 // case the exception should end up in the calling code. |
| 3273 if (!isolate_->has_pending_exception()) { | 3129 if (!isolate()->has_pending_exception()) debug_->ClearMirrorCache(); |
| 3274 // Try to avoid any pending debug break breaking in the clear mirror | |
| 3275 // cache JavaScript code. | |
| 3276 if (isolate_->stack_guard()->CheckDebugBreak()) { | |
| 3277 debug->set_has_pending_interrupt(true); | |
| 3278 isolate_->stack_guard()->ClearDebugBreak(); | |
| 3279 } | |
| 3280 debug->ClearMirrorCache(); | |
| 3281 } | |
| 3282 | |
| 3283 // Request debug break when leaving the last debugger entry | |
| 3284 // if one was recorded while debugging. | |
| 3285 if (debug->has_pending_interrupt()) { | |
| 3286 debug->set_has_pending_interrupt(false); | |
| 3287 isolate_->stack_guard()->RequestDebugBreak(); | |
| 3288 } | |
| 3289 | 3130 |
| 3290 // If there are commands in the queue when leaving the debugger request | 3131 // If there are commands in the queue when leaving the debugger request |
| 3291 // that these commands are processed. | 3132 // that these commands are processed. |
| 3292 if (isolate_->debugger()->HasCommands()) { | 3133 if (debug_->has_commands()) isolate()->stack_guard()->RequestDebugCommand(); |
| 3293 isolate_->stack_guard()->RequestDebugCommand(); | |
| 3294 } | |
| 3295 } | 3134 } |
| 3296 | 3135 |
| 3297 isolate_->debugger()->UpdateState(); | 3136 debug_->UpdateState(); |
| 3298 } | 3137 } |
| 3299 | 3138 |
| 3300 | 3139 |
| 3301 MessageImpl MessageImpl::NewEvent(DebugEvent event, | 3140 MessageImpl MessageImpl::NewEvent(DebugEvent event, |
| 3302 bool running, | 3141 bool running, |
| 3303 Handle<JSObject> exec_state, | 3142 Handle<JSObject> exec_state, |
| 3304 Handle<JSObject> event_data) { | 3143 Handle<JSObject> event_data) { |
| 3305 MessageImpl message(true, event, running, | 3144 MessageImpl message(true, event, running, |
| 3306 exec_state, event_data, Handle<String>(), NULL); | 3145 exec_state, event_data, Handle<String>(), NULL); |
| 3307 return message; | 3146 return message; |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3457 } | 3296 } |
| 3458 | 3297 |
| 3459 | 3298 |
| 3460 CommandMessage::CommandMessage(const Vector<uint16_t>& text, | 3299 CommandMessage::CommandMessage(const Vector<uint16_t>& text, |
| 3461 v8::Debug::ClientData* data) | 3300 v8::Debug::ClientData* data) |
| 3462 : text_(text), | 3301 : text_(text), |
| 3463 client_data_(data) { | 3302 client_data_(data) { |
| 3464 } | 3303 } |
| 3465 | 3304 |
| 3466 | 3305 |
| 3467 CommandMessage::~CommandMessage() { | |
| 3468 } | |
| 3469 | |
| 3470 | |
| 3471 void CommandMessage::Dispose() { | 3306 void CommandMessage::Dispose() { |
| 3472 text_.Dispose(); | 3307 text_.Dispose(); |
| 3473 delete client_data_; | 3308 delete client_data_; |
| 3474 client_data_ = NULL; | 3309 client_data_ = NULL; |
| 3475 } | 3310 } |
| 3476 | 3311 |
| 3477 | 3312 |
| 3478 CommandMessage CommandMessage::New(const Vector<uint16_t>& command, | 3313 CommandMessage CommandMessage::New(const Vector<uint16_t>& command, |
| 3479 v8::Debug::ClientData* data) { | 3314 v8::Debug::ClientData* data) { |
| 3480 return CommandMessage(command.Clone(), data); | 3315 return CommandMessage(command.Clone(), data); |
| 3481 } | 3316 } |
| 3482 | 3317 |
| 3483 | 3318 |
| 3484 CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0), | 3319 CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0), |
| 3485 size_(size) { | 3320 size_(size) { |
| 3486 messages_ = NewArray<CommandMessage>(size); | 3321 messages_ = NewArray<CommandMessage>(size); |
| 3487 } | 3322 } |
| 3488 | 3323 |
| 3489 | 3324 |
| 3490 CommandMessageQueue::~CommandMessageQueue() { | 3325 CommandMessageQueue::~CommandMessageQueue() { |
| 3491 while (!IsEmpty()) { | 3326 while (!IsEmpty()) Get().Dispose(); |
| 3492 CommandMessage m = Get(); | |
| 3493 m.Dispose(); | |
| 3494 } | |
| 3495 DeleteArray(messages_); | 3327 DeleteArray(messages_); |
| 3496 } | 3328 } |
| 3497 | 3329 |
| 3498 | 3330 |
| 3499 CommandMessage CommandMessageQueue::Get() { | 3331 CommandMessage CommandMessageQueue::Get() { |
| 3500 ASSERT(!IsEmpty()); | 3332 ASSERT(!IsEmpty()); |
| 3501 int result = start_; | 3333 int result = start_; |
| 3502 start_ = (start_ + 1) % size_; | 3334 start_ = (start_ + 1) % size_; |
| 3503 return messages_[result]; | 3335 return messages_[result]; |
| 3504 } | 3336 } |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3551 logger_->DebugEvent("Put", message.text()); | 3383 logger_->DebugEvent("Put", message.text()); |
| 3552 } | 3384 } |
| 3553 | 3385 |
| 3554 | 3386 |
| 3555 void LockingCommandMessageQueue::Clear() { | 3387 void LockingCommandMessageQueue::Clear() { |
| 3556 LockGuard<Mutex> lock_guard(&mutex_); | 3388 LockGuard<Mutex> lock_guard(&mutex_); |
| 3557 queue_.Clear(); | 3389 queue_.Clear(); |
| 3558 } | 3390 } |
| 3559 | 3391 |
| 3560 } } // namespace v8::internal | 3392 } } // namespace v8::internal |
| OLD | NEW |