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 4270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6377 | 6466 |
6378 | 6467 |
6379 void String::PrintOn(FILE* file) { | 6468 void String::PrintOn(FILE* file) { |
6380 int length = this->length(); | 6469 int length = this->length(); |
6381 for (int i = 0; i < length; i++) { | 6470 for (int i = 0; i < length; i++) { |
6382 fprintf(file, "%c", Get(i)); | 6471 fprintf(file, "%c", Get(i)); |
6383 } | 6472 } |
6384 } | 6473 } |
6385 | 6474 |
6386 | 6475 |
| 6476 void Map::CreateOneBackPointer(Map* target) { |
| 6477 #ifdef DEBUG |
| 6478 // Verify target. |
| 6479 Object* source_prototype = prototype(); |
| 6480 Object* target_prototype = target->prototype(); |
| 6481 ASSERT(source_prototype->IsJSReceiver() || |
| 6482 source_prototype->IsMap() || |
| 6483 source_prototype->IsNull()); |
| 6484 ASSERT(target_prototype->IsJSReceiver() || |
| 6485 target_prototype->IsNull()); |
| 6486 ASSERT(source_prototype->IsMap() || |
| 6487 source_prototype == target_prototype); |
| 6488 #endif |
| 6489 // Point target back to source. set_prototype() will not let us set |
| 6490 // the prototype to a map, as we do here. |
| 6491 *RawField(target, kPrototypeOffset) = this; |
| 6492 } |
| 6493 |
| 6494 |
6387 void Map::CreateBackPointers() { | 6495 void Map::CreateBackPointers() { |
6388 DescriptorArray* descriptors = instance_descriptors(); | 6496 DescriptorArray* descriptors = instance_descriptors(); |
6389 for (int i = 0; i < descriptors->number_of_descriptors(); i++) { | 6497 for (int i = 0; i < descriptors->number_of_descriptors(); i++) { |
6390 if (descriptors->GetType(i) == MAP_TRANSITION || | 6498 if (descriptors->GetType(i) == MAP_TRANSITION || |
6391 descriptors->GetType(i) == ELEMENTS_TRANSITION || | 6499 descriptors->GetType(i) == ELEMENTS_TRANSITION || |
6392 descriptors->GetType(i) == CONSTANT_TRANSITION) { | 6500 descriptors->GetType(i) == CONSTANT_TRANSITION) { |
6393 // Get target. | 6501 Object* object = reinterpret_cast<Object*>(descriptors->GetValue(i)); |
6394 Map* target = Map::cast(descriptors->GetValue(i)); | 6502 if (object->IsMap()) { |
6395 #ifdef DEBUG | 6503 CreateOneBackPointer(reinterpret_cast<Map*>(object)); |
6396 // Verify target. | 6504 } else { |
6397 Object* source_prototype = prototype(); | 6505 ASSERT(object->IsFixedArray()); |
6398 Object* target_prototype = target->prototype(); | 6506 ASSERT(descriptors->GetType(i) == ELEMENTS_TRANSITION); |
6399 ASSERT(source_prototype->IsJSReceiver() || | 6507 FixedArray* array = reinterpret_cast<FixedArray*>(object); |
6400 source_prototype->IsMap() || | 6508 for (int i = 0; i < array->length(); ++i) { |
6401 source_prototype->IsNull()); | 6509 Map* target = reinterpret_cast<Map*>(array->get(i)); |
6402 ASSERT(target_prototype->IsJSReceiver() || | 6510 if (!target->IsUndefined()) { |
6403 target_prototype->IsNull()); | 6511 CreateOneBackPointer(target); |
6404 ASSERT(source_prototype->IsMap() || | 6512 } |
6405 source_prototype == target_prototype); | 6513 } |
6406 #endif | 6514 } |
6407 // Point target back to source. set_prototype() will not let us set | |
6408 // the prototype to a map, as we do here. | |
6409 *RawField(target, kPrototypeOffset) = this; | |
6410 } | 6515 } |
6411 } | 6516 } |
6412 } | 6517 } |
6413 | 6518 |
6414 | 6519 |
6415 void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) { | 6520 void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) { |
6416 // Live DescriptorArray objects will be marked, so we must use | 6521 // Live DescriptorArray objects will be marked, so we must use |
6417 // low-level accessors to get and modify their data. | 6522 // low-level accessors to get and modify their data. |
6418 DescriptorArray* d = reinterpret_cast<DescriptorArray*>( | 6523 DescriptorArray* d = reinterpret_cast<DescriptorArray*>( |
6419 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset)); | 6524 *RawField(this, Map::kInstanceDescriptorsOrBitField3Offset)); |
6420 if (d->IsEmpty()) return; | 6525 if (d->IsEmpty()) return; |
6421 Smi* NullDescriptorDetails = | 6526 Smi* NullDescriptorDetails = |
6422 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi(); | 6527 PropertyDetails(NONE, NULL_DESCRIPTOR).AsSmi(); |
6423 FixedArray* contents = reinterpret_cast<FixedArray*>( | 6528 FixedArray* contents = reinterpret_cast<FixedArray*>( |
6424 d->get(DescriptorArray::kContentArrayIndex)); | 6529 d->get(DescriptorArray::kContentArrayIndex)); |
6425 ASSERT(contents->length() >= 2); | 6530 ASSERT(contents->length() >= 2); |
6426 for (int i = 0; i < contents->length(); i += 2) { | 6531 for (int i = 0; i < contents->length(); i += 2) { |
6427 // If the pair (value, details) is a map transition, | 6532 // If the pair (value, details) is a map transition, |
6428 // check if the target is live. If not, null the descriptor. | 6533 // check if the target is live. If not, null the descriptor. |
6429 // Also drop the back pointer for that map transition, so that this | 6534 // 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 | 6535 // map is not reached again by following a back pointer from a |
6431 // non-live object. | 6536 // non-live object. |
6432 PropertyDetails details(Smi::cast(contents->get(i + 1))); | 6537 PropertyDetails details(Smi::cast(contents->get(i + 1))); |
6433 if (details.type() == MAP_TRANSITION || | 6538 if (details.type() == MAP_TRANSITION || |
6434 details.type() == ELEMENTS_TRANSITION || | 6539 details.type() == ELEMENTS_TRANSITION || |
6435 details.type() == CONSTANT_TRANSITION) { | 6540 details.type() == CONSTANT_TRANSITION) { |
6436 Map* target = reinterpret_cast<Map*>(contents->get(i)); | 6541 Object* object = reinterpret_cast<Object*>(contents->get(i)); |
6437 ASSERT(target->IsHeapObject()); | 6542 if (object->IsMap()) { |
6438 MarkBit map_mark = Marking::MarkBitFrom(target); | 6543 Map* target = reinterpret_cast<Map*>(object); |
6439 if (!map_mark.Get()) { | 6544 ASSERT(target->IsHeapObject()); |
6440 ASSERT(target->IsMap()); | 6545 MarkBit map_mark = Marking::MarkBitFrom(target); |
6441 contents->set_unchecked(i + 1, NullDescriptorDetails); | 6546 if (!map_mark.Get()) { |
6442 contents->set_null_unchecked(heap, i); | 6547 ASSERT(target->IsMap()); |
6443 ASSERT(target->prototype() == this || | 6548 contents->set_unchecked(i + 1, NullDescriptorDetails); |
6444 target->prototype() == real_prototype); | 6549 contents->set_null_unchecked(heap, i); |
6445 // Getter prototype() is read-only, set_prototype() has side effects. | 6550 ASSERT(target->prototype() == this || |
6446 *RawField(target, Map::kPrototypeOffset) = real_prototype; | 6551 target->prototype() == real_prototype); |
| 6552 // Getter prototype() is read-only, set_prototype() has side effects. |
| 6553 *RawField(target, Map::kPrototypeOffset) = real_prototype; |
| 6554 } |
| 6555 } else { |
| 6556 ASSERT(object->IsFixedArray()); |
| 6557 ASSERT(details.type() == ELEMENTS_TRANSITION); |
| 6558 FixedArray* array = reinterpret_cast<FixedArray*>(contents->get(i)); |
| 6559 bool reachable_map_found = false; |
| 6560 for (int j = 0; j < array->length(); ++j) { |
| 6561 Map* target = reinterpret_cast<Map*>(array->get(j)); |
| 6562 ASSERT(target->IsHeapObject()); |
| 6563 MarkBit map_mark = Marking::MarkBitFrom(target); |
| 6564 if (!map_mark.Get()) { |
| 6565 ASSERT(target->IsMap()); |
| 6566 array->set_undefined(j); |
| 6567 ASSERT(target->prototype() == this || |
| 6568 target->prototype() == real_prototype); |
| 6569 // Getter prototype() is read-only, set_prototype() has side |
| 6570 // effects. |
| 6571 *RawField(target, Map::kPrototypeOffset) = real_prototype; |
| 6572 } else { |
| 6573 reachable_map_found = true; |
| 6574 } |
| 6575 } |
| 6576 // If no map was found, make sure the FixedArray also gets collected. |
| 6577 if (!reachable_map_found) { |
| 6578 contents->set_unchecked(i + 1, NullDescriptorDetails); |
| 6579 contents->set_null_unchecked(heap, i); |
| 6580 } |
6447 } | 6581 } |
6448 } | 6582 } |
6449 } | 6583 } |
6450 } | 6584 } |
6451 | 6585 |
6452 | 6586 |
6453 int Map::Hash() { | 6587 int Map::Hash() { |
6454 // For performance reasons we only hash the 3 most variable fields of a map: | 6588 // For performance reasons we only hash the 3 most variable fields of a map: |
6455 // constructor, prototype and bit_field2. | 6589 // constructor, prototype and bit_field2. |
6456 | 6590 |
(...skipping 5427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11884 if (break_point_objects()->IsUndefined()) return 0; | 12018 if (break_point_objects()->IsUndefined()) return 0; |
11885 // Single break point. | 12019 // Single break point. |
11886 if (!break_point_objects()->IsFixedArray()) return 1; | 12020 if (!break_point_objects()->IsFixedArray()) return 1; |
11887 // Multiple break points. | 12021 // Multiple break points. |
11888 return FixedArray::cast(break_point_objects())->length(); | 12022 return FixedArray::cast(break_point_objects())->length(); |
11889 } | 12023 } |
11890 #endif | 12024 #endif |
11891 | 12025 |
11892 | 12026 |
11893 } } // namespace v8::internal | 12027 } } // namespace v8::internal |
OLD | NEW |