blob: acdf11d573f139cd6d6b22f93ea028062b8daa62 [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"
34#include "compiler.h"
35#include "debug.h"
36#include "execution.h"
37#include "global-handles.h"
38#include "natives.h"
39#include "stub-cache.h"
kasper.lund7276f142008-07-30 08:49:36 +000040#include "log.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041
42namespace v8 { namespace internal {
43
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044static void PrintLn(v8::Local<v8::Value> value) {
45 v8::Local<v8::String> s = value->ToString();
46 char* data = NewArray<char>(s->Length() + 1);
47 if (data == NULL) {
48 V8::FatalProcessOutOfMemory("PrintLn");
49 return;
50 }
51 s->WriteAscii(data);
52 PrintF("%s\n", data);
53 DeleteArray(data);
54}
55
56
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057static Handle<Code> ComputeCallDebugBreak(int argc) {
58 CALL_HEAP_FUNCTION(StubCache::ComputeCallDebugBreak(argc), Code);
59}
60
61
62static Handle<Code> ComputeCallDebugPrepareStepIn(int argc) {
63 CALL_HEAP_FUNCTION(StubCache::ComputeCallDebugPrepareStepIn(argc), Code);
64}
65
66
67BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info,
68 BreakLocatorType type) {
69 debug_info_ = debug_info;
70 type_ = type;
71 reloc_iterator_ = NULL;
72 reloc_iterator_original_ = NULL;
73 Reset(); // Initialize the rest of the member variables.
74}
75
76
77BreakLocationIterator::~BreakLocationIterator() {
78 ASSERT(reloc_iterator_ != NULL);
79 ASSERT(reloc_iterator_original_ != NULL);
80 delete reloc_iterator_;
81 delete reloc_iterator_original_;
82}
83
84
85void BreakLocationIterator::Next() {
86 AssertNoAllocation nogc;
87 ASSERT(!RinfoDone());
88
89 // Iterate through reloc info for code and original code stopping at each
90 // breakable code target.
91 bool first = break_point_ == -1;
92 while (!RinfoDone()) {
93 if (!first) RinfoNext();
94 first = false;
95 if (RinfoDone()) return;
96
ager@chromium.org236ad962008-09-25 09:45:57 +000097 // Whenever a statement position or (plain) position is passed update the
98 // current value of these.
99 if (RelocInfo::IsPosition(rmode())) {
100 if (RelocInfo::IsStatementPosition(rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101 statement_position_ =
102 rinfo()->data() - debug_info_->shared()->start_position();
103 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000104 // Always update the position as we don't want that to be before the
105 // statement position.
106 position_ = rinfo()->data() - debug_info_->shared()->start_position();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000107 ASSERT(position_ >= 0);
108 ASSERT(statement_position_ >= 0);
109 }
110
111 // Check for breakable code target. Look in the original code as setting
112 // break points can cause the code targets in the running (debugged) code to
113 // be of a different kind than in the original code.
ager@chromium.org236ad962008-09-25 09:45:57 +0000114 if (RelocInfo::IsCodeTarget(rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000115 Address target = original_rinfo()->target_address();
116 Code* code = Debug::GetCodeTarget(target);
ager@chromium.org236ad962008-09-25 09:45:57 +0000117 if (code->is_inline_cache_stub() || RelocInfo::IsConstructCall(rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000118 break_point_++;
119 return;
120 }
121 if (code->kind() == Code::STUB) {
122 if (type_ == ALL_BREAK_LOCATIONS) {
123 if (Debug::IsBreakStub(code)) {
124 break_point_++;
125 return;
126 }
127 } else {
128 ASSERT(type_ == SOURCE_BREAK_LOCATIONS);
129 if (Debug::IsSourceBreakStub(code)) {
130 break_point_++;
131 return;
132 }
133 }
134 }
135 }
136
137 // Check for break at return.
ager@chromium.org236ad962008-09-25 09:45:57 +0000138 if (RelocInfo::IsJSReturn(rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000139 // Set the positions to the end of the function.
140 if (debug_info_->shared()->HasSourceCode()) {
141 position_ = debug_info_->shared()->end_position() -
142 debug_info_->shared()->start_position();
143 } else {
144 position_ = 0;
145 }
146 statement_position_ = position_;
147 break_point_++;
148 return;
149 }
150 }
151}
152
153
154void BreakLocationIterator::Next(int count) {
155 while (count > 0) {
156 Next();
157 count--;
158 }
159}
160
161
162// Find the break point closest to the supplied address.
163void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) {
164 // Run through all break points to locate the one closest to the address.
165 int closest_break_point = 0;
166 int distance = kMaxInt;
167 while (!Done()) {
168 // Check if this break point is closer that what was previously found.
169 if (this->pc() < pc && pc - this->pc() < distance) {
170 closest_break_point = break_point();
171 distance = pc - this->pc();
172 // Check whether we can't get any closer.
173 if (distance == 0) break;
174 }
175 Next();
176 }
177
178 // Move to the break point found.
179 Reset();
180 Next(closest_break_point);
181}
182
183
184// Find the break point closest to the supplied source position.
185void BreakLocationIterator::FindBreakLocationFromPosition(int position) {
186 // Run through all break points to locate the one closest to the source
187 // position.
188 int closest_break_point = 0;
189 int distance = kMaxInt;
190 while (!Done()) {
191 // Check if this break point is closer that what was previously found.
192 if (position <= statement_position() &&
193 statement_position() - position < distance) {
194 closest_break_point = break_point();
195 distance = statement_position() - position;
196 // Check whether we can't get any closer.
197 if (distance == 0) break;
198 }
199 Next();
200 }
201
202 // Move to the break point found.
203 Reset();
204 Next(closest_break_point);
205}
206
207
208void BreakLocationIterator::Reset() {
209 // Create relocation iterators for the two code objects.
210 if (reloc_iterator_ != NULL) delete reloc_iterator_;
211 if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_;
212 reloc_iterator_ = new RelocIterator(debug_info_->code());
213 reloc_iterator_original_ = new RelocIterator(debug_info_->original_code());
214
215 // Position at the first break point.
216 break_point_ = -1;
217 position_ = 1;
218 statement_position_ = 1;
219 Next();
220}
221
222
223bool BreakLocationIterator::Done() const {
224 return RinfoDone();
225}
226
227
228void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) {
229 // If there is not already a real break point here patch code with debug
230 // break.
231 if (!HasBreakPoint()) {
232 SetDebugBreak();
233 }
234 ASSERT(IsDebugBreak());
235 // Set the break point information.
236 DebugInfo::SetBreakPoint(debug_info_, code_position(),
237 position(), statement_position(),
238 break_point_object);
239}
240
241
242void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) {
243 // Clear the break point information.
244 DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object);
245 // If there are no more break points here remove the debug break.
246 if (!HasBreakPoint()) {
247 ClearDebugBreak();
248 ASSERT(!IsDebugBreak());
249 }
250}
251
252
253void BreakLocationIterator::SetOneShot() {
254 // If there is a real break point here no more to do.
255 if (HasBreakPoint()) {
256 ASSERT(IsDebugBreak());
257 return;
258 }
259
260 // Patch code with debug break.
261 SetDebugBreak();
262}
263
264
265void BreakLocationIterator::ClearOneShot() {
266 // If there is a real break point here no more to do.
267 if (HasBreakPoint()) {
268 ASSERT(IsDebugBreak());
269 return;
270 }
271
272 // Patch code removing debug break.
273 ClearDebugBreak();
274 ASSERT(!IsDebugBreak());
275}
276
277
278void BreakLocationIterator::SetDebugBreak() {
279 // If there is already a break point here just return. This might happen if
v8.team.kasperl727e9952008-09-02 14:56:44 +0000280 // the same code is flooded with break points twice. Flooding the same
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000281 // function twice might happen when stepping in a function with an exception
282 // handler as the handler and the function is the same.
283 if (IsDebugBreak()) {
284 return;
285 }
286
ager@chromium.org236ad962008-09-25 09:45:57 +0000287 if (RelocInfo::IsJSReturn(rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000288 // This path is currently only used on IA32 as JSExitFrame on ARM uses a
289 // stub.
290 // Patch the JS frame exit code with a debug break call. See
291 // VisitReturnStatement and ExitJSFrame in codegen-ia32.cc for the
292 // precise return instructions sequence.
293 ASSERT(Debug::kIa32JSReturnSequenceLength >=
294 Debug::kIa32CallInstructionLength);
295 rinfo()->patch_code_with_call(Debug::debug_break_return_entry()->entry(),
296 Debug::kIa32JSReturnSequenceLength - Debug::kIa32CallInstructionLength);
297 } else {
298 // Patch the original code with the current address as the current address
299 // might have changed by the inline caching since the code was copied.
300 original_rinfo()->set_target_address(rinfo()->target_address());
301
302 // Patch the code to invoke the builtin debug break function matching the
303 // calling convention used by the call site.
304 Handle<Code> dbgbrk_code(Debug::FindDebugBreak(rinfo()));
305 rinfo()->set_target_address(dbgbrk_code->entry());
306 }
307 ASSERT(IsDebugBreak());
308}
309
310
311void BreakLocationIterator::ClearDebugBreak() {
ager@chromium.org236ad962008-09-25 09:45:57 +0000312 if (RelocInfo::IsJSReturn(rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000313 // Restore the JS frame exit code.
314 rinfo()->patch_code(original_rinfo()->pc(),
315 Debug::kIa32JSReturnSequenceLength);
316 } else {
317 // Patch the code to the original invoke.
318 rinfo()->set_target_address(original_rinfo()->target_address());
319 }
320 ASSERT(!IsDebugBreak());
321}
322
323
324void BreakLocationIterator::PrepareStepIn() {
325 // Step in can only be prepared if currently positioned on an IC call or
326 // construct call.
327 Address target = rinfo()->target_address();
328 Code* code = Debug::GetCodeTarget(target);
329 if (code->is_call_stub()) {
330 // Step in through IC call is handled by the runtime system. Therefore make
331 // sure that the any current IC is cleared and the runtime system is
332 // called. If the executing code has a debug break at the location change
333 // the call in the original code as it is the code there that will be
334 // executed in place of the debug break call.
335 Handle<Code> stub = ComputeCallDebugPrepareStepIn(code->arguments_count());
336 if (IsDebugBreak()) {
337 original_rinfo()->set_target_address(stub->entry());
338 } else {
339 rinfo()->set_target_address(stub->entry());
340 }
341 } else {
v8.team.kasperl727e9952008-09-02 14:56:44 +0000342 // Step in through constructs call requires no changes to the running code.
ager@chromium.org236ad962008-09-25 09:45:57 +0000343 ASSERT(RelocInfo::IsConstructCall(rmode()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000344 }
345}
346
347
348// Check whether the break point is at a position which will exit the function.
349bool BreakLocationIterator::IsExit() const {
ager@chromium.org236ad962008-09-25 09:45:57 +0000350 return (RelocInfo::IsJSReturn(rmode()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000351}
352
353
354bool BreakLocationIterator::HasBreakPoint() {
355 return debug_info_->HasBreakPoint(code_position());
356}
357
358
359// Check whether there is a debug break at the current position.
360bool BreakLocationIterator::IsDebugBreak() {
ager@chromium.org236ad962008-09-25 09:45:57 +0000361 if (RelocInfo::IsJSReturn(rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362 // This is IA32 specific but works as long as the ARM version
363 // still uses a stub for JSExitFrame.
364 //
365 // TODO(1240753): Make the test architecture independent or split
366 // parts of the debugger into architecture dependent files.
367 return (*(rinfo()->pc()) == 0xE8);
368 } else {
369 return Debug::IsDebugBreak(rinfo()->target_address());
370 }
371}
372
373
374Object* BreakLocationIterator::BreakPointObjects() {
375 return debug_info_->GetBreakPointObjects(code_position());
376}
377
378
379bool BreakLocationIterator::RinfoDone() const {
380 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
381 return reloc_iterator_->done();
382}
383
384
385void BreakLocationIterator::RinfoNext() {
386 reloc_iterator_->next();
387 reloc_iterator_original_->next();
388#ifdef DEBUG
389 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
390 if (!reloc_iterator_->done()) {
391 ASSERT(rmode() == original_rmode());
392 }
393#endif
394}
395
396
397bool Debug::has_break_points_ = false;
398DebugInfoListNode* Debug::debug_info_list_ = NULL;
399
400
401// Threading support.
402void Debug::ThreadInit() {
403 thread_local_.last_step_action_ = StepNone;
ager@chromium.org236ad962008-09-25 09:45:57 +0000404 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000405 thread_local_.step_count_ = 0;
406 thread_local_.last_fp_ = 0;
407 thread_local_.step_into_fp_ = 0;
408 thread_local_.after_break_target_ = 0;
409}
410
411
412JSCallerSavedBuffer Debug::registers_;
413Debug::ThreadLocal Debug::thread_local_;
414
415
416char* Debug::ArchiveDebug(char* storage) {
417 char* to = storage;
418 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
419 to += sizeof(ThreadLocal);
420 memcpy(to, reinterpret_cast<char*>(&registers_), sizeof(registers_));
421 ThreadInit();
422 ASSERT(to <= storage + ArchiveSpacePerThread());
423 return storage + ArchiveSpacePerThread();
424}
425
426
427char* Debug::RestoreDebug(char* storage) {
428 char* from = storage;
429 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
430 from += sizeof(ThreadLocal);
431 memcpy(reinterpret_cast<char*>(&registers_), from, sizeof(registers_));
432 ASSERT(from <= storage + ArchiveSpacePerThread());
433 return storage + ArchiveSpacePerThread();
434}
435
436
437int Debug::ArchiveSpacePerThread() {
438 return sizeof(ThreadLocal) + sizeof(registers_);
439}
440
441
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000442// Default break enabled.
443bool Debug::disable_break_ = false;
444
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000445// Default call debugger on uncaught exception.
446bool Debug::break_on_exception_ = false;
447bool Debug::break_on_uncaught_exception_ = true;
448
449Handle<Context> Debug::debug_context_ = Handle<Context>();
450Code* Debug::debug_break_return_entry_ = NULL;
451Code* Debug::debug_break_return_ = NULL;
452
453
454void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Object> obj, void* data) {
455 DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data);
456 RemoveDebugInfo(node->debug_info());
457#ifdef DEBUG
458 node = Debug::debug_info_list_;
459 while (node != NULL) {
460 ASSERT(node != reinterpret_cast<DebugInfoListNode*>(data));
461 node = node->next();
462 }
463#endif
464}
465
466
467DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
468 // Globalize the request debug info object and make it weak.
469 debug_info_ = Handle<DebugInfo>::cast((GlobalHandles::Create(debug_info)));
470 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(debug_info_.location()),
471 this, Debug::HandleWeakDebugInfo);
472}
473
474
475DebugInfoListNode::~DebugInfoListNode() {
476 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_.location()));
477}
478
479
480void Debug::Setup(bool create_heap_objects) {
481 ThreadInit();
482 if (create_heap_objects) {
483 // Get code to handle entry to debug break on return.
484 debug_break_return_entry_ =
485 Builtins::builtin(Builtins::Return_DebugBreakEntry);
486 ASSERT(debug_break_return_entry_->IsCode());
487
488 // Get code to handle debug break on return.
489 debug_break_return_ =
490 Builtins::builtin(Builtins::Return_DebugBreak);
491 ASSERT(debug_break_return_->IsCode());
492 }
493}
494
495
496bool Debug::CompileDebuggerScript(int index) {
497 HandleScope scope;
498
kasper.lund44510672008-07-25 07:37:58 +0000499 // Bail out if the index is invalid.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000500 if (index == -1) {
501 return false;
502 }
kasper.lund44510672008-07-25 07:37:58 +0000503
504 // Find source and name for the requested script.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000505 Handle<String> source_code = Bootstrapper::NativesSourceLookup(index);
506 Vector<const char> name = Natives::GetScriptName(index);
507 Handle<String> script_name = Factory::NewStringFromAscii(name);
508
509 // Compile the script.
510 bool allow_natives_syntax = FLAG_allow_natives_syntax;
511 FLAG_allow_natives_syntax = true;
512 Handle<JSFunction> boilerplate;
513 boilerplate = Compiler::Compile(source_code, script_name, 0, 0, NULL, NULL);
514 FLAG_allow_natives_syntax = allow_natives_syntax;
515
516 // Silently ignore stack overflows during compilation.
517 if (boilerplate.is_null()) {
518 ASSERT(Top::has_pending_exception());
519 Top::clear_pending_exception();
520 return false;
521 }
522
kasper.lund44510672008-07-25 07:37:58 +0000523 // Execute the boilerplate function in the debugger context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000524 Handle<Context> context = Top::global_context();
kasper.lund44510672008-07-25 07:37:58 +0000525 bool caught_exception = false;
526 Handle<JSFunction> function =
527 Factory::NewFunctionFromBoilerplate(boilerplate, context);
528 Handle<Object> result =
529 Execution::TryCall(function, Handle<Object>(context->global()),
530 0, NULL, &caught_exception);
531
532 // Check for caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000533 if (caught_exception) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000534 Handle<Object> message = MessageHandler::MakeMessageObject(
535 "error_loading_debugger", NULL, HandleVector<Object>(&result, 1),
536 Handle<String>());
537 MessageHandler::ReportMessage(NULL, message);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000538 return false;
539 }
540
kasper.lund44510672008-07-25 07:37:58 +0000541 // Mark this script as native and return successfully.
542 Handle<Script> script(Script::cast(function->shared()->script()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000543 script->set_type(Smi::FromInt(SCRIPT_TYPE_NATIVE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000544 return true;
545}
546
547
548bool Debug::Load() {
549 // Return if debugger is already loaded.
kasper.lund212ac232008-07-16 07:07:30 +0000550 if (IsLoaded()) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000551
kasper.lund44510672008-07-25 07:37:58 +0000552 // Bail out if we're already in the process of compiling the native
553 // JavaScript source code for the debugger.
mads.s.agercbaa0602008-08-14 13:41:48 +0000554 if (Debugger::compiling_natives() || Debugger::is_loading_debugger())
555 return false;
556 Debugger::set_loading_debugger(true);
kasper.lund44510672008-07-25 07:37:58 +0000557
558 // Disable breakpoints and interrupts while compiling and running the
559 // debugger scripts including the context creation code.
560 DisableBreak disable(true);
561 PostponeInterruptsScope postpone;
562
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000563 // Create the debugger context.
564 HandleScope scope;
kasper.lund44510672008-07-25 07:37:58 +0000565 Handle<Context> context =
566 Bootstrapper::CreateEnvironment(Handle<Object>::null(),
567 v8::Handle<ObjectTemplate>(),
568 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000569
kasper.lund44510672008-07-25 07:37:58 +0000570 // Use the debugger context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000571 SaveContext save;
kasper.lund44510672008-07-25 07:37:58 +0000572 Top::set_context(*context);
573 Top::set_security_context(*context);
574
575 // Expose the builtins object in the debugger context.
576 Handle<String> key = Factory::LookupAsciiSymbol("builtins");
577 Handle<GlobalObject> global = Handle<GlobalObject>(context->global());
578 SetProperty(global, key, Handle<Object>(global->builtins()), NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000579
580 // Compile the JavaScript for the debugger in the debugger context.
581 Debugger::set_compiling_natives(true);
kasper.lund44510672008-07-25 07:37:58 +0000582 bool caught_exception =
583 !CompileDebuggerScript(Natives::GetIndex("mirror")) ||
584 !CompileDebuggerScript(Natives::GetIndex("debug"));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000585 Debugger::set_compiling_natives(false);
586
mads.s.agercbaa0602008-08-14 13:41:48 +0000587 // Make sure we mark the debugger as not loading before we might
588 // return.
589 Debugger::set_loading_debugger(false);
590
kasper.lund44510672008-07-25 07:37:58 +0000591 // Check for caught exceptions.
592 if (caught_exception) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000593
594 // Debugger loaded.
kasper.lund44510672008-07-25 07:37:58 +0000595 debug_context_ = Handle<Context>::cast(GlobalHandles::Create(*context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000596 return true;
597}
598
599
600void Debug::Unload() {
601 // Return debugger is not loaded.
602 if (!IsLoaded()) {
603 return;
604 }
605
606 // Clear debugger context global handle.
607 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_context_.location()));
608 debug_context_ = Handle<Context>();
609}
610
611
612void Debug::Iterate(ObjectVisitor* v) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000613#define VISIT(field) v->VisitPointer(bit_cast<Object**, Code**>(&(field)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000614 VISIT(debug_break_return_entry_);
615 VISIT(debug_break_return_);
616#undef VISIT
617}
618
619
620Object* Debug::Break(Arguments args) {
621 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +0000622 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000624 // Get the top-most JavaScript frame.
625 JavaScriptFrameIterator it;
626 JavaScriptFrame* frame = it.frame();
627
628 // Just continue if breaks are disabled or debugger cannot be loaded.
629 if (disable_break() || !Load()) {
630 SetAfterBreakTarget(frame);
mads.s.ager31e71382008-08-13 09:32:07 +0000631 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000632 }
633
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000634 // Enter the debugger.
635 EnterDebugger debugger;
636 if (debugger.FailedToEnter()) {
637 return Heap::undefined_value();
638 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000639
kasper.lund44510672008-07-25 07:37:58 +0000640 // Postpone interrupt during breakpoint processing.
641 PostponeInterruptsScope postpone;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000642
643 // Get the debug info (create it if it does not exist).
644 Handle<SharedFunctionInfo> shared =
645 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
646 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
647
648 // Find the break point where execution has stopped.
649 BreakLocationIterator break_location_iterator(debug_info,
650 ALL_BREAK_LOCATIONS);
651 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
652
653 // Check whether step next reached a new statement.
654 if (!StepNextContinue(&break_location_iterator, frame)) {
655 // Decrease steps left if performing multiple steps.
656 if (thread_local_.step_count_ > 0) {
657 thread_local_.step_count_--;
658 }
659 }
660
661 // If there is one or more real break points check whether any of these are
662 // triggered.
663 Handle<Object> break_points_hit(Heap::undefined_value());
664 if (break_location_iterator.HasBreakPoint()) {
665 Handle<Object> break_point_objects =
666 Handle<Object>(break_location_iterator.BreakPointObjects());
667 break_points_hit = CheckBreakPoints(break_point_objects);
668 }
669
670 // Notify debugger if a real break point is triggered or if performing single
671 // stepping with no more steps to perform. Otherwise do another step.
672 if (!break_points_hit->IsUndefined() ||
673 (thread_local_.last_step_action_ != StepNone &&
674 thread_local_.step_count_ == 0)) {
675 // Clear all current stepping setup.
676 ClearStepping();
677
678 // Notify the debug event listeners.
679 Debugger::OnDebugBreak(break_points_hit);
680 } else if (thread_local_.last_step_action_ != StepNone) {
681 // Hold on to last step action as it is cleared by the call to
682 // ClearStepping.
683 StepAction step_action = thread_local_.last_step_action_;
684 int step_count = thread_local_.step_count_;
685
686 // Clear all current stepping setup.
687 ClearStepping();
688
689 // Set up for the remaining steps.
690 PrepareStep(step_action, step_count);
691 }
692
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000693 // Install jump to the call address which was overwritten.
694 SetAfterBreakTarget(frame);
695
mads.s.ager31e71382008-08-13 09:32:07 +0000696 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000697}
698
699
700// Check the break point objects for whether one or more are actually
701// triggered. This function returns a JSArray with the break point objects
702// which is triggered.
703Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) {
704 int break_points_hit_count = 0;
705 Handle<JSArray> break_points_hit = Factory::NewJSArray(1);
706
v8.team.kasperl727e9952008-09-02 14:56:44 +0000707 // If there are multiple break points they are in a FixedArray.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000708 ASSERT(!break_point_objects->IsUndefined());
709 if (break_point_objects->IsFixedArray()) {
710 Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
711 for (int i = 0; i < array->length(); i++) {
712 Handle<Object> o(array->get(i));
713 if (CheckBreakPoint(o)) {
714 break_points_hit->SetElement(break_points_hit_count++, *o);
715 }
716 }
717 } else {
718 if (CheckBreakPoint(break_point_objects)) {
719 break_points_hit->SetElement(break_points_hit_count++,
720 *break_point_objects);
721 }
722 }
723
724 // Return undefined if no break points where triggered.
725 if (break_points_hit_count == 0) {
726 return Factory::undefined_value();
727 }
728 return break_points_hit;
729}
730
731
732// Check whether a single break point object is triggered.
733bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
734 // Ignore check if break point object is not a JSObject.
735 if (!break_point_object->IsJSObject()) return true;
736
737 // Get the function CheckBreakPoint (defined in debug.js).
738 Handle<JSFunction> check_break_point =
739 Handle<JSFunction>(JSFunction::cast(
740 debug_context()->global()->GetProperty(
741 *Factory::LookupAsciiSymbol("IsBreakPointTriggered"))));
742
743 // Get the break id as an object.
744 Handle<Object> break_id = Factory::NewNumberFromInt(Top::break_id());
745
746 // Call HandleBreakPointx.
747 bool caught_exception = false;
748 const int argc = 2;
749 Object** argv[argc] = {
750 break_id.location(),
751 reinterpret_cast<Object**>(break_point_object.location())
752 };
753 Handle<Object> result = Execution::TryCall(check_break_point,
754 Top::builtins(), argc, argv,
755 &caught_exception);
756
757 // If exception or non boolean result handle as not triggered
758 if (caught_exception || !result->IsBoolean()) {
759 return false;
760 }
761
762 // Return whether the break point is triggered.
763 return *result == Heap::true_value();
764}
765
766
767// Check whether the function has debug information.
768bool Debug::HasDebugInfo(Handle<SharedFunctionInfo> shared) {
769 return !shared->debug_info()->IsUndefined();
770}
771
772
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000773// Return the debug info for this function. EnsureDebugInfo must be called
774// prior to ensure the debug info has been generated for shared.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000775Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000776 ASSERT(HasDebugInfo(shared));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000777 return Handle<DebugInfo>(DebugInfo::cast(shared->debug_info()));
778}
779
780
781void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared,
782 int source_position,
783 Handle<Object> break_point_object) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000784 if (!EnsureDebugInfo(shared)) {
785 // Return if retrieving debug info failed.
786 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000787 }
788
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000789 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000790 // Source positions starts with zero.
791 ASSERT(source_position >= 0);
792
793 // Find the break point and change it.
794 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
795 it.FindBreakLocationFromPosition(source_position);
796 it.SetBreakPoint(break_point_object);
797
798 // At least one active break point now.
799 ASSERT(debug_info->GetBreakPointCount() > 0);
800}
801
802
803void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
804 DebugInfoListNode* node = debug_info_list_;
805 while (node != NULL) {
806 Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(),
807 break_point_object);
808 if (!result->IsUndefined()) {
809 // Get information in the break point.
810 BreakPointInfo* break_point_info = BreakPointInfo::cast(result);
811 Handle<DebugInfo> debug_info = node->debug_info();
812 Handle<SharedFunctionInfo> shared(debug_info->shared());
813 int source_position = break_point_info->statement_position()->value();
814
815 // Source positions starts with zero.
816 ASSERT(source_position >= 0);
817
818 // Find the break point and clear it.
819 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
820 it.FindBreakLocationFromPosition(source_position);
821 it.ClearBreakPoint(break_point_object);
822
823 // If there are no more break points left remove the debug info for this
824 // function.
825 if (debug_info->GetBreakPointCount() == 0) {
826 RemoveDebugInfo(debug_info);
827 }
828
829 return;
830 }
831 node = node->next();
832 }
833}
834
835
836void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000837 // Make sure the function has setup the debug info.
838 if (!EnsureDebugInfo(shared)) {
839 // Return if we failed to retrieve the debug info.
840 return;
841 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000842
843 // Flood the function with break points.
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000844 BreakLocationIterator it(GetDebugInfo(shared), ALL_BREAK_LOCATIONS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000845 while (!it.Done()) {
846 it.SetOneShot();
847 it.Next();
848 }
849}
850
851
852void Debug::FloodHandlerWithOneShot() {
853 StackFrame::Id id = Top::break_frame_id();
854 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) {
855 JavaScriptFrame* frame = it.frame();
856 if (frame->HasHandler()) {
857 Handle<SharedFunctionInfo> shared =
858 Handle<SharedFunctionInfo>(
859 JSFunction::cast(frame->function())->shared());
860 // Flood the function with the catch block with break points
861 FloodWithOneShot(shared);
862 return;
863 }
864 }
865}
866
867
868void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
869 if (type == BreakUncaughtException) {
870 break_on_uncaught_exception_ = enable;
871 } else {
872 break_on_exception_ = enable;
873 }
874}
875
876
877void Debug::PrepareStep(StepAction step_action, int step_count) {
878 HandleScope scope;
879 ASSERT(Debug::InDebugger());
880
881 // Remember this step action and count.
882 thread_local_.last_step_action_ = step_action;
883 thread_local_.step_count_ = step_count;
884
885 // Get the frame where the execution has stopped and skip the debug frame if
886 // any. The debug frame will only be present if execution was stopped due to
887 // hitting a break point. In other situations (e.g. unhandled exception) the
888 // debug frame is not present.
889 StackFrame::Id id = Top::break_frame_id();
890 JavaScriptFrameIterator frames_it(id);
891 JavaScriptFrame* frame = frames_it.frame();
892
893 // First of all ensure there is one-shot break points in the top handler
894 // if any.
895 FloodHandlerWithOneShot();
896
897 // If the function on the top frame is unresolved perform step out. This will
898 // be the case when calling unknown functions and having the debugger stopped
899 // in an unhandled exception.
900 if (!frame->function()->IsJSFunction()) {
901 // Step out: Find the calling JavaScript frame and flood it with
902 // breakpoints.
903 frames_it.Advance();
904 // Fill the function to return to with one-shot break points.
905 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
906 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
907 return;
908 }
909
910 // Get the debug info (create it if it does not exist).
911 Handle<SharedFunctionInfo> shared =
912 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000913 if (!EnsureDebugInfo(shared)) {
914 // Return if ensuring debug info failed.
915 return;
916 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000917 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
918
919 // Find the break location where execution has stopped.
920 BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS);
921 it.FindBreakLocationFromAddress(frame->pc());
922
923 // Compute whether or not the target is a call target.
924 bool is_call_target = false;
ager@chromium.org236ad962008-09-25 09:45:57 +0000925 if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926 Address target = it.rinfo()->target_address();
927 Code* code = Debug::GetCodeTarget(target);
928 if (code->is_call_stub()) is_call_target = true;
929 }
930
v8.team.kasperl727e9952008-09-02 14:56:44 +0000931 // If this is the last break code target step out is the only possibility.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000932 if (it.IsExit() || step_action == StepOut) {
933 // Step out: If there is a JavaScript caller frame, we need to
934 // flood it with breakpoints.
935 frames_it.Advance();
936 if (!frames_it.done()) {
937 // Fill the function to return to with one-shot break points.
938 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
939 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
940 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000941 } else if (!(is_call_target || RelocInfo::IsConstructCall(it.rmode())) ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000942 step_action == StepNext || step_action == StepMin) {
943 // Step next or step min.
944
945 // Fill the current function with one-shot break points.
946 FloodWithOneShot(shared);
947
948 // Remember source position and frame to handle step next.
949 thread_local_.last_statement_position_ =
950 debug_info->code()->SourceStatementPosition(frame->pc());
951 thread_local_.last_fp_ = frame->fp();
952 } else {
953 // Fill the current function with one-shot break points even for step in on
954 // a call target as the function called might be a native function for
955 // which step in will not stop.
956 FloodWithOneShot(shared);
957
958 // Step in or Step in min
959 it.PrepareStepIn();
960 ActivateStepIn(frame);
961 }
962}
963
964
965// Check whether the current debug break should be reported to the debugger. It
966// is used to have step next and step in only report break back to the debugger
967// if on a different frame or in a different statement. In some situations
968// there will be several break points in the same statement when the code is
v8.team.kasperl727e9952008-09-02 14:56:44 +0000969// flooded with one-shot break points. This function helps to perform several
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000970// steps before reporting break back to the debugger.
971bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
972 JavaScriptFrame* frame) {
973 // If the step last action was step next or step in make sure that a new
974 // statement is hit.
975 if (thread_local_.last_step_action_ == StepNext ||
976 thread_local_.last_step_action_ == StepIn) {
977 // Never continue if returning from function.
978 if (break_location_iterator->IsExit()) return false;
979
980 // Continue if we are still on the same frame and in the same statement.
981 int current_statement_position =
982 break_location_iterator->code()->SourceStatementPosition(frame->pc());
983 return thread_local_.last_fp_ == frame->fp() &&
ager@chromium.org236ad962008-09-25 09:45:57 +0000984 thread_local_.last_statement_position_ == current_statement_position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000985 }
986
987 // No step next action - don't continue.
988 return false;
989}
990
991
992// Check whether the code object at the specified address is a debug break code
993// object.
994bool Debug::IsDebugBreak(Address addr) {
995 Code* code = GetCodeTarget(addr);
kasper.lund7276f142008-07-30 08:49:36 +0000996 return code->ic_state() == DEBUG_BREAK;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000997}
998
999
1000// Check whether a code stub with the specified major key is a possible break
1001// point location when looking for source break locations.
1002bool Debug::IsSourceBreakStub(Code* code) {
1003 CodeStub::Major major_key = code->major_key();
1004 return major_key == CodeStub::CallFunction;
1005}
1006
1007
1008// Check whether a code stub with the specified major key is a possible break
1009// location.
1010bool Debug::IsBreakStub(Code* code) {
1011 CodeStub::Major major_key = code->major_key();
1012 return major_key == CodeStub::CallFunction ||
1013 major_key == CodeStub::StackCheck;
1014}
1015
1016
1017// Find the builtin to use for invoking the debug break
1018Handle<Code> Debug::FindDebugBreak(RelocInfo* rinfo) {
1019 // Find the builtin debug break function matching the calling convention
1020 // used by the call site.
ager@chromium.org236ad962008-09-25 09:45:57 +00001021 RelocInfo::Mode mode = rinfo->rmode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001022
ager@chromium.org236ad962008-09-25 09:45:57 +00001023 if (RelocInfo::IsCodeTarget(mode)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001024 Address target = rinfo->target_address();
1025 Code* code = Debug::GetCodeTarget(target);
1026 if (code->is_inline_cache_stub()) {
1027 if (code->is_call_stub()) {
1028 return ComputeCallDebugBreak(code->arguments_count());
1029 }
1030 if (code->is_load_stub()) {
1031 return Handle<Code>(Builtins::builtin(Builtins::LoadIC_DebugBreak));
1032 }
1033 if (code->is_store_stub()) {
1034 return Handle<Code>(Builtins::builtin(Builtins::StoreIC_DebugBreak));
1035 }
1036 if (code->is_keyed_load_stub()) {
1037 Handle<Code> result =
1038 Handle<Code>(Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak));
1039 return result;
1040 }
1041 if (code->is_keyed_store_stub()) {
1042 Handle<Code> result =
1043 Handle<Code>(Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak));
1044 return result;
1045 }
1046 }
ager@chromium.org236ad962008-09-25 09:45:57 +00001047 if (RelocInfo::IsConstructCall(mode)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001048 Handle<Code> result =
1049 Handle<Code>(Builtins::builtin(Builtins::ConstructCall_DebugBreak));
1050 return result;
1051 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001052 if (code->kind() == Code::STUB) {
1053 ASSERT(code->major_key() == CodeStub::CallFunction ||
1054 code->major_key() == CodeStub::StackCheck);
1055 Handle<Code> result =
1056 Handle<Code>(Builtins::builtin(Builtins::StubNoRegisters_DebugBreak));
1057 return result;
1058 }
1059 }
1060
1061 UNREACHABLE();
1062 return Handle<Code>::null();
1063}
1064
1065
1066// Simple function for returning the source positions for active break points.
1067Handle<Object> Debug::GetSourceBreakLocations(
1068 Handle<SharedFunctionInfo> shared) {
1069 if (!HasDebugInfo(shared)) return Handle<Object>(Heap::undefined_value());
1070 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1071 if (debug_info->GetBreakPointCount() == 0) {
1072 return Handle<Object>(Heap::undefined_value());
1073 }
1074 Handle<FixedArray> locations =
1075 Factory::NewFixedArray(debug_info->GetBreakPointCount());
1076 int count = 0;
1077 for (int i = 0; i < debug_info->break_points()->length(); i++) {
1078 if (!debug_info->break_points()->get(i)->IsUndefined()) {
1079 BreakPointInfo* break_point_info =
1080 BreakPointInfo::cast(debug_info->break_points()->get(i));
1081 if (break_point_info->GetBreakPointCount() > 0) {
1082 locations->set(count++, break_point_info->statement_position());
1083 }
1084 }
1085 }
1086 return locations;
1087}
1088
1089
1090void Debug::ClearStepping() {
1091 // Clear the various stepping setup.
1092 ClearOneShot();
1093 ClearStepIn();
1094 ClearStepNext();
1095
1096 // Clear multiple step counter.
1097 thread_local_.step_count_ = 0;
1098}
1099
1100// Clears all the one-shot break points that are currently set. Normally this
1101// function is called each time a break point is hit as one shot break points
1102// are used to support stepping.
1103void Debug::ClearOneShot() {
1104 // The current implementation just runs through all the breakpoints. When the
v8.team.kasperl727e9952008-09-02 14:56:44 +00001105 // last break point for a function is removed that function is automatically
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001106 // removed from the list.
1107
1108 DebugInfoListNode* node = debug_info_list_;
1109 while (node != NULL) {
1110 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1111 while (!it.Done()) {
1112 it.ClearOneShot();
1113 it.Next();
1114 }
1115 node = node->next();
1116 }
1117}
1118
1119
1120void Debug::ActivateStepIn(StackFrame* frame) {
1121 thread_local_.step_into_fp_ = frame->fp();
1122}
1123
1124
1125void Debug::ClearStepIn() {
1126 thread_local_.step_into_fp_ = 0;
1127}
1128
1129
1130void Debug::ClearStepNext() {
1131 thread_local_.last_step_action_ = StepNone;
ager@chromium.org236ad962008-09-25 09:45:57 +00001132 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001133 thread_local_.last_fp_ = 0;
1134}
1135
1136
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001137bool Debug::EnsureCompiled(Handle<SharedFunctionInfo> shared) {
1138 if (shared->is_compiled()) return true;
1139 return CompileLazyShared(shared, CLEAR_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001140}
1141
1142
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001143// Ensures the debug information is present for shared.
1144bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
1145 // Return if we already have the debug info for shared.
1146 if (HasDebugInfo(shared)) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001147
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001148 // Ensure shared in compiled. Return false if this failed.
1149 if (!EnsureCompiled(shared)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001150
1151 // Create the debug info object.
v8.team.kasperl727e9952008-09-02 14:56:44 +00001152 Handle<DebugInfo> debug_info = Factory::NewDebugInfo(shared);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001153
1154 // Add debug info to the list.
1155 DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
1156 node->set_next(debug_info_list_);
1157 debug_info_list_ = node;
1158
1159 // Now there is at least one break point.
1160 has_break_points_ = true;
1161
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001162 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001163}
1164
1165
1166void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
1167 ASSERT(debug_info_list_ != NULL);
1168 // Run through the debug info objects to find this one and remove it.
1169 DebugInfoListNode* prev = NULL;
1170 DebugInfoListNode* current = debug_info_list_;
1171 while (current != NULL) {
1172 if (*current->debug_info() == *debug_info) {
1173 // Unlink from list. If prev is NULL we are looking at the first element.
1174 if (prev == NULL) {
1175 debug_info_list_ = current->next();
1176 } else {
1177 prev->set_next(current->next());
1178 }
1179 current->debug_info()->shared()->set_debug_info(Heap::undefined_value());
1180 delete current;
1181
1182 // If there are no more debug info objects there are not more break
1183 // points.
1184 has_break_points_ = debug_info_list_ != NULL;
1185
1186 return;
1187 }
1188 // Move to next in list.
1189 prev = current;
1190 current = current->next();
1191 }
1192 UNREACHABLE();
1193}
1194
1195
1196void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
1197 // Get the executing function in which the debug break occurred.
1198 Handle<SharedFunctionInfo> shared =
1199 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001200 if (!EnsureDebugInfo(shared)) {
1201 // Return if we failed to retrieve the debug info.
1202 return;
1203 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001204 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1205 Handle<Code> code(debug_info->code());
1206 Handle<Code> original_code(debug_info->original_code());
1207#ifdef DEBUG
1208 // Get the code which is actually executing.
1209 Handle<Code> frame_code(frame->FindCode());
1210 ASSERT(frame_code.is_identical_to(code));
1211#endif
1212
1213 // Find the call address in the running code. This address holds the call to
1214 // either a DebugBreakXXX or to the debug break return entry code if the
1215 // break point is still active after processing the break point.
1216 Address addr = frame->pc() - Assembler::kTargetAddrToReturnAddrDist;
1217
1218 // Check if the location is at JS exit.
1219 bool at_js_exit = false;
1220 RelocIterator it(debug_info->code());
1221 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001222 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001223 at_js_exit = it.rinfo()->pc() == addr - 1;
1224 }
1225 it.next();
1226 }
1227
1228 // Handle the jump to continue execution after break point depending on the
1229 // break location.
1230 if (at_js_exit) {
1231 // First check if the call in the code is still the debug break return
1232 // entry code. If it is the break point is still active. If not the break
1233 // point was removed during break point processing.
1234 if (Assembler::target_address_at(addr) ==
1235 debug_break_return_entry()->entry()) {
1236 // Break point still active. Jump to the corresponding place in the
1237 // original code.
1238 addr += original_code->instruction_start() - code->instruction_start();
1239 }
1240
1241 // Move one byte back to where the call instruction was placed.
1242 thread_local_.after_break_target_ = addr - 1;
1243 } else {
1244 // Check if there still is a debug break call at the target address. If the
1245 // break point has been removed it will have disappeared. If it have
1246 // disappeared don't try to look in the original code as the running code
1247 // will have the right address. This takes care of the case where the last
1248 // break point is removed from the function and therefore no "original code"
1249 // is available. If the debug break call is still there find the address in
1250 // the original code.
1251 if (IsDebugBreak(Assembler::target_address_at(addr))) {
1252 // If the break point is still there find the call address which was
1253 // overwritten in the original code by the call to DebugBreakXXX.
1254
1255 // Find the corresponding address in the original code.
1256 addr += original_code->instruction_start() - code->instruction_start();
1257 }
1258
1259 // Install jump to the call address in the original code. This will be the
1260 // call which was overwritten by the call to DebugBreakXXX.
1261 thread_local_.after_break_target_ = Assembler::target_address_at(addr);
1262 }
1263}
1264
1265
1266Code* Debug::GetCodeTarget(Address target) {
1267 // Maybe this can be refactored with the stuff in ic-inl.h?
1268 Code* result =
1269 Code::cast(HeapObject::FromAddress(target - Code::kHeaderSize));
1270 return result;
1271}
1272
1273
1274bool Debug::IsDebugGlobal(GlobalObject* global) {
1275 return IsLoaded() && global == Debug::debug_context()->global();
1276}
1277
1278
1279bool Debugger::debugger_active_ = false;
1280bool Debugger::compiling_natives_ = false;
mads.s.agercbaa0602008-08-14 13:41:48 +00001281bool Debugger::is_loading_debugger_ = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001282DebugMessageThread* Debugger::message_thread_ = NULL;
1283v8::DebugMessageHandler Debugger::debug_message_handler_ = NULL;
1284void* Debugger::debug_message_handler_data_ = NULL;
1285
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001286
1287Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
1288 int argc, Object*** argv,
1289 bool* caught_exception) {
1290 ASSERT(Top::context() == *Debug::debug_context());
1291
1292 // Create the execution state object.
1293 Handle<String> constructor_str = Factory::LookupSymbol(constructor_name);
1294 Handle<Object> constructor(Top::global()->GetProperty(*constructor_str));
1295 ASSERT(constructor->IsJSFunction());
1296 if (!constructor->IsJSFunction()) {
1297 *caught_exception = true;
1298 return Factory::undefined_value();
1299 }
1300 Handle<Object> js_object = Execution::TryCall(
1301 Handle<JSFunction>::cast(constructor),
1302 Handle<JSObject>(Debug::debug_context()->global()), argc, argv,
1303 caught_exception);
1304 return js_object;
1305}
1306
1307
1308Handle<Object> Debugger::MakeExecutionState(bool* caught_exception) {
1309 // Create the execution state object.
1310 Handle<Object> break_id = Factory::NewNumberFromInt(Top::break_id());
1311 const int argc = 1;
1312 Object** argv[argc] = { break_id.location() };
1313 return MakeJSObject(CStrVector("MakeExecutionState"),
1314 argc, argv, caught_exception);
1315}
1316
1317
1318Handle<Object> Debugger::MakeBreakEvent(Handle<Object> exec_state,
1319 Handle<Object> break_points_hit,
1320 bool* caught_exception) {
1321 // Create the new break event object.
1322 const int argc = 2;
1323 Object** argv[argc] = { exec_state.location(),
1324 break_points_hit.location() };
1325 return MakeJSObject(CStrVector("MakeBreakEvent"),
1326 argc,
1327 argv,
1328 caught_exception);
1329}
1330
1331
1332Handle<Object> Debugger::MakeExceptionEvent(Handle<Object> exec_state,
1333 Handle<Object> exception,
1334 bool uncaught,
1335 bool* caught_exception) {
1336 // Create the new exception event object.
1337 const int argc = 3;
1338 Object** argv[argc] = { exec_state.location(),
1339 exception.location(),
1340 uncaught ? Factory::true_value().location() :
1341 Factory::false_value().location()};
1342 return MakeJSObject(CStrVector("MakeExceptionEvent"),
1343 argc, argv, caught_exception);
1344}
1345
1346
1347Handle<Object> Debugger::MakeNewFunctionEvent(Handle<Object> function,
1348 bool* caught_exception) {
1349 // Create the new function event object.
1350 const int argc = 1;
1351 Object** argv[argc] = { function.location() };
1352 return MakeJSObject(CStrVector("MakeNewFunctionEvent"),
1353 argc, argv, caught_exception);
1354}
1355
1356
1357Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
1358 Handle<Object> script_function,
1359 bool* caught_exception) {
1360 // Create the compile event object.
1361 Handle<Object> exec_state = MakeExecutionState(caught_exception);
1362 Handle<Object> script_source(script->source());
1363 Handle<Object> script_name(script->name());
1364 const int argc = 3;
1365 Object** argv[argc] = { script_source.location(),
1366 script_name.location(),
1367 script_function.location() };
1368 return MakeJSObject(CStrVector("MakeCompileEvent"),
1369 argc,
1370 argv,
1371 caught_exception);
1372}
1373
1374
1375Handle<String> Debugger::ProcessRequest(Handle<Object> exec_state,
1376 Handle<Object> request,
1377 bool stopped) {
1378 // Get the function ProcessDebugRequest (declared in debug.js).
1379 Handle<JSFunction> process_denbug_request =
1380 Handle<JSFunction>(JSFunction::cast(
1381 Debug::debug_context()->global()->GetProperty(
1382 *Factory::LookupAsciiSymbol("ProcessDebugRequest"))));
1383
1384 // Call ProcessDebugRequest expect String result. The ProcessDebugRequest
1385 // will never throw an exception (see debug.js).
kasper.lund212ac232008-07-16 07:07:30 +00001386 bool caught_exception;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001387 const int argc = 3;
1388 Object** argv[argc] = { exec_state.location(),
1389 request.location(),
1390 stopped ? Factory::true_value().location() :
1391 Factory::false_value().location()};
kasper.lund212ac232008-07-16 07:07:30 +00001392 Handle<Object> result = Execution::TryCall(process_denbug_request,
1393 Factory::undefined_value(),
1394 argc, argv,
1395 &caught_exception);
1396 if (caught_exception) {
1397 return Factory::empty_symbol();
1398 }
1399
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001400 return Handle<String>::cast(result);
1401}
1402
1403
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404void Debugger::OnException(Handle<Object> exception, bool uncaught) {
1405 HandleScope scope;
1406
1407 // Bail out based on state or if there is no listener for this event
1408 if (Debug::InDebugger()) return;
1409 if (!Debugger::EventActive(v8::Exception)) return;
1410
1411 // Bail out if exception breaks are not active
1412 if (uncaught) {
1413 // Uncaught exceptions are reported by either flags.
1414 if (!(Debug::break_on_uncaught_exception() ||
1415 Debug::break_on_exception())) return;
1416 } else {
1417 // Caught exceptions are reported is activated.
1418 if (!Debug::break_on_exception()) return;
1419 }
1420
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001421 // Enter the debugger.
1422 EnterDebugger debugger;
1423 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001424
1425 // Clear all current stepping setup.
1426 Debug::ClearStepping();
1427 // Create the event data object.
1428 bool caught_exception = false;
1429 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
1430 Handle<Object> event_data;
1431 if (!caught_exception) {
1432 event_data = MakeExceptionEvent(exec_state, exception, uncaught,
1433 &caught_exception);
1434 }
1435 // Bail out and don't call debugger if exception.
1436 if (caught_exception) {
1437 return;
1438 }
1439
1440 // Process debug event
1441 ProcessDebugEvent(v8::Exception, event_data);
1442 // Return to continue execution from where the exception was thrown.
1443}
1444
1445
1446void Debugger::OnDebugBreak(Handle<Object> break_points_hit) {
1447 HandleScope scope;
1448
kasper.lund212ac232008-07-16 07:07:30 +00001449 // Debugger has already been entered by caller.
1450 ASSERT(Top::context() == *Debug::debug_context());
1451
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001452 // Bail out if there is no listener for this event
1453 if (!Debugger::EventActive(v8::Break)) return;
1454
1455 // Debugger must be entered in advance.
1456 ASSERT(Top::context() == *Debug::debug_context());
1457
1458 // Create the event data object.
1459 bool caught_exception = false;
1460 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
1461 Handle<Object> event_data;
1462 if (!caught_exception) {
1463 event_data = MakeBreakEvent(exec_state, break_points_hit,
1464 &caught_exception);
1465 }
1466 // Bail out and don't call debugger if exception.
1467 if (caught_exception) {
1468 return;
1469 }
1470
1471 // Process debug event
1472 ProcessDebugEvent(v8::Break, event_data);
1473}
1474
1475
1476void Debugger::OnBeforeCompile(Handle<Script> script) {
1477 HandleScope scope;
1478
1479 // Bail out based on state or if there is no listener for this event
1480 if (Debug::InDebugger()) return;
1481 if (compiling_natives()) return;
1482 if (!EventActive(v8::BeforeCompile)) return;
1483
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001484 // Enter the debugger.
1485 EnterDebugger debugger;
1486 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001487
1488 // Create the event data object.
1489 bool caught_exception = false;
1490 Handle<Object> event_data = MakeCompileEvent(script,
1491 Factory::undefined_value(),
1492 &caught_exception);
1493 // Bail out and don't call debugger if exception.
1494 if (caught_exception) {
1495 return;
1496 }
1497
1498 // Process debug event
1499 ProcessDebugEvent(v8::BeforeCompile, event_data);
1500}
1501
1502
1503// Handle debugger actions when a new script is compiled.
1504void Debugger::OnAfterCompile(Handle<Script> script, Handle<JSFunction> fun) {
kasper.lund212ac232008-07-16 07:07:30 +00001505 HandleScope scope;
1506
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001507 // No compile events while compiling natives.
1508 if (compiling_natives()) return;
1509
1510 // No more to do if not debugging.
1511 if (!debugger_active()) return;
1512
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001513 // Enter the debugger.
1514 EnterDebugger debugger;
1515 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001516
1517 // If debugging there might be script break points registered for this
1518 // script. Make sure that these break points are set.
1519
1520 // Get the function UpdateScriptBreakPoints (defined in debug-delay.js).
1521 Handle<Object> update_script_break_points =
1522 Handle<Object>(Debug::debug_context()->global()->GetProperty(
1523 *Factory::LookupAsciiSymbol("UpdateScriptBreakPoints")));
1524 if (!update_script_break_points->IsJSFunction()) {
1525 return;
1526 }
1527 ASSERT(update_script_break_points->IsJSFunction());
1528
1529 // Wrap the script object in a proper JS object before passing it
1530 // to JavaScript.
1531 Handle<JSValue> wrapper = GetScriptWrapper(script);
1532
1533 // Call UpdateScriptBreakPoints expect no exceptions.
kasper.lund212ac232008-07-16 07:07:30 +00001534 bool caught_exception = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535 const int argc = 1;
1536 Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) };
1537 Handle<Object> result = Execution::TryCall(
1538 Handle<JSFunction>::cast(update_script_break_points),
1539 Top::builtins(), argc, argv,
1540 &caught_exception);
1541 if (caught_exception) {
1542 return;
1543 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001544 // Bail out based on state or if there is no listener for this event
1545 if (Debug::InDebugger()) return;
1546 if (!Debugger::EventActive(v8::AfterCompile)) return;
1547
1548 // Create the compile state object.
1549 Handle<Object> event_data = MakeCompileEvent(script,
1550 Factory::undefined_value(),
1551 &caught_exception);
1552 // Bail out and don't call debugger if exception.
1553 if (caught_exception) {
1554 return;
1555 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556 // Process debug event
1557 ProcessDebugEvent(v8::AfterCompile, event_data);
1558}
1559
1560
1561void Debugger::OnNewFunction(Handle<JSFunction> function) {
1562 return;
1563 HandleScope scope;
1564
1565 // Bail out based on state or if there is no listener for this event
1566 if (Debug::InDebugger()) return;
1567 if (compiling_natives()) return;
1568 if (!Debugger::EventActive(v8::NewFunction)) return;
1569
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001570 // Enter the debugger.
1571 EnterDebugger debugger;
1572 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001573
1574 // Create the event object.
1575 bool caught_exception = false;
1576 Handle<Object> event_data = MakeNewFunctionEvent(function, &caught_exception);
1577 // Bail out and don't call debugger if exception.
1578 if (caught_exception) {
1579 return;
1580 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581 // Process debug event.
1582 ProcessDebugEvent(v8::NewFunction, event_data);
1583}
1584
1585
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001586void Debugger::ProcessDebugEvent(v8::DebugEvent event,
1587 Handle<Object> event_data) {
1588 // Create the execution state.
1589 bool caught_exception = false;
1590 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
1591 if (caught_exception) {
1592 return;
1593 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001594 // First notify the builtin debugger.
1595 if (message_thread_ != NULL) {
1596 message_thread_->DebugEvent(event, exec_state, event_data);
1597 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001598 // Notify registered debug event listeners. The list can contain both C and
1599 // JavaScript functions.
1600 v8::NeanderArray listeners(Factory::debug_event_listeners());
1601 int length = listeners.length();
1602 for (int i = 0; i < length; i++) {
1603 if (listeners.get(i)->IsUndefined()) continue; // Skip deleted ones.
1604 v8::NeanderObject listener(JSObject::cast(listeners.get(i)));
1605 Handle<Object> callback_data(listener.get(1));
1606 if (listener.get(0)->IsProxy()) {
1607 // C debug event listener.
1608 Handle<Proxy> callback_obj(Proxy::cast(listener.get(0)));
1609 v8::DebugEventCallback callback =
1610 FUNCTION_CAST<v8::DebugEventCallback>(callback_obj->proxy());
1611 callback(event,
1612 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
1613 v8::Utils::ToLocal(Handle<JSObject>::cast(event_data)),
1614 v8::Utils::ToLocal(callback_data));
1615 } else {
1616 // JavaScript debug event listener.
1617 ASSERT(listener.get(0)->IsJSFunction());
1618 Handle<JSFunction> fun(JSFunction::cast(listener.get(0)));
1619
1620 // Invoke the JavaScript debug event listener.
1621 const int argc = 4;
1622 Object** argv[argc] = { Handle<Object>(Smi::FromInt(event)).location(),
1623 exec_state.location(),
1624 event_data.location(),
1625 callback_data.location() };
1626 Handle<Object> result = Execution::TryCall(fun, Top::global(),
1627 argc, argv, &caught_exception);
1628 if (caught_exception) {
1629 // Silently ignore exceptions from debug event listeners.
1630 }
1631 }
1632 }
1633}
1634
1635
1636void Debugger::SetMessageHandler(v8::DebugMessageHandler handler, void* data) {
1637 debug_message_handler_ = handler;
1638 debug_message_handler_data_ = data;
1639 if (!message_thread_) {
1640 message_thread_ = new DebugMessageThread();
1641 message_thread_->Start();
1642 }
1643 UpdateActiveDebugger();
1644}
1645
1646
kasper.lund7276f142008-07-30 08:49:36 +00001647// Posts an output message from the debugger to the debug_message_handler
1648// callback. This callback is part of the public API. Messages are
1649// kept internally as Vector<uint16_t> strings, which are allocated in various
1650// places and deallocated by the calling function sometime after this call.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001651void Debugger::SendMessage(Vector< uint16_t> message) {
1652 if (debug_message_handler_ != NULL) {
1653 debug_message_handler_(message.start(), message.length(),
1654 debug_message_handler_data_);
1655 }
1656}
1657
1658
1659void Debugger::ProcessCommand(Vector<const uint16_t> command) {
1660 if (message_thread_ != NULL) {
1661 message_thread_->ProcessCommand(
1662 Vector<uint16_t>(const_cast<uint16_t *>(command.start()),
1663 command.length()));
1664 }
1665}
1666
1667
1668void Debugger::UpdateActiveDebugger() {
1669 v8::NeanderArray listeners(Factory::debug_event_listeners());
1670 int length = listeners.length();
1671 bool active_listener = false;
1672 for (int i = 0; i < length && !active_listener; i++) {
1673 active_listener = !listeners.get(i)->IsUndefined();
1674 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001675 set_debugger_active((Debugger::message_thread_ != NULL &&
1676 Debugger::debug_message_handler_ != NULL) ||
1677 active_listener);
1678 if (!debugger_active() && message_thread_)
1679 message_thread_->OnDebuggerInactive();
1680}
1681
1682
1683DebugMessageThread::DebugMessageThread()
1684 : host_running_(true),
kasper.lund7276f142008-07-30 08:49:36 +00001685 command_queue_(kQueueInitialSize),
1686 message_queue_(kQueueInitialSize) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001687 command_received_ = OS::CreateSemaphore(0);
kasper.lund7276f142008-07-30 08:49:36 +00001688 message_received_ = OS::CreateSemaphore(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001689}
1690
kasper.lund7276f142008-07-30 08:49:36 +00001691// Does not free resources held by DebugMessageThread
1692// because this cannot be done thread-safely.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001693DebugMessageThread::~DebugMessageThread() {
1694}
1695
1696
kasper.lund7276f142008-07-30 08:49:36 +00001697// Puts an event coming from V8 on the queue. Creates
1698// a copy of the JSON formatted event string managed by the V8.
1699// Called by the V8 thread.
1700// The new copy of the event string is destroyed in Run().
1701void DebugMessageThread::SendMessage(Vector<uint16_t> message) {
1702 Vector<uint16_t> message_copy = message.Clone();
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001703 Logger::DebugTag("Put message on event message_queue.");
kasper.lund7276f142008-07-30 08:49:36 +00001704 message_queue_.Put(message_copy);
1705 message_received_->Signal();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001706}
1707
1708
1709void DebugMessageThread::SetEventJSONFromEvent(Handle<Object> event_data) {
1710 v8::HandleScope scope;
1711 // Call toJSONProtocol on the debug event object.
1712 v8::Local<v8::Object> api_event_data =
1713 v8::Utils::ToLocal(Handle<JSObject>::cast(event_data));
1714 v8::Local<v8::String> fun_name = v8::String::New("toJSONProtocol");
1715 v8::Local<v8::Function> fun =
1716 v8::Function::Cast(*api_event_data->Get(fun_name));
1717 v8::TryCatch try_catch;
kasper.lund7276f142008-07-30 08:49:36 +00001718 v8::Local<v8::Value> json_event = *fun->Call(api_event_data, 0, NULL);
1719 v8::Local<v8::String> json_event_string;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001720 if (!try_catch.HasCaught()) {
kasper.lund7276f142008-07-30 08:49:36 +00001721 if (!json_event->IsUndefined()) {
1722 json_event_string = json_event->ToString();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001723 if (FLAG_trace_debug_json) {
kasper.lund7276f142008-07-30 08:49:36 +00001724 PrintLn(json_event_string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001725 }
kasper.lund7276f142008-07-30 08:49:36 +00001726 v8::String::Value val(json_event_string);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001727 Vector<uint16_t> str(reinterpret_cast<uint16_t*>(*val),
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001728 json_event_string->Length());
kasper.lund7276f142008-07-30 08:49:36 +00001729 SendMessage(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001730 } else {
kasper.lund7276f142008-07-30 08:49:36 +00001731 SendMessage(Vector<uint16_t>::empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001732 }
1733 } else {
1734 PrintLn(try_catch.Exception());
kasper.lund7276f142008-07-30 08:49:36 +00001735 SendMessage(Vector<uint16_t>::empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001736 }
1737}
1738
1739
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001740void DebugMessageThread::Run() {
kasper.lund7276f142008-07-30 08:49:36 +00001741 // Sends debug events to an installed debugger message callback.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001742 while (true) {
kasper.lund7276f142008-07-30 08:49:36 +00001743 // Wait and Get are paired so that semaphore count equals queue length.
1744 message_received_->Wait();
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001745 Logger::DebugTag("Get message from event message_queue.");
kasper.lund7276f142008-07-30 08:49:36 +00001746 Vector<uint16_t> message = message_queue_.Get();
1747 if (message.length() > 0) {
1748 Debugger::SendMessage(message);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001749 }
1750 }
1751}
1752
1753
kasper.lund44510672008-07-25 07:37:58 +00001754// This method is called by the V8 thread whenever a debug event occurs in
1755// the VM.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001756void DebugMessageThread::DebugEvent(v8::DebugEvent event,
1757 Handle<Object> exec_state,
1758 Handle<Object> event_data) {
kasper.lund212ac232008-07-16 07:07:30 +00001759 if (!Debug::Load()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001760
1761 // Process the individual events.
1762 bool interactive = false;
1763 switch (event) {
1764 case v8::Break:
v8.team.kasperl727e9952008-09-02 14:56:44 +00001765 interactive = true; // Break event is always interactive
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001766 break;
1767 case v8::Exception:
v8.team.kasperl727e9952008-09-02 14:56:44 +00001768 interactive = true; // Exception event is always interactive
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001769 break;
1770 case v8::BeforeCompile:
1771 break;
1772 case v8::AfterCompile:
1773 break;
1774 case v8::NewFunction:
1775 break;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001776 default:
1777 UNREACHABLE();
1778 }
1779
1780 // Done if not interactive.
1781 if (!interactive) return;
1782
1783 // Get the DebugCommandProcessor.
1784 v8::Local<v8::Object> api_exec_state =
1785 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state));
1786 v8::Local<v8::String> fun_name =
1787 v8::String::New("debugCommandProcessor");
1788 v8::Local<v8::Function> fun =
1789 v8::Function::Cast(*api_exec_state->Get(fun_name));
1790 v8::TryCatch try_catch;
1791 v8::Local<v8::Object> cmd_processor =
1792 v8::Object::Cast(*fun->Call(api_exec_state, 0, NULL));
1793 if (try_catch.HasCaught()) {
1794 PrintLn(try_catch.Exception());
1795 return;
1796 }
1797
v8.team.kasperl727e9952008-09-02 14:56:44 +00001798 // Notify the debugger that a debug event has occurred.
kasper.lund7276f142008-07-30 08:49:36 +00001799 host_running_ = false;
1800 SetEventJSONFromEvent(event_data);
1801
1802 // Wait for commands from the debugger.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001803 while (true) {
kasper.lund7276f142008-07-30 08:49:36 +00001804 command_received_->Wait();
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001805 Logger::DebugTag("Get command from command queue, in interactive loop.");
kasper.lund7276f142008-07-30 08:49:36 +00001806 Vector<uint16_t> command = command_queue_.Get();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001807 ASSERT(!host_running_);
1808 if (!Debugger::debugger_active()) {
1809 host_running_ = true;
1810 return;
1811 }
1812
1813 // Invoke the JavaScript to convert the debug command line to a JSON
kasper.lund7276f142008-07-30 08:49:36 +00001814 // request, invoke the JSON request and convert the JSON response to a text
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001815 // representation.
1816 v8::Local<v8::String> fun_name;
1817 v8::Local<v8::Function> fun;
1818 v8::Local<v8::Value> args[1];
1819 v8::TryCatch try_catch;
1820 fun_name = v8::String::New("processDebugCommand");
1821 fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
kasper.lund7276f142008-07-30 08:49:36 +00001822 args[0] = v8::String::New(reinterpret_cast<uint16_t*>(command.start()),
1823 command.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001824 v8::Local<v8::Value> result_val = fun->Call(cmd_processor, 1, args);
1825
1826 // Get the result of the command.
1827 v8::Local<v8::String> result_string;
1828 bool running = false;
1829 if (!try_catch.HasCaught()) {
1830 // Get the result as an object.
1831 v8::Local<v8::Object> result = v8::Object::Cast(*result_val);
1832
1833 // Log the JSON request/response.
1834 if (FLAG_trace_debug_json) {
1835 PrintLn(result->Get(v8::String::New("request")));
1836 PrintLn(result->Get(v8::String::New("response")));
1837 }
1838
1839 // Get the running state.
1840 running = result->Get(v8::String::New("running"))->ToBoolean()->Value();
1841
1842 // Get result text.
1843 v8::Local<v8::Value> text_result =
1844 result->Get(v8::String::New("response"));
1845 if (!text_result->IsUndefined()) {
1846 result_string = text_result->ToString();
1847 } else {
1848 result_string = v8::String::New("");
1849 }
1850 } else {
1851 // In case of failure the result text is the exception text.
1852 result_string = try_catch.Exception()->ToString();
1853 }
1854
1855 // Convert text result to C string.
1856 v8::String::Value val(result_string);
1857 Vector<uint16_t> str(reinterpret_cast<uint16_t*>(*val),
1858 result_string->Length());
1859
kasper.lund7276f142008-07-30 08:49:36 +00001860 // Set host_running_ correctly for nested debugger evaluations.
1861 host_running_ = running;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001862
1863 // Return the result.
kasper.lund7276f142008-07-30 08:49:36 +00001864 SendMessage(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001865
1866 // Return from debug event processing is VM should be running.
1867 if (running) {
1868 return;
1869 }
1870 }
1871}
1872
1873
kasper.lund7276f142008-07-30 08:49:36 +00001874// Puts a command coming from the public API on the queue. Creates
1875// a copy of the command string managed by the debugger. Up to this
1876// point, the command data was managed by the API client. Called
1877// by the API client thread. This is where the API client hands off
1878// processing of the command to the DebugMessageThread thread.
1879// The new copy of the command is destroyed in HandleCommand().
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001880void DebugMessageThread::ProcessCommand(Vector<uint16_t> command) {
kasper.lund7276f142008-07-30 08:49:36 +00001881 Vector<uint16_t> command_copy = command.Clone();
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001882 Logger::DebugTag("Put command on command_queue.");
kasper.lund7276f142008-07-30 08:49:36 +00001883 command_queue_.Put(command_copy);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001884 command_received_->Signal();
1885}
1886
1887
1888void DebugMessageThread::OnDebuggerInactive() {
kasper.lund7276f142008-07-30 08:49:36 +00001889 // Send an empty command to the debugger if in a break to make JavaScript run
1890 // again if the debugger is closed.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001891 if (!host_running_) {
kasper.lund7276f142008-07-30 08:49:36 +00001892 ProcessCommand(Vector<uint16_t>::empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001893 }
1894}
1895
kasper.lund7276f142008-07-30 08:49:36 +00001896
1897MessageQueue::MessageQueue(int size) : start_(0), end_(0), size_(size) {
1898 messages_ = NewArray<Vector<uint16_t> >(size);
1899}
1900
1901
1902MessageQueue::~MessageQueue() {
1903 DeleteArray(messages_);
1904}
1905
1906
1907Vector<uint16_t> MessageQueue::Get() {
1908 ASSERT(!IsEmpty());
1909 int result = start_;
1910 start_ = (start_ + 1) % size_;
1911 return messages_[result];
1912}
1913
1914
1915void MessageQueue::Put(const Vector<uint16_t>& message) {
1916 if ((end_ + 1) % size_ == start_) {
1917 Expand();
1918 }
1919 messages_[end_] = message;
1920 end_ = (end_ + 1) % size_;
1921}
1922
1923
1924void MessageQueue::Expand() {
1925 MessageQueue new_queue(size_ * 2);
1926 while (!IsEmpty()) {
1927 new_queue.Put(Get());
1928 }
1929 Vector<uint16_t>* array_to_free = messages_;
1930 *this = new_queue;
1931 new_queue.messages_ = array_to_free;
1932 // Automatic destructor called on new_queue, freeing array_to_free.
1933}
1934
1935
1936LockingMessageQueue::LockingMessageQueue(int size) : queue_(size) {
1937 lock_ = OS::CreateMutex();
1938}
1939
1940
1941LockingMessageQueue::~LockingMessageQueue() {
1942 delete lock_;
1943}
1944
1945
1946bool LockingMessageQueue::IsEmpty() const {
1947 ScopedLock sl(lock_);
1948 return queue_.IsEmpty();
1949}
1950
1951
1952Vector<uint16_t> LockingMessageQueue::Get() {
1953 ScopedLock sl(lock_);
1954 Vector<uint16_t> result = queue_.Get();
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001955 Logger::DebugEvent("Get", result);
kasper.lund7276f142008-07-30 08:49:36 +00001956 return result;
1957}
1958
1959
1960void LockingMessageQueue::Put(const Vector<uint16_t>& message) {
1961 ScopedLock sl(lock_);
1962 queue_.Put(message);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001963 Logger::DebugEvent("Put", message);
kasper.lund7276f142008-07-30 08:49:36 +00001964}
1965
1966
1967void LockingMessageQueue::Clear() {
1968 ScopedLock sl(lock_);
1969 queue_.Clear();
1970}
1971
1972
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001973} } // namespace v8::internal