From c078783c364a003173c6b450c166cf65dadb3594 Mon Sep 17 00:00:00 2001 From: "bak@chromium.org" Date: Mon, 22 Jun 2009 08:09:57 +0000 Subject: [PATCH] Implemented a ContextSlotCache for compiled code. Review URL: http://codereview.chromium.org/141038 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2230 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/contexts.cc | 2 +- src/heap.cc | 6 ++++ src/heap.h | 23 +++++++------ src/runtime.cc | 3 +- src/scopeinfo.cc | 86 +++++++++++++++++++++++++++++++++++++++++++++--- src/scopeinfo.h | 68 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 170 insertions(+), 18 deletions(-) diff --git a/src/contexts.cc b/src/contexts.cc index 873c23ca5..ead73ee03 100644 --- a/src/contexts.cc +++ b/src/contexts.cc @@ -149,7 +149,7 @@ Handle Context::Lookup(Handle name, ContextLookupFlags flags, // check parameter locals in context int param_index = ScopeInfo<>::ParameterIndex(*code, *name); if (param_index >= 0) { - // slot found + // slot found. int index = ScopeInfo<>::ContextSlotIndex(*code, Heap::arguments_shadow_symbol(), diff --git a/src/heap.cc b/src/heap.cc index caf127493..879d6a16a 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -501,6 +501,7 @@ void Heap::MarkCompactPrologue(bool is_compacting) { // At any old GC clear the keyed lookup cache to enable collection of unused // maps. KeyedLookupCache::Clear(); + ContextSlotCache::Clear(); CompilationCache::MarkCompactPrologue(); @@ -1388,6 +1389,9 @@ bool Heap::CreateInitialObjects() { // Initialize keyed lookup cache. KeyedLookupCache::Clear(); + // Initialize context slot cache. + ContextSlotCache::Clear(); + // Initialize compilation cache. CompilationCache::Clear(); @@ -3548,8 +3552,10 @@ 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]; diff --git a/src/heap.h b/src/heap.h index 9be369776..0191b69c2 100644 --- a/src/heap.h +++ b/src/heap.h @@ -444,17 +444,6 @@ class Heap : public AllStatic { // Allocates a new utility object in the old generation. static Object* AllocateStruct(InstanceType type); - - // Initializes a function with a shared part and prototype. - // Returns the function. - // Note: this code was factored out of AllocateFunction such that - // other parts of the VM could use it. Specifically, a function that creates - // instances of type JS_FUNCTION_TYPE benefit from the use of this function. - // Please note this does not perform a garbage collection. - static Object* InitializeFunction(JSFunction* function, - SharedFunctionInfo* shared, - Object* prototype); - // Allocates a function initialized with a shared part. // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation // failed. @@ -984,7 +973,17 @@ class Heap : public AllStatic { static void ScavengeObjectSlow(HeapObject** p, HeapObject* object); // Copy memory from src to dst. - inline static void CopyBlock(Object** dst, Object** src, int byte_size); + static inline void CopyBlock(Object** dst, Object** src, int byte_size); + + // Initializes a function with a shared part and prototype. + // Returns the function. + // Note: this code was factored out of AllocateFunction such that + // other parts of the VM could use it. Specifically, a function that creates + // instances of type JS_FUNCTION_TYPE benefit from the use of this function. + // Please note this does not perform a garbage collection. + static inline Object* InitializeFunction(JSFunction* function, + SharedFunctionInfo* shared, + Object* prototype); static const int kInitialSymbolTableSize = 2048; static const int kInitialEvalCacheSize = 64; diff --git a/src/runtime.cc b/src/runtime.cc index 807abab9c..ad02f5d5b 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -124,7 +124,8 @@ static Object* DeepCopyBoilerplate(JSObject* boilerplate) { } } mode = copy->GetWriteBarrierMode(); - for (int i = 0; i < copy->map()->inobject_properties(); i++) { + int nof = copy->map()->inobject_properties(); + for (int i = 0; i < nof; i++) { Object* value = copy->InObjectPropertyAt(i); if (value->IsJSObject()) { JSObject* jsObject = JSObject::cast(value); diff --git a/src/scopeinfo.cc b/src/scopeinfo.cc index fedfbd64f..8a237fd0e 100644 --- a/src/scopeinfo.cc +++ b/src/scopeinfo.cc @@ -432,10 +432,13 @@ int ScopeInfo::ContextSlotIndex(Code* code, String* name, Variable::Mode* mode) { ASSERT(name->IsSymbol()); + int result = ContextSlotCache::Lookup(code, name, mode); + if (result != ContextSlotCache::kNotFound) return result; if (code->sinfo_size() > 0) { // Loop below depends on the NULL sentinel after the context slot names. ASSERT(NumberOfContextSlots(code) >= Context::MIN_CONTEXT_SLOTS || *(ContextEntriesAddr(code) + 1) == NULL); + // slots start after length entry Object** p0 = ContextEntriesAddr(code) + 1; Object** p = p0; @@ -443,14 +446,18 @@ int ScopeInfo::ContextSlotIndex(Code* code, while (*p != NULL) { if (*p == name) { ASSERT(((p - p0) & 1) == 0); - if (mode != NULL) { - ReadInt(p + 1, reinterpret_cast(mode)); - } - return ((p - p0) >> 1) + Context::MIN_CONTEXT_SLOTS; + int v; + ReadInt(p + 1, &v); + Variable::Mode mode_value = static_cast(v); + if (mode != NULL) *mode = mode_value; + result = ((p - p0) >> 1) + Context::MIN_CONTEXT_SLOTS; + ContextSlotCache::Update(code, name, mode_value, result); + return result; } p += 2; } } + ContextSlotCache::Update(code, name, Variable::INTERNAL, -1); return -1; } @@ -526,7 +533,78 @@ int ScopeInfo::NumberOfLocals() const { } +int ContextSlotCache::Hash(Code* code, String* name) { + // Uses only lower 32 bits if pointers are larger. + uintptr_t addr_hash = + static_cast(reinterpret_cast(code)) >> 2; + return (addr_hash ^ name->Hash()) % kLength; +} + + +int ContextSlotCache::Lookup(Code* code, + String* name, + Variable::Mode* mode) { + int index = Hash(code, name); + Key& key = keys_[index]; + if ((key.code == code) && key.name->Equals(name)) { + Value result(values_[index]); + if (mode != NULL) *mode = result.mode(); + return result.index() + kNotFound; + } + return kNotFound; +} + + +void ContextSlotCache::Update(Code* code, + String* name, + Variable::Mode mode, + int slot_index) { + String* symbol; + ASSERT(slot_index > kNotFound); + if (Heap::LookupSymbolIfExists(name, &symbol)) { + int index = Hash(code, symbol); + Key& key = keys_[index]; + key.code = code; + key.name = symbol; + // Please note value only takes a uint as index. + values_[index] = Value(mode, slot_index - kNotFound).raw(); +#ifdef DEBUG + ValidateEntry(code, name, mode, slot_index); +#endif + } +} + + +void ContextSlotCache::Clear() { + for (int index = 0; index < kLength; index++) keys_[index].code = NULL; +} + + +ContextSlotCache::Key ContextSlotCache::keys_[ContextSlotCache::kLength]; + + +uint32_t ContextSlotCache::values_[ContextSlotCache::kLength]; + + #ifdef DEBUG + +void ContextSlotCache::ValidateEntry(Code* code, + String* name, + Variable::Mode mode, + int slot_index) { + String* symbol; + if (Heap::LookupSymbolIfExists(name, &symbol)) { + int index = Hash(code, name); + Key& key = keys_[index]; + ASSERT(key.code == code); + ASSERT(key.name->Equals(name)); + Value result(values_[index]); + ASSERT(result.mode() == mode); + ASSERT(result.index() + kNotFound == slot_index); + } +} + + template static void PrintList(const char* list_name, int nof_internal_slots, diff --git a/src/scopeinfo.h b/src/scopeinfo.h index a097d34f9..28d169a39 100644 --- a/src/scopeinfo.h +++ b/src/scopeinfo.h @@ -163,6 +163,74 @@ class ZoneScopeInfo: public ScopeInfo { }; +// Cache for mapping (code, property name) into context slot index. +// The cache contains both positive and negative results. +// Slot index equals -1 means the property is absent. +// Cleared at startup and prior to mark sweep collection. +class ContextSlotCache { + public: + // Lookup context slot index for (code, name). + // If absent, kNotFound is returned. + static int Lookup(Code* code, + String* name, + Variable::Mode* mode); + + // Update an element in the cache. + static void Update(Code* code, + String* name, + Variable::Mode mode, + int slot_index); + + // Clear the cache. + static void Clear(); + + static const int kNotFound = -2; + private: + inline static int Hash(Code* code, String* name); + +#ifdef DEBUG + static void ValidateEntry(Code* code, + String* name, + Variable::Mode mode, + int slot_index); +#endif + + static const int kLength = 256; + struct Key { + Code* code; + String* name; + }; + + struct Value { + Value(Variable::Mode mode, int index) { + ASSERT(ModeField::is_valid(mode)); + ASSERT(IndexField::is_valid(index)); + value_ = ModeField::encode(mode) | IndexField::encode(index); + ASSERT(mode == this->mode()); + ASSERT(index == this->index()); + } + + inline Value(uint32_t value) : value_(value) {} + + uint32_t raw() { return value_; } + + Variable::Mode mode() { return ModeField::decode(value_); } + + int index() { return IndexField::decode(value_); } + + // Bit fields in value_ (type, shift, size). Must be public so the + // constants can be embedded in generated code. + class ModeField: public BitField {}; + class IndexField: public BitField {}; + private: + uint32_t value_; + }; + + static Key keys_[kLength]; + static uint32_t values_[kLength]; +}; + + } } // namespace v8::internal #endif // V8_SCOPEINFO_H_ -- 2.34.1