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 410 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |