Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 1691 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1702 bool hoisted = false; | 1702 bool hoisted = false; |
| 1703 if (instr->CheckFlag(HValue::kUseGVN)) { | 1703 if (instr->CheckFlag(HValue::kUseGVN)) { |
| 1704 TRACE_GVN_4("Checking instruction %d (%s) %s. Loop %s\n", | 1704 TRACE_GVN_4("Checking instruction %d (%s) %s. Loop %s\n", |
| 1705 instr->id(), | 1705 instr->id(), |
| 1706 instr->Mnemonic(), | 1706 instr->Mnemonic(), |
| 1707 *GetGVNFlagsString(instr->gvn_flags()), | 1707 *GetGVNFlagsString(instr->gvn_flags()), |
| 1708 *GetGVNFlagsString(loop_kills)); | 1708 *GetGVNFlagsString(loop_kills)); |
| 1709 bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags); | 1709 bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags); |
| 1710 if (instr->IsTransitionElementsKind()) { | 1710 if (instr->IsTransitionElementsKind()) { |
| 1711 // It's possible to hoist transitions out of a loop as long as the | 1711 // It's possible to hoist transitions out of a loop as long as the |
| 1712 // hoisting wouldn't move the transition past a DependsOn of one of it's | 1712 // hoisting wouldn't move the transition past an instruction that has a |
| 1713 // changes or any instructions that might change an objects map or | 1713 // DependsOn flag for anything it changes. |
| 1714 // elements contents. | |
| 1715 GVNFlagSet changes = instr->ChangesFlags(); | |
| 1716 GVNFlagSet hoist_depends_blockers = | 1714 GVNFlagSet hoist_depends_blockers = |
| 1717 HValue::ConvertChangesToDependsFlags(changes); | 1715 HValue::ConvertChangesToDependsFlags(instr->ChangesFlags()); |
| 1718 // In addition to not hoisting transitions above other instructions that | 1716 |
| 1719 // change dependencies that the transition changes, it must not be | 1717 // In addition, the transition must not be hoisted above elements kind |
| 1720 // hoisted above map changes and stores to an elements backing store | 1718 // changes, or if the transition is destructive to the elements buffer, |
| 1721 // that the transition might change. | 1719 // changes to array pointer or array contents. |
| 1722 GVNFlagSet hoist_change_blockers = changes; | 1720 GVNFlagSet hoist_change_blockers; |
| 1723 hoist_change_blockers.Add(kChangesMaps); | 1721 hoist_change_blockers.Add(kChangesElementsKind); |
| 1724 HTransitionElementsKind* trans = HTransitionElementsKind::cast(instr); | 1722 HTransitionElementsKind* trans = HTransitionElementsKind::cast(instr); |
| 1725 if (trans->original_map()->has_fast_double_elements()) { | 1723 if (trans->original_map()->has_fast_double_elements()) { |
| 1724 hoist_change_blockers.Add(kChangesElementsPointer); | |
| 1726 hoist_change_blockers.Add(kChangesDoubleArrayElements); | 1725 hoist_change_blockers.Add(kChangesDoubleArrayElements); |
| 1727 } | 1726 } |
| 1728 if (trans->transitioned_map()->has_fast_double_elements()) { | 1727 if (trans->transitioned_map()->has_fast_double_elements()) { |
| 1728 hoist_change_blockers.Add(kChangesElementsPointer); | |
| 1729 hoist_change_blockers.Add(kChangesArrayElements); | 1729 hoist_change_blockers.Add(kChangesArrayElements); |
| 1730 } | 1730 } |
| 1731 if (FLAG_trace_gvn) { | 1731 if (FLAG_trace_gvn) { |
| 1732 GVNFlagSet hoist_blockers = hoist_depends_blockers; | 1732 GVNFlagSet hoist_blockers = hoist_depends_blockers; |
| 1733 hoist_blockers.Add(hoist_change_blockers); | 1733 hoist_blockers.Add(hoist_change_blockers); |
| 1734 GVNFlagSet first_time = *first_time_changes; | 1734 GVNFlagSet first_time = *first_time_changes; |
| 1735 first_time.Add(*first_time_depends); | 1735 first_time.Add(*first_time_depends); |
| 1736 TRACE_GVN_4("Checking dependencies on HTransitionElementsKind " | 1736 TRACE_GVN_4("Checking dependencies on HTransitionElementsKind " |
| 1737 "%d (%s) hoist blockers: %s; " | 1737 "%d (%s) hoist blockers: %s; " |
| 1738 "first-time accumulated: %s\n", | 1738 "first-time accumulated: %s\n", |
| (...skipping 2135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3874 | 3874 |
| 3875 set_current_block(loop_successor); | 3875 set_current_block(loop_successor); |
| 3876 Drop(5); | 3876 Drop(5); |
| 3877 | 3877 |
| 3878 set_current_block(loop_body); | 3878 set_current_block(loop_body); |
| 3879 | 3879 |
| 3880 HValue* key = AddInstruction( | 3880 HValue* key = AddInstruction( |
| 3881 new(zone()) HLoadKeyedFastElement( | 3881 new(zone()) HLoadKeyedFastElement( |
| 3882 environment()->ExpressionStackAt(2), // Enum cache. | 3882 environment()->ExpressionStackAt(2), // Enum cache. |
| 3883 environment()->ExpressionStackAt(0), // Iteration index. | 3883 environment()->ExpressionStackAt(0), // Iteration index. |
| 3884 HLoadKeyedFastElement::OMIT_HOLE_CHECK)); | 3884 OMIT_HOLE_CHECK)); |
| 3885 | 3885 |
| 3886 // Check if the expected map still matches that of the enumerable. | 3886 // Check if the expected map still matches that of the enumerable. |
| 3887 // If not just deoptimize. | 3887 // If not just deoptimize. |
| 3888 AddInstruction(new(zone()) HCheckMapValue( | 3888 AddInstruction(new(zone()) HCheckMapValue( |
| 3889 environment()->ExpressionStackAt(4), | 3889 environment()->ExpressionStackAt(4), |
| 3890 environment()->ExpressionStackAt(3))); | 3890 environment()->ExpressionStackAt(3))); |
| 3891 | 3891 |
| 3892 Bind(each_var, key); | 3892 Bind(each_var, key); |
| 3893 | 3893 |
| 3894 BreakAndContinueInfo break_info(stmt, 5); | 3894 BreakAndContinueInfo break_info(stmt, 5); |
| (...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4165 int* max_properties, | 4165 int* max_properties, |
| 4166 int* total_size) { | 4166 int* total_size) { |
| 4167 ASSERT(max_depth >= 0 && *max_properties >= 0); | 4167 ASSERT(max_depth >= 0 && *max_properties >= 0); |
| 4168 if (max_depth == 0) return false; | 4168 if (max_depth == 0) return false; |
| 4169 | 4169 |
| 4170 Handle<FixedArrayBase> elements(boilerplate->elements()); | 4170 Handle<FixedArrayBase> elements(boilerplate->elements()); |
| 4171 if (elements->length() > 0 && | 4171 if (elements->length() > 0 && |
| 4172 elements->map() != boilerplate->GetHeap()->fixed_cow_array_map()) { | 4172 elements->map() != boilerplate->GetHeap()->fixed_cow_array_map()) { |
| 4173 if (boilerplate->HasFastDoubleElements()) { | 4173 if (boilerplate->HasFastDoubleElements()) { |
| 4174 *total_size += FixedDoubleArray::SizeFor(elements->length()); | 4174 *total_size += FixedDoubleArray::SizeFor(elements->length()); |
| 4175 } else if (boilerplate->HasFastElements()) { | 4175 } else if (boilerplate->HasFastObjectElements()) { |
| 4176 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); | 4176 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); |
| 4177 int length = elements->length(); | 4177 int length = elements->length(); |
| 4178 for (int i = 0; i < length; i++) { | 4178 for (int i = 0; i < length; i++) { |
| 4179 if ((*max_properties)-- == 0) return false; | 4179 if ((*max_properties)-- == 0) return false; |
| 4180 Handle<Object> value(fast_elements->get(i)); | 4180 Handle<Object> value(fast_elements->get(i)); |
| 4181 if (value->IsJSObject()) { | 4181 if (value->IsJSObject()) { |
| 4182 Handle<JSObject> value_object = Handle<JSObject>::cast(value); | 4182 Handle<JSObject> value_object = Handle<JSObject>::cast(value); |
| 4183 if (!IsFastLiteral(value_object, | 4183 if (!IsFastLiteral(value_object, |
| 4184 max_depth - 1, | 4184 max_depth - 1, |
| 4185 max_properties, | 4185 max_properties, |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4372 if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal"); | 4372 if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal"); |
| 4373 | 4373 |
| 4374 elements = new(zone()) HLoadElements(literal); | 4374 elements = new(zone()) HLoadElements(literal); |
| 4375 AddInstruction(elements); | 4375 AddInstruction(elements); |
| 4376 | 4376 |
| 4377 HValue* key = AddInstruction( | 4377 HValue* key = AddInstruction( |
| 4378 new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), | 4378 new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), |
| 4379 Representation::Integer32())); | 4379 Representation::Integer32())); |
| 4380 | 4380 |
| 4381 switch (boilerplate_elements_kind) { | 4381 switch (boilerplate_elements_kind) { |
| 4382 case FAST_SMI_ONLY_ELEMENTS: | 4382 case FAST_SMI_ELEMENTS: |
| 4383 case FAST_HOLEY_SMI_ELEMENTS: | |
| 4383 // Smi-only arrays need a smi check. | 4384 // Smi-only arrays need a smi check. |
| 4384 AddInstruction(new(zone()) HCheckSmi(value)); | 4385 AddInstruction(new(zone()) HCheckSmi(value)); |
| 4385 // Fall through. | 4386 // Fall through. |
| 4386 case FAST_ELEMENTS: | 4387 case FAST_ELEMENTS: |
| 4388 case FAST_HOLEY_ELEMENTS: | |
| 4387 AddInstruction(new(zone()) HStoreKeyedFastElement( | 4389 AddInstruction(new(zone()) HStoreKeyedFastElement( |
| 4388 elements, | 4390 elements, |
| 4389 key, | 4391 key, |
| 4390 value, | 4392 value, |
| 4391 boilerplate_elements_kind)); | 4393 boilerplate_elements_kind)); |
| 4392 break; | 4394 break; |
| 4393 case FAST_DOUBLE_ELEMENTS: | 4395 case FAST_DOUBLE_ELEMENTS: |
| 4396 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
| 4394 AddInstruction(new(zone()) HStoreKeyedFastDoubleElement(elements, | 4397 AddInstruction(new(zone()) HStoreKeyedFastDoubleElement(elements, |
| 4395 key, | 4398 key, |
| 4396 value)); | 4399 value)); |
| 4397 break; | 4400 break; |
| 4398 default: | 4401 default: |
| 4399 UNREACHABLE(); | 4402 UNREACHABLE(); |
| 4400 break; | 4403 break; |
| 4401 } | 4404 } |
| 4402 | 4405 |
| 4403 AddSimulate(expr->GetIdForElement(i)); | 4406 AddSimulate(expr->GetIdForElement(i)); |
| (...skipping 737 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5141 val, | 5144 val, |
| 5142 Representation::Integer32(), | 5145 Representation::Integer32(), |
| 5143 true, // Truncate to int32. | 5146 true, // Truncate to int32. |
| 5144 false)); // Don't deoptimize undefined (irrelevant here). | 5147 false)); // Don't deoptimize undefined (irrelevant here). |
| 5145 } | 5148 } |
| 5146 break; | 5149 break; |
| 5147 } | 5150 } |
| 5148 case EXTERNAL_FLOAT_ELEMENTS: | 5151 case EXTERNAL_FLOAT_ELEMENTS: |
| 5149 case EXTERNAL_DOUBLE_ELEMENTS: | 5152 case EXTERNAL_DOUBLE_ELEMENTS: |
| 5150 break; | 5153 break; |
| 5151 case FAST_SMI_ONLY_ELEMENTS: | 5154 case FAST_SMI_ELEMENTS: |
| 5152 case FAST_ELEMENTS: | 5155 case FAST_ELEMENTS: |
| 5153 case FAST_DOUBLE_ELEMENTS: | 5156 case FAST_DOUBLE_ELEMENTS: |
| 5157 case FAST_HOLEY_SMI_ELEMENTS: | |
| 5158 case FAST_HOLEY_ELEMENTS: | |
| 5159 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
| 5154 case DICTIONARY_ELEMENTS: | 5160 case DICTIONARY_ELEMENTS: |
| 5155 case NON_STRICT_ARGUMENTS_ELEMENTS: | 5161 case NON_STRICT_ARGUMENTS_ELEMENTS: |
| 5156 UNREACHABLE(); | 5162 UNREACHABLE(); |
| 5157 break; | 5163 break; |
| 5158 } | 5164 } |
| 5159 return new(zone()) HStoreKeyedSpecializedArrayElement( | 5165 return new(zone()) HStoreKeyedSpecializedArrayElement( |
| 5160 external_elements, checked_key, val, elements_kind); | 5166 external_elements, checked_key, val, elements_kind); |
| 5161 } else { | 5167 } else { |
| 5162 ASSERT(val == NULL); | 5168 ASSERT(val == NULL); |
| 5163 return new(zone()) HLoadKeyedSpecializedArrayElement( | 5169 return new(zone()) HLoadKeyedSpecializedArrayElement( |
| 5164 external_elements, checked_key, elements_kind); | 5170 external_elements, checked_key, elements_kind); |
| 5165 } | 5171 } |
| 5166 } | 5172 } |
| 5167 | 5173 |
| 5168 | 5174 |
| 5169 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, | 5175 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, |
| 5170 HValue* checked_key, | 5176 HValue* checked_key, |
| 5171 HValue* val, | 5177 HValue* val, |
| 5172 ElementsKind elements_kind, | 5178 ElementsKind elements_kind, |
| 5173 bool is_store) { | 5179 bool is_store) { |
| 5174 if (is_store) { | 5180 if (is_store) { |
| 5175 ASSERT(val != NULL); | 5181 ASSERT(val != NULL); |
| 5176 switch (elements_kind) { | 5182 switch (elements_kind) { |
| 5177 case FAST_DOUBLE_ELEMENTS: | 5183 case FAST_DOUBLE_ELEMENTS: |
| 5184 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
| 5178 return new(zone()) HStoreKeyedFastDoubleElement( | 5185 return new(zone()) HStoreKeyedFastDoubleElement( |
| 5179 elements, checked_key, val); | 5186 elements, checked_key, val); |
| 5180 case FAST_SMI_ONLY_ELEMENTS: | 5187 case FAST_SMI_ELEMENTS: |
| 5188 case FAST_HOLEY_SMI_ELEMENTS: | |
| 5181 // Smi-only arrays need a smi check. | 5189 // Smi-only arrays need a smi check. |
| 5182 AddInstruction(new(zone()) HCheckSmi(val)); | 5190 AddInstruction(new(zone()) HCheckSmi(val)); |
| 5183 // Fall through. | 5191 // Fall through. |
| 5184 case FAST_ELEMENTS: | 5192 case FAST_ELEMENTS: |
| 5193 case FAST_HOLEY_ELEMENTS: | |
| 5185 return new(zone()) HStoreKeyedFastElement( | 5194 return new(zone()) HStoreKeyedFastElement( |
| 5186 elements, checked_key, val, elements_kind); | 5195 elements, checked_key, val, elements_kind); |
| 5187 default: | 5196 default: |
| 5188 UNREACHABLE(); | 5197 UNREACHABLE(); |
| 5189 return NULL; | 5198 return NULL; |
| 5190 } | 5199 } |
| 5191 } | 5200 } |
| 5192 // It's an element load (!is_store). | 5201 // It's an element load (!is_store). |
| 5193 if (elements_kind == FAST_DOUBLE_ELEMENTS) { | 5202 HoleCheckMode mode = IsFastPackedElementsKind(elements_kind) ? |
| 5194 return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key); | 5203 OMIT_HOLE_CHECK : |
| 5195 } else { // FAST_ELEMENTS or FAST_SMI_ONLY_ELEMENTS. | 5204 PERFORM_HOLE_CHECK; |
| 5196 return new(zone()) HLoadKeyedFastElement(elements, checked_key); | 5205 if (IsFastDoubleElementsKind(elements_kind)) { |
| 5206 return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key, mode); | |
| 5207 } else { // Smi or Object elements. | |
| 5208 return new(zone()) HLoadKeyedFastElement(elements, checked_key, mode); | |
| 5197 } | 5209 } |
| 5198 } | 5210 } |
| 5199 | 5211 |
| 5200 | 5212 |
| 5201 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, | 5213 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, |
| 5202 HValue* key, | 5214 HValue* key, |
| 5203 HValue* val, | 5215 HValue* val, |
| 5216 HValue* dependency, | |
| 5204 Handle<Map> map, | 5217 Handle<Map> map, |
| 5205 bool is_store) { | 5218 bool is_store) { |
| 5206 HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMaps(object, map)); | 5219 HInstruction* mapcheck = AddInstruction(new(zone()) |
|
Jakob Kummerow
2012/05/13 21:55:27
nit: I'd break the line after "AddInstruction("
danno
2012/05/22 11:05:21
Done.
| |
| 5207 bool fast_smi_only_elements = map->has_fast_smi_only_elements(); | 5220 HCheckMaps(object, map, dependency)); |
| 5208 bool fast_elements = map->has_fast_elements(); | 5221 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency |
| 5222 // on a HElementsTransition instruction. The flag can also be removed if the | |
| 5223 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further | |
| 5224 // ElementsKind transitions. Finally, the dependency can be removed for stores | |
| 5225 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the | |
| 5226 // generated store code. | |
| 5227 if (dependency || | |
| 5228 (map->elements_kind() == FAST_HOLEY_ELEMENTS) || | |
| 5229 (map->elements_kind() == FAST_ELEMENTS && is_store)) { | |
| 5230 mapcheck->ClearGVNFlag(kDependsOnElementsKind); | |
| 5231 } | |
| 5232 bool fast_smi_only_elements = map->has_fast_smi_elements(); | |
| 5233 bool fast_elements = map->has_fast_object_elements(); | |
| 5209 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); | 5234 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); |
| 5210 if (is_store && (fast_elements || fast_smi_only_elements)) { | 5235 if (is_store && (fast_elements || fast_smi_only_elements)) { |
| 5211 AddInstruction(new(zone()) HCheckMaps( | 5236 HCheckMaps* check_cow_map = new(zone()) HCheckMaps( |
| 5212 elements, isolate()->factory()->fixed_array_map())); | 5237 elements, isolate()->factory()->fixed_array_map()); |
| 5238 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); | |
| 5239 AddInstruction(check_cow_map); | |
| 5213 } | 5240 } |
| 5214 HInstruction* length = NULL; | 5241 HInstruction* length = NULL; |
| 5215 HInstruction* checked_key = NULL; | 5242 HInstruction* checked_key = NULL; |
| 5216 if (map->has_external_array_elements()) { | 5243 if (map->has_external_array_elements()) { |
| 5217 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 5244 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
| 5218 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 5245 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 5219 HLoadExternalArrayPointer* external_elements = | 5246 HLoadExternalArrayPointer* external_elements = |
| 5220 new(zone()) HLoadExternalArrayPointer(elements); | 5247 new(zone()) HLoadExternalArrayPointer(elements); |
| 5221 AddInstruction(external_elements); | 5248 AddInstruction(external_elements); |
| 5222 return BuildExternalArrayElementAccess(external_elements, checked_key, | 5249 return BuildExternalArrayElementAccess(external_elements, checked_key, |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5255 type_todo[i] = false; | 5282 type_todo[i] = false; |
| 5256 } | 5283 } |
| 5257 | 5284 |
| 5258 // Elements_kind transition support. | 5285 // Elements_kind transition support. |
| 5259 MapHandleList transition_target(maps->length()); | 5286 MapHandleList transition_target(maps->length()); |
| 5260 // Collect possible transition targets. | 5287 // Collect possible transition targets. |
| 5261 MapHandleList possible_transitioned_maps(maps->length()); | 5288 MapHandleList possible_transitioned_maps(maps->length()); |
| 5262 for (int i = 0; i < maps->length(); ++i) { | 5289 for (int i = 0; i < maps->length(); ++i) { |
| 5263 Handle<Map> map = maps->at(i); | 5290 Handle<Map> map = maps->at(i); |
| 5264 ElementsKind elements_kind = map->elements_kind(); | 5291 ElementsKind elements_kind = map->elements_kind(); |
| 5265 if (elements_kind == FAST_DOUBLE_ELEMENTS || | 5292 if (IsFastElementsKind(elements_kind) && |
| 5266 elements_kind == FAST_ELEMENTS) { | 5293 elements_kind != GetInitialFastElementsKind()) { |
| 5267 possible_transitioned_maps.Add(map); | 5294 possible_transitioned_maps.Add(map); |
| 5268 } | 5295 } |
| 5269 } | 5296 } |
| 5270 // Get transition target for each map (NULL == no transition). | 5297 // Get transition target for each map (NULL == no transition). |
| 5271 for (int i = 0; i < maps->length(); ++i) { | 5298 for (int i = 0; i < maps->length(); ++i) { |
| 5272 Handle<Map> map = maps->at(i); | 5299 Handle<Map> map = maps->at(i); |
| 5273 Handle<Map> transitioned_map = | 5300 Handle<Map> transitioned_map = |
| 5274 map->FindTransitionedMap(&possible_transitioned_maps); | 5301 map->FindTransitionedMap(&possible_transitioned_maps); |
| 5275 transition_target.Add(transitioned_map); | 5302 transition_target.Add(transitioned_map); |
| 5276 } | 5303 } |
| 5277 | 5304 |
| 5278 int num_untransitionable_maps = 0; | 5305 int num_untransitionable_maps = 0; |
| 5279 Handle<Map> untransitionable_map; | 5306 Handle<Map> untransitionable_map; |
| 5307 HTransitionElementsKind* transition = NULL; | |
| 5280 for (int i = 0; i < maps->length(); ++i) { | 5308 for (int i = 0; i < maps->length(); ++i) { |
| 5281 Handle<Map> map = maps->at(i); | 5309 Handle<Map> map = maps->at(i); |
| 5282 ASSERT(map->IsMap()); | 5310 ASSERT(map->IsMap()); |
| 5283 if (!transition_target.at(i).is_null()) { | 5311 if (!transition_target.at(i).is_null()) { |
| 5284 AddInstruction(new(zone()) HTransitionElementsKind( | 5312 ASSERT(Map::IsValidElementsTransition( |
| 5285 object, map, transition_target.at(i))); | 5313 map->elements_kind(), |
| 5314 transition_target.at(i)->elements_kind())); | |
| 5315 transition = new(zone()) HTransitionElementsKind( | |
| 5316 object, map, transition_target.at(i)); | |
| 5317 AddInstruction(transition); | |
| 5286 } else { | 5318 } else { |
| 5287 type_todo[map->elements_kind()] = true; | 5319 type_todo[map->elements_kind()] = true; |
| 5288 if (map->elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) { | 5320 if (map->elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) { |
| 5289 todo_external_array = true; | 5321 todo_external_array = true; |
| 5290 } | 5322 } |
| 5291 num_untransitionable_maps++; | 5323 num_untransitionable_maps++; |
| 5292 untransitionable_map = map; | 5324 untransitionable_map = map; |
| 5293 } | 5325 } |
| 5294 } | 5326 } |
| 5295 | 5327 |
| 5296 // If only one map is left after transitioning, handle this case | 5328 // If only one map is left after transitioning, handle this case |
| 5297 // monomorphically. | 5329 // monomorphically. |
| 5298 if (num_untransitionable_maps == 1) { | 5330 if (num_untransitionable_maps == 1) { |
| 5299 HInstruction* instr = NULL; | 5331 HInstruction* instr = NULL; |
| 5300 if (untransitionable_map->has_slow_elements_kind()) { | 5332 if (untransitionable_map->has_slow_elements_kind()) { |
| 5301 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) | 5333 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) |
| 5302 : BuildLoadKeyedGeneric(object, key)); | 5334 : BuildLoadKeyedGeneric(object, key)); |
| 5303 } else { | 5335 } else { |
| 5304 instr = AddInstruction(BuildMonomorphicElementAccess( | 5336 instr = AddInstruction(BuildMonomorphicElementAccess( |
| 5305 object, key, val, untransitionable_map, is_store)); | 5337 object, key, val, transition, untransitionable_map, is_store)); |
| 5306 } | 5338 } |
| 5307 *has_side_effects |= instr->HasObservableSideEffects(); | 5339 *has_side_effects |= instr->HasObservableSideEffects(); |
| 5308 instr->set_position(position); | 5340 instr->set_position(position); |
| 5309 return is_store ? NULL : instr; | 5341 return is_store ? NULL : instr; |
| 5310 } | 5342 } |
| 5311 | 5343 |
| 5312 AddInstruction(HCheckInstanceType::NewIsSpecObject(object)); | 5344 AddInstruction(HCheckInstanceType::NewIsSpecObject(object)); |
| 5313 HBasicBlock* join = graph()->CreateBasicBlock(); | 5345 HBasicBlock* join = graph()->CreateBasicBlock(); |
| 5314 | 5346 |
| 5315 HInstruction* elements_kind_instr = | 5347 HInstruction* elements_kind_instr = |
| 5316 AddInstruction(new(zone()) HElementsKind(object)); | 5348 AddInstruction(new(zone()) HElementsKind(object)); |
| 5317 HCompareConstantEqAndBranch* elements_kind_branch = NULL; | 5349 HCompareConstantEqAndBranch* elements_kind_branch = NULL; |
| 5318 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); | 5350 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); |
| 5319 HLoadExternalArrayPointer* external_elements = NULL; | 5351 HLoadExternalArrayPointer* external_elements = NULL; |
| 5320 HInstruction* checked_key = NULL; | 5352 HInstruction* checked_key = NULL; |
| 5321 | 5353 |
| 5322 // Generated code assumes that FAST_SMI_ONLY_ELEMENTS, FAST_ELEMENTS, | 5354 // Generated code assumes that FAST_* and DICTIONARY_ELEMENTS ElementsKinds |
| 5323 // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS are handled before external | 5355 // are handled before external arrays. |
| 5324 // arrays. | 5356 STATIC_ASSERT(FAST_SMI_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
| 5325 STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | 5357 STATIC_ASSERT(FAST_HOLEY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
| 5326 STATIC_ASSERT(FAST_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | |
| 5327 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | 5358 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
| 5328 STATIC_ASSERT(DICTIONARY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | 5359 STATIC_ASSERT(DICTIONARY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
| 5329 | 5360 |
| 5330 for (ElementsKind elements_kind = FIRST_ELEMENTS_KIND; | 5361 for (ElementsKind elements_kind = FIRST_ELEMENTS_KIND; |
| 5331 elements_kind <= LAST_ELEMENTS_KIND; | 5362 elements_kind <= LAST_ELEMENTS_KIND; |
| 5332 elements_kind = ElementsKind(elements_kind + 1)) { | 5363 elements_kind = ElementsKind(elements_kind + 1)) { |
| 5333 // After having handled FAST_ELEMENTS, FAST_SMI_ONLY_ELEMENTS, | 5364 // After having handled FAST_* and DICTIONARY_ELEMENTS, we need to add some |
| 5334 // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS, we need to add some code | 5365 // code that's executed for all external array cases. |
| 5335 // that's executed for all external array cases. | |
| 5336 STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == | 5366 STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == |
| 5337 LAST_ELEMENTS_KIND); | 5367 LAST_ELEMENTS_KIND); |
| 5338 if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND | 5368 if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND |
| 5339 && todo_external_array) { | 5369 && todo_external_array) { |
| 5340 HInstruction* length = | 5370 HInstruction* length = |
| 5341 AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 5371 AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
| 5342 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 5372 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 5343 external_elements = new(zone()) HLoadExternalArrayPointer(elements); | 5373 external_elements = new(zone()) HLoadExternalArrayPointer(elements); |
| 5344 AddInstruction(external_elements); | 5374 AddInstruction(external_elements); |
| 5345 } | 5375 } |
| 5346 if (type_todo[elements_kind]) { | 5376 if (type_todo[elements_kind]) { |
| 5347 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 5377 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 5348 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 5378 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 5349 elements_kind_branch = new(zone()) HCompareConstantEqAndBranch( | 5379 elements_kind_branch = new(zone()) HCompareConstantEqAndBranch( |
| 5350 elements_kind_instr, elements_kind, Token::EQ_STRICT); | 5380 elements_kind_instr, elements_kind, Token::EQ_STRICT); |
| 5351 elements_kind_branch->SetSuccessorAt(0, if_true); | 5381 elements_kind_branch->SetSuccessorAt(0, if_true); |
| 5352 elements_kind_branch->SetSuccessorAt(1, if_false); | 5382 elements_kind_branch->SetSuccessorAt(1, if_false); |
| 5353 current_block()->Finish(elements_kind_branch); | 5383 current_block()->Finish(elements_kind_branch); |
| 5354 | 5384 |
| 5355 set_current_block(if_true); | 5385 set_current_block(if_true); |
| 5356 HInstruction* access; | 5386 HInstruction* access; |
| 5357 if (elements_kind == FAST_SMI_ONLY_ELEMENTS || | 5387 if (IsFastElementsKind(elements_kind)) { |
| 5358 elements_kind == FAST_ELEMENTS || | 5388 if (is_store && !IsFastDoubleElementsKind(elements_kind)) { |
| 5359 elements_kind == FAST_DOUBLE_ELEMENTS) { | |
| 5360 if (is_store && elements_kind != FAST_DOUBLE_ELEMENTS) { | |
| 5361 AddInstruction(new(zone()) HCheckMaps( | 5389 AddInstruction(new(zone()) HCheckMaps( |
| 5362 elements, isolate()->factory()->fixed_array_map(), | 5390 elements, isolate()->factory()->fixed_array_map(), |
| 5363 elements_kind_branch)); | 5391 elements_kind_branch)); |
| 5364 } | 5392 } |
| 5365 // TODO(jkummerow): The need for these two blocks could be avoided | 5393 // TODO(jkummerow): The need for these two blocks could be avoided |
| 5366 // in one of two ways: | 5394 // in one of two ways: |
| 5367 // (1) Introduce ElementsKinds for JSArrays that are distinct from | 5395 // (1) Introduce ElementsKinds for JSArrays that are distinct from |
| 5368 // those for fast objects. | 5396 // those for fast objects. |
| 5369 // (2) Put the common instructions into a third "join" block. This | 5397 // (2) Put the common instructions into a third "join" block. This |
| 5370 // requires additional AST IDs that we can deopt to from inside | 5398 // requires additional AST IDs that we can deopt to from inside |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5437 bool* has_side_effects) { | 5465 bool* has_side_effects) { |
| 5438 ASSERT(!expr->IsPropertyName()); | 5466 ASSERT(!expr->IsPropertyName()); |
| 5439 HInstruction* instr = NULL; | 5467 HInstruction* instr = NULL; |
| 5440 if (expr->IsMonomorphic()) { | 5468 if (expr->IsMonomorphic()) { |
| 5441 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 5469 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 5442 if (map->has_slow_elements_kind()) { | 5470 if (map->has_slow_elements_kind()) { |
| 5443 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) | 5471 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) |
| 5444 : BuildLoadKeyedGeneric(obj, key); | 5472 : BuildLoadKeyedGeneric(obj, key); |
| 5445 } else { | 5473 } else { |
| 5446 AddInstruction(new(zone()) HCheckNonSmi(obj)); | 5474 AddInstruction(new(zone()) HCheckNonSmi(obj)); |
| 5447 instr = BuildMonomorphicElementAccess(obj, key, val, map, is_store); | 5475 instr = BuildMonomorphicElementAccess(obj, key, val, NULL, map, is_store); |
| 5448 } | 5476 } |
| 5449 } else if (expr->GetReceiverTypes() != NULL && | 5477 } else if (expr->GetReceiverTypes() != NULL && |
| 5450 !expr->GetReceiverTypes()->is_empty()) { | 5478 !expr->GetReceiverTypes()->is_empty()) { |
| 5451 return HandlePolymorphicElementAccess( | 5479 return HandlePolymorphicElementAccess( |
| 5452 obj, key, val, expr, ast_id, position, is_store, has_side_effects); | 5480 obj, key, val, expr, ast_id, position, is_store, has_side_effects); |
| 5453 } else { | 5481 } else { |
| 5454 if (is_store) { | 5482 if (is_store) { |
| 5455 instr = BuildStoreKeyedGeneric(obj, key, val); | 5483 instr = BuildStoreKeyedGeneric(obj, key, val); |
| 5456 } else { | 5484 } else { |
| 5457 instr = BuildLoadKeyedGeneric(obj, key); | 5485 instr = BuildLoadKeyedGeneric(obj, key); |
| (...skipping 3402 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8860 } | 8888 } |
| 8861 } | 8889 } |
| 8862 | 8890 |
| 8863 #ifdef DEBUG | 8891 #ifdef DEBUG |
| 8864 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 8892 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
| 8865 if (allocator_ != NULL) allocator_->Verify(); | 8893 if (allocator_ != NULL) allocator_->Verify(); |
| 8866 #endif | 8894 #endif |
| 8867 } | 8895 } |
| 8868 | 8896 |
| 8869 } } // namespace v8::internal | 8897 } } // namespace v8::internal |
| OLD | NEW |