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 |