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 |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 receiver = effect = graph()->NewNode(simplified()->CheckNumber(), | 158 receiver = effect = graph()->NewNode(simplified()->CheckNumber(), |
156 receiver, effect, control); | 159 receiver, effect, control); |
157 } else { | 160 } else { |
158 // Monomorphic property access. | 161 // Monomorphic property access. |
159 effect = BuildCheckTaggedPointer(receiver, effect, control); | 162 effect = BuildCheckTaggedPointer(receiver, effect, control); |
160 effect = BuildCheckMaps(receiver, effect, control, | 163 effect = BuildCheckMaps(receiver, effect, control, |
161 access_info.receiver_maps()); | 164 access_info.receiver_maps()); |
162 } | 165 } |
163 | 166 |
164 // Generate the actual property access. | 167 // Generate the actual property access. |
165 ValueEffectControl continuation = | 168 ValueEffectControl continuation = BuildPropertyAccess( |
166 BuildPropertyAccess(receiver, value, effect, control, name, | 169 receiver, value, context, frame_state_lazy, effect, control, name, |
167 native_context, access_info, access_mode); | 170 native_context, access_info, access_mode); |
168 value = continuation.value(); | 171 value = continuation.value(); |
169 effect = continuation.effect(); | 172 effect = continuation.effect(); |
170 control = continuation.control(); | 173 control = continuation.control(); |
171 } else { | 174 } else { |
172 // The final states for every polymorphic branch. We join them with | 175 // The final states for every polymorphic branch. We join them with |
173 // Merge+Phi+EffectPhi at the bottom. | 176 // Merge+Phi+EffectPhi at the bottom. |
174 ZoneVector<Node*> values(zone()); | 177 ZoneVector<Node*> values(zone()); |
175 ZoneVector<Node*> effects(zone()); | 178 ZoneVector<Node*> effects(zone()); |
176 ZoneVector<Node*> controls(zone()); | 179 ZoneVector<Node*> controls(zone()); |
177 | 180 |
(...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. | 246 // The Number case requires special treatment to also deal with Smis. |
244 if (HasNumberMaps(receiver_maps)) { | 247 if (HasNumberMaps(receiver_maps)) { |
245 // Join this check with the "receiver is smi" check above. | 248 // Join this check with the "receiver is smi" check above. |
246 DCHECK_NOT_NULL(receiverissmi_effect); | 249 DCHECK_NOT_NULL(receiverissmi_effect); |
247 DCHECK_NOT_NULL(receiverissmi_control); | 250 DCHECK_NOT_NULL(receiverissmi_control); |
248 this_effects.push_back(receiverissmi_effect); | 251 this_effects.push_back(receiverissmi_effect); |
249 this_controls.push_back(receiverissmi_control); | 252 this_controls.push_back(receiverissmi_control); |
250 receiverissmi_effect = receiverissmi_control = nullptr; | 253 receiverissmi_effect = receiverissmi_control = nullptr; |
251 } | 254 } |
252 | 255 |
253 // Create dominating Merge+EffectPhi for this {receiver} type. | 256 // Create single chokepoint for the control. |
254 int const this_control_count = static_cast<int>(this_controls.size()); | 257 int const this_control_count = static_cast<int>(this_controls.size()); |
255 this_control = | 258 if (this_control_count == 1) { |
256 (this_control_count == 1) | 259 this_control = this_controls.front(); |
257 ? this_controls.front() | 260 this_effect = this_effects.front(); |
258 : graph()->NewNode(common()->Merge(this_control_count), | 261 } else { |
259 this_control_count, &this_controls.front()); | 262 this_control = |
260 this_effects.push_back(this_control); | 263 graph()->NewNode(common()->Merge(this_control_count), |
261 int const this_effect_count = static_cast<int>(this_effects.size()); | 264 this_control_count, &this_controls.front()); |
262 this_effect = | 265 this_effects.push_back(this_control); |
263 (this_control_count == 1) | 266 this_effect = |
264 ? this_effects.front() | 267 graph()->NewNode(common()->EffectPhi(this_control_count), |
265 : graph()->NewNode(common()->EffectPhi(this_control_count), | 268 this_control_count + 1, &this_effects.front()); |
266 this_effect_count, &this_effects.front()); | 269 |
| 270 // TODO(turbofan): The effect/control linearization will not find a |
| 271 // FrameState after the EffectPhi that is generated above. |
| 272 this_effect = |
| 273 graph()->NewNode(common()->Checkpoint(), frame_state_eager, |
| 274 this_effect, this_control); |
| 275 } |
267 } | 276 } |
268 | 277 |
269 // Generate the actual property access. | 278 // Generate the actual property access. |
270 ValueEffectControl continuation = BuildPropertyAccess( | 279 ValueEffectControl continuation = BuildPropertyAccess( |
271 this_receiver, this_value, this_effect, this_control, name, | 280 this_receiver, this_value, context, frame_state_lazy, this_effect, |
272 native_context, access_info, access_mode); | 281 this_control, name, native_context, access_info, access_mode); |
273 values.push_back(continuation.value()); | 282 values.push_back(continuation.value()); |
274 effects.push_back(continuation.effect()); | 283 effects.push_back(continuation.effect()); |
275 controls.push_back(continuation.control()); | 284 controls.push_back(continuation.control()); |
276 } | 285 } |
277 | 286 |
278 DCHECK_NULL(fallthrough_control); | 287 DCHECK_NULL(fallthrough_control); |
279 | 288 |
280 // Generate the final merge point for all (polymorphic) branches. | 289 // Generate the final merge point for all (polymorphic) branches. |
281 int const control_count = static_cast<int>(controls.size()); | 290 int const control_count = static_cast<int>(controls.size()); |
282 if (control_count == 0) { | 291 if (control_count == 0) { |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
548 } else { | 557 } else { |
549 this_control = | 558 this_control = |
550 graph()->NewNode(common()->Merge(this_control_count), | 559 graph()->NewNode(common()->Merge(this_control_count), |
551 this_control_count, &this_controls.front()); | 560 this_control_count, &this_controls.front()); |
552 this_effects.push_back(this_control); | 561 this_effects.push_back(this_control); |
553 this_effect = | 562 this_effect = |
554 graph()->NewNode(common()->EffectPhi(this_control_count), | 563 graph()->NewNode(common()->EffectPhi(this_control_count), |
555 this_control_count + 1, &this_effects.front()); | 564 this_control_count + 1, &this_effects.front()); |
556 | 565 |
557 // TODO(turbofan): The effect/control linearization will not find a | 566 // TODO(turbofan): The effect/control linearization will not find a |
558 // FrameState after the StoreField or Call that is generated for the | 567 // 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, | 568 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state, |
563 this_effect, this_control); | 569 this_effect, this_control); |
564 } | 570 } |
565 } | 571 } |
566 | 572 |
567 // Certain stores need a prototype chain check because shape changes | 573 // Certain stores need a prototype chain check because shape changes |
568 // could allow callbacks on elements in the prototype chain that are | 574 // could allow callbacks on elements in the prototype chain that are |
569 // not compatible with (monomorphic) keyed stores. | 575 // not compatible with (monomorphic) keyed stores. |
570 Handle<JSObject> holder; | 576 Handle<JSObject> holder; |
571 if (access_info.holder().ToHandle(&holder)) { | 577 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. | 733 // Extract the keyed access store mode from the KEYED_STORE_IC. |
728 KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode(); | 734 KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode(); |
729 | 735 |
730 // Try to lower the keyed access based on the {nexus}. | 736 // Try to lower the keyed access based on the {nexus}. |
731 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore, | 737 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore, |
732 p.language_mode(), store_mode); | 738 p.language_mode(), store_mode); |
733 } | 739 } |
734 | 740 |
735 JSNativeContextSpecialization::ValueEffectControl | 741 JSNativeContextSpecialization::ValueEffectControl |
736 JSNativeContextSpecialization::BuildPropertyAccess( | 742 JSNativeContextSpecialization::BuildPropertyAccess( |
737 Node* receiver, Node* value, Node* effect, Node* control, Handle<Name> name, | 743 Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect, |
738 Handle<Context> native_context, PropertyAccessInfo const& access_info, | 744 Node* control, Handle<Name> name, Handle<Context> native_context, |
739 AccessMode access_mode) { | 745 PropertyAccessInfo const& access_info, AccessMode access_mode) { |
740 // Determine actual holder and perform prototype chain checks. | 746 // Determine actual holder and perform prototype chain checks. |
741 Handle<JSObject> holder; | 747 Handle<JSObject> holder; |
742 if (access_info.holder().ToHandle(&holder)) { | 748 if (access_info.holder().ToHandle(&holder)) { |
743 AssumePrototypesStable(access_info.receiver_maps(), native_context, holder); | 749 AssumePrototypesStable(access_info.receiver_maps(), native_context, holder); |
744 } | 750 } |
745 | 751 |
746 // Generate the actual property access. | 752 // Generate the actual property access. |
747 if (access_info.IsNotFound()) { | 753 if (access_info.IsNotFound()) { |
748 DCHECK_EQ(AccessMode::kLoad, access_mode); | 754 DCHECK_EQ(AccessMode::kLoad, access_mode); |
749 value = jsgraph()->UndefinedConstant(); | 755 value = jsgraph()->UndefinedConstant(); |
750 } else if (access_info.IsDataConstant()) { | 756 } else if (access_info.IsDataConstant()) { |
751 value = jsgraph()->Constant(access_info.constant()); | 757 value = jsgraph()->Constant(access_info.constant()); |
752 if (access_mode == AccessMode::kStore) { | 758 if (access_mode == AccessMode::kStore) { |
753 Node* check = graph()->NewNode( | 759 Node* check = graph()->NewNode( |
754 simplified()->ReferenceEqual(Type::Tagged()), value, value); | 760 simplified()->ReferenceEqual(Type::Tagged()), value, value); |
755 effect = | 761 effect = |
756 graph()->NewNode(simplified()->CheckIf(), check, effect, control); | 762 graph()->NewNode(simplified()->CheckIf(), check, effect, control); |
757 } | 763 } |
| 764 } else if (access_info.IsAccessorConstant()) { |
| 765 // TODO(bmeurer): Properly rewire the IfException edge here if there's any. |
| 766 Node* target = jsgraph()->Constant(access_info.constant()); |
| 767 FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state); |
| 768 Handle<SharedFunctionInfo> shared_info = |
| 769 frame_info.shared_info().ToHandleChecked(); |
| 770 switch (access_mode) { |
| 771 case AccessMode::kLoad: { |
| 772 // We need a FrameState for the getter stub to restore the correct |
| 773 // context before returning to fullcodegen. |
| 774 FrameStateFunctionInfo const* frame_info0 = |
| 775 common()->CreateFrameStateFunctionInfo(FrameStateType::kGetterStub, |
| 776 1, 0, shared_info); |
| 777 Node* frame_state0 = graph()->NewNode( |
| 778 common()->FrameState(BailoutId::None(), |
| 779 OutputFrameStateCombine::Ignore(), |
| 780 frame_info0), |
| 781 graph()->NewNode(common()->StateValues(1), receiver), |
| 782 jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(), |
| 783 context, target, frame_state); |
| 784 |
| 785 // Introduce the call to the getter function. |
| 786 value = effect = graph()->NewNode( |
| 787 javascript()->CallFunction( |
| 788 2, VectorSlotPair(), ConvertReceiverMode::kNotNullOrUndefined), |
| 789 target, receiver, context, frame_state0, effect, control); |
| 790 control = graph()->NewNode(common()->IfSuccess(), value); |
| 791 break; |
| 792 } |
| 793 case AccessMode::kStore: { |
| 794 // We need a FrameState for the setter stub to restore the correct |
| 795 // context and return the appropriate value to fullcodegen. |
| 796 FrameStateFunctionInfo const* frame_info0 = |
| 797 common()->CreateFrameStateFunctionInfo(FrameStateType::kSetterStub, |
| 798 2, 0, shared_info); |
| 799 Node* frame_state0 = graph()->NewNode( |
| 800 common()->FrameState(BailoutId::None(), |
| 801 OutputFrameStateCombine::Ignore(), |
| 802 frame_info0), |
| 803 graph()->NewNode(common()->StateValues(2), receiver, value), |
| 804 jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(), |
| 805 context, target, frame_state); |
| 806 |
| 807 // Introduce the call to the setter function. |
| 808 effect = graph()->NewNode( |
| 809 javascript()->CallFunction( |
| 810 3, VectorSlotPair(), ConvertReceiverMode::kNotNullOrUndefined), |
| 811 target, receiver, value, context, frame_state0, effect, control); |
| 812 control = graph()->NewNode(common()->IfSuccess(), effect); |
| 813 break; |
| 814 } |
| 815 } |
758 } else { | 816 } else { |
759 DCHECK(access_info.IsDataField()); | 817 DCHECK(access_info.IsDataField()); |
760 FieldIndex const field_index = access_info.field_index(); | 818 FieldIndex const field_index = access_info.field_index(); |
761 Type* const field_type = access_info.field_type(); | 819 Type* const field_type = access_info.field_type(); |
762 if (access_mode == AccessMode::kLoad && | 820 if (access_mode == AccessMode::kLoad && |
763 access_info.holder().ToHandle(&holder)) { | 821 access_info.holder().ToHandle(&holder)) { |
764 receiver = jsgraph()->Constant(holder); | 822 receiver = jsgraph()->Constant(holder); |
765 } | 823 } |
766 Node* storage = receiver; | 824 Node* storage = receiver; |
767 if (!field_index.is_inobject()) { | 825 if (!field_index.is_inobject()) { |
(...skipping 425 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1193 } | 1251 } |
1194 | 1252 |
1195 | 1253 |
1196 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 1254 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
1197 return jsgraph()->simplified(); | 1255 return jsgraph()->simplified(); |
1198 } | 1256 } |
1199 | 1257 |
1200 } // namespace compiler | 1258 } // namespace compiler |
1201 } // namespace internal | 1259 } // namespace internal |
1202 } // namespace v8 | 1260 } // namespace v8 |
OLD | NEW |