Commit 50466436 authored by sgjesse@chromium.org's avatar sgjesse@chromium.org

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4066 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 0c2885f8
...@@ -1216,6 +1216,16 @@ Object* Heap::AllocateMap(InstanceType instance_type, int instance_size) { ...@@ -1216,6 +1216,16 @@ Object* Heap::AllocateMap(InstanceType instance_type, int instance_size) {
} }
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[] = { const Heap::StringTypeTable Heap::string_type_table[] = {
#define STRING_TYPE_ELEMENT(type, size, name, camel_name) \ #define STRING_TYPE_ELEMENT(type, size, name, camel_name) \
{type, size, k##camel_name##MapRootIndex}, {type, size, k##camel_name##MapRootIndex},
......
...@@ -348,6 +348,9 @@ class Heap : public AllStatic { ...@@ -348,6 +348,9 @@ class Heap : public AllStatic {
// Allocate a map for the specified function // Allocate a map for the specified function
static Object* AllocateInitialMap(JSFunction* fun); static Object* AllocateInitialMap(JSFunction* fun);
// Allocates an empty code cache.
static Object* AllocateCodeCache();
// Allocates and fully initializes a String. There are two String // Allocates and fully initializes a String. There are two String
// encodings: ASCII and two byte. One should choose between the three 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 // allocation functions based on the encoding of the string buffer used to
......
...@@ -63,7 +63,9 @@ void IC::TraceIC(const char* type, ...@@ -63,7 +63,9 @@ void IC::TraceIC(const char* type,
Code* new_target, Code* new_target,
const char* extra_info) { const char* extra_info) {
if (FLAG_trace_ic) { 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, PrintF("[%s (%c->%c)%s", type,
TransitionMarkFromState(old_state), TransitionMarkFromState(old_state),
TransitionMarkFromState(new_state), TransitionMarkFromState(new_state),
...@@ -132,7 +134,7 @@ Address IC::OriginalCodeAddress() { ...@@ -132,7 +134,7 @@ Address IC::OriginalCodeAddress() {
} }
#endif #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(); IC::State state = target->ic_state();
if (state != MONOMORPHIC) return state; if (state != MONOMORPHIC) return state;
...@@ -148,7 +150,7 @@ IC::State IC::StateFrom(Code* target, Object* receiver) { ...@@ -148,7 +150,7 @@ IC::State IC::StateFrom(Code* target, Object* receiver) {
// the receiver map's code cache. Therefore, if the current target // the receiver map's code cache. Therefore, if the current target
// is in the receiver map's code cache, the inline cache failed due // is in the receiver map's code cache, the inline cache failed due
// to prototype check failure. // to prototype check failure.
int index = map->IndexInCodeCache(target); int index = map->IndexInCodeCache(String::cast(name), target);
if (index >= 0) { if (index >= 0) {
// For keyed load/store, the most likely cause of cache failure is // For keyed load/store, the most likely cause of cache failure is
// that the key has changed. We do not distinguish between // that the key has changed. We do not distinguish between
...@@ -160,7 +162,7 @@ IC::State IC::StateFrom(Code* target, Object* receiver) { ...@@ -160,7 +162,7 @@ IC::State IC::StateFrom(Code* target, Object* receiver) {
// Remove the target from the code cache to avoid hitting the same // Remove the target from the code cache to avoid hitting the same
// invalid stub again. // invalid stub again.
map->RemoveFromCodeCache(index); map->RemoveFromCodeCache(String::cast(name), target, index);
return MONOMORPHIC_PROTOTYPE_FAILURE; return MONOMORPHIC_PROTOTYPE_FAILURE;
} }
...@@ -1300,7 +1302,7 @@ Object* CallIC_Miss(Arguments args) { ...@@ -1300,7 +1302,7 @@ Object* CallIC_Miss(Arguments args) {
NoHandleAllocation na; NoHandleAllocation na;
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
CallIC ic; CallIC ic;
IC::State state = IC::StateFrom(ic.target(), args[0]); IC::State state = IC::StateFrom(ic.target(), args[0], args[1]);
Object* result = Object* result =
ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1)); ic.LoadFunction(state, args.at<Object>(0), args.at<String>(1));
...@@ -1333,7 +1335,7 @@ Object* LoadIC_Miss(Arguments args) { ...@@ -1333,7 +1335,7 @@ Object* LoadIC_Miss(Arguments args) {
NoHandleAllocation na; NoHandleAllocation na;
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
LoadIC ic; 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)); return ic.Load(state, args.at<Object>(0), args.at<String>(1));
} }
...@@ -1343,7 +1345,7 @@ Object* KeyedLoadIC_Miss(Arguments args) { ...@@ -1343,7 +1345,7 @@ Object* KeyedLoadIC_Miss(Arguments args) {
NoHandleAllocation na; NoHandleAllocation na;
ASSERT(args.length() == 2); ASSERT(args.length() == 2);
KeyedLoadIC ic; 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)); return ic.Load(state, args.at<Object>(0), args.at<Object>(1));
} }
...@@ -1353,7 +1355,7 @@ Object* StoreIC_Miss(Arguments args) { ...@@ -1353,7 +1355,7 @@ Object* StoreIC_Miss(Arguments args) {
NoHandleAllocation na; NoHandleAllocation na;
ASSERT(args.length() == 3); ASSERT(args.length() == 3);
StoreIC ic; 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), return ic.Store(state, args.at<Object>(0), args.at<String>(1),
args.at<Object>(2)); args.at<Object>(2));
} }
...@@ -1411,7 +1413,7 @@ Object* KeyedStoreIC_Miss(Arguments args) { ...@@ -1411,7 +1413,7 @@ Object* KeyedStoreIC_Miss(Arguments args) {
NoHandleAllocation na; NoHandleAllocation na;
ASSERT(args.length() == 3); ASSERT(args.length() == 3);
KeyedStoreIC ic; 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), return ic.Store(state, args.at<Object>(0), args.at<Object>(1),
args.at<Object>(2)); args.at<Object>(2));
} }
......
...@@ -94,8 +94,8 @@ class IC { ...@@ -94,8 +94,8 @@ class IC {
Code* target() { return GetTargetAtAddress(address()); } Code* target() { return GetTargetAtAddress(address()); }
inline Address address(); inline Address address();
// Compute the current IC state based on the target stub and the receiver. // Compute the current IC state based on the target stub, receiver and name.
static State StateFrom(Code* target, Object* receiver); static State StateFrom(Code* target, Object* receiver, Object* name);
// Clear the inline cache to initial state. // Clear the inline cache to initial state.
static void Clear(Address address); static void Clear(Address address);
......
...@@ -644,6 +644,24 @@ void Map::MapVerify() { ...@@ -644,6 +644,24 @@ void Map::MapVerify() {
} }
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() { void FixedArray::FixedArrayPrint() {
HeapObject::PrintHeader("FixedArray"); HeapObject::PrintHeader("FixedArray");
PrintF(" - length: %d", length()); PrintF(" - length: %d", length());
......
...@@ -564,6 +564,11 @@ bool Object::IsCompilationCacheTable() { ...@@ -564,6 +564,11 @@ bool Object::IsCompilationCacheTable() {
} }
bool Object::IsCodeCacheHashTable() {
return IsHashTable();
}
bool Object::IsMapCache() { bool Object::IsMapCache() {
return IsHashTable(); return IsHashTable();
} }
...@@ -1568,6 +1573,7 @@ CAST_ACCESSOR(FixedArray) ...@@ -1568,6 +1573,7 @@ CAST_ACCESSOR(FixedArray)
CAST_ACCESSOR(DescriptorArray) CAST_ACCESSOR(DescriptorArray)
CAST_ACCESSOR(SymbolTable) CAST_ACCESSOR(SymbolTable)
CAST_ACCESSOR(CompilationCacheTable) CAST_ACCESSOR(CompilationCacheTable)
CAST_ACCESSOR(CodeCacheHashTable)
CAST_ACCESSOR(MapCache) CAST_ACCESSOR(MapCache)
CAST_ACCESSOR(String) CAST_ACCESSOR(String)
CAST_ACCESSOR(SeqString) CAST_ACCESSOR(SeqString)
...@@ -2258,7 +2264,7 @@ void Map::set_prototype(Object* value, WriteBarrierMode mode) { ...@@ -2258,7 +2264,7 @@ void Map::set_prototype(Object* value, WriteBarrierMode mode) {
ACCESSORS(Map, instance_descriptors, DescriptorArray, ACCESSORS(Map, instance_descriptors, DescriptorArray,
kInstanceDescriptorsOffset) kInstanceDescriptorsOffset)
ACCESSORS(Map, code_cache, FixedArray, kCodeCacheOffset) ACCESSORS(Map, code_cache, Object, kCodeCacheOffset)
ACCESSORS(Map, constructor, Object, kConstructorOffset) ACCESSORS(Map, constructor, Object, kConstructorOffset)
ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset) ACCESSORS(JSFunction, shared, SharedFunctionInfo, kSharedFunctionInfoOffset)
...@@ -2396,6 +2402,9 @@ INT_ACCESSORS(SharedFunctionInfo, this_property_assignments_count, ...@@ -2396,6 +2402,9 @@ INT_ACCESSORS(SharedFunctionInfo, this_property_assignments_count,
kThisPropertyAssignmentsCountOffset) kThisPropertyAssignmentsCountOffset)
ACCESSORS(CodeCache, default_cache, FixedArray, kDefaultCacheOffset)
ACCESSORS(CodeCache, normal_type_cache, Object, kNormalTypeCacheOffset)
bool Script::HasValidSource() { bool Script::HasValidSource() {
Object* src = this->source(); Object* src = this->source();
if (!src->IsString()) return true; if (!src->IsString()) return true;
......
This diff is collapsed.
...@@ -72,6 +72,7 @@ ...@@ -72,6 +72,7 @@
// - Dictionary // - Dictionary
// - SymbolTable // - SymbolTable
// - CompilationCacheTable // - CompilationCacheTable
// - CodeCacheHashTable
// - MapCache // - MapCache
// - Context // - Context
// - GlobalContext // - GlobalContext
...@@ -102,6 +103,7 @@ ...@@ -102,6 +103,7 @@
// - TypeSwitchInfo // - TypeSwitchInfo
// - DebugInfo // - DebugInfo
// - BreakPointInfo // - BreakPointInfo
// - CodeCache
// //
// Formats of Object*: // Formats of Object*:
// Smi: [31 bit signed int] 0 // Smi: [31 bit signed int] 0
...@@ -269,6 +271,7 @@ enum PropertyNormalizationMode { ...@@ -269,6 +271,7 @@ enum PropertyNormalizationMode {
V(SIGNATURE_INFO_TYPE) \ V(SIGNATURE_INFO_TYPE) \
V(TYPE_SWITCH_INFO_TYPE) \ V(TYPE_SWITCH_INFO_TYPE) \
V(SCRIPT_TYPE) \ V(SCRIPT_TYPE) \
V(CODE_CACHE_TYPE) \
\ \
V(JS_VALUE_TYPE) \ V(JS_VALUE_TYPE) \
V(JS_OBJECT_TYPE) \ V(JS_OBJECT_TYPE) \
...@@ -364,7 +367,8 @@ enum PropertyNormalizationMode { ...@@ -364,7 +367,8 @@ enum PropertyNormalizationMode {
V(OBJECT_TEMPLATE_INFO, ObjectTemplateInfo, object_template_info) \ V(OBJECT_TEMPLATE_INFO, ObjectTemplateInfo, object_template_info) \
V(SIGNATURE_INFO, SignatureInfo, signature_info) \ V(SIGNATURE_INFO, SignatureInfo, signature_info) \
V(TYPE_SWITCH_INFO, TypeSwitchInfo, type_switch_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 #ifdef ENABLE_DEBUGGER_SUPPORT
#define STRUCT_LIST_DEBUGGER(V) \ #define STRUCT_LIST_DEBUGGER(V) \
...@@ -468,6 +472,7 @@ enum InstanceType { ...@@ -468,6 +472,7 @@ enum InstanceType {
SIGNATURE_INFO_TYPE, SIGNATURE_INFO_TYPE,
TYPE_SWITCH_INFO_TYPE, TYPE_SWITCH_INFO_TYPE,
SCRIPT_TYPE, SCRIPT_TYPE,
CODE_CACHE_TYPE,
#ifdef ENABLE_DEBUGGER_SUPPORT #ifdef ENABLE_DEBUGGER_SUPPORT
DEBUG_INFO_TYPE, DEBUG_INFO_TYPE,
BREAK_POINT_INFO_TYPE, BREAK_POINT_INFO_TYPE,
...@@ -601,6 +606,7 @@ class Object BASE_EMBEDDED { ...@@ -601,6 +606,7 @@ class Object BASE_EMBEDDED {
inline bool IsDictionary(); inline bool IsDictionary();
inline bool IsSymbolTable(); inline bool IsSymbolTable();
inline bool IsCompilationCacheTable(); inline bool IsCompilationCacheTable();
inline bool IsCodeCacheHashTable();
inline bool IsMapCache(); inline bool IsMapCache();
inline bool IsPrimitive(); inline bool IsPrimitive();
inline bool IsGlobalObject(); inline bool IsGlobalObject();
...@@ -2929,7 +2935,7 @@ class Map: public HeapObject { ...@@ -2929,7 +2935,7 @@ class Map: public HeapObject {
DECL_ACCESSORS(instance_descriptors, DescriptorArray) DECL_ACCESSORS(instance_descriptors, DescriptorArray)
// [stub cache]: contains stubs compiled for this map. // [stub cache]: contains stubs compiled for this map.
DECL_ACCESSORS(code_cache, FixedArray) DECL_ACCESSORS(code_cache, Object)
Object* CopyDropDescriptors(); Object* CopyDropDescriptors();
...@@ -2965,10 +2971,10 @@ class Map: public HeapObject { ...@@ -2965,10 +2971,10 @@ class Map: public HeapObject {
// Returns the non-negative index of the code object if it is in the // Returns the non-negative index of the code object if it is in the
// cache and -1 otherwise. // 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. // 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 // For every transition in this map, makes the transition's
// target's prototype pointer point back to this map. // target's prototype pointer point back to this map.
...@@ -3033,6 +3039,11 @@ class Map: public HeapObject { ...@@ -3033,6 +3039,11 @@ class Map: public HeapObject {
static const int kNeedsLoading = 0; static const int kNeedsLoading = 0;
static const int kIsExtensible = 1; 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: private:
DISALLOW_IMPLICIT_CONSTRUCTORS(Map); DISALLOW_IMPLICIT_CONSTRUCTORS(Map);
}; };
...@@ -3716,6 +3727,97 @@ class CompilationCacheTable: public HashTable<CompilationCacheShape, ...@@ -3716,6 +3727,97 @@ class CompilationCacheTable: public HashTable<CompilationCacheShape,
}; };
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 AllowNullsFlag {ALLOW_NULLS, DISALLOW_NULLS};
enum RobustnessFlag {ROBUST_STRING_TRAVERSAL, FAST_STRING_TRAVERSAL}; enum RobustnessFlag {ROBUST_STRING_TRAVERSAL, FAST_STRING_TRAVERSAL};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment