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

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

Issue 1972563002: [turbofan] Infer some receiver maps when lowering loads/stores. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Make tests happy. Created 4 years, 7 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
« no previous file with comments | « src/compiler/js-native-context-specialization.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 410 matching lines...) Expand 10 before | Expand all | Expand 10 after
421 ReplaceWithValue(node, value, effect, control); 421 ReplaceWithValue(node, value, effect, control);
422 return Replace(value); 422 return Replace(value);
423 } 423 }
424 424
425 425
426 Reduction JSNativeContextSpecialization::ReduceNamedAccess( 426 Reduction JSNativeContextSpecialization::ReduceNamedAccess(
427 Node* node, Node* value, FeedbackNexus const& nexus, Handle<Name> name, 427 Node* node, Node* value, FeedbackNexus const& nexus, Handle<Name> name,
428 AccessMode access_mode, LanguageMode language_mode) { 428 AccessMode access_mode, LanguageMode language_mode) {
429 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed || 429 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed ||
430 node->opcode() == IrOpcode::kJSStoreNamed); 430 node->opcode() == IrOpcode::kJSStoreNamed);
431 Node* const receiver = NodeProperties::GetValueInput(node, 0);
432 Node* const effect = NodeProperties::GetEffectInput(node);
431 433
432 // Check if the {nexus} reports type feedback for the IC. 434 // Check if the {nexus} reports type feedback for the IC.
433 if (nexus.IsUninitialized()) { 435 if (nexus.IsUninitialized()) {
434 if ((flags() & kDeoptimizationEnabled) && 436 if ((flags() & kDeoptimizationEnabled) &&
435 (flags() & kBailoutOnUninitialized)) { 437 (flags() & kBailoutOnUninitialized)) {
436 // TODO(turbofan): Implement all eager bailout points correctly in 438 // TODO(turbofan): Implement all eager bailout points correctly in
437 // the graph builder. 439 // the graph builder.
438 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 440 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
439 if (!OpParameter<FrameStateInfo>(frame_state).bailout_id().IsNone()) { 441 if (!OpParameter<FrameStateInfo>(frame_state).bailout_id().IsNone()) {
440 return ReduceSoftDeoptimize(node); 442 return ReduceSoftDeoptimize(node);
441 } 443 }
442 } 444 }
443 return NoChange(); 445 return NoChange();
444 } 446 }
445 447
446 // Extract receiver maps from the IC using the {nexus}. 448 // Extract receiver maps from the IC using the {nexus}.
447 MapHandleList receiver_maps; 449 MapHandleList receiver_maps;
448 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange(); 450 if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
449 DCHECK_LT(0, receiver_maps.length()); 451 return NoChange();
452 } else if (receiver_maps.length() == 0) {
453 if ((flags() & kDeoptimizationEnabled) &&
454 (flags() & kBailoutOnUninitialized)) {
455 // TODO(turbofan): Implement all eager bailout points correctly in
456 // the graph builder.
457 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
458 if (!OpParameter<FrameStateInfo>(frame_state).bailout_id().IsNone()) {
459 return ReduceSoftDeoptimize(node);
460 }
461 }
462 return NoChange();
463 }
450 464
451 // Try to lower the named access based on the {receiver_maps}. 465 // Try to lower the named access based on the {receiver_maps}.
452 return ReduceNamedAccess(node, value, receiver_maps, name, access_mode, 466 return ReduceNamedAccess(node, value, receiver_maps, name, access_mode,
453 language_mode); 467 language_mode);
454 } 468 }
455 469
456 470
457 Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) { 471 Reduction JSNativeContextSpecialization::ReduceJSLoadNamed(Node* node) {
458 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode()); 472 DCHECK_EQ(IrOpcode::kJSLoadNamed, node->opcode());
459 NamedAccess const& p = NamedAccessOf(node->op()); 473 NamedAccess const& p = NamedAccessOf(node->op());
460 Node* const receiver = NodeProperties::GetValueInput(node, 0); 474 Node* const receiver = NodeProperties::GetValueInput(node, 0);
461 Node* const value = jsgraph()->Dead(); 475 Node* const value = jsgraph()->Dead();
462 476
463 // Check if we have a constant receiver. 477 // Check if we have a constant receiver.
464 HeapObjectMatcher m(receiver); 478 HeapObjectMatcher m(receiver);
465 if (m.HasValue()) { 479 if (m.HasValue()) {
466 // Optimize "prototype" property of functions. 480 // Optimize "prototype" property of functions.
467 if (m.Value()->IsJSFunction() && 481 if (m.Value()->IsJSFunction() &&
468 p.name().is_identical_to(factory()->prototype_string())) { 482 p.name().is_identical_to(factory()->prototype_string())) {
469 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value()); 483 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value());
470 if (function->has_initial_map()) { 484 if (function->has_initial_map()) {
471 // We need to add a code dependency on the initial map of the 485 // We need to add a code dependency on the initial map of the
472 // {function} in order to be notified about changes to the 486 // {function} in order to be notified about changes to the
473 // "prototype" of {function}, so it doesn't make sense to 487 // "prototype" of {function}, so it doesn't make sense to
474 // continue unless deoptimization is enabled. 488 // continue unless deoptimization is enabled.
475 if ((flags() & kDeoptimizationEnabled)) { 489 if (flags() & kDeoptimizationEnabled) {
476 Handle<Map> initial_map(function->initial_map(), isolate()); 490 Handle<Map> initial_map(function->initial_map(), isolate());
477 dependencies()->AssumeInitialMapCantChange(initial_map); 491 dependencies()->AssumeInitialMapCantChange(initial_map);
478 Handle<Object> prototype(initial_map->prototype(), isolate()); 492 Handle<Object> prototype(initial_map->prototype(), isolate());
479 Node* value = jsgraph()->Constant(prototype); 493 Node* value = jsgraph()->Constant(prototype);
480 ReplaceWithValue(node, value); 494 ReplaceWithValue(node, value);
481 return Replace(value); 495 return Replace(value);
482 } 496 }
483 } 497 }
484 } 498 }
485 } 499 }
(...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after
889 return Replace(value); 903 return Replace(value);
890 } 904 }
891 905
892 906
893 Reduction JSNativeContextSpecialization::ReduceKeyedAccess( 907 Reduction JSNativeContextSpecialization::ReduceKeyedAccess(
894 Node* node, Node* index, Node* value, FeedbackNexus const& nexus, 908 Node* node, Node* index, Node* value, FeedbackNexus const& nexus,
895 AccessMode access_mode, LanguageMode language_mode, 909 AccessMode access_mode, LanguageMode language_mode,
896 KeyedAccessStoreMode store_mode) { 910 KeyedAccessStoreMode store_mode) {
897 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || 911 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty ||
898 node->opcode() == IrOpcode::kJSStoreProperty); 912 node->opcode() == IrOpcode::kJSStoreProperty);
913 Node* const receiver = NodeProperties::GetValueInput(node, 0);
914 Node* const effect = NodeProperties::GetEffectInput(node);
899 915
900 // Check if the {nexus} reports type feedback for the IC. 916 // Check if the {nexus} reports type feedback for the IC.
901 if (nexus.IsUninitialized()) { 917 if (nexus.IsUninitialized()) {
902 if ((flags() & kDeoptimizationEnabled) && 918 if ((flags() & kDeoptimizationEnabled) &&
903 (flags() & kBailoutOnUninitialized)) { 919 (flags() & kBailoutOnUninitialized)) {
904 // TODO(turbofan): Implement all eager bailout points correctly in 920 // TODO(turbofan): Implement all eager bailout points correctly in
905 // the graph builder. 921 // the graph builder.
906 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1); 922 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
907 if (!OpParameter<FrameStateInfo>(frame_state).bailout_id().IsNone()) { 923 if (!OpParameter<FrameStateInfo>(frame_state).bailout_id().IsNone()) {
908 return ReduceSoftDeoptimize(node); 924 return ReduceSoftDeoptimize(node);
909 } 925 }
910 } 926 }
911 return NoChange(); 927 return NoChange();
912 } 928 }
913 929
914 // Extract receiver maps from the {nexus}. 930 // Extract receiver maps from the {nexus}.
915 MapHandleList receiver_maps; 931 MapHandleList receiver_maps;
916 if (nexus.ExtractMaps(&receiver_maps) == 0) return NoChange(); 932 if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) {
917 DCHECK_LT(0, receiver_maps.length()); 933 return NoChange();
934 } else if (receiver_maps.length() == 0) {
935 if ((flags() & kDeoptimizationEnabled) &&
936 (flags() & kBailoutOnUninitialized)) {
937 // TODO(turbofan): Implement all eager bailout points correctly in
938 // the graph builder.
939 Node* frame_state = NodeProperties::GetFrameStateInput(node, 1);
940 if (!OpParameter<FrameStateInfo>(frame_state).bailout_id().IsNone()) {
941 return ReduceSoftDeoptimize(node);
942 }
943 }
944 return NoChange();
945 }
918 946
919 // Optimize access for constant {index}. 947 // Optimize access for constant {index}.
920 HeapObjectMatcher mindex(index); 948 HeapObjectMatcher mindex(index);
921 if (mindex.HasValue() && mindex.Value()->IsPrimitive()) { 949 if (mindex.HasValue() && mindex.Value()->IsPrimitive()) {
922 // Keyed access requires a ToPropertyKey on the {index} first before 950 // Keyed access requires a ToPropertyKey on the {index} first before
923 // looking up the property on the object (see ES6 section 12.3.2.1). 951 // looking up the property on the object (see ES6 section 12.3.2.1).
924 // We can only do this for non-observable ToPropertyKey invocations, 952 // We can only do this for non-observable ToPropertyKey invocations,
925 // so we limit the constant indices to primitives at this point. 953 // so we limit the constant indices to primitives at this point.
926 Handle<Name> name; 954 Handle<Name> name;
927 if (Object::ToName(isolate(), mindex.Value()).ToHandle(&name)) { 955 if (Object::ToName(isolate(), mindex.Value()).ToHandle(&name)) {
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
1011 // Implemented according to ES6 section 7.3.2 GetV (V, P). 1039 // Implemented according to ES6 section 7.3.2 GetV (V, P).
1012 Handle<JSFunction> constructor; 1040 Handle<JSFunction> constructor;
1013 if (Map::GetConstructorFunction(map, native_context) 1041 if (Map::GetConstructorFunction(map, native_context)
1014 .ToHandle(&constructor)) { 1042 .ToHandle(&constructor)) {
1015 map = handle(constructor->initial_map(), isolate()); 1043 map = handle(constructor->initial_map(), isolate());
1016 } 1044 }
1017 dependencies()->AssumePrototypeMapsStable(map, holder); 1045 dependencies()->AssumePrototypeMapsStable(map, holder);
1018 } 1046 }
1019 } 1047 }
1020 1048
1049 bool JSNativeContextSpecialization::ExtractReceiverMaps(
1050 Node* receiver, Node* effect, FeedbackNexus const& nexus,
1051 MapHandleList* receiver_maps) {
1052 DCHECK_EQ(0, receiver_maps->length());
1053 // See if we can infer a concrete type for the {receiver}.
1054 Handle<Map> receiver_map;
1055 if (InferReceiverMap(receiver, effect).ToHandle(&receiver_map)) {
1056 // We can assume that the {receiver} still has the infered {receiver_map}.
1057 receiver_maps->Add(receiver_map);
1058 return true;
1059 }
1060 // Try to extract some maps from the {nexus}.
1061 if (nexus.ExtractMaps(receiver_maps) != 0) {
1062 // Try to filter impossible candidates based on infered root map.
1063 if (InferReceiverRootMap(receiver).ToHandle(&receiver_map)) {
1064 for (int i = receiver_maps->length(); --i >= 0;) {
1065 if (receiver_maps->at(i)->FindRootMap() != *receiver_map) {
1066 receiver_maps->Remove(i);
1067 }
1068 }
1069 }
1070 return true;
1071 }
1072 return false;
1073 }
1074
1075 MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverMap(Node* receiver,
1076 Node* effect) {
1077 NodeMatcher m(receiver);
1078 if (m.IsJSCreate()) {
1079 HeapObjectMatcher mtarget(m.InputAt(0));
1080 HeapObjectMatcher mnewtarget(m.InputAt(1));
1081 if (mtarget.HasValue() && mnewtarget.HasValue()) {
1082 Handle<JSFunction> constructor =
1083 Handle<JSFunction>::cast(mtarget.Value());
1084 if (constructor->has_initial_map()) {
1085 Handle<Map> initial_map(constructor->initial_map(), isolate());
1086 if (initial_map->constructor_or_backpointer() == *mnewtarget.Value()) {
1087 // Walk up the {effect} chain to see if the {receiver} is the
1088 // dominating effect and there's no other observable write in
1089 // between.
1090 while (true) {
1091 if (receiver == effect) return initial_map;
1092 if (!effect->op()->HasProperty(Operator::kNoWrite) ||
1093 effect->op()->EffectInputCount() != 1) {
1094 break;
1095 }
1096 effect = NodeProperties::GetEffectInput(effect);
1097 }
1098 }
1099 }
1100 }
1101 }
1102 return MaybeHandle<Map>();
1103 }
1104
1105 MaybeHandle<Map> JSNativeContextSpecialization::InferReceiverRootMap(
1106 Node* receiver) {
1107 HeapObjectMatcher m(receiver);
1108 if (m.HasValue()) {
1109 return handle(m.Value()->map()->FindRootMap(), isolate());
1110 } else if (m.IsJSCreate()) {
1111 HeapObjectMatcher mtarget(m.InputAt(0));
1112 HeapObjectMatcher mnewtarget(m.InputAt(1));
1113 if (mtarget.HasValue() && mnewtarget.HasValue()) {
1114 Handle<JSFunction> constructor =
1115 Handle<JSFunction>::cast(mtarget.Value());
1116 if (constructor->has_initial_map()) {
1117 Handle<Map> initial_map(constructor->initial_map(), isolate());
1118 if (initial_map->constructor_or_backpointer() == *mnewtarget.Value()) {
1119 DCHECK_EQ(*initial_map, initial_map->FindRootMap());
1120 return initial_map;
1121 }
1122 }
1123 }
1124 }
1125 return MaybeHandle<Map>();
1126 }
1021 1127
1022 MaybeHandle<Context> JSNativeContextSpecialization::GetNativeContext( 1128 MaybeHandle<Context> JSNativeContextSpecialization::GetNativeContext(
1023 Node* node) { 1129 Node* node) {
1024 Node* const context = NodeProperties::GetContextInput(node); 1130 Node* const context = NodeProperties::GetContextInput(node);
1025 return NodeProperties::GetSpecializationNativeContext(context, 1131 return NodeProperties::GetSpecializationNativeContext(context,
1026 native_context()); 1132 native_context());
1027 } 1133 }
1028 1134
1029 1135
1030 Graph* JSNativeContextSpecialization::graph() const { 1136 Graph* JSNativeContextSpecialization::graph() const {
(...skipping 26 matching lines...) Expand all
1057 } 1163 }
1058 1164
1059 1165
1060 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { 1166 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const {
1061 return jsgraph()->simplified(); 1167 return jsgraph()->simplified();
1062 } 1168 }
1063 1169
1064 } // namespace compiler 1170 } // namespace compiler
1065 } // namespace internal 1171 } // namespace internal
1066 } // namespace v8 1172 } // namespace v8
OLDNEW
« no previous file with comments | « src/compiler/js-native-context-specialization.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698