Utility.h 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. #ifndef js_Utility_h
  6. #define js_Utility_h
  7. #include "mozilla/Assertions.h"
  8. #include "mozilla/Atomics.h"
  9. #include "mozilla/Attributes.h"
  10. #include "mozilla/Compiler.h"
  11. #include "mozilla/Move.h"
  12. #include "mozilla/Scoped.h"
  13. #include "mozilla/TemplateLib.h"
  14. #include "mozilla/UniquePtr.h"
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #ifdef JS_OOM_DO_BACKTRACES
  18. #include <execinfo.h>
  19. #include <stdio.h>
  20. #endif
  21. #include "jstypes.h"
  22. /* The public JS engine namespace. */
  23. namespace JS {}
  24. /* The mozilla-shared reusable template/utility namespace. */
  25. namespace mozilla {}
  26. /* The private JS engine namespace. */
  27. namespace js {}
  28. #define JS_STATIC_ASSERT(cond) static_assert(cond, "JS_STATIC_ASSERT")
  29. #define JS_STATIC_ASSERT_IF(cond, expr) MOZ_STATIC_ASSERT_IF(cond, expr, "JS_STATIC_ASSERT_IF")
  30. extern MOZ_NORETURN MOZ_COLD JS_PUBLIC_API(void)
  31. JS_Assert(const char* s, const char* file, int ln);
  32. /*
  33. * Custom allocator support for SpiderMonkey
  34. */
  35. #if defined JS_USE_CUSTOM_ALLOCATOR
  36. # include "jscustomallocator.h"
  37. #else
  38. namespace js {
  39. namespace oom {
  40. /*
  41. * To make testing OOM in certain helper threads more effective,
  42. * allow restricting the OOM testing to a certain helper thread
  43. * type. This allows us to fail e.g. in off-thread script parsing
  44. * without causing an OOM in the main thread first.
  45. */
  46. enum ThreadType {
  47. THREAD_TYPE_NONE = 0, // 0
  48. THREAD_TYPE_MAIN, // 1
  49. THREAD_TYPE_ASMJS, // 2
  50. THREAD_TYPE_ION, // 3
  51. THREAD_TYPE_PARSE, // 4
  52. THREAD_TYPE_COMPRESS, // 5
  53. THREAD_TYPE_GCHELPER, // 6
  54. THREAD_TYPE_GCPARALLEL, // 7
  55. THREAD_TYPE_PROMISE_TASK, // 8
  56. THREAD_TYPE_MAX // Used to check shell function arguments
  57. };
  58. /*
  59. * Getter/Setter functions to encapsulate mozilla::ThreadLocal,
  60. * implementation is in jsutil.cpp.
  61. */
  62. # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
  63. extern bool InitThreadType(void);
  64. extern void SetThreadType(ThreadType);
  65. extern JS_FRIEND_API(uint32_t) GetThreadType(void);
  66. # else
  67. inline bool InitThreadType(void) { return true; }
  68. inline void SetThreadType(ThreadType t) {};
  69. inline uint32_t GetThreadType(void) { return 0; }
  70. # endif
  71. } /* namespace oom */
  72. } /* namespace js */
  73. # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
  74. #ifdef JS_OOM_BREAKPOINT
  75. static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); }
  76. #define JS_OOM_CALL_BP_FUNC() js_failedAllocBreakpoint()
  77. #else
  78. #define JS_OOM_CALL_BP_FUNC() do {} while(0)
  79. #endif
  80. namespace js {
  81. namespace oom {
  82. /*
  83. * Out of memory testing support. We provide various testing functions to
  84. * simulate OOM conditions and so we can test that they are handled correctly.
  85. */
  86. extern JS_PUBLIC_DATA(uint32_t) targetThread;
  87. extern JS_PUBLIC_DATA(uint64_t) maxAllocations;
  88. extern JS_PUBLIC_DATA(uint64_t) counter;
  89. extern JS_PUBLIC_DATA(bool) failAlways;
  90. extern void
  91. SimulateOOMAfter(uint64_t allocations, uint32_t thread, bool always);
  92. extern void
  93. ResetSimulatedOOM();
  94. inline bool
  95. IsThreadSimulatingOOM()
  96. {
  97. return js::oom::targetThread && js::oom::targetThread == js::oom::GetThreadType();
  98. }
  99. inline bool
  100. IsSimulatedOOMAllocation()
  101. {
  102. return IsThreadSimulatingOOM() &&
  103. (counter == maxAllocations || (counter > maxAllocations && failAlways));
  104. }
  105. inline bool
  106. ShouldFailWithOOM()
  107. {
  108. if (!IsThreadSimulatingOOM())
  109. return false;
  110. counter++;
  111. if (IsSimulatedOOMAllocation()) {
  112. JS_OOM_CALL_BP_FUNC();
  113. return true;
  114. }
  115. return false;
  116. }
  117. inline bool
  118. HadSimulatedOOM() {
  119. return counter >= maxAllocations;
  120. }
  121. } /* namespace oom */
  122. } /* namespace js */
  123. # define JS_OOM_POSSIBLY_FAIL() \
  124. do { \
  125. if (js::oom::ShouldFailWithOOM()) \
  126. return nullptr; \
  127. } while (0)
  128. # define JS_OOM_POSSIBLY_FAIL_BOOL() \
  129. do { \
  130. if (js::oom::ShouldFailWithOOM()) \
  131. return false; \
  132. } while (0)
  133. # else
  134. # define JS_OOM_POSSIBLY_FAIL() do {} while(0)
  135. # define JS_OOM_POSSIBLY_FAIL_BOOL() do {} while(0)
  136. namespace js {
  137. namespace oom {
  138. static inline bool IsSimulatedOOMAllocation() { return false; }
  139. static inline bool ShouldFailWithOOM() { return false; }
  140. } /* namespace oom */
  141. } /* namespace js */
  142. # endif /* DEBUG || JS_OOM_BREAKPOINT */
  143. namespace js {
  144. /* Disable OOM testing in sections which are not OOM safe. */
  145. struct MOZ_RAII JS_PUBLIC_DATA(AutoEnterOOMUnsafeRegion)
  146. {
  147. MOZ_NORETURN MOZ_COLD void crash(const char* reason);
  148. MOZ_NORETURN MOZ_COLD void crash(size_t size, const char* reason);
  149. using AnnotateOOMAllocationSizeCallback = void(*)(size_t);
  150. static AnnotateOOMAllocationSizeCallback annotateOOMSizeCallback;
  151. static void setAnnotateOOMAllocationSizeCallback(AnnotateOOMAllocationSizeCallback callback) {
  152. annotateOOMSizeCallback = callback;
  153. }
  154. #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
  155. AutoEnterOOMUnsafeRegion()
  156. : oomEnabled_(oom::IsThreadSimulatingOOM() && oom::maxAllocations != UINT64_MAX),
  157. oomAfter_(0)
  158. {
  159. if (oomEnabled_) {
  160. MOZ_ALWAYS_TRUE(owner_.compareExchange(nullptr, this));
  161. oomAfter_ = int64_t(oom::maxAllocations) - int64_t(oom::counter);
  162. oom::maxAllocations = UINT64_MAX;
  163. }
  164. }
  165. ~AutoEnterOOMUnsafeRegion() {
  166. if (oomEnabled_) {
  167. MOZ_ASSERT(oom::maxAllocations == UINT64_MAX);
  168. int64_t maxAllocations = int64_t(oom::counter) + oomAfter_;
  169. MOZ_ASSERT(maxAllocations >= 0,
  170. "alloc count + oom limit exceeds range, your oom limit is probably too large");
  171. oom::maxAllocations = uint64_t(maxAllocations);
  172. MOZ_ALWAYS_TRUE(owner_.compareExchange(this, nullptr));
  173. }
  174. }
  175. private:
  176. // Used to catch concurrent use from other threads.
  177. static mozilla::Atomic<AutoEnterOOMUnsafeRegion*> owner_;
  178. bool oomEnabled_;
  179. int64_t oomAfter_;
  180. #endif
  181. };
  182. } /* namespace js */
  183. static inline void* js_malloc(size_t bytes)
  184. {
  185. JS_OOM_POSSIBLY_FAIL();
  186. return malloc(bytes);
  187. }
  188. static inline void* js_calloc(size_t bytes)
  189. {
  190. JS_OOM_POSSIBLY_FAIL();
  191. return calloc(bytes, 1);
  192. }
  193. static inline void* js_calloc(size_t nmemb, size_t size)
  194. {
  195. JS_OOM_POSSIBLY_FAIL();
  196. return calloc(nmemb, size);
  197. }
  198. static inline void* js_realloc(void* p, size_t bytes)
  199. {
  200. // realloc() with zero size is not portable, as some implementations may
  201. // return nullptr on success and free |p| for this. We assume nullptr
  202. // indicates failure and that |p| is still valid.
  203. MOZ_ASSERT(bytes != 0);
  204. JS_OOM_POSSIBLY_FAIL();
  205. return realloc(p, bytes);
  206. }
  207. static inline void js_free(void* p)
  208. {
  209. free(p);
  210. }
  211. static inline char* js_strdup(const char* s)
  212. {
  213. JS_OOM_POSSIBLY_FAIL();
  214. return strdup(s);
  215. }
  216. #endif/* JS_USE_CUSTOM_ALLOCATOR */
  217. #include <new>
  218. /*
  219. * Low-level memory management in SpiderMonkey:
  220. *
  221. * ** Do not use the standard malloc/free/realloc: SpiderMonkey allows these
  222. * to be redefined (via JS_USE_CUSTOM_ALLOCATOR) and Gecko even #define's
  223. * these symbols.
  224. *
  225. * ** Do not use the builtin C++ operator new and delete: these throw on
  226. * error and we cannot override them not to.
  227. *
  228. * Allocation:
  229. *
  230. * - If the lifetime of the allocation is tied to the lifetime of a GC-thing
  231. * (that is, finalizing the GC-thing will free the allocation), call one of
  232. * the following functions:
  233. *
  234. * JSContext::{malloc_,realloc_,calloc_,new_}
  235. * JSRuntime::{malloc_,realloc_,calloc_,new_}
  236. *
  237. * These functions accumulate the number of bytes allocated which is used as
  238. * part of the GC-triggering heuristic.
  239. *
  240. * The difference between the JSContext and JSRuntime versions is that the
  241. * cx version reports an out-of-memory error on OOM. (This follows from the
  242. * general SpiderMonkey idiom that a JSContext-taking function reports its
  243. * own errors.)
  244. *
  245. * - Otherwise, use js_malloc/js_realloc/js_calloc/js_new
  246. *
  247. * Deallocation:
  248. *
  249. * - Ordinarily, use js_free/js_delete.
  250. *
  251. * - For deallocations during GC finalization, use one of the following
  252. * operations on the FreeOp provided to the finalizer:
  253. *
  254. * FreeOp::{free_,delete_}
  255. *
  256. * The advantage of these operations is that the memory is batched and freed
  257. * on another thread.
  258. */
  259. /*
  260. * Given a class which should provide a 'new' method, add
  261. * JS_DECLARE_NEW_METHODS (see js::MallocProvider for an example).
  262. *
  263. * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS,
  264. * or the build will break.
  265. */
  266. #define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS) \
  267. template <class T, typename... Args> \
  268. QUALIFIERS T * \
  269. NEWNAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \
  270. void* memory = ALLOCATOR(sizeof(T)); \
  271. return MOZ_LIKELY(memory) \
  272. ? new(memory) T(mozilla::Forward<Args>(args)...) \
  273. : nullptr; \
  274. }
  275. /*
  276. * Given a class which should provide 'make' methods, add
  277. * JS_DECLARE_MAKE_METHODS (see js::MallocProvider for an example). This
  278. * method is functionally the same as JS_DECLARE_NEW_METHODS: it just declares
  279. * methods that return mozilla::UniquePtr instances that will singly-manage
  280. * ownership of the created object.
  281. *
  282. * Note: Do not add a ; at the end of a use of JS_DECLARE_MAKE_METHODS,
  283. * or the build will break.
  284. */
  285. #define JS_DECLARE_MAKE_METHODS(MAKENAME, NEWNAME, QUALIFIERS)\
  286. template <class T, typename... Args> \
  287. QUALIFIERS mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
  288. MAKENAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \
  289. T* ptr = NEWNAME<T>(mozilla::Forward<Args>(args)...); \
  290. return mozilla::UniquePtr<T, JS::DeletePolicy<T>>(ptr); \
  291. }
  292. JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE)
  293. namespace js {
  294. /*
  295. * Calculate the number of bytes needed to allocate |numElems| contiguous
  296. * instances of type |T|. Return false if the calculation overflowed.
  297. */
  298. template <typename T>
  299. MOZ_MUST_USE inline bool
  300. CalculateAllocSize(size_t numElems, size_t* bytesOut)
  301. {
  302. *bytesOut = numElems * sizeof(T);
  303. return (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) == 0;
  304. }
  305. /*
  306. * Calculate the number of bytes needed to allocate a single instance of type
  307. * |T| followed by |numExtra| contiguous instances of type |Extra|. Return
  308. * false if the calculation overflowed.
  309. */
  310. template <typename T, typename Extra>
  311. MOZ_MUST_USE inline bool
  312. CalculateAllocSizeWithExtra(size_t numExtra, size_t* bytesOut)
  313. {
  314. *bytesOut = sizeof(T) + numExtra * sizeof(Extra);
  315. return (numExtra & mozilla::tl::MulOverflowMask<sizeof(Extra)>::value) == 0 &&
  316. *bytesOut >= sizeof(T);
  317. }
  318. } /* namespace js */
  319. template <class T>
  320. static MOZ_ALWAYS_INLINE void
  321. js_delete(const T* p)
  322. {
  323. if (p) {
  324. p->~T();
  325. js_free(const_cast<T*>(p));
  326. }
  327. }
  328. template<class T>
  329. static MOZ_ALWAYS_INLINE void
  330. js_delete_poison(const T* p)
  331. {
  332. if (p) {
  333. p->~T();
  334. memset(static_cast<void*>(const_cast<T*>(p)), 0x3B, sizeof(T));
  335. js_free(const_cast<T*>(p));
  336. }
  337. }
  338. template <class T>
  339. static MOZ_ALWAYS_INLINE T*
  340. js_pod_malloc()
  341. {
  342. return static_cast<T*>(js_malloc(sizeof(T)));
  343. }
  344. template <class T>
  345. static MOZ_ALWAYS_INLINE T*
  346. js_pod_calloc()
  347. {
  348. return static_cast<T*>(js_calloc(sizeof(T)));
  349. }
  350. template <class T>
  351. static MOZ_ALWAYS_INLINE T*
  352. js_pod_malloc(size_t numElems)
  353. {
  354. size_t bytes;
  355. if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes)))
  356. return nullptr;
  357. return static_cast<T*>(js_malloc(bytes));
  358. }
  359. template <class T>
  360. static MOZ_ALWAYS_INLINE T*
  361. js_pod_calloc(size_t numElems)
  362. {
  363. size_t bytes;
  364. if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes)))
  365. return nullptr;
  366. return static_cast<T*>(js_calloc(bytes));
  367. }
  368. template <class T>
  369. static MOZ_ALWAYS_INLINE T*
  370. js_pod_realloc(T* prior, size_t oldSize, size_t newSize)
  371. {
  372. MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value));
  373. size_t bytes;
  374. if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(newSize, &bytes)))
  375. return nullptr;
  376. return static_cast<T*>(js_realloc(prior, bytes));
  377. }
  378. namespace js {
  379. template<typename T>
  380. struct ScopedFreePtrTraits
  381. {
  382. typedef T* type;
  383. static T* empty() { return nullptr; }
  384. static void release(T* ptr) { js_free(ptr); }
  385. };
  386. SCOPED_TEMPLATE(ScopedJSFreePtr, ScopedFreePtrTraits)
  387. template <typename T>
  388. struct ScopedDeletePtrTraits : public ScopedFreePtrTraits<T>
  389. {
  390. static void release(T* ptr) { js_delete(ptr); }
  391. };
  392. SCOPED_TEMPLATE(ScopedJSDeletePtr, ScopedDeletePtrTraits)
  393. template <typename T>
  394. struct ScopedReleasePtrTraits : public ScopedFreePtrTraits<T>
  395. {
  396. static void release(T* ptr) { if (ptr) ptr->release(); }
  397. };
  398. SCOPED_TEMPLATE(ScopedReleasePtr, ScopedReleasePtrTraits)
  399. } /* namespace js */
  400. namespace JS {
  401. template<typename T>
  402. struct DeletePolicy
  403. {
  404. constexpr DeletePolicy() {}
  405. template<typename U>
  406. MOZ_IMPLICIT DeletePolicy(DeletePolicy<U> other,
  407. typename mozilla::EnableIf<mozilla::IsConvertible<U*, T*>::value,
  408. int>::Type dummy = 0)
  409. {}
  410. void operator()(const T* ptr) {
  411. js_delete(const_cast<T*>(ptr));
  412. }
  413. };
  414. struct FreePolicy
  415. {
  416. void operator()(const void* ptr) {
  417. js_free(const_cast<void*>(ptr));
  418. }
  419. };
  420. typedef mozilla::UniquePtr<char[], JS::FreePolicy> UniqueChars;
  421. typedef mozilla::UniquePtr<char16_t[], JS::FreePolicy> UniqueTwoByteChars;
  422. } // namespace JS
  423. namespace js {
  424. /* Integral types for all hash functions. */
  425. typedef uint32_t HashNumber;
  426. const unsigned HashNumberSizeBits = 32;
  427. namespace detail {
  428. /*
  429. * Given a raw hash code, h, return a number that can be used to select a hash
  430. * bucket.
  431. *
  432. * This function aims to produce as uniform an output distribution as possible,
  433. * especially in the most significant (leftmost) bits, even though the input
  434. * distribution may be highly nonrandom, given the constraints that this must
  435. * be deterministic and quick to compute.
  436. *
  437. * Since the leftmost bits of the result are best, the hash bucket index is
  438. * computed by doing ScrambleHashCode(h) / (2^32/N) or the equivalent
  439. * right-shift, not ScrambleHashCode(h) % N or the equivalent bit-mask.
  440. *
  441. * FIXME: OrderedHashTable uses a bit-mask; see bug 775896.
  442. */
  443. inline HashNumber
  444. ScrambleHashCode(HashNumber h)
  445. {
  446. /*
  447. * Simply returning h would not cause any hash tables to produce wrong
  448. * answers. But it can produce pathologically bad performance: The caller
  449. * right-shifts the result, keeping only the highest bits. The high bits of
  450. * hash codes are very often completely entropy-free. (So are the lowest
  451. * bits.)
  452. *
  453. * So we use Fibonacci hashing, as described in Knuth, The Art of Computer
  454. * Programming, 6.4. This mixes all the bits of the input hash code h.
  455. *
  456. * The value of goldenRatio is taken from the hex
  457. * expansion of the golden ratio, which starts 1.9E3779B9....
  458. * This value is especially good if values with consecutive hash codes
  459. * are stored in a hash table; see Knuth for details.
  460. */
  461. static const HashNumber goldenRatio = 0x9E3779B9U;
  462. return h * goldenRatio;
  463. }
  464. } /* namespace detail */
  465. } /* namespace js */
  466. /* sixgill annotation defines */
  467. #ifndef HAVE_STATIC_ANNOTATIONS
  468. # define HAVE_STATIC_ANNOTATIONS
  469. # ifdef XGILL_PLUGIN
  470. # define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND)))
  471. # define STATIC_PRECONDITION_ASSUME(COND) __attribute__((precondition_assume(#COND)))
  472. # define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND)))
  473. # define STATIC_POSTCONDITION_ASSUME(COND) __attribute__((postcondition_assume(#COND)))
  474. # define STATIC_INVARIANT(COND) __attribute__((invariant(#COND)))
  475. # define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND)))
  476. # define STATIC_ASSUME(COND) \
  477. JS_BEGIN_MACRO \
  478. __attribute__((assume_static(#COND), unused)) \
  479. int STATIC_PASTE1(assume_static_, __COUNTER__); \
  480. JS_END_MACRO
  481. # else /* XGILL_PLUGIN */
  482. # define STATIC_PRECONDITION(COND) /* nothing */
  483. # define STATIC_PRECONDITION_ASSUME(COND) /* nothing */
  484. # define STATIC_POSTCONDITION(COND) /* nothing */
  485. # define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */
  486. # define STATIC_INVARIANT(COND) /* nothing */
  487. # define STATIC_INVARIANT_ASSUME(COND) /* nothing */
  488. # define STATIC_ASSUME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
  489. # endif /* XGILL_PLUGIN */
  490. # define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference())
  491. #endif /* HAVE_STATIC_ANNOTATIONS */
  492. #endif /* js_Utility_h */