| 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 |