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 |