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

Unified Diff: src/objects.cc

Issue 2021373002: Refactor Maps' code_cache (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: windows don't want no constexpr Created 4 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-inl.h » ('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 de0d756966db9720d9a284d1f5d3a565add14ea1..2d47b8f3651925247285cfe2f455be09681c2d9e 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -9447,29 +9447,186 @@ Handle<Map> Map::CopyReplaceDescriptor(Handle<Map> map,
simple_flag);
}
+// Helper class to manage a Map's code cache. The layout depends on the number
+// of entries; this is worthwhile because most code caches are very small,
+// but some are huge (thousands of entries).
+// For zero entries, the EmptyFixedArray is used.
+// For one entry, we use a 2-element FixedArray containing [name, code].
+// For 2..100 entries, we use a FixedArray with linear lookups, the layout is:
+// [0] - number of slots that are currently in use
+// [1] - first name
+// [2] - first code
+// [3] - second name
+// [4] - second code
+// etc.
+// For more than 128 entries, we use a CodeCacheHashTable.
+class CodeCache : public AllStatic {
+ public:
+ // Returns the new cache, to be stored on the map.
+ static Handle<FixedArray> Put(Isolate* isolate, Handle<FixedArray> cache,
+ Handle<Name> name, Handle<Code> code) {
+ int length = cache->length();
+ if (length == 0) return PutFirstElement(isolate, name, code);
+ if (length == kEntrySize) {
+ return PutSecondElement(isolate, cache, name, code);
+ }
+ if (length <= kLinearMaxSize) {
+ Handle<FixedArray> result = PutLinearElement(isolate, cache, name, code);
+ if (!result.is_null()) return result;
+ // Fall through if linear storage is getting too large.
+ }
+ return PutHashTableElement(isolate, cache, name, code);
+ }
+
+ static Code* Lookup(FixedArray* cache, Name* name, Code::Flags flags) {
+ int length = cache->length();
+ if (length == 0) return nullptr;
+ if (length == kEntrySize) return OneElementLookup(cache, name, flags);
+ if (!cache->IsCodeCacheHashTable()) {
+ return LinearLookup(cache, name, flags);
+ } else {
+ return CodeCacheHashTable::cast(cache)->Lookup(name, flags);
+ }
+ }
+
+ private:
+ static const int kNameIndex = 0;
+ static const int kCodeIndex = 1;
+ static const int kEntrySize = 2;
+
+ static const int kLinearUsageIndex = 0;
+ static const int kLinearReservedSlots = 1;
+ static const int kLinearInitialCapacity = 2;
+ static const int kLinearMaxSize = 257; // == LinearSizeFor(128);
+
+ static const int kHashTableInitialCapacity = 200; // Number of entries.
+
+ static int LinearSizeFor(int entries) {
+ return kLinearReservedSlots + kEntrySize * entries;
+ }
+
+ static int LinearNewSize(int old_size) {
+ int old_entries = (old_size - kLinearReservedSlots) / kEntrySize;
+ return LinearSizeFor(old_entries * 2);
+ }
+
+ static Code* OneElementLookup(FixedArray* cache, Name* name,
+ Code::Flags flags) {
+ DCHECK_EQ(cache->length(), kEntrySize);
+ if (cache->get(kNameIndex) != name) return nullptr;
+ Code* maybe_code = Code::cast(cache->get(kCodeIndex));
+ if (maybe_code->flags() != flags) return nullptr;
+ return maybe_code;
+ }
+
+ static Code* LinearLookup(FixedArray* cache, Name* name, Code::Flags flags) {
+ DCHECK_GE(cache->length(), kEntrySize);
+ DCHECK(!cache->IsCodeCacheHashTable());
+ int usage = GetLinearUsage(cache);
+ for (int i = kLinearReservedSlots; i < usage; i += kEntrySize) {
+ if (cache->get(i + kNameIndex) != name) continue;
+ Code* code = Code::cast(cache->get(i + kCodeIndex));
+ if (code->flags() == flags) return code;
+ }
+ return nullptr;
+ }
+
+ static Handle<FixedArray> PutFirstElement(Isolate* isolate, Handle<Name> name,
+ Handle<Code> code) {
+ Handle<FixedArray> cache = isolate->factory()->NewFixedArray(kEntrySize);
+ cache->set(kNameIndex, *name);
+ cache->set(kCodeIndex, *code);
+ return cache;
+ }
+
+ static Handle<FixedArray> PutSecondElement(Isolate* isolate,
+ Handle<FixedArray> cache,
+ Handle<Name> name,
+ Handle<Code> code) {
+ DCHECK_EQ(cache->length(), kEntrySize);
+ Handle<FixedArray> new_cache = isolate->factory()->NewFixedArray(
+ LinearSizeFor(kLinearInitialCapacity));
+ new_cache->set(kLinearReservedSlots + kNameIndex, cache->get(kNameIndex));
+ new_cache->set(kLinearReservedSlots + kCodeIndex, cache->get(kCodeIndex));
+ new_cache->set(LinearSizeFor(1) + kNameIndex, *name);
+ new_cache->set(LinearSizeFor(1) + kCodeIndex, *code);
+ new_cache->set(kLinearUsageIndex, Smi::FromInt(LinearSizeFor(2)));
+ return new_cache;
+ }
+
+ static Handle<FixedArray> PutLinearElement(Isolate* isolate,
+ Handle<FixedArray> cache,
+ Handle<Name> name,
+ Handle<Code> code) {
+ int length = cache->length();
+ int usage = GetLinearUsage(*cache);
+ DCHECK_LE(usage, length);
+ // Check if we need to grow.
+ if (usage == length) {
+ int new_length = LinearNewSize(length);
+ if (new_length > kLinearMaxSize) return Handle<FixedArray>::null();
+ Handle<FixedArray> new_cache =
+ isolate->factory()->NewFixedArray(new_length);
+ for (int i = kLinearReservedSlots; i < length; i++) {
+ new_cache->set(i, cache->get(i));
+ }
+ cache = new_cache;
+ }
+ // Store new entry.
+ DCHECK_GE(cache->length(), usage + kEntrySize);
+ cache->set(usage + kNameIndex, *name);
+ cache->set(usage + kCodeIndex, *code);
+ cache->set(kLinearUsageIndex, Smi::FromInt(usage + kEntrySize));
+ return cache;
+ }
+
+ static Handle<FixedArray> PutHashTableElement(Isolate* isolate,
+ Handle<FixedArray> cache,
+ Handle<Name> name,
+ Handle<Code> code) {
+ // Check if we need to transition from linear to hash table storage.
+ if (!cache->IsCodeCacheHashTable()) {
+ // Check that the initial hash table capacity is large enough.
+ DCHECK_EQ(kLinearMaxSize, LinearSizeFor(128));
+ STATIC_ASSERT(kHashTableInitialCapacity > 128);
+
+ int length = cache->length();
+ // Only migrate from linear storage when it's full.
+ DCHECK_EQ(length, GetLinearUsage(*cache));
+ DCHECK_EQ(length, kLinearMaxSize);
+ Handle<CodeCacheHashTable> table =
+ CodeCacheHashTable::New(isolate, kHashTableInitialCapacity);
+ HandleScope scope(isolate);
+ for (int i = kLinearReservedSlots; i < length; i += kEntrySize) {
+ Handle<Name> old_name(Name::cast(cache->get(i + kNameIndex)), isolate);
+ Handle<Code> old_code(Code::cast(cache->get(i + kCodeIndex)), isolate);
+ CodeCacheHashTable::Put(table, old_name, old_code);
+ }
+ cache = table;
+ }
+ // Store new entry.
+ DCHECK(cache->IsCodeCacheHashTable());
+ return CodeCacheHashTable::Put(Handle<CodeCacheHashTable>::cast(cache),
+ name, code);
+ }
+
+ static inline int GetLinearUsage(FixedArray* linear_cache) {
+ DCHECK_GT(linear_cache->length(), kEntrySize);
+ return Smi::cast(linear_cache->get(kLinearUsageIndex))->value();
+ }
+};
void Map::UpdateCodeCache(Handle<Map> map,
Handle<Name> name,
Handle<Code> code) {
Isolate* isolate = map->GetIsolate();
- HandleScope scope(isolate);
- // Allocate the code cache if not present.
- if (!map->has_code_cache()) {
- Handle<Object> result =
- CodeCacheHashTable::New(isolate, CodeCacheHashTable::kInitialSize);
- map->set_code_cache(*result);
- }
-
- // Update the code cache.
- Handle<CodeCacheHashTable> cache(CodeCacheHashTable::cast(map->code_cache()),
- isolate);
- Handle<Object> new_cache = CodeCacheHashTable::Put(cache, name, code);
+ Handle<FixedArray> cache(map->code_cache(), isolate);
+ Handle<FixedArray> new_cache = CodeCache::Put(isolate, cache, name, code);
map->set_code_cache(*new_cache);
}
Code* Map::LookupInCodeCache(Name* name, Code::Flags flags) {
- if (!has_code_cache()) return nullptr;
- return CodeCacheHashTable::cast(code_cache())->Lookup(name, flags);
+ return CodeCache::Lookup(code_cache(), name, flags);
}
« no previous file with comments | « src/objects.h ('k') | src/objects-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698