blob: e279ee9eff5bf45aaaa3d71b2cf0562a9151469c [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "api.h"
31#include "arguments.h"
32#include "bootstrapper.h"
33#include "code-stubs.h"
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"
38#include "execution.h"
39#include "global-handles.h"
ager@chromium.org65dad4b2009-04-23 08:48:43 +000040#include "ic.h"
41#include "ic-inl.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000042#include "messages.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "natives.h"
44#include "stub-cache.h"
kasper.lund7276f142008-07-30 08:49:36 +000045#include "log.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046
ager@chromium.org5ec48922009-05-05 07:25:34 +000047#include "../include/v8-debug.h"
48
kasperl@chromium.org71affb52009-05-26 05:44:31 +000049namespace v8 {
50namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000051
ager@chromium.org65dad4b2009-04-23 08:48:43 +000052#ifdef ENABLE_DEBUGGER_SUPPORT
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000053static void PrintLn(v8::Local<v8::Value> value) {
54 v8::Local<v8::String> s = value->ToString();
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000055 ScopedVector<char> data(s->Length() + 1);
56 if (data.start() == NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000057 V8::FatalProcessOutOfMemory("PrintLn");
58 return;
59 }
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +000060 s->WriteAscii(data.start());
61 PrintF("%s\n", data.start());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062}
63
64
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000065static Handle<Code> ComputeCallDebugBreak(int argc, Code::Kind kind) {
66 CALL_HEAP_FUNCTION(StubCache::ComputeCallDebugBreak(argc, kind), Code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000067}
68
69
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +000070static Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind) {
71 CALL_HEAP_FUNCTION(
72 StubCache::ComputeCallDebugPrepareStepIn(argc, kind), Code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000073}
74
75
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000076static v8::Handle<v8::Context> GetDebugEventContext() {
77 Handle<Context> context = Debug::debugger_entry()->GetContext();
78 // Top::context() may have been NULL when "script collected" event occured.
79 if (*context == NULL) {
80 return v8::Local<v8::Context>();
81 }
82 Handle<Context> global_context(context->global_context());
83 return v8::Utils::ToLocal(global_context);
84}
85
86
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000087BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info,
88 BreakLocatorType type) {
89 debug_info_ = debug_info;
90 type_ = type;
91 reloc_iterator_ = NULL;
92 reloc_iterator_original_ = NULL;
93 Reset(); // Initialize the rest of the member variables.
94}
95
96
97BreakLocationIterator::~BreakLocationIterator() {
98 ASSERT(reloc_iterator_ != NULL);
99 ASSERT(reloc_iterator_original_ != NULL);
100 delete reloc_iterator_;
101 delete reloc_iterator_original_;
102}
103
104
105void BreakLocationIterator::Next() {
106 AssertNoAllocation nogc;
107 ASSERT(!RinfoDone());
108
109 // Iterate through reloc info for code and original code stopping at each
110 // breakable code target.
111 bool first = break_point_ == -1;
112 while (!RinfoDone()) {
113 if (!first) RinfoNext();
114 first = false;
115 if (RinfoDone()) return;
116
ager@chromium.org236ad962008-09-25 09:45:57 +0000117 // Whenever a statement position or (plain) position is passed update the
118 // current value of these.
119 if (RelocInfo::IsPosition(rmode())) {
120 if (RelocInfo::IsStatementPosition(rmode())) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000121 statement_position_ = static_cast<int>(
122 rinfo()->data() - debug_info_->shared()->start_position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000123 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000124 // Always update the position as we don't want that to be before the
125 // statement position.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000126 position_ = static_cast<int>(
127 rinfo()->data() - debug_info_->shared()->start_position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000128 ASSERT(position_ >= 0);
129 ASSERT(statement_position_ >= 0);
130 }
131
132 // Check for breakable code target. Look in the original code as setting
133 // break points can cause the code targets in the running (debugged) code to
134 // be of a different kind than in the original code.
ager@chromium.org236ad962008-09-25 09:45:57 +0000135 if (RelocInfo::IsCodeTarget(rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000136 Address target = original_rinfo()->target_address();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000137 Code* code = Code::GetCodeFromTargetAddress(target);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000138 if ((code->is_inline_cache_stub() &&
139 code->kind() != Code::BINARY_OP_IC) ||
140 RelocInfo::IsConstructCall(rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000141 break_point_++;
142 return;
143 }
144 if (code->kind() == Code::STUB) {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000145 if (IsDebuggerStatement()) {
146 break_point_++;
147 return;
148 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000149 if (type_ == ALL_BREAK_LOCATIONS) {
150 if (Debug::IsBreakStub(code)) {
151 break_point_++;
152 return;
153 }
154 } else {
155 ASSERT(type_ == SOURCE_BREAK_LOCATIONS);
156 if (Debug::IsSourceBreakStub(code)) {
157 break_point_++;
158 return;
159 }
160 }
161 }
162 }
163
164 // Check for break at return.
ager@chromium.org236ad962008-09-25 09:45:57 +0000165 if (RelocInfo::IsJSReturn(rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000166 // Set the positions to the end of the function.
167 if (debug_info_->shared()->HasSourceCode()) {
168 position_ = debug_info_->shared()->end_position() -
169 debug_info_->shared()->start_position();
170 } else {
171 position_ = 0;
172 }
173 statement_position_ = position_;
174 break_point_++;
175 return;
176 }
177 }
178}
179
180
181void BreakLocationIterator::Next(int count) {
182 while (count > 0) {
183 Next();
184 count--;
185 }
186}
187
188
189// Find the break point closest to the supplied address.
190void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) {
191 // Run through all break points to locate the one closest to the address.
192 int closest_break_point = 0;
193 int distance = kMaxInt;
194 while (!Done()) {
195 // Check if this break point is closer that what was previously found.
196 if (this->pc() < pc && pc - this->pc() < distance) {
197 closest_break_point = break_point();
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000198 distance = static_cast<int>(pc - this->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000199 // Check whether we can't get any closer.
200 if (distance == 0) break;
201 }
202 Next();
203 }
204
205 // Move to the break point found.
206 Reset();
207 Next(closest_break_point);
208}
209
210
211// Find the break point closest to the supplied source position.
212void BreakLocationIterator::FindBreakLocationFromPosition(int position) {
213 // Run through all break points to locate the one closest to the source
214 // position.
215 int closest_break_point = 0;
216 int distance = kMaxInt;
217 while (!Done()) {
218 // Check if this break point is closer that what was previously found.
219 if (position <= statement_position() &&
220 statement_position() - position < distance) {
221 closest_break_point = break_point();
222 distance = statement_position() - position;
223 // Check whether we can't get any closer.
224 if (distance == 0) break;
225 }
226 Next();
227 }
228
229 // Move to the break point found.
230 Reset();
231 Next(closest_break_point);
232}
233
234
235void BreakLocationIterator::Reset() {
236 // Create relocation iterators for the two code objects.
237 if (reloc_iterator_ != NULL) delete reloc_iterator_;
238 if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_;
239 reloc_iterator_ = new RelocIterator(debug_info_->code());
240 reloc_iterator_original_ = new RelocIterator(debug_info_->original_code());
241
242 // Position at the first break point.
243 break_point_ = -1;
244 position_ = 1;
245 statement_position_ = 1;
246 Next();
247}
248
249
250bool BreakLocationIterator::Done() const {
251 return RinfoDone();
252}
253
254
255void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) {
256 // If there is not already a real break point here patch code with debug
257 // break.
258 if (!HasBreakPoint()) {
259 SetDebugBreak();
260 }
ager@chromium.orga1645e22009-09-09 19:27:10 +0000261 ASSERT(IsDebugBreak() || IsDebuggerStatement());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000262 // Set the break point information.
263 DebugInfo::SetBreakPoint(debug_info_, code_position(),
264 position(), statement_position(),
265 break_point_object);
266}
267
268
269void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) {
270 // Clear the break point information.
271 DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object);
272 // If there are no more break points here remove the debug break.
273 if (!HasBreakPoint()) {
274 ClearDebugBreak();
275 ASSERT(!IsDebugBreak());
276 }
277}
278
279
280void BreakLocationIterator::SetOneShot() {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000281 // Debugger statement always calls debugger. No need to modify it.
282 if (IsDebuggerStatement()) {
283 return;
284 }
285
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000286 // If there is a real break point here no more to do.
287 if (HasBreakPoint()) {
288 ASSERT(IsDebugBreak());
289 return;
290 }
291
292 // Patch code with debug break.
293 SetDebugBreak();
294}
295
296
297void BreakLocationIterator::ClearOneShot() {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000298 // Debugger statement always calls debugger. No need to modify it.
299 if (IsDebuggerStatement()) {
300 return;
301 }
302
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000303 // If there is a real break point here no more to do.
304 if (HasBreakPoint()) {
305 ASSERT(IsDebugBreak());
306 return;
307 }
308
309 // Patch code removing debug break.
310 ClearDebugBreak();
311 ASSERT(!IsDebugBreak());
312}
313
314
315void BreakLocationIterator::SetDebugBreak() {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000316 // Debugger statement always calls debugger. No need to modify it.
317 if (IsDebuggerStatement()) {
318 return;
319 }
320
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000321 // If there is already a break point here just return. This might happen if
v8.team.kasperl727e9952008-09-02 14:56:44 +0000322 // the same code is flooded with break points twice. Flooding the same
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000323 // function twice might happen when stepping in a function with an exception
324 // handler as the handler and the function is the same.
325 if (IsDebugBreak()) {
326 return;
327 }
328
ager@chromium.org236ad962008-09-25 09:45:57 +0000329 if (RelocInfo::IsJSReturn(rmode())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000330 // Patch the frame exit code with a break point.
331 SetDebugBreakAtReturn();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000332 } else {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000333 // Patch the IC call.
334 SetDebugBreakAtIC();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000335 }
336 ASSERT(IsDebugBreak());
337}
338
339
340void BreakLocationIterator::ClearDebugBreak() {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000341 // Debugger statement always calls debugger. No need to modify it.
342 if (IsDebuggerStatement()) {
343 return;
344 }
345
ager@chromium.org236ad962008-09-25 09:45:57 +0000346 if (RelocInfo::IsJSReturn(rmode())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000347 // Restore the frame exit code.
348 ClearDebugBreakAtReturn();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000349 } else {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000350 // Patch the IC call.
351 ClearDebugBreakAtIC();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000352 }
353 ASSERT(!IsDebugBreak());
354}
355
356
357void BreakLocationIterator::PrepareStepIn() {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000358 HandleScope scope;
359
ager@chromium.orga1645e22009-09-09 19:27:10 +0000360 // Step in can only be prepared if currently positioned on an IC call,
361 // construct call or CallFunction stub call.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000362 Address target = rinfo()->target_address();
ager@chromium.orga1645e22009-09-09 19:27:10 +0000363 Handle<Code> code(Code::GetCodeFromTargetAddress(target));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000364 if (code->is_call_stub() || code->is_keyed_call_stub()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000365 // Step in through IC call is handled by the runtime system. Therefore make
366 // sure that the any current IC is cleared and the runtime system is
367 // called. If the executing code has a debug break at the location change
368 // the call in the original code as it is the code there that will be
369 // executed in place of the debug break call.
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +0000370 Handle<Code> stub = ComputeCallDebugPrepareStepIn(code->arguments_count(),
371 code->kind());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000372 if (IsDebugBreak()) {
373 original_rinfo()->set_target_address(stub->entry());
374 } else {
375 rinfo()->set_target_address(stub->entry());
376 }
377 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000378#ifdef DEBUG
379 // All the following stuff is needed only for assertion checks so the code
380 // is wrapped in ifdef.
381 Handle<Code> maybe_call_function_stub = code;
382 if (IsDebugBreak()) {
383 Address original_target = original_rinfo()->target_address();
384 maybe_call_function_stub =
385 Handle<Code>(Code::GetCodeFromTargetAddress(original_target));
386 }
387 bool is_call_function_stub =
388 (maybe_call_function_stub->kind() == Code::STUB &&
389 maybe_call_function_stub->major_key() == CodeStub::CallFunction);
390
kasperl@chromium.orge959c182009-07-27 08:59:04 +0000391 // Step in through construct call requires no changes to the running code.
392 // Step in through getters/setters should already be prepared as well
393 // because caller of this function (Debug::PrepareStep) is expected to
394 // flood the top frame's function with one shot breakpoints.
ager@chromium.orga1645e22009-09-09 19:27:10 +0000395 // Step in through CallFunction stub should also be prepared by caller of
396 // this function (Debug::PrepareStep) which should flood target function
397 // with breakpoints.
398 ASSERT(RelocInfo::IsConstructCall(rmode()) || code->is_inline_cache_stub()
399 || is_call_function_stub);
400#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000401 }
402}
403
404
405// Check whether the break point is at a position which will exit the function.
406bool BreakLocationIterator::IsExit() const {
ager@chromium.org236ad962008-09-25 09:45:57 +0000407 return (RelocInfo::IsJSReturn(rmode()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000408}
409
410
411bool BreakLocationIterator::HasBreakPoint() {
412 return debug_info_->HasBreakPoint(code_position());
413}
414
415
416// Check whether there is a debug break at the current position.
417bool BreakLocationIterator::IsDebugBreak() {
ager@chromium.org236ad962008-09-25 09:45:57 +0000418 if (RelocInfo::IsJSReturn(rmode())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000419 return IsDebugBreakAtReturn();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000420 } else {
421 return Debug::IsDebugBreak(rinfo()->target_address());
422 }
423}
424
425
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000426void BreakLocationIterator::SetDebugBreakAtIC() {
427 // Patch the original code with the current address as the current address
428 // might have changed by the inline caching since the code was copied.
429 original_rinfo()->set_target_address(rinfo()->target_address());
430
431 RelocInfo::Mode mode = rmode();
432 if (RelocInfo::IsCodeTarget(mode)) {
433 Address target = rinfo()->target_address();
434 Handle<Code> code(Code::GetCodeFromTargetAddress(target));
435
436 // Patch the code to invoke the builtin debug break function matching the
437 // calling convention used by the call site.
438 Handle<Code> dbgbrk_code(Debug::FindDebugBreak(code, mode));
439 rinfo()->set_target_address(dbgbrk_code->entry());
440
441 // For stubs that refer back to an inlined version clear the cached map for
442 // the inlined case to always go through the IC. As long as the break point
443 // is set the patching performed by the runtime system will take place in
444 // the code copy and will therefore have no effect on the running code
445 // keeping it from using the inlined code.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +0000446 if (code->is_keyed_load_stub()) {
447 KeyedLoadIC::ClearInlinedVersion(pc());
448 } else if (code->is_keyed_store_stub()) {
449 KeyedStoreIC::ClearInlinedVersion(pc());
450 } else if (code->is_load_stub()) {
451 LoadIC::ClearInlinedVersion(pc());
452 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000453 }
454}
455
456
457void BreakLocationIterator::ClearDebugBreakAtIC() {
458 // Patch the code to the original invoke.
459 rinfo()->set_target_address(original_rinfo()->target_address());
ager@chromium.orgeadaf222009-06-16 09:43:10 +0000460
461 RelocInfo::Mode mode = rmode();
462 if (RelocInfo::IsCodeTarget(mode)) {
463 Address target = original_rinfo()->target_address();
464 Handle<Code> code(Code::GetCodeFromTargetAddress(target));
465
466 // Restore the inlined version of keyed stores to get back to the
467 // fast case. We need to patch back the keyed store because no
468 // patching happens when running normally. For keyed loads, the
469 // map check will get patched back when running normally after ICs
470 // have been cleared at GC.
471 if (code->is_keyed_store_stub()) KeyedStoreIC::RestoreInlinedVersion(pc());
472 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000473}
474
475
ager@chromium.orga1645e22009-09-09 19:27:10 +0000476bool BreakLocationIterator::IsDebuggerStatement() {
ager@chromium.org5c838252010-02-19 08:53:10 +0000477 return RelocInfo::DEBUG_BREAK == rmode();
ager@chromium.orga1645e22009-09-09 19:27:10 +0000478}
479
480
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000481Object* BreakLocationIterator::BreakPointObjects() {
482 return debug_info_->GetBreakPointObjects(code_position());
483}
484
485
ager@chromium.org381abbb2009-02-25 13:23:22 +0000486// Clear out all the debug break code. This is ONLY supposed to be used when
487// shutting down the debugger as it will leave the break point information in
488// DebugInfo even though the code is patched back to the non break point state.
489void BreakLocationIterator::ClearAllDebugBreak() {
490 while (!Done()) {
491 ClearDebugBreak();
492 Next();
493 }
494}
495
496
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000497bool BreakLocationIterator::RinfoDone() const {
498 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
499 return reloc_iterator_->done();
500}
501
502
503void BreakLocationIterator::RinfoNext() {
504 reloc_iterator_->next();
505 reloc_iterator_original_->next();
506#ifdef DEBUG
507 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
508 if (!reloc_iterator_->done()) {
509 ASSERT(rmode() == original_rmode());
510 }
511#endif
512}
513
514
515bool Debug::has_break_points_ = false;
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000516ScriptCache* Debug::script_cache_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000517DebugInfoListNode* Debug::debug_info_list_ = NULL;
518
519
520// Threading support.
521void Debug::ThreadInit() {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000522 thread_local_.break_count_ = 0;
523 thread_local_.break_id_ = 0;
524 thread_local_.break_frame_id_ = StackFrame::NO_ID;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000525 thread_local_.last_step_action_ = StepNone;
ager@chromium.org236ad962008-09-25 09:45:57 +0000526 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000527 thread_local_.step_count_ = 0;
528 thread_local_.last_fp_ = 0;
529 thread_local_.step_into_fp_ = 0;
ager@chromium.orga1645e22009-09-09 19:27:10 +0000530 thread_local_.step_out_fp_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000531 thread_local_.after_break_target_ = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000532 thread_local_.debugger_entry_ = NULL;
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000533 thread_local_.pending_interrupts_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000534}
535
536
537JSCallerSavedBuffer Debug::registers_;
538Debug::ThreadLocal Debug::thread_local_;
539
540
541char* Debug::ArchiveDebug(char* storage) {
542 char* to = storage;
543 memcpy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
544 to += sizeof(ThreadLocal);
545 memcpy(to, reinterpret_cast<char*>(&registers_), sizeof(registers_));
546 ThreadInit();
547 ASSERT(to <= storage + ArchiveSpacePerThread());
548 return storage + ArchiveSpacePerThread();
549}
550
551
552char* Debug::RestoreDebug(char* storage) {
553 char* from = storage;
554 memcpy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
555 from += sizeof(ThreadLocal);
556 memcpy(reinterpret_cast<char*>(&registers_), from, sizeof(registers_));
557 ASSERT(from <= storage + ArchiveSpacePerThread());
558 return storage + ArchiveSpacePerThread();
559}
560
561
562int Debug::ArchiveSpacePerThread() {
563 return sizeof(ThreadLocal) + sizeof(registers_);
564}
565
566
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000567// Default break enabled.
568bool Debug::disable_break_ = false;
569
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000570// Default call debugger on uncaught exception.
571bool Debug::break_on_exception_ = false;
572bool Debug::break_on_uncaught_exception_ = true;
573
574Handle<Context> Debug::debug_context_ = Handle<Context>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000575Code* Debug::debug_break_return_ = NULL;
576
577
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000578void ScriptCache::Add(Handle<Script> script) {
579 // Create an entry in the hash map for the script.
580 int id = Smi::cast(script->id())->value();
581 HashMap::Entry* entry =
582 HashMap::Lookup(reinterpret_cast<void*>(id), Hash(id), true);
583 if (entry->value != NULL) {
584 ASSERT(*script == *reinterpret_cast<Script**>(entry->value));
585 return;
586 }
587
588 // Globalize the script object, make it weak and use the location of the
589 // global handle as the value in the hash map.
590 Handle<Script> script_ =
591 Handle<Script>::cast((GlobalHandles::Create(*script)));
592 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(script_.location()),
593 this, ScriptCache::HandleWeakScript);
594 entry->value = script_.location();
595}
596
597
598Handle<FixedArray> ScriptCache::GetScripts() {
599 Handle<FixedArray> instances = Factory::NewFixedArray(occupancy());
600 int count = 0;
601 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
602 ASSERT(entry->value != NULL);
603 if (entry->value != NULL) {
604 instances->set(count, *reinterpret_cast<Script**>(entry->value));
605 count++;
606 }
607 }
608 return instances;
609}
610
611
612void ScriptCache::ProcessCollectedScripts() {
613 for (int i = 0; i < collected_scripts_.length(); i++) {
614 Debugger::OnScriptCollected(collected_scripts_[i]);
615 }
616 collected_scripts_.Clear();
617}
618
619
620void ScriptCache::Clear() {
621 // Iterate the script cache to get rid of all the weak handles.
622 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
623 ASSERT(entry != NULL);
624 Object** location = reinterpret_cast<Object**>(entry->value);
625 ASSERT((*location)->IsScript());
626 GlobalHandles::ClearWeakness(location);
627 GlobalHandles::Destroy(location);
628 }
629 // Clear the content of the hash map.
630 HashMap::Clear();
631}
632
633
634void ScriptCache::HandleWeakScript(v8::Persistent<v8::Value> obj, void* data) {
635 ScriptCache* script_cache = reinterpret_cast<ScriptCache*>(data);
636 // Find the location of the global handle.
637 Script** location =
638 reinterpret_cast<Script**>(Utils::OpenHandle(*obj).location());
639 ASSERT((*location)->IsScript());
640
641 // Remove the entry from the cache.
642 int id = Smi::cast((*location)->id())->value();
643 script_cache->Remove(reinterpret_cast<void*>(id), Hash(id));
644 script_cache->collected_scripts_.Add(id);
645
646 // Clear the weak handle.
647 obj.Dispose();
648 obj.Clear();
649}
650
651
652void Debug::Setup(bool create_heap_objects) {
653 ThreadInit();
654 if (create_heap_objects) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000655 // Get code to handle debug break on return.
656 debug_break_return_ =
657 Builtins::builtin(Builtins::Return_DebugBreak);
658 ASSERT(debug_break_return_->IsCode());
659 }
660}
661
662
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000663void Debug::HandleWeakDebugInfo(v8::Persistent<v8::Value> obj, void* data) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000664 DebugInfoListNode* node = reinterpret_cast<DebugInfoListNode*>(data);
665 RemoveDebugInfo(node->debug_info());
666#ifdef DEBUG
667 node = Debug::debug_info_list_;
668 while (node != NULL) {
669 ASSERT(node != reinterpret_cast<DebugInfoListNode*>(data));
670 node = node->next();
671 }
672#endif
673}
674
675
676DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
677 // Globalize the request debug info object and make it weak.
678 debug_info_ = Handle<DebugInfo>::cast((GlobalHandles::Create(debug_info)));
679 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(debug_info_.location()),
680 this, Debug::HandleWeakDebugInfo);
681}
682
683
684DebugInfoListNode::~DebugInfoListNode() {
685 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_.location()));
686}
687
688
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000689bool Debug::CompileDebuggerScript(int index) {
690 HandleScope scope;
691
kasper.lund44510672008-07-25 07:37:58 +0000692 // Bail out if the index is invalid.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000693 if (index == -1) {
694 return false;
695 }
kasper.lund44510672008-07-25 07:37:58 +0000696
697 // Find source and name for the requested script.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000698 Handle<String> source_code = Bootstrapper::NativesSourceLookup(index);
699 Vector<const char> name = Natives::GetScriptName(index);
700 Handle<String> script_name = Factory::NewStringFromAscii(name);
701
702 // Compile the script.
703 bool allow_natives_syntax = FLAG_allow_natives_syntax;
704 FLAG_allow_natives_syntax = true;
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000705 Handle<SharedFunctionInfo> function_info;
706 function_info = Compiler::Compile(source_code,
707 script_name,
708 0, 0, NULL, NULL,
709 Handle<String>::null(),
710 NATIVES_CODE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000711 FLAG_allow_natives_syntax = allow_natives_syntax;
712
713 // Silently ignore stack overflows during compilation.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000714 if (function_info.is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000715 ASSERT(Top::has_pending_exception());
716 Top::clear_pending_exception();
717 return false;
718 }
719
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000720 // Execute the shared function in the debugger context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000721 Handle<Context> context = Top::global_context();
kasper.lund44510672008-07-25 07:37:58 +0000722 bool caught_exception = false;
723 Handle<JSFunction> function =
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000724 Factory::NewFunctionFromSharedFunctionInfo(function_info, context);
kasper.lund44510672008-07-25 07:37:58 +0000725 Handle<Object> result =
726 Execution::TryCall(function, Handle<Object>(context->global()),
727 0, NULL, &caught_exception);
728
729 // Check for caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000730 if (caught_exception) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000731 Handle<Object> message = MessageHandler::MakeMessageObject(
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000732 "error_loading_debugger", NULL, Vector<Handle<Object> >::empty(),
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000733 Handle<String>());
734 MessageHandler::ReportMessage(NULL, message);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000735 return false;
736 }
737
kasper.lund44510672008-07-25 07:37:58 +0000738 // Mark this script as native and return successfully.
739 Handle<Script> script(Script::cast(function->shared()->script()));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000740 script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000741 return true;
742}
743
744
745bool Debug::Load() {
746 // Return if debugger is already loaded.
kasper.lund212ac232008-07-16 07:07:30 +0000747 if (IsLoaded()) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000748
kasper.lund44510672008-07-25 07:37:58 +0000749 // Bail out if we're already in the process of compiling the native
750 // JavaScript source code for the debugger.
mads.s.agercbaa0602008-08-14 13:41:48 +0000751 if (Debugger::compiling_natives() || Debugger::is_loading_debugger())
752 return false;
753 Debugger::set_loading_debugger(true);
kasper.lund44510672008-07-25 07:37:58 +0000754
755 // Disable breakpoints and interrupts while compiling and running the
756 // debugger scripts including the context creation code.
757 DisableBreak disable(true);
758 PostponeInterruptsScope postpone;
759
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000760 // Create the debugger context.
761 HandleScope scope;
kasper.lund44510672008-07-25 07:37:58 +0000762 Handle<Context> context =
763 Bootstrapper::CreateEnvironment(Handle<Object>::null(),
764 v8::Handle<ObjectTemplate>(),
765 NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000766
kasper.lund44510672008-07-25 07:37:58 +0000767 // Use the debugger context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000768 SaveContext save;
kasper.lund44510672008-07-25 07:37:58 +0000769 Top::set_context(*context);
kasper.lund44510672008-07-25 07:37:58 +0000770
771 // Expose the builtins object in the debugger context.
772 Handle<String> key = Factory::LookupAsciiSymbol("builtins");
773 Handle<GlobalObject> global = Handle<GlobalObject>(context->global());
774 SetProperty(global, key, Handle<Object>(global->builtins()), NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000775
776 // Compile the JavaScript for the debugger in the debugger context.
777 Debugger::set_compiling_natives(true);
kasper.lund44510672008-07-25 07:37:58 +0000778 bool caught_exception =
779 !CompileDebuggerScript(Natives::GetIndex("mirror")) ||
780 !CompileDebuggerScript(Natives::GetIndex("debug"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000781
782 if (FLAG_enable_liveedit) {
783 caught_exception = caught_exception ||
784 !CompileDebuggerScript(Natives::GetIndex("liveedit"));
785 }
786
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000787 Debugger::set_compiling_natives(false);
788
mads.s.agercbaa0602008-08-14 13:41:48 +0000789 // Make sure we mark the debugger as not loading before we might
790 // return.
791 Debugger::set_loading_debugger(false);
792
kasper.lund44510672008-07-25 07:37:58 +0000793 // Check for caught exceptions.
794 if (caught_exception) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000795
796 // Debugger loaded.
kasper.lund44510672008-07-25 07:37:58 +0000797 debug_context_ = Handle<Context>::cast(GlobalHandles::Create(*context));
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000798
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000799 return true;
800}
801
802
803void Debug::Unload() {
804 // Return debugger is not loaded.
805 if (!IsLoaded()) {
806 return;
807 }
808
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000809 // Clear the script cache.
810 DestroyScriptCache();
811
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000812 // Clear debugger context global handle.
813 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_context_.location()));
814 debug_context_ = Handle<Context>();
815}
816
817
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000818// Set the flag indicating that preemption happened during debugging.
819void Debug::PreemptionWhileInDebugger() {
820 ASSERT(InDebugger());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +0000821 Debug::set_interrupts_pending(PREEMPT);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000822}
823
824
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000825void Debug::Iterate(ObjectVisitor* v) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000826 v->VisitPointer(BitCast<Object**, Code**>(&(debug_break_return_)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000827}
828
829
830Object* Debug::Break(Arguments args) {
831 HandleScope scope;
mads.s.ager31e71382008-08-13 09:32:07 +0000832 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000833
ager@chromium.org357bf652010-04-12 11:30:10 +0000834 thread_local_.frames_are_dropped_ = false;
835
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000836 // Get the top-most JavaScript frame.
837 JavaScriptFrameIterator it;
838 JavaScriptFrame* frame = it.frame();
839
840 // Just continue if breaks are disabled or debugger cannot be loaded.
841 if (disable_break() || !Load()) {
842 SetAfterBreakTarget(frame);
mads.s.ager31e71382008-08-13 09:32:07 +0000843 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000844 }
845
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000846 // Enter the debugger.
847 EnterDebugger debugger;
848 if (debugger.FailedToEnter()) {
849 return Heap::undefined_value();
850 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000851
kasper.lund44510672008-07-25 07:37:58 +0000852 // Postpone interrupt during breakpoint processing.
853 PostponeInterruptsScope postpone;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000854
855 // Get the debug info (create it if it does not exist).
856 Handle<SharedFunctionInfo> shared =
857 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
858 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
859
860 // Find the break point where execution has stopped.
861 BreakLocationIterator break_location_iterator(debug_info,
862 ALL_BREAK_LOCATIONS);
863 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
864
865 // Check whether step next reached a new statement.
866 if (!StepNextContinue(&break_location_iterator, frame)) {
867 // Decrease steps left if performing multiple steps.
868 if (thread_local_.step_count_ > 0) {
869 thread_local_.step_count_--;
870 }
871 }
872
873 // If there is one or more real break points check whether any of these are
874 // triggered.
875 Handle<Object> break_points_hit(Heap::undefined_value());
876 if (break_location_iterator.HasBreakPoint()) {
877 Handle<Object> break_point_objects =
878 Handle<Object>(break_location_iterator.BreakPointObjects());
879 break_points_hit = CheckBreakPoints(break_point_objects);
880 }
881
ager@chromium.orga1645e22009-09-09 19:27:10 +0000882 // If step out is active skip everything until the frame where we need to step
883 // out to is reached, unless real breakpoint is hit.
884 if (Debug::StepOutActive() && frame->fp() != Debug::step_out_fp() &&
885 break_points_hit->IsUndefined() ) {
886 // Step count should always be 0 for StepOut.
887 ASSERT(thread_local_.step_count_ == 0);
888 } else if (!break_points_hit->IsUndefined() ||
889 (thread_local_.last_step_action_ != StepNone &&
890 thread_local_.step_count_ == 0)) {
891 // Notify debugger if a real break point is triggered or if performing
892 // single stepping with no more steps to perform. Otherwise do another step.
893
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000894 // Clear all current stepping setup.
895 ClearStepping();
896
897 // Notify the debug event listeners.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000898 Debugger::OnDebugBreak(break_points_hit, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000899 } else if (thread_local_.last_step_action_ != StepNone) {
900 // Hold on to last step action as it is cleared by the call to
901 // ClearStepping.
902 StepAction step_action = thread_local_.last_step_action_;
903 int step_count = thread_local_.step_count_;
904
905 // Clear all current stepping setup.
906 ClearStepping();
907
908 // Set up for the remaining steps.
909 PrepareStep(step_action, step_count);
910 }
911
ager@chromium.org357bf652010-04-12 11:30:10 +0000912 if (thread_local_.frames_are_dropped_) {
913 // We must have been calling IC stub. Do not return there anymore.
914 Code* plain_return = Builtins::builtin(Builtins::PlainReturn_LiveEdit);
915 thread_local_.after_break_target_ = plain_return->entry();
916 } else {
917 SetAfterBreakTarget(frame);
918 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000919
mads.s.ager31e71382008-08-13 09:32:07 +0000920 return Heap::undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000921}
922
923
924// Check the break point objects for whether one or more are actually
925// triggered. This function returns a JSArray with the break point objects
926// which is triggered.
927Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) {
928 int break_points_hit_count = 0;
929 Handle<JSArray> break_points_hit = Factory::NewJSArray(1);
930
v8.team.kasperl727e9952008-09-02 14:56:44 +0000931 // If there are multiple break points they are in a FixedArray.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000932 ASSERT(!break_point_objects->IsUndefined());
933 if (break_point_objects->IsFixedArray()) {
934 Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
935 for (int i = 0; i < array->length(); i++) {
936 Handle<Object> o(array->get(i));
937 if (CheckBreakPoint(o)) {
938 break_points_hit->SetElement(break_points_hit_count++, *o);
939 }
940 }
941 } else {
942 if (CheckBreakPoint(break_point_objects)) {
943 break_points_hit->SetElement(break_points_hit_count++,
944 *break_point_objects);
945 }
946 }
947
948 // Return undefined if no break points where triggered.
949 if (break_points_hit_count == 0) {
950 return Factory::undefined_value();
951 }
952 return break_points_hit;
953}
954
955
956// Check whether a single break point object is triggered.
957bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000958 HandleScope scope;
959
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000960 // Ignore check if break point object is not a JSObject.
961 if (!break_point_object->IsJSObject()) return true;
962
963 // Get the function CheckBreakPoint (defined in debug.js).
964 Handle<JSFunction> check_break_point =
965 Handle<JSFunction>(JSFunction::cast(
966 debug_context()->global()->GetProperty(
967 *Factory::LookupAsciiSymbol("IsBreakPointTriggered"))));
968
969 // Get the break id as an object.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000970 Handle<Object> break_id = Factory::NewNumberFromInt(Debug::break_id());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000971
972 // Call HandleBreakPointx.
973 bool caught_exception = false;
974 const int argc = 2;
975 Object** argv[argc] = {
976 break_id.location(),
977 reinterpret_cast<Object**>(break_point_object.location())
978 };
979 Handle<Object> result = Execution::TryCall(check_break_point,
980 Top::builtins(), argc, argv,
981 &caught_exception);
982
983 // If exception or non boolean result handle as not triggered
984 if (caught_exception || !result->IsBoolean()) {
985 return false;
986 }
987
988 // Return whether the break point is triggered.
989 return *result == Heap::true_value();
990}
991
992
993// Check whether the function has debug information.
994bool Debug::HasDebugInfo(Handle<SharedFunctionInfo> shared) {
995 return !shared->debug_info()->IsUndefined();
996}
997
998
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000999// Return the debug info for this function. EnsureDebugInfo must be called
1000// prior to ensure the debug info has been generated for shared.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001001Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001002 ASSERT(HasDebugInfo(shared));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003 return Handle<DebugInfo>(DebugInfo::cast(shared->debug_info()));
1004}
1005
1006
1007void Debug::SetBreakPoint(Handle<SharedFunctionInfo> shared,
1008 int source_position,
1009 Handle<Object> break_point_object) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00001010 HandleScope scope;
1011
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001012 if (!EnsureDebugInfo(shared)) {
1013 // Return if retrieving debug info failed.
1014 return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001015 }
1016
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001017 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001018 // Source positions starts with zero.
1019 ASSERT(source_position >= 0);
1020
1021 // Find the break point and change it.
1022 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
1023 it.FindBreakLocationFromPosition(source_position);
1024 it.SetBreakPoint(break_point_object);
1025
1026 // At least one active break point now.
1027 ASSERT(debug_info->GetBreakPointCount() > 0);
1028}
1029
1030
1031void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00001032 HandleScope scope;
1033
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001034 DebugInfoListNode* node = debug_info_list_;
1035 while (node != NULL) {
1036 Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(),
1037 break_point_object);
1038 if (!result->IsUndefined()) {
1039 // Get information in the break point.
1040 BreakPointInfo* break_point_info = BreakPointInfo::cast(result);
1041 Handle<DebugInfo> debug_info = node->debug_info();
1042 Handle<SharedFunctionInfo> shared(debug_info->shared());
1043 int source_position = break_point_info->statement_position()->value();
1044
1045 // Source positions starts with zero.
1046 ASSERT(source_position >= 0);
1047
1048 // Find the break point and clear it.
1049 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
1050 it.FindBreakLocationFromPosition(source_position);
1051 it.ClearBreakPoint(break_point_object);
1052
1053 // If there are no more break points left remove the debug info for this
1054 // function.
1055 if (debug_info->GetBreakPointCount() == 0) {
1056 RemoveDebugInfo(debug_info);
1057 }
1058
1059 return;
1060 }
1061 node = node->next();
1062 }
1063}
1064
1065
ager@chromium.org381abbb2009-02-25 13:23:22 +00001066void Debug::ClearAllBreakPoints() {
1067 DebugInfoListNode* node = debug_info_list_;
1068 while (node != NULL) {
1069 // Remove all debug break code.
1070 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1071 it.ClearAllDebugBreak();
1072 node = node->next();
1073 }
1074
1075 // Remove all debug info.
1076 while (debug_info_list_ != NULL) {
1077 RemoveDebugInfo(debug_info_list_->debug_info());
1078 }
1079}
1080
1081
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001082void Debug::FloodWithOneShot(Handle<SharedFunctionInfo> shared) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001083 // Make sure the function has setup the debug info.
1084 if (!EnsureDebugInfo(shared)) {
1085 // Return if we failed to retrieve the debug info.
1086 return;
1087 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001088
1089 // Flood the function with break points.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001090 BreakLocationIterator it(GetDebugInfo(shared), ALL_BREAK_LOCATIONS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001091 while (!it.Done()) {
1092 it.SetOneShot();
1093 it.Next();
1094 }
1095}
1096
1097
1098void Debug::FloodHandlerWithOneShot() {
ager@chromium.org8bb60582008-12-11 12:02:20 +00001099 // Iterate through the JavaScript stack looking for handlers.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001100 StackFrame::Id id = break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00001101 if (id == StackFrame::NO_ID) {
1102 // If there is no JavaScript stack don't do anything.
1103 return;
1104 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001105 for (JavaScriptFrameIterator it(id); !it.done(); it.Advance()) {
1106 JavaScriptFrame* frame = it.frame();
1107 if (frame->HasHandler()) {
1108 Handle<SharedFunctionInfo> shared =
1109 Handle<SharedFunctionInfo>(
1110 JSFunction::cast(frame->function())->shared());
1111 // Flood the function with the catch block with break points
1112 FloodWithOneShot(shared);
1113 return;
1114 }
1115 }
1116}
1117
1118
1119void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
1120 if (type == BreakUncaughtException) {
1121 break_on_uncaught_exception_ = enable;
1122 } else {
1123 break_on_exception_ = enable;
1124 }
1125}
1126
1127
1128void Debug::PrepareStep(StepAction step_action, int step_count) {
1129 HandleScope scope;
1130 ASSERT(Debug::InDebugger());
1131
1132 // Remember this step action and count.
1133 thread_local_.last_step_action_ = step_action;
ager@chromium.orga1645e22009-09-09 19:27:10 +00001134 if (step_action == StepOut) {
1135 // For step out target frame will be found on the stack so there is no need
1136 // to set step counter for it. It's expected to always be 0 for StepOut.
1137 thread_local_.step_count_ = 0;
1138 } else {
1139 thread_local_.step_count_ = step_count;
1140 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001141
1142 // Get the frame where the execution has stopped and skip the debug frame if
1143 // any. The debug frame will only be present if execution was stopped due to
1144 // hitting a break point. In other situations (e.g. unhandled exception) the
1145 // debug frame is not present.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001146 StackFrame::Id id = break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00001147 if (id == StackFrame::NO_ID) {
1148 // If there is no JavaScript stack don't do anything.
1149 return;
1150 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001151 JavaScriptFrameIterator frames_it(id);
1152 JavaScriptFrame* frame = frames_it.frame();
1153
1154 // First of all ensure there is one-shot break points in the top handler
1155 // if any.
1156 FloodHandlerWithOneShot();
1157
1158 // If the function on the top frame is unresolved perform step out. This will
1159 // be the case when calling unknown functions and having the debugger stopped
1160 // in an unhandled exception.
1161 if (!frame->function()->IsJSFunction()) {
1162 // Step out: Find the calling JavaScript frame and flood it with
1163 // breakpoints.
1164 frames_it.Advance();
1165 // Fill the function to return to with one-shot break points.
1166 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
1167 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1168 return;
1169 }
1170
1171 // Get the debug info (create it if it does not exist).
1172 Handle<SharedFunctionInfo> shared =
1173 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001174 if (!EnsureDebugInfo(shared)) {
1175 // Return if ensuring debug info failed.
1176 return;
1177 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001178 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1179
1180 // Find the break location where execution has stopped.
1181 BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS);
1182 it.FindBreakLocationFromAddress(frame->pc());
1183
1184 // Compute whether or not the target is a call target.
1185 bool is_call_target = false;
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001186 bool is_load_or_store = false;
1187 bool is_inline_cache_stub = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +00001188 Handle<Code> call_function_stub;
ager@chromium.org236ad962008-09-25 09:45:57 +00001189 if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001190 Address target = it.rinfo()->target_address();
ager@chromium.org8bb60582008-12-11 12:02:20 +00001191 Code* code = Code::GetCodeFromTargetAddress(target);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001192 if (code->is_call_stub() || code->is_keyed_call_stub()) {
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001193 is_call_target = true;
1194 }
1195 if (code->is_inline_cache_stub()) {
1196 is_inline_cache_stub = true;
1197 is_load_or_store = !is_call_target;
1198 }
ager@chromium.orga1645e22009-09-09 19:27:10 +00001199
1200 // Check if target code is CallFunction stub.
1201 Code* maybe_call_function_stub = code;
1202 // If there is a breakpoint at this line look at the original code to
1203 // check if it is a CallFunction stub.
1204 if (it.IsDebugBreak()) {
1205 Address original_target = it.original_rinfo()->target_address();
1206 maybe_call_function_stub =
1207 Code::GetCodeFromTargetAddress(original_target);
1208 }
1209 if (maybe_call_function_stub->kind() == Code::STUB &&
1210 maybe_call_function_stub->major_key() == CodeStub::CallFunction) {
1211 // Save reference to the code as we may need it to find out arguments
1212 // count for 'step in' later.
1213 call_function_stub = Handle<Code>(maybe_call_function_stub);
1214 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 }
1216
v8.team.kasperl727e9952008-09-02 14:56:44 +00001217 // If this is the last break code target step out is the only possibility.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001218 if (it.IsExit() || step_action == StepOut) {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001219 if (step_action == StepOut) {
1220 // Skip step_count frames starting with the current one.
1221 while (step_count-- > 0 && !frames_it.done()) {
1222 frames_it.Advance();
1223 }
1224 } else {
1225 ASSERT(it.IsExit());
1226 frames_it.Advance();
1227 }
1228 // Skip builtin functions on the stack.
1229 while (!frames_it.done() &&
1230 JSFunction::cast(frames_it.frame()->function())->IsBuiltin()) {
1231 frames_it.Advance();
1232 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001233 // Step out: If there is a JavaScript caller frame, we need to
1234 // flood it with breakpoints.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001235 if (!frames_it.done()) {
1236 // Fill the function to return to with one-shot break points.
1237 JSFunction* function = JSFunction::cast(frames_it.frame()->function());
1238 FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
ager@chromium.orga1645e22009-09-09 19:27:10 +00001239 // Set target frame pointer.
1240 ActivateStepOut(frames_it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001241 }
ager@chromium.orga1645e22009-09-09 19:27:10 +00001242 } else if (!(is_inline_cache_stub || RelocInfo::IsConstructCall(it.rmode()) ||
1243 !call_function_stub.is_null())
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001244 || step_action == StepNext || step_action == StepMin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245 // Step next or step min.
1246
1247 // Fill the current function with one-shot break points.
1248 FloodWithOneShot(shared);
1249
1250 // Remember source position and frame to handle step next.
1251 thread_local_.last_statement_position_ =
1252 debug_info->code()->SourceStatementPosition(frame->pc());
1253 thread_local_.last_fp_ = frame->fp();
1254 } else {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001255 // If it's CallFunction stub ensure target function is compiled and flood
1256 // it with one shot breakpoints.
1257 if (!call_function_stub.is_null()) {
1258 // Find out number of arguments from the stub minor key.
1259 // Reverse lookup required as the minor key cannot be retrieved
1260 // from the code object.
1261 Handle<Object> obj(
1262 Heap::code_stubs()->SlowReverseLookup(*call_function_stub));
1263 ASSERT(*obj != Heap::undefined_value());
1264 ASSERT(obj->IsSmi());
1265 // Get the STUB key and extract major and minor key.
1266 uint32_t key = Smi::cast(*obj)->value();
1267 // Argc in the stub is the number of arguments passed - not the
1268 // expected arguments of the called function.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001269 int call_function_arg_count =
1270 CallFunctionStub::ExtractArgcFromMinorKey(
1271 CodeStub::MinorKeyFromKey(key));
ager@chromium.orga1645e22009-09-09 19:27:10 +00001272 ASSERT(call_function_stub->major_key() ==
1273 CodeStub::MajorKeyFromKey(key));
1274
1275 // Find target function on the expression stack.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001276 // Expression stack looks like this (top to bottom):
ager@chromium.orga1645e22009-09-09 19:27:10 +00001277 // argN
1278 // ...
1279 // arg0
1280 // Receiver
1281 // Function to call
1282 int expressions_count = frame->ComputeExpressionsCount();
1283 ASSERT(expressions_count - 2 - call_function_arg_count >= 0);
1284 Object* fun = frame->GetExpression(
1285 expressions_count - 2 - call_function_arg_count);
1286 if (fun->IsJSFunction()) {
1287 Handle<JSFunction> js_function(JSFunction::cast(fun));
1288 // Don't step into builtins.
1289 if (!js_function->IsBuiltin()) {
1290 // It will also compile target function if it's not compiled yet.
1291 FloodWithOneShot(Handle<SharedFunctionInfo>(js_function->shared()));
1292 }
1293 }
1294 }
1295
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001296 // Fill the current function with one-shot break points even for step in on
1297 // a call target as the function called might be a native function for
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001298 // which step in will not stop. It also prepares for stepping in
1299 // getters/setters.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300 FloodWithOneShot(shared);
1301
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001302 if (is_load_or_store) {
1303 // Remember source position and frame to handle step in getter/setter. If
1304 // there is a custom getter/setter it will be handled in
1305 // Object::Get/SetPropertyWithCallback, otherwise the step action will be
1306 // propagated on the next Debug::Break.
1307 thread_local_.last_statement_position_ =
1308 debug_info->code()->SourceStatementPosition(frame->pc());
1309 thread_local_.last_fp_ = frame->fp();
1310 }
1311
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312 // Step in or Step in min
1313 it.PrepareStepIn();
1314 ActivateStepIn(frame);
1315 }
1316}
1317
1318
1319// Check whether the current debug break should be reported to the debugger. It
1320// is used to have step next and step in only report break back to the debugger
1321// if on a different frame or in a different statement. In some situations
1322// there will be several break points in the same statement when the code is
v8.team.kasperl727e9952008-09-02 14:56:44 +00001323// flooded with one-shot break points. This function helps to perform several
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001324// steps before reporting break back to the debugger.
1325bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
1326 JavaScriptFrame* frame) {
1327 // If the step last action was step next or step in make sure that a new
1328 // statement is hit.
1329 if (thread_local_.last_step_action_ == StepNext ||
1330 thread_local_.last_step_action_ == StepIn) {
1331 // Never continue if returning from function.
1332 if (break_location_iterator->IsExit()) return false;
1333
1334 // Continue if we are still on the same frame and in the same statement.
1335 int current_statement_position =
1336 break_location_iterator->code()->SourceStatementPosition(frame->pc());
1337 return thread_local_.last_fp_ == frame->fp() &&
ager@chromium.org236ad962008-09-25 09:45:57 +00001338 thread_local_.last_statement_position_ == current_statement_position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001339 }
1340
1341 // No step next action - don't continue.
1342 return false;
1343}
1344
1345
1346// Check whether the code object at the specified address is a debug break code
1347// object.
1348bool Debug::IsDebugBreak(Address addr) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00001349 Code* code = Code::GetCodeFromTargetAddress(addr);
kasper.lund7276f142008-07-30 08:49:36 +00001350 return code->ic_state() == DEBUG_BREAK;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351}
1352
1353
1354// Check whether a code stub with the specified major key is a possible break
1355// point location when looking for source break locations.
1356bool Debug::IsSourceBreakStub(Code* code) {
1357 CodeStub::Major major_key = code->major_key();
1358 return major_key == CodeStub::CallFunction;
1359}
1360
1361
1362// Check whether a code stub with the specified major key is a possible break
1363// location.
1364bool Debug::IsBreakStub(Code* code) {
1365 CodeStub::Major major_key = code->major_key();
1366 return major_key == CodeStub::CallFunction ||
1367 major_key == CodeStub::StackCheck;
1368}
1369
1370
1371// Find the builtin to use for invoking the debug break
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001372Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001373 // Find the builtin debug break function matching the calling convention
1374 // used by the call site.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001375 if (code->is_inline_cache_stub()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001376 switch (code->kind()) {
1377 case Code::CALL_IC:
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001378 case Code::KEYED_CALL_IC:
1379 return ComputeCallDebugBreak(code->arguments_count(), code->kind());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001380
1381 case Code::LOAD_IC:
1382 return Handle<Code>(Builtins::builtin(Builtins::LoadIC_DebugBreak));
1383
1384 case Code::STORE_IC:
1385 return Handle<Code>(Builtins::builtin(Builtins::StoreIC_DebugBreak));
1386
1387 case Code::KEYED_LOAD_IC:
1388 return Handle<Code>(
1389 Builtins::builtin(Builtins::KeyedLoadIC_DebugBreak));
1390
1391 case Code::KEYED_STORE_IC:
1392 return Handle<Code>(
1393 Builtins::builtin(Builtins::KeyedStoreIC_DebugBreak));
1394
1395 default:
1396 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001397 }
1398 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001399 if (RelocInfo::IsConstructCall(mode)) {
1400 Handle<Code> result =
1401 Handle<Code>(Builtins::builtin(Builtins::ConstructCall_DebugBreak));
1402 return result;
1403 }
1404 if (code->kind() == Code::STUB) {
1405 ASSERT(code->major_key() == CodeStub::CallFunction ||
1406 code->major_key() == CodeStub::StackCheck);
1407 Handle<Code> result =
1408 Handle<Code>(Builtins::builtin(Builtins::StubNoRegisters_DebugBreak));
1409 return result;
1410 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001411
1412 UNREACHABLE();
1413 return Handle<Code>::null();
1414}
1415
1416
1417// Simple function for returning the source positions for active break points.
1418Handle<Object> Debug::GetSourceBreakLocations(
1419 Handle<SharedFunctionInfo> shared) {
1420 if (!HasDebugInfo(shared)) return Handle<Object>(Heap::undefined_value());
1421 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1422 if (debug_info->GetBreakPointCount() == 0) {
1423 return Handle<Object>(Heap::undefined_value());
1424 }
1425 Handle<FixedArray> locations =
1426 Factory::NewFixedArray(debug_info->GetBreakPointCount());
1427 int count = 0;
1428 for (int i = 0; i < debug_info->break_points()->length(); i++) {
1429 if (!debug_info->break_points()->get(i)->IsUndefined()) {
1430 BreakPointInfo* break_point_info =
1431 BreakPointInfo::cast(debug_info->break_points()->get(i));
1432 if (break_point_info->GetBreakPointCount() > 0) {
1433 locations->set(count++, break_point_info->statement_position());
1434 }
1435 }
1436 }
1437 return locations;
1438}
1439
1440
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001441void Debug::NewBreak(StackFrame::Id break_frame_id) {
1442 thread_local_.break_frame_id_ = break_frame_id;
1443 thread_local_.break_id_ = ++thread_local_.break_count_;
1444}
1445
1446
1447void Debug::SetBreak(StackFrame::Id break_frame_id, int break_id) {
1448 thread_local_.break_frame_id_ = break_frame_id;
1449 thread_local_.break_id_ = break_id;
1450}
1451
1452
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001453// Handle stepping into a function.
1454void Debug::HandleStepIn(Handle<JSFunction> function,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001455 Handle<Object> holder,
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001456 Address fp,
1457 bool is_constructor) {
1458 // If the frame pointer is not supplied by the caller find it.
1459 if (fp == 0) {
1460 StackFrameIterator it;
1461 it.Advance();
1462 // For constructor functions skip another frame.
1463 if (is_constructor) {
1464 ASSERT(it.frame()->is_construct());
1465 it.Advance();
1466 }
1467 fp = it.frame()->fp();
1468 }
1469
1470 // Flood the function with one-shot break points if it is called from where
1471 // step into was requested.
1472 if (fp == Debug::step_in_fp()) {
1473 // Don't allow step into functions in the native context.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001474 if (!function->IsBuiltin()) {
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001475 if (function->shared()->code() ==
1476 Builtins::builtin(Builtins::FunctionApply) ||
1477 function->shared()->code() ==
1478 Builtins::builtin(Builtins::FunctionCall)) {
1479 // Handle function.apply and function.call separately to flood the
1480 // function to be called and not the code for Builtins::FunctionApply or
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001481 // Builtins::FunctionCall. The receiver of call/apply is the target
1482 // function.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00001483 if (!holder.is_null() && holder->IsJSFunction() &&
1484 !JSFunction::cast(*holder)->IsBuiltin()) {
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001485 Handle<SharedFunctionInfo> shared_info(
1486 JSFunction::cast(*holder)->shared());
1487 Debug::FloodWithOneShot(shared_info);
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001488 }
1489 } else {
1490 Debug::FloodWithOneShot(Handle<SharedFunctionInfo>(function->shared()));
1491 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001492 }
1493 }
1494}
1495
1496
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001497void Debug::ClearStepping() {
1498 // Clear the various stepping setup.
1499 ClearOneShot();
1500 ClearStepIn();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001501 ClearStepOut();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502 ClearStepNext();
1503
1504 // Clear multiple step counter.
1505 thread_local_.step_count_ = 0;
1506}
1507
1508// Clears all the one-shot break points that are currently set. Normally this
1509// function is called each time a break point is hit as one shot break points
1510// are used to support stepping.
1511void Debug::ClearOneShot() {
1512 // The current implementation just runs through all the breakpoints. When the
v8.team.kasperl727e9952008-09-02 14:56:44 +00001513 // last break point for a function is removed that function is automatically
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514 // removed from the list.
1515
1516 DebugInfoListNode* node = debug_info_list_;
1517 while (node != NULL) {
1518 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1519 while (!it.Done()) {
1520 it.ClearOneShot();
1521 it.Next();
1522 }
1523 node = node->next();
1524 }
1525}
1526
1527
1528void Debug::ActivateStepIn(StackFrame* frame) {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001529 ASSERT(!StepOutActive());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001530 thread_local_.step_into_fp_ = frame->fp();
1531}
1532
1533
1534void Debug::ClearStepIn() {
1535 thread_local_.step_into_fp_ = 0;
1536}
1537
1538
ager@chromium.orga1645e22009-09-09 19:27:10 +00001539void Debug::ActivateStepOut(StackFrame* frame) {
1540 ASSERT(!StepInActive());
1541 thread_local_.step_out_fp_ = frame->fp();
1542}
1543
1544
1545void Debug::ClearStepOut() {
1546 thread_local_.step_out_fp_ = 0;
1547}
1548
1549
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001550void Debug::ClearStepNext() {
1551 thread_local_.last_step_action_ = StepNone;
ager@chromium.org236ad962008-09-25 09:45:57 +00001552 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001553 thread_local_.last_fp_ = 0;
1554}
1555
1556
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001557// Ensures the debug information is present for shared.
1558bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) {
1559 // Return if we already have the debug info for shared.
1560 if (HasDebugInfo(shared)) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001561
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001562 // Ensure shared in compiled. Return false if this failed.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001563 if (!EnsureCompiled(shared, CLEAR_EXCEPTION)) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564
1565 // Create the debug info object.
v8.team.kasperl727e9952008-09-02 14:56:44 +00001566 Handle<DebugInfo> debug_info = Factory::NewDebugInfo(shared);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001567
1568 // Add debug info to the list.
1569 DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
1570 node->set_next(debug_info_list_);
1571 debug_info_list_ = node;
1572
1573 // Now there is at least one break point.
1574 has_break_points_ = true;
1575
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001576 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001577}
1578
1579
1580void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
1581 ASSERT(debug_info_list_ != NULL);
1582 // Run through the debug info objects to find this one and remove it.
1583 DebugInfoListNode* prev = NULL;
1584 DebugInfoListNode* current = debug_info_list_;
1585 while (current != NULL) {
1586 if (*current->debug_info() == *debug_info) {
1587 // Unlink from list. If prev is NULL we are looking at the first element.
1588 if (prev == NULL) {
1589 debug_info_list_ = current->next();
1590 } else {
1591 prev->set_next(current->next());
1592 }
1593 current->debug_info()->shared()->set_debug_info(Heap::undefined_value());
1594 delete current;
1595
1596 // If there are no more debug info objects there are not more break
1597 // points.
1598 has_break_points_ = debug_info_list_ != NULL;
1599
1600 return;
1601 }
1602 // Move to next in list.
1603 prev = current;
1604 current = current->next();
1605 }
1606 UNREACHABLE();
1607}
1608
1609
1610void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00001611 HandleScope scope;
1612
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613 // Get the executing function in which the debug break occurred.
1614 Handle<SharedFunctionInfo> shared =
1615 Handle<SharedFunctionInfo>(JSFunction::cast(frame->function())->shared());
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001616 if (!EnsureDebugInfo(shared)) {
1617 // Return if we failed to retrieve the debug info.
1618 return;
1619 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001620 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1621 Handle<Code> code(debug_info->code());
1622 Handle<Code> original_code(debug_info->original_code());
1623#ifdef DEBUG
1624 // Get the code which is actually executing.
kasperl@chromium.org061ef742009-02-27 12:16:20 +00001625 Handle<Code> frame_code(frame->code());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001626 ASSERT(frame_code.is_identical_to(code));
1627#endif
1628
1629 // Find the call address in the running code. This address holds the call to
1630 // either a DebugBreakXXX or to the debug break return entry code if the
1631 // break point is still active after processing the break point.
ager@chromium.org4af710e2009-09-15 12:20:11 +00001632 Address addr = frame->pc() - Assembler::kCallTargetAddressOffset;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001633
1634 // Check if the location is at JS exit.
ager@chromium.orga1645e22009-09-09 19:27:10 +00001635 bool at_js_return = false;
1636 bool break_at_js_return_active = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001637 RelocIterator it(debug_info->code());
1638 while (!it.done()) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001639 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001640 at_js_return = (it.rinfo()->pc() ==
1641 addr - Assembler::kPatchReturnSequenceAddressOffset);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001642 break_at_js_return_active = it.rinfo()->IsPatchedReturnSequence();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001643 }
1644 it.next();
1645 }
1646
1647 // Handle the jump to continue execution after break point depending on the
1648 // break location.
ager@chromium.orga1645e22009-09-09 19:27:10 +00001649 if (at_js_return) {
1650 // If the break point as return is still active jump to the corresponding
1651 // place in the original code. If not the break point was removed during
1652 // break point processing.
1653 if (break_at_js_return_active) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001654 addr += original_code->instruction_start() - code->instruction_start();
1655 }
1656
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001657 // Move back to where the call instruction sequence started.
1658 thread_local_.after_break_target_ =
1659 addr - Assembler::kPatchReturnSequenceAddressOffset;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001660 } else {
1661 // Check if there still is a debug break call at the target address. If the
1662 // break point has been removed it will have disappeared. If it have
1663 // disappeared don't try to look in the original code as the running code
1664 // will have the right address. This takes care of the case where the last
1665 // break point is removed from the function and therefore no "original code"
1666 // is available. If the debug break call is still there find the address in
1667 // the original code.
1668 if (IsDebugBreak(Assembler::target_address_at(addr))) {
1669 // If the break point is still there find the call address which was
1670 // overwritten in the original code by the call to DebugBreakXXX.
1671
1672 // Find the corresponding address in the original code.
1673 addr += original_code->instruction_start() - code->instruction_start();
1674 }
1675
1676 // Install jump to the call address in the original code. This will be the
1677 // call which was overwritten by the call to DebugBreakXXX.
1678 thread_local_.after_break_target_ = Assembler::target_address_at(addr);
1679 }
1680}
1681
1682
ager@chromium.org357bf652010-04-12 11:30:10 +00001683void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id) {
1684 thread_local_.frames_are_dropped_ = true;
1685 thread_local_.break_frame_id_ = new_break_frame_id;
1686}
1687
1688
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001689bool Debug::IsDebugGlobal(GlobalObject* global) {
1690 return IsLoaded() && global == Debug::debug_context()->global();
1691}
1692
1693
ager@chromium.org32912102009-01-16 10:38:43 +00001694void Debug::ClearMirrorCache() {
ager@chromium.org381abbb2009-02-25 13:23:22 +00001695 HandleScope scope;
ager@chromium.org32912102009-01-16 10:38:43 +00001696 ASSERT(Top::context() == *Debug::debug_context());
1697
1698 // Clear the mirror cache.
1699 Handle<String> function_name =
1700 Factory::LookupSymbol(CStrVector("ClearMirrorCache"));
1701 Handle<Object> fun(Top::global()->GetProperty(*function_name));
1702 ASSERT(fun->IsJSFunction());
1703 bool caught_exception;
1704 Handle<Object> js_object = Execution::TryCall(
1705 Handle<JSFunction>::cast(fun),
1706 Handle<JSObject>(Debug::debug_context()->global()),
1707 0, NULL, &caught_exception);
1708}
1709
1710
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001711void Debug::CreateScriptCache() {
1712 HandleScope scope;
1713
1714 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
1715 // rid of all the cached script wrappers and the second gets rid of the
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001716 // scripts which are no longer referenced.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001717 Heap::CollectAllGarbage(false);
1718 Heap::CollectAllGarbage(false);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001719
1720 ASSERT(script_cache_ == NULL);
1721 script_cache_ = new ScriptCache();
1722
1723 // Scan heap for Script objects.
1724 int count = 0;
1725 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001726 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
sgjesse@chromium.org152a0b02009-10-07 13:50:16 +00001727 if (obj->IsScript() && Script::cast(obj)->HasValidSource()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001728 script_cache_->Add(Handle<Script>(Script::cast(obj)));
1729 count++;
1730 }
1731 }
1732}
1733
1734
1735void Debug::DestroyScriptCache() {
1736 // Get rid of the script cache if it was created.
1737 if (script_cache_ != NULL) {
1738 delete script_cache_;
1739 script_cache_ = NULL;
1740 }
1741}
1742
1743
1744void Debug::AddScriptToScriptCache(Handle<Script> script) {
1745 if (script_cache_ != NULL) {
1746 script_cache_->Add(script);
1747 }
1748}
1749
1750
1751Handle<FixedArray> Debug::GetLoadedScripts() {
1752 // Create and fill the script cache when the loaded scripts is requested for
1753 // the first time.
1754 if (script_cache_ == NULL) {
1755 CreateScriptCache();
1756 }
1757
1758 // If the script cache is not active just return an empty array.
1759 ASSERT(script_cache_ != NULL);
1760 if (script_cache_ == NULL) {
1761 Factory::NewFixedArray(0);
1762 }
1763
1764 // Perform GC to get unreferenced scripts evicted from the cache before
1765 // returning the content.
ager@chromium.orgab99eea2009-08-25 07:05:41 +00001766 Heap::CollectAllGarbage(false);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001767
1768 // Get the scripts from the cache.
1769 return script_cache_->GetScripts();
1770}
1771
1772
1773void Debug::AfterGarbageCollection() {
1774 // Generate events for collected scripts.
1775 if (script_cache_ != NULL) {
1776 script_cache_->ProcessCollectedScripts();
1777 }
1778}
1779
1780
ager@chromium.org71daaf62009-04-01 07:22:49 +00001781Mutex* Debugger::debugger_access_ = OS::CreateMutex();
iposva@chromium.org245aa852009-02-10 00:49:54 +00001782Handle<Object> Debugger::event_listener_ = Handle<Object>();
1783Handle<Object> Debugger::event_listener_data_ = Handle<Object>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001784bool Debugger::compiling_natives_ = false;
mads.s.agercbaa0602008-08-14 13:41:48 +00001785bool Debugger::is_loading_debugger_ = false;
ager@chromium.org71daaf62009-04-01 07:22:49 +00001786bool Debugger::never_unload_debugger_ = false;
ager@chromium.org5ec48922009-05-05 07:25:34 +00001787v8::Debug::MessageHandler2 Debugger::message_handler_ = NULL;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001788bool Debugger::debugger_unload_pending_ = false;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001789v8::Debug::HostDispatchHandler Debugger::host_dispatch_handler_ = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001790Mutex* Debugger::dispatch_handler_access_ = OS::CreateMutex();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00001791v8::Debug::DebugMessageDispatchHandler
1792 Debugger::debug_message_dispatch_handler_ = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001793MessageDispatchHelperThread* Debugger::message_dispatch_helper_thread_ = NULL;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001794int Debugger::host_dispatch_micros_ = 100 * 1000;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001795DebuggerAgent* Debugger::agent_ = NULL;
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00001796LockingCommandMessageQueue Debugger::command_queue_(kQueueInitialSize);
ager@chromium.org41826e72009-03-30 13:30:57 +00001797Semaphore* Debugger::command_received_ = OS::CreateSemaphore(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001798
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001799
1800Handle<Object> Debugger::MakeJSObject(Vector<const char> constructor_name,
1801 int argc, Object*** argv,
1802 bool* caught_exception) {
1803 ASSERT(Top::context() == *Debug::debug_context());
1804
1805 // Create the execution state object.
1806 Handle<String> constructor_str = Factory::LookupSymbol(constructor_name);
1807 Handle<Object> constructor(Top::global()->GetProperty(*constructor_str));
1808 ASSERT(constructor->IsJSFunction());
1809 if (!constructor->IsJSFunction()) {
1810 *caught_exception = true;
1811 return Factory::undefined_value();
1812 }
1813 Handle<Object> js_object = Execution::TryCall(
1814 Handle<JSFunction>::cast(constructor),
1815 Handle<JSObject>(Debug::debug_context()->global()), argc, argv,
1816 caught_exception);
1817 return js_object;
1818}
1819
1820
1821Handle<Object> Debugger::MakeExecutionState(bool* caught_exception) {
1822 // Create the execution state object.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001823 Handle<Object> break_id = Factory::NewNumberFromInt(Debug::break_id());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001824 const int argc = 1;
1825 Object** argv[argc] = { break_id.location() };
1826 return MakeJSObject(CStrVector("MakeExecutionState"),
1827 argc, argv, caught_exception);
1828}
1829
1830
1831Handle<Object> Debugger::MakeBreakEvent(Handle<Object> exec_state,
1832 Handle<Object> break_points_hit,
1833 bool* caught_exception) {
1834 // Create the new break event object.
1835 const int argc = 2;
1836 Object** argv[argc] = { exec_state.location(),
1837 break_points_hit.location() };
1838 return MakeJSObject(CStrVector("MakeBreakEvent"),
1839 argc,
1840 argv,
1841 caught_exception);
1842}
1843
1844
1845Handle<Object> Debugger::MakeExceptionEvent(Handle<Object> exec_state,
1846 Handle<Object> exception,
1847 bool uncaught,
1848 bool* caught_exception) {
1849 // Create the new exception event object.
1850 const int argc = 3;
1851 Object** argv[argc] = { exec_state.location(),
1852 exception.location(),
1853 uncaught ? Factory::true_value().location() :
1854 Factory::false_value().location()};
1855 return MakeJSObject(CStrVector("MakeExceptionEvent"),
1856 argc, argv, caught_exception);
1857}
1858
1859
1860Handle<Object> Debugger::MakeNewFunctionEvent(Handle<Object> function,
1861 bool* caught_exception) {
1862 // Create the new function event object.
1863 const int argc = 1;
1864 Object** argv[argc] = { function.location() };
1865 return MakeJSObject(CStrVector("MakeNewFunctionEvent"),
1866 argc, argv, caught_exception);
1867}
1868
1869
1870Handle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
iposva@chromium.org245aa852009-02-10 00:49:54 +00001871 bool before,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001872 bool* caught_exception) {
1873 // Create the compile event object.
1874 Handle<Object> exec_state = MakeExecutionState(caught_exception);
iposva@chromium.org245aa852009-02-10 00:49:54 +00001875 Handle<Object> script_wrapper = GetScriptWrapper(script);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001876 const int argc = 3;
iposva@chromium.org245aa852009-02-10 00:49:54 +00001877 Object** argv[argc] = { exec_state.location(),
1878 script_wrapper.location(),
1879 before ? Factory::true_value().location() :
1880 Factory::false_value().location() };
1881
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001882 return MakeJSObject(CStrVector("MakeCompileEvent"),
1883 argc,
1884 argv,
1885 caught_exception);
1886}
1887
1888
kasperl@chromium.org71affb52009-05-26 05:44:31 +00001889Handle<Object> Debugger::MakeScriptCollectedEvent(int id,
1890 bool* caught_exception) {
1891 // Create the script collected event object.
1892 Handle<Object> exec_state = MakeExecutionState(caught_exception);
1893 Handle<Object> id_object = Handle<Smi>(Smi::FromInt(id));
1894 const int argc = 2;
1895 Object** argv[argc] = { exec_state.location(), id_object.location() };
1896
1897 return MakeJSObject(CStrVector("MakeScriptCollectedEvent"),
1898 argc,
1899 argv,
1900 caught_exception);
1901}
1902
1903
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001904void Debugger::OnException(Handle<Object> exception, bool uncaught) {
1905 HandleScope scope;
1906
1907 // Bail out based on state or if there is no listener for this event
1908 if (Debug::InDebugger()) return;
1909 if (!Debugger::EventActive(v8::Exception)) return;
1910
1911 // Bail out if exception breaks are not active
1912 if (uncaught) {
1913 // Uncaught exceptions are reported by either flags.
1914 if (!(Debug::break_on_uncaught_exception() ||
1915 Debug::break_on_exception())) return;
1916 } else {
1917 // Caught exceptions are reported is activated.
1918 if (!Debug::break_on_exception()) return;
1919 }
1920
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001921 // Enter the debugger.
1922 EnterDebugger debugger;
1923 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001924
1925 // Clear all current stepping setup.
1926 Debug::ClearStepping();
1927 // Create the event data object.
1928 bool caught_exception = false;
1929 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
1930 Handle<Object> event_data;
1931 if (!caught_exception) {
1932 event_data = MakeExceptionEvent(exec_state, exception, uncaught,
1933 &caught_exception);
1934 }
1935 // Bail out and don't call debugger if exception.
1936 if (caught_exception) {
1937 return;
1938 }
1939
ager@chromium.org5ec48922009-05-05 07:25:34 +00001940 // Process debug event.
1941 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001942 // Return to continue execution from where the exception was thrown.
1943}
1944
1945
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001946void Debugger::OnDebugBreak(Handle<Object> break_points_hit,
1947 bool auto_continue) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001948 HandleScope scope;
1949
kasper.lund212ac232008-07-16 07:07:30 +00001950 // Debugger has already been entered by caller.
1951 ASSERT(Top::context() == *Debug::debug_context());
1952
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001953 // Bail out if there is no listener for this event
1954 if (!Debugger::EventActive(v8::Break)) return;
1955
1956 // Debugger must be entered in advance.
1957 ASSERT(Top::context() == *Debug::debug_context());
1958
1959 // Create the event data object.
1960 bool caught_exception = false;
1961 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
1962 Handle<Object> event_data;
1963 if (!caught_exception) {
1964 event_data = MakeBreakEvent(exec_state, break_points_hit,
1965 &caught_exception);
1966 }
1967 // Bail out and don't call debugger if exception.
1968 if (caught_exception) {
1969 return;
1970 }
1971
ager@chromium.org5ec48922009-05-05 07:25:34 +00001972 // Process debug event.
1973 ProcessDebugEvent(v8::Break,
1974 Handle<JSObject>::cast(event_data),
1975 auto_continue);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001976}
1977
1978
1979void Debugger::OnBeforeCompile(Handle<Script> script) {
1980 HandleScope scope;
1981
1982 // Bail out based on state or if there is no listener for this event
1983 if (Debug::InDebugger()) return;
1984 if (compiling_natives()) return;
1985 if (!EventActive(v8::BeforeCompile)) return;
1986
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001987 // Enter the debugger.
1988 EnterDebugger debugger;
1989 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001990
1991 // Create the event data object.
1992 bool caught_exception = false;
iposva@chromium.org245aa852009-02-10 00:49:54 +00001993 Handle<Object> event_data = MakeCompileEvent(script, true, &caught_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001994 // Bail out and don't call debugger if exception.
1995 if (caught_exception) {
1996 return;
1997 }
1998
ager@chromium.org5ec48922009-05-05 07:25:34 +00001999 // Process debug event.
2000 ProcessDebugEvent(v8::BeforeCompile,
2001 Handle<JSObject>::cast(event_data),
2002 true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002003}
2004
2005
2006// Handle debugger actions when a new script is compiled.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002007void Debugger::OnAfterCompile(Handle<Script> script,
2008 AfterCompileFlags after_compile_flags) {
kasper.lund212ac232008-07-16 07:07:30 +00002009 HandleScope scope;
2010
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002011 // Add the newly compiled script to the script cache.
2012 Debug::AddScriptToScriptCache(script);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013
2014 // No more to do if not debugging.
ager@chromium.org71daaf62009-04-01 07:22:49 +00002015 if (!IsDebuggerActive()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002016
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002017 // No compile events while compiling natives.
2018 if (compiling_natives()) return;
2019
iposva@chromium.org245aa852009-02-10 00:49:54 +00002020 // Store whether in debugger before entering debugger.
2021 bool in_debugger = Debug::InDebugger();
2022
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002023 // Enter the debugger.
2024 EnterDebugger debugger;
2025 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002026
2027 // If debugging there might be script break points registered for this
2028 // script. Make sure that these break points are set.
2029
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002030 // Get the function UpdateScriptBreakPoints (defined in debug-debugger.js).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002031 Handle<Object> update_script_break_points =
2032 Handle<Object>(Debug::debug_context()->global()->GetProperty(
2033 *Factory::LookupAsciiSymbol("UpdateScriptBreakPoints")));
2034 if (!update_script_break_points->IsJSFunction()) {
2035 return;
2036 }
2037 ASSERT(update_script_break_points->IsJSFunction());
2038
2039 // Wrap the script object in a proper JS object before passing it
2040 // to JavaScript.
2041 Handle<JSValue> wrapper = GetScriptWrapper(script);
2042
2043 // Call UpdateScriptBreakPoints expect no exceptions.
kasper.lund212ac232008-07-16 07:07:30 +00002044 bool caught_exception = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002045 const int argc = 1;
2046 Object** argv[argc] = { reinterpret_cast<Object**>(wrapper.location()) };
2047 Handle<Object> result = Execution::TryCall(
2048 Handle<JSFunction>::cast(update_script_break_points),
2049 Top::builtins(), argc, argv,
2050 &caught_exception);
2051 if (caught_exception) {
2052 return;
2053 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002054 // Bail out based on state or if there is no listener for this event
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002055 if (in_debugger && (after_compile_flags & SEND_WHEN_DEBUGGING) == 0) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002056 if (!Debugger::EventActive(v8::AfterCompile)) return;
2057
2058 // Create the compile state object.
2059 Handle<Object> event_data = MakeCompileEvent(script,
iposva@chromium.org245aa852009-02-10 00:49:54 +00002060 false,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002061 &caught_exception);
2062 // Bail out and don't call debugger if exception.
2063 if (caught_exception) {
2064 return;
2065 }
ager@chromium.org5ec48922009-05-05 07:25:34 +00002066 // Process debug event.
2067 ProcessDebugEvent(v8::AfterCompile,
2068 Handle<JSObject>::cast(event_data),
2069 true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002070}
2071
2072
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002073void Debugger::OnScriptCollected(int id) {
2074 HandleScope scope;
2075
2076 // No more to do if not debugging.
2077 if (!IsDebuggerActive()) return;
2078 if (!Debugger::EventActive(v8::ScriptCollected)) return;
2079
2080 // Enter the debugger.
2081 EnterDebugger debugger;
2082 if (debugger.FailedToEnter()) return;
2083
2084 // Create the script collected state object.
2085 bool caught_exception = false;
2086 Handle<Object> event_data = MakeScriptCollectedEvent(id,
2087 &caught_exception);
2088 // Bail out and don't call debugger if exception.
2089 if (caught_exception) {
2090 return;
2091 }
2092
2093 // Process debug event.
2094 ProcessDebugEvent(v8::ScriptCollected,
2095 Handle<JSObject>::cast(event_data),
2096 true);
2097}
2098
2099
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002100void Debugger::ProcessDebugEvent(v8::DebugEvent event,
ager@chromium.org5ec48922009-05-05 07:25:34 +00002101 Handle<JSObject> event_data,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002102 bool auto_continue) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00002103 HandleScope scope;
2104
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00002105 // Clear any pending debug break if this is a real break.
2106 if (!auto_continue) {
2107 Debug::clear_interrupt_pending(DEBUGBREAK);
2108 }
2109
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002110 // Create the execution state.
2111 bool caught_exception = false;
2112 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2113 if (caught_exception) {
2114 return;
2115 }
ager@chromium.org41826e72009-03-30 13:30:57 +00002116 // First notify the message handler if any.
2117 if (message_handler_ != NULL) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002118 NotifyMessageHandler(event,
2119 Handle<JSObject>::cast(exec_state),
2120 event_data,
2121 auto_continue);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002122 }
iposva@chromium.org245aa852009-02-10 00:49:54 +00002123 // Notify registered debug event listener. This can be either a C or a
2124 // JavaScript function.
2125 if (!event_listener_.is_null()) {
2126 if (event_listener_->IsProxy()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002127 // C debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00002128 Handle<Proxy> callback_obj(Handle<Proxy>::cast(event_listener_));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002129 v8::Debug::EventCallback2 callback =
2130 FUNCTION_CAST<v8::Debug::EventCallback2>(callback_obj->proxy());
2131 EventDetailsImpl event_details(
2132 event,
2133 Handle<JSObject>::cast(exec_state),
2134 event_data,
2135 event_listener_data_);
2136 callback(event_details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002137 } else {
2138 // JavaScript debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +00002139 ASSERT(event_listener_->IsJSFunction());
2140 Handle<JSFunction> fun(Handle<JSFunction>::cast(event_listener_));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002141
2142 // Invoke the JavaScript debug event listener.
2143 const int argc = 4;
2144 Object** argv[argc] = { Handle<Object>(Smi::FromInt(event)).location(),
2145 exec_state.location(),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002146 Handle<Object>::cast(event_data).location(),
iposva@chromium.org245aa852009-02-10 00:49:54 +00002147 event_listener_data_.location() };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002148 Handle<Object> result = Execution::TryCall(fun, Top::global(),
2149 argc, argv, &caught_exception);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002150 // Silently ignore exceptions from debug event listeners.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002151 }
2152 }
2153}
2154
2155
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002156Handle<Context> Debugger::GetDebugContext() {
2157 never_unload_debugger_ = true;
2158 EnterDebugger debugger;
2159 return Debug::debug_context();
2160}
2161
2162
ager@chromium.org71daaf62009-04-01 07:22:49 +00002163void Debugger::UnloadDebugger() {
2164 // Make sure that there are no breakpoints left.
2165 Debug::ClearAllBreakPoints();
2166
2167 // Unload the debugger if feasible.
2168 if (!never_unload_debugger_) {
2169 Debug::Unload();
2170 }
2171
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002172 // Clear the flag indicating that the debugger should be unloaded.
2173 debugger_unload_pending_ = false;
ager@chromium.org71daaf62009-04-01 07:22:49 +00002174}
2175
2176
ager@chromium.org41826e72009-03-30 13:30:57 +00002177void Debugger::NotifyMessageHandler(v8::DebugEvent event,
ager@chromium.org5ec48922009-05-05 07:25:34 +00002178 Handle<JSObject> exec_state,
2179 Handle<JSObject> event_data,
ager@chromium.org41826e72009-03-30 13:30:57 +00002180 bool auto_continue) {
2181 HandleScope scope;
2182
2183 if (!Debug::Load()) return;
2184
2185 // Process the individual events.
ager@chromium.org5ec48922009-05-05 07:25:34 +00002186 bool sendEventMessage = false;
ager@chromium.org41826e72009-03-30 13:30:57 +00002187 switch (event) {
2188 case v8::Break:
ager@chromium.org5ec48922009-05-05 07:25:34 +00002189 sendEventMessage = !auto_continue;
ager@chromium.org41826e72009-03-30 13:30:57 +00002190 break;
2191 case v8::Exception:
ager@chromium.org5ec48922009-05-05 07:25:34 +00002192 sendEventMessage = true;
ager@chromium.org41826e72009-03-30 13:30:57 +00002193 break;
2194 case v8::BeforeCompile:
2195 break;
2196 case v8::AfterCompile:
ager@chromium.org5ec48922009-05-05 07:25:34 +00002197 sendEventMessage = true;
ager@chromium.org41826e72009-03-30 13:30:57 +00002198 break;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002199 case v8::ScriptCollected:
2200 sendEventMessage = true;
2201 break;
ager@chromium.org41826e72009-03-30 13:30:57 +00002202 case v8::NewFunction:
2203 break;
2204 default:
2205 UNREACHABLE();
2206 }
2207
ager@chromium.org5ec48922009-05-05 07:25:34 +00002208 // The debug command interrupt flag might have been set when the command was
2209 // added. It should be enough to clear the flag only once while we are in the
2210 // debugger.
2211 ASSERT(Debug::InDebugger());
2212 StackGuard::Continue(DEBUGCOMMAND);
2213
2214 // Notify the debugger that a debug event has occurred unless auto continue is
2215 // active in which case no event is send.
2216 if (sendEventMessage) {
2217 MessageImpl message = MessageImpl::NewEvent(
2218 event,
2219 auto_continue,
2220 Handle<JSObject>::cast(exec_state),
2221 Handle<JSObject>::cast(event_data));
2222 InvokeMessageHandler(message);
2223 }
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00002224
2225 // If auto continue don't make the event cause a break, but process messages
2226 // in the queue if any. For script collected events don't even process
2227 // messages in the queue as the execution state might not be what is expected
2228 // by the client.
ager@chromium.org6ffc2172009-05-29 19:20:16 +00002229 if ((auto_continue && !HasCommands()) || event == v8::ScriptCollected) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002230 return;
2231 }
ager@chromium.org41826e72009-03-30 13:30:57 +00002232
ager@chromium.org41826e72009-03-30 13:30:57 +00002233 v8::TryCatch try_catch;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002234
2235 // DebugCommandProcessor goes here.
2236 v8::Local<v8::Object> cmd_processor;
2237 {
2238 v8::Local<v8::Object> api_exec_state =
2239 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state));
2240 v8::Local<v8::String> fun_name =
2241 v8::String::New("debugCommandProcessor");
2242 v8::Local<v8::Function> fun =
2243 v8::Function::Cast(*api_exec_state->Get(fun_name));
2244
2245 v8::Handle<v8::Boolean> running =
2246 auto_continue ? v8::True() : v8::False();
2247 static const int kArgc = 1;
2248 v8::Handle<Value> argv[kArgc] = { running };
2249 cmd_processor = v8::Object::Cast(*fun->Call(api_exec_state, kArgc, argv));
2250 if (try_catch.HasCaught()) {
2251 PrintLn(try_catch.Exception());
2252 return;
2253 }
ager@chromium.org41826e72009-03-30 13:30:57 +00002254 }
2255
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002256 bool running = auto_continue;
2257
ager@chromium.org41826e72009-03-30 13:30:57 +00002258 // Process requests from the debugger.
2259 while (true) {
2260 // Wait for new command in the queue.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002261 if (Debugger::host_dispatch_handler_) {
2262 // In case there is a host dispatch - do periodic dispatches.
2263 if (!command_received_->Wait(host_dispatch_micros_)) {
2264 // Timout expired, do the dispatch.
2265 Debugger::host_dispatch_handler_();
2266 continue;
2267 }
2268 } else {
2269 // In case there is no host dispatch - just wait.
2270 command_received_->Wait();
2271 }
ager@chromium.org41826e72009-03-30 13:30:57 +00002272
ager@chromium.org41826e72009-03-30 13:30:57 +00002273 // Get the command from the queue.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002274 CommandMessage command = command_queue_.Get();
ager@chromium.org41826e72009-03-30 13:30:57 +00002275 Logger::DebugTag("Got request from command queue, in interactive loop.");
ager@chromium.org71daaf62009-04-01 07:22:49 +00002276 if (!Debugger::IsDebuggerActive()) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002277 // Delete command text and user data.
2278 command.Dispose();
ager@chromium.org41826e72009-03-30 13:30:57 +00002279 return;
2280 }
2281
ager@chromium.org41826e72009-03-30 13:30:57 +00002282 // Invoke JavaScript to process the debug request.
2283 v8::Local<v8::String> fun_name;
2284 v8::Local<v8::Function> fun;
2285 v8::Local<v8::Value> request;
2286 v8::TryCatch try_catch;
2287 fun_name = v8::String::New("processDebugRequest");
2288 fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002289
2290 request = v8::String::New(command.text().start(),
2291 command.text().length());
ager@chromium.org41826e72009-03-30 13:30:57 +00002292 static const int kArgc = 1;
2293 v8::Handle<Value> argv[kArgc] = { request };
2294 v8::Local<v8::Value> response_val = fun->Call(cmd_processor, kArgc, argv);
2295
2296 // Get the response.
2297 v8::Local<v8::String> response;
ager@chromium.org41826e72009-03-30 13:30:57 +00002298 if (!try_catch.HasCaught()) {
2299 // Get response string.
2300 if (!response_val->IsUndefined()) {
2301 response = v8::String::Cast(*response_val);
2302 } else {
2303 response = v8::String::New("");
2304 }
2305
2306 // Log the JSON request/response.
2307 if (FLAG_trace_debug_json) {
2308 PrintLn(request);
2309 PrintLn(response);
2310 }
2311
2312 // Get the running state.
2313 fun_name = v8::String::New("isRunning");
2314 fun = v8::Function::Cast(*cmd_processor->Get(fun_name));
2315 static const int kArgc = 1;
2316 v8::Handle<Value> argv[kArgc] = { response };
2317 v8::Local<v8::Value> running_val = fun->Call(cmd_processor, kArgc, argv);
2318 if (!try_catch.HasCaught()) {
2319 running = running_val->ToBoolean()->Value();
2320 }
2321 } else {
2322 // In case of failure the result text is the exception text.
2323 response = try_catch.Exception()->ToString();
2324 }
2325
ager@chromium.org41826e72009-03-30 13:30:57 +00002326 // Return the result.
ager@chromium.org5ec48922009-05-05 07:25:34 +00002327 MessageImpl message = MessageImpl::NewResponse(
2328 event,
2329 running,
2330 Handle<JSObject>::cast(exec_state),
2331 Handle<JSObject>::cast(event_data),
2332 Handle<String>(Utils::OpenHandle(*response)),
2333 command.client_data());
2334 InvokeMessageHandler(message);
2335 command.Dispose();
ager@chromium.org41826e72009-03-30 13:30:57 +00002336
2337 // Return from debug event processing if either the VM is put into the
2338 // runnning state (through a continue command) or auto continue is active
2339 // and there are no more commands queued.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002340 if (running && !HasCommands()) {
ager@chromium.org41826e72009-03-30 13:30:57 +00002341 return;
2342 }
2343 }
2344}
2345
2346
iposva@chromium.org245aa852009-02-10 00:49:54 +00002347void Debugger::SetEventListener(Handle<Object> callback,
2348 Handle<Object> data) {
2349 HandleScope scope;
2350
2351 // Clear the global handles for the event listener and the event listener data
2352 // object.
2353 if (!event_listener_.is_null()) {
2354 GlobalHandles::Destroy(
2355 reinterpret_cast<Object**>(event_listener_.location()));
2356 event_listener_ = Handle<Object>();
2357 }
2358 if (!event_listener_data_.is_null()) {
2359 GlobalHandles::Destroy(
2360 reinterpret_cast<Object**>(event_listener_data_.location()));
2361 event_listener_data_ = Handle<Object>();
2362 }
2363
2364 // If there is a new debug event listener register it together with its data
2365 // object.
2366 if (!callback->IsUndefined() && !callback->IsNull()) {
2367 event_listener_ = Handle<Object>::cast(GlobalHandles::Create(*callback));
2368 if (data.is_null()) {
2369 data = Factory::undefined_value();
2370 }
2371 event_listener_data_ = Handle<Object>::cast(GlobalHandles::Create(*data));
2372 }
2373
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002374 ListenersChanged();
iposva@chromium.org245aa852009-02-10 00:49:54 +00002375}
2376
2377
ager@chromium.org5ec48922009-05-05 07:25:34 +00002378void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002379 ScopedLock with(debugger_access_);
2380
ager@chromium.org381abbb2009-02-25 13:23:22 +00002381 message_handler_ = handler;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002382 ListenersChanged();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002383 if (handler == NULL) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002384 // Send an empty command to the debugger if in a break to make JavaScript
2385 // run again if the debugger is closed.
2386 if (Debug::InDebugger()) {
2387 ProcessCommand(Vector<const uint16_t>::empty());
2388 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002389 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002390}
2391
2392
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002393void Debugger::ListenersChanged() {
2394 if (IsDebuggerActive()) {
2395 // Disable the compilation cache when the debugger is active.
2396 CompilationCache::Disable();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002397 debugger_unload_pending_ = false;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002398 } else {
2399 CompilationCache::Enable();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002400 // Unload the debugger if event listener and message handler cleared.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002401 // Schedule this for later, because we may be in non-V8 thread.
2402 debugger_unload_pending_ = true;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002403 }
2404}
2405
2406
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002407void Debugger::SetHostDispatchHandler(v8::Debug::HostDispatchHandler handler,
2408 int period) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00002409 host_dispatch_handler_ = handler;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002410 host_dispatch_micros_ = period * 1000;
ager@chromium.org381abbb2009-02-25 13:23:22 +00002411}
2412
2413
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002414void Debugger::SetDebugMessageDispatchHandler(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002415 v8::Debug::DebugMessageDispatchHandler handler, bool provide_locker) {
2416 ScopedLock with(dispatch_handler_access_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002417 debug_message_dispatch_handler_ = handler;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002418
2419 if (provide_locker && message_dispatch_helper_thread_ == NULL) {
2420 message_dispatch_helper_thread_ = new MessageDispatchHelperThread;
2421 message_dispatch_helper_thread_->Start();
2422 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002423}
2424
2425
ager@chromium.org41826e72009-03-30 13:30:57 +00002426// Calls the registered debug message handler. This callback is part of the
ager@chromium.org5ec48922009-05-05 07:25:34 +00002427// public API.
2428void Debugger::InvokeMessageHandler(MessageImpl message) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002429 ScopedLock with(debugger_access_);
2430
ager@chromium.org381abbb2009-02-25 13:23:22 +00002431 if (message_handler_ != NULL) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002432 message_handler_(message);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002433 }
ager@chromium.org41826e72009-03-30 13:30:57 +00002434}
2435
2436
2437// Puts a command coming from the public API on the queue. Creates
2438// a copy of the command string managed by the debugger. Up to this
2439// point, the command data was managed by the API client. Called
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002440// by the API client thread.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002441void Debugger::ProcessCommand(Vector<const uint16_t> command,
2442 v8::Debug::ClientData* client_data) {
2443 // Need to cast away const.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002444 CommandMessage message = CommandMessage::New(
ager@chromium.org41826e72009-03-30 13:30:57 +00002445 Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002446 command.length()),
2447 client_data);
ager@chromium.org41826e72009-03-30 13:30:57 +00002448 Logger::DebugTag("Put command on command_queue.");
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002449 command_queue_.Put(message);
ager@chromium.org41826e72009-03-30 13:30:57 +00002450 command_received_->Signal();
sgjesse@chromium.org3afc1582009-04-16 22:31:44 +00002451
2452 // Set the debug command break flag to have the command processed.
ager@chromium.org41826e72009-03-30 13:30:57 +00002453 if (!Debug::InDebugger()) {
2454 StackGuard::DebugCommand();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002455 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002456
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002457 MessageDispatchHelperThread* dispatch_thread;
2458 {
2459 ScopedLock with(dispatch_handler_access_);
2460 dispatch_thread = message_dispatch_helper_thread_;
2461 }
2462
2463 if (dispatch_thread == NULL) {
2464 CallMessageDispatchHandler();
2465 } else {
2466 dispatch_thread->Schedule();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002467 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002468}
2469
2470
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002471bool Debugger::HasCommands() {
ager@chromium.org41826e72009-03-30 13:30:57 +00002472 return !command_queue_.IsEmpty();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002473}
2474
2475
ager@chromium.org71daaf62009-04-01 07:22:49 +00002476bool Debugger::IsDebuggerActive() {
2477 ScopedLock with(debugger_access_);
2478
2479 return message_handler_ != NULL || !event_listener_.is_null();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002480}
2481
2482
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002483Handle<Object> Debugger::Call(Handle<JSFunction> fun,
2484 Handle<Object> data,
2485 bool* pending_exception) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00002486 // When calling functions in the debugger prevent it from beeing unloaded.
2487 Debugger::never_unload_debugger_ = true;
2488
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002489 // Enter the debugger.
2490 EnterDebugger debugger;
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00002491 if (debugger.FailedToEnter()) {
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002492 return Factory::undefined_value();
2493 }
2494
2495 // Create the execution state.
2496 bool caught_exception = false;
2497 Handle<Object> exec_state = MakeExecutionState(&caught_exception);
2498 if (caught_exception) {
2499 return Factory::undefined_value();
2500 }
2501
2502 static const int kArgc = 2;
2503 Object** argv[kArgc] = { exec_state.location(), data.location() };
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00002504 Handle<Object> result = Execution::Call(
2505 fun,
2506 Handle<Object>(Debug::debug_context_->global_proxy()),
2507 kArgc,
2508 argv,
2509 pending_exception);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00002510 return result;
2511}
2512
2513
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002514static void StubMessageHandler2(const v8::Debug::Message& message) {
2515 // Simply ignore message.
2516}
2517
2518
2519bool Debugger::StartAgent(const char* name, int port,
2520 bool wait_for_connection) {
2521 if (wait_for_connection) {
2522 // Suspend V8 if it is already running or set V8 to suspend whenever
2523 // it starts.
2524 // Provide stub message handler; V8 auto-continues each suspend
2525 // when there is no message handler; we doesn't need it.
2526 // Once become suspended, V8 will stay so indefinitely long, until remote
2527 // debugger connects and issues "continue" command.
2528 Debugger::message_handler_ = StubMessageHandler2;
2529 v8::Debug::DebugBreak();
2530 }
2531
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002532 if (Socket::Setup()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002533 agent_ = new DebuggerAgent(name, port);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002534 agent_->Start();
2535 return true;
2536 }
2537
2538 return false;
2539}
2540
2541
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002542void Debugger::StopAgent() {
2543 if (agent_ != NULL) {
2544 agent_->Shutdown();
2545 agent_->Join();
2546 delete agent_;
2547 agent_ = NULL;
2548 }
2549}
2550
2551
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00002552void Debugger::WaitForAgent() {
2553 if (agent_ != NULL)
2554 agent_->WaitUntilListening();
2555}
2556
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002557
2558void Debugger::CallMessageDispatchHandler() {
2559 v8::Debug::DebugMessageDispatchHandler handler;
2560 {
2561 ScopedLock with(dispatch_handler_access_);
2562 handler = Debugger::debug_message_dispatch_handler_;
2563 }
2564 if (handler != NULL) {
2565 handler();
2566 }
2567}
2568
2569
ager@chromium.org5ec48922009-05-05 07:25:34 +00002570MessageImpl MessageImpl::NewEvent(DebugEvent event,
2571 bool running,
2572 Handle<JSObject> exec_state,
2573 Handle<JSObject> event_data) {
2574 MessageImpl message(true, event, running,
2575 exec_state, event_data, Handle<String>(), NULL);
2576 return message;
2577}
2578
2579
2580MessageImpl MessageImpl::NewResponse(DebugEvent event,
2581 bool running,
2582 Handle<JSObject> exec_state,
2583 Handle<JSObject> event_data,
2584 Handle<String> response_json,
2585 v8::Debug::ClientData* client_data) {
2586 MessageImpl message(false, event, running,
2587 exec_state, event_data, response_json, client_data);
2588 return message;
2589}
2590
2591
2592MessageImpl::MessageImpl(bool is_event,
2593 DebugEvent event,
2594 bool running,
2595 Handle<JSObject> exec_state,
2596 Handle<JSObject> event_data,
2597 Handle<String> response_json,
2598 v8::Debug::ClientData* client_data)
2599 : is_event_(is_event),
2600 event_(event),
2601 running_(running),
2602 exec_state_(exec_state),
2603 event_data_(event_data),
2604 response_json_(response_json),
2605 client_data_(client_data) {}
2606
2607
2608bool MessageImpl::IsEvent() const {
2609 return is_event_;
2610}
2611
2612
2613bool MessageImpl::IsResponse() const {
2614 return !is_event_;
2615}
2616
2617
2618DebugEvent MessageImpl::GetEvent() const {
2619 return event_;
2620}
2621
2622
2623bool MessageImpl::WillStartRunning() const {
2624 return running_;
2625}
2626
2627
2628v8::Handle<v8::Object> MessageImpl::GetExecutionState() const {
2629 return v8::Utils::ToLocal(exec_state_);
2630}
2631
2632
2633v8::Handle<v8::Object> MessageImpl::GetEventData() const {
2634 return v8::Utils::ToLocal(event_data_);
2635}
2636
2637
2638v8::Handle<v8::String> MessageImpl::GetJSON() const {
2639 v8::HandleScope scope;
2640
2641 if (IsEvent()) {
2642 // Call toJSONProtocol on the debug event object.
2643 Handle<Object> fun = GetProperty(event_data_, "toJSONProtocol");
2644 if (!fun->IsJSFunction()) {
2645 return v8::Handle<v8::String>();
2646 }
2647 bool caught_exception;
2648 Handle<Object> json = Execution::TryCall(Handle<JSFunction>::cast(fun),
2649 event_data_,
2650 0, NULL, &caught_exception);
2651 if (caught_exception || !json->IsString()) {
2652 return v8::Handle<v8::String>();
2653 }
2654 return scope.Close(v8::Utils::ToLocal(Handle<String>::cast(json)));
2655 } else {
2656 return v8::Utils::ToLocal(response_json_);
2657 }
2658}
2659
2660
2661v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002662 v8::Handle<v8::Context> context = GetDebugEventContext();
2663 // Top::context() may be NULL when "script collected" event occures.
2664 ASSERT(!context.IsEmpty() || event_ == v8::ScriptCollected);
2665 return GetDebugEventContext();
ager@chromium.org5ec48922009-05-05 07:25:34 +00002666}
2667
2668
2669v8::Debug::ClientData* MessageImpl::GetClientData() const {
2670 return client_data_;
2671}
2672
2673
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002674EventDetailsImpl::EventDetailsImpl(DebugEvent event,
2675 Handle<JSObject> exec_state,
2676 Handle<JSObject> event_data,
2677 Handle<Object> callback_data)
2678 : event_(event),
2679 exec_state_(exec_state),
2680 event_data_(event_data),
2681 callback_data_(callback_data) {}
2682
2683
2684DebugEvent EventDetailsImpl::GetEvent() const {
2685 return event_;
2686}
2687
2688
2689v8::Handle<v8::Object> EventDetailsImpl::GetExecutionState() const {
2690 return v8::Utils::ToLocal(exec_state_);
2691}
2692
2693
2694v8::Handle<v8::Object> EventDetailsImpl::GetEventData() const {
2695 return v8::Utils::ToLocal(event_data_);
2696}
2697
2698
2699v8::Handle<v8::Context> EventDetailsImpl::GetEventContext() const {
2700 return GetDebugEventContext();
2701}
2702
2703
2704v8::Handle<v8::Value> EventDetailsImpl::GetCallbackData() const {
2705 return v8::Utils::ToLocal(callback_data_);
2706}
2707
2708
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002709CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()),
2710 client_data_(NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002711}
2712
2713
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002714CommandMessage::CommandMessage(const Vector<uint16_t>& text,
2715 v8::Debug::ClientData* data)
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002716 : text_(text),
2717 client_data_(data) {
2718}
2719
2720
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002721CommandMessage::~CommandMessage() {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002722}
2723
2724
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002725void CommandMessage::Dispose() {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002726 text_.Dispose();
2727 delete client_data_;
2728 client_data_ = NULL;
2729}
2730
2731
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002732CommandMessage CommandMessage::New(const Vector<uint16_t>& command,
2733 v8::Debug::ClientData* data) {
2734 return CommandMessage(command.Clone(), data);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002735}
2736
2737
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002738CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0),
2739 size_(size) {
2740 messages_ = NewArray<CommandMessage>(size);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002741}
2742
2743
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002744CommandMessageQueue::~CommandMessageQueue() {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002745 while (!IsEmpty()) {
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002746 CommandMessage m = Get();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002747 m.Dispose();
2748 }
kasper.lund7276f142008-07-30 08:49:36 +00002749 DeleteArray(messages_);
2750}
2751
2752
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002753CommandMessage CommandMessageQueue::Get() {
kasper.lund7276f142008-07-30 08:49:36 +00002754 ASSERT(!IsEmpty());
2755 int result = start_;
2756 start_ = (start_ + 1) % size_;
2757 return messages_[result];
2758}
2759
2760
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002761void CommandMessageQueue::Put(const CommandMessage& message) {
kasper.lund7276f142008-07-30 08:49:36 +00002762 if ((end_ + 1) % size_ == start_) {
2763 Expand();
2764 }
2765 messages_[end_] = message;
2766 end_ = (end_ + 1) % size_;
2767}
2768
2769
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002770void CommandMessageQueue::Expand() {
2771 CommandMessageQueue new_queue(size_ * 2);
kasper.lund7276f142008-07-30 08:49:36 +00002772 while (!IsEmpty()) {
2773 new_queue.Put(Get());
2774 }
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002775 CommandMessage* array_to_free = messages_;
kasper.lund7276f142008-07-30 08:49:36 +00002776 *this = new_queue;
2777 new_queue.messages_ = array_to_free;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002778 // Make the new_queue empty so that it doesn't call Dispose on any messages.
2779 new_queue.start_ = new_queue.end_;
kasper.lund7276f142008-07-30 08:49:36 +00002780 // Automatic destructor called on new_queue, freeing array_to_free.
2781}
2782
2783
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002784LockingCommandMessageQueue::LockingCommandMessageQueue(int size)
2785 : queue_(size) {
kasper.lund7276f142008-07-30 08:49:36 +00002786 lock_ = OS::CreateMutex();
2787}
2788
2789
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002790LockingCommandMessageQueue::~LockingCommandMessageQueue() {
kasper.lund7276f142008-07-30 08:49:36 +00002791 delete lock_;
2792}
2793
2794
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002795bool LockingCommandMessageQueue::IsEmpty() const {
kasper.lund7276f142008-07-30 08:49:36 +00002796 ScopedLock sl(lock_);
2797 return queue_.IsEmpty();
2798}
2799
2800
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002801CommandMessage LockingCommandMessageQueue::Get() {
kasper.lund7276f142008-07-30 08:49:36 +00002802 ScopedLock sl(lock_);
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002803 CommandMessage result = queue_.Get();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002804 Logger::DebugEvent("Get", result.text());
kasper.lund7276f142008-07-30 08:49:36 +00002805 return result;
2806}
2807
2808
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002809void LockingCommandMessageQueue::Put(const CommandMessage& message) {
kasper.lund7276f142008-07-30 08:49:36 +00002810 ScopedLock sl(lock_);
2811 queue_.Put(message);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002812 Logger::DebugEvent("Put", message.text());
kasper.lund7276f142008-07-30 08:49:36 +00002813}
2814
2815
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00002816void LockingCommandMessageQueue::Clear() {
kasper.lund7276f142008-07-30 08:49:36 +00002817 ScopedLock sl(lock_);
2818 queue_.Clear();
2819}
2820
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002821
2822MessageDispatchHelperThread::MessageDispatchHelperThread()
2823 : sem_(OS::CreateSemaphore(0)), mutex_(OS::CreateMutex()),
2824 already_signalled_(false) {
2825}
2826
2827
2828MessageDispatchHelperThread::~MessageDispatchHelperThread() {
2829 delete mutex_;
2830 delete sem_;
2831}
2832
2833
2834void MessageDispatchHelperThread::Schedule() {
2835 {
2836 ScopedLock lock(mutex_);
2837 if (already_signalled_) {
2838 return;
2839 }
2840 already_signalled_ = true;
2841 }
2842 sem_->Signal();
2843}
2844
2845
2846void MessageDispatchHelperThread::Run() {
2847 while (true) {
2848 sem_->Wait();
2849 {
2850 ScopedLock lock(mutex_);
2851 already_signalled_ = false;
2852 }
2853 {
2854 Locker locker;
2855 Debugger::CallMessageDispatchHandler();
2856 }
2857 }
2858}
2859
ager@chromium.org65dad4b2009-04-23 08:48:43 +00002860#endif // ENABLE_DEBUGGER_SUPPORT
kasper.lund7276f142008-07-30 08:49:36 +00002861
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002862} } // namespace v8::internal