| 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 | |
| 1767 void Debug::PrepareForBreakPoints() { | 1730 void Debug::PrepareForBreakPoints() { |
| 1768 // If preparing for the first break point make sure to deoptimize all | 1731 // If preparing for the first break point make sure to deoptimize all |
| 1769 // functions as debugging does not work with optimized code. | 1732 // functions as debugging does not work with optimized code. |
| 1770 if (!has_break_points_) { | 1733 if (!has_break_points_) { |
| 1771 Deoptimizer::DeoptimizeAll(); | 1734 Deoptimizer::DeoptimizeAll(); |
| 1772 | 1735 |
| 1773 Handle<Code> lazy_compile = | 1736 // We are going to iterate heap to find all functions without |
| 1774 Handle<Code>(isolate_->builtins()->builtin(Builtins::kLazyCompile)); | 1737 // debug break slots. |
| 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()) { |
| 1748 JavaScriptFrame* frame = it.frame(); |
| 1749 if (frame->function()->IsJSFunction()) { |
| 1750 JSFunction* function = JSFunction::cast(frame->function()); |
| 1751 if (function->code()->kind() == Code::FUNCTION) |
| 1752 active_functions.Add(function); |
| 1753 } |
| 1754 } |
| 1755 active_functions.Sort(); |
| 1784 | 1756 |
| 1785 // Ensure no GC in this scope as we are comparing raw pointer | 1757 // Scan the heap for all non-optimized functions which has no |
| 1786 // values and performing a heap iteration. | 1758 // debug break slots. |
| 1787 AssertNoAllocation no_allocation; | 1759 HeapIterator iterator; |
| 1788 | 1760 HeapObject* obj = NULL; |
| 1789 // Find all non-optimized code functions with activation frames on | 1761 while (((obj = iterator.next()) != NULL)) { |
| 1790 // the stack. | 1762 if (obj->IsJSFunction()) { |
| 1791 for (JavaScriptFrameIterator it(isolate_); !it.done(); it.Advance()) { | 1763 JSFunction* function = JSFunction::cast(obj); |
| 1792 JavaScriptFrame* frame = it.frame(); | 1764 if (function->shared()->allows_lazy_compilation() && |
| 1793 if (frame->function()->IsJSFunction()) { | 1765 function->shared()->script()->IsScript() && |
| 1794 JSFunction* function = JSFunction::cast(frame->function()); | 1766 function->code()->kind() == Code::FUNCTION && |
| 1795 if (function->code()->kind() == Code::FUNCTION && | 1767 !function->code()->has_debug_break_slots()) { |
| 1796 !function->code()->has_debug_break_slots()) | 1768 bool has_activation = |
| 1797 active_functions.Add(Handle<JSFunction>(function)); | 1769 SortedListBSearch<JSFunction*>(active_functions, function) != -1; |
| 1798 } | 1770 if (!has_activation) { |
| 1799 } | 1771 function->set_code(lazy_compile); |
| 1800 // Sort the functions on the object pointer value to prepare for | 1772 function->shared()->set_code(lazy_compile); |
| 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 } | 1773 } |
| 1825 } | 1774 } |
| 1826 } | 1775 } |
| 1827 } | 1776 } |
| 1828 | |
| 1829 // Now the non-GC scope is left, and the sorting of the functions | |
| 1830 // in active_function is not ensured any more. The code below does | |
| 1831 // not rely on it. | |
| 1832 | |
| 1833 // Now recompile all functions with activation frames and and | |
| 1834 // patch the return address to run in the new compiled code. | |
| 1835 for (int i = 0; i < active_functions.length(); i++) { | |
| 1836 Handle<JSFunction> function = active_functions[i]; | |
| 1837 Handle<SharedFunctionInfo> shared(function->shared()); | |
| 1838 // If recompilation is not possible just skip it. | |
| 1839 if (shared->is_toplevel() || | |
| 1840 !shared->allows_lazy_compilation() || | |
| 1841 shared->code()->kind() == Code::BUILTIN) { | |
| 1842 continue; | |
| 1843 } | |
| 1844 | |
| 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++; | |
| 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); | |
| 1927 } | |
| 1928 } | |
| 1929 } | |
| 1930 } | 1777 } |
| 1931 } | 1778 } |
| 1932 | 1779 |
| 1933 | 1780 |
| 1934 // Ensures the debug information is present for shared. | 1781 // Ensures the debug information is present for shared. |
| 1935 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) { | 1782 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) { |
| 1936 // Return if we already have the debug info for shared. | 1783 // Return if we already have the debug info for shared. |
| 1937 if (HasDebugInfo(shared)) { | 1784 if (HasDebugInfo(shared)) { |
| 1938 ASSERT(shared->is_compiled()); | 1785 ASSERT(shared->is_compiled()); |
| 1939 return true; | 1786 return true; |
| (...skipping 1047 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2987 // Set the debug command break flag to have the command processed. | 2834 // Set the debug command break flag to have the command processed. |
| 2988 if (!isolate_->debug()->InDebugger()) { | 2835 if (!isolate_->debug()->InDebugger()) { |
| 2989 isolate_->stack_guard()->DebugCommand(); | 2836 isolate_->stack_guard()->DebugCommand(); |
| 2990 } | 2837 } |
| 2991 } | 2838 } |
| 2992 | 2839 |
| 2993 | 2840 |
| 2994 bool Debugger::IsDebuggerActive() { | 2841 bool Debugger::IsDebuggerActive() { |
| 2995 ScopedLock with(debugger_access_); | 2842 ScopedLock with(debugger_access_); |
| 2996 | 2843 |
| 2997 return message_handler_ != NULL || | 2844 return message_handler_ != NULL || !event_listener_.is_null(); |
| 2998 !event_listener_.is_null() || | |
| 2999 force_debugger_active_; | |
| 3000 } | 2845 } |
| 3001 | 2846 |
| 3002 | 2847 |
| 3003 Handle<Object> Debugger::Call(Handle<JSFunction> fun, | 2848 Handle<Object> Debugger::Call(Handle<JSFunction> fun, |
| 3004 Handle<Object> data, | 2849 Handle<Object> data, |
| 3005 bool* pending_exception) { | 2850 bool* pending_exception) { |
| 3006 // When calling functions in the debugger prevent it from beeing unloaded. | 2851 // When calling functions in the debugger prevent it from beeing unloaded. |
| 3007 Debugger::never_unload_debugger_ = true; | 2852 Debugger::never_unload_debugger_ = true; |
| 3008 | 2853 |
| 3009 // Enter the debugger. | 2854 // Enter the debugger. |
| (...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3387 { | 3232 { |
| 3388 Locker locker; | 3233 Locker locker; |
| 3389 Isolate::Current()->debugger()->CallMessageDispatchHandler(); | 3234 Isolate::Current()->debugger()->CallMessageDispatchHandler(); |
| 3390 } | 3235 } |
| 3391 } | 3236 } |
| 3392 } | 3237 } |
| 3393 | 3238 |
| 3394 #endif // ENABLE_DEBUGGER_SUPPORT | 3239 #endif // ENABLE_DEBUGGER_SUPPORT |
| 3395 | 3240 |
| 3396 } } // namespace v8::internal | 3241 } } // namespace v8::internal |
| OLD | NEW |