OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/js-native-context-specialization.h" | 5 #include "src/compiler/js-native-context-specialization.h" |
6 | 6 |
7 #include "src/accessors.h" | 7 #include "src/accessors.h" |
8 #include "src/code-factory.h" | 8 #include "src/code-factory.h" |
9 #include "src/compilation-dependencies.h" | 9 #include "src/compilation-dependencies.h" |
10 #include "src/compiler/access-builder.h" | 10 #include "src/compiler/access-builder.h" |
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 this_effect = | 218 this_effect = |
219 (this_control_count == 1) | 219 (this_control_count == 1) |
220 ? this_effects.front() | 220 ? this_effects.front() |
221 : graph()->NewNode(common()->EffectPhi(this_control_count), | 221 : graph()->NewNode(common()->EffectPhi(this_control_count), |
222 this_effect_count, &this_effects.front()); | 222 this_effect_count, &this_effects.front()); |
223 } | 223 } |
224 | 224 |
225 // Determine actual holder and perform prototype chain checks. | 225 // Determine actual holder and perform prototype chain checks. |
226 Handle<JSObject> holder; | 226 Handle<JSObject> holder; |
227 if (access_info.holder().ToHandle(&holder)) { | 227 if (access_info.holder().ToHandle(&holder)) { |
228 this_effect = CheckPrototypeMaps(receiver_type, native_context, holder, | 228 AssumePrototypesStable(receiver_type, native_context, holder); |
229 this_effect, this_control); | |
230 } | 229 } |
231 | 230 |
232 // Generate the actual property access. | 231 // Generate the actual property access. |
233 if (access_info.IsNotFound()) { | 232 if (access_info.IsNotFound()) { |
234 DCHECK_EQ(AccessMode::kLoad, access_mode); | 233 DCHECK_EQ(AccessMode::kLoad, access_mode); |
235 this_value = jsgraph()->UndefinedConstant(); | 234 this_value = jsgraph()->UndefinedConstant(); |
236 } else if (access_info.IsDataConstant()) { | 235 } else if (access_info.IsDataConstant()) { |
237 this_value = jsgraph()->Constant(access_info.constant()); | 236 this_value = jsgraph()->Constant(access_info.constant()); |
238 if (access_mode == AccessMode::kStore) { | 237 if (access_mode == AccessMode::kStore) { |
239 Node* check = graph()->NewNode( | 238 Node* check = graph()->NewNode( |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
662 // observable by JavaScript. | 661 // observable by JavaScript. |
663 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state, | 662 this_effect = graph()->NewNode(common()->Checkpoint(), frame_state, |
664 this_effect, this_control); | 663 this_effect, this_control); |
665 } | 664 } |
666 | 665 |
667 // Certain stores need a prototype chain check because shape changes | 666 // Certain stores need a prototype chain check because shape changes |
668 // could allow callbacks on elements in the prototype chain that are | 667 // could allow callbacks on elements in the prototype chain that are |
669 // not compatible with (monomorphic) keyed stores. | 668 // not compatible with (monomorphic) keyed stores. |
670 Handle<JSObject> holder; | 669 Handle<JSObject> holder; |
671 if (access_info.holder().ToHandle(&holder)) { | 670 if (access_info.holder().ToHandle(&holder)) { |
672 this_effect = CheckPrototypeMaps(receiver_type, native_context, holder, | 671 AssumePrototypesStable(receiver_type, native_context, holder); |
673 this_effect, this_control); | |
674 } | 672 } |
675 | 673 |
676 // TODO(bmeurer): We currently specialize based on elements kind. We should | 674 // TODO(bmeurer): We currently specialize based on elements kind. We should |
677 // also be able to properly support strings and other JSObjects here. | 675 // also be able to properly support strings and other JSObjects here. |
678 ElementsKind elements_kind = access_info.elements_kind(); | 676 ElementsKind elements_kind = access_info.elements_kind(); |
679 | 677 |
680 // Load the elements for the {receiver}. | 678 // Load the elements for the {receiver}. |
681 Node* this_elements = this_effect = graph()->NewNode( | 679 Node* this_elements = this_effect = graph()->NewNode( |
682 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), | 680 simplified()->LoadField(AccessBuilder::ForJSObjectElements()), |
683 this_receiver, this_effect, this_control); | 681 this_receiver, this_effect, this_control); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
748 elements_kind == FAST_HOLEY_SMI_ELEMENTS) { | 746 elements_kind == FAST_HOLEY_SMI_ELEMENTS) { |
749 // Perform the hole check on the result. | 747 // Perform the hole check on the result. |
750 CheckTaggedHoleMode mode = CheckTaggedHoleMode::kNeverReturnHole; | 748 CheckTaggedHoleMode mode = CheckTaggedHoleMode::kNeverReturnHole; |
751 // Check if we are allowed to turn the hole into undefined. | 749 // Check if we are allowed to turn the hole into undefined. |
752 Type* initial_holey_array_type = Type::Class( | 750 Type* initial_holey_array_type = Type::Class( |
753 handle(isolate()->get_initial_js_array_map(elements_kind)), | 751 handle(isolate()->get_initial_js_array_map(elements_kind)), |
754 graph()->zone()); | 752 graph()->zone()); |
755 if (receiver_type->NowIs(initial_holey_array_type) && | 753 if (receiver_type->NowIs(initial_holey_array_type) && |
756 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { | 754 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { |
757 // Add a code dependency on the array protector cell. | 755 // Add a code dependency on the array protector cell. |
758 this_effect = CheckPrototypeMaps( | 756 AssumePrototypesStable(receiver_type, native_context, |
759 receiver_type, native_context, | 757 isolate()->initial_object_prototype()); |
760 isolate()->initial_object_prototype(), this_effect, this_control); | |
761 dependencies()->AssumePropertyCell(factory()->array_protector()); | 758 dependencies()->AssumePropertyCell(factory()->array_protector()); |
762 // Turn the hole into undefined. | 759 // Turn the hole into undefined. |
763 mode = CheckTaggedHoleMode::kConvertHoleToUndefined; | 760 mode = CheckTaggedHoleMode::kConvertHoleToUndefined; |
764 } | 761 } |
765 this_value = this_effect = | 762 this_value = this_effect = |
766 graph()->NewNode(simplified()->CheckTaggedHole(mode), this_value, | 763 graph()->NewNode(simplified()->CheckTaggedHole(mode), this_value, |
767 this_effect, this_control); | 764 this_effect, this_control); |
768 } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) { | 765 } else if (elements_kind == FAST_HOLEY_DOUBLE_ELEMENTS) { |
769 // Perform the hole check on the result. | 766 // Perform the hole check on the result. |
770 CheckFloat64HoleMode mode = CheckFloat64HoleMode::kNeverReturnHole; | 767 CheckFloat64HoleMode mode = CheckFloat64HoleMode::kNeverReturnHole; |
771 // Check if we are allowed to return the hole directly. | 768 // Check if we are allowed to return the hole directly. |
772 Type* initial_holey_array_type = Type::Class( | 769 Type* initial_holey_array_type = Type::Class( |
773 handle(isolate()->get_initial_js_array_map(elements_kind)), | 770 handle(isolate()->get_initial_js_array_map(elements_kind)), |
774 graph()->zone()); | 771 graph()->zone()); |
775 if (receiver_type->NowIs(initial_holey_array_type) && | 772 if (receiver_type->NowIs(initial_holey_array_type) && |
776 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { | 773 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { |
777 // Add a code dependency on the array protector cell. | 774 // Add a code dependency on the array protector cell. |
778 this_effect = CheckPrototypeMaps( | 775 AssumePrototypesStable(receiver_type, native_context, |
779 receiver_type, native_context, | 776 isolate()->initial_object_prototype()); |
780 isolate()->initial_object_prototype(), this_effect, this_control); | |
781 dependencies()->AssumePropertyCell(factory()->array_protector()); | 777 dependencies()->AssumePropertyCell(factory()->array_protector()); |
782 // Return the signaling NaN hole directly if all uses are truncating. | 778 // Return the signaling NaN hole directly if all uses are truncating. |
783 mode = CheckFloat64HoleMode::kAllowReturnHole; | 779 mode = CheckFloat64HoleMode::kAllowReturnHole; |
784 } | 780 } |
785 this_value = this_effect = | 781 this_value = this_effect = |
786 graph()->NewNode(simplified()->CheckFloat64Hole(mode), this_value, | 782 graph()->NewNode(simplified()->CheckFloat64Hole(mode), this_value, |
787 this_effect, this_control); | 783 this_effect, this_control); |
788 } | 784 } |
789 } else { | 785 } else { |
790 DCHECK_EQ(AccessMode::kStore, access_mode); | 786 DCHECK_EQ(AccessMode::kStore, access_mode); |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
953 KeyedStoreICNexus nexus(p.feedback().vector(), p.feedback().slot()); | 949 KeyedStoreICNexus nexus(p.feedback().vector(), p.feedback().slot()); |
954 | 950 |
955 // Extract the keyed access store mode from the KEYED_STORE_IC. | 951 // Extract the keyed access store mode from the KEYED_STORE_IC. |
956 KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode(); | 952 KeyedAccessStoreMode store_mode = nexus.GetKeyedAccessStoreMode(); |
957 | 953 |
958 // Try to lower the keyed access based on the {nexus}. | 954 // Try to lower the keyed access based on the {nexus}. |
959 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore, | 955 return ReduceKeyedAccess(node, index, value, nexus, AccessMode::kStore, |
960 p.language_mode(), store_mode); | 956 p.language_mode(), store_mode); |
961 } | 957 } |
962 | 958 |
963 Node* JSNativeContextSpecialization::CheckPrototypeMaps( | 959 |
| 960 void JSNativeContextSpecialization::AssumePrototypesStable( |
964 Type* receiver_type, Handle<Context> native_context, | 961 Type* receiver_type, Handle<Context> native_context, |
965 Handle<JSObject> holder, Node* effect, Node* control) { | 962 Handle<JSObject> holder) { |
966 // Determine actual holder and perform prototype chain checks. | 963 // Determine actual holder and perform prototype chain checks. |
967 for (auto i = receiver_type->Classes(); !i.Done(); i.Advance()) { | 964 for (auto i = receiver_type->Classes(); !i.Done(); i.Advance()) { |
968 Handle<Map> map = i.Current(); | 965 Handle<Map> map = i.Current(); |
969 // Perform the implicit ToObject for primitives here. | 966 // Perform the implicit ToObject for primitives here. |
970 // Implemented according to ES6 section 7.3.2 GetV (V, P). | 967 // Implemented according to ES6 section 7.3.2 GetV (V, P). |
971 Handle<JSFunction> constructor; | 968 Handle<JSFunction> constructor; |
972 if (Map::GetConstructorFunction(map, native_context) | 969 if (Map::GetConstructorFunction(map, native_context) |
973 .ToHandle(&constructor)) { | 970 .ToHandle(&constructor)) { |
974 map = handle(constructor->initial_map(), isolate()); | 971 map = handle(constructor->initial_map(), isolate()); |
975 } | 972 } |
976 for (PrototypeIterator j(map); !j.IsAtEnd(); j.Advance()) { | 973 dependencies()->AssumePrototypeMapsStable(map, holder); |
977 Handle<JSReceiver> const current = | |
978 PrototypeIterator::GetCurrent<JSReceiver>(j); | |
979 Handle<Map> current_map(current->map(), isolate()); | |
980 if (current_map->is_stable()) { | |
981 dependencies()->AssumeMapStable(current_map); | |
982 } else { | |
983 // TODO(bmeurer): Introduce a dedicated CheckMaps operator. | |
984 Node* prototype = jsgraph()->HeapConstant(current); | |
985 Node* prototype_map = effect = | |
986 graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), | |
987 prototype, effect, control); | |
988 Node* check = graph()->NewNode( | |
989 simplified()->ReferenceEqual(Type::Internal()), prototype_map, | |
990 jsgraph()->HeapConstant(current_map)); | |
991 effect = | |
992 graph()->NewNode(simplified()->CheckIf(), check, effect, control); | |
993 } | |
994 if (holder.is_identical_to(current)) break; | |
995 } | |
996 } | 974 } |
997 return effect; | |
998 } | 975 } |
999 | 976 |
1000 bool JSNativeContextSpecialization::ExtractReceiverMaps( | 977 bool JSNativeContextSpecialization::ExtractReceiverMaps( |
1001 Node* receiver, Node* effect, FeedbackNexus const& nexus, | 978 Node* receiver, Node* effect, FeedbackNexus const& nexus, |
1002 MapHandleList* receiver_maps) { | 979 MapHandleList* receiver_maps) { |
1003 DCHECK_EQ(0, receiver_maps->length()); | 980 DCHECK_EQ(0, receiver_maps->length()); |
1004 // See if we can infer a concrete type for the {receiver}. | 981 // See if we can infer a concrete type for the {receiver}. |
1005 Handle<Map> receiver_map; | 982 Handle<Map> receiver_map; |
1006 if (InferReceiverMap(receiver, effect).ToHandle(&receiver_map)) { | 983 if (InferReceiverMap(receiver, effect).ToHandle(&receiver_map)) { |
1007 // We can assume that the {receiver} still has the infered {receiver_map}. | 984 // We can assume that the {receiver} still has the infered {receiver_map}. |
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1114 } | 1091 } |
1115 | 1092 |
1116 | 1093 |
1117 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 1094 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
1118 return jsgraph()->simplified(); | 1095 return jsgraph()->simplified(); |
1119 } | 1096 } |
1120 | 1097 |
1121 } // namespace compiler | 1098 } // namespace compiler |
1122 } // namespace internal | 1099 } // namespace internal |
1123 } // namespace v8 | 1100 } // namespace v8 |
OLD | NEW |