OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
480 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value; | 480 if (!maybe_store_value->ToObject(&store_value)) return maybe_store_value; |
481 } | 481 } |
482 Object* dict; | 482 Object* dict; |
483 { MaybeObject* maybe_dict = | 483 { MaybeObject* maybe_dict = |
484 property_dictionary()->Add(name, store_value, details); | 484 property_dictionary()->Add(name, store_value, details); |
485 if (!maybe_dict->ToObject(&dict)) return maybe_dict; | 485 if (!maybe_dict->ToObject(&dict)) return maybe_dict; |
486 } | 486 } |
487 set_properties(StringDictionary::cast(dict)); | 487 set_properties(StringDictionary::cast(dict)); |
488 return value; | 488 return value; |
489 } | 489 } |
490 // Preserve enumeration index. | 490 |
| 491 PropertyDetails original_details = property_dictionary()->DetailsAt(entry); |
| 492 int enumeration_index; |
| 493 // Preserve the enumeration index unless the property was deleted. |
| 494 if (original_details.IsDeleted()) { |
| 495 enumeration_index = property_dictionary()->NextEnumerationIndex(); |
| 496 property_dictionary()->SetNextEnumerationIndex(enumeration_index + 1); |
| 497 } else { |
| 498 enumeration_index = original_details.dictionary_index(); |
| 499 ASSERT(enumeration_index > 0); |
| 500 } |
| 501 |
491 details = PropertyDetails( | 502 details = PropertyDetails( |
492 details.attributes(), | 503 details.attributes(), details.type(), enumeration_index); |
493 details.type(), | |
494 property_dictionary()->DetailsAt(entry).dictionary_index()); | |
495 | 504 |
496 if (IsGlobalObject()) { | 505 if (IsGlobalObject()) { |
497 JSGlobalPropertyCell* cell = | 506 JSGlobalPropertyCell* cell = |
498 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry)); | 507 JSGlobalPropertyCell::cast(property_dictionary()->ValueAt(entry)); |
499 cell->set_value(value); | 508 cell->set_value(value); |
500 // Please note we have to update the property details. | 509 // Please note we have to update the property details. |
501 property_dictionary()->DetailsAtPut(entry, details); | 510 property_dictionary()->DetailsAtPut(entry, details); |
502 } else { | 511 } else { |
503 property_dictionary()->SetEntry(entry, name, value, details); | 512 property_dictionary()->SetEntry(entry, name, value, details); |
504 } | 513 } |
(...skipping 1020 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1525 } | 1534 } |
1526 return true; | 1535 return true; |
1527 } | 1536 } |
1528 | 1537 |
1529 | 1538 |
1530 MaybeObject* JSObject::AddFastProperty(String* name, | 1539 MaybeObject* JSObject::AddFastProperty(String* name, |
1531 Object* value, | 1540 Object* value, |
1532 PropertyAttributes attributes, | 1541 PropertyAttributes attributes, |
1533 StoreFromKeyed store_mode) { | 1542 StoreFromKeyed store_mode) { |
1534 ASSERT(!IsJSGlobalProxy()); | 1543 ASSERT(!IsJSGlobalProxy()); |
1535 ASSERT(map()->instance_descriptors()->Search(name) == | 1544 ASSERT(DescriptorArray::kNotFound == |
1536 DescriptorArray::kNotFound); | 1545 map()->instance_descriptors()->Search( |
| 1546 name, map()->NumberOfOwnDescriptors())); |
1537 | 1547 |
1538 // Normalize the object if the name is an actual string (not the | 1548 // Normalize the object if the name is an actual string (not the |
1539 // hidden symbols) and is not a real identifier. | 1549 // hidden symbols) and is not a real identifier. |
1540 // Normalize the object if it will have too many fast properties. | 1550 // Normalize the object if it will have too many fast properties. |
1541 Isolate* isolate = GetHeap()->isolate(); | 1551 Isolate* isolate = GetHeap()->isolate(); |
1542 StringInputBuffer buffer(name); | 1552 StringInputBuffer buffer(name); |
1543 if ((!IsIdentifier(isolate->unicode_cache(), &buffer) | 1553 if ((!IsIdentifier(isolate->unicode_cache(), &buffer) |
1544 && name != isolate->heap()->hidden_symbol()) || | 1554 && name != isolate->heap()->hidden_symbol()) || |
1545 (map()->unused_property_fields() == 0 && | 1555 (map()->unused_property_fields() == 0 && |
1546 TooManyFastProperties(properties()->length(), store_mode))) { | 1556 TooManyFastProperties(properties()->length(), store_mode))) { |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1746 return SetNormalizedProperty(name, value, new_details); | 1756 return SetNormalizedProperty(name, value, new_details); |
1747 } | 1757 } |
1748 | 1758 |
1749 | 1759 |
1750 MaybeObject* JSObject::ConvertTransitionToMapTransition( | 1760 MaybeObject* JSObject::ConvertTransitionToMapTransition( |
1751 int transition_index, | 1761 int transition_index, |
1752 String* name, | 1762 String* name, |
1753 Object* new_value, | 1763 Object* new_value, |
1754 PropertyAttributes attributes) { | 1764 PropertyAttributes attributes) { |
1755 Map* old_map = map(); | 1765 Map* old_map = map(); |
| 1766 Map* old_target = old_map->GetTransition(transition_index); |
1756 Object* result; | 1767 Object* result; |
1757 | 1768 |
| 1769 // To sever a transition to a map with which the descriptors are shared, the |
| 1770 // larger map (more descriptors) needs to store its own descriptors array. |
| 1771 // Both sides of the severed chain need to have their own descriptors pointer |
| 1772 // to store distinct descriptor arrays. |
| 1773 |
| 1774 // If the old_target did not yet store its own descriptors, the new |
| 1775 // descriptors pointer is created for the old_target by temporarily clearing |
| 1776 // the back pointer and setting its descriptor array. |
| 1777 |
| 1778 // This phase is executed before creating the new map since it requires |
| 1779 // allocation that may fail. |
| 1780 if (!old_target->StoresOwnDescriptors()) { |
| 1781 DescriptorArray* old_descriptors = old_map->instance_descriptors(); |
| 1782 |
| 1783 old_target->SetBackPointer(GetHeap()->undefined_value()); |
| 1784 MaybeObject* maybe_failure = old_target->SetDescriptors(old_descriptors); |
| 1785 // Reset the backpointer before returning failure, otherwise the map ends up |
| 1786 // with an undefined backpointer and no descriptors, losing its own |
| 1787 // descriptors. Setting the backpointer always succeeds. |
| 1788 old_target->SetBackPointer(old_map); |
| 1789 if (maybe_failure->IsFailure()) return maybe_failure; |
| 1790 } |
| 1791 |
1758 MaybeObject* maybe_result = | 1792 MaybeObject* maybe_result = |
1759 ConvertDescriptorToField(name, new_value, attributes); | 1793 ConvertDescriptorToField(name, new_value, attributes); |
1760 if (!maybe_result->To(&result)) return maybe_result; | 1794 if (!maybe_result->To(&result)) return maybe_result; |
1761 | 1795 |
1762 if (!HasFastProperties()) return result; | 1796 if (!HasFastProperties()) return result; |
1763 | 1797 |
1764 // This method should only be used to convert existing transitions. Objects | 1798 // This method should only be used to convert existing transitions. Objects |
1765 // with the map of "new Object()" cannot have transitions in the first place. | 1799 // with the map of "new Object()" cannot have transitions in the first place. |
1766 ASSERT(map() != GetIsolate()->empty_object_map()); | 1800 Map* new_map = map(); |
| 1801 ASSERT(new_map != GetIsolate()->empty_object_map()); |
1767 | 1802 |
1768 // TODO(verwaest): From here on we lose existing map transitions, causing | 1803 // TODO(verwaest): From here on we lose existing map transitions, causing |
1769 // invalid back pointers. This will change once we can store multiple | 1804 // invalid back pointers. This will change once we can store multiple |
1770 // transitions with the same key. | 1805 // transitions with the same key. |
1771 old_map->SetTransition(transition_index, map()); | 1806 |
1772 map()->SetBackPointer(old_map); | 1807 if (old_map->owns_descriptors()) { |
| 1808 // If the old map owns its own descriptors, transfer ownership to the |
| 1809 // new_map and install its descriptors in the old_map. Since the old_map |
| 1810 // stores the descriptors for the new_map, remove the transition array of |
| 1811 // the new_map that is only in place to store the descriptors. |
| 1812 old_map->transitions()->descriptors_pointer()->set_value( |
| 1813 new_map->instance_descriptors()); |
| 1814 new_map->ClearTransitions(GetHeap()); |
| 1815 old_map->set_owns_descriptors(false); |
| 1816 } else if (old_target->instance_descriptors() == |
| 1817 old_map->instance_descriptors()) { |
| 1818 // Since the conversion above generated a new fast map with an additional |
| 1819 // property which can be shared as well, install this descriptor pointer |
| 1820 // along the entire chain of smaller maps; and remove the transition array |
| 1821 // that is only in place to hold the descriptor array in the new map. |
| 1822 Map* map; |
| 1823 JSGlobalPropertyCell* new_pointer = |
| 1824 new_map->transitions()->descriptors_pointer(); |
| 1825 JSGlobalPropertyCell* old_pointer = |
| 1826 old_map->transitions()->descriptors_pointer(); |
| 1827 for (Object* current = old_map; |
| 1828 !current->IsUndefined(); |
| 1829 current = map->GetBackPointer()) { |
| 1830 map = Map::cast(current); |
| 1831 if (!map->HasTransitionArray()) break; |
| 1832 TransitionArray* transitions = map->transitions(); |
| 1833 if (transitions->descriptors_pointer() != old_pointer) break; |
| 1834 map->SetEnumLength(Map::kInvalidEnumCache); |
| 1835 transitions->set_descriptors_pointer(new_pointer); |
| 1836 } |
| 1837 new_map->ClearTransitions(GetHeap()); |
| 1838 } |
| 1839 |
| 1840 old_map->SetTransition(transition_index, new_map); |
| 1841 new_map->SetBackPointer(old_map); |
1773 return result; | 1842 return result; |
1774 } | 1843 } |
1775 | 1844 |
1776 | 1845 |
1777 MaybeObject* JSObject::ConvertDescriptorToField(String* name, | 1846 MaybeObject* JSObject::ConvertDescriptorToField(String* name, |
1778 Object* new_value, | 1847 Object* new_value, |
1779 PropertyAttributes attributes) { | 1848 PropertyAttributes attributes) { |
1780 if (map()->unused_property_fields() == 0 && | 1849 if (map()->unused_property_fields() == 0 && |
1781 TooManyFastProperties(properties()->length(), MAY_BE_STORE_FROM_KEYED)) { | 1850 TooManyFastProperties(properties()->length(), MAY_BE_STORE_FROM_KEYED)) { |
1782 Object* obj; | 1851 Object* obj; |
(...skipping 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2138 } | 2207 } |
2139 | 2208 |
2140 | 2209 |
2141 void Map::CopyAppendCallbackDescriptors(Handle<Map> map, | 2210 void Map::CopyAppendCallbackDescriptors(Handle<Map> map, |
2142 Handle<Object> descriptors) { | 2211 Handle<Object> descriptors) { |
2143 Isolate* isolate = map->GetIsolate(); | 2212 Isolate* isolate = map->GetIsolate(); |
2144 Handle<DescriptorArray> array(map->instance_descriptors()); | 2213 Handle<DescriptorArray> array(map->instance_descriptors()); |
2145 v8::NeanderArray callbacks(descriptors); | 2214 v8::NeanderArray callbacks(descriptors); |
2146 int nof_callbacks = callbacks.length(); | 2215 int nof_callbacks = callbacks.length(); |
2147 int descriptor_count = array->number_of_descriptors(); | 2216 int descriptor_count = array->number_of_descriptors(); |
| 2217 ASSERT(descriptor_count == map->NumberOfOwnDescriptors()); |
2148 | 2218 |
2149 // Ensure the keys are symbols before writing them into the instance | 2219 // Ensure the keys are symbols before writing them into the instance |
2150 // descriptor. Since it may cause a GC, it has to be done before we | 2220 // descriptor. Since it may cause a GC, it has to be done before we |
2151 // temporarily put the heap in an invalid state while appending descriptors. | 2221 // temporarily put the heap in an invalid state while appending descriptors. |
2152 for (int i = 0; i < nof_callbacks; ++i) { | 2222 for (int i = 0; i < nof_callbacks; ++i) { |
2153 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks.get(i))); | 2223 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks.get(i))); |
2154 Handle<String> key = | 2224 Handle<String> key = |
2155 isolate->factory()->SymbolFromString( | 2225 isolate->factory()->SymbolFromString( |
2156 Handle<String>(String::cast(entry->name()))); | 2226 Handle<String>(String::cast(entry->name()))); |
2157 entry->set_name(*key); | 2227 entry->set_name(*key); |
2158 } | 2228 } |
2159 | 2229 |
2160 Handle<DescriptorArray> result = | 2230 Handle<DescriptorArray> result = |
2161 isolate->factory()->NewDescriptorArray(descriptor_count + nof_callbacks); | 2231 isolate->factory()->NewDescriptorArray(descriptor_count + nof_callbacks); |
2162 | 2232 |
2163 // Ensure that marking will not progress and change color of objects. | 2233 // Ensure that marking will not progress and change color of objects. |
2164 DescriptorArray::WhitenessWitness witness(*result); | 2234 DescriptorArray::WhitenessWitness witness(*result); |
2165 | 2235 |
2166 // Copy the descriptors from the array. | 2236 // Copy the descriptors from the array. |
2167 if (0 < descriptor_count) { | 2237 for (int i = 0; i < descriptor_count; i++) { |
2168 for (int i = 0; i < descriptor_count; i++) { | 2238 result->CopyFrom(i, *array, i, witness); |
2169 result->CopyFrom(i, *array, i, witness); | |
2170 } | |
2171 } | 2239 } |
2172 | 2240 |
2173 // After this point the GC is not allowed to run anymore until the map is in a | 2241 // After this point the GC is not allowed to run anymore until the map is in a |
2174 // consistent state again, i.e., all the descriptors are appended and the | 2242 // consistent state again, i.e., all the descriptors are appended and the |
2175 // descriptor array is trimmed to the right size. | 2243 // descriptor array is trimmed to the right size. |
2176 Map::SetDescriptors(map, result); | 2244 Map::SetDescriptors(map, result); |
2177 | 2245 |
2178 // Fill in new callback descriptors. Process the callbacks from | 2246 // Fill in new callback descriptors. Process the callbacks from |
2179 // back to front so that the last callback with a given name takes | 2247 // back to front so that the last callback with a given name takes |
2180 // precedence over previously added callbacks with that name. | 2248 // precedence over previously added callbacks with that name. |
| 2249 int nof = descriptor_count; |
2181 for (int i = nof_callbacks - 1; i >= 0; i--) { | 2250 for (int i = nof_callbacks - 1; i >= 0; i--) { |
2182 AccessorInfo* entry = AccessorInfo::cast(callbacks.get(i)); | 2251 AccessorInfo* entry = AccessorInfo::cast(callbacks.get(i)); |
2183 String* key = String::cast(entry->name()); | 2252 String* key = String::cast(entry->name()); |
2184 // Check if a descriptor with this name already exists before writing. | 2253 // Check if a descriptor with this name already exists before writing. |
2185 if (LinearSearch(*result, key, map->NumberOfOwnDescriptors()) == | 2254 if (result->Search(key, nof) == DescriptorArray::kNotFound) { |
2186 DescriptorArray::kNotFound) { | |
2187 CallbacksDescriptor desc(key, entry, entry->property_attributes()); | 2255 CallbacksDescriptor desc(key, entry, entry->property_attributes()); |
2188 map->AppendDescriptor(&desc, witness); | 2256 map->AppendDescriptor(&desc, witness); |
| 2257 nof += 1; |
2189 } | 2258 } |
2190 } | 2259 } |
2191 | 2260 |
2192 int new_number_of_descriptors = map->NumberOfOwnDescriptors(); | 2261 ASSERT(nof == map->NumberOfOwnDescriptors()); |
| 2262 |
2193 // Reinstall the original descriptor array if no new elements were added. | 2263 // Reinstall the original descriptor array if no new elements were added. |
2194 if (new_number_of_descriptors == descriptor_count) { | 2264 if (nof == descriptor_count) { |
2195 Map::SetDescriptors(map, array); | 2265 Map::SetDescriptors(map, array); |
2196 return; | 2266 return; |
2197 } | 2267 } |
2198 | 2268 |
2199 // If duplicates were detected, trim the descriptor array to the right size. | 2269 // If duplicates were detected, trim the descriptor array to the right size. |
2200 int new_array_size = DescriptorArray::LengthFor(new_number_of_descriptors); | 2270 int new_array_size = DescriptorArray::LengthFor(nof); |
2201 if (new_array_size < result->length()) { | 2271 if (new_array_size < result->length()) { |
2202 RightTrimFixedArray<FROM_MUTATOR>( | 2272 RightTrimFixedArray<FROM_MUTATOR>( |
2203 isolate->heap(), *result, result->length() - new_array_size); | 2273 isolate->heap(), *result, result->length() - new_array_size); |
2204 } | 2274 } |
2205 } | 2275 } |
2206 | 2276 |
2207 | 2277 |
2208 static bool ContainsMap(MapHandleList* maps, Handle<Map> map) { | 2278 static bool ContainsMap(MapHandleList* maps, Handle<Map> map) { |
2209 ASSERT(!map.is_null()); | 2279 ASSERT(!map.is_null()); |
2210 for (int i = 0; i < maps->length(); ++i) { | 2280 for (int i = 0; i < maps->length(); ++i) { |
(...skipping 1046 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3257 if (!HasFastProperties()) return this; | 3327 if (!HasFastProperties()) return this; |
3258 | 3328 |
3259 // The global object is always normalized. | 3329 // The global object is always normalized. |
3260 ASSERT(!IsGlobalObject()); | 3330 ASSERT(!IsGlobalObject()); |
3261 // JSGlobalProxy must never be normalized | 3331 // JSGlobalProxy must never be normalized |
3262 ASSERT(!IsJSGlobalProxy()); | 3332 ASSERT(!IsJSGlobalProxy()); |
3263 | 3333 |
3264 Map* map_of_this = map(); | 3334 Map* map_of_this = map(); |
3265 | 3335 |
3266 // Allocate new content. | 3336 // Allocate new content. |
3267 int property_count = map_of_this->NumberOfDescribedProperties(); | 3337 int real_size = map_of_this->NumberOfOwnDescriptors(); |
| 3338 int property_count = |
| 3339 map_of_this->NumberOfDescribedProperties(OWN_DESCRIPTORS); |
3268 if (expected_additional_properties > 0) { | 3340 if (expected_additional_properties > 0) { |
3269 property_count += expected_additional_properties; | 3341 property_count += expected_additional_properties; |
3270 } else { | 3342 } else { |
3271 property_count += 2; // Make space for two more properties. | 3343 property_count += 2; // Make space for two more properties. |
3272 } | 3344 } |
3273 StringDictionary* dictionary; | 3345 StringDictionary* dictionary; |
3274 { MaybeObject* maybe_dictionary = StringDictionary::Allocate(property_count); | 3346 MaybeObject* maybe_dictionary = StringDictionary::Allocate(property_count); |
3275 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; | 3347 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; |
3276 } | |
3277 | 3348 |
3278 DescriptorArray* descs = map_of_this->instance_descriptors(); | 3349 DescriptorArray* descs = map_of_this->instance_descriptors(); |
3279 for (int i = 0; i < descs->number_of_descriptors(); i++) { | 3350 for (int i = 0; i < real_size; i++) { |
3280 PropertyDetails details = descs->GetDetails(i); | 3351 PropertyDetails details = descs->GetDetails(i); |
3281 switch (details.type()) { | 3352 switch (details.type()) { |
3282 case CONSTANT_FUNCTION: { | 3353 case CONSTANT_FUNCTION: { |
3283 PropertyDetails d = PropertyDetails(details.attributes(), | 3354 PropertyDetails d = PropertyDetails(details.attributes(), |
3284 NORMAL, | 3355 NORMAL, |
3285 details.descriptor_index()); | 3356 details.descriptor_index()); |
3286 Object* value = descs->GetConstantFunction(i); | 3357 Object* value = descs->GetConstantFunction(i); |
3287 MaybeObject* maybe_dictionary = | 3358 MaybeObject* maybe_dictionary = |
3288 dictionary->Add(descs->GetKey(i), value, d); | 3359 dictionary->Add(descs->GetKey(i), value, d); |
3289 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; | 3360 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; |
(...skipping 24 matching lines...) Expand all Loading... |
3314 case TRANSITION: | 3385 case TRANSITION: |
3315 case NONEXISTENT: | 3386 case NONEXISTENT: |
3316 UNREACHABLE(); | 3387 UNREACHABLE(); |
3317 break; | 3388 break; |
3318 } | 3389 } |
3319 } | 3390 } |
3320 | 3391 |
3321 Heap* current_heap = GetHeap(); | 3392 Heap* current_heap = GetHeap(); |
3322 | 3393 |
3323 // Copy the next enumeration index from instance descriptor. | 3394 // Copy the next enumeration index from instance descriptor. |
3324 int index = map_of_this->instance_descriptors()->NextEnumerationIndex(); | 3395 dictionary->SetNextEnumerationIndex(real_size + 1); |
3325 dictionary->SetNextEnumerationIndex(index); | |
3326 | 3396 |
3327 Map* new_map; | 3397 Map* new_map; |
3328 MaybeObject* maybe_map = | 3398 MaybeObject* maybe_map = |
3329 current_heap->isolate()->context()->native_context()-> | 3399 current_heap->isolate()->context()->native_context()-> |
3330 normalized_map_cache()->Get(this, mode); | 3400 normalized_map_cache()->Get(this, mode); |
3331 if (!maybe_map->To(&new_map)) return maybe_map; | 3401 if (!maybe_map->To(&new_map)) return maybe_map; |
3332 ASSERT(new_map->is_dictionary_map()); | 3402 ASSERT(new_map->is_dictionary_map()); |
3333 | 3403 |
3334 // We have now successfully allocated all the necessary objects. | 3404 // We have now successfully allocated all the necessary objects. |
3335 // Changes can now be made with the guarantee that all of them take effect. | 3405 // Changes can now be made with the guarantee that all of them take effect. |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3661 ASSERT(!IsJSGlobalProxy()); | 3731 ASSERT(!IsJSGlobalProxy()); |
3662 Object* inline_value; | 3732 Object* inline_value; |
3663 if (HasFastProperties()) { | 3733 if (HasFastProperties()) { |
3664 // If the object has fast properties, check whether the first slot | 3734 // If the object has fast properties, check whether the first slot |
3665 // in the descriptor array matches the hidden symbol. Since the | 3735 // in the descriptor array matches the hidden symbol. Since the |
3666 // hidden symbols hash code is zero (and no other string has hash | 3736 // hidden symbols hash code is zero (and no other string has hash |
3667 // code zero) it will always occupy the first entry if present. | 3737 // code zero) it will always occupy the first entry if present. |
3668 DescriptorArray* descriptors = this->map()->instance_descriptors(); | 3738 DescriptorArray* descriptors = this->map()->instance_descriptors(); |
3669 if (descriptors->number_of_descriptors() > 0) { | 3739 if (descriptors->number_of_descriptors() > 0) { |
3670 int sorted_index = descriptors->GetSortedKeyIndex(0); | 3740 int sorted_index = descriptors->GetSortedKeyIndex(0); |
3671 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_symbol()) { | 3741 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_symbol() && |
| 3742 sorted_index < map()->NumberOfOwnDescriptors()) { |
3672 ASSERT(descriptors->GetType(sorted_index) == FIELD); | 3743 ASSERT(descriptors->GetType(sorted_index) == FIELD); |
3673 inline_value = this->FastPropertyAt( | 3744 inline_value = |
3674 descriptors->GetFieldIndex(sorted_index)); | 3745 this->FastPropertyAt(descriptors->GetFieldIndex(sorted_index)); |
3675 } else { | 3746 } else { |
3676 inline_value = GetHeap()->undefined_value(); | 3747 inline_value = GetHeap()->undefined_value(); |
3677 } | 3748 } |
3678 } else { | 3749 } else { |
3679 inline_value = GetHeap()->undefined_value(); | 3750 inline_value = GetHeap()->undefined_value(); |
3680 } | 3751 } |
3681 } else { | 3752 } else { |
3682 PropertyAttributes attributes; | 3753 PropertyAttributes attributes; |
3683 // You can't install a getter on a property indexed by the hidden symbol, | 3754 // You can't install a getter on a property indexed by the hidden symbol, |
3684 // so we can be sure that GetLocalPropertyPostInterceptor returns a real | 3755 // so we can be sure that GetLocalPropertyPostInterceptor returns a real |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3729 // for hidden properties yet. | 3800 // for hidden properties yet. |
3730 ASSERT(HasHiddenProperties() != value->IsSmi()); | 3801 ASSERT(HasHiddenProperties() != value->IsSmi()); |
3731 if (HasFastProperties()) { | 3802 if (HasFastProperties()) { |
3732 // If the object has fast properties, check whether the first slot | 3803 // If the object has fast properties, check whether the first slot |
3733 // in the descriptor array matches the hidden symbol. Since the | 3804 // in the descriptor array matches the hidden symbol. Since the |
3734 // hidden symbols hash code is zero (and no other string has hash | 3805 // hidden symbols hash code is zero (and no other string has hash |
3735 // code zero) it will always occupy the first entry if present. | 3806 // code zero) it will always occupy the first entry if present. |
3736 DescriptorArray* descriptors = this->map()->instance_descriptors(); | 3807 DescriptorArray* descriptors = this->map()->instance_descriptors(); |
3737 if (descriptors->number_of_descriptors() > 0) { | 3808 if (descriptors->number_of_descriptors() > 0) { |
3738 int sorted_index = descriptors->GetSortedKeyIndex(0); | 3809 int sorted_index = descriptors->GetSortedKeyIndex(0); |
3739 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_symbol()) { | 3810 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_symbol() && |
| 3811 sorted_index < map()->NumberOfOwnDescriptors()) { |
3740 ASSERT(descriptors->GetType(sorted_index) == FIELD); | 3812 ASSERT(descriptors->GetType(sorted_index) == FIELD); |
3741 this->FastPropertyAtPut(descriptors->GetFieldIndex(sorted_index), | 3813 this->FastPropertyAtPut(descriptors->GetFieldIndex(sorted_index), |
3742 value); | 3814 value); |
3743 return this; | 3815 return this; |
3744 } | 3816 } |
3745 } | 3817 } |
3746 } | 3818 } |
3747 MaybeObject* store_result = | 3819 MaybeObject* store_result = |
3748 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(), | 3820 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(), |
3749 value, | 3821 value, |
(...skipping 421 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4171 } | 4243 } |
4172 | 4244 |
4173 | 4245 |
4174 void Map::SetDescriptors(Handle<Map> map, | 4246 void Map::SetDescriptors(Handle<Map> map, |
4175 Handle<DescriptorArray> descriptors) { | 4247 Handle<DescriptorArray> descriptors) { |
4176 Isolate* isolate = map->GetIsolate(); | 4248 Isolate* isolate = map->GetIsolate(); |
4177 CALL_HEAP_FUNCTION_VOID(isolate, map->SetDescriptors(*descriptors)); | 4249 CALL_HEAP_FUNCTION_VOID(isolate, map->SetDescriptors(*descriptors)); |
4178 } | 4250 } |
4179 | 4251 |
4180 | 4252 |
4181 int Map::NumberOfDescribedProperties(PropertyAttributes filter) { | 4253 int Map::NumberOfDescribedProperties(DescriptorFlag which, |
| 4254 PropertyAttributes filter) { |
4182 int result = 0; | 4255 int result = 0; |
4183 DescriptorArray* descs = instance_descriptors(); | 4256 DescriptorArray* descs = instance_descriptors(); |
4184 for (int i = 0; i < descs->number_of_descriptors(); i++) { | 4257 int limit = which == ALL_DESCRIPTORS |
4185 PropertyDetails details = descs->GetDetails(i); | 4258 ? descs->number_of_descriptors() |
4186 if ((details.attributes() & filter) == 0) { | 4259 : NumberOfOwnDescriptors(); |
4187 result++; | 4260 for (int i = 0; i < limit; i++) { |
4188 } | 4261 if ((descs->GetDetails(i).attributes() & filter) == 0) result++; |
4189 } | 4262 } |
4190 return result; | 4263 return result; |
4191 } | 4264 } |
4192 | 4265 |
4193 | 4266 |
4194 int Map::PropertyIndexFor(String* name) { | 4267 int Map::PropertyIndexFor(String* name) { |
4195 DescriptorArray* descs = instance_descriptors(); | 4268 DescriptorArray* descs = instance_descriptors(); |
4196 for (int i = 0; i < descs->number_of_descriptors(); i++) { | 4269 int limit = NumberOfOwnDescriptors(); |
| 4270 for (int i = 0; i < limit; i++) { |
4197 if (name->Equals(descs->GetKey(i))) return descs->GetFieldIndex(i); | 4271 if (name->Equals(descs->GetKey(i))) return descs->GetFieldIndex(i); |
4198 } | 4272 } |
4199 return -1; | 4273 return -1; |
4200 } | 4274 } |
4201 | 4275 |
4202 | 4276 |
4203 int Map::NextFreePropertyIndex() { | 4277 int Map::NextFreePropertyIndex() { |
4204 int max_index = -1; | 4278 int max_index = -1; |
| 4279 int number_of_own_descriptors = NumberOfOwnDescriptors(); |
4205 DescriptorArray* descs = instance_descriptors(); | 4280 DescriptorArray* descs = instance_descriptors(); |
4206 for (int i = 0; i < descs->number_of_descriptors(); i++) { | 4281 for (int i = 0; i < number_of_own_descriptors; i++) { |
4207 if (descs->GetType(i) == FIELD) { | 4282 if (descs->GetType(i) == FIELD) { |
4208 int current_index = descs->GetFieldIndex(i); | 4283 int current_index = descs->GetFieldIndex(i); |
4209 if (current_index > max_index) max_index = current_index; | 4284 if (current_index > max_index) max_index = current_index; |
4210 } | 4285 } |
4211 } | 4286 } |
4212 return max_index + 1; | 4287 return max_index + 1; |
4213 } | 4288 } |
4214 | 4289 |
4215 | 4290 |
4216 AccessorDescriptor* Map::FindAccessor(String* name) { | 4291 AccessorDescriptor* Map::FindAccessor(String* name) { |
4217 DescriptorArray* descs = instance_descriptors(); | 4292 DescriptorArray* descs = instance_descriptors(); |
4218 for (int i = 0; i < descs->number_of_descriptors(); i++) { | 4293 int number_of_own_descriptors = NumberOfOwnDescriptors(); |
4219 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) { | 4294 for (int i = 0; i < number_of_own_descriptors; i++) { |
| 4295 if (descs->GetType(i) == CALLBACKS && name->Equals(descs->GetKey(i))) { |
4220 return descs->GetCallbacks(i); | 4296 return descs->GetCallbacks(i); |
4221 } | 4297 } |
4222 } | 4298 } |
4223 return NULL; | 4299 return NULL; |
4224 } | 4300 } |
4225 | 4301 |
4226 | 4302 |
4227 void JSReceiver::LocalLookup(String* name, LookupResult* result) { | 4303 void JSReceiver::LocalLookup(String* name, LookupResult* result) { |
4228 ASSERT(name->IsString()); | 4304 ASSERT(name->IsString()); |
4229 | 4305 |
(...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4633 } else { | 4709 } else { |
4634 return GetHeap()->null_value(); | 4710 return GetHeap()->null_value(); |
4635 } | 4711 } |
4636 | 4712 |
4637 int descriptor_number = result.GetDescriptorIndex(); | 4713 int descriptor_number = result.GetDescriptorIndex(); |
4638 | 4714 |
4639 map()->LookupTransition(this, name, &result); | 4715 map()->LookupTransition(this, name, &result); |
4640 | 4716 |
4641 if (result.IsFound()) { | 4717 if (result.IsFound()) { |
4642 Map* target = result.GetTransitionTarget(); | 4718 Map* target = result.GetTransitionTarget(); |
4643 ASSERT(target->instance_descriptors()->number_of_descriptors() == | 4719 ASSERT(target->NumberOfOwnDescriptors() == |
4644 map()->instance_descriptors()->number_of_descriptors()); | 4720 map()->NumberOfOwnDescriptors()); |
4645 ASSERT(target->instance_descriptors()->GetKey(descriptor_number) == name); | 4721 // This works since descriptors are sorted in order of addition. |
| 4722 ASSERT(map()->instance_descriptors()->GetKey(descriptor_number) == name); |
4646 return TryAccessorTransition( | 4723 return TryAccessorTransition( |
4647 this, target, descriptor_number, component, accessor, attributes); | 4724 this, target, descriptor_number, component, accessor, attributes); |
4648 } | 4725 } |
4649 } else { | 4726 } else { |
4650 // If not, lookup a transition. | 4727 // If not, lookup a transition. |
4651 map()->LookupTransition(this, name, &result); | 4728 map()->LookupTransition(this, name, &result); |
4652 | 4729 |
4653 // If there is a transition, try to follow it. | 4730 // If there is a transition, try to follow it. |
4654 if (result.IsFound()) { | 4731 if (result.IsFound()) { |
4655 Map* target = result.GetTransitionTarget(); | 4732 Map* target = result.GetTransitionTarget(); |
(...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4818 } | 4895 } |
4819 } | 4896 } |
4820 } | 4897 } |
4821 } | 4898 } |
4822 return heap->undefined_value(); | 4899 return heap->undefined_value(); |
4823 } | 4900 } |
4824 | 4901 |
4825 | 4902 |
4826 Object* JSObject::SlowReverseLookup(Object* value) { | 4903 Object* JSObject::SlowReverseLookup(Object* value) { |
4827 if (HasFastProperties()) { | 4904 if (HasFastProperties()) { |
| 4905 int number_of_own_descriptors = map()->NumberOfOwnDescriptors(); |
4828 DescriptorArray* descs = map()->instance_descriptors(); | 4906 DescriptorArray* descs = map()->instance_descriptors(); |
4829 for (int i = 0; i < descs->number_of_descriptors(); i++) { | 4907 for (int i = 0; i < number_of_own_descriptors; i++) { |
4830 if (descs->GetType(i) == FIELD) { | 4908 if (descs->GetType(i) == FIELD) { |
4831 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) { | 4909 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) { |
4832 return descs->GetKey(i); | 4910 return descs->GetKey(i); |
4833 } | 4911 } |
4834 } else if (descs->GetType(i) == CONSTANT_FUNCTION) { | 4912 } else if (descs->GetType(i) == CONSTANT_FUNCTION) { |
4835 if (descs->GetConstantFunction(i) == value) { | 4913 if (descs->GetConstantFunction(i) == value) { |
4836 return descs->GetKey(i); | 4914 return descs->GetKey(i); |
4837 } | 4915 } |
4838 } | 4916 } |
4839 } | 4917 } |
4840 return GetHeap()->undefined_value(); | 4918 return GetHeap()->undefined_value(); |
4841 } else { | 4919 } else { |
4842 return property_dictionary()->SlowReverseLookup(value); | 4920 return property_dictionary()->SlowReverseLookup(value); |
4843 } | 4921 } |
4844 } | 4922 } |
4845 | 4923 |
4846 | 4924 |
4847 MaybeObject* Map::RawCopy(int instance_size) { | 4925 MaybeObject* Map::RawCopy(int instance_size) { |
4848 Map* result; | 4926 Map* result; |
4849 MaybeObject* maybe_result = | 4927 MaybeObject* maybe_result = |
4850 GetHeap()->AllocateMap(instance_type(), instance_size); | 4928 GetHeap()->AllocateMap(instance_type(), instance_size); |
4851 if (!maybe_result->To(&result)) return maybe_result; | 4929 if (!maybe_result->To(&result)) return maybe_result; |
4852 | 4930 |
4853 result->set_prototype(prototype()); | 4931 result->set_prototype(prototype()); |
4854 result->set_constructor(constructor()); | 4932 result->set_constructor(constructor()); |
4855 result->set_bit_field(bit_field()); | 4933 result->set_bit_field(bit_field()); |
4856 result->set_bit_field2(bit_field2()); | 4934 result->set_bit_field2(bit_field2()); |
4857 result->set_bit_field3(bit_field3()); | 4935 result->set_bit_field3(bit_field3()); |
4858 result->SetNumberOfOwnDescriptors(0); | 4936 int new_bit_field3 = bit_field3(); |
4859 result->SetEnumLength(kInvalidEnumCache); | 4937 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true); |
| 4938 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0); |
| 4939 new_bit_field3 = EnumLengthBits::update(new_bit_field3, kInvalidEnumCache); |
| 4940 result->set_bit_field3(new_bit_field3); |
4860 return result; | 4941 return result; |
4861 } | 4942 } |
4862 | 4943 |
4863 | 4944 |
4864 MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode, | 4945 MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode, |
4865 NormalizedMapSharingMode sharing) { | 4946 NormalizedMapSharingMode sharing) { |
4866 int new_instance_size = instance_size(); | 4947 int new_instance_size = instance_size(); |
4867 if (mode == CLEAR_INOBJECT_PROPERTIES) { | 4948 if (mode == CLEAR_INOBJECT_PROPERTIES) { |
4868 new_instance_size -= inobject_properties() * kPointerSize; | 4949 new_instance_size -= inobject_properties() * kPointerSize; |
4869 } | 4950 } |
(...skipping 29 matching lines...) Expand all Loading... |
4899 result->set_inobject_properties(inobject_properties()); | 4980 result->set_inobject_properties(inobject_properties()); |
4900 result->set_unused_property_fields(unused_property_fields()); | 4981 result->set_unused_property_fields(unused_property_fields()); |
4901 | 4982 |
4902 result->set_pre_allocated_property_fields(pre_allocated_property_fields()); | 4983 result->set_pre_allocated_property_fields(pre_allocated_property_fields()); |
4903 result->set_is_shared(false); | 4984 result->set_is_shared(false); |
4904 result->ClearCodeCache(GetHeap()); | 4985 result->ClearCodeCache(GetHeap()); |
4905 return result; | 4986 return result; |
4906 } | 4987 } |
4907 | 4988 |
4908 | 4989 |
| 4990 MaybeObject* Map::ShareDescriptor(Descriptor* descriptor) { |
| 4991 // Sanity check. This path is only to be taken if the map owns its descriptor |
| 4992 // array, implying that its NumberOfOwnDescriptors equals the number of |
| 4993 // descriptors in the descriptor array. |
| 4994 if (NumberOfOwnDescriptors() != |
| 4995 instance_descriptors()->number_of_descriptors()) { |
| 4996 Isolate::Current()->PushStackTraceAndDie( |
| 4997 0xDEAD0002, GetBackPointer(), this, 0xDEAD0003); |
| 4998 } |
| 4999 Map* result; |
| 5000 MaybeObject* maybe_result = CopyDropDescriptors(); |
| 5001 if (!maybe_result->To(&result)) return maybe_result; |
| 5002 |
| 5003 String* name = descriptor->GetKey(); |
| 5004 |
| 5005 TransitionArray* transitions; |
| 5006 MaybeObject* maybe_transitions = AddTransition(name, result); |
| 5007 if (!maybe_transitions->To(&transitions)) return maybe_transitions; |
| 5008 |
| 5009 DescriptorArray* descriptors = instance_descriptors(); |
| 5010 int old_size = descriptors->number_of_descriptors(); |
| 5011 |
| 5012 DescriptorArray* new_descriptors; |
| 5013 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(old_size + 1); |
| 5014 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
| 5015 DescriptorArray::WhitenessWitness witness(new_descriptors); |
| 5016 |
| 5017 for (int i = 0; i < old_size; ++i) { |
| 5018 new_descriptors->CopyFrom(i, descriptors, i, witness); |
| 5019 } |
| 5020 new_descriptors->Append(descriptor, witness, old_size); |
| 5021 |
| 5022 // If the source descriptors had an enum cache we copy it. This ensures that |
| 5023 // the maps to which we push the new descriptor array back can rely on a |
| 5024 // cache always being available once it is set. If the map has more |
| 5025 // enumerated descriptors than available in the original cache, the cache |
| 5026 // will be lazily replaced by the extended cache when needed. |
| 5027 if (descriptors->HasEnumCache()) { |
| 5028 new_descriptors->CopyEnumCacheFrom(descriptors); |
| 5029 } |
| 5030 |
| 5031 transitions->set_descriptors(new_descriptors); |
| 5032 set_transitions(transitions); |
| 5033 result->SetBackPointer(this); |
| 5034 set_owns_descriptors(false); |
| 5035 |
| 5036 result->SetNumberOfOwnDescriptors(new_descriptors->number_of_descriptors()); |
| 5037 ASSERT(result->NumberOfOwnDescriptors() == NumberOfOwnDescriptors() + 1); |
| 5038 |
| 5039 return result; |
| 5040 } |
| 5041 |
| 5042 |
4909 MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors, | 5043 MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors, |
4910 String* name, | 5044 String* name, |
4911 TransitionFlag flag) { | 5045 TransitionFlag flag) { |
| 5046 ASSERT(descriptors->IsSortedNoDuplicates()); |
| 5047 |
4912 Map* result; | 5048 Map* result; |
4913 MaybeObject* maybe_result = CopyDropDescriptors(); | 5049 MaybeObject* maybe_result = CopyDropDescriptors(); |
4914 if (!maybe_result->To(&result)) return maybe_result; | 5050 if (!maybe_result->To(&result)) return maybe_result; |
4915 | 5051 |
4916 if (descriptors->number_of_descriptors() != 0) { | 5052 // Unless we are creating a map with no descriptors and no back pointer, we |
| 5053 // insert the descriptor array locally. |
| 5054 if (!descriptors->IsEmpty()) { |
4917 MaybeObject* maybe_failure = result->SetDescriptors(descriptors); | 5055 MaybeObject* maybe_failure = result->SetDescriptors(descriptors); |
4918 if (maybe_failure->IsFailure()) return maybe_failure; | 5056 if (maybe_failure->IsFailure()) return maybe_failure; |
4919 result->SetNumberOfOwnDescriptors(descriptors->number_of_descriptors()); | 5057 result->SetNumberOfOwnDescriptors(descriptors->number_of_descriptors()); |
4920 } | 5058 } |
4921 | 5059 |
4922 if (flag == INSERT_TRANSITION && CanHaveMoreTransitions()) { | 5060 if (flag == INSERT_TRANSITION && CanHaveMoreTransitions()) { |
4923 TransitionArray* transitions; | 5061 TransitionArray* transitions; |
4924 MaybeObject* maybe_transitions = AddTransition(name, result); | 5062 MaybeObject* maybe_transitions = AddTransition(name, result); |
4925 if (!maybe_transitions->To(&transitions)) return maybe_transitions; | 5063 if (!maybe_transitions->To(&transitions)) return maybe_transitions; |
4926 | 5064 |
| 5065 if (descriptors->IsEmpty()) { |
| 5066 if (owns_descriptors()) { |
| 5067 // If the copied map has no added fields, and the parent map owns its |
| 5068 // descriptors, those descriptors have to be empty. In that case, |
| 5069 // transfer ownership of the descriptors to the new child. |
| 5070 CHECK(instance_descriptors()->IsEmpty()); |
| 5071 set_owns_descriptors(false); |
| 5072 } else { |
| 5073 // If the parent did not own its own descriptors, it may share a larger |
| 5074 // descriptors array already. In that case, force a split by setting |
| 5075 // the descriptor array of the new map to the empty descriptor array. |
| 5076 MaybeObject* maybe_failure = |
| 5077 result->SetDescriptors(GetHeap()->empty_descriptor_array()); |
| 5078 if (maybe_failure->IsFailure()) return maybe_failure; |
| 5079 } |
| 5080 } |
| 5081 |
4927 set_transitions(transitions); | 5082 set_transitions(transitions); |
4928 result->SetBackPointer(this); | 5083 result->SetBackPointer(this); |
4929 } | 5084 } |
4930 | 5085 |
4931 return result; | 5086 return result; |
4932 } | 5087 } |
4933 | 5088 |
4934 | 5089 |
4935 MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) { | 5090 MaybeObject* Map::CopyAsElementsKind(ElementsKind kind, TransitionFlag flag) { |
4936 // Create a new free-floating map only if we are not allowed to store it. | |
4937 Map* new_map = NULL; | |
4938 MaybeObject* maybe_new_map = Copy(); | |
4939 if (!maybe_new_map->To(&new_map)) return maybe_new_map; | |
4940 new_map->set_elements_kind(kind); | |
4941 | |
4942 if (flag == INSERT_TRANSITION) { | 5091 if (flag == INSERT_TRANSITION) { |
4943 ASSERT(!HasElementsTransition() || | 5092 ASSERT(!HasElementsTransition() || |
4944 ((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS || | 5093 ((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS || |
4945 IsExternalArrayElementsKind( | 5094 IsExternalArrayElementsKind( |
4946 elements_transition_map()->elements_kind())) && | 5095 elements_transition_map()->elements_kind())) && |
4947 (kind == DICTIONARY_ELEMENTS || | 5096 (kind == DICTIONARY_ELEMENTS || |
4948 IsExternalArrayElementsKind(kind)))); | 5097 IsExternalArrayElementsKind(kind)))); |
4949 ASSERT(!IsFastElementsKind(kind) || | 5098 ASSERT(!IsFastElementsKind(kind) || |
4950 IsMoreGeneralElementsKindTransition(elements_kind(), kind)); | 5099 IsMoreGeneralElementsKindTransition(elements_kind(), kind)); |
4951 ASSERT(kind != elements_kind()); | 5100 ASSERT(kind != elements_kind()); |
| 5101 } |
4952 | 5102 |
| 5103 if (flag == INSERT_TRANSITION && owns_descriptors()) { |
| 5104 // In case the map owned its own descriptors, share the descriptors and |
| 5105 // transfer ownership to the new map. |
| 5106 Map* new_map; |
| 5107 MaybeObject* maybe_new_map = CopyDropDescriptors(); |
| 5108 if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
| 5109 |
| 5110 MaybeObject* added_elements = set_elements_transition_map(new_map); |
| 5111 if (added_elements->IsFailure()) return added_elements; |
| 5112 |
| 5113 new_map->set_elements_kind(kind); |
| 5114 new_map->SetBackPointer(this); |
| 5115 new_map->SetNumberOfOwnDescriptors(NumberOfOwnDescriptors()); |
| 5116 set_owns_descriptors(false); |
| 5117 return new_map; |
| 5118 } |
| 5119 |
| 5120 // In case the map did not own its own descriptors, a split is forced by |
| 5121 // copying the map; creating a new descriptor array cell. |
| 5122 // Create a new free-floating map only if we are not allowed to store it. |
| 5123 Map* new_map; |
| 5124 MaybeObject* maybe_new_map = Copy(); |
| 5125 if (!maybe_new_map->To(&new_map)) return maybe_new_map; |
| 5126 ASSERT(new_map->NumberOfOwnDescriptors() == NumberOfOwnDescriptors()); |
| 5127 new_map->set_elements_kind(kind); |
| 5128 |
| 5129 if (flag == INSERT_TRANSITION) { |
| 5130 // Map::Copy does not store the descriptor array in case it is empty, since |
| 5131 // it does not insert a back pointer; implicitly indicating that its |
| 5132 // descriptor array is empty. Since in this case we do want to insert a back |
| 5133 // pointer, we have to manually set the empty descriptor array to force a |
| 5134 // split. |
| 5135 if (!new_map->StoresOwnDescriptors()) { |
| 5136 ASSERT(new_map->NumberOfOwnDescriptors() == 0); |
| 5137 MaybeObject* maybe_failure = |
| 5138 new_map->SetDescriptors(GetHeap()->empty_descriptor_array()); |
| 5139 if (maybe_failure->IsFailure()) return maybe_failure; |
| 5140 } |
4953 MaybeObject* added_elements = set_elements_transition_map(new_map); | 5141 MaybeObject* added_elements = set_elements_transition_map(new_map); |
4954 if (added_elements->IsFailure()) return added_elements; | 5142 if (added_elements->IsFailure()) return added_elements; |
4955 | 5143 |
4956 new_map->SetBackPointer(this); | 5144 new_map->SetBackPointer(this); |
4957 } | 5145 } |
4958 | 5146 |
4959 return new_map; | 5147 return new_map; |
4960 } | 5148 } |
4961 | 5149 |
4962 | 5150 |
4963 MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() { | 5151 MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() { |
4964 if (pre_allocated_property_fields() == 0) return CopyDropDescriptors(); | 5152 if (pre_allocated_property_fields() == 0) return CopyDropDescriptors(); |
4965 | 5153 |
4966 // If the map has pre-allocated properties always start out with a descriptor | 5154 // If the map has pre-allocated properties always start out with a descriptor |
4967 // array describing these properties. | 5155 // array describing these properties. |
4968 ASSERT(constructor()->IsJSFunction()); | 5156 ASSERT(constructor()->IsJSFunction()); |
4969 JSFunction* ctor = JSFunction::cast(constructor()); | 5157 JSFunction* ctor = JSFunction::cast(constructor()); |
4970 Map* map = ctor->initial_map(); | 5158 Map* map = ctor->initial_map(); |
4971 DescriptorArray* descriptors = map->instance_descriptors(); | 5159 DescriptorArray* descriptors = map->instance_descriptors(); |
4972 | 5160 |
4973 return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION); | 5161 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); |
| 5162 DescriptorArray* new_descriptors; |
| 5163 MaybeObject* maybe_descriptors = |
| 5164 descriptors->CopyUpTo(number_of_own_descriptors); |
| 5165 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
| 5166 |
| 5167 return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION); |
4974 } | 5168 } |
4975 | 5169 |
4976 | 5170 |
4977 MaybeObject* Map::Copy() { | 5171 MaybeObject* Map::Copy() { |
4978 DescriptorArray* descriptors = instance_descriptors(); | 5172 DescriptorArray* descriptors = instance_descriptors(); |
4979 return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION); | 5173 DescriptorArray* new_descriptors; |
| 5174 int number_of_own_descriptors = NumberOfOwnDescriptors(); |
| 5175 MaybeObject* maybe_descriptors = |
| 5176 descriptors->CopyUpTo(number_of_own_descriptors); |
| 5177 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
| 5178 |
| 5179 return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION); |
4980 } | 5180 } |
4981 | 5181 |
4982 | 5182 |
4983 MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor, | 5183 MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor, |
4984 TransitionFlag flag) { | 5184 TransitionFlag flag) { |
4985 DescriptorArray* descriptors = instance_descriptors(); | 5185 DescriptorArray* descriptors = instance_descriptors(); |
4986 | 5186 |
4987 // Ensure the key is a symbol. | 5187 // Ensure the key is a symbol. |
4988 MaybeObject* maybe_failure = descriptor->KeyToSymbol(); | 5188 MaybeObject* maybe_failure = descriptor->KeyToSymbol(); |
4989 if (maybe_failure->IsFailure()) return maybe_failure; | 5189 if (maybe_failure->IsFailure()) return maybe_failure; |
4990 | 5190 |
4991 String* key = descriptor->GetKey(); | 5191 int old_size = NumberOfOwnDescriptors(); |
4992 ASSERT(descriptors->Search(key) == DescriptorArray::kNotFound); | 5192 int new_size = old_size + 1; |
| 5193 descriptor->SetEnumerationIndex(new_size); |
4993 | 5194 |
4994 int old_size = descriptors->number_of_descriptors(); | 5195 if (flag == INSERT_TRANSITION && |
4995 int new_size = old_size + 1; | 5196 owns_descriptors() && |
| 5197 CanHaveMoreTransitions()) { |
| 5198 return ShareDescriptor(descriptor); |
| 5199 } |
4996 | 5200 |
4997 DescriptorArray* new_descriptors; | 5201 DescriptorArray* new_descriptors; |
4998 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(new_size); | 5202 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(old_size + 1); |
4999 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; | 5203 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
5000 | 5204 |
5001 DescriptorArray::WhitenessWitness witness(new_descriptors); | 5205 DescriptorArray::WhitenessWitness witness(new_descriptors); |
5002 | 5206 |
5003 // Copy the descriptors, inserting a descriptor. | 5207 // Copy the descriptors, inserting a descriptor. |
5004 for (int i = 0; i < old_size; ++i) { | 5208 for (int i = 0; i < old_size; ++i) { |
5005 new_descriptors->CopyFrom(i, descriptors, i, witness); | 5209 new_descriptors->CopyFrom(i, descriptors, i, witness); |
5006 } | 5210 } |
5007 | 5211 |
5008 new_descriptors->Append(descriptor, witness, old_size); | 5212 new_descriptors->Set(old_size, descriptor, witness); |
| 5213 new_descriptors->Sort(); |
5009 | 5214 |
5010 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates()); | 5215 return CopyReplaceDescriptors(new_descriptors, descriptor->GetKey(), flag); |
5011 | |
5012 return CopyReplaceDescriptors(new_descriptors, key, flag); | |
5013 } | 5216 } |
5014 | 5217 |
5015 | 5218 |
5016 MaybeObject* Map::CopyInsertDescriptor(Descriptor* descriptor, | 5219 MaybeObject* Map::CopyInsertDescriptor(Descriptor* descriptor, |
5017 TransitionFlag flag) { | 5220 TransitionFlag flag) { |
5018 DescriptorArray* old_descriptors = instance_descriptors(); | 5221 DescriptorArray* old_descriptors = instance_descriptors(); |
5019 | 5222 |
5020 // Ensure the key is a symbol. | 5223 // Ensure the key is a symbol. |
5021 MaybeObject* maybe_result = descriptor->KeyToSymbol(); | 5224 MaybeObject* maybe_result = descriptor->KeyToSymbol(); |
5022 if (maybe_result->IsFailure()) return maybe_result; | 5225 if (maybe_result->IsFailure()) return maybe_result; |
5023 | 5226 |
5024 // We replace the key if it is already present. | 5227 // We replace the key if it is already present. |
5025 int index = old_descriptors->SearchWithCache(descriptor->GetKey()); | 5228 int index = old_descriptors->SearchWithCache(descriptor->GetKey(), this); |
5026 if (index != DescriptorArray::kNotFound) { | 5229 if (index != DescriptorArray::kNotFound) { |
5027 return CopyReplaceDescriptor(descriptor, index, flag); | 5230 return CopyReplaceDescriptor(descriptor, index, flag); |
5028 } | 5231 } |
5029 return CopyAddDescriptor(descriptor, flag); | 5232 return CopyAddDescriptor(descriptor, flag); |
5030 } | 5233 } |
5031 | 5234 |
5032 | 5235 |
| 5236 MaybeObject* DescriptorArray::CopyUpTo(int enumeration_index) { |
| 5237 if (enumeration_index == 0) return GetHeap()->empty_descriptor_array(); |
| 5238 |
| 5239 int size = enumeration_index; |
| 5240 |
| 5241 DescriptorArray* descriptors; |
| 5242 MaybeObject* maybe_descriptors = Allocate(size); |
| 5243 if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors; |
| 5244 DescriptorArray::WhitenessWitness witness(descriptors); |
| 5245 |
| 5246 for (int i = 0; i < size; ++i) { |
| 5247 descriptors->CopyFrom(i, this, i, witness); |
| 5248 } |
| 5249 |
| 5250 if (number_of_descriptors() != enumeration_index) descriptors->Sort(); |
| 5251 |
| 5252 return descriptors; |
| 5253 } |
| 5254 |
| 5255 |
5033 MaybeObject* Map::CopyReplaceDescriptor(Descriptor* descriptor, | 5256 MaybeObject* Map::CopyReplaceDescriptor(Descriptor* descriptor, |
5034 int insertion_index, | 5257 int insertion_index, |
5035 TransitionFlag flag) { | 5258 TransitionFlag flag) { |
5036 DescriptorArray* descriptors = instance_descriptors(); | |
5037 int size = descriptors->number_of_descriptors(); | |
5038 ASSERT(0 <= insertion_index && insertion_index < size); | |
5039 | |
5040 // Ensure the key is a symbol. | 5259 // Ensure the key is a symbol. |
5041 MaybeObject* maybe_failure = descriptor->KeyToSymbol(); | 5260 MaybeObject* maybe_failure = descriptor->KeyToSymbol(); |
5042 if (maybe_failure->IsFailure()) return maybe_failure; | 5261 if (maybe_failure->IsFailure()) return maybe_failure; |
5043 | 5262 |
| 5263 DescriptorArray* descriptors = instance_descriptors(); |
| 5264 |
5044 String* key = descriptor->GetKey(); | 5265 String* key = descriptor->GetKey(); |
5045 ASSERT(key == descriptors->GetKey(insertion_index)); | 5266 ASSERT(key == descriptors->GetKey(insertion_index)); |
5046 | 5267 |
| 5268 int new_size = NumberOfOwnDescriptors(); |
| 5269 ASSERT(0 <= insertion_index && insertion_index < new_size); |
| 5270 |
| 5271 PropertyDetails details = descriptors->GetDetails(insertion_index); |
| 5272 ASSERT_LE(details.descriptor_index(), new_size); |
| 5273 descriptor->SetEnumerationIndex(details.descriptor_index()); |
| 5274 |
5047 DescriptorArray* new_descriptors; | 5275 DescriptorArray* new_descriptors; |
5048 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(size); | 5276 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(new_size); |
5049 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; | 5277 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
5050 | |
5051 DescriptorArray::WhitenessWitness witness(new_descriptors); | 5278 DescriptorArray::WhitenessWitness witness(new_descriptors); |
5052 | 5279 |
5053 // Copy the descriptors, replacing a descriptor. | 5280 for (int i = 0; i < new_size; ++i) { |
5054 for (int index = 0; index < size; ++index) { | 5281 if (i == insertion_index) { |
5055 if (index == insertion_index) continue; | 5282 new_descriptors->Set(i, descriptor, witness); |
5056 new_descriptors->CopyFrom(index, descriptors, index, witness); | 5283 } else { |
| 5284 new_descriptors->CopyFrom(i, descriptors, i, witness); |
| 5285 } |
5057 } | 5286 } |
5058 | 5287 |
5059 PropertyDetails original_details = descriptors->GetDetails(insertion_index); | 5288 // Re-sort if descriptors were removed. |
5060 descriptor->SetEnumerationIndex(original_details.descriptor_index()); | 5289 if (new_size != descriptors->length()) new_descriptors->Sort(); |
5061 descriptor->SetSortedKey(original_details.pointer()); | |
5062 | |
5063 new_descriptors->Set(insertion_index, descriptor, witness); | |
5064 | |
5065 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates()); | |
5066 | 5290 |
5067 return CopyReplaceDescriptors(new_descriptors, key, flag); | 5291 return CopyReplaceDescriptors(new_descriptors, key, flag); |
5068 } | 5292 } |
5069 | 5293 |
5070 | 5294 |
5071 void Map::UpdateCodeCache(Handle<Map> map, | 5295 void Map::UpdateCodeCache(Handle<Map> map, |
5072 Handle<String> name, | 5296 Handle<String> name, |
5073 Handle<Code> code) { | 5297 Handle<Code> code) { |
5074 Isolate* isolate = map->GetIsolate(); | 5298 Isolate* isolate = map->GetIsolate(); |
5075 CALL_HEAP_FUNCTION_VOID(isolate, | 5299 CALL_HEAP_FUNCTION_VOID(isolate, |
(...skipping 771 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5847 // Allocate the array of keys. | 6071 // Allocate the array of keys. |
5848 MaybeObject* maybe_array = | 6072 MaybeObject* maybe_array = |
5849 heap->AllocateFixedArray(LengthFor(number_of_descriptors)); | 6073 heap->AllocateFixedArray(LengthFor(number_of_descriptors)); |
5850 if (!maybe_array->To(&result)) return maybe_array; | 6074 if (!maybe_array->To(&result)) return maybe_array; |
5851 | 6075 |
5852 result->set(kEnumCacheIndex, Smi::FromInt(0)); | 6076 result->set(kEnumCacheIndex, Smi::FromInt(0)); |
5853 return result; | 6077 return result; |
5854 } | 6078 } |
5855 | 6079 |
5856 | 6080 |
| 6081 void DescriptorArray::ClearEnumCache() { |
| 6082 set(kEnumCacheIndex, Smi::FromInt(0)); |
| 6083 } |
| 6084 |
| 6085 |
5857 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, | 6086 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, |
5858 FixedArray* new_cache, | 6087 FixedArray* new_cache, |
5859 Object* new_index_cache) { | 6088 Object* new_index_cache) { |
5860 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength); | 6089 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength); |
5861 ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray()); | 6090 ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray()); |
5862 if (HasEnumCache()) { | 6091 if (HasEnumCache()) { |
| 6092 ASSERT(new_cache->length() > FixedArray::cast(GetEnumCache())->length()); |
5863 FixedArray::cast(get(kEnumCacheIndex))-> | 6093 FixedArray::cast(get(kEnumCacheIndex))-> |
5864 set(kEnumCacheBridgeCacheIndex, new_cache); | 6094 set(kEnumCacheBridgeCacheIndex, new_cache); |
5865 FixedArray::cast(get(kEnumCacheIndex))-> | 6095 FixedArray::cast(get(kEnumCacheIndex))-> |
5866 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache); | 6096 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache); |
5867 } else { | 6097 } else { |
5868 if (IsEmpty()) return; // Do nothing for empty descriptor array. | 6098 ASSERT(!IsEmpty()); |
5869 FixedArray::cast(bridge_storage)-> | 6099 FixedArray::cast(bridge_storage)-> |
5870 set(kEnumCacheBridgeCacheIndex, new_cache); | 6100 set(kEnumCacheBridgeCacheIndex, new_cache); |
5871 FixedArray::cast(bridge_storage)-> | 6101 FixedArray::cast(bridge_storage)-> |
5872 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache); | 6102 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache); |
5873 set(kEnumCacheIndex, bridge_storage); | 6103 set(kEnumCacheIndex, bridge_storage); |
5874 } | 6104 } |
5875 } | 6105 } |
5876 | 6106 |
5877 | 6107 |
5878 void DescriptorArray::CopyFrom(int dst_index, | 6108 void DescriptorArray::CopyFrom(int dst_index, |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5934 if (right_child_hash > child_hash) { | 6164 if (right_child_hash > child_hash) { |
5935 child_index++; | 6165 child_index++; |
5936 child_hash = right_child_hash; | 6166 child_hash = right_child_hash; |
5937 } | 6167 } |
5938 } | 6168 } |
5939 if (child_hash <= parent_hash) break; | 6169 if (child_hash <= parent_hash) break; |
5940 SwapSortedKeys(parent_index, child_index); | 6170 SwapSortedKeys(parent_index, child_index); |
5941 parent_index = child_index; | 6171 parent_index = child_index; |
5942 } | 6172 } |
5943 } | 6173 } |
| 6174 ASSERT(IsSortedNoDuplicates()); |
5944 } | 6175 } |
5945 | 6176 |
5946 | 6177 |
5947 MaybeObject* AccessorPair::Copy() { | 6178 MaybeObject* AccessorPair::Copy() { |
5948 Heap* heap = GetHeap(); | 6179 Heap* heap = GetHeap(); |
5949 AccessorPair* copy; | 6180 AccessorPair* copy; |
5950 MaybeObject* maybe_copy = heap->AllocateAccessorPair(); | 6181 MaybeObject* maybe_copy = heap->AllocateAccessorPair(); |
5951 if (!maybe_copy->To(©)) return maybe_copy; | 6182 if (!maybe_copy->To(©)) return maybe_copy; |
5952 | 6183 |
5953 copy->set_getter(getter()); | 6184 copy->set_getter(getter()); |
(...skipping 1227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7181 void String::PrintOn(FILE* file) { | 7412 void String::PrintOn(FILE* file) { |
7182 int length = this->length(); | 7413 int length = this->length(); |
7183 for (int i = 0; i < length; i++) { | 7414 for (int i = 0; i < length; i++) { |
7184 fprintf(file, "%c", Get(i)); | 7415 fprintf(file, "%c", Get(i)); |
7185 } | 7416 } |
7186 } | 7417 } |
7187 | 7418 |
7188 | 7419 |
7189 // Clear a possible back pointer in case the transition leads to a dead map. | 7420 // Clear a possible back pointer in case the transition leads to a dead map. |
7190 // Return true in case a back pointer has been cleared and false otherwise. | 7421 // Return true in case a back pointer has been cleared and false otherwise. |
7191 static bool ClearBackPointer(Heap* heap, Object* target) { | 7422 static bool ClearBackPointer(Heap* heap, Map* target) { |
7192 ASSERT(target->IsMap()); | 7423 if (Marking::MarkBitFrom(target).Get()) return false; |
7193 Map* map = Map::cast(target); | 7424 target->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER); |
7194 if (Marking::MarkBitFrom(map).Get()) return false; | |
7195 map->SetBackPointer(heap->undefined_value(), SKIP_WRITE_BARRIER); | |
7196 return true; | 7425 return true; |
7197 } | 7426 } |
7198 | 7427 |
7199 | 7428 |
7200 // TODO(mstarzinger): This method should be moved into MarkCompactCollector, | 7429 // TODO(mstarzinger): This method should be moved into MarkCompactCollector, |
7201 // because it cannot be called from outside the GC and we already have methods | 7430 // because it cannot be called from outside the GC and we already have methods |
7202 // depending on the transitions layout in the GC anyways. | 7431 // depending on the transitions layout in the GC anyways. |
7203 void Map::ClearNonLiveTransitions(Heap* heap) { | 7432 void Map::ClearNonLiveTransitions(Heap* heap) { |
7204 // If there are no transitions to be cleared, return. | 7433 // If there are no transitions to be cleared, return. |
7205 // TODO(verwaest) Should be an assert, otherwise back pointers are not | 7434 // TODO(verwaest) Should be an assert, otherwise back pointers are not |
7206 // properly cleared. | 7435 // properly cleared. |
7207 if (!HasTransitionArray()) return; | 7436 if (!HasTransitionArray()) return; |
7208 | 7437 |
7209 TransitionArray* t = transitions(); | 7438 TransitionArray* t = transitions(); |
7210 MarkCompactCollector* collector = heap->mark_compact_collector(); | 7439 MarkCompactCollector* collector = heap->mark_compact_collector(); |
7211 | 7440 |
7212 int transition_index = 0; | 7441 int transition_index = 0; |
7213 | 7442 |
| 7443 DescriptorArray* descriptors = t->descriptors(); |
| 7444 bool descriptors_owner_died = false; |
| 7445 |
7214 // Compact all live descriptors to the left. | 7446 // Compact all live descriptors to the left. |
7215 for (int i = 0; i < t->number_of_transitions(); ++i) { | 7447 for (int i = 0; i < t->number_of_transitions(); ++i) { |
7216 if (!ClearBackPointer(heap, t->GetTarget(i))) { | 7448 Map* target = t->GetTarget(i); |
| 7449 if (ClearBackPointer(heap, target)) { |
| 7450 ASSERT(!Marking::IsGrey(Marking::MarkBitFrom(target))); |
| 7451 DescriptorArray* target_descriptors = target->instance_descriptors(); |
| 7452 if ((target_descriptors->number_of_descriptors() == 0 && |
| 7453 target->NumberOfOwnDescriptors() > 0) || |
| 7454 target_descriptors == descriptors) { |
| 7455 descriptors_owner_died = true; |
| 7456 } |
| 7457 } else { |
7217 if (i != transition_index) { | 7458 if (i != transition_index) { |
7218 String* key = t->GetKey(i); | 7459 String* key = t->GetKey(i); |
7219 t->SetKey(transition_index, key); | 7460 t->SetKey(transition_index, key); |
7220 Object** key_slot = t->GetKeySlot(transition_index); | 7461 Object** key_slot = t->GetKeySlot(transition_index); |
7221 collector->RecordSlot(key_slot, key_slot, key); | 7462 collector->RecordSlot(key_slot, key_slot, key); |
7222 // Target slots do not need to be recorded since maps are not compacted. | 7463 // Target slots do not need to be recorded since maps are not compacted. |
7223 t->SetTarget(transition_index, t->GetTarget(i)); | 7464 t->SetTarget(transition_index, t->GetTarget(i)); |
7224 } | 7465 } |
7225 transition_index++; | 7466 transition_index++; |
7226 } | 7467 } |
7227 } | 7468 } |
7228 | 7469 |
7229 if (t->HasElementsTransition() && | 7470 if (t->HasElementsTransition() && |
7230 ClearBackPointer(heap, t->elements_transition())) { | 7471 ClearBackPointer(heap, t->elements_transition())) { |
| 7472 if (t->elements_transition()->instance_descriptors() == descriptors) { |
| 7473 descriptors_owner_died = true; |
| 7474 } |
7231 t->ClearElementsTransition(); | 7475 t->ClearElementsTransition(); |
7232 } else { | 7476 } else { |
7233 // If there are no transitions to be cleared, return. | 7477 // If there are no transitions to be cleared, return. |
7234 // TODO(verwaest) Should be an assert, otherwise back pointers are not | 7478 // TODO(verwaest) Should be an assert, otherwise back pointers are not |
7235 // properly cleared. | 7479 // properly cleared. |
7236 if (transition_index == t->number_of_transitions()) return; | 7480 if (transition_index == t->number_of_transitions()) return; |
7237 } | 7481 } |
7238 | 7482 |
| 7483 int number_of_own_descriptors = NumberOfOwnDescriptors(); |
| 7484 |
| 7485 if (descriptors_owner_died) { |
| 7486 if (number_of_own_descriptors > 0) { |
| 7487 int number_of_descriptors = descriptors->number_of_descriptors(); |
| 7488 int to_trim = number_of_descriptors - number_of_own_descriptors; |
| 7489 if (to_trim > 0) { |
| 7490 RightTrimFixedArray<FROM_GC>( |
| 7491 heap, descriptors, to_trim * DescriptorArray::kDescriptorSize); |
| 7492 if (descriptors->HasEnumCache()) { |
| 7493 int live_enum = |
| 7494 NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_ENUM); |
| 7495 if (live_enum == 0) { |
| 7496 descriptors->ClearEnumCache(); |
| 7497 } else { |
| 7498 FixedArray* enum_cache = |
| 7499 FixedArray::cast(descriptors->GetEnumCache()); |
| 7500 to_trim = enum_cache->length() - live_enum; |
| 7501 if (to_trim > 0) { |
| 7502 RightTrimFixedArray<FROM_GC>( |
| 7503 heap, FixedArray::cast(descriptors->GetEnumCache()), to_trim); |
| 7504 } |
| 7505 } |
| 7506 } |
| 7507 descriptors->Sort(); |
| 7508 } |
| 7509 ASSERT(descriptors->number_of_descriptors() == number_of_own_descriptors); |
| 7510 } else { |
| 7511 t->set_descriptors(heap->empty_descriptor_array()); |
| 7512 } |
| 7513 set_owns_descriptors(true); |
| 7514 } |
| 7515 |
7239 // If the final transition array does not contain any live transitions, remove | 7516 // If the final transition array does not contain any live transitions, remove |
7240 // the transition array from the map. | 7517 // the transition array from the map. |
7241 if (transition_index == 0 && | 7518 if (transition_index == 0 && |
7242 !t->HasElementsTransition() && | 7519 !t->HasElementsTransition() && |
7243 !t->HasPrototypeTransitions() && | 7520 !t->HasPrototypeTransitions() && |
7244 t->descriptors()->IsEmpty()) { | 7521 number_of_own_descriptors == 0) { |
| 7522 ASSERT(owns_descriptors()); |
7245 return ClearTransitions(heap); | 7523 return ClearTransitions(heap); |
7246 } | 7524 } |
7247 | 7525 |
7248 int trim = t->number_of_transitions() - transition_index; | 7526 int trim = t->number_of_transitions() - transition_index; |
7249 if (trim > 0) { | 7527 if (trim > 0) { |
7250 RightTrimFixedArray<FROM_GC>( | 7528 RightTrimFixedArray<FROM_GC>( |
7251 heap, t, trim * TransitionArray::kTransitionSize); | 7529 heap, t, trim * TransitionArray::kTransitionSize); |
7252 } | 7530 } |
7253 } | 7531 } |
7254 | 7532 |
(...skipping 3104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10359 } | 10637 } |
10360 | 10638 |
10361 LookupResult result(isolate); | 10639 LookupResult result(isolate); |
10362 LocalLookupRealNamedProperty(key, &result); | 10640 LocalLookupRealNamedProperty(key, &result); |
10363 return result.IsPropertyCallbacks(); | 10641 return result.IsPropertyCallbacks(); |
10364 } | 10642 } |
10365 | 10643 |
10366 | 10644 |
10367 int JSObject::NumberOfLocalProperties(PropertyAttributes filter) { | 10645 int JSObject::NumberOfLocalProperties(PropertyAttributes filter) { |
10368 return HasFastProperties() ? | 10646 return HasFastProperties() ? |
10369 map()->NumberOfDescribedProperties(filter) : | 10647 map()->NumberOfDescribedProperties(OWN_DESCRIPTORS, filter) : |
10370 property_dictionary()->NumberOfElementsFilterAttributes(filter); | 10648 property_dictionary()->NumberOfElementsFilterAttributes(filter); |
10371 } | 10649 } |
10372 | 10650 |
10373 | 10651 |
10374 void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) { | 10652 void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) { |
10375 Object* temp = get(i); | 10653 Object* temp = get(i); |
10376 set(i, get(j)); | 10654 set(i, get(j)); |
10377 set(j, temp); | 10655 set(j, temp); |
10378 if (this != numbers) { | 10656 if (this != numbers) { |
10379 temp = numbers->get(i); | 10657 temp = numbers->get(i); |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10483 } | 10761 } |
10484 } | 10762 } |
10485 | 10763 |
10486 | 10764 |
10487 // Fill in the names of local properties into the supplied storage. The main | 10765 // Fill in the names of local properties into the supplied storage. The main |
10488 // purpose of this function is to provide reflection information for the object | 10766 // purpose of this function is to provide reflection information for the object |
10489 // mirrors. | 10767 // mirrors. |
10490 void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) { | 10768 void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) { |
10491 ASSERT(storage->length() >= (NumberOfLocalProperties() - index)); | 10769 ASSERT(storage->length() >= (NumberOfLocalProperties() - index)); |
10492 if (HasFastProperties()) { | 10770 if (HasFastProperties()) { |
| 10771 int real_size = map()->NumberOfOwnDescriptors(); |
10493 DescriptorArray* descs = map()->instance_descriptors(); | 10772 DescriptorArray* descs = map()->instance_descriptors(); |
10494 ASSERT(storage->length() >= index + descs->number_of_descriptors()); | 10773 ASSERT(storage->length() >= index + real_size); |
10495 for (int i = 0; i < descs->number_of_descriptors(); i++) { | 10774 for (int i = 0; i < real_size; i++) { |
10496 storage->set(index + i, descs->GetKey(i)); | 10775 storage->set(index + i, descs->GetKey(i)); |
10497 } | 10776 } |
10498 } else { | 10777 } else { |
10499 property_dictionary()->CopyKeysTo(storage, | 10778 property_dictionary()->CopyKeysTo(storage, |
10500 index, | 10779 index, |
10501 StringDictionary::UNSORTED); | 10780 StringDictionary::UNSORTED); |
10502 } | 10781 } |
10503 } | 10782 } |
10504 | 10783 |
10505 | 10784 |
(...skipping 1682 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12188 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length); | 12467 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length); |
12189 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 12468 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
12190 } | 12469 } |
12191 FixedArray* enumeration_order = FixedArray::cast(obj); | 12470 FixedArray* enumeration_order = FixedArray::cast(obj); |
12192 | 12471 |
12193 // Fill the enumeration order array with property details. | 12472 // Fill the enumeration order array with property details. |
12194 int capacity = HashTable<Shape, Key>::Capacity(); | 12473 int capacity = HashTable<Shape, Key>::Capacity(); |
12195 int pos = 0; | 12474 int pos = 0; |
12196 for (int i = 0; i < capacity; i++) { | 12475 for (int i = 0; i < capacity; i++) { |
12197 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) { | 12476 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) { |
12198 enumeration_order->set( | 12477 int index = DetailsAt(i).dictionary_index(); |
12199 pos++, Smi::FromInt(DetailsAt(i).dictionary_index())); | 12478 enumeration_order->set(pos++, Smi::FromInt(index)); |
12200 } | 12479 } |
12201 } | 12480 } |
12202 | 12481 |
12203 // Sort the arrays wrt. enumeration order. | 12482 // Sort the arrays wrt. enumeration order. |
12204 iteration_order->SortPairs(enumeration_order, enumeration_order->length()); | 12483 iteration_order->SortPairs(enumeration_order, enumeration_order->length()); |
12205 | 12484 |
12206 // Overwrite the enumeration_order with the enumeration indices. | 12485 // Overwrite the enumeration_order with the enumeration indices. |
12207 for (int i = 0; i < length; i++) { | 12486 for (int i = 0; i < length; i++) { |
12208 int index = Smi::cast(iteration_order->get(i))->value(); | 12487 int index = Smi::cast(iteration_order->get(i))->value(); |
12209 int enum_index = PropertyDetails::kInitialIndex + i; | 12488 int enum_index = PropertyDetails::kInitialIndex + i; |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
12318 uint32_t hash) { | 12597 uint32_t hash) { |
12319 // Compute the key object. | 12598 // Compute the key object. |
12320 Object* k; | 12599 Object* k; |
12321 { MaybeObject* maybe_k = Shape::AsObject(key); | 12600 { MaybeObject* maybe_k = Shape::AsObject(key); |
12322 if (!maybe_k->ToObject(&k)) return maybe_k; | 12601 if (!maybe_k->ToObject(&k)) return maybe_k; |
12323 } | 12602 } |
12324 | 12603 |
12325 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash); | 12604 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash); |
12326 // Insert element at empty or deleted entry | 12605 // Insert element at empty or deleted entry |
12327 if (!details.IsDeleted() && | 12606 if (!details.IsDeleted() && |
12328 details.dictionary_index() == 0 && Shape::kIsEnumerable) { | 12607 details.dictionary_index() == 0 && |
| 12608 Shape::kIsEnumerable) { |
12329 // Assign an enumeration index to the property and update | 12609 // Assign an enumeration index to the property and update |
12330 // SetNextEnumerationIndex. | 12610 // SetNextEnumerationIndex. |
12331 int index = NextEnumerationIndex(); | 12611 int index = NextEnumerationIndex(); |
12332 details = PropertyDetails(details.attributes(), details.type(), index); | 12612 details = PropertyDetails(details.attributes(), details.type(), index); |
12333 SetNextEnumerationIndex(index + 1); | 12613 SetNextEnumerationIndex(index + 1); |
12334 } | 12614 } |
12335 SetEntry(entry, k, value, details); | 12615 SetEntry(entry, k, value, details); |
12336 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber() | 12616 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber() |
12337 || Dictionary<Shape, Key>::KeyAt(entry)->IsString())); | 12617 || Dictionary<Shape, Key>::KeyAt(entry)->IsString())); |
12338 HashTable<Shape, Key>::ElementAdded(); | 12618 HashTable<Shape, Key>::ElementAdded(); |
(...skipping 873 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
13212 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); | 13492 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); |
13213 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); | 13493 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); |
13214 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); | 13494 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); |
13215 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); | 13495 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); |
13216 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); | 13496 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); |
13217 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); | 13497 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); |
13218 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); | 13498 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); |
13219 } | 13499 } |
13220 | 13500 |
13221 } } // namespace v8::internal | 13501 } } // namespace v8::internal |
OLD | NEW |