| // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| #include "vm/megamorphic_cache_table.h" |
| |
| #include <stdlib.h> |
| #include "vm/compiler/jit/compiler.h" |
| #include "vm/object.h" |
| #include "vm/object_store.h" |
| #include "vm/stub_code.h" |
| #include "vm/symbols.h" |
| |
| namespace dart { |
| |
| MegamorphicCachePtr MegamorphicCacheTable::Lookup(Thread* thread, |
| const String& name, |
| const Array& descriptor) { |
| auto object_store = thread->isolate_group()->object_store(); |
| SafepointMutexLocker ml(thread->isolate_group()->megamorphic_table_mutex()); |
| |
| ASSERT(name.IsSymbol()); |
| // TODO(rmacnak): ASSERT(descriptor.IsCanonical()); |
| |
| // TODO(rmacnak): Make a proper hashtable a la symbol table. |
| auto& table = |
| GrowableObjectArray::Handle(object_store->megamorphic_cache_table()); |
| MegamorphicCache& cache = MegamorphicCache::Handle(); |
| if (table.IsNull()) { |
| table = GrowableObjectArray::New(Heap::kOld); |
| object_store->set_megamorphic_cache_table(table); |
| } else { |
| for (intptr_t i = 0; i < table.Length(); i++) { |
| cache ^= table.At(i); |
| if ((cache.target_name() == name.ptr()) && |
| (cache.arguments_descriptor() == descriptor.ptr())) { |
| return cache.ptr(); |
| } |
| } |
| } |
| |
| cache = MegamorphicCache::New(name, descriptor); |
| table.Add(cache, Heap::kOld); |
| return cache.ptr(); |
| } |
| |
| void MegamorphicCacheTable::PrintSizes(Isolate* isolate) { |
| auto thread = Thread::Current(); |
| auto isolate_group = thread->isolate_group(); |
| SafepointMutexLocker ml(isolate_group->megamorphic_table_mutex()); |
| |
| StackZone zone(thread); |
| intptr_t size = 0; |
| MegamorphicCache& cache = MegamorphicCache::Handle(); |
| Array& buckets = Array::Handle(); |
| const GrowableObjectArray& table = GrowableObjectArray::Handle( |
| isolate_group->object_store()->megamorphic_cache_table()); |
| if (table.IsNull()) return; |
| intptr_t max_size = 0; |
| for (intptr_t i = 0; i < table.Length(); i++) { |
| cache ^= table.At(i); |
| buckets = cache.buckets(); |
| size += MegamorphicCache::InstanceSize(); |
| size += Array::InstanceSize(buckets.Length()); |
| if (buckets.Length() > max_size) { |
| max_size = buckets.Length(); |
| } |
| } |
| OS::PrintErr("%" Pd " megamorphic caches using %" Pd "KB.\n", table.Length(), |
| size / 1024); |
| |
| intptr_t* probe_counts = new intptr_t[max_size]; |
| intptr_t entry_count = 0; |
| intptr_t max_probe_count = 0; |
| for (intptr_t i = 0; i < max_size; i++) { |
| probe_counts[i] = 0; |
| } |
| for (intptr_t i = 0; i < table.Length(); i++) { |
| cache ^= table.At(i); |
| buckets = cache.buckets(); |
| intptr_t mask = cache.mask(); |
| intptr_t capacity = mask + 1; |
| for (intptr_t j = 0; j < capacity; j++) { |
| intptr_t class_id = |
| Smi::Value(Smi::RawCast(cache.GetClassId(buckets, j))); |
| if (class_id != kIllegalCid) { |
| intptr_t probe_count = 0; |
| intptr_t probe_index = |
| (class_id * MegamorphicCache::kSpreadFactor) & mask; |
| intptr_t probe_cid; |
| while (true) { |
| probe_count++; |
| probe_cid = |
| Smi::Value(Smi::RawCast(cache.GetClassId(buckets, probe_index))); |
| if (probe_cid == class_id) { |
| break; |
| } |
| probe_index = (probe_index + 1) & mask; |
| } |
| probe_counts[probe_count]++; |
| if (probe_count > max_probe_count) { |
| max_probe_count = probe_count; |
| } |
| entry_count++; |
| } |
| } |
| } |
| intptr_t cumulative_entries = 0; |
| for (intptr_t i = 0; i <= max_probe_count; i++) { |
| cumulative_entries += probe_counts[i]; |
| OS::PrintErr("Megamorphic probe %" Pd ": %" Pd " (%lf)\n", i, |
| probe_counts[i], |
| static_cast<double>(cumulative_entries) / |
| static_cast<double>(entry_count)); |
| } |
| delete[] probe_counts; |
| } |
| |
| } // namespace dart |