Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10)

Side by Side Diff: src/debug/debug.cc

Issue 2633803002: [inspector] implemented blackboxing inside v8 (Closed)
Patch Set: addressed comments Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 822 matching lines...) Expand 10 before | Expand all | Expand 10 after
833 while (debug_info_list_ != NULL) { 833 while (debug_info_list_ != NULL) {
834 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info()); 834 RemoveDebugInfoAndClearFromShared(debug_info_list_->debug_info());
835 } 835 }
836 } 836 }
837 837
838 void Debug::FloodWithOneShot(Handle<JSFunction> function, 838 void Debug::FloodWithOneShot(Handle<JSFunction> function,
839 BreakLocatorType type) { 839 BreakLocatorType type) {
840 // Debug utility functions are not subject to debugging. 840 // Debug utility functions are not subject to debugging.
841 if (function->native_context() == *debug_context()) return; 841 if (function->native_context() == *debug_context()) return;
842 842
843 if (!function->shared()->IsSubjectToDebugging()) { 843 if (!function->shared()->IsSubjectToDebugging() ||
844 IsBlackboxed(function->shared())) {
844 // Builtin functions are not subject to stepping, but need to be 845 // Builtin functions are not subject to stepping, but need to be
845 // deoptimized, because optimized code does not check for debug 846 // deoptimized, because optimized code does not check for debug
846 // step in at call sites. 847 // step in at call sites.
847 Deoptimizer::DeoptimizeFunction(*function); 848 Deoptimizer::DeoptimizeFunction(*function);
848 return; 849 return;
849 } 850 }
850 // Make sure the function is compiled and has set up the debug info. 851 // Make sure the function is compiled and has set up the debug info.
851 Handle<SharedFunctionInfo> shared(function->shared()); 852 Handle<SharedFunctionInfo> shared(function->shared());
852 if (!EnsureDebugInfo(shared, function)) { 853 if (!EnsureDebugInfo(shared, function)) {
853 // Return if we failed to retrieve the debug info. 854 // Return if we failed to retrieve the debug info.
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
952 if (last_step_action() == StepNext || last_step_action() == StepOut) { 953 if (last_step_action() == StepNext || last_step_action() == StepOut) {
953 while (!it.done()) { 954 while (!it.done()) {
954 Address current_fp = it.frame()->UnpaddedFP(); 955 Address current_fp = it.frame()->UnpaddedFP();
955 if (current_fp >= thread_local_.target_fp_) break; 956 if (current_fp >= thread_local_.target_fp_) break;
956 it.Advance(); 957 it.Advance();
957 } 958 }
958 } 959 }
959 960
960 // Find the closest Javascript frame we can flood with one-shots. 961 // Find the closest Javascript frame we can flood with one-shots.
961 while (!it.done() && 962 while (!it.done() &&
962 !it.frame()->function()->shared()->IsSubjectToDebugging()) { 963 (!it.frame()->function()->shared()->IsSubjectToDebugging() ||
964 IsBlackboxed(it.frame()->function()->shared()))) {
963 it.Advance(); 965 it.Advance();
964 } 966 }
965 967
966 if (it.done()) return; // No suitable Javascript catch handler. 968 if (it.done()) return; // No suitable Javascript catch handler.
967 969
968 FloodWithOneShot(Handle<JSFunction>(it.frame()->function())); 970 FloodWithOneShot(Handle<JSFunction>(it.frame()->function()));
969 } 971 }
970 972
971 973
972 void Debug::PrepareStep(StepAction step_action) { 974 void Debug::PrepareStep(StepAction step_action) {
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
1012 return; 1014 return;
1013 } 1015 }
1014 1016
1015 Handle<DebugInfo> debug_info(shared->GetDebugInfo()); 1017 Handle<DebugInfo> debug_info(shared->GetDebugInfo());
1016 BreakLocation location = BreakLocation::FromFrame(debug_info, frame); 1018 BreakLocation location = BreakLocation::FromFrame(debug_info, frame);
1017 1019
1018 // Any step at a return is a step-out. 1020 // Any step at a return is a step-out.
1019 if (location.IsReturn()) step_action = StepOut; 1021 if (location.IsReturn()) step_action = StepOut;
1020 // A step-next at a tail call is a step-out. 1022 // A step-next at a tail call is a step-out.
1021 if (location.IsTailCall() && step_action == StepNext) step_action = StepOut; 1023 if (location.IsTailCall() && step_action == StepNext) step_action = StepOut;
1024 // A step-next in blackboxed function is a step-out.
1025 if (step_action == StepNext && IsBlackboxed(shared)) {
dgozman 2017/01/24 00:12:08 nit: fits one line
kozy 2017/01/24 01:11:51 Done.
1026 step_action = StepOut;
1027 }
1022 1028
1023 thread_local_.last_statement_position_ = 1029 thread_local_.last_statement_position_ =
1024 summary.abstract_code()->SourceStatementPosition(summary.code_offset()); 1030 summary.abstract_code()->SourceStatementPosition(summary.code_offset());
1025 thread_local_.last_fp_ = frame->UnpaddedFP(); 1031 thread_local_.last_fp_ = frame->UnpaddedFP();
1026 // No longer perform the current async step. 1032 // No longer perform the current async step.
1027 clear_suspended_generator(); 1033 clear_suspended_generator();
1028 1034
1029 switch (step_action) { 1035 switch (step_action) {
1030 case StepNone: 1036 case StepNone:
1031 UNREACHABLE(); 1037 UNREACHABLE();
1032 break; 1038 break;
1033 case StepOut: 1039 case StepOut:
1034 // Advance to caller frame. 1040 // Advance to caller frame.
1035 frames_it.Advance(); 1041 frames_it.Advance();
1036 // Skip native and extension functions on the stack. 1042 // Skip native and extension functions on the stack.
1037 while (!frames_it.done() && 1043 while (
1038 !frames_it.frame()->function()->shared()->IsSubjectToDebugging()) { 1044 !frames_it.done() &&
1045 (!frames_it.frame()->function()->shared()->IsSubjectToDebugging() ||
1046 IsBlackboxed(frames_it.frame()->function()->shared()))) {
1039 // Builtin functions are not subject to stepping, but need to be 1047 // Builtin functions are not subject to stepping, but need to be
1040 // deoptimized to include checks for step-in at call sites. 1048 // deoptimized to include checks for step-in at call sites.
1041 Deoptimizer::DeoptimizeFunction(frames_it.frame()->function()); 1049 Deoptimizer::DeoptimizeFunction(frames_it.frame()->function());
1042 frames_it.Advance(); 1050 frames_it.Advance();
1043 } 1051 }
1044 if (!frames_it.done()) { 1052 if (!frames_it.done()) {
1045 // Fill the caller function to return to with one-shot break points. 1053 // Fill the caller function to return to with one-shot break points.
1046 Handle<JSFunction> caller_function(frames_it.frame()->function()); 1054 Handle<JSFunction> caller_function(frames_it.frame()->function());
1047 FloodWithOneShot(caller_function); 1055 FloodWithOneShot(caller_function);
1048 thread_local_.target_fp_ = frames_it.frame()->UnpaddedFP(); 1056 thread_local_.target_fp_ = frames_it.frame()->UnpaddedFP();
(...skipping 695 matching lines...) Expand 10 before | Expand all | Expand 10 after
1744 // Bail out if exception breaks are not active 1752 // Bail out if exception breaks are not active
1745 if (uncaught) { 1753 if (uncaught) {
1746 // Uncaught exceptions are reported by either flags. 1754 // Uncaught exceptions are reported by either flags.
1747 if (!(break_on_uncaught_exception_ || break_on_exception_)) return; 1755 if (!(break_on_uncaught_exception_ || break_on_exception_)) return;
1748 } else { 1756 } else {
1749 // Caught exceptions are reported is activated. 1757 // Caught exceptions are reported is activated.
1750 if (!break_on_exception_) return; 1758 if (!break_on_exception_) return;
1751 } 1759 }
1752 1760
1753 { 1761 {
1754 // Check whether the break location is muted.
1755 JavaScriptFrameIterator it(isolate_); 1762 JavaScriptFrameIterator it(isolate_);
1756 if (!it.done() && IsMutedAtCurrentLocation(it.frame())) return; 1763 // Check whether the top frame is blackboxed or the break location is muted.
1764 if (!it.done() && (IsBlackboxed(it.frame()->function()->shared()) ||
1765 IsMutedAtCurrentLocation(it.frame()))) {
1766 return;
1767 }
1757 } 1768 }
1758 1769
1759 DebugScope debug_scope(this); 1770 DebugScope debug_scope(this);
1760 if (debug_scope.failed()) return; 1771 if (debug_scope.failed()) return;
1761 1772
1762 if (debug_event_listener_) { 1773 if (debug_delegate_) {
1763 HandleScope scope(isolate_); 1774 HandleScope scope(isolate_);
1764 1775
1765 // Create the execution state. 1776 // Create the execution state.
1766 Handle<Object> exec_state; 1777 Handle<Object> exec_state;
1767 // Bail out and don't call debugger if exception. 1778 // Bail out and don't call debugger if exception.
1768 if (!MakeExecutionState().ToHandle(&exec_state)) return; 1779 if (!MakeExecutionState().ToHandle(&exec_state)) return;
1769 1780
1770 debug_event_listener_->ExceptionThrown( 1781 debug_delegate_->ExceptionThrown(
1771 GetDebugEventContext(isolate_), 1782 GetDebugEventContext(isolate_),
1772 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)), 1783 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
1773 v8::Utils::ToLocal(exception), promise->IsJSObject(), uncaught); 1784 v8::Utils::ToLocal(exception), promise->IsJSObject(), uncaught);
1774 if (!non_inspector_listener_exists()) return; 1785 if (!non_inspector_listener_exists()) return;
1775 } 1786 }
1776 1787
1777 // Create the event data object. 1788 // Create the event data object.
1778 Handle<Object> event_data; 1789 Handle<Object> event_data;
1779 // Bail out and don't call debugger if exception. 1790 // Bail out and don't call debugger if exception.
1780 if (!MakeExceptionEvent( 1791 if (!MakeExceptionEvent(
1781 exception, uncaught, promise).ToHandle(&event_data)) { 1792 exception, uncaught, promise).ToHandle(&event_data)) {
1782 return; 1793 return;
1783 } 1794 }
1784 1795
1785 // Process debug event. 1796 // Process debug event.
1786 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data)); 1797 ProcessDebugEvent(v8::Exception, Handle<JSObject>::cast(event_data));
1787 // Return to continue execution from where the exception was thrown. 1798 // Return to continue execution from where the exception was thrown.
1788 } 1799 }
1789 1800
1790 void Debug::OnDebugBreak(Handle<Object> break_points_hit) { 1801 void Debug::OnDebugBreak(Handle<Object> break_points_hit) {
1791 // The caller provided for DebugScope. 1802 // The caller provided for DebugScope.
1792 AssertDebugContext(); 1803 AssertDebugContext();
1793 // Bail out if there is no listener for this event 1804 // Bail out if there is no listener for this event
1794 if (ignore_events()) return; 1805 if (ignore_events()) return;
1795 1806
1796 #ifdef DEBUG 1807 #ifdef DEBUG
1797 PrintBreakLocation(); 1808 PrintBreakLocation();
1798 #endif // DEBUG 1809 #endif // DEBUG
1799 1810
1800 if (debug_event_listener_) { 1811 if (debug_delegate_) {
1801 HandleScope scope(isolate_); 1812 HandleScope scope(isolate_);
1802 1813
1803 // Create the execution state. 1814 // Create the execution state.
1804 Handle<Object> exec_state; 1815 Handle<Object> exec_state;
1805 // Bail out and don't call debugger if exception. 1816 // Bail out and don't call debugger if exception.
1806 if (!MakeExecutionState().ToHandle(&exec_state)) return; 1817 if (!MakeExecutionState().ToHandle(&exec_state)) return;
1807 1818
1808 bool previous = in_debug_event_listener_; 1819 bool previous = in_debug_event_listener_;
1809 in_debug_event_listener_ = true; 1820 in_debug_event_listener_ = true;
1810 debug_event_listener_->BreakProgramRequested( 1821 debug_delegate_->BreakProgramRequested(
1811 GetDebugEventContext(isolate_), 1822 GetDebugEventContext(isolate_),
1812 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)), 1823 v8::Utils::ToLocal(Handle<JSObject>::cast(exec_state)),
1813 v8::Utils::ToLocal(break_points_hit)); 1824 v8::Utils::ToLocal(break_points_hit));
1814 in_debug_event_listener_ = previous; 1825 in_debug_event_listener_ = previous;
1815 if (!non_inspector_listener_exists()) return; 1826 if (!non_inspector_listener_exists()) return;
1816 } 1827 }
1817 1828
1818 HandleScope scope(isolate_); 1829 HandleScope scope(isolate_);
1819 // Create the event data object. 1830 // Create the event data object.
1820 Handle<Object> event_data; 1831 Handle<Object> event_data;
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
1884 // Since we holding promise when at least one microtask is scheduled (inside 1895 // Since we holding promise when at least one microtask is scheduled (inside
1885 // PromiseReactionJobInfo), we can send cancel event in weak callback. 1896 // PromiseReactionJobInfo), we can send cancel event in weak callback.
1886 GlobalHandles::MakeWeak( 1897 GlobalHandles::MakeWeak(
1887 global_handle.location(), 1898 global_handle.location(),
1888 new CollectedCallbackData(global_handle.location(), async_id->value(), 1899 new CollectedCallbackData(global_handle.location(), async_id->value(),
1889 this, isolate_), 1900 this, isolate_),
1890 &ResetPromiseHandle, v8::WeakCallbackType::kParameter); 1901 &ResetPromiseHandle, v8::WeakCallbackType::kParameter);
1891 return async_id->value(); 1902 return async_id->value();
1892 } 1903 }
1893 1904
1905 namespace {
1906 debug::Location GetDebugLocation(Handle<Script> script, int source_position) {
1907 Script::PositionInfo info;
1908 Script::GetPositionInfo(script, source_position, &info, Script::WITH_OFFSET);
1909 return debug::Location(info.line, info.column);
1910 }
1911 } // namespace
1912
1913 bool Debug::IsBlackboxed(SharedFunctionInfo* shared) {
1914 HandleScope scope(isolate_);
1915 Handle<SharedFunctionInfo> shared_function_info(shared);
1916 return IsBlackboxed(shared_function_info);
1917 }
1918
1919 bool Debug::IsBlackboxed(Handle<SharedFunctionInfo> shared) {
1920 if (!debug_delegate_) return false;
1921 if (!shared->computed_debug_is_blackboxed()) {
1922 HandleScope handle_scope(isolate_);
1923
1924 bool is_blackboxed = false;
1925 Handle<Script> script(Script::cast(shared->script()));
1926 if (script->type() == i::Script::TYPE_NORMAL) {
1927 debug::Location start =
1928 GetDebugLocation(script, shared->start_position());
1929 debug::Location end = GetDebugLocation(script, shared->end_position());
1930 is_blackboxed = debug_delegate_->IsBlackboxed(
1931 ToApiHandle<debug::Script>(script), start, end);
1932 }
1933 shared->set_debug_is_blackboxed(is_blackboxed);
1934 shared->set_computed_debug_is_blackboxed(true);
1935 }
1936 return shared->debug_is_blackboxed();
1937 }
1938
1894 void Debug::OnAsyncTaskEvent(debug::PromiseDebugActionType type, int id) { 1939 void Debug::OnAsyncTaskEvent(debug::PromiseDebugActionType type, int id) {
1895 if (in_debug_scope() || ignore_events()) return; 1940 if (in_debug_scope() || ignore_events()) return;
1896 1941
1897 if (debug_event_listener_) { 1942 if (debug_delegate_) {
1898 debug_event_listener_->PromiseEventOccurred(type, id); 1943 debug_delegate_->PromiseEventOccurred(type, id);
1899 if (!non_inspector_listener_exists()) return; 1944 if (!non_inspector_listener_exists()) return;
1900 } 1945 }
1901 1946
1902 HandleScope scope(isolate_); 1947 HandleScope scope(isolate_);
1903 DebugScope debug_scope(this); 1948 DebugScope debug_scope(this);
1904 if (debug_scope.failed()) return; 1949 if (debug_scope.failed()) return;
1905 1950
1906 // Create the script collected state object. 1951 // Create the script collected state object.
1907 Handle<Object> event_data; 1952 Handle<Object> event_data;
1908 // Bail out and don't call debugger if exception. 1953 // Bail out and don't call debugger if exception.
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
1960 void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) { 2005 void Debug::ProcessCompileEvent(v8::DebugEvent event, Handle<Script> script) {
1961 if (ignore_events()) return; 2006 if (ignore_events()) return;
1962 if (script->type() != i::Script::TYPE_NORMAL && 2007 if (script->type() != i::Script::TYPE_NORMAL &&
1963 script->type() != i::Script::TYPE_WASM) { 2008 script->type() != i::Script::TYPE_WASM) {
1964 return; 2009 return;
1965 } 2010 }
1966 SuppressDebug while_processing(this); 2011 SuppressDebug while_processing(this);
1967 DebugScope debug_scope(this); 2012 DebugScope debug_scope(this);
1968 if (debug_scope.failed()) return; 2013 if (debug_scope.failed()) return;
1969 2014
1970 if (debug_event_listener_) { 2015 if (debug_delegate_) {
1971 debug_event_listener_->ScriptCompiled(ToApiHandle<debug::Script>(script), 2016 debug_delegate_->ScriptCompiled(ToApiHandle<debug::Script>(script),
1972 event != v8::AfterCompile); 2017 event != v8::AfterCompile);
1973 if (!non_inspector_listener_exists()) return; 2018 if (!non_inspector_listener_exists()) return;
1974 } 2019 }
1975 2020
1976 HandleScope scope(isolate_); 2021 HandleScope scope(isolate_);
1977 // Create the compile state object. 2022 // Create the compile state object.
1978 Handle<Object> event_data; 2023 Handle<Object> event_data;
1979 // Bail out and don't call debugger if exception. 2024 // Bail out and don't call debugger if exception.
1980 if (!MakeCompileEvent(script, event).ToHandle(&event_data)) return; 2025 if (!MakeCompileEvent(script, event).ToHandle(&event_data)) return;
1981 2026
1982 // Process debug event. 2027 // Process debug event.
(...skipping 23 matching lines...) Expand all
2006 // Set new entry. 2051 // Set new entry.
2007 if (!callback->IsNullOrUndefined(isolate_)) { 2052 if (!callback->IsNullOrUndefined(isolate_)) {
2008 event_listener_ = global_handles->Create(*callback); 2053 event_listener_ = global_handles->Create(*callback);
2009 if (data.is_null()) data = isolate_->factory()->undefined_value(); 2054 if (data.is_null()) data = isolate_->factory()->undefined_value();
2010 event_listener_data_ = global_handles->Create(*data); 2055 event_listener_data_ = global_handles->Create(*data);
2011 } 2056 }
2012 2057
2013 UpdateState(); 2058 UpdateState();
2014 } 2059 }
2015 2060
2016 2061 void Debug::SetDebugDelegate(debug::DebugDelegate* delegate) {
2017 void Debug::SetDebugEventListener(debug::DebugEventListener* listener) { 2062 debug_delegate_ = delegate;
2018 debug_event_listener_ = listener;
2019 UpdateState(); 2063 UpdateState();
2020 } 2064 }
2021 2065
2022 void Debug::UpdateState() { 2066 void Debug::UpdateState() {
2023 bool is_active = 2067 bool is_active = !event_listener_.is_null() || debug_delegate_ != nullptr;
2024 !event_listener_.is_null() || debug_event_listener_ != nullptr;
2025 if (is_active || in_debug_scope()) { 2068 if (is_active || in_debug_scope()) {
2026 // Note that the debug context could have already been loaded to 2069 // Note that the debug context could have already been loaded to
2027 // bootstrap test cases. 2070 // bootstrap test cases.
2028 isolate_->compilation_cache()->Disable(); 2071 isolate_->compilation_cache()->Disable();
2029 is_active = Load(); 2072 is_active = Load();
2030 } else if (is_loaded()) { 2073 } else if (is_loaded()) {
2031 isolate_->compilation_cache()->Enable(); 2074 isolate_->compilation_cache()->Enable();
2032 Unload(); 2075 Unload();
2033 } 2076 }
2034 is_active_ = is_active; 2077 is_active_ = is_active;
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
2071 2114
2072 StackLimitCheck check(isolate_); 2115 StackLimitCheck check(isolate_);
2073 if (check.HasOverflowed()) return; 2116 if (check.HasOverflowed()) return;
2074 2117
2075 { JavaScriptFrameIterator it(isolate_); 2118 { JavaScriptFrameIterator it(isolate_);
2076 DCHECK(!it.done()); 2119 DCHECK(!it.done());
2077 Object* fun = it.frame()->function(); 2120 Object* fun = it.frame()->function();
2078 if (fun && fun->IsJSFunction()) { 2121 if (fun && fun->IsJSFunction()) {
2079 // Don't stop in builtin functions. 2122 // Don't stop in builtin functions.
2080 if (!JSFunction::cast(fun)->shared()->IsSubjectToDebugging()) return; 2123 if (!JSFunction::cast(fun)->shared()->IsSubjectToDebugging()) return;
2124 if (isolate_->stack_guard()->CheckDebugBreak() &&
2125 IsBlackboxed(JSFunction::cast(fun)->shared())) {
2126 Deoptimizer::DeoptimizeFunction(JSFunction::cast(fun));
2127 return;
2128 }
2081 JSGlobalObject* global = 2129 JSGlobalObject* global =
2082 JSFunction::cast(fun)->context()->global_object(); 2130 JSFunction::cast(fun)->context()->global_object();
2083 // Don't stop in debugger functions. 2131 // Don't stop in debugger functions.
2084 if (IsDebugGlobal(global)) return; 2132 if (IsDebugGlobal(global)) return;
2085 // Don't stop if the break location is muted. 2133 // Don't stop if the break location is muted.
2086 if (IsMutedAtCurrentLocation(it.frame())) return; 2134 if (IsMutedAtCurrentLocation(it.frame())) return;
2087 } 2135 }
2088 } 2136 }
2089 2137
2090 isolate_->stack_guard()->ClearDebugBreak(); 2138 isolate_->stack_guard()->ClearDebugBreak();
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after
2268 return v8::Utils::ToLocal(callback_data_); 2316 return v8::Utils::ToLocal(callback_data_);
2269 } 2317 }
2270 2318
2271 2319
2272 v8::Isolate* EventDetailsImpl::GetIsolate() const { 2320 v8::Isolate* EventDetailsImpl::GetIsolate() const {
2273 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate()); 2321 return reinterpret_cast<v8::Isolate*>(exec_state_->GetIsolate());
2274 } 2322 }
2275 2323
2276 } // namespace internal 2324 } // namespace internal
2277 } // namespace v8 2325 } // namespace v8
OLDNEW
« no previous file with comments | « src/debug/debug.h ('k') | src/debug/debug-interface.h » ('j') | src/debug/debug-interface.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698