1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include "v8.h"
29
30 #include "api.h"
31 #include "arguments.h"
32 #include "bootstrapper.h"
33 #include "code-stubs.h"
34 #include "codegen.h"
35 #include "compilation-cache.h"
36 #include "compiler.h"
37 #include "debug.h"
38 #include "deoptimizer.h"
39 #include "execution.h"
40 #include "full-codegen.h"
41 #include "global-handles.h"
42 #include "ic.h"
43 #include "ic-inl.h"
44 #include "isolate-inl.h"
45 #include "list.h"
46 #include "messages.h"
47 #include "natives.h"
48 #include "stub-cache.h"
49 #include "log.h"
50
51 #include "../include/v8-debug.h"
52
53 namespace v8 {
54 namespace internal {
55
56 #ifdef ENABLE_DEBUGGER_SUPPORT
57
58
Debug(Isolate * isolate)59 Debug::Debug(Isolate* isolate)
60 : has_break_points_(false),
61 script_cache_(NULL),
62 debug_info_list_(NULL),
63 disable_break_(false),
64 break_on_exception_(false),
65 break_on_uncaught_exception_(false),
66 debug_break_return_(NULL),
67 debug_break_slot_(NULL),
68 isolate_(isolate) {
69 memset(registers_, 0, sizeof(JSCallerSavedBuffer));
70 }
71
72
~Debug()73 Debug::~Debug() {
74 }
75
76
PrintLn(v8::Local<v8::Value> value)77 static void PrintLn(v8::Local<v8::Value> value) {
78 v8::Local<v8::String> s = value->ToString();
79 ScopedVector<char> data(s->Length() + 1);
80 if (data.start() == NULL) {
81 V8::FatalProcessOutOfMemory("PrintLn");
82 return;
83 }
84 s->WriteAscii(data.start());
85 PrintF("%s\n", data.start());
86 }
87
88
ComputeCallDebugPrepareStepIn(int argc,Code::Kind kind)89 static Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind) {
90 Isolate* isolate = Isolate::Current();
91 return isolate->stub_cache()->ComputeCallDebugPrepareStepIn(argc, kind);
92 }
93
94
GetDebugEventContext(Isolate * isolate)95 static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) {
96 Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
97 // Isolate::context() may have been NULL when "script collected" event
98 // occured.
99 if (context.is_null()) return v8::Local<v8::Context>();
100 Handle<Context> global_context(context->global_context());
101 return v8::Utils::ToLocal(global_context);
102 }
103
104
BreakLocationIterator(Handle<DebugInfo> debug_info,BreakLocatorType type)105 BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info,
106 BreakLocatorType type) {
107 debug_info_ = debug_info;
108 type_ = type;
109 reloc_iterator_ = NULL;
110 reloc_iterator_original_ = NULL;
111 Reset(); // Initialize the rest of the member variables.
112 }
113
114
~BreakLocationIterator()115 BreakLocationIterator::~BreakLocationIterator() {
116 ASSERT(reloc_iterator_ != NULL);
117 ASSERT(reloc_iterator_original_ != NULL);
118 delete reloc_iterator_;
119 delete reloc_iterator_original_;
120 }
121
122
Next()123 void BreakLocationIterator::Next() {
124 AssertNoAllocation nogc;
125 ASSERT(!RinfoDone());
126
127 // Iterate through reloc info for code and original code stopping at each
128 // breakable code target.
129 bool first = break_point_ == -1;
130 while (!RinfoDone()) {
131 if (!first) RinfoNext();
132 first = false;
133 if (RinfoDone()) return;
134
135 // Whenever a statement position or (plain) position is passed update the
136 // current value of these.
137 if (RelocInfo::IsPosition(rmode())) {
138 if (RelocInfo::IsStatementPosition(rmode())) {
139 statement_position_ = static_cast<int>(
140 rinfo()->data() - debug_info_->shared()->start_position());
141 }
142 // Always update the position as we don't want that to be before the
143 // statement position.
144 position_ = static_cast<int>(
145 rinfo()->data() - debug_info_->shared()->start_position());
146 ASSERT(position_ >= 0);
147 ASSERT(statement_position_ >= 0);
148 }
149
150 if (IsDebugBreakSlot()) {
151 // There is always a possible break point at a debug break slot.
152 break_point_++;
153 return;
154 } else if (RelocInfo::IsCodeTarget(rmode())) {
155 // Check for breakable code target. Look in the original code as setting
156 // break points can cause the code targets in the running (debugged) code
157 // to be of a different kind than in the original code.
158 Address target = original_rinfo()->target_address();
159 Code* code = Code::GetCodeFromTargetAddress(target);
160 if ((code->is_inline_cache_stub() &&
161 !code->is_binary_op_stub() &&
162 !code->is_unary_op_stub() &&
163 !code->is_compare_ic_stub() &&
164 !code->is_to_boolean_ic_stub()) ||
165 RelocInfo::IsConstructCall(rmode())) {
166 break_point_++;
167 return;
168 }
169 if (code->kind() == Code::STUB) {
170 if (IsDebuggerStatement()) {
171 break_point_++;
172 return;
173 }
174 if (type_ == ALL_BREAK_LOCATIONS) {
175 if (Debug::IsBreakStub(code)) {
176 break_point_++;
177 return;
178 }
179 } else {
180 ASSERT(type_ == SOURCE_BREAK_LOCATIONS);
181 if (Debug::IsSourceBreakStub(code)) {
182 break_point_++;
183 return;
184 }
185 }
186 }
187 }
188
189 // Check for break at return.
190 if (RelocInfo::IsJSReturn(rmode())) {
191 // Set the positions to the end of the function.
192 if (debug_info_->shared()->HasSourceCode()) {
193 position_ = debug_info_->shared()->end_position() -
194 debug_info_->shared()->start_position() - 1;
195 } else {
196 position_ = 0;
197 }
198 statement_position_ = position_;
199 break_point_++;
200 return;
201 }
202 }
203 }
204
205
Next(int count)206 void BreakLocationIterator::Next(int count) {
207 while (count > 0) {
208 Next();
209 count--;
210 }
211 }
212
213
214 // Find the break point closest to the supplied address.
FindBreakLocationFromAddress(Address pc)215 void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) {
216 // Run through all break points to locate the one closest to the address.
217 int closest_break_point = 0;
218 int distance = kMaxInt;
219 while (!Done()) {
220 // Check if this break point is closer that what was previously found.
221 if (this->pc() < pc && pc - this->pc() < distance) {
222 closest_break_point = break_point();
223 distance = static_cast<int>(pc - this->pc());
224 // Check whether we can't get any closer.
225 if (distance == 0) break;
226 }
227 Next();
228 }
229
230 // Move to the break point found.
231 Reset();
232 Next(closest_break_point);
233 }
234
235
236 // Find the break point closest to the supplied source position.
FindBreakLocationFromPosition(int position)237 void BreakLocationIterator::FindBreakLocationFromPosition(int position) {
238 // Run through all break points to locate the one closest to the source
239 // position.
240 int closest_break_point = 0;
241 int distance = kMaxInt;
242 while (!Done()) {
243 // Check if this break point is closer that what was previously found.
244 if (position <= statement_position() &&
245 statement_position() - position < distance) {
246 closest_break_point = break_point();
247 distance = statement_position() - position;
248 // Check whether we can't get any closer.
249 if (distance == 0) break;
250 }
251 Next();
252 }
253
254 // Move to the break point found.
255 Reset();
256 Next(closest_break_point);
257 }
258
259
Reset()260 void BreakLocationIterator::Reset() {
261 // Create relocation iterators for the two code objects.
262 if (reloc_iterator_ != NULL) delete reloc_iterator_;
263 if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_;
264 reloc_iterator_ = new RelocIterator(debug_info_->code());
265 reloc_iterator_original_ = new RelocIterator(debug_info_->original_code());
266
267 // Position at the first break point.
268 break_point_ = -1;
269 position_ = 1;
270 statement_position_ = 1;
271 Next();
272 }
273
274
Done() const275 bool BreakLocationIterator::Done() const {
276 return RinfoDone();
277 }
278
279
SetBreakPoint(Handle<Object> break_point_object)280 void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) {
281 // If there is not already a real break point here patch code with debug
282 // break.
283 if (!HasBreakPoint()) {
284 SetDebugBreak();
285 }
286 ASSERT(IsDebugBreak() || IsDebuggerStatement());
287 // Set the break point information.
288 DebugInfo::SetBreakPoint(debug_info_, code_position(),
289 position(), statement_position(),
290 break_point_object);
291 }
292
293
ClearBreakPoint(Handle<Object> break_point_object)294 void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) {
295 // Clear the break point information.
296 DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object);
297 // If there are no more break points here remove the debug break.
298 if (!HasBreakPoint()) {
299 ClearDebugBreak();
300 ASSERT(!IsDebugBreak());
301 }
302 }
303
304
SetOneShot()305 void BreakLocationIterator::SetOneShot() {
306 // Debugger statement always calls debugger. No need to modify it.
307 if (IsDebuggerStatement()) {
308 return;
309 }
310
311 // If there is a real break point here no more to do.
312 if (HasBreakPoint()) {
313 ASSERT(IsDebugBreak());
314 return;
315 }
316
317 // Patch code with debug break.
318 SetDebugBreak();
319 }
320
321
ClearOneShot()322 void BreakLocationIterator::ClearOneShot() {
323 // Debugger statement always calls debugger. No need to modify it.
324 if (IsDebuggerStatement()) {
325 return;
326 }
327
328 // If there is a real break point here no more to do.
329 if (HasBreakPoint()) {
330 ASSERT(IsDebugBreak());
331 return;
332 }
333
334 // Patch code removing debug break.
335 ClearDebugBreak();
336 ASSERT(!IsDebugBreak());
337 }
338
339
SetDebugBreak()340 void BreakLocationIterator::SetDebugBreak() {
341 // Debugger statement always calls debugger. No need to modify it.
342 if (IsDebuggerStatement()) {
343 return;
344 }
345
346 // If there is already a break point here just return. This might happen if
347 // the same code is flooded with break points twice. Flooding the same
348 // function twice might happen when stepping in a function with an exception
349 // handler as the handler and the function is the same.
350 if (IsDebugBreak()) {
351 return;
352 }
353
354 if (RelocInfo::IsJSReturn(rmode())) {
355 // Patch the frame exit code with a break point.
356 SetDebugBreakAtReturn();
357 } else if (IsDebugBreakSlot()) {
358 // Patch the code in the break slot.
359 SetDebugBreakAtSlot();
360 } else {
361 // Patch the IC call.
362 SetDebugBreakAtIC();
363 }
364 ASSERT(IsDebugBreak());
365 }
366
367
ClearDebugBreak()368 void BreakLocationIterator::ClearDebugBreak() {
369 // Debugger statement always calls debugger. No need to modify it.
370 if (IsDebuggerStatement()) {
371 return;
372 }
373
374 if (RelocInfo::IsJSReturn(rmode())) {
375 // Restore the frame exit code.
376 ClearDebugBreakAtReturn();
377 } else if (IsDebugBreakSlot()) {
378 // Restore the code in the break slot.
379 ClearDebugBreakAtSlot();
380 } else {
381 // Patch the IC call.
382 ClearDebugBreakAtIC();
383 }
384 ASSERT(!IsDebugBreak());
385 }
386
387
PrepareStepIn()388 void BreakLocationIterator::PrepareStepIn() {
389 HandleScope scope;
390
391 // Step in can only be prepared if currently positioned on an IC call,
392 // construct call or CallFunction stub call.
393 Address target = rinfo()->target_address();
394 Handle<Code> target_code(Code::GetCodeFromTargetAddress(target));
395 if (target_code->is_call_stub() || target_code->is_keyed_call_stub()) {
396 // Step in through IC call is handled by the runtime system. Therefore make
397 // sure that the any current IC is cleared and the runtime system is
398 // called. If the executing code has a debug break at the location change
399 // the call in the original code as it is the code there that will be
400 // executed in place of the debug break call.
401 Handle<Code> stub = ComputeCallDebugPrepareStepIn(
402 target_code->arguments_count(), target_code->kind());
403 if (IsDebugBreak()) {
404 original_rinfo()->set_target_address(stub->entry());
405 } else {
406 rinfo()->set_target_address(stub->entry());
407 }
408 } else {
409 #ifdef DEBUG
410 // All the following stuff is needed only for assertion checks so the code
411 // is wrapped in ifdef.
412 Handle<Code> maybe_call_function_stub = target_code;
413 if (IsDebugBreak()) {
414 Address original_target = original_rinfo()->target_address();
415 maybe_call_function_stub =
416 Handle<Code>(Code::GetCodeFromTargetAddress(original_target));
417 }
418 bool is_call_function_stub =
419 (maybe_call_function_stub->kind() == Code::STUB &&
420 maybe_call_function_stub->major_key() == CodeStub::CallFunction);
421
422 // Step in through construct call requires no changes to the running code.
423 // Step in through getters/setters should already be prepared as well
424 // because caller of this function (Debug::PrepareStep) is expected to
425 // flood the top frame's function with one shot breakpoints.
426 // Step in through CallFunction stub should also be prepared by caller of
427 // this function (Debug::PrepareStep) which should flood target function
428 // with breakpoints.
429 ASSERT(RelocInfo::IsConstructCall(rmode()) ||
430 target_code->is_inline_cache_stub() ||
431 is_call_function_stub);
432 #endif
433 }
434 }
435
436
437 // Check whether the break point is at a position which will exit the function.
IsExit() const438 bool BreakLocationIterator::IsExit() const {
439 return (RelocInfo::IsJSReturn(rmode()));
440 }
441
442
HasBreakPoint()443 bool BreakLocationIterator::HasBreakPoint() {
444 return debug_info_->HasBreakPoint(code_position());
445 }
446
447
448 // Check whether there is a debug break at the current position.
IsDebugBreak()449 bool BreakLocationIterator::IsDebugBreak() {
450 if (RelocInfo::IsJSReturn(rmode())) {
451 return IsDebugBreakAtReturn();
452 } else if (IsDebugBreakSlot()) {
453 return IsDebugBreakAtSlot();
454 } else {
455 return Debug::IsDebugBreak(rinfo()->target_address());
456 }
457 }
458
459
SetDebugBreakAtIC()460 void BreakLocationIterator::SetDebugBreakAtIC() {
461 // Patch the original code with the current address as the current address
462 // might have changed by the inline caching since the code was copied.
463 original_rinfo()->set_target_address(rinfo()->target_address());
464
465 RelocInfo::Mode mode = rmode();
466 if (RelocInfo::IsCodeTarget(mode)) {
467 Address target = rinfo()->target_address();
468 Handle<Code> target_code(Code::GetCodeFromTargetAddress(target));
469
470 // Patch the code to invoke the builtin debug break function matching the
471 // calling convention used by the call site.
472 Handle<Code> dbgbrk_code(Debug::FindDebugBreak(target_code, mode));
473 rinfo()->set_target_address(dbgbrk_code->entry());
474 }
475 }
476
477
ClearDebugBreakAtIC()478 void BreakLocationIterator::ClearDebugBreakAtIC() {
479 // Patch the code to the original invoke.
480 rinfo()->set_target_address(original_rinfo()->target_address());
481 }
482
483
IsDebuggerStatement()484 bool BreakLocationIterator::IsDebuggerStatement() {
485 return RelocInfo::DEBUG_BREAK == rmode();
486 }
487
488
IsDebugBreakSlot()489 bool BreakLocationIterator::IsDebugBreakSlot() {
490 return RelocInfo::DEBUG_BREAK_SLOT == rmode();
491 }
492
493
BreakPointObjects()494 Object* BreakLocationIterator::BreakPointObjects() {
495 return debug_info_->GetBreakPointObjects(code_position());
496 }
497
498
499 // Clear out all the debug break code. This is ONLY supposed to be used when
500 // shutting down the debugger as it will leave the break point information in
501 // DebugInfo even though the code is patched back to the non break point state.
ClearAllDebugBreak()502 void BreakLocationIterator::ClearAllDebugBreak() {
503 while (!Done()) {
504 ClearDebugBreak();
505 Next();
506 }
507 }
508
509
RinfoDone() const510 bool BreakLocationIterator::RinfoDone() const {
511 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
512 return reloc_iterator_->done();
513 }
514
515
RinfoNext()516 void BreakLocationIterator::RinfoNext() {
517 reloc_iterator_->next();
518 reloc_iterator_original_->next();
519 #ifdef DEBUG
520 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
521 if (!reloc_iterator_->done()) {
522 ASSERT(rmode() == original_rmode());
523 }
524 #endif
525 }
526
527
528 // Threading support.
ThreadInit()529 void Debug::ThreadInit() {
530 thread_local_.break_count_ = 0;
531 thread_local_.break_id_ = 0;
532 thread_local_.break_frame_id_ = StackFrame::NO_ID;
533 thread_local_.last_step_action_ = StepNone;
534 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
535 thread_local_.step_count_ = 0;
536 thread_local_.last_fp_ = 0;
537 thread_local_.queued_step_count_ = 0;
538 thread_local_.step_into_fp_ = 0;
539 thread_local_.step_out_fp_ = 0;
540 thread_local_.after_break_target_ = 0;
541 // TODO(isolates): frames_are_dropped_?
542 thread_local_.debugger_entry_ = NULL;
543 thread_local_.pending_interrupts_ = 0;
544 thread_local_.restarter_frame_function_pointer_ = NULL;
545 }
546
547
ArchiveDebug(char * storage)548 char* Debug::ArchiveDebug(char* storage) {
549 char* to = storage;
550 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
551 to += sizeof(ThreadLocal);
552 memcpy(to, reinterpret_cast<char*>(®isters_), sizeof(registers_));
553 ThreadInit();
554 ASSERT(to <= storage + ArchiveSpacePerThread());
555 return storage + ArchiveSpacePerThread();
556 }
557
558
RestoreDebug(char * storage)559 char* Debug::RestoreDebug(char* storage) {
560 char* from = storage;
561 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
562 from += sizeof(ThreadLocal);
563 memcpy(reinterpret_cast<char*>(®isters_), from, sizeof(registers_));
564 ASSERT(from <= storage + ArchiveSpacePerThread());
565 return storage + ArchiveSpacePerThread();
566 }
567
568
ArchiveSpacePerThread()569 int Debug::ArchiveSpacePerThread() {
570 return sizeof(ThreadLocal) + sizeof(JSCallerSavedBuffer);
571 }
572
573
574 // Frame structure (conforms InternalFrame structure):
575 // -- code
576 // -- SMI maker
577 // -- function (slot is called "context")
578 // -- frame base
SetUpFrameDropperFrame(StackFrame * bottom_js_frame,Handle<Code> code)579 Object** Debug::SetUpFrameDropperFrame(StackFrame* bottom_js_frame,
580 Handle<Code> code) {
581 ASSERT(bottom_js_frame->is_java_script());
582
583 Address fp = bottom_js_frame->fp();
584
585 // Move function pointer into "context" slot.
586 Memory::Object_at(fp + StandardFrameConstants::kContextOffset) =
587 Memory::Object_at(fp + JavaScriptFrameConstants::kFunctionOffset);
588
589 Memory::Object_at(fp + InternalFrameConstants::kCodeOffset) = *code;
590 Memory::Object_at(fp + StandardFrameConstants::kMarkerOffset) =
591 Smi::FromInt(StackFrame::INTERNAL);
592
593 return reinterpret_cast<Object**>(&Memory::Object_at(
594 fp + StandardFrameConstants::kContextOffset));
595 }
596
597 const int Debug::kFrameDropperFrameSize = 4;
598
599
Add(Handle<Script> script)600 void ScriptCache::Add(Handle<Script> script) {
601 GlobalHandles* global_handles = Isolate::Current()->global_handles();
602 // Create an entry in the hash map for the script.
603 int id = Smi::cast(script->id())->value();
604 HashMap::Entry* entry =
605 HashMap::Lookup(reinterpret_cast<void*>(id), Hash(id), true);
606 if (entry->value != NULL) {
607 ASSERT(*script == *reinterpret_cast<Script**>(entry->value));
608 return;
609 }
610
611 // Globalize the script object, make it weak and use the location of the
612 // global handle as the value in the hash map.
613 Handle<Script> script_ =
614 Handle<Script>::cast(
615 (global_handles->Create(*script)));
616 global_handles->MakeWeak(
617 reinterpret_cast<Object**>(script_.location()),
618 this,
619 ScriptCache::HandleWeakScript);
620 entry->value = script_.location();
621 }
622
623
GetScripts()624 Handle<FixedArray> ScriptCache::GetScripts() {
625 Handle<FixedArray> instances = FACTORY->NewFixedArray(occupancy());
626 int count = 0;
627 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
628 ASSERT(entry->value != NULL);
629 if (entry->value != NULL) {
630 instances->set(count, *reinterpret_cast<Script**>(entry->value));
631 count++;
632 }
633 }
634 return instances;
635 }
636
637
ProcessCollectedScripts()638 void ScriptCache::ProcessCollectedScripts() {
639 Debugger* debugger = Isolate::Current()->debugger();
640 for (int i = 0; i < collected_scripts_.length(); i++) {
641 debugger->OnScriptCollected(collected_scripts_[i]);
642 }
643 collected_scripts_.Clear();
644 }
645
646
Clear()647 void ScriptCache::Clear() {
648 GlobalHandles* global_handles = Isolate::Current()->global_handles();
649 // Iterate the script cache to get rid of all the weak handles.
650 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
651 ASSERT(entry != NULL);
652 Object** location = reinterpret_cast<Object**>(entry->value);
653 ASSERT((*location)->IsScript());
654 global_handles->ClearWeakness(location);
655 global_handles->Destroy(location);
656 }
657 // Clear the content of the hash map.
658 HashMap::Clear();
659 }
660
661
HandleWeakScript(v8::Persistent<v8::Value> obj,void * data)662 void ScriptCache::HandleWeakScript(v8::Persistent<v8::Value> obj, void* data) {
663 ScriptCache* script_cache = reinterpret_cast<ScriptCache*>(data);
664 // Find the location of the global handle.
665 Script** location =
666 reinterpret_cast<Script**>(Utils::OpenHandle(*obj).location());
667 ASSERT((*location)->IsScript());
668
669 // Remove the entry from the cache.
670 int id = Smi::cast((*location)->id())->value();
671 script_cache->Remove(reinterpret_cast<void*>(id), Hash(id));
672 script_cache->collected_scripts_.Add(id);
673
674 // Clear the weak handle.
675 obj.Dispose();
676 obj.Clear();
677 }
678
679
SetUp(bool create_heap_objects)680 void Debug::SetUp(bool create_heap_objects) {
681 ThreadInit();
682 if (create_heap_objects) {
683 // Get code to handle debug break on return.
684 debug_break_return_ =
685 isolate_->builtins()->builtin(Builtins::kReturn_DebugBreak);
686 ASSERT(debug_break_return_->IsCode());
687 // Get code to handle debug break in debug break slots.
688 debug_break_slot_ =
689 isolate_->builtins()->builtin(Builtins::kSlot_DebugBreak);
690 ASSERT(debug_break_slot_->IsCode());
691 }
692 }
693
694
HandleWeakDebugInfo(v8::Persistent<v8::Value> obj,void * data)695 void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) {
696 Debug* debug = Isolate::Current()->debug();
697 DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data);
698 // We need to clear all breakpoints associated with the function to restore
699 // original code and avoid patching the code twice later because
700 // the function will live in the heap until next gc, and can be found by
701 // Runtime::FindSharedFunctionInfoInScript.
702 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
703 it.ClearAllDebugBreak();
704 debug->RemoveDebugInfo(node->debug_info());
705 #ifdef DEBUG
706 node = debug->debug_info_list_;
707 while (node != NULL) {
708 ASSERT(node != reinterpret_cast<DebugInfoListNode*>(data));
709 node = node->next();
710 }
711 #endif
712 }
713
714
DebugInfoListNode(DebugInfo * debug_info)715 DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
716 GlobalHandles* global_handles = Isolate::Current()->global_handles();
717 // Globalize the request debug info object and make it weak.
718 debug_info_ = Handle<DebugInfo>::cast(
719 (global_handles->Create(debug_info)));
720 global_handles->MakeWeak(
721 reinterpret_cast<Object**>(debug_info_.location()),
722 this,
723 Debug::HandleWeakDebugInfo);
724 }
725
726
~DebugInfoListNode()727 DebugInfoListNode::~DebugInfoListNode() {
728 Isolate::Current()->global_handles()->Destroy(
729 reinterpret_cast<Object**>(debug_info_.location()));
730 }
731
732
CompileDebuggerScript(int index)733 bool Debug::CompileDebuggerScript(int index) {
734 Isolate* isolate = Isolate::Current();
735 Factory* factory = isolate->factory();
736 HandleScope scope(isolate);
737
738 // Bail out if the index is invalid.
739 if (index == -1) {
740 return false;
741 }
742
743 // Find source and name for the requested script.
744 Handle<String> source_code =
745 isolate->bootstrapper()->NativesSourceLookup(index);
746 Vector<const char> name = Natives::GetScriptName(index);
747 Handle<String> script_name = factory->NewStringFromAscii(name);
748
749 // Compile the script.
750 Handle<SharedFunctionInfo> function_info;
751 function_info = Compiler::Compile(source_code,
752 script_name,
753 0, 0, NULL, NULL,
754 Handle<String>::null(),
755 NATIVES_CODE);
756
757 // Silently ignore stack overflows during compilation.
758 if (function_info.is_null()) {
759 ASSERT(isolate->has_pending_exception());
760 isolate->clear_pending_exception();
761 return false;
762 }
763
764 // Execute the shared function in the debugger context.
765 Handle<Context> context = isolate->global_context();
766 bool caught_exception;
767 Handle<JSFunction> function =
768 factory->NewFunctionFromSharedFunctionInfo(function_info, context);
769
770 Handle<Object> exception =
771 Execution::TryCall(function, Handle<Object>(context->global()),
772 0, NULL, &caught_exception);
773
774 // Check for caught exceptions.
775 if (caught_exception) {
776 ASSERT(!isolate->has_pending_exception());
777 MessageLocation computed_location;
778 isolate->ComputeLocation(&computed_location);
779 Handle<Object> message = MessageHandler::MakeMessageObject(
780 "error_loading_debugger", &computed_location,
781 Vector<Handle<Object> >::empty(), Handle<String>(), Handle<JSArray>());
782 ASSERT(!isolate->has_pending_exception());
783 isolate->set_pending_exception(*exception);
784 MessageHandler::ReportMessage(Isolate::Current(), NULL, message);
785 isolate->clear_pending_exception();
786 return false;
787 }
788
789 // Mark this script as native and return successfully.
790 Handle<Script> script(Script::cast(function->shared()->script()));
791 script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
792 return true;
793 }
794
795
Load()796 bool Debug::Load() {
797 // Return if debugger is already loaded.
798 if (IsLoaded()) return true;
799
800 Debugger* debugger = isolate_->debugger();
801
802 // Bail out if we're already in the process of compiling the native
803 // JavaScript source code for the debugger.
804 if (debugger->compiling_natives() ||
805 debugger->is_loading_debugger())
806 return false;
807 debugger->set_loading_debugger(true);
808
809 // Disable breakpoints and interrupts while compiling and running the
810 // debugger scripts including the context creation code.
811 DisableBreak disable(true);
812 PostponeInterruptsScope postpone(isolate_);
813
814 // Create the debugger context.
815 HandleScope scope(isolate_);
816 Handle<Context> context =
817 isolate_->bootstrapper()->CreateEnvironment(
818 isolate_,
819 Handle<Object>::null(),
820 v8::Handle<ObjectTemplate>(),
821 NULL);
822
823 // Fail if no context could be created.
824 if (context.is_null()) return false;
825
826 // Use the debugger context.
827 SaveContext save(isolate_);
828 isolate_->set_context(*context);
829
830 // Expose the builtins object in the debugger context.
831 Handle<String> key = isolate_->factory()->LookupAsciiSymbol("builtins");
832 Handle<GlobalObject> global = Handle<GlobalObject>(context->global());
833 RETURN_IF_EMPTY_HANDLE_VALUE(
834 isolate_,
835 JSReceiver::SetProperty(global, key, Handle<Object>(global->builtins()),
836 NONE, kNonStrictMode),
837 false);
838
839 // Compile the JavaScript for the debugger in the debugger context.
840 debugger->set_compiling_natives(true);
841 bool caught_exception =
842 !CompileDebuggerScript(Natives::GetIndex("mirror")) ||
843 !CompileDebuggerScript(Natives::GetIndex("debug"));
844
845 if (FLAG_enable_liveedit) {
846 caught_exception = caught_exception ||
847 !CompileDebuggerScript(Natives::GetIndex("liveedit"));
848 }
849
850 debugger->set_compiling_natives(false);
851
852 // Make sure we mark the debugger as not loading before we might
853 // return.
854 debugger->set_loading_debugger(false);
855
856 // Check for caught exceptions.
857 if (caught_exception) return false;
858
859 // Debugger loaded.
860 debug_context_ = context;
861
862 return true;
863 }
864
865
Unload()866 void Debug::Unload() {
867 // Return debugger is not loaded.
868 if (!IsLoaded()) {
869 return;
870 }
871
872 // Clear the script cache.
873 DestroyScriptCache();
874
875 // Clear debugger context global handle.
876 Isolate::Current()->global_handles()->Destroy(
877 reinterpret_cast<Object**>(debug_context_.location()));
878 debug_context_ = Handle<Context>();
879 }
880
881
882 // Set the flag indicating that preemption happened during debugging.
PreemptionWhileInDebugger()883 void Debug::PreemptionWhileInDebugger() {
884 ASSERT(InDebugger());
885 Debug::set_interrupts_pending(PREEMPT);
886 }
887
888
Iterate(ObjectVisitor * v)889 void Debug::Iterate(ObjectVisitor* v) {
890 v->VisitPointer(BitCast<Object**>(&(debug_break_return_)));
891 v->VisitPointer(BitCast<Object**>(&(debug_break_slot_)));
892 }
893
894
Break(Arguments args)895 Object* Debug::Break(Arguments args) {
896 Heap* heap = isolate_->heap();
897 HandleScope scope(isolate_);
898 ASSERT(args.length() == 0);
899
900 thread_local_.frame_drop_mode_ = FRAMES_UNTOUCHED;
901
902 // Get the top-most JavaScript frame.
903 JavaScriptFrameIterator it(isolate_);
904 JavaScriptFrame* frame = it.frame();
905
906 // Just continue if breaks are disabled or debugger cannot be loaded.
907 if (disable_break() || !Load()) {
908 SetAfterBreakTarget(frame);
909 return heap->undefined_value();
910 }
911
912 // Enter the debugger.
913 EnterDebugger debugger;
914 if (debugger.FailedToEnter()) {
915 return heap->undefined_value();
916 }
917
918 // Postpone interrupt during breakpoint processing.
919 PostponeInterruptsScope postpone(isolate_);
920
921 // Get the debug info (create it if it does not exist).
922 Handle<SharedFunctionInfo> shared =
923 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
924 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
925
926 // Find the break point where execution has stopped.
927 BreakLocationIterator break_location_iterator(debug_info,
928 ALL_BREAK_LOCATIONS);
929 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
930
931 // Check whether step next reached a new statement.
932 if (!StepNextContinue(&break_location_iterator, frame)) {
933 // Decrease steps left if performing multiple steps.
934 if (thread_local_.step_count_ > 0) {
935 thread_local_.step_count_--;
936 }
937 }
938
939 // If there is one or more real break points check whether any of these are
940 // triggered.
941 Handle<Object> break_points_hit(heap->undefined_value());
942 if (break_location_iterator.HasBreakPoint()) {
943 Handle<Object> break_point_objects =
944 Handle<Object>(break_location_iterator.BreakPointObjects());
945 break_points_hit = CheckBreakPoints(break_point_objects);
946 }
947
948 // If step out is active skip everything until the frame where we need to step
949 // out to is reached, unless real breakpoint is hit.
950 if (StepOutActive() && frame->fp() != step_out_fp() &&
951 break_points_hit->IsUndefined() ) {
952 // Step count should always be 0 for StepOut.
953 ASSERT(thread_local_.step_count_ == 0);
954 } else if (!break_points_hit->IsUndefined() ||
955 (thread_local_.last_step_action_ != StepNone &&
956 thread_local_.step_count_ == 0)) {
957 // Notify debugger if a real break point is triggered or if performing
958 // single stepping with no more steps to perform. Otherwise do another step.
959
960 // Clear all current stepping setup.
961 ClearStepping();
962
963 if (thread_local_.queued_step_count_ > 0) {
964 // Perform queued steps
965 int step_count = thread_local_.queued_step_count_;
966
967 // Clear queue
968 thread_local_.queued_step_count_ = 0;
969
970 PrepareStep(StepNext, step_count);
971 } else {
972 // Notify the debug event listeners.
973 isolate_->debugger()->OnDebugBreak(break_points_hit, false);
974 }
975 } else if (thread_local_.last_step_action_ != StepNone) {
976 // Hold on to last step action as it is cleared by the call to
977 // ClearStepping.
978 StepAction step_action = thread_local_.last_step_action_;
979 int step_count = thread_local_.step_count_;
980
981 // If StepNext goes deeper in code, StepOut until original frame
982 // and keep step count queued up in the meantime.
983 if (step_action == StepNext && frame->fp() < thread_local_.last_fp_) {
984 // Count frames until target frame
985 int count = 0;
986 JavaScriptFrameIterator it(isolate_);
987 while (!it.done() && it.frame()->fp() != thread_local_.last_fp_) {
988 count++;
989 it.Advance();
990 }
991
992 // If we found original frame
993 if (it.frame()->fp() == thread_local_.last_fp_) {
994 if (step_count > 1) {
995 // Save old count and action to continue stepping after
996 // StepOut
997 thread_local_.queued_step_count_ = step_count - 1;
998 }
999
1000 // Set up for StepOut to reach target frame
1001 step_action = StepOut;
1002 step_count = count;
1003 }
1004 }
1005
1006 // Clear all current stepping setup.
1007 ClearStepping();
1008
1009 // Set up for the remaining steps.
1010 PrepareStep(step_action, step_count);
1011 }
1012
1013 if (thread_local_.frame_drop_mode_ == FRAMES_UNTOUCHED) {
1014 SetAfterBreakTarget(frame);
1015 } else if (thread_local_.frame_drop_mode_ ==
1016 FRAME_DROPPED_IN_IC_CALL) {
1017 // We must have been calling IC stub. Do not go there anymore.
1018 Code* plain_return = isolate_->builtins()->builtin(
1019 Builtins::kPlainReturn_LiveEdit);
1020 thread_local_.after_break_target_ = plain_return->entry();
1021 } else if (thread_local_.frame_drop_mode_ ==
1022 FRAME_DROPPED_IN_DEBUG_SLOT_CALL) {
1023 // Debug break slot stub does not return normally, instead it manually
1024 // cleans the stack and jumps. We should patch the jump address.
1025 Code* plain_return = isolate_->builtins()->builtin(
1026 Builtins::kFrameDropper_LiveEdit);
1027 thread_local_.after_break_target_ = plain_return->entry();
1028 } else if (thread_local_.frame_drop_mode_ ==
1029 FRAME_DROPPED_IN_DIRECT_CALL) {
1030 // Nothing to do, after_break_target is not used here.
1031 } else if (thread_local_.frame_drop_mode_ ==
1032 FRAME_DROPPED_IN_RETURN_CALL) {
1033 Code* plain_return = isolate_->builtins()->builtin(
1034 Builtins::kFrameDropper_LiveEdit);
1035 thread_local_.after_break_target_ = plain_return->entry();
1036 } else {
1037 UNREACHABLE();
1038 }
1039
1040 return heap->undefined_value();
1041 }
1042
1043
RUNTIME_FUNCTION(Object *,Debug_Break)1044 RUNTIME_FUNCTION(Object*, Debug_Break) {
1045 return isolate->debug()->Break(args);
1046 }
1047
1048
1049 // Check the break point objects for whether one or more are actually
1050 // triggered. This function returns a JSArray with the break point objects
1051 // which is triggered.
CheckBreakPoints(Handle<Object> break_point_objects)1052 Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) {
1053 Factory* factory = isolate_->factory();
1054
1055 // Count the number of break points hit. If there are multiple break points
1056 // they are in a FixedArray.
1057 Handle<FixedArray> break_points_hit;
1058 int break_points_hit_count = 0;
1059 ASSERT(!break_point_objects->IsUndefined());
1060 if (break_point_objects->IsFixedArray()) {
1061 Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
1062 break_points_hit = factory->NewFixedArray(array->length());
1063 for (int i = 0; i < array->length(); i++) {
1064 Handle<Object> o(array->get(i));
1065 if (CheckBreakPoint(o)) {
1066 break_points_hit->set(break_points_hit_count++, *o);
1067 }
1068 }
1069 } else {
1070 break_points_hit = factory->NewFixedArray(1);
1071 if (CheckBreakPoint(break_point_objects)) {
1072 break_points_hit->set(break_points_hit_count++, *break_point_objects);
1073 }
1074 }
1075
1076 // Return undefined if no break points were triggered.
1077 if (break_points_hit_count == 0) {
1078 return factory->undefined_value();
1079 }
1080 // Return break points hit as a JSArray.
1081 Handle<JSArray> result = factory->NewJSArrayWithElements(break_points_hit);
1082 result->set_length(Smi::FromInt(break_points_hit_count));
1083 return result;
1084 }
1085
1086
1087 // Check whether a single break point object is triggered.
CheckBreakPoint(Handle<Object> break_point_object)1088 bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
1089 Factory* factory = isolate_->factory();
1090 HandleScope scope(isolate_);
1091
1092 // Ignore check if break point object is not a JSObject.
1093 if (!break_point_object->IsJSObject()) return true;
1094
1095 // Get the function IsBreakPointTriggered (defined in debug-debugger.js).
1096 Handle<String> is_break_point_triggered_symbol =
1097 factory->LookupAsciiSymbol("IsBreakPointTriggered");
1098 Handle<JSFunction> check_break_point =
1099 Handle<JSFunction>(JSFunction::cast(
1100 debug_context()->global()->GetPropertyNoExceptionThrown(
1101 *is_break_point_triggered_symbol)));
1102
1103 // Get the break id as an object.
1104 Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id());
1105
1106 // Call HandleBreakPointx.
1107 bool caught_exception;
1108 Handle<Object> argv[] = { break_id, break_point_object };
1109 Handle<Object> result = Execution::TryCall(check_break_point,
1110 isolate_->js_builtins_object(),
1111 ARRAY_SIZE(argv),
1112 argv,
1113 &caught_exception);
1114
1115 // If exception or non boolean result handle as not triggered
1116 if (caught_exception || !result->IsBoolean()) {
1117 return false;
1118 }
1119
1120 // Return whether the break point is triggered.
1121 ASSERT(!result.is_null());
1122 return (*result)->IsTrue();
1123 }
1124
1125
1126 // Check whether the function has debug information.
HasDebugInfo(Handle<SharedFunctionInfo> shared)1127 bool Debug::HasDebugInfo(Handle<SharedFunctionInfo> shared) {
1128 return !shared->debug_info()->IsUndefined();
1129 }
1130
1131
1132 // Return the debug info for this function. EnsureDebugInfo must be called
1133 // prior to ensure the debug info has been generated for shared.
GetDebugInfo(Handle<SharedFunctionInfo> shared)1134 Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) {
1135 ASSERT(HasDebugInfo(shared));
1136 return Handle<DebugInfo>(DebugInfo::cast(shared->debug_info()));
1137 }
1138
1139
SetBreakPoint(Handle<SharedFunctionInfo> shared,Handle<Object> break_point_object,int * source_position)1140 void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared,
1141 Handle<Object> break_point_object,
1142 int* source_position) {
1143 HandleScope scope(isolate_);
1144
1145 PrepareForBreakPoints();
1146
1147 if (!EnsureDebugInfo(shared)) {
1148 // Return if retrieving debug info failed.
1149 return;
1150 }
1151
1152 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1153 // Source positions starts with zero.
1154 ASSERT(*source_position >= 0);
1155
1156 // Find the break point and change it.
1157 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
1158 it.FindBreakLocationFromPosition(*source_position);
1159 it.SetBreakPoint(break_point_object);
1160
1161 *source_position = it.position();
1162
1163 // At least one active break point now.
1164 ASSERT(debug_info->GetBreakPointCount() > 0);
1165 }
1166
1167
ClearBreakPoint(Handle<Object> break_point_object)1168 void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
1169 HandleScope scope(isolate_);
1170
1171 DebugInfoListNode* node = debug_info_list_;
1172 while (node != NULL) {
1173 Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(),
1174 break_point_object);
1175 if (!result->IsUndefined()) {
1176 // Get information in the break point.
1177 BreakPointInfo* break_point_info = BreakPointInfo::cast(result);
1178 Handle<DebugInfo> debug_info = node->debug_info();
1179 Handle<SharedFunctionInfo> shared(debug_info->shared());
1180 int source_position = break_point_info->statement_position()->value();
1181
1182 // Source positions starts with zero.
1183 ASSERT(source_position >= 0);
1184
1185 // Find the break point and clear it.
1186 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
1187 it.FindBreakLocationFromPosition(source_position);
1188 it.ClearBreakPoint(break_point_object);
1189
1190 // If there are no more break points left remove the debug info for this
1191 // function.
1192 if (debug_info->GetBreakPointCount() == 0) {
1193 RemoveDebugInfo(debug_info);
1194 }
1195
1196 return;
1197 }
1198 node = node->next();
1199 }
1200 }
1201
1202
ClearAllBreakPoints()1203 void Debug::ClearAllBreakPoints() {
1204 DebugInfoListNode* node = debug_info_list_;
1205 while (node != NULL) {
1206 // Remove all debug break code.
1207 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1208 it.ClearAllDebugBreak();
1209 node = node->next();
1210 }
1211
1212 // Remove all debug info.
1213 while (debug_info_list_ != NULL) {
1214 RemoveDebugInfo(debug_info_list_->debug_info());
1215 }
1216 }
1217
1218
FloodWithOneShot(Handle<SharedFunctionInfo> shared)1219 void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) {
1220 PrepareForBreakPoints();
1221 // Make sure the function has set up the debug info.
1222 if (!EnsureDebugInfo(shared)) {
1223 // Return if we failed to retrieve the debug info.
1224 return;
1225 }
1226
1227 // Flood the function with break points.
1228 BreakLocationIterator it(GetDebugInfo(shared), ALL_BREAK_LOCATIONS);
1229 while (!it.Done()) {
1230 it.SetOneShot();
1231 it.Next();
1232 }
1233 }
1234
1235
FloodBoundFunctionWithOneShot(Handle<JSFunction> function)1236 void Debug::FloodBoundFunctionWithOneShot(Handle<JSFunction> function) {
1237 Handle<FixedArray> new_bindings(function->function_bindings());
1238 Handle<Object> bindee(new_bindings->get(JSFunction::kBoundFunctionIndex));
1239
1240 if (!bindee.is_null() && bindee->IsJSFunction() &&
1241 !JSFunction::cast(*bindee)->IsBuiltin()) {
1242 Handle<SharedFunctionInfo> shared_info(JSFunction::cast(*bindee)->shared());
1243 Debug::FloodWithOneShot(shared_info);
1244 }
1245 }
1246
1247
FloodHandlerWithOneShot()1248 void Debug::FloodHandlerWithOneShot() {
1249 // Iterate through the JavaScript stack looking for handlers.
1250 StackFrame::Id id = break_frame_id();
1251 if (id == StackFrame::NO_ID) {
1252 // If there is no JavaScript stack don't do anything.
1253 return;
1254 }
1255 for (JavaScriptFrameIterator it(isolate_, id); !it.done(); it.Advance()) {
1256 JavaScriptFrame* frame = it.frame();
1257 if (frame->HasHandler()) {
1258 Handle<SharedFunctionInfo> shared =
1259 Handle<SharedFunctionInfo>(
1260 JSFunction::cast(frame->function())->shared());
1261 // Flood the function with the catch block with break points
1262 FloodWithOneShot(shared);
1263 return;
1264 }
1265 }
1266 }
1267
1268
ChangeBreakOnException(ExceptionBreakType type,bool enable)1269 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
1270 if (type == BreakUncaughtException) {
1271 break_on_uncaught_exception_ = enable;
1272 } else {
1273 break_on_exception_ = enable;
1274 }
1275 }
1276
1277
IsBreakOnException(ExceptionBreakType type)1278 bool Debug::IsBreakOnException(ExceptionBreakType type) {
1279 if (type == BreakUncaughtException) {
1280 return break_on_uncaught_exception_;
1281 } else {
1282 return break_on_exception_;
1283 }
1284 }
1285
1286
PrepareStep(StepAction step_action,int step_count)1287 void Debug::PrepareStep(StepAction step_action, int step_count) {
1288 HandleScope scope(isolate_);
1289
1290 PrepareForBreakPoints();
1291
1292 ASSERT(Debug::InDebugger());
1293
1294 // Remember this step action and count.
1295 thread_local_.last_step_action_ = step_action;
1296 if (step_action == StepOut) {
1297 // For step out target frame will be found on the stack so there is no need
1298 // to set step counter for it. It's expected to always be 0 for StepOut.
1299 thread_local_.step_count_ = 0;
1300 } else {
1301 thread_local_.step_count_ = step_count;
1302 }
1303
1304 // Get the frame where the execution has stopped and skip the debug frame if
1305 // any. The debug frame will only be present if execution was stopped due to
1306 // hitting a break point. In other situations (e.g. unhandled exception) the
1307 // debug frame is not present.
1308 StackFrame::Id id = break_frame_id();
1309 if (id == StackFrame::NO_ID) {
1310 // If there is no JavaScript stack don't do anything.
1311 return;
1312 }
1313 JavaScriptFrameIterator frames_it(isolate_, id);
1314 JavaScriptFrame* frame = frames_it.frame();
1315
1316 // First of all ensure there is one-shot break points in the top handler
1317 // if any.
1318 FloodHandlerWithOneShot();
1319
1320 // If the function on the top frame is unresolved perform step out. This will
1321 // be the case when calling unknown functions and having the debugger stopped
1322 // in an unhandled exception.
1323 if (!frame->function()->IsJSFunction()) {
1324 // Step out: Find the calling JavaScript frame and flood it with
1325 // breakpoints.
1326 frames_it.Advance();
1327 // Fill the function to return to with one-shot break points.
1328 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
1329 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1330 return;
1331 }
1332
1333 // Get the debug info (create it if it does not exist).
1334 Handle<SharedFunctionInfo> shared =
1335 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
1336 if (!EnsureDebugInfo(shared)) {
1337 // Return if ensuring debug info failed.
1338 return;
1339 }
1340 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1341
1342 // Find the break location where execution has stopped.
1343 BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS);
1344 it.FindBreakLocationFromAddress(frame->pc());
1345
1346 // Compute whether or not the target is a call target.
1347 bool is_load_or_store = false;
1348 bool is_inline_cache_stub = false;
1349 bool is_at_restarted_function = false;
1350 Handle<Code> call_function_stub;
1351
1352 if (thread_local_.restarter_frame_function_pointer_ == NULL) {
1353 if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) {
1354 bool is_call_target = false;
1355 Address target = it.rinfo()->target_address();
1356 Code* code = Code::GetCodeFromTargetAddress(target);
1357 if (code->is_call_stub() || code->is_keyed_call_stub()) {
1358 is_call_target = true;
1359 }
1360 if (code->is_inline_cache_stub()) {
1361 is_inline_cache_stub = true;
1362 is_load_or_store = !is_call_target;
1363 }
1364
1365 // Check if target code is CallFunction stub.
1366 Code* maybe_call_function_stub = code;
1367 // If there is a breakpoint at this line look at the original code to
1368 // check if it is a CallFunction stub.
1369 if (it.IsDebugBreak()) {
1370 Address original_target = it.original_rinfo()->target_address();
1371 maybe_call_function_stub =
1372 Code::GetCodeFromTargetAddress(original_target);
1373 }
1374 if (maybe_call_function_stub->kind() == Code::STUB &&
1375 maybe_call_function_stub->major_key() == CodeStub::CallFunction) {
1376 // Save reference to the code as we may need it to find out arguments
1377 // count for 'step in' later.
1378 call_function_stub = Handle<Code>(maybe_call_function_stub);
1379 }
1380 }
1381 } else {
1382 is_at_restarted_function = true;
1383 }
1384
1385 // If this is the last break code target step out is the only possibility.
1386 if (it.IsExit() || step_action == StepOut) {
1387 if (step_action == StepOut) {
1388 // Skip step_count frames starting with the current one.
1389 while (step_count-- > 0 && !frames_it.done()) {
1390 frames_it.Advance();
1391 }
1392 } else {
1393 ASSERT(it.IsExit());
1394 frames_it.Advance();
1395 }
1396 // Skip builtin functions on the stack.
1397 while (!frames_it.done() &&
1398 JSFunction::cast(frames_it.frame()->function())->IsBuiltin()) {
1399 frames_it.Advance();
1400 }
1401 // Step out: If there is a JavaScript caller frame, we need to
1402 // flood it with breakpoints.
1403 if (!frames_it.done()) {
1404 // Fill the function to return to with one-shot break points.
1405 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
1406 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1407 // Set target frame pointer.
1408 ActivateStepOut(frames_it.frame());
1409 }
1410 } else if (!(is_inline_cache_stub || RelocInfo::IsConstructCall(it.rmode()) ||
1411 !call_function_stub.is_null() || is_at_restarted_function)
1412 || step_action == StepNext || step_action == StepMin) {
1413 // Step next or step min.
1414
1415 // Fill the current function with one-shot break points.
1416 FloodWithOneShot(shared);
1417
1418 // Remember source position and frame to handle step next.
1419 thread_local_.last_statement_position_ =
1420 debug_info->code()->SourceStatementPosition(frame->pc());
1421 thread_local_.last_fp_ = frame->fp();
1422 } else {
1423 // If there's restarter frame on top of the stack, just get the pointer
1424 // to function which is going to be restarted.
1425 if (is_at_restarted_function) {
1426 Handle<JSFunction> restarted_function(
1427 JSFunction::cast(*thread_local_.restarter_frame_function_pointer_));
1428 Handle<SharedFunctionInfo> restarted_shared(
1429 restarted_function->shared());
1430 FloodWithOneShot(restarted_shared);
1431 } else if (!call_function_stub.is_null()) {
1432 // If it's CallFunction stub ensure target function is compiled and flood
1433 // it with one shot breakpoints.
1434
1435 // Find out number of arguments from the stub minor key.
1436 // Reverse lookup required as the minor key cannot be retrieved
1437 // from the code object.
1438 Handle<Object> obj(
1439 isolate_->heap()->code_stubs()->SlowReverseLookup(
1440 *call_function_stub));
1441 ASSERT(!obj.is_null());
1442 ASSERT(!(*obj)->IsUndefined());
1443 ASSERT(obj->IsSmi());
1444 // Get the STUB key and extract major and minor key.
1445 uint32_t key = Smi::cast(*obj)->value();
1446 // Argc in the stub is the number of arguments passed - not the
1447 // expected arguments of the called function.
1448 int call_function_arg_count =
1449 CallFunctionStub::ExtractArgcFromMinorKey(
1450 CodeStub::MinorKeyFromKey(key));
1451 ASSERT(call_function_stub->major_key() ==
1452 CodeStub::MajorKeyFromKey(key));
1453
1454 // Find target function on the expression stack.
1455 // Expression stack looks like this (top to bottom):
1456 // argN
1457 // ...
1458 // arg0
1459 // Receiver
1460 // Function to call
1461 int expressions_count = frame->ComputeExpressionsCount();
1462 ASSERT(expressions_count - 2 - call_function_arg_count >= 0);
1463 Object* fun = frame->GetExpression(
1464 expressions_count - 2 - call_function_arg_count);
1465 if (fun->IsJSFunction()) {
1466 Handle<JSFunction> js_function(JSFunction::cast(fun));
1467 if (js_function->shared()->bound()) {
1468 Debug::FloodBoundFunctionWithOneShot(js_function);
1469 } else if (!js_function->IsBuiltin()) {
1470 // Don't step into builtins.
1471 // It will also compile target function if it's not compiled yet.
1472 FloodWithOneShot(Handle<SharedFunctionInfo>(js_function->shared()));
1473 }
1474 }
1475 }
1476
1477 // Fill the current function with one-shot break points even for step in on
1478 // a call target as the function called might be a native function for
1479 // which step in will not stop. It also prepares for stepping in
1480 // getters/setters.
1481 FloodWithOneShot(shared);
1482
1483 if (is_load_or_store) {
1484 // Remember source position and frame to handle step in getter/setter. If
1485 // there is a custom getter/setter it will be handled in
1486 // Object::Get/SetPropertyWithCallback, otherwise the step action will be
1487 // propagated on the next Debug::Break.
1488 thread_local_.last_statement_position_ =
1489 debug_info->code()->SourceStatementPosition(frame->pc());
1490 thread_local_.last_fp_ = frame->fp();
1491 }
1492
1493 // Step in or Step in min
1494 it.PrepareStepIn();
1495 ActivateStepIn(frame);
1496 }
1497 }
1498
1499
1500 // Check whether the current debug break should be reported to the debugger. It
1501 // is used to have step next and step in only report break back to the debugger
1502 // if on a different frame or in a different statement. In some situations
1503 // there will be several break points in the same statement when the code is
1504 // flooded with one-shot break points. This function helps to perform several
1505 // steps before reporting break back to the debugger.
StepNextContinue(BreakLocationIterator * break_location_iterator,JavaScriptFrame * frame)1506 bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
1507 JavaScriptFrame* frame) {
1508 // StepNext and StepOut shouldn't bring us deeper in code, so last frame
1509 // shouldn't be a parent of current frame.
1510 if (thread_local_.last_step_action_ == StepNext ||
1511 thread_local_.last_step_action_ == StepOut) {
1512 if (frame->fp() < thread_local_.last_fp_) return true;
1513 }
1514
1515 // If the step last action was step next or step in make sure that a new
1516 // statement is hit.
1517 if (thread_local_.last_step_action_ == StepNext ||
1518 thread_local_.last_step_action_ == StepIn) {
1519 // Never continue if returning from function.
1520 if (break_location_iterator->IsExit()) return false;
1521
1522 // Continue if we are still on the same frame and in the same statement.
1523 int current_statement_position =
1524 break_location_iterator->code()->SourceStatementPosition(frame->pc());
1525 return thread_local_.last_fp_ == frame->fp() &&
1526 thread_local_.last_statement_position_ == current_statement_position;
1527 }
1528
1529 // No step next action - don't continue.
1530 return false;
1531 }
1532
1533
1534 // Check whether the code object at the specified address is a debug break code
1535 // object.
IsDebugBreak(Address addr)1536 bool Debug::IsDebugBreak(Address addr) {
1537 Code* code = Code::GetCodeFromTargetAddress(addr);
1538 return code->ic_state() == DEBUG_BREAK;
1539 }
1540
1541
1542 // Check whether a code stub with the specified major key is a possible break
1543 // point location when looking for source break locations.
IsSourceBreakStub(Code * code)1544 bool Debug::IsSourceBreakStub(Code* code) {
1545 CodeStub::Major major_key = CodeStub::GetMajorKey(code);
1546 return major_key == CodeStub::CallFunction;
1547 }
1548
1549
1550 // Check whether a code stub with the specified major key is a possible break
1551 // location.
IsBreakStub(Code * code)1552 bool Debug::IsBreakStub(Code* code) {
1553 CodeStub::Major major_key = CodeStub::GetMajorKey(code);
1554 return major_key == CodeStub::CallFunction;
1555 }
1556
1557
1558 // Find the builtin to use for invoking the debug break
FindDebugBreak(Handle<Code> code,RelocInfo::Mode mode)1559 Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
1560 Isolate* isolate = Isolate::Current();
1561
1562 // Find the builtin debug break function matching the calling convention
1563 // used by the call site.
1564 if (code->is_inline_cache_stub()) {
1565 switch (code->kind()) {
1566 case Code::CALL_IC:
1567 case Code::KEYED_CALL_IC:
1568 return isolate->stub_cache()->ComputeCallDebugBreak(
1569 code->arguments_count(), code->kind());
1570
1571 case Code::LOAD_IC:
1572 return isolate->builtins()->LoadIC_DebugBreak();
1573
1574 case Code::STORE_IC:
1575 return isolate->builtins()->StoreIC_DebugBreak();
1576
1577 case Code::KEYED_LOAD_IC:
1578 return isolate->builtins()->KeyedLoadIC_DebugBreak();
1579
1580 case Code::KEYED_STORE_IC:
1581 return isolate->builtins()->KeyedStoreIC_DebugBreak();
1582
1583 default:
1584 UNREACHABLE();
1585 }
1586 }
1587 if (RelocInfo::IsConstructCall(mode)) {
1588 if (code->has_function_cache()) {
1589 return isolate->builtins()->CallConstructStub_Recording_DebugBreak();
1590 } else {
1591 return isolate->builtins()->CallConstructStub_DebugBreak();
1592 }
1593 }
1594 if (code->kind() == Code::STUB) {
1595 ASSERT(code->major_key() == CodeStub::CallFunction);
1596 if (code->has_function_cache()) {
1597 return isolate->builtins()->CallFunctionStub_Recording_DebugBreak();
1598 } else {
1599 return isolate->builtins()->CallFunctionStub_DebugBreak();
1600 }
1601 }
1602
1603 UNREACHABLE();
1604 return Handle<Code>::null();
1605 }
1606
1607
1608 // Simple function for returning the source positions for active break points.
GetSourceBreakLocations(Handle<SharedFunctionInfo> shared)1609 Handle<Object> Debug::GetSourceBreakLocations(
1610 Handle<SharedFunctionInfo> shared) {
1611 Isolate* isolate = Isolate::Current();
1612 Heap* heap = isolate->heap();
1613 if (!HasDebugInfo(shared)) return Handle<Object>(heap->undefined_value());
1614 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1615 if (debug_info->GetBreakPointCount() == 0) {
1616 return Handle<Object>(heap->undefined_value());
1617 }
1618 Handle<FixedArray> locations =
1619 isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount());
1620 int count = 0;
1621 for (int i = 0; i < debug_info->break_points()->length(); i++) {
1622 if (!debug_info->break_points()->get(i)->IsUndefined()) {
1623 BreakPointInfo* break_point_info =
1624 BreakPointInfo::cast(debug_info->break_points()->get(i));
1625 if (break_point_info->GetBreakPointCount() > 0) {
1626 locations->set(count++, break_point_info->statement_position());
1627 }
1628 }
1629 }
1630 return locations;
1631 }
1632
1633
NewBreak(StackFrame::Id break_frame_id)1634 void Debug::NewBreak(StackFrame::Id break_frame_id) {
1635 thread_local_.break_frame_id_ = break_frame_id;
1636 thread_local_.break_id_ = ++thread_local_.break_count_;
1637 }
1638
1639
SetBreak(StackFrame::Id break_frame_id,int break_id)1640 void Debug::SetBreak(StackFrame::Id break_frame_id, int break_id) {
1641 thread_local_.break_frame_id_ = break_frame_id;
1642 thread_local_.break_id_ = break_id;
1643 }
1644
1645
1646 // Handle stepping into a function.
HandleStepIn(Handle<JSFunction> function,Handle<Object> holder,Address fp,bool is_constructor)1647 void Debug::HandleStepIn(Handle<JSFunction> function,
1648 Handle<Object> holder,
1649 Address fp,
1650 bool is_constructor) {
1651 // If the frame pointer is not supplied by the caller find it.
1652 if (fp == 0) {
1653 StackFrameIterator it;
1654 it.Advance();
1655 // For constructor functions skip another frame.
1656 if (is_constructor) {
1657 ASSERT(it.frame()->is_construct());
1658 it.Advance();
1659 }
1660 fp = it.frame()->fp();
1661 }
1662
1663 // Flood the function with one-shot break points if it is called from where
1664 // step into was requested.
1665 if (fp == step_in_fp()) {
1666 if (function->shared()->bound()) {
1667 // Handle Function.prototype.bind
1668 Debug::FloodBoundFunctionWithOneShot(function);
1669 } else if (!function->IsBuiltin()) {
1670 // Don't allow step into functions in the native context.
1671 if (function->shared()->code() ==
1672 Isolate::Current()->builtins()->builtin(Builtins::kFunctionApply) ||
1673 function->shared()->code() ==
1674 Isolate::Current()->builtins()->builtin(Builtins::kFunctionCall)) {
1675 // Handle function.apply and function.call separately to flood the
1676 // function to be called and not the code for Builtins::FunctionApply or
1677 // Builtins::FunctionCall. The receiver of call/apply is the target
1678 // function.
1679 if (!holder.is_null() && holder->IsJSFunction() &&
1680 !JSFunction::cast(*holder)->IsBuiltin()) {
1681 Handle<SharedFunctionInfo> shared_info(
1682 JSFunction::cast(*holder)->shared());
1683 Debug::FloodWithOneShot(shared_info);
1684 }
1685 } else {
1686 Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1687 }
1688 }
1689 }
1690 }
1691
1692
ClearStepping()1693 void Debug::ClearStepping() {
1694 // Clear the various stepping setup.
1695 ClearOneShot();
1696 ClearStepIn();
1697 ClearStepOut();
1698 ClearStepNext();
1699
1700 // Clear multiple step counter.
1701 thread_local_.step_count_ = 0;
1702 }
1703
1704 // Clears all the one-shot break points that are currently set. Normally this
1705 // function is called each time a break point is hit as one shot break points
1706 // are used to support stepping.
ClearOneShot()1707 void Debug::ClearOneShot() {
1708 // The current implementation just runs through all the breakpoints. When the
1709 // last break point for a function is removed that function is automatically
1710 // removed from the list.
1711
1712 DebugInfoListNode* node = debug_info_list_;
1713 while (node != NULL) {
1714 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1715 while (!it.Done()) {
1716 it.ClearOneShot();
1717 it.Next();
1718 }
1719 node = node->next();
1720 }
1721 }
1722
1723
ActivateStepIn(StackFrame * frame)1724 void Debug::ActivateStepIn(StackFrame* frame) {
1725 ASSERT(!StepOutActive());
1726 thread_local_.step_into_fp_ = frame->fp();
1727 }
1728
1729
ClearStepIn()1730 void Debug::ClearStepIn() {
1731 thread_local_.step_into_fp_ = 0;
1732 }
1733
1734
ActivateStepOut(StackFrame * frame)1735 void Debug::ActivateStepOut(StackFrame* frame) {
1736 ASSERT(!StepInActive());
1737 thread_local_.step_out_fp_ = frame->fp();
1738 }
1739
1740
ClearStepOut()1741 void Debug::ClearStepOut() {
1742 thread_local_.step_out_fp_ = 0;
1743 }
1744
1745
ClearStepNext()1746 void Debug::ClearStepNext() {
1747 thread_local_.last_step_action_ = StepNone;
1748 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
1749 thread_local_.last_fp_ = 0;
1750 }
1751
1752
1753 // Helper function to compile full code for debugging. This code will
1754 // have debug break slots and deoptimization
1755 // information. Deoptimization information is required in case that an
1756 // optimized version of this function is still activated on the
1757 // stack. It will also make sure that the full code is compiled with
1758 // the same flags as the previous version - that is flags which can
1759 // change the code generated. The current method of mapping from
1760 // already compiled full code without debug break slots to full code
1761 // with debug break slots depends on the generated code is otherwise
1762 // exactly the same.
CompileFullCodeForDebugging(Handle<SharedFunctionInfo> shared,Handle<Code> current_code)1763 static bool CompileFullCodeForDebugging(Handle<SharedFunctionInfo> shared,
1764 Handle<Code> current_code) {
1765 ASSERT(!current_code->has_debug_break_slots());
1766
1767 CompilationInfo info(shared);
1768 info.MarkCompilingForDebugging(current_code);
1769 ASSERT(!info.shared_info()->is_compiled());
1770 ASSERT(!info.isolate()->has_pending_exception());
1771
1772 // Use compile lazy which will end up compiling the full code in the
1773 // configuration configured above.
1774 bool result = Compiler::CompileLazy(&info);
1775 ASSERT(result != Isolate::Current()->has_pending_exception());
1776 info.isolate()->clear_pending_exception();
1777 #if DEBUG
1778 if (result) {
1779 Handle<Code> new_code(shared->code());
1780 ASSERT(new_code->has_debug_break_slots());
1781 ASSERT(current_code->is_compiled_optimizable() ==
1782 new_code->is_compiled_optimizable());
1783 }
1784 #endif
1785 return result;
1786 }
1787
1788
CollectActiveFunctionsFromThread(Isolate * isolate,ThreadLocalTop * top,List<Handle<JSFunction>> * active_functions,Object * active_code_marker)1789 static void CollectActiveFunctionsFromThread(
1790 Isolate* isolate,
1791 ThreadLocalTop* top,
1792 List<Handle<JSFunction> >* active_functions,
1793 Object* active_code_marker) {
1794 // Find all non-optimized code functions with activation frames
1795 // on the stack. This includes functions which have optimized
1796 // activations (including inlined functions) on the stack as the
1797 // non-optimized code is needed for the lazy deoptimization.
1798 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
1799 JavaScriptFrame* frame = it.frame();
1800 if (frame->is_optimized()) {
1801 List<JSFunction*> functions(Compiler::kMaxInliningLevels + 1);
1802 frame->GetFunctions(&functions);
1803 for (int i = 0; i < functions.length(); i++) {
1804 JSFunction* function = functions[i];
1805 active_functions->Add(Handle<JSFunction>(function));
1806 function->shared()->code()->set_gc_metadata(active_code_marker);
1807 }
1808 } else if (frame->function()->IsJSFunction()) {
1809 JSFunction* function = JSFunction::cast(frame->function());
1810 ASSERT(frame->LookupCode()->kind() == Code::FUNCTION);
1811 active_functions->Add(Handle<JSFunction>(function));
1812 function->shared()->code()->set_gc_metadata(active_code_marker);
1813 }
1814 }
1815 }
1816
1817
RedirectActivationsToRecompiledCodeOnThread(Isolate * isolate,ThreadLocalTop * top)1818 static void RedirectActivationsToRecompiledCodeOnThread(
1819 Isolate* isolate,
1820 ThreadLocalTop* top) {
1821 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
1822 JavaScriptFrame* frame = it.frame();
1823
1824 if (frame->is_optimized() || !frame->function()->IsJSFunction()) continue;
1825
1826 JSFunction* function = JSFunction::cast(frame->function());
1827
1828 ASSERT(frame->LookupCode()->kind() == Code::FUNCTION);
1829
1830 Handle<Code> frame_code(frame->LookupCode());
1831 if (frame_code->has_debug_break_slots()) continue;
1832
1833 Handle<Code> new_code(function->shared()->code());
1834 if (new_code->kind() != Code::FUNCTION ||
1835 !new_code->has_debug_break_slots()) {
1836 continue;
1837 }
1838
1839 intptr_t delta = frame->pc() - frame_code->instruction_start();
1840 int debug_break_slot_count = 0;
1841 int mask = RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT);
1842 for (RelocIterator it(*new_code, mask); !it.done(); it.next()) {
1843 // Check if the pc in the new code with debug break
1844 // slots is before this slot.
1845 RelocInfo* info = it.rinfo();
1846 int debug_break_slot_bytes =
1847 debug_break_slot_count * Assembler::kDebugBreakSlotLength;
1848 intptr_t new_delta =
1849 info->pc() -
1850 new_code->instruction_start() -
1851 debug_break_slot_bytes;
1852 if (new_delta > delta) {
1853 break;
1854 }
1855
1856 // Passed a debug break slot in the full code with debug
1857 // break slots.
1858 debug_break_slot_count++;
1859 }
1860 if (frame_code->has_self_optimization_header() &&
1861 !new_code->has_self_optimization_header()) {
1862 delta -= FullCodeGenerator::self_optimization_header_size();
1863 } else {
1864 ASSERT(frame_code->has_self_optimization_header() ==
1865 new_code->has_self_optimization_header());
1866 }
1867 int debug_break_slot_bytes =
1868 debug_break_slot_count * Assembler::kDebugBreakSlotLength;
1869 if (FLAG_trace_deopt) {
1870 PrintF("Replacing code %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) "
1871 "with %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) "
1872 "for debugging, "
1873 "changing pc from %08" V8PRIxPTR " to %08" V8PRIxPTR "\n",
1874 reinterpret_cast<intptr_t>(
1875 frame_code->instruction_start()),
1876 reinterpret_cast<intptr_t>(
1877 frame_code->instruction_start()) +
1878 frame_code->instruction_size(),
1879 frame_code->instruction_size(),
1880 reinterpret_cast<intptr_t>(new_code->instruction_start()),
1881 reinterpret_cast<intptr_t>(new_code->instruction_start()) +
1882 new_code->instruction_size(),
1883 new_code->instruction_size(),
1884 reinterpret_cast<intptr_t>(frame->pc()),
1885 reinterpret_cast<intptr_t>(new_code->instruction_start()) +
1886 delta + debug_break_slot_bytes);
1887 }
1888
1889 // Patch the return address to return into the code with
1890 // debug break slots.
1891 frame->set_pc(
1892 new_code->instruction_start() + delta + debug_break_slot_bytes);
1893 }
1894 }
1895
1896
1897 class ActiveFunctionsCollector : public ThreadVisitor {
1898 public:
ActiveFunctionsCollector(List<Handle<JSFunction>> * active_functions,Object * active_code_marker)1899 explicit ActiveFunctionsCollector(List<Handle<JSFunction> >* active_functions,
1900 Object* active_code_marker)
1901 : active_functions_(active_functions),
1902 active_code_marker_(active_code_marker) { }
1903
VisitThread(Isolate * isolate,ThreadLocalTop * top)1904 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
1905 CollectActiveFunctionsFromThread(isolate,
1906 top,
1907 active_functions_,
1908 active_code_marker_);
1909 }
1910
1911 private:
1912 List<Handle<JSFunction> >* active_functions_;
1913 Object* active_code_marker_;
1914 };
1915
1916
1917 class ActiveFunctionsRedirector : public ThreadVisitor {
1918 public:
VisitThread(Isolate * isolate,ThreadLocalTop * top)1919 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
1920 RedirectActivationsToRecompiledCodeOnThread(isolate, top);
1921 }
1922 };
1923
1924
PrepareForBreakPoints()1925 void Debug::PrepareForBreakPoints() {
1926 // If preparing for the first break point make sure to deoptimize all
1927 // functions as debugging does not work with optimized code.
1928 if (!has_break_points_) {
1929 Deoptimizer::DeoptimizeAll();
1930
1931 Handle<Code> lazy_compile =
1932 Handle<Code>(isolate_->builtins()->builtin(Builtins::kLazyCompile));
1933
1934 // Keep the list of activated functions in a handlified list as it
1935 // is used both in GC and non-GC code.
1936 List<Handle<JSFunction> > active_functions(100);
1937
1938 {
1939 // We are going to iterate heap to find all functions without
1940 // debug break slots.
1941 isolate_->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1942 "preparing for breakpoints");
1943
1944 // Ensure no GC in this scope as we are going to use gc_metadata
1945 // field in the Code object to mark active functions.
1946 AssertNoAllocation no_allocation;
1947
1948 Object* active_code_marker = isolate_->heap()->the_hole_value();
1949
1950 CollectActiveFunctionsFromThread(isolate_,
1951 isolate_->thread_local_top(),
1952 &active_functions,
1953 active_code_marker);
1954 ActiveFunctionsCollector active_functions_collector(&active_functions,
1955 active_code_marker);
1956 isolate_->thread_manager()->IterateArchivedThreads(
1957 &active_functions_collector);
1958
1959 // Scan the heap for all non-optimized functions which have no
1960 // debug break slots and are not active or inlined into an active
1961 // function and mark them for lazy compilation.
1962 HeapIterator iterator;
1963 HeapObject* obj = NULL;
1964 while (((obj = iterator.next()) != NULL)) {
1965 if (obj->IsJSFunction()) {
1966 JSFunction* function = JSFunction::cast(obj);
1967 SharedFunctionInfo* shared = function->shared();
1968 if (shared->allows_lazy_compilation() &&
1969 shared->script()->IsScript() &&
1970 function->code()->kind() == Code::FUNCTION &&
1971 !function->code()->has_debug_break_slots() &&
1972 shared->code()->gc_metadata() != active_code_marker) {
1973 function->set_code(*lazy_compile);
1974 function->shared()->set_code(*lazy_compile);
1975 }
1976 }
1977 }
1978
1979 // Clear gc_metadata field.
1980 for (int i = 0; i < active_functions.length(); i++) {
1981 Handle<JSFunction> function = active_functions[i];
1982 function->shared()->code()->set_gc_metadata(Smi::FromInt(0));
1983 }
1984 }
1985
1986 // Now recompile all functions with activation frames and and
1987 // patch the return address to run in the new compiled code.
1988 for (int i = 0; i < active_functions.length(); i++) {
1989 Handle<JSFunction> function = active_functions[i];
1990
1991 if (function->code()->kind() == Code::FUNCTION &&
1992 function->code()->has_debug_break_slots()) {
1993 // Nothing to do. Function code already had debug break slots.
1994 continue;
1995 }
1996
1997 Handle<SharedFunctionInfo> shared(function->shared());
1998 // If recompilation is not possible just skip it.
1999 if (shared->is_toplevel() ||
2000 !shared->allows_lazy_compilation() ||
2001 shared->code()->kind() == Code::BUILTIN) {
2002 continue;
2003 }
2004
2005 // Make sure that the shared full code is compiled with debug
2006 // break slots.
2007 if (!shared->code()->has_debug_break_slots()) {
2008 // Try to compile the full code with debug break slots. If it
2009 // fails just keep the current code.
2010 Handle<Code> current_code(function->shared()->code());
2011 ZoneScope zone_scope(isolate_, DELETE_ON_EXIT);
2012 shared->set_code(*lazy_compile);
2013 bool prev_force_debugger_active =
2014 isolate_->debugger()->force_debugger_active();
2015 isolate_->debugger()->set_force_debugger_active(true);
2016 ASSERT(current_code->kind() == Code::FUNCTION);
2017 CompileFullCodeForDebugging(shared, current_code);
2018 isolate_->debugger()->set_force_debugger_active(
2019 prev_force_debugger_active);
2020 if (!shared->is_compiled()) {
2021 shared->set_code(*current_code);
2022 continue;
2023 }
2024 }
2025
2026 // Keep function code in sync with shared function info.
2027 function->set_code(shared->code());
2028 }
2029
2030 RedirectActivationsToRecompiledCodeOnThread(isolate_,
2031 isolate_->thread_local_top());
2032
2033 ActiveFunctionsRedirector active_functions_redirector;
2034 isolate_->thread_manager()->IterateArchivedThreads(
2035 &active_functions_redirector);
2036 }
2037 }
2038
2039
2040 // Ensures the debug information is present for shared.
EnsureDebugInfo(Handle<SharedFunctionInfo> shared)2041 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
2042 // Return if we already have the debug info for shared.
2043 if (HasDebugInfo(shared)) {
2044 ASSERT(shared->is_compiled());
2045 return true;
2046 }
2047
2048 // Ensure shared in compiled. Return false if this failed.
2049 if (!SharedFunctionInfo::EnsureCompiled(shared, CLEAR_EXCEPTION)) {
2050 return false;
2051 }
2052
2053 // Create the debug info object.
2054 Handle<DebugInfo> debug_info = FACTORY->NewDebugInfo(shared);
2055
2056 // Add debug info to the list.
2057 DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
2058 node->set_next(debug_info_list_);
2059 debug_info_list_ = node;
2060
2061 // Now there is at least one break point.
2062 has_break_points_ = true;
2063
2064 return true;
2065 }
2066
2067
RemoveDebugInfo(Handle<DebugInfo> debug_info)2068 void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
2069 ASSERT(debug_info_list_ != NULL);
2070 // Run through the debug info objects to find this one and remove it.
2071 DebugInfoListNode* prev = NULL;
2072 DebugInfoListNode* current = debug_info_list_;
2073 while (current != NULL) {
2074 if (*current->debug_info() == *debug_info) {
2075 // Unlink from list. If prev is NULL we are looking at the first element.
2076 if (prev == NULL) {
2077 debug_info_list_ = current->next();
2078 } else {
2079 prev->set_next(current->next());
2080 }
2081 current->debug_info()->shared()->set_debug_info(
2082 isolate_->heap()->undefined_value());
2083 delete current;
2084
2085 // If there are no more debug info objects there are not more break
2086 // points.
2087 has_break_points_ = debug_info_list_ != NULL;
2088
2089 return;
2090 }
2091 // Move to next in list.
2092 prev = current;
2093 current = current->next();
2094 }
2095 UNREACHABLE();
2096 }
2097
2098
SetAfterBreakTarget(JavaScriptFrame * frame)2099 void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
2100 HandleScope scope(isolate_);
2101
2102 PrepareForBreakPoints();
2103
2104 // Get the executing function in which the debug break occurred.
2105 Handle<SharedFunctionInfo> shared =
2106 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
2107 if (!EnsureDebugInfo(shared)) {
2108 // Return if we failed to retrieve the debug info.
2109 return;
2110 }
2111 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
2112 Handle<Code> code(debug_info->code());
2113 Handle<Code> original_code(debug_info->original_code());
2114 #ifdef DEBUG
2115 // Get the code which is actually executing.
2116 Handle<Code> frame_code(frame->LookupCode());
2117 ASSERT(frame_code.is_identical_to(code));
2118 #endif
2119
2120 // Find the call address in the running code. This address holds the call to
2121 // either a DebugBreakXXX or to the debug break return entry code if the
2122 // break point is still active after processing the break point.
2123 Address addr = frame->pc() - Assembler::kCallTargetAddressOffset;
2124
2125 // Check if the location is at JS exit or debug break slot.
2126 bool at_js_return = false;
2127 bool break_at_js_return_active = false;
2128 bool at_debug_break_slot = false;
2129 RelocIterator it(debug_info->code());
2130 while (!it.done() && !at_js_return && !at_debug_break_slot) {
2131 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
2132 at_js_return = (it.rinfo()->pc() ==
2133 addr - Assembler::kPatchReturnSequenceAddressOffset);
2134 break_at_js_return_active = it.rinfo()->IsPatchedReturnSequence();
2135 }
2136 if (RelocInfo::IsDebugBreakSlot(it.rinfo()->rmode())) {
2137 at_debug_break_slot = (it.rinfo()->pc() ==
2138 addr - Assembler::kPatchDebugBreakSlotAddressOffset);
2139 }
2140 it.next();
2141 }
2142
2143 // Handle the jump to continue execution after break point depending on the
2144 // break location.
2145 if (at_js_return) {
2146 // If the break point as return is still active jump to the corresponding
2147 // place in the original code. If not the break point was removed during
2148 // break point processing.
2149 if (break_at_js_return_active) {
2150 addr += original_code->instruction_start() - code->instruction_start();
2151 }
2152
2153 // Move back to where the call instruction sequence started.
2154 thread_local_.after_break_target_ =
2155 addr - Assembler::kPatchReturnSequenceAddressOffset;
2156 } else if (at_debug_break_slot) {
2157 // Address of where the debug break slot starts.
2158 addr = addr - Assembler::kPatchDebugBreakSlotAddressOffset;
2159
2160 // Continue just after the slot.
2161 thread_local_.after_break_target_ = addr + Assembler::kDebugBreakSlotLength;
2162 } else if (IsDebugBreak(Assembler::target_address_at(addr))) {
2163 // We now know that there is still a debug break call at the target address,
2164 // so the break point is still there and the original code will hold the
2165 // address to jump to in order to complete the call which is replaced by a
2166 // call to DebugBreakXXX.
2167
2168 // Find the corresponding address in the original code.
2169 addr += original_code->instruction_start() - code->instruction_start();
2170
2171 // Install jump to the call address in the original code. This will be the
2172 // call which was overwritten by the call to DebugBreakXXX.
2173 thread_local_.after_break_target_ = Assembler::target_address_at(addr);
2174 } else {
2175 // There is no longer a break point present. Don't try to look in the
2176 // original code as the running code will have the right address. This takes
2177 // care of the case where the last break point is removed from the function
2178 // and therefore no "original code" is available.
2179 thread_local_.after_break_target_ = Assembler::target_address_at(addr);
2180 }
2181 }
2182
2183
IsBreakAtReturn(JavaScriptFrame * frame)2184 bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
2185 HandleScope scope(isolate_);
2186
2187 // If there are no break points this cannot be break at return, as
2188 // the debugger statement and stack guard bebug break cannot be at
2189 // return.
2190 if (!has_break_points_) {
2191 return false;
2192 }
2193
2194 PrepareForBreakPoints();
2195
2196 // Get the executing function in which the debug break occurred.
2197 Handle<SharedFunctionInfo> shared =
2198 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
2199 if (!EnsureDebugInfo(shared)) {
2200 // Return if we failed to retrieve the debug info.
2201 return false;
2202 }
2203 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
2204 Handle<Code> code(debug_info->code());
2205 #ifdef DEBUG
2206 // Get the code which is actually executing.
2207 Handle<Code> frame_code(frame->LookupCode());
2208 ASSERT(frame_code.is_identical_to(code));
2209 #endif
2210
2211 // Find the call address in the running code.
2212 Address addr = frame->pc() - Assembler::kCallTargetAddressOffset;
2213
2214 // Check if the location is at JS return.
2215 RelocIterator it(debug_info->code());
2216 while (!it.done()) {
2217 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
2218 return (it.rinfo()->pc() ==
2219 addr - Assembler::kPatchReturnSequenceAddressOffset);
2220 }
2221 it.next();
2222 }
2223 return false;
2224 }
2225
2226
FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,FrameDropMode mode,Object ** restarter_frame_function_pointer)2227 void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
2228 FrameDropMode mode,
2229 Object** restarter_frame_function_pointer) {
2230 thread_local_.frame_drop_mode_ = mode;
2231 thread_local_.break_frame_id_ = new_break_frame_id;
2232 thread_local_.restarter_frame_function_pointer_ =
2233 restarter_frame_function_pointer;
2234 }
2235
2236
IsDebugGlobal(GlobalObject * global)2237 bool Debug::IsDebugGlobal(GlobalObject* global) {
2238 return IsLoaded() && global == debug_context()->global();
2239 }
2240
2241
ClearMirrorCache()2242 void Debug::ClearMirrorCache() {
2243 PostponeInterruptsScope postpone(isolate_);
2244 HandleScope scope(isolate_);
2245 ASSERT(isolate_->context() == *Debug::debug_context());
2246
2247 // Clear the mirror cache.
2248 Handle<String> function_name =
2249 isolate_->factory()->LookupSymbol(CStrVector("ClearMirrorCache"));
2250 Handle<Object> fun(Isolate::Current()->global()->GetPropertyNoExceptionThrown(
2251 *function_name));
2252 ASSERT(fun->IsJSFunction());
2253 bool caught_exception;
2254 Execution::TryCall(Handle<JSFunction>::cast(fun),
2255 Handle<JSObject>(Debug::debug_context()->global()),
2256 0, NULL, &caught_exception);
2257 }
2258
2259
CreateScriptCache()2260 void Debug::CreateScriptCache() {
2261 Heap* heap = isolate_->heap();
2262 HandleScope scope(isolate_);
2263
2264 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
2265 // rid of all the cached script wrappers and the second gets rid of the
2266 // scripts which are no longer referenced. The second also sweeps precisely,
2267 // which saves us doing yet another GC to make the heap iterable.
2268 heap->CollectAllGarbage(Heap::kNoGCFlags, "Debug::CreateScriptCache");
2269 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
2270 "Debug::CreateScriptCache");
2271
2272 ASSERT(script_cache_ == NULL);
2273 script_cache_ = new ScriptCache();
2274
2275 // Scan heap for Script objects.
2276 int count = 0;
2277 HeapIterator iterator;
2278 AssertNoAllocation no_allocation;
2279
2280 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
2281 if (obj->IsScript() && Script::cast(obj)->HasValidSource()) {
2282 script_cache_->Add(Handle<Script>(Script::cast(obj)));
2283 count++;
2284 }
2285 }
2286 }
2287
2288
DestroyScriptCache()2289 void Debug::DestroyScriptCache() {
2290 // Get rid of the script cache if it was created.
2291 if (script_cache_ != NULL) {
2292 delete script_cache_;
2293 script_cache_ = NULL;
2294 }
2295 }
2296
2297
AddScriptToScriptCache(Handle<Script> script)2298 void Debug::AddScriptToScriptCache(Handle<Script> script) {
2299 if (script_cache_ != NULL) {
2300 script_cache_->Add(script);
2301 }
2302 }
2303
2304
GetLoadedScripts()2305 Handle<FixedArray> Debug::GetLoadedScripts() {
2306 // Create and fill the script cache when the loaded scripts is requested for
2307 // the first time.
2308 if (script_cache_ == NULL) {
2309 CreateScriptCache();
2310 }
2311
2312 // If the script cache is not active just return an empty array.
2313 ASSERT(script_cache_ != NULL);
2314 if (script_cache_ == NULL) {
2315 isolate_->factory()->NewFixedArray(0);
2316 }
2317
2318 // Perform GC to get unreferenced scripts evicted from the cache before
2319 // returning the content.
2320 isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags,
2321 "Debug::GetLoadedScripts");
2322
2323 // Get the scripts from the cache.
2324 return script_cache_->GetScripts();
2325 }
2326
2327
AfterGarbageCollection()2328 void Debug::AfterGarbageCollection() {
2329 // Generate events for collected scripts.
2330 if (script_cache_ != NULL) {
2331 script_cache_->ProcessCollectedScripts();
2332 }
2333 }
2334
2335
Debugger(Isolate * isolate)2336 Debugger::Debugger(Isolate* isolate)
2337 : debugger_access_(isolate->debugger_access()),
2338 event_listener_(Handle<Object>()),
2339 event_listener_data_(Handle<Object>()),
2340 compiling_natives_(false),
2341 is_loading_debugger_(false),
2342 never_unload_debugger_(false),
2343 force_debugger_active_(false),
2344 message_handler_(NULL),
2345 debugger_unload_pending_(false),
2346 host_dispatch_handler_(NULL),
2347 dispatch_handler_access_(OS::CreateMutex()),
2348 debug_message_dispatch_handler_(NULL),
2349 message_dispatch_helper_thread_(NULL),
2350 host_dispatch_micros_(100 * 1000),
2351 agent_(NULL),
2352 command_queue_(isolate->logger(), kQueueInitialSize),
2353 command_received_(OS::CreateSemaphore(0)),
2354 event_command_queue_(isolate->logger(), kQueueInitialSize),
2355 isolate_(isolate) {
2356 }
2357
2358
~Debugger()2359 Debugger::~Debugger() {
2360 delete dispatch_handler_access_;
2361 dispatch_handler_access_ = 0;
2362 delete command_received_;
2363 command_received_ = 0;
2364 }
2365
2366
MakeJSObject(Vector<const char> constructor_name,int argc,Handle<Object> argv[],bool * caught_exception)2367 Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
2368 int argc,
2369 Handle<Object> argv[],
2370 bool* caught_exception) {
2371 ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
2372
2373 // Create the execution state object.
2374 Handle<String> constructor_str =
2375 isolate_->factory()->LookupSymbol(constructor_name);
2376 Handle<Object> constructor(
2377 isolate_->global()->GetPropertyNoExceptionThrown(*constructor_str));
2378 ASSERT(constructor->IsJSFunction());
2379 if (!constructor->IsJSFunction()) {
2380 *caught_exception = true;
2381 return isolate_->factory()->undefined_value();
2382 }
2383 Handle<Object> js_object = Execution::TryCall(
2384 Handle<JSFunction>::cast(constructor),
2385 Handle<JSObject>(isolate_->debug()->debug_context()->global()),
2386 argc,
2387 argv,
2388 caught_exception);
2389 return js_object;
2390 }
2391
2392
MakeExecutionState(bool * caught_exception)2393 Handle<Object> Debugger::MakeExecutionState(bool* caught_exception) {
2394 // Create the execution state object.
2395 Handle<Object> break_id = isolate_->factory()->NewNumberFromInt(
2396 isolate_->debug()->break_id());
2397 Handle<Object> argv[] = { break_id };
2398 return MakeJSObject(CStrVector("MakeExecutionState"),
2399 ARRAY_SIZE(argv),
2400 argv,
2401 caught_exception);
2402 }
2403
2404
MakeBreakEvent(Handle<Object> exec_state,Handle<Object> break_points_hit,bool * caught_exception)2405 Handle<Object> Debugger::MakeBreakEvent(Handle<Object> exec_state,
2406 Handle<Object> break_points_hit,
2407 bool* caught_exception) {
2408 // Create the new break event object.
2409 Handle<Object> argv[] = { exec_state, break_points_hit };
2410 return MakeJSObject(CStrVector("MakeBreakEvent"),
2411 ARRAY_SIZE(argv),
2412 argv,
2413 caught_exception);
2414 }
2415
2416
MakeExceptionEvent(Handle<Object> exec_state,Handle<Object> exception,bool uncaught,bool * caught_exception)2417 Handle<Object> Debugger::MakeExceptionEvent(Handle<Object> exec_state,
2418 Handle<Object> exception,
2419 bool uncaught,
2420 bool* caught_exception) {
2421 Factory* factory = isolate_->factory();
2422 // Create the new exception event object.
2423 Handle<Object> argv[] = { exec_state,
2424 exception,
2425 factory->ToBoolean(uncaught) };
2426 return MakeJSObject(CStrVector("MakeExceptionEvent"),
2427 ARRAY_SIZE(argv),
2428 argv,
2429 caught_exception);
2430 }
2431
2432
MakeNewFunctionEvent(Handle<Object> function,bool * caught_exception)2433 Handle<Object> Debugger::MakeNewFunctionEvent(Handle<Object> function,
2434 bool* caught_exception) {
2435 // Create the new function event object.
2436 Handle<Object> argv[] = { function };
2437 return MakeJSObject(CStrVector("MakeNewFunctionEvent"),
2438 ARRAY_SIZE(argv),
2439 argv,
2440 caught_exception);
2441 }
2442
2443
MakeCompileEvent(Handle<Script> script,bool before,bool * caught_exception)2444 Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
2445 bool before,
2446 bool* caught_exception) {
2447 Factory* factory = isolate_->factory();
2448 // Create the compile event object.
2449 Handle<Object> exec_state = MakeExecutionState(caught_exception);
2450 Handle<Object> script_wrapper = GetScriptWrapper(script);
2451 Handle<Object> argv[] = { exec_state,
2452 script_wrapper,
2453 factory->ToBoolean(before) };
2454 return MakeJSObject(CStrVector("MakeCompileEvent"),
2455 ARRAY_SIZE(argv),
2456 argv,
2457 caught_exception);
2458 }
2459
2460
MakeScriptCollectedEvent(int id,bool * caught_exception)2461 Handle<Object> Debugger::MakeScriptCollectedEvent(int id,
2462 bool* caught_exception) {
2463 // Create the script collected event object.
2464 Handle<Object> exec_state = MakeExecutionState(caught_exception);
2465 Handle<Object> id_object = Handle<Smi>(Smi::FromInt(id));
2466 Handle<Object> argv[] = { exec_state, id_object };
2467
2468 return MakeJSObject(CStrVector("MakeScriptCollectedEvent"),
2469 ARRAY_SIZE(argv),
2470 argv,
2471 caught_exception);
2472 }
2473
2474
OnException(Handle<Object> exception,bool uncaught)2475 void Debugger::OnException(Handle<Object> exception, bool uncaught) {
2476 HandleScope scope(isolate_);
2477 Debug* debug = isolate_->debug();
2478
2479 // Bail out based on state or if there is no listener for this event
2480 if (debug->InDebugger()) return;
2481 if (!Debugger::EventActive(v8::Exception)) return;
2482
2483 // Bail out if exception breaks are not active
2484 if (uncaught) {
2485 // Uncaught exceptions are reported by either flags.
2486 if (!(debug->break_on_uncaught_exception() ||
2487 debug->break_on_exception())) return;
2488 } else {
2489 // Caught exceptions are reported is activated.
2490 if (!debug->break_on_exception()) return;
2491 }
2492
2493 // Enter the debugger.
2494 EnterDebugger debugger;
2495 if (debugger.FailedToEnter()) return;
2496
2497 // Clear all current stepping setup.
2498 debug->ClearStepping();
2499 // Create the event data object.
2500 bool caught_exception = false;
2501 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2502 Handle<Object> event_data;
2503 if (!caught_exception) {
2504 event_data = MakeExceptionEvent(exec_state, exception, uncaught,
2505 &caught_exception);
2506 }
2507 // Bail out and don't call debugger if exception.
2508 if (caught_exception) {
2509 return;
2510 }
2511
2512 // Process debug event.
2513 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false);
2514 // Return to continue execution from where the exception was thrown.
2515 }
2516
2517
OnDebugBreak(Handle<Object> break_points_hit,bool auto_continue)2518 void Debugger::OnDebugBreak(Handle<Object> break_points_hit,
2519 bool auto_continue) {
2520 HandleScope scope(isolate_);
2521
2522 // Debugger has already been entered by caller.
2523 ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
2524
2525 // Bail out if there is no listener for this event
2526 if (!Debugger::EventActive(v8::Break)) return;
2527
2528 // Debugger must be entered in advance.
2529 ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
2530
2531 // Create the event data object.
2532 bool caught_exception = false;
2533 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2534 Handle<Object> event_data;
2535 if (!caught_exception) {
2536 event_data = MakeBreakEvent(exec_state, break_points_hit,
2537 &caught_exception);
2538 }
2539 // Bail out and don't call debugger if exception.
2540 if (caught_exception) {
2541 return;
2542 }
2543
2544 // Process debug event.
2545 ProcessDebugEvent(v8::Break,
2546 Handle<JSObject>::cast(event_data),
2547 auto_continue);
2548 }
2549
2550
OnBeforeCompile(Handle<Script> script)2551 void Debugger::OnBeforeCompile(Handle<Script> script) {
2552 HandleScope scope(isolate_);
2553
2554 // Bail out based on state or if there is no listener for this event
2555 if (isolate_->debug()->InDebugger()) return;
2556 if (compiling_natives()) return;
2557 if (!EventActive(v8::BeforeCompile)) return;
2558
2559 // Enter the debugger.
2560 EnterDebugger debugger;
2561 if (debugger.FailedToEnter()) return;
2562
2563 // Create the event data object.
2564 bool caught_exception = false;
2565 Handle<Object> event_data = MakeCompileEvent(script, true, &caught_exception);
2566 // Bail out and don't call debugger if exception.
2567 if (caught_exception) {
2568 return;
2569 }
2570
2571 // Process debug event.
2572 ProcessDebugEvent(v8::BeforeCompile,
2573 Handle<JSObject>::cast(event_data),
2574 true);
2575 }
2576
2577
2578 // Handle debugger actions when a new script is compiled.
OnAfterCompile(Handle<Script> script,AfterCompileFlags after_compile_flags)2579 void Debugger::OnAfterCompile(Handle<Script> script,
2580 AfterCompileFlags after_compile_flags) {
2581 HandleScope scope(isolate_);
2582 Debug* debug = isolate_->debug();
2583
2584 // Add the newly compiled script to the script cache.
2585 debug->AddScriptToScriptCache(script);
2586
2587 // No more to do if not debugging.
2588 if (!IsDebuggerActive()) return;
2589
2590 // No compile events while compiling natives.
2591 if (compiling_natives()) return;
2592
2593 // Store whether in debugger before entering debugger.
2594 bool in_debugger = debug->InDebugger();
2595
2596 // Enter the debugger.
2597 EnterDebugger debugger;
2598 if (debugger.FailedToEnter()) return;
2599
2600 // If debugging there might be script break points registered for this
2601 // script. Make sure that these break points are set.
2602
2603 // Get the function UpdateScriptBreakPoints (defined in debug-debugger.js).
2604 Handle<String> update_script_break_points_symbol =
2605 isolate_->factory()->LookupAsciiSymbol("UpdateScriptBreakPoints");
2606 Handle<Object> update_script_break_points =
2607 Handle<Object>(debug->debug_context()->global()->
2608 GetPropertyNoExceptionThrown(*update_script_break_points_symbol));
2609 if (!update_script_break_points->IsJSFunction()) {
2610 return;
2611 }
2612 ASSERT(update_script_break_points->IsJSFunction());
2613
2614 // Wrap the script object in a proper JS object before passing it
2615 // to JavaScript.
2616 Handle<JSValue> wrapper = GetScriptWrapper(script);
2617
2618 // Call UpdateScriptBreakPoints expect no exceptions.
2619 bool caught_exception;
2620 Handle<Object> argv[] = { wrapper };
2621 Execution::TryCall(Handle<JSFunction>::cast(update_script_break_points),
2622 Isolate::Current()->js_builtins_object(),
2623 ARRAY_SIZE(argv),
2624 argv,
2625 &caught_exception);
2626 if (caught_exception) {
2627 return;
2628 }
2629 // Bail out based on state or if there is no listener for this event
2630 if (in_debugger && (after_compile_flags & SEND_WHEN_DEBUGGING) == 0) return;
2631 if (!Debugger::EventActive(v8::AfterCompile)) return;
2632
2633 // Create the compile state object.
2634 Handle<Object> event_data = MakeCompileEvent(script,
2635 false,
2636 &caught_exception);
2637 // Bail out and don't call debugger if exception.
2638 if (caught_exception) {
2639 return;
2640 }
2641 // Process debug event.
2642 ProcessDebugEvent(v8::AfterCompile,
2643 Handle<JSObject>::cast(event_data),
2644 true);
2645 }
2646
2647
OnScriptCollected(int id)2648 void Debugger::OnScriptCollected(int id) {
2649 HandleScope scope(isolate_);
2650
2651 // No more to do if not debugging.
2652 if (!IsDebuggerActive()) return;
2653 if (!Debugger::EventActive(v8::ScriptCollected)) return;
2654
2655 // Enter the debugger.
2656 EnterDebugger debugger;
2657 if (debugger.FailedToEnter()) return;
2658
2659 // Create the script collected state object.
2660 bool caught_exception = false;
2661 Handle<Object> event_data = MakeScriptCollectedEvent(id,
2662 &caught_exception);
2663 // Bail out and don't call debugger if exception.
2664 if (caught_exception) {
2665 return;
2666 }
2667
2668 // Process debug event.
2669 ProcessDebugEvent(v8::ScriptCollected,
2670 Handle<JSObject>::cast(event_data),
2671 true);
2672 }
2673
2674
ProcessDebugEvent(v8::DebugEvent event,Handle<JSObject> event_data,bool auto_continue)2675 void Debugger::ProcessDebugEvent(v8::DebugEvent event,
2676 Handle<JSObject> event_data,
2677 bool auto_continue) {
2678 HandleScope scope(isolate_);
2679
2680 // Clear any pending debug break if this is a real break.
2681 if (!auto_continue) {
2682 isolate_->debug()->clear_interrupt_pending(DEBUGBREAK);
2683 }
2684
2685 // Create the execution state.
2686 bool caught_exception = false;
2687 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2688 if (caught_exception) {
2689 return;
2690 }
2691 // First notify the message handler if any.
2692 if (message_handler_ != NULL) {
2693 NotifyMessageHandler(event,
2694 Handle<JSObject>::cast(exec_state),
2695 event_data,
2696 auto_continue);
2697 }
2698 // Notify registered debug event listener. This can be either a C or
2699 // a JavaScript function. Don't call event listener for v8::Break
2700 // here, if it's only a debug command -- they will be processed later.
2701 if ((event != v8::Break || !auto_continue) && !event_listener_.is_null()) {
2702 CallEventCallback(event, exec_state, event_data, NULL);
2703 }
2704 // Process pending debug commands.
2705 if (event == v8::Break) {
2706 while (!event_command_queue_.IsEmpty()) {
2707 CommandMessage command = event_command_queue_.Get();
2708 if (!event_listener_.is_null()) {
2709 CallEventCallback(v8::BreakForCommand,
2710 exec_state,
2711 event_data,
2712 command.client_data());
2713 }
2714 command.Dispose();
2715 }
2716 }
2717 }
2718
2719
CallEventCallback(v8::DebugEvent event,Handle<Object> exec_state,Handle<Object> event_data,v8::Debug::ClientData * client_data)2720 void Debugger::CallEventCallback(v8::DebugEvent event,
2721 Handle<Object> exec_state,
2722 Handle<Object> event_data,
2723 v8::Debug::ClientData* client_data) {
2724 if (event_listener_->IsForeign()) {
2725 CallCEventCallback(event, exec_state, event_data, client_data);
2726 } else {
2727 CallJSEventCallback(event, exec_state, event_data);
2728 }
2729 }
2730
2731
CallCEventCallback(v8::DebugEvent event,Handle<Object> exec_state,Handle<Object> event_data,v8::Debug::ClientData * client_data)2732 void Debugger::CallCEventCallback(v8::DebugEvent event,
2733 Handle<Object> exec_state,
2734 Handle<Object> event_data,
2735 v8::Debug::ClientData* client_data) {
2736 Handle<Foreign> callback_obj(Handle<Foreign>::cast(event_listener_));
2737 v8::Debug::EventCallback2 callback =
2738 FUNCTION_CAST<v8::Debug::EventCallback2>(
2739 callback_obj->foreign_address());
2740 EventDetailsImpl event_details(
2741 event,
2742 Handle<JSObject>::cast(exec_state),
2743 Handle<JSObject>::cast(event_data),
2744 event_listener_data_,
2745 client_data);
2746 callback(event_details);
2747 }
2748
2749
CallJSEventCallback(v8::DebugEvent event,Handle<Object> exec_state,Handle<Object> event_data)2750 void Debugger::CallJSEventCallback(v8::DebugEvent event,
2751 Handle<Object> exec_state,
2752 Handle<Object> event_data) {
2753 ASSERT(event_listener_->IsJSFunction());
2754 Handle<JSFunction> fun(Handle<JSFunction>::cast(event_listener_));
2755
2756 // Invoke the JavaScript debug event listener.
2757 Handle<Object> argv[] = { Handle<Object>(Smi::FromInt(event)),
2758 exec_state,
2759 event_data,
2760 event_listener_data_ };
2761 bool caught_exception;
2762 Execution::TryCall(fun,
2763 isolate_->global(),
2764 ARRAY_SIZE(argv),
2765 argv,
2766 &caught_exception);
2767 // Silently ignore exceptions from debug event listeners.
2768 }
2769
2770
GetDebugContext()2771 Handle<Context> Debugger::GetDebugContext() {
2772 never_unload_debugger_ = true;
2773 EnterDebugger debugger;
2774 return isolate_->debug()->debug_context();
2775 }
2776
2777
UnloadDebugger()2778 void Debugger::UnloadDebugger() {
2779 Debug* debug = isolate_->debug();
2780
2781 // Make sure that there are no breakpoints left.
2782 debug->ClearAllBreakPoints();
2783
2784 // Unload the debugger if feasible.
2785 if (!never_unload_debugger_) {
2786 debug->Unload();
2787 }
2788
2789 // Clear the flag indicating that the debugger should be unloaded.
2790 debugger_unload_pending_ = false;
2791 }
2792
2793
NotifyMessageHandler(v8::DebugEvent event,Handle<JSObject> exec_state,Handle<JSObject> event_data,bool auto_continue)2794 void Debugger::NotifyMessageHandler(v8::DebugEvent event,
2795 Handle<JSObject> exec_state,
2796 Handle<JSObject> event_data,
2797 bool auto_continue) {
2798 HandleScope scope(isolate_);
2799
2800 if (!isolate_->debug()->Load()) return;
2801
2802 // Process the individual events.
2803 bool sendEventMessage = false;
2804 switch (event) {
2805 case v8::Break:
2806 case v8::BreakForCommand:
2807 sendEventMessage = !auto_continue;
2808 break;
2809 case v8::Exception:
2810 sendEventMessage = true;
2811 break;
2812 case v8::BeforeCompile:
2813 break;
2814 case v8::AfterCompile:
2815 sendEventMessage = true;
2816 break;
2817 case v8::ScriptCollected:
2818 sendEventMessage = true;
2819 break;
2820 case v8::NewFunction:
2821 break;
2822 default:
2823 UNREACHABLE();
2824 }
2825
2826 // The debug command interrupt flag might have been set when the command was
2827 // added. It should be enough to clear the flag only once while we are in the
2828 // debugger.
2829 ASSERT(isolate_->debug()->InDebugger());
2830 isolate_->stack_guard()->Continue(DEBUGCOMMAND);
2831
2832 // Notify the debugger that a debug event has occurred unless auto continue is
2833 // active in which case no event is send.
2834 if (sendEventMessage) {
2835 MessageImpl message = MessageImpl::NewEvent(
2836 event,
2837 auto_continue,
2838 Handle<JSObject>::cast(exec_state),
2839 Handle<JSObject>::cast(event_data));
2840 InvokeMessageHandler(message);
2841 }
2842
2843 // If auto continue don't make the event cause a break, but process messages
2844 // in the queue if any. For script collected events don't even process
2845 // messages in the queue as the execution state might not be what is expected
2846 // by the client.
2847 if ((auto_continue && !HasCommands()) || event == v8::ScriptCollected) {
2848 return;
2849 }
2850
2851 v8::TryCatch try_catch;
2852
2853 // DebugCommandProcessor goes here.
2854 v8::Local<v8::Object> cmd_processor;
2855 {
2856 v8::Local<v8::Object> api_exec_state =
2857 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state));
2858 v8::Local<v8::String> fun_name =
2859 v8::String::New("debugCommandProcessor");
2860 v8::Local<v8::Function> fun =
2861 v8::Function::Cast(*api_exec_state->Get(fun_name));
2862
2863 v8::Handle<v8::Boolean> running =
2864 auto_continue ? v8::True() : v8::False();
2865 static const int kArgc = 1;
2866 v8::Handle<Value> argv[kArgc] = { running };
2867 cmd_processor = v8::Object::Cast(*fun->Call(api_exec_state, kArgc, argv));
2868 if (try_catch.HasCaught()) {
2869 PrintLn(try_catch.Exception());
2870 return;
2871 }
2872 }
2873
2874 bool running = auto_continue;
2875
2876 // Process requests from the debugger.
2877 while (true) {
2878 // Wait for new command in the queue.
2879 if (Debugger::host_dispatch_handler_) {
2880 // In case there is a host dispatch - do periodic dispatches.
2881 if (!command_received_->Wait(host_dispatch_micros_)) {
2882 // Timout expired, do the dispatch.
2883 Debugger::host_dispatch_handler_();
2884 continue;
2885 }
2886 } else {
2887 // In case there is no host dispatch - just wait.
2888 command_received_->Wait();
2889 }
2890
2891 // Get the command from the queue.
2892 CommandMessage command = command_queue_.Get();
2893 isolate_->logger()->DebugTag(
2894 "Got request from command queue, in interactive loop.");
2895 if (!Debugger::IsDebuggerActive()) {
2896 // Delete command text and user data.
2897 command.Dispose();
2898 return;
2899 }
2900
2901 // Invoke JavaScript to process the debug request.
2902 v8::Local<v8::String> fun_name;
2903 v8::Local<v8::Function> fun;
2904 v8::Local<v8::Value> request;
2905 v8::TryCatch try_catch;
2906 fun_name = v8::String::New("processDebugRequest");
2907 fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
2908
2909 request = v8::String::New(command.text().start(),
2910 command.text().length());
2911 static const int kArgc = 1;
2912 v8::Handle<Value> argv[kArgc] = { request };
2913 v8::Local<v8::Value> response_val = fun->Call(cmd_processor, kArgc, argv);
2914
2915 // Get the response.
2916 v8::Local<v8::String> response;
2917 if (!try_catch.HasCaught()) {
2918 // Get response string.
2919 if (!response_val->IsUndefined()) {
2920 response = v8::String::Cast(*response_val);
2921 } else {
2922 response = v8::String::New("");
2923 }
2924
2925 // Log the JSON request/response.
2926 if (FLAG_trace_debug_json) {
2927 PrintLn(request);
2928 PrintLn(response);
2929 }
2930
2931 // Get the running state.
2932 fun_name = v8::String::New("isRunning");
2933 fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
2934 static const int kArgc = 1;
2935 v8::Handle<Value> argv[kArgc] = { response };
2936 v8::Local<v8::Value> running_val = fun->Call(cmd_processor, kArgc, argv);
2937 if (!try_catch.HasCaught()) {
2938 running = running_val->ToBoolean()->Value();
2939 }
2940 } else {
2941 // In case of failure the result text is the exception text.
2942 response = try_catch.Exception()->ToString();
2943 }
2944
2945 // Return the result.
2946 MessageImpl message = MessageImpl::NewResponse(
2947 event,
2948 running,
2949 Handle<JSObject>::cast(exec_state),
2950 Handle<JSObject>::cast(event_data),
2951 Handle<String>(Utils::OpenHandle(*response)),
2952 command.client_data());
2953 InvokeMessageHandler(message);
2954 command.Dispose();
2955
2956 // Return from debug event processing if either the VM is put into the
2957 // running state (through a continue command) or auto continue is active
2958 // and there are no more commands queued.
2959 if (running && !HasCommands()) {
2960 return;
2961 }
2962 }
2963 }
2964
2965
SetEventListener(Handle<Object> callback,Handle<Object> data)2966 void Debugger::SetEventListener(Handle<Object> callback,
2967 Handle<Object> data) {
2968 HandleScope scope(isolate_);
2969 GlobalHandles* global_handles = isolate_->global_handles();
2970
2971 // Clear the global handles for the event listener and the event listener data
2972 // object.
2973 if (!event_listener_.is_null()) {
2974 global_handles->Destroy(
2975 reinterpret_cast<Object**>(event_listener_.location()));
2976 event_listener_ = Handle<Object>();
2977 }
2978 if (!event_listener_data_.is_null()) {
2979 global_handles->Destroy(
2980 reinterpret_cast<Object**>(event_listener_data_.location()));
2981 event_listener_data_ = Handle<Object>();
2982 }
2983
2984 // If there is a new debug event listener register it together with its data
2985 // object.
2986 if (!callback->IsUndefined() && !callback->IsNull()) {
2987 event_listener_ = Handle<Object>::cast(
2988 global_handles->Create(*callback));
2989 if (data.is_null()) {
2990 data = isolate_->factory()->undefined_value();
2991 }
2992 event_listener_data_ = Handle<Object>::cast(
2993 global_handles->Create(*data));
2994 }
2995
2996 ListenersChanged();
2997 }
2998
2999
SetMessageHandler(v8::Debug::MessageHandler2 handler)3000 void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) {
3001 ScopedLock with(debugger_access_);
3002
3003 message_handler_ = handler;
3004 ListenersChanged();
3005 if (handler == NULL) {
3006 // Send an empty command to the debugger if in a break to make JavaScript
3007 // run again if the debugger is closed.
3008 if (isolate_->debug()->InDebugger()) {
3009 ProcessCommand(Vector<const uint16_t>::empty());
3010 }
3011 }
3012 }
3013
3014
ListenersChanged()3015 void Debugger::ListenersChanged() {
3016 if (IsDebuggerActive()) {
3017 // Disable the compilation cache when the debugger is active.
3018 isolate_->compilation_cache()->Disable();
3019 debugger_unload_pending_ = false;
3020 } else {
3021 isolate_->compilation_cache()->Enable();
3022 // Unload the debugger if event listener and message handler cleared.
3023 // Schedule this for later, because we may be in non-V8 thread.
3024 debugger_unload_pending_ = true;
3025 }
3026 }
3027
3028
SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,int period)3029 void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
3030 int period) {
3031 host_dispatch_handler_ = handler;
3032 host_dispatch_micros_ = period * 1000;
3033 }
3034
3035
SetDebugMessageDispatchHandler(v8::Debug::DebugMessageDispatchHandler handler,bool provide_locker)3036 void Debugger::SetDebugMessageDispatchHandler(
3037 v8::Debug::DebugMessageDispatchHandler handler, bool provide_locker) {
3038 ScopedLock with(dispatch_handler_access_);
3039 debug_message_dispatch_handler_ = handler;
3040
3041 if (provide_locker && message_dispatch_helper_thread_ == NULL) {
3042 message_dispatch_helper_thread_ = new MessageDispatchHelperThread(isolate_);
3043 message_dispatch_helper_thread_->Start();
3044 }
3045 }
3046
3047
3048 // Calls the registered debug message handler. This callback is part of the
3049 // public API.
InvokeMessageHandler(MessageImpl message)3050 void Debugger::InvokeMessageHandler(MessageImpl message) {
3051 ScopedLock with(debugger_access_);
3052
3053 if (message_handler_ != NULL) {
3054 message_handler_(message);
3055 }
3056 }
3057
3058
3059 // Puts a command coming from the public API on the queue. Creates
3060 // a copy of the command string managed by the debugger. Up to this
3061 // point, the command data was managed by the API client. Called
3062 // by the API client thread.
ProcessCommand(Vector<const uint16_t> command,v8::Debug::ClientData * client_data)3063 void Debugger::ProcessCommand(Vector<const uint16_t> command,
3064 v8::Debug::ClientData* client_data) {
3065 // Need to cast away const.
3066 CommandMessage message = CommandMessage::New(
3067 Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
3068 command.length()),
3069 client_data);
3070 isolate_->logger()->DebugTag("Put command on command_queue.");
3071 command_queue_.Put(message);
3072 command_received_->Signal();
3073
3074 // Set the debug command break flag to have the command processed.
3075 if (!isolate_->debug()->InDebugger()) {
3076 isolate_->stack_guard()->DebugCommand();
3077 }
3078
3079 MessageDispatchHelperThread* dispatch_thread;
3080 {
3081 ScopedLock with(dispatch_handler_access_);
3082 dispatch_thread = message_dispatch_helper_thread_;
3083 }
3084
3085 if (dispatch_thread == NULL) {
3086 CallMessageDispatchHandler();
3087 } else {
3088 dispatch_thread->Schedule();
3089 }
3090 }
3091
3092
HasCommands()3093 bool Debugger::HasCommands() {
3094 return !command_queue_.IsEmpty();
3095 }
3096
3097
EnqueueDebugCommand(v8::Debug::ClientData * client_data)3098 void Debugger::EnqueueDebugCommand(v8::Debug::ClientData* client_data) {
3099 CommandMessage message = CommandMessage::New(Vector<uint16_t>(), client_data);
3100 event_command_queue_.Put(message);
3101
3102 // Set the debug command break flag to have the command processed.
3103 if (!isolate_->debug()->InDebugger()) {
3104 isolate_->stack_guard()->DebugCommand();
3105 }
3106 }
3107
3108
IsDebuggerActive()3109 bool Debugger::IsDebuggerActive() {
3110 ScopedLock with(debugger_access_);
3111
3112 return message_handler_ != NULL ||
3113 !event_listener_.is_null() ||
3114 force_debugger_active_;
3115 }
3116
3117
Call(Handle<JSFunction> fun,Handle<Object> data,bool * pending_exception)3118 Handle<Object> Debugger::Call(Handle<JSFunction> fun,
3119 Handle<Object> data,
3120 bool* pending_exception) {
3121 // When calling functions in the debugger prevent it from beeing unloaded.
3122 Debugger::never_unload_debugger_ = true;
3123
3124 // Enter the debugger.
3125 EnterDebugger debugger;
3126 if (debugger.FailedToEnter()) {
3127 return isolate_->factory()->undefined_value();
3128 }
3129
3130 // Create the execution state.
3131 bool caught_exception = false;
3132 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
3133 if (caught_exception) {
3134 return isolate_->factory()->undefined_value();
3135 }
3136
3137 Handle<Object> argv[] = { exec_state, data };
3138 Handle<Object> result = Execution::Call(
3139 fun,
3140 Handle<Object>(isolate_->debug()->debug_context_->global_proxy()),
3141 ARRAY_SIZE(argv),
3142 argv,
3143 pending_exception);
3144 return result;
3145 }
3146
3147
StubMessageHandler2(const v8::Debug::Message & message)3148 static void StubMessageHandler2(const v8::Debug::Message& message) {
3149 // Simply ignore message.
3150 }
3151
3152
StartAgent(const char * name,int port,bool wait_for_connection)3153 bool Debugger::StartAgent(const char* name, int port,
3154 bool wait_for_connection) {
3155 ASSERT(Isolate::Current() == isolate_);
3156 if (wait_for_connection) {
3157 // Suspend V8 if it is already running or set V8 to suspend whenever
3158 // it starts.
3159 // Provide stub message handler; V8 auto-continues each suspend
3160 // when there is no message handler; we doesn't need it.
3161 // Once become suspended, V8 will stay so indefinitely long, until remote
3162 // debugger connects and issues "continue" command.
3163 Debugger::message_handler_ = StubMessageHandler2;
3164 v8::Debug::DebugBreak();
3165 }
3166
3167 if (Socket::SetUp()) {
3168 if (agent_ == NULL) {
3169 agent_ = new DebuggerAgent(name, port);
3170 agent_->Start();
3171 }
3172 return true;
3173 }
3174
3175 return false;
3176 }
3177
3178
StopAgent()3179 void Debugger::StopAgent() {
3180 ASSERT(Isolate::Current() == isolate_);
3181 if (agent_ != NULL) {
3182 agent_->Shutdown();
3183 agent_->Join();
3184 delete agent_;
3185 agent_ = NULL;
3186 }
3187 }
3188
3189
WaitForAgent()3190 void Debugger::WaitForAgent() {
3191 ASSERT(Isolate::Current() == isolate_);
3192 if (agent_ != NULL)
3193 agent_->WaitUntilListening();
3194 }
3195
3196
CallMessageDispatchHandler()3197 void Debugger::CallMessageDispatchHandler() {
3198 v8::Debug::DebugMessageDispatchHandler handler;
3199 {
3200 ScopedLock with(dispatch_handler_access_);
3201 handler = Debugger::debug_message_dispatch_handler_;
3202 }
3203 if (handler != NULL) {
3204 handler();
3205 }
3206 }
3207
3208
EnterDebugger()3209 EnterDebugger::EnterDebugger()
3210 : isolate_(Isolate::Current()),
3211 prev_(isolate_->debug()->debugger_entry()),
3212 it_(isolate_),
3213 has_js_frames_(!it_.done()),
3214 save_(isolate_) {
3215 Debug* debug = isolate_->debug();
3216 ASSERT(prev_ != NULL || !debug->is_interrupt_pending(PREEMPT));
3217 ASSERT(prev_ != NULL || !debug->is_interrupt_pending(DEBUGBREAK));
3218
3219 // Link recursive debugger entry.
3220 debug->set_debugger_entry(this);
3221
3222 // Store the previous break id and frame id.
3223 break_id_ = debug->break_id();
3224 break_frame_id_ = debug->break_frame_id();
3225
3226 // Create the new break info. If there is no JavaScript frames there is no
3227 // break frame id.
3228 if (has_js_frames_) {
3229 debug->NewBreak(it_.frame()->id());
3230 } else {
3231 debug->NewBreak(StackFrame::NO_ID);
3232 }
3233
3234 // Make sure that debugger is loaded and enter the debugger context.
3235 load_failed_ = !debug->Load();
3236 if (!load_failed_) {
3237 // NOTE the member variable save which saves the previous context before
3238 // this change.
3239 isolate_->set_context(*debug->debug_context());
3240 }
3241 }
3242
3243
~EnterDebugger()3244 EnterDebugger::~EnterDebugger() {
3245 ASSERT(Isolate::Current() == isolate_);
3246 Debug* debug = isolate_->debug();
3247
3248 // Restore to the previous break state.
3249 debug->SetBreak(break_frame_id_, break_id_);
3250
3251 // Check for leaving the debugger.
3252 if (!load_failed_ && prev_ == NULL) {
3253 // Clear mirror cache when leaving the debugger. Skip this if there is a
3254 // pending exception as clearing the mirror cache calls back into
3255 // JavaScript. This can happen if the v8::Debug::Call is used in which
3256 // case the exception should end up in the calling code.
3257 if (!isolate_->has_pending_exception()) {
3258 // Try to avoid any pending debug break breaking in the clear mirror
3259 // cache JavaScript code.
3260 if (isolate_->stack_guard()->IsDebugBreak()) {
3261 debug->set_interrupts_pending(DEBUGBREAK);
3262 isolate_->stack_guard()->Continue(DEBUGBREAK);
3263 }
3264 debug->ClearMirrorCache();
3265 }
3266
3267 // Request preemption and debug break when leaving the last debugger entry
3268 // if any of these where recorded while debugging.
3269 if (debug->is_interrupt_pending(PREEMPT)) {
3270 // This re-scheduling of preemption is to avoid starvation in some
3271 // debugging scenarios.
3272 debug->clear_interrupt_pending(PREEMPT);
3273 isolate_->stack_guard()->Preempt();
3274 }
3275 if (debug->is_interrupt_pending(DEBUGBREAK)) {
3276 debug->clear_interrupt_pending(DEBUGBREAK);
3277 isolate_->stack_guard()->DebugBreak();
3278 }
3279
3280 // If there are commands in the queue when leaving the debugger request
3281 // that these commands are processed.
3282 if (isolate_->debugger()->HasCommands()) {
3283 isolate_->stack_guard()->DebugCommand();
3284 }
3285
3286 // If leaving the debugger with the debugger no longer active unload it.
3287 if (!isolate_->debugger()->IsDebuggerActive()) {
3288 isolate_->debugger()->UnloadDebugger();
3289 }
3290 }
3291
3292 // Leaving this debugger entry.
3293 debug->set_debugger_entry(prev_);
3294 }
3295
3296
NewEvent(DebugEvent event,bool running,Handle<JSObject> exec_state,Handle<JSObject> event_data)3297 MessageImpl MessageImpl::NewEvent(DebugEvent event,
3298 bool running,
3299 Handle<JSObject> exec_state,
3300 Handle<JSObject> event_data) {
3301 MessageImpl message(true, event, running,
3302 exec_state, event_data, Handle<String>(), NULL);
3303 return message;
3304 }
3305
3306
NewResponse(DebugEvent event,bool running,Handle<JSObject> exec_state,Handle<JSObject> event_data,Handle<String> response_json,v8::Debug::ClientData * client_data)3307 MessageImpl MessageImpl::NewResponse(DebugEvent event,
3308 bool running,
3309 Handle<JSObject> exec_state,
3310 Handle<JSObject> event_data,
3311 Handle<String> response_json,
3312 v8::Debug::ClientData* client_data) {
3313 MessageImpl message(false, event, running,
3314 exec_state, event_data, response_json, client_data);
3315 return message;
3316 }
3317
3318
MessageImpl(bool is_event,DebugEvent event,bool running,Handle<JSObject> exec_state,Handle<JSObject> event_data,Handle<String> response_json,v8::Debug::ClientData * client_data)3319 MessageImpl::MessageImpl(bool is_event,
3320 DebugEvent event,
3321 bool running,
3322 Handle<JSObject> exec_state,
3323 Handle<JSObject> event_data,
3324 Handle<String> response_json,
3325 v8::Debug::ClientData* client_data)
3326 : is_event_(is_event),
3327 event_(event),
3328 running_(running),
3329 exec_state_(exec_state),
3330 event_data_(event_data),
3331 response_json_(response_json),
3332 client_data_(client_data) {}
3333
3334
IsEvent() const3335 bool MessageImpl::IsEvent() const {
3336 return is_event_;
3337 }
3338
3339
IsResponse() const3340 bool MessageImpl::IsResponse() const {
3341 return !is_event_;
3342 }
3343
3344
GetEvent() const3345 DebugEvent MessageImpl::GetEvent() const {
3346 return event_;
3347 }
3348
3349
WillStartRunning() const3350 bool MessageImpl::WillStartRunning() const {
3351 return running_;
3352 }
3353
3354
GetExecutionState() const3355 v8::Handle<v8::Object> MessageImpl::GetExecutionState() const {
3356 return v8::Utils::ToLocal(exec_state_);
3357 }
3358
3359
GetEventData() const3360 v8::Handle<v8::Object> MessageImpl::GetEventData() const {
3361 return v8::Utils::ToLocal(event_data_);
3362 }
3363
3364
GetJSON() const3365 v8::Handle<v8::String> MessageImpl::GetJSON() const {
3366 v8::HandleScope scope;
3367
3368 if (IsEvent()) {
3369 // Call toJSONProtocol on the debug event object.
3370 Handle<Object> fun = GetProperty(event_data_, "toJSONProtocol");
3371 if (!fun->IsJSFunction()) {
3372 return v8::Handle<v8::String>();
3373 }
3374 bool caught_exception;
3375 Handle<Object> json = Execution::TryCall(Handle<JSFunction>::cast(fun),
3376 event_data_,
3377 0, NULL, &caught_exception);
3378 if (caught_exception || !json->IsString()) {
3379 return v8::Handle<v8::String>();
3380 }
3381 return scope.Close(v8::Utils::ToLocal(Handle<String>::cast(json)));
3382 } else {
3383 return v8::Utils::ToLocal(response_json_);
3384 }
3385 }
3386
3387
GetEventContext() const3388 v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
3389 Isolate* isolate = Isolate::Current();
3390 v8::Handle<v8::Context> context = GetDebugEventContext(isolate);
3391 // Isolate::context() may be NULL when "script collected" event occures.
3392 ASSERT(!context.IsEmpty() || event_ == v8::ScriptCollected);
3393 return context;
3394 }
3395
3396
GetClientData() const3397 v8::Debug::ClientData* MessageImpl::GetClientData() const {
3398 return client_data_;
3399 }
3400
3401
EventDetailsImpl(DebugEvent event,Handle<JSObject> exec_state,Handle<JSObject> event_data,Handle<Object> callback_data,v8::Debug::ClientData * client_data)3402 EventDetailsImpl::EventDetailsImpl(DebugEvent event,
3403 Handle<JSObject> exec_state,
3404 Handle<JSObject> event_data,
3405 Handle<Object> callback_data,
3406 v8::Debug::ClientData* client_data)
3407 : event_(event),
3408 exec_state_(exec_state),
3409 event_data_(event_data),
3410 callback_data_(callback_data),
3411 client_data_(client_data) {}
3412
3413
GetEvent() const3414 DebugEvent EventDetailsImpl::GetEvent() const {
3415 return event_;
3416 }
3417
3418
GetExecutionState() const3419 v8::Handle<v8::Object> EventDetailsImpl::GetExecutionState() const {
3420 return v8::Utils::ToLocal(exec_state_);
3421 }
3422
3423
GetEventData() const3424 v8::Handle<v8::Object> EventDetailsImpl::GetEventData() const {
3425 return v8::Utils::ToLocal(event_data_);
3426 }
3427
3428
GetEventContext() const3429 v8::Handle<v8::Context> EventDetailsImpl::GetEventContext() const {
3430 return GetDebugEventContext(Isolate::Current());
3431 }
3432
3433
GetCallbackData() const3434 v8::Handle<v8::Value> EventDetailsImpl::GetCallbackData() const {
3435 return v8::Utils::ToLocal(callback_data_);
3436 }
3437
3438
GetClientData() const3439 v8::Debug::ClientData* EventDetailsImpl::GetClientData() const {
3440 return client_data_;
3441 }
3442
3443
CommandMessage()3444 CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()),
3445 client_data_(NULL) {
3446 }
3447
3448
CommandMessage(const Vector<uint16_t> & text,v8::Debug::ClientData * data)3449 CommandMessage::CommandMessage(const Vector<uint16_t>& text,
3450 v8::Debug::ClientData* data)
3451 : text_(text),
3452 client_data_(data) {
3453 }
3454
3455
~CommandMessage()3456 CommandMessage::~CommandMessage() {
3457 }
3458
3459
Dispose()3460 void CommandMessage::Dispose() {
3461 text_.Dispose();
3462 delete client_data_;
3463 client_data_ = NULL;
3464 }
3465
3466
New(const Vector<uint16_t> & command,v8::Debug::ClientData * data)3467 CommandMessage CommandMessage::New(const Vector<uint16_t>& command,
3468 v8::Debug::ClientData* data) {
3469 return CommandMessage(command.Clone(), data);
3470 }
3471
3472
CommandMessageQueue(int size)3473 CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0),
3474 size_(size) {
3475 messages_ = NewArray<CommandMessage>(size);
3476 }
3477
3478
~CommandMessageQueue()3479 CommandMessageQueue::~CommandMessageQueue() {
3480 while (!IsEmpty()) {
3481 CommandMessage m = Get();
3482 m.Dispose();
3483 }
3484 DeleteArray(messages_);
3485 }
3486
3487
Get()3488 CommandMessage CommandMessageQueue::Get() {
3489 ASSERT(!IsEmpty());
3490 int result = start_;
3491 start_ = (start_ + 1) % size_;
3492 return messages_[result];
3493 }
3494
3495
Put(const CommandMessage & message)3496 void CommandMessageQueue::Put(const CommandMessage& message) {
3497 if ((end_ + 1) % size_ == start_) {
3498 Expand();
3499 }
3500 messages_[end_] = message;
3501 end_ = (end_ + 1) % size_;
3502 }
3503
3504
Expand()3505 void CommandMessageQueue::Expand() {
3506 CommandMessageQueue new_queue(size_ * 2);
3507 while (!IsEmpty()) {
3508 new_queue.Put(Get());
3509 }
3510 CommandMessage* array_to_free = messages_;
3511 *this = new_queue;
3512 new_queue.messages_ = array_to_free;
3513 // Make the new_queue empty so that it doesn't call Dispose on any messages.
3514 new_queue.start_ = new_queue.end_;
3515 // Automatic destructor called on new_queue, freeing array_to_free.
3516 }
3517
3518
LockingCommandMessageQueue(Logger * logger,int size)3519 LockingCommandMessageQueue::LockingCommandMessageQueue(Logger* logger, int size)
3520 : logger_(logger), queue_(size) {
3521 lock_ = OS::CreateMutex();
3522 }
3523
3524
~LockingCommandMessageQueue()3525 LockingCommandMessageQueue::~LockingCommandMessageQueue() {
3526 delete lock_;
3527 }
3528
3529
IsEmpty() const3530 bool LockingCommandMessageQueue::IsEmpty() const {
3531 ScopedLock sl(lock_);
3532 return queue_.IsEmpty();
3533 }
3534
3535
Get()3536 CommandMessage LockingCommandMessageQueue::Get() {
3537 ScopedLock sl(lock_);
3538 CommandMessage result = queue_.Get();
3539 logger_->DebugEvent("Get", result.text());
3540 return result;
3541 }
3542
3543
Put(const CommandMessage & message)3544 void LockingCommandMessageQueue::Put(const CommandMessage& message) {
3545 ScopedLock sl(lock_);
3546 queue_.Put(message);
3547 logger_->DebugEvent("Put", message.text());
3548 }
3549
3550
Clear()3551 void LockingCommandMessageQueue::Clear() {
3552 ScopedLock sl(lock_);
3553 queue_.Clear();
3554 }
3555
3556
MessageDispatchHelperThread(Isolate * isolate)3557 MessageDispatchHelperThread::MessageDispatchHelperThread(Isolate* isolate)
3558 : Thread("v8:MsgDispHelpr"),
3559 sem_(OS::CreateSemaphore(0)), mutex_(OS::CreateMutex()),
3560 already_signalled_(false) {
3561 }
3562
3563
~MessageDispatchHelperThread()3564 MessageDispatchHelperThread::~MessageDispatchHelperThread() {
3565 delete mutex_;
3566 delete sem_;
3567 }
3568
3569
Schedule()3570 void MessageDispatchHelperThread::Schedule() {
3571 {
3572 ScopedLock lock(mutex_);
3573 if (already_signalled_) {
3574 return;
3575 }
3576 already_signalled_ = true;
3577 }
3578 sem_->Signal();
3579 }
3580
3581
Run()3582 void MessageDispatchHelperThread::Run() {
3583 while (true) {
3584 sem_->Wait();
3585 {
3586 ScopedLock lock(mutex_);
3587 already_signalled_ = false;
3588 }
3589 {
3590 Locker locker;
3591 Isolate::Current()->debugger()->CallMessageDispatchHandler();
3592 }
3593 }
3594 }
3595
3596 #endif // ENABLE_DEBUGGER_SUPPORT
3597
3598 } } // namespace v8::internal
3599