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 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
103 | 103 |
104 Reduction JSNativeContextSpecialization::ReduceNamedAccess( | 104 Reduction JSNativeContextSpecialization::ReduceNamedAccess( |
105 Node* node, Node* value, MapHandleList const& receiver_maps, | 105 Node* node, Node* value, MapHandleList const& receiver_maps, |
106 Handle<Name> name, AccessMode access_mode, LanguageMode language_mode, | 106 Handle<Name> name, AccessMode access_mode, LanguageMode language_mode, |
107 Node* index) { | 107 Node* index) { |
108 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed || | 108 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed || |
109 node->opcode() == IrOpcode::kJSStoreNamed || | 109 node->opcode() == IrOpcode::kJSStoreNamed || |
110 node->opcode() == IrOpcode::kJSLoadProperty || | 110 node->opcode() == IrOpcode::kJSLoadProperty || |
111 node->opcode() == IrOpcode::kJSStoreProperty); | 111 node->opcode() == IrOpcode::kJSStoreProperty); |
112 Node* receiver = NodeProperties::GetValueInput(node, 0); | 112 Node* receiver = NodeProperties::GetValueInput(node, 0); |
| 113 Node* context = NodeProperties::GetContextInput(node); |
| 114 Node* frame_state_eager = NodeProperties::FindFrameStateBefore(node); |
| 115 Node* frame_state_lazy = NodeProperties::GetFrameStateInput(node, 0); |
113 Node* effect = NodeProperties::GetEffectInput(node); | 116 Node* effect = NodeProperties::GetEffectInput(node); |
114 Node* control = NodeProperties::GetControlInput(node); | 117 Node* control = NodeProperties::GetControlInput(node); |
115 | 118 |
116 // Not much we can do if deoptimization support is disabled. | 119 // Not much we can do if deoptimization support is disabled. |
117 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | 120 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); |
118 | 121 |
119 // Retrieve the native context from the given {node}. | 122 // Retrieve the native context from the given {node}. |
120 Handle<Context> native_context; | 123 Handle<Context> native_context; |
121 if (!GetNativeContext(node).ToHandle(&native_context)) return NoChange(); | 124 if (!GetNativeContext(node).ToHandle(&native_context)) return NoChange(); |
122 | 125 |
123 // Compute property access infos for the receiver maps. | 126 // Compute property access infos for the receiver maps. |
124 AccessInfoFactory access_info_factory(dependencies(), native_context, | 127 AccessInfoFactory access_info_factory(dependencies(), native_context, |
125 graph()->zone()); | 128 graph()->zone()); |
126 ZoneVector<PropertyAccessInfo> access_infos(zone()); | 129 ZoneVector<PropertyAccessInfo> access_infos(zone()); |
127 if (!access_info_factory.ComputePropertyAccessInfos( | 130 if (!access_info_factory.ComputePropertyAccessInfos( |
128 receiver_maps, name, access_mode, &access_infos)) { | 131 receiver_maps, name, access_mode, &access_infos)) { |
129 return NoChange(); | 132 return NoChange(); |
130 } | 133 } |
131 | 134 |
| 135 // TODO(turbofan): Add support for inlining into try blocks. |
| 136 if (NodeProperties::IsExceptionalCall(node) || |
| 137 !(flags() & kAccessorInliningEnabled)) { |
| 138 for (auto access_info : access_infos) { |
| 139 if (access_info.IsAccessorConstant()) return NoChange(); |
| 140 } |
| 141 } |
| 142 |
132 // Nothing to do if we have no non-deprecated maps. | 143 // Nothing to do if we have no non-deprecated maps. |
133 if (access_infos.empty()) { | 144 if (access_infos.empty()) { |
134 return ReduceSoftDeoptimize( | 145 return ReduceSoftDeoptimize( |
135 node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess); | 146 node, DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess); |
136 } | 147 } |
137 | 148 |
138 // Ensure that {index} matches the specified {name} (if {index} is given). | 149 // Ensure that {index} matches the specified {name} (if {index} is given). |
139 if (index != nullptr) { | 150 if (index != nullptr) { |
140 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()), | 151 Node* check = graph()->NewNode(simplified()->ReferenceEqual(Type::Name()), |
141 index, jsgraph()->HeapConstant(name)); | 152 index, jsgraph()->HeapConstant(name)); |
(...skipping 13 matching lines...) Expand all Loading... |
155 receiver = effect = graph()->NewNode(simplified()->CheckNumber(), | 166 receiver = effect = graph()->NewNode(simplified()->CheckNumber(), |
156 receiver, effect, control); | 167 receiver, effect, control); |
157 } else { | 168 } else { |
158 // Monomorphic property access. | 169 // Monomorphic property access. |
159 effect = BuildCheckTaggedPointer(receiver, effect, control); | 170 effect = BuildCheckTaggedPointer(receiver, effect, control); |
160 effect = BuildCheckMaps(receiver, effect, control, | 171 effect = BuildCheckMaps(receiver, effect, control, |
161 access_info.receiver_maps()); | 172 access_info.receiver_maps()); |
162 } | 173 } |
163 | 174 |
164 // Generate the actual property access. | 175 // Generate the actual property access. |
165 ValueEffectControl continuation = | 176 ValueEffectControl continuation = BuildPropertyAccess( |
166 BuildPropertyAccess(receiver, value, effect, control, name, | 177 receiver, value, context, frame_state_lazy, effect, control, name, |
167 native_context, access_info, access_mode); | 178 native_context, access_info, access_mode); |
168 value = continuation.value(); | 179 value = continuation.value(); |
169 effect = continuation.effect(); | 180 effect = continuation.effect(); |
170 control = continuation.control(); | 181 control = continuation.control(); |
171 } else { | 182 } else { |
172 // The final states for every polymorphic branch. We join them with | 183 // The final states for every polymorphic branch. We join them with |
173 // Merge+Phi+EffectPhi at the bottom. | 184 // Merge+Phi+EffectPhi at the bottom. |
174 ZoneVector<Node*> values(zone()); | 185 ZoneVector<Node*> values(zone()); |
175 ZoneVector<Node*> effects(zone()); | 186 ZoneVector<Node*> effects(zone()); |
176 ZoneVector<Node*> controls(zone()); | 187 ZoneVector<Node*> controls(zone()); |
177 | 188 |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 // The Number case requires special treatment to also deal with Smis. | 254 // The Number case requires special treatment to also deal with Smis. |
244 if (HasNumberMaps(receiver_maps)) { | 255 if (HasNumberMaps(receiver_maps)) { |
245 // Join this check with the "receiver is smi" check above. | 256 // Join this check with the "receiver is smi" check above. |
246 DCHECK_NOT_NULL(receiverissmi_effect); | 257 DCHECK_NOT_NULL(receiverissmi_effect); |
247 DCHECK_NOT_NULL(receiverissmi_control); | 258 DCHECK_NOT_NULL(receiverissmi_control); |
248 this_effects.push_back(receiverissmi_effect); | 259 this_effects.push_back(receiverissmi_effect); |
249 this_controls.push_back(receiverissmi_control); | 260 this_controls.push_back(receiverissmi_control); |
250 receiverissmi_effect = receiverissmi_control = nullptr; | 261 receiverissmi_effect = receiverissmi_control = nullptr; |
251 } | 262 } |
252 | 263 |
253 // Create dominating Merge+EffectPhi for this {receiver} type. | 264 // Create single chokepoint for the control. |
254 int const this_control_count = static_cast<int>(this_controls.size()); | 265 int const this_control_count = static_cast<int>(this_controls.size()); |
255 this_control = | 266 if (this_control_count == 1) { |
256 (this_control_count == 1) | 267 this_control = this_controls.front(); |
257 ? this_controls.front() | 268 this_effect = this_effects.front(); |
258 : graph()->NewNode(common()->Merge(this_control_count), | 269 } else { |
259 this_control_count, &this_controls.front()); | 270 this_control = |
260 this_effects.push_back(this_control); | 271 graph()->NewNode(common()->Merge(this_control_count), |
261 int const this_effect_count = static_cast<int>(this_effects.size()); | 272 this_control_count, &this_controls.front()); |
262 this_effect = | 273 this_effects.push_back(this_control); |
263 (this_control_count == 1) | 274 this_effect = |
264 ? this_effects.front() | 275 graph()->NewNode(common()->EffectPhi(this_control_count), |
265 : graph()->NewNode(common()->EffectPhi(this_control_count), | 276 this_control_count + 1, &this_effects.front()); |
266 this_effect_count, &this_effects.front()); | 277 |
| 278 // TODO(turbofan): The effect/control linearization will not find a |
| 279 // FrameState after the EffectPhi that is generated above. |
| 280 this_effect = |
| 281 graph()->NewNode(common()->Checkpoint(), frame_state_eager, |
| 282 this_effect, this_control); |
| 283 } |
267 } | 284 } |
268 | 285 |
269 // Generate the actual property access. | 286 // Generate the actual property access. |
270 ValueEffectControl continuation = BuildPropertyAccess( | 287 ValueEffectControl continuation = BuildPropertyAccess( |
271 this_receiver, this_value, this_effect, this_control, name, | 288 this_receiver, this_value, context, frame_state_lazy, this_effect, |
272 native_context, access_info, access_mode); | 289 this_control, name, native_context, access_info, access_mode); |
273 values.push_back(continuation.value()); | 290 values.push_back(continuation.value()); |
274 effects.push_back(continuation.effect()); | 291 effects.push_back(continuation.effect()); |
275 controls.push_back(continuation.control()); | 292 controls.push_back(continuation.control()); |
276 } | 293 } |
277 | 294 |
278 DCHECK_NULL(fallthrough_control); | 295 DCHECK_NULL(fallthrough_control); |
279 | 296 |
280 // Generate the final merge point for all (polymorphic) branches. | 297 // Generate the final merge point for all (polymorphic) branches. |
281 int const control_count = static_cast<int>(controls.size()); | 298 int const control_count = static_cast<int>(controls.size()); |
282 if (control_count == 0) { | 299 if (control_count == 0) { |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
548 } else { | 565 } else { |
549 this_control = | 566 this_control = |
550 graph()->NewNode(common()->Merge(this_control_count), | 567 graph()->NewNode(common()->Merge(this_control_count), |
551 this_control_count, &this_controls.front()); | 568 this_control_count, &this_controls.front()); |
552 this_effects.push_back(this_control); | 569 this_effects.push_back(this_control); |
553 this_effect = | 570 this_effect = |
554 graph()->NewNode(common()->EffectPhi(this_control_count), | 571 graph()->NewNode(common()->EffectPhi(this_control_count), |
555 this_control_count + 1, &this_effects.front()); | 572 this_control_count + 1, &this_effects.front()); |
556 | 573 |
557 // TODO(turbofan): The effect/control linearization will not find a | 574 // TODO(turbofan): The effect/control linearization will not find a |
558 // FrameState after the StoreField or Call that is generated for the | 575 // FrameState after the EffectPhi that is generated above. |
559 // elements kind transition above. This is because those operators | |
560 // don't have the kNoWrite flag on it, even though they are not | |
561 // observable by JavaScript. | |
562 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state, | 576 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state, |
563 this_effect, this_control); | 577 this_effect, this_control); |
564 } | 578 } |
565 } | 579 } |
566 | 580 |
567 // Certain stores need a prototype chain check because shape changes | 581 // Certain stores need a prototype chain check because shape changes |
568 // could allow callbacks on elements in the prototype chain that are | 582 // could allow callbacks on elements in the prototype chain that are |
569 // not compatible with (monomorphic) keyed stores. | 583 // not compatible with (monomorphic) keyed stores. |
570 Handle<JSObject> holder; | 584 Handle<JSObject> holder; |
571 if (access_info.holder().ToHandle(&holder)) { | 585 if (access_info.holder().ToHandle(&holder)) { |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
727 // Extract the keyed access store mode from the KEYED_STORE_IC. | 741 // Extract the keyed access store mode from the KEYED_STORE_IC. |
728 KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode(); | 742 KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode(); |
729 | 743 |
730 // Try to lower the keyed access based on the {nexus}. | 744 // Try to lower the keyed access based on the {nexus}. |
731 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore, | 745 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore, |
732 p.language_mode(), store_mode); | 746 p.language_mode(), store_mode); |
733 } | 747 } |
734 | 748 |
735 JSNativeContextSpecialization::ValueEffectControl | 749 JSNativeContextSpecialization::ValueEffectControl |
736 JSNativeContextSpecialization::BuildPropertyAccess( | 750 JSNativeContextSpecialization::BuildPropertyAccess( |
737 Node* receiver, Node* value, Node* effect, Node* control, Handle<Name> name, | 751 Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect, |
738 Handle<Context> native_context, PropertyAccessInfo const& access_info, | 752 Node* control, Handle<Name> name, Handle<Context> native_context, |
739 AccessMode access_mode) { | 753 PropertyAccessInfo const& access_info, AccessMode access_mode) { |
740 // Determine actual holder and perform prototype chain checks. | 754 // Determine actual holder and perform prototype chain checks. |
741 Handle<JSObject> holder; | 755 Handle<JSObject> holder; |
742 if (access_info.holder().ToHandle(&holder)) { | 756 if (access_info.holder().ToHandle(&holder)) { |
743 AssumePrototypesStable(access_info.receiver_maps(), native_context, holder); | 757 AssumePrototypesStable(access_info.receiver_maps(), native_context, holder); |
744 } | 758 } |
745 | 759 |
746 // Generate the actual property access. | 760 // Generate the actual property access. |
747 if (access_info.IsNotFound()) { | 761 if (access_info.IsNotFound()) { |
748 DCHECK_EQ(AccessMode::kLoad, access_mode); | 762 DCHECK_EQ(AccessMode::kLoad, access_mode); |
749 value = jsgraph()->UndefinedConstant(); | 763 value = jsgraph()->UndefinedConstant(); |
750 } else if (access_info.IsDataConstant()) { | 764 } else if (access_info.IsDataConstant()) { |
751 value = jsgraph()->Constant(access_info.constant()); | 765 value = jsgraph()->Constant(access_info.constant()); |
752 if (access_mode == AccessMode::kStore) { | 766 if (access_mode == AccessMode::kStore) { |
753 Node* check = graph()->NewNode( | 767 Node* check = graph()->NewNode( |
754 simplified()->ReferenceEqual(Type::Tagged()), value, value); | 768 simplified()->ReferenceEqual(Type::Tagged()), value, value); |
755 effect = | 769 effect = |
756 graph()->NewNode(simplified()->CheckIf(), check, effect, control); | 770 graph()->NewNode(simplified()->CheckIf(), check, effect, control); |
757 } | 771 } |
| 772 } else if (access_info.IsAccessorConstant()) { |
| 773 // TODO(bmeurer): Properly rewire the IfException edge here if there's any. |
| 774 Node* target = jsgraph()->Constant(access_info.constant()); |
| 775 FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state); |
| 776 Handle<SharedFunctionInfo> shared_info = |
| 777 frame_info.shared_info().ToHandleChecked(); |
| 778 switch (access_mode) { |
| 779 case AccessMode::kLoad: { |
| 780 // We need a FrameState for the getter stub to restore the correct |
| 781 // context before returning to fullcodegen. |
| 782 FrameStateFunctionInfo const* frame_info0 = |
| 783 common()->CreateFrameStateFunctionInfo(FrameStateType::kGetterStub, |
| 784 1, 0, shared_info); |
| 785 Node* frame_state0 = graph()->NewNode( |
| 786 common()->FrameState(BailoutId::None(), |
| 787 OutputFrameStateCombine::Ignore(), |
| 788 frame_info0), |
| 789 graph()->NewNode(common()->StateValues(1), receiver), |
| 790 jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(), |
| 791 context, target, frame_state); |
| 792 |
| 793 // Introduce the call to the getter function. |
| 794 value = effect = graph()->NewNode( |
| 795 javascript()->CallFunction( |
| 796 2, VectorSlotPair(), ConvertReceiverMode::kNotNullOrUndefined), |
| 797 target, receiver, context, frame_state0, effect, control); |
| 798 control = graph()->NewNode(common()->IfSuccess(), value); |
| 799 break; |
| 800 } |
| 801 case AccessMode::kStore: { |
| 802 // We need a FrameState for the setter stub to restore the correct |
| 803 // context and return the appropriate value to fullcodegen. |
| 804 FrameStateFunctionInfo const* frame_info0 = |
| 805 common()->CreateFrameStateFunctionInfo(FrameStateType::kSetterStub, |
| 806 2, 0, shared_info); |
| 807 Node* frame_state0 = graph()->NewNode( |
| 808 common()->FrameState(BailoutId::None(), |
| 809 OutputFrameStateCombine::Ignore(), |
| 810 frame_info0), |
| 811 graph()->NewNode(common()->StateValues(2), receiver, value), |
| 812 jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(), |
| 813 context, target, frame_state); |
| 814 |
| 815 // Introduce the call to the setter function. |
| 816 effect = graph()->NewNode( |
| 817 javascript()->CallFunction( |
| 818 3, VectorSlotPair(), ConvertReceiverMode::kNotNullOrUndefined), |
| 819 target, receiver, value, context, frame_state0, effect, control); |
| 820 control = graph()->NewNode(common()->IfSuccess(), effect); |
| 821 break; |
| 822 } |
| 823 } |
758 } else { | 824 } else { |
759 DCHECK(access_info.IsDataField()); | 825 DCHECK(access_info.IsDataField()); |
760 FieldIndex const field_index = access_info.field_index(); | 826 FieldIndex const field_index = access_info.field_index(); |
761 Type* const field_type = access_info.field_type(); | 827 Type* const field_type = access_info.field_type(); |
762 if (access_mode == AccessMode::kLoad && | 828 if (access_mode == AccessMode::kLoad && |
763 access_info.holder().ToHandle(&holder)) { | 829 access_info.holder().ToHandle(&holder)) { |
764 receiver = jsgraph()->Constant(holder); | 830 receiver = jsgraph()->Constant(holder); |
765 } | 831 } |
766 Node* storage = receiver; | 832 Node* storage = receiver; |
767 if (!field_index.is_inobject()) { | 833 if (!field_index.is_inobject()) { |
(...skipping 425 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1193 } | 1259 } |
1194 | 1260 |
1195 | 1261 |
1196 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 1262 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
1197 return jsgraph()->simplified(); | 1263 return jsgraph()->simplified(); |
1198 } | 1264 } |
1199 | 1265 |
1200 } // namespace compiler | 1266 } // namespace compiler |
1201 } // namespace internal | 1267 } // namespace internal |
1202 } // namespace v8 | 1268 } // namespace v8 |
OLD | NEW |