OLD | NEW |
---|---|
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 2004 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2015 cache->Update(descriptors, name, number); | 2015 cache->Update(descriptors, name, number); |
2016 } | 2016 } |
2017 if (number != DescriptorArray::kNotFound) { | 2017 if (number != DescriptorArray::kNotFound) { |
2018 result->DescriptorResult(holder, descriptors->GetDetails(number), number); | 2018 result->DescriptorResult(holder, descriptors->GetDetails(number), number); |
2019 } else { | 2019 } else { |
2020 result->NotFound(); | 2020 result->NotFound(); |
2021 } | 2021 } |
2022 } | 2022 } |
2023 | 2023 |
2024 | 2024 |
2025 static Map* GetElementsTransitionMapFromDescriptor(Object* descriptor_contents, | |
2026 ElementsKind elements_kind) { | |
2027 if (descriptor_contents->IsMap()) { | |
2028 Map* map = Map::cast(descriptor_contents); | |
2029 if (map->elements_kind() == elements_kind) { | |
2030 return map; | |
2031 } | |
2032 return NULL; | |
2033 } | |
2034 | |
2035 FixedArray* map_array = FixedArray::cast(descriptor_contents); | |
2036 for (int i = 0; i < map_array->length(); ++i) { | |
2037 Object* current = map_array->get(i); | |
2038 // Skip undefined slots, they are sentinels for reclaimed maps. | |
2039 if (!current->IsUndefined()) { | |
2040 Map* current_map = Map::cast(map_array->get(i)); | |
2041 if (current_map->elements_kind() == elements_kind) { | |
2042 return current_map; | |
2043 } | |
2044 } | |
2045 } | |
2046 | |
2047 return NULL; | |
2048 } | |
2049 | |
2050 | |
2051 static MaybeObject* AddElementsTransitionMapToDescriptor( | |
2052 Object* descriptor_contents, | |
2053 Map* new_map) { | |
2054 // Nothing was in the descriptor for an ELEMENTS_TRANSITION, | |
2055 // simply add the map. | |
2056 if (descriptor_contents == NULL) { | |
2057 return new_map; | |
2058 } | |
2059 | |
2060 // There was already a map in the descriptor, create a 2-element FixedArray | |
2061 // to contain the existing map plus the new one. | |
2062 FixedArray* new_array; | |
2063 Heap* heap = new_map->GetHeap(); | |
2064 if (descriptor_contents->IsMap()) { | |
2065 // Must tenure, DescriptorArray expects no new-space objects. | |
2066 MaybeObject* maybe_new_array = heap->AllocateFixedArray(2, TENURED); | |
2067 if (!maybe_new_array->To<FixedArray>(&new_array)) { | |
2068 return maybe_new_array; | |
2069 } | |
2070 new_array->set(0, descriptor_contents); | |
2071 new_array->set(1, new_map); | |
2072 return new_array; | |
2073 } | |
2074 | |
2075 // The descriptor already contained a list of maps for different ElementKinds | |
2076 // of ELEMENTS_TRANSITION, first check the existing array for an undefined | |
2077 // slot, and if that's not available, create a FixedArray to hold the existing | |
2078 // maps plus the new one and fill it in. | |
2079 FixedArray* array = FixedArray::cast(descriptor_contents); | |
2080 for (int i = 0; i < array->length(); ++i) { | |
2081 if (array->get(i)->IsUndefined()) { | |
2082 array->set(i, new_map); | |
2083 return array; | |
2084 } | |
2085 } | |
2086 | |
2087 // Must tenure, DescriptorArray expects no new-space objects. | |
2088 MaybeObject* maybe_new_array = | |
2089 heap->AllocateFixedArray(array->length() + 1, TENURED); | |
2090 if (!maybe_new_array->To<FixedArray>(&new_array)) { | |
2091 return maybe_new_array; | |
2092 } | |
2093 int i = 0; | |
2094 while (i < array->length()) { | |
2095 new_array->set(i, array->get(i)); | |
2096 ++i; | |
2097 } | |
2098 new_array->set(i, new_map); | |
2099 return new_array; | |
2100 } | |
2101 | |
2102 | |
2025 MaybeObject* JSObject::GetElementsTransitionMap(ElementsKind elements_kind) { | 2103 MaybeObject* JSObject::GetElementsTransitionMap(ElementsKind elements_kind) { |
2026 Heap* current_heap = GetHeap(); | 2104 Heap* current_heap = GetHeap(); |
2027 Map* current_map = map(); | 2105 Map* current_map = map(); |
2028 DescriptorArray* descriptors = current_map->instance_descriptors(); | 2106 DescriptorArray* descriptors = current_map->instance_descriptors(); |
2029 String* elements_transition_sentinel_name = current_heap->empty_symbol(); | 2107 String* elements_transition_sentinel_name = current_heap->empty_symbol(); |
2030 | 2108 |
2031 if (current_map->elements_kind() == elements_kind) return current_map; | 2109 if (current_map->elements_kind() == elements_kind) return current_map; |
2032 | 2110 |
2033 // Only objects with FastProperties can have DescriptorArrays and can track | 2111 // Only objects with FastProperties can have DescriptorArrays and can track |
2034 // element-related maps. Also don't add descriptors to maps that are shared. | 2112 // element-related maps. Also don't add descriptors to maps that are shared. |
2035 bool safe_to_add_transition = HasFastProperties() && | 2113 bool safe_to_add_transition = HasFastProperties() && |
2036 !current_map->IsUndefined() && | 2114 !current_map->IsUndefined() && |
2037 !current_map->is_shared(); | 2115 !current_map->is_shared(); |
2038 | 2116 |
2039 // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps cause by objects | 2117 // Prevent long chains of DICTIONARY -> FAST_ELEMENTS maps cause by objects |
2040 // with elements that switch back and forth between dictionary and fast | 2118 // with elements that switch back and forth between dictionary and fast |
2041 // element mode. | 2119 // element mode. |
2042 if ((current_map->elements_kind() == DICTIONARY_ELEMENTS && | 2120 if ((current_map->elements_kind() == DICTIONARY_ELEMENTS && |
2043 elements_kind == FAST_ELEMENTS)) { | 2121 elements_kind == FAST_ELEMENTS)) { |
2044 safe_to_add_transition = false; | 2122 safe_to_add_transition = false; |
2045 } | 2123 } |
2046 | 2124 |
2125 Object* descriptor_contents = NULL; | |
2047 if (safe_to_add_transition) { | 2126 if (safe_to_add_transition) { |
2048 // It's only safe to manipulate the descriptor array if it would be | 2127 // It's only safe to manipulate the descriptor array if it would be |
2049 // safe to add a transition. | 2128 // safe to add a transition. |
2050 | 2129 |
2051 // Check if the elements transition already exists. | 2130 // Check if the elements transition already exists. |
2052 DescriptorLookupCache* cache = | 2131 DescriptorLookupCache* cache = |
2053 current_heap->isolate()->descriptor_lookup_cache(); | 2132 current_heap->isolate()->descriptor_lookup_cache(); |
2054 int index = cache->Lookup(descriptors, elements_transition_sentinel_name); | 2133 int index = cache->Lookup(descriptors, elements_transition_sentinel_name); |
2055 if (index == DescriptorLookupCache::kAbsent) { | 2134 if (index == DescriptorLookupCache::kAbsent) { |
2056 index = descriptors->Search(elements_transition_sentinel_name); | 2135 index = descriptors->Search(elements_transition_sentinel_name); |
2057 cache->Update(descriptors, | 2136 cache->Update(descriptors, |
2058 elements_transition_sentinel_name, | 2137 elements_transition_sentinel_name, |
2059 index); | 2138 index); |
2060 } | 2139 } |
2061 | 2140 |
2062 // If the transition already exists, check the type. If there is a match, | 2141 // If the transition already exists, check the type. If there is a match, |
2063 // return it. | 2142 // return it. |
2064 if (index != DescriptorArray::kNotFound) { | 2143 if (index != DescriptorArray::kNotFound) { |
2065 PropertyDetails details(PropertyDetails(descriptors->GetDetails(index))); | 2144 PropertyDetails details(PropertyDetails(descriptors->GetDetails(index))); |
2066 if (details.type() == ELEMENTS_TRANSITION && | 2145 if (details.type() == ELEMENTS_TRANSITION) { |
2067 details.elements_kind() == elements_kind) { | 2146 descriptor_contents = descriptors->GetValue(index); |
2068 return descriptors->GetValue(index); | 2147 Map* maybe_transition_map = |
2148 GetElementsTransitionMapFromDescriptor(descriptor_contents, | |
2149 elements_kind); | |
2150 if (maybe_transition_map != NULL) { | |
2151 ASSERT(maybe_transition_map->IsMap()); | |
2152 return maybe_transition_map; | |
2153 } | |
2069 } else { | 2154 } else { |
2070 safe_to_add_transition = false; | 2155 safe_to_add_transition = false; |
2071 } | 2156 } |
2072 } | 2157 } |
2073 } | 2158 } |
2074 | 2159 |
2075 // No transition to an existing map for the given ElementsKind. Make a new | 2160 // No transition to an existing map for the given ElementsKind. Make a new |
2076 // one. | 2161 // one. |
2077 Object* obj; | 2162 Object* obj; |
2078 { MaybeObject* maybe_map = current_map->CopyDropTransitions(); | 2163 { MaybeObject* maybe_map = current_map->CopyDropTransitions(); |
2079 if (!maybe_map->ToObject(&obj)) return maybe_map; | 2164 if (!maybe_map->ToObject(&obj)) return maybe_map; |
2080 } | 2165 } |
2081 Map* new_map = Map::cast(obj); | 2166 Map* new_map = Map::cast(obj); |
2082 | 2167 |
2083 new_map->set_elements_kind(elements_kind); | 2168 new_map->set_elements_kind(elements_kind); |
2084 | 2169 |
2085 // Only remember the map transition if the object's map is NOT equal to the | 2170 // Only remember the map transition if the object's map is NOT equal to the |
2086 // global object_function's map and there is not an already existing | 2171 // global object_function's map and there is not an already existing |
2087 // non-matching element transition. | 2172 // non-matching element transition. |
2088 bool allow_map_transition = | 2173 bool allow_map_transition = safe_to_add_transition && |
2089 safe_to_add_transition && | |
2090 (GetIsolate()->context()->global_context()->object_function()->map() != | 2174 (GetIsolate()->context()->global_context()->object_function()->map() != |
2091 map()); | 2175 map()); |
2092 if (allow_map_transition) { | 2176 if (allow_map_transition) { |
2093 // Allocate new instance descriptors for the old map with map transition. | 2177 MaybeObject* maybe_new_contents = |
2178 AddElementsTransitionMapToDescriptor(descriptor_contents, new_map); | |
2179 Object* new_contents; | |
2180 if (!maybe_new_contents->ToObject(&new_contents)) { | |
2181 return maybe_new_contents; | |
2182 } | |
2183 | |
2094 ElementsTransitionDescriptor desc(elements_transition_sentinel_name, | 2184 ElementsTransitionDescriptor desc(elements_transition_sentinel_name, |
2095 Map::cast(new_map), | 2185 new_contents); |
2096 elements_kind); | |
2097 Object* new_descriptors; | 2186 Object* new_descriptors; |
2098 MaybeObject* maybe_new_descriptors = descriptors->CopyInsert( | 2187 MaybeObject* maybe_new_descriptors = descriptors->CopyInsert( |
2099 &desc, | 2188 &desc, |
2100 KEEP_TRANSITIONS); | 2189 KEEP_TRANSITIONS); |
2101 if (!maybe_new_descriptors->ToObject(&new_descriptors)) { | 2190 if (!maybe_new_descriptors->ToObject(&new_descriptors)) { |
2102 return maybe_new_descriptors; | 2191 return maybe_new_descriptors; |
2103 } | 2192 } |
2104 descriptors = DescriptorArray::cast(new_descriptors); | 2193 descriptors = DescriptorArray::cast(new_descriptors); |
2105 current_map->set_instance_descriptors(descriptors); | 2194 current_map->set_instance_descriptors(descriptors); |
2106 } | 2195 } |
(...skipping 4276 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6383 } | 6472 } |
6384 } | 6473 } |
6385 | 6474 |
6386 | 6475 |
6387 void Map::CreateBackPointers() { | 6476 void Map::CreateBackPointers() { |
6388 DescriptorArray* descriptors = instance_descriptors(); | 6477 DescriptorArray* descriptors = instance_descriptors(); |
6389 for (int i = 0; i < descriptors->number_of_descriptors(); i++) { | 6478 for (int i = 0; i < descriptors->number_of_descriptors(); i++) { |
6390 if (descriptors->GetType(i) == MAP_TRANSITION || | 6479 if (descriptors->GetType(i) == MAP_TRANSITION || |
6391 descriptors->GetType(i) == ELEMENTS_TRANSITION || | 6480 descriptors->GetType(i) == ELEMENTS_TRANSITION || |
6392 descriptors->GetType(i) == CONSTANT_TRANSITION) { | 6481 descriptors->GetType(i) == CONSTANT_TRANSITION) { |
6393 // Get target. | 6482 Object* object = reinterpret_cast<Object*>(descriptors->GetValue(i)); |
6394 Map* target = Map::cast(descriptors->GetValue(i)); | 6483 if (object->IsMap()) { |
6484 // Get target. | |
6485 Map* target = reinterpret_cast<Map*>(object); | |
6395 #ifdef DEBUG | 6486 #ifdef DEBUG |
6396 // Verify target. | 6487 // Verify target. |
6397 Object* source_prototype = prototype(); | 6488 Object* source_prototype = prototype(); |
6398 Object* target_prototype = target->prototype(); | 6489 Object* target_prototype = target->prototype(); |
6399 ASSERT(source_prototype->IsJSReceiver() || | 6490 ASSERT(source_prototype->IsJSReceiver() || |
6400 source_prototype->IsMap() || | 6491 source_prototype->IsMap() || |
6401 source_prototype->IsNull()); | 6492 source_prototype->IsNull()); |
6402 ASSERT(target_prototype->IsJSReceiver() || | 6493 ASSERT(target_prototype->IsJSReceiver() || |
6403 target_prototype->IsNull()); | 6494 target_prototype->IsNull()); |
6404 ASSERT(source_prototype->IsMap() || | 6495 ASSERT(source_prototype->IsMap() || |
6405 source_prototype == target_prototype); | 6496 source_prototype == target_prototype); |
6406 #endif | 6497 #endif |
6407 // Point target back to source. set_prototype() will not let us set | 6498 // Point target back to source. set_prototype() will not let us set |
6408 // the prototype to a map, as we do here. | 6499 // the prototype to a map, as we do here. |
6409 *RawField(target, kPrototypeOffset) = this; | 6500 *RawField(target, kPrototypeOffset) = this; |
6501 } else { | |
6502 ASSERT(object->IsFixedArray()); | |
6503 ASSERT(descriptors->GetType(i) == ELEMENTS_TRANSITION); | |
6504 FixedArray* array = reinterpret_cast<FixedArray*>(object); | |
6505 for (int i = 0; i < array->length(); ++i) { | |
6506 Map* target = reinterpret_cast<Map*>(array->get(i)); | |
6507 if (!target->IsUndefined()) { | |
6508 #ifdef DEBUG | |
6509 // Verify target. | |
Vyacheslav Egorov (Chromium)
2011/09/23 13:49:23
Can we avoid code duplication by moving these asse
danno
2011/09/25 09:24:27
Done.
| |
6510 Object* source_prototype = prototype(); | |
6511 Object* target_prototype = target->prototype(); | |
6512 ASSERT(source_prototype->IsJSReceiver() || | |
6513 source_prototype->IsMap() || | |
6514 source_prototype->IsNull()); | |
6515 ASSERT(target_prototype->IsJSReceiver() || | |
6516 target_prototype->IsNull()); | |
6517 ASSERT(source_prototype->IsMap() || | |
6518 source_prototype == target_prototype); | |
6519 #endif | |
6520 // Point target back to source. set_prototype() will not let us set | |
6521 // the prototype to a map, as we do here. | |
6522 *RawField(target, kPrototypeOffset) = this; | |
6523 } | |
6524 } | |
6525 } | |
6410 } | 6526 } |
6411 } | 6527 } |
6412 } | 6528 } |
6413 | 6529 |
6414 | 6530 |
6415 void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) { | 6531 void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) { |
6416 // Live DescriptorArray objects will be marked, so we must use | 6532 // Live DescriptorArray objects will be marked, so we must use |
6417 // low-level accessors to get and modify their data. | 6533 // low-level accessors to get and modify their data. |
6418 DescriptorArray* d = reinterpret_cast<DescriptorArray*>( | 6534 DescriptorArray* d = reinterpret_cast<DescriptorArray*>( |
6419 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset)); | 6535 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset)); |
6420 if (d->IsEmpty()) return; | 6536 if (d->IsEmpty()) return; |
6421 Smi* NullDescriptorDetails = | 6537 Smi* NullDescriptorDetails = |
6422 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi(); | 6538 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi(); |
6423 FixedArray* contents = reinterpret_cast<FixedArray*>( | 6539 FixedArray* contents = reinterpret_cast<FixedArray*>( |
6424 d->get(DescriptorArray::kContentArrayIndex)); | 6540 d->get(DescriptorArray::kContentArrayIndex)); |
6425 ASSERT(contents->length() >= 2); | 6541 ASSERT(contents->length() >= 2); |
6426 for (int i = 0; i < contents->length(); i += 2) { | 6542 for (int i = 0; i < contents->length(); i += 2) { |
6427 // If the pair (value, details) is a map transition, | 6543 // If the pair (value, details) is a map transition, |
6428 // check if the target is live. If not, null the descriptor. | 6544 // check if the target is live. If not, null the descriptor. |
6429 // Also drop the back pointer for that map transition, so that this | 6545 // Also drop the back pointer for that map transition, so that this |
6430 // map is not reached again by following a back pointer from a | 6546 // map is not reached again by following a back pointer from a |
6431 // non-live object. | 6547 // non-live object. |
6432 PropertyDetails details(Smi::cast(contents->get(i + 1))); | 6548 PropertyDetails details(Smi::cast(contents->get(i + 1))); |
6433 if (details.type() == MAP_TRANSITION || | 6549 if (details.type() == MAP_TRANSITION || |
6434 details.type() == ELEMENTS_TRANSITION || | 6550 details.type() == ELEMENTS_TRANSITION || |
6435 details.type() == CONSTANT_TRANSITION) { | 6551 details.type() == CONSTANT_TRANSITION) { |
6436 Map* target = reinterpret_cast<Map*>(contents->get(i)); | 6552 Object* object = reinterpret_cast<Object*>(contents->get(i)); |
6437 ASSERT(target->IsHeapObject()); | 6553 if (object->IsMap()) { |
6438 MarkBit map_mark = Marking::MarkBitFrom(target); | 6554 Map* target = reinterpret_cast<Map*>(object); |
6439 if (!map_mark.Get()) { | 6555 ASSERT(target->IsHeapObject()); |
6440 ASSERT(target->IsMap()); | 6556 MarkBit map_mark = Marking::MarkBitFrom(target); |
6441 contents->set_unchecked(i + 1, NullDescriptorDetails); | 6557 if (!map_mark.Get()) { |
6442 contents->set_null_unchecked(heap, i); | 6558 ASSERT(target->IsMap()); |
6443 ASSERT(target->prototype() == this || | 6559 contents->set_unchecked(i + 1, NullDescriptorDetails); |
6444 target->prototype() == real_prototype); | 6560 contents->set_null_unchecked(heap, i); |
6445 // Getter prototype() is read-only, set_prototype() has side effects. | 6561 ASSERT(target->prototype() == this || |
6446 *RawField(target, Map::kPrototypeOffset) = real_prototype; | 6562 target->prototype() == real_prototype); |
6563 // Getter prototype() is read-only, set_prototype() has side effects. | |
6564 *RawField(target, Map::kPrototypeOffset) = real_prototype; | |
6565 } | |
6566 } else { | |
6567 ASSERT(object->IsFixedArray()); | |
6568 ASSERT(details.type() == ELEMENTS_TRANSITION); | |
6569 FixedArray* array = reinterpret_cast<FixedArray*>(contents->get(i)); | |
6570 for (int i = 0; i < array->length(); ++i) { | |
Vyacheslav Egorov (Chromium)
2011/09/23 13:49:23
Probably you can discard this transition altogethe
danno
2011/09/25 09:24:27
Done.
| |
6571 Map* target = reinterpret_cast<Map*>(array->get(i)); | |
6572 ASSERT(target->IsHeapObject()); | |
6573 MarkBit map_mark = Marking::MarkBitFrom(target); | |
6574 if (!map_mark.Get()) { | |
6575 ASSERT(target->IsMap()); | |
6576 array->set_undefined(i); | |
6577 ASSERT(target->prototype() == this || | |
6578 target->prototype() == real_prototype); | |
6579 // Getter prototype() is read-only, set_prototype() has side effects . | |
Vyacheslav Egorov (Chromium)
2011/09/23 13:49:23
long line
danno
2011/09/25 09:24:27
Done.
| |
6580 *RawField(target, Map::kPrototypeOffset) = real_prototype; | |
6581 } | |
6582 } | |
6447 } | 6583 } |
6448 } | 6584 } |
6449 } | 6585 } |
6450 } | 6586 } |
6451 | 6587 |
6452 | 6588 |
6453 int Map::Hash() { | 6589 int Map::Hash() { |
6454 // For performance reasons we only hash the 3 most variable fields of a map: | 6590 // For performance reasons we only hash the 3 most variable fields of a map: |
6455 // constructor, prototype and bit_field2. | 6591 // constructor, prototype and bit_field2. |
6456 | 6592 |
(...skipping 5427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
11884 if (break_point_objects()->IsUndefined()) return 0; | 12020 if (break_point_objects()->IsUndefined()) return 0; |
11885 // Single break point. | 12021 // Single break point. |
11886 if (!break_point_objects()->IsFixedArray()) return 1; | 12022 if (!break_point_objects()->IsFixedArray()) return 1; |
11887 // Multiple break points. | 12023 // Multiple break points. |
11888 return FixedArray::cast(break_point_objects())->length(); | 12024 return FixedArray::cast(break_point_objects())->length(); |
11889 } | 12025 } |
11890 #endif | 12026 #endif |
11891 | 12027 |
11892 | 12028 |
11893 } } // namespace v8::internal | 12029 } } // namespace v8::internal |
OLD | NEW |