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 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
164 // Monormorphic string access (ignoring the fact that there are multiple | 164 // Monormorphic string access (ignoring the fact that there are multiple |
165 // String maps). | 165 // String maps). |
166 receiver = effect = graph()->NewNode(simplified()->CheckString(), | 166 receiver = effect = graph()->NewNode(simplified()->CheckString(), |
167 receiver, effect, control); | 167 receiver, effect, control); |
168 } else if (HasOnlyNumberMaps(access_info.receiver_maps())) { | 168 } else if (HasOnlyNumberMaps(access_info.receiver_maps())) { |
169 // Monomorphic number access (we also deal with Smis here). | 169 // Monomorphic number access (we also deal with Smis here). |
170 receiver = effect = graph()->NewNode(simplified()->CheckNumber(), | 170 receiver = effect = graph()->NewNode(simplified()->CheckNumber(), |
171 receiver, effect, control); | 171 receiver, effect, control); |
172 } else { | 172 } else { |
173 // Monomorphic property access. | 173 // Monomorphic property access. |
174 receiver = effect = graph()->NewNode(simplified()->CheckHeapObject(), | 174 receiver = BuildCheckHeapObject(receiver, &effect, control); |
175 receiver, effect, control); | |
176 effect = BuildCheckMaps(receiver, effect, control, | 175 effect = BuildCheckMaps(receiver, effect, control, |
177 access_info.receiver_maps()); | 176 access_info.receiver_maps()); |
178 } | 177 } |
179 | 178 |
180 // Generate the actual property access. | 179 // Generate the actual property access. |
181 ValueEffectControl continuation = BuildPropertyAccess( | 180 ValueEffectControl continuation = BuildPropertyAccess( |
182 receiver, value, context, frame_state_lazy, effect, control, name, | 181 receiver, value, context, frame_state_lazy, effect, control, name, |
183 access_info, access_mode, language_mode, vector, slot); | 182 access_info, access_mode, language_mode, vector, slot); |
184 value = continuation.value(); | 183 value = continuation.value(); |
185 effect = continuation.effect(); | 184 effect = continuation.effect(); |
(...skipping 17 matching lines...) Expand all Loading... |
203 // Ensure that {receiver} is a heap object. | 202 // Ensure that {receiver} is a heap object. |
204 Node* receiverissmi_control = nullptr; | 203 Node* receiverissmi_control = nullptr; |
205 Node* receiverissmi_effect = effect; | 204 Node* receiverissmi_effect = effect; |
206 if (receiverissmi_possible) { | 205 if (receiverissmi_possible) { |
207 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); | 206 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); |
208 Node* branch = graph()->NewNode(common()->Branch(), check, control); | 207 Node* branch = graph()->NewNode(common()->Branch(), check, control); |
209 control = graph()->NewNode(common()->IfFalse(), branch); | 208 control = graph()->NewNode(common()->IfFalse(), branch); |
210 receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch); | 209 receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch); |
211 receiverissmi_effect = effect; | 210 receiverissmi_effect = effect; |
212 } else { | 211 } else { |
213 receiver = effect = graph()->NewNode(simplified()->CheckHeapObject(), | 212 receiver = BuildCheckHeapObject(receiver, &effect, control); |
214 receiver, effect, control); | |
215 } | 213 } |
216 | 214 |
217 // Load the {receiver} map. The resulting effect is the dominating effect | 215 // Load the {receiver} map. The resulting effect is the dominating effect |
218 // for all (polymorphic) branches. | 216 // for all (polymorphic) branches. |
219 Node* receiver_map = effect = | 217 Node* receiver_map = effect = |
220 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 218 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
221 receiver, effect, control); | 219 receiver, effect, control); |
222 | 220 |
223 // Generate code for the various different property access patterns. | 221 // Generate code for the various different property access patterns. |
224 Node* fallthrough_control = control; | 222 Node* fallthrough_control = control; |
(...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
513 } | 511 } |
514 } | 512 } |
515 | 513 |
516 // Install dependencies on the relevant prototype maps. | 514 // Install dependencies on the relevant prototype maps. |
517 for (Handle<Map> prototype_map : prototype_maps) { | 515 for (Handle<Map> prototype_map : prototype_maps) { |
518 dependencies()->AssumeMapStable(prototype_map); | 516 dependencies()->AssumeMapStable(prototype_map); |
519 } | 517 } |
520 } | 518 } |
521 | 519 |
522 // Ensure that {receiver} is a heap object. | 520 // Ensure that {receiver} is a heap object. |
523 receiver = effect = graph()->NewNode(simplified()->CheckHeapObject(), | 521 receiver = BuildCheckHeapObject(receiver, &effect, control); |
524 receiver, effect, control); | |
525 | 522 |
526 // Check for the monomorphic case. | 523 // Check for the monomorphic case. |
527 if (access_infos.size() == 1) { | 524 if (access_infos.size() == 1) { |
528 ElementAccessInfo access_info = access_infos.front(); | 525 ElementAccessInfo access_info = access_infos.front(); |
529 | 526 |
530 // Perform possible elements kind transitions. | 527 // Perform possible elements kind transitions. |
531 for (auto transition : access_info.transitions()) { | 528 for (auto transition : access_info.transitions()) { |
532 Handle<Map> const transition_source = transition.first; | 529 Handle<Map> const transition_source = transition.first; |
533 Handle<Map> const transition_target = transition.second; | 530 Handle<Map> const transition_target = transition.second; |
534 effect = graph()->NewNode( | 531 effect = graph()->NewNode( |
(...skipping 528 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1063 break; | 1060 break; |
1064 } | 1061 } |
1065 case MachineRepresentation::kTaggedSigned: { | 1062 case MachineRepresentation::kTaggedSigned: { |
1066 value = effect = graph()->NewNode(simplified()->CheckSmi(), value, | 1063 value = effect = graph()->NewNode(simplified()->CheckSmi(), value, |
1067 effect, control); | 1064 effect, control); |
1068 field_access.write_barrier_kind = kNoWriteBarrier; | 1065 field_access.write_barrier_kind = kNoWriteBarrier; |
1069 break; | 1066 break; |
1070 } | 1067 } |
1071 case MachineRepresentation::kTaggedPointer: { | 1068 case MachineRepresentation::kTaggedPointer: { |
1072 // Ensure that {value} is a HeapObject. | 1069 // Ensure that {value} is a HeapObject. |
1073 value = effect = graph()->NewNode(simplified()->CheckHeapObject(), | 1070 value = BuildCheckHeapObject(value, &effect, control); |
1074 value, effect, control); | |
1075 Handle<Map> field_map; | 1071 Handle<Map> field_map; |
1076 if (access_info.field_map().ToHandle(&field_map)) { | 1072 if (access_info.field_map().ToHandle(&field_map)) { |
1077 // Emit a map check for the value. | 1073 // Emit a map check for the value. |
1078 effect = graph()->NewNode(simplified()->CheckMaps(1), value, | 1074 effect = graph()->NewNode(simplified()->CheckMaps(1), value, |
1079 jsgraph()->HeapConstant(field_map), | 1075 jsgraph()->HeapConstant(field_map), |
1080 effect, control); | 1076 effect, control); |
1081 } | 1077 } |
1082 field_access.write_barrier_kind = kPointerWriteBarrier; | 1078 field_access.write_barrier_kind = kPointerWriteBarrier; |
1083 break; | 1079 break; |
1084 } | 1080 } |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1158 JSNativeContextSpecialization::ValueEffectControl | 1154 JSNativeContextSpecialization::ValueEffectControl |
1159 JSNativeContextSpecialization::BuildElementAccess( | 1155 JSNativeContextSpecialization::BuildElementAccess( |
1160 Node* receiver, Node* index, Node* value, Node* effect, Node* control, | 1156 Node* receiver, Node* index, Node* value, Node* effect, Node* control, |
1161 ElementAccessInfo const& access_info, AccessMode access_mode, | 1157 ElementAccessInfo const& access_info, AccessMode access_mode, |
1162 KeyedAccessStoreMode store_mode) { | 1158 KeyedAccessStoreMode store_mode) { |
1163 // TODO(bmeurer): We currently specialize based on elements kind. We should | 1159 // TODO(bmeurer): We currently specialize based on elements kind. We should |
1164 // also be able to properly support strings and other JSObjects here. | 1160 // also be able to properly support strings and other JSObjects here. |
1165 ElementsKind elements_kind = access_info.elements_kind(); | 1161 ElementsKind elements_kind = access_info.elements_kind(); |
1166 MapList const& receiver_maps = access_info.receiver_maps(); | 1162 MapList const& receiver_maps = access_info.receiver_maps(); |
1167 | 1163 |
1168 // Load the elements for the {receiver}. | 1164 if (IsFixedTypedArrayElementsKind(elements_kind)) { |
1169 Node* elements = effect = graph()->NewNode( | 1165 Node* buffer; |
1170 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver, | 1166 Node* length; |
1171 effect, control); | 1167 Node* base_pointer; |
| 1168 Node* external_pointer; |
1172 | 1169 |
1173 // Don't try to store to a copy-on-write backing store. | 1170 // Check if we can constant-fold information about the {receiver} (i.e. |
1174 if (access_mode == AccessMode::kStore && | 1171 // for asm.js-like code patterns). |
1175 IsFastSmiOrObjectElementsKind(elements_kind) && | 1172 HeapObjectMatcher m(receiver); |
1176 store_mode != STORE_NO_TRANSITION_HANDLE_COW) { | 1173 if (m.HasValue() && m.Value()->IsJSTypedArray()) { |
1177 effect = | 1174 Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(m.Value()); |
1178 graph()->NewNode(simplified()->CheckMaps(1), elements, | |
1179 jsgraph()->FixedArrayMapConstant(), effect, control); | |
1180 } | |
1181 | 1175 |
1182 if (IsFixedTypedArrayElementsKind(elements_kind)) { | 1176 // Determine the {receiver}s (known) length. |
1183 // Load the {receiver}s length. | 1177 length = jsgraph()->Constant(typed_array->length_value()); |
1184 Node* length = effect = graph()->NewNode( | |
1185 simplified()->LoadField(AccessBuilder::ForJSTypedArrayLength()), | |
1186 receiver, effect, control); | |
1187 | 1178 |
1188 // Check if the {receiver}s buffer was neutered. | 1179 // Check if the {receiver}s buffer was neutered. |
1189 Node* buffer = effect = graph()->NewNode( | 1180 buffer = jsgraph()->HeapConstant(typed_array->GetBuffer()); |
1190 simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), | 1181 |
1191 receiver, effect, control); | 1182 // Load the (known) base and external pointer for the {receiver}. The |
| 1183 // {external_pointer} might be invalid if the {buffer} was neutered, so |
| 1184 // we need to make sure that any access is properly guarded. |
| 1185 base_pointer = jsgraph()->ZeroConstant(); |
| 1186 external_pointer = jsgraph()->PointerConstant( |
| 1187 FixedTypedArrayBase::cast(typed_array->elements()) |
| 1188 ->external_pointer()); |
| 1189 } else { |
| 1190 // Load the {receiver}s length. |
| 1191 length = effect = graph()->NewNode( |
| 1192 simplified()->LoadField(AccessBuilder::ForJSTypedArrayLength()), |
| 1193 receiver, effect, control); |
| 1194 |
| 1195 // Load the buffer for the {receiver}. |
| 1196 buffer = effect = graph()->NewNode( |
| 1197 simplified()->LoadField(AccessBuilder::ForJSArrayBufferViewBuffer()), |
| 1198 receiver, effect, control); |
| 1199 |
| 1200 // Load the elements for the {receiver}. |
| 1201 Node* elements = effect = graph()->NewNode( |
| 1202 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), |
| 1203 receiver, effect, control); |
| 1204 |
| 1205 // Load the base and external pointer for the {receiver}s {elements}. |
| 1206 base_pointer = effect = graph()->NewNode( |
| 1207 simplified()->LoadField( |
| 1208 AccessBuilder::ForFixedTypedArrayBaseBasePointer()), |
| 1209 elements, effect, control); |
| 1210 external_pointer = effect = graph()->NewNode( |
| 1211 simplified()->LoadField( |
| 1212 AccessBuilder::ForFixedTypedArrayBaseExternalPointer()), |
| 1213 elements, effect, control); |
| 1214 } |
| 1215 |
| 1216 // Default to zero if the {receiver}s buffer was neutered. |
1192 Node* check = effect = graph()->NewNode( | 1217 Node* check = effect = graph()->NewNode( |
1193 simplified()->ArrayBufferWasNeutered(), buffer, effect, control); | 1218 simplified()->ArrayBufferWasNeutered(), buffer, effect, control); |
1194 | |
1195 // Default to zero if the {receiver}s buffer was neutered. | |
1196 length = graph()->NewNode( | 1219 length = graph()->NewNode( |
1197 common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse), | 1220 common()->Select(MachineRepresentation::kTagged, BranchHint::kFalse), |
1198 check, jsgraph()->ZeroConstant(), length); | 1221 check, jsgraph()->ZeroConstant(), length); |
1199 | 1222 |
1200 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { | 1223 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { |
1201 // Check that the {index} is a valid array index, we do the actual | 1224 // Check that the {index} is a valid array index, we do the actual |
1202 // bounds check below and just skip the store below if it's out of | 1225 // bounds check below and just skip the store below if it's out of |
1203 // bounds for the {receiver}. | 1226 // bounds for the {receiver}. |
1204 index = effect = graph()->NewNode(simplified()->CheckBounds(), index, | 1227 index = effect = graph()->NewNode(simplified()->CheckBounds(), index, |
1205 jsgraph()->Constant(Smi::kMaxValue), | 1228 jsgraph()->Constant(Smi::kMaxValue), |
1206 effect, control); | 1229 effect, control); |
1207 } else { | 1230 } else { |
1208 // Check that the {index} is in the valid range for the {receiver}. | 1231 // Check that the {index} is in the valid range for the {receiver}. |
1209 DCHECK_EQ(STANDARD_STORE, store_mode); | 1232 DCHECK_EQ(STANDARD_STORE, store_mode); |
1210 index = effect = graph()->NewNode(simplified()->CheckBounds(), index, | 1233 index = effect = graph()->NewNode(simplified()->CheckBounds(), index, |
1211 length, effect, control); | 1234 length, effect, control); |
1212 } | 1235 } |
1213 | 1236 |
1214 // Load the base and external pointer for the {receiver}. | |
1215 Node* base_pointer = effect = graph()->NewNode( | |
1216 simplified()->LoadField( | |
1217 AccessBuilder::ForFixedTypedArrayBaseBasePointer()), | |
1218 elements, effect, control); | |
1219 Node* external_pointer = effect = graph()->NewNode( | |
1220 simplified()->LoadField( | |
1221 AccessBuilder::ForFixedTypedArrayBaseExternalPointer()), | |
1222 elements, effect, control); | |
1223 | |
1224 // Access the actual element. | 1237 // Access the actual element. |
1225 ExternalArrayType external_array_type = | 1238 ExternalArrayType external_array_type = |
1226 GetArrayTypeFromElementsKind(elements_kind); | 1239 GetArrayTypeFromElementsKind(elements_kind); |
1227 switch (access_mode) { | 1240 switch (access_mode) { |
1228 case AccessMode::kLoad: { | 1241 case AccessMode::kLoad: { |
1229 value = effect = graph()->NewNode( | 1242 value = effect = graph()->NewNode( |
1230 simplified()->LoadTypedElement(external_array_type), buffer, | 1243 simplified()->LoadTypedElement(external_array_type), buffer, |
1231 base_pointer, external_pointer, index, effect, control); | 1244 base_pointer, external_pointer, index, effect, control); |
1232 break; | 1245 break; |
1233 } | 1246 } |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1273 // Perform the actual store | 1286 // Perform the actual store |
1274 DCHECK_EQ(STANDARD_STORE, store_mode); | 1287 DCHECK_EQ(STANDARD_STORE, store_mode); |
1275 effect = graph()->NewNode( | 1288 effect = graph()->NewNode( |
1276 simplified()->StoreTypedElement(external_array_type), buffer, | 1289 simplified()->StoreTypedElement(external_array_type), buffer, |
1277 base_pointer, external_pointer, index, value, effect, control); | 1290 base_pointer, external_pointer, index, value, effect, control); |
1278 } | 1291 } |
1279 break; | 1292 break; |
1280 } | 1293 } |
1281 } | 1294 } |
1282 } else { | 1295 } else { |
| 1296 // Load the elements for the {receiver}. |
| 1297 Node* elements = effect = graph()->NewNode( |
| 1298 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver, |
| 1299 effect, control); |
| 1300 |
| 1301 // Don't try to store to a copy-on-write backing store. |
| 1302 if (access_mode == AccessMode::kStore && |
| 1303 IsFastSmiOrObjectElementsKind(elements_kind) && |
| 1304 store_mode != STORE_NO_TRANSITION_HANDLE_COW) { |
| 1305 effect = |
| 1306 graph()->NewNode(simplified()->CheckMaps(1), elements, |
| 1307 jsgraph()->FixedArrayMapConstant(), effect, control); |
| 1308 } |
| 1309 |
1283 // Check if the {receiver} is a JSArray. | 1310 // Check if the {receiver} is a JSArray. |
1284 bool receiver_is_jsarray = HasOnlyJSArrayMaps(receiver_maps); | 1311 bool receiver_is_jsarray = HasOnlyJSArrayMaps(receiver_maps); |
1285 | 1312 |
1286 // Load the length of the {receiver}. | 1313 // Load the length of the {receiver}. |
1287 Node* length = effect = | 1314 Node* length = effect = |
1288 receiver_is_jsarray | 1315 receiver_is_jsarray |
1289 ? graph()->NewNode( | 1316 ? graph()->NewNode( |
1290 simplified()->LoadField( | 1317 simplified()->LoadField( |
1291 AccessBuilder::ForJSArrayLength(elements_kind)), | 1318 AccessBuilder::ForJSArrayLength(elements_kind)), |
1292 receiver, effect, control) | 1319 receiver, effect, control) |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1461 inputs.push_back(control); | 1488 inputs.push_back(control); |
1462 | 1489 |
1463 Node* effect0; | 1490 Node* effect0; |
1464 Node* value0 = effect0 = | 1491 Node* value0 = effect0 = |
1465 graph()->NewNode(common()->Call(call_descriptor), | 1492 graph()->NewNode(common()->Call(call_descriptor), |
1466 static_cast<int>(inputs.size()), inputs.data()); | 1493 static_cast<int>(inputs.size()), inputs.data()); |
1467 Node* control0 = graph()->NewNode(common()->IfSuccess(), value0); | 1494 Node* control0 = graph()->NewNode(common()->IfSuccess(), value0); |
1468 return ValueEffectControl(value0, effect0, control0); | 1495 return ValueEffectControl(value0, effect0, control0); |
1469 } | 1496 } |
1470 | 1497 |
| 1498 Node* JSNativeContextSpecialization::BuildCheckHeapObject(Node* receiver, |
| 1499 Node** effect, |
| 1500 Node* control) { |
| 1501 switch (receiver->opcode()) { |
| 1502 case IrOpcode::kHeapConstant: |
| 1503 case IrOpcode::kJSCreate: |
| 1504 case IrOpcode::kJSCreateArguments: |
| 1505 case IrOpcode::kJSCreateArray: |
| 1506 case IrOpcode::kJSCreateClosure: |
| 1507 case IrOpcode::kJSCreateIterResultObject: |
| 1508 case IrOpcode::kJSCreateLiteralArray: |
| 1509 case IrOpcode::kJSCreateLiteralObject: |
| 1510 case IrOpcode::kJSCreateLiteralRegExp: |
| 1511 case IrOpcode::kJSConvertReceiver: |
| 1512 case IrOpcode::kJSToName: |
| 1513 case IrOpcode::kJSToString: |
| 1514 case IrOpcode::kJSToObject: |
| 1515 case IrOpcode::kJSTypeOf: { |
| 1516 return receiver; |
| 1517 } |
| 1518 default: { |
| 1519 return *effect = graph()->NewNode(simplified()->CheckHeapObject(), |
| 1520 receiver, *effect, control); |
| 1521 } |
| 1522 } |
| 1523 } |
| 1524 |
1471 Node* JSNativeContextSpecialization::BuildCheckMaps( | 1525 Node* JSNativeContextSpecialization::BuildCheckMaps( |
1472 Node* receiver, Node* effect, Node* control, | 1526 Node* receiver, Node* effect, Node* control, |
1473 std::vector<Handle<Map>> const& maps) { | 1527 std::vector<Handle<Map>> const& maps) { |
1474 HeapObjectMatcher m(receiver); | 1528 HeapObjectMatcher m(receiver); |
1475 if (m.HasValue()) { | 1529 if (m.HasValue()) { |
1476 Handle<Map> receiver_map(m.Value()->map(), isolate()); | 1530 Handle<Map> receiver_map(m.Value()->map(), isolate()); |
1477 if (receiver_map->is_stable()) { | 1531 if (receiver_map->is_stable()) { |
1478 for (Handle<Map> map : maps) { | 1532 for (Handle<Map> map : maps) { |
1479 if (map.is_identical_to(receiver_map)) { | 1533 if (map.is_identical_to(receiver_map)) { |
1480 dependencies()->AssumeMapStable(receiver_map); | 1534 dependencies()->AssumeMapStable(receiver_map); |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1653 return jsgraph()->javascript(); | 1707 return jsgraph()->javascript(); |
1654 } | 1708 } |
1655 | 1709 |
1656 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 1710 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
1657 return jsgraph()->simplified(); | 1711 return jsgraph()->simplified(); |
1658 } | 1712 } |
1659 | 1713 |
1660 } // namespace compiler | 1714 } // namespace compiler |
1661 } // namespace internal | 1715 } // namespace internal |
1662 } // namespace v8 | 1716 } // namespace v8 |
OLD | NEW |