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