OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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/hydrogen.h" | 5 #include "src/hydrogen.h" |
6 | 6 |
7 #include <sstream> | 7 #include <sstream> |
8 | 8 |
9 #include "src/v8.h" | 9 #include "src/v8.h" |
10 | 10 |
(...skipping 6923 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6934 | 6934 |
6935 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); | 6935 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); |
6936 return BuildUncheckedMonomorphicElementAccess( | 6936 return BuildUncheckedMonomorphicElementAccess( |
6937 checked_object, key, val, | 6937 checked_object, key, val, |
6938 map->instance_type() == JS_ARRAY_TYPE, | 6938 map->instance_type() == JS_ARRAY_TYPE, |
6939 map->elements_kind(), access_type, | 6939 map->elements_kind(), access_type, |
6940 load_mode, store_mode); | 6940 load_mode, store_mode); |
6941 } | 6941 } |
6942 | 6942 |
6943 | 6943 |
| 6944 static bool CanInlineElementAccess(Handle<Map> map) { |
| 6945 return map->IsJSObjectMap() && !map->has_slow_elements_kind() && |
| 6946 !map->has_indexed_interceptor(); |
| 6947 } |
| 6948 |
| 6949 |
6944 HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( | 6950 HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( |
6945 HValue* object, | 6951 HValue* object, |
6946 HValue* key, | 6952 HValue* key, |
6947 HValue* val, | 6953 HValue* val, |
6948 SmallMapList* maps) { | 6954 SmallMapList* maps) { |
6949 // For polymorphic loads of similar elements kinds (i.e. all tagged or all | 6955 // For polymorphic loads of similar elements kinds (i.e. all tagged or all |
6950 // double), always use the "worst case" code without a transition. This is | 6956 // double), always use the "worst case" code without a transition. This is |
6951 // much faster than transitioning the elements to the worst case, trading a | 6957 // much faster than transitioning the elements to the worst case, trading a |
6952 // HTransitionElements for a HCheckMaps, and avoiding mutation of the array. | 6958 // HTransitionElements for a HCheckMaps, and avoiding mutation of the array. |
6953 bool has_double_maps = false; | 6959 bool has_double_maps = false; |
6954 bool has_smi_or_object_maps = false; | 6960 bool has_smi_or_object_maps = false; |
6955 bool has_js_array_access = false; | 6961 bool has_js_array_access = false; |
6956 bool has_non_js_array_access = false; | 6962 bool has_non_js_array_access = false; |
6957 bool has_seen_holey_elements = false; | 6963 bool has_seen_holey_elements = false; |
6958 Handle<Map> most_general_consolidated_map; | 6964 Handle<Map> most_general_consolidated_map; |
6959 for (int i = 0; i < maps->length(); ++i) { | 6965 for (int i = 0; i < maps->length(); ++i) { |
6960 Handle<Map> map = maps->at(i); | 6966 Handle<Map> map = maps->at(i); |
6961 if (!map->IsJSObjectMap()) return NULL; | 6967 if (!CanInlineElementAccess(map)) return NULL; |
6962 // Don't allow mixing of JSArrays with JSObjects. | 6968 // Don't allow mixing of JSArrays with JSObjects. |
6963 if (map->instance_type() == JS_ARRAY_TYPE) { | 6969 if (map->instance_type() == JS_ARRAY_TYPE) { |
6964 if (has_non_js_array_access) return NULL; | 6970 if (has_non_js_array_access) return NULL; |
6965 has_js_array_access = true; | 6971 has_js_array_access = true; |
6966 } else if (has_js_array_access) { | 6972 } else if (has_js_array_access) { |
6967 return NULL; | 6973 return NULL; |
6968 } else { | 6974 } else { |
6969 has_non_js_array_access = true; | 6975 has_non_js_array_access = true; |
6970 } | 6976 } |
6971 // Don't allow mixed, incompatible elements kinds. | 6977 // Don't allow mixed, incompatible elements kinds. |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7029 } | 7035 } |
7030 | 7036 |
7031 // Elements_kind transition support. | 7037 // Elements_kind transition support. |
7032 MapHandleList transition_target(maps->length()); | 7038 MapHandleList transition_target(maps->length()); |
7033 // Collect possible transition targets. | 7039 // Collect possible transition targets. |
7034 MapHandleList possible_transitioned_maps(maps->length()); | 7040 MapHandleList possible_transitioned_maps(maps->length()); |
7035 for (int i = 0; i < maps->length(); ++i) { | 7041 for (int i = 0; i < maps->length(); ++i) { |
7036 Handle<Map> map = maps->at(i); | 7042 Handle<Map> map = maps->at(i); |
7037 DCHECK(!map->IsStringMap()); | 7043 DCHECK(!map->IsStringMap()); |
7038 ElementsKind elements_kind = map->elements_kind(); | 7044 ElementsKind elements_kind = map->elements_kind(); |
7039 if (IsFastElementsKind(elements_kind) && | 7045 if (CanInlineElementAccess(map) && IsFastElementsKind(elements_kind) && |
7040 elements_kind != GetInitialFastElementsKind()) { | 7046 elements_kind != GetInitialFastElementsKind()) { |
7041 possible_transitioned_maps.Add(map); | 7047 possible_transitioned_maps.Add(map); |
7042 } | 7048 } |
7043 if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) { | 7049 if (elements_kind == SLOPPY_ARGUMENTS_ELEMENTS) { |
7044 HInstruction* result = BuildKeyedGeneric(access_type, expr, object, key, | 7050 HInstruction* result = BuildKeyedGeneric(access_type, expr, object, key, |
7045 val); | 7051 val); |
7046 *has_side_effects = result->HasObservableSideEffects(); | 7052 *has_side_effects = result->HasObservableSideEffects(); |
7047 return AddInstruction(result); | 7053 return AddInstruction(result); |
7048 } | 7054 } |
7049 } | 7055 } |
(...skipping 20 matching lines...) Expand all Loading... |
7070 untransitionable_maps.Add(map); | 7076 untransitionable_maps.Add(map); |
7071 } | 7077 } |
7072 } | 7078 } |
7073 | 7079 |
7074 // If only one map is left after transitioning, handle this case | 7080 // If only one map is left after transitioning, handle this case |
7075 // monomorphically. | 7081 // monomorphically. |
7076 DCHECK(untransitionable_maps.length() >= 1); | 7082 DCHECK(untransitionable_maps.length() >= 1); |
7077 if (untransitionable_maps.length() == 1) { | 7083 if (untransitionable_maps.length() == 1) { |
7078 Handle<Map> untransitionable_map = untransitionable_maps[0]; | 7084 Handle<Map> untransitionable_map = untransitionable_maps[0]; |
7079 HInstruction* instr = NULL; | 7085 HInstruction* instr = NULL; |
7080 if (untransitionable_map->has_slow_elements_kind() || | 7086 if (!CanInlineElementAccess(untransitionable_map)) { |
7081 !untransitionable_map->IsJSObjectMap()) { | |
7082 instr = AddInstruction(BuildKeyedGeneric(access_type, expr, object, key, | 7087 instr = AddInstruction(BuildKeyedGeneric(access_type, expr, object, key, |
7083 val)); | 7088 val)); |
7084 } else { | 7089 } else { |
7085 instr = BuildMonomorphicElementAccess( | 7090 instr = BuildMonomorphicElementAccess( |
7086 object, key, val, transition, untransitionable_map, access_type, | 7091 object, key, val, transition, untransitionable_map, access_type, |
7087 store_mode); | 7092 store_mode); |
7088 } | 7093 } |
7089 *has_side_effects |= instr->HasObservableSideEffects(); | 7094 *has_side_effects |= instr->HasObservableSideEffects(); |
7090 return access_type == STORE ? val : instr; | 7095 return access_type == STORE ? val : instr; |
7091 } | 7096 } |
7092 | 7097 |
7093 HBasicBlock* join = graph()->CreateBasicBlock(); | 7098 HBasicBlock* join = graph()->CreateBasicBlock(); |
7094 | 7099 |
7095 for (int i = 0; i < untransitionable_maps.length(); ++i) { | 7100 for (int i = 0; i < untransitionable_maps.length(); ++i) { |
7096 Handle<Map> map = untransitionable_maps[i]; | 7101 Handle<Map> map = untransitionable_maps[i]; |
7097 if (!map->IsJSObjectMap()) continue; | |
7098 ElementsKind elements_kind = map->elements_kind(); | 7102 ElementsKind elements_kind = map->elements_kind(); |
7099 HBasicBlock* this_map = graph()->CreateBasicBlock(); | 7103 HBasicBlock* this_map = graph()->CreateBasicBlock(); |
7100 HBasicBlock* other_map = graph()->CreateBasicBlock(); | 7104 HBasicBlock* other_map = graph()->CreateBasicBlock(); |
7101 HCompareMap* mapcompare = | 7105 HCompareMap* mapcompare = |
7102 New<HCompareMap>(object, map, this_map, other_map); | 7106 New<HCompareMap>(object, map, this_map, other_map); |
7103 FinishCurrentBlock(mapcompare); | 7107 FinishCurrentBlock(mapcompare); |
7104 | 7108 |
7105 set_current_block(this_map); | 7109 set_current_block(this_map); |
7106 HInstruction* access = NULL; | 7110 HInstruction* access = NULL; |
7107 if (IsDictionaryElementsKind(elements_kind)) { | 7111 if (!CanInlineElementAccess(map)) { |
7108 access = AddInstruction(BuildKeyedGeneric(access_type, expr, object, key, | 7112 access = AddInstruction(BuildKeyedGeneric(access_type, expr, object, key, |
7109 val)); | 7113 val)); |
7110 } else { | 7114 } else { |
7111 DCHECK(IsFastElementsKind(elements_kind) || | 7115 DCHECK(IsFastElementsKind(elements_kind) || |
7112 IsExternalArrayElementsKind(elements_kind) || | 7116 IsExternalArrayElementsKind(elements_kind) || |
7113 IsFixedTypedArrayElementsKind(elements_kind)); | 7117 IsFixedTypedArrayElementsKind(elements_kind)); |
7114 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); | 7118 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); |
7115 // Happily, mapcompare is a checked object. | 7119 // Happily, mapcompare is a checked object. |
7116 access = BuildUncheckedMonomorphicElementAccess( | 7120 access = BuildUncheckedMonomorphicElementAccess( |
7117 mapcompare, key, val, | 7121 mapcompare, key, val, |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7208 Handle<Map> current_map = types->at(i); | 7212 Handle<Map> current_map = types->at(i); |
7209 if (current_map->IsStringMap()) { | 7213 if (current_map->IsStringMap()) { |
7210 force_generic = true; | 7214 force_generic = true; |
7211 break; | 7215 break; |
7212 } | 7216 } |
7213 } | 7217 } |
7214 } | 7218 } |
7215 | 7219 |
7216 if (monomorphic) { | 7220 if (monomorphic) { |
7217 Handle<Map> map = types->first(); | 7221 Handle<Map> map = types->first(); |
7218 if (map->has_slow_elements_kind() || !map->IsJSObjectMap()) { | 7222 if (!CanInlineElementAccess(map)) { |
7219 instr = AddInstruction(BuildKeyedGeneric(access_type, expr, obj, key, | 7223 instr = AddInstruction(BuildKeyedGeneric(access_type, expr, obj, key, |
7220 val)); | 7224 val)); |
7221 } else { | 7225 } else { |
7222 BuildCheckHeapObject(obj); | 7226 BuildCheckHeapObject(obj); |
7223 instr = BuildMonomorphicElementAccess( | 7227 instr = BuildMonomorphicElementAccess( |
7224 obj, key, val, NULL, map, access_type, expr->GetStoreMode()); | 7228 obj, key, val, NULL, map, access_type, expr->GetStoreMode()); |
7225 } | 7229 } |
7226 } else if (!force_generic && (types != NULL && !types->is_empty())) { | 7230 } else if (!force_generic && (types != NULL && !types->is_empty())) { |
7227 return HandlePolymorphicElementAccess( | 7231 return HandlePolymorphicElementAccess( |
7228 expr, obj, key, val, types, access_type, | 7232 expr, obj, key, val, types, access_type, |
(...skipping 5438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12667 if (ShouldProduceTraceOutput()) { | 12671 if (ShouldProduceTraceOutput()) { |
12668 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 12672 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
12669 } | 12673 } |
12670 | 12674 |
12671 #ifdef DEBUG | 12675 #ifdef DEBUG |
12672 graph_->Verify(false); // No full verify. | 12676 graph_->Verify(false); // No full verify. |
12673 #endif | 12677 #endif |
12674 } | 12678 } |
12675 | 12679 |
12676 } } // namespace v8::internal | 12680 } } // namespace v8::internal |
OLD | NEW |