Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 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 1540 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1551 elements, isolate()->factory()->fixed_array_map(), top_info()); | 1551 elements, isolate()->factory()->fixed_array_map(), top_info()); |
| 1552 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); | 1552 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); |
| 1553 } | 1553 } |
| 1554 } | 1554 } |
| 1555 } | 1555 } |
| 1556 return AddElementAccess(elements, checked_key, val, checked_object, | 1556 return AddElementAccess(elements, checked_key, val, checked_object, |
| 1557 elements_kind, is_store, load_mode); | 1557 elements_kind, is_store, load_mode); |
| 1558 } | 1558 } |
| 1559 | 1559 |
| 1560 | 1560 |
| 1561 | |
| 1562 HValue* HGraphBuilder::BuildAllocateArrayFromLength( | |
| 1563 JSArrayBuilder* array_builder, | |
| 1564 HValue* length_argument) { | |
| 1565 if (length_argument->IsConstant() && | |
| 1566 HConstant::cast(length_argument)->HasSmiValue()) { | |
| 1567 int array_length = HConstant::cast(length_argument)->Integer32Value(); | |
| 1568 HValue* new_object = (array_length == 0) | |
|
Toon Verwaest
2013/11/11 13:59:28
Remove the parentheses.
mvstanton
2013/11/13 14:12:52
Done.
| |
| 1569 ? array_builder->AllocateEmptyArray() | |
| 1570 : array_builder->AllocateArray(length_argument, length_argument); | |
| 1571 return new_object; | |
| 1572 } | |
| 1573 | |
| 1574 HValue* constant_zero = graph()->GetConstant0(); | |
| 1575 HConstant* max_alloc_length = | |
| 1576 Add<HConstant>(JSObject::kInitialMaxFastElementArray); | |
| 1577 const int initial_capacity = JSArray::kPreallocatedArrayElements; | |
| 1578 HConstant* initial_capacity_node = Add<HConstant>(initial_capacity); | |
|
Toon Verwaest
2013/11/11 13:59:28
Move this down to the case where initial-capacity-
mvstanton
2013/11/13 14:12:52
Done.
| |
| 1579 HInstruction* checked_length = Add<HBoundsCheck>(length_argument, | |
| 1580 max_alloc_length); | |
| 1581 IfBuilder if_builder(this); | |
| 1582 if_builder.If<HCompareNumericAndBranch>(checked_length, constant_zero, | |
| 1583 Token::EQ); | |
| 1584 if_builder.Then(); | |
| 1585 Push(initial_capacity_node); // capacity | |
| 1586 Push(constant_zero); // length | |
| 1587 if_builder.Else(); | |
| 1588 Push(checked_length); // capacity | |
| 1589 Push(checked_length); // length | |
| 1590 if_builder.End(); | |
| 1591 | |
| 1592 // Figure out total size | |
| 1593 HValue* length = Pop(); | |
| 1594 HValue* capacity = Pop(); | |
| 1595 return array_builder->AllocateArray(capacity, length); | |
| 1596 } | |
| 1597 | |
| 1561 HValue* HGraphBuilder::BuildAllocateElements(ElementsKind kind, | 1598 HValue* HGraphBuilder::BuildAllocateElements(ElementsKind kind, |
| 1562 HValue* capacity) { | 1599 HValue* capacity) { |
| 1563 int elements_size; | 1600 int elements_size; |
| 1564 InstanceType instance_type; | 1601 InstanceType instance_type; |
| 1565 | 1602 |
| 1566 if (IsFastDoubleElementsKind(kind)) { | 1603 if (IsFastDoubleElementsKind(kind)) { |
| 1567 elements_size = kDoubleSize; | 1604 elements_size = kDoubleSize; |
| 1568 instance_type = FIXED_DOUBLE_ARRAY_TYPE; | 1605 instance_type = FIXED_DOUBLE_ARRAY_TYPE; |
| 1569 } else { | 1606 } else { |
| 1570 elements_size = kPointerSize; | 1607 elements_size = kPointerSize; |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1739 // Fast elements kinds need to be initialized in case statements below cause | 1776 // Fast elements kinds need to be initialized in case statements below cause |
| 1740 // a garbage collection. | 1777 // a garbage collection. |
| 1741 Factory* factory = isolate()->factory(); | 1778 Factory* factory = isolate()->factory(); |
| 1742 | 1779 |
| 1743 double nan_double = FixedDoubleArray::hole_nan_as_double(); | 1780 double nan_double = FixedDoubleArray::hole_nan_as_double(); |
| 1744 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind) | 1781 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind) |
| 1745 ? Add<HConstant>(factory->the_hole_value()) | 1782 ? Add<HConstant>(factory->the_hole_value()) |
| 1746 : Add<HConstant>(nan_double); | 1783 : Add<HConstant>(nan_double); |
| 1747 | 1784 |
| 1748 // Special loop unfolding case | 1785 // Special loop unfolding case |
| 1749 static const int kLoopUnfoldLimit = 4; | 1786 static const int kLoopUnfoldLimit = 6; |
| 1750 bool unfold_loop = false; | 1787 bool unfold_loop = false; |
| 1751 int initial_capacity = JSArray::kPreallocatedArrayElements; | 1788 int initial_capacity; |
| 1752 if (from->IsConstant() && to->IsConstant() && | 1789 |
| 1753 initial_capacity <= kLoopUnfoldLimit) { | 1790 if (from->ActualValue()->IsConstant() && to->ActualValue()->IsConstant()) { |
|
Toon Verwaest
2013/11/11 13:59:28
Please put this is a separate CL (that also more w
mvstanton
2013/11/13 14:12:52
I made another CL that isolates the idef of HForce
| |
| 1754 HConstant* constant_from = HConstant::cast(from); | 1791 HConstant* constant_from = HConstant::cast(from->ActualValue()); |
| 1755 HConstant* constant_to = HConstant::cast(to); | 1792 HConstant* constant_to = HConstant::cast(to->ActualValue()); |
| 1756 | 1793 |
| 1757 if (constant_from->HasInteger32Value() && | 1794 if (constant_from->HasInteger32Value() && |
| 1758 constant_from->Integer32Value() == 0 && | 1795 constant_from->Integer32Value() == 0 && |
| 1759 constant_to->HasInteger32Value() && | 1796 constant_to->HasInteger32Value() && |
| 1760 constant_to->Integer32Value() == initial_capacity) { | 1797 constant_to->Integer32Value() <= kLoopUnfoldLimit) { |
| 1761 unfold_loop = true; | 1798 unfold_loop = true; |
| 1799 initial_capacity = constant_to->Integer32Value(); | |
| 1762 } | 1800 } |
| 1763 } | 1801 } |
| 1764 | 1802 |
| 1765 // Since we're about to store a hole value, the store instruction below must | 1803 // Since we're about to store a hole value, the store instruction below must |
| 1766 // assume an elements kind that supports heap object values. | 1804 // assume an elements kind that supports heap object values. |
| 1767 if (IsFastSmiOrObjectElementsKind(elements_kind)) { | 1805 if (IsFastSmiOrObjectElementsKind(elements_kind)) { |
| 1768 elements_kind = FAST_HOLEY_ELEMENTS; | 1806 elements_kind = FAST_HOLEY_ELEMENTS; |
| 1769 } | 1807 } |
| 1770 | 1808 |
| 1771 if (unfold_loop) { | 1809 if (unfold_loop) { |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1997 Add<HConstant>(static_cast<int32_t>(Context::ARRAY_FUNCTION_INDEX)); | 2035 Add<HConstant>(static_cast<int32_t>(Context::ARRAY_FUNCTION_INDEX)); |
| 1998 return Add<HLoadKeyed>( | 2036 return Add<HLoadKeyed>( |
| 1999 native_context, index, static_cast<HValue*>(NULL), FAST_ELEMENTS); | 2037 native_context, index, static_cast<HValue*>(NULL), FAST_ELEMENTS); |
| 2000 } | 2038 } |
| 2001 | 2039 |
| 2002 | 2040 |
| 2003 HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder, | 2041 HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder, |
| 2004 ElementsKind kind, | 2042 ElementsKind kind, |
| 2005 HValue* allocation_site_payload, | 2043 HValue* allocation_site_payload, |
| 2006 HValue* constructor_function, | 2044 HValue* constructor_function, |
| 2007 AllocationSiteOverrideMode override_mode) : | 2045 AllocationSiteOverrideMode override_mode, |
| 2046 bool is_inlined) : | |
| 2008 builder_(builder), | 2047 builder_(builder), |
| 2009 kind_(kind), | 2048 kind_(kind), |
| 2010 allocation_site_payload_(allocation_site_payload), | 2049 allocation_site_payload_(allocation_site_payload), |
| 2011 constructor_function_(constructor_function) { | 2050 constructor_function_(constructor_function), |
| 2051 is_inlined_(is_inlined) { | |
| 2012 mode_ = override_mode == DISABLE_ALLOCATION_SITES | 2052 mode_ = override_mode == DISABLE_ALLOCATION_SITES |
| 2013 ? DONT_TRACK_ALLOCATION_SITE | 2053 ? DONT_TRACK_ALLOCATION_SITE |
| 2014 : AllocationSite::GetMode(kind); | 2054 : AllocationSite::GetMode(kind); |
| 2015 } | 2055 } |
| 2016 | 2056 |
| 2017 | 2057 |
| 2018 HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder, | 2058 HGraphBuilder::JSArrayBuilder::JSArrayBuilder(HGraphBuilder* builder, |
| 2019 ElementsKind kind, | 2059 ElementsKind kind, |
| 2020 HValue* constructor_function) : | 2060 HValue* constructor_function) : |
| 2021 builder_(builder), | 2061 builder_(builder), |
| 2022 kind_(kind), | 2062 kind_(kind), |
| 2023 mode_(DONT_TRACK_ALLOCATION_SITE), | 2063 mode_(DONT_TRACK_ALLOCATION_SITE), |
| 2024 allocation_site_payload_(NULL), | 2064 allocation_site_payload_(NULL), |
| 2025 constructor_function_(constructor_function) { | 2065 constructor_function_(constructor_function), |
| 2066 is_inlined_(false) { | |
| 2026 } | 2067 } |
| 2027 | 2068 |
| 2028 | 2069 |
| 2029 HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode() { | 2070 HValue* HGraphBuilder::JSArrayBuilder::EmitMapCode() { |
| 2071 if (is_inlined_) { | |
|
Toon Verwaest
2013/11/11 13:59:28
Is it good enough to use IsStub() rather than is_i
mvstanton
2013/11/13 14:12:52
Sure is, thanks for the idea. Done.
| |
| 2072 // A constant map is fine. | |
| 2073 Handle<Map> map(builder()->isolate()->get_initial_js_array_map(kind_), | |
| 2074 builder()->isolate()); | |
| 2075 return builder()->Add<HConstant>(map); | |
| 2076 } | |
| 2077 | |
| 2030 if (kind_ == GetInitialFastElementsKind()) { | 2078 if (kind_ == GetInitialFastElementsKind()) { |
| 2031 // No need for a context lookup if the kind_ matches the initial | 2079 // No need for a context lookup if the kind_ matches the initial |
| 2032 // map, because we can just load the map in that case. | 2080 // map, because we can just load the map in that case. |
| 2033 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); | 2081 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); |
| 2034 return builder()->AddLoadNamedField(constructor_function_, access); | 2082 return builder()->AddLoadNamedField(constructor_function_, access); |
| 2035 } | 2083 } |
| 2036 | 2084 |
| 2037 HInstruction* native_context = builder()->BuildGetNativeContext(); | 2085 HInstruction* native_context = builder()->BuildGetNativeContext(); |
| 2038 HInstruction* index = builder()->Add<HConstant>( | 2086 HInstruction* index = builder()->Add<HConstant>( |
| 2039 static_cast<int32_t>(Context::JS_ARRAY_MAPS_INDEX)); | 2087 static_cast<int32_t>(Context::JS_ARRAY_MAPS_INDEX)); |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 2060 ASSERT(length_node != NULL); | 2108 ASSERT(length_node != NULL); |
| 2061 | 2109 |
| 2062 int base_size = JSArray::kSize; | 2110 int base_size = JSArray::kSize; |
| 2063 if (mode_ == TRACK_ALLOCATION_SITE) { | 2111 if (mode_ == TRACK_ALLOCATION_SITE) { |
| 2064 base_size += AllocationMemento::kSize; | 2112 base_size += AllocationMemento::kSize; |
| 2065 } | 2113 } |
| 2066 | 2114 |
| 2067 STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize); | 2115 STATIC_ASSERT(FixedDoubleArray::kHeaderSize == FixedArray::kHeaderSize); |
| 2068 base_size += FixedArray::kHeaderSize; | 2116 base_size += FixedArray::kHeaderSize; |
| 2069 | 2117 |
| 2118 if (length_node->IsConstant()) { | |
| 2119 HConstant* constant_length_node = HConstant::cast(length_node); | |
| 2120 if (constant_length_node->HasInteger32Value()) { | |
| 2121 int size = base_size + elements_size() * | |
| 2122 constant_length_node->Integer32Value(); | |
| 2123 HInstruction* const_size = builder()->Add<HConstant>(size); | |
| 2124 return const_size; | |
|
Toon Verwaest
2013/11/11 13:59:28
I think constant folding should take care of this.
mvstanton
2013/11/13 14:12:52
Indeed, thx!
| |
| 2125 } | |
| 2126 } | |
| 2127 | |
| 2070 HInstruction* elements_size_value = | 2128 HInstruction* elements_size_value = |
| 2071 builder()->Add<HConstant>(elements_size()); | 2129 builder()->Add<HConstant>(elements_size()); |
| 2072 HInstruction* mul = builder()->Add<HMul>(length_node, elements_size_value); | 2130 HInstruction* mul = builder()->Add<HMul>(length_node, elements_size_value); |
| 2073 mul->ClearFlag(HValue::kCanOverflow); | 2131 mul->ClearFlag(HValue::kCanOverflow); |
| 2074 | 2132 |
| 2075 HInstruction* base = builder()->Add<HConstant>(base_size); | 2133 HInstruction* base = builder()->Add<HConstant>(base_size); |
| 2076 HInstruction* total_size = builder()->Add<HAdd>(base, mul); | 2134 HInstruction* total_size = builder()->Add<HAdd>(base, mul); |
| 2077 total_size->ClearFlag(HValue::kCanOverflow); | 2135 total_size->ClearFlag(HValue::kCanOverflow); |
| 2078 return total_size; | 2136 return total_size; |
| 2079 } | 2137 } |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 2091 | 2149 |
| 2092 return builder()->Add<HConstant>(base_size); | 2150 return builder()->Add<HConstant>(base_size); |
| 2093 } | 2151 } |
| 2094 | 2152 |
| 2095 | 2153 |
| 2096 HValue* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() { | 2154 HValue* HGraphBuilder::JSArrayBuilder::AllocateEmptyArray() { |
| 2097 HValue* size_in_bytes = EstablishEmptyArrayAllocationSize(); | 2155 HValue* size_in_bytes = EstablishEmptyArrayAllocationSize(); |
| 2098 HConstant* capacity = builder()->Add<HConstant>(initial_capacity()); | 2156 HConstant* capacity = builder()->Add<HConstant>(initial_capacity()); |
| 2099 return AllocateArray(size_in_bytes, | 2157 return AllocateArray(size_in_bytes, |
| 2100 capacity, | 2158 capacity, |
| 2101 builder()->graph()->GetConstant0(), | 2159 builder()->graph()->GetConstant0()); |
| 2102 true); | |
| 2103 } | 2160 } |
| 2104 | 2161 |
| 2105 | 2162 |
| 2106 HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* capacity, | 2163 HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* capacity, |
| 2107 HValue* length_field, | 2164 HValue* length_field, |
| 2108 bool fill_with_hole) { | 2165 FillMode fill_mode) { |
| 2109 HValue* size_in_bytes = EstablishAllocationSize(capacity); | 2166 HValue* size_in_bytes = EstablishAllocationSize(capacity); |
| 2110 return AllocateArray(size_in_bytes, capacity, length_field, fill_with_hole); | 2167 return AllocateArray(size_in_bytes, capacity, length_field, fill_mode); |
| 2111 } | 2168 } |
| 2112 | 2169 |
| 2113 | 2170 |
| 2114 HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes, | 2171 HValue* HGraphBuilder::JSArrayBuilder::AllocateArray(HValue* size_in_bytes, |
| 2115 HValue* capacity, | 2172 HValue* capacity, |
| 2116 HValue* length_field, | 2173 HValue* length_field, |
| 2117 bool fill_with_hole) { | 2174 FillMode fill_mode) { |
| 2118 // These HForceRepresentations are because we store these as fields in the | 2175 // These HForceRepresentations are because we store these as fields in the |
| 2119 // objects we construct, and an int32-to-smi HChange could deopt. Accept | 2176 // objects we construct, and an int32-to-smi HChange could deopt. Accept |
| 2120 // the deopt possibility now, before allocation occurs. | 2177 // the deopt possibility now, before allocation occurs. |
| 2121 capacity = builder()->Add<HForceRepresentation>(capacity, | 2178 capacity = builder()->Add<HForceRepresentation>(capacity, |
| 2122 Representation::Smi()); | 2179 Representation::Smi()); |
| 2123 length_field = builder()->Add<HForceRepresentation>(length_field, | 2180 length_field = builder()->Add<HForceRepresentation>(length_field, |
| 2124 Representation::Smi()); | 2181 Representation::Smi()); |
| 2125 // Allocate (dealing with failure appropriately) | 2182 // Allocate (dealing with failure appropriately) |
| 2126 HAllocate* new_object = builder()->Add<HAllocate>(size_in_bytes, | 2183 HAllocate* new_object = builder()->Add<HAllocate>(size_in_bytes, |
| 2127 HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE); | 2184 HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE); |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 2141 elements_location_ = builder()->BuildJSArrayHeader(new_object, | 2198 elements_location_ = builder()->BuildJSArrayHeader(new_object, |
| 2142 map, | 2199 map, |
| 2143 mode_, | 2200 mode_, |
| 2144 kind_, | 2201 kind_, |
| 2145 allocation_site_payload_, | 2202 allocation_site_payload_, |
| 2146 length_field); | 2203 length_field); |
| 2147 | 2204 |
| 2148 // Initialize the elements | 2205 // Initialize the elements |
| 2149 builder()->BuildInitializeElementsHeader(elements_location_, kind_, capacity); | 2206 builder()->BuildInitializeElementsHeader(elements_location_, kind_, capacity); |
| 2150 | 2207 |
| 2151 if (fill_with_hole) { | 2208 if (fill_mode == FILL_WITH_HOLE) { |
| 2152 builder()->BuildFillElementsWithHole(elements_location_, kind_, | 2209 builder()->BuildFillElementsWithHole(elements_location_, kind_, |
| 2153 graph()->GetConstant0(), capacity); | 2210 graph()->GetConstant0(), capacity); |
| 2154 } | 2211 } |
| 2155 | 2212 |
| 2156 return new_object; | 2213 return new_object; |
| 2157 } | 2214 } |
| 2158 | 2215 |
| 2159 | 2216 |
| 2160 HStoreNamedField* HGraphBuilder::AddStoreMapConstant(HValue *object, | 2217 HStoreNamedField* HGraphBuilder::AddStoreMapConstant(HValue *object, |
| 2161 Handle<Map> map) { | 2218 Handle<Map> map) { |
| (...skipping 5000 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7162 | 7219 |
| 7163 call = New<HCallFunction>(function, argument_count); | 7220 call = New<HCallFunction>(function, argument_count); |
| 7164 Drop(argument_count + 1); | 7221 Drop(argument_count + 1); |
| 7165 } | 7222 } |
| 7166 } | 7223 } |
| 7167 | 7224 |
| 7168 return ast_context()->ReturnInstruction(call, expr->id()); | 7225 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7169 } | 7226 } |
| 7170 | 7227 |
| 7171 | 7228 |
| 7229 void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) { | |
| 7230 NoObservableSideEffectsScope no_effects(this); | |
| 7231 | |
| 7232 int argument_count = expr->arguments()->length(); | |
| 7233 // We should at least have the constructor on the expression stack. | |
| 7234 ASSERT(!environment()->ExpressionStackIsEmpty()); | |
|
Toon Verwaest
2013/11/11 13:59:28
I this ASSERT and the comment necessary? Doesn't t
mvstanton
2013/11/13 14:12:52
Done.
| |
| 7235 HValue* constructor = environment()->ExpressionStackAt(argument_count); | |
| 7236 | |
| 7237 ElementsKind kind = expr->elements_kind(); | |
| 7238 Handle<Cell> cell = expr->allocation_info_cell(); | |
| 7239 AllocationSite* site = AllocationSite::cast(cell->value()); | |
| 7240 | |
| 7241 // Register on the site for deoptimization if the cell value changes. | |
| 7242 site->AddDependentCompilationInfo(AllocationSite::TRANSITIONS, top_info()); | |
| 7243 HInstruction* cell_instruction = Add<HConstant>(cell); | |
| 7244 | |
| 7245 // In the single constant argument case, we may have to adjust elements kind | |
| 7246 // to avoid creating a packed non-empty array (not kosher). | |
|
Toon Verwaest
2013/11/11 13:59:28
I'd remove the (not kosher) part.
mvstanton
2013/11/13 14:12:52
Done.
| |
| 7247 if (argument_count == 1 && !IsHoleyElementsKind(kind)) { | |
|
Toon Verwaest
2013/11/11 13:59:28
Can't we just do this in BuildAllocateArrayFromLen
mvstanton
2013/11/13 14:12:52
Hmm, I'd rather not because then the JSArrayBuilde
| |
| 7248 HValue* argument = environment()->Top(); | |
| 7249 if (argument->IsConstant()) { | |
| 7250 HConstant* constant_argument = HConstant::cast(argument); | |
| 7251 ASSERT(constant_argument->HasSmiValue()); | |
| 7252 int constant_array_size = constant_argument->Integer32Value(); | |
| 7253 if (constant_array_size != 0) { | |
| 7254 kind = GetHoleyElementsKind(kind); | |
| 7255 } | |
| 7256 } | |
| 7257 } | |
| 7258 | |
| 7259 // Build the array. | |
| 7260 JSArrayBuilder array_builder(this, | |
| 7261 kind, | |
| 7262 cell_instruction, | |
| 7263 constructor, | |
| 7264 DISABLE_ALLOCATION_SITES, | |
| 7265 true); | |
| 7266 HValue* new_object; | |
| 7267 if (argument_count == 0) { | |
| 7268 new_object = array_builder.AllocateEmptyArray(); | |
| 7269 } else if (argument_count == 1) { | |
| 7270 HValue* argument = environment()->Top(); | |
| 7271 new_object = BuildAllocateArrayFromLength(&array_builder, argument); | |
| 7272 } else { | |
| 7273 HValue* length = Add<HConstant>(argument_count); | |
| 7274 // Smi arrays need to initialize array elements with the hole because | |
| 7275 // bailout could occur if the arguments don't fit in a smi. | |
| 7276 // | |
| 7277 // TODO(mvstanton): If all the arguments are constants in smi range, then | |
| 7278 // we could set fill_with_hole to false and save a few instructions. | |
| 7279 JSArrayBuilder::FillMode fill_mode = IsFastSmiElementsKind(kind) | |
| 7280 ? JSArrayBuilder::FILL_WITH_HOLE | |
| 7281 : JSArrayBuilder::DONT_FILL_WITH_HOLE; | |
| 7282 new_object = array_builder.AllocateArray(length, length, fill_mode); | |
| 7283 HValue* elements = array_builder.GetElementsLocation(); | |
| 7284 for (int i = 0; i < argument_count; i++) { | |
| 7285 HValue* value = environment()->ExpressionStackAt(argument_count - i - 1); | |
| 7286 HValue* constant_i = Add<HConstant>(i); | |
| 7287 Add<HStoreKeyed>(elements, constant_i, value, kind); | |
| 7288 } | |
| 7289 } | |
| 7290 | |
| 7291 Drop(argument_count + 1); // drop constructor and args. | |
| 7292 ast_context()->ReturnValue(new_object); | |
| 7293 } | |
| 7294 | |
| 7295 | |
| 7172 // Checks whether allocation using the given constructor can be inlined. | 7296 // Checks whether allocation using the given constructor can be inlined. |
| 7173 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { | 7297 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { |
| 7174 return constructor->has_initial_map() && | 7298 return constructor->has_initial_map() && |
| 7175 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && | 7299 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && |
| 7176 constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize && | 7300 constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize && |
| 7177 constructor->initial_map()->InitialPropertiesLength() == 0; | 7301 constructor->initial_map()->InitialPropertiesLength() == 0; |
| 7178 } | 7302 } |
| 7179 | 7303 |
| 7180 | 7304 |
| 7305 bool HOptimizedGraphBuilder::IsCallNewArrayInlineable(CallNew* expr) { | |
| 7306 bool inline_ok = false; | |
| 7307 Handle<JSFunction> caller = current_info()->closure(); | |
| 7308 Handle<JSFunction> target(isolate()->global_context()->array_function(), | |
| 7309 isolate()); | |
| 7310 int argument_count = expr->arguments()->length(); | |
| 7311 // We should have the function plus array arguments on the environment stack. | |
| 7312 ASSERT(environment()->length() >= (argument_count + 1)); | |
| 7313 Handle<Cell> cell = expr->allocation_info_cell(); | |
| 7314 AllocationSite* site = AllocationSite::cast(cell->value()); | |
| 7315 if (site->CanInlineCall()) { | |
| 7316 // We also want to avoid inlining in certain 1 argument scenarios. | |
| 7317 if (argument_count == 1) { | |
| 7318 HValue* argument = Top(); | |
| 7319 if (argument->IsConstant()) { | |
| 7320 // Do not inline if the constant length argument is not a smi or | |
| 7321 // outside the valid range for a fast array. | |
| 7322 HConstant* constant_argument = HConstant::cast(argument); | |
| 7323 if (constant_argument->HasSmiValue()) { | |
| 7324 int value = constant_argument->Integer32Value(); | |
| 7325 inline_ok = value >= 0 && | |
| 7326 value < JSObject::kInitialMaxFastElementArray; | |
| 7327 if (!inline_ok) { | |
| 7328 TraceInline(target, caller, | |
| 7329 "Length outside of valid array range"); | |
| 7330 } | |
| 7331 } | |
| 7332 } else { | |
| 7333 // The amount of code we'd have to generate doubles if we have a | |
| 7334 // non-constant length, but packed elements_kind feedback. Don't | |
| 7335 // inline this case. | |
| 7336 inline_ok = IsHoleyElementsKind(expr->elements_kind()); | |
|
Toon Verwaest
2013/11/11 13:59:28
Shouldn't we just deopt if the passed length is no
mvstanton
2013/11/13 14:12:52
Yep, done. I also added a test in array-constructo
| |
| 7337 if (!inline_ok) { | |
| 7338 TraceInline(target, caller, | |
| 7339 "Non-holey elements kind for single argument"); | |
| 7340 } | |
| 7341 } | |
| 7342 } else { | |
| 7343 inline_ok = true; | |
| 7344 } | |
| 7345 } else { | |
| 7346 TraceInline(target, caller, "AllocationSite requested no inlining."); | |
| 7347 } | |
| 7348 | |
| 7349 if (inline_ok) { | |
| 7350 TraceInline(target, caller, NULL); | |
| 7351 } | |
| 7352 return inline_ok; | |
| 7353 } | |
| 7354 | |
| 7355 | |
| 7181 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { | 7356 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { |
| 7182 ASSERT(!HasStackOverflow()); | 7357 ASSERT(!HasStackOverflow()); |
| 7183 ASSERT(current_block() != NULL); | 7358 ASSERT(current_block() != NULL); |
| 7184 ASSERT(current_block()->HasPredecessor()); | 7359 ASSERT(current_block()->HasPredecessor()); |
| 7185 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); | 7360 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); |
| 7186 int argument_count = expr->arguments()->length() + 1; // Plus constructor. | 7361 int argument_count = expr->arguments()->length() + 1; // Plus constructor. |
| 7187 Factory* factory = isolate()->factory(); | 7362 Factory* factory = isolate()->factory(); |
| 7188 | 7363 |
| 7364 // The constructor function is on the stack in the unoptimized code | |
| 7365 // during evaluation of the arguments. | |
| 7366 CHECK_ALIVE(VisitForValue(expr->expression())); | |
| 7367 HValue* function = Top(); | |
| 7368 CHECK_ALIVE(VisitExpressions(expr->arguments())); | |
| 7369 | |
| 7189 if (FLAG_inline_construct && | 7370 if (FLAG_inline_construct && |
| 7190 expr->IsMonomorphic() && | 7371 expr->IsMonomorphic() && |
| 7191 IsAllocationInlineable(expr->target())) { | 7372 IsAllocationInlineable(expr->target())) { |
| 7192 // The constructor function is on the stack in the unoptimized code | |
| 7193 // during evaluation of the arguments. | |
| 7194 CHECK_ALIVE(VisitForValue(expr->expression())); | |
| 7195 HValue* function = Top(); | |
| 7196 CHECK_ALIVE(VisitExpressions(expr->arguments())); | |
| 7197 Handle<JSFunction> constructor = expr->target(); | 7373 Handle<JSFunction> constructor = expr->target(); |
| 7198 HValue* check = Add<HCheckValue>(function, constructor); | 7374 HValue* check = Add<HCheckValue>(function, constructor); |
| 7199 | 7375 |
| 7200 // Force completion of inobject slack tracking before generating | 7376 // Force completion of inobject slack tracking before generating |
| 7201 // allocation code to finalize instance size. | 7377 // allocation code to finalize instance size. |
| 7202 if (constructor->shared()->IsInobjectSlackTrackingInProgress()) { | 7378 if (constructor->shared()->IsInobjectSlackTrackingInProgress()) { |
| 7203 constructor->shared()->CompleteInobjectSlackTracking(); | 7379 constructor->shared()->CompleteInobjectSlackTracking(); |
| 7204 } | 7380 } |
| 7205 | 7381 |
| 7206 // Calculate instance size from initial map of constructor. | 7382 // Calculate instance size from initial map of constructor. |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 7273 check->DeleteAndReplaceWith(NULL); | 7449 check->DeleteAndReplaceWith(NULL); |
| 7274 environment()->SetExpressionStackAt(receiver_index, function); | 7450 environment()->SetExpressionStackAt(receiver_index, function); |
| 7275 HInstruction* call = | 7451 HInstruction* call = |
| 7276 PreProcessCall(New<HCallNew>(function, argument_count)); | 7452 PreProcessCall(New<HCallNew>(function, argument_count)); |
| 7277 return ast_context()->ReturnInstruction(call, expr->id()); | 7453 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7278 } else { | 7454 } else { |
| 7279 // The constructor function is both an operand to the instruction and an | 7455 // The constructor function is both an operand to the instruction and an |
| 7280 // argument to the construct call. | 7456 // argument to the construct call. |
| 7281 Handle<JSFunction> array_function( | 7457 Handle<JSFunction> array_function( |
| 7282 isolate()->global_context()->array_function(), isolate()); | 7458 isolate()->global_context()->array_function(), isolate()); |
| 7283 CHECK_ALIVE(VisitArgument(expr->expression())); | 7459 bool use_call_new_array = expr->target().is_identical_to(array_function); |
| 7284 HValue* constructor = HPushArgument::cast(Top())->argument(); | 7460 Handle<Cell> cell = expr->allocation_info_cell(); |
| 7285 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 7461 if (use_call_new_array && IsCallNewArrayInlineable(expr)) { |
| 7462 // Verify we are still calling the array function for our native context. | |
| 7463 Add<HCheckValue>(function, array_function); | |
| 7464 BuildInlinedCallNewArray(expr); | |
| 7465 return; | |
| 7466 } | |
| 7467 | |
| 7286 HBinaryCall* call; | 7468 HBinaryCall* call; |
| 7287 if (expr->target().is_identical_to(array_function)) { | 7469 if (use_call_new_array) { |
| 7288 Handle<Cell> cell = expr->allocation_info_cell(); | 7470 Add<HCheckValue>(function, array_function); |
| 7289 Add<HCheckValue>(constructor, array_function); | 7471 call = New<HCallNewArray>(function, argument_count, cell, |
| 7290 call = New<HCallNewArray>(constructor, argument_count, | 7472 expr->elements_kind()); |
| 7291 cell, expr->elements_kind()); | |
| 7292 } else { | 7473 } else { |
| 7293 call = New<HCallNew>(constructor, argument_count); | 7474 call = New<HCallNew>(function, argument_count); |
| 7294 } | 7475 } |
| 7295 Drop(argument_count); | 7476 PreProcessCall(call); |
| 7296 return ast_context()->ReturnInstruction(call, expr->id()); | 7477 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7297 } | 7478 } |
| 7298 } | 7479 } |
| 7299 | 7480 |
| 7300 | 7481 |
| 7301 // Support for generating inlined runtime functions. | 7482 // Support for generating inlined runtime functions. |
| 7302 | 7483 |
| 7303 // Lookup table for generators for runtime calls that are generated inline. | 7484 // Lookup table for generators for runtime calls that are generated inline. |
| 7304 // Elements of the table are member pointers to functions of | 7485 // Elements of the table are member pointers to functions of |
| 7305 // HOptimizedGraphBuilder. | 7486 // HOptimizedGraphBuilder. |
| (...skipping 2517 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 9823 if (ShouldProduceTraceOutput()) { | 10004 if (ShouldProduceTraceOutput()) { |
| 9824 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 10005 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 9825 } | 10006 } |
| 9826 | 10007 |
| 9827 #ifdef DEBUG | 10008 #ifdef DEBUG |
| 9828 graph_->Verify(false); // No full verify. | 10009 graph_->Verify(false); // No full verify. |
| 9829 #endif | 10010 #endif |
| 9830 } | 10011 } |
| 9831 | 10012 |
| 9832 } } // namespace v8::internal | 10013 } } // namespace v8::internal |
| OLD | NEW |