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 | 31 |
32 #include "include/v8-debug.h" | 32 #include "include/v8-debug.h" |
33 | 33 |
34 namespace v8 { | 34 namespace v8 { |
35 namespace internal { | 35 namespace internal { |
36 | 36 |
37 Debug::Debug(Isolate* isolate) | 37 Debug::Debug(Isolate* isolate) |
38 : debug_context_(Handle<Context>()), | 38 : debug_context_(Handle<Context>()), |
39 event_listener_(Handle<Object>()), | 39 event_listener_(Handle<Object>()), |
40 event_listener_data_(Handle<Object>()), | 40 event_listener_data_(Handle<Object>()), |
| 41 message_handler_(NULL), |
| 42 command_received_(0), |
| 43 command_queue_(isolate->logger(), kQueueInitialSize), |
41 is_active_(false), | 44 is_active_(false), |
42 is_suppressed_(false), | 45 is_suppressed_(false), |
43 live_edit_enabled_(true), // TODO(yangguo): set to false by default. | 46 live_edit_enabled_(true), // TODO(yangguo): set to false by default. |
44 break_disabled_(false), | 47 break_disabled_(false), |
45 break_points_active_(true), | 48 break_points_active_(true), |
46 in_debug_event_listener_(false), | 49 in_debug_event_listener_(false), |
47 break_on_exception_(false), | 50 break_on_exception_(false), |
48 break_on_uncaught_exception_(false), | 51 break_on_uncaught_exception_(false), |
49 debug_info_list_(NULL), | 52 debug_info_list_(NULL), |
50 feature_tracker_(isolate), | 53 feature_tracker_(isolate), |
(...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
515 | 518 |
516 // Find the break location where execution has stopped. | 519 // Find the break location where execution has stopped. |
517 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); | 520 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); |
518 | 521 |
519 // Find actual break points, if any, and trigger debug break event. | 522 // Find actual break points, if any, and trigger debug break event. |
520 Handle<Object> break_points_hit = CheckBreakPoints(debug_info, &location); | 523 Handle<Object> break_points_hit = CheckBreakPoints(debug_info, &location); |
521 if (!break_points_hit->IsUndefined(isolate_)) { | 524 if (!break_points_hit->IsUndefined(isolate_)) { |
522 // Clear all current stepping setup. | 525 // Clear all current stepping setup. |
523 ClearStepping(); | 526 ClearStepping(); |
524 // Notify the debug event listeners. | 527 // Notify the debug event listeners. |
525 OnDebugBreak(break_points_hit); | 528 OnDebugBreak(break_points_hit, false); |
526 return; | 529 return; |
527 } | 530 } |
528 | 531 |
529 // No break point. Check for stepping. | 532 // No break point. Check for stepping. |
530 StepAction step_action = last_step_action(); | 533 StepAction step_action = last_step_action(); |
531 Address current_fp = frame->UnpaddedFP(); | 534 Address current_fp = frame->UnpaddedFP(); |
532 Address target_fp = thread_local_.target_fp_; | 535 Address target_fp = thread_local_.target_fp_; |
533 Address last_fp = thread_local_.last_fp_; | 536 Address last_fp = thread_local_.last_fp_; |
534 | 537 |
535 bool step_break = false; | 538 bool step_break = false; |
(...skipping 23 matching lines...) Expand all Loading... |
559 case StepFrame: | 562 case StepFrame: |
560 step_break = current_fp != last_fp; | 563 step_break = current_fp != last_fp; |
561 break; | 564 break; |
562 } | 565 } |
563 | 566 |
564 // Clear all current stepping setup. | 567 // Clear all current stepping setup. |
565 ClearStepping(); | 568 ClearStepping(); |
566 | 569 |
567 if (step_break) { | 570 if (step_break) { |
568 // Notify the debug event listeners. | 571 // Notify the debug event listeners. |
569 OnDebugBreak(isolate_->factory()->undefined_value()); | 572 OnDebugBreak(isolate_->factory()->undefined_value(), false); |
570 } else { | 573 } else { |
571 // Re-prepare to continue. | 574 // Re-prepare to continue. |
572 PrepareStep(step_action); | 575 PrepareStep(step_action); |
573 } | 576 } |
574 } | 577 } |
575 | 578 |
576 | 579 |
577 // Find break point objects for this location, if any, and evaluate them. | 580 // Find break point objects for this location, if any, and evaluate them. |
578 // Return an array of break point objects that evaluated true. | 581 // Return an array of break point objects that evaluated true. |
579 Handle<Object> Debug::CheckBreakPoints(Handle<DebugInfo> debug_info, | 582 Handle<Object> Debug::CheckBreakPoints(Handle<DebugInfo> debug_info, |
(...skipping 1157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1737 | 1740 |
1738 // Create the event data object. | 1741 // Create the event data object. |
1739 Handle<Object> event_data; | 1742 Handle<Object> event_data; |
1740 // Bail out and don't call debugger if exception. | 1743 // Bail out and don't call debugger if exception. |
1741 if (!MakeExceptionEvent( | 1744 if (!MakeExceptionEvent( |
1742 exception, uncaught, promise).ToHandle(&event_data)) { | 1745 exception, uncaught, promise).ToHandle(&event_data)) { |
1743 return; | 1746 return; |
1744 } | 1747 } |
1745 | 1748 |
1746 // Process debug event. | 1749 // Process debug event. |
1747 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data)); | 1750 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false); |
1748 // Return to continue execution from where the exception was thrown. | 1751 // Return to continue execution from where the exception was thrown. |
1749 } | 1752 } |
1750 | 1753 |
1751 void Debug::OnDebugBreak(Handle<Object> break_points_hit) { | 1754 void Debug::OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue) { |
1752 // The caller provided for DebugScope. | 1755 // The caller provided for DebugScope. |
1753 AssertDebugContext(); | 1756 AssertDebugContext(); |
1754 // Bail out if there is no listener for this event | 1757 // Bail out if there is no listener for this event |
1755 if (ignore_events()) return; | 1758 if (ignore_events()) return; |
1756 | 1759 |
1757 #ifdef DEBUG | 1760 #ifdef DEBUG |
1758 PrintBreakLocation(); | 1761 PrintBreakLocation(); |
1759 #endif // DEBUG | 1762 #endif // DEBUG |
1760 | 1763 |
1761 HandleScope scope(isolate_); | 1764 HandleScope scope(isolate_); |
1762 // Create the event data object. | 1765 // Create the event data object. |
1763 Handle<Object> event_data; | 1766 Handle<Object> event_data; |
1764 // Bail out and don't call debugger if exception. | 1767 // Bail out and don't call debugger if exception. |
1765 if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return; | 1768 if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return; |
1766 | 1769 |
1767 // Process debug event. | 1770 // Process debug event. |
1768 ProcessDebugEvent(v8::Break, Handle<JSObject>::cast(event_data)); | 1771 ProcessDebugEvent(v8::Break, Handle<JSObject>::cast(event_data), |
| 1772 auto_continue); |
1769 } | 1773 } |
1770 | 1774 |
1771 | 1775 |
1772 void Debug::OnCompileError(Handle<Script> script) { | 1776 void Debug::OnCompileError(Handle<Script> script) { |
1773 ProcessCompileEvent(v8::CompileError, script); | 1777 ProcessCompileEvent(v8::CompileError, script); |
1774 } | 1778 } |
1775 | 1779 |
| 1780 void Debug::OnBeforeCompile(Handle<Script> script) { |
| 1781 ProcessCompileEvent(v8::BeforeCompile, script); |
| 1782 } |
1776 | 1783 |
1777 // Handle debugger actions when a new script is compiled. | 1784 // Handle debugger actions when a new script is compiled. |
1778 void Debug::OnAfterCompile(Handle<Script> script) { | 1785 void Debug::OnAfterCompile(Handle<Script> script) { |
1779 ProcessCompileEvent(v8::AfterCompile, script); | 1786 ProcessCompileEvent(v8::AfterCompile, script); |
1780 } | 1787 } |
1781 | 1788 |
1782 void Debug::OnAsyncTaskEvent(Handle<String> type, Handle<Object> id, | 1789 void Debug::OnAsyncTaskEvent(Handle<String> type, Handle<Object> id, |
1783 Handle<String> name) { | 1790 Handle<String> name) { |
1784 DCHECK(id->IsNumber()); | 1791 DCHECK(id->IsNumber()); |
1785 if (in_debug_scope() || ignore_events()) return; | 1792 if (in_debug_scope() || ignore_events()) return; |
1786 | 1793 |
1787 HandleScope scope(isolate_); | 1794 HandleScope scope(isolate_); |
1788 DebugScope debug_scope(this); | 1795 DebugScope debug_scope(this); |
1789 if (debug_scope.failed()) return; | 1796 if (debug_scope.failed()) return; |
1790 | 1797 |
1791 // Create the script collected state object. | 1798 // Create the script collected state object. |
1792 Handle<Object> event_data; | 1799 Handle<Object> event_data; |
1793 // Bail out and don't call debugger if exception. | 1800 // Bail out and don't call debugger if exception. |
1794 if (!MakeAsyncTaskEvent(type, id, name).ToHandle(&event_data)) return; | 1801 if (!MakeAsyncTaskEvent(type, id, name).ToHandle(&event_data)) return; |
1795 | 1802 |
1796 // Process debug event. | 1803 // Process debug event. |
1797 ProcessDebugEvent(v8::AsyncTaskEvent, Handle<JSObject>::cast(event_data)); | 1804 ProcessDebugEvent(v8::AsyncTaskEvent, Handle<JSObject>::cast(event_data), |
| 1805 true); |
1798 } | 1806 } |
1799 | 1807 |
1800 void Debug::ProcessDebugEvent(v8::DebugEvent event, | 1808 void Debug::ProcessDebugEvent(v8::DebugEvent event, Handle<JSObject> event_data, |
1801 Handle<JSObject> event_data) { | 1809 bool auto_continue) { |
1802 HandleScope scope(isolate_); | 1810 HandleScope scope(isolate_); |
1803 | 1811 |
1804 // Create the execution state. | 1812 // Create the execution state. |
1805 Handle<Object> exec_state; | 1813 Handle<Object> exec_state; |
1806 // Bail out and don't call debugger if exception. | 1814 // Bail out and don't call debugger if exception. |
1807 if (!MakeExecutionState().ToHandle(&exec_state)) return; | 1815 if (!MakeExecutionState().ToHandle(&exec_state)) return; |
1808 | 1816 |
1809 // Notify registered debug event listener. | 1817 // First notify the message handler if any. |
1810 if (!event_listener_.is_null()) { | 1818 if (message_handler_ != NULL) { |
| 1819 NotifyMessageHandler(event, Handle<JSObject>::cast(exec_state), event_data, |
| 1820 auto_continue); |
| 1821 } |
| 1822 // Notify registered debug event listener. This can be either a C or |
| 1823 // a JavaScript function. Don't call event listener for v8::Break |
| 1824 // here, if it's only a debug command -- they will be processed later. |
| 1825 if ((event != v8::Break || !auto_continue) && !event_listener_.is_null()) { |
1811 CallEventCallback(event, exec_state, event_data, NULL); | 1826 CallEventCallback(event, exec_state, event_data, NULL); |
1812 } | 1827 } |
1813 } | 1828 } |
1814 | 1829 |
1815 | 1830 |
1816 void Debug::CallEventCallback(v8::DebugEvent event, | 1831 void Debug::CallEventCallback(v8::DebugEvent event, |
1817 Handle<Object> exec_state, | 1832 Handle<Object> exec_state, |
1818 Handle<Object> event_data, | 1833 Handle<Object> event_data, |
1819 v8::Debug::ClientData* client_data) { | 1834 v8::Debug::ClientData* client_data) { |
1820 // Prevent other interrupts from triggering, for example API callbacks, | 1835 // Prevent other interrupts from triggering, for example API callbacks, |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1852 | 1867 |
1853 | 1868 |
1854 void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) { | 1869 void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) { |
1855 if (ignore_events()) return; | 1870 if (ignore_events()) return; |
1856 if (script->type() != i::Script::TYPE_NORMAL && | 1871 if (script->type() != i::Script::TYPE_NORMAL && |
1857 script->type() != i::Script::TYPE_WASM) { | 1872 script->type() != i::Script::TYPE_WASM) { |
1858 return; | 1873 return; |
1859 } | 1874 } |
1860 SuppressDebug while_processing(this); | 1875 SuppressDebug while_processing(this); |
1861 | 1876 |
| 1877 bool in_nested_debug_scope = in_debug_scope(); |
1862 HandleScope scope(isolate_); | 1878 HandleScope scope(isolate_); |
1863 DebugScope debug_scope(this); | 1879 DebugScope debug_scope(this); |
1864 if (debug_scope.failed()) return; | 1880 if (debug_scope.failed()) return; |
1865 | 1881 |
1866 if (event == v8::AfterCompile) { | 1882 if (event == v8::AfterCompile) { |
1867 // If debugging there might be script break points registered for this | 1883 // If debugging there might be script break points registered for this |
1868 // script. Make sure that these break points are set. | 1884 // script. Make sure that these break points are set. |
1869 Handle<Object> argv[] = {Script::GetWrapper(script)}; | 1885 Handle<Object> argv[] = {Script::GetWrapper(script)}; |
1870 if (CallFunction("UpdateScriptBreakPoints", arraysize(argv), argv) | 1886 if (CallFunction("UpdateScriptBreakPoints", arraysize(argv), argv) |
1871 .is_null()) { | 1887 .is_null()) { |
1872 return; | 1888 return; |
1873 } | 1889 } |
1874 } | 1890 } |
1875 | 1891 |
1876 // Create the compile state object. | 1892 // Create the compile state object. |
1877 Handle<Object> event_data; | 1893 Handle<Object> event_data; |
1878 // Bail out and don't call debugger if exception. | 1894 // Bail out and don't call debugger if exception. |
1879 if (!MakeCompileEvent(script, event).ToHandle(&event_data)) return; | 1895 if (!MakeCompileEvent(script, event).ToHandle(&event_data)) return; |
1880 | 1896 |
1881 ProcessDebugEvent(event, Handle<JSObject>::cast(event_data)); | 1897 // Don't call NotifyMessageHandler if already in debug scope to avoid running |
| 1898 // nested command loop. |
| 1899 if (in_nested_debug_scope) { |
| 1900 if (event_listener_.is_null()) return; |
| 1901 // Create the execution state. |
| 1902 Handle<Object> exec_state; |
| 1903 // Bail out and don't call debugger if exception. |
| 1904 if (!MakeExecutionState().ToHandle(&exec_state)) return; |
| 1905 |
| 1906 CallEventCallback(event, exec_state, event_data, NULL); |
| 1907 } else { |
| 1908 // Process debug event. |
| 1909 ProcessDebugEvent(event, Handle<JSObject>::cast(event_data), true); |
| 1910 } |
1882 } | 1911 } |
1883 | 1912 |
1884 | 1913 |
1885 Handle<Context> Debug::GetDebugContext() { | 1914 Handle<Context> Debug::GetDebugContext() { |
1886 if (!is_loaded()) return Handle<Context>(); | 1915 if (!is_loaded()) return Handle<Context>(); |
1887 DebugScope debug_scope(this); | 1916 DebugScope debug_scope(this); |
1888 if (debug_scope.failed()) return Handle<Context>(); | 1917 if (debug_scope.failed()) return Handle<Context>(); |
1889 // The global handle may be destroyed soon after. Return it reboxed. | 1918 // The global handle may be destroyed soon after. Return it reboxed. |
1890 return handle(*debug_context(), isolate_); | 1919 return handle(*debug_context(), isolate_); |
1891 } | 1920 } |
1892 | 1921 |
| 1922 void Debug::NotifyMessageHandler(v8::DebugEvent event, |
| 1923 Handle<JSObject> exec_state, |
| 1924 Handle<JSObject> event_data, |
| 1925 bool auto_continue) { |
| 1926 // Prevent other interrupts from triggering, for example API callbacks, |
| 1927 // while dispatching message handler callbacks. |
| 1928 PostponeInterruptsScope no_interrupts(isolate_); |
| 1929 DCHECK(is_active_); |
| 1930 HandleScope scope(isolate_); |
| 1931 // Process the individual events. |
| 1932 bool sendEventMessage = false; |
| 1933 switch (event) { |
| 1934 case v8::Break: |
| 1935 sendEventMessage = !auto_continue; |
| 1936 break; |
| 1937 case v8::NewFunction: |
| 1938 case v8::BeforeCompile: |
| 1939 case v8::CompileError: |
| 1940 case v8::AsyncTaskEvent: |
| 1941 break; |
| 1942 case v8::Exception: |
| 1943 case v8::AfterCompile: |
| 1944 sendEventMessage = true; |
| 1945 break; |
| 1946 } |
| 1947 |
| 1948 // The debug command interrupt flag might have been set when the command was |
| 1949 // added. It should be enough to clear the flag only once while we are in the |
| 1950 // debugger. |
| 1951 DCHECK(in_debug_scope()); |
| 1952 isolate_->stack_guard()->ClearDebugCommand(); |
| 1953 |
| 1954 // Notify the debugger that a debug event has occurred unless auto continue is |
| 1955 // active in which case no event is send. |
| 1956 if (sendEventMessage) { |
| 1957 MessageImpl message = MessageImpl::NewEvent( |
| 1958 event, auto_continue, Handle<JSObject>::cast(exec_state), |
| 1959 Handle<JSObject>::cast(event_data)); |
| 1960 InvokeMessageHandler(message); |
| 1961 } |
| 1962 |
| 1963 // If auto continue don't make the event cause a break, but process messages |
| 1964 // in the queue if any. For script collected events don't even process |
| 1965 // messages in the queue as the execution state might not be what is expected |
| 1966 // by the client. |
| 1967 if (auto_continue && !has_commands()) return; |
| 1968 |
| 1969 // DebugCommandProcessor goes here. |
| 1970 bool running = auto_continue; |
| 1971 |
| 1972 Handle<Object> cmd_processor_ctor = |
| 1973 JSReceiver::GetProperty(isolate_, exec_state, "debugCommandProcessor") |
| 1974 .ToHandleChecked(); |
| 1975 Handle<Object> ctor_args[] = {isolate_->factory()->ToBoolean(running)}; |
| 1976 Handle<JSReceiver> cmd_processor = Handle<JSReceiver>::cast( |
| 1977 Execution::Call(isolate_, cmd_processor_ctor, exec_state, 1, ctor_args) |
| 1978 .ToHandleChecked()); |
| 1979 Handle<JSFunction> process_debug_request = Handle<JSFunction>::cast( |
| 1980 JSReceiver::GetProperty(isolate_, cmd_processor, "processDebugRequest") |
| 1981 .ToHandleChecked()); |
| 1982 Handle<Object> is_running = |
| 1983 JSReceiver::GetProperty(isolate_, cmd_processor, "isRunning") |
| 1984 .ToHandleChecked(); |
| 1985 |
| 1986 // Process requests from the debugger. |
| 1987 do { |
| 1988 // Wait for new command in the queue. |
| 1989 command_received_.Wait(); |
| 1990 |
| 1991 // Get the command from the queue. |
| 1992 CommandMessage command = command_queue_.Get(); |
| 1993 isolate_->logger()->DebugTag( |
| 1994 "Got request from command queue, in interactive loop."); |
| 1995 if (!is_active()) { |
| 1996 // Delete command text and user data. |
| 1997 command.Dispose(); |
| 1998 return; |
| 1999 } |
| 2000 |
| 2001 Vector<const uc16> command_text( |
| 2002 const_cast<const uc16*>(command.text().start()), |
| 2003 command.text().length()); |
| 2004 Handle<String> request_text = isolate_->factory() |
| 2005 ->NewStringFromTwoByte(command_text) |
| 2006 .ToHandleChecked(); |
| 2007 Handle<Object> request_args[] = {request_text}; |
| 2008 Handle<Object> answer_value; |
| 2009 Handle<String> answer; |
| 2010 MaybeHandle<Object> maybe_exception; |
| 2011 MaybeHandle<Object> maybe_result = |
| 2012 Execution::TryCall(isolate_, process_debug_request, cmd_processor, 1, |
| 2013 request_args, &maybe_exception); |
| 2014 |
| 2015 if (maybe_result.ToHandle(&answer_value)) { |
| 2016 if (answer_value->IsUndefined(isolate_)) { |
| 2017 answer = isolate_->factory()->empty_string(); |
| 2018 } else { |
| 2019 answer = Handle<String>::cast(answer_value); |
| 2020 } |
| 2021 |
| 2022 // Log the JSON request/response. |
| 2023 if (FLAG_trace_debug_json) { |
| 2024 PrintF("%s\n", request_text->ToCString().get()); |
| 2025 PrintF("%s\n", answer->ToCString().get()); |
| 2026 } |
| 2027 |
| 2028 Handle<Object> is_running_args[] = {answer}; |
| 2029 maybe_result = Execution::Call(isolate_, is_running, cmd_processor, 1, |
| 2030 is_running_args); |
| 2031 Handle<Object> result; |
| 2032 if (!maybe_result.ToHandle(&result)) break; |
| 2033 running = result->IsTrue(isolate_); |
| 2034 } else { |
| 2035 Handle<Object> exception; |
| 2036 if (!maybe_exception.ToHandle(&exception)) break; |
| 2037 Handle<Object> result; |
| 2038 if (!Object::ToString(isolate_, exception).ToHandle(&result)) break; |
| 2039 answer = Handle<String>::cast(result); |
| 2040 } |
| 2041 |
| 2042 // Return the result. |
| 2043 MessageImpl message = MessageImpl::NewResponse( |
| 2044 event, running, exec_state, event_data, answer, command.client_data()); |
| 2045 InvokeMessageHandler(message); |
| 2046 command.Dispose(); |
| 2047 |
| 2048 // Return from debug event processing if either the VM is put into the |
| 2049 // running state (through a continue command) or auto continue is active |
| 2050 // and there are no more commands queued. |
| 2051 } while (!running || has_commands()); |
| 2052 command_queue_.Clear(); |
| 2053 } |
1893 | 2054 |
1894 void Debug::SetEventListener(Handle<Object> callback, | 2055 void Debug::SetEventListener(Handle<Object> callback, |
1895 Handle<Object> data) { | 2056 Handle<Object> data) { |
1896 GlobalHandles* global_handles = isolate_->global_handles(); | 2057 GlobalHandles* global_handles = isolate_->global_handles(); |
1897 | 2058 |
1898 // Remove existing entry. | 2059 // Remove existing entry. |
1899 GlobalHandles::Destroy(event_listener_.location()); | 2060 GlobalHandles::Destroy(event_listener_.location()); |
1900 event_listener_ = Handle<Object>(); | 2061 event_listener_ = Handle<Object>(); |
1901 GlobalHandles::Destroy(event_listener_data_.location()); | 2062 GlobalHandles::Destroy(event_listener_data_.location()); |
1902 event_listener_data_ = Handle<Object>(); | 2063 event_listener_data_ = Handle<Object>(); |
1903 | 2064 |
1904 // Set new entry. | 2065 // Set new entry. |
1905 if (!callback->IsUndefined(isolate_) && !callback->IsNull(isolate_)) { | 2066 if (!callback->IsUndefined(isolate_) && !callback->IsNull(isolate_)) { |
1906 event_listener_ = global_handles->Create(*callback); | 2067 event_listener_ = global_handles->Create(*callback); |
1907 if (data.is_null()) data = isolate_->factory()->undefined_value(); | 2068 if (data.is_null()) data = isolate_->factory()->undefined_value(); |
1908 event_listener_data_ = global_handles->Create(*data); | 2069 event_listener_data_ = global_handles->Create(*data); |
1909 } | 2070 } |
1910 | 2071 |
1911 UpdateState(); | 2072 UpdateState(); |
1912 } | 2073 } |
1913 | 2074 |
| 2075 void Debug::SetMessageHandler(v8::Debug::MessageHandler handler) { |
| 2076 message_handler_ = handler; |
| 2077 UpdateState(); |
| 2078 if (handler == NULL && in_debug_scope()) { |
| 2079 // Send an empty command to the debugger if in a break to make JavaScript |
| 2080 // run again if the debugger is closed. |
| 2081 EnqueueCommandMessage(Vector<const uint16_t>::empty()); |
| 2082 } |
| 2083 } |
1914 | 2084 |
1915 void Debug::UpdateState() { | 2085 void Debug::UpdateState() { |
1916 bool is_active = !event_listener_.is_null(); | 2086 bool is_active = message_handler_ != NULL || !event_listener_.is_null(); |
1917 if (is_active || in_debug_scope()) { | 2087 if (is_active || in_debug_scope()) { |
1918 // Note that the debug context could have already been loaded to | 2088 // Note that the debug context could have already been loaded to |
1919 // bootstrap test cases. | 2089 // bootstrap test cases. |
1920 isolate_->compilation_cache()->Disable(); | 2090 isolate_->compilation_cache()->Disable(); |
1921 is_active = Load(); | 2091 is_active = Load(); |
1922 } else if (is_loaded()) { | 2092 } else if (is_loaded()) { |
1923 isolate_->compilation_cache()->Enable(); | 2093 isolate_->compilation_cache()->Enable(); |
1924 Unload(); | 2094 Unload(); |
1925 } | 2095 } |
1926 is_active_ = is_active; | 2096 is_active_ = is_active; |
1927 } | 2097 } |
1928 | 2098 |
| 2099 // Calls the registered debug message handler. This callback is part of the |
| 2100 // public API. |
| 2101 void Debug::InvokeMessageHandler(MessageImpl message) { |
| 2102 if (message_handler_ != NULL) message_handler_(message); |
| 2103 } |
| 2104 |
| 2105 // Puts a command coming from the public API on the queue. Creates |
| 2106 // a copy of the command string managed by the debugger. Up to this |
| 2107 // point, the command data was managed by the API client. Called |
| 2108 // by the API client thread. |
| 2109 void Debug::EnqueueCommandMessage(Vector<const uint16_t> command, |
| 2110 v8::Debug::ClientData* client_data) { |
| 2111 // Need to cast away const. |
| 2112 CommandMessage message = CommandMessage::New( |
| 2113 Vector<uint16_t>(const_cast<uint16_t*>(command.start()), |
| 2114 command.length()), |
| 2115 client_data); |
| 2116 isolate_->logger()->DebugTag("Put command on command_queue."); |
| 2117 command_queue_.Put(message); |
| 2118 command_received_.Signal(); |
| 2119 |
| 2120 // Set the debug command break flag to have the command processed. |
| 2121 if (!in_debug_scope()) isolate_->stack_guard()->RequestDebugCommand(); |
| 2122 } |
1929 | 2123 |
1930 MaybeHandle<Object> Debug::Call(Handle<Object> fun, Handle<Object> data) { | 2124 MaybeHandle<Object> Debug::Call(Handle<Object> fun, Handle<Object> data) { |
1931 DebugScope debug_scope(this); | 2125 DebugScope debug_scope(this); |
1932 if (debug_scope.failed()) return isolate_->factory()->undefined_value(); | 2126 if (debug_scope.failed()) return isolate_->factory()->undefined_value(); |
1933 | 2127 |
1934 // Create the execution state. | 2128 // Create the execution state. |
1935 Handle<Object> exec_state; | 2129 Handle<Object> exec_state; |
1936 if (!MakeExecutionState().ToHandle(&exec_state)) { | 2130 if (!MakeExecutionState().ToHandle(&exec_state)) { |
1937 return isolate_->factory()->undefined_value(); | 2131 return isolate_->factory()->undefined_value(); |
1938 } | 2132 } |
(...skipping 27 matching lines...) Expand all Loading... |
1966 if (!JSFunction::cast(fun)->shared()->IsSubjectToDebugging()) return; | 2160 if (!JSFunction::cast(fun)->shared()->IsSubjectToDebugging()) return; |
1967 JSGlobalObject* global = | 2161 JSGlobalObject* global = |
1968 JSFunction::cast(fun)->context()->global_object(); | 2162 JSFunction::cast(fun)->context()->global_object(); |
1969 // Don't stop in debugger functions. | 2163 // Don't stop in debugger functions. |
1970 if (IsDebugGlobal(global)) return; | 2164 if (IsDebugGlobal(global)) return; |
1971 // Don't stop if the break location is muted. | 2165 // Don't stop if the break location is muted. |
1972 if (IsMutedAtCurrentLocation(it.frame())) return; | 2166 if (IsMutedAtCurrentLocation(it.frame())) return; |
1973 } | 2167 } |
1974 } | 2168 } |
1975 | 2169 |
| 2170 // Collect the break state before clearing the flags. |
| 2171 bool debug_command_only = isolate_->stack_guard()->CheckDebugCommand() && |
| 2172 !isolate_->stack_guard()->CheckDebugBreak(); |
| 2173 |
1976 isolate_->stack_guard()->ClearDebugBreak(); | 2174 isolate_->stack_guard()->ClearDebugBreak(); |
1977 | 2175 |
1978 // Clear stepping to avoid duplicate breaks. | 2176 // Clear stepping to avoid duplicate breaks. |
1979 ClearStepping(); | 2177 ClearStepping(); |
1980 | 2178 |
| 2179 ProcessDebugMessages(debug_command_only); |
| 2180 } |
| 2181 |
| 2182 void Debug::ProcessDebugMessages(bool debug_command_only) { |
| 2183 isolate_->stack_guard()->ClearDebugCommand(); |
| 2184 |
| 2185 StackLimitCheck check(isolate_); |
| 2186 if (check.HasOverflowed()) return; |
| 2187 |
1981 HandleScope scope(isolate_); | 2188 HandleScope scope(isolate_); |
1982 DebugScope debug_scope(this); | 2189 DebugScope debug_scope(this); |
1983 if (debug_scope.failed()) return; | 2190 if (debug_scope.failed()) return; |
1984 | 2191 |
1985 // Notify the debug event listeners. | 2192 // Notify the debug event listeners. Indicate auto continue if the break was |
1986 OnDebugBreak(isolate_->factory()->undefined_value()); | 2193 // a debug command break. |
| 2194 OnDebugBreak(isolate_->factory()->undefined_value(), debug_command_only); |
1987 } | 2195 } |
1988 | 2196 |
1989 #ifdef DEBUG | 2197 #ifdef DEBUG |
1990 void Debug::PrintBreakLocation() { | 2198 void Debug::PrintBreakLocation() { |
1991 if (!FLAG_print_break_location) return; | 2199 if (!FLAG_print_break_location) return; |
1992 HandleScope scope(isolate_); | 2200 HandleScope scope(isolate_); |
1993 JavaScriptFrameIterator iterator(isolate_); | 2201 JavaScriptFrameIterator iterator(isolate_); |
1994 if (iterator.done()) return; | 2202 if (iterator.done()) return; |
1995 JavaScriptFrame* frame = iterator.frame(); | 2203 JavaScriptFrame* frame = iterator.frame(); |
1996 FrameSummary summary = FrameSummary::GetFirst(frame); | 2204 FrameSummary summary = FrameSummary::GetFirst(frame); |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2060 } | 2268 } |
2061 | 2269 |
2062 | 2270 |
2063 DebugScope::~DebugScope() { | 2271 DebugScope::~DebugScope() { |
2064 if (!failed_ && prev_ == NULL) { | 2272 if (!failed_ && prev_ == NULL) { |
2065 // Clear mirror cache when leaving the debugger. Skip this if there is a | 2273 // Clear mirror cache when leaving the debugger. Skip this if there is a |
2066 // pending exception as clearing the mirror cache calls back into | 2274 // pending exception as clearing the mirror cache calls back into |
2067 // JavaScript. This can happen if the v8::Debug::Call is used in which | 2275 // JavaScript. This can happen if the v8::Debug::Call is used in which |
2068 // case the exception should end up in the calling code. | 2276 // case the exception should end up in the calling code. |
2069 if (!isolate()->has_pending_exception()) debug_->ClearMirrorCache(); | 2277 if (!isolate()->has_pending_exception()) debug_->ClearMirrorCache(); |
| 2278 |
| 2279 // If there are commands in the queue when leaving the debugger request |
| 2280 // that these commands are processed. |
| 2281 if (debug_->has_commands()) isolate()->stack_guard()->RequestDebugCommand(); |
2070 } | 2282 } |
2071 | 2283 |
2072 // Leaving this debugger entry. | 2284 // Leaving this debugger entry. |
2073 base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_, | 2285 base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_, |
2074 reinterpret_cast<base::AtomicWord>(prev_)); | 2286 reinterpret_cast<base::AtomicWord>(prev_)); |
2075 | 2287 |
2076 // Restore to the previous break state. | 2288 // Restore to the previous break state. |
2077 debug_->thread_local_.break_frame_id_ = break_frame_id_; | 2289 debug_->thread_local_.break_frame_id_ = break_frame_id_; |
2078 debug_->thread_local_.break_id_ = break_id_; | 2290 debug_->thread_local_.break_id_ = break_id_; |
2079 debug_->thread_local_.return_value_ = return_value_; | 2291 debug_->thread_local_.return_value_ = return_value_; |
2080 | 2292 |
2081 debug_->UpdateState(); | 2293 debug_->UpdateState(); |
2082 } | 2294 } |
2083 | 2295 |
| 2296 MessageImpl MessageImpl::NewEvent(DebugEvent event, bool running, |
| 2297 Handle<JSObject> exec_state, |
| 2298 Handle<JSObject> event_data) { |
| 2299 MessageImpl message(true, event, running, exec_state, event_data, |
| 2300 Handle<String>(), NULL); |
| 2301 return message; |
| 2302 } |
| 2303 |
| 2304 MessageImpl MessageImpl::NewResponse(DebugEvent event, bool running, |
| 2305 Handle<JSObject> exec_state, |
| 2306 Handle<JSObject> event_data, |
| 2307 Handle<String> response_json, |
| 2308 v8::Debug::ClientData* client_data) { |
| 2309 MessageImpl message(false, event, running, exec_state, event_data, |
| 2310 response_json, client_data); |
| 2311 return message; |
| 2312 } |
| 2313 |
| 2314 MessageImpl::MessageImpl(bool is_event, DebugEvent event, bool running, |
| 2315 Handle<JSObject> exec_state, |
| 2316 Handle<JSObject> event_data, |
| 2317 Handle<String> response_json, |
| 2318 v8::Debug::ClientData* client_data) |
| 2319 : is_event_(is_event), |
| 2320 event_(event), |
| 2321 running_(running), |
| 2322 exec_state_(exec_state), |
| 2323 event_data_(event_data), |
| 2324 response_json_(response_json), |
| 2325 client_data_(client_data) {} |
| 2326 |
| 2327 bool MessageImpl::IsEvent() const { return is_event_; } |
| 2328 |
| 2329 bool MessageImpl::IsResponse() const { return !is_event_; } |
| 2330 |
| 2331 DebugEvent MessageImpl::GetEvent() const { return event_; } |
| 2332 |
| 2333 bool MessageImpl::WillStartRunning() const { return running_; } |
| 2334 |
| 2335 v8::Local<v8::Object> MessageImpl::GetExecutionState() const { |
| 2336 return v8::Utils::ToLocal(exec_state_); |
| 2337 } |
| 2338 |
| 2339 v8::Isolate* MessageImpl::GetIsolate() const { |
| 2340 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate()); |
| 2341 } |
| 2342 |
| 2343 v8::Local<v8::Object> MessageImpl::GetEventData() const { |
| 2344 return v8::Utils::ToLocal(event_data_); |
| 2345 } |
| 2346 |
| 2347 v8::Local<v8::String> MessageImpl::GetJSON() const { |
| 2348 Isolate* isolate = event_data_->GetIsolate(); |
| 2349 v8::EscapableHandleScope scope(reinterpret_cast<v8::Isolate*>(isolate)); |
| 2350 |
| 2351 if (IsEvent()) { |
| 2352 // Call toJSONProtocol on the debug event object. |
| 2353 Handle<Object> fun = |
| 2354 JSReceiver::GetProperty(isolate, event_data_, "toJSONProtocol") |
| 2355 .ToHandleChecked(); |
| 2356 if (!fun->IsJSFunction()) { |
| 2357 return v8::Local<v8::String>(); |
| 2358 } |
| 2359 |
| 2360 MaybeHandle<Object> maybe_json = |
| 2361 Execution::TryCall(isolate, fun, event_data_, 0, NULL); |
| 2362 Handle<Object> json; |
| 2363 if (!maybe_json.ToHandle(&json) || !json->IsString()) { |
| 2364 return v8::Local<v8::String>(); |
| 2365 } |
| 2366 return scope.Escape(v8::Utils::ToLocal(Handle<String>::cast(json))); |
| 2367 } else { |
| 2368 return v8::Utils::ToLocal(response_json_); |
| 2369 } |
| 2370 } |
| 2371 |
| 2372 namespace { |
| 2373 v8::Local<v8::Context> GetDebugEventContext(Isolate* isolate) { |
| 2374 Handle<Context> context = isolate->debug()->debugger_entry()->GetContext(); |
| 2375 // Isolate::context() may have been NULL when "script collected" event |
| 2376 // occured. |
| 2377 if (context.is_null()) return v8::Local<v8::Context>(); |
| 2378 Handle<Context> native_context(context->native_context()); |
| 2379 return v8::Utils::ToLocal(native_context); |
| 2380 } |
| 2381 } // anonymous namespace |
| 2382 |
| 2383 v8::Local<v8::Context> MessageImpl::GetEventContext() const { |
| 2384 Isolate* isolate = event_data_->GetIsolate(); |
| 2385 v8::Local<v8::Context> context = GetDebugEventContext(isolate); |
| 2386 // Isolate::context() may be NULL when "script collected" event occurs. |
| 2387 DCHECK(!context.IsEmpty()); |
| 2388 return context; |
| 2389 } |
| 2390 |
| 2391 v8::Debug::ClientData* MessageImpl::GetClientData() const { |
| 2392 return client_data_; |
| 2393 } |
2084 | 2394 |
2085 EventDetailsImpl::EventDetailsImpl(DebugEvent event, | 2395 EventDetailsImpl::EventDetailsImpl(DebugEvent event, |
2086 Handle<JSObject> exec_state, | 2396 Handle<JSObject> exec_state, |
2087 Handle<JSObject> event_data, | 2397 Handle<JSObject> event_data, |
2088 Handle<Object> callback_data, | 2398 Handle<Object> callback_data, |
2089 v8::Debug::ClientData* client_data) | 2399 v8::Debug::ClientData* client_data) |
2090 : event_(event), | 2400 : event_(event), |
2091 exec_state_(exec_state), | 2401 exec_state_(exec_state), |
2092 event_data_(event_data), | 2402 event_data_(event_data), |
2093 callback_data_(callback_data), | 2403 callback_data_(callback_data), |
2094 client_data_(client_data) {} | 2404 client_data_(client_data) {} |
2095 | 2405 |
2096 | 2406 |
2097 DebugEvent EventDetailsImpl::GetEvent() const { | 2407 DebugEvent EventDetailsImpl::GetEvent() const { |
2098 return event_; | 2408 return event_; |
2099 } | 2409 } |
2100 | 2410 |
2101 | 2411 |
2102 v8::Local<v8::Object> EventDetailsImpl::GetExecutionState() const { | 2412 v8::Local<v8::Object> EventDetailsImpl::GetExecutionState() const { |
2103 return v8::Utils::ToLocal(exec_state_); | 2413 return v8::Utils::ToLocal(exec_state_); |
2104 } | 2414 } |
2105 | 2415 |
2106 | 2416 |
2107 v8::Local<v8::Object> EventDetailsImpl::GetEventData() const { | 2417 v8::Local<v8::Object> EventDetailsImpl::GetEventData() const { |
2108 return v8::Utils::ToLocal(event_data_); | 2418 return v8::Utils::ToLocal(event_data_); |
2109 } | 2419 } |
2110 | 2420 |
2111 | 2421 |
2112 v8::Local<v8::Context> EventDetailsImpl::GetEventContext() const { | 2422 v8::Local<v8::Context> EventDetailsImpl::GetEventContext() const { |
2113 Handle<Context> context = | 2423 return GetDebugEventContext(exec_state_->GetIsolate()); |
2114 exec_state_->GetIsolate()->debug()->debugger_entry()->GetContext(); | |
2115 if (context.is_null()) return v8::Local<v8::Context>(); | |
2116 Handle<Context> native_context(context->native_context()); | |
2117 return v8::Utils::ToLocal(native_context); | |
2118 } | 2424 } |
2119 | 2425 |
2120 | 2426 |
2121 v8::Local<v8::Value> EventDetailsImpl::GetCallbackData() const { | 2427 v8::Local<v8::Value> EventDetailsImpl::GetCallbackData() const { |
2122 return v8::Utils::ToLocal(callback_data_); | 2428 return v8::Utils::ToLocal(callback_data_); |
2123 } | 2429 } |
2124 | 2430 |
2125 | 2431 |
2126 v8::Debug::ClientData* EventDetailsImpl::GetClientData() const { | 2432 v8::Debug::ClientData* EventDetailsImpl::GetClientData() const { |
2127 return client_data_; | 2433 return client_data_; |
2128 } | 2434 } |
2129 | 2435 |
2130 v8::Isolate* EventDetailsImpl::GetIsolate() const { | 2436 v8::Isolate* EventDetailsImpl::GetIsolate() const { |
2131 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate()); | 2437 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate()); |
2132 } | 2438 } |
2133 | 2439 |
| 2440 CommandMessage::CommandMessage() |
| 2441 : text_(Vector<uint16_t>::empty()), client_data_(NULL) {} |
| 2442 |
| 2443 CommandMessage::CommandMessage(const Vector<uint16_t>& text, |
| 2444 v8::Debug::ClientData* data) |
| 2445 : text_(text), client_data_(data) {} |
| 2446 |
| 2447 void CommandMessage::Dispose() { |
| 2448 text_.Dispose(); |
| 2449 delete client_data_; |
| 2450 client_data_ = NULL; |
| 2451 } |
| 2452 |
| 2453 CommandMessage CommandMessage::New(const Vector<uint16_t>& command, |
| 2454 v8::Debug::ClientData* data) { |
| 2455 return CommandMessage(command.Clone(), data); |
| 2456 } |
| 2457 |
| 2458 CommandMessageQueue::CommandMessageQueue(int size) |
| 2459 : start_(0), end_(0), size_(size) { |
| 2460 messages_ = NewArray<CommandMessage>(size); |
| 2461 } |
| 2462 |
| 2463 CommandMessageQueue::~CommandMessageQueue() { |
| 2464 while (!IsEmpty()) Get().Dispose(); |
| 2465 DeleteArray(messages_); |
| 2466 } |
| 2467 |
| 2468 CommandMessage CommandMessageQueue::Get() { |
| 2469 DCHECK(!IsEmpty()); |
| 2470 int result = start_; |
| 2471 start_ = (start_ + 1) % size_; |
| 2472 return messages_[result]; |
| 2473 } |
| 2474 |
| 2475 void CommandMessageQueue::Put(const CommandMessage& message) { |
| 2476 if ((end_ + 1) % size_ == start_) { |
| 2477 Expand(); |
| 2478 } |
| 2479 messages_[end_] = message; |
| 2480 end_ = (end_ + 1) % size_; |
| 2481 } |
| 2482 |
| 2483 void CommandMessageQueue::Expand() { |
| 2484 CommandMessageQueue new_queue(size_ * 2); |
| 2485 while (!IsEmpty()) { |
| 2486 new_queue.Put(Get()); |
| 2487 } |
| 2488 CommandMessage* array_to_free = messages_; |
| 2489 *this = new_queue; |
| 2490 new_queue.messages_ = array_to_free; |
| 2491 // Make the new_queue empty so that it doesn't call Dispose on any messages. |
| 2492 new_queue.start_ = new_queue.end_; |
| 2493 // Automatic destructor called on new_queue, freeing array_to_free. |
| 2494 } |
| 2495 |
| 2496 LockingCommandMessageQueue::LockingCommandMessageQueue(Logger* logger, int size) |
| 2497 : logger_(logger), queue_(size) {} |
| 2498 |
| 2499 bool LockingCommandMessageQueue::IsEmpty() const { |
| 2500 base::LockGuard<base::Mutex> lock_guard(&mutex_); |
| 2501 return queue_.IsEmpty(); |
| 2502 } |
| 2503 |
| 2504 CommandMessage LockingCommandMessageQueue::Get() { |
| 2505 base::LockGuard<base::Mutex> lock_guard(&mutex_); |
| 2506 CommandMessage result = queue_.Get(); |
| 2507 logger_->DebugEvent("Get", result.text()); |
| 2508 return result; |
| 2509 } |
| 2510 |
| 2511 void LockingCommandMessageQueue::Put(const CommandMessage& message) { |
| 2512 base::LockGuard<base::Mutex> lock_guard(&mutex_); |
| 2513 queue_.Put(message); |
| 2514 logger_->DebugEvent("Put", message.text()); |
| 2515 } |
| 2516 |
| 2517 void LockingCommandMessageQueue::Clear() { |
| 2518 base::LockGuard<base::Mutex> lock_guard(&mutex_); |
| 2519 queue_.Clear(); |
| 2520 } |
| 2521 |
2134 } // namespace internal | 2522 } // namespace internal |
2135 } // namespace v8 | 2523 } // namespace v8 |
OLD | NEW |