}
-Object* Heap::GetKeyedLookupCache() {
- if (keyed_lookup_cache()->IsUndefined()) {
- Object* obj = LookupCache::Allocate(4);
- if (obj->IsFailure()) return obj;
- keyed_lookup_cache_ = obj;
- }
- return keyed_lookup_cache();
-}
-
-
-void Heap::SetKeyedLookupCache(LookupCache* cache) {
- keyed_lookup_cache_ = cache;
-}
-
-
-void Heap::ClearKeyedLookupCache() {
- keyed_lookup_cache_ = undefined_value();
-}
-
-
void Heap::SetLastScriptId(Object* last_script_id) {
last_script_id_ = last_script_id;
}
void Heap::MarkCompactPrologue(bool is_compacting) {
// At any old GC clear the keyed lookup cache to enable collection of unused
// maps.
- ClearKeyedLookupCache();
+ KeyedLookupCache::Clear();
CompilationCache::MarkCompactPrologue();
last_script_id_ = undefined_value();
// Initialize keyed lookup cache.
- ClearKeyedLookupCache();
+ KeyedLookupCache::Clear();
// Initialize compilation cache.
CompilationCache::Clear();
}
+int KeyedLookupCache::Hash(Map* map, String* name) {
+ // Uses only lower 32 bits if pointers are larger.
+ uintptr_t addr_hash =
+ static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map)) >> 2;
+ return (addr_hash ^ name->Hash()) % kLength;
+}
+
+
+int KeyedLookupCache::Lookup(Map* map, String* name) {
+ int index = Hash(map, name);
+ Key& key = keys_[index];
+ if ((key.map == map) && key.name->Equals(name)) {
+ return field_offsets_[index];
+ }
+ return -1;
+}
+
+
+void KeyedLookupCache::Update(Map* map, String* name, int field_offset) {
+ String* symbol;
+ if (Heap::LookupSymbolIfExists(name, &symbol)) {
+ int index = Hash(map, symbol);
+ Key& key = keys_[index];
+ key.map = map;
+ key.name = symbol;
+ field_offsets_[index] = field_offset;
+ }
+}
+
+
+void KeyedLookupCache::Clear() {
+ for (int index = 0; index < kLength; index++) keys_[index].map = NULL;
+}
+
+KeyedLookupCache::Key KeyedLookupCache::keys_[KeyedLookupCache::kLength];
+
+int KeyedLookupCache::field_offsets_[KeyedLookupCache::kLength];
+
+
#ifdef DEBUG
bool Heap::GarbageCollectionGreedyCheck() {
ASSERT(FLAG_gc_greedy);
V(FixedArray, number_string_cache) \
V(FixedArray, single_character_string_cache) \
V(FixedArray, natives_source_cache) \
- V(Object, keyed_lookup_cache) \
V(Object, last_script_id)
non_monomorphic_cache_ = value;
}
- // Gets, sets and clears the lookup cache used for keyed access.
- static inline Object* GetKeyedLookupCache();
- static inline void SetKeyedLookupCache(LookupCache* cache);
- static inline void ClearKeyedLookupCache();
-
// Update the next script id.
static inline void SetLastScriptId(Object* last_script_id);
};
+// Cache for mapping (map, property name) into field offset.
+// Cleared at startup and prior to mark sweep collection.
+class KeyedLookupCache {
+ public:
+ // Lookup field offset for (map, name). If absent, -1 is returned.
+ static int Lookup(Map* map, String* name);
+
+ // Update an element in the cache.
+ static void Update(Map* map, String* name, int field_offset);
+
+ // Clear the cache.
+ static void Clear();
+ private:
+ inline static int Hash(Map* map, String* name);
+ static const int kLength = 128;
+ struct Key {
+ Map* map;
+ String* name;
+ };
+ static Key keys_[kLength];
+ static int field_offsets_[kLength];
+};
+
+
// ----------------------------------------------------------------------------
// Marking stack for tracing live objects.
}
-bool Object::IsLookupCache() {
- return IsHashTable();
-}
-
-
bool Object::IsPrimitive() {
return IsOddball() || IsNumber() || IsString();
}
CAST_ACCESSOR(SymbolTable)
CAST_ACCESSOR(CompilationCacheTable)
CAST_ACCESSOR(MapCache)
-CAST_ACCESSOR(LookupCache)
CAST_ACCESSOR(String)
CAST_ACCESSOR(SeqString)
CAST_ACCESSOR(SeqAsciiString)
};
-// MapNameKeys are used as keys in lookup caches.
-class MapNameKey : public HashTableKey {
- public:
- MapNameKey(Map* map, String* name)
- : map_(map), name_(name) { }
-
- bool IsMatch(Object* other) {
- if (!other->IsFixedArray()) return false;
- FixedArray* pair = FixedArray::cast(other);
- Map* map = Map::cast(pair->get(0));
- if (map != map_) return false;
- String* name = String::cast(pair->get(1));
- return name->Equals(name_);
- }
-
- typedef uint32_t (*HashFunction)(Object* obj);
-
- virtual HashFunction GetHashFunction() { return MapNameHash; }
-
- static uint32_t MapNameHashHelper(Map* map, String* name) {
- // Uses only lower 32 bits if pointers are larger.
- uintptr_t addr_hash =
- static_cast<uint32_t>(reinterpret_cast<uintptr_t>(map));
- return addr_hash ^ name->Hash();
- }
-
- static uint32_t MapNameHash(Object* obj) {
- FixedArray* pair = FixedArray::cast(obj);
- Map* map = Map::cast(pair->get(0));
- String* name = String::cast(pair->get(1));
- return MapNameHashHelper(map, name);
- }
-
- virtual uint32_t Hash() {
- return MapNameHashHelper(map_, name_);
- }
-
- virtual Object* GetObject() {
- Object* obj = Heap::AllocateFixedArray(2);
- if (obj->IsFailure()) return obj;
- FixedArray* pair = FixedArray::cast(obj);
- pair->set(0, map_);
- pair->set(1, name_);
- return pair;
- }
-
- virtual bool IsStringKey() { return false; }
-
- private:
- Map* map_;
- String* name_;
-};
-
-
Object* MapCache::Lookup(FixedArray* array) {
SymbolsKey key(array);
int entry = FindEntry(&key);
}
-int LookupCache::Lookup(Map* map, String* name) {
- MapNameKey key(map, name);
- int entry = FindEntry(&key);
- if (entry == -1) return kNotFound;
- return Smi::cast(get(EntryToIndex(entry) + 1))->value();
-}
-
-
-Object* LookupCache::Put(Map* map, String* name, int value) {
- MapNameKey key(map, name);
- Object* obj = EnsureCapacity(1, &key);
- if (obj->IsFailure()) return obj;
- Object* k = key.GetObject();
- if (k->IsFailure()) return k;
-
- LookupCache* cache = reinterpret_cast<LookupCache*>(obj);
- int entry = cache->FindInsertionEntry(k, key.Hash());
- int index = EntryToIndex(entry);
- cache->set(index, k);
- cache->set(index + 1, Smi::FromInt(value), SKIP_WRITE_BARRIER);
- cache->ElementAdded();
- return cache;
-}
-
-
Object* Dictionary::Allocate(int at_least_space_for) {
Object* obj = DictionaryBase::Allocate(at_least_space_for);
// Initialize the next enumeration index.
// - SymbolTable
// - CompilationCacheTable
// - MapCache
-// - LookupCache
// - Context
// - GlobalContext
// - String
inline bool IsSymbolTable();
inline bool IsCompilationCacheTable();
inline bool IsMapCache();
- inline bool IsLookupCache();
inline bool IsPrimitive();
inline bool IsGlobalObject();
inline bool IsJSGlobalObject();
};
-// LookupCache.
-//
-// Maps a key consisting of a map and a name to an index within a
-// fast-case properties array.
-//
-// LookupCaches are used to avoid repeatedly searching instance
-// descriptors.
-class LookupCache: public HashTable<0, 2> {
- public:
- int Lookup(Map* map, String* name);
- Object* Put(Map* map, String* name, int offset);
- static inline LookupCache* cast(Object* obj);
-
- // Constant returned by Lookup when the key was not found.
- static const int kNotFound = -1;
-
- private:
- DISALLOW_IMPLICIT_CONSTRUCTORS(LookupCache);
-};
-
-
// Dictionary for keeping properties and elements in slow case.
//
// One element in the prefix is used for storing non-element
String* key = String::cast(args[1]);
if (receiver->HasFastProperties()) {
// Attempt to use lookup cache.
- Object* obj = Heap::GetKeyedLookupCache();
- if (obj->IsFailure()) return obj;
- LookupCache* cache = LookupCache::cast(obj);
Map* receiver_map = receiver->map();
- int offset = cache->Lookup(receiver_map, key);
- if (offset != LookupCache::kNotFound) {
+ int offset = KeyedLookupCache::Lookup(receiver_map, key);
+ if (offset != -1) {
Object* value = receiver->FastPropertyAt(offset);
return value->IsTheHole() ? Heap::undefined_value() : value;
}
receiver->LocalLookup(key, &result);
if (result.IsProperty() && result.IsLoaded() && result.type() == FIELD) {
int offset = result.GetFieldIndex();
- Object* obj = cache->Put(receiver_map, key, offset);
- if (obj->IsFailure()) return obj;
- Heap::SetKeyedLookupCache(LookupCache::cast(obj));
+ KeyedLookupCache::Update(receiver_map, key, offset);
Object* value = receiver->FastPropertyAt(offset);
return value->IsTheHole() ? Heap::undefined_value() : value;
}