Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(531)

Side by Side Diff: src/compiler/js-native-context-specialization.cc

Issue 2067423003: [turbofan] Properly handle dictionary maps in the prototype chain. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@TurboFan_CheckedOperators
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/compiler/js-native-context-specialization.h ('k') | test/mjsunit/regress/regress-crbug-616709.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698