| 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 2220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3959 | 3959 |
| 3960 set_current_block(loop_successor); | 3960 set_current_block(loop_successor); |
| 3961 Drop(5); | 3961 Drop(5); |
| 3962 | 3962 |
| 3963 set_current_block(loop_body); | 3963 set_current_block(loop_body); |
| 3964 | 3964 |
| 3965 HValue* key = AddInstruction( | 3965 HValue* key = AddInstruction( |
| 3966 new(zone()) HLoadKeyedFastElement( | 3966 new(zone()) HLoadKeyedFastElement( |
| 3967 environment()->ExpressionStackAt(2), // Enum cache. | 3967 environment()->ExpressionStackAt(2), // Enum cache. |
| 3968 environment()->ExpressionStackAt(0), // Iteration index. | 3968 environment()->ExpressionStackAt(0), // Iteration index. |
| 3969 HLoadKeyedFastElement::OMIT_HOLE_CHECK)); | 3969 OMIT_HOLE_CHECK)); |
| 3970 | 3970 |
| 3971 // Check if the expected map still matches that of the enumerable. | 3971 // Check if the expected map still matches that of the enumerable. |
| 3972 // If not just deoptimize. | 3972 // If not just deoptimize. |
| 3973 AddInstruction(new(zone()) HCheckMapValue( | 3973 AddInstruction(new(zone()) HCheckMapValue( |
| 3974 environment()->ExpressionStackAt(4), | 3974 environment()->ExpressionStackAt(4), |
| 3975 environment()->ExpressionStackAt(3))); | 3975 environment()->ExpressionStackAt(3))); |
| 3976 | 3976 |
| 3977 Bind(each_var, key); | 3977 Bind(each_var, key); |
| 3978 | 3978 |
| 3979 BreakAndContinueInfo break_info(stmt, 5); | 3979 BreakAndContinueInfo break_info(stmt, 5); |
| (...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4250 int* max_properties, | 4250 int* max_properties, |
| 4251 int* total_size) { | 4251 int* total_size) { |
| 4252 ASSERT(max_depth >= 0 && *max_properties >= 0); | 4252 ASSERT(max_depth >= 0 && *max_properties >= 0); |
| 4253 if (max_depth == 0) return false; | 4253 if (max_depth == 0) return false; |
| 4254 | 4254 |
| 4255 Handle<FixedArrayBase> elements(boilerplate->elements()); | 4255 Handle<FixedArrayBase> elements(boilerplate->elements()); |
| 4256 if (elements->length() > 0 && | 4256 if (elements->length() > 0 && |
| 4257 elements->map() != boilerplate->GetHeap()->fixed_cow_array_map()) { | 4257 elements->map() != boilerplate->GetHeap()->fixed_cow_array_map()) { |
| 4258 if (boilerplate->HasFastDoubleElements()) { | 4258 if (boilerplate->HasFastDoubleElements()) { |
| 4259 *total_size += FixedDoubleArray::SizeFor(elements->length()); | 4259 *total_size += FixedDoubleArray::SizeFor(elements->length()); |
| 4260 } else if (boilerplate->HasFastElements()) { | 4260 } else if (boilerplate->HasFastObjectElements()) { |
| 4261 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); | 4261 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); |
| 4262 int length = elements->length(); | 4262 int length = elements->length(); |
| 4263 for (int i = 0; i < length; i++) { | 4263 for (int i = 0; i < length; i++) { |
| 4264 if ((*max_properties)-- == 0) return false; | 4264 if ((*max_properties)-- == 0) return false; |
| 4265 Handle<Object> value(fast_elements->get(i)); | 4265 Handle<Object> value(fast_elements->get(i)); |
| 4266 if (value->IsJSObject()) { | 4266 if (value->IsJSObject()) { |
| 4267 Handle<JSObject> value_object = Handle<JSObject>::cast(value); | 4267 Handle<JSObject> value_object = Handle<JSObject>::cast(value); |
| 4268 if (!IsFastLiteral(value_object, | 4268 if (!IsFastLiteral(value_object, |
| 4269 max_depth - 1, | 4269 max_depth - 1, |
| 4270 max_properties, | 4270 max_properties, |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4457 if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal"); | 4457 if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal"); |
| 4458 | 4458 |
| 4459 elements = new(zone()) HLoadElements(literal); | 4459 elements = new(zone()) HLoadElements(literal); |
| 4460 AddInstruction(elements); | 4460 AddInstruction(elements); |
| 4461 | 4461 |
| 4462 HValue* key = AddInstruction( | 4462 HValue* key = AddInstruction( |
| 4463 new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), | 4463 new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), |
| 4464 Representation::Integer32())); | 4464 Representation::Integer32())); |
| 4465 | 4465 |
| 4466 switch (boilerplate_elements_kind) { | 4466 switch (boilerplate_elements_kind) { |
| 4467 case FAST_SMI_ONLY_ELEMENTS: | 4467 case FAST_SMI_ELEMENTS: |
| 4468 case FAST_HOLEY_SMI_ELEMENTS: |
| 4468 // Smi-only arrays need a smi check. | 4469 // Smi-only arrays need a smi check. |
| 4469 AddInstruction(new(zone()) HCheckSmi(value)); | 4470 AddInstruction(new(zone()) HCheckSmi(value)); |
| 4470 // Fall through. | 4471 // Fall through. |
| 4471 case FAST_ELEMENTS: | 4472 case FAST_ELEMENTS: |
| 4473 case FAST_HOLEY_ELEMENTS: |
| 4472 AddInstruction(new(zone()) HStoreKeyedFastElement( | 4474 AddInstruction(new(zone()) HStoreKeyedFastElement( |
| 4473 elements, | 4475 elements, |
| 4474 key, | 4476 key, |
| 4475 value, | 4477 value, |
| 4476 boilerplate_elements_kind)); | 4478 boilerplate_elements_kind)); |
| 4477 break; | 4479 break; |
| 4478 case FAST_DOUBLE_ELEMENTS: | 4480 case FAST_DOUBLE_ELEMENTS: |
| 4481 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 4479 AddInstruction(new(zone()) HStoreKeyedFastDoubleElement(elements, | 4482 AddInstruction(new(zone()) HStoreKeyedFastDoubleElement(elements, |
| 4480 key, | 4483 key, |
| 4481 value)); | 4484 value)); |
| 4482 break; | 4485 break; |
| 4483 default: | 4486 default: |
| 4484 UNREACHABLE(); | 4487 UNREACHABLE(); |
| 4485 break; | 4488 break; |
| 4486 } | 4489 } |
| 4487 | 4490 |
| 4488 AddSimulate(expr->GetIdForElement(i)); | 4491 AddSimulate(expr->GetIdForElement(i)); |
| (...skipping 737 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5226 val, | 5229 val, |
| 5227 Representation::Integer32(), | 5230 Representation::Integer32(), |
| 5228 true, // Truncate to int32. | 5231 true, // Truncate to int32. |
| 5229 false)); // Don't deoptimize undefined (irrelevant here). | 5232 false)); // Don't deoptimize undefined (irrelevant here). |
| 5230 } | 5233 } |
| 5231 break; | 5234 break; |
| 5232 } | 5235 } |
| 5233 case EXTERNAL_FLOAT_ELEMENTS: | 5236 case EXTERNAL_FLOAT_ELEMENTS: |
| 5234 case EXTERNAL_DOUBLE_ELEMENTS: | 5237 case EXTERNAL_DOUBLE_ELEMENTS: |
| 5235 break; | 5238 break; |
| 5236 case FAST_SMI_ONLY_ELEMENTS: | 5239 case FAST_SMI_ELEMENTS: |
| 5237 case FAST_ELEMENTS: | 5240 case FAST_ELEMENTS: |
| 5238 case FAST_DOUBLE_ELEMENTS: | 5241 case FAST_DOUBLE_ELEMENTS: |
| 5242 case FAST_HOLEY_SMI_ELEMENTS: |
| 5243 case FAST_HOLEY_ELEMENTS: |
| 5244 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 5239 case DICTIONARY_ELEMENTS: | 5245 case DICTIONARY_ELEMENTS: |
| 5240 case NON_STRICT_ARGUMENTS_ELEMENTS: | 5246 case NON_STRICT_ARGUMENTS_ELEMENTS: |
| 5241 UNREACHABLE(); | 5247 UNREACHABLE(); |
| 5242 break; | 5248 break; |
| 5243 } | 5249 } |
| 5244 return new(zone()) HStoreKeyedSpecializedArrayElement( | 5250 return new(zone()) HStoreKeyedSpecializedArrayElement( |
| 5245 external_elements, checked_key, val, elements_kind); | 5251 external_elements, checked_key, val, elements_kind); |
| 5246 } else { | 5252 } else { |
| 5247 ASSERT(val == NULL); | 5253 ASSERT(val == NULL); |
| 5248 return new(zone()) HLoadKeyedSpecializedArrayElement( | 5254 return new(zone()) HLoadKeyedSpecializedArrayElement( |
| 5249 external_elements, checked_key, elements_kind); | 5255 external_elements, checked_key, elements_kind); |
| 5250 } | 5256 } |
| 5251 } | 5257 } |
| 5252 | 5258 |
| 5253 | 5259 |
| 5254 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, | 5260 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, |
| 5255 HValue* checked_key, | 5261 HValue* checked_key, |
| 5256 HValue* val, | 5262 HValue* val, |
| 5257 ElementsKind elements_kind, | 5263 ElementsKind elements_kind, |
| 5258 bool is_store) { | 5264 bool is_store) { |
| 5259 if (is_store) { | 5265 if (is_store) { |
| 5260 ASSERT(val != NULL); | 5266 ASSERT(val != NULL); |
| 5261 switch (elements_kind) { | 5267 switch (elements_kind) { |
| 5262 case FAST_DOUBLE_ELEMENTS: | 5268 case FAST_DOUBLE_ELEMENTS: |
| 5269 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 5263 return new(zone()) HStoreKeyedFastDoubleElement( | 5270 return new(zone()) HStoreKeyedFastDoubleElement( |
| 5264 elements, checked_key, val); | 5271 elements, checked_key, val); |
| 5265 case FAST_SMI_ONLY_ELEMENTS: | 5272 case FAST_SMI_ELEMENTS: |
| 5273 case FAST_HOLEY_SMI_ELEMENTS: |
| 5266 // Smi-only arrays need a smi check. | 5274 // Smi-only arrays need a smi check. |
| 5267 AddInstruction(new(zone()) HCheckSmi(val)); | 5275 AddInstruction(new(zone()) HCheckSmi(val)); |
| 5268 // Fall through. | 5276 // Fall through. |
| 5269 case FAST_ELEMENTS: | 5277 case FAST_ELEMENTS: |
| 5278 case FAST_HOLEY_ELEMENTS: |
| 5270 return new(zone()) HStoreKeyedFastElement( | 5279 return new(zone()) HStoreKeyedFastElement( |
| 5271 elements, checked_key, val, elements_kind); | 5280 elements, checked_key, val, elements_kind); |
| 5272 default: | 5281 default: |
| 5273 UNREACHABLE(); | 5282 UNREACHABLE(); |
| 5274 return NULL; | 5283 return NULL; |
| 5275 } | 5284 } |
| 5276 } | 5285 } |
| 5277 // It's an element load (!is_store). | 5286 // It's an element load (!is_store). |
| 5278 if (elements_kind == FAST_DOUBLE_ELEMENTS) { | 5287 HoleCheckMode mode = IsFastPackedElementsKind(elements_kind) ? |
| 5279 return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key); | 5288 OMIT_HOLE_CHECK : |
| 5280 } else { // FAST_ELEMENTS or FAST_SMI_ONLY_ELEMENTS. | 5289 PERFORM_HOLE_CHECK; |
| 5281 return new(zone()) HLoadKeyedFastElement(elements, checked_key); | 5290 if (IsFastDoubleElementsKind(elements_kind)) { |
| 5291 return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key, mode); |
| 5292 } else { // Smi or Object elements. |
| 5293 return new(zone()) HLoadKeyedFastElement(elements, checked_key, mode); |
| 5282 } | 5294 } |
| 5283 } | 5295 } |
| 5284 | 5296 |
| 5285 | 5297 |
| 5286 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, | 5298 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, |
| 5287 HValue* key, | 5299 HValue* key, |
| 5288 HValue* val, | 5300 HValue* val, |
| 5301 HValue* dependency, |
| 5289 Handle<Map> map, | 5302 Handle<Map> map, |
| 5290 bool is_store) { | 5303 bool is_store) { |
| 5291 HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMaps(object, map)); | 5304 HInstruction* mapcheck = |
| 5292 bool fast_smi_only_elements = map->has_fast_smi_only_elements(); | 5305 AddInstruction(new(zone()) HCheckMaps(object, map, dependency)); |
| 5293 bool fast_elements = map->has_fast_elements(); | 5306 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency |
| 5307 // on a HElementsTransition instruction. The flag can also be removed if the |
| 5308 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further |
| 5309 // ElementsKind transitions. Finally, the dependency can be removed for stores |
| 5310 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the |
| 5311 // generated store code. |
| 5312 if (dependency || |
| 5313 (map->elements_kind() == FAST_HOLEY_ELEMENTS) || |
| 5314 (map->elements_kind() == FAST_ELEMENTS && is_store)) { |
| 5315 mapcheck->ClearGVNFlag(kDependsOnElementsKind); |
| 5316 } |
| 5317 bool fast_smi_only_elements = map->has_fast_smi_elements(); |
| 5318 bool fast_elements = map->has_fast_object_elements(); |
| 5294 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); | 5319 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); |
| 5295 if (is_store && (fast_elements || fast_smi_only_elements)) { | 5320 if (is_store && (fast_elements || fast_smi_only_elements)) { |
| 5296 AddInstruction(new(zone()) HCheckMaps( | 5321 HCheckMaps* check_cow_map = new(zone()) HCheckMaps( |
| 5297 elements, isolate()->factory()->fixed_array_map())); | 5322 elements, isolate()->factory()->fixed_array_map()); |
| 5323 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); |
| 5324 AddInstruction(check_cow_map); |
| 5298 } | 5325 } |
| 5299 HInstruction* length = NULL; | 5326 HInstruction* length = NULL; |
| 5300 HInstruction* checked_key = NULL; | 5327 HInstruction* checked_key = NULL; |
| 5301 if (map->has_external_array_elements()) { | 5328 if (map->has_external_array_elements()) { |
| 5302 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 5329 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
| 5303 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 5330 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 5304 HLoadExternalArrayPointer* external_elements = | 5331 HLoadExternalArrayPointer* external_elements = |
| 5305 new(zone()) HLoadExternalArrayPointer(elements); | 5332 new(zone()) HLoadExternalArrayPointer(elements); |
| 5306 AddInstruction(external_elements); | 5333 AddInstruction(external_elements); |
| 5307 return BuildExternalArrayElementAccess(external_elements, checked_key, | 5334 return BuildExternalArrayElementAccess(external_elements, checked_key, |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5340 type_todo[i] = false; | 5367 type_todo[i] = false; |
| 5341 } | 5368 } |
| 5342 | 5369 |
| 5343 // Elements_kind transition support. | 5370 // Elements_kind transition support. |
| 5344 MapHandleList transition_target(maps->length()); | 5371 MapHandleList transition_target(maps->length()); |
| 5345 // Collect possible transition targets. | 5372 // Collect possible transition targets. |
| 5346 MapHandleList possible_transitioned_maps(maps->length()); | 5373 MapHandleList possible_transitioned_maps(maps->length()); |
| 5347 for (int i = 0; i < maps->length(); ++i) { | 5374 for (int i = 0; i < maps->length(); ++i) { |
| 5348 Handle<Map> map = maps->at(i); | 5375 Handle<Map> map = maps->at(i); |
| 5349 ElementsKind elements_kind = map->elements_kind(); | 5376 ElementsKind elements_kind = map->elements_kind(); |
| 5350 if (elements_kind == FAST_DOUBLE_ELEMENTS || | 5377 if (IsFastElementsKind(elements_kind) && |
| 5351 elements_kind == FAST_ELEMENTS) { | 5378 elements_kind != GetInitialFastElementsKind()) { |
| 5352 possible_transitioned_maps.Add(map); | 5379 possible_transitioned_maps.Add(map); |
| 5353 } | 5380 } |
| 5354 } | 5381 } |
| 5355 // Get transition target for each map (NULL == no transition). | 5382 // Get transition target for each map (NULL == no transition). |
| 5356 for (int i = 0; i < maps->length(); ++i) { | 5383 for (int i = 0; i < maps->length(); ++i) { |
| 5357 Handle<Map> map = maps->at(i); | 5384 Handle<Map> map = maps->at(i); |
| 5358 Handle<Map> transitioned_map = | 5385 Handle<Map> transitioned_map = |
| 5359 map->FindTransitionedMap(&possible_transitioned_maps); | 5386 map->FindTransitionedMap(&possible_transitioned_maps); |
| 5360 transition_target.Add(transitioned_map); | 5387 transition_target.Add(transitioned_map); |
| 5361 } | 5388 } |
| 5362 | 5389 |
| 5363 int num_untransitionable_maps = 0; | 5390 int num_untransitionable_maps = 0; |
| 5364 Handle<Map> untransitionable_map; | 5391 Handle<Map> untransitionable_map; |
| 5392 HTransitionElementsKind* transition = NULL; |
| 5365 for (int i = 0; i < maps->length(); ++i) { | 5393 for (int i = 0; i < maps->length(); ++i) { |
| 5366 Handle<Map> map = maps->at(i); | 5394 Handle<Map> map = maps->at(i); |
| 5367 ASSERT(map->IsMap()); | 5395 ASSERT(map->IsMap()); |
| 5368 if (!transition_target.at(i).is_null()) { | 5396 if (!transition_target.at(i).is_null()) { |
| 5369 AddInstruction(new(zone()) HTransitionElementsKind( | 5397 ASSERT(Map::IsValidElementsTransition( |
| 5370 object, map, transition_target.at(i))); | 5398 map->elements_kind(), |
| 5399 transition_target.at(i)->elements_kind())); |
| 5400 transition = new(zone()) HTransitionElementsKind( |
| 5401 object, map, transition_target.at(i)); |
| 5402 AddInstruction(transition); |
| 5371 } else { | 5403 } else { |
| 5372 type_todo[map->elements_kind()] = true; | 5404 type_todo[map->elements_kind()] = true; |
| 5373 if (map->elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) { | 5405 if (map->elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) { |
| 5374 todo_external_array = true; | 5406 todo_external_array = true; |
| 5375 } | 5407 } |
| 5376 num_untransitionable_maps++; | 5408 num_untransitionable_maps++; |
| 5377 untransitionable_map = map; | 5409 untransitionable_map = map; |
| 5378 } | 5410 } |
| 5379 } | 5411 } |
| 5380 | 5412 |
| 5381 // If only one map is left after transitioning, handle this case | 5413 // If only one map is left after transitioning, handle this case |
| 5382 // monomorphically. | 5414 // monomorphically. |
| 5383 if (num_untransitionable_maps == 1) { | 5415 if (num_untransitionable_maps == 1) { |
| 5384 HInstruction* instr = NULL; | 5416 HInstruction* instr = NULL; |
| 5385 if (untransitionable_map->has_slow_elements_kind()) { | 5417 if (untransitionable_map->has_slow_elements_kind()) { |
| 5386 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) | 5418 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) |
| 5387 : BuildLoadKeyedGeneric(object, key)); | 5419 : BuildLoadKeyedGeneric(object, key)); |
| 5388 } else { | 5420 } else { |
| 5389 instr = AddInstruction(BuildMonomorphicElementAccess( | 5421 instr = AddInstruction(BuildMonomorphicElementAccess( |
| 5390 object, key, val, untransitionable_map, is_store)); | 5422 object, key, val, transition, untransitionable_map, is_store)); |
| 5391 } | 5423 } |
| 5392 *has_side_effects |= instr->HasObservableSideEffects(); | 5424 *has_side_effects |= instr->HasObservableSideEffects(); |
| 5393 instr->set_position(position); | 5425 instr->set_position(position); |
| 5394 return is_store ? NULL : instr; | 5426 return is_store ? NULL : instr; |
| 5395 } | 5427 } |
| 5396 | 5428 |
| 5397 AddInstruction(HCheckInstanceType::NewIsSpecObject(object)); | 5429 AddInstruction(HCheckInstanceType::NewIsSpecObject(object)); |
| 5398 HBasicBlock* join = graph()->CreateBasicBlock(); | 5430 HBasicBlock* join = graph()->CreateBasicBlock(); |
| 5399 | 5431 |
| 5400 HInstruction* elements_kind_instr = | 5432 HInstruction* elements_kind_instr = |
| 5401 AddInstruction(new(zone()) HElementsKind(object)); | 5433 AddInstruction(new(zone()) HElementsKind(object)); |
| 5402 HCompareConstantEqAndBranch* elements_kind_branch = NULL; | 5434 HCompareConstantEqAndBranch* elements_kind_branch = NULL; |
| 5403 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); | 5435 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); |
| 5404 HLoadExternalArrayPointer* external_elements = NULL; | 5436 HLoadExternalArrayPointer* external_elements = NULL; |
| 5405 HInstruction* checked_key = NULL; | 5437 HInstruction* checked_key = NULL; |
| 5406 | 5438 |
| 5407 // Generated code assumes that FAST_SMI_ONLY_ELEMENTS, FAST_ELEMENTS, | 5439 // Generated code assumes that FAST_* and DICTIONARY_ELEMENTS ElementsKinds |
| 5408 // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS are handled before external | 5440 // are handled before external arrays. |
| 5409 // arrays. | 5441 STATIC_ASSERT(FAST_SMI_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
| 5410 STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | 5442 STATIC_ASSERT(FAST_HOLEY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
| 5411 STATIC_ASSERT(FAST_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | |
| 5412 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | 5443 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
| 5413 STATIC_ASSERT(DICTIONARY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | 5444 STATIC_ASSERT(DICTIONARY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
| 5414 | 5445 |
| 5415 for (ElementsKind elements_kind = FIRST_ELEMENTS_KIND; | 5446 for (ElementsKind elements_kind = FIRST_ELEMENTS_KIND; |
| 5416 elements_kind <= LAST_ELEMENTS_KIND; | 5447 elements_kind <= LAST_ELEMENTS_KIND; |
| 5417 elements_kind = ElementsKind(elements_kind + 1)) { | 5448 elements_kind = ElementsKind(elements_kind + 1)) { |
| 5418 // After having handled FAST_ELEMENTS, FAST_SMI_ONLY_ELEMENTS, | 5449 // After having handled FAST_* and DICTIONARY_ELEMENTS, we need to add some |
| 5419 // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS, we need to add some code | 5450 // code that's executed for all external array cases. |
| 5420 // that's executed for all external array cases. | |
| 5421 STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == | 5451 STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == |
| 5422 LAST_ELEMENTS_KIND); | 5452 LAST_ELEMENTS_KIND); |
| 5423 if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND | 5453 if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND |
| 5424 && todo_external_array) { | 5454 && todo_external_array) { |
| 5425 HInstruction* length = | 5455 HInstruction* length = |
| 5426 AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 5456 AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
| 5427 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 5457 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 5428 external_elements = new(zone()) HLoadExternalArrayPointer(elements); | 5458 external_elements = new(zone()) HLoadExternalArrayPointer(elements); |
| 5429 AddInstruction(external_elements); | 5459 AddInstruction(external_elements); |
| 5430 } | 5460 } |
| 5431 if (type_todo[elements_kind]) { | 5461 if (type_todo[elements_kind]) { |
| 5432 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 5462 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 5433 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 5463 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 5434 elements_kind_branch = new(zone()) HCompareConstantEqAndBranch( | 5464 elements_kind_branch = new(zone()) HCompareConstantEqAndBranch( |
| 5435 elements_kind_instr, elements_kind, Token::EQ_STRICT); | 5465 elements_kind_instr, elements_kind, Token::EQ_STRICT); |
| 5436 elements_kind_branch->SetSuccessorAt(0, if_true); | 5466 elements_kind_branch->SetSuccessorAt(0, if_true); |
| 5437 elements_kind_branch->SetSuccessorAt(1, if_false); | 5467 elements_kind_branch->SetSuccessorAt(1, if_false); |
| 5438 current_block()->Finish(elements_kind_branch); | 5468 current_block()->Finish(elements_kind_branch); |
| 5439 | 5469 |
| 5440 set_current_block(if_true); | 5470 set_current_block(if_true); |
| 5441 HInstruction* access; | 5471 HInstruction* access; |
| 5442 if (elements_kind == FAST_SMI_ONLY_ELEMENTS || | 5472 if (IsFastElementsKind(elements_kind)) { |
| 5443 elements_kind == FAST_ELEMENTS || | 5473 if (is_store && !IsFastDoubleElementsKind(elements_kind)) { |
| 5444 elements_kind == FAST_DOUBLE_ELEMENTS) { | |
| 5445 if (is_store && elements_kind != FAST_DOUBLE_ELEMENTS) { | |
| 5446 AddInstruction(new(zone()) HCheckMaps( | 5474 AddInstruction(new(zone()) HCheckMaps( |
| 5447 elements, isolate()->factory()->fixed_array_map(), | 5475 elements, isolate()->factory()->fixed_array_map(), |
| 5448 elements_kind_branch)); | 5476 elements_kind_branch)); |
| 5449 } | 5477 } |
| 5450 // TODO(jkummerow): The need for these two blocks could be avoided | 5478 // TODO(jkummerow): The need for these two blocks could be avoided |
| 5451 // in one of two ways: | 5479 // in one of two ways: |
| 5452 // (1) Introduce ElementsKinds for JSArrays that are distinct from | 5480 // (1) Introduce ElementsKinds for JSArrays that are distinct from |
| 5453 // those for fast objects. | 5481 // those for fast objects. |
| 5454 // (2) Put the common instructions into a third "join" block. This | 5482 // (2) Put the common instructions into a third "join" block. This |
| 5455 // requires additional AST IDs that we can deopt to from inside | 5483 // requires additional AST IDs that we can deopt to from inside |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5522 bool* has_side_effects) { | 5550 bool* has_side_effects) { |
| 5523 ASSERT(!expr->IsPropertyName()); | 5551 ASSERT(!expr->IsPropertyName()); |
| 5524 HInstruction* instr = NULL; | 5552 HInstruction* instr = NULL; |
| 5525 if (expr->IsMonomorphic()) { | 5553 if (expr->IsMonomorphic()) { |
| 5526 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 5554 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 5527 if (map->has_slow_elements_kind()) { | 5555 if (map->has_slow_elements_kind()) { |
| 5528 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) | 5556 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) |
| 5529 : BuildLoadKeyedGeneric(obj, key); | 5557 : BuildLoadKeyedGeneric(obj, key); |
| 5530 } else { | 5558 } else { |
| 5531 AddInstruction(new(zone()) HCheckNonSmi(obj)); | 5559 AddInstruction(new(zone()) HCheckNonSmi(obj)); |
| 5532 instr = BuildMonomorphicElementAccess(obj, key, val, map, is_store); | 5560 instr = BuildMonomorphicElementAccess(obj, key, val, NULL, map, is_store); |
| 5533 } | 5561 } |
| 5534 } else if (expr->GetReceiverTypes() != NULL && | 5562 } else if (expr->GetReceiverTypes() != NULL && |
| 5535 !expr->GetReceiverTypes()->is_empty()) { | 5563 !expr->GetReceiverTypes()->is_empty()) { |
| 5536 return HandlePolymorphicElementAccess( | 5564 return HandlePolymorphicElementAccess( |
| 5537 obj, key, val, expr, ast_id, position, is_store, has_side_effects); | 5565 obj, key, val, expr, ast_id, position, is_store, has_side_effects); |
| 5538 } else { | 5566 } else { |
| 5539 if (is_store) { | 5567 if (is_store) { |
| 5540 instr = BuildStoreKeyedGeneric(obj, key, val); | 5568 instr = BuildStoreKeyedGeneric(obj, key, val); |
| 5541 } else { | 5569 } else { |
| 5542 instr = BuildLoadKeyedGeneric(obj, key); | 5570 instr = BuildLoadKeyedGeneric(obj, key); |
| (...skipping 3394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8937 } | 8965 } |
| 8938 } | 8966 } |
| 8939 | 8967 |
| 8940 #ifdef DEBUG | 8968 #ifdef DEBUG |
| 8941 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 8969 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
| 8942 if (allocator_ != NULL) allocator_->Verify(); | 8970 if (allocator_ != NULL) allocator_->Verify(); |
| 8943 #endif | 8971 #endif |
| 8944 } | 8972 } |
| 8945 | 8973 |
| 8946 } } // namespace v8::internal | 8974 } } // namespace v8::internal |
| OLD | NEW |