blob: becfaa6eae20bc5fbaf44b4d15002aeacbf9d04f [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.org65dad4b2009-04-23 08:48:43 +0000385 }
386}
387
388
389void BreakLocationIterator::ClearDebugBreakAtIC() {
390 // Patch the code to the original invoke.
391 rinfo()->set_target_address(original_rinfo()->target_address());
392}
393
394
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000395Object* BreakLocationIterator::BreakPointObjects() {
396 return debug_info_->GetBreakPointObjects(code_position());
397}
398
399
ager@chromium.org381abbb2009-02-25 13:23:22 +0000400// Clear out all the debug break code. This is ONLY supposed to be used when
401// shutting down the debugger as it will leave the break point information in
402// DebugInfo even though the code is patched back to the non break point state.
403void BreakLocationIterator::ClearAllDebugBreak() {
404 while (!Done()) {
405 ClearDebugBreak();
406 Next();
407 }
408}
409
410
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000411bool BreakLocationIterator::RinfoDone() const {
412 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
413 return reloc_iterator_->done();
414}
415
416
417void BreakLocationIterator::RinfoNext() {
418 reloc_iterator_->next();
419 reloc_iterator_original_->next();
420#ifdef DEBUG
421 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
422 if (!reloc_iterator_->done()) {
423 ASSERT(rmode() == original_rmode());
424 }
425#endif
426}
427
428
429bool Debug::has_break_points_ = false;
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000430ScriptCache* Debug::script_cache_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000431DebugInfoListNode* Debug::debug_info_list_ = NULL;
432
433
434// Threading support.
435void Debug::ThreadInit() {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000436 thread_local_.break_count_ = 0;
437 thread_local_.break_id_ = 0;
438 thread_local_.break_frame_id_ = StackFrame::NO_ID;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000439 thread_local_.last_step_action_ = StepNone;
ager@chromium.org236ad962008-09-25 09:45:57 +0000440 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000441 thread_local_.step_count_ = 0;
442 thread_local_.last_fp_ = 0;
443 thread_local_.step_into_fp_ = 0;
444 thread_local_.after_break_target_ = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000445 thread_local_.debugger_entry_ = NULL;
446 thread_local_.preemption_pending_ = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000447}
448
449
450JSCallerSavedBuffer Debug::registers_;
451Debug::ThreadLocal Debug::thread_local_;
452
453
454char* Debug::ArchiveDebug(char* storage) {
455 char* to = storage;
456 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
457 to += sizeof(ThreadLocal);
458 memcpy(to, reinterpret_cast<char*>(&registers_), sizeof(registers_));
459 ThreadInit();
460 ASSERT(to <= storage + ArchiveSpacePerThread());
461 return storage + ArchiveSpacePerThread();
462}
463
464
465char* Debug::RestoreDebug(char* storage) {
466 char* from = storage;
467 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
468 from += sizeof(ThreadLocal);
469 memcpy(reinterpret_cast<char*>(&registers_), from, sizeof(registers_));
470 ASSERT(from <= storage + ArchiveSpacePerThread());
471 return storage + ArchiveSpacePerThread();
472}
473
474
475int Debug::ArchiveSpacePerThread() {
476 return sizeof(ThreadLocal) + sizeof(registers_);
477}
478
479
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000480// Default break enabled.
481bool Debug::disable_break_ = false;
482
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000483// Default call debugger on uncaught exception.
484bool Debug::break_on_exception_ = false;
485bool Debug::break_on_uncaught_exception_ = true;
486
487Handle<Context> Debug::debug_context_ = Handle<Context>();
488Code* Debug::debug_break_return_entry_ = NULL;
489Code* Debug::debug_break_return_ = NULL;
490
491
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000492void ScriptCache::Add(Handle<Script> script) {
493 // Create an entry in the hash map for the script.
494 int id = Smi::cast(script->id())->value();
495 HashMap::Entry* entry =
496 HashMap::Lookup(reinterpret_cast<void*>(id), Hash(id), true);
497 if (entry->value != NULL) {
498 ASSERT(*script == *reinterpret_cast<Script**>(entry->value));
499 return;
500 }
501
502 // Globalize the script object, make it weak and use the location of the
503 // global handle as the value in the hash map.
504 Handle<Script> script_ =
505 Handle<Script>::cast((GlobalHandles::Create(*script)));
506 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(script_.location()),
507 this, ScriptCache::HandleWeakScript);
508 entry->value = script_.location();
509}
510
511
512Handle<FixedArray> ScriptCache::GetScripts() {
513 Handle<FixedArray> instances = Factory::NewFixedArray(occupancy());
514 int count = 0;
515 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
516 ASSERT(entry->value != NULL);
517 if (entry->value != NULL) {
518 instances->set(count, *reinterpret_cast<Script**>(entry->value));
519 count++;
520 }
521 }
522 return instances;
523}
524
525
526void ScriptCache::ProcessCollectedScripts() {
527 for (int i = 0; i < collected_scripts_.length(); i++) {
528 Debugger::OnScriptCollected(collected_scripts_[i]);
529 }
530 collected_scripts_.Clear();
531}
532
533
534void ScriptCache::Clear() {
535 // Iterate the script cache to get rid of all the weak handles.
536 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
537 ASSERT(entry != NULL);
538 Object** location = reinterpret_cast<Object**>(entry->value);
539 ASSERT((*location)->IsScript());
540 GlobalHandles::ClearWeakness(location);
541 GlobalHandles::Destroy(location);
542 }
543 // Clear the content of the hash map.
544 HashMap::Clear();
545}
546
547
548void ScriptCache::HandleWeakScript(v8::Persistent<v8::Value> obj, void* data) {
549 ScriptCache* script_cache = reinterpret_cast<ScriptCache*>(data);
550 // Find the location of the global handle.
551 Script** location =
552 reinterpret_cast<Script**>(Utils::OpenHandle(*obj).location());
553 ASSERT((*location)->IsScript());
554
555 // Remove the entry from the cache.
556 int id = Smi::cast((*location)->id())->value();
557 script_cache->Remove(reinterpret_cast<void*>(id), Hash(id));
558 script_cache->collected_scripts_.Add(id);
559
560 // Clear the weak handle.
561 obj.Dispose();
562 obj.Clear();
563}
564
565
566void Debug::Setup(bool create_heap_objects) {
567 ThreadInit();
568 if (create_heap_objects) {
569 // Get code to handle entry to debug break on return.
570 debug_break_return_entry_ =
571 Builtins::builtin(Builtins::Return_DebugBreakEntry);
572 ASSERT(debug_break_return_entry_->IsCode());
573
574 // Get code to handle debug break on return.
575 debug_break_return_ =
576 Builtins::builtin(Builtins::Return_DebugBreak);
577 ASSERT(debug_break_return_->IsCode());
578 }
579}
580
581
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000582void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000583 DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data);
584 RemoveDebugInfo(node->debug_info());
585#ifdef DEBUG
586 node = Debug::debug_info_list_;
587 while (node != NULL) {
588 ASSERT(node != reinterpret_cast<DebugInfoListNode*>(data));
589 node = node->next();
590 }
591#endif
592}
593
594
595DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
596 // Globalize the request debug info object and make it weak.
597 debug_info_ = Handle<DebugInfo>::cast((GlobalHandles::Create(debug_info)));
598 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(debug_info_.location()),
599 this, Debug::HandleWeakDebugInfo);
600}
601
602
603DebugInfoListNode::~DebugInfoListNode() {
604 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_.location()));
605}
606
607
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000608bool Debug::CompileDebuggerScript(int index) {
609 HandleScope scope;
610
kasper.lund44510672008-07-25 07:37:58 +0000611 // Bail out if the index is invalid.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000612 if (index == -1) {
613 return false;
614 }
kasper.lund44510672008-07-25 07:37:58 +0000615
616 // Find source and name for the requested script.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000617 Handle<String> source_code = Bootstrapper::NativesSourceLookup(index);
618 Vector<const char> name = Natives::GetScriptName(index);
619 Handle<String> script_name = Factory::NewStringFromAscii(name);
620
621 // Compile the script.
622 bool allow_natives_syntax = FLAG_allow_natives_syntax;
623 FLAG_allow_natives_syntax = true;
624 Handle<JSFunction> boilerplate;
625 boilerplate = Compiler::Compile(source_code, script_name, 0, 0, NULL, NULL);
626 FLAG_allow_natives_syntax = allow_natives_syntax;
627
628 // Silently ignore stack overflows during compilation.
629 if (boilerplate.is_null()) {
630 ASSERT(Top::has_pending_exception());
631 Top::clear_pending_exception();
632 return false;
633 }
634
kasper.lund44510672008-07-25 07:37:58 +0000635 // Execute the boilerplate function in the debugger context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000636 Handle<Context> context = Top::global_context();
kasper.lund44510672008-07-25 07:37:58 +0000637 bool caught_exception = false;
638 Handle<JSFunction> function =
639 Factory::NewFunctionFromBoilerplate(boilerplate, context);
640 Handle<Object> result =
641 Execution::TryCall(function, Handle<Object>(context->global()),
642 0, NULL, &caught_exception);
643
644 // Check for caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000645 if (caught_exception) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000646 Handle<Object> message = MessageHandler::MakeMessageObject(
647 "error_loading_debugger", NULL, HandleVector<Object>(&result, 1),
648 Handle<String>());
649 MessageHandler::ReportMessage(NULL, message);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000650 return false;
651 }
652
kasper.lund44510672008-07-25 07:37:58 +0000653 // Mark this script as native and return successfully.
654 Handle<Script> script(Script::cast(function->shared()->script()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000655 script->set_type(Smi::FromInt(SCRIPT_TYPE_NATIVE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000656 return true;
657}
658
659
660bool Debug::Load() {
661 // Return if debugger is already loaded.
kasper.lund212ac232008-07-16 07:07:30 +0000662 if (IsLoaded()) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000663
kasper.lund44510672008-07-25 07:37:58 +0000664 // Bail out if we're already in the process of compiling the native
665 // JavaScript source code for the debugger.
mads.s.agercbaa0602008-08-14 13:41:48 +0000666 if (Debugger::compiling_natives() || Debugger::is_loading_debugger())
667 return false;
668 Debugger::set_loading_debugger(true);
kasper.lund44510672008-07-25 07:37:58 +0000669
670 // Disable breakpoints and interrupts while compiling and running the
671 // debugger scripts including the context creation code.
672 DisableBreak disable(true);
673 PostponeInterruptsScope postpone;
674
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000675 // Create the debugger context.
676 HandleScope scope;
kasper.lund44510672008-07-25 07:37:58 +0000677 Handle<Context> context =
678 Bootstrapper::CreateEnvironment(Handle<Object>::null(),
679 v8::Handle<ObjectTemplate>(),
680 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000681
kasper.lund44510672008-07-25 07:37:58 +0000682 // Use the debugger context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000683 SaveContext save;
kasper.lund44510672008-07-25 07:37:58 +0000684 Top::set_context(*context);
kasper.lund44510672008-07-25 07:37:58 +0000685
686 // Expose the builtins object in the debugger context.
687 Handle<String> key = Factory::LookupAsciiSymbol("builtins");
688 Handle<GlobalObject> global = Handle<GlobalObject>(context->global());
689 SetProperty(global, key, Handle<Object>(global->builtins()), NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000690
691 // Compile the JavaScript for the debugger in the debugger context.
692 Debugger::set_compiling_natives(true);
kasper.lund44510672008-07-25 07:37:58 +0000693 bool caught_exception =
694 !CompileDebuggerScript(Natives::GetIndex("mirror")) ||
695 !CompileDebuggerScript(Natives::GetIndex("debug"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000696 Debugger::set_compiling_natives(false);
697
mads.s.agercbaa0602008-08-14 13:41:48 +0000698 // Make sure we mark the debugger as not loading before we might
699 // return.
700 Debugger::set_loading_debugger(false);
701
kasper.lund44510672008-07-25 07:37:58 +0000702 // Check for caught exceptions.
703 if (caught_exception) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000704
705 // Debugger loaded.
kasper.lund44510672008-07-25 07:37:58 +0000706 debug_context_ = Handle<Context>::cast(GlobalHandles::Create(*context));
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000707
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000708 return true;
709}
710
711
712void Debug::Unload() {
713 // Return debugger is not loaded.
714 if (!IsLoaded()) {
715 return;
716 }
717
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000718 // Clear the script cache.
719 DestroyScriptCache();
720
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000721 // Clear debugger context global handle.
722 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_context_.location()));
723 debug_context_ = Handle<Context>();
724}
725
726
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000727// Set the flag indicating that preemption happened during debugging.
728void Debug::PreemptionWhileInDebugger() {
729 ASSERT(InDebugger());
730 Debug::set_preemption_pending(true);
731}
732
733
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000734void Debug::Iterate(ObjectVisitor* v) {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000735 v->VisitPointer(bit_cast<Object**, Code**>(&(debug_break_return_entry_)));
736 v->VisitPointer(bit_cast<Object**, Code**>(&(debug_break_return_)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000737}
738
739
740Object* Debug::Break(Arguments args) {
741 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +0000742 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000743
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000744 // Get the top-most JavaScript frame.
745 JavaScriptFrameIterator it;
746 JavaScriptFrame* frame = it.frame();
747
748 // Just continue if breaks are disabled or debugger cannot be loaded.
749 if (disable_break() || !Load()) {
750 SetAfterBreakTarget(frame);
mads.s.ager31e71382008-08-13 09:32:07 +0000751 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000752 }
753
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000754 // Enter the debugger.
755 EnterDebugger debugger;
756 if (debugger.FailedToEnter()) {
757 return Heap::undefined_value();
758 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000759
kasper.lund44510672008-07-25 07:37:58 +0000760 // Postpone interrupt during breakpoint processing.
761 PostponeInterruptsScope postpone;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000762
763 // Get the debug info (create it if it does not exist).
764 Handle<SharedFunctionInfo> shared =
765 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
766 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
767
768 // Find the break point where execution has stopped.
769 BreakLocationIterator break_location_iterator(debug_info,
770 ALL_BREAK_LOCATIONS);
771 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
772
773 // Check whether step next reached a new statement.
774 if (!StepNextContinue(&break_location_iterator, frame)) {
775 // Decrease steps left if performing multiple steps.
776 if (thread_local_.step_count_ > 0) {
777 thread_local_.step_count_--;
778 }
779 }
780
781 // If there is one or more real break points check whether any of these are
782 // triggered.
783 Handle<Object> break_points_hit(Heap::undefined_value());
784 if (break_location_iterator.HasBreakPoint()) {
785 Handle<Object> break_point_objects =
786 Handle<Object>(break_location_iterator.BreakPointObjects());
787 break_points_hit = CheckBreakPoints(break_point_objects);
788 }
789
790 // Notify debugger if a real break point is triggered or if performing single
791 // stepping with no more steps to perform. Otherwise do another step.
792 if (!break_points_hit->IsUndefined() ||
793 (thread_local_.last_step_action_ != StepNone &&
794 thread_local_.step_count_ == 0)) {
795 // Clear all current stepping setup.
796 ClearStepping();
797
798 // Notify the debug event listeners.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000799 Debugger::OnDebugBreak(break_points_hit, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000800 } else if (thread_local_.last_step_action_ != StepNone) {
801 // Hold on to last step action as it is cleared by the call to
802 // ClearStepping.
803 StepAction step_action = thread_local_.last_step_action_;
804 int step_count = thread_local_.step_count_;
805
806 // Clear all current stepping setup.
807 ClearStepping();
808
809 // Set up for the remaining steps.
810 PrepareStep(step_action, step_count);
811 }
812
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000813 // Install jump to the call address which was overwritten.
814 SetAfterBreakTarget(frame);
815
mads.s.ager31e71382008-08-13 09:32:07 +0000816 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000817}
818
819
820// Check the break point objects for whether one or more are actually
821// triggered. This function returns a JSArray with the break point objects
822// which is triggered.
823Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) {
824 int break_points_hit_count = 0;
825 Handle<JSArray> break_points_hit = Factory::NewJSArray(1);
826
v8.team.kasperl727e9952008-09-02 14:56:44 +0000827 // If there are multiple break points they are in a FixedArray.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000828 ASSERT(!break_point_objects->IsUndefined());
829 if (break_point_objects->IsFixedArray()) {
830 Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
831 for (int i = 0; i < array->length(); i++) {
832 Handle<Object> o(array->get(i));
833 if (CheckBreakPoint(o)) {
834 break_points_hit->SetElement(break_points_hit_count++, *o);
835 }
836 }
837 } else {
838 if (CheckBreakPoint(break_point_objects)) {
839 break_points_hit->SetElement(break_points_hit_count++,
840 *break_point_objects);
841 }
842 }
843
844 // Return undefined if no break points where triggered.
845 if (break_points_hit_count == 0) {
846 return Factory::undefined_value();
847 }
848 return break_points_hit;
849}
850
851
852// Check whether a single break point object is triggered.
853bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000854 HandleScope scope;
855
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000856 // Ignore check if break point object is not a JSObject.
857 if (!break_point_object->IsJSObject()) return true;
858
859 // Get the function CheckBreakPoint (defined in debug.js).
860 Handle<JSFunction> check_break_point =
861 Handle<JSFunction>(JSFunction::cast(
862 debug_context()->global()->GetProperty(
863 *Factory::LookupAsciiSymbol("IsBreakPointTriggered"))));
864
865 // Get the break id as an object.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000866 Handle<Object> break_id = Factory::NewNumberFromInt(Debug::break_id());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000867
868 // Call HandleBreakPointx.
869 bool caught_exception = false;
870 const int argc = 2;
871 Object** argv[argc] = {
872 break_id.location(),
873 reinterpret_cast<Object**>(break_point_object.location())
874 };
875 Handle<Object> result = Execution::TryCall(check_break_point,
876 Top::builtins(), argc, argv,
877 &caught_exception);
878
879 // If exception or non boolean result handle as not triggered
880 if (caught_exception || !result->IsBoolean()) {
881 return false;
882 }
883
884 // Return whether the break point is triggered.
885 return *result == Heap::true_value();
886}
887
888
889// Check whether the function has debug information.
890bool Debug::HasDebugInfo(Handle<SharedFunctionInfo> shared) {
891 return !shared->debug_info()->IsUndefined();
892}
893
894
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000895// Return the debug info for this function. EnsureDebugInfo must be called
896// prior to ensure the debug info has been generated for shared.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000897Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000898 ASSERT(HasDebugInfo(shared));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000899 return Handle<DebugInfo>(DebugInfo::cast(shared->debug_info()));
900}
901
902
903void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared,
904 int source_position,
905 Handle<Object> break_point_object) {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000906 HandleScope scope;
907
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000908 if (!EnsureDebugInfo(shared)) {
909 // Return if retrieving debug info failed.
910 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000911 }
912
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000913 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000914 // Source positions starts with zero.
915 ASSERT(source_position >= 0);
916
917 // Find the break point and change it.
918 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
919 it.FindBreakLocationFromPosition(source_position);
920 it.SetBreakPoint(break_point_object);
921
922 // At least one active break point now.
923 ASSERT(debug_info->GetBreakPointCount() > 0);
924}
925
926
927void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000928 HandleScope scope;
929
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000930 DebugInfoListNode* node = debug_info_list_;
931 while (node != NULL) {
932 Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(),
933 break_point_object);
934 if (!result->IsUndefined()) {
935 // Get information in the break point.
936 BreakPointInfo* break_point_info = BreakPointInfo::cast(result);
937 Handle<DebugInfo> debug_info = node->debug_info();
938 Handle<SharedFunctionInfo> shared(debug_info->shared());
939 int source_position = break_point_info->statement_position()->value();
940
941 // Source positions starts with zero.
942 ASSERT(source_position >= 0);
943
944 // Find the break point and clear it.
945 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
946 it.FindBreakLocationFromPosition(source_position);
947 it.ClearBreakPoint(break_point_object);
948
949 // If there are no more break points left remove the debug info for this
950 // function.
951 if (debug_info->GetBreakPointCount() == 0) {
952 RemoveDebugInfo(debug_info);
953 }
954
955 return;
956 }
957 node = node->next();
958 }
959}
960
961
ager@chromium.org381abbb2009-02-25 13:23:22 +0000962void Debug::ClearAllBreakPoints() {
963 DebugInfoListNode* node = debug_info_list_;
964 while (node != NULL) {
965 // Remove all debug break code.
966 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
967 it.ClearAllDebugBreak();
968 node = node->next();
969 }
970
971 // Remove all debug info.
972 while (debug_info_list_ != NULL) {
973 RemoveDebugInfo(debug_info_list_->debug_info());
974 }
975}
976
977
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000978void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000979 // Make sure the function has setup the debug info.
980 if (!EnsureDebugInfo(shared)) {
981 // Return if we failed to retrieve the debug info.
982 return;
983 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000984
985 // Flood the function with break points.
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000986 BreakLocationIterator it(GetDebugInfo(shared), ALL_BREAK_LOCATIONS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000987 while (!it.Done()) {
988 it.SetOneShot();
989 it.Next();
990 }
991}
992
993
994void Debug::FloodHandlerWithOneShot() {
ager@chromium.org8bb60582008-12-11 12:02:20 +0000995 // Iterate through the JavaScript stack looking for handlers.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000996 StackFrame::Id id = break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000997 if (id == StackFrame::NO_ID) {
998 // If there is no JavaScript stack don't do anything.
999 return;
1000 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001001 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) {
1002 JavaScriptFrame* frame = it.frame();
1003 if (frame->HasHandler()) {
1004 Handle<SharedFunctionInfo> shared =
1005 Handle<SharedFunctionInfo>(
1006 JSFunction::cast(frame->function())->shared());
1007 // Flood the function with the catch block with break points
1008 FloodWithOneShot(shared);
1009 return;
1010 }
1011 }
1012}
1013
1014
1015void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
1016 if (type == BreakUncaughtException) {
1017 break_on_uncaught_exception_ = enable;
1018 } else {
1019 break_on_exception_ = enable;
1020 }
1021}
1022
1023
1024void Debug::PrepareStep(StepAction step_action, int step_count) {
1025 HandleScope scope;
1026 ASSERT(Debug::InDebugger());
1027
1028 // Remember this step action and count.
1029 thread_local_.last_step_action_ = step_action;
1030 thread_local_.step_count_ = step_count;
1031
1032 // Get the frame where the execution has stopped and skip the debug frame if
1033 // any. The debug frame will only be present if execution was stopped due to
1034 // hitting a break point. In other situations (e.g. unhandled exception) the
1035 // debug frame is not present.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001036 StackFrame::Id id = break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00001037 if (id == StackFrame::NO_ID) {
1038 // If there is no JavaScript stack don't do anything.
1039 return;
1040 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001041 JavaScriptFrameIterator frames_it(id);
1042 JavaScriptFrame* frame = frames_it.frame();
1043
1044 // First of all ensure there is one-shot break points in the top handler
1045 // if any.
1046 FloodHandlerWithOneShot();
1047
1048 // If the function on the top frame is unresolved perform step out. This will
1049 // be the case when calling unknown functions and having the debugger stopped
1050 // in an unhandled exception.
1051 if (!frame->function()->IsJSFunction()) {
1052 // Step out: Find the calling JavaScript frame and flood it with
1053 // breakpoints.
1054 frames_it.Advance();
1055 // Fill the function to return to with one-shot break points.
1056 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
1057 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1058 return;
1059 }
1060
1061 // Get the debug info (create it if it does not exist).
1062 Handle<SharedFunctionInfo> shared =
1063 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001064 if (!EnsureDebugInfo(shared)) {
1065 // Return if ensuring debug info failed.
1066 return;
1067 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001068 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1069
1070 // Find the break location where execution has stopped.
1071 BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS);
1072 it.FindBreakLocationFromAddress(frame->pc());
1073
1074 // Compute whether or not the target is a call target.
1075 bool is_call_target = false;
ager@chromium.org236ad962008-09-25 09:45:57 +00001076 if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001077 Address target = it.rinfo()->target_address();
ager@chromium.org8bb60582008-12-11 12:02:20 +00001078 Code* code = Code::GetCodeFromTargetAddress(target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001079 if (code->is_call_stub()) is_call_target = true;
1080 }
1081
v8.team.kasperl727e9952008-09-02 14:56:44 +00001082 // If this is the last break code target step out is the only possibility.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001083 if (it.IsExit() || step_action == StepOut) {
1084 // Step out: If there is a JavaScript caller frame, we need to
1085 // flood it with breakpoints.
1086 frames_it.Advance();
1087 if (!frames_it.done()) {
1088 // Fill the function to return to with one-shot break points.
1089 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
1090 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1091 }
ager@chromium.org236ad962008-09-25 09:45:57 +00001092 } else if (!(is_call_target || RelocInfo::IsConstructCall(it.rmode())) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001093 step_action == StepNext || step_action == StepMin) {
1094 // Step next or step min.
1095
1096 // Fill the current function with one-shot break points.
1097 FloodWithOneShot(shared);
1098
1099 // Remember source position and frame to handle step next.
1100 thread_local_.last_statement_position_ =
1101 debug_info->code()->SourceStatementPosition(frame->pc());
1102 thread_local_.last_fp_ = frame->fp();
1103 } else {
1104 // Fill the current function with one-shot break points even for step in on
1105 // a call target as the function called might be a native function for
1106 // which step in will not stop.
1107 FloodWithOneShot(shared);
1108
1109 // Step in or Step in min
1110 it.PrepareStepIn();
1111 ActivateStepIn(frame);
1112 }
1113}
1114
1115
1116// Check whether the current debug break should be reported to the debugger. It
1117// is used to have step next and step in only report break back to the debugger
1118// if on a different frame or in a different statement. In some situations
1119// there will be several break points in the same statement when the code is
v8.team.kasperl727e9952008-09-02 14:56:44 +00001120// flooded with one-shot break points. This function helps to perform several
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001121// steps before reporting break back to the debugger.
1122bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
1123 JavaScriptFrame* frame) {
1124 // If the step last action was step next or step in make sure that a new
1125 // statement is hit.
1126 if (thread_local_.last_step_action_ == StepNext ||
1127 thread_local_.last_step_action_ == StepIn) {
1128 // Never continue if returning from function.
1129 if (break_location_iterator->IsExit()) return false;
1130
1131 // Continue if we are still on the same frame and in the same statement.
1132 int current_statement_position =
1133 break_location_iterator->code()->SourceStatementPosition(frame->pc());
1134 return thread_local_.last_fp_ == frame->fp() &&
ager@chromium.org236ad962008-09-25 09:45:57 +00001135 thread_local_.last_statement_position_ == current_statement_position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001136 }
1137
1138 // No step next action - don't continue.
1139 return false;
1140}
1141
1142
1143// Check whether the code object at the specified address is a debug break code
1144// object.
1145bool Debug::IsDebugBreak(Address addr) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00001146 Code* code = Code::GetCodeFromTargetAddress(addr);
kasper.lund7276f142008-07-30 08:49:36 +00001147 return code->ic_state() == DEBUG_BREAK;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001148}
1149
1150
1151// Check whether a code stub with the specified major key is a possible break
1152// point location when looking for source break locations.
1153bool Debug::IsSourceBreakStub(Code* code) {
1154 CodeStub::Major major_key = code->major_key();
1155 return major_key == CodeStub::CallFunction;
1156}
1157
1158
1159// Check whether a code stub with the specified major key is a possible break
1160// location.
1161bool Debug::IsBreakStub(Code* code) {
1162 CodeStub::Major major_key = code->major_key();
1163 return major_key == CodeStub::CallFunction ||
1164 major_key == CodeStub::StackCheck;
1165}
1166
1167
1168// Find the builtin to use for invoking the debug break
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001169Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001170 // Find the builtin debug break function matching the calling convention
1171 // used by the call site.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001172 if (code->is_inline_cache_stub()) {
1173 if (code->is_call_stub()) {
1174 return ComputeCallDebugBreak(code->arguments_count());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001175 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001176 if (code->is_load_stub()) {
1177 return Handle<Code>(Builtins::builtin(Builtins::LoadIC_DebugBreak));
1178 }
1179 if (code->is_store_stub()) {
1180 return Handle<Code>(Builtins::builtin(Builtins::StoreIC_DebugBreak));
1181 }
1182 if (code->is_keyed_load_stub()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001183 Handle<Code> result =
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001184 Handle<Code>(Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185 return result;
1186 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001187 if (code->is_keyed_store_stub()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188 Handle<Code> result =
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001189 Handle<Code>(Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190 return result;
1191 }
1192 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001193 if (RelocInfo::IsConstructCall(mode)) {
1194 Handle<Code> result =
1195 Handle<Code>(Builtins::builtin(Builtins::ConstructCall_DebugBreak));
1196 return result;
1197 }
1198 if (code->kind() == Code::STUB) {
1199 ASSERT(code->major_key() == CodeStub::CallFunction ||
1200 code->major_key() == CodeStub::StackCheck);
1201 Handle<Code> result =
1202 Handle<Code>(Builtins::builtin(Builtins::StubNoRegisters_DebugBreak));
1203 return result;
1204 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205
1206 UNREACHABLE();
1207 return Handle<Code>::null();
1208}
1209
1210
1211// Simple function for returning the source positions for active break points.
1212Handle<Object> Debug::GetSourceBreakLocations(
1213 Handle<SharedFunctionInfo> shared) {
1214 if (!HasDebugInfo(shared)) return Handle<Object>(Heap::undefined_value());
1215 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1216 if (debug_info->GetBreakPointCount() == 0) {
1217 return Handle<Object>(Heap::undefined_value());
1218 }
1219 Handle<FixedArray> locations =
1220 Factory::NewFixedArray(debug_info->GetBreakPointCount());
1221 int count = 0;
1222 for (int i = 0; i < debug_info->break_points()->length(); i++) {
1223 if (!debug_info->break_points()->get(i)->IsUndefined()) {
1224 BreakPointInfo* break_point_info =
1225 BreakPointInfo::cast(debug_info->break_points()->get(i));
1226 if (break_point_info->GetBreakPointCount() > 0) {
1227 locations->set(count++, break_point_info->statement_position());
1228 }
1229 }
1230 }
1231 return locations;
1232}
1233
1234
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001235void Debug::NewBreak(StackFrame::Id break_frame_id) {
1236 thread_local_.break_frame_id_ = break_frame_id;
1237 thread_local_.break_id_ = ++thread_local_.break_count_;
1238}
1239
1240
1241void Debug::SetBreak(StackFrame::Id break_frame_id, int break_id) {
1242 thread_local_.break_frame_id_ = break_frame_id;
1243 thread_local_.break_id_ = break_id;
1244}
1245
1246
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001247// Handle stepping into a function.
1248void Debug::HandleStepIn(Handle<JSFunction> function,
1249 Address fp,
1250 bool is_constructor) {
1251 // If the frame pointer is not supplied by the caller find it.
1252 if (fp == 0) {
1253 StackFrameIterator it;
1254 it.Advance();
1255 // For constructor functions skip another frame.
1256 if (is_constructor) {
1257 ASSERT(it.frame()->is_construct());
1258 it.Advance();
1259 }
1260 fp = it.frame()->fp();
1261 }
1262
1263 // Flood the function with one-shot break points if it is called from where
1264 // step into was requested.
1265 if (fp == Debug::step_in_fp()) {
1266 // Don't allow step into functions in the native context.
1267 if (function->context()->global() != Top::context()->builtins()) {
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001268 if (function->shared()->code() ==
1269 Builtins::builtin(Builtins::FunctionApply) ||
1270 function->shared()->code() ==
1271 Builtins::builtin(Builtins::FunctionCall)) {
1272 // Handle function.apply and function.call separately to flood the
1273 // function to be called and not the code for Builtins::FunctionApply or
1274 // Builtins::FunctionCall. At the point of the call IC to call either
1275 // Builtins::FunctionApply or Builtins::FunctionCall the expression
1276 // stack has the following content:
1277 // symbol "apply" or "call"
1278 // function apply or call was called on
1279 // receiver for apply or call (first parameter to apply or call)
1280 // ... further arguments to apply or call.
1281 JavaScriptFrameIterator it;
1282 ASSERT(it.frame()->fp() == fp);
1283 ASSERT(it.frame()->GetExpression(1)->IsJSFunction());
1284 if (it.frame()->GetExpression(1)->IsJSFunction()) {
1285 Handle<JSFunction>
1286 actual_function(JSFunction::cast(it.frame()->GetExpression(1)));
1287 Handle<SharedFunctionInfo> actual_shared(actual_function->shared());
1288 Debug::FloodWithOneShot(actual_shared);
1289 }
1290 } else {
1291 Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1292 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001293 }
1294 }
1295}
1296
1297
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001298void Debug::ClearStepping() {
1299 // Clear the various stepping setup.
1300 ClearOneShot();
1301 ClearStepIn();
1302 ClearStepNext();
1303
1304 // Clear multiple step counter.
1305 thread_local_.step_count_ = 0;
1306}
1307
1308// Clears all the one-shot break points that are currently set. Normally this
1309// function is called each time a break point is hit as one shot break points
1310// are used to support stepping.
1311void Debug::ClearOneShot() {
1312 // The current implementation just runs through all the breakpoints. When the
v8.team.kasperl727e9952008-09-02 14:56:44 +00001313 // last break point for a function is removed that function is automatically
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001314 // removed from the list.
1315
1316 DebugInfoListNode* node = debug_info_list_;
1317 while (node != NULL) {
1318 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1319 while (!it.Done()) {
1320 it.ClearOneShot();
1321 it.Next();
1322 }
1323 node = node->next();
1324 }
1325}
1326
1327
1328void Debug::ActivateStepIn(StackFrame* frame) {
1329 thread_local_.step_into_fp_ = frame->fp();
1330}
1331
1332
1333void Debug::ClearStepIn() {
1334 thread_local_.step_into_fp_ = 0;
1335}
1336
1337
1338void Debug::ClearStepNext() {
1339 thread_local_.last_step_action_ = StepNone;
ager@chromium.org236ad962008-09-25 09:45:57 +00001340 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001341 thread_local_.last_fp_ = 0;
1342}
1343
1344
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001345bool Debug::EnsureCompiled(Handle<SharedFunctionInfo> shared) {
1346 if (shared->is_compiled()) return true;
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001347 return CompileLazyShared(shared, CLEAR_EXCEPTION, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001348}
1349
1350
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001351// Ensures the debug information is present for shared.
1352bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
1353 // Return if we already have the debug info for shared.
1354 if (HasDebugInfo(shared)) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001355
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001356 // Ensure shared in compiled. Return false if this failed.
1357 if (!EnsureCompiled(shared)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358
1359 // Create the debug info object.
v8.team.kasperl727e9952008-09-02 14:56:44 +00001360 Handle<DebugInfo> debug_info = Factory::NewDebugInfo(shared);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001361
1362 // Add debug info to the list.
1363 DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
1364 node->set_next(debug_info_list_);
1365 debug_info_list_ = node;
1366
1367 // Now there is at least one break point.
1368 has_break_points_ = true;
1369
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001370 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001371}
1372
1373
1374void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
1375 ASSERT(debug_info_list_ != NULL);
1376 // Run through the debug info objects to find this one and remove it.
1377 DebugInfoListNode* prev = NULL;
1378 DebugInfoListNode* current = debug_info_list_;
1379 while (current != NULL) {
1380 if (*current->debug_info() == *debug_info) {
1381 // Unlink from list. If prev is NULL we are looking at the first element.
1382 if (prev == NULL) {
1383 debug_info_list_ = current->next();
1384 } else {
1385 prev->set_next(current->next());
1386 }
1387 current->debug_info()->shared()->set_debug_info(Heap::undefined_value());
1388 delete current;
1389
1390 // If there are no more debug info objects there are not more break
1391 // points.
1392 has_break_points_ = debug_info_list_ != NULL;
1393
1394 return;
1395 }
1396 // Move to next in list.
1397 prev = current;
1398 current = current->next();
1399 }
1400 UNREACHABLE();
1401}
1402
1403
1404void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00001405 HandleScope scope;
1406
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001407 // Get the executing function in which the debug break occurred.
1408 Handle<SharedFunctionInfo> shared =
1409 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001410 if (!EnsureDebugInfo(shared)) {
1411 // Return if we failed to retrieve the debug info.
1412 return;
1413 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001414 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1415 Handle<Code> code(debug_info->code());
1416 Handle<Code> original_code(debug_info->original_code());
1417#ifdef DEBUG
1418 // Get the code which is actually executing.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001419 Handle<Code> frame_code(frame->code());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420 ASSERT(frame_code.is_identical_to(code));
1421#endif
1422
1423 // Find the call address in the running code. This address holds the call to
1424 // either a DebugBreakXXX or to the debug break return entry code if the
1425 // break point is still active after processing the break point.
1426 Address addr = frame->pc() - Assembler::kTargetAddrToReturnAddrDist;
1427
1428 // Check if the location is at JS exit.
1429 bool at_js_exit = false;
1430 RelocIterator it(debug_info->code());
1431 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001432 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001433 at_js_exit = it.rinfo()->pc() == addr - 1;
1434 }
1435 it.next();
1436 }
1437
1438 // Handle the jump to continue execution after break point depending on the
1439 // break location.
1440 if (at_js_exit) {
1441 // First check if the call in the code is still the debug break return
1442 // entry code. If it is the break point is still active. If not the break
1443 // point was removed during break point processing.
1444 if (Assembler::target_address_at(addr) ==
1445 debug_break_return_entry()->entry()) {
1446 // Break point still active. Jump to the corresponding place in the
1447 // original code.
1448 addr += original_code->instruction_start() - code->instruction_start();
1449 }
1450
1451 // Move one byte back to where the call instruction was placed.
1452 thread_local_.after_break_target_ = addr - 1;
1453 } else {
1454 // Check if there still is a debug break call at the target address. If the
1455 // break point has been removed it will have disappeared. If it have
1456 // disappeared don't try to look in the original code as the running code
1457 // will have the right address. This takes care of the case where the last
1458 // break point is removed from the function and therefore no "original code"
1459 // is available. If the debug break call is still there find the address in
1460 // the original code.
1461 if (IsDebugBreak(Assembler::target_address_at(addr))) {
1462 // If the break point is still there find the call address which was
1463 // overwritten in the original code by the call to DebugBreakXXX.
1464
1465 // Find the corresponding address in the original code.
1466 addr += original_code->instruction_start() - code->instruction_start();
1467 }
1468
1469 // Install jump to the call address in the original code. This will be the
1470 // call which was overwritten by the call to DebugBreakXXX.
1471 thread_local_.after_break_target_ = Assembler::target_address_at(addr);
1472 }
1473}
1474
1475
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001476bool Debug::IsDebugGlobal(GlobalObject* global) {
1477 return IsLoaded() && global == Debug::debug_context()->global();
1478}
1479
1480
ager@chromium.org32912102009-01-16 10:38:43 +00001481void Debug::ClearMirrorCache() {
ager@chromium.org381abbb2009-02-25 13:23:22 +00001482 HandleScope scope;
ager@chromium.org32912102009-01-16 10:38:43 +00001483 ASSERT(Top::context() == *Debug::debug_context());
1484
1485 // Clear the mirror cache.
1486 Handle<String> function_name =
1487 Factory::LookupSymbol(CStrVector("ClearMirrorCache"));
1488 Handle<Object> fun(Top::global()->GetProperty(*function_name));
1489 ASSERT(fun->IsJSFunction());
1490 bool caught_exception;
1491 Handle<Object> js_object = Execution::TryCall(
1492 Handle<JSFunction>::cast(fun),
1493 Handle<JSObject>(Debug::debug_context()->global()),
1494 0, NULL, &caught_exception);
1495}
1496
1497
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001498// If an object given is an external string, check that the underlying
1499// resource is accessible. For other kinds of objects, always return true.
1500static bool IsExternalStringValid(Object* str) {
1501 if (!str->IsString() || !StringShape(String::cast(str)).IsExternal()) {
1502 return true;
1503 }
1504 if (String::cast(str)->IsAsciiRepresentation()) {
1505 return ExternalAsciiString::cast(str)->resource() != NULL;
1506 } else if (String::cast(str)->IsTwoByteRepresentation()) {
1507 return ExternalTwoByteString::cast(str)->resource() != NULL;
1508 } else {
1509 return true;
1510 }
1511}
1512
1513
1514void Debug::CreateScriptCache() {
1515 HandleScope scope;
1516
1517 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
1518 // rid of all the cached script wrappers and the second gets rid of the
1519 // scripts which is no longer referenced.
1520 Heap::CollectAllGarbage();
1521 Heap::CollectAllGarbage();
1522
1523 ASSERT(script_cache_ == NULL);
1524 script_cache_ = new ScriptCache();
1525
1526 // Scan heap for Script objects.
1527 int count = 0;
1528 HeapIterator iterator;
1529 while (iterator.has_next()) {
1530 HeapObject* obj = iterator.next();
1531 ASSERT(obj != NULL);
1532 if (obj->IsScript() && IsExternalStringValid(Script::cast(obj)->source())) {
1533 script_cache_->Add(Handle<Script>(Script::cast(obj)));
1534 count++;
1535 }
1536 }
1537}
1538
1539
1540void Debug::DestroyScriptCache() {
1541 // Get rid of the script cache if it was created.
1542 if (script_cache_ != NULL) {
1543 delete script_cache_;
1544 script_cache_ = NULL;
1545 }
1546}
1547
1548
1549void Debug::AddScriptToScriptCache(Handle<Script> script) {
1550 if (script_cache_ != NULL) {
1551 script_cache_->Add(script);
1552 }
1553}
1554
1555
1556Handle<FixedArray> Debug::GetLoadedScripts() {
1557 // Create and fill the script cache when the loaded scripts is requested for
1558 // the first time.
1559 if (script_cache_ == NULL) {
1560 CreateScriptCache();
1561 }
1562
1563 // If the script cache is not active just return an empty array.
1564 ASSERT(script_cache_ != NULL);
1565 if (script_cache_ == NULL) {
1566 Factory::NewFixedArray(0);
1567 }
1568
1569 // Perform GC to get unreferenced scripts evicted from the cache before
1570 // returning the content.
1571 Heap::CollectAllGarbage();
1572
1573 // Get the scripts from the cache.
1574 return script_cache_->GetScripts();
1575}
1576
1577
1578void Debug::AfterGarbageCollection() {
1579 // Generate events for collected scripts.
1580 if (script_cache_ != NULL) {
1581 script_cache_->ProcessCollectedScripts();
1582 }
1583}
1584
1585
ager@chromium.org71daaf62009-04-01 07:22:49 +00001586Mutex* Debugger::debugger_access_ = OS::CreateMutex();
iposva@chromium.org245aa852009-02-10 00:49:54 +00001587Handle<Object> Debugger::event_listener_ = Handle<Object>();
1588Handle<Object> Debugger::event_listener_data_ = Handle<Object>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001589bool Debugger::compiling_natives_ = false;
mads.s.agercbaa0602008-08-14 13:41:48 +00001590bool Debugger::is_loading_debugger_ = false;
ager@chromium.org71daaf62009-04-01 07:22:49 +00001591bool Debugger::never_unload_debugger_ = false;
ager@chromium.org5ec48922009-05-05 07:25:34 +00001592v8::Debug::MessageHandler2 Debugger::message_handler_ = NULL;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001593bool Debugger::debugger_unload_pending_ = false;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001594v8::Debug::HostDispatchHandler Debugger::host_dispatch_handler_ = NULL;
1595int Debugger::host_dispatch_micros_ = 100 * 1000;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001596DebuggerAgent* Debugger::agent_ = NULL;
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00001597LockingCommandMessageQueue Debugger::command_queue_(kQueueInitialSize);
ager@chromium.org41826e72009-03-30 13:30:57 +00001598Semaphore* Debugger::command_received_ = OS::CreateSemaphore(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001599
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001600
1601Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
1602 int argc, Object*** argv,
1603 bool* caught_exception) {
1604 ASSERT(Top::context() == *Debug::debug_context());
1605
1606 // Create the execution state object.
1607 Handle<String> constructor_str = Factory::LookupSymbol(constructor_name);
1608 Handle<Object> constructor(Top::global()->GetProperty(*constructor_str));
1609 ASSERT(constructor->IsJSFunction());
1610 if (!constructor->IsJSFunction()) {
1611 *caught_exception = true;
1612 return Factory::undefined_value();
1613 }
1614 Handle<Object> js_object = Execution::TryCall(
1615 Handle<JSFunction>::cast(constructor),
1616 Handle<JSObject>(Debug::debug_context()->global()), argc, argv,
1617 caught_exception);
1618 return js_object;
1619}
1620
1621
1622Handle<Object> Debugger::MakeExecutionState(bool* caught_exception) {
1623 // Create the execution state object.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001624 Handle<Object> break_id = Factory::NewNumberFromInt(Debug::break_id());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001625 const int argc = 1;
1626 Object** argv[argc] = { break_id.location() };
1627 return MakeJSObject(CStrVector("MakeExecutionState"),
1628 argc, argv, caught_exception);
1629}
1630
1631
1632Handle<Object> Debugger::MakeBreakEvent(Handle<Object> exec_state,
1633 Handle<Object> break_points_hit,
1634 bool* caught_exception) {
1635 // Create the new break event object.
1636 const int argc = 2;
1637 Object** argv[argc] = { exec_state.location(),
1638 break_points_hit.location() };
1639 return MakeJSObject(CStrVector("MakeBreakEvent"),
1640 argc,
1641 argv,
1642 caught_exception);
1643}
1644
1645
1646Handle<Object> Debugger::MakeExceptionEvent(Handle<Object> exec_state,
1647 Handle<Object> exception,
1648 bool uncaught,
1649 bool* caught_exception) {
1650 // Create the new exception event object.
1651 const int argc = 3;
1652 Object** argv[argc] = { exec_state.location(),
1653 exception.location(),
1654 uncaught ? Factory::true_value().location() :
1655 Factory::false_value().location()};
1656 return MakeJSObject(CStrVector("MakeExceptionEvent"),
1657 argc, argv, caught_exception);
1658}
1659
1660
1661Handle<Object> Debugger::MakeNewFunctionEvent(Handle<Object> function,
1662 bool* caught_exception) {
1663 // Create the new function event object.
1664 const int argc = 1;
1665 Object** argv[argc] = { function.location() };
1666 return MakeJSObject(CStrVector("MakeNewFunctionEvent"),
1667 argc, argv, caught_exception);
1668}
1669
1670
1671Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
iposva@chromium.org245aa852009-02-10 00:49:54 +00001672 bool before,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001673 bool* caught_exception) {
1674 // Create the compile event object.
1675 Handle<Object> exec_state = MakeExecutionState(caught_exception);
iposva@chromium.org245aa852009-02-10 00:49:54 +00001676 Handle<Object> script_wrapper = GetScriptWrapper(script);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001677 const int argc = 3;
iposva@chromium.org245aa852009-02-10 00:49:54 +00001678 Object** argv[argc] = { exec_state.location(),
1679 script_wrapper.location(),
1680 before ? Factory::true_value().location() :
1681 Factory::false_value().location() };
1682
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001683 return MakeJSObject(CStrVector("MakeCompileEvent"),
1684 argc,
1685 argv,
1686 caught_exception);
1687}
1688
1689
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001690Handle<Object> Debugger::MakeScriptCollectedEvent(int id,
1691 bool* caught_exception) {
1692 // Create the script collected event object.
1693 Handle<Object> exec_state = MakeExecutionState(caught_exception);
1694 Handle<Object> id_object = Handle<Smi>(Smi::FromInt(id));
1695 const int argc = 2;
1696 Object** argv[argc] = { exec_state.location(), id_object.location() };
1697
1698 return MakeJSObject(CStrVector("MakeScriptCollectedEvent"),
1699 argc,
1700 argv,
1701 caught_exception);
1702}
1703
1704
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001705void Debugger::OnException(Handle<Object> exception, bool uncaught) {
1706 HandleScope scope;
1707
1708 // Bail out based on state or if there is no listener for this event
1709 if (Debug::InDebugger()) return;
1710 if (!Debugger::EventActive(v8::Exception)) return;
1711
1712 // Bail out if exception breaks are not active
1713 if (uncaught) {
1714 // Uncaught exceptions are reported by either flags.
1715 if (!(Debug::break_on_uncaught_exception() ||
1716 Debug::break_on_exception())) return;
1717 } else {
1718 // Caught exceptions are reported is activated.
1719 if (!Debug::break_on_exception()) return;
1720 }
1721
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001722 // Enter the debugger.
1723 EnterDebugger debugger;
1724 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001725
1726 // Clear all current stepping setup.
1727 Debug::ClearStepping();
1728 // Create the event data object.
1729 bool caught_exception = false;
1730 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
1731 Handle<Object> event_data;
1732 if (!caught_exception) {
1733 event_data = MakeExceptionEvent(exec_state, exception, uncaught,
1734 &caught_exception);
1735 }
1736 // Bail out and don't call debugger if exception.
1737 if (caught_exception) {
1738 return;
1739 }
1740
ager@chromium.org5ec48922009-05-05 07:25:34 +00001741 // Process debug event.
1742 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001743 // Return to continue execution from where the exception was thrown.
1744}
1745
1746
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001747void Debugger::OnDebugBreak(Handle<Object> break_points_hit,
1748 bool auto_continue) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001749 HandleScope scope;
1750
kasper.lund212ac232008-07-16 07:07:30 +00001751 // Debugger has already been entered by caller.
1752 ASSERT(Top::context() == *Debug::debug_context());
1753
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001754 // Bail out if there is no listener for this event
1755 if (!Debugger::EventActive(v8::Break)) return;
1756
1757 // Debugger must be entered in advance.
1758 ASSERT(Top::context() == *Debug::debug_context());
1759
1760 // Create the event data object.
1761 bool caught_exception = false;
1762 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
1763 Handle<Object> event_data;
1764 if (!caught_exception) {
1765 event_data = MakeBreakEvent(exec_state, break_points_hit,
1766 &caught_exception);
1767 }
1768 // Bail out and don't call debugger if exception.
1769 if (caught_exception) {
1770 return;
1771 }
1772
ager@chromium.org5ec48922009-05-05 07:25:34 +00001773 // Process debug event.
1774 ProcessDebugEvent(v8::Break,
1775 Handle<JSObject>::cast(event_data),
1776 auto_continue);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001777}
1778
1779
1780void Debugger::OnBeforeCompile(Handle<Script> script) {
1781 HandleScope scope;
1782
1783 // Bail out based on state or if there is no listener for this event
1784 if (Debug::InDebugger()) return;
1785 if (compiling_natives()) return;
1786 if (!EventActive(v8::BeforeCompile)) return;
1787
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001788 // Enter the debugger.
1789 EnterDebugger debugger;
1790 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001791
1792 // Create the event data object.
1793 bool caught_exception = false;
iposva@chromium.org245aa852009-02-10 00:49:54 +00001794 Handle<Object> event_data = MakeCompileEvent(script, true, &caught_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001795 // Bail out and don't call debugger if exception.
1796 if (caught_exception) {
1797 return;
1798 }
1799
ager@chromium.org5ec48922009-05-05 07:25:34 +00001800 // Process debug event.
1801 ProcessDebugEvent(v8::BeforeCompile,
1802 Handle<JSObject>::cast(event_data),
1803 true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001804}
1805
1806
1807// Handle debugger actions when a new script is compiled.
1808void Debugger::OnAfterCompile(Handle<Script> script, Handle<JSFunction> fun) {
kasper.lund212ac232008-07-16 07:07:30 +00001809 HandleScope scope;
1810
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001811 // Add the newly compiled script to the script cache.
1812 Debug::AddScriptToScriptCache(script);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001813
1814 // No more to do if not debugging.
ager@chromium.org71daaf62009-04-01 07:22:49 +00001815 if (!IsDebuggerActive()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001816
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001817 // No compile events while compiling natives.
1818 if (compiling_natives()) return;
1819
iposva@chromium.org245aa852009-02-10 00:49:54 +00001820 // Store whether in debugger before entering debugger.
1821 bool in_debugger = Debug::InDebugger();
1822
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001823 // Enter the debugger.
1824 EnterDebugger debugger;
1825 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001826
1827 // If debugging there might be script break points registered for this
1828 // script. Make sure that these break points are set.
1829
1830 // Get the function UpdateScriptBreakPoints (defined in debug-delay.js).
1831 Handle<Object> update_script_break_points =
1832 Handle<Object>(Debug::debug_context()->global()->GetProperty(
1833 *Factory::LookupAsciiSymbol("UpdateScriptBreakPoints")));
1834 if (!update_script_break_points->IsJSFunction()) {
1835 return;
1836 }
1837 ASSERT(update_script_break_points->IsJSFunction());
1838
1839 // Wrap the script object in a proper JS object before passing it
1840 // to JavaScript.
1841 Handle<JSValue> wrapper = GetScriptWrapper(script);
1842
1843 // Call UpdateScriptBreakPoints expect no exceptions.
kasper.lund212ac232008-07-16 07:07:30 +00001844 bool caught_exception = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001845 const int argc = 1;
1846 Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) };
1847 Handle<Object> result = Execution::TryCall(
1848 Handle<JSFunction>::cast(update_script_break_points),
1849 Top::builtins(), argc, argv,
1850 &caught_exception);
1851 if (caught_exception) {
1852 return;
1853 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001854 // Bail out based on state or if there is no listener for this event
iposva@chromium.org245aa852009-02-10 00:49:54 +00001855 if (in_debugger) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001856 if (!Debugger::EventActive(v8::AfterCompile)) return;
1857
1858 // Create the compile state object.
1859 Handle<Object> event_data = MakeCompileEvent(script,
iposva@chromium.org245aa852009-02-10 00:49:54 +00001860 false,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001861 &caught_exception);
1862 // Bail out and don't call debugger if exception.
1863 if (caught_exception) {
1864 return;
1865 }
ager@chromium.org5ec48922009-05-05 07:25:34 +00001866 // Process debug event.
1867 ProcessDebugEvent(v8::AfterCompile,
1868 Handle<JSObject>::cast(event_data),
1869 true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001870}
1871
1872
1873void Debugger::OnNewFunction(Handle<JSFunction> function) {
1874 return;
1875 HandleScope scope;
1876
1877 // Bail out based on state or if there is no listener for this event
1878 if (Debug::InDebugger()) return;
1879 if (compiling_natives()) return;
1880 if (!Debugger::EventActive(v8::NewFunction)) return;
1881
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001882 // Enter the debugger.
1883 EnterDebugger debugger;
1884 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001885
1886 // Create the event object.
1887 bool caught_exception = false;
1888 Handle<Object> event_data = MakeNewFunctionEvent(function, &caught_exception);
1889 // Bail out and don't call debugger if exception.
1890 if (caught_exception) {
1891 return;
1892 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001893 // Process debug event.
ager@chromium.org5ec48922009-05-05 07:25:34 +00001894 ProcessDebugEvent(v8::NewFunction, Handle<JSObject>::cast(event_data), true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001895}
1896
1897
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001898void Debugger::OnScriptCollected(int id) {
1899 HandleScope scope;
1900
1901 // No more to do if not debugging.
1902 if (!IsDebuggerActive()) return;
1903 if (!Debugger::EventActive(v8::ScriptCollected)) return;
1904
1905 // Enter the debugger.
1906 EnterDebugger debugger;
1907 if (debugger.FailedToEnter()) return;
1908
1909 // Create the script collected state object.
1910 bool caught_exception = false;
1911 Handle<Object> event_data = MakeScriptCollectedEvent(id,
1912 &caught_exception);
1913 // Bail out and don't call debugger if exception.
1914 if (caught_exception) {
1915 return;
1916 }
1917
1918 // Process debug event.
1919 ProcessDebugEvent(v8::ScriptCollected,
1920 Handle<JSObject>::cast(event_data),
1921 true);
1922}
1923
1924
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001925void Debugger::ProcessDebugEvent(v8::DebugEvent event,
ager@chromium.org5ec48922009-05-05 07:25:34 +00001926 Handle<JSObject> event_data,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001927 bool auto_continue) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00001928 HandleScope scope;
1929
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001930 // Create the execution state.
1931 bool caught_exception = false;
1932 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
1933 if (caught_exception) {
1934 return;
1935 }
ager@chromium.org41826e72009-03-30 13:30:57 +00001936 // First notify the message handler if any.
1937 if (message_handler_ != NULL) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00001938 NotifyMessageHandler(event,
1939 Handle<JSObject>::cast(exec_state),
1940 event_data,
1941 auto_continue);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001942 }
iposva@chromium.org245aa852009-02-10 00:49:54 +00001943 // Notify registered debug event listener. This can be either a C or a
1944 // JavaScript function.
1945 if (!event_listener_.is_null()) {
1946 if (event_listener_->IsProxy()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001947 // C debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00001948 Handle<Proxy> callback_obj(Handle<Proxy>::cast(event_listener_));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001949 v8::Debug::EventCallback callback =
1950 FUNCTION_CAST<v8::Debug::EventCallback>(callback_obj->proxy());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001951 callback(event,
1952 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
ager@chromium.org5ec48922009-05-05 07:25:34 +00001953 v8::Utils::ToLocal(event_data),
iposva@chromium.org245aa852009-02-10 00:49:54 +00001954 v8::Utils::ToLocal(Handle<Object>::cast(event_listener_data_)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001955 } else {
1956 // JavaScript debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00001957 ASSERT(event_listener_->IsJSFunction());
1958 Handle<JSFunction> fun(Handle<JSFunction>::cast(event_listener_));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001959
1960 // Invoke the JavaScript debug event listener.
1961 const int argc = 4;
1962 Object** argv[argc] = { Handle<Object>(Smi::FromInt(event)).location(),
1963 exec_state.location(),
ager@chromium.org5ec48922009-05-05 07:25:34 +00001964 Handle<Object>::cast(event_data).location(),
iposva@chromium.org245aa852009-02-10 00:49:54 +00001965 event_listener_data_.location() };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001966 Handle<Object> result = Execution::TryCall(fun, Top::global(),
1967 argc, argv, &caught_exception);
1968 if (caught_exception) {
1969 // Silently ignore exceptions from debug event listeners.
1970 }
1971 }
1972 }
1973}
1974
1975
ager@chromium.org71daaf62009-04-01 07:22:49 +00001976void Debugger::UnloadDebugger() {
1977 // Make sure that there are no breakpoints left.
1978 Debug::ClearAllBreakPoints();
1979
1980 // Unload the debugger if feasible.
1981 if (!never_unload_debugger_) {
1982 Debug::Unload();
1983 }
1984
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001985 // Clear the flag indicating that the debugger should be unloaded.
1986 debugger_unload_pending_ = false;
ager@chromium.org71daaf62009-04-01 07:22:49 +00001987}
1988
1989
ager@chromium.org41826e72009-03-30 13:30:57 +00001990void Debugger::NotifyMessageHandler(v8::DebugEvent event,
ager@chromium.org5ec48922009-05-05 07:25:34 +00001991 Handle<JSObject> exec_state,
1992 Handle<JSObject> event_data,
ager@chromium.org41826e72009-03-30 13:30:57 +00001993 bool auto_continue) {
1994 HandleScope scope;
1995
1996 if (!Debug::Load()) return;
1997
1998 // Process the individual events.
ager@chromium.org5ec48922009-05-05 07:25:34 +00001999 bool sendEventMessage = false;
ager@chromium.org41826e72009-03-30 13:30:57 +00002000 switch (event) {
2001 case v8::Break:
ager@chromium.org5ec48922009-05-05 07:25:34 +00002002 sendEventMessage = !auto_continue;
ager@chromium.org41826e72009-03-30 13:30:57 +00002003 break;
2004 case v8::Exception:
ager@chromium.org5ec48922009-05-05 07:25:34 +00002005 sendEventMessage = true;
ager@chromium.org41826e72009-03-30 13:30:57 +00002006 break;
2007 case v8::BeforeCompile:
2008 break;
2009 case v8::AfterCompile:
ager@chromium.org5ec48922009-05-05 07:25:34 +00002010 sendEventMessage = true;
ager@chromium.org41826e72009-03-30 13:30:57 +00002011 break;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002012 case v8::ScriptCollected:
2013 sendEventMessage = true;
2014 break;
ager@chromium.org41826e72009-03-30 13:30:57 +00002015 case v8::NewFunction:
2016 break;
2017 default:
2018 UNREACHABLE();
2019 }
2020
ager@chromium.org5ec48922009-05-05 07:25:34 +00002021 // The debug command interrupt flag might have been set when the command was
2022 // added. It should be enough to clear the flag only once while we are in the
2023 // debugger.
2024 ASSERT(Debug::InDebugger());
2025 StackGuard::Continue(DEBUGCOMMAND);
2026
2027 // Notify the debugger that a debug event has occurred unless auto continue is
2028 // active in which case no event is send.
2029 if (sendEventMessage) {
2030 MessageImpl message = MessageImpl::NewEvent(
2031 event,
2032 auto_continue,
2033 Handle<JSObject>::cast(exec_state),
2034 Handle<JSObject>::cast(event_data));
2035 InvokeMessageHandler(message);
2036 }
2037 if (auto_continue && !HasCommands()) {
2038 return;
2039 }
ager@chromium.org41826e72009-03-30 13:30:57 +00002040
2041 // Get the DebugCommandProcessor.
2042 v8::Local<v8::Object> api_exec_state =
2043 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state));
2044 v8::Local<v8::String> fun_name =
2045 v8::String::New("debugCommandProcessor");
2046 v8::Local<v8::Function> fun =
2047 v8::Function::Cast(*api_exec_state->Get(fun_name));
2048 v8::TryCatch try_catch;
2049 v8::Local<v8::Object> cmd_processor =
2050 v8::Object::Cast(*fun->Call(api_exec_state, 0, NULL));
2051 if (try_catch.HasCaught()) {
2052 PrintLn(try_catch.Exception());
2053 return;
2054 }
2055
ager@chromium.org41826e72009-03-30 13:30:57 +00002056 // Process requests from the debugger.
2057 while (true) {
2058 // Wait for new command in the queue.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002059 if (Debugger::host_dispatch_handler_) {
2060 // In case there is a host dispatch - do periodic dispatches.
2061 if (!command_received_->Wait(host_dispatch_micros_)) {
2062 // Timout expired, do the dispatch.
2063 Debugger::host_dispatch_handler_();
2064 continue;
2065 }
2066 } else {
2067 // In case there is no host dispatch - just wait.
2068 command_received_->Wait();
2069 }
ager@chromium.org41826e72009-03-30 13:30:57 +00002070
ager@chromium.org41826e72009-03-30 13:30:57 +00002071 // Get the command from the queue.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002072 CommandMessage command = command_queue_.Get();
ager@chromium.org41826e72009-03-30 13:30:57 +00002073 Logger::DebugTag("Got request from command queue, in interactive loop.");
ager@chromium.org71daaf62009-04-01 07:22:49 +00002074 if (!Debugger::IsDebuggerActive()) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002075 // Delete command text and user data.
2076 command.Dispose();
ager@chromium.org41826e72009-03-30 13:30:57 +00002077 return;
2078 }
2079
ager@chromium.org41826e72009-03-30 13:30:57 +00002080 // Invoke JavaScript to process the debug request.
2081 v8::Local<v8::String> fun_name;
2082 v8::Local<v8::Function> fun;
2083 v8::Local<v8::Value> request;
2084 v8::TryCatch try_catch;
2085 fun_name = v8::String::New("processDebugRequest");
2086 fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002087
2088 request = v8::String::New(command.text().start(),
2089 command.text().length());
ager@chromium.org41826e72009-03-30 13:30:57 +00002090 static const int kArgc = 1;
2091 v8::Handle<Value> argv[kArgc] = { request };
2092 v8::Local<v8::Value> response_val = fun->Call(cmd_processor, kArgc, argv);
2093
2094 // Get the response.
2095 v8::Local<v8::String> response;
2096 bool running = false;
2097 if (!try_catch.HasCaught()) {
2098 // Get response string.
2099 if (!response_val->IsUndefined()) {
2100 response = v8::String::Cast(*response_val);
2101 } else {
2102 response = v8::String::New("");
2103 }
2104
2105 // Log the JSON request/response.
2106 if (FLAG_trace_debug_json) {
2107 PrintLn(request);
2108 PrintLn(response);
2109 }
2110
2111 // Get the running state.
2112 fun_name = v8::String::New("isRunning");
2113 fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
2114 static const int kArgc = 1;
2115 v8::Handle<Value> argv[kArgc] = { response };
2116 v8::Local<v8::Value> running_val = fun->Call(cmd_processor, kArgc, argv);
2117 if (!try_catch.HasCaught()) {
2118 running = running_val->ToBoolean()->Value();
2119 }
2120 } else {
2121 // In case of failure the result text is the exception text.
2122 response = try_catch.Exception()->ToString();
2123 }
2124
ager@chromium.org41826e72009-03-30 13:30:57 +00002125 // Return the result.
ager@chromium.org5ec48922009-05-05 07:25:34 +00002126 MessageImpl message = MessageImpl::NewResponse(
2127 event,
2128 running,
2129 Handle<JSObject>::cast(exec_state),
2130 Handle<JSObject>::cast(event_data),
2131 Handle<String>(Utils::OpenHandle(*response)),
2132 command.client_data());
2133 InvokeMessageHandler(message);
2134 command.Dispose();
ager@chromium.org41826e72009-03-30 13:30:57 +00002135
2136 // Return from debug event processing if either the VM is put into the
2137 // runnning state (through a continue command) or auto continue is active
2138 // and there are no more commands queued.
2139 if (running || (auto_continue && !HasCommands())) {
2140 return;
2141 }
2142 }
2143}
2144
2145
iposva@chromium.org245aa852009-02-10 00:49:54 +00002146void Debugger::SetEventListener(Handle<Object> callback,
2147 Handle<Object> data) {
2148 HandleScope scope;
2149
2150 // Clear the global handles for the event listener and the event listener data
2151 // object.
2152 if (!event_listener_.is_null()) {
2153 GlobalHandles::Destroy(
2154 reinterpret_cast<Object**>(event_listener_.location()));
2155 event_listener_ = Handle<Object>();
2156 }
2157 if (!event_listener_data_.is_null()) {
2158 GlobalHandles::Destroy(
2159 reinterpret_cast<Object**>(event_listener_data_.location()));
2160 event_listener_data_ = Handle<Object>();
2161 }
2162
2163 // If there is a new debug event listener register it together with its data
2164 // object.
2165 if (!callback->IsUndefined() && !callback->IsNull()) {
2166 event_listener_ = Handle<Object>::cast(GlobalHandles::Create(*callback));
2167 if (data.is_null()) {
2168 data = Factory::undefined_value();
2169 }
2170 event_listener_data_ = Handle<Object>::cast(GlobalHandles::Create(*data));
2171 }
2172
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002173 ListenersChanged();
iposva@chromium.org245aa852009-02-10 00:49:54 +00002174}
2175
2176
ager@chromium.org5ec48922009-05-05 07:25:34 +00002177void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002178 ScopedLock with(debugger_access_);
2179
ager@chromium.org381abbb2009-02-25 13:23:22 +00002180 message_handler_ = handler;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002181 ListenersChanged();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002182 if (handler == NULL) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002183 // Send an empty command to the debugger if in a break to make JavaScript
2184 // run again if the debugger is closed.
2185 if (Debug::InDebugger()) {
2186 ProcessCommand(Vector<const uint16_t>::empty());
2187 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002188 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002189}
2190
2191
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002192void Debugger::ListenersChanged() {
2193 if (IsDebuggerActive()) {
2194 // Disable the compilation cache when the debugger is active.
2195 CompilationCache::Disable();
2196 } else {
2197 CompilationCache::Enable();
2198
2199 // Unload the debugger if event listener and message handler cleared.
2200 if (Debug::InDebugger()) {
2201 // If we are in debugger set the flag to unload the debugger when last
2202 // EnterDebugger on the current stack is destroyed.
2203 debugger_unload_pending_ = true;
2204 } else {
2205 UnloadDebugger();
2206 }
2207 }
2208}
2209
2210
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002211void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
2212 int period) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00002213 host_dispatch_handler_ = handler;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002214 host_dispatch_micros_ = period * 1000;
ager@chromium.org381abbb2009-02-25 13:23:22 +00002215}
2216
2217
ager@chromium.org41826e72009-03-30 13:30:57 +00002218// Calls the registered debug message handler. This callback is part of the
ager@chromium.org5ec48922009-05-05 07:25:34 +00002219// public API.
2220void Debugger::InvokeMessageHandler(MessageImpl message) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002221 ScopedLock with(debugger_access_);
2222
ager@chromium.org381abbb2009-02-25 13:23:22 +00002223 if (message_handler_ != NULL) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002224 message_handler_(message);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002225 }
ager@chromium.org41826e72009-03-30 13:30:57 +00002226}
2227
2228
2229// Puts a command coming from the public API on the queue. Creates
2230// a copy of the command string managed by the debugger. Up to this
2231// point, the command data was managed by the API client. Called
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002232// by the API client thread.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002233void Debugger::ProcessCommand(Vector<const uint16_t> command,
2234 v8::Debug::ClientData* client_data) {
2235 // Need to cast away const.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002236 CommandMessage message = CommandMessage::New(
ager@chromium.org41826e72009-03-30 13:30:57 +00002237 Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002238 command.length()),
2239 client_data);
ager@chromium.org41826e72009-03-30 13:30:57 +00002240 Logger::DebugTag("Put command on command_queue.");
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002241 command_queue_.Put(message);
ager@chromium.org41826e72009-03-30 13:30:57 +00002242 command_received_->Signal();
sgjesse@chromium.org3afc1582009-04-16 22:31:44 +00002243
2244 // Set the debug command break flag to have the command processed.
ager@chromium.org41826e72009-03-30 13:30:57 +00002245 if (!Debug::InDebugger()) {
2246 StackGuard::DebugCommand();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002247 }
2248}
2249
2250
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002251bool Debugger::HasCommands() {
ager@chromium.org41826e72009-03-30 13:30:57 +00002252 return !command_queue_.IsEmpty();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002253}
2254
2255
ager@chromium.org71daaf62009-04-01 07:22:49 +00002256bool Debugger::IsDebuggerActive() {
2257 ScopedLock with(debugger_access_);
2258
2259 return message_handler_ != NULL || !event_listener_.is_null();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002260}
2261
2262
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002263Handle<Object> Debugger::Call(Handle<JSFunction> fun,
2264 Handle<Object> data,
2265 bool* pending_exception) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002266 // When calling functions in the debugger prevent it from beeing unloaded.
2267 Debugger::never_unload_debugger_ = true;
2268
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002269 // Enter the debugger.
2270 EnterDebugger debugger;
2271 if (debugger.FailedToEnter() || !debugger.HasJavaScriptFrames()) {
2272 return Factory::undefined_value();
2273 }
2274
2275 // Create the execution state.
2276 bool caught_exception = false;
2277 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2278 if (caught_exception) {
2279 return Factory::undefined_value();
2280 }
2281
2282 static const int kArgc = 2;
2283 Object** argv[kArgc] = { exec_state.location(), data.location() };
2284 Handle<Object> result = Execution::Call(fun, Factory::undefined_value(),
2285 kArgc, argv, pending_exception);
2286 return result;
2287}
2288
2289
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002290bool Debugger::StartAgent(const char* name, int port) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002291 if (Socket::Setup()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002292 agent_ = new DebuggerAgent(name, port);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002293 agent_->Start();
2294 return true;
2295 }
2296
2297 return false;
2298}
2299
2300
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002301void Debugger::StopAgent() {
2302 if (agent_ != NULL) {
2303 agent_->Shutdown();
2304 agent_->Join();
2305 delete agent_;
2306 agent_ = NULL;
2307 }
2308}
2309
2310
ager@chromium.org5ec48922009-05-05 07:25:34 +00002311MessageImpl MessageImpl::NewEvent(DebugEvent event,
2312 bool running,
2313 Handle<JSObject> exec_state,
2314 Handle<JSObject> event_data) {
2315 MessageImpl message(true, event, running,
2316 exec_state, event_data, Handle<String>(), NULL);
2317 return message;
2318}
2319
2320
2321MessageImpl MessageImpl::NewResponse(DebugEvent event,
2322 bool running,
2323 Handle<JSObject> exec_state,
2324 Handle<JSObject> event_data,
2325 Handle<String> response_json,
2326 v8::Debug::ClientData* client_data) {
2327 MessageImpl message(false, event, running,
2328 exec_state, event_data, response_json, client_data);
2329 return message;
2330}
2331
2332
2333MessageImpl::MessageImpl(bool is_event,
2334 DebugEvent event,
2335 bool running,
2336 Handle<JSObject> exec_state,
2337 Handle<JSObject> event_data,
2338 Handle<String> response_json,
2339 v8::Debug::ClientData* client_data)
2340 : is_event_(is_event),
2341 event_(event),
2342 running_(running),
2343 exec_state_(exec_state),
2344 event_data_(event_data),
2345 response_json_(response_json),
2346 client_data_(client_data) {}
2347
2348
2349bool MessageImpl::IsEvent() const {
2350 return is_event_;
2351}
2352
2353
2354bool MessageImpl::IsResponse() const {
2355 return !is_event_;
2356}
2357
2358
2359DebugEvent MessageImpl::GetEvent() const {
2360 return event_;
2361}
2362
2363
2364bool MessageImpl::WillStartRunning() const {
2365 return running_;
2366}
2367
2368
2369v8::Handle<v8::Object> MessageImpl::GetExecutionState() const {
2370 return v8::Utils::ToLocal(exec_state_);
2371}
2372
2373
2374v8::Handle<v8::Object> MessageImpl::GetEventData() const {
2375 return v8::Utils::ToLocal(event_data_);
2376}
2377
2378
2379v8::Handle<v8::String> MessageImpl::GetJSON() const {
2380 v8::HandleScope scope;
2381
2382 if (IsEvent()) {
2383 // Call toJSONProtocol on the debug event object.
2384 Handle<Object> fun = GetProperty(event_data_, "toJSONProtocol");
2385 if (!fun->IsJSFunction()) {
2386 return v8::Handle<v8::String>();
2387 }
2388 bool caught_exception;
2389 Handle<Object> json = Execution::TryCall(Handle<JSFunction>::cast(fun),
2390 event_data_,
2391 0, NULL, &caught_exception);
2392 if (caught_exception || !json->IsString()) {
2393 return v8::Handle<v8::String>();
2394 }
2395 return scope.Close(v8::Utils::ToLocal(Handle<String>::cast(json)));
2396 } else {
2397 return v8::Utils::ToLocal(response_json_);
2398 }
2399}
2400
2401
2402v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002403 Handle<Context> context = Debug::debugger_entry()->GetContext();
2404 // Top::context() may have been NULL when "script collected" event occured.
2405 if (*context == NULL) {
2406 ASSERT(event_ == v8::ScriptCollected);
2407 return v8::Local<v8::Context>();
2408 }
2409 Handle<Context> global_context(context->global_context());
2410 return v8::Utils::ToLocal(global_context);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002411}
2412
2413
2414v8::Debug::ClientData* MessageImpl::GetClientData() const {
2415 return client_data_;
2416}
2417
2418
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002419CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()),
2420 client_data_(NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002421}
2422
2423
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002424CommandMessage::CommandMessage(const Vector<uint16_t>& text,
2425 v8::Debug::ClientData* data)
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002426 : text_(text),
2427 client_data_(data) {
2428}
2429
2430
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002431CommandMessage::~CommandMessage() {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002432}
2433
2434
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002435void CommandMessage::Dispose() {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002436 text_.Dispose();
2437 delete client_data_;
2438 client_data_ = NULL;
2439}
2440
2441
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002442CommandMessage CommandMessage::New(const Vector<uint16_t>& command,
2443 v8::Debug::ClientData* data) {
2444 return CommandMessage(command.Clone(), data);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002445}
2446
2447
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002448CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0),
2449 size_(size) {
2450 messages_ = NewArray<CommandMessage>(size);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002451}
2452
2453
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002454CommandMessageQueue::~CommandMessageQueue() {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002455 while (!IsEmpty()) {
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002456 CommandMessage m = Get();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002457 m.Dispose();
2458 }
kasper.lund7276f142008-07-30 08:49:36 +00002459 DeleteArray(messages_);
2460}
2461
2462
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002463CommandMessage CommandMessageQueue::Get() {
kasper.lund7276f142008-07-30 08:49:36 +00002464 ASSERT(!IsEmpty());
2465 int result = start_;
2466 start_ = (start_ + 1) % size_;
2467 return messages_[result];
2468}
2469
2470
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002471void CommandMessageQueue::Put(const CommandMessage& message) {
kasper.lund7276f142008-07-30 08:49:36 +00002472 if ((end_ + 1) % size_ == start_) {
2473 Expand();
2474 }
2475 messages_[end_] = message;
2476 end_ = (end_ + 1) % size_;
2477}
2478
2479
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002480void CommandMessageQueue::Expand() {
2481 CommandMessageQueue new_queue(size_ * 2);
kasper.lund7276f142008-07-30 08:49:36 +00002482 while (!IsEmpty()) {
2483 new_queue.Put(Get());
2484 }
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002485 CommandMessage* array_to_free = messages_;
kasper.lund7276f142008-07-30 08:49:36 +00002486 *this = new_queue;
2487 new_queue.messages_ = array_to_free;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002488 // Make the new_queue empty so that it doesn't call Dispose on any messages.
2489 new_queue.start_ = new_queue.end_;
kasper.lund7276f142008-07-30 08:49:36 +00002490 // Automatic destructor called on new_queue, freeing array_to_free.
2491}
2492
2493
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002494LockingCommandMessageQueue::LockingCommandMessageQueue(int size)
2495 : queue_(size) {
kasper.lund7276f142008-07-30 08:49:36 +00002496 lock_ = OS::CreateMutex();
2497}
2498
2499
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002500LockingCommandMessageQueue::~LockingCommandMessageQueue() {
kasper.lund7276f142008-07-30 08:49:36 +00002501 delete lock_;
2502}
2503
2504
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002505bool LockingCommandMessageQueue::IsEmpty() const {
kasper.lund7276f142008-07-30 08:49:36 +00002506 ScopedLock sl(lock_);
2507 return queue_.IsEmpty();
2508}
2509
2510
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002511CommandMessage LockingCommandMessageQueue::Get() {
kasper.lund7276f142008-07-30 08:49:36 +00002512 ScopedLock sl(lock_);
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002513 CommandMessage result = queue_.Get();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002514 Logger::DebugEvent("Get", result.text());
kasper.lund7276f142008-07-30 08:49:36 +00002515 return result;
2516}
2517
2518
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002519void LockingCommandMessageQueue::Put(const CommandMessage& message) {
kasper.lund7276f142008-07-30 08:49:36 +00002520 ScopedLock sl(lock_);
2521 queue_.Put(message);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002522 Logger::DebugEvent("Put", message.text());
kasper.lund7276f142008-07-30 08:49:36 +00002523}
2524
2525
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002526void LockingCommandMessageQueue::Clear() {
kasper.lund7276f142008-07-30 08:49:36 +00002527 ScopedLock sl(lock_);
2528 queue_.Clear();
2529}
2530
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002531#endif // ENABLE_DEBUGGER_SUPPORT
kasper.lund7276f142008-07-30 08:49:36 +00002532
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002533} } // namespace v8::internal