blob: 85c4b5ef34d25758e97e3bcdd47ae002ba5e5e6c [file] [log] [blame]
Ben Murdoch257744e2011-11-30 15:57:28 +00001// Copyright 2011 the V8 project authors. All rights reserved.
Steve Blocka7e24c12009-10-30 11:49:00 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
31#include "arguments.h"
32#include "bootstrapper.h"
33#include "code-stubs.h"
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
Steve Block44f0eee2011-05-26 01:26:41 +010054
55
56Debug::Debug(Isolate* isolate)
57 : has_break_points_(false),
58 script_cache_(NULL),
59 debug_info_list_(NULL),
60 disable_break_(false),
61 break_on_exception_(false),
62 break_on_uncaught_exception_(false),
63 debug_break_return_(NULL),
64 debug_break_slot_(NULL),
65 isolate_(isolate) {
66 memset(registers_, 0, sizeof(JSCallerSavedBuffer));
67}
68
69
70Debug::~Debug() {
71}
72
73
Steve Blocka7e24c12009-10-30 11:49:00 +000074static void PrintLn(v8::Local<v8::Value> value) {
75 v8::Local<v8::String> s = value->ToString();
Kristian Monsen25f61362010-05-21 11:50:48 +010076 ScopedVector<char> data(s->Length() + 1);
77 if (data.start() == NULL) {
Steve Blocka7e24c12009-10-30 11:49:00 +000078 V8::FatalProcessOutOfMemory("PrintLn");
79 return;
80 }
Kristian Monsen25f61362010-05-21 11:50:48 +010081 s->WriteAscii(data.start());
82 PrintF("%s\n", data.start());
Steve Blocka7e24c12009-10-30 11:49:00 +000083}
84
85
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010086static Handle<Code> ComputeCallDebugBreak(int argc, Code::Kind kind) {
Steve Block44f0eee2011-05-26 01:26:41 +010087 Isolate* isolate = Isolate::Current();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010088 CALL_HEAP_FUNCTION(
Steve Block44f0eee2011-05-26 01:26:41 +010089 isolate,
90 isolate->stub_cache()->ComputeCallDebugBreak(argc, kind),
91 Code);
Steve Blocka7e24c12009-10-30 11:49:00 +000092}
93
94
Ben Murdoch257744e2011-11-30 15:57:28 +000095static Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind) {
Steve Block44f0eee2011-05-26 01:26:41 +010096 Isolate* isolate = Isolate::Current();
97 CALL_HEAP_FUNCTION(
98 isolate,
99 isolate->stub_cache()->ComputeCallDebugPrepareStepIn(argc, kind),
100 Code);
101}
102
103
104static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) {
105 Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
106 // Isolate::context() may have been NULL when "script collected" event
107 // occured.
108 if (context.is_null()) return v8::Local<v8::Context>();
Leon Clarkef7060e22010-06-03 12:02:55 +0100109 Handle<Context> global_context(context->global_context());
110 return v8::Utils::ToLocal(global_context);
111}
112
113
Steve Blocka7e24c12009-10-30 11:49:00 +0000114BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info,
115 BreakLocatorType type) {
116 debug_info_ = debug_info;
117 type_ = type;
Steve Blocka7e24c12009-10-30 11:49:00 +0000118 reloc_iterator_ = NULL;
119 reloc_iterator_original_ = NULL;
120 Reset(); // Initialize the rest of the member variables.
121}
122
123
124BreakLocationIterator::~BreakLocationIterator() {
125 ASSERT(reloc_iterator_ != NULL);
126 ASSERT(reloc_iterator_original_ != NULL);
127 delete reloc_iterator_;
128 delete reloc_iterator_original_;
129}
130
131
132void BreakLocationIterator::Next() {
133 AssertNoAllocation nogc;
134 ASSERT(!RinfoDone());
135
136 // Iterate through reloc info for code and original code stopping at each
137 // breakable code target.
138 bool first = break_point_ == -1;
139 while (!RinfoDone()) {
140 if (!first) RinfoNext();
141 first = false;
142 if (RinfoDone()) return;
143
144 // Whenever a statement position or (plain) position is passed update the
145 // current value of these.
146 if (RelocInfo::IsPosition(rmode())) {
147 if (RelocInfo::IsStatementPosition(rmode())) {
Steve Blockd0582a62009-12-15 09:54:21 +0000148 statement_position_ = static_cast<int>(
149 rinfo()->data() - debug_info_->shared()->start_position());
Steve Blocka7e24c12009-10-30 11:49:00 +0000150 }
151 // Always update the position as we don't want that to be before the
152 // statement position.
Steve Blockd0582a62009-12-15 09:54:21 +0000153 position_ = static_cast<int>(
154 rinfo()->data() - debug_info_->shared()->start_position());
Steve Blocka7e24c12009-10-30 11:49:00 +0000155 ASSERT(position_ >= 0);
156 ASSERT(statement_position_ >= 0);
157 }
158
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100159 if (IsDebugBreakSlot()) {
160 // There is always a possible break point at a debug break slot.
161 break_point_++;
162 return;
163 } else if (RelocInfo::IsCodeTarget(rmode())) {
164 // Check for breakable code target. Look in the original code as setting
165 // break points can cause the code targets in the running (debugged) code
166 // to be of a different kind than in the original code.
Steve Blocka7e24c12009-10-30 11:49:00 +0000167 Address target = original_rinfo()->target_address();
168 Code* code = Code::GetCodeFromTargetAddress(target);
Steve Block6ded16b2010-05-10 14:33:55 +0100169 if ((code->is_inline_cache_stub() &&
Ben Murdoch257744e2011-11-30 15:57:28 +0000170 !code->is_binary_op_stub() &&
171 !code->is_unary_op_stub() &&
Ben Murdochb0fe1622011-05-05 13:52:32 +0100172 !code->is_compare_ic_stub()) ||
Steve Block6ded16b2010-05-10 14:33:55 +0100173 RelocInfo::IsConstructCall(rmode())) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000174 break_point_++;
175 return;
176 }
177 if (code->kind() == Code::STUB) {
178 if (IsDebuggerStatement()) {
179 break_point_++;
180 return;
181 }
182 if (type_ == ALL_BREAK_LOCATIONS) {
183 if (Debug::IsBreakStub(code)) {
184 break_point_++;
185 return;
186 }
187 } else {
188 ASSERT(type_ == SOURCE_BREAK_LOCATIONS);
189 if (Debug::IsSourceBreakStub(code)) {
190 break_point_++;
191 return;
192 }
193 }
194 }
195 }
196
197 // Check for break at return.
198 if (RelocInfo::IsJSReturn(rmode())) {
199 // Set the positions to the end of the function.
200 if (debug_info_->shared()->HasSourceCode()) {
201 position_ = debug_info_->shared()->end_position() -
Ben Murdochbb769b22010-08-11 14:56:33 +0100202 debug_info_->shared()->start_position() - 1;
Steve Blocka7e24c12009-10-30 11:49:00 +0000203 } else {
204 position_ = 0;
205 }
206 statement_position_ = position_;
207 break_point_++;
208 return;
209 }
210 }
211}
212
213
214void BreakLocationIterator::Next(int count) {
215 while (count > 0) {
216 Next();
217 count--;
218 }
219}
220
221
222// Find the break point closest to the supplied address.
223void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) {
224 // Run through all break points to locate the one closest to the address.
225 int closest_break_point = 0;
226 int distance = kMaxInt;
227 while (!Done()) {
228 // Check if this break point is closer that what was previously found.
229 if (this->pc() < pc && pc - this->pc() < distance) {
230 closest_break_point = break_point();
Steve Blockd0582a62009-12-15 09:54:21 +0000231 distance = static_cast<int>(pc - this->pc());
Steve Blocka7e24c12009-10-30 11:49:00 +0000232 // Check whether we can't get any closer.
233 if (distance == 0) break;
234 }
235 Next();
236 }
237
238 // Move to the break point found.
239 Reset();
240 Next(closest_break_point);
241}
242
243
244// Find the break point closest to the supplied source position.
245void BreakLocationIterator::FindBreakLocationFromPosition(int position) {
246 // Run through all break points to locate the one closest to the source
247 // position.
248 int closest_break_point = 0;
249 int distance = kMaxInt;
250 while (!Done()) {
251 // Check if this break point is closer that what was previously found.
252 if (position <= statement_position() &&
253 statement_position() - position < distance) {
254 closest_break_point = break_point();
255 distance = statement_position() - position;
256 // Check whether we can't get any closer.
257 if (distance == 0) break;
258 }
259 Next();
260 }
261
262 // Move to the break point found.
263 Reset();
264 Next(closest_break_point);
265}
266
267
268void BreakLocationIterator::Reset() {
269 // Create relocation iterators for the two code objects.
270 if (reloc_iterator_ != NULL) delete reloc_iterator_;
271 if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_;
272 reloc_iterator_ = new RelocIterator(debug_info_->code());
273 reloc_iterator_original_ = new RelocIterator(debug_info_->original_code());
274
275 // Position at the first break point.
276 break_point_ = -1;
277 position_ = 1;
278 statement_position_ = 1;
279 Next();
280}
281
282
283bool BreakLocationIterator::Done() const {
284 return RinfoDone();
285}
286
287
288void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) {
289 // If there is not already a real break point here patch code with debug
290 // break.
291 if (!HasBreakPoint()) {
292 SetDebugBreak();
293 }
294 ASSERT(IsDebugBreak() || IsDebuggerStatement());
295 // Set the break point information.
296 DebugInfo::SetBreakPoint(debug_info_, code_position(),
297 position(), statement_position(),
298 break_point_object);
299}
300
301
302void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) {
303 // Clear the break point information.
304 DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object);
305 // If there are no more break points here remove the debug break.
306 if (!HasBreakPoint()) {
307 ClearDebugBreak();
308 ASSERT(!IsDebugBreak());
309 }
310}
311
312
313void BreakLocationIterator::SetOneShot() {
314 // Debugger statement always calls debugger. No need to modify it.
315 if (IsDebuggerStatement()) {
316 return;
317 }
318
319 // If there is a real break point here no more to do.
320 if (HasBreakPoint()) {
321 ASSERT(IsDebugBreak());
322 return;
323 }
324
325 // Patch code with debug break.
326 SetDebugBreak();
327}
328
329
330void BreakLocationIterator::ClearOneShot() {
331 // Debugger statement always calls debugger. No need to modify it.
332 if (IsDebuggerStatement()) {
333 return;
334 }
335
336 // If there is a real break point here no more to do.
337 if (HasBreakPoint()) {
338 ASSERT(IsDebugBreak());
339 return;
340 }
341
342 // Patch code removing debug break.
343 ClearDebugBreak();
344 ASSERT(!IsDebugBreak());
345}
346
347
348void BreakLocationIterator::SetDebugBreak() {
349 // Debugger statement always calls debugger. No need to modify it.
350 if (IsDebuggerStatement()) {
351 return;
352 }
353
354 // If there is already a break point here just return. This might happen if
355 // the same code is flooded with break points twice. Flooding the same
356 // function twice might happen when stepping in a function with an exception
357 // handler as the handler and the function is the same.
358 if (IsDebugBreak()) {
359 return;
360 }
361
362 if (RelocInfo::IsJSReturn(rmode())) {
363 // Patch the frame exit code with a break point.
364 SetDebugBreakAtReturn();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100365 } else if (IsDebugBreakSlot()) {
366 // Patch the code in the break slot.
367 SetDebugBreakAtSlot();
Steve Blocka7e24c12009-10-30 11:49:00 +0000368 } else {
369 // Patch the IC call.
370 SetDebugBreakAtIC();
371 }
372 ASSERT(IsDebugBreak());
373}
374
375
376void BreakLocationIterator::ClearDebugBreak() {
377 // Debugger statement always calls debugger. No need to modify it.
378 if (IsDebuggerStatement()) {
379 return;
380 }
381
382 if (RelocInfo::IsJSReturn(rmode())) {
383 // Restore the frame exit code.
384 ClearDebugBreakAtReturn();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100385 } else if (IsDebugBreakSlot()) {
386 // Restore the code in the break slot.
387 ClearDebugBreakAtSlot();
Steve Blocka7e24c12009-10-30 11:49:00 +0000388 } else {
389 // Patch the IC call.
390 ClearDebugBreakAtIC();
391 }
392 ASSERT(!IsDebugBreak());
393}
394
395
396void BreakLocationIterator::PrepareStepIn() {
397 HandleScope scope;
398
399 // Step in can only be prepared if currently positioned on an IC call,
400 // construct call or CallFunction stub call.
401 Address target = rinfo()->target_address();
402 Handle<Code> code(Code::GetCodeFromTargetAddress(target));
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100403 if (code->is_call_stub() || code->is_keyed_call_stub()) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000404 // Step in through IC call is handled by the runtime system. Therefore make
405 // sure that the any current IC is cleared and the runtime system is
406 // called. If the executing code has a debug break at the location change
407 // the call in the original code as it is the code there that will be
408 // executed in place of the debug break call.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100409 Handle<Code> stub = ComputeCallDebugPrepareStepIn(code->arguments_count(),
410 code->kind());
Steve Blocka7e24c12009-10-30 11:49:00 +0000411 if (IsDebugBreak()) {
412 original_rinfo()->set_target_address(stub->entry());
413 } else {
414 rinfo()->set_target_address(stub->entry());
415 }
416 } else {
417#ifdef DEBUG
418 // All the following stuff is needed only for assertion checks so the code
419 // is wrapped in ifdef.
420 Handle<Code> maybe_call_function_stub = code;
421 if (IsDebugBreak()) {
422 Address original_target = original_rinfo()->target_address();
423 maybe_call_function_stub =
424 Handle<Code>(Code::GetCodeFromTargetAddress(original_target));
425 }
426 bool is_call_function_stub =
427 (maybe_call_function_stub->kind() == Code::STUB &&
428 maybe_call_function_stub->major_key() == CodeStub::CallFunction);
429
430 // Step in through construct call requires no changes to the running code.
431 // Step in through getters/setters should already be prepared as well
432 // because caller of this function (Debug::PrepareStep) is expected to
433 // flood the top frame's function with one shot breakpoints.
434 // Step in through CallFunction stub should also be prepared by caller of
435 // this function (Debug::PrepareStep) which should flood target function
436 // with breakpoints.
437 ASSERT(RelocInfo::IsConstructCall(rmode()) || code->is_inline_cache_stub()
438 || is_call_function_stub);
439#endif
440 }
441}
442
443
444// Check whether the break point is at a position which will exit the function.
445bool BreakLocationIterator::IsExit() const {
446 return (RelocInfo::IsJSReturn(rmode()));
447}
448
449
450bool BreakLocationIterator::HasBreakPoint() {
451 return debug_info_->HasBreakPoint(code_position());
452}
453
454
455// Check whether there is a debug break at the current position.
456bool BreakLocationIterator::IsDebugBreak() {
457 if (RelocInfo::IsJSReturn(rmode())) {
458 return IsDebugBreakAtReturn();
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100459 } else if (IsDebugBreakSlot()) {
460 return IsDebugBreakAtSlot();
Steve Blocka7e24c12009-10-30 11:49:00 +0000461 } else {
462 return Debug::IsDebugBreak(rinfo()->target_address());
463 }
464}
465
466
467void BreakLocationIterator::SetDebugBreakAtIC() {
468 // Patch the original code with the current address as the current address
469 // might have changed by the inline caching since the code was copied.
470 original_rinfo()->set_target_address(rinfo()->target_address());
471
472 RelocInfo::Mode mode = rmode();
473 if (RelocInfo::IsCodeTarget(mode)) {
474 Address target = rinfo()->target_address();
475 Handle<Code> code(Code::GetCodeFromTargetAddress(target));
476
477 // Patch the code to invoke the builtin debug break function matching the
478 // calling convention used by the call site.
479 Handle<Code> dbgbrk_code(Debug::FindDebugBreak(code, mode));
480 rinfo()->set_target_address(dbgbrk_code->entry());
Steve Blocka7e24c12009-10-30 11:49:00 +0000481 }
482}
483
484
485void BreakLocationIterator::ClearDebugBreakAtIC() {
486 // Patch the code to the original invoke.
487 rinfo()->set_target_address(original_rinfo()->target_address());
Steve Blocka7e24c12009-10-30 11:49:00 +0000488}
489
490
491bool BreakLocationIterator::IsDebuggerStatement() {
Andrei Popescu402d9372010-02-26 13:31:12 +0000492 return RelocInfo::DEBUG_BREAK == rmode();
Steve Blocka7e24c12009-10-30 11:49:00 +0000493}
494
495
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100496bool BreakLocationIterator::IsDebugBreakSlot() {
497 return RelocInfo::DEBUG_BREAK_SLOT == rmode();
498}
499
500
Steve Blocka7e24c12009-10-30 11:49:00 +0000501Object* BreakLocationIterator::BreakPointObjects() {
502 return debug_info_->GetBreakPointObjects(code_position());
503}
504
505
506// Clear out all the debug break code. This is ONLY supposed to be used when
507// shutting down the debugger as it will leave the break point information in
508// DebugInfo even though the code is patched back to the non break point state.
509void BreakLocationIterator::ClearAllDebugBreak() {
510 while (!Done()) {
511 ClearDebugBreak();
512 Next();
513 }
514}
515
516
517bool BreakLocationIterator::RinfoDone() const {
518 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
519 return reloc_iterator_->done();
520}
521
522
523void BreakLocationIterator::RinfoNext() {
524 reloc_iterator_->next();
525 reloc_iterator_original_->next();
526#ifdef DEBUG
527 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
528 if (!reloc_iterator_->done()) {
529 ASSERT(rmode() == original_rmode());
530 }
531#endif
532}
533
534
Steve Blocka7e24c12009-10-30 11:49:00 +0000535// Threading support.
536void Debug::ThreadInit() {
537 thread_local_.break_count_ = 0;
538 thread_local_.break_id_ = 0;
539 thread_local_.break_frame_id_ = StackFrame::NO_ID;
540 thread_local_.last_step_action_ = StepNone;
541 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
542 thread_local_.step_count_ = 0;
543 thread_local_.last_fp_ = 0;
544 thread_local_.step_into_fp_ = 0;
545 thread_local_.step_out_fp_ = 0;
546 thread_local_.after_break_target_ = 0;
Steve Block44f0eee2011-05-26 01:26:41 +0100547 // TODO(isolates): frames_are_dropped_?
Steve Blocka7e24c12009-10-30 11:49:00 +0000548 thread_local_.debugger_entry_ = NULL;
549 thread_local_.pending_interrupts_ = 0;
Iain Merrick75681382010-08-19 15:07:18 +0100550 thread_local_.restarter_frame_function_pointer_ = NULL;
Steve Blocka7e24c12009-10-30 11:49:00 +0000551}
552
553
Steve Blocka7e24c12009-10-30 11:49:00 +0000554char* Debug::ArchiveDebug(char* storage) {
555 char* to = storage;
556 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
557 to += sizeof(ThreadLocal);
558 memcpy(to, reinterpret_cast<char*>(&registers_), sizeof(registers_));
559 ThreadInit();
560 ASSERT(to <= storage + ArchiveSpacePerThread());
561 return storage + ArchiveSpacePerThread();
562}
563
564
565char* Debug::RestoreDebug(char* storage) {
566 char* from = storage;
567 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
568 from += sizeof(ThreadLocal);
569 memcpy(reinterpret_cast<char*>(&registers_), from, sizeof(registers_));
570 ASSERT(from <= storage + ArchiveSpacePerThread());
571 return storage + ArchiveSpacePerThread();
572}
573
574
575int Debug::ArchiveSpacePerThread() {
Steve Block44f0eee2011-05-26 01:26:41 +0100576 return sizeof(ThreadLocal) + sizeof(JSCallerSavedBuffer);
Steve Blocka7e24c12009-10-30 11:49:00 +0000577}
578
579
Iain Merrick75681382010-08-19 15:07:18 +0100580// Frame structure (conforms InternalFrame structure):
581// -- code
582// -- SMI maker
583// -- function (slot is called "context")
584// -- frame base
585Object** Debug::SetUpFrameDropperFrame(StackFrame* bottom_js_frame,
586 Handle<Code> code) {
587 ASSERT(bottom_js_frame->is_java_script());
588
589 Address fp = bottom_js_frame->fp();
590
591 // Move function pointer into "context" slot.
592 Memory::Object_at(fp + StandardFrameConstants::kContextOffset) =
593 Memory::Object_at(fp + JavaScriptFrameConstants::kFunctionOffset);
594
595 Memory::Object_at(fp + InternalFrameConstants::kCodeOffset) = *code;
596 Memory::Object_at(fp + StandardFrameConstants::kMarkerOffset) =
597 Smi::FromInt(StackFrame::INTERNAL);
598
599 return reinterpret_cast<Object**>(&Memory::Object_at(
600 fp + StandardFrameConstants::kContextOffset));
601}
602
603const int Debug::kFrameDropperFrameSize = 4;
604
605
Steve Blocka7e24c12009-10-30 11:49:00 +0000606void ScriptCache::Add(Handle<Script> script) {
Steve Block44f0eee2011-05-26 01:26:41 +0100607 GlobalHandles* global_handles = Isolate::Current()->global_handles();
Steve Blocka7e24c12009-10-30 11:49:00 +0000608 // Create an entry in the hash map for the script.
609 int id = Smi::cast(script->id())->value();
610 HashMap::Entry* entry =
611 HashMap::Lookup(reinterpret_cast<void*>(id), Hash(id), true);
612 if (entry->value != NULL) {
613 ASSERT(*script == *reinterpret_cast<Script**>(entry->value));
614 return;
615 }
616
617 // Globalize the script object, make it weak and use the location of the
618 // global handle as the value in the hash map.
619 Handle<Script> script_ =
Steve Block44f0eee2011-05-26 01:26:41 +0100620 Handle<Script>::cast(
621 (global_handles->Create(*script)));
622 global_handles->MakeWeak(
623 reinterpret_cast<Object**>(script_.location()),
624 this,
625 ScriptCache::HandleWeakScript);
Steve Blocka7e24c12009-10-30 11:49:00 +0000626 entry->value = script_.location();
627}
628
629
630Handle<FixedArray> ScriptCache::GetScripts() {
Steve Block44f0eee2011-05-26 01:26:41 +0100631 Handle<FixedArray> instances = FACTORY->NewFixedArray(occupancy());
Steve Blocka7e24c12009-10-30 11:49:00 +0000632 int count = 0;
633 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
634 ASSERT(entry->value != NULL);
635 if (entry->value != NULL) {
636 instances->set(count, *reinterpret_cast<Script**>(entry->value));
637 count++;
638 }
639 }
640 return instances;
641}
642
643
644void ScriptCache::ProcessCollectedScripts() {
Steve Block44f0eee2011-05-26 01:26:41 +0100645 Debugger* debugger = Isolate::Current()->debugger();
Steve Blocka7e24c12009-10-30 11:49:00 +0000646 for (int i = 0; i < collected_scripts_.length(); i++) {
Steve Block44f0eee2011-05-26 01:26:41 +0100647 debugger->OnScriptCollected(collected_scripts_[i]);
Steve Blocka7e24c12009-10-30 11:49:00 +0000648 }
649 collected_scripts_.Clear();
650}
651
652
653void ScriptCache::Clear() {
Steve Block44f0eee2011-05-26 01:26:41 +0100654 GlobalHandles* global_handles = Isolate::Current()->global_handles();
Steve Blocka7e24c12009-10-30 11:49:00 +0000655 // Iterate the script cache to get rid of all the weak handles.
656 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
657 ASSERT(entry != NULL);
658 Object** location = reinterpret_cast<Object**>(entry->value);
659 ASSERT((*location)->IsScript());
Steve Block44f0eee2011-05-26 01:26:41 +0100660 global_handles->ClearWeakness(location);
661 global_handles->Destroy(location);
Steve Blocka7e24c12009-10-30 11:49:00 +0000662 }
663 // Clear the content of the hash map.
664 HashMap::Clear();
665}
666
667
668void ScriptCache::HandleWeakScript(v8::Persistent<v8::Value> obj, void* data) {
669 ScriptCache* script_cache = reinterpret_cast<ScriptCache*>(data);
670 // Find the location of the global handle.
671 Script** location =
672 reinterpret_cast<Script**>(Utils::OpenHandle(*obj).location());
673 ASSERT((*location)->IsScript());
674
675 // Remove the entry from the cache.
676 int id = Smi::cast((*location)->id())->value();
677 script_cache->Remove(reinterpret_cast<void*>(id), Hash(id));
678 script_cache->collected_scripts_.Add(id);
679
680 // Clear the weak handle.
681 obj.Dispose();
682 obj.Clear();
683}
684
685
686void Debug::Setup(bool create_heap_objects) {
687 ThreadInit();
688 if (create_heap_objects) {
689 // Get code to handle debug break on return.
690 debug_break_return_ =
Steve Block44f0eee2011-05-26 01:26:41 +0100691 isolate_->builtins()->builtin(Builtins::kReturn_DebugBreak);
Steve Blocka7e24c12009-10-30 11:49:00 +0000692 ASSERT(debug_break_return_->IsCode());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100693 // Get code to handle debug break in debug break slots.
694 debug_break_slot_ =
Steve Block44f0eee2011-05-26 01:26:41 +0100695 isolate_->builtins()->builtin(Builtins::kSlot_DebugBreak);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100696 ASSERT(debug_break_slot_->IsCode());
Steve Blocka7e24c12009-10-30 11:49:00 +0000697 }
698}
699
700
701void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) {
Steve Block44f0eee2011-05-26 01:26:41 +0100702 Debug* debug = Isolate::Current()->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +0000703 DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data);
Steve Block8defd9f2010-07-08 12:39:36 +0100704 // We need to clear all breakpoints associated with the function to restore
705 // original code and avoid patching the code twice later because
706 // the function will live in the heap until next gc, and can be found by
707 // Runtime::FindSharedFunctionInfoInScript.
708 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
709 it.ClearAllDebugBreak();
Steve Block44f0eee2011-05-26 01:26:41 +0100710 debug->RemoveDebugInfo(node->debug_info());
Steve Blocka7e24c12009-10-30 11:49:00 +0000711#ifdef DEBUG
Steve Block44f0eee2011-05-26 01:26:41 +0100712 node = debug->debug_info_list_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000713 while (node != NULL) {
714 ASSERT(node != reinterpret_cast<DebugInfoListNode*>(data));
715 node = node->next();
716 }
717#endif
718}
719
720
721DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +0100722 GlobalHandles* global_handles = Isolate::Current()->global_handles();
Steve Blocka7e24c12009-10-30 11:49:00 +0000723 // Globalize the request debug info object and make it weak.
Steve Block44f0eee2011-05-26 01:26:41 +0100724 debug_info_ = Handle<DebugInfo>::cast(
725 (global_handles->Create(debug_info)));
726 global_handles->MakeWeak(
727 reinterpret_cast<Object**>(debug_info_.location()),
728 this,
729 Debug::HandleWeakDebugInfo);
Steve Blocka7e24c12009-10-30 11:49:00 +0000730}
731
732
733DebugInfoListNode::~DebugInfoListNode() {
Steve Block44f0eee2011-05-26 01:26:41 +0100734 Isolate::Current()->global_handles()->Destroy(
735 reinterpret_cast<Object**>(debug_info_.location()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000736}
737
738
739bool Debug::CompileDebuggerScript(int index) {
Steve Block44f0eee2011-05-26 01:26:41 +0100740 Isolate* isolate = Isolate::Current();
741 Factory* factory = isolate->factory();
742 HandleScope scope(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +0000743
744 // Bail out if the index is invalid.
745 if (index == -1) {
746 return false;
747 }
748
749 // Find source and name for the requested script.
Steve Block44f0eee2011-05-26 01:26:41 +0100750 Handle<String> source_code =
751 isolate->bootstrapper()->NativesSourceLookup(index);
Steve Blocka7e24c12009-10-30 11:49:00 +0000752 Vector<const char> name = Natives::GetScriptName(index);
Steve Block44f0eee2011-05-26 01:26:41 +0100753 Handle<String> script_name = factory->NewStringFromAscii(name);
Steve Blocka7e24c12009-10-30 11:49:00 +0000754
755 // Compile the script.
Steve Block6ded16b2010-05-10 14:33:55 +0100756 Handle<SharedFunctionInfo> function_info;
757 function_info = Compiler::Compile(source_code,
758 script_name,
759 0, 0, NULL, NULL,
760 Handle<String>::null(),
761 NATIVES_CODE);
Steve Blocka7e24c12009-10-30 11:49:00 +0000762
763 // Silently ignore stack overflows during compilation.
Steve Block6ded16b2010-05-10 14:33:55 +0100764 if (function_info.is_null()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100765 ASSERT(isolate->has_pending_exception());
766 isolate->clear_pending_exception();
Steve Blocka7e24c12009-10-30 11:49:00 +0000767 return false;
768 }
769
Steve Block6ded16b2010-05-10 14:33:55 +0100770 // Execute the shared function in the debugger context.
Steve Block44f0eee2011-05-26 01:26:41 +0100771 Handle<Context> context = isolate->global_context();
Steve Blocka7e24c12009-10-30 11:49:00 +0000772 bool caught_exception = false;
773 Handle<JSFunction> function =
Steve Block44f0eee2011-05-26 01:26:41 +0100774 factory->NewFunctionFromSharedFunctionInfo(function_info, context);
Steve Blocka7e24c12009-10-30 11:49:00 +0000775 Handle<Object> result =
776 Execution::TryCall(function, Handle<Object>(context->global()),
777 0, NULL, &caught_exception);
778
779 // Check for caught exceptions.
780 if (caught_exception) {
781 Handle<Object> message = MessageHandler::MakeMessageObject(
782 "error_loading_debugger", NULL, Vector<Handle<Object> >::empty(),
Ben Murdoch3bec4d22010-07-22 14:51:16 +0100783 Handle<String>(), Handle<JSArray>());
Ben Murdoch8b112d22011-06-08 16:22:53 +0100784 MessageHandler::ReportMessage(Isolate::Current(), NULL, message);
Steve Blocka7e24c12009-10-30 11:49:00 +0000785 return false;
786 }
787
788 // Mark this script as native and return successfully.
789 Handle<Script> script(Script::cast(function->shared()->script()));
Steve Block6ded16b2010-05-10 14:33:55 +0100790 script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
Steve Blocka7e24c12009-10-30 11:49:00 +0000791 return true;
792}
793
794
795bool Debug::Load() {
796 // Return if debugger is already loaded.
797 if (IsLoaded()) return true;
798
Steve Block44f0eee2011-05-26 01:26:41 +0100799 ASSERT(Isolate::Current() == isolate_);
800 Debugger* debugger = isolate_->debugger();
801
Steve Blocka7e24c12009-10-30 11:49:00 +0000802 // Bail out if we're already in the process of compiling the native
803 // JavaScript source code for the debugger.
Steve Block44f0eee2011-05-26 01:26:41 +0100804 if (debugger->compiling_natives() ||
805 debugger->is_loading_debugger())
Steve Blocka7e24c12009-10-30 11:49:00 +0000806 return false;
Steve Block44f0eee2011-05-26 01:26:41 +0100807 debugger->set_loading_debugger(true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000808
809 // Disable breakpoints and interrupts while compiling and running the
810 // debugger scripts including the context creation code.
811 DisableBreak disable(true);
Steve Block44f0eee2011-05-26 01:26:41 +0100812 PostponeInterruptsScope postpone(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000813
814 // Create the debugger context.
Steve Block44f0eee2011-05-26 01:26:41 +0100815 HandleScope scope(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000816 Handle<Context> context =
Steve Block44f0eee2011-05-26 01:26:41 +0100817 isolate_->bootstrapper()->CreateEnvironment(
Ben Murdoch257744e2011-11-30 15:57:28 +0000818 isolate_,
Steve Block44f0eee2011-05-26 01:26:41 +0100819 Handle<Object>::null(),
820 v8::Handle<ObjectTemplate>(),
821 NULL);
Steve Blocka7e24c12009-10-30 11:49:00 +0000822
823 // Use the debugger context.
Steve Block44f0eee2011-05-26 01:26:41 +0100824 SaveContext save(isolate_);
825 isolate_->set_context(*context);
Steve Blocka7e24c12009-10-30 11:49:00 +0000826
827 // Expose the builtins object in the debugger context.
Steve Block44f0eee2011-05-26 01:26:41 +0100828 Handle<String> key = isolate_->factory()->LookupAsciiSymbol("builtins");
Steve Blocka7e24c12009-10-30 11:49:00 +0000829 Handle<GlobalObject> global = Handle<GlobalObject>(context->global());
Steve Block1e0659c2011-05-24 12:43:12 +0100830 RETURN_IF_EMPTY_HANDLE_VALUE(
Steve Block44f0eee2011-05-26 01:26:41 +0100831 isolate_,
Ben Murdoche0cee9b2011-05-25 10:26:03 +0100832 SetProperty(global, key, Handle<Object>(global->builtins()),
833 NONE, kNonStrictMode),
Steve Block1e0659c2011-05-24 12:43:12 +0100834 false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000835
836 // Compile the JavaScript for the debugger in the debugger context.
Steve Block44f0eee2011-05-26 01:26:41 +0100837 debugger->set_compiling_natives(true);
Steve Blocka7e24c12009-10-30 11:49:00 +0000838 bool caught_exception =
839 !CompileDebuggerScript(Natives::GetIndex("mirror")) ||
840 !CompileDebuggerScript(Natives::GetIndex("debug"));
Steve Block6ded16b2010-05-10 14:33:55 +0100841
842 if (FLAG_enable_liveedit) {
843 caught_exception = caught_exception ||
844 !CompileDebuggerScript(Natives::GetIndex("liveedit"));
845 }
846
Steve Block44f0eee2011-05-26 01:26:41 +0100847 debugger->set_compiling_natives(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000848
849 // Make sure we mark the debugger as not loading before we might
850 // return.
Steve Block44f0eee2011-05-26 01:26:41 +0100851 debugger->set_loading_debugger(false);
Steve Blocka7e24c12009-10-30 11:49:00 +0000852
853 // Check for caught exceptions.
854 if (caught_exception) return false;
855
856 // Debugger loaded.
Ben Murdochb0fe1622011-05-05 13:52:32 +0100857 debug_context_ = context;
Steve Blocka7e24c12009-10-30 11:49:00 +0000858
859 return true;
860}
861
862
863void Debug::Unload() {
864 // Return debugger is not loaded.
865 if (!IsLoaded()) {
866 return;
867 }
868
869 // Clear the script cache.
870 DestroyScriptCache();
871
872 // Clear debugger context global handle.
Steve Block44f0eee2011-05-26 01:26:41 +0100873 Isolate::Current()->global_handles()->Destroy(
874 reinterpret_cast<Object**>(debug_context_.location()));
Steve Blocka7e24c12009-10-30 11:49:00 +0000875 debug_context_ = Handle<Context>();
876}
877
878
879// Set the flag indicating that preemption happened during debugging.
880void Debug::PreemptionWhileInDebugger() {
881 ASSERT(InDebugger());
882 Debug::set_interrupts_pending(PREEMPT);
883}
884
885
886void Debug::Iterate(ObjectVisitor* v) {
Iain Merrick75681382010-08-19 15:07:18 +0100887 v->VisitPointer(BitCast<Object**>(&(debug_break_return_)));
888 v->VisitPointer(BitCast<Object**>(&(debug_break_slot_)));
Steve Blocka7e24c12009-10-30 11:49:00 +0000889}
890
891
Ben Murdoch8b112d22011-06-08 16:22:53 +0100892Object* Debug::Break(Arguments args) {
893 Heap* heap = isolate_->heap();
894 HandleScope scope(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000895 ASSERT(args.length() == 0);
896
Ben Murdoch8b112d22011-06-08 16:22:53 +0100897 thread_local_.frame_drop_mode_ = FRAMES_UNTOUCHED;
Steve Block6ded16b2010-05-10 14:33:55 +0100898
Steve Blocka7e24c12009-10-30 11:49:00 +0000899 // Get the top-most JavaScript frame.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100900 JavaScriptFrameIterator it(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000901 JavaScriptFrame* frame = it.frame();
902
903 // Just continue if breaks are disabled or debugger cannot be loaded.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100904 if (disable_break() || !Load()) {
905 SetAfterBreakTarget(frame);
Steve Block44f0eee2011-05-26 01:26:41 +0100906 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000907 }
908
909 // Enter the debugger.
910 EnterDebugger debugger;
911 if (debugger.FailedToEnter()) {
Steve Block44f0eee2011-05-26 01:26:41 +0100912 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +0000913 }
914
915 // Postpone interrupt during breakpoint processing.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100916 PostponeInterruptsScope postpone(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +0000917
918 // Get the debug info (create it if it does not exist).
919 Handle<SharedFunctionInfo> shared =
920 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
921 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
922
923 // Find the break point where execution has stopped.
924 BreakLocationIterator break_location_iterator(debug_info,
925 ALL_BREAK_LOCATIONS);
926 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
927
928 // Check whether step next reached a new statement.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100929 if (!StepNextContinue(&break_location_iterator, frame)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000930 // Decrease steps left if performing multiple steps.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100931 if (thread_local_.step_count_ > 0) {
932 thread_local_.step_count_--;
Steve Blocka7e24c12009-10-30 11:49:00 +0000933 }
934 }
935
936 // If there is one or more real break points check whether any of these are
937 // triggered.
Steve Block44f0eee2011-05-26 01:26:41 +0100938 Handle<Object> break_points_hit(heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +0000939 if (break_location_iterator.HasBreakPoint()) {
940 Handle<Object> break_point_objects =
941 Handle<Object>(break_location_iterator.BreakPointObjects());
Ben Murdoch8b112d22011-06-08 16:22:53 +0100942 break_points_hit = CheckBreakPoints(break_point_objects);
Steve Blocka7e24c12009-10-30 11:49:00 +0000943 }
944
945 // If step out is active skip everything until the frame where we need to step
946 // out to is reached, unless real breakpoint is hit.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100947 if (StepOutActive() && frame->fp() != step_out_fp() &&
Steve Blocka7e24c12009-10-30 11:49:00 +0000948 break_points_hit->IsUndefined() ) {
949 // Step count should always be 0 for StepOut.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100950 ASSERT(thread_local_.step_count_ == 0);
Steve Blocka7e24c12009-10-30 11:49:00 +0000951 } else if (!break_points_hit->IsUndefined() ||
Ben Murdoch8b112d22011-06-08 16:22:53 +0100952 (thread_local_.last_step_action_ != StepNone &&
953 thread_local_.step_count_ == 0)) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000954 // Notify debugger if a real break point is triggered or if performing
955 // single stepping with no more steps to perform. Otherwise do another step.
956
957 // Clear all current stepping setup.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100958 ClearStepping();
Steve Blocka7e24c12009-10-30 11:49:00 +0000959
960 // Notify the debug event listeners.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100961 isolate_->debugger()->OnDebugBreak(break_points_hit, false);
962 } else if (thread_local_.last_step_action_ != StepNone) {
Steve Blocka7e24c12009-10-30 11:49:00 +0000963 // Hold on to last step action as it is cleared by the call to
964 // ClearStepping.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100965 StepAction step_action = thread_local_.last_step_action_;
966 int step_count = thread_local_.step_count_;
Steve Blocka7e24c12009-10-30 11:49:00 +0000967
968 // Clear all current stepping setup.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100969 ClearStepping();
Steve Blocka7e24c12009-10-30 11:49:00 +0000970
971 // Set up for the remaining steps.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100972 PrepareStep(step_action, step_count);
Steve Blocka7e24c12009-10-30 11:49:00 +0000973 }
974
Ben Murdoch8b112d22011-06-08 16:22:53 +0100975 if (thread_local_.frame_drop_mode_ == FRAMES_UNTOUCHED) {
976 SetAfterBreakTarget(frame);
977 } else if (thread_local_.frame_drop_mode_ ==
Steve Block44f0eee2011-05-26 01:26:41 +0100978 FRAME_DROPPED_IN_IC_CALL) {
Steve Block8defd9f2010-07-08 12:39:36 +0100979 // We must have been calling IC stub. Do not go there anymore.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100980 Code* plain_return = isolate_->builtins()->builtin(
981 Builtins::kPlainReturn_LiveEdit);
982 thread_local_.after_break_target_ = plain_return->entry();
983 } else if (thread_local_.frame_drop_mode_ ==
Steve Block8defd9f2010-07-08 12:39:36 +0100984 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.
Ben Murdoch8b112d22011-06-08 16:22:53 +0100987 Code* plain_return = isolate_->builtins()->builtin(
Steve Block44f0eee2011-05-26 01:26:41 +0100988 Builtins::kFrameDropper_LiveEdit);
Ben Murdoch8b112d22011-06-08 16:22:53 +0100989 thread_local_.after_break_target_ = plain_return->entry();
990 } else if (thread_local_.frame_drop_mode_ ==
Steve Block44f0eee2011-05-26 01:26:41 +0100991 FRAME_DROPPED_IN_DIRECT_CALL) {
Steve Block8defd9f2010-07-08 12:39:36 +0100992 // Nothing to do, after_break_target is not used here.
Ben Murdoch257744e2011-11-30 15:57:28 +0000993 } else if (thread_local_.frame_drop_mode_ ==
994 FRAME_DROPPED_IN_RETURN_CALL) {
995 Code* plain_return = isolate_->builtins()->builtin(
996 Builtins::kFrameDropper_LiveEdit);
997 thread_local_.after_break_target_ = plain_return->entry();
Steve Block6ded16b2010-05-10 14:33:55 +0100998 } else {
Steve Block8defd9f2010-07-08 12:39:36 +0100999 UNREACHABLE();
Steve Block6ded16b2010-05-10 14:33:55 +01001000 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001001
Steve Block44f0eee2011-05-26 01:26:41 +01001002 return heap->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001003}
1004
1005
Ben Murdoch8b112d22011-06-08 16:22:53 +01001006RUNTIME_FUNCTION(Object*, Debug_Break) {
1007 return isolate->debug()->Break(args);
1008}
1009
1010
Steve Blocka7e24c12009-10-30 11:49:00 +00001011// Check the break point objects for whether one or more are actually
1012// triggered. This function returns a JSArray with the break point objects
1013// which is triggered.
1014Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) {
Steve Block44f0eee2011-05-26 01:26:41 +01001015 Factory* factory = isolate_->factory();
Steve Blocka7e24c12009-10-30 11:49:00 +00001016
Steve Block44f0eee2011-05-26 01:26:41 +01001017 // Count the number of break points hit. If there are multiple break points
1018 // they are in a FixedArray.
1019 Handle<FixedArray> break_points_hit;
1020 int break_points_hit_count = 0;
Steve Blocka7e24c12009-10-30 11:49:00 +00001021 ASSERT(!break_point_objects->IsUndefined());
1022 if (break_point_objects->IsFixedArray()) {
1023 Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
Steve Block44f0eee2011-05-26 01:26:41 +01001024 break_points_hit = factory->NewFixedArray(array->length());
Steve Blocka7e24c12009-10-30 11:49:00 +00001025 for (int i = 0; i < array->length(); i++) {
1026 Handle<Object> o(array->get(i));
1027 if (CheckBreakPoint(o)) {
Steve Block44f0eee2011-05-26 01:26:41 +01001028 break_points_hit->set(break_points_hit_count++, *o);
Steve Blocka7e24c12009-10-30 11:49:00 +00001029 }
1030 }
1031 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01001032 break_points_hit = factory->NewFixedArray(1);
Steve Blocka7e24c12009-10-30 11:49:00 +00001033 if (CheckBreakPoint(break_point_objects)) {
Steve Block44f0eee2011-05-26 01:26:41 +01001034 break_points_hit->set(break_points_hit_count++, *break_point_objects);
Steve Blocka7e24c12009-10-30 11:49:00 +00001035 }
1036 }
1037
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001038 // Return undefined if no break points were triggered.
Steve Blocka7e24c12009-10-30 11:49:00 +00001039 if (break_points_hit_count == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01001040 return factory->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00001041 }
Steve Block44f0eee2011-05-26 01:26:41 +01001042 // Return break points hit as a JSArray.
1043 Handle<JSArray> result = factory->NewJSArrayWithElements(break_points_hit);
1044 result->set_length(Smi::FromInt(break_points_hit_count));
1045 return result;
Steve Blocka7e24c12009-10-30 11:49:00 +00001046}
1047
1048
1049// Check whether a single break point object is triggered.
1050bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +01001051 ASSERT(Isolate::Current() == isolate_);
1052 Factory* factory = isolate_->factory();
1053 HandleScope scope(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00001054
1055 // Ignore check if break point object is not a JSObject.
1056 if (!break_point_object->IsJSObject()) return true;
1057
Steve Block44f0eee2011-05-26 01:26:41 +01001058 // Get the function IsBreakPointTriggered (defined in debug-debugger.js).
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001059 Handle<String> is_break_point_triggered_symbol =
Steve Block44f0eee2011-05-26 01:26:41 +01001060 factory->LookupAsciiSymbol("IsBreakPointTriggered");
Steve Blocka7e24c12009-10-30 11:49:00 +00001061 Handle<JSFunction> check_break_point =
1062 Handle<JSFunction>(JSFunction::cast(
John Reck59135872010-11-02 12:39:01 -07001063 debug_context()->global()->GetPropertyNoExceptionThrown(
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001064 *is_break_point_triggered_symbol)));
Steve Blocka7e24c12009-10-30 11:49:00 +00001065
1066 // Get the break id as an object.
Steve Block44f0eee2011-05-26 01:26:41 +01001067 Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id());
Steve Blocka7e24c12009-10-30 11:49:00 +00001068
1069 // Call HandleBreakPointx.
1070 bool caught_exception = false;
1071 const int argc = 2;
1072 Object** argv[argc] = {
1073 break_id.location(),
1074 reinterpret_cast<Object**>(break_point_object.location())
1075 };
1076 Handle<Object> result = Execution::TryCall(check_break_point,
Steve Block44f0eee2011-05-26 01:26:41 +01001077 isolate_->js_builtins_object(), argc, argv, &caught_exception);
Steve Blocka7e24c12009-10-30 11:49:00 +00001078
1079 // If exception or non boolean result handle as not triggered
1080 if (caught_exception || !result->IsBoolean()) {
1081 return false;
1082 }
1083
1084 // Return whether the break point is triggered.
Steve Block44f0eee2011-05-26 01:26:41 +01001085 ASSERT(!result.is_null());
1086 return (*result)->IsTrue();
Steve Blocka7e24c12009-10-30 11:49:00 +00001087}
1088
1089
1090// Check whether the function has debug information.
1091bool Debug::HasDebugInfo(Handle<SharedFunctionInfo> shared) {
1092 return !shared->debug_info()->IsUndefined();
1093}
1094
1095
1096// Return the debug info for this function. EnsureDebugInfo must be called
1097// prior to ensure the debug info has been generated for shared.
1098Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) {
1099 ASSERT(HasDebugInfo(shared));
1100 return Handle<DebugInfo>(DebugInfo::cast(shared->debug_info()));
1101}
1102
1103
1104void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared,
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001105 Handle<Object> break_point_object,
1106 int* source_position) {
Steve Block44f0eee2011-05-26 01:26:41 +01001107 HandleScope scope(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00001108
1109 if (!EnsureDebugInfo(shared)) {
1110 // Return if retrieving debug info failed.
1111 return;
1112 }
1113
1114 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1115 // Source positions starts with zero.
1116 ASSERT(source_position >= 0);
1117
1118 // Find the break point and change it.
1119 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001120 it.FindBreakLocationFromPosition(*source_position);
Steve Blocka7e24c12009-10-30 11:49:00 +00001121 it.SetBreakPoint(break_point_object);
1122
Kristian Monsen9dcf7e22010-06-28 14:14:28 +01001123 *source_position = it.position();
1124
Steve Blocka7e24c12009-10-30 11:49:00 +00001125 // At least one active break point now.
1126 ASSERT(debug_info->GetBreakPointCount() > 0);
1127}
1128
1129
1130void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
Steve Block44f0eee2011-05-26 01:26:41 +01001131 HandleScope scope(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00001132
1133 DebugInfoListNode* node = debug_info_list_;
1134 while (node != NULL) {
1135 Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(),
1136 break_point_object);
1137 if (!result->IsUndefined()) {
1138 // Get information in the break point.
1139 BreakPointInfo* break_point_info = BreakPointInfo::cast(result);
1140 Handle<DebugInfo> debug_info = node->debug_info();
1141 Handle<SharedFunctionInfo> shared(debug_info->shared());
1142 int source_position = break_point_info->statement_position()->value();
1143
1144 // Source positions starts with zero.
1145 ASSERT(source_position >= 0);
1146
1147 // Find the break point and clear it.
1148 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
1149 it.FindBreakLocationFromPosition(source_position);
1150 it.ClearBreakPoint(break_point_object);
1151
1152 // If there are no more break points left remove the debug info for this
1153 // function.
1154 if (debug_info->GetBreakPointCount() == 0) {
1155 RemoveDebugInfo(debug_info);
1156 }
1157
1158 return;
1159 }
1160 node = node->next();
1161 }
1162}
1163
1164
1165void Debug::ClearAllBreakPoints() {
1166 DebugInfoListNode* node = debug_info_list_;
1167 while (node != NULL) {
1168 // Remove all debug break code.
1169 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1170 it.ClearAllDebugBreak();
1171 node = node->next();
1172 }
1173
1174 // Remove all debug info.
1175 while (debug_info_list_ != NULL) {
1176 RemoveDebugInfo(debug_info_list_->debug_info());
1177 }
1178}
1179
1180
1181void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) {
1182 // Make sure the function has setup the debug info.
1183 if (!EnsureDebugInfo(shared)) {
1184 // Return if we failed to retrieve the debug info.
1185 return;
1186 }
1187
1188 // Flood the function with break points.
1189 BreakLocationIterator it(GetDebugInfo(shared), ALL_BREAK_LOCATIONS);
1190 while (!it.Done()) {
1191 it.SetOneShot();
1192 it.Next();
1193 }
1194}
1195
1196
1197void Debug::FloodHandlerWithOneShot() {
1198 // Iterate through the JavaScript stack looking for handlers.
1199 StackFrame::Id id = break_frame_id();
1200 if (id == StackFrame::NO_ID) {
1201 // If there is no JavaScript stack don't do anything.
1202 return;
1203 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01001204 for (JavaScriptFrameIterator it(isolate_, id); !it.done(); it.Advance()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001205 JavaScriptFrame* frame = it.frame();
1206 if (frame->HasHandler()) {
1207 Handle<SharedFunctionInfo> shared =
1208 Handle<SharedFunctionInfo>(
1209 JSFunction::cast(frame->function())->shared());
1210 // Flood the function with the catch block with break points
1211 FloodWithOneShot(shared);
1212 return;
1213 }
1214 }
1215}
1216
1217
1218void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
1219 if (type == BreakUncaughtException) {
1220 break_on_uncaught_exception_ = enable;
1221 } else {
1222 break_on_exception_ = enable;
1223 }
1224}
1225
1226
Kristian Monsen0d5e1162010-09-30 15:31:59 +01001227bool Debug::IsBreakOnException(ExceptionBreakType type) {
1228 if (type == BreakUncaughtException) {
1229 return break_on_uncaught_exception_;
1230 } else {
1231 return break_on_exception_;
1232 }
1233}
1234
1235
Steve Blocka7e24c12009-10-30 11:49:00 +00001236void Debug::PrepareStep(StepAction step_action, int step_count) {
Steve Block44f0eee2011-05-26 01:26:41 +01001237 ASSERT(Isolate::Current() == isolate_);
1238 HandleScope scope(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00001239 ASSERT(Debug::InDebugger());
1240
1241 // Remember this step action and count.
1242 thread_local_.last_step_action_ = step_action;
1243 if (step_action == StepOut) {
1244 // For step out target frame will be found on the stack so there is no need
1245 // to set step counter for it. It's expected to always be 0 for StepOut.
1246 thread_local_.step_count_ = 0;
1247 } else {
1248 thread_local_.step_count_ = step_count;
1249 }
1250
1251 // Get the frame where the execution has stopped and skip the debug frame if
1252 // any. The debug frame will only be present if execution was stopped due to
1253 // hitting a break point. In other situations (e.g. unhandled exception) the
1254 // debug frame is not present.
1255 StackFrame::Id id = break_frame_id();
1256 if (id == StackFrame::NO_ID) {
1257 // If there is no JavaScript stack don't do anything.
1258 return;
1259 }
Ben Murdoch8b112d22011-06-08 16:22:53 +01001260 JavaScriptFrameIterator frames_it(isolate_, id);
Steve Blocka7e24c12009-10-30 11:49:00 +00001261 JavaScriptFrame* frame = frames_it.frame();
1262
1263 // First of all ensure there is one-shot break points in the top handler
1264 // if any.
1265 FloodHandlerWithOneShot();
1266
1267 // If the function on the top frame is unresolved perform step out. This will
1268 // be the case when calling unknown functions and having the debugger stopped
1269 // in an unhandled exception.
1270 if (!frame->function()->IsJSFunction()) {
1271 // Step out: Find the calling JavaScript frame and flood it with
1272 // breakpoints.
1273 frames_it.Advance();
1274 // Fill the function to return to with one-shot break points.
1275 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
1276 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1277 return;
1278 }
1279
1280 // Get the debug info (create it if it does not exist).
1281 Handle<SharedFunctionInfo> shared =
1282 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
1283 if (!EnsureDebugInfo(shared)) {
1284 // Return if ensuring debug info failed.
1285 return;
1286 }
1287 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1288
1289 // Find the break location where execution has stopped.
1290 BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS);
1291 it.FindBreakLocationFromAddress(frame->pc());
1292
1293 // Compute whether or not the target is a call target.
Steve Blocka7e24c12009-10-30 11:49:00 +00001294 bool is_load_or_store = false;
1295 bool is_inline_cache_stub = false;
Ben Murdochbb769b22010-08-11 14:56:33 +01001296 bool is_at_restarted_function = false;
Steve Blocka7e24c12009-10-30 11:49:00 +00001297 Handle<Code> call_function_stub;
Steve Blocka7e24c12009-10-30 11:49:00 +00001298
Ben Murdochbb769b22010-08-11 14:56:33 +01001299 if (thread_local_.restarter_frame_function_pointer_ == NULL) {
1300 if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) {
1301 bool is_call_target = false;
1302 Address target = it.rinfo()->target_address();
1303 Code* code = Code::GetCodeFromTargetAddress(target);
1304 if (code->is_call_stub() || code->is_keyed_call_stub()) {
1305 is_call_target = true;
1306 }
1307 if (code->is_inline_cache_stub()) {
1308 is_inline_cache_stub = true;
1309 is_load_or_store = !is_call_target;
1310 }
1311
1312 // Check if target code is CallFunction stub.
1313 Code* maybe_call_function_stub = code;
1314 // If there is a breakpoint at this line look at the original code to
1315 // check if it is a CallFunction stub.
1316 if (it.IsDebugBreak()) {
1317 Address original_target = it.original_rinfo()->target_address();
1318 maybe_call_function_stub =
1319 Code::GetCodeFromTargetAddress(original_target);
1320 }
1321 if (maybe_call_function_stub->kind() == Code::STUB &&
1322 maybe_call_function_stub->major_key() == CodeStub::CallFunction) {
1323 // Save reference to the code as we may need it to find out arguments
1324 // count for 'step in' later.
1325 call_function_stub = Handle<Code>(maybe_call_function_stub);
1326 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001327 }
Ben Murdochbb769b22010-08-11 14:56:33 +01001328 } else {
1329 is_at_restarted_function = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00001330 }
1331
1332 // If this is the last break code target step out is the only possibility.
1333 if (it.IsExit() || step_action == StepOut) {
1334 if (step_action == StepOut) {
1335 // Skip step_count frames starting with the current one.
1336 while (step_count-- > 0 && !frames_it.done()) {
1337 frames_it.Advance();
1338 }
1339 } else {
1340 ASSERT(it.IsExit());
1341 frames_it.Advance();
1342 }
1343 // Skip builtin functions on the stack.
1344 while (!frames_it.done() &&
1345 JSFunction::cast(frames_it.frame()->function())->IsBuiltin()) {
1346 frames_it.Advance();
1347 }
1348 // Step out: If there is a JavaScript caller frame, we need to
1349 // flood it with breakpoints.
1350 if (!frames_it.done()) {
1351 // Fill the function to return to with one-shot break points.
1352 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
1353 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1354 // Set target frame pointer.
1355 ActivateStepOut(frames_it.frame());
1356 }
1357 } else if (!(is_inline_cache_stub || RelocInfo::IsConstructCall(it.rmode()) ||
Ben Murdochbb769b22010-08-11 14:56:33 +01001358 !call_function_stub.is_null() || is_at_restarted_function)
Steve Blocka7e24c12009-10-30 11:49:00 +00001359 || step_action == StepNext || step_action == StepMin) {
1360 // Step next or step min.
1361
1362 // Fill the current function with one-shot break points.
1363 FloodWithOneShot(shared);
1364
1365 // Remember source position and frame to handle step next.
1366 thread_local_.last_statement_position_ =
1367 debug_info->code()->SourceStatementPosition(frame->pc());
1368 thread_local_.last_fp_ = frame->fp();
1369 } else {
Ben Murdochbb769b22010-08-11 14:56:33 +01001370 // If there's restarter frame on top of the stack, just get the pointer
1371 // to function which is going to be restarted.
1372 if (is_at_restarted_function) {
1373 Handle<JSFunction> restarted_function(
1374 JSFunction::cast(*thread_local_.restarter_frame_function_pointer_));
1375 Handle<SharedFunctionInfo> restarted_shared(
1376 restarted_function->shared());
1377 FloodWithOneShot(restarted_shared);
1378 } else if (!call_function_stub.is_null()) {
1379 // If it's CallFunction stub ensure target function is compiled and flood
1380 // it with one shot breakpoints.
1381
Steve Blocka7e24c12009-10-30 11:49:00 +00001382 // Find out number of arguments from the stub minor key.
1383 // Reverse lookup required as the minor key cannot be retrieved
1384 // from the code object.
1385 Handle<Object> obj(
Steve Block44f0eee2011-05-26 01:26:41 +01001386 isolate_->heap()->code_stubs()->SlowReverseLookup(
1387 *call_function_stub));
1388 ASSERT(!obj.is_null());
1389 ASSERT(!(*obj)->IsUndefined());
Steve Blocka7e24c12009-10-30 11:49:00 +00001390 ASSERT(obj->IsSmi());
1391 // Get the STUB key and extract major and minor key.
1392 uint32_t key = Smi::cast(*obj)->value();
1393 // Argc in the stub is the number of arguments passed - not the
1394 // expected arguments of the called function.
Leon Clarkee46be812010-01-19 14:06:41 +00001395 int call_function_arg_count =
1396 CallFunctionStub::ExtractArgcFromMinorKey(
1397 CodeStub::MinorKeyFromKey(key));
Steve Blocka7e24c12009-10-30 11:49:00 +00001398 ASSERT(call_function_stub->major_key() ==
1399 CodeStub::MajorKeyFromKey(key));
1400
1401 // Find target function on the expression stack.
Leon Clarkee46be812010-01-19 14:06:41 +00001402 // Expression stack looks like this (top to bottom):
Steve Blocka7e24c12009-10-30 11:49:00 +00001403 // argN
1404 // ...
1405 // arg0
1406 // Receiver
1407 // Function to call
1408 int expressions_count = frame->ComputeExpressionsCount();
1409 ASSERT(expressions_count - 2 - call_function_arg_count >= 0);
1410 Object* fun = frame->GetExpression(
1411 expressions_count - 2 - call_function_arg_count);
1412 if (fun->IsJSFunction()) {
1413 Handle<JSFunction> js_function(JSFunction::cast(fun));
1414 // Don't step into builtins.
1415 if (!js_function->IsBuiltin()) {
1416 // It will also compile target function if it's not compiled yet.
1417 FloodWithOneShot(Handle<SharedFunctionInfo>(js_function->shared()));
1418 }
1419 }
1420 }
1421
1422 // Fill the current function with one-shot break points even for step in on
1423 // a call target as the function called might be a native function for
1424 // which step in will not stop. It also prepares for stepping in
1425 // getters/setters.
1426 FloodWithOneShot(shared);
1427
1428 if (is_load_or_store) {
1429 // Remember source position and frame to handle step in getter/setter. If
1430 // there is a custom getter/setter it will be handled in
1431 // Object::Get/SetPropertyWithCallback, otherwise the step action will be
1432 // propagated on the next Debug::Break.
1433 thread_local_.last_statement_position_ =
1434 debug_info->code()->SourceStatementPosition(frame->pc());
1435 thread_local_.last_fp_ = frame->fp();
1436 }
1437
1438 // Step in or Step in min
1439 it.PrepareStepIn();
1440 ActivateStepIn(frame);
1441 }
1442}
1443
1444
1445// Check whether the current debug break should be reported to the debugger. It
1446// is used to have step next and step in only report break back to the debugger
1447// if on a different frame or in a different statement. In some situations
1448// there will be several break points in the same statement when the code is
1449// flooded with one-shot break points. This function helps to perform several
1450// steps before reporting break back to the debugger.
1451bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
1452 JavaScriptFrame* frame) {
1453 // If the step last action was step next or step in make sure that a new
1454 // statement is hit.
1455 if (thread_local_.last_step_action_ == StepNext ||
1456 thread_local_.last_step_action_ == StepIn) {
1457 // Never continue if returning from function.
1458 if (break_location_iterator->IsExit()) return false;
1459
1460 // Continue if we are still on the same frame and in the same statement.
1461 int current_statement_position =
1462 break_location_iterator->code()->SourceStatementPosition(frame->pc());
1463 return thread_local_.last_fp_ == frame->fp() &&
1464 thread_local_.last_statement_position_ == current_statement_position;
1465 }
1466
1467 // No step next action - don't continue.
1468 return false;
1469}
1470
1471
1472// Check whether the code object at the specified address is a debug break code
1473// object.
1474bool Debug::IsDebugBreak(Address addr) {
1475 Code* code = Code::GetCodeFromTargetAddress(addr);
1476 return code->ic_state() == DEBUG_BREAK;
1477}
1478
1479
1480// Check whether a code stub with the specified major key is a possible break
1481// point location when looking for source break locations.
1482bool Debug::IsSourceBreakStub(Code* code) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001483 CodeStub::Major major_key = CodeStub::GetMajorKey(code);
Steve Blocka7e24c12009-10-30 11:49:00 +00001484 return major_key == CodeStub::CallFunction;
1485}
1486
1487
1488// Check whether a code stub with the specified major key is a possible break
1489// location.
1490bool Debug::IsBreakStub(Code* code) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001491 CodeStub::Major major_key = CodeStub::GetMajorKey(code);
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001492 return major_key == CodeStub::CallFunction;
Steve Blocka7e24c12009-10-30 11:49:00 +00001493}
1494
1495
1496// Find the builtin to use for invoking the debug break
1497Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
1498 // Find the builtin debug break function matching the calling convention
1499 // used by the call site.
1500 if (code->is_inline_cache_stub()) {
Steve Block6ded16b2010-05-10 14:33:55 +01001501 switch (code->kind()) {
1502 case Code::CALL_IC:
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001503 case Code::KEYED_CALL_IC:
1504 return ComputeCallDebugBreak(code->arguments_count(), code->kind());
Steve Block6ded16b2010-05-10 14:33:55 +01001505
1506 case Code::LOAD_IC:
Steve Block44f0eee2011-05-26 01:26:41 +01001507 return Isolate::Current()->builtins()->LoadIC_DebugBreak();
Steve Block6ded16b2010-05-10 14:33:55 +01001508
1509 case Code::STORE_IC:
Steve Block44f0eee2011-05-26 01:26:41 +01001510 return Isolate::Current()->builtins()->StoreIC_DebugBreak();
Steve Block6ded16b2010-05-10 14:33:55 +01001511
1512 case Code::KEYED_LOAD_IC:
Steve Block44f0eee2011-05-26 01:26:41 +01001513 return Isolate::Current()->builtins()->KeyedLoadIC_DebugBreak();
Steve Block6ded16b2010-05-10 14:33:55 +01001514
1515 case Code::KEYED_STORE_IC:
Steve Block44f0eee2011-05-26 01:26:41 +01001516 return Isolate::Current()->builtins()->KeyedStoreIC_DebugBreak();
Steve Block6ded16b2010-05-10 14:33:55 +01001517
1518 default:
1519 UNREACHABLE();
Steve Blocka7e24c12009-10-30 11:49:00 +00001520 }
1521 }
1522 if (RelocInfo::IsConstructCall(mode)) {
1523 Handle<Code> result =
Steve Block44f0eee2011-05-26 01:26:41 +01001524 Isolate::Current()->builtins()->ConstructCall_DebugBreak();
Steve Blocka7e24c12009-10-30 11:49:00 +00001525 return result;
1526 }
1527 if (code->kind() == Code::STUB) {
Teng-Hui Zhu3e5fa292010-11-09 16:16:48 -08001528 ASSERT(code->major_key() == CodeStub::CallFunction);
Steve Blocka7e24c12009-10-30 11:49:00 +00001529 Handle<Code> result =
Steve Block44f0eee2011-05-26 01:26:41 +01001530 Isolate::Current()->builtins()->StubNoRegisters_DebugBreak();
Steve Blocka7e24c12009-10-30 11:49:00 +00001531 return result;
1532 }
1533
1534 UNREACHABLE();
1535 return Handle<Code>::null();
1536}
1537
1538
1539// Simple function for returning the source positions for active break points.
1540Handle<Object> Debug::GetSourceBreakLocations(
1541 Handle<SharedFunctionInfo> shared) {
Steve Block44f0eee2011-05-26 01:26:41 +01001542 Isolate* isolate = Isolate::Current();
1543 Heap* heap = isolate->heap();
1544 if (!HasDebugInfo(shared)) return Handle<Object>(heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001545 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1546 if (debug_info->GetBreakPointCount() == 0) {
Steve Block44f0eee2011-05-26 01:26:41 +01001547 return Handle<Object>(heap->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001548 }
1549 Handle<FixedArray> locations =
Steve Block44f0eee2011-05-26 01:26:41 +01001550 isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount());
Steve Blocka7e24c12009-10-30 11:49:00 +00001551 int count = 0;
1552 for (int i = 0; i < debug_info->break_points()->length(); i++) {
1553 if (!debug_info->break_points()->get(i)->IsUndefined()) {
1554 BreakPointInfo* break_point_info =
1555 BreakPointInfo::cast(debug_info->break_points()->get(i));
1556 if (break_point_info->GetBreakPointCount() > 0) {
1557 locations->set(count++, break_point_info->statement_position());
1558 }
1559 }
1560 }
1561 return locations;
1562}
1563
1564
1565void Debug::NewBreak(StackFrame::Id break_frame_id) {
1566 thread_local_.break_frame_id_ = break_frame_id;
1567 thread_local_.break_id_ = ++thread_local_.break_count_;
1568}
1569
1570
1571void Debug::SetBreak(StackFrame::Id break_frame_id, int break_id) {
1572 thread_local_.break_frame_id_ = break_frame_id;
1573 thread_local_.break_id_ = break_id;
1574}
1575
1576
1577// Handle stepping into a function.
1578void Debug::HandleStepIn(Handle<JSFunction> function,
1579 Handle<Object> holder,
1580 Address fp,
1581 bool is_constructor) {
1582 // If the frame pointer is not supplied by the caller find it.
1583 if (fp == 0) {
1584 StackFrameIterator it;
1585 it.Advance();
1586 // For constructor functions skip another frame.
1587 if (is_constructor) {
1588 ASSERT(it.frame()->is_construct());
1589 it.Advance();
1590 }
1591 fp = it.frame()->fp();
1592 }
1593
1594 // Flood the function with one-shot break points if it is called from where
1595 // step into was requested.
Steve Block44f0eee2011-05-26 01:26:41 +01001596 if (fp == step_in_fp()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001597 // Don't allow step into functions in the native context.
1598 if (!function->IsBuiltin()) {
1599 if (function->shared()->code() ==
Steve Block44f0eee2011-05-26 01:26:41 +01001600 Isolate::Current()->builtins()->builtin(Builtins::kFunctionApply) ||
Steve Blocka7e24c12009-10-30 11:49:00 +00001601 function->shared()->code() ==
Steve Block44f0eee2011-05-26 01:26:41 +01001602 Isolate::Current()->builtins()->builtin(Builtins::kFunctionCall)) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001603 // Handle function.apply and function.call separately to flood the
1604 // function to be called and not the code for Builtins::FunctionApply or
1605 // Builtins::FunctionCall. The receiver of call/apply is the target
1606 // function.
1607 if (!holder.is_null() && holder->IsJSFunction() &&
1608 !JSFunction::cast(*holder)->IsBuiltin()) {
1609 Handle<SharedFunctionInfo> shared_info(
1610 JSFunction::cast(*holder)->shared());
1611 Debug::FloodWithOneShot(shared_info);
1612 }
1613 } else {
1614 Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1615 }
1616 }
1617 }
1618}
1619
1620
1621void Debug::ClearStepping() {
1622 // Clear the various stepping setup.
1623 ClearOneShot();
1624 ClearStepIn();
1625 ClearStepOut();
1626 ClearStepNext();
1627
1628 // Clear multiple step counter.
1629 thread_local_.step_count_ = 0;
1630}
1631
1632// Clears all the one-shot break points that are currently set. Normally this
1633// function is called each time a break point is hit as one shot break points
1634// are used to support stepping.
1635void Debug::ClearOneShot() {
1636 // The current implementation just runs through all the breakpoints. When the
1637 // last break point for a function is removed that function is automatically
1638 // removed from the list.
1639
1640 DebugInfoListNode* node = debug_info_list_;
1641 while (node != NULL) {
1642 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1643 while (!it.Done()) {
1644 it.ClearOneShot();
1645 it.Next();
1646 }
1647 node = node->next();
1648 }
1649}
1650
1651
1652void Debug::ActivateStepIn(StackFrame* frame) {
1653 ASSERT(!StepOutActive());
1654 thread_local_.step_into_fp_ = frame->fp();
1655}
1656
1657
1658void Debug::ClearStepIn() {
1659 thread_local_.step_into_fp_ = 0;
1660}
1661
1662
1663void Debug::ActivateStepOut(StackFrame* frame) {
1664 ASSERT(!StepInActive());
1665 thread_local_.step_out_fp_ = frame->fp();
1666}
1667
1668
1669void Debug::ClearStepOut() {
1670 thread_local_.step_out_fp_ = 0;
1671}
1672
1673
1674void Debug::ClearStepNext() {
1675 thread_local_.last_step_action_ = StepNone;
1676 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
1677 thread_local_.last_fp_ = 0;
1678}
1679
1680
Steve Blocka7e24c12009-10-30 11:49:00 +00001681// Ensures the debug information is present for shared.
1682bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
1683 // Return if we already have the debug info for shared.
1684 if (HasDebugInfo(shared)) return true;
1685
1686 // Ensure shared in compiled. Return false if this failed.
Leon Clarke4515c472010-02-03 11:58:03 +00001687 if (!EnsureCompiled(shared, CLEAR_EXCEPTION)) return false;
Steve Blocka7e24c12009-10-30 11:49:00 +00001688
Ben Murdochb0fe1622011-05-05 13:52:32 +01001689 // If preparing for the first break point make sure to deoptimize all
1690 // functions as debugging does not work with optimized code.
1691 if (!has_break_points_) {
1692 Deoptimizer::DeoptimizeAll();
1693 }
1694
Steve Blocka7e24c12009-10-30 11:49:00 +00001695 // Create the debug info object.
Steve Block44f0eee2011-05-26 01:26:41 +01001696 Handle<DebugInfo> debug_info = FACTORY->NewDebugInfo(shared);
Steve Blocka7e24c12009-10-30 11:49:00 +00001697
1698 // Add debug info to the list.
1699 DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
1700 node->set_next(debug_info_list_);
1701 debug_info_list_ = node;
1702
1703 // Now there is at least one break point.
1704 has_break_points_ = true;
1705
1706 return true;
1707}
1708
1709
1710void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
1711 ASSERT(debug_info_list_ != NULL);
1712 // Run through the debug info objects to find this one and remove it.
1713 DebugInfoListNode* prev = NULL;
1714 DebugInfoListNode* current = debug_info_list_;
1715 while (current != NULL) {
1716 if (*current->debug_info() == *debug_info) {
1717 // Unlink from list. If prev is NULL we are looking at the first element.
1718 if (prev == NULL) {
1719 debug_info_list_ = current->next();
1720 } else {
1721 prev->set_next(current->next());
1722 }
Steve Block44f0eee2011-05-26 01:26:41 +01001723 current->debug_info()->shared()->set_debug_info(
1724 isolate_->heap()->undefined_value());
Steve Blocka7e24c12009-10-30 11:49:00 +00001725 delete current;
1726
1727 // If there are no more debug info objects there are not more break
1728 // points.
1729 has_break_points_ = debug_info_list_ != NULL;
1730
1731 return;
1732 }
1733 // Move to next in list.
1734 prev = current;
1735 current = current->next();
1736 }
1737 UNREACHABLE();
1738}
1739
1740
1741void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
Steve Block44f0eee2011-05-26 01:26:41 +01001742 ASSERT(Isolate::Current() == isolate_);
1743 HandleScope scope(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00001744
1745 // Get the executing function in which the debug break occurred.
1746 Handle<SharedFunctionInfo> shared =
1747 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
1748 if (!EnsureDebugInfo(shared)) {
1749 // Return if we failed to retrieve the debug info.
1750 return;
1751 }
1752 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1753 Handle<Code> code(debug_info->code());
1754 Handle<Code> original_code(debug_info->original_code());
1755#ifdef DEBUG
1756 // Get the code which is actually executing.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001757 Handle<Code> frame_code(frame->LookupCode());
Steve Blocka7e24c12009-10-30 11:49:00 +00001758 ASSERT(frame_code.is_identical_to(code));
1759#endif
1760
1761 // Find the call address in the running code. This address holds the call to
1762 // either a DebugBreakXXX or to the debug break return entry code if the
1763 // break point is still active after processing the break point.
1764 Address addr = frame->pc() - Assembler::kCallTargetAddressOffset;
1765
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001766 // Check if the location is at JS exit or debug break slot.
Steve Blocka7e24c12009-10-30 11:49:00 +00001767 bool at_js_return = false;
1768 bool break_at_js_return_active = false;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001769 bool at_debug_break_slot = false;
Steve Blocka7e24c12009-10-30 11:49:00 +00001770 RelocIterator it(debug_info->code());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001771 while (!it.done() && !at_js_return && !at_debug_break_slot) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001772 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
1773 at_js_return = (it.rinfo()->pc() ==
1774 addr - Assembler::kPatchReturnSequenceAddressOffset);
Steve Block3ce2e202009-11-05 08:53:23 +00001775 break_at_js_return_active = it.rinfo()->IsPatchedReturnSequence();
Steve Blocka7e24c12009-10-30 11:49:00 +00001776 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001777 if (RelocInfo::IsDebugBreakSlot(it.rinfo()->rmode())) {
1778 at_debug_break_slot = (it.rinfo()->pc() ==
1779 addr - Assembler::kPatchDebugBreakSlotAddressOffset);
1780 }
Steve Blocka7e24c12009-10-30 11:49:00 +00001781 it.next();
1782 }
1783
1784 // Handle the jump to continue execution after break point depending on the
1785 // break location.
1786 if (at_js_return) {
1787 // If the break point as return is still active jump to the corresponding
1788 // place in the original code. If not the break point was removed during
1789 // break point processing.
1790 if (break_at_js_return_active) {
1791 addr += original_code->instruction_start() - code->instruction_start();
1792 }
1793
1794 // Move back to where the call instruction sequence started.
1795 thread_local_.after_break_target_ =
1796 addr - Assembler::kPatchReturnSequenceAddressOffset;
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001797 } else if (at_debug_break_slot) {
1798 // Address of where the debug break slot starts.
1799 addr = addr - Assembler::kPatchDebugBreakSlotAddressOffset;
Steve Blocka7e24c12009-10-30 11:49:00 +00001800
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001801 // Continue just after the slot.
1802 thread_local_.after_break_target_ = addr + Assembler::kDebugBreakSlotLength;
1803 } else if (IsDebugBreak(Assembler::target_address_at(addr))) {
1804 // We now know that there is still a debug break call at the target address,
1805 // so the break point is still there and the original code will hold the
1806 // address to jump to in order to complete the call which is replaced by a
1807 // call to DebugBreakXXX.
1808
1809 // Find the corresponding address in the original code.
1810 addr += original_code->instruction_start() - code->instruction_start();
Steve Blocka7e24c12009-10-30 11:49:00 +00001811
1812 // Install jump to the call address in the original code. This will be the
1813 // call which was overwritten by the call to DebugBreakXXX.
1814 thread_local_.after_break_target_ = Assembler::target_address_at(addr);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001815 } else {
1816 // There is no longer a break point present. Don't try to look in the
1817 // original code as the running code will have the right address. This takes
1818 // care of the case where the last break point is removed from the function
1819 // and therefore no "original code" is available.
1820 thread_local_.after_break_target_ = Assembler::target_address_at(addr);
Steve Blocka7e24c12009-10-30 11:49:00 +00001821 }
1822}
1823
1824
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001825bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
Steve Block44f0eee2011-05-26 01:26:41 +01001826 HandleScope scope(isolate_);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001827
1828 // Get the executing function in which the debug break occurred.
1829 Handle<SharedFunctionInfo> shared =
1830 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
1831 if (!EnsureDebugInfo(shared)) {
1832 // Return if we failed to retrieve the debug info.
1833 return false;
1834 }
1835 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1836 Handle<Code> code(debug_info->code());
1837#ifdef DEBUG
1838 // Get the code which is actually executing.
Ben Murdoch8b112d22011-06-08 16:22:53 +01001839 Handle<Code> frame_code(frame->LookupCode());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001840 ASSERT(frame_code.is_identical_to(code));
1841#endif
1842
1843 // Find the call address in the running code.
1844 Address addr = frame->pc() - Assembler::kCallTargetAddressOffset;
1845
1846 // Check if the location is at JS return.
1847 RelocIterator it(debug_info->code());
1848 while (!it.done()) {
1849 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
1850 return (it.rinfo()->pc() ==
1851 addr - Assembler::kPatchReturnSequenceAddressOffset);
1852 }
1853 it.next();
1854 }
1855 return false;
1856}
1857
1858
Steve Block8defd9f2010-07-08 12:39:36 +01001859void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
Ben Murdochbb769b22010-08-11 14:56:33 +01001860 FrameDropMode mode,
1861 Object** restarter_frame_function_pointer) {
Steve Block8defd9f2010-07-08 12:39:36 +01001862 thread_local_.frame_drop_mode_ = mode;
Steve Block6ded16b2010-05-10 14:33:55 +01001863 thread_local_.break_frame_id_ = new_break_frame_id;
Ben Murdochbb769b22010-08-11 14:56:33 +01001864 thread_local_.restarter_frame_function_pointer_ =
1865 restarter_frame_function_pointer;
Steve Block6ded16b2010-05-10 14:33:55 +01001866}
1867
1868
Steve Blocka7e24c12009-10-30 11:49:00 +00001869bool Debug::IsDebugGlobal(GlobalObject* global) {
Steve Block44f0eee2011-05-26 01:26:41 +01001870 return IsLoaded() && global == debug_context()->global();
Steve Blocka7e24c12009-10-30 11:49:00 +00001871}
1872
1873
1874void Debug::ClearMirrorCache() {
Steve Block44f0eee2011-05-26 01:26:41 +01001875 ASSERT(Isolate::Current() == isolate_);
1876 PostponeInterruptsScope postpone(isolate_);
1877 HandleScope scope(isolate_);
1878 ASSERT(isolate_->context() == *Debug::debug_context());
Steve Blocka7e24c12009-10-30 11:49:00 +00001879
1880 // Clear the mirror cache.
1881 Handle<String> function_name =
Steve Block44f0eee2011-05-26 01:26:41 +01001882 isolate_->factory()->LookupSymbol(CStrVector("ClearMirrorCache"));
1883 Handle<Object> fun(Isolate::Current()->global()->GetPropertyNoExceptionThrown(
John Reck59135872010-11-02 12:39:01 -07001884 *function_name));
Steve Blocka7e24c12009-10-30 11:49:00 +00001885 ASSERT(fun->IsJSFunction());
1886 bool caught_exception;
1887 Handle<Object> js_object = Execution::TryCall(
1888 Handle<JSFunction>::cast(fun),
1889 Handle<JSObject>(Debug::debug_context()->global()),
1890 0, NULL, &caught_exception);
1891}
1892
1893
Steve Blocka7e24c12009-10-30 11:49:00 +00001894void Debug::CreateScriptCache() {
Steve Block44f0eee2011-05-26 01:26:41 +01001895 ASSERT(Isolate::Current() == isolate_);
1896 Heap* heap = isolate_->heap();
1897 HandleScope scope(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00001898
1899 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
1900 // rid of all the cached script wrappers and the second gets rid of the
Andrei Popescu31002712010-02-23 13:46:05 +00001901 // scripts which are no longer referenced.
Steve Block44f0eee2011-05-26 01:26:41 +01001902 heap->CollectAllGarbage(false);
1903 heap->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001904
1905 ASSERT(script_cache_ == NULL);
1906 script_cache_ = new ScriptCache();
1907
1908 // Scan heap for Script objects.
1909 int count = 0;
1910 HeapIterator iterator;
Leon Clarked91b9f72010-01-27 17:25:45 +00001911 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
Steve Block3ce2e202009-11-05 08:53:23 +00001912 if (obj->IsScript() && Script::cast(obj)->HasValidSource()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001913 script_cache_->Add(Handle<Script>(Script::cast(obj)));
1914 count++;
1915 }
1916 }
1917}
1918
1919
1920void Debug::DestroyScriptCache() {
1921 // Get rid of the script cache if it was created.
1922 if (script_cache_ != NULL) {
1923 delete script_cache_;
1924 script_cache_ = NULL;
1925 }
1926}
1927
1928
1929void Debug::AddScriptToScriptCache(Handle<Script> script) {
1930 if (script_cache_ != NULL) {
1931 script_cache_->Add(script);
1932 }
1933}
1934
1935
1936Handle<FixedArray> Debug::GetLoadedScripts() {
Steve Block44f0eee2011-05-26 01:26:41 +01001937 ASSERT(Isolate::Current() == isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00001938 // Create and fill the script cache when the loaded scripts is requested for
1939 // the first time.
1940 if (script_cache_ == NULL) {
1941 CreateScriptCache();
1942 }
1943
1944 // If the script cache is not active just return an empty array.
1945 ASSERT(script_cache_ != NULL);
1946 if (script_cache_ == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01001947 isolate_->factory()->NewFixedArray(0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001948 }
1949
1950 // Perform GC to get unreferenced scripts evicted from the cache before
1951 // returning the content.
Steve Block44f0eee2011-05-26 01:26:41 +01001952 isolate_->heap()->CollectAllGarbage(false);
Steve Blocka7e24c12009-10-30 11:49:00 +00001953
1954 // Get the scripts from the cache.
1955 return script_cache_->GetScripts();
1956}
1957
1958
1959void Debug::AfterGarbageCollection() {
1960 // Generate events for collected scripts.
1961 if (script_cache_ != NULL) {
1962 script_cache_->ProcessCollectedScripts();
1963 }
1964}
1965
1966
Ben Murdoch257744e2011-11-30 15:57:28 +00001967Debugger::Debugger()
1968 : debugger_access_(OS::CreateMutex()),
Steve Block44f0eee2011-05-26 01:26:41 +01001969 event_listener_(Handle<Object>()),
1970 event_listener_data_(Handle<Object>()),
1971 compiling_natives_(false),
1972 is_loading_debugger_(false),
1973 never_unload_debugger_(false),
1974 message_handler_(NULL),
1975 debugger_unload_pending_(false),
1976 host_dispatch_handler_(NULL),
1977 dispatch_handler_access_(OS::CreateMutex()),
1978 debug_message_dispatch_handler_(NULL),
1979 message_dispatch_helper_thread_(NULL),
1980 host_dispatch_micros_(100 * 1000),
1981 agent_(NULL),
1982 command_queue_(kQueueInitialSize),
1983 command_received_(OS::CreateSemaphore(0)),
Ben Murdoch257744e2011-11-30 15:57:28 +00001984 event_command_queue_(kQueueInitialSize) {
Steve Block44f0eee2011-05-26 01:26:41 +01001985}
1986
1987
1988Debugger::~Debugger() {
Ben Murdoch257744e2011-11-30 15:57:28 +00001989 delete debugger_access_;
1990 debugger_access_ = 0;
Steve Block44f0eee2011-05-26 01:26:41 +01001991 delete dispatch_handler_access_;
1992 dispatch_handler_access_ = 0;
1993 delete command_received_;
1994 command_received_ = 0;
1995}
Steve Blocka7e24c12009-10-30 11:49:00 +00001996
1997
1998Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
1999 int argc, Object*** argv,
2000 bool* caught_exception) {
Steve Block44f0eee2011-05-26 01:26:41 +01002001 ASSERT(Isolate::Current() == isolate_);
2002 ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
Steve Blocka7e24c12009-10-30 11:49:00 +00002003
2004 // Create the execution state object.
Steve Block44f0eee2011-05-26 01:26:41 +01002005 Handle<String> constructor_str =
2006 isolate_->factory()->LookupSymbol(constructor_name);
2007 Handle<Object> constructor(
2008 isolate_->global()->GetPropertyNoExceptionThrown(*constructor_str));
Steve Blocka7e24c12009-10-30 11:49:00 +00002009 ASSERT(constructor->IsJSFunction());
2010 if (!constructor->IsJSFunction()) {
2011 *caught_exception = true;
Steve Block44f0eee2011-05-26 01:26:41 +01002012 return isolate_->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002013 }
2014 Handle<Object> js_object = Execution::TryCall(
2015 Handle<JSFunction>::cast(constructor),
Steve Block44f0eee2011-05-26 01:26:41 +01002016 Handle<JSObject>(isolate_->debug()->debug_context()->global()),
2017 argc, argv, caught_exception);
Steve Blocka7e24c12009-10-30 11:49:00 +00002018 return js_object;
2019}
2020
2021
2022Handle<Object> Debugger::MakeExecutionState(bool* caught_exception) {
Steve Block44f0eee2011-05-26 01:26:41 +01002023 ASSERT(Isolate::Current() == isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002024 // Create the execution state object.
Steve Block44f0eee2011-05-26 01:26:41 +01002025 Handle<Object> break_id = isolate_->factory()->NewNumberFromInt(
2026 isolate_->debug()->break_id());
Steve Blocka7e24c12009-10-30 11:49:00 +00002027 const int argc = 1;
2028 Object** argv[argc] = { break_id.location() };
2029 return MakeJSObject(CStrVector("MakeExecutionState"),
2030 argc, argv, caught_exception);
2031}
2032
2033
2034Handle<Object> Debugger::MakeBreakEvent(Handle<Object> exec_state,
2035 Handle<Object> break_points_hit,
2036 bool* caught_exception) {
Steve Block44f0eee2011-05-26 01:26:41 +01002037 ASSERT(Isolate::Current() == isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002038 // Create the new break event object.
2039 const int argc = 2;
2040 Object** argv[argc] = { exec_state.location(),
2041 break_points_hit.location() };
2042 return MakeJSObject(CStrVector("MakeBreakEvent"),
2043 argc,
2044 argv,
2045 caught_exception);
2046}
2047
2048
2049Handle<Object> Debugger::MakeExceptionEvent(Handle<Object> exec_state,
2050 Handle<Object> exception,
2051 bool uncaught,
2052 bool* caught_exception) {
Steve Block44f0eee2011-05-26 01:26:41 +01002053 ASSERT(Isolate::Current() == isolate_);
2054 Factory* factory = isolate_->factory();
Steve Blocka7e24c12009-10-30 11:49:00 +00002055 // Create the new exception event object.
2056 const int argc = 3;
2057 Object** argv[argc] = { exec_state.location(),
2058 exception.location(),
Steve Block44f0eee2011-05-26 01:26:41 +01002059 uncaught ? factory->true_value().location() :
2060 factory->false_value().location()};
Steve Blocka7e24c12009-10-30 11:49:00 +00002061 return MakeJSObject(CStrVector("MakeExceptionEvent"),
2062 argc, argv, caught_exception);
2063}
2064
2065
2066Handle<Object> Debugger::MakeNewFunctionEvent(Handle<Object> function,
2067 bool* caught_exception) {
Steve Block44f0eee2011-05-26 01:26:41 +01002068 ASSERT(Isolate::Current() == isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002069 // Create the new function event object.
2070 const int argc = 1;
2071 Object** argv[argc] = { function.location() };
2072 return MakeJSObject(CStrVector("MakeNewFunctionEvent"),
2073 argc, argv, caught_exception);
2074}
2075
2076
2077Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
2078 bool before,
2079 bool* caught_exception) {
Steve Block44f0eee2011-05-26 01:26:41 +01002080 ASSERT(Isolate::Current() == isolate_);
2081 Factory* factory = isolate_->factory();
Steve Blocka7e24c12009-10-30 11:49:00 +00002082 // Create the compile event object.
2083 Handle<Object> exec_state = MakeExecutionState(caught_exception);
2084 Handle<Object> script_wrapper = GetScriptWrapper(script);
2085 const int argc = 3;
2086 Object** argv[argc] = { exec_state.location(),
2087 script_wrapper.location(),
Steve Block44f0eee2011-05-26 01:26:41 +01002088 before ? factory->true_value().location() :
2089 factory->false_value().location() };
Steve Blocka7e24c12009-10-30 11:49:00 +00002090
2091 return MakeJSObject(CStrVector("MakeCompileEvent"),
2092 argc,
2093 argv,
2094 caught_exception);
2095}
2096
2097
2098Handle<Object> Debugger::MakeScriptCollectedEvent(int id,
2099 bool* caught_exception) {
Steve Block44f0eee2011-05-26 01:26:41 +01002100 ASSERT(Isolate::Current() == isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002101 // Create the script collected event object.
2102 Handle<Object> exec_state = MakeExecutionState(caught_exception);
2103 Handle<Object> id_object = Handle<Smi>(Smi::FromInt(id));
2104 const int argc = 2;
2105 Object** argv[argc] = { exec_state.location(), id_object.location() };
2106
2107 return MakeJSObject(CStrVector("MakeScriptCollectedEvent"),
2108 argc,
2109 argv,
2110 caught_exception);
2111}
2112
2113
2114void Debugger::OnException(Handle<Object> exception, bool uncaught) {
Steve Block44f0eee2011-05-26 01:26:41 +01002115 ASSERT(Isolate::Current() == isolate_);
2116 HandleScope scope(isolate_);
2117 Debug* debug = isolate_->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +00002118
2119 // Bail out based on state or if there is no listener for this event
Steve Block44f0eee2011-05-26 01:26:41 +01002120 if (debug->InDebugger()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002121 if (!Debugger::EventActive(v8::Exception)) return;
2122
2123 // Bail out if exception breaks are not active
2124 if (uncaught) {
2125 // Uncaught exceptions are reported by either flags.
Steve Block44f0eee2011-05-26 01:26:41 +01002126 if (!(debug->break_on_uncaught_exception() ||
2127 debug->break_on_exception())) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002128 } else {
2129 // Caught exceptions are reported is activated.
Steve Block44f0eee2011-05-26 01:26:41 +01002130 if (!debug->break_on_exception()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002131 }
2132
2133 // Enter the debugger.
2134 EnterDebugger debugger;
2135 if (debugger.FailedToEnter()) return;
2136
2137 // Clear all current stepping setup.
Steve Block44f0eee2011-05-26 01:26:41 +01002138 debug->ClearStepping();
Steve Blocka7e24c12009-10-30 11:49:00 +00002139 // Create the event data object.
2140 bool caught_exception = false;
2141 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2142 Handle<Object> event_data;
2143 if (!caught_exception) {
2144 event_data = MakeExceptionEvent(exec_state, exception, uncaught,
2145 &caught_exception);
2146 }
2147 // Bail out and don't call debugger if exception.
2148 if (caught_exception) {
2149 return;
2150 }
2151
2152 // Process debug event.
2153 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false);
2154 // Return to continue execution from where the exception was thrown.
2155}
2156
2157
2158void Debugger::OnDebugBreak(Handle<Object> break_points_hit,
2159 bool auto_continue) {
Steve Block44f0eee2011-05-26 01:26:41 +01002160 ASSERT(Isolate::Current() == isolate_);
2161 HandleScope scope(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002162
2163 // Debugger has already been entered by caller.
Steve Block44f0eee2011-05-26 01:26:41 +01002164 ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
Steve Blocka7e24c12009-10-30 11:49:00 +00002165
2166 // Bail out if there is no listener for this event
2167 if (!Debugger::EventActive(v8::Break)) return;
2168
2169 // Debugger must be entered in advance.
Steve Block44f0eee2011-05-26 01:26:41 +01002170 ASSERT(Isolate::Current()->context() == *isolate_->debug()->debug_context());
Steve Blocka7e24c12009-10-30 11:49:00 +00002171
2172 // Create the event data object.
2173 bool caught_exception = false;
2174 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2175 Handle<Object> event_data;
2176 if (!caught_exception) {
2177 event_data = MakeBreakEvent(exec_state, break_points_hit,
2178 &caught_exception);
2179 }
2180 // Bail out and don't call debugger if exception.
2181 if (caught_exception) {
2182 return;
2183 }
2184
2185 // Process debug event.
2186 ProcessDebugEvent(v8::Break,
2187 Handle<JSObject>::cast(event_data),
2188 auto_continue);
2189}
2190
2191
2192void Debugger::OnBeforeCompile(Handle<Script> script) {
Steve Block44f0eee2011-05-26 01:26:41 +01002193 ASSERT(Isolate::Current() == isolate_);
2194 HandleScope scope(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002195
2196 // Bail out based on state or if there is no listener for this event
Steve Block44f0eee2011-05-26 01:26:41 +01002197 if (isolate_->debug()->InDebugger()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002198 if (compiling_natives()) return;
2199 if (!EventActive(v8::BeforeCompile)) return;
2200
2201 // Enter the debugger.
2202 EnterDebugger debugger;
2203 if (debugger.FailedToEnter()) return;
2204
2205 // Create the event data object.
2206 bool caught_exception = false;
2207 Handle<Object> event_data = MakeCompileEvent(script, true, &caught_exception);
2208 // Bail out and don't call debugger if exception.
2209 if (caught_exception) {
2210 return;
2211 }
2212
2213 // Process debug event.
2214 ProcessDebugEvent(v8::BeforeCompile,
2215 Handle<JSObject>::cast(event_data),
2216 true);
2217}
2218
2219
2220// Handle debugger actions when a new script is compiled.
Steve Block6ded16b2010-05-10 14:33:55 +01002221void Debugger::OnAfterCompile(Handle<Script> script,
2222 AfterCompileFlags after_compile_flags) {
Steve Block44f0eee2011-05-26 01:26:41 +01002223 ASSERT(Isolate::Current() == isolate_);
2224 HandleScope scope(isolate_);
2225 Debug* debug = isolate_->debug();
Steve Blocka7e24c12009-10-30 11:49:00 +00002226
2227 // Add the newly compiled script to the script cache.
Steve Block44f0eee2011-05-26 01:26:41 +01002228 debug->AddScriptToScriptCache(script);
Steve Blocka7e24c12009-10-30 11:49:00 +00002229
2230 // No more to do if not debugging.
2231 if (!IsDebuggerActive()) return;
2232
2233 // No compile events while compiling natives.
2234 if (compiling_natives()) return;
2235
2236 // Store whether in debugger before entering debugger.
Steve Block44f0eee2011-05-26 01:26:41 +01002237 bool in_debugger = debug->InDebugger();
Steve Blocka7e24c12009-10-30 11:49:00 +00002238
2239 // Enter the debugger.
2240 EnterDebugger debugger;
2241 if (debugger.FailedToEnter()) return;
2242
2243 // If debugging there might be script break points registered for this
2244 // script. Make sure that these break points are set.
2245
Andrei Popescu31002712010-02-23 13:46:05 +00002246 // Get the function UpdateScriptBreakPoints (defined in debug-debugger.js).
Kristian Monsen0d5e1162010-09-30 15:31:59 +01002247 Handle<String> update_script_break_points_symbol =
Steve Block44f0eee2011-05-26 01:26:41 +01002248 isolate_->factory()->LookupAsciiSymbol("UpdateScriptBreakPoints");
Steve Blocka7e24c12009-10-30 11:49:00 +00002249 Handle<Object> update_script_break_points =
Steve Block44f0eee2011-05-26 01:26:41 +01002250 Handle<Object>(debug->debug_context()->global()->
John Reck59135872010-11-02 12:39:01 -07002251 GetPropertyNoExceptionThrown(*update_script_break_points_symbol));
Steve Blocka7e24c12009-10-30 11:49:00 +00002252 if (!update_script_break_points->IsJSFunction()) {
2253 return;
2254 }
2255 ASSERT(update_script_break_points->IsJSFunction());
2256
2257 // Wrap the script object in a proper JS object before passing it
2258 // to JavaScript.
2259 Handle<JSValue> wrapper = GetScriptWrapper(script);
2260
2261 // Call UpdateScriptBreakPoints expect no exceptions.
2262 bool caught_exception = false;
2263 const int argc = 1;
2264 Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) };
2265 Handle<Object> result = Execution::TryCall(
2266 Handle<JSFunction>::cast(update_script_break_points),
Steve Block44f0eee2011-05-26 01:26:41 +01002267 Isolate::Current()->js_builtins_object(), argc, argv,
Steve Blocka7e24c12009-10-30 11:49:00 +00002268 &caught_exception);
2269 if (caught_exception) {
2270 return;
2271 }
2272 // Bail out based on state or if there is no listener for this event
Steve Block6ded16b2010-05-10 14:33:55 +01002273 if (in_debugger && (after_compile_flags & SEND_WHEN_DEBUGGING) == 0) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002274 if (!Debugger::EventActive(v8::AfterCompile)) return;
2275
2276 // Create the compile state object.
2277 Handle<Object> event_data = MakeCompileEvent(script,
2278 false,
2279 &caught_exception);
2280 // Bail out and don't call debugger if exception.
2281 if (caught_exception) {
2282 return;
2283 }
2284 // Process debug event.
2285 ProcessDebugEvent(v8::AfterCompile,
2286 Handle<JSObject>::cast(event_data),
2287 true);
2288}
2289
2290
Steve Blocka7e24c12009-10-30 11:49:00 +00002291void Debugger::OnScriptCollected(int id) {
Steve Block44f0eee2011-05-26 01:26:41 +01002292 ASSERT(Isolate::Current() == isolate_);
2293 HandleScope scope(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002294
2295 // No more to do if not debugging.
2296 if (!IsDebuggerActive()) return;
2297 if (!Debugger::EventActive(v8::ScriptCollected)) return;
2298
2299 // Enter the debugger.
2300 EnterDebugger debugger;
2301 if (debugger.FailedToEnter()) return;
2302
2303 // Create the script collected state object.
2304 bool caught_exception = false;
2305 Handle<Object> event_data = MakeScriptCollectedEvent(id,
2306 &caught_exception);
2307 // Bail out and don't call debugger if exception.
2308 if (caught_exception) {
2309 return;
2310 }
2311
2312 // Process debug event.
2313 ProcessDebugEvent(v8::ScriptCollected,
2314 Handle<JSObject>::cast(event_data),
2315 true);
2316}
2317
2318
2319void Debugger::ProcessDebugEvent(v8::DebugEvent event,
2320 Handle<JSObject> event_data,
2321 bool auto_continue) {
Steve Block44f0eee2011-05-26 01:26:41 +01002322 ASSERT(Isolate::Current() == isolate_);
2323 HandleScope scope(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002324
2325 // Clear any pending debug break if this is a real break.
2326 if (!auto_continue) {
Steve Block44f0eee2011-05-26 01:26:41 +01002327 isolate_->debug()->clear_interrupt_pending(DEBUGBREAK);
Steve Blocka7e24c12009-10-30 11:49:00 +00002328 }
2329
2330 // Create the execution state.
2331 bool caught_exception = false;
2332 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2333 if (caught_exception) {
2334 return;
2335 }
2336 // First notify the message handler if any.
2337 if (message_handler_ != NULL) {
2338 NotifyMessageHandler(event,
2339 Handle<JSObject>::cast(exec_state),
2340 event_data,
2341 auto_continue);
2342 }
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002343 // Notify registered debug event listener. This can be either a C or
2344 // a JavaScript function. Don't call event listener for v8::Break
2345 // here, if it's only a debug command -- they will be processed later.
2346 if ((event != v8::Break || !auto_continue) && !event_listener_.is_null()) {
2347 CallEventCallback(event, exec_state, event_data, NULL);
2348 }
2349 // Process pending debug commands.
2350 if (event == v8::Break) {
2351 while (!event_command_queue_.IsEmpty()) {
2352 CommandMessage command = event_command_queue_.Get();
2353 if (!event_listener_.is_null()) {
2354 CallEventCallback(v8::BreakForCommand,
2355 exec_state,
2356 event_data,
2357 command.client_data());
2358 }
2359 command.Dispose();
Steve Blocka7e24c12009-10-30 11:49:00 +00002360 }
2361 }
2362}
2363
2364
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002365void Debugger::CallEventCallback(v8::DebugEvent event,
2366 Handle<Object> exec_state,
2367 Handle<Object> event_data,
2368 v8::Debug::ClientData* client_data) {
Ben Murdoch257744e2011-11-30 15:57:28 +00002369 if (event_listener_->IsForeign()) {
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002370 CallCEventCallback(event, exec_state, event_data, client_data);
2371 } else {
2372 CallJSEventCallback(event, exec_state, event_data);
2373 }
2374}
2375
2376
2377void Debugger::CallCEventCallback(v8::DebugEvent event,
2378 Handle<Object> exec_state,
2379 Handle<Object> event_data,
2380 v8::Debug::ClientData* client_data) {
Ben Murdoch257744e2011-11-30 15:57:28 +00002381 Handle<Foreign> callback_obj(Handle<Foreign>::cast(event_listener_));
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002382 v8::Debug::EventCallback2 callback =
Ben Murdoch257744e2011-11-30 15:57:28 +00002383 FUNCTION_CAST<v8::Debug::EventCallback2>(callback_obj->address());
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002384 EventDetailsImpl event_details(
2385 event,
2386 Handle<JSObject>::cast(exec_state),
2387 Handle<JSObject>::cast(event_data),
2388 event_listener_data_,
2389 client_data);
2390 callback(event_details);
2391}
2392
2393
2394void Debugger::CallJSEventCallback(v8::DebugEvent event,
2395 Handle<Object> exec_state,
2396 Handle<Object> event_data) {
2397 ASSERT(event_listener_->IsJSFunction());
Steve Block44f0eee2011-05-26 01:26:41 +01002398 ASSERT(Isolate::Current() == isolate_);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002399 Handle<JSFunction> fun(Handle<JSFunction>::cast(event_listener_));
2400
2401 // Invoke the JavaScript debug event listener.
2402 const int argc = 4;
2403 Object** argv[argc] = { Handle<Object>(Smi::FromInt(event)).location(),
2404 exec_state.location(),
2405 Handle<Object>::cast(event_data).location(),
2406 event_listener_data_.location() };
2407 bool caught_exception = false;
Steve Block44f0eee2011-05-26 01:26:41 +01002408 Execution::TryCall(fun, isolate_->global(), argc, argv, &caught_exception);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002409 // Silently ignore exceptions from debug event listeners.
2410}
2411
2412
Steve Block6ded16b2010-05-10 14:33:55 +01002413Handle<Context> Debugger::GetDebugContext() {
Steve Block44f0eee2011-05-26 01:26:41 +01002414 ASSERT(Isolate::Current() == isolate_);
2415 never_unload_debugger_ = true;
2416 EnterDebugger debugger;
2417 return isolate_->debug()->debug_context();
Steve Block6ded16b2010-05-10 14:33:55 +01002418}
2419
2420
Steve Blocka7e24c12009-10-30 11:49:00 +00002421void Debugger::UnloadDebugger() {
Steve Block44f0eee2011-05-26 01:26:41 +01002422 ASSERT(Isolate::Current() == isolate_);
2423 Debug* debug = isolate_->debug();
2424
Steve Blocka7e24c12009-10-30 11:49:00 +00002425 // Make sure that there are no breakpoints left.
Steve Block44f0eee2011-05-26 01:26:41 +01002426 debug->ClearAllBreakPoints();
Steve Blocka7e24c12009-10-30 11:49:00 +00002427
2428 // Unload the debugger if feasible.
2429 if (!never_unload_debugger_) {
Steve Block44f0eee2011-05-26 01:26:41 +01002430 debug->Unload();
Steve Blocka7e24c12009-10-30 11:49:00 +00002431 }
2432
2433 // Clear the flag indicating that the debugger should be unloaded.
2434 debugger_unload_pending_ = false;
2435}
2436
2437
2438void Debugger::NotifyMessageHandler(v8::DebugEvent event,
2439 Handle<JSObject> exec_state,
2440 Handle<JSObject> event_data,
2441 bool auto_continue) {
Steve Block44f0eee2011-05-26 01:26:41 +01002442 ASSERT(Isolate::Current() == isolate_);
2443 HandleScope scope(isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002444
Steve Block44f0eee2011-05-26 01:26:41 +01002445 if (!isolate_->debug()->Load()) return;
Steve Blocka7e24c12009-10-30 11:49:00 +00002446
2447 // Process the individual events.
2448 bool sendEventMessage = false;
2449 switch (event) {
2450 case v8::Break:
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002451 case v8::BreakForCommand:
Steve Blocka7e24c12009-10-30 11:49:00 +00002452 sendEventMessage = !auto_continue;
2453 break;
2454 case v8::Exception:
2455 sendEventMessage = true;
2456 break;
2457 case v8::BeforeCompile:
2458 break;
2459 case v8::AfterCompile:
2460 sendEventMessage = true;
2461 break;
2462 case v8::ScriptCollected:
2463 sendEventMessage = true;
2464 break;
2465 case v8::NewFunction:
2466 break;
2467 default:
2468 UNREACHABLE();
2469 }
2470
2471 // The debug command interrupt flag might have been set when the command was
2472 // added. It should be enough to clear the flag only once while we are in the
2473 // debugger.
Steve Block44f0eee2011-05-26 01:26:41 +01002474 ASSERT(isolate_->debug()->InDebugger());
2475 isolate_->stack_guard()->Continue(DEBUGCOMMAND);
Steve Blocka7e24c12009-10-30 11:49:00 +00002476
2477 // Notify the debugger that a debug event has occurred unless auto continue is
2478 // active in which case no event is send.
2479 if (sendEventMessage) {
2480 MessageImpl message = MessageImpl::NewEvent(
2481 event,
2482 auto_continue,
2483 Handle<JSObject>::cast(exec_state),
2484 Handle<JSObject>::cast(event_data));
2485 InvokeMessageHandler(message);
2486 }
2487
2488 // If auto continue don't make the event cause a break, but process messages
2489 // in the queue if any. For script collected events don't even process
2490 // messages in the queue as the execution state might not be what is expected
2491 // by the client.
2492 if ((auto_continue && !HasCommands()) || event == v8::ScriptCollected) {
2493 return;
2494 }
2495
Steve Blocka7e24c12009-10-30 11:49:00 +00002496 v8::TryCatch try_catch;
Steve Block3ce2e202009-11-05 08:53:23 +00002497
2498 // DebugCommandProcessor goes here.
2499 v8::Local<v8::Object> cmd_processor;
2500 {
2501 v8::Local<v8::Object> api_exec_state =
2502 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state));
2503 v8::Local<v8::String> fun_name =
2504 v8::String::New("debugCommandProcessor");
2505 v8::Local<v8::Function> fun =
2506 v8::Function::Cast(*api_exec_state->Get(fun_name));
2507
2508 v8::Handle<v8::Boolean> running =
2509 auto_continue ? v8::True() : v8::False();
2510 static const int kArgc = 1;
2511 v8::Handle<Value> argv[kArgc] = { running };
2512 cmd_processor = v8::Object::Cast(*fun->Call(api_exec_state, kArgc, argv));
2513 if (try_catch.HasCaught()) {
2514 PrintLn(try_catch.Exception());
2515 return;
2516 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002517 }
2518
Steve Block3ce2e202009-11-05 08:53:23 +00002519 bool running = auto_continue;
2520
Steve Blocka7e24c12009-10-30 11:49:00 +00002521 // Process requests from the debugger.
2522 while (true) {
2523 // Wait for new command in the queue.
2524 if (Debugger::host_dispatch_handler_) {
2525 // In case there is a host dispatch - do periodic dispatches.
2526 if (!command_received_->Wait(host_dispatch_micros_)) {
2527 // Timout expired, do the dispatch.
2528 Debugger::host_dispatch_handler_();
2529 continue;
2530 }
2531 } else {
2532 // In case there is no host dispatch - just wait.
2533 command_received_->Wait();
2534 }
2535
2536 // Get the command from the queue.
2537 CommandMessage command = command_queue_.Get();
Steve Block44f0eee2011-05-26 01:26:41 +01002538 LOGGER->DebugTag("Got request from command queue, in interactive loop.");
Steve Blocka7e24c12009-10-30 11:49:00 +00002539 if (!Debugger::IsDebuggerActive()) {
2540 // Delete command text and user data.
2541 command.Dispose();
2542 return;
2543 }
2544
2545 // Invoke JavaScript to process the debug request.
2546 v8::Local<v8::String> fun_name;
2547 v8::Local<v8::Function> fun;
2548 v8::Local<v8::Value> request;
2549 v8::TryCatch try_catch;
2550 fun_name = v8::String::New("processDebugRequest");
2551 fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
2552
2553 request = v8::String::New(command.text().start(),
2554 command.text().length());
2555 static const int kArgc = 1;
2556 v8::Handle<Value> argv[kArgc] = { request };
2557 v8::Local<v8::Value> response_val = fun->Call(cmd_processor, kArgc, argv);
2558
2559 // Get the response.
2560 v8::Local<v8::String> response;
Steve Blocka7e24c12009-10-30 11:49:00 +00002561 if (!try_catch.HasCaught()) {
2562 // Get response string.
2563 if (!response_val->IsUndefined()) {
2564 response = v8::String::Cast(*response_val);
2565 } else {
2566 response = v8::String::New("");
2567 }
2568
2569 // Log the JSON request/response.
2570 if (FLAG_trace_debug_json) {
2571 PrintLn(request);
2572 PrintLn(response);
2573 }
2574
2575 // Get the running state.
2576 fun_name = v8::String::New("isRunning");
2577 fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
2578 static const int kArgc = 1;
2579 v8::Handle<Value> argv[kArgc] = { response };
2580 v8::Local<v8::Value> running_val = fun->Call(cmd_processor, kArgc, argv);
2581 if (!try_catch.HasCaught()) {
2582 running = running_val->ToBoolean()->Value();
2583 }
2584 } else {
2585 // In case of failure the result text is the exception text.
2586 response = try_catch.Exception()->ToString();
2587 }
2588
2589 // Return the result.
2590 MessageImpl message = MessageImpl::NewResponse(
2591 event,
2592 running,
2593 Handle<JSObject>::cast(exec_state),
2594 Handle<JSObject>::cast(event_data),
2595 Handle<String>(Utils::OpenHandle(*response)),
2596 command.client_data());
2597 InvokeMessageHandler(message);
2598 command.Dispose();
2599
2600 // Return from debug event processing if either the VM is put into the
2601 // runnning state (through a continue command) or auto continue is active
2602 // and there are no more commands queued.
Steve Block3ce2e202009-11-05 08:53:23 +00002603 if (running && !HasCommands()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002604 return;
2605 }
2606 }
2607}
2608
2609
2610void Debugger::SetEventListener(Handle<Object> callback,
2611 Handle<Object> data) {
Steve Block44f0eee2011-05-26 01:26:41 +01002612 ASSERT(Isolate::Current() == isolate_);
2613 HandleScope scope(isolate_);
2614 GlobalHandles* global_handles = isolate_->global_handles();
Steve Blocka7e24c12009-10-30 11:49:00 +00002615
2616 // Clear the global handles for the event listener and the event listener data
2617 // object.
2618 if (!event_listener_.is_null()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002619 global_handles->Destroy(
Steve Blocka7e24c12009-10-30 11:49:00 +00002620 reinterpret_cast<Object**>(event_listener_.location()));
2621 event_listener_ = Handle<Object>();
2622 }
2623 if (!event_listener_data_.is_null()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002624 global_handles->Destroy(
Steve Blocka7e24c12009-10-30 11:49:00 +00002625 reinterpret_cast<Object**>(event_listener_data_.location()));
2626 event_listener_data_ = Handle<Object>();
2627 }
2628
2629 // If there is a new debug event listener register it together with its data
2630 // object.
2631 if (!callback->IsUndefined() && !callback->IsNull()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002632 event_listener_ = Handle<Object>::cast(
2633 global_handles->Create(*callback));
Steve Blocka7e24c12009-10-30 11:49:00 +00002634 if (data.is_null()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002635 data = isolate_->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002636 }
Steve Block44f0eee2011-05-26 01:26:41 +01002637 event_listener_data_ = Handle<Object>::cast(
2638 global_handles->Create(*data));
Steve Blocka7e24c12009-10-30 11:49:00 +00002639 }
2640
2641 ListenersChanged();
2642}
2643
2644
2645void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) {
Steve Block44f0eee2011-05-26 01:26:41 +01002646 ASSERT(Isolate::Current() == isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002647 ScopedLock with(debugger_access_);
2648
2649 message_handler_ = handler;
2650 ListenersChanged();
2651 if (handler == NULL) {
2652 // Send an empty command to the debugger if in a break to make JavaScript
2653 // run again if the debugger is closed.
Steve Block44f0eee2011-05-26 01:26:41 +01002654 if (isolate_->debug()->InDebugger()) {
Steve Blocka7e24c12009-10-30 11:49:00 +00002655 ProcessCommand(Vector<const uint16_t>::empty());
2656 }
2657 }
2658}
2659
2660
2661void Debugger::ListenersChanged() {
Steve Block44f0eee2011-05-26 01:26:41 +01002662 ASSERT(Isolate::Current() == isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002663 if (IsDebuggerActive()) {
2664 // Disable the compilation cache when the debugger is active.
Steve Block44f0eee2011-05-26 01:26:41 +01002665 isolate_->compilation_cache()->Disable();
Leon Clarkee46be812010-01-19 14:06:41 +00002666 debugger_unload_pending_ = false;
Steve Blocka7e24c12009-10-30 11:49:00 +00002667 } else {
Steve Block44f0eee2011-05-26 01:26:41 +01002668 isolate_->compilation_cache()->Enable();
Steve Blocka7e24c12009-10-30 11:49:00 +00002669 // Unload the debugger if event listener and message handler cleared.
Leon Clarkee46be812010-01-19 14:06:41 +00002670 // Schedule this for later, because we may be in non-V8 thread.
2671 debugger_unload_pending_ = true;
Steve Blocka7e24c12009-10-30 11:49:00 +00002672 }
2673}
2674
2675
2676void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
2677 int period) {
Steve Block44f0eee2011-05-26 01:26:41 +01002678 ASSERT(Isolate::Current() == isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002679 host_dispatch_handler_ = handler;
2680 host_dispatch_micros_ = period * 1000;
2681}
2682
2683
Steve Blockd0582a62009-12-15 09:54:21 +00002684void Debugger::SetDebugMessageDispatchHandler(
Leon Clarkee46be812010-01-19 14:06:41 +00002685 v8::Debug::DebugMessageDispatchHandler handler, bool provide_locker) {
Steve Block44f0eee2011-05-26 01:26:41 +01002686 ASSERT(Isolate::Current() == isolate_);
Leon Clarkee46be812010-01-19 14:06:41 +00002687 ScopedLock with(dispatch_handler_access_);
Steve Blockd0582a62009-12-15 09:54:21 +00002688 debug_message_dispatch_handler_ = handler;
Leon Clarkee46be812010-01-19 14:06:41 +00002689
2690 if (provide_locker && message_dispatch_helper_thread_ == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01002691 message_dispatch_helper_thread_ = new MessageDispatchHelperThread(isolate_);
Leon Clarkee46be812010-01-19 14:06:41 +00002692 message_dispatch_helper_thread_->Start();
2693 }
Steve Blockd0582a62009-12-15 09:54:21 +00002694}
2695
2696
Steve Blocka7e24c12009-10-30 11:49:00 +00002697// Calls the registered debug message handler. This callback is part of the
2698// public API.
2699void Debugger::InvokeMessageHandler(MessageImpl message) {
Steve Block44f0eee2011-05-26 01:26:41 +01002700 ASSERT(Isolate::Current() == isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002701 ScopedLock with(debugger_access_);
2702
2703 if (message_handler_ != NULL) {
2704 message_handler_(message);
2705 }
2706}
2707
2708
2709// Puts a command coming from the public API on the queue. Creates
2710// a copy of the command string managed by the debugger. Up to this
2711// point, the command data was managed by the API client. Called
2712// by the API client thread.
2713void Debugger::ProcessCommand(Vector<const uint16_t> command,
2714 v8::Debug::ClientData* client_data) {
Steve Block44f0eee2011-05-26 01:26:41 +01002715 ASSERT(Isolate::Current() == isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002716 // Need to cast away const.
2717 CommandMessage message = CommandMessage::New(
2718 Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
2719 command.length()),
2720 client_data);
Steve Block44f0eee2011-05-26 01:26:41 +01002721 LOGGER->DebugTag("Put command on command_queue.");
Steve Blocka7e24c12009-10-30 11:49:00 +00002722 command_queue_.Put(message);
2723 command_received_->Signal();
2724
2725 // Set the debug command break flag to have the command processed.
Steve Block44f0eee2011-05-26 01:26:41 +01002726 if (!isolate_->debug()->InDebugger()) {
2727 isolate_->stack_guard()->DebugCommand();
Steve Blocka7e24c12009-10-30 11:49:00 +00002728 }
Steve Blockd0582a62009-12-15 09:54:21 +00002729
Leon Clarkee46be812010-01-19 14:06:41 +00002730 MessageDispatchHelperThread* dispatch_thread;
2731 {
2732 ScopedLock with(dispatch_handler_access_);
2733 dispatch_thread = message_dispatch_helper_thread_;
2734 }
2735
2736 if (dispatch_thread == NULL) {
2737 CallMessageDispatchHandler();
2738 } else {
2739 dispatch_thread->Schedule();
Steve Blockd0582a62009-12-15 09:54:21 +00002740 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002741}
2742
2743
2744bool Debugger::HasCommands() {
Steve Block44f0eee2011-05-26 01:26:41 +01002745 ASSERT(Isolate::Current() == isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002746 return !command_queue_.IsEmpty();
2747}
2748
2749
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002750void Debugger::EnqueueDebugCommand(v8::Debug::ClientData* client_data) {
Steve Block44f0eee2011-05-26 01:26:41 +01002751 ASSERT(Isolate::Current() == isolate_);
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002752 CommandMessage message = CommandMessage::New(Vector<uint16_t>(), client_data);
2753 event_command_queue_.Put(message);
2754
2755 // Set the debug command break flag to have the command processed.
Steve Block44f0eee2011-05-26 01:26:41 +01002756 if (!isolate_->debug()->InDebugger()) {
2757 isolate_->stack_guard()->DebugCommand();
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002758 }
2759}
2760
2761
Steve Blocka7e24c12009-10-30 11:49:00 +00002762bool Debugger::IsDebuggerActive() {
Steve Block44f0eee2011-05-26 01:26:41 +01002763 ASSERT(Isolate::Current() == isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002764 ScopedLock with(debugger_access_);
2765
2766 return message_handler_ != NULL || !event_listener_.is_null();
2767}
2768
2769
2770Handle<Object> Debugger::Call(Handle<JSFunction> fun,
2771 Handle<Object> data,
2772 bool* pending_exception) {
Steve Block44f0eee2011-05-26 01:26:41 +01002773 ASSERT(Isolate::Current() == isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002774 // When calling functions in the debugger prevent it from beeing unloaded.
2775 Debugger::never_unload_debugger_ = true;
2776
2777 // Enter the debugger.
2778 EnterDebugger debugger;
Steve Block6ded16b2010-05-10 14:33:55 +01002779 if (debugger.FailedToEnter()) {
Steve Block44f0eee2011-05-26 01:26:41 +01002780 return isolate_->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002781 }
2782
2783 // Create the execution state.
2784 bool caught_exception = false;
2785 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2786 if (caught_exception) {
Steve Block44f0eee2011-05-26 01:26:41 +01002787 return isolate_->factory()->undefined_value();
Steve Blocka7e24c12009-10-30 11:49:00 +00002788 }
2789
2790 static const int kArgc = 2;
2791 Object** argv[kArgc] = { exec_state.location(), data.location() };
Steve Block6ded16b2010-05-10 14:33:55 +01002792 Handle<Object> result = Execution::Call(
2793 fun,
Steve Block44f0eee2011-05-26 01:26:41 +01002794 Handle<Object>(isolate_->debug()->debug_context_->global_proxy()),
Steve Block6ded16b2010-05-10 14:33:55 +01002795 kArgc,
2796 argv,
2797 pending_exception);
Steve Blocka7e24c12009-10-30 11:49:00 +00002798 return result;
2799}
2800
2801
Leon Clarkee46be812010-01-19 14:06:41 +00002802static void StubMessageHandler2(const v8::Debug::Message& message) {
2803 // Simply ignore message.
2804}
2805
2806
2807bool Debugger::StartAgent(const char* name, int port,
2808 bool wait_for_connection) {
Steve Block44f0eee2011-05-26 01:26:41 +01002809 ASSERT(Isolate::Current() == isolate_);
Leon Clarkee46be812010-01-19 14:06:41 +00002810 if (wait_for_connection) {
2811 // Suspend V8 if it is already running or set V8 to suspend whenever
2812 // it starts.
2813 // Provide stub message handler; V8 auto-continues each suspend
2814 // when there is no message handler; we doesn't need it.
2815 // Once become suspended, V8 will stay so indefinitely long, until remote
2816 // debugger connects and issues "continue" command.
2817 Debugger::message_handler_ = StubMessageHandler2;
2818 v8::Debug::DebugBreak();
2819 }
2820
Steve Blocka7e24c12009-10-30 11:49:00 +00002821 if (Socket::Setup()) {
Ben Murdoch086aeea2011-05-13 15:57:08 +01002822 if (agent_ == NULL) {
Steve Block44f0eee2011-05-26 01:26:41 +01002823 agent_ = new DebuggerAgent(isolate_, name, port);
Ben Murdoch086aeea2011-05-13 15:57:08 +01002824 agent_->Start();
2825 }
Steve Blocka7e24c12009-10-30 11:49:00 +00002826 return true;
2827 }
2828
2829 return false;
2830}
2831
2832
2833void Debugger::StopAgent() {
Steve Block44f0eee2011-05-26 01:26:41 +01002834 ASSERT(Isolate::Current() == isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002835 if (agent_ != NULL) {
2836 agent_->Shutdown();
2837 agent_->Join();
2838 delete agent_;
2839 agent_ = NULL;
2840 }
2841}
2842
2843
2844void Debugger::WaitForAgent() {
Steve Block44f0eee2011-05-26 01:26:41 +01002845 ASSERT(Isolate::Current() == isolate_);
Steve Blocka7e24c12009-10-30 11:49:00 +00002846 if (agent_ != NULL)
2847 agent_->WaitUntilListening();
2848}
2849
Leon Clarkee46be812010-01-19 14:06:41 +00002850
2851void Debugger::CallMessageDispatchHandler() {
Steve Block44f0eee2011-05-26 01:26:41 +01002852 ASSERT(Isolate::Current() == isolate_);
Leon Clarkee46be812010-01-19 14:06:41 +00002853 v8::Debug::DebugMessageDispatchHandler handler;
2854 {
2855 ScopedLock with(dispatch_handler_access_);
2856 handler = Debugger::debug_message_dispatch_handler_;
2857 }
2858 if (handler != NULL) {
2859 handler();
2860 }
2861}
2862
2863
Steve Blocka7e24c12009-10-30 11:49:00 +00002864MessageImpl MessageImpl::NewEvent(DebugEvent event,
2865 bool running,
2866 Handle<JSObject> exec_state,
2867 Handle<JSObject> event_data) {
2868 MessageImpl message(true, event, running,
2869 exec_state, event_data, Handle<String>(), NULL);
2870 return message;
2871}
2872
2873
2874MessageImpl MessageImpl::NewResponse(DebugEvent event,
2875 bool running,
2876 Handle<JSObject> exec_state,
2877 Handle<JSObject> event_data,
2878 Handle<String> response_json,
2879 v8::Debug::ClientData* client_data) {
2880 MessageImpl message(false, event, running,
2881 exec_state, event_data, response_json, client_data);
2882 return message;
2883}
2884
2885
2886MessageImpl::MessageImpl(bool is_event,
2887 DebugEvent event,
2888 bool running,
2889 Handle<JSObject> exec_state,
2890 Handle<JSObject> event_data,
2891 Handle<String> response_json,
2892 v8::Debug::ClientData* client_data)
2893 : is_event_(is_event),
2894 event_(event),
2895 running_(running),
2896 exec_state_(exec_state),
2897 event_data_(event_data),
2898 response_json_(response_json),
2899 client_data_(client_data) {}
2900
2901
2902bool MessageImpl::IsEvent() const {
2903 return is_event_;
2904}
2905
2906
2907bool MessageImpl::IsResponse() const {
2908 return !is_event_;
2909}
2910
2911
2912DebugEvent MessageImpl::GetEvent() const {
2913 return event_;
2914}
2915
2916
2917bool MessageImpl::WillStartRunning() const {
2918 return running_;
2919}
2920
2921
2922v8::Handle<v8::Object> MessageImpl::GetExecutionState() const {
2923 return v8::Utils::ToLocal(exec_state_);
2924}
2925
2926
2927v8::Handle<v8::Object> MessageImpl::GetEventData() const {
2928 return v8::Utils::ToLocal(event_data_);
2929}
2930
2931
2932v8::Handle<v8::String> MessageImpl::GetJSON() const {
2933 v8::HandleScope scope;
2934
2935 if (IsEvent()) {
2936 // Call toJSONProtocol on the debug event object.
2937 Handle<Object> fun = GetProperty(event_data_, "toJSONProtocol");
2938 if (!fun->IsJSFunction()) {
2939 return v8::Handle<v8::String>();
2940 }
2941 bool caught_exception;
2942 Handle<Object> json = Execution::TryCall(Handle<JSFunction>::cast(fun),
2943 event_data_,
2944 0, NULL, &caught_exception);
2945 if (caught_exception || !json->IsString()) {
2946 return v8::Handle<v8::String>();
2947 }
2948 return scope.Close(v8::Utils::ToLocal(Handle<String>::cast(json)));
2949 } else {
2950 return v8::Utils::ToLocal(response_json_);
2951 }
2952}
2953
2954
2955v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
Steve Block44f0eee2011-05-26 01:26:41 +01002956 Isolate* isolate = Isolate::Current();
2957 v8::Handle<v8::Context> context = GetDebugEventContext(isolate);
2958 // Isolate::context() may be NULL when "script collected" event occures.
Leon Clarkef7060e22010-06-03 12:02:55 +01002959 ASSERT(!context.IsEmpty() || event_ == v8::ScriptCollected);
Steve Block44f0eee2011-05-26 01:26:41 +01002960 return GetDebugEventContext(isolate);
Steve Blocka7e24c12009-10-30 11:49:00 +00002961}
2962
2963
2964v8::Debug::ClientData* MessageImpl::GetClientData() const {
2965 return client_data_;
2966}
2967
2968
Leon Clarkef7060e22010-06-03 12:02:55 +01002969EventDetailsImpl::EventDetailsImpl(DebugEvent event,
2970 Handle<JSObject> exec_state,
2971 Handle<JSObject> event_data,
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002972 Handle<Object> callback_data,
2973 v8::Debug::ClientData* client_data)
Leon Clarkef7060e22010-06-03 12:02:55 +01002974 : event_(event),
2975 exec_state_(exec_state),
2976 event_data_(event_data),
Ben Murdoch3bec4d22010-07-22 14:51:16 +01002977 callback_data_(callback_data),
2978 client_data_(client_data) {}
Leon Clarkef7060e22010-06-03 12:02:55 +01002979
2980
2981DebugEvent EventDetailsImpl::GetEvent() const {
2982 return event_;
2983}
2984
2985
2986v8::Handle<v8::Object> EventDetailsImpl::GetExecutionState() const {
2987 return v8::Utils::ToLocal(exec_state_);
2988}
2989
2990
2991v8::Handle<v8::Object> EventDetailsImpl::GetEventData() const {
2992 return v8::Utils::ToLocal(event_data_);
2993}
2994
2995
2996v8::Handle<v8::Context> EventDetailsImpl::GetEventContext() const {
Steve Block44f0eee2011-05-26 01:26:41 +01002997 return GetDebugEventContext(Isolate::Current());
Leon Clarkef7060e22010-06-03 12:02:55 +01002998}
2999
3000
3001v8::Handle<v8::Value> EventDetailsImpl::GetCallbackData() const {
3002 return v8::Utils::ToLocal(callback_data_);
3003}
3004
3005
Ben Murdoch3bec4d22010-07-22 14:51:16 +01003006v8::Debug::ClientData* EventDetailsImpl::GetClientData() const {
3007 return client_data_;
3008}
3009
3010
Steve Blocka7e24c12009-10-30 11:49:00 +00003011CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()),
3012 client_data_(NULL) {
3013}
3014
3015
3016CommandMessage::CommandMessage(const Vector<uint16_t>& text,
3017 v8::Debug::ClientData* data)
3018 : text_(text),
3019 client_data_(data) {
3020}
3021
3022
3023CommandMessage::~CommandMessage() {
3024}
3025
3026
3027void CommandMessage::Dispose() {
3028 text_.Dispose();
3029 delete client_data_;
3030 client_data_ = NULL;
3031}
3032
3033
3034CommandMessage CommandMessage::New(const Vector<uint16_t>& command,
3035 v8::Debug::ClientData* data) {
3036 return CommandMessage(command.Clone(), data);
3037}
3038
3039
3040CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0),
3041 size_(size) {
3042 messages_ = NewArray<CommandMessage>(size);
3043}
3044
3045
3046CommandMessageQueue::~CommandMessageQueue() {
3047 while (!IsEmpty()) {
3048 CommandMessage m = Get();
3049 m.Dispose();
3050 }
3051 DeleteArray(messages_);
3052}
3053
3054
3055CommandMessage CommandMessageQueue::Get() {
3056 ASSERT(!IsEmpty());
3057 int result = start_;
3058 start_ = (start_ + 1) % size_;
3059 return messages_[result];
3060}
3061
3062
3063void CommandMessageQueue::Put(const CommandMessage& message) {
3064 if ((end_ + 1) % size_ == start_) {
3065 Expand();
3066 }
3067 messages_[end_] = message;
3068 end_ = (end_ + 1) % size_;
3069}
3070
3071
3072void CommandMessageQueue::Expand() {
3073 CommandMessageQueue new_queue(size_ * 2);
3074 while (!IsEmpty()) {
3075 new_queue.Put(Get());
3076 }
3077 CommandMessage* array_to_free = messages_;
3078 *this = new_queue;
3079 new_queue.messages_ = array_to_free;
3080 // Make the new_queue empty so that it doesn't call Dispose on any messages.
3081 new_queue.start_ = new_queue.end_;
3082 // Automatic destructor called on new_queue, freeing array_to_free.
3083}
3084
3085
3086LockingCommandMessageQueue::LockingCommandMessageQueue(int size)
3087 : queue_(size) {
3088 lock_ = OS::CreateMutex();
3089}
3090
3091
3092LockingCommandMessageQueue::~LockingCommandMessageQueue() {
3093 delete lock_;
3094}
3095
3096
3097bool LockingCommandMessageQueue::IsEmpty() const {
3098 ScopedLock sl(lock_);
3099 return queue_.IsEmpty();
3100}
3101
3102
3103CommandMessage LockingCommandMessageQueue::Get() {
3104 ScopedLock sl(lock_);
3105 CommandMessage result = queue_.Get();
Steve Block44f0eee2011-05-26 01:26:41 +01003106 LOGGER->DebugEvent("Get", result.text());
Steve Blocka7e24c12009-10-30 11:49:00 +00003107 return result;
3108}
3109
3110
3111void LockingCommandMessageQueue::Put(const CommandMessage& message) {
3112 ScopedLock sl(lock_);
3113 queue_.Put(message);
Steve Block44f0eee2011-05-26 01:26:41 +01003114 LOGGER->DebugEvent("Put", message.text());
Steve Blocka7e24c12009-10-30 11:49:00 +00003115}
3116
3117
3118void LockingCommandMessageQueue::Clear() {
3119 ScopedLock sl(lock_);
3120 queue_.Clear();
3121}
3122
Leon Clarkee46be812010-01-19 14:06:41 +00003123
Steve Block44f0eee2011-05-26 01:26:41 +01003124MessageDispatchHelperThread::MessageDispatchHelperThread(Isolate* isolate)
3125 : Thread(isolate, "v8:MsgDispHelpr"),
Steve Block9fac8402011-05-12 15:51:54 +01003126 sem_(OS::CreateSemaphore(0)), mutex_(OS::CreateMutex()),
Leon Clarkee46be812010-01-19 14:06:41 +00003127 already_signalled_(false) {
3128}
3129
3130
3131MessageDispatchHelperThread::~MessageDispatchHelperThread() {
3132 delete mutex_;
3133 delete sem_;
3134}
3135
3136
3137void MessageDispatchHelperThread::Schedule() {
3138 {
3139 ScopedLock lock(mutex_);
3140 if (already_signalled_) {
3141 return;
3142 }
3143 already_signalled_ = true;
3144 }
3145 sem_->Signal();
3146}
3147
3148
3149void MessageDispatchHelperThread::Run() {
3150 while (true) {
3151 sem_->Wait();
3152 {
3153 ScopedLock lock(mutex_);
3154 already_signalled_ = false;
3155 }
3156 {
3157 Locker locker;
Steve Block44f0eee2011-05-26 01:26:41 +01003158 Isolate::Current()->debugger()->CallMessageDispatchHandler();
Leon Clarkee46be812010-01-19 14:06:41 +00003159 }
3160 }
3161}
3162
Steve Blocka7e24c12009-10-30 11:49:00 +00003163#endif // ENABLE_DEBUGGER_SUPPORT
3164
3165} } // namespace v8::internal