Chromium Code Reviews| 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 670 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 681 } | 681 } |
| 682 | 682 |
| 683 | 683 |
| 684 Handle<SharedFunctionInfo> SharedInfoWrapper::GetInfo() { | 684 Handle<SharedFunctionInfo> SharedInfoWrapper::GetInfo() { |
| 685 Handle<Object> element = this->GetField(kSharedInfoOffset_); | 685 Handle<Object> element = this->GetField(kSharedInfoOffset_); |
| 686 Handle<JSValue> value_wrapper = Handle<JSValue>::cast(element); | 686 Handle<JSValue> value_wrapper = Handle<JSValue>::cast(element); |
| 687 return UnwrapSharedFunctionInfoFromJSValue(value_wrapper); | 687 return UnwrapSharedFunctionInfoFromJSValue(value_wrapper); |
| 688 } | 688 } |
| 689 | 689 |
| 690 | 690 |
| 691 class FunctionInfoListener { | |
| 692 public: | |
| 693 explicit FunctionInfoListener(Isolate* isolate) { | |
| 694 current_parent_index_ = -1; | |
| 695 len_ = 0; | |
| 696 result_ = isolate->factory()->NewJSArray(10); | |
| 697 } | |
| 698 | |
| 699 void FunctionStarted(FunctionLiteral* fun) { | |
| 700 HandleScope scope(isolate()); | |
| 701 FunctionInfoWrapper info = FunctionInfoWrapper::Create(isolate()); | |
| 702 info.SetInitialProperties(fun->name(), fun->start_position(), | |
| 703 fun->end_position(), fun->parameter_count(), | |
| 704 fun->materialized_literal_count(), | |
| 705 current_parent_index_); | |
| 706 current_parent_index_ = len_; | |
| 707 SetElementSloppy(result_, len_, info.GetJSArray()); | |
| 708 len_++; | |
| 709 } | |
| 710 | |
| 711 void FunctionDone() { | |
| 712 HandleScope scope(isolate()); | |
| 713 FunctionInfoWrapper info = FunctionInfoWrapper::cast( | |
| 714 *JSReceiver::GetElement(isolate(), result_, current_parent_index_) | |
| 715 .ToHandleChecked()); | |
| 716 current_parent_index_ = info.GetParentIndex(); | |
| 717 } | |
| 718 | |
| 719 // Saves full information about a function: its code, its scope info | |
| 720 // and a SharedFunctionInfo object. | |
| 721 void FunctionInfo(Handle<SharedFunctionInfo> shared, Scope* scope, | |
| 722 Zone* zone) { | |
| 723 if (!shared->IsSharedFunctionInfo()) { | |
| 724 return; | |
| 725 } | |
| 726 FunctionInfoWrapper info = FunctionInfoWrapper::cast( | |
| 727 *JSReceiver::GetElement(isolate(), result_, current_parent_index_) | |
| 728 .ToHandleChecked()); | |
| 729 info.SetFunctionCode(Handle<Code>(shared->code()), | |
| 730 Handle<HeapObject>(shared->scope_info())); | |
| 731 info.SetSharedFunctionInfo(shared); | |
| 732 | |
| 733 Handle<Object> scope_info_list = SerializeFunctionScope(scope, zone); | |
| 734 info.SetFunctionScopeInfo(scope_info_list); | |
| 735 } | |
| 736 | |
| 737 Handle<JSArray> GetResult() { return result_; } | |
| 738 | |
| 739 private: | |
| 740 Isolate* isolate() const { return result_->GetIsolate(); } | |
| 741 | |
| 742 Handle<Object> SerializeFunctionScope(Scope* scope, Zone* zone) { | |
| 743 Handle<JSArray> scope_info_list = isolate()->factory()->NewJSArray(10); | |
| 744 int scope_info_length = 0; | |
| 745 | |
| 746 // Saves some description of scope. It stores name and indexes of | |
| 747 // variables in the whole scope chain. Null-named slots delimit | |
| 748 // scopes of this chain. | |
| 749 Scope* current_scope = scope; | |
| 750 while (current_scope != NULL) { | |
| 751 HandleScope handle_scope(isolate()); | |
| 752 ZoneList<Variable*> stack_list(current_scope->StackLocalCount(), zone); | |
| 753 ZoneList<Variable*> context_list( | |
| 754 current_scope->ContextLocalCount(), zone); | |
| 755 ZoneList<Variable*> globals_list(current_scope->ContextGlobalCount(), | |
| 756 zone); | |
| 757 current_scope->CollectStackAndContextLocals(&stack_list, &context_list, | |
| 758 &globals_list); | |
| 759 context_list.Sort(&Variable::CompareIndex); | |
| 760 | |
| 761 for (int i = 0; i < context_list.length(); i++) { | |
| 762 SetElementSloppy(scope_info_list, | |
| 763 scope_info_length, | |
| 764 context_list[i]->name()); | |
| 765 scope_info_length++; | |
| 766 SetElementSloppy( | |
| 767 scope_info_list, | |
| 768 scope_info_length, | |
| 769 Handle<Smi>(Smi::FromInt(context_list[i]->index()), isolate())); | |
| 770 scope_info_length++; | |
| 771 } | |
| 772 SetElementSloppy(scope_info_list, | |
| 773 scope_info_length, | |
| 774 Handle<Object>(isolate()->heap()->null_value(), | |
| 775 isolate())); | |
| 776 scope_info_length++; | |
| 777 | |
| 778 current_scope = current_scope->outer_scope(); | |
| 779 } | |
| 780 | |
| 781 return scope_info_list; | |
| 782 } | |
| 783 | |
| 784 Handle<JSArray> result_; | |
| 785 int len_; | |
| 786 int current_parent_index_; | |
| 787 }; | |
| 788 | |
| 789 | |
| 790 void LiveEdit::InitializeThreadLocal(Debug* debug) { | 691 void LiveEdit::InitializeThreadLocal(Debug* debug) { |
| 791 debug->thread_local_.frame_drop_mode_ = LiveEdit::FRAMES_UNTOUCHED; | 692 debug->thread_local_.frame_drop_mode_ = LiveEdit::FRAMES_UNTOUCHED; |
| 792 } | 693 } |
| 793 | 694 |
| 794 | 695 |
| 795 bool LiveEdit::SetAfterBreakTarget(Debug* debug) { | 696 bool LiveEdit::SetAfterBreakTarget(Debug* debug) { |
| 796 Code* code = NULL; | 697 Code* code = NULL; |
| 797 Isolate* isolate = debug->isolate_; | 698 Isolate* isolate = debug->isolate_; |
| 798 switch (debug->thread_local_.frame_drop_mode_) { | 699 switch (debug->thread_local_.frame_drop_mode_) { |
| 799 case FRAMES_UNTOUCHED: | 700 case FRAMES_UNTOUCHED: |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 815 } | 716 } |
| 816 debug->after_break_target_ = code->entry(); | 717 debug->after_break_target_ = code->entry(); |
| 817 return true; | 718 return true; |
| 818 } | 719 } |
| 819 | 720 |
| 820 | 721 |
| 821 MaybeHandle<JSArray> LiveEdit::GatherCompileInfo(Handle<Script> script, | 722 MaybeHandle<JSArray> LiveEdit::GatherCompileInfo(Handle<Script> script, |
| 822 Handle<String> source) { | 723 Handle<String> source) { |
| 823 Isolate* isolate = script->GetIsolate(); | 724 Isolate* isolate = script->GetIsolate(); |
| 824 | 725 |
| 825 FunctionInfoListener listener(isolate); | 726 Handle<JSArray> infos; |
| 826 Handle<Object> original_source = | 727 Handle<Object> original_source = |
| 827 Handle<Object>(script->source(), isolate); | 728 Handle<Object>(script->source(), isolate); |
| 828 script->set_source(*source); | 729 script->set_source(*source); |
| 829 isolate->set_active_function_info_listener(&listener); | |
| 830 | 730 |
| 831 { | 731 { |
| 832 // Creating verbose TryCatch from public API is currently the only way to | 732 // Creating verbose TryCatch from public API is currently the only way to |
| 833 // force code save location. We do not use this the object directly. | 733 // force code save location. We do not use this the object directly. |
| 834 v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate)); | 734 v8::TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate)); |
| 835 try_catch.SetVerbose(true); | 735 try_catch.SetVerbose(true); |
| 836 | 736 |
| 837 // A logical 'try' section. | 737 // A logical 'try' section. |
| 838 Compiler::CompileForLiveEdit(script); | 738 Compiler::CompileForLiveEdit(script).ToHandle(&infos); |
|
Yang
2016/05/13 08:50:26
Or we could just keep infos as a MaybeHandle.
| |
| 839 } | 739 } |
| 840 | 740 |
| 841 // A logical 'catch' section. | 741 // A logical 'catch' section. |
| 842 Handle<JSObject> rethrow_exception; | 742 Handle<JSObject> rethrow_exception; |
| 843 if (isolate->has_pending_exception()) { | 743 if (isolate->has_pending_exception()) { |
| 844 Handle<Object> exception(isolate->pending_exception(), isolate); | 744 Handle<Object> exception(isolate->pending_exception(), isolate); |
| 845 MessageLocation message_location = isolate->GetMessageLocation(); | 745 MessageLocation message_location = isolate->GetMessageLocation(); |
| 846 | 746 |
| 847 isolate->clear_pending_message(); | 747 isolate->clear_pending_message(); |
| 848 isolate->clear_pending_exception(); | 748 isolate->clear_pending_exception(); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 866 Object::SetProperty(rethrow_exception, start_pos_key, start_pos, SLOPPY) | 766 Object::SetProperty(rethrow_exception, start_pos_key, start_pos, SLOPPY) |
| 867 .Assert(); | 767 .Assert(); |
| 868 Object::SetProperty(rethrow_exception, end_pos_key, end_pos, SLOPPY) | 768 Object::SetProperty(rethrow_exception, end_pos_key, end_pos, SLOPPY) |
| 869 .Assert(); | 769 .Assert(); |
| 870 Object::SetProperty(rethrow_exception, script_obj_key, script_obj, SLOPPY) | 770 Object::SetProperty(rethrow_exception, script_obj_key, script_obj, SLOPPY) |
| 871 .Assert(); | 771 .Assert(); |
| 872 } | 772 } |
| 873 } | 773 } |
| 874 | 774 |
| 875 // A logical 'finally' section. | 775 // A logical 'finally' section. |
| 876 isolate->set_active_function_info_listener(NULL); | |
| 877 script->set_source(*original_source); | 776 script->set_source(*original_source); |
| 878 | 777 |
| 879 if (rethrow_exception.is_null()) { | 778 if (rethrow_exception.is_null()) { |
| 880 return listener.GetResult(); | 779 return infos; |
| 881 } else { | 780 } else { |
| 882 return isolate->Throw<JSArray>(rethrow_exception); | 781 return isolate->Throw<JSArray>(rethrow_exception); |
| 883 } | 782 } |
| 884 } | 783 } |
| 885 | 784 |
| 886 | 785 |
| 887 // Visitor that finds all references to a particular code object, | 786 // Visitor that finds all references to a particular code object, |
| 888 // including "CODE_TARGET" references in other code objects and replaces | 787 // including "CODE_TARGET" references in other code objects and replaces |
| 889 // them on the fly. | 788 // them on the fly. |
| 890 class ReplacingVisitor : public ObjectVisitor { | 789 class ReplacingVisitor : public ObjectVisitor { |
| (...skipping 1095 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1986 } | 1885 } |
| 1987 if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE) { | 1886 if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_NATIVE_CODE) { |
| 1988 return "Function is blocked under native code"; | 1887 return "Function is blocked under native code"; |
| 1989 } | 1888 } |
| 1990 if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR) { | 1889 if (target.saved_status() == LiveEdit::FUNCTION_BLOCKED_UNDER_GENERATOR) { |
| 1991 return "Function is blocked under a generator activation"; | 1890 return "Function is blocked under a generator activation"; |
| 1992 } | 1891 } |
| 1993 return NULL; | 1892 return NULL; |
| 1994 } | 1893 } |
| 1995 | 1894 |
| 1996 | 1895 Handle<JSArray> LiveEditFunctionTracker::Collect(FunctionLiteral* node, |
| 1997 LiveEditFunctionTracker::LiveEditFunctionTracker(Isolate* isolate, | 1896 Handle<Script> script, |
| 1998 FunctionLiteral* fun) | 1897 Zone* zone, Isolate* isolate) { |
| 1999 : isolate_(isolate) { | 1898 LiveEditFunctionTracker visitor(script, zone, isolate); |
| 2000 if (isolate_->active_function_info_listener() != NULL) { | 1899 visitor.VisitFunctionLiteral(node); |
| 2001 isolate_->active_function_info_listener()->FunctionStarted(fun); | 1900 return visitor.result_; |
| 2002 } | |
| 2003 } | 1901 } |
| 2004 | 1902 |
| 2005 | 1903 LiveEditFunctionTracker::LiveEditFunctionTracker(Handle<Script> script, |
| 2006 LiveEditFunctionTracker::~LiveEditFunctionTracker() { | 1904 Zone* zone, Isolate* isolate) |
| 2007 if (isolate_->active_function_info_listener() != NULL) { | 1905 : AstTraversalVisitor(isolate) { |
| 2008 isolate_->active_function_info_listener()->FunctionDone(); | 1906 current_parent_index_ = -1; |
| 2009 } | 1907 isolate_ = isolate; |
| 1908 len_ = 0; | |
| 1909 result_ = isolate->factory()->NewJSArray(10); | |
| 1910 script_ = script; | |
| 1911 zone_ = zone; | |
| 2010 } | 1912 } |
| 2011 | 1913 |
| 1914 void LiveEditFunctionTracker::VisitFunctionLiteral(FunctionLiteral* node) { | |
| 1915 Scope* scope = node->scope(); | |
| 2012 | 1916 |
| 2013 void LiveEditFunctionTracker::RecordFunctionInfo( | 1917 // FunctionStarted is called in pre-order. |
| 2014 Handle<SharedFunctionInfo> info, FunctionLiteral* lit, | 1918 FunctionStarted(node); |
| 2015 Zone* zone) { | 1919 |
| 2016 if (isolate_->active_function_info_listener() != NULL) { | 1920 VisitDeclarations(scope->declarations()); |
| 2017 isolate_->active_function_info_listener()->FunctionInfo(info, lit->scope(), | 1921 VisitStatements(node->body()); |
| 2018 zone); | 1922 |
| 2019 } | 1923 // FunctionDone are called in post-order. |
| 1924 // TODO(jgruber): If required, replace the (linear cost) | |
| 1925 // FindSharedFunctionInfo call with a more efficient implementation. | |
| 1926 Handle<SharedFunctionInfo> info = | |
| 1927 script_->FindSharedFunctionInfo(node).ToHandleChecked(); | |
| 1928 FunctionDone(info, scope); | |
| 2020 } | 1929 } |
| 2021 | 1930 |
| 1931 void LiveEditFunctionTracker::FunctionStarted(FunctionLiteral* fun) { | |
| 1932 HandleScope handle_scope(isolate_); | |
| 1933 FunctionInfoWrapper info = FunctionInfoWrapper::Create(isolate_); | |
| 1934 info.SetInitialProperties(fun->name(), fun->start_position(), | |
| 1935 fun->end_position(), fun->parameter_count(), | |
| 1936 fun->materialized_literal_count(), | |
| 1937 current_parent_index_); | |
| 1938 current_parent_index_ = len_; | |
| 1939 SetElementSloppy(result_, len_, info.GetJSArray()); | |
| 1940 len_++; | |
| 1941 } | |
| 2022 | 1942 |
| 2023 bool LiveEditFunctionTracker::IsActive(Isolate* isolate) { | 1943 // Saves full information about a function: its code, its scope info |
| 2024 return isolate->active_function_info_listener() != NULL; | 1944 // and a SharedFunctionInfo object. |
| 1945 void LiveEditFunctionTracker::FunctionDone(Handle<SharedFunctionInfo> shared, | |
| 1946 Scope* scope) { | |
| 1947 HandleScope handle_scope(isolate_); | |
| 1948 FunctionInfoWrapper info = FunctionInfoWrapper::cast( | |
| 1949 *JSReceiver::GetElement(isolate_, result_, current_parent_index_) | |
| 1950 .ToHandleChecked()); | |
| 1951 info.SetFunctionCode(Handle<Code>(shared->code()), | |
| 1952 Handle<HeapObject>(shared->scope_info())); | |
| 1953 info.SetSharedFunctionInfo(shared); | |
| 1954 | |
| 1955 Handle<Object> scope_info_list = SerializeFunctionScope(scope); | |
| 1956 info.SetFunctionScopeInfo(scope_info_list); | |
| 1957 | |
| 1958 current_parent_index_ = info.GetParentIndex(); | |
| 1959 } | |
| 1960 | |
| 1961 Handle<Object> LiveEditFunctionTracker::SerializeFunctionScope(Scope* scope) { | |
| 1962 Handle<JSArray> scope_info_list = isolate_->factory()->NewJSArray(10); | |
| 1963 int scope_info_length = 0; | |
| 1964 | |
| 1965 // Saves some description of scope. It stores name and indexes of | |
| 1966 // variables in the whole scope chain. Null-named slots delimit | |
| 1967 // scopes of this chain. | |
| 1968 Scope* current_scope = scope; | |
| 1969 while (current_scope != NULL) { | |
| 1970 HandleScope handle_scope(isolate_); | |
| 1971 ZoneList<Variable*> stack_list(current_scope->StackLocalCount(), zone_); | |
| 1972 ZoneList<Variable*> context_list(current_scope->ContextLocalCount(), zone_); | |
| 1973 ZoneList<Variable*> globals_list(current_scope->ContextGlobalCount(), | |
| 1974 zone_); | |
| 1975 current_scope->CollectStackAndContextLocals(&stack_list, &context_list, | |
| 1976 &globals_list); | |
| 1977 context_list.Sort(&Variable::CompareIndex); | |
| 1978 | |
| 1979 for (int i = 0; i < context_list.length(); i++) { | |
| 1980 SetElementSloppy(scope_info_list, scope_info_length, | |
| 1981 context_list[i]->name()); | |
| 1982 scope_info_length++; | |
| 1983 SetElementSloppy( | |
| 1984 scope_info_list, scope_info_length, | |
| 1985 Handle<Smi>(Smi::FromInt(context_list[i]->index()), isolate_)); | |
| 1986 scope_info_length++; | |
| 1987 } | |
| 1988 SetElementSloppy(scope_info_list, scope_info_length, | |
| 1989 Handle<Object>(isolate_->heap()->null_value(), isolate_)); | |
| 1990 scope_info_length++; | |
| 1991 | |
| 1992 current_scope = current_scope->outer_scope(); | |
| 1993 } | |
| 1994 | |
| 1995 return scope_info_list; | |
| 2025 } | 1996 } |
| 2026 | 1997 |
| 2027 } // namespace internal | 1998 } // namespace internal |
| 2028 } // namespace v8 | 1999 } // namespace v8 |
| OLD | NEW |