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