blob: c48e514ab8a0677b171379a79491e2f35e84c8de [file] [log] [blame]
danno@chromium.org40cb8782011-05-25 07:58:50 +00001// Copyright 2011 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
31#include "arguments.h"
32#include "bootstrapper.h"
33#include "code-stubs.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000034#include "codegen.h"
kasperl@chromium.org71affb52009-05-26 05:44:31 +000035#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000036#include "compiler.h"
37#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000038#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000039#include "execution.h"
40#include "global-handles.h"
ager@chromium.org65dad4b2009-04-23 08:48:43 +000041#include "ic.h"
42#include "ic-inl.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000043#include "messages.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000044#include "natives.h"
45#include "stub-cache.h"
kasper.lund7276f142008-07-30 08:49:36 +000046#include "log.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000047
ager@chromium.org5ec48922009-05-05 07:25:34 +000048#include "../include/v8-debug.h"
49
kasperl@chromium.org71affb52009-05-26 05:44:31 +000050namespace v8 {
51namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052
ager@chromium.org65dad4b2009-04-23 08:48:43 +000053#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000054
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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000074static void PrintLn(v8::Local<v8::Value> value) {
75 v8::Local<v8::String> s = value->ToString();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000076 ScopedVector<char> data(s->Length() + 1);
77 if (data.start() == NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000078 V8::FatalProcessOutOfMemory("PrintLn");
79 return;
80 }
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000081 s->WriteAscii(data.start());
82 PrintF("%s\n", data.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000083}
84
85
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000086static Handle<Code> ComputeCallDebugBreak(int argc, Code::Kind kind) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000087 Isolate* isolate = Isolate::Current();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000088 CALL_HEAP_FUNCTION(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000089 isolate,
90 isolate->stub_cache()->ComputeCallDebugBreak(argc, kind),
91 Code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000092}
93
94
danno@chromium.org40cb8782011-05-25 07:58:50 +000095static Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000096 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>();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000109 Handle<Context> global_context(context->global_context());
110 return v8::Utils::ToLocal(global_context);
111}
112
113
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000114BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info,
115 BreakLocatorType type) {
116 debug_info_ = debug_info;
117 type_ = type;
118 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
ager@chromium.org236ad962008-09-25 09:45:57 +0000144 // 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())) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000148 statement_position_ = static_cast<int>(
149 rinfo()->data() - debug_info_->shared()->start_position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000150 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000151 // Always update the position as we don't want that to be before the
152 // statement position.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000153 position_ = static_cast<int>(
154 rinfo()->data() - debug_info_->shared()->start_position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000155 ASSERT(position_ >= 0);
156 ASSERT(statement_position_ >= 0);
157 }
158
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000159 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.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000167 Address target = original_rinfo()->target_address();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000168 Code* code = Code::GetCodeFromTargetAddress(target);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000169 if ((code->is_inline_cache_stub() &&
danno@chromium.org40cb8782011-05-25 07:58:50 +0000170 !code->is_binary_op_stub() &&
171 !code->is_unary_op_stub() &&
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000172 !code->is_compare_ic_stub()) ||
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000173 RelocInfo::IsConstructCall(rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000174 break_point_++;
175 return;
176 }
177 if (code->kind() == Code::STUB) {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000178 if (IsDebuggerStatement()) {
179 break_point_++;
180 return;
181 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000182 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.
ager@chromium.org236ad962008-09-25 09:45:57 +0000198 if (RelocInfo::IsJSReturn(rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000199 // Set the positions to the end of the function.
200 if (debug_info_->shared()->HasSourceCode()) {
201 position_ = debug_info_->shared()->end_position() -
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000202 debug_info_->shared()->start_position() - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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();
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000231 distance = static_cast<int>(pc - this->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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 }
ager@chromium.orga1645e22009-09-09 19:27:10 +0000294 ASSERT(IsDebugBreak() || IsDebuggerStatement());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000295 // 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() {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000314 // Debugger statement always calls debugger. No need to modify it.
315 if (IsDebuggerStatement()) {
316 return;
317 }
318
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000319 // 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() {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000331 // Debugger statement always calls debugger. No need to modify it.
332 if (IsDebuggerStatement()) {
333 return;
334 }
335
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000336 // 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() {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000349 // Debugger statement always calls debugger. No need to modify it.
350 if (IsDebuggerStatement()) {
351 return;
352 }
353
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354 // If there is already a break point here just return. This might happen if
v8.team.kasperl727e9952008-09-02 14:56:44 +0000355 // the same code is flooded with break points twice. Flooding the same
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000356 // 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
ager@chromium.org236ad962008-09-25 09:45:57 +0000362 if (RelocInfo::IsJSReturn(rmode())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000363 // Patch the frame exit code with a break point.
364 SetDebugBreakAtReturn();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000365 } else if (IsDebugBreakSlot()) {
366 // Patch the code in the break slot.
367 SetDebugBreakAtSlot();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000368 } else {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000369 // Patch the IC call.
370 SetDebugBreakAtIC();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000371 }
372 ASSERT(IsDebugBreak());
373}
374
375
376void BreakLocationIterator::ClearDebugBreak() {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000377 // Debugger statement always calls debugger. No need to modify it.
378 if (IsDebuggerStatement()) {
379 return;
380 }
381
ager@chromium.org236ad962008-09-25 09:45:57 +0000382 if (RelocInfo::IsJSReturn(rmode())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000383 // Restore the frame exit code.
384 ClearDebugBreakAtReturn();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000385 } else if (IsDebugBreakSlot()) {
386 // Restore the code in the break slot.
387 ClearDebugBreakAtSlot();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000388 } else {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000389 // Patch the IC call.
390 ClearDebugBreakAtIC();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000391 }
392 ASSERT(!IsDebugBreak());
393}
394
395
396void BreakLocationIterator::PrepareStepIn() {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000397 HandleScope scope;
398
ager@chromium.orga1645e22009-09-09 19:27:10 +0000399 // Step in can only be prepared if currently positioned on an IC call,
400 // construct call or CallFunction stub call.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401 Address target = rinfo()->target_address();
ager@chromium.orga1645e22009-09-09 19:27:10 +0000402 Handle<Code> code(Code::GetCodeFromTargetAddress(target));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000403 if (code->is_call_stub() || code->is_keyed_call_stub()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000409 Handle<Code> stub = ComputeCallDebugPrepareStepIn(code->arguments_count(),
410 code->kind());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000411 if (IsDebugBreak()) {
412 original_rinfo()->set_target_address(stub->entry());
413 } else {
414 rinfo()->set_target_address(stub->entry());
415 }
416 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000417#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
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000430 // 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.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000434 // 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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440 }
441}
442
443
444// Check whether the break point is at a position which will exit the function.
445bool BreakLocationIterator::IsExit() const {
ager@chromium.org236ad962008-09-25 09:45:57 +0000446 return (RelocInfo::IsJSReturn(rmode()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000447}
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() {
ager@chromium.org236ad962008-09-25 09:45:57 +0000457 if (RelocInfo::IsJSReturn(rmode())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000458 return IsDebugBreakAtReturn();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000459 } else if (IsDebugBreakSlot()) {
460 return IsDebugBreakAtSlot();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000461 } else {
462 return Debug::IsDebugBreak(rinfo()->target_address());
463 }
464}
465
466
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000467void 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());
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000481 }
482}
483
484
485void BreakLocationIterator::ClearDebugBreakAtIC() {
486 // Patch the code to the original invoke.
487 rinfo()->set_target_address(original_rinfo()->target_address());
488}
489
490
ager@chromium.orga1645e22009-09-09 19:27:10 +0000491bool BreakLocationIterator::IsDebuggerStatement() {
ager@chromium.org5c838252010-02-19 08:53:10 +0000492 return RelocInfo::DEBUG_BREAK == rmode();
ager@chromium.orga1645e22009-09-09 19:27:10 +0000493}
494
495
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000496bool BreakLocationIterator::IsDebugBreakSlot() {
497 return RelocInfo::DEBUG_BREAK_SLOT == rmode();
498}
499
500
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000501Object* BreakLocationIterator::BreakPointObjects() {
502 return debug_info_->GetBreakPointObjects(code_position());
503}
504
505
ager@chromium.org381abbb2009-02-25 13:23:22 +0000506// 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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000517bool 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
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000535// Threading support.
536void Debug::ThreadInit() {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000537 thread_local_.break_count_ = 0;
538 thread_local_.break_id_ = 0;
539 thread_local_.break_frame_id_ = StackFrame::NO_ID;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000540 thread_local_.last_step_action_ = StepNone;
ager@chromium.org236ad962008-09-25 09:45:57 +0000541 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000542 thread_local_.step_count_ = 0;
543 thread_local_.last_fp_ = 0;
544 thread_local_.step_into_fp_ = 0;
ager@chromium.orga1645e22009-09-09 19:27:10 +0000545 thread_local_.step_out_fp_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000546 thread_local_.after_break_target_ = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000547 // TODO(isolates): frames_are_dropped_?
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000548 thread_local_.debugger_entry_ = NULL;
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000549 thread_local_.pending_interrupts_ = 0;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000550 thread_local_.restarter_frame_function_pointer_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000551}
552
553
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000576 return sizeof(ThreadLocal) + sizeof(JSCallerSavedBuffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000577}
578
579
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000580// 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
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000606void ScriptCache::Add(Handle<Script> script) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000607 GlobalHandles* global_handles = Isolate::Current()->global_handles();
kasperl@chromium.org71affb52009-05-26 05:44:31 +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_ =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000620 Handle<Script>::cast(
lrn@chromium.org7516f052011-03-30 08:52:27 +0000621 (global_handles->Create(*script)));
622 global_handles->MakeWeak(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000623 reinterpret_cast<Object**>(script_.location()),
624 this,
625 ScriptCache::HandleWeakScript);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000626 entry->value = script_.location();
627}
628
629
630Handle<FixedArray> ScriptCache::GetScripts() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000631 Handle<FixedArray> instances = FACTORY->NewFixedArray(occupancy());
kasperl@chromium.org71affb52009-05-26 05:44:31 +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() {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000645 Debugger* debugger = Isolate::Current()->debugger();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000646 for (int i = 0; i < collected_scripts_.length(); i++) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000647 debugger->OnScriptCollected(collected_scripts_[i]);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000648 }
649 collected_scripts_.Clear();
650}
651
652
653void ScriptCache::Clear() {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000654 GlobalHandles* global_handles = Isolate::Current()->global_handles();
kasperl@chromium.org71affb52009-05-26 05:44:31 +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());
lrn@chromium.org7516f052011-03-30 08:52:27 +0000660 global_handles->ClearWeakness(location);
661 global_handles->Destroy(location);
kasperl@chromium.org71affb52009-05-26 05:44:31 +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) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000689 // Get code to handle debug break on return.
690 debug_break_return_ =
lrn@chromium.org7516f052011-03-30 08:52:27 +0000691 isolate_->builtins()->builtin(Builtins::kReturn_DebugBreak);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000692 ASSERT(debug_break_return_->IsCode());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000693 // Get code to handle debug break in debug break slots.
694 debug_break_slot_ =
lrn@chromium.org7516f052011-03-30 08:52:27 +0000695 isolate_->builtins()->builtin(Builtins::kSlot_DebugBreak);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000696 ASSERT(debug_break_slot_->IsCode());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000697 }
698}
699
700
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000701void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000702 Debug* debug = Isolate::Current()->debug();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000703 DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data);
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000704 // 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();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000710 debug->RemoveDebugInfo(node->debug_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000711#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000712 node = debug->debug_info_list_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000722 GlobalHandles* global_handles = Isolate::Current()->global_handles();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000723 // Globalize the request debug info object and make it weak.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000724 debug_info_ = Handle<DebugInfo>::cast(
lrn@chromium.org7516f052011-03-30 08:52:27 +0000725 (global_handles->Create(debug_info)));
726 global_handles->MakeWeak(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000727 reinterpret_cast<Object**>(debug_info_.location()),
728 this,
729 Debug::HandleWeakDebugInfo);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000730}
731
732
733DebugInfoListNode::~DebugInfoListNode() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000734 Isolate::Current()->global_handles()->Destroy(
735 reinterpret_cast<Object**>(debug_info_.location()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000736}
737
738
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000739bool Debug::CompileDebuggerScript(int index) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000740 Isolate* isolate = Isolate::Current();
741 Factory* factory = isolate->factory();
742 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000743
kasper.lund44510672008-07-25 07:37:58 +0000744 // Bail out if the index is invalid.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000745 if (index == -1) {
746 return false;
747 }
kasper.lund44510672008-07-25 07:37:58 +0000748
749 // Find source and name for the requested script.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000750 Handle<String> source_code =
lrn@chromium.org7516f052011-03-30 08:52:27 +0000751 isolate->bootstrapper()->NativesSourceLookup(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000752 Vector<const char> name = Natives::GetScriptName(index);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000753 Handle<String> script_name = factory->NewStringFromAscii(name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000754
755 // Compile the script.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000756 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);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000762
763 // Silently ignore stack overflows during compilation.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000764 if (function_info.is_null()) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000765 ASSERT(isolate->has_pending_exception());
766 isolate->clear_pending_exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000767 return false;
768 }
769
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000770 // Execute the shared function in the debugger context.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000771 Handle<Context> context = isolate->global_context();
kasper.lund44510672008-07-25 07:37:58 +0000772 bool caught_exception = false;
773 Handle<JSFunction> function =
lrn@chromium.org7516f052011-03-30 08:52:27 +0000774 factory->NewFunctionFromSharedFunctionInfo(function_info, context);
kasper.lund44510672008-07-25 07:37:58 +0000775 Handle<Object> result =
776 Execution::TryCall(function, Handle<Object>(context->global()),
777 0, NULL, &caught_exception);
778
779 // Check for caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000780 if (caught_exception) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000781 Handle<Object> message = MessageHandler::MakeMessageObject(
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000782 "error_loading_debugger", NULL, Vector<Handle<Object> >::empty(),
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +0000783 Handle<String>(), Handle<JSArray>());
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000784 MessageHandler::ReportMessage(Isolate::Current(), NULL, message);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000785 return false;
786 }
787
kasper.lund44510672008-07-25 07:37:58 +0000788 // Mark this script as native and return successfully.
789 Handle<Script> script(Script::cast(function->shared()->script()));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000790 script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000791 return true;
792}
793
794
795bool Debug::Load() {
796 // Return if debugger is already loaded.
kasper.lund212ac232008-07-16 07:07:30 +0000797 if (IsLoaded()) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000798
lrn@chromium.org7516f052011-03-30 08:52:27 +0000799 Debugger* debugger = isolate_->debugger();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000800
kasper.lund44510672008-07-25 07:37:58 +0000801 // Bail out if we're already in the process of compiling the native
802 // JavaScript source code for the debugger.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000803 if (debugger->compiling_natives() ||
804 debugger->is_loading_debugger())
mads.s.agercbaa0602008-08-14 13:41:48 +0000805 return false;
lrn@chromium.org7516f052011-03-30 08:52:27 +0000806 debugger->set_loading_debugger(true);
kasper.lund44510672008-07-25 07:37:58 +0000807
808 // Disable breakpoints and interrupts while compiling and running the
809 // debugger scripts including the context creation code.
810 DisableBreak disable(true);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000811 PostponeInterruptsScope postpone(isolate_);
kasper.lund44510672008-07-25 07:37:58 +0000812
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000813 // Create the debugger context.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000814 HandleScope scope(isolate_);
kasper.lund44510672008-07-25 07:37:58 +0000815 Handle<Context> context =
lrn@chromium.org7516f052011-03-30 08:52:27 +0000816 isolate_->bootstrapper()->CreateEnvironment(
danno@chromium.org160a7b02011-04-18 15:51:38 +0000817 isolate_,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000818 Handle<Object>::null(),
819 v8::Handle<ObjectTemplate>(),
820 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000821
kasper.lund44510672008-07-25 07:37:58 +0000822 // Use the debugger context.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000823 SaveContext save(isolate_);
824 isolate_->set_context(*context);
kasper.lund44510672008-07-25 07:37:58 +0000825
826 // Expose the builtins object in the debugger context.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000827 Handle<String> key = isolate_->factory()->LookupAsciiSymbol("builtins");
kasper.lund44510672008-07-25 07:37:58 +0000828 Handle<GlobalObject> global = Handle<GlobalObject>(context->global());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000829 RETURN_IF_EMPTY_HANDLE_VALUE(
lrn@chromium.org7516f052011-03-30 08:52:27 +0000830 isolate_,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000831 SetProperty(global, key, Handle<Object>(global->builtins()),
832 NONE, kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000833 false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000834
835 // Compile the JavaScript for the debugger in the debugger context.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000836 debugger->set_compiling_natives(true);
kasper.lund44510672008-07-25 07:37:58 +0000837 bool caught_exception =
838 !CompileDebuggerScript(Natives::GetIndex("mirror")) ||
839 !CompileDebuggerScript(Natives::GetIndex("debug"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000840
841 if (FLAG_enable_liveedit) {
842 caught_exception = caught_exception ||
843 !CompileDebuggerScript(Natives::GetIndex("liveedit"));
844 }
845
lrn@chromium.org7516f052011-03-30 08:52:27 +0000846 debugger->set_compiling_natives(false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000847
mads.s.agercbaa0602008-08-14 13:41:48 +0000848 // Make sure we mark the debugger as not loading before we might
849 // return.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000850 debugger->set_loading_debugger(false);
mads.s.agercbaa0602008-08-14 13:41:48 +0000851
kasper.lund44510672008-07-25 07:37:58 +0000852 // Check for caught exceptions.
853 if (caught_exception) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000854
855 // Debugger loaded.
whesse@chromium.org023421e2010-12-21 12:19:12 +0000856 debug_context_ = context;
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000857
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000858 return true;
859}
860
861
862void Debug::Unload() {
863 // Return debugger is not loaded.
864 if (!IsLoaded()) {
865 return;
866 }
867
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000868 // Clear the script cache.
869 DestroyScriptCache();
870
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000871 // Clear debugger context global handle.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000872 Isolate::Current()->global_handles()->Destroy(
873 reinterpret_cast<Object**>(debug_context_.location()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000874 debug_context_ = Handle<Context>();
875}
876
877
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000878// Set the flag indicating that preemption happened during debugging.
879void Debug::PreemptionWhileInDebugger() {
880 ASSERT(InDebugger());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000881 Debug::set_interrupts_pending(PREEMPT);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000882}
883
884
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000885void Debug::Iterate(ObjectVisitor* v) {
vegorov@chromium.org26c16f82010-08-11 13:41:03 +0000886 v->VisitPointer(BitCast<Object**>(&(debug_break_return_)));
887 v->VisitPointer(BitCast<Object**>(&(debug_break_slot_)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000888}
889
890
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000891Object* Debug::Break(Arguments args) {
892 Heap* heap = isolate_->heap();
893 HandleScope scope(isolate_);
mads.s.ager31e71382008-08-13 09:32:07 +0000894 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000895
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000896 thread_local_.frame_drop_mode_ = FRAMES_UNTOUCHED;
ager@chromium.org357bf652010-04-12 11:30:10 +0000897
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000898 // Get the top-most JavaScript frame.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000899 JavaScriptFrameIterator it(isolate_);
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000900 JavaScriptFrame* frame = it.frame();
901
902 // Just continue if breaks are disabled or debugger cannot be loaded.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000903 if (disable_break() || !Load()) {
904 SetAfterBreakTarget(frame);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000905 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000906 }
907
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000908 // Enter the debugger.
909 EnterDebugger debugger;
910 if (debugger.FailedToEnter()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000911 return heap->undefined_value();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000912 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000913
kasper.lund44510672008-07-25 07:37:58 +0000914 // Postpone interrupt during breakpoint processing.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000915 PostponeInterruptsScope postpone(isolate_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000916
917 // Get the debug info (create it if it does not exist).
918 Handle<SharedFunctionInfo> shared =
919 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
920 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
921
922 // Find the break point where execution has stopped.
923 BreakLocationIterator break_location_iterator(debug_info,
924 ALL_BREAK_LOCATIONS);
925 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
926
927 // Check whether step next reached a new statement.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000928 if (!StepNextContinue(&break_location_iterator, frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000929 // Decrease steps left if performing multiple steps.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000930 if (thread_local_.step_count_ > 0) {
931 thread_local_.step_count_--;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000932 }
933 }
934
935 // If there is one or more real break points check whether any of these are
936 // triggered.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000937 Handle<Object> break_points_hit(heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000938 if (break_location_iterator.HasBreakPoint()) {
939 Handle<Object> break_point_objects =
940 Handle<Object>(break_location_iterator.BreakPointObjects());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000941 break_points_hit = CheckBreakPoints(break_point_objects);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000942 }
943
ager@chromium.orga1645e22009-09-09 19:27:10 +0000944 // If step out is active skip everything until the frame where we need to step
945 // out to is reached, unless real breakpoint is hit.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000946 if (StepOutActive() && frame->fp() != step_out_fp() &&
ager@chromium.orga1645e22009-09-09 19:27:10 +0000947 break_points_hit->IsUndefined() ) {
948 // Step count should always be 0 for StepOut.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000949 ASSERT(thread_local_.step_count_ == 0);
ager@chromium.orga1645e22009-09-09 19:27:10 +0000950 } else if (!break_points_hit->IsUndefined() ||
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000951 (thread_local_.last_step_action_ != StepNone &&
952 thread_local_.step_count_ == 0)) {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000953 // Notify debugger if a real break point is triggered or if performing
954 // single stepping with no more steps to perform. Otherwise do another step.
955
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000956 // Clear all current stepping setup.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000957 ClearStepping();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000958
959 // Notify the debug event listeners.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000960 isolate_->debugger()->OnDebugBreak(break_points_hit, false);
961 } else if (thread_local_.last_step_action_ != StepNone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000962 // Hold on to last step action as it is cleared by the call to
963 // ClearStepping.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000964 StepAction step_action = thread_local_.last_step_action_;
965 int step_count = thread_local_.step_count_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000966
967 // Clear all current stepping setup.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000968 ClearStepping();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000969
970 // Set up for the remaining steps.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000971 PrepareStep(step_action, step_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000972 }
973
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000974 if (thread_local_.frame_drop_mode_ == FRAMES_UNTOUCHED) {
975 SetAfterBreakTarget(frame);
976 } else if (thread_local_.frame_drop_mode_ ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000977 FRAME_DROPPED_IN_IC_CALL) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000978 // We must have been calling IC stub. Do not go there anymore.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000979 Code* plain_return = isolate_->builtins()->builtin(
980 Builtins::kPlainReturn_LiveEdit);
981 thread_local_.after_break_target_ = plain_return->entry();
982 } else if (thread_local_.frame_drop_mode_ ==
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000983 FRAME_DROPPED_IN_DEBUG_SLOT_CALL) {
984 // Debug break slot stub does not return normally, instead it manually
985 // cleans the stack and jumps. We should patch the jump address.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000986 Code* plain_return = isolate_->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000987 Builtins::kFrameDropper_LiveEdit);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000988 thread_local_.after_break_target_ = plain_return->entry();
989 } else if (thread_local_.frame_drop_mode_ ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000990 FRAME_DROPPED_IN_DIRECT_CALL) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000991 // Nothing to do, after_break_target is not used here.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000992 } else if (thread_local_.frame_drop_mode_ ==
993 FRAME_DROPPED_IN_RETURN_CALL) {
994 Code* plain_return = isolate_->builtins()->builtin(
995 Builtins::kFrameDropper_LiveEdit);
996 thread_local_.after_break_target_ = plain_return->entry();
ager@chromium.org357bf652010-04-12 11:30:10 +0000997 } else {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000998 UNREACHABLE();
ager@chromium.org357bf652010-04-12 11:30:10 +0000999 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001000
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001001 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001002}
1003
1004
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001005RUNTIME_FUNCTION(Object*, Debug_Break) {
1006 return isolate->debug()->Break(args);
1007}
1008
1009
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001010// Check the break point objects for whether one or more are actually
1011// triggered. This function returns a JSArray with the break point objects
1012// which is triggered.
1013Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001014 Factory* factory = isolate_->factory();
1015
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001016 // Count the number of break points hit. If there are multiple break points
1017 // they are in a FixedArray.
1018 Handle<FixedArray> break_points_hit;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001019 int break_points_hit_count = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001020 ASSERT(!break_point_objects->IsUndefined());
1021 if (break_point_objects->IsFixedArray()) {
1022 Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001023 break_points_hit = factory->NewFixedArray(array->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001024 for (int i = 0; i < array->length(); i++) {
1025 Handle<Object> o(array->get(i));
1026 if (CheckBreakPoint(o)) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001027 break_points_hit->set(break_points_hit_count++, *o);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001028 }
1029 }
1030 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001031 break_points_hit = factory->NewFixedArray(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001032 if (CheckBreakPoint(break_point_objects)) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001033 break_points_hit->set(break_points_hit_count++, *break_point_objects);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001034 }
1035 }
1036
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001037 // Return undefined if no break points were triggered.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001038 if (break_points_hit_count == 0) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001039 return factory->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001040 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001041 // Return break points hit as a JSArray.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001042 Handle<JSArray> result = factory->NewJSArrayWithElements(break_points_hit);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001043 result->set_length(Smi::FromInt(break_points_hit_count));
1044 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001045}
1046
1047
1048// Check whether a single break point object is triggered.
1049bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001050 Factory* factory = isolate_->factory();
1051 HandleScope scope(isolate_);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001052
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001053 // Ignore check if break point object is not a JSObject.
1054 if (!break_point_object->IsJSObject()) return true;
1055
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001056 // Get the function IsBreakPointTriggered (defined in debug-debugger.js).
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001057 Handle<String> is_break_point_triggered_symbol =
lrn@chromium.org7516f052011-03-30 08:52:27 +00001058 factory->LookupAsciiSymbol("IsBreakPointTriggered");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001059 Handle<JSFunction> check_break_point =
1060 Handle<JSFunction>(JSFunction::cast(
lrn@chromium.org303ada72010-10-27 09:33:13 +00001061 debug_context()->global()->GetPropertyNoExceptionThrown(
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001062 *is_break_point_triggered_symbol)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001063
1064 // Get the break id as an object.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001065 Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001066
1067 // Call HandleBreakPointx.
1068 bool caught_exception = false;
1069 const int argc = 2;
1070 Object** argv[argc] = {
1071 break_id.location(),
1072 reinterpret_cast<Object**>(break_point_object.location())
1073 };
1074 Handle<Object> result = Execution::TryCall(check_break_point,
lrn@chromium.org7516f052011-03-30 08:52:27 +00001075 isolate_->js_builtins_object(), argc, argv, &caught_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001076
1077 // If exception or non boolean result handle as not triggered
1078 if (caught_exception || !result->IsBoolean()) {
1079 return false;
1080 }
1081
1082 // Return whether the break point is triggered.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001083 ASSERT(!result.is_null());
1084 return (*result)->IsTrue();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001085}
1086
1087
1088// Check whether the function has debug information.
1089bool Debug::HasDebugInfo(Handle<SharedFunctionInfo> shared) {
1090 return !shared->debug_info()->IsUndefined();
1091}
1092
1093
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001094// Return the debug info for this function. EnsureDebugInfo must be called
1095// prior to ensure the debug info has been generated for shared.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001096Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001097 ASSERT(HasDebugInfo(shared));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098 return Handle<DebugInfo>(DebugInfo::cast(shared->debug_info()));
1099}
1100
1101
1102void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared,
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001103 Handle<Object> break_point_object,
1104 int* source_position) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001105 HandleScope scope(isolate_);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001106
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001107 if (!EnsureDebugInfo(shared)) {
1108 // Return if retrieving debug info failed.
1109 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001110 }
1111
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001112 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001113 // Source positions starts with zero.
1114 ASSERT(source_position >= 0);
1115
1116 // Find the break point and change it.
1117 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001118 it.FindBreakLocationFromPosition(*source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001119 it.SetBreakPoint(break_point_object);
1120
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001121 *source_position = it.position();
1122
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001123 // At least one active break point now.
1124 ASSERT(debug_info->GetBreakPointCount() > 0);
1125}
1126
1127
1128void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001129 HandleScope scope(isolate_);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001130
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001131 DebugInfoListNode* node = debug_info_list_;
1132 while (node != NULL) {
1133 Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(),
1134 break_point_object);
1135 if (!result->IsUndefined()) {
1136 // Get information in the break point.
1137 BreakPointInfo* break_point_info = BreakPointInfo::cast(result);
1138 Handle<DebugInfo> debug_info = node->debug_info();
1139 Handle<SharedFunctionInfo> shared(debug_info->shared());
1140 int source_position = break_point_info->statement_position()->value();
1141
1142 // Source positions starts with zero.
1143 ASSERT(source_position >= 0);
1144
1145 // Find the break point and clear it.
1146 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
1147 it.FindBreakLocationFromPosition(source_position);
1148 it.ClearBreakPoint(break_point_object);
1149
1150 // If there are no more break points left remove the debug info for this
1151 // function.
1152 if (debug_info->GetBreakPointCount() == 0) {
1153 RemoveDebugInfo(debug_info);
1154 }
1155
1156 return;
1157 }
1158 node = node->next();
1159 }
1160}
1161
1162
ager@chromium.org381abbb2009-02-25 13:23:22 +00001163void Debug::ClearAllBreakPoints() {
1164 DebugInfoListNode* node = debug_info_list_;
1165 while (node != NULL) {
1166 // Remove all debug break code.
1167 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1168 it.ClearAllDebugBreak();
1169 node = node->next();
1170 }
1171
1172 // Remove all debug info.
1173 while (debug_info_list_ != NULL) {
1174 RemoveDebugInfo(debug_info_list_->debug_info());
1175 }
1176}
1177
1178
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001179void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001180 // Make sure the function has setup the debug info.
1181 if (!EnsureDebugInfo(shared)) {
1182 // Return if we failed to retrieve the debug info.
1183 return;
1184 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185
1186 // Flood the function with break points.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001187 BreakLocationIterator it(GetDebugInfo(shared), ALL_BREAK_LOCATIONS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001188 while (!it.Done()) {
1189 it.SetOneShot();
1190 it.Next();
1191 }
1192}
1193
1194
1195void Debug::FloodHandlerWithOneShot() {
ager@chromium.org8bb60582008-12-11 12:02:20 +00001196 // Iterate through the JavaScript stack looking for handlers.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001197 StackFrame::Id id = break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00001198 if (id == StackFrame::NO_ID) {
1199 // If there is no JavaScript stack don't do anything.
1200 return;
1201 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001202 for (JavaScriptFrameIterator it(isolate_, id); !it.done(); it.Advance()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001203 JavaScriptFrame* frame = it.frame();
1204 if (frame->HasHandler()) {
1205 Handle<SharedFunctionInfo> shared =
1206 Handle<SharedFunctionInfo>(
1207 JSFunction::cast(frame->function())->shared());
1208 // Flood the function with the catch block with break points
1209 FloodWithOneShot(shared);
1210 return;
1211 }
1212 }
1213}
1214
1215
1216void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
1217 if (type == BreakUncaughtException) {
1218 break_on_uncaught_exception_ = enable;
1219 } else {
1220 break_on_exception_ = enable;
1221 }
1222}
1223
1224
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001225bool Debug::IsBreakOnException(ExceptionBreakType type) {
1226 if (type == BreakUncaughtException) {
1227 return break_on_uncaught_exception_;
1228 } else {
1229 return break_on_exception_;
1230 }
1231}
1232
1233
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001234void Debug::PrepareStep(StepAction step_action, int step_count) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001235 HandleScope scope(isolate_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001236 ASSERT(Debug::InDebugger());
1237
1238 // Remember this step action and count.
1239 thread_local_.last_step_action_ = step_action;
ager@chromium.orga1645e22009-09-09 19:27:10 +00001240 if (step_action == StepOut) {
1241 // For step out target frame will be found on the stack so there is no need
1242 // to set step counter for it. It's expected to always be 0 for StepOut.
1243 thread_local_.step_count_ = 0;
1244 } else {
1245 thread_local_.step_count_ = step_count;
1246 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247
1248 // Get the frame where the execution has stopped and skip the debug frame if
1249 // any. The debug frame will only be present if execution was stopped due to
1250 // hitting a break point. In other situations (e.g. unhandled exception) the
1251 // debug frame is not present.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001252 StackFrame::Id id = break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00001253 if (id == StackFrame::NO_ID) {
1254 // If there is no JavaScript stack don't do anything.
1255 return;
1256 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001257 JavaScriptFrameIterator frames_it(isolate_, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258 JavaScriptFrame* frame = frames_it.frame();
1259
1260 // First of all ensure there is one-shot break points in the top handler
1261 // if any.
1262 FloodHandlerWithOneShot();
1263
1264 // If the function on the top frame is unresolved perform step out. This will
1265 // be the case when calling unknown functions and having the debugger stopped
1266 // in an unhandled exception.
1267 if (!frame->function()->IsJSFunction()) {
1268 // Step out: Find the calling JavaScript frame and flood it with
1269 // breakpoints.
1270 frames_it.Advance();
1271 // Fill the function to return to with one-shot break points.
1272 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
1273 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1274 return;
1275 }
1276
1277 // Get the debug info (create it if it does not exist).
1278 Handle<SharedFunctionInfo> shared =
1279 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001280 if (!EnsureDebugInfo(shared)) {
1281 // Return if ensuring debug info failed.
1282 return;
1283 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001284 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1285
1286 // Find the break location where execution has stopped.
1287 BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS);
1288 it.FindBreakLocationFromAddress(frame->pc());
1289
1290 // Compute whether or not the target is a call target.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001291 bool is_load_or_store = false;
1292 bool is_inline_cache_stub = false;
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001293 bool is_at_restarted_function = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +00001294 Handle<Code> call_function_stub;
ager@chromium.orga1645e22009-09-09 19:27:10 +00001295
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001296 if (thread_local_.restarter_frame_function_pointer_ == NULL) {
1297 if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) {
1298 bool is_call_target = false;
1299 Address target = it.rinfo()->target_address();
1300 Code* code = Code::GetCodeFromTargetAddress(target);
1301 if (code->is_call_stub() || code->is_keyed_call_stub()) {
1302 is_call_target = true;
1303 }
1304 if (code->is_inline_cache_stub()) {
1305 is_inline_cache_stub = true;
1306 is_load_or_store = !is_call_target;
1307 }
1308
1309 // Check if target code is CallFunction stub.
1310 Code* maybe_call_function_stub = code;
1311 // If there is a breakpoint at this line look at the original code to
1312 // check if it is a CallFunction stub.
1313 if (it.IsDebugBreak()) {
1314 Address original_target = it.original_rinfo()->target_address();
1315 maybe_call_function_stub =
1316 Code::GetCodeFromTargetAddress(original_target);
1317 }
1318 if (maybe_call_function_stub->kind() == Code::STUB &&
1319 maybe_call_function_stub->major_key() == CodeStub::CallFunction) {
1320 // Save reference to the code as we may need it to find out arguments
1321 // count for 'step in' later.
1322 call_function_stub = Handle<Code>(maybe_call_function_stub);
1323 }
ager@chromium.orga1645e22009-09-09 19:27:10 +00001324 }
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001325 } else {
1326 is_at_restarted_function = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001327 }
1328
v8.team.kasperl727e9952008-09-02 14:56:44 +00001329 // If this is the last break code target step out is the only possibility.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001330 if (it.IsExit() || step_action == StepOut) {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001331 if (step_action == StepOut) {
1332 // Skip step_count frames starting with the current one.
1333 while (step_count-- > 0 && !frames_it.done()) {
1334 frames_it.Advance();
1335 }
1336 } else {
1337 ASSERT(it.IsExit());
1338 frames_it.Advance();
1339 }
1340 // Skip builtin functions on the stack.
1341 while (!frames_it.done() &&
1342 JSFunction::cast(frames_it.frame()->function())->IsBuiltin()) {
1343 frames_it.Advance();
1344 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001345 // Step out: If there is a JavaScript caller frame, we need to
1346 // flood it with breakpoints.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001347 if (!frames_it.done()) {
1348 // Fill the function to return to with one-shot break points.
1349 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
1350 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
ager@chromium.orga1645e22009-09-09 19:27:10 +00001351 // Set target frame pointer.
1352 ActivateStepOut(frames_it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001353 }
ager@chromium.orga1645e22009-09-09 19:27:10 +00001354 } else if (!(is_inline_cache_stub || RelocInfo::IsConstructCall(it.rmode()) ||
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001355 !call_function_stub.is_null() || is_at_restarted_function)
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001356 || step_action == StepNext || step_action == StepMin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001357 // Step next or step min.
1358
1359 // Fill the current function with one-shot break points.
1360 FloodWithOneShot(shared);
1361
1362 // Remember source position and frame to handle step next.
1363 thread_local_.last_statement_position_ =
1364 debug_info->code()->SourceStatementPosition(frame->pc());
1365 thread_local_.last_fp_ = frame->fp();
1366 } else {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001367 // If there's restarter frame on top of the stack, just get the pointer
1368 // to function which is going to be restarted.
1369 if (is_at_restarted_function) {
1370 Handle<JSFunction> restarted_function(
1371 JSFunction::cast(*thread_local_.restarter_frame_function_pointer_));
1372 Handle<SharedFunctionInfo> restarted_shared(
1373 restarted_function->shared());
1374 FloodWithOneShot(restarted_shared);
1375 } else if (!call_function_stub.is_null()) {
1376 // If it's CallFunction stub ensure target function is compiled and flood
1377 // it with one shot breakpoints.
1378
ager@chromium.orga1645e22009-09-09 19:27:10 +00001379 // Find out number of arguments from the stub minor key.
1380 // Reverse lookup required as the minor key cannot be retrieved
1381 // from the code object.
1382 Handle<Object> obj(
lrn@chromium.org7516f052011-03-30 08:52:27 +00001383 isolate_->heap()->code_stubs()->SlowReverseLookup(
1384 *call_function_stub));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001385 ASSERT(!obj.is_null());
1386 ASSERT(!(*obj)->IsUndefined());
ager@chromium.orga1645e22009-09-09 19:27:10 +00001387 ASSERT(obj->IsSmi());
1388 // Get the STUB key and extract major and minor key.
1389 uint32_t key = Smi::cast(*obj)->value();
1390 // Argc in the stub is the number of arguments passed - not the
1391 // expected arguments of the called function.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001392 int call_function_arg_count =
1393 CallFunctionStub::ExtractArgcFromMinorKey(
1394 CodeStub::MinorKeyFromKey(key));
ager@chromium.orga1645e22009-09-09 19:27:10 +00001395 ASSERT(call_function_stub->major_key() ==
1396 CodeStub::MajorKeyFromKey(key));
1397
1398 // Find target function on the expression stack.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001399 // Expression stack looks like this (top to bottom):
ager@chromium.orga1645e22009-09-09 19:27:10 +00001400 // argN
1401 // ...
1402 // arg0
1403 // Receiver
1404 // Function to call
1405 int expressions_count = frame->ComputeExpressionsCount();
1406 ASSERT(expressions_count - 2 - call_function_arg_count >= 0);
1407 Object* fun = frame->GetExpression(
1408 expressions_count - 2 - call_function_arg_count);
1409 if (fun->IsJSFunction()) {
1410 Handle<JSFunction> js_function(JSFunction::cast(fun));
1411 // Don't step into builtins.
1412 if (!js_function->IsBuiltin()) {
1413 // It will also compile target function if it's not compiled yet.
1414 FloodWithOneShot(Handle<SharedFunctionInfo>(js_function->shared()));
1415 }
1416 }
1417 }
1418
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001419 // Fill the current function with one-shot break points even for step in on
1420 // a call target as the function called might be a native function for
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001421 // which step in will not stop. It also prepares for stepping in
1422 // getters/setters.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001423 FloodWithOneShot(shared);
1424
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001425 if (is_load_or_store) {
1426 // Remember source position and frame to handle step in getter/setter. If
1427 // there is a custom getter/setter it will be handled in
1428 // Object::Get/SetPropertyWithCallback, otherwise the step action will be
1429 // propagated on the next Debug::Break.
1430 thread_local_.last_statement_position_ =
1431 debug_info->code()->SourceStatementPosition(frame->pc());
1432 thread_local_.last_fp_ = frame->fp();
1433 }
1434
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001435 // Step in or Step in min
1436 it.PrepareStepIn();
1437 ActivateStepIn(frame);
1438 }
1439}
1440
1441
1442// Check whether the current debug break should be reported to the debugger. It
1443// is used to have step next and step in only report break back to the debugger
1444// if on a different frame or in a different statement. In some situations
1445// there will be several break points in the same statement when the code is
v8.team.kasperl727e9952008-09-02 14:56:44 +00001446// flooded with one-shot break points. This function helps to perform several
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001447// steps before reporting break back to the debugger.
1448bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
1449 JavaScriptFrame* frame) {
1450 // If the step last action was step next or step in make sure that a new
1451 // statement is hit.
1452 if (thread_local_.last_step_action_ == StepNext ||
1453 thread_local_.last_step_action_ == StepIn) {
1454 // Never continue if returning from function.
1455 if (break_location_iterator->IsExit()) return false;
1456
1457 // Continue if we are still on the same frame and in the same statement.
1458 int current_statement_position =
1459 break_location_iterator->code()->SourceStatementPosition(frame->pc());
1460 return thread_local_.last_fp_ == frame->fp() &&
ager@chromium.org236ad962008-09-25 09:45:57 +00001461 thread_local_.last_statement_position_ == current_statement_position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001462 }
1463
1464 // No step next action - don't continue.
1465 return false;
1466}
1467
1468
1469// Check whether the code object at the specified address is a debug break code
1470// object.
1471bool Debug::IsDebugBreak(Address addr) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00001472 Code* code = Code::GetCodeFromTargetAddress(addr);
kasper.lund7276f142008-07-30 08:49:36 +00001473 return code->ic_state() == DEBUG_BREAK;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001474}
1475
1476
1477// Check whether a code stub with the specified major key is a possible break
1478// point location when looking for source break locations.
1479bool Debug::IsSourceBreakStub(Code* code) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001480 CodeStub::Major major_key = CodeStub::GetMajorKey(code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001481 return major_key == CodeStub::CallFunction;
1482}
1483
1484
1485// Check whether a code stub with the specified major key is a possible break
1486// location.
1487bool Debug::IsBreakStub(Code* code) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001488 CodeStub::Major major_key = CodeStub::GetMajorKey(code);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001489 return major_key == CodeStub::CallFunction;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001490}
1491
1492
1493// Find the builtin to use for invoking the debug break
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001494Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001495 // Find the builtin debug break function matching the calling convention
1496 // used by the call site.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001497 if (code->is_inline_cache_stub()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001498 switch (code->kind()) {
1499 case Code::CALL_IC:
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001500 case Code::KEYED_CALL_IC:
1501 return ComputeCallDebugBreak(code->arguments_count(), code->kind());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001502
1503 case Code::LOAD_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001504 return Isolate::Current()->builtins()->LoadIC_DebugBreak();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001505
1506 case Code::STORE_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001507 return Isolate::Current()->builtins()->StoreIC_DebugBreak();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001508
1509 case Code::KEYED_LOAD_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001510 return Isolate::Current()->builtins()->KeyedLoadIC_DebugBreak();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001511
1512 case Code::KEYED_STORE_IC:
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001513 return Isolate::Current()->builtins()->KeyedStoreIC_DebugBreak();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001514
1515 default:
1516 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001517 }
1518 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001519 if (RelocInfo::IsConstructCall(mode)) {
1520 Handle<Code> result =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001521 Isolate::Current()->builtins()->ConstructCall_DebugBreak();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001522 return result;
1523 }
1524 if (code->kind() == Code::STUB) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001525 ASSERT(code->major_key() == CodeStub::CallFunction);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001526 Handle<Code> result =
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001527 Isolate::Current()->builtins()->StubNoRegisters_DebugBreak();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001528 return result;
1529 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001530
1531 UNREACHABLE();
1532 return Handle<Code>::null();
1533}
1534
1535
1536// Simple function for returning the source positions for active break points.
1537Handle<Object> Debug::GetSourceBreakLocations(
1538 Handle<SharedFunctionInfo> shared) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001539 Isolate* isolate = Isolate::Current();
1540 Heap* heap = isolate->heap();
1541 if (!HasDebugInfo(shared)) return Handle<Object>(heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1543 if (debug_info->GetBreakPointCount() == 0) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001544 return Handle<Object>(heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001545 }
1546 Handle<FixedArray> locations =
lrn@chromium.org7516f052011-03-30 08:52:27 +00001547 isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548 int count = 0;
1549 for (int i = 0; i < debug_info->break_points()->length(); i++) {
1550 if (!debug_info->break_points()->get(i)->IsUndefined()) {
1551 BreakPointInfo* break_point_info =
1552 BreakPointInfo::cast(debug_info->break_points()->get(i));
1553 if (break_point_info->GetBreakPointCount() > 0) {
1554 locations->set(count++, break_point_info->statement_position());
1555 }
1556 }
1557 }
1558 return locations;
1559}
1560
1561
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001562void Debug::NewBreak(StackFrame::Id break_frame_id) {
1563 thread_local_.break_frame_id_ = break_frame_id;
1564 thread_local_.break_id_ = ++thread_local_.break_count_;
1565}
1566
1567
1568void Debug::SetBreak(StackFrame::Id break_frame_id, int break_id) {
1569 thread_local_.break_frame_id_ = break_frame_id;
1570 thread_local_.break_id_ = break_id;
1571}
1572
1573
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001574// Handle stepping into a function.
1575void Debug::HandleStepIn(Handle<JSFunction> function,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001576 Handle<Object> holder,
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001577 Address fp,
1578 bool is_constructor) {
1579 // If the frame pointer is not supplied by the caller find it.
1580 if (fp == 0) {
1581 StackFrameIterator it;
1582 it.Advance();
1583 // For constructor functions skip another frame.
1584 if (is_constructor) {
1585 ASSERT(it.frame()->is_construct());
1586 it.Advance();
1587 }
1588 fp = it.frame()->fp();
1589 }
1590
1591 // Flood the function with one-shot break points if it is called from where
1592 // step into was requested.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001593 if (fp == step_in_fp()) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001594 // Don't allow step into functions in the native context.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001595 if (!function->IsBuiltin()) {
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001596 if (function->shared()->code() ==
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001597 Isolate::Current()->builtins()->builtin(Builtins::kFunctionApply) ||
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001598 function->shared()->code() ==
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001599 Isolate::Current()->builtins()->builtin(Builtins::kFunctionCall)) {
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001600 // Handle function.apply and function.call separately to flood the
1601 // function to be called and not the code for Builtins::FunctionApply or
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001602 // Builtins::FunctionCall. The receiver of call/apply is the target
1603 // function.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001604 if (!holder.is_null() && holder->IsJSFunction() &&
1605 !JSFunction::cast(*holder)->IsBuiltin()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001606 Handle<SharedFunctionInfo> shared_info(
1607 JSFunction::cast(*holder)->shared());
1608 Debug::FloodWithOneShot(shared_info);
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001609 }
1610 } else {
1611 Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1612 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001613 }
1614 }
1615}
1616
1617
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001618void Debug::ClearStepping() {
1619 // Clear the various stepping setup.
1620 ClearOneShot();
1621 ClearStepIn();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001622 ClearStepOut();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001623 ClearStepNext();
1624
1625 // Clear multiple step counter.
1626 thread_local_.step_count_ = 0;
1627}
1628
1629// Clears all the one-shot break points that are currently set. Normally this
1630// function is called each time a break point is hit as one shot break points
1631// are used to support stepping.
1632void Debug::ClearOneShot() {
1633 // The current implementation just runs through all the breakpoints. When the
v8.team.kasperl727e9952008-09-02 14:56:44 +00001634 // last break point for a function is removed that function is automatically
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001635 // removed from the list.
1636
1637 DebugInfoListNode* node = debug_info_list_;
1638 while (node != NULL) {
1639 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1640 while (!it.Done()) {
1641 it.ClearOneShot();
1642 it.Next();
1643 }
1644 node = node->next();
1645 }
1646}
1647
1648
1649void Debug::ActivateStepIn(StackFrame* frame) {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001650 ASSERT(!StepOutActive());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001651 thread_local_.step_into_fp_ = frame->fp();
1652}
1653
1654
1655void Debug::ClearStepIn() {
1656 thread_local_.step_into_fp_ = 0;
1657}
1658
1659
ager@chromium.orga1645e22009-09-09 19:27:10 +00001660void Debug::ActivateStepOut(StackFrame* frame) {
1661 ASSERT(!StepInActive());
1662 thread_local_.step_out_fp_ = frame->fp();
1663}
1664
1665
1666void Debug::ClearStepOut() {
1667 thread_local_.step_out_fp_ = 0;
1668}
1669
1670
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001671void Debug::ClearStepNext() {
1672 thread_local_.last_step_action_ = StepNone;
ager@chromium.org236ad962008-09-25 09:45:57 +00001673 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001674 thread_local_.last_fp_ = 0;
1675}
1676
1677
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001678// Ensures the debug information is present for shared.
1679bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
1680 // Return if we already have the debug info for shared.
1681 if (HasDebugInfo(shared)) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001682
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001683 // Ensure shared in compiled. Return false if this failed.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001684 if (!EnsureCompiled(shared, CLEAR_EXCEPTION)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001685
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001686 // If preparing for the first break point make sure to deoptimize all
1687 // functions as debugging does not work with optimized code.
1688 if (!has_break_points_) {
1689 Deoptimizer::DeoptimizeAll();
1690 }
1691
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001692 // Create the debug info object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001693 Handle<DebugInfo> debug_info = FACTORY->NewDebugInfo(shared);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001694
1695 // Add debug info to the list.
1696 DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
1697 node->set_next(debug_info_list_);
1698 debug_info_list_ = node;
1699
1700 // Now there is at least one break point.
1701 has_break_points_ = true;
1702
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001703 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001704}
1705
1706
1707void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
1708 ASSERT(debug_info_list_ != NULL);
1709 // Run through the debug info objects to find this one and remove it.
1710 DebugInfoListNode* prev = NULL;
1711 DebugInfoListNode* current = debug_info_list_;
1712 while (current != NULL) {
1713 if (*current->debug_info() == *debug_info) {
1714 // Unlink from list. If prev is NULL we are looking at the first element.
1715 if (prev == NULL) {
1716 debug_info_list_ = current->next();
1717 } else {
1718 prev->set_next(current->next());
1719 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00001720 current->debug_info()->shared()->set_debug_info(
1721 isolate_->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001722 delete current;
1723
1724 // If there are no more debug info objects there are not more break
1725 // points.
1726 has_break_points_ = debug_info_list_ != NULL;
1727
1728 return;
1729 }
1730 // Move to next in list.
1731 prev = current;
1732 current = current->next();
1733 }
1734 UNREACHABLE();
1735}
1736
1737
1738void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001739 HandleScope scope(isolate_);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001740
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001741 // Get the executing function in which the debug break occurred.
1742 Handle<SharedFunctionInfo> shared =
1743 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001744 if (!EnsureDebugInfo(shared)) {
1745 // Return if we failed to retrieve the debug info.
1746 return;
1747 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001748 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1749 Handle<Code> code(debug_info->code());
1750 Handle<Code> original_code(debug_info->original_code());
1751#ifdef DEBUG
1752 // Get the code which is actually executing.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001753 Handle<Code> frame_code(frame->LookupCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001754 ASSERT(frame_code.is_identical_to(code));
1755#endif
1756
1757 // Find the call address in the running code. This address holds the call to
1758 // either a DebugBreakXXX or to the debug break return entry code if the
1759 // break point is still active after processing the break point.
ager@chromium.org4af710e2009-09-15 12:20:11 +00001760 Address addr = frame->pc() - Assembler::kCallTargetAddressOffset;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001761
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001762 // Check if the location is at JS exit or debug break slot.
ager@chromium.orga1645e22009-09-09 19:27:10 +00001763 bool at_js_return = false;
1764 bool break_at_js_return_active = false;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001765 bool at_debug_break_slot = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001766 RelocIterator it(debug_info->code());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001767 while (!it.done() && !at_js_return && !at_debug_break_slot) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001768 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001769 at_js_return = (it.rinfo()->pc() ==
1770 addr - Assembler::kPatchReturnSequenceAddressOffset);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001771 break_at_js_return_active = it.rinfo()->IsPatchedReturnSequence();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001772 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001773 if (RelocInfo::IsDebugBreakSlot(it.rinfo()->rmode())) {
1774 at_debug_break_slot = (it.rinfo()->pc() ==
1775 addr - Assembler::kPatchDebugBreakSlotAddressOffset);
1776 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001777 it.next();
1778 }
1779
1780 // Handle the jump to continue execution after break point depending on the
1781 // break location.
ager@chromium.orga1645e22009-09-09 19:27:10 +00001782 if (at_js_return) {
1783 // If the break point as return is still active jump to the corresponding
1784 // place in the original code. If not the break point was removed during
1785 // break point processing.
1786 if (break_at_js_return_active) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001787 addr += original_code->instruction_start() - code->instruction_start();
1788 }
1789
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001790 // Move back to where the call instruction sequence started.
1791 thread_local_.after_break_target_ =
1792 addr - Assembler::kPatchReturnSequenceAddressOffset;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001793 } else if (at_debug_break_slot) {
1794 // Address of where the debug break slot starts.
1795 addr = addr - Assembler::kPatchDebugBreakSlotAddressOffset;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001796
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001797 // Continue just after the slot.
1798 thread_local_.after_break_target_ = addr + Assembler::kDebugBreakSlotLength;
1799 } else if (IsDebugBreak(Assembler::target_address_at(addr))) {
1800 // We now know that there is still a debug break call at the target address,
1801 // so the break point is still there and the original code will hold the
1802 // address to jump to in order to complete the call which is replaced by a
1803 // call to DebugBreakXXX.
1804
1805 // Find the corresponding address in the original code.
1806 addr += original_code->instruction_start() - code->instruction_start();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001807
1808 // Install jump to the call address in the original code. This will be the
1809 // call which was overwritten by the call to DebugBreakXXX.
1810 thread_local_.after_break_target_ = Assembler::target_address_at(addr);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001811 } else {
1812 // There is no longer a break point present. Don't try to look in the
1813 // original code as the running code will have the right address. This takes
1814 // care of the case where the last break point is removed from the function
1815 // and therefore no "original code" is available.
1816 thread_local_.after_break_target_ = Assembler::target_address_at(addr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001817 }
1818}
1819
1820
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001821bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001822 HandleScope scope(isolate_);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001823
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00001824 // If there are no break points this cannot be break at return, as
1825 // the debugger statement and stack guard bebug break cannot be at
1826 // return.
1827 if (!has_break_points_) {
1828 return false;
1829 }
1830
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001831 // Get the executing function in which the debug break occurred.
1832 Handle<SharedFunctionInfo> shared =
1833 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
1834 if (!EnsureDebugInfo(shared)) {
1835 // Return if we failed to retrieve the debug info.
1836 return false;
1837 }
1838 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1839 Handle<Code> code(debug_info->code());
1840#ifdef DEBUG
1841 // Get the code which is actually executing.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001842 Handle<Code> frame_code(frame->LookupCode());
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00001843 ASSERT(frame_code.is_identical_to(code));
1844#endif
1845
1846 // Find the call address in the running code.
1847 Address addr = frame->pc() - Assembler::kCallTargetAddressOffset;
1848
1849 // Check if the location is at JS return.
1850 RelocIterator it(debug_info->code());
1851 while (!it.done()) {
1852 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
1853 return (it.rinfo()->pc() ==
1854 addr - Assembler::kPatchReturnSequenceAddressOffset);
1855 }
1856 it.next();
1857 }
1858 return false;
1859}
1860
1861
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001862void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001863 FrameDropMode mode,
1864 Object** restarter_frame_function_pointer) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001865 thread_local_.frame_drop_mode_ = mode;
ager@chromium.org357bf652010-04-12 11:30:10 +00001866 thread_local_.break_frame_id_ = new_break_frame_id;
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001867 thread_local_.restarter_frame_function_pointer_ =
1868 restarter_frame_function_pointer;
ager@chromium.org357bf652010-04-12 11:30:10 +00001869}
1870
1871
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001872bool Debug::IsDebugGlobal(GlobalObject* global) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001873 return IsLoaded() && global == debug_context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001874}
1875
1876
ager@chromium.org32912102009-01-16 10:38:43 +00001877void Debug::ClearMirrorCache() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001878 PostponeInterruptsScope postpone(isolate_);
lrn@chromium.org7516f052011-03-30 08:52:27 +00001879 HandleScope scope(isolate_);
1880 ASSERT(isolate_->context() == *Debug::debug_context());
ager@chromium.org32912102009-01-16 10:38:43 +00001881
1882 // Clear the mirror cache.
1883 Handle<String> function_name =
lrn@chromium.org7516f052011-03-30 08:52:27 +00001884 isolate_->factory()->LookupSymbol(CStrVector("ClearMirrorCache"));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001885 Handle<Object> fun(Isolate::Current()->global()->GetPropertyNoExceptionThrown(
lrn@chromium.org303ada72010-10-27 09:33:13 +00001886 *function_name));
ager@chromium.org32912102009-01-16 10:38:43 +00001887 ASSERT(fun->IsJSFunction());
1888 bool caught_exception;
1889 Handle<Object> js_object = Execution::TryCall(
1890 Handle<JSFunction>::cast(fun),
1891 Handle<JSObject>(Debug::debug_context()->global()),
1892 0, NULL, &caught_exception);
1893}
1894
1895
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001896void Debug::CreateScriptCache() {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001897 Heap* heap = isolate_->heap();
1898 HandleScope scope(isolate_);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001899
1900 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
1901 // rid of all the cached script wrappers and the second gets rid of the
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001902 // scripts which are no longer referenced.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001903 heap->CollectAllGarbage(false);
1904 heap->CollectAllGarbage(false);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001905
1906 ASSERT(script_cache_ == NULL);
1907 script_cache_ = new ScriptCache();
1908
1909 // Scan heap for Script objects.
1910 int count = 0;
1911 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001912 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
sgjesse@chromium.org152a0b02009-10-07 13:50:16 +00001913 if (obj->IsScript() && Script::cast(obj)->HasValidSource()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001914 script_cache_->Add(Handle<Script>(Script::cast(obj)));
1915 count++;
1916 }
1917 }
1918}
1919
1920
1921void Debug::DestroyScriptCache() {
1922 // Get rid of the script cache if it was created.
1923 if (script_cache_ != NULL) {
1924 delete script_cache_;
1925 script_cache_ = NULL;
1926 }
1927}
1928
1929
1930void Debug::AddScriptToScriptCache(Handle<Script> script) {
1931 if (script_cache_ != NULL) {
1932 script_cache_->Add(script);
1933 }
1934}
1935
1936
1937Handle<FixedArray> Debug::GetLoadedScripts() {
1938 // 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) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001947 isolate_->factory()->NewFixedArray(0);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001948 }
1949
1950 // Perform GC to get unreferenced scripts evicted from the cache before
1951 // returning the content.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001952 isolate_->heap()->CollectAllGarbage(false);
kasperl@chromium.org71affb52009-05-26 05:44:31 +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
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001967Debugger::Debugger(Isolate* isolate)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001968 : debugger_access_(OS::CreateMutex()),
1969 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),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001982 command_queue_(isolate->logger(), kQueueInitialSize),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001983 command_received_(OS::CreateSemaphore(0)),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001984 event_command_queue_(isolate->logger(), kQueueInitialSize),
1985 isolate_(isolate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001986}
1987
1988
1989Debugger::~Debugger() {
1990 delete debugger_access_;
1991 debugger_access_ = 0;
1992 delete dispatch_handler_access_;
1993 dispatch_handler_access_ = 0;
1994 delete command_received_;
1995 command_received_ = 0;
1996}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001997
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001998
1999Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
2000 int argc, Object*** argv,
2001 bool* caught_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002002 ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002003
2004 // Create the execution state object.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002005 Handle<String> constructor_str =
2006 isolate_->factory()->LookupSymbol(constructor_name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002007 Handle<Object> constructor(
2008 isolate_->global()->GetPropertyNoExceptionThrown(*constructor_str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002009 ASSERT(constructor->IsJSFunction());
2010 if (!constructor->IsJSFunction()) {
2011 *caught_exception = true;
lrn@chromium.org7516f052011-03-30 08:52:27 +00002012 return isolate_->factory()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 }
2014 Handle<Object> js_object = Execution::TryCall(
2015 Handle<JSFunction>::cast(constructor),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002016 Handle<JSObject>(isolate_->debug()->debug_context()->global()),
2017 argc, argv, caught_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002018 return js_object;
2019}
2020
2021
2022Handle<Object> Debugger::MakeExecutionState(bool* caught_exception) {
2023 // Create the execution state object.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002024 Handle<Object> break_id = isolate_->factory()->NewNumberFromInt(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002025 isolate_->debug()->break_id());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002026 const int argc = 1;
2027 Object** argv[argc] = { break_id.location() };
2028 return MakeJSObject(CStrVector("MakeExecutionState"),
2029 argc, argv, caught_exception);
2030}
2031
2032
2033Handle<Object> Debugger::MakeBreakEvent(Handle<Object> exec_state,
2034 Handle<Object> break_points_hit,
2035 bool* caught_exception) {
2036 // Create the new break event object.
2037 const int argc = 2;
2038 Object** argv[argc] = { exec_state.location(),
2039 break_points_hit.location() };
2040 return MakeJSObject(CStrVector("MakeBreakEvent"),
2041 argc,
2042 argv,
2043 caught_exception);
2044}
2045
2046
2047Handle<Object> Debugger::MakeExceptionEvent(Handle<Object> exec_state,
2048 Handle<Object> exception,
2049 bool uncaught,
2050 bool* caught_exception) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002051 Factory* factory = isolate_->factory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002052 // Create the new exception event object.
2053 const int argc = 3;
2054 Object** argv[argc] = { exec_state.location(),
2055 exception.location(),
lrn@chromium.org7516f052011-03-30 08:52:27 +00002056 uncaught ? factory->true_value().location() :
2057 factory->false_value().location()};
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002058 return MakeJSObject(CStrVector("MakeExceptionEvent"),
2059 argc, argv, caught_exception);
2060}
2061
2062
2063Handle<Object> Debugger::MakeNewFunctionEvent(Handle<Object> function,
2064 bool* caught_exception) {
2065 // Create the new function event object.
2066 const int argc = 1;
2067 Object** argv[argc] = { function.location() };
2068 return MakeJSObject(CStrVector("MakeNewFunctionEvent"),
2069 argc, argv, caught_exception);
2070}
2071
2072
2073Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
iposva@chromium.org245aa852009-02-10 00:49:54 +00002074 bool before,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002075 bool* caught_exception) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002076 Factory* factory = isolate_->factory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002077 // Create the compile event object.
2078 Handle<Object> exec_state = MakeExecutionState(caught_exception);
iposva@chromium.org245aa852009-02-10 00:49:54 +00002079 Handle<Object> script_wrapper = GetScriptWrapper(script);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002080 const int argc = 3;
iposva@chromium.org245aa852009-02-10 00:49:54 +00002081 Object** argv[argc] = { exec_state.location(),
2082 script_wrapper.location(),
lrn@chromium.org7516f052011-03-30 08:52:27 +00002083 before ? factory->true_value().location() :
2084 factory->false_value().location() };
iposva@chromium.org245aa852009-02-10 00:49:54 +00002085
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002086 return MakeJSObject(CStrVector("MakeCompileEvent"),
2087 argc,
2088 argv,
2089 caught_exception);
2090}
2091
2092
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002093Handle<Object> Debugger::MakeScriptCollectedEvent(int id,
2094 bool* caught_exception) {
2095 // Create the script collected event object.
2096 Handle<Object> exec_state = MakeExecutionState(caught_exception);
2097 Handle<Object> id_object = Handle<Smi>(Smi::FromInt(id));
2098 const int argc = 2;
2099 Object** argv[argc] = { exec_state.location(), id_object.location() };
2100
2101 return MakeJSObject(CStrVector("MakeScriptCollectedEvent"),
2102 argc,
2103 argv,
2104 caught_exception);
2105}
2106
2107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002108void Debugger::OnException(Handle<Object> exception, bool uncaught) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002109 HandleScope scope(isolate_);
2110 Debug* debug = isolate_->debug();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002111
2112 // Bail out based on state or if there is no listener for this event
lrn@chromium.org7516f052011-03-30 08:52:27 +00002113 if (debug->InDebugger()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002114 if (!Debugger::EventActive(v8::Exception)) return;
2115
2116 // Bail out if exception breaks are not active
2117 if (uncaught) {
2118 // Uncaught exceptions are reported by either flags.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002119 if (!(debug->break_on_uncaught_exception() ||
2120 debug->break_on_exception())) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002121 } else {
2122 // Caught exceptions are reported is activated.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002123 if (!debug->break_on_exception()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002124 }
2125
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002126 // Enter the debugger.
2127 EnterDebugger debugger;
2128 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002129
2130 // Clear all current stepping setup.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002131 debug->ClearStepping();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002132 // Create the event data object.
2133 bool caught_exception = false;
2134 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2135 Handle<Object> event_data;
2136 if (!caught_exception) {
2137 event_data = MakeExceptionEvent(exec_state, exception, uncaught,
2138 &caught_exception);
2139 }
2140 // Bail out and don't call debugger if exception.
2141 if (caught_exception) {
2142 return;
2143 }
2144
ager@chromium.org5ec48922009-05-05 07:25:34 +00002145 // Process debug event.
2146 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002147 // Return to continue execution from where the exception was thrown.
2148}
2149
2150
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002151void Debugger::OnDebugBreak(Handle<Object> break_points_hit,
2152 bool auto_continue) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002153 HandleScope scope(isolate_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002154
kasper.lund212ac232008-07-16 07:07:30 +00002155 // Debugger has already been entered by caller.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002156 ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
kasper.lund212ac232008-07-16 07:07:30 +00002157
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002158 // Bail out if there is no listener for this event
2159 if (!Debugger::EventActive(v8::Break)) return;
2160
2161 // Debugger must be entered in advance.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002162 ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002163
2164 // Create the event data object.
2165 bool caught_exception = false;
2166 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2167 Handle<Object> event_data;
2168 if (!caught_exception) {
2169 event_data = MakeBreakEvent(exec_state, break_points_hit,
2170 &caught_exception);
2171 }
2172 // Bail out and don't call debugger if exception.
2173 if (caught_exception) {
2174 return;
2175 }
2176
ager@chromium.org5ec48922009-05-05 07:25:34 +00002177 // Process debug event.
2178 ProcessDebugEvent(v8::Break,
2179 Handle<JSObject>::cast(event_data),
2180 auto_continue);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002181}
2182
2183
2184void Debugger::OnBeforeCompile(Handle<Script> script) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002185 HandleScope scope(isolate_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002186
2187 // Bail out based on state or if there is no listener for this event
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002188 if (isolate_->debug()->InDebugger()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002189 if (compiling_natives()) return;
2190 if (!EventActive(v8::BeforeCompile)) return;
2191
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002192 // Enter the debugger.
2193 EnterDebugger debugger;
2194 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002195
2196 // Create the event data object.
2197 bool caught_exception = false;
iposva@chromium.org245aa852009-02-10 00:49:54 +00002198 Handle<Object> event_data = MakeCompileEvent(script, true, &caught_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002199 // Bail out and don't call debugger if exception.
2200 if (caught_exception) {
2201 return;
2202 }
2203
ager@chromium.org5ec48922009-05-05 07:25:34 +00002204 // Process debug event.
2205 ProcessDebugEvent(v8::BeforeCompile,
2206 Handle<JSObject>::cast(event_data),
2207 true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002208}
2209
2210
2211// Handle debugger actions when a new script is compiled.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002212void Debugger::OnAfterCompile(Handle<Script> script,
2213 AfterCompileFlags after_compile_flags) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002214 HandleScope scope(isolate_);
2215 Debug* debug = isolate_->debug();
kasper.lund212ac232008-07-16 07:07:30 +00002216
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002217 // Add the newly compiled script to the script cache.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002218 debug->AddScriptToScriptCache(script);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002219
2220 // No more to do if not debugging.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002221 if (!IsDebuggerActive()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002222
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002223 // No compile events while compiling natives.
2224 if (compiling_natives()) return;
2225
iposva@chromium.org245aa852009-02-10 00:49:54 +00002226 // Store whether in debugger before entering debugger.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002227 bool in_debugger = debug->InDebugger();
iposva@chromium.org245aa852009-02-10 00:49:54 +00002228
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002229 // Enter the debugger.
2230 EnterDebugger debugger;
2231 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002232
2233 // If debugging there might be script break points registered for this
2234 // script. Make sure that these break points are set.
2235
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002236 // Get the function UpdateScriptBreakPoints (defined in debug-debugger.js).
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002237 Handle<String> update_script_break_points_symbol =
lrn@chromium.org7516f052011-03-30 08:52:27 +00002238 isolate_->factory()->LookupAsciiSymbol("UpdateScriptBreakPoints");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002239 Handle<Object> update_script_break_points =
lrn@chromium.org7516f052011-03-30 08:52:27 +00002240 Handle<Object>(debug->debug_context()->global()->
lrn@chromium.org303ada72010-10-27 09:33:13 +00002241 GetPropertyNoExceptionThrown(*update_script_break_points_symbol));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002242 if (!update_script_break_points->IsJSFunction()) {
2243 return;
2244 }
2245 ASSERT(update_script_break_points->IsJSFunction());
2246
2247 // Wrap the script object in a proper JS object before passing it
2248 // to JavaScript.
2249 Handle<JSValue> wrapper = GetScriptWrapper(script);
2250
2251 // Call UpdateScriptBreakPoints expect no exceptions.
kasper.lund212ac232008-07-16 07:07:30 +00002252 bool caught_exception = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002253 const int argc = 1;
2254 Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) };
2255 Handle<Object> result = Execution::TryCall(
2256 Handle<JSFunction>::cast(update_script_break_points),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002257 Isolate::Current()->js_builtins_object(), argc, argv,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002258 &caught_exception);
2259 if (caught_exception) {
2260 return;
2261 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002262 // Bail out based on state or if there is no listener for this event
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002263 if (in_debugger && (after_compile_flags & SEND_WHEN_DEBUGGING) == 0) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002264 if (!Debugger::EventActive(v8::AfterCompile)) return;
2265
2266 // Create the compile state object.
2267 Handle<Object> event_data = MakeCompileEvent(script,
iposva@chromium.org245aa852009-02-10 00:49:54 +00002268 false,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002269 &caught_exception);
2270 // Bail out and don't call debugger if exception.
2271 if (caught_exception) {
2272 return;
2273 }
ager@chromium.org5ec48922009-05-05 07:25:34 +00002274 // Process debug event.
2275 ProcessDebugEvent(v8::AfterCompile,
2276 Handle<JSObject>::cast(event_data),
2277 true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002278}
2279
2280
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002281void Debugger::OnScriptCollected(int id) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002282 HandleScope scope(isolate_);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002283
2284 // No more to do if not debugging.
2285 if (!IsDebuggerActive()) return;
2286 if (!Debugger::EventActive(v8::ScriptCollected)) return;
2287
2288 // Enter the debugger.
2289 EnterDebugger debugger;
2290 if (debugger.FailedToEnter()) return;
2291
2292 // Create the script collected state object.
2293 bool caught_exception = false;
2294 Handle<Object> event_data = MakeScriptCollectedEvent(id,
2295 &caught_exception);
2296 // Bail out and don't call debugger if exception.
2297 if (caught_exception) {
2298 return;
2299 }
2300
2301 // Process debug event.
2302 ProcessDebugEvent(v8::ScriptCollected,
2303 Handle<JSObject>::cast(event_data),
2304 true);
2305}
2306
2307
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002308void Debugger::ProcessDebugEvent(v8::DebugEvent event,
ager@chromium.org5ec48922009-05-05 07:25:34 +00002309 Handle<JSObject> event_data,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002310 bool auto_continue) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002311 HandleScope scope(isolate_);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002312
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00002313 // Clear any pending debug break if this is a real break.
2314 if (!auto_continue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002315 isolate_->debug()->clear_interrupt_pending(DEBUGBREAK);
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00002316 }
2317
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002318 // Create the execution state.
2319 bool caught_exception = false;
2320 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2321 if (caught_exception) {
2322 return;
2323 }
ager@chromium.org41826e72009-03-30 13:30:57 +00002324 // First notify the message handler if any.
2325 if (message_handler_ != NULL) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002326 NotifyMessageHandler(event,
2327 Handle<JSObject>::cast(exec_state),
2328 event_data,
2329 auto_continue);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002330 }
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00002331 // Notify registered debug event listener. This can be either a C or
2332 // a JavaScript function. Don't call event listener for v8::Break
2333 // here, if it's only a debug command -- they will be processed later.
2334 if ((event != v8::Break || !auto_continue) && !event_listener_.is_null()) {
2335 CallEventCallback(event, exec_state, event_data, NULL);
2336 }
2337 // Process pending debug commands.
2338 if (event == v8::Break) {
2339 while (!event_command_queue_.IsEmpty()) {
2340 CommandMessage command = event_command_queue_.Get();
2341 if (!event_listener_.is_null()) {
2342 CallEventCallback(v8::BreakForCommand,
2343 exec_state,
2344 event_data,
2345 command.client_data());
2346 }
2347 command.Dispose();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002348 }
2349 }
2350}
2351
2352
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00002353void Debugger::CallEventCallback(v8::DebugEvent event,
2354 Handle<Object> exec_state,
2355 Handle<Object> event_data,
2356 v8::Debug::ClientData* client_data) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002357 if (event_listener_->IsForeign()) {
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00002358 CallCEventCallback(event, exec_state, event_data, client_data);
2359 } else {
2360 CallJSEventCallback(event, exec_state, event_data);
2361 }
2362}
2363
2364
2365void Debugger::CallCEventCallback(v8::DebugEvent event,
2366 Handle<Object> exec_state,
2367 Handle<Object> event_data,
2368 v8::Debug::ClientData* client_data) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002369 Handle<Foreign> callback_obj(Handle<Foreign>::cast(event_listener_));
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00002370 v8::Debug::EventCallback2 callback =
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002371 FUNCTION_CAST<v8::Debug::EventCallback2>(callback_obj->address());
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00002372 EventDetailsImpl event_details(
2373 event,
2374 Handle<JSObject>::cast(exec_state),
2375 Handle<JSObject>::cast(event_data),
2376 event_listener_data_,
2377 client_data);
2378 callback(event_details);
2379}
2380
2381
2382void Debugger::CallJSEventCallback(v8::DebugEvent event,
2383 Handle<Object> exec_state,
2384 Handle<Object> event_data) {
2385 ASSERT(event_listener_->IsJSFunction());
2386 Handle<JSFunction> fun(Handle<JSFunction>::cast(event_listener_));
2387
2388 // Invoke the JavaScript debug event listener.
2389 const int argc = 4;
2390 Object** argv[argc] = { Handle<Object>(Smi::FromInt(event)).location(),
2391 exec_state.location(),
2392 Handle<Object>::cast(event_data).location(),
2393 event_listener_data_.location() };
2394 bool caught_exception = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002395 Execution::TryCall(fun, isolate_->global(), argc, argv, &caught_exception);
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00002396 // Silently ignore exceptions from debug event listeners.
2397}
2398
2399
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002400Handle<Context> Debugger::GetDebugContext() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002401 never_unload_debugger_ = true;
2402 EnterDebugger debugger;
2403 return isolate_->debug()->debug_context();
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002404}
2405
2406
ager@chromium.org71daaf62009-04-01 07:22:49 +00002407void Debugger::UnloadDebugger() {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002408 Debug* debug = isolate_->debug();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002409
ager@chromium.org71daaf62009-04-01 07:22:49 +00002410 // Make sure that there are no breakpoints left.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002411 debug->ClearAllBreakPoints();
ager@chromium.org71daaf62009-04-01 07:22:49 +00002412
2413 // Unload the debugger if feasible.
2414 if (!never_unload_debugger_) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002415 debug->Unload();
ager@chromium.org71daaf62009-04-01 07:22:49 +00002416 }
2417
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002418 // Clear the flag indicating that the debugger should be unloaded.
2419 debugger_unload_pending_ = false;
ager@chromium.org71daaf62009-04-01 07:22:49 +00002420}
2421
2422
ager@chromium.org41826e72009-03-30 13:30:57 +00002423void Debugger::NotifyMessageHandler(v8::DebugEvent event,
ager@chromium.org5ec48922009-05-05 07:25:34 +00002424 Handle<JSObject> exec_state,
2425 Handle<JSObject> event_data,
ager@chromium.org41826e72009-03-30 13:30:57 +00002426 bool auto_continue) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002427 HandleScope scope(isolate_);
ager@chromium.org41826e72009-03-30 13:30:57 +00002428
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002429 if (!isolate_->debug()->Load()) return;
ager@chromium.org41826e72009-03-30 13:30:57 +00002430
2431 // Process the individual events.
ager@chromium.org5ec48922009-05-05 07:25:34 +00002432 bool sendEventMessage = false;
ager@chromium.org41826e72009-03-30 13:30:57 +00002433 switch (event) {
2434 case v8::Break:
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00002435 case v8::BreakForCommand:
ager@chromium.org5ec48922009-05-05 07:25:34 +00002436 sendEventMessage = !auto_continue;
ager@chromium.org41826e72009-03-30 13:30:57 +00002437 break;
2438 case v8::Exception:
ager@chromium.org5ec48922009-05-05 07:25:34 +00002439 sendEventMessage = true;
ager@chromium.org41826e72009-03-30 13:30:57 +00002440 break;
2441 case v8::BeforeCompile:
2442 break;
2443 case v8::AfterCompile:
ager@chromium.org5ec48922009-05-05 07:25:34 +00002444 sendEventMessage = true;
ager@chromium.org41826e72009-03-30 13:30:57 +00002445 break;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002446 case v8::ScriptCollected:
2447 sendEventMessage = true;
2448 break;
ager@chromium.org41826e72009-03-30 13:30:57 +00002449 case v8::NewFunction:
2450 break;
2451 default:
2452 UNREACHABLE();
2453 }
2454
ager@chromium.org5ec48922009-05-05 07:25:34 +00002455 // The debug command interrupt flag might have been set when the command was
2456 // added. It should be enough to clear the flag only once while we are in the
2457 // debugger.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002458 ASSERT(isolate_->debug()->InDebugger());
2459 isolate_->stack_guard()->Continue(DEBUGCOMMAND);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002460
2461 // Notify the debugger that a debug event has occurred unless auto continue is
2462 // active in which case no event is send.
2463 if (sendEventMessage) {
2464 MessageImpl message = MessageImpl::NewEvent(
2465 event,
2466 auto_continue,
2467 Handle<JSObject>::cast(exec_state),
2468 Handle<JSObject>::cast(event_data));
2469 InvokeMessageHandler(message);
2470 }
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00002471
2472 // If auto continue don't make the event cause a break, but process messages
2473 // in the queue if any. For script collected events don't even process
2474 // messages in the queue as the execution state might not be what is expected
2475 // by the client.
ager@chromium.org6ffc2172009-05-29 19:20:16 +00002476 if ((auto_continue && !HasCommands()) || event == v8::ScriptCollected) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002477 return;
2478 }
ager@chromium.org41826e72009-03-30 13:30:57 +00002479
ager@chromium.org41826e72009-03-30 13:30:57 +00002480 v8::TryCatch try_catch;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002481
2482 // DebugCommandProcessor goes here.
2483 v8::Local<v8::Object> cmd_processor;
2484 {
2485 v8::Local<v8::Object> api_exec_state =
2486 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state));
2487 v8::Local<v8::String> fun_name =
2488 v8::String::New("debugCommandProcessor");
2489 v8::Local<v8::Function> fun =
2490 v8::Function::Cast(*api_exec_state->Get(fun_name));
2491
2492 v8::Handle<v8::Boolean> running =
2493 auto_continue ? v8::True() : v8::False();
2494 static const int kArgc = 1;
2495 v8::Handle<Value> argv[kArgc] = { running };
2496 cmd_processor = v8::Object::Cast(*fun->Call(api_exec_state, kArgc, argv));
2497 if (try_catch.HasCaught()) {
2498 PrintLn(try_catch.Exception());
2499 return;
2500 }
ager@chromium.org41826e72009-03-30 13:30:57 +00002501 }
2502
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002503 bool running = auto_continue;
2504
ager@chromium.org41826e72009-03-30 13:30:57 +00002505 // Process requests from the debugger.
2506 while (true) {
2507 // Wait for new command in the queue.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002508 if (Debugger::host_dispatch_handler_) {
2509 // In case there is a host dispatch - do periodic dispatches.
2510 if (!command_received_->Wait(host_dispatch_micros_)) {
2511 // Timout expired, do the dispatch.
2512 Debugger::host_dispatch_handler_();
2513 continue;
2514 }
2515 } else {
2516 // In case there is no host dispatch - just wait.
2517 command_received_->Wait();
2518 }
ager@chromium.org41826e72009-03-30 13:30:57 +00002519
ager@chromium.org41826e72009-03-30 13:30:57 +00002520 // Get the command from the queue.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002521 CommandMessage command = command_queue_.Get();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002522 isolate_->logger()->DebugTag(
2523 "Got request from command queue, in interactive loop.");
ager@chromium.org71daaf62009-04-01 07:22:49 +00002524 if (!Debugger::IsDebuggerActive()) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002525 // Delete command text and user data.
2526 command.Dispose();
ager@chromium.org41826e72009-03-30 13:30:57 +00002527 return;
2528 }
2529
ager@chromium.org41826e72009-03-30 13:30:57 +00002530 // Invoke JavaScript to process the debug request.
2531 v8::Local<v8::String> fun_name;
2532 v8::Local<v8::Function> fun;
2533 v8::Local<v8::Value> request;
2534 v8::TryCatch try_catch;
2535 fun_name = v8::String::New("processDebugRequest");
2536 fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002537
2538 request = v8::String::New(command.text().start(),
2539 command.text().length());
ager@chromium.org41826e72009-03-30 13:30:57 +00002540 static const int kArgc = 1;
2541 v8::Handle<Value> argv[kArgc] = { request };
2542 v8::Local<v8::Value> response_val = fun->Call(cmd_processor, kArgc, argv);
2543
2544 // Get the response.
2545 v8::Local<v8::String> response;
ager@chromium.org41826e72009-03-30 13:30:57 +00002546 if (!try_catch.HasCaught()) {
2547 // Get response string.
2548 if (!response_val->IsUndefined()) {
2549 response = v8::String::Cast(*response_val);
2550 } else {
2551 response = v8::String::New("");
2552 }
2553
2554 // Log the JSON request/response.
2555 if (FLAG_trace_debug_json) {
2556 PrintLn(request);
2557 PrintLn(response);
2558 }
2559
2560 // Get the running state.
2561 fun_name = v8::String::New("isRunning");
2562 fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
2563 static const int kArgc = 1;
2564 v8::Handle<Value> argv[kArgc] = { response };
2565 v8::Local<v8::Value> running_val = fun->Call(cmd_processor, kArgc, argv);
2566 if (!try_catch.HasCaught()) {
2567 running = running_val->ToBoolean()->Value();
2568 }
2569 } else {
2570 // In case of failure the result text is the exception text.
2571 response = try_catch.Exception()->ToString();
2572 }
2573
ager@chromium.org41826e72009-03-30 13:30:57 +00002574 // Return the result.
ager@chromium.org5ec48922009-05-05 07:25:34 +00002575 MessageImpl message = MessageImpl::NewResponse(
2576 event,
2577 running,
2578 Handle<JSObject>::cast(exec_state),
2579 Handle<JSObject>::cast(event_data),
2580 Handle<String>(Utils::OpenHandle(*response)),
2581 command.client_data());
2582 InvokeMessageHandler(message);
2583 command.Dispose();
ager@chromium.org41826e72009-03-30 13:30:57 +00002584
2585 // Return from debug event processing if either the VM is put into the
2586 // runnning state (through a continue command) or auto continue is active
2587 // and there are no more commands queued.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002588 if (running && !HasCommands()) {
ager@chromium.org41826e72009-03-30 13:30:57 +00002589 return;
2590 }
2591 }
2592}
2593
2594
iposva@chromium.org245aa852009-02-10 00:49:54 +00002595void Debugger::SetEventListener(Handle<Object> callback,
2596 Handle<Object> data) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002597 HandleScope scope(isolate_);
2598 GlobalHandles* global_handles = isolate_->global_handles();
iposva@chromium.org245aa852009-02-10 00:49:54 +00002599
2600 // Clear the global handles for the event listener and the event listener data
2601 // object.
2602 if (!event_listener_.is_null()) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002603 global_handles->Destroy(
iposva@chromium.org245aa852009-02-10 00:49:54 +00002604 reinterpret_cast<Object**>(event_listener_.location()));
2605 event_listener_ = Handle<Object>();
2606 }
2607 if (!event_listener_data_.is_null()) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002608 global_handles->Destroy(
iposva@chromium.org245aa852009-02-10 00:49:54 +00002609 reinterpret_cast<Object**>(event_listener_data_.location()));
2610 event_listener_data_ = Handle<Object>();
2611 }
2612
2613 // If there is a new debug event listener register it together with its data
2614 // object.
2615 if (!callback->IsUndefined() && !callback->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002616 event_listener_ = Handle<Object>::cast(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002617 global_handles->Create(*callback));
iposva@chromium.org245aa852009-02-10 00:49:54 +00002618 if (data.is_null()) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002619 data = isolate_->factory()->undefined_value();
iposva@chromium.org245aa852009-02-10 00:49:54 +00002620 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002621 event_listener_data_ = Handle<Object>::cast(
lrn@chromium.org7516f052011-03-30 08:52:27 +00002622 global_handles->Create(*data));
iposva@chromium.org245aa852009-02-10 00:49:54 +00002623 }
2624
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002625 ListenersChanged();
iposva@chromium.org245aa852009-02-10 00:49:54 +00002626}
2627
2628
ager@chromium.org5ec48922009-05-05 07:25:34 +00002629void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002630 ScopedLock with(debugger_access_);
2631
ager@chromium.org381abbb2009-02-25 13:23:22 +00002632 message_handler_ = handler;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002633 ListenersChanged();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002634 if (handler == NULL) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002635 // Send an empty command to the debugger if in a break to make JavaScript
2636 // run again if the debugger is closed.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002637 if (isolate_->debug()->InDebugger()) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002638 ProcessCommand(Vector<const uint16_t>::empty());
2639 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002640 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002641}
2642
2643
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002644void Debugger::ListenersChanged() {
2645 if (IsDebuggerActive()) {
2646 // Disable the compilation cache when the debugger is active.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002647 isolate_->compilation_cache()->Disable();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002648 debugger_unload_pending_ = false;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002649 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002650 isolate_->compilation_cache()->Enable();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002651 // Unload the debugger if event listener and message handler cleared.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002652 // Schedule this for later, because we may be in non-V8 thread.
2653 debugger_unload_pending_ = true;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002654 }
2655}
2656
2657
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002658void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
2659 int period) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00002660 host_dispatch_handler_ = handler;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002661 host_dispatch_micros_ = period * 1000;
ager@chromium.org381abbb2009-02-25 13:23:22 +00002662}
2663
2664
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002665void Debugger::SetDebugMessageDispatchHandler(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002666 v8::Debug::DebugMessageDispatchHandler handler, bool provide_locker) {
2667 ScopedLock with(dispatch_handler_access_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002668 debug_message_dispatch_handler_ = handler;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002669
2670 if (provide_locker && message_dispatch_helper_thread_ == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002671 message_dispatch_helper_thread_ = new MessageDispatchHelperThread(isolate_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002672 message_dispatch_helper_thread_->Start();
2673 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002674}
2675
2676
ager@chromium.org41826e72009-03-30 13:30:57 +00002677// Calls the registered debug message handler. This callback is part of the
ager@chromium.org5ec48922009-05-05 07:25:34 +00002678// public API.
2679void Debugger::InvokeMessageHandler(MessageImpl message) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002680 ScopedLock with(debugger_access_);
2681
ager@chromium.org381abbb2009-02-25 13:23:22 +00002682 if (message_handler_ != NULL) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002683 message_handler_(message);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002684 }
ager@chromium.org41826e72009-03-30 13:30:57 +00002685}
2686
2687
2688// Puts a command coming from the public API on the queue. Creates
2689// a copy of the command string managed by the debugger. Up to this
2690// point, the command data was managed by the API client. Called
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002691// by the API client thread.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002692void Debugger::ProcessCommand(Vector<const uint16_t> command,
2693 v8::Debug::ClientData* client_data) {
2694 // Need to cast away const.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002695 CommandMessage message = CommandMessage::New(
ager@chromium.org41826e72009-03-30 13:30:57 +00002696 Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002697 command.length()),
2698 client_data);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002699 isolate_->logger()->DebugTag("Put command on command_queue.");
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002700 command_queue_.Put(message);
ager@chromium.org41826e72009-03-30 13:30:57 +00002701 command_received_->Signal();
sgjesse@chromium.org3afc1582009-04-16 22:31:44 +00002702
2703 // Set the debug command break flag to have the command processed.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002704 if (!isolate_->debug()->InDebugger()) {
2705 isolate_->stack_guard()->DebugCommand();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002706 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002707
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002708 MessageDispatchHelperThread* dispatch_thread;
2709 {
2710 ScopedLock with(dispatch_handler_access_);
2711 dispatch_thread = message_dispatch_helper_thread_;
2712 }
2713
2714 if (dispatch_thread == NULL) {
2715 CallMessageDispatchHandler();
2716 } else {
2717 dispatch_thread->Schedule();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002718 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002719}
2720
2721
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002722bool Debugger::HasCommands() {
ager@chromium.org41826e72009-03-30 13:30:57 +00002723 return !command_queue_.IsEmpty();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002724}
2725
2726
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00002727void Debugger::EnqueueDebugCommand(v8::Debug::ClientData* client_data) {
2728 CommandMessage message = CommandMessage::New(Vector<uint16_t>(), client_data);
2729 event_command_queue_.Put(message);
2730
2731 // Set the debug command break flag to have the command processed.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002732 if (!isolate_->debug()->InDebugger()) {
2733 isolate_->stack_guard()->DebugCommand();
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00002734 }
2735}
2736
2737
ager@chromium.org71daaf62009-04-01 07:22:49 +00002738bool Debugger::IsDebuggerActive() {
2739 ScopedLock with(debugger_access_);
2740
2741 return message_handler_ != NULL || !event_listener_.is_null();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002742}
2743
2744
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002745Handle<Object> Debugger::Call(Handle<JSFunction> fun,
2746 Handle<Object> data,
2747 bool* pending_exception) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002748 // When calling functions in the debugger prevent it from beeing unloaded.
2749 Debugger::never_unload_debugger_ = true;
2750
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002751 // Enter the debugger.
2752 EnterDebugger debugger;
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00002753 if (debugger.FailedToEnter()) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002754 return isolate_->factory()->undefined_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002755 }
2756
2757 // Create the execution state.
2758 bool caught_exception = false;
2759 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2760 if (caught_exception) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002761 return isolate_->factory()->undefined_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002762 }
2763
2764 static const int kArgc = 2;
2765 Object** argv[kArgc] = { exec_state.location(), data.location() };
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00002766 Handle<Object> result = Execution::Call(
2767 fun,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002768 Handle<Object>(isolate_->debug()->debug_context_->global_proxy()),
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00002769 kArgc,
2770 argv,
2771 pending_exception);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002772 return result;
2773}
2774
2775
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002776static void StubMessageHandler2(const v8::Debug::Message& message) {
2777 // Simply ignore message.
2778}
2779
2780
2781bool Debugger::StartAgent(const char* name, int port,
2782 bool wait_for_connection) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002783 ASSERT(Isolate::Current() == isolate_);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002784 if (wait_for_connection) {
2785 // Suspend V8 if it is already running or set V8 to suspend whenever
2786 // it starts.
2787 // Provide stub message handler; V8 auto-continues each suspend
2788 // when there is no message handler; we doesn't need it.
2789 // Once become suspended, V8 will stay so indefinitely long, until remote
2790 // debugger connects and issues "continue" command.
2791 Debugger::message_handler_ = StubMessageHandler2;
2792 v8::Debug::DebugBreak();
2793 }
2794
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002795 if (Socket::Setup()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002796 if (agent_ == NULL) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002797 agent_ = new DebuggerAgent(name, port);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00002798 agent_->Start();
2799 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002800 return true;
2801 }
2802
2803 return false;
2804}
2805
2806
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002807void Debugger::StopAgent() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002808 ASSERT(Isolate::Current() == isolate_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002809 if (agent_ != NULL) {
2810 agent_->Shutdown();
2811 agent_->Join();
2812 delete agent_;
2813 agent_ = NULL;
2814 }
2815}
2816
2817
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002818void Debugger::WaitForAgent() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002819 ASSERT(Isolate::Current() == isolate_);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002820 if (agent_ != NULL)
2821 agent_->WaitUntilListening();
2822}
2823
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002824
2825void Debugger::CallMessageDispatchHandler() {
2826 v8::Debug::DebugMessageDispatchHandler handler;
2827 {
2828 ScopedLock with(dispatch_handler_access_);
2829 handler = Debugger::debug_message_dispatch_handler_;
2830 }
2831 if (handler != NULL) {
2832 handler();
2833 }
2834}
2835
2836
ager@chromium.org5ec48922009-05-05 07:25:34 +00002837MessageImpl MessageImpl::NewEvent(DebugEvent event,
2838 bool running,
2839 Handle<JSObject> exec_state,
2840 Handle<JSObject> event_data) {
2841 MessageImpl message(true, event, running,
2842 exec_state, event_data, Handle<String>(), NULL);
2843 return message;
2844}
2845
2846
2847MessageImpl MessageImpl::NewResponse(DebugEvent event,
2848 bool running,
2849 Handle<JSObject> exec_state,
2850 Handle<JSObject> event_data,
2851 Handle<String> response_json,
2852 v8::Debug::ClientData* client_data) {
2853 MessageImpl message(false, event, running,
2854 exec_state, event_data, response_json, client_data);
2855 return message;
2856}
2857
2858
2859MessageImpl::MessageImpl(bool is_event,
2860 DebugEvent event,
2861 bool running,
2862 Handle<JSObject> exec_state,
2863 Handle<JSObject> event_data,
2864 Handle<String> response_json,
2865 v8::Debug::ClientData* client_data)
2866 : is_event_(is_event),
2867 event_(event),
2868 running_(running),
2869 exec_state_(exec_state),
2870 event_data_(event_data),
2871 response_json_(response_json),
2872 client_data_(client_data) {}
2873
2874
2875bool MessageImpl::IsEvent() const {
2876 return is_event_;
2877}
2878
2879
2880bool MessageImpl::IsResponse() const {
2881 return !is_event_;
2882}
2883
2884
2885DebugEvent MessageImpl::GetEvent() const {
2886 return event_;
2887}
2888
2889
2890bool MessageImpl::WillStartRunning() const {
2891 return running_;
2892}
2893
2894
2895v8::Handle<v8::Object> MessageImpl::GetExecutionState() const {
2896 return v8::Utils::ToLocal(exec_state_);
2897}
2898
2899
2900v8::Handle<v8::Object> MessageImpl::GetEventData() const {
2901 return v8::Utils::ToLocal(event_data_);
2902}
2903
2904
2905v8::Handle<v8::String> MessageImpl::GetJSON() const {
2906 v8::HandleScope scope;
2907
2908 if (IsEvent()) {
2909 // Call toJSONProtocol on the debug event object.
2910 Handle<Object> fun = GetProperty(event_data_, "toJSONProtocol");
2911 if (!fun->IsJSFunction()) {
2912 return v8::Handle<v8::String>();
2913 }
2914 bool caught_exception;
2915 Handle<Object> json = Execution::TryCall(Handle<JSFunction>::cast(fun),
2916 event_data_,
2917 0, NULL, &caught_exception);
2918 if (caught_exception || !json->IsString()) {
2919 return v8::Handle<v8::String>();
2920 }
2921 return scope.Close(v8::Utils::ToLocal(Handle<String>::cast(json)));
2922 } else {
2923 return v8::Utils::ToLocal(response_json_);
2924 }
2925}
2926
2927
2928v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002929 Isolate* isolate = Isolate::Current();
2930 v8::Handle<v8::Context> context = GetDebugEventContext(isolate);
2931 // Isolate::context() may be NULL when "script collected" event occures.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002932 ASSERT(!context.IsEmpty() || event_ == v8::ScriptCollected);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002933 return GetDebugEventContext(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002934}
2935
2936
2937v8::Debug::ClientData* MessageImpl::GetClientData() const {
2938 return client_data_;
2939}
2940
2941
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002942EventDetailsImpl::EventDetailsImpl(DebugEvent event,
2943 Handle<JSObject> exec_state,
2944 Handle<JSObject> event_data,
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00002945 Handle<Object> callback_data,
2946 v8::Debug::ClientData* client_data)
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002947 : event_(event),
2948 exec_state_(exec_state),
2949 event_data_(event_data),
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00002950 callback_data_(callback_data),
2951 client_data_(client_data) {}
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002952
2953
2954DebugEvent EventDetailsImpl::GetEvent() const {
2955 return event_;
2956}
2957
2958
2959v8::Handle<v8::Object> EventDetailsImpl::GetExecutionState() const {
2960 return v8::Utils::ToLocal(exec_state_);
2961}
2962
2963
2964v8::Handle<v8::Object> EventDetailsImpl::GetEventData() const {
2965 return v8::Utils::ToLocal(event_data_);
2966}
2967
2968
2969v8::Handle<v8::Context> EventDetailsImpl::GetEventContext() const {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002970 return GetDebugEventContext(Isolate::Current());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002971}
2972
2973
2974v8::Handle<v8::Value> EventDetailsImpl::GetCallbackData() const {
2975 return v8::Utils::ToLocal(callback_data_);
2976}
2977
2978
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00002979v8::Debug::ClientData* EventDetailsImpl::GetClientData() const {
2980 return client_data_;
2981}
2982
2983
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002984CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()),
2985 client_data_(NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002986}
2987
2988
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002989CommandMessage::CommandMessage(const Vector<uint16_t>& text,
2990 v8::Debug::ClientData* data)
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002991 : text_(text),
2992 client_data_(data) {
2993}
2994
2995
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002996CommandMessage::~CommandMessage() {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002997}
2998
2999
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003000void CommandMessage::Dispose() {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003001 text_.Dispose();
3002 delete client_data_;
3003 client_data_ = NULL;
3004}
3005
3006
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003007CommandMessage CommandMessage::New(const Vector<uint16_t>& command,
3008 v8::Debug::ClientData* data) {
3009 return CommandMessage(command.Clone(), data);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003010}
3011
3012
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003013CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0),
3014 size_(size) {
3015 messages_ = NewArray<CommandMessage>(size);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003016}
3017
3018
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003019CommandMessageQueue::~CommandMessageQueue() {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003020 while (!IsEmpty()) {
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003021 CommandMessage m = Get();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003022 m.Dispose();
3023 }
kasper.lund7276f142008-07-30 08:49:36 +00003024 DeleteArray(messages_);
3025}
3026
3027
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003028CommandMessage CommandMessageQueue::Get() {
kasper.lund7276f142008-07-30 08:49:36 +00003029 ASSERT(!IsEmpty());
3030 int result = start_;
3031 start_ = (start_ + 1) % size_;
3032 return messages_[result];
3033}
3034
3035
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003036void CommandMessageQueue::Put(const CommandMessage& message) {
kasper.lund7276f142008-07-30 08:49:36 +00003037 if ((end_ + 1) % size_ == start_) {
3038 Expand();
3039 }
3040 messages_[end_] = message;
3041 end_ = (end_ + 1) % size_;
3042}
3043
3044
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003045void CommandMessageQueue::Expand() {
3046 CommandMessageQueue new_queue(size_ * 2);
kasper.lund7276f142008-07-30 08:49:36 +00003047 while (!IsEmpty()) {
3048 new_queue.Put(Get());
3049 }
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003050 CommandMessage* array_to_free = messages_;
kasper.lund7276f142008-07-30 08:49:36 +00003051 *this = new_queue;
3052 new_queue.messages_ = array_to_free;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003053 // Make the new_queue empty so that it doesn't call Dispose on any messages.
3054 new_queue.start_ = new_queue.end_;
kasper.lund7276f142008-07-30 08:49:36 +00003055 // Automatic destructor called on new_queue, freeing array_to_free.
3056}
3057
3058
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003059LockingCommandMessageQueue::LockingCommandMessageQueue(Logger* logger, int size)
3060 : logger_(logger), queue_(size) {
kasper.lund7276f142008-07-30 08:49:36 +00003061 lock_ = OS::CreateMutex();
3062}
3063
3064
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003065LockingCommandMessageQueue::~LockingCommandMessageQueue() {
kasper.lund7276f142008-07-30 08:49:36 +00003066 delete lock_;
3067}
3068
3069
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003070bool LockingCommandMessageQueue::IsEmpty() const {
kasper.lund7276f142008-07-30 08:49:36 +00003071 ScopedLock sl(lock_);
3072 return queue_.IsEmpty();
3073}
3074
3075
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003076CommandMessage LockingCommandMessageQueue::Get() {
kasper.lund7276f142008-07-30 08:49:36 +00003077 ScopedLock sl(lock_);
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003078 CommandMessage result = queue_.Get();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003079 logger_->DebugEvent("Get", result.text());
kasper.lund7276f142008-07-30 08:49:36 +00003080 return result;
3081}
3082
3083
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003084void LockingCommandMessageQueue::Put(const CommandMessage& message) {
kasper.lund7276f142008-07-30 08:49:36 +00003085 ScopedLock sl(lock_);
3086 queue_.Put(message);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003087 logger_->DebugEvent("Put", message.text());
kasper.lund7276f142008-07-30 08:49:36 +00003088}
3089
3090
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003091void LockingCommandMessageQueue::Clear() {
kasper.lund7276f142008-07-30 08:49:36 +00003092 ScopedLock sl(lock_);
3093 queue_.Clear();
3094}
3095
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003096
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003097MessageDispatchHelperThread::MessageDispatchHelperThread(Isolate* isolate)
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003098 : Thread("v8:MsgDispHelpr"),
lrn@chromium.org5d00b602011-01-05 09:51:43 +00003099 sem_(OS::CreateSemaphore(0)), mutex_(OS::CreateMutex()),
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003100 already_signalled_(false) {
3101}
3102
3103
3104MessageDispatchHelperThread::~MessageDispatchHelperThread() {
3105 delete mutex_;
3106 delete sem_;
3107}
3108
3109
3110void MessageDispatchHelperThread::Schedule() {
3111 {
3112 ScopedLock lock(mutex_);
3113 if (already_signalled_) {
3114 return;
3115 }
3116 already_signalled_ = true;
3117 }
3118 sem_->Signal();
3119}
3120
3121
3122void MessageDispatchHelperThread::Run() {
3123 while (true) {
3124 sem_->Wait();
3125 {
3126 ScopedLock lock(mutex_);
3127 already_signalled_ = false;
3128 }
3129 {
3130 Locker locker;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003131 Isolate::Current()->debugger()->CallMessageDispatchHandler();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003132 }
3133 }
3134}
3135
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003136#endif // ENABLE_DEBUGGER_SUPPORT
kasper.lund7276f142008-07-30 08:49:36 +00003137
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003138} } // namespace v8::internal