| OLD | NEW | 
|---|
| 1 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file | 
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a | 
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. | 
| 4 | 4 | 
| 5 #ifndef VM_WEAK_TABLE_H_ | 5 #ifndef VM_WEAK_TABLE_H_ | 
| 6 #define VM_WEAK_TABLE_H_ | 6 #define VM_WEAK_TABLE_H_ | 
| 7 | 7 | 
| 8 #include "vm/globals.h" | 8 #include "vm/globals.h" | 
| 9 | 9 | 
| 10 #include "platform/assert.h" | 10 #include "platform/assert.h" | 
| 11 #include "vm/raw_object.h" | 11 #include "vm/raw_object.h" | 
| 12 | 12 | 
| 13 namespace dart { | 13 namespace dart { | 
| 14 | 14 | 
| 15 class WeakTable { | 15 class WeakTable { | 
| 16  public: | 16  public: | 
|  | 17   WeakTable() : size_(kMinSize), used_(0), count_(0) { | 
|  | 18     ASSERT(Utils::IsPowerOfTwo(size_)); | 
|  | 19     data_ = reinterpret_cast<intptr_t*>(calloc(size_, kEntrySize * kWordSize)); | 
|  | 20   } | 
| 17   explicit WeakTable(intptr_t size) : used_(0), count_(0) { | 21   explicit WeakTable(intptr_t size) : used_(0), count_(0) { | 
| 18     ASSERT(size >= 0); | 22     ASSERT(size >= 0); | 
|  | 23     ASSERT(Utils::IsPowerOfTwo(kMinSize)); | 
| 19     if (size < kMinSize) { | 24     if (size < kMinSize) { | 
| 20       size = kMinSize; | 25       size = kMinSize; | 
| 21     } | 26     } | 
| 22     data_ = reinterpret_cast<intptr_t*>(calloc(size, kEntrySize * kWordSize)); | 27     // Get a max size that avoids overflows. | 
|  | 28     const intptr_t kMaxSize = | 
|  | 29       (kIntptrOne << (kBitsPerWord - 2)) / (kEntrySize * kWordSize); | 
|  | 30     ASSERT(Utils::IsPowerOfTwo(kMaxSize)); | 
|  | 31     if (size > kMaxSize) { | 
|  | 32       size = kMaxSize; | 
|  | 33     } | 
| 23     size_ = size; | 34     size_ = size; | 
|  | 35     ASSERT(Utils::IsPowerOfTwo(size_)); | 
|  | 36     data_ = reinterpret_cast<intptr_t*>(calloc(size_, kEntrySize * kWordSize)); | 
|  | 37   } | 
|  | 38 | 
|  | 39   ~WeakTable() { | 
|  | 40     free(data_); | 
| 24   } | 41   } | 
| 25 | 42 | 
| 26   static WeakTable* NewFrom(WeakTable* original) { | 43   static WeakTable* NewFrom(WeakTable* original) { | 
| 27     intptr_t cnt = original->count(); | 44     return new WeakTable(SizeFor(original->count(), original->size())); | 
| 28     intptr_t sz = original->size(); |  | 
| 29     intptr_t new_sz = sz; |  | 
| 30 |  | 
| 31     if (cnt <= (sz / 4)) { |  | 
| 32       // Reduce the capacity. |  | 
| 33       new_sz = sz / 2; |  | 
| 34     } else if (cnt > (sz / 2)) { |  | 
| 35       // Increase the capacity. |  | 
| 36       new_sz = sz * 2; |  | 
| 37       if (new_sz < sz) { |  | 
| 38         FATAL("Reached impossible state of having more weak table entries" |  | 
| 39               " than memory available for heap objects."); |  | 
| 40       } |  | 
| 41     } |  | 
| 42     return new WeakTable(new_sz); |  | 
| 43   } | 45   } | 
| 44 | 46 | 
| 45   intptr_t size() const { return size_; } | 47   intptr_t size() const { return size_; } | 
| 46   intptr_t used() const { return used_; } | 48   intptr_t used() const { return used_; } | 
| 47   intptr_t count() const { return count_; } | 49   intptr_t count() const { return count_; } | 
| 48 | 50 | 
| 49   bool IsValidEntryAt(intptr_t i) const { | 51   bool IsValidEntryAt(intptr_t i) const { | 
| 50     ASSERT(((ValueAt(i) == 0) && | 52     ASSERT(((ValueAt(i) == 0) && | 
| 51             ((ObjectAt(i) == NULL) || | 53             ((ObjectAt(i) == NULL) || | 
| 52              (data_[ObjectIndex(i)] == kDeletedEntry))) || | 54              (data_[ObjectIndex(i)] == kDeletedEntry))) || | 
| 53            ((ValueAt(i) != 0) && | 55            ((ValueAt(i) != 0) && | 
| 54             (ObjectAt(i) != NULL) && | 56             (ObjectAt(i) != NULL) && | 
| 55             (data_[ObjectIndex(i)] != kDeletedEntry))); | 57             (data_[ObjectIndex(i)] != kDeletedEntry))); | 
| 56     return (data_[ValueIndex(i)] != 0); | 58     return (data_[ValueIndex(i)] != 0); | 
| 57   } | 59   } | 
| 58 | 60 | 
| 59   void InvalidateAt(intptr_t i) { | 61   void InvalidateAt(intptr_t i) { | 
| 60     ASSERT(IsValidEntryAt(i)); | 62     ASSERT(IsValidEntryAt(i)); | 
| 61     SetValueAt(i, 0); | 63     SetValueAt(i, 0); | 
| 62   } | 64   } | 
| 63 | 65 | 
| 64   RawObject* ObjectAt(intptr_t i) const { | 66   RawObject* ObjectAt(intptr_t i) const { | 
|  | 67     ASSERT(i >= 0); | 
|  | 68     ASSERT(i < size()); | 
| 65     return reinterpret_cast<RawObject*>(data_[ObjectIndex(i)]); | 69     return reinterpret_cast<RawObject*>(data_[ObjectIndex(i)]); | 
| 66   } | 70   } | 
| 67 | 71 | 
| 68   intptr_t ValueAt(intptr_t i) const { | 72   intptr_t ValueAt(intptr_t i) const { | 
|  | 73     ASSERT(i >= 0); | 
|  | 74     ASSERT(i < size()); | 
| 69     return data_[ValueIndex(i)]; | 75     return data_[ValueIndex(i)]; | 
| 70   } | 76   } | 
| 71 | 77 | 
| 72   WeakTable* SetValue(RawObject* key, intptr_t val); | 78   void SetValue(RawObject* key, intptr_t val); | 
| 73 | 79 | 
| 74   intptr_t GetValue(RawObject* key) const { | 80   intptr_t GetValue(RawObject* key) const { | 
| 75     intptr_t sz = size(); | 81     intptr_t mask = size() - 1; | 
| 76     intptr_t idx = Hash(key) % sz; | 82     intptr_t idx = Hash(key) & mask; | 
| 77     RawObject* obj = ObjectAt(idx); | 83     RawObject* obj = ObjectAt(idx); | 
| 78     while (obj != NULL) { | 84     while (obj != NULL) { | 
| 79       if (obj == key) { | 85       if (obj == key) { | 
| 80         return ValueAt(idx); | 86         return ValueAt(idx); | 
| 81       } | 87       } | 
| 82       idx = (idx + 1) % sz; | 88       idx = (idx + 1) & mask; | 
| 83       obj = ObjectAt(idx); | 89       obj = ObjectAt(idx); | 
| 84     } | 90     } | 
| 85     ASSERT(ValueAt(idx) == 0); | 91     ASSERT(ValueAt(idx) == 0); | 
| 86     return 0; | 92     return 0; | 
| 87   } | 93   } | 
| 88 | 94 | 
| 89  private: | 95  private: | 
| 90   enum { | 96   enum { | 
| 91     kObjectOffset = 0, | 97     kObjectOffset = 0, | 
| 92     kValueOffset, | 98     kValueOffset, | 
| 93     kEntrySize, | 99     kEntrySize, | 
| 94   }; | 100   }; | 
| 95 | 101 | 
| 96   static const intptr_t kDeletedEntry = 1;  // Equivalent to a tagged NULL. | 102   static const intptr_t kDeletedEntry = 1;  // Equivalent to a tagged NULL. | 
| 97   static const intptr_t kMinSize = 8; | 103   static const intptr_t kMinSize = 8; | 
| 98 | 104 | 
|  | 105   static intptr_t SizeFor(intptr_t count, intptr_t size); | 
| 99   static intptr_t LimitFor(intptr_t size) { | 106   static intptr_t LimitFor(intptr_t size) { | 
| 100     // Maintain a maximum of 75% fill rate. | 107     // Maintain a maximum of 75% fill rate. | 
| 101     return 3 * (size / 4); | 108     return 3 * (size / 4); | 
| 102   } | 109   } | 
| 103   intptr_t limit() const { return LimitFor(size()); } | 110   intptr_t limit() const { return LimitFor(size()); } | 
| 104 | 111 | 
| 105   intptr_t index(intptr_t i) const { | 112   intptr_t index(intptr_t i) const { | 
| 106     ASSERT(i >= 0); |  | 
| 107     ASSERT(i < size()); |  | 
| 108     return i * kEntrySize; | 113     return i * kEntrySize; | 
| 109   } | 114   } | 
| 110 | 115 | 
| 111   void set_used(intptr_t val) { | 116   void set_used(intptr_t val) { | 
| 112     ASSERT(val <= limit()); | 117     ASSERT(val <= limit()); | 
| 113     used_ = val; | 118     used_ = val; | 
| 114   } | 119   } | 
| 115 | 120 | 
| 116   void set_count(intptr_t val) { | 121   void set_count(intptr_t val) { | 
| 117     ASSERT(val <= limit()); | 122     ASSERT(val <= limit()); | 
| 118     ASSERT(val <= used()); | 123     ASSERT(val <= used()); | 
| 119     count_ = val; | 124     count_ = val; | 
| 120   } | 125   } | 
| 121 | 126 | 
| 122   intptr_t ObjectIndex(intptr_t i) const { | 127   intptr_t ObjectIndex(intptr_t i) const { | 
| 123     return index(i) + kObjectOffset; | 128     return index(i) + kObjectOffset; | 
| 124   } | 129   } | 
| 125 | 130 | 
| 126   intptr_t ValueIndex(intptr_t i) const { | 131   intptr_t ValueIndex(intptr_t i) const { | 
| 127     return index(i) + kValueOffset; | 132     return index(i) + kValueOffset; | 
| 128   } | 133   } | 
| 129 | 134 | 
| 130   void SetObjectAt(intptr_t i, RawObject* key) { | 135   void SetObjectAt(intptr_t i, RawObject* key) { | 
|  | 136     ASSERT(i >= 0); | 
|  | 137     ASSERT(i < size()); | 
| 131     data_[ObjectIndex(i)] = reinterpret_cast<intptr_t>(key); | 138     data_[ObjectIndex(i)] = reinterpret_cast<intptr_t>(key); | 
| 132   } | 139   } | 
| 133 | 140 | 
| 134   void SetValueAt(intptr_t i, intptr_t val) { | 141   void SetValueAt(intptr_t i, intptr_t val) { | 
|  | 142     ASSERT(i >= 0); | 
|  | 143     ASSERT(i < size()); | 
| 135     // Setting a value of 0 is equivalent to invalidating the entry. | 144     // Setting a value of 0 is equivalent to invalidating the entry. | 
| 136     if (val == 0) { | 145     if (val == 0) { | 
| 137       data_[ObjectIndex(i)] = kDeletedEntry; | 146       data_[ObjectIndex(i)] = kDeletedEntry; | 
| 138       set_count(count() - 1); | 147       set_count(count() - 1); | 
| 139     } | 148     } | 
| 140     data_[ValueIndex(i)] = val; | 149     data_[ValueIndex(i)] = val; | 
| 141   } | 150   } | 
| 142 | 151 | 
| 143   WeakTable* Rehash(); | 152   void Rehash(); | 
| 144 | 153 | 
| 145   static intptr_t Hash(RawObject* key) { | 154   static intptr_t Hash(RawObject* key) { | 
| 146     return reinterpret_cast<intptr_t>(key) >> kObjectAlignmentLog2; | 155     return reinterpret_cast<intptr_t>(key) >> kObjectAlignmentLog2; | 
| 147   } | 156   } | 
| 148 | 157 | 
| 149   // data_ contains size_ tuples of key/value. | 158   // data_ contains size_ tuples of key/value. | 
| 150   intptr_t* data_; | 159   intptr_t* data_; | 
| 151   // size_ keeps the number of entries in data_. used_ maintains the number of | 160   // size_ keeps the number of entries in data_. used_ maintains the number of | 
| 152   // non-NULL entries and will trigger rehashing if needed. count_ stores the | 161   // non-NULL entries and will trigger rehashing if needed. count_ stores the | 
| 153   // number valid entries, and will determine the size_ after rehashing. | 162   // number valid entries, and will determine the size_ after rehashing. | 
| 154   intptr_t size_; | 163   intptr_t size_; | 
| 155   intptr_t used_; | 164   intptr_t used_; | 
| 156   intptr_t count_; | 165   intptr_t count_; | 
| 157 | 166 | 
| 158   DISALLOW_IMPLICIT_CONSTRUCTORS(WeakTable); | 167   DISALLOW_COPY_AND_ASSIGN(WeakTable); | 
| 159 }; | 168 }; | 
| 160 | 169 | 
| 161 }  // namespace dart | 170 }  // namespace dart | 
| 162 | 171 | 
| 163 #endif  // VM_WEAK_TABLE_H_ | 172 #endif  // VM_WEAK_TABLE_H_ | 
| OLD | NEW | 
|---|