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