1 // Copyright 2006-2008 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 "compilation-cache.h"
35 #include "compiler.h"
36 #include "debug.h"
37 #include "execution.h"
38 #include "global-handles.h"
39 #include "ic.h"
40 #include "ic-inl.h"
41 #include "natives.h"
42 #include "stub-cache.h"
43 #include "log.h"
44
45 #include "../include/v8-debug.h"
46
47 namespace v8 {
48 namespace internal {
49
50 #ifdef ENABLE_DEBUGGER_SUPPORT
PrintLn(v8::Local<v8::Value> value)51 static void PrintLn(v8::Local<v8::Value> value) {
52 v8::Local<v8::String> s = value->ToString();
53 char* data = NewArray<char>(s->Length() + 1);
54 if (data == NULL) {
55 V8::FatalProcessOutOfMemory("PrintLn");
56 return;
57 }
58 s->WriteAscii(data);
59 PrintF("%s\n", data);
60 DeleteArray(data);
61 }
62
63
ComputeCallDebugBreak(int argc)64 static Handle<Code> ComputeCallDebugBreak(int argc) {
65 CALL_HEAP_FUNCTION(StubCache::ComputeCallDebugBreak(argc), Code);
66 }
67
68
ComputeCallDebugPrepareStepIn(int argc)69 static Handle<Code> ComputeCallDebugPrepareStepIn(int argc) {
70 CALL_HEAP_FUNCTION(StubCache::ComputeCallDebugPrepareStepIn(argc), Code);
71 }
72
73
BreakLocationIterator(Handle<DebugInfo> debug_info,BreakLocatorType type)74 BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info,
75 BreakLocatorType type) {
76 debug_info_ = debug_info;
77 type_ = type;
78 // Get the stub early to avoid possible GC during iterations. We may need
79 // this stub to detect debugger calls generated from debugger statements.
80 debug_break_stub_ = RuntimeStub(Runtime::kDebugBreak, 0).GetCode();
81 reloc_iterator_ = NULL;
82 reloc_iterator_original_ = NULL;
83 Reset(); // Initialize the rest of the member variables.
84 }
85
86
~BreakLocationIterator()87 BreakLocationIterator::~BreakLocationIterator() {
88 ASSERT(reloc_iterator_ != NULL);
89 ASSERT(reloc_iterator_original_ != NULL);
90 delete reloc_iterator_;
91 delete reloc_iterator_original_;
92 }
93
94
Next()95 void BreakLocationIterator::Next() {
96 AssertNoAllocation nogc;
97 ASSERT(!RinfoDone());
98
99 // Iterate through reloc info for code and original code stopping at each
100 // breakable code target.
101 bool first = break_point_ == -1;
102 while (!RinfoDone()) {
103 if (!first) RinfoNext();
104 first = false;
105 if (RinfoDone()) return;
106
107 // Whenever a statement position or (plain) position is passed update the
108 // current value of these.
109 if (RelocInfo::IsPosition(rmode())) {
110 if (RelocInfo::IsStatementPosition(rmode())) {
111 statement_position_ =
112 rinfo()->data() - debug_info_->shared()->start_position();
113 }
114 // Always update the position as we don't want that to be before the
115 // statement position.
116 position_ = rinfo()->data() - debug_info_->shared()->start_position();
117 ASSERT(position_ >= 0);
118 ASSERT(statement_position_ >= 0);
119 }
120
121 // Check for breakable code target. Look in the original code as setting
122 // break points can cause the code targets in the running (debugged) code to
123 // be of a different kind than in the original code.
124 if (RelocInfo::IsCodeTarget(rmode())) {
125 Address target = original_rinfo()->target_address();
126 Code* code = Code::GetCodeFromTargetAddress(target);
127 if (code->is_inline_cache_stub() || RelocInfo::IsConstructCall(rmode())) {
128 break_point_++;
129 return;
130 }
131 if (code->kind() == Code::STUB) {
132 if (IsDebuggerStatement()) {
133 break_point_++;
134 return;
135 }
136 if (type_ == ALL_BREAK_LOCATIONS) {
137 if (Debug::IsBreakStub(code)) {
138 break_point_++;
139 return;
140 }
141 } else {
142 ASSERT(type_ == SOURCE_BREAK_LOCATIONS);
143 if (Debug::IsSourceBreakStub(code)) {
144 break_point_++;
145 return;
146 }
147 }
148 }
149 }
150
151 // Check for break at return.
152 if (RelocInfo::IsJSReturn(rmode())) {
153 // Set the positions to the end of the function.
154 if (debug_info_->shared()->HasSourceCode()) {
155 position_ = debug_info_->shared()->end_position() -
156 debug_info_->shared()->start_position();
157 } else {
158 position_ = 0;
159 }
160 statement_position_ = position_;
161 break_point_++;
162 return;
163 }
164 }
165 }
166
167
Next(int count)168 void BreakLocationIterator::Next(int count) {
169 while (count > 0) {
170 Next();
171 count--;
172 }
173 }
174
175
176 // Find the break point closest to the supplied address.
FindBreakLocationFromAddress(Address pc)177 void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) {
178 // Run through all break points to locate the one closest to the address.
179 int closest_break_point = 0;
180 int distance = kMaxInt;
181 while (!Done()) {
182 // Check if this break point is closer that what was previously found.
183 if (this->pc() < pc && pc - this->pc() < distance) {
184 closest_break_point = break_point();
185 distance = pc - this->pc();
186 // Check whether we can't get any closer.
187 if (distance == 0) break;
188 }
189 Next();
190 }
191
192 // Move to the break point found.
193 Reset();
194 Next(closest_break_point);
195 }
196
197
198 // Find the break point closest to the supplied source position.
FindBreakLocationFromPosition(int position)199 void BreakLocationIterator::FindBreakLocationFromPosition(int position) {
200 // Run through all break points to locate the one closest to the source
201 // position.
202 int closest_break_point = 0;
203 int distance = kMaxInt;
204 while (!Done()) {
205 // Check if this break point is closer that what was previously found.
206 if (position <= statement_position() &&
207 statement_position() - position < distance) {
208 closest_break_point = break_point();
209 distance = statement_position() - position;
210 // Check whether we can't get any closer.
211 if (distance == 0) break;
212 }
213 Next();
214 }
215
216 // Move to the break point found.
217 Reset();
218 Next(closest_break_point);
219 }
220
221
Reset()222 void BreakLocationIterator::Reset() {
223 // Create relocation iterators for the two code objects.
224 if (reloc_iterator_ != NULL) delete reloc_iterator_;
225 if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_;
226 reloc_iterator_ = new RelocIterator(debug_info_->code());
227 reloc_iterator_original_ = new RelocIterator(debug_info_->original_code());
228
229 // Position at the first break point.
230 break_point_ = -1;
231 position_ = 1;
232 statement_position_ = 1;
233 Next();
234 }
235
236
Done() const237 bool BreakLocationIterator::Done() const {
238 return RinfoDone();
239 }
240
241
SetBreakPoint(Handle<Object> break_point_object)242 void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) {
243 // If there is not already a real break point here patch code with debug
244 // break.
245 if (!HasBreakPoint()) {
246 SetDebugBreak();
247 }
248 ASSERT(IsDebugBreak() || IsDebuggerStatement());
249 // Set the break point information.
250 DebugInfo::SetBreakPoint(debug_info_, code_position(),
251 position(), statement_position(),
252 break_point_object);
253 }
254
255
ClearBreakPoint(Handle<Object> break_point_object)256 void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) {
257 // Clear the break point information.
258 DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object);
259 // If there are no more break points here remove the debug break.
260 if (!HasBreakPoint()) {
261 ClearDebugBreak();
262 ASSERT(!IsDebugBreak());
263 }
264 }
265
266
SetOneShot()267 void BreakLocationIterator::SetOneShot() {
268 // Debugger statement always calls debugger. No need to modify it.
269 if (IsDebuggerStatement()) {
270 return;
271 }
272
273 // If there is a real break point here no more to do.
274 if (HasBreakPoint()) {
275 ASSERT(IsDebugBreak());
276 return;
277 }
278
279 // Patch code with debug break.
280 SetDebugBreak();
281 }
282
283
ClearOneShot()284 void BreakLocationIterator::ClearOneShot() {
285 // Debugger statement always calls debugger. No need to modify it.
286 if (IsDebuggerStatement()) {
287 return;
288 }
289
290 // If there is a real break point here no more to do.
291 if (HasBreakPoint()) {
292 ASSERT(IsDebugBreak());
293 return;
294 }
295
296 // Patch code removing debug break.
297 ClearDebugBreak();
298 ASSERT(!IsDebugBreak());
299 }
300
301
SetDebugBreak()302 void BreakLocationIterator::SetDebugBreak() {
303 // Debugger statement always calls debugger. No need to modify it.
304 if (IsDebuggerStatement()) {
305 return;
306 }
307
308 // If there is already a break point here just return. This might happen if
309 // the same code is flooded with break points twice. Flooding the same
310 // function twice might happen when stepping in a function with an exception
311 // handler as the handler and the function is the same.
312 if (IsDebugBreak()) {
313 return;
314 }
315
316 if (RelocInfo::IsJSReturn(rmode())) {
317 // Patch the frame exit code with a break point.
318 SetDebugBreakAtReturn();
319 } else {
320 // Patch the IC call.
321 SetDebugBreakAtIC();
322 }
323 ASSERT(IsDebugBreak());
324 }
325
326
ClearDebugBreak()327 void BreakLocationIterator::ClearDebugBreak() {
328 // Debugger statement always calls debugger. No need to modify it.
329 if (IsDebuggerStatement()) {
330 return;
331 }
332
333 if (RelocInfo::IsJSReturn(rmode())) {
334 // Restore the frame exit code.
335 ClearDebugBreakAtReturn();
336 } else {
337 // Patch the IC call.
338 ClearDebugBreakAtIC();
339 }
340 ASSERT(!IsDebugBreak());
341 }
342
343
PrepareStepIn()344 void BreakLocationIterator::PrepareStepIn() {
345 HandleScope scope;
346
347 // Step in can only be prepared if currently positioned on an IC call,
348 // construct call or CallFunction stub call.
349 Address target = rinfo()->target_address();
350 Handle<Code> code(Code::GetCodeFromTargetAddress(target));
351 if (code->is_call_stub()) {
352 // Step in through IC call is handled by the runtime system. Therefore make
353 // sure that the any current IC is cleared and the runtime system is
354 // called. If the executing code has a debug break at the location change
355 // the call in the original code as it is the code there that will be
356 // executed in place of the debug break call.
357 Handle<Code> stub = ComputeCallDebugPrepareStepIn(code->arguments_count());
358 if (IsDebugBreak()) {
359 original_rinfo()->set_target_address(stub->entry());
360 } else {
361 rinfo()->set_target_address(stub->entry());
362 }
363 } else {
364 #ifdef DEBUG
365 // All the following stuff is needed only for assertion checks so the code
366 // is wrapped in ifdef.
367 Handle<Code> maybe_call_function_stub = code;
368 if (IsDebugBreak()) {
369 Address original_target = original_rinfo()->target_address();
370 maybe_call_function_stub =
371 Handle<Code>(Code::GetCodeFromTargetAddress(original_target));
372 }
373 bool is_call_function_stub =
374 (maybe_call_function_stub->kind() == Code::STUB &&
375 maybe_call_function_stub->major_key() == CodeStub::CallFunction);
376
377 // Step in through construct call requires no changes to the running code.
378 // Step in through getters/setters should already be prepared as well
379 // because caller of this function (Debug::PrepareStep) is expected to
380 // flood the top frame's function with one shot breakpoints.
381 // Step in through CallFunction stub should also be prepared by caller of
382 // this function (Debug::PrepareStep) which should flood target function
383 // with breakpoints.
384 ASSERT(RelocInfo::IsConstructCall(rmode()) || code->is_inline_cache_stub()
385 || is_call_function_stub);
386 #endif
387 }
388 }
389
390
391 // Check whether the break point is at a position which will exit the function.
IsExit() const392 bool BreakLocationIterator::IsExit() const {
393 return (RelocInfo::IsJSReturn(rmode()));
394 }
395
396
HasBreakPoint()397 bool BreakLocationIterator::HasBreakPoint() {
398 return debug_info_->HasBreakPoint(code_position());
399 }
400
401
402 // Check whether there is a debug break at the current position.
IsDebugBreak()403 bool BreakLocationIterator::IsDebugBreak() {
404 if (RelocInfo::IsJSReturn(rmode())) {
405 return IsDebugBreakAtReturn();
406 } else {
407 return Debug::IsDebugBreak(rinfo()->target_address());
408 }
409 }
410
411
SetDebugBreakAtIC()412 void BreakLocationIterator::SetDebugBreakAtIC() {
413 // Patch the original code with the current address as the current address
414 // might have changed by the inline caching since the code was copied.
415 original_rinfo()->set_target_address(rinfo()->target_address());
416
417 RelocInfo::Mode mode = rmode();
418 if (RelocInfo::IsCodeTarget(mode)) {
419 Address target = rinfo()->target_address();
420 Handle<Code> code(Code::GetCodeFromTargetAddress(target));
421
422 // Patch the code to invoke the builtin debug break function matching the
423 // calling convention used by the call site.
424 Handle<Code> dbgbrk_code(Debug::FindDebugBreak(code, mode));
425 rinfo()->set_target_address(dbgbrk_code->entry());
426
427 // For stubs that refer back to an inlined version clear the cached map for
428 // the inlined case to always go through the IC. As long as the break point
429 // is set the patching performed by the runtime system will take place in
430 // the code copy and will therefore have no effect on the running code
431 // keeping it from using the inlined code.
432 if (code->is_keyed_load_stub()) KeyedLoadIC::ClearInlinedVersion(pc());
433 if (code->is_keyed_store_stub()) KeyedStoreIC::ClearInlinedVersion(pc());
434 }
435 }
436
437
ClearDebugBreakAtIC()438 void BreakLocationIterator::ClearDebugBreakAtIC() {
439 // Patch the code to the original invoke.
440 rinfo()->set_target_address(original_rinfo()->target_address());
441
442 RelocInfo::Mode mode = rmode();
443 if (RelocInfo::IsCodeTarget(mode)) {
444 Address target = original_rinfo()->target_address();
445 Handle<Code> code(Code::GetCodeFromTargetAddress(target));
446
447 // Restore the inlined version of keyed stores to get back to the
448 // fast case. We need to patch back the keyed store because no
449 // patching happens when running normally. For keyed loads, the
450 // map check will get patched back when running normally after ICs
451 // have been cleared at GC.
452 if (code->is_keyed_store_stub()) KeyedStoreIC::RestoreInlinedVersion(pc());
453 }
454 }
455
456
IsDebuggerStatement()457 bool BreakLocationIterator::IsDebuggerStatement() {
458 if (RelocInfo::IsCodeTarget(rmode())) {
459 Address target = original_rinfo()->target_address();
460 Code* code = Code::GetCodeFromTargetAddress(target);
461 if (code->kind() == Code::STUB) {
462 CodeStub::Major major_key = code->major_key();
463 if (major_key == CodeStub::Runtime) {
464 return (*debug_break_stub_ == code);
465 }
466 }
467 }
468 return false;
469 }
470
471
BreakPointObjects()472 Object* BreakLocationIterator::BreakPointObjects() {
473 return debug_info_->GetBreakPointObjects(code_position());
474 }
475
476
477 // Clear out all the debug break code. This is ONLY supposed to be used when
478 // shutting down the debugger as it will leave the break point information in
479 // DebugInfo even though the code is patched back to the non break point state.
ClearAllDebugBreak()480 void BreakLocationIterator::ClearAllDebugBreak() {
481 while (!Done()) {
482 ClearDebugBreak();
483 Next();
484 }
485 }
486
487
RinfoDone() const488 bool BreakLocationIterator::RinfoDone() const {
489 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
490 return reloc_iterator_->done();
491 }
492
493
RinfoNext()494 void BreakLocationIterator::RinfoNext() {
495 reloc_iterator_->next();
496 reloc_iterator_original_->next();
497 #ifdef DEBUG
498 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
499 if (!reloc_iterator_->done()) {
500 ASSERT(rmode() == original_rmode());
501 }
502 #endif
503 }
504
505
506 bool Debug::has_break_points_ = false;
507 ScriptCache* Debug::script_cache_ = NULL;
508 DebugInfoListNode* Debug::debug_info_list_ = NULL;
509
510
511 // Threading support.
ThreadInit()512 void Debug::ThreadInit() {
513 thread_local_.break_count_ = 0;
514 thread_local_.break_id_ = 0;
515 thread_local_.break_frame_id_ = StackFrame::NO_ID;
516 thread_local_.last_step_action_ = StepNone;
517 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
518 thread_local_.step_count_ = 0;
519 thread_local_.last_fp_ = 0;
520 thread_local_.step_into_fp_ = 0;
521 thread_local_.after_break_target_ = 0;
522 thread_local_.debugger_entry_ = NULL;
523 thread_local_.pending_interrupts_ = 0;
524 }
525
526
527 JSCallerSavedBuffer Debug::registers_;
528 Debug::ThreadLocal Debug::thread_local_;
529
530
ArchiveDebug(char * storage)531 char* Debug::ArchiveDebug(char* storage) {
532 char* to = storage;
533 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
534 to += sizeof(ThreadLocal);
535 memcpy(to, reinterpret_cast<char*>(®isters_), sizeof(registers_));
536 ThreadInit();
537 ASSERT(to <= storage + ArchiveSpacePerThread());
538 return storage + ArchiveSpacePerThread();
539 }
540
541
RestoreDebug(char * storage)542 char* Debug::RestoreDebug(char* storage) {
543 char* from = storage;
544 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
545 from += sizeof(ThreadLocal);
546 memcpy(reinterpret_cast<char*>(®isters_), from, sizeof(registers_));
547 ASSERT(from <= storage + ArchiveSpacePerThread());
548 return storage + ArchiveSpacePerThread();
549 }
550
551
ArchiveSpacePerThread()552 int Debug::ArchiveSpacePerThread() {
553 return sizeof(ThreadLocal) + sizeof(registers_);
554 }
555
556
557 // Default break enabled.
558 bool Debug::disable_break_ = false;
559
560 // Default call debugger on uncaught exception.
561 bool Debug::break_on_exception_ = false;
562 bool Debug::break_on_uncaught_exception_ = true;
563
564 Handle<Context> Debug::debug_context_ = Handle<Context>();
565 Code* Debug::debug_break_return_entry_ = NULL;
566 Code* Debug::debug_break_return_ = NULL;
567
568
Add(Handle<Script> script)569 void ScriptCache::Add(Handle<Script> script) {
570 // Create an entry in the hash map for the script.
571 int id = Smi::cast(script->id())->value();
572 HashMap::Entry* entry =
573 HashMap::Lookup(reinterpret_cast<void*>(id), Hash(id), true);
574 if (entry->value != NULL) {
575 ASSERT(*script == *reinterpret_cast<Script**>(entry->value));
576 return;
577 }
578
579 // Globalize the script object, make it weak and use the location of the
580 // global handle as the value in the hash map.
581 Handle<Script> script_ =
582 Handle<Script>::cast((GlobalHandles::Create(*script)));
583 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(script_.location()),
584 this, ScriptCache::HandleWeakScript);
585 entry->value = script_.location();
586 }
587
588
GetScripts()589 Handle<FixedArray> ScriptCache::GetScripts() {
590 Handle<FixedArray> instances = Factory::NewFixedArray(occupancy());
591 int count = 0;
592 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
593 ASSERT(entry->value != NULL);
594 if (entry->value != NULL) {
595 instances->set(count, *reinterpret_cast<Script**>(entry->value));
596 count++;
597 }
598 }
599 return instances;
600 }
601
602
ProcessCollectedScripts()603 void ScriptCache::ProcessCollectedScripts() {
604 for (int i = 0; i < collected_scripts_.length(); i++) {
605 Debugger::OnScriptCollected(collected_scripts_[i]);
606 }
607 collected_scripts_.Clear();
608 }
609
610
Clear()611 void ScriptCache::Clear() {
612 // Iterate the script cache to get rid of all the weak handles.
613 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
614 ASSERT(entry != NULL);
615 Object** location = reinterpret_cast<Object**>(entry->value);
616 ASSERT((*location)->IsScript());
617 GlobalHandles::ClearWeakness(location);
618 GlobalHandles::Destroy(location);
619 }
620 // Clear the content of the hash map.
621 HashMap::Clear();
622 }
623
624
HandleWeakScript(v8::Persistent<v8::Value> obj,void * data)625 void ScriptCache::HandleWeakScript(v8::Persistent<v8::Value> obj, void* data) {
626 ScriptCache* script_cache = reinterpret_cast<ScriptCache*>(data);
627 // Find the location of the global handle.
628 Script** location =
629 reinterpret_cast<Script**>(Utils::OpenHandle(*obj).location());
630 ASSERT((*location)->IsScript());
631
632 // Remove the entry from the cache.
633 int id = Smi::cast((*location)->id())->value();
634 script_cache->Remove(reinterpret_cast<void*>(id), Hash(id));
635 script_cache->collected_scripts_.Add(id);
636
637 // Clear the weak handle.
638 obj.Dispose();
639 obj.Clear();
640 }
641
642
Setup(bool create_heap_objects)643 void Debug::Setup(bool create_heap_objects) {
644 ThreadInit();
645 if (create_heap_objects) {
646 // Get code to handle entry to debug break on return.
647 debug_break_return_entry_ =
648 Builtins::builtin(Builtins::Return_DebugBreakEntry);
649 ASSERT(debug_break_return_entry_->IsCode());
650
651 // Get code to handle debug break on return.
652 debug_break_return_ =
653 Builtins::builtin(Builtins::Return_DebugBreak);
654 ASSERT(debug_break_return_->IsCode());
655 }
656 }
657
658
HandleWeakDebugInfo(v8::Persistent<v8::Value> obj,void * data)659 void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) {
660 DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data);
661 RemoveDebugInfo(node->debug_info());
662 #ifdef DEBUG
663 node = Debug::debug_info_list_;
664 while (node != NULL) {
665 ASSERT(node != reinterpret_cast<DebugInfoListNode*>(data));
666 node = node->next();
667 }
668 #endif
669 }
670
671
DebugInfoListNode(DebugInfo * debug_info)672 DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
673 // Globalize the request debug info object and make it weak.
674 debug_info_ = Handle<DebugInfo>::cast((GlobalHandles::Create(debug_info)));
675 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(debug_info_.location()),
676 this, Debug::HandleWeakDebugInfo);
677 }
678
679
~DebugInfoListNode()680 DebugInfoListNode::~DebugInfoListNode() {
681 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_.location()));
682 }
683
684
CompileDebuggerScript(int index)685 bool Debug::CompileDebuggerScript(int index) {
686 HandleScope scope;
687
688 // Bail out if the index is invalid.
689 if (index == -1) {
690 return false;
691 }
692
693 // Find source and name for the requested script.
694 Handle<String> source_code = Bootstrapper::NativesSourceLookup(index);
695 Vector<const char> name = Natives::GetScriptName(index);
696 Handle<String> script_name = Factory::NewStringFromAscii(name);
697
698 // Compile the script.
699 bool allow_natives_syntax = FLAG_allow_natives_syntax;
700 FLAG_allow_natives_syntax = true;
701 Handle<JSFunction> boilerplate;
702 boilerplate = Compiler::Compile(source_code, script_name, 0, 0, NULL, NULL);
703 FLAG_allow_natives_syntax = allow_natives_syntax;
704
705 // Silently ignore stack overflows during compilation.
706 if (boilerplate.is_null()) {
707 ASSERT(Top::has_pending_exception());
708 Top::clear_pending_exception();
709 return false;
710 }
711
712 // Execute the boilerplate function in the debugger context.
713 Handle<Context> context = Top::global_context();
714 bool caught_exception = false;
715 Handle<JSFunction> function =
716 Factory::NewFunctionFromBoilerplate(boilerplate, context);
717 Handle<Object> result =
718 Execution::TryCall(function, Handle<Object>(context->global()),
719 0, NULL, &caught_exception);
720
721 // Check for caught exceptions.
722 if (caught_exception) {
723 Handle<Object> message = MessageHandler::MakeMessageObject(
724 "error_loading_debugger", NULL, Vector<Handle<Object> >::empty(),
725 Handle<String>());
726 MessageHandler::ReportMessage(NULL, message);
727 return false;
728 }
729
730 // Mark this script as native and return successfully.
731 Handle<Script> script(Script::cast(function->shared()->script()));
732 script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
733 return true;
734 }
735
736
Load()737 bool Debug::Load() {
738 // Return if debugger is already loaded.
739 if (IsLoaded()) return true;
740
741 // Bail out if we're already in the process of compiling the native
742 // JavaScript source code for the debugger.
743 if (Debugger::compiling_natives() || Debugger::is_loading_debugger())
744 return false;
745 Debugger::set_loading_debugger(true);
746
747 // Disable breakpoints and interrupts while compiling and running the
748 // debugger scripts including the context creation code.
749 DisableBreak disable(true);
750 PostponeInterruptsScope postpone;
751
752 // Create the debugger context.
753 HandleScope scope;
754 Handle<Context> context =
755 Bootstrapper::CreateEnvironment(Handle<Object>::null(),
756 v8::Handle<ObjectTemplate>(),
757 NULL);
758
759 // Use the debugger context.
760 SaveContext save;
761 Top::set_context(*context);
762
763 // Expose the builtins object in the debugger context.
764 Handle<String> key = Factory::LookupAsciiSymbol("builtins");
765 Handle<GlobalObject> global = Handle<GlobalObject>(context->global());
766 SetProperty(global, key, Handle<Object>(global->builtins()), NONE);
767
768 // Compile the JavaScript for the debugger in the debugger context.
769 Debugger::set_compiling_natives(true);
770 bool caught_exception =
771 !CompileDebuggerScript(Natives::GetIndex("mirror")) ||
772 !CompileDebuggerScript(Natives::GetIndex("debug"));
773 Debugger::set_compiling_natives(false);
774
775 // Make sure we mark the debugger as not loading before we might
776 // return.
777 Debugger::set_loading_debugger(false);
778
779 // Check for caught exceptions.
780 if (caught_exception) return false;
781
782 // Debugger loaded.
783 debug_context_ = Handle<Context>::cast(GlobalHandles::Create(*context));
784
785 return true;
786 }
787
788
Unload()789 void Debug::Unload() {
790 // Return debugger is not loaded.
791 if (!IsLoaded()) {
792 return;
793 }
794
795 // Clear the script cache.
796 DestroyScriptCache();
797
798 // Clear debugger context global handle.
799 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_context_.location()));
800 debug_context_ = Handle<Context>();
801 }
802
803
804 // Set the flag indicating that preemption happened during debugging.
PreemptionWhileInDebugger()805 void Debug::PreemptionWhileInDebugger() {
806 ASSERT(InDebugger());
807 Debug::set_interrupts_pending(PREEMPT);
808 }
809
810
Iterate(ObjectVisitor * v)811 void Debug::Iterate(ObjectVisitor* v) {
812 v->VisitPointer(bit_cast<Object**, Code**>(&(debug_break_return_entry_)));
813 v->VisitPointer(bit_cast<Object**, Code**>(&(debug_break_return_)));
814 }
815
816
Break(Arguments args)817 Object* Debug::Break(Arguments args) {
818 HandleScope scope;
819 ASSERT(args.length() == 0);
820
821 // Get the top-most JavaScript frame.
822 JavaScriptFrameIterator it;
823 JavaScriptFrame* frame = it.frame();
824
825 // Just continue if breaks are disabled or debugger cannot be loaded.
826 if (disable_break() || !Load()) {
827 SetAfterBreakTarget(frame);
828 return Heap::undefined_value();
829 }
830
831 // Enter the debugger.
832 EnterDebugger debugger;
833 if (debugger.FailedToEnter()) {
834 return Heap::undefined_value();
835 }
836
837 // Postpone interrupt during breakpoint processing.
838 PostponeInterruptsScope postpone;
839
840 // Get the debug info (create it if it does not exist).
841 Handle<SharedFunctionInfo> shared =
842 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
843 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
844
845 // Find the break point where execution has stopped.
846 BreakLocationIterator break_location_iterator(debug_info,
847 ALL_BREAK_LOCATIONS);
848 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
849
850 // Check whether step next reached a new statement.
851 if (!StepNextContinue(&break_location_iterator, frame)) {
852 // Decrease steps left if performing multiple steps.
853 if (thread_local_.step_count_ > 0) {
854 thread_local_.step_count_--;
855 }
856 }
857
858 // If there is one or more real break points check whether any of these are
859 // triggered.
860 Handle<Object> break_points_hit(Heap::undefined_value());
861 if (break_location_iterator.HasBreakPoint()) {
862 Handle<Object> break_point_objects =
863 Handle<Object>(break_location_iterator.BreakPointObjects());
864 break_points_hit = CheckBreakPoints(break_point_objects);
865 }
866
867 // Notify debugger if a real break point is triggered or if performing single
868 // stepping with no more steps to perform. Otherwise do another step.
869 if (!break_points_hit->IsUndefined() ||
870 (thread_local_.last_step_action_ != StepNone &&
871 thread_local_.step_count_ == 0)) {
872 // Clear all current stepping setup.
873 ClearStepping();
874
875 // Notify the debug event listeners.
876 Debugger::OnDebugBreak(break_points_hit, false);
877 } else if (thread_local_.last_step_action_ != StepNone) {
878 // Hold on to last step action as it is cleared by the call to
879 // ClearStepping.
880 StepAction step_action = thread_local_.last_step_action_;
881 int step_count = thread_local_.step_count_;
882
883 // Clear all current stepping setup.
884 ClearStepping();
885
886 // Set up for the remaining steps.
887 PrepareStep(step_action, step_count);
888 }
889
890 // Install jump to the call address which was overwritten.
891 SetAfterBreakTarget(frame);
892
893 return Heap::undefined_value();
894 }
895
896
897 // Check the break point objects for whether one or more are actually
898 // triggered. This function returns a JSArray with the break point objects
899 // which is triggered.
CheckBreakPoints(Handle<Object> break_point_objects)900 Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) {
901 int break_points_hit_count = 0;
902 Handle<JSArray> break_points_hit = Factory::NewJSArray(1);
903
904 // If there are multiple break points they are in a FixedArray.
905 ASSERT(!break_point_objects->IsUndefined());
906 if (break_point_objects->IsFixedArray()) {
907 Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
908 for (int i = 0; i < array->length(); i++) {
909 Handle<Object> o(array->get(i));
910 if (CheckBreakPoint(o)) {
911 break_points_hit->SetElement(break_points_hit_count++, *o);
912 }
913 }
914 } else {
915 if (CheckBreakPoint(break_point_objects)) {
916 break_points_hit->SetElement(break_points_hit_count++,
917 *break_point_objects);
918 }
919 }
920
921 // Return undefined if no break points where triggered.
922 if (break_points_hit_count == 0) {
923 return Factory::undefined_value();
924 }
925 return break_points_hit;
926 }
927
928
929 // Check whether a single break point object is triggered.
CheckBreakPoint(Handle<Object> break_point_object)930 bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
931 HandleScope scope;
932
933 // Ignore check if break point object is not a JSObject.
934 if (!break_point_object->IsJSObject()) return true;
935
936 // Get the function CheckBreakPoint (defined in debug.js).
937 Handle<JSFunction> check_break_point =
938 Handle<JSFunction>(JSFunction::cast(
939 debug_context()->global()->GetProperty(
940 *Factory::LookupAsciiSymbol("IsBreakPointTriggered"))));
941
942 // Get the break id as an object.
943 Handle<Object> break_id = Factory::NewNumberFromInt(Debug::break_id());
944
945 // Call HandleBreakPointx.
946 bool caught_exception = false;
947 const int argc = 2;
948 Object** argv[argc] = {
949 break_id.location(),
950 reinterpret_cast<Object**>(break_point_object.location())
951 };
952 Handle<Object> result = Execution::TryCall(check_break_point,
953 Top::builtins(), argc, argv,
954 &caught_exception);
955
956 // If exception or non boolean result handle as not triggered
957 if (caught_exception || !result->IsBoolean()) {
958 return false;
959 }
960
961 // Return whether the break point is triggered.
962 return *result == Heap::true_value();
963 }
964
965
966 // Check whether the function has debug information.
HasDebugInfo(Handle<SharedFunctionInfo> shared)967 bool Debug::HasDebugInfo(Handle<SharedFunctionInfo> shared) {
968 return !shared->debug_info()->IsUndefined();
969 }
970
971
972 // Return the debug info for this function. EnsureDebugInfo must be called
973 // prior to ensure the debug info has been generated for shared.
GetDebugInfo(Handle<SharedFunctionInfo> shared)974 Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) {
975 ASSERT(HasDebugInfo(shared));
976 return Handle<DebugInfo>(DebugInfo::cast(shared->debug_info()));
977 }
978
979
SetBreakPoint(Handle<SharedFunctionInfo> shared,int source_position,Handle<Object> break_point_object)980 void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared,
981 int source_position,
982 Handle<Object> break_point_object) {
983 HandleScope scope;
984
985 if (!EnsureDebugInfo(shared)) {
986 // Return if retrieving debug info failed.
987 return;
988 }
989
990 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
991 // Source positions starts with zero.
992 ASSERT(source_position >= 0);
993
994 // Find the break point and change it.
995 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
996 it.FindBreakLocationFromPosition(source_position);
997 it.SetBreakPoint(break_point_object);
998
999 // At least one active break point now.
1000 ASSERT(debug_info->GetBreakPointCount() > 0);
1001 }
1002
1003
ClearBreakPoint(Handle<Object> break_point_object)1004 void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
1005 HandleScope scope;
1006
1007 DebugInfoListNode* node = debug_info_list_;
1008 while (node != NULL) {
1009 Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(),
1010 break_point_object);
1011 if (!result->IsUndefined()) {
1012 // Get information in the break point.
1013 BreakPointInfo* break_point_info = BreakPointInfo::cast(result);
1014 Handle<DebugInfo> debug_info = node->debug_info();
1015 Handle<SharedFunctionInfo> shared(debug_info->shared());
1016 int source_position = break_point_info->statement_position()->value();
1017
1018 // Source positions starts with zero.
1019 ASSERT(source_position >= 0);
1020
1021 // Find the break point and clear it.
1022 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
1023 it.FindBreakLocationFromPosition(source_position);
1024 it.ClearBreakPoint(break_point_object);
1025
1026 // If there are no more break points left remove the debug info for this
1027 // function.
1028 if (debug_info->GetBreakPointCount() == 0) {
1029 RemoveDebugInfo(debug_info);
1030 }
1031
1032 return;
1033 }
1034 node = node->next();
1035 }
1036 }
1037
1038
ClearAllBreakPoints()1039 void Debug::ClearAllBreakPoints() {
1040 DebugInfoListNode* node = debug_info_list_;
1041 while (node != NULL) {
1042 // Remove all debug break code.
1043 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1044 it.ClearAllDebugBreak();
1045 node = node->next();
1046 }
1047
1048 // Remove all debug info.
1049 while (debug_info_list_ != NULL) {
1050 RemoveDebugInfo(debug_info_list_->debug_info());
1051 }
1052 }
1053
1054
FloodWithOneShot(Handle<SharedFunctionInfo> shared)1055 void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) {
1056 // Make sure the function has setup the debug info.
1057 if (!EnsureDebugInfo(shared)) {
1058 // Return if we failed to retrieve the debug info.
1059 return;
1060 }
1061
1062 // Flood the function with break points.
1063 BreakLocationIterator it(GetDebugInfo(shared), ALL_BREAK_LOCATIONS);
1064 while (!it.Done()) {
1065 it.SetOneShot();
1066 it.Next();
1067 }
1068 }
1069
1070
FloodHandlerWithOneShot()1071 void Debug::FloodHandlerWithOneShot() {
1072 // Iterate through the JavaScript stack looking for handlers.
1073 StackFrame::Id id = break_frame_id();
1074 if (id == StackFrame::NO_ID) {
1075 // If there is no JavaScript stack don't do anything.
1076 return;
1077 }
1078 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) {
1079 JavaScriptFrame* frame = it.frame();
1080 if (frame->HasHandler()) {
1081 Handle<SharedFunctionInfo> shared =
1082 Handle<SharedFunctionInfo>(
1083 JSFunction::cast(frame->function())->shared());
1084 // Flood the function with the catch block with break points
1085 FloodWithOneShot(shared);
1086 return;
1087 }
1088 }
1089 }
1090
1091
ChangeBreakOnException(ExceptionBreakType type,bool enable)1092 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
1093 if (type == BreakUncaughtException) {
1094 break_on_uncaught_exception_ = enable;
1095 } else {
1096 break_on_exception_ = enable;
1097 }
1098 }
1099
1100
PrepareStep(StepAction step_action,int step_count)1101 void Debug::PrepareStep(StepAction step_action, int step_count) {
1102 HandleScope scope;
1103 ASSERT(Debug::InDebugger());
1104
1105 // Remember this step action and count.
1106 thread_local_.last_step_action_ = step_action;
1107 thread_local_.step_count_ = step_count;
1108
1109 // Get the frame where the execution has stopped and skip the debug frame if
1110 // any. The debug frame will only be present if execution was stopped due to
1111 // hitting a break point. In other situations (e.g. unhandled exception) the
1112 // debug frame is not present.
1113 StackFrame::Id id = break_frame_id();
1114 if (id == StackFrame::NO_ID) {
1115 // If there is no JavaScript stack don't do anything.
1116 return;
1117 }
1118 JavaScriptFrameIterator frames_it(id);
1119 JavaScriptFrame* frame = frames_it.frame();
1120
1121 // First of all ensure there is one-shot break points in the top handler
1122 // if any.
1123 FloodHandlerWithOneShot();
1124
1125 // If the function on the top frame is unresolved perform step out. This will
1126 // be the case when calling unknown functions and having the debugger stopped
1127 // in an unhandled exception.
1128 if (!frame->function()->IsJSFunction()) {
1129 // Step out: Find the calling JavaScript frame and flood it with
1130 // breakpoints.
1131 frames_it.Advance();
1132 // Fill the function to return to with one-shot break points.
1133 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
1134 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1135 return;
1136 }
1137
1138 // Get the debug info (create it if it does not exist).
1139 Handle<SharedFunctionInfo> shared =
1140 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
1141 if (!EnsureDebugInfo(shared)) {
1142 // Return if ensuring debug info failed.
1143 return;
1144 }
1145 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1146
1147 // Find the break location where execution has stopped.
1148 BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS);
1149 it.FindBreakLocationFromAddress(frame->pc());
1150
1151 // Compute whether or not the target is a call target.
1152 bool is_call_target = false;
1153 bool is_load_or_store = false;
1154 bool is_inline_cache_stub = false;
1155 Handle<Code> call_function_stub;
1156 if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) {
1157 Address target = it.rinfo()->target_address();
1158 Code* code = Code::GetCodeFromTargetAddress(target);
1159 if (code->is_call_stub()) {
1160 is_call_target = true;
1161 }
1162 if (code->is_inline_cache_stub()) {
1163 is_inline_cache_stub = true;
1164 is_load_or_store = !is_call_target;
1165 }
1166
1167 // Check if target code is CallFunction stub.
1168 Code* maybe_call_function_stub = code;
1169 // If there is a breakpoint at this line look at the original code to
1170 // check if it is a CallFunction stub.
1171 if (it.IsDebugBreak()) {
1172 Address original_target = it.original_rinfo()->target_address();
1173 maybe_call_function_stub =
1174 Code::GetCodeFromTargetAddress(original_target);
1175 }
1176 if (maybe_call_function_stub->kind() == Code::STUB &&
1177 maybe_call_function_stub->major_key() == CodeStub::CallFunction) {
1178 // Save reference to the code as we may need it to find out arguments
1179 // count for 'step in' later.
1180 call_function_stub = Handle<Code>(maybe_call_function_stub);
1181 }
1182 }
1183
1184 // If this is the last break code target step out is the only possibility.
1185 if (it.IsExit() || step_action == StepOut) {
1186 // Step out: If there is a JavaScript caller frame, we need to
1187 // flood it with breakpoints.
1188 frames_it.Advance();
1189 if (!frames_it.done()) {
1190 // Fill the function to return to with one-shot break points.
1191 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
1192 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1193 }
1194 } else if (!(is_inline_cache_stub || RelocInfo::IsConstructCall(it.rmode()) ||
1195 !call_function_stub.is_null())
1196 || step_action == StepNext || step_action == StepMin) {
1197 // Step next or step min.
1198
1199 // Fill the current function with one-shot break points.
1200 FloodWithOneShot(shared);
1201
1202 // Remember source position and frame to handle step next.
1203 thread_local_.last_statement_position_ =
1204 debug_info->code()->SourceStatementPosition(frame->pc());
1205 thread_local_.last_fp_ = frame->fp();
1206 } else {
1207 // If it's CallFunction stub ensure target function is compiled and flood
1208 // it with one shot breakpoints.
1209 if (!call_function_stub.is_null()) {
1210 // Find out number of arguments from the stub minor key.
1211 // Reverse lookup required as the minor key cannot be retrieved
1212 // from the code object.
1213 Handle<Object> obj(
1214 Heap::code_stubs()->SlowReverseLookup(*call_function_stub));
1215 ASSERT(*obj != Heap::undefined_value());
1216 ASSERT(obj->IsSmi());
1217 // Get the STUB key and extract major and minor key.
1218 uint32_t key = Smi::cast(*obj)->value();
1219 // Argc in the stub is the number of arguments passed - not the
1220 // expected arguments of the called function.
1221 int call_function_arg_count = CodeStub::MinorKeyFromKey(key);
1222 ASSERT(call_function_stub->major_key() ==
1223 CodeStub::MajorKeyFromKey(key));
1224
1225 // Find target function on the expression stack.
1226 // Expression stack lools like this (top to bottom):
1227 // argN
1228 // ...
1229 // arg0
1230 // Receiver
1231 // Function to call
1232 int expressions_count = frame->ComputeExpressionsCount();
1233 ASSERT(expressions_count - 2 - call_function_arg_count >= 0);
1234 Object* fun = frame->GetExpression(
1235 expressions_count - 2 - call_function_arg_count);
1236 if (fun->IsJSFunction()) {
1237 Handle<JSFunction> js_function(JSFunction::cast(fun));
1238 // Don't step into builtins.
1239 if (!js_function->IsBuiltin()) {
1240 // It will also compile target function if it's not compiled yet.
1241 FloodWithOneShot(Handle<SharedFunctionInfo>(js_function->shared()));
1242 }
1243 }
1244 }
1245
1246 // Fill the current function with one-shot break points even for step in on
1247 // a call target as the function called might be a native function for
1248 // which step in will not stop. It also prepares for stepping in
1249 // getters/setters.
1250 FloodWithOneShot(shared);
1251
1252 if (is_load_or_store) {
1253 // Remember source position and frame to handle step in getter/setter. If
1254 // there is a custom getter/setter it will be handled in
1255 // Object::Get/SetPropertyWithCallback, otherwise the step action will be
1256 // propagated on the next Debug::Break.
1257 thread_local_.last_statement_position_ =
1258 debug_info->code()->SourceStatementPosition(frame->pc());
1259 thread_local_.last_fp_ = frame->fp();
1260 }
1261
1262 // Step in or Step in min
1263 it.PrepareStepIn();
1264 ActivateStepIn(frame);
1265 }
1266 }
1267
1268
1269 // Check whether the current debug break should be reported to the debugger. It
1270 // is used to have step next and step in only report break back to the debugger
1271 // if on a different frame or in a different statement. In some situations
1272 // there will be several break points in the same statement when the code is
1273 // flooded with one-shot break points. This function helps to perform several
1274 // steps before reporting break back to the debugger.
StepNextContinue(BreakLocationIterator * break_location_iterator,JavaScriptFrame * frame)1275 bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
1276 JavaScriptFrame* frame) {
1277 // If the step last action was step next or step in make sure that a new
1278 // statement is hit.
1279 if (thread_local_.last_step_action_ == StepNext ||
1280 thread_local_.last_step_action_ == StepIn) {
1281 // Never continue if returning from function.
1282 if (break_location_iterator->IsExit()) return false;
1283
1284 // Continue if we are still on the same frame and in the same statement.
1285 int current_statement_position =
1286 break_location_iterator->code()->SourceStatementPosition(frame->pc());
1287 return thread_local_.last_fp_ == frame->fp() &&
1288 thread_local_.last_statement_position_ == current_statement_position;
1289 }
1290
1291 // No step next action - don't continue.
1292 return false;
1293 }
1294
1295
1296 // Check whether the code object at the specified address is a debug break code
1297 // object.
IsDebugBreak(Address addr)1298 bool Debug::IsDebugBreak(Address addr) {
1299 Code* code = Code::GetCodeFromTargetAddress(addr);
1300 return code->ic_state() == DEBUG_BREAK;
1301 }
1302
1303
1304 // Check whether a code stub with the specified major key is a possible break
1305 // point location when looking for source break locations.
IsSourceBreakStub(Code * code)1306 bool Debug::IsSourceBreakStub(Code* code) {
1307 CodeStub::Major major_key = code->major_key();
1308 return major_key == CodeStub::CallFunction;
1309 }
1310
1311
1312 // Check whether a code stub with the specified major key is a possible break
1313 // location.
IsBreakStub(Code * code)1314 bool Debug::IsBreakStub(Code* code) {
1315 CodeStub::Major major_key = code->major_key();
1316 return major_key == CodeStub::CallFunction ||
1317 major_key == CodeStub::StackCheck;
1318 }
1319
1320
1321 // Find the builtin to use for invoking the debug break
FindDebugBreak(Handle<Code> code,RelocInfo::Mode mode)1322 Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
1323 // Find the builtin debug break function matching the calling convention
1324 // used by the call site.
1325 if (code->is_inline_cache_stub()) {
1326 if (code->is_call_stub()) {
1327 return ComputeCallDebugBreak(code->arguments_count());
1328 }
1329 if (code->is_load_stub()) {
1330 return Handle<Code>(Builtins::builtin(Builtins::LoadIC_DebugBreak));
1331 }
1332 if (code->is_store_stub()) {
1333 return Handle<Code>(Builtins::builtin(Builtins::StoreIC_DebugBreak));
1334 }
1335 if (code->is_keyed_load_stub()) {
1336 Handle<Code> result =
1337 Handle<Code>(Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak));
1338 return result;
1339 }
1340 if (code->is_keyed_store_stub()) {
1341 Handle<Code> result =
1342 Handle<Code>(Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak));
1343 return result;
1344 }
1345 }
1346 if (RelocInfo::IsConstructCall(mode)) {
1347 Handle<Code> result =
1348 Handle<Code>(Builtins::builtin(Builtins::ConstructCall_DebugBreak));
1349 return result;
1350 }
1351 if (code->kind() == Code::STUB) {
1352 ASSERT(code->major_key() == CodeStub::CallFunction ||
1353 code->major_key() == CodeStub::StackCheck);
1354 Handle<Code> result =
1355 Handle<Code>(Builtins::builtin(Builtins::StubNoRegisters_DebugBreak));
1356 return result;
1357 }
1358
1359 UNREACHABLE();
1360 return Handle<Code>::null();
1361 }
1362
1363
1364 // Simple function for returning the source positions for active break points.
GetSourceBreakLocations(Handle<SharedFunctionInfo> shared)1365 Handle<Object> Debug::GetSourceBreakLocations(
1366 Handle<SharedFunctionInfo> shared) {
1367 if (!HasDebugInfo(shared)) return Handle<Object>(Heap::undefined_value());
1368 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1369 if (debug_info->GetBreakPointCount() == 0) {
1370 return Handle<Object>(Heap::undefined_value());
1371 }
1372 Handle<FixedArray> locations =
1373 Factory::NewFixedArray(debug_info->GetBreakPointCount());
1374 int count = 0;
1375 for (int i = 0; i < debug_info->break_points()->length(); i++) {
1376 if (!debug_info->break_points()->get(i)->IsUndefined()) {
1377 BreakPointInfo* break_point_info =
1378 BreakPointInfo::cast(debug_info->break_points()->get(i));
1379 if (break_point_info->GetBreakPointCount() > 0) {
1380 locations->set(count++, break_point_info->statement_position());
1381 }
1382 }
1383 }
1384 return locations;
1385 }
1386
1387
NewBreak(StackFrame::Id break_frame_id)1388 void Debug::NewBreak(StackFrame::Id break_frame_id) {
1389 thread_local_.break_frame_id_ = break_frame_id;
1390 thread_local_.break_id_ = ++thread_local_.break_count_;
1391 }
1392
1393
SetBreak(StackFrame::Id break_frame_id,int break_id)1394 void Debug::SetBreak(StackFrame::Id break_frame_id, int break_id) {
1395 thread_local_.break_frame_id_ = break_frame_id;
1396 thread_local_.break_id_ = break_id;
1397 }
1398
1399
1400 // Handle stepping into a function.
HandleStepIn(Handle<JSFunction> function,Handle<Object> holder,Address fp,bool is_constructor)1401 void Debug::HandleStepIn(Handle<JSFunction> function,
1402 Handle<Object> holder,
1403 Address fp,
1404 bool is_constructor) {
1405 // If the frame pointer is not supplied by the caller find it.
1406 if (fp == 0) {
1407 StackFrameIterator it;
1408 it.Advance();
1409 // For constructor functions skip another frame.
1410 if (is_constructor) {
1411 ASSERT(it.frame()->is_construct());
1412 it.Advance();
1413 }
1414 fp = it.frame()->fp();
1415 }
1416
1417 // Flood the function with one-shot break points if it is called from where
1418 // step into was requested.
1419 if (fp == Debug::step_in_fp()) {
1420 // Don't allow step into functions in the native context.
1421 if (!function->IsBuiltin()) {
1422 if (function->shared()->code() ==
1423 Builtins::builtin(Builtins::FunctionApply) ||
1424 function->shared()->code() ==
1425 Builtins::builtin(Builtins::FunctionCall)) {
1426 // Handle function.apply and function.call separately to flood the
1427 // function to be called and not the code for Builtins::FunctionApply or
1428 // Builtins::FunctionCall. The receiver of call/apply is the target
1429 // function.
1430 if (!holder.is_null() && holder->IsJSFunction() &&
1431 !JSFunction::cast(*holder)->IsBuiltin()) {
1432 Handle<SharedFunctionInfo> shared_info(
1433 JSFunction::cast(*holder)->shared());
1434 Debug::FloodWithOneShot(shared_info);
1435 }
1436 } else {
1437 Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1438 }
1439 }
1440 }
1441 }
1442
1443
ClearStepping()1444 void Debug::ClearStepping() {
1445 // Clear the various stepping setup.
1446 ClearOneShot();
1447 ClearStepIn();
1448 ClearStepNext();
1449
1450 // Clear multiple step counter.
1451 thread_local_.step_count_ = 0;
1452 }
1453
1454 // Clears all the one-shot break points that are currently set. Normally this
1455 // function is called each time a break point is hit as one shot break points
1456 // are used to support stepping.
ClearOneShot()1457 void Debug::ClearOneShot() {
1458 // The current implementation just runs through all the breakpoints. When the
1459 // last break point for a function is removed that function is automatically
1460 // removed from the list.
1461
1462 DebugInfoListNode* node = debug_info_list_;
1463 while (node != NULL) {
1464 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1465 while (!it.Done()) {
1466 it.ClearOneShot();
1467 it.Next();
1468 }
1469 node = node->next();
1470 }
1471 }
1472
1473
ActivateStepIn(StackFrame * frame)1474 void Debug::ActivateStepIn(StackFrame* frame) {
1475 thread_local_.step_into_fp_ = frame->fp();
1476 }
1477
1478
ClearStepIn()1479 void Debug::ClearStepIn() {
1480 thread_local_.step_into_fp_ = 0;
1481 }
1482
1483
ClearStepNext()1484 void Debug::ClearStepNext() {
1485 thread_local_.last_step_action_ = StepNone;
1486 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
1487 thread_local_.last_fp_ = 0;
1488 }
1489
1490
EnsureCompiled(Handle<SharedFunctionInfo> shared)1491 bool Debug::EnsureCompiled(Handle<SharedFunctionInfo> shared) {
1492 if (shared->is_compiled()) return true;
1493 return CompileLazyShared(shared, CLEAR_EXCEPTION, 0);
1494 }
1495
1496
1497 // Ensures the debug information is present for shared.
EnsureDebugInfo(Handle<SharedFunctionInfo> shared)1498 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
1499 // Return if we already have the debug info for shared.
1500 if (HasDebugInfo(shared)) return true;
1501
1502 // Ensure shared in compiled. Return false if this failed.
1503 if (!EnsureCompiled(shared)) return false;
1504
1505 // Create the debug info object.
1506 Handle<DebugInfo> debug_info = Factory::NewDebugInfo(shared);
1507
1508 // Add debug info to the list.
1509 DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
1510 node->set_next(debug_info_list_);
1511 debug_info_list_ = node;
1512
1513 // Now there is at least one break point.
1514 has_break_points_ = true;
1515
1516 return true;
1517 }
1518
1519
RemoveDebugInfo(Handle<DebugInfo> debug_info)1520 void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
1521 ASSERT(debug_info_list_ != NULL);
1522 // Run through the debug info objects to find this one and remove it.
1523 DebugInfoListNode* prev = NULL;
1524 DebugInfoListNode* current = debug_info_list_;
1525 while (current != NULL) {
1526 if (*current->debug_info() == *debug_info) {
1527 // Unlink from list. If prev is NULL we are looking at the first element.
1528 if (prev == NULL) {
1529 debug_info_list_ = current->next();
1530 } else {
1531 prev->set_next(current->next());
1532 }
1533 current->debug_info()->shared()->set_debug_info(Heap::undefined_value());
1534 delete current;
1535
1536 // If there are no more debug info objects there are not more break
1537 // points.
1538 has_break_points_ = debug_info_list_ != NULL;
1539
1540 return;
1541 }
1542 // Move to next in list.
1543 prev = current;
1544 current = current->next();
1545 }
1546 UNREACHABLE();
1547 }
1548
1549
SetAfterBreakTarget(JavaScriptFrame * frame)1550 void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
1551 HandleScope scope;
1552
1553 // Get the executing function in which the debug break occurred.
1554 Handle<SharedFunctionInfo> shared =
1555 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
1556 if (!EnsureDebugInfo(shared)) {
1557 // Return if we failed to retrieve the debug info.
1558 return;
1559 }
1560 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1561 Handle<Code> code(debug_info->code());
1562 Handle<Code> original_code(debug_info->original_code());
1563 #ifdef DEBUG
1564 // Get the code which is actually executing.
1565 Handle<Code> frame_code(frame->code());
1566 ASSERT(frame_code.is_identical_to(code));
1567 #endif
1568
1569 // Find the call address in the running code. This address holds the call to
1570 // either a DebugBreakXXX or to the debug break return entry code if the
1571 // break point is still active after processing the break point.
1572 Address addr = frame->pc() - Assembler::kPatchReturnSequenceLength;
1573
1574 // Check if the location is at JS exit.
1575 bool at_js_exit = false;
1576 RelocIterator it(debug_info->code());
1577 while (!it.done()) {
1578 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
1579 at_js_exit = (it.rinfo()->pc() ==
1580 addr - Assembler::kPatchReturnSequenceAddressOffset);
1581 }
1582 it.next();
1583 }
1584
1585 // Handle the jump to continue execution after break point depending on the
1586 // break location.
1587 if (at_js_exit) {
1588 // First check if the call in the code is still the debug break return
1589 // entry code. If it is the break point is still active. If not the break
1590 // point was removed during break point processing.
1591 if (Assembler::target_address_at(addr) ==
1592 debug_break_return_entry()->entry()) {
1593 // Break point still active. Jump to the corresponding place in the
1594 // original code.
1595 addr += original_code->instruction_start() - code->instruction_start();
1596 }
1597
1598 // Move back to where the call instruction sequence started.
1599 thread_local_.after_break_target_ =
1600 addr - Assembler::kPatchReturnSequenceAddressOffset;
1601 } else {
1602 // Check if there still is a debug break call at the target address. If the
1603 // break point has been removed it will have disappeared. If it have
1604 // disappeared don't try to look in the original code as the running code
1605 // will have the right address. This takes care of the case where the last
1606 // break point is removed from the function and therefore no "original code"
1607 // is available. If the debug break call is still there find the address in
1608 // the original code.
1609 if (IsDebugBreak(Assembler::target_address_at(addr))) {
1610 // If the break point is still there find the call address which was
1611 // overwritten in the original code by the call to DebugBreakXXX.
1612
1613 // Find the corresponding address in the original code.
1614 addr += original_code->instruction_start() - code->instruction_start();
1615 }
1616
1617 // Install jump to the call address in the original code. This will be the
1618 // call which was overwritten by the call to DebugBreakXXX.
1619 thread_local_.after_break_target_ = Assembler::target_address_at(addr);
1620 }
1621 }
1622
1623
IsDebugGlobal(GlobalObject * global)1624 bool Debug::IsDebugGlobal(GlobalObject* global) {
1625 return IsLoaded() && global == Debug::debug_context()->global();
1626 }
1627
1628
ClearMirrorCache()1629 void Debug::ClearMirrorCache() {
1630 HandleScope scope;
1631 ASSERT(Top::context() == *Debug::debug_context());
1632
1633 // Clear the mirror cache.
1634 Handle<String> function_name =
1635 Factory::LookupSymbol(CStrVector("ClearMirrorCache"));
1636 Handle<Object> fun(Top::global()->GetProperty(*function_name));
1637 ASSERT(fun->IsJSFunction());
1638 bool caught_exception;
1639 Handle<Object> js_object = Execution::TryCall(
1640 Handle<JSFunction>::cast(fun),
1641 Handle<JSObject>(Debug::debug_context()->global()),
1642 0, NULL, &caught_exception);
1643 }
1644
1645
1646 // If an object given is an external string, check that the underlying
1647 // resource is accessible. For other kinds of objects, always return true.
IsExternalStringValid(Object * str)1648 static bool IsExternalStringValid(Object* str) {
1649 if (!str->IsString() || !StringShape(String::cast(str)).IsExternal()) {
1650 return true;
1651 }
1652 if (String::cast(str)->IsAsciiRepresentation()) {
1653 return ExternalAsciiString::cast(str)->resource() != NULL;
1654 } else if (String::cast(str)->IsTwoByteRepresentation()) {
1655 return ExternalTwoByteString::cast(str)->resource() != NULL;
1656 } else {
1657 return true;
1658 }
1659 }
1660
1661
CreateScriptCache()1662 void Debug::CreateScriptCache() {
1663 HandleScope scope;
1664
1665 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
1666 // rid of all the cached script wrappers and the second gets rid of the
1667 // scripts which is no longer referenced.
1668 Heap::CollectAllGarbage(false);
1669 Heap::CollectAllGarbage(false);
1670
1671 ASSERT(script_cache_ == NULL);
1672 script_cache_ = new ScriptCache();
1673
1674 // Scan heap for Script objects.
1675 int count = 0;
1676 HeapIterator iterator;
1677 while (iterator.has_next()) {
1678 HeapObject* obj = iterator.next();
1679 ASSERT(obj != NULL);
1680 if (obj->IsScript() && IsExternalStringValid(Script::cast(obj)->source())) {
1681 script_cache_->Add(Handle<Script>(Script::cast(obj)));
1682 count++;
1683 }
1684 }
1685 }
1686
1687
DestroyScriptCache()1688 void Debug::DestroyScriptCache() {
1689 // Get rid of the script cache if it was created.
1690 if (script_cache_ != NULL) {
1691 delete script_cache_;
1692 script_cache_ = NULL;
1693 }
1694 }
1695
1696
AddScriptToScriptCache(Handle<Script> script)1697 void Debug::AddScriptToScriptCache(Handle<Script> script) {
1698 if (script_cache_ != NULL) {
1699 script_cache_->Add(script);
1700 }
1701 }
1702
1703
GetLoadedScripts()1704 Handle<FixedArray> Debug::GetLoadedScripts() {
1705 // Create and fill the script cache when the loaded scripts is requested for
1706 // the first time.
1707 if (script_cache_ == NULL) {
1708 CreateScriptCache();
1709 }
1710
1711 // If the script cache is not active just return an empty array.
1712 ASSERT(script_cache_ != NULL);
1713 if (script_cache_ == NULL) {
1714 Factory::NewFixedArray(0);
1715 }
1716
1717 // Perform GC to get unreferenced scripts evicted from the cache before
1718 // returning the content.
1719 Heap::CollectAllGarbage(false);
1720
1721 // Get the scripts from the cache.
1722 return script_cache_->GetScripts();
1723 }
1724
1725
AfterGarbageCollection()1726 void Debug::AfterGarbageCollection() {
1727 // Generate events for collected scripts.
1728 if (script_cache_ != NULL) {
1729 script_cache_->ProcessCollectedScripts();
1730 }
1731 }
1732
1733
1734 Mutex* Debugger::debugger_access_ = OS::CreateMutex();
1735 Handle<Object> Debugger::event_listener_ = Handle<Object>();
1736 Handle<Object> Debugger::event_listener_data_ = Handle<Object>();
1737 bool Debugger::compiling_natives_ = false;
1738 bool Debugger::is_loading_debugger_ = false;
1739 bool Debugger::never_unload_debugger_ = false;
1740 v8::Debug::MessageHandler2 Debugger::message_handler_ = NULL;
1741 bool Debugger::debugger_unload_pending_ = false;
1742 v8::Debug::HostDispatchHandler Debugger::host_dispatch_handler_ = NULL;
1743 int Debugger::host_dispatch_micros_ = 100 * 1000;
1744 DebuggerAgent* Debugger::agent_ = NULL;
1745 LockingCommandMessageQueue Debugger::command_queue_(kQueueInitialSize);
1746 Semaphore* Debugger::command_received_ = OS::CreateSemaphore(0);
1747
1748
MakeJSObject(Vector<const char> constructor_name,int argc,Object *** argv,bool * caught_exception)1749 Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
1750 int argc, Object*** argv,
1751 bool* caught_exception) {
1752 ASSERT(Top::context() == *Debug::debug_context());
1753
1754 // Create the execution state object.
1755 Handle<String> constructor_str = Factory::LookupSymbol(constructor_name);
1756 Handle<Object> constructor(Top::global()->GetProperty(*constructor_str));
1757 ASSERT(constructor->IsJSFunction());
1758 if (!constructor->IsJSFunction()) {
1759 *caught_exception = true;
1760 return Factory::undefined_value();
1761 }
1762 Handle<Object> js_object = Execution::TryCall(
1763 Handle<JSFunction>::cast(constructor),
1764 Handle<JSObject>(Debug::debug_context()->global()), argc, argv,
1765 caught_exception);
1766 return js_object;
1767 }
1768
1769
MakeExecutionState(bool * caught_exception)1770 Handle<Object> Debugger::MakeExecutionState(bool* caught_exception) {
1771 // Create the execution state object.
1772 Handle<Object> break_id = Factory::NewNumberFromInt(Debug::break_id());
1773 const int argc = 1;
1774 Object** argv[argc] = { break_id.location() };
1775 return MakeJSObject(CStrVector("MakeExecutionState"),
1776 argc, argv, caught_exception);
1777 }
1778
1779
MakeBreakEvent(Handle<Object> exec_state,Handle<Object> break_points_hit,bool * caught_exception)1780 Handle<Object> Debugger::MakeBreakEvent(Handle<Object> exec_state,
1781 Handle<Object> break_points_hit,
1782 bool* caught_exception) {
1783 // Create the new break event object.
1784 const int argc = 2;
1785 Object** argv[argc] = { exec_state.location(),
1786 break_points_hit.location() };
1787 return MakeJSObject(CStrVector("MakeBreakEvent"),
1788 argc,
1789 argv,
1790 caught_exception);
1791 }
1792
1793
MakeExceptionEvent(Handle<Object> exec_state,Handle<Object> exception,bool uncaught,bool * caught_exception)1794 Handle<Object> Debugger::MakeExceptionEvent(Handle<Object> exec_state,
1795 Handle<Object> exception,
1796 bool uncaught,
1797 bool* caught_exception) {
1798 // Create the new exception event object.
1799 const int argc = 3;
1800 Object** argv[argc] = { exec_state.location(),
1801 exception.location(),
1802 uncaught ? Factory::true_value().location() :
1803 Factory::false_value().location()};
1804 return MakeJSObject(CStrVector("MakeExceptionEvent"),
1805 argc, argv, caught_exception);
1806 }
1807
1808
MakeNewFunctionEvent(Handle<Object> function,bool * caught_exception)1809 Handle<Object> Debugger::MakeNewFunctionEvent(Handle<Object> function,
1810 bool* caught_exception) {
1811 // Create the new function event object.
1812 const int argc = 1;
1813 Object** argv[argc] = { function.location() };
1814 return MakeJSObject(CStrVector("MakeNewFunctionEvent"),
1815 argc, argv, caught_exception);
1816 }
1817
1818
MakeCompileEvent(Handle<Script> script,bool before,bool * caught_exception)1819 Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
1820 bool before,
1821 bool* caught_exception) {
1822 // Create the compile event object.
1823 Handle<Object> exec_state = MakeExecutionState(caught_exception);
1824 Handle<Object> script_wrapper = GetScriptWrapper(script);
1825 const int argc = 3;
1826 Object** argv[argc] = { exec_state.location(),
1827 script_wrapper.location(),
1828 before ? Factory::true_value().location() :
1829 Factory::false_value().location() };
1830
1831 return MakeJSObject(CStrVector("MakeCompileEvent"),
1832 argc,
1833 argv,
1834 caught_exception);
1835 }
1836
1837
MakeScriptCollectedEvent(int id,bool * caught_exception)1838 Handle<Object> Debugger::MakeScriptCollectedEvent(int id,
1839 bool* caught_exception) {
1840 // Create the script collected event object.
1841 Handle<Object> exec_state = MakeExecutionState(caught_exception);
1842 Handle<Object> id_object = Handle<Smi>(Smi::FromInt(id));
1843 const int argc = 2;
1844 Object** argv[argc] = { exec_state.location(), id_object.location() };
1845
1846 return MakeJSObject(CStrVector("MakeScriptCollectedEvent"),
1847 argc,
1848 argv,
1849 caught_exception);
1850 }
1851
1852
OnException(Handle<Object> exception,bool uncaught)1853 void Debugger::OnException(Handle<Object> exception, bool uncaught) {
1854 HandleScope scope;
1855
1856 // Bail out based on state or if there is no listener for this event
1857 if (Debug::InDebugger()) return;
1858 if (!Debugger::EventActive(v8::Exception)) return;
1859
1860 // Bail out if exception breaks are not active
1861 if (uncaught) {
1862 // Uncaught exceptions are reported by either flags.
1863 if (!(Debug::break_on_uncaught_exception() ||
1864 Debug::break_on_exception())) return;
1865 } else {
1866 // Caught exceptions are reported is activated.
1867 if (!Debug::break_on_exception()) return;
1868 }
1869
1870 // Enter the debugger.
1871 EnterDebugger debugger;
1872 if (debugger.FailedToEnter()) return;
1873
1874 // Clear all current stepping setup.
1875 Debug::ClearStepping();
1876 // Create the event data object.
1877 bool caught_exception = false;
1878 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
1879 Handle<Object> event_data;
1880 if (!caught_exception) {
1881 event_data = MakeExceptionEvent(exec_state, exception, uncaught,
1882 &caught_exception);
1883 }
1884 // Bail out and don't call debugger if exception.
1885 if (caught_exception) {
1886 return;
1887 }
1888
1889 // Process debug event.
1890 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false);
1891 // Return to continue execution from where the exception was thrown.
1892 }
1893
1894
OnDebugBreak(Handle<Object> break_points_hit,bool auto_continue)1895 void Debugger::OnDebugBreak(Handle<Object> break_points_hit,
1896 bool auto_continue) {
1897 HandleScope scope;
1898
1899 // Debugger has already been entered by caller.
1900 ASSERT(Top::context() == *Debug::debug_context());
1901
1902 // Bail out if there is no listener for this event
1903 if (!Debugger::EventActive(v8::Break)) return;
1904
1905 // Debugger must be entered in advance.
1906 ASSERT(Top::context() == *Debug::debug_context());
1907
1908 // Create the event data object.
1909 bool caught_exception = false;
1910 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
1911 Handle<Object> event_data;
1912 if (!caught_exception) {
1913 event_data = MakeBreakEvent(exec_state, break_points_hit,
1914 &caught_exception);
1915 }
1916 // Bail out and don't call debugger if exception.
1917 if (caught_exception) {
1918 return;
1919 }
1920
1921 // Process debug event.
1922 ProcessDebugEvent(v8::Break,
1923 Handle<JSObject>::cast(event_data),
1924 auto_continue);
1925 }
1926
1927
OnBeforeCompile(Handle<Script> script)1928 void Debugger::OnBeforeCompile(Handle<Script> script) {
1929 HandleScope scope;
1930
1931 // Bail out based on state or if there is no listener for this event
1932 if (Debug::InDebugger()) return;
1933 if (compiling_natives()) return;
1934 if (!EventActive(v8::BeforeCompile)) return;
1935
1936 // Enter the debugger.
1937 EnterDebugger debugger;
1938 if (debugger.FailedToEnter()) return;
1939
1940 // Create the event data object.
1941 bool caught_exception = false;
1942 Handle<Object> event_data = MakeCompileEvent(script, true, &caught_exception);
1943 // Bail out and don't call debugger if exception.
1944 if (caught_exception) {
1945 return;
1946 }
1947
1948 // Process debug event.
1949 ProcessDebugEvent(v8::BeforeCompile,
1950 Handle<JSObject>::cast(event_data),
1951 true);
1952 }
1953
1954
1955 // Handle debugger actions when a new script is compiled.
OnAfterCompile(Handle<Script> script,Handle<JSFunction> fun)1956 void Debugger::OnAfterCompile(Handle<Script> script, Handle<JSFunction> fun) {
1957 HandleScope scope;
1958
1959 // Add the newly compiled script to the script cache.
1960 Debug::AddScriptToScriptCache(script);
1961
1962 // No more to do if not debugging.
1963 if (!IsDebuggerActive()) return;
1964
1965 // No compile events while compiling natives.
1966 if (compiling_natives()) return;
1967
1968 // Store whether in debugger before entering debugger.
1969 bool in_debugger = Debug::InDebugger();
1970
1971 // Enter the debugger.
1972 EnterDebugger debugger;
1973 if (debugger.FailedToEnter()) return;
1974
1975 // If debugging there might be script break points registered for this
1976 // script. Make sure that these break points are set.
1977
1978 // Get the function UpdateScriptBreakPoints (defined in debug-delay.js).
1979 Handle<Object> update_script_break_points =
1980 Handle<Object>(Debug::debug_context()->global()->GetProperty(
1981 *Factory::LookupAsciiSymbol("UpdateScriptBreakPoints")));
1982 if (!update_script_break_points->IsJSFunction()) {
1983 return;
1984 }
1985 ASSERT(update_script_break_points->IsJSFunction());
1986
1987 // Wrap the script object in a proper JS object before passing it
1988 // to JavaScript.
1989 Handle<JSValue> wrapper = GetScriptWrapper(script);
1990
1991 // Call UpdateScriptBreakPoints expect no exceptions.
1992 bool caught_exception = false;
1993 const int argc = 1;
1994 Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) };
1995 Handle<Object> result = Execution::TryCall(
1996 Handle<JSFunction>::cast(update_script_break_points),
1997 Top::builtins(), argc, argv,
1998 &caught_exception);
1999 if (caught_exception) {
2000 return;
2001 }
2002 // Bail out based on state or if there is no listener for this event
2003 if (in_debugger) return;
2004 if (!Debugger::EventActive(v8::AfterCompile)) return;
2005
2006 // Create the compile state object.
2007 Handle<Object> event_data = MakeCompileEvent(script,
2008 false,
2009 &caught_exception);
2010 // Bail out and don't call debugger if exception.
2011 if (caught_exception) {
2012 return;
2013 }
2014 // Process debug event.
2015 ProcessDebugEvent(v8::AfterCompile,
2016 Handle<JSObject>::cast(event_data),
2017 true);
2018 }
2019
2020
OnNewFunction(Handle<JSFunction> function)2021 void Debugger::OnNewFunction(Handle<JSFunction> function) {
2022 return;
2023 HandleScope scope;
2024
2025 // Bail out based on state or if there is no listener for this event
2026 if (Debug::InDebugger()) return;
2027 if (compiling_natives()) return;
2028 if (!Debugger::EventActive(v8::NewFunction)) return;
2029
2030 // Enter the debugger.
2031 EnterDebugger debugger;
2032 if (debugger.FailedToEnter()) return;
2033
2034 // Create the event object.
2035 bool caught_exception = false;
2036 Handle<Object> event_data = MakeNewFunctionEvent(function, &caught_exception);
2037 // Bail out and don't call debugger if exception.
2038 if (caught_exception) {
2039 return;
2040 }
2041 // Process debug event.
2042 ProcessDebugEvent(v8::NewFunction, Handle<JSObject>::cast(event_data), true);
2043 }
2044
2045
OnScriptCollected(int id)2046 void Debugger::OnScriptCollected(int id) {
2047 HandleScope scope;
2048
2049 // No more to do if not debugging.
2050 if (!IsDebuggerActive()) return;
2051 if (!Debugger::EventActive(v8::ScriptCollected)) return;
2052
2053 // Enter the debugger.
2054 EnterDebugger debugger;
2055 if (debugger.FailedToEnter()) return;
2056
2057 // Create the script collected state object.
2058 bool caught_exception = false;
2059 Handle<Object> event_data = MakeScriptCollectedEvent(id,
2060 &caught_exception);
2061 // Bail out and don't call debugger if exception.
2062 if (caught_exception) {
2063 return;
2064 }
2065
2066 // Process debug event.
2067 ProcessDebugEvent(v8::ScriptCollected,
2068 Handle<JSObject>::cast(event_data),
2069 true);
2070 }
2071
2072
ProcessDebugEvent(v8::DebugEvent event,Handle<JSObject> event_data,bool auto_continue)2073 void Debugger::ProcessDebugEvent(v8::DebugEvent event,
2074 Handle<JSObject> event_data,
2075 bool auto_continue) {
2076 HandleScope scope;
2077
2078 // Clear any pending debug break if this is a real break.
2079 if (!auto_continue) {
2080 Debug::clear_interrupt_pending(DEBUGBREAK);
2081 }
2082
2083 // Create the execution state.
2084 bool caught_exception = false;
2085 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2086 if (caught_exception) {
2087 return;
2088 }
2089 // First notify the message handler if any.
2090 if (message_handler_ != NULL) {
2091 NotifyMessageHandler(event,
2092 Handle<JSObject>::cast(exec_state),
2093 event_data,
2094 auto_continue);
2095 }
2096 // Notify registered debug event listener. This can be either a C or a
2097 // JavaScript function.
2098 if (!event_listener_.is_null()) {
2099 if (event_listener_->IsProxy()) {
2100 // C debug event listener.
2101 Handle<Proxy> callback_obj(Handle<Proxy>::cast(event_listener_));
2102 v8::Debug::EventCallback callback =
2103 FUNCTION_CAST<v8::Debug::EventCallback>(callback_obj->proxy());
2104 callback(event,
2105 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
2106 v8::Utils::ToLocal(event_data),
2107 v8::Utils::ToLocal(Handle<Object>::cast(event_listener_data_)));
2108 } else {
2109 // JavaScript debug event listener.
2110 ASSERT(event_listener_->IsJSFunction());
2111 Handle<JSFunction> fun(Handle<JSFunction>::cast(event_listener_));
2112
2113 // Invoke the JavaScript debug event listener.
2114 const int argc = 4;
2115 Object** argv[argc] = { Handle<Object>(Smi::FromInt(event)).location(),
2116 exec_state.location(),
2117 Handle<Object>::cast(event_data).location(),
2118 event_listener_data_.location() };
2119 Handle<Object> result = Execution::TryCall(fun, Top::global(),
2120 argc, argv, &caught_exception);
2121 // Silently ignore exceptions from debug event listeners.
2122 }
2123 }
2124 }
2125
2126
UnloadDebugger()2127 void Debugger::UnloadDebugger() {
2128 // Make sure that there are no breakpoints left.
2129 Debug::ClearAllBreakPoints();
2130
2131 // Unload the debugger if feasible.
2132 if (!never_unload_debugger_) {
2133 Debug::Unload();
2134 }
2135
2136 // Clear the flag indicating that the debugger should be unloaded.
2137 debugger_unload_pending_ = false;
2138 }
2139
2140
NotifyMessageHandler(v8::DebugEvent event,Handle<JSObject> exec_state,Handle<JSObject> event_data,bool auto_continue)2141 void Debugger::NotifyMessageHandler(v8::DebugEvent event,
2142 Handle<JSObject> exec_state,
2143 Handle<JSObject> event_data,
2144 bool auto_continue) {
2145 HandleScope scope;
2146
2147 if (!Debug::Load()) return;
2148
2149 // Process the individual events.
2150 bool sendEventMessage = false;
2151 switch (event) {
2152 case v8::Break:
2153 sendEventMessage = !auto_continue;
2154 break;
2155 case v8::Exception:
2156 sendEventMessage = true;
2157 break;
2158 case v8::BeforeCompile:
2159 break;
2160 case v8::AfterCompile:
2161 sendEventMessage = true;
2162 break;
2163 case v8::ScriptCollected:
2164 sendEventMessage = true;
2165 break;
2166 case v8::NewFunction:
2167 break;
2168 default:
2169 UNREACHABLE();
2170 }
2171
2172 // The debug command interrupt flag might have been set when the command was
2173 // added. It should be enough to clear the flag only once while we are in the
2174 // debugger.
2175 ASSERT(Debug::InDebugger());
2176 StackGuard::Continue(DEBUGCOMMAND);
2177
2178 // Notify the debugger that a debug event has occurred unless auto continue is
2179 // active in which case no event is send.
2180 if (sendEventMessage) {
2181 MessageImpl message = MessageImpl::NewEvent(
2182 event,
2183 auto_continue,
2184 Handle<JSObject>::cast(exec_state),
2185 Handle<JSObject>::cast(event_data));
2186 InvokeMessageHandler(message);
2187 }
2188
2189 // If auto continue don't make the event cause a break, but process messages
2190 // in the queue if any. For script collected events don't even process
2191 // messages in the queue as the execution state might not be what is expected
2192 // by the client.
2193 if ((auto_continue && !HasCommands()) || event == v8::ScriptCollected) {
2194 return;
2195 }
2196
2197 // Get the DebugCommandProcessor.
2198 v8::Local<v8::Object> api_exec_state =
2199 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state));
2200 v8::Local<v8::String> fun_name =
2201 v8::String::New("debugCommandProcessor");
2202 v8::Local<v8::Function> fun =
2203 v8::Function::Cast(*api_exec_state->Get(fun_name));
2204 v8::TryCatch try_catch;
2205 v8::Local<v8::Object> cmd_processor =
2206 v8::Object::Cast(*fun->Call(api_exec_state, 0, NULL));
2207 if (try_catch.HasCaught()) {
2208 PrintLn(try_catch.Exception());
2209 return;
2210 }
2211
2212 // Process requests from the debugger.
2213 while (true) {
2214 // Wait for new command in the queue.
2215 if (Debugger::host_dispatch_handler_) {
2216 // In case there is a host dispatch - do periodic dispatches.
2217 if (!command_received_->Wait(host_dispatch_micros_)) {
2218 // Timout expired, do the dispatch.
2219 Debugger::host_dispatch_handler_();
2220 continue;
2221 }
2222 } else {
2223 // In case there is no host dispatch - just wait.
2224 command_received_->Wait();
2225 }
2226
2227 // Get the command from the queue.
2228 CommandMessage command = command_queue_.Get();
2229 Logger::DebugTag("Got request from command queue, in interactive loop.");
2230 if (!Debugger::IsDebuggerActive()) {
2231 // Delete command text and user data.
2232 command.Dispose();
2233 return;
2234 }
2235
2236 // Invoke JavaScript to process the debug request.
2237 v8::Local<v8::String> fun_name;
2238 v8::Local<v8::Function> fun;
2239 v8::Local<v8::Value> request;
2240 v8::TryCatch try_catch;
2241 fun_name = v8::String::New("processDebugRequest");
2242 fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
2243
2244 request = v8::String::New(command.text().start(),
2245 command.text().length());
2246 static const int kArgc = 1;
2247 v8::Handle<Value> argv[kArgc] = { request };
2248 v8::Local<v8::Value> response_val = fun->Call(cmd_processor, kArgc, argv);
2249
2250 // Get the response.
2251 v8::Local<v8::String> response;
2252 bool running = false;
2253 if (!try_catch.HasCaught()) {
2254 // Get response string.
2255 if (!response_val->IsUndefined()) {
2256 response = v8::String::Cast(*response_val);
2257 } else {
2258 response = v8::String::New("");
2259 }
2260
2261 // Log the JSON request/response.
2262 if (FLAG_trace_debug_json) {
2263 PrintLn(request);
2264 PrintLn(response);
2265 }
2266
2267 // Get the running state.
2268 fun_name = v8::String::New("isRunning");
2269 fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
2270 static const int kArgc = 1;
2271 v8::Handle<Value> argv[kArgc] = { response };
2272 v8::Local<v8::Value> running_val = fun->Call(cmd_processor, kArgc, argv);
2273 if (!try_catch.HasCaught()) {
2274 running = running_val->ToBoolean()->Value();
2275 }
2276 } else {
2277 // In case of failure the result text is the exception text.
2278 response = try_catch.Exception()->ToString();
2279 }
2280
2281 // Return the result.
2282 MessageImpl message = MessageImpl::NewResponse(
2283 event,
2284 running,
2285 Handle<JSObject>::cast(exec_state),
2286 Handle<JSObject>::cast(event_data),
2287 Handle<String>(Utils::OpenHandle(*response)),
2288 command.client_data());
2289 InvokeMessageHandler(message);
2290 command.Dispose();
2291
2292 // Return from debug event processing if either the VM is put into the
2293 // runnning state (through a continue command) or auto continue is active
2294 // and there are no more commands queued.
2295 if (running || (auto_continue && !HasCommands())) {
2296 return;
2297 }
2298 }
2299 }
2300
2301
SetEventListener(Handle<Object> callback,Handle<Object> data)2302 void Debugger::SetEventListener(Handle<Object> callback,
2303 Handle<Object> data) {
2304 HandleScope scope;
2305
2306 // Clear the global handles for the event listener and the event listener data
2307 // object.
2308 if (!event_listener_.is_null()) {
2309 GlobalHandles::Destroy(
2310 reinterpret_cast<Object**>(event_listener_.location()));
2311 event_listener_ = Handle<Object>();
2312 }
2313 if (!event_listener_data_.is_null()) {
2314 GlobalHandles::Destroy(
2315 reinterpret_cast<Object**>(event_listener_data_.location()));
2316 event_listener_data_ = Handle<Object>();
2317 }
2318
2319 // If there is a new debug event listener register it together with its data
2320 // object.
2321 if (!callback->IsUndefined() && !callback->IsNull()) {
2322 event_listener_ = Handle<Object>::cast(GlobalHandles::Create(*callback));
2323 if (data.is_null()) {
2324 data = Factory::undefined_value();
2325 }
2326 event_listener_data_ = Handle<Object>::cast(GlobalHandles::Create(*data));
2327 }
2328
2329 ListenersChanged();
2330 }
2331
2332
SetMessageHandler(v8::Debug::MessageHandler2 handler)2333 void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) {
2334 ScopedLock with(debugger_access_);
2335
2336 message_handler_ = handler;
2337 ListenersChanged();
2338 if (handler == NULL) {
2339 // Send an empty command to the debugger if in a break to make JavaScript
2340 // run again if the debugger is closed.
2341 if (Debug::InDebugger()) {
2342 ProcessCommand(Vector<const uint16_t>::empty());
2343 }
2344 }
2345 }
2346
2347
ListenersChanged()2348 void Debugger::ListenersChanged() {
2349 if (IsDebuggerActive()) {
2350 // Disable the compilation cache when the debugger is active.
2351 CompilationCache::Disable();
2352 } else {
2353 CompilationCache::Enable();
2354
2355 // Unload the debugger if event listener and message handler cleared.
2356 if (Debug::InDebugger()) {
2357 // If we are in debugger set the flag to unload the debugger when last
2358 // EnterDebugger on the current stack is destroyed.
2359 debugger_unload_pending_ = true;
2360 } else {
2361 UnloadDebugger();
2362 }
2363 }
2364 }
2365
2366
SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,int period)2367 void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
2368 int period) {
2369 host_dispatch_handler_ = handler;
2370 host_dispatch_micros_ = period * 1000;
2371 }
2372
2373
2374 // Calls the registered debug message handler. This callback is part of the
2375 // public API.
InvokeMessageHandler(MessageImpl message)2376 void Debugger::InvokeMessageHandler(MessageImpl message) {
2377 ScopedLock with(debugger_access_);
2378
2379 if (message_handler_ != NULL) {
2380 message_handler_(message);
2381 }
2382 }
2383
2384
2385 // Puts a command coming from the public API on the queue. Creates
2386 // a copy of the command string managed by the debugger. Up to this
2387 // point, the command data was managed by the API client. Called
2388 // by the API client thread.
ProcessCommand(Vector<const uint16_t> command,v8::Debug::ClientData * client_data)2389 void Debugger::ProcessCommand(Vector<const uint16_t> command,
2390 v8::Debug::ClientData* client_data) {
2391 // Need to cast away const.
2392 CommandMessage message = CommandMessage::New(
2393 Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
2394 command.length()),
2395 client_data);
2396 Logger::DebugTag("Put command on command_queue.");
2397 command_queue_.Put(message);
2398 command_received_->Signal();
2399
2400 // Set the debug command break flag to have the command processed.
2401 if (!Debug::InDebugger()) {
2402 StackGuard::DebugCommand();
2403 }
2404 }
2405
2406
HasCommands()2407 bool Debugger::HasCommands() {
2408 return !command_queue_.IsEmpty();
2409 }
2410
2411
IsDebuggerActive()2412 bool Debugger::IsDebuggerActive() {
2413 ScopedLock with(debugger_access_);
2414
2415 return message_handler_ != NULL || !event_listener_.is_null();
2416 }
2417
2418
Call(Handle<JSFunction> fun,Handle<Object> data,bool * pending_exception)2419 Handle<Object> Debugger::Call(Handle<JSFunction> fun,
2420 Handle<Object> data,
2421 bool* pending_exception) {
2422 // When calling functions in the debugger prevent it from beeing unloaded.
2423 Debugger::never_unload_debugger_ = true;
2424
2425 // Enter the debugger.
2426 EnterDebugger debugger;
2427 if (debugger.FailedToEnter() || !debugger.HasJavaScriptFrames()) {
2428 return Factory::undefined_value();
2429 }
2430
2431 // Create the execution state.
2432 bool caught_exception = false;
2433 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2434 if (caught_exception) {
2435 return Factory::undefined_value();
2436 }
2437
2438 static const int kArgc = 2;
2439 Object** argv[kArgc] = { exec_state.location(), data.location() };
2440 Handle<Object> result = Execution::Call(fun, Factory::undefined_value(),
2441 kArgc, argv, pending_exception);
2442 return result;
2443 }
2444
2445
StartAgent(const char * name,int port)2446 bool Debugger::StartAgent(const char* name, int port) {
2447 if (Socket::Setup()) {
2448 agent_ = new DebuggerAgent(name, port);
2449 agent_->Start();
2450 return true;
2451 }
2452
2453 return false;
2454 }
2455
2456
StopAgent()2457 void Debugger::StopAgent() {
2458 if (agent_ != NULL) {
2459 agent_->Shutdown();
2460 agent_->Join();
2461 delete agent_;
2462 agent_ = NULL;
2463 }
2464 }
2465
2466
NewEvent(DebugEvent event,bool running,Handle<JSObject> exec_state,Handle<JSObject> event_data)2467 MessageImpl MessageImpl::NewEvent(DebugEvent event,
2468 bool running,
2469 Handle<JSObject> exec_state,
2470 Handle<JSObject> event_data) {
2471 MessageImpl message(true, event, running,
2472 exec_state, event_data, Handle<String>(), NULL);
2473 return message;
2474 }
2475
2476
NewResponse(DebugEvent event,bool running,Handle<JSObject> exec_state,Handle<JSObject> event_data,Handle<String> response_json,v8::Debug::ClientData * client_data)2477 MessageImpl MessageImpl::NewResponse(DebugEvent event,
2478 bool running,
2479 Handle<JSObject> exec_state,
2480 Handle<JSObject> event_data,
2481 Handle<String> response_json,
2482 v8::Debug::ClientData* client_data) {
2483 MessageImpl message(false, event, running,
2484 exec_state, event_data, response_json, client_data);
2485 return message;
2486 }
2487
2488
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)2489 MessageImpl::MessageImpl(bool is_event,
2490 DebugEvent event,
2491 bool running,
2492 Handle<JSObject> exec_state,
2493 Handle<JSObject> event_data,
2494 Handle<String> response_json,
2495 v8::Debug::ClientData* client_data)
2496 : is_event_(is_event),
2497 event_(event),
2498 running_(running),
2499 exec_state_(exec_state),
2500 event_data_(event_data),
2501 response_json_(response_json),
2502 client_data_(client_data) {}
2503
2504
IsEvent() const2505 bool MessageImpl::IsEvent() const {
2506 return is_event_;
2507 }
2508
2509
IsResponse() const2510 bool MessageImpl::IsResponse() const {
2511 return !is_event_;
2512 }
2513
2514
GetEvent() const2515 DebugEvent MessageImpl::GetEvent() const {
2516 return event_;
2517 }
2518
2519
WillStartRunning() const2520 bool MessageImpl::WillStartRunning() const {
2521 return running_;
2522 }
2523
2524
GetExecutionState() const2525 v8::Handle<v8::Object> MessageImpl::GetExecutionState() const {
2526 return v8::Utils::ToLocal(exec_state_);
2527 }
2528
2529
GetEventData() const2530 v8::Handle<v8::Object> MessageImpl::GetEventData() const {
2531 return v8::Utils::ToLocal(event_data_);
2532 }
2533
2534
GetJSON() const2535 v8::Handle<v8::String> MessageImpl::GetJSON() const {
2536 v8::HandleScope scope;
2537
2538 if (IsEvent()) {
2539 // Call toJSONProtocol on the debug event object.
2540 Handle<Object> fun = GetProperty(event_data_, "toJSONProtocol");
2541 if (!fun->IsJSFunction()) {
2542 return v8::Handle<v8::String>();
2543 }
2544 bool caught_exception;
2545 Handle<Object> json = Execution::TryCall(Handle<JSFunction>::cast(fun),
2546 event_data_,
2547 0, NULL, &caught_exception);
2548 if (caught_exception || !json->IsString()) {
2549 return v8::Handle<v8::String>();
2550 }
2551 return scope.Close(v8::Utils::ToLocal(Handle<String>::cast(json)));
2552 } else {
2553 return v8::Utils::ToLocal(response_json_);
2554 }
2555 }
2556
2557
GetEventContext() const2558 v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
2559 Handle<Context> context = Debug::debugger_entry()->GetContext();
2560 // Top::context() may have been NULL when "script collected" event occured.
2561 if (*context == NULL) {
2562 ASSERT(event_ == v8::ScriptCollected);
2563 return v8::Local<v8::Context>();
2564 }
2565 Handle<Context> global_context(context->global_context());
2566 return v8::Utils::ToLocal(global_context);
2567 }
2568
2569
GetClientData() const2570 v8::Debug::ClientData* MessageImpl::GetClientData() const {
2571 return client_data_;
2572 }
2573
2574
CommandMessage()2575 CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()),
2576 client_data_(NULL) {
2577 }
2578
2579
CommandMessage(const Vector<uint16_t> & text,v8::Debug::ClientData * data)2580 CommandMessage::CommandMessage(const Vector<uint16_t>& text,
2581 v8::Debug::ClientData* data)
2582 : text_(text),
2583 client_data_(data) {
2584 }
2585
2586
~CommandMessage()2587 CommandMessage::~CommandMessage() {
2588 }
2589
2590
Dispose()2591 void CommandMessage::Dispose() {
2592 text_.Dispose();
2593 delete client_data_;
2594 client_data_ = NULL;
2595 }
2596
2597
New(const Vector<uint16_t> & command,v8::Debug::ClientData * data)2598 CommandMessage CommandMessage::New(const Vector<uint16_t>& command,
2599 v8::Debug::ClientData* data) {
2600 return CommandMessage(command.Clone(), data);
2601 }
2602
2603
CommandMessageQueue(int size)2604 CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0),
2605 size_(size) {
2606 messages_ = NewArray<CommandMessage>(size);
2607 }
2608
2609
~CommandMessageQueue()2610 CommandMessageQueue::~CommandMessageQueue() {
2611 while (!IsEmpty()) {
2612 CommandMessage m = Get();
2613 m.Dispose();
2614 }
2615 DeleteArray(messages_);
2616 }
2617
2618
Get()2619 CommandMessage CommandMessageQueue::Get() {
2620 ASSERT(!IsEmpty());
2621 int result = start_;
2622 start_ = (start_ + 1) % size_;
2623 return messages_[result];
2624 }
2625
2626
Put(const CommandMessage & message)2627 void CommandMessageQueue::Put(const CommandMessage& message) {
2628 if ((end_ + 1) % size_ == start_) {
2629 Expand();
2630 }
2631 messages_[end_] = message;
2632 end_ = (end_ + 1) % size_;
2633 }
2634
2635
Expand()2636 void CommandMessageQueue::Expand() {
2637 CommandMessageQueue new_queue(size_ * 2);
2638 while (!IsEmpty()) {
2639 new_queue.Put(Get());
2640 }
2641 CommandMessage* array_to_free = messages_;
2642 *this = new_queue;
2643 new_queue.messages_ = array_to_free;
2644 // Make the new_queue empty so that it doesn't call Dispose on any messages.
2645 new_queue.start_ = new_queue.end_;
2646 // Automatic destructor called on new_queue, freeing array_to_free.
2647 }
2648
2649
LockingCommandMessageQueue(int size)2650 LockingCommandMessageQueue::LockingCommandMessageQueue(int size)
2651 : queue_(size) {
2652 lock_ = OS::CreateMutex();
2653 }
2654
2655
~LockingCommandMessageQueue()2656 LockingCommandMessageQueue::~LockingCommandMessageQueue() {
2657 delete lock_;
2658 }
2659
2660
IsEmpty() const2661 bool LockingCommandMessageQueue::IsEmpty() const {
2662 ScopedLock sl(lock_);
2663 return queue_.IsEmpty();
2664 }
2665
2666
Get()2667 CommandMessage LockingCommandMessageQueue::Get() {
2668 ScopedLock sl(lock_);
2669 CommandMessage result = queue_.Get();
2670 Logger::DebugEvent("Get", result.text());
2671 return result;
2672 }
2673
2674
Put(const CommandMessage & message)2675 void LockingCommandMessageQueue::Put(const CommandMessage& message) {
2676 ScopedLock sl(lock_);
2677 queue_.Put(message);
2678 Logger::DebugEvent("Put", message.text());
2679 }
2680
2681
Clear()2682 void LockingCommandMessageQueue::Clear() {
2683 ScopedLock sl(lock_);
2684 queue_.Clear();
2685 }
2686
2687 #endif // ENABLE_DEBUGGER_SUPPORT
2688
2689 } } // namespace v8::internal
2690