Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1178)

Side by Side Diff: src/debug.cc

Issue 1265923002: Debugger: move implementation to a separate folder. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: rebase Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/debug.h ('k') | src/debug-debugger.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // 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/v8.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/debug.h"
15 #include "src/deoptimizer.h"
16 #include "src/execution.h"
17 #include "src/full-codegen/full-codegen.h"
18 #include "src/global-handles.h"
19 #include "src/list.h"
20 #include "src/log.h"
21 #include "src/messages.h"
22 #include "src/snapshot/natives.h"
23
24 #include "include/v8-debug.h"
25
26 namespace v8 {
27 namespace internal {
28
29 Debug::Debug(Isolate* isolate)
30 : debug_context_(Handle<Context>()),
31 event_listener_(Handle<Object>()),
32 event_listener_data_(Handle<Object>()),
33 message_handler_(NULL),
34 command_received_(0),
35 command_queue_(isolate->logger(), kQueueInitialSize),
36 is_active_(false),
37 is_suppressed_(false),
38 live_edit_enabled_(true), // TODO(yangguo): set to false by default.
39 break_disabled_(false),
40 in_debug_event_listener_(false),
41 break_on_exception_(false),
42 break_on_uncaught_exception_(false),
43 script_cache_(NULL),
44 debug_info_list_(NULL),
45 isolate_(isolate) {
46 ThreadInit();
47 }
48
49
50 static v8::Local<v8::Context> GetDebugEventContext(Isolate* isolate) {
51 Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
52 // Isolate::context() may have been NULL when "script collected" event
53 // occured.
54 if (context.is_null()) return v8::Local<v8::Context>();
55 Handle<Context> native_context(context->native_context());
56 return v8::Utils::ToLocal(native_context);
57 }
58
59
60 BreakLocation::BreakLocation(Handle<DebugInfo> debug_info, RelocInfo* rinfo,
61 int position, int statement_position)
62 : debug_info_(debug_info),
63 pc_offset_(static_cast<int>(rinfo->pc() - debug_info->code()->entry())),
64 rmode_(rinfo->rmode()),
65 data_(rinfo->data()),
66 position_(position),
67 statement_position_(statement_position) {}
68
69
70 BreakLocation::Iterator::Iterator(Handle<DebugInfo> debug_info,
71 BreakLocatorType type)
72 : debug_info_(debug_info),
73 reloc_iterator_(debug_info->code(), GetModeMask(type)),
74 break_index_(-1),
75 position_(1),
76 statement_position_(1) {
77 if (!Done()) Next();
78 }
79
80
81 int BreakLocation::Iterator::GetModeMask(BreakLocatorType type) {
82 int mask = 0;
83 mask |= RelocInfo::ModeMask(RelocInfo::POSITION);
84 mask |= RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION);
85 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN);
86 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_CALL);
87 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_CONSTRUCT_CALL);
88 if (type == ALL_BREAK_LOCATIONS) {
89 mask |= RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION);
90 mask |= RelocInfo::ModeMask(RelocInfo::DEBUGGER_STATEMENT);
91 }
92 return mask;
93 }
94
95
96 void BreakLocation::Iterator::Next() {
97 DisallowHeapAllocation no_gc;
98 DCHECK(!Done());
99
100 // Iterate through reloc info for code and original code stopping at each
101 // breakable code target.
102 bool first = break_index_ == -1;
103 while (!Done()) {
104 if (!first) reloc_iterator_.next();
105 first = false;
106 if (Done()) return;
107
108 // Whenever a statement position or (plain) position is passed update the
109 // current value of these.
110 if (RelocInfo::IsPosition(rmode())) {
111 if (RelocInfo::IsStatementPosition(rmode())) {
112 statement_position_ = static_cast<int>(
113 rinfo()->data() - debug_info_->shared()->start_position());
114 }
115 // Always update the position as we don't want that to be before the
116 // statement position.
117 position_ = static_cast<int>(rinfo()->data() -
118 debug_info_->shared()->start_position());
119 DCHECK(position_ >= 0);
120 DCHECK(statement_position_ >= 0);
121 continue;
122 }
123
124 DCHECK(RelocInfo::IsDebugBreakSlot(rmode()) ||
125 RelocInfo::IsDebuggerStatement(rmode()));
126
127 if (RelocInfo::IsDebugBreakSlotAtReturn(rmode())) {
128 // Set the positions to the end of the function.
129 if (debug_info_->shared()->HasSourceCode()) {
130 position_ = debug_info_->shared()->end_position() -
131 debug_info_->shared()->start_position() - 1;
132 } else {
133 position_ = 0;
134 }
135 statement_position_ = position_;
136 }
137
138 break;
139 }
140 break_index_++;
141 }
142
143
144 // Find the break point at the supplied address, or the closest one before
145 // the address.
146 BreakLocation BreakLocation::FromAddress(Handle<DebugInfo> debug_info,
147 BreakLocatorType type, Address pc) {
148 Iterator it(debug_info, type);
149 it.SkipTo(BreakIndexFromAddress(debug_info, type, pc));
150 return it.GetBreakLocation();
151 }
152
153
154 // Find the break point at the supplied address, or the closest one before
155 // the address.
156 void BreakLocation::FromAddressSameStatement(Handle<DebugInfo> debug_info,
157 BreakLocatorType type, Address pc,
158 List<BreakLocation>* result_out) {
159 int break_index = BreakIndexFromAddress(debug_info, type, pc);
160 Iterator it(debug_info, type);
161 it.SkipTo(break_index);
162 int statement_position = it.statement_position();
163 while (!it.Done() && it.statement_position() == statement_position) {
164 result_out->Add(it.GetBreakLocation());
165 it.Next();
166 }
167 }
168
169
170 int BreakLocation::BreakIndexFromAddress(Handle<DebugInfo> debug_info,
171 BreakLocatorType type, Address pc) {
172 // Run through all break points to locate the one closest to the address.
173 int closest_break = 0;
174 int distance = kMaxInt;
175 for (Iterator it(debug_info, type); !it.Done(); it.Next()) {
176 // Check if this break point is closer that what was previously found.
177 if (it.pc() <= pc && pc - it.pc() < distance) {
178 closest_break = it.break_index();
179 distance = static_cast<int>(pc - it.pc());
180 // Check whether we can't get any closer.
181 if (distance == 0) break;
182 }
183 }
184 return closest_break;
185 }
186
187
188 BreakLocation BreakLocation::FromPosition(Handle<DebugInfo> debug_info,
189 BreakLocatorType type, int position,
190 BreakPositionAlignment alignment) {
191 // Run through all break points to locate the one closest to the source
192 // position.
193 int closest_break = 0;
194 int distance = kMaxInt;
195
196 for (Iterator it(debug_info, type); !it.Done(); it.Next()) {
197 int next_position;
198 if (alignment == STATEMENT_ALIGNED) {
199 next_position = it.statement_position();
200 } else {
201 DCHECK(alignment == BREAK_POSITION_ALIGNED);
202 next_position = it.position();
203 }
204 if (position <= next_position && next_position - position < distance) {
205 closest_break = it.break_index();
206 distance = next_position - position;
207 // Check whether we can't get any closer.
208 if (distance == 0) break;
209 }
210 }
211
212 Iterator it(debug_info, type);
213 it.SkipTo(closest_break);
214 return it.GetBreakLocation();
215 }
216
217
218 void BreakLocation::SetBreakPoint(Handle<Object> break_point_object) {
219 // If there is not already a real break point here patch code with debug
220 // break.
221 if (!HasBreakPoint()) SetDebugBreak();
222 DCHECK(IsDebugBreak() || IsDebuggerStatement());
223 // Set the break point information.
224 DebugInfo::SetBreakPoint(debug_info_, pc_offset_, position_,
225 statement_position_, break_point_object);
226 }
227
228
229 void BreakLocation::ClearBreakPoint(Handle<Object> break_point_object) {
230 // Clear the break point information.
231 DebugInfo::ClearBreakPoint(debug_info_, pc_offset_, break_point_object);
232 // If there are no more break points here remove the debug break.
233 if (!HasBreakPoint()) {
234 ClearDebugBreak();
235 DCHECK(!IsDebugBreak());
236 }
237 }
238
239
240 void BreakLocation::SetOneShot() {
241 // Debugger statement always calls debugger. No need to modify it.
242 if (IsDebuggerStatement()) return;
243
244 // If there is a real break point here no more to do.
245 if (HasBreakPoint()) {
246 DCHECK(IsDebugBreak());
247 return;
248 }
249
250 // Patch code with debug break.
251 SetDebugBreak();
252 }
253
254
255 void BreakLocation::ClearOneShot() {
256 // Debugger statement always calls debugger. No need to modify it.
257 if (IsDebuggerStatement()) return;
258
259 // If there is a real break point here no more to do.
260 if (HasBreakPoint()) {
261 DCHECK(IsDebugBreak());
262 return;
263 }
264
265 // Patch code removing debug break.
266 ClearDebugBreak();
267 DCHECK(!IsDebugBreak());
268 }
269
270
271 void BreakLocation::SetDebugBreak() {
272 // Debugger statement always calls debugger. No need to modify it.
273 if (IsDebuggerStatement()) return;
274
275 // If there is already a break point here just return. This might happen if
276 // the same code is flooded with break points twice. Flooding the same
277 // function twice might happen when stepping in a function with an exception
278 // handler as the handler and the function is the same.
279 if (IsDebugBreak()) return;
280
281 DCHECK(IsDebugBreakSlot());
282 Builtins* builtins = debug_info_->GetIsolate()->builtins();
283 Handle<Code> target =
284 IsReturn() ? builtins->Return_DebugBreak() : builtins->Slot_DebugBreak();
285 DebugCodegen::PatchDebugBreakSlot(pc(), target);
286 DCHECK(IsDebugBreak());
287 }
288
289
290 void BreakLocation::ClearDebugBreak() {
291 // Debugger statement always calls debugger. No need to modify it.
292 if (IsDebuggerStatement()) return;
293
294 DCHECK(IsDebugBreakSlot());
295 DebugCodegen::ClearDebugBreakSlot(pc());
296 DCHECK(!IsDebugBreak());
297 }
298
299
300 bool BreakLocation::IsStepInLocation() const {
301 return IsConstructCall() || IsCall();
302 }
303
304
305 bool BreakLocation::IsDebugBreak() const {
306 if (IsDebugBreakSlot()) {
307 return rinfo().IsPatchedDebugBreakSlotSequence();
308 }
309 return false;
310 }
311
312
313 Handle<Object> BreakLocation::BreakPointObjects() const {
314 return debug_info_->GetBreakPointObjects(pc_offset_);
315 }
316
317
318 // Threading support.
319 void Debug::ThreadInit() {
320 thread_local_.break_count_ = 0;
321 thread_local_.break_id_ = 0;
322 thread_local_.break_frame_id_ = StackFrame::NO_ID;
323 thread_local_.last_step_action_ = StepNone;
324 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
325 thread_local_.step_count_ = 0;
326 thread_local_.last_fp_ = 0;
327 thread_local_.queued_step_count_ = 0;
328 thread_local_.step_into_fp_ = 0;
329 thread_local_.step_out_fp_ = 0;
330 // TODO(isolates): frames_are_dropped_?
331 base::NoBarrier_Store(&thread_local_.current_debug_scope_,
332 static_cast<base::AtomicWord>(0));
333 thread_local_.restarter_frame_function_pointer_ = NULL;
334 }
335
336
337 char* Debug::ArchiveDebug(char* storage) {
338 char* to = storage;
339 MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
340 ThreadInit();
341 return storage + ArchiveSpacePerThread();
342 }
343
344
345 char* Debug::RestoreDebug(char* storage) {
346 char* from = storage;
347 MemCopy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
348 return storage + ArchiveSpacePerThread();
349 }
350
351
352 int Debug::ArchiveSpacePerThread() {
353 return sizeof(ThreadLocal);
354 }
355
356
357 ScriptCache::ScriptCache(Isolate* isolate) : isolate_(isolate) {
358 Heap* heap = isolate_->heap();
359 HandleScope scope(isolate_);
360
361 DCHECK(isolate_->debug()->is_active());
362
363 // Perform a GC to get rid of all unreferenced scripts.
364 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "ScriptCache");
365
366 // Scan heap for Script objects.
367 List<Handle<Script> > scripts;
368 {
369 HeapIterator iterator(heap, HeapIterator::kFilterUnreachable);
370 DisallowHeapAllocation no_allocation;
371 for (HeapObject* obj = iterator.next(); obj != NULL;
372 obj = iterator.next()) {
373 if (obj->IsScript() && Script::cast(obj)->HasValidSource()) {
374 scripts.Add(Handle<Script>(Script::cast(obj)));
375 }
376 }
377 }
378
379 GlobalHandles* global_handles = isolate_->global_handles();
380 table_ = Handle<WeakValueHashTable>::cast(global_handles->Create(
381 Object::cast(*WeakValueHashTable::New(isolate_, scripts.length()))));
382 for (int i = 0; i < scripts.length(); i++) Add(scripts[i]);
383 }
384
385
386 void ScriptCache::Add(Handle<Script> script) {
387 HandleScope scope(isolate_);
388 Handle<Smi> id(script->id(), isolate_);
389
390 #ifdef DEBUG
391 Handle<Object> lookup(table_->LookupWeak(id), isolate_);
392 if (!lookup->IsTheHole()) {
393 Handle<Script> found = Handle<Script>::cast(lookup);
394 DCHECK(script->id() == found->id());
395 DCHECK(!script->name()->IsString() ||
396 String::cast(script->name())->Equals(String::cast(found->name())));
397 }
398 #endif
399
400 Handle<WeakValueHashTable> new_table =
401 WeakValueHashTable::PutWeak(table_, id, script);
402
403 if (new_table.is_identical_to(table_)) return;
404 GlobalHandles* global_handles = isolate_->global_handles();
405 global_handles->Destroy(Handle<Object>::cast(table_).location());
406 table_ = Handle<WeakValueHashTable>::cast(
407 global_handles->Create(Object::cast(*new_table)));
408 }
409
410
411 ScriptCache::~ScriptCache() {
412 isolate_->global_handles()->Destroy(Handle<Object>::cast(table_).location());
413 table_ = Handle<WeakValueHashTable>();
414 }
415
416
417 DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
418 // Globalize the request debug info object and make it weak.
419 GlobalHandles* global_handles = debug_info->GetIsolate()->global_handles();
420 debug_info_ =
421 Handle<DebugInfo>::cast(global_handles->Create(debug_info)).location();
422 }
423
424
425 DebugInfoListNode::~DebugInfoListNode() {
426 if (debug_info_ == nullptr) return;
427 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_));
428 debug_info_ = nullptr;
429 }
430
431
432 bool Debug::CompileDebuggerScript(Isolate* isolate, int index) {
433 Factory* factory = isolate->factory();
434 HandleScope scope(isolate);
435
436 // Bail out if the index is invalid.
437 if (index == -1) return false;
438
439 // Find source and name for the requested script.
440 Handle<String> source_code =
441 isolate->bootstrapper()->SourceLookup<Natives>(index);
442 Vector<const char> name = Natives::GetScriptName(index);
443 Handle<String> script_name =
444 factory->NewStringFromAscii(name).ToHandleChecked();
445 Handle<Context> context = isolate->native_context();
446
447 // Compile the script.
448 Handle<SharedFunctionInfo> function_info;
449 function_info = Compiler::CompileScript(
450 source_code, script_name, 0, 0, ScriptOriginOptions(), Handle<Object>(),
451 context, NULL, NULL, ScriptCompiler::kNoCompileOptions, NATIVES_CODE,
452 false);
453 if (function_info.is_null()) return false;
454
455 // Execute the shared function in the debugger context.
456 Handle<JSFunction> function =
457 factory->NewFunctionFromSharedFunctionInfo(function_info, context);
458
459 MaybeHandle<Object> maybe_exception;
460 MaybeHandle<Object> result = Execution::TryCall(
461 function, handle(context->global_proxy()), 0, NULL, &maybe_exception);
462
463 // Check for caught exceptions.
464 if (result.is_null()) {
465 DCHECK(!isolate->has_pending_exception());
466 MessageLocation computed_location;
467 isolate->ComputeLocation(&computed_location);
468 Handle<JSMessageObject> message = MessageHandler::MakeMessageObject(
469 isolate, MessageTemplate::kDebuggerLoading, &computed_location,
470 isolate->factory()->undefined_value(), Handle<JSArray>());
471 DCHECK(!isolate->has_pending_exception());
472 Handle<Object> exception;
473 if (maybe_exception.ToHandle(&exception)) {
474 isolate->set_pending_exception(*exception);
475 MessageHandler::ReportMessage(isolate, NULL, message);
476 }
477 DCHECK(!maybe_exception.is_null());
478 return false;
479 }
480
481 // Mark this script as native and return successfully.
482 Handle<Script> script(Script::cast(function->shared()->script()));
483 script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
484 return true;
485 }
486
487
488 bool Debug::Load() {
489 // Return if debugger is already loaded.
490 if (is_loaded()) return true;
491
492 // Bail out if we're already in the process of compiling the native
493 // JavaScript source code for the debugger.
494 if (is_suppressed_) return false;
495 SuppressDebug while_loading(this);
496
497 // Disable breakpoints and interrupts while compiling and running the
498 // debugger scripts including the context creation code.
499 DisableBreak disable(this, true);
500 PostponeInterruptsScope postpone(isolate_);
501
502 // Create the debugger context.
503 HandleScope scope(isolate_);
504 ExtensionConfiguration no_extensions;
505 Handle<Context> context = isolate_->bootstrapper()->CreateEnvironment(
506 MaybeHandle<JSGlobalProxy>(), v8::Local<ObjectTemplate>(),
507 &no_extensions);
508
509 // Fail if no context could be created.
510 if (context.is_null()) return false;
511
512 // Use the debugger context.
513 SaveContext save(isolate_);
514 isolate_->set_context(*context);
515
516 // Expose the builtins object in the debugger context.
517 Handle<String> key = isolate_->factory()->InternalizeOneByteString(
518 STATIC_CHAR_VECTOR("builtins"));
519 Handle<GlobalObject> global =
520 Handle<GlobalObject>(context->global_object(), isolate_);
521 Handle<JSBuiltinsObject> builtin =
522 Handle<JSBuiltinsObject>(global->builtins(), isolate_);
523 RETURN_ON_EXCEPTION_VALUE(
524 isolate_, Object::SetProperty(global, key, builtin, SLOPPY), false);
525
526 // Compile the JavaScript for the debugger in the debugger context.
527 bool caught_exception =
528 !CompileDebuggerScript(isolate_, Natives::GetIndex("mirror")) ||
529 !CompileDebuggerScript(isolate_, Natives::GetIndex("debug"));
530
531 if (FLAG_enable_liveedit) {
532 caught_exception = caught_exception ||
533 !CompileDebuggerScript(isolate_, Natives::GetIndex("liveedit"));
534 }
535 // Check for caught exceptions.
536 if (caught_exception) return false;
537
538 debug_context_ = Handle<Context>::cast(
539 isolate_->global_handles()->Create(*context));
540 return true;
541 }
542
543
544 void Debug::Unload() {
545 ClearAllBreakPoints();
546 ClearStepping();
547
548 // Return debugger is not loaded.
549 if (!is_loaded()) return;
550
551 // Clear the script cache.
552 if (script_cache_ != NULL) {
553 delete script_cache_;
554 script_cache_ = NULL;
555 }
556
557 // Clear debugger context global handle.
558 GlobalHandles::Destroy(Handle<Object>::cast(debug_context_).location());
559 debug_context_ = Handle<Context>();
560 }
561
562
563 void Debug::Break(Arguments args, JavaScriptFrame* frame) {
564 Heap* heap = isolate_->heap();
565 HandleScope scope(isolate_);
566 DCHECK(args.length() == 0);
567
568 // Initialize LiveEdit.
569 LiveEdit::InitializeThreadLocal(this);
570
571 // Just continue if breaks are disabled or debugger cannot be loaded.
572 if (break_disabled()) return;
573
574 // Enter the debugger.
575 DebugScope debug_scope(this);
576 if (debug_scope.failed()) return;
577
578 // Postpone interrupt during breakpoint processing.
579 PostponeInterruptsScope postpone(isolate_);
580
581 // Get the debug info (create it if it does not exist).
582 Handle<SharedFunctionInfo> shared =
583 Handle<SharedFunctionInfo>(frame->function()->shared());
584 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
585
586 // Find the break point where execution has stopped.
587 // PC points to the instruction after the current one, possibly a break
588 // location as well. So the "- 1" to exclude it from the search.
589 Address call_pc = frame->pc() - 1;
590 BreakLocation break_location =
591 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc);
592
593 // Check whether step next reached a new statement.
594 if (!StepNextContinue(&break_location, frame)) {
595 // Decrease steps left if performing multiple steps.
596 if (thread_local_.step_count_ > 0) {
597 thread_local_.step_count_--;
598 }
599 }
600
601 // If there is one or more real break points check whether any of these are
602 // triggered.
603 Handle<Object> break_points_hit(heap->undefined_value(), isolate_);
604 if (break_location.HasBreakPoint()) {
605 Handle<Object> break_point_objects = break_location.BreakPointObjects();
606 break_points_hit = CheckBreakPoints(break_point_objects);
607 }
608
609 // If step out is active skip everything until the frame where we need to step
610 // out to is reached, unless real breakpoint is hit.
611 if (StepOutActive() &&
612 frame->fp() != thread_local_.step_out_fp_ &&
613 break_points_hit->IsUndefined() ) {
614 // Step count should always be 0 for StepOut.
615 DCHECK(thread_local_.step_count_ == 0);
616 } else if (!break_points_hit->IsUndefined() ||
617 (thread_local_.last_step_action_ != StepNone &&
618 thread_local_.step_count_ == 0)) {
619 // Notify debugger if a real break point is triggered or if performing
620 // single stepping with no more steps to perform. Otherwise do another step.
621
622 // Clear all current stepping setup.
623 ClearStepping();
624
625 if (thread_local_.queued_step_count_ > 0) {
626 // Perform queued steps
627 int step_count = thread_local_.queued_step_count_;
628
629 // Clear queue
630 thread_local_.queued_step_count_ = 0;
631
632 PrepareStep(StepNext, step_count, StackFrame::NO_ID);
633 } else {
634 // Notify the debug event listeners.
635 OnDebugBreak(break_points_hit, false);
636 }
637 } else if (thread_local_.last_step_action_ != StepNone) {
638 // Hold on to last step action as it is cleared by the call to
639 // ClearStepping.
640 StepAction step_action = thread_local_.last_step_action_;
641 int step_count = thread_local_.step_count_;
642
643 // If StepNext goes deeper in code, StepOut until original frame
644 // and keep step count queued up in the meantime.
645 if (step_action == StepNext && frame->fp() < thread_local_.last_fp_) {
646 // Count frames until target frame
647 int count = 0;
648 JavaScriptFrameIterator it(isolate_);
649 while (!it.done() && it.frame()->fp() < thread_local_.last_fp_) {
650 count++;
651 it.Advance();
652 }
653
654 // Check that we indeed found the frame we are looking for.
655 CHECK(!it.done() && (it.frame()->fp() == thread_local_.last_fp_));
656 if (step_count > 1) {
657 // Save old count and action to continue stepping after StepOut.
658 thread_local_.queued_step_count_ = step_count - 1;
659 }
660
661 // Set up for StepOut to reach target frame.
662 step_action = StepOut;
663 step_count = count;
664 }
665
666 // Clear all current stepping setup.
667 ClearStepping();
668
669 // Set up for the remaining steps.
670 PrepareStep(step_action, step_count, StackFrame::NO_ID);
671 }
672 }
673
674
675 // Check the break point objects for whether one or more are actually
676 // triggered. This function returns a JSArray with the break point objects
677 // which is triggered.
678 Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) {
679 Factory* factory = isolate_->factory();
680
681 // Count the number of break points hit. If there are multiple break points
682 // they are in a FixedArray.
683 Handle<FixedArray> break_points_hit;
684 int break_points_hit_count = 0;
685 DCHECK(!break_point_objects->IsUndefined());
686 if (break_point_objects->IsFixedArray()) {
687 Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
688 break_points_hit = factory->NewFixedArray(array->length());
689 for (int i = 0; i < array->length(); i++) {
690 Handle<Object> o(array->get(i), isolate_);
691 if (CheckBreakPoint(o)) {
692 break_points_hit->set(break_points_hit_count++, *o);
693 }
694 }
695 } else {
696 break_points_hit = factory->NewFixedArray(1);
697 if (CheckBreakPoint(break_point_objects)) {
698 break_points_hit->set(break_points_hit_count++, *break_point_objects);
699 }
700 }
701
702 // Return undefined if no break points were triggered.
703 if (break_points_hit_count == 0) {
704 return factory->undefined_value();
705 }
706 // Return break points hit as a JSArray.
707 Handle<JSArray> result = factory->NewJSArrayWithElements(break_points_hit);
708 result->set_length(Smi::FromInt(break_points_hit_count));
709 return result;
710 }
711
712
713 // Check whether a single break point object is triggered.
714 bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
715 Factory* factory = isolate_->factory();
716 HandleScope scope(isolate_);
717
718 // Ignore check if break point object is not a JSObject.
719 if (!break_point_object->IsJSObject()) return true;
720
721 // Get the function IsBreakPointTriggered (defined in debug-debugger.js).
722 Handle<String> is_break_point_triggered_string =
723 factory->InternalizeOneByteString(
724 STATIC_CHAR_VECTOR("IsBreakPointTriggered"));
725 Handle<GlobalObject> debug_global(debug_context()->global_object());
726 Handle<JSFunction> check_break_point =
727 Handle<JSFunction>::cast(Object::GetProperty(
728 debug_global, is_break_point_triggered_string).ToHandleChecked());
729
730 // Get the break id as an object.
731 Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id());
732
733 // Call HandleBreakPointx.
734 Handle<Object> argv[] = { break_id, break_point_object };
735 Handle<Object> result;
736 if (!Execution::TryCall(check_break_point,
737 isolate_->js_builtins_object(),
738 arraysize(argv),
739 argv).ToHandle(&result)) {
740 return false;
741 }
742
743 // Return whether the break point is triggered.
744 return result->IsTrue();
745 }
746
747
748 bool Debug::SetBreakPoint(Handle<JSFunction> function,
749 Handle<Object> break_point_object,
750 int* source_position) {
751 HandleScope scope(isolate_);
752
753 // Make sure the function is compiled and has set up the debug info.
754 Handle<SharedFunctionInfo> shared(function->shared());
755 if (!EnsureDebugInfo(shared, function)) {
756 // Return if retrieving debug info failed.
757 return true;
758 }
759
760 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
761 // Source positions starts with zero.
762 DCHECK(*source_position >= 0);
763
764 // Find the break point and change it.
765 BreakLocation location = BreakLocation::FromPosition(
766 debug_info, ALL_BREAK_LOCATIONS, *source_position, STATEMENT_ALIGNED);
767 *source_position = location.statement_position();
768 location.SetBreakPoint(break_point_object);
769
770 // At least one active break point now.
771 return debug_info->GetBreakPointCount() > 0;
772 }
773
774
775 bool Debug::SetBreakPointForScript(Handle<Script> script,
776 Handle<Object> break_point_object,
777 int* source_position,
778 BreakPositionAlignment alignment) {
779 HandleScope scope(isolate_);
780
781 // Obtain shared function info for the function.
782 Handle<Object> result =
783 FindSharedFunctionInfoInScript(script, *source_position);
784 if (result->IsUndefined()) return false;
785
786 // Make sure the function has set up the debug info.
787 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>::cast(result);
788 if (!EnsureDebugInfo(shared, Handle<JSFunction>::null())) {
789 // Return if retrieving debug info failed.
790 return false;
791 }
792
793 // Find position within function. The script position might be before the
794 // source position of the first function.
795 int position;
796 if (shared->start_position() > *source_position) {
797 position = 0;
798 } else {
799 position = *source_position - shared->start_position();
800 }
801
802 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
803 // Source positions starts with zero.
804 DCHECK(position >= 0);
805
806 // Find the break point and change it.
807 BreakLocation location = BreakLocation::FromPosition(
808 debug_info, ALL_BREAK_LOCATIONS, position, alignment);
809 location.SetBreakPoint(break_point_object);
810
811 position = (alignment == STATEMENT_ALIGNED) ? location.statement_position()
812 : location.position();
813
814 *source_position = position + shared->start_position();
815
816 // At least one active break point now.
817 DCHECK(debug_info->GetBreakPointCount() > 0);
818 return true;
819 }
820
821
822 void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
823 HandleScope scope(isolate_);
824
825 DebugInfoListNode* node = debug_info_list_;
826 while (node != NULL) {
827 Handle<Object> result =
828 DebugInfo::FindBreakPointInfo(node->debug_info(), break_point_object);
829 if (!result->IsUndefined()) {
830 // Get information in the break point.
831 Handle<BreakPointInfo> break_point_info =
832 Handle<BreakPointInfo>::cast(result);
833 Handle<DebugInfo> debug_info = node->debug_info();
834
835 // Find the break point and clear it.
836 Address pc = debug_info->code()->entry() +
837 break_point_info->code_position()->value();
838
839 BreakLocation location =
840 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, pc);
841 location.ClearBreakPoint(break_point_object);
842
843 // If there are no more break points left remove the debug info for this
844 // function.
845 if (debug_info->GetBreakPointCount() == 0) {
846 RemoveDebugInfoAndClearFromShared(debug_info);
847 }
848
849 return;
850 }
851 node = node->next();
852 }
853 }
854
855
856 // Clear out all the debug break code. This is ONLY supposed to be used when
857 // shutting down the debugger as it will leave the break point information in
858 // DebugInfo even though the code is patched back to the non break point state.
859 void Debug::ClearAllBreakPoints() {
860 for (DebugInfoListNode* node = debug_info_list_; node != NULL;
861 node = node->next()) {
862 for (BreakLocation::Iterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
863 !it.Done(); it.Next()) {
864 it.GetBreakLocation().ClearDebugBreak();
865 }
866 }
867 // Remove all debug info.
868 while (debug_info_list_ != NULL) {
869 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info());
870 }
871 }
872
873
874 void Debug::FloodWithOneShot(Handle<JSFunction> function,
875 BreakLocatorType type) {
876 // Make sure the function is compiled and has set up the debug info.
877 Handle<SharedFunctionInfo> shared(function->shared());
878 if (!EnsureDebugInfo(shared, function)) {
879 // Return if we failed to retrieve the debug info.
880 return;
881 }
882
883 // Flood the function with break points.
884 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
885 for (BreakLocation::Iterator it(debug_info, type); !it.Done(); it.Next()) {
886 it.GetBreakLocation().SetOneShot();
887 }
888 }
889
890
891 void Debug::FloodBoundFunctionWithOneShot(Handle<JSFunction> function) {
892 Handle<FixedArray> new_bindings(function->function_bindings());
893 Handle<Object> bindee(new_bindings->get(JSFunction::kBoundFunctionIndex),
894 isolate_);
895
896 if (!bindee.is_null() && bindee->IsJSFunction()) {
897 Handle<JSFunction> bindee_function(JSFunction::cast(*bindee));
898 FloodWithOneShotGeneric(bindee_function);
899 }
900 }
901
902
903 void Debug::FloodDefaultConstructorWithOneShot(Handle<JSFunction> function) {
904 DCHECK(function->shared()->is_default_constructor());
905 // Instead of stepping into the function we directly step into the super class
906 // constructor.
907 Isolate* isolate = function->GetIsolate();
908 PrototypeIterator iter(isolate, function);
909 Handle<Object> proto = PrototypeIterator::GetCurrent(iter);
910 if (!proto->IsJSFunction()) return; // Object.prototype
911 Handle<JSFunction> function_proto = Handle<JSFunction>::cast(proto);
912 FloodWithOneShotGeneric(function_proto);
913 }
914
915
916 void Debug::FloodWithOneShotGeneric(Handle<JSFunction> function,
917 Handle<Object> holder) {
918 if (function->shared()->bound()) {
919 FloodBoundFunctionWithOneShot(function);
920 } else if (function->shared()->is_default_constructor()) {
921 FloodDefaultConstructorWithOneShot(function);
922 } else {
923 Isolate* isolate = function->GetIsolate();
924 // Don't allow step into functions in the native context.
925 if (function->shared()->code() ==
926 isolate->builtins()->builtin(Builtins::kFunctionApply) ||
927 function->shared()->code() ==
928 isolate->builtins()->builtin(Builtins::kFunctionCall)) {
929 // Handle function.apply and function.call separately to flood the
930 // function to be called and not the code for Builtins::FunctionApply or
931 // Builtins::FunctionCall. The receiver of call/apply is the target
932 // function.
933 if (!holder.is_null() && holder->IsJSFunction()) {
934 Handle<JSFunction> js_function = Handle<JSFunction>::cast(holder);
935 FloodWithOneShotGeneric(js_function);
936 }
937 } else {
938 FloodWithOneShot(function);
939 }
940 }
941 }
942
943
944 void Debug::FloodHandlerWithOneShot() {
945 // Iterate through the JavaScript stack looking for handlers.
946 StackFrame::Id id = break_frame_id();
947 if (id == StackFrame::NO_ID) {
948 // If there is no JavaScript stack don't do anything.
949 return;
950 }
951 for (JavaScriptFrameIterator it(isolate_, id); !it.done(); it.Advance()) {
952 JavaScriptFrame* frame = it.frame();
953 int stack_slots = 0; // The computed stack slot count is not used.
954 if (frame->LookupExceptionHandlerInTable(&stack_slots, NULL) > 0) {
955 // Flood the function with the catch/finally block with break points.
956 FloodWithOneShot(Handle<JSFunction>(frame->function()));
957 return;
958 }
959 }
960 }
961
962
963 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
964 if (type == BreakUncaughtException) {
965 break_on_uncaught_exception_ = enable;
966 } else {
967 break_on_exception_ = enable;
968 }
969 }
970
971
972 bool Debug::IsBreakOnException(ExceptionBreakType type) {
973 if (type == BreakUncaughtException) {
974 return break_on_uncaught_exception_;
975 } else {
976 return break_on_exception_;
977 }
978 }
979
980
981 FrameSummary GetFirstFrameSummary(JavaScriptFrame* frame) {
982 List<FrameSummary> frames(FLAG_max_inlining_levels + 1);
983 frame->Summarize(&frames);
984 return frames.first();
985 }
986
987
988 void Debug::PrepareStep(StepAction step_action,
989 int step_count,
990 StackFrame::Id frame_id) {
991 HandleScope scope(isolate_);
992
993 DCHECK(in_debug_scope());
994
995 // Remember this step action and count.
996 thread_local_.last_step_action_ = step_action;
997 if (step_action == StepOut) {
998 // For step out target frame will be found on the stack so there is no need
999 // to set step counter for it. It's expected to always be 0 for StepOut.
1000 thread_local_.step_count_ = 0;
1001 } else {
1002 thread_local_.step_count_ = step_count;
1003 }
1004
1005 // Get the frame where the execution has stopped and skip the debug frame if
1006 // any. The debug frame will only be present if execution was stopped due to
1007 // hitting a break point. In other situations (e.g. unhandled exception) the
1008 // debug frame is not present.
1009 StackFrame::Id id = break_frame_id();
1010 if (id == StackFrame::NO_ID) {
1011 // If there is no JavaScript stack don't do anything.
1012 return;
1013 }
1014 if (frame_id != StackFrame::NO_ID) {
1015 id = frame_id;
1016 }
1017 JavaScriptFrameIterator frames_it(isolate_, id);
1018 JavaScriptFrame* frame = frames_it.frame();
1019
1020 // First of all ensure there is one-shot break points in the top handler
1021 // if any.
1022 FloodHandlerWithOneShot();
1023
1024 // If the function on the top frame is unresolved perform step out. This will
1025 // be the case when calling unknown function and having the debugger stopped
1026 // in an unhandled exception.
1027 if (!frame->function()->IsJSFunction()) {
1028 // Step out: Find the calling JavaScript frame and flood it with
1029 // breakpoints.
1030 frames_it.Advance();
1031 // Fill the function to return to with one-shot break points.
1032 JSFunction* function = frames_it.frame()->function();
1033 FloodWithOneShot(Handle<JSFunction>(function));
1034 return;
1035 }
1036
1037 // Get the debug info (create it if it does not exist).
1038 FrameSummary summary = GetFirstFrameSummary(frame);
1039 Handle<JSFunction> function(summary.function());
1040 Handle<SharedFunctionInfo> shared(function->shared());
1041 if (!EnsureDebugInfo(shared, function)) {
1042 // Return if ensuring debug info failed.
1043 return;
1044 }
1045
1046 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
1047 // Refresh frame summary if the code has been recompiled for debugging.
1048 if (shared->code() != *summary.code()) summary = GetFirstFrameSummary(frame);
1049
1050 // PC points to the instruction after the current one, possibly a break
1051 // location as well. So the "- 1" to exclude it from the search.
1052 Address call_pc = summary.pc() - 1;
1053 BreakLocation location =
1054 BreakLocation::FromAddress(debug_info, ALL_BREAK_LOCATIONS, call_pc);
1055
1056 // If this is the last break code target step out is the only possibility.
1057 if (location.IsReturn() || step_action == StepOut) {
1058 if (step_action == StepOut) {
1059 // Skip step_count frames starting with the current one.
1060 while (step_count-- > 0 && !frames_it.done()) {
1061 frames_it.Advance();
1062 }
1063 } else {
1064 DCHECK(location.IsReturn());
1065 frames_it.Advance();
1066 }
1067 // Skip native and extension functions on the stack.
1068 while (!frames_it.done() &&
1069 !frames_it.frame()->function()->IsSubjectToDebugging()) {
1070 frames_it.Advance();
1071 }
1072 // Step out: If there is a JavaScript caller frame, we need to
1073 // flood it with breakpoints.
1074 if (!frames_it.done()) {
1075 // Fill the function to return to with one-shot break points.
1076 JSFunction* function = frames_it.frame()->function();
1077 FloodWithOneShot(Handle<JSFunction>(function));
1078 // Set target frame pointer.
1079 ActivateStepOut(frames_it.frame());
1080 }
1081 return;
1082 }
1083
1084 if (step_action != StepNext && step_action != StepMin) {
1085 // If there's restarter frame on top of the stack, just get the pointer
1086 // to function which is going to be restarted.
1087 if (thread_local_.restarter_frame_function_pointer_ != NULL) {
1088 Handle<JSFunction> restarted_function(
1089 JSFunction::cast(*thread_local_.restarter_frame_function_pointer_));
1090 FloodWithOneShot(restarted_function);
1091 } else if (location.IsCall()) {
1092 // Find target function on the expression stack.
1093 // Expression stack looks like this (top to bottom):
1094 // argN
1095 // ...
1096 // arg0
1097 // Receiver
1098 // Function to call
1099 int num_expressions_without_args =
1100 frame->ComputeExpressionsCount() - location.CallArgumentsCount();
1101 DCHECK(num_expressions_without_args >= 2);
1102 Object* fun = frame->GetExpression(num_expressions_without_args - 2);
1103
1104 // Flood the actual target of call/apply.
1105 if (fun->IsJSFunction()) {
1106 Isolate* isolate = JSFunction::cast(fun)->GetIsolate();
1107 Code* apply = isolate->builtins()->builtin(Builtins::kFunctionApply);
1108 Code* call = isolate->builtins()->builtin(Builtins::kFunctionCall);
1109 // Find target function on the expression stack for expression like
1110 // Function.call.call...apply(...)
1111 int i = 1;
1112 while (fun->IsJSFunction()) {
1113 Code* code = JSFunction::cast(fun)->shared()->code();
1114 if (code != apply && code != call) break;
1115 DCHECK(num_expressions_without_args >= i);
1116 fun = frame->GetExpression(num_expressions_without_args - i);
1117 i--;
1118 }
1119 }
1120
1121 if (fun->IsJSFunction()) {
1122 Handle<JSFunction> js_function(JSFunction::cast(fun));
1123 FloodWithOneShotGeneric(js_function);
1124 }
1125 }
1126
1127 ActivateStepIn(frame);
1128 }
1129
1130 // Fill the current function with one-shot break points even for step in on
1131 // a call target as the function called might be a native function for
1132 // which step in will not stop. It also prepares for stepping in
1133 // getters/setters.
1134 // If we are stepping into another frame, only fill calls and returns.
1135 FloodWithOneShot(function, step_action == StepFrame ? CALLS_AND_RETURNS
1136 : ALL_BREAK_LOCATIONS);
1137
1138 // Remember source position and frame to handle step next.
1139 thread_local_.last_statement_position_ =
1140 debug_info->code()->SourceStatementPosition(summary.pc());
1141 thread_local_.last_fp_ = frame->UnpaddedFP();
1142 }
1143
1144
1145 // Check whether the current debug break should be reported to the debugger. It
1146 // is used to have step next and step in only report break back to the debugger
1147 // if on a different frame or in a different statement. In some situations
1148 // there will be several break points in the same statement when the code is
1149 // flooded with one-shot break points. This function helps to perform several
1150 // steps before reporting break back to the debugger.
1151 bool Debug::StepNextContinue(BreakLocation* break_location,
1152 JavaScriptFrame* frame) {
1153 // StepNext and StepOut shouldn't bring us deeper in code, so last frame
1154 // shouldn't be a parent of current frame.
1155 StepAction step_action = thread_local_.last_step_action_;
1156
1157 if (step_action == StepNext || step_action == StepOut) {
1158 if (frame->fp() < thread_local_.last_fp_) return true;
1159 }
1160
1161 // We stepped into a new frame if the frame pointer changed.
1162 if (step_action == StepFrame) {
1163 return frame->UnpaddedFP() == thread_local_.last_fp_;
1164 }
1165
1166 // If the step last action was step next or step in make sure that a new
1167 // statement is hit.
1168 if (step_action == StepNext || step_action == StepIn) {
1169 // Never continue if returning from function.
1170 if (break_location->IsReturn()) return false;
1171
1172 // Continue if we are still on the same frame and in the same statement.
1173 int current_statement_position =
1174 break_location->code()->SourceStatementPosition(frame->pc());
1175 return thread_local_.last_fp_ == frame->UnpaddedFP() &&
1176 thread_local_.last_statement_position_ == current_statement_position;
1177 }
1178
1179 // No step next action - don't continue.
1180 return false;
1181 }
1182
1183
1184 // Check whether the code object at the specified address is a debug break code
1185 // object.
1186 bool Debug::IsDebugBreak(Address addr) {
1187 Code* code = Code::GetCodeFromTargetAddress(addr);
1188 return code->is_debug_stub();
1189 }
1190
1191
1192 // Simple function for returning the source positions for active break points.
1193 Handle<Object> Debug::GetSourceBreakLocations(
1194 Handle<SharedFunctionInfo> shared,
1195 BreakPositionAlignment position_alignment) {
1196 Isolate* isolate = shared->GetIsolate();
1197 Heap* heap = isolate->heap();
1198 if (!shared->HasDebugInfo()) {
1199 return Handle<Object>(heap->undefined_value(), isolate);
1200 }
1201 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
1202 if (debug_info->GetBreakPointCount() == 0) {
1203 return Handle<Object>(heap->undefined_value(), isolate);
1204 }
1205 Handle<FixedArray> locations =
1206 isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount());
1207 int count = 0;
1208 for (int i = 0; i < debug_info->break_points()->length(); ++i) {
1209 if (!debug_info->break_points()->get(i)->IsUndefined()) {
1210 BreakPointInfo* break_point_info =
1211 BreakPointInfo::cast(debug_info->break_points()->get(i));
1212 int break_points = break_point_info->GetBreakPointCount();
1213 if (break_points == 0) continue;
1214 Smi* position = NULL;
1215 switch (position_alignment) {
1216 case STATEMENT_ALIGNED:
1217 position = break_point_info->statement_position();
1218 break;
1219 case BREAK_POSITION_ALIGNED:
1220 position = break_point_info->source_position();
1221 break;
1222 }
1223 for (int j = 0; j < break_points; ++j) locations->set(count++, position);
1224 }
1225 }
1226 return locations;
1227 }
1228
1229
1230 // Handle stepping into a function.
1231 void Debug::HandleStepIn(Handle<Object> function_obj, bool is_constructor) {
1232 // Flood getter/setter if we either step in or step to another frame.
1233 bool step_frame = thread_local_.last_step_action_ == StepFrame;
1234 if (!StepInActive() && !step_frame) return;
1235 if (!function_obj->IsJSFunction()) return;
1236 Handle<JSFunction> function = Handle<JSFunction>::cast(function_obj);
1237 Isolate* isolate = function->GetIsolate();
1238
1239 StackFrameIterator it(isolate);
1240 it.Advance();
1241 // For constructor functions skip another frame.
1242 if (is_constructor) {
1243 DCHECK(it.frame()->is_construct());
1244 it.Advance();
1245 }
1246 Address fp = it.frame()->fp();
1247
1248 // Flood the function with one-shot break points if it is called from where
1249 // step into was requested, or when stepping into a new frame.
1250 if (fp == thread_local_.step_into_fp_ || step_frame) {
1251 FloodWithOneShotGeneric(function, Handle<Object>());
1252 }
1253 }
1254
1255
1256 void Debug::ClearStepping() {
1257 // Clear the various stepping setup.
1258 ClearOneShot();
1259 ClearStepIn();
1260 ClearStepOut();
1261 ClearStepNext();
1262
1263 // Clear multiple step counter.
1264 thread_local_.step_count_ = 0;
1265 }
1266
1267
1268 // Clears all the one-shot break points that are currently set. Normally this
1269 // function is called each time a break point is hit as one shot break points
1270 // are used to support stepping.
1271 void Debug::ClearOneShot() {
1272 // The current implementation just runs through all the breakpoints. When the
1273 // last break point for a function is removed that function is automatically
1274 // removed from the list.
1275 for (DebugInfoListNode* node = debug_info_list_; node != NULL;
1276 node = node->next()) {
1277 for (BreakLocation::Iterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1278 !it.Done(); it.Next()) {
1279 it.GetBreakLocation().ClearOneShot();
1280 }
1281 }
1282 }
1283
1284
1285 void Debug::ActivateStepIn(StackFrame* frame) {
1286 DCHECK(!StepOutActive());
1287 thread_local_.step_into_fp_ = frame->UnpaddedFP();
1288 }
1289
1290
1291 void Debug::ClearStepIn() {
1292 thread_local_.step_into_fp_ = 0;
1293 }
1294
1295
1296 void Debug::ActivateStepOut(StackFrame* frame) {
1297 DCHECK(!StepInActive());
1298 thread_local_.step_out_fp_ = frame->UnpaddedFP();
1299 }
1300
1301
1302 void Debug::ClearStepOut() {
1303 thread_local_.step_out_fp_ = 0;
1304 }
1305
1306
1307 void Debug::ClearStepNext() {
1308 thread_local_.last_step_action_ = StepNone;
1309 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
1310 thread_local_.last_fp_ = 0;
1311 }
1312
1313
1314 bool MatchingCodeTargets(Code* target1, Code* target2) {
1315 if (target1 == target2) return true;
1316 if (target1->kind() != target2->kind()) return false;
1317 return target1->is_handler() || target1->is_inline_cache_stub();
1318 }
1319
1320
1321 // Count the number of calls before the current frame PC to find the
1322 // corresponding PC in the newly recompiled code.
1323 static Address ComputeNewPcForRedirect(Code* new_code, Code* old_code,
1324 Address old_pc) {
1325 DCHECK_EQ(old_code->kind(), Code::FUNCTION);
1326 DCHECK_EQ(new_code->kind(), Code::FUNCTION);
1327 DCHECK(new_code->has_debug_break_slots());
1328 static const int mask = RelocInfo::kCodeTargetMask;
1329
1330 // Find the target of the current call.
1331 Code* target = NULL;
1332 intptr_t delta = 0;
1333 for (RelocIterator it(old_code, mask); !it.done(); it.next()) {
1334 RelocInfo* rinfo = it.rinfo();
1335 Address current_pc = rinfo->pc();
1336 // The frame PC is behind the call instruction by the call instruction size.
1337 if (current_pc > old_pc) break;
1338 delta = old_pc - current_pc;
1339 target = Code::GetCodeFromTargetAddress(rinfo->target_address());
1340 }
1341
1342 // Count the number of calls to the same target before the current call.
1343 int index = 0;
1344 for (RelocIterator it(old_code, mask); !it.done(); it.next()) {
1345 RelocInfo* rinfo = it.rinfo();
1346 Address current_pc = rinfo->pc();
1347 if (current_pc > old_pc) break;
1348 Code* current = Code::GetCodeFromTargetAddress(rinfo->target_address());
1349 if (MatchingCodeTargets(target, current)) index++;
1350 }
1351
1352 DCHECK(index > 0);
1353
1354 // Repeat the count on the new code to find corresponding call.
1355 for (RelocIterator it(new_code, mask); !it.done(); it.next()) {
1356 RelocInfo* rinfo = it.rinfo();
1357 Code* current = Code::GetCodeFromTargetAddress(rinfo->target_address());
1358 if (MatchingCodeTargets(target, current)) index--;
1359 if (index == 0) return rinfo->pc() + delta;
1360 }
1361
1362 UNREACHABLE();
1363 return NULL;
1364 }
1365
1366
1367 // Count the number of continuations at which the current pc offset is at.
1368 static int ComputeContinuationIndexFromPcOffset(Code* code, int pc_offset) {
1369 DCHECK_EQ(code->kind(), Code::FUNCTION);
1370 Address pc = code->instruction_start() + pc_offset;
1371 int mask = RelocInfo::ModeMask(RelocInfo::GENERATOR_CONTINUATION);
1372 int index = 0;
1373 for (RelocIterator it(code, mask); !it.done(); it.next()) {
1374 index++;
1375 RelocInfo* rinfo = it.rinfo();
1376 Address current_pc = rinfo->pc();
1377 if (current_pc == pc) break;
1378 DCHECK(current_pc < pc);
1379 }
1380 return index;
1381 }
1382
1383
1384 // Find the pc offset for the given continuation index.
1385 static int ComputePcOffsetFromContinuationIndex(Code* code, int index) {
1386 DCHECK_EQ(code->kind(), Code::FUNCTION);
1387 DCHECK(code->has_debug_break_slots());
1388 int mask = RelocInfo::ModeMask(RelocInfo::GENERATOR_CONTINUATION);
1389 RelocIterator it(code, mask);
1390 for (int i = 1; i < index; i++) it.next();
1391 return static_cast<int>(it.rinfo()->pc() - code->instruction_start());
1392 }
1393
1394
1395 class RedirectActiveFunctions : public ThreadVisitor {
1396 public:
1397 explicit RedirectActiveFunctions(SharedFunctionInfo* shared)
1398 : shared_(shared) {
1399 DCHECK(shared->HasDebugCode());
1400 }
1401
1402 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
1403 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
1404 JavaScriptFrame* frame = it.frame();
1405 JSFunction* function = frame->function();
1406 if (frame->is_optimized()) continue;
1407 if (!function->Inlines(shared_)) continue;
1408
1409 Code* frame_code = frame->LookupCode();
1410 DCHECK(frame_code->kind() == Code::FUNCTION);
1411 if (frame_code->has_debug_break_slots()) continue;
1412
1413 Code* new_code = function->shared()->code();
1414 Address old_pc = frame->pc();
1415 Address new_pc = ComputeNewPcForRedirect(new_code, frame_code, old_pc);
1416
1417 if (FLAG_trace_deopt) {
1418 PrintF("Replacing pc for debugging: %08" V8PRIxPTR " => %08" V8PRIxPTR
1419 "\n",
1420 reinterpret_cast<intptr_t>(old_pc),
1421 reinterpret_cast<intptr_t>(new_pc));
1422 }
1423
1424 if (FLAG_enable_embedded_constant_pool) {
1425 // Update constant pool pointer for new code.
1426 frame->set_constant_pool(new_code->constant_pool());
1427 }
1428
1429 // Patch the return address to return into the code with
1430 // debug break slots.
1431 frame->set_pc(new_pc);
1432 }
1433 }
1434
1435 private:
1436 SharedFunctionInfo* shared_;
1437 DisallowHeapAllocation no_gc_;
1438 };
1439
1440
1441 bool Debug::PrepareFunctionForBreakPoints(Handle<SharedFunctionInfo> shared) {
1442 DCHECK(shared->is_compiled());
1443
1444 if (isolate_->concurrent_recompilation_enabled()) {
1445 isolate_->optimizing_compile_dispatcher()->Flush();
1446 }
1447
1448 List<Handle<JSFunction> > functions;
1449 List<Handle<JSGeneratorObject> > suspended_generators;
1450
1451 if (!shared->optimized_code_map()->IsSmi()) {
1452 shared->ClearOptimizedCodeMap();
1453 }
1454
1455 // Make sure we abort incremental marking.
1456 isolate_->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1457 "prepare for break points");
1458
1459 {
1460 HeapIterator iterator(isolate_->heap());
1461 HeapObject* obj;
1462 bool include_generators = shared->is_generator();
1463
1464 while ((obj = iterator.next())) {
1465 if (obj->IsJSFunction()) {
1466 JSFunction* function = JSFunction::cast(obj);
1467 if (!function->Inlines(*shared)) continue;
1468 if (function->code()->kind() == Code::OPTIMIZED_FUNCTION) {
1469 Deoptimizer::DeoptimizeFunction(function);
1470 }
1471 if (function->shared() == *shared) functions.Add(handle(function));
1472 } else if (include_generators && obj->IsJSGeneratorObject()) {
1473 JSGeneratorObject* generator_obj = JSGeneratorObject::cast(obj);
1474 if (!generator_obj->is_suspended()) continue;
1475 JSFunction* function = generator_obj->function();
1476 if (!function->Inlines(*shared)) continue;
1477 int pc_offset = generator_obj->continuation();
1478 int index =
1479 ComputeContinuationIndexFromPcOffset(function->code(), pc_offset);
1480 generator_obj->set_continuation(index);
1481 suspended_generators.Add(handle(generator_obj));
1482 }
1483 }
1484 }
1485
1486 if (!shared->HasDebugCode()) {
1487 DCHECK(functions.length() > 0);
1488 if (!Compiler::CompileDebugCode(functions.first())) return false;
1489 }
1490
1491 for (Handle<JSFunction> const function : functions) {
1492 function->ReplaceCode(shared->code());
1493 }
1494
1495 for (Handle<JSGeneratorObject> const generator_obj : suspended_generators) {
1496 int index = generator_obj->continuation();
1497 int pc_offset = ComputePcOffsetFromContinuationIndex(shared->code(), index);
1498 generator_obj->set_continuation(pc_offset);
1499 }
1500
1501 // Update PCs on the stack to point to recompiled code.
1502 RedirectActiveFunctions redirect_visitor(*shared);
1503 redirect_visitor.VisitThread(isolate_, isolate_->thread_local_top());
1504 isolate_->thread_manager()->IterateArchivedThreads(&redirect_visitor);
1505
1506 return true;
1507 }
1508
1509
1510 class SharedFunctionInfoFinder {
1511 public:
1512 explicit SharedFunctionInfoFinder(int target_position)
1513 : current_candidate_(NULL),
1514 current_candidate_closure_(NULL),
1515 current_start_position_(RelocInfo::kNoPosition),
1516 target_position_(target_position) {}
1517
1518 void NewCandidate(SharedFunctionInfo* shared, JSFunction* closure = NULL) {
1519 int start_position = shared->function_token_position();
1520 if (start_position == RelocInfo::kNoPosition) {
1521 start_position = shared->start_position();
1522 }
1523
1524 if (start_position > target_position_) return;
1525 if (target_position_ > shared->end_position()) return;
1526
1527 if (current_candidate_ != NULL) {
1528 if (current_start_position_ == start_position &&
1529 shared->end_position() == current_candidate_->end_position()) {
1530 // If a top-level function contains only one function
1531 // declaration the source for the top-level and the function
1532 // is the same. In that case prefer the non top-level function.
1533 if (shared->is_toplevel()) return;
1534 } else if (start_position < current_start_position_ ||
1535 current_candidate_->end_position() < shared->end_position()) {
1536 return;
1537 }
1538 }
1539
1540 current_start_position_ = start_position;
1541 current_candidate_ = shared;
1542 current_candidate_closure_ = closure;
1543 }
1544
1545 SharedFunctionInfo* Result() { return current_candidate_; }
1546
1547 JSFunction* ResultClosure() { return current_candidate_closure_; }
1548
1549 private:
1550 SharedFunctionInfo* current_candidate_;
1551 JSFunction* current_candidate_closure_;
1552 int current_start_position_;
1553 int target_position_;
1554 DisallowHeapAllocation no_gc_;
1555 };
1556
1557
1558 // We need to find a SFI for a literal that may not yet have been compiled yet,
1559 // and there may not be a JSFunction referencing it. Find the SFI closest to
1560 // the given position, compile it to reveal possible inner SFIs and repeat.
1561 // While we are at this, also ensure code with debug break slots so that we do
1562 // not have to compile a SFI without JSFunction, which is paifu for those that
1563 // cannot be compiled without context (need to find outer compilable SFI etc.)
1564 Handle<Object> Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
1565 int position) {
1566 while (true) {
1567 // Go through all shared function infos associated with this script to
1568 // find the inner most function containing this position.
1569 if (!script->shared_function_infos()->IsWeakFixedArray()) break;
1570 WeakFixedArray* array =
1571 WeakFixedArray::cast(script->shared_function_infos());
1572
1573 SharedFunctionInfo* shared;
1574 {
1575 SharedFunctionInfoFinder finder(position);
1576 for (int i = 0; i < array->Length(); i++) {
1577 Object* item = array->Get(i);
1578 if (!item->IsSharedFunctionInfo()) continue;
1579 finder.NewCandidate(SharedFunctionInfo::cast(item));
1580 }
1581 shared = finder.Result();
1582 if (shared == NULL) break;
1583 // We found it if it's already compiled and has debug code.
1584 if (shared->HasDebugCode()) return handle(shared);
1585 }
1586 // If not, compile to reveal inner functions, if possible.
1587 if (shared->allows_lazy_compilation_without_context()) {
1588 HandleScope scope(isolate_);
1589 if (!Compiler::CompileDebugCode(handle(shared))) break;
1590 continue;
1591 }
1592
1593 // If not possible, comb the heap for the best suitable compile target.
1594 JSFunction* closure;
1595 {
1596 HeapIterator it(isolate_->heap());
1597 SharedFunctionInfoFinder finder(position);
1598 while (HeapObject* object = it.next()) {
1599 JSFunction* candidate_closure = NULL;
1600 SharedFunctionInfo* candidate = NULL;
1601 if (object->IsJSFunction()) {
1602 candidate_closure = JSFunction::cast(object);
1603 candidate = candidate_closure->shared();
1604 } else if (object->IsSharedFunctionInfo()) {
1605 candidate = SharedFunctionInfo::cast(object);
1606 if (!candidate->allows_lazy_compilation_without_context()) continue;
1607 } else {
1608 continue;
1609 }
1610 if (candidate->script() == *script) {
1611 finder.NewCandidate(candidate, candidate_closure);
1612 }
1613 }
1614 closure = finder.ResultClosure();
1615 shared = finder.Result();
1616 }
1617 HandleScope scope(isolate_);
1618 if (closure == NULL) {
1619 if (!Compiler::CompileDebugCode(handle(shared))) break;
1620 } else {
1621 if (!Compiler::CompileDebugCode(handle(closure))) break;
1622 }
1623 }
1624 return isolate_->factory()->undefined_value();
1625 }
1626
1627
1628 // Ensures the debug information is present for shared.
1629 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared,
1630 Handle<JSFunction> function) {
1631 if (!shared->IsSubjectToDebugging()) return false;
1632
1633 // Return if we already have the debug info for shared.
1634 if (shared->HasDebugInfo()) return true;
1635
1636 if (function.is_null()) {
1637 DCHECK(shared->HasDebugCode());
1638 } else if (!Compiler::EnsureCompiled(function, CLEAR_EXCEPTION)) {
1639 return false;
1640 }
1641
1642 if (!PrepareFunctionForBreakPoints(shared)) return false;
1643
1644 // Make sure IC state is clean. This is so that we correctly flood
1645 // accessor pairs when stepping in.
1646 shared->code()->ClearInlineCaches();
1647 shared->feedback_vector()->ClearICSlots(*shared);
1648
1649 // Create the debug info object.
1650 DCHECK(shared->HasDebugCode());
1651 Handle<DebugInfo> debug_info = isolate_->factory()->NewDebugInfo(shared);
1652
1653 // Add debug info to the list.
1654 DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
1655 node->set_next(debug_info_list_);
1656 debug_info_list_ = node;
1657
1658 return true;
1659 }
1660
1661
1662 void Debug::RemoveDebugInfoAndClearFromShared(Handle<DebugInfo> debug_info) {
1663 HandleScope scope(isolate_);
1664 Handle<SharedFunctionInfo> shared(debug_info->shared());
1665
1666 DCHECK_NOT_NULL(debug_info_list_);
1667 // Run through the debug info objects to find this one and remove it.
1668 DebugInfoListNode* prev = NULL;
1669 DebugInfoListNode* current = debug_info_list_;
1670 while (current != NULL) {
1671 if (current->debug_info().is_identical_to(debug_info)) {
1672 // Unlink from list. If prev is NULL we are looking at the first element.
1673 if (prev == NULL) {
1674 debug_info_list_ = current->next();
1675 } else {
1676 prev->set_next(current->next());
1677 }
1678 delete current;
1679 shared->set_debug_info(isolate_->heap()->undefined_value());
1680 return;
1681 }
1682 // Move to next in list.
1683 prev = current;
1684 current = current->next();
1685 }
1686
1687 UNREACHABLE();
1688 }
1689
1690
1691 void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
1692 after_break_target_ = NULL;
1693
1694 if (LiveEdit::SetAfterBreakTarget(this)) return; // LiveEdit did the job.
1695
1696 // Continue just after the slot.
1697 after_break_target_ = frame->pc();
1698 }
1699
1700
1701 bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
1702 HandleScope scope(isolate_);
1703
1704 // Get the executing function in which the debug break occurred.
1705 Handle<JSFunction> function(JSFunction::cast(frame->function()));
1706 Handle<SharedFunctionInfo> shared(function->shared());
1707
1708 // With no debug info there are no break points, so we can't be at a return.
1709 if (!shared->HasDebugInfo()) return false;
1710 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
1711 Handle<Code> code(debug_info->code());
1712 #ifdef DEBUG
1713 // Get the code which is actually executing.
1714 Handle<Code> frame_code(frame->LookupCode());
1715 DCHECK(frame_code.is_identical_to(code));
1716 #endif
1717
1718 // Find the reloc info matching the start of the debug break slot.
1719 Address slot_pc = frame->pc() - Assembler::kDebugBreakSlotLength;
1720 int mask = RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN);
1721 for (RelocIterator it(*code, mask); !it.done(); it.next()) {
1722 if (it.rinfo()->pc() == slot_pc) return true;
1723 }
1724 return false;
1725 }
1726
1727
1728 void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
1729 LiveEdit::FrameDropMode mode,
1730 Object** restarter_frame_function_pointer) {
1731 if (mode != LiveEdit::CURRENTLY_SET_MODE) {
1732 thread_local_.frame_drop_mode_ = mode;
1733 }
1734 thread_local_.break_frame_id_ = new_break_frame_id;
1735 thread_local_.restarter_frame_function_pointer_ =
1736 restarter_frame_function_pointer;
1737 }
1738
1739
1740 bool Debug::IsDebugGlobal(GlobalObject* global) {
1741 return is_loaded() && global == debug_context()->global_object();
1742 }
1743
1744
1745 void Debug::ClearMirrorCache() {
1746 PostponeInterruptsScope postpone(isolate_);
1747 HandleScope scope(isolate_);
1748 AssertDebugContext();
1749 Factory* factory = isolate_->factory();
1750 Handle<GlobalObject> global(isolate_->global_object());
1751 JSObject::SetProperty(global,
1752 factory->NewStringFromAsciiChecked("next_handle_"),
1753 handle(Smi::FromInt(0), isolate_), SLOPPY).Check();
1754 JSObject::SetProperty(global,
1755 factory->NewStringFromAsciiChecked("mirror_cache_"),
1756 factory->NewJSArray(0, FAST_ELEMENTS), SLOPPY).Check();
1757 }
1758
1759
1760 Handle<FixedArray> Debug::GetLoadedScripts() {
1761 // Create and fill the script cache when the loaded scripts is requested for
1762 // the first time.
1763 if (script_cache_ == NULL) script_cache_ = new ScriptCache(isolate_);
1764
1765 // Perform GC to get unreferenced scripts evicted from the cache before
1766 // returning the content.
1767 isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags,
1768 "Debug::GetLoadedScripts");
1769
1770 // Get the scripts from the cache.
1771 return script_cache_->GetScripts();
1772 }
1773
1774
1775 void Debug::GetStepinPositions(JavaScriptFrame* frame, StackFrame::Id frame_id,
1776 List<int>* results_out) {
1777 FrameSummary summary = GetFirstFrameSummary(frame);
1778
1779 Handle<JSFunction> fun = Handle<JSFunction>(summary.function());
1780 Handle<SharedFunctionInfo> shared = Handle<SharedFunctionInfo>(fun->shared());
1781
1782 if (!EnsureDebugInfo(shared, fun)) return;
1783
1784 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
1785 // Refresh frame summary if the code has been recompiled for debugging.
1786 if (shared->code() != *summary.code()) summary = GetFirstFrameSummary(frame);
1787
1788 // Find range of break points starting from the break point where execution
1789 // has stopped.
1790 Address call_pc = summary.pc() - 1;
1791 List<BreakLocation> locations;
1792 BreakLocation::FromAddressSameStatement(debug_info, ALL_BREAK_LOCATIONS,
1793 call_pc, &locations);
1794
1795 for (BreakLocation location : locations) {
1796 if (location.pc() <= summary.pc()) {
1797 // The break point is near our pc. Could be a step-in possibility,
1798 // that is currently taken by active debugger call.
1799 if (break_frame_id() == StackFrame::NO_ID) {
1800 continue; // We are not stepping.
1801 } else {
1802 JavaScriptFrameIterator frame_it(isolate_, break_frame_id());
1803 // If our frame is a top frame and we are stepping, we can do step-in
1804 // at this place.
1805 if (frame_it.frame()->id() != frame_id) continue;
1806 }
1807 }
1808 if (location.IsStepInLocation()) results_out->Add(location.position());
1809 }
1810 }
1811
1812
1813 void Debug::RecordEvalCaller(Handle<Script> script) {
1814 script->set_compilation_type(Script::COMPILATION_TYPE_EVAL);
1815 // For eval scripts add information on the function from which eval was
1816 // called.
1817 StackTraceFrameIterator it(script->GetIsolate());
1818 if (!it.done()) {
1819 script->set_eval_from_shared(it.frame()->function()->shared());
1820 Code* code = it.frame()->LookupCode();
1821 int offset = static_cast<int>(
1822 it.frame()->pc() - code->instruction_start());
1823 script->set_eval_from_instructions_offset(Smi::FromInt(offset));
1824 }
1825 }
1826
1827
1828 MaybeHandle<Object> Debug::MakeJSObject(const char* constructor_name,
1829 int argc,
1830 Handle<Object> argv[]) {
1831 AssertDebugContext();
1832 // Create the execution state object.
1833 Handle<GlobalObject> global(isolate_->global_object());
1834 Handle<Object> constructor = Object::GetProperty(
1835 isolate_, global, constructor_name).ToHandleChecked();
1836 DCHECK(constructor->IsJSFunction());
1837 if (!constructor->IsJSFunction()) return MaybeHandle<Object>();
1838 // We do not handle interrupts here. In particular, termination interrupts.
1839 PostponeInterruptsScope no_interrupts(isolate_);
1840 return Execution::TryCall(Handle<JSFunction>::cast(constructor),
1841 handle(debug_context()->global_proxy()),
1842 argc,
1843 argv);
1844 }
1845
1846
1847 MaybeHandle<Object> Debug::MakeExecutionState() {
1848 // Create the execution state object.
1849 Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()) };
1850 return MakeJSObject("MakeExecutionState", arraysize(argv), argv);
1851 }
1852
1853
1854 MaybeHandle<Object> Debug::MakeBreakEvent(Handle<Object> break_points_hit) {
1855 // Create the new break event object.
1856 Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()),
1857 break_points_hit };
1858 return MakeJSObject("MakeBreakEvent", arraysize(argv), argv);
1859 }
1860
1861
1862 MaybeHandle<Object> Debug::MakeExceptionEvent(Handle<Object> exception,
1863 bool uncaught,
1864 Handle<Object> promise) {
1865 // Create the new exception event object.
1866 Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()),
1867 exception,
1868 isolate_->factory()->ToBoolean(uncaught),
1869 promise };
1870 return MakeJSObject("MakeExceptionEvent", arraysize(argv), argv);
1871 }
1872
1873
1874 MaybeHandle<Object> Debug::MakeCompileEvent(Handle<Script> script,
1875 v8::DebugEvent type) {
1876 // Create the compile event object.
1877 Handle<Object> script_wrapper = Script::GetWrapper(script);
1878 Handle<Object> argv[] = { script_wrapper,
1879 isolate_->factory()->NewNumberFromInt(type) };
1880 return MakeJSObject("MakeCompileEvent", arraysize(argv), argv);
1881 }
1882
1883
1884 MaybeHandle<Object> Debug::MakePromiseEvent(Handle<JSObject> event_data) {
1885 // Create the promise event object.
1886 Handle<Object> argv[] = { event_data };
1887 return MakeJSObject("MakePromiseEvent", arraysize(argv), argv);
1888 }
1889
1890
1891 MaybeHandle<Object> Debug::MakeAsyncTaskEvent(Handle<JSObject> task_event) {
1892 // Create the async task event object.
1893 Handle<Object> argv[] = { task_event };
1894 return MakeJSObject("MakeAsyncTaskEvent", arraysize(argv), argv);
1895 }
1896
1897
1898 void Debug::OnThrow(Handle<Object> exception) {
1899 if (in_debug_scope() || ignore_events()) return;
1900 // Temporarily clear any scheduled_exception to allow evaluating
1901 // JavaScript from the debug event handler.
1902 HandleScope scope(isolate_);
1903 Handle<Object> scheduled_exception;
1904 if (isolate_->has_scheduled_exception()) {
1905 scheduled_exception = handle(isolate_->scheduled_exception(), isolate_);
1906 isolate_->clear_scheduled_exception();
1907 }
1908 OnException(exception, isolate_->GetPromiseOnStackOnThrow());
1909 if (!scheduled_exception.is_null()) {
1910 isolate_->thread_local_top()->scheduled_exception_ = *scheduled_exception;
1911 }
1912 }
1913
1914
1915 void Debug::OnPromiseReject(Handle<JSObject> promise, Handle<Object> value) {
1916 if (in_debug_scope() || ignore_events()) return;
1917 HandleScope scope(isolate_);
1918 // Check whether the promise has been marked as having triggered a message.
1919 Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol();
1920 if (JSReceiver::GetDataProperty(promise, key)->IsUndefined()) {
1921 OnException(value, promise);
1922 }
1923 }
1924
1925
1926 MaybeHandle<Object> Debug::PromiseHasUserDefinedRejectHandler(
1927 Handle<JSObject> promise) {
1928 Handle<JSFunction> fun = Handle<JSFunction>::cast(
1929 JSReceiver::GetDataProperty(isolate_->js_builtins_object(),
1930 isolate_->factory()->NewStringFromStaticChars(
1931 "$promiseHasUserDefinedRejectHandler")));
1932 return Execution::Call(isolate_, fun, promise, 0, NULL);
1933 }
1934
1935
1936 void Debug::OnException(Handle<Object> exception, Handle<Object> promise) {
1937 // In our prediction, try-finally is not considered to catch.
1938 Isolate::CatchType catch_type = isolate_->PredictExceptionCatcher();
1939 bool uncaught = (catch_type == Isolate::NOT_CAUGHT);
1940 if (promise->IsJSObject()) {
1941 Handle<JSObject> jspromise = Handle<JSObject>::cast(promise);
1942 // Mark the promise as already having triggered a message.
1943 Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol();
1944 JSObject::SetProperty(jspromise, key, key, STRICT).Assert();
1945 // Check whether the promise reject is considered an uncaught exception.
1946 Handle<Object> has_reject_handler;
1947 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
1948 isolate_, has_reject_handler,
1949 PromiseHasUserDefinedRejectHandler(jspromise), /* void */);
1950 uncaught = has_reject_handler->IsFalse();
1951 }
1952 // Bail out if exception breaks are not active
1953 if (uncaught) {
1954 // Uncaught exceptions are reported by either flags.
1955 if (!(break_on_uncaught_exception_ || break_on_exception_)) return;
1956 } else {
1957 // Caught exceptions are reported is activated.
1958 if (!break_on_exception_) return;
1959 }
1960
1961 DebugScope debug_scope(this);
1962 if (debug_scope.failed()) return;
1963
1964 // Clear all current stepping setup.
1965 ClearStepping();
1966
1967 // Create the event data object.
1968 Handle<Object> event_data;
1969 // Bail out and don't call debugger if exception.
1970 if (!MakeExceptionEvent(
1971 exception, uncaught, promise).ToHandle(&event_data)) {
1972 return;
1973 }
1974
1975 // Process debug event.
1976 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false);
1977 // Return to continue execution from where the exception was thrown.
1978 }
1979
1980
1981 void Debug::OnCompileError(Handle<Script> script) {
1982 if (ignore_events()) return;
1983
1984 if (in_debug_scope()) {
1985 ProcessCompileEventInDebugScope(v8::CompileError, script);
1986 return;
1987 }
1988
1989 HandleScope scope(isolate_);
1990 DebugScope debug_scope(this);
1991 if (debug_scope.failed()) return;
1992
1993 // Create the compile state object.
1994 Handle<Object> event_data;
1995 // Bail out and don't call debugger if exception.
1996 if (!MakeCompileEvent(script, v8::CompileError).ToHandle(&event_data)) return;
1997
1998 // Process debug event.
1999 ProcessDebugEvent(v8::CompileError, Handle<JSObject>::cast(event_data), true);
2000 }
2001
2002
2003 void Debug::OnDebugBreak(Handle<Object> break_points_hit,
2004 bool auto_continue) {
2005 // The caller provided for DebugScope.
2006 AssertDebugContext();
2007 // Bail out if there is no listener for this event
2008 if (ignore_events()) return;
2009
2010 HandleScope scope(isolate_);
2011 // Create the event data object.
2012 Handle<Object> event_data;
2013 // Bail out and don't call debugger if exception.
2014 if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return;
2015
2016 // Process debug event.
2017 ProcessDebugEvent(v8::Break,
2018 Handle<JSObject>::cast(event_data),
2019 auto_continue);
2020 }
2021
2022
2023 void Debug::OnBeforeCompile(Handle<Script> script) {
2024 if (in_debug_scope() || ignore_events()) return;
2025
2026 HandleScope scope(isolate_);
2027 DebugScope debug_scope(this);
2028 if (debug_scope.failed()) return;
2029
2030 // Create the event data object.
2031 Handle<Object> event_data;
2032 // Bail out and don't call debugger if exception.
2033 if (!MakeCompileEvent(script, v8::BeforeCompile).ToHandle(&event_data))
2034 return;
2035
2036 // Process debug event.
2037 ProcessDebugEvent(v8::BeforeCompile,
2038 Handle<JSObject>::cast(event_data),
2039 true);
2040 }
2041
2042
2043 // Handle debugger actions when a new script is compiled.
2044 void Debug::OnAfterCompile(Handle<Script> script) {
2045 // Add the newly compiled script to the script cache.
2046 if (script_cache_ != NULL) script_cache_->Add(script);
2047
2048 if (ignore_events()) return;
2049
2050 if (in_debug_scope()) {
2051 ProcessCompileEventInDebugScope(v8::AfterCompile, script);
2052 return;
2053 }
2054
2055 HandleScope scope(isolate_);
2056 DebugScope debug_scope(this);
2057 if (debug_scope.failed()) return;
2058
2059 // If debugging there might be script break points registered for this
2060 // script. Make sure that these break points are set.
2061
2062 // Get the function UpdateScriptBreakPoints (defined in debug-debugger.js).
2063 Handle<String> update_script_break_points_string =
2064 isolate_->factory()->InternalizeOneByteString(
2065 STATIC_CHAR_VECTOR("UpdateScriptBreakPoints"));
2066 Handle<GlobalObject> debug_global(debug_context()->global_object());
2067 Handle<Object> update_script_break_points =
2068 Object::GetProperty(
2069 debug_global, update_script_break_points_string).ToHandleChecked();
2070 if (!update_script_break_points->IsJSFunction()) {
2071 return;
2072 }
2073 DCHECK(update_script_break_points->IsJSFunction());
2074
2075 // Wrap the script object in a proper JS object before passing it
2076 // to JavaScript.
2077 Handle<Object> wrapper = Script::GetWrapper(script);
2078
2079 // Call UpdateScriptBreakPoints expect no exceptions.
2080 Handle<Object> argv[] = { wrapper };
2081 if (Execution::TryCall(Handle<JSFunction>::cast(update_script_break_points),
2082 isolate_->js_builtins_object(),
2083 arraysize(argv),
2084 argv).is_null()) {
2085 return;
2086 }
2087
2088 // Create the compile state object.
2089 Handle<Object> event_data;
2090 // Bail out and don't call debugger if exception.
2091 if (!MakeCompileEvent(script, v8::AfterCompile).ToHandle(&event_data)) return;
2092
2093 // Process debug event.
2094 ProcessDebugEvent(v8::AfterCompile, Handle<JSObject>::cast(event_data), true);
2095 }
2096
2097
2098 void Debug::OnPromiseEvent(Handle<JSObject> data) {
2099 if (in_debug_scope() || ignore_events()) return;
2100
2101 HandleScope scope(isolate_);
2102 DebugScope debug_scope(this);
2103 if (debug_scope.failed()) return;
2104
2105 // Create the script collected state object.
2106 Handle<Object> event_data;
2107 // Bail out and don't call debugger if exception.
2108 if (!MakePromiseEvent(data).ToHandle(&event_data)) return;
2109
2110 // Process debug event.
2111 ProcessDebugEvent(v8::PromiseEvent,
2112 Handle<JSObject>::cast(event_data),
2113 true);
2114 }
2115
2116
2117 void Debug::OnAsyncTaskEvent(Handle<JSObject> data) {
2118 if (in_debug_scope() || ignore_events()) return;
2119
2120 HandleScope scope(isolate_);
2121 DebugScope debug_scope(this);
2122 if (debug_scope.failed()) return;
2123
2124 // Create the script collected state object.
2125 Handle<Object> event_data;
2126 // Bail out and don't call debugger if exception.
2127 if (!MakeAsyncTaskEvent(data).ToHandle(&event_data)) return;
2128
2129 // Process debug event.
2130 ProcessDebugEvent(v8::AsyncTaskEvent,
2131 Handle<JSObject>::cast(event_data),
2132 true);
2133 }
2134
2135
2136 void Debug::ProcessDebugEvent(v8::DebugEvent event,
2137 Handle<JSObject> event_data,
2138 bool auto_continue) {
2139 HandleScope scope(isolate_);
2140
2141 // Create the execution state.
2142 Handle<Object> exec_state;
2143 // Bail out and don't call debugger if exception.
2144 if (!MakeExecutionState().ToHandle(&exec_state)) return;
2145
2146 // First notify the message handler if any.
2147 if (message_handler_ != NULL) {
2148 NotifyMessageHandler(event,
2149 Handle<JSObject>::cast(exec_state),
2150 event_data,
2151 auto_continue);
2152 }
2153 // Notify registered debug event listener. This can be either a C or
2154 // a JavaScript function. Don't call event listener for v8::Break
2155 // here, if it's only a debug command -- they will be processed later.
2156 if ((event != v8::Break || !auto_continue) && !event_listener_.is_null()) {
2157 CallEventCallback(event, exec_state, event_data, NULL);
2158 }
2159 }
2160
2161
2162 void Debug::CallEventCallback(v8::DebugEvent event,
2163 Handle<Object> exec_state,
2164 Handle<Object> event_data,
2165 v8::Debug::ClientData* client_data) {
2166 bool previous = in_debug_event_listener_;
2167 in_debug_event_listener_ = true;
2168 if (event_listener_->IsForeign()) {
2169 // Invoke the C debug event listener.
2170 v8::Debug::EventCallback callback =
2171 FUNCTION_CAST<v8::Debug::EventCallback>(
2172 Handle<Foreign>::cast(event_listener_)->foreign_address());
2173 EventDetailsImpl event_details(event,
2174 Handle<JSObject>::cast(exec_state),
2175 Handle<JSObject>::cast(event_data),
2176 event_listener_data_,
2177 client_data);
2178 callback(event_details);
2179 DCHECK(!isolate_->has_scheduled_exception());
2180 } else {
2181 // Invoke the JavaScript debug event listener.
2182 DCHECK(event_listener_->IsJSFunction());
2183 Handle<Object> argv[] = { Handle<Object>(Smi::FromInt(event), isolate_),
2184 exec_state,
2185 event_data,
2186 event_listener_data_ };
2187 Handle<JSReceiver> global(isolate_->global_proxy());
2188 Execution::TryCall(Handle<JSFunction>::cast(event_listener_),
2189 global, arraysize(argv), argv);
2190 }
2191 in_debug_event_listener_ = previous;
2192 }
2193
2194
2195 void Debug::ProcessCompileEventInDebugScope(v8::DebugEvent event,
2196 Handle<Script> script) {
2197 if (event_listener_.is_null()) return;
2198
2199 SuppressDebug while_processing(this);
2200 DebugScope debug_scope(this);
2201 if (debug_scope.failed()) return;
2202
2203 Handle<Object> event_data;
2204 // Bail out and don't call debugger if exception.
2205 if (!MakeCompileEvent(script, event).ToHandle(&event_data)) return;
2206
2207 // Create the execution state.
2208 Handle<Object> exec_state;
2209 // Bail out and don't call debugger if exception.
2210 if (!MakeExecutionState().ToHandle(&exec_state)) return;
2211
2212 CallEventCallback(event, exec_state, event_data, NULL);
2213 }
2214
2215
2216 Handle<Context> Debug::GetDebugContext() {
2217 if (!is_loaded()) return Handle<Context>();
2218 DebugScope debug_scope(this);
2219 if (debug_scope.failed()) return Handle<Context>();
2220 // The global handle may be destroyed soon after. Return it reboxed.
2221 return handle(*debug_context(), isolate_);
2222 }
2223
2224
2225 void Debug::NotifyMessageHandler(v8::DebugEvent event,
2226 Handle<JSObject> exec_state,
2227 Handle<JSObject> event_data,
2228 bool auto_continue) {
2229 // Prevent other interrupts from triggering, for example API callbacks,
2230 // while dispatching message handler callbacks.
2231 PostponeInterruptsScope no_interrupts(isolate_);
2232 DCHECK(is_active_);
2233 HandleScope scope(isolate_);
2234 // Process the individual events.
2235 bool sendEventMessage = false;
2236 switch (event) {
2237 case v8::Break:
2238 sendEventMessage = !auto_continue;
2239 break;
2240 case v8::NewFunction:
2241 case v8::BeforeCompile:
2242 case v8::CompileError:
2243 case v8::PromiseEvent:
2244 case v8::AsyncTaskEvent:
2245 break;
2246 case v8::Exception:
2247 case v8::AfterCompile:
2248 sendEventMessage = true;
2249 break;
2250 }
2251
2252 // The debug command interrupt flag might have been set when the command was
2253 // added. It should be enough to clear the flag only once while we are in the
2254 // debugger.
2255 DCHECK(in_debug_scope());
2256 isolate_->stack_guard()->ClearDebugCommand();
2257
2258 // Notify the debugger that a debug event has occurred unless auto continue is
2259 // active in which case no event is send.
2260 if (sendEventMessage) {
2261 MessageImpl message = MessageImpl::NewEvent(
2262 event,
2263 auto_continue,
2264 Handle<JSObject>::cast(exec_state),
2265 Handle<JSObject>::cast(event_data));
2266 InvokeMessageHandler(message);
2267 }
2268
2269 // If auto continue don't make the event cause a break, but process messages
2270 // in the queue if any. For script collected events don't even process
2271 // messages in the queue as the execution state might not be what is expected
2272 // by the client.
2273 if (auto_continue && !has_commands()) return;
2274
2275 // DebugCommandProcessor goes here.
2276 bool running = auto_continue;
2277
2278 Handle<Object> cmd_processor_ctor = Object::GetProperty(
2279 isolate_, exec_state, "debugCommandProcessor").ToHandleChecked();
2280 Handle<Object> ctor_args[] = { isolate_->factory()->ToBoolean(running) };
2281 Handle<Object> cmd_processor = Execution::Call(
2282 isolate_, cmd_processor_ctor, exec_state, 1, ctor_args).ToHandleChecked();
2283 Handle<JSFunction> process_debug_request = Handle<JSFunction>::cast(
2284 Object::GetProperty(
2285 isolate_, cmd_processor, "processDebugRequest").ToHandleChecked());
2286 Handle<Object> is_running = Object::GetProperty(
2287 isolate_, cmd_processor, "isRunning").ToHandleChecked();
2288
2289 // Process requests from the debugger.
2290 do {
2291 // Wait for new command in the queue.
2292 command_received_.Wait();
2293
2294 // Get the command from the queue.
2295 CommandMessage command = command_queue_.Get();
2296 isolate_->logger()->DebugTag(
2297 "Got request from command queue, in interactive loop.");
2298 if (!is_active()) {
2299 // Delete command text and user data.
2300 command.Dispose();
2301 return;
2302 }
2303
2304 Vector<const uc16> command_text(
2305 const_cast<const uc16*>(command.text().start()),
2306 command.text().length());
2307 Handle<String> request_text = isolate_->factory()->NewStringFromTwoByte(
2308 command_text).ToHandleChecked();
2309 Handle<Object> request_args[] = { request_text };
2310 Handle<Object> answer_value;
2311 Handle<String> answer;
2312 MaybeHandle<Object> maybe_exception;
2313 MaybeHandle<Object> maybe_result =
2314 Execution::TryCall(process_debug_request, cmd_processor, 1,
2315 request_args, &maybe_exception);
2316
2317 if (maybe_result.ToHandle(&answer_value)) {
2318 if (answer_value->IsUndefined()) {
2319 answer = isolate_->factory()->empty_string();
2320 } else {
2321 answer = Handle<String>::cast(answer_value);
2322 }
2323
2324 // Log the JSON request/response.
2325 if (FLAG_trace_debug_json) {
2326 PrintF("%s\n", request_text->ToCString().get());
2327 PrintF("%s\n", answer->ToCString().get());
2328 }
2329
2330 Handle<Object> is_running_args[] = { answer };
2331 maybe_result = Execution::Call(
2332 isolate_, is_running, cmd_processor, 1, is_running_args);
2333 Handle<Object> result;
2334 if (!maybe_result.ToHandle(&result)) break;
2335 running = result->IsTrue();
2336 } else {
2337 Handle<Object> exception;
2338 if (!maybe_exception.ToHandle(&exception)) break;
2339 Handle<Object> result;
2340 if (!Execution::ToString(isolate_, exception).ToHandle(&result)) break;
2341 answer = Handle<String>::cast(result);
2342 }
2343
2344 // Return the result.
2345 MessageImpl message = MessageImpl::NewResponse(
2346 event, running, exec_state, event_data, answer, command.client_data());
2347 InvokeMessageHandler(message);
2348 command.Dispose();
2349
2350 // Return from debug event processing if either the VM is put into the
2351 // running state (through a continue command) or auto continue is active
2352 // and there are no more commands queued.
2353 } while (!running || has_commands());
2354 command_queue_.Clear();
2355 }
2356
2357
2358 void Debug::SetEventListener(Handle<Object> callback,
2359 Handle<Object> data) {
2360 GlobalHandles* global_handles = isolate_->global_handles();
2361
2362 // Remove existing entry.
2363 GlobalHandles::Destroy(event_listener_.location());
2364 event_listener_ = Handle<Object>();
2365 GlobalHandles::Destroy(event_listener_data_.location());
2366 event_listener_data_ = Handle<Object>();
2367
2368 // Set new entry.
2369 if (!callback->IsUndefined() && !callback->IsNull()) {
2370 event_listener_ = global_handles->Create(*callback);
2371 if (data.is_null()) data = isolate_->factory()->undefined_value();
2372 event_listener_data_ = global_handles->Create(*data);
2373 }
2374
2375 UpdateState();
2376 }
2377
2378
2379 void Debug::SetMessageHandler(v8::Debug::MessageHandler handler) {
2380 message_handler_ = handler;
2381 UpdateState();
2382 if (handler == NULL && in_debug_scope()) {
2383 // Send an empty command to the debugger if in a break to make JavaScript
2384 // run again if the debugger is closed.
2385 EnqueueCommandMessage(Vector<const uint16_t>::empty());
2386 }
2387 }
2388
2389
2390
2391 void Debug::UpdateState() {
2392 bool is_active = message_handler_ != NULL || !event_listener_.is_null();
2393 if (is_active || in_debug_scope()) {
2394 // Note that the debug context could have already been loaded to
2395 // bootstrap test cases.
2396 isolate_->compilation_cache()->Disable();
2397 is_active = Load();
2398 } else if (is_loaded()) {
2399 isolate_->compilation_cache()->Enable();
2400 Unload();
2401 }
2402 is_active_ = is_active;
2403 }
2404
2405
2406 // Calls the registered debug message handler. This callback is part of the
2407 // public API.
2408 void Debug::InvokeMessageHandler(MessageImpl message) {
2409 if (message_handler_ != NULL) message_handler_(message);
2410 }
2411
2412
2413 // Puts a command coming from the public API on the queue. Creates
2414 // a copy of the command string managed by the debugger. Up to this
2415 // point, the command data was managed by the API client. Called
2416 // by the API client thread.
2417 void Debug::EnqueueCommandMessage(Vector<const uint16_t> command,
2418 v8::Debug::ClientData* client_data) {
2419 // Need to cast away const.
2420 CommandMessage message = CommandMessage::New(
2421 Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
2422 command.length()),
2423 client_data);
2424 isolate_->logger()->DebugTag("Put command on command_queue.");
2425 command_queue_.Put(message);
2426 command_received_.Signal();
2427
2428 // Set the debug command break flag to have the command processed.
2429 if (!in_debug_scope()) isolate_->stack_guard()->RequestDebugCommand();
2430 }
2431
2432
2433 MaybeHandle<Object> Debug::Call(Handle<JSFunction> fun, Handle<Object> data) {
2434 DebugScope debug_scope(this);
2435 if (debug_scope.failed()) return isolate_->factory()->undefined_value();
2436
2437 // Create the execution state.
2438 Handle<Object> exec_state;
2439 if (!MakeExecutionState().ToHandle(&exec_state)) {
2440 return isolate_->factory()->undefined_value();
2441 }
2442
2443 Handle<Object> argv[] = { exec_state, data };
2444 return Execution::Call(
2445 isolate_,
2446 fun,
2447 Handle<Object>(debug_context()->global_proxy(), isolate_),
2448 arraysize(argv),
2449 argv);
2450 }
2451
2452
2453 void Debug::HandleDebugBreak() {
2454 // Ignore debug break during bootstrapping.
2455 if (isolate_->bootstrapper()->IsActive()) return;
2456 // Just continue if breaks are disabled.
2457 if (break_disabled()) return;
2458 // Ignore debug break if debugger is not active.
2459 if (!is_active()) return;
2460
2461 StackLimitCheck check(isolate_);
2462 if (check.HasOverflowed()) return;
2463
2464 { JavaScriptFrameIterator it(isolate_);
2465 DCHECK(!it.done());
2466 Object* fun = it.frame()->function();
2467 if (fun && fun->IsJSFunction()) {
2468 // Don't stop in builtin functions.
2469 if (JSFunction::cast(fun)->IsBuiltin()) return;
2470 GlobalObject* global = JSFunction::cast(fun)->context()->global_object();
2471 // Don't stop in debugger functions.
2472 if (IsDebugGlobal(global)) return;
2473 }
2474 }
2475
2476 // Collect the break state before clearing the flags.
2477 bool debug_command_only = isolate_->stack_guard()->CheckDebugCommand() &&
2478 !isolate_->stack_guard()->CheckDebugBreak();
2479
2480 isolate_->stack_guard()->ClearDebugBreak();
2481
2482 ProcessDebugMessages(debug_command_only);
2483 }
2484
2485
2486 void Debug::ProcessDebugMessages(bool debug_command_only) {
2487 isolate_->stack_guard()->ClearDebugCommand();
2488
2489 StackLimitCheck check(isolate_);
2490 if (check.HasOverflowed()) return;
2491
2492 HandleScope scope(isolate_);
2493 DebugScope debug_scope(this);
2494 if (debug_scope.failed()) return;
2495
2496 // Notify the debug event listeners. Indicate auto continue if the break was
2497 // a debug command break.
2498 OnDebugBreak(isolate_->factory()->undefined_value(), debug_command_only);
2499 }
2500
2501
2502 DebugScope::DebugScope(Debug* debug)
2503 : debug_(debug),
2504 prev_(debug->debugger_entry()),
2505 save_(debug_->isolate_),
2506 no_termination_exceptons_(debug_->isolate_,
2507 StackGuard::TERMINATE_EXECUTION) {
2508 // Link recursive debugger entry.
2509 base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_,
2510 reinterpret_cast<base::AtomicWord>(this));
2511
2512 // Store the previous break id and frame id.
2513 break_id_ = debug_->break_id();
2514 break_frame_id_ = debug_->break_frame_id();
2515
2516 // Create the new break info. If there is no JavaScript frames there is no
2517 // break frame id.
2518 JavaScriptFrameIterator it(isolate());
2519 bool has_js_frames = !it.done();
2520 debug_->thread_local_.break_frame_id_ = has_js_frames ? it.frame()->id()
2521 : StackFrame::NO_ID;
2522 debug_->SetNextBreakId();
2523
2524 debug_->UpdateState();
2525 // Make sure that debugger is loaded and enter the debugger context.
2526 // The previous context is kept in save_.
2527 failed_ = !debug_->is_loaded();
2528 if (!failed_) isolate()->set_context(*debug->debug_context());
2529 }
2530
2531
2532
2533 DebugScope::~DebugScope() {
2534 if (!failed_ && prev_ == NULL) {
2535 // Clear mirror cache when leaving the debugger. Skip this if there is a
2536 // pending exception as clearing the mirror cache calls back into
2537 // JavaScript. This can happen if the v8::Debug::Call is used in which
2538 // case the exception should end up in the calling code.
2539 if (!isolate()->has_pending_exception()) debug_->ClearMirrorCache();
2540
2541 // If there are commands in the queue when leaving the debugger request
2542 // that these commands are processed.
2543 if (debug_->has_commands()) isolate()->stack_guard()->RequestDebugCommand();
2544 }
2545
2546 // Leaving this debugger entry.
2547 base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_,
2548 reinterpret_cast<base::AtomicWord>(prev_));
2549
2550 // Restore to the previous break state.
2551 debug_->thread_local_.break_frame_id_ = break_frame_id_;
2552 debug_->thread_local_.break_id_ = break_id_;
2553
2554 debug_->UpdateState();
2555 }
2556
2557
2558 MessageImpl MessageImpl::NewEvent(DebugEvent event,
2559 bool running,
2560 Handle<JSObject> exec_state,
2561 Handle<JSObject> event_data) {
2562 MessageImpl message(true, event, running,
2563 exec_state, event_data, Handle<String>(), NULL);
2564 return message;
2565 }
2566
2567
2568 MessageImpl MessageImpl::NewResponse(DebugEvent event,
2569 bool running,
2570 Handle<JSObject> exec_state,
2571 Handle<JSObject> event_data,
2572 Handle<String> response_json,
2573 v8::Debug::ClientData* client_data) {
2574 MessageImpl message(false, event, running,
2575 exec_state, event_data, response_json, client_data);
2576 return message;
2577 }
2578
2579
2580 MessageImpl::MessageImpl(bool is_event,
2581 DebugEvent event,
2582 bool running,
2583 Handle<JSObject> exec_state,
2584 Handle<JSObject> event_data,
2585 Handle<String> response_json,
2586 v8::Debug::ClientData* client_data)
2587 : is_event_(is_event),
2588 event_(event),
2589 running_(running),
2590 exec_state_(exec_state),
2591 event_data_(event_data),
2592 response_json_(response_json),
2593 client_data_(client_data) {}
2594
2595
2596 bool MessageImpl::IsEvent() const {
2597 return is_event_;
2598 }
2599
2600
2601 bool MessageImpl::IsResponse() const {
2602 return !is_event_;
2603 }
2604
2605
2606 DebugEvent MessageImpl::GetEvent() const {
2607 return event_;
2608 }
2609
2610
2611 bool MessageImpl::WillStartRunning() const {
2612 return running_;
2613 }
2614
2615
2616 v8::Local<v8::Object> MessageImpl::GetExecutionState() const {
2617 return v8::Utils::ToLocal(exec_state_);
2618 }
2619
2620
2621 v8::Isolate* MessageImpl::GetIsolate() const {
2622 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate());
2623 }
2624
2625
2626 v8::Local<v8::Object> MessageImpl::GetEventData() const {
2627 return v8::Utils::ToLocal(event_data_);
2628 }
2629
2630
2631 v8::Local<v8::String> MessageImpl::GetJSON() const {
2632 Isolate* isolate = event_data_->GetIsolate();
2633 v8::EscapableHandleScope scope(reinterpret_cast<v8::Isolate*>(isolate));
2634
2635 if (IsEvent()) {
2636 // Call toJSONProtocol on the debug event object.
2637 Handle<Object> fun = Object::GetProperty(
2638 isolate, event_data_, "toJSONProtocol").ToHandleChecked();
2639 if (!fun->IsJSFunction()) {
2640 return v8::Local<v8::String>();
2641 }
2642
2643 MaybeHandle<Object> maybe_json =
2644 Execution::TryCall(Handle<JSFunction>::cast(fun), event_data_, 0, NULL);
2645 Handle<Object> json;
2646 if (!maybe_json.ToHandle(&json) || !json->IsString()) {
2647 return v8::Local<v8::String>();
2648 }
2649 return scope.Escape(v8::Utils::ToLocal(Handle<String>::cast(json)));
2650 } else {
2651 return v8::Utils::ToLocal(response_json_);
2652 }
2653 }
2654
2655
2656 v8::Local<v8::Context> MessageImpl::GetEventContext() const {
2657 Isolate* isolate = event_data_->GetIsolate();
2658 v8::Local<v8::Context> context = GetDebugEventContext(isolate);
2659 // Isolate::context() may be NULL when "script collected" event occurs.
2660 DCHECK(!context.IsEmpty());
2661 return context;
2662 }
2663
2664
2665 v8::Debug::ClientData* MessageImpl::GetClientData() const {
2666 return client_data_;
2667 }
2668
2669
2670 EventDetailsImpl::EventDetailsImpl(DebugEvent event,
2671 Handle<JSObject> exec_state,
2672 Handle<JSObject> event_data,
2673 Handle<Object> callback_data,
2674 v8::Debug::ClientData* client_data)
2675 : event_(event),
2676 exec_state_(exec_state),
2677 event_data_(event_data),
2678 callback_data_(callback_data),
2679 client_data_(client_data) {}
2680
2681
2682 DebugEvent EventDetailsImpl::GetEvent() const {
2683 return event_;
2684 }
2685
2686
2687 v8::Local<v8::Object> EventDetailsImpl::GetExecutionState() const {
2688 return v8::Utils::ToLocal(exec_state_);
2689 }
2690
2691
2692 v8::Local<v8::Object> EventDetailsImpl::GetEventData() const {
2693 return v8::Utils::ToLocal(event_data_);
2694 }
2695
2696
2697 v8::Local<v8::Context> EventDetailsImpl::GetEventContext() const {
2698 return GetDebugEventContext(exec_state_->GetIsolate());
2699 }
2700
2701
2702 v8::Local<v8::Value> EventDetailsImpl::GetCallbackData() const {
2703 return v8::Utils::ToLocal(callback_data_);
2704 }
2705
2706
2707 v8::Debug::ClientData* EventDetailsImpl::GetClientData() const {
2708 return client_data_;
2709 }
2710
2711
2712 CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()),
2713 client_data_(NULL) {
2714 }
2715
2716
2717 CommandMessage::CommandMessage(const Vector<uint16_t>& text,
2718 v8::Debug::ClientData* data)
2719 : text_(text),
2720 client_data_(data) {
2721 }
2722
2723
2724 void CommandMessage::Dispose() {
2725 text_.Dispose();
2726 delete client_data_;
2727 client_data_ = NULL;
2728 }
2729
2730
2731 CommandMessage CommandMessage::New(const Vector<uint16_t>& command,
2732 v8::Debug::ClientData* data) {
2733 return CommandMessage(command.Clone(), data);
2734 }
2735
2736
2737 CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0),
2738 size_(size) {
2739 messages_ = NewArray<CommandMessage>(size);
2740 }
2741
2742
2743 CommandMessageQueue::~CommandMessageQueue() {
2744 while (!IsEmpty()) Get().Dispose();
2745 DeleteArray(messages_);
2746 }
2747
2748
2749 CommandMessage CommandMessageQueue::Get() {
2750 DCHECK(!IsEmpty());
2751 int result = start_;
2752 start_ = (start_ + 1) % size_;
2753 return messages_[result];
2754 }
2755
2756
2757 void CommandMessageQueue::Put(const CommandMessage& message) {
2758 if ((end_ + 1) % size_ == start_) {
2759 Expand();
2760 }
2761 messages_[end_] = message;
2762 end_ = (end_ + 1) % size_;
2763 }
2764
2765
2766 void CommandMessageQueue::Expand() {
2767 CommandMessageQueue new_queue(size_ * 2);
2768 while (!IsEmpty()) {
2769 new_queue.Put(Get());
2770 }
2771 CommandMessage* array_to_free = messages_;
2772 *this = new_queue;
2773 new_queue.messages_ = array_to_free;
2774 // Make the new_queue empty so that it doesn't call Dispose on any messages.
2775 new_queue.start_ = new_queue.end_;
2776 // Automatic destructor called on new_queue, freeing array_to_free.
2777 }
2778
2779
2780 LockingCommandMessageQueue::LockingCommandMessageQueue(Logger* logger, int size)
2781 : logger_(logger), queue_(size) {}
2782
2783
2784 bool LockingCommandMessageQueue::IsEmpty() const {
2785 base::LockGuard<base::Mutex> lock_guard(&mutex_);
2786 return queue_.IsEmpty();
2787 }
2788
2789
2790 CommandMessage LockingCommandMessageQueue::Get() {
2791 base::LockGuard<base::Mutex> lock_guard(&mutex_);
2792 CommandMessage result = queue_.Get();
2793 logger_->DebugEvent("Get", result.text());
2794 return result;
2795 }
2796
2797
2798 void LockingCommandMessageQueue::Put(const CommandMessage& message) {
2799 base::LockGuard<base::Mutex> lock_guard(&mutex_);
2800 queue_.Put(message);
2801 logger_->DebugEvent("Put", message.text());
2802 }
2803
2804
2805 void LockingCommandMessageQueue::Clear() {
2806 base::LockGuard<base::Mutex> lock_guard(&mutex_);
2807 queue_.Clear();
2808 }
2809
2810 } // namespace internal
2811 } // namespace v8
OLDNEW
« no previous file with comments | « src/debug.h ('k') | src/debug-debugger.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698