| // 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 |