Commit c078783c authored by bak@chromium.org's avatar bak@chromium.org

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
parent 4f6a4a83
......@@ -149,7 +149,7 @@ Handle<Object> Context::Lookup(Handle<String> 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(),
......
......@@ -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];
......
......@@ -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;
......
......@@ -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);
......
......@@ -432,10 +432,13 @@ int ScopeInfo<Allocator>::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<Allocator>::ContextSlotIndex(Code* code,
while (*p != NULL) {
if (*p == name) {
ASSERT(((p - p0) & 1) == 0);
if (mode != NULL) {
ReadInt(p + 1, reinterpret_cast<int*>(mode));
}
return ((p - p0) >> 1) + Context::MIN_CONTEXT_SLOTS;
int v;
ReadInt(p + 1, &v);
Variable::Mode mode_value = static_cast<Variable::Mode>(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<Allocator>::NumberOfLocals() const {
}
int ContextSlotCache::Hash(Code* code, String* name) {
// Uses only lower 32 bits if pointers are larger.
uintptr_t addr_hash =
static_cast<uint32_t>(reinterpret_cast<uintptr_t>(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 <class Allocator>
static void PrintList(const char* list_name,
int nof_internal_slots,
......
......@@ -163,6 +163,74 @@ class ZoneScopeInfo: public ScopeInfo<ZoneListAllocationPolicy> {
};
// 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<Variable::Mode, 0, 3> {};
class IndexField: public BitField<int, 3, 32-3> {};
private:
uint32_t value_;
};
static Key keys_[kLength];
static uint32_t values_[kLength];
};
} } // namespace v8::internal
#endif // V8_SCOPEINFO_H_
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