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

Unified Diff: runtime/vm/object.cc

Issue 11299298: Cache lookups at megamorphic call sites in optimized code. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years 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
Index: runtime/vm/object.cc
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index c51a27cc9ab0cd9391c4a7ec7b5f6434ee2f7ae9..dcd503d5489d596b14d434646fd62b5b3b7d266d 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -97,6 +97,8 @@ RawClass* Object::deopt_info_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::context_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::context_scope_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::icdata_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
+RawClass* Object::megamorphic_cache_class_ =
+ reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::subtypetestcache_class_ =
reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::api_error_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
@@ -382,6 +384,9 @@ void Object::InitOnce() {
cls = Class::New<ICData>();
icdata_class_ = cls.raw();
+ cls = Class::New<MegamorphicCache>();
+ megamorphic_cache_class_ = cls.raw();
+
cls = Class::New<SubtypeTestCache>();
subtypetestcache_class_ = cls.raw();
@@ -457,6 +462,7 @@ void Object::RegisterSingletonClassNames() {
SET_CLASS_NAME(context, Context);
SET_CLASS_NAME(context_scope, ContextScope);
SET_CLASS_NAME(icdata, ICData);
+ SET_CLASS_NAME(megamorphic_cache, MegamorphicCache);
SET_CLASS_NAME(subtypetestcache, SubtypeTestCache);
SET_CLASS_NAME(api_error, ApiError);
SET_CLASS_NAME(language_error, LanguageError);
@@ -7758,6 +7764,122 @@ RawICData* ICData::New(const Function& function,
}
+RawArray* MegamorphicCache::buckets() const {
+ return raw_ptr()->buckets_;
+}
+
+
+void MegamorphicCache::set_buckets(const Array& buckets) const {
+ StorePointer(&raw_ptr()->buckets_, buckets.raw());
+}
+
+
+// Class IDs in the table are smi-tagged, so we use a smi-tagged mask
+// and target class ID to avoid untagging (on each iteration of the
+// test loop) in generated code.
+intptr_t MegamorphicCache::mask() const {
+ return Smi::Value(raw_ptr()->mask_);
+}
+
+
+void MegamorphicCache::set_mask(intptr_t mask) const {
+ raw_ptr()->mask_ = Smi::New(mask);
+}
+
+
+intptr_t MegamorphicCache::fill_count() const {
+ return raw_ptr()->fill_count_;
+}
+
+
+void MegamorphicCache::set_fill_count(intptr_t fill_count) const {
+ raw_ptr()->fill_count_ = fill_count;
+}
+
+
+RawMegamorphicCache* MegamorphicCache::New() {
+ MegamorphicCache& result = MegamorphicCache::Handle();
+ { RawObject* raw = Object::Allocate(MegamorphicCache::kClassId,
+ MegamorphicCache::InstanceSize(),
+ Heap::kOld);
+ NoGCScope no_gc;
+ result ^= raw;
+ }
+ const intptr_t size = kInitialCapacity;
+ const Array& buckets = Array::Handle(Array::New(2 * size));
+ const Smi& illegal = Smi::Handle(Smi::New(kIllegalCid));
+ const Function& handler = Function::Handle(
+ Isolate::Current()->megamorphic_cache_table()->miss_handler());
+ for (intptr_t i = 0; i < size; ++i) {
+ buckets.SetAt(2 * i, illegal);
Vyacheslav Egorov (Google) 2012/12/03 14:55:22 I don't like magical constant spread around
Kevin Millikin (Google) 2012/12/06 14:03:11 I thought this was already pretty localized, but I
+ buckets.SetAt((2 * i) + 1, handler);
+ }
+ result.set_buckets(buckets);
+ result.set_mask(size - 1);
+ result.set_fill_count(0);
+ return result.raw();
+}
+
+
+void MegamorphicCache::EnsureCapacity() const {
+ intptr_t old_size = mask() + 1;
+ double load_limit = kLoadFactor * static_cast<double>(old_size);
+ if (static_cast<double>(fill_count() + 1) > load_limit) {
+ const Array& old_buckets = Array::Handle(buckets());
+ intptr_t new_size = old_size * 2;
+ const Array& new_buckets = Array::Handle(Array::New(2 * new_size));
+
+ Smi& class_id = Smi::Handle(Smi::New(kIllegalCid));
+ Function& target = Function::Handle(
+ Isolate::Current()->megamorphic_cache_table()->miss_handler());
+ for (intptr_t i = 0; i < new_size; ++i) {
+ new_buckets.SetAt(2 * i, class_id);
+ new_buckets.SetAt((2 * i) + 1, target);
+ }
+ set_buckets(new_buckets);
+ set_mask(new_size - 1);
+ set_fill_count(0);
+
+ // Rehash the valid entries.
+ for (intptr_t i = 0; i < old_size; ++i) {
+ class_id ^= old_buckets.At(2 * i);
+ if (class_id.Value() != kIllegalCid) {
+ target ^= old_buckets.At((2 * i) + 1);
+ Insert(class_id, target);
+ }
+ }
+ }
+}
+
+
+void MegamorphicCache::Insert(const Smi& class_id,
+ const Function& target) const {
+ ASSERT(static_cast<double>(fill_count() + 1) <=
+ (kLoadFactor * static_cast<double>(mask() + 1)));
+ const Array& backing_array = Array::Handle(buckets());
+ intptr_t id_mask = mask();
+ intptr_t index = class_id.Value() & id_mask;
+ Smi& probe = Smi::Handle();
+ intptr_t i = index;
+ do {
+ probe ^= backing_array.At(2 * i);
+ if (probe.Value() == kIllegalCid) {
+ backing_array.SetAt(2 * i, class_id);
+ backing_array.SetAt((2 * i) + 1, target);
+ set_fill_count(fill_count() + 1);
Vyacheslav Egorov (Google) 2012/12/03 14:55:22 consider renaming fill_count to size
Kevin Millikin (Google) 2012/12/06 14:03:11 Since variables ending in _size are always in byte
+ return;
+ }
+ i = (i + 1) & id_mask;
+ } while (i != index);
+ UNREACHABLE();
+}
+
+
+const char* MegamorphicCache::ToCString() const {
+ return "";
+}
+
+
RawSubtypeTestCache* SubtypeTestCache::New() {
ASSERT(Object::subtypetestcache_class() != Class::null());
SubtypeTestCache& result = SubtypeTestCache::Handle();

Powered by Google App Engine
This is Rietveld 408576698