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