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.h"
18 #include "src/global-handles.h"
19 #include "src/isolate-inl.h"
20 #include "src/list.h"
21 #include "src/log.h"
22 #include "src/messages.h"
23 #include "src/natives.h"
24
25 #include "include/v8-debug.h"
26
27 namespace v8 {
28 namespace internal {
29
Debug(Isolate * isolate)30 Debug::Debug(Isolate* isolate)
31 : debug_context_(Handle<Context>()),
32 event_listener_(Handle<Object>()),
33 event_listener_data_(Handle<Object>()),
34 message_handler_(NULL),
35 command_received_(0),
36 command_queue_(isolate->logger(), kQueueInitialSize),
37 event_command_queue_(isolate->logger(), kQueueInitialSize),
38 is_active_(false),
39 is_suppressed_(false),
40 live_edit_enabled_(true), // TODO(yangguo): set to false by default.
41 has_break_points_(false),
42 break_disabled_(false),
43 break_on_exception_(false),
44 break_on_uncaught_exception_(false),
45 script_cache_(NULL),
46 debug_info_list_(NULL),
47 isolate_(isolate) {
48 ThreadInit();
49 }
50
51
GetDebugEventContext(Isolate * isolate)52 static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) {
53 Handle<Context> context = isolate->debug()->debugger_entry()->GetContext();
54 // Isolate::context() may have been NULL when "script collected" event
55 // occured.
56 if (context.is_null()) return v8::Local<v8::Context>();
57 Handle<Context> native_context(context->native_context());
58 return v8::Utils::ToLocal(native_context);
59 }
60
61
BreakLocationIterator(Handle<DebugInfo> debug_info,BreakLocatorType type)62 BreakLocationIterator::BreakLocationIterator(Handle<DebugInfo> debug_info,
63 BreakLocatorType type) {
64 debug_info_ = debug_info;
65 type_ = type;
66 reloc_iterator_ = NULL;
67 reloc_iterator_original_ = NULL;
68 Reset(); // Initialize the rest of the member variables.
69 }
70
71
~BreakLocationIterator()72 BreakLocationIterator::~BreakLocationIterator() {
73 DCHECK(reloc_iterator_ != NULL);
74 DCHECK(reloc_iterator_original_ != NULL);
75 delete reloc_iterator_;
76 delete reloc_iterator_original_;
77 }
78
79
80 // Check whether a code stub with the specified major key is a possible break
81 // point location when looking for source break locations.
IsSourceBreakStub(Code * code)82 static bool IsSourceBreakStub(Code* code) {
83 CodeStub::Major major_key = CodeStub::GetMajorKey(code);
84 return major_key == CodeStub::CallFunction;
85 }
86
87
88 // Check whether a code stub with the specified major key is a possible break
89 // location.
IsBreakStub(Code * code)90 static bool IsBreakStub(Code* code) {
91 CodeStub::Major major_key = CodeStub::GetMajorKey(code);
92 return major_key == CodeStub::CallFunction;
93 }
94
95
Next()96 void BreakLocationIterator::Next() {
97 DisallowHeapAllocation no_gc;
98 DCHECK(!RinfoDone());
99
100 // Iterate through reloc info for code and original code stopping at each
101 // breakable code target.
102 bool first = break_point_ == -1;
103 while (!RinfoDone()) {
104 if (!first) RinfoNext();
105 first = false;
106 if (RinfoDone()) 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>(
118 rinfo()->data() - debug_info_->shared()->start_position());
119 DCHECK(position_ >= 0);
120 DCHECK(statement_position_ >= 0);
121 }
122
123 if (IsDebugBreakSlot()) {
124 // There is always a possible break point at a debug break slot.
125 break_point_++;
126 return;
127 } else if (RelocInfo::IsCodeTarget(rmode())) {
128 // Check for breakable code target. Look in the original code as setting
129 // break points can cause the code targets in the running (debugged) code
130 // to be of a different kind than in the original code.
131 Address target = original_rinfo()->target_address();
132 Code* code = Code::GetCodeFromTargetAddress(target);
133 if ((code->is_inline_cache_stub() &&
134 !code->is_binary_op_stub() &&
135 !code->is_compare_ic_stub() &&
136 !code->is_to_boolean_ic_stub()) ||
137 RelocInfo::IsConstructCall(rmode())) {
138 break_point_++;
139 return;
140 }
141 if (code->kind() == Code::STUB) {
142 if (IsDebuggerStatement()) {
143 break_point_++;
144 return;
145 } else if (type_ == ALL_BREAK_LOCATIONS) {
146 if (IsBreakStub(code)) {
147 break_point_++;
148 return;
149 }
150 } else {
151 DCHECK(type_ == SOURCE_BREAK_LOCATIONS);
152 if (IsSourceBreakStub(code)) {
153 break_point_++;
154 return;
155 }
156 }
157 }
158 }
159
160 // Check for break at return.
161 if (RelocInfo::IsJSReturn(rmode())) {
162 // Set the positions to the end of the function.
163 if (debug_info_->shared()->HasSourceCode()) {
164 position_ = debug_info_->shared()->end_position() -
165 debug_info_->shared()->start_position() - 1;
166 } else {
167 position_ = 0;
168 }
169 statement_position_ = position_;
170 break_point_++;
171 return;
172 }
173 }
174 }
175
176
Next(int count)177 void BreakLocationIterator::Next(int count) {
178 while (count > 0) {
179 Next();
180 count--;
181 }
182 }
183
184
185 // Find the break point at the supplied address, or the closest one before
186 // the address.
FindBreakLocationFromAddress(Address pc)187 void BreakLocationIterator::FindBreakLocationFromAddress(Address pc) {
188 // Run through all break points to locate the one closest to the address.
189 int closest_break_point = 0;
190 int distance = kMaxInt;
191 while (!Done()) {
192 // Check if this break point is closer that what was previously found.
193 if (this->pc() <= pc && pc - this->pc() < distance) {
194 closest_break_point = break_point();
195 distance = static_cast<int>(pc - this->pc());
196 // Check whether we can't get any closer.
197 if (distance == 0) break;
198 }
199 Next();
200 }
201
202 // Move to the break point found.
203 Reset();
204 Next(closest_break_point);
205 }
206
207
208 // Find the break point closest to the supplied source position.
FindBreakLocationFromPosition(int position,BreakPositionAlignment alignment)209 void BreakLocationIterator::FindBreakLocationFromPosition(int position,
210 BreakPositionAlignment alignment) {
211 // Run through all break points to locate the one closest to the source
212 // position.
213 int closest_break_point = 0;
214 int distance = kMaxInt;
215
216 while (!Done()) {
217 int next_position;
218 switch (alignment) {
219 case STATEMENT_ALIGNED:
220 next_position = this->statement_position();
221 break;
222 case BREAK_POSITION_ALIGNED:
223 next_position = this->position();
224 break;
225 default:
226 UNREACHABLE();
227 next_position = this->statement_position();
228 }
229 // Check if this break point is closer that what was previously found.
230 if (position <= next_position && next_position - position < distance) {
231 closest_break_point = break_point();
232 distance = next_position - position;
233 // Check whether we can't get any closer.
234 if (distance == 0) break;
235 }
236 Next();
237 }
238
239 // Move to the break point found.
240 Reset();
241 Next(closest_break_point);
242 }
243
244
Reset()245 void BreakLocationIterator::Reset() {
246 // Create relocation iterators for the two code objects.
247 if (reloc_iterator_ != NULL) delete reloc_iterator_;
248 if (reloc_iterator_original_ != NULL) delete reloc_iterator_original_;
249 reloc_iterator_ = new RelocIterator(
250 debug_info_->code(),
251 ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE));
252 reloc_iterator_original_ = new RelocIterator(
253 debug_info_->original_code(),
254 ~RelocInfo::ModeMask(RelocInfo::CODE_AGE_SEQUENCE));
255
256 // Position at the first break point.
257 break_point_ = -1;
258 position_ = 1;
259 statement_position_ = 1;
260 Next();
261 }
262
263
Done() const264 bool BreakLocationIterator::Done() const {
265 return RinfoDone();
266 }
267
268
SetBreakPoint(Handle<Object> break_point_object)269 void BreakLocationIterator::SetBreakPoint(Handle<Object> break_point_object) {
270 // If there is not already a real break point here patch code with debug
271 // break.
272 if (!HasBreakPoint()) SetDebugBreak();
273 DCHECK(IsDebugBreak() || IsDebuggerStatement());
274 // Set the break point information.
275 DebugInfo::SetBreakPoint(debug_info_, code_position(),
276 position(), statement_position(),
277 break_point_object);
278 }
279
280
ClearBreakPoint(Handle<Object> break_point_object)281 void BreakLocationIterator::ClearBreakPoint(Handle<Object> break_point_object) {
282 // Clear the break point information.
283 DebugInfo::ClearBreakPoint(debug_info_, code_position(), break_point_object);
284 // If there are no more break points here remove the debug break.
285 if (!HasBreakPoint()) {
286 ClearDebugBreak();
287 DCHECK(!IsDebugBreak());
288 }
289 }
290
291
SetOneShot()292 void BreakLocationIterator::SetOneShot() {
293 // Debugger statement always calls debugger. No need to modify it.
294 if (IsDebuggerStatement()) return;
295
296 // If there is a real break point here no more to do.
297 if (HasBreakPoint()) {
298 DCHECK(IsDebugBreak());
299 return;
300 }
301
302 // Patch code with debug break.
303 SetDebugBreak();
304 }
305
306
ClearOneShot()307 void BreakLocationIterator::ClearOneShot() {
308 // Debugger statement always calls debugger. No need to modify it.
309 if (IsDebuggerStatement()) return;
310
311 // If there is a real break point here no more to do.
312 if (HasBreakPoint()) {
313 DCHECK(IsDebugBreak());
314 return;
315 }
316
317 // Patch code removing debug break.
318 ClearDebugBreak();
319 DCHECK(!IsDebugBreak());
320 }
321
322
SetDebugBreak()323 void BreakLocationIterator::SetDebugBreak() {
324 // Debugger statement always calls debugger. No need to modify it.
325 if (IsDebuggerStatement()) return;
326
327 // If there is already a break point here just return. This might happen if
328 // the same code is flooded with break points twice. Flooding the same
329 // function twice might happen when stepping in a function with an exception
330 // handler as the handler and the function is the same.
331 if (IsDebugBreak()) return;
332
333 if (RelocInfo::IsJSReturn(rmode())) {
334 // Patch the frame exit code with a break point.
335 SetDebugBreakAtReturn();
336 } else if (IsDebugBreakSlot()) {
337 // Patch the code in the break slot.
338 SetDebugBreakAtSlot();
339 } else {
340 // Patch the IC call.
341 SetDebugBreakAtIC();
342 }
343 DCHECK(IsDebugBreak());
344 }
345
346
ClearDebugBreak()347 void BreakLocationIterator::ClearDebugBreak() {
348 // Debugger statement always calls debugger. No need to modify it.
349 if (IsDebuggerStatement()) return;
350
351 if (RelocInfo::IsJSReturn(rmode())) {
352 // Restore the frame exit code.
353 ClearDebugBreakAtReturn();
354 } else if (IsDebugBreakSlot()) {
355 // Restore the code in the break slot.
356 ClearDebugBreakAtSlot();
357 } else {
358 // Patch the IC call.
359 ClearDebugBreakAtIC();
360 }
361 DCHECK(!IsDebugBreak());
362 }
363
364
IsStepInLocation(Isolate * isolate)365 bool BreakLocationIterator::IsStepInLocation(Isolate* isolate) {
366 if (RelocInfo::IsConstructCall(original_rmode())) {
367 return true;
368 } else if (RelocInfo::IsCodeTarget(rmode())) {
369 HandleScope scope(debug_info_->GetIsolate());
370 Address target = original_rinfo()->target_address();
371 Handle<Code> target_code(Code::GetCodeFromTargetAddress(target));
372 if (target_code->kind() == Code::STUB) {
373 return CodeStub::GetMajorKey(*target_code) == CodeStub::CallFunction;
374 }
375 return target_code->is_call_stub();
376 }
377 return false;
378 }
379
380
PrepareStepIn(Isolate * isolate)381 void BreakLocationIterator::PrepareStepIn(Isolate* isolate) {
382 #ifdef DEBUG
383 HandleScope scope(isolate);
384 // Step in can only be prepared if currently positioned on an IC call,
385 // construct call or CallFunction stub call.
386 Address target = rinfo()->target_address();
387 Handle<Code> target_code(Code::GetCodeFromTargetAddress(target));
388 // All the following stuff is needed only for assertion checks so the code
389 // is wrapped in ifdef.
390 Handle<Code> maybe_call_function_stub = target_code;
391 if (IsDebugBreak()) {
392 Address original_target = original_rinfo()->target_address();
393 maybe_call_function_stub =
394 Handle<Code>(Code::GetCodeFromTargetAddress(original_target));
395 }
396 bool is_call_function_stub =
397 (maybe_call_function_stub->kind() == Code::STUB &&
398 CodeStub::GetMajorKey(*maybe_call_function_stub) ==
399 CodeStub::CallFunction);
400
401 // Step in through construct call requires no changes to the running code.
402 // Step in through getters/setters should already be prepared as well
403 // because caller of this function (Debug::PrepareStep) is expected to
404 // flood the top frame's function with one shot breakpoints.
405 // Step in through CallFunction stub should also be prepared by caller of
406 // this function (Debug::PrepareStep) which should flood target function
407 // with breakpoints.
408 DCHECK(RelocInfo::IsConstructCall(rmode()) ||
409 target_code->is_inline_cache_stub() ||
410 is_call_function_stub);
411 #endif
412 }
413
414
415 // Check whether the break point is at a position which will exit the function.
IsExit() const416 bool BreakLocationIterator::IsExit() const {
417 return (RelocInfo::IsJSReturn(rmode()));
418 }
419
420
HasBreakPoint()421 bool BreakLocationIterator::HasBreakPoint() {
422 return debug_info_->HasBreakPoint(code_position());
423 }
424
425
426 // Check whether there is a debug break at the current position.
IsDebugBreak()427 bool BreakLocationIterator::IsDebugBreak() {
428 if (RelocInfo::IsJSReturn(rmode())) {
429 return IsDebugBreakAtReturn();
430 } else if (IsDebugBreakSlot()) {
431 return IsDebugBreakAtSlot();
432 } else {
433 return Debug::IsDebugBreak(rinfo()->target_address());
434 }
435 }
436
437
438 // Find the builtin to use for invoking the debug break
DebugBreakForIC(Handle<Code> code,RelocInfo::Mode mode)439 static Handle<Code> DebugBreakForIC(Handle<Code> code, RelocInfo::Mode mode) {
440 Isolate* isolate = code->GetIsolate();
441
442 // Find the builtin debug break function matching the calling convention
443 // used by the call site.
444 if (code->is_inline_cache_stub()) {
445 switch (code->kind()) {
446 case Code::CALL_IC:
447 return isolate->builtins()->CallICStub_DebugBreak();
448
449 case Code::LOAD_IC:
450 return isolate->builtins()->LoadIC_DebugBreak();
451
452 case Code::STORE_IC:
453 return isolate->builtins()->StoreIC_DebugBreak();
454
455 case Code::KEYED_LOAD_IC:
456 return isolate->builtins()->KeyedLoadIC_DebugBreak();
457
458 case Code::KEYED_STORE_IC:
459 return isolate->builtins()->KeyedStoreIC_DebugBreak();
460
461 case Code::COMPARE_NIL_IC:
462 return isolate->builtins()->CompareNilIC_DebugBreak();
463
464 default:
465 UNREACHABLE();
466 }
467 }
468 if (RelocInfo::IsConstructCall(mode)) {
469 if (code->has_function_cache()) {
470 return isolate->builtins()->CallConstructStub_Recording_DebugBreak();
471 } else {
472 return isolate->builtins()->CallConstructStub_DebugBreak();
473 }
474 }
475 if (code->kind() == Code::STUB) {
476 DCHECK(CodeStub::GetMajorKey(*code) == CodeStub::CallFunction);
477 return isolate->builtins()->CallFunctionStub_DebugBreak();
478 }
479
480 UNREACHABLE();
481 return Handle<Code>::null();
482 }
483
484
SetDebugBreakAtIC()485 void BreakLocationIterator::SetDebugBreakAtIC() {
486 // Patch the original code with the current address as the current address
487 // might have changed by the inline caching since the code was copied.
488 original_rinfo()->set_target_address(rinfo()->target_address());
489
490 RelocInfo::Mode mode = rmode();
491 if (RelocInfo::IsCodeTarget(mode)) {
492 Address target = rinfo()->target_address();
493 Handle<Code> target_code(Code::GetCodeFromTargetAddress(target));
494
495 // Patch the code to invoke the builtin debug break function matching the
496 // calling convention used by the call site.
497 Handle<Code> dbgbrk_code = DebugBreakForIC(target_code, mode);
498 rinfo()->set_target_address(dbgbrk_code->entry());
499 }
500 }
501
502
ClearDebugBreakAtIC()503 void BreakLocationIterator::ClearDebugBreakAtIC() {
504 // Patch the code to the original invoke.
505 rinfo()->set_target_address(original_rinfo()->target_address());
506 }
507
508
IsDebuggerStatement()509 bool BreakLocationIterator::IsDebuggerStatement() {
510 return RelocInfo::DEBUG_BREAK == rmode();
511 }
512
513
IsDebugBreakSlot()514 bool BreakLocationIterator::IsDebugBreakSlot() {
515 return RelocInfo::DEBUG_BREAK_SLOT == rmode();
516 }
517
518
BreakPointObjects()519 Object* BreakLocationIterator::BreakPointObjects() {
520 return debug_info_->GetBreakPointObjects(code_position());
521 }
522
523
524 // Clear out all the debug break code. This is ONLY supposed to be used when
525 // shutting down the debugger as it will leave the break point information in
526 // DebugInfo even though the code is patched back to the non break point state.
ClearAllDebugBreak()527 void BreakLocationIterator::ClearAllDebugBreak() {
528 while (!Done()) {
529 ClearDebugBreak();
530 Next();
531 }
532 }
533
534
RinfoDone() const535 bool BreakLocationIterator::RinfoDone() const {
536 DCHECK(reloc_iterator_->done() == reloc_iterator_original_->done());
537 return reloc_iterator_->done();
538 }
539
540
RinfoNext()541 void BreakLocationIterator::RinfoNext() {
542 reloc_iterator_->next();
543 reloc_iterator_original_->next();
544 #ifdef DEBUG
545 DCHECK(reloc_iterator_->done() == reloc_iterator_original_->done());
546 if (!reloc_iterator_->done()) {
547 DCHECK(rmode() == original_rmode());
548 }
549 #endif
550 }
551
552
553 // Threading support.
ThreadInit()554 void Debug::ThreadInit() {
555 thread_local_.break_count_ = 0;
556 thread_local_.break_id_ = 0;
557 thread_local_.break_frame_id_ = StackFrame::NO_ID;
558 thread_local_.last_step_action_ = StepNone;
559 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
560 thread_local_.step_count_ = 0;
561 thread_local_.last_fp_ = 0;
562 thread_local_.queued_step_count_ = 0;
563 thread_local_.step_into_fp_ = 0;
564 thread_local_.step_out_fp_ = 0;
565 // TODO(isolates): frames_are_dropped_?
566 thread_local_.current_debug_scope_ = NULL;
567 thread_local_.restarter_frame_function_pointer_ = NULL;
568 }
569
570
ArchiveDebug(char * storage)571 char* Debug::ArchiveDebug(char* storage) {
572 char* to = storage;
573 MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
574 ThreadInit();
575 return storage + ArchiveSpacePerThread();
576 }
577
578
RestoreDebug(char * storage)579 char* Debug::RestoreDebug(char* storage) {
580 char* from = storage;
581 MemCopy(reinterpret_cast<char*>(&thread_local_), from, sizeof(ThreadLocal));
582 return storage + ArchiveSpacePerThread();
583 }
584
585
ArchiveSpacePerThread()586 int Debug::ArchiveSpacePerThread() {
587 return sizeof(ThreadLocal);
588 }
589
590
ScriptCache(Isolate * isolate)591 ScriptCache::ScriptCache(Isolate* isolate) : HashMap(HashMap::PointersMatch),
592 isolate_(isolate) {
593 Heap* heap = isolate_->heap();
594 HandleScope scope(isolate_);
595
596 // Perform two GCs to get rid of all unreferenced scripts. The first GC gets
597 // rid of all the cached script wrappers and the second gets rid of the
598 // scripts which are no longer referenced.
599 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "ScriptCache");
600 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, "ScriptCache");
601
602 // Scan heap for Script objects.
603 HeapIterator iterator(heap);
604 DisallowHeapAllocation no_allocation;
605
606 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
607 if (obj->IsScript() && Script::cast(obj)->HasValidSource()) {
608 Add(Handle<Script>(Script::cast(obj)));
609 }
610 }
611 }
612
613
Add(Handle<Script> script)614 void ScriptCache::Add(Handle<Script> script) {
615 GlobalHandles* global_handles = isolate_->global_handles();
616 // Create an entry in the hash map for the script.
617 int id = script->id()->value();
618 HashMap::Entry* entry =
619 HashMap::Lookup(reinterpret_cast<void*>(id), Hash(id), true);
620 if (entry->value != NULL) {
621 #ifdef DEBUG
622 // The code deserializer may introduce duplicate Script objects.
623 // Assert that the Script objects with the same id have the same name.
624 Handle<Script> found(reinterpret_cast<Script**>(entry->value));
625 DCHECK(script->id() == found->id());
626 DCHECK(!script->name()->IsString() ||
627 String::cast(script->name())->Equals(String::cast(found->name())));
628 #endif
629 return;
630 }
631 // Globalize the script object, make it weak and use the location of the
632 // global handle as the value in the hash map.
633 Handle<Script> script_ =
634 Handle<Script>::cast(global_handles->Create(*script));
635 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(script_.location()),
636 this,
637 ScriptCache::HandleWeakScript);
638 entry->value = script_.location();
639 }
640
641
GetScripts()642 Handle<FixedArray> ScriptCache::GetScripts() {
643 Factory* factory = isolate_->factory();
644 Handle<FixedArray> instances = factory->NewFixedArray(occupancy());
645 int count = 0;
646 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
647 DCHECK(entry->value != NULL);
648 if (entry->value != NULL) {
649 instances->set(count, *reinterpret_cast<Script**>(entry->value));
650 count++;
651 }
652 }
653 return instances;
654 }
655
656
Clear()657 void ScriptCache::Clear() {
658 // Iterate the script cache to get rid of all the weak handles.
659 for (HashMap::Entry* entry = Start(); entry != NULL; entry = Next(entry)) {
660 DCHECK(entry != NULL);
661 Object** location = reinterpret_cast<Object**>(entry->value);
662 DCHECK((*location)->IsScript());
663 GlobalHandles::ClearWeakness(location);
664 GlobalHandles::Destroy(location);
665 }
666 // Clear the content of the hash map.
667 HashMap::Clear();
668 }
669
670
HandleWeakScript(const v8::WeakCallbackData<v8::Value,void> & data)671 void ScriptCache::HandleWeakScript(
672 const v8::WeakCallbackData<v8::Value, void>& data) {
673 // Retrieve the script identifier.
674 Handle<Object> object = Utils::OpenHandle(*data.GetValue());
675 int id = Handle<Script>::cast(object)->id()->value();
676 void* key = reinterpret_cast<void*>(id);
677 uint32_t hash = Hash(id);
678
679 // Remove the corresponding entry from the cache.
680 ScriptCache* script_cache =
681 reinterpret_cast<ScriptCache*>(data.GetParameter());
682 HashMap::Entry* entry = script_cache->Lookup(key, hash, false);
683 Object** location = reinterpret_cast<Object**>(entry->value);
684 script_cache->Remove(key, hash);
685
686 // Clear the weak handle.
687 GlobalHandles::Destroy(location);
688 }
689
690
HandleWeakDebugInfo(const v8::WeakCallbackData<v8::Value,void> & data)691 void Debug::HandleWeakDebugInfo(
692 const v8::WeakCallbackData<v8::Value, void>& data) {
693 Debug* debug = reinterpret_cast<Isolate*>(data.GetIsolate())->debug();
694 DebugInfoListNode* node =
695 reinterpret_cast<DebugInfoListNode*>(data.GetParameter());
696 // We need to clear all breakpoints associated with the function to restore
697 // original code and avoid patching the code twice later because
698 // the function will live in the heap until next gc, and can be found by
699 // Debug::FindSharedFunctionInfoInScript.
700 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
701 it.ClearAllDebugBreak();
702 debug->RemoveDebugInfo(node->debug_info());
703 #ifdef DEBUG
704 for (DebugInfoListNode* n = debug->debug_info_list_;
705 n != NULL;
706 n = n->next()) {
707 DCHECK(n != node);
708 }
709 #endif
710 }
711
712
DebugInfoListNode(DebugInfo * debug_info)713 DebugInfoListNode::DebugInfoListNode(DebugInfo* debug_info): next_(NULL) {
714 // Globalize the request debug info object and make it weak.
715 GlobalHandles* global_handles = debug_info->GetIsolate()->global_handles();
716 debug_info_ = Handle<DebugInfo>::cast(global_handles->Create(debug_info));
717 GlobalHandles::MakeWeak(reinterpret_cast<Object**>(debug_info_.location()),
718 this,
719 Debug::HandleWeakDebugInfo);
720 }
721
722
~DebugInfoListNode()723 DebugInfoListNode::~DebugInfoListNode() {
724 GlobalHandles::Destroy(reinterpret_cast<Object**>(debug_info_.location()));
725 }
726
727
CompileDebuggerScript(Isolate * isolate,int index)728 bool Debug::CompileDebuggerScript(Isolate* isolate, int index) {
729 Factory* factory = isolate->factory();
730 HandleScope scope(isolate);
731
732 // Bail out if the index is invalid.
733 if (index == -1) return false;
734
735 // Find source and name for the requested script.
736 Handle<String> source_code =
737 isolate->bootstrapper()->NativesSourceLookup(index);
738 Vector<const char> name = Natives::GetScriptName(index);
739 Handle<String> script_name =
740 factory->NewStringFromAscii(name).ToHandleChecked();
741 Handle<Context> context = isolate->native_context();
742
743 // Compile the script.
744 Handle<SharedFunctionInfo> function_info;
745 function_info = Compiler::CompileScript(
746 source_code, script_name, 0, 0, false, context, NULL, NULL,
747 ScriptCompiler::kNoCompileOptions, NATIVES_CODE);
748
749 // Silently ignore stack overflows during compilation.
750 if (function_info.is_null()) {
751 DCHECK(isolate->has_pending_exception());
752 isolate->clear_pending_exception();
753 return false;
754 }
755
756 // Execute the shared function in the debugger context.
757 Handle<JSFunction> function =
758 factory->NewFunctionFromSharedFunctionInfo(function_info, context);
759
760 MaybeHandle<Object> maybe_exception;
761 MaybeHandle<Object> result = Execution::TryCall(
762 function, handle(context->global_proxy()), 0, NULL, &maybe_exception);
763
764 // Check for caught exceptions.
765 if (result.is_null()) {
766 DCHECK(!isolate->has_pending_exception());
767 MessageLocation computed_location;
768 isolate->ComputeLocation(&computed_location);
769 Handle<Object> message = MessageHandler::MakeMessageObject(
770 isolate, "error_loading_debugger", &computed_location,
771 Vector<Handle<Object> >::empty(), Handle<JSArray>());
772 DCHECK(!isolate->has_pending_exception());
773 Handle<Object> exception;
774 if (maybe_exception.ToHandle(&exception)) {
775 isolate->set_pending_exception(*exception);
776 MessageHandler::ReportMessage(isolate, NULL, message);
777 isolate->clear_pending_exception();
778 }
779 return false;
780 }
781
782 // Mark this script as native and return successfully.
783 Handle<Script> script(Script::cast(function->shared()->script()));
784 script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
785 return true;
786 }
787
788
Load()789 bool Debug::Load() {
790 // Return if debugger is already loaded.
791 if (is_loaded()) return true;
792
793 // Bail out if we're already in the process of compiling the native
794 // JavaScript source code for the debugger.
795 if (is_suppressed_) return false;
796 SuppressDebug while_loading(this);
797
798 // Disable breakpoints and interrupts while compiling and running the
799 // debugger scripts including the context creation code.
800 DisableBreak disable(this, true);
801 PostponeInterruptsScope postpone(isolate_);
802
803 // Create the debugger context.
804 HandleScope scope(isolate_);
805 ExtensionConfiguration no_extensions;
806 Handle<Context> context =
807 isolate_->bootstrapper()->CreateEnvironment(
808 MaybeHandle<JSGlobalProxy>(),
809 v8::Handle<ObjectTemplate>(),
810 &no_extensions);
811
812 // Fail if no context could be created.
813 if (context.is_null()) return false;
814
815 // Use the debugger context.
816 SaveContext save(isolate_);
817 isolate_->set_context(*context);
818
819 // Expose the builtins object in the debugger context.
820 Handle<String> key = isolate_->factory()->InternalizeOneByteString(
821 STATIC_CHAR_VECTOR("builtins"));
822 Handle<GlobalObject> global =
823 Handle<GlobalObject>(context->global_object(), isolate_);
824 Handle<JSBuiltinsObject> builtin =
825 Handle<JSBuiltinsObject>(global->builtins(), isolate_);
826 RETURN_ON_EXCEPTION_VALUE(
827 isolate_, Object::SetProperty(global, key, builtin, SLOPPY), false);
828
829 // Compile the JavaScript for the debugger in the debugger context.
830 bool caught_exception =
831 !CompileDebuggerScript(isolate_, Natives::GetIndex("mirror")) ||
832 !CompileDebuggerScript(isolate_, Natives::GetIndex("debug"));
833
834 if (FLAG_enable_liveedit) {
835 caught_exception = caught_exception ||
836 !CompileDebuggerScript(isolate_, Natives::GetIndex("liveedit"));
837 }
838 // Check for caught exceptions.
839 if (caught_exception) return false;
840
841 debug_context_ = Handle<Context>::cast(
842 isolate_->global_handles()->Create(*context));
843 return true;
844 }
845
846
Unload()847 void Debug::Unload() {
848 ClearAllBreakPoints();
849 ClearStepping();
850
851 // Return debugger is not loaded.
852 if (!is_loaded()) return;
853
854 // Clear the script cache.
855 if (script_cache_ != NULL) {
856 delete script_cache_;
857 script_cache_ = NULL;
858 }
859
860 // Clear debugger context global handle.
861 GlobalHandles::Destroy(Handle<Object>::cast(debug_context_).location());
862 debug_context_ = Handle<Context>();
863 }
864
865
Break(Arguments args,JavaScriptFrame * frame)866 void Debug::Break(Arguments args, JavaScriptFrame* frame) {
867 Heap* heap = isolate_->heap();
868 HandleScope scope(isolate_);
869 DCHECK(args.length() == 0);
870
871 // Initialize LiveEdit.
872 LiveEdit::InitializeThreadLocal(this);
873
874 // Just continue if breaks are disabled or debugger cannot be loaded.
875 if (break_disabled_) return;
876
877 // Enter the debugger.
878 DebugScope debug_scope(this);
879 if (debug_scope.failed()) return;
880
881 // Postpone interrupt during breakpoint processing.
882 PostponeInterruptsScope postpone(isolate_);
883
884 // Get the debug info (create it if it does not exist).
885 Handle<SharedFunctionInfo> shared =
886 Handle<SharedFunctionInfo>(frame->function()->shared());
887 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
888
889 // Find the break point where execution has stopped.
890 BreakLocationIterator break_location_iterator(debug_info,
891 ALL_BREAK_LOCATIONS);
892 // pc points to the instruction after the current one, possibly a break
893 // location as well. So the "- 1" to exclude it from the search.
894 break_location_iterator.FindBreakLocationFromAddress(frame->pc() - 1);
895
896 // Check whether step next reached a new statement.
897 if (!StepNextContinue(&break_location_iterator, frame)) {
898 // Decrease steps left if performing multiple steps.
899 if (thread_local_.step_count_ > 0) {
900 thread_local_.step_count_--;
901 }
902 }
903
904 // If there is one or more real break points check whether any of these are
905 // triggered.
906 Handle<Object> break_points_hit(heap->undefined_value(), isolate_);
907 if (break_location_iterator.HasBreakPoint()) {
908 Handle<Object> break_point_objects =
909 Handle<Object>(break_location_iterator.BreakPointObjects(), isolate_);
910 break_points_hit = CheckBreakPoints(break_point_objects);
911 }
912
913 // If step out is active skip everything until the frame where we need to step
914 // out to is reached, unless real breakpoint is hit.
915 if (StepOutActive() &&
916 frame->fp() != thread_local_.step_out_fp_ &&
917 break_points_hit->IsUndefined() ) {
918 // Step count should always be 0 for StepOut.
919 DCHECK(thread_local_.step_count_ == 0);
920 } else if (!break_points_hit->IsUndefined() ||
921 (thread_local_.last_step_action_ != StepNone &&
922 thread_local_.step_count_ == 0)) {
923 // Notify debugger if a real break point is triggered or if performing
924 // single stepping with no more steps to perform. Otherwise do another step.
925
926 // Clear all current stepping setup.
927 ClearStepping();
928
929 if (thread_local_.queued_step_count_ > 0) {
930 // Perform queued steps
931 int step_count = thread_local_.queued_step_count_;
932
933 // Clear queue
934 thread_local_.queued_step_count_ = 0;
935
936 PrepareStep(StepNext, step_count, StackFrame::NO_ID);
937 } else {
938 // Notify the debug event listeners.
939 OnDebugBreak(break_points_hit, false);
940 }
941 } else if (thread_local_.last_step_action_ != StepNone) {
942 // Hold on to last step action as it is cleared by the call to
943 // ClearStepping.
944 StepAction step_action = thread_local_.last_step_action_;
945 int step_count = thread_local_.step_count_;
946
947 // If StepNext goes deeper in code, StepOut until original frame
948 // and keep step count queued up in the meantime.
949 if (step_action == StepNext && frame->fp() < thread_local_.last_fp_) {
950 // Count frames until target frame
951 int count = 0;
952 JavaScriptFrameIterator it(isolate_);
953 while (!it.done() && it.frame()->fp() < thread_local_.last_fp_) {
954 count++;
955 it.Advance();
956 }
957
958 // Check that we indeed found the frame we are looking for.
959 CHECK(!it.done() && (it.frame()->fp() == thread_local_.last_fp_));
960 if (step_count > 1) {
961 // Save old count and action to continue stepping after StepOut.
962 thread_local_.queued_step_count_ = step_count - 1;
963 }
964
965 // Set up for StepOut to reach target frame.
966 step_action = StepOut;
967 step_count = count;
968 }
969
970 // Clear all current stepping setup.
971 ClearStepping();
972
973 // Set up for the remaining steps.
974 PrepareStep(step_action, step_count, StackFrame::NO_ID);
975 }
976 }
977
978
RUNTIME_FUNCTION(Debug_Break)979 RUNTIME_FUNCTION(Debug_Break) {
980 // Get the top-most JavaScript frame.
981 JavaScriptFrameIterator it(isolate);
982 isolate->debug()->Break(args, it.frame());
983 isolate->debug()->SetAfterBreakTarget(it.frame());
984 return isolate->heap()->undefined_value();
985 }
986
987
988 // Check the break point objects for whether one or more are actually
989 // triggered. This function returns a JSArray with the break point objects
990 // which is triggered.
CheckBreakPoints(Handle<Object> break_point_objects)991 Handle<Object> Debug::CheckBreakPoints(Handle<Object> break_point_objects) {
992 Factory* factory = isolate_->factory();
993
994 // Count the number of break points hit. If there are multiple break points
995 // they are in a FixedArray.
996 Handle<FixedArray> break_points_hit;
997 int break_points_hit_count = 0;
998 DCHECK(!break_point_objects->IsUndefined());
999 if (break_point_objects->IsFixedArray()) {
1000 Handle<FixedArray> array(FixedArray::cast(*break_point_objects));
1001 break_points_hit = factory->NewFixedArray(array->length());
1002 for (int i = 0; i < array->length(); i++) {
1003 Handle<Object> o(array->get(i), isolate_);
1004 if (CheckBreakPoint(o)) {
1005 break_points_hit->set(break_points_hit_count++, *o);
1006 }
1007 }
1008 } else {
1009 break_points_hit = factory->NewFixedArray(1);
1010 if (CheckBreakPoint(break_point_objects)) {
1011 break_points_hit->set(break_points_hit_count++, *break_point_objects);
1012 }
1013 }
1014
1015 // Return undefined if no break points were triggered.
1016 if (break_points_hit_count == 0) {
1017 return factory->undefined_value();
1018 }
1019 // Return break points hit as a JSArray.
1020 Handle<JSArray> result = factory->NewJSArrayWithElements(break_points_hit);
1021 result->set_length(Smi::FromInt(break_points_hit_count));
1022 return result;
1023 }
1024
1025
1026 // Check whether a single break point object is triggered.
CheckBreakPoint(Handle<Object> break_point_object)1027 bool Debug::CheckBreakPoint(Handle<Object> break_point_object) {
1028 Factory* factory = isolate_->factory();
1029 HandleScope scope(isolate_);
1030
1031 // Ignore check if break point object is not a JSObject.
1032 if (!break_point_object->IsJSObject()) return true;
1033
1034 // Get the function IsBreakPointTriggered (defined in debug-debugger.js).
1035 Handle<String> is_break_point_triggered_string =
1036 factory->InternalizeOneByteString(
1037 STATIC_CHAR_VECTOR("IsBreakPointTriggered"));
1038 Handle<GlobalObject> debug_global(debug_context()->global_object());
1039 Handle<JSFunction> check_break_point =
1040 Handle<JSFunction>::cast(Object::GetProperty(
1041 debug_global, is_break_point_triggered_string).ToHandleChecked());
1042
1043 // Get the break id as an object.
1044 Handle<Object> break_id = factory->NewNumberFromInt(Debug::break_id());
1045
1046 // Call HandleBreakPointx.
1047 Handle<Object> argv[] = { break_id, break_point_object };
1048 Handle<Object> result;
1049 if (!Execution::TryCall(check_break_point,
1050 isolate_->js_builtins_object(),
1051 arraysize(argv),
1052 argv).ToHandle(&result)) {
1053 return false;
1054 }
1055
1056 // Return whether the break point is triggered.
1057 return result->IsTrue();
1058 }
1059
1060
1061 // Check whether the function has debug information.
HasDebugInfo(Handle<SharedFunctionInfo> shared)1062 bool Debug::HasDebugInfo(Handle<SharedFunctionInfo> shared) {
1063 return !shared->debug_info()->IsUndefined();
1064 }
1065
1066
1067 // Return the debug info for this function. EnsureDebugInfo must be called
1068 // prior to ensure the debug info has been generated for shared.
GetDebugInfo(Handle<SharedFunctionInfo> shared)1069 Handle<DebugInfo> Debug::GetDebugInfo(Handle<SharedFunctionInfo> shared) {
1070 DCHECK(HasDebugInfo(shared));
1071 return Handle<DebugInfo>(DebugInfo::cast(shared->debug_info()));
1072 }
1073
1074
SetBreakPoint(Handle<JSFunction> function,Handle<Object> break_point_object,int * source_position)1075 bool Debug::SetBreakPoint(Handle<JSFunction> function,
1076 Handle<Object> break_point_object,
1077 int* source_position) {
1078 HandleScope scope(isolate_);
1079
1080 PrepareForBreakPoints();
1081
1082 // Make sure the function is compiled and has set up the debug info.
1083 Handle<SharedFunctionInfo> shared(function->shared());
1084 if (!EnsureDebugInfo(shared, function)) {
1085 // Return if retrieving debug info failed.
1086 return true;
1087 }
1088
1089 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1090 // Source positions starts with zero.
1091 DCHECK(*source_position >= 0);
1092
1093 // Find the break point and change it.
1094 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
1095 it.FindBreakLocationFromPosition(*source_position, STATEMENT_ALIGNED);
1096 it.SetBreakPoint(break_point_object);
1097
1098 *source_position = it.position();
1099
1100 // At least one active break point now.
1101 return debug_info->GetBreakPointCount() > 0;
1102 }
1103
1104
SetBreakPointForScript(Handle<Script> script,Handle<Object> break_point_object,int * source_position,BreakPositionAlignment alignment)1105 bool Debug::SetBreakPointForScript(Handle<Script> script,
1106 Handle<Object> break_point_object,
1107 int* source_position,
1108 BreakPositionAlignment alignment) {
1109 HandleScope scope(isolate_);
1110
1111 PrepareForBreakPoints();
1112
1113 // Obtain shared function info for the function.
1114 Object* result = FindSharedFunctionInfoInScript(script, *source_position);
1115 if (result->IsUndefined()) return false;
1116
1117 // Make sure the function has set up the debug info.
1118 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
1119 if (!EnsureDebugInfo(shared, Handle<JSFunction>::null())) {
1120 // Return if retrieving debug info failed.
1121 return false;
1122 }
1123
1124 // Find position within function. The script position might be before the
1125 // source position of the first function.
1126 int position;
1127 if (shared->start_position() > *source_position) {
1128 position = 0;
1129 } else {
1130 position = *source_position - shared->start_position();
1131 }
1132
1133 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1134 // Source positions starts with zero.
1135 DCHECK(position >= 0);
1136
1137 // Find the break point and change it.
1138 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
1139 it.FindBreakLocationFromPosition(position, alignment);
1140 it.SetBreakPoint(break_point_object);
1141
1142 *source_position = it.position() + shared->start_position();
1143
1144 // At least one active break point now.
1145 DCHECK(debug_info->GetBreakPointCount() > 0);
1146 return true;
1147 }
1148
1149
ClearBreakPoint(Handle<Object> break_point_object)1150 void Debug::ClearBreakPoint(Handle<Object> break_point_object) {
1151 HandleScope scope(isolate_);
1152
1153 DebugInfoListNode* node = debug_info_list_;
1154 while (node != NULL) {
1155 Object* result = DebugInfo::FindBreakPointInfo(node->debug_info(),
1156 break_point_object);
1157 if (!result->IsUndefined()) {
1158 // Get information in the break point.
1159 BreakPointInfo* break_point_info = BreakPointInfo::cast(result);
1160 Handle<DebugInfo> debug_info = node->debug_info();
1161
1162 // Find the break point and clear it.
1163 BreakLocationIterator it(debug_info, SOURCE_BREAK_LOCATIONS);
1164 it.FindBreakLocationFromAddress(debug_info->code()->entry() +
1165 break_point_info->code_position()->value());
1166 it.ClearBreakPoint(break_point_object);
1167
1168 // If there are no more break points left remove the debug info for this
1169 // function.
1170 if (debug_info->GetBreakPointCount() == 0) {
1171 RemoveDebugInfo(debug_info);
1172 }
1173
1174 return;
1175 }
1176 node = node->next();
1177 }
1178 }
1179
1180
ClearAllBreakPoints()1181 void Debug::ClearAllBreakPoints() {
1182 DebugInfoListNode* node = debug_info_list_;
1183 while (node != NULL) {
1184 // Remove all debug break code.
1185 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1186 it.ClearAllDebugBreak();
1187 node = node->next();
1188 }
1189
1190 // Remove all debug info.
1191 while (debug_info_list_ != NULL) {
1192 RemoveDebugInfo(debug_info_list_->debug_info());
1193 }
1194 }
1195
1196
FloodWithOneShot(Handle<JSFunction> function)1197 void Debug::FloodWithOneShot(Handle<JSFunction> function) {
1198 PrepareForBreakPoints();
1199
1200 // Make sure the function is compiled and has set up the debug info.
1201 Handle<SharedFunctionInfo> shared(function->shared());
1202 if (!EnsureDebugInfo(shared, function)) {
1203 // Return if we failed to retrieve the debug info.
1204 return;
1205 }
1206
1207 // Flood the function with break points.
1208 BreakLocationIterator it(GetDebugInfo(shared), ALL_BREAK_LOCATIONS);
1209 while (!it.Done()) {
1210 it.SetOneShot();
1211 it.Next();
1212 }
1213 }
1214
1215
FloodBoundFunctionWithOneShot(Handle<JSFunction> function)1216 void Debug::FloodBoundFunctionWithOneShot(Handle<JSFunction> function) {
1217 Handle<FixedArray> new_bindings(function->function_bindings());
1218 Handle<Object> bindee(new_bindings->get(JSFunction::kBoundFunctionIndex),
1219 isolate_);
1220
1221 if (!bindee.is_null() && bindee->IsJSFunction() &&
1222 !JSFunction::cast(*bindee)->IsFromNativeScript()) {
1223 Handle<JSFunction> bindee_function(JSFunction::cast(*bindee));
1224 Debug::FloodWithOneShot(bindee_function);
1225 }
1226 }
1227
1228
FloodHandlerWithOneShot()1229 void Debug::FloodHandlerWithOneShot() {
1230 // Iterate through the JavaScript stack looking for handlers.
1231 StackFrame::Id id = break_frame_id();
1232 if (id == StackFrame::NO_ID) {
1233 // If there is no JavaScript stack don't do anything.
1234 return;
1235 }
1236 for (JavaScriptFrameIterator it(isolate_, id); !it.done(); it.Advance()) {
1237 JavaScriptFrame* frame = it.frame();
1238 if (frame->HasHandler()) {
1239 // Flood the function with the catch block with break points
1240 FloodWithOneShot(Handle<JSFunction>(frame->function()));
1241 return;
1242 }
1243 }
1244 }
1245
1246
ChangeBreakOnException(ExceptionBreakType type,bool enable)1247 void Debug::ChangeBreakOnException(ExceptionBreakType type, bool enable) {
1248 if (type == BreakUncaughtException) {
1249 break_on_uncaught_exception_ = enable;
1250 } else {
1251 break_on_exception_ = enable;
1252 }
1253 }
1254
1255
IsBreakOnException(ExceptionBreakType type)1256 bool Debug::IsBreakOnException(ExceptionBreakType type) {
1257 if (type == BreakUncaughtException) {
1258 return break_on_uncaught_exception_;
1259 } else {
1260 return break_on_exception_;
1261 }
1262 }
1263
1264
PromiseHasRejectHandler(Handle<JSObject> promise)1265 bool Debug::PromiseHasRejectHandler(Handle<JSObject> promise) {
1266 Handle<JSFunction> fun = Handle<JSFunction>::cast(
1267 JSObject::GetDataProperty(isolate_->js_builtins_object(),
1268 isolate_->factory()->NewStringFromStaticChars(
1269 "PromiseHasRejectHandler")));
1270 Handle<Object> result =
1271 Execution::Call(isolate_, fun, promise, 0, NULL).ToHandleChecked();
1272 return result->IsTrue();
1273 }
1274
1275
PrepareStep(StepAction step_action,int step_count,StackFrame::Id frame_id)1276 void Debug::PrepareStep(StepAction step_action,
1277 int step_count,
1278 StackFrame::Id frame_id) {
1279 HandleScope scope(isolate_);
1280
1281 PrepareForBreakPoints();
1282
1283 DCHECK(in_debug_scope());
1284
1285 // Remember this step action and count.
1286 thread_local_.last_step_action_ = step_action;
1287 if (step_action == StepOut) {
1288 // For step out target frame will be found on the stack so there is no need
1289 // to set step counter for it. It's expected to always be 0 for StepOut.
1290 thread_local_.step_count_ = 0;
1291 } else {
1292 thread_local_.step_count_ = step_count;
1293 }
1294
1295 // Get the frame where the execution has stopped and skip the debug frame if
1296 // any. The debug frame will only be present if execution was stopped due to
1297 // hitting a break point. In other situations (e.g. unhandled exception) the
1298 // debug frame is not present.
1299 StackFrame::Id id = break_frame_id();
1300 if (id == StackFrame::NO_ID) {
1301 // If there is no JavaScript stack don't do anything.
1302 return;
1303 }
1304 if (frame_id != StackFrame::NO_ID) {
1305 id = frame_id;
1306 }
1307 JavaScriptFrameIterator frames_it(isolate_, id);
1308 JavaScriptFrame* frame = frames_it.frame();
1309
1310 // First of all ensure there is one-shot break points in the top handler
1311 // if any.
1312 FloodHandlerWithOneShot();
1313
1314 // If the function on the top frame is unresolved perform step out. This will
1315 // be the case when calling unknown functions and having the debugger stopped
1316 // in an unhandled exception.
1317 if (!frame->function()->IsJSFunction()) {
1318 // Step out: Find the calling JavaScript frame and flood it with
1319 // breakpoints.
1320 frames_it.Advance();
1321 // Fill the function to return to with one-shot break points.
1322 JSFunction* function = frames_it.frame()->function();
1323 FloodWithOneShot(Handle<JSFunction>(function));
1324 return;
1325 }
1326
1327 // Get the debug info (create it if it does not exist).
1328 Handle<JSFunction> function(frame->function());
1329 Handle<SharedFunctionInfo> shared(function->shared());
1330 if (!EnsureDebugInfo(shared, function)) {
1331 // Return if ensuring debug info failed.
1332 return;
1333 }
1334 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1335
1336 // Find the break location where execution has stopped.
1337 BreakLocationIterator it(debug_info, ALL_BREAK_LOCATIONS);
1338 // pc points to the instruction after the current one, possibly a break
1339 // location as well. So the "- 1" to exclude it from the search.
1340 it.FindBreakLocationFromAddress(frame->pc() - 1);
1341
1342 // Compute whether or not the target is a call target.
1343 bool is_load_or_store = false;
1344 bool is_inline_cache_stub = false;
1345 bool is_at_restarted_function = false;
1346 Handle<Code> call_function_stub;
1347
1348 if (thread_local_.restarter_frame_function_pointer_ == NULL) {
1349 if (RelocInfo::IsCodeTarget(it.rinfo()->rmode())) {
1350 bool is_call_target = false;
1351 Address target = it.rinfo()->target_address();
1352 Code* code = Code::GetCodeFromTargetAddress(target);
1353 if (code->is_call_stub()) {
1354 is_call_target = true;
1355 }
1356 if (code->is_inline_cache_stub()) {
1357 is_inline_cache_stub = true;
1358 is_load_or_store = !is_call_target;
1359 }
1360
1361 // Check if target code is CallFunction stub.
1362 Code* maybe_call_function_stub = code;
1363 // If there is a breakpoint at this line look at the original code to
1364 // check if it is a CallFunction stub.
1365 if (it.IsDebugBreak()) {
1366 Address original_target = it.original_rinfo()->target_address();
1367 maybe_call_function_stub =
1368 Code::GetCodeFromTargetAddress(original_target);
1369 }
1370 if ((maybe_call_function_stub->kind() == Code::STUB &&
1371 CodeStub::GetMajorKey(maybe_call_function_stub) ==
1372 CodeStub::CallFunction) ||
1373 maybe_call_function_stub->kind() == Code::CALL_IC) {
1374 // Save reference to the code as we may need it to find out arguments
1375 // count for 'step in' later.
1376 call_function_stub = Handle<Code>(maybe_call_function_stub);
1377 }
1378 }
1379 } else {
1380 is_at_restarted_function = true;
1381 }
1382
1383 // If this is the last break code target step out is the only possibility.
1384 if (it.IsExit() || step_action == StepOut) {
1385 if (step_action == StepOut) {
1386 // Skip step_count frames starting with the current one.
1387 while (step_count-- > 0 && !frames_it.done()) {
1388 frames_it.Advance();
1389 }
1390 } else {
1391 DCHECK(it.IsExit());
1392 frames_it.Advance();
1393 }
1394 // Skip builtin functions on the stack.
1395 while (!frames_it.done() &&
1396 frames_it.frame()->function()->IsFromNativeScript()) {
1397 frames_it.Advance();
1398 }
1399 // Step out: If there is a JavaScript caller frame, we need to
1400 // flood it with breakpoints.
1401 if (!frames_it.done()) {
1402 // Fill the function to return to with one-shot break points.
1403 JSFunction* function = frames_it.frame()->function();
1404 FloodWithOneShot(Handle<JSFunction>(function));
1405 // Set target frame pointer.
1406 ActivateStepOut(frames_it.frame());
1407 }
1408 } else if (!(is_inline_cache_stub || RelocInfo::IsConstructCall(it.rmode()) ||
1409 !call_function_stub.is_null() || is_at_restarted_function)
1410 || step_action == StepNext || step_action == StepMin) {
1411 // Step next or step min.
1412
1413 // Fill the current function with one-shot break points.
1414 FloodWithOneShot(function);
1415
1416 // Remember source position and frame to handle step next.
1417 thread_local_.last_statement_position_ =
1418 debug_info->code()->SourceStatementPosition(frame->pc());
1419 thread_local_.last_fp_ = frame->UnpaddedFP();
1420 } else {
1421 // If there's restarter frame on top of the stack, just get the pointer
1422 // to function which is going to be restarted.
1423 if (is_at_restarted_function) {
1424 Handle<JSFunction> restarted_function(
1425 JSFunction::cast(*thread_local_.restarter_frame_function_pointer_));
1426 FloodWithOneShot(restarted_function);
1427 } else if (!call_function_stub.is_null()) {
1428 // If it's CallFunction stub ensure target function is compiled and flood
1429 // it with one shot breakpoints.
1430 bool is_call_ic = call_function_stub->kind() == Code::CALL_IC;
1431
1432 // Find out number of arguments from the stub minor key.
1433 uint32_t key = call_function_stub->stub_key();
1434 // Argc in the stub is the number of arguments passed - not the
1435 // expected arguments of the called function.
1436 int call_function_arg_count = is_call_ic
1437 ? CallICStub::ExtractArgcFromMinorKey(CodeStub::MinorKeyFromKey(key))
1438 : CallFunctionStub::ExtractArgcFromMinorKey(
1439 CodeStub::MinorKeyFromKey(key));
1440
1441 DCHECK(is_call_ic ||
1442 CodeStub::GetMajorKey(*call_function_stub) ==
1443 CodeStub::MajorKeyFromKey(key));
1444
1445 // Find target function on the expression stack.
1446 // Expression stack looks like this (top to bottom):
1447 // argN
1448 // ...
1449 // arg0
1450 // Receiver
1451 // Function to call
1452 int expressions_count = frame->ComputeExpressionsCount();
1453 DCHECK(expressions_count - 2 - call_function_arg_count >= 0);
1454 Object* fun = frame->GetExpression(
1455 expressions_count - 2 - call_function_arg_count);
1456
1457 // Flood the actual target of call/apply.
1458 if (fun->IsJSFunction()) {
1459 Isolate* isolate = JSFunction::cast(fun)->GetIsolate();
1460 Code* apply = isolate->builtins()->builtin(Builtins::kFunctionApply);
1461 Code* call = isolate->builtins()->builtin(Builtins::kFunctionCall);
1462 while (fun->IsJSFunction()) {
1463 Code* code = JSFunction::cast(fun)->shared()->code();
1464 if (code != apply && code != call) break;
1465 fun = frame->GetExpression(
1466 expressions_count - 1 - call_function_arg_count);
1467 }
1468 }
1469
1470 if (fun->IsJSFunction()) {
1471 Handle<JSFunction> js_function(JSFunction::cast(fun));
1472 if (js_function->shared()->bound()) {
1473 Debug::FloodBoundFunctionWithOneShot(js_function);
1474 } else if (!js_function->IsFromNativeScript()) {
1475 // Don't step into builtins.
1476 // It will also compile target function if it's not compiled yet.
1477 FloodWithOneShot(js_function);
1478 }
1479 }
1480 }
1481
1482 // Fill the current function with one-shot break points even for step in on
1483 // a call target as the function called might be a native function for
1484 // which step in will not stop. It also prepares for stepping in
1485 // getters/setters.
1486 FloodWithOneShot(function);
1487
1488 if (is_load_or_store) {
1489 // Remember source position and frame to handle step in getter/setter. If
1490 // there is a custom getter/setter it will be handled in
1491 // Object::Get/SetPropertyWithAccessor, otherwise the step action will be
1492 // propagated on the next Debug::Break.
1493 thread_local_.last_statement_position_ =
1494 debug_info->code()->SourceStatementPosition(frame->pc());
1495 thread_local_.last_fp_ = frame->UnpaddedFP();
1496 }
1497
1498 // Step in or Step in min
1499 it.PrepareStepIn(isolate_);
1500 ActivateStepIn(frame);
1501 }
1502 }
1503
1504
1505 // Check whether the current debug break should be reported to the debugger. It
1506 // is used to have step next and step in only report break back to the debugger
1507 // if on a different frame or in a different statement. In some situations
1508 // there will be several break points in the same statement when the code is
1509 // flooded with one-shot break points. This function helps to perform several
1510 // steps before reporting break back to the debugger.
StepNextContinue(BreakLocationIterator * break_location_iterator,JavaScriptFrame * frame)1511 bool Debug::StepNextContinue(BreakLocationIterator* break_location_iterator,
1512 JavaScriptFrame* frame) {
1513 // StepNext and StepOut shouldn't bring us deeper in code, so last frame
1514 // shouldn't be a parent of current frame.
1515 if (thread_local_.last_step_action_ == StepNext ||
1516 thread_local_.last_step_action_ == StepOut) {
1517 if (frame->fp() < thread_local_.last_fp_) return true;
1518 }
1519
1520 // If the step last action was step next or step in make sure that a new
1521 // statement is hit.
1522 if (thread_local_.last_step_action_ == StepNext ||
1523 thread_local_.last_step_action_ == StepIn) {
1524 // Never continue if returning from function.
1525 if (break_location_iterator->IsExit()) return false;
1526
1527 // Continue if we are still on the same frame and in the same statement.
1528 int current_statement_position =
1529 break_location_iterator->code()->SourceStatementPosition(frame->pc());
1530 return thread_local_.last_fp_ == frame->UnpaddedFP() &&
1531 thread_local_.last_statement_position_ == current_statement_position;
1532 }
1533
1534 // No step next action - don't continue.
1535 return false;
1536 }
1537
1538
1539 // Check whether the code object at the specified address is a debug break code
1540 // object.
IsDebugBreak(Address addr)1541 bool Debug::IsDebugBreak(Address addr) {
1542 Code* code = Code::GetCodeFromTargetAddress(addr);
1543 return code->is_debug_stub() && code->extra_ic_state() == DEBUG_BREAK;
1544 }
1545
1546
1547
1548
1549
1550 // Simple function for returning the source positions for active break points.
GetSourceBreakLocations(Handle<SharedFunctionInfo> shared,BreakPositionAlignment position_alignment)1551 Handle<Object> Debug::GetSourceBreakLocations(
1552 Handle<SharedFunctionInfo> shared,
1553 BreakPositionAlignment position_alignment) {
1554 Isolate* isolate = shared->GetIsolate();
1555 Heap* heap = isolate->heap();
1556 if (!HasDebugInfo(shared)) {
1557 return Handle<Object>(heap->undefined_value(), isolate);
1558 }
1559 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
1560 if (debug_info->GetBreakPointCount() == 0) {
1561 return Handle<Object>(heap->undefined_value(), isolate);
1562 }
1563 Handle<FixedArray> locations =
1564 isolate->factory()->NewFixedArray(debug_info->GetBreakPointCount());
1565 int count = 0;
1566 for (int i = 0; i < debug_info->break_points()->length(); i++) {
1567 if (!debug_info->break_points()->get(i)->IsUndefined()) {
1568 BreakPointInfo* break_point_info =
1569 BreakPointInfo::cast(debug_info->break_points()->get(i));
1570 if (break_point_info->GetBreakPointCount() > 0) {
1571 Smi* position;
1572 switch (position_alignment) {
1573 case STATEMENT_ALIGNED:
1574 position = break_point_info->statement_position();
1575 break;
1576 case BREAK_POSITION_ALIGNED:
1577 position = break_point_info->source_position();
1578 break;
1579 default:
1580 UNREACHABLE();
1581 position = break_point_info->statement_position();
1582 }
1583
1584 locations->set(count++, position);
1585 }
1586 }
1587 }
1588 return locations;
1589 }
1590
1591
1592 // Handle stepping into a function.
HandleStepIn(Handle<JSFunction> function,Handle<Object> holder,Address fp,bool is_constructor)1593 void Debug::HandleStepIn(Handle<JSFunction> function,
1594 Handle<Object> holder,
1595 Address fp,
1596 bool is_constructor) {
1597 Isolate* isolate = function->GetIsolate();
1598 // If the frame pointer is not supplied by the caller find it.
1599 if (fp == 0) {
1600 StackFrameIterator it(isolate);
1601 it.Advance();
1602 // For constructor functions skip another frame.
1603 if (is_constructor) {
1604 DCHECK(it.frame()->is_construct());
1605 it.Advance();
1606 }
1607 fp = it.frame()->fp();
1608 }
1609
1610 // Flood the function with one-shot break points if it is called from where
1611 // step into was requested.
1612 if (fp == thread_local_.step_into_fp_) {
1613 if (function->shared()->bound()) {
1614 // Handle Function.prototype.bind
1615 Debug::FloodBoundFunctionWithOneShot(function);
1616 } else if (!function->IsFromNativeScript()) {
1617 // Don't allow step into functions in the native context.
1618 if (function->shared()->code() ==
1619 isolate->builtins()->builtin(Builtins::kFunctionApply) ||
1620 function->shared()->code() ==
1621 isolate->builtins()->builtin(Builtins::kFunctionCall)) {
1622 // Handle function.apply and function.call separately to flood the
1623 // function to be called and not the code for Builtins::FunctionApply or
1624 // Builtins::FunctionCall. The receiver of call/apply is the target
1625 // function.
1626 if (!holder.is_null() && holder->IsJSFunction()) {
1627 Handle<JSFunction> js_function = Handle<JSFunction>::cast(holder);
1628 if (!js_function->IsFromNativeScript()) {
1629 Debug::FloodWithOneShot(js_function);
1630 } else if (js_function->shared()->bound()) {
1631 // Handle Function.prototype.bind
1632 Debug::FloodBoundFunctionWithOneShot(js_function);
1633 }
1634 }
1635 } else {
1636 Debug::FloodWithOneShot(function);
1637 }
1638 }
1639 }
1640 }
1641
1642
ClearStepping()1643 void Debug::ClearStepping() {
1644 // Clear the various stepping setup.
1645 ClearOneShot();
1646 ClearStepIn();
1647 ClearStepOut();
1648 ClearStepNext();
1649
1650 // Clear multiple step counter.
1651 thread_local_.step_count_ = 0;
1652 }
1653
1654
1655 // Clears all the one-shot break points that are currently set. Normally this
1656 // function is called each time a break point is hit as one shot break points
1657 // are used to support stepping.
ClearOneShot()1658 void Debug::ClearOneShot() {
1659 // The current implementation just runs through all the breakpoints. When the
1660 // last break point for a function is removed that function is automatically
1661 // removed from the list.
1662
1663 DebugInfoListNode* node = debug_info_list_;
1664 while (node != NULL) {
1665 BreakLocationIterator it(node->debug_info(), ALL_BREAK_LOCATIONS);
1666 while (!it.Done()) {
1667 it.ClearOneShot();
1668 it.Next();
1669 }
1670 node = node->next();
1671 }
1672 }
1673
1674
ActivateStepIn(StackFrame * frame)1675 void Debug::ActivateStepIn(StackFrame* frame) {
1676 DCHECK(!StepOutActive());
1677 thread_local_.step_into_fp_ = frame->UnpaddedFP();
1678 }
1679
1680
ClearStepIn()1681 void Debug::ClearStepIn() {
1682 thread_local_.step_into_fp_ = 0;
1683 }
1684
1685
ActivateStepOut(StackFrame * frame)1686 void Debug::ActivateStepOut(StackFrame* frame) {
1687 DCHECK(!StepInActive());
1688 thread_local_.step_out_fp_ = frame->UnpaddedFP();
1689 }
1690
1691
ClearStepOut()1692 void Debug::ClearStepOut() {
1693 thread_local_.step_out_fp_ = 0;
1694 }
1695
1696
ClearStepNext()1697 void Debug::ClearStepNext() {
1698 thread_local_.last_step_action_ = StepNone;
1699 thread_local_.last_statement_position_ = RelocInfo::kNoPosition;
1700 thread_local_.last_fp_ = 0;
1701 }
1702
1703
CollectActiveFunctionsFromThread(Isolate * isolate,ThreadLocalTop * top,List<Handle<JSFunction>> * active_functions,Object * active_code_marker)1704 static void CollectActiveFunctionsFromThread(
1705 Isolate* isolate,
1706 ThreadLocalTop* top,
1707 List<Handle<JSFunction> >* active_functions,
1708 Object* active_code_marker) {
1709 // Find all non-optimized code functions with activation frames
1710 // on the stack. This includes functions which have optimized
1711 // activations (including inlined functions) on the stack as the
1712 // non-optimized code is needed for the lazy deoptimization.
1713 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
1714 JavaScriptFrame* frame = it.frame();
1715 if (frame->is_optimized()) {
1716 List<JSFunction*> functions(FLAG_max_inlining_levels + 1);
1717 frame->GetFunctions(&functions);
1718 for (int i = 0; i < functions.length(); i++) {
1719 JSFunction* function = functions[i];
1720 active_functions->Add(Handle<JSFunction>(function));
1721 function->shared()->code()->set_gc_metadata(active_code_marker);
1722 }
1723 } else if (frame->function()->IsJSFunction()) {
1724 JSFunction* function = frame->function();
1725 DCHECK(frame->LookupCode()->kind() == Code::FUNCTION);
1726 active_functions->Add(Handle<JSFunction>(function));
1727 function->shared()->code()->set_gc_metadata(active_code_marker);
1728 }
1729 }
1730 }
1731
1732
1733 // Figure out how many bytes of "pc_offset" correspond to actual code by
1734 // subtracting off the bytes that correspond to constant/veneer pools. See
1735 // Assembler::CheckConstPool() and Assembler::CheckVeneerPool(). Note that this
1736 // is only useful for architectures using constant pools or veneer pools.
ComputeCodeOffsetFromPcOffset(Code * code,int pc_offset)1737 static int ComputeCodeOffsetFromPcOffset(Code *code, int pc_offset) {
1738 DCHECK_EQ(code->kind(), Code::FUNCTION);
1739 DCHECK(!code->has_debug_break_slots());
1740 DCHECK_LE(0, pc_offset);
1741 DCHECK_LT(pc_offset, code->instruction_end() - code->instruction_start());
1742
1743 int mask = RelocInfo::ModeMask(RelocInfo::CONST_POOL) |
1744 RelocInfo::ModeMask(RelocInfo::VENEER_POOL);
1745 byte *pc = code->instruction_start() + pc_offset;
1746 int code_offset = pc_offset;
1747 for (RelocIterator it(code, mask); !it.done(); it.next()) {
1748 RelocInfo* info = it.rinfo();
1749 if (info->pc() >= pc) break;
1750 DCHECK(RelocInfo::IsConstPool(info->rmode()));
1751 code_offset -= static_cast<int>(info->data());
1752 DCHECK_LE(0, code_offset);
1753 }
1754
1755 return code_offset;
1756 }
1757
1758
1759 // The inverse of ComputeCodeOffsetFromPcOffset.
ComputePcOffsetFromCodeOffset(Code * code,int code_offset)1760 static int ComputePcOffsetFromCodeOffset(Code *code, int code_offset) {
1761 DCHECK_EQ(code->kind(), Code::FUNCTION);
1762
1763 int mask = RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT) |
1764 RelocInfo::ModeMask(RelocInfo::CONST_POOL) |
1765 RelocInfo::ModeMask(RelocInfo::VENEER_POOL);
1766 int reloc = 0;
1767 for (RelocIterator it(code, mask); !it.done(); it.next()) {
1768 RelocInfo* info = it.rinfo();
1769 if (info->pc() - code->instruction_start() - reloc >= code_offset) break;
1770 if (RelocInfo::IsDebugBreakSlot(info->rmode())) {
1771 reloc += Assembler::kDebugBreakSlotLength;
1772 } else {
1773 DCHECK(RelocInfo::IsConstPool(info->rmode()));
1774 reloc += static_cast<int>(info->data());
1775 }
1776 }
1777
1778 int pc_offset = code_offset + reloc;
1779
1780 DCHECK_LT(code->instruction_start() + pc_offset, code->instruction_end());
1781
1782 return pc_offset;
1783 }
1784
1785
RedirectActivationsToRecompiledCodeOnThread(Isolate * isolate,ThreadLocalTop * top)1786 static void RedirectActivationsToRecompiledCodeOnThread(
1787 Isolate* isolate,
1788 ThreadLocalTop* top) {
1789 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
1790 JavaScriptFrame* frame = it.frame();
1791
1792 if (frame->is_optimized() || !frame->function()->IsJSFunction()) continue;
1793
1794 JSFunction* function = frame->function();
1795
1796 DCHECK(frame->LookupCode()->kind() == Code::FUNCTION);
1797
1798 Handle<Code> frame_code(frame->LookupCode());
1799 if (frame_code->has_debug_break_slots()) continue;
1800
1801 Handle<Code> new_code(function->shared()->code());
1802 if (new_code->kind() != Code::FUNCTION ||
1803 !new_code->has_debug_break_slots()) {
1804 continue;
1805 }
1806
1807 int old_pc_offset =
1808 static_cast<int>(frame->pc() - frame_code->instruction_start());
1809 int code_offset = ComputeCodeOffsetFromPcOffset(*frame_code, old_pc_offset);
1810 int new_pc_offset = ComputePcOffsetFromCodeOffset(*new_code, code_offset);
1811
1812 // Compute the equivalent pc in the new code.
1813 byte* new_pc = new_code->instruction_start() + new_pc_offset;
1814
1815 if (FLAG_trace_deopt) {
1816 PrintF("Replacing code %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) "
1817 "with %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) "
1818 "for debugging, "
1819 "changing pc from %08" V8PRIxPTR " to %08" V8PRIxPTR "\n",
1820 reinterpret_cast<intptr_t>(
1821 frame_code->instruction_start()),
1822 reinterpret_cast<intptr_t>(
1823 frame_code->instruction_start()) +
1824 frame_code->instruction_size(),
1825 frame_code->instruction_size(),
1826 reinterpret_cast<intptr_t>(new_code->instruction_start()),
1827 reinterpret_cast<intptr_t>(new_code->instruction_start()) +
1828 new_code->instruction_size(),
1829 new_code->instruction_size(),
1830 reinterpret_cast<intptr_t>(frame->pc()),
1831 reinterpret_cast<intptr_t>(new_pc));
1832 }
1833
1834 if (FLAG_enable_ool_constant_pool) {
1835 // Update constant pool pointer for new code.
1836 frame->set_constant_pool(new_code->constant_pool());
1837 }
1838
1839 // Patch the return address to return into the code with
1840 // debug break slots.
1841 frame->set_pc(new_pc);
1842 }
1843 }
1844
1845
1846 class ActiveFunctionsCollector : public ThreadVisitor {
1847 public:
ActiveFunctionsCollector(List<Handle<JSFunction>> * active_functions,Object * active_code_marker)1848 explicit ActiveFunctionsCollector(List<Handle<JSFunction> >* active_functions,
1849 Object* active_code_marker)
1850 : active_functions_(active_functions),
1851 active_code_marker_(active_code_marker) { }
1852
VisitThread(Isolate * isolate,ThreadLocalTop * top)1853 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
1854 CollectActiveFunctionsFromThread(isolate,
1855 top,
1856 active_functions_,
1857 active_code_marker_);
1858 }
1859
1860 private:
1861 List<Handle<JSFunction> >* active_functions_;
1862 Object* active_code_marker_;
1863 };
1864
1865
1866 class ActiveFunctionsRedirector : public ThreadVisitor {
1867 public:
VisitThread(Isolate * isolate,ThreadLocalTop * top)1868 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
1869 RedirectActivationsToRecompiledCodeOnThread(isolate, top);
1870 }
1871 };
1872
1873
EnsureFunctionHasDebugBreakSlots(Handle<JSFunction> function)1874 static void EnsureFunctionHasDebugBreakSlots(Handle<JSFunction> function) {
1875 if (function->code()->kind() == Code::FUNCTION &&
1876 function->code()->has_debug_break_slots()) {
1877 // Nothing to do. Function code already had debug break slots.
1878 return;
1879 }
1880 // Make sure that the shared full code is compiled with debug
1881 // break slots.
1882 if (!function->shared()->code()->has_debug_break_slots()) {
1883 MaybeHandle<Code> code = Compiler::GetDebugCode(function);
1884 // Recompilation can fail. In that case leave the code as it was.
1885 if (!code.is_null()) function->ReplaceCode(*code.ToHandleChecked());
1886 } else {
1887 // Simply use shared code if it has debug break slots.
1888 function->ReplaceCode(function->shared()->code());
1889 }
1890 }
1891
1892
RecompileAndRelocateSuspendedGenerators(const List<Handle<JSGeneratorObject>> & generators)1893 static void RecompileAndRelocateSuspendedGenerators(
1894 const List<Handle<JSGeneratorObject> > &generators) {
1895 for (int i = 0; i < generators.length(); i++) {
1896 Handle<JSFunction> fun(generators[i]->function());
1897
1898 EnsureFunctionHasDebugBreakSlots(fun);
1899
1900 int code_offset = generators[i]->continuation();
1901 int pc_offset = ComputePcOffsetFromCodeOffset(fun->code(), code_offset);
1902 generators[i]->set_continuation(pc_offset);
1903 }
1904 }
1905
1906
PrepareForBreakPoints()1907 void Debug::PrepareForBreakPoints() {
1908 // If preparing for the first break point make sure to deoptimize all
1909 // functions as debugging does not work with optimized code.
1910 if (!has_break_points_) {
1911 if (isolate_->concurrent_recompilation_enabled()) {
1912 isolate_->optimizing_compiler_thread()->Flush();
1913 }
1914
1915 Deoptimizer::DeoptimizeAll(isolate_);
1916
1917 Handle<Code> lazy_compile = isolate_->builtins()->CompileLazy();
1918
1919 // There will be at least one break point when we are done.
1920 has_break_points_ = true;
1921
1922 // Keep the list of activated functions in a handlified list as it
1923 // is used both in GC and non-GC code.
1924 List<Handle<JSFunction> > active_functions(100);
1925
1926 // A list of all suspended generators.
1927 List<Handle<JSGeneratorObject> > suspended_generators;
1928
1929 // A list of all generator functions. We need to recompile all functions,
1930 // but we don't know until after visiting the whole heap which generator
1931 // functions have suspended activations and which do not. As in the case of
1932 // functions with activations on the stack, we need to be careful with
1933 // generator functions with suspended activations because although they
1934 // should be recompiled, recompilation can fail, and we need to avoid
1935 // leaving the heap in an inconsistent state.
1936 //
1937 // We could perhaps avoid this list and instead re-use the GC metadata
1938 // links.
1939 List<Handle<JSFunction> > generator_functions;
1940
1941 {
1942 // We are going to iterate heap to find all functions without
1943 // debug break slots.
1944 Heap* heap = isolate_->heap();
1945 heap->CollectAllGarbage(Heap::kMakeHeapIterableMask,
1946 "preparing for breakpoints");
1947 HeapIterator iterator(heap);
1948
1949 // Ensure no GC in this scope as we are going to use gc_metadata
1950 // field in the Code object to mark active functions.
1951 DisallowHeapAllocation no_allocation;
1952
1953 Object* active_code_marker = heap->the_hole_value();
1954
1955 CollectActiveFunctionsFromThread(isolate_,
1956 isolate_->thread_local_top(),
1957 &active_functions,
1958 active_code_marker);
1959 ActiveFunctionsCollector active_functions_collector(&active_functions,
1960 active_code_marker);
1961 isolate_->thread_manager()->IterateArchivedThreads(
1962 &active_functions_collector);
1963
1964 // Scan the heap for all non-optimized functions which have no
1965 // debug break slots and are not active or inlined into an active
1966 // function and mark them for lazy compilation.
1967 HeapObject* obj = NULL;
1968 while (((obj = iterator.next()) != NULL)) {
1969 if (obj->IsJSFunction()) {
1970 JSFunction* function = JSFunction::cast(obj);
1971 SharedFunctionInfo* shared = function->shared();
1972
1973 if (!shared->allows_lazy_compilation()) continue;
1974 if (!shared->script()->IsScript()) continue;
1975 if (function->IsFromNativeScript()) continue;
1976 if (shared->code()->gc_metadata() == active_code_marker) continue;
1977
1978 if (shared->is_generator()) {
1979 generator_functions.Add(Handle<JSFunction>(function, isolate_));
1980 continue;
1981 }
1982
1983 Code::Kind kind = function->code()->kind();
1984 if (kind == Code::FUNCTION &&
1985 !function->code()->has_debug_break_slots()) {
1986 function->ReplaceCode(*lazy_compile);
1987 function->shared()->ReplaceCode(*lazy_compile);
1988 } else if (kind == Code::BUILTIN &&
1989 (function->IsInOptimizationQueue() ||
1990 function->IsMarkedForOptimization() ||
1991 function->IsMarkedForConcurrentOptimization())) {
1992 // Abort in-flight compilation.
1993 Code* shared_code = function->shared()->code();
1994 if (shared_code->kind() == Code::FUNCTION &&
1995 shared_code->has_debug_break_slots()) {
1996 function->ReplaceCode(shared_code);
1997 } else {
1998 function->ReplaceCode(*lazy_compile);
1999 function->shared()->ReplaceCode(*lazy_compile);
2000 }
2001 }
2002 } else if (obj->IsJSGeneratorObject()) {
2003 JSGeneratorObject* gen = JSGeneratorObject::cast(obj);
2004 if (!gen->is_suspended()) continue;
2005
2006 JSFunction* fun = gen->function();
2007 DCHECK_EQ(fun->code()->kind(), Code::FUNCTION);
2008 if (fun->code()->has_debug_break_slots()) continue;
2009
2010 int pc_offset = gen->continuation();
2011 DCHECK_LT(0, pc_offset);
2012
2013 int code_offset =
2014 ComputeCodeOffsetFromPcOffset(fun->code(), pc_offset);
2015
2016 // This will be fixed after we recompile the functions.
2017 gen->set_continuation(code_offset);
2018
2019 suspended_generators.Add(Handle<JSGeneratorObject>(gen, isolate_));
2020 }
2021 }
2022
2023 // Clear gc_metadata field.
2024 for (int i = 0; i < active_functions.length(); i++) {
2025 Handle<JSFunction> function = active_functions[i];
2026 function->shared()->code()->set_gc_metadata(Smi::FromInt(0));
2027 }
2028 }
2029
2030 // Recompile generator functions that have suspended activations, and
2031 // relocate those activations.
2032 RecompileAndRelocateSuspendedGenerators(suspended_generators);
2033
2034 // Mark generator functions that didn't have suspended activations for lazy
2035 // recompilation. Note that this set does not include any active functions.
2036 for (int i = 0; i < generator_functions.length(); i++) {
2037 Handle<JSFunction> &function = generator_functions[i];
2038 if (function->code()->kind() != Code::FUNCTION) continue;
2039 if (function->code()->has_debug_break_slots()) continue;
2040 function->ReplaceCode(*lazy_compile);
2041 function->shared()->ReplaceCode(*lazy_compile);
2042 }
2043
2044 // Now recompile all functions with activation frames and and
2045 // patch the return address to run in the new compiled code. It could be
2046 // that some active functions were recompiled already by the suspended
2047 // generator recompilation pass above; a generator with suspended
2048 // activations could also have active activations. That's fine.
2049 for (int i = 0; i < active_functions.length(); i++) {
2050 Handle<JSFunction> function = active_functions[i];
2051 Handle<SharedFunctionInfo> shared(function->shared());
2052
2053 // If recompilation is not possible just skip it.
2054 if (shared->is_toplevel()) continue;
2055 if (!shared->allows_lazy_compilation()) continue;
2056 if (shared->code()->kind() == Code::BUILTIN) continue;
2057
2058 EnsureFunctionHasDebugBreakSlots(function);
2059 }
2060
2061 RedirectActivationsToRecompiledCodeOnThread(isolate_,
2062 isolate_->thread_local_top());
2063
2064 ActiveFunctionsRedirector active_functions_redirector;
2065 isolate_->thread_manager()->IterateArchivedThreads(
2066 &active_functions_redirector);
2067 }
2068 }
2069
2070
FindSharedFunctionInfoInScript(Handle<Script> script,int position)2071 Object* Debug::FindSharedFunctionInfoInScript(Handle<Script> script,
2072 int position) {
2073 // Iterate the heap looking for SharedFunctionInfo generated from the
2074 // script. The inner most SharedFunctionInfo containing the source position
2075 // for the requested break point is found.
2076 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
2077 // which is found is not compiled it is compiled and the heap is iterated
2078 // again as the compilation might create inner functions from the newly
2079 // compiled function and the actual requested break point might be in one of
2080 // these functions.
2081 // NOTE: The below fix-point iteration depends on all functions that cannot be
2082 // compiled lazily without a context to not be compiled at all. Compilation
2083 // will be triggered at points where we do not need a context.
2084 bool done = false;
2085 // The current candidate for the source position:
2086 int target_start_position = RelocInfo::kNoPosition;
2087 Handle<JSFunction> target_function;
2088 Handle<SharedFunctionInfo> target;
2089 Heap* heap = isolate_->heap();
2090 while (!done) {
2091 { // Extra scope for iterator.
2092 HeapIterator iterator(heap);
2093 for (HeapObject* obj = iterator.next();
2094 obj != NULL; obj = iterator.next()) {
2095 bool found_next_candidate = false;
2096 Handle<JSFunction> function;
2097 Handle<SharedFunctionInfo> shared;
2098 if (obj->IsJSFunction()) {
2099 function = Handle<JSFunction>(JSFunction::cast(obj));
2100 shared = Handle<SharedFunctionInfo>(function->shared());
2101 DCHECK(shared->allows_lazy_compilation() || shared->is_compiled());
2102 found_next_candidate = true;
2103 } else if (obj->IsSharedFunctionInfo()) {
2104 shared = Handle<SharedFunctionInfo>(SharedFunctionInfo::cast(obj));
2105 // Skip functions that we cannot compile lazily without a context,
2106 // which is not available here, because there is no closure.
2107 found_next_candidate = shared->is_compiled() ||
2108 shared->allows_lazy_compilation_without_context();
2109 }
2110 if (!found_next_candidate) continue;
2111 if (shared->script() == *script) {
2112 // If the SharedFunctionInfo found has the requested script data and
2113 // contains the source position it is a candidate.
2114 int start_position = shared->function_token_position();
2115 if (start_position == RelocInfo::kNoPosition) {
2116 start_position = shared->start_position();
2117 }
2118 if (start_position <= position &&
2119 position <= shared->end_position()) {
2120 // If there is no candidate or this function is within the current
2121 // candidate this is the new candidate.
2122 if (target.is_null()) {
2123 target_start_position = start_position;
2124 target_function = function;
2125 target = shared;
2126 } else {
2127 if (target_start_position == start_position &&
2128 shared->end_position() == target->end_position()) {
2129 // If a top-level function contains only one function
2130 // declaration the source for the top-level and the function
2131 // is the same. In that case prefer the non top-level function.
2132 if (!shared->is_toplevel()) {
2133 target_start_position = start_position;
2134 target_function = function;
2135 target = shared;
2136 }
2137 } else if (target_start_position <= start_position &&
2138 shared->end_position() <= target->end_position()) {
2139 // This containment check includes equality as a function
2140 // inside a top-level function can share either start or end
2141 // position with the top-level function.
2142 target_start_position = start_position;
2143 target_function = function;
2144 target = shared;
2145 }
2146 }
2147 }
2148 }
2149 } // End for loop.
2150 } // End no-allocation scope.
2151
2152 if (target.is_null()) return heap->undefined_value();
2153
2154 // There will be at least one break point when we are done.
2155 has_break_points_ = true;
2156
2157 // If the candidate found is compiled we are done.
2158 done = target->is_compiled();
2159 if (!done) {
2160 // If the candidate is not compiled, compile it to reveal any inner
2161 // functions which might contain the requested source position. This
2162 // will compile all inner functions that cannot be compiled without a
2163 // context, because Compiler::BuildFunctionInfo checks whether the
2164 // debugger is active.
2165 MaybeHandle<Code> maybe_result = target_function.is_null()
2166 ? Compiler::GetUnoptimizedCode(target)
2167 : Compiler::GetUnoptimizedCode(target_function);
2168 if (maybe_result.is_null()) return isolate_->heap()->undefined_value();
2169 }
2170 } // End while loop.
2171
2172 return *target;
2173 }
2174
2175
2176 // Ensures the debug information is present for shared.
EnsureDebugInfo(Handle<SharedFunctionInfo> shared,Handle<JSFunction> function)2177 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared,
2178 Handle<JSFunction> function) {
2179 Isolate* isolate = shared->GetIsolate();
2180
2181 // Return if we already have the debug info for shared.
2182 if (HasDebugInfo(shared)) {
2183 DCHECK(shared->is_compiled());
2184 return true;
2185 }
2186
2187 // There will be at least one break point when we are done.
2188 has_break_points_ = true;
2189
2190 // Ensure function is compiled. Return false if this failed.
2191 if (!function.is_null() &&
2192 !Compiler::EnsureCompiled(function, CLEAR_EXCEPTION)) {
2193 return false;
2194 }
2195
2196 // Create the debug info object.
2197 Handle<DebugInfo> debug_info = isolate->factory()->NewDebugInfo(shared);
2198
2199 // Add debug info to the list.
2200 DebugInfoListNode* node = new DebugInfoListNode(*debug_info);
2201 node->set_next(debug_info_list_);
2202 debug_info_list_ = node;
2203
2204 return true;
2205 }
2206
2207
RemoveDebugInfo(Handle<DebugInfo> debug_info)2208 void Debug::RemoveDebugInfo(Handle<DebugInfo> debug_info) {
2209 DCHECK(debug_info_list_ != NULL);
2210 // Run through the debug info objects to find this one and remove it.
2211 DebugInfoListNode* prev = NULL;
2212 DebugInfoListNode* current = debug_info_list_;
2213 while (current != NULL) {
2214 if (*current->debug_info() == *debug_info) {
2215 // Unlink from list. If prev is NULL we are looking at the first element.
2216 if (prev == NULL) {
2217 debug_info_list_ = current->next();
2218 } else {
2219 prev->set_next(current->next());
2220 }
2221 current->debug_info()->shared()->set_debug_info(
2222 isolate_->heap()->undefined_value());
2223 delete current;
2224
2225 // If there are no more debug info objects there are not more break
2226 // points.
2227 has_break_points_ = debug_info_list_ != NULL;
2228
2229 return;
2230 }
2231 // Move to next in list.
2232 prev = current;
2233 current = current->next();
2234 }
2235 UNREACHABLE();
2236 }
2237
2238
SetAfterBreakTarget(JavaScriptFrame * frame)2239 void Debug::SetAfterBreakTarget(JavaScriptFrame* frame) {
2240 after_break_target_ = NULL;
2241
2242 if (LiveEdit::SetAfterBreakTarget(this)) return; // LiveEdit did the job.
2243
2244 HandleScope scope(isolate_);
2245 PrepareForBreakPoints();
2246
2247 // Get the executing function in which the debug break occurred.
2248 Handle<JSFunction> function(JSFunction::cast(frame->function()));
2249 Handle<SharedFunctionInfo> shared(function->shared());
2250 if (!EnsureDebugInfo(shared, function)) {
2251 // Return if we failed to retrieve the debug info.
2252 return;
2253 }
2254 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
2255 Handle<Code> code(debug_info->code());
2256 Handle<Code> original_code(debug_info->original_code());
2257 #ifdef DEBUG
2258 // Get the code which is actually executing.
2259 Handle<Code> frame_code(frame->LookupCode());
2260 DCHECK(frame_code.is_identical_to(code));
2261 #endif
2262
2263 // Find the call address in the running code. This address holds the call to
2264 // either a DebugBreakXXX or to the debug break return entry code if the
2265 // break point is still active after processing the break point.
2266 Address addr = Assembler::break_address_from_return_address(frame->pc());
2267
2268 // Check if the location is at JS exit or debug break slot.
2269 bool at_js_return = false;
2270 bool break_at_js_return_active = false;
2271 bool at_debug_break_slot = false;
2272 RelocIterator it(debug_info->code());
2273 while (!it.done() && !at_js_return && !at_debug_break_slot) {
2274 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
2275 at_js_return = (it.rinfo()->pc() ==
2276 addr - Assembler::kPatchReturnSequenceAddressOffset);
2277 break_at_js_return_active = it.rinfo()->IsPatchedReturnSequence();
2278 }
2279 if (RelocInfo::IsDebugBreakSlot(it.rinfo()->rmode())) {
2280 at_debug_break_slot = (it.rinfo()->pc() ==
2281 addr - Assembler::kPatchDebugBreakSlotAddressOffset);
2282 }
2283 it.next();
2284 }
2285
2286 // Handle the jump to continue execution after break point depending on the
2287 // break location.
2288 if (at_js_return) {
2289 // If the break point as return is still active jump to the corresponding
2290 // place in the original code. If not the break point was removed during
2291 // break point processing.
2292 if (break_at_js_return_active) {
2293 addr += original_code->instruction_start() - code->instruction_start();
2294 }
2295
2296 // Move back to where the call instruction sequence started.
2297 after_break_target_ = addr - Assembler::kPatchReturnSequenceAddressOffset;
2298 } else if (at_debug_break_slot) {
2299 // Address of where the debug break slot starts.
2300 addr = addr - Assembler::kPatchDebugBreakSlotAddressOffset;
2301
2302 // Continue just after the slot.
2303 after_break_target_ = addr + Assembler::kDebugBreakSlotLength;
2304 } else {
2305 addr = Assembler::target_address_from_return_address(frame->pc());
2306 if (IsDebugBreak(Assembler::target_address_at(addr, *code))) {
2307 // We now know that there is still a debug break call at the target
2308 // address, so the break point is still there and the original code will
2309 // hold the address to jump to in order to complete the call which is
2310 // replaced by a call to DebugBreakXXX.
2311
2312 // Find the corresponding address in the original code.
2313 addr += original_code->instruction_start() - code->instruction_start();
2314
2315 // Install jump to the call address in the original code. This will be the
2316 // call which was overwritten by the call to DebugBreakXXX.
2317 after_break_target_ = Assembler::target_address_at(addr, *original_code);
2318 } else {
2319 // There is no longer a break point present. Don't try to look in the
2320 // original code as the running code will have the right address. This
2321 // takes care of the case where the last break point is removed from the
2322 // function and therefore no "original code" is available.
2323 after_break_target_ = Assembler::target_address_at(addr, *code);
2324 }
2325 }
2326 }
2327
2328
IsBreakAtReturn(JavaScriptFrame * frame)2329 bool Debug::IsBreakAtReturn(JavaScriptFrame* frame) {
2330 HandleScope scope(isolate_);
2331
2332 // If there are no break points this cannot be break at return, as
2333 // the debugger statement and stack guard bebug break cannot be at
2334 // return.
2335 if (!has_break_points_) {
2336 return false;
2337 }
2338
2339 PrepareForBreakPoints();
2340
2341 // Get the executing function in which the debug break occurred.
2342 Handle<JSFunction> function(JSFunction::cast(frame->function()));
2343 Handle<SharedFunctionInfo> shared(function->shared());
2344 if (!EnsureDebugInfo(shared, function)) {
2345 // Return if we failed to retrieve the debug info.
2346 return false;
2347 }
2348 Handle<DebugInfo> debug_info = GetDebugInfo(shared);
2349 Handle<Code> code(debug_info->code());
2350 #ifdef DEBUG
2351 // Get the code which is actually executing.
2352 Handle<Code> frame_code(frame->LookupCode());
2353 DCHECK(frame_code.is_identical_to(code));
2354 #endif
2355
2356 // Find the call address in the running code.
2357 Address addr = Assembler::break_address_from_return_address(frame->pc());
2358
2359 // Check if the location is at JS return.
2360 RelocIterator it(debug_info->code());
2361 while (!it.done()) {
2362 if (RelocInfo::IsJSReturn(it.rinfo()->rmode())) {
2363 return (it.rinfo()->pc() ==
2364 addr - Assembler::kPatchReturnSequenceAddressOffset);
2365 }
2366 it.next();
2367 }
2368 return false;
2369 }
2370
2371
FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,LiveEdit::FrameDropMode mode,Object ** restarter_frame_function_pointer)2372 void Debug::FramesHaveBeenDropped(StackFrame::Id new_break_frame_id,
2373 LiveEdit::FrameDropMode mode,
2374 Object** restarter_frame_function_pointer) {
2375 if (mode != LiveEdit::CURRENTLY_SET_MODE) {
2376 thread_local_.frame_drop_mode_ = mode;
2377 }
2378 thread_local_.break_frame_id_ = new_break_frame_id;
2379 thread_local_.restarter_frame_function_pointer_ =
2380 restarter_frame_function_pointer;
2381 }
2382
2383
IsDebugGlobal(GlobalObject * global)2384 bool Debug::IsDebugGlobal(GlobalObject* global) {
2385 return is_loaded() && global == debug_context()->global_object();
2386 }
2387
2388
ClearMirrorCache()2389 void Debug::ClearMirrorCache() {
2390 PostponeInterruptsScope postpone(isolate_);
2391 HandleScope scope(isolate_);
2392 AssertDebugContext();
2393 Factory* factory = isolate_->factory();
2394 Handle<GlobalObject> global(isolate_->global_object());
2395 JSObject::SetProperty(global,
2396 factory->NewStringFromAsciiChecked("next_handle_"),
2397 handle(Smi::FromInt(0), isolate_), SLOPPY).Check();
2398 JSObject::SetProperty(global,
2399 factory->NewStringFromAsciiChecked("mirror_cache_"),
2400 factory->NewJSArray(0, FAST_ELEMENTS), SLOPPY).Check();
2401 }
2402
2403
GetLoadedScripts()2404 Handle<FixedArray> Debug::GetLoadedScripts() {
2405 // Create and fill the script cache when the loaded scripts is requested for
2406 // the first time.
2407 if (script_cache_ == NULL) script_cache_ = new ScriptCache(isolate_);
2408
2409 // Perform GC to get unreferenced scripts evicted from the cache before
2410 // returning the content.
2411 isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags,
2412 "Debug::GetLoadedScripts");
2413
2414 // Get the scripts from the cache.
2415 return script_cache_->GetScripts();
2416 }
2417
2418
RecordEvalCaller(Handle<Script> script)2419 void Debug::RecordEvalCaller(Handle<Script> script) {
2420 script->set_compilation_type(Script::COMPILATION_TYPE_EVAL);
2421 // For eval scripts add information on the function from which eval was
2422 // called.
2423 StackTraceFrameIterator it(script->GetIsolate());
2424 if (!it.done()) {
2425 script->set_eval_from_shared(it.frame()->function()->shared());
2426 Code* code = it.frame()->LookupCode();
2427 int offset = static_cast<int>(
2428 it.frame()->pc() - code->instruction_start());
2429 script->set_eval_from_instructions_offset(Smi::FromInt(offset));
2430 }
2431 }
2432
2433
MakeJSObject(const char * constructor_name,int argc,Handle<Object> argv[])2434 MaybeHandle<Object> Debug::MakeJSObject(const char* constructor_name,
2435 int argc,
2436 Handle<Object> argv[]) {
2437 AssertDebugContext();
2438 // Create the execution state object.
2439 Handle<GlobalObject> global(isolate_->global_object());
2440 Handle<Object> constructor = Object::GetProperty(
2441 isolate_, global, constructor_name).ToHandleChecked();
2442 DCHECK(constructor->IsJSFunction());
2443 if (!constructor->IsJSFunction()) return MaybeHandle<Object>();
2444 // We do not handle interrupts here. In particular, termination interrupts.
2445 PostponeInterruptsScope no_interrupts(isolate_);
2446 return Execution::TryCall(Handle<JSFunction>::cast(constructor),
2447 handle(debug_context()->global_proxy()),
2448 argc,
2449 argv);
2450 }
2451
2452
MakeExecutionState()2453 MaybeHandle<Object> Debug::MakeExecutionState() {
2454 // Create the execution state object.
2455 Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()) };
2456 return MakeJSObject("MakeExecutionState", arraysize(argv), argv);
2457 }
2458
2459
MakeBreakEvent(Handle<Object> break_points_hit)2460 MaybeHandle<Object> Debug::MakeBreakEvent(Handle<Object> break_points_hit) {
2461 // Create the new break event object.
2462 Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()),
2463 break_points_hit };
2464 return MakeJSObject("MakeBreakEvent", arraysize(argv), argv);
2465 }
2466
2467
MakeExceptionEvent(Handle<Object> exception,bool uncaught,Handle<Object> promise)2468 MaybeHandle<Object> Debug::MakeExceptionEvent(Handle<Object> exception,
2469 bool uncaught,
2470 Handle<Object> promise) {
2471 // Create the new exception event object.
2472 Handle<Object> argv[] = { isolate_->factory()->NewNumberFromInt(break_id()),
2473 exception,
2474 isolate_->factory()->ToBoolean(uncaught),
2475 promise };
2476 return MakeJSObject("MakeExceptionEvent", arraysize(argv), argv);
2477 }
2478
2479
MakeCompileEvent(Handle<Script> script,v8::DebugEvent type)2480 MaybeHandle<Object> Debug::MakeCompileEvent(Handle<Script> script,
2481 v8::DebugEvent type) {
2482 // Create the compile event object.
2483 Handle<Object> script_wrapper = Script::GetWrapper(script);
2484 Handle<Object> argv[] = { script_wrapper,
2485 isolate_->factory()->NewNumberFromInt(type) };
2486 return MakeJSObject("MakeCompileEvent", arraysize(argv), argv);
2487 }
2488
2489
MakePromiseEvent(Handle<JSObject> event_data)2490 MaybeHandle<Object> Debug::MakePromiseEvent(Handle<JSObject> event_data) {
2491 // Create the promise event object.
2492 Handle<Object> argv[] = { event_data };
2493 return MakeJSObject("MakePromiseEvent", arraysize(argv), argv);
2494 }
2495
2496
MakeAsyncTaskEvent(Handle<JSObject> task_event)2497 MaybeHandle<Object> Debug::MakeAsyncTaskEvent(Handle<JSObject> task_event) {
2498 // Create the async task event object.
2499 Handle<Object> argv[] = { task_event };
2500 return MakeJSObject("MakeAsyncTaskEvent", arraysize(argv), argv);
2501 }
2502
2503
OnThrow(Handle<Object> exception,bool uncaught)2504 void Debug::OnThrow(Handle<Object> exception, bool uncaught) {
2505 if (in_debug_scope() || ignore_events()) return;
2506 // Temporarily clear any scheduled_exception to allow evaluating
2507 // JavaScript from the debug event handler.
2508 HandleScope scope(isolate_);
2509 Handle<Object> scheduled_exception;
2510 if (isolate_->has_scheduled_exception()) {
2511 scheduled_exception = handle(isolate_->scheduled_exception(), isolate_);
2512 isolate_->clear_scheduled_exception();
2513 }
2514 OnException(exception, uncaught, isolate_->GetPromiseOnStackOnThrow());
2515 if (!scheduled_exception.is_null()) {
2516 isolate_->thread_local_top()->scheduled_exception_ = *scheduled_exception;
2517 }
2518 }
2519
2520
OnPromiseReject(Handle<JSObject> promise,Handle<Object> value)2521 void Debug::OnPromiseReject(Handle<JSObject> promise, Handle<Object> value) {
2522 if (in_debug_scope() || ignore_events()) return;
2523 HandleScope scope(isolate_);
2524 OnException(value, false, promise);
2525 }
2526
2527
OnException(Handle<Object> exception,bool uncaught,Handle<Object> promise)2528 void Debug::OnException(Handle<Object> exception, bool uncaught,
2529 Handle<Object> promise) {
2530 if (promise->IsJSObject()) {
2531 uncaught |= !PromiseHasRejectHandler(Handle<JSObject>::cast(promise));
2532 }
2533 // Bail out if exception breaks are not active
2534 if (uncaught) {
2535 // Uncaught exceptions are reported by either flags.
2536 if (!(break_on_uncaught_exception_ || break_on_exception_)) return;
2537 } else {
2538 // Caught exceptions are reported is activated.
2539 if (!break_on_exception_) return;
2540 }
2541
2542 DebugScope debug_scope(this);
2543 if (debug_scope.failed()) return;
2544
2545 // Clear all current stepping setup.
2546 ClearStepping();
2547
2548 // Create the event data object.
2549 Handle<Object> event_data;
2550 // Bail out and don't call debugger if exception.
2551 if (!MakeExceptionEvent(
2552 exception, uncaught, promise).ToHandle(&event_data)) {
2553 return;
2554 }
2555
2556 // Process debug event.
2557 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false);
2558 // Return to continue execution from where the exception was thrown.
2559 }
2560
2561
OnCompileError(Handle<Script> script)2562 void Debug::OnCompileError(Handle<Script> script) {
2563 // No more to do if not debugging.
2564 if (in_debug_scope() || ignore_events()) return;
2565
2566 HandleScope scope(isolate_);
2567 DebugScope debug_scope(this);
2568 if (debug_scope.failed()) return;
2569
2570 // Create the compile state object.
2571 Handle<Object> event_data;
2572 // Bail out and don't call debugger if exception.
2573 if (!MakeCompileEvent(script, v8::CompileError).ToHandle(&event_data)) return;
2574
2575 // Process debug event.
2576 ProcessDebugEvent(v8::CompileError, Handle<JSObject>::cast(event_data), true);
2577 }
2578
2579
OnDebugBreak(Handle<Object> break_points_hit,bool auto_continue)2580 void Debug::OnDebugBreak(Handle<Object> break_points_hit,
2581 bool auto_continue) {
2582 // The caller provided for DebugScope.
2583 AssertDebugContext();
2584 // Bail out if there is no listener for this event
2585 if (ignore_events()) return;
2586
2587 HandleScope scope(isolate_);
2588 // Create the event data object.
2589 Handle<Object> event_data;
2590 // Bail out and don't call debugger if exception.
2591 if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return;
2592
2593 // Process debug event.
2594 ProcessDebugEvent(v8::Break,
2595 Handle<JSObject>::cast(event_data),
2596 auto_continue);
2597 }
2598
2599
OnBeforeCompile(Handle<Script> script)2600 void Debug::OnBeforeCompile(Handle<Script> script) {
2601 if (in_debug_scope() || ignore_events()) return;
2602
2603 HandleScope scope(isolate_);
2604 DebugScope debug_scope(this);
2605 if (debug_scope.failed()) return;
2606
2607 // Create the event data object.
2608 Handle<Object> event_data;
2609 // Bail out and don't call debugger if exception.
2610 if (!MakeCompileEvent(script, v8::BeforeCompile).ToHandle(&event_data))
2611 return;
2612
2613 // Process debug event.
2614 ProcessDebugEvent(v8::BeforeCompile,
2615 Handle<JSObject>::cast(event_data),
2616 true);
2617 }
2618
2619
2620 // Handle debugger actions when a new script is compiled.
OnAfterCompile(Handle<Script> script)2621 void Debug::OnAfterCompile(Handle<Script> script) {
2622 // Add the newly compiled script to the script cache.
2623 if (script_cache_ != NULL) script_cache_->Add(script);
2624
2625 // No more to do if not debugging.
2626 if (in_debug_scope() || ignore_events()) return;
2627
2628 HandleScope scope(isolate_);
2629 DebugScope debug_scope(this);
2630 if (debug_scope.failed()) return;
2631
2632 // If debugging there might be script break points registered for this
2633 // script. Make sure that these break points are set.
2634
2635 // Get the function UpdateScriptBreakPoints (defined in debug-debugger.js).
2636 Handle<String> update_script_break_points_string =
2637 isolate_->factory()->InternalizeOneByteString(
2638 STATIC_CHAR_VECTOR("UpdateScriptBreakPoints"));
2639 Handle<GlobalObject> debug_global(debug_context()->global_object());
2640 Handle<Object> update_script_break_points =
2641 Object::GetProperty(
2642 debug_global, update_script_break_points_string).ToHandleChecked();
2643 if (!update_script_break_points->IsJSFunction()) {
2644 return;
2645 }
2646 DCHECK(update_script_break_points->IsJSFunction());
2647
2648 // Wrap the script object in a proper JS object before passing it
2649 // to JavaScript.
2650 Handle<Object> wrapper = Script::GetWrapper(script);
2651
2652 // Call UpdateScriptBreakPoints expect no exceptions.
2653 Handle<Object> argv[] = { wrapper };
2654 if (Execution::TryCall(Handle<JSFunction>::cast(update_script_break_points),
2655 isolate_->js_builtins_object(),
2656 arraysize(argv),
2657 argv).is_null()) {
2658 return;
2659 }
2660
2661 // Create the compile state object.
2662 Handle<Object> event_data;
2663 // Bail out and don't call debugger if exception.
2664 if (!MakeCompileEvent(script, v8::AfterCompile).ToHandle(&event_data)) return;
2665
2666 // Process debug event.
2667 ProcessDebugEvent(v8::AfterCompile, Handle<JSObject>::cast(event_data), true);
2668 }
2669
2670
OnPromiseEvent(Handle<JSObject> data)2671 void Debug::OnPromiseEvent(Handle<JSObject> data) {
2672 if (in_debug_scope() || ignore_events()) return;
2673
2674 HandleScope scope(isolate_);
2675 DebugScope debug_scope(this);
2676 if (debug_scope.failed()) return;
2677
2678 // Create the script collected state object.
2679 Handle<Object> event_data;
2680 // Bail out and don't call debugger if exception.
2681 if (!MakePromiseEvent(data).ToHandle(&event_data)) return;
2682
2683 // Process debug event.
2684 ProcessDebugEvent(v8::PromiseEvent,
2685 Handle<JSObject>::cast(event_data),
2686 true);
2687 }
2688
2689
OnAsyncTaskEvent(Handle<JSObject> data)2690 void Debug::OnAsyncTaskEvent(Handle<JSObject> data) {
2691 if (in_debug_scope() || ignore_events()) return;
2692
2693 HandleScope scope(isolate_);
2694 DebugScope debug_scope(this);
2695 if (debug_scope.failed()) return;
2696
2697 // Create the script collected state object.
2698 Handle<Object> event_data;
2699 // Bail out and don't call debugger if exception.
2700 if (!MakeAsyncTaskEvent(data).ToHandle(&event_data)) return;
2701
2702 // Process debug event.
2703 ProcessDebugEvent(v8::AsyncTaskEvent,
2704 Handle<JSObject>::cast(event_data),
2705 true);
2706 }
2707
2708
ProcessDebugEvent(v8::DebugEvent event,Handle<JSObject> event_data,bool auto_continue)2709 void Debug::ProcessDebugEvent(v8::DebugEvent event,
2710 Handle<JSObject> event_data,
2711 bool auto_continue) {
2712 HandleScope scope(isolate_);
2713
2714 // Create the execution state.
2715 Handle<Object> exec_state;
2716 // Bail out and don't call debugger if exception.
2717 if (!MakeExecutionState().ToHandle(&exec_state)) return;
2718
2719 // First notify the message handler if any.
2720 if (message_handler_ != NULL) {
2721 NotifyMessageHandler(event,
2722 Handle<JSObject>::cast(exec_state),
2723 event_data,
2724 auto_continue);
2725 }
2726 // Notify registered debug event listener. This can be either a C or
2727 // a JavaScript function. Don't call event listener for v8::Break
2728 // here, if it's only a debug command -- they will be processed later.
2729 if ((event != v8::Break || !auto_continue) && !event_listener_.is_null()) {
2730 CallEventCallback(event, exec_state, event_data, NULL);
2731 }
2732 // Process pending debug commands.
2733 if (event == v8::Break) {
2734 while (!event_command_queue_.IsEmpty()) {
2735 CommandMessage command = event_command_queue_.Get();
2736 if (!event_listener_.is_null()) {
2737 CallEventCallback(v8::BreakForCommand,
2738 exec_state,
2739 event_data,
2740 command.client_data());
2741 }
2742 command.Dispose();
2743 }
2744 }
2745 }
2746
2747
CallEventCallback(v8::DebugEvent event,Handle<Object> exec_state,Handle<Object> event_data,v8::Debug::ClientData * client_data)2748 void Debug::CallEventCallback(v8::DebugEvent event,
2749 Handle<Object> exec_state,
2750 Handle<Object> event_data,
2751 v8::Debug::ClientData* client_data) {
2752 if (event_listener_->IsForeign()) {
2753 // Invoke the C debug event listener.
2754 v8::Debug::EventCallback callback =
2755 FUNCTION_CAST<v8::Debug::EventCallback>(
2756 Handle<Foreign>::cast(event_listener_)->foreign_address());
2757 EventDetailsImpl event_details(event,
2758 Handle<JSObject>::cast(exec_state),
2759 Handle<JSObject>::cast(event_data),
2760 event_listener_data_,
2761 client_data);
2762 callback(event_details);
2763 DCHECK(!isolate_->has_scheduled_exception());
2764 } else {
2765 // Invoke the JavaScript debug event listener.
2766 DCHECK(event_listener_->IsJSFunction());
2767 Handle<Object> argv[] = { Handle<Object>(Smi::FromInt(event), isolate_),
2768 exec_state,
2769 event_data,
2770 event_listener_data_ };
2771 Handle<JSReceiver> global(isolate_->global_proxy());
2772 Execution::TryCall(Handle<JSFunction>::cast(event_listener_),
2773 global, arraysize(argv), argv);
2774 }
2775 }
2776
2777
GetDebugContext()2778 Handle<Context> Debug::GetDebugContext() {
2779 DebugScope debug_scope(this);
2780 // The global handle may be destroyed soon after. Return it reboxed.
2781 return handle(*debug_context(), isolate_);
2782 }
2783
2784
NotifyMessageHandler(v8::DebugEvent event,Handle<JSObject> exec_state,Handle<JSObject> event_data,bool auto_continue)2785 void Debug::NotifyMessageHandler(v8::DebugEvent event,
2786 Handle<JSObject> exec_state,
2787 Handle<JSObject> event_data,
2788 bool auto_continue) {
2789 // Prevent other interrupts from triggering, for example API callbacks,
2790 // while dispatching message handler callbacks.
2791 PostponeInterruptsScope no_interrupts(isolate_);
2792 DCHECK(is_active_);
2793 HandleScope scope(isolate_);
2794 // Process the individual events.
2795 bool sendEventMessage = false;
2796 switch (event) {
2797 case v8::Break:
2798 case v8::BreakForCommand:
2799 sendEventMessage = !auto_continue;
2800 break;
2801 case v8::Exception:
2802 sendEventMessage = true;
2803 break;
2804 case v8::BeforeCompile:
2805 break;
2806 case v8::AfterCompile:
2807 sendEventMessage = true;
2808 break;
2809 case v8::NewFunction:
2810 break;
2811 default:
2812 UNREACHABLE();
2813 }
2814
2815 // The debug command interrupt flag might have been set when the command was
2816 // added. It should be enough to clear the flag only once while we are in the
2817 // debugger.
2818 DCHECK(in_debug_scope());
2819 isolate_->stack_guard()->ClearDebugCommand();
2820
2821 // Notify the debugger that a debug event has occurred unless auto continue is
2822 // active in which case no event is send.
2823 if (sendEventMessage) {
2824 MessageImpl message = MessageImpl::NewEvent(
2825 event,
2826 auto_continue,
2827 Handle<JSObject>::cast(exec_state),
2828 Handle<JSObject>::cast(event_data));
2829 InvokeMessageHandler(message);
2830 }
2831
2832 // If auto continue don't make the event cause a break, but process messages
2833 // in the queue if any. For script collected events don't even process
2834 // messages in the queue as the execution state might not be what is expected
2835 // by the client.
2836 if (auto_continue && !has_commands()) return;
2837
2838 // DebugCommandProcessor goes here.
2839 bool running = auto_continue;
2840
2841 Handle<Object> cmd_processor_ctor = Object::GetProperty(
2842 isolate_, exec_state, "debugCommandProcessor").ToHandleChecked();
2843 Handle<Object> ctor_args[] = { isolate_->factory()->ToBoolean(running) };
2844 Handle<Object> cmd_processor = Execution::Call(
2845 isolate_, cmd_processor_ctor, exec_state, 1, ctor_args).ToHandleChecked();
2846 Handle<JSFunction> process_debug_request = Handle<JSFunction>::cast(
2847 Object::GetProperty(
2848 isolate_, cmd_processor, "processDebugRequest").ToHandleChecked());
2849 Handle<Object> is_running = Object::GetProperty(
2850 isolate_, cmd_processor, "isRunning").ToHandleChecked();
2851
2852 // Process requests from the debugger.
2853 do {
2854 // Wait for new command in the queue.
2855 command_received_.Wait();
2856
2857 // Get the command from the queue.
2858 CommandMessage command = command_queue_.Get();
2859 isolate_->logger()->DebugTag(
2860 "Got request from command queue, in interactive loop.");
2861 if (!is_active()) {
2862 // Delete command text and user data.
2863 command.Dispose();
2864 return;
2865 }
2866
2867 Vector<const uc16> command_text(
2868 const_cast<const uc16*>(command.text().start()),
2869 command.text().length());
2870 Handle<String> request_text = isolate_->factory()->NewStringFromTwoByte(
2871 command_text).ToHandleChecked();
2872 Handle<Object> request_args[] = { request_text };
2873 Handle<Object> answer_value;
2874 Handle<String> answer;
2875 MaybeHandle<Object> maybe_exception;
2876 MaybeHandle<Object> maybe_result =
2877 Execution::TryCall(process_debug_request, cmd_processor, 1,
2878 request_args, &maybe_exception);
2879
2880 if (maybe_result.ToHandle(&answer_value)) {
2881 if (answer_value->IsUndefined()) {
2882 answer = isolate_->factory()->empty_string();
2883 } else {
2884 answer = Handle<String>::cast(answer_value);
2885 }
2886
2887 // Log the JSON request/response.
2888 if (FLAG_trace_debug_json) {
2889 PrintF("%s\n", request_text->ToCString().get());
2890 PrintF("%s\n", answer->ToCString().get());
2891 }
2892
2893 Handle<Object> is_running_args[] = { answer };
2894 maybe_result = Execution::Call(
2895 isolate_, is_running, cmd_processor, 1, is_running_args);
2896 Handle<Object> result;
2897 if (!maybe_result.ToHandle(&result)) break;
2898 running = result->IsTrue();
2899 } else {
2900 Handle<Object> exception;
2901 if (!maybe_exception.ToHandle(&exception)) break;
2902 Handle<Object> result;
2903 if (!Execution::ToString(isolate_, exception).ToHandle(&result)) break;
2904 answer = Handle<String>::cast(result);
2905 }
2906
2907 // Return the result.
2908 MessageImpl message = MessageImpl::NewResponse(
2909 event, running, exec_state, event_data, answer, command.client_data());
2910 InvokeMessageHandler(message);
2911 command.Dispose();
2912
2913 // Return from debug event processing if either the VM is put into the
2914 // running state (through a continue command) or auto continue is active
2915 // and there are no more commands queued.
2916 } while (!running || has_commands());
2917 command_queue_.Clear();
2918 }
2919
2920
SetEventListener(Handle<Object> callback,Handle<Object> data)2921 void Debug::SetEventListener(Handle<Object> callback,
2922 Handle<Object> data) {
2923 GlobalHandles* global_handles = isolate_->global_handles();
2924
2925 // Remove existing entry.
2926 GlobalHandles::Destroy(event_listener_.location());
2927 event_listener_ = Handle<Object>();
2928 GlobalHandles::Destroy(event_listener_data_.location());
2929 event_listener_data_ = Handle<Object>();
2930
2931 // Set new entry.
2932 if (!callback->IsUndefined() && !callback->IsNull()) {
2933 event_listener_ = global_handles->Create(*callback);
2934 if (data.is_null()) data = isolate_->factory()->undefined_value();
2935 event_listener_data_ = global_handles->Create(*data);
2936 }
2937
2938 UpdateState();
2939 }
2940
2941
SetMessageHandler(v8::Debug::MessageHandler handler)2942 void Debug::SetMessageHandler(v8::Debug::MessageHandler handler) {
2943 message_handler_ = handler;
2944 UpdateState();
2945 if (handler == NULL && in_debug_scope()) {
2946 // Send an empty command to the debugger if in a break to make JavaScript
2947 // run again if the debugger is closed.
2948 EnqueueCommandMessage(Vector<const uint16_t>::empty());
2949 }
2950 }
2951
2952
2953
UpdateState()2954 void Debug::UpdateState() {
2955 is_active_ = message_handler_ != NULL || !event_listener_.is_null();
2956 if (is_active_ || in_debug_scope()) {
2957 // Note that the debug context could have already been loaded to
2958 // bootstrap test cases.
2959 isolate_->compilation_cache()->Disable();
2960 is_active_ = Load();
2961 } else if (is_loaded()) {
2962 isolate_->compilation_cache()->Enable();
2963 Unload();
2964 }
2965 }
2966
2967
2968 // Calls the registered debug message handler. This callback is part of the
2969 // public API.
InvokeMessageHandler(MessageImpl message)2970 void Debug::InvokeMessageHandler(MessageImpl message) {
2971 if (message_handler_ != NULL) message_handler_(message);
2972 }
2973
2974
2975 // Puts a command coming from the public API on the queue. Creates
2976 // a copy of the command string managed by the debugger. Up to this
2977 // point, the command data was managed by the API client. Called
2978 // by the API client thread.
EnqueueCommandMessage(Vector<const uint16_t> command,v8::Debug::ClientData * client_data)2979 void Debug::EnqueueCommandMessage(Vector<const uint16_t> command,
2980 v8::Debug::ClientData* client_data) {
2981 // Need to cast away const.
2982 CommandMessage message = CommandMessage::New(
2983 Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
2984 command.length()),
2985 client_data);
2986 isolate_->logger()->DebugTag("Put command on command_queue.");
2987 command_queue_.Put(message);
2988 command_received_.Signal();
2989
2990 // Set the debug command break flag to have the command processed.
2991 if (!in_debug_scope()) isolate_->stack_guard()->RequestDebugCommand();
2992 }
2993
2994
EnqueueDebugCommand(v8::Debug::ClientData * client_data)2995 void Debug::EnqueueDebugCommand(v8::Debug::ClientData* client_data) {
2996 CommandMessage message = CommandMessage::New(Vector<uint16_t>(), client_data);
2997 event_command_queue_.Put(message);
2998
2999 // Set the debug command break flag to have the command processed.
3000 if (!in_debug_scope()) isolate_->stack_guard()->RequestDebugCommand();
3001 }
3002
3003
Call(Handle<JSFunction> fun,Handle<Object> data)3004 MaybeHandle<Object> Debug::Call(Handle<JSFunction> fun, Handle<Object> data) {
3005 DebugScope debug_scope(this);
3006 if (debug_scope.failed()) return isolate_->factory()->undefined_value();
3007
3008 // Create the execution state.
3009 Handle<Object> exec_state;
3010 if (!MakeExecutionState().ToHandle(&exec_state)) {
3011 return isolate_->factory()->undefined_value();
3012 }
3013
3014 Handle<Object> argv[] = { exec_state, data };
3015 return Execution::Call(
3016 isolate_,
3017 fun,
3018 Handle<Object>(debug_context()->global_proxy(), isolate_),
3019 arraysize(argv),
3020 argv);
3021 }
3022
3023
HandleDebugBreak()3024 void Debug::HandleDebugBreak() {
3025 // Ignore debug break during bootstrapping.
3026 if (isolate_->bootstrapper()->IsActive()) return;
3027 // Just continue if breaks are disabled.
3028 if (break_disabled_) return;
3029 // Ignore debug break if debugger is not active.
3030 if (!is_active()) return;
3031
3032 StackLimitCheck check(isolate_);
3033 if (check.HasOverflowed()) return;
3034
3035 { JavaScriptFrameIterator it(isolate_);
3036 DCHECK(!it.done());
3037 Object* fun = it.frame()->function();
3038 if (fun && fun->IsJSFunction()) {
3039 // Don't stop in builtin functions.
3040 if (JSFunction::cast(fun)->IsBuiltin()) return;
3041 GlobalObject* global = JSFunction::cast(fun)->context()->global_object();
3042 // Don't stop in debugger functions.
3043 if (IsDebugGlobal(global)) return;
3044 }
3045 }
3046
3047 // Collect the break state before clearing the flags.
3048 bool debug_command_only = isolate_->stack_guard()->CheckDebugCommand() &&
3049 !isolate_->stack_guard()->CheckDebugBreak();
3050
3051 isolate_->stack_guard()->ClearDebugBreak();
3052
3053 ProcessDebugMessages(debug_command_only);
3054 }
3055
3056
ProcessDebugMessages(bool debug_command_only)3057 void Debug::ProcessDebugMessages(bool debug_command_only) {
3058 isolate_->stack_guard()->ClearDebugCommand();
3059
3060 StackLimitCheck check(isolate_);
3061 if (check.HasOverflowed()) return;
3062
3063 HandleScope scope(isolate_);
3064 DebugScope debug_scope(this);
3065 if (debug_scope.failed()) return;
3066
3067 // Notify the debug event listeners. Indicate auto continue if the break was
3068 // a debug command break.
3069 OnDebugBreak(isolate_->factory()->undefined_value(), debug_command_only);
3070 }
3071
3072
DebugScope(Debug * debug)3073 DebugScope::DebugScope(Debug* debug)
3074 : debug_(debug),
3075 prev_(debug->debugger_entry()),
3076 save_(debug_->isolate_),
3077 no_termination_exceptons_(debug_->isolate_,
3078 StackGuard::TERMINATE_EXECUTION) {
3079 // Link recursive debugger entry.
3080 debug_->thread_local_.current_debug_scope_ = this;
3081
3082 // Store the previous break id and frame id.
3083 break_id_ = debug_->break_id();
3084 break_frame_id_ = debug_->break_frame_id();
3085
3086 // Create the new break info. If there is no JavaScript frames there is no
3087 // break frame id.
3088 JavaScriptFrameIterator it(isolate());
3089 bool has_js_frames = !it.done();
3090 debug_->thread_local_.break_frame_id_ = has_js_frames ? it.frame()->id()
3091 : StackFrame::NO_ID;
3092 debug_->SetNextBreakId();
3093
3094 debug_->UpdateState();
3095 // Make sure that debugger is loaded and enter the debugger context.
3096 // The previous context is kept in save_.
3097 failed_ = !debug_->is_loaded();
3098 if (!failed_) isolate()->set_context(*debug->debug_context());
3099 }
3100
3101
3102
~DebugScope()3103 DebugScope::~DebugScope() {
3104 if (!failed_ && prev_ == NULL) {
3105 // Clear mirror cache when leaving the debugger. Skip this if there is a
3106 // pending exception as clearing the mirror cache calls back into
3107 // JavaScript. This can happen if the v8::Debug::Call is used in which
3108 // case the exception should end up in the calling code.
3109 if (!isolate()->has_pending_exception()) debug_->ClearMirrorCache();
3110
3111 // If there are commands in the queue when leaving the debugger request
3112 // that these commands are processed.
3113 if (debug_->has_commands()) isolate()->stack_guard()->RequestDebugCommand();
3114 }
3115
3116 // Leaving this debugger entry.
3117 debug_->thread_local_.current_debug_scope_ = prev_;
3118
3119 // Restore to the previous break state.
3120 debug_->thread_local_.break_frame_id_ = break_frame_id_;
3121 debug_->thread_local_.break_id_ = break_id_;
3122
3123 debug_->UpdateState();
3124 }
3125
3126
NewEvent(DebugEvent event,bool running,Handle<JSObject> exec_state,Handle<JSObject> event_data)3127 MessageImpl MessageImpl::NewEvent(DebugEvent event,
3128 bool running,
3129 Handle<JSObject> exec_state,
3130 Handle<JSObject> event_data) {
3131 MessageImpl message(true, event, running,
3132 exec_state, event_data, Handle<String>(), NULL);
3133 return message;
3134 }
3135
3136
NewResponse(DebugEvent event,bool running,Handle<JSObject> exec_state,Handle<JSObject> event_data,Handle<String> response_json,v8::Debug::ClientData * client_data)3137 MessageImpl MessageImpl::NewResponse(DebugEvent event,
3138 bool running,
3139 Handle<JSObject> exec_state,
3140 Handle<JSObject> event_data,
3141 Handle<String> response_json,
3142 v8::Debug::ClientData* client_data) {
3143 MessageImpl message(false, event, running,
3144 exec_state, event_data, response_json, client_data);
3145 return message;
3146 }
3147
3148
MessageImpl(bool is_event,DebugEvent event,bool running,Handle<JSObject> exec_state,Handle<JSObject> event_data,Handle<String> response_json,v8::Debug::ClientData * client_data)3149 MessageImpl::MessageImpl(bool is_event,
3150 DebugEvent event,
3151 bool running,
3152 Handle<JSObject> exec_state,
3153 Handle<JSObject> event_data,
3154 Handle<String> response_json,
3155 v8::Debug::ClientData* client_data)
3156 : is_event_(is_event),
3157 event_(event),
3158 running_(running),
3159 exec_state_(exec_state),
3160 event_data_(event_data),
3161 response_json_(response_json),
3162 client_data_(client_data) {}
3163
3164
IsEvent() const3165 bool MessageImpl::IsEvent() const {
3166 return is_event_;
3167 }
3168
3169
IsResponse() const3170 bool MessageImpl::IsResponse() const {
3171 return !is_event_;
3172 }
3173
3174
GetEvent() const3175 DebugEvent MessageImpl::GetEvent() const {
3176 return event_;
3177 }
3178
3179
WillStartRunning() const3180 bool MessageImpl::WillStartRunning() const {
3181 return running_;
3182 }
3183
3184
GetExecutionState() const3185 v8::Handle<v8::Object> MessageImpl::GetExecutionState() const {
3186 return v8::Utils::ToLocal(exec_state_);
3187 }
3188
3189
GetIsolate() const3190 v8::Isolate* MessageImpl::GetIsolate() const {
3191 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate());
3192 }
3193
3194
GetEventData() const3195 v8::Handle<v8::Object> MessageImpl::GetEventData() const {
3196 return v8::Utils::ToLocal(event_data_);
3197 }
3198
3199
GetJSON() const3200 v8::Handle<v8::String> MessageImpl::GetJSON() const {
3201 Isolate* isolate = event_data_->GetIsolate();
3202 v8::EscapableHandleScope scope(reinterpret_cast<v8::Isolate*>(isolate));
3203
3204 if (IsEvent()) {
3205 // Call toJSONProtocol on the debug event object.
3206 Handle<Object> fun = Object::GetProperty(
3207 isolate, event_data_, "toJSONProtocol").ToHandleChecked();
3208 if (!fun->IsJSFunction()) {
3209 return v8::Handle<v8::String>();
3210 }
3211
3212 MaybeHandle<Object> maybe_json =
3213 Execution::TryCall(Handle<JSFunction>::cast(fun), event_data_, 0, NULL);
3214 Handle<Object> json;
3215 if (!maybe_json.ToHandle(&json) || !json->IsString()) {
3216 return v8::Handle<v8::String>();
3217 }
3218 return scope.Escape(v8::Utils::ToLocal(Handle<String>::cast(json)));
3219 } else {
3220 return v8::Utils::ToLocal(response_json_);
3221 }
3222 }
3223
3224
GetEventContext() const3225 v8::Handle<v8::Context> MessageImpl::GetEventContext() const {
3226 Isolate* isolate = event_data_->GetIsolate();
3227 v8::Handle<v8::Context> context = GetDebugEventContext(isolate);
3228 // Isolate::context() may be NULL when "script collected" event occures.
3229 DCHECK(!context.IsEmpty());
3230 return context;
3231 }
3232
3233
GetClientData() const3234 v8::Debug::ClientData* MessageImpl::GetClientData() const {
3235 return client_data_;
3236 }
3237
3238
EventDetailsImpl(DebugEvent event,Handle<JSObject> exec_state,Handle<JSObject> event_data,Handle<Object> callback_data,v8::Debug::ClientData * client_data)3239 EventDetailsImpl::EventDetailsImpl(DebugEvent event,
3240 Handle<JSObject> exec_state,
3241 Handle<JSObject> event_data,
3242 Handle<Object> callback_data,
3243 v8::Debug::ClientData* client_data)
3244 : event_(event),
3245 exec_state_(exec_state),
3246 event_data_(event_data),
3247 callback_data_(callback_data),
3248 client_data_(client_data) {}
3249
3250
GetEvent() const3251 DebugEvent EventDetailsImpl::GetEvent() const {
3252 return event_;
3253 }
3254
3255
GetExecutionState() const3256 v8::Handle<v8::Object> EventDetailsImpl::GetExecutionState() const {
3257 return v8::Utils::ToLocal(exec_state_);
3258 }
3259
3260
GetEventData() const3261 v8::Handle<v8::Object> EventDetailsImpl::GetEventData() const {
3262 return v8::Utils::ToLocal(event_data_);
3263 }
3264
3265
GetEventContext() const3266 v8::Handle<v8::Context> EventDetailsImpl::GetEventContext() const {
3267 return GetDebugEventContext(exec_state_->GetIsolate());
3268 }
3269
3270
GetCallbackData() const3271 v8::Handle<v8::Value> EventDetailsImpl::GetCallbackData() const {
3272 return v8::Utils::ToLocal(callback_data_);
3273 }
3274
3275
GetClientData() const3276 v8::Debug::ClientData* EventDetailsImpl::GetClientData() const {
3277 return client_data_;
3278 }
3279
3280
CommandMessage()3281 CommandMessage::CommandMessage() : text_(Vector<uint16_t>::empty()),
3282 client_data_(NULL) {
3283 }
3284
3285
CommandMessage(const Vector<uint16_t> & text,v8::Debug::ClientData * data)3286 CommandMessage::CommandMessage(const Vector<uint16_t>& text,
3287 v8::Debug::ClientData* data)
3288 : text_(text),
3289 client_data_(data) {
3290 }
3291
3292
Dispose()3293 void CommandMessage::Dispose() {
3294 text_.Dispose();
3295 delete client_data_;
3296 client_data_ = NULL;
3297 }
3298
3299
New(const Vector<uint16_t> & command,v8::Debug::ClientData * data)3300 CommandMessage CommandMessage::New(const Vector<uint16_t>& command,
3301 v8::Debug::ClientData* data) {
3302 return CommandMessage(command.Clone(), data);
3303 }
3304
3305
CommandMessageQueue(int size)3306 CommandMessageQueue::CommandMessageQueue(int size) : start_(0), end_(0),
3307 size_(size) {
3308 messages_ = NewArray<CommandMessage>(size);
3309 }
3310
3311
~CommandMessageQueue()3312 CommandMessageQueue::~CommandMessageQueue() {
3313 while (!IsEmpty()) Get().Dispose();
3314 DeleteArray(messages_);
3315 }
3316
3317
Get()3318 CommandMessage CommandMessageQueue::Get() {
3319 DCHECK(!IsEmpty());
3320 int result = start_;
3321 start_ = (start_ + 1) % size_;
3322 return messages_[result];
3323 }
3324
3325
Put(const CommandMessage & message)3326 void CommandMessageQueue::Put(const CommandMessage& message) {
3327 if ((end_ + 1) % size_ == start_) {
3328 Expand();
3329 }
3330 messages_[end_] = message;
3331 end_ = (end_ + 1) % size_;
3332 }
3333
3334
Expand()3335 void CommandMessageQueue::Expand() {
3336 CommandMessageQueue new_queue(size_ * 2);
3337 while (!IsEmpty()) {
3338 new_queue.Put(Get());
3339 }
3340 CommandMessage* array_to_free = messages_;
3341 *this = new_queue;
3342 new_queue.messages_ = array_to_free;
3343 // Make the new_queue empty so that it doesn't call Dispose on any messages.
3344 new_queue.start_ = new_queue.end_;
3345 // Automatic destructor called on new_queue, freeing array_to_free.
3346 }
3347
3348
LockingCommandMessageQueue(Logger * logger,int size)3349 LockingCommandMessageQueue::LockingCommandMessageQueue(Logger* logger, int size)
3350 : logger_(logger), queue_(size) {}
3351
3352
IsEmpty() const3353 bool LockingCommandMessageQueue::IsEmpty() const {
3354 base::LockGuard<base::Mutex> lock_guard(&mutex_);
3355 return queue_.IsEmpty();
3356 }
3357
3358
Get()3359 CommandMessage LockingCommandMessageQueue::Get() {
3360 base::LockGuard<base::Mutex> lock_guard(&mutex_);
3361 CommandMessage result = queue_.Get();
3362 logger_->DebugEvent("Get", result.text());
3363 return result;
3364 }
3365
3366
Put(const CommandMessage & message)3367 void LockingCommandMessageQueue::Put(const CommandMessage& message) {
3368 base::LockGuard<base::Mutex> lock_guard(&mutex_);
3369 queue_.Put(message);
3370 logger_->DebugEvent("Put", message.text());
3371 }
3372
3373
Clear()3374 void LockingCommandMessageQueue::Clear() {
3375 base::LockGuard<base::Mutex> lock_guard(&mutex_);
3376 queue_.Clear();
3377 }
3378
3379 } } // namespace v8::internal
3380