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 an instruction that has a | 1712 // hoisting wouldn't move the transition past a DependsOn of one of it's |
1713 // DependsOn flag for anything it changes. | 1713 // changes or any instructions that might change an objects map or |
| 1714 // elements contents. |
| 1715 GVNFlagSet changes = instr->ChangesFlags(); |
1714 GVNFlagSet hoist_depends_blockers = | 1716 GVNFlagSet hoist_depends_blockers = |
1715 HValue::ConvertChangesToDependsFlags(instr->ChangesFlags()); | 1717 HValue::ConvertChangesToDependsFlags(changes); |
1716 | 1718 // In addition to not hoisting transitions above other instructions that |
1717 // In addition, the transition must not be hoisted above elements kind | 1719 // change dependencies that the transition changes, it must not be |
1718 // changes, or if the transition is destructive to the elements buffer, | 1720 // hoisted above map changes and stores to an elements backing store |
1719 // changes to array pointer or array contents. | 1721 // that the transition might change. |
1720 GVNFlagSet hoist_change_blockers; | 1722 GVNFlagSet hoist_change_blockers = changes; |
1721 hoist_change_blockers.Add(kChangesElementsKind); | 1723 hoist_change_blockers.Add(kChangesMaps); |
1722 HTransitionElementsKind* trans = HTransitionElementsKind::cast(instr); | 1724 HTransitionElementsKind* trans = HTransitionElementsKind::cast(instr); |
1723 if (trans->original_map()->has_fast_double_elements()) { | 1725 if (trans->original_map()->has_fast_double_elements()) { |
1724 hoist_change_blockers.Add(kChangesElementsPointer); | |
1725 hoist_change_blockers.Add(kChangesDoubleArrayElements); | 1726 hoist_change_blockers.Add(kChangesDoubleArrayElements); |
1726 } | 1727 } |
1727 if (trans->transitioned_map()->has_fast_double_elements()) { | 1728 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 OMIT_HOLE_CHECK)); | 3969 HLoadKeyedFastElement::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->HasFastObjectElements()) { | 4260 } else if (boilerplate->HasFastElements()) { |
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_ELEMENTS: | 4467 case FAST_SMI_ONLY_ELEMENTS: |
4468 case FAST_HOLEY_SMI_ELEMENTS: | |
4469 // Smi-only arrays need a smi check. | 4468 // Smi-only arrays need a smi check. |
4470 AddInstruction(new(zone()) HCheckSmi(value)); | 4469 AddInstruction(new(zone()) HCheckSmi(value)); |
4471 // Fall through. | 4470 // Fall through. |
4472 case FAST_ELEMENTS: | 4471 case FAST_ELEMENTS: |
4473 case FAST_HOLEY_ELEMENTS: | |
4474 AddInstruction(new(zone()) HStoreKeyedFastElement( | 4472 AddInstruction(new(zone()) HStoreKeyedFastElement( |
4475 elements, | 4473 elements, |
4476 key, | 4474 key, |
4477 value, | 4475 value, |
4478 boilerplate_elements_kind)); | 4476 boilerplate_elements_kind)); |
4479 break; | 4477 break; |
4480 case FAST_DOUBLE_ELEMENTS: | 4478 case FAST_DOUBLE_ELEMENTS: |
4481 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
4482 AddInstruction(new(zone()) HStoreKeyedFastDoubleElement(elements, | 4479 AddInstruction(new(zone()) HStoreKeyedFastDoubleElement(elements, |
4483 key, | 4480 key, |
4484 value)); | 4481 value)); |
4485 break; | 4482 break; |
4486 default: | 4483 default: |
4487 UNREACHABLE(); | 4484 UNREACHABLE(); |
4488 break; | 4485 break; |
4489 } | 4486 } |
4490 | 4487 |
4491 AddSimulate(expr->GetIdForElement(i)); | 4488 AddSimulate(expr->GetIdForElement(i)); |
(...skipping 737 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5229 val, | 5226 val, |
5230 Representation::Integer32(), | 5227 Representation::Integer32(), |
5231 true, // Truncate to int32. | 5228 true, // Truncate to int32. |
5232 false)); // Don't deoptimize undefined (irrelevant here). | 5229 false)); // Don't deoptimize undefined (irrelevant here). |
5233 } | 5230 } |
5234 break; | 5231 break; |
5235 } | 5232 } |
5236 case EXTERNAL_FLOAT_ELEMENTS: | 5233 case EXTERNAL_FLOAT_ELEMENTS: |
5237 case EXTERNAL_DOUBLE_ELEMENTS: | 5234 case EXTERNAL_DOUBLE_ELEMENTS: |
5238 break; | 5235 break; |
5239 case FAST_SMI_ELEMENTS: | 5236 case FAST_SMI_ONLY_ELEMENTS: |
5240 case FAST_ELEMENTS: | 5237 case FAST_ELEMENTS: |
5241 case FAST_DOUBLE_ELEMENTS: | 5238 case FAST_DOUBLE_ELEMENTS: |
5242 case FAST_HOLEY_SMI_ELEMENTS: | |
5243 case FAST_HOLEY_ELEMENTS: | |
5244 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
5245 case DICTIONARY_ELEMENTS: | 5239 case DICTIONARY_ELEMENTS: |
5246 case NON_STRICT_ARGUMENTS_ELEMENTS: | 5240 case NON_STRICT_ARGUMENTS_ELEMENTS: |
5247 UNREACHABLE(); | 5241 UNREACHABLE(); |
5248 break; | 5242 break; |
5249 } | 5243 } |
5250 return new(zone()) HStoreKeyedSpecializedArrayElement( | 5244 return new(zone()) HStoreKeyedSpecializedArrayElement( |
5251 external_elements, checked_key, val, elements_kind); | 5245 external_elements, checked_key, val, elements_kind); |
5252 } else { | 5246 } else { |
5253 ASSERT(val == NULL); | 5247 ASSERT(val == NULL); |
5254 return new(zone()) HLoadKeyedSpecializedArrayElement( | 5248 return new(zone()) HLoadKeyedSpecializedArrayElement( |
5255 external_elements, checked_key, elements_kind); | 5249 external_elements, checked_key, elements_kind); |
5256 } | 5250 } |
5257 } | 5251 } |
5258 | 5252 |
5259 | 5253 |
5260 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, | 5254 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, |
5261 HValue* checked_key, | 5255 HValue* checked_key, |
5262 HValue* val, | 5256 HValue* val, |
5263 ElementsKind elements_kind, | 5257 ElementsKind elements_kind, |
5264 bool is_store) { | 5258 bool is_store) { |
5265 if (is_store) { | 5259 if (is_store) { |
5266 ASSERT(val != NULL); | 5260 ASSERT(val != NULL); |
5267 switch (elements_kind) { | 5261 switch (elements_kind) { |
5268 case FAST_DOUBLE_ELEMENTS: | 5262 case FAST_DOUBLE_ELEMENTS: |
5269 case FAST_HOLEY_DOUBLE_ELEMENTS: | |
5270 return new(zone()) HStoreKeyedFastDoubleElement( | 5263 return new(zone()) HStoreKeyedFastDoubleElement( |
5271 elements, checked_key, val); | 5264 elements, checked_key, val); |
5272 case FAST_SMI_ELEMENTS: | 5265 case FAST_SMI_ONLY_ELEMENTS: |
5273 case FAST_HOLEY_SMI_ELEMENTS: | |
5274 // Smi-only arrays need a smi check. | 5266 // Smi-only arrays need a smi check. |
5275 AddInstruction(new(zone()) HCheckSmi(val)); | 5267 AddInstruction(new(zone()) HCheckSmi(val)); |
5276 // Fall through. | 5268 // Fall through. |
5277 case FAST_ELEMENTS: | 5269 case FAST_ELEMENTS: |
5278 case FAST_HOLEY_ELEMENTS: | |
5279 return new(zone()) HStoreKeyedFastElement( | 5270 return new(zone()) HStoreKeyedFastElement( |
5280 elements, checked_key, val, elements_kind); | 5271 elements, checked_key, val, elements_kind); |
5281 default: | 5272 default: |
5282 UNREACHABLE(); | 5273 UNREACHABLE(); |
5283 return NULL; | 5274 return NULL; |
5284 } | 5275 } |
5285 } | 5276 } |
5286 // It's an element load (!is_store). | 5277 // It's an element load (!is_store). |
5287 HoleCheckMode mode = IsFastPackedElementsKind(elements_kind) ? | 5278 if (elements_kind == FAST_DOUBLE_ELEMENTS) { |
5288 OMIT_HOLE_CHECK : | 5279 return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key); |
5289 PERFORM_HOLE_CHECK; | 5280 } else { // FAST_ELEMENTS or FAST_SMI_ONLY_ELEMENTS. |
5290 if (IsFastDoubleElementsKind(elements_kind)) { | 5281 return new(zone()) HLoadKeyedFastElement(elements, checked_key); |
5291 return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key, mode); | |
5292 } else { // Smi or Object elements. | |
5293 return new(zone()) HLoadKeyedFastElement(elements, checked_key, mode); | |
5294 } | 5282 } |
5295 } | 5283 } |
5296 | 5284 |
5297 | 5285 |
5298 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, | 5286 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, |
5299 HValue* key, | 5287 HValue* key, |
5300 HValue* val, | 5288 HValue* val, |
5301 HValue* dependency, | |
5302 Handle<Map> map, | 5289 Handle<Map> map, |
5303 bool is_store) { | 5290 bool is_store) { |
5304 HInstruction* mapcheck = | 5291 HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMaps(object, map)); |
5305 AddInstruction(new(zone()) HCheckMaps(object, map, dependency)); | 5292 bool fast_smi_only_elements = map->has_fast_smi_only_elements(); |
5306 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency | 5293 bool fast_elements = map->has_fast_elements(); |
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(); | |
5319 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); | 5294 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); |
5320 if (is_store && (fast_elements || fast_smi_only_elements)) { | 5295 if (is_store && (fast_elements || fast_smi_only_elements)) { |
5321 HCheckMaps* check_cow_map = new(zone()) HCheckMaps( | 5296 AddInstruction(new(zone()) HCheckMaps( |
5322 elements, isolate()->factory()->fixed_array_map()); | 5297 elements, isolate()->factory()->fixed_array_map())); |
5323 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); | |
5324 AddInstruction(check_cow_map); | |
5325 } | 5298 } |
5326 HInstruction* length = NULL; | 5299 HInstruction* length = NULL; |
5327 HInstruction* checked_key = NULL; | 5300 HInstruction* checked_key = NULL; |
5328 if (map->has_external_array_elements()) { | 5301 if (map->has_external_array_elements()) { |
5329 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 5302 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
5330 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 5303 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
5331 HLoadExternalArrayPointer* external_elements = | 5304 HLoadExternalArrayPointer* external_elements = |
5332 new(zone()) HLoadExternalArrayPointer(elements); | 5305 new(zone()) HLoadExternalArrayPointer(elements); |
5333 AddInstruction(external_elements); | 5306 AddInstruction(external_elements); |
5334 return BuildExternalArrayElementAccess(external_elements, checked_key, | 5307 return BuildExternalArrayElementAccess(external_elements, checked_key, |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5367 type_todo[i] = false; | 5340 type_todo[i] = false; |
5368 } | 5341 } |
5369 | 5342 |
5370 // Elements_kind transition support. | 5343 // Elements_kind transition support. |
5371 MapHandleList transition_target(maps->length()); | 5344 MapHandleList transition_target(maps->length()); |
5372 // Collect possible transition targets. | 5345 // Collect possible transition targets. |
5373 MapHandleList possible_transitioned_maps(maps->length()); | 5346 MapHandleList possible_transitioned_maps(maps->length()); |
5374 for (int i = 0; i < maps->length(); ++i) { | 5347 for (int i = 0; i < maps->length(); ++i) { |
5375 Handle<Map> map = maps->at(i); | 5348 Handle<Map> map = maps->at(i); |
5376 ElementsKind elements_kind = map->elements_kind(); | 5349 ElementsKind elements_kind = map->elements_kind(); |
5377 if (IsFastElementsKind(elements_kind) && | 5350 if (elements_kind == FAST_DOUBLE_ELEMENTS || |
5378 elements_kind != GetInitialFastElementsKind()) { | 5351 elements_kind == FAST_ELEMENTS) { |
5379 possible_transitioned_maps.Add(map); | 5352 possible_transitioned_maps.Add(map); |
5380 } | 5353 } |
5381 } | 5354 } |
5382 // Get transition target for each map (NULL == no transition). | 5355 // Get transition target for each map (NULL == no transition). |
5383 for (int i = 0; i < maps->length(); ++i) { | 5356 for (int i = 0; i < maps->length(); ++i) { |
5384 Handle<Map> map = maps->at(i); | 5357 Handle<Map> map = maps->at(i); |
5385 Handle<Map> transitioned_map = | 5358 Handle<Map> transitioned_map = |
5386 map->FindTransitionedMap(&possible_transitioned_maps); | 5359 map->FindTransitionedMap(&possible_transitioned_maps); |
5387 transition_target.Add(transitioned_map); | 5360 transition_target.Add(transitioned_map); |
5388 } | 5361 } |
5389 | 5362 |
5390 int num_untransitionable_maps = 0; | 5363 int num_untransitionable_maps = 0; |
5391 Handle<Map> untransitionable_map; | 5364 Handle<Map> untransitionable_map; |
5392 HTransitionElementsKind* transition = NULL; | |
5393 for (int i = 0; i < maps->length(); ++i) { | 5365 for (int i = 0; i < maps->length(); ++i) { |
5394 Handle<Map> map = maps->at(i); | 5366 Handle<Map> map = maps->at(i); |
5395 ASSERT(map->IsMap()); | 5367 ASSERT(map->IsMap()); |
5396 if (!transition_target.at(i).is_null()) { | 5368 if (!transition_target.at(i).is_null()) { |
5397 ASSERT(Map::IsValidElementsTransition( | 5369 AddInstruction(new(zone()) HTransitionElementsKind( |
5398 map->elements_kind(), | 5370 object, map, transition_target.at(i))); |
5399 transition_target.at(i)->elements_kind())); | |
5400 transition = new(zone()) HTransitionElementsKind( | |
5401 object, map, transition_target.at(i)); | |
5402 AddInstruction(transition); | |
5403 } else { | 5371 } else { |
5404 type_todo[map->elements_kind()] = true; | 5372 type_todo[map->elements_kind()] = true; |
5405 if (map->elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) { | 5373 if (map->elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) { |
5406 todo_external_array = true; | 5374 todo_external_array = true; |
5407 } | 5375 } |
5408 num_untransitionable_maps++; | 5376 num_untransitionable_maps++; |
5409 untransitionable_map = map; | 5377 untransitionable_map = map; |
5410 } | 5378 } |
5411 } | 5379 } |
5412 | 5380 |
5413 // If only one map is left after transitioning, handle this case | 5381 // If only one map is left after transitioning, handle this case |
5414 // monomorphically. | 5382 // monomorphically. |
5415 if (num_untransitionable_maps == 1) { | 5383 if (num_untransitionable_maps == 1) { |
5416 HInstruction* instr = NULL; | 5384 HInstruction* instr = NULL; |
5417 if (untransitionable_map->has_slow_elements_kind()) { | 5385 if (untransitionable_map->has_slow_elements_kind()) { |
5418 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) | 5386 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) |
5419 : BuildLoadKeyedGeneric(object, key)); | 5387 : BuildLoadKeyedGeneric(object, key)); |
5420 } else { | 5388 } else { |
5421 instr = AddInstruction(BuildMonomorphicElementAccess( | 5389 instr = AddInstruction(BuildMonomorphicElementAccess( |
5422 object, key, val, transition, untransitionable_map, is_store)); | 5390 object, key, val, untransitionable_map, is_store)); |
5423 } | 5391 } |
5424 *has_side_effects |= instr->HasObservableSideEffects(); | 5392 *has_side_effects |= instr->HasObservableSideEffects(); |
5425 instr->set_position(position); | 5393 instr->set_position(position); |
5426 return is_store ? NULL : instr; | 5394 return is_store ? NULL : instr; |
5427 } | 5395 } |
5428 | 5396 |
5429 AddInstruction(HCheckInstanceType::NewIsSpecObject(object)); | 5397 AddInstruction(HCheckInstanceType::NewIsSpecObject(object)); |
5430 HBasicBlock* join = graph()->CreateBasicBlock(); | 5398 HBasicBlock* join = graph()->CreateBasicBlock(); |
5431 | 5399 |
5432 HInstruction* elements_kind_instr = | 5400 HInstruction* elements_kind_instr = |
5433 AddInstruction(new(zone()) HElementsKind(object)); | 5401 AddInstruction(new(zone()) HElementsKind(object)); |
5434 HCompareConstantEqAndBranch* elements_kind_branch = NULL; | 5402 HCompareConstantEqAndBranch* elements_kind_branch = NULL; |
5435 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); | 5403 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); |
5436 HLoadExternalArrayPointer* external_elements = NULL; | 5404 HLoadExternalArrayPointer* external_elements = NULL; |
5437 HInstruction* checked_key = NULL; | 5405 HInstruction* checked_key = NULL; |
5438 | 5406 |
5439 // Generated code assumes that FAST_* and DICTIONARY_ELEMENTS ElementsKinds | 5407 // Generated code assumes that FAST_SMI_ONLY_ELEMENTS, FAST_ELEMENTS, |
5440 // are handled before external arrays. | 5408 // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS are handled before external |
5441 STATIC_ASSERT(FAST_SMI_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | 5409 // arrays. |
5442 STATIC_ASSERT(FAST_HOLEY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | 5410 STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
| 5411 STATIC_ASSERT(FAST_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
5443 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | 5412 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
5444 STATIC_ASSERT(DICTIONARY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | 5413 STATIC_ASSERT(DICTIONARY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
5445 | 5414 |
5446 for (ElementsKind elements_kind = FIRST_ELEMENTS_KIND; | 5415 for (ElementsKind elements_kind = FIRST_ELEMENTS_KIND; |
5447 elements_kind <= LAST_ELEMENTS_KIND; | 5416 elements_kind <= LAST_ELEMENTS_KIND; |
5448 elements_kind = ElementsKind(elements_kind + 1)) { | 5417 elements_kind = ElementsKind(elements_kind + 1)) { |
5449 // After having handled FAST_* and DICTIONARY_ELEMENTS, we need to add some | 5418 // After having handled FAST_ELEMENTS, FAST_SMI_ONLY_ELEMENTS, |
5450 // code that's executed for all external array cases. | 5419 // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS, we need to add some code |
| 5420 // that's executed for all external array cases. |
5451 STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == | 5421 STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == |
5452 LAST_ELEMENTS_KIND); | 5422 LAST_ELEMENTS_KIND); |
5453 if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND | 5423 if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND |
5454 && todo_external_array) { | 5424 && todo_external_array) { |
5455 HInstruction* length = | 5425 HInstruction* length = |
5456 AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 5426 AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
5457 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 5427 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
5458 external_elements = new(zone()) HLoadExternalArrayPointer(elements); | 5428 external_elements = new(zone()) HLoadExternalArrayPointer(elements); |
5459 AddInstruction(external_elements); | 5429 AddInstruction(external_elements); |
5460 } | 5430 } |
5461 if (type_todo[elements_kind]) { | 5431 if (type_todo[elements_kind]) { |
5462 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 5432 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
5463 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 5433 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
5464 elements_kind_branch = new(zone()) HCompareConstantEqAndBranch( | 5434 elements_kind_branch = new(zone()) HCompareConstantEqAndBranch( |
5465 elements_kind_instr, elements_kind, Token::EQ_STRICT); | 5435 elements_kind_instr, elements_kind, Token::EQ_STRICT); |
5466 elements_kind_branch->SetSuccessorAt(0, if_true); | 5436 elements_kind_branch->SetSuccessorAt(0, if_true); |
5467 elements_kind_branch->SetSuccessorAt(1, if_false); | 5437 elements_kind_branch->SetSuccessorAt(1, if_false); |
5468 current_block()->Finish(elements_kind_branch); | 5438 current_block()->Finish(elements_kind_branch); |
5469 | 5439 |
5470 set_current_block(if_true); | 5440 set_current_block(if_true); |
5471 HInstruction* access; | 5441 HInstruction* access; |
5472 if (IsFastElementsKind(elements_kind)) { | 5442 if (elements_kind == FAST_SMI_ONLY_ELEMENTS || |
5473 if (is_store && !IsFastDoubleElementsKind(elements_kind)) { | 5443 elements_kind == FAST_ELEMENTS || |
| 5444 elements_kind == FAST_DOUBLE_ELEMENTS) { |
| 5445 if (is_store && elements_kind != FAST_DOUBLE_ELEMENTS) { |
5474 AddInstruction(new(zone()) HCheckMaps( | 5446 AddInstruction(new(zone()) HCheckMaps( |
5475 elements, isolate()->factory()->fixed_array_map(), | 5447 elements, isolate()->factory()->fixed_array_map(), |
5476 elements_kind_branch)); | 5448 elements_kind_branch)); |
5477 } | 5449 } |
5478 // TODO(jkummerow): The need for these two blocks could be avoided | 5450 // TODO(jkummerow): The need for these two blocks could be avoided |
5479 // in one of two ways: | 5451 // in one of two ways: |
5480 // (1) Introduce ElementsKinds for JSArrays that are distinct from | 5452 // (1) Introduce ElementsKinds for JSArrays that are distinct from |
5481 // those for fast objects. | 5453 // those for fast objects. |
5482 // (2) Put the common instructions into a third "join" block. This | 5454 // (2) Put the common instructions into a third "join" block. This |
5483 // requires additional AST IDs that we can deopt to from inside | 5455 // requires additional AST IDs that we can deopt to from inside |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5550 bool* has_side_effects) { | 5522 bool* has_side_effects) { |
5551 ASSERT(!expr->IsPropertyName()); | 5523 ASSERT(!expr->IsPropertyName()); |
5552 HInstruction* instr = NULL; | 5524 HInstruction* instr = NULL; |
5553 if (expr->IsMonomorphic()) { | 5525 if (expr->IsMonomorphic()) { |
5554 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 5526 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
5555 if (map->has_slow_elements_kind()) { | 5527 if (map->has_slow_elements_kind()) { |
5556 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) | 5528 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) |
5557 : BuildLoadKeyedGeneric(obj, key); | 5529 : BuildLoadKeyedGeneric(obj, key); |
5558 } else { | 5530 } else { |
5559 AddInstruction(new(zone()) HCheckNonSmi(obj)); | 5531 AddInstruction(new(zone()) HCheckNonSmi(obj)); |
5560 instr = BuildMonomorphicElementAccess(obj, key, val, NULL, map, is_store); | 5532 instr = BuildMonomorphicElementAccess(obj, key, val, map, is_store); |
5561 } | 5533 } |
5562 } else if (expr->GetReceiverTypes() != NULL && | 5534 } else if (expr->GetReceiverTypes() != NULL && |
5563 !expr->GetReceiverTypes()->is_empty()) { | 5535 !expr->GetReceiverTypes()->is_empty()) { |
5564 return HandlePolymorphicElementAccess( | 5536 return HandlePolymorphicElementAccess( |
5565 obj, key, val, expr, ast_id, position, is_store, has_side_effects); | 5537 obj, key, val, expr, ast_id, position, is_store, has_side_effects); |
5566 } else { | 5538 } else { |
5567 if (is_store) { | 5539 if (is_store) { |
5568 instr = BuildStoreKeyedGeneric(obj, key, val); | 5540 instr = BuildStoreKeyedGeneric(obj, key, val); |
5569 } else { | 5541 } else { |
5570 instr = BuildLoadKeyedGeneric(obj, key); | 5542 instr = BuildLoadKeyedGeneric(obj, key); |
(...skipping 3394 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
8965 } | 8937 } |
8966 } | 8938 } |
8967 | 8939 |
8968 #ifdef DEBUG | 8940 #ifdef DEBUG |
8969 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 8941 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
8970 if (allocator_ != NULL) allocator_->Verify(); | 8942 if (allocator_ != NULL) allocator_->Verify(); |
8971 #endif | 8943 #endif |
8972 } | 8944 } |
8973 | 8945 |
8974 } } // namespace v8::internal | 8946 } } // namespace v8::internal |
OLD | NEW |