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