| 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 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 131 } | 131 } |
| 132 } | 132 } |
| 133 return NoChange(); | 133 return NoChange(); |
| 134 } | 134 } |
| 135 | 135 |
| 136 Reduction JSNativeContextSpecialization::ReduceJSGetSuperConstructor( | 136 Reduction JSNativeContextSpecialization::ReduceJSGetSuperConstructor( |
| 137 Node* node) { | 137 Node* node) { |
| 138 DCHECK_EQ(IrOpcode::kJSGetSuperConstructor, node->opcode()); | 138 DCHECK_EQ(IrOpcode::kJSGetSuperConstructor, node->opcode()); |
| 139 Node* constructor = NodeProperties::GetValueInput(node, 0); | 139 Node* constructor = NodeProperties::GetValueInput(node, 0); |
| 140 | 140 |
| 141 // If deoptimization is disabled, we cannot optimize. | |
| 142 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | |
| 143 | |
| 144 // Check if the input is a known JSFunction. | 141 // Check if the input is a known JSFunction. |
| 145 HeapObjectMatcher m(constructor); | 142 HeapObjectMatcher m(constructor); |
| 146 if (!m.HasValue()) return NoChange(); | 143 if (!m.HasValue()) return NoChange(); |
| 147 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value()); | 144 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value()); |
| 148 Handle<Map> function_map(function->map(), isolate()); | 145 Handle<Map> function_map(function->map(), isolate()); |
| 149 Handle<Object> function_prototype(function_map->prototype(), isolate()); | 146 Handle<Object> function_prototype(function_map->prototype(), isolate()); |
| 150 | 147 |
| 151 // We can constant-fold the super constructor access if the | 148 // We can constant-fold the super constructor access if the |
| 152 // {function}s map is stable, i.e. we can use a code dependency | 149 // {function}s map is stable, i.e. we can use a code dependency |
| 153 // to guard against [[Prototype]] changes of {function}. | 150 // to guard against [[Prototype]] changes of {function}. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 169 } | 166 } |
| 170 | 167 |
| 171 Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) { | 168 Reduction JSNativeContextSpecialization::ReduceJSInstanceOf(Node* node) { |
| 172 DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode()); | 169 DCHECK_EQ(IrOpcode::kJSInstanceOf, node->opcode()); |
| 173 Node* object = NodeProperties::GetValueInput(node, 0); | 170 Node* object = NodeProperties::GetValueInput(node, 0); |
| 174 Node* constructor = NodeProperties::GetValueInput(node, 1); | 171 Node* constructor = NodeProperties::GetValueInput(node, 1); |
| 175 Node* context = NodeProperties::GetContextInput(node); | 172 Node* context = NodeProperties::GetContextInput(node); |
| 176 Node* effect = NodeProperties::GetEffectInput(node); | 173 Node* effect = NodeProperties::GetEffectInput(node); |
| 177 Node* control = NodeProperties::GetControlInput(node); | 174 Node* control = NodeProperties::GetControlInput(node); |
| 178 | 175 |
| 179 // If deoptimization is disabled, we cannot optimize. | |
| 180 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | |
| 181 | |
| 182 // Check if the right hand side is a known {receiver}. | 176 // Check if the right hand side is a known {receiver}. |
| 183 HeapObjectMatcher m(constructor); | 177 HeapObjectMatcher m(constructor); |
| 184 if (!m.HasValue() || !m.Value()->IsJSObject()) return NoChange(); | 178 if (!m.HasValue() || !m.Value()->IsJSObject()) return NoChange(); |
| 185 Handle<JSObject> receiver = Handle<JSObject>::cast(m.Value()); | 179 Handle<JSObject> receiver = Handle<JSObject>::cast(m.Value()); |
| 186 Handle<Map> receiver_map(receiver->map(), isolate()); | 180 Handle<Map> receiver_map(receiver->map(), isolate()); |
| 187 | 181 |
| 188 // Compute property access info for @@hasInstance on {receiver}. | 182 // Compute property access info for @@hasInstance on {receiver}. |
| 189 PropertyAccessInfo access_info; | 183 PropertyAccessInfo access_info; |
| 190 AccessInfoFactory access_info_factory(dependencies(), native_context(), | 184 AccessInfoFactory access_info_factory(dependencies(), native_context(), |
| 191 graph()->zone()); | 185 graph()->zone()); |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 506 if (LookupInScriptContextTable(name, &result)) { | 500 if (LookupInScriptContextTable(name, &result)) { |
| 507 if (result.context->is_the_hole(isolate(), result.index)) return NoChange(); | 501 if (result.context->is_the_hole(isolate(), result.index)) return NoChange(); |
| 508 Node* context = jsgraph()->HeapConstant(result.context); | 502 Node* context = jsgraph()->HeapConstant(result.context); |
| 509 Node* value = effect = graph()->NewNode( | 503 Node* value = effect = graph()->NewNode( |
| 510 javascript()->LoadContext(0, result.index, result.immutable), context, | 504 javascript()->LoadContext(0, result.index, result.immutable), context, |
| 511 effect); | 505 effect); |
| 512 ReplaceWithValue(node, value, effect); | 506 ReplaceWithValue(node, value, effect); |
| 513 return Replace(value); | 507 return Replace(value); |
| 514 } | 508 } |
| 515 | 509 |
| 516 // Not much we can do if deoptimization support is disabled. | |
| 517 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | |
| 518 | |
| 519 // Lookup the {name} on the global object instead. | 510 // Lookup the {name} on the global object instead. |
| 520 return ReduceGlobalAccess(node, nullptr, nullptr, name, AccessMode::kLoad); | 511 return ReduceGlobalAccess(node, nullptr, nullptr, name, AccessMode::kLoad); |
| 521 } | 512 } |
| 522 | 513 |
| 523 Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) { | 514 Reduction JSNativeContextSpecialization::ReduceJSStoreGlobal(Node* node) { |
| 524 DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode()); | 515 DCHECK_EQ(IrOpcode::kJSStoreGlobal, node->opcode()); |
| 525 Handle<Name> name = StoreGlobalParametersOf(node->op()).name(); | 516 Handle<Name> name = StoreGlobalParametersOf(node->op()).name(); |
| 526 Node* value = NodeProperties::GetValueInput(node, 0); | 517 Node* value = NodeProperties::GetValueInput(node, 0); |
| 527 Node* effect = NodeProperties::GetEffectInput(node); | 518 Node* effect = NodeProperties::GetEffectInput(node); |
| 528 Node* control = NodeProperties::GetControlInput(node); | 519 Node* control = NodeProperties::GetControlInput(node); |
| 529 | 520 |
| 530 // Try to lookup the name on the script context table first (lexical scoping). | 521 // Try to lookup the name on the script context table first (lexical scoping). |
| 531 ScriptContextTableLookupResult result; | 522 ScriptContextTableLookupResult result; |
| 532 if (LookupInScriptContextTable(name, &result)) { | 523 if (LookupInScriptContextTable(name, &result)) { |
| 533 if (result.context->is_the_hole(isolate(), result.index)) return NoChange(); | 524 if (result.context->is_the_hole(isolate(), result.index)) return NoChange(); |
| 534 if (result.immutable) return NoChange(); | 525 if (result.immutable) return NoChange(); |
| 535 Node* context = jsgraph()->HeapConstant(result.context); | 526 Node* context = jsgraph()->HeapConstant(result.context); |
| 536 effect = graph()->NewNode(javascript()->StoreContext(0, result.index), | 527 effect = graph()->NewNode(javascript()->StoreContext(0, result.index), |
| 537 value, context, effect, control); | 528 value, context, effect, control); |
| 538 ReplaceWithValue(node, value, effect, control); | 529 ReplaceWithValue(node, value, effect, control); |
| 539 return Replace(value); | 530 return Replace(value); |
| 540 } | 531 } |
| 541 | 532 |
| 542 // Not much we can do if deoptimization support is disabled. | |
| 543 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | |
| 544 | |
| 545 // Lookup the {name} on the global object instead. | 533 // Lookup the {name} on the global object instead. |
| 546 return ReduceGlobalAccess(node, nullptr, value, name, AccessMode::kStore); | 534 return ReduceGlobalAccess(node, nullptr, value, name, AccessMode::kStore); |
| 547 } | 535 } |
| 548 | 536 |
| 549 Reduction JSNativeContextSpecialization::ReduceNamedAccess( | 537 Reduction JSNativeContextSpecialization::ReduceNamedAccess( |
| 550 Node* node, Node* value, MapHandleList const& receiver_maps, | 538 Node* node, Node* value, MapHandleList const& receiver_maps, |
| 551 Handle<Name> name, AccessMode access_mode, LanguageMode language_mode, | 539 Handle<Name> name, AccessMode access_mode, LanguageMode language_mode, |
| 552 Handle<FeedbackVector> vector, FeedbackSlot slot, Node* index) { | 540 Handle<FeedbackVector> vector, FeedbackSlot slot, Node* index) { |
| 553 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed || | 541 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed || |
| 554 node->opcode() == IrOpcode::kJSStoreNamed || | 542 node->opcode() == IrOpcode::kJSStoreNamed || |
| 555 node->opcode() == IrOpcode::kJSLoadProperty || | 543 node->opcode() == IrOpcode::kJSLoadProperty || |
| 556 node->opcode() == IrOpcode::kJSStoreProperty || | 544 node->opcode() == IrOpcode::kJSStoreProperty || |
| 557 node->opcode() == IrOpcode::kJSStoreNamedOwn); | 545 node->opcode() == IrOpcode::kJSStoreNamedOwn); |
| 558 Node* receiver = NodeProperties::GetValueInput(node, 0); | 546 Node* receiver = NodeProperties::GetValueInput(node, 0); |
| 559 Node* context = NodeProperties::GetContextInput(node); | 547 Node* context = NodeProperties::GetContextInput(node); |
| 560 Node* frame_state = NodeProperties::GetFrameStateInput(node); | 548 Node* frame_state = NodeProperties::GetFrameStateInput(node); |
| 561 Node* effect = NodeProperties::GetEffectInput(node); | 549 Node* effect = NodeProperties::GetEffectInput(node); |
| 562 Node* control = NodeProperties::GetControlInput(node); | 550 Node* control = NodeProperties::GetControlInput(node); |
| 563 | 551 |
| 564 // Not much we can do if deoptimization support is disabled. | |
| 565 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | |
| 566 | |
| 567 // Check if we have an access o.x or o.x=v where o is the current | 552 // Check if we have an access o.x or o.x=v where o is the current |
| 568 // native contexts' global proxy, and turn that into a direct access | 553 // native contexts' global proxy, and turn that into a direct access |
| 569 // to the current native contexts' global object instead. | 554 // to the current native contexts' global object instead. |
| 570 if (receiver_maps.length() == 1) { | 555 if (receiver_maps.length() == 1) { |
| 571 Handle<Map> receiver_map = receiver_maps.first(); | 556 Handle<Map> receiver_map = receiver_maps.first(); |
| 572 if (receiver_map->IsJSGlobalProxyMap()) { | 557 if (receiver_map->IsJSGlobalProxyMap()) { |
| 573 Object* maybe_constructor = receiver_map->GetConstructor(); | 558 Object* maybe_constructor = receiver_map->GetConstructor(); |
| 574 // Detached global proxies have |null| as their constructor. | 559 // Detached global proxies have |null| as their constructor. |
| 575 if (maybe_constructor->IsJSFunction() && | 560 if (maybe_constructor->IsJSFunction() && |
| 576 JSFunction::cast(maybe_constructor)->native_context() == | 561 JSFunction::cast(maybe_constructor)->native_context() == |
| (...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 783 | 768 |
| 784 Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus( | 769 Reduction JSNativeContextSpecialization::ReduceNamedAccessFromNexus( |
| 785 Node* node, Node* value, FeedbackNexus const& nexus, Handle<Name> name, | 770 Node* node, Node* value, FeedbackNexus const& nexus, Handle<Name> name, |
| 786 AccessMode access_mode, LanguageMode language_mode) { | 771 AccessMode access_mode, LanguageMode language_mode) { |
| 787 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed || | 772 DCHECK(node->opcode() == IrOpcode::kJSLoadNamed || |
| 788 node->opcode() == IrOpcode::kJSStoreNamed || | 773 node->opcode() == IrOpcode::kJSStoreNamed || |
| 789 node->opcode() == IrOpcode::kJSStoreNamedOwn); | 774 node->opcode() == IrOpcode::kJSStoreNamedOwn); |
| 790 Node* const receiver = NodeProperties::GetValueInput(node, 0); | 775 Node* const receiver = NodeProperties::GetValueInput(node, 0); |
| 791 Node* const effect = NodeProperties::GetEffectInput(node); | 776 Node* const effect = NodeProperties::GetEffectInput(node); |
| 792 | 777 |
| 793 if (flags() & kDeoptimizationEnabled) { | 778 // Check if we are accessing the current native contexts' global proxy. |
| 794 // Check if we are accessing the current native contexts' global proxy. | 779 HeapObjectMatcher m(receiver); |
| 795 HeapObjectMatcher m(receiver); | 780 if (m.HasValue() && m.Value().is_identical_to(global_proxy())) { |
| 796 if (m.HasValue() && m.Value().is_identical_to(global_proxy())) { | 781 // Optimize accesses to the current native contexts' global proxy. |
| 797 // Optimize accesses to the current native contexts' global proxy. | 782 return ReduceGlobalAccess(node, nullptr, value, name, access_mode); |
| 798 return ReduceGlobalAccess(node, nullptr, value, name, access_mode); | |
| 799 } | |
| 800 } | 783 } |
| 801 | 784 |
| 802 // Check if the {nexus} reports type feedback for the IC. | 785 // Check if the {nexus} reports type feedback for the IC. |
| 803 if (nexus.IsUninitialized()) { | 786 if (nexus.IsUninitialized()) { |
| 804 if ((flags() & kDeoptimizationEnabled) && | 787 if (flags() & kBailoutOnUninitialized) { |
| 805 (flags() & kBailoutOnUninitialized)) { | |
| 806 return ReduceSoftDeoptimize( | 788 return ReduceSoftDeoptimize( |
| 807 node, | 789 node, |
| 808 DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess); | 790 DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess); |
| 809 } | 791 } |
| 810 return NoChange(); | 792 return NoChange(); |
| 811 } | 793 } |
| 812 | 794 |
| 813 // Extract receiver maps from the IC using the {nexus}. | 795 // Extract receiver maps from the IC using the {nexus}. |
| 814 MapHandleList receiver_maps; | 796 MapHandleList receiver_maps; |
| 815 if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) { | 797 if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) { |
| 816 return NoChange(); | 798 return NoChange(); |
| 817 } else if (receiver_maps.length() == 0) { | 799 } else if (receiver_maps.length() == 0) { |
| 818 if ((flags() & kDeoptimizationEnabled) && | 800 if (flags() & kBailoutOnUninitialized) { |
| 819 (flags() & kBailoutOnUninitialized)) { | |
| 820 return ReduceSoftDeoptimize( | 801 return ReduceSoftDeoptimize( |
| 821 node, | 802 node, |
| 822 DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess); | 803 DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess); |
| 823 } | 804 } |
| 824 return NoChange(); | 805 return NoChange(); |
| 825 } | 806 } |
| 826 | 807 |
| 827 // Try to lower the named access based on the {receiver_maps}. | 808 // Try to lower the named access based on the {receiver_maps}. |
| 828 return ReduceNamedAccess(node, value, receiver_maps, name, access_mode, | 809 return ReduceNamedAccess(node, value, receiver_maps, name, access_mode, |
| 829 language_mode, nexus.vector_handle(), nexus.slot()); | 810 language_mode, nexus.vector_handle(), nexus.slot()); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 840 if (m.HasValue()) { | 821 if (m.HasValue()) { |
| 841 if (m.Value()->IsJSFunction() && | 822 if (m.Value()->IsJSFunction() && |
| 842 p.name().is_identical_to(factory()->prototype_string())) { | 823 p.name().is_identical_to(factory()->prototype_string())) { |
| 843 // Optimize "prototype" property of functions. | 824 // Optimize "prototype" property of functions. |
| 844 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value()); | 825 Handle<JSFunction> function = Handle<JSFunction>::cast(m.Value()); |
| 845 if (function->has_initial_map()) { | 826 if (function->has_initial_map()) { |
| 846 // We need to add a code dependency on the initial map of the | 827 // We need to add a code dependency on the initial map of the |
| 847 // {function} in order to be notified about changes to the | 828 // {function} in order to be notified about changes to the |
| 848 // "prototype" of {function}, so it doesn't make sense to | 829 // "prototype" of {function}, so it doesn't make sense to |
| 849 // continue unless deoptimization is enabled. | 830 // continue unless deoptimization is enabled. |
| 850 if (flags() & kDeoptimizationEnabled) { | 831 Handle<Map> initial_map(function->initial_map(), isolate()); |
| 851 Handle<Map> initial_map(function->initial_map(), isolate()); | 832 dependencies()->AssumeInitialMapCantChange(initial_map); |
| 852 dependencies()->AssumeInitialMapCantChange(initial_map); | 833 Handle<Object> prototype(initial_map->prototype(), isolate()); |
| 853 Handle<Object> prototype(initial_map->prototype(), isolate()); | 834 Node* value = jsgraph()->Constant(prototype); |
| 854 Node* value = jsgraph()->Constant(prototype); | 835 ReplaceWithValue(node, value); |
| 855 ReplaceWithValue(node, value); | 836 return Replace(value); |
| 856 return Replace(value); | |
| 857 } | |
| 858 } | 837 } |
| 859 } else if (m.Value()->IsString() && | 838 } else if (m.Value()->IsString() && |
| 860 p.name().is_identical_to(factory()->length_string())) { | 839 p.name().is_identical_to(factory()->length_string())) { |
| 861 // Constant-fold "length" property on constant strings. | 840 // Constant-fold "length" property on constant strings. |
| 862 Handle<String> string = Handle<String>::cast(m.Value()); | 841 Handle<String> string = Handle<String>::cast(m.Value()); |
| 863 Node* value = jsgraph()->Constant(string->length()); | 842 Node* value = jsgraph()->Constant(string->length()); |
| 864 ReplaceWithValue(node, value); | 843 ReplaceWithValue(node, value); |
| 865 return Replace(value); | 844 return Replace(value); |
| 866 } | 845 } |
| 867 } | 846 } |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 908 Node* node, Node* index, Node* value, MapHandleList const& receiver_maps, | 887 Node* node, Node* index, Node* value, MapHandleList const& receiver_maps, |
| 909 AccessMode access_mode, LanguageMode language_mode, | 888 AccessMode access_mode, LanguageMode language_mode, |
| 910 KeyedAccessStoreMode store_mode) { | 889 KeyedAccessStoreMode store_mode) { |
| 911 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || | 890 DCHECK(node->opcode() == IrOpcode::kJSLoadProperty || |
| 912 node->opcode() == IrOpcode::kJSStoreProperty); | 891 node->opcode() == IrOpcode::kJSStoreProperty); |
| 913 Node* receiver = NodeProperties::GetValueInput(node, 0); | 892 Node* receiver = NodeProperties::GetValueInput(node, 0); |
| 914 Node* effect = NodeProperties::GetEffectInput(node); | 893 Node* effect = NodeProperties::GetEffectInput(node); |
| 915 Node* control = NodeProperties::GetControlInput(node); | 894 Node* control = NodeProperties::GetControlInput(node); |
| 916 Node* frame_state = NodeProperties::FindFrameStateBefore(node); | 895 Node* frame_state = NodeProperties::FindFrameStateBefore(node); |
| 917 | 896 |
| 918 // Not much we can do if deoptimization support is disabled. | |
| 919 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | |
| 920 | |
| 921 // Check for keyed access to strings. | 897 // Check for keyed access to strings. |
| 922 if (HasOnlyStringMaps(receiver_maps)) { | 898 if (HasOnlyStringMaps(receiver_maps)) { |
| 923 // Strings are immutable in JavaScript. | 899 // Strings are immutable in JavaScript. |
| 924 if (access_mode == AccessMode::kStore) return NoChange(); | 900 if (access_mode == AccessMode::kStore) return NoChange(); |
| 925 | 901 |
| 926 // Ensure that the {receiver} is actually a String. | 902 // Ensure that the {receiver} is actually a String. |
| 927 receiver = effect = graph()->NewNode(simplified()->CheckString(), receiver, | 903 receiver = effect = graph()->NewNode(simplified()->CheckString(), receiver, |
| 928 effect, control); | 904 effect, control); |
| 929 | 905 |
| 930 // Determine the {receiver} length. | 906 // Determine the {receiver} length. |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1156 node->opcode() == IrOpcode::kJSStoreProperty); | 1132 node->opcode() == IrOpcode::kJSStoreProperty); |
| 1157 Node* receiver = NodeProperties::GetValueInput(node, 0); | 1133 Node* receiver = NodeProperties::GetValueInput(node, 0); |
| 1158 Node* effect = NodeProperties::GetEffectInput(node); | 1134 Node* effect = NodeProperties::GetEffectInput(node); |
| 1159 Node* control = NodeProperties::GetControlInput(node); | 1135 Node* control = NodeProperties::GetControlInput(node); |
| 1160 | 1136 |
| 1161 // Optimize access for constant {receiver}. | 1137 // Optimize access for constant {receiver}. |
| 1162 HeapObjectMatcher mreceiver(receiver); | 1138 HeapObjectMatcher mreceiver(receiver); |
| 1163 if (mreceiver.HasValue() && mreceiver.Value()->IsString()) { | 1139 if (mreceiver.HasValue() && mreceiver.Value()->IsString()) { |
| 1164 Handle<String> string = Handle<String>::cast(mreceiver.Value()); | 1140 Handle<String> string = Handle<String>::cast(mreceiver.Value()); |
| 1165 | 1141 |
| 1142 // Strings are immutable in JavaScript. |
| 1143 if (access_mode == AccessMode::kStore) return NoChange(); |
| 1144 |
| 1145 // Properly deal with constant {index}. |
| 1146 NumberMatcher mindex(index); |
| 1147 if (mindex.IsInteger() && mindex.IsInRange(0.0, string->length() - 1)) { |
| 1148 // Constant-fold the {index} access to {string}. |
| 1149 Node* value = jsgraph()->HeapConstant( |
| 1150 factory()->LookupSingleCharacterStringFromCode( |
| 1151 string->Get(static_cast<int>(mindex.Value())))); |
| 1152 ReplaceWithValue(node, value, effect, control); |
| 1153 return Replace(value); |
| 1154 } |
| 1155 |
| 1166 // We can only assume that the {index} is a valid array index if the IC | 1156 // We can only assume that the {index} is a valid array index if the IC |
| 1167 // is in element access mode and not MEGAMORPHIC, otherwise there's no | 1157 // is in element access mode and not MEGAMORPHIC, otherwise there's no |
| 1168 // guard for the bounds check below. | 1158 // guard for the bounds check below. |
| 1169 if (nexus.ic_state() != MEGAMORPHIC && nexus.GetKeyType() == ELEMENT) { | 1159 if (nexus.ic_state() != MEGAMORPHIC && nexus.GetKeyType() == ELEMENT) { |
| 1170 // Strings are immutable in JavaScript. | 1160 // Ensure that {index} is less than {receiver} length. |
| 1171 if (access_mode == AccessMode::kStore) return NoChange(); | 1161 Node* length = jsgraph()->Constant(string->length()); |
| 1162 index = effect = graph()->NewNode(simplified()->CheckBounds(), index, |
| 1163 length, effect, control); |
| 1172 | 1164 |
| 1173 // Properly deal with constant {index}. | 1165 // Return the character from the {receiver} as single character string. |
| 1174 NumberMatcher mindex(index); | 1166 value = graph()->NewNode(simplified()->StringCharAt(), receiver, index, |
| 1175 if (mindex.IsInteger() && mindex.IsInRange(0.0, string->length() - 1)) { | 1167 control); |
| 1176 // Constant-fold the {index} access to {string}. | 1168 ReplaceWithValue(node, value, effect, control); |
| 1177 Node* value = jsgraph()->HeapConstant( | 1169 return Replace(value); |
| 1178 factory()->LookupSingleCharacterStringFromCode( | |
| 1179 string->Get(static_cast<int>(mindex.Value())))); | |
| 1180 ReplaceWithValue(node, value, effect, control); | |
| 1181 return Replace(value); | |
| 1182 } else if (flags() & kDeoptimizationEnabled) { | |
| 1183 // Ensure that {index} is less than {receiver} length. | |
| 1184 Node* length = jsgraph()->Constant(string->length()); | |
| 1185 index = effect = graph()->NewNode(simplified()->CheckBounds(), index, | |
| 1186 length, effect, control); | |
| 1187 | |
| 1188 // Return the character from the {receiver} as single character string. | |
| 1189 value = graph()->NewNode(simplified()->StringCharAt(), receiver, index, | |
| 1190 control); | |
| 1191 ReplaceWithValue(node, value, effect, control); | |
| 1192 return Replace(value); | |
| 1193 } | |
| 1194 } | 1170 } |
| 1195 } | 1171 } |
| 1196 | 1172 |
| 1197 // Check if the {nexus} reports type feedback for the IC. | 1173 // Check if the {nexus} reports type feedback for the IC. |
| 1198 if (nexus.IsUninitialized()) { | 1174 if (nexus.IsUninitialized()) { |
| 1199 if ((flags() & kDeoptimizationEnabled) && | 1175 if (flags() & kBailoutOnUninitialized) { |
| 1200 (flags() & kBailoutOnUninitialized)) { | |
| 1201 return ReduceSoftDeoptimize( | 1176 return ReduceSoftDeoptimize( |
| 1202 node, | 1177 node, |
| 1203 DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess); | 1178 DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess); |
| 1204 } | 1179 } |
| 1205 return NoChange(); | 1180 return NoChange(); |
| 1206 } | 1181 } |
| 1207 | 1182 |
| 1208 // Extract receiver maps from the {nexus}. | 1183 // Extract receiver maps from the {nexus}. |
| 1209 MapHandleList receiver_maps; | 1184 MapHandleList receiver_maps; |
| 1210 if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) { | 1185 if (!ExtractReceiverMaps(receiver, effect, nexus, &receiver_maps)) { |
| 1211 return NoChange(); | 1186 return NoChange(); |
| 1212 } else if (receiver_maps.length() == 0) { | 1187 } else if (receiver_maps.length() == 0) { |
| 1213 if ((flags() & kDeoptimizationEnabled) && | 1188 if (flags() & kBailoutOnUninitialized) { |
| 1214 (flags() & kBailoutOnUninitialized)) { | |
| 1215 return ReduceSoftDeoptimize( | 1189 return ReduceSoftDeoptimize( |
| 1216 node, | 1190 node, |
| 1217 DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess); | 1191 DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess); |
| 1218 } | 1192 } |
| 1219 return NoChange(); | 1193 return NoChange(); |
| 1220 } | 1194 } |
| 1221 | 1195 |
| 1222 // Optimize access for constant {index}. | 1196 // Optimize access for constant {index}. |
| 1223 HeapObjectMatcher mindex(index); | 1197 HeapObjectMatcher mindex(index); |
| 1224 if (mindex.HasValue() && mindex.Value()->IsPrimitive()) { | 1198 if (mindex.HasValue() && mindex.Value()->IsPrimitive()) { |
| (...skipping 449 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1674 control = graph()->NewNode(common()->IfSuccess(), control); | 1648 control = graph()->NewNode(common()->IfSuccess(), control); |
| 1675 } | 1649 } |
| 1676 | 1650 |
| 1677 return ValueEffectControl(value, effect, control); | 1651 return ValueEffectControl(value, effect, control); |
| 1678 } | 1652 } |
| 1679 | 1653 |
| 1680 Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral( | 1654 Reduction JSNativeContextSpecialization::ReduceJSStoreDataPropertyInLiteral( |
| 1681 Node* node) { | 1655 Node* node) { |
| 1682 DCHECK_EQ(IrOpcode::kJSStoreDataPropertyInLiteral, node->opcode()); | 1656 DCHECK_EQ(IrOpcode::kJSStoreDataPropertyInLiteral, node->opcode()); |
| 1683 | 1657 |
| 1684 // If deoptimization is disabled, we cannot optimize. | |
| 1685 if (!(flags() & kDeoptimizationEnabled)) return NoChange(); | |
| 1686 | |
| 1687 FeedbackParameter const& p = FeedbackParameterOf(node->op()); | 1658 FeedbackParameter const& p = FeedbackParameterOf(node->op()); |
| 1688 | 1659 |
| 1689 if (!p.feedback().IsValid()) return NoChange(); | 1660 if (!p.feedback().IsValid()) return NoChange(); |
| 1690 | 1661 |
| 1691 StoreDataPropertyInLiteralICNexus nexus(p.feedback().vector(), | 1662 StoreDataPropertyInLiteralICNexus nexus(p.feedback().vector(), |
| 1692 p.feedback().slot()); | 1663 p.feedback().slot()); |
| 1693 if (nexus.IsUninitialized()) { | 1664 if (nexus.IsUninitialized()) { |
| 1694 return NoChange(); | 1665 return NoChange(); |
| 1695 } | 1666 } |
| 1696 | 1667 |
| (...skipping 633 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2330 return jsgraph()->javascript(); | 2301 return jsgraph()->javascript(); |
| 2331 } | 2302 } |
| 2332 | 2303 |
| 2333 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { | 2304 SimplifiedOperatorBuilder* JSNativeContextSpecialization::simplified() const { |
| 2334 return jsgraph()->simplified(); | 2305 return jsgraph()->simplified(); |
| 2335 } | 2306 } |
| 2336 | 2307 |
| 2337 } // namespace compiler | 2308 } // namespace compiler |
| 2338 } // namespace internal | 2309 } // namespace internal |
| 2339 } // namespace v8 | 2310 } // namespace v8 |
| OLD | NEW |