Utility.h 17 KB

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