| 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 1666 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1677 bool hoisted = false; | 1677 bool hoisted = false; |
| 1678 if (instr->CheckFlag(HValue::kUseGVN)) { | 1678 if (instr->CheckFlag(HValue::kUseGVN)) { |
| 1679 TraceGVN("Checking instruction %d (%s) %s. Loop %s\n", | 1679 TraceGVN("Checking instruction %d (%s) %s. Loop %s\n", |
| 1680 instr->id(), | 1680 instr->id(), |
| 1681 instr->Mnemonic(), | 1681 instr->Mnemonic(), |
| 1682 *GetGVNFlagsString(instr->gvn_flags()), | 1682 *GetGVNFlagsString(instr->gvn_flags()), |
| 1683 *GetGVNFlagsString(loop_kills)); | 1683 *GetGVNFlagsString(loop_kills)); |
| 1684 bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags); | 1684 bool can_hoist = !instr->gvn_flags().ContainsAnyOf(depends_flags); |
| 1685 if (instr->IsTransitionElementsKind()) { | 1685 if (instr->IsTransitionElementsKind()) { |
| 1686 // It's possible to hoist transitions out of a loop as long as the | 1686 // It's possible to hoist transitions out of a loop as long as the |
| 1687 // hoisting wouldn't move the transition past a DependsOn of one of it's | 1687 // hoisting wouldn't move the transition past a DependsOn on anything it |
| 1688 // changes or any instructions that might change an objects map or | 1688 // changes. |
| 1689 // elements contents. | |
| 1690 GVNFlagSet changes = instr->ChangesFlags(); | |
| 1691 GVNFlagSet hoist_depends_blockers = | 1689 GVNFlagSet hoist_depends_blockers = |
| 1692 HValue::ConvertChangesToDependsFlags(changes); | 1690 HValue::ConvertChangesToDependsFlags(instr->ChangesFlags()); |
| 1691 |
| 1693 // In addition to not hoisting transitions above other instructions that | 1692 // In addition to not hoisting transitions above other instructions that |
| 1694 // change dependencies that the transition changes, it must not be | 1693 // change dependencies that the transition changes, it must not be |
| 1695 // hoisted above map changes and stores to an elements backing store | 1694 // hoisted above element pointer changes, elements kind changes, or |
| 1696 // that the transition might change. | 1695 // changes to array contents that need to be made before the transition |
| 1697 GVNFlagSet hoist_change_blockers = changes; | 1696 // converts the elements buffer. |
| 1698 hoist_change_blockers.Add(kChangesMaps); | 1697 GVNFlagSet hoist_change_blockers; |
| 1698 hoist_change_blockers.Add(kChangesElementsKind); |
| 1699 HTransitionElementsKind* trans = HTransitionElementsKind::cast(instr); | 1699 HTransitionElementsKind* trans = HTransitionElementsKind::cast(instr); |
| 1700 if (trans->original_map()->has_fast_double_elements()) { | 1700 if (trans->original_map()->has_fast_double_elements()) { |
| 1701 hoist_change_blockers.Add(kChangesElementsPointer); |
| 1701 hoist_change_blockers.Add(kChangesDoubleArrayElements); | 1702 hoist_change_blockers.Add(kChangesDoubleArrayElements); |
| 1702 } | 1703 } |
| 1703 if (trans->transitioned_map()->has_fast_double_elements()) { | 1704 if (trans->transitioned_map()->has_fast_double_elements()) { |
| 1705 hoist_change_blockers.Add(kChangesElementsPointer); |
| 1704 hoist_change_blockers.Add(kChangesArrayElements); | 1706 hoist_change_blockers.Add(kChangesArrayElements); |
| 1705 } | 1707 } |
| 1706 TraceGVN("Checking dependencies on HTransitionElementsKind %d (%s) " | 1708 TraceGVN("Checking dependencies on HTransitionElementsKind %d (%s) " |
| 1707 "hoist blockers: %s %s; " | 1709 "hoist blockers: %s %s; " |
| 1708 "first-time accumulated: %s %s\n", | 1710 "first-time accumulated: %s %s\n", |
| 1709 instr->id(), | 1711 instr->id(), |
| 1710 instr->Mnemonic(), | 1712 instr->Mnemonic(), |
| 1711 *GetGVNFlagsString(hoist_depends_blockers), | 1713 *GetGVNFlagsString(hoist_depends_blockers), |
| 1712 *GetGVNFlagsString(hoist_change_blockers), | 1714 *GetGVNFlagsString(hoist_change_blockers), |
| 1713 *GetGVNFlagsString(*first_time_depends), | 1715 *GetGVNFlagsString(*first_time_depends), |
| 1714 *GetGVNFlagsString(*first_time_changes)); | 1716 *GetGVNFlagsString(*first_time_changes)); |
| 1717 |
| 1715 // It's possible to hoist transition from the current loop loop only if | 1718 // It's possible to hoist transition from the current loop loop only if |
| 1716 // they dominate all of the successor blocks in the same loop and there | 1719 // they dominate all of the successor blocks in the same loop and there |
| 1717 // are not any instructions that have Changes/DependsOn that intervene | 1720 // are not any instructions that have Changes/DependsOn that intervene |
| 1718 // between it and the beginning of the loop header. | 1721 // between it and the beginning of the loop header. |
| 1719 bool in_nested_loop = block != loop_header && | 1722 bool in_nested_loop = block != loop_header && |
| 1720 ((block->parent_loop_header() != loop_header) || | 1723 ((block->parent_loop_header() != loop_header) || |
| 1721 block->IsLoopHeader()); | 1724 block->IsLoopHeader()); |
| 1722 can_hoist = !in_nested_loop && | 1725 can_hoist = !in_nested_loop && |
| 1723 block->IsLoopSuccessorDominator() && | 1726 block->IsLoopSuccessorDominator() && |
| 1724 !first_time_depends->ContainsAnyOf(hoist_depends_blockers) && | 1727 !first_time_depends->ContainsAnyOf(hoist_depends_blockers) && |
| (...skipping 1820 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3545 | 3548 |
| 3546 set_current_block(loop_successor); | 3549 set_current_block(loop_successor); |
| 3547 Drop(5); | 3550 Drop(5); |
| 3548 | 3551 |
| 3549 set_current_block(loop_body); | 3552 set_current_block(loop_body); |
| 3550 | 3553 |
| 3551 HValue* key = AddInstruction( | 3554 HValue* key = AddInstruction( |
| 3552 new(zone()) HLoadKeyedFastElement( | 3555 new(zone()) HLoadKeyedFastElement( |
| 3553 environment()->ExpressionStackAt(2), // Enum cache. | 3556 environment()->ExpressionStackAt(2), // Enum cache. |
| 3554 environment()->ExpressionStackAt(0), // Iteration index. | 3557 environment()->ExpressionStackAt(0), // Iteration index. |
| 3555 HLoadKeyedFastElement::OMIT_HOLE_CHECK)); | 3558 OMIT_HOLE_CHECK)); |
| 3556 | 3559 |
| 3557 // Check if the expected map still matches that of the enumerable. | 3560 // Check if the expected map still matches that of the enumerable. |
| 3558 // If not just deoptimize. | 3561 // If not just deoptimize. |
| 3559 AddInstruction(new(zone()) HCheckMapValue( | 3562 AddInstruction(new(zone()) HCheckMapValue( |
| 3560 environment()->ExpressionStackAt(4), | 3563 environment()->ExpressionStackAt(4), |
| 3561 environment()->ExpressionStackAt(3))); | 3564 environment()->ExpressionStackAt(3))); |
| 3562 | 3565 |
| 3563 Bind(each_var, key); | 3566 Bind(each_var, key); |
| 3564 | 3567 |
| 3565 BreakAndContinueInfo break_info(stmt, 5); | 3568 BreakAndContinueInfo break_info(stmt, 5); |
| (...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3836 int* max_properties, | 3839 int* max_properties, |
| 3837 int* total_size) { | 3840 int* total_size) { |
| 3838 ASSERT(max_depth >= 0 && *max_properties >= 0); | 3841 ASSERT(max_depth >= 0 && *max_properties >= 0); |
| 3839 if (max_depth == 0) return false; | 3842 if (max_depth == 0) return false; |
| 3840 | 3843 |
| 3841 Handle<FixedArrayBase> elements(boilerplate->elements()); | 3844 Handle<FixedArrayBase> elements(boilerplate->elements()); |
| 3842 if (elements->length() > 0 && | 3845 if (elements->length() > 0 && |
| 3843 elements->map() != boilerplate->GetHeap()->fixed_cow_array_map()) { | 3846 elements->map() != boilerplate->GetHeap()->fixed_cow_array_map()) { |
| 3844 if (boilerplate->HasFastDoubleElements()) { | 3847 if (boilerplate->HasFastDoubleElements()) { |
| 3845 *total_size += FixedDoubleArray::SizeFor(elements->length()); | 3848 *total_size += FixedDoubleArray::SizeFor(elements->length()); |
| 3846 } else if (boilerplate->HasFastElements()) { | 3849 } else if (boilerplate->HasFastObjectElements()) { |
| 3847 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); | 3850 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); |
| 3848 int length = elements->length(); | 3851 int length = elements->length(); |
| 3849 for (int i = 0; i < length; i++) { | 3852 for (int i = 0; i < length; i++) { |
| 3850 if ((*max_properties)-- == 0) return false; | 3853 if ((*max_properties)-- == 0) return false; |
| 3851 Handle<Object> value(fast_elements->get(i)); | 3854 Handle<Object> value(fast_elements->get(i)); |
| 3852 if (value->IsJSObject()) { | 3855 if (value->IsJSObject()) { |
| 3853 Handle<JSObject> value_object = Handle<JSObject>::cast(value); | 3856 Handle<JSObject> value_object = Handle<JSObject>::cast(value); |
| 3854 if (!IsFastLiteral(value_object, | 3857 if (!IsFastLiteral(value_object, |
| 3855 max_depth - 1, | 3858 max_depth - 1, |
| 3856 max_properties, | 3859 max_properties, |
| (...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4043 if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal"); | 4046 if (!Smi::IsValid(i)) return Bailout("Non-smi key in array literal"); |
| 4044 | 4047 |
| 4045 elements = new(zone()) HLoadElements(literal); | 4048 elements = new(zone()) HLoadElements(literal); |
| 4046 AddInstruction(elements); | 4049 AddInstruction(elements); |
| 4047 | 4050 |
| 4048 HValue* key = AddInstruction( | 4051 HValue* key = AddInstruction( |
| 4049 new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), | 4052 new(zone()) HConstant(Handle<Object>(Smi::FromInt(i)), |
| 4050 Representation::Integer32())); | 4053 Representation::Integer32())); |
| 4051 | 4054 |
| 4052 switch (boilerplate_elements_kind) { | 4055 switch (boilerplate_elements_kind) { |
| 4053 case FAST_SMI_ONLY_ELEMENTS: | 4056 case FAST_SMI_ELEMENTS: |
| 4057 case FAST_HOLEY_SMI_ELEMENTS: |
| 4054 // Smi-only arrays need a smi check. | 4058 // Smi-only arrays need a smi check. |
| 4055 AddInstruction(new(zone()) HCheckSmi(value)); | 4059 AddInstruction(new(zone()) HCheckSmi(value)); |
| 4056 // Fall through. | 4060 // Fall through. |
| 4057 case FAST_ELEMENTS: | 4061 case FAST_ELEMENTS: |
| 4062 case FAST_HOLEY_ELEMENTS: |
| 4058 AddInstruction(new(zone()) HStoreKeyedFastElement( | 4063 AddInstruction(new(zone()) HStoreKeyedFastElement( |
| 4059 elements, | 4064 elements, |
| 4060 key, | 4065 key, |
| 4061 value, | 4066 value, |
| 4062 boilerplate_elements_kind)); | 4067 boilerplate_elements_kind)); |
| 4063 break; | 4068 break; |
| 4064 case FAST_DOUBLE_ELEMENTS: | 4069 case FAST_DOUBLE_ELEMENTS: |
| 4070 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 4065 AddInstruction(new(zone()) HStoreKeyedFastDoubleElement(elements, | 4071 AddInstruction(new(zone()) HStoreKeyedFastDoubleElement(elements, |
| 4066 key, | 4072 key, |
| 4067 value)); | 4073 value)); |
| 4068 break; | 4074 break; |
| 4069 default: | 4075 default: |
| 4070 UNREACHABLE(); | 4076 UNREACHABLE(); |
| 4071 break; | 4077 break; |
| 4072 } | 4078 } |
| 4073 | 4079 |
| 4074 AddSimulate(expr->GetIdForElement(i)); | 4080 AddSimulate(expr->GetIdForElement(i)); |
| (...skipping 737 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4812 val, | 4818 val, |
| 4813 Representation::Integer32(), | 4819 Representation::Integer32(), |
| 4814 true, // Truncate to int32. | 4820 true, // Truncate to int32. |
| 4815 false)); // Don't deoptimize undefined (irrelevant here). | 4821 false)); // Don't deoptimize undefined (irrelevant here). |
| 4816 } | 4822 } |
| 4817 break; | 4823 break; |
| 4818 } | 4824 } |
| 4819 case EXTERNAL_FLOAT_ELEMENTS: | 4825 case EXTERNAL_FLOAT_ELEMENTS: |
| 4820 case EXTERNAL_DOUBLE_ELEMENTS: | 4826 case EXTERNAL_DOUBLE_ELEMENTS: |
| 4821 break; | 4827 break; |
| 4822 case FAST_SMI_ONLY_ELEMENTS: | 4828 case FAST_SMI_ELEMENTS: |
| 4823 case FAST_ELEMENTS: | 4829 case FAST_ELEMENTS: |
| 4824 case FAST_DOUBLE_ELEMENTS: | 4830 case FAST_DOUBLE_ELEMENTS: |
| 4831 case FAST_HOLEY_SMI_ELEMENTS: |
| 4832 case FAST_HOLEY_ELEMENTS: |
| 4833 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 4825 case DICTIONARY_ELEMENTS: | 4834 case DICTIONARY_ELEMENTS: |
| 4826 case NON_STRICT_ARGUMENTS_ELEMENTS: | 4835 case NON_STRICT_ARGUMENTS_ELEMENTS: |
| 4827 UNREACHABLE(); | 4836 UNREACHABLE(); |
| 4828 break; | 4837 break; |
| 4829 } | 4838 } |
| 4830 return new(zone()) HStoreKeyedSpecializedArrayElement( | 4839 return new(zone()) HStoreKeyedSpecializedArrayElement( |
| 4831 external_elements, checked_key, val, elements_kind); | 4840 external_elements, checked_key, val, elements_kind); |
| 4832 } else { | 4841 } else { |
| 4833 ASSERT(val == NULL); | 4842 ASSERT(val == NULL); |
| 4834 return new(zone()) HLoadKeyedSpecializedArrayElement( | 4843 return new(zone()) HLoadKeyedSpecializedArrayElement( |
| 4835 external_elements, checked_key, elements_kind); | 4844 external_elements, checked_key, elements_kind); |
| 4836 } | 4845 } |
| 4837 } | 4846 } |
| 4838 | 4847 |
| 4839 | 4848 |
| 4840 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, | 4849 HInstruction* HGraphBuilder::BuildFastElementAccess(HValue* elements, |
| 4841 HValue* checked_key, | 4850 HValue* checked_key, |
| 4842 HValue* val, | 4851 HValue* val, |
| 4843 ElementsKind elements_kind, | 4852 ElementsKind elements_kind, |
| 4844 bool is_store) { | 4853 bool is_store) { |
| 4845 if (is_store) { | 4854 if (is_store) { |
| 4846 ASSERT(val != NULL); | 4855 ASSERT(val != NULL); |
| 4847 switch (elements_kind) { | 4856 switch (elements_kind) { |
| 4848 case FAST_DOUBLE_ELEMENTS: | 4857 case FAST_DOUBLE_ELEMENTS: |
| 4858 case FAST_HOLEY_DOUBLE_ELEMENTS: |
| 4849 return new(zone()) HStoreKeyedFastDoubleElement( | 4859 return new(zone()) HStoreKeyedFastDoubleElement( |
| 4850 elements, checked_key, val); | 4860 elements, checked_key, val); |
| 4851 case FAST_SMI_ONLY_ELEMENTS: | 4861 case FAST_SMI_ELEMENTS: |
| 4862 case FAST_HOLEY_SMI_ELEMENTS: |
| 4852 // Smi-only arrays need a smi check. | 4863 // Smi-only arrays need a smi check. |
| 4853 AddInstruction(new(zone()) HCheckSmi(val)); | 4864 AddInstruction(new(zone()) HCheckSmi(val)); |
| 4854 // Fall through. | 4865 // Fall through. |
| 4855 case FAST_ELEMENTS: | 4866 case FAST_ELEMENTS: |
| 4867 case FAST_HOLEY_ELEMENTS: |
| 4856 return new(zone()) HStoreKeyedFastElement( | 4868 return new(zone()) HStoreKeyedFastElement( |
| 4857 elements, checked_key, val, elements_kind); | 4869 elements, checked_key, val, elements_kind); |
| 4858 default: | 4870 default: |
| 4859 UNREACHABLE(); | 4871 UNREACHABLE(); |
| 4860 return NULL; | 4872 return NULL; |
| 4861 } | 4873 } |
| 4862 } | 4874 } |
| 4863 // It's an element load (!is_store). | 4875 // It's an element load (!is_store). |
| 4864 if (elements_kind == FAST_DOUBLE_ELEMENTS) { | 4876 HoleCheckMode mode = IsFastPackedElementsKind(elements_kind) ? |
| 4865 return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key); | 4877 OMIT_HOLE_CHECK : |
| 4866 } else { // FAST_ELEMENTS or FAST_SMI_ONLY_ELEMENTS. | 4878 PERFORM_HOLE_CHECK; |
| 4867 return new(zone()) HLoadKeyedFastElement(elements, checked_key); | 4879 if (IsFastDoubleElementsKind(elements_kind)) { |
| 4880 return new(zone()) HLoadKeyedFastDoubleElement(elements, checked_key, mode); |
| 4881 } else { // Smi or Object elements. |
| 4882 return new(zone()) HLoadKeyedFastElement(elements, checked_key, mode); |
| 4868 } | 4883 } |
| 4869 } | 4884 } |
| 4870 | 4885 |
| 4871 | 4886 |
| 4872 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, | 4887 HInstruction* HGraphBuilder::BuildMonomorphicElementAccess(HValue* object, |
| 4873 HValue* key, | 4888 HValue* key, |
| 4874 HValue* val, | 4889 HValue* val, |
| 4890 HValue* dependency, |
| 4875 Handle<Map> map, | 4891 Handle<Map> map, |
| 4876 bool is_store) { | 4892 bool is_store) { |
| 4877 HInstruction* mapcheck = AddInstruction(new(zone()) HCheckMaps(object, map)); | 4893 HInstruction* mapcheck = AddInstruction(new(zone()) |
| 4878 bool fast_smi_only_elements = map->has_fast_smi_only_elements(); | 4894 HCheckMaps(object, map, dependency)); |
| 4879 bool fast_elements = map->has_fast_elements(); | 4895 // No GVNFlag dependency is necessary for ElementsKind if there is an explicit |
| 4896 // dependency on a HElementsTransition instruction. The flag can also be |
| 4897 // removed if map to check has FAST_HOLEY_ELEMENTS, since there can be no |
| 4898 // further ElementsKind transitions. Finally, it can be removed for stores for |
| 4899 // FAST_ELEMENTS, since a transition to HOLEY elements won't change the |
| 4900 // generated store code. |
| 4901 if (dependency || |
| 4902 (map->elements_kind() == FAST_HOLEY_ELEMENTS) || |
| 4903 (map->elements_kind() == FAST_ELEMENTS && is_store)) { |
| 4904 mapcheck->ClearGVNFlag(kDependsOnElementsKind); |
| 4905 } |
| 4906 bool fast_smi_only_elements = map->has_fast_smi_elements(); |
| 4907 bool fast_elements = map->has_fast_object_elements(); |
| 4880 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); | 4908 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); |
| 4881 if (is_store && (fast_elements || fast_smi_only_elements)) { | 4909 if (is_store && (fast_elements || fast_smi_only_elements)) { |
| 4882 AddInstruction(new(zone()) HCheckMaps( | 4910 HCheckMaps* check_cow_map = new(zone()) HCheckMaps( |
| 4883 elements, isolate()->factory()->fixed_array_map())); | 4911 elements, isolate()->factory()->fixed_array_map()); |
| 4912 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); |
| 4913 AddInstruction(check_cow_map); |
| 4884 } | 4914 } |
| 4885 HInstruction* length = NULL; | 4915 HInstruction* length = NULL; |
| 4886 HInstruction* checked_key = NULL; | 4916 HInstruction* checked_key = NULL; |
| 4887 if (map->has_external_array_elements()) { | 4917 if (map->has_external_array_elements()) { |
| 4888 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 4918 length = AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
| 4889 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 4919 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 4890 HLoadExternalArrayPointer* external_elements = | 4920 HLoadExternalArrayPointer* external_elements = |
| 4891 new(zone()) HLoadExternalArrayPointer(elements); | 4921 new(zone()) HLoadExternalArrayPointer(elements); |
| 4892 AddInstruction(external_elements); | 4922 AddInstruction(external_elements); |
| 4893 return BuildExternalArrayElementAccess(external_elements, checked_key, | 4923 return BuildExternalArrayElementAccess(external_elements, checked_key, |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4926 type_todo[i] = false; | 4956 type_todo[i] = false; |
| 4927 } | 4957 } |
| 4928 | 4958 |
| 4929 // Elements_kind transition support. | 4959 // Elements_kind transition support. |
| 4930 MapHandleList transition_target(maps->length()); | 4960 MapHandleList transition_target(maps->length()); |
| 4931 // Collect possible transition targets. | 4961 // Collect possible transition targets. |
| 4932 MapHandleList possible_transitioned_maps(maps->length()); | 4962 MapHandleList possible_transitioned_maps(maps->length()); |
| 4933 for (int i = 0; i < maps->length(); ++i) { | 4963 for (int i = 0; i < maps->length(); ++i) { |
| 4934 Handle<Map> map = maps->at(i); | 4964 Handle<Map> map = maps->at(i); |
| 4935 ElementsKind elements_kind = map->elements_kind(); | 4965 ElementsKind elements_kind = map->elements_kind(); |
| 4936 if (elements_kind == FAST_DOUBLE_ELEMENTS || | 4966 if (IsFastElementsKind(elements_kind) && |
| 4937 elements_kind == FAST_ELEMENTS) { | 4967 elements_kind != GetInitialFastElementsKind()) { |
| 4938 possible_transitioned_maps.Add(map); | 4968 possible_transitioned_maps.Add(map); |
| 4939 } | 4969 } |
| 4940 } | 4970 } |
| 4941 // Get transition target for each map (NULL == no transition). | 4971 // Get transition target for each map (NULL == no transition). |
| 4942 for (int i = 0; i < maps->length(); ++i) { | 4972 for (int i = 0; i < maps->length(); ++i) { |
| 4943 Handle<Map> map = maps->at(i); | 4973 Handle<Map> map = maps->at(i); |
| 4944 Handle<Map> transitioned_map = | 4974 Handle<Map> transitioned_map = |
| 4945 map->FindTransitionedMap(&possible_transitioned_maps); | 4975 map->FindTransitionedMap(&possible_transitioned_maps); |
| 4946 transition_target.Add(transitioned_map); | 4976 transition_target.Add(transitioned_map); |
| 4947 } | 4977 } |
| 4948 | 4978 |
| 4949 int num_untransitionable_maps = 0; | 4979 int num_untransitionable_maps = 0; |
| 4950 Handle<Map> untransitionable_map; | 4980 Handle<Map> untransitionable_map; |
| 4981 HTransitionElementsKind* transition = NULL; |
| 4951 for (int i = 0; i < maps->length(); ++i) { | 4982 for (int i = 0; i < maps->length(); ++i) { |
| 4952 Handle<Map> map = maps->at(i); | 4983 Handle<Map> map = maps->at(i); |
| 4953 ASSERT(map->IsMap()); | 4984 ASSERT(map->IsMap()); |
| 4954 if (!transition_target.at(i).is_null()) { | 4985 if (!transition_target.at(i).is_null()) { |
| 4955 AddInstruction(new(zone()) HTransitionElementsKind( | 4986 ASSERT(Map::IsValidElementsTransition( |
| 4956 object, map, transition_target.at(i))); | 4987 map->elements_kind(), |
| 4988 transition_target.at(i)->elements_kind())); |
| 4989 transition = new(zone()) HTransitionElementsKind( |
| 4990 object, map, transition_target.at(i)); |
| 4991 AddInstruction(transition); |
| 4957 } else { | 4992 } else { |
| 4958 type_todo[map->elements_kind()] = true; | 4993 type_todo[map->elements_kind()] = true; |
| 4959 if (map->elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) { | 4994 if (map->elements_kind() >= FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND) { |
| 4960 todo_external_array = true; | 4995 todo_external_array = true; |
| 4961 } | 4996 } |
| 4962 num_untransitionable_maps++; | 4997 num_untransitionable_maps++; |
| 4963 untransitionable_map = map; | 4998 untransitionable_map = map; |
| 4964 } | 4999 } |
| 4965 } | 5000 } |
| 4966 | 5001 |
| 4967 // If only one map is left after transitioning, handle this case | 5002 // If only one map is left after transitioning, handle this case |
| 4968 // monomorphically. | 5003 // monomorphically. |
| 4969 if (num_untransitionable_maps == 1) { | 5004 if (num_untransitionable_maps == 1) { |
| 4970 HInstruction* instr = NULL; | 5005 HInstruction* instr = NULL; |
| 4971 if (untransitionable_map->has_slow_elements_kind()) { | 5006 if (untransitionable_map->has_slow_elements_kind()) { |
| 4972 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) | 5007 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) |
| 4973 : BuildLoadKeyedGeneric(object, key)); | 5008 : BuildLoadKeyedGeneric(object, key)); |
| 4974 } else { | 5009 } else { |
| 4975 instr = AddInstruction(BuildMonomorphicElementAccess( | 5010 instr = AddInstruction(BuildMonomorphicElementAccess( |
| 4976 object, key, val, untransitionable_map, is_store)); | 5011 object, key, val, transition, untransitionable_map, is_store)); |
| 4977 } | 5012 } |
| 4978 *has_side_effects |= instr->HasObservableSideEffects(); | 5013 *has_side_effects |= instr->HasObservableSideEffects(); |
| 4979 instr->set_position(position); | 5014 instr->set_position(position); |
| 4980 return is_store ? NULL : instr; | 5015 return is_store ? NULL : instr; |
| 4981 } | 5016 } |
| 4982 | 5017 |
| 4983 AddInstruction(HCheckInstanceType::NewIsSpecObject(object)); | 5018 AddInstruction(HCheckInstanceType::NewIsSpecObject(object)); |
| 4984 HBasicBlock* join = graph()->CreateBasicBlock(); | 5019 HBasicBlock* join = graph()->CreateBasicBlock(); |
| 4985 | 5020 |
| 4986 HInstruction* elements_kind_instr = | 5021 HInstruction* elements_kind_instr = |
| 4987 AddInstruction(new(zone()) HElementsKind(object)); | 5022 AddInstruction(new(zone()) HElementsKind(object)); |
| 4988 HCompareConstantEqAndBranch* elements_kind_branch = NULL; | 5023 HCompareConstantEqAndBranch* elements_kind_branch = NULL; |
| 4989 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); | 5024 HInstruction* elements = AddInstruction(new(zone()) HLoadElements(object)); |
| 4990 HLoadExternalArrayPointer* external_elements = NULL; | 5025 HLoadExternalArrayPointer* external_elements = NULL; |
| 4991 HInstruction* checked_key = NULL; | 5026 HInstruction* checked_key = NULL; |
| 4992 | 5027 |
| 4993 // Generated code assumes that FAST_SMI_ONLY_ELEMENTS, FAST_ELEMENTS, | 5028 // Generated code assumes that FAST_* and DICTIONARY_ELEMENTS ElementsKinds |
| 4994 // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS are handled before external | 5029 // are handled before external arrays. |
| 4995 // arrays. | 5030 STATIC_ASSERT(FAST_SMI_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
| 4996 STATIC_ASSERT(FAST_SMI_ONLY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | 5031 STATIC_ASSERT(FAST_HOLEY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
| 4997 STATIC_ASSERT(FAST_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | |
| 4998 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | 5032 STATIC_ASSERT(FAST_DOUBLE_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
| 4999 STATIC_ASSERT(DICTIONARY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); | 5033 STATIC_ASSERT(DICTIONARY_ELEMENTS < FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND); |
| 5000 | 5034 |
| 5001 for (ElementsKind elements_kind = FIRST_ELEMENTS_KIND; | 5035 for (ElementsKind elements_kind = FIRST_ELEMENTS_KIND; |
| 5002 elements_kind <= LAST_ELEMENTS_KIND; | 5036 elements_kind <= LAST_ELEMENTS_KIND; |
| 5003 elements_kind = ElementsKind(elements_kind + 1)) { | 5037 elements_kind = ElementsKind(elements_kind + 1)) { |
| 5004 // After having handled FAST_ELEMENTS, FAST_SMI_ONLY_ELEMENTS, | 5038 // After having handled FAST_* and DICTIONARY_ELEMENTS, we need to add some |
| 5005 // FAST_DOUBLE_ELEMENTS and DICTIONARY_ELEMENTS, we need to add some code | 5039 // code that's executed for all external array cases. |
| 5006 // that's executed for all external array cases. | |
| 5007 STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == | 5040 STATIC_ASSERT(LAST_EXTERNAL_ARRAY_ELEMENTS_KIND == |
| 5008 LAST_ELEMENTS_KIND); | 5041 LAST_ELEMENTS_KIND); |
| 5009 if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND | 5042 if (elements_kind == FIRST_EXTERNAL_ARRAY_ELEMENTS_KIND |
| 5010 && todo_external_array) { | 5043 && todo_external_array) { |
| 5011 HInstruction* length = | 5044 HInstruction* length = |
| 5012 AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); | 5045 AddInstruction(new(zone()) HFixedArrayBaseLength(elements)); |
| 5013 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); | 5046 checked_key = AddInstruction(new(zone()) HBoundsCheck(key, length)); |
| 5014 external_elements = new(zone()) HLoadExternalArrayPointer(elements); | 5047 external_elements = new(zone()) HLoadExternalArrayPointer(elements); |
| 5015 AddInstruction(external_elements); | 5048 AddInstruction(external_elements); |
| 5016 } | 5049 } |
| 5017 if (type_todo[elements_kind]) { | 5050 if (type_todo[elements_kind]) { |
| 5018 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 5051 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 5019 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 5052 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 5020 elements_kind_branch = new(zone()) HCompareConstantEqAndBranch( | 5053 elements_kind_branch = new(zone()) HCompareConstantEqAndBranch( |
| 5021 elements_kind_instr, elements_kind, Token::EQ_STRICT); | 5054 elements_kind_instr, elements_kind, Token::EQ_STRICT); |
| 5022 elements_kind_branch->SetSuccessorAt(0, if_true); | 5055 elements_kind_branch->SetSuccessorAt(0, if_true); |
| 5023 elements_kind_branch->SetSuccessorAt(1, if_false); | 5056 elements_kind_branch->SetSuccessorAt(1, if_false); |
| 5024 current_block()->Finish(elements_kind_branch); | 5057 current_block()->Finish(elements_kind_branch); |
| 5025 | 5058 |
| 5026 set_current_block(if_true); | 5059 set_current_block(if_true); |
| 5027 HInstruction* access; | 5060 HInstruction* access; |
| 5028 if (elements_kind == FAST_SMI_ONLY_ELEMENTS || | 5061 if (IsFastElementsKind(elements_kind)) { |
| 5029 elements_kind == FAST_ELEMENTS || | 5062 if (is_store && !IsFastDoubleElementsKind(elements_kind)) { |
| 5030 elements_kind == FAST_DOUBLE_ELEMENTS) { | |
| 5031 if (is_store && elements_kind != FAST_DOUBLE_ELEMENTS) { | |
| 5032 AddInstruction(new(zone()) HCheckMaps( | 5063 AddInstruction(new(zone()) HCheckMaps( |
| 5033 elements, isolate()->factory()->fixed_array_map(), | 5064 elements, isolate()->factory()->fixed_array_map(), |
| 5034 elements_kind_branch)); | 5065 elements_kind_branch)); |
| 5035 } | 5066 } |
| 5036 // TODO(jkummerow): The need for these two blocks could be avoided | 5067 // TODO(jkummerow): The need for these two blocks could be avoided |
| 5037 // in one of two ways: | 5068 // in one of two ways: |
| 5038 // (1) Introduce ElementsKinds for JSArrays that are distinct from | 5069 // (1) Introduce ElementsKinds for JSArrays that are distinct from |
| 5039 // those for fast objects. | 5070 // those for fast objects. |
| 5040 // (2) Put the common instructions into a third "join" block. This | 5071 // (2) Put the common instructions into a third "join" block. This |
| 5041 // requires additional AST IDs that we can deopt to from inside | 5072 // requires additional AST IDs that we can deopt to from inside |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5108 bool* has_side_effects) { | 5139 bool* has_side_effects) { |
| 5109 ASSERT(!expr->IsPropertyName()); | 5140 ASSERT(!expr->IsPropertyName()); |
| 5110 HInstruction* instr = NULL; | 5141 HInstruction* instr = NULL; |
| 5111 if (expr->IsMonomorphic()) { | 5142 if (expr->IsMonomorphic()) { |
| 5112 Handle<Map> map = expr->GetMonomorphicReceiverType(); | 5143 Handle<Map> map = expr->GetMonomorphicReceiverType(); |
| 5113 if (map->has_slow_elements_kind()) { | 5144 if (map->has_slow_elements_kind()) { |
| 5114 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) | 5145 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) |
| 5115 : BuildLoadKeyedGeneric(obj, key); | 5146 : BuildLoadKeyedGeneric(obj, key); |
| 5116 } else { | 5147 } else { |
| 5117 AddInstruction(new(zone()) HCheckNonSmi(obj)); | 5148 AddInstruction(new(zone()) HCheckNonSmi(obj)); |
| 5118 instr = BuildMonomorphicElementAccess(obj, key, val, map, is_store); | 5149 instr = BuildMonomorphicElementAccess(obj, key, val, NULL, map, is_store); |
| 5119 } | 5150 } |
| 5120 } else if (expr->GetReceiverTypes() != NULL && | 5151 } else if (expr->GetReceiverTypes() != NULL && |
| 5121 !expr->GetReceiverTypes()->is_empty()) { | 5152 !expr->GetReceiverTypes()->is_empty()) { |
| 5122 return HandlePolymorphicElementAccess( | 5153 return HandlePolymorphicElementAccess( |
| 5123 obj, key, val, expr, ast_id, position, is_store, has_side_effects); | 5154 obj, key, val, expr, ast_id, position, is_store, has_side_effects); |
| 5124 } else { | 5155 } else { |
| 5125 if (is_store) { | 5156 if (is_store) { |
| 5126 instr = BuildStoreKeyedGeneric(obj, key, val); | 5157 instr = BuildStoreKeyedGeneric(obj, key, val); |
| 5127 } else { | 5158 } else { |
| 5128 instr = BuildLoadKeyedGeneric(obj, key); | 5159 instr = BuildLoadKeyedGeneric(obj, key); |
| (...skipping 3332 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8461 } | 8492 } |
| 8462 } | 8493 } |
| 8463 | 8494 |
| 8464 #ifdef DEBUG | 8495 #ifdef DEBUG |
| 8465 if (graph_ != NULL) graph_->Verify(false); // No full verify. | 8496 if (graph_ != NULL) graph_->Verify(false); // No full verify. |
| 8466 if (allocator_ != NULL) allocator_->Verify(); | 8497 if (allocator_ != NULL) allocator_->Verify(); |
| 8467 #endif | 8498 #endif |
| 8468 } | 8499 } |
| 8469 | 8500 |
| 8470 } } // namespace v8::internal | 8501 } } // namespace v8::internal |
| OLD | NEW |