Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(708)

Unified Diff: src/objects.cc

Issue 7094003: Per-Isolate cache for polymorphic stubs (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: address Mads' comments Created 9 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/objects.h ('k') | src/objects-debug.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/objects.cc
diff --git a/src/objects.cc b/src/objects.cc
index 292e75300633026409a114e52ddda7e0ceae7f48..edb2b111185b1742cbdc63a86549184ad5b6f913 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -2489,10 +2489,12 @@ MaybeObject* NormalizedMapCache::Get(JSObject* obj,
PropertyNormalizationMode mode) {
Isolate* isolate = obj->GetIsolate();
Map* fast = obj->map();
- int index = Hash(fast) % kEntries;
+ int index = fast->Hash() % kEntries;
Object* result = get(index);
- if (result->IsMap() && CheckHit(Map::cast(result), fast, mode)) {
+ if (result->IsMap() &&
+ Map::cast(result)->EquivalentToForNormalization(fast, mode)) {
#ifdef DEBUG
+ Map::cast(result)->SharedMapVerify();
if (FLAG_enable_slow_asserts) {
// The cached map should match newly created normalized map bit-by-bit.
Object* fresh;
@@ -2528,43 +2530,6 @@ void NormalizedMapCache::Clear() {
}
-int NormalizedMapCache::Hash(Map* fast) {
- // For performance reasons we only hash the 3 most variable fields of a map:
- // constructor, prototype and bit_field2.
-
- // Shift away the tag.
- int hash = (static_cast<uint32_t>(
- reinterpret_cast<uintptr_t>(fast->constructor())) >> 2);
-
- // XOR-ing the prototype and constructor directly yields too many zero bits
- // when the two pointers are close (which is fairly common).
- // To avoid this we shift the prototype 4 bits relatively to the constructor.
- hash ^= (static_cast<uint32_t>(
- reinterpret_cast<uintptr_t>(fast->prototype())) << 2);
-
- return hash ^ (hash >> 16) ^ fast->bit_field2();
-}
-
-
-bool NormalizedMapCache::CheckHit(Map* slow,
- Map* fast,
- PropertyNormalizationMode mode) {
-#ifdef DEBUG
- slow->SharedMapVerify();
-#endif
- return
- slow->constructor() == fast->constructor() &&
- slow->prototype() == fast->prototype() &&
- slow->inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
- 0 :
- fast->inobject_properties()) &&
- slow->instance_type() == fast->instance_type() &&
- slow->bit_field() == fast->bit_field() &&
- slow->bit_field2() == fast->bit_field2() &&
- (slow->bit_field3() & ~(1<<Map::kIsShared)) == fast->bit_field3();
-}
-
-
MaybeObject* JSObject::UpdateMapCodeCache(String* name, Code* code) {
if (map()->is_shared()) {
// Fast case maps are never marked as shared.
@@ -4058,6 +4023,7 @@ class CodeCacheHashTableKey : public HashTableKey {
private:
String* name_;
Code::Flags flags_;
+ // TODO(jkummerow): We should be able to get by without this.
Code* code_;
};
@@ -4077,7 +4043,7 @@ MaybeObject* CodeCacheHashTable::Put(String* name, Code* code) {
if (!maybe_obj->ToObject(&obj)) return maybe_obj;
}
- // Don't use this, as the table might have grown.
+ // Don't use |this|, as the table might have grown.
CodeCacheHashTable* cache = reinterpret_cast<CodeCacheHashTable*>(obj);
int entry = cache->FindInsertionEntry(key.Hash());
@@ -4123,6 +4089,165 @@ static bool HasKey(FixedArray* array, Object* key) {
}
+MaybeObject* PolymorphicCodeCache::Update(MapList* maps,
+ Code::Flags flags,
+ Code* code) {
+ // Initialize cache if necessary.
+ if (cache()->IsUndefined()) {
+ Object* result;
+ { MaybeObject* maybe_result =
+ PolymorphicCodeCacheHashTable::Allocate(
+ PolymorphicCodeCacheHashTable::kInitialSize);
+ if (!maybe_result->ToObject(&result)) return maybe_result;
+ }
+ set_cache(result);
+ } else {
+ // This entry shouldn't be contained in the cache yet.
+ ASSERT(PolymorphicCodeCacheHashTable::cast(cache())
+ ->Lookup(maps, flags)->IsUndefined());
+ }
+ PolymorphicCodeCacheHashTable* hash_table =
+ PolymorphicCodeCacheHashTable::cast(cache());
+ Object* new_cache;
+ { MaybeObject* maybe_new_cache = hash_table->Put(maps, flags, code);
+ if (!maybe_new_cache->ToObject(&new_cache)) return maybe_new_cache;
+ }
+ set_cache(new_cache);
+ return this;
+}
+
+
+Object* PolymorphicCodeCache::Lookup(MapList* maps, Code::Flags flags) {
+ if (!cache()->IsUndefined()) {
+ PolymorphicCodeCacheHashTable* hash_table =
+ PolymorphicCodeCacheHashTable::cast(cache());
+ return hash_table->Lookup(maps, flags);
+ } else {
+ return GetHeap()->undefined_value();
+ }
+}
+
+
+// Despite their name, object of this class are not stored in the actual
+// hash table; instead they're temporarily used for lookups. It is therefore
+// safe to have a weak (non-owning) pointer to a MapList as a member field.
+class PolymorphicCodeCacheHashTableKey : public HashTableKey {
+ public:
+ // Callers must ensure that |maps| outlives the newly constructed object.
+ PolymorphicCodeCacheHashTableKey(MapList* maps, int code_flags)
+ : maps_(maps),
+ code_flags_(code_flags) {}
+
+ bool IsMatch(Object* other) {
+ MapList other_maps(kDefaultListAllocationSize);
+ int other_flags;
+ FromObject(other, &other_flags, &other_maps);
+ if (code_flags_ != other_flags) return false;
+ if (maps_->length() != other_maps.length()) return false;
+ // Compare just the hashes first because it's faster.
+ int this_hash = MapsHashHelper(maps_, code_flags_);
+ int other_hash = MapsHashHelper(&other_maps, other_flags);
+ if (this_hash != other_hash) return false;
+
+ // Full comparison: for each map in maps_, look for an equivalent map in
+ // other_maps. This implementation is slow, but probably good enough for
+ // now because the lists are short (<= 4 elements currently).
+ for (int i = 0; i < maps_->length(); ++i) {
+ bool match_found = false;
+ for (int j = 0; j < other_maps.length(); ++j) {
+ if (maps_->at(i)->EquivalentTo(other_maps.at(j))) {
+ match_found = true;
+ break;
+ }
+ }
+ if (!match_found) return false;
+ }
+ return true;
+ }
+
+ static uint32_t MapsHashHelper(MapList* maps, int code_flags) {
+ uint32_t hash = code_flags;
+ for (int i = 0; i < maps->length(); ++i) {
+ hash ^= maps->at(i)->Hash();
+ }
+ return hash;
+ }
+
+ uint32_t Hash() {
+ return MapsHashHelper(maps_, code_flags_);
+ }
+
+ uint32_t HashForObject(Object* obj) {
+ MapList other_maps(kDefaultListAllocationSize);
+ int other_flags;
+ FromObject(obj, &other_flags, &other_maps);
+ return MapsHashHelper(&other_maps, other_flags);
+ }
+
+ MUST_USE_RESULT MaybeObject* AsObject() {
+ Object* obj;
+ // The maps in |maps_| must be copied to a newly allocated FixedArray,
+ // both because the referenced MapList is short-lived, and because C++
+ // objects can't be stored in the heap anyway.
+ { MaybeObject* maybe_obj =
+ HEAP->AllocateUninitializedFixedArray(maps_->length() + 1);
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ }
+ FixedArray* list = FixedArray::cast(obj);
+ list->set(0, Smi::FromInt(code_flags_));
+ for (int i = 0; i < maps_->length(); ++i) {
+ list->set(i + 1, maps_->at(i));
+ }
+ return list;
+ }
+
+ private:
+ static MapList* FromObject(Object* obj, int* code_flags, MapList* maps) {
+ FixedArray* list = FixedArray::cast(obj);
+ maps->Rewind(0);
+ *code_flags = Smi::cast(list->get(0))->value();
+ for (int i = 1; i < list->length(); ++i) {
+ maps->Add(Map::cast(list->get(i)));
+ }
+ return maps;
+ }
+
+ MapList* maps_; // weak.
+ int code_flags_;
+ static const int kDefaultListAllocationSize =
+ KeyedIC::kMaxKeyedPolymorphism + 1;
+};
+
+
+Object* PolymorphicCodeCacheHashTable::Lookup(MapList* maps, int code_flags) {
+ PolymorphicCodeCacheHashTableKey key(maps, code_flags);
+ int entry = FindEntry(&key);
+ if (entry == kNotFound) return GetHeap()->undefined_value();
+ return get(EntryToIndex(entry) + 1);
+}
+
+
+MaybeObject* PolymorphicCodeCacheHashTable::Put(MapList* maps,
+ int code_flags,
+ Code* code) {
+ PolymorphicCodeCacheHashTableKey key(maps, code_flags);
+ Object* obj;
+ { MaybeObject* maybe_obj = EnsureCapacity(1, &key);
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ }
+ PolymorphicCodeCacheHashTable* cache =
+ reinterpret_cast<PolymorphicCodeCacheHashTable*>(obj);
+ int entry = cache->FindInsertionEntry(key.Hash());
+ { MaybeObject* maybe_obj = key.AsObject();
+ if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ }
+ cache->set(EntryToIndex(entry), obj);
+ cache->set(EntryToIndex(entry) + 1, code);
+ cache->ElementAdded();
+ return cache;
+}
+
+
MaybeObject* FixedArray::AddKeysFromJSArray(JSArray* array) {
ASSERT(!array->HasExternalArrayElements());
switch (array->GetElementsKind()) {
@@ -5768,6 +5893,40 @@ void Map::ClearNonLiveTransitions(Heap* heap, Object* real_prototype) {
}
+int Map::Hash() {
+ // For performance reasons we only hash the 3 most variable fields of a map:
+ // constructor, prototype and bit_field2.
+
+ // Shift away the tag.
+ int hash = (static_cast<uint32_t>(
+ reinterpret_cast<uintptr_t>(constructor())) >> 2);
+
+ // XOR-ing the prototype and constructor directly yields too many zero bits
+ // when the two pointers are close (which is fairly common).
+ // To avoid this we shift the prototype 4 bits relatively to the constructor.
+ hash ^= (static_cast<uint32_t>(
+ reinterpret_cast<uintptr_t>(prototype())) << 2);
+
+ return hash ^ (hash >> 16) ^ bit_field2();
+}
+
+
+bool Map::EquivalentToForNormalization(Map* other,
+ PropertyNormalizationMode mode) {
+ return
+ constructor() == other->constructor() &&
+ prototype() == other->prototype() &&
+ inobject_properties() == ((mode == CLEAR_INOBJECT_PROPERTIES) ?
+ 0 :
+ other->inobject_properties()) &&
+ instance_type() == other->instance_type() &&
+ bit_field() == other->bit_field() &&
+ bit_field2() == other->bit_field2() &&
+ (bit_field3() & ~(1<<Map::kIsShared)) ==
+ (other->bit_field3() & ~(1<<Map::kIsShared));
+}
+
+
void JSFunction::JSFunctionIterateBody(int object_size, ObjectVisitor* v) {
// Iterate over all fields in the body but take care in dealing with
// the code entry.
« no previous file with comments | « src/objects.h ('k') | src/objects-debug.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698