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

Unified Diff: src/objects.cc

Issue 7074052: Fix traversal of the map transition tree to take the prototype (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 9 years, 7 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/objects.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/objects.cc
===================================================================
--- src/objects.cc (revision 8132)
+++ src/objects.cc (working copy)
@@ -3894,39 +3894,68 @@
void Map::TraverseTransitionTree(TraverseCallback callback, void* data) {
+ // Traverse the transition tree without using a stack. We do this by
+ // reversing the pointers in the maps and descriptor arrays.
Map* current = this;
Map* meta_map = heap()->meta_map();
+ Object** map_or_index_field = NULL;
while (current != meta_map) {
DescriptorArray* d = reinterpret_cast<DescriptorArray*>(
*RawField(current, Map::kInstanceDescriptorsOrBitField3Offset));
- if (d->IsEmpty()) {
- Map* prev = current->map();
- current->set_map(meta_map);
- callback(current, data);
- current = prev;
- continue;
+ if (!d->IsEmpty()) {
+ FixedArray* contents = reinterpret_cast<FixedArray*>(
+ d->get(DescriptorArray::kContentArrayIndex));
+ map_or_index_field = RawField(contents, HeapObject::kMapOffset);
+ Object* map_or_index = *map_or_index_field;
+ bool map_done = true; // Controls a nested continue statement.
+ for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0;
+ i < contents->length();
+ i += 2) {
+ PropertyDetails details(Smi::cast(contents->get(i + 1)));
+ if (details.IsTransition()) {
+ // Found a map in the transition array. We record our progress in
+ // the transition array by recording the current map in the map field
+ // of the next map and recording the index in the transition array in
+ // the map field of the array.
+ Map* next = Map::cast(contents->get(i));
+ next->set_map(current);
+ *map_or_index_field = Smi::FromInt(i + 2);
+ current = next;
+ map_done = false;
+ break;
+ }
+ }
+ if (!map_done) continue;
}
-
- FixedArray* contents = reinterpret_cast<FixedArray*>(
- d->get(DescriptorArray::kContentArrayIndex));
- Object** map_or_index_field = RawField(contents, HeapObject::kMapOffset);
- Object* map_or_index = *map_or_index_field;
- bool map_done = true;
- for (int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : 0;
- i < contents->length();
- i += 2) {
- PropertyDetails details(Smi::cast(contents->get(i + 1)));
- if (details.IsTransition()) {
- Map* next = reinterpret_cast<Map*>(contents->get(i));
+ // That was the regular transitions, now for the prototype transitions.
+ FixedArray* prototype_transitions =
+ current->unchecked_prototype_transitions();
+ Object** proto_map_or_index_field =
+ RawField(prototype_transitions, HeapObject::kMapOffset);
+ Object* map_or_index = *proto_map_or_index_field;
+ const int start = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
+ int i = map_or_index->IsSmi() ? Smi::cast(map_or_index)->value() : start;
+ if (i < prototype_transitions->length()) {
+ // Found a map in the prototype transition array. Record progress in
+ // an analogous way to the regular transitions array above.
+ Object* perhaps_map = prototype_transitions->get(i);
+ if (perhaps_map->IsMap()) {
+ Map* next = Map::cast(perhaps_map);
next->set_map(current);
- *map_or_index_field = Smi::FromInt(i + 2);
+ *proto_map_or_index_field =
+ Smi::FromInt(i + kProtoTransitionElementsPerEntry);
current = next;
- map_done = false;
- break;
+ continue;
}
}
- if (!map_done) continue;
- *map_or_index_field = heap()->fixed_array_map();
+ *proto_map_or_index_field = heap()->fixed_array_map();
+ if (map_or_index_field != NULL) {
+ *map_or_index_field = heap()->fixed_array_map();
+ }
+
+ // The callback expects a map to have a real map as its map, so we save
+ // the map field, which is being used to track the traversal and put the
+ // correct map (the meta_map) in place while we do the callback.
Map* prev = current->map();
current->set_map(meta_map);
callback(current, data);
@@ -6364,6 +6393,7 @@
if (slack != 0) {
// Resize the initial map and all maps in its transition tree.
map->TraverseTransitionTree(&ShrinkInstanceSize, &slack);
+
// Give the correct expected_nof_properties to initial maps created later.
ASSERT(expected_nof_properties() >= slack);
set_expected_nof_properties(expected_nof_properties() - slack);
@@ -7083,49 +7113,70 @@
Object* Map::GetPrototypeTransition(Object* prototype) {
FixedArray* cache = prototype_transitions();
- int capacity = cache->length();
- if (capacity == 0) return NULL;
- int finger = Smi::cast(cache->get(0))->value();
- for (int i = 1; i < finger; i += 2) {
- if (cache->get(i) == prototype) return cache->get(i + 1);
+ int number_of_transitions = NumberOfProtoTransitions();
+ const int proto_offset =
+ kProtoTransitionHeaderSize + kProtoTransitionPrototypeOffset;
+ const int map_offset = kProtoTransitionHeaderSize + kProtoTransitionMapOffset;
+ const int step = kProtoTransitionElementsPerEntry;
+ for (int i = 0; i < number_of_transitions; i++) {
+ if (cache->get(proto_offset + i * step) == prototype) {
+ Object* map = cache->get(map_offset + i * step);
+ ASSERT(map->IsMap());
+ return map;
+ }
}
return NULL;
}
MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) {
+ ASSERT(map->IsMap());
+ ASSERT(HeapObject::cast(prototype)->map()->IsMap());
// Don't cache prototype transition if this map is shared.
if (is_shared() || !FLAG_cache_prototype_transitions) return this;
FixedArray* cache = prototype_transitions();
- int capacity = cache->length();
+ const int step = kProtoTransitionElementsPerEntry;
+ const int header = kProtoTransitionHeaderSize;
- int finger = (capacity == 0) ? 1 : Smi::cast(cache->get(0))->value();
+ int capacity = (cache->length() - header) / step;
- if (finger >= capacity) {
+ int transitions = NumberOfProtoTransitions() + 1;
+
+ if (transitions > capacity) {
if (capacity > kMaxCachedPrototypeTransitions) return this;
FixedArray* new_cache;
- { MaybeObject* maybe_cache = heap()->AllocateFixedArray(finger * 2 + 1);
+ // Grow array by factor 2 over and above what we need.
+ { MaybeObject* maybe_cache =
+ heap()->AllocateFixedArray(transitions * 2 * step + header);
if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache;
}
- for (int i = 1; i < capacity; i++) new_cache->set(i, cache->get(i));
+ for (int i = 0; i < capacity * step; i++) {
+ new_cache->set(i + header, cache->get(i + header));
+ }
cache = new_cache;
set_prototype_transitions(cache);
}
- cache->set(finger, prototype);
- cache->set(finger + 1, map);
- cache->set(0, Smi::FromInt(finger + 2));
+ int last = transitions - 1;
+ cache->set(header + last * step + kProtoTransitionPrototypeOffset, prototype);
+ cache->set(header + last * step + kProtoTransitionMapOffset, map);
+ SetNumberOfProtoTransitions(transitions);
+
return cache;
}
MaybeObject* JSReceiver::SetPrototype(Object* value,
bool skip_hidden_prototypes) {
+#ifdef DEBUG
+ int size = Size();
+#endif
+
Heap* heap = GetHeap();
// Silently ignore the change if value is not a JSObject or null.
// SpiderMonkey behaves this way.
@@ -7196,7 +7247,7 @@
real_receiver->set_map(Map::cast(new_map));
heap->ClearInstanceofCache();
-
+ ASSERT(size == Size());
return value;
}
« no previous file with comments | « src/objects.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698