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 409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
420 node->opcode() == IrOpcode::kJSStoreProperty); | 420 node->opcode() == IrOpcode::kJSStoreProperty); |
421 Node* receiver = NodeProperties::GetValueInput(node, 0); | 421 Node* receiver = NodeProperties::GetValueInput(node, 0); |
422 Node* effect = NodeProperties::GetEffectInput(node); | 422 Node* effect = NodeProperties::GetEffectInput(node); |
423 Node* control = NodeProperties::GetControlInput(node); | 423 Node* control = NodeProperties::GetControlInput(node); |
424 Node* frame_state = NodeProperties::FindFrameStateBefore(node); | 424 Node* frame_state = NodeProperties::FindFrameStateBefore(node); |
425 | 425 |
426 // Not much we can do if deoptimization support is disabled. | 426 // Not much we can do if deoptimization support is disabled. |
427 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | 427 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); |
428 | 428 |
429 // TODO(bmeurer): Add support for non-standard stores. | 429 // TODO(bmeurer): Add support for non-standard stores. |
430 if (store_mode != STANDARD_STORE) return NoChange(); | 430 if (store_mode != STANDARD_STORE && |
| 431 store_mode != STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { |
| 432 return NoChange(); |
| 433 } |
431 | 434 |
432 // Retrieve the native context from the given {node}. | 435 // Retrieve the native context from the given {node}. |
433 Handle<Context> native_context; | 436 Handle<Context> native_context; |
434 if (!GetNativeContext(node).ToHandle(&native_context)) return NoChange(); | 437 if (!GetNativeContext(node).ToHandle(&native_context)) return NoChange(); |
435 | 438 |
436 // Compute element access infos for the receiver maps. | 439 // Compute element access infos for the receiver maps. |
437 AccessInfoFactory access_info_factory(dependencies(), native_context, | 440 AccessInfoFactory access_info_factory(dependencies(), native_context, |
438 graph()->zone()); | 441 graph()->zone()); |
439 ZoneVector<ElementAccessInfo> access_infos(zone()); | 442 ZoneVector<ElementAccessInfo> access_infos(zone()); |
440 if (!access_info_factory.ComputeElementAccessInfos(receiver_maps, access_mode, | 443 if (!access_info_factory.ComputeElementAccessInfos(receiver_maps, access_mode, |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
475 // don't have the kNoWrite flag on it, even though they are not | 478 // don't have the kNoWrite flag on it, even though they are not |
476 // observable by JavaScript. | 479 // observable by JavaScript. |
477 effect = | 480 effect = |
478 graph()->NewNode(common()->Checkpoint(), frame_state, effect, control); | 481 graph()->NewNode(common()->Checkpoint(), frame_state, effect, control); |
479 | 482 |
480 // Perform map check on the {receiver}. | 483 // Perform map check on the {receiver}. |
481 effect = | 484 effect = |
482 BuildCheckMaps(receiver, effect, control, access_info.receiver_maps()); | 485 BuildCheckMaps(receiver, effect, control, access_info.receiver_maps()); |
483 | 486 |
484 // Access the actual element. | 487 // Access the actual element. |
485 ValueEffectControl continuation = | 488 ValueEffectControl continuation = BuildElementAccess( |
486 BuildElementAccess(receiver, index, value, effect, control, | 489 receiver, index, value, effect, control, native_context, access_info, |
487 native_context, access_info, access_mode); | 490 access_mode, store_mode); |
488 value = continuation.value(); | 491 value = continuation.value(); |
489 effect = continuation.effect(); | 492 effect = continuation.effect(); |
490 control = continuation.control(); | 493 control = continuation.control(); |
491 } else { | 494 } else { |
492 // The final states for every polymorphic branch. We join them with | 495 // The final states for every polymorphic branch. We join them with |
493 // Merge+Phi+EffectPhi at the bottom. | 496 // Merge+Phi+EffectPhi at the bottom. |
494 ZoneVector<Node*> values(zone()); | 497 ZoneVector<Node*> values(zone()); |
495 ZoneVector<Node*> effects(zone()); | 498 ZoneVector<Node*> effects(zone()); |
496 ZoneVector<Node*> controls(zone()); | 499 ZoneVector<Node*> controls(zone()); |
497 | 500 |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
582 // could allow callbacks on elements in the prototype chain that are | 585 // could allow callbacks on elements in the prototype chain that are |
583 // not compatible with (monomorphic) keyed stores. | 586 // not compatible with (monomorphic) keyed stores. |
584 Handle<JSObject> holder; | 587 Handle<JSObject> holder; |
585 if (access_info.holder().ToHandle(&holder)) { | 588 if (access_info.holder().ToHandle(&holder)) { |
586 AssumePrototypesStable(receiver_maps, native_context, holder); | 589 AssumePrototypesStable(receiver_maps, native_context, holder); |
587 } | 590 } |
588 | 591 |
589 // Access the actual element. | 592 // Access the actual element. |
590 ValueEffectControl continuation = BuildElementAccess( | 593 ValueEffectControl continuation = BuildElementAccess( |
591 this_receiver, this_index, this_value, this_effect, this_control, | 594 this_receiver, this_index, this_value, this_effect, this_control, |
592 native_context, access_info, access_mode); | 595 native_context, access_info, access_mode, store_mode); |
593 values.push_back(continuation.value()); | 596 values.push_back(continuation.value()); |
594 effects.push_back(continuation.effect()); | 597 effects.push_back(continuation.effect()); |
595 controls.push_back(continuation.control()); | 598 controls.push_back(continuation.control()); |
596 } | 599 } |
597 | 600 |
598 DCHECK_NULL(fallthrough_control); | 601 DCHECK_NULL(fallthrough_control); |
599 | 602 |
600 // Generate the final merge point for all (polymorphic) branches. | 603 // Generate the final merge point for all (polymorphic) branches. |
601 int const control_count = static_cast<int>(controls.size()); | 604 int const control_count = static_cast<int>(controls.size()); |
602 if (control_count == 0) { | 605 if (control_count == 0) { |
(...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
945 UNREACHABLE(); | 948 UNREACHABLE(); |
946 return kExternalInt8Array; | 949 return kExternalInt8Array; |
947 } | 950 } |
948 | 951 |
949 } // namespace | 952 } // namespace |
950 | 953 |
951 JSNativeContextSpecialization::ValueEffectControl | 954 JSNativeContextSpecialization::ValueEffectControl |
952 JSNativeContextSpecialization::BuildElementAccess( | 955 JSNativeContextSpecialization::BuildElementAccess( |
953 Node* receiver, Node* index, Node* value, Node* effect, Node* control, | 956 Node* receiver, Node* index, Node* value, Node* effect, Node* control, |
954 Handle<Context> native_context, ElementAccessInfo const& access_info, | 957 Handle<Context> native_context, ElementAccessInfo const& access_info, |
955 AccessMode access_mode) { | 958 AccessMode access_mode, KeyedAccessStoreMode store_mode) { |
956 // Determine actual holder and perform prototype chain checks. | 959 // Determine actual holder and perform prototype chain checks. |
957 Handle<JSObject> holder; | 960 Handle<JSObject> holder; |
958 if (access_info.holder().ToHandle(&holder)) { | 961 if (access_info.holder().ToHandle(&holder)) { |
959 AssumePrototypesStable(access_info.receiver_maps(), native_context, holder); | 962 AssumePrototypesStable(access_info.receiver_maps(), native_context, holder); |
960 } | 963 } |
961 | 964 |
962 // TODO(bmeurer): We currently specialize based on elements kind. We should | 965 // TODO(bmeurer): We currently specialize based on elements kind. We should |
963 // also be able to properly support strings and other JSObjects here. | 966 // also be able to properly support strings and other JSObjects here. |
964 ElementsKind elements_kind = access_info.elements_kind(); | 967 ElementsKind elements_kind = access_info.elements_kind(); |
965 MapList const& receiver_maps = access_info.receiver_maps(); | 968 MapList const& receiver_maps = access_info.receiver_maps(); |
(...skipping 29 matching lines...) Expand all Loading... |
995 graph()->NewNode( | 998 graph()->NewNode( |
996 simplified()->NumberBitwiseAnd(), buffer_bitfield, | 999 simplified()->NumberBitwiseAnd(), buffer_bitfield, |
997 jsgraph()->Constant(JSArrayBuffer::WasNeutered::kMask)), | 1000 jsgraph()->Constant(JSArrayBuffer::WasNeutered::kMask)), |
998 jsgraph()->ZeroConstant()); | 1001 jsgraph()->ZeroConstant()); |
999 | 1002 |
1000 // Default to zero if the {receiver}s buffer was neutered. | 1003 // Default to zero if the {receiver}s buffer was neutered. |
1001 length = graph()->NewNode( | 1004 length = graph()->NewNode( |
1002 common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue), | 1005 common()->Select(MachineRepresentation::kTagged, BranchHint::kTrue), |
1003 check, length, jsgraph()->ZeroConstant()); | 1006 check, length, jsgraph()->ZeroConstant()); |
1004 | 1007 |
1005 // Check that the {index} is in the valid range for the {receiver}. | 1008 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { |
1006 index = effect = graph()->NewNode(simplified()->CheckBounds(), index, | 1009 // Check that the {index} is a valid array index, we do the actual |
1007 length, effect, control); | 1010 // bounds check below and just skip the store below if it's out of |
| 1011 // bounds for the {receiver}. |
| 1012 index = effect = graph()->NewNode(simplified()->CheckBounds(), index, |
| 1013 jsgraph()->Constant(Smi::kMaxValue), |
| 1014 effect, control); |
| 1015 } else { |
| 1016 // Check that the {index} is in the valid range for the {receiver}. |
| 1017 DCHECK_EQ(STANDARD_STORE, store_mode); |
| 1018 index = effect = graph()->NewNode(simplified()->CheckBounds(), index, |
| 1019 length, effect, control); |
| 1020 } |
1008 | 1021 |
1009 // Load the base and external pointer for the {receiver}. | 1022 // Load the base and external pointer for the {receiver}. |
1010 Node* base_pointer = effect = graph()->NewNode( | 1023 Node* base_pointer = effect = graph()->NewNode( |
1011 simplified()->LoadField( | 1024 simplified()->LoadField( |
1012 AccessBuilder::ForFixedTypedArrayBaseBasePointer()), | 1025 AccessBuilder::ForFixedTypedArrayBaseBasePointer()), |
1013 elements, effect, control); | 1026 elements, effect, control); |
1014 Node* external_pointer = effect = graph()->NewNode( | 1027 Node* external_pointer = effect = graph()->NewNode( |
1015 simplified()->LoadField( | 1028 simplified()->LoadField( |
1016 AccessBuilder::ForFixedTypedArrayBaseExternalPointer()), | 1029 AccessBuilder::ForFixedTypedArrayBaseExternalPointer()), |
1017 elements, effect, control); | 1030 elements, effect, control); |
1018 | 1031 |
1019 // Access the actual element. | 1032 // Access the actual element. |
1020 ExternalArrayType external_array_type = | 1033 ExternalArrayType external_array_type = |
1021 GetArrayTypeFromElementsKind(elements_kind); | 1034 GetArrayTypeFromElementsKind(elements_kind); |
1022 switch (access_mode) { | 1035 switch (access_mode) { |
1023 case AccessMode::kLoad: { | 1036 case AccessMode::kLoad: { |
1024 value = effect = graph()->NewNode( | 1037 value = effect = graph()->NewNode( |
1025 simplified()->LoadTypedElement(external_array_type), buffer, | 1038 simplified()->LoadTypedElement(external_array_type), buffer, |
1026 base_pointer, external_pointer, index, effect, control); | 1039 base_pointer, external_pointer, index, effect, control); |
1027 break; | 1040 break; |
1028 } | 1041 } |
1029 case AccessMode::kStore: { | 1042 case AccessMode::kStore: { |
1030 // Ensure that the {value} is actually a Number. | 1043 // Ensure that the {value} is actually a Number. |
1031 value = effect = graph()->NewNode(simplified()->CheckNumber(), value, | 1044 value = effect = graph()->NewNode(simplified()->CheckNumber(), value, |
1032 effect, control); | 1045 effect, control); |
1033 effect = graph()->NewNode( | 1046 |
1034 simplified()->StoreTypedElement(external_array_type), buffer, | 1047 // Check if we can skip the out-of-bounds store. |
1035 base_pointer, external_pointer, index, value, effect, control); | 1048 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { |
| 1049 Node* check = |
| 1050 graph()->NewNode(simplified()->NumberLessThan(), index, length); |
| 1051 Node* branch = graph()->NewNode(common()->Branch(BranchHint::kTrue), |
| 1052 check, control); |
| 1053 |
| 1054 Node* if_true = graph()->NewNode(common()->IfTrue(), branch); |
| 1055 Node* etrue = effect; |
| 1056 { |
| 1057 // Perform the actual store. |
| 1058 etrue = graph()->NewNode( |
| 1059 simplified()->StoreTypedElement(external_array_type), buffer, |
| 1060 base_pointer, external_pointer, index, value, etrue, if_true); |
| 1061 } |
| 1062 |
| 1063 Node* if_false = graph()->NewNode(common()->IfFalse(), branch); |
| 1064 Node* efalse = effect; |
| 1065 { |
| 1066 // Just ignore the out-of-bounds write. |
| 1067 } |
| 1068 |
| 1069 control = graph()->NewNode(common()->Merge(2), if_true, if_false); |
| 1070 effect = |
| 1071 graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control); |
| 1072 } else { |
| 1073 // Perform the actual store |
| 1074 DCHECK_EQ(STANDARD_STORE, store_mode); |
| 1075 effect = graph()->NewNode( |
| 1076 simplified()->StoreTypedElement(external_array_type), buffer, |
| 1077 base_pointer, external_pointer, index, value, effect, control); |
| 1078 } |
1036 break; | 1079 break; |
1037 } | 1080 } |
1038 } | 1081 } |
1039 } else { | 1082 } else { |
| 1083 // TODO(turbofan): Add support for additional store modes. |
| 1084 DCHECK_EQ(STANDARD_STORE, store_mode); |
| 1085 |
1040 // Load the length of the {receiver}. | 1086 // Load the length of the {receiver}. |
1041 Node* length = effect = | 1087 Node* length = effect = |
1042 HasOnlyJSArrayMaps(receiver_maps) | 1088 HasOnlyJSArrayMaps(receiver_maps) |
1043 ? graph()->NewNode( | 1089 ? graph()->NewNode( |
1044 simplified()->LoadField( | 1090 simplified()->LoadField( |
1045 AccessBuilder::ForJSArrayLength(elements_kind)), | 1091 AccessBuilder::ForJSArrayLength(elements_kind)), |
1046 receiver, effect, control) | 1092 receiver, effect, control) |
1047 : graph()->NewNode( | 1093 : graph()->NewNode( |
1048 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), | 1094 simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), |
1049 elements, effect, control); | 1095 elements, effect, control); |
1050 | 1096 |
1051 // Check that the {index} is in the valid range for the {receiver}. | 1097 // Check that the {index} is in the valid range for the {receiver}. |
1052 index = effect = graph()->NewNode(simplified()->CheckBounds(), index, | 1098 index = effect = graph()->NewNode(simplified()->CheckBounds(), index, |
1053 length, effect, control); | 1099 length, effect, control); |
1054 | 1100 |
1055 // Compute the element access. | 1101 // Compute the element access. |
1056 Type* element_type = Type::Any(); | 1102 Type* element_type = Type::Any(); |
1057 MachineType element_machine_type = MachineType::AnyTagged(); | 1103 MachineType element_machine_type = MachineType::AnyTagged(); |
1058 if (IsFastDoubleElementsKind(elements_kind)) { | 1104 if (IsFastDoubleElementsKind(elements_kind)) { |
1059 element_type = Type::Number(); | 1105 element_type = Type::Number(); |
1060 element_machine_type = MachineType::Float64(); | 1106 element_machine_type = MachineType::Float64(); |
1061 } else if (IsFastSmiElementsKind(elements_kind)) { | 1107 } else if (IsFastSmiElementsKind(elements_kind)) { |
1062 element_type = type_cache_.kSmi; | 1108 element_type = type_cache_.kSmi; |
1063 } | 1109 } |
1064 ElementAccess element_access = {kTaggedBase, FixedArray::kHeaderSize, | 1110 ElementAccess element_access = {kTaggedBase, FixedArray::kHeaderSize, |
1065 element_type, element_machine_type, | 1111 element_type, element_machine_type, |
1066 kFullWriteBarrier}; | 1112 kFullWriteBarrier}; |
1067 | 1113 |
1068 // Access the actual element. | 1114 // Access the actual element. |
1069 // TODO(bmeurer): Refactor this into separate methods or even a separate | |
1070 // class that deals with the elements access. | |
1071 if (access_mode == AccessMode::kLoad) { | 1115 if (access_mode == AccessMode::kLoad) { |
1072 // Compute the real element access type, which includes the hole in case | 1116 // Compute the real element access type, which includes the hole in case |
1073 // of holey backing stores. | 1117 // of holey backing stores. |
1074 if (elements_kind == FAST_HOLEY_ELEMENTS || | 1118 if (elements_kind == FAST_HOLEY_ELEMENTS || |
1075 elements_kind == FAST_HOLEY_SMI_ELEMENTS) { | 1119 elements_kind == FAST_HOLEY_SMI_ELEMENTS) { |
1076 element_access.type = Type::Union( | 1120 element_access.type = Type::Union( |
1077 element_type, | 1121 element_type, |
1078 Type::Constant(factory()->the_hole_value(), graph()->zone()), | 1122 Type::Constant(factory()->the_hole_value(), graph()->zone()), |
1079 graph()->zone()); | 1123 graph()->zone()); |
1080 } | 1124 } |
(...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1335 } | 1379 } |
1336 | 1380 |
1337 | 1381 |
1338 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 1382 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
1339 return jsgraph()->simplified(); | 1383 return jsgraph()->simplified(); |
1340 } | 1384 } |
1341 | 1385 |
1342 } // namespace compiler | 1386 } // namespace compiler |
1343 } // namespace internal | 1387 } // namespace internal |
1344 } // namespace v8 | 1388 } // namespace v8 |
OLD | NEW |