Chromium Code Reviews| Index: src/objects.cc |
| diff --git a/src/objects.cc b/src/objects.cc |
| index 292e75300633026409a114e52ddda7e0ceae7f48..4b46fa3f508279e73c80b5bbd82e997d50c2a333 100644 |
| --- a/src/objects.cc |
| +++ b/src/objects.cc |
| @@ -2489,10 +2489,11 @@ MaybeObject* NormalizedMapCache::Get(JSObject* obj, |
| PropertyNormalizationMode mode) { |
| Isolate* isolate = obj->GetIsolate(); |
| Map* fast = obj->map(); |
| - int index = Hash(fast) % kEntries; |
| + int index = fast->Hash() % kEntries; |
| Object* result = get(index); |
| - if (result->IsMap() && CheckHit(Map::cast(result), fast, mode)) { |
| + if (result->IsMap() && Map::cast(result)->Equals(fast, mode)) { |
| #ifdef DEBUG |
| + Map::cast(result)->SharedMapVerify(); |
| if (FLAG_enable_slow_asserts) { |
| // The cached map should match newly created normalized map bit-by-bit. |
| Object* fresh; |
| @@ -2528,43 +2529,6 @@ void NormalizedMapCache::Clear() { |
| } |
| -int NormalizedMapCache::Hash(Map* fast) { |
| - // For performance reasons we only hash the 3 most variable fields of a map: |
| - // constructor, prototype and bit_field2. |
| - |
| - // Shift away the tag. |
| - int hash = (static_cast<uint32_t>( |
| - reinterpret_cast<uintptr_t>(fast->constructor())) >> 2); |
| - |
| - // XOR-ing the prototype and constructor directly yields too many zero bits |
| - // when the two pointers are close (which is fairly common). |
| - // To avoid this we shift the prototype 4 bits relatively to the constructor. |
| - hash ^= (static_cast<uint32_t>( |
| - reinterpret_cast<uintptr_t>(fast->prototype())) << 2); |
| - |
| - return hash ^ (hash >> 16) ^ fast->bit_field2(); |
| -} |
| - |
| - |
| -bool NormalizedMapCache::CheckHit(Map* slow, |
| - Map* fast, |
| - PropertyNormalizationMode mode) { |
| -#ifdef DEBUG |
| - slow->SharedMapVerify(); |
| -#endif |
| - return |
| - slow->constructor() == fast->constructor() && |
| - slow->prototype() == fast->prototype() && |
| - slow->inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ? |
| - 0 : |
| - fast->inobject_properties()) && |
| - slow->instance_type() == fast->instance_type() && |
| - slow->bit_field() == fast->bit_field() && |
| - slow->bit_field2() == fast->bit_field2() && |
| - (slow->bit_field3() & ~(1<<Map::kIsShared)) == fast->bit_field3(); |
|
Mads Ager (chromium)
2011/06/01 08:45:53
Here we only ignore the shared bit on |slow|. Is t
Jakob Kummerow
2011/06/01 10:15:27
If I understand the code correctly, for all cases
|
| -} |
| - |
| - |
| MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) { |
| if (map()->is_shared()) { |
| // Fast case maps are never marked as shared. |
| @@ -4058,6 +4022,7 @@ class CodeCacheHashTableKey : public HashTableKey { |
| private: |
| String* name_; |
| Code::Flags flags_; |
| + // TODO(jkummerow): We should be able to get by without this. |
| Code* code_; |
| }; |
| @@ -4077,7 +4042,7 @@ MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) { |
| if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| } |
| - // Don't use this, as the table might have grown. |
| + // Don't use |this|, as the table might have grown. |
| CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj); |
| int entry = cache->FindInsertionEntry(key.Hash()); |
| @@ -4123,6 +4088,158 @@ static bool HasKey(FixedArray* array, Object* key) { |
| } |
| +MaybeObject* PolymorphicCodeCache::Update(MapList* maps, |
| + Code::Flags flags, |
| + Code* code) { |
| + // Initialize cache if necessary. |
| + if (cache()->IsUndefined()) { |
| + Object* result; |
| + { MaybeObject* maybe_result = |
| + PolymorphicCodeCacheHashTable::Allocate( |
| + PolymorphicCodeCacheHashTable::kInitialSize); |
| + if (!maybe_result->ToObject(&result)) return maybe_result; |
| + } |
| + set_cache(result); |
| + } else { |
| + // This entry shouldn't be contained in the cache yet. |
| + ASSERT(PolymorphicCodeCacheHashTable::cast(cache()) |
| + ->Lookup(maps, flags)->IsUndefined()); |
| + } |
| + PolymorphicCodeCacheHashTable* hash_table = |
| + PolymorphicCodeCacheHashTable::cast(cache()); |
| + Object* new_cache; |
| + { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code); |
| + if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache; |
| + } |
| + set_cache(new_cache); |
| + return this; |
| +} |
| + |
| + |
| +Object* PolymorphicCodeCache::Lookup(MapList* maps, Code::Flags flags) { |
| + if (!cache()->IsUndefined()) { |
| + PolymorphicCodeCacheHashTable* hash_table = |
| + PolymorphicCodeCacheHashTable::cast(cache()); |
| + return hash_table->Lookup(maps, flags); |
| + } else { |
| + return GetHeap()->undefined_value(); |
| + } |
| +} |
| + |
| + |
| +class PolymorphicCodeCacheHashTableKey : public HashTableKey { |
| + public: |
| + PolymorphicCodeCacheHashTableKey(MapList* maps, int code_flags) |
| + : maps_(maps), |
|
Mads Ager (chromium)
2011/06/01 08:45:53
This looks unsafe. I think you have to copy the ma
Jakob Kummerow
2011/06/01 10:15:27
Note how the |key| objects constructed from this c
Mads Ager (chromium)
2011/06/01 10:36:54
Ah, yeah. Sorry I forgot how this works. You are a
Jakob Kummerow
2011/06/01 12:03:09
Done.
|
| + code_flags_(code_flags) {} |
| + |
| + bool IsMatch(Object* other) { |
| + MapList other_maps(kDefaultListAllocationSize); |
| + int other_flags; |
| + FromObject(other, &other_flags, &other_maps); |
| + if (code_flags_ != other_flags) return false; |
| + if (maps_->length() != other_maps.length()) return false; |
| + // Compare just the hashes first because it's faster. |
| + int this_hash = MapsHashHelper(maps_, code_flags_); |
| + int other_hash = MapsHashHelper(&other_maps, other_flags); |
| + if (this_hash != other_hash) return false; |
| + |
| + // Full comparison: for each map in maps_, look for an equivalent map in |
| + // other_maps. This implementation is slow, but probably good enough for |
| + // now because the lists are short (<= 4 elements currently). |
| + for (int i = 0; i < maps_->length(); ++i) { |
| + bool match_found = false; |
| + for (int j = 0; j < other_maps.length(); ++j) { |
| + if (maps_->at(i)->Equals(other_maps.at(j), KEEP_INOBJECT_PROPERTIES)) { |
| + match_found = true; |
| + break; |
| + } |
| + } |
| + if (!match_found) return false; |
| + } |
| + return true; |
| + } |
| + |
| + static uint32_t MapsHashHelper(MapList* maps, int code_flags) { |
| + uint32_t hash = code_flags; |
| + for (int i = 0; i < maps->length(); ++i) { |
| + hash ^= maps->at(i)->Hash(); |
| + } |
| + return hash; |
| + } |
| + |
| + uint32_t Hash() { |
| + return MapsHashHelper(maps_, code_flags_); |
| + } |
| + |
| + uint32_t HashForObject(Object* obj) { |
| + MapList other_maps(kDefaultListAllocationSize); |
| + int other_flags; |
| + FromObject(obj, &other_flags, &other_maps); |
| + return MapsHashHelper(&other_maps, other_flags); |
| + } |
| + |
| + MUST_USE_RESULT MaybeObject* AsObject() { |
| + Object* obj; |
| + { MaybeObject* maybe_obj = |
| + HEAP->AllocateUninitializedFixedArray(maps_->length() + 1); |
| + if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| + } |
| + FixedArray* list = FixedArray::cast(obj); |
| + list->set(0, Smi::FromInt(code_flags_)); |
| + for (int i = 0; i < maps_->length(); ++i) { |
| + list->set(i + 1, maps_->at(i)); |
| + } |
| + return list; |
| + } |
| + |
| + private: |
| + static MapList* FromObject(Object* obj, int* code_flags, MapList* maps) { |
| + FixedArray* list = FixedArray::cast(obj); |
| + maps->Rewind(0); |
| + *code_flags = Smi::cast(list->get(0))->value(); |
| + for (int i = 1; i < list->length(); ++i) { |
| + maps->Add(Map::cast(list->get(i))); |
| + } |
| + return maps; |
| + } |
| + |
| + MapList* maps_; |
| + int code_flags_; |
| + static const int kDefaultListAllocationSize = |
| + KeyedIC::kMaxKeyedPolymorphism + 1; |
| +}; |
| + |
| + |
| +Object* PolymorphicCodeCacheHashTable::Lookup(MapList* maps, int code_flags) { |
| + PolymorphicCodeCacheHashTableKey key(maps, code_flags); |
| + int entry = FindEntry(&key); |
| + if (entry == kNotFound) return GetHeap()->undefined_value(); |
| + return get(EntryToIndex(entry) + 1); |
| +} |
| + |
| + |
| +MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps, |
| + int code_flags, |
| + Code* code) { |
| + PolymorphicCodeCacheHashTableKey key(maps, code_flags); |
| + Object* obj; |
| + { MaybeObject* maybe_obj = EnsureCapacity(1, &key); |
| + if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| + } |
| + PolymorphicCodeCacheHashTable* cache = |
| + reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj); |
| + int entry = cache->FindInsertionEntry(key.Hash()); |
| + { MaybeObject* maybe_obj = key.AsObject(); |
| + if (!maybe_obj->ToObject(&obj)) return maybe_obj; |
| + } |
| + cache->set(EntryToIndex(entry), obj); |
| + cache->set(EntryToIndex(entry) + 1, code); |
| + cache->ElementAdded(); |
| + return cache; |
| +} |
| + |
| + |
| MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) { |
| ASSERT(!array->HasExternalArrayElements()); |
| switch (array->GetElementsKind()) { |
| @@ -5768,6 +5885,39 @@ void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) { |
| } |
| +int Map::Hash() { |
| + // For performance reasons we only hash the 3 most variable fields of a map: |
| + // constructor, prototype and bit_field2. |
| + |
| + // Shift away the tag. |
| + int hash = (static_cast<uint32_t>( |
| + reinterpret_cast<uintptr_t>(constructor())) >> 2); |
| + |
| + // XOR-ing the prototype and constructor directly yields too many zero bits |
| + // when the two pointers are close (which is fairly common). |
| + // To avoid this we shift the prototype 4 bits relatively to the constructor. |
| + hash ^= (static_cast<uint32_t>( |
| + reinterpret_cast<uintptr_t>(prototype())) << 2); |
| + |
| + return hash ^ (hash >> 16) ^ bit_field2(); |
| +} |
| + |
| + |
| +bool Map::Equals(Map* other, PropertyNormalizationMode mode) { |
| + return |
| + constructor() == other->constructor() && |
| + prototype() == other->prototype() && |
| + inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ? |
| + 0 : |
| + other->inobject_properties()) && |
| + instance_type() == other->instance_type() && |
| + bit_field() == other->bit_field() && |
| + bit_field2() == other->bit_field2() && |
| + (bit_field3() & ~(1<<Map::kIsShared)) == |
| + (other->bit_field3() & ~(1<<Map::kIsShared)); |
| +} |
| + |
| + |
| void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) { |
| // Iterate over all fields in the body but take care in dealing with |
| // the code entry. |