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