Utility.h (24464B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- 2 * vim: set ts=8 sts=2 et sw=2 tw=80: 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/CheckedArithmetic.h" 14 #include "mozilla/Likely.h" 15 #include "mozilla/UniquePtr.h" 16 17 #include <stdlib.h> 18 #include <string.h> 19 #include <type_traits> 20 #include <utility> 21 22 #include "jstypes.h" 23 #include "mozmemory.h" 24 #include "js/TypeDecls.h" 25 26 /* The public JS engine namespace. */ 27 namespace JS {} 28 29 /* The mozilla-shared reusable template/utility namespace. */ 30 namespace mozilla {} 31 32 /* The private JS engine namespace. */ 33 namespace js {} 34 35 [[noreturn]] extern MOZ_COLD JS_PUBLIC_API void JS_Assert(const char* s, 36 const char* file, 37 int ln); 38 39 /* 40 * Custom allocator support for SpiderMonkey 41 */ 42 #if defined JS_USE_CUSTOM_ALLOCATOR 43 # include "jscustomallocator.h" 44 #else 45 46 namespace js { 47 48 /* 49 * Thread types are used to tag threads for certain kinds of testing (see 50 * below), and also used to characterize threads in the thread scheduler (see 51 * js/src/vm/HelperThreads.cpp). 52 * 53 * Please update oom::FirstThreadTypeToTest and oom::LastThreadTypeToTest when 54 * adding new thread types. 55 */ 56 enum ThreadType { 57 THREAD_TYPE_NONE = 0, // 0 58 THREAD_TYPE_MAIN, // 1 59 THREAD_TYPE_WASM_COMPILE_TIER1, // 2 60 THREAD_TYPE_WASM_COMPILE_TIER2, // 3 61 THREAD_TYPE_BASELINE, // 4 62 THREAD_TYPE_ION, // 5 63 THREAD_TYPE_COMPRESS, // 6 64 THREAD_TYPE_GCPARALLEL, // 7 65 THREAD_TYPE_PROMISE_TASK, // 8 66 THREAD_TYPE_ION_FREE, // 9 67 THREAD_TYPE_WASM_GENERATOR_COMPLETE_TIER2, // 10 68 THREAD_TYPE_WASM_COMPILE_PARTIAL_TIER2, // 11 69 THREAD_TYPE_WORKER, // 12 70 THREAD_TYPE_DELAZIFY, // 13 71 THREAD_TYPE_DELAZIFY_FREE, // 14 72 THREAD_TYPE_MAX // Used to check shell function arguments 73 }; 74 75 namespace oom { 76 77 /* 78 * Theads are tagged only in certain debug contexts. Notably, to make testing 79 * OOM in certain helper threads more effective, we allow restricting the OOM 80 * testing to a certain helper thread type. This allows us to fail e.g. in 81 * off-thread script parsing without causing an OOM in the active thread first. 82 * 83 * Getter/Setter functions to encapsulate mozilla::ThreadLocal, implementation 84 * is in util/Utility.cpp. 85 */ 86 # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) 87 88 // Define the range of threads tested by simulated OOM testing and the 89 // like. Testing worker threads is not supported. 90 const ThreadType FirstThreadTypeToTest = THREAD_TYPE_MAIN; 91 const ThreadType LastThreadTypeToTest = THREAD_TYPE_WASM_COMPILE_PARTIAL_TIER2; 92 93 extern bool InitThreadType(void); 94 extern void SetThreadType(ThreadType); 95 extern JS_PUBLIC_API uint32_t GetThreadType(void); 96 97 # else 98 99 inline bool InitThreadType(void) { return true; } 100 inline void SetThreadType(ThreadType t) {}; 101 inline uint32_t GetThreadType(void) { return 0; } 102 inline uint32_t GetAllocationThreadType(void) { return 0; } 103 inline uint32_t GetStackCheckThreadType(void) { return 0; } 104 inline uint32_t GetInterruptCheckThreadType(void) { return 0; } 105 106 # endif 107 108 } /* namespace oom */ 109 } /* namespace js */ 110 111 # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) 112 113 # ifdef JS_OOM_BREAKPOINT 114 # if defined(_MSC_VER) 115 static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { 116 __asm {} 117 ; 118 } 119 # else 120 static MOZ_NEVER_INLINE void js_failedAllocBreakpoint() { asm(""); } 121 # endif 122 # define JS_OOM_CALL_BP_FUNC() js_failedAllocBreakpoint() 123 # else 124 # define JS_OOM_CALL_BP_FUNC() \ 125 do { \ 126 } while (0) 127 # endif 128 129 namespace js { 130 namespace oom { 131 132 /* 133 * Out of memory testing support. We provide various testing functions to 134 * simulate OOM conditions and so we can test that they are handled correctly. 135 */ 136 class FailureSimulator { 137 public: 138 enum class Kind : uint8_t { Nothing, OOM, StackOOM, Interrupt }; 139 140 private: 141 Kind kind_ = Kind::Nothing; 142 uint32_t targetThread_ = 0; 143 uint64_t maxChecks_ = UINT64_MAX; 144 uint64_t counter_ = 0; 145 bool failAlways_ = true; 146 bool inUnsafeRegion_ = false; 147 148 public: 149 uint64_t maxChecks() const { return maxChecks_; } 150 uint64_t counter() const { return counter_; } 151 void setInUnsafeRegion(bool b) { 152 MOZ_ASSERT(inUnsafeRegion_ != b); 153 inUnsafeRegion_ = b; 154 } 155 uint32_t targetThread() const { return targetThread_; } 156 bool isThreadSimulatingAny() const { 157 return targetThread_ && targetThread_ == js::oom::GetThreadType() && 158 !inUnsafeRegion_; 159 } 160 bool isThreadSimulating(Kind kind) const { 161 return kind_ == kind && isThreadSimulatingAny(); 162 } 163 bool isSimulatedFailure(Kind kind) const { 164 if (!isThreadSimulating(kind)) { 165 return false; 166 } 167 return counter_ == maxChecks_ || (counter_ > maxChecks_ && failAlways_); 168 } 169 bool hadFailure(Kind kind) const { 170 return kind_ == kind && counter_ >= maxChecks_; 171 } 172 bool shouldFail(Kind kind) { 173 if (!isThreadSimulating(kind)) { 174 return false; 175 } 176 counter_++; 177 if (isSimulatedFailure(kind)) { 178 JS_OOM_CALL_BP_FUNC(); 179 return true; 180 } 181 return false; 182 } 183 184 void simulateFailureAfter(Kind kind, uint64_t checks, uint32_t thread, 185 bool always); 186 void reset(); 187 }; 188 extern JS_PUBLIC_DATA FailureSimulator simulator; 189 190 inline bool IsSimulatedOOMAllocation() { 191 return simulator.isSimulatedFailure(FailureSimulator::Kind::OOM); 192 } 193 194 inline bool ShouldFailWithOOM() { 195 return simulator.shouldFail(FailureSimulator::Kind::OOM); 196 } 197 198 inline bool HadSimulatedOOM() { 199 return simulator.hadFailure(FailureSimulator::Kind::OOM); 200 } 201 202 /* 203 * Out of stack space testing support, similar to OOM testing functions. 204 */ 205 206 inline bool IsSimulatedStackOOMCheck() { 207 return simulator.isSimulatedFailure(FailureSimulator::Kind::StackOOM); 208 } 209 210 inline bool ShouldFailWithStackOOM() { 211 return simulator.shouldFail(FailureSimulator::Kind::StackOOM); 212 } 213 214 inline bool HadSimulatedStackOOM() { 215 return simulator.hadFailure(FailureSimulator::Kind::StackOOM); 216 } 217 218 /* 219 * Interrupt testing support, similar to OOM testing functions. 220 */ 221 222 inline bool IsSimulatedInterruptCheck() { 223 return simulator.isSimulatedFailure(FailureSimulator::Kind::Interrupt); 224 } 225 226 inline bool ShouldFailWithInterrupt() { 227 return simulator.shouldFail(FailureSimulator::Kind::Interrupt); 228 } 229 230 inline bool HadSimulatedInterrupt() { 231 return simulator.hadFailure(FailureSimulator::Kind::Interrupt); 232 } 233 234 } /* namespace oom */ 235 } /* namespace js */ 236 237 # define JS_OOM_POSSIBLY_FAIL() \ 238 do { \ 239 if (js::oom::ShouldFailWithOOM()) return nullptr; \ 240 } while (0) 241 242 # define JS_OOM_POSSIBLY_FAIL_BOOL() \ 243 do { \ 244 if (js::oom::ShouldFailWithOOM()) return false; \ 245 } while (0) 246 247 # define JS_STACK_OOM_POSSIBLY_FAIL() \ 248 do { \ 249 if (js::oom::ShouldFailWithStackOOM()) return false; \ 250 } while (0) 251 252 # define JS_INTERRUPT_POSSIBLY_FAIL() \ 253 do { \ 254 if (MOZ_UNLIKELY(js::oom::ShouldFailWithInterrupt())) { \ 255 cx->requestInterrupt(js::InterruptReason::CallbackUrgent); \ 256 return cx->handleInterrupt(); \ 257 } \ 258 } while (0) 259 260 # else 261 262 # define JS_OOM_POSSIBLY_FAIL() \ 263 do { \ 264 } while (0) 265 # define JS_OOM_POSSIBLY_FAIL_BOOL() \ 266 do { \ 267 } while (0) 268 # define JS_STACK_OOM_POSSIBLY_FAIL() \ 269 do { \ 270 } while (0) 271 # define JS_INTERRUPT_POSSIBLY_FAIL() \ 272 do { \ 273 } while (0) 274 namespace js { 275 namespace oom { 276 static inline bool IsSimulatedOOMAllocation() { return false; } 277 static inline bool ShouldFailWithOOM() { return false; } 278 } /* namespace oom */ 279 } /* namespace js */ 280 281 # endif /* DEBUG || JS_OOM_BREAKPOINT */ 282 283 # ifdef FUZZING 284 namespace js { 285 namespace oom { 286 extern JS_PUBLIC_DATA size_t largeAllocLimit; 287 extern void InitLargeAllocLimit(); 288 } /* namespace oom */ 289 } /* namespace js */ 290 291 # define JS_CHECK_LARGE_ALLOC(x) \ 292 do { \ 293 if (js::oom::largeAllocLimit && x > js::oom::largeAllocLimit) { \ 294 if (getenv("MOZ_FUZZ_CRASH_ON_LARGE_ALLOC")) { \ 295 MOZ_CRASH("Large allocation"); \ 296 } else { \ 297 return nullptr; \ 298 } \ 299 } \ 300 } while (0) 301 # else 302 # define JS_CHECK_LARGE_ALLOC(x) \ 303 do { \ 304 } while (0) 305 # endif 306 307 namespace js { 308 309 /* Disable OOM testing in sections which are not OOM safe. */ 310 struct MOZ_RAII JS_PUBLIC_DATA AutoEnterOOMUnsafeRegion { 311 [[noreturn]] MOZ_COLD void crash(const char* reason) { crash_impl(reason); } 312 [[noreturn]] MOZ_COLD void crash(size_t size, const char* reason) { 313 crash_impl(reason); 314 } 315 316 using AnnotateOOMAllocationSizeCallback = void (*)(size_t); 317 static mozilla::Atomic<AnnotateOOMAllocationSizeCallback, mozilla::Relaxed> 318 annotateOOMSizeCallback; 319 static void setAnnotateOOMAllocationSizeCallback( 320 AnnotateOOMAllocationSizeCallback callback) { 321 annotateOOMSizeCallback = callback; 322 } 323 324 # if defined(DEBUG) || defined(JS_OOM_BREAKPOINT) 325 AutoEnterOOMUnsafeRegion() 326 : oomEnabled_(oom::simulator.isThreadSimulatingAny()) { 327 if (oomEnabled_) { 328 MOZ_ALWAYS_TRUE(owner_.compareExchange(nullptr, this)); 329 oom::simulator.setInUnsafeRegion(true); 330 } 331 } 332 333 ~AutoEnterOOMUnsafeRegion() { 334 if (oomEnabled_) { 335 oom::simulator.setInUnsafeRegion(false); 336 MOZ_ALWAYS_TRUE(owner_.compareExchange(this, nullptr)); 337 } 338 } 339 340 private: 341 // Used to catch concurrent use from other threads. 342 static mozilla::Atomic<AutoEnterOOMUnsafeRegion*> owner_; 343 344 bool oomEnabled_; 345 # endif 346 private: 347 [[noreturn]] static MOZ_COLD void crash_impl(const char* reason); 348 [[noreturn]] static MOZ_COLD void crash_impl(size_t size, const char* reason); 349 }; 350 351 } /* namespace js */ 352 353 // Malloc allocation. 354 355 namespace js { 356 357 // The following two arenas require a little bit of clarification. We have 358 // observed that, particularly on devices with heterogeneous CPU architectures 359 // where background work can run on significantly slower cores than main thread 360 // work, the lock contention in the allocator can be a big problem for the 361 // main thread. So we introduced an arena for background allocations which can 362 // reduce that contention. 363 // 364 // The general rule for these is: if it's easy to determine at the time of 365 // authorship that an allocation will be *off* the main thread, use the 366 // BackgroundMallocArena, and vice versa. If it is hard to determine, just make 367 // a guess, and that will be fine. Do not spend too much time on this, and 368 // don't do anything fancy at runtime to try to determine which to use. 369 extern JS_PUBLIC_DATA arena_id_t MallocArena; 370 extern JS_PUBLIC_DATA arena_id_t BackgroundMallocArena; 371 372 extern JS_PUBLIC_DATA arena_id_t ArrayBufferContentsArena; 373 extern JS_PUBLIC_DATA arena_id_t StringBufferArena; 374 375 extern void InitMallocAllocator(); 376 extern void ShutDownMallocAllocator(); 377 378 // This is a no-op if built without MOZ_MEMORY and MOZ_DEBUG. 379 extern void AssertJSStringBufferInCorrectArena(const void* ptr); 380 381 } /* namespace js */ 382 383 static inline void* js_arena_malloc(arena_id_t arena, size_t bytes) { 384 JS_OOM_POSSIBLY_FAIL(); 385 JS_CHECK_LARGE_ALLOC(bytes); 386 return moz_arena_malloc(arena, bytes); 387 } 388 389 static inline void* js_malloc(size_t bytes) { 390 return js_arena_malloc(js::MallocArena, bytes); 391 } 392 393 static inline void* js_arena_calloc(arena_id_t arena, size_t bytes) { 394 JS_OOM_POSSIBLY_FAIL(); 395 JS_CHECK_LARGE_ALLOC(bytes); 396 return moz_arena_calloc(arena, bytes, 1); 397 } 398 399 static inline void* js_arena_calloc(arena_id_t arena, size_t nmemb, 400 size_t size) { 401 JS_OOM_POSSIBLY_FAIL(); 402 JS_CHECK_LARGE_ALLOC(nmemb * size); 403 return moz_arena_calloc(arena, nmemb, size); 404 } 405 406 static inline void* js_calloc(size_t bytes) { 407 return js_arena_calloc(js::MallocArena, bytes); 408 } 409 410 static inline void* js_calloc(size_t nmemb, size_t size) { 411 return js_arena_calloc(js::MallocArena, nmemb, size); 412 } 413 414 static inline void* js_arena_realloc(arena_id_t arena, void* p, size_t bytes) { 415 // realloc() with zero size is not portable, as some implementations may 416 // return nullptr on success and free |p| for this. We assume nullptr 417 // indicates failure and that |p| is still valid. 418 MOZ_ASSERT(bytes != 0); 419 420 JS_OOM_POSSIBLY_FAIL(); 421 JS_CHECK_LARGE_ALLOC(bytes); 422 return moz_arena_realloc(arena, p, bytes); 423 } 424 425 static inline void* js_realloc(void* p, size_t bytes) { 426 return js_arena_realloc(js::MallocArena, p, bytes); 427 } 428 429 static inline void js_free(void* p) { 430 // Bug 1784164: This should call |moz_arena_free(js::MallocArena, p)| but we 431 // currently can't enforce that all memory freed here was allocated by 432 // js_malloc(). All other memory should go through a different allocator and 433 // deallocator. 434 free(p); 435 } 436 #endif /* JS_USE_CUSTOM_ALLOCATOR */ 437 438 #include <new> 439 440 /* 441 * [SMDOC] Low-level memory management in SpiderMonkey 442 * 443 * ** Do not use the standard malloc/free/realloc: SpiderMonkey allows these 444 * to be redefined (via JS_USE_CUSTOM_ALLOCATOR) and Gecko even #define's 445 * these symbols. 446 * 447 * ** Do not use the builtin C++ operator new and delete: these throw on 448 * error and we cannot override them not to. 449 * 450 * Allocation: 451 * 452 * - If the lifetime of the allocation is tied to the lifetime of a GC-thing 453 * (that is, finalizing the GC-thing will free the allocation), call one of 454 * the following functions: 455 * 456 * JSContext::{pod_malloc,pod_calloc,pod_realloc} 457 * Zone::{pod_malloc,pod_calloc,pod_realloc} 458 * 459 * These functions accumulate the number of bytes allocated which is used as 460 * part of the GC-triggering heuristics. 461 * 462 * The difference between the JSContext and Zone versions is that the 463 * cx version report an out-of-memory error on OOM. (This follows from the 464 * general SpiderMonkey idiom that a JSContext-taking function reports its 465 * own errors.) 466 * 467 * If you don't want to report an error on failure, there are maybe_ versions 468 * of these methods available too, e.g. maybe_pod_malloc. 469 * 470 * The methods above use templates to allow allocating memory suitable for an 471 * array of a given type and number of elements. There are _with_extra 472 * versions to allow allocating an area of memory which is larger by a 473 * specified number of bytes, e.g. pod_malloc_with_extra. 474 * 475 * These methods are available on a JSRuntime, but calling them is 476 * discouraged. Memory attributed to a runtime can only be reclaimed by full 477 * GCs, and we try to avoid those where possible. 478 * 479 * - Otherwise, use js_malloc/js_realloc/js_calloc/js_new 480 * 481 * Deallocation: 482 * 483 * - Ordinarily, use js_free/js_delete. 484 * 485 * - For deallocations during GC finalization, use one of the following 486 * operations on the JS::GCContext provided to the finalizer: 487 * 488 * JS::GCContext::{free_,delete_} 489 */ 490 491 /* 492 * Given a class which should provide a 'new' method, add 493 * JS_DECLARE_NEW_METHODS (see js::MallocProvider for an example). 494 * 495 * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_METHODS, 496 * or the build will break. 497 */ 498 #define JS_DECLARE_NEW_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS) \ 499 template <class T, typename... Args> \ 500 QUALIFIERS T* MOZ_HEAP_ALLOCATOR NEWNAME(Args&&... args) { \ 501 static_assert( \ 502 alignof(T) <= alignof(max_align_t), \ 503 "over-aligned type is not supported by JS_DECLARE_NEW_METHODS"); \ 504 void* memory = ALLOCATOR(sizeof(T)); \ 505 return MOZ_LIKELY(memory) ? new (memory) T(std::forward<Args>(args)...) \ 506 : nullptr; \ 507 } 508 509 /* 510 * Given a class which should provide a 'new' method that takes an arena as 511 * its first argument, add JS_DECLARE_NEW_ARENA_METHODS 512 * (see js::MallocProvider for an example). 513 * 514 * Note: Do not add a ; at the end of a use of JS_DECLARE_NEW_ARENA_METHODS, 515 * or the build will break. 516 */ 517 #define JS_DECLARE_NEW_ARENA_METHODS(NEWNAME, ALLOCATOR, QUALIFIERS) \ 518 template <class T, typename... Args> \ 519 QUALIFIERS T* MOZ_HEAP_ALLOCATOR NEWNAME(arena_id_t arena, Args&&... args) { \ 520 static_assert( \ 521 alignof(T) <= alignof(max_align_t), \ 522 "over-aligned type is not supported by JS_DECLARE_NEW_ARENA_METHODS"); \ 523 void* memory = ALLOCATOR(arena, sizeof(T)); \ 524 return MOZ_LIKELY(memory) ? new (memory) T(std::forward<Args>(args)...) \ 525 : nullptr; \ 526 } 527 528 /* 529 * Given a class which should provide 'make' methods, add 530 * JS_DECLARE_MAKE_METHODS (see js::MallocProvider for an example). This 531 * method is functionally the same as JS_DECLARE_NEW_METHODS: it just declares 532 * methods that return mozilla::UniquePtr instances that will singly-manage 533 * ownership of the created object. 534 * 535 * Note: Do not add a ; at the end of a use of JS_DECLARE_MAKE_METHODS, 536 * or the build will break. 537 */ 538 #define JS_DECLARE_MAKE_METHODS(MAKENAME, NEWNAME, QUALIFIERS) \ 539 template <class T, typename... Args> \ 540 QUALIFIERS mozilla::UniquePtr<T, JS::DeletePolicy<T>> MOZ_HEAP_ALLOCATOR \ 541 MAKENAME(Args&&... args) { \ 542 T* ptr = NEWNAME<T>(std::forward<Args>(args)...); \ 543 return mozilla::UniquePtr<T, JS::DeletePolicy<T>>(ptr); \ 544 } 545 546 JS_DECLARE_NEW_METHODS(js_new, js_malloc, static MOZ_ALWAYS_INLINE) 547 JS_DECLARE_NEW_ARENA_METHODS(js_arena_new, js_arena_malloc, 548 static MOZ_ALWAYS_INLINE) 549 550 namespace js { 551 552 /* 553 * Calculate the number of bytes needed to allocate |numElems| contiguous 554 * instances of type |T|. Return false if the calculation overflowed. 555 */ 556 template <typename T> 557 [[nodiscard]] inline bool CalculateAllocSize(size_t numElems, 558 size_t* bytesOut) { 559 return mozilla::SafeMul(numElems, sizeof(T), bytesOut); 560 } 561 562 /* 563 * Calculate the number of bytes needed to allocate a single instance of type 564 * |T| followed by |numExtra| contiguous instances of type |Extra|. Return 565 * false if the calculation overflowed. 566 */ 567 template <typename T, typename Extra> 568 [[nodiscard]] inline bool CalculateAllocSizeWithExtra(size_t numExtra, 569 size_t* bytesOut) { 570 size_t tmp; 571 return mozilla::SafeMul(numExtra, sizeof(Extra), &tmp) && 572 mozilla::SafeAdd(sizeof(T), tmp, bytesOut); 573 } 574 575 } /* namespace js */ 576 577 template <class T> 578 static MOZ_ALWAYS_INLINE void js_delete(const T* p) { 579 if (p) { 580 p->~T(); 581 js_free(const_cast<T*>(p)); 582 } 583 } 584 585 template <class T> 586 static MOZ_ALWAYS_INLINE void js_delete_poison(const T* p) { 587 if (p) { 588 p->~T(); 589 memset(static_cast<void*>(const_cast<T*>(p)), 0x3B, sizeof(T)); 590 js_free(const_cast<T*>(p)); 591 } 592 } 593 594 template <class T> 595 static MOZ_ALWAYS_INLINE T* js_pod_arena_malloc(arena_id_t arena, 596 size_t numElems) { 597 size_t bytes; 598 if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) { 599 return nullptr; 600 } 601 return static_cast<T*>(js_arena_malloc(arena, bytes)); 602 } 603 604 template <class T> 605 static MOZ_ALWAYS_INLINE T* js_pod_malloc(size_t numElems) { 606 return js_pod_arena_malloc<T>(js::MallocArena, numElems); 607 } 608 609 template <class T> 610 static MOZ_ALWAYS_INLINE T* js_pod_arena_calloc(arena_id_t arena, 611 size_t numElems) { 612 size_t bytes; 613 if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) { 614 return nullptr; 615 } 616 return static_cast<T*>(js_arena_calloc(arena, bytes, 1)); 617 } 618 619 template <class T> 620 static MOZ_ALWAYS_INLINE T* js_pod_calloc(size_t numElems) { 621 return js_pod_arena_calloc<T>(js::MallocArena, numElems); 622 } 623 624 template <class T> 625 static MOZ_ALWAYS_INLINE T* js_pod_arena_realloc(arena_id_t arena, T* prior, 626 size_t oldSize, 627 size_t newSize) { 628 [[maybe_unused]] size_t tmp; 629 MOZ_ASSERT(mozilla::SafeMul(oldSize, sizeof(T), &tmp)); 630 size_t bytes; 631 if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(newSize, &bytes))) { 632 return nullptr; 633 } 634 return static_cast<T*>(js_arena_realloc(arena, prior, bytes)); 635 } 636 637 template <class T> 638 static MOZ_ALWAYS_INLINE T* js_pod_realloc(T* prior, size_t oldSize, 639 size_t newSize) { 640 return js_pod_arena_realloc<T>(js::MallocArena, prior, oldSize, newSize); 641 } 642 643 namespace JS { 644 645 template <typename T> 646 struct DeletePolicy { 647 constexpr DeletePolicy() = default; 648 649 template <typename U> 650 MOZ_IMPLICIT DeletePolicy( 651 DeletePolicy<U> other, 652 std::enable_if_t<std::is_convertible_v<U*, T*>, int> dummy = 0) {} 653 654 void operator()(const T* ptr) { js_delete(const_cast<T*>(ptr)); } 655 }; 656 657 struct FreePolicy { 658 void operator()(const void* ptr) { js_free(const_cast<void*>(ptr)); } 659 }; 660 661 using UniqueChars = mozilla::UniquePtr<char[], JS::FreePolicy>; 662 using UniqueTwoByteChars = mozilla::UniquePtr<char16_t[], JS::FreePolicy>; 663 using UniqueLatin1Chars = mozilla::UniquePtr<JS::Latin1Char[], JS::FreePolicy>; 664 using UniqueWideChars = mozilla::UniquePtr<wchar_t[], JS::FreePolicy>; 665 666 } // namespace JS 667 668 /* sixgill annotation defines */ 669 #ifndef HAVE_STATIC_ANNOTATIONS 670 # define HAVE_STATIC_ANNOTATIONS 671 # ifdef XGILL_PLUGIN 672 # define STATIC_PRECONDITION(COND) __attribute__((precondition(#COND))) 673 # define STATIC_PRECONDITION_ASSUME(COND) \ 674 __attribute__((precondition_assume(#COND))) 675 # define STATIC_POSTCONDITION(COND) __attribute__((postcondition(#COND))) 676 # define STATIC_POSTCONDITION_ASSUME(COND) \ 677 __attribute__((postcondition_assume(#COND))) 678 # define STATIC_INVARIANT(COND) __attribute__((invariant(#COND))) 679 # define STATIC_INVARIANT_ASSUME(COND) \ 680 __attribute__((invariant_assume(#COND))) 681 # define STATIC_ASSUME(COND) \ 682 JS_BEGIN_MACRO \ 683 __attribute__((assume_static(#COND), unused)) int STATIC_PASTE1( \ 684 assume_static_, __COUNTER__); \ 685 JS_END_MACRO 686 # else /* XGILL_PLUGIN */ 687 # define STATIC_PRECONDITION(COND) /* nothing */ 688 # define STATIC_PRECONDITION_ASSUME(COND) /* nothing */ 689 # define STATIC_POSTCONDITION(COND) /* nothing */ 690 # define STATIC_POSTCONDITION_ASSUME(COND) /* nothing */ 691 # define STATIC_INVARIANT(COND) /* nothing */ 692 # define STATIC_INVARIANT_ASSUME(COND) /* nothing */ 693 # define STATIC_ASSUME(COND) \ 694 JS_BEGIN_MACRO /* nothing */ \ 695 JS_END_MACRO 696 # endif /* XGILL_PLUGIN */ 697 # define STATIC_SKIP_INFERENCE STATIC_INVARIANT(skip_inference()) 698 #endif /* HAVE_STATIC_ANNOTATIONS */ 699 700 #endif /* js_Utility_h */