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 22 matching lines...) Expand all Loading... |
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>()), | 41 event_listener_(Handle<Object>()), |
42 event_listener_data_(Handle<Object>()), | 42 event_listener_data_(Handle<Object>()), |
43 message_handler_(NULL), | |
44 command_received_(0), | |
45 command_queue_(isolate->logger(), kQueueInitialSize), | |
46 is_active_(false), | 43 is_active_(false), |
47 hook_on_function_call_(false), | 44 hook_on_function_call_(false), |
48 is_suppressed_(false), | 45 is_suppressed_(false), |
49 live_edit_enabled_(true), // TODO(yangguo): set to false by default. | 46 live_edit_enabled_(true), // TODO(yangguo): set to false by default. |
50 break_disabled_(false), | 47 break_disabled_(false), |
51 break_points_active_(true), | 48 break_points_active_(true), |
52 in_debug_event_listener_(false), | 49 in_debug_event_listener_(false), |
53 break_on_exception_(false), | 50 break_on_exception_(false), |
54 break_on_uncaught_exception_(false), | 51 break_on_uncaught_exception_(false), |
55 side_effect_check_failed_(false), | 52 side_effect_check_failed_(false), |
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
525 | 522 |
526 // Find actual break points, if any, and trigger debug break event. | 523 // Find actual break points, if any, and trigger debug break event. |
527 MaybeHandle<FixedArray> break_points_hit = | 524 MaybeHandle<FixedArray> break_points_hit = |
528 CheckBreakPoints(debug_info, &location); | 525 CheckBreakPoints(debug_info, &location); |
529 if (!break_points_hit.is_null()) { | 526 if (!break_points_hit.is_null()) { |
530 // Clear all current stepping setup. | 527 // Clear all current stepping setup. |
531 ClearStepping(); | 528 ClearStepping(); |
532 // Notify the debug event listeners. | 529 // Notify the debug event listeners. |
533 Handle<JSArray> jsarr = isolate_->factory()->NewJSArrayWithElements( | 530 Handle<JSArray> jsarr = isolate_->factory()->NewJSArrayWithElements( |
534 break_points_hit.ToHandleChecked()); | 531 break_points_hit.ToHandleChecked()); |
535 OnDebugBreak(jsarr, false); | 532 OnDebugBreak(jsarr); |
536 return; | 533 return; |
537 } | 534 } |
538 | 535 |
539 // No break point. Check for stepping. | 536 // No break point. Check for stepping. |
540 StepAction step_action = last_step_action(); | 537 StepAction step_action = last_step_action(); |
541 Address current_fp = frame->UnpaddedFP(); | 538 Address current_fp = frame->UnpaddedFP(); |
542 Address target_fp = thread_local_.target_fp_; | 539 Address target_fp = thread_local_.target_fp_; |
543 Address last_fp = thread_local_.last_fp_; | 540 Address last_fp = thread_local_.last_fp_; |
544 | 541 |
545 bool step_break = false; | 542 bool step_break = false; |
(...skipping 21 matching lines...) Expand all Loading... |
567 case StepFrame: | 564 case StepFrame: |
568 step_break = current_fp != last_fp; | 565 step_break = current_fp != last_fp; |
569 break; | 566 break; |
570 } | 567 } |
571 | 568 |
572 // Clear all current stepping setup. | 569 // Clear all current stepping setup. |
573 ClearStepping(); | 570 ClearStepping(); |
574 | 571 |
575 if (step_break) { | 572 if (step_break) { |
576 // Notify the debug event listeners. | 573 // Notify the debug event listeners. |
577 OnDebugBreak(isolate_->factory()->undefined_value(), false); | 574 OnDebugBreak(isolate_->factory()->undefined_value()); |
578 } else { | 575 } else { |
579 // Re-prepare to continue. | 576 // Re-prepare to continue. |
580 PrepareStep(step_action); | 577 PrepareStep(step_action); |
581 } | 578 } |
582 } | 579 } |
583 | 580 |
584 | 581 |
585 // Find break point objects for this location, if any, and evaluate them. | 582 // Find break point objects for this location, if any, and evaluate them. |
586 // Return an array of break point objects that evaluated true, or an empty | 583 // Return an array of break point objects that evaluated true, or an empty |
587 // handle if none evaluated true. | 584 // handle if none evaluated true. |
(...skipping 1191 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1779 | 1776 |
1780 // Create the event data object. | 1777 // Create the event data object. |
1781 Handle<Object> event_data; | 1778 Handle<Object> event_data; |
1782 // Bail out and don't call debugger if exception. | 1779 // Bail out and don't call debugger if exception. |
1783 if (!MakeExceptionEvent( | 1780 if (!MakeExceptionEvent( |
1784 exception, uncaught, promise).ToHandle(&event_data)) { | 1781 exception, uncaught, promise).ToHandle(&event_data)) { |
1785 return; | 1782 return; |
1786 } | 1783 } |
1787 | 1784 |
1788 // Process debug event. | 1785 // Process debug event. |
1789 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data), false); | 1786 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data)); |
1790 // Return to continue execution from where the exception was thrown. | 1787 // Return to continue execution from where the exception was thrown. |
1791 } | 1788 } |
1792 | 1789 |
1793 void Debug::OnDebugBreak(Handle<Object> break_points_hit, bool auto_continue) { | 1790 void Debug::OnDebugBreak(Handle<Object> break_points_hit) { |
1794 // The caller provided for DebugScope. | 1791 // The caller provided for DebugScope. |
1795 AssertDebugContext(); | 1792 AssertDebugContext(); |
1796 // Bail out if there is no listener for this event | 1793 // Bail out if there is no listener for this event |
1797 if (ignore_events()) return; | 1794 if (ignore_events()) return; |
1798 | 1795 |
1799 #ifdef DEBUG | 1796 #ifdef DEBUG |
1800 PrintBreakLocation(); | 1797 PrintBreakLocation(); |
1801 #endif // DEBUG | 1798 #endif // DEBUG |
1802 | 1799 |
1803 if (debug_event_listener_) { | 1800 if (debug_event_listener_) { |
(...skipping 14 matching lines...) Expand all Loading... |
1818 if (!non_inspector_listener_exists()) return; | 1815 if (!non_inspector_listener_exists()) return; |
1819 } | 1816 } |
1820 | 1817 |
1821 HandleScope scope(isolate_); | 1818 HandleScope scope(isolate_); |
1822 // Create the event data object. | 1819 // Create the event data object. |
1823 Handle<Object> event_data; | 1820 Handle<Object> event_data; |
1824 // Bail out and don't call debugger if exception. | 1821 // Bail out and don't call debugger if exception. |
1825 if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return; | 1822 if (!MakeBreakEvent(break_points_hit).ToHandle(&event_data)) return; |
1826 | 1823 |
1827 // Process debug event. | 1824 // Process debug event. |
1828 ProcessDebugEvent(v8::Break, Handle<JSObject>::cast(event_data), | 1825 ProcessDebugEvent(v8::Break, Handle<JSObject>::cast(event_data)); |
1829 auto_continue); | |
1830 } | 1826 } |
1831 | 1827 |
1832 | 1828 |
1833 void Debug::OnCompileError(Handle<Script> script) { | 1829 void Debug::OnCompileError(Handle<Script> script) { |
1834 ProcessCompileEvent(v8::CompileError, script); | 1830 ProcessCompileEvent(v8::CompileError, script); |
1835 } | 1831 } |
1836 | 1832 |
1837 | 1833 |
1838 // Handle debugger actions when a new script is compiled. | 1834 // Handle debugger actions when a new script is compiled. |
1839 void Debug::OnAfterCompile(Handle<Script> script) { | 1835 void Debug::OnAfterCompile(Handle<Script> script) { |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1909 | 1905 |
1910 // Create the script collected state object. | 1906 // Create the script collected state object. |
1911 Handle<Object> event_data; | 1907 Handle<Object> event_data; |
1912 // Bail out and don't call debugger if exception. | 1908 // Bail out and don't call debugger if exception. |
1913 if (!MakeAsyncTaskEvent(handle(Smi::FromInt(type), isolate_), | 1909 if (!MakeAsyncTaskEvent(handle(Smi::FromInt(type), isolate_), |
1914 handle(Smi::FromInt(id), isolate_)) | 1910 handle(Smi::FromInt(id), isolate_)) |
1915 .ToHandle(&event_data)) | 1911 .ToHandle(&event_data)) |
1916 return; | 1912 return; |
1917 | 1913 |
1918 // Process debug event. | 1914 // Process debug event. |
1919 ProcessDebugEvent(v8::AsyncTaskEvent, Handle<JSObject>::cast(event_data), | 1915 ProcessDebugEvent(v8::AsyncTaskEvent, Handle<JSObject>::cast(event_data)); |
1920 true); | |
1921 } | 1916 } |
1922 | 1917 |
1923 void Debug::ProcessDebugEvent(v8::DebugEvent event, Handle<JSObject> event_data, | 1918 void Debug::ProcessDebugEvent(v8::DebugEvent event, |
1924 bool auto_continue) { | 1919 Handle<JSObject> event_data) { |
| 1920 // Notify registered debug event listener. This can be either a C or |
| 1921 // a JavaScript function. |
| 1922 if (event_listener_.is_null()) return; |
1925 HandleScope scope(isolate_); | 1923 HandleScope scope(isolate_); |
1926 | 1924 |
1927 // Create the execution state. | 1925 // Create the execution state. |
1928 Handle<Object> exec_state; | 1926 Handle<Object> exec_state; |
1929 // Bail out and don't call debugger if exception. | 1927 // Bail out and don't call debugger if exception. |
1930 if (!MakeExecutionState().ToHandle(&exec_state)) return; | 1928 if (!MakeExecutionState().ToHandle(&exec_state)) return; |
1931 | 1929 |
1932 // First notify the message handler if any. | |
1933 if (message_handler_ != NULL) { | |
1934 NotifyMessageHandler(event, Handle<JSObject>::cast(exec_state), event_data, | |
1935 auto_continue); | |
1936 } | |
1937 // Notify registered debug event listener. This can be either a C or | |
1938 // a JavaScript function. Don't call event listener for v8::Break | |
1939 // here, if it's only a debug command -- they will be processed later. | |
1940 if ((event != v8::Break || !auto_continue) && !event_listener_.is_null()) { | |
1941 CallEventCallback(event, exec_state, event_data, NULL); | |
1942 } | |
1943 } | |
1944 | |
1945 | |
1946 void Debug::CallEventCallback(v8::DebugEvent event, | |
1947 Handle<Object> exec_state, | |
1948 Handle<Object> event_data, | |
1949 v8::Debug::ClientData* client_data) { | |
1950 // Prevent other interrupts from triggering, for example API callbacks, | 1930 // Prevent other interrupts from triggering, for example API callbacks, |
1951 // while dispatching event listners. | 1931 // while dispatching event listners. |
1952 PostponeInterruptsScope postpone(isolate_); | 1932 PostponeInterruptsScope postpone(isolate_); |
1953 bool previous = in_debug_event_listener_; | 1933 bool previous = in_debug_event_listener_; |
1954 in_debug_event_listener_ = true; | 1934 in_debug_event_listener_ = true; |
1955 if (event_listener_->IsForeign()) { | 1935 if (event_listener_->IsForeign()) { |
1956 // Invoke the C debug event listener. | 1936 // Invoke the C debug event listener. |
1957 v8::Debug::EventCallback callback = FUNCTION_CAST<v8::Debug::EventCallback>( | 1937 v8::Debug::EventCallback callback = FUNCTION_CAST<v8::Debug::EventCallback>( |
1958 Handle<Foreign>::cast(event_listener_)->foreign_address()); | 1938 Handle<Foreign>::cast(event_listener_)->foreign_address()); |
1959 EventDetailsImpl event_details(event, | 1939 EventDetailsImpl event_details(event, Handle<JSObject>::cast(exec_state), |
1960 Handle<JSObject>::cast(exec_state), | |
1961 Handle<JSObject>::cast(event_data), | 1940 Handle<JSObject>::cast(event_data), |
1962 event_listener_data_, | 1941 event_listener_data_); |
1963 client_data); | |
1964 callback(event_details); | 1942 callback(event_details); |
1965 CHECK(!isolate_->has_scheduled_exception()); | 1943 CHECK(!isolate_->has_scheduled_exception()); |
1966 } else { | 1944 } else { |
1967 // Invoke the JavaScript debug event listener. | 1945 // Invoke the JavaScript debug event listener. |
1968 DCHECK(event_listener_->IsJSFunction()); | 1946 DCHECK(event_listener_->IsJSFunction()); |
1969 Handle<Object> argv[] = { Handle<Object>(Smi::FromInt(event), isolate_), | 1947 Handle<Object> argv[] = { Handle<Object>(Smi::FromInt(event), isolate_), |
1970 exec_state, | 1948 exec_state, |
1971 event_data, | 1949 event_data, |
1972 event_listener_data_ }; | 1950 event_listener_data_ }; |
1973 Handle<JSReceiver> global = isolate_->global_proxy(); | 1951 Handle<JSReceiver> global = isolate_->global_proxy(); |
1974 MaybeHandle<Object> result = | 1952 MaybeHandle<Object> result = |
1975 Execution::Call(isolate_, Handle<JSFunction>::cast(event_listener_), | 1953 Execution::Call(isolate_, Handle<JSFunction>::cast(event_listener_), |
1976 global, arraysize(argv), argv); | 1954 global, arraysize(argv), argv); |
1977 CHECK(!result.is_null()); // Listeners must not throw. | 1955 CHECK(!result.is_null()); // Listeners must not throw. |
1978 } | 1956 } |
1979 in_debug_event_listener_ = previous; | 1957 in_debug_event_listener_ = previous; |
1980 } | 1958 } |
1981 | 1959 |
1982 void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) { | 1960 void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) { |
1983 if (ignore_events()) return; | 1961 if (ignore_events()) return; |
1984 if (script->type() != i::Script::TYPE_NORMAL && | 1962 if (script->type() != i::Script::TYPE_NORMAL && |
1985 script->type() != i::Script::TYPE_WASM) { | 1963 script->type() != i::Script::TYPE_WASM) { |
1986 return; | 1964 return; |
1987 } | 1965 } |
1988 SuppressDebug while_processing(this); | 1966 SuppressDebug while_processing(this); |
1989 bool in_nested_debug_scope = in_debug_scope(); | |
1990 DebugScope debug_scope(this); | 1967 DebugScope debug_scope(this); |
1991 if (debug_scope.failed()) return; | 1968 if (debug_scope.failed()) return; |
1992 | 1969 |
1993 if (debug_event_listener_) { | 1970 if (debug_event_listener_) { |
1994 debug_event_listener_->ScriptCompiled(ToApiHandle<debug::Script>(script), | 1971 debug_event_listener_->ScriptCompiled(ToApiHandle<debug::Script>(script), |
1995 event != v8::AfterCompile); | 1972 event != v8::AfterCompile); |
1996 if (!non_inspector_listener_exists()) return; | 1973 if (!non_inspector_listener_exists()) return; |
1997 } | 1974 } |
1998 | 1975 |
1999 HandleScope scope(isolate_); | 1976 HandleScope scope(isolate_); |
2000 // Create the compile state object. | 1977 // Create the compile state object. |
2001 Handle<Object> event_data; | 1978 Handle<Object> event_data; |
2002 // Bail out and don't call debugger if exception. | 1979 // Bail out and don't call debugger if exception. |
2003 if (!MakeCompileEvent(script, event).ToHandle(&event_data)) return; | 1980 if (!MakeCompileEvent(script, event).ToHandle(&event_data)) return; |
2004 | 1981 |
2005 // Don't call NotifyMessageHandler if already in debug scope to avoid running | 1982 // Process debug event. |
2006 // nested command loop. | 1983 ProcessDebugEvent(event, Handle<JSObject>::cast(event_data)); |
2007 if (in_nested_debug_scope) { | |
2008 if (event_listener_.is_null()) return; | |
2009 // Create the execution state. | |
2010 Handle<Object> exec_state; | |
2011 // Bail out and don't call debugger if exception. | |
2012 if (!MakeExecutionState().ToHandle(&exec_state)) return; | |
2013 | |
2014 CallEventCallback(event, exec_state, event_data, NULL); | |
2015 } else { | |
2016 // Process debug event. | |
2017 ProcessDebugEvent(event, Handle<JSObject>::cast(event_data), true); | |
2018 } | |
2019 } | 1984 } |
2020 | 1985 |
2021 | 1986 |
2022 Handle<Context> Debug::GetDebugContext() { | 1987 Handle<Context> Debug::GetDebugContext() { |
2023 if (!is_loaded()) return Handle<Context>(); | 1988 if (!is_loaded()) return Handle<Context>(); |
2024 DebugScope debug_scope(this); | 1989 DebugScope debug_scope(this); |
2025 if (debug_scope.failed()) return Handle<Context>(); | 1990 if (debug_scope.failed()) return Handle<Context>(); |
2026 // The global handle may be destroyed soon after. Return it reboxed. | 1991 // The global handle may be destroyed soon after. Return it reboxed. |
2027 return handle(*debug_context(), isolate_); | 1992 return handle(*debug_context(), isolate_); |
2028 } | 1993 } |
2029 | 1994 |
2030 void Debug::NotifyMessageHandler(v8::DebugEvent event, | |
2031 Handle<JSObject> exec_state, | |
2032 Handle<JSObject> event_data, | |
2033 bool auto_continue) { | |
2034 // Prevent other interrupts from triggering, for example API callbacks, | |
2035 // while dispatching message handler callbacks. | |
2036 PostponeInterruptsScope no_interrupts(isolate_); | |
2037 DCHECK(is_active_); | |
2038 HandleScope scope(isolate_); | |
2039 // Process the individual events. | |
2040 bool sendEventMessage = false; | |
2041 switch (event) { | |
2042 case v8::Break: | |
2043 sendEventMessage = !auto_continue; | |
2044 break; | |
2045 case v8::CompileError: | |
2046 case v8::AsyncTaskEvent: | |
2047 break; | |
2048 case v8::Exception: | |
2049 case v8::AfterCompile: | |
2050 sendEventMessage = true; | |
2051 break; | |
2052 } | |
2053 | |
2054 // The debug command interrupt flag might have been set when the command was | |
2055 // added. It should be enough to clear the flag only once while we are in the | |
2056 // debugger. | |
2057 DCHECK(in_debug_scope()); | |
2058 isolate_->stack_guard()->ClearDebugCommand(); | |
2059 | |
2060 // Notify the debugger that a debug event has occurred unless auto continue is | |
2061 // active in which case no event is send. | |
2062 if (sendEventMessage) { | |
2063 MessageImpl message = MessageImpl::NewEvent( | |
2064 event, auto_continue, Handle<JSObject>::cast(exec_state), | |
2065 Handle<JSObject>::cast(event_data)); | |
2066 InvokeMessageHandler(message); | |
2067 } | |
2068 | |
2069 // If auto continue don't make the event cause a break, but process messages | |
2070 // in the queue if any. For script collected events don't even process | |
2071 // messages in the queue as the execution state might not be what is expected | |
2072 // by the client. | |
2073 if (auto_continue && !has_commands()) return; | |
2074 | |
2075 // DebugCommandProcessor goes here. | |
2076 bool running = auto_continue; | |
2077 | |
2078 Handle<Object> cmd_processor_ctor = | |
2079 JSReceiver::GetProperty(isolate_, exec_state, "debugCommandProcessor") | |
2080 .ToHandleChecked(); | |
2081 Handle<Object> ctor_args[] = {isolate_->factory()->ToBoolean(running)}; | |
2082 Handle<JSReceiver> cmd_processor = Handle<JSReceiver>::cast( | |
2083 Execution::Call(isolate_, cmd_processor_ctor, exec_state, 1, ctor_args) | |
2084 .ToHandleChecked()); | |
2085 Handle<JSFunction> process_debug_request = Handle<JSFunction>::cast( | |
2086 JSReceiver::GetProperty(isolate_, cmd_processor, "processDebugRequest") | |
2087 .ToHandleChecked()); | |
2088 Handle<Object> is_running = | |
2089 JSReceiver::GetProperty(isolate_, cmd_processor, "isRunning") | |
2090 .ToHandleChecked(); | |
2091 | |
2092 // Process requests from the debugger. | |
2093 do { | |
2094 // Wait for new command in the queue. | |
2095 command_received_.Wait(); | |
2096 | |
2097 // Get the command from the queue. | |
2098 CommandMessage command = command_queue_.Get(); | |
2099 isolate_->logger()->DebugTag( | |
2100 "Got request from command queue, in interactive loop."); | |
2101 if (!is_active()) { | |
2102 // Delete command text and user data. | |
2103 command.Dispose(); | |
2104 return; | |
2105 } | |
2106 | |
2107 Vector<const uc16> command_text( | |
2108 const_cast<const uc16*>(command.text().start()), | |
2109 command.text().length()); | |
2110 Handle<String> request_text = isolate_->factory() | |
2111 ->NewStringFromTwoByte(command_text) | |
2112 .ToHandleChecked(); | |
2113 Handle<Object> request_args[] = {request_text}; | |
2114 Handle<Object> answer_value; | |
2115 Handle<String> answer; | |
2116 MaybeHandle<Object> maybe_exception; | |
2117 MaybeHandle<Object> maybe_result = Execution::TryCall( | |
2118 isolate_, process_debug_request, cmd_processor, 1, request_args, | |
2119 Execution::MessageHandling::kReport, &maybe_exception); | |
2120 | |
2121 if (maybe_result.ToHandle(&answer_value)) { | |
2122 if (answer_value->IsUndefined(isolate_)) { | |
2123 answer = isolate_->factory()->empty_string(); | |
2124 } else { | |
2125 answer = Handle<String>::cast(answer_value); | |
2126 } | |
2127 | |
2128 // Log the JSON request/response. | |
2129 if (FLAG_trace_debug_json) { | |
2130 PrintF("%s\n", request_text->ToCString().get()); | |
2131 PrintF("%s\n", answer->ToCString().get()); | |
2132 } | |
2133 | |
2134 Handle<Object> is_running_args[] = {answer}; | |
2135 maybe_result = Execution::Call(isolate_, is_running, cmd_processor, 1, | |
2136 is_running_args); | |
2137 Handle<Object> result; | |
2138 if (!maybe_result.ToHandle(&result)) break; | |
2139 running = result->IsTrue(isolate_); | |
2140 } else { | |
2141 Handle<Object> exception; | |
2142 if (!maybe_exception.ToHandle(&exception)) break; | |
2143 Handle<Object> result; | |
2144 if (!Object::ToString(isolate_, exception).ToHandle(&result)) break; | |
2145 answer = Handle<String>::cast(result); | |
2146 } | |
2147 | |
2148 // Return the result. | |
2149 MessageImpl message = MessageImpl::NewResponse( | |
2150 event, running, exec_state, event_data, answer, command.client_data()); | |
2151 InvokeMessageHandler(message); | |
2152 command.Dispose(); | |
2153 | |
2154 // Return from debug event processing if either the VM is put into the | |
2155 // running state (through a continue command) or auto continue is active | |
2156 // and there are no more commands queued. | |
2157 } while (!running || has_commands()); | |
2158 command_queue_.Clear(); | |
2159 } | |
2160 | 1995 |
2161 void Debug::SetEventListener(Handle<Object> callback, | 1996 void Debug::SetEventListener(Handle<Object> callback, |
2162 Handle<Object> data) { | 1997 Handle<Object> data) { |
2163 GlobalHandles* global_handles = isolate_->global_handles(); | 1998 GlobalHandles* global_handles = isolate_->global_handles(); |
2164 | 1999 |
2165 // Remove existing entry. | 2000 // Remove existing entry. |
2166 GlobalHandles::Destroy(event_listener_.location()); | 2001 GlobalHandles::Destroy(event_listener_.location()); |
2167 event_listener_ = Handle<Object>(); | 2002 event_listener_ = Handle<Object>(); |
2168 GlobalHandles::Destroy(event_listener_data_.location()); | 2003 GlobalHandles::Destroy(event_listener_data_.location()); |
2169 event_listener_data_ = Handle<Object>(); | 2004 event_listener_data_ = Handle<Object>(); |
2170 | 2005 |
2171 // Set new entry. | 2006 // Set new entry. |
2172 if (!callback->IsNullOrUndefined(isolate_)) { | 2007 if (!callback->IsNullOrUndefined(isolate_)) { |
2173 event_listener_ = global_handles->Create(*callback); | 2008 event_listener_ = global_handles->Create(*callback); |
2174 if (data.is_null()) data = isolate_->factory()->undefined_value(); | 2009 if (data.is_null()) data = isolate_->factory()->undefined_value(); |
2175 event_listener_data_ = global_handles->Create(*data); | 2010 event_listener_data_ = global_handles->Create(*data); |
2176 } | 2011 } |
2177 | 2012 |
2178 UpdateState(); | 2013 UpdateState(); |
2179 } | 2014 } |
2180 | 2015 |
2181 void Debug::SetMessageHandler(v8::Debug::MessageHandler handler) { | |
2182 message_handler_ = handler; | |
2183 UpdateState(); | |
2184 if (handler == NULL && in_debug_scope()) { | |
2185 // Send an empty command to the debugger if in a break to make JavaScript | |
2186 // run again if the debugger is closed. | |
2187 EnqueueCommandMessage(Vector<const uint16_t>::empty()); | |
2188 } | |
2189 } | |
2190 | 2016 |
2191 void Debug::SetDebugEventListener(debug::DebugEventListener* listener) { | 2017 void Debug::SetDebugEventListener(debug::DebugEventListener* listener) { |
2192 debug_event_listener_ = listener; | 2018 debug_event_listener_ = listener; |
2193 UpdateState(); | 2019 UpdateState(); |
2194 } | 2020 } |
2195 | 2021 |
2196 void Debug::UpdateState() { | 2022 void Debug::UpdateState() { |
2197 bool is_active = message_handler_ != nullptr || !event_listener_.is_null() || | 2023 bool is_active = |
2198 debug_event_listener_ != nullptr; | 2024 !event_listener_.is_null() || debug_event_listener_ != nullptr; |
2199 if (is_active || in_debug_scope()) { | 2025 if (is_active || in_debug_scope()) { |
2200 // Note that the debug context could have already been loaded to | 2026 // Note that the debug context could have already been loaded to |
2201 // bootstrap test cases. | 2027 // bootstrap test cases. |
2202 isolate_->compilation_cache()->Disable(); | 2028 isolate_->compilation_cache()->Disable(); |
2203 is_active = Load(); | 2029 is_active = Load(); |
2204 } else if (is_loaded()) { | 2030 } else if (is_loaded()) { |
2205 isolate_->compilation_cache()->Enable(); | 2031 isolate_->compilation_cache()->Enable(); |
2206 Unload(); | 2032 Unload(); |
2207 } | 2033 } |
2208 is_active_ = is_active; | 2034 is_active_ = is_active; |
2209 } | 2035 } |
2210 | 2036 |
2211 void Debug::UpdateHookOnFunctionCall() { | 2037 void Debug::UpdateHookOnFunctionCall() { |
2212 STATIC_ASSERT(StepFrame > StepIn); | 2038 STATIC_ASSERT(StepFrame > StepIn); |
2213 STATIC_ASSERT(LastStepAction == StepFrame); | 2039 STATIC_ASSERT(LastStepAction == StepFrame); |
2214 hook_on_function_call_ = thread_local_.last_step_action_ >= StepIn || | 2040 hook_on_function_call_ = thread_local_.last_step_action_ >= StepIn || |
2215 isolate_->needs_side_effect_check(); | 2041 isolate_->needs_side_effect_check(); |
2216 } | 2042 } |
2217 | 2043 |
2218 // Calls the registered debug message handler. This callback is part of the | |
2219 // public API. | |
2220 void Debug::InvokeMessageHandler(MessageImpl message) { | |
2221 if (message_handler_ != NULL) message_handler_(message); | |
2222 } | |
2223 | |
2224 // Puts a command coming from the public API on the queue. Creates | |
2225 // a copy of the command string managed by the debugger. Up to this | |
2226 // point, the command data was managed by the API client. Called | |
2227 // by the API client thread. | |
2228 void Debug::EnqueueCommandMessage(Vector<const uint16_t> command, | |
2229 v8::Debug::ClientData* client_data) { | |
2230 // Need to cast away const. | |
2231 CommandMessage message = CommandMessage::New( | |
2232 Vector<uint16_t>(const_cast<uint16_t*>(command.start()), | |
2233 command.length()), | |
2234 client_data); | |
2235 isolate_->logger()->DebugTag("Put command on command_queue."); | |
2236 command_queue_.Put(message); | |
2237 command_received_.Signal(); | |
2238 | |
2239 // Set the debug command break flag to have the command processed. | |
2240 if (!in_debug_scope()) isolate_->stack_guard()->RequestDebugCommand(); | |
2241 } | |
2242 | |
2243 MaybeHandle<Object> Debug::Call(Handle<Object> fun, Handle<Object> data) { | 2044 MaybeHandle<Object> Debug::Call(Handle<Object> fun, Handle<Object> data) { |
2244 DebugScope debug_scope(this); | 2045 DebugScope debug_scope(this); |
2245 if (debug_scope.failed()) return isolate_->factory()->undefined_value(); | 2046 if (debug_scope.failed()) return isolate_->factory()->undefined_value(); |
2246 | 2047 |
2247 // Create the execution state. | 2048 // Create the execution state. |
2248 Handle<Object> exec_state; | 2049 Handle<Object> exec_state; |
2249 if (!MakeExecutionState().ToHandle(&exec_state)) { | 2050 if (!MakeExecutionState().ToHandle(&exec_state)) { |
2250 return isolate_->factory()->undefined_value(); | 2051 return isolate_->factory()->undefined_value(); |
2251 } | 2052 } |
2252 | 2053 |
(...skipping 26 matching lines...) Expand all Loading... |
2279 if (!JSFunction::cast(fun)->shared()->IsSubjectToDebugging()) return; | 2080 if (!JSFunction::cast(fun)->shared()->IsSubjectToDebugging()) return; |
2280 JSGlobalObject* global = | 2081 JSGlobalObject* global = |
2281 JSFunction::cast(fun)->context()->global_object(); | 2082 JSFunction::cast(fun)->context()->global_object(); |
2282 // Don't stop in debugger functions. | 2083 // Don't stop in debugger functions. |
2283 if (IsDebugGlobal(global)) return; | 2084 if (IsDebugGlobal(global)) return; |
2284 // Don't stop if the break location is muted. | 2085 // Don't stop if the break location is muted. |
2285 if (IsMutedAtCurrentLocation(it.frame())) return; | 2086 if (IsMutedAtCurrentLocation(it.frame())) return; |
2286 } | 2087 } |
2287 } | 2088 } |
2288 | 2089 |
2289 // Collect the break state before clearing the flags. | |
2290 bool debug_command_only = isolate_->stack_guard()->CheckDebugCommand() && | |
2291 !isolate_->stack_guard()->CheckDebugBreak(); | |
2292 | |
2293 isolate_->stack_guard()->ClearDebugBreak(); | 2090 isolate_->stack_guard()->ClearDebugBreak(); |
2294 | 2091 |
2295 // Clear stepping to avoid duplicate breaks. | 2092 // Clear stepping to avoid duplicate breaks. |
2296 ClearStepping(); | 2093 ClearStepping(); |
2297 | 2094 |
2298 ProcessDebugMessages(debug_command_only); | |
2299 } | |
2300 | |
2301 void Debug::ProcessDebugMessages(bool debug_command_only) { | |
2302 isolate_->stack_guard()->ClearDebugCommand(); | |
2303 | |
2304 StackLimitCheck check(isolate_); | |
2305 if (check.HasOverflowed()) return; | |
2306 | |
2307 HandleScope scope(isolate_); | 2095 HandleScope scope(isolate_); |
2308 DebugScope debug_scope(this); | 2096 DebugScope debug_scope(this); |
2309 if (debug_scope.failed()) return; | 2097 if (debug_scope.failed()) return; |
2310 | 2098 |
2311 // Notify the debug event listeners. Indicate auto continue if the break was | 2099 OnDebugBreak(isolate_->factory()->undefined_value()); |
2312 // a debug command break. | |
2313 OnDebugBreak(isolate_->factory()->undefined_value(), debug_command_only); | |
2314 } | 2100 } |
2315 | 2101 |
2316 #ifdef DEBUG | 2102 #ifdef DEBUG |
2317 void Debug::PrintBreakLocation() { | 2103 void Debug::PrintBreakLocation() { |
2318 if (!FLAG_print_break_location) return; | 2104 if (!FLAG_print_break_location) return; |
2319 HandleScope scope(isolate_); | 2105 HandleScope scope(isolate_); |
2320 StackTraceFrameIterator iterator(isolate_); | 2106 StackTraceFrameIterator iterator(isolate_); |
2321 if (iterator.done()) return; | 2107 if (iterator.done()) return; |
2322 StandardFrame* frame = iterator.frame(); | 2108 StandardFrame* frame = iterator.frame(); |
2323 FrameSummary summary = FrameSummary::GetTop(frame); | 2109 FrameSummary summary = FrameSummary::GetTop(frame); |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2384 } | 2170 } |
2385 | 2171 |
2386 | 2172 |
2387 DebugScope::~DebugScope() { | 2173 DebugScope::~DebugScope() { |
2388 if (!failed_ && prev_ == NULL) { | 2174 if (!failed_ && prev_ == NULL) { |
2389 // Clear mirror cache when leaving the debugger. Skip this if there is a | 2175 // Clear mirror cache when leaving the debugger. Skip this if there is a |
2390 // pending exception as clearing the mirror cache calls back into | 2176 // pending exception as clearing the mirror cache calls back into |
2391 // JavaScript. This can happen if the v8::Debug::Call is used in which | 2177 // JavaScript. This can happen if the v8::Debug::Call is used in which |
2392 // case the exception should end up in the calling code. | 2178 // case the exception should end up in the calling code. |
2393 if (!isolate()->has_pending_exception()) debug_->ClearMirrorCache(); | 2179 if (!isolate()->has_pending_exception()) debug_->ClearMirrorCache(); |
2394 | |
2395 // If there are commands in the queue when leaving the debugger request | |
2396 // that these commands are processed. | |
2397 if (debug_->has_commands()) isolate()->stack_guard()->RequestDebugCommand(); | |
2398 } | 2180 } |
2399 | 2181 |
2400 // Leaving this debugger entry. | 2182 // Leaving this debugger entry. |
2401 base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_, | 2183 base::NoBarrier_Store(&debug_->thread_local_.current_debug_scope_, |
2402 reinterpret_cast<base::AtomicWord>(prev_)); | 2184 reinterpret_cast<base::AtomicWord>(prev_)); |
2403 | 2185 |
2404 // Restore to the previous break state. | 2186 // Restore to the previous break state. |
2405 debug_->thread_local_.break_frame_id_ = break_frame_id_; | 2187 debug_->thread_local_.break_frame_id_ = break_frame_id_; |
2406 debug_->thread_local_.break_id_ = break_id_; | 2188 debug_->thread_local_.break_id_ = break_id_; |
2407 debug_->thread_local_.return_value_ = return_value_; | 2189 debug_->thread_local_.return_value_ = return_value_; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2446 // Convert the termination exception into a regular exception. | 2228 // Convert the termination exception into a regular exception. |
2447 isolate_->CancelTerminateExecution(); | 2229 isolate_->CancelTerminateExecution(); |
2448 isolate_->Throw(*isolate_->factory()->NewEvalError( | 2230 isolate_->Throw(*isolate_->factory()->NewEvalError( |
2449 MessageTemplate::kNoSideEffectDebugEvaluate)); | 2231 MessageTemplate::kNoSideEffectDebugEvaluate)); |
2450 } | 2232 } |
2451 isolate_->set_needs_side_effect_check(old_needs_side_effect_check_); | 2233 isolate_->set_needs_side_effect_check(old_needs_side_effect_check_); |
2452 isolate_->debug()->UpdateHookOnFunctionCall(); | 2234 isolate_->debug()->UpdateHookOnFunctionCall(); |
2453 isolate_->debug()->side_effect_check_failed_ = false; | 2235 isolate_->debug()->side_effect_check_failed_ = false; |
2454 } | 2236 } |
2455 | 2237 |
2456 MessageImpl MessageImpl::NewEvent(DebugEvent event, bool running, | |
2457 Handle<JSObject> exec_state, | |
2458 Handle<JSObject> event_data) { | |
2459 MessageImpl message(true, event, running, exec_state, event_data, | |
2460 Handle<String>(), NULL); | |
2461 return message; | |
2462 } | |
2463 | |
2464 MessageImpl MessageImpl::NewResponse(DebugEvent event, bool running, | |
2465 Handle<JSObject> exec_state, | |
2466 Handle<JSObject> event_data, | |
2467 Handle<String> response_json, | |
2468 v8::Debug::ClientData* client_data) { | |
2469 MessageImpl message(false, event, running, exec_state, event_data, | |
2470 response_json, client_data); | |
2471 return message; | |
2472 } | |
2473 | |
2474 MessageImpl::MessageImpl(bool is_event, DebugEvent event, bool running, | |
2475 Handle<JSObject> exec_state, | |
2476 Handle<JSObject> event_data, | |
2477 Handle<String> response_json, | |
2478 v8::Debug::ClientData* client_data) | |
2479 : is_event_(is_event), | |
2480 event_(event), | |
2481 running_(running), | |
2482 exec_state_(exec_state), | |
2483 event_data_(event_data), | |
2484 response_json_(response_json), | |
2485 client_data_(client_data) {} | |
2486 | |
2487 bool MessageImpl::IsEvent() const { return is_event_; } | |
2488 | |
2489 bool MessageImpl::IsResponse() const { return !is_event_; } | |
2490 | |
2491 DebugEvent MessageImpl::GetEvent() const { return event_; } | |
2492 | |
2493 bool MessageImpl::WillStartRunning() const { return running_; } | |
2494 | |
2495 v8::Local<v8::Object> MessageImpl::GetExecutionState() const { | |
2496 return v8::Utils::ToLocal(exec_state_); | |
2497 } | |
2498 | |
2499 v8::Isolate* MessageImpl::GetIsolate() const { | |
2500 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate()); | |
2501 } | |
2502 | |
2503 v8::Local<v8::Object> MessageImpl::GetEventData() const { | |
2504 return v8::Utils::ToLocal(event_data_); | |
2505 } | |
2506 | |
2507 v8::Local<v8::String> MessageImpl::GetJSON() const { | |
2508 Isolate* isolate = event_data_->GetIsolate(); | |
2509 v8::EscapableHandleScope scope(reinterpret_cast<v8::Isolate*>(isolate)); | |
2510 | |
2511 if (IsEvent()) { | |
2512 // Call toJSONProtocol on the debug event object. | |
2513 Handle<Object> fun = | |
2514 JSReceiver::GetProperty(isolate, event_data_, "toJSONProtocol") | |
2515 .ToHandleChecked(); | |
2516 if (!fun->IsJSFunction()) { | |
2517 return v8::Local<v8::String>(); | |
2518 } | |
2519 | |
2520 MaybeHandle<Object> maybe_exception; | |
2521 MaybeHandle<Object> maybe_json = Execution::TryCall( | |
2522 isolate, fun, event_data_, 0, nullptr, | |
2523 Execution::MessageHandling::kReport, &maybe_exception); | |
2524 Handle<Object> json; | |
2525 if (!maybe_json.ToHandle(&json) || !json->IsString()) { | |
2526 return v8::Local<v8::String>(); | |
2527 } | |
2528 return scope.Escape(v8::Utils::ToLocal(Handle<String>::cast(json))); | |
2529 } else { | |
2530 return v8::Utils::ToLocal(response_json_); | |
2531 } | |
2532 } | |
2533 | |
2534 v8::Local<v8::Context> MessageImpl::GetEventContext() const { | |
2535 Isolate* isolate = event_data_->GetIsolate(); | |
2536 v8::Local<v8::Context> context = GetDebugEventContext(isolate); | |
2537 // Isolate::context() may be NULL when "script collected" event occurs. | |
2538 DCHECK(!context.IsEmpty()); | |
2539 return context; | |
2540 } | |
2541 | |
2542 v8::Debug::ClientData* MessageImpl::GetClientData() const { | |
2543 return client_data_; | |
2544 } | |
2545 | |
2546 EventDetailsImpl::EventDetailsImpl(DebugEvent event, | 2238 EventDetailsImpl::EventDetailsImpl(DebugEvent event, |
2547 Handle<JSObject> exec_state, | 2239 Handle<JSObject> exec_state, |
2548 Handle<JSObject> event_data, | 2240 Handle<JSObject> event_data, |
2549 Handle<Object> callback_data, | 2241 Handle<Object> callback_data) |
2550 v8::Debug::ClientData* client_data) | |
2551 : event_(event), | 2242 : event_(event), |
2552 exec_state_(exec_state), | 2243 exec_state_(exec_state), |
2553 event_data_(event_data), | 2244 event_data_(event_data), |
2554 callback_data_(callback_data), | 2245 callback_data_(callback_data) {} |
2555 client_data_(client_data) {} | |
2556 | |
2557 | 2246 |
2558 DebugEvent EventDetailsImpl::GetEvent() const { | 2247 DebugEvent EventDetailsImpl::GetEvent() const { |
2559 return event_; | 2248 return event_; |
2560 } | 2249 } |
2561 | 2250 |
2562 | 2251 |
2563 v8::Local<v8::Object> EventDetailsImpl::GetExecutionState() const { | 2252 v8::Local<v8::Object> EventDetailsImpl::GetExecutionState() const { |
2564 return v8::Utils::ToLocal(exec_state_); | 2253 return v8::Utils::ToLocal(exec_state_); |
2565 } | 2254 } |
2566 | 2255 |
2567 | 2256 |
2568 v8::Local<v8::Object> EventDetailsImpl::GetEventData() const { | 2257 v8::Local<v8::Object> EventDetailsImpl::GetEventData() const { |
2569 return v8::Utils::ToLocal(event_data_); | 2258 return v8::Utils::ToLocal(event_data_); |
2570 } | 2259 } |
2571 | 2260 |
2572 | 2261 |
2573 v8::Local<v8::Context> EventDetailsImpl::GetEventContext() const { | 2262 v8::Local<v8::Context> EventDetailsImpl::GetEventContext() const { |
2574 return GetDebugEventContext(exec_state_->GetIsolate()); | 2263 return GetDebugEventContext(exec_state_->GetIsolate()); |
2575 } | 2264 } |
2576 | 2265 |
2577 | 2266 |
2578 v8::Local<v8::Value> EventDetailsImpl::GetCallbackData() const { | 2267 v8::Local<v8::Value> EventDetailsImpl::GetCallbackData() const { |
2579 return v8::Utils::ToLocal(callback_data_); | 2268 return v8::Utils::ToLocal(callback_data_); |
2580 } | 2269 } |
2581 | 2270 |
2582 | 2271 |
2583 v8::Debug::ClientData* EventDetailsImpl::GetClientData() const { | |
2584 return client_data_; | |
2585 } | |
2586 | |
2587 v8::Isolate* EventDetailsImpl::GetIsolate() const { | 2272 v8::Isolate* EventDetailsImpl::GetIsolate() const { |
2588 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate()); | 2273 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate()); |
2589 } | 2274 } |
2590 | 2275 |
2591 CommandMessage::CommandMessage() | |
2592 : text_(Vector<uint16_t>::empty()), client_data_(NULL) {} | |
2593 | |
2594 CommandMessage::CommandMessage(const Vector<uint16_t>& text, | |
2595 v8::Debug::ClientData* data) | |
2596 : text_(text), client_data_(data) {} | |
2597 | |
2598 void CommandMessage::Dispose() { | |
2599 text_.Dispose(); | |
2600 delete client_data_; | |
2601 client_data_ = NULL; | |
2602 } | |
2603 | |
2604 CommandMessage CommandMessage::New(const Vector<uint16_t>& command, | |
2605 v8::Debug::ClientData* data) { | |
2606 return CommandMessage(command.Clone(), data); | |
2607 } | |
2608 | |
2609 CommandMessageQueue::CommandMessageQueue(int size) | |
2610 : start_(0), end_(0), size_(size) { | |
2611 messages_ = NewArray<CommandMessage>(size); | |
2612 } | |
2613 | |
2614 CommandMessageQueue::~CommandMessageQueue() { | |
2615 while (!IsEmpty()) Get().Dispose(); | |
2616 DeleteArray(messages_); | |
2617 } | |
2618 | |
2619 CommandMessage CommandMessageQueue::Get() { | |
2620 DCHECK(!IsEmpty()); | |
2621 int result = start_; | |
2622 start_ = (start_ + 1) % size_; | |
2623 return messages_[result]; | |
2624 } | |
2625 | |
2626 void CommandMessageQueue::Put(const CommandMessage& message) { | |
2627 if ((end_ + 1) % size_ == start_) { | |
2628 Expand(); | |
2629 } | |
2630 messages_[end_] = message; | |
2631 end_ = (end_ + 1) % size_; | |
2632 } | |
2633 | |
2634 void CommandMessageQueue::Expand() { | |
2635 CommandMessageQueue new_queue(size_ * 2); | |
2636 while (!IsEmpty()) { | |
2637 new_queue.Put(Get()); | |
2638 } | |
2639 CommandMessage* array_to_free = messages_; | |
2640 *this = new_queue; | |
2641 new_queue.messages_ = array_to_free; | |
2642 // Make the new_queue empty so that it doesn't call Dispose on any messages. | |
2643 new_queue.start_ = new_queue.end_; | |
2644 // Automatic destructor called on new_queue, freeing array_to_free. | |
2645 } | |
2646 | |
2647 LockingCommandMessageQueue::LockingCommandMessageQueue(Logger* logger, int size) | |
2648 : logger_(logger), queue_(size) {} | |
2649 | |
2650 bool LockingCommandMessageQueue::IsEmpty() const { | |
2651 base::LockGuard<base::Mutex> lock_guard(&mutex_); | |
2652 return queue_.IsEmpty(); | |
2653 } | |
2654 | |
2655 CommandMessage LockingCommandMessageQueue::Get() { | |
2656 base::LockGuard<base::Mutex> lock_guard(&mutex_); | |
2657 CommandMessage result = queue_.Get(); | |
2658 logger_->DebugEvent("Get", result.text()); | |
2659 return result; | |
2660 } | |
2661 | |
2662 void LockingCommandMessageQueue::Put(const CommandMessage& message) { | |
2663 base::LockGuard<base::Mutex> lock_guard(&mutex_); | |
2664 queue_.Put(message); | |
2665 logger_->DebugEvent("Put", message.text()); | |
2666 } | |
2667 | |
2668 void LockingCommandMessageQueue::Clear() { | |
2669 base::LockGuard<base::Mutex> lock_guard(&mutex_); | |
2670 queue_.Clear(); | |
2671 } | |
2672 | |
2673 } // namespace internal | 2276 } // namespace internal |
2674 } // namespace v8 | 2277 } // namespace v8 |
OLD | NEW |