| 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 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 644 value = result->holder()->FastPropertyAt(result->GetFieldIndex()); | 635 value = result->holder()->FastPropertyAt(result->GetFieldIndex()); |
| 645 ASSERT(!value->IsTheHole() || result->IsReadOnly()); | 636 ASSERT(!value->IsTheHole() || result->IsReadOnly()); |
| 646 return value->IsTheHole() ? heap->undefined_value() : value; | 637 return value->IsTheHole() ? heap->undefined_value() : value; |
| 647 case CONSTANT_FUNCTION: | 638 case CONSTANT_FUNCTION: |
| 648 return result->GetConstantFunction(); | 639 return result->GetConstantFunction(); |
| 649 case CALLBACKS: | 640 case CALLBACKS: |
| 650 return result->holder()->GetPropertyWithCallback( | 641 return result->holder()->GetPropertyWithCallback( |
| 651 receiver, result->GetCallbackObject(), name); | 642 receiver, result->GetCallbackObject(), name); |
| 652 case HANDLER: | 643 case HANDLER: |
| 653 return result->proxy()->GetPropertyWithHandler(receiver, name); | 644 return result->proxy()->GetPropertyWithHandler(receiver, name); |
| 654 case INTERCEPTOR: | 645 case INTERCEPTOR: { |
| 646 JSObject* recvr = JSObject::cast(receiver); |
| 655 return result->holder()->GetPropertyWithInterceptor( | 647 return result->holder()->GetPropertyWithInterceptor( |
| 656 receiver, name, attributes); | 648 recvr, name, attributes); |
| 649 } |
| 657 case TRANSITION: | 650 case TRANSITION: |
| 658 case NONEXISTENT: | 651 case NONEXISTENT: |
| 659 UNREACHABLE(); | 652 UNREACHABLE(); |
| 660 break; | 653 break; |
| 661 } | 654 } |
| 662 UNREACHABLE(); | 655 UNREACHABLE(); |
| 663 return NULL; | 656 return NULL; |
| 664 } | 657 } |
| 665 | 658 |
| 666 | 659 |
| (...skipping 865 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1532 } | 1525 } |
| 1533 return true; | 1526 return true; |
| 1534 } | 1527 } |
| 1535 | 1528 |
| 1536 | 1529 |
| 1537 MaybeObject* JSObject::AddFastProperty(String* name, | 1530 MaybeObject* JSObject::AddFastProperty(String* name, |
| 1538 Object* value, | 1531 Object* value, |
| 1539 PropertyAttributes attributes, | 1532 PropertyAttributes attributes, |
| 1540 StoreFromKeyed store_mode) { | 1533 StoreFromKeyed store_mode) { |
| 1541 ASSERT(!IsJSGlobalProxy()); | 1534 ASSERT(!IsJSGlobalProxy()); |
| 1542 ASSERT(DescriptorArray::kNotFound == | 1535 ASSERT(map()->instance_descriptors()->Search(name) == |
| 1543 map()->instance_descriptors()->Search( | 1536 DescriptorArray::kNotFound); |
| 1544 name, map()->NumberOfOwnDescriptors())); | |
| 1545 | 1537 |
| 1546 // 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 |
| 1547 // hidden symbols) and is not a real identifier. | 1539 // hidden symbols) and is not a real identifier. |
| 1548 // Normalize the object if it will have too many fast properties. | 1540 // Normalize the object if it will have too many fast properties. |
| 1549 Isolate* isolate = GetHeap()->isolate(); | 1541 Isolate* isolate = GetHeap()->isolate(); |
| 1550 StringInputBuffer buffer(name); | 1542 StringInputBuffer buffer(name); |
| 1551 if ((!IsIdentifier(isolate->unicode_cache(), &buffer) | 1543 if ((!IsIdentifier(isolate->unicode_cache(), &buffer) |
| 1552 && name != isolate->heap()->hidden_symbol()) || | 1544 && name != isolate->heap()->hidden_symbol()) || |
| 1553 (map()->unused_property_fields() == 0 && | 1545 (map()->unused_property_fields() == 0 && |
| 1554 TooManyFastProperties(properties()->length(), store_mode))) { | 1546 TooManyFastProperties(properties()->length(), store_mode))) { |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1683 return value; | 1675 return value; |
| 1684 } else { | 1676 } else { |
| 1685 Handle<Object> args[1] = {Handle<String>(name)}; | 1677 Handle<Object> args[1] = {Handle<String>(name)}; |
| 1686 return heap->isolate()->Throw( | 1678 return heap->isolate()->Throw( |
| 1687 *FACTORY->NewTypeError("object_not_extensible", | 1679 *FACTORY->NewTypeError("object_not_extensible", |
| 1688 HandleVector(args, 1))); | 1680 HandleVector(args, 1))); |
| 1689 } | 1681 } |
| 1690 } | 1682 } |
| 1691 if (HasFastProperties()) { | 1683 if (HasFastProperties()) { |
| 1692 // Ensure the descriptor array does not get too big. | 1684 // Ensure the descriptor array does not get too big. |
| 1693 if (map_of_this->NumberOfOwnDescriptors() < | 1685 if (map_of_this->instance_descriptors()->number_of_descriptors() < |
| 1694 DescriptorArray::kMaxNumberOfDescriptors) { | 1686 DescriptorArray::kMaxNumberOfDescriptors) { |
| 1695 if (value->IsJSFunction()) { | 1687 if (value->IsJSFunction()) { |
| 1696 return AddConstantFunctionProperty(name, | 1688 return AddConstantFunctionProperty(name, |
| 1697 JSFunction::cast(value), | 1689 JSFunction::cast(value), |
| 1698 attributes); | 1690 attributes); |
| 1699 } else { | 1691 } else { |
| 1700 return AddFastProperty(name, value, attributes, store_mode); | 1692 return AddFastProperty(name, value, attributes, store_mode); |
| 1701 } | 1693 } |
| 1702 } else { | 1694 } else { |
| 1703 // Normalize the object to prevent very large instance descriptors. | 1695 // Normalize the object to prevent very large instance descriptors. |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1754 return SetNormalizedProperty(name, value, new_details); | 1746 return SetNormalizedProperty(name, value, new_details); |
| 1755 } | 1747 } |
| 1756 | 1748 |
| 1757 | 1749 |
| 1758 MaybeObject* JSObject::ConvertTransitionToMapTransition( | 1750 MaybeObject* JSObject::ConvertTransitionToMapTransition( |
| 1759 int transition_index, | 1751 int transition_index, |
| 1760 String* name, | 1752 String* name, |
| 1761 Object* new_value, | 1753 Object* new_value, |
| 1762 PropertyAttributes attributes) { | 1754 PropertyAttributes attributes) { |
| 1763 Map* old_map = map(); | 1755 Map* old_map = map(); |
| 1764 Map* old_target = old_map->GetTransition(transition_index); | |
| 1765 Object* result; | 1756 Object* result; |
| 1766 | 1757 |
| 1767 // To sever a transition to a map with which the descriptors are shared, the | |
| 1768 // larger map (more descriptors) needs to store its own descriptors array. | |
| 1769 // Both sides of the severed chain need to have their own descriptors pointer | |
| 1770 // to store distinct descriptor arrays. | |
| 1771 | |
| 1772 // If the old_target did not yet store its own descriptors, the new | |
| 1773 // descriptors pointer is created for the old_target by temporarily clearing | |
| 1774 // the back pointer and setting its descriptor array. The ownership of the | |
| 1775 // descriptor array is returned to the smaller maps by installing a reduced | |
| 1776 // copy of the descriptor array in the old_map. | |
| 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 old_map->set_owns_descriptors(true); | |
| 1792 } | |
| 1793 | |
| 1794 MaybeObject* maybe_result = | 1758 MaybeObject* maybe_result = |
| 1795 ConvertDescriptorToField(name, new_value, attributes); | 1759 ConvertDescriptorToField(name, new_value, attributes); |
| 1796 if (!maybe_result->To(&result)) return maybe_result; | 1760 if (!maybe_result->To(&result)) return maybe_result; |
| 1797 | 1761 |
| 1798 if (!HasFastProperties()) return result; | 1762 if (!HasFastProperties()) return result; |
| 1799 | 1763 |
| 1800 // This method should only be used to convert existing transitions. Objects | 1764 // This method should only be used to convert existing transitions. Objects |
| 1801 // 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. |
| 1802 Map* new_map = map(); | 1766 ASSERT(map() != GetIsolate()->empty_object_map()); |
| 1803 ASSERT(new_map != GetIsolate()->empty_object_map()); | |
| 1804 | 1767 |
| 1805 // TODO(verwaest): From here on we lose existing map transitions, causing | 1768 // TODO(verwaest): From here on we lose existing map transitions, causing |
| 1806 // invalid back pointers. This will change once we can store multiple | 1769 // invalid back pointers. This will change once we can store multiple |
| 1807 // transitions with the same key. | 1770 // transitions with the same key. |
| 1808 | 1771 old_map->SetTransition(transition_index, map()); |
| 1809 if (old_map->owns_descriptors()) { | 1772 map()->SetBackPointer(old_map); |
| 1810 // If the old map owns its own descriptors, transfer ownership to the | |
| 1811 // new_map and install its descriptors in the old_map. Since the old_map | |
| 1812 // stores the descriptors for the new_map, remove the transition array of | |
| 1813 // the new_map that is only in place to store the descriptors. | |
| 1814 old_map->transitions()->descriptors_pointer()->set_value( | |
| 1815 new_map->instance_descriptors()); | |
| 1816 new_map->ClearTransitions(GetHeap()); | |
| 1817 old_map->set_owns_descriptors(false); | |
| 1818 Map* map; | |
| 1819 JSGlobalPropertyCell* pointer = | |
| 1820 old_map->transitions()->descriptors_pointer(); | |
| 1821 for (Object* current = old_map; | |
| 1822 !current->IsUndefined(); | |
| 1823 current = map->GetBackPointer()) { | |
| 1824 map = Map::cast(current); | |
| 1825 if (!map->HasTransitionArray()) break; | |
| 1826 TransitionArray* transitions = map->transitions(); | |
| 1827 if (transitions->descriptors_pointer() != pointer) break; | |
| 1828 map->SetEnumLength(Map::kInvalidEnumCache); | |
| 1829 } | |
| 1830 } else if (old_target->instance_descriptors() == | |
| 1831 old_map->instance_descriptors()) { | |
| 1832 // Since the conversion above generated a new fast map with an additional | |
| 1833 // property which can be shared as well, install this descriptor pointer | |
| 1834 // along the entire chain of smaller maps; and remove the transition array | |
| 1835 // that is only in place to hold the descriptor array in the new map. | |
| 1836 Map* map; | |
| 1837 JSGlobalPropertyCell* new_pointer = | |
| 1838 new_map->transitions()->descriptors_pointer(); | |
| 1839 JSGlobalPropertyCell* old_pointer = | |
| 1840 old_map->transitions()->descriptors_pointer(); | |
| 1841 for (Object* current = old_map; | |
| 1842 !current->IsUndefined(); | |
| 1843 current = map->GetBackPointer()) { | |
| 1844 map = Map::cast(current); | |
| 1845 if (!map->HasTransitionArray()) break; | |
| 1846 TransitionArray* transitions = map->transitions(); | |
| 1847 if (transitions->descriptors_pointer() != old_pointer) break; | |
| 1848 map->SetEnumLength(Map::kInvalidEnumCache); | |
| 1849 transitions->set_descriptors_pointer(new_pointer); | |
| 1850 } | |
| 1851 new_map->ClearTransitions(GetHeap()); | |
| 1852 } | |
| 1853 | |
| 1854 old_map->SetTransition(transition_index, new_map); | |
| 1855 new_map->SetBackPointer(old_map); | |
| 1856 return result; | 1773 return result; |
| 1857 } | 1774 } |
| 1858 | 1775 |
| 1859 | 1776 |
| 1860 MaybeObject* JSObject::ConvertDescriptorToField(String* name, | 1777 MaybeObject* JSObject::ConvertDescriptorToField(String* name, |
| 1861 Object* new_value, | 1778 Object* new_value, |
| 1862 PropertyAttributes attributes) { | 1779 PropertyAttributes attributes) { |
| 1863 if (map()->unused_property_fields() == 0 && | 1780 if (map()->unused_property_fields() == 0 && |
| 1864 TooManyFastProperties(properties()->length(), MAY_BE_STORE_FROM_KEYED)) { | 1781 TooManyFastProperties(properties()->length(), MAY_BE_STORE_FROM_KEYED)) { |
| 1865 Object* obj; | 1782 Object* obj; |
| (...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2169 return heap->the_hole_value(); | 2086 return heap->the_hole_value(); |
| 2170 } | 2087 } |
| 2171 | 2088 |
| 2172 | 2089 |
| 2173 enum RightTrimMode { FROM_GC, FROM_MUTATOR }; | 2090 enum RightTrimMode { FROM_GC, FROM_MUTATOR }; |
| 2174 | 2091 |
| 2175 | 2092 |
| 2176 static void ZapEndOfFixedArray(Address new_end, int to_trim) { | 2093 static void ZapEndOfFixedArray(Address new_end, int to_trim) { |
| 2177 // If we are doing a big trim in old space then we zap the space. | 2094 // If we are doing a big trim in old space then we zap the space. |
| 2178 Object** zap = reinterpret_cast<Object**>(new_end); | 2095 Object** zap = reinterpret_cast<Object**>(new_end); |
| 2179 zap++; // Header of filler must be at least one word so skip that. | |
| 2180 for (int i = 1; i < to_trim; i++) { | 2096 for (int i = 1; i < to_trim; i++) { |
| 2181 *zap++ = Smi::FromInt(0); | 2097 *zap++ = Smi::FromInt(0); |
| 2182 } | 2098 } |
| 2183 } | 2099 } |
| 2184 | 2100 |
| 2185 | |
| 2186 template<RightTrimMode trim_mode> | 2101 template<RightTrimMode trim_mode> |
| 2187 static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) { | 2102 static void RightTrimFixedArray(Heap* heap, FixedArray* elms, int to_trim) { |
| 2188 ASSERT(elms->map() != HEAP->fixed_cow_array_map()); | 2103 ASSERT(elms->map() != HEAP->fixed_cow_array_map()); |
| 2189 // For now this trick is only applied to fixed arrays in new and paged space. | 2104 // For now this trick is only applied to fixed arrays in new and paged space. |
| 2190 ASSERT(!HEAP->lo_space()->Contains(elms)); | 2105 ASSERT(!HEAP->lo_space()->Contains(elms)); |
| 2191 | 2106 |
| 2192 const int len = elms->length(); | 2107 const int len = elms->length(); |
| 2193 | 2108 |
| 2194 ASSERT(to_trim < len); | 2109 ASSERT(to_trim < len); |
| 2195 | 2110 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 2216 if (Marking::IsBlack(Marking::MarkBitFrom(elms))) { | 2131 if (Marking::IsBlack(Marking::MarkBitFrom(elms))) { |
| 2217 if (trim_mode == FROM_GC) { | 2132 if (trim_mode == FROM_GC) { |
| 2218 MemoryChunk::IncrementLiveBytesFromGC(elms->address(), -size_delta); | 2133 MemoryChunk::IncrementLiveBytesFromGC(elms->address(), -size_delta); |
| 2219 } else { | 2134 } else { |
| 2220 MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta); | 2135 MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta); |
| 2221 } | 2136 } |
| 2222 } | 2137 } |
| 2223 } | 2138 } |
| 2224 | 2139 |
| 2225 | 2140 |
| 2226 void Map::EnsureDescriptorSlack(Handle<Map> map, int slack) { | 2141 void Map::CopyAppendCallbackDescriptors(Handle<Map> map, |
| 2227 Handle<DescriptorArray> descriptors(map->instance_descriptors()); | 2142 Handle<Object> descriptors) { |
| 2228 if (slack <= descriptors->NumberOfSlackDescriptors()) return; | |
| 2229 int number_of_descriptors = descriptors->number_of_descriptors(); | |
| 2230 Isolate* isolate = map->GetIsolate(); | |
| 2231 Handle<DescriptorArray> new_descriptors = | |
| 2232 isolate->factory()->NewDescriptorArray(number_of_descriptors, slack); | |
| 2233 DescriptorArray::WhitenessWitness witness(*new_descriptors); | |
| 2234 | |
| 2235 for (int i = 0; i < number_of_descriptors; ++i) { | |
| 2236 new_descriptors->CopyFrom(i, *descriptors, i, witness); | |
| 2237 } | |
| 2238 | |
| 2239 Map::SetDescriptors(map, new_descriptors); | |
| 2240 } | |
| 2241 | |
| 2242 | |
| 2243 void Map::AppendCallbackDescriptors(Handle<Map> map, | |
| 2244 Handle<Object> descriptors) { | |
| 2245 Isolate* isolate = map->GetIsolate(); | 2143 Isolate* isolate = map->GetIsolate(); |
| 2246 Handle<DescriptorArray> array(map->instance_descriptors()); | 2144 Handle<DescriptorArray> array(map->instance_descriptors()); |
| 2247 NeanderArray callbacks(descriptors); | 2145 v8::NeanderArray callbacks(descriptors); |
| 2248 int nof_callbacks = callbacks.length(); | 2146 int nof_callbacks = callbacks.length(); |
| 2249 | 2147 int descriptor_count = array->number_of_descriptors(); |
| 2250 ASSERT(array->NumberOfSlackDescriptors() >= nof_callbacks); | |
| 2251 | 2148 |
| 2252 // Ensure the keys are symbols before writing them into the instance | 2149 // Ensure the keys are symbols before writing them into the instance |
| 2253 // 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 |
| 2254 // temporarily put the heap in an invalid state while appending descriptors. | 2151 // temporarily put the heap in an invalid state while appending descriptors. |
| 2255 for (int i = 0; i < nof_callbacks; ++i) { | 2152 for (int i = 0; i < nof_callbacks; ++i) { |
| 2256 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks.get(i))); | 2153 Handle<AccessorInfo> entry(AccessorInfo::cast(callbacks.get(i))); |
| 2257 Handle<String> key = | 2154 Handle<String> key = |
| 2258 isolate->factory()->SymbolFromString( | 2155 isolate->factory()->SymbolFromString( |
| 2259 Handle<String>(String::cast(entry->name()))); | 2156 Handle<String>(String::cast(entry->name()))); |
| 2260 entry->set_name(*key); | 2157 entry->set_name(*key); |
| 2261 } | 2158 } |
| 2262 | 2159 |
| 2263 int nof = map->NumberOfOwnDescriptors(); | 2160 Handle<DescriptorArray> result = |
| 2161 isolate->factory()->NewDescriptorArray(descriptor_count + nof_callbacks); |
| 2162 |
| 2163 // Ensure that marking will not progress and change color of objects. |
| 2164 DescriptorArray::WhitenessWitness witness(*result); |
| 2165 |
| 2166 // Copy the descriptors from the array. |
| 2167 if (0 < descriptor_count) { |
| 2168 for (int i = 0; i < descriptor_count; i++) { |
| 2169 result->CopyFrom(i, *array, i, witness); |
| 2170 } |
| 2171 } |
| 2172 |
| 2173 // 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 |
| 2175 // descriptor array is trimmed to the right size. |
| 2176 Map::SetDescriptors(map, result); |
| 2264 | 2177 |
| 2265 // Fill in new callback descriptors. Process the callbacks from | 2178 // Fill in new callback descriptors. Process the callbacks from |
| 2266 // 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 |
| 2267 // precedence over previously added callbacks with that name. | 2180 // precedence over previously added callbacks with that name. |
| 2268 for (int i = nof_callbacks - 1; i >= 0; i--) { | 2181 for (int i = nof_callbacks - 1; i >= 0; i--) { |
| 2269 AccessorInfo* entry = AccessorInfo::cast(callbacks.get(i)); | 2182 AccessorInfo* entry = AccessorInfo::cast(callbacks.get(i)); |
| 2270 String* key = String::cast(entry->name()); | 2183 String* key = String::cast(entry->name()); |
| 2271 // Check if a descriptor with this name already exists before writing. | 2184 // Check if a descriptor with this name already exists before writing. |
| 2272 if (array->Search(key, nof) == DescriptorArray::kNotFound) { | 2185 if (LinearSearch(*result, key, map->NumberOfOwnDescriptors()) == |
| 2186 DescriptorArray::kNotFound) { |
| 2273 CallbacksDescriptor desc(key, entry, entry->property_attributes()); | 2187 CallbacksDescriptor desc(key, entry, entry->property_attributes()); |
| 2274 array->Append(&desc); | 2188 map->AppendDescriptor(&desc, witness); |
| 2275 nof += 1; | |
| 2276 } | 2189 } |
| 2277 } | 2190 } |
| 2278 | 2191 |
| 2279 map->SetNumberOfOwnDescriptors(nof); | 2192 int new_number_of_descriptors = map->NumberOfOwnDescriptors(); |
| 2193 // Reinstall the original descriptor array if no new elements were added. |
| 2194 if (new_number_of_descriptors == descriptor_count) { |
| 2195 Map::SetDescriptors(map, array); |
| 2196 return; |
| 2197 } |
| 2198 |
| 2199 // If duplicates were detected, trim the descriptor array to the right size. |
| 2200 int new_array_size = DescriptorArray::LengthFor(new_number_of_descriptors); |
| 2201 if (new_array_size < result->length()) { |
| 2202 RightTrimFixedArray<FROM_MUTATOR>( |
| 2203 isolate->heap(), *result, result->length() - new_array_size); |
| 2204 } |
| 2280 } | 2205 } |
| 2281 | 2206 |
| 2282 | 2207 |
| 2283 static bool ContainsMap(MapHandleList* maps, Handle<Map> map) { | 2208 static bool ContainsMap(MapHandleList* maps, Handle<Map> map) { |
| 2284 ASSERT(!map.is_null()); | 2209 ASSERT(!map.is_null()); |
| 2285 for (int i = 0; i < maps->length(); ++i) { | 2210 for (int i = 0; i < maps->length(); ++i) { |
| 2286 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true; | 2211 if (!maps->at(i).is_null() && maps->at(i).is_identical_to(map)) return true; |
| 2287 } | 2212 } |
| 2288 return false; | 2213 return false; |
| 2289 } | 2214 } |
| (...skipping 1042 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3332 if (!HasFastProperties()) return this; | 3257 if (!HasFastProperties()) return this; |
| 3333 | 3258 |
| 3334 // The global object is always normalized. | 3259 // The global object is always normalized. |
| 3335 ASSERT(!IsGlobalObject()); | 3260 ASSERT(!IsGlobalObject()); |
| 3336 // JSGlobalProxy must never be normalized | 3261 // JSGlobalProxy must never be normalized |
| 3337 ASSERT(!IsJSGlobalProxy()); | 3262 ASSERT(!IsJSGlobalProxy()); |
| 3338 | 3263 |
| 3339 Map* map_of_this = map(); | 3264 Map* map_of_this = map(); |
| 3340 | 3265 |
| 3341 // Allocate new content. | 3266 // Allocate new content. |
| 3342 int real_size = map_of_this->NumberOfOwnDescriptors(); | 3267 int property_count = map_of_this->NumberOfDescribedProperties(); |
| 3343 int property_count = real_size; | |
| 3344 if (expected_additional_properties > 0) { | 3268 if (expected_additional_properties > 0) { |
| 3345 property_count += expected_additional_properties; | 3269 property_count += expected_additional_properties; |
| 3346 } else { | 3270 } else { |
| 3347 property_count += 2; // Make space for two more properties. | 3271 property_count += 2; // Make space for two more properties. |
| 3348 } | 3272 } |
| 3349 StringDictionary* dictionary; | 3273 StringDictionary* dictionary; |
| 3350 MaybeObject* maybe_dictionary = StringDictionary::Allocate(property_count); | 3274 { MaybeObject* maybe_dictionary = StringDictionary::Allocate(property_count); |
| 3351 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; | 3275 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; |
| 3276 } |
| 3352 | 3277 |
| 3353 DescriptorArray* descs = map_of_this->instance_descriptors(); | 3278 DescriptorArray* descs = map_of_this->instance_descriptors(); |
| 3354 for (int i = 0; i < real_size; i++) { | 3279 for (int i = 0; i < descs->number_of_descriptors(); i++) { |
| 3355 PropertyDetails details = descs->GetDetails(i); | 3280 PropertyDetails details = descs->GetDetails(i); |
| 3356 switch (details.type()) { | 3281 switch (details.type()) { |
| 3357 case CONSTANT_FUNCTION: { | 3282 case CONSTANT_FUNCTION: { |
| 3358 PropertyDetails d = PropertyDetails(details.attributes(), | 3283 PropertyDetails d = PropertyDetails(details.attributes(), |
| 3359 NORMAL, | 3284 NORMAL, |
| 3360 details.descriptor_index()); | 3285 details.descriptor_index()); |
| 3361 Object* value = descs->GetConstantFunction(i); | 3286 Object* value = descs->GetConstantFunction(i); |
| 3362 MaybeObject* maybe_dictionary = | 3287 MaybeObject* maybe_dictionary = |
| 3363 dictionary->Add(descs->GetKey(i), value, d); | 3288 dictionary->Add(descs->GetKey(i), value, d); |
| 3364 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; | 3289 if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 3389 case TRANSITION: | 3314 case TRANSITION: |
| 3390 case NONEXISTENT: | 3315 case NONEXISTENT: |
| 3391 UNREACHABLE(); | 3316 UNREACHABLE(); |
| 3392 break; | 3317 break; |
| 3393 } | 3318 } |
| 3394 } | 3319 } |
| 3395 | 3320 |
| 3396 Heap* current_heap = GetHeap(); | 3321 Heap* current_heap = GetHeap(); |
| 3397 | 3322 |
| 3398 // Copy the next enumeration index from instance descriptor. | 3323 // Copy the next enumeration index from instance descriptor. |
| 3399 dictionary->SetNextEnumerationIndex(real_size + 1); | 3324 int index = map_of_this->instance_descriptors()->NextEnumerationIndex(); |
| 3325 dictionary->SetNextEnumerationIndex(index); |
| 3400 | 3326 |
| 3401 Map* new_map; | 3327 Map* new_map; |
| 3402 MaybeObject* maybe_map = | 3328 MaybeObject* maybe_map = |
| 3403 current_heap->isolate()->context()->native_context()-> | 3329 current_heap->isolate()->context()->native_context()-> |
| 3404 normalized_map_cache()->Get(this, mode); | 3330 normalized_map_cache()->Get(this, mode); |
| 3405 if (!maybe_map->To(&new_map)) return maybe_map; | 3331 if (!maybe_map->To(&new_map)) return maybe_map; |
| 3406 ASSERT(new_map->is_dictionary_map()); | 3332 ASSERT(new_map->is_dictionary_map()); |
| 3407 | 3333 |
| 3408 // We have now successfully allocated all the necessary objects. | 3334 // We have now successfully allocated all the necessary objects. |
| 3409 // 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... |
| 3735 ASSERT(!IsJSGlobalProxy()); | 3661 ASSERT(!IsJSGlobalProxy()); |
| 3736 Object* inline_value; | 3662 Object* inline_value; |
| 3737 if (HasFastProperties()) { | 3663 if (HasFastProperties()) { |
| 3738 // If the object has fast properties, check whether the first slot | 3664 // If the object has fast properties, check whether the first slot |
| 3739 // in the descriptor array matches the hidden symbol. Since the | 3665 // in the descriptor array matches the hidden symbol. Since the |
| 3740 // 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 |
| 3741 // code zero) it will always occupy the first entry if present. | 3667 // code zero) it will always occupy the first entry if present. |
| 3742 DescriptorArray* descriptors = this->map()->instance_descriptors(); | 3668 DescriptorArray* descriptors = this->map()->instance_descriptors(); |
| 3743 if (descriptors->number_of_descriptors() > 0) { | 3669 if (descriptors->number_of_descriptors() > 0) { |
| 3744 int sorted_index = descriptors->GetSortedKeyIndex(0); | 3670 int sorted_index = descriptors->GetSortedKeyIndex(0); |
| 3745 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_symbol() && | 3671 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_symbol()) { |
| 3746 sorted_index < map()->NumberOfOwnDescriptors()) { | |
| 3747 ASSERT(descriptors->GetType(sorted_index) == FIELD); | 3672 ASSERT(descriptors->GetType(sorted_index) == FIELD); |
| 3748 inline_value = | 3673 inline_value = this->FastPropertyAt( |
| 3749 this->FastPropertyAt(descriptors->GetFieldIndex(sorted_index)); | 3674 descriptors->GetFieldIndex(sorted_index)); |
| 3750 } else { | 3675 } else { |
| 3751 inline_value = GetHeap()->undefined_value(); | 3676 inline_value = GetHeap()->undefined_value(); |
| 3752 } | 3677 } |
| 3753 } else { | 3678 } else { |
| 3754 inline_value = GetHeap()->undefined_value(); | 3679 inline_value = GetHeap()->undefined_value(); |
| 3755 } | 3680 } |
| 3756 } else { | 3681 } else { |
| 3757 PropertyAttributes attributes; | 3682 PropertyAttributes attributes; |
| 3758 // 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, |
| 3759 // 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... |
| 3804 // for hidden properties yet. | 3729 // for hidden properties yet. |
| 3805 ASSERT(HasHiddenProperties() != value->IsSmi()); | 3730 ASSERT(HasHiddenProperties() != value->IsSmi()); |
| 3806 if (HasFastProperties()) { | 3731 if (HasFastProperties()) { |
| 3807 // If the object has fast properties, check whether the first slot | 3732 // If the object has fast properties, check whether the first slot |
| 3808 // in the descriptor array matches the hidden symbol. Since the | 3733 // in the descriptor array matches the hidden symbol. Since the |
| 3809 // 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 |
| 3810 // code zero) it will always occupy the first entry if present. | 3735 // code zero) it will always occupy the first entry if present. |
| 3811 DescriptorArray* descriptors = this->map()->instance_descriptors(); | 3736 DescriptorArray* descriptors = this->map()->instance_descriptors(); |
| 3812 if (descriptors->number_of_descriptors() > 0) { | 3737 if (descriptors->number_of_descriptors() > 0) { |
| 3813 int sorted_index = descriptors->GetSortedKeyIndex(0); | 3738 int sorted_index = descriptors->GetSortedKeyIndex(0); |
| 3814 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_symbol() && | 3739 if (descriptors->GetKey(sorted_index) == GetHeap()->hidden_symbol()) { |
| 3815 sorted_index < map()->NumberOfOwnDescriptors()) { | |
| 3816 ASSERT(descriptors->GetType(sorted_index) == FIELD); | 3740 ASSERT(descriptors->GetType(sorted_index) == FIELD); |
| 3817 this->FastPropertyAtPut(descriptors->GetFieldIndex(sorted_index), | 3741 this->FastPropertyAtPut(descriptors->GetFieldIndex(sorted_index), |
| 3818 value); | 3742 value); |
| 3819 return this; | 3743 return this; |
| 3820 } | 3744 } |
| 3821 } | 3745 } |
| 3822 } | 3746 } |
| 3823 MaybeObject* store_result = | 3747 MaybeObject* store_result = |
| 3824 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(), | 3748 SetPropertyPostInterceptor(GetHeap()->hidden_symbol(), |
| 3825 value, | 3749 value, |
| (...skipping 421 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4247 } | 4171 } |
| 4248 | 4172 |
| 4249 | 4173 |
| 4250 void Map::SetDescriptors(Handle<Map> map, | 4174 void Map::SetDescriptors(Handle<Map> map, |
| 4251 Handle<DescriptorArray> descriptors) { | 4175 Handle<DescriptorArray> descriptors) { |
| 4252 Isolate* isolate = map->GetIsolate(); | 4176 Isolate* isolate = map->GetIsolate(); |
| 4253 CALL_HEAP_FUNCTION_VOID(isolate, map->SetDescriptors(*descriptors)); | 4177 CALL_HEAP_FUNCTION_VOID(isolate, map->SetDescriptors(*descriptors)); |
| 4254 } | 4178 } |
| 4255 | 4179 |
| 4256 | 4180 |
| 4257 int Map::NumberOfDescribedProperties(DescriptorFlag which, | 4181 int Map::NumberOfDescribedProperties(PropertyAttributes filter) { |
| 4258 PropertyAttributes filter) { | |
| 4259 int result = 0; | 4182 int result = 0; |
| 4260 DescriptorArray* descs = instance_descriptors(); | 4183 DescriptorArray* descs = instance_descriptors(); |
| 4261 int limit = which == ALL_DESCRIPTORS | 4184 for (int i = 0; i < descs->number_of_descriptors(); i++) { |
| 4262 ? descs->number_of_descriptors() | 4185 PropertyDetails details = descs->GetDetails(i); |
| 4263 : NumberOfOwnDescriptors(); | 4186 if ((details.attributes() & filter) == 0) { |
| 4264 for (int i = 0; i < limit; i++) { | 4187 result++; |
| 4265 if ((descs->GetDetails(i).attributes() & filter) == 0) result++; | 4188 } |
| 4266 } | 4189 } |
| 4267 return result; | 4190 return result; |
| 4268 } | 4191 } |
| 4269 | 4192 |
| 4270 | 4193 |
| 4271 int Map::PropertyIndexFor(String* name) { | 4194 int Map::PropertyIndexFor(String* name) { |
| 4272 DescriptorArray* descs = instance_descriptors(); | 4195 DescriptorArray* descs = instance_descriptors(); |
| 4273 int limit = NumberOfOwnDescriptors(); | 4196 for (int i = 0; i < descs->number_of_descriptors(); i++) { |
| 4274 for (int i = 0; i < limit; i++) { | |
| 4275 if (name->Equals(descs->GetKey(i))) return descs->GetFieldIndex(i); | 4197 if (name->Equals(descs->GetKey(i))) return descs->GetFieldIndex(i); |
| 4276 } | 4198 } |
| 4277 return -1; | 4199 return -1; |
| 4278 } | 4200 } |
| 4279 | 4201 |
| 4280 | 4202 |
| 4281 int Map::NextFreePropertyIndex() { | 4203 int Map::NextFreePropertyIndex() { |
| 4282 int max_index = -1; | 4204 int max_index = -1; |
| 4283 int number_of_own_descriptors = NumberOfOwnDescriptors(); | |
| 4284 DescriptorArray* descs = instance_descriptors(); | 4205 DescriptorArray* descs = instance_descriptors(); |
| 4285 for (int i = 0; i < number_of_own_descriptors; i++) { | 4206 for (int i = 0; i < descs->number_of_descriptors(); i++) { |
| 4286 if (descs->GetType(i) == FIELD) { | 4207 if (descs->GetType(i) == FIELD) { |
| 4287 int current_index = descs->GetFieldIndex(i); | 4208 int current_index = descs->GetFieldIndex(i); |
| 4288 if (current_index > max_index) max_index = current_index; | 4209 if (current_index > max_index) max_index = current_index; |
| 4289 } | 4210 } |
| 4290 } | 4211 } |
| 4291 return max_index + 1; | 4212 return max_index + 1; |
| 4292 } | 4213 } |
| 4293 | 4214 |
| 4294 | 4215 |
| 4295 AccessorDescriptor* Map::FindAccessor(String* name) { | 4216 AccessorDescriptor* Map::FindAccessor(String* name) { |
| 4296 DescriptorArray* descs = instance_descriptors(); | 4217 DescriptorArray* descs = instance_descriptors(); |
| 4297 int number_of_own_descriptors = NumberOfOwnDescriptors(); | 4218 for (int i = 0; i < descs->number_of_descriptors(); i++) { |
| 4298 for (int i = 0; i < number_of_own_descriptors; i++) { | 4219 if (name->Equals(descs->GetKey(i)) && descs->GetType(i) == CALLBACKS) { |
| 4299 if (descs->GetType(i) == CALLBACKS && name->Equals(descs->GetKey(i))) { | |
| 4300 return descs->GetCallbacks(i); | 4220 return descs->GetCallbacks(i); |
| 4301 } | 4221 } |
| 4302 } | 4222 } |
| 4303 return NULL; | 4223 return NULL; |
| 4304 } | 4224 } |
| 4305 | 4225 |
| 4306 | 4226 |
| 4307 void JSReceiver::LocalLookup(String* name, LookupResult* result) { | 4227 void JSReceiver::LocalLookup(String* name, LookupResult* result) { |
| 4308 ASSERT(name->IsString()); | 4228 ASSERT(name->IsString()); |
| 4309 | 4229 |
| (...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4713 } else { | 4633 } else { |
| 4714 return GetHeap()->null_value(); | 4634 return GetHeap()->null_value(); |
| 4715 } | 4635 } |
| 4716 | 4636 |
| 4717 int descriptor_number = result.GetDescriptorIndex(); | 4637 int descriptor_number = result.GetDescriptorIndex(); |
| 4718 | 4638 |
| 4719 map()->LookupTransition(this, name, &result); | 4639 map()->LookupTransition(this, name, &result); |
| 4720 | 4640 |
| 4721 if (result.IsFound()) { | 4641 if (result.IsFound()) { |
| 4722 Map* target = result.GetTransitionTarget(); | 4642 Map* target = result.GetTransitionTarget(); |
| 4723 ASSERT(target->NumberOfOwnDescriptors() == | 4643 ASSERT(target->instance_descriptors()->number_of_descriptors() == |
| 4724 map()->NumberOfOwnDescriptors()); | 4644 map()->instance_descriptors()->number_of_descriptors()); |
| 4725 // This works since descriptors are sorted in order of addition. | 4645 ASSERT(target->instance_descriptors()->GetKey(descriptor_number) == name); |
| 4726 ASSERT(map()->instance_descriptors()->GetKey(descriptor_number) == name); | |
| 4727 return TryAccessorTransition( | 4646 return TryAccessorTransition( |
| 4728 this, target, descriptor_number, component, accessor, attributes); | 4647 this, target, descriptor_number, component, accessor, attributes); |
| 4729 } | 4648 } |
| 4730 } else { | 4649 } else { |
| 4731 // If not, lookup a transition. | 4650 // If not, lookup a transition. |
| 4732 map()->LookupTransition(this, name, &result); | 4651 map()->LookupTransition(this, name, &result); |
| 4733 | 4652 |
| 4734 // If there is a transition, try to follow it. | 4653 // If there is a transition, try to follow it. |
| 4735 if (result.IsFound()) { | 4654 if (result.IsFound()) { |
| 4736 Map* target = result.GetTransitionTarget(); | 4655 Map* target = result.GetTransitionTarget(); |
| (...skipping 162 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4899 } | 4818 } |
| 4900 } | 4819 } |
| 4901 } | 4820 } |
| 4902 } | 4821 } |
| 4903 return heap->undefined_value(); | 4822 return heap->undefined_value(); |
| 4904 } | 4823 } |
| 4905 | 4824 |
| 4906 | 4825 |
| 4907 Object* JSObject::SlowReverseLookup(Object* value) { | 4826 Object* JSObject::SlowReverseLookup(Object* value) { |
| 4908 if (HasFastProperties()) { | 4827 if (HasFastProperties()) { |
| 4909 int number_of_own_descriptors = map()->NumberOfOwnDescriptors(); | |
| 4910 DescriptorArray* descs = map()->instance_descriptors(); | 4828 DescriptorArray* descs = map()->instance_descriptors(); |
| 4911 for (int i = 0; i < number_of_own_descriptors; i++) { | 4829 for (int i = 0; i < descs->number_of_descriptors(); i++) { |
| 4912 if (descs->GetType(i) == FIELD) { | 4830 if (descs->GetType(i) == FIELD) { |
| 4913 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) { | 4831 if (FastPropertyAt(descs->GetFieldIndex(i)) == value) { |
| 4914 return descs->GetKey(i); | 4832 return descs->GetKey(i); |
| 4915 } | 4833 } |
| 4916 } else if (descs->GetType(i) == CONSTANT_FUNCTION) { | 4834 } else if (descs->GetType(i) == CONSTANT_FUNCTION) { |
| 4917 if (descs->GetConstantFunction(i) == value) { | 4835 if (descs->GetConstantFunction(i) == value) { |
| 4918 return descs->GetKey(i); | 4836 return descs->GetKey(i); |
| 4919 } | 4837 } |
| 4920 } | 4838 } |
| 4921 } | 4839 } |
| 4922 return GetHeap()->undefined_value(); | 4840 return GetHeap()->undefined_value(); |
| 4923 } else { | 4841 } else { |
| 4924 return property_dictionary()->SlowReverseLookup(value); | 4842 return property_dictionary()->SlowReverseLookup(value); |
| 4925 } | 4843 } |
| 4926 } | 4844 } |
| 4927 | 4845 |
| 4928 | 4846 |
| 4929 MaybeObject* Map::RawCopy(int instance_size) { | 4847 MaybeObject* Map::RawCopy(int instance_size) { |
| 4930 Map* result; | 4848 Map* result; |
| 4931 MaybeObject* maybe_result = | 4849 MaybeObject* maybe_result = |
| 4932 GetHeap()->AllocateMap(instance_type(), instance_size); | 4850 GetHeap()->AllocateMap(instance_type(), instance_size); |
| 4933 if (!maybe_result->To(&result)) return maybe_result; | 4851 if (!maybe_result->To(&result)) return maybe_result; |
| 4934 | 4852 |
| 4935 result->set_prototype(prototype()); | 4853 result->set_prototype(prototype()); |
| 4936 result->set_constructor(constructor()); | 4854 result->set_constructor(constructor()); |
| 4937 result->set_bit_field(bit_field()); | 4855 result->set_bit_field(bit_field()); |
| 4938 result->set_bit_field2(bit_field2()); | 4856 result->set_bit_field2(bit_field2()); |
| 4939 result->set_bit_field3(bit_field3()); | 4857 result->set_bit_field3(bit_field3()); |
| 4940 int new_bit_field3 = bit_field3(); | 4858 result->SetNumberOfOwnDescriptors(0); |
| 4941 new_bit_field3 = OwnsDescriptors::update(new_bit_field3, true); | 4859 result->SetEnumLength(kInvalidEnumCache); |
| 4942 new_bit_field3 = NumberOfOwnDescriptorsBits::update(new_bit_field3, 0); | |
| 4943 new_bit_field3 = EnumLengthBits::update(new_bit_field3, kInvalidEnumCache); | |
| 4944 result->set_bit_field3(new_bit_field3); | |
| 4945 return result; | 4860 return result; |
| 4946 } | 4861 } |
| 4947 | 4862 |
| 4948 | 4863 |
| 4949 MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode, | 4864 MaybeObject* Map::CopyNormalized(PropertyNormalizationMode mode, |
| 4950 NormalizedMapSharingMode sharing) { | 4865 NormalizedMapSharingMode sharing) { |
| 4951 int new_instance_size = instance_size(); | 4866 int new_instance_size = instance_size(); |
| 4952 if (mode == CLEAR_INOBJECT_PROPERTIES) { | 4867 if (mode == CLEAR_INOBJECT_PROPERTIES) { |
| 4953 new_instance_size -= inobject_properties() * kPointerSize; | 4868 new_instance_size -= inobject_properties() * kPointerSize; |
| 4954 } | 4869 } |
| (...skipping 29 matching lines...) Expand all Loading... |
| 4984 result->set_inobject_properties(inobject_properties()); | 4899 result->set_inobject_properties(inobject_properties()); |
| 4985 result->set_unused_property_fields(unused_property_fields()); | 4900 result->set_unused_property_fields(unused_property_fields()); |
| 4986 | 4901 |
| 4987 result->set_pre_allocated_property_fields(pre_allocated_property_fields()); | 4902 result->set_pre_allocated_property_fields(pre_allocated_property_fields()); |
| 4988 result->set_is_shared(false); | 4903 result->set_is_shared(false); |
| 4989 result->ClearCodeCache(GetHeap()); | 4904 result->ClearCodeCache(GetHeap()); |
| 4990 return result; | 4905 return result; |
| 4991 } | 4906 } |
| 4992 | 4907 |
| 4993 | 4908 |
| 4994 MaybeObject* Map::ShareDescriptor(Descriptor* descriptor) { | |
| 4995 // Sanity check. This path is only to be taken if the map owns its descriptor | |
| 4996 // array, implying that its NumberOfOwnDescriptors equals the number of | |
| 4997 // descriptors in the descriptor array. | |
| 4998 ASSERT(NumberOfOwnDescriptors() == | |
| 4999 instance_descriptors()->number_of_descriptors()); | |
| 5000 Map* result; | |
| 5001 MaybeObject* maybe_result = CopyDropDescriptors(); | |
| 5002 if (!maybe_result->To(&result)) return maybe_result; | |
| 5003 | |
| 5004 String* name = descriptor->GetKey(); | |
| 5005 | |
| 5006 TransitionArray* transitions; | |
| 5007 MaybeObject* maybe_transitions = | |
| 5008 AddTransition(name, result, SIMPLE_TRANSITION); | |
| 5009 if (!maybe_transitions->To(&transitions)) return maybe_transitions; | |
| 5010 | |
| 5011 DescriptorArray* descriptors = instance_descriptors(); | |
| 5012 int old_size = descriptors->number_of_descriptors(); | |
| 5013 | |
| 5014 DescriptorArray* new_descriptors; | |
| 5015 | |
| 5016 if (descriptors->NumberOfSlackDescriptors() > 0) { | |
| 5017 new_descriptors = descriptors; | |
| 5018 new_descriptors->Append(descriptor); | |
| 5019 } else { | |
| 5020 // Descriptor arrays grow by 50%. | |
| 5021 MaybeObject* maybe_descriptors = DescriptorArray::Allocate( | |
| 5022 old_size, old_size < 4 ? 1 : old_size / 2); | |
| 5023 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; | |
| 5024 | |
| 5025 DescriptorArray::WhitenessWitness witness(new_descriptors); | |
| 5026 | |
| 5027 // Copy the descriptors, inserting a descriptor. | |
| 5028 for (int i = 0; i < old_size; ++i) { | |
| 5029 new_descriptors->CopyFrom(i, descriptors, i, witness); | |
| 5030 } | |
| 5031 | |
| 5032 new_descriptors->Append(descriptor, witness); | |
| 5033 | |
| 5034 // If the source descriptors had an enum cache we copy it. This ensures that | |
| 5035 // the maps to which we push the new descriptor array back can rely on a | |
| 5036 // cache always being available once it is set. If the map has more | |
| 5037 // enumerated descriptors than available in the original cache, the cache | |
| 5038 // will be lazily replaced by the extended cache when needed. | |
| 5039 if (descriptors->HasEnumCache()) { | |
| 5040 new_descriptors->CopyEnumCacheFrom(descriptors); | |
| 5041 } | |
| 5042 } | |
| 5043 | |
| 5044 transitions->set_descriptors(new_descriptors); | |
| 5045 | |
| 5046 set_transitions(transitions); | |
| 5047 result->SetBackPointer(this); | |
| 5048 set_owns_descriptors(false); | |
| 5049 | |
| 5050 result->SetNumberOfOwnDescriptors(new_descriptors->number_of_descriptors()); | |
| 5051 ASSERT(result->NumberOfOwnDescriptors() == NumberOfOwnDescriptors() + 1); | |
| 5052 | |
| 5053 return result; | |
| 5054 } | |
| 5055 | |
| 5056 | |
| 5057 MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors, | 4909 MaybeObject* Map::CopyReplaceDescriptors(DescriptorArray* descriptors, |
| 5058 String* name, | 4910 String* name, |
| 5059 TransitionFlag flag, | 4911 TransitionFlag flag) { |
| 5060 int descriptor_index) { | |
| 5061 ASSERT(descriptors->IsSortedNoDuplicates()); | |
| 5062 | |
| 5063 Map* result; | 4912 Map* result; |
| 5064 MaybeObject* maybe_result = CopyDropDescriptors(); | 4913 MaybeObject* maybe_result = CopyDropDescriptors(); |
| 5065 if (!maybe_result->To(&result)) return maybe_result; | 4914 if (!maybe_result->To(&result)) return maybe_result; |
| 5066 | 4915 |
| 5067 // Unless we are creating a map with no descriptors and no back pointer, we | 4916 if (descriptors->number_of_descriptors() != 0) { |
| 5068 // insert the descriptor array locally. | |
| 5069 if (!descriptors->IsEmpty()) { | |
| 5070 MaybeObject* maybe_failure = result->SetDescriptors(descriptors); | 4917 MaybeObject* maybe_failure = result->SetDescriptors(descriptors); |
| 5071 if (maybe_failure->IsFailure()) return maybe_failure; | 4918 if (maybe_failure->IsFailure()) return maybe_failure; |
| 5072 result->SetNumberOfOwnDescriptors(descriptors->number_of_descriptors()); | 4919 result->SetNumberOfOwnDescriptors(descriptors->number_of_descriptors()); |
| 5073 } | 4920 } |
| 5074 | 4921 |
| 5075 if (flag == INSERT_TRANSITION && CanHaveMoreTransitions()) { | 4922 if (flag == INSERT_TRANSITION && CanHaveMoreTransitions()) { |
| 5076 TransitionArray* transitions; | 4923 TransitionArray* transitions; |
| 5077 SimpleTransitionFlag simple_flag = | 4924 MaybeObject* maybe_transitions = AddTransition(name, result); |
| 5078 (descriptor_index == descriptors->number_of_descriptors() - 1) | |
| 5079 ? SIMPLE_TRANSITION | |
| 5080 : FULL_TRANSITION; | |
| 5081 MaybeObject* maybe_transitions = AddTransition(name, result, simple_flag); | |
| 5082 if (!maybe_transitions->To(&transitions)) return maybe_transitions; | 4925 if (!maybe_transitions->To(&transitions)) return maybe_transitions; |
| 5083 | 4926 |
| 5084 if (descriptors->IsEmpty()) { | |
| 5085 if (owns_descriptors()) { | |
| 5086 // If the copied map has no added fields, and the parent map owns its | |
| 5087 // descriptors, those descriptors have to be empty. In that case, | |
| 5088 // transfer ownership of the descriptors to the new child. | |
| 5089 ASSERT(instance_descriptors()->IsEmpty()); | |
| 5090 set_owns_descriptors(false); | |
| 5091 } else { | |
| 5092 // If the parent did not own its own descriptors, it may share a larger | |
| 5093 // descriptors array already. In that case, force a split by setting | |
| 5094 // the descriptor array of the new map to the empty descriptor array. | |
| 5095 MaybeObject* maybe_failure = | |
| 5096 result->SetDescriptors(GetHeap()->empty_descriptor_array()); | |
| 5097 if (maybe_failure->IsFailure()) return maybe_failure; | |
| 5098 } | |
| 5099 } | |
| 5100 | |
| 5101 set_transitions(transitions); | 4927 set_transitions(transitions); |
| 5102 result->SetBackPointer(this); | 4928 result->SetBackPointer(this); |
| 5103 } | 4929 } |
| 5104 | 4930 |
| 5105 return result; | 4931 return result; |
| 5106 } | 4932 } |
| 5107 | 4933 |
| 5108 | 4934 |
| 5109 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 |
| 5110 if (flag == INSERT_TRANSITION) { | 4942 if (flag == INSERT_TRANSITION) { |
| 5111 ASSERT(!HasElementsTransition() || | 4943 ASSERT(!HasElementsTransition() || |
| 5112 ((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS || | 4944 ((elements_transition_map()->elements_kind() == DICTIONARY_ELEMENTS || |
| 5113 IsExternalArrayElementsKind( | 4945 IsExternalArrayElementsKind( |
| 5114 elements_transition_map()->elements_kind())) && | 4946 elements_transition_map()->elements_kind())) && |
| 5115 (kind == DICTIONARY_ELEMENTS || | 4947 (kind == DICTIONARY_ELEMENTS || |
| 5116 IsExternalArrayElementsKind(kind)))); | 4948 IsExternalArrayElementsKind(kind)))); |
| 5117 ASSERT(!IsFastElementsKind(kind) || | 4949 ASSERT(!IsFastElementsKind(kind) || |
| 5118 IsMoreGeneralElementsKindTransition(elements_kind(), kind)); | 4950 IsMoreGeneralElementsKindTransition(elements_kind(), kind)); |
| 5119 ASSERT(kind != elements_kind()); | 4951 ASSERT(kind != elements_kind()); |
| 5120 } | |
| 5121 | 4952 |
| 5122 if (flag == INSERT_TRANSITION && owns_descriptors()) { | |
| 5123 // In case the map owned its own descriptors, share the descriptors and | |
| 5124 // transfer ownership to the new map. | |
| 5125 Map* new_map; | |
| 5126 MaybeObject* maybe_new_map = CopyDropDescriptors(); | |
| 5127 if (!maybe_new_map->To(&new_map)) return maybe_new_map; | |
| 5128 | |
| 5129 MaybeObject* added_elements = set_elements_transition_map(new_map); | |
| 5130 if (added_elements->IsFailure()) return added_elements; | |
| 5131 | |
| 5132 new_map->set_elements_kind(kind); | |
| 5133 new_map->SetBackPointer(this); | |
| 5134 new_map->SetNumberOfOwnDescriptors(NumberOfOwnDescriptors()); | |
| 5135 set_owns_descriptors(false); | |
| 5136 return new_map; | |
| 5137 } | |
| 5138 | |
| 5139 // In case the map did not own its own descriptors, a split is forced by | |
| 5140 // copying the map; creating a new descriptor array cell. | |
| 5141 // Create a new free-floating map only if we are not allowed to store it. | |
| 5142 Map* new_map; | |
| 5143 MaybeObject* maybe_new_map = Copy(); | |
| 5144 if (!maybe_new_map->To(&new_map)) return maybe_new_map; | |
| 5145 ASSERT(new_map->NumberOfOwnDescriptors() == NumberOfOwnDescriptors()); | |
| 5146 new_map->set_elements_kind(kind); | |
| 5147 | |
| 5148 if (flag == INSERT_TRANSITION) { | |
| 5149 // Map::Copy does not store the descriptor array in case it is empty, since | |
| 5150 // it does not insert a back pointer; implicitly indicating that its | |
| 5151 // descriptor array is empty. Since in this case we do want to insert a back | |
| 5152 // pointer, we have to manually set the empty descriptor array to force a | |
| 5153 // split. | |
| 5154 if (!new_map->StoresOwnDescriptors()) { | |
| 5155 ASSERT(new_map->NumberOfOwnDescriptors() == 0); | |
| 5156 MaybeObject* maybe_failure = | |
| 5157 new_map->SetDescriptors(GetHeap()->empty_descriptor_array()); | |
| 5158 if (maybe_failure->IsFailure()) return maybe_failure; | |
| 5159 } | |
| 5160 MaybeObject* added_elements = set_elements_transition_map(new_map); | 4953 MaybeObject* added_elements = set_elements_transition_map(new_map); |
| 5161 if (added_elements->IsFailure()) return added_elements; | 4954 if (added_elements->IsFailure()) return added_elements; |
| 5162 | 4955 |
| 5163 new_map->SetBackPointer(this); | 4956 new_map->SetBackPointer(this); |
| 5164 } | 4957 } |
| 5165 | 4958 |
| 5166 return new_map; | 4959 return new_map; |
| 5167 } | 4960 } |
| 5168 | 4961 |
| 5169 | 4962 |
| 5170 MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() { | 4963 MaybeObject* Map::CopyWithPreallocatedFieldDescriptors() { |
| 5171 if (pre_allocated_property_fields() == 0) return CopyDropDescriptors(); | 4964 if (pre_allocated_property_fields() == 0) return CopyDropDescriptors(); |
| 5172 | 4965 |
| 5173 // 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 |
| 5174 // array describing these properties. | 4967 // array describing these properties. |
| 5175 ASSERT(constructor()->IsJSFunction()); | 4968 ASSERT(constructor()->IsJSFunction()); |
| 5176 JSFunction* ctor = JSFunction::cast(constructor()); | 4969 JSFunction* ctor = JSFunction::cast(constructor()); |
| 5177 Map* map = ctor->initial_map(); | 4970 Map* map = ctor->initial_map(); |
| 5178 DescriptorArray* descriptors = map->instance_descriptors(); | 4971 DescriptorArray* descriptors = map->instance_descriptors(); |
| 5179 | 4972 |
| 5180 int number_of_own_descriptors = map->NumberOfOwnDescriptors(); | 4973 return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION); |
| 5181 DescriptorArray* new_descriptors; | |
| 5182 MaybeObject* maybe_descriptors = | |
| 5183 descriptors->CopyUpTo(number_of_own_descriptors); | |
| 5184 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; | |
| 5185 | |
| 5186 return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION, 0); | |
| 5187 } | 4974 } |
| 5188 | 4975 |
| 5189 | 4976 |
| 5190 MaybeObject* Map::Copy() { | 4977 MaybeObject* Map::Copy() { |
| 5191 DescriptorArray* descriptors = instance_descriptors(); | 4978 DescriptorArray* descriptors = instance_descriptors(); |
| 5192 DescriptorArray* new_descriptors; | 4979 return CopyReplaceDescriptors(descriptors, NULL, OMIT_TRANSITION); |
| 5193 int number_of_own_descriptors = NumberOfOwnDescriptors(); | |
| 5194 MaybeObject* maybe_descriptors = | |
| 5195 descriptors->CopyUpTo(number_of_own_descriptors); | |
| 5196 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; | |
| 5197 | |
| 5198 return CopyReplaceDescriptors(new_descriptors, NULL, OMIT_TRANSITION, 0); | |
| 5199 } | 4980 } |
| 5200 | 4981 |
| 5201 | 4982 |
| 5202 MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor, | 4983 MaybeObject* Map::CopyAddDescriptor(Descriptor* descriptor, |
| 5203 TransitionFlag flag) { | 4984 TransitionFlag flag) { |
| 5204 DescriptorArray* descriptors = instance_descriptors(); | 4985 DescriptorArray* descriptors = instance_descriptors(); |
| 5205 | 4986 |
| 5206 // Ensure the key is a symbol. | 4987 // Ensure the key is a symbol. |
| 5207 MaybeObject* maybe_failure = descriptor->KeyToSymbol(); | 4988 MaybeObject* maybe_failure = descriptor->KeyToSymbol(); |
| 5208 if (maybe_failure->IsFailure()) return maybe_failure; | 4989 if (maybe_failure->IsFailure()) return maybe_failure; |
| 5209 | 4990 |
| 5210 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(); |
| 5211 int new_size = old_size + 1; | 4995 int new_size = old_size + 1; |
| 5212 descriptor->SetEnumerationIndex(new_size); | |
| 5213 | |
| 5214 if (flag == INSERT_TRANSITION && | |
| 5215 owns_descriptors() && | |
| 5216 CanHaveMoreTransitions()) { | |
| 5217 return ShareDescriptor(descriptor); | |
| 5218 } | |
| 5219 | 4996 |
| 5220 DescriptorArray* new_descriptors; | 4997 DescriptorArray* new_descriptors; |
| 5221 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(old_size, 1); | 4998 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(new_size); |
| 5222 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; | 4999 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; |
| 5223 | 5000 |
| 5224 DescriptorArray::WhitenessWitness witness(new_descriptors); | 5001 FixedArray::WhitenessWitness witness(new_descriptors); |
| 5225 | 5002 |
| 5226 // Copy the descriptors, inserting a descriptor. | 5003 // Copy the descriptors, inserting a descriptor. |
| 5227 for (int i = 0; i < old_size; ++i) { | 5004 for (int i = 0; i < old_size; ++i) { |
| 5228 new_descriptors->CopyFrom(i, descriptors, i, witness); | 5005 new_descriptors->CopyFrom(i, descriptors, i, witness); |
| 5229 } | 5006 } |
| 5230 | 5007 |
| 5231 if (old_size != descriptors->number_of_descriptors()) { | 5008 new_descriptors->Append(descriptor, witness, old_size); |
| 5232 new_descriptors->SetNumberOfDescriptors(new_size); | |
| 5233 new_descriptors->Set(old_size, descriptor, witness); | |
| 5234 new_descriptors->Sort(); | |
| 5235 } else { | |
| 5236 new_descriptors->Append(descriptor, witness); | |
| 5237 } | |
| 5238 | 5009 |
| 5239 String* key = descriptor->GetKey(); | 5010 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates()); |
| 5240 int insertion_index = new_descriptors->number_of_descriptors() - 1; | |
| 5241 | 5011 |
| 5242 return CopyReplaceDescriptors(new_descriptors, key, flag, insertion_index); | 5012 return CopyReplaceDescriptors(new_descriptors, key, flag); |
| 5243 } | 5013 } |
| 5244 | 5014 |
| 5245 | 5015 |
| 5246 MaybeObject* Map::CopyInsertDescriptor(Descriptor* descriptor, | 5016 MaybeObject* Map::CopyInsertDescriptor(Descriptor* descriptor, |
| 5247 TransitionFlag flag) { | 5017 TransitionFlag flag) { |
| 5248 DescriptorArray* old_descriptors = instance_descriptors(); | 5018 DescriptorArray* old_descriptors = instance_descriptors(); |
| 5249 | 5019 |
| 5250 // Ensure the key is a symbol. | 5020 // Ensure the key is a symbol. |
| 5251 MaybeObject* maybe_result = descriptor->KeyToSymbol(); | 5021 MaybeObject* maybe_result = descriptor->KeyToSymbol(); |
| 5252 if (maybe_result->IsFailure()) return maybe_result; | 5022 if (maybe_result->IsFailure()) return maybe_result; |
| 5253 | 5023 |
| 5254 // We replace the key if it is already present. | 5024 // We replace the key if it is already present. |
| 5255 int index = old_descriptors->SearchWithCache(descriptor->GetKey(), this); | 5025 int index = old_descriptors->SearchWithCache(descriptor->GetKey()); |
| 5256 if (index != DescriptorArray::kNotFound) { | 5026 if (index != DescriptorArray::kNotFound) { |
| 5257 return CopyReplaceDescriptor(descriptor, index, flag); | 5027 return CopyReplaceDescriptor(descriptor, index, flag); |
| 5258 } | 5028 } |
| 5259 return CopyAddDescriptor(descriptor, flag); | 5029 return CopyAddDescriptor(descriptor, flag); |
| 5260 } | 5030 } |
| 5261 | 5031 |
| 5262 | 5032 |
| 5263 MaybeObject* DescriptorArray::CopyUpTo(int enumeration_index) { | |
| 5264 if (enumeration_index == 0) return GetHeap()->empty_descriptor_array(); | |
| 5265 | |
| 5266 int size = enumeration_index; | |
| 5267 | |
| 5268 DescriptorArray* descriptors; | |
| 5269 MaybeObject* maybe_descriptors = Allocate(size); | |
| 5270 if (!maybe_descriptors->To(&descriptors)) return maybe_descriptors; | |
| 5271 DescriptorArray::WhitenessWitness witness(descriptors); | |
| 5272 | |
| 5273 for (int i = 0; i < size; ++i) { | |
| 5274 descriptors->CopyFrom(i, this, i, witness); | |
| 5275 } | |
| 5276 | |
| 5277 if (number_of_descriptors() != enumeration_index) descriptors->Sort(); | |
| 5278 | |
| 5279 return descriptors; | |
| 5280 } | |
| 5281 | |
| 5282 | |
| 5283 MaybeObject* Map::CopyReplaceDescriptor(Descriptor* descriptor, | 5033 MaybeObject* Map::CopyReplaceDescriptor(Descriptor* descriptor, |
| 5284 int insertion_index, | 5034 int insertion_index, |
| 5285 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 |
| 5286 // Ensure the key is a symbol. | 5040 // Ensure the key is a symbol. |
| 5287 MaybeObject* maybe_failure = descriptor->KeyToSymbol(); | 5041 MaybeObject* maybe_failure = descriptor->KeyToSymbol(); |
| 5288 if (maybe_failure->IsFailure()) return maybe_failure; | 5042 if (maybe_failure->IsFailure()) return maybe_failure; |
| 5289 | 5043 |
| 5290 DescriptorArray* descriptors = instance_descriptors(); | |
| 5291 | |
| 5292 String* key = descriptor->GetKey(); | 5044 String* key = descriptor->GetKey(); |
| 5293 ASSERT(key == descriptors->GetKey(insertion_index)); | 5045 ASSERT(key == descriptors->GetKey(insertion_index)); |
| 5294 | 5046 |
| 5295 int new_size = NumberOfOwnDescriptors(); | 5047 DescriptorArray* new_descriptors; |
| 5296 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; |
| 5297 | 5050 |
| 5298 PropertyDetails details = descriptors->GetDetails(insertion_index); | 5051 FixedArray::WhitenessWitness witness(new_descriptors); |
| 5299 ASSERT_LE(details.descriptor_index(), new_size); | |
| 5300 descriptor->SetEnumerationIndex(details.descriptor_index()); | |
| 5301 | 5052 |
| 5302 DescriptorArray* new_descriptors; | 5053 // Copy the descriptors, replacing a descriptor. |
| 5303 MaybeObject* maybe_descriptors = DescriptorArray::Allocate(new_size); | 5054 for (int index = 0; index < size; ++index) { |
| 5304 if (!maybe_descriptors->To(&new_descriptors)) return maybe_descriptors; | 5055 if (index == insertion_index) continue; |
| 5305 DescriptorArray::WhitenessWitness witness(new_descriptors); | 5056 new_descriptors->CopyFrom(index, descriptors, index, witness); |
| 5306 | |
| 5307 for (int i = 0; i < new_size; ++i) { | |
| 5308 if (i == insertion_index) { | |
| 5309 new_descriptors->Set(i, descriptor, witness); | |
| 5310 } else { | |
| 5311 new_descriptors->CopyFrom(i, descriptors, i, witness); | |
| 5312 } | |
| 5313 } | 5057 } |
| 5314 | 5058 |
| 5315 // Re-sort if descriptors were removed. | 5059 PropertyDetails original_details = descriptors->GetDetails(insertion_index); |
| 5316 if (new_size != descriptors->length()) new_descriptors->Sort(); | 5060 descriptor->SetEnumerationIndex(original_details.descriptor_index()); |
| 5061 descriptor->SetSortedKey(original_details.pointer()); |
| 5317 | 5062 |
| 5318 return CopyReplaceDescriptors(new_descriptors, key, flag, insertion_index); | 5063 new_descriptors->Set(insertion_index, descriptor, witness); |
| 5064 |
| 5065 SLOW_ASSERT(new_descriptors->IsSortedNoDuplicates()); |
| 5066 |
| 5067 return CopyReplaceDescriptors(new_descriptors, key, flag); |
| 5319 } | 5068 } |
| 5320 | 5069 |
| 5321 | 5070 |
| 5322 void Map::UpdateCodeCache(Handle<Map> map, | 5071 void Map::UpdateCodeCache(Handle<Map> map, |
| 5323 Handle<String> name, | 5072 Handle<String> name, |
| 5324 Handle<Code> code) { | 5073 Handle<Code> code) { |
| 5325 Isolate* isolate = map->GetIsolate(); | 5074 Isolate* isolate = map->GetIsolate(); |
| 5326 CALL_HEAP_FUNCTION_VOID(isolate, | 5075 CALL_HEAP_FUNCTION_VOID(isolate, |
| 5327 map->UpdateCodeCache(*name, *code)); | 5076 map->UpdateCodeCache(*name, *code)); |
| 5328 } | 5077 } |
| (...skipping 754 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6083 bool FixedArray::IsEqualTo(FixedArray* other) { | 5832 bool FixedArray::IsEqualTo(FixedArray* other) { |
| 6084 if (length() != other->length()) return false; | 5833 if (length() != other->length()) return false; |
| 6085 for (int i = 0 ; i < length(); ++i) { | 5834 for (int i = 0 ; i < length(); ++i) { |
| 6086 if (get(i) != other->get(i)) return false; | 5835 if (get(i) != other->get(i)) return false; |
| 6087 } | 5836 } |
| 6088 return true; | 5837 return true; |
| 6089 } | 5838 } |
| 6090 #endif | 5839 #endif |
| 6091 | 5840 |
| 6092 | 5841 |
| 6093 MaybeObject* DescriptorArray::Allocate(int number_of_descriptors, int slack) { | 5842 MaybeObject* DescriptorArray::Allocate(int number_of_descriptors) { |
| 6094 Heap* heap = Isolate::Current()->heap(); | 5843 Heap* heap = Isolate::Current()->heap(); |
| 6095 // Do not use DescriptorArray::cast on incomplete object. | 5844 // Do not use DescriptorArray::cast on incomplete object. |
| 6096 int size = number_of_descriptors + slack; | |
| 6097 if (size == 0) return heap->empty_descriptor_array(); | |
| 6098 FixedArray* result; | 5845 FixedArray* result; |
| 5846 if (number_of_descriptors == 0) return heap->empty_descriptor_array(); |
| 6099 // Allocate the array of keys. | 5847 // Allocate the array of keys. |
| 6100 MaybeObject* maybe_array = heap->AllocateFixedArray(LengthFor(size)); | 5848 MaybeObject* maybe_array = |
| 5849 heap->AllocateFixedArray(LengthFor(number_of_descriptors)); |
| 6101 if (!maybe_array->To(&result)) return maybe_array; | 5850 if (!maybe_array->To(&result)) return maybe_array; |
| 6102 | 5851 |
| 6103 result->set(kDescriptorLengthIndex, Smi::FromInt(number_of_descriptors)); | |
| 6104 result->set(kEnumCacheIndex, Smi::FromInt(0)); | 5852 result->set(kEnumCacheIndex, Smi::FromInt(0)); |
| 6105 return result; | 5853 return result; |
| 6106 } | 5854 } |
| 6107 | 5855 |
| 6108 | 5856 |
| 6109 void DescriptorArray::ClearEnumCache() { | |
| 6110 set(kEnumCacheIndex, Smi::FromInt(0)); | |
| 6111 } | |
| 6112 | |
| 6113 | |
| 6114 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, | 5857 void DescriptorArray::SetEnumCache(FixedArray* bridge_storage, |
| 6115 FixedArray* new_cache, | 5858 FixedArray* new_cache, |
| 6116 Object* new_index_cache) { | 5859 Object* new_index_cache) { |
| 6117 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength); | 5860 ASSERT(bridge_storage->length() >= kEnumCacheBridgeLength); |
| 6118 ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray()); | 5861 ASSERT(new_index_cache->IsSmi() || new_index_cache->IsFixedArray()); |
| 6119 if (HasEnumCache()) { | 5862 if (HasEnumCache()) { |
| 6120 ASSERT(new_cache->length() > GetEnumCache()->length()); | |
| 6121 FixedArray::cast(get(kEnumCacheIndex))-> | 5863 FixedArray::cast(get(kEnumCacheIndex))-> |
| 6122 set(kEnumCacheBridgeCacheIndex, new_cache); | 5864 set(kEnumCacheBridgeCacheIndex, new_cache); |
| 6123 FixedArray::cast(get(kEnumCacheIndex))-> | 5865 FixedArray::cast(get(kEnumCacheIndex))-> |
| 6124 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache); | 5866 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache); |
| 6125 } else { | 5867 } else { |
| 6126 ASSERT(!IsEmpty()); | 5868 if (IsEmpty()) return; // Do nothing for empty descriptor array. |
| 6127 FixedArray::cast(bridge_storage)-> | 5869 FixedArray::cast(bridge_storage)-> |
| 6128 set(kEnumCacheBridgeCacheIndex, new_cache); | 5870 set(kEnumCacheBridgeCacheIndex, new_cache); |
| 6129 FixedArray::cast(bridge_storage)-> | 5871 FixedArray::cast(bridge_storage)-> |
| 6130 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache); | 5872 set(kEnumCacheBridgeIndicesCacheIndex, new_index_cache); |
| 6131 set(kEnumCacheIndex, bridge_storage); | 5873 set(kEnumCacheIndex, bridge_storage); |
| 6132 } | 5874 } |
| 6133 } | 5875 } |
| 6134 | 5876 |
| 6135 | 5877 |
| 6136 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... |
| 6192 if (right_child_hash > child_hash) { | 5934 if (right_child_hash > child_hash) { |
| 6193 child_index++; | 5935 child_index++; |
| 6194 child_hash = right_child_hash; | 5936 child_hash = right_child_hash; |
| 6195 } | 5937 } |
| 6196 } | 5938 } |
| 6197 if (child_hash <= parent_hash) break; | 5939 if (child_hash <= parent_hash) break; |
| 6198 SwapSortedKeys(parent_index, child_index); | 5940 SwapSortedKeys(parent_index, child_index); |
| 6199 parent_index = child_index; | 5941 parent_index = child_index; |
| 6200 } | 5942 } |
| 6201 } | 5943 } |
| 6202 ASSERT(IsSortedNoDuplicates()); | |
| 6203 } | 5944 } |
| 6204 | 5945 |
| 6205 | 5946 |
| 6206 MaybeObject* AccessorPair::Copy() { | 5947 MaybeObject* AccessorPair::Copy() { |
| 6207 Heap* heap = GetHeap(); | 5948 Heap* heap = GetHeap(); |
| 6208 AccessorPair* copy; | 5949 AccessorPair* copy; |
| 6209 MaybeObject* maybe_copy = heap->AllocateAccessorPair(); | 5950 MaybeObject* maybe_copy = heap->AllocateAccessorPair(); |
| 6210 if (!maybe_copy->To(©)) return maybe_copy; | 5951 if (!maybe_copy->To(©)) return maybe_copy; |
| 6211 | 5952 |
| 6212 copy->set_getter(getter()); | 5953 copy->set_getter(getter()); |
| (...skipping 1170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7383 | 7124 |
| 7384 void StringHasher::AddSurrogatePairNoIndex(uc32 c) { | 7125 void StringHasher::AddSurrogatePairNoIndex(uc32 c) { |
| 7385 uint16_t lead = unibrow::Utf16::LeadSurrogate(c); | 7126 uint16_t lead = unibrow::Utf16::LeadSurrogate(c); |
| 7386 AddCharacterNoIndex(lead); | 7127 AddCharacterNoIndex(lead); |
| 7387 uint16_t trail = unibrow::Utf16::TrailSurrogate(c); | 7128 uint16_t trail = unibrow::Utf16::TrailSurrogate(c); |
| 7388 AddCharacterNoIndex(trail); | 7129 AddCharacterNoIndex(trail); |
| 7389 } | 7130 } |
| 7390 | 7131 |
| 7391 | 7132 |
| 7392 uint32_t StringHasher::GetHashField() { | 7133 uint32_t StringHasher::GetHashField() { |
| 7134 ASSERT(is_valid()); |
| 7393 if (length_ <= String::kMaxHashCalcLength) { | 7135 if (length_ <= String::kMaxHashCalcLength) { |
| 7394 if (is_array_index()) { | 7136 if (is_array_index()) { |
| 7395 return MakeArrayIndexHash(array_index(), length_); | 7137 return MakeArrayIndexHash(array_index(), length_); |
| 7396 } | 7138 } |
| 7397 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask; | 7139 return (GetHash() << String::kHashShift) | String::kIsNotArrayIndexMask; |
| 7398 } else { | 7140 } else { |
| 7399 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask; | 7141 return (length_ << String::kHashShift) | String::kIsNotArrayIndexMask; |
| 7400 } | 7142 } |
| 7401 } | 7143 } |
| 7402 | 7144 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7439 void String::PrintOn(FILE* file) { | 7181 void String::PrintOn(FILE* file) { |
| 7440 int length = this->length(); | 7182 int length = this->length(); |
| 7441 for (int i = 0; i < length; i++) { | 7183 for (int i = 0; i < length; i++) { |
| 7442 fprintf(file, "%c", Get(i)); | 7184 fprintf(file, "%c", Get(i)); |
| 7443 } | 7185 } |
| 7444 } | 7186 } |
| 7445 | 7187 |
| 7446 | 7188 |
| 7447 // 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. |
| 7448 // 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. |
| 7449 static bool ClearBackPointer(Heap* heap, Map* target) { | 7191 static bool ClearBackPointer(Heap* heap, Object* target) { |
| 7450 if (Marking::MarkBitFrom(target).Get()) return false; | 7192 ASSERT(target->IsMap()); |
| 7451 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); |
| 7452 return true; | 7196 return true; |
| 7453 } | 7197 } |
| 7454 | 7198 |
| 7455 | 7199 |
| 7456 static void TrimEnumCache(Heap* heap, Map* map, DescriptorArray* descriptors) { | |
| 7457 int live_enum = map->EnumLength(); | |
| 7458 if (live_enum == Map::kInvalidEnumCache) { | |
| 7459 live_enum = map->NumberOfDescribedProperties(OWN_DESCRIPTORS, DONT_ENUM); | |
| 7460 } | |
| 7461 if (live_enum == 0) return descriptors->ClearEnumCache(); | |
| 7462 | |
| 7463 FixedArray* enum_cache = descriptors->GetEnumCache(); | |
| 7464 | |
| 7465 int to_trim = enum_cache->length() - live_enum; | |
| 7466 if (to_trim <= 0) return; | |
| 7467 RightTrimFixedArray<FROM_GC>(heap, descriptors->GetEnumCache(), to_trim); | |
| 7468 | |
| 7469 if (!descriptors->HasEnumIndicesCache()) return; | |
| 7470 FixedArray* enum_indices_cache = descriptors->GetEnumIndicesCache(); | |
| 7471 RightTrimFixedArray<FROM_GC>(heap, enum_indices_cache, to_trim); | |
| 7472 } | |
| 7473 | |
| 7474 | |
| 7475 static void TrimDescriptorArray(Heap* heap, | |
| 7476 Map* map, | |
| 7477 DescriptorArray* descriptors, | |
| 7478 int number_of_own_descriptors) { | |
| 7479 int number_of_descriptors = descriptors->number_of_descriptors(); | |
| 7480 int to_trim = number_of_descriptors - number_of_own_descriptors; | |
| 7481 if (to_trim <= 0) return; | |
| 7482 | |
| 7483 // Maximally keep 50% of unused descriptors. | |
| 7484 int keep = Min(to_trim, number_of_own_descriptors / 2); | |
| 7485 for (int i = number_of_own_descriptors; | |
| 7486 i < number_of_own_descriptors + keep; | |
| 7487 ++i) { | |
| 7488 descriptors->EraseDescriptor(heap, i); | |
| 7489 } | |
| 7490 | |
| 7491 if (to_trim > keep) { | |
| 7492 RightTrimFixedArray<FROM_GC>(heap, descriptors, to_trim - keep); | |
| 7493 } | |
| 7494 descriptors->SetNumberOfDescriptors(number_of_own_descriptors); | |
| 7495 | |
| 7496 if (descriptors->HasEnumCache()) TrimEnumCache(heap, map, descriptors); | |
| 7497 descriptors->Sort(); | |
| 7498 } | |
| 7499 | |
| 7500 | |
| 7501 // TODO(mstarzinger): This method should be moved into MarkCompactCollector, | 7200 // TODO(mstarzinger): This method should be moved into MarkCompactCollector, |
| 7502 // 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 |
| 7503 // depending on the transitions layout in the GC anyways. | 7202 // depending on the transitions layout in the GC anyways. |
| 7504 void Map::ClearNonLiveTransitions(Heap* heap) { | 7203 void Map::ClearNonLiveTransitions(Heap* heap) { |
| 7505 // If there are no transitions to be cleared, return. | 7204 // If there are no transitions to be cleared, return. |
| 7506 // TODO(verwaest) Should be an assert, otherwise back pointers are not | 7205 // TODO(verwaest) Should be an assert, otherwise back pointers are not |
| 7507 // properly cleared. | 7206 // properly cleared. |
| 7508 if (!HasTransitionArray()) return; | 7207 if (!HasTransitionArray()) return; |
| 7509 | 7208 |
| 7510 TransitionArray* t = transitions(); | 7209 TransitionArray* t = transitions(); |
| 7511 MarkCompactCollector* collector = heap->mark_compact_collector(); | 7210 MarkCompactCollector* collector = heap->mark_compact_collector(); |
| 7512 | 7211 |
| 7513 int transition_index = 0; | 7212 int transition_index = 0; |
| 7514 | 7213 |
| 7515 DescriptorArray* descriptors = t->descriptors(); | |
| 7516 bool descriptors_owner_died = false; | |
| 7517 | |
| 7518 // Compact all live descriptors to the left. | 7214 // Compact all live descriptors to the left. |
| 7519 for (int i = 0; i < t->number_of_transitions(); ++i) { | 7215 for (int i = 0; i < t->number_of_transitions(); ++i) { |
| 7520 Map* target = t->GetTarget(i); | 7216 if (!ClearBackPointer(heap, t->GetTarget(i))) { |
| 7521 if (ClearBackPointer(heap, target)) { | |
| 7522 ASSERT(!Marking::IsGrey(Marking::MarkBitFrom(target))); | |
| 7523 DescriptorArray* target_descriptors = target->instance_descriptors(); | |
| 7524 if ((target_descriptors->number_of_descriptors() == 0 && | |
| 7525 target->NumberOfOwnDescriptors() > 0) || | |
| 7526 target_descriptors == descriptors) { | |
| 7527 descriptors_owner_died = true; | |
| 7528 } | |
| 7529 } else { | |
| 7530 if (i != transition_index) { | 7217 if (i != transition_index) { |
| 7531 String* key = t->GetKey(i); | 7218 String* key = t->GetKey(i); |
| 7532 t->SetKey(transition_index, key); | 7219 t->SetKey(transition_index, key); |
| 7533 Object** key_slot = t->GetKeySlot(transition_index); | 7220 Object** key_slot = t->GetKeySlot(transition_index); |
| 7534 collector->RecordSlot(key_slot, key_slot, key); | 7221 collector->RecordSlot(key_slot, key_slot, key); |
| 7535 // 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. |
| 7536 t->SetTarget(transition_index, t->GetTarget(i)); | 7223 t->SetTarget(transition_index, t->GetTarget(i)); |
| 7537 } | 7224 } |
| 7538 transition_index++; | 7225 transition_index++; |
| 7539 } | 7226 } |
| 7540 } | 7227 } |
| 7541 | 7228 |
| 7542 if (t->HasElementsTransition() && | 7229 if (t->HasElementsTransition() && |
| 7543 ClearBackPointer(heap, t->elements_transition())) { | 7230 ClearBackPointer(heap, t->elements_transition())) { |
| 7544 if (t->elements_transition()->instance_descriptors() == descriptors) { | |
| 7545 descriptors_owner_died = true; | |
| 7546 } | |
| 7547 t->ClearElementsTransition(); | 7231 t->ClearElementsTransition(); |
| 7548 } else { | 7232 } else { |
| 7549 // If there are no transitions to be cleared, return. | 7233 // If there are no transitions to be cleared, return. |
| 7550 // TODO(verwaest) Should be an assert, otherwise back pointers are not | 7234 // TODO(verwaest) Should be an assert, otherwise back pointers are not |
| 7551 // properly cleared. | 7235 // properly cleared. |
| 7552 if (transition_index == t->number_of_transitions()) return; | 7236 if (transition_index == t->number_of_transitions()) return; |
| 7553 } | 7237 } |
| 7554 | 7238 |
| 7555 int number_of_own_descriptors = NumberOfOwnDescriptors(); | |
| 7556 | |
| 7557 if (descriptors_owner_died) { | |
| 7558 if (number_of_own_descriptors > 0) { | |
| 7559 TrimDescriptorArray(heap, this, descriptors, number_of_own_descriptors); | |
| 7560 ASSERT(descriptors->number_of_descriptors() == number_of_own_descriptors); | |
| 7561 } else { | |
| 7562 t->set_descriptors(heap->empty_descriptor_array()); | |
| 7563 } | |
| 7564 set_owns_descriptors(true); | |
| 7565 } | |
| 7566 | |
| 7567 // 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 |
| 7568 // the transition array from the map. | 7240 // the transition array from the map. |
| 7569 if (transition_index == 0 && | 7241 if (transition_index == 0 && |
| 7570 !t->HasElementsTransition() && | 7242 !t->HasElementsTransition() && |
| 7571 !t->HasPrototypeTransitions() && | 7243 !t->HasPrototypeTransitions() && |
| 7572 number_of_own_descriptors == 0) { | 7244 t->descriptors()->IsEmpty()) { |
| 7573 ASSERT(owns_descriptors()); | |
| 7574 return ClearTransitions(heap); | 7245 return ClearTransitions(heap); |
| 7575 } | 7246 } |
| 7576 | 7247 |
| 7577 int trim = t->number_of_transitions() - transition_index; | 7248 int trim = t->number_of_transitions() - transition_index; |
| 7578 if (trim > 0) { | 7249 if (trim > 0) { |
| 7579 RightTrimFixedArray<FROM_GC>(heap, t, t->IsSimpleTransition() | 7250 RightTrimFixedArray<FROM_GC>( |
| 7580 ? trim : trim * TransitionArray::kTransitionSize); | 7251 heap, t, trim * TransitionArray::kTransitionSize); |
| 7581 } | 7252 } |
| 7582 } | 7253 } |
| 7583 | 7254 |
| 7584 | 7255 |
| 7585 int Map::Hash() { | 7256 int Map::Hash() { |
| 7586 // For performance reasons we only hash the 3 most variable fields of a map: | 7257 // For performance reasons we only hash the 3 most variable fields of a map: |
| 7587 // constructor, prototype and bit_field2. | 7258 // constructor, prototype and bit_field2. |
| 7588 | 7259 |
| 7589 // Shift away the tag. | 7260 // Shift away the tag. |
| 7590 int hash = (static_cast<uint32_t>( | 7261 int hash = (static_cast<uint32_t>( |
| (...skipping 2926 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10517 ASSERT(map()->has_indexed_interceptor()); | 10188 ASSERT(map()->has_indexed_interceptor()); |
| 10518 JSFunction* constructor = JSFunction::cast(map()->constructor()); | 10189 JSFunction* constructor = JSFunction::cast(map()->constructor()); |
| 10519 ASSERT(constructor->shared()->IsApiFunction()); | 10190 ASSERT(constructor->shared()->IsApiFunction()); |
| 10520 Object* result = | 10191 Object* result = |
| 10521 constructor->shared()->get_api_func_data()->indexed_property_handler(); | 10192 constructor->shared()->get_api_func_data()->indexed_property_handler(); |
| 10522 return InterceptorInfo::cast(result); | 10193 return InterceptorInfo::cast(result); |
| 10523 } | 10194 } |
| 10524 | 10195 |
| 10525 | 10196 |
| 10526 MaybeObject* JSObject::GetPropertyPostInterceptor( | 10197 MaybeObject* JSObject::GetPropertyPostInterceptor( |
| 10527 Object* receiver, | 10198 JSReceiver* receiver, |
| 10528 String* name, | 10199 String* name, |
| 10529 PropertyAttributes* attributes) { | 10200 PropertyAttributes* attributes) { |
| 10530 // Check local property in holder, ignore interceptor. | 10201 // Check local property in holder, ignore interceptor. |
| 10531 LookupResult result(GetIsolate()); | 10202 LookupResult result(GetIsolate()); |
| 10532 LocalLookupRealNamedProperty(name, &result); | 10203 LocalLookupRealNamedProperty(name, &result); |
| 10533 if (result.IsFound()) { | 10204 if (result.IsFound()) { |
| 10534 return GetProperty(receiver, &result, name, attributes); | 10205 return GetProperty(receiver, &result, name, attributes); |
| 10535 } | 10206 } |
| 10536 // Continue searching via the prototype chain. | 10207 // Continue searching via the prototype chain. |
| 10537 Object* pt = GetPrototype(); | 10208 Object* pt = GetPrototype(); |
| 10538 *attributes = ABSENT; | 10209 *attributes = ABSENT; |
| 10539 if (pt->IsNull()) return GetHeap()->undefined_value(); | 10210 if (pt->IsNull()) return GetHeap()->undefined_value(); |
| 10540 return pt->GetPropertyWithReceiver(receiver, name, attributes); | 10211 return pt->GetPropertyWithReceiver(receiver, name, attributes); |
| 10541 } | 10212 } |
| 10542 | 10213 |
| 10543 | 10214 |
| 10544 MaybeObject* JSObject::GetLocalPropertyPostInterceptor( | 10215 MaybeObject* JSObject::GetLocalPropertyPostInterceptor( |
| 10545 Object* receiver, | 10216 JSReceiver* receiver, |
| 10546 String* name, | 10217 String* name, |
| 10547 PropertyAttributes* attributes) { | 10218 PropertyAttributes* attributes) { |
| 10548 // Check local property in holder, ignore interceptor. | 10219 // Check local property in holder, ignore interceptor. |
| 10549 LookupResult result(GetIsolate()); | 10220 LookupResult result(GetIsolate()); |
| 10550 LocalLookupRealNamedProperty(name, &result); | 10221 LocalLookupRealNamedProperty(name, &result); |
| 10551 if (result.IsFound()) { | 10222 if (result.IsFound()) { |
| 10552 return GetProperty(receiver, &result, name, attributes); | 10223 return GetProperty(receiver, &result, name, attributes); |
| 10553 } | 10224 } |
| 10554 return GetHeap()->undefined_value(); | 10225 return GetHeap()->undefined_value(); |
| 10555 } | 10226 } |
| 10556 | 10227 |
| 10557 | 10228 |
| 10558 MaybeObject* JSObject::GetPropertyWithInterceptor( | 10229 MaybeObject* JSObject::GetPropertyWithInterceptor( |
| 10559 Object* receiver, | 10230 JSReceiver* receiver, |
| 10560 String* name, | 10231 String* name, |
| 10561 PropertyAttributes* attributes) { | 10232 PropertyAttributes* attributes) { |
| 10562 Isolate* isolate = GetIsolate(); | 10233 Isolate* isolate = GetIsolate(); |
| 10563 InterceptorInfo* interceptor = GetNamedInterceptor(); | 10234 InterceptorInfo* interceptor = GetNamedInterceptor(); |
| 10564 HandleScope scope(isolate); | 10235 HandleScope scope(isolate); |
| 10565 Handle<Object> receiver_handle(receiver); | 10236 Handle<JSReceiver> receiver_handle(receiver); |
| 10566 Handle<JSObject> holder_handle(this); | 10237 Handle<JSObject> holder_handle(this); |
| 10567 Handle<String> name_handle(name); | 10238 Handle<String> name_handle(name); |
| 10568 | 10239 |
| 10569 if (!interceptor->getter()->IsUndefined()) { | 10240 if (!interceptor->getter()->IsUndefined()) { |
| 10570 v8::NamedPropertyGetter getter = | 10241 v8::NamedPropertyGetter getter = |
| 10571 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter()); | 10242 v8::ToCData<v8::NamedPropertyGetter>(interceptor->getter()); |
| 10572 LOG(isolate, | 10243 LOG(isolate, |
| 10573 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name)); | 10244 ApiNamedPropertyAccess("interceptor-named-get", *holder_handle, name)); |
| 10574 CustomArguments args(isolate, interceptor->data(), receiver, this); | 10245 CustomArguments args(isolate, interceptor->data(), receiver, this); |
| 10575 v8::AccessorInfo info(args.end()); | 10246 v8::AccessorInfo info(args.end()); |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10687 } | 10358 } |
| 10688 } | 10359 } |
| 10689 | 10360 |
| 10690 LookupResult result(isolate); | 10361 LookupResult result(isolate); |
| 10691 LocalLookupRealNamedProperty(key, &result); | 10362 LocalLookupRealNamedProperty(key, &result); |
| 10692 return result.IsPropertyCallbacks(); | 10363 return result.IsPropertyCallbacks(); |
| 10693 } | 10364 } |
| 10694 | 10365 |
| 10695 | 10366 |
| 10696 int JSObject::NumberOfLocalProperties(PropertyAttributes filter) { | 10367 int JSObject::NumberOfLocalProperties(PropertyAttributes filter) { |
| 10697 if (HasFastProperties()) { | 10368 return HasFastProperties() ? |
| 10698 Map* map = this->map(); | 10369 map()->NumberOfDescribedProperties(filter) : |
| 10699 if (filter == NONE) return map->NumberOfOwnDescriptors(); | 10370 property_dictionary()->NumberOfElementsFilterAttributes(filter); |
| 10700 if (filter == DONT_ENUM) { | |
| 10701 int result = map->EnumLength(); | |
| 10702 if (result != Map::kInvalidEnumCache) return result; | |
| 10703 } | |
| 10704 return map->NumberOfDescribedProperties(OWN_DESCRIPTORS, filter); | |
| 10705 } | |
| 10706 return property_dictionary()->NumberOfElementsFilterAttributes(filter); | |
| 10707 } | 10371 } |
| 10708 | 10372 |
| 10709 | 10373 |
| 10710 void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) { | 10374 void FixedArray::SwapPairs(FixedArray* numbers, int i, int j) { |
| 10711 Object* temp = get(i); | 10375 Object* temp = get(i); |
| 10712 set(i, get(j)); | 10376 set(i, get(j)); |
| 10713 set(j, temp); | 10377 set(j, temp); |
| 10714 if (this != numbers) { | 10378 if (this != numbers) { |
| 10715 temp = numbers->get(i); | 10379 temp = numbers->get(i); |
| 10716 numbers->set(i, Smi::cast(numbers->get(j))); | 10380 numbers->set(i, Smi::cast(numbers->get(j))); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10819 } | 10483 } |
| 10820 } | 10484 } |
| 10821 | 10485 |
| 10822 | 10486 |
| 10823 // 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 |
| 10824 // 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 |
| 10825 // mirrors. | 10489 // mirrors. |
| 10826 void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) { | 10490 void JSObject::GetLocalPropertyNames(FixedArray* storage, int index) { |
| 10827 ASSERT(storage->length() >= (NumberOfLocalProperties() - index)); | 10491 ASSERT(storage->length() >= (NumberOfLocalProperties() - index)); |
| 10828 if (HasFastProperties()) { | 10492 if (HasFastProperties()) { |
| 10829 int real_size = map()->NumberOfOwnDescriptors(); | |
| 10830 DescriptorArray* descs = map()->instance_descriptors(); | 10493 DescriptorArray* descs = map()->instance_descriptors(); |
| 10831 ASSERT(storage->length() >= index + real_size); | 10494 ASSERT(storage->length() >= index + descs->number_of_descriptors()); |
| 10832 for (int i = 0; i < real_size; i++) { | 10495 for (int i = 0; i < descs->number_of_descriptors(); i++) { |
| 10833 storage->set(index + i, descs->GetKey(i)); | 10496 storage->set(index + i, descs->GetKey(i)); |
| 10834 } | 10497 } |
| 10835 } else { | 10498 } else { |
| 10836 property_dictionary()->CopyKeysTo(storage, | 10499 property_dictionary()->CopyKeysTo(storage, |
| 10837 index, | 10500 index, |
| 10838 StringDictionary::UNSORTED); | 10501 StringDictionary::UNSORTED); |
| 10839 } | 10502 } |
| 10840 } | 10503 } |
| 10841 | 10504 |
| 10842 | 10505 |
| (...skipping 1682 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12525 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length); | 12188 { MaybeObject* maybe_obj = heap->AllocateFixedArray(length); |
| 12526 if (!maybe_obj->ToObject(&obj)) return maybe_obj; | 12189 if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| 12527 } | 12190 } |
| 12528 FixedArray* enumeration_order = FixedArray::cast(obj); | 12191 FixedArray* enumeration_order = FixedArray::cast(obj); |
| 12529 | 12192 |
| 12530 // Fill the enumeration order array with property details. | 12193 // Fill the enumeration order array with property details. |
| 12531 int capacity = HashTable<Shape, Key>::Capacity(); | 12194 int capacity = HashTable<Shape, Key>::Capacity(); |
| 12532 int pos = 0; | 12195 int pos = 0; |
| 12533 for (int i = 0; i < capacity; i++) { | 12196 for (int i = 0; i < capacity; i++) { |
| 12534 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) { | 12197 if (Dictionary<Shape, Key>::IsKey(Dictionary<Shape, Key>::KeyAt(i))) { |
| 12535 int index = DetailsAt(i).dictionary_index(); | 12198 enumeration_order->set( |
| 12536 enumeration_order->set(pos++, Smi::FromInt(index)); | 12199 pos++, Smi::FromInt(DetailsAt(i).dictionary_index())); |
| 12537 } | 12200 } |
| 12538 } | 12201 } |
| 12539 | 12202 |
| 12540 // Sort the arrays wrt. enumeration order. | 12203 // Sort the arrays wrt. enumeration order. |
| 12541 iteration_order->SortPairs(enumeration_order, enumeration_order->length()); | 12204 iteration_order->SortPairs(enumeration_order, enumeration_order->length()); |
| 12542 | 12205 |
| 12543 // Overwrite the enumeration_order with the enumeration indices. | 12206 // Overwrite the enumeration_order with the enumeration indices. |
| 12544 for (int i = 0; i < length; i++) { | 12207 for (int i = 0; i < length; i++) { |
| 12545 int index = Smi::cast(iteration_order->get(i))->value(); | 12208 int index = Smi::cast(iteration_order->get(i))->value(); |
| 12546 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... |
| 12655 uint32_t hash) { | 12318 uint32_t hash) { |
| 12656 // Compute the key object. | 12319 // Compute the key object. |
| 12657 Object* k; | 12320 Object* k; |
| 12658 { MaybeObject* maybe_k = Shape::AsObject(key); | 12321 { MaybeObject* maybe_k = Shape::AsObject(key); |
| 12659 if (!maybe_k->ToObject(&k)) return maybe_k; | 12322 if (!maybe_k->ToObject(&k)) return maybe_k; |
| 12660 } | 12323 } |
| 12661 | 12324 |
| 12662 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash); | 12325 uint32_t entry = Dictionary<Shape, Key>::FindInsertionEntry(hash); |
| 12663 // Insert element at empty or deleted entry | 12326 // Insert element at empty or deleted entry |
| 12664 if (!details.IsDeleted() && | 12327 if (!details.IsDeleted() && |
| 12665 details.dictionary_index() == 0 && | 12328 details.dictionary_index() == 0 && Shape::kIsEnumerable) { |
| 12666 Shape::kIsEnumerable) { | |
| 12667 // Assign an enumeration index to the property and update | 12329 // Assign an enumeration index to the property and update |
| 12668 // SetNextEnumerationIndex. | 12330 // SetNextEnumerationIndex. |
| 12669 int index = NextEnumerationIndex(); | 12331 int index = NextEnumerationIndex(); |
| 12670 details = PropertyDetails(details.attributes(), details.type(), index); | 12332 details = PropertyDetails(details.attributes(), details.type(), index); |
| 12671 SetNextEnumerationIndex(index + 1); | 12333 SetNextEnumerationIndex(index + 1); |
| 12672 } | 12334 } |
| 12673 SetEntry(entry, k, value, details); | 12335 SetEntry(entry, k, value, details); |
| 12674 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber() | 12336 ASSERT((Dictionary<Shape, Key>::KeyAt(entry)->IsNumber() |
| 12675 || Dictionary<Shape, Key>::KeyAt(entry)->IsString())); | 12337 || Dictionary<Shape, Key>::KeyAt(entry)->IsString())); |
| 12676 HashTable<Shape, Key>::ElementAdded(); | 12338 HashTable<Shape, Key>::ElementAdded(); |
| (...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 12962 } | 12624 } |
| 12963 | 12625 |
| 12964 // Allocate the instance descriptor. | 12626 // Allocate the instance descriptor. |
| 12965 DescriptorArray* descriptors; | 12627 DescriptorArray* descriptors; |
| 12966 MaybeObject* maybe_descriptors = | 12628 MaybeObject* maybe_descriptors = |
| 12967 DescriptorArray::Allocate(instance_descriptor_length); | 12629 DescriptorArray::Allocate(instance_descriptor_length); |
| 12968 if (!maybe_descriptors->To(&descriptors)) { | 12630 if (!maybe_descriptors->To(&descriptors)) { |
| 12969 return maybe_descriptors; | 12631 return maybe_descriptors; |
| 12970 } | 12632 } |
| 12971 | 12633 |
| 12972 DescriptorArray::WhitenessWitness witness(descriptors); | 12634 FixedArray::WhitenessWitness witness(descriptors); |
| 12973 | 12635 |
| 12974 int number_of_allocated_fields = | 12636 int number_of_allocated_fields = |
| 12975 number_of_fields + unused_property_fields - inobject_props; | 12637 number_of_fields + unused_property_fields - inobject_props; |
| 12976 if (number_of_allocated_fields < 0) { | 12638 if (number_of_allocated_fields < 0) { |
| 12977 // There is enough inobject space for all fields (including unused). | 12639 // There is enough inobject space for all fields (including unused). |
| 12978 number_of_allocated_fields = 0; | 12640 number_of_allocated_fields = 0; |
| 12979 unused_property_fields = inobject_props - number_of_fields; | 12641 unused_property_fields = inobject_props - number_of_fields; |
| 12980 } | 12642 } |
| 12981 | 12643 |
| 12982 // Allocate the fixed array for the fields. | 12644 // Allocate the fixed array for the fields. |
| (...skipping 567 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 13550 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); | 13212 set_year(Smi::FromInt(year), SKIP_WRITE_BARRIER); |
| 13551 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); | 13213 set_month(Smi::FromInt(month), SKIP_WRITE_BARRIER); |
| 13552 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); | 13214 set_day(Smi::FromInt(day), SKIP_WRITE_BARRIER); |
| 13553 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); | 13215 set_weekday(Smi::FromInt(weekday), SKIP_WRITE_BARRIER); |
| 13554 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); | 13216 set_hour(Smi::FromInt(hour), SKIP_WRITE_BARRIER); |
| 13555 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); | 13217 set_min(Smi::FromInt(min), SKIP_WRITE_BARRIER); |
| 13556 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); | 13218 set_sec(Smi::FromInt(sec), SKIP_WRITE_BARRIER); |
| 13557 } | 13219 } |
| 13558 | 13220 |
| 13559 } } // namespace v8::internal | 13221 } } // namespace v8::internal |
| OLD | NEW |