OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 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/compiler/js-native-context-specialization.h" | 5 #include "src/compiler/js-native-context-specialization.h" |
6 | 6 |
7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/compilation-dependencies.h" | 9 #include "src/compilation-dependencies.h" |
10 #include "src/compiler/access-builder.h" | 10 #include "src/compiler/access-builder.h" |
(...skipping 912 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
923 if (access_info.HasTransitionMap()) { | 923 if (access_info.HasTransitionMap()) { |
924 effect = graph()->NewNode(common()->FinishRegion(), | 924 effect = graph()->NewNode(common()->FinishRegion(), |
925 jsgraph()->UndefinedConstant(), effect); | 925 jsgraph()->UndefinedConstant(), effect); |
926 } | 926 } |
927 } | 927 } |
928 } | 928 } |
929 | 929 |
930 return ValueEffectControl(value, effect, control); | 930 return ValueEffectControl(value, effect, control); |
931 } | 931 } |
932 | 932 |
| 933 namespace { |
| 934 |
| 935 ExternalArrayType GetArrayTypeFromElementsKind(ElementsKind kind) { |
| 936 switch (kind) { |
| 937 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ |
| 938 case TYPE##_ELEMENTS: \ |
| 939 return kExternal##Type##Array; |
| 940 TYPED_ARRAYS(TYPED_ARRAY_CASE) |
| 941 #undef TYPED_ARRAY_CASE |
| 942 default: |
| 943 break; |
| 944 } |
| 945 UNREACHABLE(); |
| 946 return kExternalInt8Array; |
| 947 } |
| 948 |
| 949 } // namespace |
| 950 |
933 JSNativeContextSpecialization::ValueEffectControl | 951 JSNativeContextSpecialization::ValueEffectControl |
934 JSNativeContextSpecialization::BuildElementAccess( | 952 JSNativeContextSpecialization::BuildElementAccess( |
935 Node* receiver, Node* index, Node* value, Node* effect, Node* control, | 953 Node* receiver, Node* index, Node* value, Node* effect, Node* control, |
936 Handle<Context> native_context, ElementAccessInfo const& access_info, | 954 Handle<Context> native_context, ElementAccessInfo const& access_info, |
937 AccessMode access_mode) { | 955 AccessMode access_mode) { |
938 // Determine actual holder and perform prototype chain checks. | 956 // Determine actual holder and perform prototype chain checks. |
939 Handle<JSObject> holder; | 957 Handle<JSObject> holder; |
940 if (access_info.holder().ToHandle(&holder)) { | 958 if (access_info.holder().ToHandle(&holder)) { |
941 AssumePrototypesStable(access_info.receiver_maps(), native_context, holder); | 959 AssumePrototypesStable(access_info.receiver_maps(), native_context, holder); |
942 } | 960 } |
(...skipping 13 matching lines...) Expand all Loading... |
956 IsFastSmiOrObjectElementsKind(elements_kind)) { | 974 IsFastSmiOrObjectElementsKind(elements_kind)) { |
957 Node* elements_map = effect = | 975 Node* elements_map = effect = |
958 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 976 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
959 elements, effect, control); | 977 elements, effect, control); |
960 Node* check = graph()->NewNode( | 978 Node* check = graph()->NewNode( |
961 simplified()->ReferenceEqual(Type::Any()), elements_map, | 979 simplified()->ReferenceEqual(Type::Any()), elements_map, |
962 jsgraph()->HeapConstant(factory()->fixed_array_map())); | 980 jsgraph()->HeapConstant(factory()->fixed_array_map())); |
963 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control); | 981 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control); |
964 } | 982 } |
965 | 983 |
966 // Load the length of the {receiver}. | 984 if (IsFixedTypedArrayElementsKind(elements_kind)) { |
967 Node* length = effect = | 985 // Load the {receiver}s length. |
968 HasOnlyJSArrayMaps(receiver_maps) | 986 Node* length = effect = graph()->NewNode( |
969 ? graph()->NewNode( | 987 simplified()->LoadField(AccessBuilder::ForJSTypedArrayLength()), |
970 simplified()->LoadField( | 988 receiver, effect, control); |
971 AccessBuilder::ForJSArrayLength(elements_kind)), | |
972 receiver, effect, control) | |
973 : graph()->NewNode( | |
974 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), | |
975 elements, effect, control); | |
976 | 989 |
977 // Check that the {index} is in the valid range for the {receiver}. | 990 // Check if the {receiver}s buffer was neutered. |
978 index = effect = graph()->NewNode(simplified()->CheckBounds(), index, length, | 991 Node* buffer = effect = graph()->NewNode( |
979 effect, control); | 992 simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), |
| 993 receiver, effect, control); |
| 994 Node* buffer_bitfield = effect = graph()->NewNode( |
| 995 simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()), |
| 996 buffer, effect, control); |
| 997 Node* check = graph()->NewNode( |
| 998 simplified()->NumberEqual(), |
| 999 graph()->NewNode( |
| 1000 simplified()->NumberBitwiseAnd(), buffer_bitfield, |
| 1001 jsgraph()->Constant(JSArrayBuffer::WasNeutered::kMask)), |
| 1002 jsgraph()->ZeroConstant()); |
980 | 1003 |
981 // Compute the element access. | 1004 // Default to zero if the {receiver}s buffer was neutered. |
982 Type* element_type = Type::Any(); | 1005 length = graph()->NewNode( |
983 MachineType element_machine_type = MachineType::AnyTagged(); | 1006 common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue), |
984 if (IsFastDoubleElementsKind(elements_kind)) { | 1007 check, length, jsgraph()->ZeroConstant()); |
985 element_type = Type::Number(); | |
986 element_machine_type = MachineType::Float64(); | |
987 } else if (IsFastSmiElementsKind(elements_kind)) { | |
988 element_type = type_cache_.kSmi; | |
989 } | |
990 ElementAccess element_access = {kTaggedBase, FixedArray::kHeaderSize, | |
991 element_type, element_machine_type, | |
992 kFullWriteBarrier}; | |
993 | 1008 |
994 // Access the actual element. | 1009 // Check that the {index} is in the valid range for the {receiver}. |
995 // TODO(bmeurer): Refactor this into separate methods or even a separate | 1010 index = effect = graph()->NewNode(simplified()->CheckBounds(), index, |
996 // class that deals with the elements access. | 1011 length, effect, control); |
997 if (access_mode == AccessMode::kLoad) { | 1012 |
998 // Compute the real element access type, which includes the hole in case | 1013 // Load the base and external pointer for the {receiver}. |
999 // of holey backing stores. | 1014 Node* base_pointer = effect = graph()->NewNode( |
1000 if (elements_kind == FAST_HOLEY_ELEMENTS || | 1015 simplified()->LoadField( |
1001 elements_kind == FAST_HOLEY_SMI_ELEMENTS) { | 1016 AccessBuilder::ForFixedTypedArrayBaseBasePointer()), |
1002 element_access.type = Type::Union( | 1017 elements, effect, control); |
1003 element_type, | 1018 Node* external_pointer = effect = graph()->NewNode( |
1004 Type::Constant(factory()->the_hole_value(), graph()->zone()), | 1019 simplified()->LoadField( |
1005 graph()->zone()); | 1020 AccessBuilder::ForFixedTypedArrayBaseExternalPointer()), |
1006 } | 1021 elements, effect, control); |
1007 // Perform the actual backing store access. | 1022 |
1008 value = effect = graph()->NewNode(simplified()->LoadElement(element_access), | 1023 // Access the actual element. |
1009 elements, index, effect, control); | 1024 ExternalArrayType external_array_type = |
1010 // Handle loading from holey backing stores correctly, by either mapping | 1025 GetArrayTypeFromElementsKind(elements_kind); |
1011 // the hole to undefined if possible, or deoptimizing otherwise. | 1026 switch (access_mode) { |
1012 if (elements_kind == FAST_HOLEY_ELEMENTS || | 1027 case AccessMode::kLoad: { |
1013 elements_kind == FAST_HOLEY_SMI_ELEMENTS) { | 1028 value = effect = graph()->NewNode( |
1014 // Perform the hole check on the result. | 1029 simplified()->LoadTypedElement(external_array_type), buffer, |
1015 CheckTaggedHoleMode mode = CheckTaggedHoleMode::kNeverReturnHole; | 1030 base_pointer, external_pointer, index, effect, control); |
1016 // Check if we are allowed to turn the hole into undefined. | 1031 break; |
1017 // TODO(bmeurer): We might check the JSArray map from a different | |
1018 // context here; may need reinvestigation. | |
1019 if (receiver_maps.size() == 1 && | |
1020 receiver_maps[0].is_identical_to( | |
1021 handle(isolate()->get_initial_js_array_map(elements_kind))) && | |
1022 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { | |
1023 // Add a code dependency on the array protector cell. | |
1024 dependencies()->AssumePrototypeMapsStable( | |
1025 receiver_maps[0], isolate()->initial_object_prototype()); | |
1026 dependencies()->AssumePropertyCell(factory()->array_protector()); | |
1027 // Turn the hole into undefined. | |
1028 mode = CheckTaggedHoleMode::kConvertHoleToUndefined; | |
1029 } | 1032 } |
1030 value = effect = graph()->NewNode(simplified()->CheckTaggedHole(mode), | 1033 case AccessMode::kStore: { |
1031 value, effect, control); | 1034 // Ensure that the {value} is actually a Number. |
1032 } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) { | 1035 value = effect = graph()->NewNode(simplified()->CheckNumber(), value, |
1033 // Perform the hole check on the result. | 1036 effect, control); |
1034 CheckFloat64HoleMode mode = CheckFloat64HoleMode::kNeverReturnHole; | 1037 effect = graph()->NewNode( |
1035 // Check if we are allowed to return the hole directly. | 1038 simplified()->StoreTypedElement(external_array_type), buffer, |
1036 // TODO(bmeurer): We might check the JSArray map from a different | 1039 base_pointer, external_pointer, index, value, effect, control); |
1037 // context here; may need reinvestigation. | 1040 break; |
1038 if (receiver_maps.size() == 1 && | |
1039 receiver_maps[0].is_identical_to( | |
1040 handle(isolate()->get_initial_js_array_map(elements_kind))) && | |
1041 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { | |
1042 // Add a code dependency on the array protector cell. | |
1043 dependencies()->AssumePrototypeMapsStable( | |
1044 receiver_maps[0], isolate()->initial_object_prototype()); | |
1045 dependencies()->AssumePropertyCell(factory()->array_protector()); | |
1046 // Return the signaling NaN hole directly if all uses are truncating. | |
1047 mode = CheckFloat64HoleMode::kAllowReturnHole; | |
1048 } | 1041 } |
1049 value = effect = graph()->NewNode(simplified()->CheckFloat64Hole(mode), | |
1050 value, effect, control); | |
1051 } | 1042 } |
1052 } else { | 1043 } else { |
1053 DCHECK_EQ(AccessMode::kStore, access_mode); | 1044 // Load the length of the {receiver}. |
1054 if (IsFastSmiElementsKind(elements_kind)) { | 1045 Node* length = effect = |
1055 value = effect = graph()->NewNode(simplified()->CheckTaggedSigned(), | 1046 HasOnlyJSArrayMaps(receiver_maps) |
1056 value, effect, control); | 1047 ? graph()->NewNode( |
1057 } else if (IsFastDoubleElementsKind(elements_kind)) { | 1048 simplified()->LoadField( |
| 1049 AccessBuilder::ForJSArrayLength(elements_kind)), |
| 1050 receiver, effect, control) |
| 1051 : graph()->NewNode( |
| 1052 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), |
| 1053 elements, effect, control); |
| 1054 |
| 1055 // Check that the {index} is in the valid range for the {receiver}. |
| 1056 index = effect = graph()->NewNode(simplified()->CheckBounds(), index, |
| 1057 length, effect, control); |
| 1058 |
| 1059 // Compute the element access. |
| 1060 Type* element_type = Type::Any(); |
| 1061 MachineType element_machine_type = MachineType::AnyTagged(); |
| 1062 if (IsFastDoubleElementsKind(elements_kind)) { |
| 1063 element_type = Type::Number(); |
| 1064 element_machine_type = MachineType::Float64(); |
| 1065 } else if (IsFastSmiElementsKind(elements_kind)) { |
| 1066 element_type = type_cache_.kSmi; |
| 1067 } |
| 1068 ElementAccess element_access = {kTaggedBase, FixedArray::kHeaderSize, |
| 1069 element_type, element_machine_type, |
| 1070 kFullWriteBarrier}; |
| 1071 |
| 1072 // Access the actual element. |
| 1073 // TODO(bmeurer): Refactor this into separate methods or even a separate |
| 1074 // class that deals with the elements access. |
| 1075 if (access_mode == AccessMode::kLoad) { |
| 1076 // Compute the real element access type, which includes the hole in case |
| 1077 // of holey backing stores. |
| 1078 if (elements_kind == FAST_HOLEY_ELEMENTS || |
| 1079 elements_kind == FAST_HOLEY_SMI_ELEMENTS) { |
| 1080 element_access.type = Type::Union( |
| 1081 element_type, |
| 1082 Type::Constant(factory()->the_hole_value(), graph()->zone()), |
| 1083 graph()->zone()); |
| 1084 } |
| 1085 // Perform the actual backing store access. |
1058 value = effect = | 1086 value = effect = |
1059 graph()->NewNode(simplified()->CheckNumber(), value, effect, control); | 1087 graph()->NewNode(simplified()->LoadElement(element_access), elements, |
1060 // Make sure we do not store signalling NaNs into double arrays. | 1088 index, effect, control); |
1061 value = graph()->NewNode(simplified()->NumberSilenceNaN(), value); | 1089 // Handle loading from holey backing stores correctly, by either mapping |
| 1090 // the hole to undefined if possible, or deoptimizing otherwise. |
| 1091 if (elements_kind == FAST_HOLEY_ELEMENTS || |
| 1092 elements_kind == FAST_HOLEY_SMI_ELEMENTS) { |
| 1093 // Perform the hole check on the result. |
| 1094 CheckTaggedHoleMode mode = CheckTaggedHoleMode::kNeverReturnHole; |
| 1095 // Check if we are allowed to turn the hole into undefined. |
| 1096 // TODO(bmeurer): We might check the JSArray map from a different |
| 1097 // context here; may need reinvestigation. |
| 1098 if (receiver_maps.size() == 1 && |
| 1099 receiver_maps[0].is_identical_to( |
| 1100 handle(isolate()->get_initial_js_array_map(elements_kind))) && |
| 1101 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { |
| 1102 // Add a code dependency on the array protector cell. |
| 1103 dependencies()->AssumePrototypeMapsStable( |
| 1104 receiver_maps[0], isolate()->initial_object_prototype()); |
| 1105 dependencies()->AssumePropertyCell(factory()->array_protector()); |
| 1106 // Turn the hole into undefined. |
| 1107 mode = CheckTaggedHoleMode::kConvertHoleToUndefined; |
| 1108 } |
| 1109 value = effect = graph()->NewNode(simplified()->CheckTaggedHole(mode), |
| 1110 value, effect, control); |
| 1111 } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) { |
| 1112 // Perform the hole check on the result. |
| 1113 CheckFloat64HoleMode mode = CheckFloat64HoleMode::kNeverReturnHole; |
| 1114 // Check if we are allowed to return the hole directly. |
| 1115 // TODO(bmeurer): We might check the JSArray map from a different |
| 1116 // context here; may need reinvestigation. |
| 1117 if (receiver_maps.size() == 1 && |
| 1118 receiver_maps[0].is_identical_to( |
| 1119 handle(isolate()->get_initial_js_array_map(elements_kind))) && |
| 1120 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { |
| 1121 // Add a code dependency on the array protector cell. |
| 1122 dependencies()->AssumePrototypeMapsStable( |
| 1123 receiver_maps[0], isolate()->initial_object_prototype()); |
| 1124 dependencies()->AssumePropertyCell(factory()->array_protector()); |
| 1125 // Return the signaling NaN hole directly if all uses are truncating. |
| 1126 mode = CheckFloat64HoleMode::kAllowReturnHole; |
| 1127 } |
| 1128 value = effect = graph()->NewNode(simplified()->CheckFloat64Hole(mode), |
| 1129 value, effect, control); |
| 1130 } |
| 1131 } else { |
| 1132 DCHECK_EQ(AccessMode::kStore, access_mode); |
| 1133 if (IsFastSmiElementsKind(elements_kind)) { |
| 1134 value = effect = graph()->NewNode(simplified()->CheckTaggedSigned(), |
| 1135 value, effect, control); |
| 1136 } else if (IsFastDoubleElementsKind(elements_kind)) { |
| 1137 value = effect = graph()->NewNode(simplified()->CheckNumber(), value, |
| 1138 effect, control); |
| 1139 // Make sure we do not store signalling NaNs into double arrays. |
| 1140 value = graph()->NewNode(simplified()->NumberSilenceNaN(), value); |
| 1141 } |
| 1142 effect = graph()->NewNode(simplified()->StoreElement(element_access), |
| 1143 elements, index, value, effect, control); |
1062 } | 1144 } |
1063 effect = graph()->NewNode(simplified()->StoreElement(element_access), | |
1064 elements, index, value, effect, control); | |
1065 } | 1145 } |
1066 | 1146 |
1067 return ValueEffectControl(value, effect, control); | 1147 return ValueEffectControl(value, effect, control); |
1068 } | 1148 } |
1069 | 1149 |
1070 Node* JSNativeContextSpecialization::BuildCheckMaps( | 1150 Node* JSNativeContextSpecialization::BuildCheckMaps( |
1071 Node* receiver, Node* effect, Node* control, | 1151 Node* receiver, Node* effect, Node* control, |
1072 std::vector<Handle<Map>> const& maps) { | 1152 std::vector<Handle<Map>> const& maps) { |
1073 HeapObjectMatcher m(receiver); | 1153 HeapObjectMatcher m(receiver); |
1074 if (m.HasValue()) { | 1154 if (m.HasValue()) { |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1259 } | 1339 } |
1260 | 1340 |
1261 | 1341 |
1262 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 1342 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
1263 return jsgraph()->simplified(); | 1343 return jsgraph()->simplified(); |
1264 } | 1344 } |
1265 | 1345 |
1266 } // namespace compiler | 1346 } // namespace compiler |
1267 } // namespace internal | 1347 } // namespace internal |
1268 } // namespace v8 | 1348 } // namespace v8 |
OLD | NEW |