v8-util.h 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. // Copyright 2014 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_UTIL_H_
  5. #define V8_UTIL_H_
  6. #include "v8.h" // NOLINT(build/include)
  7. #include <assert.h>
  8. #include <map>
  9. #include <vector>
  10. /**
  11. * Support for Persistent containers.
  12. *
  13. * C++11 embedders can use STL containers with Global values,
  14. * but pre-C++11 does not support the required move semantic and hence
  15. * may want these container classes.
  16. */
  17. namespace v8 {
  18. typedef uintptr_t PersistentContainerValue;
  19. static const uintptr_t kPersistentContainerNotFound = 0;
  20. enum PersistentContainerCallbackType {
  21. kNotWeak,
  22. // These correspond to v8::WeakCallbackType
  23. kWeakWithParameter,
  24. kWeakWithInternalFields
  25. };
  26. /**
  27. * A default trait implementation for PersistentValueMap which uses std::map
  28. * as a backing map.
  29. *
  30. * Users will have to implement their own weak callbacks & dispose traits.
  31. */
  32. template<typename K, typename V>
  33. class StdMapTraits {
  34. public:
  35. // STL map & related:
  36. typedef std::map<K, PersistentContainerValue> Impl;
  37. typedef typename Impl::iterator Iterator;
  38. static bool Empty(Impl* impl) { return impl->empty(); }
  39. static size_t Size(Impl* impl) { return impl->size(); }
  40. static void Swap(Impl& a, Impl& b) { std::swap(a, b); } // NOLINT
  41. static Iterator Begin(Impl* impl) { return impl->begin(); }
  42. static Iterator End(Impl* impl) { return impl->end(); }
  43. static K Key(Iterator it) { return it->first; }
  44. static PersistentContainerValue Value(Iterator it) { return it->second; }
  45. static PersistentContainerValue Set(Impl* impl, K key,
  46. PersistentContainerValue value) {
  47. std::pair<Iterator, bool> res = impl->insert(std::make_pair(key, value));
  48. PersistentContainerValue old_value = kPersistentContainerNotFound;
  49. if (!res.second) {
  50. old_value = res.first->second;
  51. res.first->second = value;
  52. }
  53. return old_value;
  54. }
  55. static PersistentContainerValue Get(Impl* impl, K key) {
  56. Iterator it = impl->find(key);
  57. if (it == impl->end()) return kPersistentContainerNotFound;
  58. return it->second;
  59. }
  60. static PersistentContainerValue Remove(Impl* impl, K key) {
  61. Iterator it = impl->find(key);
  62. if (it == impl->end()) return kPersistentContainerNotFound;
  63. PersistentContainerValue value = it->second;
  64. impl->erase(it);
  65. return value;
  66. }
  67. };
  68. /**
  69. * A default trait implementation for PersistentValueMap, which inherits
  70. * a std:map backing map from StdMapTraits and holds non-weak persistent
  71. * objects and has no special Dispose handling.
  72. *
  73. * You should not derive from this class, since MapType depends on the
  74. * surrounding class, and hence a subclass cannot simply inherit the methods.
  75. */
  76. template<typename K, typename V>
  77. class DefaultPersistentValueMapTraits : public StdMapTraits<K, V> {
  78. public:
  79. // Weak callback & friends:
  80. static const PersistentContainerCallbackType kCallbackType = kNotWeak;
  81. typedef PersistentValueMap<K, V, DefaultPersistentValueMapTraits<K, V> >
  82. MapType;
  83. typedef void WeakCallbackDataType;
  84. static WeakCallbackDataType* WeakCallbackParameter(
  85. MapType* map, const K& key, Local<V> value) {
  86. return nullptr;
  87. }
  88. static MapType* MapFromWeakCallbackInfo(
  89. const WeakCallbackInfo<WeakCallbackDataType>& data) {
  90. return nullptr;
  91. }
  92. static K KeyFromWeakCallbackInfo(
  93. const WeakCallbackInfo<WeakCallbackDataType>& data) {
  94. return K();
  95. }
  96. static void DisposeCallbackData(WeakCallbackDataType* data) { }
  97. static void Dispose(Isolate* isolate, Global<V> value, K key) {}
  98. };
  99. template <typename K, typename V>
  100. class DefaultGlobalMapTraits : public StdMapTraits<K, V> {
  101. private:
  102. template <typename T>
  103. struct RemovePointer;
  104. public:
  105. // Weak callback & friends:
  106. static const PersistentContainerCallbackType kCallbackType = kNotWeak;
  107. typedef GlobalValueMap<K, V, DefaultGlobalMapTraits<K, V> > MapType;
  108. typedef void WeakCallbackDataType;
  109. static WeakCallbackDataType* WeakCallbackParameter(MapType* map, const K& key,
  110. Local<V> value) {
  111. return nullptr;
  112. }
  113. static MapType* MapFromWeakCallbackInfo(
  114. const WeakCallbackInfo<WeakCallbackDataType>& data) {
  115. return nullptr;
  116. }
  117. static K KeyFromWeakCallbackInfo(
  118. const WeakCallbackInfo<WeakCallbackDataType>& data) {
  119. return K();
  120. }
  121. static void DisposeCallbackData(WeakCallbackDataType* data) {}
  122. static void OnWeakCallback(
  123. const WeakCallbackInfo<WeakCallbackDataType>& data) {}
  124. static void Dispose(Isolate* isolate, Global<V> value, K key) {}
  125. // This is a second pass callback, so SetSecondPassCallback cannot be called.
  126. static void DisposeWeak(const WeakCallbackInfo<WeakCallbackDataType>& data) {}
  127. private:
  128. template <typename T>
  129. struct RemovePointer<T*> {
  130. typedef T Type;
  131. };
  132. };
  133. /**
  134. * A map wrapper that allows using Global as a mapped value.
  135. * C++11 embedders don't need this class, as they can use Global
  136. * directly in std containers.
  137. *
  138. * The map relies on a backing map, whose type and accessors are described
  139. * by the Traits class. The backing map will handle values of type
  140. * PersistentContainerValue, with all conversion into and out of V8
  141. * handles being transparently handled by this class.
  142. */
  143. template <typename K, typename V, typename Traits>
  144. class PersistentValueMapBase {
  145. public:
  146. Isolate* GetIsolate() { return isolate_; }
  147. /**
  148. * Return size of the map.
  149. */
  150. size_t Size() { return Traits::Size(&impl_); }
  151. /**
  152. * Return whether the map holds weak persistents.
  153. */
  154. bool IsWeak() { return Traits::kCallbackType != kNotWeak; }
  155. /**
  156. * Get value stored in map.
  157. */
  158. Local<V> Get(const K& key) {
  159. return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, key)));
  160. }
  161. /**
  162. * Check whether a value is contained in the map.
  163. */
  164. bool Contains(const K& key) {
  165. return Traits::Get(&impl_, key) != kPersistentContainerNotFound;
  166. }
  167. /**
  168. * Get value stored in map and set it in returnValue.
  169. * Return true if a value was found.
  170. */
  171. bool SetReturnValue(const K& key,
  172. ReturnValue<Value> returnValue) {
  173. return SetReturnValueFromVal(&returnValue, Traits::Get(&impl_, key));
  174. }
  175. /**
  176. * Return value for key and remove it from the map.
  177. */
  178. Global<V> Remove(const K& key) {
  179. return Release(Traits::Remove(&impl_, key)).Pass();
  180. }
  181. /**
  182. * Traverses the map repeatedly,
  183. * in case side effects of disposal cause insertions.
  184. **/
  185. void Clear() {
  186. typedef typename Traits::Iterator It;
  187. HandleScope handle_scope(isolate_);
  188. // TODO(dcarney): figure out if this swap and loop is necessary.
  189. while (!Traits::Empty(&impl_)) {
  190. typename Traits::Impl impl;
  191. Traits::Swap(impl_, impl);
  192. for (It i = Traits::Begin(&impl); i != Traits::End(&impl); ++i) {
  193. Traits::Dispose(isolate_, Release(Traits::Value(i)).Pass(),
  194. Traits::Key(i));
  195. }
  196. }
  197. }
  198. /**
  199. * Helper class for GetReference/SetWithReference. Do not use outside
  200. * that context.
  201. */
  202. class PersistentValueReference {
  203. public:
  204. PersistentValueReference() : value_(kPersistentContainerNotFound) { }
  205. PersistentValueReference(const PersistentValueReference& other)
  206. : value_(other.value_) { }
  207. Local<V> NewLocal(Isolate* isolate) const {
  208. return Local<V>::New(isolate, FromVal(value_));
  209. }
  210. bool IsEmpty() const {
  211. return value_ == kPersistentContainerNotFound;
  212. }
  213. template<typename T>
  214. bool SetReturnValue(ReturnValue<T> returnValue) {
  215. return SetReturnValueFromVal(&returnValue, value_);
  216. }
  217. void Reset() {
  218. value_ = kPersistentContainerNotFound;
  219. }
  220. void operator=(const PersistentValueReference& other) {
  221. value_ = other.value_;
  222. }
  223. private:
  224. friend class PersistentValueMapBase;
  225. friend class PersistentValueMap<K, V, Traits>;
  226. friend class GlobalValueMap<K, V, Traits>;
  227. explicit PersistentValueReference(PersistentContainerValue value)
  228. : value_(value) { }
  229. void operator=(PersistentContainerValue value) {
  230. value_ = value;
  231. }
  232. PersistentContainerValue value_;
  233. };
  234. /**
  235. * Get a reference to a map value. This enables fast, repeated access
  236. * to a value stored in the map while the map remains unchanged.
  237. *
  238. * Careful: This is potentially unsafe, so please use with care.
  239. * The value will become invalid if the value for this key changes
  240. * in the underlying map, as a result of Set or Remove for the same
  241. * key; as a result of the weak callback for the same key; or as a
  242. * result of calling Clear() or destruction of the map.
  243. */
  244. PersistentValueReference GetReference(const K& key) {
  245. return PersistentValueReference(Traits::Get(&impl_, key));
  246. }
  247. protected:
  248. explicit PersistentValueMapBase(Isolate* isolate)
  249. : isolate_(isolate), label_(nullptr) {}
  250. PersistentValueMapBase(Isolate* isolate, const char* label)
  251. : isolate_(isolate), label_(label) {}
  252. ~PersistentValueMapBase() { Clear(); }
  253. Isolate* isolate() { return isolate_; }
  254. typename Traits::Impl* impl() { return &impl_; }
  255. static V* FromVal(PersistentContainerValue v) {
  256. return reinterpret_cast<V*>(v);
  257. }
  258. static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
  259. V* v = persistent->val_;
  260. persistent->val_ = nullptr;
  261. return reinterpret_cast<PersistentContainerValue>(v);
  262. }
  263. static PersistentContainerValue Leak(Global<V>* persistent) {
  264. return reinterpret_cast<PersistentContainerValue>(persistent->val_);
  265. }
  266. /**
  267. * Return a container value as Global and make sure the weak
  268. * callback is properly disposed of. All remove functionality should go
  269. * through this.
  270. */
  271. static Global<V> Release(PersistentContainerValue v) {
  272. Global<V> p;
  273. p.val_ = FromVal(v);
  274. if (Traits::kCallbackType != kNotWeak && p.IsWeak()) {
  275. Traits::DisposeCallbackData(
  276. p.template ClearWeak<typename Traits::WeakCallbackDataType>());
  277. }
  278. return p.Pass();
  279. }
  280. void RemoveWeak(const K& key) {
  281. Global<V> p;
  282. p.val_ = FromVal(Traits::Remove(&impl_, key));
  283. p.Reset();
  284. }
  285. void AnnotateStrongRetainer(Global<V>* persistent) {
  286. persistent->AnnotateStrongRetainer(label_);
  287. }
  288. private:
  289. PersistentValueMapBase(PersistentValueMapBase&);
  290. void operator=(PersistentValueMapBase&);
  291. static bool SetReturnValueFromVal(ReturnValue<Value>* returnValue,
  292. PersistentContainerValue value) {
  293. bool hasValue = value != kPersistentContainerNotFound;
  294. if (hasValue) {
  295. returnValue->SetInternal(
  296. *reinterpret_cast<internal::Address*>(FromVal(value)));
  297. }
  298. return hasValue;
  299. }
  300. Isolate* isolate_;
  301. typename Traits::Impl impl_;
  302. const char* label_;
  303. };
  304. template <typename K, typename V, typename Traits>
  305. class PersistentValueMap : public PersistentValueMapBase<K, V, Traits> {
  306. public:
  307. explicit PersistentValueMap(Isolate* isolate)
  308. : PersistentValueMapBase<K, V, Traits>(isolate) {}
  309. PersistentValueMap(Isolate* isolate, const char* label)
  310. : PersistentValueMapBase<K, V, Traits>(isolate, label) {}
  311. typedef
  312. typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
  313. PersistentValueReference;
  314. /**
  315. * Put value into map. Depending on Traits::kIsWeak, the value will be held
  316. * by the map strongly or weakly.
  317. * Returns old value as Global.
  318. */
  319. Global<V> Set(const K& key, Local<V> value) {
  320. Global<V> persistent(this->isolate(), value);
  321. return SetUnique(key, &persistent);
  322. }
  323. /**
  324. * Put value into map, like Set(const K&, Local<V>).
  325. */
  326. Global<V> Set(const K& key, Global<V> value) {
  327. return SetUnique(key, &value);
  328. }
  329. /**
  330. * Put the value into the map, and set the 'weak' callback when demanded
  331. * by the Traits class.
  332. */
  333. Global<V> SetUnique(const K& key, Global<V>* persistent) {
  334. if (Traits::kCallbackType == kNotWeak) {
  335. this->AnnotateStrongRetainer(persistent);
  336. } else {
  337. WeakCallbackType callback_type =
  338. Traits::kCallbackType == kWeakWithInternalFields
  339. ? WeakCallbackType::kInternalFields
  340. : WeakCallbackType::kParameter;
  341. Local<V> value(Local<V>::New(this->isolate(), *persistent));
  342. persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
  343. Traits::WeakCallbackParameter(this, key, value), WeakCallback,
  344. callback_type);
  345. }
  346. PersistentContainerValue old_value =
  347. Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
  348. return this->Release(old_value).Pass();
  349. }
  350. /**
  351. * Put a value into the map and update the reference.
  352. * Restrictions of GetReference apply here as well.
  353. */
  354. Global<V> Set(const K& key, Global<V> value,
  355. PersistentValueReference* reference) {
  356. *reference = this->Leak(&value);
  357. return SetUnique(key, &value);
  358. }
  359. private:
  360. static void WeakCallback(
  361. const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
  362. if (Traits::kCallbackType != kNotWeak) {
  363. PersistentValueMap<K, V, Traits>* persistentValueMap =
  364. Traits::MapFromWeakCallbackInfo(data);
  365. K key = Traits::KeyFromWeakCallbackInfo(data);
  366. Traits::Dispose(data.GetIsolate(),
  367. persistentValueMap->Remove(key).Pass(), key);
  368. Traits::DisposeCallbackData(data.GetParameter());
  369. }
  370. }
  371. };
  372. template <typename K, typename V, typename Traits>
  373. class GlobalValueMap : public PersistentValueMapBase<K, V, Traits> {
  374. public:
  375. explicit GlobalValueMap(Isolate* isolate)
  376. : PersistentValueMapBase<K, V, Traits>(isolate) {}
  377. GlobalValueMap(Isolate* isolate, const char* label)
  378. : PersistentValueMapBase<K, V, Traits>(isolate, label) {}
  379. typedef
  380. typename PersistentValueMapBase<K, V, Traits>::PersistentValueReference
  381. PersistentValueReference;
  382. /**
  383. * Put value into map. Depending on Traits::kIsWeak, the value will be held
  384. * by the map strongly or weakly.
  385. * Returns old value as Global.
  386. */
  387. Global<V> Set(const K& key, Local<V> value) {
  388. Global<V> persistent(this->isolate(), value);
  389. return SetUnique(key, &persistent);
  390. }
  391. /**
  392. * Put value into map, like Set(const K&, Local<V>).
  393. */
  394. Global<V> Set(const K& key, Global<V> value) {
  395. return SetUnique(key, &value);
  396. }
  397. /**
  398. * Put the value into the map, and set the 'weak' callback when demanded
  399. * by the Traits class.
  400. */
  401. Global<V> SetUnique(const K& key, Global<V>* persistent) {
  402. if (Traits::kCallbackType == kNotWeak) {
  403. this->AnnotateStrongRetainer(persistent);
  404. } else {
  405. WeakCallbackType callback_type =
  406. Traits::kCallbackType == kWeakWithInternalFields
  407. ? WeakCallbackType::kInternalFields
  408. : WeakCallbackType::kParameter;
  409. Local<V> value(Local<V>::New(this->isolate(), *persistent));
  410. persistent->template SetWeak<typename Traits::WeakCallbackDataType>(
  411. Traits::WeakCallbackParameter(this, key, value), OnWeakCallback,
  412. callback_type);
  413. }
  414. PersistentContainerValue old_value =
  415. Traits::Set(this->impl(), key, this->ClearAndLeak(persistent));
  416. return this->Release(old_value).Pass();
  417. }
  418. /**
  419. * Put a value into the map and update the reference.
  420. * Restrictions of GetReference apply here as well.
  421. */
  422. Global<V> Set(const K& key, Global<V> value,
  423. PersistentValueReference* reference) {
  424. *reference = this->Leak(&value);
  425. return SetUnique(key, &value);
  426. }
  427. private:
  428. static void OnWeakCallback(
  429. const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
  430. if (Traits::kCallbackType != kNotWeak) {
  431. auto map = Traits::MapFromWeakCallbackInfo(data);
  432. K key = Traits::KeyFromWeakCallbackInfo(data);
  433. map->RemoveWeak(key);
  434. Traits::OnWeakCallback(data);
  435. data.SetSecondPassCallback(SecondWeakCallback);
  436. }
  437. }
  438. static void SecondWeakCallback(
  439. const WeakCallbackInfo<typename Traits::WeakCallbackDataType>& data) {
  440. Traits::DisposeWeak(data);
  441. }
  442. };
  443. /**
  444. * A map that uses Global as value and std::map as the backing
  445. * implementation. Persistents are held non-weak.
  446. *
  447. * C++11 embedders don't need this class, as they can use
  448. * Global directly in std containers.
  449. */
  450. template<typename K, typename V,
  451. typename Traits = DefaultPersistentValueMapTraits<K, V> >
  452. class StdPersistentValueMap : public PersistentValueMap<K, V, Traits> {
  453. public:
  454. explicit StdPersistentValueMap(Isolate* isolate)
  455. : PersistentValueMap<K, V, Traits>(isolate) {}
  456. };
  457. /**
  458. * A map that uses Global as value and std::map as the backing
  459. * implementation. Globals are held non-weak.
  460. *
  461. * C++11 embedders don't need this class, as they can use
  462. * Global directly in std containers.
  463. */
  464. template <typename K, typename V,
  465. typename Traits = DefaultGlobalMapTraits<K, V> >
  466. class StdGlobalValueMap : public GlobalValueMap<K, V, Traits> {
  467. public:
  468. explicit StdGlobalValueMap(Isolate* isolate)
  469. : GlobalValueMap<K, V, Traits>(isolate) {}
  470. };
  471. class DefaultPersistentValueVectorTraits {
  472. public:
  473. typedef std::vector<PersistentContainerValue> Impl;
  474. static void Append(Impl* impl, PersistentContainerValue value) {
  475. impl->push_back(value);
  476. }
  477. static bool IsEmpty(const Impl* impl) {
  478. return impl->empty();
  479. }
  480. static size_t Size(const Impl* impl) {
  481. return impl->size();
  482. }
  483. static PersistentContainerValue Get(const Impl* impl, size_t i) {
  484. return (i < impl->size()) ? impl->at(i) : kPersistentContainerNotFound;
  485. }
  486. static void ReserveCapacity(Impl* impl, size_t capacity) {
  487. impl->reserve(capacity);
  488. }
  489. static void Clear(Impl* impl) {
  490. impl->clear();
  491. }
  492. };
  493. /**
  494. * A vector wrapper that safely stores Global values.
  495. * C++11 embedders don't need this class, as they can use Global
  496. * directly in std containers.
  497. *
  498. * This class relies on a backing vector implementation, whose type and methods
  499. * are described by the Traits class. The backing map will handle values of type
  500. * PersistentContainerValue, with all conversion into and out of V8
  501. * handles being transparently handled by this class.
  502. */
  503. template<typename V, typename Traits = DefaultPersistentValueVectorTraits>
  504. class PersistentValueVector {
  505. public:
  506. explicit PersistentValueVector(Isolate* isolate) : isolate_(isolate) { }
  507. ~PersistentValueVector() {
  508. Clear();
  509. }
  510. /**
  511. * Append a value to the vector.
  512. */
  513. void Append(Local<V> value) {
  514. Global<V> persistent(isolate_, value);
  515. Traits::Append(&impl_, ClearAndLeak(&persistent));
  516. }
  517. /**
  518. * Append a persistent's value to the vector.
  519. */
  520. void Append(Global<V> persistent) {
  521. Traits::Append(&impl_, ClearAndLeak(&persistent));
  522. }
  523. /**
  524. * Are there any values in the vector?
  525. */
  526. bool IsEmpty() const {
  527. return Traits::IsEmpty(&impl_);
  528. }
  529. /**
  530. * How many elements are in the vector?
  531. */
  532. size_t Size() const {
  533. return Traits::Size(&impl_);
  534. }
  535. /**
  536. * Retrieve the i-th value in the vector.
  537. */
  538. Local<V> Get(size_t index) const {
  539. return Local<V>::New(isolate_, FromVal(Traits::Get(&impl_, index)));
  540. }
  541. /**
  542. * Remove all elements from the vector.
  543. */
  544. void Clear() {
  545. size_t length = Traits::Size(&impl_);
  546. for (size_t i = 0; i < length; i++) {
  547. Global<V> p;
  548. p.val_ = FromVal(Traits::Get(&impl_, i));
  549. }
  550. Traits::Clear(&impl_);
  551. }
  552. /**
  553. * Reserve capacity in the vector.
  554. * (Efficiency gains depend on the backing implementation.)
  555. */
  556. void ReserveCapacity(size_t capacity) {
  557. Traits::ReserveCapacity(&impl_, capacity);
  558. }
  559. private:
  560. static PersistentContainerValue ClearAndLeak(Global<V>* persistent) {
  561. V* v = persistent->val_;
  562. persistent->val_ = nullptr;
  563. return reinterpret_cast<PersistentContainerValue>(v);
  564. }
  565. static V* FromVal(PersistentContainerValue v) {
  566. return reinterpret_cast<V*>(v);
  567. }
  568. Isolate* isolate_;
  569. typename Traits::Impl impl_;
  570. };
  571. } // namespace v8
  572. #endif // V8_UTIL_H