Index: src/objects.cc |
diff --git a/src/objects.cc b/src/objects.cc |
index c3a900d0dc8b655356a5bb5f69dded0de548d159..a069f195a59af7565e765a32482125c19ad4e95d 100644 |
--- a/src/objects.cc |
+++ b/src/objects.cc |
@@ -6883,6 +6883,46 @@ MaybeObject* JSObject::SetElementsLength(Object* len) { |
} |
+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); |
+ } |
+ return NULL; |
+} |
+ |
+ |
+MaybeObject* Map::PutPrototypeTransition(Object* prototype, Map* map) { |
+ // 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(); |
+ int finger = (capacity == 0) ? 1 : Smi::cast(cache->get(0))->value(); |
+ |
+ if (finger >= capacity) { |
Mads Ager (chromium)
2011/04/26 09:14:23
I think we want to put a limit on the number of pr
|
+ FixedArray* new_cache; |
+ { MaybeObject* maybe_cache = heap()->AllocateFixedArray(finger * 2 + 1); |
+ if (!maybe_cache->To<FixedArray>(&new_cache)) return maybe_cache; |
+ } |
+ |
+ for (int i = 1; i < capacity; i++) new_cache->set(i, cache->get(i)); |
+ cache = new_cache; |
+ set_prototype_transitions(cache); |
+ } |
+ |
+ cache->set(finger, prototype); |
+ cache->set(finger + 1, map); |
+ cache->set(0, Smi::FromInt(finger + 2)); |
+ |
+ return cache; |
+} |
+ |
+ |
MaybeObject* JSObject::SetPrototype(Object* value, |
bool skip_hidden_prototypes) { |
Heap* heap = GetHeap(); |
@@ -6933,11 +6973,25 @@ MaybeObject* JSObject::SetPrototype(Object* value, |
} |
// Set the new prototype of the object. |
- Object* new_map; |
- { MaybeObject* maybe_new_map = real_receiver->map()->CopyDropTransitions(); |
- if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; |
+ Map* map = real_receiver->map(); |
+ |
+ // Nothing to do if prototype is already set. |
+ if (map->prototype() == value) return value; |
+ |
+ Object* new_map = map->GetPrototypeTransition(value); |
+ if (new_map == NULL) { |
+ { MaybeObject* maybe_new_map = map->CopyDropTransitions(); |
+ if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map; |
+ } |
+ |
+ { MaybeObject* maybe_new_cache = |
+ map->PutPrototypeTransition(value, Map::cast(new_map)); |
+ if (maybe_new_cache->IsFailure()) return maybe_new_cache; |
+ } |
+ |
+ Map::cast(new_map)->set_prototype(value); |
} |
- Map::cast(new_map)->set_prototype(value); |
+ ASSERT(Map::cast(new_map)->prototype() == value); |
real_receiver->set_map(Map::cast(new_map)); |
heap->ClearInstanceofCache(); |