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); | |
1739 | 1775 |
1740 AssertNoAllocation no_allocation; | 1776 // Keep the list of activated functions in a handlified list as it |
1741 Builtins* builtins = isolate_->builtins(); | 1777 // is used both in GC and non-GC code. |
1742 Code* lazy_compile = builtins->builtin(Builtins::kLazyCompile); | 1778 List<Handle<JSFunction> > active_functions(100); |
1743 | 1779 |
1744 // Find all non-optimized code functions with activation frames on | 1780 { |
1745 // the stack. | 1781 // Ensure no GC in this scope as we are comparing raw pointer |
1746 List<JSFunction*> active_functions(100); | 1782 // values and performing a heap iteration. |
1747 for (JavaScriptFrameIterator it(isolate_); !it.done(); it.Advance()) { | 1783 AssertNoAllocation no_allocation; |
1748 JavaScriptFrame* frame = it.frame(); | 1784 |
1749 if (frame->function()->IsJSFunction()) { | 1785 // Find all non-optimized code functions with activation frames on |
1750 JSFunction* function = JSFunction::cast(frame->function()); | 1786 // the stack. |
1751 if (function->code()->kind() == Code::FUNCTION) | 1787 for (JavaScriptFrameIterator it(isolate_); !it.done(); it.Advance()) { |
1752 active_functions.Add(function); | 1788 JavaScriptFrame* frame = it.frame(); |
| 1789 if (frame->function()->IsJSFunction()) { |
| 1790 JSFunction* function = JSFunction::cast(frame->function()); |
| 1791 if (function->code()->kind() == Code::FUNCTION && |
| 1792 !function->code()->has_debug_break_slots()) |
| 1793 active_functions.Add(Handle<JSFunction>(function)); |
| 1794 } |
1753 } | 1795 } |
1754 } | 1796 // Sort the functions on the object pointer value to prepare for |
1755 active_functions.Sort(); | 1797 // the binary search below. |
| 1798 active_functions.Sort(HandleObjectPointerCompare<JSFunction>); |
1756 | 1799 |
1757 // Scan the heap for all non-optimized functions which has no | 1800 // Scan the heap for all non-optimized functions which has no |
1758 // debug break slots. | 1801 // debug break slots. |
1759 HeapIterator iterator; | 1802 HeapIterator iterator; |
1760 HeapObject* obj = NULL; | 1803 HeapObject* obj = NULL; |
1761 while (((obj = iterator.next()) != NULL)) { | 1804 while (((obj = iterator.next()) != NULL)) { |
1762 if (obj->IsJSFunction()) { | 1805 if (obj->IsJSFunction()) { |
1763 JSFunction* function = JSFunction::cast(obj); | 1806 JSFunction* function = JSFunction::cast(obj); |
1764 if (function->shared()->allows_lazy_compilation() && | 1807 if (function->shared()->allows_lazy_compilation() && |
1765 function->shared()->script()->IsScript() && | 1808 function->shared()->script()->IsScript() && |
1766 function->code()->kind() == Code::FUNCTION && | 1809 function->code()->kind() == Code::FUNCTION && |
1767 !function->code()->has_debug_break_slots()) { | 1810 !function->code()->has_debug_break_slots()) { |
1768 bool has_activation = | 1811 bool has_activation = |
1769 SortedListBSearch<JSFunction*>(active_functions, function) != -1; | 1812 SortedListBSearch<Handle<JSFunction> >( |
1770 if (!has_activation) { | 1813 active_functions, |
1771 function->set_code(lazy_compile); | 1814 Handle<JSFunction>(function), |
1772 function->shared()->set_code(lazy_compile); | 1815 HandleObjectPointerCompare<JSFunction>) != -1; |
| 1816 if (!has_activation) { |
| 1817 function->set_code(*lazy_compile); |
| 1818 function->shared()->set_code(*lazy_compile); |
| 1819 } |
1773 } | 1820 } |
1774 } | 1821 } |
1775 } | 1822 } |
1776 } | 1823 } |
| 1824 |
| 1825 // Now the non-GC scope is left, and the sorting of the functions |
| 1826 // in active_function is not ensured any more. The code below does |
| 1827 // not rely on it. |
| 1828 |
| 1829 // Now recompile all functions with activation frames and and |
| 1830 // patch the return address to run in the new compiled code. |
| 1831 for (int i = 0; i < active_functions.length(); i++) { |
| 1832 Handle<JSFunction> function = active_functions[i]; |
| 1833 Handle<SharedFunctionInfo> shared(function->shared()); |
| 1834 // If recompilation is not possible just skip it. |
| 1835 if (shared->is_toplevel() || |
| 1836 !shared->allows_lazy_compilation() || |
| 1837 shared->code()->kind() == Code::BUILTIN) { |
| 1838 continue; |
| 1839 } |
| 1840 |
| 1841 // Make sure that the shared full code is compiled with debug |
| 1842 // break slots. |
| 1843 Handle<Code> current_code(function->code()); |
| 1844 if (shared->code()->has_debug_break_slots()) { |
| 1845 // if the code is already recompiled to have break slots skip |
| 1846 // recompilation. |
| 1847 ASSERT(!function->code()->has_debug_break_slots()); |
| 1848 } else { |
| 1849 // Try to compile the full code with debug break slots. If it |
| 1850 // fails just keep the current code. |
| 1851 ASSERT(shared->code() == *current_code); |
| 1852 ZoneScope zone_scope(isolate_, DELETE_ON_EXIT); |
| 1853 shared->set_code(*lazy_compile); |
| 1854 bool prev_force_debugger_active = |
| 1855 isolate_->debugger()->force_debugger_active(); |
| 1856 isolate_->debugger()->set_force_debugger_active(true); |
| 1857 CompileFullCodeForDebugging(shared, current_code); |
| 1858 isolate_->debugger()->set_force_debugger_active( |
| 1859 prev_force_debugger_active); |
| 1860 if (!shared->is_compiled()) { |
| 1861 shared->set_code(*current_code); |
| 1862 continue; |
| 1863 } |
| 1864 } |
| 1865 Handle<Code> new_code(shared->code()); |
| 1866 |
| 1867 // Find the function and patch return address. |
| 1868 for (JavaScriptFrameIterator it(isolate_); !it.done(); it.Advance()) { |
| 1869 JavaScriptFrame* frame = it.frame(); |
| 1870 // If the current frame is for this function in its |
| 1871 // non-optimized form rewrite the return address to continue |
| 1872 // in the newly compiled full code with debug break slots. |
| 1873 if (frame->function()->IsJSFunction() && |
| 1874 frame->function() == *function && |
| 1875 frame->LookupCode()->kind() == Code::FUNCTION) { |
| 1876 int delta = frame->pc() - current_code->instruction_start(); |
| 1877 int debug_break_slot_count = 0; |
| 1878 int mask = RelocInfo::ModeMask(RelocInfo::DEBUG_BREAK_SLOT); |
| 1879 for (RelocIterator it(*new_code, mask); !it.done(); it.next()) { |
| 1880 // Check if the pc in the new code with debug break |
| 1881 // slots is before this slot. |
| 1882 RelocInfo* info = it.rinfo(); |
| 1883 int debug_break_slot_bytes = |
| 1884 debug_break_slot_count * Assembler::kDebugBreakSlotLength; |
| 1885 int new_delta = |
| 1886 info->pc() - |
| 1887 new_code->instruction_start() - |
| 1888 debug_break_slot_bytes; |
| 1889 if (new_delta > delta) { |
| 1890 break; |
| 1891 } |
| 1892 |
| 1893 // Passed a debug break slot in the full code with debug |
| 1894 // break slots. |
| 1895 debug_break_slot_count++; |
| 1896 } |
| 1897 int debug_break_slot_bytes = |
| 1898 debug_break_slot_count * Assembler::kDebugBreakSlotLength; |
| 1899 if (FLAG_trace_deopt) { |
| 1900 PrintF("Replacing code %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) " |
| 1901 "with %08" V8PRIxPTR " - %08" V8PRIxPTR " (%d) " |
| 1902 "for debugging, " |
| 1903 "changing pc from %08" V8PRIxPTR " to %08" V8PRIxPTR "\n", |
| 1904 reinterpret_cast<intptr_t>( |
| 1905 current_code->instruction_start()), |
| 1906 reinterpret_cast<intptr_t>( |
| 1907 current_code->instruction_start()) + |
| 1908 current_code->instruction_size(), |
| 1909 current_code->instruction_size(), |
| 1910 reinterpret_cast<intptr_t>(new_code->instruction_start()), |
| 1911 reinterpret_cast<intptr_t>(new_code->instruction_start()) + |
| 1912 new_code->instruction_size(), |
| 1913 new_code->instruction_size(), |
| 1914 reinterpret_cast<intptr_t>(frame->pc()), |
| 1915 reinterpret_cast<intptr_t>(new_code->instruction_start()) + |
| 1916 delta + debug_break_slot_bytes); |
| 1917 } |
| 1918 |
| 1919 // Patch the return address to return into the code with |
| 1920 // debug break slots. |
| 1921 frame->set_pc( |
| 1922 new_code->instruction_start() + delta + debug_break_slot_bytes); |
| 1923 } |
| 1924 } |
| 1925 } |
1777 } | 1926 } |
1778 } | 1927 } |
1779 | 1928 |
1780 | 1929 |
1781 // Ensures the debug information is present for shared. | 1930 // Ensures the debug information is present for shared. |
1782 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) { | 1931 bool Debug::EnsureDebugInfo(Handle<SharedFunctionInfo> shared) { |
1783 // Return if we already have the debug info for shared. | 1932 // Return if we already have the debug info for shared. |
1784 if (HasDebugInfo(shared)) { | 1933 if (HasDebugInfo(shared)) { |
1785 ASSERT(shared->is_compiled()); | 1934 ASSERT(shared->is_compiled()); |
1786 return true; | 1935 return true; |
(...skipping 1047 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2834 // Set the debug command break flag to have the command processed. | 2983 // Set the debug command break flag to have the command processed. |
2835 if (!isolate_->debug()->InDebugger()) { | 2984 if (!isolate_->debug()->InDebugger()) { |
2836 isolate_->stack_guard()->DebugCommand(); | 2985 isolate_->stack_guard()->DebugCommand(); |
2837 } | 2986 } |
2838 } | 2987 } |
2839 | 2988 |
2840 | 2989 |
2841 bool Debugger::IsDebuggerActive() { | 2990 bool Debugger::IsDebuggerActive() { |
2842 ScopedLock with(debugger_access_); | 2991 ScopedLock with(debugger_access_); |
2843 | 2992 |
2844 return message_handler_ != NULL || !event_listener_.is_null(); | 2993 return message_handler_ != NULL || |
| 2994 !event_listener_.is_null() || |
| 2995 force_debugger_active_; |
2845 } | 2996 } |
2846 | 2997 |
2847 | 2998 |
2848 Handle<Object> Debugger::Call(Handle<JSFunction> fun, | 2999 Handle<Object> Debugger::Call(Handle<JSFunction> fun, |
2849 Handle<Object> data, | 3000 Handle<Object> data, |
2850 bool* pending_exception) { | 3001 bool* pending_exception) { |
2851 // When calling functions in the debugger prevent it from beeing unloaded. | 3002 // When calling functions in the debugger prevent it from beeing unloaded. |
2852 Debugger::never_unload_debugger_ = true; | 3003 Debugger::never_unload_debugger_ = true; |
2853 | 3004 |
2854 // Enter the debugger. | 3005 // Enter the debugger. |
(...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3232 { | 3383 { |
3233 Locker locker; | 3384 Locker locker; |
3234 Isolate::Current()->debugger()->CallMessageDispatchHandler(); | 3385 Isolate::Current()->debugger()->CallMessageDispatchHandler(); |
3235 } | 3386 } |
3236 } | 3387 } |
3237 } | 3388 } |
3238 | 3389 |
3239 #endif // ENABLE_DEBUGGER_SUPPORT | 3390 #endif // ENABLE_DEBUGGER_SUPPORT |
3240 | 3391 |
3241 } } // namespace v8::internal | 3392 } } // namespace v8::internal |
OLD | NEW |