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 | 5 |
6 #include "v8.h" | 6 #include "v8.h" |
7 | 7 |
8 #include "liveedit.h" | 8 #include "liveedit.h" |
9 | 9 |
10 #include "code-stubs.h" | 10 #include "code-stubs.h" |
(...skipping 1664 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1675 for (Address a = unused_stack_top; | 1675 for (Address a = unused_stack_top; |
1676 a < unused_stack_bottom; | 1676 a < unused_stack_bottom; |
1677 a += kPointerSize) { | 1677 a += kPointerSize) { |
1678 Memory::Object_at(a) = Smi::FromInt(0); | 1678 Memory::Object_at(a) = Smi::FromInt(0); |
1679 } | 1679 } |
1680 | 1680 |
1681 return NULL; | 1681 return NULL; |
1682 } | 1682 } |
1683 | 1683 |
1684 | 1684 |
1685 static bool IsDropableFrame(StackFrame* frame) { | |
1686 return !frame->is_exit(); | |
1687 } | |
1688 | |
1689 | |
1690 // Describes a set of call frames that execute any of listed functions. | 1685 // Describes a set of call frames that execute any of listed functions. |
1691 // Finding no such frames does not mean error. | 1686 // Finding no such frames does not mean error. |
1692 class MultipleFunctionTarget { | 1687 class MultipleFunctionTarget { |
1693 public: | 1688 public: |
1694 MultipleFunctionTarget(Handle<JSArray> shared_info_array, | 1689 MultipleFunctionTarget(Handle<JSArray> shared_info_array, |
1695 Handle<JSArray> result) | 1690 Handle<JSArray> result) |
1696 : m_shared_info_array(shared_info_array), | 1691 : m_shared_info_array(shared_info_array), |
1697 m_result(result) {} | 1692 m_result(result) {} |
1698 bool MatchActivation(StackFrame* frame, | 1693 bool MatchActivation(StackFrame* frame, |
1699 LiveEdit::FunctionPatchabilityStatus status) { | 1694 LiveEdit::FunctionPatchabilityStatus status) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1733 } | 1728 } |
1734 } | 1729 } |
1735 | 1730 |
1736 if (top_frame_index == -1) { | 1731 if (top_frame_index == -1) { |
1737 // We haven't found break frame, but no function is blocking us anyway. | 1732 // We haven't found break frame, but no function is blocking us anyway. |
1738 return target.GetNotFoundMessage(); | 1733 return target.GetNotFoundMessage(); |
1739 } | 1734 } |
1740 | 1735 |
1741 bool target_frame_found = false; | 1736 bool target_frame_found = false; |
1742 int bottom_js_frame_index = top_frame_index; | 1737 int bottom_js_frame_index = top_frame_index; |
1743 bool c_code_found = false; | 1738 bool non_droppable_frame_found = false; |
| 1739 LiveEdit::FunctionPatchabilityStatus non_droppable_reason; |
1744 | 1740 |
1745 for (; frame_index < frames.length(); frame_index++) { | 1741 for (; frame_index < frames.length(); frame_index++) { |
1746 StackFrame* frame = frames[frame_index]; | 1742 StackFrame* frame = frames[frame_index]; |
1747 if (!IsDropableFrame(frame)) { | 1743 if (frame->is_exit()) { |
1748 c_code_found = true; | 1744 non_droppable_frame_found = true; |
| 1745 non_droppable_reason = LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE; |
| 1746 break; |
| 1747 } |
| 1748 if (frame->is_java_script() && |
| 1749 JavaScriptFrame::cast(frame)->function()->shared()->is_generator()) { |
| 1750 non_droppable_frame_found = true; |
| 1751 non_droppable_reason = LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR; |
1749 break; | 1752 break; |
1750 } | 1753 } |
1751 if (target.MatchActivation( | 1754 if (target.MatchActivation( |
1752 frame, LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) { | 1755 frame, LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) { |
1753 target_frame_found = true; | 1756 target_frame_found = true; |
1754 bottom_js_frame_index = frame_index; | 1757 bottom_js_frame_index = frame_index; |
1755 } | 1758 } |
1756 } | 1759 } |
1757 | 1760 |
1758 if (c_code_found) { | 1761 if (non_droppable_frame_found) { |
1759 // There is a C frames on stack. Check that there are no target frames | 1762 // There is a C or generator frame on stack. We can't drop C frames, and we |
1760 // below them. | 1763 // can't restart generators. Check that there are no target frames below |
| 1764 // them. |
1761 for (; frame_index < frames.length(); frame_index++) { | 1765 for (; frame_index < frames.length(); frame_index++) { |
1762 StackFrame* frame = frames[frame_index]; | 1766 StackFrame* frame = frames[frame_index]; |
1763 if (frame->is_java_script()) { | 1767 if (frame->is_java_script()) { |
1764 if (target.MatchActivation( | 1768 if (target.MatchActivation(frame, non_droppable_reason)) { |
1765 frame, LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE)) { | 1769 // Fail. |
1766 // Cannot drop frame under C frames. | |
1767 return NULL; | 1770 return NULL; |
1768 } | 1771 } |
1769 } | 1772 } |
1770 } | 1773 } |
1771 } | 1774 } |
1772 | 1775 |
1773 if (!do_drop) { | 1776 if (!do_drop) { |
1774 // We are in check-only mode. | 1777 // We are in check-only mode. |
1775 return NULL; | 1778 return NULL; |
1776 } | 1779 } |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1826 if (*obj == Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) { | 1829 if (*obj == Smi::FromInt(LiveEdit::FUNCTION_BLOCKED_ON_ACTIVE_STACK)) { |
1827 Handle<Object> replaced( | 1830 Handle<Object> replaced( |
1828 Smi::FromInt(LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK), isolate); | 1831 Smi::FromInt(LiveEdit::FUNCTION_REPLACED_ON_ACTIVE_STACK), isolate); |
1829 SetElementSloppy(result, i, replaced); | 1832 SetElementSloppy(result, i, replaced); |
1830 } | 1833 } |
1831 } | 1834 } |
1832 return NULL; | 1835 return NULL; |
1833 } | 1836 } |
1834 | 1837 |
1835 | 1838 |
| 1839 bool LiveEdit::FindActiveGenerators(Handle<FixedArray> shared_info_array, |
| 1840 Handle<FixedArray> result, |
| 1841 int len) { |
| 1842 Isolate* isolate = shared_info_array->GetIsolate(); |
| 1843 Heap* heap = isolate->heap(); |
| 1844 heap->EnsureHeapIsIterable(); |
| 1845 bool found_suspended_activations = false; |
| 1846 |
| 1847 ASSERT_LE(len, result->length()); |
| 1848 |
| 1849 DisallowHeapAllocation no_allocation; |
| 1850 |
| 1851 FunctionPatchabilityStatus active = FUNCTION_BLOCKED_ACTIVE_GENERATOR; |
| 1852 |
| 1853 HeapIterator iterator(heap); |
| 1854 HeapObject* obj = NULL; |
| 1855 while ((obj = iterator.next()) != NULL) { |
| 1856 if (!obj->IsJSGeneratorObject()) continue; |
| 1857 |
| 1858 JSGeneratorObject* gen = JSGeneratorObject::cast(obj); |
| 1859 if (gen->is_closed()) continue; |
| 1860 |
| 1861 HandleScope scope(isolate); |
| 1862 |
| 1863 for (int i = 0; i < len; i++) { |
| 1864 Handle<JSValue> jsvalue = |
| 1865 Handle<JSValue>::cast(FixedArray::get(shared_info_array, i)); |
| 1866 Handle<SharedFunctionInfo> shared = |
| 1867 UnwrapSharedFunctionInfoFromJSValue(jsvalue); |
| 1868 |
| 1869 if (gen->function()->shared() == *shared) { |
| 1870 result->set(i, Smi::FromInt(active)); |
| 1871 found_suspended_activations = true; |
| 1872 } |
| 1873 } |
| 1874 } |
| 1875 |
| 1876 return found_suspended_activations; |
| 1877 } |
| 1878 |
| 1879 |
1836 class InactiveThreadActivationsChecker : public ThreadVisitor { | 1880 class InactiveThreadActivationsChecker : public ThreadVisitor { |
1837 public: | 1881 public: |
1838 InactiveThreadActivationsChecker(Handle<JSArray> shared_info_array, | 1882 InactiveThreadActivationsChecker(Handle<JSArray> shared_info_array, |
1839 Handle<JSArray> result) | 1883 Handle<JSArray> result) |
1840 : shared_info_array_(shared_info_array), result_(result), | 1884 : shared_info_array_(shared_info_array), result_(result), |
1841 has_blocked_functions_(false) { | 1885 has_blocked_functions_(false) { |
1842 } | 1886 } |
1843 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { | 1887 void VisitThread(Isolate* isolate, ThreadLocalTop* top) { |
1844 for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) { | 1888 for (StackFrameIterator it(isolate, top); !it.done(); it.Advance()) { |
1845 has_blocked_functions_ |= CheckActivation( | 1889 has_blocked_functions_ |= CheckActivation( |
(...skipping 10 matching lines...) Expand all Loading... |
1856 Handle<JSArray> result_; | 1900 Handle<JSArray> result_; |
1857 bool has_blocked_functions_; | 1901 bool has_blocked_functions_; |
1858 }; | 1902 }; |
1859 | 1903 |
1860 | 1904 |
1861 Handle<JSArray> LiveEdit::CheckAndDropActivations( | 1905 Handle<JSArray> LiveEdit::CheckAndDropActivations( |
1862 Handle<JSArray> shared_info_array, bool do_drop) { | 1906 Handle<JSArray> shared_info_array, bool do_drop) { |
1863 Isolate* isolate = shared_info_array->GetIsolate(); | 1907 Isolate* isolate = shared_info_array->GetIsolate(); |
1864 int len = GetArrayLength(shared_info_array); | 1908 int len = GetArrayLength(shared_info_array); |
1865 | 1909 |
| 1910 CHECK(shared_info_array->HasFastElements()); |
| 1911 Handle<FixedArray> shared_info_array_elements( |
| 1912 FixedArray::cast(shared_info_array->elements())); |
| 1913 |
1866 Handle<JSArray> result = isolate->factory()->NewJSArray(len); | 1914 Handle<JSArray> result = isolate->factory()->NewJSArray(len); |
| 1915 Handle<FixedArray> result_elements = |
| 1916 JSObject::EnsureWritableFastElements(result); |
1867 | 1917 |
1868 // Fill the default values. | 1918 // Fill the default values. |
1869 for (int i = 0; i < len; i++) { | 1919 for (int i = 0; i < len; i++) { |
1870 SetElementSloppy( | 1920 FunctionPatchabilityStatus status = FUNCTION_AVAILABLE_FOR_PATCH; |
1871 result, | 1921 result_elements->set(i, Smi::FromInt(status)); |
1872 i, | |
1873 Handle<Smi>(Smi::FromInt(FUNCTION_AVAILABLE_FOR_PATCH), isolate)); | |
1874 } | 1922 } |
1875 | 1923 |
| 1924 // Scan the heap for active generators -- those that are either currently |
| 1925 // running (as we wouldn't want to restart them, because we don't know where |
| 1926 // to restart them from) or suspended. Fail if any one corresponds to the set |
| 1927 // of functions being edited. |
| 1928 if (FindActiveGenerators(shared_info_array_elements, result_elements, len)) { |
| 1929 return result; |
| 1930 } |
1876 | 1931 |
1877 // First check inactive threads. Fail if some functions are blocked there. | 1932 // Check inactive threads. Fail if some functions are blocked there. |
1878 InactiveThreadActivationsChecker inactive_threads_checker(shared_info_array, | 1933 InactiveThreadActivationsChecker inactive_threads_checker(shared_info_array, |
1879 result); | 1934 result); |
1880 isolate->thread_manager()->IterateArchivedThreads( | 1935 isolate->thread_manager()->IterateArchivedThreads( |
1881 &inactive_threads_checker); | 1936 &inactive_threads_checker); |
1882 if (inactive_threads_checker.HasBlockedFunctions()) { | 1937 if (inactive_threads_checker.HasBlockedFunctions()) { |
1883 return result; | 1938 return result; |
1884 } | 1939 } |
1885 | 1940 |
1886 // Try to drop activations from the current stack. | 1941 // Try to drop activations from the current stack. |
1887 const char* error_message = | 1942 const char* error_message = |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1930 SingleFrameTarget target(frame); | 1985 SingleFrameTarget target(frame); |
1931 | 1986 |
1932 const char* result = DropActivationsInActiveThreadImpl( | 1987 const char* result = DropActivationsInActiveThreadImpl( |
1933 frame->isolate(), target, true); | 1988 frame->isolate(), target, true); |
1934 if (result != NULL) { | 1989 if (result != NULL) { |
1935 return result; | 1990 return result; |
1936 } | 1991 } |
1937 if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE) { | 1992 if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE) { |
1938 return "Function is blocked under native code"; | 1993 return "Function is blocked under native code"; |
1939 } | 1994 } |
| 1995 if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR) { |
| 1996 return "Function is blocked under a generator activation"; |
| 1997 } |
1940 return NULL; | 1998 return NULL; |
1941 } | 1999 } |
1942 | 2000 |
1943 | 2001 |
1944 LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate, | 2002 LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate, |
1945 FunctionLiteral* fun) | 2003 FunctionLiteral* fun) |
1946 : isolate_(isolate) { | 2004 : isolate_(isolate) { |
1947 if (isolate_->active_function_info_listener() != NULL) { | 2005 if (isolate_->active_function_info_listener() != NULL) { |
1948 isolate_->active_function_info_listener()->FunctionStarted(fun); | 2006 isolate_->active_function_info_listener()->FunctionStarted(fun); |
1949 } | 2007 } |
(...skipping 20 matching lines...) Expand all Loading... |
1970 void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) { | 2028 void LiveEditFunctionTracker::RecordRootFunctionInfo(Handle<Code> code) { |
1971 isolate_->active_function_info_listener()->FunctionCode(code); | 2029 isolate_->active_function_info_listener()->FunctionCode(code); |
1972 } | 2030 } |
1973 | 2031 |
1974 | 2032 |
1975 bool LiveEditFunctionTracker::IsActive(Isolate* isolate) { | 2033 bool LiveEditFunctionTracker::IsActive(Isolate* isolate) { |
1976 return isolate->active_function_info_listener() != NULL; | 2034 return isolate->active_function_info_listener() != NULL; |
1977 } | 2035 } |
1978 | 2036 |
1979 } } // namespace v8::internal | 2037 } } // namespace v8::internal |
OLD | NEW |