Commit 57e2aa1b authored by ager@chromium.org's avatar ager@chromium.org

Use null instead of undefined for deleted elements in code caches.

Update the lookup and update code for code caches to deal with deleted
elements.

Do not clear the code cache for the builtins object.  If there was a
matching element in the code cache, we would have hit the monomorphic
prototype failure case and removed it.
Review URL: http://codereview.chromium.org/3140

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@340 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent cb4ea563
...@@ -164,11 +164,9 @@ IC::State IC::StateFrom(Code* target, Object* receiver) { ...@@ -164,11 +164,9 @@ IC::State IC::StateFrom(Code* target, Object* receiver) {
// builtins are loaded lazily. It is important to keep inline // builtins are loaded lazily. It is important to keep inline
// caches for the builtins object monomorphic. Therefore, if we get // caches for the builtins object monomorphic. Therefore, if we get
// an inline cache miss for the builtins object after lazily loading // an inline cache miss for the builtins object after lazily loading
// JavaScript builtins, we clear the code cache and return // JavaScript builtins, we return uninitialized as the state to
// uninitialized as the state to force the inline cache back to // force the inline cache back to monomorphic state.
// monomorphic state.
if (receiver->IsJSBuiltinsObject()) { if (receiver->IsJSBuiltinsObject()) {
map->ClearCodeCache();
return UNINITIALIZED; return UNINITIALIZED;
} }
......
...@@ -977,6 +977,13 @@ void FixedArray::set_undefined(int index) { ...@@ -977,6 +977,13 @@ void FixedArray::set_undefined(int index) {
} }
void FixedArray::set_null(int index) {
ASSERT(index >= 0 && index < this->length());
ASSERT(!Heap::InNewSpace(Heap::null_value()));
WRITE_FIELD(this, kHeaderSize + index * kPointerSize, Heap::null_value());
}
void FixedArray::set_the_hole(int index) { void FixedArray::set_the_hole(int index) {
ASSERT(index >= 0 && index < this->length()); ASSERT(index >= 0 && index < this->length());
ASSERT(!Heap::InNewSpace(Heap::the_hole_value())); ASSERT(!Heap::InNewSpace(Heap::the_hole_value()));
......
...@@ -2379,9 +2379,15 @@ Object* Map::UpdateCodeCache(String* name, Code* code) { ...@@ -2379,9 +2379,15 @@ Object* Map::UpdateCodeCache(String* name, Code* code) {
// First check whether we can update existing code cache without // First check whether we can update existing code cache without
// extending it. // extending it.
int length = cache->length(); int length = cache->length();
int deleted_index = -1;
for (int i = 0; i < length; i += 2) { for (int i = 0; i < length; i += 2) {
Object* key = cache->get(i); Object* key = cache->get(i);
if (key->IsNull()) {
if (deleted_index < 0) deleted_index = i;
continue;
}
if (key->IsUndefined()) { if (key->IsUndefined()) {
if (deleted_index >= 0) i = deleted_index;
cache->set(i + 0, name); cache->set(i + 0, name);
cache->set(i + 1, code); cache->set(i + 1, code);
return this; return this;
...@@ -2395,6 +2401,14 @@ Object* Map::UpdateCodeCache(String* name, Code* code) { ...@@ -2395,6 +2401,14 @@ Object* Map::UpdateCodeCache(String* name, Code* code) {
} }
} }
// 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);
return this;
}
// Extend the code cache with some new entries (at least one). // Extend the code cache with some new entries (at least one).
int new_length = length + ((length >> 1) & ~1) + 2; int new_length = length + ((length >> 1) & ~1) + 2;
ASSERT((new_length & 1) == 0); // must be a multiple of two ASSERT((new_length & 1) == 0); // must be a multiple of two
...@@ -2415,9 +2429,9 @@ Object* Map::FindInCodeCache(String* name, Code::Flags flags) { ...@@ -2415,9 +2429,9 @@ Object* Map::FindInCodeCache(String* name, Code::Flags flags) {
int length = cache->length(); int length = cache->length();
for (int i = 0; i < length; i += 2) { for (int i = 0; i < length; i += 2) {
Object* key = cache->get(i); Object* key = cache->get(i);
if (key->IsUndefined()) { // Skip deleted elements.
return key; if (key->IsNull()) continue;
} if (key->IsUndefined()) return key;
if (name->Equals(String::cast(key))) { if (name->Equals(String::cast(key))) {
Code* code = Code::cast(cache->get(i + 1)); Code* code = Code::cast(cache->get(i + 1));
if (code->flags() == flags) return code; if (code->flags() == flags) return code;
...@@ -2440,8 +2454,11 @@ int Map::IndexInCodeCache(Code* code) { ...@@ -2440,8 +2454,11 @@ int Map::IndexInCodeCache(Code* code) {
void Map::RemoveFromCodeCache(int index) { void Map::RemoveFromCodeCache(int index) {
FixedArray* array = code_cache(); FixedArray* array = code_cache();
ASSERT(array->length() >= index && array->get(index)->IsCode()); ASSERT(array->length() >= index && array->get(index)->IsCode());
array->set_undefined(index - 1); // key // Use null instead of undefined for deleted elements to distinguish
array->set_undefined(index); // code // 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
} }
......
...@@ -1443,6 +1443,7 @@ class FixedArray: public Array { ...@@ -1443,6 +1443,7 @@ class FixedArray: public Array {
// Setters for frequently used oddballs located in old space. // Setters for frequently used oddballs located in old space.
inline void set_undefined(int index); inline void set_undefined(int index);
inline void set_null(int index);
inline void set_the_hole(int index); inline void set_the_hole(int index);
// Setter that skips the write barrier if mode is SKIP_WRITE_BARRIER. // Setter that skips the write barrier if mode is SKIP_WRITE_BARRIER.
......
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