blob: ca3c1db790b0ead96669fd49793dafdfef70dcaf [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
31#include "arguments.h"
32#include "bootstrapper.h"
33#include "code-stubs.h"
Andrei Popescu402d9372010-02-26 13:31:12 +000034#include "codegen.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000035#include "compilation-cache.h"
36#include "compiler.h"
37#include "debug.h"
Ben Murdochb0fe1622011-05-05 13:52:32 +010038#include "deoptimizer.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000039#include "execution.h"
40#include "global-handles.h"
41#include "ic.h"
42#include "ic-inl.h"
Steve Block6ded16b2010-05-10 14:33:55 +010043#include "messages.h"
Steve Blocka7e24c12009-10-30 11:49:00 +000044#include "natives.h"
45#include "stub-cache.h"
46#include "log.h"
47
48#include "../include/v8-debug.h"
49
50namespace v8 {
51namespace internal {
52
53#ifdef ENABLE_DEBUGGER_SUPPORT
54static void PrintLn(v8::Local<v8::Value> value) {
55 v8::Local<v8::String> s = value->ToString();
Kristian Monsen25f61362010-05-21 11:50:48 +010056 ScopedVector<char> data(s->Length() + 1);
57 if (data.start() == NULL) {
Steve Blocka7e24c12009-10-30 11:49:00 +000058 V8::FatalProcessOutOfMemory("PrintLn");
59 return;
60 }
Kristian Monsen25f61362010-05-21 11:50:48 +010061 s->WriteAscii(data.start());
62 PrintF("%s\n", data.start());
Steve Blocka7e24c12009-10-30 11:49:00 +000063}
64
65
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010066static Handle<Code> ComputeCallDebugBreak(int argc, Code::Kind kind) {
67 CALL_HEAP_FUNCTION(StubCache::ComputeCallDebugBreak(argc, kind), Code);
Steve Blocka7e24c12009-10-30 11:49:00 +000068}
69
70
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010071static Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind) {
72 CALL_HEAP_FUNCTION(
73 StubCache::ComputeCallDebugPrepareStepIn(argc, kind), Code);
Steve Blocka7e24c12009-10-30 11:49:00 +000074}
75
76
Leon Clarkef7060e22010-06-03 12:02:55 +010077static v8::Handle<v8::Context> GetDebugEventContext() {
78 Handle<Context> context = Debug::debugger_entry()->GetContext();
79 // Top::context() may have been NULL when "script collected" event occured.
80 if (*context == NULL) {
81 return v8::Local<v8::Context>();
82 }
83 Handle<Context> global_context(context->global_context());
84 return v8::Utils::ToLocal(global_context);
85}
86
87
Steve Blocka7e24c12009-10-30 11:49:00 +000088BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info,
89 BreakLocatorType type) {
90 debug_info_ = debug_info;
91 type_ = type;
Steve Blocka7e24c12009-10-30 11:49:00 +000092 reloc_iterator_ = NULL;
93 reloc_iterator_original_ = NULL;
94 Reset(); // Initialize the rest of the member variables.
95}
96
97
98BreakLocationIterator::~BreakLocationIterator() {
99 ASSERT(reloc_iterator_ != NULL);
100 ASSERT(reloc_iterator_original_ != NULL);
101 delete reloc_iterator_;
102 delete reloc_iterator_original_;
103}
104
105
106void BreakLocationIterator::Next() {
107 AssertNoAllocation nogc;
108 ASSERT(!RinfoDone());
109
110 // Iterate through reloc info for code and original code stopping at each
111 // breakable code target.
112 bool first = break_point_ == -1;
113 while (!RinfoDone()) {
114 if (!first) RinfoNext();
115 first = false;
116 if (RinfoDone()) return;
117
118 // Whenever a statement position or (plain) position is passed update the
119 // current value of these.
120 if (RelocInfo::IsPosition(rmode())) {
121 if (RelocInfo::IsStatementPosition(rmode())) {
Steve Blockd0582a62009-12-15 09:54:21 +0000122 statement_position_ = static_cast<int>(
123 rinfo()->data() - debug_info_->shared()->start_position());
Steve Blocka7e24c12009-10-30 11:49:00 +0000124 }
125 // Always update the position as we don't want that to be before the
126 // statement position.
Steve Blockd0582a62009-12-15 09:54:21 +0000127 position_ = static_cast<int>(
128 rinfo()->data() - debug_info_->shared()->start_position());
Steve Blocka7e24c12009-10-30 11:49:00 +0000129 ASSERT(position_ >= 0);
130 ASSERT(statement_position_ >= 0);
131 }
132
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100133 if (IsDebugBreakSlot()) {
134 // There is always a possible break point at a debug break slot.
135 break_point_++;
136 return;
137 } else if (RelocInfo::IsCodeTarget(rmode())) {
138 // Check for breakable code target. Look in the original code as setting
139 // break points can cause the code targets in the running (debugged) code
140 // to be of a different kind than in the original code.
Steve Blocka7e24c12009-10-30 11:49:00 +0000141 Address target = original_rinfo()->target_address();
142 Code* code = Code::GetCodeFromTargetAddress(target);
Steve Block6ded16b2010-05-10 14:33:55 +0100143 if ((code->is_inline_cache_stub() &&
Ben Murdochb0fe1622011-05-05 13:52:32 +0100144 !code->is_binary_op_stub() &&
145 !code->is_type_recording_binary_op_stub() &&
146 !code->is_compare_ic_stub()) ||
Steve Block6ded16b2010-05-10 14:33:55 +0100147 RelocInfo::IsConstructCall(rmode())) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000148 break_point_++;
149 return;
150 }
151 if (code->kind() == Code::STUB) {
152 if (IsDebuggerStatement()) {
153 break_point_++;
154 return;
155 }
156 if (type_ == ALL_BREAK_LOCATIONS) {
157 if (Debug::IsBreakStub(code)) {
158 break_point_++;
159 return;
160 }
161 } else {
162 ASSERT(type_ == SOURCE_BREAK_LOCATIONS);
163 if (Debug::IsSourceBreakStub(code)) {
164 break_point_++;
165 return;
166 }
167 }
168 }
169 }
170
171 // Check for break at return.
172 if (RelocInfo::IsJSReturn(rmode())) {
173 // Set the positions to the end of the function.
174 if (debug_info_->shared()->HasSourceCode()) {
175 position_ = debug_info_->shared()->end_position() -
Ben Murdochbb769b22010-08-11 14:56:33 +0100176 debug_info_->shared()->start_position() - 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000177 } else {
178 position_ = 0;
179 }
180 statement_position_ = position_;
181 break_point_++;
182 return;
183 }
184 }
185}
186
187
188void BreakLocationIterator::Next(int count) {
189 while (count > 0) {
190 Next();
191 count--;
192 }
193}
194
195
196// Find the break point closest to the supplied address.
197void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) {
198 // Run through all break points to locate the one closest to the address.
199 int closest_break_point = 0;
200 int distance = kMaxInt;
201 while (!Done()) {
202 // Check if this break point is closer that what was previously found.
203 if (this->pc() < pc && pc - this->pc() < distance) {
204 closest_break_point = break_point();
Steve Blockd0582a62009-12-15 09:54:21 +0000205 distance = static_cast<int>(pc - this->pc());
Steve Blocka7e24c12009-10-30 11:49:00 +0000206 // Check whether we can't get any closer.
207 if (distance == 0) break;
208 }
209 Next();
210 }
211
212 // Move to the break point found.
213 Reset();
214 Next(closest_break_point);
215}
216
217
218// Find the break point closest to the supplied source position.
219void BreakLocationIterator::FindBreakLocationFromPosition(int position) {
220 // Run through all break points to locate the one closest to the source
221 // position.
222 int closest_break_point = 0;
223 int distance = kMaxInt;
224 while (!Done()) {
225 // Check if this break point is closer that what was previously found.
226 if (position <= statement_position() &&
227 statement_position() - position < distance) {
228 closest_break_point = break_point();
229 distance = statement_position() - position;
230 // Check whether we can't get any closer.
231 if (distance == 0) break;
232 }
233 Next();
234 }
235
236 // Move to the break point found.
237 Reset();
238 Next(closest_break_point);
239}
240
241
242void BreakLocationIterator::Reset() {
243 // Create relocation iterators for the two code objects.
244 if (reloc_iterator_ != NULL) delete reloc_iterator_;
245 if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_;
246 reloc_iterator_ = new RelocIterator(debug_info_->code());
247 reloc_iterator_original_ = new RelocIterator(debug_info_->original_code());
248
249 // Position at the first break point.
250 break_point_ = -1;
251 position_ = 1;
252 statement_position_ = 1;
253 Next();
254}
255
256
257bool BreakLocationIterator::Done() const {
258 return RinfoDone();
259}
260
261
262void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) {
263 // If there is not already a real break point here patch code with debug
264 // break.
265 if (!HasBreakPoint()) {
266 SetDebugBreak();
267 }
268 ASSERT(IsDebugBreak() || IsDebuggerStatement());
269 // Set the break point information.
270 DebugInfo::SetBreakPoint(debug_info_, code_position(),
271 position(), statement_position(),
272 break_point_object);
273}
274
275
276void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) {
277 // Clear the break point information.
278 DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object);
279 // If there are no more break points here remove the debug break.
280 if (!HasBreakPoint()) {
281 ClearDebugBreak();
282 ASSERT(!IsDebugBreak());
283 }
284}
285
286
287void BreakLocationIterator::SetOneShot() {
288 // Debugger statement always calls debugger. No need to modify it.
289 if (IsDebuggerStatement()) {
290 return;
291 }
292
293 // If there is a real break point here no more to do.
294 if (HasBreakPoint()) {
295 ASSERT(IsDebugBreak());
296 return;
297 }
298
299 // Patch code with debug break.
300 SetDebugBreak();
301}
302
303
304void BreakLocationIterator::ClearOneShot() {
305 // Debugger statement always calls debugger. No need to modify it.
306 if (IsDebuggerStatement()) {
307 return;
308 }
309
310 // If there is a real break point here no more to do.
311 if (HasBreakPoint()) {
312 ASSERT(IsDebugBreak());
313 return;
314 }
315
316 // Patch code removing debug break.
317 ClearDebugBreak();
318 ASSERT(!IsDebugBreak());
319}
320
321
322void BreakLocationIterator::SetDebugBreak() {
323 // Debugger statement always calls debugger. No need to modify it.
324 if (IsDebuggerStatement()) {
325 return;
326 }
327
328 // If there is already a break point here just return. This might happen if
329 // the same code is flooded with break points twice. Flooding the same
330 // function twice might happen when stepping in a function with an exception
331 // handler as the handler and the function is the same.
332 if (IsDebugBreak()) {
333 return;
334 }
335
336 if (RelocInfo::IsJSReturn(rmode())) {
337 // Patch the frame exit code with a break point.
338 SetDebugBreakAtReturn();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100339 } else if (IsDebugBreakSlot()) {
340 // Patch the code in the break slot.
341 SetDebugBreakAtSlot();
Steve Blocka7e24c12009-10-30 11:49:00 +0000342 } else {
343 // Patch the IC call.
344 SetDebugBreakAtIC();
345 }
346 ASSERT(IsDebugBreak());
347}
348
349
350void BreakLocationIterator::ClearDebugBreak() {
351 // Debugger statement always calls debugger. No need to modify it.
352 if (IsDebuggerStatement()) {
353 return;
354 }
355
356 if (RelocInfo::IsJSReturn(rmode())) {
357 // Restore the frame exit code.
358 ClearDebugBreakAtReturn();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100359 } else if (IsDebugBreakSlot()) {
360 // Restore the code in the break slot.
361 ClearDebugBreakAtSlot();
Steve Blocka7e24c12009-10-30 11:49:00 +0000362 } else {
363 // Patch the IC call.
364 ClearDebugBreakAtIC();
365 }
366 ASSERT(!IsDebugBreak());
367}
368
369
370void BreakLocationIterator::PrepareStepIn() {
371 HandleScope scope;
372
373 // Step in can only be prepared if currently positioned on an IC call,
374 // construct call or CallFunction stub call.
375 Address target = rinfo()->target_address();
376 Handle<Code> code(Code::GetCodeFromTargetAddress(target));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100377 if (code->is_call_stub() || code->is_keyed_call_stub()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000378 // Step in through IC call is handled by the runtime system. Therefore make
379 // sure that the any current IC is cleared and the runtime system is
380 // called. If the executing code has a debug break at the location change
381 // the call in the original code as it is the code there that will be
382 // executed in place of the debug break call.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100383 Handle<Code> stub = ComputeCallDebugPrepareStepIn(code->arguments_count(),
384 code->kind());
Steve Blocka7e24c12009-10-30 11:49:00 +0000385 if (IsDebugBreak()) {
386 original_rinfo()->set_target_address(stub->entry());
387 } else {
388 rinfo()->set_target_address(stub->entry());
389 }
390 } else {
391#ifdef DEBUG
392 // All the following stuff is needed only for assertion checks so the code
393 // is wrapped in ifdef.
394 Handle<Code> maybe_call_function_stub = code;
395 if (IsDebugBreak()) {
396 Address original_target = original_rinfo()->target_address();
397 maybe_call_function_stub =
398 Handle<Code>(Code::GetCodeFromTargetAddress(original_target));
399 }
400 bool is_call_function_stub =
401 (maybe_call_function_stub->kind() == Code::STUB &&
402 maybe_call_function_stub->major_key() == CodeStub::CallFunction);
403
404 // Step in through construct call requires no changes to the running code.
405 // Step in through getters/setters should already be prepared as well
406 // because caller of this function (Debug::PrepareStep) is expected to
407 // flood the top frame's function with one shot breakpoints.
408 // Step in through CallFunction stub should also be prepared by caller of
409 // this function (Debug::PrepareStep) which should flood target function
410 // with breakpoints.
411 ASSERT(RelocInfo::IsConstructCall(rmode()) || code->is_inline_cache_stub()
412 || is_call_function_stub);
413#endif
414 }
415}
416
417
418// Check whether the break point is at a position which will exit the function.
419bool BreakLocationIterator::IsExit() const {
420 return (RelocInfo::IsJSReturn(rmode()));
421}
422
423
424bool BreakLocationIterator::HasBreakPoint() {
425 return debug_info_->HasBreakPoint(code_position());
426}
427
428
429// Check whether there is a debug break at the current position.
430bool BreakLocationIterator::IsDebugBreak() {
431 if (RelocInfo::IsJSReturn(rmode())) {
432 return IsDebugBreakAtReturn();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100433 } else if (IsDebugBreakSlot()) {
434 return IsDebugBreakAtSlot();
Steve Blocka7e24c12009-10-30 11:49:00 +0000435 } else {
436 return Debug::IsDebugBreak(rinfo()->target_address());
437 }
438}
439
440
441void BreakLocationIterator::SetDebugBreakAtIC() {
442 // Patch the original code with the current address as the current address
443 // might have changed by the inline caching since the code was copied.
444 original_rinfo()->set_target_address(rinfo()->target_address());
445
446 RelocInfo::Mode mode = rmode();
447 if (RelocInfo::IsCodeTarget(mode)) {
448 Address target = rinfo()->target_address();
449 Handle<Code> code(Code::GetCodeFromTargetAddress(target));
450
451 // Patch the code to invoke the builtin debug break function matching the
452 // calling convention used by the call site.
453 Handle<Code> dbgbrk_code(Debug::FindDebugBreak(code, mode));
454 rinfo()->set_target_address(dbgbrk_code->entry());
455
456 // For stubs that refer back to an inlined version clear the cached map for
457 // the inlined case to always go through the IC. As long as the break point
458 // is set the patching performed by the runtime system will take place in
459 // the code copy and will therefore have no effect on the running code
460 // keeping it from using the inlined code.
Kristian Monsen25f61362010-05-21 11:50:48 +0100461 if (code->is_keyed_load_stub()) {
462 KeyedLoadIC::ClearInlinedVersion(pc());
463 } else if (code->is_keyed_store_stub()) {
464 KeyedStoreIC::ClearInlinedVersion(pc());
465 } else if (code->is_load_stub()) {
466 LoadIC::ClearInlinedVersion(pc());
Iain Merrick75681382010-08-19 15:07:18 +0100467 } else if (code->is_store_stub()) {
468 StoreIC::ClearInlinedVersion(pc());
Kristian Monsen25f61362010-05-21 11:50:48 +0100469 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000470 }
471}
472
473
474void BreakLocationIterator::ClearDebugBreakAtIC() {
475 // Patch the code to the original invoke.
476 rinfo()->set_target_address(original_rinfo()->target_address());
477
478 RelocInfo::Mode mode = rmode();
479 if (RelocInfo::IsCodeTarget(mode)) {
Leon Clarkeac952652010-07-15 11:15:24 +0100480 AssertNoAllocation nogc;
Steve Blocka7e24c12009-10-30 11:49:00 +0000481 Address target = original_rinfo()->target_address();
Leon Clarkeac952652010-07-15 11:15:24 +0100482 Code* code = Code::GetCodeFromTargetAddress(target);
Steve Blocka7e24c12009-10-30 11:49:00 +0000483
484 // Restore the inlined version of keyed stores to get back to the
485 // fast case. We need to patch back the keyed store because no
486 // patching happens when running normally. For keyed loads, the
487 // map check will get patched back when running normally after ICs
488 // have been cleared at GC.
489 if (code->is_keyed_store_stub()) KeyedStoreIC::RestoreInlinedVersion(pc());
490 }
491}
492
493
494bool BreakLocationIterator::IsDebuggerStatement() {
Andrei Popescu402d9372010-02-26 13:31:12 +0000495 return RelocInfo::DEBUG_BREAK == rmode();
Steve Blocka7e24c12009-10-30 11:49:00 +0000496}
497
498
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100499bool BreakLocationIterator::IsDebugBreakSlot() {
500 return RelocInfo::DEBUG_BREAK_SLOT == rmode();
501}
502
503
Steve Blocka7e24c12009-10-30 11:49:00 +0000504Object* BreakLocationIterator::BreakPointObjects() {
505 return debug_info_->GetBreakPointObjects(code_position());
506}
507
508
509// Clear out all the debug break code. This is ONLY supposed to be used when
510// shutting down the debugger as it will leave the break point information in
511// DebugInfo even though the code is patched back to the non break point state.
512void BreakLocationIterator::ClearAllDebugBreak() {
513 while (!Done()) {
514 ClearDebugBreak();
515 Next();
516 }
517}
518
519
520bool BreakLocationIterator::RinfoDone() const {
521 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
522 return reloc_iterator_->done();
523}
524
525
526void BreakLocationIterator::RinfoNext() {
527 reloc_iterator_->next();
528 reloc_iterator_original_->next();
529#ifdef DEBUG
530 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
531 if (!reloc_iterator_->done()) {
532 ASSERT(rmode() == original_rmode());
533 }
534#endif
535}
536
537
538bool Debug::has_break_points_ = false;
539ScriptCache* Debug::script_cache_ = NULL;
540DebugInfoListNode* Debug::debug_info_list_ = NULL;
541
542
543// Threading support.
544void Debug::ThreadInit() {
545 thread_local_.break_count_ = 0;
546 thread_local_.break_id_ = 0;
547 thread_local_.break_frame_id_ = StackFrame::NO_ID;
548 thread_local_.last_step_action_ = StepNone;
549 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
550 thread_local_.step_count_ = 0;
551 thread_local_.last_fp_ = 0;
552 thread_local_.step_into_fp_ = 0;
553 thread_local_.step_out_fp_ = 0;
554 thread_local_.after_break_target_ = 0;
555 thread_local_.debugger_entry_ = NULL;
556 thread_local_.pending_interrupts_ = 0;
Iain Merrick75681382010-08-19 15:07:18 +0100557 thread_local_.restarter_frame_function_pointer_ = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000558}
559
560
561JSCallerSavedBuffer Debug::registers_;
562Debug::ThreadLocal Debug::thread_local_;
563
564
565char* Debug::ArchiveDebug(char* storage) {
566 char* to = storage;
567 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
568 to += sizeof(ThreadLocal);
569 memcpy(to, reinterpret_cast<char*>(&registers_), sizeof(registers_));
570 ThreadInit();
571 ASSERT(to <= storage + ArchiveSpacePerThread());
572 return storage + ArchiveSpacePerThread();
573}
574
575
576char* Debug::RestoreDebug(char* storage) {
577 char* from = storage;
578 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
579 from += sizeof(ThreadLocal);
580 memcpy(reinterpret_cast<char*>(&registers_), from, sizeof(registers_));
581 ASSERT(from <= storage + ArchiveSpacePerThread());
582 return storage + ArchiveSpacePerThread();
583}
584
585
586int Debug::ArchiveSpacePerThread() {
587 return sizeof(ThreadLocal) + sizeof(registers_);
588}
589
590
Iain Merrick75681382010-08-19 15:07:18 +0100591// Frame structure (conforms InternalFrame structure):
592// -- code
593// -- SMI maker
594// -- function (slot is called "context")
595// -- frame base
596Object** Debug::SetUpFrameDropperFrame(StackFrame* bottom_js_frame,
597 Handle<Code> code) {
598 ASSERT(bottom_js_frame->is_java_script());
599
600 Address fp = bottom_js_frame->fp();
601
602 // Move function pointer into "context" slot.
603 Memory::Object_at(fp + StandardFrameConstants::kContextOffset) =
604 Memory::Object_at(fp + JavaScriptFrameConstants::kFunctionOffset);
605
606 Memory::Object_at(fp + InternalFrameConstants::kCodeOffset) = *code;
607 Memory::Object_at(fp + StandardFrameConstants::kMarkerOffset) =
608 Smi::FromInt(StackFrame::INTERNAL);
609
610 return reinterpret_cast<Object**>(&Memory::Object_at(
611 fp + StandardFrameConstants::kContextOffset));
612}
613
614const int Debug::kFrameDropperFrameSize = 4;
615
616
617
618
619
Steve Blocka7e24c12009-10-30 11:49:00 +0000620// Default break enabled.
621bool Debug::disable_break_ = false;
622
623// Default call debugger on uncaught exception.
624bool Debug::break_on_exception_ = false;
625bool Debug::break_on_uncaught_exception_ = true;
626
627Handle<Context> Debug::debug_context_ = Handle<Context>();
628Code* Debug::debug_break_return_ = NULL;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100629Code* Debug::debug_break_slot_ = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000630
631
632void ScriptCache::Add(Handle<Script> script) {
633 // Create an entry in the hash map for the script.
634 int id = Smi::cast(script->id())->value();
635 HashMap::Entry* entry =
636 HashMap::Lookup(reinterpret_cast<void*>(id), Hash(id), true);
637 if (entry->value != NULL) {
638 ASSERT(*script == *reinterpret_cast<Script**>(entry->value));
639 return;
640 }
641
642 // Globalize the script object, make it weak and use the location of the
643 // global handle as the value in the hash map.
644 Handle<Script> script_ =
645 Handle<Script>::cast((GlobalHandles::Create(*script)));
646 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(script_.location()),
647 this, ScriptCache::HandleWeakScript);
648 entry->value = script_.location();
649}
650
651
652Handle<FixedArray> ScriptCache::GetScripts() {
653 Handle<FixedArray> instances = Factory::NewFixedArray(occupancy());
654 int count = 0;
655 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
656 ASSERT(entry->value != NULL);
657 if (entry->value != NULL) {
658 instances->set(count, *reinterpret_cast<Script**>(entry->value));
659 count++;
660 }
661 }
662 return instances;
663}
664
665
666void ScriptCache::ProcessCollectedScripts() {
667 for (int i = 0; i < collected_scripts_.length(); i++) {
668 Debugger::OnScriptCollected(collected_scripts_[i]);
669 }
670 collected_scripts_.Clear();
671}
672
673
674void ScriptCache::Clear() {
675 // Iterate the script cache to get rid of all the weak handles.
676 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
677 ASSERT(entry != NULL);
678 Object** location = reinterpret_cast<Object**>(entry->value);
679 ASSERT((*location)->IsScript());
680 GlobalHandles::ClearWeakness(location);
681 GlobalHandles::Destroy(location);
682 }
683 // Clear the content of the hash map.
684 HashMap::Clear();
685}
686
687
688void ScriptCache::HandleWeakScript(v8::Persistent<v8::Value> obj, void* data) {
689 ScriptCache* script_cache = reinterpret_cast<ScriptCache*>(data);
690 // Find the location of the global handle.
691 Script** location =
692 reinterpret_cast<Script**>(Utils::OpenHandle(*obj).location());
693 ASSERT((*location)->IsScript());
694
695 // Remove the entry from the cache.
696 int id = Smi::cast((*location)->id())->value();
697 script_cache->Remove(reinterpret_cast<void*>(id), Hash(id));
698 script_cache->collected_scripts_.Add(id);
699
700 // Clear the weak handle.
701 obj.Dispose();
702 obj.Clear();
703}
704
705
706void Debug::Setup(bool create_heap_objects) {
707 ThreadInit();
708 if (create_heap_objects) {
709 // Get code to handle debug break on return.
710 debug_break_return_ =
711 Builtins::builtin(Builtins::Return_DebugBreak);
712 ASSERT(debug_break_return_->IsCode());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100713 // Get code to handle debug break in debug break slots.
714 debug_break_slot_ =
715 Builtins::builtin(Builtins::Slot_DebugBreak);
716 ASSERT(debug_break_slot_->IsCode());
Steve Blocka7e24c12009-10-30 11:49:00 +0000717 }
718}
719
720
721void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) {
722 DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data);
Steve Block8defd9f2010-07-08 12:39:36 +0100723 // We need to clear all breakpoints associated with the function to restore
724 // original code and avoid patching the code twice later because
725 // the function will live in the heap until next gc, and can be found by
726 // Runtime::FindSharedFunctionInfoInScript.
727 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
728 it.ClearAllDebugBreak();
Steve Blocka7e24c12009-10-30 11:49:00 +0000729 RemoveDebugInfo(node->debug_info());
730#ifdef DEBUG
731 node = Debug::debug_info_list_;
732 while (node != NULL) {
733 ASSERT(node != reinterpret_cast<DebugInfoListNode*>(data));
734 node = node->next();
735 }
736#endif
737}
738
739
740DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
741 // Globalize the request debug info object and make it weak.
742 debug_info_ = Handle<DebugInfo>::cast((GlobalHandles::Create(debug_info)));
743 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(debug_info_.location()),
744 this, Debug::HandleWeakDebugInfo);
745}
746
747
748DebugInfoListNode::~DebugInfoListNode() {
749 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_.location()));
750}
751
752
753bool Debug::CompileDebuggerScript(int index) {
754 HandleScope scope;
755
756 // Bail out if the index is invalid.
757 if (index == -1) {
758 return false;
759 }
760
761 // Find source and name for the requested script.
762 Handle<String> source_code = Bootstrapper::NativesSourceLookup(index);
763 Vector<const char> name = Natives::GetScriptName(index);
764 Handle<String> script_name = Factory::NewStringFromAscii(name);
765
766 // Compile the script.
767 bool allow_natives_syntax = FLAG_allow_natives_syntax;
768 FLAG_allow_natives_syntax = true;
Steve Block6ded16b2010-05-10 14:33:55 +0100769 Handle<SharedFunctionInfo> function_info;
770 function_info = Compiler::Compile(source_code,
771 script_name,
772 0, 0, NULL, NULL,
773 Handle<String>::null(),
774 NATIVES_CODE);
Steve Blocka7e24c12009-10-30 11:49:00 +0000775 FLAG_allow_natives_syntax = allow_natives_syntax;
776
777 // Silently ignore stack overflows during compilation.
Steve Block6ded16b2010-05-10 14:33:55 +0100778 if (function_info.is_null()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000779 ASSERT(Top::has_pending_exception());
780 Top::clear_pending_exception();
781 return false;
782 }
783
Steve Block6ded16b2010-05-10 14:33:55 +0100784 // Execute the shared function in the debugger context.
Steve Blocka7e24c12009-10-30 11:49:00 +0000785 Handle<Context> context = Top::global_context();
786 bool caught_exception = false;
787 Handle<JSFunction> function =
Steve Block6ded16b2010-05-10 14:33:55 +0100788 Factory::NewFunctionFromSharedFunctionInfo(function_info, context);
Steve Blocka7e24c12009-10-30 11:49:00 +0000789 Handle<Object> result =
790 Execution::TryCall(function, Handle<Object>(context->global()),
791 0, NULL, &caught_exception);
792
793 // Check for caught exceptions.
794 if (caught_exception) {
795 Handle<Object> message = MessageHandler::MakeMessageObject(
796 "error_loading_debugger", NULL, Vector<Handle<Object> >::empty(),
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100797 Handle<String>(), Handle<JSArray>());
Steve Blocka7e24c12009-10-30 11:49:00 +0000798 MessageHandler::ReportMessage(NULL, message);
799 return false;
800 }
801
802 // Mark this script as native and return successfully.
803 Handle<Script> script(Script::cast(function->shared()->script()));
Steve Block6ded16b2010-05-10 14:33:55 +0100804 script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
Steve Blocka7e24c12009-10-30 11:49:00 +0000805 return true;
806}
807
808
809bool Debug::Load() {
810 // Return if debugger is already loaded.
811 if (IsLoaded()) return true;
812
813 // Bail out if we're already in the process of compiling the native
814 // JavaScript source code for the debugger.
815 if (Debugger::compiling_natives() || Debugger::is_loading_debugger())
816 return false;
817 Debugger::set_loading_debugger(true);
818
819 // Disable breakpoints and interrupts while compiling and running the
820 // debugger scripts including the context creation code.
821 DisableBreak disable(true);
822 PostponeInterruptsScope postpone;
823
824 // Create the debugger context.
825 HandleScope scope;
826 Handle<Context> context =
827 Bootstrapper::CreateEnvironment(Handle<Object>::null(),
828 v8::Handle<ObjectTemplate>(),
829 NULL);
830
831 // Use the debugger context.
832 SaveContext save;
833 Top::set_context(*context);
834
835 // Expose the builtins object in the debugger context.
836 Handle<String> key = Factory::LookupAsciiSymbol("builtins");
837 Handle<GlobalObject> global = Handle<GlobalObject>(context->global());
838 SetProperty(global, key, Handle<Object>(global->builtins()), NONE);
839
840 // Compile the JavaScript for the debugger in the debugger context.
841 Debugger::set_compiling_natives(true);
842 bool caught_exception =
843 !CompileDebuggerScript(Natives::GetIndex("mirror")) ||
844 !CompileDebuggerScript(Natives::GetIndex("debug"));
Steve Block6ded16b2010-05-10 14:33:55 +0100845
846 if (FLAG_enable_liveedit) {
847 caught_exception = caught_exception ||
848 !CompileDebuggerScript(Natives::GetIndex("liveedit"));
849 }
850
Steve Blocka7e24c12009-10-30 11:49:00 +0000851 Debugger::set_compiling_natives(false);
852
853 // Make sure we mark the debugger as not loading before we might
854 // return.
855 Debugger::set_loading_debugger(false);
856
857 // Check for caught exceptions.
858 if (caught_exception) return false;
859
860 // Debugger loaded.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100861 debug_context_ = context;
Steve Blocka7e24c12009-10-30 11:49:00 +0000862
863 return true;
864}
865
866
867void Debug::Unload() {
868 // Return debugger is not loaded.
869 if (!IsLoaded()) {
870 return;
871 }
872
873 // Clear the script cache.
874 DestroyScriptCache();
875
876 // Clear debugger context global handle.
877 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_context_.location()));
878 debug_context_ = Handle<Context>();
879}
880
881
882// Set the flag indicating that preemption happened during debugging.
883void Debug::PreemptionWhileInDebugger() {
884 ASSERT(InDebugger());
885 Debug::set_interrupts_pending(PREEMPT);
886}
887
888
889void Debug::Iterate(ObjectVisitor* v) {
Iain Merrick75681382010-08-19 15:07:18 +0100890 v->VisitPointer(BitCast<Object**>(&(debug_break_return_)));
891 v->VisitPointer(BitCast<Object**>(&(debug_break_slot_)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000892}
893
894
895Object* Debug::Break(Arguments args) {
896 HandleScope scope;
897 ASSERT(args.length() == 0);
898
Steve Block8defd9f2010-07-08 12:39:36 +0100899 thread_local_.frame_drop_mode_ = FRAMES_UNTOUCHED;
Steve Block6ded16b2010-05-10 14:33:55 +0100900
Steve Blocka7e24c12009-10-30 11:49:00 +0000901 // Get the top-most JavaScript frame.
902 JavaScriptFrameIterator it;
903 JavaScriptFrame* frame = it.frame();
904
905 // Just continue if breaks are disabled or debugger cannot be loaded.
906 if (disable_break() || !Load()) {
907 SetAfterBreakTarget(frame);
908 return Heap::undefined_value();
909 }
910
911 // Enter the debugger.
912 EnterDebugger debugger;
913 if (debugger.FailedToEnter()) {
914 return Heap::undefined_value();
915 }
916
917 // Postpone interrupt during breakpoint processing.
918 PostponeInterruptsScope postpone;
919
920 // Get the debug info (create it if it does not exist).
921 Handle<SharedFunctionInfo> shared =
922 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
923 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
924
925 // Find the break point where execution has stopped.
926 BreakLocationIterator break_location_iterator(debug_info,
927 ALL_BREAK_LOCATIONS);
928 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
929
930 // Check whether step next reached a new statement.
931 if (!StepNextContinue(&break_location_iterator, frame)) {
932 // Decrease steps left if performing multiple steps.
933 if (thread_local_.step_count_ > 0) {
934 thread_local_.step_count_--;
935 }
936 }
937
938 // If there is one or more real break points check whether any of these are
939 // triggered.
940 Handle<Object> break_points_hit(Heap::undefined_value());
941 if (break_location_iterator.HasBreakPoint()) {
942 Handle<Object> break_point_objects =
943 Handle<Object>(break_location_iterator.BreakPointObjects());
944 break_points_hit = CheckBreakPoints(break_point_objects);
945 }
946
947 // If step out is active skip everything until the frame where we need to step
948 // out to is reached, unless real breakpoint is hit.
949 if (Debug::StepOutActive() && frame->fp() != Debug::step_out_fp() &&
950 break_points_hit->IsUndefined() ) {
951 // Step count should always be 0 for StepOut.
952 ASSERT(thread_local_.step_count_ == 0);
953 } else if (!break_points_hit->IsUndefined() ||
954 (thread_local_.last_step_action_ != StepNone &&
955 thread_local_.step_count_ == 0)) {
956 // Notify debugger if a real break point is triggered or if performing
957 // single stepping with no more steps to perform. Otherwise do another step.
958
959 // Clear all current stepping setup.
960 ClearStepping();
961
962 // Notify the debug event listeners.
963 Debugger::OnDebugBreak(break_points_hit, false);
964 } else if (thread_local_.last_step_action_ != StepNone) {
965 // Hold on to last step action as it is cleared by the call to
966 // ClearStepping.
967 StepAction step_action = thread_local_.last_step_action_;
968 int step_count = thread_local_.step_count_;
969
970 // Clear all current stepping setup.
971 ClearStepping();
972
973 // Set up for the remaining steps.
974 PrepareStep(step_action, step_count);
975 }
976
Steve Block8defd9f2010-07-08 12:39:36 +0100977 if (thread_local_.frame_drop_mode_ == FRAMES_UNTOUCHED) {
978 SetAfterBreakTarget(frame);
979 } else if (thread_local_.frame_drop_mode_ == FRAME_DROPPED_IN_IC_CALL) {
980 // We must have been calling IC stub. Do not go there anymore.
Steve Block6ded16b2010-05-10 14:33:55 +0100981 Code* plain_return = Builtins::builtin(Builtins::PlainReturn_LiveEdit);
982 thread_local_.after_break_target_ = plain_return->entry();
Steve Block8defd9f2010-07-08 12:39:36 +0100983 } else if (thread_local_.frame_drop_mode_ ==
984 FRAME_DROPPED_IN_DEBUG_SLOT_CALL) {
985 // Debug break slot stub does not return normally, instead it manually
986 // cleans the stack and jumps. We should patch the jump address.
987 Code* plain_return = Builtins::builtin(Builtins::FrameDropper_LiveEdit);
988 thread_local_.after_break_target_ = plain_return->entry();
989 } else if (thread_local_.frame_drop_mode_ == FRAME_DROPPED_IN_DIRECT_CALL) {
990 // Nothing to do, after_break_target is not used here.
Steve Block6ded16b2010-05-10 14:33:55 +0100991 } else {
Steve Block8defd9f2010-07-08 12:39:36 +0100992 UNREACHABLE();
Steve Block6ded16b2010-05-10 14:33:55 +0100993 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000994
995 return Heap::undefined_value();
996}
997
998
999// Check the break point objects for whether one or more are actually
1000// triggered. This function returns a JSArray with the break point objects
1001// which is triggered.
1002Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) {
1003 int break_points_hit_count = 0;
1004 Handle<JSArray> break_points_hit = Factory::NewJSArray(1);
1005
1006 // If there are multiple break points they are in a FixedArray.
1007 ASSERT(!break_point_objects->IsUndefined());
1008 if (break_point_objects->IsFixedArray()) {
1009 Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
1010 for (int i = 0; i < array->length(); i++) {
1011 Handle<Object> o(array->get(i));
1012 if (CheckBreakPoint(o)) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001013 SetElement(break_points_hit, break_points_hit_count++, o);
Steve Blocka7e24c12009-10-30 11:49:00 +00001014 }
1015 }
1016 } else {
1017 if (CheckBreakPoint(break_point_objects)) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001018 SetElement(break_points_hit,
1019 break_points_hit_count++,
1020 break_point_objects);
Steve Blocka7e24c12009-10-30 11:49:00 +00001021 }
1022 }
1023
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001024 // Return undefined if no break points were triggered.
Steve Blocka7e24c12009-10-30 11:49:00 +00001025 if (break_points_hit_count == 0) {
1026 return Factory::undefined_value();
1027 }
1028 return break_points_hit;
1029}
1030
1031
1032// Check whether a single break point object is triggered.
1033bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
1034 HandleScope scope;
1035
1036 // Ignore check if break point object is not a JSObject.
1037 if (!break_point_object->IsJSObject()) return true;
1038
1039 // Get the function CheckBreakPoint (defined in debug.js).
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001040 Handle<String> is_break_point_triggered_symbol =
1041 Factory::LookupAsciiSymbol("IsBreakPointTriggered");
Steve Blocka7e24c12009-10-30 11:49:00 +00001042 Handle<JSFunction> check_break_point =
1043 Handle<JSFunction>(JSFunction::cast(
John Reck59135872010-11-02 12:39:01 -07001044 debug_context()->global()->GetPropertyNoExceptionThrown(
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001045 *is_break_point_triggered_symbol)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001046
1047 // Get the break id as an object.
1048 Handle<Object> break_id = Factory::NewNumberFromInt(Debug::break_id());
1049
1050 // Call HandleBreakPointx.
1051 bool caught_exception = false;
1052 const int argc = 2;
1053 Object** argv[argc] = {
1054 break_id.location(),
1055 reinterpret_cast<Object**>(break_point_object.location())
1056 };
1057 Handle<Object> result = Execution::TryCall(check_break_point,
1058 Top::builtins(), argc, argv,
1059 &caught_exception);
1060
1061 // If exception or non boolean result handle as not triggered
1062 if (caught_exception || !result->IsBoolean()) {
1063 return false;
1064 }
1065
1066 // Return whether the break point is triggered.
1067 return *result == Heap::true_value();
1068}
1069
1070
1071// Check whether the function has debug information.
1072bool Debug::HasDebugInfo(Handle<SharedFunctionInfo> shared) {
1073 return !shared->debug_info()->IsUndefined();
1074}
1075
1076
1077// Return the debug info for this function. EnsureDebugInfo must be called
1078// prior to ensure the debug info has been generated for shared.
1079Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) {
1080 ASSERT(HasDebugInfo(shared));
1081 return Handle<DebugInfo>(DebugInfo::cast(shared->debug_info()));
1082}
1083
1084
1085void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared,
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001086 Handle<Object> break_point_object,
1087 int* source_position) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001088 HandleScope scope;
1089
1090 if (!EnsureDebugInfo(shared)) {
1091 // Return if retrieving debug info failed.
1092 return;
1093 }
1094
1095 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1096 // Source positions starts with zero.
1097 ASSERT(source_position >= 0);
1098
1099 // Find the break point and change it.
1100 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001101 it.FindBreakLocationFromPosition(*source_position);
Steve Blocka7e24c12009-10-30 11:49:00 +00001102 it.SetBreakPoint(break_point_object);
1103
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001104 *source_position = it.position();
1105
Steve Blocka7e24c12009-10-30 11:49:00 +00001106 // At least one active break point now.
1107 ASSERT(debug_info->GetBreakPointCount() > 0);
1108}
1109
1110
1111void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
1112 HandleScope scope;
1113
1114 DebugInfoListNode* node = debug_info_list_;
1115 while (node != NULL) {
1116 Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(),
1117 break_point_object);
1118 if (!result->IsUndefined()) {
1119 // Get information in the break point.
1120 BreakPointInfo* break_point_info = BreakPointInfo::cast(result);
1121 Handle<DebugInfo> debug_info = node->debug_info();
1122 Handle<SharedFunctionInfo> shared(debug_info->shared());
1123 int source_position = break_point_info->statement_position()->value();
1124
1125 // Source positions starts with zero.
1126 ASSERT(source_position >= 0);
1127
1128 // Find the break point and clear it.
1129 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
1130 it.FindBreakLocationFromPosition(source_position);
1131 it.ClearBreakPoint(break_point_object);
1132
1133 // If there are no more break points left remove the debug info for this
1134 // function.
1135 if (debug_info->GetBreakPointCount() == 0) {
1136 RemoveDebugInfo(debug_info);
1137 }
1138
1139 return;
1140 }
1141 node = node->next();
1142 }
1143}
1144
1145
1146void Debug::ClearAllBreakPoints() {
1147 DebugInfoListNode* node = debug_info_list_;
1148 while (node != NULL) {
1149 // Remove all debug break code.
1150 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1151 it.ClearAllDebugBreak();
1152 node = node->next();
1153 }
1154
1155 // Remove all debug info.
1156 while (debug_info_list_ != NULL) {
1157 RemoveDebugInfo(debug_info_list_->debug_info());
1158 }
1159}
1160
1161
1162void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) {
1163 // Make sure the function has setup the debug info.
1164 if (!EnsureDebugInfo(shared)) {
1165 // Return if we failed to retrieve the debug info.
1166 return;
1167 }
1168
1169 // Flood the function with break points.
1170 BreakLocationIterator it(GetDebugInfo(shared), ALL_BREAK_LOCATIONS);
1171 while (!it.Done()) {
1172 it.SetOneShot();
1173 it.Next();
1174 }
1175}
1176
1177
1178void Debug::FloodHandlerWithOneShot() {
1179 // Iterate through the JavaScript stack looking for handlers.
1180 StackFrame::Id id = break_frame_id();
1181 if (id == StackFrame::NO_ID) {
1182 // If there is no JavaScript stack don't do anything.
1183 return;
1184 }
1185 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) {
1186 JavaScriptFrame* frame = it.frame();
1187 if (frame->HasHandler()) {
1188 Handle<SharedFunctionInfo> shared =
1189 Handle<SharedFunctionInfo>(
1190 JSFunction::cast(frame->function())->shared());
1191 // Flood the function with the catch block with break points
1192 FloodWithOneShot(shared);
1193 return;
1194 }
1195 }
1196}
1197
1198
1199void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
1200 if (type == BreakUncaughtException) {
1201 break_on_uncaught_exception_ = enable;
1202 } else {
1203 break_on_exception_ = enable;
1204 }
1205}
1206
1207
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001208bool Debug::IsBreakOnException(ExceptionBreakType type) {
1209 if (type == BreakUncaughtException) {
1210 return break_on_uncaught_exception_;
1211 } else {
1212 return break_on_exception_;
1213 }
1214}
1215
1216
Steve Blocka7e24c12009-10-30 11:49:00 +00001217void Debug::PrepareStep(StepAction step_action, int step_count) {
1218 HandleScope scope;
1219 ASSERT(Debug::InDebugger());
1220
1221 // Remember this step action and count.
1222 thread_local_.last_step_action_ = step_action;
1223 if (step_action == StepOut) {
1224 // For step out target frame will be found on the stack so there is no need
1225 // to set step counter for it. It's expected to always be 0 for StepOut.
1226 thread_local_.step_count_ = 0;
1227 } else {
1228 thread_local_.step_count_ = step_count;
1229 }
1230
1231 // Get the frame where the execution has stopped and skip the debug frame if
1232 // any. The debug frame will only be present if execution was stopped due to
1233 // hitting a break point. In other situations (e.g. unhandled exception) the
1234 // debug frame is not present.
1235 StackFrame::Id id = break_frame_id();
1236 if (id == StackFrame::NO_ID) {
1237 // If there is no JavaScript stack don't do anything.
1238 return;
1239 }
1240 JavaScriptFrameIterator frames_it(id);
1241 JavaScriptFrame* frame = frames_it.frame();
1242
1243 // First of all ensure there is one-shot break points in the top handler
1244 // if any.
1245 FloodHandlerWithOneShot();
1246
1247 // If the function on the top frame is unresolved perform step out. This will
1248 // be the case when calling unknown functions and having the debugger stopped
1249 // in an unhandled exception.
1250 if (!frame->function()->IsJSFunction()) {
1251 // Step out: Find the calling JavaScript frame and flood it with
1252 // breakpoints.
1253 frames_it.Advance();
1254 // Fill the function to return to with one-shot break points.
1255 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
1256 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1257 return;
1258 }
1259
1260 // Get the debug info (create it if it does not exist).
1261 Handle<SharedFunctionInfo> shared =
1262 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
1263 if (!EnsureDebugInfo(shared)) {
1264 // Return if ensuring debug info failed.
1265 return;
1266 }
1267 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1268
1269 // Find the break location where execution has stopped.
1270 BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS);
1271 it.FindBreakLocationFromAddress(frame->pc());
1272
1273 // Compute whether or not the target is a call target.
Steve Blocka7e24c12009-10-30 11:49:00 +00001274 bool is_load_or_store = false;
1275 bool is_inline_cache_stub = false;
Ben Murdochbb769b22010-08-11 14:56:33 +01001276 bool is_at_restarted_function = false;
Steve Blocka7e24c12009-10-30 11:49:00 +00001277 Handle<Code> call_function_stub;
Steve Blocka7e24c12009-10-30 11:49:00 +00001278
Ben Murdochbb769b22010-08-11 14:56:33 +01001279 if (thread_local_.restarter_frame_function_pointer_ == NULL) {
1280 if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) {
1281 bool is_call_target = false;
1282 Address target = it.rinfo()->target_address();
1283 Code* code = Code::GetCodeFromTargetAddress(target);
1284 if (code->is_call_stub() || code->is_keyed_call_stub()) {
1285 is_call_target = true;
1286 }
1287 if (code->is_inline_cache_stub()) {
1288 is_inline_cache_stub = true;
1289 is_load_or_store = !is_call_target;
1290 }
1291
1292 // Check if target code is CallFunction stub.
1293 Code* maybe_call_function_stub = code;
1294 // If there is a breakpoint at this line look at the original code to
1295 // check if it is a CallFunction stub.
1296 if (it.IsDebugBreak()) {
1297 Address original_target = it.original_rinfo()->target_address();
1298 maybe_call_function_stub =
1299 Code::GetCodeFromTargetAddress(original_target);
1300 }
1301 if (maybe_call_function_stub->kind() == Code::STUB &&
1302 maybe_call_function_stub->major_key() == CodeStub::CallFunction) {
1303 // Save reference to the code as we may need it to find out arguments
1304 // count for 'step in' later.
1305 call_function_stub = Handle<Code>(maybe_call_function_stub);
1306 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001307 }
Ben Murdochbb769b22010-08-11 14:56:33 +01001308 } else {
1309 is_at_restarted_function = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001310 }
1311
1312 // If this is the last break code target step out is the only possibility.
1313 if (it.IsExit() || step_action == StepOut) {
1314 if (step_action == StepOut) {
1315 // Skip step_count frames starting with the current one.
1316 while (step_count-- > 0 && !frames_it.done()) {
1317 frames_it.Advance();
1318 }
1319 } else {
1320 ASSERT(it.IsExit());
1321 frames_it.Advance();
1322 }
1323 // Skip builtin functions on the stack.
1324 while (!frames_it.done() &&
1325 JSFunction::cast(frames_it.frame()->function())->IsBuiltin()) {
1326 frames_it.Advance();
1327 }
1328 // Step out: If there is a JavaScript caller frame, we need to
1329 // flood it with breakpoints.
1330 if (!frames_it.done()) {
1331 // Fill the function to return to with one-shot break points.
1332 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
1333 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1334 // Set target frame pointer.
1335 ActivateStepOut(frames_it.frame());
1336 }
1337 } else if (!(is_inline_cache_stub || RelocInfo::IsConstructCall(it.rmode()) ||
Ben Murdochbb769b22010-08-11 14:56:33 +01001338 !call_function_stub.is_null() || is_at_restarted_function)
Steve Blocka7e24c12009-10-30 11:49:00 +00001339 || step_action == StepNext || step_action == StepMin) {
1340 // Step next or step min.
1341
1342 // Fill the current function with one-shot break points.
1343 FloodWithOneShot(shared);
1344
1345 // Remember source position and frame to handle step next.
1346 thread_local_.last_statement_position_ =
1347 debug_info->code()->SourceStatementPosition(frame->pc());
1348 thread_local_.last_fp_ = frame->fp();
1349 } else {
Ben Murdochbb769b22010-08-11 14:56:33 +01001350 // If there's restarter frame on top of the stack, just get the pointer
1351 // to function which is going to be restarted.
1352 if (is_at_restarted_function) {
1353 Handle<JSFunction> restarted_function(
1354 JSFunction::cast(*thread_local_.restarter_frame_function_pointer_));
1355 Handle<SharedFunctionInfo> restarted_shared(
1356 restarted_function->shared());
1357 FloodWithOneShot(restarted_shared);
1358 } else if (!call_function_stub.is_null()) {
1359 // If it's CallFunction stub ensure target function is compiled and flood
1360 // it with one shot breakpoints.
1361
Steve Blocka7e24c12009-10-30 11:49:00 +00001362 // Find out number of arguments from the stub minor key.
1363 // Reverse lookup required as the minor key cannot be retrieved
1364 // from the code object.
1365 Handle<Object> obj(
1366 Heap::code_stubs()->SlowReverseLookup(*call_function_stub));
1367 ASSERT(*obj != Heap::undefined_value());
1368 ASSERT(obj->IsSmi());
1369 // Get the STUB key and extract major and minor key.
1370 uint32_t key = Smi::cast(*obj)->value();
1371 // Argc in the stub is the number of arguments passed - not the
1372 // expected arguments of the called function.
Leon Clarkee46be812010-01-19 14:06:41 +00001373 int call_function_arg_count =
1374 CallFunctionStub::ExtractArgcFromMinorKey(
1375 CodeStub::MinorKeyFromKey(key));
Steve Blocka7e24c12009-10-30 11:49:00 +00001376 ASSERT(call_function_stub->major_key() ==
1377 CodeStub::MajorKeyFromKey(key));
1378
1379 // Find target function on the expression stack.
Leon Clarkee46be812010-01-19 14:06:41 +00001380 // Expression stack looks like this (top to bottom):
Steve Blocka7e24c12009-10-30 11:49:00 +00001381 // argN
1382 // ...
1383 // arg0
1384 // Receiver
1385 // Function to call
1386 int expressions_count = frame->ComputeExpressionsCount();
1387 ASSERT(expressions_count - 2 - call_function_arg_count >= 0);
1388 Object* fun = frame->GetExpression(
1389 expressions_count - 2 - call_function_arg_count);
1390 if (fun->IsJSFunction()) {
1391 Handle<JSFunction> js_function(JSFunction::cast(fun));
1392 // Don't step into builtins.
1393 if (!js_function->IsBuiltin()) {
1394 // It will also compile target function if it's not compiled yet.
1395 FloodWithOneShot(Handle<SharedFunctionInfo>(js_function->shared()));
1396 }
1397 }
1398 }
1399
1400 // Fill the current function with one-shot break points even for step in on
1401 // a call target as the function called might be a native function for
1402 // which step in will not stop. It also prepares for stepping in
1403 // getters/setters.
1404 FloodWithOneShot(shared);
1405
1406 if (is_load_or_store) {
1407 // Remember source position and frame to handle step in getter/setter. If
1408 // there is a custom getter/setter it will be handled in
1409 // Object::Get/SetPropertyWithCallback, otherwise the step action will be
1410 // propagated on the next Debug::Break.
1411 thread_local_.last_statement_position_ =
1412 debug_info->code()->SourceStatementPosition(frame->pc());
1413 thread_local_.last_fp_ = frame->fp();
1414 }
1415
1416 // Step in or Step in min
1417 it.PrepareStepIn();
1418 ActivateStepIn(frame);
1419 }
1420}
1421
1422
1423// Check whether the current debug break should be reported to the debugger. It
1424// is used to have step next and step in only report break back to the debugger
1425// if on a different frame or in a different statement. In some situations
1426// there will be several break points in the same statement when the code is
1427// flooded with one-shot break points. This function helps to perform several
1428// steps before reporting break back to the debugger.
1429bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
1430 JavaScriptFrame* frame) {
1431 // If the step last action was step next or step in make sure that a new
1432 // statement is hit.
1433 if (thread_local_.last_step_action_ == StepNext ||
1434 thread_local_.last_step_action_ == StepIn) {
1435 // Never continue if returning from function.
1436 if (break_location_iterator->IsExit()) return false;
1437
1438 // Continue if we are still on the same frame and in the same statement.
1439 int current_statement_position =
1440 break_location_iterator->code()->SourceStatementPosition(frame->pc());
1441 return thread_local_.last_fp_ == frame->fp() &&
1442 thread_local_.last_statement_position_ == current_statement_position;
1443 }
1444
1445 // No step next action - don't continue.
1446 return false;
1447}
1448
1449
1450// Check whether the code object at the specified address is a debug break code
1451// object.
1452bool Debug::IsDebugBreak(Address addr) {
1453 Code* code = Code::GetCodeFromTargetAddress(addr);
1454 return code->ic_state() == DEBUG_BREAK;
1455}
1456
1457
1458// Check whether a code stub with the specified major key is a possible break
1459// point location when looking for source break locations.
1460bool Debug::IsSourceBreakStub(Code* code) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001461 CodeStub::Major major_key = CodeStub::GetMajorKey(code);
Steve Blocka7e24c12009-10-30 11:49:00 +00001462 return major_key == CodeStub::CallFunction;
1463}
1464
1465
1466// Check whether a code stub with the specified major key is a possible break
1467// location.
1468bool Debug::IsBreakStub(Code* code) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001469 CodeStub::Major major_key = CodeStub::GetMajorKey(code);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001470 return major_key == CodeStub::CallFunction;
Steve Blocka7e24c12009-10-30 11:49:00 +00001471}
1472
1473
1474// Find the builtin to use for invoking the debug break
1475Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
1476 // Find the builtin debug break function matching the calling convention
1477 // used by the call site.
1478 if (code->is_inline_cache_stub()) {
Steve Block6ded16b2010-05-10 14:33:55 +01001479 switch (code->kind()) {
1480 case Code::CALL_IC:
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001481 case Code::KEYED_CALL_IC:
1482 return ComputeCallDebugBreak(code->arguments_count(), code->kind());
Steve Block6ded16b2010-05-10 14:33:55 +01001483
1484 case Code::LOAD_IC:
1485 return Handle<Code>(Builtins::builtin(Builtins::LoadIC_DebugBreak));
1486
1487 case Code::STORE_IC:
1488 return Handle<Code>(Builtins::builtin(Builtins::StoreIC_DebugBreak));
1489
1490 case Code::KEYED_LOAD_IC:
1491 return Handle<Code>(
1492 Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak));
1493
1494 case Code::KEYED_STORE_IC:
1495 return Handle<Code>(
1496 Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak));
1497
1498 default:
1499 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00001500 }
1501 }
1502 if (RelocInfo::IsConstructCall(mode)) {
1503 Handle<Code> result =
1504 Handle<Code>(Builtins::builtin(Builtins::ConstructCall_DebugBreak));
1505 return result;
1506 }
1507 if (code->kind() == Code::STUB) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001508 ASSERT(code->major_key() == CodeStub::CallFunction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001509 Handle<Code> result =
1510 Handle<Code>(Builtins::builtin(Builtins::StubNoRegisters_DebugBreak));
1511 return result;
1512 }
1513
1514 UNREACHABLE();
1515 return Handle<Code>::null();
1516}
1517
1518
1519// Simple function for returning the source positions for active break points.
1520Handle<Object> Debug::GetSourceBreakLocations(
1521 Handle<SharedFunctionInfo> shared) {
1522 if (!HasDebugInfo(shared)) return Handle<Object>(Heap::undefined_value());
1523 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1524 if (debug_info->GetBreakPointCount() == 0) {
1525 return Handle<Object>(Heap::undefined_value());
1526 }
1527 Handle<FixedArray> locations =
1528 Factory::NewFixedArray(debug_info->GetBreakPointCount());
1529 int count = 0;
1530 for (int i = 0; i < debug_info->break_points()->length(); i++) {
1531 if (!debug_info->break_points()->get(i)->IsUndefined()) {
1532 BreakPointInfo* break_point_info =
1533 BreakPointInfo::cast(debug_info->break_points()->get(i));
1534 if (break_point_info->GetBreakPointCount() > 0) {
1535 locations->set(count++, break_point_info->statement_position());
1536 }
1537 }
1538 }
1539 return locations;
1540}
1541
1542
1543void Debug::NewBreak(StackFrame::Id break_frame_id) {
1544 thread_local_.break_frame_id_ = break_frame_id;
1545 thread_local_.break_id_ = ++thread_local_.break_count_;
1546}
1547
1548
1549void Debug::SetBreak(StackFrame::Id break_frame_id, int break_id) {
1550 thread_local_.break_frame_id_ = break_frame_id;
1551 thread_local_.break_id_ = break_id;
1552}
1553
1554
1555// Handle stepping into a function.
1556void Debug::HandleStepIn(Handle<JSFunction> function,
1557 Handle<Object> holder,
1558 Address fp,
1559 bool is_constructor) {
1560 // If the frame pointer is not supplied by the caller find it.
1561 if (fp == 0) {
1562 StackFrameIterator it;
1563 it.Advance();
1564 // For constructor functions skip another frame.
1565 if (is_constructor) {
1566 ASSERT(it.frame()->is_construct());
1567 it.Advance();
1568 }
1569 fp = it.frame()->fp();
1570 }
1571
1572 // Flood the function with one-shot break points if it is called from where
1573 // step into was requested.
1574 if (fp == Debug::step_in_fp()) {
1575 // Don't allow step into functions in the native context.
1576 if (!function->IsBuiltin()) {
1577 if (function->shared()->code() ==
1578 Builtins::builtin(Builtins::FunctionApply) ||
1579 function->shared()->code() ==
1580 Builtins::builtin(Builtins::FunctionCall)) {
1581 // Handle function.apply and function.call separately to flood the
1582 // function to be called and not the code for Builtins::FunctionApply or
1583 // Builtins::FunctionCall. The receiver of call/apply is the target
1584 // function.
1585 if (!holder.is_null() && holder->IsJSFunction() &&
1586 !JSFunction::cast(*holder)->IsBuiltin()) {
1587 Handle<SharedFunctionInfo> shared_info(
1588 JSFunction::cast(*holder)->shared());
1589 Debug::FloodWithOneShot(shared_info);
1590 }
1591 } else {
1592 Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1593 }
1594 }
1595 }
1596}
1597
1598
1599void Debug::ClearStepping() {
1600 // Clear the various stepping setup.
1601 ClearOneShot();
1602 ClearStepIn();
1603 ClearStepOut();
1604 ClearStepNext();
1605
1606 // Clear multiple step counter.
1607 thread_local_.step_count_ = 0;
1608}
1609
1610// Clears all the one-shot break points that are currently set. Normally this
1611// function is called each time a break point is hit as one shot break points
1612// are used to support stepping.
1613void Debug::ClearOneShot() {
1614 // The current implementation just runs through all the breakpoints. When the
1615 // last break point for a function is removed that function is automatically
1616 // removed from the list.
1617
1618 DebugInfoListNode* node = debug_info_list_;
1619 while (node != NULL) {
1620 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1621 while (!it.Done()) {
1622 it.ClearOneShot();
1623 it.Next();
1624 }
1625 node = node->next();
1626 }
1627}
1628
1629
1630void Debug::ActivateStepIn(StackFrame* frame) {
1631 ASSERT(!StepOutActive());
1632 thread_local_.step_into_fp_ = frame->fp();
1633}
1634
1635
1636void Debug::ClearStepIn() {
1637 thread_local_.step_into_fp_ = 0;
1638}
1639
1640
1641void Debug::ActivateStepOut(StackFrame* frame) {
1642 ASSERT(!StepInActive());
1643 thread_local_.step_out_fp_ = frame->fp();
1644}
1645
1646
1647void Debug::ClearStepOut() {
1648 thread_local_.step_out_fp_ = 0;
1649}
1650
1651
1652void Debug::ClearStepNext() {
1653 thread_local_.last_step_action_ = StepNone;
1654 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
1655 thread_local_.last_fp_ = 0;
1656}
1657
1658
Steve Blocka7e24c12009-10-30 11:49:00 +00001659// Ensures the debug information is present for shared.
1660bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
1661 // Return if we already have the debug info for shared.
1662 if (HasDebugInfo(shared)) return true;
1663
1664 // Ensure shared in compiled. Return false if this failed.
Leon Clarke4515c472010-02-03 11:58:03 +00001665 if (!EnsureCompiled(shared, CLEAR_EXCEPTION)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00001666
Ben Murdochb0fe1622011-05-05 13:52:32 +01001667 // If preparing for the first break point make sure to deoptimize all
1668 // functions as debugging does not work with optimized code.
1669 if (!has_break_points_) {
1670 Deoptimizer::DeoptimizeAll();
1671 }
1672
Steve Blocka7e24c12009-10-30 11:49:00 +00001673 // Create the debug info object.
1674 Handle<DebugInfo> debug_info = Factory::NewDebugInfo(shared);
1675
1676 // Add debug info to the list.
1677 DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
1678 node->set_next(debug_info_list_);
1679 debug_info_list_ = node;
1680
1681 // Now there is at least one break point.
1682 has_break_points_ = true;
1683
1684 return true;
1685}
1686
1687
1688void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
1689 ASSERT(debug_info_list_ != NULL);
1690 // Run through the debug info objects to find this one and remove it.
1691 DebugInfoListNode* prev = NULL;
1692 DebugInfoListNode* current = debug_info_list_;
1693 while (current != NULL) {
1694 if (*current->debug_info() == *debug_info) {
1695 // Unlink from list. If prev is NULL we are looking at the first element.
1696 if (prev == NULL) {
1697 debug_info_list_ = current->next();
1698 } else {
1699 prev->set_next(current->next());
1700 }
1701 current->debug_info()->shared()->set_debug_info(Heap::undefined_value());
1702 delete current;
1703
1704 // If there are no more debug info objects there are not more break
1705 // points.
1706 has_break_points_ = debug_info_list_ != NULL;
1707
1708 return;
1709 }
1710 // Move to next in list.
1711 prev = current;
1712 current = current->next();
1713 }
1714 UNREACHABLE();
1715}
1716
1717
1718void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
1719 HandleScope scope;
1720
1721 // Get the executing function in which the debug break occurred.
1722 Handle<SharedFunctionInfo> shared =
1723 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
1724 if (!EnsureDebugInfo(shared)) {
1725 // Return if we failed to retrieve the debug info.
1726 return;
1727 }
1728 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1729 Handle<Code> code(debug_info->code());
1730 Handle<Code> original_code(debug_info->original_code());
1731#ifdef DEBUG
1732 // Get the code which is actually executing.
1733 Handle<Code> frame_code(frame->code());
1734 ASSERT(frame_code.is_identical_to(code));
1735#endif
1736
1737 // Find the call address in the running code. This address holds the call to
1738 // either a DebugBreakXXX or to the debug break return entry code if the
1739 // break point is still active after processing the break point.
1740 Address addr = frame->pc() - Assembler::kCallTargetAddressOffset;
1741
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001742 // Check if the location is at JS exit or debug break slot.
Steve Blocka7e24c12009-10-30 11:49:00 +00001743 bool at_js_return = false;
1744 bool break_at_js_return_active = false;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001745 bool at_debug_break_slot = false;
Steve Blocka7e24c12009-10-30 11:49:00 +00001746 RelocIterator it(debug_info->code());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001747 while (!it.done() && !at_js_return && !at_debug_break_slot) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001748 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
1749 at_js_return = (it.rinfo()->pc() ==
1750 addr - Assembler::kPatchReturnSequenceAddressOffset);
Steve Block3ce2e202009-11-05 08:53:23 +00001751 break_at_js_return_active = it.rinfo()->IsPatchedReturnSequence();
Steve Blocka7e24c12009-10-30 11:49:00 +00001752 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001753 if (RelocInfo::IsDebugBreakSlot(it.rinfo()->rmode())) {
1754 at_debug_break_slot = (it.rinfo()->pc() ==
1755 addr - Assembler::kPatchDebugBreakSlotAddressOffset);
1756 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001757 it.next();
1758 }
1759
1760 // Handle the jump to continue execution after break point depending on the
1761 // break location.
1762 if (at_js_return) {
1763 // If the break point as return is still active jump to the corresponding
1764 // place in the original code. If not the break point was removed during
1765 // break point processing.
1766 if (break_at_js_return_active) {
1767 addr += original_code->instruction_start() - code->instruction_start();
1768 }
1769
1770 // Move back to where the call instruction sequence started.
1771 thread_local_.after_break_target_ =
1772 addr - Assembler::kPatchReturnSequenceAddressOffset;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001773 } else if (at_debug_break_slot) {
1774 // Address of where the debug break slot starts.
1775 addr = addr - Assembler::kPatchDebugBreakSlotAddressOffset;
Steve Blocka7e24c12009-10-30 11:49:00 +00001776
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001777 // Continue just after the slot.
1778 thread_local_.after_break_target_ = addr + Assembler::kDebugBreakSlotLength;
1779 } else if (IsDebugBreak(Assembler::target_address_at(addr))) {
1780 // We now know that there is still a debug break call at the target address,
1781 // so the break point is still there and the original code will hold the
1782 // address to jump to in order to complete the call which is replaced by a
1783 // call to DebugBreakXXX.
1784
1785 // Find the corresponding address in the original code.
1786 addr += original_code->instruction_start() - code->instruction_start();
Steve Blocka7e24c12009-10-30 11:49:00 +00001787
1788 // Install jump to the call address in the original code. This will be the
1789 // call which was overwritten by the call to DebugBreakXXX.
1790 thread_local_.after_break_target_ = Assembler::target_address_at(addr);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001791 } else {
1792 // There is no longer a break point present. Don't try to look in the
1793 // original code as the running code will have the right address. This takes
1794 // care of the case where the last break point is removed from the function
1795 // and therefore no "original code" is available.
1796 thread_local_.after_break_target_ = Assembler::target_address_at(addr);
Steve Blocka7e24c12009-10-30 11:49:00 +00001797 }
1798}
1799
1800
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001801bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
1802 HandleScope scope;
1803
1804 // Get the executing function in which the debug break occurred.
1805 Handle<SharedFunctionInfo> shared =
1806 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
1807 if (!EnsureDebugInfo(shared)) {
1808 // Return if we failed to retrieve the debug info.
1809 return false;
1810 }
1811 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1812 Handle<Code> code(debug_info->code());
1813#ifdef DEBUG
1814 // Get the code which is actually executing.
1815 Handle<Code> frame_code(frame->code());
1816 ASSERT(frame_code.is_identical_to(code));
1817#endif
1818
1819 // Find the call address in the running code.
1820 Address addr = frame->pc() - Assembler::kCallTargetAddressOffset;
1821
1822 // Check if the location is at JS return.
1823 RelocIterator it(debug_info->code());
1824 while (!it.done()) {
1825 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
1826 return (it.rinfo()->pc() ==
1827 addr - Assembler::kPatchReturnSequenceAddressOffset);
1828 }
1829 it.next();
1830 }
1831 return false;
1832}
1833
1834
Steve Block8defd9f2010-07-08 12:39:36 +01001835void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
Ben Murdochbb769b22010-08-11 14:56:33 +01001836 FrameDropMode mode,
1837 Object** restarter_frame_function_pointer) {
Steve Block8defd9f2010-07-08 12:39:36 +01001838 thread_local_.frame_drop_mode_ = mode;
Steve Block6ded16b2010-05-10 14:33:55 +01001839 thread_local_.break_frame_id_ = new_break_frame_id;
Ben Murdochbb769b22010-08-11 14:56:33 +01001840 thread_local_.restarter_frame_function_pointer_ =
1841 restarter_frame_function_pointer;
Steve Block6ded16b2010-05-10 14:33:55 +01001842}
1843
1844
Steve Blocka7e24c12009-10-30 11:49:00 +00001845bool Debug::IsDebugGlobal(GlobalObject* global) {
1846 return IsLoaded() && global == Debug::debug_context()->global();
1847}
1848
1849
1850void Debug::ClearMirrorCache() {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001851 PostponeInterruptsScope postpone;
Steve Blocka7e24c12009-10-30 11:49:00 +00001852 HandleScope scope;
1853 ASSERT(Top::context() == *Debug::debug_context());
1854
1855 // Clear the mirror cache.
1856 Handle<String> function_name =
1857 Factory::LookupSymbol(CStrVector("ClearMirrorCache"));
John Reck59135872010-11-02 12:39:01 -07001858 Handle<Object> fun(Top::global()->GetPropertyNoExceptionThrown(
1859 *function_name));
Steve Blocka7e24c12009-10-30 11:49:00 +00001860 ASSERT(fun->IsJSFunction());
1861 bool caught_exception;
1862 Handle<Object> js_object = Execution::TryCall(
1863 Handle<JSFunction>::cast(fun),
1864 Handle<JSObject>(Debug::debug_context()->global()),
1865 0, NULL, &caught_exception);
1866}
1867
1868
Steve Blocka7e24c12009-10-30 11:49:00 +00001869void Debug::CreateScriptCache() {
1870 HandleScope scope;
1871
1872 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
1873 // rid of all the cached script wrappers and the second gets rid of the
Andrei Popescu31002712010-02-23 13:46:05 +00001874 // scripts which are no longer referenced.
Steve Blocka7e24c12009-10-30 11:49:00 +00001875 Heap::CollectAllGarbage(false);
1876 Heap::CollectAllGarbage(false);
1877
1878 ASSERT(script_cache_ == NULL);
1879 script_cache_ = new ScriptCache();
1880
1881 // Scan heap for Script objects.
1882 int count = 0;
1883 HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +00001884 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
Steve Block3ce2e202009-11-05 08:53:23 +00001885 if (obj->IsScript() && Script::cast(obj)->HasValidSource()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001886 script_cache_->Add(Handle<Script>(Script::cast(obj)));
1887 count++;
1888 }
1889 }
1890}
1891
1892
1893void Debug::DestroyScriptCache() {
1894 // Get rid of the script cache if it was created.
1895 if (script_cache_ != NULL) {
1896 delete script_cache_;
1897 script_cache_ = NULL;
1898 }
1899}
1900
1901
1902void Debug::AddScriptToScriptCache(Handle<Script> script) {
1903 if (script_cache_ != NULL) {
1904 script_cache_->Add(script);
1905 }
1906}
1907
1908
1909Handle<FixedArray> Debug::GetLoadedScripts() {
1910 // Create and fill the script cache when the loaded scripts is requested for
1911 // the first time.
1912 if (script_cache_ == NULL) {
1913 CreateScriptCache();
1914 }
1915
1916 // If the script cache is not active just return an empty array.
1917 ASSERT(script_cache_ != NULL);
1918 if (script_cache_ == NULL) {
1919 Factory::NewFixedArray(0);
1920 }
1921
1922 // Perform GC to get unreferenced scripts evicted from the cache before
1923 // returning the content.
1924 Heap::CollectAllGarbage(false);
1925
1926 // Get the scripts from the cache.
1927 return script_cache_->GetScripts();
1928}
1929
1930
1931void Debug::AfterGarbageCollection() {
1932 // Generate events for collected scripts.
1933 if (script_cache_ != NULL) {
1934 script_cache_->ProcessCollectedScripts();
1935 }
1936}
1937
1938
1939Mutex* Debugger::debugger_access_ = OS::CreateMutex();
1940Handle<Object> Debugger::event_listener_ = Handle<Object>();
1941Handle<Object> Debugger::event_listener_data_ = Handle<Object>();
1942bool Debugger::compiling_natives_ = false;
1943bool Debugger::is_loading_debugger_ = false;
1944bool Debugger::never_unload_debugger_ = false;
1945v8::Debug::MessageHandler2 Debugger::message_handler_ = NULL;
1946bool Debugger::debugger_unload_pending_ = false;
1947v8::Debug::HostDispatchHandler Debugger::host_dispatch_handler_ = NULL;
Leon Clarkee46be812010-01-19 14:06:41 +00001948Mutex* Debugger::dispatch_handler_access_ = OS::CreateMutex();
Steve Blockd0582a62009-12-15 09:54:21 +00001949v8::Debug::DebugMessageDispatchHandler
1950 Debugger::debug_message_dispatch_handler_ = NULL;
Leon Clarkee46be812010-01-19 14:06:41 +00001951MessageDispatchHelperThread* Debugger::message_dispatch_helper_thread_ = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +00001952int Debugger::host_dispatch_micros_ = 100 * 1000;
1953DebuggerAgent* Debugger::agent_ = NULL;
1954LockingCommandMessageQueue Debugger::command_queue_(kQueueInitialSize);
1955Semaphore* Debugger::command_received_ = OS::CreateSemaphore(0);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01001956LockingCommandMessageQueue Debugger::event_command_queue_(kQueueInitialSize);
Steve Blocka7e24c12009-10-30 11:49:00 +00001957
1958
1959Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
1960 int argc, Object*** argv,
1961 bool* caught_exception) {
1962 ASSERT(Top::context() == *Debug::debug_context());
1963
1964 // Create the execution state object.
1965 Handle<String> constructor_str = Factory::LookupSymbol(constructor_name);
John Reck59135872010-11-02 12:39:01 -07001966 Handle<Object> constructor(Top::global()->GetPropertyNoExceptionThrown(
1967 *constructor_str));
Steve Blocka7e24c12009-10-30 11:49:00 +00001968 ASSERT(constructor->IsJSFunction());
1969 if (!constructor->IsJSFunction()) {
1970 *caught_exception = true;
1971 return Factory::undefined_value();
1972 }
1973 Handle<Object> js_object = Execution::TryCall(
1974 Handle<JSFunction>::cast(constructor),
1975 Handle<JSObject>(Debug::debug_context()->global()), argc, argv,
1976 caught_exception);
1977 return js_object;
1978}
1979
1980
1981Handle<Object> Debugger::MakeExecutionState(bool* caught_exception) {
1982 // Create the execution state object.
1983 Handle<Object> break_id = Factory::NewNumberFromInt(Debug::break_id());
1984 const int argc = 1;
1985 Object** argv[argc] = { break_id.location() };
1986 return MakeJSObject(CStrVector("MakeExecutionState"),
1987 argc, argv, caught_exception);
1988}
1989
1990
1991Handle<Object> Debugger::MakeBreakEvent(Handle<Object> exec_state,
1992 Handle<Object> break_points_hit,
1993 bool* caught_exception) {
1994 // Create the new break event object.
1995 const int argc = 2;
1996 Object** argv[argc] = { exec_state.location(),
1997 break_points_hit.location() };
1998 return MakeJSObject(CStrVector("MakeBreakEvent"),
1999 argc,
2000 argv,
2001 caught_exception);
2002}
2003
2004
2005Handle<Object> Debugger::MakeExceptionEvent(Handle<Object> exec_state,
2006 Handle<Object> exception,
2007 bool uncaught,
2008 bool* caught_exception) {
2009 // Create the new exception event object.
2010 const int argc = 3;
2011 Object** argv[argc] = { exec_state.location(),
2012 exception.location(),
2013 uncaught ? Factory::true_value().location() :
2014 Factory::false_value().location()};
2015 return MakeJSObject(CStrVector("MakeExceptionEvent"),
2016 argc, argv, caught_exception);
2017}
2018
2019
2020Handle<Object> Debugger::MakeNewFunctionEvent(Handle<Object> function,
2021 bool* caught_exception) {
2022 // Create the new function event object.
2023 const int argc = 1;
2024 Object** argv[argc] = { function.location() };
2025 return MakeJSObject(CStrVector("MakeNewFunctionEvent"),
2026 argc, argv, caught_exception);
2027}
2028
2029
2030Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
2031 bool before,
2032 bool* caught_exception) {
2033 // Create the compile event object.
2034 Handle<Object> exec_state = MakeExecutionState(caught_exception);
2035 Handle<Object> script_wrapper = GetScriptWrapper(script);
2036 const int argc = 3;
2037 Object** argv[argc] = { exec_state.location(),
2038 script_wrapper.location(),
2039 before ? Factory::true_value().location() :
2040 Factory::false_value().location() };
2041
2042 return MakeJSObject(CStrVector("MakeCompileEvent"),
2043 argc,
2044 argv,
2045 caught_exception);
2046}
2047
2048
2049Handle<Object> Debugger::MakeScriptCollectedEvent(int id,
2050 bool* caught_exception) {
2051 // Create the script collected event object.
2052 Handle<Object> exec_state = MakeExecutionState(caught_exception);
2053 Handle<Object> id_object = Handle<Smi>(Smi::FromInt(id));
2054 const int argc = 2;
2055 Object** argv[argc] = { exec_state.location(), id_object.location() };
2056
2057 return MakeJSObject(CStrVector("MakeScriptCollectedEvent"),
2058 argc,
2059 argv,
2060 caught_exception);
2061}
2062
2063
2064void Debugger::OnException(Handle<Object> exception, bool uncaught) {
2065 HandleScope scope;
2066
2067 // Bail out based on state or if there is no listener for this event
2068 if (Debug::InDebugger()) return;
2069 if (!Debugger::EventActive(v8::Exception)) return;
2070
2071 // Bail out if exception breaks are not active
2072 if (uncaught) {
2073 // Uncaught exceptions are reported by either flags.
2074 if (!(Debug::break_on_uncaught_exception() ||
2075 Debug::break_on_exception())) return;
2076 } else {
2077 // Caught exceptions are reported is activated.
2078 if (!Debug::break_on_exception()) return;
2079 }
2080
2081 // Enter the debugger.
2082 EnterDebugger debugger;
2083 if (debugger.FailedToEnter()) return;
2084
2085 // Clear all current stepping setup.
2086 Debug::ClearStepping();
2087 // Create the event data object.
2088 bool caught_exception = false;
2089 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2090 Handle<Object> event_data;
2091 if (!caught_exception) {
2092 event_data = MakeExceptionEvent(exec_state, exception, uncaught,
2093 &caught_exception);
2094 }
2095 // Bail out and don't call debugger if exception.
2096 if (caught_exception) {
2097 return;
2098 }
2099
2100 // Process debug event.
2101 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false);
2102 // Return to continue execution from where the exception was thrown.
2103}
2104
2105
2106void Debugger::OnDebugBreak(Handle<Object> break_points_hit,
2107 bool auto_continue) {
2108 HandleScope scope;
2109
2110 // Debugger has already been entered by caller.
2111 ASSERT(Top::context() == *Debug::debug_context());
2112
2113 // Bail out if there is no listener for this event
2114 if (!Debugger::EventActive(v8::Break)) return;
2115
2116 // Debugger must be entered in advance.
2117 ASSERT(Top::context() == *Debug::debug_context());
2118
2119 // Create the event data object.
2120 bool caught_exception = false;
2121 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2122 Handle<Object> event_data;
2123 if (!caught_exception) {
2124 event_data = MakeBreakEvent(exec_state, break_points_hit,
2125 &caught_exception);
2126 }
2127 // Bail out and don't call debugger if exception.
2128 if (caught_exception) {
2129 return;
2130 }
2131
2132 // Process debug event.
2133 ProcessDebugEvent(v8::Break,
2134 Handle<JSObject>::cast(event_data),
2135 auto_continue);
2136}
2137
2138
2139void Debugger::OnBeforeCompile(Handle<Script> script) {
2140 HandleScope scope;
2141
2142 // Bail out based on state or if there is no listener for this event
2143 if (Debug::InDebugger()) return;
2144 if (compiling_natives()) return;
2145 if (!EventActive(v8::BeforeCompile)) return;
2146
2147 // Enter the debugger.
2148 EnterDebugger debugger;
2149 if (debugger.FailedToEnter()) return;
2150
2151 // Create the event data object.
2152 bool caught_exception = false;
2153 Handle<Object> event_data = MakeCompileEvent(script, true, &caught_exception);
2154 // Bail out and don't call debugger if exception.
2155 if (caught_exception) {
2156 return;
2157 }
2158
2159 // Process debug event.
2160 ProcessDebugEvent(v8::BeforeCompile,
2161 Handle<JSObject>::cast(event_data),
2162 true);
2163}
2164
2165
2166// Handle debugger actions when a new script is compiled.
Steve Block6ded16b2010-05-10 14:33:55 +01002167void Debugger::OnAfterCompile(Handle<Script> script,
2168 AfterCompileFlags after_compile_flags) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002169 HandleScope scope;
2170
2171 // Add the newly compiled script to the script cache.
2172 Debug::AddScriptToScriptCache(script);
2173
2174 // No more to do if not debugging.
2175 if (!IsDebuggerActive()) return;
2176
2177 // No compile events while compiling natives.
2178 if (compiling_natives()) return;
2179
2180 // Store whether in debugger before entering debugger.
2181 bool in_debugger = Debug::InDebugger();
2182
2183 // Enter the debugger.
2184 EnterDebugger debugger;
2185 if (debugger.FailedToEnter()) return;
2186
2187 // If debugging there might be script break points registered for this
2188 // script. Make sure that these break points are set.
2189
Andrei Popescu31002712010-02-23 13:46:05 +00002190 // Get the function UpdateScriptBreakPoints (defined in debug-debugger.js).
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002191 Handle<String> update_script_break_points_symbol =
2192 Factory::LookupAsciiSymbol("UpdateScriptBreakPoints");
Steve Blocka7e24c12009-10-30 11:49:00 +00002193 Handle<Object> update_script_break_points =
John Reck59135872010-11-02 12:39:01 -07002194 Handle<Object>(Debug::debug_context()->global()->
2195 GetPropertyNoExceptionThrown(*update_script_break_points_symbol));
Steve Blocka7e24c12009-10-30 11:49:00 +00002196 if (!update_script_break_points->IsJSFunction()) {
2197 return;
2198 }
2199 ASSERT(update_script_break_points->IsJSFunction());
2200
2201 // Wrap the script object in a proper JS object before passing it
2202 // to JavaScript.
2203 Handle<JSValue> wrapper = GetScriptWrapper(script);
2204
2205 // Call UpdateScriptBreakPoints expect no exceptions.
2206 bool caught_exception = false;
2207 const int argc = 1;
2208 Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) };
2209 Handle<Object> result = Execution::TryCall(
2210 Handle<JSFunction>::cast(update_script_break_points),
2211 Top::builtins(), argc, argv,
2212 &caught_exception);
2213 if (caught_exception) {
2214 return;
2215 }
2216 // Bail out based on state or if there is no listener for this event
Steve Block6ded16b2010-05-10 14:33:55 +01002217 if (in_debugger && (after_compile_flags & SEND_WHEN_DEBUGGING) == 0) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002218 if (!Debugger::EventActive(v8::AfterCompile)) return;
2219
2220 // Create the compile state object.
2221 Handle<Object> event_data = MakeCompileEvent(script,
2222 false,
2223 &caught_exception);
2224 // Bail out and don't call debugger if exception.
2225 if (caught_exception) {
2226 return;
2227 }
2228 // Process debug event.
2229 ProcessDebugEvent(v8::AfterCompile,
2230 Handle<JSObject>::cast(event_data),
2231 true);
2232}
2233
2234
Steve Blocka7e24c12009-10-30 11:49:00 +00002235void Debugger::OnScriptCollected(int id) {
2236 HandleScope scope;
2237
2238 // No more to do if not debugging.
2239 if (!IsDebuggerActive()) return;
2240 if (!Debugger::EventActive(v8::ScriptCollected)) return;
2241
2242 // Enter the debugger.
2243 EnterDebugger debugger;
2244 if (debugger.FailedToEnter()) return;
2245
2246 // Create the script collected state object.
2247 bool caught_exception = false;
2248 Handle<Object> event_data = MakeScriptCollectedEvent(id,
2249 &caught_exception);
2250 // Bail out and don't call debugger if exception.
2251 if (caught_exception) {
2252 return;
2253 }
2254
2255 // Process debug event.
2256 ProcessDebugEvent(v8::ScriptCollected,
2257 Handle<JSObject>::cast(event_data),
2258 true);
2259}
2260
2261
2262void Debugger::ProcessDebugEvent(v8::DebugEvent event,
2263 Handle<JSObject> event_data,
2264 bool auto_continue) {
2265 HandleScope scope;
2266
2267 // Clear any pending debug break if this is a real break.
2268 if (!auto_continue) {
2269 Debug::clear_interrupt_pending(DEBUGBREAK);
2270 }
2271
2272 // Create the execution state.
2273 bool caught_exception = false;
2274 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2275 if (caught_exception) {
2276 return;
2277 }
2278 // First notify the message handler if any.
2279 if (message_handler_ != NULL) {
2280 NotifyMessageHandler(event,
2281 Handle<JSObject>::cast(exec_state),
2282 event_data,
2283 auto_continue);
2284 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002285 // Notify registered debug event listener. This can be either a C or
2286 // a JavaScript function. Don't call event listener for v8::Break
2287 // here, if it's only a debug command -- they will be processed later.
2288 if ((event != v8::Break || !auto_continue) && !event_listener_.is_null()) {
2289 CallEventCallback(event, exec_state, event_data, NULL);
2290 }
2291 // Process pending debug commands.
2292 if (event == v8::Break) {
2293 while (!event_command_queue_.IsEmpty()) {
2294 CommandMessage command = event_command_queue_.Get();
2295 if (!event_listener_.is_null()) {
2296 CallEventCallback(v8::BreakForCommand,
2297 exec_state,
2298 event_data,
2299 command.client_data());
2300 }
2301 command.Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +00002302 }
2303 }
2304}
2305
2306
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002307void Debugger::CallEventCallback(v8::DebugEvent event,
2308 Handle<Object> exec_state,
2309 Handle<Object> event_data,
2310 v8::Debug::ClientData* client_data) {
2311 if (event_listener_->IsProxy()) {
2312 CallCEventCallback(event, exec_state, event_data, client_data);
2313 } else {
2314 CallJSEventCallback(event, exec_state, event_data);
2315 }
2316}
2317
2318
2319void Debugger::CallCEventCallback(v8::DebugEvent event,
2320 Handle<Object> exec_state,
2321 Handle<Object> event_data,
2322 v8::Debug::ClientData* client_data) {
2323 Handle<Proxy> callback_obj(Handle<Proxy>::cast(event_listener_));
2324 v8::Debug::EventCallback2 callback =
2325 FUNCTION_CAST<v8::Debug::EventCallback2>(callback_obj->proxy());
2326 EventDetailsImpl event_details(
2327 event,
2328 Handle<JSObject>::cast(exec_state),
2329 Handle<JSObject>::cast(event_data),
2330 event_listener_data_,
2331 client_data);
2332 callback(event_details);
2333}
2334
2335
2336void Debugger::CallJSEventCallback(v8::DebugEvent event,
2337 Handle<Object> exec_state,
2338 Handle<Object> event_data) {
2339 ASSERT(event_listener_->IsJSFunction());
2340 Handle<JSFunction> fun(Handle<JSFunction>::cast(event_listener_));
2341
2342 // Invoke the JavaScript debug event listener.
2343 const int argc = 4;
2344 Object** argv[argc] = { Handle<Object>(Smi::FromInt(event)).location(),
2345 exec_state.location(),
2346 Handle<Object>::cast(event_data).location(),
2347 event_listener_data_.location() };
2348 bool caught_exception = false;
2349 Execution::TryCall(fun, Top::global(), argc, argv, &caught_exception);
2350 // Silently ignore exceptions from debug event listeners.
2351}
2352
2353
Steve Block6ded16b2010-05-10 14:33:55 +01002354Handle<Context> Debugger::GetDebugContext() {
2355 never_unload_debugger_ = true;
2356 EnterDebugger debugger;
2357 return Debug::debug_context();
2358}
2359
2360
Steve Blocka7e24c12009-10-30 11:49:00 +00002361void Debugger::UnloadDebugger() {
2362 // Make sure that there are no breakpoints left.
2363 Debug::ClearAllBreakPoints();
2364
2365 // Unload the debugger if feasible.
2366 if (!never_unload_debugger_) {
2367 Debug::Unload();
2368 }
2369
2370 // Clear the flag indicating that the debugger should be unloaded.
2371 debugger_unload_pending_ = false;
2372}
2373
2374
2375void Debugger::NotifyMessageHandler(v8::DebugEvent event,
2376 Handle<JSObject> exec_state,
2377 Handle<JSObject> event_data,
2378 bool auto_continue) {
2379 HandleScope scope;
2380
2381 if (!Debug::Load()) return;
2382
2383 // Process the individual events.
2384 bool sendEventMessage = false;
2385 switch (event) {
2386 case v8::Break:
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002387 case v8::BreakForCommand:
Steve Blocka7e24c12009-10-30 11:49:00 +00002388 sendEventMessage = !auto_continue;
2389 break;
2390 case v8::Exception:
2391 sendEventMessage = true;
2392 break;
2393 case v8::BeforeCompile:
2394 break;
2395 case v8::AfterCompile:
2396 sendEventMessage = true;
2397 break;
2398 case v8::ScriptCollected:
2399 sendEventMessage = true;
2400 break;
2401 case v8::NewFunction:
2402 break;
2403 default:
2404 UNREACHABLE();
2405 }
2406
2407 // The debug command interrupt flag might have been set when the command was
2408 // added. It should be enough to clear the flag only once while we are in the
2409 // debugger.
2410 ASSERT(Debug::InDebugger());
2411 StackGuard::Continue(DEBUGCOMMAND);
2412
2413 // Notify the debugger that a debug event has occurred unless auto continue is
2414 // active in which case no event is send.
2415 if (sendEventMessage) {
2416 MessageImpl message = MessageImpl::NewEvent(
2417 event,
2418 auto_continue,
2419 Handle<JSObject>::cast(exec_state),
2420 Handle<JSObject>::cast(event_data));
2421 InvokeMessageHandler(message);
2422 }
2423
2424 // If auto continue don't make the event cause a break, but process messages
2425 // in the queue if any. For script collected events don't even process
2426 // messages in the queue as the execution state might not be what is expected
2427 // by the client.
2428 if ((auto_continue && !HasCommands()) || event == v8::ScriptCollected) {
2429 return;
2430 }
2431
Steve Blocka7e24c12009-10-30 11:49:00 +00002432 v8::TryCatch try_catch;
Steve Block3ce2e202009-11-05 08:53:23 +00002433
2434 // DebugCommandProcessor goes here.
2435 v8::Local<v8::Object> cmd_processor;
2436 {
2437 v8::Local<v8::Object> api_exec_state =
2438 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state));
2439 v8::Local<v8::String> fun_name =
2440 v8::String::New("debugCommandProcessor");
2441 v8::Local<v8::Function> fun =
2442 v8::Function::Cast(*api_exec_state->Get(fun_name));
2443
2444 v8::Handle<v8::Boolean> running =
2445 auto_continue ? v8::True() : v8::False();
2446 static const int kArgc = 1;
2447 v8::Handle<Value> argv[kArgc] = { running };
2448 cmd_processor = v8::Object::Cast(*fun->Call(api_exec_state, kArgc, argv));
2449 if (try_catch.HasCaught()) {
2450 PrintLn(try_catch.Exception());
2451 return;
2452 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002453 }
2454
Steve Block3ce2e202009-11-05 08:53:23 +00002455 bool running = auto_continue;
2456
Steve Blocka7e24c12009-10-30 11:49:00 +00002457 // Process requests from the debugger.
2458 while (true) {
2459 // Wait for new command in the queue.
2460 if (Debugger::host_dispatch_handler_) {
2461 // In case there is a host dispatch - do periodic dispatches.
2462 if (!command_received_->Wait(host_dispatch_micros_)) {
2463 // Timout expired, do the dispatch.
2464 Debugger::host_dispatch_handler_();
2465 continue;
2466 }
2467 } else {
2468 // In case there is no host dispatch - just wait.
2469 command_received_->Wait();
2470 }
2471
2472 // Get the command from the queue.
2473 CommandMessage command = command_queue_.Get();
2474 Logger::DebugTag("Got request from command queue, in interactive loop.");
2475 if (!Debugger::IsDebuggerActive()) {
2476 // Delete command text and user data.
2477 command.Dispose();
2478 return;
2479 }
2480
2481 // Invoke JavaScript to process the debug request.
2482 v8::Local<v8::String> fun_name;
2483 v8::Local<v8::Function> fun;
2484 v8::Local<v8::Value> request;
2485 v8::TryCatch try_catch;
2486 fun_name = v8::String::New("processDebugRequest");
2487 fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
2488
2489 request = v8::String::New(command.text().start(),
2490 command.text().length());
2491 static const int kArgc = 1;
2492 v8::Handle<Value> argv[kArgc] = { request };
2493 v8::Local<v8::Value> response_val = fun->Call(cmd_processor, kArgc, argv);
2494
2495 // Get the response.
2496 v8::Local<v8::String> response;
Steve Blocka7e24c12009-10-30 11:49:00 +00002497 if (!try_catch.HasCaught()) {
2498 // Get response string.
2499 if (!response_val->IsUndefined()) {
2500 response = v8::String::Cast(*response_val);
2501 } else {
2502 response = v8::String::New("");
2503 }
2504
2505 // Log the JSON request/response.
2506 if (FLAG_trace_debug_json) {
2507 PrintLn(request);
2508 PrintLn(response);
2509 }
2510
2511 // Get the running state.
2512 fun_name = v8::String::New("isRunning");
2513 fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
2514 static const int kArgc = 1;
2515 v8::Handle<Value> argv[kArgc] = { response };
2516 v8::Local<v8::Value> running_val = fun->Call(cmd_processor, kArgc, argv);
2517 if (!try_catch.HasCaught()) {
2518 running = running_val->ToBoolean()->Value();
2519 }
2520 } else {
2521 // In case of failure the result text is the exception text.
2522 response = try_catch.Exception()->ToString();
2523 }
2524
2525 // Return the result.
2526 MessageImpl message = MessageImpl::NewResponse(
2527 event,
2528 running,
2529 Handle<JSObject>::cast(exec_state),
2530 Handle<JSObject>::cast(event_data),
2531 Handle<String>(Utils::OpenHandle(*response)),
2532 command.client_data());
2533 InvokeMessageHandler(message);
2534 command.Dispose();
2535
2536 // Return from debug event processing if either the VM is put into the
2537 // runnning state (through a continue command) or auto continue is active
2538 // and there are no more commands queued.
Steve Block3ce2e202009-11-05 08:53:23 +00002539 if (running && !HasCommands()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002540 return;
2541 }
2542 }
2543}
2544
2545
2546void Debugger::SetEventListener(Handle<Object> callback,
2547 Handle<Object> data) {
2548 HandleScope scope;
2549
2550 // Clear the global handles for the event listener and the event listener data
2551 // object.
2552 if (!event_listener_.is_null()) {
2553 GlobalHandles::Destroy(
2554 reinterpret_cast<Object**>(event_listener_.location()));
2555 event_listener_ = Handle<Object>();
2556 }
2557 if (!event_listener_data_.is_null()) {
2558 GlobalHandles::Destroy(
2559 reinterpret_cast<Object**>(event_listener_data_.location()));
2560 event_listener_data_ = Handle<Object>();
2561 }
2562
2563 // If there is a new debug event listener register it together with its data
2564 // object.
2565 if (!callback->IsUndefined() && !callback->IsNull()) {
2566 event_listener_ = Handle<Object>::cast(GlobalHandles::Create(*callback));
2567 if (data.is_null()) {
2568 data = Factory::undefined_value();
2569 }
2570 event_listener_data_ = Handle<Object>::cast(GlobalHandles::Create(*data));
2571 }
2572
2573 ListenersChanged();
2574}
2575
2576
2577void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) {
2578 ScopedLock with(debugger_access_);
2579
2580 message_handler_ = handler;
2581 ListenersChanged();
2582 if (handler == NULL) {
2583 // Send an empty command to the debugger if in a break to make JavaScript
2584 // run again if the debugger is closed.
2585 if (Debug::InDebugger()) {
2586 ProcessCommand(Vector<const uint16_t>::empty());
2587 }
2588 }
2589}
2590
2591
2592void Debugger::ListenersChanged() {
2593 if (IsDebuggerActive()) {
2594 // Disable the compilation cache when the debugger is active.
2595 CompilationCache::Disable();
Leon Clarkee46be812010-01-19 14:06:41 +00002596 debugger_unload_pending_ = false;
Steve Blocka7e24c12009-10-30 11:49:00 +00002597 } else {
2598 CompilationCache::Enable();
Steve Blocka7e24c12009-10-30 11:49:00 +00002599 // Unload the debugger if event listener and message handler cleared.
Leon Clarkee46be812010-01-19 14:06:41 +00002600 // Schedule this for later, because we may be in non-V8 thread.
2601 debugger_unload_pending_ = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00002602 }
2603}
2604
2605
2606void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
2607 int period) {
2608 host_dispatch_handler_ = handler;
2609 host_dispatch_micros_ = period * 1000;
2610}
2611
2612
Steve Blockd0582a62009-12-15 09:54:21 +00002613void Debugger::SetDebugMessageDispatchHandler(
Leon Clarkee46be812010-01-19 14:06:41 +00002614 v8::Debug::DebugMessageDispatchHandler handler, bool provide_locker) {
2615 ScopedLock with(dispatch_handler_access_);
Steve Blockd0582a62009-12-15 09:54:21 +00002616 debug_message_dispatch_handler_ = handler;
Leon Clarkee46be812010-01-19 14:06:41 +00002617
2618 if (provide_locker && message_dispatch_helper_thread_ == NULL) {
2619 message_dispatch_helper_thread_ = new MessageDispatchHelperThread;
2620 message_dispatch_helper_thread_->Start();
2621 }
Steve Blockd0582a62009-12-15 09:54:21 +00002622}
2623
2624
Steve Blocka7e24c12009-10-30 11:49:00 +00002625// Calls the registered debug message handler. This callback is part of the
2626// public API.
2627void Debugger::InvokeMessageHandler(MessageImpl message) {
2628 ScopedLock with(debugger_access_);
2629
2630 if (message_handler_ != NULL) {
2631 message_handler_(message);
2632 }
2633}
2634
2635
2636// Puts a command coming from the public API on the queue. Creates
2637// a copy of the command string managed by the debugger. Up to this
2638// point, the command data was managed by the API client. Called
2639// by the API client thread.
2640void Debugger::ProcessCommand(Vector<const uint16_t> command,
2641 v8::Debug::ClientData* client_data) {
2642 // Need to cast away const.
2643 CommandMessage message = CommandMessage::New(
2644 Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
2645 command.length()),
2646 client_data);
2647 Logger::DebugTag("Put command on command_queue.");
2648 command_queue_.Put(message);
2649 command_received_->Signal();
2650
2651 // Set the debug command break flag to have the command processed.
2652 if (!Debug::InDebugger()) {
2653 StackGuard::DebugCommand();
2654 }
Steve Blockd0582a62009-12-15 09:54:21 +00002655
Leon Clarkee46be812010-01-19 14:06:41 +00002656 MessageDispatchHelperThread* dispatch_thread;
2657 {
2658 ScopedLock with(dispatch_handler_access_);
2659 dispatch_thread = message_dispatch_helper_thread_;
2660 }
2661
2662 if (dispatch_thread == NULL) {
2663 CallMessageDispatchHandler();
2664 } else {
2665 dispatch_thread->Schedule();
Steve Blockd0582a62009-12-15 09:54:21 +00002666 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002667}
2668
2669
2670bool Debugger::HasCommands() {
2671 return !command_queue_.IsEmpty();
2672}
2673
2674
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002675void Debugger::EnqueueDebugCommand(v8::Debug::ClientData* client_data) {
2676 CommandMessage message = CommandMessage::New(Vector<uint16_t>(), client_data);
2677 event_command_queue_.Put(message);
2678
2679 // Set the debug command break flag to have the command processed.
2680 if (!Debug::InDebugger()) {
2681 StackGuard::DebugCommand();
2682 }
2683}
2684
2685
Steve Blocka7e24c12009-10-30 11:49:00 +00002686bool Debugger::IsDebuggerActive() {
2687 ScopedLock with(debugger_access_);
2688
2689 return message_handler_ != NULL || !event_listener_.is_null();
2690}
2691
2692
2693Handle<Object> Debugger::Call(Handle<JSFunction> fun,
2694 Handle<Object> data,
2695 bool* pending_exception) {
2696 // When calling functions in the debugger prevent it from beeing unloaded.
2697 Debugger::never_unload_debugger_ = true;
2698
2699 // Enter the debugger.
2700 EnterDebugger debugger;
Steve Block6ded16b2010-05-10 14:33:55 +01002701 if (debugger.FailedToEnter()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002702 return Factory::undefined_value();
2703 }
2704
2705 // Create the execution state.
2706 bool caught_exception = false;
2707 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2708 if (caught_exception) {
2709 return Factory::undefined_value();
2710 }
2711
2712 static const int kArgc = 2;
2713 Object** argv[kArgc] = { exec_state.location(), data.location() };
Steve Block6ded16b2010-05-10 14:33:55 +01002714 Handle<Object> result = Execution::Call(
2715 fun,
2716 Handle<Object>(Debug::debug_context_->global_proxy()),
2717 kArgc,
2718 argv,
2719 pending_exception);
Steve Blocka7e24c12009-10-30 11:49:00 +00002720 return result;
2721}
2722
2723
Leon Clarkee46be812010-01-19 14:06:41 +00002724static void StubMessageHandler2(const v8::Debug::Message& message) {
2725 // Simply ignore message.
2726}
2727
2728
2729bool Debugger::StartAgent(const char* name, int port,
2730 bool wait_for_connection) {
2731 if (wait_for_connection) {
2732 // Suspend V8 if it is already running or set V8 to suspend whenever
2733 // it starts.
2734 // Provide stub message handler; V8 auto-continues each suspend
2735 // when there is no message handler; we doesn't need it.
2736 // Once become suspended, V8 will stay so indefinitely long, until remote
2737 // debugger connects and issues "continue" command.
2738 Debugger::message_handler_ = StubMessageHandler2;
2739 v8::Debug::DebugBreak();
2740 }
2741
Steve Blocka7e24c12009-10-30 11:49:00 +00002742 if (Socket::Setup()) {
2743 agent_ = new DebuggerAgent(name, port);
2744 agent_->Start();
2745 return true;
2746 }
2747
2748 return false;
2749}
2750
2751
2752void Debugger::StopAgent() {
2753 if (agent_ != NULL) {
2754 agent_->Shutdown();
2755 agent_->Join();
2756 delete agent_;
2757 agent_ = NULL;
2758 }
2759}
2760
2761
2762void Debugger::WaitForAgent() {
2763 if (agent_ != NULL)
2764 agent_->WaitUntilListening();
2765}
2766
Leon Clarkee46be812010-01-19 14:06:41 +00002767
2768void Debugger::CallMessageDispatchHandler() {
2769 v8::Debug::DebugMessageDispatchHandler handler;
2770 {
2771 ScopedLock with(dispatch_handler_access_);
2772 handler = Debugger::debug_message_dispatch_handler_;
2773 }
2774 if (handler != NULL) {
2775 handler();
2776 }
2777}
2778
2779
Steve Blocka7e24c12009-10-30 11:49:00 +00002780MessageImpl MessageImpl::NewEvent(DebugEvent event,
2781 bool running,
2782 Handle<JSObject> exec_state,
2783 Handle<JSObject> event_data) {
2784 MessageImpl message(true, event, running,
2785 exec_state, event_data, Handle<String>(), NULL);
2786 return message;
2787}
2788
2789
2790MessageImpl MessageImpl::NewResponse(DebugEvent event,
2791 bool running,
2792 Handle<JSObject> exec_state,
2793 Handle<JSObject> event_data,
2794 Handle<String> response_json,
2795 v8::Debug::ClientData* client_data) {
2796 MessageImpl message(false, event, running,
2797 exec_state, event_data, response_json, client_data);
2798 return message;
2799}
2800
2801
2802MessageImpl::MessageImpl(bool is_event,
2803 DebugEvent event,
2804 bool running,
2805 Handle<JSObject> exec_state,
2806 Handle<JSObject> event_data,
2807 Handle<String> response_json,
2808 v8::Debug::ClientData* client_data)
2809 : is_event_(is_event),
2810 event_(event),
2811 running_(running),
2812 exec_state_(exec_state),
2813 event_data_(event_data),
2814 response_json_(response_json),
2815 client_data_(client_data) {}
2816
2817
2818bool MessageImpl::IsEvent() const {
2819 return is_event_;
2820}
2821
2822
2823bool MessageImpl::IsResponse() const {
2824 return !is_event_;
2825}
2826
2827
2828DebugEvent MessageImpl::GetEvent() const {
2829 return event_;
2830}
2831
2832
2833bool MessageImpl::WillStartRunning() const {
2834 return running_;
2835}
2836
2837
2838v8::Handle<v8::Object> MessageImpl::GetExecutionState() const {
2839 return v8::Utils::ToLocal(exec_state_);
2840}
2841
2842
2843v8::Handle<v8::Object> MessageImpl::GetEventData() const {
2844 return v8::Utils::ToLocal(event_data_);
2845}
2846
2847
2848v8::Handle<v8::String> MessageImpl::GetJSON() const {
2849 v8::HandleScope scope;
2850
2851 if (IsEvent()) {
2852 // Call toJSONProtocol on the debug event object.
2853 Handle<Object> fun = GetProperty(event_data_, "toJSONProtocol");
2854 if (!fun->IsJSFunction()) {
2855 return v8::Handle<v8::String>();
2856 }
2857 bool caught_exception;
2858 Handle<Object> json = Execution::TryCall(Handle<JSFunction>::cast(fun),
2859 event_data_,
2860 0, NULL, &caught_exception);
2861 if (caught_exception || !json->IsString()) {
2862 return v8::Handle<v8::String>();
2863 }
2864 return scope.Close(v8::Utils::ToLocal(Handle<String>::cast(json)));
2865 } else {
2866 return v8::Utils::ToLocal(response_json_);
2867 }
2868}
2869
2870
2871v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
Leon Clarkef7060e22010-06-03 12:02:55 +01002872 v8::Handle<v8::Context> context = GetDebugEventContext();
2873 // Top::context() may be NULL when "script collected" event occures.
2874 ASSERT(!context.IsEmpty() || event_ == v8::ScriptCollected);
2875 return GetDebugEventContext();
Steve Blocka7e24c12009-10-30 11:49:00 +00002876}
2877
2878
2879v8::Debug::ClientData* MessageImpl::GetClientData() const {
2880 return client_data_;
2881}
2882
2883
Leon Clarkef7060e22010-06-03 12:02:55 +01002884EventDetailsImpl::EventDetailsImpl(DebugEvent event,
2885 Handle<JSObject> exec_state,
2886 Handle<JSObject> event_data,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002887 Handle<Object> callback_data,
2888 v8::Debug::ClientData* client_data)
Leon Clarkef7060e22010-06-03 12:02:55 +01002889 : event_(event),
2890 exec_state_(exec_state),
2891 event_data_(event_data),
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002892 callback_data_(callback_data),
2893 client_data_(client_data) {}
Leon Clarkef7060e22010-06-03 12:02:55 +01002894
2895
2896DebugEvent EventDetailsImpl::GetEvent() const {
2897 return event_;
2898}
2899
2900
2901v8::Handle<v8::Object> EventDetailsImpl::GetExecutionState() const {
2902 return v8::Utils::ToLocal(exec_state_);
2903}
2904
2905
2906v8::Handle<v8::Object> EventDetailsImpl::GetEventData() const {
2907 return v8::Utils::ToLocal(event_data_);
2908}
2909
2910
2911v8::Handle<v8::Context> EventDetailsImpl::GetEventContext() const {
2912 return GetDebugEventContext();
2913}
2914
2915
2916v8::Handle<v8::Value> EventDetailsImpl::GetCallbackData() const {
2917 return v8::Utils::ToLocal(callback_data_);
2918}
2919
2920
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002921v8::Debug::ClientData* EventDetailsImpl::GetClientData() const {
2922 return client_data_;
2923}
2924
2925
Steve Blocka7e24c12009-10-30 11:49:00 +00002926CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()),
2927 client_data_(NULL) {
2928}
2929
2930
2931CommandMessage::CommandMessage(const Vector<uint16_t>& text,
2932 v8::Debug::ClientData* data)
2933 : text_(text),
2934 client_data_(data) {
2935}
2936
2937
2938CommandMessage::~CommandMessage() {
2939}
2940
2941
2942void CommandMessage::Dispose() {
2943 text_.Dispose();
2944 delete client_data_;
2945 client_data_ = NULL;
2946}
2947
2948
2949CommandMessage CommandMessage::New(const Vector<uint16_t>& command,
2950 v8::Debug::ClientData* data) {
2951 return CommandMessage(command.Clone(), data);
2952}
2953
2954
2955CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0),
2956 size_(size) {
2957 messages_ = NewArray<CommandMessage>(size);
2958}
2959
2960
2961CommandMessageQueue::~CommandMessageQueue() {
2962 while (!IsEmpty()) {
2963 CommandMessage m = Get();
2964 m.Dispose();
2965 }
2966 DeleteArray(messages_);
2967}
2968
2969
2970CommandMessage CommandMessageQueue::Get() {
2971 ASSERT(!IsEmpty());
2972 int result = start_;
2973 start_ = (start_ + 1) % size_;
2974 return messages_[result];
2975}
2976
2977
2978void CommandMessageQueue::Put(const CommandMessage& message) {
2979 if ((end_ + 1) % size_ == start_) {
2980 Expand();
2981 }
2982 messages_[end_] = message;
2983 end_ = (end_ + 1) % size_;
2984}
2985
2986
2987void CommandMessageQueue::Expand() {
2988 CommandMessageQueue new_queue(size_ * 2);
2989 while (!IsEmpty()) {
2990 new_queue.Put(Get());
2991 }
2992 CommandMessage* array_to_free = messages_;
2993 *this = new_queue;
2994 new_queue.messages_ = array_to_free;
2995 // Make the new_queue empty so that it doesn't call Dispose on any messages.
2996 new_queue.start_ = new_queue.end_;
2997 // Automatic destructor called on new_queue, freeing array_to_free.
2998}
2999
3000
3001LockingCommandMessageQueue::LockingCommandMessageQueue(int size)
3002 : queue_(size) {
3003 lock_ = OS::CreateMutex();
3004}
3005
3006
3007LockingCommandMessageQueue::~LockingCommandMessageQueue() {
3008 delete lock_;
3009}
3010
3011
3012bool LockingCommandMessageQueue::IsEmpty() const {
3013 ScopedLock sl(lock_);
3014 return queue_.IsEmpty();
3015}
3016
3017
3018CommandMessage LockingCommandMessageQueue::Get() {
3019 ScopedLock sl(lock_);
3020 CommandMessage result = queue_.Get();
3021 Logger::DebugEvent("Get", result.text());
3022 return result;
3023}
3024
3025
3026void LockingCommandMessageQueue::Put(const CommandMessage& message) {
3027 ScopedLock sl(lock_);
3028 queue_.Put(message);
3029 Logger::DebugEvent("Put", message.text());
3030}
3031
3032
3033void LockingCommandMessageQueue::Clear() {
3034 ScopedLock sl(lock_);
3035 queue_.Clear();
3036}
3037
Leon Clarkee46be812010-01-19 14:06:41 +00003038
3039MessageDispatchHelperThread::MessageDispatchHelperThread()
3040 : sem_(OS::CreateSemaphore(0)), mutex_(OS::CreateMutex()),
3041 already_signalled_(false) {
3042}
3043
3044
3045MessageDispatchHelperThread::~MessageDispatchHelperThread() {
3046 delete mutex_;
3047 delete sem_;
3048}
3049
3050
3051void MessageDispatchHelperThread::Schedule() {
3052 {
3053 ScopedLock lock(mutex_);
3054 if (already_signalled_) {
3055 return;
3056 }
3057 already_signalled_ = true;
3058 }
3059 sem_->Signal();
3060}
3061
3062
3063void MessageDispatchHelperThread::Run() {
3064 while (true) {
3065 sem_->Wait();
3066 {
3067 ScopedLock lock(mutex_);
3068 already_signalled_ = false;
3069 }
3070 {
3071 Locker locker;
3072 Debugger::CallMessageDispatchHandler();
3073 }
3074 }
3075}
3076
Steve Blocka7e24c12009-10-30 11:49:00 +00003077#endif // ENABLE_DEBUGGER_SUPPORT
3078
3079} } // namespace v8::internal