Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/inspector/v8-debugger.h" | 5 #include "src/inspector/v8-debugger.h" |
| 6 | 6 |
| 7 #include "src/inspector/debugger-script.h" | 7 #include "src/inspector/debugger-script.h" |
| 8 #include "src/inspector/inspected-context.h" | 8 #include "src/inspector/inspected-context.h" |
| 9 #include "src/inspector/protocol/Protocol.h" | 9 #include "src/inspector/protocol/Protocol.h" |
| 10 #include "src/inspector/script-breakpoint.h" | 10 #include "src/inspector/script-breakpoint.h" |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 23 | 23 |
| 24 // Based on DevTools frontend measurement, with asyncCallStackDepth = 4, | 24 // Based on DevTools frontend measurement, with asyncCallStackDepth = 4, |
| 25 // average async call stack tail requires ~1 Kb. Let's reserve ~ 128 Mb | 25 // average async call stack tail requires ~1 Kb. Let's reserve ~ 128 Mb |
| 26 // for async stacks. | 26 // for async stacks. |
| 27 static const int kMaxAsyncTaskStacks = 128 * 1024; | 27 static const int kMaxAsyncTaskStacks = 128 * 1024; |
| 28 | 28 |
| 29 inline v8::Local<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate) { | 29 inline v8::Local<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate) { |
| 30 return value ? v8::True(isolate) : v8::False(isolate); | 30 return value ? v8::True(isolate) : v8::False(isolate); |
| 31 } | 31 } |
| 32 | 32 |
| 33 String16 promiseDebugActionName(v8::debug::PromiseDebugActionName action) { | |
| 34 switch (action) { | |
| 35 case v8::debug::kDebugAsyncFunction: | |
| 36 return "async function"; | |
| 37 case v8::debug::kDebugPromiseResolve: | |
| 38 return "Promise.resolve"; | |
| 39 case v8::debug::kDebugPromiseReject: | |
| 40 return "Promise.reject"; | |
| 41 case v8::debug::kDebugPromiseResolveThenableJob: | |
| 42 return "PromiseResolveThenableJob"; | |
| 43 case v8::debug::kDebugPromiseCollected: | |
| 44 return "Promise collected"; | |
| 45 } | |
| 46 return String16(); | |
| 47 } | |
| 48 | |
| 33 } // namespace | 49 } // namespace |
| 34 | 50 |
| 35 static bool inLiveEditScope = false; | 51 static bool inLiveEditScope = false; |
| 36 | 52 |
| 37 v8::MaybeLocal<v8::Value> V8Debugger::callDebuggerMethod( | 53 v8::MaybeLocal<v8::Value> V8Debugger::callDebuggerMethod( |
| 38 const char* functionName, int argc, v8::Local<v8::Value> argv[]) { | 54 const char* functionName, int argc, v8::Local<v8::Value> argv[]) { |
| 39 v8::MicrotasksScope microtasks(m_isolate, | 55 v8::MicrotasksScope microtasks(m_isolate, |
| 40 v8::MicrotasksScope::kDoNotRunMicrotasks); | 56 v8::MicrotasksScope::kDoNotRunMicrotasks); |
| 41 DCHECK(m_isolate->InContext()); | 57 DCHECK(m_isolate->InContext()); |
| 42 v8::Local<v8::Context> context = m_isolate->GetCurrentContext(); | 58 v8::Local<v8::Context> context = m_isolate->GetCurrentContext(); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 67 void V8Debugger::enable() { | 83 void V8Debugger::enable() { |
| 68 if (m_enableCount++) return; | 84 if (m_enableCount++) return; |
| 69 DCHECK(!enabled()); | 85 DCHECK(!enabled()); |
| 70 v8::HandleScope scope(m_isolate); | 86 v8::HandleScope scope(m_isolate); |
| 71 v8::debug::SetDebugEventListener(m_isolate, &V8Debugger::v8DebugEventCallback, | 87 v8::debug::SetDebugEventListener(m_isolate, &V8Debugger::v8DebugEventCallback, |
| 72 v8::External::New(m_isolate, this)); | 88 v8::External::New(m_isolate, this)); |
| 73 m_debuggerContext.Reset(m_isolate, v8::debug::GetDebugContext(m_isolate)); | 89 m_debuggerContext.Reset(m_isolate, v8::debug::GetDebugContext(m_isolate)); |
| 74 v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException); | 90 v8::debug::ChangeBreakOnException(m_isolate, v8::debug::NoBreakOnException); |
| 75 m_pauseOnExceptionsState = v8::debug::NoBreakOnException; | 91 m_pauseOnExceptionsState = v8::debug::NoBreakOnException; |
| 76 compileDebuggerScript(); | 92 compileDebuggerScript(); |
| 93 v8::debug::SetAsyncTaskListener(m_isolate, &V8Debugger::v8AsyncTaskListener, | |
|
dgozman
2017/01/13 00:01:48
Move it next to SetDebugEventListener.
kozy
2017/01/13 15:59:13
Done.
| |
| 94 this); | |
| 77 } | 95 } |
| 78 | 96 |
| 79 void V8Debugger::disable() { | 97 void V8Debugger::disable() { |
| 80 if (--m_enableCount) return; | 98 if (--m_enableCount) return; |
| 81 DCHECK(enabled()); | 99 DCHECK(enabled()); |
| 82 clearBreakpoints(); | 100 clearBreakpoints(); |
| 83 m_debuggerScript.Reset(); | 101 m_debuggerScript.Reset(); |
| 84 m_debuggerContext.Reset(); | 102 m_debuggerContext.Reset(); |
| 85 allAsyncTasksCanceled(); | 103 allAsyncTasksCanceled(); |
| 86 m_wasmTranslation.Clear(); | 104 m_wasmTranslation.Clear(); |
| 87 v8::debug::SetDebugEventListener(m_isolate, nullptr); | 105 v8::debug::SetDebugEventListener(m_isolate, nullptr); |
| 106 v8::debug::SetAsyncTaskListener(m_isolate, nullptr, nullptr); | |
| 88 } | 107 } |
| 89 | 108 |
| 90 bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); } | 109 bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); } |
| 91 | 110 |
| 92 void V8Debugger::getCompiledScripts( | 111 void V8Debugger::getCompiledScripts( |
| 93 int contextGroupId, | 112 int contextGroupId, |
| 94 std::vector<std::unique_ptr<V8DebuggerScript>>& result) { | 113 std::vector<std::unique_ptr<V8DebuggerScript>>& result) { |
| 95 v8::HandleScope scope(m_isolate); | 114 v8::HandleScope scope(m_isolate); |
| 96 v8::PersistentValueVector<v8::debug::Script> scripts(m_isolate); | 115 v8::PersistentValueVector<v8::debug::Script> scripts(m_isolate); |
| 97 v8::debug::GetLoadedScripts(m_isolate, scripts); | 116 v8::debug::GetLoadedScripts(m_isolate, scripts); |
| (...skipping 428 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 526 ->Call(m_isolate->GetCurrentContext(), object, 0, nullptr) | 545 ->Call(m_isolate->GetCurrentContext(), object, 0, nullptr) |
| 527 .ToLocalChecked(); | 546 .ToLocalChecked(); |
| 528 } | 547 } |
| 529 | 548 |
| 530 void V8Debugger::handleV8DebugEvent( | 549 void V8Debugger::handleV8DebugEvent( |
| 531 const v8::debug::EventDetails& eventDetails) { | 550 const v8::debug::EventDetails& eventDetails) { |
| 532 if (!enabled()) return; | 551 if (!enabled()) return; |
| 533 v8::HandleScope scope(m_isolate); | 552 v8::HandleScope scope(m_isolate); |
| 534 | 553 |
| 535 v8::DebugEvent event = eventDetails.GetEvent(); | 554 v8::DebugEvent event = eventDetails.GetEvent(); |
| 536 if (event != v8::AsyncTaskEvent && event != v8::Break && | 555 if (event != v8::Break && event != v8::Exception && |
| 537 event != v8::Exception && event != v8::AfterCompile && | 556 event != v8::AfterCompile && event != v8::CompileError) |
| 538 event != v8::CompileError) | |
| 539 return; | 557 return; |
| 540 | 558 |
| 541 if (event == v8::AsyncTaskEvent) { | |
| 542 handleV8AsyncTaskEvent(eventDetails.GetEventData()); | |
| 543 return; | |
| 544 } | |
| 545 | |
| 546 v8::Local<v8::Context> eventContext = eventDetails.GetEventContext(); | 559 v8::Local<v8::Context> eventContext = eventDetails.GetEventContext(); |
| 547 DCHECK(!eventContext.IsEmpty()); | 560 DCHECK(!eventContext.IsEmpty()); |
| 548 V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup( | 561 V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup( |
| 549 m_inspector->contextGroupId(eventContext)); | 562 m_inspector->contextGroupId(eventContext)); |
| 550 if (!agent) return; | 563 if (!agent) return; |
| 551 | 564 |
| 552 if (event == v8::AfterCompile || event == v8::CompileError) { | 565 if (event == v8::AfterCompile || event == v8::CompileError) { |
| 553 v8::Context::Scope contextScope(debuggerContext()); | 566 v8::Context::Scope contextScope(debuggerContext()); |
| 554 // Determine if the script is a wasm script. | 567 // Determine if the script is a wasm script. |
| 555 v8::Local<v8::Value> scriptMirror = | 568 v8::Local<v8::Value> scriptMirror = |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 589 v8::Local<v8::Value> hitBreakpoints; | 602 v8::Local<v8::Value> hitBreakpoints; |
| 590 if (!callDebuggerMethod("getBreakpointNumbers", 1, argv) | 603 if (!callDebuggerMethod("getBreakpointNumbers", 1, argv) |
| 591 .ToLocal(&hitBreakpoints)) | 604 .ToLocal(&hitBreakpoints)) |
| 592 return; | 605 return; |
| 593 DCHECK(hitBreakpoints->IsArray()); | 606 DCHECK(hitBreakpoints->IsArray()); |
| 594 handleProgramBreak(eventContext, eventDetails.GetExecutionState(), | 607 handleProgramBreak(eventContext, eventDetails.GetExecutionState(), |
| 595 v8::Local<v8::Value>(), hitBreakpoints.As<v8::Array>()); | 608 v8::Local<v8::Value>(), hitBreakpoints.As<v8::Array>()); |
| 596 } | 609 } |
| 597 } | 610 } |
| 598 | 611 |
| 599 void V8Debugger::handleV8AsyncTaskEvent(v8::Local<v8::Object> eventData) { | 612 void V8Debugger::v8AsyncTaskListener(v8::debug::PromiseDebugActionType type, |
| 600 if (!m_maxAsyncCallStackDepth) return; | 613 int id, |
| 614 v8::debug::PromiseDebugActionName name, | |
| 615 void* data) { | |
| 616 V8Debugger* debugger = static_cast<V8Debugger*>(data); | |
| 601 | 617 |
| 602 // TODO(kozyatinskiy): remove usage of current context as soon as async event | |
| 603 // is migrated to pure C++ API. | |
| 604 v8::debug::PromiseDebugActionType type = | |
| 605 static_cast<v8::debug::PromiseDebugActionType>( | |
| 606 eventData | |
| 607 ->Get(m_isolate->GetCurrentContext(), | |
| 608 toV8StringInternalized(m_isolate, "type_")) | |
| 609 .ToLocalChecked() | |
| 610 ->ToInteger(m_isolate->GetCurrentContext()) | |
| 611 .ToLocalChecked() | |
| 612 ->Value()); | |
| 613 String16 name = toProtocolStringWithTypeCheck( | |
| 614 eventData | |
| 615 ->Get(m_isolate->GetCurrentContext(), | |
| 616 toV8StringInternalized(m_isolate, "name_")) | |
| 617 .ToLocalChecked()); | |
| 618 int id = static_cast<int>(eventData | |
| 619 ->Get(m_isolate->GetCurrentContext(), | |
| 620 toV8StringInternalized(m_isolate, "id_")) | |
| 621 .ToLocalChecked() | |
| 622 ->ToInteger(m_isolate->GetCurrentContext()) | |
| 623 .ToLocalChecked() | |
| 624 ->Value()); | |
| 625 // Async task events from Promises are given misaligned pointers to prevent | 618 // Async task events from Promises are given misaligned pointers to prevent |
| 626 // from overlapping with other Blink task identifiers. There is a single | 619 // from overlapping with other Blink task identifiers. There is a single |
| 627 // namespace of such ids, managed by src/js/promise.js. | 620 // namespace of such ids, managed by src/js/promise.js. |
| 628 void* ptr = reinterpret_cast<void*>(id * 2 + 1); | 621 void* ptr = reinterpret_cast<void*>(id * 2 + 1); |
| 629 switch (type) { | 622 switch (type) { |
| 630 case v8::debug::kDebugEnqueueRecurring: | 623 case v8::debug::kDebugEnqueueRecurring: |
| 631 asyncTaskScheduled(name, ptr, true); | 624 debugger->asyncTaskScheduled(promiseDebugActionName(name), ptr, true); |
| 632 break; | 625 break; |
| 633 case v8::debug::kDebugCancel: | 626 case v8::debug::kDebugCancel: |
| 634 asyncTaskCanceled(ptr); | 627 debugger->asyncTaskCanceled(ptr); |
| 635 break; | 628 break; |
| 636 case v8::debug::kDebugWillHandle: | 629 case v8::debug::kDebugWillHandle: |
| 637 asyncTaskStarted(ptr); | 630 debugger->asyncTaskStarted(ptr); |
| 638 break; | 631 break; |
| 639 case v8::debug::kDebugDidHandle: | 632 case v8::debug::kDebugDidHandle: |
| 640 asyncTaskFinished(ptr); | 633 debugger->asyncTaskFinished(ptr); |
| 641 break; | 634 break; |
| 642 } | 635 } |
| 643 } | 636 } |
| 644 | 637 |
| 645 V8StackTraceImpl* V8Debugger::currentAsyncCallChain() { | 638 V8StackTraceImpl* V8Debugger::currentAsyncCallChain() { |
| 646 if (!m_currentStacks.size()) return nullptr; | 639 if (!m_currentStacks.size()) return nullptr; |
| 647 return m_currentStacks.back().get(); | 640 return m_currentStacks.back().get(); |
| 648 } | 641 } |
| 649 | 642 |
| 650 void V8Debugger::compileDebuggerScript() { | 643 void V8Debugger::compileDebuggerScript() { |
| (...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1010 | 1003 |
| 1011 size_t stackSize = | 1004 size_t stackSize = |
| 1012 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; | 1005 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; |
| 1013 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) | 1006 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) |
| 1014 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; | 1007 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; |
| 1015 | 1008 |
| 1016 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); | 1009 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); |
| 1017 } | 1010 } |
| 1018 | 1011 |
| 1019 } // namespace v8_inspector | 1012 } // namespace v8_inspector |
| OLD | NEW |