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