OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
80 V8::FatalProcessOutOfMemory("PrintLn"); | 80 V8::FatalProcessOutOfMemory("PrintLn"); |
81 return; | 81 return; |
82 } | 82 } |
83 s->WriteAscii(data.start()); | 83 s->WriteAscii(data.start()); |
84 PrintF("%s\n", data.start()); | 84 PrintF("%s\n", data.start()); |
85 } | 85 } |
86 | 86 |
87 | 87 |
88 static Handle<Code> ComputeCallDebugBreak(int argc, Code::Kind kind) { | 88 static Handle<Code> ComputeCallDebugBreak(int argc, Code::Kind kind) { |
89 Isolate* isolate = Isolate::Current(); | 89 Isolate* isolate = Isolate::Current(); |
90 CALL_HEAP_FUNCTION( | 90 return isolate->stub_cache()->ComputeCallDebugBreak(argc, kind); |
91 isolate, | |
92 isolate->stub_cache()->ComputeCallDebugBreak(argc, kind), | |
93 Code); | |
94 } | 91 } |
95 | 92 |
96 | 93 |
97 static Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind) { | 94 static Handle<Code> ComputeCallDebugPrepareStepIn(int argc, Code::Kind kind) { |
98 Isolate* isolate = Isolate::Current(); | 95 Isolate* isolate = Isolate::Current(); |
99 CALL_HEAP_FUNCTION( | 96 return isolate->stub_cache()->ComputeCallDebugPrepareStepIn(argc, kind); |
100 isolate, | |
101 isolate->stub_cache()->ComputeCallDebugPrepareStepIn(argc, kind), | |
102 Code); | |
103 } | 97 } |
104 | 98 |
105 | 99 |
106 static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) { | 100 static v8::Handle<v8::Context> GetDebugEventContext(Isolate* isolate) { |
107 Handle<Context> context = isolate->debug()->debugger_entry()->GetContext(); | 101 Handle<Context> context = isolate->debug()->debugger_entry()->GetContext(); |
108 // Isolate::context() may have been NULL when "script collected" event | 102 // Isolate::context() may have been NULL when "script collected" event |
109 // occured. | 103 // occured. |
110 if (context.is_null()) return v8::Local<v8::Context>(); | 104 if (context.is_null()) return v8::Local<v8::Context>(); |
111 Handle<Context> global_context(context->global_context()); | 105 Handle<Context> global_context(context->global_context()); |
112 return v8::Utils::ToLocal(global_context); | 106 return v8::Utils::ToLocal(global_context); |
(...skipping 1607 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1720 } | 1714 } |
1721 | 1715 |
1722 | 1716 |
1723 void Debug::ClearStepNext() { | 1717 void Debug::ClearStepNext() { |
1724 thread_local_.last_step_action_ = StepNone; | 1718 thread_local_.last_step_action_ = StepNone; |
1725 thread_local_.last_statement_position_ = RelocInfo::kNoPosition; | 1719 thread_local_.last_statement_position_ = RelocInfo::kNoPosition; |
1726 thread_local_.last_fp_ = 0; | 1720 thread_local_.last_fp_ = 0; |
1727 } | 1721 } |
1728 | 1722 |
1729 | 1723 |
| 1724 // Helper function to compile full code for debugging. This code will |
| 1725 // have debug break slots and deoptimization |
| 1726 // information. Deoptimization information is required in case that an |
| 1727 // optimized version of this function is still activated on the |
| 1728 // stack. It will also make sure that the full code is compiled with |
| 1729 // the same flags as the previous version - that is flags which can |
| 1730 // change the code generated. The current method of mapping from |
| 1731 // already compiled full code without debug break slots to full code |
| 1732 // with debug break slots depends on the generated code is otherwise |
| 1733 // exactly the same. |
| 1734 static bool CompileFullCodeForDebugging(Handle<SharedFunctionInfo> shared, |
| 1735 Handle<Code> current_code) { |
| 1736 ASSERT(!current_code->has_debug_break_slots()); |
| 1737 |
| 1738 CompilationInfo info(shared); |
| 1739 info.MarkCompilingForDebugging(current_code); |
| 1740 ASSERT(!info.shared_info()->is_compiled()); |
| 1741 ASSERT(!info.isolate()->has_pending_exception()); |
| 1742 |
| 1743 // Use compile lazy which will end up compiling the full code in the |
| 1744 // configuration configured above. |
| 1745 bool result = Compiler::CompileLazy(&info); |
| 1746 ASSERT(result != Isolate::Current()->has_pending_exception()); |
| 1747 info.isolate()->clear_pending_exception(); |
| 1748 #if DEBUG |
| 1749 if (result) { |
| 1750 Handle<Code> new_code(shared->code()); |
| 1751 ASSERT(new_code->has_debug_break_slots()); |
| 1752 ASSERT(current_code->is_compiled_optimizable() == |
| 1753 new_code->is_compiled_optimizable()); |
| 1754 ASSERT(current_code->instruction_size() <= new_code->instruction_size()); |
| 1755 } |
| 1756 #endif |
| 1757 return result; |
| 1758 } |
| 1759 |
| 1760 |
1730 void Debug::PrepareForBreakPoints() { | 1761 void Debug::PrepareForBreakPoints() { |
1731 // If preparing for the first break point make sure to deoptimize all | 1762 // If preparing for the first break point make sure to deoptimize all |
1732 // functions as debugging does not work with optimized code. | 1763 // functions as debugging does not work with optimized code. |
1733 if (!has_break_points_) { | 1764 if (!has_break_points_) { |
1734 Deoptimizer::DeoptimizeAll(); | 1765 Deoptimizer::DeoptimizeAll(); |
1735 | 1766 |
1736 // We are going to iterate heap to find all functions without | 1767 Handle<Code> lazy_compile = |
1737 // debug break slots. | 1768 Handle<Code>(isolate_->builtins()->builtin(Builtins::kLazyCompile)); |
1738 isolate_->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask); | 1769 |
1739 | 1770 // Keep the list of activated functions in a handlified list as it |
1740 AssertNoAllocation no_allocation; | 1771 // is used both in GC and non-GC code. |
1741 Builtins* builtins = isolate_->builtins(); | 1772 List<Handle<JSFunction> > active_functions(100); |
1742 Code* lazy_compile = builtins->builtin(Builtins::kLazyCompile); | 1773 |
1743 | 1774 { |
1744 // Find all non-optimized code functions with activation frames on | 1775 // We are going to iterate heap to find all functions without |
1745 // the stack. | 1776 // debug break slots. |
1746 List<JSFunction*> active_functions(100); | 1777 isolate_->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask); |
1747 for (JavaScriptFrameIterator it(isolate_); !it.done(); it.Advance()) { | 1778 |
1748 JavaScriptFrame* frame = it.frame(); | 1779 // Ensure no GC in this scope as we are comparing raw pointer |
1749 if (frame->function()->IsJSFunction()) { | 1780 // values and performing a heap iteration. |
1750 JSFunction* function = JSFunction::cast(frame->function()); | 1781 AssertNoAllocation no_allocation; |
1751 if (function->code()->kind() == Code::FUNCTION) | 1782 |
1752 active_functions.Add(function); | 1783 // Find all non-optimized code functions with activation frames on |
| 1784 // the stack. |
| 1785 for (JavaScriptFrameIterator it(isolate_); !it.done(); it.Advance()) { |
| 1786 JavaScriptFrame* frame = it.frame(); |
| 1787 if (frame->function()->IsJSFunction()) { |
| 1788 JSFunction* function = JSFunction::cast(frame->function()); |
| 1789 if (function->code()->kind() == Code::FUNCTION && |
| 1790 !function->code()->has_debug_break_slots()) |
| 1791 active_functions.Add(Handle<JSFunction>(function)); |
| 1792 } |
| 1793 } |
| 1794 // Sort the functions on the object pointer value to prepare for |
| 1795 // the binary search below. |
| 1796 active_functions.Sort(HandleObjectPointerCompare<JSFunction>); |
| 1797 |
| 1798 // Scan the heap for all non-optimized functions which has no |
| 1799 // debug break slots. |
| 1800 HeapIterator iterator; |
| 1801 HeapObject* obj = NULL; |
| 1802 while (((obj = iterator.next()) != NULL)) { |
| 1803 if (obj->IsJSFunction()) { |
| 1804 JSFunction* function = JSFunction::cast(obj); |
| 1805 if (function->shared()->allows_lazy_compilation() && |
| 1806 function->shared()->script()->IsScript() && |
| 1807 function->code()->kind() == Code::FUNCTION && |
| 1808 !function->code()->has_debug_break_slots()) { |
| 1809 bool has_activation = |
| 1810 SortedListBSearch<Handle<JSFunction> >( |
| 1811 active_functions, |
| 1812 Handle<JSFunction>(function), |
| 1813 HandleObjectPointerCompare<JSFunction>) != -1; |
| 1814 if (!has_activation) { |
| 1815 function->set_code(*lazy_compile); |
| 1816 function->shared()->set_code(*lazy_compile); |
| 1817 } |
| 1818 } |
| 1819 } |
1753 } | 1820 } |
1754 } | 1821 } |
1755 active_functions.Sort(); | 1822 |
1756 | 1823 // Now the non-GC scope is left, and the sorting of the functions |
1757 // Scan the heap for all non-optimized functions which has no | 1824 // in active_function is not ensured any more. The code below does |
1758 // debug break slots. | 1825 // not rely on it. |
1759 HeapIterator iterator; | 1826 |
1760 HeapObject* obj = NULL; | 1827 // Now recompile all functions with activation frames and and |
1761 while (((obj = iterator.next()) != NULL)) { | 1828 // patch the return address to run in the new compiled code. |
1762 if (obj->IsJSFunction()) { | 1829 for (int i = 0; i < active_functions.length(); i++) { |
1763 JSFunction* function = JSFunction::cast(obj); | 1830 Handle<JSFunction> function = active_functions[i]; |
1764 if (function->shared()->allows_lazy_compilation() && | 1831 Handle<SharedFunctionInfo> shared(function->shared()); |
1765 function->shared()->script()->IsScript() && | 1832 // If recompilation is not possible just skip it. |
1766 function->code()->kind() == Code::FUNCTION && | 1833 if (shared->is_toplevel() || |
1767 !function->code()->has_debug_break_slots()) { | 1834 !shared->allows_lazy_compilation() || |
1768 bool has_activation = | 1835 shared->code()->kind() == Code::BUILTIN) { |
1769 SortedListBSearch<JSFunction*>(active_functions, function) != -1; | 1836 continue; |
1770 if (!has_activation) { | 1837 } |
1771 function->set_code(lazy_compile); | 1838 |
1772 function->shared()->set_code(lazy_compile); | 1839 // Make sure that the shared full code is compiled with debug |
| 1840 // break slots. |
| 1841 Handle<Code> current_code(function->code()); |
| 1842 if (shared->code()->has_debug_break_slots()) { |
| 1843 // if the code is already recompiled to have break slots skip |
| 1844 // recompilation. |
| 1845 ASSERT(!function->code()->has_debug_break_slots()); |
| 1846 } else { |
| 1847 // Try to compile the full code with debug break slots. If it |
| 1848 // fails just keep the current code. |
| 1849 ASSERT(shared->code() == *current_code); |
| 1850 ZoneScope zone_scope(isolate_, DELETE_ON_EXIT); |
| 1851 shared->set_code(*lazy_compile); |
| 1852 bool prev_force_debugger_active = |
| 1853 isolate_->debugger()->force_debugger_active(); |
| 1854 isolate_->debugger()->set_force_debugger_active(true); |
| 1855 CompileFullCodeForDebugging(shared, current_code); |
| 1856 isolate_->debugger()->set_force_debugger_active( |
| 1857 prev_force_debugger_active); |
| 1858 if (!shared->is_compiled()) { |
| 1859 shared->set_code(*current_code); |
| 1860 continue; |
| 1861 } |
| 1862 } |
| 1863 Handle<Code> new_code(shared->code()); |
| 1864 |
| 1865 // Find the function and patch return address. |
| 1866 for (JavaScriptFrameIterator it(isolate_); !it.done(); it.Advance()) { |
| 1867 JavaScriptFrame* frame = it.frame(); |
| 1868 // If the current frame is for this function in its |
| 1869 // non-optimized form rewrite the return address to continue |
| 1870 // in the newly compiled full code with debug break slots. |
| 1871 if (frame->function()->IsJSFunction() && |
| 1872 frame->function() == *function && |
| 1873 frame->LookupCode()->kind() == Code::FUNCTION) { |
| 1874 intptr_t delta = frame->pc() - current_code->instruction_start(); |
| 1875 int debug_break_slot_count = 0; |
| 1876 int mask = RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT); |
| 1877 for (RelocIterator it(*new_code, mask); !it.done(); it.next()) { |
| 1878 // Check if the pc in the new code with debug break |
| 1879 // slots is before this slot. |
| 1880 RelocInfo* info = it.rinfo(); |
| 1881 int debug_break_slot_bytes = |
| 1882 debug_break_slot_count * Assembler::kDebugBreakSlotLength; |
| 1883 intptr_t new_delta = |
| 1884 info->pc() - |
| 1885 new_code->instruction_start() - |
| 1886 debug_break_slot_bytes; |
| 1887 if (new_delta > delta) { |
| 1888 break; |
| 1889 } |
| 1890 |
| 1891 // Passed a debug break slot in the full code with debug |
| 1892 // break slots. |
| 1893 debug_break_slot_count++; |
1773 } | 1894 } |
| 1895 int debug_break_slot_bytes = |
| 1896 debug_break_slot_count * Assembler::kDebugBreakSlotLength; |
| 1897 if (FLAG_trace_deopt) { |
| 1898 PrintF("Replacing code %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) " |
| 1899 "with %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) " |
| 1900 "for debugging, " |
| 1901 "changing pc from %08" V8PRIxPTR " to %08" V8PRIxPTR "\n", |
| 1902 reinterpret_cast<intptr_t>( |
| 1903 current_code->instruction_start()), |
| 1904 reinterpret_cast<intptr_t>( |
| 1905 current_code->instruction_start()) + |
| 1906 current_code->instruction_size(), |
| 1907 current_code->instruction_size(), |
| 1908 reinterpret_cast<intptr_t>(new_code->instruction_start()), |
| 1909 reinterpret_cast<intptr_t>(new_code->instruction_start()) + |
| 1910 new_code->instruction_size(), |
| 1911 new_code->instruction_size(), |
| 1912 reinterpret_cast<intptr_t>(frame->pc()), |
| 1913 reinterpret_cast<intptr_t>(new_code->instruction_start()) + |
| 1914 delta + debug_break_slot_bytes); |
| 1915 } |
| 1916 |
| 1917 // Patch the return address to return into the code with |
| 1918 // debug break slots. |
| 1919 frame->set_pc( |
| 1920 new_code->instruction_start() + delta + debug_break_slot_bytes); |
1774 } | 1921 } |
1775 } | 1922 } |
1776 } | 1923 } |
1777 } | 1924 } |
1778 } | 1925 } |
1779 | 1926 |
1780 | 1927 |
1781 // Ensures the debug information is present for shared. | 1928 // Ensures the debug information is present for shared. |
1782 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) { | 1929 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) { |
1783 // Return if we already have the debug info for shared. | 1930 // Return if we already have the debug info for shared. |
1784 if (HasDebugInfo(shared)) { | 1931 if (HasDebugInfo(shared)) { |
1785 ASSERT(shared->is_compiled()); | 1932 ASSERT(shared->is_compiled()); |
1786 return true; | 1933 return true; |
1787 } | 1934 } |
1788 | 1935 |
1789 // Ensure shared in compiled. Return false if this failed. | 1936 // Ensure shared in compiled. Return false if this failed. |
1790 if (!EnsureCompiled(shared, CLEAR_EXCEPTION)) return false; | 1937 if (!SharedFunctionInfo::EnsureCompiled(shared, CLEAR_EXCEPTION)) { |
| 1938 return false; |
| 1939 } |
1791 | 1940 |
1792 // Create the debug info object. | 1941 // Create the debug info object. |
1793 Handle<DebugInfo> debug_info = FACTORY->NewDebugInfo(shared); | 1942 Handle<DebugInfo> debug_info = FACTORY->NewDebugInfo(shared); |
1794 | 1943 |
1795 // Add debug info to the list. | 1944 // Add debug info to the list. |
1796 DebugInfoListNode* node = new DebugInfoListNode(*debug_info); | 1945 DebugInfoListNode* node = new DebugInfoListNode(*debug_info); |
1797 node->set_next(debug_info_list_); | 1946 node->set_next(debug_info_list_); |
1798 debug_info_list_ = node; | 1947 debug_info_list_ = node; |
1799 | 1948 |
1800 // Now there is at least one break point. | 1949 // Now there is at least one break point. |
(...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2070 } | 2219 } |
2071 | 2220 |
2072 | 2221 |
2073 Debugger::Debugger(Isolate* isolate) | 2222 Debugger::Debugger(Isolate* isolate) |
2074 : debugger_access_(isolate->debugger_access()), | 2223 : debugger_access_(isolate->debugger_access()), |
2075 event_listener_(Handle<Object>()), | 2224 event_listener_(Handle<Object>()), |
2076 event_listener_data_(Handle<Object>()), | 2225 event_listener_data_(Handle<Object>()), |
2077 compiling_natives_(false), | 2226 compiling_natives_(false), |
2078 is_loading_debugger_(false), | 2227 is_loading_debugger_(false), |
2079 never_unload_debugger_(false), | 2228 never_unload_debugger_(false), |
| 2229 force_debugger_active_(false), |
2080 message_handler_(NULL), | 2230 message_handler_(NULL), |
2081 debugger_unload_pending_(false), | 2231 debugger_unload_pending_(false), |
2082 host_dispatch_handler_(NULL), | 2232 host_dispatch_handler_(NULL), |
2083 dispatch_handler_access_(OS::CreateMutex()), | 2233 dispatch_handler_access_(OS::CreateMutex()), |
2084 debug_message_dispatch_handler_(NULL), | 2234 debug_message_dispatch_handler_(NULL), |
2085 message_dispatch_helper_thread_(NULL), | 2235 message_dispatch_helper_thread_(NULL), |
2086 host_dispatch_micros_(100 * 1000), | 2236 host_dispatch_micros_(100 * 1000), |
2087 agent_(NULL), | 2237 agent_(NULL), |
2088 command_queue_(isolate->logger(), kQueueInitialSize), | 2238 command_queue_(isolate->logger(), kQueueInitialSize), |
2089 command_received_(OS::CreateSemaphore(0)), | 2239 command_received_(OS::CreateSemaphore(0)), |
(...skipping 747 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2837 // Set the debug command break flag to have the command processed. | 2987 // Set the debug command break flag to have the command processed. |
2838 if (!isolate_->debug()->InDebugger()) { | 2988 if (!isolate_->debug()->InDebugger()) { |
2839 isolate_->stack_guard()->DebugCommand(); | 2989 isolate_->stack_guard()->DebugCommand(); |
2840 } | 2990 } |
2841 } | 2991 } |
2842 | 2992 |
2843 | 2993 |
2844 bool Debugger::IsDebuggerActive() { | 2994 bool Debugger::IsDebuggerActive() { |
2845 ScopedLock with(debugger_access_); | 2995 ScopedLock with(debugger_access_); |
2846 | 2996 |
2847 return message_handler_ != NULL || !event_listener_.is_null(); | 2997 return message_handler_ != NULL || |
| 2998 !event_listener_.is_null() || |
| 2999 force_debugger_active_; |
2848 } | 3000 } |
2849 | 3001 |
2850 | 3002 |
2851 Handle<Object> Debugger::Call(Handle<JSFunction> fun, | 3003 Handle<Object> Debugger::Call(Handle<JSFunction> fun, |
2852 Handle<Object> data, | 3004 Handle<Object> data, |
2853 bool* pending_exception) { | 3005 bool* pending_exception) { |
2854 // When calling functions in the debugger prevent it from beeing unloaded. | 3006 // When calling functions in the debugger prevent it from beeing unloaded. |
2855 Debugger::never_unload_debugger_ = true; | 3007 Debugger::never_unload_debugger_ = true; |
2856 | 3008 |
2857 // Enter the debugger. | 3009 // Enter the debugger. |
(...skipping 464 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3322 { | 3474 { |
3323 Locker locker; | 3475 Locker locker; |
3324 Isolate::Current()->debugger()->CallMessageDispatchHandler(); | 3476 Isolate::Current()->debugger()->CallMessageDispatchHandler(); |
3325 } | 3477 } |
3326 } | 3478 } |
3327 } | 3479 } |
3328 | 3480 |
3329 #endif // ENABLE_DEBUGGER_SUPPORT | 3481 #endif // ENABLE_DEBUGGER_SUPPORT |
3330 | 3482 |
3331 } } // namespace v8::internal | 3483 } } // namespace v8::internal |
OLD | NEW |