Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(442)

Side by Side Diff: src/objects.cc

Issue 8017003: Cache multiple ElementsKind map transition per map. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: review feedback Created 9 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/objects.h ('k') | src/objects-printer.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « src/objects.h ('k') | src/objects-printer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698