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 |