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 563 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
574 graph()->NewNode(common()->EffectPhi(this_control_count), | 574 graph()->NewNode(common()->EffectPhi(this_control_count), |
575 this_control_count + 1, &this_effects.front()); | 575 this_control_count + 1, &this_effects.front()); |
576 | 576 |
577 // TODO(turbofan): The effect/control linearization will not find a | 577 // TODO(turbofan): The effect/control linearization will not find a |
578 // FrameState after the EffectPhi that is generated above. | 578 // FrameState after the EffectPhi that is generated above. |
579 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state, | 579 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state, |
580 this_effect, this_control); | 580 this_effect, this_control); |
581 } | 581 } |
582 } | 582 } |
583 | 583 |
584 // Certain stores need a prototype chain check because shape changes | |
585 // could allow callbacks on elements in the prototype chain that are | |
586 // not compatible with (monomorphic) keyed stores. | |
587 Handle<JSObject> holder; | |
588 if (access_info.holder().ToHandle(&holder)) { | |
589 AssumePrototypesStable(receiver_maps, native_context, holder); | |
590 } | |
591 | |
592 // Access the actual element. | 584 // Access the actual element. |
593 ValueEffectControl continuation = BuildElementAccess( | 585 ValueEffectControl continuation = BuildElementAccess( |
594 this_receiver, this_index, this_value, this_effect, this_control, | 586 this_receiver, this_index, this_value, this_effect, this_control, |
595 native_context, access_info, access_mode, store_mode); | 587 native_context, access_info, access_mode, store_mode); |
596 values.push_back(continuation.value()); | 588 values.push_back(continuation.value()); |
597 effects.push_back(continuation.effect()); | 589 effects.push_back(continuation.effect()); |
598 controls.push_back(continuation.control()); | 590 controls.push_back(continuation.control()); |
599 } | 591 } |
600 | 592 |
601 DCHECK_NULL(fallthrough_control); | 593 DCHECK_NULL(fallthrough_control); |
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
949 return kExternalInt8Array; | 941 return kExternalInt8Array; |
950 } | 942 } |
951 | 943 |
952 } // namespace | 944 } // namespace |
953 | 945 |
954 JSNativeContextSpecialization::ValueEffectControl | 946 JSNativeContextSpecialization::ValueEffectControl |
955 JSNativeContextSpecialization::BuildElementAccess( | 947 JSNativeContextSpecialization::BuildElementAccess( |
956 Node* receiver, Node* index, Node* value, Node* effect, Node* control, | 948 Node* receiver, Node* index, Node* value, Node* effect, Node* control, |
957 Handle<Context> native_context, ElementAccessInfo const& access_info, | 949 Handle<Context> native_context, ElementAccessInfo const& access_info, |
958 AccessMode access_mode, KeyedAccessStoreMode store_mode) { | 950 AccessMode access_mode, KeyedAccessStoreMode store_mode) { |
959 // Determine actual holder and perform prototype chain checks. | |
960 Handle<JSObject> holder; | |
961 if (access_info.holder().ToHandle(&holder)) { | |
962 AssumePrototypesStable(access_info.receiver_maps(), native_context, holder); | |
963 } | |
964 | |
965 // TODO(bmeurer): We currently specialize based on elements kind. We should | 951 // TODO(bmeurer): We currently specialize based on elements kind. We should |
966 // also be able to properly support strings and other JSObjects here. | 952 // also be able to properly support strings and other JSObjects here. |
967 ElementsKind elements_kind = access_info.elements_kind(); | 953 ElementsKind elements_kind = access_info.elements_kind(); |
968 MapList const& receiver_maps = access_info.receiver_maps(); | 954 MapList const& receiver_maps = access_info.receiver_maps(); |
969 | 955 |
970 // Load the elements for the {receiver}. | 956 // Load the elements for the {receiver}. |
971 Node* elements = effect = graph()->NewNode( | 957 Node* elements = effect = graph()->NewNode( |
972 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver, | 958 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver, |
973 effect, control); | 959 effect, control); |
974 | 960 |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1126 value = effect = | 1112 value = effect = |
1127 graph()->NewNode(simplified()->LoadElement(element_access), elements, | 1113 graph()->NewNode(simplified()->LoadElement(element_access), elements, |
1128 index, effect, control); | 1114 index, effect, control); |
1129 // Handle loading from holey backing stores correctly, by either mapping | 1115 // Handle loading from holey backing stores correctly, by either mapping |
1130 // the hole to undefined if possible, or deoptimizing otherwise. | 1116 // the hole to undefined if possible, or deoptimizing otherwise. |
1131 if (elements_kind == FAST_HOLEY_ELEMENTS || | 1117 if (elements_kind == FAST_HOLEY_ELEMENTS || |
1132 elements_kind == FAST_HOLEY_SMI_ELEMENTS) { | 1118 elements_kind == FAST_HOLEY_SMI_ELEMENTS) { |
1133 // Perform the hole check on the result. | 1119 // Perform the hole check on the result. |
1134 CheckTaggedHoleMode mode = CheckTaggedHoleMode::kNeverReturnHole; | 1120 CheckTaggedHoleMode mode = CheckTaggedHoleMode::kNeverReturnHole; |
1135 // Check if we are allowed to turn the hole into undefined. | 1121 // Check if we are allowed to turn the hole into undefined. |
1136 // TODO(bmeurer): We might check the JSArray map from a different | 1122 if (CanTreatHoleAsUndefined(receiver_maps, native_context)) { |
1137 // context here; may need reinvestigation. | |
1138 if (receiver_maps.size() == 1 && | |
1139 receiver_maps[0].is_identical_to( | |
1140 handle(isolate()->get_initial_js_array_map(elements_kind))) && | |
1141 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { | |
1142 // Add a code dependency on the array protector cell. | |
1143 dependencies()->AssumePrototypeMapsStable( | |
1144 receiver_maps[0], isolate()->initial_object_prototype()); | |
1145 dependencies()->AssumePropertyCell(factory()->array_protector()); | |
1146 // Turn the hole into undefined. | 1123 // Turn the hole into undefined. |
1147 mode = CheckTaggedHoleMode::kConvertHoleToUndefined; | 1124 mode = CheckTaggedHoleMode::kConvertHoleToUndefined; |
1148 } | 1125 } |
1149 value = effect = graph()->NewNode(simplified()->CheckTaggedHole(mode), | 1126 value = effect = graph()->NewNode(simplified()->CheckTaggedHole(mode), |
1150 value, effect, control); | 1127 value, effect, control); |
1151 } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) { | 1128 } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) { |
1152 // Perform the hole check on the result. | 1129 // Perform the hole check on the result. |
1153 CheckFloat64HoleMode mode = CheckFloat64HoleMode::kNeverReturnHole; | 1130 CheckFloat64HoleMode mode = CheckFloat64HoleMode::kNeverReturnHole; |
1154 // Check if we are allowed to return the hole directly. | 1131 // Check if we are allowed to return the hole directly. |
1155 // TODO(bmeurer): We might check the JSArray map from a different | 1132 if (CanTreatHoleAsUndefined(receiver_maps, native_context)) { |
1156 // context here; may need reinvestigation. | |
1157 if (receiver_maps.size() == 1 && | |
1158 receiver_maps[0].is_identical_to( | |
1159 handle(isolate()->get_initial_js_array_map(elements_kind))) && | |
1160 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { | |
1161 // Add a code dependency on the array protector cell. | |
1162 dependencies()->AssumePrototypeMapsStable( | |
1163 receiver_maps[0], isolate()->initial_object_prototype()); | |
1164 dependencies()->AssumePropertyCell(factory()->array_protector()); | |
1165 // Return the signaling NaN hole directly if all uses are truncating. | 1133 // Return the signaling NaN hole directly if all uses are truncating. |
1166 mode = CheckFloat64HoleMode::kAllowReturnHole; | 1134 mode = CheckFloat64HoleMode::kAllowReturnHole; |
1167 } | 1135 } |
1168 value = effect = graph()->NewNode(simplified()->CheckFloat64Hole(mode), | 1136 value = effect = graph()->NewNode(simplified()->CheckFloat64Hole(mode), |
1169 value, effect, control); | 1137 value, effect, control); |
1170 } | 1138 } |
1171 } else { | 1139 } else { |
1172 DCHECK_EQ(AccessMode::kStore, access_mode); | 1140 DCHECK_EQ(AccessMode::kStore, access_mode); |
1173 if (IsFastSmiElementsKind(elements_kind)) { | 1141 if (IsFastSmiElementsKind(elements_kind)) { |
1174 value = effect = graph()->NewNode(simplified()->CheckTaggedSigned(), | 1142 value = effect = graph()->NewNode(simplified()->CheckTaggedSigned(), |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1251 // Implemented according to ES6 section 7.3.2 GetV (V, P). | 1219 // Implemented according to ES6 section 7.3.2 GetV (V, P). |
1252 Handle<JSFunction> constructor; | 1220 Handle<JSFunction> constructor; |
1253 if (Map::GetConstructorFunction(map, native_context) | 1221 if (Map::GetConstructorFunction(map, native_context) |
1254 .ToHandle(&constructor)) { | 1222 .ToHandle(&constructor)) { |
1255 map = handle(constructor->initial_map(), isolate()); | 1223 map = handle(constructor->initial_map(), isolate()); |
1256 } | 1224 } |
1257 dependencies()->AssumePrototypeMapsStable(map, holder); | 1225 dependencies()->AssumePrototypeMapsStable(map, holder); |
1258 } | 1226 } |
1259 } | 1227 } |
1260 | 1228 |
1229 bool JSNativeContextSpecialization::CanTreatHoleAsUndefined( | |
1230 std::vector<Handle<Map>> const& receiver_maps, | |
1231 Handle<Context> native_context) { | |
1232 // Check if the array prototype chain is intact. | |
1233 if (!isolate()->IsFastArrayConstructorPrototypeChainIntact()) return false; | |
1234 | |
1235 // Make sure both the initial Array and Object prototypes are stable. | |
1236 Handle<JSObject> initial_array_prototype( | |
1237 native_context->initial_array_prototype(), isolate()); | |
1238 Handle<JSObject> initial_object_prototype( | |
1239 native_context->initial_object_prototype(), isolate()); | |
1240 if (!initial_array_prototype->map()->is_stable() || | |
1241 !initial_object_prototype->map()->is_stable()) { | |
1242 return false; | |
1243 } | |
1244 | |
1245 // Check if all {receiver_maps} either have the initial Array.prototype | |
1246 // or the initial Object.prototype as their prototype, as those are | |
1247 // guarded by the array protector cell. | |
1248 for (Handle<Map> map : receiver_maps) { | |
1249 if (map->prototype() != *initial_array_prototype && | |
1250 map->prototype() != *initial_object_prototype) { | |
1251 return false; | |
1252 } | |
1253 } | |
1254 | |
1255 // Install code dependencies on the prototype maps. | |
1256 for (Handle<Map> map : receiver_maps) { | |
1257 dependencies()->AssumePrototypeMapsStable(map, initial_object_prototype); | |
adamk
2016/08/08 22:02:00
Are you missing a call for initial_array_prototype
| |
1258 } | |
1259 | |
1260 // Install code dependency on the array protector cell. | |
1261 dependencies()->AssumePropertyCell(factory()->array_protector()); | |
1262 return true; | |
1263 } | |
1264 | |
1261 bool JSNativeContextSpecialization::ExtractReceiverMaps( | 1265 bool JSNativeContextSpecialization::ExtractReceiverMaps( |
1262 Node* receiver, Node* effect, FeedbackNexus const& nexus, | 1266 Node* receiver, Node* effect, FeedbackNexus const& nexus, |
1263 MapHandleList* receiver_maps) { | 1267 MapHandleList* receiver_maps) { |
1264 DCHECK_EQ(0, receiver_maps->length()); | 1268 DCHECK_EQ(0, receiver_maps->length()); |
1265 // See if we can infer a concrete type for the {receiver}. | 1269 // See if we can infer a concrete type for the {receiver}. |
1266 Handle<Map> receiver_map; | 1270 Handle<Map> receiver_map; |
1267 if (InferReceiverMap(receiver, effect).ToHandle(&receiver_map)) { | 1271 if (InferReceiverMap(receiver, effect).ToHandle(&receiver_map)) { |
1268 // We can assume that the {receiver} still has the infered {receiver_map}. | 1272 // We can assume that the {receiver} still has the infered {receiver_map}. |
1269 receiver_maps->Add(receiver_map); | 1273 receiver_maps->Add(receiver_map); |
1270 return true; | 1274 return true; |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1379 } | 1383 } |
1380 | 1384 |
1381 | 1385 |
1382 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 1386 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
1383 return jsgraph()->simplified(); | 1387 return jsgraph()->simplified(); |
1384 } | 1388 } |
1385 | 1389 |
1386 } // namespace compiler | 1390 } // namespace compiler |
1387 } // namespace internal | 1391 } // namespace internal |
1388 } // namespace v8 | 1392 } // namespace v8 |
OLD | NEW |