| 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" |
| 11 #include "src/compiler/access-info.h" | 11 #include "src/compiler/access-info.h" |
| 12 #include "src/compiler/js-graph.h" | 12 #include "src/compiler/js-graph.h" |
| 13 #include "src/compiler/js-operator.h" | 13 #include "src/compiler/js-operator.h" |
| 14 #include "src/compiler/linkage.h" | 14 #include "src/compiler/linkage.h" |
| 15 #include "src/compiler/node-matchers.h" | 15 #include "src/compiler/node-matchers.h" |
| 16 #include "src/compiler/property-access-builder.h" |
| 16 #include "src/compiler/type-cache.h" | 17 #include "src/compiler/type-cache.h" |
| 17 #include "src/feedback-vector.h" | 18 #include "src/feedback-vector.h" |
| 18 #include "src/field-index-inl.h" | 19 #include "src/field-index-inl.h" |
| 19 #include "src/isolate-inl.h" | 20 #include "src/isolate-inl.h" |
| 20 | 21 |
| 21 namespace v8 { | 22 namespace v8 { |
| 22 namespace internal { | 23 namespace internal { |
| 23 namespace compiler { | 24 namespace compiler { |
| 24 | 25 |
| 25 namespace { | 26 namespace { |
| 26 | 27 |
| 27 bool HasNumberMaps(MapHandles const& maps) { | 28 bool HasNumberMaps(MapHandles const& maps) { |
| 28 for (auto map : maps) { | 29 for (auto map : maps) { |
| 29 if (map->instance_type() == HEAP_NUMBER_TYPE) return true; | 30 if (map->instance_type() == HEAP_NUMBER_TYPE) return true; |
| 30 } | 31 } |
| 31 return false; | 32 return false; |
| 32 } | 33 } |
| 33 | 34 |
| 34 bool HasOnlyJSArrayMaps(MapHandles const& maps) { | 35 bool HasOnlyJSArrayMaps(MapHandles const& maps) { |
| 35 for (auto map : maps) { | 36 for (auto map : maps) { |
| 36 if (!map->IsJSArrayMap()) return false; | 37 if (!map->IsJSArrayMap()) return false; |
| 37 } | 38 } |
| 38 return true; | 39 return true; |
| 39 } | 40 } |
| 40 | 41 |
| 41 bool HasOnlyNumberMaps(MapHandles const& maps) { | |
| 42 for (auto map : maps) { | |
| 43 if (map->instance_type() != HEAP_NUMBER_TYPE) return false; | |
| 44 } | |
| 45 return true; | |
| 46 } | |
| 47 | |
| 48 bool HasOnlyStringMaps(MapHandles const& maps) { | 42 bool HasOnlyStringMaps(MapHandles const& maps) { |
| 49 for (auto map : maps) { | 43 for (auto map : maps) { |
| 50 if (!map->IsStringMap()) return false; | 44 if (!map->IsStringMap()) return false; |
| 51 } | 45 } |
| 52 return true; | 46 return true; |
| 53 } | 47 } |
| 54 | 48 |
| 55 bool HasOnlySequentialStringMaps(MapHandles const& maps) { | |
| 56 for (auto map : maps) { | |
| 57 if (!map->IsStringMap()) return false; | |
| 58 if (!StringShape(map->instance_type()).IsSequential()) { | |
| 59 return false; | |
| 60 } | |
| 61 } | |
| 62 return true; | |
| 63 } | |
| 64 | |
| 65 } // namespace | 49 } // namespace |
| 66 | 50 |
| 67 struct JSNativeContextSpecialization::ScriptContextTableLookupResult { | 51 struct JSNativeContextSpecialization::ScriptContextTableLookupResult { |
| 68 Handle<Context> context; | 52 Handle<Context> context; |
| 69 bool immutable; | 53 bool immutable; |
| 70 int index; | 54 int index; |
| 71 }; | 55 }; |
| 72 | 56 |
| 73 JSNativeContextSpecialization::JSNativeContextSpecialization( | 57 JSNativeContextSpecialization::JSNativeContextSpecialization( |
| 74 Editor* editor, JSGraph* jsgraph, Flags flags, | 58 Editor* editor, JSGraph* jsgraph, Flags flags, |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 186 // Compute property access info for @@hasInstance on {receiver}. | 170 // Compute property access info for @@hasInstance on {receiver}. |
| 187 PropertyAccessInfo access_info; | 171 PropertyAccessInfo access_info; |
| 188 AccessInfoFactory access_info_factory(dependencies(), native_context(), | 172 AccessInfoFactory access_info_factory(dependencies(), native_context(), |
| 189 graph()->zone()); | 173 graph()->zone()); |
| 190 if (!access_info_factory.ComputePropertyAccessInfo( | 174 if (!access_info_factory.ComputePropertyAccessInfo( |
| 191 receiver_map, factory()->has_instance_symbol(), AccessMode::kLoad, | 175 receiver_map, factory()->has_instance_symbol(), AccessMode::kLoad, |
| 192 &access_info)) { | 176 &access_info)) { |
| 193 return NoChange(); | 177 return NoChange(); |
| 194 } | 178 } |
| 195 | 179 |
| 180 PropertyAccessBuilder access_builder(jsgraph(), dependencies()); |
| 181 |
| 196 if (access_info.IsNotFound()) { | 182 if (access_info.IsNotFound()) { |
| 197 // If there's no @@hasInstance handler, the OrdinaryHasInstance operation | 183 // If there's no @@hasInstance handler, the OrdinaryHasInstance operation |
| 198 // takes over, but that requires the {receiver} to be callable. | 184 // takes over, but that requires the {receiver} to be callable. |
| 199 if (receiver->IsCallable()) { | 185 if (receiver->IsCallable()) { |
| 200 // Determine actual holder and perform prototype chain checks. | 186 // Determine actual holder and perform prototype chain checks. |
| 201 Handle<JSObject> holder; | 187 Handle<JSObject> holder; |
| 202 if (access_info.holder().ToHandle(&holder)) { | 188 if (access_info.holder().ToHandle(&holder)) { |
| 203 AssumePrototypesStable(access_info.receiver_maps(), holder); | 189 access_builder.AssumePrototypesStable( |
| 190 native_context(), access_info.receiver_maps(), holder); |
| 204 } | 191 } |
| 205 | 192 |
| 206 // Monomorphic property access. | 193 // Monomorphic property access. |
| 207 effect = BuildCheckMaps(constructor, effect, control, | 194 access_builder.BuildCheckMaps(constructor, &effect, control, |
| 208 access_info.receiver_maps()); | 195 access_info.receiver_maps()); |
| 209 | 196 |
| 210 // Lower to OrdinaryHasInstance(C, O). | 197 // Lower to OrdinaryHasInstance(C, O). |
| 211 NodeProperties::ReplaceValueInput(node, constructor, 0); | 198 NodeProperties::ReplaceValueInput(node, constructor, 0); |
| 212 NodeProperties::ReplaceValueInput(node, object, 1); | 199 NodeProperties::ReplaceValueInput(node, object, 1); |
| 213 NodeProperties::ReplaceEffectInput(node, effect); | 200 NodeProperties::ReplaceEffectInput(node, effect); |
| 214 NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance()); | 201 NodeProperties::ChangeOp(node, javascript()->OrdinaryHasInstance()); |
| 215 Reduction const reduction = ReduceJSOrdinaryHasInstance(node); | 202 Reduction const reduction = ReduceJSOrdinaryHasInstance(node); |
| 216 return reduction.Changed() ? reduction : Changed(node); | 203 return reduction.Changed() ? reduction : Changed(node); |
| 217 } | 204 } |
| 218 } else if (access_info.IsDataConstant() || | 205 } else if (access_info.IsDataConstant() || |
| 219 access_info.IsDataConstantField()) { | 206 access_info.IsDataConstantField()) { |
| 220 // Determine actual holder and perform prototype chain checks. | 207 // Determine actual holder and perform prototype chain checks. |
| 221 Handle<JSObject> holder; | 208 Handle<JSObject> holder; |
| 222 if (access_info.holder().ToHandle(&holder)) { | 209 if (access_info.holder().ToHandle(&holder)) { |
| 223 AssumePrototypesStable(access_info.receiver_maps(), holder); | 210 access_builder.AssumePrototypesStable( |
| 211 native_context(), access_info.receiver_maps(), holder); |
| 224 } else { | 212 } else { |
| 225 holder = receiver; | 213 holder = receiver; |
| 226 } | 214 } |
| 227 | 215 |
| 228 Handle<Object> constant; | 216 Handle<Object> constant; |
| 229 if (access_info.IsDataConstant()) { | 217 if (access_info.IsDataConstant()) { |
| 230 DCHECK(!FLAG_track_constant_fields); | 218 DCHECK(!FLAG_track_constant_fields); |
| 231 constant = access_info.constant(); | 219 constant = access_info.constant(); |
| 232 } else { | 220 } else { |
| 233 DCHECK(FLAG_track_constant_fields); | 221 DCHECK(FLAG_track_constant_fields); |
| 234 DCHECK(access_info.IsDataConstantField()); | 222 DCHECK(access_info.IsDataConstantField()); |
| 235 // The value must be callable therefore tagged. | 223 // The value must be callable therefore tagged. |
| 236 DCHECK(CanBeTaggedPointer(access_info.field_representation())); | 224 DCHECK(CanBeTaggedPointer(access_info.field_representation())); |
| 237 FieldIndex field_index = access_info.field_index(); | 225 FieldIndex field_index = access_info.field_index(); |
| 238 constant = JSObject::FastPropertyAt(holder, Representation::Tagged(), | 226 constant = JSObject::FastPropertyAt(holder, Representation::Tagged(), |
| 239 field_index); | 227 field_index); |
| 240 } | 228 } |
| 241 DCHECK(constant->IsCallable()); | 229 DCHECK(constant->IsCallable()); |
| 242 | 230 |
| 243 // Monomorphic property access. | 231 // Monomorphic property access. |
| 244 effect = BuildCheckMaps(constructor, effect, control, | 232 access_builder.BuildCheckMaps(constructor, &effect, control, |
| 245 access_info.receiver_maps()); | 233 access_info.receiver_maps()); |
| 246 | 234 |
| 247 // Call the @@hasInstance handler. | 235 // Call the @@hasInstance handler. |
| 248 Node* target = jsgraph()->Constant(constant); | 236 Node* target = jsgraph()->Constant(constant); |
| 249 node->InsertInput(graph()->zone(), 0, target); | 237 node->InsertInput(graph()->zone(), 0, target); |
| 250 node->ReplaceInput(1, constructor); | 238 node->ReplaceInput(1, constructor); |
| 251 node->ReplaceInput(2, object); | 239 node->ReplaceInput(2, object); |
| 252 node->ReplaceInput(5, effect); | 240 node->ReplaceInput(5, effect); |
| 253 NodeProperties::ChangeOp( | 241 NodeProperties::ChangeOp( |
| 254 node, javascript()->Call(3, CallFrequency(), VectorSlotPair(), | 242 node, javascript()->Call(3, CallFrequency(), VectorSlotPair(), |
| 255 ConvertReceiverMode::kNotNullOrUndefined)); | 243 ConvertReceiverMode::kNotNullOrUndefined)); |
| (...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 634 } | 622 } |
| 635 | 623 |
| 636 // Collect call nodes to rewire exception edges. | 624 // Collect call nodes to rewire exception edges. |
| 637 ZoneVector<Node*> if_exception_nodes(zone()); | 625 ZoneVector<Node*> if_exception_nodes(zone()); |
| 638 ZoneVector<Node*>* if_exceptions = nullptr; | 626 ZoneVector<Node*>* if_exceptions = nullptr; |
| 639 Node* if_exception = nullptr; | 627 Node* if_exception = nullptr; |
| 640 if (NodeProperties::IsExceptionalCall(node, &if_exception)) { | 628 if (NodeProperties::IsExceptionalCall(node, &if_exception)) { |
| 641 if_exceptions = &if_exception_nodes; | 629 if_exceptions = &if_exception_nodes; |
| 642 } | 630 } |
| 643 | 631 |
| 632 PropertyAccessBuilder access_builder(jsgraph(), dependencies()); |
| 633 |
| 644 // Check for the monomorphic cases. | 634 // Check for the monomorphic cases. |
| 645 if (access_infos.size() == 1) { | 635 if (access_infos.size() == 1) { |
| 646 PropertyAccessInfo access_info = access_infos.front(); | 636 PropertyAccessInfo access_info = access_infos.front(); |
| 647 if (HasOnlyStringMaps(access_info.receiver_maps())) { | 637 // Try to build string check or number check if possible. |
| 648 if (HasOnlySequentialStringMaps(access_info.receiver_maps())) { | 638 // Otherwise build a map check. |
| 649 receiver = effect = graph()->NewNode(simplified()->CheckSeqString(), | 639 if (!access_builder.TryBuildStringCheck(access_info.receiver_maps(), |
| 650 receiver, effect, control); | 640 &receiver, &effect, control) && |
| 651 } else { | 641 !access_builder.TryBuildNumberCheck(access_info.receiver_maps(), |
| 652 // Monormorphic string access (ignoring the fact that there are multiple | 642 &receiver, &effect, control)) { |
| 653 // String maps). | 643 receiver = |
| 654 receiver = effect = graph()->NewNode(simplified()->CheckString(), | 644 access_builder.BuildCheckHeapObject(receiver, &effect, control); |
| 655 receiver, effect, control); | 645 access_builder.BuildCheckMaps(receiver, &effect, control, |
| 656 } | 646 access_info.receiver_maps()); |
| 657 | |
| 658 } else if (HasOnlyNumberMaps(access_info.receiver_maps())) { | |
| 659 // Monomorphic number access (we also deal with Smis here). | |
| 660 receiver = effect = graph()->NewNode(simplified()->CheckNumber(), | |
| 661 receiver, effect, control); | |
| 662 } else { | |
| 663 // Monomorphic property access. | |
| 664 receiver = BuildCheckHeapObject(receiver, &effect, control); | |
| 665 effect = BuildCheckMaps(receiver, effect, control, | |
| 666 access_info.receiver_maps()); | |
| 667 } | 647 } |
| 668 | 648 |
| 669 // Generate the actual property access. | 649 // Generate the actual property access. |
| 670 ValueEffectControl continuation = BuildPropertyAccess( | 650 ValueEffectControl continuation = BuildPropertyAccess( |
| 671 receiver, value, context, frame_state, effect, control, name, | 651 receiver, value, context, frame_state, effect, control, name, |
| 672 if_exceptions, access_info, access_mode, language_mode); | 652 if_exceptions, access_info, access_mode, language_mode); |
| 673 value = continuation.value(); | 653 value = continuation.value(); |
| 674 effect = continuation.effect(); | 654 effect = continuation.effect(); |
| 675 control = continuation.control(); | 655 control = continuation.control(); |
| 676 } else { | 656 } else { |
| (...skipping 15 matching lines...) Expand all Loading... |
| 692 // Ensure that {receiver} is a heap object. | 672 // Ensure that {receiver} is a heap object. |
| 693 Node* receiverissmi_control = nullptr; | 673 Node* receiverissmi_control = nullptr; |
| 694 Node* receiverissmi_effect = effect; | 674 Node* receiverissmi_effect = effect; |
| 695 if (receiverissmi_possible) { | 675 if (receiverissmi_possible) { |
| 696 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); | 676 Node* check = graph()->NewNode(simplified()->ObjectIsSmi(), receiver); |
| 697 Node* branch = graph()->NewNode(common()->Branch(), check, control); | 677 Node* branch = graph()->NewNode(common()->Branch(), check, control); |
| 698 control = graph()->NewNode(common()->IfFalse(), branch); | 678 control = graph()->NewNode(common()->IfFalse(), branch); |
| 699 receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch); | 679 receiverissmi_control = graph()->NewNode(common()->IfTrue(), branch); |
| 700 receiverissmi_effect = effect; | 680 receiverissmi_effect = effect; |
| 701 } else { | 681 } else { |
| 702 receiver = BuildCheckHeapObject(receiver, &effect, control); | 682 receiver = |
| 683 access_builder.BuildCheckHeapObject(receiver, &effect, control); |
| 703 } | 684 } |
| 704 | 685 |
| 705 // Load the {receiver} map. The resulting effect is the dominating effect | 686 // Load the {receiver} map. The resulting effect is the dominating effect |
| 706 // for all (polymorphic) branches. | 687 // for all (polymorphic) branches. |
| 707 Node* receiver_map = effect = | 688 Node* receiver_map = effect = |
| 708 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 689 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 709 receiver, effect, control); | 690 receiver, effect, control); |
| 710 | 691 |
| 711 // Generate code for the various different property access patterns. | 692 // Generate code for the various different property access patterns. |
| 712 Node* fallthrough_control = control; | 693 Node* fallthrough_control = control; |
| 713 for (size_t j = 0; j < access_infos.size(); ++j) { | 694 for (size_t j = 0; j < access_infos.size(); ++j) { |
| 714 PropertyAccessInfo const& access_info = access_infos[j]; | 695 PropertyAccessInfo const& access_info = access_infos[j]; |
| 715 Node* this_value = value; | 696 Node* this_value = value; |
| 716 Node* this_receiver = receiver; | 697 Node* this_receiver = receiver; |
| 717 Node* this_effect = effect; | 698 Node* this_effect = effect; |
| 718 Node* this_control = fallthrough_control; | 699 Node* this_control = fallthrough_control; |
| 719 | 700 |
| 720 // Perform map check on {receiver}. | 701 // Perform map check on {receiver}. |
| 721 MapHandles const& receiver_maps = access_info.receiver_maps(); | 702 MapHandles const& receiver_maps = access_info.receiver_maps(); |
| 722 { | 703 { |
| 723 // Emit a (sequence of) map checks for other {receiver}s. | 704 // Emit a (sequence of) map checks for other {receiver}s. |
| 724 ZoneVector<Node*> this_controls(zone()); | 705 ZoneVector<Node*> this_controls(zone()); |
| 725 ZoneVector<Node*> this_effects(zone()); | 706 ZoneVector<Node*> this_effects(zone()); |
| 726 if (j == access_infos.size() - 1) { | 707 if (j == access_infos.size() - 1) { |
| 727 // Last map check on the fallthrough control path, do a | 708 // Last map check on the fallthrough control path, do a |
| 728 // conditional eager deoptimization exit here. | 709 // conditional eager deoptimization exit here. |
| 729 this_effect = BuildCheckMaps(receiver, this_effect, this_control, | 710 access_builder.BuildCheckMaps(receiver, &this_effect, this_control, |
| 730 receiver_maps); | 711 receiver_maps); |
| 731 this_effects.push_back(this_effect); | 712 this_effects.push_back(this_effect); |
| 732 this_controls.push_back(fallthrough_control); | 713 this_controls.push_back(fallthrough_control); |
| 733 fallthrough_control = nullptr; | 714 fallthrough_control = nullptr; |
| 734 } else { | 715 } else { |
| 735 for (auto map : receiver_maps) { | 716 for (auto map : receiver_maps) { |
| 736 Node* check = | 717 Node* check = |
| 737 graph()->NewNode(simplified()->ReferenceEqual(), receiver_map, | 718 graph()->NewNode(simplified()->ReferenceEqual(), receiver_map, |
| 738 jsgraph()->Constant(map)); | 719 jsgraph()->Constant(map)); |
| 739 Node* branch = graph()->NewNode(common()->Branch(), check, | 720 Node* branch = graph()->NewNode(common()->Branch(), check, |
| 740 fallthrough_control); | 721 fallthrough_control); |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1023 } | 1004 } |
| 1024 } | 1005 } |
| 1025 | 1006 |
| 1026 // Install dependencies on the relevant prototype maps. | 1007 // Install dependencies on the relevant prototype maps. |
| 1027 for (Handle<Map> prototype_map : prototype_maps) { | 1008 for (Handle<Map> prototype_map : prototype_maps) { |
| 1028 dependencies()->AssumeMapStable(prototype_map); | 1009 dependencies()->AssumeMapStable(prototype_map); |
| 1029 } | 1010 } |
| 1030 } | 1011 } |
| 1031 | 1012 |
| 1032 // Ensure that {receiver} is a heap object. | 1013 // Ensure that {receiver} is a heap object. |
| 1033 receiver = BuildCheckHeapObject(receiver, &effect, control); | 1014 PropertyAccessBuilder access_builder(jsgraph(), dependencies()); |
| 1015 receiver = access_builder.BuildCheckHeapObject(receiver, &effect, control); |
| 1034 | 1016 |
| 1035 // Check for the monomorphic case. | 1017 // Check for the monomorphic case. |
| 1036 if (access_infos.size() == 1) { | 1018 if (access_infos.size() == 1) { |
| 1037 ElementAccessInfo access_info = access_infos.front(); | 1019 ElementAccessInfo access_info = access_infos.front(); |
| 1038 | 1020 |
| 1039 // Perform possible elements kind transitions. | 1021 // Perform possible elements kind transitions. |
| 1040 for (auto transition : access_info.transitions()) { | 1022 for (auto transition : access_info.transitions()) { |
| 1041 Handle<Map> const transition_source = transition.first; | 1023 Handle<Map> const transition_source = transition.first; |
| 1042 Handle<Map> const transition_target = transition.second; | 1024 Handle<Map> const transition_target = transition.second; |
| 1043 effect = graph()->NewNode( | 1025 effect = graph()->NewNode( |
| 1044 simplified()->TransitionElementsKind(ElementsTransition( | 1026 simplified()->TransitionElementsKind(ElementsTransition( |
| 1045 IsSimpleMapChangeTransition(transition_source->elements_kind(), | 1027 IsSimpleMapChangeTransition(transition_source->elements_kind(), |
| 1046 transition_target->elements_kind()) | 1028 transition_target->elements_kind()) |
| 1047 ? ElementsTransition::kFastTransition | 1029 ? ElementsTransition::kFastTransition |
| 1048 : ElementsTransition::kSlowTransition, | 1030 : ElementsTransition::kSlowTransition, |
| 1049 transition_source, transition_target)), | 1031 transition_source, transition_target)), |
| 1050 receiver, effect, control); | 1032 receiver, effect, control); |
| 1051 } | 1033 } |
| 1052 | 1034 |
| 1053 // TODO(turbofan): The effect/control linearization will not find a | 1035 // TODO(turbofan): The effect/control linearization will not find a |
| 1054 // FrameState after the StoreField or Call that is generated for the | 1036 // FrameState after the StoreField or Call that is generated for the |
| 1055 // elements kind transition above. This is because those operators | 1037 // elements kind transition above. This is because those operators |
| 1056 // don't have the kNoWrite flag on it, even though they are not | 1038 // don't have the kNoWrite flag on it, even though they are not |
| 1057 // observable by JavaScript. | 1039 // observable by JavaScript. |
| 1058 effect = graph()->NewNode(common()->Checkpoint(), frame_state, effect, | 1040 effect = graph()->NewNode(common()->Checkpoint(), frame_state, effect, |
| 1059 control); | 1041 control); |
| 1060 | 1042 |
| 1061 // Perform map check on the {receiver}. | 1043 // Perform map check on the {receiver}. |
| 1062 effect = BuildCheckMaps(receiver, effect, control, | 1044 access_builder.BuildCheckMaps(receiver, &effect, control, |
| 1063 access_info.receiver_maps()); | 1045 access_info.receiver_maps()); |
| 1064 | 1046 |
| 1065 // Access the actual element. | 1047 // Access the actual element. |
| 1066 ValueEffectControl continuation = | 1048 ValueEffectControl continuation = |
| 1067 BuildElementAccess(receiver, index, value, effect, control, | 1049 BuildElementAccess(receiver, index, value, effect, control, |
| 1068 access_info, access_mode, store_mode); | 1050 access_info, access_mode, store_mode); |
| 1069 value = continuation.value(); | 1051 value = continuation.value(); |
| 1070 effect = continuation.effect(); | 1052 effect = continuation.effect(); |
| 1071 control = continuation.control(); | 1053 control = continuation.control(); |
| 1072 } else { | 1054 } else { |
| 1073 // The final states for every polymorphic branch. We join them with | 1055 // The final states for every polymorphic branch. We join them with |
| (...skipping 30 matching lines...) Expand all Loading... |
| 1104 // Load the {receiver} map. | 1086 // Load the {receiver} map. |
| 1105 Node* receiver_map = this_effect = | 1087 Node* receiver_map = this_effect = |
| 1106 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | 1088 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), |
| 1107 receiver, this_effect, this_control); | 1089 receiver, this_effect, this_control); |
| 1108 | 1090 |
| 1109 // Perform map check(s) on {receiver}. | 1091 // Perform map check(s) on {receiver}. |
| 1110 MapHandles const& receiver_maps = access_info.receiver_maps(); | 1092 MapHandles const& receiver_maps = access_info.receiver_maps(); |
| 1111 if (j == access_infos.size() - 1) { | 1093 if (j == access_infos.size() - 1) { |
| 1112 // Last map check on the fallthrough control path, do a | 1094 // Last map check on the fallthrough control path, do a |
| 1113 // conditional eager deoptimization exit here. | 1095 // conditional eager deoptimization exit here. |
| 1114 this_effect = BuildCheckMaps(receiver, this_effect, this_control, | 1096 access_builder.BuildCheckMaps(receiver, &this_effect, this_control, |
| 1115 receiver_maps); | 1097 receiver_maps); |
| 1116 fallthrough_control = nullptr; | 1098 fallthrough_control = nullptr; |
| 1117 } else { | 1099 } else { |
| 1118 ZoneVector<Node*> this_controls(zone()); | 1100 ZoneVector<Node*> this_controls(zone()); |
| 1119 ZoneVector<Node*> this_effects(zone()); | 1101 ZoneVector<Node*> this_effects(zone()); |
| 1120 for (Handle<Map> map : receiver_maps) { | 1102 for (Handle<Map> map : receiver_maps) { |
| 1121 Node* check = | 1103 Node* check = |
| 1122 graph()->NewNode(simplified()->ReferenceEqual(), receiver_map, | 1104 graph()->NewNode(simplified()->ReferenceEqual(), receiver_map, |
| 1123 jsgraph()->Constant(map)); | 1105 jsgraph()->Constant(map)); |
| 1124 Node* branch = graph()->NewNode(common()->Branch(), check, | 1106 Node* branch = graph()->NewNode(common()->Branch(), check, |
| 1125 fallthrough_control); | 1107 fallthrough_control); |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1340 KeyedStoreICNexus nexus(p.feedback().vector(), p.feedback().slot()); | 1322 KeyedStoreICNexus nexus(p.feedback().vector(), p.feedback().slot()); |
| 1341 | 1323 |
| 1342 // Extract the keyed access store mode from the KEYED_STORE_IC. | 1324 // Extract the keyed access store mode from the KEYED_STORE_IC. |
| 1343 KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode(); | 1325 KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode(); |
| 1344 | 1326 |
| 1345 // Try to lower the keyed access based on the {nexus}. | 1327 // Try to lower the keyed access based on the {nexus}. |
| 1346 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore, | 1328 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore, |
| 1347 p.language_mode(), store_mode); | 1329 p.language_mode(), store_mode); |
| 1348 } | 1330 } |
| 1349 | 1331 |
| 1332 Node* JSNativeContextSpecialization::InlinePropertyGetterCall( |
| 1333 Node* receiver, Node* context, Node* frame_state, Node** effect, |
| 1334 Node** control, ZoneVector<Node*>* if_exceptions, |
| 1335 PropertyAccessInfo const& access_info) { |
| 1336 Node* target = jsgraph()->Constant(access_info.constant()); |
| 1337 FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state); |
| 1338 Handle<SharedFunctionInfo> shared_info = |
| 1339 frame_info.shared_info().ToHandleChecked(); |
| 1340 // We need a FrameState for the getter stub to restore the correct |
| 1341 // context before returning to fullcodegen. |
| 1342 FrameStateFunctionInfo const* frame_info0 = |
| 1343 common()->CreateFrameStateFunctionInfo(FrameStateType::kGetterStub, 1, 0, |
| 1344 shared_info); |
| 1345 Node* frame_state0 = graph()->NewNode( |
| 1346 common()->FrameState(BailoutId::None(), OutputFrameStateCombine::Ignore(), |
| 1347 frame_info0), |
| 1348 graph()->NewNode(common()->StateValues(1, SparseInputMask::Dense()), |
| 1349 receiver), |
| 1350 jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(), context, |
| 1351 target, frame_state); |
| 1352 |
| 1353 // Introduce the call to the getter function. |
| 1354 Node* value; |
| 1355 if (access_info.constant()->IsJSFunction()) { |
| 1356 value = *effect = *control = graph()->NewNode( |
| 1357 jsgraph()->javascript()->Call(2, CallFrequency(), VectorSlotPair(), |
| 1358 ConvertReceiverMode::kNotNullOrUndefined), |
| 1359 target, receiver, context, frame_state0, *effect, *control); |
| 1360 } else { |
| 1361 DCHECK(access_info.constant()->IsFunctionTemplateInfo()); |
| 1362 Handle<FunctionTemplateInfo> function_template_info( |
| 1363 Handle<FunctionTemplateInfo>::cast(access_info.constant())); |
| 1364 DCHECK(!function_template_info->call_code()->IsUndefined(isolate())); |
| 1365 value = InlineApiCall(receiver, context, target, frame_state0, nullptr, |
| 1366 effect, control, shared_info, function_template_info); |
| 1367 } |
| 1368 // Remember to rewire the IfException edge if this is inside a try-block. |
| 1369 if (if_exceptions != nullptr) { |
| 1370 // Create the appropriate IfException/IfSuccess projections. |
| 1371 Node* const if_exception = |
| 1372 graph()->NewNode(common()->IfException(), *control, *effect); |
| 1373 Node* const if_success = graph()->NewNode(common()->IfSuccess(), *control); |
| 1374 if_exceptions->push_back(if_exception); |
| 1375 *control = if_success; |
| 1376 } |
| 1377 return value; |
| 1378 } |
| 1379 |
| 1380 Node* JSNativeContextSpecialization::InlinePropertySetterCall( |
| 1381 Node* receiver, Node* value, Node* context, Node* frame_state, |
| 1382 Node** effect, Node** control, ZoneVector<Node*>* if_exceptions, |
| 1383 PropertyAccessInfo const& access_info) { |
| 1384 Node* target = jsgraph()->Constant(access_info.constant()); |
| 1385 FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state); |
| 1386 Handle<SharedFunctionInfo> shared_info = |
| 1387 frame_info.shared_info().ToHandleChecked(); |
| 1388 // We need a FrameState for the setter stub to restore the correct |
| 1389 // context and return the appropriate value to fullcodegen. |
| 1390 FrameStateFunctionInfo const* frame_info0 = |
| 1391 common()->CreateFrameStateFunctionInfo(FrameStateType::kSetterStub, 2, 0, |
| 1392 shared_info); |
| 1393 Node* frame_state0 = graph()->NewNode( |
| 1394 common()->FrameState(BailoutId::None(), OutputFrameStateCombine::Ignore(), |
| 1395 frame_info0), |
| 1396 graph()->NewNode(common()->StateValues(2, SparseInputMask::Dense()), |
| 1397 receiver, value), |
| 1398 jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(), context, |
| 1399 target, frame_state); |
| 1400 |
| 1401 // Introduce the call to the setter function. |
| 1402 if (access_info.constant()->IsJSFunction()) { |
| 1403 *effect = *control = graph()->NewNode( |
| 1404 jsgraph()->javascript()->Call(3, CallFrequency(), VectorSlotPair(), |
| 1405 ConvertReceiverMode::kNotNullOrUndefined), |
| 1406 target, receiver, value, context, frame_state0, *effect, *control); |
| 1407 } else { |
| 1408 DCHECK(access_info.constant()->IsFunctionTemplateInfo()); |
| 1409 Handle<FunctionTemplateInfo> function_template_info( |
| 1410 Handle<FunctionTemplateInfo>::cast(access_info.constant())); |
| 1411 DCHECK(!function_template_info->call_code()->IsUndefined(isolate())); |
| 1412 value = InlineApiCall(receiver, context, target, frame_state0, value, |
| 1413 effect, control, shared_info, function_template_info); |
| 1414 } |
| 1415 // Remember to rewire the IfException edge if this is inside a try-block. |
| 1416 if (if_exceptions != nullptr) { |
| 1417 // Create the appropriate IfException/IfSuccess projections. |
| 1418 Node* const if_exception = |
| 1419 graph()->NewNode(common()->IfException(), *control, *effect); |
| 1420 Node* const if_success = graph()->NewNode(common()->IfSuccess(), *control); |
| 1421 if_exceptions->push_back(if_exception); |
| 1422 *control = if_success; |
| 1423 } |
| 1424 return value; |
| 1425 } |
| 1426 |
| 1427 Node* JSNativeContextSpecialization::InlineApiCall( |
| 1428 Node* receiver, Node* context, Node* target, Node* frame_state, Node* value, |
| 1429 Node** effect, Node** control, Handle<SharedFunctionInfo> shared_info, |
| 1430 Handle<FunctionTemplateInfo> function_template_info) { |
| 1431 Handle<CallHandlerInfo> call_handler_info = handle( |
| 1432 CallHandlerInfo::cast(function_template_info->call_code()), isolate()); |
| 1433 Handle<Object> call_data_object(call_handler_info->data(), isolate()); |
| 1434 |
| 1435 // Only setters have a value. |
| 1436 int const argc = value == nullptr ? 0 : 1; |
| 1437 // The stub always expects the receiver as the first param on the stack. |
| 1438 CallApiCallbackStub stub( |
| 1439 isolate(), argc, |
| 1440 true /* FunctionTemplateInfo doesn't have an associated context. */); |
| 1441 CallInterfaceDescriptor call_interface_descriptor = |
| 1442 stub.GetCallInterfaceDescriptor(); |
| 1443 CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor( |
| 1444 isolate(), graph()->zone(), call_interface_descriptor, |
| 1445 call_interface_descriptor.GetStackParameterCount() + argc + |
| 1446 1 /* implicit receiver */, |
| 1447 CallDescriptor::kNeedsFrameState, Operator::kNoProperties, |
| 1448 MachineType::AnyTagged(), 1); |
| 1449 |
| 1450 Node* data = jsgraph()->Constant(call_data_object); |
| 1451 ApiFunction function(v8::ToCData<Address>(call_handler_info->callback())); |
| 1452 Node* function_reference = |
| 1453 graph()->NewNode(common()->ExternalConstant(ExternalReference( |
| 1454 &function, ExternalReference::DIRECT_API_CALL, isolate()))); |
| 1455 Node* code = jsgraph()->HeapConstant(stub.GetCode()); |
| 1456 |
| 1457 // Add CallApiCallbackStub's register argument as well. |
| 1458 Node* inputs[11] = { |
| 1459 code, target, data, receiver /* holder */, function_reference, receiver}; |
| 1460 int index = 6 + argc; |
| 1461 inputs[index++] = context; |
| 1462 inputs[index++] = frame_state; |
| 1463 inputs[index++] = *effect; |
| 1464 inputs[index++] = *control; |
| 1465 // This needs to stay here because of the edge case described in |
| 1466 // http://crbug.com/675648. |
| 1467 if (value != nullptr) { |
| 1468 inputs[6] = value; |
| 1469 } |
| 1470 |
| 1471 return *effect = *control = |
| 1472 graph()->NewNode(common()->Call(call_descriptor), index, inputs); |
| 1473 } |
| 1474 |
| 1475 JSNativeContextSpecialization::ValueEffectControl |
| 1476 JSNativeContextSpecialization::BuildPropertyLoad( |
| 1477 Node* receiver, Node* context, Node* frame_state, Node* effect, |
| 1478 Node* control, Handle<Name> name, ZoneVector<Node*>* if_exceptions, |
| 1479 PropertyAccessInfo const& access_info, LanguageMode language_mode) { |
| 1480 // Determine actual holder and perform prototype chain checks. |
| 1481 Handle<JSObject> holder; |
| 1482 PropertyAccessBuilder access_builder(jsgraph(), dependencies()); |
| 1483 if (access_info.holder().ToHandle(&holder)) { |
| 1484 access_builder.AssumePrototypesStable(native_context(), |
| 1485 access_info.receiver_maps(), holder); |
| 1486 } |
| 1487 |
| 1488 // Generate the actual property access. |
| 1489 Node* value; |
| 1490 if (access_info.IsNotFound()) { |
| 1491 value = jsgraph()->UndefinedConstant(); |
| 1492 } else if (access_info.IsDataConstant()) { |
| 1493 DCHECK(!FLAG_track_constant_fields); |
| 1494 value = jsgraph()->Constant(access_info.constant()); |
| 1495 } else if (access_info.IsAccessorConstant()) { |
| 1496 value = InlinePropertyGetterCall(receiver, context, frame_state, &effect, |
| 1497 &control, if_exceptions, access_info); |
| 1498 } else { |
| 1499 DCHECK(access_info.IsDataField() || access_info.IsDataConstantField()); |
| 1500 value = access_builder.BuildLoadDataField(name, access_info, receiver, |
| 1501 &effect, &control); |
| 1502 } |
| 1503 |
| 1504 return ValueEffectControl(value, effect, control); |
| 1505 } |
| 1506 |
| 1350 JSNativeContextSpecialization::ValueEffectControl | 1507 JSNativeContextSpecialization::ValueEffectControl |
| 1351 JSNativeContextSpecialization::BuildPropertyAccess( | 1508 JSNativeContextSpecialization::BuildPropertyAccess( |
| 1352 Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect, | 1509 Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect, |
| 1353 Node* control, Handle<Name> name, ZoneVector<Node*>* if_exceptions, | 1510 Node* control, Handle<Name> name, ZoneVector<Node*>* if_exceptions, |
| 1354 PropertyAccessInfo const& access_info, AccessMode access_mode, | 1511 PropertyAccessInfo const& access_info, AccessMode access_mode, |
| 1355 LanguageMode language_mode) { | 1512 LanguageMode language_mode) { |
| 1513 switch (access_mode) { |
| 1514 case AccessMode::kLoad: |
| 1515 return BuildPropertyLoad(receiver, context, frame_state, effect, control, |
| 1516 name, if_exceptions, access_info, language_mode); |
| 1517 case AccessMode::kStore: |
| 1518 case AccessMode::kStoreInLiteral: |
| 1519 return BuildPropertyStore(receiver, value, context, frame_state, effect, |
| 1520 control, name, if_exceptions, access_info, |
| 1521 access_mode, language_mode); |
| 1522 } |
| 1523 UNREACHABLE(); |
| 1524 return ValueEffectControl(); |
| 1525 } |
| 1526 |
| 1527 JSNativeContextSpecialization::ValueEffectControl |
| 1528 JSNativeContextSpecialization::BuildPropertyStore( |
| 1529 Node* receiver, Node* value, Node* context, Node* frame_state, Node* effect, |
| 1530 Node* control, Handle<Name> name, ZoneVector<Node*>* if_exceptions, |
| 1531 PropertyAccessInfo const& access_info, AccessMode access_mode, |
| 1532 LanguageMode language_mode) { |
| 1356 // Determine actual holder and perform prototype chain checks. | 1533 // Determine actual holder and perform prototype chain checks. |
| 1357 Handle<JSObject> holder; | 1534 Handle<JSObject> holder; |
| 1535 PropertyAccessBuilder access_builder(jsgraph(), dependencies()); |
| 1358 if (access_info.holder().ToHandle(&holder)) { | 1536 if (access_info.holder().ToHandle(&holder)) { |
| 1359 DCHECK_NE(AccessMode::kStoreInLiteral, access_mode); | 1537 DCHECK_NE(AccessMode::kStoreInLiteral, access_mode); |
| 1360 AssumePrototypesStable(access_info.receiver_maps(), holder); | 1538 access_builder.AssumePrototypesStable(native_context(), |
| 1361 } | 1539 access_info.receiver_maps(), holder); |
| 1540 } |
| 1541 |
| 1542 DCHECK(!access_info.IsNotFound()); |
| 1362 | 1543 |
| 1363 // Generate the actual property access. | 1544 // Generate the actual property access. |
| 1364 if (access_info.IsNotFound()) { | 1545 if (access_info.IsDataConstant()) { |
| 1365 DCHECK_EQ(AccessMode::kLoad, access_mode); | |
| 1366 value = jsgraph()->UndefinedConstant(); | |
| 1367 } else if (access_info.IsDataConstant()) { | |
| 1368 DCHECK(!FLAG_track_constant_fields); | 1546 DCHECK(!FLAG_track_constant_fields); |
| 1369 Node* constant_value = jsgraph()->Constant(access_info.constant()); | 1547 Node* constant_value = jsgraph()->Constant(access_info.constant()); |
| 1370 if (access_mode == AccessMode::kStore) { | 1548 Node* check = |
| 1371 Node* check = graph()->NewNode(simplified()->ReferenceEqual(), value, | 1549 graph()->NewNode(simplified()->ReferenceEqual(), value, constant_value); |
| 1372 constant_value); | 1550 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control); |
| 1373 effect = | |
| 1374 graph()->NewNode(simplified()->CheckIf(), check, effect, control); | |
| 1375 } | |
| 1376 value = constant_value; | 1551 value = constant_value; |
| 1377 } else if (access_info.IsAccessorConstant()) { | 1552 } else if (access_info.IsAccessorConstant()) { |
| 1378 Node* target = jsgraph()->Constant(access_info.constant()); | 1553 value = |
| 1379 FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state); | 1554 InlinePropertySetterCall(receiver, value, context, frame_state, &effect, |
| 1380 Handle<SharedFunctionInfo> shared_info = | 1555 &control, if_exceptions, access_info); |
| 1381 frame_info.shared_info().ToHandleChecked(); | |
| 1382 switch (access_mode) { | |
| 1383 case AccessMode::kLoad: { | |
| 1384 // We need a FrameState for the getter stub to restore the correct | |
| 1385 // context before returning to unoptimized code. | |
| 1386 FrameStateFunctionInfo const* frame_info0 = | |
| 1387 common()->CreateFrameStateFunctionInfo(FrameStateType::kGetterStub, | |
| 1388 1, 0, shared_info); | |
| 1389 Node* frame_state0 = graph()->NewNode( | |
| 1390 common()->FrameState(BailoutId::None(), | |
| 1391 OutputFrameStateCombine::Ignore(), | |
| 1392 frame_info0), | |
| 1393 graph()->NewNode(common()->StateValues(1, SparseInputMask::Dense()), | |
| 1394 receiver), | |
| 1395 jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(), | |
| 1396 context, target, frame_state); | |
| 1397 | |
| 1398 // Introduce the call to the getter function. | |
| 1399 if (access_info.constant()->IsJSFunction()) { | |
| 1400 value = effect = control = graph()->NewNode( | |
| 1401 javascript()->Call(2, CallFrequency(), VectorSlotPair(), | |
| 1402 ConvertReceiverMode::kNotNullOrUndefined), | |
| 1403 target, receiver, context, frame_state0, effect, control); | |
| 1404 } else { | |
| 1405 DCHECK(access_info.constant()->IsFunctionTemplateInfo()); | |
| 1406 Handle<FunctionTemplateInfo> function_template_info( | |
| 1407 Handle<FunctionTemplateInfo>::cast(access_info.constant())); | |
| 1408 DCHECK(!function_template_info->call_code()->IsUndefined(isolate())); | |
| 1409 ValueEffectControl value_effect_control = InlineApiCall( | |
| 1410 receiver, context, target, frame_state0, nullptr, effect, control, | |
| 1411 shared_info, function_template_info); | |
| 1412 value = value_effect_control.value(); | |
| 1413 effect = value_effect_control.effect(); | |
| 1414 control = value_effect_control.control(); | |
| 1415 } | |
| 1416 break; | |
| 1417 } | |
| 1418 case AccessMode::kStore: { | |
| 1419 // We need a FrameState for the setter stub to restore the correct | |
| 1420 // context and return the appropriate value to unoptimized code. | |
| 1421 FrameStateFunctionInfo const* frame_info0 = | |
| 1422 common()->CreateFrameStateFunctionInfo(FrameStateType::kSetterStub, | |
| 1423 2, 0, shared_info); | |
| 1424 Node* frame_state0 = graph()->NewNode( | |
| 1425 common()->FrameState(BailoutId::None(), | |
| 1426 OutputFrameStateCombine::Ignore(), | |
| 1427 frame_info0), | |
| 1428 graph()->NewNode(common()->StateValues(2, SparseInputMask::Dense()), | |
| 1429 receiver, value), | |
| 1430 jsgraph()->EmptyStateValues(), jsgraph()->EmptyStateValues(), | |
| 1431 context, target, frame_state); | |
| 1432 | |
| 1433 // Introduce the call to the setter function. | |
| 1434 if (access_info.constant()->IsJSFunction()) { | |
| 1435 effect = control = graph()->NewNode( | |
| 1436 javascript()->Call(3, CallFrequency(), VectorSlotPair(), | |
| 1437 ConvertReceiverMode::kNotNullOrUndefined), | |
| 1438 target, receiver, value, context, frame_state0, effect, control); | |
| 1439 } else { | |
| 1440 DCHECK(access_info.constant()->IsFunctionTemplateInfo()); | |
| 1441 Handle<FunctionTemplateInfo> function_template_info( | |
| 1442 Handle<FunctionTemplateInfo>::cast(access_info.constant())); | |
| 1443 DCHECK(!function_template_info->call_code()->IsUndefined(isolate())); | |
| 1444 ValueEffectControl value_effect_control = InlineApiCall( | |
| 1445 receiver, context, target, frame_state0, value, effect, control, | |
| 1446 shared_info, function_template_info); | |
| 1447 value = value_effect_control.value(); | |
| 1448 effect = value_effect_control.effect(); | |
| 1449 control = value_effect_control.control(); | |
| 1450 } | |
| 1451 break; | |
| 1452 } | |
| 1453 case AccessMode::kStoreInLiteral: { | |
| 1454 UNREACHABLE(); | |
| 1455 break; | |
| 1456 } | |
| 1457 } | |
| 1458 // Remember to rewire the IfException edge if this is inside a try-block. | |
| 1459 if (if_exceptions != nullptr) { | |
| 1460 // Create the appropriate IfException/IfSuccess projections. | |
| 1461 Node* const if_exception = | |
| 1462 graph()->NewNode(common()->IfException(), control, effect); | |
| 1463 Node* const if_success = graph()->NewNode(common()->IfSuccess(), control); | |
| 1464 if_exceptions->push_back(if_exception); | |
| 1465 control = if_success; | |
| 1466 } | |
| 1467 } else { | 1556 } else { |
| 1468 DCHECK(access_info.IsDataField() || access_info.IsDataConstantField()); | 1557 DCHECK(access_info.IsDataField() || access_info.IsDataConstantField()); |
| 1469 FieldIndex const field_index = access_info.field_index(); | 1558 FieldIndex const field_index = access_info.field_index(); |
| 1470 Type* const field_type = access_info.field_type(); | 1559 Type* const field_type = access_info.field_type(); |
| 1471 MachineRepresentation const field_representation = | 1560 MachineRepresentation const field_representation = |
| 1472 access_info.field_representation(); | 1561 access_info.field_representation(); |
| 1473 if (access_mode == AccessMode::kLoad) { | |
| 1474 if (access_info.holder().ToHandle(&holder)) { | |
| 1475 receiver = jsgraph()->Constant(holder); | |
| 1476 } | |
| 1477 // Optimize immutable property loads. | |
| 1478 HeapObjectMatcher m(receiver); | |
| 1479 if (m.HasValue() && m.Value()->IsJSObject()) { | |
| 1480 // TODO(ishell): Use something simpler like | |
| 1481 // | |
| 1482 // Handle<Object> value = | |
| 1483 // JSObject::FastPropertyAt(Handle<JSObject>::cast(m.Value()), | |
| 1484 // Representation::Tagged(), field_index); | |
| 1485 // | |
| 1486 // here, once we have the immutable bit in the access_info. | |
| 1487 | |
| 1488 // TODO(turbofan): Given that we already have the field_index here, we | |
| 1489 // might be smarter in the future and not rely on the LookupIterator, | |
| 1490 // but for now let's just do what Crankshaft does. | |
| 1491 LookupIterator it(m.Value(), name, | |
| 1492 LookupIterator::OWN_SKIP_INTERCEPTOR); | |
| 1493 if (it.state() == LookupIterator::DATA) { | |
| 1494 bool is_reaonly_non_configurable = | |
| 1495 it.IsReadOnly() && !it.IsConfigurable(); | |
| 1496 if (is_reaonly_non_configurable || | |
| 1497 (FLAG_track_constant_fields && | |
| 1498 access_info.IsDataConstantField())) { | |
| 1499 Node* value = jsgraph()->Constant(JSReceiver::GetDataProperty(&it)); | |
| 1500 if (!is_reaonly_non_configurable) { | |
| 1501 // It's necessary to add dependency on the map that introduced | |
| 1502 // the field. | |
| 1503 DCHECK(access_info.IsDataConstantField()); | |
| 1504 DCHECK(!it.is_dictionary_holder()); | |
| 1505 Handle<Map> field_owner_map = it.GetFieldOwnerMap(); | |
| 1506 dependencies()->AssumeFieldOwner(field_owner_map); | |
| 1507 } | |
| 1508 return ValueEffectControl(value, effect, control); | |
| 1509 } | |
| 1510 } | |
| 1511 } | |
| 1512 } | |
| 1513 Node* storage = receiver; | 1562 Node* storage = receiver; |
| 1514 if (!field_index.is_inobject()) { | 1563 if (!field_index.is_inobject()) { |
| 1515 storage = effect = graph()->NewNode( | 1564 storage = effect = graph()->NewNode( |
| 1516 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()), | 1565 simplified()->LoadField(AccessBuilder::ForJSObjectProperties()), |
| 1517 storage, effect, control); | 1566 storage, effect, control); |
| 1518 } | 1567 } |
| 1519 FieldAccess field_access = { | 1568 FieldAccess field_access = { |
| 1520 kTaggedBase, | 1569 kTaggedBase, |
| 1521 field_index.offset(), | 1570 field_index.offset(), |
| 1522 name, | 1571 name, |
| 1523 MaybeHandle<Map>(), | 1572 MaybeHandle<Map>(), |
| 1524 field_type, | 1573 field_type, |
| 1525 MachineType::TypeForRepresentation(field_representation), | 1574 MachineType::TypeForRepresentation(field_representation), |
| 1526 kFullWriteBarrier}; | 1575 kFullWriteBarrier}; |
| 1527 if (access_mode == AccessMode::kLoad) { | 1576 bool store_to_constant_field = FLAG_track_constant_fields && |
| 1528 if (field_representation == MachineRepresentation::kFloat64) { | 1577 (access_mode == AccessMode::kStore) && |
| 1578 access_info.IsDataConstantField(); |
| 1579 |
| 1580 DCHECK(access_mode == AccessMode::kStore || |
| 1581 access_mode == AccessMode::kStoreInLiteral); |
| 1582 switch (field_representation) { |
| 1583 case MachineRepresentation::kFloat64: { |
| 1584 value = effect = graph()->NewNode(simplified()->CheckNumber(), value, |
| 1585 effect, control); |
| 1529 if (!field_index.is_inobject() || field_index.is_hidden_field() || | 1586 if (!field_index.is_inobject() || field_index.is_hidden_field() || |
| 1530 !FLAG_unbox_double_fields) { | 1587 !FLAG_unbox_double_fields) { |
| 1531 FieldAccess const storage_access = {kTaggedBase, | 1588 if (access_info.HasTransitionMap()) { |
| 1532 field_index.offset(), | 1589 // Allocate a MutableHeapNumber for the new property. |
| 1533 name, | 1590 effect = graph()->NewNode( |
| 1534 MaybeHandle<Map>(), | 1591 common()->BeginRegion(RegionObservability::kNotObservable), |
| 1535 Type::OtherInternal(), | 1592 effect); |
| 1536 MachineType::TaggedPointer(), | 1593 Node* box = effect = graph()->NewNode( |
| 1537 kPointerWriteBarrier}; | 1594 simplified()->Allocate(Type::OtherInternal(), NOT_TENURED), |
| 1538 storage = effect = | 1595 jsgraph()->Constant(HeapNumber::kSize), effect, control); |
| 1539 graph()->NewNode(simplified()->LoadField(storage_access), storage, | 1596 effect = graph()->NewNode( |
| 1540 effect, control); | 1597 simplified()->StoreField(AccessBuilder::ForMap()), box, |
| 1541 field_access.offset = HeapNumber::kValueOffset; | 1598 jsgraph()->HeapConstant(factory()->mutable_heap_number_map()), |
| 1542 field_access.name = MaybeHandle<Name>(); | 1599 effect, control); |
| 1543 } | 1600 effect = graph()->NewNode( |
| 1544 } else if (field_representation == | 1601 simplified()->StoreField(AccessBuilder::ForHeapNumberValue()), |
| 1545 MachineRepresentation::kTaggedPointer) { | 1602 box, value, effect, control); |
| 1546 // Remember the map of the field value, if its map is stable. This is | 1603 value = effect = |
| 1547 // used by the LoadElimination to eliminate map checks on the result. | 1604 graph()->NewNode(common()->FinishRegion(), box, effect); |
| 1548 Handle<Map> field_map; | 1605 |
| 1549 if (access_info.field_map().ToHandle(&field_map)) { | 1606 field_access.type = Type::Any(); |
| 1550 if (field_map->is_stable()) { | 1607 field_access.machine_type = MachineType::TaggedPointer(); |
| 1551 dependencies()->AssumeMapStable(field_map); | 1608 field_access.write_barrier_kind = kPointerWriteBarrier; |
| 1552 field_access.map = field_map; | 1609 } else { |
| 1610 // We just store directly to the MutableHeapNumber. |
| 1611 FieldAccess const storage_access = {kTaggedBase, |
| 1612 field_index.offset(), |
| 1613 name, |
| 1614 MaybeHandle<Map>(), |
| 1615 Type::OtherInternal(), |
| 1616 MachineType::TaggedPointer(), |
| 1617 kPointerWriteBarrier}; |
| 1618 storage = effect = |
| 1619 graph()->NewNode(simplified()->LoadField(storage_access), |
| 1620 storage, effect, control); |
| 1621 field_access.offset = HeapNumber::kValueOffset; |
| 1622 field_access.name = MaybeHandle<Name>(); |
| 1623 field_access.machine_type = MachineType::Float64(); |
| 1553 } | 1624 } |
| 1554 } | 1625 } |
| 1626 if (store_to_constant_field) { |
| 1627 DCHECK(!access_info.HasTransitionMap()); |
| 1628 // If the field is constant check that the value we are going |
| 1629 // to store matches current value. |
| 1630 Node* current_value = effect = graph()->NewNode( |
| 1631 simplified()->LoadField(field_access), storage, effect, control); |
| 1632 |
| 1633 Node* check = graph()->NewNode(simplified()->NumberEqual(), |
| 1634 current_value, value); |
| 1635 effect = |
| 1636 graph()->NewNode(simplified()->CheckIf(), check, effect, control); |
| 1637 return ValueEffectControl(value, effect, control); |
| 1638 } |
| 1639 break; |
| 1555 } | 1640 } |
| 1556 value = effect = graph()->NewNode(simplified()->LoadField(field_access), | 1641 case MachineRepresentation::kTaggedSigned: |
| 1557 storage, effect, control); | 1642 case MachineRepresentation::kTaggedPointer: |
| 1558 } else { | 1643 case MachineRepresentation::kTagged: |
| 1559 bool store_to_constant_field = FLAG_track_constant_fields && | 1644 if (store_to_constant_field) { |
| 1560 (access_mode == AccessMode::kStore) && | 1645 DCHECK(!access_info.HasTransitionMap()); |
| 1561 access_info.IsDataConstantField(); | 1646 // If the field is constant check that the value we are going |
| 1647 // to store matches current value. |
| 1648 Node* current_value = effect = graph()->NewNode( |
| 1649 simplified()->LoadField(field_access), storage, effect, control); |
| 1562 | 1650 |
| 1563 DCHECK(access_mode == AccessMode::kStore || | 1651 Node* check = graph()->NewNode(simplified()->ReferenceEqual(), |
| 1564 access_mode == AccessMode::kStoreInLiteral); | 1652 current_value, value); |
| 1565 switch (field_representation) { | 1653 effect = |
| 1566 case MachineRepresentation::kFloat64: { | 1654 graph()->NewNode(simplified()->CheckIf(), check, effect, control); |
| 1567 value = effect = graph()->NewNode(simplified()->CheckNumber(), value, | 1655 return ValueEffectControl(value, effect, control); |
| 1656 } |
| 1657 |
| 1658 if (field_representation == MachineRepresentation::kTaggedSigned) { |
| 1659 value = effect = graph()->NewNode(simplified()->CheckSmi(), value, |
| 1568 effect, control); | 1660 effect, control); |
| 1569 if (!field_index.is_inobject() || field_index.is_hidden_field() || | 1661 field_access.write_barrier_kind = kNoWriteBarrier; |
| 1570 !FLAG_unbox_double_fields) { | |
| 1571 if (access_info.HasTransitionMap()) { | |
| 1572 // Allocate a MutableHeapNumber for the new property. | |
| 1573 effect = graph()->NewNode( | |
| 1574 common()->BeginRegion(RegionObservability::kNotObservable), | |
| 1575 effect); | |
| 1576 Node* box = effect = graph()->NewNode( | |
| 1577 simplified()->Allocate(Type::OtherInternal(), NOT_TENURED), | |
| 1578 jsgraph()->Constant(HeapNumber::kSize), effect, control); | |
| 1579 effect = graph()->NewNode( | |
| 1580 simplified()->StoreField(AccessBuilder::ForMap()), box, | |
| 1581 jsgraph()->HeapConstant(factory()->mutable_heap_number_map()), | |
| 1582 effect, control); | |
| 1583 effect = graph()->NewNode( | |
| 1584 simplified()->StoreField(AccessBuilder::ForHeapNumberValue()), | |
| 1585 box, value, effect, control); | |
| 1586 value = effect = | |
| 1587 graph()->NewNode(common()->FinishRegion(), box, effect); | |
| 1588 | 1662 |
| 1589 field_access.type = Type::Any(); | 1663 } else if (field_representation == |
| 1590 field_access.machine_type = MachineType::TaggedPointer(); | 1664 MachineRepresentation::kTaggedPointer) { |
| 1591 field_access.write_barrier_kind = kPointerWriteBarrier; | 1665 // Ensure that {value} is a HeapObject. |
| 1592 } else { | 1666 value = access_builder.BuildCheckHeapObject(value, &effect, control); |
| 1593 // We just store directly to the MutableHeapNumber. | 1667 Handle<Map> field_map; |
| 1594 FieldAccess const storage_access = {kTaggedBase, | 1668 if (access_info.field_map().ToHandle(&field_map)) { |
| 1595 field_index.offset(), | 1669 // Emit a map check for the value. |
| 1596 name, | 1670 effect = graph()->NewNode( |
| 1597 MaybeHandle<Map>(), | 1671 simplified()->CheckMaps(CheckMapsFlag::kNone, |
| 1598 Type::OtherInternal(), | 1672 ZoneHandleSet<Map>(field_map)), |
| 1599 MachineType::TaggedPointer(), | 1673 value, effect, control); |
| 1600 kPointerWriteBarrier}; | |
| 1601 storage = effect = | |
| 1602 graph()->NewNode(simplified()->LoadField(storage_access), | |
| 1603 storage, effect, control); | |
| 1604 field_access.offset = HeapNumber::kValueOffset; | |
| 1605 field_access.name = MaybeHandle<Name>(); | |
| 1606 field_access.machine_type = MachineType::Float64(); | |
| 1607 } | |
| 1608 } | 1674 } |
| 1609 if (store_to_constant_field) { | 1675 field_access.write_barrier_kind = kPointerWriteBarrier; |
| 1610 DCHECK(!access_info.HasTransitionMap()); | |
| 1611 // If the field is constant check that the value we are going | |
| 1612 // to store matches current value. | |
| 1613 Node* current_value = effect = | |
| 1614 graph()->NewNode(simplified()->LoadField(field_access), storage, | |
| 1615 effect, control); | |
| 1616 | 1676 |
| 1617 Node* check = graph()->NewNode(simplified()->NumberEqual(), | 1677 } else { |
| 1618 current_value, value); | 1678 DCHECK_EQ(MachineRepresentation::kTagged, field_representation); |
| 1619 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, | |
| 1620 control); | |
| 1621 return ValueEffectControl(value, effect, control); | |
| 1622 } | |
| 1623 break; | |
| 1624 } | 1679 } |
| 1625 case MachineRepresentation::kTaggedSigned: | 1680 break; |
| 1626 case MachineRepresentation::kTaggedPointer: | 1681 case MachineRepresentation::kNone: |
| 1627 case MachineRepresentation::kTagged: | 1682 case MachineRepresentation::kBit: |
| 1628 if (store_to_constant_field) { | 1683 case MachineRepresentation::kWord8: |
| 1629 DCHECK(!access_info.HasTransitionMap()); | 1684 case MachineRepresentation::kWord16: |
| 1630 // If the field is constant check that the value we are going | 1685 case MachineRepresentation::kWord32: |
| 1631 // to store matches current value. | 1686 case MachineRepresentation::kWord64: |
| 1632 Node* current_value = effect = | 1687 case MachineRepresentation::kFloat32: |
| 1633 graph()->NewNode(simplified()->LoadField(field_access), storage, | 1688 case MachineRepresentation::kSimd128: |
| 1634 effect, control); | 1689 UNREACHABLE(); |
| 1690 break; |
| 1691 } |
| 1692 // Check if we need to perform a transitioning store. |
| 1693 Handle<Map> transition_map; |
| 1694 if (access_info.transition_map().ToHandle(&transition_map)) { |
| 1695 // Check if we need to grow the properties backing store |
| 1696 // with this transitioning store. |
| 1697 Handle<Map> original_map(Map::cast(transition_map->GetBackPointer()), |
| 1698 isolate()); |
| 1699 if (original_map->unused_property_fields() == 0) { |
| 1700 DCHECK(!field_index.is_inobject()); |
| 1635 | 1701 |
| 1636 Node* check = graph()->NewNode(simplified()->ReferenceEqual(), | 1702 // Reallocate the properties {storage}. |
| 1637 current_value, value); | 1703 storage = effect = BuildExtendPropertiesBackingStore( |
| 1638 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, | 1704 original_map, storage, effect, control); |
| 1639 control); | |
| 1640 return ValueEffectControl(value, effect, control); | |
| 1641 } | |
| 1642 | 1705 |
| 1643 if (field_representation == MachineRepresentation::kTaggedSigned) { | 1706 // Perform the actual store. |
| 1644 value = effect = graph()->NewNode(simplified()->CheckSmi(), value, | |
| 1645 effect, control); | |
| 1646 field_access.write_barrier_kind = kNoWriteBarrier; | |
| 1647 | |
| 1648 } else if (field_representation == | |
| 1649 MachineRepresentation::kTaggedPointer) { | |
| 1650 // Ensure that {value} is a HeapObject. | |
| 1651 value = BuildCheckHeapObject(value, &effect, control); | |
| 1652 Handle<Map> field_map; | |
| 1653 if (access_info.field_map().ToHandle(&field_map)) { | |
| 1654 // Emit a map check for the value. | |
| 1655 effect = graph()->NewNode( | |
| 1656 simplified()->CheckMaps(CheckMapsFlag::kNone, | |
| 1657 ZoneHandleSet<Map>(field_map)), | |
| 1658 value, effect, control); | |
| 1659 } | |
| 1660 field_access.write_barrier_kind = kPointerWriteBarrier; | |
| 1661 | |
| 1662 } else { | |
| 1663 DCHECK_EQ(MachineRepresentation::kTagged, field_representation); | |
| 1664 } | |
| 1665 break; | |
| 1666 case MachineRepresentation::kNone: | |
| 1667 case MachineRepresentation::kBit: | |
| 1668 case MachineRepresentation::kWord8: | |
| 1669 case MachineRepresentation::kWord16: | |
| 1670 case MachineRepresentation::kWord32: | |
| 1671 case MachineRepresentation::kWord64: | |
| 1672 case MachineRepresentation::kFloat32: | |
| 1673 case MachineRepresentation::kSimd128: | |
| 1674 UNREACHABLE(); | |
| 1675 break; | |
| 1676 } | |
| 1677 // Check if we need to perform a transitioning store. | |
| 1678 Handle<Map> transition_map; | |
| 1679 if (access_info.transition_map().ToHandle(&transition_map)) { | |
| 1680 // Check if we need to grow the properties backing store | |
| 1681 // with this transitioning store. | |
| 1682 Handle<Map> original_map(Map::cast(transition_map->GetBackPointer()), | |
| 1683 isolate()); | |
| 1684 if (original_map->unused_property_fields() == 0) { | |
| 1685 DCHECK(!field_index.is_inobject()); | |
| 1686 | |
| 1687 // Reallocate the properties {storage}. | |
| 1688 storage = effect = BuildExtendPropertiesBackingStore( | |
| 1689 original_map, storage, effect, control); | |
| 1690 | |
| 1691 // Perform the actual store. | |
| 1692 effect = graph()->NewNode(simplified()->StoreField(field_access), | |
| 1693 storage, value, effect, control); | |
| 1694 | |
| 1695 // Atomically switch to the new properties below. | |
| 1696 field_access = AccessBuilder::ForJSObjectProperties(); | |
| 1697 value = storage; | |
| 1698 storage = receiver; | |
| 1699 } | |
| 1700 effect = graph()->NewNode( | |
| 1701 common()->BeginRegion(RegionObservability::kObservable), effect); | |
| 1702 effect = graph()->NewNode( | |
| 1703 simplified()->StoreField(AccessBuilder::ForMap()), receiver, | |
| 1704 jsgraph()->Constant(transition_map), effect, control); | |
| 1705 effect = graph()->NewNode(simplified()->StoreField(field_access), | 1707 effect = graph()->NewNode(simplified()->StoreField(field_access), |
| 1706 storage, value, effect, control); | 1708 storage, value, effect, control); |
| 1707 effect = graph()->NewNode(common()->FinishRegion(), | 1709 |
| 1708 jsgraph()->UndefinedConstant(), effect); | 1710 // Atomically switch to the new properties below. |
| 1709 } else { | 1711 field_access = AccessBuilder::ForJSObjectProperties(); |
| 1710 // Regular non-transitioning field store. | 1712 value = storage; |
| 1711 effect = graph()->NewNode(simplified()->StoreField(field_access), | 1713 storage = receiver; |
| 1712 storage, value, effect, control); | |
| 1713 } | 1714 } |
| 1715 effect = graph()->NewNode( |
| 1716 common()->BeginRegion(RegionObservability::kObservable), effect); |
| 1717 effect = graph()->NewNode( |
| 1718 simplified()->StoreField(AccessBuilder::ForMap()), receiver, |
| 1719 jsgraph()->Constant(transition_map), effect, control); |
| 1720 effect = graph()->NewNode(simplified()->StoreField(field_access), storage, |
| 1721 value, effect, control); |
| 1722 effect = graph()->NewNode(common()->FinishRegion(), |
| 1723 jsgraph()->UndefinedConstant(), effect); |
| 1724 } else { |
| 1725 // Regular non-transitioning field store. |
| 1726 effect = graph()->NewNode(simplified()->StoreField(field_access), storage, |
| 1727 value, effect, control); |
| 1714 } | 1728 } |
| 1715 } | 1729 } |
| 1716 | 1730 |
| 1717 return ValueEffectControl(value, effect, control); | 1731 return ValueEffectControl(value, effect, control); |
| 1718 } | 1732 } |
| 1719 | 1733 |
| 1720 Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral( | 1734 Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral( |
| 1721 Node* node) { | 1735 Node* node) { |
| 1722 DCHECK_EQ(IrOpcode::kJSStoreDataPropertyInLiteral, node->opcode()); | 1736 DCHECK_EQ(IrOpcode::kJSStoreDataPropertyInLiteral, node->opcode()); |
| 1723 | 1737 |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1756 receiver_map, cached_name, AccessMode::kStoreInLiteral, | 1770 receiver_map, cached_name, AccessMode::kStoreInLiteral, |
| 1757 &access_info)) { | 1771 &access_info)) { |
| 1758 return NoChange(); | 1772 return NoChange(); |
| 1759 } | 1773 } |
| 1760 | 1774 |
| 1761 Node* receiver = NodeProperties::GetValueInput(node, 0); | 1775 Node* receiver = NodeProperties::GetValueInput(node, 0); |
| 1762 Node* effect = NodeProperties::GetEffectInput(node); | 1776 Node* effect = NodeProperties::GetEffectInput(node); |
| 1763 Node* control = NodeProperties::GetControlInput(node); | 1777 Node* control = NodeProperties::GetControlInput(node); |
| 1764 | 1778 |
| 1765 // Monomorphic property access. | 1779 // Monomorphic property access. |
| 1766 receiver = BuildCheckHeapObject(receiver, &effect, control); | 1780 PropertyAccessBuilder access_builder(jsgraph(), dependencies()); |
| 1767 | 1781 receiver = access_builder.BuildCheckHeapObject(receiver, &effect, control); |
| 1768 effect = | 1782 access_builder.BuildCheckMaps(receiver, &effect, control, |
| 1769 BuildCheckMaps(receiver, effect, control, access_info.receiver_maps()); | 1783 access_info.receiver_maps()); |
| 1770 | 1784 |
| 1771 // Ensure that {name} matches the cached name. | 1785 // Ensure that {name} matches the cached name. |
| 1772 Node* name = NodeProperties::GetValueInput(node, 1); | 1786 Node* name = NodeProperties::GetValueInput(node, 1); |
| 1773 Node* check = graph()->NewNode(simplified()->ReferenceEqual(), name, | 1787 Node* check = graph()->NewNode(simplified()->ReferenceEqual(), name, |
| 1774 jsgraph()->HeapConstant(cached_name)); | 1788 jsgraph()->HeapConstant(cached_name)); |
| 1775 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control); | 1789 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control); |
| 1776 | 1790 |
| 1777 Node* value = NodeProperties::GetValueInput(node, 2); | 1791 Node* value = NodeProperties::GetValueInput(node, 2); |
| 1778 Node* context = NodeProperties::GetContextInput(node); | 1792 Node* context = NodeProperties::GetContextInput(node); |
| 1779 Node* frame_state_lazy = NodeProperties::GetFrameStateInput(node); | 1793 Node* frame_state_lazy = NodeProperties::GetFrameStateInput(node); |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2100 | 2114 |
| 2101 // Perform the actual element access. | 2115 // Perform the actual element access. |
| 2102 effect = graph()->NewNode(simplified()->StoreElement(element_access), | 2116 effect = graph()->NewNode(simplified()->StoreElement(element_access), |
| 2103 elements, index, value, effect, control); | 2117 elements, index, value, effect, control); |
| 2104 } | 2118 } |
| 2105 } | 2119 } |
| 2106 | 2120 |
| 2107 return ValueEffectControl(value, effect, control); | 2121 return ValueEffectControl(value, effect, control); |
| 2108 } | 2122 } |
| 2109 | 2123 |
| 2110 JSNativeContextSpecialization::ValueEffectControl | |
| 2111 JSNativeContextSpecialization::InlineApiCall( | |
| 2112 Node* receiver, Node* context, Node* target, Node* frame_state, Node* value, | |
| 2113 Node* effect, Node* control, Handle<SharedFunctionInfo> shared_info, | |
| 2114 Handle<FunctionTemplateInfo> function_template_info) { | |
| 2115 Handle<CallHandlerInfo> call_handler_info = handle( | |
| 2116 CallHandlerInfo::cast(function_template_info->call_code()), isolate()); | |
| 2117 Handle<Object> call_data_object(call_handler_info->data(), isolate()); | |
| 2118 | |
| 2119 // Only setters have a value. | |
| 2120 int const argc = value == nullptr ? 0 : 1; | |
| 2121 // The stub always expects the receiver as the first param on the stack. | |
| 2122 CallApiCallbackStub stub( | |
| 2123 isolate(), argc, | |
| 2124 true /* FunctionTemplateInfo doesn't have an associated context. */); | |
| 2125 CallInterfaceDescriptor call_interface_descriptor = | |
| 2126 stub.GetCallInterfaceDescriptor(); | |
| 2127 CallDescriptor* call_descriptor = Linkage::GetStubCallDescriptor( | |
| 2128 isolate(), graph()->zone(), call_interface_descriptor, | |
| 2129 call_interface_descriptor.GetStackParameterCount() + argc + | |
| 2130 1 /* implicit receiver */, | |
| 2131 CallDescriptor::kNeedsFrameState, Operator::kNoProperties, | |
| 2132 MachineType::AnyTagged(), 1); | |
| 2133 | |
| 2134 Node* data = jsgraph()->Constant(call_data_object); | |
| 2135 ApiFunction function(v8::ToCData<Address>(call_handler_info->callback())); | |
| 2136 Node* function_reference = | |
| 2137 graph()->NewNode(common()->ExternalConstant(ExternalReference( | |
| 2138 &function, ExternalReference::DIRECT_API_CALL, isolate()))); | |
| 2139 Node* code = jsgraph()->HeapConstant(stub.GetCode()); | |
| 2140 | |
| 2141 // Add CallApiCallbackStub's register argument as well. | |
| 2142 Node* inputs[11] = { | |
| 2143 code, target, data, receiver /* holder */, function_reference, receiver}; | |
| 2144 int index = 6 + argc; | |
| 2145 inputs[index++] = context; | |
| 2146 inputs[index++] = frame_state; | |
| 2147 inputs[index++] = effect; | |
| 2148 inputs[index++] = control; | |
| 2149 // This needs to stay here because of the edge case described in | |
| 2150 // http://crbug.com/675648. | |
| 2151 if (value != nullptr) { | |
| 2152 inputs[6] = value; | |
| 2153 } | |
| 2154 | |
| 2155 Node* control0; | |
| 2156 Node* effect0; | |
| 2157 Node* value0 = effect0 = control0 = | |
| 2158 graph()->NewNode(common()->Call(call_descriptor), index, inputs); | |
| 2159 return ValueEffectControl(value0, effect0, control0); | |
| 2160 } | |
| 2161 | |
| 2162 Node* JSNativeContextSpecialization::BuildCheckHeapObject(Node* receiver, | |
| 2163 Node** effect, | |
| 2164 Node* control) { | |
| 2165 switch (receiver->opcode()) { | |
| 2166 case IrOpcode::kHeapConstant: | |
| 2167 case IrOpcode::kJSCreate: | |
| 2168 case IrOpcode::kJSCreateArguments: | |
| 2169 case IrOpcode::kJSCreateArray: | |
| 2170 case IrOpcode::kJSCreateClosure: | |
| 2171 case IrOpcode::kJSCreateIterResultObject: | |
| 2172 case IrOpcode::kJSCreateLiteralArray: | |
| 2173 case IrOpcode::kJSCreateLiteralObject: | |
| 2174 case IrOpcode::kJSCreateLiteralRegExp: | |
| 2175 case IrOpcode::kJSConvertReceiver: | |
| 2176 case IrOpcode::kJSToName: | |
| 2177 case IrOpcode::kJSToString: | |
| 2178 case IrOpcode::kJSToObject: | |
| 2179 case IrOpcode::kJSTypeOf: { | |
| 2180 return receiver; | |
| 2181 } | |
| 2182 default: { | |
| 2183 return *effect = graph()->NewNode(simplified()->CheckHeapObject(), | |
| 2184 receiver, *effect, control); | |
| 2185 } | |
| 2186 } | |
| 2187 } | |
| 2188 | |
| 2189 Node* JSNativeContextSpecialization::BuildCheckMaps( | |
| 2190 Node* receiver, Node* effect, Node* control, | |
| 2191 MapHandles const& receiver_maps) { | |
| 2192 HeapObjectMatcher m(receiver); | |
| 2193 if (m.HasValue()) { | |
| 2194 Handle<Map> receiver_map(m.Value()->map(), isolate()); | |
| 2195 if (receiver_map->is_stable()) { | |
| 2196 for (Handle<Map> map : receiver_maps) { | |
| 2197 if (map.is_identical_to(receiver_map)) { | |
| 2198 dependencies()->AssumeMapStable(receiver_map); | |
| 2199 return effect; | |
| 2200 } | |
| 2201 } | |
| 2202 } | |
| 2203 } | |
| 2204 ZoneHandleSet<Map> maps; | |
| 2205 CheckMapsFlags flags = CheckMapsFlag::kNone; | |
| 2206 for (Handle<Map> map : receiver_maps) { | |
| 2207 maps.insert(map, graph()->zone()); | |
| 2208 if (map->is_migration_target()) { | |
| 2209 flags |= CheckMapsFlag::kTryMigrateInstance; | |
| 2210 } | |
| 2211 } | |
| 2212 return graph()->NewNode(simplified()->CheckMaps(flags, maps), receiver, | |
| 2213 effect, control); | |
| 2214 } | |
| 2215 | |
| 2216 Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore( | 2124 Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore( |
| 2217 Handle<Map> map, Node* properties, Node* effect, Node* control) { | 2125 Handle<Map> map, Node* properties, Node* effect, Node* control) { |
| 2218 // TODO(bmeurer/jkummerow): Property deletions can undo map transitions | 2126 // TODO(bmeurer/jkummerow): Property deletions can undo map transitions |
| 2219 // while keeping the backing store around, meaning that even though the | 2127 // while keeping the backing store around, meaning that even though the |
| 2220 // map might believe that objects have no unused property fields, there | 2128 // map might believe that objects have no unused property fields, there |
| 2221 // might actually be some. It would be nice to not create a new backing | 2129 // might actually be some. It would be nice to not create a new backing |
| 2222 // store in that case (i.e. when properties->length() >= new_length). | 2130 // store in that case (i.e. when properties->length() >= new_length). |
| 2223 // However, introducing branches and Phi nodes here would make it more | 2131 // However, introducing branches and Phi nodes here would make it more |
| 2224 // difficult for escape analysis to get rid of the backing stores used | 2132 // difficult for escape analysis to get rid of the backing stores used |
| 2225 // for intermediate states of chains of property additions. That makes | 2133 // for intermediate states of chains of property additions. That makes |
| (...skipping 28 matching lines...) Expand all Loading... |
| 2254 simplified()->StoreField(AccessBuilder::ForFixedArrayLength()), | 2162 simplified()->StoreField(AccessBuilder::ForFixedArrayLength()), |
| 2255 new_properties, jsgraph()->Constant(new_length), effect, control); | 2163 new_properties, jsgraph()->Constant(new_length), effect, control); |
| 2256 for (int i = 0; i < new_length; ++i) { | 2164 for (int i = 0; i < new_length; ++i) { |
| 2257 effect = graph()->NewNode( | 2165 effect = graph()->NewNode( |
| 2258 simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), | 2166 simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), |
| 2259 new_properties, values[i], effect, control); | 2167 new_properties, values[i], effect, control); |
| 2260 } | 2168 } |
| 2261 return graph()->NewNode(common()->FinishRegion(), new_properties, effect); | 2169 return graph()->NewNode(common()->FinishRegion(), new_properties, effect); |
| 2262 } | 2170 } |
| 2263 | 2171 |
| 2264 void JSNativeContextSpecialization::AssumePrototypesStable( | |
| 2265 MapHandles const& receiver_maps, Handle<JSObject> holder) { | |
| 2266 // Determine actual holder and perform prototype chain checks. | |
| 2267 for (auto map : receiver_maps) { | |
| 2268 // Perform the implicit ToObject for primitives here. | |
| 2269 // Implemented according to ES6 section 7.3.2 GetV (V, P). | |
| 2270 Handle<JSFunction> constructor; | |
| 2271 if (Map::GetConstructorFunction(map, native_context()) | |
| 2272 .ToHandle(&constructor)) { | |
| 2273 map = handle(constructor->initial_map(), isolate()); | |
| 2274 } | |
| 2275 dependencies()->AssumePrototypeMapsStable(map, holder); | |
| 2276 } | |
| 2277 } | |
| 2278 | |
| 2279 bool JSNativeContextSpecialization::CanTreatHoleAsUndefined( | 2172 bool JSNativeContextSpecialization::CanTreatHoleAsUndefined( |
| 2280 MapHandles const& receiver_maps) { | 2173 MapHandles const& receiver_maps) { |
| 2281 // Check if the array prototype chain is intact. | 2174 // Check if the array prototype chain is intact. |
| 2282 if (!isolate()->IsFastArrayConstructorPrototypeChainIntact()) return false; | 2175 if (!isolate()->IsFastArrayConstructorPrototypeChainIntact()) return false; |
| 2283 | 2176 |
| 2284 // Make sure both the initial Array and Object prototypes are stable. | 2177 // Make sure both the initial Array and Object prototypes are stable. |
| 2285 Handle<JSObject> initial_array_prototype( | 2178 Handle<JSObject> initial_array_prototype( |
| 2286 native_context()->initial_array_prototype(), isolate()); | 2179 native_context()->initial_array_prototype(), isolate()); |
| 2287 Handle<JSObject> initial_object_prototype( | 2180 Handle<JSObject> initial_object_prototype( |
| 2288 native_context()->initial_object_prototype(), isolate()); | 2181 native_context()->initial_object_prototype(), isolate()); |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2426 return jsgraph()->javascript(); | 2319 return jsgraph()->javascript(); |
| 2427 } | 2320 } |
| 2428 | 2321 |
| 2429 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 2322 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
| 2430 return jsgraph()->simplified(); | 2323 return jsgraph()->simplified(); |
| 2431 } | 2324 } |
| 2432 | 2325 |
| 2433 } // namespace compiler | 2326 } // namespace compiler |
| 2434 } // namespace internal | 2327 } // namespace internal |
| 2435 } // namespace v8 | 2328 } // namespace v8 |
| OLD | NEW |