Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 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/v8.h" | 5 #include "src/v8.h" |
| 6 | 6 |
| 7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
| 8 #include "src/arguments.h" | 8 #include "src/arguments.h" |
| 9 #include "src/compiler.h" | 9 #include "src/compiler.h" |
| 10 #include "src/debug.h" | 10 #include "src/debug.h" |
| (...skipping 669 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 680 MaybeAssignedFlag maybe_assigned_flag; | 680 MaybeAssignedFlag maybe_assigned_flag; |
| 681 return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &init_flag, | 681 return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &init_flag, |
| 682 &maybe_assigned_flag) != -1; | 682 &maybe_assigned_flag) != -1; |
| 683 } | 683 } |
| 684 | 684 |
| 685 | 685 |
| 686 // Create a plain JSObject which materializes the local scope for the specified | 686 // Create a plain JSObject which materializes the local scope for the specified |
| 687 // frame. | 687 // frame. |
| 688 MUST_USE_RESULT | 688 MUST_USE_RESULT |
| 689 static MaybeHandle<JSObject> MaterializeStackLocalsWithFrameInspector( | 689 static MaybeHandle<JSObject> MaterializeStackLocalsWithFrameInspector( |
| 690 Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function, | 690 Isolate* isolate, Handle<JSObject> target, Handle<ScopeInfo> scope_info, |
| 691 FrameInspector* frame_inspector) { | 691 FrameInspector* frame_inspector) { |
| 692 Handle<SharedFunctionInfo> shared(function->shared()); | |
| 693 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
| 694 | |
| 695 // First fill all parameters. | 692 // First fill all parameters. |
| 696 for (int i = 0; i < scope_info->ParameterCount(); ++i) { | 693 for (int i = 0; i < scope_info->ParameterCount(); ++i) { |
| 697 // Do not materialize the parameter if it is shadowed by a context local. | 694 // Do not materialize the parameter if it is shadowed by a context local. |
| 698 Handle<String> name(scope_info->ParameterName(i)); | 695 Handle<String> name(scope_info->ParameterName(i)); |
| 699 if (ParameterIsShadowedByContextLocal(scope_info, name)) continue; | 696 if (ParameterIsShadowedByContextLocal(scope_info, name)) continue; |
| 700 | 697 |
| 698 DCHECK(frame_inspector != nullptr); | |
| 699 | |
| 701 HandleScope scope(isolate); | 700 HandleScope scope(isolate); |
| 702 Handle<Object> value(i < frame_inspector->GetParametersCount() | 701 Handle<Object> value(i < frame_inspector->GetParametersCount() |
| 703 ? frame_inspector->GetParameter(i) | 702 ? frame_inspector->GetParameter(i) |
| 704 : isolate->heap()->undefined_value(), | 703 : isolate->heap()->undefined_value(), |
| 705 isolate); | 704 isolate); |
| 706 DCHECK(!value->IsTheHole()); | 705 DCHECK(!value->IsTheHole()); |
| 707 | 706 |
| 708 RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty( | 707 RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty( |
| 709 isolate, target, name, value, SLOPPY), | 708 isolate, target, name, value, SLOPPY), |
| 710 JSObject); | 709 JSObject); |
| 711 } | 710 } |
| 712 | 711 |
| 713 // Second fill all stack locals. | 712 // Second fill all stack locals. |
| 714 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { | 713 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { |
| 715 if (scope_info->LocalIsSynthetic(i)) continue; | 714 if (scope_info->LocalIsSynthetic(i)) continue; |
| 716 Handle<String> name(scope_info->StackLocalName(i)); | 715 Handle<String> name(scope_info->StackLocalName(i)); |
| 717 Handle<Object> value(frame_inspector->GetExpression(i), isolate); | 716 Handle<Object> value( |
| 718 if (value->IsTheHole()) continue; | 717 frame_inspector->GetExpression(scope_info->StackLocalIndex(i)), |
| 718 isolate); | |
| 719 if (value->IsTheHole()) { | |
| 720 value = isolate->factory()->undefined_value(); | |
|
rossberg
2015/04/17 15:16:27
Is this safe? Isn't the implication that you can n
Dmitry Lomov (no reviews)
2015/04/17 15:21:54
If we do not do that, shadowing will not work corr
rossberg
2015/04/17 15:26:07
I see. Yes, preventing the copying back sounds goo
Dmitry Lomov (no reviews)
2015/04/20 11:53:20
We actually already have the check (line 770)
| |
| 721 } | |
| 719 | 722 |
| 720 RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty( | 723 RETURN_ON_EXCEPTION(isolate, Runtime::SetObjectProperty( |
| 721 isolate, target, name, value, SLOPPY), | 724 isolate, target, name, value, SLOPPY), |
| 722 JSObject); | 725 JSObject); |
| 723 } | 726 } |
| 724 | 727 |
| 725 return target; | 728 return target; |
| 726 } | 729 } |
| 727 | 730 |
| 731 MUST_USE_RESULT | |
| 732 static MaybeHandle<JSObject> MaterializeStackLocalsWithFrameInspector( | |
| 733 Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function, | |
| 734 FrameInspector* frame_inspector) { | |
| 735 Handle<SharedFunctionInfo> shared(function->shared()); | |
| 736 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
| 728 | 737 |
| 729 static void UpdateStackLocalsFromMaterializedObject(Isolate* isolate, | 738 return MaterializeStackLocalsWithFrameInspector(isolate, target, scope_info, |
| 730 Handle<JSObject> target, | 739 frame_inspector); |
| 731 Handle<JSFunction> function, | 740 } |
| 732 JavaScriptFrame* frame, | 741 |
| 733 int inlined_jsframe_index) { | 742 |
| 743 static void UpdateStackLocalsFromMaterializedObject( | |
| 744 Isolate* isolate, Handle<JSObject> target, Handle<ScopeInfo> scope_info, | |
| 745 JavaScriptFrame* frame, int inlined_jsframe_index) { | |
| 734 if (inlined_jsframe_index != 0 || frame->is_optimized()) { | 746 if (inlined_jsframe_index != 0 || frame->is_optimized()) { |
| 735 // Optimized frames are not supported. | 747 // Optimized frames are not supported. |
| 736 // TODO(yangguo): make sure all code deoptimized when debugger is active | 748 // TODO(yangguo): make sure all code deoptimized when debugger is active |
| 737 // and assert that this cannot happen. | 749 // and assert that this cannot happen. |
| 738 return; | 750 return; |
| 739 } | 751 } |
| 740 | 752 |
| 741 Handle<SharedFunctionInfo> shared(function->shared()); | |
| 742 Handle<ScopeInfo> scope_info(shared->scope_info()); | |
| 743 | |
| 744 // Parameters. | 753 // Parameters. |
| 745 for (int i = 0; i < scope_info->ParameterCount(); ++i) { | 754 for (int i = 0; i < scope_info->ParameterCount(); ++i) { |
| 746 // Shadowed parameters were not materialized. | 755 // Shadowed parameters were not materialized. |
| 747 Handle<String> name(scope_info->ParameterName(i)); | 756 Handle<String> name(scope_info->ParameterName(i)); |
| 748 if (ParameterIsShadowedByContextLocal(scope_info, name)) continue; | 757 if (ParameterIsShadowedByContextLocal(scope_info, name)) continue; |
| 749 | 758 |
| 750 DCHECK(!frame->GetParameter(i)->IsTheHole()); | 759 DCHECK(!frame->GetParameter(i)->IsTheHole()); |
| 751 HandleScope scope(isolate); | 760 HandleScope scope(isolate); |
| 752 Handle<Object> value = | 761 Handle<Object> value = |
| 753 Object::GetPropertyOrElement(target, name).ToHandleChecked(); | 762 Object::GetPropertyOrElement(target, name).ToHandleChecked(); |
| 754 frame->SetParameterValue(i, *value); | 763 frame->SetParameterValue(i, *value); |
| 755 } | 764 } |
| 756 | 765 |
| 757 // Stack locals. | 766 // Stack locals. |
| 758 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { | 767 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { |
| 759 if (scope_info->LocalIsSynthetic(i)) continue; | 768 if (scope_info->LocalIsSynthetic(i)) continue; |
| 760 if (frame->GetExpression(i)->IsTheHole()) continue; | 769 int index = scope_info->StackLocalIndex(i); |
| 770 if (frame->GetExpression(index)->IsTheHole()) continue; | |
| 761 HandleScope scope(isolate); | 771 HandleScope scope(isolate); |
| 762 Handle<Object> value = Object::GetPropertyOrElement( | 772 Handle<Object> value = Object::GetPropertyOrElement( |
| 763 target, handle(scope_info->StackLocalName(i), | 773 target, handle(scope_info->StackLocalName(i), |
| 764 isolate)).ToHandleChecked(); | 774 isolate)).ToHandleChecked(); |
| 765 frame->SetExpression(i, *value); | 775 frame->SetExpression(index, *value); |
| 766 } | 776 } |
| 767 } | 777 } |
| 768 | 778 |
| 769 | 779 |
| 770 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalContext( | 780 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeLocalContext( |
| 771 Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function, | 781 Isolate* isolate, Handle<JSObject> target, Handle<JSFunction> function, |
| 772 JavaScriptFrame* frame) { | 782 JavaScriptFrame* frame) { |
| 773 HandleScope scope(isolate); | 783 HandleScope scope(isolate); |
| 774 Handle<SharedFunctionInfo> shared(function->shared()); | 784 Handle<SharedFunctionInfo> shared(function->shared()); |
| 775 Handle<ScopeInfo> scope_info(shared->scope_info()); | 785 Handle<ScopeInfo> scope_info(shared->scope_info()); |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 897 frame->SetParameterValue(i, *new_value); | 907 frame->SetParameterValue(i, *new_value); |
| 898 // Argument might be shadowed in heap context, don't stop here. | 908 // Argument might be shadowed in heap context, don't stop here. |
| 899 default_result = true; | 909 default_result = true; |
| 900 } | 910 } |
| 901 } | 911 } |
| 902 | 912 |
| 903 // Stack locals. | 913 // Stack locals. |
| 904 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { | 914 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { |
| 905 HandleScope scope(isolate); | 915 HandleScope scope(isolate); |
| 906 if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) { | 916 if (String::Equals(handle(scope_info->StackLocalName(i)), variable_name)) { |
| 907 frame->SetExpression(i, *new_value); | 917 frame->SetExpression(scope_info->StackLocalIndex(i), *new_value); |
| 908 return true; | 918 return true; |
| 909 } | 919 } |
| 910 } | 920 } |
| 911 | 921 |
| 912 if (scope_info->HasContext()) { | 922 if (scope_info->HasContext()) { |
| 913 // Context locals. | 923 // Context locals. |
| 914 Handle<Context> frame_context(Context::cast(frame->context())); | 924 Handle<Context> frame_context(Context::cast(frame->context())); |
| 915 Handle<Context> function_context(frame_context->declaration_context()); | 925 Handle<Context> function_context(frame_context->declaration_context()); |
| 916 if (SetContextLocalValue(isolate, scope_info, function_context, | 926 if (SetContextLocalValue(isolate, scope_info, function_context, |
| 917 variable_name, new_value)) { | 927 variable_name, new_value)) { |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 934 return true; | 944 return true; |
| 935 } | 945 } |
| 936 } | 946 } |
| 937 } | 947 } |
| 938 } | 948 } |
| 939 | 949 |
| 940 return default_result; | 950 return default_result; |
| 941 } | 951 } |
| 942 | 952 |
| 943 | 953 |
| 954 static bool SetBlockVariableValue(Isolate* isolate, | |
| 955 Handle<Context> block_context, | |
| 956 Handle<ScopeInfo> scope_info, | |
| 957 JavaScriptFrame* frame, | |
| 958 Handle<String> variable_name, | |
| 959 Handle<Object> new_value) { | |
| 960 if (frame != nullptr) { | |
| 961 for (int i = 0; i < scope_info->StackLocalCount(); ++i) { | |
| 962 HandleScope scope(isolate); | |
| 963 if (String::Equals(handle(scope_info->StackLocalName(i)), | |
| 964 variable_name)) { | |
| 965 frame->SetExpression(scope_info->StackLocalIndex(i), *new_value); | |
| 966 return true; | |
| 967 } | |
| 968 } | |
| 969 } | |
| 970 if (!block_context.is_null()) { | |
| 971 return SetContextLocalValue(block_context->GetIsolate(), scope_info, | |
| 972 block_context, variable_name, new_value); | |
| 973 } | |
| 974 return false; | |
| 975 } | |
| 976 | |
| 977 | |
| 944 // Create a plain JSObject which materializes the closure content for the | 978 // Create a plain JSObject which materializes the closure content for the |
| 945 // context. | 979 // context. |
| 946 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeClosure( | 980 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeClosure( |
| 947 Isolate* isolate, Handle<Context> context) { | 981 Isolate* isolate, Handle<Context> context) { |
| 948 DCHECK(context->IsFunctionContext()); | 982 DCHECK(context->IsFunctionContext()); |
| 949 | 983 |
| 950 Handle<SharedFunctionInfo> shared(context->closure()->shared()); | 984 Handle<SharedFunctionInfo> shared(context->closure()->shared()); |
| 951 Handle<ScopeInfo> scope_info(shared->scope_info()); | 985 Handle<ScopeInfo> scope_info(shared->scope_info()); |
| 952 | 986 |
| 953 // Allocate and initialize a JSObject with all the content of this function | 987 // Allocate and initialize a JSObject with all the content of this function |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1014 Runtime::DefineObjectProperty(ext, variable_name, new_value, NONE) | 1048 Runtime::DefineObjectProperty(ext, variable_name, new_value, NONE) |
| 1015 .Assert(); | 1049 .Assert(); |
| 1016 return true; | 1050 return true; |
| 1017 } | 1051 } |
| 1018 } | 1052 } |
| 1019 | 1053 |
| 1020 return false; | 1054 return false; |
| 1021 } | 1055 } |
| 1022 | 1056 |
| 1023 | 1057 |
| 1024 static bool SetBlockContextVariableValue(Handle<Context> block_context, | |
| 1025 Handle<String> variable_name, | |
| 1026 Handle<Object> new_value) { | |
| 1027 DCHECK(block_context->IsBlockContext()); | |
| 1028 Handle<ScopeInfo> scope_info(ScopeInfo::cast(block_context->extension())); | |
| 1029 | |
| 1030 return SetContextLocalValue(block_context->GetIsolate(), scope_info, | |
| 1031 block_context, variable_name, new_value); | |
| 1032 } | |
| 1033 | |
| 1034 | |
| 1035 static bool SetScriptVariableValue(Handle<Context> context, | 1058 static bool SetScriptVariableValue(Handle<Context> context, |
| 1036 Handle<String> variable_name, | 1059 Handle<String> variable_name, |
| 1037 Handle<Object> new_value) { | 1060 Handle<Object> new_value) { |
| 1038 Handle<ScriptContextTable> script_contexts( | 1061 Handle<ScriptContextTable> script_contexts( |
| 1039 context->global_object()->native_context()->script_context_table()); | 1062 context->global_object()->native_context()->script_context_table()); |
| 1040 ScriptContextTable::LookupResult lookup_result; | 1063 ScriptContextTable::LookupResult lookup_result; |
| 1041 if (ScriptContextTable::Lookup(script_contexts, variable_name, | 1064 if (ScriptContextTable::Lookup(script_contexts, variable_name, |
| 1042 &lookup_result)) { | 1065 &lookup_result)) { |
| 1043 Handle<Context> script_context = ScriptContextTable::GetContext( | 1066 Handle<Context> script_context = ScriptContextTable::GetContext( |
| 1044 script_contexts, lookup_result.context_index); | 1067 script_contexts, lookup_result.context_index); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1076 return false; | 1099 return false; |
| 1077 } | 1100 } |
| 1078 context->set(Context::THROWN_OBJECT_INDEX, *new_value); | 1101 context->set(Context::THROWN_OBJECT_INDEX, *new_value); |
| 1079 return true; | 1102 return true; |
| 1080 } | 1103 } |
| 1081 | 1104 |
| 1082 | 1105 |
| 1083 // Create a plain JSObject which materializes the block scope for the specified | 1106 // Create a plain JSObject which materializes the block scope for the specified |
| 1084 // block context. | 1107 // block context. |
| 1085 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeBlockScope( | 1108 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeBlockScope( |
| 1086 Isolate* isolate, Handle<Context> context) { | 1109 Isolate* isolate, Handle<ScopeInfo> scope_info, Handle<Context> context, |
| 1087 DCHECK(context->IsBlockContext()); | 1110 JavaScriptFrame* frame, int inlined_jsframe_index) { |
| 1088 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension())); | |
| 1089 | |
| 1090 // Allocate and initialize a JSObject with all the arguments, stack locals | |
| 1091 // heap locals and extension properties of the debugged function. | |
| 1092 Handle<JSObject> block_scope = | 1111 Handle<JSObject> block_scope = |
| 1093 isolate->factory()->NewJSObject(isolate->object_function()); | 1112 isolate->factory()->NewJSObject(isolate->object_function()); |
| 1094 | 1113 |
| 1095 // Fill all context locals. | 1114 if (frame != nullptr) { |
| 1096 if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info, context, | 1115 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); |
| 1097 block_scope)) { | 1116 RETURN_ON_EXCEPTION(isolate, |
| 1098 return MaybeHandle<JSObject>(); | 1117 MaterializeStackLocalsWithFrameInspector( |
| 1118 isolate, block_scope, scope_info, &frame_inspector), | |
| 1119 JSObject); | |
| 1120 } | |
| 1121 | |
| 1122 if (!context.is_null()) { | |
| 1123 Handle<ScopeInfo> scope_info_from_context( | |
| 1124 ScopeInfo::cast(context->extension())); | |
| 1125 // Fill all context locals. | |
| 1126 if (!ScopeInfo::CopyContextLocalsToScopeObject(scope_info_from_context, | |
| 1127 context, block_scope)) { | |
| 1128 return MaybeHandle<JSObject>(); | |
| 1129 } | |
| 1099 } | 1130 } |
| 1100 | 1131 |
| 1101 return block_scope; | 1132 return block_scope; |
| 1102 } | 1133 } |
| 1103 | 1134 |
| 1104 | 1135 |
| 1105 // Create a plain JSObject which materializes the module scope for the specified | 1136 // Create a plain JSObject which materializes the module scope for the specified |
| 1106 // module context. | 1137 // module context. |
| 1107 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeModuleScope( | 1138 MUST_USE_RESULT static MaybeHandle<JSObject> MaterializeModuleScope( |
| 1108 Isolate* isolate, Handle<Context> context) { | 1139 Isolate* isolate, Handle<Context> context) { |
| (...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1355 DCHECK(nested_scope_chain_.length() == 1); | 1386 DCHECK(nested_scope_chain_.length() == 1); |
| 1356 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_); | 1387 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_); |
| 1357 case ScopeIterator::ScopeTypeWith: | 1388 case ScopeIterator::ScopeTypeWith: |
| 1358 // Return the with object. | 1389 // Return the with object. |
| 1359 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension())); | 1390 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension())); |
| 1360 case ScopeIterator::ScopeTypeCatch: | 1391 case ScopeIterator::ScopeTypeCatch: |
| 1361 return MaterializeCatchScope(isolate_, CurrentContext()); | 1392 return MaterializeCatchScope(isolate_, CurrentContext()); |
| 1362 case ScopeIterator::ScopeTypeClosure: | 1393 case ScopeIterator::ScopeTypeClosure: |
| 1363 // Materialize the content of the closure scope into a JSObject. | 1394 // Materialize the content of the closure scope into a JSObject. |
| 1364 return MaterializeClosure(isolate_, CurrentContext()); | 1395 return MaterializeClosure(isolate_, CurrentContext()); |
| 1365 case ScopeIterator::ScopeTypeBlock: | 1396 case ScopeIterator::ScopeTypeBlock: { |
| 1366 return MaterializeBlockScope(isolate_, CurrentContext()); | 1397 if (!nested_scope_chain_.is_empty()) { |
| 1398 // this is a block scope on the stack. | |
|
rossberg
2015/04/17 15:16:27
Nit: upper case
| |
| 1399 Handle<ScopeInfo> scope_info = nested_scope_chain_.last(); | |
| 1400 Handle<Context> context = scope_info->HasContext() | |
| 1401 ? CurrentContext() | |
| 1402 : Handle<Context>::null(); | |
| 1403 return MaterializeBlockScope(isolate_, scope_info, context, frame_, | |
| 1404 inlined_jsframe_index_); | |
| 1405 } else { | |
| 1406 return MaterializeBlockScope(isolate_, Handle<ScopeInfo>::null(), | |
| 1407 CurrentContext(), nullptr, 0); | |
| 1408 } | |
| 1409 } | |
| 1367 case ScopeIterator::ScopeTypeModule: | 1410 case ScopeIterator::ScopeTypeModule: |
| 1368 return MaterializeModuleScope(isolate_, CurrentContext()); | 1411 return MaterializeModuleScope(isolate_, CurrentContext()); |
| 1369 } | 1412 } |
| 1370 UNREACHABLE(); | 1413 UNREACHABLE(); |
| 1371 return Handle<JSObject>(); | 1414 return Handle<JSObject>(); |
| 1372 } | 1415 } |
| 1373 | 1416 |
| 1417 bool HasContext() { | |
| 1418 ScopeType type = Type(); | |
| 1419 if (type == ScopeTypeBlock || type == ScopeTypeLocal) { | |
| 1420 if (!nested_scope_chain_.is_empty()) { | |
| 1421 return nested_scope_chain_.last()->HasContext(); | |
| 1422 } | |
| 1423 } | |
| 1424 return true; | |
| 1425 } | |
| 1426 | |
| 1374 bool SetVariableValue(Handle<String> variable_name, | 1427 bool SetVariableValue(Handle<String> variable_name, |
| 1375 Handle<Object> new_value) { | 1428 Handle<Object> new_value) { |
| 1376 DCHECK(!failed_); | 1429 DCHECK(!failed_); |
| 1377 switch (Type()) { | 1430 switch (Type()) { |
| 1378 case ScopeIterator::ScopeTypeGlobal: | 1431 case ScopeIterator::ScopeTypeGlobal: |
| 1379 break; | 1432 break; |
| 1380 case ScopeIterator::ScopeTypeLocal: | 1433 case ScopeIterator::ScopeTypeLocal: |
| 1381 return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_, | 1434 return SetLocalVariableValue(isolate_, frame_, inlined_jsframe_index_, |
| 1382 variable_name, new_value); | 1435 variable_name, new_value); |
| 1383 case ScopeIterator::ScopeTypeWith: | 1436 case ScopeIterator::ScopeTypeWith: |
| 1384 break; | 1437 break; |
| 1385 case ScopeIterator::ScopeTypeCatch: | 1438 case ScopeIterator::ScopeTypeCatch: |
| 1386 return SetCatchVariableValue(isolate_, CurrentContext(), variable_name, | 1439 return SetCatchVariableValue(isolate_, CurrentContext(), variable_name, |
| 1387 new_value); | 1440 new_value); |
| 1388 case ScopeIterator::ScopeTypeClosure: | 1441 case ScopeIterator::ScopeTypeClosure: |
| 1389 return SetClosureVariableValue(isolate_, CurrentContext(), | 1442 return SetClosureVariableValue(isolate_, CurrentContext(), |
| 1390 variable_name, new_value); | 1443 variable_name, new_value); |
| 1391 case ScopeIterator::ScopeTypeScript: | 1444 case ScopeIterator::ScopeTypeScript: |
| 1392 return SetScriptVariableValue(CurrentContext(), variable_name, | 1445 return SetScriptVariableValue(CurrentContext(), variable_name, |
| 1393 new_value); | 1446 new_value); |
| 1394 case ScopeIterator::ScopeTypeBlock: | 1447 case ScopeIterator::ScopeTypeBlock: |
| 1395 return SetBlockContextVariableValue(CurrentContext(), variable_name, | 1448 return SetBlockVariableValue( |
| 1396 new_value); | 1449 isolate_, HasContext() ? CurrentContext() : Handle<Context>::null(), |
| 1450 CurrentScopeInfo(), frame_, variable_name, new_value); | |
| 1397 case ScopeIterator::ScopeTypeModule: | 1451 case ScopeIterator::ScopeTypeModule: |
| 1398 // TODO(2399): should we implement it? | 1452 // TODO(2399): should we implement it? |
| 1399 break; | 1453 break; |
| 1400 } | 1454 } |
| 1401 return false; | 1455 return false; |
| 1402 } | 1456 } |
| 1403 | 1457 |
| 1404 Handle<ScopeInfo> CurrentScopeInfo() { | 1458 Handle<ScopeInfo> CurrentScopeInfo() { |
| 1405 DCHECK(!failed_); | 1459 DCHECK(!failed_); |
| 1406 if (!nested_scope_chain_.is_empty()) { | 1460 if (!nested_scope_chain_.is_empty()) { |
| (...skipping 775 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2182 Handle<JSObject> result = | 2236 Handle<JSObject> result = |
| 2183 isolate->factory()->NewJSObject(isolate->object_function()); | 2237 isolate->factory()->NewJSObject(isolate->object_function()); |
| 2184 Handle<Map> new_map = | 2238 Handle<Map> new_map = |
| 2185 Map::Copy(Handle<Map>(result->map()), "ObjectWithNullProto"); | 2239 Map::Copy(Handle<Map>(result->map()), "ObjectWithNullProto"); |
| 2186 Map::SetPrototype(new_map, isolate->factory()->null_value()); | 2240 Map::SetPrototype(new_map, isolate->factory()->null_value()); |
| 2187 JSObject::MigrateToMap(result, new_map); | 2241 JSObject::MigrateToMap(result, new_map); |
| 2188 return result; | 2242 return result; |
| 2189 } | 2243 } |
| 2190 | 2244 |
| 2191 | 2245 |
| 2246 namespace { | |
| 2247 | |
| 2248 // This class builds a context chain for evaluation of expressions | |
| 2249 // in debugger. | |
| 2250 // The scope chain leading up to a breakpoint where evaluation occurs | |
| 2251 // looks like: | |
| 2252 // - [a mix of with, catch and block scopes] | |
| 2253 // - [function stack + context] | |
| 2254 // - [outer context] | |
| 2255 // The builder materializes all stack variables into properties of objects; | |
| 2256 // the expression is then evaluated as if it is inside a series of 'with' | |
| 2257 // statements using those objects. To this end, the builder builds a new | |
| 2258 // context chain, based on a scope chain: | |
| 2259 // - every With and Catch scope begets a cloned context | |
| 2260 // - Block scope begets one or two contexts: | |
| 2261 // - if a block has context-allocated varaibles, its context is cloned | |
|
rossberg
2015/04/17 15:16:27
typo: variables
| |
| 2262 // - stack locals are materizalized as a With context | |
| 2263 // - Local scope begets a With context for materizalized locals, chained to | |
| 2264 // original function context. Original function context is the end of | |
| 2265 // the chain. | |
| 2266 class EvaluationContextBuilder { | |
| 2267 public: | |
| 2268 EvaluationContextBuilder(Isolate* isolate, JavaScriptFrame* frame, | |
| 2269 int inlined_jsframe_index) | |
| 2270 : isolate_(isolate), | |
| 2271 frame_(frame), | |
| 2272 inlined_jsframe_index_(inlined_jsframe_index) { | |
| 2273 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); | |
| 2274 Handle<JSFunction> function = | |
| 2275 handle(JSFunction::cast(frame_inspector.GetFunction())); | |
| 2276 Handle<Context> outer_context = handle(function->context(), isolate); | |
| 2277 outer_info_ = handle(function->shared()); | |
| 2278 Handle<Context> inner_context; | |
| 2279 | |
| 2280 bool stop = false; | |
| 2281 for (ScopeIterator it(isolate, frame, inlined_jsframe_index); | |
| 2282 !it.Failed() && !it.Done() && !stop; it.Next()) { | |
| 2283 ScopeIterator::ScopeType scope_type = it.Type(); | |
| 2284 | |
| 2285 if (scope_type == ScopeIterator::ScopeTypeLocal) { | |
| 2286 Handle<JSObject> materialized_function = | |
| 2287 NewJSObjectWithNullProto(isolate); | |
| 2288 | |
| 2289 if (!MaterializeStackLocalsWithFrameInspector( | |
| 2290 isolate, materialized_function, function, &frame_inspector) | |
| 2291 .ToHandle(&materialized_function)) | |
| 2292 return; | |
| 2293 | |
| 2294 if (!MaterializeArgumentsObject(isolate, materialized_function, | |
| 2295 function) | |
| 2296 .ToHandle(&materialized_function)) | |
| 2297 return; | |
| 2298 | |
| 2299 Handle<Context> parent_context = | |
| 2300 it.HasContext() ? it.CurrentContext() : outer_context; | |
| 2301 Handle<Context> with_context = isolate->factory()->NewWithContext( | |
| 2302 function, parent_context, materialized_function); | |
| 2303 | |
| 2304 ContextChainElement context_chain_element; | |
| 2305 context_chain_element.original_context = it.CurrentContext(); | |
| 2306 context_chain_element.materialized_object = materialized_function; | |
| 2307 context_chain_element.scope_info = it.CurrentScopeInfo(); | |
| 2308 context_chain_.Add(context_chain_element); | |
| 2309 | |
| 2310 stop = true; | |
| 2311 RecordContextsInChain(&inner_context, with_context, with_context); | |
| 2312 } else if (scope_type == ScopeIterator::ScopeTypeCatch || | |
| 2313 scope_type == ScopeIterator::ScopeTypeWith) { | |
| 2314 Handle<Context> cloned_context = | |
| 2315 Handle<Context>::cast(FixedArray::CopySize( | |
| 2316 it.CurrentContext(), it.CurrentContext()->length())); | |
| 2317 | |
| 2318 ContextChainElement context_chain_element; | |
| 2319 context_chain_element.original_context = it.CurrentContext(); | |
| 2320 context_chain_element.cloned_context = cloned_context; | |
| 2321 context_chain_.Add(context_chain_element); | |
| 2322 | |
| 2323 RecordContextsInChain(&inner_context, cloned_context, cloned_context); | |
| 2324 } else if (scope_type == ScopeIterator::ScopeTypeBlock) { | |
| 2325 Handle<JSObject> materialized_object = | |
| 2326 NewJSObjectWithNullProto(isolate); | |
| 2327 if (!MaterializeStackLocalsWithFrameInspector( | |
| 2328 isolate, materialized_object, it.CurrentScopeInfo(), | |
| 2329 &frame_inspector).ToHandle(&materialized_object)) | |
| 2330 return; | |
| 2331 if (it.HasContext()) { | |
| 2332 Handle<Context> cloned_context = | |
| 2333 Handle<Context>::cast(FixedArray::CopySize( | |
| 2334 it.CurrentContext(), it.CurrentContext()->length())); | |
| 2335 Handle<Context> with_context = isolate->factory()->NewWithContext( | |
| 2336 function, cloned_context, materialized_object); | |
| 2337 | |
| 2338 ContextChainElement context_chain_element; | |
| 2339 context_chain_element.original_context = it.CurrentContext(); | |
| 2340 context_chain_element.cloned_context = cloned_context; | |
| 2341 context_chain_element.materialized_object = materialized_object; | |
| 2342 context_chain_element.scope_info = it.CurrentScopeInfo(); | |
| 2343 context_chain_.Add(context_chain_element); | |
| 2344 | |
| 2345 RecordContextsInChain(&inner_context, cloned_context, with_context); | |
| 2346 } else { | |
| 2347 Handle<Context> with_context = isolate->factory()->NewWithContext( | |
| 2348 function, outer_context, materialized_object); | |
| 2349 | |
| 2350 ContextChainElement context_chain_element; | |
| 2351 context_chain_element.materialized_object = materialized_object; | |
| 2352 context_chain_element.scope_info = it.CurrentScopeInfo(); | |
| 2353 context_chain_.Add(context_chain_element); | |
| 2354 | |
| 2355 RecordContextsInChain(&inner_context, with_context, with_context); | |
| 2356 } | |
| 2357 } else { | |
| 2358 stop = true; | |
| 2359 } | |
| 2360 } | |
| 2361 if (innermost_context_.is_null()) { | |
| 2362 innermost_context_ = outer_context; | |
| 2363 } | |
| 2364 DCHECK(!innermost_context_.is_null()); | |
| 2365 } | |
| 2366 | |
| 2367 void UpdateVariables() { | |
| 2368 for (int i = 0; i < context_chain_.length(); i++) { | |
| 2369 ContextChainElement element = context_chain_[i]; | |
| 2370 if (!element.original_context.is_null() && | |
| 2371 !element.cloned_context.is_null()) { | |
| 2372 Handle<Context> cloned_context = element.cloned_context; | |
| 2373 cloned_context->CopyTo( | |
| 2374 Context::MIN_CONTEXT_SLOTS, *element.original_context, | |
| 2375 Context::MIN_CONTEXT_SLOTS, | |
| 2376 cloned_context->length() - Context::MIN_CONTEXT_SLOTS); | |
| 2377 } | |
| 2378 if (!element.materialized_object.is_null()) { | |
| 2379 // Write back potential changes to materialized stack locals to the | |
| 2380 // stack. | |
| 2381 UpdateStackLocalsFromMaterializedObject( | |
| 2382 isolate_, element.materialized_object, element.scope_info, frame_, | |
| 2383 inlined_jsframe_index_); | |
| 2384 } | |
| 2385 } | |
| 2386 } | |
| 2387 | |
| 2388 Handle<Context> innermost_context() const { return innermost_context_; } | |
| 2389 Handle<SharedFunctionInfo> outer_info() const { return outer_info_; } | |
| 2390 | |
| 2391 private: | |
| 2392 struct ContextChainElement { | |
| 2393 Handle<Context> original_context; | |
| 2394 Handle<Context> cloned_context; | |
| 2395 Handle<JSObject> materialized_object; | |
| 2396 Handle<ScopeInfo> scope_info; | |
| 2397 }; | |
| 2398 | |
| 2399 void RecordContextsInChain(Handle<Context>* inner_context, | |
| 2400 Handle<Context> first, Handle<Context> last) { | |
| 2401 if (!inner_context->is_null()) { | |
| 2402 (*inner_context)->set_previous(*last); | |
| 2403 } else { | |
| 2404 innermost_context_ = last; | |
| 2405 } | |
| 2406 *inner_context = first; | |
| 2407 } | |
| 2408 | |
| 2409 Handle<SharedFunctionInfo> outer_info_; | |
| 2410 Handle<Context> innermost_context_; | |
| 2411 List<ContextChainElement> context_chain_; | |
| 2412 Isolate* isolate_; | |
| 2413 JavaScriptFrame* frame_; | |
| 2414 int inlined_jsframe_index_; | |
| 2415 }; | |
| 2416 } | |
| 2417 | |
| 2418 | |
| 2192 // Evaluate a piece of JavaScript in the context of a stack frame for | 2419 // Evaluate a piece of JavaScript in the context of a stack frame for |
| 2193 // debugging. Things that need special attention are: | 2420 // debugging. Things that need special attention are: |
| 2194 // - Parameters and stack-allocated locals need to be materialized. Altered | 2421 // - Parameters and stack-allocated locals need to be materialized. Altered |
| 2195 // values need to be written back to the stack afterwards. | 2422 // values need to be written back to the stack afterwards. |
| 2196 // - The arguments object needs to materialized. | 2423 // - The arguments object needs to materialized. |
| 2197 RUNTIME_FUNCTION(Runtime_DebugEvaluate) { | 2424 RUNTIME_FUNCTION(Runtime_DebugEvaluate) { |
| 2198 HandleScope scope(isolate); | 2425 HandleScope scope(isolate); |
| 2199 | 2426 |
| 2200 // Check the execution state and decode arguments frame and source to be | 2427 // Check the execution state and decode arguments frame and source to be |
| 2201 // evaluated. | 2428 // evaluated. |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 2218 JavaScriptFrame* frame = it.frame(); | 2445 JavaScriptFrame* frame = it.frame(); |
| 2219 | 2446 |
| 2220 // Traverse the saved contexts chain to find the active context for the | 2447 // Traverse the saved contexts chain to find the active context for the |
| 2221 // selected frame. | 2448 // selected frame. |
| 2222 SaveContext* save = FindSavedContextForFrame(isolate, frame); | 2449 SaveContext* save = FindSavedContextForFrame(isolate, frame); |
| 2223 | 2450 |
| 2224 SaveContext savex(isolate); | 2451 SaveContext savex(isolate); |
| 2225 isolate->set_context(*(save->context())); | 2452 isolate->set_context(*(save->context())); |
| 2226 | 2453 |
| 2227 // Materialize stack locals and the arguments object. | 2454 // Materialize stack locals and the arguments object. |
| 2228 Handle<JSObject> materialized; | |
| 2229 Handle<JSFunction> function; | |
| 2230 Handle<SharedFunctionInfo> outer_info; | |
| 2231 Handle<Context> eval_context; | |
| 2232 | 2455 |
| 2233 // We need to limit the lifetime of the FrameInspector because evaluation can | 2456 EvaluationContextBuilder context_builder(isolate, frame, |
| 2234 // call arbitrary code and only one FrameInspector can be active at a time. | 2457 inlined_jsframe_index); |
| 2235 { | 2458 if (isolate->has_pending_exception()) { |
| 2236 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate); | 2459 return isolate->heap()->exception(); |
| 2237 materialized = NewJSObjectWithNullProto(isolate); | |
| 2238 function = handle(JSFunction::cast(frame_inspector.GetFunction())); | |
| 2239 outer_info = handle(function->shared()); | |
| 2240 eval_context = handle(Context::cast(frame_inspector.GetContext())); | |
| 2241 | |
| 2242 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 2243 isolate, materialized, | |
| 2244 MaterializeStackLocalsWithFrameInspector(isolate, materialized, | |
| 2245 function, &frame_inspector)); | |
| 2246 | |
| 2247 ASSIGN_RETURN_FAILURE_ON_EXCEPTION( | |
| 2248 isolate, materialized, | |
| 2249 MaterializeArgumentsObject(isolate, materialized, function)); | |
| 2250 } | 2460 } |
| 2251 | 2461 |
| 2252 // At this point, the lookup chain may look like this: | |
| 2253 // [inner context] -> [function stack]+[function context] -> [outer context] | |
| 2254 // The function stack is not an actual context, it complements the function | |
| 2255 // context. In order to have the same lookup chain when debug-evaluating, | |
| 2256 // we: | |
| 2257 // - clone inner context | |
| 2258 // - materialize the stack and insert it into the context chain as a | |
| 2259 // with-context before the function context. | |
| 2260 // [inner context clone] -> [with context] -> [function context] -> | |
| 2261 // [outer context] | |
| 2262 // Ordering the with-context before the function context forces a dynamic | |
| 2263 // lookup instead of a static lookup that could fail as the scope info is | |
| 2264 // outdated and may expect variables to still be stack-allocated. | |
| 2265 // Afterwards, we write changes to the with-context back to the stack, and | |
| 2266 // write changes in cloned contexts back to original contexts. | |
| 2267 | |
| 2268 DCHECK(!eval_context.is_null()); | |
| 2269 Handle<Context> function_context = eval_context; | |
| 2270 Handle<Context> outer_context(function->context(), isolate); | |
| 2271 Handle<Context> inner_context; | |
| 2272 Handle<Context> innermost_context; | |
| 2273 | |
| 2274 // We iterate to find the function's context, cloning until we hit it. | |
| 2275 // If the function has no context-allocated variables, we iterate until | |
| 2276 // we hit the outer context. | |
| 2277 while (!function_context->IsFunctionContext() && | |
| 2278 !function_context->IsScriptContext() && | |
| 2279 !function_context.is_identical_to(outer_context)) { | |
| 2280 Handle<Context> clone = Handle<Context>::cast( | |
| 2281 FixedArray::CopySize(function_context, function_context->length())); | |
| 2282 if (!inner_context.is_null()) { | |
| 2283 inner_context->set_previous(*clone); | |
| 2284 } else { | |
| 2285 innermost_context = clone; | |
| 2286 } | |
| 2287 inner_context = clone; | |
| 2288 function_context = Handle<Context>(function_context->previous(), isolate); | |
| 2289 } | |
| 2290 | |
| 2291 Handle<Context> materialized_context = isolate->factory()->NewWithContext( | |
| 2292 function, function_context, materialized); | |
| 2293 | |
| 2294 if (inner_context.is_null()) { | |
| 2295 // No inner context. The with-context is now inner-most. | |
| 2296 innermost_context = materialized_context; | |
| 2297 } else { | |
| 2298 inner_context->set_previous(*materialized_context); | |
| 2299 } | |
| 2300 | 2462 |
| 2301 Handle<Object> receiver(frame->receiver(), isolate); | 2463 Handle<Object> receiver(frame->receiver(), isolate); |
| 2302 MaybeHandle<Object> maybe_result = | 2464 MaybeHandle<Object> maybe_result = DebugEvaluate( |
| 2303 DebugEvaluate(isolate, outer_info, innermost_context, context_extension, | 2465 isolate, context_builder.outer_info(), |
| 2304 receiver, source); | 2466 context_builder.innermost_context(), context_extension, receiver, source); |
| 2305 | 2467 |
| 2306 Handle<Object> result; | 2468 Handle<Object> result; |
| 2307 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result); | 2469 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, result, maybe_result); |
| 2308 | 2470 context_builder.UpdateVariables(); |
| 2309 // Write back potential changes to materialized stack locals to the stack. | |
| 2310 UpdateStackLocalsFromMaterializedObject(isolate, materialized, function, | |
| 2311 frame, inlined_jsframe_index); | |
| 2312 | |
| 2313 while (!innermost_context.is_identical_to(materialized_context)) { | |
| 2314 DCHECK(eval_context->map() == innermost_context->map()); | |
| 2315 innermost_context->CopyTo( | |
| 2316 Context::MIN_CONTEXT_SLOTS, *eval_context, Context::MIN_CONTEXT_SLOTS, | |
| 2317 innermost_context->length() - Context::MIN_CONTEXT_SLOTS); | |
| 2318 innermost_context = handle(innermost_context->previous(), isolate); | |
| 2319 eval_context = handle(eval_context->previous(), isolate); | |
| 2320 } | |
| 2321 | |
| 2322 return *result; | 2471 return *result; |
| 2323 } | 2472 } |
| 2324 | 2473 |
| 2325 | 2474 |
| 2326 RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) { | 2475 RUNTIME_FUNCTION(Runtime_DebugEvaluateGlobal) { |
| 2327 HandleScope scope(isolate); | 2476 HandleScope scope(isolate); |
| 2328 | 2477 |
| 2329 // Check the execution state and decode arguments frame and source to be | 2478 // Check the execution state and decode arguments frame and source to be |
| 2330 // evaluated. | 2479 // evaluated. |
| 2331 DCHECK(args.length() == 4); | 2480 DCHECK(args.length() == 4); |
| (...skipping 505 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2837 return Smi::FromInt(isolate->debug()->is_active()); | 2986 return Smi::FromInt(isolate->debug()->is_active()); |
| 2838 } | 2987 } |
| 2839 | 2988 |
| 2840 | 2989 |
| 2841 RUNTIME_FUNCTION(Runtime_DebugBreakInOptimizedCode) { | 2990 RUNTIME_FUNCTION(Runtime_DebugBreakInOptimizedCode) { |
| 2842 UNIMPLEMENTED(); | 2991 UNIMPLEMENTED(); |
| 2843 return NULL; | 2992 return NULL; |
| 2844 } | 2993 } |
| 2845 } | 2994 } |
| 2846 } // namespace v8::internal | 2995 } // namespace v8::internal |
| OLD | NEW |