| 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 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 95 Node* value = jsgraph()->HeapConstant(native_context()); | 95 Node* value = jsgraph()->HeapConstant(native_context()); |
| 96 ReplaceWithValue(node, value); | 96 ReplaceWithValue(node, value); |
| 97 return Replace(value); | 97 return Replace(value); |
| 98 } | 98 } |
| 99 return NoChange(); | 99 return NoChange(); |
| 100 } | 100 } |
| 101 | 101 |
| 102 Reduction JSNativeContextSpecialization::ReduceNamedAccess( | 102 Reduction JSNativeContextSpecialization::ReduceNamedAccess( |
| 103 Node* node, Node* value, MapHandleList const& receiver_maps, | 103 Node* node, Node* value, MapHandleList const& receiver_maps, |
| 104 Handle<Name> name, AccessMode access_mode, LanguageMode language_mode, | 104 Handle<Name> name, AccessMode access_mode, LanguageMode language_mode, |
| 105 Node* index) { | 105 Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot, Node* index) { |
| 106 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed || | 106 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed || |
| 107 node->opcode() == IrOpcode::kJSStoreNamed || | 107 node->opcode() == IrOpcode::kJSStoreNamed || |
| 108 node->opcode() == IrOpcode::kJSLoadProperty || | 108 node->opcode() == IrOpcode::kJSLoadProperty || |
| 109 node->opcode() == IrOpcode::kJSStoreProperty); | 109 node->opcode() == IrOpcode::kJSStoreProperty); |
| 110 Node* receiver = NodeProperties::GetValueInput(node, 0); | 110 Node* receiver = NodeProperties::GetValueInput(node, 0); |
| 111 Node* context = NodeProperties::GetContextInput(node); | 111 Node* context = NodeProperties::GetContextInput(node); |
| 112 Node* frame_state_eager = NodeProperties::FindFrameStateBefore(node); | 112 Node* frame_state_eager = NodeProperties::FindFrameStateBefore(node); |
| 113 Node* frame_state_lazy = NodeProperties::GetFrameStateInput(node); | 113 Node* frame_state_lazy = NodeProperties::GetFrameStateInput(node); |
| 114 Node* effect = NodeProperties::GetEffectInput(node); | 114 Node* effect = NodeProperties::GetEffectInput(node); |
| 115 Node* control = NodeProperties::GetControlInput(node); | 115 Node* control = NodeProperties::GetControlInput(node); |
| 116 | 116 |
| 117 // Not much we can do if deoptimization support is disabled. | 117 // Not much we can do if deoptimization support is disabled. |
| 118 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | 118 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); |
| 119 | 119 |
| 120 // Compute property access infos for the receiver maps. | 120 // Compute property access infos for the receiver maps. |
| 121 AccessInfoFactory access_info_factory(dependencies(), native_context(), | 121 AccessInfoFactory access_info_factory(dependencies(), native_context(), |
| 122 graph()->zone()); | 122 graph()->zone()); |
| 123 ZoneVector<PropertyAccessInfo> access_infos(zone()); | 123 ZoneVector<PropertyAccessInfo> access_infos(zone()); |
| 124 if (!access_info_factory.ComputePropertyAccessInfos( | 124 if (!access_info_factory.ComputePropertyAccessInfos( |
| 125 receiver_maps, name, access_mode, &access_infos)) { | 125 receiver_maps, name, access_mode, &access_infos)) { |
| 126 return NoChange(); | 126 return NoChange(); |
| 127 } | 127 } |
| 128 | 128 |
| 129 // TODO(turbofan): Add support for inlining into try blocks. | 129 // TODO(turbofan): Add support for inlining into try blocks. |
| 130 if (NodeProperties::IsExceptionalCall(node) || | 130 bool is_exceptional = NodeProperties::IsExceptionalCall(node); |
| 131 !(flags() & kAccessorInliningEnabled)) { | 131 for (auto access_info : access_infos) { |
| 132 for (auto access_info : access_infos) { | 132 if (access_info.IsAccessorConstant()) { |
| 133 if (access_info.IsAccessorConstant()) return NoChange(); | 133 // Accessor in try-blocks are not supported yet. |
| 134 if (is_exceptional || !(flags() & kAccessorInliningEnabled)) { |
| 135 return NoChange(); |
| 136 } |
| 137 } else if (access_info.IsGeneric()) { |
| 138 // We do not handle generic calls in try blocks. |
| 139 if (is_exceptional) return NoChange(); |
| 140 // We only handle the generic store IC case. |
| 141 if (vector->GetKind(slot) != FeedbackVectorSlotKind::STORE_IC) { |
| 142 return NoChange(); |
| 143 } |
| 134 } | 144 } |
| 135 } | 145 } |
| 136 | 146 |
| 137 // Nothing to do if we have no non-deprecated maps. | 147 // Nothing to do if we have no non-deprecated maps. |
| 138 if (access_infos.empty()) { | 148 if (access_infos.empty()) { |
| 139 return ReduceSoftDeoptimize( | 149 return ReduceSoftDeoptimize( |
| 140 node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess); | 150 node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess); |
| 141 } | 151 } |
| 142 | 152 |
| 143 // Ensure that {index} matches the specified {name} (if {index} is given). | 153 // Ensure that {index} matches the specified {name} (if {index} is given). |
| (...skipping 17 matching lines...) Expand all Loading... |
| 161 receiver, effect, control); | 171 receiver, effect, control); |
| 162 } else { | 172 } else { |
| 163 // Monomorphic property access. | 173 // Monomorphic property access. |
| 164 receiver = effect = graph()->NewNode(simplified()->CheckHeapObject(), | 174 receiver = effect = graph()->NewNode(simplified()->CheckHeapObject(), |
| 165 receiver, effect, control); | 175 receiver, effect, control); |
| 166 effect = BuildCheckMaps(receiver, effect, control, | 176 effect = BuildCheckMaps(receiver, effect, control, |
| 167 access_info.receiver_maps()); | 177 access_info.receiver_maps()); |
| 168 } | 178 } |
| 169 | 179 |
| 170 // Generate the actual property access. | 180 // Generate the actual property access. |
| 171 ValueEffectControl continuation = | 181 ValueEffectControl continuation = BuildPropertyAccess( |
| 172 BuildPropertyAccess(receiver, value, context, frame_state_lazy, effect, | 182 receiver, value, context, frame_state_lazy, effect, control, name, |
| 173 control, name, access_info, access_mode); | 183 access_info, access_mode, language_mode, vector, slot); |
| 174 value = continuation.value(); | 184 value = continuation.value(); |
| 175 effect = continuation.effect(); | 185 effect = continuation.effect(); |
| 176 control = continuation.control(); | 186 control = continuation.control(); |
| 177 } else { | 187 } else { |
| 178 // The final states for every polymorphic branch. We join them with | 188 // The final states for every polymorphic branch. We join them with |
| 179 // Merge+Phi+EffectPhi at the bottom. | 189 // Merge+Phi+EffectPhi at the bottom. |
| 180 ZoneVector<Node*> values(zone()); | 190 ZoneVector<Node*> values(zone()); |
| 181 ZoneVector<Node*> effects(zone()); | 191 ZoneVector<Node*> effects(zone()); |
| 182 ZoneVector<Node*> controls(zone()); | 192 ZoneVector<Node*> controls(zone()); |
| 183 | 193 |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 275 // FrameState after the EffectPhi that is generated above. | 285 // FrameState after the EffectPhi that is generated above. |
| 276 this_effect = | 286 this_effect = |
| 277 graph()->NewNode(common()->Checkpoint(), frame_state_eager, | 287 graph()->NewNode(common()->Checkpoint(), frame_state_eager, |
| 278 this_effect, this_control); | 288 this_effect, this_control); |
| 279 } | 289 } |
| 280 } | 290 } |
| 281 | 291 |
| 282 // Generate the actual property access. | 292 // Generate the actual property access. |
| 283 ValueEffectControl continuation = BuildPropertyAccess( | 293 ValueEffectControl continuation = BuildPropertyAccess( |
| 284 this_receiver, this_value, context, frame_state_lazy, this_effect, | 294 this_receiver, this_value, context, frame_state_lazy, this_effect, |
| 285 this_control, name, access_info, access_mode); | 295 this_control, name, access_info, access_mode, language_mode, vector, |
| 296 slot); |
| 286 values.push_back(continuation.value()); | 297 values.push_back(continuation.value()); |
| 287 effects.push_back(continuation.effect()); | 298 effects.push_back(continuation.effect()); |
| 288 controls.push_back(continuation.control()); | 299 controls.push_back(continuation.control()); |
| 289 } | 300 } |
| 290 | 301 |
| 291 DCHECK_NULL(fallthrough_control); | 302 DCHECK_NULL(fallthrough_control); |
| 292 | 303 |
| 293 // Generate the final merge point for all (polymorphic) branches. | 304 // Generate the final merge point for all (polymorphic) branches. |
| 294 int const control_count = static_cast<int>(controls.size()); | 305 int const control_count = static_cast<int>(controls.size()); |
| 295 if (control_count == 0) { | 306 if (control_count == 0) { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 342 (flags() & kBailoutOnUninitialized)) { | 353 (flags() & kBailoutOnUninitialized)) { |
| 343 return ReduceSoftDeoptimize( | 354 return ReduceSoftDeoptimize( |
| 344 node, | 355 node, |
| 345 DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess); | 356 DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess); |
| 346 } | 357 } |
| 347 return NoChange(); | 358 return NoChange(); |
| 348 } | 359 } |
| 349 | 360 |
| 350 // Try to lower the named access based on the {receiver_maps}. | 361 // Try to lower the named access based on the {receiver_maps}. |
| 351 return ReduceNamedAccess(node, value, receiver_maps, name, access_mode, | 362 return ReduceNamedAccess(node, value, receiver_maps, name, access_mode, |
| 352 language_mode); | 363 language_mode, nexus.vector_handle(), nexus.slot()); |
| 353 } | 364 } |
| 354 | 365 |
| 355 | 366 |
| 356 Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) { | 367 Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) { |
| 357 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode()); | 368 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode()); |
| 358 NamedAccess const& p = NamedAccessOf(node->op()); | 369 NamedAccess const& p = NamedAccessOf(node->op()); |
| 359 Node* const receiver = NodeProperties::GetValueInput(node, 0); | 370 Node* const receiver = NodeProperties::GetValueInput(node, 0); |
| 360 Node* const value = jsgraph()->Dead(); | 371 Node* const value = jsgraph()->Dead(); |
| 361 | 372 |
| 362 // Check if we have a constant receiver. | 373 // Check if we have a constant receiver. |
| (...skipping 388 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 751 // so we limit the constant indices to primitives at this point. | 762 // so we limit the constant indices to primitives at this point. |
| 752 Handle<Name> name; | 763 Handle<Name> name; |
| 753 if (Object::ToName(isolate(), mindex.Value()).ToHandle(&name)) { | 764 if (Object::ToName(isolate(), mindex.Value()).ToHandle(&name)) { |
| 754 uint32_t array_index; | 765 uint32_t array_index; |
| 755 if (name->AsArrayIndex(&array_index)) { | 766 if (name->AsArrayIndex(&array_index)) { |
| 756 // Use the constant array index. | 767 // Use the constant array index. |
| 757 index = jsgraph()->Constant(static_cast<double>(array_index)); | 768 index = jsgraph()->Constant(static_cast<double>(array_index)); |
| 758 } else { | 769 } else { |
| 759 name = factory()->InternalizeName(name); | 770 name = factory()->InternalizeName(name); |
| 760 return ReduceNamedAccess(node, value, receiver_maps, name, access_mode, | 771 return ReduceNamedAccess(node, value, receiver_maps, name, access_mode, |
| 761 language_mode); | 772 language_mode, nexus.vector_handle(), |
| 773 nexus.slot()); |
| 762 } | 774 } |
| 763 } | 775 } |
| 764 } | 776 } |
| 765 | 777 |
| 766 // Check if we have feedback for a named access. | 778 // Check if we have feedback for a named access. |
| 767 if (Name* name = nexus.FindFirstName()) { | 779 if (Name* name = nexus.FindFirstName()) { |
| 768 return ReduceNamedAccess(node, value, receiver_maps, | 780 return ReduceNamedAccess( |
| 769 handle(name, isolate()), access_mode, | 781 node, value, receiver_maps, handle(name, isolate()), access_mode, |
| 770 language_mode, index); | 782 language_mode, nexus.vector_handle(), nexus.slot(), index); |
| 771 } else if (nexus.GetKeyType() != ELEMENT) { | 783 } else if (nexus.GetKeyType() != ELEMENT) { |
| 772 // The KeyedLoad/StoreIC has seen non-element accesses, so we cannot assume | 784 // The KeyedLoad/StoreIC has seen non-element accesses, so we cannot assume |
| 773 // that the {index} is a valid array index, thus we just let the IC continue | 785 // that the {index} is a valid array index, thus we just let the IC continue |
| 774 // to deal with this load/store. | 786 // to deal with this load/store. |
| 775 return NoChange(); | 787 return NoChange(); |
| 776 } else if (nexus.ic_state() == MEGAMORPHIC) { | 788 } else if (nexus.ic_state() == MEGAMORPHIC) { |
| 777 // The KeyedLoad/StoreIC uses the MEGAMORPHIC state to guard the assumption | 789 // The KeyedLoad/StoreIC uses the MEGAMORPHIC state to guard the assumption |
| 778 // that a numeric {index} is within the valid bounds for {receiver}, i.e. | 790 // that a numeric {index} is within the valid bounds for {receiver}, i.e. |
| 779 // it transitions to MEGAMORPHIC once it sees an out-of-bounds access. Thus | 791 // it transitions to MEGAMORPHIC once it sees an out-of-bounds access. Thus |
| 780 // we cannot continue here if the IC state is MEGAMORPHIC. | 792 // we cannot continue here if the IC state is MEGAMORPHIC. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 834 | 846 |
| 835 // Try to lower the keyed access based on the {nexus}. | 847 // Try to lower the keyed access based on the {nexus}. |
| 836 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore, | 848 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore, |
| 837 p.language_mode(), store_mode); | 849 p.language_mode(), store_mode); |
| 838 } | 850 } |
| 839 | 851 |
| 840 JSNativeContextSpecialization::ValueEffectControl | 852 JSNativeContextSpecialization::ValueEffectControl |
| 841 JSNativeContextSpecialization::BuildPropertyAccess( | 853 JSNativeContextSpecialization::BuildPropertyAccess( |
| 842 Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect, | 854 Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect, |
| 843 Node* control, Handle<Name> name, PropertyAccessInfo const& access_info, | 855 Node* control, Handle<Name> name, PropertyAccessInfo const& access_info, |
| 844 AccessMode access_mode) { | 856 AccessMode access_mode, LanguageMode language_mode, |
| 857 Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot) { |
| 845 // Determine actual holder and perform prototype chain checks. | 858 // Determine actual holder and perform prototype chain checks. |
| 846 Handle<JSObject> holder; | 859 Handle<JSObject> holder; |
| 847 if (access_info.holder().ToHandle(&holder)) { | 860 if (access_info.holder().ToHandle(&holder)) { |
| 848 AssumePrototypesStable(access_info.receiver_maps(), holder); | 861 AssumePrototypesStable(access_info.receiver_maps(), holder); |
| 849 } | 862 } |
| 850 | 863 |
| 851 // Generate the actual property access. | 864 // Generate the actual property access. |
| 852 if (access_info.IsNotFound()) { | 865 if (access_info.IsNotFound()) { |
| 853 DCHECK_EQ(AccessMode::kLoad, access_mode); | 866 DCHECK_EQ(AccessMode::kLoad, access_mode); |
| 854 value = jsgraph()->UndefinedConstant(); | 867 value = jsgraph()->UndefinedConstant(); |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 936 ValueEffectControl value_effect_control = InlineApiCall( | 949 ValueEffectControl value_effect_control = InlineApiCall( |
| 937 receiver, context, target, frame_state0, &stack_parameters, | 950 receiver, context, target, frame_state0, &stack_parameters, |
| 938 effect, control, shared_info, function_template_info); | 951 effect, control, shared_info, function_template_info); |
| 939 value = value_effect_control.value(); | 952 value = value_effect_control.value(); |
| 940 effect = value_effect_control.effect(); | 953 effect = value_effect_control.effect(); |
| 941 control = value_effect_control.control(); | 954 control = value_effect_control.control(); |
| 942 } | 955 } |
| 943 break; | 956 break; |
| 944 } | 957 } |
| 945 } | 958 } |
| 946 } else { | 959 } else if (access_info.IsDataField()) { |
| 947 DCHECK(access_info.IsDataField()); | |
| 948 FieldIndex const field_index = access_info.field_index(); | 960 FieldIndex const field_index = access_info.field_index(); |
| 949 Type* const field_type = access_info.field_type(); | 961 Type* const field_type = access_info.field_type(); |
| 950 MachineRepresentation const field_representation = | 962 MachineRepresentation const field_representation = |
| 951 access_info.field_representation(); | 963 access_info.field_representation(); |
| 952 if (access_mode == AccessMode::kLoad) { | 964 if (access_mode == AccessMode::kLoad) { |
| 953 if (access_info.holder().ToHandle(&holder)) { | 965 if (access_info.holder().ToHandle(&holder)) { |
| 954 receiver = jsgraph()->Constant(holder); | 966 receiver = jsgraph()->Constant(holder); |
| 955 } | 967 } |
| 956 // Optimize immutable property loads. | 968 // Optimize immutable property loads. |
| 957 HeapObjectMatcher m(receiver); | 969 HeapObjectMatcher m(receiver); |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1089 simplified()->StoreField(AccessBuilder::ForMap()), receiver, | 1101 simplified()->StoreField(AccessBuilder::ForMap()), receiver, |
| 1090 jsgraph()->Constant(transition_map), effect, control); | 1102 jsgraph()->Constant(transition_map), effect, control); |
| 1091 } | 1103 } |
| 1092 effect = graph()->NewNode(simplified()->StoreField(field_access), storage, | 1104 effect = graph()->NewNode(simplified()->StoreField(field_access), storage, |
| 1093 value, effect, control); | 1105 value, effect, control); |
| 1094 if (access_info.HasTransitionMap()) { | 1106 if (access_info.HasTransitionMap()) { |
| 1095 effect = graph()->NewNode(common()->FinishRegion(), | 1107 effect = graph()->NewNode(common()->FinishRegion(), |
| 1096 jsgraph()->UndefinedConstant(), effect); | 1108 jsgraph()->UndefinedConstant(), effect); |
| 1097 } | 1109 } |
| 1098 } | 1110 } |
| 1111 } else { |
| 1112 DCHECK(access_info.IsGeneric()); |
| 1113 DCHECK_EQ(AccessMode::kStore, access_mode); |
| 1114 DCHECK_EQ(FeedbackVectorSlotKind::STORE_IC, vector->GetKind(slot)); |
| 1115 Callable callable = |
| 1116 CodeFactory::StoreICInOptimizedCode(isolate(), language_mode); |
| 1117 const CallInterfaceDescriptor& descriptor = callable.descriptor(); |
| 1118 CallDescriptor* desc = Linkage::GetStubCallDescriptor( |
| 1119 isolate(), graph()->zone(), descriptor, |
| 1120 descriptor.GetStackParameterCount(), CallDescriptor::kNeedsFrameState, |
| 1121 Operator::kNoProperties); |
| 1122 Node* stub_code = jsgraph()->HeapConstant(callable.code()); |
| 1123 Node* name_node = jsgraph()->HeapConstant(name); |
| 1124 Node* slot_node = jsgraph()->Constant(vector->GetIndex(slot)); |
| 1125 Node* vector_node = jsgraph()->HeapConstant(vector); |
| 1126 |
| 1127 Node* inputs[] = {stub_code, receiver, name_node, value, slot_node, |
| 1128 vector_node, context, frame_state, effect, control}; |
| 1129 |
| 1130 value = effect = control = |
| 1131 graph()->NewNode(common()->Call(desc), arraysize(inputs), inputs); |
| 1132 control = graph()->NewNode(common()->IfSuccess(), control); |
| 1099 } | 1133 } |
| 1100 | 1134 |
| 1101 return ValueEffectControl(value, effect, control); | 1135 return ValueEffectControl(value, effect, control); |
| 1102 } | 1136 } |
| 1103 | 1137 |
| 1104 namespace { | 1138 namespace { |
| 1105 | 1139 |
| 1106 ExternalArrayType GetArrayTypeFromElementsKind(ElementsKind kind) { | 1140 ExternalArrayType GetArrayTypeFromElementsKind(ElementsKind kind) { |
| 1107 switch (kind) { | 1141 switch (kind) { |
| 1108 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ | 1142 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ |
| (...skipping 508 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1617 return jsgraph()->javascript(); | 1651 return jsgraph()->javascript(); |
| 1618 } | 1652 } |
| 1619 | 1653 |
| 1620 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 1654 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
| 1621 return jsgraph()->simplified(); | 1655 return jsgraph()->simplified(); |
| 1622 } | 1656 } |
| 1623 | 1657 |
| 1624 } // namespace compiler | 1658 } // namespace compiler |
| 1625 } // namespace internal | 1659 } // namespace internal |
| 1626 } // namespace v8 | 1660 } // namespace v8 |
| OLD | NEW |