OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/debug/liveedit.h" | 5 #include "src/debug/liveedit.h" |
6 | 6 |
7 #include "src/ast/scopeinfo.h" | 7 #include "src/ast/scopeinfo.h" |
8 #include "src/ast/scopes.h" | 8 #include "src/ast/scopes.h" |
9 #include "src/code-stubs.h" | 9 #include "src/code-stubs.h" |
10 #include "src/compilation-cache.h" | 10 #include "src/compilation-cache.h" |
(...skipping 1642 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1653 } | 1653 } |
1654 | 1654 |
1655 return NULL; | 1655 return NULL; |
1656 } | 1656 } |
1657 | 1657 |
1658 | 1658 |
1659 // Describes a set of call frames that execute any of listed functions. | 1659 // Describes a set of call frames that execute any of listed functions. |
1660 // Finding no such frames does not mean error. | 1660 // Finding no such frames does not mean error. |
1661 class MultipleFunctionTarget { | 1661 class MultipleFunctionTarget { |
1662 public: | 1662 public: |
1663 MultipleFunctionTarget(Handle<JSArray> shared_info_array, | 1663 MultipleFunctionTarget(Handle<JSArray> old_shared_array, |
1664 Handle<JSArray> result) | 1664 Handle<JSArray> new_shared_array, |
1665 : m_shared_info_array(shared_info_array), | 1665 Handle<JSArray> result) |
1666 m_result(result) {} | 1666 : old_shared_array_(old_shared_array), |
| 1667 new_shared_array_(new_shared_array), |
| 1668 result_(result) {} |
1667 bool MatchActivation(StackFrame* frame, | 1669 bool MatchActivation(StackFrame* frame, |
1668 LiveEdit::FunctionPatchabilityStatus status) { | 1670 LiveEdit::FunctionPatchabilityStatus status) { |
1669 return CheckActivation(m_shared_info_array, m_result, frame, status); | 1671 return CheckActivation(old_shared_array_, result_, frame, status); |
1670 } | 1672 } |
1671 const char* GetNotFoundMessage() const { | 1673 const char* GetNotFoundMessage() const { |
1672 return NULL; | 1674 return NULL; |
1673 } | 1675 } |
| 1676 bool FrameUsesNewTarget(StackFrame* frame) { |
| 1677 if (!frame->is_java_script()) return false; |
| 1678 JavaScriptFrame* jsframe = JavaScriptFrame::cast(frame); |
| 1679 Handle<SharedFunctionInfo> old_shared(jsframe->function()->shared()); |
| 1680 Isolate* isolate = old_shared->GetIsolate(); |
| 1681 int len = GetArrayLength(old_shared_array_); |
| 1682 // Find corresponding new shared function info and return whether it |
| 1683 // references new.target. |
| 1684 for (int i = 0; i < len; i++) { |
| 1685 HandleScope scope(isolate); |
| 1686 Handle<Object> old_element = |
| 1687 Object::GetElement(isolate, old_shared_array_, i).ToHandleChecked(); |
| 1688 if (!old_shared.is_identical_to(UnwrapSharedFunctionInfoFromJSValue( |
| 1689 Handle<JSValue>::cast(old_element)))) { |
| 1690 continue; |
| 1691 } |
| 1692 |
| 1693 Handle<Object> new_element = |
| 1694 Object::GetElement(isolate, new_shared_array_, i).ToHandleChecked(); |
| 1695 if (new_element->IsUndefined()) return false; |
| 1696 Handle<SharedFunctionInfo> new_shared = |
| 1697 UnwrapSharedFunctionInfoFromJSValue( |
| 1698 Handle<JSValue>::cast(new_element)); |
| 1699 if (new_shared->scope_info()->HasNewTarget()) { |
| 1700 SetElementSloppy( |
| 1701 result_, i, |
| 1702 Handle<Smi>( |
| 1703 Smi::FromInt( |
| 1704 LiveEdit::FUNCTION_BLOCKED_NO_NEW_TARGET_ON_RESTART), |
| 1705 isolate)); |
| 1706 return true; |
| 1707 } |
| 1708 return false; |
| 1709 } |
| 1710 return false; |
| 1711 } |
| 1712 |
1674 private: | 1713 private: |
1675 Handle<JSArray> m_shared_info_array; | 1714 Handle<JSArray> old_shared_array_; |
1676 Handle<JSArray> m_result; | 1715 Handle<JSArray> new_shared_array_; |
| 1716 Handle<JSArray> result_; |
1677 }; | 1717 }; |
1678 | 1718 |
1679 | 1719 |
1680 // Drops all call frame matched by target and all frames above them. | 1720 // Drops all call frame matched by target and all frames above them. |
1681 template <typename TARGET> | 1721 template <typename TARGET> |
1682 static const char* DropActivationsInActiveThreadImpl(Isolate* isolate, | 1722 static const char* DropActivationsInActiveThreadImpl(Isolate* isolate, |
1683 TARGET& target, // NOLINT | 1723 TARGET& target, // NOLINT |
1684 bool do_drop) { | 1724 bool do_drop) { |
1685 Debug* debug = isolate->debug(); | 1725 Debug* debug = isolate->debug(); |
1686 Zone zone; | 1726 Zone zone; |
(...skipping 26 matching lines...) Expand all Loading... |
1713 bool non_droppable_frame_found = false; | 1753 bool non_droppable_frame_found = false; |
1714 LiveEdit::FunctionPatchabilityStatus non_droppable_reason; | 1754 LiveEdit::FunctionPatchabilityStatus non_droppable_reason; |
1715 | 1755 |
1716 for (; frame_index < frames.length(); frame_index++) { | 1756 for (; frame_index < frames.length(); frame_index++) { |
1717 StackFrame* frame = frames[frame_index]; | 1757 StackFrame* frame = frames[frame_index]; |
1718 if (frame->is_exit()) { | 1758 if (frame->is_exit()) { |
1719 non_droppable_frame_found = true; | 1759 non_droppable_frame_found = true; |
1720 non_droppable_reason = LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE; | 1760 non_droppable_reason = LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE; |
1721 break; | 1761 break; |
1722 } | 1762 } |
1723 if (frame->is_java_script() && | 1763 if (frame->is_java_script()) { |
1724 JavaScriptFrame::cast(frame)->function()->shared()->is_generator()) { | 1764 SharedFunctionInfo* shared = |
1725 non_droppable_frame_found = true; | 1765 JavaScriptFrame::cast(frame)->function()->shared(); |
1726 non_droppable_reason = LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR; | 1766 if (shared->is_generator()) { |
1727 break; | 1767 non_droppable_frame_found = true; |
| 1768 non_droppable_reason = LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR; |
| 1769 break; |
| 1770 } |
1728 } | 1771 } |
1729 if (target.MatchActivation( | 1772 if (target.MatchActivation( |
1730 frame, LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) { | 1773 frame, LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) { |
1731 target_frame_found = true; | 1774 target_frame_found = true; |
1732 bottom_js_frame_index = frame_index; | 1775 bottom_js_frame_index = frame_index; |
1733 } | 1776 } |
1734 } | 1777 } |
1735 | 1778 |
1736 if (non_droppable_frame_found) { | 1779 if (non_droppable_frame_found) { |
1737 // There is a C or generator frame on stack. We can't drop C frames, and we | 1780 // There is a C or generator frame on stack. We can't drop C frames, and we |
1738 // can't restart generators. Check that there are no target frames below | 1781 // can't restart generators. Check that there are no target frames below |
1739 // them. | 1782 // them. |
1740 for (; frame_index < frames.length(); frame_index++) { | 1783 for (; frame_index < frames.length(); frame_index++) { |
1741 StackFrame* frame = frames[frame_index]; | 1784 StackFrame* frame = frames[frame_index]; |
1742 if (frame->is_java_script()) { | 1785 if (frame->is_java_script()) { |
1743 if (target.MatchActivation(frame, non_droppable_reason)) { | 1786 if (target.MatchActivation(frame, non_droppable_reason)) { |
1744 // Fail. | 1787 // Fail. |
1745 return NULL; | 1788 return NULL; |
1746 } | 1789 } |
1747 } | 1790 } |
1748 } | 1791 } |
1749 } | 1792 } |
1750 | 1793 |
| 1794 // We cannot restart a frame that uses new.target. |
| 1795 if (target.FrameUsesNewTarget(frames[bottom_js_frame_index])) return NULL; |
| 1796 |
1751 if (!do_drop) { | 1797 if (!do_drop) { |
1752 // We are in check-only mode. | 1798 // We are in check-only mode. |
1753 return NULL; | 1799 return NULL; |
1754 } | 1800 } |
1755 | 1801 |
1756 if (!target_frame_found) { | 1802 if (!target_frame_found) { |
1757 // Nothing to drop. | 1803 // Nothing to drop. |
1758 return target.GetNotFoundMessage(); | 1804 return target.GetNotFoundMessage(); |
1759 } | 1805 } |
1760 | 1806 |
(...skipping 17 matching lines...) Expand all Loading... |
1778 } | 1824 } |
1779 debug->FramesHaveBeenDropped( | 1825 debug->FramesHaveBeenDropped( |
1780 new_id, drop_mode, restarter_frame_function_pointer); | 1826 new_id, drop_mode, restarter_frame_function_pointer); |
1781 return NULL; | 1827 return NULL; |
1782 } | 1828 } |
1783 | 1829 |
1784 | 1830 |
1785 // Fills result array with statuses of functions. Modifies the stack | 1831 // Fills result array with statuses of functions. Modifies the stack |
1786 // removing all listed function if possible and if do_drop is true. | 1832 // removing all listed function if possible and if do_drop is true. |
1787 static const char* DropActivationsInActiveThread( | 1833 static const char* DropActivationsInActiveThread( |
1788 Handle<JSArray> shared_info_array, Handle<JSArray> result, bool do_drop) { | 1834 Handle<JSArray> old_shared_array, Handle<JSArray> new_shared_array, |
1789 MultipleFunctionTarget target(shared_info_array, result); | 1835 Handle<JSArray> result, bool do_drop) { |
1790 Isolate* isolate = shared_info_array->GetIsolate(); | 1836 MultipleFunctionTarget target(old_shared_array, new_shared_array, result); |
| 1837 Isolate* isolate = old_shared_array->GetIsolate(); |
1791 | 1838 |
1792 const char* message = | 1839 const char* message = |
1793 DropActivationsInActiveThreadImpl(isolate, target, do_drop); | 1840 DropActivationsInActiveThreadImpl(isolate, target, do_drop); |
1794 if (message) { | 1841 if (message) { |
1795 return message; | 1842 return message; |
1796 } | 1843 } |
1797 | 1844 |
1798 int array_len = GetArrayLength(shared_info_array); | 1845 int array_len = GetArrayLength(old_shared_array); |
1799 | 1846 |
1800 // Replace "blocked on active" with "replaced on active" status. | 1847 // Replace "blocked on active" with "replaced on active" status. |
1801 for (int i = 0; i < array_len; i++) { | 1848 for (int i = 0; i < array_len; i++) { |
1802 Handle<Object> obj = | 1849 Handle<Object> obj = |
1803 Object::GetElement(isolate, result, i).ToHandleChecked(); | 1850 Object::GetElement(isolate, result, i).ToHandleChecked(); |
1804 if (*obj == Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) { | 1851 if (*obj == Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) { |
1805 Handle<Object> replaced( | 1852 Handle<Object> replaced( |
1806 Smi::FromInt(LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK), isolate); | 1853 Smi::FromInt(LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK), isolate); |
1807 SetElementSloppy(result, i, replaced); | 1854 SetElementSloppy(result, i, replaced); |
1808 } | 1855 } |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1844 } | 1891 } |
1845 } | 1892 } |
1846 } | 1893 } |
1847 | 1894 |
1848 return found_suspended_activations; | 1895 return found_suspended_activations; |
1849 } | 1896 } |
1850 | 1897 |
1851 | 1898 |
1852 class InactiveThreadActivationsChecker : public ThreadVisitor { | 1899 class InactiveThreadActivationsChecker : public ThreadVisitor { |
1853 public: | 1900 public: |
1854 InactiveThreadActivationsChecker(Handle<JSArray> shared_info_array, | 1901 InactiveThreadActivationsChecker(Handle<JSArray> old_shared_array, |
1855 Handle<JSArray> result) | 1902 Handle<JSArray> result) |
1856 : shared_info_array_(shared_info_array), result_(result), | 1903 : old_shared_array_(old_shared_array), |
1857 has_blocked_functions_(false) { | 1904 result_(result), |
1858 } | 1905 has_blocked_functions_(false) {} |
1859 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { | 1906 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { |
1860 for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) { | 1907 for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) { |
1861 has_blocked_functions_ |= CheckActivation( | 1908 has_blocked_functions_ |= |
1862 shared_info_array_, result_, it.frame(), | 1909 CheckActivation(old_shared_array_, result_, it.frame(), |
1863 LiveEdit::FUNCTION_BLOCKED_ON_OTHER_STACK); | 1910 LiveEdit::FUNCTION_BLOCKED_ON_OTHER_STACK); |
1864 } | 1911 } |
1865 } | 1912 } |
1866 bool HasBlockedFunctions() { | 1913 bool HasBlockedFunctions() { |
1867 return has_blocked_functions_; | 1914 return has_blocked_functions_; |
1868 } | 1915 } |
1869 | 1916 |
1870 private: | 1917 private: |
1871 Handle<JSArray> shared_info_array_; | 1918 Handle<JSArray> old_shared_array_; |
1872 Handle<JSArray> result_; | 1919 Handle<JSArray> result_; |
1873 bool has_blocked_functions_; | 1920 bool has_blocked_functions_; |
1874 }; | 1921 }; |
1875 | 1922 |
1876 | 1923 |
1877 Handle<JSArray> LiveEdit::CheckAndDropActivations( | 1924 Handle<JSArray> LiveEdit::CheckAndDropActivations( |
1878 Handle<JSArray> shared_info_array, bool do_drop) { | 1925 Handle<JSArray> old_shared_array, Handle<JSArray> new_shared_array, |
1879 Isolate* isolate = shared_info_array->GetIsolate(); | 1926 bool do_drop) { |
1880 int len = GetArrayLength(shared_info_array); | 1927 Isolate* isolate = old_shared_array->GetIsolate(); |
| 1928 int len = GetArrayLength(old_shared_array); |
1881 | 1929 |
1882 DCHECK(shared_info_array->HasFastElements()); | 1930 DCHECK(old_shared_array->HasFastElements()); |
1883 Handle<FixedArray> shared_info_array_elements( | 1931 Handle<FixedArray> old_shared_array_elements( |
1884 FixedArray::cast(shared_info_array->elements())); | 1932 FixedArray::cast(old_shared_array->elements())); |
1885 | 1933 |
1886 Handle<JSArray> result = isolate->factory()->NewJSArray(len); | 1934 Handle<JSArray> result = isolate->factory()->NewJSArray(len); |
1887 Handle<FixedArray> result_elements = | 1935 Handle<FixedArray> result_elements = |
1888 JSObject::EnsureWritableFastElements(result); | 1936 JSObject::EnsureWritableFastElements(result); |
1889 | 1937 |
1890 // Fill the default values. | 1938 // Fill the default values. |
1891 for (int i = 0; i < len; i++) { | 1939 for (int i = 0; i < len; i++) { |
1892 FunctionPatchabilityStatus status = FUNCTION_AVAILABLE_FOR_PATCH; | 1940 FunctionPatchabilityStatus status = FUNCTION_AVAILABLE_FOR_PATCH; |
1893 result_elements->set(i, Smi::FromInt(status)); | 1941 result_elements->set(i, Smi::FromInt(status)); |
1894 } | 1942 } |
1895 | 1943 |
1896 // Scan the heap for active generators -- those that are either currently | 1944 // Scan the heap for active generators -- those that are either currently |
1897 // running (as we wouldn't want to restart them, because we don't know where | 1945 // running (as we wouldn't want to restart them, because we don't know where |
1898 // to restart them from) or suspended. Fail if any one corresponds to the set | 1946 // to restart them from) or suspended. Fail if any one corresponds to the set |
1899 // of functions being edited. | 1947 // of functions being edited. |
1900 if (FindActiveGenerators(shared_info_array_elements, result_elements, len)) { | 1948 if (FindActiveGenerators(old_shared_array_elements, result_elements, len)) { |
1901 return result; | 1949 return result; |
1902 } | 1950 } |
1903 | 1951 |
1904 // Check inactive threads. Fail if some functions are blocked there. | 1952 // Check inactive threads. Fail if some functions are blocked there. |
1905 InactiveThreadActivationsChecker inactive_threads_checker(shared_info_array, | 1953 InactiveThreadActivationsChecker inactive_threads_checker(old_shared_array, |
1906 result); | 1954 result); |
1907 isolate->thread_manager()->IterateArchivedThreads( | 1955 isolate->thread_manager()->IterateArchivedThreads( |
1908 &inactive_threads_checker); | 1956 &inactive_threads_checker); |
1909 if (inactive_threads_checker.HasBlockedFunctions()) { | 1957 if (inactive_threads_checker.HasBlockedFunctions()) { |
1910 return result; | 1958 return result; |
1911 } | 1959 } |
1912 | 1960 |
1913 // Try to drop activations from the current stack. | 1961 // Try to drop activations from the current stack. |
1914 const char* error_message = | 1962 const char* error_message = DropActivationsInActiveThread( |
1915 DropActivationsInActiveThread(shared_info_array, result, do_drop); | 1963 old_shared_array, new_shared_array, result, do_drop); |
1916 if (error_message != NULL) { | 1964 if (error_message != NULL) { |
1917 // Add error message as an array extra element. | 1965 // Add error message as an array extra element. |
1918 Handle<String> str = | 1966 Handle<String> str = |
1919 isolate->factory()->NewStringFromAsciiChecked(error_message); | 1967 isolate->factory()->NewStringFromAsciiChecked(error_message); |
1920 SetElementSloppy(result, len, str); | 1968 SetElementSloppy(result, len, str); |
1921 } | 1969 } |
1922 return result; | 1970 return result; |
1923 } | 1971 } |
1924 | 1972 |
1925 | 1973 |
(...skipping 12 matching lines...) Expand all Loading... |
1938 return true; | 1986 return true; |
1939 } | 1987 } |
1940 return false; | 1988 return false; |
1941 } | 1989 } |
1942 const char* GetNotFoundMessage() const { | 1990 const char* GetNotFoundMessage() const { |
1943 return "Failed to found requested frame"; | 1991 return "Failed to found requested frame"; |
1944 } | 1992 } |
1945 LiveEdit::FunctionPatchabilityStatus saved_status() { | 1993 LiveEdit::FunctionPatchabilityStatus saved_status() { |
1946 return m_saved_status; | 1994 return m_saved_status; |
1947 } | 1995 } |
| 1996 void set_status(LiveEdit::FunctionPatchabilityStatus status) { |
| 1997 m_saved_status = status; |
| 1998 } |
| 1999 |
| 2000 bool FrameUsesNewTarget(StackFrame* frame) { |
| 2001 if (!frame->is_java_script()) return false; |
| 2002 JavaScriptFrame* jsframe = JavaScriptFrame::cast(frame); |
| 2003 Handle<SharedFunctionInfo> shared(jsframe->function()->shared()); |
| 2004 return shared->scope_info()->HasNewTarget(); |
| 2005 } |
| 2006 |
1948 private: | 2007 private: |
1949 JavaScriptFrame* m_frame; | 2008 JavaScriptFrame* m_frame; |
1950 LiveEdit::FunctionPatchabilityStatus m_saved_status; | 2009 LiveEdit::FunctionPatchabilityStatus m_saved_status; |
1951 }; | 2010 }; |
1952 | 2011 |
1953 | 2012 |
1954 // Finds a drops required frame and all frames above. | 2013 // Finds a drops required frame and all frames above. |
1955 // Returns error message or NULL. | 2014 // Returns error message or NULL. |
1956 const char* LiveEdit::RestartFrame(JavaScriptFrame* frame) { | 2015 const char* LiveEdit::RestartFrame(JavaScriptFrame* frame) { |
1957 SingleFrameTarget target(frame); | 2016 SingleFrameTarget target(frame); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2001 isolate_->active_function_info_listener()->FunctionCode(code); | 2060 isolate_->active_function_info_listener()->FunctionCode(code); |
2002 } | 2061 } |
2003 | 2062 |
2004 | 2063 |
2005 bool LiveEditFunctionTracker::IsActive(Isolate* isolate) { | 2064 bool LiveEditFunctionTracker::IsActive(Isolate* isolate) { |
2006 return isolate->active_function_info_listener() != NULL; | 2065 return isolate->active_function_info_listener() != NULL; |
2007 } | 2066 } |
2008 | 2067 |
2009 } // namespace internal | 2068 } // namespace internal |
2010 } // namespace v8 | 2069 } // namespace v8 |
OLD | NEW |