Chromium Code Reviews| 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 |