OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 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 | 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/debug/debug.h" | 5 #include "src/debug/debug.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 | 8 |
9 #include "src/api.h" | 9 #include "src/api.h" |
10 #include "src/arguments.h" | 10 #include "src/arguments.h" |
(...skipping 20 matching lines...) Expand all Loading... |
31 #include "src/wasm/wasm-module.h" | 31 #include "src/wasm/wasm-module.h" |
32 #include "src/wasm/wasm-objects.h" | 32 #include "src/wasm/wasm-objects.h" |
33 | 33 |
34 #include "include/v8-debug.h" | 34 #include "include/v8-debug.h" |
35 | 35 |
36 namespace v8 { | 36 namespace v8 { |
37 namespace internal { | 37 namespace internal { |
38 | 38 |
39 Debug::Debug(Isolate* isolate) | 39 Debug::Debug(Isolate* isolate) |
40 : debug_context_(Handle<Context>()), | 40 : debug_context_(Handle<Context>()), |
41 event_listener_(Handle<Object>()), | |
42 event_listener_data_(Handle<Object>()), | |
43 is_active_(false), | 41 is_active_(false), |
44 hook_on_function_call_(false), | 42 hook_on_function_call_(false), |
45 is_suppressed_(false), | 43 is_suppressed_(false), |
46 live_edit_enabled_(true), // TODO(yangguo): set to false by default. | 44 live_edit_enabled_(true), // TODO(yangguo): set to false by default. |
47 break_disabled_(false), | 45 break_disabled_(false), |
48 break_points_active_(true), | 46 break_points_active_(true), |
49 in_debug_event_listener_(false), | |
50 break_on_exception_(false), | 47 break_on_exception_(false), |
51 break_on_uncaught_exception_(false), | 48 break_on_uncaught_exception_(false), |
52 side_effect_check_failed_(false), | 49 side_effect_check_failed_(false), |
53 debug_info_list_(NULL), | 50 debug_info_list_(NULL), |
54 feature_tracker_(isolate), | 51 feature_tracker_(isolate), |
55 isolate_(isolate) { | 52 isolate_(isolate) { |
56 ThreadInit(); | 53 ThreadInit(); |
57 } | 54 } |
58 | 55 |
59 BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info, | 56 BreakLocation BreakLocation::FromFrame(Handle<DebugInfo> debug_info, |
(...skipping 406 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
466 | 463 |
467 feature_tracker()->Track(DebugFeatureTracker::kActive); | 464 feature_tracker()->Track(DebugFeatureTracker::kActive); |
468 | 465 |
469 return true; | 466 return true; |
470 } | 467 } |
471 | 468 |
472 | 469 |
473 void Debug::Unload() { | 470 void Debug::Unload() { |
474 ClearAllBreakPoints(); | 471 ClearAllBreakPoints(); |
475 ClearStepping(); | 472 ClearStepping(); |
| 473 RemoveDebugDelegate(); |
476 | 474 |
477 // Return debugger is not loaded. | 475 // Return debugger is not loaded. |
478 if (!is_loaded()) return; | 476 if (!is_loaded()) return; |
479 | 477 |
480 // Clear debugger context global handle. | 478 // Clear debugger context global handle. |
481 GlobalHandles::Destroy(Handle<Object>::cast(debug_context_).location()); | 479 GlobalHandles::Destroy(Handle<Object>::cast(debug_context_).location()); |
482 debug_context_ = Handle<Context>(); | 480 debug_context_ = Handle<Context>(); |
483 } | 481 } |
484 | 482 |
485 void Debug::Break(JavaScriptFrame* frame) { | 483 void Debug::Break(JavaScriptFrame* frame) { |
486 HandleScope scope(isolate_); | 484 HandleScope scope(isolate_); |
487 | 485 |
488 // Initialize LiveEdit. | 486 // Initialize LiveEdit. |
489 LiveEdit::InitializeThreadLocal(this); | 487 LiveEdit::InitializeThreadLocal(this); |
490 | 488 |
491 // Just continue if breaks are disabled or debugger cannot be loaded. | 489 // Just continue if breaks are disabled or debugger cannot be loaded. |
492 if (break_disabled()) return; | 490 if (break_disabled()) return; |
493 | 491 |
494 // Enter the debugger. | 492 // Enter the debugger. |
495 DebugScope debug_scope(this); | 493 DebugScope debug_scope(this); |
496 if (debug_scope.failed()) return; | 494 if (debug_scope.failed()) return; |
497 | 495 |
498 // Postpone interrupt during breakpoint processing. | 496 // Postpone interrupt during breakpoint processing. |
499 PostponeInterruptsScope postpone(isolate_); | 497 PostponeInterruptsScope postpone(isolate_); |
| 498 DisableBreak no_recursive_break(this); |
500 | 499 |
501 // Return if we fail to retrieve debug info. | 500 // Return if we fail to retrieve debug info. |
502 Handle<JSFunction> function(frame->function()); | 501 Handle<JSFunction> function(frame->function()); |
503 Handle<SharedFunctionInfo> shared(function->shared()); | 502 Handle<SharedFunctionInfo> shared(function->shared()); |
504 if (!EnsureDebugInfo(shared)) return; | 503 if (!EnsureDebugInfo(shared)) return; |
505 Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_); | 504 Handle<DebugInfo> debug_info(shared->GetDebugInfo(), isolate_); |
506 | 505 |
507 // Find the break location where execution has stopped. | 506 // Find the break location where execution has stopped. |
508 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); | 507 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); |
509 | 508 |
(...skipping 1150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1660 | 1659 |
1661 MaybeHandle<Object> Debug::MakeCompileEvent(Handle<Script> script, | 1660 MaybeHandle<Object> Debug::MakeCompileEvent(Handle<Script> script, |
1662 v8::DebugEvent type) { | 1661 v8::DebugEvent type) { |
1663 // Create the compile event object. | 1662 // Create the compile event object. |
1664 Handle<Object> script_wrapper = Script::GetWrapper(script); | 1663 Handle<Object> script_wrapper = Script::GetWrapper(script); |
1665 Handle<Object> argv[] = { script_wrapper, | 1664 Handle<Object> argv[] = { script_wrapper, |
1666 isolate_->factory()->NewNumberFromInt(type) }; | 1665 isolate_->factory()->NewNumberFromInt(type) }; |
1667 return CallFunction("MakeCompileEvent", arraysize(argv), argv); | 1666 return CallFunction("MakeCompileEvent", arraysize(argv), argv); |
1668 } | 1667 } |
1669 | 1668 |
1670 MaybeHandle<Object> Debug::MakeAsyncTaskEvent(Handle<Smi> type, | 1669 MaybeHandle<Object> Debug::MakeAsyncTaskEvent( |
1671 Handle<Smi> id) { | 1670 v8::debug::PromiseDebugActionType type, int id) { |
1672 DCHECK(id->IsNumber()); | |
1673 // Create the async task event object. | 1671 // Create the async task event object. |
1674 Handle<Object> argv[] = {type, id}; | 1672 Handle<Object> argv[] = {Handle<Smi>(Smi::FromInt(type), isolate_), |
| 1673 Handle<Smi>(Smi::FromInt(id), isolate_)}; |
1675 return CallFunction("MakeAsyncTaskEvent", arraysize(argv), argv); | 1674 return CallFunction("MakeAsyncTaskEvent", arraysize(argv), argv); |
1676 } | 1675 } |
1677 | 1676 |
1678 | 1677 |
1679 void Debug::OnThrow(Handle<Object> exception) { | 1678 void Debug::OnThrow(Handle<Object> exception) { |
1680 if (in_debug_scope() || ignore_events()) return; | 1679 if (in_debug_scope() || ignore_events()) return; |
1681 // Temporarily clear any scheduled_exception to allow evaluating | 1680 // Temporarily clear any scheduled_exception to allow evaluating |
1682 // JavaScript from the debug event handler. | 1681 // JavaScript from the debug event handler. |
1683 HandleScope scope(isolate_); | 1682 HandleScope scope(isolate_); |
1684 Handle<Object> scheduled_exception; | 1683 Handle<Object> scheduled_exception; |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1757 | 1756 |
1758 bool uncaught = catch_type == Isolate::NOT_CAUGHT; | 1757 bool uncaught = catch_type == Isolate::NOT_CAUGHT; |
1759 if (promise->IsJSObject()) { | 1758 if (promise->IsJSObject()) { |
1760 Handle<JSObject> jspromise = Handle<JSObject>::cast(promise); | 1759 Handle<JSObject> jspromise = Handle<JSObject>::cast(promise); |
1761 // Mark the promise as already having triggered a message. | 1760 // Mark the promise as already having triggered a message. |
1762 Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol(); | 1761 Handle<Symbol> key = isolate_->factory()->promise_debug_marker_symbol(); |
1763 JSObject::SetProperty(jspromise, key, key, STRICT).Assert(); | 1762 JSObject::SetProperty(jspromise, key, key, STRICT).Assert(); |
1764 // Check whether the promise reject is considered an uncaught exception. | 1763 // Check whether the promise reject is considered an uncaught exception. |
1765 uncaught = !isolate_->PromiseHasUserDefinedRejectHandler(jspromise); | 1764 uncaught = !isolate_->PromiseHasUserDefinedRejectHandler(jspromise); |
1766 } | 1765 } |
| 1766 |
| 1767 if (!debug_delegate_) return; |
| 1768 |
1767 // Bail out if exception breaks are not active | 1769 // Bail out if exception breaks are not active |
1768 if (uncaught) { | 1770 if (uncaught) { |
1769 // Uncaught exceptions are reported by either flags. | 1771 // Uncaught exceptions are reported by either flags. |
1770 if (!(break_on_uncaught_exception_ || break_on_exception_)) return; | 1772 if (!(break_on_uncaught_exception_ || break_on_exception_)) return; |
1771 } else { | 1773 } else { |
1772 // Caught exceptions are reported is activated. | 1774 // Caught exceptions are reported is activated. |
1773 if (!break_on_exception_) return; | 1775 if (!break_on_exception_) return; |
1774 } | 1776 } |
1775 | 1777 |
1776 bool empty_js_stack = false; | |
1777 { | 1778 { |
1778 JavaScriptFrameIterator it(isolate_); | 1779 JavaScriptFrameIterator it(isolate_); |
1779 // Check whether the top frame is blackboxed or the break location is muted. | 1780 // Check whether the top frame is blackboxed or the break location is muted. |
1780 if (!it.done() && (IsMutedAtCurrentLocation(it.frame()) || | 1781 if (!it.done() && (IsMutedAtCurrentLocation(it.frame()) || |
1781 IsExceptionBlackboxed(uncaught))) { | 1782 IsExceptionBlackboxed(uncaught))) { |
1782 return; | 1783 return; |
1783 } | 1784 } |
1784 empty_js_stack = it.done(); | 1785 if (it.done()) return; // Do not trigger an event with an empty stack. |
1785 } | 1786 } |
1786 | 1787 |
1787 DebugScope debug_scope(this); | 1788 DebugScope debug_scope(this); |
1788 if (debug_scope.failed()) return; | 1789 if (debug_scope.failed()) return; |
| 1790 HandleScope scope(isolate_); |
| 1791 PostponeInterruptsScope postpone(isolate_); |
| 1792 DisableBreak no_recursive_break(this); |
1789 | 1793 |
1790 if (debug_delegate_ && !empty_js_stack) { | 1794 // Create the execution state. |
1791 HandleScope scope(isolate_); | 1795 Handle<Object> exec_state; |
| 1796 // Bail out and don't call debugger if exception. |
| 1797 if (!MakeExecutionState().ToHandle(&exec_state)) return; |
1792 | 1798 |
1793 // Create the execution state. | 1799 debug_delegate_->ExceptionThrown( |
1794 Handle<Object> exec_state; | 1800 GetDebugEventContext(isolate_), |
1795 // Bail out and don't call debugger if exception. | 1801 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)), |
1796 if (!MakeExecutionState().ToHandle(&exec_state)) return; | 1802 v8::Utils::ToLocal(exception), v8::Utils::ToLocal(promise), uncaught); |
1797 | |
1798 debug_delegate_->ExceptionThrown( | |
1799 GetDebugEventContext(isolate_), | |
1800 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)), | |
1801 v8::Utils::ToLocal(exception), promise->IsJSObject(), uncaught); | |
1802 } | |
1803 if (debug_delegate_ && !non_inspector_listener_exists()) return; | |
1804 | |
1805 // Create the event data object. | |
1806 Handle<Object> event_data; | |
1807 // Bail out and don't call debugger if exception. | |
1808 if (!MakeExceptionEvent( | |
1809 exception, uncaught, promise).ToHandle(&event_data)) { | |
1810 return; | |
1811 } | |
1812 | |
1813 // Process debug event. | |
1814 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data)); | |
1815 // Return to continue execution from where the exception was thrown. | |
1816 } | 1803 } |
1817 | 1804 |
1818 void Debug::OnDebugBreak(Handle<Object> break_points_hit) { | 1805 void Debug::OnDebugBreak(Handle<Object> break_points_hit) { |
1819 // The caller provided for DebugScope. | 1806 // The caller provided for DebugScope. |
1820 AssertDebugContext(); | 1807 AssertDebugContext(); |
1821 // Bail out if there is no listener for this event | 1808 // Bail out if there is no listener for this event |
1822 if (ignore_events()) return; | 1809 if (ignore_events()) return; |
1823 | 1810 |
1824 #ifdef DEBUG | 1811 #ifdef DEBUG |
1825 PrintBreakLocation(); | 1812 PrintBreakLocation(); |
1826 #endif // DEBUG | 1813 #endif // DEBUG |
1827 | 1814 |
1828 if (debug_delegate_) { | 1815 if (!debug_delegate_) return; |
1829 HandleScope scope(isolate_); | 1816 HandleScope scope(isolate_); |
| 1817 PostponeInterruptsScope no_interrupts(isolate_); |
| 1818 DisableBreak no_recursive_break(this); |
1830 | 1819 |
1831 // Create the execution state. | 1820 // Create the execution state. |
1832 Handle<Object> exec_state; | 1821 Handle<Object> exec_state; |
1833 // Bail out and don't call debugger if exception. | 1822 // Bail out and don't call debugger if exception. |
1834 if (!MakeExecutionState().ToHandle(&exec_state)) return; | 1823 if (!MakeExecutionState().ToHandle(&exec_state)) return; |
1835 | 1824 |
1836 bool previous = in_debug_event_listener_; | 1825 debug_delegate_->BreakProgramRequested( |
1837 in_debug_event_listener_ = true; | 1826 GetDebugEventContext(isolate_), |
1838 debug_delegate_->BreakProgramRequested( | 1827 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)), |
1839 GetDebugEventContext(isolate_), | 1828 v8::Utils::ToLocal(break_points_hit)); |
1840 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)), | |
1841 v8::Utils::ToLocal(break_points_hit)); | |
1842 in_debug_event_listener_ = previous; | |
1843 if (!non_inspector_listener_exists()) return; | |
1844 } | |
1845 | |
1846 HandleScope scope(isolate_); | |
1847 // Create the event data object. | |
1848 Handle<Object> event_data; | |
1849 // Bail out and don't call debugger if exception. | |
1850 if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return; | |
1851 | |
1852 // Process debug event. | |
1853 ProcessDebugEvent(v8::Break, Handle<JSObject>::cast(event_data)); | |
1854 } | 1829 } |
1855 | 1830 |
1856 | 1831 |
1857 void Debug::OnCompileError(Handle<Script> script) { | 1832 void Debug::OnCompileError(Handle<Script> script) { |
1858 ProcessCompileEvent(v8::CompileError, script); | 1833 ProcessCompileEvent(v8::CompileError, script); |
1859 } | 1834 } |
1860 | 1835 |
1861 | 1836 |
1862 // Handle debugger actions when a new script is compiled. | 1837 // Handle debugger actions when a new script is compiled. |
1863 void Debug::OnAfterCompile(Handle<Script> script) { | 1838 void Debug::OnAfterCompile(Handle<Script> script) { |
(...skipping 10 matching lines...) Expand all Loading... |
1874 CollectedCallbackData(Object** location, int id, Debug* debug, | 1849 CollectedCallbackData(Object** location, int id, Debug* debug, |
1875 Isolate* isolate) | 1850 Isolate* isolate) |
1876 : location(location), id(id), debug(debug), isolate(isolate) {} | 1851 : location(location), id(id), debug(debug), isolate(isolate) {} |
1877 }; | 1852 }; |
1878 | 1853 |
1879 void SendAsyncTaskEventCancel(const v8::WeakCallbackInfo<void>& info) { | 1854 void SendAsyncTaskEventCancel(const v8::WeakCallbackInfo<void>& info) { |
1880 std::unique_ptr<CollectedCallbackData> data( | 1855 std::unique_ptr<CollectedCallbackData> data( |
1881 reinterpret_cast<CollectedCallbackData*>(info.GetParameter())); | 1856 reinterpret_cast<CollectedCallbackData*>(info.GetParameter())); |
1882 if (!data->debug->is_active()) return; | 1857 if (!data->debug->is_active()) return; |
1883 HandleScope scope(data->isolate); | 1858 HandleScope scope(data->isolate); |
1884 data->debug->OnAsyncTaskEvent(debug::kDebugPromiseCollected, data->id); | 1859 data->debug->OnAsyncTaskEvent(debug::kDebugPromiseCollected, data->id, 0); |
1885 } | 1860 } |
1886 | 1861 |
1887 void ResetPromiseHandle(const v8::WeakCallbackInfo<void>& info) { | 1862 void ResetPromiseHandle(const v8::WeakCallbackInfo<void>& info) { |
1888 CollectedCallbackData* data = | 1863 CollectedCallbackData* data = |
1889 reinterpret_cast<CollectedCallbackData*>(info.GetParameter()); | 1864 reinterpret_cast<CollectedCallbackData*>(info.GetParameter()); |
1890 GlobalHandles::Destroy(data->location); | 1865 GlobalHandles::Destroy(data->location); |
1891 info.SetSecondPassCallback(&SendAsyncTaskEventCancel); | 1866 info.SetSecondPassCallback(&SendAsyncTaskEventCancel); |
1892 } | 1867 } |
1893 | 1868 |
1894 // In an async function, reuse the existing stack related to the outer | 1869 // In an async function, reuse the existing stack related to the outer |
(...skipping 27 matching lines...) Expand all Loading... |
1922 return Handle<Smi>::cast(async_task_id)->value(); | 1897 return Handle<Smi>::cast(async_task_id)->value(); |
1923 } | 1898 } |
1924 } // namespace | 1899 } // namespace |
1925 | 1900 |
1926 void Debug::RunPromiseHook(PromiseHookType type, Handle<JSPromise> promise, | 1901 void Debug::RunPromiseHook(PromiseHookType type, Handle<JSPromise> promise, |
1927 Handle<Object> parent) { | 1902 Handle<Object> parent) { |
1928 if (!debug_delegate_) return; | 1903 if (!debug_delegate_) return; |
1929 int id = GetReferenceAsyncTaskId(isolate_, promise); | 1904 int id = GetReferenceAsyncTaskId(isolate_, promise); |
1930 switch (type) { | 1905 switch (type) { |
1931 case PromiseHookType::kInit: | 1906 case PromiseHookType::kInit: |
1932 debug_delegate_->PromiseEventOccurred( | 1907 OnAsyncTaskEvent(debug::kDebugPromiseCreated, id, |
1933 debug::kDebugPromiseCreated, id, | 1908 parent->IsJSPromise() |
1934 parent->IsJSPromise() ? GetReferenceAsyncTaskId( | 1909 ? GetReferenceAsyncTaskId( |
1935 isolate_, Handle<JSPromise>::cast(parent)) | 1910 isolate_, Handle<JSPromise>::cast(parent)) |
1936 : 0); | 1911 : 0); |
1937 return; | 1912 return; |
1938 case PromiseHookType::kResolve: | 1913 case PromiseHookType::kResolve: |
1939 // We can't use this hook because it's called before promise object will | 1914 // We can't use this hook because it's called before promise object will |
1940 // get resolved status. | 1915 // get resolved status. |
1941 return; | 1916 return; |
1942 case PromiseHookType::kBefore: | 1917 case PromiseHookType::kBefore: |
1943 OnAsyncTaskEvent(debug::kDebugWillHandle, id); | 1918 OnAsyncTaskEvent(debug::kDebugWillHandle, id, 0); |
1944 return; | 1919 return; |
1945 case PromiseHookType::kAfter: | 1920 case PromiseHookType::kAfter: |
1946 OnAsyncTaskEvent(debug::kDebugDidHandle, id); | 1921 OnAsyncTaskEvent(debug::kDebugDidHandle, id, 0); |
1947 return; | 1922 return; |
1948 } | 1923 } |
1949 } | 1924 } |
1950 | 1925 |
1951 int Debug::NextAsyncTaskId(Handle<JSObject> promise) { | 1926 int Debug::NextAsyncTaskId(Handle<JSObject> promise) { |
1952 LookupIterator it(promise, isolate_->factory()->promise_async_id_symbol()); | 1927 LookupIterator it(promise, isolate_->factory()->promise_async_id_symbol()); |
1953 Maybe<bool> maybe = JSReceiver::HasProperty(&it); | 1928 Maybe<bool> maybe = JSReceiver::HasProperty(&it); |
1954 if (maybe.ToChecked()) { | 1929 if (maybe.ToChecked()) { |
1955 MaybeHandle<Object> result = Object::GetProperty(&it); | 1930 MaybeHandle<Object> result = Object::GetProperty(&it); |
1956 return Handle<Smi>::cast(result.ToHandleChecked())->value(); | 1931 return Handle<Smi>::cast(result.ToHandleChecked())->value(); |
(...skipping 24 matching lines...) Expand all Loading... |
1981 Script::GetPositionInfo(script, source_position, &info, Script::WITH_OFFSET); | 1956 Script::GetPositionInfo(script, source_position, &info, Script::WITH_OFFSET); |
1982 return debug::Location(info.line, info.column); | 1957 return debug::Location(info.line, info.column); |
1983 } | 1958 } |
1984 } // namespace | 1959 } // namespace |
1985 | 1960 |
1986 bool Debug::IsBlackboxed(Handle<SharedFunctionInfo> shared) { | 1961 bool Debug::IsBlackboxed(Handle<SharedFunctionInfo> shared) { |
1987 if (!debug_delegate_) return false; | 1962 if (!debug_delegate_) return false; |
1988 if (!shared->computed_debug_is_blackboxed()) { | 1963 if (!shared->computed_debug_is_blackboxed()) { |
1989 bool is_blackboxed = false; | 1964 bool is_blackboxed = false; |
1990 if (shared->script()->IsScript()) { | 1965 if (shared->script()->IsScript()) { |
| 1966 SuppressDebug while_processing(this); |
1991 HandleScope handle_scope(isolate_); | 1967 HandleScope handle_scope(isolate_); |
| 1968 PostponeInterruptsScope no_interrupts(isolate_); |
| 1969 DisableBreak no_recursive_break(this); |
1992 Handle<Script> script(Script::cast(shared->script())); | 1970 Handle<Script> script(Script::cast(shared->script())); |
1993 if (script->type() == i::Script::TYPE_NORMAL) { | 1971 if (script->type() == i::Script::TYPE_NORMAL) { |
1994 debug::Location start = | 1972 debug::Location start = |
1995 GetDebugLocation(script, shared->start_position()); | 1973 GetDebugLocation(script, shared->start_position()); |
1996 debug::Location end = GetDebugLocation(script, shared->end_position()); | 1974 debug::Location end = GetDebugLocation(script, shared->end_position()); |
1997 is_blackboxed = debug_delegate_->IsFunctionBlackboxed( | 1975 is_blackboxed = debug_delegate_->IsFunctionBlackboxed( |
1998 ToApiHandle<debug::Script>(script), start, end); | 1976 ToApiHandle<debug::Script>(script), start, end); |
1999 } | 1977 } |
2000 } | 1978 } |
2001 shared->set_debug_is_blackboxed(is_blackboxed); | 1979 shared->set_debug_is_blackboxed(is_blackboxed); |
2002 shared->set_computed_debug_is_blackboxed(true); | 1980 shared->set_computed_debug_is_blackboxed(true); |
2003 } | 1981 } |
2004 return shared->debug_is_blackboxed(); | 1982 return shared->debug_is_blackboxed(); |
2005 } | 1983 } |
2006 | 1984 |
2007 void Debug::OnAsyncTaskEvent(debug::PromiseDebugActionType type, int id) { | 1985 void Debug::OnAsyncTaskEvent(debug::PromiseDebugActionType type, int id, |
| 1986 int parent_id) { |
2008 if (in_debug_scope() || ignore_events()) return; | 1987 if (in_debug_scope() || ignore_events()) return; |
2009 | 1988 if (!debug_delegate_) return; |
2010 if (debug_delegate_) { | 1989 SuppressDebug while_processing(this); |
2011 debug_delegate_->PromiseEventOccurred(type, id, 0); | 1990 DebugScope debug_scope(isolate_->debug()); |
2012 if (!non_inspector_listener_exists()) return; | 1991 if (debug_scope.failed()) return; |
2013 } | |
2014 | |
2015 HandleScope scope(isolate_); | 1992 HandleScope scope(isolate_); |
2016 DebugScope debug_scope(this); | 1993 PostponeInterruptsScope no_interrupts(isolate_); |
2017 if (debug_scope.failed()) return; | 1994 DisableBreak no_recursive_break(this); |
2018 | 1995 debug_delegate_->PromiseEventOccurred(type, id, parent_id); |
2019 // Create the script collected state object. | |
2020 Handle<Object> event_data; | |
2021 // Bail out and don't call debugger if exception. | |
2022 if (!MakeAsyncTaskEvent(handle(Smi::FromInt(type), isolate_), | |
2023 handle(Smi::FromInt(id), isolate_)) | |
2024 .ToHandle(&event_data)) | |
2025 return; | |
2026 | |
2027 // Process debug event. | |
2028 ProcessDebugEvent(v8::AsyncTaskEvent, Handle<JSObject>::cast(event_data)); | |
2029 } | |
2030 | |
2031 void Debug::ProcessDebugEvent(v8::DebugEvent event, | |
2032 Handle<JSObject> event_data) { | |
2033 // Notify registered debug event listener. This can be either a C or | |
2034 // a JavaScript function. | |
2035 if (event_listener_.is_null()) return; | |
2036 HandleScope scope(isolate_); | |
2037 | |
2038 // Create the execution state. | |
2039 Handle<Object> exec_state; | |
2040 // Bail out and don't call debugger if exception. | |
2041 if (!MakeExecutionState().ToHandle(&exec_state)) return; | |
2042 | |
2043 // Prevent other interrupts from triggering, for example API callbacks, | |
2044 // while dispatching event listners. | |
2045 PostponeInterruptsScope postpone(isolate_); | |
2046 bool previous = in_debug_event_listener_; | |
2047 in_debug_event_listener_ = true; | |
2048 if (event_listener_->IsForeign()) { | |
2049 // Invoke the C debug event listener. | |
2050 v8::Debug::EventCallback callback = FUNCTION_CAST<v8::Debug::EventCallback>( | |
2051 Handle<Foreign>::cast(event_listener_)->foreign_address()); | |
2052 EventDetailsImpl event_details(event, Handle<JSObject>::cast(exec_state), | |
2053 Handle<JSObject>::cast(event_data), | |
2054 event_listener_data_); | |
2055 callback(event_details); | |
2056 CHECK(!isolate_->has_scheduled_exception()); | |
2057 } else { | |
2058 // Invoke the JavaScript debug event listener. | |
2059 DCHECK(event_listener_->IsJSFunction()); | |
2060 Handle<Object> argv[] = { Handle<Object>(Smi::FromInt(event), isolate_), | |
2061 exec_state, | |
2062 event_data, | |
2063 event_listener_data_ }; | |
2064 Handle<JSReceiver> global = isolate_->global_proxy(); | |
2065 MaybeHandle<Object> result = | |
2066 Execution::Call(isolate_, Handle<JSFunction>::cast(event_listener_), | |
2067 global, arraysize(argv), argv); | |
2068 CHECK(!result.is_null()); // Listeners must not throw. | |
2069 } | |
2070 in_debug_event_listener_ = previous; | |
2071 } | 1996 } |
2072 | 1997 |
2073 void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) { | 1998 void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) { |
2074 if (ignore_events()) return; | 1999 if (ignore_events()) return; |
2075 if (script->type() != i::Script::TYPE_NORMAL && | 2000 if (script->type() != i::Script::TYPE_NORMAL && |
2076 script->type() != i::Script::TYPE_WASM) { | 2001 script->type() != i::Script::TYPE_WASM) { |
2077 return; | 2002 return; |
2078 } | 2003 } |
| 2004 if (!debug_delegate_) return; |
2079 SuppressDebug while_processing(this); | 2005 SuppressDebug while_processing(this); |
2080 DebugScope debug_scope(this); | 2006 DebugScope debug_scope(this); |
2081 if (debug_scope.failed()) return; | 2007 if (debug_scope.failed()) return; |
2082 | |
2083 if (debug_delegate_) { | |
2084 debug_delegate_->ScriptCompiled(ToApiHandle<debug::Script>(script), | |
2085 event != v8::AfterCompile); | |
2086 if (!non_inspector_listener_exists()) return; | |
2087 } | |
2088 | |
2089 HandleScope scope(isolate_); | 2008 HandleScope scope(isolate_); |
2090 // Create the compile state object. | 2009 PostponeInterruptsScope postpone(isolate_); |
2091 Handle<Object> event_data; | 2010 DisableBreak no_recursive_break(this); |
2092 // Bail out and don't call debugger if exception. | 2011 debug_delegate_->ScriptCompiled(ToApiHandle<debug::Script>(script), |
2093 if (!MakeCompileEvent(script, event).ToHandle(&event_data)) return; | 2012 event != v8::AfterCompile); |
2094 | |
2095 // Process debug event. | |
2096 ProcessDebugEvent(event, Handle<JSObject>::cast(event_data)); | |
2097 } | 2013 } |
2098 | 2014 |
2099 | 2015 |
2100 Handle<Context> Debug::GetDebugContext() { | 2016 Handle<Context> Debug::GetDebugContext() { |
2101 if (!is_loaded()) return Handle<Context>(); | 2017 if (!is_loaded()) return Handle<Context>(); |
2102 DebugScope debug_scope(this); | 2018 DebugScope debug_scope(this); |
2103 if (debug_scope.failed()) return Handle<Context>(); | 2019 if (debug_scope.failed()) return Handle<Context>(); |
2104 // The global handle may be destroyed soon after. Return it reboxed. | 2020 // The global handle may be destroyed soon after. Return it reboxed. |
2105 return handle(*debug_context(), isolate_); | 2021 return handle(*debug_context(), isolate_); |
2106 } | 2022 } |
2107 | 2023 |
2108 | |
2109 void Debug::SetEventListener(Handle<Object> callback, | |
2110 Handle<Object> data) { | |
2111 GlobalHandles* global_handles = isolate_->global_handles(); | |
2112 | |
2113 // Remove existing entry. | |
2114 GlobalHandles::Destroy(event_listener_.location()); | |
2115 event_listener_ = Handle<Object>(); | |
2116 GlobalHandles::Destroy(event_listener_data_.location()); | |
2117 event_listener_data_ = Handle<Object>(); | |
2118 | |
2119 // Set new entry. | |
2120 if (!callback->IsNullOrUndefined(isolate_)) { | |
2121 event_listener_ = global_handles->Create(*callback); | |
2122 if (data.is_null()) data = isolate_->factory()->undefined_value(); | |
2123 event_listener_data_ = global_handles->Create(*data); | |
2124 } | |
2125 | |
2126 UpdateState(); | |
2127 } | |
2128 | |
2129 int Debug::CurrentFrameCount() { | 2024 int Debug::CurrentFrameCount() { |
2130 StackTraceFrameIterator it(isolate_); | 2025 StackTraceFrameIterator it(isolate_); |
2131 if (break_frame_id() != StackFrame::NO_ID) { | 2026 if (break_frame_id() != StackFrame::NO_ID) { |
2132 // Skip to break frame. | 2027 // Skip to break frame. |
2133 DCHECK(in_debug_scope()); | 2028 DCHECK(in_debug_scope()); |
2134 while (!it.done() && it.frame()->id() != break_frame_id()) it.Advance(); | 2029 while (!it.done() && it.frame()->id() != break_frame_id()) it.Advance(); |
2135 } | 2030 } |
2136 int counter = 0; | 2031 int counter = 0; |
2137 while (!it.done()) { | 2032 while (!it.done()) { |
2138 if (it.frame()->is_optimized()) { | 2033 if (it.frame()->is_optimized()) { |
2139 List<SharedFunctionInfo*> infos; | 2034 List<SharedFunctionInfo*> infos; |
2140 OptimizedFrame::cast(it.frame())->GetFunctions(&infos); | 2035 OptimizedFrame::cast(it.frame())->GetFunctions(&infos); |
2141 counter += infos.length(); | 2036 counter += infos.length(); |
2142 } else { | 2037 } else { |
2143 counter++; | 2038 counter++; |
2144 } | 2039 } |
2145 it.Advance(); | 2040 it.Advance(); |
2146 } | 2041 } |
2147 return counter; | 2042 return counter; |
2148 } | 2043 } |
2149 | 2044 |
2150 void Debug::SetDebugDelegate(debug::DebugDelegate* delegate) { | 2045 void Debug::SetDebugDelegate(debug::DebugDelegate* delegate, |
| 2046 bool pass_ownership) { |
| 2047 RemoveDebugDelegate(); |
2151 debug_delegate_ = delegate; | 2048 debug_delegate_ = delegate; |
| 2049 owns_debug_delegate_ = pass_ownership; |
2152 UpdateState(); | 2050 UpdateState(); |
2153 } | 2051 } |
2154 | 2052 |
| 2053 void Debug::RemoveDebugDelegate() { |
| 2054 if (debug_delegate_ == nullptr) return; |
| 2055 if (owns_debug_delegate_) { |
| 2056 owns_debug_delegate_ = false; |
| 2057 delete debug_delegate_; |
| 2058 } |
| 2059 debug_delegate_ = nullptr; |
| 2060 } |
| 2061 |
2155 void Debug::UpdateState() { | 2062 void Debug::UpdateState() { |
2156 bool is_active = !event_listener_.is_null() || debug_delegate_ != nullptr; | 2063 bool is_active = debug_delegate_ != nullptr; |
2157 if (is_active || in_debug_scope()) { | 2064 if (is_active || in_debug_scope()) { |
2158 // Note that the debug context could have already been loaded to | 2065 // Note that the debug context could have already been loaded to |
2159 // bootstrap test cases. | 2066 // bootstrap test cases. |
2160 isolate_->compilation_cache()->Disable(); | 2067 isolate_->compilation_cache()->Disable(); |
2161 is_active = Load(); | 2068 is_active = Load(); |
2162 } else if (is_loaded()) { | 2069 } else if (is_loaded()) { |
2163 isolate_->compilation_cache()->Enable(); | 2070 isolate_->compilation_cache()->Enable(); |
2164 Unload(); | 2071 Unload(); |
2165 } | 2072 } |
2166 is_active_ = is_active; | 2073 is_active_ = is_active; |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2351 bool Debug::PerformSideEffectCheckForCallback(Address function) { | 2258 bool Debug::PerformSideEffectCheckForCallback(Address function) { |
2352 DCHECK(isolate_->needs_side_effect_check()); | 2259 DCHECK(isolate_->needs_side_effect_check()); |
2353 if (DebugEvaluate::CallbackHasNoSideEffect(function)) return true; | 2260 if (DebugEvaluate::CallbackHasNoSideEffect(function)) return true; |
2354 side_effect_check_failed_ = true; | 2261 side_effect_check_failed_ = true; |
2355 // Throw an uncatchable termination exception. | 2262 // Throw an uncatchable termination exception. |
2356 isolate_->TerminateExecution(); | 2263 isolate_->TerminateExecution(); |
2357 isolate_->OptionalRescheduleException(false); | 2264 isolate_->OptionalRescheduleException(false); |
2358 return false; | 2265 return false; |
2359 } | 2266 } |
2360 | 2267 |
| 2268 void LegacyDebugDelegate::PromiseEventOccurred( |
| 2269 v8::debug::PromiseDebugActionType type, int id, int parent_id) { |
| 2270 Handle<Object> event_data; |
| 2271 if (isolate_->debug()->MakeAsyncTaskEvent(type, id).ToHandle(&event_data)) { |
| 2272 ProcessDebugEvent(v8::AsyncTaskEvent, Handle<JSObject>::cast(event_data)); |
| 2273 } |
| 2274 } |
| 2275 |
| 2276 void LegacyDebugDelegate::ScriptCompiled(v8::Local<v8::debug::Script> script, |
| 2277 bool is_compile_error) { |
| 2278 Handle<Object> event_data; |
| 2279 v8::DebugEvent event = is_compile_error ? v8::CompileError : v8::AfterCompile; |
| 2280 if (isolate_->debug() |
| 2281 ->MakeCompileEvent(v8::Utils::OpenHandle(*script), event) |
| 2282 .ToHandle(&event_data)) { |
| 2283 ProcessDebugEvent(event, Handle<JSObject>::cast(event_data)); |
| 2284 } |
| 2285 } |
| 2286 |
| 2287 void LegacyDebugDelegate::BreakProgramRequested( |
| 2288 v8::Local<v8::Context> paused_context, v8::Local<v8::Object> exec_state, |
| 2289 v8::Local<v8::Value> break_points_hit) { |
| 2290 Handle<Object> event_data; |
| 2291 if (isolate_->debug() |
| 2292 ->MakeBreakEvent(v8::Utils::OpenHandle(*break_points_hit)) |
| 2293 .ToHandle(&event_data)) { |
| 2294 ProcessDebugEvent( |
| 2295 v8::Break, Handle<JSObject>::cast(event_data), |
| 2296 Handle<JSObject>::cast(v8::Utils::OpenHandle(*exec_state))); |
| 2297 } |
| 2298 } |
| 2299 |
| 2300 void LegacyDebugDelegate::ExceptionThrown(v8::Local<v8::Context> paused_context, |
| 2301 v8::Local<v8::Object> exec_state, |
| 2302 v8::Local<v8::Value> exception, |
| 2303 v8::Local<v8::Value> promise, |
| 2304 bool is_uncaught) { |
| 2305 Handle<Object> event_data; |
| 2306 if (isolate_->debug() |
| 2307 ->MakeExceptionEvent(v8::Utils::OpenHandle(*exception), is_uncaught, |
| 2308 v8::Utils::OpenHandle(*promise)) |
| 2309 .ToHandle(&event_data)) { |
| 2310 ProcessDebugEvent( |
| 2311 v8::Exception, Handle<JSObject>::cast(event_data), |
| 2312 Handle<JSObject>::cast(v8::Utils::OpenHandle(*exec_state))); |
| 2313 } |
| 2314 } |
| 2315 |
| 2316 void LegacyDebugDelegate::ProcessDebugEvent(v8::DebugEvent event, |
| 2317 Handle<JSObject> event_data) { |
| 2318 Handle<Object> exec_state; |
| 2319 if (isolate_->debug()->MakeExecutionState().ToHandle(&exec_state)) { |
| 2320 ProcessDebugEvent(event, event_data, Handle<JSObject>::cast(exec_state)); |
| 2321 } |
| 2322 } |
| 2323 |
| 2324 JavaScriptDebugDelegate::JavaScriptDebugDelegate(Isolate* isolate, |
| 2325 Handle<JSFunction> listener, |
| 2326 Handle<Object> data) |
| 2327 : LegacyDebugDelegate(isolate) { |
| 2328 GlobalHandles* global_handles = isolate->global_handles(); |
| 2329 listener_ = Handle<JSFunction>::cast(global_handles->Create(*listener)); |
| 2330 data_ = global_handles->Create(*data); |
| 2331 } |
| 2332 |
| 2333 JavaScriptDebugDelegate::~JavaScriptDebugDelegate() { |
| 2334 GlobalHandles::Destroy(Handle<Object>::cast(listener_).location()); |
| 2335 GlobalHandles::Destroy(data_.location()); |
| 2336 } |
| 2337 |
| 2338 void JavaScriptDebugDelegate::ProcessDebugEvent(v8::DebugEvent event, |
| 2339 Handle<JSObject> event_data, |
| 2340 Handle<JSObject> exec_state) { |
| 2341 Handle<Object> argv[] = {Handle<Object>(Smi::FromInt(event), isolate_), |
| 2342 exec_state, event_data, data_}; |
| 2343 Handle<JSReceiver> global = isolate_->global_proxy(); |
| 2344 // Listener must not throw. |
| 2345 Execution::Call(isolate_, listener_, global, arraysize(argv), argv) |
| 2346 .ToHandleChecked(); |
| 2347 } |
| 2348 |
| 2349 NativeDebugDelegate::NativeDebugDelegate(Isolate* isolate, |
| 2350 v8::Debug::EventCallback callback, |
| 2351 Handle<Object> data) |
| 2352 : LegacyDebugDelegate(isolate), callback_(callback) { |
| 2353 data_ = isolate->global_handles()->Create(*data); |
| 2354 } |
| 2355 |
| 2356 NativeDebugDelegate::~NativeDebugDelegate() { |
| 2357 GlobalHandles::Destroy(data_.location()); |
| 2358 } |
| 2359 |
| 2360 NativeDebugDelegate::EventDetails::EventDetails(DebugEvent event, |
| 2361 Handle<JSObject> exec_state, |
| 2362 Handle<JSObject> event_data, |
| 2363 Handle<Object> callback_data) |
| 2364 : event_(event), |
| 2365 exec_state_(exec_state), |
| 2366 event_data_(event_data), |
| 2367 callback_data_(callback_data) {} |
| 2368 |
| 2369 DebugEvent NativeDebugDelegate::EventDetails::GetEvent() const { |
| 2370 return event_; |
| 2371 } |
| 2372 |
| 2373 v8::Local<v8::Object> NativeDebugDelegate::EventDetails::GetExecutionState() |
| 2374 const { |
| 2375 return v8::Utils::ToLocal(exec_state_); |
| 2376 } |
| 2377 |
| 2378 v8::Local<v8::Object> NativeDebugDelegate::EventDetails::GetEventData() const { |
| 2379 return v8::Utils::ToLocal(event_data_); |
| 2380 } |
| 2381 |
| 2382 v8::Local<v8::Context> NativeDebugDelegate::EventDetails::GetEventContext() |
| 2383 const { |
| 2384 return GetDebugEventContext(exec_state_->GetIsolate()); |
| 2385 } |
| 2386 |
| 2387 v8::Local<v8::Value> NativeDebugDelegate::EventDetails::GetCallbackData() |
| 2388 const { |
| 2389 return v8::Utils::ToLocal(callback_data_); |
| 2390 } |
| 2391 |
| 2392 v8::Isolate* NativeDebugDelegate::EventDetails::GetIsolate() const { |
| 2393 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate()); |
| 2394 } |
| 2395 |
| 2396 void NativeDebugDelegate::ProcessDebugEvent(v8::DebugEvent event, |
| 2397 Handle<JSObject> event_data, |
| 2398 Handle<JSObject> exec_state) { |
| 2399 EventDetails event_details(event, exec_state, event_data, data_); |
| 2400 Isolate* isolate = isolate_; |
| 2401 callback_(event_details); |
| 2402 CHECK(!isolate->has_scheduled_exception()); |
| 2403 } |
| 2404 |
2361 NoSideEffectScope::~NoSideEffectScope() { | 2405 NoSideEffectScope::~NoSideEffectScope() { |
2362 if (isolate_->needs_side_effect_check() && | 2406 if (isolate_->needs_side_effect_check() && |
2363 isolate_->debug()->side_effect_check_failed_) { | 2407 isolate_->debug()->side_effect_check_failed_) { |
2364 DCHECK(isolate_->has_pending_exception()); | 2408 DCHECK(isolate_->has_pending_exception()); |
2365 DCHECK_EQ(isolate_->heap()->termination_exception(), | 2409 DCHECK_EQ(isolate_->heap()->termination_exception(), |
2366 isolate_->pending_exception()); | 2410 isolate_->pending_exception()); |
2367 // Convert the termination exception into a regular exception. | 2411 // Convert the termination exception into a regular exception. |
2368 isolate_->CancelTerminateExecution(); | 2412 isolate_->CancelTerminateExecution(); |
2369 isolate_->Throw(*isolate_->factory()->NewEvalError( | 2413 isolate_->Throw(*isolate_->factory()->NewEvalError( |
2370 MessageTemplate::kNoSideEffectDebugEvaluate)); | 2414 MessageTemplate::kNoSideEffectDebugEvaluate)); |
2371 } | 2415 } |
2372 isolate_->set_needs_side_effect_check(old_needs_side_effect_check_); | 2416 isolate_->set_needs_side_effect_check(old_needs_side_effect_check_); |
2373 isolate_->debug()->UpdateHookOnFunctionCall(); | 2417 isolate_->debug()->UpdateHookOnFunctionCall(); |
2374 isolate_->debug()->side_effect_check_failed_ = false; | 2418 isolate_->debug()->side_effect_check_failed_ = false; |
2375 } | 2419 } |
2376 | 2420 |
2377 EventDetailsImpl::EventDetailsImpl(DebugEvent event, | |
2378 Handle<JSObject> exec_state, | |
2379 Handle<JSObject> event_data, | |
2380 Handle<Object> callback_data) | |
2381 : event_(event), | |
2382 exec_state_(exec_state), | |
2383 event_data_(event_data), | |
2384 callback_data_(callback_data) {} | |
2385 | |
2386 DebugEvent EventDetailsImpl::GetEvent() const { | |
2387 return event_; | |
2388 } | |
2389 | |
2390 | |
2391 v8::Local<v8::Object> EventDetailsImpl::GetExecutionState() const { | |
2392 return v8::Utils::ToLocal(exec_state_); | |
2393 } | |
2394 | |
2395 | |
2396 v8::Local<v8::Object> EventDetailsImpl::GetEventData() const { | |
2397 return v8::Utils::ToLocal(event_data_); | |
2398 } | |
2399 | |
2400 | |
2401 v8::Local<v8::Context> EventDetailsImpl::GetEventContext() const { | |
2402 return GetDebugEventContext(exec_state_->GetIsolate()); | |
2403 } | |
2404 | |
2405 | |
2406 v8::Local<v8::Value> EventDetailsImpl::GetCallbackData() const { | |
2407 return v8::Utils::ToLocal(callback_data_); | |
2408 } | |
2409 | |
2410 | |
2411 v8::Isolate* EventDetailsImpl::GetIsolate() const { | |
2412 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate()); | |
2413 } | |
2414 | |
2415 } // namespace internal | 2421 } // namespace internal |
2416 } // namespace v8 | 2422 } // namespace v8 |
OLD | NEW |