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 1697 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1708 } | 1708 } |
| 1709 | 1709 |
| 1710 | 1710 |
| 1711 MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map, | 1711 MaybeObject* JSObject::AddFastPropertyUsingMap(Map* new_map, |
| 1712 Name* name, | 1712 Name* name, |
| 1713 Object* value, | 1713 Object* value, |
| 1714 int field_index) { | 1714 int field_index) { |
| 1715 if (map()->unused_property_fields() == 0) { | 1715 if (map()->unused_property_fields() == 0) { |
| 1716 int new_unused = new_map->unused_property_fields(); | 1716 int new_unused = new_map->unused_property_fields(); |
| 1717 FixedArray* values; | 1717 FixedArray* values; |
| 1718 { MaybeObject* maybe_values = | 1718 MaybeObject* maybe_values = |
| 1719 properties()->CopySize(properties()->length() + new_unused + 1); | 1719 properties()->CopySize(properties()->length() + new_unused + 1); |
| 1720 if (!maybe_values->To(&values)) return maybe_values; | 1720 if (!maybe_values->To(&values)) return maybe_values; |
| 1721 } | 1721 |
| 1722 set_properties(values); | 1722 set_properties(values); |
| 1723 } | 1723 } |
| 1724 set_map(new_map); | 1724 set_map(new_map); |
| 1725 return FastPropertyAtPut(field_index, value); | 1725 return FastPropertyAtPut(field_index, value); |
| 1726 } | 1726 } |
| 1727 | 1727 |
| 1728 | 1728 |
| 1729 static bool IsIdentifier(UnicodeCache* cache, Name* name) { | 1729 static bool IsIdentifier(UnicodeCache* cache, Name* name) { |
| 1730 // Checks whether the buffer contains an identifier (no escape). | 1730 // Checks whether the buffer contains an identifier (no escape). |
| 1731 if (!name->IsString()) return false; | 1731 if (!name->IsString()) return false; |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1768 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 1768 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 1769 | 1769 |
| 1770 return AddSlowProperty(name, value, attributes); | 1770 return AddSlowProperty(name, value, attributes); |
| 1771 } | 1771 } |
| 1772 | 1772 |
| 1773 // Compute the new index for new field. | 1773 // Compute the new index for new field. |
| 1774 int index = map()->NextFreePropertyIndex(); | 1774 int index = map()->NextFreePropertyIndex(); |
| 1775 | 1775 |
| 1776 // Allocate new instance descriptors with (name, index) added | 1776 // Allocate new instance descriptors with (name, index) added |
| 1777 FieldDescriptor new_field(name, index, attributes, 0); | 1777 FieldDescriptor new_field(name, index, attributes, 0); |
| 1778 new_field.SetStorageType(value->RequiredStorage()); | |
| 1778 | 1779 |
| 1779 ASSERT(index < map()->inobject_properties() || | 1780 ASSERT(index < map()->inobject_properties() || |
| 1780 (index - map()->inobject_properties()) < properties()->length() || | 1781 (index - map()->inobject_properties()) < properties()->length() || |
| 1781 map()->unused_property_fields() == 0); | 1782 map()->unused_property_fields() == 0); |
| 1782 | 1783 |
| 1783 FixedArray* values = NULL; | 1784 FixedArray* values = NULL; |
| 1784 | 1785 |
| 1785 if (map()->unused_property_fields() == 0) { | 1786 if (map()->unused_property_fields() == 0) { |
| 1786 // Make room for the new value | 1787 // Make room for the new value |
| 1787 MaybeObject* maybe_values = | 1788 MaybeObject* maybe_values = |
| (...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2021 if (!maybe_result->To(&result)) return maybe_result; | 2022 if (!maybe_result->To(&result)) return maybe_result; |
| 2022 | 2023 |
| 2023 if (!HasFastProperties()) return result; | 2024 if (!HasFastProperties()) return result; |
| 2024 | 2025 |
| 2025 // This method should only be used to convert existing transitions. | 2026 // This method should only be used to convert existing transitions. |
| 2026 Map* new_map = map(); | 2027 Map* new_map = map(); |
| 2027 | 2028 |
| 2028 // TODO(verwaest): From here on we lose existing map transitions, causing | 2029 // TODO(verwaest): From here on we lose existing map transitions, causing |
| 2029 // invalid back pointers. This will change once we can store multiple | 2030 // invalid back pointers. This will change once we can store multiple |
| 2030 // transitions with the same key. | 2031 // transitions with the same key. |
| 2031 | |
| 2032 bool owned_descriptors = old_map->owns_descriptors(); | 2032 bool owned_descriptors = old_map->owns_descriptors(); |
| 2033 if (owned_descriptors || | 2033 if (owned_descriptors || |
| 2034 old_target->instance_descriptors() == old_map->instance_descriptors()) { | 2034 old_target->instance_descriptors() == old_map->instance_descriptors()) { |
| 2035 // Since the conversion above generated a new fast map with an additional | 2035 // Since the conversion above generated a new fast map with an additional |
| 2036 // property which can be shared as well, install this descriptor pointer | 2036 // property which can be shared as well, install this descriptor pointer |
| 2037 // along the entire chain of smaller maps. | 2037 // along the entire chain of smaller maps. |
| 2038 Map* map; | 2038 Map* map; |
| 2039 DescriptorArray* new_descriptors = new_map->instance_descriptors(); | 2039 DescriptorArray* new_descriptors = new_map->instance_descriptors(); |
| 2040 DescriptorArray* old_descriptors = old_map->instance_descriptors(); | 2040 DescriptorArray* old_descriptors = old_map->instance_descriptors(); |
| 2041 for (Object* current = old_map; | 2041 for (Object* current = old_map; |
| 2042 !current->IsUndefined(); | 2042 !current->IsUndefined(); |
| 2043 current = map->GetBackPointer()) { | 2043 current = map->GetBackPointer()) { |
| 2044 map = Map::cast(current); | 2044 map = Map::cast(current); |
| 2045 if (map->instance_descriptors() != old_descriptors) break; | 2045 if (map->instance_descriptors() != old_descriptors) break; |
| 2046 map->SetEnumLength(Map::kInvalidEnumCache); | 2046 map->SetEnumLength(Map::kInvalidEnumCache); |
| 2047 map->set_instance_descriptors(new_descriptors); | 2047 map->set_instance_descriptors(new_descriptors); |
| 2048 } | 2048 } |
| 2049 old_map->set_owns_descriptors(false); | 2049 old_map->set_owns_descriptors(false); |
| 2050 } | 2050 } |
| 2051 | 2051 |
| 2052 old_target->InvalidateTransitionTree(); | |
|
danno
2013/04/24 15:23:00
nit: How about InvalidateMapTransitionTree()?
| |
| 2053 | |
| 2052 old_map->SetTransition(transition_index, new_map); | 2054 old_map->SetTransition(transition_index, new_map); |
| 2053 new_map->SetBackPointer(old_map); | 2055 new_map->SetBackPointer(old_map); |
| 2054 return result; | 2056 return result; |
| 2055 } | 2057 } |
| 2056 | 2058 |
| 2057 | 2059 |
| 2058 MaybeObject* JSObject::ConvertDescriptorToField(Name* name, | 2060 MaybeObject* JSObject::ConvertDescriptorToField(Name* name, |
| 2059 Object* new_value, | 2061 Object* new_value, |
| 2060 PropertyAttributes attributes) { | 2062 PropertyAttributes attributes) { |
| 2061 if (map()->unused_property_fields() == 0 && | 2063 if (map()->unused_property_fields() == 0 && |
| 2062 TooManyFastProperties(properties()->length(), MAY_BE_STORE_FROM_KEYED)) { | 2064 TooManyFastProperties(properties()->length(), MAY_BE_STORE_FROM_KEYED)) { |
| 2063 Object* obj; | 2065 Object* obj; |
| 2064 MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); | 2066 MaybeObject* maybe_obj = NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0); |
| 2065 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 2067 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 2066 return ReplaceSlowProperty(name, new_value, attributes); | 2068 return ReplaceSlowProperty(name, new_value, attributes); |
| 2067 } | 2069 } |
| 2068 | 2070 |
| 2069 int index = map()->NextFreePropertyIndex(); | 2071 int index = map()->NextFreePropertyIndex(); |
| 2070 FieldDescriptor new_field(name, index, attributes, 0); | 2072 FieldDescriptor new_field(name, index, attributes, 0); |
| 2073 new_field.SetStorageType(new_value->RequiredStorage()); | |
| 2071 | 2074 |
| 2072 // Make a new map for the object. | 2075 // Make a new map for the object. |
| 2073 Map* new_map; | 2076 Map* new_map; |
| 2074 MaybeObject* maybe_new_map = map()->CopyInsertDescriptor(&new_field, | 2077 MaybeObject* maybe_new_map = map()->CopyInsertDescriptor(&new_field, |
| 2075 OMIT_TRANSITION); | 2078 OMIT_TRANSITION); |
| 2076 if (!maybe_new_map->To(&new_map)) return maybe_new_map; | 2079 if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
| 2077 | 2080 |
| 2078 // Make new properties array if necessary. | 2081 // Make new properties array if necessary. |
| 2079 FixedArray* new_properties = NULL; | 2082 FixedArray* new_properties = NULL; |
| 2080 int new_unused_property_fields = map()->unused_property_fields() - 1; | 2083 int new_unused_property_fields = map()->unused_property_fields() - 1; |
| 2081 if (map()->unused_property_fields() == 0) { | 2084 if (map()->unused_property_fields() == 0) { |
| 2082 new_unused_property_fields = kFieldsAdded - 1; | 2085 new_unused_property_fields = kFieldsAdded - 1; |
| 2083 MaybeObject* maybe_new_properties = | 2086 MaybeObject* maybe_new_properties = |
| 2084 properties()->CopySize(properties()->length() + kFieldsAdded); | 2087 properties()->CopySize(properties()->length() + kFieldsAdded); |
| 2085 if (!maybe_new_properties->To(&new_properties)) return maybe_new_properties; | 2088 if (!maybe_new_properties->To(&new_properties)) return maybe_new_properties; |
| 2086 } | 2089 } |
| 2087 | 2090 |
| 2088 // Update pointers to commit changes. | 2091 // Update pointers to commit changes. |
| 2089 // Object points to the new map. | 2092 // Object points to the new map. |
| 2090 new_map->set_unused_property_fields(new_unused_property_fields); | 2093 new_map->set_unused_property_fields(new_unused_property_fields); |
| 2091 set_map(new_map); | 2094 set_map(new_map); |
| 2092 if (new_properties != NULL) { | 2095 if (new_properties != NULL) { |
| 2093 set_properties(new_properties); | 2096 set_properties(new_properties); |
| 2094 } | 2097 } |
| 2095 return FastPropertyAtPut(index, new_value); | 2098 return FastPropertyAtPut(index, new_value); |
| 2096 } | 2099 } |
| 2097 | 2100 |
| 2098 | 2101 |
| 2102 enum RightTrimMode { FROM_GC, FROM_MUTATOR }; | |
| 2103 | |
| 2104 | |
| 2105 static void ZapEndOfFixedArray(Address new_end, int to_trim) { | |
| 2106 // If we are doing a big trim in old space then we zap the space. | |
| 2107 Object** zap = reinterpret_cast<Object**>(new_end); | |
| 2108 zap++; // Header of filler must be at least one word so skip that. | |
| 2109 for (int i = 1; i < to_trim; i++) { | |
| 2110 *zap++ = Smi::FromInt(0); | |
| 2111 } | |
| 2112 } | |
| 2113 | |
| 2114 | |
| 2115 template<RightTrimMode trim_mode> | |
| 2116 static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) { | |
| 2117 ASSERT(elms->map() != HEAP->fixed_cow_array_map()); | |
| 2118 // For now this trick is only applied to fixed arrays in new and paged space. | |
| 2119 ASSERT(!HEAP->lo_space()->Contains(elms)); | |
| 2120 | |
| 2121 const int len = elms->length(); | |
| 2122 | |
| 2123 ASSERT(to_trim < len); | |
| 2124 | |
| 2125 Address new_end = elms->address() + FixedArray::SizeFor(len - to_trim); | |
| 2126 | |
| 2127 if (trim_mode != FROM_GC || Heap::ShouldZapGarbage()) { | |
| 2128 ZapEndOfFixedArray(new_end, to_trim); | |
| 2129 } | |
| 2130 | |
| 2131 int size_delta = to_trim * kPointerSize; | |
| 2132 | |
| 2133 // Technically in new space this write might be omitted (except for | |
| 2134 // debug mode which iterates through the heap), but to play safer | |
| 2135 // we still do it. | |
| 2136 heap->CreateFillerObjectAt(new_end, size_delta); | |
| 2137 | |
| 2138 elms->set_length(len - to_trim); | |
| 2139 | |
| 2140 // Maintain marking consistency for IncrementalMarking. | |
| 2141 if (Marking::IsBlack(Marking::MarkBitFrom(elms))) { | |
| 2142 if (trim_mode == FROM_GC) { | |
| 2143 MemoryChunk::IncrementLiveBytesFromGC(elms->address(), -size_delta); | |
| 2144 } else { | |
| 2145 MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta); | |
| 2146 } | |
| 2147 } | |
| 2148 } | |
| 2149 | |
| 2150 | |
| 2151 MaybeObject* JSObject::MigrateToMap(Map* new_map) { | |
| 2152 Heap* heap = GetHeap(); | |
| 2153 Map* old_map = map(); | |
| 2154 int number_of_fields = new_map->NumberOfFields(); | |
| 2155 | |
| 2156 // Nothing to do if no functions were converted to fields. | |
| 2157 if (old_map->NumberOfFields() == number_of_fields && | |
| 2158 (old_map->inobject_properties() == new_map->inobject_properties() || | |
| 2159 number_of_fields < new_map->inobject_properties())) { | |
| 2160 ASSERT(map()->inobject_properties() == new_map->inobject_properties() || | |
| 2161 new_map->NumberOfFields() <= new_map->inobject_properties()); | |
| 2162 ASSERT(map()->unused_property_fields() == | |
| 2163 (new_map->unused_property_fields() + | |
| 2164 map()->inobject_properties() - | |
| 2165 new_map->inobject_properties())); | |
| 2166 set_map(new_map); | |
| 2167 return this; | |
| 2168 } | |
| 2169 | |
| 2170 int inobject = new_map->inobject_properties(); | |
| 2171 int total_size = number_of_fields + new_map->unused_property_fields(); | |
| 2172 int external = total_size - inobject; | |
| 2173 FixedArray* array; | |
| 2174 MaybeObject* maybe_array = heap->AllocateFixedArray(total_size); | |
| 2175 if (!maybe_array->To(&array)) return maybe_array; | |
| 2176 | |
| 2177 DescriptorArray* old_descriptors = old_map->instance_descriptors(); | |
| 2178 DescriptorArray* new_descriptors = new_map->instance_descriptors(); | |
| 2179 int descriptors = new_map->NumberOfOwnDescriptors(); | |
| 2180 | |
| 2181 for (int i = 0; i < descriptors; i++) { | |
| 2182 PropertyDetails details = new_descriptors->GetDetails(i); | |
| 2183 if (details.type() != FIELD) continue; | |
| 2184 PropertyDetails old_details = old_descriptors->GetDetails(i); | |
| 2185 ASSERT(old_details.type() == CONSTANT_FUNCTION || | |
| 2186 old_details.type() == FIELD); | |
| 2187 Object* value = old_details.type() == CONSTANT_FUNCTION | |
| 2188 ? old_descriptors->GetValue(i) | |
| 2189 : FastPropertyAt(old_descriptors->GetFieldIndex(i)); | |
| 2190 int target_index = new_descriptors->GetFieldIndex(i) - inobject; | |
| 2191 if (target_index < 0) target_index += total_size; | |
| 2192 array->set(target_index, value); | |
| 2193 } | |
| 2194 | |
| 2195 // From here on we cannot fail anymore. | |
| 2196 | |
| 2197 // Copy (real) inobject properties. | |
| 2198 int limit = Min(inobject, number_of_fields); | |
| 2199 for (int i = 0; i < limit; i++) { | |
| 2200 FastPropertyAtPut(i, array->get(external + i)); | |
| 2201 } | |
| 2202 | |
| 2203 // Create filler object past the new instance size. | |
| 2204 int new_instance_size = new_map->instance_size(); | |
| 2205 int instance_size_delta = old_map->instance_size() - new_instance_size; | |
| 2206 ASSERT(instance_size_delta >= 0); | |
| 2207 Address address = this->address() + new_instance_size; | |
| 2208 heap->CreateFillerObjectAt(address, instance_size_delta); | |
| 2209 | |
| 2210 // If there are properties in the new backing store, trim it to the correct | |
| 2211 // size and install the backing store into the object. | |
| 2212 if (external > 0) { | |
| 2213 RightTrimFixedArray<FROM_MUTATOR>(heap, array, inobject); | |
| 2214 set_properties(array); | |
| 2215 } | |
| 2216 | |
| 2217 set_map(new_map); | |
| 2218 | |
| 2219 return this; | |
| 2220 } | |
| 2221 | |
| 2222 | |
| 2223 MaybeObject* JSObject::GeneralizeFieldStorage(int modify_index, | |
| 2224 StorageType new_storage) { | |
| 2225 Map* new_map; | |
| 2226 MaybeObject* maybe_new_map = | |
| 2227 map()->GeneralizeStorage(modify_index, new_storage); | |
| 2228 if (!maybe_new_map->To(&new_map)) return maybe_new_map; | |
| 2229 ASSERT(map() != new_map || new_map->FindRootMap()->is_invalid_transition()); | |
| 2230 | |
| 2231 return MigrateToMap(new_map); | |
| 2232 } | |
| 2233 | |
| 2234 | |
| 2235 int Map::NumberOfFields() { | |
| 2236 DescriptorArray* descriptors = instance_descriptors(); | |
| 2237 int result = 0; | |
| 2238 for (int i = 0; i < NumberOfOwnDescriptors(); i++) { | |
| 2239 if (descriptors->GetDetails(i).type() == FIELD) result++; | |
| 2240 } | |
| 2241 return result; | |
| 2242 } | |
| 2243 | |
| 2244 | |
| 2245 MaybeObject* Map::CopyGeneralizeStorage(int modify_index, | |
| 2246 StorageType new_storage) { | |
| 2247 Map* new_map; | |
| 2248 MaybeObject* maybe_map = this->Copy(); | |
| 2249 if (!maybe_map->To(&new_map)) return maybe_map; | |
| 2250 | |
| 2251 new_map->instance_descriptors()->InitializeStorageTypes(TAGGED); | |
| 2252 return new_map; | |
| 2253 } | |
| 2254 | |
| 2255 | |
| 2256 void Map::InvalidateTransitionTree() { | |
| 2257 if (is_invalid_transition()) return; | |
| 2258 if (HasTransitionArray()) { | |
| 2259 TransitionArray* transitions = this->transitions(); | |
| 2260 for (int i = 0; i < transitions->number_of_transitions(); i++) { | |
| 2261 transitions->GetTarget(i)->InvalidateTransitionTree(); | |
| 2262 } | |
| 2263 } | |
| 2264 invalidate_transition(); | |
| 2265 dependent_code()->DeoptimizeDependentCodeGroup( | |
| 2266 GetIsolate(), DependentCode::kFieldTransitionGroup); | |
| 2267 dependent_code()->DeoptimizeDependentCodeGroup( | |
| 2268 GetIsolate(), DependentCode::kPrototypeCheckGroup); | |
| 2269 } | |
| 2270 | |
| 2271 | |
| 2272 void Map::InvalidateTarget(Name* key, DescriptorArray* new_descriptors) { | |
| 2273 if (HasTransitionArray()) { | |
| 2274 TransitionArray* transitions = this->transitions(); | |
| 2275 int transition = transitions->Search(key); | |
| 2276 if (transition != TransitionArray::kNotFound) { | |
| 2277 transitions->GetTarget(transition)->InvalidateTransitionTree(); | |
| 2278 } | |
| 2279 } | |
| 2280 | |
| 2281 // Don't overwrite the empty descriptor array. | |
| 2282 if (NumberOfOwnDescriptors() == 0) return; | |
| 2283 | |
| 2284 DescriptorArray* to_replace = instance_descriptors(); | |
| 2285 Map* current = this; | |
| 2286 while (current->instance_descriptors() == to_replace) { | |
| 2287 current->SetEnumLength(Map::kInvalidEnumCache); | |
| 2288 current->set_instance_descriptors(new_descriptors); | |
| 2289 Object* next = current->GetBackPointer(); | |
| 2290 if (next->IsUndefined()) break; | |
| 2291 current = Map::cast(next); | |
| 2292 } | |
| 2293 | |
| 2294 set_owns_descriptors(false); | |
| 2295 } | |
| 2296 | |
| 2297 | |
| 2298 bool Map::TransitionsTo(Map* other) { | |
| 2299 if (!HasTransitionArray()) return false; | |
| 2300 | |
| 2301 int descriptor = other->LastAdded(); | |
| 2302 Name* name = other->instance_descriptors()->GetKey(descriptor); | |
| 2303 | |
| 2304 TransitionArray* transitions = this->transitions(); | |
| 2305 int transition = transitions->Search(name); | |
| 2306 if (transition == TransitionArray::kNotFound) return false; | |
| 2307 | |
| 2308 return transitions->GetTarget(transition) == other; | |
| 2309 } | |
| 2310 | |
| 2311 | |
| 2312 Map* Map::FindRootMap() { | |
| 2313 Map* result = this; | |
| 2314 while (true) { | |
| 2315 Object* back = result->GetBackPointer(); | |
| 2316 if (back->IsUndefined()) return result; | |
| 2317 result = Map::cast(back); | |
| 2318 } | |
| 2319 } | |
| 2320 | |
| 2321 | |
| 2322 Map* Map::FindUpdatedMap(int length, DescriptorArray* descriptors) { | |
| 2323 // This can only be called on roots of transition trees. | |
| 2324 ASSERT(GetBackPointer()->IsUndefined()); | |
| 2325 | |
| 2326 Map* current = this; | |
| 2327 | |
| 2328 for (int i = 0; i < length; i++) { | |
| 2329 if (!current->HasTransitionArray()) break; | |
| 2330 Name* name = descriptors->GetKey(i); | |
| 2331 TransitionArray* transitions = current->transitions(); | |
| 2332 int transition = transitions->Search(name); | |
| 2333 if (transition == TransitionArray::kNotFound) break; | |
| 2334 current = transitions->GetTarget(transition); | |
| 2335 } | |
| 2336 | |
| 2337 return current; | |
| 2338 } | |
| 2339 | |
| 2340 | |
| 2341 Map* Map::FindLastMatchMap(DescriptorArray* descriptors) { | |
| 2342 // This can only be called on roots of transition trees. | |
| 2343 ASSERT(GetBackPointer()->IsUndefined()); | |
| 2344 | |
| 2345 Map* current = this; | |
| 2346 int length = descriptors->number_of_descriptors(); | |
| 2347 | |
| 2348 for (int i = 0; i < length; i++) { | |
| 2349 if (!current->HasTransitionArray()) break; | |
| 2350 Name* name = descriptors->GetKey(i); | |
| 2351 TransitionArray* transitions = current->transitions(); | |
| 2352 int transition = transitions->Search(name); | |
| 2353 if (transition == TransitionArray::kNotFound) break; | |
| 2354 | |
| 2355 Map* next = transitions->GetTarget(transition); | |
| 2356 DescriptorArray* next_descriptors = next->instance_descriptors(); | |
| 2357 | |
| 2358 if (next_descriptors->GetValue(i) != descriptors->GetValue(i)) break; | |
| 2359 | |
| 2360 PropertyDetails details = descriptors->GetDetails(i); | |
| 2361 PropertyDetails next_details = next_descriptors->GetDetails(i); | |
| 2362 if (details.type() != next_details.type()) break; | |
| 2363 if (details.attributes() != next_details.attributes()) break; | |
| 2364 if (details.storage_type() != next_details.storage_type()) break; | |
| 2365 ASSERT(!details.IsDeleted()); | |
| 2366 ASSERT(!next_details.IsDeleted()); | |
| 2367 | |
| 2368 current = next; | |
| 2369 } | |
| 2370 return current; | |
| 2371 } | |
| 2372 | |
| 2373 | |
| 2374 MaybeObject* Map::GeneralizeStorage(int modify_index, StorageType new_storage) { | |
| 2375 Map* old_map = this; | |
| 2376 DescriptorArray* old_descriptors = old_map->instance_descriptors(); | |
| 2377 StorageType old_storage = | |
| 2378 old_descriptors->GetDetails(modify_index).storage_type(); | |
| 2379 | |
| 2380 if (old_storage == ANY) { | |
| 2381 old_descriptors->SetStorageType(modify_index, new_storage); | |
| 2382 return this; | |
| 2383 } | |
| 2384 | |
| 2385 int descriptors = old_map->NumberOfOwnDescriptors(); | |
| 2386 Map* root_map = old_map->FindRootMap(); | |
| 2387 | |
| 2388 if (!old_map->EquivalentToForTransition(root_map)) { | |
| 2389 return CopyGeneralizeStorage(modify_index, new_storage); | |
| 2390 } | |
| 2391 | |
| 2392 Map* updated = root_map->FindUpdatedMap(descriptors, old_descriptors); | |
| 2393 // Check the state of the root map. | |
| 2394 DescriptorArray* updated_descriptors = updated->instance_descriptors(); | |
| 2395 | |
| 2396 DescriptorArray* new_descriptors; | |
| 2397 MaybeObject* maybe_descriptors = updated_descriptors->Merge( | |
| 2398 root_map->NumberOfOwnDescriptors(), | |
| 2399 updated->NumberOfOwnDescriptors(), | |
| 2400 descriptors, | |
| 2401 old_descriptors); | |
| 2402 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; | |
| 2403 | |
| 2404 if (IsMoreGeneralStorageType( | |
| 2405 new_storage, | |
| 2406 new_descriptors->GetDetails(modify_index).storage_type())) { | |
| 2407 new_descriptors->SetStorageType(modify_index, new_storage); | |
| 2408 } | |
| 2409 | |
| 2410 Map* split_map = root_map->FindLastMatchMap(new_descriptors); | |
| 2411 | |
| 2412 int descriptor = split_map->NumberOfOwnDescriptors(); | |
| 2413 // Check whether |split_map| matches what we were looking for. If so, return | |
| 2414 // it. | |
| 2415 if (descriptors == descriptor) return split_map; | |
| 2416 | |
| 2417 split_map->InvalidateTarget( | |
| 2418 old_descriptors->GetKey(descriptor), new_descriptors); | |
| 2419 | |
| 2420 Map* new_map = split_map; | |
| 2421 // Add missing transitions. | |
| 2422 for (; descriptor < descriptors; descriptor++) { | |
| 2423 MaybeObject* maybe_map = new_map->CopyInstallDescriptors( | |
| 2424 descriptor, new_descriptors); | |
| 2425 if (!maybe_map->To(&new_map)) { | |
| 2426 // Create a handle for the last created map to ensure it stays alive | |
| 2427 // during GC. Its descriptor array is too large, but it will be | |
| 2428 // overwritten during retry anyway. | |
| 2429 Handle<Map>(new_map); | |
| 2430 } | |
| 2431 } | |
| 2432 | |
| 2433 new_map->set_owns_descriptors(true); | |
| 2434 return new_map; | |
| 2435 } | |
| 2436 | |
| 2099 | 2437 |
| 2100 MaybeObject* JSObject::SetPropertyWithInterceptor( | 2438 MaybeObject* JSObject::SetPropertyWithInterceptor( |
| 2101 Name* name, | 2439 Name* name, |
| 2102 Object* value, | 2440 Object* value, |
| 2103 PropertyAttributes attributes, | 2441 PropertyAttributes attributes, |
| 2104 StrictModeFlag strict_mode) { | 2442 StrictModeFlag strict_mode) { |
| 2105 // TODO(rossberg): Support symbols in the API. | 2443 // TODO(rossberg): Support symbols in the API. |
| 2106 if (name->IsSymbol()) return value; | 2444 if (name->IsSymbol()) return value; |
| 2107 Isolate* isolate = GetIsolate(); | 2445 Isolate* isolate = GetIsolate(); |
| 2108 HandleScope scope(isolate); | 2446 HandleScope scope(isolate); |
| (...skipping 275 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2384 if (strict_mode == kNonStrictMode) return value; | 2722 if (strict_mode == kNonStrictMode) return value; |
| 2385 Handle<Object> args[] = { Handle<Object>(name, isolate), | 2723 Handle<Object> args[] = { Handle<Object>(name, isolate), |
| 2386 Handle<Object>(this, isolate)}; | 2724 Handle<Object>(this, isolate)}; |
| 2387 return isolate->Throw(*isolate->factory()->NewTypeError( | 2725 return isolate->Throw(*isolate->factory()->NewTypeError( |
| 2388 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)))); | 2726 "strict_read_only_property", HandleVector(args, ARRAY_SIZE(args)))); |
| 2389 } | 2727 } |
| 2390 return heap->the_hole_value(); | 2728 return heap->the_hole_value(); |
| 2391 } | 2729 } |
| 2392 | 2730 |
| 2393 | 2731 |
| 2394 enum RightTrimMode { FROM_GC, FROM_MUTATOR }; | |
| 2395 | |
| 2396 | |
| 2397 static void ZapEndOfFixedArray(Address new_end, int to_trim) { | |
| 2398 // If we are doing a big trim in old space then we zap the space. | |
| 2399 Object** zap = reinterpret_cast<Object**>(new_end); | |
| 2400 zap++; // Header of filler must be at least one word so skip that. | |
| 2401 for (int i = 1; i < to_trim; i++) { | |
| 2402 *zap++ = Smi::FromInt(0); | |
| 2403 } | |
| 2404 } | |
| 2405 | |
| 2406 | |
| 2407 template<RightTrimMode trim_mode> | |
| 2408 static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) { | |
| 2409 ASSERT(elms->map() != HEAP->fixed_cow_array_map()); | |
| 2410 // For now this trick is only applied to fixed arrays in new and paged space. | |
| 2411 ASSERT(!HEAP->lo_space()->Contains(elms)); | |
| 2412 | |
| 2413 const int len = elms->length(); | |
| 2414 | |
| 2415 ASSERT(to_trim < len); | |
| 2416 | |
| 2417 Address new_end = elms->address() + FixedArray::SizeFor(len - to_trim); | |
| 2418 | |
| 2419 if (trim_mode != FROM_GC || Heap::ShouldZapGarbage()) { | |
| 2420 ZapEndOfFixedArray(new_end, to_trim); | |
| 2421 } | |
| 2422 | |
| 2423 int size_delta = to_trim * kPointerSize; | |
| 2424 | |
| 2425 // Technically in new space this write might be omitted (except for | |
| 2426 // debug mode which iterates through the heap), but to play safer | |
| 2427 // we still do it. | |
| 2428 heap->CreateFillerObjectAt(new_end, size_delta); | |
| 2429 | |
| 2430 elms->set_length(len - to_trim); | |
| 2431 | |
| 2432 // Maintain marking consistency for IncrementalMarking. | |
| 2433 if (Marking::IsBlack(Marking::MarkBitFrom(elms))) { | |
| 2434 if (trim_mode == FROM_GC) { | |
| 2435 MemoryChunk::IncrementLiveBytesFromGC(elms->address(), -size_delta); | |
| 2436 } else { | |
| 2437 MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta); | |
| 2438 } | |
| 2439 } | |
| 2440 } | |
| 2441 | |
| 2442 | |
| 2443 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { | 2732 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { |
| 2444 Handle<DescriptorArray> descriptors(map->instance_descriptors()); | 2733 Handle<DescriptorArray> descriptors(map->instance_descriptors()); |
| 2445 if (slack <= descriptors->NumberOfSlackDescriptors()) return; | 2734 if (slack <= descriptors->NumberOfSlackDescriptors()) return; |
| 2446 int number_of_descriptors = descriptors->number_of_descriptors(); | 2735 int number_of_descriptors = descriptors->number_of_descriptors(); |
| 2447 Isolate* isolate = map->GetIsolate(); | 2736 Isolate* isolate = map->GetIsolate(); |
| 2448 Handle<DescriptorArray> new_descriptors = | 2737 Handle<DescriptorArray> new_descriptors = |
| 2449 isolate->factory()->NewDescriptorArray(number_of_descriptors, slack); | 2738 isolate->factory()->NewDescriptorArray(number_of_descriptors, slack); |
| 2450 DescriptorArray::WhitenessWitness witness(*new_descriptors); | 2739 DescriptorArray::WhitenessWitness witness(*new_descriptors); |
| 2451 | 2740 |
| 2452 for (int i = 0; i < number_of_descriptors; ++i) { | 2741 for (int i = 0; i < number_of_descriptors; ++i) { |
| (...skipping 643 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3096 return Handle<Object>(); | 3385 return Handle<Object>(); |
| 3097 } | 3386 } |
| 3098 trap = Handle<Object>(derived); | 3387 trap = Handle<Object>(derived); |
| 3099 } | 3388 } |
| 3100 | 3389 |
| 3101 bool threw; | 3390 bool threw; |
| 3102 return Execution::Call(trap, handler, argc, argv, &threw); | 3391 return Execution::Call(trap, handler, argc, argv, &threw); |
| 3103 } | 3392 } |
| 3104 | 3393 |
| 3105 | 3394 |
| 3106 void JSObject::AddFastPropertyUsingMap(Handle<JSObject> object, | |
| 3107 Handle<Map> map) { | |
| 3108 CALL_HEAP_FUNCTION_VOID( | |
| 3109 object->GetIsolate(), | |
| 3110 object->AddFastPropertyUsingMap(*map)); | |
| 3111 } | |
| 3112 | |
| 3113 | |
| 3114 void JSObject::TransitionToMap(Handle<JSObject> object, Handle<Map> map) { | 3395 void JSObject::TransitionToMap(Handle<JSObject> object, Handle<Map> map) { |
| 3115 CALL_HEAP_FUNCTION_VOID( | 3396 CALL_HEAP_FUNCTION_VOID( |
| 3116 object->GetIsolate(), | 3397 object->GetIsolate(), |
| 3117 object->TransitionToMap(*map)); | 3398 object->TransitionToMap(*map)); |
| 3118 } | 3399 } |
| 3119 | 3400 |
| 3120 | 3401 |
| 3402 void JSObject::MigrateInstance(Handle<JSObject> object) { | |
| 3403 CALL_HEAP_FUNCTION_VOID( | |
| 3404 object->GetIsolate(), | |
| 3405 object->MigrateInstance()); | |
| 3406 } | |
| 3407 | |
| 3408 | |
| 3121 MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup, | 3409 MaybeObject* JSObject::SetPropertyForResult(LookupResult* lookup, |
| 3122 Name* name_raw, | 3410 Name* name_raw, |
| 3123 Object* value_raw, | 3411 Object* value_raw, |
| 3124 PropertyAttributes attributes, | 3412 PropertyAttributes attributes, |
| 3125 StrictModeFlag strict_mode, | 3413 StrictModeFlag strict_mode, |
| 3126 StoreFromKeyed store_mode) { | 3414 StoreFromKeyed store_mode) { |
| 3127 Heap* heap = GetHeap(); | 3415 Heap* heap = GetHeap(); |
| 3128 Isolate* isolate = heap->isolate(); | 3416 Isolate* isolate = heap->isolate(); |
| 3129 // Make sure that the top context does not change when doing callbacks or | 3417 // Make sure that the top context does not change when doing callbacks or |
| 3130 // interceptor calls. | 3418 // interceptor calls. |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3199 old_value = Object::GetProperty(self, name); | 3487 old_value = Object::GetProperty(self, name); |
| 3200 } | 3488 } |
| 3201 | 3489 |
| 3202 // This is a real property that is not read-only, or it is a | 3490 // This is a real property that is not read-only, or it is a |
| 3203 // transition or null descriptor and there are no setters in the prototypes. | 3491 // transition or null descriptor and there are no setters in the prototypes. |
| 3204 MaybeObject* result = *value; | 3492 MaybeObject* result = *value; |
| 3205 switch (lookup->type()) { | 3493 switch (lookup->type()) { |
| 3206 case NORMAL: | 3494 case NORMAL: |
| 3207 result = lookup->holder()->SetNormalizedProperty(lookup, *value); | 3495 result = lookup->holder()->SetNormalizedProperty(lookup, *value); |
| 3208 break; | 3496 break; |
| 3209 case FIELD: | 3497 case FIELD: { |
| 3498 StorageType storage_type = lookup->storage_type(); | |
| 3499 if (!value->FitsStorage(storage_type)) { | |
| 3500 MaybeObject* maybe_failure = GeneralizeFieldStorage( | |
| 3501 lookup->GetDescriptorIndex(), value->RequiredStorage()); | |
| 3502 if (maybe_failure->IsFailure()) return maybe_failure; | |
| 3503 } | |
| 3210 result = lookup->holder()->FastPropertyAtPut( | 3504 result = lookup->holder()->FastPropertyAtPut( |
| 3211 lookup->GetFieldIndex().field_index(), *value); | 3505 lookup->GetFieldIndex().field_index(), *value); |
| 3212 break; | 3506 break; |
| 3507 } | |
| 3213 case CONSTANT_FUNCTION: | 3508 case CONSTANT_FUNCTION: |
| 3214 // Only replace the function if necessary. | 3509 // Only replace the function if necessary. |
| 3215 if (*value == lookup->GetConstantFunction()) return *value; | 3510 if (*value == lookup->GetConstantFunction()) return *value; |
| 3216 // Preserve the attributes of this existing property. | 3511 // Preserve the attributes of this existing property. |
| 3217 attributes = lookup->GetAttributes(); | 3512 attributes = lookup->GetAttributes(); |
| 3218 result = | 3513 result = |
| 3219 lookup->holder()->ConvertDescriptorToField(*name, *value, attributes); | 3514 lookup->holder()->ConvertDescriptorToField(*name, *value, attributes); |
| 3220 break; | 3515 break; |
| 3221 case CALLBACKS: { | 3516 case CALLBACKS: { |
| 3222 Object* callback_object = lookup->GetCallbackObject(); | 3517 Object* callback_object = lookup->GetCallbackObject(); |
| 3223 return self->SetPropertyWithCallback( | 3518 return self->SetPropertyWithCallback( |
| 3224 callback_object, *name, *value, lookup->holder(), strict_mode); | 3519 callback_object, *name, *value, lookup->holder(), strict_mode); |
| 3225 } | 3520 } |
| 3226 case INTERCEPTOR: | 3521 case INTERCEPTOR: |
| 3227 result = lookup->holder()->SetPropertyWithInterceptor( | 3522 result = lookup->holder()->SetPropertyWithInterceptor( |
| 3228 *name, *value, attributes, strict_mode); | 3523 *name, *value, attributes, strict_mode); |
| 3229 break; | 3524 break; |
| 3230 case TRANSITION: { | 3525 case TRANSITION: { |
| 3231 Map* transition_map = lookup->GetTransitionTarget(); | 3526 Map* transition_map = lookup->GetTransitionTarget(); |
| 3232 int descriptor = transition_map->LastAdded(); | 3527 int descriptor = transition_map->LastAdded(); |
| 3233 | 3528 |
| 3234 DescriptorArray* descriptors = transition_map->instance_descriptors(); | 3529 DescriptorArray* descriptors = transition_map->instance_descriptors(); |
| 3235 PropertyDetails details = descriptors->GetDetails(descriptor); | 3530 PropertyDetails details = descriptors->GetDetails(descriptor); |
| 3236 | 3531 |
| 3237 if (details.type() == FIELD) { | 3532 if (details.type() == FIELD) { |
| 3238 if (attributes == details.attributes()) { | 3533 if (attributes == details.attributes()) { |
| 3534 if (!value->FitsStorage(details.storage_type())) { | |
| 3535 MaybeObject* maybe_map = transition_map->GeneralizeStorage( | |
| 3536 descriptor, value->RequiredStorage()); | |
| 3537 if (!maybe_map->To(&transition_map)) return maybe_map; | |
| 3538 Object* back = transition_map->GetBackPointer(); | |
| 3539 if (back->IsMap()) { | |
| 3540 MaybeObject* maybe_failure = MigrateToMap(Map::cast(back)); | |
| 3541 if (maybe_failure->IsFailure()) return maybe_failure; | |
| 3542 } | |
| 3543 } | |
| 3239 int field_index = descriptors->GetFieldIndex(descriptor); | 3544 int field_index = descriptors->GetFieldIndex(descriptor); |
| 3240 result = lookup->holder()->AddFastPropertyUsingMap( | 3545 result = lookup->holder()->AddFastPropertyUsingMap( |
| 3241 transition_map, *name, *value, field_index); | 3546 transition_map, *name, *value, field_index); |
| 3242 } else { | 3547 } else { |
| 3243 result = lookup->holder()->ConvertDescriptorToField( | 3548 result = lookup->holder()->ConvertDescriptorToField( |
| 3244 *name, *value, attributes); | 3549 *name, *value, attributes); |
| 3245 } | 3550 } |
| 3246 } else if (details.type() == CALLBACKS) { | 3551 } else if (details.type() == CALLBACKS) { |
| 3247 result = lookup->holder()->ConvertDescriptorToField( | 3552 result = lookup->holder()->ConvertDescriptorToField( |
| 3248 *name, *value, attributes); | 3553 *name, *value, attributes); |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3363 } | 3668 } |
| 3364 | 3669 |
| 3365 // Check of IsReadOnly removed from here in clone. | 3670 // Check of IsReadOnly removed from here in clone. |
| 3366 MaybeObject* result = *value; | 3671 MaybeObject* result = *value; |
| 3367 switch (lookup.type()) { | 3672 switch (lookup.type()) { |
| 3368 case NORMAL: { | 3673 case NORMAL: { |
| 3369 PropertyDetails details = PropertyDetails(attributes, NORMAL); | 3674 PropertyDetails details = PropertyDetails(attributes, NORMAL); |
| 3370 result = self->SetNormalizedProperty(*name, *value, details); | 3675 result = self->SetNormalizedProperty(*name, *value, details); |
| 3371 break; | 3676 break; |
| 3372 } | 3677 } |
| 3373 case FIELD: | 3678 case FIELD: { |
| 3679 StorageType storage_type = lookup.storage_type(); | |
| 3680 if (!value->FitsStorage(storage_type)) { | |
| 3681 MaybeObject* maybe_failure = GeneralizeFieldStorage( | |
| 3682 lookup.GetDescriptorIndex(), value->RequiredStorage()); | |
| 3683 if (maybe_failure->IsFailure()) return maybe_failure; | |
| 3684 } | |
| 3374 result = self->FastPropertyAtPut( | 3685 result = self->FastPropertyAtPut( |
| 3375 lookup.GetFieldIndex().field_index(), *value); | 3686 lookup.GetFieldIndex().field_index(), *value); |
| 3376 break; | 3687 break; |
| 3688 } | |
| 3377 case CONSTANT_FUNCTION: | 3689 case CONSTANT_FUNCTION: |
| 3378 // Only replace the function if necessary. | 3690 // Only replace the function if necessary. |
| 3379 if (*value != lookup.GetConstantFunction()) { | 3691 if (*value != lookup.GetConstantFunction()) { |
| 3380 // Preserve the attributes of this existing property. | 3692 // Preserve the attributes of this existing property. |
| 3381 attributes = lookup.GetAttributes(); | 3693 attributes = lookup.GetAttributes(); |
| 3382 result = self->ConvertDescriptorToField(*name, *value, attributes); | 3694 result = self->ConvertDescriptorToField(*name, *value, attributes); |
| 3383 } | 3695 } |
| 3384 break; | 3696 break; |
| 3385 case CALLBACKS: | 3697 case CALLBACKS: |
| 3386 case INTERCEPTOR: | 3698 case INTERCEPTOR: |
| 3387 // Override callback in clone | 3699 // Override callback in clone |
| 3388 result = self->ConvertDescriptorToField(*name, *value, attributes); | 3700 result = self->ConvertDescriptorToField(*name, *value, attributes); |
| 3389 break; | 3701 break; |
| 3390 case TRANSITION: { | 3702 case TRANSITION: { |
| 3391 Map* transition_map = lookup.GetTransitionTarget(); | 3703 Map* transition_map = lookup.GetTransitionTarget(); |
| 3392 int descriptor = transition_map->LastAdded(); | 3704 int descriptor = transition_map->LastAdded(); |
| 3393 | 3705 |
| 3394 DescriptorArray* descriptors = transition_map->instance_descriptors(); | 3706 DescriptorArray* descriptors = transition_map->instance_descriptors(); |
| 3395 PropertyDetails details = descriptors->GetDetails(descriptor); | 3707 PropertyDetails details = descriptors->GetDetails(descriptor); |
| 3396 | 3708 |
| 3397 if (details.type() == FIELD) { | 3709 if (details.type() == FIELD) { |
| 3398 if (attributes == details.attributes()) { | 3710 if (attributes == details.attributes()) { |
| 3711 if (!value->FitsStorage(details.storage_type())) { | |
| 3712 MaybeObject* maybe_map = transition_map->GeneralizeStorage( | |
| 3713 descriptor, value->RequiredStorage()); | |
| 3714 if (!maybe_map->To(&transition_map)) return maybe_map; | |
| 3715 Object* back = transition_map->GetBackPointer(); | |
| 3716 if (back->IsMap()) { | |
| 3717 MaybeObject* maybe_failure = MigrateToMap(Map::cast(back)); | |
| 3718 if (maybe_failure->IsFailure()) return maybe_failure; | |
| 3719 } | |
| 3720 } | |
| 3399 int field_index = descriptors->GetFieldIndex(descriptor); | 3721 int field_index = descriptors->GetFieldIndex(descriptor); |
| 3400 result = self->AddFastPropertyUsingMap( | 3722 result = self->AddFastPropertyUsingMap( |
| 3401 transition_map, *name, *value, field_index); | 3723 transition_map, *name, *value, field_index); |
| 3402 } else { | 3724 } else { |
| 3403 result = self->ConvertDescriptorToField(*name, *value, attributes); | 3725 result = self->ConvertDescriptorToField(*name, *value, attributes); |
| 3404 } | 3726 } |
| 3405 } else if (details.type() == CALLBACKS) { | 3727 } else if (details.type() == CALLBACKS) { |
| 3406 result = self->ConvertDescriptorToField(*name, *value, attributes); | 3728 result = self->ConvertDescriptorToField(*name, *value, attributes); |
| 3407 } else { | 3729 } else { |
| 3408 ASSERT(details.type() == CONSTANT_FUNCTION); | 3730 ASSERT(details.type() == CONSTANT_FUNCTION); |
| (...skipping 1502 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 4911 for (int i = 0; i < limit; i++) { | 5233 for (int i = 0; i < limit; i++) { |
| 4912 if ((descs->GetDetails(i).attributes() & filter) == 0 && | 5234 if ((descs->GetDetails(i).attributes() & filter) == 0 && |
| 4913 ((filter & SYMBOLIC) == 0 || !descs->GetKey(i)->IsSymbol())) { | 5235 ((filter & SYMBOLIC) == 0 || !descs->GetKey(i)->IsSymbol())) { |
| 4914 result++; | 5236 result++; |
| 4915 } | 5237 } |
| 4916 } | 5238 } |
| 4917 return result; | 5239 return result; |
| 4918 } | 5240 } |
| 4919 | 5241 |
| 4920 | 5242 |
| 4921 int Map::PropertyIndexFor(Name* name) { | |
| 4922 DescriptorArray* descs = instance_descriptors(); | |
| 4923 int limit = NumberOfOwnDescriptors(); | |
| 4924 for (int i = 0; i < limit; i++) { | |
| 4925 if (name->Equals(descs->GetKey(i))) return descs->GetFieldIndex(i); | |
| 4926 } | |
| 4927 return -1; | |
| 4928 } | |
| 4929 | |
| 4930 | |
| 4931 int Map::NextFreePropertyIndex() { | 5243 int Map::NextFreePropertyIndex() { |
| 4932 int max_index = -1; | 5244 int max_index = -1; |
| 4933 int number_of_own_descriptors = NumberOfOwnDescriptors(); | 5245 int number_of_own_descriptors = NumberOfOwnDescriptors(); |
| 4934 DescriptorArray* descs = instance_descriptors(); | 5246 DescriptorArray* descs = instance_descriptors(); |
| 4935 for (int i = 0; i < number_of_own_descriptors; i++) { | 5247 for (int i = 0; i < number_of_own_descriptors; i++) { |
| 4936 if (descs->GetType(i) == FIELD) { | 5248 if (descs->GetType(i) == FIELD) { |
| 4937 int current_index = descs->GetFieldIndex(i); | 5249 int current_index = descs->GetFieldIndex(i); |
| 4938 if (current_index > max_index) max_index = current_index; | 5250 if (current_index > max_index) max_index = current_index; |
| 4939 } | 5251 } |
| 4940 } | 5252 } |
| (...skipping 830 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5771 if (!maybe_result->To(&result)) return maybe_result; | 6083 if (!maybe_result->To(&result)) return maybe_result; |
| 5772 | 6084 |
| 5773 result->InitializeDescriptors(descriptors); | 6085 result->InitializeDescriptors(descriptors); |
| 5774 | 6086 |
| 5775 if (flag == INSERT_TRANSITION && CanHaveMoreTransitions()) { | 6087 if (flag == INSERT_TRANSITION && CanHaveMoreTransitions()) { |
| 5776 TransitionArray* transitions; | 6088 TransitionArray* transitions; |
| 5777 SimpleTransitionFlag simple_flag = | 6089 SimpleTransitionFlag simple_flag = |
| 5778 (descriptor_index == descriptors->number_of_descriptors() - 1) | 6090 (descriptor_index == descriptors->number_of_descriptors() - 1) |
| 5779 ? SIMPLE_TRANSITION | 6091 ? SIMPLE_TRANSITION |
| 5780 : FULL_TRANSITION; | 6092 : FULL_TRANSITION; |
| 6093 ASSERT(name == descriptors->GetKey(descriptor_index)); | |
| 5781 MaybeObject* maybe_transitions = AddTransition(name, result, simple_flag); | 6094 MaybeObject* maybe_transitions = AddTransition(name, result, simple_flag); |
| 5782 if (!maybe_transitions->To(&transitions)) return maybe_transitions; | 6095 if (!maybe_transitions->To(&transitions)) return maybe_transitions; |
| 5783 | 6096 |
| 5784 set_transitions(transitions); | 6097 set_transitions(transitions); |
| 5785 result->SetBackPointer(this); | 6098 result->SetBackPointer(this); |
| 5786 } | 6099 } |
| 5787 | 6100 |
| 5788 return result; | 6101 return result; |
| 5789 } | 6102 } |
| 5790 | 6103 |
| 5791 | 6104 |
| 6105 MaybeObject* Map::CopyInstallDescriptors(int new_descriptor, | |
| 6106 DescriptorArray* descriptors) { | |
| 6107 ASSERT(descriptors->IsSortedNoDuplicates()); | |
| 6108 | |
| 6109 Map* result; | |
| 6110 MaybeObject* maybe_result = CopyDropDescriptors(); | |
| 6111 if (!maybe_result->To(&result)) return maybe_result; | |
| 6112 | |
| 6113 result->InitializeDescriptors(descriptors); | |
| 6114 result->SetNumberOfOwnDescriptors(new_descriptor + 1); | |
| 6115 | |
| 6116 int unused_property_fields = this->unused_property_fields(); | |
| 6117 if (descriptors->GetDetails(new_descriptor).type() == FIELD) { | |
| 6118 unused_property_fields = this->unused_property_fields() - 1; | |
| 6119 if (unused_property_fields < 0) { | |
| 6120 unused_property_fields += JSObject::kFieldsAdded; | |
| 6121 } | |
| 6122 } | |
| 6123 | |
| 6124 result->set_unused_property_fields(unused_property_fields); | |
| 6125 result->set_owns_descriptors(false); | |
| 6126 | |
| 6127 if (CanHaveMoreTransitions()) { | |
| 6128 Name* name = descriptors->GetKey(new_descriptor); | |
| 6129 TransitionArray* transitions; | |
| 6130 MaybeObject* maybe_transitions = | |
| 6131 AddTransition(name, result, SIMPLE_TRANSITION); | |
| 6132 if (!maybe_transitions->To(&transitions)) return maybe_transitions; | |
| 6133 | |
| 6134 set_transitions(transitions); | |
| 6135 result->SetBackPointer(this); | |
| 6136 } | |
| 6137 | |
| 6138 return result; | |
| 6139 } | |
| 6140 | |
| 6141 | |
| 5792 MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) { | 6142 MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) { |
| 5793 if (flag == INSERT_TRANSITION) { | 6143 if (flag == INSERT_TRANSITION) { |
| 5794 ASSERT(!HasElementsTransition() || | 6144 ASSERT(!HasElementsTransition() || |
| 5795 ((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS || | 6145 ((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS || |
| 5796 IsExternalArrayElementsKind( | 6146 IsExternalArrayElementsKind( |
| 5797 elements_transition_map()->elements_kind())) && | 6147 elements_transition_map()->elements_kind())) && |
| 5798 (kind == DICTIONARY_ELEMENTS || | 6148 (kind == DICTIONARY_ELEMENTS || |
| 5799 IsExternalArrayElementsKind(kind)))); | 6149 IsExternalArrayElementsKind(kind)))); |
| 5800 ASSERT(!IsFastElementsKind(kind) || | 6150 ASSERT(!IsFastElementsKind(kind) || |
| 5801 IsMoreGeneralElementsKindTransition(elements_kind(), kind)); | 6151 IsMoreGeneralElementsKindTransition(elements_kind(), kind)); |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 5850 JSFunction* ctor = JSFunction::cast(constructor()); | 6200 JSFunction* ctor = JSFunction::cast(constructor()); |
| 5851 Map* map = ctor->initial_map(); | 6201 Map* map = ctor->initial_map(); |
| 5852 DescriptorArray* descriptors = map->instance_descriptors(); | 6202 DescriptorArray* descriptors = map->instance_descriptors(); |
| 5853 | 6203 |
| 5854 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); | 6204 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); |
| 5855 DescriptorArray* new_descriptors; | 6205 DescriptorArray* new_descriptors; |
| 5856 MaybeObject* maybe_descriptors = | 6206 MaybeObject* maybe_descriptors = |
| 5857 descriptors->CopyUpTo(number_of_own_descriptors); | 6207 descriptors->CopyUpTo(number_of_own_descriptors); |
| 5858 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; | 6208 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
| 5859 | 6209 |
| 6210 new_descriptors->InitializeStorageTypes(TAGGED); | |
| 6211 | |
| 5860 return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION, 0); | 6212 return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION, 0); |
| 5861 } | 6213 } |
| 5862 | 6214 |
| 5863 | 6215 |
| 5864 MaybeObject* Map::Copy() { | 6216 MaybeObject* Map::Copy() { |
| 5865 DescriptorArray* descriptors = instance_descriptors(); | 6217 DescriptorArray* descriptors = instance_descriptors(); |
| 5866 DescriptorArray* new_descriptors; | 6218 DescriptorArray* new_descriptors; |
| 5867 int number_of_own_descriptors = NumberOfOwnDescriptors(); | 6219 int number_of_own_descriptors = NumberOfOwnDescriptors(); |
| 5868 MaybeObject* maybe_descriptors = | 6220 MaybeObject* maybe_descriptors = |
| 5869 descriptors->CopyUpTo(number_of_own_descriptors); | 6221 descriptors->CopyUpTo(number_of_own_descriptors); |
| (...skipping 935 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 6805 DescriptorArray* src, | 7157 DescriptorArray* src, |
| 6806 int src_index, | 7158 int src_index, |
| 6807 const WhitenessWitness& witness) { | 7159 const WhitenessWitness& witness) { |
| 6808 Object* value = src->GetValue(src_index); | 7160 Object* value = src->GetValue(src_index); |
| 6809 PropertyDetails details = src->GetDetails(src_index); | 7161 PropertyDetails details = src->GetDetails(src_index); |
| 6810 Descriptor desc(src->GetKey(src_index), value, details); | 7162 Descriptor desc(src->GetKey(src_index), value, details); |
| 6811 Set(dst_index, &desc, witness); | 7163 Set(dst_index, &desc, witness); |
| 6812 } | 7164 } |
| 6813 | 7165 |
| 6814 | 7166 |
| 7167 MaybeObject* DescriptorArray::Merge(int verbatim, | |
| 7168 int valid, | |
| 7169 int new_size, | |
| 7170 DescriptorArray* other) { | |
| 7171 ASSERT(verbatim <= valid); | |
| 7172 ASSERT(valid <= new_size); | |
| 7173 | |
| 7174 DescriptorArray* result; | |
| 7175 // Allocate a new descriptor array large enough to hold the required | |
| 7176 // descriptors, with minimally the exact same size as this descriptor array. | |
| 7177 MaybeObject* maybe_descriptors = DescriptorArray::Allocate( | |
| 7178 new_size, Max(new_size, number_of_descriptors()) - new_size); | |
| 7179 if (!maybe_descriptors->To(&result)) return maybe_descriptors; | |
| 7180 ASSERT(result->length() > length() || | |
| 7181 result->NumberOfSlackDescriptors() > 0 || | |
| 7182 result->number_of_descriptors() == other->number_of_descriptors()); | |
| 7183 ASSERT(result->number_of_descriptors() == new_size); | |
| 7184 | |
| 7185 DescriptorArray::WhitenessWitness witness(result); | |
| 7186 | |
| 7187 int descriptor; | |
| 7188 | |
| 7189 int current_offset = 0; | |
| 7190 for (descriptor = 0; descriptor < verbatim; descriptor++) { | |
| 7191 if (GetDetails(descriptor).type() == FIELD) current_offset++; | |
| 7192 result->CopyFrom(descriptor, this, descriptor, witness); | |
| 7193 } | |
| 7194 | |
| 7195 for (; descriptor < valid; descriptor++) { | |
| 7196 Name* key = GetKey(descriptor); | |
| 7197 PropertyDetails details = GetDetails(descriptor); | |
| 7198 PropertyDetails other_details = other->GetDetails(descriptor); | |
| 7199 ASSERT(details.attributes() == other_details.attributes()); | |
| 7200 | |
| 7201 if (details.type() == FIELD) { | |
| 7202 ASSERT(other_details.type() != CALLBACKS); | |
| 7203 FieldDescriptor d(key, | |
| 7204 current_offset++, | |
| 7205 details.attributes(), | |
| 7206 descriptor + 1); | |
| 7207 StorageType storage = | |
| 7208 IsMoreGeneralStorageType( | |
| 7209 other_details.storage_type(), details.storage_type()) | |
| 7210 ? other_details.storage_type() : details.storage_type(); | |
| 7211 d.SetStorageType(storage); | |
| 7212 result->Set(descriptor, &d, witness); | |
| 7213 } else if (other_details.type() == FIELD) { | |
| 7214 FieldDescriptor d(key, | |
| 7215 current_offset++, | |
| 7216 details.attributes(), | |
| 7217 descriptor + 1); | |
| 7218 StorageType storage = | |
| 7219 IsMoreGeneralStorageType( | |
| 7220 other_details.storage_type(), details.storage_type()) | |
| 7221 ? other_details.storage_type() : details.storage_type(); | |
| 7222 d.SetStorageType(storage); | |
| 7223 result->Set(descriptor, &d, witness); | |
| 7224 } else if (other_details.type() == CONSTANT_FUNCTION) { | |
| 7225 Object* value = GetValue(descriptor); | |
| 7226 Object* other_value = other->GetValue(descriptor); | |
| 7227 if (details.type() == CONSTANT_FUNCTION && value != other_value) { | |
| 7228 FieldDescriptor d(key, | |
| 7229 current_offset++, | |
| 7230 details.attributes(), | |
| 7231 descriptor + 1); | |
| 7232 d.SetStorageType(TAGGED); | |
| 7233 result->Set(descriptor, &d, witness); | |
| 7234 } else { | |
| 7235 ConstantFunctionDescriptor d(key, | |
| 7236 JSFunction::cast(other_value), | |
| 7237 details.attributes(), | |
| 7238 descriptor + 1); | |
| 7239 result->Set(descriptor, &d, witness); | |
| 7240 } | |
| 7241 } else { | |
| 7242 ASSERT(other_details.type() != FIELD); | |
| 7243 result->CopyFrom(descriptor, other, descriptor, witness); | |
| 7244 } | |
| 7245 } | |
| 7246 | |
| 7247 for (; descriptor < new_size; descriptor++) { | |
| 7248 PropertyDetails details = other->GetDetails(descriptor); | |
| 7249 if (details.type() == FIELD) { | |
| 7250 Name* key = other->GetKey(descriptor); | |
| 7251 FieldDescriptor d(key, | |
| 7252 current_offset++, | |
| 7253 details.attributes(), | |
| 7254 descriptor + 1); | |
| 7255 result->Set(descriptor, &d, witness); | |
| 7256 } else { | |
| 7257 result->CopyFrom(descriptor, other, descriptor, witness); | |
| 7258 } | |
| 7259 } | |
| 7260 | |
| 7261 result->Sort(); | |
| 7262 return result; | |
| 7263 } | |
| 7264 | |
| 7265 | |
| 6815 // We need the whiteness witness since sort will reshuffle the entries in the | 7266 // We need the whiteness witness since sort will reshuffle the entries in the |
| 6816 // descriptor array. If the descriptor array were to be black, the shuffling | 7267 // descriptor array. If the descriptor array were to be black, the shuffling |
| 6817 // would move a slot that was already recorded as pointing into an evacuation | 7268 // would move a slot that was already recorded as pointing into an evacuation |
| 6818 // candidate. This would result in missing updates upon evacuation. | 7269 // candidate. This would result in missing updates upon evacuation. |
| 6819 void DescriptorArray::Sort() { | 7270 void DescriptorArray::Sort() { |
| 6820 // In-place heap sort. | 7271 // In-place heap sort. |
| 6821 int len = number_of_descriptors(); | 7272 int len = number_of_descriptors(); |
| 6822 // Reset sorting since the descriptor array might contain invalid pointers. | 7273 // Reset sorting since the descriptor array might contain invalid pointers. |
| 6823 for (int i = 0; i < len; ++i) SetSortedKey(i, i); | 7274 for (int i = 0; i < len; ++i) SetSortedKey(i, i); |
| 6824 // Bottom-up max-heap construction. | 7275 // Bottom-up max-heap construction. |
| (...skipping 1341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 8166 // XOR-ing the prototype and constructor directly yields too many zero bits | 8617 // XOR-ing the prototype and constructor directly yields too many zero bits |
| 8167 // when the two pointers are close (which is fairly common). | 8618 // when the two pointers are close (which is fairly common). |
| 8168 // To avoid this we shift the prototype 4 bits relatively to the constructor. | 8619 // To avoid this we shift the prototype 4 bits relatively to the constructor. |
| 8169 hash ^= (static_cast<uint32_t>( | 8620 hash ^= (static_cast<uint32_t>( |
| 8170 reinterpret_cast<uintptr_t>(prototype())) << 2); | 8621 reinterpret_cast<uintptr_t>(prototype())) << 2); |
| 8171 | 8622 |
| 8172 return hash ^ (hash >> 16) ^ bit_field2(); | 8623 return hash ^ (hash >> 16) ^ bit_field2(); |
| 8173 } | 8624 } |
| 8174 | 8625 |
| 8175 | 8626 |
| 8627 static bool CheckEquivalent(Map* first, Map* second) { | |
| 8628 return | |
| 8629 first->constructor() == second->constructor() && | |
| 8630 first->prototype() == second->prototype() && | |
| 8631 first->instance_type() == second->instance_type() && | |
| 8632 first->bit_field() == second->bit_field() && | |
| 8633 first->bit_field2() == second->bit_field2() && | |
| 8634 first->is_observed() == second->is_observed() && | |
| 8635 first->function_with_prototype() == second->function_with_prototype(); | |
| 8636 } | |
| 8637 | |
| 8638 | |
| 8639 bool Map::EquivalentToForTransition(Map* other) { | |
| 8640 return CheckEquivalent(this, other); | |
| 8641 } | |
| 8642 | |
| 8643 | |
| 8176 bool Map::EquivalentToForNormalization(Map* other, | 8644 bool Map::EquivalentToForNormalization(Map* other, |
| 8177 PropertyNormalizationMode mode) { | 8645 PropertyNormalizationMode mode) { |
| 8178 return | 8646 int properties = mode == CLEAR_INOBJECT_PROPERTIES |
| 8179 constructor() == other->constructor() && | 8647 ? 0 : other->inobject_properties(); |
| 8180 prototype() == other->prototype() && | 8648 return CheckEquivalent(this, other) && inobject_properties() == properties; |
| 8181 inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ? | |
| 8182 0 : | |
| 8183 other->inobject_properties()) && | |
| 8184 instance_type() == other->instance_type() && | |
| 8185 bit_field() == other->bit_field() && | |
| 8186 bit_field2() == other->bit_field2() && | |
| 8187 is_observed() == other->is_observed() && | |
| 8188 function_with_prototype() == other->function_with_prototype(); | |
| 8189 } | 8649 } |
| 8190 | 8650 |
| 8191 | 8651 |
| 8192 void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) { | 8652 void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) { |
| 8193 // Iterate over all fields in the body but take care in dealing with | 8653 // Iterate over all fields in the body but take care in dealing with |
| 8194 // the code entry. | 8654 // the code entry. |
| 8195 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset); | 8655 IteratePointers(v, kPropertiesOffset, kCodeEntryOffset); |
| 8196 v->VisitCodeEntry(this->address() + kCodeEntryOffset); | 8656 v->VisitCodeEntry(this->address() + kCodeEntryOffset); |
| 8197 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size); | 8657 IteratePointers(v, kCodeEntryOffset + kPointerSize, object_size); |
| 8198 } | 8658 } |
| (...skipping 5716 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 13915 value, | 14375 value, |
| 13916 UPDATE_WRITE_BARRIER); | 14376 UPDATE_WRITE_BARRIER); |
| 13917 } else { | 14377 } else { |
| 13918 int offset = current_offset - inobject_props; | 14378 int offset = current_offset - inobject_props; |
| 13919 fields->set(offset, value); | 14379 fields->set(offset, value); |
| 13920 } | 14380 } |
| 13921 FieldDescriptor d(key, | 14381 FieldDescriptor d(key, |
| 13922 current_offset++, | 14382 current_offset++, |
| 13923 details.attributes(), | 14383 details.attributes(), |
| 13924 enumeration_index); | 14384 enumeration_index); |
| 14385 // TODO(verwaest): Support storage types in the boilerplate. | |
| 14386 // d.SetStorageType(value->RequiredStorage()); | |
| 14387 d.SetStorageType(TAGGED); | |
| 13925 descriptors->Set(enumeration_index - 1, &d, witness); | 14388 descriptors->Set(enumeration_index - 1, &d, witness); |
| 13926 } else if (type == CALLBACKS) { | 14389 } else if (type == CALLBACKS) { |
| 13927 CallbacksDescriptor d(key, | 14390 CallbacksDescriptor d(key, |
| 13928 value, | 14391 value, |
| 13929 details.attributes(), | 14392 details.attributes(), |
| 13930 enumeration_index); | 14393 enumeration_index); |
| 13931 descriptors->Set(enumeration_index - 1, &d, witness); | 14394 descriptors->Set(enumeration_index - 1, &d, witness); |
| 13932 } else { | 14395 } else { |
| 13933 UNREACHABLE(); | 14396 UNREACHABLE(); |
| 13934 } | 14397 } |
| (...skipping 570 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 14505 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); | 14968 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); |
| 14506 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); | 14969 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); |
| 14507 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); | 14970 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); |
| 14508 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); | 14971 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); |
| 14509 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); | 14972 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); |
| 14510 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); | 14973 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); |
| 14511 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); | 14974 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); |
| 14512 } | 14975 } |
| 14513 | 14976 |
| 14514 } } // namespace v8::internal | 14977 } } // namespace v8::internal |
| OLD | NEW |