blob: e37bfb77ca2cf113c41a891d85cbc9441a69badc [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// 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"
kasperl@chromium.org71affb52009-05-26 05:44:31 +000034#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035#include "compiler.h"
36#include "debug.h"
37#include "execution.h"
38#include "global-handles.h"
ager@chromium.org65dad4b2009-04-23 08:48:43 +000039#include "ic.h"
40#include "ic-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "natives.h"
42#include "stub-cache.h"
kasper.lund7276f142008-07-30 08:49:36 +000043#include "log.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044
ager@chromium.org5ec48922009-05-05 07:25:34 +000045#include "../include/v8-debug.h"
46
kasperl@chromium.org71affb52009-05-26 05:44:31 +000047namespace v8 {
48namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000049
ager@chromium.org65dad4b2009-04-23 08:48:43 +000050#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051static 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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064static Handle<Code> ComputeCallDebugBreak(int argc) {
65 CALL_HEAP_FUNCTION(StubCache::ComputeCallDebugBreak(argc), Code);
66}
67
68
69static Handle<Code> ComputeCallDebugPrepareStepIn(int argc) {
70 CALL_HEAP_FUNCTION(StubCache::ComputeCallDebugPrepareStepIn(argc), Code);
71}
72
73
74BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info,
75 BreakLocatorType type) {
76 debug_info_ = debug_info;
77 type_ = type;
78 reloc_iterator_ = NULL;
79 reloc_iterator_original_ = NULL;
80 Reset(); // Initialize the rest of the member variables.
81}
82
83
84BreakLocationIterator::~BreakLocationIterator() {
85 ASSERT(reloc_iterator_ != NULL);
86 ASSERT(reloc_iterator_original_ != NULL);
87 delete reloc_iterator_;
88 delete reloc_iterator_original_;
89}
90
91
92void BreakLocationIterator::Next() {
93 AssertNoAllocation nogc;
94 ASSERT(!RinfoDone());
95
96 // Iterate through reloc info for code and original code stopping at each
97 // breakable code target.
98 bool first = break_point_ == -1;
99 while (!RinfoDone()) {
100 if (!first) RinfoNext();
101 first = false;
102 if (RinfoDone()) return;
103
ager@chromium.org236ad962008-09-25 09:45:57 +0000104 // Whenever a statement position or (plain) position is passed update the
105 // current value of these.
106 if (RelocInfo::IsPosition(rmode())) {
107 if (RelocInfo::IsStatementPosition(rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108 statement_position_ =
109 rinfo()->data() - debug_info_->shared()->start_position();
110 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000111 // Always update the position as we don't want that to be before the
112 // statement position.
113 position_ = rinfo()->data() - debug_info_->shared()->start_position();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000114 ASSERT(position_ >= 0);
115 ASSERT(statement_position_ >= 0);
116 }
117
118 // Check for breakable code target. Look in the original code as setting
119 // break points can cause the code targets in the running (debugged) code to
120 // be of a different kind than in the original code.
ager@chromium.org236ad962008-09-25 09:45:57 +0000121 if (RelocInfo::IsCodeTarget(rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000122 Address target = original_rinfo()->target_address();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000123 Code* code = Code::GetCodeFromTargetAddress(target);
ager@chromium.org236ad962008-09-25 09:45:57 +0000124 if (code->is_inline_cache_stub() || RelocInfo::IsConstructCall(rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000125 break_point_++;
126 return;
127 }
128 if (code->kind() == Code::STUB) {
129 if (type_ == ALL_BREAK_LOCATIONS) {
130 if (Debug::IsBreakStub(code)) {
131 break_point_++;
132 return;
133 }
134 } else {
135 ASSERT(type_ == SOURCE_BREAK_LOCATIONS);
136 if (Debug::IsSourceBreakStub(code)) {
137 break_point_++;
138 return;
139 }
140 }
141 }
142 }
143
144 // Check for break at return.
ager@chromium.org236ad962008-09-25 09:45:57 +0000145 if (RelocInfo::IsJSReturn(rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000146 // Set the positions to the end of the function.
147 if (debug_info_->shared()->HasSourceCode()) {
148 position_ = debug_info_->shared()->end_position() -
149 debug_info_->shared()->start_position();
150 } else {
151 position_ = 0;
152 }
153 statement_position_ = position_;
154 break_point_++;
155 return;
156 }
157 }
158}
159
160
161void BreakLocationIterator::Next(int count) {
162 while (count > 0) {
163 Next();
164 count--;
165 }
166}
167
168
169// Find the break point closest to the supplied address.
170void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) {
171 // Run through all break points to locate the one closest to the address.
172 int closest_break_point = 0;
173 int distance = kMaxInt;
174 while (!Done()) {
175 // Check if this break point is closer that what was previously found.
176 if (this->pc() < pc && pc - this->pc() < distance) {
177 closest_break_point = break_point();
178 distance = pc - this->pc();
179 // Check whether we can't get any closer.
180 if (distance == 0) break;
181 }
182 Next();
183 }
184
185 // Move to the break point found.
186 Reset();
187 Next(closest_break_point);
188}
189
190
191// Find the break point closest to the supplied source position.
192void BreakLocationIterator::FindBreakLocationFromPosition(int position) {
193 // Run through all break points to locate the one closest to the source
194 // position.
195 int closest_break_point = 0;
196 int distance = kMaxInt;
197 while (!Done()) {
198 // Check if this break point is closer that what was previously found.
199 if (position <= statement_position() &&
200 statement_position() - position < distance) {
201 closest_break_point = break_point();
202 distance = statement_position() - position;
203 // Check whether we can't get any closer.
204 if (distance == 0) break;
205 }
206 Next();
207 }
208
209 // Move to the break point found.
210 Reset();
211 Next(closest_break_point);
212}
213
214
215void BreakLocationIterator::Reset() {
216 // Create relocation iterators for the two code objects.
217 if (reloc_iterator_ != NULL) delete reloc_iterator_;
218 if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_;
219 reloc_iterator_ = new RelocIterator(debug_info_->code());
220 reloc_iterator_original_ = new RelocIterator(debug_info_->original_code());
221
222 // Position at the first break point.
223 break_point_ = -1;
224 position_ = 1;
225 statement_position_ = 1;
226 Next();
227}
228
229
230bool BreakLocationIterator::Done() const {
231 return RinfoDone();
232}
233
234
235void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) {
236 // If there is not already a real break point here patch code with debug
237 // break.
238 if (!HasBreakPoint()) {
239 SetDebugBreak();
240 }
241 ASSERT(IsDebugBreak());
242 // Set the break point information.
243 DebugInfo::SetBreakPoint(debug_info_, code_position(),
244 position(), statement_position(),
245 break_point_object);
246}
247
248
249void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) {
250 // Clear the break point information.
251 DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object);
252 // If there are no more break points here remove the debug break.
253 if (!HasBreakPoint()) {
254 ClearDebugBreak();
255 ASSERT(!IsDebugBreak());
256 }
257}
258
259
260void BreakLocationIterator::SetOneShot() {
261 // If there is a real break point here no more to do.
262 if (HasBreakPoint()) {
263 ASSERT(IsDebugBreak());
264 return;
265 }
266
267 // Patch code with debug break.
268 SetDebugBreak();
269}
270
271
272void BreakLocationIterator::ClearOneShot() {
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 removing debug break.
280 ClearDebugBreak();
281 ASSERT(!IsDebugBreak());
282}
283
284
285void BreakLocationIterator::SetDebugBreak() {
286 // If there is already a break point here just return. This might happen if
v8.team.kasperl727e9952008-09-02 14:56:44 +0000287 // the same code is flooded with break points twice. Flooding the same
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000288 // function twice might happen when stepping in a function with an exception
289 // handler as the handler and the function is the same.
290 if (IsDebugBreak()) {
291 return;
292 }
293
ager@chromium.org236ad962008-09-25 09:45:57 +0000294 if (RelocInfo::IsJSReturn(rmode())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000295 // Patch the frame exit code with a break point.
296 SetDebugBreakAtReturn();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000297 } else {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000298 // Patch the IC call.
299 SetDebugBreakAtIC();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000300 }
301 ASSERT(IsDebugBreak());
302}
303
304
305void BreakLocationIterator::ClearDebugBreak() {
ager@chromium.org236ad962008-09-25 09:45:57 +0000306 if (RelocInfo::IsJSReturn(rmode())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000307 // Restore the frame exit code.
308 ClearDebugBreakAtReturn();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000309 } else {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000310 // Patch the IC call.
311 ClearDebugBreakAtIC();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000312 }
313 ASSERT(!IsDebugBreak());
314}
315
316
317void BreakLocationIterator::PrepareStepIn() {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000318 HandleScope scope;
319
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320 // Step in can only be prepared if currently positioned on an IC call or
321 // construct call.
322 Address target = rinfo()->target_address();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000323 Code* code = Code::GetCodeFromTargetAddress(target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000324 if (code->is_call_stub()) {
325 // Step in through IC call is handled by the runtime system. Therefore make
326 // sure that the any current IC is cleared and the runtime system is
327 // called. If the executing code has a debug break at the location change
328 // the call in the original code as it is the code there that will be
329 // executed in place of the debug break call.
330 Handle<Code> stub = ComputeCallDebugPrepareStepIn(code->arguments_count());
331 if (IsDebugBreak()) {
332 original_rinfo()->set_target_address(stub->entry());
333 } else {
334 rinfo()->set_target_address(stub->entry());
335 }
336 } else {
v8.team.kasperl727e9952008-09-02 14:56:44 +0000337 // Step in through constructs call requires no changes to the running code.
ager@chromium.org236ad962008-09-25 09:45:57 +0000338 ASSERT(RelocInfo::IsConstructCall(rmode()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000339 }
340}
341
342
343// Check whether the break point is at a position which will exit the function.
344bool BreakLocationIterator::IsExit() const {
ager@chromium.org236ad962008-09-25 09:45:57 +0000345 return (RelocInfo::IsJSReturn(rmode()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000346}
347
348
349bool BreakLocationIterator::HasBreakPoint() {
350 return debug_info_->HasBreakPoint(code_position());
351}
352
353
354// Check whether there is a debug break at the current position.
355bool BreakLocationIterator::IsDebugBreak() {
ager@chromium.org236ad962008-09-25 09:45:57 +0000356 if (RelocInfo::IsJSReturn(rmode())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000357 return IsDebugBreakAtReturn();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000358 } else {
359 return Debug::IsDebugBreak(rinfo()->target_address());
360 }
361}
362
363
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000364void BreakLocationIterator::SetDebugBreakAtIC() {
365 // Patch the original code with the current address as the current address
366 // might have changed by the inline caching since the code was copied.
367 original_rinfo()->set_target_address(rinfo()->target_address());
368
369 RelocInfo::Mode mode = rmode();
370 if (RelocInfo::IsCodeTarget(mode)) {
371 Address target = rinfo()->target_address();
372 Handle<Code> code(Code::GetCodeFromTargetAddress(target));
373
374 // Patch the code to invoke the builtin debug break function matching the
375 // calling convention used by the call site.
376 Handle<Code> dbgbrk_code(Debug::FindDebugBreak(code, mode));
377 rinfo()->set_target_address(dbgbrk_code->entry());
378
379 // For stubs that refer back to an inlined version clear the cached map for
380 // the inlined case to always go through the IC. As long as the break point
381 // is set the patching performed by the runtime system will take place in
382 // the code copy and will therefore have no effect on the running code
383 // keeping it from using the inlined code.
ager@chromium.org5ec48922009-05-05 07:25:34 +0000384 if (code->is_keyed_load_stub()) KeyedLoadIC::ClearInlinedVersion(pc());
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000385 if (code->is_keyed_store_stub()) KeyedStoreIC::ClearInlinedVersion(pc());
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000386 }
387}
388
389
390void BreakLocationIterator::ClearDebugBreakAtIC() {
391 // Patch the code to the original invoke.
392 rinfo()->set_target_address(original_rinfo()->target_address());
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000393
394 RelocInfo::Mode mode = rmode();
395 if (RelocInfo::IsCodeTarget(mode)) {
396 Address target = original_rinfo()->target_address();
397 Handle<Code> code(Code::GetCodeFromTargetAddress(target));
398
399 // Restore the inlined version of keyed stores to get back to the
400 // fast case. We need to patch back the keyed store because no
401 // patching happens when running normally. For keyed loads, the
402 // map check will get patched back when running normally after ICs
403 // have been cleared at GC.
404 if (code->is_keyed_store_stub()) KeyedStoreIC::RestoreInlinedVersion(pc());
405 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000406}
407
408
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000409Object* BreakLocationIterator::BreakPointObjects() {
410 return debug_info_->GetBreakPointObjects(code_position());
411}
412
413
ager@chromium.org381abbb2009-02-25 13:23:22 +0000414// Clear out all the debug break code. This is ONLY supposed to be used when
415// shutting down the debugger as it will leave the break point information in
416// DebugInfo even though the code is patched back to the non break point state.
417void BreakLocationIterator::ClearAllDebugBreak() {
418 while (!Done()) {
419 ClearDebugBreak();
420 Next();
421 }
422}
423
424
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000425bool BreakLocationIterator::RinfoDone() const {
426 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
427 return reloc_iterator_->done();
428}
429
430
431void BreakLocationIterator::RinfoNext() {
432 reloc_iterator_->next();
433 reloc_iterator_original_->next();
434#ifdef DEBUG
435 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
436 if (!reloc_iterator_->done()) {
437 ASSERT(rmode() == original_rmode());
438 }
439#endif
440}
441
442
443bool Debug::has_break_points_ = false;
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000444ScriptCache* Debug::script_cache_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000445DebugInfoListNode* Debug::debug_info_list_ = NULL;
446
447
448// Threading support.
449void Debug::ThreadInit() {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000450 thread_local_.break_count_ = 0;
451 thread_local_.break_id_ = 0;
452 thread_local_.break_frame_id_ = StackFrame::NO_ID;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000453 thread_local_.last_step_action_ = StepNone;
ager@chromium.org236ad962008-09-25 09:45:57 +0000454 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000455 thread_local_.step_count_ = 0;
456 thread_local_.last_fp_ = 0;
457 thread_local_.step_into_fp_ = 0;
458 thread_local_.after_break_target_ = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000459 thread_local_.debugger_entry_ = NULL;
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000460 thread_local_.pending_interrupts_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000461}
462
463
464JSCallerSavedBuffer Debug::registers_;
465Debug::ThreadLocal Debug::thread_local_;
466
467
468char* Debug::ArchiveDebug(char* storage) {
469 char* to = storage;
470 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
471 to += sizeof(ThreadLocal);
472 memcpy(to, reinterpret_cast<char*>(&registers_), sizeof(registers_));
473 ThreadInit();
474 ASSERT(to <= storage + ArchiveSpacePerThread());
475 return storage + ArchiveSpacePerThread();
476}
477
478
479char* Debug::RestoreDebug(char* storage) {
480 char* from = storage;
481 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
482 from += sizeof(ThreadLocal);
483 memcpy(reinterpret_cast<char*>(&registers_), from, sizeof(registers_));
484 ASSERT(from <= storage + ArchiveSpacePerThread());
485 return storage + ArchiveSpacePerThread();
486}
487
488
489int Debug::ArchiveSpacePerThread() {
490 return sizeof(ThreadLocal) + sizeof(registers_);
491}
492
493
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000494// Default break enabled.
495bool Debug::disable_break_ = false;
496
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000497// Default call debugger on uncaught exception.
498bool Debug::break_on_exception_ = false;
499bool Debug::break_on_uncaught_exception_ = true;
500
501Handle<Context> Debug::debug_context_ = Handle<Context>();
502Code* Debug::debug_break_return_entry_ = NULL;
503Code* Debug::debug_break_return_ = NULL;
504
505
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000506void ScriptCache::Add(Handle<Script> script) {
507 // Create an entry in the hash map for the script.
508 int id = Smi::cast(script->id())->value();
509 HashMap::Entry* entry =
510 HashMap::Lookup(reinterpret_cast<void*>(id), Hash(id), true);
511 if (entry->value != NULL) {
512 ASSERT(*script == *reinterpret_cast<Script**>(entry->value));
513 return;
514 }
515
516 // Globalize the script object, make it weak and use the location of the
517 // global handle as the value in the hash map.
518 Handle<Script> script_ =
519 Handle<Script>::cast((GlobalHandles::Create(*script)));
520 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(script_.location()),
521 this, ScriptCache::HandleWeakScript);
522 entry->value = script_.location();
523}
524
525
526Handle<FixedArray> ScriptCache::GetScripts() {
527 Handle<FixedArray> instances = Factory::NewFixedArray(occupancy());
528 int count = 0;
529 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
530 ASSERT(entry->value != NULL);
531 if (entry->value != NULL) {
532 instances->set(count, *reinterpret_cast<Script**>(entry->value));
533 count++;
534 }
535 }
536 return instances;
537}
538
539
540void ScriptCache::ProcessCollectedScripts() {
541 for (int i = 0; i < collected_scripts_.length(); i++) {
542 Debugger::OnScriptCollected(collected_scripts_[i]);
543 }
544 collected_scripts_.Clear();
545}
546
547
548void ScriptCache::Clear() {
549 // Iterate the script cache to get rid of all the weak handles.
550 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
551 ASSERT(entry != NULL);
552 Object** location = reinterpret_cast<Object**>(entry->value);
553 ASSERT((*location)->IsScript());
554 GlobalHandles::ClearWeakness(location);
555 GlobalHandles::Destroy(location);
556 }
557 // Clear the content of the hash map.
558 HashMap::Clear();
559}
560
561
562void ScriptCache::HandleWeakScript(v8::Persistent<v8::Value> obj, void* data) {
563 ScriptCache* script_cache = reinterpret_cast<ScriptCache*>(data);
564 // Find the location of the global handle.
565 Script** location =
566 reinterpret_cast<Script**>(Utils::OpenHandle(*obj).location());
567 ASSERT((*location)->IsScript());
568
569 // Remove the entry from the cache.
570 int id = Smi::cast((*location)->id())->value();
571 script_cache->Remove(reinterpret_cast<void*>(id), Hash(id));
572 script_cache->collected_scripts_.Add(id);
573
574 // Clear the weak handle.
575 obj.Dispose();
576 obj.Clear();
577}
578
579
580void Debug::Setup(bool create_heap_objects) {
581 ThreadInit();
582 if (create_heap_objects) {
583 // Get code to handle entry to debug break on return.
584 debug_break_return_entry_ =
585 Builtins::builtin(Builtins::Return_DebugBreakEntry);
586 ASSERT(debug_break_return_entry_->IsCode());
587
588 // Get code to handle debug break on return.
589 debug_break_return_ =
590 Builtins::builtin(Builtins::Return_DebugBreak);
591 ASSERT(debug_break_return_->IsCode());
592 }
593}
594
595
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000596void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000597 DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data);
598 RemoveDebugInfo(node->debug_info());
599#ifdef DEBUG
600 node = Debug::debug_info_list_;
601 while (node != NULL) {
602 ASSERT(node != reinterpret_cast<DebugInfoListNode*>(data));
603 node = node->next();
604 }
605#endif
606}
607
608
609DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
610 // Globalize the request debug info object and make it weak.
611 debug_info_ = Handle<DebugInfo>::cast((GlobalHandles::Create(debug_info)));
612 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(debug_info_.location()),
613 this, Debug::HandleWeakDebugInfo);
614}
615
616
617DebugInfoListNode::~DebugInfoListNode() {
618 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_.location()));
619}
620
621
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000622bool Debug::CompileDebuggerScript(int index) {
623 HandleScope scope;
624
kasper.lund44510672008-07-25 07:37:58 +0000625 // Bail out if the index is invalid.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000626 if (index == -1) {
627 return false;
628 }
kasper.lund44510672008-07-25 07:37:58 +0000629
630 // Find source and name for the requested script.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000631 Handle<String> source_code = Bootstrapper::NativesSourceLookup(index);
632 Vector<const char> name = Natives::GetScriptName(index);
633 Handle<String> script_name = Factory::NewStringFromAscii(name);
634
635 // Compile the script.
636 bool allow_natives_syntax = FLAG_allow_natives_syntax;
637 FLAG_allow_natives_syntax = true;
638 Handle<JSFunction> boilerplate;
639 boilerplate = Compiler::Compile(source_code, script_name, 0, 0, NULL, NULL);
640 FLAG_allow_natives_syntax = allow_natives_syntax;
641
642 // Silently ignore stack overflows during compilation.
643 if (boilerplate.is_null()) {
644 ASSERT(Top::has_pending_exception());
645 Top::clear_pending_exception();
646 return false;
647 }
648
kasper.lund44510672008-07-25 07:37:58 +0000649 // Execute the boilerplate function in the debugger context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000650 Handle<Context> context = Top::global_context();
kasper.lund44510672008-07-25 07:37:58 +0000651 bool caught_exception = false;
652 Handle<JSFunction> function =
653 Factory::NewFunctionFromBoilerplate(boilerplate, context);
654 Handle<Object> result =
655 Execution::TryCall(function, Handle<Object>(context->global()),
656 0, NULL, &caught_exception);
657
658 // Check for caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000659 if (caught_exception) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000660 Handle<Object> message = MessageHandler::MakeMessageObject(
661 "error_loading_debugger", NULL, HandleVector<Object>(&result, 1),
662 Handle<String>());
663 MessageHandler::ReportMessage(NULL, message);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000664 return false;
665 }
666
kasper.lund44510672008-07-25 07:37:58 +0000667 // Mark this script as native and return successfully.
668 Handle<Script> script(Script::cast(function->shared()->script()));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000669 script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000670 return true;
671}
672
673
674bool Debug::Load() {
675 // Return if debugger is already loaded.
kasper.lund212ac232008-07-16 07:07:30 +0000676 if (IsLoaded()) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000677
kasper.lund44510672008-07-25 07:37:58 +0000678 // Bail out if we're already in the process of compiling the native
679 // JavaScript source code for the debugger.
mads.s.agercbaa0602008-08-14 13:41:48 +0000680 if (Debugger::compiling_natives() || Debugger::is_loading_debugger())
681 return false;
682 Debugger::set_loading_debugger(true);
kasper.lund44510672008-07-25 07:37:58 +0000683
684 // Disable breakpoints and interrupts while compiling and running the
685 // debugger scripts including the context creation code.
686 DisableBreak disable(true);
687 PostponeInterruptsScope postpone;
688
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000689 // Create the debugger context.
690 HandleScope scope;
kasper.lund44510672008-07-25 07:37:58 +0000691 Handle<Context> context =
692 Bootstrapper::CreateEnvironment(Handle<Object>::null(),
693 v8::Handle<ObjectTemplate>(),
694 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000695
kasper.lund44510672008-07-25 07:37:58 +0000696 // Use the debugger context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000697 SaveContext save;
kasper.lund44510672008-07-25 07:37:58 +0000698 Top::set_context(*context);
kasper.lund44510672008-07-25 07:37:58 +0000699
700 // Expose the builtins object in the debugger context.
701 Handle<String> key = Factory::LookupAsciiSymbol("builtins");
702 Handle<GlobalObject> global = Handle<GlobalObject>(context->global());
703 SetProperty(global, key, Handle<Object>(global->builtins()), NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000704
705 // Compile the JavaScript for the debugger in the debugger context.
706 Debugger::set_compiling_natives(true);
kasper.lund44510672008-07-25 07:37:58 +0000707 bool caught_exception =
708 !CompileDebuggerScript(Natives::GetIndex("mirror")) ||
709 !CompileDebuggerScript(Natives::GetIndex("debug"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000710 Debugger::set_compiling_natives(false);
711
mads.s.agercbaa0602008-08-14 13:41:48 +0000712 // Make sure we mark the debugger as not loading before we might
713 // return.
714 Debugger::set_loading_debugger(false);
715
kasper.lund44510672008-07-25 07:37:58 +0000716 // Check for caught exceptions.
717 if (caught_exception) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000718
719 // Debugger loaded.
kasper.lund44510672008-07-25 07:37:58 +0000720 debug_context_ = Handle<Context>::cast(GlobalHandles::Create(*context));
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000721
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000722 return true;
723}
724
725
726void Debug::Unload() {
727 // Return debugger is not loaded.
728 if (!IsLoaded()) {
729 return;
730 }
731
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000732 // Clear the script cache.
733 DestroyScriptCache();
734
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000735 // Clear debugger context global handle.
736 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_context_.location()));
737 debug_context_ = Handle<Context>();
738}
739
740
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000741// Set the flag indicating that preemption happened during debugging.
742void Debug::PreemptionWhileInDebugger() {
743 ASSERT(InDebugger());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000744 Debug::set_interrupts_pending(PREEMPT);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000745}
746
747
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000748void Debug::Iterate(ObjectVisitor* v) {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000749 v->VisitPointer(bit_cast<Object**, Code**>(&(debug_break_return_entry_)));
750 v->VisitPointer(bit_cast<Object**, Code**>(&(debug_break_return_)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000751}
752
753
754Object* Debug::Break(Arguments args) {
755 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +0000756 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000757
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000758 // Get the top-most JavaScript frame.
759 JavaScriptFrameIterator it;
760 JavaScriptFrame* frame = it.frame();
761
762 // Just continue if breaks are disabled or debugger cannot be loaded.
763 if (disable_break() || !Load()) {
764 SetAfterBreakTarget(frame);
mads.s.ager31e71382008-08-13 09:32:07 +0000765 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000766 }
767
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000768 // Enter the debugger.
769 EnterDebugger debugger;
770 if (debugger.FailedToEnter()) {
771 return Heap::undefined_value();
772 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000773
kasper.lund44510672008-07-25 07:37:58 +0000774 // Postpone interrupt during breakpoint processing.
775 PostponeInterruptsScope postpone;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000776
777 // Get the debug info (create it if it does not exist).
778 Handle<SharedFunctionInfo> shared =
779 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
780 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
781
782 // Find the break point where execution has stopped.
783 BreakLocationIterator break_location_iterator(debug_info,
784 ALL_BREAK_LOCATIONS);
785 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
786
787 // Check whether step next reached a new statement.
788 if (!StepNextContinue(&break_location_iterator, frame)) {
789 // Decrease steps left if performing multiple steps.
790 if (thread_local_.step_count_ > 0) {
791 thread_local_.step_count_--;
792 }
793 }
794
795 // If there is one or more real break points check whether any of these are
796 // triggered.
797 Handle<Object> break_points_hit(Heap::undefined_value());
798 if (break_location_iterator.HasBreakPoint()) {
799 Handle<Object> break_point_objects =
800 Handle<Object>(break_location_iterator.BreakPointObjects());
801 break_points_hit = CheckBreakPoints(break_point_objects);
802 }
803
804 // Notify debugger if a real break point is triggered or if performing single
805 // stepping with no more steps to perform. Otherwise do another step.
806 if (!break_points_hit->IsUndefined() ||
807 (thread_local_.last_step_action_ != StepNone &&
808 thread_local_.step_count_ == 0)) {
809 // Clear all current stepping setup.
810 ClearStepping();
811
812 // Notify the debug event listeners.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000813 Debugger::OnDebugBreak(break_points_hit, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000814 } else if (thread_local_.last_step_action_ != StepNone) {
815 // Hold on to last step action as it is cleared by the call to
816 // ClearStepping.
817 StepAction step_action = thread_local_.last_step_action_;
818 int step_count = thread_local_.step_count_;
819
820 // Clear all current stepping setup.
821 ClearStepping();
822
823 // Set up for the remaining steps.
824 PrepareStep(step_action, step_count);
825 }
826
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000827 // Install jump to the call address which was overwritten.
828 SetAfterBreakTarget(frame);
829
mads.s.ager31e71382008-08-13 09:32:07 +0000830 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000831}
832
833
834// Check the break point objects for whether one or more are actually
835// triggered. This function returns a JSArray with the break point objects
836// which is triggered.
837Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) {
838 int break_points_hit_count = 0;
839 Handle<JSArray> break_points_hit = Factory::NewJSArray(1);
840
v8.team.kasperl727e9952008-09-02 14:56:44 +0000841 // If there are multiple break points they are in a FixedArray.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842 ASSERT(!break_point_objects->IsUndefined());
843 if (break_point_objects->IsFixedArray()) {
844 Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
845 for (int i = 0; i < array->length(); i++) {
846 Handle<Object> o(array->get(i));
847 if (CheckBreakPoint(o)) {
848 break_points_hit->SetElement(break_points_hit_count++, *o);
849 }
850 }
851 } else {
852 if (CheckBreakPoint(break_point_objects)) {
853 break_points_hit->SetElement(break_points_hit_count++,
854 *break_point_objects);
855 }
856 }
857
858 // Return undefined if no break points where triggered.
859 if (break_points_hit_count == 0) {
860 return Factory::undefined_value();
861 }
862 return break_points_hit;
863}
864
865
866// Check whether a single break point object is triggered.
867bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000868 HandleScope scope;
869
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000870 // Ignore check if break point object is not a JSObject.
871 if (!break_point_object->IsJSObject()) return true;
872
873 // Get the function CheckBreakPoint (defined in debug.js).
874 Handle<JSFunction> check_break_point =
875 Handle<JSFunction>(JSFunction::cast(
876 debug_context()->global()->GetProperty(
877 *Factory::LookupAsciiSymbol("IsBreakPointTriggered"))));
878
879 // Get the break id as an object.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000880 Handle<Object> break_id = Factory::NewNumberFromInt(Debug::break_id());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000881
882 // Call HandleBreakPointx.
883 bool caught_exception = false;
884 const int argc = 2;
885 Object** argv[argc] = {
886 break_id.location(),
887 reinterpret_cast<Object**>(break_point_object.location())
888 };
889 Handle<Object> result = Execution::TryCall(check_break_point,
890 Top::builtins(), argc, argv,
891 &caught_exception);
892
893 // If exception or non boolean result handle as not triggered
894 if (caught_exception || !result->IsBoolean()) {
895 return false;
896 }
897
898 // Return whether the break point is triggered.
899 return *result == Heap::true_value();
900}
901
902
903// Check whether the function has debug information.
904bool Debug::HasDebugInfo(Handle<SharedFunctionInfo> shared) {
905 return !shared->debug_info()->IsUndefined();
906}
907
908
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000909// Return the debug info for this function. EnsureDebugInfo must be called
910// prior to ensure the debug info has been generated for shared.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000911Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000912 ASSERT(HasDebugInfo(shared));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000913 return Handle<DebugInfo>(DebugInfo::cast(shared->debug_info()));
914}
915
916
917void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared,
918 int source_position,
919 Handle<Object> break_point_object) {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000920 HandleScope scope;
921
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000922 if (!EnsureDebugInfo(shared)) {
923 // Return if retrieving debug info failed.
924 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000925 }
926
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000927 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000928 // Source positions starts with zero.
929 ASSERT(source_position >= 0);
930
931 // Find the break point and change it.
932 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
933 it.FindBreakLocationFromPosition(source_position);
934 it.SetBreakPoint(break_point_object);
935
936 // At least one active break point now.
937 ASSERT(debug_info->GetBreakPointCount() > 0);
938}
939
940
941void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000942 HandleScope scope;
943
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000944 DebugInfoListNode* node = debug_info_list_;
945 while (node != NULL) {
946 Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(),
947 break_point_object);
948 if (!result->IsUndefined()) {
949 // Get information in the break point.
950 BreakPointInfo* break_point_info = BreakPointInfo::cast(result);
951 Handle<DebugInfo> debug_info = node->debug_info();
952 Handle<SharedFunctionInfo> shared(debug_info->shared());
953 int source_position = break_point_info->statement_position()->value();
954
955 // Source positions starts with zero.
956 ASSERT(source_position >= 0);
957
958 // Find the break point and clear it.
959 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
960 it.FindBreakLocationFromPosition(source_position);
961 it.ClearBreakPoint(break_point_object);
962
963 // If there are no more break points left remove the debug info for this
964 // function.
965 if (debug_info->GetBreakPointCount() == 0) {
966 RemoveDebugInfo(debug_info);
967 }
968
969 return;
970 }
971 node = node->next();
972 }
973}
974
975
ager@chromium.org381abbb2009-02-25 13:23:22 +0000976void Debug::ClearAllBreakPoints() {
977 DebugInfoListNode* node = debug_info_list_;
978 while (node != NULL) {
979 // Remove all debug break code.
980 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
981 it.ClearAllDebugBreak();
982 node = node->next();
983 }
984
985 // Remove all debug info.
986 while (debug_info_list_ != NULL) {
987 RemoveDebugInfo(debug_info_list_->debug_info());
988 }
989}
990
991
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000992void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000993 // Make sure the function has setup the debug info.
994 if (!EnsureDebugInfo(shared)) {
995 // Return if we failed to retrieve the debug info.
996 return;
997 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000998
999 // Flood the function with break points.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001000 BreakLocationIterator it(GetDebugInfo(shared), ALL_BREAK_LOCATIONS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001001 while (!it.Done()) {
1002 it.SetOneShot();
1003 it.Next();
1004 }
1005}
1006
1007
1008void Debug::FloodHandlerWithOneShot() {
ager@chromium.org8bb60582008-12-11 12:02:20 +00001009 // Iterate through the JavaScript stack looking for handlers.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001010 StackFrame::Id id = break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00001011 if (id == StackFrame::NO_ID) {
1012 // If there is no JavaScript stack don't do anything.
1013 return;
1014 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001015 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) {
1016 JavaScriptFrame* frame = it.frame();
1017 if (frame->HasHandler()) {
1018 Handle<SharedFunctionInfo> shared =
1019 Handle<SharedFunctionInfo>(
1020 JSFunction::cast(frame->function())->shared());
1021 // Flood the function with the catch block with break points
1022 FloodWithOneShot(shared);
1023 return;
1024 }
1025 }
1026}
1027
1028
1029void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
1030 if (type == BreakUncaughtException) {
1031 break_on_uncaught_exception_ = enable;
1032 } else {
1033 break_on_exception_ = enable;
1034 }
1035}
1036
1037
1038void Debug::PrepareStep(StepAction step_action, int step_count) {
1039 HandleScope scope;
1040 ASSERT(Debug::InDebugger());
1041
1042 // Remember this step action and count.
1043 thread_local_.last_step_action_ = step_action;
1044 thread_local_.step_count_ = step_count;
1045
1046 // Get the frame where the execution has stopped and skip the debug frame if
1047 // any. The debug frame will only be present if execution was stopped due to
1048 // hitting a break point. In other situations (e.g. unhandled exception) the
1049 // debug frame is not present.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001050 StackFrame::Id id = break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00001051 if (id == StackFrame::NO_ID) {
1052 // If there is no JavaScript stack don't do anything.
1053 return;
1054 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001055 JavaScriptFrameIterator frames_it(id);
1056 JavaScriptFrame* frame = frames_it.frame();
1057
1058 // First of all ensure there is one-shot break points in the top handler
1059 // if any.
1060 FloodHandlerWithOneShot();
1061
1062 // If the function on the top frame is unresolved perform step out. This will
1063 // be the case when calling unknown functions and having the debugger stopped
1064 // in an unhandled exception.
1065 if (!frame->function()->IsJSFunction()) {
1066 // Step out: Find the calling JavaScript frame and flood it with
1067 // breakpoints.
1068 frames_it.Advance();
1069 // Fill the function to return to with one-shot break points.
1070 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
1071 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1072 return;
1073 }
1074
1075 // Get the debug info (create it if it does not exist).
1076 Handle<SharedFunctionInfo> shared =
1077 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001078 if (!EnsureDebugInfo(shared)) {
1079 // Return if ensuring debug info failed.
1080 return;
1081 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001082 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1083
1084 // Find the break location where execution has stopped.
1085 BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS);
1086 it.FindBreakLocationFromAddress(frame->pc());
1087
1088 // Compute whether or not the target is a call target.
1089 bool is_call_target = false;
ager@chromium.org236ad962008-09-25 09:45:57 +00001090 if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001091 Address target = it.rinfo()->target_address();
ager@chromium.org8bb60582008-12-11 12:02:20 +00001092 Code* code = Code::GetCodeFromTargetAddress(target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001093 if (code->is_call_stub()) is_call_target = true;
1094 }
1095
v8.team.kasperl727e9952008-09-02 14:56:44 +00001096 // If this is the last break code target step out is the only possibility.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001097 if (it.IsExit() || step_action == StepOut) {
1098 // Step out: If there is a JavaScript caller frame, we need to
1099 // flood it with breakpoints.
1100 frames_it.Advance();
1101 if (!frames_it.done()) {
1102 // Fill the function to return to with one-shot break points.
1103 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
1104 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1105 }
ager@chromium.org236ad962008-09-25 09:45:57 +00001106 } else if (!(is_call_target || RelocInfo::IsConstructCall(it.rmode())) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001107 step_action == StepNext || step_action == StepMin) {
1108 // Step next or step min.
1109
1110 // Fill the current function with one-shot break points.
1111 FloodWithOneShot(shared);
1112
1113 // Remember source position and frame to handle step next.
1114 thread_local_.last_statement_position_ =
1115 debug_info->code()->SourceStatementPosition(frame->pc());
1116 thread_local_.last_fp_ = frame->fp();
1117 } else {
1118 // Fill the current function with one-shot break points even for step in on
1119 // a call target as the function called might be a native function for
1120 // which step in will not stop.
1121 FloodWithOneShot(shared);
1122
1123 // Step in or Step in min
1124 it.PrepareStepIn();
1125 ActivateStepIn(frame);
1126 }
1127}
1128
1129
1130// Check whether the current debug break should be reported to the debugger. It
1131// is used to have step next and step in only report break back to the debugger
1132// if on a different frame or in a different statement. In some situations
1133// there will be several break points in the same statement when the code is
v8.team.kasperl727e9952008-09-02 14:56:44 +00001134// flooded with one-shot break points. This function helps to perform several
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001135// steps before reporting break back to the debugger.
1136bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
1137 JavaScriptFrame* frame) {
1138 // If the step last action was step next or step in make sure that a new
1139 // statement is hit.
1140 if (thread_local_.last_step_action_ == StepNext ||
1141 thread_local_.last_step_action_ == StepIn) {
1142 // Never continue if returning from function.
1143 if (break_location_iterator->IsExit()) return false;
1144
1145 // Continue if we are still on the same frame and in the same statement.
1146 int current_statement_position =
1147 break_location_iterator->code()->SourceStatementPosition(frame->pc());
1148 return thread_local_.last_fp_ == frame->fp() &&
ager@chromium.org236ad962008-09-25 09:45:57 +00001149 thread_local_.last_statement_position_ == current_statement_position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001150 }
1151
1152 // No step next action - don't continue.
1153 return false;
1154}
1155
1156
1157// Check whether the code object at the specified address is a debug break code
1158// object.
1159bool Debug::IsDebugBreak(Address addr) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00001160 Code* code = Code::GetCodeFromTargetAddress(addr);
kasper.lund7276f142008-07-30 08:49:36 +00001161 return code->ic_state() == DEBUG_BREAK;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001162}
1163
1164
1165// Check whether a code stub with the specified major key is a possible break
1166// point location when looking for source break locations.
1167bool Debug::IsSourceBreakStub(Code* code) {
1168 CodeStub::Major major_key = code->major_key();
1169 return major_key == CodeStub::CallFunction;
1170}
1171
1172
1173// Check whether a code stub with the specified major key is a possible break
1174// location.
1175bool Debug::IsBreakStub(Code* code) {
1176 CodeStub::Major major_key = code->major_key();
1177 return major_key == CodeStub::CallFunction ||
1178 major_key == CodeStub::StackCheck;
1179}
1180
1181
1182// Find the builtin to use for invoking the debug break
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001183Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001184 // Find the builtin debug break function matching the calling convention
1185 // used by the call site.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001186 if (code->is_inline_cache_stub()) {
1187 if (code->is_call_stub()) {
1188 return ComputeCallDebugBreak(code->arguments_count());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001189 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001190 if (code->is_load_stub()) {
1191 return Handle<Code>(Builtins::builtin(Builtins::LoadIC_DebugBreak));
1192 }
1193 if (code->is_store_stub()) {
1194 return Handle<Code>(Builtins::builtin(Builtins::StoreIC_DebugBreak));
1195 }
1196 if (code->is_keyed_load_stub()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 Handle<Code> result =
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001198 Handle<Code>(Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001199 return result;
1200 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001201 if (code->is_keyed_store_stub()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001202 Handle<Code> result =
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001203 Handle<Code>(Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001204 return result;
1205 }
1206 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001207 if (RelocInfo::IsConstructCall(mode)) {
1208 Handle<Code> result =
1209 Handle<Code>(Builtins::builtin(Builtins::ConstructCall_DebugBreak));
1210 return result;
1211 }
1212 if (code->kind() == Code::STUB) {
1213 ASSERT(code->major_key() == CodeStub::CallFunction ||
1214 code->major_key() == CodeStub::StackCheck);
1215 Handle<Code> result =
1216 Handle<Code>(Builtins::builtin(Builtins::StubNoRegisters_DebugBreak));
1217 return result;
1218 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001219
1220 UNREACHABLE();
1221 return Handle<Code>::null();
1222}
1223
1224
1225// Simple function for returning the source positions for active break points.
1226Handle<Object> Debug::GetSourceBreakLocations(
1227 Handle<SharedFunctionInfo> shared) {
1228 if (!HasDebugInfo(shared)) return Handle<Object>(Heap::undefined_value());
1229 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1230 if (debug_info->GetBreakPointCount() == 0) {
1231 return Handle<Object>(Heap::undefined_value());
1232 }
1233 Handle<FixedArray> locations =
1234 Factory::NewFixedArray(debug_info->GetBreakPointCount());
1235 int count = 0;
1236 for (int i = 0; i < debug_info->break_points()->length(); i++) {
1237 if (!debug_info->break_points()->get(i)->IsUndefined()) {
1238 BreakPointInfo* break_point_info =
1239 BreakPointInfo::cast(debug_info->break_points()->get(i));
1240 if (break_point_info->GetBreakPointCount() > 0) {
1241 locations->set(count++, break_point_info->statement_position());
1242 }
1243 }
1244 }
1245 return locations;
1246}
1247
1248
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001249void Debug::NewBreak(StackFrame::Id break_frame_id) {
1250 thread_local_.break_frame_id_ = break_frame_id;
1251 thread_local_.break_id_ = ++thread_local_.break_count_;
1252}
1253
1254
1255void Debug::SetBreak(StackFrame::Id break_frame_id, int break_id) {
1256 thread_local_.break_frame_id_ = break_frame_id;
1257 thread_local_.break_id_ = break_id;
1258}
1259
1260
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001261// Handle stepping into a function.
1262void Debug::HandleStepIn(Handle<JSFunction> function,
1263 Address fp,
1264 bool is_constructor) {
1265 // If the frame pointer is not supplied by the caller find it.
1266 if (fp == 0) {
1267 StackFrameIterator it;
1268 it.Advance();
1269 // For constructor functions skip another frame.
1270 if (is_constructor) {
1271 ASSERT(it.frame()->is_construct());
1272 it.Advance();
1273 }
1274 fp = it.frame()->fp();
1275 }
1276
1277 // Flood the function with one-shot break points if it is called from where
1278 // step into was requested.
1279 if (fp == Debug::step_in_fp()) {
1280 // Don't allow step into functions in the native context.
1281 if (function->context()->global() != Top::context()->builtins()) {
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001282 if (function->shared()->code() ==
1283 Builtins::builtin(Builtins::FunctionApply) ||
1284 function->shared()->code() ==
1285 Builtins::builtin(Builtins::FunctionCall)) {
1286 // Handle function.apply and function.call separately to flood the
1287 // function to be called and not the code for Builtins::FunctionApply or
1288 // Builtins::FunctionCall. At the point of the call IC to call either
1289 // Builtins::FunctionApply or Builtins::FunctionCall the expression
1290 // stack has the following content:
1291 // symbol "apply" or "call"
1292 // function apply or call was called on
1293 // receiver for apply or call (first parameter to apply or call)
1294 // ... further arguments to apply or call.
1295 JavaScriptFrameIterator it;
1296 ASSERT(it.frame()->fp() == fp);
1297 ASSERT(it.frame()->GetExpression(1)->IsJSFunction());
1298 if (it.frame()->GetExpression(1)->IsJSFunction()) {
1299 Handle<JSFunction>
1300 actual_function(JSFunction::cast(it.frame()->GetExpression(1)));
1301 Handle<SharedFunctionInfo> actual_shared(actual_function->shared());
1302 Debug::FloodWithOneShot(actual_shared);
1303 }
1304 } else {
1305 Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1306 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001307 }
1308 }
1309}
1310
1311
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312void Debug::ClearStepping() {
1313 // Clear the various stepping setup.
1314 ClearOneShot();
1315 ClearStepIn();
1316 ClearStepNext();
1317
1318 // Clear multiple step counter.
1319 thread_local_.step_count_ = 0;
1320}
1321
1322// Clears all the one-shot break points that are currently set. Normally this
1323// function is called each time a break point is hit as one shot break points
1324// are used to support stepping.
1325void Debug::ClearOneShot() {
1326 // The current implementation just runs through all the breakpoints. When the
v8.team.kasperl727e9952008-09-02 14:56:44 +00001327 // last break point for a function is removed that function is automatically
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001328 // removed from the list.
1329
1330 DebugInfoListNode* node = debug_info_list_;
1331 while (node != NULL) {
1332 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1333 while (!it.Done()) {
1334 it.ClearOneShot();
1335 it.Next();
1336 }
1337 node = node->next();
1338 }
1339}
1340
1341
1342void Debug::ActivateStepIn(StackFrame* frame) {
1343 thread_local_.step_into_fp_ = frame->fp();
1344}
1345
1346
1347void Debug::ClearStepIn() {
1348 thread_local_.step_into_fp_ = 0;
1349}
1350
1351
1352void Debug::ClearStepNext() {
1353 thread_local_.last_step_action_ = StepNone;
ager@chromium.org236ad962008-09-25 09:45:57 +00001354 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001355 thread_local_.last_fp_ = 0;
1356}
1357
1358
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001359bool Debug::EnsureCompiled(Handle<SharedFunctionInfo> shared) {
1360 if (shared->is_compiled()) return true;
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001361 return CompileLazyShared(shared, CLEAR_EXCEPTION, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001362}
1363
1364
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001365// Ensures the debug information is present for shared.
1366bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
1367 // Return if we already have the debug info for shared.
1368 if (HasDebugInfo(shared)) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001370 // Ensure shared in compiled. Return false if this failed.
1371 if (!EnsureCompiled(shared)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001372
1373 // Create the debug info object.
v8.team.kasperl727e9952008-09-02 14:56:44 +00001374 Handle<DebugInfo> debug_info = Factory::NewDebugInfo(shared);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001375
1376 // Add debug info to the list.
1377 DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
1378 node->set_next(debug_info_list_);
1379 debug_info_list_ = node;
1380
1381 // Now there is at least one break point.
1382 has_break_points_ = true;
1383
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001384 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001385}
1386
1387
1388void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
1389 ASSERT(debug_info_list_ != NULL);
1390 // Run through the debug info objects to find this one and remove it.
1391 DebugInfoListNode* prev = NULL;
1392 DebugInfoListNode* current = debug_info_list_;
1393 while (current != NULL) {
1394 if (*current->debug_info() == *debug_info) {
1395 // Unlink from list. If prev is NULL we are looking at the first element.
1396 if (prev == NULL) {
1397 debug_info_list_ = current->next();
1398 } else {
1399 prev->set_next(current->next());
1400 }
1401 current->debug_info()->shared()->set_debug_info(Heap::undefined_value());
1402 delete current;
1403
1404 // If there are no more debug info objects there are not more break
1405 // points.
1406 has_break_points_ = debug_info_list_ != NULL;
1407
1408 return;
1409 }
1410 // Move to next in list.
1411 prev = current;
1412 current = current->next();
1413 }
1414 UNREACHABLE();
1415}
1416
1417
1418void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00001419 HandleScope scope;
1420
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001421 // Get the executing function in which the debug break occurred.
1422 Handle<SharedFunctionInfo> shared =
1423 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001424 if (!EnsureDebugInfo(shared)) {
1425 // Return if we failed to retrieve the debug info.
1426 return;
1427 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001428 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1429 Handle<Code> code(debug_info->code());
1430 Handle<Code> original_code(debug_info->original_code());
1431#ifdef DEBUG
1432 // Get the code which is actually executing.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001433 Handle<Code> frame_code(frame->code());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001434 ASSERT(frame_code.is_identical_to(code));
1435#endif
1436
1437 // Find the call address in the running code. This address holds the call to
1438 // either a DebugBreakXXX or to the debug break return entry code if the
1439 // break point is still active after processing the break point.
1440 Address addr = frame->pc() - Assembler::kTargetAddrToReturnAddrDist;
1441
1442 // Check if the location is at JS exit.
1443 bool at_js_exit = false;
1444 RelocIterator it(debug_info->code());
1445 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001446 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001447 at_js_exit = it.rinfo()->pc() == addr - 1;
1448 }
1449 it.next();
1450 }
1451
1452 // Handle the jump to continue execution after break point depending on the
1453 // break location.
1454 if (at_js_exit) {
1455 // First check if the call in the code is still the debug break return
1456 // entry code. If it is the break point is still active. If not the break
1457 // point was removed during break point processing.
1458 if (Assembler::target_address_at(addr) ==
1459 debug_break_return_entry()->entry()) {
1460 // Break point still active. Jump to the corresponding place in the
1461 // original code.
1462 addr += original_code->instruction_start() - code->instruction_start();
1463 }
1464
1465 // Move one byte back to where the call instruction was placed.
1466 thread_local_.after_break_target_ = addr - 1;
1467 } else {
1468 // Check if there still is a debug break call at the target address. If the
1469 // break point has been removed it will have disappeared. If it have
1470 // disappeared don't try to look in the original code as the running code
1471 // will have the right address. This takes care of the case where the last
1472 // break point is removed from the function and therefore no "original code"
1473 // is available. If the debug break call is still there find the address in
1474 // the original code.
1475 if (IsDebugBreak(Assembler::target_address_at(addr))) {
1476 // If the break point is still there find the call address which was
1477 // overwritten in the original code by the call to DebugBreakXXX.
1478
1479 // Find the corresponding address in the original code.
1480 addr += original_code->instruction_start() - code->instruction_start();
1481 }
1482
1483 // Install jump to the call address in the original code. This will be the
1484 // call which was overwritten by the call to DebugBreakXXX.
1485 thread_local_.after_break_target_ = Assembler::target_address_at(addr);
1486 }
1487}
1488
1489
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490bool Debug::IsDebugGlobal(GlobalObject* global) {
1491 return IsLoaded() && global == Debug::debug_context()->global();
1492}
1493
1494
ager@chromium.org32912102009-01-16 10:38:43 +00001495void Debug::ClearMirrorCache() {
ager@chromium.org381abbb2009-02-25 13:23:22 +00001496 HandleScope scope;
ager@chromium.org32912102009-01-16 10:38:43 +00001497 ASSERT(Top::context() == *Debug::debug_context());
1498
1499 // Clear the mirror cache.
1500 Handle<String> function_name =
1501 Factory::LookupSymbol(CStrVector("ClearMirrorCache"));
1502 Handle<Object> fun(Top::global()->GetProperty(*function_name));
1503 ASSERT(fun->IsJSFunction());
1504 bool caught_exception;
1505 Handle<Object> js_object = Execution::TryCall(
1506 Handle<JSFunction>::cast(fun),
1507 Handle<JSObject>(Debug::debug_context()->global()),
1508 0, NULL, &caught_exception);
1509}
1510
1511
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001512// If an object given is an external string, check that the underlying
1513// resource is accessible. For other kinds of objects, always return true.
1514static bool IsExternalStringValid(Object* str) {
1515 if (!str->IsString() || !StringShape(String::cast(str)).IsExternal()) {
1516 return true;
1517 }
1518 if (String::cast(str)->IsAsciiRepresentation()) {
1519 return ExternalAsciiString::cast(str)->resource() != NULL;
1520 } else if (String::cast(str)->IsTwoByteRepresentation()) {
1521 return ExternalTwoByteString::cast(str)->resource() != NULL;
1522 } else {
1523 return true;
1524 }
1525}
1526
1527
1528void Debug::CreateScriptCache() {
1529 HandleScope scope;
1530
1531 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
1532 // rid of all the cached script wrappers and the second gets rid of the
1533 // scripts which is no longer referenced.
1534 Heap::CollectAllGarbage();
1535 Heap::CollectAllGarbage();
1536
1537 ASSERT(script_cache_ == NULL);
1538 script_cache_ = new ScriptCache();
1539
1540 // Scan heap for Script objects.
1541 int count = 0;
1542 HeapIterator iterator;
1543 while (iterator.has_next()) {
1544 HeapObject* obj = iterator.next();
1545 ASSERT(obj != NULL);
1546 if (obj->IsScript() && IsExternalStringValid(Script::cast(obj)->source())) {
1547 script_cache_->Add(Handle<Script>(Script::cast(obj)));
1548 count++;
1549 }
1550 }
1551}
1552
1553
1554void Debug::DestroyScriptCache() {
1555 // Get rid of the script cache if it was created.
1556 if (script_cache_ != NULL) {
1557 delete script_cache_;
1558 script_cache_ = NULL;
1559 }
1560}
1561
1562
1563void Debug::AddScriptToScriptCache(Handle<Script> script) {
1564 if (script_cache_ != NULL) {
1565 script_cache_->Add(script);
1566 }
1567}
1568
1569
1570Handle<FixedArray> Debug::GetLoadedScripts() {
1571 // Create and fill the script cache when the loaded scripts is requested for
1572 // the first time.
1573 if (script_cache_ == NULL) {
1574 CreateScriptCache();
1575 }
1576
1577 // If the script cache is not active just return an empty array.
1578 ASSERT(script_cache_ != NULL);
1579 if (script_cache_ == NULL) {
1580 Factory::NewFixedArray(0);
1581 }
1582
1583 // Perform GC to get unreferenced scripts evicted from the cache before
1584 // returning the content.
1585 Heap::CollectAllGarbage();
1586
1587 // Get the scripts from the cache.
1588 return script_cache_->GetScripts();
1589}
1590
1591
1592void Debug::AfterGarbageCollection() {
1593 // Generate events for collected scripts.
1594 if (script_cache_ != NULL) {
1595 script_cache_->ProcessCollectedScripts();
1596 }
1597}
1598
1599
ager@chromium.org71daaf62009-04-01 07:22:49 +00001600Mutex* Debugger::debugger_access_ = OS::CreateMutex();
iposva@chromium.org245aa852009-02-10 00:49:54 +00001601Handle<Object> Debugger::event_listener_ = Handle<Object>();
1602Handle<Object> Debugger::event_listener_data_ = Handle<Object>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001603bool Debugger::compiling_natives_ = false;
mads.s.agercbaa0602008-08-14 13:41:48 +00001604bool Debugger::is_loading_debugger_ = false;
ager@chromium.org71daaf62009-04-01 07:22:49 +00001605bool Debugger::never_unload_debugger_ = false;
ager@chromium.org5ec48922009-05-05 07:25:34 +00001606v8::Debug::MessageHandler2 Debugger::message_handler_ = NULL;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001607bool Debugger::debugger_unload_pending_ = false;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001608v8::Debug::HostDispatchHandler Debugger::host_dispatch_handler_ = NULL;
1609int Debugger::host_dispatch_micros_ = 100 * 1000;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001610DebuggerAgent* Debugger::agent_ = NULL;
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00001611LockingCommandMessageQueue Debugger::command_queue_(kQueueInitialSize);
ager@chromium.org41826e72009-03-30 13:30:57 +00001612Semaphore* Debugger::command_received_ = OS::CreateSemaphore(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001614
1615Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
1616 int argc, Object*** argv,
1617 bool* caught_exception) {
1618 ASSERT(Top::context() == *Debug::debug_context());
1619
1620 // Create the execution state object.
1621 Handle<String> constructor_str = Factory::LookupSymbol(constructor_name);
1622 Handle<Object> constructor(Top::global()->GetProperty(*constructor_str));
1623 ASSERT(constructor->IsJSFunction());
1624 if (!constructor->IsJSFunction()) {
1625 *caught_exception = true;
1626 return Factory::undefined_value();
1627 }
1628 Handle<Object> js_object = Execution::TryCall(
1629 Handle<JSFunction>::cast(constructor),
1630 Handle<JSObject>(Debug::debug_context()->global()), argc, argv,
1631 caught_exception);
1632 return js_object;
1633}
1634
1635
1636Handle<Object> Debugger::MakeExecutionState(bool* caught_exception) {
1637 // Create the execution state object.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001638 Handle<Object> break_id = Factory::NewNumberFromInt(Debug::break_id());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001639 const int argc = 1;
1640 Object** argv[argc] = { break_id.location() };
1641 return MakeJSObject(CStrVector("MakeExecutionState"),
1642 argc, argv, caught_exception);
1643}
1644
1645
1646Handle<Object> Debugger::MakeBreakEvent(Handle<Object> exec_state,
1647 Handle<Object> break_points_hit,
1648 bool* caught_exception) {
1649 // Create the new break event object.
1650 const int argc = 2;
1651 Object** argv[argc] = { exec_state.location(),
1652 break_points_hit.location() };
1653 return MakeJSObject(CStrVector("MakeBreakEvent"),
1654 argc,
1655 argv,
1656 caught_exception);
1657}
1658
1659
1660Handle<Object> Debugger::MakeExceptionEvent(Handle<Object> exec_state,
1661 Handle<Object> exception,
1662 bool uncaught,
1663 bool* caught_exception) {
1664 // Create the new exception event object.
1665 const int argc = 3;
1666 Object** argv[argc] = { exec_state.location(),
1667 exception.location(),
1668 uncaught ? Factory::true_value().location() :
1669 Factory::false_value().location()};
1670 return MakeJSObject(CStrVector("MakeExceptionEvent"),
1671 argc, argv, caught_exception);
1672}
1673
1674
1675Handle<Object> Debugger::MakeNewFunctionEvent(Handle<Object> function,
1676 bool* caught_exception) {
1677 // Create the new function event object.
1678 const int argc = 1;
1679 Object** argv[argc] = { function.location() };
1680 return MakeJSObject(CStrVector("MakeNewFunctionEvent"),
1681 argc, argv, caught_exception);
1682}
1683
1684
1685Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
iposva@chromium.org245aa852009-02-10 00:49:54 +00001686 bool before,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001687 bool* caught_exception) {
1688 // Create the compile event object.
1689 Handle<Object> exec_state = MakeExecutionState(caught_exception);
iposva@chromium.org245aa852009-02-10 00:49:54 +00001690 Handle<Object> script_wrapper = GetScriptWrapper(script);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001691 const int argc = 3;
iposva@chromium.org245aa852009-02-10 00:49:54 +00001692 Object** argv[argc] = { exec_state.location(),
1693 script_wrapper.location(),
1694 before ? Factory::true_value().location() :
1695 Factory::false_value().location() };
1696
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001697 return MakeJSObject(CStrVector("MakeCompileEvent"),
1698 argc,
1699 argv,
1700 caught_exception);
1701}
1702
1703
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001704Handle<Object> Debugger::MakeScriptCollectedEvent(int id,
1705 bool* caught_exception) {
1706 // Create the script collected event object.
1707 Handle<Object> exec_state = MakeExecutionState(caught_exception);
1708 Handle<Object> id_object = Handle<Smi>(Smi::FromInt(id));
1709 const int argc = 2;
1710 Object** argv[argc] = { exec_state.location(), id_object.location() };
1711
1712 return MakeJSObject(CStrVector("MakeScriptCollectedEvent"),
1713 argc,
1714 argv,
1715 caught_exception);
1716}
1717
1718
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001719void Debugger::OnException(Handle<Object> exception, bool uncaught) {
1720 HandleScope scope;
1721
1722 // Bail out based on state or if there is no listener for this event
1723 if (Debug::InDebugger()) return;
1724 if (!Debugger::EventActive(v8::Exception)) return;
1725
1726 // Bail out if exception breaks are not active
1727 if (uncaught) {
1728 // Uncaught exceptions are reported by either flags.
1729 if (!(Debug::break_on_uncaught_exception() ||
1730 Debug::break_on_exception())) return;
1731 } else {
1732 // Caught exceptions are reported is activated.
1733 if (!Debug::break_on_exception()) return;
1734 }
1735
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001736 // Enter the debugger.
1737 EnterDebugger debugger;
1738 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001739
1740 // Clear all current stepping setup.
1741 Debug::ClearStepping();
1742 // Create the event data object.
1743 bool caught_exception = false;
1744 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
1745 Handle<Object> event_data;
1746 if (!caught_exception) {
1747 event_data = MakeExceptionEvent(exec_state, exception, uncaught,
1748 &caught_exception);
1749 }
1750 // Bail out and don't call debugger if exception.
1751 if (caught_exception) {
1752 return;
1753 }
1754
ager@chromium.org5ec48922009-05-05 07:25:34 +00001755 // Process debug event.
1756 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001757 // Return to continue execution from where the exception was thrown.
1758}
1759
1760
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001761void Debugger::OnDebugBreak(Handle<Object> break_points_hit,
1762 bool auto_continue) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001763 HandleScope scope;
1764
kasper.lund212ac232008-07-16 07:07:30 +00001765 // Debugger has already been entered by caller.
1766 ASSERT(Top::context() == *Debug::debug_context());
1767
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001768 // Bail out if there is no listener for this event
1769 if (!Debugger::EventActive(v8::Break)) return;
1770
1771 // Debugger must be entered in advance.
1772 ASSERT(Top::context() == *Debug::debug_context());
1773
1774 // Create the event data object.
1775 bool caught_exception = false;
1776 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
1777 Handle<Object> event_data;
1778 if (!caught_exception) {
1779 event_data = MakeBreakEvent(exec_state, break_points_hit,
1780 &caught_exception);
1781 }
1782 // Bail out and don't call debugger if exception.
1783 if (caught_exception) {
1784 return;
1785 }
1786
ager@chromium.org5ec48922009-05-05 07:25:34 +00001787 // Process debug event.
1788 ProcessDebugEvent(v8::Break,
1789 Handle<JSObject>::cast(event_data),
1790 auto_continue);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001791}
1792
1793
1794void Debugger::OnBeforeCompile(Handle<Script> script) {
1795 HandleScope scope;
1796
1797 // Bail out based on state or if there is no listener for this event
1798 if (Debug::InDebugger()) return;
1799 if (compiling_natives()) return;
1800 if (!EventActive(v8::BeforeCompile)) return;
1801
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001802 // Enter the debugger.
1803 EnterDebugger debugger;
1804 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001805
1806 // Create the event data object.
1807 bool caught_exception = false;
iposva@chromium.org245aa852009-02-10 00:49:54 +00001808 Handle<Object> event_data = MakeCompileEvent(script, true, &caught_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001809 // Bail out and don't call debugger if exception.
1810 if (caught_exception) {
1811 return;
1812 }
1813
ager@chromium.org5ec48922009-05-05 07:25:34 +00001814 // Process debug event.
1815 ProcessDebugEvent(v8::BeforeCompile,
1816 Handle<JSObject>::cast(event_data),
1817 true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001818}
1819
1820
1821// Handle debugger actions when a new script is compiled.
1822void Debugger::OnAfterCompile(Handle<Script> script, Handle<JSFunction> fun) {
kasper.lund212ac232008-07-16 07:07:30 +00001823 HandleScope scope;
1824
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001825 // Add the newly compiled script to the script cache.
1826 Debug::AddScriptToScriptCache(script);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001827
1828 // No more to do if not debugging.
ager@chromium.org71daaf62009-04-01 07:22:49 +00001829 if (!IsDebuggerActive()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001830
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001831 // No compile events while compiling natives.
1832 if (compiling_natives()) return;
1833
iposva@chromium.org245aa852009-02-10 00:49:54 +00001834 // Store whether in debugger before entering debugger.
1835 bool in_debugger = Debug::InDebugger();
1836
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001837 // Enter the debugger.
1838 EnterDebugger debugger;
1839 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001840
1841 // If debugging there might be script break points registered for this
1842 // script. Make sure that these break points are set.
1843
1844 // Get the function UpdateScriptBreakPoints (defined in debug-delay.js).
1845 Handle<Object> update_script_break_points =
1846 Handle<Object>(Debug::debug_context()->global()->GetProperty(
1847 *Factory::LookupAsciiSymbol("UpdateScriptBreakPoints")));
1848 if (!update_script_break_points->IsJSFunction()) {
1849 return;
1850 }
1851 ASSERT(update_script_break_points->IsJSFunction());
1852
1853 // Wrap the script object in a proper JS object before passing it
1854 // to JavaScript.
1855 Handle<JSValue> wrapper = GetScriptWrapper(script);
1856
1857 // Call UpdateScriptBreakPoints expect no exceptions.
kasper.lund212ac232008-07-16 07:07:30 +00001858 bool caught_exception = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001859 const int argc = 1;
1860 Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) };
1861 Handle<Object> result = Execution::TryCall(
1862 Handle<JSFunction>::cast(update_script_break_points),
1863 Top::builtins(), argc, argv,
1864 &caught_exception);
1865 if (caught_exception) {
1866 return;
1867 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001868 // Bail out based on state or if there is no listener for this event
iposva@chromium.org245aa852009-02-10 00:49:54 +00001869 if (in_debugger) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001870 if (!Debugger::EventActive(v8::AfterCompile)) return;
1871
1872 // Create the compile state object.
1873 Handle<Object> event_data = MakeCompileEvent(script,
iposva@chromium.org245aa852009-02-10 00:49:54 +00001874 false,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001875 &caught_exception);
1876 // Bail out and don't call debugger if exception.
1877 if (caught_exception) {
1878 return;
1879 }
ager@chromium.org5ec48922009-05-05 07:25:34 +00001880 // Process debug event.
1881 ProcessDebugEvent(v8::AfterCompile,
1882 Handle<JSObject>::cast(event_data),
1883 true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001884}
1885
1886
1887void Debugger::OnNewFunction(Handle<JSFunction> function) {
1888 return;
1889 HandleScope scope;
1890
1891 // Bail out based on state or if there is no listener for this event
1892 if (Debug::InDebugger()) return;
1893 if (compiling_natives()) return;
1894 if (!Debugger::EventActive(v8::NewFunction)) return;
1895
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001896 // Enter the debugger.
1897 EnterDebugger debugger;
1898 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001899
1900 // Create the event object.
1901 bool caught_exception = false;
1902 Handle<Object> event_data = MakeNewFunctionEvent(function, &caught_exception);
1903 // Bail out and don't call debugger if exception.
1904 if (caught_exception) {
1905 return;
1906 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001907 // Process debug event.
ager@chromium.org5ec48922009-05-05 07:25:34 +00001908 ProcessDebugEvent(v8::NewFunction, Handle<JSObject>::cast(event_data), true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001909}
1910
1911
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001912void Debugger::OnScriptCollected(int id) {
1913 HandleScope scope;
1914
1915 // No more to do if not debugging.
1916 if (!IsDebuggerActive()) return;
1917 if (!Debugger::EventActive(v8::ScriptCollected)) return;
1918
1919 // Enter the debugger.
1920 EnterDebugger debugger;
1921 if (debugger.FailedToEnter()) return;
1922
1923 // Create the script collected state object.
1924 bool caught_exception = false;
1925 Handle<Object> event_data = MakeScriptCollectedEvent(id,
1926 &caught_exception);
1927 // Bail out and don't call debugger if exception.
1928 if (caught_exception) {
1929 return;
1930 }
1931
1932 // Process debug event.
1933 ProcessDebugEvent(v8::ScriptCollected,
1934 Handle<JSObject>::cast(event_data),
1935 true);
1936}
1937
1938
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001939void Debugger::ProcessDebugEvent(v8::DebugEvent event,
ager@chromium.org5ec48922009-05-05 07:25:34 +00001940 Handle<JSObject> event_data,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001941 bool auto_continue) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00001942 HandleScope scope;
1943
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00001944 // Clear any pending debug break if this is a real break.
1945 if (!auto_continue) {
1946 Debug::clear_interrupt_pending(DEBUGBREAK);
1947 }
1948
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001949 // Create the execution state.
1950 bool caught_exception = false;
1951 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
1952 if (caught_exception) {
1953 return;
1954 }
ager@chromium.org41826e72009-03-30 13:30:57 +00001955 // First notify the message handler if any.
1956 if (message_handler_ != NULL) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00001957 NotifyMessageHandler(event,
1958 Handle<JSObject>::cast(exec_state),
1959 event_data,
1960 auto_continue);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001961 }
iposva@chromium.org245aa852009-02-10 00:49:54 +00001962 // Notify registered debug event listener. This can be either a C or a
1963 // JavaScript function.
1964 if (!event_listener_.is_null()) {
1965 if (event_listener_->IsProxy()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001966 // C debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00001967 Handle<Proxy> callback_obj(Handle<Proxy>::cast(event_listener_));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001968 v8::Debug::EventCallback callback =
1969 FUNCTION_CAST<v8::Debug::EventCallback>(callback_obj->proxy());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001970 callback(event,
1971 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
ager@chromium.org5ec48922009-05-05 07:25:34 +00001972 v8::Utils::ToLocal(event_data),
iposva@chromium.org245aa852009-02-10 00:49:54 +00001973 v8::Utils::ToLocal(Handle<Object>::cast(event_listener_data_)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001974 } else {
1975 // JavaScript debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00001976 ASSERT(event_listener_->IsJSFunction());
1977 Handle<JSFunction> fun(Handle<JSFunction>::cast(event_listener_));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001978
1979 // Invoke the JavaScript debug event listener.
1980 const int argc = 4;
1981 Object** argv[argc] = { Handle<Object>(Smi::FromInt(event)).location(),
1982 exec_state.location(),
ager@chromium.org5ec48922009-05-05 07:25:34 +00001983 Handle<Object>::cast(event_data).location(),
iposva@chromium.org245aa852009-02-10 00:49:54 +00001984 event_listener_data_.location() };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001985 Handle<Object> result = Execution::TryCall(fun, Top::global(),
1986 argc, argv, &caught_exception);
1987 if (caught_exception) {
1988 // Silently ignore exceptions from debug event listeners.
1989 }
1990 }
1991 }
1992}
1993
1994
ager@chromium.org71daaf62009-04-01 07:22:49 +00001995void Debugger::UnloadDebugger() {
1996 // Make sure that there are no breakpoints left.
1997 Debug::ClearAllBreakPoints();
1998
1999 // Unload the debugger if feasible.
2000 if (!never_unload_debugger_) {
2001 Debug::Unload();
2002 }
2003
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002004 // Clear the flag indicating that the debugger should be unloaded.
2005 debugger_unload_pending_ = false;
ager@chromium.org71daaf62009-04-01 07:22:49 +00002006}
2007
2008
ager@chromium.org41826e72009-03-30 13:30:57 +00002009void Debugger::NotifyMessageHandler(v8::DebugEvent event,
ager@chromium.org5ec48922009-05-05 07:25:34 +00002010 Handle<JSObject> exec_state,
2011 Handle<JSObject> event_data,
ager@chromium.org41826e72009-03-30 13:30:57 +00002012 bool auto_continue) {
2013 HandleScope scope;
2014
2015 if (!Debug::Load()) return;
2016
2017 // Process the individual events.
ager@chromium.org5ec48922009-05-05 07:25:34 +00002018 bool sendEventMessage = false;
ager@chromium.org41826e72009-03-30 13:30:57 +00002019 switch (event) {
2020 case v8::Break:
ager@chromium.org5ec48922009-05-05 07:25:34 +00002021 sendEventMessage = !auto_continue;
ager@chromium.org41826e72009-03-30 13:30:57 +00002022 break;
2023 case v8::Exception:
ager@chromium.org5ec48922009-05-05 07:25:34 +00002024 sendEventMessage = true;
ager@chromium.org41826e72009-03-30 13:30:57 +00002025 break;
2026 case v8::BeforeCompile:
2027 break;
2028 case v8::AfterCompile:
ager@chromium.org5ec48922009-05-05 07:25:34 +00002029 sendEventMessage = true;
ager@chromium.org41826e72009-03-30 13:30:57 +00002030 break;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002031 case v8::ScriptCollected:
2032 sendEventMessage = true;
2033 break;
ager@chromium.org41826e72009-03-30 13:30:57 +00002034 case v8::NewFunction:
2035 break;
2036 default:
2037 UNREACHABLE();
2038 }
2039
ager@chromium.org5ec48922009-05-05 07:25:34 +00002040 // The debug command interrupt flag might have been set when the command was
2041 // added. It should be enough to clear the flag only once while we are in the
2042 // debugger.
2043 ASSERT(Debug::InDebugger());
2044 StackGuard::Continue(DEBUGCOMMAND);
2045
2046 // Notify the debugger that a debug event has occurred unless auto continue is
2047 // active in which case no event is send.
2048 if (sendEventMessage) {
2049 MessageImpl message = MessageImpl::NewEvent(
2050 event,
2051 auto_continue,
2052 Handle<JSObject>::cast(exec_state),
2053 Handle<JSObject>::cast(event_data));
2054 InvokeMessageHandler(message);
2055 }
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00002056
2057 // If auto continue don't make the event cause a break, but process messages
2058 // in the queue if any. For script collected events don't even process
2059 // messages in the queue as the execution state might not be what is expected
2060 // by the client.
ager@chromium.org6ffc2172009-05-29 19:20:16 +00002061 if ((auto_continue && !HasCommands()) || event == v8::ScriptCollected) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002062 return;
2063 }
ager@chromium.org41826e72009-03-30 13:30:57 +00002064
2065 // Get the DebugCommandProcessor.
2066 v8::Local<v8::Object> api_exec_state =
2067 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state));
2068 v8::Local<v8::String> fun_name =
2069 v8::String::New("debugCommandProcessor");
2070 v8::Local<v8::Function> fun =
2071 v8::Function::Cast(*api_exec_state->Get(fun_name));
2072 v8::TryCatch try_catch;
2073 v8::Local<v8::Object> cmd_processor =
2074 v8::Object::Cast(*fun->Call(api_exec_state, 0, NULL));
2075 if (try_catch.HasCaught()) {
2076 PrintLn(try_catch.Exception());
2077 return;
2078 }
2079
ager@chromium.org41826e72009-03-30 13:30:57 +00002080 // Process requests from the debugger.
2081 while (true) {
2082 // Wait for new command in the queue.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002083 if (Debugger::host_dispatch_handler_) {
2084 // In case there is a host dispatch - do periodic dispatches.
2085 if (!command_received_->Wait(host_dispatch_micros_)) {
2086 // Timout expired, do the dispatch.
2087 Debugger::host_dispatch_handler_();
2088 continue;
2089 }
2090 } else {
2091 // In case there is no host dispatch - just wait.
2092 command_received_->Wait();
2093 }
ager@chromium.org41826e72009-03-30 13:30:57 +00002094
ager@chromium.org41826e72009-03-30 13:30:57 +00002095 // Get the command from the queue.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002096 CommandMessage command = command_queue_.Get();
ager@chromium.org41826e72009-03-30 13:30:57 +00002097 Logger::DebugTag("Got request from command queue, in interactive loop.");
ager@chromium.org71daaf62009-04-01 07:22:49 +00002098 if (!Debugger::IsDebuggerActive()) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002099 // Delete command text and user data.
2100 command.Dispose();
ager@chromium.org41826e72009-03-30 13:30:57 +00002101 return;
2102 }
2103
ager@chromium.org41826e72009-03-30 13:30:57 +00002104 // Invoke JavaScript to process the debug request.
2105 v8::Local<v8::String> fun_name;
2106 v8::Local<v8::Function> fun;
2107 v8::Local<v8::Value> request;
2108 v8::TryCatch try_catch;
2109 fun_name = v8::String::New("processDebugRequest");
2110 fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002111
2112 request = v8::String::New(command.text().start(),
2113 command.text().length());
ager@chromium.org41826e72009-03-30 13:30:57 +00002114 static const int kArgc = 1;
2115 v8::Handle<Value> argv[kArgc] = { request };
2116 v8::Local<v8::Value> response_val = fun->Call(cmd_processor, kArgc, argv);
2117
2118 // Get the response.
2119 v8::Local<v8::String> response;
2120 bool running = false;
2121 if (!try_catch.HasCaught()) {
2122 // Get response string.
2123 if (!response_val->IsUndefined()) {
2124 response = v8::String::Cast(*response_val);
2125 } else {
2126 response = v8::String::New("");
2127 }
2128
2129 // Log the JSON request/response.
2130 if (FLAG_trace_debug_json) {
2131 PrintLn(request);
2132 PrintLn(response);
2133 }
2134
2135 // Get the running state.
2136 fun_name = v8::String::New("isRunning");
2137 fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
2138 static const int kArgc = 1;
2139 v8::Handle<Value> argv[kArgc] = { response };
2140 v8::Local<v8::Value> running_val = fun->Call(cmd_processor, kArgc, argv);
2141 if (!try_catch.HasCaught()) {
2142 running = running_val->ToBoolean()->Value();
2143 }
2144 } else {
2145 // In case of failure the result text is the exception text.
2146 response = try_catch.Exception()->ToString();
2147 }
2148
ager@chromium.org41826e72009-03-30 13:30:57 +00002149 // Return the result.
ager@chromium.org5ec48922009-05-05 07:25:34 +00002150 MessageImpl message = MessageImpl::NewResponse(
2151 event,
2152 running,
2153 Handle<JSObject>::cast(exec_state),
2154 Handle<JSObject>::cast(event_data),
2155 Handle<String>(Utils::OpenHandle(*response)),
2156 command.client_data());
2157 InvokeMessageHandler(message);
2158 command.Dispose();
ager@chromium.org41826e72009-03-30 13:30:57 +00002159
2160 // Return from debug event processing if either the VM is put into the
2161 // runnning state (through a continue command) or auto continue is active
2162 // and there are no more commands queued.
2163 if (running || (auto_continue && !HasCommands())) {
2164 return;
2165 }
2166 }
2167}
2168
2169
iposva@chromium.org245aa852009-02-10 00:49:54 +00002170void Debugger::SetEventListener(Handle<Object> callback,
2171 Handle<Object> data) {
2172 HandleScope scope;
2173
2174 // Clear the global handles for the event listener and the event listener data
2175 // object.
2176 if (!event_listener_.is_null()) {
2177 GlobalHandles::Destroy(
2178 reinterpret_cast<Object**>(event_listener_.location()));
2179 event_listener_ = Handle<Object>();
2180 }
2181 if (!event_listener_data_.is_null()) {
2182 GlobalHandles::Destroy(
2183 reinterpret_cast<Object**>(event_listener_data_.location()));
2184 event_listener_data_ = Handle<Object>();
2185 }
2186
2187 // If there is a new debug event listener register it together with its data
2188 // object.
2189 if (!callback->IsUndefined() && !callback->IsNull()) {
2190 event_listener_ = Handle<Object>::cast(GlobalHandles::Create(*callback));
2191 if (data.is_null()) {
2192 data = Factory::undefined_value();
2193 }
2194 event_listener_data_ = Handle<Object>::cast(GlobalHandles::Create(*data));
2195 }
2196
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002197 ListenersChanged();
iposva@chromium.org245aa852009-02-10 00:49:54 +00002198}
2199
2200
ager@chromium.org5ec48922009-05-05 07:25:34 +00002201void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002202 ScopedLock with(debugger_access_);
2203
ager@chromium.org381abbb2009-02-25 13:23:22 +00002204 message_handler_ = handler;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002205 ListenersChanged();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002206 if (handler == NULL) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002207 // Send an empty command to the debugger if in a break to make JavaScript
2208 // run again if the debugger is closed.
2209 if (Debug::InDebugger()) {
2210 ProcessCommand(Vector<const uint16_t>::empty());
2211 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002212 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002213}
2214
2215
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002216void Debugger::ListenersChanged() {
2217 if (IsDebuggerActive()) {
2218 // Disable the compilation cache when the debugger is active.
2219 CompilationCache::Disable();
2220 } else {
2221 CompilationCache::Enable();
2222
2223 // Unload the debugger if event listener and message handler cleared.
2224 if (Debug::InDebugger()) {
2225 // If we are in debugger set the flag to unload the debugger when last
2226 // EnterDebugger on the current stack is destroyed.
2227 debugger_unload_pending_ = true;
2228 } else {
2229 UnloadDebugger();
2230 }
2231 }
2232}
2233
2234
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002235void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
2236 int period) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00002237 host_dispatch_handler_ = handler;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002238 host_dispatch_micros_ = period * 1000;
ager@chromium.org381abbb2009-02-25 13:23:22 +00002239}
2240
2241
ager@chromium.org41826e72009-03-30 13:30:57 +00002242// Calls the registered debug message handler. This callback is part of the
ager@chromium.org5ec48922009-05-05 07:25:34 +00002243// public API.
2244void Debugger::InvokeMessageHandler(MessageImpl message) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002245 ScopedLock with(debugger_access_);
2246
ager@chromium.org381abbb2009-02-25 13:23:22 +00002247 if (message_handler_ != NULL) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002248 message_handler_(message);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002249 }
ager@chromium.org41826e72009-03-30 13:30:57 +00002250}
2251
2252
2253// Puts a command coming from the public API on the queue. Creates
2254// a copy of the command string managed by the debugger. Up to this
2255// point, the command data was managed by the API client. Called
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002256// by the API client thread.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002257void Debugger::ProcessCommand(Vector<const uint16_t> command,
2258 v8::Debug::ClientData* client_data) {
2259 // Need to cast away const.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002260 CommandMessage message = CommandMessage::New(
ager@chromium.org41826e72009-03-30 13:30:57 +00002261 Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002262 command.length()),
2263 client_data);
ager@chromium.org41826e72009-03-30 13:30:57 +00002264 Logger::DebugTag("Put command on command_queue.");
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002265 command_queue_.Put(message);
ager@chromium.org41826e72009-03-30 13:30:57 +00002266 command_received_->Signal();
sgjesse@chromium.org3afc1582009-04-16 22:31:44 +00002267
2268 // Set the debug command break flag to have the command processed.
ager@chromium.org41826e72009-03-30 13:30:57 +00002269 if (!Debug::InDebugger()) {
2270 StackGuard::DebugCommand();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002271 }
2272}
2273
2274
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002275bool Debugger::HasCommands() {
ager@chromium.org41826e72009-03-30 13:30:57 +00002276 return !command_queue_.IsEmpty();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002277}
2278
2279
ager@chromium.org71daaf62009-04-01 07:22:49 +00002280bool Debugger::IsDebuggerActive() {
2281 ScopedLock with(debugger_access_);
2282
2283 return message_handler_ != NULL || !event_listener_.is_null();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002284}
2285
2286
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002287Handle<Object> Debugger::Call(Handle<JSFunction> fun,
2288 Handle<Object> data,
2289 bool* pending_exception) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002290 // When calling functions in the debugger prevent it from beeing unloaded.
2291 Debugger::never_unload_debugger_ = true;
2292
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002293 // Enter the debugger.
2294 EnterDebugger debugger;
2295 if (debugger.FailedToEnter() || !debugger.HasJavaScriptFrames()) {
2296 return Factory::undefined_value();
2297 }
2298
2299 // Create the execution state.
2300 bool caught_exception = false;
2301 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2302 if (caught_exception) {
2303 return Factory::undefined_value();
2304 }
2305
2306 static const int kArgc = 2;
2307 Object** argv[kArgc] = { exec_state.location(), data.location() };
2308 Handle<Object> result = Execution::Call(fun, Factory::undefined_value(),
2309 kArgc, argv, pending_exception);
2310 return result;
2311}
2312
2313
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002314bool Debugger::StartAgent(const char* name, int port) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002315 if (Socket::Setup()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002316 agent_ = new DebuggerAgent(name, port);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002317 agent_->Start();
2318 return true;
2319 }
2320
2321 return false;
2322}
2323
2324
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002325void Debugger::StopAgent() {
2326 if (agent_ != NULL) {
2327 agent_->Shutdown();
2328 agent_->Join();
2329 delete agent_;
2330 agent_ = NULL;
2331 }
2332}
2333
2334
ager@chromium.org5ec48922009-05-05 07:25:34 +00002335MessageImpl MessageImpl::NewEvent(DebugEvent event,
2336 bool running,
2337 Handle<JSObject> exec_state,
2338 Handle<JSObject> event_data) {
2339 MessageImpl message(true, event, running,
2340 exec_state, event_data, Handle<String>(), NULL);
2341 return message;
2342}
2343
2344
2345MessageImpl MessageImpl::NewResponse(DebugEvent event,
2346 bool running,
2347 Handle<JSObject> exec_state,
2348 Handle<JSObject> event_data,
2349 Handle<String> response_json,
2350 v8::Debug::ClientData* client_data) {
2351 MessageImpl message(false, event, running,
2352 exec_state, event_data, response_json, client_data);
2353 return message;
2354}
2355
2356
2357MessageImpl::MessageImpl(bool is_event,
2358 DebugEvent event,
2359 bool running,
2360 Handle<JSObject> exec_state,
2361 Handle<JSObject> event_data,
2362 Handle<String> response_json,
2363 v8::Debug::ClientData* client_data)
2364 : is_event_(is_event),
2365 event_(event),
2366 running_(running),
2367 exec_state_(exec_state),
2368 event_data_(event_data),
2369 response_json_(response_json),
2370 client_data_(client_data) {}
2371
2372
2373bool MessageImpl::IsEvent() const {
2374 return is_event_;
2375}
2376
2377
2378bool MessageImpl::IsResponse() const {
2379 return !is_event_;
2380}
2381
2382
2383DebugEvent MessageImpl::GetEvent() const {
2384 return event_;
2385}
2386
2387
2388bool MessageImpl::WillStartRunning() const {
2389 return running_;
2390}
2391
2392
2393v8::Handle<v8::Object> MessageImpl::GetExecutionState() const {
2394 return v8::Utils::ToLocal(exec_state_);
2395}
2396
2397
2398v8::Handle<v8::Object> MessageImpl::GetEventData() const {
2399 return v8::Utils::ToLocal(event_data_);
2400}
2401
2402
2403v8::Handle<v8::String> MessageImpl::GetJSON() const {
2404 v8::HandleScope scope;
2405
2406 if (IsEvent()) {
2407 // Call toJSONProtocol on the debug event object.
2408 Handle<Object> fun = GetProperty(event_data_, "toJSONProtocol");
2409 if (!fun->IsJSFunction()) {
2410 return v8::Handle<v8::String>();
2411 }
2412 bool caught_exception;
2413 Handle<Object> json = Execution::TryCall(Handle<JSFunction>::cast(fun),
2414 event_data_,
2415 0, NULL, &caught_exception);
2416 if (caught_exception || !json->IsString()) {
2417 return v8::Handle<v8::String>();
2418 }
2419 return scope.Close(v8::Utils::ToLocal(Handle<String>::cast(json)));
2420 } else {
2421 return v8::Utils::ToLocal(response_json_);
2422 }
2423}
2424
2425
2426v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002427 Handle<Context> context = Debug::debugger_entry()->GetContext();
2428 // Top::context() may have been NULL when "script collected" event occured.
2429 if (*context == NULL) {
2430 ASSERT(event_ == v8::ScriptCollected);
2431 return v8::Local<v8::Context>();
2432 }
2433 Handle<Context> global_context(context->global_context());
2434 return v8::Utils::ToLocal(global_context);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002435}
2436
2437
2438v8::Debug::ClientData* MessageImpl::GetClientData() const {
2439 return client_data_;
2440}
2441
2442
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002443CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()),
2444 client_data_(NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002445}
2446
2447
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002448CommandMessage::CommandMessage(const Vector<uint16_t>& text,
2449 v8::Debug::ClientData* data)
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002450 : text_(text),
2451 client_data_(data) {
2452}
2453
2454
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002455CommandMessage::~CommandMessage() {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002456}
2457
2458
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002459void CommandMessage::Dispose() {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002460 text_.Dispose();
2461 delete client_data_;
2462 client_data_ = NULL;
2463}
2464
2465
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002466CommandMessage CommandMessage::New(const Vector<uint16_t>& command,
2467 v8::Debug::ClientData* data) {
2468 return CommandMessage(command.Clone(), data);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002469}
2470
2471
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002472CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0),
2473 size_(size) {
2474 messages_ = NewArray<CommandMessage>(size);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002475}
2476
2477
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002478CommandMessageQueue::~CommandMessageQueue() {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002479 while (!IsEmpty()) {
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002480 CommandMessage m = Get();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002481 m.Dispose();
2482 }
kasper.lund7276f142008-07-30 08:49:36 +00002483 DeleteArray(messages_);
2484}
2485
2486
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002487CommandMessage CommandMessageQueue::Get() {
kasper.lund7276f142008-07-30 08:49:36 +00002488 ASSERT(!IsEmpty());
2489 int result = start_;
2490 start_ = (start_ + 1) % size_;
2491 return messages_[result];
2492}
2493
2494
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002495void CommandMessageQueue::Put(const CommandMessage& message) {
kasper.lund7276f142008-07-30 08:49:36 +00002496 if ((end_ + 1) % size_ == start_) {
2497 Expand();
2498 }
2499 messages_[end_] = message;
2500 end_ = (end_ + 1) % size_;
2501}
2502
2503
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002504void CommandMessageQueue::Expand() {
2505 CommandMessageQueue new_queue(size_ * 2);
kasper.lund7276f142008-07-30 08:49:36 +00002506 while (!IsEmpty()) {
2507 new_queue.Put(Get());
2508 }
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002509 CommandMessage* array_to_free = messages_;
kasper.lund7276f142008-07-30 08:49:36 +00002510 *this = new_queue;
2511 new_queue.messages_ = array_to_free;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002512 // Make the new_queue empty so that it doesn't call Dispose on any messages.
2513 new_queue.start_ = new_queue.end_;
kasper.lund7276f142008-07-30 08:49:36 +00002514 // Automatic destructor called on new_queue, freeing array_to_free.
2515}
2516
2517
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002518LockingCommandMessageQueue::LockingCommandMessageQueue(int size)
2519 : queue_(size) {
kasper.lund7276f142008-07-30 08:49:36 +00002520 lock_ = OS::CreateMutex();
2521}
2522
2523
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002524LockingCommandMessageQueue::~LockingCommandMessageQueue() {
kasper.lund7276f142008-07-30 08:49:36 +00002525 delete lock_;
2526}
2527
2528
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002529bool LockingCommandMessageQueue::IsEmpty() const {
kasper.lund7276f142008-07-30 08:49:36 +00002530 ScopedLock sl(lock_);
2531 return queue_.IsEmpty();
2532}
2533
2534
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002535CommandMessage LockingCommandMessageQueue::Get() {
kasper.lund7276f142008-07-30 08:49:36 +00002536 ScopedLock sl(lock_);
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002537 CommandMessage result = queue_.Get();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002538 Logger::DebugEvent("Get", result.text());
kasper.lund7276f142008-07-30 08:49:36 +00002539 return result;
2540}
2541
2542
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002543void LockingCommandMessageQueue::Put(const CommandMessage& message) {
kasper.lund7276f142008-07-30 08:49:36 +00002544 ScopedLock sl(lock_);
2545 queue_.Put(message);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002546 Logger::DebugEvent("Put", message.text());
kasper.lund7276f142008-07-30 08:49:36 +00002547}
2548
2549
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002550void LockingCommandMessageQueue::Clear() {
kasper.lund7276f142008-07-30 08:49:36 +00002551 ScopedLock sl(lock_);
2552 queue_.Clear();
2553}
2554
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002555#endif // ENABLE_DEBUGGER_SUPPORT
kasper.lund7276f142008-07-30 08:49:36 +00002556
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002557} } // namespace v8::internal