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