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