blob: 68166541bce4ff796eb49eb788614def857c4457 [file] [log] [blame]
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00001// Copyright 2013 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#ifndef V8_HYDROGEN_UNIQUE_H_
29#define V8_HYDROGEN_UNIQUE_H_
30
31#include "handles.h"
machenbach@chromium.org528ce022013-09-23 14:09:36 +000032#include "objects.h"
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000033#include "utils.h"
34#include "zone.h"
35
36namespace v8 {
37namespace internal {
38
39
40template <typename T>
41class UniqueSet;
42
43
44// Represents a handle to an object on the heap, but with the additional
45// ability of checking for equality and hashing without accessing the heap.
46//
47// Creating a Unique<T> requires first dereferencing the handle to obtain
48// the address of the object, which is used as the hashcode and the basis for
49// comparison. The object can be moved later by the GC, but comparison
50// and hashing use the old address of the object, without dereferencing it.
51//
52// Careful! Comparison of two Uniques is only correct if both were created
53// in the same "era" of GC or if at least one is a non-movable object.
54template <typename T>
55class Unique V8_FINAL {
56 public:
machenbach@chromium.org528ce022013-09-23 14:09:36 +000057 // TODO(titzer): make private and introduce a factory.
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000058 explicit Unique(Handle<T> handle) {
59 if (handle.is_null()) {
60 raw_address_ = NULL;
61 } else {
machenbach@chromium.org528ce022013-09-23 14:09:36 +000062 // This is a best-effort check to prevent comparing Unique<T>'s created
63 // in different GC eras; we require heap allocation to be disallowed at
64 // creation time.
65 // NOTE: we currently consider maps to be non-movable, so no special
66 // assurance is required for creating a Unique<Map>.
67 // TODO(titzer): other immortable immovable objects are also fine.
68 ASSERT(!AllowHeapAllocation::IsAllowed() || handle->IsMap());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000069 raw_address_ = reinterpret_cast<Address>(*handle);
machenbach@chromium.org528ce022013-09-23 14:09:36 +000070 ASSERT_NE(raw_address_, NULL); // Non-null should imply non-zero address.
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000071 }
72 handle_ = handle;
73 }
74
machenbach@chromium.org528ce022013-09-23 14:09:36 +000075 // TODO(titzer): this is a hack to migrate to Unique<T> incrementally.
76 Unique(Address raw_address, Handle<T> handle)
77 : raw_address_(raw_address), handle_(handle) { }
78
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000079 // Constructor for handling automatic up casting.
machenbach@chromium.org528ce022013-09-23 14:09:36 +000080 // Eg. Unique<JSFunction> can be passed when Unique<Object> is expected.
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000081 template <class S> Unique(Unique<S> uniq) {
82#ifdef DEBUG
83 T* a = NULL;
84 S* b = NULL;
85 a = b; // Fake assignment to enforce type checks.
86 USE(a);
87#endif
88 raw_address_ = uniq.raw_address_;
machenbach@chromium.org528ce022013-09-23 14:09:36 +000089 handle_ = uniq.handle_;
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000090 }
91
92 template <typename U>
machenbach@chromium.org528ce022013-09-23 14:09:36 +000093 inline bool operator==(const Unique<U>& other) const {
94 ASSERT(IsInitialized() && other.IsInitialized());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +000095 return raw_address_ == other.raw_address_;
96 }
97
98 template <typename U>
machenbach@chromium.org528ce022013-09-23 14:09:36 +000099 inline bool operator!=(const Unique<U>& other) const {
100 ASSERT(IsInitialized() && other.IsInitialized());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000101 return raw_address_ != other.raw_address_;
102 }
103
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000104 inline intptr_t Hashcode() const {
105 ASSERT(IsInitialized());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000106 return reinterpret_cast<intptr_t>(raw_address_);
107 }
108
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000109 inline bool IsNull() const {
110 ASSERT(IsInitialized());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000111 return raw_address_ == NULL;
112 }
113
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000114 // Extract the handle from this Unique in order to dereference it.
115 // WARNING: Only do this if you have access to the heap.
116 inline Handle<T> handle() const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000117 return handle_;
118 }
119
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000120 inline bool IsInitialized() const {
121 return raw_address_ != NULL || handle_.is_null();
122 }
123
124 // TODO(titzer): this is a hack to migrate to Unique<T> incrementally.
125 static Unique<T> CreateUninitialized(Handle<T> handle) {
126 return Unique<T>(static_cast<Address>(NULL), handle);
127 }
128
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000129 friend class UniqueSet<T>; // Uses internal details for speed.
130 template <class U>
131 friend class Unique; // For comparing raw_address values.
132
133 private:
134 Address raw_address_;
135 Handle<T> handle_;
136};
137
138
139template <typename T>
140class UniqueSet V8_FINAL : public ZoneObject {
141 public:
142 // Constructor. A new set will be empty.
143 UniqueSet() : size_(0), capacity_(0), array_(NULL) { }
144
145 // Add a new element to this unique set. Mutates this set. O(|this|).
146 void Add(Unique<T> uniq, Zone* zone) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000147 ASSERT(uniq.IsInitialized());
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000148 // Keep the set sorted by the {raw_address} of the unique elements.
149 for (int i = 0; i < size_; i++) {
150 if (array_[i] == uniq) return;
151 if (array_[i].raw_address_ > uniq.raw_address_) {
152 // Insert in the middle.
153 Grow(size_ + 1, zone);
154 for (int j = size_ - 1; j >= i; j--) array_[j + 1] = array_[j];
155 array_[i] = uniq;
156 size_++;
157 return;
158 }
159 }
160 // Append the element to the the end.
161 Grow(size_ + 1, zone);
162 array_[size_++] = uniq;
163 }
164
165 // Compare this set against another set. O(|this|).
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000166 bool Equals(UniqueSet<T>* that) const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000167 if (that->size_ != this->size_) return false;
168 for (int i = 0; i < this->size_; i++) {
169 if (this->array_[i] != that->array_[i]) return false;
170 }
171 return true;
172 }
173
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000174 template <typename U>
175 bool Contains(Unique<U> elem) const {
176 // TODO(titzer): use binary search for larger sets.
177 for (int i = 0; i < size_; i++) {
178 if (this->array_[i] == elem) return true;
179 }
180 return false;
181 }
182
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000183 // Check if this set is a subset of the given set. O(|this| + |that|).
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000184 bool IsSubset(UniqueSet<T>* that) const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000185 if (that->size_ < this->size_) return false;
186 int j = 0;
187 for (int i = 0; i < this->size_; i++) {
188 Unique<T> sought = this->array_[i];
189 while (true) {
190 if (sought == that->array_[j++]) break;
191 // Fail whenever there are more elements in {this} than {that}.
192 if ((this->size_ - i) > (that->size_ - j)) return false;
193 }
194 }
195 return true;
196 }
197
198 // Returns a new set representing the intersection of this set and the other.
199 // O(|this| + |that|).
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000200 UniqueSet<T>* Intersect(UniqueSet<T>* that, Zone* zone) const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000201 if (that->size_ == 0 || this->size_ == 0) return new(zone) UniqueSet<T>();
202
203 UniqueSet<T>* out = new(zone) UniqueSet<T>();
204 out->Grow(Min(this->size_, that->size_), zone);
205
206 int i = 0, j = 0, k = 0;
207 while (i < this->size_ && j < that->size_) {
208 Unique<T> a = this->array_[i];
209 Unique<T> b = that->array_[j];
210 if (a == b) {
211 out->array_[k++] = a;
212 i++;
213 j++;
214 } else if (a.raw_address_ < b.raw_address_) {
215 i++;
216 } else {
217 j++;
218 }
219 }
220
221 out->size_ = k;
222 return out;
223 }
224
225 // Returns a new set representing the union of this set and the other.
226 // O(|this| + |that|).
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000227 UniqueSet<T>* Union(UniqueSet<T>* that, Zone* zone) const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000228 if (that->size_ == 0) return this->Copy(zone);
229 if (this->size_ == 0) return that->Copy(zone);
230
231 UniqueSet<T>* out = new(zone) UniqueSet<T>();
232 out->Grow(this->size_ + that->size_, zone);
233
234 int i = 0, j = 0, k = 0;
235 while (i < this->size_ && j < that->size_) {
236 Unique<T> a = this->array_[i];
237 Unique<T> b = that->array_[j];
238 if (a == b) {
239 out->array_[k++] = a;
240 i++;
241 j++;
242 } else if (a.raw_address_ < b.raw_address_) {
243 out->array_[k++] = a;
244 i++;
245 } else {
246 out->array_[k++] = b;
247 j++;
248 }
249 }
250
251 while (i < this->size_) out->array_[k++] = this->array_[i++];
252 while (j < that->size_) out->array_[k++] = that->array_[j++];
253
254 out->size_ = k;
255 return out;
256 }
257
258 // Makes an exact copy of this set. O(|this| + |that|).
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000259 UniqueSet<T>* Copy(Zone* zone) const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000260 UniqueSet<T>* copy = new(zone) UniqueSet<T>();
261 copy->size_ = this->size_;
262 copy->capacity_ = this->size_;
263 copy->array_ = zone->NewArray<Unique<T> >(this->size_);
264 memcpy(copy->array_, this->array_, this->size_ * sizeof(Unique<T>));
265 return copy;
266 }
267
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000268 inline int size() const {
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000269 return size_;
270 }
271
machenbach@chromium.org528ce022013-09-23 14:09:36 +0000272 inline Unique<T> at(int index) const {
273 ASSERT(index >= 0 && index < size_);
274 return array_[index];
275 }
276
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +0000277 private:
278 // These sets should be small, since operations are implemented with simple
279 // linear algorithms. Enforce a maximum size.
280 static const int kMaxCapacity = 65535;
281
282 uint16_t size_;
283 uint16_t capacity_;
284 Unique<T>* array_;
285
286 // Grow the size of internal storage to be at least {size} elements.
287 void Grow(int size, Zone* zone) {
288 CHECK(size < kMaxCapacity); // Enforce maximum size.
289 if (capacity_ < size) {
290 int new_capacity = 2 * capacity_ + size;
291 if (new_capacity > kMaxCapacity) new_capacity = kMaxCapacity;
292 Unique<T>* new_array = zone->NewArray<Unique<T> >(new_capacity);
293 if (size_ > 0) {
294 memcpy(new_array, array_, size_ * sizeof(Unique<T>));
295 }
296 capacity_ = new_capacity;
297 array_ = new_array;
298 }
299 }
300};
301
302
303} } // namespace v8::internal
304
305#endif // V8_HYDROGEN_UNIQUE_H_