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) { | |
1528 if (field_representation == MachineRepresentation::kFloat64) { | |
1529 if (!field_index.is_inobject() || field_index.is_hidden_field() || | |
1530 !FLAG_unbox_double_fields) { | |
1531 FieldAccess const storage_access = {kTaggedBase, | |
1532 field_index.offset(), | |
1533 name, | |
1534 MaybeHandle<Map>(), | |
1535 Type::OtherInternal(), | |
1536 MachineType::TaggedPointer(), | |
1537 kPointerWriteBarrier}; | |
1538 storage = effect = | |
1539 graph()->NewNode(simplified()->LoadField(storage_access), storage, | |
1540 effect, control); | |
1541 field_access.offset = HeapNumber::kValueOffset; | |
1542 field_access.name = MaybeHandle<Name>(); | |
1543 } | |
1544 } else if (field_representation == | |
1545 MachineRepresentation::kTaggedPointer) { | |
1546 // Remember the map of the field value, if its map is stable. This is | |
1547 // used by the LoadElimination to eliminate map checks on the result. | |
1548 Handle<Map> field_map; | |
1549 if (access_info.field_map().ToHandle(&field_map)) { | |
1550 if (field_map->is_stable()) { | |
1551 dependencies()->AssumeMapStable(field_map); | |
1552 field_access.map = field_map; | |
1553 } | |
1554 } | |
1555 } | |
1556 value = effect = graph()->NewNode(simplified()->LoadField(field_access), | |
1557 storage, effect, control); | |
1558 } else { | |
1559 bool store_to_constant_field = FLAG_track_constant_fields && | 1576 bool store_to_constant_field = FLAG_track_constant_fields && |
Michael Starzinger
2017/06/16 08:32:22
nit: Indentation looks off starting here, all the
Jarin
2017/06/16 09:32:27
Done.
| |
1560 (access_mode == AccessMode::kStore) && | 1577 (access_mode == AccessMode::kStore) && |
1561 access_info.IsDataConstantField(); | 1578 access_info.IsDataConstantField(); |
1562 | 1579 |
1563 DCHECK(access_mode == AccessMode::kStore || | 1580 DCHECK(access_mode == AccessMode::kStore || |
1564 access_mode == AccessMode::kStoreInLiteral); | 1581 access_mode == AccessMode::kStoreInLiteral); |
1565 switch (field_representation) { | 1582 switch (field_representation) { |
1566 case MachineRepresentation::kFloat64: { | 1583 case MachineRepresentation::kFloat64: { |
1567 value = effect = graph()->NewNode(simplified()->CheckNumber(), value, | 1584 value = effect = graph()->NewNode(simplified()->CheckNumber(), value, |
1568 effect, control); | 1585 effect, control); |
1569 if (!field_index.is_inobject() || field_index.is_hidden_field() || | 1586 if (!field_index.is_inobject() || field_index.is_hidden_field() || |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1641 } | 1658 } |
1642 | 1659 |
1643 if (field_representation == MachineRepresentation::kTaggedSigned) { | 1660 if (field_representation == MachineRepresentation::kTaggedSigned) { |
1644 value = effect = graph()->NewNode(simplified()->CheckSmi(), value, | 1661 value = effect = graph()->NewNode(simplified()->CheckSmi(), value, |
1645 effect, control); | 1662 effect, control); |
1646 field_access.write_barrier_kind = kNoWriteBarrier; | 1663 field_access.write_barrier_kind = kNoWriteBarrier; |
1647 | 1664 |
1648 } else if (field_representation == | 1665 } else if (field_representation == |
1649 MachineRepresentation::kTaggedPointer) { | 1666 MachineRepresentation::kTaggedPointer) { |
1650 // Ensure that {value} is a HeapObject. | 1667 // Ensure that {value} is a HeapObject. |
1651 value = BuildCheckHeapObject(value, &effect, control); | 1668 value = |
1669 access_builder.BuildCheckHeapObject(value, &effect, control); | |
1652 Handle<Map> field_map; | 1670 Handle<Map> field_map; |
1653 if (access_info.field_map().ToHandle(&field_map)) { | 1671 if (access_info.field_map().ToHandle(&field_map)) { |
1654 // Emit a map check for the value. | 1672 // Emit a map check for the value. |
1655 effect = graph()->NewNode( | 1673 effect = graph()->NewNode( |
1656 simplified()->CheckMaps(CheckMapsFlag::kNone, | 1674 simplified()->CheckMaps(CheckMapsFlag::kNone, |
1657 ZoneHandleSet<Map>(field_map)), | 1675 ZoneHandleSet<Map>(field_map)), |
1658 value, effect, control); | 1676 value, effect, control); |
1659 } | 1677 } |
1660 field_access.write_barrier_kind = kPointerWriteBarrier; | 1678 field_access.write_barrier_kind = kPointerWriteBarrier; |
1661 | 1679 |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1705 effect = graph()->NewNode(simplified()->StoreField(field_access), | 1723 effect = graph()->NewNode(simplified()->StoreField(field_access), |
1706 storage, value, effect, control); | 1724 storage, value, effect, control); |
1707 effect = graph()->NewNode(common()->FinishRegion(), | 1725 effect = graph()->NewNode(common()->FinishRegion(), |
1708 jsgraph()->UndefinedConstant(), effect); | 1726 jsgraph()->UndefinedConstant(), effect); |
1709 } else { | 1727 } else { |
1710 // Regular non-transitioning field store. | 1728 // Regular non-transitioning field store. |
1711 effect = graph()->NewNode(simplified()->StoreField(field_access), | 1729 effect = graph()->NewNode(simplified()->StoreField(field_access), |
1712 storage, value, effect, control); | 1730 storage, value, effect, control); |
1713 } | 1731 } |
1714 } | 1732 } |
1715 } | |
1716 | 1733 |
1717 return ValueEffectControl(value, effect, control); | 1734 return ValueEffectControl(value, effect, control); |
1718 } | 1735 } |
1719 | 1736 |
1720 Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral( | 1737 Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral( |
1721 Node* node) { | 1738 Node* node) { |
1722 DCHECK_EQ(IrOpcode::kJSStoreDataPropertyInLiteral, node->opcode()); | 1739 DCHECK_EQ(IrOpcode::kJSStoreDataPropertyInLiteral, node->opcode()); |
1723 | 1740 |
1724 FeedbackParameter const& p = FeedbackParameterOf(node->op()); | 1741 FeedbackParameter const& p = FeedbackParameterOf(node->op()); |
1725 | 1742 |
(...skipping 30 matching lines...) Expand all Loading... | |
1756 receiver_map, cached_name, AccessMode::kStoreInLiteral, | 1773 receiver_map, cached_name, AccessMode::kStoreInLiteral, |
1757 &access_info)) { | 1774 &access_info)) { |
1758 return NoChange(); | 1775 return NoChange(); |
1759 } | 1776 } |
1760 | 1777 |
1761 Node* receiver = NodeProperties::GetValueInput(node, 0); | 1778 Node* receiver = NodeProperties::GetValueInput(node, 0); |
1762 Node* effect = NodeProperties::GetEffectInput(node); | 1779 Node* effect = NodeProperties::GetEffectInput(node); |
1763 Node* control = NodeProperties::GetControlInput(node); | 1780 Node* control = NodeProperties::GetControlInput(node); |
1764 | 1781 |
1765 // Monomorphic property access. | 1782 // Monomorphic property access. |
1766 receiver = BuildCheckHeapObject(receiver, &effect, control); | 1783 PropertyAccessBuilder access_builder(jsgraph(), dependencies()); |
1767 | 1784 receiver = access_builder.BuildCheckHeapObject(receiver, &effect, control); |
1768 effect = | 1785 access_builder.BuildCheckMaps(receiver, &effect, control, |
1769 BuildCheckMaps(receiver, effect, control, access_info.receiver_maps()); | 1786 access_info.receiver_maps()); |
1770 | 1787 |
1771 // Ensure that {name} matches the cached name. | 1788 // Ensure that {name} matches the cached name. |
1772 Node* name = NodeProperties::GetValueInput(node, 1); | 1789 Node* name = NodeProperties::GetValueInput(node, 1); |
1773 Node* check = graph()->NewNode(simplified()->ReferenceEqual(), name, | 1790 Node* check = graph()->NewNode(simplified()->ReferenceEqual(), name, |
1774 jsgraph()->HeapConstant(cached_name)); | 1791 jsgraph()->HeapConstant(cached_name)); |
1775 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control); | 1792 effect = graph()->NewNode(simplified()->CheckIf(), check, effect, control); |
1776 | 1793 |
1777 Node* value = NodeProperties::GetValueInput(node, 2); | 1794 Node* value = NodeProperties::GetValueInput(node, 2); |
1778 Node* context = NodeProperties::GetContextInput(node); | 1795 Node* context = NodeProperties::GetContextInput(node); |
1779 Node* frame_state_lazy = NodeProperties::GetFrameStateInput(node); | 1796 Node* frame_state_lazy = NodeProperties::GetFrameStateInput(node); |
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2100 | 2117 |
2101 // Perform the actual element access. | 2118 // Perform the actual element access. |
2102 effect = graph()->NewNode(simplified()->StoreElement(element_access), | 2119 effect = graph()->NewNode(simplified()->StoreElement(element_access), |
2103 elements, index, value, effect, control); | 2120 elements, index, value, effect, control); |
2104 } | 2121 } |
2105 } | 2122 } |
2106 | 2123 |
2107 return ValueEffectControl(value, effect, control); | 2124 return ValueEffectControl(value, effect, control); |
2108 } | 2125 } |
2109 | 2126 |
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( | 2127 Node* JSNativeContextSpecialization::BuildExtendPropertiesBackingStore( |
2217 Handle<Map> map, Node* properties, Node* effect, Node* control) { | 2128 Handle<Map> map, Node* properties, Node* effect, Node* control) { |
2218 // TODO(bmeurer/jkummerow): Property deletions can undo map transitions | 2129 // TODO(bmeurer/jkummerow): Property deletions can undo map transitions |
2219 // while keeping the backing store around, meaning that even though the | 2130 // while keeping the backing store around, meaning that even though the |
2220 // map might believe that objects have no unused property fields, there | 2131 // 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 | 2132 // 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). | 2133 // store in that case (i.e. when properties->length() >= new_length). |
2223 // However, introducing branches and Phi nodes here would make it more | 2134 // However, introducing branches and Phi nodes here would make it more |
2224 // difficult for escape analysis to get rid of the backing stores used | 2135 // difficult for escape analysis to get rid of the backing stores used |
2225 // for intermediate states of chains of property additions. That makes | 2136 // for intermediate states of chains of property additions. That makes |
(...skipping 28 matching lines...) Expand all Loading... | |
2254 simplified()->StoreField(AccessBuilder::ForFixedArrayLength()), | 2165 simplified()->StoreField(AccessBuilder::ForFixedArrayLength()), |
2255 new_properties, jsgraph()->Constant(new_length), effect, control); | 2166 new_properties, jsgraph()->Constant(new_length), effect, control); |
2256 for (int i = 0; i < new_length; ++i) { | 2167 for (int i = 0; i < new_length; ++i) { |
2257 effect = graph()->NewNode( | 2168 effect = graph()->NewNode( |
2258 simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), | 2169 simplified()->StoreField(AccessBuilder::ForFixedArraySlot(i)), |
2259 new_properties, values[i], effect, control); | 2170 new_properties, values[i], effect, control); |
2260 } | 2171 } |
2261 return graph()->NewNode(common()->FinishRegion(), new_properties, effect); | 2172 return graph()->NewNode(common()->FinishRegion(), new_properties, effect); |
2262 } | 2173 } |
2263 | 2174 |
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( | 2175 bool JSNativeContextSpecialization::CanTreatHoleAsUndefined( |
2280 MapHandles const& receiver_maps) { | 2176 MapHandles const& receiver_maps) { |
2281 // Check if the array prototype chain is intact. | 2177 // Check if the array prototype chain is intact. |
2282 if (!isolate()->IsFastArrayConstructorPrototypeChainIntact()) return false; | 2178 if (!isolate()->IsFastArrayConstructorPrototypeChainIntact()) return false; |
2283 | 2179 |
2284 // Make sure both the initial Array and Object prototypes are stable. | 2180 // Make sure both the initial Array and Object prototypes are stable. |
2285 Handle<JSObject> initial_array_prototype( | 2181 Handle<JSObject> initial_array_prototype( |
2286 native_context()->initial_array_prototype(), isolate()); | 2182 native_context()->initial_array_prototype(), isolate()); |
2287 Handle<JSObject> initial_object_prototype( | 2183 Handle<JSObject> initial_object_prototype( |
2288 native_context()->initial_object_prototype(), isolate()); | 2184 native_context()->initial_object_prototype(), isolate()); |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2426 return jsgraph()->javascript(); | 2322 return jsgraph()->javascript(); |
2427 } | 2323 } |
2428 | 2324 |
2429 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 2325 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
2430 return jsgraph()->simplified(); | 2326 return jsgraph()->simplified(); |
2431 } | 2327 } |
2432 | 2328 |
2433 } // namespace compiler | 2329 } // namespace compiler |
2434 } // namespace internal | 2330 } // namespace internal |
2435 } // namespace v8 | 2331 } // namespace v8 |
OLD | NEW |