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