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