blob: 3b5fb5f53d5f449b9cd3e0122a34fdffb93c44cc [file] [log] [blame]
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001// Copyright 2012 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/debug/debug.h"
6
7#include "src/api.h"
8#include "src/arguments.h"
9#include "src/bootstrapper.h"
10#include "src/code-stubs.h"
11#include "src/codegen.h"
12#include "src/compilation-cache.h"
13#include "src/compiler.h"
14#include "src/deoptimizer.h"
15#include "src/execution.h"
16#include "src/frames-inl.h"
17#include "src/full-codegen/full-codegen.h"
18#include "src/global-handles.h"
Ben Murdoch097c5b22016-05-18 11:27:45 +010019#include "src/interpreter/interpreter.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000020#include "src/isolate-inl.h"
21#include "src/list.h"
22#include "src/log.h"
23#include "src/messages.h"
24#include "src/snapshot/natives.h"
25
26#include "include/v8-debug.h"
27
28namespace v8 {
29namespace internal {
30
31Debug::Debug(Isolate* isolate)
32 : debug_context_(Handle<Context>()),
33 event_listener_(Handle<Object>()),
34 event_listener_data_(Handle<Object>()),
35 message_handler_(NULL),
36 command_received_(0),
37 command_queue_(isolate->logger(), kQueueInitialSize),
38 is_active_(false),
39 is_suppressed_(false),
40 live_edit_enabled_(true), // TODO(yangguo): set to false by default.
41 break_disabled_(false),
42 break_points_active_(true),
43 in_debug_event_listener_(false),
44 break_on_exception_(false),
45 break_on_uncaught_exception_(false),
46 debug_info_list_(NULL),
47 feature_tracker_(isolate),
48 isolate_(isolate) {
49 ThreadInit();
50}
51
52
53static v8::Local<v8::Context> GetDebugEventContext(Isolate* isolate) {
54 Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
55 // Isolate::context() may have been NULL when "script collected" event
56 // occured.
57 if (context.is_null()) return v8::Local<v8::Context>();
58 Handle<Context> native_context(context->native_context());
59 return v8::Utils::ToLocal(native_context);
60}
61
Ben Murdoch097c5b22016-05-18 11:27:45 +010062BreakLocation::BreakLocation(Handle<DebugInfo> debug_info, DebugBreakType type,
63 int code_offset, int position,
64 int statement_position)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000065 : debug_info_(debug_info),
Ben Murdoch097c5b22016-05-18 11:27:45 +010066 code_offset_(code_offset),
67 type_(type),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000068 position_(position),
69 statement_position_(statement_position) {}
70
Ben Murdoch097c5b22016-05-18 11:27:45 +010071BreakLocation::Iterator* BreakLocation::GetIterator(
72 Handle<DebugInfo> debug_info, BreakLocatorType type) {
73 if (debug_info->abstract_code()->IsBytecodeArray()) {
74 return new BytecodeArrayIterator(debug_info, type);
75 } else {
76 return new CodeIterator(debug_info, type);
77 }
78}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000079
Ben Murdoch097c5b22016-05-18 11:27:45 +010080BreakLocation::Iterator::Iterator(Handle<DebugInfo> debug_info)
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000081 : debug_info_(debug_info),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000082 break_index_(-1),
83 position_(1),
Ben Murdoch097c5b22016-05-18 11:27:45 +010084 statement_position_(1) {}
85
Ben Murdochda12d292016-06-02 14:46:10 +010086int BreakLocation::Iterator::ReturnPosition() {
87 if (debug_info_->shared()->HasSourceCode()) {
88 return debug_info_->shared()->end_position() -
89 debug_info_->shared()->start_position() - 1;
90 } else {
91 return 0;
92 }
93}
94
Ben Murdoch097c5b22016-05-18 11:27:45 +010095BreakLocation::CodeIterator::CodeIterator(Handle<DebugInfo> debug_info,
96 BreakLocatorType type)
97 : Iterator(debug_info),
98 reloc_iterator_(debug_info->abstract_code()->GetCode(),
99 GetModeMask(type)) {
Ben Murdochda12d292016-06-02 14:46:10 +0100100 // There is at least one break location.
101 DCHECK(!Done());
102 Next();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000103}
104
Ben Murdoch097c5b22016-05-18 11:27:45 +0100105int BreakLocation::CodeIterator::GetModeMask(BreakLocatorType type) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000106 int mask = 0;
107 mask |= RelocInfo::ModeMask(RelocInfo::POSITION);
108 mask |= RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION);
109 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN);
110 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_CALL);
Ben Murdochda12d292016-06-02 14:46:10 +0100111 if (isolate()->is_tail_call_elimination_enabled()) {
112 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL);
113 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000114 if (type == ALL_BREAK_LOCATIONS) {
115 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION);
116 mask |= RelocInfo::ModeMask(RelocInfo::DEBUGGER_STATEMENT);
117 }
118 return mask;
119}
120
Ben Murdoch097c5b22016-05-18 11:27:45 +0100121void BreakLocation::CodeIterator::Next() {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000122 DisallowHeapAllocation no_gc;
123 DCHECK(!Done());
124
Ben Murdoch097c5b22016-05-18 11:27:45 +0100125 // Iterate through reloc info stopping at each breakable code target.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000126 bool first = break_index_ == -1;
127 while (!Done()) {
128 if (!first) reloc_iterator_.next();
129 first = false;
130 if (Done()) return;
131
132 // Whenever a statement position or (plain) position is passed update the
133 // current value of these.
134 if (RelocInfo::IsPosition(rmode())) {
135 if (RelocInfo::IsStatementPosition(rmode())) {
136 statement_position_ = static_cast<int>(
137 rinfo()->data() - debug_info_->shared()->start_position());
138 }
139 // Always update the position as we don't want that to be before the
140 // statement position.
141 position_ = static_cast<int>(rinfo()->data() -
142 debug_info_->shared()->start_position());
143 DCHECK(position_ >= 0);
144 DCHECK(statement_position_ >= 0);
145 continue;
146 }
147
148 DCHECK(RelocInfo::IsDebugBreakSlot(rmode()) ||
149 RelocInfo::IsDebuggerStatement(rmode()));
150
151 if (RelocInfo::IsDebugBreakSlotAtReturn(rmode())) {
152 // Set the positions to the end of the function.
Ben Murdochda12d292016-06-02 14:46:10 +0100153 statement_position_ = position_ = ReturnPosition();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000154 }
155
156 break;
157 }
158 break_index_++;
159}
160
Ben Murdoch097c5b22016-05-18 11:27:45 +0100161BreakLocation BreakLocation::CodeIterator::GetBreakLocation() {
162 DebugBreakType type;
163 if (RelocInfo::IsDebugBreakSlotAtReturn(rmode())) {
164 type = DEBUG_BREAK_SLOT_AT_RETURN;
165 } else if (RelocInfo::IsDebugBreakSlotAtCall(rmode())) {
166 type = DEBUG_BREAK_SLOT_AT_CALL;
Ben Murdochda12d292016-06-02 14:46:10 +0100167 } else if (RelocInfo::IsDebugBreakSlotAtTailCall(rmode())) {
168 type = isolate()->is_tail_call_elimination_enabled()
169 ? DEBUG_BREAK_SLOT_AT_TAIL_CALL
170 : DEBUG_BREAK_SLOT_AT_CALL;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100171 } else if (RelocInfo::IsDebuggerStatement(rmode())) {
172 type = DEBUGGER_STATEMENT;
173 } else if (RelocInfo::IsDebugBreakSlot(rmode())) {
174 type = DEBUG_BREAK_SLOT;
175 } else {
176 type = NOT_DEBUG_BREAK;
177 }
178 return BreakLocation(debug_info_, type, code_offset(), position(),
179 statement_position());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000180}
181
Ben Murdoch097c5b22016-05-18 11:27:45 +0100182BreakLocation::BytecodeArrayIterator::BytecodeArrayIterator(
183 Handle<DebugInfo> debug_info, BreakLocatorType type)
184 : Iterator(debug_info),
Ben Murdochda12d292016-06-02 14:46:10 +0100185 source_position_iterator_(debug_info->abstract_code()
186 ->GetBytecodeArray()
187 ->source_position_table()),
Ben Murdoch097c5b22016-05-18 11:27:45 +0100188 break_locator_type_(type),
189 start_position_(debug_info->shared()->start_position()) {
Ben Murdochda12d292016-06-02 14:46:10 +0100190 // There is at least one break location.
191 DCHECK(!Done());
192 Next();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100193}
194
195void BreakLocation::BytecodeArrayIterator::Next() {
196 DisallowHeapAllocation no_gc;
197 DCHECK(!Done());
198 bool first = break_index_ == -1;
199 while (!Done()) {
200 if (!first) source_position_iterator_.Advance();
201 first = false;
202 if (Done()) return;
203 position_ = source_position_iterator_.source_position() - start_position_;
204 if (source_position_iterator_.is_statement()) {
205 statement_position_ = position_;
206 }
207 DCHECK(position_ >= 0);
208 DCHECK(statement_position_ >= 0);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100209
210 enum DebugBreakType type = GetDebugBreakType();
211 if (type == NOT_DEBUG_BREAK) continue;
212
213 if (break_locator_type_ == ALL_BREAK_LOCATIONS) break;
214
215 DCHECK_EQ(CALLS_AND_RETURNS, break_locator_type_);
Ben Murdochda12d292016-06-02 14:46:10 +0100216 if (type == DEBUG_BREAK_SLOT_AT_CALL) break;
217 if (type == DEBUG_BREAK_SLOT_AT_RETURN) {
218 DCHECK_EQ(ReturnPosition(), position_);
219 DCHECK_EQ(ReturnPosition(), statement_position_);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100220 break;
221 }
222 }
Ben Murdochda12d292016-06-02 14:46:10 +0100223 break_index_++;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100224}
225
226BreakLocation::DebugBreakType
227BreakLocation::BytecodeArrayIterator::GetDebugBreakType() {
228 BytecodeArray* bytecode_array = debug_info_->original_bytecode_array();
229 interpreter::Bytecode bytecode =
230 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset()));
231
232 if (bytecode == interpreter::Bytecode::kDebugger) {
233 return DEBUGGER_STATEMENT;
234 } else if (bytecode == interpreter::Bytecode::kReturn) {
235 return DEBUG_BREAK_SLOT_AT_RETURN;
Ben Murdochda12d292016-06-02 14:46:10 +0100236 } else if (bytecode == interpreter::Bytecode::kTailCall) {
237 return isolate()->is_tail_call_elimination_enabled()
238 ? DEBUG_BREAK_SLOT_AT_TAIL_CALL
239 : DEBUG_BREAK_SLOT_AT_CALL;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100240 } else if (interpreter::Bytecodes::IsCallOrNew(bytecode)) {
241 return DEBUG_BREAK_SLOT_AT_CALL;
242 } else if (source_position_iterator_.is_statement()) {
243 return DEBUG_BREAK_SLOT;
244 } else {
245 return NOT_DEBUG_BREAK;
246 }
247}
248
249BreakLocation BreakLocation::BytecodeArrayIterator::GetBreakLocation() {
250 return BreakLocation(debug_info_, GetDebugBreakType(), code_offset(),
251 position(), statement_position());
252}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000253
254// Find the break point at the supplied address, or the closest one before
255// the address.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100256BreakLocation BreakLocation::FromCodeOffset(Handle<DebugInfo> debug_info,
257 int offset) {
258 base::SmartPointer<Iterator> it(GetIterator(debug_info));
259 it->SkipTo(BreakIndexFromCodeOffset(debug_info, offset));
260 return it->GetBreakLocation();
261}
262
Ben Murdoch097c5b22016-05-18 11:27:45 +0100263int CallOffsetFromCodeOffset(int code_offset, bool is_interpreted) {
264 // Code offset points to the instruction after the call. Subtract 1 to
265 // exclude that instruction from the search. For bytecode, the code offset
266 // still points to the call.
267 return is_interpreted ? code_offset : code_offset - 1;
268}
269
270BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info,
271 JavaScriptFrame* frame) {
Ben Murdochc5610432016-08-08 18:44:38 +0100272 FrameSummary summary = FrameSummary::GetFirst(frame);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100273 int call_offset =
274 CallOffsetFromCodeOffset(summary.code_offset(), frame->is_interpreted());
275 return FromCodeOffset(debug_info, call_offset);
276}
277
Ben Murdoch097c5b22016-05-18 11:27:45 +0100278void BreakLocation::AllForStatementPosition(Handle<DebugInfo> debug_info,
279 int statement_position,
280 List<BreakLocation>* result_out) {
281 for (base::SmartPointer<Iterator> it(GetIterator(debug_info)); !it->Done();
282 it->Next()) {
283 if (it->statement_position() == statement_position) {
284 result_out->Add(it->GetBreakLocation());
285 }
286 }
287}
288
289int BreakLocation::BreakIndexFromCodeOffset(Handle<DebugInfo> debug_info,
290 int offset) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000291 // Run through all break points to locate the one closest to the address.
292 int closest_break = 0;
293 int distance = kMaxInt;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100294 DCHECK(0 <= offset && offset < debug_info->abstract_code()->Size());
295 for (base::SmartPointer<Iterator> it(GetIterator(debug_info)); !it->Done();
296 it->Next()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000297 // Check if this break point is closer that what was previously found.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100298 if (it->code_offset() <= offset && offset - it->code_offset() < distance) {
299 closest_break = it->break_index();
300 distance = offset - it->code_offset();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000301 // Check whether we can't get any closer.
302 if (distance == 0) break;
303 }
304 }
305 return closest_break;
306}
307
308
309BreakLocation BreakLocation::FromPosition(Handle<DebugInfo> debug_info,
310 int position,
311 BreakPositionAlignment alignment) {
312 // Run through all break points to locate the one closest to the source
313 // position.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000314 int distance = kMaxInt;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100315 base::SmartPointer<Iterator> it(GetIterator(debug_info));
316 BreakLocation closest_break = it->GetBreakLocation();
317 while (!it->Done()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318 int next_position;
319 if (alignment == STATEMENT_ALIGNED) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100320 next_position = it->statement_position();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000321 } else {
322 DCHECK(alignment == BREAK_POSITION_ALIGNED);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100323 next_position = it->position();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000324 }
325 if (position <= next_position && next_position - position < distance) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100326 closest_break = it->GetBreakLocation();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000327 distance = next_position - position;
328 // Check whether we can't get any closer.
329 if (distance == 0) break;
330 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100331 it->Next();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000332 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100333 return closest_break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000334}
335
336
337void BreakLocation::SetBreakPoint(Handle<Object> break_point_object) {
338 // If there is not already a real break point here patch code with debug
339 // break.
340 if (!HasBreakPoint()) SetDebugBreak();
341 DCHECK(IsDebugBreak() || IsDebuggerStatement());
342 // Set the break point information.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100343 DebugInfo::SetBreakPoint(debug_info_, code_offset_, position_,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000344 statement_position_, break_point_object);
345}
346
347
348void BreakLocation::ClearBreakPoint(Handle<Object> break_point_object) {
349 // Clear the break point information.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100350 DebugInfo::ClearBreakPoint(debug_info_, code_offset_, break_point_object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000351 // If there are no more break points here remove the debug break.
352 if (!HasBreakPoint()) {
353 ClearDebugBreak();
354 DCHECK(!IsDebugBreak());
355 }
356}
357
358
359void BreakLocation::SetOneShot() {
360 // Debugger statement always calls debugger. No need to modify it.
361 if (IsDebuggerStatement()) return;
362
363 // If there is a real break point here no more to do.
364 if (HasBreakPoint()) {
365 DCHECK(IsDebugBreak());
366 return;
367 }
368
369 // Patch code with debug break.
370 SetDebugBreak();
371}
372
373
374void BreakLocation::ClearOneShot() {
375 // Debugger statement always calls debugger. No need to modify it.
376 if (IsDebuggerStatement()) return;
377
378 // If there is a real break point here no more to do.
379 if (HasBreakPoint()) {
380 DCHECK(IsDebugBreak());
381 return;
382 }
383
384 // Patch code removing debug break.
385 ClearDebugBreak();
386 DCHECK(!IsDebugBreak());
387}
388
389
390void BreakLocation::SetDebugBreak() {
391 // Debugger statement always calls debugger. No need to modify it.
392 if (IsDebuggerStatement()) return;
393
394 // If there is already a break point here just return. This might happen if
395 // the same code is flooded with break points twice. Flooding the same
396 // function twice might happen when stepping in a function with an exception
397 // handler as the handler and the function is the same.
398 if (IsDebugBreak()) return;
399
400 DCHECK(IsDebugBreakSlot());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100401 if (abstract_code()->IsCode()) {
402 Code* code = abstract_code()->GetCode();
403 DCHECK(code->kind() == Code::FUNCTION);
404 Builtins* builtins = isolate()->builtins();
405 Handle<Code> target = IsReturn() ? builtins->Return_DebugBreak()
406 : builtins->Slot_DebugBreak();
407 Address pc = code->instruction_start() + code_offset();
408 DebugCodegen::PatchDebugBreakSlot(isolate(), pc, target);
409 } else {
410 BytecodeArray* bytecode_array = abstract_code()->GetBytecodeArray();
411 interpreter::Bytecode bytecode =
412 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset()));
413 interpreter::Bytecode debugbreak =
414 interpreter::Bytecodes::GetDebugBreak(bytecode);
415 bytecode_array->set(code_offset(),
416 interpreter::Bytecodes::ToByte(debugbreak));
417 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000418 DCHECK(IsDebugBreak());
419}
420
421
422void BreakLocation::ClearDebugBreak() {
423 // Debugger statement always calls debugger. No need to modify it.
424 if (IsDebuggerStatement()) return;
425
426 DCHECK(IsDebugBreakSlot());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100427 if (abstract_code()->IsCode()) {
428 Code* code = abstract_code()->GetCode();
429 DCHECK(code->kind() == Code::FUNCTION);
430 Address pc = code->instruction_start() + code_offset();
431 DebugCodegen::ClearDebugBreakSlot(isolate(), pc);
432 } else {
433 BytecodeArray* bytecode_array = abstract_code()->GetBytecodeArray();
434 BytecodeArray* original = debug_info_->original_bytecode_array();
435 bytecode_array->set(code_offset(), original->get(code_offset()));
436 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000437 DCHECK(!IsDebugBreak());
438}
439
440
441bool BreakLocation::IsDebugBreak() const {
442 if (IsDebuggerStatement()) return false;
443 DCHECK(IsDebugBreakSlot());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100444 if (abstract_code()->IsCode()) {
445 Code* code = abstract_code()->GetCode();
446 DCHECK(code->kind() == Code::FUNCTION);
447 Address pc = code->instruction_start() + code_offset();
448 return DebugCodegen::DebugBreakSlotIsPatched(pc);
449 } else {
450 BytecodeArray* bytecode_array = abstract_code()->GetBytecodeArray();
451 interpreter::Bytecode bytecode =
452 interpreter::Bytecodes::FromByte(bytecode_array->get(code_offset()));
453 return interpreter::Bytecodes::IsDebugBreak(bytecode);
454 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000455}
456
457
458Handle<Object> BreakLocation::BreakPointObjects() const {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100459 return debug_info_->GetBreakPointObjects(code_offset_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000460}
461
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000462void DebugFeatureTracker::Track(DebugFeatureTracker::Feature feature) {
463 uint32_t mask = 1 << feature;
464 // Only count one sample per feature and isolate.
465 if (bitfield_ & mask) return;
466 isolate_->counters()->debug_feature_usage()->AddSample(feature);
467 bitfield_ |= mask;
468}
469
470
471// Threading support.
472void Debug::ThreadInit() {
473 thread_local_.break_count_ = 0;
474 thread_local_.break_id_ = 0;
475 thread_local_.break_frame_id_ = StackFrame::NO_ID;
476 thread_local_.last_step_action_ = StepNone;
477 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
478 thread_local_.last_fp_ = 0;
479 thread_local_.target_fp_ = 0;
480 thread_local_.step_in_enabled_ = false;
Ben Murdochda12d292016-06-02 14:46:10 +0100481 thread_local_.return_value_ = Handle<Object>();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000482 // TODO(isolates): frames_are_dropped_?
483 base::NoBarrier_Store(&thread_local_.current_debug_scope_,
484 static_cast<base::AtomicWord>(0));
485}
486
487
488char* Debug::ArchiveDebug(char* storage) {
489 char* to = storage;
490 MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
491 ThreadInit();
492 return storage + ArchiveSpacePerThread();
493}
494
495
496char* Debug::RestoreDebug(char* storage) {
497 char* from = storage;
498 MemCopy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
499 return storage + ArchiveSpacePerThread();
500}
501
502
503int Debug::ArchiveSpacePerThread() {
504 return sizeof(ThreadLocal);
505}
506
507
508DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
509 // Globalize the request debug info object and make it weak.
510 GlobalHandles* global_handles = debug_info->GetIsolate()->global_handles();
511 debug_info_ =
512 Handle<DebugInfo>::cast(global_handles->Create(debug_info)).location();
513}
514
515
516DebugInfoListNode::~DebugInfoListNode() {
517 if (debug_info_ == nullptr) return;
518 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_));
519 debug_info_ = nullptr;
520}
521
522
523bool Debug::Load() {
524 // Return if debugger is already loaded.
525 if (is_loaded()) return true;
526
527 // Bail out if we're already in the process of compiling the native
528 // JavaScript source code for the debugger.
529 if (is_suppressed_) return false;
530 SuppressDebug while_loading(this);
531
532 // Disable breakpoints and interrupts while compiling and running the
533 // debugger scripts including the context creation code.
534 DisableBreak disable(this, true);
535 PostponeInterruptsScope postpone(isolate_);
536
537 // Create the debugger context.
538 HandleScope scope(isolate_);
539 ExtensionConfiguration no_extensions;
540 Handle<Context> context = isolate_->bootstrapper()->CreateEnvironment(
541 MaybeHandle<JSGlobalProxy>(), v8::Local<ObjectTemplate>(), &no_extensions,
542 DEBUG_CONTEXT);
543
544 // Fail if no context could be created.
545 if (context.is_null()) return false;
546
547 debug_context_ = Handle<Context>::cast(
548 isolate_->global_handles()->Create(*context));
549
550 feature_tracker()->Track(DebugFeatureTracker::kActive);
551
552 return true;
553}
554
555
556void Debug::Unload() {
557 ClearAllBreakPoints();
558 ClearStepping();
559
560 // Return debugger is not loaded.
561 if (!is_loaded()) return;
562
563 // Clear debugger context global handle.
564 GlobalHandles::Destroy(Handle<Object>::cast(debug_context_).location());
565 debug_context_ = Handle<Context>();
566}
567
Ben Murdochda12d292016-06-02 14:46:10 +0100568void Debug::Break(JavaScriptFrame* frame) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000569 HandleScope scope(isolate_);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000570
571 // Initialize LiveEdit.
572 LiveEdit::InitializeThreadLocal(this);
573
574 // Just continue if breaks are disabled or debugger cannot be loaded.
575 if (break_disabled()) return;
576
577 // Enter the debugger.
578 DebugScope debug_scope(this);
579 if (debug_scope.failed()) return;
580
581 // Postpone interrupt during breakpoint processing.
582 PostponeInterruptsScope postpone(isolate_);
583
584 // Get the debug info (create it if it does not exist).
585 Handle<JSFunction> function(frame->function());
586 Handle<SharedFunctionInfo> shared(function->shared());
587 if (!EnsureDebugInfo(shared, function)) {
588 // Return if we failed to retrieve the debug info.
589 return;
590 }
591 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
592
593 // Find the break location where execution has stopped.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100594 BreakLocation location = BreakLocation::FromFrame(debug_info, frame);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000595
596 // Find actual break points, if any, and trigger debug break event.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100597 Handle<Object> break_points_hit = CheckBreakPoints(&location);
598 if (!break_points_hit->IsUndefined()) {
599 // Clear all current stepping setup.
600 ClearStepping();
601 // Notify the debug event listeners.
602 OnDebugBreak(break_points_hit, false);
603 return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000604 }
605
606 // No break point. Check for stepping.
607 StepAction step_action = last_step_action();
608 Address current_fp = frame->UnpaddedFP();
609 Address target_fp = thread_local_.target_fp_;
610 Address last_fp = thread_local_.last_fp_;
611
Ben Murdochda12d292016-06-02 14:46:10 +0100612 bool step_break = false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000613 switch (step_action) {
614 case StepNone:
615 return;
616 case StepOut:
617 // Step out has not reached the target frame yet.
618 if (current_fp < target_fp) return;
Ben Murdochda12d292016-06-02 14:46:10 +0100619 step_break = true;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000620 break;
621 case StepNext:
622 // Step next should not break in a deeper frame.
623 if (current_fp < target_fp) return;
Ben Murdochda12d292016-06-02 14:46:10 +0100624 // For step-next, a tail call is like a return and should break.
625 step_break = location.IsTailCall();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000626 // Fall through.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100627 case StepIn: {
Ben Murdochc5610432016-08-08 18:44:38 +0100628 FrameSummary summary = FrameSummary::GetFirst(frame);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100629 int offset = summary.code_offset();
Ben Murdochda12d292016-06-02 14:46:10 +0100630 step_break = step_break || location.IsReturn() ||
631 (current_fp != last_fp) ||
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000632 (thread_local_.last_statement_position_ !=
Ben Murdoch097c5b22016-05-18 11:27:45 +0100633 location.abstract_code()->SourceStatementPosition(offset));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000634 break;
Ben Murdoch097c5b22016-05-18 11:27:45 +0100635 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000636 case StepFrame:
637 step_break = current_fp != last_fp;
638 break;
639 }
640
641 // Clear all current stepping setup.
642 ClearStepping();
643
644 if (step_break) {
645 // Notify the debug event listeners.
646 OnDebugBreak(isolate_->factory()->undefined_value(), false);
647 } else {
648 // Re-prepare to continue.
649 PrepareStep(step_action);
650 }
651}
652
653
Ben Murdoch097c5b22016-05-18 11:27:45 +0100654// Find break point objects for this location, if any, and evaluate them.
655// Return an array of break point objects that evaluated true.
656Handle<Object> Debug::CheckBreakPoints(BreakLocation* location,
657 bool* has_break_points) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000658 Factory* factory = isolate_->factory();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100659 bool has_break_points_to_check =
660 break_points_active_ && location->HasBreakPoint();
661 if (has_break_points) *has_break_points = has_break_points_to_check;
662 if (!has_break_points_to_check) return factory->undefined_value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000663
Ben Murdoch097c5b22016-05-18 11:27:45 +0100664 Handle<Object> break_point_objects = location->BreakPointObjects();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000665 // Count the number of break points hit. If there are multiple break points
666 // they are in a FixedArray.
667 Handle<FixedArray> break_points_hit;
668 int break_points_hit_count = 0;
669 DCHECK(!break_point_objects->IsUndefined());
670 if (break_point_objects->IsFixedArray()) {
671 Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
672 break_points_hit = factory->NewFixedArray(array->length());
673 for (int i = 0; i < array->length(); i++) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100674 Handle<Object> break_point_object(array->get(i), isolate_);
675 if (CheckBreakPoint(break_point_object)) {
676 break_points_hit->set(break_points_hit_count++, *break_point_object);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000677 }
678 }
679 } else {
680 break_points_hit = factory->NewFixedArray(1);
681 if (CheckBreakPoint(break_point_objects)) {
682 break_points_hit->set(break_points_hit_count++, *break_point_objects);
683 }
684 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100685 if (break_points_hit_count == 0) return factory->undefined_value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000686 Handle<JSArray> result = factory->NewJSArrayWithElements(break_points_hit);
687 result->set_length(Smi::FromInt(break_points_hit_count));
688 return result;
689}
690
691
Ben Murdoch097c5b22016-05-18 11:27:45 +0100692bool Debug::IsMutedAtCurrentLocation(JavaScriptFrame* frame) {
693 // A break location is considered muted if break locations on the current
694 // statement have at least one break point, and all of these break points
695 // evaluate to false. Aside from not triggering a debug break event at the
696 // break location, we also do not trigger one for debugger statements, nor
697 // an exception event on exception at this location.
698 Object* fun = frame->function();
699 if (!fun->IsJSFunction()) return false;
700 JSFunction* function = JSFunction::cast(fun);
701 if (!function->shared()->HasDebugInfo()) return false;
702 HandleScope scope(isolate_);
703 Handle<DebugInfo> debug_info(function->shared()->GetDebugInfo());
704 // Enter the debugger.
705 DebugScope debug_scope(this);
706 if (debug_scope.failed()) return false;
707 BreakLocation current_position = BreakLocation::FromFrame(debug_info, frame);
708 List<BreakLocation> break_locations;
709 BreakLocation::AllForStatementPosition(
710 debug_info, current_position.statement_position(), &break_locations);
711 bool has_break_points_at_all = false;
712 for (int i = 0; i < break_locations.length(); i++) {
713 bool has_break_points;
714 Handle<Object> check_result =
715 CheckBreakPoints(&break_locations[i], &has_break_points);
716 has_break_points_at_all |= has_break_points;
717 if (has_break_points && !check_result->IsUndefined()) return false;
718 }
719 return has_break_points_at_all;
720}
721
722
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000723MaybeHandle<Object> Debug::CallFunction(const char* name, int argc,
724 Handle<Object> args[]) {
725 PostponeInterruptsScope no_interrupts(isolate_);
726 AssertDebugContext();
Ben Murdochda12d292016-06-02 14:46:10 +0100727 Handle<JSReceiver> holder =
728 Handle<JSReceiver>::cast(isolate_->natives_utils_object());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000729 Handle<JSFunction> fun = Handle<JSFunction>::cast(
Ben Murdochda12d292016-06-02 14:46:10 +0100730 JSReceiver::GetProperty(isolate_, holder, name).ToHandleChecked());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000731 Handle<Object> undefined = isolate_->factory()->undefined_value();
732 return Execution::TryCall(isolate_, fun, undefined, argc, args);
733}
734
735
736// Check whether a single break point object is triggered.
737bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
738 Factory* factory = isolate_->factory();
739 HandleScope scope(isolate_);
740
741 // Ignore check if break point object is not a JSObject.
742 if (!break_point_object->IsJSObject()) return true;
743
744 // Get the break id as an object.
745 Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id());
746
747 // Call IsBreakPointTriggered.
748 Handle<Object> argv[] = { break_id, break_point_object };
749 Handle<Object> result;
750 if (!CallFunction("IsBreakPointTriggered", arraysize(argv), argv)
751 .ToHandle(&result)) {
752 return false;
753 }
754
755 // Return whether the break point is triggered.
756 return result->IsTrue();
757}
758
759
760bool Debug::SetBreakPoint(Handle<JSFunction> function,
761 Handle<Object> break_point_object,
762 int* source_position) {
763 HandleScope scope(isolate_);
764
765 // Make sure the function is compiled and has set up the debug info.
766 Handle<SharedFunctionInfo> shared(function->shared());
767 if (!EnsureDebugInfo(shared, function)) {
768 // Return if retrieving debug info failed.
769 return true;
770 }
771
772 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
773 // Source positions starts with zero.
774 DCHECK(*source_position >= 0);
775
776 // Find the break point and change it.
777 BreakLocation location = BreakLocation::FromPosition(
778 debug_info, *source_position, STATEMENT_ALIGNED);
779 *source_position = location.statement_position();
780 location.SetBreakPoint(break_point_object);
781
782 feature_tracker()->Track(DebugFeatureTracker::kBreakPoint);
783
784 // At least one active break point now.
785 return debug_info->GetBreakPointCount() > 0;
786}
787
788
789bool Debug::SetBreakPointForScript(Handle<Script> script,
790 Handle<Object> break_point_object,
791 int* source_position,
792 BreakPositionAlignment alignment) {
793 HandleScope scope(isolate_);
794
795 // Obtain shared function info for the function.
796 Handle<Object> result =
797 FindSharedFunctionInfoInScript(script, *source_position);
798 if (result->IsUndefined()) return false;
799
800 // Make sure the function has set up the debug info.
801 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(result);
802 if (!EnsureDebugInfo(shared, Handle<JSFunction>::null())) {
803 // Return if retrieving debug info failed.
804 return false;
805 }
806
807 // Find position within function. The script position might be before the
808 // source position of the first function.
809 int position;
810 if (shared->start_position() > *source_position) {
811 position = 0;
812 } else {
813 position = *source_position - shared->start_position();
814 }
815
816 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
817 // Source positions starts with zero.
818 DCHECK(position >= 0);
819
820 // Find the break point and change it.
821 BreakLocation location =
822 BreakLocation::FromPosition(debug_info, position, alignment);
823 location.SetBreakPoint(break_point_object);
824
825 feature_tracker()->Track(DebugFeatureTracker::kBreakPoint);
826
827 position = (alignment == STATEMENT_ALIGNED) ? location.statement_position()
828 : location.position();
829
830 *source_position = position + shared->start_position();
831
832 // At least one active break point now.
833 DCHECK(debug_info->GetBreakPointCount() > 0);
834 return true;
835}
836
837
838void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
839 HandleScope scope(isolate_);
840
841 DebugInfoListNode* node = debug_info_list_;
842 while (node != NULL) {
843 Handle<Object> result =
844 DebugInfo::FindBreakPointInfo(node->debug_info(), break_point_object);
845 if (!result->IsUndefined()) {
846 // Get information in the break point.
847 Handle<BreakPointInfo> break_point_info =
848 Handle<BreakPointInfo>::cast(result);
849 Handle<DebugInfo> debug_info = node->debug_info();
850
Ben Murdoch097c5b22016-05-18 11:27:45 +0100851 BreakLocation location = BreakLocation::FromCodeOffset(
852 debug_info, break_point_info->code_offset());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000853 location.ClearBreakPoint(break_point_object);
854
855 // If there are no more break points left remove the debug info for this
856 // function.
857 if (debug_info->GetBreakPointCount() == 0) {
858 RemoveDebugInfoAndClearFromShared(debug_info);
859 }
860
861 return;
862 }
863 node = node->next();
864 }
865}
866
867
868// Clear out all the debug break code. This is ONLY supposed to be used when
869// shutting down the debugger as it will leave the break point information in
870// DebugInfo even though the code is patched back to the non break point state.
871void Debug::ClearAllBreakPoints() {
872 for (DebugInfoListNode* node = debug_info_list_; node != NULL;
873 node = node->next()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +0100874 for (base::SmartPointer<BreakLocation::Iterator> it(
875 BreakLocation::GetIterator(node->debug_info()));
876 !it->Done(); it->Next()) {
877 it->GetBreakLocation().ClearDebugBreak();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000878 }
879 }
880 // Remove all debug info.
881 while (debug_info_list_ != NULL) {
882 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info());
883 }
884}
885
886
887void Debug::FloodWithOneShot(Handle<JSFunction> function,
888 BreakLocatorType type) {
889 // Debug utility functions are not subject to debugging.
890 if (function->native_context() == *debug_context()) return;
891
892 if (!function->shared()->IsSubjectToDebugging()) {
893 // Builtin functions are not subject to stepping, but need to be
894 // deoptimized, because optimized code does not check for debug
895 // step in at call sites.
896 Deoptimizer::DeoptimizeFunction(*function);
897 return;
898 }
899 // Make sure the function is compiled and has set up the debug info.
900 Handle<SharedFunctionInfo> shared(function->shared());
901 if (!EnsureDebugInfo(shared, function)) {
902 // Return if we failed to retrieve the debug info.
903 return;
904 }
905
906 // Flood the function with break points.
907 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100908 for (base::SmartPointer<BreakLocation::Iterator> it(
909 BreakLocation::GetIterator(debug_info, type));
910 !it->Done(); it->Next()) {
911 it->GetBreakLocation().SetOneShot();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000912 }
913}
914
915
916void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
917 if (type == BreakUncaughtException) {
918 break_on_uncaught_exception_ = enable;
919 } else {
920 break_on_exception_ = enable;
921 }
922}
923
924
925bool Debug::IsBreakOnException(ExceptionBreakType type) {
926 if (type == BreakUncaughtException) {
927 return break_on_uncaught_exception_;
928 } else {
929 return break_on_exception_;
930 }
931}
932
933
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000934void Debug::PrepareStepIn(Handle<JSFunction> function) {
935 if (!is_active()) return;
936 if (last_step_action() < StepIn) return;
937 if (in_debug_scope()) return;
938 if (thread_local_.step_in_enabled_) {
939 FloodWithOneShot(function);
940 }
941}
942
943
944void Debug::PrepareStepOnThrow() {
945 if (!is_active()) return;
946 if (last_step_action() == StepNone) return;
947 if (in_debug_scope()) return;
948
949 ClearOneShot();
950
951 // Iterate through the JavaScript stack looking for handlers.
952 JavaScriptFrameIterator it(isolate_);
953 while (!it.done()) {
954 JavaScriptFrame* frame = it.frame();
Ben Murdoch097c5b22016-05-18 11:27:45 +0100955 if (frame->LookupExceptionHandlerInTable(nullptr, nullptr) > 0) break;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000956 it.Advance();
957 }
958
Ben Murdochc5610432016-08-08 18:44:38 +0100959 if (last_step_action() == StepNext) {
960 while (!it.done()) {
961 Address current_fp = it.frame()->UnpaddedFP();
962 if (current_fp >= thread_local_.target_fp_) break;
963 it.Advance();
964 }
965 }
966
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000967 // Find the closest Javascript frame we can flood with one-shots.
968 while (!it.done() &&
969 !it.frame()->function()->shared()->IsSubjectToDebugging()) {
970 it.Advance();
971 }
972
973 if (it.done()) return; // No suitable Javascript catch handler.
974
975 FloodWithOneShot(Handle<JSFunction>(it.frame()->function()));
976}
977
978
979void Debug::PrepareStep(StepAction step_action) {
980 HandleScope scope(isolate_);
981
982 DCHECK(in_debug_scope());
983
984 // Get the frame where the execution has stopped and skip the debug frame if
985 // any. The debug frame will only be present if execution was stopped due to
986 // hitting a break point. In other situations (e.g. unhandled exception) the
987 // debug frame is not present.
988 StackFrame::Id frame_id = break_frame_id();
989 // If there is no JavaScript stack don't do anything.
990 if (frame_id == StackFrame::NO_ID) return;
991
992 JavaScriptFrameIterator frames_it(isolate_, frame_id);
993 JavaScriptFrame* frame = frames_it.frame();
994
995 feature_tracker()->Track(DebugFeatureTracker::kStepping);
996
997 // Remember this step action and count.
998 thread_local_.last_step_action_ = step_action;
999 STATIC_ASSERT(StepFrame > StepIn);
1000 thread_local_.step_in_enabled_ = (step_action >= StepIn);
1001
1002 // If the function on the top frame is unresolved perform step out. This will
1003 // be the case when calling unknown function and having the debugger stopped
1004 // in an unhandled exception.
1005 if (!frame->function()->IsJSFunction()) {
1006 // Step out: Find the calling JavaScript frame and flood it with
1007 // breakpoints.
1008 frames_it.Advance();
1009 // Fill the function to return to with one-shot break points.
1010 JSFunction* function = frames_it.frame()->function();
1011 FloodWithOneShot(Handle<JSFunction>(function));
1012 return;
1013 }
1014
1015 // Get the debug info (create it if it does not exist).
Ben Murdochc5610432016-08-08 18:44:38 +01001016 FrameSummary summary = FrameSummary::GetFirst(frame);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001017 Handle<JSFunction> function(summary.function());
1018 Handle<SharedFunctionInfo> shared(function->shared());
1019 if (!EnsureDebugInfo(shared, function)) {
1020 // Return if ensuring debug info failed.
1021 return;
1022 }
1023
1024 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
1025 // Refresh frame summary if the code has been recompiled for debugging.
Ben Murdoch097c5b22016-05-18 11:27:45 +01001026 if (AbstractCode::cast(shared->code()) != *summary.abstract_code()) {
Ben Murdochc5610432016-08-08 18:44:38 +01001027 summary = FrameSummary::GetFirst(frame);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001028 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001029
Ben Murdoch097c5b22016-05-18 11:27:45 +01001030 int call_offset =
1031 CallOffsetFromCodeOffset(summary.code_offset(), frame->is_interpreted());
1032 BreakLocation location =
1033 BreakLocation::FromCodeOffset(debug_info, call_offset);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001034
Ben Murdochda12d292016-06-02 14:46:10 +01001035 // Any step at a return is a step-out.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001036 if (location.IsReturn()) step_action = StepOut;
Ben Murdochda12d292016-06-02 14:46:10 +01001037 // A step-next at a tail call is a step-out.
1038 if (location.IsTailCall() && step_action == StepNext) step_action = StepOut;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001039
1040 thread_local_.last_statement_position_ =
Ben Murdoch097c5b22016-05-18 11:27:45 +01001041 debug_info->abstract_code()->SourceStatementPosition(
1042 summary.code_offset());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001043 thread_local_.last_fp_ = frame->UnpaddedFP();
1044
1045 switch (step_action) {
1046 case StepNone:
1047 UNREACHABLE();
1048 break;
1049 case StepOut:
1050 // Advance to caller frame.
1051 frames_it.Advance();
1052 // Skip native and extension functions on the stack.
1053 while (!frames_it.done() &&
1054 !frames_it.frame()->function()->shared()->IsSubjectToDebugging()) {
1055 // Builtin functions are not subject to stepping, but need to be
1056 // deoptimized to include checks for step-in at call sites.
1057 Deoptimizer::DeoptimizeFunction(frames_it.frame()->function());
1058 frames_it.Advance();
1059 }
1060 if (frames_it.done()) {
1061 // Stepping out to the embedder. Disable step-in to avoid stepping into
1062 // the next (unrelated) call that the embedder makes.
1063 thread_local_.step_in_enabled_ = false;
1064 } else {
1065 // Fill the caller function to return to with one-shot break points.
1066 Handle<JSFunction> caller_function(frames_it.frame()->function());
1067 FloodWithOneShot(caller_function);
1068 thread_local_.target_fp_ = frames_it.frame()->UnpaddedFP();
1069 }
1070 // Clear last position info. For stepping out it does not matter.
1071 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
1072 thread_local_.last_fp_ = 0;
1073 break;
1074 case StepNext:
1075 thread_local_.target_fp_ = frame->UnpaddedFP();
1076 FloodWithOneShot(function);
1077 break;
1078 case StepIn:
1079 FloodWithOneShot(function);
1080 break;
1081 case StepFrame:
1082 // No point in setting one-shot breaks at places where we are not about
1083 // to leave the current frame.
1084 FloodWithOneShot(function, CALLS_AND_RETURNS);
1085 break;
1086 }
1087}
1088
1089
1090// Simple function for returning the source positions for active break points.
1091Handle<Object> Debug::GetSourceBreakLocations(
1092 Handle<SharedFunctionInfo> shared,
1093 BreakPositionAlignment position_alignment) {
1094 Isolate* isolate = shared->GetIsolate();
1095 Heap* heap = isolate->heap();
1096 if (!shared->HasDebugInfo()) {
1097 return Handle<Object>(heap->undefined_value(), isolate);
1098 }
1099 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
1100 if (debug_info->GetBreakPointCount() == 0) {
1101 return Handle<Object>(heap->undefined_value(), isolate);
1102 }
1103 Handle<FixedArray> locations =
1104 isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount());
1105 int count = 0;
1106 for (int i = 0; i < debug_info->break_points()->length(); ++i) {
1107 if (!debug_info->break_points()->get(i)->IsUndefined()) {
1108 BreakPointInfo* break_point_info =
1109 BreakPointInfo::cast(debug_info->break_points()->get(i));
1110 int break_points = break_point_info->GetBreakPointCount();
1111 if (break_points == 0) continue;
1112 Smi* position = NULL;
1113 switch (position_alignment) {
1114 case STATEMENT_ALIGNED:
1115 position = Smi::FromInt(break_point_info->statement_position());
1116 break;
1117 case BREAK_POSITION_ALIGNED:
1118 position = Smi::FromInt(break_point_info->source_position());
1119 break;
1120 }
1121 for (int j = 0; j < break_points; ++j) locations->set(count++, position);
1122 }
1123 }
1124 return locations;
1125}
1126
1127
1128void Debug::ClearStepping() {
1129 // Clear the various stepping setup.
1130 ClearOneShot();
1131
1132 thread_local_.last_step_action_ = StepNone;
1133 thread_local_.step_in_enabled_ = false;
1134 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
1135 thread_local_.last_fp_ = 0;
1136 thread_local_.target_fp_ = 0;
1137}
1138
1139
1140// Clears all the one-shot break points that are currently set. Normally this
1141// function is called each time a break point is hit as one shot break points
1142// are used to support stepping.
1143void Debug::ClearOneShot() {
1144 // The current implementation just runs through all the breakpoints. When the
1145 // last break point for a function is removed that function is automatically
1146 // removed from the list.
1147 for (DebugInfoListNode* node = debug_info_list_; node != NULL;
1148 node = node->next()) {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001149 for (base::SmartPointer<BreakLocation::Iterator> it(
1150 BreakLocation::GetIterator(node->debug_info()));
1151 !it->Done(); it->Next()) {
1152 it->GetBreakLocation().ClearOneShot();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001153 }
1154 }
1155}
1156
1157
1158void Debug::EnableStepIn() {
1159 STATIC_ASSERT(StepFrame > StepIn);
1160 thread_local_.step_in_enabled_ = (last_step_action() >= StepIn);
1161}
1162
1163
1164bool MatchingCodeTargets(Code* target1, Code* target2) {
1165 if (target1 == target2) return true;
1166 if (target1->kind() != target2->kind()) return false;
1167 return target1->is_handler() || target1->is_inline_cache_stub();
1168}
1169
1170
1171// Count the number of calls before the current frame PC to find the
1172// corresponding PC in the newly recompiled code.
1173static Address ComputeNewPcForRedirect(Code* new_code, Code* old_code,
1174 Address old_pc) {
1175 DCHECK_EQ(old_code->kind(), Code::FUNCTION);
1176 DCHECK_EQ(new_code->kind(), Code::FUNCTION);
1177 DCHECK(new_code->has_debug_break_slots());
1178 static const int mask = RelocInfo::kCodeTargetMask;
1179
1180 // Find the target of the current call.
1181 Code* target = NULL;
1182 intptr_t delta = 0;
1183 for (RelocIterator it(old_code, mask); !it.done(); it.next()) {
1184 RelocInfo* rinfo = it.rinfo();
1185 Address current_pc = rinfo->pc();
1186 // The frame PC is behind the call instruction by the call instruction size.
1187 if (current_pc > old_pc) break;
1188 delta = old_pc - current_pc;
1189 target = Code::GetCodeFromTargetAddress(rinfo->target_address());
1190 }
1191
1192 // Count the number of calls to the same target before the current call.
1193 int index = 0;
1194 for (RelocIterator it(old_code, mask); !it.done(); it.next()) {
1195 RelocInfo* rinfo = it.rinfo();
1196 Address current_pc = rinfo->pc();
1197 if (current_pc > old_pc) break;
1198 Code* current = Code::GetCodeFromTargetAddress(rinfo->target_address());
1199 if (MatchingCodeTargets(target, current)) index++;
1200 }
1201
1202 DCHECK(index > 0);
1203
1204 // Repeat the count on the new code to find corresponding call.
1205 for (RelocIterator it(new_code, mask); !it.done(); it.next()) {
1206 RelocInfo* rinfo = it.rinfo();
1207 Code* current = Code::GetCodeFromTargetAddress(rinfo->target_address());
1208 if (MatchingCodeTargets(target, current)) index--;
1209 if (index == 0) return rinfo->pc() + delta;
1210 }
1211
1212 UNREACHABLE();
1213 return NULL;
1214}
1215
1216
1217// Count the number of continuations at which the current pc offset is at.
1218static int ComputeContinuationIndexFromPcOffset(Code* code, int pc_offset) {
1219 DCHECK_EQ(code->kind(), Code::FUNCTION);
1220 Address pc = code->instruction_start() + pc_offset;
1221 int mask = RelocInfo::ModeMask(RelocInfo::GENERATOR_CONTINUATION);
1222 int index = 0;
1223 for (RelocIterator it(code, mask); !it.done(); it.next()) {
1224 index++;
1225 RelocInfo* rinfo = it.rinfo();
1226 Address current_pc = rinfo->pc();
1227 if (current_pc == pc) break;
1228 DCHECK(current_pc < pc);
1229 }
1230 return index;
1231}
1232
1233
1234// Find the pc offset for the given continuation index.
1235static int ComputePcOffsetFromContinuationIndex(Code* code, int index) {
1236 DCHECK_EQ(code->kind(), Code::FUNCTION);
1237 DCHECK(code->has_debug_break_slots());
1238 int mask = RelocInfo::ModeMask(RelocInfo::GENERATOR_CONTINUATION);
1239 RelocIterator it(code, mask);
1240 for (int i = 1; i < index; i++) it.next();
1241 return static_cast<int>(it.rinfo()->pc() - code->instruction_start());
1242}
1243
1244
1245class RedirectActiveFunctions : public ThreadVisitor {
1246 public:
1247 explicit RedirectActiveFunctions(SharedFunctionInfo* shared)
1248 : shared_(shared) {
1249 DCHECK(shared->HasDebugCode());
1250 }
1251
1252 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
1253 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
1254 JavaScriptFrame* frame = it.frame();
1255 JSFunction* function = frame->function();
1256 if (frame->is_optimized()) continue;
1257 if (!function->Inlines(shared_)) continue;
1258
Ben Murdoch097c5b22016-05-18 11:27:45 +01001259 if (frame->is_interpreted()) {
1260 InterpretedFrame* interpreted_frame =
1261 reinterpret_cast<InterpretedFrame*>(frame);
1262 BytecodeArray* debug_copy =
1263 shared_->GetDebugInfo()->abstract_code()->GetBytecodeArray();
1264 interpreted_frame->PatchBytecodeArray(debug_copy);
1265 continue;
1266 }
1267
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001268 Code* frame_code = frame->LookupCode();
1269 DCHECK(frame_code->kind() == Code::FUNCTION);
1270 if (frame_code->has_debug_break_slots()) continue;
1271
1272 Code* new_code = function->shared()->code();
1273 Address old_pc = frame->pc();
1274 Address new_pc = ComputeNewPcForRedirect(new_code, frame_code, old_pc);
1275
1276 if (FLAG_trace_deopt) {
1277 PrintF("Replacing pc for debugging: %08" V8PRIxPTR " => %08" V8PRIxPTR
1278 "\n",
1279 reinterpret_cast<intptr_t>(old_pc),
1280 reinterpret_cast<intptr_t>(new_pc));
1281 }
1282
1283 if (FLAG_enable_embedded_constant_pool) {
1284 // Update constant pool pointer for new code.
1285 frame->set_constant_pool(new_code->constant_pool());
1286 }
1287
1288 // Patch the return address to return into the code with
1289 // debug break slots.
1290 frame->set_pc(new_pc);
1291 }
1292 }
1293
1294 private:
1295 SharedFunctionInfo* shared_;
1296 DisallowHeapAllocation no_gc_;
1297};
1298
1299
1300bool Debug::PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared) {
1301 DCHECK(shared->is_compiled());
1302
1303 if (isolate_->concurrent_recompilation_enabled()) {
1304 isolate_->optimizing_compile_dispatcher()->Flush();
1305 }
1306
1307 List<Handle<JSFunction> > functions;
1308 List<Handle<JSGeneratorObject> > suspended_generators;
1309
1310 // Flush all optimized code maps. Note that the below heap iteration does not
1311 // cover this, because the given function might have been inlined into code
1312 // for which no JSFunction exists.
1313 {
1314 SharedFunctionInfo::Iterator iterator(isolate_);
1315 while (SharedFunctionInfo* shared = iterator.Next()) {
1316 if (!shared->OptimizedCodeMapIsCleared()) {
1317 shared->ClearOptimizedCodeMap();
1318 }
1319 }
1320 }
1321
1322 // Make sure we abort incremental marking.
1323 isolate_->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1324 "prepare for break points");
Ben Murdochda12d292016-06-02 14:46:10 +01001325
Ben Murdoch097c5b22016-05-18 11:27:45 +01001326 bool is_interpreted = shared->HasBytecodeArray();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001327
1328 {
Ben Murdoch097c5b22016-05-18 11:27:45 +01001329 // TODO(yangguo): with bytecode, we still walk the heap to find all
1330 // optimized code for the function to deoptimize. We can probably be
1331 // smarter here and avoid the heap walk.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001332 HeapIterator iterator(isolate_->heap());
1333 HeapObject* obj;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001334 bool include_generators = !is_interpreted && shared->is_generator();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001335
1336 while ((obj = iterator.next())) {
1337 if (obj->IsJSFunction()) {
1338 JSFunction* function = JSFunction::cast(obj);
1339 if (!function->Inlines(*shared)) continue;
1340 if (function->code()->kind() == Code::OPTIMIZED_FUNCTION) {
1341 Deoptimizer::DeoptimizeFunction(function);
1342 }
Ben Murdoch097c5b22016-05-18 11:27:45 +01001343 if (is_interpreted) continue;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001344 if (function->shared() == *shared) functions.Add(handle(function));
1345 } else if (include_generators && obj->IsJSGeneratorObject()) {
1346 JSGeneratorObject* generator_obj = JSGeneratorObject::cast(obj);
1347 if (!generator_obj->is_suspended()) continue;
1348 JSFunction* function = generator_obj->function();
1349 if (!function->Inlines(*shared)) continue;
1350 int pc_offset = generator_obj->continuation();
1351 int index =
1352 ComputeContinuationIndexFromPcOffset(function->code(), pc_offset);
1353 generator_obj->set_continuation(index);
1354 suspended_generators.Add(handle(generator_obj));
1355 }
1356 }
1357 }
1358
Ben Murdoch097c5b22016-05-18 11:27:45 +01001359 // We do not need to replace code to debug bytecode.
1360 DCHECK(!is_interpreted || functions.length() == 0);
1361 DCHECK(!is_interpreted || suspended_generators.length() == 0);
1362
1363 // We do not need to recompile to debug bytecode.
1364 if (!is_interpreted && !shared->HasDebugCode()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001365 DCHECK(functions.length() > 0);
1366 if (!Compiler::CompileDebugCode(functions.first())) return false;
1367 }
1368
1369 for (Handle<JSFunction> const function : functions) {
1370 function->ReplaceCode(shared->code());
1371 }
1372
1373 for (Handle<JSGeneratorObject> const generator_obj : suspended_generators) {
1374 int index = generator_obj->continuation();
1375 int pc_offset = ComputePcOffsetFromContinuationIndex(shared->code(), index);
1376 generator_obj->set_continuation(pc_offset);
1377 }
1378
1379 // Update PCs on the stack to point to recompiled code.
1380 RedirectActiveFunctions redirect_visitor(*shared);
1381 redirect_visitor.VisitThread(isolate_, isolate_->thread_local_top());
1382 isolate_->thread_manager()->IterateArchivedThreads(&redirect_visitor);
1383
1384 return true;
1385}
1386
1387
1388class SharedFunctionInfoFinder {
1389 public:
1390 explicit SharedFunctionInfoFinder(int target_position)
1391 : current_candidate_(NULL),
1392 current_candidate_closure_(NULL),
1393 current_start_position_(RelocInfo::kNoPosition),
1394 target_position_(target_position) {}
1395
1396 void NewCandidate(SharedFunctionInfo* shared, JSFunction* closure = NULL) {
1397 if (!shared->IsSubjectToDebugging()) return;
1398 int start_position = shared->function_token_position();
1399 if (start_position == RelocInfo::kNoPosition) {
1400 start_position = shared->start_position();
1401 }
1402
1403 if (start_position > target_position_) return;
1404 if (target_position_ > shared->end_position()) return;
1405
1406 if (current_candidate_ != NULL) {
1407 if (current_start_position_ == start_position &&
1408 shared->end_position() == current_candidate_->end_position()) {
1409 // If we already have a matching closure, do not throw it away.
1410 if (current_candidate_closure_ != NULL && closure == NULL) return;
1411 // If a top-level function contains only one function
1412 // declaration the source for the top-level and the function
1413 // is the same. In that case prefer the non top-level function.
1414 if (!current_candidate_->is_toplevel() && shared->is_toplevel()) return;
1415 } else if (start_position < current_start_position_ ||
1416 current_candidate_->end_position() < shared->end_position()) {
1417 return;
1418 }
1419 }
1420
1421 current_start_position_ = start_position;
1422 current_candidate_ = shared;
1423 current_candidate_closure_ = closure;
1424 }
1425
1426 SharedFunctionInfo* Result() { return current_candidate_; }
1427
1428 JSFunction* ResultClosure() { return current_candidate_closure_; }
1429
1430 private:
1431 SharedFunctionInfo* current_candidate_;
1432 JSFunction* current_candidate_closure_;
1433 int current_start_position_;
1434 int target_position_;
1435 DisallowHeapAllocation no_gc_;
1436};
1437
1438
1439// We need to find a SFI for a literal that may not yet have been compiled yet,
1440// and there may not be a JSFunction referencing it. Find the SFI closest to
1441// the given position, compile it to reveal possible inner SFIs and repeat.
1442// While we are at this, also ensure code with debug break slots so that we do
1443// not have to compile a SFI without JSFunction, which is paifu for those that
1444// cannot be compiled without context (need to find outer compilable SFI etc.)
1445Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
1446 int position) {
1447 for (int iteration = 0;; iteration++) {
1448 // Go through all shared function infos associated with this script to
1449 // find the inner most function containing this position.
1450 // If there is no shared function info for this script at all, there is
1451 // no point in looking for it by walking the heap.
1452 if (!script->shared_function_infos()->IsWeakFixedArray()) break;
1453
1454 SharedFunctionInfo* shared;
1455 {
1456 SharedFunctionInfoFinder finder(position);
1457 WeakFixedArray::Iterator iterator(script->shared_function_infos());
1458 SharedFunctionInfo* candidate;
1459 while ((candidate = iterator.Next<SharedFunctionInfo>())) {
1460 finder.NewCandidate(candidate);
1461 }
1462 shared = finder.Result();
1463 if (shared == NULL) break;
1464 // We found it if it's already compiled and has debug code.
1465 if (shared->HasDebugCode()) {
1466 Handle<SharedFunctionInfo> shared_handle(shared);
1467 // If the iteration count is larger than 1, we had to compile the outer
1468 // function in order to create this shared function info. So there can
1469 // be no JSFunction referencing it. We can anticipate creating a debug
1470 // info while bypassing PrepareFunctionForBreakpoints.
1471 if (iteration > 1) {
1472 AllowHeapAllocation allow_before_return;
1473 CreateDebugInfo(shared_handle);
1474 }
1475 return shared_handle;
1476 }
1477 }
1478 // If not, compile to reveal inner functions, if possible.
1479 if (shared->allows_lazy_compilation_without_context()) {
1480 HandleScope scope(isolate_);
1481 if (!Compiler::CompileDebugCode(handle(shared))) break;
1482 continue;
1483 }
1484
1485 // If not possible, comb the heap for the best suitable compile target.
1486 JSFunction* closure;
1487 {
1488 HeapIterator it(isolate_->heap());
1489 SharedFunctionInfoFinder finder(position);
1490 while (HeapObject* object = it.next()) {
1491 JSFunction* candidate_closure = NULL;
1492 SharedFunctionInfo* candidate = NULL;
1493 if (object->IsJSFunction()) {
1494 candidate_closure = JSFunction::cast(object);
1495 candidate = candidate_closure->shared();
1496 } else if (object->IsSharedFunctionInfo()) {
1497 candidate = SharedFunctionInfo::cast(object);
1498 if (!candidate->allows_lazy_compilation_without_context()) continue;
1499 } else {
1500 continue;
1501 }
1502 if (candidate->script() == *script) {
1503 finder.NewCandidate(candidate, candidate_closure);
1504 }
1505 }
1506 closure = finder.ResultClosure();
1507 shared = finder.Result();
1508 }
1509 if (shared == NULL) break;
1510 HandleScope scope(isolate_);
1511 if (closure == NULL) {
1512 if (!Compiler::CompileDebugCode(handle(shared))) break;
1513 } else {
1514 if (!Compiler::CompileDebugCode(handle(closure))) break;
1515 }
1516 }
1517 return isolate_->factory()->undefined_value();
1518}
1519
1520
1521// Ensures the debug information is present for shared.
1522bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared,
1523 Handle<JSFunction> function) {
1524 if (!shared->IsSubjectToDebugging()) return false;
1525
1526 // Return if we already have the debug info for shared.
1527 if (shared->HasDebugInfo()) return true;
1528
1529 if (function.is_null()) {
1530 DCHECK(shared->HasDebugCode());
Ben Murdochda12d292016-06-02 14:46:10 +01001531 } else if (!Compiler::Compile(function, Compiler::CLEAR_EXCEPTION)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001532 return false;
1533 }
1534
Ben Murdoch097c5b22016-05-18 11:27:45 +01001535 if (shared->HasBytecodeArray()) {
1536 // To prepare bytecode for debugging, we already need to have the debug
1537 // info (containing the debug copy) upfront, but since we do not recompile,
1538 // preparing for break points cannot fail.
1539 CreateDebugInfo(shared);
1540 CHECK(PrepareFunctionForBreakPoints(shared));
1541 } else {
1542 if (!PrepareFunctionForBreakPoints(shared)) return false;
1543 CreateDebugInfo(shared);
1544 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001545 return true;
1546}
1547
1548
1549void Debug::CreateDebugInfo(Handle<SharedFunctionInfo> shared) {
1550 // Create the debug info object.
1551 DCHECK(shared->HasDebugCode());
1552 Handle<DebugInfo> debug_info = isolate_->factory()->NewDebugInfo(shared);
1553
1554 // Add debug info to the list.
1555 DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
1556 node->set_next(debug_info_list_);
1557 debug_info_list_ = node;
1558}
1559
1560
1561void Debug::RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info) {
1562 HandleScope scope(isolate_);
1563 Handle<SharedFunctionInfo> shared(debug_info->shared());
1564
1565 DCHECK_NOT_NULL(debug_info_list_);
1566 // Run through the debug info objects to find this one and remove it.
1567 DebugInfoListNode* prev = NULL;
1568 DebugInfoListNode* current = debug_info_list_;
1569 while (current != NULL) {
1570 if (current->debug_info().is_identical_to(debug_info)) {
1571 // Unlink from list. If prev is NULL we are looking at the first element.
1572 if (prev == NULL) {
1573 debug_info_list_ = current->next();
1574 } else {
1575 prev->set_next(current->next());
1576 }
1577 delete current;
Ben Murdoch097c5b22016-05-18 11:27:45 +01001578 shared->set_debug_info(DebugInfo::uninitialized());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001579 return;
1580 }
1581 // Move to next in list.
1582 prev = current;
1583 current = current->next();
1584 }
1585
1586 UNREACHABLE();
1587}
1588
Ben Murdochda12d292016-06-02 14:46:10 +01001589void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
1590 after_break_target_ = NULL;
1591 if (!LiveEdit::SetAfterBreakTarget(this)) {
1592 // Continue just after the slot.
1593 after_break_target_ = frame->pc();
Ben Murdoch097c5b22016-05-18 11:27:45 +01001594 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001595}
1596
1597
1598bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
1599 HandleScope scope(isolate_);
1600
1601 // Get the executing function in which the debug break occurred.
1602 Handle<JSFunction> function(JSFunction::cast(frame->function()));
1603 Handle<SharedFunctionInfo> shared(function->shared());
1604
1605 // With no debug info there are no break points, so we can't be at a return.
1606 if (!shared->HasDebugInfo()) return false;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001607
Ben Murdoch097c5b22016-05-18 11:27:45 +01001608 DCHECK(!frame->is_optimized());
Ben Murdochc5610432016-08-08 18:44:38 +01001609 FrameSummary summary = FrameSummary::GetFirst(frame);
Ben Murdoch097c5b22016-05-18 11:27:45 +01001610
1611 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
1612 BreakLocation location =
1613 BreakLocation::FromCodeOffset(debug_info, summary.code_offset());
Ben Murdochda12d292016-06-02 14:46:10 +01001614 return location.IsReturn() || location.IsTailCall();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001615}
1616
1617
1618void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
1619 LiveEdit::FrameDropMode mode) {
1620 if (mode != LiveEdit::CURRENTLY_SET_MODE) {
1621 thread_local_.frame_drop_mode_ = mode;
1622 }
1623 thread_local_.break_frame_id_ = new_break_frame_id;
1624}
1625
1626
1627bool Debug::IsDebugGlobal(JSGlobalObject* global) {
1628 return is_loaded() && global == debug_context()->global_object();
1629}
1630
1631
1632void Debug::ClearMirrorCache() {
1633 PostponeInterruptsScope postpone(isolate_);
1634 HandleScope scope(isolate_);
1635 CallFunction("ClearMirrorCache", 0, NULL);
1636}
1637
1638
1639Handle<FixedArray> Debug::GetLoadedScripts() {
1640 isolate_->heap()->CollectAllGarbage();
1641 Factory* factory = isolate_->factory();
1642 if (!factory->script_list()->IsWeakFixedArray()) {
1643 return factory->empty_fixed_array();
1644 }
1645 Handle<WeakFixedArray> array =
1646 Handle<WeakFixedArray>::cast(factory->script_list());
1647 Handle<FixedArray> results = factory->NewFixedArray(array->Length());
1648 int length = 0;
1649 {
1650 Script::Iterator iterator(isolate_);
1651 Script* script;
1652 while ((script = iterator.Next())) {
1653 if (script->HasValidSource()) results->set(length++, script);
1654 }
1655 }
1656 results->Shrink(length);
1657 return results;
1658}
1659
1660
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001661MaybeHandle<Object> Debug::MakeExecutionState() {
1662 // Create the execution state object.
1663 Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()) };
1664 return CallFunction("MakeExecutionState", arraysize(argv), argv);
1665}
1666
1667
1668MaybeHandle<Object> Debug::MakeBreakEvent(Handle<Object> break_points_hit) {
1669 // Create the new break event object.
1670 Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()),
1671 break_points_hit };
1672 return CallFunction("MakeBreakEvent", arraysize(argv), argv);
1673}
1674
1675
1676MaybeHandle<Object> Debug::MakeExceptionEvent(Handle<Object> exception,
1677 bool uncaught,
1678 Handle<Object> promise) {
1679 // Create the new exception event object.
1680 Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()),
1681 exception,
1682 isolate_->factory()->ToBoolean(uncaught),
1683 promise };
1684 return CallFunction("MakeExceptionEvent", arraysize(argv), argv);
1685}
1686
1687
1688MaybeHandle<Object> Debug::MakeCompileEvent(Handle<Script> script,
1689 v8::DebugEvent type) {
1690 // Create the compile event object.
1691 Handle<Object> script_wrapper = Script::GetWrapper(script);
1692 Handle<Object> argv[] = { script_wrapper,
1693 isolate_->factory()->NewNumberFromInt(type) };
1694 return CallFunction("MakeCompileEvent", arraysize(argv), argv);
1695}
1696
1697
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001698MaybeHandle<Object> Debug::MakeAsyncTaskEvent(Handle<JSObject> task_event) {
1699 // Create the async task event object.
1700 Handle<Object> argv[] = { task_event };
1701 return CallFunction("MakeAsyncTaskEvent", arraysize(argv), argv);
1702}
1703
1704
1705void Debug::OnThrow(Handle<Object> exception) {
1706 if (in_debug_scope() || ignore_events()) return;
1707 PrepareStepOnThrow();
1708 // Temporarily clear any scheduled_exception to allow evaluating
1709 // JavaScript from the debug event handler.
1710 HandleScope scope(isolate_);
1711 Handle<Object> scheduled_exception;
1712 if (isolate_->has_scheduled_exception()) {
1713 scheduled_exception = handle(isolate_->scheduled_exception(), isolate_);
1714 isolate_->clear_scheduled_exception();
1715 }
1716 OnException(exception, isolate_->GetPromiseOnStackOnThrow());
1717 if (!scheduled_exception.is_null()) {
1718 isolate_->thread_local_top()->scheduled_exception_ = *scheduled_exception;
1719 }
1720}
1721
1722
1723void Debug::OnPromiseReject(Handle<JSObject> promise, Handle<Object> value) {
1724 if (in_debug_scope() || ignore_events()) return;
1725 HandleScope scope(isolate_);
1726 // Check whether the promise has been marked as having triggered a message.
1727 Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol();
1728 if (JSReceiver::GetDataProperty(promise, key)->IsUndefined()) {
1729 OnException(value, promise);
1730 }
1731}
1732
1733
1734MaybeHandle<Object> Debug::PromiseHasUserDefinedRejectHandler(
1735 Handle<JSObject> promise) {
1736 Handle<JSFunction> fun = isolate_->promise_has_user_defined_reject_handler();
1737 return Execution::Call(isolate_, fun, promise, 0, NULL);
1738}
1739
1740
1741void Debug::OnException(Handle<Object> exception, Handle<Object> promise) {
1742 // In our prediction, try-finally is not considered to catch.
1743 Isolate::CatchType catch_type = isolate_->PredictExceptionCatcher();
1744 bool uncaught = (catch_type == Isolate::NOT_CAUGHT);
1745 if (promise->IsJSObject()) {
1746 Handle<JSObject> jspromise = Handle<JSObject>::cast(promise);
1747 // Mark the promise as already having triggered a message.
1748 Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol();
1749 JSObject::SetProperty(jspromise, key, key, STRICT).Assert();
1750 // Check whether the promise reject is considered an uncaught exception.
1751 Handle<Object> has_reject_handler;
1752 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1753 isolate_, has_reject_handler,
1754 PromiseHasUserDefinedRejectHandler(jspromise), /* void */);
1755 uncaught = has_reject_handler->IsFalse();
1756 }
1757 // Bail out if exception breaks are not active
1758 if (uncaught) {
1759 // Uncaught exceptions are reported by either flags.
1760 if (!(break_on_uncaught_exception_ || break_on_exception_)) return;
1761 } else {
1762 // Caught exceptions are reported is activated.
1763 if (!break_on_exception_) return;
1764 }
1765
Ben Murdoch097c5b22016-05-18 11:27:45 +01001766 {
1767 // Check whether the break location is muted.
1768 JavaScriptFrameIterator it(isolate_);
1769 if (!it.done() && IsMutedAtCurrentLocation(it.frame())) return;
1770 }
1771
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001772 DebugScope debug_scope(this);
1773 if (debug_scope.failed()) return;
1774
1775 // Create the event data object.
1776 Handle<Object> event_data;
1777 // Bail out and don't call debugger if exception.
1778 if (!MakeExceptionEvent(
1779 exception, uncaught, promise).ToHandle(&event_data)) {
1780 return;
1781 }
1782
1783 // Process debug event.
1784 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false);
1785 // Return to continue execution from where the exception was thrown.
1786}
1787
1788
Ben Murdoch097c5b22016-05-18 11:27:45 +01001789void Debug::OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001790 // The caller provided for DebugScope.
1791 AssertDebugContext();
1792 // Bail out if there is no listener for this event
1793 if (ignore_events()) return;
1794
Ben Murdochda12d292016-06-02 14:46:10 +01001795#ifdef DEBUG
1796 PrintBreakLocation();
1797#endif // DEBUG
1798
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001799 HandleScope scope(isolate_);
1800 // Create the event data object.
1801 Handle<Object> event_data;
1802 // Bail out and don't call debugger if exception.
1803 if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return;
1804
1805 // Process debug event.
1806 ProcessDebugEvent(v8::Break,
1807 Handle<JSObject>::cast(event_data),
1808 auto_continue);
1809}
1810
1811
1812void Debug::OnCompileError(Handle<Script> script) {
1813 ProcessCompileEvent(v8::CompileError, script);
1814}
1815
1816
1817void Debug::OnBeforeCompile(Handle<Script> script) {
1818 ProcessCompileEvent(v8::BeforeCompile, script);
1819}
1820
1821
1822// Handle debugger actions when a new script is compiled.
1823void Debug::OnAfterCompile(Handle<Script> script) {
1824 ProcessCompileEvent(v8::AfterCompile, script);
1825}
1826
1827
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001828void Debug::OnAsyncTaskEvent(Handle<JSObject> data) {
1829 if (in_debug_scope() || ignore_events()) return;
1830
1831 HandleScope scope(isolate_);
1832 DebugScope debug_scope(this);
1833 if (debug_scope.failed()) return;
1834
1835 // Create the script collected state object.
1836 Handle<Object> event_data;
1837 // Bail out and don't call debugger if exception.
1838 if (!MakeAsyncTaskEvent(data).ToHandle(&event_data)) return;
1839
1840 // Process debug event.
1841 ProcessDebugEvent(v8::AsyncTaskEvent,
1842 Handle<JSObject>::cast(event_data),
1843 true);
1844}
1845
1846
1847void Debug::ProcessDebugEvent(v8::DebugEvent event,
1848 Handle<JSObject> event_data,
1849 bool auto_continue) {
1850 HandleScope scope(isolate_);
1851
1852 // Create the execution state.
1853 Handle<Object> exec_state;
1854 // Bail out and don't call debugger if exception.
1855 if (!MakeExecutionState().ToHandle(&exec_state)) return;
1856
1857 // First notify the message handler if any.
1858 if (message_handler_ != NULL) {
1859 NotifyMessageHandler(event,
1860 Handle<JSObject>::cast(exec_state),
1861 event_data,
1862 auto_continue);
1863 }
1864 // Notify registered debug event listener. This can be either a C or
1865 // a JavaScript function. Don't call event listener for v8::Break
1866 // here, if it's only a debug command -- they will be processed later.
1867 if ((event != v8::Break || !auto_continue) && !event_listener_.is_null()) {
1868 CallEventCallback(event, exec_state, event_data, NULL);
1869 }
1870}
1871
1872
1873void Debug::CallEventCallback(v8::DebugEvent event,
1874 Handle<Object> exec_state,
1875 Handle<Object> event_data,
1876 v8::Debug::ClientData* client_data) {
1877 // Prevent other interrupts from triggering, for example API callbacks,
1878 // while dispatching event listners.
1879 PostponeInterruptsScope postpone(isolate_);
1880 bool previous = in_debug_event_listener_;
1881 in_debug_event_listener_ = true;
1882 if (event_listener_->IsForeign()) {
1883 // Invoke the C debug event listener.
1884 v8::Debug::EventCallback callback =
1885 FUNCTION_CAST<v8::Debug::EventCallback>(
1886 Handle<Foreign>::cast(event_listener_)->foreign_address());
1887 EventDetailsImpl event_details(event,
1888 Handle<JSObject>::cast(exec_state),
1889 Handle<JSObject>::cast(event_data),
1890 event_listener_data_,
1891 client_data);
1892 callback(event_details);
1893 DCHECK(!isolate_->has_scheduled_exception());
1894 } else {
1895 // Invoke the JavaScript debug event listener.
1896 DCHECK(event_listener_->IsJSFunction());
1897 Handle<Object> argv[] = { Handle<Object>(Smi::FromInt(event), isolate_),
1898 exec_state,
1899 event_data,
1900 event_listener_data_ };
Ben Murdochc5610432016-08-08 18:44:38 +01001901 Handle<JSReceiver> global = isolate_->global_proxy();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001902 Execution::TryCall(isolate_, Handle<JSFunction>::cast(event_listener_),
1903 global, arraysize(argv), argv);
1904 }
1905 in_debug_event_listener_ = previous;
1906}
1907
1908
1909void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) {
1910 if (ignore_events()) return;
1911 SuppressDebug while_processing(this);
1912
1913 bool in_nested_debug_scope = in_debug_scope();
1914 HandleScope scope(isolate_);
1915 DebugScope debug_scope(this);
1916 if (debug_scope.failed()) return;
1917
1918 if (event == v8::AfterCompile) {
1919 // If debugging there might be script break points registered for this
1920 // script. Make sure that these break points are set.
1921 Handle<Object> argv[] = {Script::GetWrapper(script)};
1922 if (CallFunction("UpdateScriptBreakPoints", arraysize(argv), argv)
1923 .is_null()) {
1924 return;
1925 }
1926 }
1927
1928 // Create the compile state object.
1929 Handle<Object> event_data;
1930 // Bail out and don't call debugger if exception.
1931 if (!MakeCompileEvent(script, event).ToHandle(&event_data)) return;
1932
1933 // Don't call NotifyMessageHandler if already in debug scope to avoid running
1934 // nested command loop.
1935 if (in_nested_debug_scope) {
1936 if (event_listener_.is_null()) return;
1937 // Create the execution state.
1938 Handle<Object> exec_state;
1939 // Bail out and don't call debugger if exception.
1940 if (!MakeExecutionState().ToHandle(&exec_state)) return;
1941
1942 CallEventCallback(event, exec_state, event_data, NULL);
1943 } else {
1944 // Process debug event.
1945 ProcessDebugEvent(event, Handle<JSObject>::cast(event_data), true);
1946 }
1947}
1948
1949
1950Handle<Context> Debug::GetDebugContext() {
1951 if (!is_loaded()) return Handle<Context>();
1952 DebugScope debug_scope(this);
1953 if (debug_scope.failed()) return Handle<Context>();
1954 // The global handle may be destroyed soon after. Return it reboxed.
1955 return handle(*debug_context(), isolate_);
1956}
1957
1958
1959void Debug::NotifyMessageHandler(v8::DebugEvent event,
1960 Handle<JSObject> exec_state,
1961 Handle<JSObject> event_data,
1962 bool auto_continue) {
1963 // Prevent other interrupts from triggering, for example API callbacks,
1964 // while dispatching message handler callbacks.
1965 PostponeInterruptsScope no_interrupts(isolate_);
1966 DCHECK(is_active_);
1967 HandleScope scope(isolate_);
1968 // Process the individual events.
1969 bool sendEventMessage = false;
1970 switch (event) {
1971 case v8::Break:
1972 sendEventMessage = !auto_continue;
1973 break;
1974 case v8::NewFunction:
1975 case v8::BeforeCompile:
1976 case v8::CompileError:
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00001977 case v8::AsyncTaskEvent:
1978 break;
1979 case v8::Exception:
1980 case v8::AfterCompile:
1981 sendEventMessage = true;
1982 break;
1983 }
1984
1985 // The debug command interrupt flag might have been set when the command was
1986 // added. It should be enough to clear the flag only once while we are in the
1987 // debugger.
1988 DCHECK(in_debug_scope());
1989 isolate_->stack_guard()->ClearDebugCommand();
1990
1991 // Notify the debugger that a debug event has occurred unless auto continue is
1992 // active in which case no event is send.
1993 if (sendEventMessage) {
1994 MessageImpl message = MessageImpl::NewEvent(
1995 event,
1996 auto_continue,
1997 Handle<JSObject>::cast(exec_state),
1998 Handle<JSObject>::cast(event_data));
1999 InvokeMessageHandler(message);
2000 }
2001
2002 // If auto continue don't make the event cause a break, but process messages
2003 // in the queue if any. For script collected events don't even process
2004 // messages in the queue as the execution state might not be what is expected
2005 // by the client.
2006 if (auto_continue && !has_commands()) return;
2007
2008 // DebugCommandProcessor goes here.
2009 bool running = auto_continue;
2010
Ben Murdochda12d292016-06-02 14:46:10 +01002011 Handle<Object> cmd_processor_ctor =
2012 JSReceiver::GetProperty(isolate_, exec_state, "debugCommandProcessor")
2013 .ToHandleChecked();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002014 Handle<Object> ctor_args[] = { isolate_->factory()->ToBoolean(running) };
Ben Murdochda12d292016-06-02 14:46:10 +01002015 Handle<JSReceiver> cmd_processor = Handle<JSReceiver>::cast(
2016 Execution::Call(isolate_, cmd_processor_ctor, exec_state, 1, ctor_args)
2017 .ToHandleChecked());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002018 Handle<JSFunction> process_debug_request = Handle<JSFunction>::cast(
Ben Murdochda12d292016-06-02 14:46:10 +01002019 JSReceiver::GetProperty(isolate_, cmd_processor, "processDebugRequest")
2020 .ToHandleChecked());
2021 Handle<Object> is_running =
2022 JSReceiver::GetProperty(isolate_, cmd_processor, "isRunning")
2023 .ToHandleChecked();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002024
2025 // Process requests from the debugger.
2026 do {
2027 // Wait for new command in the queue.
2028 command_received_.Wait();
2029
2030 // Get the command from the queue.
2031 CommandMessage command = command_queue_.Get();
2032 isolate_->logger()->DebugTag(
2033 "Got request from command queue, in interactive loop.");
2034 if (!is_active()) {
2035 // Delete command text and user data.
2036 command.Dispose();
2037 return;
2038 }
2039
2040 Vector<const uc16> command_text(
2041 const_cast<const uc16*>(command.text().start()),
2042 command.text().length());
2043 Handle<String> request_text = isolate_->factory()->NewStringFromTwoByte(
2044 command_text).ToHandleChecked();
2045 Handle<Object> request_args[] = { request_text };
2046 Handle<Object> answer_value;
2047 Handle<String> answer;
2048 MaybeHandle<Object> maybe_exception;
2049 MaybeHandle<Object> maybe_result =
2050 Execution::TryCall(isolate_, process_debug_request, cmd_processor, 1,
2051 request_args, &maybe_exception);
2052
2053 if (maybe_result.ToHandle(&answer_value)) {
2054 if (answer_value->IsUndefined()) {
2055 answer = isolate_->factory()->empty_string();
2056 } else {
2057 answer = Handle<String>::cast(answer_value);
2058 }
2059
2060 // Log the JSON request/response.
2061 if (FLAG_trace_debug_json) {
2062 PrintF("%s\n", request_text->ToCString().get());
2063 PrintF("%s\n", answer->ToCString().get());
2064 }
2065
2066 Handle<Object> is_running_args[] = { answer };
2067 maybe_result = Execution::Call(
2068 isolate_, is_running, cmd_processor, 1, is_running_args);
2069 Handle<Object> result;
2070 if (!maybe_result.ToHandle(&result)) break;
2071 running = result->IsTrue();
2072 } else {
2073 Handle<Object> exception;
2074 if (!maybe_exception.ToHandle(&exception)) break;
2075 Handle<Object> result;
2076 if (!Object::ToString(isolate_, exception).ToHandle(&result)) break;
2077 answer = Handle<String>::cast(result);
2078 }
2079
2080 // Return the result.
2081 MessageImpl message = MessageImpl::NewResponse(
2082 event, running, exec_state, event_data, answer, command.client_data());
2083 InvokeMessageHandler(message);
2084 command.Dispose();
2085
2086 // Return from debug event processing if either the VM is put into the
2087 // running state (through a continue command) or auto continue is active
2088 // and there are no more commands queued.
2089 } while (!running || has_commands());
2090 command_queue_.Clear();
2091}
2092
2093
2094void Debug::SetEventListener(Handle<Object> callback,
2095 Handle<Object> data) {
2096 GlobalHandles* global_handles = isolate_->global_handles();
2097
2098 // Remove existing entry.
2099 GlobalHandles::Destroy(event_listener_.location());
2100 event_listener_ = Handle<Object>();
2101 GlobalHandles::Destroy(event_listener_data_.location());
2102 event_listener_data_ = Handle<Object>();
2103
2104 // Set new entry.
2105 if (!callback->IsUndefined() && !callback->IsNull()) {
2106 event_listener_ = global_handles->Create(*callback);
2107 if (data.is_null()) data = isolate_->factory()->undefined_value();
2108 event_listener_data_ = global_handles->Create(*data);
2109 }
2110
2111 UpdateState();
2112}
2113
2114
2115void Debug::SetMessageHandler(v8::Debug::MessageHandler handler) {
2116 message_handler_ = handler;
2117 UpdateState();
2118 if (handler == NULL && in_debug_scope()) {
2119 // Send an empty command to the debugger if in a break to make JavaScript
2120 // run again if the debugger is closed.
2121 EnqueueCommandMessage(Vector<const uint16_t>::empty());
2122 }
2123}
2124
2125
2126
2127void Debug::UpdateState() {
2128 bool is_active = message_handler_ != NULL || !event_listener_.is_null();
2129 if (is_active || in_debug_scope()) {
2130 // Note that the debug context could have already been loaded to
2131 // bootstrap test cases.
2132 isolate_->compilation_cache()->Disable();
2133 is_active = Load();
2134 } else if (is_loaded()) {
2135 isolate_->compilation_cache()->Enable();
2136 Unload();
2137 }
2138 is_active_ = is_active;
2139}
2140
2141
2142// Calls the registered debug message handler. This callback is part of the
2143// public API.
2144void Debug::InvokeMessageHandler(MessageImpl message) {
2145 if (message_handler_ != NULL) message_handler_(message);
2146}
2147
2148
2149// Puts a command coming from the public API on the queue. Creates
2150// a copy of the command string managed by the debugger. Up to this
2151// point, the command data was managed by the API client. Called
2152// by the API client thread.
2153void Debug::EnqueueCommandMessage(Vector<const uint16_t> command,
2154 v8::Debug::ClientData* client_data) {
2155 // Need to cast away const.
2156 CommandMessage message = CommandMessage::New(
2157 Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
2158 command.length()),
2159 client_data);
2160 isolate_->logger()->DebugTag("Put command on command_queue.");
2161 command_queue_.Put(message);
2162 command_received_.Signal();
2163
2164 // Set the debug command break flag to have the command processed.
2165 if (!in_debug_scope()) isolate_->stack_guard()->RequestDebugCommand();
2166}
2167
2168
2169MaybeHandle<Object> Debug::Call(Handle<Object> fun, Handle<Object> data) {
2170 DebugScope debug_scope(this);
2171 if (debug_scope.failed()) return isolate_->factory()->undefined_value();
2172
2173 // Create the execution state.
2174 Handle<Object> exec_state;
2175 if (!MakeExecutionState().ToHandle(&exec_state)) {
2176 return isolate_->factory()->undefined_value();
2177 }
2178
2179 Handle<Object> argv[] = { exec_state, data };
2180 return Execution::Call(
2181 isolate_,
2182 fun,
2183 Handle<Object>(debug_context()->global_proxy(), isolate_),
2184 arraysize(argv),
2185 argv);
2186}
2187
2188
2189void Debug::HandleDebugBreak() {
2190 // Ignore debug break during bootstrapping.
2191 if (isolate_->bootstrapper()->IsActive()) return;
2192 // Just continue if breaks are disabled.
2193 if (break_disabled()) return;
2194 // Ignore debug break if debugger is not active.
2195 if (!is_active()) return;
2196
2197 StackLimitCheck check(isolate_);
2198 if (check.HasOverflowed()) return;
2199
2200 { JavaScriptFrameIterator it(isolate_);
2201 DCHECK(!it.done());
2202 Object* fun = it.frame()->function();
2203 if (fun && fun->IsJSFunction()) {
2204 // Don't stop in builtin functions.
2205 if (!JSFunction::cast(fun)->shared()->IsSubjectToDebugging()) return;
2206 JSGlobalObject* global =
2207 JSFunction::cast(fun)->context()->global_object();
2208 // Don't stop in debugger functions.
2209 if (IsDebugGlobal(global)) return;
Ben Murdoch097c5b22016-05-18 11:27:45 +01002210 // Don't stop if the break location is muted.
2211 if (IsMutedAtCurrentLocation(it.frame())) return;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002212 }
2213 }
2214
2215 // Collect the break state before clearing the flags.
2216 bool debug_command_only = isolate_->stack_guard()->CheckDebugCommand() &&
2217 !isolate_->stack_guard()->CheckDebugBreak();
2218
2219 isolate_->stack_guard()->ClearDebugBreak();
2220
2221 // Clear stepping to avoid duplicate breaks.
2222 ClearStepping();
2223
2224 ProcessDebugMessages(debug_command_only);
2225}
2226
2227
2228void Debug::ProcessDebugMessages(bool debug_command_only) {
2229 isolate_->stack_guard()->ClearDebugCommand();
2230
2231 StackLimitCheck check(isolate_);
2232 if (check.HasOverflowed()) return;
2233
2234 HandleScope scope(isolate_);
2235 DebugScope debug_scope(this);
2236 if (debug_scope.failed()) return;
2237
2238 // Notify the debug event listeners. Indicate auto continue if the break was
2239 // a debug command break.
2240 OnDebugBreak(isolate_->factory()->undefined_value(), debug_command_only);
2241}
2242
Ben Murdochda12d292016-06-02 14:46:10 +01002243#ifdef DEBUG
2244void Debug::PrintBreakLocation() {
2245 if (!FLAG_print_break_location) return;
2246 HandleScope scope(isolate_);
2247 JavaScriptFrameIterator iterator(isolate_);
2248 if (iterator.done()) return;
2249 JavaScriptFrame* frame = iterator.frame();
Ben Murdochc5610432016-08-08 18:44:38 +01002250 FrameSummary summary = FrameSummary::GetFirst(frame);
Ben Murdochda12d292016-06-02 14:46:10 +01002251 int source_position =
2252 summary.abstract_code()->SourcePosition(summary.code_offset());
2253 Handle<Object> script_obj(summary.function()->shared()->script(), isolate_);
2254 PrintF("[debug] break in function '");
2255 summary.function()->PrintName();
2256 PrintF("'.\n");
2257 if (script_obj->IsScript()) {
2258 Handle<Script> script = Handle<Script>::cast(script_obj);
2259 Handle<String> source(String::cast(script->source()));
2260 Script::InitLineEnds(script);
Ben Murdochc5610432016-08-08 18:44:38 +01002261 int line =
2262 Script::GetLineNumber(script, source_position) - script->line_offset();
2263 int column = Script::GetColumnNumber(script, source_position) -
2264 (line == 0 ? script->column_offset() : 0);
Ben Murdochda12d292016-06-02 14:46:10 +01002265 Handle<FixedArray> line_ends(FixedArray::cast(script->line_ends()));
2266 int line_start =
2267 line == 0 ? 0 : Smi::cast(line_ends->get(line - 1))->value() + 1;
2268 int line_end = Smi::cast(line_ends->get(line))->value();
2269 DisallowHeapAllocation no_gc;
2270 String::FlatContent content = source->GetFlatContent();
2271 if (content.IsOneByte()) {
2272 PrintF("[debug] %.*s\n", line_end - line_start,
2273 content.ToOneByteVector().start() + line_start);
2274 PrintF("[debug] ");
2275 for (int i = 0; i < column; i++) PrintF(" ");
2276 PrintF("^\n");
2277 } else {
2278 PrintF("[debug] at line %d column %d\n", line, column);
2279 }
2280 }
2281}
2282#endif // DEBUG
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002283
2284DebugScope::DebugScope(Debug* debug)
2285 : debug_(debug),
2286 prev_(debug->debugger_entry()),
2287 save_(debug_->isolate_),
2288 no_termination_exceptons_(debug_->isolate_,
2289 StackGuard::TERMINATE_EXECUTION) {
2290 // Link recursive debugger entry.
2291 base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_,
2292 reinterpret_cast<base::AtomicWord>(this));
2293
Ben Murdochda12d292016-06-02 14:46:10 +01002294 // Store the previous break id, frame id and return value.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002295 break_id_ = debug_->break_id();
2296 break_frame_id_ = debug_->break_frame_id();
Ben Murdochda12d292016-06-02 14:46:10 +01002297 return_value_ = debug_->return_value();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002298
2299 // Create the new break info. If there is no JavaScript frames there is no
2300 // break frame id.
2301 JavaScriptFrameIterator it(isolate());
2302 bool has_js_frames = !it.done();
2303 debug_->thread_local_.break_frame_id_ = has_js_frames ? it.frame()->id()
2304 : StackFrame::NO_ID;
2305 debug_->SetNextBreakId();
2306
2307 debug_->UpdateState();
2308 // Make sure that debugger is loaded and enter the debugger context.
2309 // The previous context is kept in save_.
2310 failed_ = !debug_->is_loaded();
2311 if (!failed_) isolate()->set_context(*debug->debug_context());
2312}
2313
2314
2315DebugScope::~DebugScope() {
2316 if (!failed_ && prev_ == NULL) {
2317 // Clear mirror cache when leaving the debugger. Skip this if there is a
2318 // pending exception as clearing the mirror cache calls back into
2319 // JavaScript. This can happen if the v8::Debug::Call is used in which
2320 // case the exception should end up in the calling code.
2321 if (!isolate()->has_pending_exception()) debug_->ClearMirrorCache();
2322
2323 // If there are commands in the queue when leaving the debugger request
2324 // that these commands are processed.
2325 if (debug_->has_commands()) isolate()->stack_guard()->RequestDebugCommand();
2326 }
2327
2328 // Leaving this debugger entry.
2329 base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_,
2330 reinterpret_cast<base::AtomicWord>(prev_));
2331
2332 // Restore to the previous break state.
2333 debug_->thread_local_.break_frame_id_ = break_frame_id_;
2334 debug_->thread_local_.break_id_ = break_id_;
Ben Murdochda12d292016-06-02 14:46:10 +01002335 debug_->thread_local_.return_value_ = return_value_;
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002336
2337 debug_->UpdateState();
2338}
2339
2340
2341MessageImpl MessageImpl::NewEvent(DebugEvent event,
2342 bool running,
2343 Handle<JSObject> exec_state,
2344 Handle<JSObject> event_data) {
2345 MessageImpl message(true, event, running,
2346 exec_state, event_data, Handle<String>(), NULL);
2347 return message;
2348}
2349
2350
2351MessageImpl MessageImpl::NewResponse(DebugEvent event,
2352 bool running,
2353 Handle<JSObject> exec_state,
2354 Handle<JSObject> event_data,
2355 Handle<String> response_json,
2356 v8::Debug::ClientData* client_data) {
2357 MessageImpl message(false, event, running,
2358 exec_state, event_data, response_json, client_data);
2359 return message;
2360}
2361
2362
2363MessageImpl::MessageImpl(bool is_event,
2364 DebugEvent event,
2365 bool running,
2366 Handle<JSObject> exec_state,
2367 Handle<JSObject> event_data,
2368 Handle<String> response_json,
2369 v8::Debug::ClientData* client_data)
2370 : is_event_(is_event),
2371 event_(event),
2372 running_(running),
2373 exec_state_(exec_state),
2374 event_data_(event_data),
2375 response_json_(response_json),
2376 client_data_(client_data) {}
2377
2378
2379bool MessageImpl::IsEvent() const {
2380 return is_event_;
2381}
2382
2383
2384bool MessageImpl::IsResponse() const {
2385 return !is_event_;
2386}
2387
2388
2389DebugEvent MessageImpl::GetEvent() const {
2390 return event_;
2391}
2392
2393
2394bool MessageImpl::WillStartRunning() const {
2395 return running_;
2396}
2397
2398
2399v8::Local<v8::Object> MessageImpl::GetExecutionState() const {
2400 return v8::Utils::ToLocal(exec_state_);
2401}
2402
2403
2404v8::Isolate* MessageImpl::GetIsolate() const {
2405 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate());
2406}
2407
2408
2409v8::Local<v8::Object> MessageImpl::GetEventData() const {
2410 return v8::Utils::ToLocal(event_data_);
2411}
2412
2413
2414v8::Local<v8::String> MessageImpl::GetJSON() const {
2415 Isolate* isolate = event_data_->GetIsolate();
2416 v8::EscapableHandleScope scope(reinterpret_cast<v8::Isolate*>(isolate));
2417
2418 if (IsEvent()) {
2419 // Call toJSONProtocol on the debug event object.
Ben Murdochda12d292016-06-02 14:46:10 +01002420 Handle<Object> fun =
2421 JSReceiver::GetProperty(isolate, event_data_, "toJSONProtocol")
2422 .ToHandleChecked();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00002423 if (!fun->IsJSFunction()) {
2424 return v8::Local<v8::String>();
2425 }
2426
2427 MaybeHandle<Object> maybe_json =
2428 Execution::TryCall(isolate, fun, event_data_, 0, NULL);
2429 Handle<Object> json;
2430 if (!maybe_json.ToHandle(&json) || !json->IsString()) {
2431 return v8::Local<v8::String>();
2432 }
2433 return scope.Escape(v8::Utils::ToLocal(Handle<String>::cast(json)));
2434 } else {
2435 return v8::Utils::ToLocal(response_json_);
2436 }
2437}
2438
2439
2440v8::Local<v8::Context> MessageImpl::GetEventContext() const {
2441 Isolate* isolate = event_data_->GetIsolate();
2442 v8::Local<v8::Context> context = GetDebugEventContext(isolate);
2443 // Isolate::context() may be NULL when "script collected" event occurs.
2444 DCHECK(!context.IsEmpty());
2445 return context;
2446}
2447
2448
2449v8::Debug::ClientData* MessageImpl::GetClientData() const {
2450 return client_data_;
2451}
2452
2453
2454EventDetailsImpl::EventDetailsImpl(DebugEvent event,
2455 Handle<JSObject> exec_state,
2456 Handle<JSObject> event_data,
2457 Handle<Object> callback_data,
2458 v8::Debug::ClientData* client_data)
2459 : event_(event),
2460 exec_state_(exec_state),
2461 event_data_(event_data),
2462 callback_data_(callback_data),
2463 client_data_(client_data) {}
2464
2465
2466DebugEvent EventDetailsImpl::GetEvent() const {
2467 return event_;
2468}
2469
2470
2471v8::Local<v8::Object> EventDetailsImpl::GetExecutionState() const {
2472 return v8::Utils::ToLocal(exec_state_);
2473}
2474
2475
2476v8::Local<v8::Object> EventDetailsImpl::GetEventData() const {
2477 return v8::Utils::ToLocal(event_data_);
2478}
2479
2480
2481v8::Local<v8::Context> EventDetailsImpl::GetEventContext() const {
2482 return GetDebugEventContext(exec_state_->GetIsolate());
2483}
2484
2485
2486v8::Local<v8::Value> EventDetailsImpl::GetCallbackData() const {
2487 return v8::Utils::ToLocal(callback_data_);
2488}
2489
2490
2491v8::Debug::ClientData* EventDetailsImpl::GetClientData() const {
2492 return client_data_;
2493}
2494
2495
2496CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()),
2497 client_data_(NULL) {
2498}
2499
2500
2501CommandMessage::CommandMessage(const Vector<uint16_t>& text,
2502 v8::Debug::ClientData* data)
2503 : text_(text),
2504 client_data_(data) {
2505}
2506
2507
2508void CommandMessage::Dispose() {
2509 text_.Dispose();
2510 delete client_data_;
2511 client_data_ = NULL;
2512}
2513
2514
2515CommandMessage CommandMessage::New(const Vector<uint16_t>& command,
2516 v8::Debug::ClientData* data) {
2517 return CommandMessage(command.Clone(), data);
2518}
2519
2520
2521CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0),
2522 size_(size) {
2523 messages_ = NewArray<CommandMessage>(size);
2524}
2525
2526
2527CommandMessageQueue::~CommandMessageQueue() {
2528 while (!IsEmpty()) Get().Dispose();
2529 DeleteArray(messages_);
2530}
2531
2532
2533CommandMessage CommandMessageQueue::Get() {
2534 DCHECK(!IsEmpty());
2535 int result = start_;
2536 start_ = (start_ + 1) % size_;
2537 return messages_[result];
2538}
2539
2540
2541void CommandMessageQueue::Put(const CommandMessage& message) {
2542 if ((end_ + 1) % size_ == start_) {
2543 Expand();
2544 }
2545 messages_[end_] = message;
2546 end_ = (end_ + 1) % size_;
2547}
2548
2549
2550void CommandMessageQueue::Expand() {
2551 CommandMessageQueue new_queue(size_ * 2);
2552 while (!IsEmpty()) {
2553 new_queue.Put(Get());
2554 }
2555 CommandMessage* array_to_free = messages_;
2556 *this = new_queue;
2557 new_queue.messages_ = array_to_free;
2558 // Make the new_queue empty so that it doesn't call Dispose on any messages.
2559 new_queue.start_ = new_queue.end_;
2560 // Automatic destructor called on new_queue, freeing array_to_free.
2561}
2562
2563
2564LockingCommandMessageQueue::LockingCommandMessageQueue(Logger* logger, int size)
2565 : logger_(logger), queue_(size) {}
2566
2567
2568bool LockingCommandMessageQueue::IsEmpty() const {
2569 base::LockGuard<base::Mutex> lock_guard(&mutex_);
2570 return queue_.IsEmpty();
2571}
2572
2573
2574CommandMessage LockingCommandMessageQueue::Get() {
2575 base::LockGuard<base::Mutex> lock_guard(&mutex_);
2576 CommandMessage result = queue_.Get();
2577 logger_->DebugEvent("Get", result.text());
2578 return result;
2579}
2580
2581
2582void LockingCommandMessageQueue::Put(const CommandMessage& message) {
2583 base::LockGuard<base::Mutex> lock_guard(&mutex_);
2584 queue_.Put(message);
2585 logger_->DebugEvent("Put", message.text());
2586}
2587
2588
2589void LockingCommandMessageQueue::Clear() {
2590 base::LockGuard<base::Mutex> lock_guard(&mutex_);
2591 queue_.Clear();
2592}
2593
2594} // namespace internal
2595} // namespace v8