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 |