Revision: 4066
Author: [email protected]
Date: Tue Mar 9 02:49:41 2010
Log: Refactor the code cache to handle large number of properties on the
global object (take 2).
A separate object type for the code cache have been added. This object has
two different code caches. The first one (default_cache) is a fixed array
organized in the same way as the as the code cache was before. The second
cache (global_access_cache) is for code stubs to access the global object.
This cache is organized as a hash table taking the property name and code
flags as the key.
The reason for separating the global access stubs into a hash table
representation is that the number of these is not bounded in the same was
as the other types.
This is a remake of r3952 (http://codereview.chromium.org/652119) which
have the additional ability to look for the index of code stubs for access
to the global object.
BUG=http://code.google.com/p/v8/issues/detail?id=613
Review URL: http://codereview.chromium.org/717001
http://code.google.com/p/v8/source/detail?r=4066
Modified:
/branches/bleeding_edge/src/heap.cc
/branches/bleeding_edge/src/heap.h
/branches/bleeding_edge/src/ic.cc
/branches/bleeding_edge/src/ic.h
/branches/bleeding_edge/src/objects-debug.cc
/branches/bleeding_edge/src/objects-inl.h
/branches/bleeding_edge/src/objects.cc
/branches/bleeding_edge/src/objects.h
=======================================
--- /branches/bleeding_edge/src/heap.cc Tue Mar 9 01:41:58 2010
+++ /branches/bleeding_edge/src/heap.cc Tue Mar 9 02:49:41 2010
@@ -1214,6 +1214,16 @@
}
return map;
}
+
+
+Object* Heap::AllocateCodeCache() {
+ Object* result = AllocateStruct(CODE_CACHE_TYPE);
+ if (result->IsFailure()) return result;
+ CodeCache* code_cache = CodeCache::cast(result);
+ code_cache->set_default_cache(empty_fixed_array());
+ code_cache->set_normal_type_cache(undefined_value());
+ return code_cache;
+}
const Heap::StringTypeTable Heap::string_type_table[] = {
=======================================
--- /branches/bleeding_edge/src/heap.h Mon Mar 8 22:38:33 2010
+++ /branches/bleeding_edge/src/heap.h Tue Mar 9 02:49:41 2010
@@ -348,6 +348,9 @@
// Allocate a map for the specified function
static Object* AllocateInitialMap(JSFunction* fun);
+ // Allocates an empty code cache.
+ static Object* AllocateCodeCache();
+
// Allocates and fully initializes a String. There are two String
// encodings: ASCII and two byte. One should choose between the three
string
// allocation functions based on the encoding of the string buffer used
to
=======================================
--- /branches/bleeding_edge/src/ic.cc Mon Mar 1 08:24:05 2010
+++ /branches/bleeding_edge/src/ic.cc Tue Mar 9 02:49:41 2010
@@ -63,7 +63,9 @@
Code* new_target,
const char* extra_info) {
if (FLAG_trace_ic) {
- State new_state = StateFrom(new_target, Heap::undefined_value());
+ State new_state = StateFrom(new_target,
+ Heap::undefined_value(),
+ Heap::undefined_value());
PrintF("[%s (%c->%c)%s", type,
TransitionMarkFromState(old_state),
TransitionMarkFromState(new_state),
@@ -132,7 +134,7 @@
}
#endif
-IC::State IC::StateFrom(Code* target, Object* receiver) {
+IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) {
IC::State state = target->ic_state();
if (state != MONOMORPHIC) return state;
@@ -148,7 +150,7 @@
// the receiver map's code cache. Therefore, if the current target
// is in the receiver map's code cache, the inline cache failed due
// to prototype check failure.
- int index = map->IndexInCodeCache(target);
+ int index = map->IndexInCodeCache(String::cast(name), target);
if (index >= 0) {
// For keyed load/store, the most likely cause of cache failure is
// that the key has changed. We do not distinguish between
@@ -160,7 +162,7 @@
// Remove the target from the code cache to avoid hitting the same
// invalid stub again.
- map->RemoveFromCodeCache(index);
+ map->RemoveFromCodeCache(String::cast(name), target, index);
return MONOMORPHIC_PROTOTYPE_FAILURE;
}
@@ -1300,7 +1302,7 @@
NoHandleAllocation na;
ASSERT(args.length() == 2);
CallIC ic;
- IC::State state = IC::StateFrom(ic.target(), args[0]);
+ IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
Object* result =
ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1));
@@ -1333,7 +1335,7 @@
NoHandleAllocation na;
ASSERT(args.length() == 2);
LoadIC ic;
- IC::State state = IC::StateFrom(ic.target(), args[0]);
+ IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
return ic.Load(state, args.at<Object>(0), args.at<String>(1));
}
@@ -1343,7 +1345,7 @@
NoHandleAllocation na;
ASSERT(args.length() == 2);
KeyedLoadIC ic;
- IC::State state = IC::StateFrom(ic.target(), args[0]);
+ IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
return ic.Load(state, args.at<Object>(0), args.at<Object>(1));
}
@@ -1353,7 +1355,7 @@
NoHandleAllocation na;
ASSERT(args.length() == 3);
StoreIC ic;
- IC::State state = IC::StateFrom(ic.target(), args[0]);
+ IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
return ic.Store(state, args.at<Object>(0), args.at<String>(1),
args.at<Object>(2));
}
@@ -1411,7 +1413,7 @@
NoHandleAllocation na;
ASSERT(args.length() == 3);
KeyedStoreIC ic;
- IC::State state = IC::StateFrom(ic.target(), args[0]);
+ IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
return ic.Store(state, args.at<Object>(0), args.at<Object>(1),
args.at<Object>(2));
}
=======================================
--- /branches/bleeding_edge/src/ic.h Mon Mar 1 08:24:05 2010
+++ /branches/bleeding_edge/src/ic.h Tue Mar 9 02:49:41 2010
@@ -94,8 +94,8 @@
Code* target() { return GetTargetAtAddress(address()); }
inline Address address();
- // Compute the current IC state based on the target stub and the
receiver.
- static State StateFrom(Code* target, Object* receiver);
+ // Compute the current IC state based on the target stub, receiver and
name.
+ static State StateFrom(Code* target, Object* receiver, Object* name);
// Clear the inline cache to initial state.
static void Clear(Address address);
=======================================
--- /branches/bleeding_edge/src/objects-debug.cc Thu Feb 25 07:43:27 2010
+++ /branches/bleeding_edge/src/objects-debug.cc Tue Mar 9 02:49:41 2010
@@ -642,6 +642,24 @@
VerifyHeapPointer(prototype());
VerifyHeapPointer(instance_descriptors());
}
+
+
+void CodeCache::CodeCachePrint() {
+ HeapObject::PrintHeader("CodeCache");
+ PrintF("\n - default_cache: ");
+ default_cache()->ShortPrint();
+ PrintF("\n - normal_type_cache: ");
+ normal_type_cache()->ShortPrint();
+}
+
+
+void CodeCache::CodeCacheVerify() {
+ VerifyHeapPointer(default_cache());
+ VerifyHeapPointer(normal_type_cache());
+ ASSERT(default_cache()->IsFixedArray());
+ ASSERT(normal_type_cache()->IsUndefined()
+ || normal_type_cache()->IsCodeCacheHashTable());
+}
void FixedArray::FixedArrayPrint() {
=======================================
--- /branches/bleeding_edge/src/objects-inl.h Mon Mar 1 08:24:05 2010
+++ /branches/bleeding_edge/src/objects-inl.h Tue Mar 9 02:49:41 2010
@@ -562,6 +562,11 @@
bool Object::IsCompilationCacheTable() {
return IsHashTable();
}
+
+
+bool Object::IsCodeCacheHashTable() {
+ return IsHashTable();
+}
bool Object::IsMapCache() {
@@ -1568,6 +1573,7 @@
CAST_ACCESSOR(DescriptorArray)
CAST_ACCESSOR(SymbolTable)
CAST_ACCESSOR(CompilationCacheTable)
+CAST_ACCESSOR(CodeCacheHashTable)
CAST_ACCESSOR(MapCache)
CAST_ACCESSOR(String)
CAST_ACCESSOR(SeqString)
@@ -2258,7 +2264,7 @@
ACCESSORS(Map, instance_descriptors, DescriptorArray,
kInstanceDescriptorsOffset)
-ACCESSORS(Map, code_cache, FixedArray, kCodeCacheOffset)
+ACCESSORS(Map, code_cache, Object, kCodeCacheOffset)
ACCESSORS(Map, constructor, Object, kConstructorOffset)
ACCESSORS(JSFunction, shared, SharedFunctionInfo,
kSharedFunctionInfoOffset)
@@ -2396,6 +2402,9 @@
kThisPropertyAssignmentsCountOffset)
+ACCESSORS(CodeCache, default_cache, FixedArray, kDefaultCacheOffset)
+ACCESSORS(CodeCache, normal_type_cache, Object, kNormalTypeCacheOffset)
+
bool Script::HasValidSource() {
Object* src = this->source();
if (!src->IsString()) return true;
=======================================
--- /branches/bleeding_edge/src/objects.cc Thu Mar 4 03:27:28 2010
+++ /branches/bleeding_edge/src/objects.cc Tue Mar 9 02:49:41 2010
@@ -3033,19 +3033,79 @@
Object* Map::UpdateCodeCache(String* name, Code* code) {
+ // Allocate the code cache if not present.
+ if (code_cache()->IsFixedArray()) {
+ Object* result = Heap::AllocateCodeCache();
+ if (result->IsFailure()) return result;
+ set_code_cache(result);
+ }
+
+ // Update the code cache.
+ return CodeCache::cast(code_cache())->Update(name, code);
+}
+
+
+Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
+ // Do a lookup if a code cache exists.
+ if (!code_cache()->IsFixedArray()) {
+ return CodeCache::cast(code_cache())->Lookup(name, flags);
+ } else {
+ return Heap::undefined_value();
+ }
+}
+
+
+int Map::IndexInCodeCache(String* name, Code* code) {
+ // Get the internal index if a code cache exists.
+ if (!code_cache()->IsFixedArray()) {
+ return CodeCache::cast(code_cache())->GetIndex(name, code);
+ }
+ return -1;
+}
+
+
+void Map::RemoveFromCodeCache(String* name, Code* code, int index) {
+ // No GC is supposed to happen between a call to IndexInCodeCache and
+ // RemoveFromCodeCache so the code cache must be there.
+ ASSERT(!code_cache()->IsFixedArray());
+ CodeCache::cast(code_cache())->RemoveByIndex(name, code, index);
+}
+
+
+Object* CodeCache::Update(String* name, Code* code) {
ASSERT(code->ic_state() == MONOMORPHIC);
- FixedArray* cache = code_cache();
-
- // When updating the code cache we disregard the type encoded in the
+
+ // The number of monomorphic stubs for normal load/store/call IC's can
grow to
+ // a large number and therefore they need to go into a hash table. They
are
+ // used to load global properties from cells.
+ if (code->type() == NORMAL) {
+ // Make sure that a hash table is allocated for the normal load code
cache.
+ if (normal_type_cache()->IsUndefined()) {
+ Object* result =
+ CodeCacheHashTable::Allocate(CodeCacheHashTable::kInitialSize);
+ if (result->IsFailure()) return result;
+ set_normal_type_cache(result);
+ }
+ return UpdateNormalTypeCache(name, code);
+ } else {
+ ASSERT(default_cache()->IsFixedArray());
+ return UpdateDefaultCache(name, code);
+ }
+}
+
+
+Object* CodeCache::UpdateDefaultCache(String* name, Code* code) {
+ // When updating the default code cache we disregard the type encoded in
the
// flags. This allows call constant stubs to overwrite call field
// stubs, etc.
Code::Flags flags = Code::RemoveTypeFromFlags(code->flags());
// First check whether we can update existing code cache without
// extending it.
+ FixedArray* cache = default_cache();
int length = cache->length();
int deleted_index = -1;
- for (int i = 0; i < length; i += 2) {
+ for (int i = 0; i < length; i += kCodeCacheEntrySize) {
Object* key = cache->get(i);
if (key->IsNull()) {
if (deleted_index < 0) deleted_index = i;
@@ -3053,14 +3113,15 @@
}
if (key->IsUndefined()) {
if (deleted_index >= 0) i = deleted_index;
- cache->set(i + 0, name);
- cache->set(i + 1, code);
+ cache->set(i + kCodeCacheEntryNameOffset, name);
+ cache->set(i + kCodeCacheEntryCodeOffset, code);
return this;
}
if (name->Equals(String::cast(key))) {
- Code::Flags found = Code::cast(cache->get(i + 1))->flags();
+ Code::Flags found =
+ Code::cast(cache->get(i + kCodeCacheEntryCodeOffset))->flags();
if (Code::RemoveTypeFromFlags(found) == flags) {
- cache->set(i + 1, code);
+ cache->set(i + kCodeCacheEntryCodeOffset, code);
return this;
}
}
@@ -3069,61 +3130,207 @@
// Reached the end of the code cache. If there were deleted
// elements, reuse the space for the first of them.
if (deleted_index >= 0) {
- cache->set(deleted_index + 0, name);
- cache->set(deleted_index + 1, code);
+ cache->set(deleted_index + kCodeCacheEntryNameOffset, name);
+ cache->set(deleted_index + kCodeCacheEntryCodeOffset, code);
return this;
}
- // Extend the code cache with some new entries (at least one).
- int new_length = length + ((length >> 1) & ~1) + 2;
- ASSERT((new_length & 1) == 0); // must be a multiple of two
+ // Extend the code cache with some new entries (at least one). Must be a
+ // multiple of the entry size.
+ int new_length = length + ((length >> 1)) + kCodeCacheEntrySize;
+ new_length = new_length - new_length % kCodeCacheEntrySize;
+ ASSERT((new_length % kCodeCacheEntrySize) == 0);
Object* result = cache->CopySize(new_length);
if (result->IsFailure()) return result;
// Add the (name, code) pair to the new cache.
cache = FixedArray::cast(result);
- cache->set(length + 0, name);
- cache->set(length + 1, code);
- set_code_cache(cache);
+ cache->set(length + kCodeCacheEntryNameOffset, name);
+ cache->set(length + kCodeCacheEntryCodeOffset, code);
+ set_default_cache(cache);
return this;
}
-Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
- FixedArray* cache = code_cache();
+Object* CodeCache::UpdateNormalTypeCache(String* name, Code* code) {
+ // Adding a new entry can cause a new cache to be allocated.
+ CodeCacheHashTable* cache =
CodeCacheHashTable::cast(normal_type_cache());
+ Object* new_cache = cache->Put(name, code);
+ if (new_cache->IsFailure()) return new_cache;
+ set_normal_type_cache(new_cache);
+ return this;
+}
+
+
+Object* CodeCache::Lookup(String* name, Code::Flags flags) {
+ if (Code::ExtractTypeFromFlags(flags) == NORMAL) {
+ return LookupNormalTypeCache(name, flags);
+ } else {
+ return LookupDefaultCache(name, flags);
+ }
+}
+
+
+Object* CodeCache::LookupDefaultCache(String* name, Code::Flags flags) {
+ FixedArray* cache = default_cache();
int length = cache->length();
- for (int i = 0; i < length; i += 2) {
- Object* key = cache->get(i);
+ for (int i = 0; i < length; i += kCodeCacheEntrySize) {
+ Object* key = cache->get(i + kCodeCacheEntryNameOffset);
// Skip deleted elements.
if (key->IsNull()) continue;
if (key->IsUndefined()) return key;
if (name->Equals(String::cast(key))) {
- Code* code = Code::cast(cache->get(i + 1));
- if (code->flags() == flags) return code;
+ Code* code = Code::cast(cache->get(i + kCodeCacheEntryCodeOffset));
+ if (code->flags() == flags) {
+ return code;
+ }
}
}
return Heap::undefined_value();
}
-int Map::IndexInCodeCache(Code* code) {
- FixedArray* array = code_cache();
+Object* CodeCache::LookupNormalTypeCache(String* name, Code::Flags flags) {
+ if (!normal_type_cache()->IsUndefined()) {
+ CodeCacheHashTable* cache =
CodeCacheHashTable::cast(normal_type_cache());
+ return cache->Lookup(name, flags);
+ } else {
+ return Heap::undefined_value();
+ }
+}
+
+
+int CodeCache::GetIndex(String* name, Code* code) {
+ // This is not used for normal load/store/call IC's.
+ if (code->type() == NORMAL) {
+ if (normal_type_cache()->IsUndefined()) return -1;
+ CodeCacheHashTable* cache =
CodeCacheHashTable::cast(normal_type_cache());
+ return cache->GetIndex(name, code->flags());
+ }
+
+ FixedArray* array = default_cache();
int len = array->length();
- for (int i = 0; i < len; i += 2) {
- if (array->get(i + 1) == code) return i + 1;
+ for (int i = 0; i < len; i += kCodeCacheEntrySize) {
+ if (array->get(i + kCodeCacheEntryCodeOffset) == code) return i + 1;
}
return -1;
}
-void Map::RemoveFromCodeCache(int index) {
- FixedArray* array = code_cache();
- ASSERT(array->length() >= index && array->get(index)->IsCode());
- // Use null instead of undefined for deleted elements to distinguish
- // deleted elements from unused elements. This distinction is used
- // when looking up in the cache and when updating the cache.
- array->set_null(index - 1); // key
- array->set_null(index); // code
+void CodeCache::RemoveByIndex(String* name, Code* code, int index) {
+ if (code->type() == NORMAL) {
+ ASSERT(!normal_type_cache()->IsUndefined());
+ CodeCacheHashTable* cache =
CodeCacheHashTable::cast(normal_type_cache());
+ ASSERT(cache->GetIndex(name, code->flags()) == index);
+ cache->RemoveByIndex(index);
+ } else {
+ FixedArray* array = default_cache();
+ ASSERT(array->length() >= index && array->get(index)->IsCode());
+ // Use null instead of undefined for deleted elements to distinguish
+ // deleted elements from unused elements. This distinction is used
+ // when looking up in the cache and when updating the cache.
+ ASSERT_EQ(1, kCodeCacheEntryCodeOffset - kCodeCacheEntryNameOffset);
+ array->set_null(index - 1); // Name.
+ array->set_null(index); // Code.
+ }
+}
+
+
+// The key in the code cache hash table consists of the property name and
the
+// code object. The actual match is on the name and the code flags. If a
key
+// is created using the flags and not a code object it can only be used for
+// lookup not to create a new entry.
+class CodeCacheHashTableKey : public HashTableKey {
+ public:
+ CodeCacheHashTableKey(String* name, Code::Flags flags)
+ : name_(name), flags_(flags), code_(NULL) { }
+
+ CodeCacheHashTableKey(String* name, Code* code)
+ : name_(name),
+ flags_(code->flags()),
+ code_(code) { }
+
+
+ bool IsMatch(Object* other) {
+ if (!other->IsFixedArray()) return false;
+ FixedArray* pair = FixedArray::cast(other);
+ String* name = String::cast(pair->get(0));
+ Code::Flags flags = Code::cast(pair->get(1))->flags();
+ if (flags != flags_) {
+ return false;
+ }
+ return name_->Equals(name);
+ }
+
+ static uint32_t NameFlagsHashHelper(String* name, Code::Flags flags) {
+ return name->Hash() ^ flags;
+ }
+
+ uint32_t Hash() { return NameFlagsHashHelper(name_, flags_); }
+
+ uint32_t HashForObject(Object* obj) {
+ FixedArray* pair = FixedArray::cast(obj);
+ String* name = String::cast(pair->get(0));
+ Code* code = Code::cast(pair->get(1));
+ return NameFlagsHashHelper(name, code->flags());
+ }
+
+ Object* AsObject() {
+ ASSERT(code_ != NULL);
+ Object* obj = Heap::AllocateFixedArray(2);
+ if (obj->IsFailure()) return obj;
+ FixedArray* pair = FixedArray::cast(obj);
+ pair->set(0, name_);
+ pair->set(1, code_);
+ return pair;
+ }
+
+ private:
+ String* name_;
+ Code::Flags flags_;
+ Code* code_;
+};
+
+
+Object* CodeCacheHashTable::Lookup(String* name, Code::Flags flags) {
+ CodeCacheHashTableKey key(name, flags);
+ int entry = FindEntry(&key);
+ if (entry == kNotFound) return Heap::undefined_value();
+ return get(EntryToIndex(entry) + 1);
+}
+
+
+Object* CodeCacheHashTable::Put(String* name, Code* code) {
+ CodeCacheHashTableKey key(name, code);
+ Object* obj = EnsureCapacity(1, &key);
+ if (obj->IsFailure()) return obj;
+
+ // Don't use this, as the table might have grown.
+ CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
+
+ int entry = cache->FindInsertionEntry(key.Hash());
+ Object* k = key.AsObject();
+ if (k->IsFailure()) return k;
+
+ cache->set(EntryToIndex(entry), k);
+ cache->set(EntryToIndex(entry) + 1, code);
+ cache->ElementAdded();
+ return cache;
+}
+
+
+int CodeCacheHashTable::GetIndex(String* name, Code::Flags flags) {
+ CodeCacheHashTableKey key(name, flags);
+ int entry = FindEntry(&key);
+ return (entry == kNotFound) ? -1 : entry;
+}
+
+
+void CodeCacheHashTable::RemoveByIndex(int index) {
+ ASSERT(index >= 0);
+ set(EntryToIndex(index), Heap::null_value());
+ set(EntryToIndex(index) + 1, Heap::null_value());
+ ElementRemoved();
}
@@ -6992,7 +7199,6 @@
table->SetNumberOfDeletedElements(0);
return table;
}
-
template<typename Shape, typename Key>
=======================================
--- /branches/bleeding_edge/src/objects.h Mon Mar 8 03:58:33 2010
+++ /branches/bleeding_edge/src/objects.h Tue Mar 9 02:49:41 2010
@@ -72,6 +72,7 @@
// - Dictionary
// - SymbolTable
// - CompilationCacheTable
+// - CodeCacheHashTable
// - MapCache
// - Context
// - GlobalContext
@@ -102,6 +103,7 @@
// - TypeSwitchInfo
// - DebugInfo
// - BreakPointInfo
+// - CodeCache
//
// Formats of Object*:
// Smi: [31 bit signed int] 0
@@ -269,6 +271,7 @@
V(SIGNATURE_INFO_TYPE)
\
V(TYPE_SWITCH_INFO_TYPE)
\
V(SCRIPT_TYPE)
\
+
V(CODE_CACHE_TYPE)
\
\
V(JS_VALUE_TYPE)
\
V(JS_OBJECT_TYPE)
\
@@ -364,7 +367,8 @@
V(OBJECT_TEMPLATE_INFO, ObjectTemplateInfo,
object_template_info) \
V(SIGNATURE_INFO, SignatureInfo,
signature_info) \
V(TYPE_SWITCH_INFO, TypeSwitchInfo,
type_switch_info) \
- V(SCRIPT, Script, script)
+ V(SCRIPT, Script,
script) \
+ V(CODE_CACHE, CodeCache, code_cache)
#ifdef ENABLE_DEBUGGER_SUPPORT
#define
STRUCT_LIST_DEBUGGER(V) \
@@ -468,6 +472,7 @@
SIGNATURE_INFO_TYPE,
TYPE_SWITCH_INFO_TYPE,
SCRIPT_TYPE,
+ CODE_CACHE_TYPE,
#ifdef ENABLE_DEBUGGER_SUPPORT
DEBUG_INFO_TYPE,
BREAK_POINT_INFO_TYPE,
@@ -601,6 +606,7 @@
inline bool IsDictionary();
inline bool IsSymbolTable();
inline bool IsCompilationCacheTable();
+ inline bool IsCodeCacheHashTable();
inline bool IsMapCache();
inline bool IsPrimitive();
inline bool IsGlobalObject();
@@ -2929,7 +2935,7 @@
DECL_ACCESSORS(instance_descriptors, DescriptorArray)
// [stub cache]: contains stubs compiled for this map.
- DECL_ACCESSORS(code_cache, FixedArray)
+ DECL_ACCESSORS(code_cache, Object)
Object* CopyDropDescriptors();
@@ -2965,10 +2971,10 @@
// Returns the non-negative index of the code object if it is in the
// cache and -1 otherwise.
- int IndexInCodeCache(Code* code);
+ int IndexInCodeCache(String* name, Code* code);
// Removes a code object from the code cache at the given index.
- void RemoveFromCodeCache(int index);
+ void RemoveFromCodeCache(String* name, Code* code, int index);
// For every transition in this map, makes the transition's
// target's prototype pointer point back to this map.
@@ -3033,6 +3039,11 @@
static const int kNeedsLoading = 0;
static const int kIsExtensible = 1;
+ // Layout of the default cache. It holds alternating name and code
objects.
+ static const int kCodeCacheEntrySize = 2;
+ static const int kCodeCacheEntryNameOffset = 0;
+ static const int kCodeCacheEntryCodeOffset = 1;
+
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Map);
};
@@ -3716,6 +3727,97 @@
};
+class CodeCache: public Struct {
+ public:
+ DECL_ACCESSORS(default_cache, FixedArray)
+ DECL_ACCESSORS(normal_type_cache, Object)
+
+ // Add the code object to the cache.
+ Object* Update(String* name, Code* code);
+
+ // Lookup code object in the cache. Returns code object if found and
undefined
+ // if not.
+ Object* Lookup(String* name, Code::Flags flags);
+
+ // Get the internal index of a code object in the cache. Returns -1 if
the
+ // code object is not in that cache. This index can be used to later call
+ // RemoveByIndex. The cache cannot be modified between a call to
GetIndex and
+ // RemoveByIndex.
+ int GetIndex(String* name, Code* code);
+
+ // Remove an object from the cache with the provided internal index.
+ void RemoveByIndex(String* name, Code* code, int index);
+
+ static inline CodeCache* cast(Object* obj);
+
+#ifdef DEBUG
+ void CodeCachePrint();
+ void CodeCacheVerify();
+#endif
+
+ static const int kDefaultCacheOffset = HeapObject::kHeaderSize;
+ static const int kNormalTypeCacheOffset =
+ kDefaultCacheOffset + kPointerSize;
+ static const int kSize = kNormalTypeCacheOffset + kPointerSize;
+
+ private:
+ Object* UpdateDefaultCache(String* name, Code* code);
+ Object* UpdateNormalTypeCache(String* name, Code* code);
+ Object* LookupDefaultCache(String* name, Code::Flags flags);
+ Object* LookupNormalTypeCache(String* name, Code::Flags flags);
+
+ // Code cache layout of the default cache. Elements are alternating name
and
+ // code objects for non normal load/store/call IC's.
+ static const int kCodeCacheEntrySize = 2;
+ static const int kCodeCacheEntryNameOffset = 0;
+ static const int kCodeCacheEntryCodeOffset = 1;
+
+ DISALLOW_IMPLICIT_CONSTRUCTORS(CodeCache);
+};
+
+
+class CodeCacheHashTableShape {
+ public:
+ static inline bool IsMatch(HashTableKey* key, Object* value) {
+ return key->IsMatch(value);
+ }
+
+ static inline uint32_t Hash(HashTableKey* key) {
+ return key->Hash();
+ }
+
+ static inline uint32_t HashForObject(HashTableKey* key, Object* object) {
+ return key->HashForObject(object);
+ }
+
+ static Object* AsObject(HashTableKey* key) {
+ return key->AsObject();
+ }
+
+ static const int kPrefixSize = 0;
+ static const int kEntrySize = 2;
+};
+
+
+class CodeCacheHashTable: public HashTable<CodeCacheHashTableShape,
+ HashTableKey*> {
+ public:
+ Object* Lookup(String* name, Code::Flags flags);
+ Object* Put(String* name, Code* code);
+
+ int GetIndex(String* name, Code::Flags flags);
+ void RemoveByIndex(int index);
+
+ static inline CodeCacheHashTable* cast(Object* obj);
+
+ // Initial size of the fixed array backing the hash table.
+ static const int kInitialSize = 64;
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(CodeCacheHashTable);
+};
+
+
enum AllowNullsFlag {ALLOW_NULLS, DISALLOW_NULLS};
enum RobustnessFlag {ROBUST_STRING_TRAVERSAL, FAST_STRING_TRAVERSAL};
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev