blob: 6adb38a17ceaa9c89903beb658fd1c6c1fbcac31 [file] [log] [blame]
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001// Copyright 2012 the V8 project authors. All rights reserved.
rossberg@chromium.org34849642014-04-29 16:30:47 +00002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004
5#include "v8.h"
6
7#include "api.h"
8#include "arguments.h"
9#include "bootstrapper.h"
10#include "code-stubs.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000011#include "codegen.h"
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013#include "compiler.h"
14#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000015#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000016#include "execution.h"
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +000017#include "full-codegen.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000018#include "global-handles.h"
ager@chromium.org65dad4b2009-04-23 08:48:43 +000019#include "ic.h"
20#include "ic-inl.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000021#include "isolate-inl.h"
lrn@chromium.org34e60782011-09-15 07:25:40 +000022#include "list.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000023#include "messages.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000024#include "natives.h"
25#include "stub-cache.h"
kasper.lund7276f142008-07-30 08:49:36 +000026#include "log.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000027
ager@chromium.org5ec48922009-05-05 07:25:34 +000028#include "../include/v8-debug.h"
29
kasperl@chromium.org71affb52009-05-26 05:44:31 +000030namespace v8 {
31namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000032
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000033Debug::Debug(Isolate* isolate)
34 : has_break_points_(false),
35 script_cache_(NULL),
36 debug_info_list_(NULL),
37 disable_break_(false),
38 break_on_exception_(false),
39 break_on_uncaught_exception_(false),
machenbach@chromium.orga86d4162014-05-01 00:05:11 +000040 promise_catch_handlers_(0),
41 promise_getters_(0),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000042 isolate_(isolate) {
43 memset(registers_, 0, sizeof(JSCallerSavedBuffer));
machenbach@chromium.orgaf6f6992014-05-06 00:04:47 +000044 ThreadInit();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000045}
46
47
48Debug::~Debug() {
49}
50
51
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000052static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) {
53 Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
54 // Isolate::context() may have been NULL when "script collected" event
55 // occured.
56 if (context.is_null()) return v8::Local<v8::Context>();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +000057 Handle<Context> native_context(context->native_context());
58 return v8::Utils::ToLocal(native_context);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000059}
60
61
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000062BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info,
63 BreakLocatorType type) {
64 debug_info_ = debug_info;
65 type_ = type;
66 reloc_iterator_ = NULL;
67 reloc_iterator_original_ = NULL;
68 Reset(); // Initialize the rest of the member variables.
69}
70
71
72BreakLocationIterator::~BreakLocationIterator() {
73 ASSERT(reloc_iterator_ != NULL);
74 ASSERT(reloc_iterator_original_ != NULL);
75 delete reloc_iterator_;
76 delete reloc_iterator_original_;
77}
78
79
80void BreakLocationIterator::Next() {
rossberg@chromium.org79e79022013-06-03 15:43:46 +000081 DisallowHeapAllocation no_gc;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000082 ASSERT(!RinfoDone());
83
84 // Iterate through reloc info for code and original code stopping at each
85 // breakable code target.
86 bool first = break_point_ == -1;
87 while (!RinfoDone()) {
88 if (!first) RinfoNext();
89 first = false;
90 if (RinfoDone()) return;
91
ager@chromium.org236ad962008-09-25 09:45:57 +000092 // Whenever a statement position or (plain) position is passed update the
93 // current value of these.
94 if (RelocInfo::IsPosition(rmode())) {
95 if (RelocInfo::IsStatementPosition(rmode())) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +000096 statement_position_ = static_cast<int>(
97 rinfo()->data() - debug_info_->shared()->start_position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098 }
ager@chromium.org236ad962008-09-25 09:45:57 +000099 // Always update the position as we don't want that to be before the
100 // statement position.
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000101 position_ = static_cast<int>(
102 rinfo()->data() - debug_info_->shared()->start_position());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000103 ASSERT(position_ >= 0);
104 ASSERT(statement_position_ >= 0);
105 }
106
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000107 if (IsDebugBreakSlot()) {
108 // There is always a possible break point at a debug break slot.
109 break_point_++;
110 return;
111 } else if (RelocInfo::IsCodeTarget(rmode())) {
112 // Check for breakable code target. Look in the original code as setting
113 // break points can cause the code targets in the running (debugged) code
114 // to be of a different kind than in the original code.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000115 Address target = original_rinfo()->target_address();
ager@chromium.org8bb60582008-12-11 12:02:20 +0000116 Code* code = Code::GetCodeFromTargetAddress(target);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000117 if ((code->is_inline_cache_stub() &&
danno@chromium.org40cb8782011-05-25 07:58:50 +0000118 !code->is_binary_op_stub() &&
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000119 !code->is_compare_ic_stub() &&
120 !code->is_to_boolean_ic_stub()) ||
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000121 RelocInfo::IsConstructCall(rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000122 break_point_++;
123 return;
124 }
125 if (code->kind() == Code::STUB) {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000126 if (IsDebuggerStatement()) {
127 break_point_++;
128 return;
129 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000130 if (type_ == ALL_BREAK_LOCATIONS) {
131 if (Debug::IsBreakStub(code)) {
132 break_point_++;
133 return;
134 }
135 } else {
136 ASSERT(type_ == SOURCE_BREAK_LOCATIONS);
137 if (Debug::IsSourceBreakStub(code)) {
138 break_point_++;
139 return;
140 }
141 }
142 }
143 }
144
145 // Check for break at return.
ager@chromium.org236ad962008-09-25 09:45:57 +0000146 if (RelocInfo::IsJSReturn(rmode())) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000147 // Set the positions to the end of the function.
148 if (debug_info_->shared()->HasSourceCode()) {
149 position_ = debug_info_->shared()->end_position() -
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000150 debug_info_->shared()->start_position() - 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000151 } else {
152 position_ = 0;
153 }
154 statement_position_ = position_;
155 break_point_++;
156 return;
157 }
158 }
159}
160
161
162void BreakLocationIterator::Next(int count) {
163 while (count > 0) {
164 Next();
165 count--;
166 }
167}
168
169
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000170// Find the break point at the supplied address, or the closest one before
171// the address.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000172void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) {
173 // Run through all break points to locate the one closest to the address.
174 int closest_break_point = 0;
175 int distance = kMaxInt;
176 while (!Done()) {
177 // Check if this break point is closer that what was previously found.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000178 if (this->pc() <= pc && pc - this->pc() < distance) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000179 closest_break_point = break_point();
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000180 distance = static_cast<int>(pc - this->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000181 // Check whether we can't get any closer.
182 if (distance == 0) break;
183 }
184 Next();
185 }
186
187 // Move to the break point found.
188 Reset();
189 Next(closest_break_point);
190}
191
192
193// Find the break point closest to the supplied source position.
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +0000194void BreakLocationIterator::FindBreakLocationFromPosition(int position,
195 BreakPositionAlignment alignment) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000196 // Run through all break points to locate the one closest to the source
197 // position.
198 int closest_break_point = 0;
199 int distance = kMaxInt;
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +0000200
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000201 while (!Done()) {
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +0000202 int next_position;
203 switch (alignment) {
204 case STATEMENT_ALIGNED:
205 next_position = this->statement_position();
206 break;
207 case BREAK_POSITION_ALIGNED:
208 next_position = this->position();
209 break;
210 default:
211 UNREACHABLE();
212 next_position = this->statement_position();
213 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000214 // Check if this break point is closer that what was previously found.
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +0000215 if (position <= next_position && next_position - position < distance) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000216 closest_break_point = break_point();
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +0000217 distance = next_position - position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000218 // Check whether we can't get any closer.
219 if (distance == 0) break;
220 }
221 Next();
222 }
223
224 // Move to the break point found.
225 Reset();
226 Next(closest_break_point);
227}
228
229
230void BreakLocationIterator::Reset() {
231 // Create relocation iterators for the two code objects.
232 if (reloc_iterator_ != NULL) delete reloc_iterator_;
233 if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_;
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +0000234 reloc_iterator_ = new RelocIterator(
235 debug_info_->code(),
236 ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE));
237 reloc_iterator_original_ = new RelocIterator(
238 debug_info_->original_code(),
239 ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000240
241 // Position at the first break point.
242 break_point_ = -1;
243 position_ = 1;
244 statement_position_ = 1;
245 Next();
246}
247
248
249bool BreakLocationIterator::Done() const {
250 return RinfoDone();
251}
252
253
254void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) {
255 // If there is not already a real break point here patch code with debug
256 // break.
257 if (!HasBreakPoint()) {
258 SetDebugBreak();
259 }
ager@chromium.orga1645e22009-09-09 19:27:10 +0000260 ASSERT(IsDebugBreak() || IsDebuggerStatement());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000261 // Set the break point information.
262 DebugInfo::SetBreakPoint(debug_info_, code_position(),
263 position(), statement_position(),
264 break_point_object);
265}
266
267
268void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) {
269 // Clear the break point information.
270 DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object);
271 // If there are no more break points here remove the debug break.
272 if (!HasBreakPoint()) {
273 ClearDebugBreak();
274 ASSERT(!IsDebugBreak());
275 }
276}
277
278
279void BreakLocationIterator::SetOneShot() {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000280 // Debugger statement always calls debugger. No need to modify it.
281 if (IsDebuggerStatement()) {
282 return;
283 }
284
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000285 // If there is a real break point here no more to do.
286 if (HasBreakPoint()) {
287 ASSERT(IsDebugBreak());
288 return;
289 }
290
291 // Patch code with debug break.
292 SetDebugBreak();
293}
294
295
296void BreakLocationIterator::ClearOneShot() {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000297 // Debugger statement always calls debugger. No need to modify it.
298 if (IsDebuggerStatement()) {
299 return;
300 }
301
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000302 // If there is a real break point here no more to do.
303 if (HasBreakPoint()) {
304 ASSERT(IsDebugBreak());
305 return;
306 }
307
308 // Patch code removing debug break.
309 ClearDebugBreak();
310 ASSERT(!IsDebugBreak());
311}
312
313
314void BreakLocationIterator::SetDebugBreak() {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000315 // Debugger statement always calls debugger. No need to modify it.
316 if (IsDebuggerStatement()) {
317 return;
318 }
319
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000320 // If there is already a break point here just return. This might happen if
v8.team.kasperl727e9952008-09-02 14:56:44 +0000321 // the same code is flooded with break points twice. Flooding the same
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000322 // function twice might happen when stepping in a function with an exception
323 // handler as the handler and the function is the same.
324 if (IsDebugBreak()) {
325 return;
326 }
327
ager@chromium.org236ad962008-09-25 09:45:57 +0000328 if (RelocInfo::IsJSReturn(rmode())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000329 // Patch the frame exit code with a break point.
330 SetDebugBreakAtReturn();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000331 } else if (IsDebugBreakSlot()) {
332 // Patch the code in the break slot.
333 SetDebugBreakAtSlot();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000334 } else {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000335 // Patch the IC call.
336 SetDebugBreakAtIC();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000337 }
338 ASSERT(IsDebugBreak());
339}
340
341
342void BreakLocationIterator::ClearDebugBreak() {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000343 // Debugger statement always calls debugger. No need to modify it.
344 if (IsDebuggerStatement()) {
345 return;
346 }
347
ager@chromium.org236ad962008-09-25 09:45:57 +0000348 if (RelocInfo::IsJSReturn(rmode())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000349 // Restore the frame exit code.
350 ClearDebugBreakAtReturn();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000351 } else if (IsDebugBreakSlot()) {
352 // Restore the code in the break slot.
353 ClearDebugBreakAtSlot();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354 } else {
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000355 // Patch the IC call.
356 ClearDebugBreakAtIC();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000357 }
358 ASSERT(!IsDebugBreak());
359}
360
361
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000362bool BreakLocationIterator::IsStepInLocation(Isolate* isolate) {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000363 if (RelocInfo::IsConstructCall(original_rmode())) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000364 return true;
365 } else if (RelocInfo::IsCodeTarget(rmode())) {
366 HandleScope scope(debug_info_->GetIsolate());
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000367 Address target = original_rinfo()->target_address();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000368 Handle<Code> target_code(Code::GetCodeFromTargetAddress(target));
danno@chromium.org59400602013-08-13 17:09:37 +0000369 if (target_code->kind() == Code::STUB) {
370 return target_code->major_key() == CodeStub::CallFunction;
371 }
machenbach@chromium.orga86d4162014-05-01 00:05:11 +0000372 return target_code->is_call_stub();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000373 }
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +0000374 return false;
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000375}
376
377
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000378void BreakLocationIterator::PrepareStepIn(Isolate* isolate) {
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +0000379#ifdef DEBUG
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000380 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +0000381 // Step in can only be prepared if currently positioned on an IC call,
382 // construct call or CallFunction stub call.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000383 Address target = rinfo()->target_address();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000384 Handle<Code> target_code(Code::GetCodeFromTargetAddress(target));
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +0000385 // All the following stuff is needed only for assertion checks so the code
386 // is wrapped in ifdef.
387 Handle<Code> maybe_call_function_stub = target_code;
388 if (IsDebugBreak()) {
389 Address original_target = original_rinfo()->target_address();
390 maybe_call_function_stub =
391 Handle<Code>(Code::GetCodeFromTargetAddress(original_target));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000392 }
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +0000393 bool is_call_function_stub =
394 (maybe_call_function_stub->kind() == Code::STUB &&
395 maybe_call_function_stub->major_key() == CodeStub::CallFunction);
396
397 // Step in through construct call requires no changes to the running code.
398 // Step in through getters/setters should already be prepared as well
399 // because caller of this function (Debug::PrepareStep) is expected to
400 // flood the top frame's function with one shot breakpoints.
401 // Step in through CallFunction stub should also be prepared by caller of
402 // this function (Debug::PrepareStep) which should flood target function
403 // with breakpoints.
404 ASSERT(RelocInfo::IsConstructCall(rmode()) ||
405 target_code->is_inline_cache_stub() ||
406 is_call_function_stub);
407#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000408}
409
410
411// Check whether the break point is at a position which will exit the function.
412bool BreakLocationIterator::IsExit() const {
ager@chromium.org236ad962008-09-25 09:45:57 +0000413 return (RelocInfo::IsJSReturn(rmode()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000414}
415
416
417bool BreakLocationIterator::HasBreakPoint() {
418 return debug_info_->HasBreakPoint(code_position());
419}
420
421
422// Check whether there is a debug break at the current position.
423bool BreakLocationIterator::IsDebugBreak() {
ager@chromium.org236ad962008-09-25 09:45:57 +0000424 if (RelocInfo::IsJSReturn(rmode())) {
iposva@chromium.org245aa852009-02-10 00:49:54 +0000425 return IsDebugBreakAtReturn();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000426 } else if (IsDebugBreakSlot()) {
427 return IsDebugBreakAtSlot();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000428 } else {
429 return Debug::IsDebugBreak(rinfo()->target_address());
430 }
431}
432
433
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000434void BreakLocationIterator::SetDebugBreakAtIC() {
435 // Patch the original code with the current address as the current address
436 // might have changed by the inline caching since the code was copied.
437 original_rinfo()->set_target_address(rinfo()->target_address());
438
439 RelocInfo::Mode mode = rmode();
440 if (RelocInfo::IsCodeTarget(mode)) {
441 Address target = rinfo()->target_address();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000442 Handle<Code> target_code(Code::GetCodeFromTargetAddress(target));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000443
444 // Patch the code to invoke the builtin debug break function matching the
445 // calling convention used by the call site.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000446 Handle<Code> dbgbrk_code(Debug::FindDebugBreak(target_code, mode));
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000447 rinfo()->set_target_address(dbgbrk_code->entry());
ager@chromium.org65dad4b2009-04-23 08:48:43 +0000448 }
449}
450
451
452void BreakLocationIterator::ClearDebugBreakAtIC() {
453 // Patch the code to the original invoke.
454 rinfo()->set_target_address(original_rinfo()->target_address());
455}
456
457
ager@chromium.orga1645e22009-09-09 19:27:10 +0000458bool BreakLocationIterator::IsDebuggerStatement() {
ager@chromium.org5c838252010-02-19 08:53:10 +0000459 return RelocInfo::DEBUG_BREAK == rmode();
ager@chromium.orga1645e22009-09-09 19:27:10 +0000460}
461
462
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000463bool BreakLocationIterator::IsDebugBreakSlot() {
464 return RelocInfo::DEBUG_BREAK_SLOT == rmode();
465}
466
467
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000468Object* BreakLocationIterator::BreakPointObjects() {
469 return debug_info_->GetBreakPointObjects(code_position());
470}
471
472
ager@chromium.org381abbb2009-02-25 13:23:22 +0000473// Clear out all the debug break code. This is ONLY supposed to be used when
474// shutting down the debugger as it will leave the break point information in
475// DebugInfo even though the code is patched back to the non break point state.
476void BreakLocationIterator::ClearAllDebugBreak() {
477 while (!Done()) {
478 ClearDebugBreak();
479 Next();
480 }
481}
482
483
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000484bool BreakLocationIterator::RinfoDone() const {
485 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
486 return reloc_iterator_->done();
487}
488
489
490void BreakLocationIterator::RinfoNext() {
491 reloc_iterator_->next();
492 reloc_iterator_original_->next();
493#ifdef DEBUG
494 ASSERT(reloc_iterator_->done() == reloc_iterator_original_->done());
495 if (!reloc_iterator_->done()) {
496 ASSERT(rmode() == original_rmode());
497 }
498#endif
499}
500
501
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000502// Threading support.
503void Debug::ThreadInit() {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000504 thread_local_.break_count_ = 0;
505 thread_local_.break_id_ = 0;
506 thread_local_.break_frame_id_ = StackFrame::NO_ID;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000507 thread_local_.last_step_action_ = StepNone;
ager@chromium.org236ad962008-09-25 09:45:57 +0000508 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000509 thread_local_.step_count_ = 0;
510 thread_local_.last_fp_ = 0;
lrn@chromium.org34e60782011-09-15 07:25:40 +0000511 thread_local_.queued_step_count_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000512 thread_local_.step_into_fp_ = 0;
ager@chromium.orga1645e22009-09-09 19:27:10 +0000513 thread_local_.step_out_fp_ = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000514 thread_local_.after_break_target_ = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000515 // TODO(isolates): frames_are_dropped_?
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000516 thread_local_.debugger_entry_ = NULL;
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +0000517 thread_local_.has_pending_interrupt_ = false;
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000518 thread_local_.restarter_frame_function_pointer_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000519}
520
521
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000522char* Debug::ArchiveDebug(char* storage) {
523 char* to = storage;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000524 OS::MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000525 to += sizeof(ThreadLocal);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000526 OS::MemCopy(to, reinterpret_cast<char*>(&registers_), sizeof(registers_));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000527 ThreadInit();
528 ASSERT(to <= storage + ArchiveSpacePerThread());
529 return storage + ArchiveSpacePerThread();
530}
531
532
533char* Debug::RestoreDebug(char* storage) {
534 char* from = storage;
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000535 OS::MemCopy(
536 reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000537 from += sizeof(ThreadLocal);
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000538 OS::MemCopy(reinterpret_cast<char*>(&registers_), from, sizeof(registers_));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000539 ASSERT(from <= storage + ArchiveSpacePerThread());
540 return storage + ArchiveSpacePerThread();
541}
542
543
544int Debug::ArchiveSpacePerThread() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 return sizeof(ThreadLocal) + sizeof(JSCallerSavedBuffer);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000546}
547
548
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000549// Frame structure (conforms InternalFrame structure):
550// -- code
551// -- SMI maker
552// -- function (slot is called "context")
553// -- frame base
554Object** Debug::SetUpFrameDropperFrame(StackFrame* bottom_js_frame,
555 Handle<Code> code) {
556 ASSERT(bottom_js_frame->is_java_script());
557
558 Address fp = bottom_js_frame->fp();
559
560 // Move function pointer into "context" slot.
561 Memory::Object_at(fp + StandardFrameConstants::kContextOffset) =
562 Memory::Object_at(fp + JavaScriptFrameConstants::kFunctionOffset);
563
564 Memory::Object_at(fp + InternalFrameConstants::kCodeOffset) = *code;
565 Memory::Object_at(fp + StandardFrameConstants::kMarkerOffset) =
566 Smi::FromInt(StackFrame::INTERNAL);
567
568 return reinterpret_cast<Object**>(&Memory::Object_at(
569 fp + StandardFrameConstants::kContextOffset));
570}
571
572const int Debug::kFrameDropperFrameSize = 4;
573
574
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000575void ScriptCache::Add(Handle<Script> script) {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000576 GlobalHandles* global_handles = isolate_->global_handles();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000577 // Create an entry in the hash map for the script.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +0000578 int id = script->id()->value();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000579 HashMap::Entry* entry =
580 HashMap::Lookup(reinterpret_cast<void*>(id), Hash(id), true);
581 if (entry->value != NULL) {
582 ASSERT(*script == *reinterpret_cast<Script**>(entry->value));
583 return;
584 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000585 // Globalize the script object, make it weak and use the location of the
586 // global handle as the value in the hash map.
587 Handle<Script> script_ =
hpayer@chromium.org4f99be92013-12-18 16:23:55 +0000588 Handle<Script>::cast(global_handles->Create(*script));
589 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(script_.location()),
590 this,
591 ScriptCache::HandleWeakScript);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000592 entry->value = script_.location();
593}
594
595
596Handle<FixedArray> ScriptCache::GetScripts() {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000597 Factory* factory = isolate_->factory();
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000598 Handle<FixedArray> instances = factory->NewFixedArray(occupancy());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000599 int count = 0;
600 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
601 ASSERT(entry->value != NULL);
602 if (entry->value != NULL) {
603 instances->set(count, *reinterpret_cast<Script**>(entry->value));
604 count++;
605 }
606 }
607 return instances;
608}
609
610
611void ScriptCache::ProcessCollectedScripts() {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000612 Debugger* debugger = isolate_->debugger();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000613 for (int i = 0; i < collected_scripts_.length(); i++) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000614 debugger->OnScriptCollected(collected_scripts_[i]);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000615 }
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());
hpayer@chromium.org4f99be92013-12-18 16:23:55 +0000626 GlobalHandles::ClearWeakness(location);
627 GlobalHandles::Destroy(location);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000628 }
629 // Clear the content of the hash map.
630 HashMap::Clear();
631}
632
633
hpayer@chromium.org4f99be92013-12-18 16:23:55 +0000634void ScriptCache::HandleWeakScript(
635 const v8::WeakCallbackData<v8::Value, void>& data) {
636 // Retrieve the script identifier.
637 Handle<Object> object = Utils::OpenHandle(*data.GetValue());
638 int id = Handle<Script>::cast(object)->id()->value();
639 void* key = reinterpret_cast<void*>(id);
640 uint32_t hash = Hash(id);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000641
hpayer@chromium.org4f99be92013-12-18 16:23:55 +0000642 // Remove the corresponding entry from the cache.
643 ScriptCache* script_cache =
644 reinterpret_cast<ScriptCache*>(data.GetParameter());
645 HashMap::Entry* entry = script_cache->Lookup(key, hash, false);
646 Object** location = reinterpret_cast<Object**>(entry->value);
647 script_cache->Remove(key, hash);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000648 script_cache->collected_scripts_.Add(id);
649
650 // Clear the weak handle.
hpayer@chromium.org4f99be92013-12-18 16:23:55 +0000651 GlobalHandles::Destroy(location);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000652}
653
654
hpayer@chromium.org4f99be92013-12-18 16:23:55 +0000655void Debug::HandleWeakDebugInfo(
656 const v8::WeakCallbackData<v8::Value, void>& data) {
657 Debug* debug = reinterpret_cast<Isolate*>(data.GetIsolate())->debug();
658 DebugInfoListNode* node =
659 reinterpret_cast<DebugInfoListNode*>(data.GetParameter());
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000660 // We need to clear all breakpoints associated with the function to restore
661 // original code and avoid patching the code twice later because
662 // the function will live in the heap until next gc, and can be found by
jkummerow@chromium.org78502a92012-09-06 13:50:42 +0000663 // Debug::FindSharedFunctionInfoInScript.
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000664 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
665 it.ClearAllDebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000666 debug->RemoveDebugInfo(node->debug_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000667#ifdef DEBUG
hpayer@chromium.org4f99be92013-12-18 16:23:55 +0000668 for (DebugInfoListNode* n = debug->debug_info_list_;
669 n != NULL;
670 n = n->next()) {
671 ASSERT(n != node);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000672 }
673#endif
674}
675
676
677DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
678 // Globalize the request debug info object and make it weak.
hpayer@chromium.org4f99be92013-12-18 16:23:55 +0000679 GlobalHandles* global_handles = debug_info->GetIsolate()->global_handles();
680 debug_info_ = Handle<DebugInfo>::cast(global_handles->Create(debug_info));
681 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(debug_info_.location()),
682 this,
683 Debug::HandleWeakDebugInfo);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000684}
685
686
687DebugInfoListNode::~DebugInfoListNode() {
hpayer@chromium.org4f99be92013-12-18 16:23:55 +0000688 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_.location()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000689}
690
691
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000692bool Debug::CompileDebuggerScript(Isolate* isolate, int index) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000693 Factory* factory = isolate->factory();
694 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000695
kasper.lund44510672008-07-25 07:37:58 +0000696 // Bail out if the index is invalid.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000697 if (index == -1) {
698 return false;
699 }
kasper.lund44510672008-07-25 07:37:58 +0000700
701 // Find source and name for the requested script.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000702 Handle<String> source_code =
lrn@chromium.org7516f052011-03-30 08:52:27 +0000703 isolate->bootstrapper()->NativesSourceLookup(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000704 Vector<const char> name = Natives::GetScriptName(index);
machenbach@chromium.org84960272014-04-18 00:05:16 +0000705 Handle<String> script_name =
706 factory->NewStringFromAscii(name).ToHandleChecked();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000707 Handle<Context> context = isolate->native_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000708
709 // Compile the script.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000710 Handle<SharedFunctionInfo> function_info;
yangguo@chromium.org49546742013-12-23 16:17:49 +0000711 function_info = Compiler::CompileScript(source_code,
712 script_name, 0, 0,
713 false,
714 context,
machenbach@chromium.org69f64b12014-03-20 01:04:55 +0000715 NULL, NULL, NO_CACHED_DATA,
yangguo@chromium.org49546742013-12-23 16:17:49 +0000716 NATIVES_CODE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000717
718 // Silently ignore stack overflows during compilation.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000719 if (function_info.is_null()) {
lrn@chromium.org7516f052011-03-30 08:52:27 +0000720 ASSERT(isolate->has_pending_exception());
721 isolate->clear_pending_exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000722 return false;
723 }
724
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000725 // Execute the shared function in the debugger context.
kasper.lund44510672008-07-25 07:37:58 +0000726 Handle<JSFunction> function =
lrn@chromium.org7516f052011-03-30 08:52:27 +0000727 factory->NewFunctionFromSharedFunctionInfo(function_info, context);
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000728
machenbach@chromium.org2ebef182014-04-14 00:05:03 +0000729 Handle<Object> exception;
730 MaybeHandle<Object> result =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000731 Execution::TryCall(function,
732 Handle<Object>(context->global_object(), isolate),
733 0,
734 NULL,
machenbach@chromium.org2ebef182014-04-14 00:05:03 +0000735 &exception);
kasper.lund44510672008-07-25 07:37:58 +0000736
737 // Check for caught exceptions.
machenbach@chromium.org2ebef182014-04-14 00:05:03 +0000738 if (result.is_null()) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000739 ASSERT(!isolate->has_pending_exception());
740 MessageLocation computed_location;
741 isolate->ComputeLocation(&computed_location);
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000742 Handle<Object> message = MessageHandler::MakeMessageObject(
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +0000743 isolate, "error_loading_debugger", &computed_location,
titzer@chromium.orgf5a24542014-03-04 09:06:17 +0000744 Vector<Handle<Object> >::empty(), Handle<JSArray>());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000745 ASSERT(!isolate->has_pending_exception());
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000746 if (!exception.is_null()) {
747 isolate->set_pending_exception(*exception);
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000748 MessageHandler::ReportMessage(isolate, NULL, message);
mmassi@chromium.org49a44672012-12-04 13:52:03 +0000749 isolate->clear_pending_exception();
750 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000751 return false;
752 }
753
kasper.lund44510672008-07-25 07:37:58 +0000754 // Mark this script as native and return successfully.
755 Handle<Script> script(Script::cast(function->shared()->script()));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000756 script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000757 return true;
758}
759
760
761bool Debug::Load() {
762 // Return if debugger is already loaded.
kasper.lund212ac232008-07-16 07:07:30 +0000763 if (IsLoaded()) return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000764
lrn@chromium.org7516f052011-03-30 08:52:27 +0000765 Debugger* debugger = isolate_->debugger();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000766
kasper.lund44510672008-07-25 07:37:58 +0000767 // Bail out if we're already in the process of compiling the native
768 // JavaScript source code for the debugger.
machenbach@chromium.orga3b66332014-05-13 00:04:55 +0000769 if (debugger->ignore_debugger()) return false;
kasper.lund44510672008-07-25 07:37:58 +0000770
machenbach@chromium.orga3b66332014-05-13 00:04:55 +0000771 Debugger::IgnoreScope during_load(debugger);
kasper.lund44510672008-07-25 07:37:58 +0000772 // Disable breakpoints and interrupts while compiling and running the
773 // debugger scripts including the context creation code.
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000774 DisableBreak disable(isolate_, true);
lrn@chromium.org7516f052011-03-30 08:52:27 +0000775 PostponeInterruptsScope postpone(isolate_);
kasper.lund44510672008-07-25 07:37:58 +0000776
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000777 // Create the debugger context.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000778 HandleScope scope(isolate_);
machenbach@chromium.org26ca35c2014-01-16 08:22:55 +0000779 ExtensionConfiguration no_extensions;
kasper.lund44510672008-07-25 07:37:58 +0000780 Handle<Context> context =
lrn@chromium.org7516f052011-03-30 08:52:27 +0000781 isolate_->bootstrapper()->CreateEnvironment(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000782 Handle<Object>::null(),
783 v8::Handle<ObjectTemplate>(),
machenbach@chromium.org26ca35c2014-01-16 08:22:55 +0000784 &no_extensions);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000785
fschneider@chromium.org7d10be52012-04-10 12:30:14 +0000786 // Fail if no context could be created.
787 if (context.is_null()) return false;
788
kasper.lund44510672008-07-25 07:37:58 +0000789 // Use the debugger context.
lrn@chromium.org7516f052011-03-30 08:52:27 +0000790 SaveContext save(isolate_);
791 isolate_->set_context(*context);
kasper.lund44510672008-07-25 07:37:58 +0000792
793 // Expose the builtins object in the debugger context.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +0000794 Handle<String> key = isolate_->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000795 STATIC_ASCII_VECTOR("builtins"));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000796 Handle<GlobalObject> global = Handle<GlobalObject>(context->global_object());
machenbach@chromium.org8f8fe812014-04-07 00:05:03 +0000797 RETURN_ON_EXCEPTION_VALUE(
lrn@chromium.org7516f052011-03-30 08:52:27 +0000798 isolate_,
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000799 JSReceiver::SetProperty(global,
800 key,
801 Handle<Object>(global->builtins(), isolate_),
802 NONE,
dslomov@chromium.org486536d2014-03-12 13:09:18 +0000803 SLOPPY),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000804 false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000805
806 // Compile the JavaScript for the debugger in the debugger context.
kasper.lund44510672008-07-25 07:37:58 +0000807 bool caught_exception =
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000808 !CompileDebuggerScript(isolate_, Natives::GetIndex("mirror")) ||
809 !CompileDebuggerScript(isolate_, Natives::GetIndex("debug"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000810
811 if (FLAG_enable_liveedit) {
812 caught_exception = caught_exception ||
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000813 !CompileDebuggerScript(isolate_, Natives::GetIndex("liveedit"));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000814 }
815
mads.s.agercbaa0602008-08-14 13:41:48 +0000816 // Make sure we mark the debugger as not loading before we might
817 // return.
mads.s.agercbaa0602008-08-14 13:41:48 +0000818
kasper.lund44510672008-07-25 07:37:58 +0000819 // Check for caught exceptions.
820 if (caught_exception) return false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000821
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000822 // Debugger loaded, create debugger context global handle.
823 debug_context_ = Handle<Context>::cast(
824 isolate_->global_handles()->Create(*context));
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000825
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000826 return true;
827}
828
829
830void Debug::Unload() {
831 // Return debugger is not loaded.
832 if (!IsLoaded()) {
833 return;
834 }
835
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000836 // Clear the script cache.
837 DestroyScriptCache();
838
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000839 // Clear debugger context global handle.
hpayer@chromium.org4f99be92013-12-18 16:23:55 +0000840 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_context_.location()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000841 debug_context_ = Handle<Context>();
842}
843
844
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000845Object* Debug::Break(Arguments args) {
846 Heap* heap = isolate_->heap();
847 HandleScope scope(isolate_);
mads.s.ager31e71382008-08-13 09:32:07 +0000848 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000849
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000850 thread_local_.frame_drop_mode_ = FRAMES_UNTOUCHED;
ager@chromium.org357bf652010-04-12 11:30:10 +0000851
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000852 // Get the top-most JavaScript frame.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000853 JavaScriptFrameIterator it(isolate_);
kasper.lundbd3ec4e2008-07-09 11:06:54 +0000854 JavaScriptFrame* frame = it.frame();
855
856 // Just continue if breaks are disabled or debugger cannot be loaded.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000857 if (disable_break() || !Load()) {
858 SetAfterBreakTarget(frame);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000859 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000860 }
861
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000862 // Enter the debugger.
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +0000863 EnterDebugger debugger(isolate_);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000864 if (debugger.FailedToEnter()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000865 return heap->undefined_value();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000866 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000867
kasper.lund44510672008-07-25 07:37:58 +0000868 // Postpone interrupt during breakpoint processing.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000869 PostponeInterruptsScope postpone(isolate_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000870
871 // Get the debug info (create it if it does not exist).
872 Handle<SharedFunctionInfo> shared =
danno@chromium.org169691d2013-07-15 08:01:13 +0000873 Handle<SharedFunctionInfo>(frame->function()->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000874 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
875
876 // Find the break point where execution has stopped.
877 BreakLocationIterator break_location_iterator(debug_info,
878 ALL_BREAK_LOCATIONS);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +0000879 // pc points to the instruction after the current one, possibly a break
880 // location as well. So the "- 1" to exclude it from the search.
881 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000882
883 // Check whether step next reached a new statement.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000884 if (!StepNextContinue(&break_location_iterator, frame)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000885 // Decrease steps left if performing multiple steps.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000886 if (thread_local_.step_count_ > 0) {
887 thread_local_.step_count_--;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000888 }
889 }
890
891 // If there is one or more real break points check whether any of these are
892 // triggered.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000893 Handle<Object> break_points_hit(heap->undefined_value(), isolate_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000894 if (break_location_iterator.HasBreakPoint()) {
895 Handle<Object> break_point_objects =
ulan@chromium.org09d7ab52013-02-25 15:50:35 +0000896 Handle<Object>(break_location_iterator.BreakPointObjects(), isolate_);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000897 break_points_hit = CheckBreakPoints(break_point_objects);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000898 }
899
ager@chromium.orga1645e22009-09-09 19:27:10 +0000900 // If step out is active skip everything until the frame where we need to step
901 // out to is reached, unless real breakpoint is hit.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000902 if (StepOutActive() && frame->fp() != step_out_fp() &&
ager@chromium.orga1645e22009-09-09 19:27:10 +0000903 break_points_hit->IsUndefined() ) {
904 // Step count should always be 0 for StepOut.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000905 ASSERT(thread_local_.step_count_ == 0);
ager@chromium.orga1645e22009-09-09 19:27:10 +0000906 } else if (!break_points_hit->IsUndefined() ||
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000907 (thread_local_.last_step_action_ != StepNone &&
908 thread_local_.step_count_ == 0)) {
ager@chromium.orga1645e22009-09-09 19:27:10 +0000909 // Notify debugger if a real break point is triggered or if performing
910 // single stepping with no more steps to perform. Otherwise do another step.
911
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000912 // Clear all current stepping setup.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000913 ClearStepping();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000914
lrn@chromium.org34e60782011-09-15 07:25:40 +0000915 if (thread_local_.queued_step_count_ > 0) {
916 // Perform queued steps
917 int step_count = thread_local_.queued_step_count_;
918
919 // Clear queue
920 thread_local_.queued_step_count_ = 0;
921
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000922 PrepareStep(StepNext, step_count, StackFrame::NO_ID);
lrn@chromium.org34e60782011-09-15 07:25:40 +0000923 } else {
924 // Notify the debug event listeners.
925 isolate_->debugger()->OnDebugBreak(break_points_hit, false);
926 }
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000927 } else if (thread_local_.last_step_action_ != StepNone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000928 // Hold on to last step action as it is cleared by the call to
929 // ClearStepping.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000930 StepAction step_action = thread_local_.last_step_action_;
931 int step_count = thread_local_.step_count_;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000932
lrn@chromium.org34e60782011-09-15 07:25:40 +0000933 // If StepNext goes deeper in code, StepOut until original frame
934 // and keep step count queued up in the meantime.
935 if (step_action == StepNext && frame->fp() < thread_local_.last_fp_) {
936 // Count frames until target frame
937 int count = 0;
938 JavaScriptFrameIterator it(isolate_);
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000939 while (!it.done() && it.frame()->fp() < thread_local_.last_fp_) {
lrn@chromium.org34e60782011-09-15 07:25:40 +0000940 count++;
941 it.Advance();
942 }
943
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000944 // Check that we indeed found the frame we are looking for.
945 CHECK(!it.done() && (it.frame()->fp() == thread_local_.last_fp_));
946 if (step_count > 1) {
947 // Save old count and action to continue stepping after StepOut.
948 thread_local_.queued_step_count_ = step_count - 1;
jkummerow@chromium.org212d9642012-05-11 15:02:09 +0000949 }
950
danno@chromium.org81cac2b2012-07-10 11:28:27 +0000951 // Set up for StepOut to reach target frame.
952 step_action = StepOut;
953 step_count = count;
lrn@chromium.org34e60782011-09-15 07:25:40 +0000954 }
955
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000956 // Clear all current stepping setup.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000957 ClearStepping();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000958
959 // Set up for the remaining steps.
dslomov@chromium.org639bac02013-09-09 11:58:54 +0000960 PrepareStep(step_action, step_count, StackFrame::NO_ID);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000961 }
962
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000963 if (thread_local_.frame_drop_mode_ == FRAMES_UNTOUCHED) {
964 SetAfterBreakTarget(frame);
965 } else if (thread_local_.frame_drop_mode_ ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000966 FRAME_DROPPED_IN_IC_CALL) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000967 // We must have been calling IC stub. Do not go there anymore.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000968 Code* plain_return = isolate_->builtins()->builtin(
969 Builtins::kPlainReturn_LiveEdit);
970 thread_local_.after_break_target_ = plain_return->entry();
971 } else if (thread_local_.frame_drop_mode_ ==
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000972 FRAME_DROPPED_IN_DEBUG_SLOT_CALL) {
973 // Debug break slot stub does not return normally, instead it manually
974 // cleans the stack and jumps. We should patch the jump address.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000975 Code* plain_return = isolate_->builtins()->builtin(
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000976 Builtins::kFrameDropper_LiveEdit);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000977 thread_local_.after_break_target_ = plain_return->entry();
978 } else if (thread_local_.frame_drop_mode_ ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000979 FRAME_DROPPED_IN_DIRECT_CALL) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000980 // Nothing to do, after_break_target is not used here.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000981 } else if (thread_local_.frame_drop_mode_ ==
982 FRAME_DROPPED_IN_RETURN_CALL) {
983 Code* plain_return = isolate_->builtins()->builtin(
984 Builtins::kFrameDropper_LiveEdit);
985 thread_local_.after_break_target_ = plain_return->entry();
ager@chromium.org357bf652010-04-12 11:30:10 +0000986 } else {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +0000987 UNREACHABLE();
ager@chromium.org357bf652010-04-12 11:30:10 +0000988 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000989
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000990 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000991}
992
993
machenbach@chromium.orga77ec9c2014-04-23 00:05:14 +0000994RUNTIME_FUNCTION(Debug_Break) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000995 return isolate->debug()->Break(args);
996}
997
998
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000999// Check the break point objects for whether one or more are actually
1000// triggered. This function returns a JSArray with the break point objects
1001// which is triggered.
1002Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001003 Factory* factory = isolate_->factory();
1004
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001005 // Count the number of break points hit. If there are multiple break points
1006 // they are in a FixedArray.
1007 Handle<FixedArray> break_points_hit;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001008 int break_points_hit_count = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009 ASSERT(!break_point_objects->IsUndefined());
1010 if (break_point_objects->IsFixedArray()) {
1011 Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
lrn@chromium.org7516f052011-03-30 08:52:27 +00001012 break_points_hit = factory->NewFixedArray(array->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001013 for (int i = 0; i < array->length(); i++) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001014 Handle<Object> o(array->get(i), isolate_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001015 if (CheckBreakPoint(o)) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001016 break_points_hit->set(break_points_hit_count++, *o);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001017 }
1018 }
1019 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001020 break_points_hit = factory->NewFixedArray(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001021 if (CheckBreakPoint(break_point_objects)) {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001022 break_points_hit->set(break_points_hit_count++, *break_point_objects);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001023 }
1024 }
1025
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001026 // Return undefined if no break points were triggered.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001027 if (break_points_hit_count == 0) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001028 return factory->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001029 }
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001030 // Return break points hit as a JSArray.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001031 Handle<JSArray> result = factory->NewJSArrayWithElements(break_points_hit);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001032 result->set_length(Smi::FromInt(break_points_hit_count));
1033 return result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001034}
1035
1036
1037// Check whether a single break point object is triggered.
1038bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001039 Factory* factory = isolate_->factory();
1040 HandleScope scope(isolate_);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001041
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001042 // Ignore check if break point object is not a JSObject.
1043 if (!break_point_object->IsJSObject()) return true;
1044
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001045 // Get the function IsBreakPointTriggered (defined in debug-debugger.js).
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00001046 Handle<String> is_break_point_triggered_string =
1047 factory->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001048 STATIC_ASCII_VECTOR("IsBreakPointTriggered"));
machenbach@chromium.org5b080562014-04-10 00:05:02 +00001049 Handle<GlobalObject> debug_global(debug_context()->global_object());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001050 Handle<JSFunction> check_break_point =
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00001051 Handle<JSFunction>::cast(Object::GetProperty(
1052 debug_global, is_break_point_triggered_string).ToHandleChecked());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001053
1054 // Get the break id as an object.
lrn@chromium.org7516f052011-03-30 08:52:27 +00001055 Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001056
1057 // Call HandleBreakPointx.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001058 Handle<Object> argv[] = { break_id, break_point_object };
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00001059 Handle<Object> result;
machenbach@chromium.orge9fd6582014-04-16 00:05:02 +00001060 if (!Execution::TryCall(check_break_point,
1061 isolate_->js_builtins_object(),
1062 ARRAY_SIZE(argv),
1063 argv).ToHandle(&result)) {
1064 return false;
1065 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001066
1067 // Return whether the break point is triggered.
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00001068 return result->IsTrue();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001069}
1070
1071
1072// Check whether the function has debug information.
1073bool Debug::HasDebugInfo(Handle<SharedFunctionInfo> shared) {
1074 return !shared->debug_info()->IsUndefined();
1075}
1076
1077
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001078// Return the debug info for this function. EnsureDebugInfo must be called
1079// prior to ensure the debug info has been generated for shared.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001080Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001081 ASSERT(HasDebugInfo(shared));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001082 return Handle<DebugInfo>(DebugInfo::cast(shared->debug_info()));
1083}
1084
1085
machenbach@chromium.orga7cc0282014-05-09 10:55:31 +00001086bool Debug::SetBreakPoint(Handle<JSFunction> function,
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001087 Handle<Object> break_point_object,
1088 int* source_position) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001089 HandleScope scope(isolate_);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001090
lrn@chromium.org34e60782011-09-15 07:25:40 +00001091 PrepareForBreakPoints();
1092
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001093 // Make sure the function is compiled and has set up the debug info.
1094 Handle<SharedFunctionInfo> shared(function->shared());
1095 if (!EnsureDebugInfo(shared, function)) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001096 // Return if retrieving debug info failed.
machenbach@chromium.orga7cc0282014-05-09 10:55:31 +00001097 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001098 }
1099
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001100 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001101 // Source positions starts with zero.
danno@chromium.orgbf0c8202011-12-27 10:09:42 +00001102 ASSERT(*source_position >= 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001103
1104 // Find the break point and change it.
1105 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00001106 it.FindBreakLocationFromPosition(*source_position, STATEMENT_ALIGNED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001107 it.SetBreakPoint(break_point_object);
1108
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001109 *source_position = it.position();
1110
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001111 // At least one active break point now.
machenbach@chromium.orga7cc0282014-05-09 10:55:31 +00001112 return debug_info->GetBreakPointCount() > 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001113}
1114
1115
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001116bool Debug::SetBreakPointForScript(Handle<Script> script,
1117 Handle<Object> break_point_object,
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00001118 int* source_position,
1119 BreakPositionAlignment alignment) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001120 HandleScope scope(isolate_);
1121
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00001122 PrepareForBreakPoints();
1123
1124 // Obtain shared function info for the function.
1125 Object* result = FindSharedFunctionInfoInScript(script, *source_position);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001126 if (result->IsUndefined()) return false;
1127
1128 // Make sure the function has set up the debug info.
1129 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
1130 if (!EnsureDebugInfo(shared, Handle<JSFunction>::null())) {
1131 // Return if retrieving debug info failed.
1132 return false;
1133 }
1134
1135 // Find position within function. The script position might be before the
1136 // source position of the first function.
1137 int position;
1138 if (shared->start_position() > *source_position) {
1139 position = 0;
1140 } else {
1141 position = *source_position - shared->start_position();
1142 }
1143
1144 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1145 // Source positions starts with zero.
1146 ASSERT(position >= 0);
1147
1148 // Find the break point and change it.
1149 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00001150 it.FindBreakLocationFromPosition(position, alignment);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001151 it.SetBreakPoint(break_point_object);
1152
1153 *source_position = it.position() + shared->start_position();
1154
1155 // At least one active break point now.
1156 ASSERT(debug_info->GetBreakPointCount() > 0);
1157 return true;
1158}
1159
1160
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001161void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001162 HandleScope scope(isolate_);
ager@chromium.org381abbb2009-02-25 13:23:22 +00001163
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001164 DebugInfoListNode* node = debug_info_list_;
1165 while (node != NULL) {
1166 Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(),
1167 break_point_object);
1168 if (!result->IsUndefined()) {
1169 // Get information in the break point.
1170 BreakPointInfo* break_point_info = BreakPointInfo::cast(result);
1171 Handle<DebugInfo> debug_info = node->debug_info();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172
1173 // Find the break point and clear it.
1174 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001175 it.FindBreakLocationFromAddress(debug_info->code()->entry() +
1176 break_point_info->code_position()->value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001177 it.ClearBreakPoint(break_point_object);
1178
1179 // If there are no more break points left remove the debug info for this
1180 // function.
1181 if (debug_info->GetBreakPointCount() == 0) {
1182 RemoveDebugInfo(debug_info);
1183 }
1184
1185 return;
1186 }
1187 node = node->next();
1188 }
1189}
1190
1191
ager@chromium.org381abbb2009-02-25 13:23:22 +00001192void Debug::ClearAllBreakPoints() {
1193 DebugInfoListNode* node = debug_info_list_;
1194 while (node != NULL) {
1195 // Remove all debug break code.
1196 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1197 it.ClearAllDebugBreak();
1198 node = node->next();
1199 }
1200
1201 // Remove all debug info.
1202 while (debug_info_list_ != NULL) {
1203 RemoveDebugInfo(debug_info_list_->debug_info());
1204 }
1205}
1206
1207
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001208void Debug::FloodWithOneShot(Handle<JSFunction> function) {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001209 PrepareForBreakPoints();
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001210
1211 // Make sure the function is compiled and has set up the debug info.
1212 Handle<SharedFunctionInfo> shared(function->shared());
1213 if (!EnsureDebugInfo(shared, function)) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001214 // Return if we failed to retrieve the debug info.
1215 return;
1216 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001217
1218 // Flood the function with break points.
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001219 BreakLocationIterator it(GetDebugInfo(shared), ALL_BREAK_LOCATIONS);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001220 while (!it.Done()) {
1221 it.SetOneShot();
1222 it.Next();
1223 }
1224}
1225
1226
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001227void Debug::FloodBoundFunctionWithOneShot(Handle<JSFunction> function) {
1228 Handle<FixedArray> new_bindings(function->function_bindings());
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001229 Handle<Object> bindee(new_bindings->get(JSFunction::kBoundFunctionIndex),
1230 isolate_);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001231
1232 if (!bindee.is_null() && bindee->IsJSFunction() &&
1233 !JSFunction::cast(*bindee)->IsBuiltin()) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001234 Handle<JSFunction> bindee_function(JSFunction::cast(*bindee));
1235 Debug::FloodWithOneShot(bindee_function);
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001236 }
1237}
1238
1239
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001240void Debug::FloodHandlerWithOneShot() {
ager@chromium.org8bb60582008-12-11 12:02:20 +00001241 // Iterate through the JavaScript stack looking for handlers.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001242 StackFrame::Id id = break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00001243 if (id == StackFrame::NO_ID) {
1244 // If there is no JavaScript stack don't do anything.
1245 return;
1246 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001247 for (JavaScriptFrameIterator it(isolate_, id); !it.done(); it.Advance()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001248 JavaScriptFrame* frame = it.frame();
1249 if (frame->HasHandler()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001250 // Flood the function with the catch block with break points
danno@chromium.org169691d2013-07-15 08:01:13 +00001251 FloodWithOneShot(Handle<JSFunction>(frame->function()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001252 return;
1253 }
1254 }
1255}
1256
1257
1258void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
1259 if (type == BreakUncaughtException) {
1260 break_on_uncaught_exception_ = enable;
1261 } else {
1262 break_on_exception_ = enable;
1263 }
1264}
1265
1266
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001267bool Debug::IsBreakOnException(ExceptionBreakType type) {
1268 if (type == BreakUncaughtException) {
1269 return break_on_uncaught_exception_;
1270 } else {
1271 return break_on_exception_;
1272 }
1273}
1274
1275
machenbach@chromium.orga86d4162014-05-01 00:05:11 +00001276void Debug::PromiseHandlePrologue(Handle<JSFunction> promise_getter) {
1277 Handle<JSFunction> promise_getter_global = Handle<JSFunction>::cast(
1278 isolate_->global_handles()->Create(*promise_getter));
1279 StackHandler* handler =
1280 StackHandler::FromAddress(Isolate::handler(isolate_->thread_local_top()));
1281 promise_getters_.Add(promise_getter_global);
1282 promise_catch_handlers_.Add(handler);
1283}
1284
1285
1286void Debug::PromiseHandleEpilogue() {
1287 if (promise_catch_handlers_.length() == 0) return;
1288 promise_catch_handlers_.RemoveLast();
1289 Handle<Object> promise_getter = promise_getters_.RemoveLast();
1290 isolate_->global_handles()->Destroy(promise_getter.location());
1291}
1292
1293
1294Handle<Object> Debug::GetPromiseForUncaughtException() {
1295 Handle<Object> undefined = isolate_->factory()->undefined_value();
1296 if (promise_getters_.length() == 0) return undefined;
1297 Handle<JSFunction> promise_getter = promise_getters_.last();
1298 StackHandler* promise_catch = promise_catch_handlers_.last();
1299 // Find the top-most try-catch handler.
1300 StackHandler* handler = StackHandler::FromAddress(
1301 Isolate::handler(isolate_->thread_local_top()));
1302 while (handler != NULL && !handler->is_catch()) {
1303 handler = handler->next();
1304 }
1305#ifdef DEBUG
1306 // Make sure that our promise catch handler is in the list of handlers,
1307 // even if it's not the top-most try-catch handler.
1308 StackHandler* temp = handler;
1309 while (temp != promise_catch && !temp->is_catch()) {
1310 temp = temp->next();
1311 CHECK(temp != NULL);
1312 }
1313#endif // DEBUG
1314
1315 if (handler == promise_catch) {
1316 return Execution::Call(
1317 isolate_, promise_getter, undefined, 0, NULL).ToHandleChecked();
1318 }
1319 return undefined;
1320}
1321
1322
dslomov@chromium.org639bac02013-09-09 11:58:54 +00001323void Debug::PrepareStep(StepAction step_action,
1324 int step_count,
1325 StackFrame::Id frame_id) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00001326 HandleScope scope(isolate_);
lrn@chromium.org34e60782011-09-15 07:25:40 +00001327
1328 PrepareForBreakPoints();
1329
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001330 ASSERT(Debug::InDebugger());
1331
1332 // Remember this step action and count.
1333 thread_local_.last_step_action_ = step_action;
ager@chromium.orga1645e22009-09-09 19:27:10 +00001334 if (step_action == StepOut) {
1335 // For step out target frame will be found on the stack so there is no need
1336 // to set step counter for it. It's expected to always be 0 for StepOut.
1337 thread_local_.step_count_ = 0;
1338 } else {
1339 thread_local_.step_count_ = step_count;
1340 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001341
1342 // Get the frame where the execution has stopped and skip the debug frame if
1343 // any. The debug frame will only be present if execution was stopped due to
1344 // hitting a break point. In other situations (e.g. unhandled exception) the
1345 // debug frame is not present.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001346 StackFrame::Id id = break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +00001347 if (id == StackFrame::NO_ID) {
1348 // If there is no JavaScript stack don't do anything.
1349 return;
1350 }
dslomov@chromium.org639bac02013-09-09 11:58:54 +00001351 if (frame_id != StackFrame::NO_ID) {
1352 id = frame_id;
1353 }
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00001354 JavaScriptFrameIterator frames_it(isolate_, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001355 JavaScriptFrame* frame = frames_it.frame();
1356
1357 // First of all ensure there is one-shot break points in the top handler
1358 // if any.
1359 FloodHandlerWithOneShot();
1360
1361 // If the function on the top frame is unresolved perform step out. This will
1362 // be the case when calling unknown functions and having the debugger stopped
1363 // in an unhandled exception.
1364 if (!frame->function()->IsJSFunction()) {
1365 // Step out: Find the calling JavaScript frame and flood it with
1366 // breakpoints.
1367 frames_it.Advance();
1368 // Fill the function to return to with one-shot break points.
danno@chromium.org169691d2013-07-15 08:01:13 +00001369 JSFunction* function = frames_it.frame()->function();
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001370 FloodWithOneShot(Handle<JSFunction>(function));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001371 return;
1372 }
1373
1374 // Get the debug info (create it if it does not exist).
danno@chromium.org169691d2013-07-15 08:01:13 +00001375 Handle<JSFunction> function(frame->function());
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001376 Handle<SharedFunctionInfo> shared(function->shared());
1377 if (!EnsureDebugInfo(shared, function)) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +00001378 // Return if ensuring debug info failed.
1379 return;
1380 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001381 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1382
1383 // Find the break location where execution has stopped.
1384 BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00001385 // pc points to the instruction after the current one, possibly a break
1386 // location as well. So the "- 1" to exclude it from the search.
1387 it.FindBreakLocationFromAddress(frame->pc() - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001388
1389 // Compute whether or not the target is a call target.
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001390 bool is_load_or_store = false;
1391 bool is_inline_cache_stub = false;
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001392 bool is_at_restarted_function = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +00001393 Handle<Code> call_function_stub;
ager@chromium.orga1645e22009-09-09 19:27:10 +00001394
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001395 if (thread_local_.restarter_frame_function_pointer_ == NULL) {
1396 if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) {
1397 bool is_call_target = false;
1398 Address target = it.rinfo()->target_address();
1399 Code* code = Code::GetCodeFromTargetAddress(target);
machenbach@chromium.orga86d4162014-05-01 00:05:11 +00001400 if (code->is_call_stub()) {
1401 is_call_target = true;
1402 }
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001403 if (code->is_inline_cache_stub()) {
1404 is_inline_cache_stub = true;
1405 is_load_or_store = !is_call_target;
1406 }
1407
1408 // Check if target code is CallFunction stub.
1409 Code* maybe_call_function_stub = code;
1410 // If there is a breakpoint at this line look at the original code to
1411 // check if it is a CallFunction stub.
1412 if (it.IsDebugBreak()) {
1413 Address original_target = it.original_rinfo()->target_address();
1414 maybe_call_function_stub =
1415 Code::GetCodeFromTargetAddress(original_target);
1416 }
machenbach@chromium.orga86d4162014-05-01 00:05:11 +00001417 if ((maybe_call_function_stub->kind() == Code::STUB &&
1418 maybe_call_function_stub->major_key() == CodeStub::CallFunction) ||
1419 maybe_call_function_stub->kind() == Code::CALL_IC) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001420 // Save reference to the code as we may need it to find out arguments
1421 // count for 'step in' later.
1422 call_function_stub = Handle<Code>(maybe_call_function_stub);
1423 }
ager@chromium.orga1645e22009-09-09 19:27:10 +00001424 }
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001425 } else {
1426 is_at_restarted_function = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001427 }
1428
v8.team.kasperl727e9952008-09-02 14:56:44 +00001429 // If this is the last break code target step out is the only possibility.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001430 if (it.IsExit() || step_action == StepOut) {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001431 if (step_action == StepOut) {
1432 // Skip step_count frames starting with the current one.
1433 while (step_count-- > 0 && !frames_it.done()) {
1434 frames_it.Advance();
1435 }
1436 } else {
1437 ASSERT(it.IsExit());
1438 frames_it.Advance();
1439 }
1440 // Skip builtin functions on the stack.
danno@chromium.org169691d2013-07-15 08:01:13 +00001441 while (!frames_it.done() && frames_it.frame()->function()->IsBuiltin()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001442 frames_it.Advance();
1443 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001444 // Step out: If there is a JavaScript caller frame, we need to
1445 // flood it with breakpoints.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001446 if (!frames_it.done()) {
1447 // Fill the function to return to with one-shot break points.
danno@chromium.org169691d2013-07-15 08:01:13 +00001448 JSFunction* function = frames_it.frame()->function();
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001449 FloodWithOneShot(Handle<JSFunction>(function));
ager@chromium.orga1645e22009-09-09 19:27:10 +00001450 // Set target frame pointer.
1451 ActivateStepOut(frames_it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001452 }
ager@chromium.orga1645e22009-09-09 19:27:10 +00001453 } else if (!(is_inline_cache_stub || RelocInfo::IsConstructCall(it.rmode()) ||
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001454 !call_function_stub.is_null() || is_at_restarted_function)
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001455 || step_action == StepNext || step_action == StepMin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001456 // Step next or step min.
1457
1458 // Fill the current function with one-shot break points.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001459 FloodWithOneShot(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460
1461 // Remember source position and frame to handle step next.
1462 thread_local_.last_statement_position_ =
1463 debug_info->code()->SourceStatementPosition(frame->pc());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001464 thread_local_.last_fp_ = frame->UnpaddedFP();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001465 } else {
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001466 // If there's restarter frame on top of the stack, just get the pointer
1467 // to function which is going to be restarted.
1468 if (is_at_restarted_function) {
1469 Handle<JSFunction> restarted_function(
1470 JSFunction::cast(*thread_local_.restarter_frame_function_pointer_));
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001471 FloodWithOneShot(restarted_function);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001472 } else if (!call_function_stub.is_null()) {
1473 // If it's CallFunction stub ensure target function is compiled and flood
1474 // it with one shot breakpoints.
machenbach@chromium.orga86d4162014-05-01 00:05:11 +00001475 bool is_call_ic = call_function_stub->kind() == Code::CALL_IC;
whesse@chromium.orge90029b2010-08-02 11:52:17 +00001476
ager@chromium.orga1645e22009-09-09 19:27:10 +00001477 // Find out number of arguments from the stub minor key.
1478 // Reverse lookup required as the minor key cannot be retrieved
1479 // from the code object.
1480 Handle<Object> obj(
lrn@chromium.org7516f052011-03-30 08:52:27 +00001481 isolate_->heap()->code_stubs()->SlowReverseLookup(
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001482 *call_function_stub),
1483 isolate_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001484 ASSERT(!obj.is_null());
1485 ASSERT(!(*obj)->IsUndefined());
ager@chromium.orga1645e22009-09-09 19:27:10 +00001486 ASSERT(obj->IsSmi());
1487 // Get the STUB key and extract major and minor key.
1488 uint32_t key = Smi::cast(*obj)->value();
1489 // Argc in the stub is the number of arguments passed - not the
1490 // expected arguments of the called function.
machenbach@chromium.orga86d4162014-05-01 00:05:11 +00001491 int call_function_arg_count = is_call_ic
1492 ? CallICStub::ExtractArgcFromMinorKey(CodeStub::MinorKeyFromKey(key))
1493 : CallFunctionStub::ExtractArgcFromMinorKey(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001494 CodeStub::MinorKeyFromKey(key));
machenbach@chromium.orga86d4162014-05-01 00:05:11 +00001495
1496 ASSERT(is_call_ic ||
1497 call_function_stub->major_key() == CodeStub::MajorKeyFromKey(key));
ager@chromium.orga1645e22009-09-09 19:27:10 +00001498
1499 // Find target function on the expression stack.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001500 // Expression stack looks like this (top to bottom):
ager@chromium.orga1645e22009-09-09 19:27:10 +00001501 // argN
1502 // ...
1503 // arg0
1504 // Receiver
1505 // Function to call
1506 int expressions_count = frame->ComputeExpressionsCount();
1507 ASSERT(expressions_count - 2 - call_function_arg_count >= 0);
1508 Object* fun = frame->GetExpression(
1509 expressions_count - 2 - call_function_arg_count);
machenbach@chromium.orga03ba1e2014-02-01 08:54:43 +00001510
1511 // Flood the actual target of call/apply.
1512 if (fun->IsJSFunction()) {
1513 Isolate* isolate = JSFunction::cast(fun)->GetIsolate();
1514 Code* apply = isolate->builtins()->builtin(Builtins::kFunctionApply);
1515 Code* call = isolate->builtins()->builtin(Builtins::kFunctionCall);
1516 while (fun->IsJSFunction()) {
1517 Code* code = JSFunction::cast(fun)->shared()->code();
1518 if (code != apply && code != call) break;
1519 fun = frame->GetExpression(
1520 expressions_count - 1 - call_function_arg_count);
1521 }
1522 }
1523
ager@chromium.orga1645e22009-09-09 19:27:10 +00001524 if (fun->IsJSFunction()) {
1525 Handle<JSFunction> js_function(JSFunction::cast(fun));
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001526 if (js_function->shared()->bound()) {
1527 Debug::FloodBoundFunctionWithOneShot(js_function);
1528 } else if (!js_function->IsBuiltin()) {
1529 // Don't step into builtins.
ager@chromium.orga1645e22009-09-09 19:27:10 +00001530 // It will also compile target function if it's not compiled yet.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001531 FloodWithOneShot(js_function);
ager@chromium.orga1645e22009-09-09 19:27:10 +00001532 }
1533 }
1534 }
1535
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001536 // Fill the current function with one-shot break points even for step in on
1537 // a call target as the function called might be a native function for
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001538 // which step in will not stop. It also prepares for stepping in
1539 // getters/setters.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001540 FloodWithOneShot(function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001541
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001542 if (is_load_or_store) {
1543 // Remember source position and frame to handle step in getter/setter. If
1544 // there is a custom getter/setter it will be handled in
1545 // Object::Get/SetPropertyWithCallback, otherwise the step action will be
1546 // propagated on the next Debug::Break.
1547 thread_local_.last_statement_position_ =
1548 debug_info->code()->SourceStatementPosition(frame->pc());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001549 thread_local_.last_fp_ = frame->UnpaddedFP();
kasperl@chromium.orge959c182009-07-27 08:59:04 +00001550 }
1551
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001552 // Step in or Step in min
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001553 it.PrepareStepIn(isolate_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001554 ActivateStepIn(frame);
1555 }
1556}
1557
1558
1559// Check whether the current debug break should be reported to the debugger. It
1560// is used to have step next and step in only report break back to the debugger
1561// if on a different frame or in a different statement. In some situations
1562// there will be several break points in the same statement when the code is
v8.team.kasperl727e9952008-09-02 14:56:44 +00001563// flooded with one-shot break points. This function helps to perform several
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001564// steps before reporting break back to the debugger.
1565bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
1566 JavaScriptFrame* frame) {
lrn@chromium.org34e60782011-09-15 07:25:40 +00001567 // StepNext and StepOut shouldn't bring us deeper in code, so last frame
1568 // shouldn't be a parent of current frame.
1569 if (thread_local_.last_step_action_ == StepNext ||
1570 thread_local_.last_step_action_ == StepOut) {
1571 if (frame->fp() < thread_local_.last_fp_) return true;
1572 }
1573
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574 // If the step last action was step next or step in make sure that a new
1575 // statement is hit.
1576 if (thread_local_.last_step_action_ == StepNext ||
1577 thread_local_.last_step_action_ == StepIn) {
1578 // Never continue if returning from function.
1579 if (break_location_iterator->IsExit()) return false;
1580
1581 // Continue if we are still on the same frame and in the same statement.
1582 int current_statement_position =
1583 break_location_iterator->code()->SourceStatementPosition(frame->pc());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001584 return thread_local_.last_fp_ == frame->UnpaddedFP() &&
ager@chromium.org236ad962008-09-25 09:45:57 +00001585 thread_local_.last_statement_position_ == current_statement_position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001586 }
1587
1588 // No step next action - don't continue.
1589 return false;
1590}
1591
1592
1593// Check whether the code object at the specified address is a debug break code
1594// object.
1595bool Debug::IsDebugBreak(Address addr) {
ager@chromium.org8bb60582008-12-11 12:02:20 +00001596 Code* code = Code::GetCodeFromTargetAddress(addr);
verwaest@chromium.orgec6855e2013-08-22 12:26:58 +00001597 return code->is_debug_stub() && code->extra_ic_state() == DEBUG_BREAK;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001598}
1599
1600
1601// Check whether a code stub with the specified major key is a possible break
1602// point location when looking for source break locations.
1603bool Debug::IsSourceBreakStub(Code* code) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001604 CodeStub::Major major_key = CodeStub::GetMajorKey(code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605 return major_key == CodeStub::CallFunction;
1606}
1607
1608
1609// Check whether a code stub with the specified major key is a possible break
1610// location.
1611bool Debug::IsBreakStub(Code* code) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001612 CodeStub::Major major_key = CodeStub::GetMajorKey(code);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001613 return major_key == CodeStub::CallFunction;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001614}
1615
1616
1617// Find the builtin to use for invoking the debug break
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001618Handle<Code> Debug::FindDebugBreak(Handle<Code> code, RelocInfo::Mode mode) {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00001619 Isolate* isolate = code->GetIsolate();
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001620
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001621 // Find the builtin debug break function matching the calling convention
1622 // used by the call site.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001623 if (code->is_inline_cache_stub()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001624 switch (code->kind()) {
machenbach@chromium.orga86d4162014-05-01 00:05:11 +00001625 case Code::CALL_IC:
1626 return isolate->builtins()->CallICStub_DebugBreak();
1627
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001628 case Code::LOAD_IC:
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001629 return isolate->builtins()->LoadIC_DebugBreak();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001630
1631 case Code::STORE_IC:
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001632 return isolate->builtins()->StoreIC_DebugBreak();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001633
1634 case Code::KEYED_LOAD_IC:
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001635 return isolate->builtins()->KeyedLoadIC_DebugBreak();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001636
1637 case Code::KEYED_STORE_IC:
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001638 return isolate->builtins()->KeyedStoreIC_DebugBreak();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001639
danno@chromium.orgf005df62013-04-30 16:36:45 +00001640 case Code::COMPARE_NIL_IC:
1641 return isolate->builtins()->CompareNilIC_DebugBreak();
1642
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001643 default:
1644 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001645 }
1646 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001647 if (RelocInfo::IsConstructCall(mode)) {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001648 if (code->has_function_cache()) {
1649 return isolate->builtins()->CallConstructStub_Recording_DebugBreak();
1650 } else {
1651 return isolate->builtins()->CallConstructStub_DebugBreak();
1652 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001653 }
1654 if (code->kind() == Code::STUB) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001655 ASSERT(code->major_key() == CodeStub::CallFunction);
machenbach@chromium.orga86d4162014-05-01 00:05:11 +00001656 return isolate->builtins()->CallFunctionStub_DebugBreak();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00001657 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001658
1659 UNREACHABLE();
1660 return Handle<Code>::null();
1661}
1662
1663
1664// Simple function for returning the source positions for active break points.
1665Handle<Object> Debug::GetSourceBreakLocations(
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00001666 Handle<SharedFunctionInfo> shared,
1667 BreakPositionAlignment position_alignment) {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00001668 Isolate* isolate = shared->GetIsolate();
lrn@chromium.org7516f052011-03-30 08:52:27 +00001669 Heap* heap = isolate->heap();
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001670 if (!HasDebugInfo(shared)) {
1671 return Handle<Object>(heap->undefined_value(), isolate);
1672 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001673 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1674 if (debug_info->GetBreakPointCount() == 0) {
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00001675 return Handle<Object>(heap->undefined_value(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001676 }
1677 Handle<FixedArray> locations =
lrn@chromium.org7516f052011-03-30 08:52:27 +00001678 isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001679 int count = 0;
1680 for (int i = 0; i < debug_info->break_points()->length(); i++) {
1681 if (!debug_info->break_points()->get(i)->IsUndefined()) {
1682 BreakPointInfo* break_point_info =
1683 BreakPointInfo::cast(debug_info->break_points()->get(i));
1684 if (break_point_info->GetBreakPointCount() > 0) {
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +00001685 Smi* position;
1686 switch (position_alignment) {
1687 case STATEMENT_ALIGNED:
1688 position = break_point_info->statement_position();
1689 break;
1690 case BREAK_POSITION_ALIGNED:
1691 position = break_point_info->source_position();
1692 break;
1693 default:
1694 UNREACHABLE();
1695 position = break_point_info->statement_position();
1696 }
1697
1698 locations->set(count++, position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001699 }
1700 }
1701 }
1702 return locations;
1703}
1704
1705
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001706void Debug::NewBreak(StackFrame::Id break_frame_id) {
1707 thread_local_.break_frame_id_ = break_frame_id;
1708 thread_local_.break_id_ = ++thread_local_.break_count_;
1709}
1710
1711
1712void Debug::SetBreak(StackFrame::Id break_frame_id, int break_id) {
1713 thread_local_.break_frame_id_ = break_frame_id;
1714 thread_local_.break_id_ = break_id;
1715}
1716
1717
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001718// Handle stepping into a function.
1719void Debug::HandleStepIn(Handle<JSFunction> function,
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001720 Handle<Object> holder,
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001721 Address fp,
1722 bool is_constructor) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001723 Isolate* isolate = function->GetIsolate();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001724 // If the frame pointer is not supplied by the caller find it.
1725 if (fp == 0) {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001726 StackFrameIterator it(isolate);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001727 it.Advance();
1728 // For constructor functions skip another frame.
1729 if (is_constructor) {
1730 ASSERT(it.frame()->is_construct());
1731 it.Advance();
1732 }
1733 fp = it.frame()->fp();
1734 }
1735
1736 // Flood the function with one-shot break points if it is called from where
1737 // step into was requested.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001738 if (fp == step_in_fp()) {
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001739 if (function->shared()->bound()) {
1740 // Handle Function.prototype.bind
1741 Debug::FloodBoundFunctionWithOneShot(function);
1742 } else if (!function->IsBuiltin()) {
1743 // Don't allow step into functions in the native context.
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001744 if (function->shared()->code() ==
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001745 isolate->builtins()->builtin(Builtins::kFunctionApply) ||
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001746 function->shared()->code() ==
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001747 isolate->builtins()->builtin(Builtins::kFunctionCall)) {
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001748 // Handle function.apply and function.call separately to flood the
1749 // function to be called and not the code for Builtins::FunctionApply or
kasperl@chromium.orgdefbd102009-07-13 14:04:26 +00001750 // Builtins::FunctionCall. The receiver of call/apply is the target
1751 // function.
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001752 if (!holder.is_null() && holder->IsJSFunction()) {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001753 Handle<JSFunction> js_function = Handle<JSFunction>::cast(holder);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001754 if (!js_function->IsBuiltin()) {
1755 Debug::FloodWithOneShot(js_function);
1756 } else if (js_function->shared()->bound()) {
1757 // Handle Function.prototype.bind
1758 Debug::FloodBoundFunctionWithOneShot(js_function);
1759 }
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001760 }
1761 } else {
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001762 Debug::FloodWithOneShot(function);
kasperl@chromium.orgacae3782009-04-11 09:17:08 +00001763 }
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001764 }
1765 }
1766}
1767
1768
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001769void Debug::ClearStepping() {
1770 // Clear the various stepping setup.
1771 ClearOneShot();
1772 ClearStepIn();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001773 ClearStepOut();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001774 ClearStepNext();
1775
1776 // Clear multiple step counter.
1777 thread_local_.step_count_ = 0;
1778}
1779
mstarzinger@chromium.orge0e1b0d2013-07-08 08:38:06 +00001780
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001781// Clears all the one-shot break points that are currently set. Normally this
1782// function is called each time a break point is hit as one shot break points
1783// are used to support stepping.
1784void Debug::ClearOneShot() {
1785 // The current implementation just runs through all the breakpoints. When the
v8.team.kasperl727e9952008-09-02 14:56:44 +00001786 // last break point for a function is removed that function is automatically
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001787 // removed from the list.
1788
1789 DebugInfoListNode* node = debug_info_list_;
1790 while (node != NULL) {
1791 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1792 while (!it.Done()) {
1793 it.ClearOneShot();
1794 it.Next();
1795 }
1796 node = node->next();
1797 }
1798}
1799
1800
1801void Debug::ActivateStepIn(StackFrame* frame) {
ager@chromium.orga1645e22009-09-09 19:27:10 +00001802 ASSERT(!StepOutActive());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001803 thread_local_.step_into_fp_ = frame->UnpaddedFP();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001804}
1805
1806
1807void Debug::ClearStepIn() {
1808 thread_local_.step_into_fp_ = 0;
1809}
1810
1811
ager@chromium.orga1645e22009-09-09 19:27:10 +00001812void Debug::ActivateStepOut(StackFrame* frame) {
1813 ASSERT(!StepInActive());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001814 thread_local_.step_out_fp_ = frame->UnpaddedFP();
ager@chromium.orga1645e22009-09-09 19:27:10 +00001815}
1816
1817
1818void Debug::ClearStepOut() {
1819 thread_local_.step_out_fp_ = 0;
1820}
1821
1822
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001823void Debug::ClearStepNext() {
1824 thread_local_.last_step_action_ = StepNone;
ager@chromium.org236ad962008-09-25 09:45:57 +00001825 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001826 thread_local_.last_fp_ = 0;
1827}
1828
1829
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001830static void CollectActiveFunctionsFromThread(
1831 Isolate* isolate,
1832 ThreadLocalTop* top,
1833 List<Handle<JSFunction> >* active_functions,
1834 Object* active_code_marker) {
1835 // Find all non-optimized code functions with activation frames
1836 // on the stack. This includes functions which have optimized
1837 // activations (including inlined functions) on the stack as the
1838 // non-optimized code is needed for the lazy deoptimization.
1839 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
1840 JavaScriptFrame* frame = it.frame();
1841 if (frame->is_optimized()) {
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00001842 List<JSFunction*> functions(FLAG_max_inlining_levels + 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001843 frame->GetFunctions(&functions);
1844 for (int i = 0; i < functions.length(); i++) {
1845 JSFunction* function = functions[i];
1846 active_functions->Add(Handle<JSFunction>(function));
1847 function->shared()->code()->set_gc_metadata(active_code_marker);
1848 }
1849 } else if (frame->function()->IsJSFunction()) {
danno@chromium.org169691d2013-07-15 08:01:13 +00001850 JSFunction* function = frame->function();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001851 ASSERT(frame->LookupCode()->kind() == Code::FUNCTION);
1852 active_functions->Add(Handle<JSFunction>(function));
1853 function->shared()->code()->set_gc_metadata(active_code_marker);
1854 }
1855 }
1856}
1857
1858
machenbach@chromium.orgaf6f6992014-05-06 00:04:47 +00001859// Figure out how many bytes of "pc_offset" correspond to actual code by
1860// subtracting off the bytes that correspond to constant/veneer pools. See
1861// Assembler::CheckConstPool() and Assembler::CheckVeneerPool(). Note that this
1862// is only useful for architectures using constant pools or veneer pools.
1863static int ComputeCodeOffsetFromPcOffset(Code *code, int pc_offset) {
1864 ASSERT_EQ(code->kind(), Code::FUNCTION);
1865 ASSERT(!code->has_debug_break_slots());
1866 ASSERT_LE(0, pc_offset);
1867 ASSERT_LT(pc_offset, code->instruction_end() - code->instruction_start());
1868
1869 int mask = RelocInfo::ModeMask(RelocInfo::CONST_POOL) |
1870 RelocInfo::ModeMask(RelocInfo::VENEER_POOL);
1871 byte *pc = code->instruction_start() + pc_offset;
1872 int code_offset = pc_offset;
1873 for (RelocIterator it(code, mask); !it.done(); it.next()) {
1874 RelocInfo* info = it.rinfo();
1875 if (info->pc() >= pc) break;
1876 ASSERT(RelocInfo::IsConstPool(info->rmode()));
1877 code_offset -= static_cast<int>(info->data());
1878 ASSERT_LE(0, code_offset);
1879 }
1880
1881 return code_offset;
1882}
1883
1884
1885// The inverse of ComputeCodeOffsetFromPcOffset.
1886static int ComputePcOffsetFromCodeOffset(Code *code, int code_offset) {
1887 ASSERT_EQ(code->kind(), Code::FUNCTION);
1888
1889 int mask = RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) |
1890 RelocInfo::ModeMask(RelocInfo::CONST_POOL) |
1891 RelocInfo::ModeMask(RelocInfo::VENEER_POOL);
1892 int reloc = 0;
1893 for (RelocIterator it(code, mask); !it.done(); it.next()) {
1894 RelocInfo* info = it.rinfo();
1895 if (info->pc() - code->instruction_start() - reloc >= code_offset) break;
1896 if (RelocInfo::IsDebugBreakSlot(info->rmode())) {
1897 reloc += Assembler::kDebugBreakSlotLength;
1898 } else {
1899 ASSERT(RelocInfo::IsConstPool(info->rmode()));
1900 reloc += static_cast<int>(info->data());
1901 }
1902 }
1903
1904 int pc_offset = code_offset + reloc;
1905
1906 ASSERT_LT(code->instruction_start() + pc_offset, code->instruction_end());
1907
1908 return pc_offset;
1909}
1910
1911
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001912static void RedirectActivationsToRecompiledCodeOnThread(
1913 Isolate* isolate,
1914 ThreadLocalTop* top) {
1915 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
1916 JavaScriptFrame* frame = it.frame();
1917
1918 if (frame->is_optimized() || !frame->function()->IsJSFunction()) continue;
1919
danno@chromium.org169691d2013-07-15 08:01:13 +00001920 JSFunction* function = frame->function();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001921
1922 ASSERT(frame->LookupCode()->kind() == Code::FUNCTION);
1923
1924 Handle<Code> frame_code(frame->LookupCode());
1925 if (frame_code->has_debug_break_slots()) continue;
1926
1927 Handle<Code> new_code(function->shared()->code());
1928 if (new_code->kind() != Code::FUNCTION ||
1929 !new_code->has_debug_break_slots()) {
1930 continue;
1931 }
1932
machenbach@chromium.orgaf6f6992014-05-06 00:04:47 +00001933 int old_pc_offset =
1934 static_cast<int>(frame->pc() - frame_code->instruction_start());
1935 int code_offset = ComputeCodeOffsetFromPcOffset(*frame_code, old_pc_offset);
1936 int new_pc_offset = ComputePcOffsetFromCodeOffset(*new_code, code_offset);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001937
1938 // Compute the equivalent pc in the new code.
machenbach@chromium.orgaf6f6992014-05-06 00:04:47 +00001939 byte* new_pc = new_code->instruction_start() + new_pc_offset;
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001940
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001941 if (FLAG_trace_deopt) {
1942 PrintF("Replacing code %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) "
1943 "with %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) "
1944 "for debugging, "
1945 "changing pc from %08" V8PRIxPTR " to %08" V8PRIxPTR "\n",
1946 reinterpret_cast<intptr_t>(
1947 frame_code->instruction_start()),
1948 reinterpret_cast<intptr_t>(
1949 frame_code->instruction_start()) +
1950 frame_code->instruction_size(),
1951 frame_code->instruction_size(),
1952 reinterpret_cast<intptr_t>(new_code->instruction_start()),
1953 reinterpret_cast<intptr_t>(new_code->instruction_start()) +
1954 new_code->instruction_size(),
1955 new_code->instruction_size(),
1956 reinterpret_cast<intptr_t>(frame->pc()),
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001957 reinterpret_cast<intptr_t>(new_pc));
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001958 }
1959
1960 // Patch the return address to return into the code with
1961 // debug break slots.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001962 frame->set_pc(new_pc);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00001963 }
1964}
1965
1966
1967class ActiveFunctionsCollector : public ThreadVisitor {
1968 public:
1969 explicit ActiveFunctionsCollector(List<Handle<JSFunction> >* active_functions,
1970 Object* active_code_marker)
1971 : active_functions_(active_functions),
1972 active_code_marker_(active_code_marker) { }
1973
1974 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
1975 CollectActiveFunctionsFromThread(isolate,
1976 top,
1977 active_functions_,
1978 active_code_marker_);
1979 }
1980
1981 private:
1982 List<Handle<JSFunction> >* active_functions_;
1983 Object* active_code_marker_;
1984};
1985
1986
1987class ActiveFunctionsRedirector : public ThreadVisitor {
1988 public:
1989 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
1990 RedirectActivationsToRecompiledCodeOnThread(isolate, top);
1991 }
1992};
1993
1994
machenbach@chromium.orga7cc0282014-05-09 10:55:31 +00001995void Debug::EnsureFunctionHasDebugBreakSlots(Handle<JSFunction> function) {
1996 if (function->code()->kind() == Code::FUNCTION &&
1997 function->code()->has_debug_break_slots()) {
1998 // Nothing to do. Function code already had debug break slots.
1999 return;
2000 }
machenbach@chromium.orga7cc0282014-05-09 10:55:31 +00002001 // Make sure that the shared full code is compiled with debug
2002 // break slots.
2003 if (!function->shared()->code()->has_debug_break_slots()) {
machenbach@chromium.orga7cc0282014-05-09 10:55:31 +00002004 MaybeHandle<Code> code = Compiler::GetCodeForDebugging(function);
2005 // Recompilation can fail. In that case leave the code as it was.
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00002006 if (!code.is_null()) function->ReplaceCode(*code.ToHandleChecked());
2007 } else {
2008 // Simply use shared code if it has debug break slots.
2009 function->ReplaceCode(function->shared()->code());
machenbach@chromium.orga7cc0282014-05-09 10:55:31 +00002010 }
machenbach@chromium.orgaf6f6992014-05-06 00:04:47 +00002011}
2012
2013
2014void Debug::RecompileAndRelocateSuspendedGenerators(
2015 const List<Handle<JSGeneratorObject> > &generators) {
2016 for (int i = 0; i < generators.length(); i++) {
2017 Handle<JSFunction> fun(generators[i]->function());
2018
machenbach@chromium.orga7cc0282014-05-09 10:55:31 +00002019 EnsureFunctionHasDebugBreakSlots(fun);
machenbach@chromium.orgaf6f6992014-05-06 00:04:47 +00002020
2021 int code_offset = generators[i]->continuation();
2022 int pc_offset = ComputePcOffsetFromCodeOffset(fun->code(), code_offset);
2023 generators[i]->set_continuation(pc_offset);
2024 }
2025}
2026
2027
lrn@chromium.org34e60782011-09-15 07:25:40 +00002028void Debug::PrepareForBreakPoints() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002029 // If preparing for the first break point make sure to deoptimize all
2030 // functions as debugging does not work with optimized code.
2031 if (!has_break_points_) {
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00002032 if (isolate_->concurrent_recompilation_enabled()) {
danno@chromium.org59400602013-08-13 17:09:37 +00002033 isolate_->optimizing_compiler_thread()->Flush();
2034 }
2035
svenpanne@chromium.org876cca82013-03-18 14:43:20 +00002036 Deoptimizer::DeoptimizeAll(isolate_);
lrn@chromium.org34e60782011-09-15 07:25:40 +00002037
yangguo@chromium.org49546742013-12-23 16:17:49 +00002038 Handle<Code> lazy_compile = isolate_->builtins()->CompileUnoptimized();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002039
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002040 // There will be at least one break point when we are done.
2041 has_break_points_ = true;
2042
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002043 // Keep the list of activated functions in a handlified list as it
2044 // is used both in GC and non-GC code.
2045 List<Handle<JSFunction> > active_functions(100);
lrn@chromium.org34e60782011-09-15 07:25:40 +00002046
machenbach@chromium.orgaf6f6992014-05-06 00:04:47 +00002047 // A list of all suspended generators.
2048 List<Handle<JSGeneratorObject> > suspended_generators;
2049
2050 // A list of all generator functions. We need to recompile all functions,
2051 // but we don't know until after visiting the whole heap which generator
2052 // functions have suspended activations and which do not. As in the case of
2053 // functions with activations on the stack, we need to be careful with
2054 // generator functions with suspended activations because although they
2055 // should be recompiled, recompilation can fail, and we need to avoid
2056 // leaving the heap in an inconsistent state.
2057 //
2058 // We could perhaps avoid this list and instead re-use the GC metadata
2059 // links.
2060 List<Handle<JSFunction> > generator_functions;
2061
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002062 {
2063 // We are going to iterate heap to find all functions without
2064 // debug break slots.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002065 Heap* heap = isolate_->heap();
2066 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
2067 "preparing for breakpoints");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002068
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002069 // Ensure no GC in this scope as we are going to use gc_metadata
2070 // field in the Code object to mark active functions.
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002071 DisallowHeapAllocation no_allocation;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002072
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002073 Object* active_code_marker = heap->the_hole_value();
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00002074
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002075 CollectActiveFunctionsFromThread(isolate_,
2076 isolate_->thread_local_top(),
2077 &active_functions,
2078 active_code_marker);
2079 ActiveFunctionsCollector active_functions_collector(&active_functions,
2080 active_code_marker);
2081 isolate_->thread_manager()->IterateArchivedThreads(
2082 &active_functions_collector);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002083
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002084 // Scan the heap for all non-optimized functions which have no
2085 // debug break slots and are not active or inlined into an active
2086 // function and mark them for lazy compilation.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002087 HeapIterator iterator(heap);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002088 HeapObject* obj = NULL;
2089 while (((obj = iterator.next()) != NULL)) {
2090 if (obj->IsJSFunction()) {
2091 JSFunction* function = JSFunction::cast(obj);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002092 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002093
2094 if (!shared->allows_lazy_compilation()) continue;
2095 if (!shared->script()->IsScript()) continue;
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +00002096 if (function->IsBuiltin()) continue;
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002097 if (shared->code()->gc_metadata() == active_code_marker) continue;
2098
machenbach@chromium.orgaf6f6992014-05-06 00:04:47 +00002099 if (shared->is_generator()) {
2100 generator_functions.Add(Handle<JSFunction>(function, isolate_));
2101 continue;
2102 }
2103
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002104 Code::Kind kind = function->code()->kind();
2105 if (kind == Code::FUNCTION &&
2106 !function->code()->has_debug_break_slots()) {
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00002107 function->ReplaceCode(*lazy_compile);
2108 function->shared()->ReplaceCode(*lazy_compile);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002109 } else if (kind == Code::BUILTIN &&
yangguo@chromium.org49546742013-12-23 16:17:49 +00002110 (function->IsInOptimizationQueue() ||
2111 function->IsMarkedForOptimization() ||
2112 function->IsMarkedForConcurrentOptimization())) {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002113 // Abort in-flight compilation.
2114 Code* shared_code = function->shared()->code();
2115 if (shared_code->kind() == Code::FUNCTION &&
2116 shared_code->has_debug_break_slots()) {
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00002117 function->ReplaceCode(shared_code);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002118 } else {
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00002119 function->ReplaceCode(*lazy_compile);
2120 function->shared()->ReplaceCode(*lazy_compile);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002121 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002122 }
machenbach@chromium.orgaf6f6992014-05-06 00:04:47 +00002123 } else if (obj->IsJSGeneratorObject()) {
2124 JSGeneratorObject* gen = JSGeneratorObject::cast(obj);
2125 if (!gen->is_suspended()) continue;
2126
2127 JSFunction* fun = gen->function();
2128 ASSERT_EQ(fun->code()->kind(), Code::FUNCTION);
2129 if (fun->code()->has_debug_break_slots()) continue;
2130
2131 int pc_offset = gen->continuation();
2132 ASSERT_LT(0, pc_offset);
2133
2134 int code_offset =
2135 ComputeCodeOffsetFromPcOffset(fun->code(), pc_offset);
2136
2137 // This will be fixed after we recompile the functions.
2138 gen->set_continuation(code_offset);
2139
2140 suspended_generators.Add(Handle<JSGeneratorObject>(gen, isolate_));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002141 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00002142 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00002143
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002144 // Clear gc_metadata field.
2145 for (int i = 0; i < active_functions.length(); i++) {
2146 Handle<JSFunction> function = active_functions[i];
2147 function->shared()->code()->set_gc_metadata(Smi::FromInt(0));
2148 }
2149 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002150
machenbach@chromium.orgaf6f6992014-05-06 00:04:47 +00002151 // Recompile generator functions that have suspended activations, and
2152 // relocate those activations.
2153 RecompileAndRelocateSuspendedGenerators(suspended_generators);
2154
2155 // Mark generator functions that didn't have suspended activations for lazy
2156 // recompilation. Note that this set does not include any active functions.
2157 for (int i = 0; i < generator_functions.length(); i++) {
2158 Handle<JSFunction> &function = generator_functions[i];
2159 if (function->code()->kind() != Code::FUNCTION) continue;
2160 if (function->code()->has_debug_break_slots()) continue;
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00002161 function->ReplaceCode(*lazy_compile);
2162 function->shared()->ReplaceCode(*lazy_compile);
machenbach@chromium.orgaf6f6992014-05-06 00:04:47 +00002163 }
2164
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002165 // Now recompile all functions with activation frames and and
machenbach@chromium.orgaf6f6992014-05-06 00:04:47 +00002166 // patch the return address to run in the new compiled code. It could be
2167 // that some active functions were recompiled already by the suspended
2168 // generator recompilation pass above; a generator with suspended
2169 // activations could also have active activations. That's fine.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002170 for (int i = 0; i < active_functions.length(); i++) {
2171 Handle<JSFunction> function = active_functions[i];
mmassi@chromium.org7028c052012-06-13 11:51:58 +00002172 Handle<SharedFunctionInfo> shared(function->shared());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002173
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002174 // If recompilation is not possible just skip it.
machenbach@chromium.orgaf6f6992014-05-06 00:04:47 +00002175 if (shared->is_toplevel()) continue;
2176 if (!shared->allows_lazy_compilation()) continue;
2177 if (shared->code()->kind() == Code::BUILTIN) continue;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002178
machenbach@chromium.orga7cc0282014-05-09 10:55:31 +00002179 EnsureFunctionHasDebugBreakSlots(function);
lrn@chromium.org34e60782011-09-15 07:25:40 +00002180 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00002181
2182 RedirectActivationsToRecompiledCodeOnThread(isolate_,
2183 isolate_->thread_local_top());
2184
2185 ActiveFunctionsRedirector active_functions_redirector;
2186 isolate_->thread_manager()->IterateArchivedThreads(
2187 &active_functions_redirector);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002188 }
lrn@chromium.org34e60782011-09-15 07:25:40 +00002189}
2190
2191
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002192Object* Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
2193 int position) {
2194 // Iterate the heap looking for SharedFunctionInfo generated from the
2195 // script. The inner most SharedFunctionInfo containing the source position
2196 // for the requested break point is found.
2197 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
2198 // which is found is not compiled it is compiled and the heap is iterated
2199 // again as the compilation might create inner functions from the newly
2200 // compiled function and the actual requested break point might be in one of
2201 // these functions.
2202 // NOTE: The below fix-point iteration depends on all functions that cannot be
2203 // compiled lazily without a context to not be compiled at all. Compilation
2204 // will be triggered at points where we do not need a context.
2205 bool done = false;
2206 // The current candidate for the source position:
2207 int target_start_position = RelocInfo::kNoPosition;
2208 Handle<JSFunction> target_function;
2209 Handle<SharedFunctionInfo> target;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002210 Heap* heap = isolate_->heap();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002211 while (!done) {
2212 { // Extra scope for iterator and no-allocation.
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002213 heap->EnsureHeapIsIterable();
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002214 DisallowHeapAllocation no_alloc_during_heap_iteration;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002215 HeapIterator iterator(heap);
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002216 for (HeapObject* obj = iterator.next();
2217 obj != NULL; obj = iterator.next()) {
2218 bool found_next_candidate = false;
2219 Handle<JSFunction> function;
2220 Handle<SharedFunctionInfo> shared;
2221 if (obj->IsJSFunction()) {
2222 function = Handle<JSFunction>(JSFunction::cast(obj));
2223 shared = Handle<SharedFunctionInfo>(function->shared());
2224 ASSERT(shared->allows_lazy_compilation() || shared->is_compiled());
2225 found_next_candidate = true;
2226 } else if (obj->IsSharedFunctionInfo()) {
2227 shared = Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(obj));
2228 // Skip functions that we cannot compile lazily without a context,
2229 // which is not available here, because there is no closure.
2230 found_next_candidate = shared->is_compiled() ||
2231 shared->allows_lazy_compilation_without_context();
2232 }
2233 if (!found_next_candidate) continue;
2234 if (shared->script() == *script) {
2235 // If the SharedFunctionInfo found has the requested script data and
2236 // contains the source position it is a candidate.
2237 int start_position = shared->function_token_position();
2238 if (start_position == RelocInfo::kNoPosition) {
2239 start_position = shared->start_position();
2240 }
2241 if (start_position <= position &&
2242 position <= shared->end_position()) {
2243 // If there is no candidate or this function is within the current
2244 // candidate this is the new candidate.
2245 if (target.is_null()) {
2246 target_start_position = start_position;
2247 target_function = function;
2248 target = shared;
2249 } else {
2250 if (target_start_position == start_position &&
2251 shared->end_position() == target->end_position()) {
2252 // If a top-level function contains only one function
2253 // declaration the source for the top-level and the function
2254 // is the same. In that case prefer the non top-level function.
2255 if (!shared->is_toplevel()) {
2256 target_start_position = start_position;
2257 target_function = function;
2258 target = shared;
2259 }
2260 } else if (target_start_position <= start_position &&
2261 shared->end_position() <= target->end_position()) {
2262 // This containment check includes equality as a function
2263 // inside a top-level function can share either start or end
2264 // position with the top-level function.
2265 target_start_position = start_position;
2266 target_function = function;
2267 target = shared;
2268 }
2269 }
2270 }
2271 }
2272 } // End for loop.
2273 } // End no-allocation scope.
2274
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002275 if (target.is_null()) return heap->undefined_value();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002276
2277 // There will be at least one break point when we are done.
2278 has_break_points_ = true;
2279
2280 // If the candidate found is compiled we are done.
2281 done = target->is_compiled();
2282 if (!done) {
2283 // If the candidate is not compiled, compile it to reveal any inner
2284 // functions which might contain the requested source position. This
2285 // will compile all inner functions that cannot be compiled without a
2286 // context, because Compiler::BuildFunctionInfo checks whether the
2287 // debugger is active.
machenbach@chromium.orga77ec9c2014-04-23 00:05:14 +00002288 MaybeHandle<Code> maybe_result = target_function.is_null()
yangguo@chromium.org49546742013-12-23 16:17:49 +00002289 ? Compiler::GetUnoptimizedCode(target)
2290 : Compiler::GetUnoptimizedCode(target_function);
machenbach@chromium.orga77ec9c2014-04-23 00:05:14 +00002291 if (maybe_result.is_null()) return isolate_->heap()->undefined_value();
jkummerow@chromium.org78502a92012-09-06 13:50:42 +00002292 }
2293 } // End while loop.
2294
2295 return *target;
2296}
2297
2298
lrn@chromium.org34e60782011-09-15 07:25:40 +00002299// Ensures the debug information is present for shared.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002300bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared,
2301 Handle<JSFunction> function) {
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002302 Isolate* isolate = shared->GetIsolate();
2303
lrn@chromium.org34e60782011-09-15 07:25:40 +00002304 // Return if we already have the debug info for shared.
2305 if (HasDebugInfo(shared)) {
2306 ASSERT(shared->is_compiled());
2307 return true;
2308 }
2309
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002310 // There will be at least one break point when we are done.
2311 has_break_points_ = true;
2312
2313 // Ensure function is compiled. Return false if this failed.
2314 if (!function.is_null() &&
yangguo@chromium.org49546742013-12-23 16:17:49 +00002315 !Compiler::EnsureCompiled(function, CLEAR_EXCEPTION)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002316 return false;
2317 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002318
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002319 // Create the debug info object.
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00002320 Handle<DebugInfo> debug_info = isolate->factory()->NewDebugInfo(shared);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002321
2322 // Add debug info to the list.
2323 DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
2324 node->set_next(debug_info_list_);
2325 debug_info_list_ = node;
2326
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002327 return true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002328}
2329
2330
2331void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
2332 ASSERT(debug_info_list_ != NULL);
2333 // Run through the debug info objects to find this one and remove it.
2334 DebugInfoListNode* prev = NULL;
2335 DebugInfoListNode* current = debug_info_list_;
2336 while (current != NULL) {
2337 if (*current->debug_info() == *debug_info) {
2338 // Unlink from list. If prev is NULL we are looking at the first element.
2339 if (prev == NULL) {
2340 debug_info_list_ = current->next();
2341 } else {
2342 prev->set_next(current->next());
2343 }
lrn@chromium.org7516f052011-03-30 08:52:27 +00002344 current->debug_info()->shared()->set_debug_info(
2345 isolate_->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002346 delete current;
2347
2348 // If there are no more debug info objects there are not more break
2349 // points.
2350 has_break_points_ = debug_info_list_ != NULL;
2351
2352 return;
2353 }
2354 // Move to next in list.
2355 prev = current;
2356 current = current->next();
2357 }
2358 UNREACHABLE();
2359}
2360
2361
2362void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002363 HandleScope scope(isolate_);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002364
lrn@chromium.org34e60782011-09-15 07:25:40 +00002365 PrepareForBreakPoints();
2366
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002367 // Get the executing function in which the debug break occurred.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002368 Handle<JSFunction> function(JSFunction::cast(frame->function()));
2369 Handle<SharedFunctionInfo> shared(function->shared());
2370 if (!EnsureDebugInfo(shared, function)) {
kasper.lundbd3ec4e2008-07-09 11:06:54 +00002371 // Return if we failed to retrieve the debug info.
2372 return;
2373 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002374 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
2375 Handle<Code> code(debug_info->code());
2376 Handle<Code> original_code(debug_info->original_code());
2377#ifdef DEBUG
2378 // Get the code which is actually executing.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002379 Handle<Code> frame_code(frame->LookupCode());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002380 ASSERT(frame_code.is_identical_to(code));
2381#endif
2382
2383 // Find the call address in the running code. This address holds the call to
2384 // either a DebugBreakXXX or to the debug break return entry code if the
2385 // break point is still active after processing the break point.
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002386 Address addr = frame->pc() - Assembler::kPatchDebugBreakSlotReturnOffset;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002387
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002388 // Check if the location is at JS exit or debug break slot.
ager@chromium.orga1645e22009-09-09 19:27:10 +00002389 bool at_js_return = false;
2390 bool break_at_js_return_active = false;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002391 bool at_debug_break_slot = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002392 RelocIterator it(debug_info->code());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002393 while (!it.done() && !at_js_return && !at_debug_break_slot) {
ager@chromium.org236ad962008-09-25 09:45:57 +00002394 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
ager@chromium.orga1645e22009-09-09 19:27:10 +00002395 at_js_return = (it.rinfo()->pc() ==
2396 addr - Assembler::kPatchReturnSequenceAddressOffset);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00002397 break_at_js_return_active = it.rinfo()->IsPatchedReturnSequence();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002398 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002399 if (RelocInfo::IsDebugBreakSlot(it.rinfo()->rmode())) {
2400 at_debug_break_slot = (it.rinfo()->pc() ==
2401 addr - Assembler::kPatchDebugBreakSlotAddressOffset);
2402 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002403 it.next();
2404 }
2405
2406 // Handle the jump to continue execution after break point depending on the
2407 // break location.
ager@chromium.orga1645e22009-09-09 19:27:10 +00002408 if (at_js_return) {
2409 // If the break point as return is still active jump to the corresponding
2410 // place in the original code. If not the break point was removed during
2411 // break point processing.
2412 if (break_at_js_return_active) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002413 addr += original_code->instruction_start() - code->instruction_start();
2414 }
2415
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00002416 // Move back to where the call instruction sequence started.
2417 thread_local_.after_break_target_ =
2418 addr - Assembler::kPatchReturnSequenceAddressOffset;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002419 } else if (at_debug_break_slot) {
2420 // Address of where the debug break slot starts.
2421 addr = addr - Assembler::kPatchDebugBreakSlotAddressOffset;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002422
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002423 // Continue just after the slot.
2424 thread_local_.after_break_target_ = addr + Assembler::kDebugBreakSlotLength;
machenbach@chromium.org97b98c92014-03-13 03:05:00 +00002425 } else if (IsDebugBreak(Assembler::target_address_at(addr, *code))) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002426 // We now know that there is still a debug break call at the target address,
2427 // so the break point is still there and the original code will hold the
2428 // address to jump to in order to complete the call which is replaced by a
2429 // call to DebugBreakXXX.
2430
2431 // Find the corresponding address in the original code.
2432 addr += original_code->instruction_start() - code->instruction_start();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002433
2434 // Install jump to the call address in the original code. This will be the
2435 // call which was overwritten by the call to DebugBreakXXX.
machenbach@chromium.org97b98c92014-03-13 03:05:00 +00002436 thread_local_.after_break_target_ =
2437 Assembler::target_address_at(addr, *original_code);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00002438 } else {
2439 // There is no longer a break point present. Don't try to look in the
2440 // original code as the running code will have the right address. This takes
2441 // care of the case where the last break point is removed from the function
2442 // and therefore no "original code" is available.
machenbach@chromium.org97b98c92014-03-13 03:05:00 +00002443 thread_local_.after_break_target_ =
2444 Assembler::target_address_at(addr, *code);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002445 }
2446}
2447
2448
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00002449bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002450 HandleScope scope(isolate_);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00002451
sgjesse@chromium.org6db88712011-07-11 11:41:22 +00002452 // If there are no break points this cannot be break at return, as
2453 // the debugger statement and stack guard bebug break cannot be at
2454 // return.
2455 if (!has_break_points_) {
2456 return false;
2457 }
2458
lrn@chromium.org34e60782011-09-15 07:25:40 +00002459 PrepareForBreakPoints();
2460
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00002461 // Get the executing function in which the debug break occurred.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00002462 Handle<JSFunction> function(JSFunction::cast(frame->function()));
2463 Handle<SharedFunctionInfo> shared(function->shared());
2464 if (!EnsureDebugInfo(shared, function)) {
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00002465 // Return if we failed to retrieve the debug info.
2466 return false;
2467 }
2468 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
2469 Handle<Code> code(debug_info->code());
2470#ifdef DEBUG
2471 // Get the code which is actually executing.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00002472 Handle<Code> frame_code(frame->LookupCode());
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00002473 ASSERT(frame_code.is_identical_to(code));
2474#endif
2475
2476 // Find the call address in the running code.
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002477 Address addr = frame->pc() - Assembler::kPatchDebugBreakSlotReturnOffset;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +00002478
2479 // Check if the location is at JS return.
2480 RelocIterator it(debug_info->code());
2481 while (!it.done()) {
2482 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
2483 return (it.rinfo()->pc() ==
2484 addr - Assembler::kPatchReturnSequenceAddressOffset);
2485 }
2486 it.next();
2487 }
2488 return false;
2489}
2490
2491
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00002492void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
whesse@chromium.orge90029b2010-08-02 11:52:17 +00002493 FrameDropMode mode,
2494 Object** restarter_frame_function_pointer) {
ulan@chromium.orgd9e468a2012-06-25 09:47:40 +00002495 if (mode != CURRENTLY_SET_MODE) {
2496 thread_local_.frame_drop_mode_ = mode;
2497 }
ager@chromium.org357bf652010-04-12 11:30:10 +00002498 thread_local_.break_frame_id_ = new_break_frame_id;
whesse@chromium.orge90029b2010-08-02 11:52:17 +00002499 thread_local_.restarter_frame_function_pointer_ =
2500 restarter_frame_function_pointer;
ager@chromium.org357bf652010-04-12 11:30:10 +00002501}
2502
2503
jkummerow@chromium.org212d9642012-05-11 15:02:09 +00002504const int Debug::FramePaddingLayout::kInitialSize = 1;
2505
2506
2507// Any even value bigger than kInitialSize as needed for stack scanning.
2508const int Debug::FramePaddingLayout::kPaddingValue = kInitialSize + 1;
2509
2510
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002511bool Debug::IsDebugGlobal(GlobalObject* global) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002512 return IsLoaded() && global == debug_context()->global_object();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002513}
2514
2515
ager@chromium.org32912102009-01-16 10:38:43 +00002516void Debug::ClearMirrorCache() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002517 PostponeInterruptsScope postpone(isolate_);
lrn@chromium.org7516f052011-03-30 08:52:27 +00002518 HandleScope scope(isolate_);
2519 ASSERT(isolate_->context() == *Debug::debug_context());
ager@chromium.org32912102009-01-16 10:38:43 +00002520
2521 // Clear the mirror cache.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002522 Handle<String> function_name = isolate_->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002523 STATIC_ASCII_VECTOR("ClearMirrorCache"));
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002524 Handle<Object> fun = Object::GetProperty(
2525 isolate_->global_object(), function_name).ToHandleChecked();
ager@chromium.org32912102009-01-16 10:38:43 +00002526 ASSERT(fun->IsJSFunction());
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002527 Execution::TryCall(
2528 Handle<JSFunction>::cast(fun),
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002529 Handle<JSObject>(Debug::debug_context()->global_object()),
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002530 0,
2531 NULL);
ager@chromium.org32912102009-01-16 10:38:43 +00002532}
2533
2534
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002535void Debug::CreateScriptCache() {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002536 Heap* heap = isolate_->heap();
2537 HandleScope scope(isolate_);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002538
2539 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
2540 // rid of all the cached script wrappers and the second gets rid of the
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002541 // scripts which are no longer referenced. The second also sweeps precisely,
2542 // which saves us doing yet another GC to make the heap iterable.
rossberg@chromium.org994edf62012-02-06 10:12:55 +00002543 heap->CollectAllGarbage(Heap::kNoGCFlags, "Debug::CreateScriptCache");
2544 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
2545 "Debug::CreateScriptCache");
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002546
2547 ASSERT(script_cache_ == NULL);
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00002548 script_cache_ = new ScriptCache(isolate_);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002549
2550 // Scan heap for Script objects.
2551 int count = 0;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002552 HeapIterator iterator(heap);
rossberg@chromium.org79e79022013-06-03 15:43:46 +00002553 DisallowHeapAllocation no_allocation;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002554
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002555 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
sgjesse@chromium.org152a0b02009-10-07 13:50:16 +00002556 if (obj->IsScript() && Script::cast(obj)->HasValidSource()) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002557 script_cache_->Add(Handle<Script>(Script::cast(obj)));
2558 count++;
2559 }
2560 }
2561}
2562
2563
2564void Debug::DestroyScriptCache() {
2565 // Get rid of the script cache if it was created.
2566 if (script_cache_ != NULL) {
2567 delete script_cache_;
2568 script_cache_ = NULL;
2569 }
2570}
2571
2572
2573void Debug::AddScriptToScriptCache(Handle<Script> script) {
2574 if (script_cache_ != NULL) {
2575 script_cache_->Add(script);
2576 }
2577}
2578
2579
2580Handle<FixedArray> Debug::GetLoadedScripts() {
2581 // Create and fill the script cache when the loaded scripts is requested for
2582 // the first time.
2583 if (script_cache_ == NULL) {
2584 CreateScriptCache();
2585 }
2586
2587 // If the script cache is not active just return an empty array.
2588 ASSERT(script_cache_ != NULL);
2589 if (script_cache_ == NULL) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002590 isolate_->factory()->NewFixedArray(0);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002591 }
2592
2593 // Perform GC to get unreferenced scripts evicted from the cache before
2594 // returning the content.
rossberg@chromium.org994edf62012-02-06 10:12:55 +00002595 isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags,
2596 "Debug::GetLoadedScripts");
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002597
2598 // Get the scripts from the cache.
2599 return script_cache_->GetScripts();
2600}
2601
2602
yangguo@chromium.org49546742013-12-23 16:17:49 +00002603void Debug::RecordEvalCaller(Handle<Script> script) {
2604 script->set_compilation_type(Script::COMPILATION_TYPE_EVAL);
2605 // For eval scripts add information on the function from which eval was
2606 // called.
2607 StackTraceFrameIterator it(script->GetIsolate());
2608 if (!it.done()) {
2609 script->set_eval_from_shared(it.frame()->function()->shared());
2610 Code* code = it.frame()->LookupCode();
2611 int offset = static_cast<int>(
2612 it.frame()->pc() - code->instruction_start());
2613 script->set_eval_from_instructions_offset(Smi::FromInt(offset));
2614 }
2615}
2616
2617
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002618void Debug::AfterGarbageCollection() {
2619 // Generate events for collected scripts.
2620 if (script_cache_ != NULL) {
2621 script_cache_->ProcessCollectedScripts();
2622 }
2623}
2624
2625
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002626Debugger::Debugger(Isolate* isolate)
machenbach@chromium.orga3b66332014-05-13 00:04:55 +00002627 : event_listener_(Handle<Object>()),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002628 event_listener_data_(Handle<Object>()),
machenbach@chromium.orga3b66332014-05-13 00:04:55 +00002629 is_active_(false),
2630 ignore_debugger_(false),
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00002631 live_edit_enabled_(true),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002632 never_unload_debugger_(false),
2633 message_handler_(NULL),
2634 debugger_unload_pending_(false),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002635 debug_message_dispatch_handler_(NULL),
2636 message_dispatch_helper_thread_(NULL),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002637 agent_(NULL),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002638 command_queue_(isolate->logger(), kQueueInitialSize),
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00002639 command_received_(0),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002640 event_command_queue_(isolate->logger(), kQueueInitialSize),
2641 isolate_(isolate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002642}
2643
2644
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00002645Debugger::~Debugger() {}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002646
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002647
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002648MaybeHandle<Object> Debugger::MakeJSObject(
2649 Vector<const char> constructor_name,
2650 int argc,
2651 Handle<Object> argv[]) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002652 ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002653
2654 // Create the execution state object.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002655 Handle<String> constructor_str =
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002656 isolate_->factory()->InternalizeUtf8String(constructor_name);
machenbach@chromium.orgb5ed9302014-03-25 13:44:35 +00002657 ASSERT(!constructor_str.is_null());
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002658 Handle<Object> constructor = Object::GetProperty(
2659 isolate_->global_object(), constructor_str).ToHandleChecked();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002660 ASSERT(constructor->IsJSFunction());
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002661 if (!constructor->IsJSFunction()) return MaybeHandle<Object>();
2662 return Execution::TryCall(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002663 Handle<JSFunction>::cast(constructor),
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002664 Handle<JSObject>(isolate_->debug()->debug_context()->global_object()),
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002665 argc,
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002666 argv);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002667}
2668
2669
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002670MaybeHandle<Object> Debugger::MakeExecutionState() {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002671 // Create the execution state object.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002672 Handle<Object> break_id = isolate_->factory()->NewNumberFromInt(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002673 isolate_->debug()->break_id());
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002674 Handle<Object> argv[] = { break_id };
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002675 return MakeJSObject(CStrVector("MakeExecutionState"), ARRAY_SIZE(argv), argv);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002676}
2677
2678
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002679MaybeHandle<Object> Debugger::MakeBreakEvent(Handle<Object> break_points_hit) {
2680 Handle<Object> exec_state;
machenbach@chromium.orge9fd6582014-04-16 00:05:02 +00002681 if (!MakeExecutionState().ToHandle(&exec_state)) return MaybeHandle<Object>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002682 // Create the new break event object.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002683 Handle<Object> argv[] = { exec_state, break_points_hit };
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002684 return MakeJSObject(CStrVector("MakeBreakEvent"), ARRAY_SIZE(argv), argv);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002685}
2686
2687
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002688MaybeHandle<Object> Debugger::MakeExceptionEvent(Handle<Object> exception,
machenbach@chromium.org865f51f2014-04-28 00:05:12 +00002689 bool uncaught,
2690 Handle<Object> promise) {
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002691 Handle<Object> exec_state;
machenbach@chromium.orge9fd6582014-04-16 00:05:02 +00002692 if (!MakeExecutionState().ToHandle(&exec_state)) return MaybeHandle<Object>();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002693 // Create the new exception event object.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002694 Handle<Object> argv[] = { exec_state,
2695 exception,
machenbach@chromium.org865f51f2014-04-28 00:05:12 +00002696 isolate_->factory()->ToBoolean(uncaught),
2697 promise };
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002698 return MakeJSObject(CStrVector("MakeExceptionEvent"), ARRAY_SIZE(argv), argv);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002699}
2700
2701
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002702MaybeHandle<Object> Debugger::MakeCompileEvent(Handle<Script> script,
2703 bool before) {
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002704 Handle<Object> exec_state;
machenbach@chromium.orge9fd6582014-04-16 00:05:02 +00002705 if (!MakeExecutionState().ToHandle(&exec_state)) return MaybeHandle<Object>();
2706 // Create the compile event object.
machenbach@chromium.org9fa61952014-04-17 00:05:12 +00002707 Handle<Object> script_wrapper = Script::GetWrapper(script);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002708 Handle<Object> argv[] = { exec_state,
2709 script_wrapper,
machenbach@chromium.orge9fd6582014-04-16 00:05:02 +00002710 isolate_->factory()->ToBoolean(before) };
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002711 return MakeJSObject(CStrVector("MakeCompileEvent"), ARRAY_SIZE(argv), argv);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002712}
2713
2714
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002715MaybeHandle<Object> Debugger::MakeScriptCollectedEvent(int id) {
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002716 Handle<Object> exec_state;
machenbach@chromium.orge9fd6582014-04-16 00:05:02 +00002717 if (!MakeExecutionState().ToHandle(&exec_state)) return MaybeHandle<Object>();
2718 // Create the script collected event object.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002719 Handle<Object> id_object = Handle<Smi>(Smi::FromInt(id), isolate_);
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002720 Handle<Object> argv[] = { exec_state, id_object };
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002721
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002722 return MakeJSObject(
2723 CStrVector("MakeScriptCollectedEvent"), ARRAY_SIZE(argv), argv);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002724}
2725
2726
machenbach@chromium.orga86d4162014-05-01 00:05:11 +00002727void Debugger::OnException(Handle<Object> exception, bool uncaught) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002728 HandleScope scope(isolate_);
2729 Debug* debug = isolate_->debug();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002730
2731 // Bail out based on state or if there is no listener for this event
lrn@chromium.org7516f052011-03-30 08:52:27 +00002732 if (debug->InDebugger()) return;
machenbach@chromium.orga3b66332014-05-13 00:04:55 +00002733 if (!Debugger::EventActive()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002734
machenbach@chromium.orga86d4162014-05-01 00:05:11 +00002735 Handle<Object> promise = debug->GetPromiseForUncaughtException();
2736 uncaught |= !promise->IsUndefined();
2737
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002738 // Bail out if exception breaks are not active
2739 if (uncaught) {
2740 // Uncaught exceptions are reported by either flags.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002741 if (!(debug->break_on_uncaught_exception() ||
2742 debug->break_on_exception())) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002743 } else {
2744 // Caught exceptions are reported is activated.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002745 if (!debug->break_on_exception()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002746 }
2747
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002748 // Enter the debugger.
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00002749 EnterDebugger debugger(isolate_);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002750 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002751
2752 // Clear all current stepping setup.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002753 debug->ClearStepping();
machenbach@chromium.org865f51f2014-04-28 00:05:12 +00002754
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002755 // Create the event data object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002756 Handle<Object> event_data;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002757 // Bail out and don't call debugger if exception.
machenbach@chromium.org865f51f2014-04-28 00:05:12 +00002758 if (!MakeExceptionEvent(
2759 exception, uncaught, promise).ToHandle(&event_data)) {
2760 return;
2761 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002762
ager@chromium.org5ec48922009-05-05 07:25:34 +00002763 // Process debug event.
machenbach@chromium.orga86d4162014-05-01 00:05:11 +00002764 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002765 // Return to continue execution from where the exception was thrown.
2766}
2767
2768
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002769void Debugger::OnDebugBreak(Handle<Object> break_points_hit,
2770 bool auto_continue) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002771 HandleScope scope(isolate_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002772
kasper.lund212ac232008-07-16 07:07:30 +00002773 // Debugger has already been entered by caller.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002774 ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
kasper.lund212ac232008-07-16 07:07:30 +00002775
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002776 // Bail out if there is no listener for this event
machenbach@chromium.orga3b66332014-05-13 00:04:55 +00002777 if (!Debugger::EventActive()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002778
2779 // Debugger must be entered in advance.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002780 ASSERT(isolate_->context() == *isolate_->debug()->debug_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002781
2782 // Create the event data object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002783 Handle<Object> event_data;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002784 // Bail out and don't call debugger if exception.
machenbach@chromium.orge9fd6582014-04-16 00:05:02 +00002785 if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002786
ager@chromium.org5ec48922009-05-05 07:25:34 +00002787 // Process debug event.
2788 ProcessDebugEvent(v8::Break,
2789 Handle<JSObject>::cast(event_data),
2790 auto_continue);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002791}
2792
2793
2794void Debugger::OnBeforeCompile(Handle<Script> script) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002795 HandleScope scope(isolate_);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002796
2797 // Bail out based on state or if there is no listener for this event
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002798 if (isolate_->debug()->InDebugger()) return;
machenbach@chromium.orga3b66332014-05-13 00:04:55 +00002799 if (!EventActive()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002800
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002801 // Enter the debugger.
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00002802 EnterDebugger debugger(isolate_);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002803 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002804
2805 // Create the event data object.
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002806 Handle<Object> event_data;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002807 // Bail out and don't call debugger if exception.
machenbach@chromium.orge9fd6582014-04-16 00:05:02 +00002808 if (!MakeCompileEvent(script, true).ToHandle(&event_data)) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002809
ager@chromium.org5ec48922009-05-05 07:25:34 +00002810 // Process debug event.
2811 ProcessDebugEvent(v8::BeforeCompile,
2812 Handle<JSObject>::cast(event_data),
2813 true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002814}
2815
2816
2817// Handle debugger actions when a new script is compiled.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002818void Debugger::OnAfterCompile(Handle<Script> script,
2819 AfterCompileFlags after_compile_flags) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002820 HandleScope scope(isolate_);
2821 Debug* debug = isolate_->debug();
kasper.lund212ac232008-07-16 07:07:30 +00002822
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002823 // Add the newly compiled script to the script cache.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002824 debug->AddScriptToScriptCache(script);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002825
2826 // No more to do if not debugging.
machenbach@chromium.orga3b66332014-05-13 00:04:55 +00002827 if (!Debugger::EventActive()) return;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002828
iposva@chromium.org245aa852009-02-10 00:49:54 +00002829 // Store whether in debugger before entering debugger.
lrn@chromium.org7516f052011-03-30 08:52:27 +00002830 bool in_debugger = debug->InDebugger();
iposva@chromium.org245aa852009-02-10 00:49:54 +00002831
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002832 // Enter the debugger.
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00002833 EnterDebugger debugger(isolate_);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002834 if (debugger.FailedToEnter()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002835
2836 // If debugging there might be script break points registered for this
2837 // script. Make sure that these break points are set.
2838
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00002839 // Get the function UpdateScriptBreakPoints (defined in debug-debugger.js).
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00002840 Handle<String> update_script_break_points_string =
2841 isolate_->factory()->InternalizeOneByteString(
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002842 STATIC_ASCII_VECTOR("UpdateScriptBreakPoints"));
machenbach@chromium.org5b080562014-04-10 00:05:02 +00002843 Handle<GlobalObject> debug_global(debug->debug_context()->global_object());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002844 Handle<Object> update_script_break_points =
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002845 Object::GetProperty(
2846 debug_global, update_script_break_points_string).ToHandleChecked();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002847 if (!update_script_break_points->IsJSFunction()) {
2848 return;
2849 }
2850 ASSERT(update_script_break_points->IsJSFunction());
2851
2852 // Wrap the script object in a proper JS object before passing it
2853 // to JavaScript.
machenbach@chromium.org9fa61952014-04-17 00:05:12 +00002854 Handle<Object> wrapper = Script::GetWrapper(script);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002855
2856 // Call UpdateScriptBreakPoints expect no exceptions.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002857 Handle<Object> argv[] = { wrapper };
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002858 if (Execution::TryCall(Handle<JSFunction>::cast(update_script_break_points),
2859 isolate_->js_builtins_object(),
2860 ARRAY_SIZE(argv),
2861 argv).is_null()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002862 return;
2863 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002864 // Bail out based on state or if there is no listener for this event
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00002865 if (in_debugger && (after_compile_flags & SEND_WHEN_DEBUGGING) == 0) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002866
2867 // Create the compile state object.
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002868 Handle<Object> event_data;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002869 // Bail out and don't call debugger if exception.
machenbach@chromium.orge9fd6582014-04-16 00:05:02 +00002870 if (!MakeCompileEvent(script, false).ToHandle(&event_data)) return;
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002871
ager@chromium.org5ec48922009-05-05 07:25:34 +00002872 // Process debug event.
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002873 ProcessDebugEvent(v8::AfterCompile, Handle<JSObject>::cast(event_data), true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002874}
2875
2876
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002877void Debugger::OnScriptCollected(int id) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002878 HandleScope scope(isolate_);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002879
2880 // No more to do if not debugging.
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002881 if (isolate_->debug()->InDebugger()) return;
machenbach@chromium.orga3b66332014-05-13 00:04:55 +00002882 if (!Debugger::EventActive()) return;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002883
2884 // Enter the debugger.
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00002885 EnterDebugger debugger(isolate_);
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002886 if (debugger.FailedToEnter()) return;
2887
2888 // Create the script collected state object.
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002889 Handle<Object> event_data;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002890 // Bail out and don't call debugger if exception.
machenbach@chromium.orge9fd6582014-04-16 00:05:02 +00002891 if (!MakeScriptCollectedEvent(id).ToHandle(&event_data)) return;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002892
2893 // Process debug event.
2894 ProcessDebugEvent(v8::ScriptCollected,
2895 Handle<JSObject>::cast(event_data),
2896 true);
2897}
2898
2899
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002900void Debugger::ProcessDebugEvent(v8::DebugEvent event,
ager@chromium.org5ec48922009-05-05 07:25:34 +00002901 Handle<JSObject> event_data,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002902 bool auto_continue) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00002903 HandleScope scope(isolate_);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002904
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00002905 // Clear any pending debug break if this is a real break.
2906 if (!auto_continue) {
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00002907 isolate_->debug()->set_has_pending_interrupt(false);
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00002908 }
2909
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002910 // Create the execution state.
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002911 Handle<Object> exec_state;
2912 // Bail out and don't call debugger if exception.
machenbach@chromium.orge9fd6582014-04-16 00:05:02 +00002913 if (!MakeExecutionState().ToHandle(&exec_state)) return;
2914
ager@chromium.org41826e72009-03-30 13:30:57 +00002915 // First notify the message handler if any.
2916 if (message_handler_ != NULL) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00002917 NotifyMessageHandler(event,
2918 Handle<JSObject>::cast(exec_state),
2919 event_data,
2920 auto_continue);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002921 }
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00002922 // Notify registered debug event listener. This can be either a C or
2923 // a JavaScript function. Don't call event listener for v8::Break
2924 // here, if it's only a debug command -- they will be processed later.
2925 if ((event != v8::Break || !auto_continue) && !event_listener_.is_null()) {
2926 CallEventCallback(event, exec_state, event_data, NULL);
2927 }
2928 // Process pending debug commands.
2929 if (event == v8::Break) {
2930 while (!event_command_queue_.IsEmpty()) {
2931 CommandMessage command = event_command_queue_.Get();
2932 if (!event_listener_.is_null()) {
2933 CallEventCallback(v8::BreakForCommand,
2934 exec_state,
2935 event_data,
2936 command.client_data());
2937 }
2938 command.Dispose();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002939 }
2940 }
2941}
2942
2943
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00002944void Debugger::CallEventCallback(v8::DebugEvent event,
2945 Handle<Object> exec_state,
2946 Handle<Object> event_data,
2947 v8::Debug::ClientData* client_data) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002948 if (event_listener_->IsForeign()) {
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00002949 CallCEventCallback(event, exec_state, event_data, client_data);
2950 } else {
2951 CallJSEventCallback(event, exec_state, event_data);
2952 }
2953}
2954
2955
2956void Debugger::CallCEventCallback(v8::DebugEvent event,
2957 Handle<Object> exec_state,
2958 Handle<Object> event_data,
2959 v8::Debug::ClientData* client_data) {
ager@chromium.orgea91cc52011-05-23 06:06:11 +00002960 Handle<Foreign> callback_obj(Handle<Foreign>::cast(event_listener_));
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00002961 v8::Debug::EventCallback2 callback =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002962 FUNCTION_CAST<v8::Debug::EventCallback2>(
2963 callback_obj->foreign_address());
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00002964 EventDetailsImpl event_details(
2965 event,
2966 Handle<JSObject>::cast(exec_state),
2967 Handle<JSObject>::cast(event_data),
2968 event_listener_data_,
2969 client_data);
2970 callback(event_details);
2971}
2972
2973
2974void Debugger::CallJSEventCallback(v8::DebugEvent event,
2975 Handle<Object> exec_state,
2976 Handle<Object> event_data) {
2977 ASSERT(event_listener_->IsJSFunction());
2978 Handle<JSFunction> fun(Handle<JSFunction>::cast(event_listener_));
2979
2980 // Invoke the JavaScript debug event listener.
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00002981 Handle<Object> argv[] = { Handle<Object>(Smi::FromInt(event), isolate_),
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002982 exec_state,
2983 event_data,
2984 event_listener_data_ };
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002985 Execution::TryCall(fun,
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002986 isolate_->global_object(),
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00002987 ARRAY_SIZE(argv),
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00002988 argv);
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00002989 // Silently ignore exceptions from debug event listeners.
2990}
2991
2992
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002993Handle<Context> Debugger::GetDebugContext() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002994 never_unload_debugger_ = true;
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00002995 EnterDebugger debugger(isolate_);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002996 return isolate_->debug()->debug_context();
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00002997}
2998
2999
ager@chromium.org71daaf62009-04-01 07:22:49 +00003000void Debugger::UnloadDebugger() {
lrn@chromium.org7516f052011-03-30 08:52:27 +00003001 Debug* debug = isolate_->debug();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003002
ager@chromium.org71daaf62009-04-01 07:22:49 +00003003 // Make sure that there are no breakpoints left.
lrn@chromium.org7516f052011-03-30 08:52:27 +00003004 debug->ClearAllBreakPoints();
ager@chromium.org71daaf62009-04-01 07:22:49 +00003005
3006 // Unload the debugger if feasible.
3007 if (!never_unload_debugger_) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00003008 debug->Unload();
ager@chromium.org71daaf62009-04-01 07:22:49 +00003009 }
3010
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003011 // Clear the flag indicating that the debugger should be unloaded.
3012 debugger_unload_pending_ = false;
ager@chromium.org71daaf62009-04-01 07:22:49 +00003013}
3014
3015
ager@chromium.org41826e72009-03-30 13:30:57 +00003016void Debugger::NotifyMessageHandler(v8::DebugEvent event,
ager@chromium.org5ec48922009-05-05 07:25:34 +00003017 Handle<JSObject> exec_state,
3018 Handle<JSObject> event_data,
ager@chromium.org41826e72009-03-30 13:30:57 +00003019 bool auto_continue) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00003020 HandleScope scope(isolate_);
ager@chromium.org41826e72009-03-30 13:30:57 +00003021
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003022 if (!isolate_->debug()->Load()) return;
ager@chromium.org41826e72009-03-30 13:30:57 +00003023
3024 // Process the individual events.
ager@chromium.org5ec48922009-05-05 07:25:34 +00003025 bool sendEventMessage = false;
ager@chromium.org41826e72009-03-30 13:30:57 +00003026 switch (event) {
3027 case v8::Break:
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00003028 case v8::BreakForCommand:
ager@chromium.org5ec48922009-05-05 07:25:34 +00003029 sendEventMessage = !auto_continue;
ager@chromium.org41826e72009-03-30 13:30:57 +00003030 break;
3031 case v8::Exception:
ager@chromium.org5ec48922009-05-05 07:25:34 +00003032 sendEventMessage = true;
ager@chromium.org41826e72009-03-30 13:30:57 +00003033 break;
3034 case v8::BeforeCompile:
3035 break;
3036 case v8::AfterCompile:
ager@chromium.org5ec48922009-05-05 07:25:34 +00003037 sendEventMessage = true;
ager@chromium.org41826e72009-03-30 13:30:57 +00003038 break;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003039 case v8::ScriptCollected:
3040 sendEventMessage = true;
3041 break;
ager@chromium.org41826e72009-03-30 13:30:57 +00003042 case v8::NewFunction:
3043 break;
3044 default:
3045 UNREACHABLE();
3046 }
3047
ager@chromium.org5ec48922009-05-05 07:25:34 +00003048 // The debug command interrupt flag might have been set when the command was
3049 // added. It should be enough to clear the flag only once while we are in the
3050 // debugger.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003051 ASSERT(isolate_->debug()->InDebugger());
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00003052 isolate_->stack_guard()->ClearDebugCommand();
ager@chromium.org5ec48922009-05-05 07:25:34 +00003053
3054 // Notify the debugger that a debug event has occurred unless auto continue is
3055 // active in which case no event is send.
3056 if (sendEventMessage) {
3057 MessageImpl message = MessageImpl::NewEvent(
3058 event,
3059 auto_continue,
3060 Handle<JSObject>::cast(exec_state),
3061 Handle<JSObject>::cast(event_data));
3062 InvokeMessageHandler(message);
3063 }
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +00003064
3065 // If auto continue don't make the event cause a break, but process messages
3066 // in the queue if any. For script collected events don't even process
3067 // messages in the queue as the execution state might not be what is expected
3068 // by the client.
ager@chromium.org6ffc2172009-05-29 19:20:16 +00003069 if ((auto_continue && !HasCommands()) || event == v8::ScriptCollected) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00003070 return;
3071 }
ager@chromium.org41826e72009-03-30 13:30:57 +00003072
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00003073 // DebugCommandProcessor goes here.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00003074 bool running = auto_continue;
3075
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00003076 Handle<Object> cmd_processor_ctor = Object::GetProperty(
3077 isolate_, exec_state, "debugCommandProcessor").ToHandleChecked();
3078 Handle<Object> ctor_args[] = { isolate_->factory()->ToBoolean(running) };
3079 Handle<Object> cmd_processor = Execution::Call(
3080 isolate_, cmd_processor_ctor, exec_state, 1, ctor_args).ToHandleChecked();
3081 Handle<JSFunction> process_debug_request = Handle<JSFunction>::cast(
3082 Object::GetProperty(
3083 isolate_, cmd_processor, "processDebugRequest").ToHandleChecked());
3084 Handle<Object> is_running = Object::GetProperty(
3085 isolate_, cmd_processor, "isRunning").ToHandleChecked();
3086
ager@chromium.org41826e72009-03-30 13:30:57 +00003087 // Process requests from the debugger.
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00003088 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003089 // Wait for new command in the queue.
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00003090 command_received_.Wait();
ager@chromium.org41826e72009-03-30 13:30:57 +00003091
ager@chromium.org41826e72009-03-30 13:30:57 +00003092 // Get the command from the queue.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003093 CommandMessage command = command_queue_.Get();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003094 isolate_->logger()->DebugTag(
3095 "Got request from command queue, in interactive loop.");
machenbach@chromium.orga3b66332014-05-13 00:04:55 +00003096 if (!Debugger::is_active()) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003097 // Delete command text and user data.
3098 command.Dispose();
ager@chromium.org41826e72009-03-30 13:30:57 +00003099 return;
3100 }
3101
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00003102 Vector<const uc16> command_text(
3103 const_cast<const uc16*>(command.text().start()),
3104 command.text().length());
3105 Handle<String> request_text = isolate_->factory()->NewStringFromTwoByte(
3106 command_text).ToHandleChecked();
3107 Handle<Object> request_args[] = { request_text };
3108 Handle<Object> exception;
3109 Handle<Object> answer_value;
3110 Handle<String> answer;
3111 MaybeHandle<Object> maybe_result = Execution::TryCall(
3112 process_debug_request, cmd_processor, 1, request_args, &exception);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003113
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00003114 if (maybe_result.ToHandle(&answer_value)) {
3115 if (answer_value->IsUndefined()) {
3116 answer = isolate_->factory()->empty_string();
ager@chromium.org41826e72009-03-30 13:30:57 +00003117 } else {
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00003118 answer = Handle<String>::cast(answer_value);
ager@chromium.org41826e72009-03-30 13:30:57 +00003119 }
3120
3121 // Log the JSON request/response.
3122 if (FLAG_trace_debug_json) {
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00003123 PrintF("%s\n", request_text->ToCString().get());
3124 PrintF("%s\n", answer->ToCString().get());
ager@chromium.org41826e72009-03-30 13:30:57 +00003125 }
3126
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00003127 Handle<Object> is_running_args[] = { answer };
3128 maybe_result = Execution::Call(
3129 isolate_, is_running, cmd_processor, 1, is_running_args);
3130 running = maybe_result.ToHandleChecked()->IsTrue();
ager@chromium.org41826e72009-03-30 13:30:57 +00003131 } else {
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00003132 answer = Handle<String>::cast(
3133 Execution::ToString(isolate_, exception).ToHandleChecked());
ager@chromium.org41826e72009-03-30 13:30:57 +00003134 }
3135
ager@chromium.org41826e72009-03-30 13:30:57 +00003136 // Return the result.
ager@chromium.org5ec48922009-05-05 07:25:34 +00003137 MessageImpl message = MessageImpl::NewResponse(
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00003138 event, running, exec_state, event_data, answer, command.client_data());
ager@chromium.org5ec48922009-05-05 07:25:34 +00003139 InvokeMessageHandler(message);
3140 command.Dispose();
ager@chromium.org41826e72009-03-30 13:30:57 +00003141
3142 // Return from debug event processing if either the VM is put into the
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00003143 // running state (through a continue command) or auto continue is active
ager@chromium.org41826e72009-03-30 13:30:57 +00003144 // and there are no more commands queued.
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00003145 } while (!running || HasCommands());
ager@chromium.org41826e72009-03-30 13:30:57 +00003146}
3147
3148
iposva@chromium.org245aa852009-02-10 00:49:54 +00003149void Debugger::SetEventListener(Handle<Object> callback,
3150 Handle<Object> data) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00003151 HandleScope scope(isolate_);
3152 GlobalHandles* global_handles = isolate_->global_handles();
iposva@chromium.org245aa852009-02-10 00:49:54 +00003153
3154 // Clear the global handles for the event listener and the event listener data
3155 // object.
3156 if (!event_listener_.is_null()) {
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00003157 GlobalHandles::Destroy(
iposva@chromium.org245aa852009-02-10 00:49:54 +00003158 reinterpret_cast<Object**>(event_listener_.location()));
3159 event_listener_ = Handle<Object>();
3160 }
3161 if (!event_listener_data_.is_null()) {
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00003162 GlobalHandles::Destroy(
iposva@chromium.org245aa852009-02-10 00:49:54 +00003163 reinterpret_cast<Object**>(event_listener_data_.location()));
3164 event_listener_data_ = Handle<Object>();
3165 }
3166
3167 // If there is a new debug event listener register it together with its data
3168 // object.
3169 if (!callback->IsUndefined() && !callback->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003170 event_listener_ = Handle<Object>::cast(
lrn@chromium.org7516f052011-03-30 08:52:27 +00003171 global_handles->Create(*callback));
iposva@chromium.org245aa852009-02-10 00:49:54 +00003172 if (data.is_null()) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00003173 data = isolate_->factory()->undefined_value();
iposva@chromium.org245aa852009-02-10 00:49:54 +00003174 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003175 event_listener_data_ = Handle<Object>::cast(
lrn@chromium.org7516f052011-03-30 08:52:27 +00003176 global_handles->Create(*data));
iposva@chromium.org245aa852009-02-10 00:49:54 +00003177 }
3178
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003179 ListenersChanged();
iposva@chromium.org245aa852009-02-10 00:49:54 +00003180}
3181
3182
ager@chromium.org5ec48922009-05-05 07:25:34 +00003183void Debugger::SetMessageHandler(v8::Debug::MessageHandler2 handler) {
machenbach@chromium.orga3b66332014-05-13 00:04:55 +00003184 LockGuard<RecursiveMutex> with(&debugger_access_);
ager@chromium.org71daaf62009-04-01 07:22:49 +00003185
ager@chromium.org381abbb2009-02-25 13:23:22 +00003186 message_handler_ = handler;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003187 ListenersChanged();
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003188 if (handler == NULL) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00003189 // Send an empty command to the debugger if in a break to make JavaScript
3190 // run again if the debugger is closed.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003191 if (isolate_->debug()->InDebugger()) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00003192 ProcessCommand(Vector<const uint16_t>::empty());
3193 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003194 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003195}
3196
3197
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003198void Debugger::ListenersChanged() {
machenbach@chromium.orga3b66332014-05-13 00:04:55 +00003199 LockGuard<RecursiveMutex> with(&debugger_access_);
3200 is_active_ = message_handler_ != NULL || !event_listener_.is_null();
3201 if (is_active_) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003202 // Disable the compilation cache when the debugger is active.
lrn@chromium.org7516f052011-03-30 08:52:27 +00003203 isolate_->compilation_cache()->Disable();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003204 debugger_unload_pending_ = false;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003205 } else {
lrn@chromium.org7516f052011-03-30 08:52:27 +00003206 isolate_->compilation_cache()->Enable();
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003207 // Unload the debugger if event listener and message handler cleared.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003208 // Schedule this for later, because we may be in non-V8 thread.
3209 debugger_unload_pending_ = true;
kasperl@chromium.org71affb52009-05-26 05:44:31 +00003210 }
3211}
3212
3213
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003214void Debugger::SetDebugMessageDispatchHandler(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003215 v8::Debug::DebugMessageDispatchHandler handler, bool provide_locker) {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00003216 LockGuard<Mutex> lock_guard(&dispatch_handler_access_);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003217 debug_message_dispatch_handler_ = handler;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003218
3219 if (provide_locker && message_dispatch_helper_thread_ == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003220 message_dispatch_helper_thread_ = new MessageDispatchHelperThread(isolate_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003221 message_dispatch_helper_thread_->Start();
3222 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003223}
3224
3225
ager@chromium.org41826e72009-03-30 13:30:57 +00003226// Calls the registered debug message handler. This callback is part of the
ager@chromium.org5ec48922009-05-05 07:25:34 +00003227// public API.
3228void Debugger::InvokeMessageHandler(MessageImpl message) {
machenbach@chromium.orga3b66332014-05-13 00:04:55 +00003229 LockGuard<RecursiveMutex> with(&debugger_access_);
ager@chromium.org71daaf62009-04-01 07:22:49 +00003230
ager@chromium.org381abbb2009-02-25 13:23:22 +00003231 if (message_handler_ != NULL) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00003232 message_handler_(message);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003233 }
ager@chromium.org41826e72009-03-30 13:30:57 +00003234}
3235
3236
3237// Puts a command coming from the public API on the queue. Creates
3238// a copy of the command string managed by the debugger. Up to this
3239// point, the command data was managed by the API client. Called
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003240// by the API client thread.
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003241void Debugger::ProcessCommand(Vector<const uint16_t> command,
3242 v8::Debug::ClientData* client_data) {
3243 // Need to cast away const.
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003244 CommandMessage message = CommandMessage::New(
ager@chromium.org41826e72009-03-30 13:30:57 +00003245 Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003246 command.length()),
3247 client_data);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003248 isolate_->logger()->DebugTag("Put command on command_queue.");
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003249 command_queue_.Put(message);
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00003250 command_received_.Signal();
sgjesse@chromium.org3afc1582009-04-16 22:31:44 +00003251
3252 // Set the debug command break flag to have the command processed.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003253 if (!isolate_->debug()->InDebugger()) {
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00003254 isolate_->stack_guard()->RequestDebugCommand();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003255 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003256
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003257 MessageDispatchHelperThread* dispatch_thread;
3258 {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00003259 LockGuard<Mutex> lock_guard(&dispatch_handler_access_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003260 dispatch_thread = message_dispatch_helper_thread_;
3261 }
3262
3263 if (dispatch_thread == NULL) {
3264 CallMessageDispatchHandler();
3265 } else {
3266 dispatch_thread->Schedule();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003267 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003268}
3269
3270
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003271bool Debugger::HasCommands() {
ager@chromium.org41826e72009-03-30 13:30:57 +00003272 return !command_queue_.IsEmpty();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003273}
3274
3275
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00003276void Debugger::EnqueueDebugCommand(v8::Debug::ClientData* client_data) {
3277 CommandMessage message = CommandMessage::New(Vector<uint16_t>(), client_data);
3278 event_command_queue_.Put(message);
3279
3280 // Set the debug command break flag to have the command processed.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003281 if (!isolate_->debug()->InDebugger()) {
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00003282 isolate_->stack_guard()->RequestDebugCommand();
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00003283 }
3284}
3285
3286
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00003287MaybeHandle<Object> Debugger::Call(Handle<JSFunction> fun,
3288 Handle<Object> data) {
ager@chromium.org71daaf62009-04-01 07:22:49 +00003289 // When calling functions in the debugger prevent it from beeing unloaded.
3290 Debugger::never_unload_debugger_ = true;
3291
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003292 // Enter the debugger.
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00003293 EnterDebugger debugger(isolate_);
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00003294 if (debugger.FailedToEnter()) {
lrn@chromium.org7516f052011-03-30 08:52:27 +00003295 return isolate_->factory()->undefined_value();
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003296 }
3297
3298 // Create the execution state.
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00003299 Handle<Object> exec_state;
machenbach@chromium.orge9fd6582014-04-16 00:05:02 +00003300 if (!MakeExecutionState().ToHandle(&exec_state)) {
3301 return isolate_->factory()->undefined_value();
3302 }
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003303
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00003304 Handle<Object> argv[] = { exec_state, data };
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00003305 return Execution::Call(
jkummerow@chromium.org2c9426b2013-09-05 16:31:13 +00003306 isolate_,
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00003307 fun,
ulan@chromium.org09d7ab52013-02-25 15:50:35 +00003308 Handle<Object>(isolate_->debug()->debug_context_->global_proxy(),
3309 isolate_),
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00003310 ARRAY_SIZE(argv),
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00003311 argv);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003312}
3313
3314
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003315static void StubMessageHandler2(const v8::Debug::Message& message) {
3316 // Simply ignore message.
3317}
3318
3319
3320bool Debugger::StartAgent(const char* name, int port,
3321 bool wait_for_connection) {
3322 if (wait_for_connection) {
3323 // Suspend V8 if it is already running or set V8 to suspend whenever
3324 // it starts.
3325 // Provide stub message handler; V8 auto-continues each suspend
3326 // when there is no message handler; we doesn't need it.
3327 // Once become suspended, V8 will stay so indefinitely long, until remote
3328 // debugger connects and issues "continue" command.
3329 Debugger::message_handler_ = StubMessageHandler2;
machenbach@chromium.orge9fd6582014-04-16 00:05:02 +00003330 v8::Debug::DebugBreak(reinterpret_cast<v8::Isolate*>(isolate_));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00003331 }
3332
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00003333 if (agent_ == NULL) {
3334 agent_ = new DebuggerAgent(isolate_, name, port);
3335 agent_->Start();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003336 }
jkummerow@chromium.org3d00d0a2013-09-04 13:57:32 +00003337 return true;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003338}
3339
3340
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003341void Debugger::StopAgent() {
3342 if (agent_ != NULL) {
3343 agent_->Shutdown();
3344 agent_->Join();
3345 delete agent_;
3346 agent_ = NULL;
3347 }
3348}
3349
3350
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00003351void Debugger::WaitForAgent() {
3352 if (agent_ != NULL)
3353 agent_->WaitUntilListening();
3354}
3355
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003356
3357void Debugger::CallMessageDispatchHandler() {
3358 v8::Debug::DebugMessageDispatchHandler handler;
3359 {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00003360 LockGuard<Mutex> lock_guard(&dispatch_handler_access_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003361 handler = Debugger::debug_message_dispatch_handler_;
3362 }
3363 if (handler != NULL) {
3364 handler();
3365 }
3366}
3367
3368
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00003369EnterDebugger::EnterDebugger(Isolate* isolate)
3370 : isolate_(isolate),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003371 prev_(isolate_->debug()->debugger_entry()),
3372 it_(isolate_),
3373 has_js_frames_(!it_.done()),
3374 save_(isolate_) {
3375 Debug* debug = isolate_->debug();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003376 // Link recursive debugger entry.
3377 debug->set_debugger_entry(this);
3378
3379 // Store the previous break id and frame id.
3380 break_id_ = debug->break_id();
3381 break_frame_id_ = debug->break_frame_id();
3382
3383 // Create the new break info. If there is no JavaScript frames there is no
3384 // break frame id.
3385 if (has_js_frames_) {
3386 debug->NewBreak(it_.frame()->id());
3387 } else {
3388 debug->NewBreak(StackFrame::NO_ID);
3389 }
3390
3391 // Make sure that debugger is loaded and enter the debugger context.
3392 load_failed_ = !debug->Load();
3393 if (!load_failed_) {
3394 // NOTE the member variable save which saves the previous context before
3395 // this change.
3396 isolate_->set_context(*debug->debug_context());
3397 }
3398}
3399
3400
3401EnterDebugger::~EnterDebugger() {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003402 Debug* debug = isolate_->debug();
3403
3404 // Restore to the previous break state.
3405 debug->SetBreak(break_frame_id_, break_id_);
3406
3407 // Check for leaving the debugger.
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003408 if (!load_failed_ && prev_ == NULL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003409 // Clear mirror cache when leaving the debugger. Skip this if there is a
3410 // pending exception as clearing the mirror cache calls back into
3411 // JavaScript. This can happen if the v8::Debug::Call is used in which
3412 // case the exception should end up in the calling code.
3413 if (!isolate_->has_pending_exception()) {
3414 // Try to avoid any pending debug break breaking in the clear mirror
3415 // cache JavaScript code.
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00003416 if (isolate_->stack_guard()->CheckDebugBreak()) {
3417 debug->set_has_pending_interrupt(true);
3418 isolate_->stack_guard()->ClearDebugBreak();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003419 }
3420 debug->ClearMirrorCache();
3421 }
3422
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00003423 // Request debug break when leaving the last debugger entry
3424 // if one was recorded while debugging.
3425 if (debug->has_pending_interrupt()) {
3426 debug->set_has_pending_interrupt(false);
3427 isolate_->stack_guard()->RequestDebugBreak();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003428 }
3429
3430 // If there are commands in the queue when leaving the debugger request
3431 // that these commands are processed.
3432 if (isolate_->debugger()->HasCommands()) {
machenbach@chromium.org3c3c8d72014-05-12 00:05:07 +00003433 isolate_->stack_guard()->RequestDebugCommand();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003434 }
3435
3436 // If leaving the debugger with the debugger no longer active unload it.
machenbach@chromium.orga3b66332014-05-13 00:04:55 +00003437 if (!isolate_->debugger()->is_active()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003438 isolate_->debugger()->UnloadDebugger();
3439 }
3440 }
3441
3442 // Leaving this debugger entry.
3443 debug->set_debugger_entry(prev_);
3444}
3445
3446
ager@chromium.org5ec48922009-05-05 07:25:34 +00003447MessageImpl MessageImpl::NewEvent(DebugEvent event,
3448 bool running,
3449 Handle<JSObject> exec_state,
3450 Handle<JSObject> event_data) {
3451 MessageImpl message(true, event, running,
3452 exec_state, event_data, Handle<String>(), NULL);
3453 return message;
3454}
3455
3456
3457MessageImpl MessageImpl::NewResponse(DebugEvent event,
3458 bool running,
3459 Handle<JSObject> exec_state,
3460 Handle<JSObject> event_data,
3461 Handle<String> response_json,
3462 v8::Debug::ClientData* client_data) {
3463 MessageImpl message(false, event, running,
3464 exec_state, event_data, response_json, client_data);
3465 return message;
3466}
3467
3468
3469MessageImpl::MessageImpl(bool is_event,
3470 DebugEvent event,
3471 bool running,
3472 Handle<JSObject> exec_state,
3473 Handle<JSObject> event_data,
3474 Handle<String> response_json,
3475 v8::Debug::ClientData* client_data)
3476 : is_event_(is_event),
3477 event_(event),
3478 running_(running),
3479 exec_state_(exec_state),
3480 event_data_(event_data),
3481 response_json_(response_json),
3482 client_data_(client_data) {}
3483
3484
3485bool MessageImpl::IsEvent() const {
3486 return is_event_;
3487}
3488
3489
3490bool MessageImpl::IsResponse() const {
3491 return !is_event_;
3492}
3493
3494
3495DebugEvent MessageImpl::GetEvent() const {
3496 return event_;
3497}
3498
3499
3500bool MessageImpl::WillStartRunning() const {
3501 return running_;
3502}
3503
3504
3505v8::Handle<v8::Object> MessageImpl::GetExecutionState() const {
3506 return v8::Utils::ToLocal(exec_state_);
3507}
3508
3509
hpayer@chromium.orgc5d49712013-09-11 08:25:48 +00003510v8::Isolate* MessageImpl::GetIsolate() const {
3511 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate());
3512}
3513
3514
ager@chromium.org5ec48922009-05-05 07:25:34 +00003515v8::Handle<v8::Object> MessageImpl::GetEventData() const {
3516 return v8::Utils::ToLocal(event_data_);
3517}
3518
3519
3520v8::Handle<v8::String> MessageImpl::GetJSON() const {
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00003521 Isolate* isolate = event_data_->GetIsolate();
3522 v8::EscapableHandleScope scope(reinterpret_cast<v8::Isolate*>(isolate));
ager@chromium.org5ec48922009-05-05 07:25:34 +00003523
3524 if (IsEvent()) {
3525 // Call toJSONProtocol on the debug event object.
machenbach@chromium.org9fa61952014-04-17 00:05:12 +00003526 Handle<Object> fun = Object::GetProperty(
3527 isolate, event_data_, "toJSONProtocol").ToHandleChecked();
ager@chromium.org5ec48922009-05-05 07:25:34 +00003528 if (!fun->IsJSFunction()) {
3529 return v8::Handle<v8::String>();
3530 }
machenbach@chromium.org2ebef182014-04-14 00:05:03 +00003531
3532 MaybeHandle<Object> maybe_json =
3533 Execution::TryCall(Handle<JSFunction>::cast(fun), event_data_, 0, NULL);
3534 Handle<Object> json;
3535 if (!maybe_json.ToHandle(&json) || !json->IsString()) {
ager@chromium.org5ec48922009-05-05 07:25:34 +00003536 return v8::Handle<v8::String>();
3537 }
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00003538 return scope.Escape(v8::Utils::ToLocal(Handle<String>::cast(json)));
ager@chromium.org5ec48922009-05-05 07:25:34 +00003539 } else {
3540 return v8::Utils::ToLocal(response_json_);
3541 }
3542}
3543
3544
3545v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00003546 Isolate* isolate = event_data_->GetIsolate();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003547 v8::Handle<v8::Context> context = GetDebugEventContext(isolate);
3548 // Isolate::context() may be NULL when "script collected" event occures.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003549 ASSERT(!context.IsEmpty() || event_ == v8::ScriptCollected);
rossberg@chromium.org717967f2011-07-20 13:44:42 +00003550 return context;
ager@chromium.org5ec48922009-05-05 07:25:34 +00003551}
3552
3553
3554v8::Debug::ClientData* MessageImpl::GetClientData() const {
3555 return client_data_;
3556}
3557
3558
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003559EventDetailsImpl::EventDetailsImpl(DebugEvent event,
3560 Handle<JSObject> exec_state,
3561 Handle<JSObject> event_data,
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00003562 Handle<Object> callback_data,
3563 v8::Debug::ClientData* client_data)
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003564 : event_(event),
3565 exec_state_(exec_state),
3566 event_data_(event_data),
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00003567 callback_data_(callback_data),
3568 client_data_(client_data) {}
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003569
3570
3571DebugEvent EventDetailsImpl::GetEvent() const {
3572 return event_;
3573}
3574
3575
3576v8::Handle<v8::Object> EventDetailsImpl::GetExecutionState() const {
3577 return v8::Utils::ToLocal(exec_state_);
3578}
3579
3580
3581v8::Handle<v8::Object> EventDetailsImpl::GetEventData() const {
3582 return v8::Utils::ToLocal(event_data_);
3583}
3584
3585
3586v8::Handle<v8::Context> EventDetailsImpl::GetEventContext() const {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00003587 return GetDebugEventContext(exec_state_->GetIsolate());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003588}
3589
3590
3591v8::Handle<v8::Value> EventDetailsImpl::GetCallbackData() const {
3592 return v8::Utils::ToLocal(callback_data_);
3593}
3594
3595
mikhail.naganov@gmail.com22762872010-07-14 09:29:05 +00003596v8::Debug::ClientData* EventDetailsImpl::GetClientData() const {
3597 return client_data_;
3598}
3599
3600
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003601CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()),
3602 client_data_(NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003603}
3604
3605
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003606CommandMessage::CommandMessage(const Vector<uint16_t>& text,
3607 v8::Debug::ClientData* data)
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003608 : text_(text),
3609 client_data_(data) {
3610}
3611
3612
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003613CommandMessage::~CommandMessage() {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003614}
3615
3616
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003617void CommandMessage::Dispose() {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003618 text_.Dispose();
3619 delete client_data_;
3620 client_data_ = NULL;
3621}
3622
3623
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003624CommandMessage CommandMessage::New(const Vector<uint16_t>& command,
3625 v8::Debug::ClientData* data) {
3626 return CommandMessage(command.Clone(), data);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003627}
3628
3629
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003630CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0),
3631 size_(size) {
3632 messages_ = NewArray<CommandMessage>(size);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003633}
3634
3635
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003636CommandMessageQueue::~CommandMessageQueue() {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003637 while (!IsEmpty()) {
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003638 CommandMessage m = Get();
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003639 m.Dispose();
3640 }
kasper.lund7276f142008-07-30 08:49:36 +00003641 DeleteArray(messages_);
3642}
3643
3644
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003645CommandMessage CommandMessageQueue::Get() {
kasper.lund7276f142008-07-30 08:49:36 +00003646 ASSERT(!IsEmpty());
3647 int result = start_;
3648 start_ = (start_ + 1) % size_;
3649 return messages_[result];
3650}
3651
3652
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003653void CommandMessageQueue::Put(const CommandMessage& message) {
kasper.lund7276f142008-07-30 08:49:36 +00003654 if ((end_ + 1) % size_ == start_) {
3655 Expand();
3656 }
3657 messages_[end_] = message;
3658 end_ = (end_ + 1) % size_;
3659}
3660
3661
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003662void CommandMessageQueue::Expand() {
3663 CommandMessageQueue new_queue(size_ * 2);
kasper.lund7276f142008-07-30 08:49:36 +00003664 while (!IsEmpty()) {
3665 new_queue.Put(Get());
3666 }
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003667 CommandMessage* array_to_free = messages_;
kasper.lund7276f142008-07-30 08:49:36 +00003668 *this = new_queue;
3669 new_queue.messages_ = array_to_free;
ager@chromium.org65dad4b2009-04-23 08:48:43 +00003670 // Make the new_queue empty so that it doesn't call Dispose on any messages.
3671 new_queue.start_ = new_queue.end_;
kasper.lund7276f142008-07-30 08:49:36 +00003672 // Automatic destructor called on new_queue, freeing array_to_free.
3673}
3674
3675
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003676LockingCommandMessageQueue::LockingCommandMessageQueue(Logger* logger, int size)
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00003677 : logger_(logger), queue_(size) {}
kasper.lund7276f142008-07-30 08:49:36 +00003678
3679
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003680bool LockingCommandMessageQueue::IsEmpty() const {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00003681 LockGuard<Mutex> lock_guard(&mutex_);
kasper.lund7276f142008-07-30 08:49:36 +00003682 return queue_.IsEmpty();
3683}
3684
3685
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003686CommandMessage LockingCommandMessageQueue::Get() {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00003687 LockGuard<Mutex> lock_guard(&mutex_);
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003688 CommandMessage result = queue_.Get();
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003689 logger_->DebugEvent("Get", result.text());
kasper.lund7276f142008-07-30 08:49:36 +00003690 return result;
3691}
3692
3693
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003694void LockingCommandMessageQueue::Put(const CommandMessage& message) {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00003695 LockGuard<Mutex> lock_guard(&mutex_);
kasper.lund7276f142008-07-30 08:49:36 +00003696 queue_.Put(message);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003697 logger_->DebugEvent("Put", message.text());
kasper.lund7276f142008-07-30 08:49:36 +00003698}
3699
3700
ager@chromium.org3a37e9b2009-04-27 09:26:21 +00003701void LockingCommandMessageQueue::Clear() {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00003702 LockGuard<Mutex> lock_guard(&mutex_);
kasper.lund7276f142008-07-30 08:49:36 +00003703 queue_.Clear();
3704}
3705
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003706
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003707MessageDispatchHelperThread::MessageDispatchHelperThread(Isolate* isolate)
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003708 : Thread("v8:MsgDispHelpr"),
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00003709 isolate_(isolate), sem_(0),
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00003710 already_signalled_(false) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003711}
3712
3713
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003714void MessageDispatchHelperThread::Schedule() {
3715 {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00003716 LockGuard<Mutex> lock_guard(&mutex_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003717 if (already_signalled_) {
3718 return;
3719 }
3720 already_signalled_ = true;
3721 }
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00003722 sem_.Signal();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003723}
3724
3725
3726void MessageDispatchHelperThread::Run() {
3727 while (true) {
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00003728 sem_.Wait();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003729 {
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +00003730 LockGuard<Mutex> lock_guard(&mutex_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003731 already_signalled_ = false;
3732 }
3733 {
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00003734 Locker locker(reinterpret_cast<v8::Isolate*>(isolate_));
3735 isolate_->debugger()->CallMessageDispatchHandler();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003736 }
3737 }
3738}
3739
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003740} } // namespace v8::internal