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