| 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 |