PageRenderTime 66ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/deps/v8/src/unique.h

https://gitlab.com/GeekSir/node
C Header | 413 lines | 292 code | 63 blank | 58 comment | 66 complexity | c763807c065c7f27ddd1a88409fe2877 MD5 | raw file
Possible License(s): 0BSD, Apache-2.0, MPL-2.0-no-copyleft-exception, JSON, WTFPL, CC-BY-SA-3.0, Unlicense, ISC, BSD-3-Clause, MIT, AGPL-3.0
  1. // Copyright 2013 the V8 project authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef V8_HYDROGEN_UNIQUE_H_
  5. #define V8_HYDROGEN_UNIQUE_H_
  6. #include "src/handles.h"
  7. #include "src/objects.h"
  8. #include "src/string-stream.h"
  9. #include "src/utils.h"
  10. #include "src/zone.h"
  11. namespace v8 {
  12. namespace internal {
  13. template <typename T>
  14. class UniqueSet;
  15. // Represents a handle to an object on the heap, but with the additional
  16. // ability of checking for equality and hashing without accessing the heap.
  17. //
  18. // Creating a Unique<T> requires first dereferencing the handle to obtain
  19. // the address of the object, which is used as the hashcode and the basis for
  20. // comparison. The object can be moved later by the GC, but comparison
  21. // and hashing use the old address of the object, without dereferencing it.
  22. //
  23. // Careful! Comparison of two Uniques is only correct if both were created
  24. // in the same "era" of GC or if at least one is a non-movable object.
  25. template <typename T>
  26. class Unique {
  27. public:
  28. // TODO(titzer): make private and introduce a uniqueness scope.
  29. explicit Unique(Handle<T> handle) {
  30. if (handle.is_null()) {
  31. raw_address_ = NULL;
  32. } else {
  33. // This is a best-effort check to prevent comparing Unique<T>'s created
  34. // in different GC eras; we require heap allocation to be disallowed at
  35. // creation time.
  36. // NOTE: we currently consider maps to be non-movable, so no special
  37. // assurance is required for creating a Unique<Map>.
  38. // TODO(titzer): other immortable immovable objects are also fine.
  39. DCHECK(!AllowHeapAllocation::IsAllowed() || handle->IsMap());
  40. raw_address_ = reinterpret_cast<Address>(*handle);
  41. DCHECK_NE(raw_address_, NULL); // Non-null should imply non-zero address.
  42. }
  43. handle_ = handle;
  44. }
  45. // TODO(titzer): this is a hack to migrate to Unique<T> incrementally.
  46. Unique(Address raw_address, Handle<T> handle)
  47. : raw_address_(raw_address), handle_(handle) { }
  48. // Constructor for handling automatic up casting.
  49. // Eg. Unique<JSFunction> can be passed when Unique<Object> is expected.
  50. template <class S> Unique(Unique<S> uniq) {
  51. #ifdef DEBUG
  52. T* a = NULL;
  53. S* b = NULL;
  54. a = b; // Fake assignment to enforce type checks.
  55. USE(a);
  56. #endif
  57. raw_address_ = uniq.raw_address_;
  58. handle_ = uniq.handle_;
  59. }
  60. template <typename U>
  61. inline bool operator==(const Unique<U>& other) const {
  62. DCHECK(IsInitialized() && other.IsInitialized());
  63. return raw_address_ == other.raw_address_;
  64. }
  65. template <typename U>
  66. inline bool operator!=(const Unique<U>& other) const {
  67. DCHECK(IsInitialized() && other.IsInitialized());
  68. return raw_address_ != other.raw_address_;
  69. }
  70. inline intptr_t Hashcode() const {
  71. DCHECK(IsInitialized());
  72. return reinterpret_cast<intptr_t>(raw_address_);
  73. }
  74. inline bool IsNull() const {
  75. DCHECK(IsInitialized());
  76. return raw_address_ == NULL;
  77. }
  78. inline bool IsKnownGlobal(void* global) const {
  79. DCHECK(IsInitialized());
  80. return raw_address_ == reinterpret_cast<Address>(global);
  81. }
  82. inline Handle<T> handle() const {
  83. return handle_;
  84. }
  85. template <class S> static Unique<T> cast(Unique<S> that) {
  86. return Unique<T>(that.raw_address_, Handle<T>::cast(that.handle_));
  87. }
  88. inline bool IsInitialized() const {
  89. return raw_address_ != NULL || handle_.is_null();
  90. }
  91. // TODO(titzer): this is a hack to migrate to Unique<T> incrementally.
  92. static Unique<T> CreateUninitialized(Handle<T> handle) {
  93. return Unique<T>(reinterpret_cast<Address>(NULL), handle);
  94. }
  95. static Unique<T> CreateImmovable(Handle<T> handle) {
  96. return Unique<T>(reinterpret_cast<Address>(*handle), handle);
  97. }
  98. friend class UniqueSet<T>; // Uses internal details for speed.
  99. template <class U>
  100. friend class Unique; // For comparing raw_address values.
  101. template <class U>
  102. friend class PrintableUnique; // For automatic up casting.
  103. protected:
  104. Unique<T>() : raw_address_(NULL) { }
  105. Address raw_address_;
  106. Handle<T> handle_;
  107. friend class SideEffectsTracker;
  108. };
  109. // TODO(danno): At some point if all of the uses of Unique end up using
  110. // PrintableUnique, then we should merge PrintableUnique into Unique and
  111. // predicate generating the printable string on a "am I tracing" check.
  112. template <class T>
  113. class PrintableUnique : public Unique<T> {
  114. public:
  115. // TODO(titzer): make private and introduce a uniqueness scope.
  116. explicit PrintableUnique(Zone* zone, Handle<T> handle) : Unique<T>(handle) {
  117. InitializeString(zone);
  118. }
  119. // TODO(titzer): this is a hack to migrate to Unique<T> incrementally.
  120. PrintableUnique(Zone* zone, Address raw_address, Handle<T> handle)
  121. : Unique<T>(raw_address, handle) {
  122. InitializeString(zone);
  123. }
  124. // Constructor for handling automatic up casting.
  125. // Eg. PrintableUnique<JSFunction> can be passed when PrintableUnique<Object>
  126. // is expected.
  127. template <class S>
  128. PrintableUnique(PrintableUnique<S> uniq) // NOLINT
  129. : Unique<T>(Handle<T>()) {
  130. #ifdef DEBUG
  131. T* a = NULL;
  132. S* b = NULL;
  133. a = b; // Fake assignment to enforce type checks.
  134. USE(a);
  135. #endif
  136. this->raw_address_ = uniq.raw_address_;
  137. this->handle_ = uniq.handle_;
  138. string_ = uniq.string();
  139. }
  140. // TODO(titzer): this is a hack to migrate to Unique<T> incrementally.
  141. static PrintableUnique<T> CreateUninitialized(Zone* zone, Handle<T> handle) {
  142. return PrintableUnique<T>(zone, reinterpret_cast<Address>(NULL), handle);
  143. }
  144. static PrintableUnique<T> CreateImmovable(Zone* zone, Handle<T> handle) {
  145. return PrintableUnique<T>(zone, reinterpret_cast<Address>(*handle), handle);
  146. }
  147. const char* string() { return string_; }
  148. private:
  149. const char* string_;
  150. void InitializeString(Zone* zone) {
  151. // The stringified version of the parameter must be calculated when the
  152. // Operator is constructed to avoid accessing the heap.
  153. HeapStringAllocator temp_allocator;
  154. StringStream stream(&temp_allocator);
  155. this->handle_->ShortPrint(&stream);
  156. SmartArrayPointer<const char> desc_string = stream.ToCString();
  157. const char* desc_chars = desc_string.get();
  158. int length = static_cast<int>(strlen(desc_chars));
  159. char* desc_copy = zone->NewArray<char>(length + 1);
  160. memcpy(desc_copy, desc_chars, length + 1);
  161. string_ = desc_copy;
  162. }
  163. };
  164. template <typename T>
  165. class UniqueSet V8_FINAL : public ZoneObject {
  166. public:
  167. // Constructor. A new set will be empty.
  168. UniqueSet() : size_(0), capacity_(0), array_(NULL) { }
  169. // Capacity constructor. A new set will be empty.
  170. UniqueSet(int capacity, Zone* zone)
  171. : size_(0), capacity_(capacity),
  172. array_(zone->NewArray<Unique<T> >(capacity)) {
  173. DCHECK(capacity <= kMaxCapacity);
  174. }
  175. // Singleton constructor.
  176. UniqueSet(Unique<T> uniq, Zone* zone)
  177. : size_(1), capacity_(1), array_(zone->NewArray<Unique<T> >(1)) {
  178. array_[0] = uniq;
  179. }
  180. // Add a new element to this unique set. Mutates this set. O(|this|).
  181. void Add(Unique<T> uniq, Zone* zone) {
  182. DCHECK(uniq.IsInitialized());
  183. // Keep the set sorted by the {raw_address} of the unique elements.
  184. for (int i = 0; i < size_; i++) {
  185. if (array_[i] == uniq) return;
  186. if (array_[i].raw_address_ > uniq.raw_address_) {
  187. // Insert in the middle.
  188. Grow(size_ + 1, zone);
  189. for (int j = size_ - 1; j >= i; j--) array_[j + 1] = array_[j];
  190. array_[i] = uniq;
  191. size_++;
  192. return;
  193. }
  194. }
  195. // Append the element to the the end.
  196. Grow(size_ + 1, zone);
  197. array_[size_++] = uniq;
  198. }
  199. // Remove an element from this set. Mutates this set. O(|this|)
  200. void Remove(Unique<T> uniq) {
  201. for (int i = 0; i < size_; i++) {
  202. if (array_[i] == uniq) {
  203. while (++i < size_) array_[i - 1] = array_[i];
  204. size_--;
  205. return;
  206. }
  207. }
  208. }
  209. // Compare this set against another set. O(|this|).
  210. bool Equals(const UniqueSet<T>* that) const {
  211. if (that->size_ != this->size_) return false;
  212. for (int i = 0; i < this->size_; i++) {
  213. if (this->array_[i] != that->array_[i]) return false;
  214. }
  215. return true;
  216. }
  217. // Check whether this set contains the given element. O(|this|)
  218. // TODO(titzer): use binary search for large sets to make this O(log|this|)
  219. template <typename U>
  220. bool Contains(const Unique<U> elem) const {
  221. for (int i = 0; i < this->size_; ++i) {
  222. Unique<T> cand = this->array_[i];
  223. if (cand.raw_address_ >= elem.raw_address_) {
  224. return cand.raw_address_ == elem.raw_address_;
  225. }
  226. }
  227. return false;
  228. }
  229. // Check if this set is a subset of the given set. O(|this| + |that|).
  230. bool IsSubset(const UniqueSet<T>* that) const {
  231. if (that->size_ < this->size_) return false;
  232. int j = 0;
  233. for (int i = 0; i < this->size_; i++) {
  234. Unique<T> sought = this->array_[i];
  235. while (true) {
  236. if (sought == that->array_[j++]) break;
  237. // Fail whenever there are more elements in {this} than {that}.
  238. if ((this->size_ - i) > (that->size_ - j)) return false;
  239. }
  240. }
  241. return true;
  242. }
  243. // Returns a new set representing the intersection of this set and the other.
  244. // O(|this| + |that|).
  245. UniqueSet<T>* Intersect(const UniqueSet<T>* that, Zone* zone) const {
  246. if (that->size_ == 0 || this->size_ == 0) return new(zone) UniqueSet<T>();
  247. UniqueSet<T>* out = new(zone) UniqueSet<T>(
  248. Min(this->size_, that->size_), zone);
  249. int i = 0, j = 0, k = 0;
  250. while (i < this->size_ && j < that->size_) {
  251. Unique<T> a = this->array_[i];
  252. Unique<T> b = that->array_[j];
  253. if (a == b) {
  254. out->array_[k++] = a;
  255. i++;
  256. j++;
  257. } else if (a.raw_address_ < b.raw_address_) {
  258. i++;
  259. } else {
  260. j++;
  261. }
  262. }
  263. out->size_ = k;
  264. return out;
  265. }
  266. // Returns a new set representing the union of this set and the other.
  267. // O(|this| + |that|).
  268. UniqueSet<T>* Union(const UniqueSet<T>* that, Zone* zone) const {
  269. if (that->size_ == 0) return this->Copy(zone);
  270. if (this->size_ == 0) return that->Copy(zone);
  271. UniqueSet<T>* out = new(zone) UniqueSet<T>(
  272. this->size_ + that->size_, zone);
  273. int i = 0, j = 0, k = 0;
  274. while (i < this->size_ && j < that->size_) {
  275. Unique<T> a = this->array_[i];
  276. Unique<T> b = that->array_[j];
  277. if (a == b) {
  278. out->array_[k++] = a;
  279. i++;
  280. j++;
  281. } else if (a.raw_address_ < b.raw_address_) {
  282. out->array_[k++] = a;
  283. i++;
  284. } else {
  285. out->array_[k++] = b;
  286. j++;
  287. }
  288. }
  289. while (i < this->size_) out->array_[k++] = this->array_[i++];
  290. while (j < that->size_) out->array_[k++] = that->array_[j++];
  291. out->size_ = k;
  292. return out;
  293. }
  294. // Returns a new set representing all elements from this set which are not in
  295. // that set. O(|this| * |that|).
  296. UniqueSet<T>* Subtract(const UniqueSet<T>* that, Zone* zone) const {
  297. if (that->size_ == 0) return this->Copy(zone);
  298. UniqueSet<T>* out = new(zone) UniqueSet<T>(this->size_, zone);
  299. int i = 0, j = 0;
  300. while (i < this->size_) {
  301. Unique<T> cand = this->array_[i];
  302. if (!that->Contains(cand)) {
  303. out->array_[j++] = cand;
  304. }
  305. i++;
  306. }
  307. out->size_ = j;
  308. return out;
  309. }
  310. // Makes an exact copy of this set. O(|this|).
  311. UniqueSet<T>* Copy(Zone* zone) const {
  312. UniqueSet<T>* copy = new(zone) UniqueSet<T>(this->size_, zone);
  313. copy->size_ = this->size_;
  314. memcpy(copy->array_, this->array_, this->size_ * sizeof(Unique<T>));
  315. return copy;
  316. }
  317. void Clear() {
  318. size_ = 0;
  319. }
  320. inline int size() const {
  321. return size_;
  322. }
  323. inline Unique<T> at(int index) const {
  324. DCHECK(index >= 0 && index < size_);
  325. return array_[index];
  326. }
  327. private:
  328. // These sets should be small, since operations are implemented with simple
  329. // linear algorithms. Enforce a maximum size.
  330. static const int kMaxCapacity = 65535;
  331. uint16_t size_;
  332. uint16_t capacity_;
  333. Unique<T>* array_;
  334. // Grow the size of internal storage to be at least {size} elements.
  335. void Grow(int size, Zone* zone) {
  336. CHECK(size < kMaxCapacity); // Enforce maximum size.
  337. if (capacity_ < size) {
  338. int new_capacity = 2 * capacity_ + size;
  339. if (new_capacity > kMaxCapacity) new_capacity = kMaxCapacity;
  340. Unique<T>* new_array = zone->NewArray<Unique<T> >(new_capacity);
  341. if (size_ > 0) {
  342. memcpy(new_array, array_, size_ * sizeof(Unique<T>));
  343. }
  344. capacity_ = new_capacity;
  345. array_ = new_array;
  346. }
  347. }
  348. };
  349. } } // namespace v8::internal
  350. #endif // V8_HYDROGEN_UNIQUE_H_