Line data Source code
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 :
7 : #ifndef js_Utility_h
8 : #define js_Utility_h
9 :
10 : #include "mozilla/Assertions.h"
11 : #include "mozilla/Atomics.h"
12 : #include "mozilla/Attributes.h"
13 : #include "mozilla/Compiler.h"
14 : #include "mozilla/Move.h"
15 : #include "mozilla/Scoped.h"
16 : #include "mozilla/TemplateLib.h"
17 : #include "mozilla/UniquePtr.h"
18 : #include "mozilla/WrappingOperations.h"
19 :
20 : #include <stdlib.h>
21 : #include <string.h>
22 :
23 : #ifdef JS_OOM_DO_BACKTRACES
24 : #include <execinfo.h>
25 : #include <stdio.h>
26 : #endif
27 :
28 : #include "jstypes.h"
29 :
30 : #include "mozmemory.h"
31 :
32 : /* The public JS engine namespace. */
33 : namespace JS {}
34 :
35 : /* The mozilla-shared reusable template/utility namespace. */
36 : namespace mozilla {}
37 :
38 : /* The private JS engine namespace. */
39 : namespace js {}
40 :
41 : #define JS_STATIC_ASSERT(cond) static_assert(cond, "JS_STATIC_ASSERT")
42 : #define JS_STATIC_ASSERT_IF(cond, expr) MOZ_STATIC_ASSERT_IF(cond, expr, "JS_STATIC_ASSERT_IF")
43 :
44 : extern MOZ_NORETURN MOZ_COLD JS_PUBLIC_API(void)
45 : JS_Assert(const char* s, const char* file, int ln);
46 :
47 : /*
48 : * Custom allocator support for SpiderMonkey
49 : */
50 : #if defined JS_USE_CUSTOM_ALLOCATOR
51 : # include "jscustomallocator.h"
52 : #else
53 :
54 : namespace js {
55 :
56 : /*
57 : * Thread types are used to tag threads for certain kinds of testing (see
58 : * below), and also used to characterize threads in the thread scheduler (see
59 : * js/src/vm/HelperThreads.cpp).
60 : *
61 : * Please update oom::FirstThreadTypeToTest and oom::LastThreadTypeToTest when
62 : * adding new thread types.
63 : */
64 : enum ThreadType {
65 : THREAD_TYPE_NONE = 0, // 0
66 : THREAD_TYPE_MAIN, // 1
67 : THREAD_TYPE_WASM, // 2
68 : THREAD_TYPE_ION, // 3
69 : THREAD_TYPE_PARSE, // 4
70 : THREAD_TYPE_COMPRESS, // 5
71 : THREAD_TYPE_GCHELPER, // 6
72 : THREAD_TYPE_GCPARALLEL, // 7
73 : THREAD_TYPE_PROMISE_TASK, // 8
74 : THREAD_TYPE_ION_FREE, // 9
75 : THREAD_TYPE_WASM_TIER2, // 10
76 : THREAD_TYPE_WORKER, // 11
77 : THREAD_TYPE_MAX // Used to check shell function arguments
78 : };
79 :
80 : namespace oom {
81 :
82 : /*
83 : * Theads are tagged only in certain debug contexts. Notably, to make testing
84 : * OOM in certain helper threads more effective, we allow restricting the OOM
85 : * testing to a certain helper thread type. This allows us to fail e.g. in
86 : * off-thread script parsing without causing an OOM in the active thread first.
87 : *
88 : * Getter/Setter functions to encapsulate mozilla::ThreadLocal, implementation
89 : * is in jsutil.cpp.
90 : */
91 : # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
92 :
93 : // Define the range of threads tested by simulated OOM testing and the
94 : // like. Testing worker threads is not supported.
95 : const ThreadType FirstThreadTypeToTest = THREAD_TYPE_MAIN;
96 : const ThreadType LastThreadTypeToTest = THREAD_TYPE_WASM_TIER2;
97 :
98 : extern bool InitThreadType(void);
99 : extern void SetThreadType(ThreadType);
100 : extern JS_FRIEND_API(uint32_t) GetThreadType(void);
101 :
102 : # else
103 :
104 : inline bool InitThreadType(void) { return true; }
105 : inline void SetThreadType(ThreadType t) {};
106 : inline uint32_t GetThreadType(void) { return 0; }
107 :
108 : # endif
109 :
110 : } /* namespace oom */
111 : } /* namespace js */
112 :
113 : # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
114 :
115 : #ifdef JS_OOM_BREAKPOINT
116 : # if defined(_MSC_VER)
117 : static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { __asm { }; }
118 : # else
119 : static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); }
120 : # endif
121 : #define JS_OOM_CALL_BP_FUNC() js_failedAllocBreakpoint()
122 : #else
123 : #define JS_OOM_CALL_BP_FUNC() do {} while(0)
124 : #endif
125 :
126 : namespace js {
127 : namespace oom {
128 :
129 : /*
130 : * Out of memory testing support. We provide various testing functions to
131 : * simulate OOM conditions and so we can test that they are handled correctly.
132 : */
133 :
134 : extern JS_PUBLIC_DATA(uint32_t) targetThread;
135 : extern JS_PUBLIC_DATA(uint64_t) maxAllocations;
136 : extern JS_PUBLIC_DATA(uint64_t) counter;
137 : extern JS_PUBLIC_DATA(bool) failAlways;
138 :
139 : extern void
140 : SimulateOOMAfter(uint64_t allocations, uint32_t thread, bool always);
141 :
142 : extern void
143 : ResetSimulatedOOM();
144 :
145 : inline bool
146 0 : IsThreadSimulatingOOM()
147 : {
148 0 : return js::oom::targetThread && js::oom::targetThread == js::oom::GetThreadType();
149 : }
150 :
151 : inline bool
152 0 : IsSimulatedOOMAllocation()
153 : {
154 0 : return IsThreadSimulatingOOM() &&
155 0 : (counter == maxAllocations || (counter > maxAllocations && failAlways));
156 : }
157 :
158 : inline bool
159 0 : ShouldFailWithOOM()
160 : {
161 0 : if (!IsThreadSimulatingOOM())
162 : return false;
163 :
164 0 : counter++;
165 0 : if (IsSimulatedOOMAllocation()) {
166 : JS_OOM_CALL_BP_FUNC();
167 : return true;
168 : }
169 0 : return false;
170 : }
171 :
172 : inline bool
173 : HadSimulatedOOM() {
174 0 : return counter >= maxAllocations;
175 : }
176 :
177 : /*
178 : * Out of stack space testing support, similar to OOM testing functions.
179 : */
180 :
181 : extern JS_PUBLIC_DATA(uint32_t) stackTargetThread;
182 : extern JS_PUBLIC_DATA(uint64_t) maxStackChecks;
183 : extern JS_PUBLIC_DATA(uint64_t) stackCheckCounter;
184 : extern JS_PUBLIC_DATA(bool) stackCheckFailAlways;
185 :
186 : extern void
187 : SimulateStackOOMAfter(uint64_t checks, uint32_t thread, bool always);
188 :
189 : extern void
190 : ResetSimulatedStackOOM();
191 :
192 : inline bool
193 0 : IsThreadSimulatingStackOOM()
194 : {
195 0 : return js::oom::stackTargetThread && js::oom::stackTargetThread == js::oom::GetThreadType();
196 : }
197 :
198 : inline bool
199 0 : IsSimulatedStackOOMCheck()
200 : {
201 0 : return IsThreadSimulatingStackOOM() &&
202 0 : (stackCheckCounter == maxStackChecks || (stackCheckCounter > maxStackChecks && stackCheckFailAlways));
203 : }
204 :
205 : inline bool
206 0 : ShouldFailWithStackOOM()
207 : {
208 0 : if (!IsThreadSimulatingStackOOM())
209 : return false;
210 :
211 0 : stackCheckCounter++;
212 0 : if (IsSimulatedStackOOMCheck()) {
213 : JS_OOM_CALL_BP_FUNC();
214 : return true;
215 : }
216 0 : return false;
217 : }
218 :
219 : inline bool
220 : HadSimulatedStackOOM()
221 : {
222 0 : return stackCheckCounter >= maxStackChecks;
223 : }
224 :
225 : /*
226 : * Interrupt testing support, similar to OOM testing functions.
227 : */
228 :
229 : extern JS_PUBLIC_DATA(uint32_t) interruptTargetThread;
230 : extern JS_PUBLIC_DATA(uint64_t) maxInterruptChecks;
231 : extern JS_PUBLIC_DATA(uint64_t) interruptCheckCounter;
232 : extern JS_PUBLIC_DATA(bool) interruptCheckFailAlways;
233 :
234 : extern void
235 : SimulateInterruptAfter(uint64_t checks, uint32_t thread, bool always);
236 :
237 : extern void
238 : ResetSimulatedInterrupt();
239 :
240 : inline bool
241 : IsThreadSimulatingInterrupt()
242 : {
243 0 : return js::oom::interruptTargetThread && js::oom::interruptTargetThread == js::oom::GetThreadType();
244 : }
245 :
246 : inline bool
247 0 : IsSimulatedInterruptCheck()
248 : {
249 0 : return IsThreadSimulatingInterrupt() &&
250 0 : (interruptCheckCounter == maxInterruptChecks || (interruptCheckCounter > maxInterruptChecks && interruptCheckFailAlways));
251 : }
252 :
253 : inline bool
254 0 : ShouldFailWithInterrupt()
255 : {
256 0 : if (!IsThreadSimulatingInterrupt())
257 : return false;
258 :
259 0 : interruptCheckCounter++;
260 0 : if (IsSimulatedInterruptCheck()) {
261 : JS_OOM_CALL_BP_FUNC();
262 : return true;
263 : }
264 0 : return false;
265 : }
266 :
267 : inline bool
268 : HadSimulatedInterrupt()
269 : {
270 0 : return interruptCheckCounter >= maxInterruptChecks;
271 : }
272 :
273 : } /* namespace oom */
274 : } /* namespace js */
275 :
276 : # define JS_OOM_POSSIBLY_FAIL() \
277 : do { \
278 : if (js::oom::ShouldFailWithOOM()) \
279 : return nullptr; \
280 : } while (0)
281 :
282 : # define JS_OOM_POSSIBLY_FAIL_BOOL() \
283 : do { \
284 : if (js::oom::ShouldFailWithOOM()) \
285 : return false; \
286 : } while (0)
287 :
288 : # define JS_STACK_OOM_POSSIBLY_FAIL() \
289 : do { \
290 : if (js::oom::ShouldFailWithStackOOM()) \
291 : return false; \
292 : } while (0)
293 :
294 : # define JS_STACK_OOM_POSSIBLY_FAIL_REPORT() \
295 : do { \
296 : if (js::oom::ShouldFailWithStackOOM()) { \
297 : ReportOverRecursed(cx); \
298 : return false; \
299 : } \
300 : } while (0)
301 :
302 : # define JS_INTERRUPT_POSSIBLY_FAIL() \
303 : do { \
304 : if (MOZ_UNLIKELY(js::oom::ShouldFailWithInterrupt())) { \
305 : cx->requestInterrupt(js::InterruptReason::CallbackUrgent); \
306 : return cx->handleInterrupt(); \
307 : } \
308 : } while (0)
309 :
310 : # else
311 :
312 : # define JS_OOM_POSSIBLY_FAIL() do {} while(0)
313 : # define JS_OOM_POSSIBLY_FAIL_BOOL() do {} while(0)
314 : # define JS_STACK_OOM_POSSIBLY_FAIL() do {} while(0)
315 : # define JS_STACK_OOM_POSSIBLY_FAIL_REPORT() do {} while(0)
316 : # define JS_INTERRUPT_POSSIBLY_FAIL() do {} while(0)
317 : namespace js {
318 : namespace oom {
319 : static inline bool IsSimulatedOOMAllocation() { return false; }
320 : static inline bool ShouldFailWithOOM() { return false; }
321 : } /* namespace oom */
322 : } /* namespace js */
323 :
324 : # endif /* DEBUG || JS_OOM_BREAKPOINT */
325 :
326 : namespace js {
327 :
328 : /* Disable OOM testing in sections which are not OOM safe. */
329 : struct MOZ_RAII JS_PUBLIC_DATA(AutoEnterOOMUnsafeRegion)
330 : {
331 : MOZ_NORETURN MOZ_COLD void crash(const char* reason);
332 : MOZ_NORETURN MOZ_COLD void crash(size_t size, const char* reason);
333 :
334 : using AnnotateOOMAllocationSizeCallback = void(*)(size_t);
335 : static AnnotateOOMAllocationSizeCallback annotateOOMSizeCallback;
336 : static void setAnnotateOOMAllocationSizeCallback(AnnotateOOMAllocationSizeCallback callback) {
337 0 : annotateOOMSizeCallback = callback;
338 : }
339 :
340 : #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
341 0 : AutoEnterOOMUnsafeRegion()
342 0 : : oomEnabled_(oom::IsThreadSimulatingOOM() && oom::maxAllocations != UINT64_MAX),
343 0 : oomAfter_(0)
344 : {
345 0 : if (oomEnabled_) {
346 0 : MOZ_ALWAYS_TRUE(owner_.compareExchange(nullptr, this));
347 0 : oomAfter_ = int64_t(oom::maxAllocations) - int64_t(oom::counter);
348 0 : oom::maxAllocations = UINT64_MAX;
349 : }
350 0 : }
351 :
352 0 : ~AutoEnterOOMUnsafeRegion() {
353 0 : if (oomEnabled_) {
354 0 : MOZ_ASSERT(oom::maxAllocations == UINT64_MAX);
355 0 : int64_t maxAllocations = int64_t(oom::counter) + oomAfter_;
356 0 : MOZ_ASSERT(maxAllocations >= 0,
357 : "alloc count + oom limit exceeds range, your oom limit is probably too large");
358 0 : oom::maxAllocations = uint64_t(maxAllocations);
359 0 : MOZ_ALWAYS_TRUE(owner_.compareExchange(this, nullptr));
360 : }
361 0 : }
362 :
363 : private:
364 : // Used to catch concurrent use from other threads.
365 : static mozilla::Atomic<AutoEnterOOMUnsafeRegion*> owner_;
366 :
367 : bool oomEnabled_;
368 : int64_t oomAfter_;
369 : #endif
370 : };
371 :
372 : } /* namespace js */
373 :
374 : // Malloc allocation.
375 :
376 : namespace js {
377 :
378 : extern JS_PUBLIC_DATA(arena_id_t) MallocArena;
379 :
380 : extern void InitMallocAllocator();
381 : extern void ShutDownMallocAllocator();
382 :
383 : } /* namespace js */
384 :
385 0 : static inline void* js_malloc(size_t bytes)
386 : {
387 0 : JS_OOM_POSSIBLY_FAIL();
388 0 : return moz_arena_malloc(js::MallocArena, bytes);
389 : }
390 :
391 0 : static inline void* js_calloc(size_t bytes)
392 : {
393 0 : JS_OOM_POSSIBLY_FAIL();
394 0 : return moz_arena_calloc(js::MallocArena, bytes, 1);
395 : }
396 :
397 0 : static inline void* js_calloc(size_t nmemb, size_t size)
398 : {
399 0 : JS_OOM_POSSIBLY_FAIL();
400 0 : return moz_arena_calloc(js::MallocArena, nmemb, size);
401 : }
402 :
403 0 : static inline void* js_realloc(void* p, size_t bytes)
404 : {
405 : // realloc() with zero size is not portable, as some implementations may
406 : // return nullptr on success and free |p| for this. We assume nullptr
407 : // indicates failure and that |p| is still valid.
408 0 : MOZ_ASSERT(bytes != 0);
409 :
410 0 : JS_OOM_POSSIBLY_FAIL();
411 0 : return moz_arena_realloc(js::MallocArena, p, bytes);
412 : }
413 :
414 0 : static inline void js_free(void* p)
415 : {
416 : // TODO: This should call |moz_arena_free(js::MallocArena, p)| but we
417 : // currently can't enforce that all memory freed here was allocated by
418 : // js_malloc().
419 0 : free(p);
420 0 : }
421 : #endif/* JS_USE_CUSTOM_ALLOCATOR */
422 :
423 : #include <new>
424 :
425 : /*
426 : * Low-level memory management in SpiderMonkey:
427 : *
428 : * ** Do not use the standard malloc/free/realloc: SpiderMonkey allows these
429 : * to be redefined (via JS_USE_CUSTOM_ALLOCATOR) and Gecko even #define's
430 : * these symbols.
431 : *
432 : * ** Do not use the builtin C++ operator new and delete: these throw on
433 : * error and we cannot override them not to.
434 : *
435 : * Allocation:
436 : *
437 : * - If the lifetime of the allocation is tied to the lifetime of a GC-thing
438 : * (that is, finalizing the GC-thing will free the allocation), call one of
439 : * the following functions:
440 : *
441 : * JSContext::{pod_malloc,pod_calloc,pod_realloc}
442 : * Zone::{pod_malloc,pod_calloc,pod_realloc}
443 : *
444 : * These functions accumulate the number of bytes allocated which is used as
445 : * part of the GC-triggering heuristics.
446 : *
447 : * The difference between the JSContext and Zone versions is that the
448 : * cx version report an out-of-memory error on OOM. (This follows from the
449 : * general SpiderMonkey idiom that a JSContext-taking function reports its
450 : * own errors.)
451 : *
452 : * If you don't want to report an error on failure, there are maybe_ versions
453 : * of these methods available too, e.g. maybe_pod_malloc.
454 : *
455 : * The methods above use templates to allow allocating memory suitable for an
456 : * array of a given type and number of elements. There are _with_extra
457 : * versions to allow allocating an area of memory which is larger by a
458 : * specified number of bytes, e.g. pod_malloc_with_extra.
459 : *
460 : * These methods are available on a JSRuntime, but calling them is
461 : * discouraged. Memory attributed to a runtime can only be reclaimed by full
462 : * GCs, and we try to avoid those where possible.
463 : *
464 : * - Otherwise, use js_malloc/js_realloc/js_calloc/js_new
465 : *
466 : * Deallocation:
467 : *
468 : * - Ordinarily, use js_free/js_delete.
469 : *
470 : * - For deallocations during GC finalization, use one of the following
471 : * operations on the FreeOp provided to the finalizer:
472 : *
473 : * FreeOp::{free_,delete_}
474 : */
475 :
476 : /*
477 : * Given a class which should provide a 'new' method, add
478 : * JS_DECLARE_NEW_METHODS (see js::MallocProvider for an example).
479 : *
480 : * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS,
481 : * or the build will break.
482 : */
483 : #define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS) \
484 : template <class T, typename... Args> \
485 : QUALIFIERS T * \
486 : NEWNAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \
487 : void* memory = ALLOCATOR(sizeof(T)); \
488 : return MOZ_LIKELY(memory) \
489 : ? new(memory) T(std::forward<Args>(args)...) \
490 : : nullptr; \
491 : }
492 :
493 : /*
494 : * Given a class which should provide 'make' methods, add
495 : * JS_DECLARE_MAKE_METHODS (see js::MallocProvider for an example). This
496 : * method is functionally the same as JS_DECLARE_NEW_METHODS: it just declares
497 : * methods that return mozilla::UniquePtr instances that will singly-manage
498 : * ownership of the created object.
499 : *
500 : * Note: Do not add a ; at the end of a use of JS_DECLARE_MAKE_METHODS,
501 : * or the build will break.
502 : */
503 : #define JS_DECLARE_MAKE_METHODS(MAKENAME, NEWNAME, QUALIFIERS)\
504 : template <class T, typename... Args> \
505 : QUALIFIERS mozilla::UniquePtr<T, JS::DeletePolicy<T>> \
506 : MAKENAME(Args&&... args) MOZ_HEAP_ALLOCATOR { \
507 : T* ptr = NEWNAME<T>(std::forward<Args>(args)...); \
508 : return mozilla::UniquePtr<T, JS::DeletePolicy<T>>(ptr); \
509 : }
510 :
511 12822 : JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE)
512 :
513 : namespace js {
514 :
515 : /*
516 : * Calculate the number of bytes needed to allocate |numElems| contiguous
517 : * instances of type |T|. Return false if the calculation overflowed.
518 : */
519 : template <typename T>
520 : MOZ_MUST_USE inline bool
521 : CalculateAllocSize(size_t numElems, size_t* bytesOut)
522 : {
523 411547 : *bytesOut = numElems * sizeof(T);
524 205882 : return (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) == 0;
525 : }
526 :
527 : /*
528 : * Calculate the number of bytes needed to allocate a single instance of type
529 : * |T| followed by |numExtra| contiguous instances of type |Extra|. Return
530 : * false if the calculation overflowed.
531 : */
532 : template <typename T, typename Extra>
533 : MOZ_MUST_USE inline bool
534 : CalculateAllocSizeWithExtra(size_t numExtra, size_t* bytesOut)
535 : {
536 977 : *bytesOut = sizeof(T) + numExtra * sizeof(Extra);
537 124 : return (numExtra & mozilla::tl::MulOverflowMask<sizeof(Extra)>::value) == 0 &&
538 : *bytesOut >= sizeof(T);
539 : }
540 :
541 : } /* namespace js */
542 :
543 : template <class T>
544 : static MOZ_ALWAYS_INLINE void
545 1519 : js_delete(const T* p)
546 : {
547 18468 : if (p) {
548 0 : p->~T();
549 : js_free(const_cast<T*>(p));
550 : }
551 0 : }
552 :
553 : template<class T>
554 : static MOZ_ALWAYS_INLINE void
555 0 : js_delete_poison(const T* p)
556 : {
557 0 : if (p) {
558 0 : p->~T();
559 0 : memset(static_cast<void*>(const_cast<T*>(p)), 0x3B, sizeof(T));
560 : js_free(const_cast<T*>(p));
561 : }
562 0 : }
563 :
564 : template <class T>
565 : static MOZ_ALWAYS_INLINE T*
566 : js_pod_malloc()
567 : {
568 : return static_cast<T*>(js_malloc(sizeof(T)));
569 : }
570 :
571 : template <class T>
572 : static MOZ_ALWAYS_INLINE T*
573 : js_pod_calloc()
574 : {
575 : return static_cast<T*>(js_calloc(sizeof(T)));
576 : }
577 :
578 : template <class T>
579 : static MOZ_ALWAYS_INLINE T*
580 2047 : js_pod_malloc(size_t numElems)
581 : {
582 : size_t bytes;
583 262542 : if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes)))
584 : return nullptr;
585 262542 : return static_cast<T*>(js_malloc(bytes));
586 : }
587 :
588 : template <class T>
589 : static MOZ_ALWAYS_INLINE T*
590 : js_pod_calloc(size_t numElems)
591 : {
592 : size_t bytes;
593 0 : if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes)))
594 : return nullptr;
595 0 : return static_cast<T*>(js_calloc(bytes));
596 : }
597 :
598 : template <class T>
599 : static MOZ_ALWAYS_INLINE T*
600 13474 : js_pod_realloc(T* prior, size_t oldSize, size_t newSize)
601 : {
602 13474 : MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value));
603 : size_t bytes;
604 57834 : if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(newSize, &bytes)))
605 : return nullptr;
606 57834 : return static_cast<T*>(js_realloc(prior, bytes));
607 : }
608 :
609 : namespace js {
610 :
611 : template<typename T>
612 : struct ScopedFreePtrTraits
613 : {
614 : typedef T* type;
615 : static T* empty() { return nullptr; }
616 0 : static void release(T* ptr) { js_free(ptr); }
617 : };
618 0 : SCOPED_TEMPLATE(ScopedJSFreePtr, ScopedFreePtrTraits)
619 :
620 : template <typename T>
621 : struct ScopedDeletePtrTraits : public ScopedFreePtrTraits<T>
622 : {
623 378 : static void release(T* ptr) { js_delete(ptr); }
624 : };
625 1230 : SCOPED_TEMPLATE(ScopedJSDeletePtr, ScopedDeletePtrTraits)
626 :
627 : template <typename T>
628 : struct ScopedReleasePtrTraits : public ScopedFreePtrTraits<T>
629 : {
630 : static void release(T* ptr) { if (ptr) ptr->release(); }
631 : };
632 : SCOPED_TEMPLATE(ScopedReleasePtr, ScopedReleasePtrTraits)
633 :
634 : } /* namespace js */
635 :
636 : namespace JS {
637 :
638 : template<typename T>
639 : struct DeletePolicy
640 : {
641 0 : constexpr DeletePolicy() {}
642 :
643 : template<typename U>
644 : MOZ_IMPLICIT DeletePolicy(DeletePolicy<U> other,
645 : typename mozilla::EnableIf<mozilla::IsConvertible<U*, T*>::value,
646 : int>::Type dummy = 0)
647 : {}
648 :
649 1195 : void operator()(const T* ptr) {
650 0 : js_delete(const_cast<T*>(ptr));
651 1195 : }
652 : };
653 :
654 : struct FreePolicy
655 : {
656 : void operator()(const void* ptr) {
657 27187 : js_free(const_cast<void*>(ptr));
658 : }
659 : };
660 :
661 : typedef mozilla::UniquePtr<char[], JS::FreePolicy> UniqueChars;
662 : typedef mozilla::UniquePtr<char16_t[], JS::FreePolicy> UniqueTwoByteChars;
663 :
664 : } // namespace JS
665 :
666 : namespace js {
667 :
668 : /* Integral types for all hash functions. */
669 : typedef uint32_t HashNumber;
670 : const unsigned HashNumberSizeBits = 32;
671 :
672 : namespace detail {
673 :
674 : /*
675 : * Given a raw hash code, h, return a number that can be used to select a hash
676 : * bucket.
677 : *
678 : * This function aims to produce as uniform an output distribution as possible,
679 : * especially in the most significant (leftmost) bits, even though the input
680 : * distribution may be highly nonrandom, given the constraints that this must
681 : * be deterministic and quick to compute.
682 : *
683 : * Since the leftmost bits of the result are best, the hash bucket index is
684 : * computed by doing ScrambleHashCode(h) / (2^32/N) or the equivalent
685 : * right-shift, not ScrambleHashCode(h) % N or the equivalent bit-mask.
686 : *
687 : * FIXME: OrderedHashTable uses a bit-mask; see bug 775896.
688 : */
689 : inline HashNumber
690 : ScrambleHashCode(HashNumber h)
691 : {
692 : /*
693 : * Simply returning h would not cause any hash tables to produce wrong
694 : * answers. But it can produce pathologically bad performance: The caller
695 : * right-shifts the result, keeping only the highest bits. The high bits of
696 : * hash codes are very often completely entropy-free. (So are the lowest
697 : * bits.)
698 : *
699 : * So we use Fibonacci hashing, as described in Knuth, The Art of Computer
700 : * Programming, 6.4. This mixes all the bits of the input hash code h.
701 : *
702 : * The value of goldenRatio is taken from the hex
703 : * expansion of the golden ratio, which starts 1.9E3779B9....
704 : * This value is especially good if values with consecutive hash codes
705 : * are stored in a hash table; see Knuth for details.
706 : */
707 : static const HashNumber goldenRatio = 0x9E3779B9U;
708 : return mozilla::WrappingMultiply(h, goldenRatio);
709 : }
710 :
711 : } /* namespace detail */
712 :
713 : } /* namespace js */
714 :
715 : /* sixgill annotation defines */
716 : #ifndef HAVE_STATIC_ANNOTATIONS
717 : # define HAVE_STATIC_ANNOTATIONS
718 : # ifdef XGILL_PLUGIN
719 : # define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND)))
720 : # define STATIC_PRECONDITION_ASSUME(COND) __attribute__((precondition_assume(#COND)))
721 : # define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND)))
722 : # define STATIC_POSTCONDITION_ASSUME(COND) __attribute__((postcondition_assume(#COND)))
723 : # define STATIC_INVARIANT(COND) __attribute__((invariant(#COND)))
724 : # define STATIC_INVARIANT_ASSUME(COND) __attribute__((invariant_assume(#COND)))
725 : # define STATIC_ASSUME(COND) \
726 : JS_BEGIN_MACRO \
727 : __attribute__((assume_static(#COND), unused)) \
728 : int STATIC_PASTE1(assume_static_, __COUNTER__); \
729 : JS_END_MACRO
730 : # else /* XGILL_PLUGIN */
731 : # define STATIC_PRECONDITION(COND) /* nothing */
732 : # define STATIC_PRECONDITION_ASSUME(COND) /* nothing */
733 : # define STATIC_POSTCONDITION(COND) /* nothing */
734 : # define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */
735 : # define STATIC_INVARIANT(COND) /* nothing */
736 : # define STATIC_INVARIANT_ASSUME(COND) /* nothing */
737 : # define STATIC_ASSUME(COND) JS_BEGIN_MACRO /* nothing */ JS_END_MACRO
738 : # endif /* XGILL_PLUGIN */
739 : # define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference())
740 : #endif /* HAVE_STATIC_ANNOTATIONS */
741 :
742 : #endif /* js_Utility_h */
|