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 ds_LifoAlloc_h
8 : #define ds_LifoAlloc_h
9 :
10 : #include "mozilla/Attributes.h"
11 : #include "mozilla/MathAlgorithms.h"
12 : #include "mozilla/MemoryChecking.h"
13 : #include "mozilla/MemoryReporting.h"
14 : #include "mozilla/PodOperations.h"
15 : #include "mozilla/TemplateLib.h"
16 : #include "mozilla/TypeTraits.h"
17 :
18 : // This data structure supports stacky LIFO allocation (mark/release and
19 : // LifoAllocScope). It does not maintain one contiguous segment; instead, it
20 : // maintains a bunch of linked memory segments. In order to prevent malloc/free
21 : // thrashing, unused segments are deallocated when garbage collection occurs.
22 :
23 : #include "jsutil.h"
24 :
25 : namespace js {
26 :
27 : namespace detail {
28 :
29 : static const size_t LIFO_ALLOC_ALIGN = 8;
30 :
31 : MOZ_ALWAYS_INLINE
32 : char*
33 2465426 : AlignPtr(void* orig)
34 : {
35 : static_assert(mozilla::tl::FloorLog2<LIFO_ALLOC_ALIGN>::value ==
36 : mozilla::tl::CeilingLog2<LIFO_ALLOC_ALIGN>::value,
37 : "LIFO_ALLOC_ALIGN must be a power of two");
38 :
39 2465426 : char* result = (char*) ((uintptr_t(orig) + (LIFO_ALLOC_ALIGN - 1)) & (~LIFO_ALLOC_ALIGN + 1));
40 2465426 : MOZ_ASSERT(uintptr_t(result) % LIFO_ALLOC_ALIGN == 0);
41 2465426 : return result;
42 : }
43 :
44 : // Header for a chunk of memory wrangled by the LifoAlloc.
45 : class BumpChunk
46 : {
47 : char* bump; // start of the available data
48 : char* limit; // end of the data
49 : BumpChunk* next_; // the next BumpChunk
50 : size_t bumpSpaceSize; // size of the data area
51 :
52 583231 : char* headerBase() { return reinterpret_cast<char*>(this); }
53 1210353 : char* bumpBase() const { return limit - bumpSpaceSize; }
54 :
55 4042 : explicit BumpChunk(size_t bumpSpaceSize)
56 4042 : : bump(reinterpret_cast<char*>(this) + sizeof(BumpChunk)),
57 4042 : limit(bump + bumpSpaceSize),
58 8084 : next_(nullptr), bumpSpaceSize(bumpSpaceSize)
59 : {
60 4042 : MOZ_ASSERT(bump == AlignPtr(bump));
61 4042 : }
62 :
63 593719 : void setBump(void* ptr) {
64 593719 : MOZ_ASSERT(bumpBase() <= ptr);
65 593719 : MOZ_ASSERT(ptr <= limit);
66 : #if defined(DEBUG) || defined(MOZ_HAVE_MEM_CHECKS)
67 593719 : char* prevBump = bump;
68 : #endif
69 593719 : bump = static_cast<char*>(ptr);
70 : #ifdef DEBUG
71 593719 : MOZ_ASSERT(contains(prevBump));
72 :
73 : // Clobber the now-free space.
74 593712 : if (prevBump > bump)
75 19113 : memset(bump, 0xcd, prevBump - bump);
76 : #endif
77 :
78 : // Poison/Unpoison memory that we just free'd/allocated.
79 : #if defined(MOZ_HAVE_MEM_CHECKS)
80 : if (prevBump > bump)
81 : MOZ_MAKE_MEM_NOACCESS(bump, prevBump - bump);
82 : else if (bump > prevBump)
83 : MOZ_MAKE_MEM_UNDEFINED(prevBump, bump - prevBump);
84 : #endif
85 593712 : }
86 :
87 : public:
88 1190448 : BumpChunk* next() const { return next_; }
89 3142 : void setNext(BumpChunk* succ) { next_ = succ; }
90 :
91 4014 : size_t used() const { return bump - bumpBase(); }
92 :
93 21 : void* start() const { return bumpBase(); }
94 25664 : void* end() const { return limit; }
95 :
96 0 : size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) {
97 0 : return mallocSizeOf(this);
98 : }
99 :
100 6138 : size_t computedSizeOfIncludingThis() {
101 6138 : return limit - headerBase();
102 : }
103 :
104 3553 : void resetBump() {
105 3553 : setBump(headerBase() + sizeof(BumpChunk));
106 3553 : }
107 :
108 35667 : void* mark() const { return bump; }
109 :
110 18945 : void release(void* mark) {
111 18945 : MOZ_ASSERT(contains(mark));
112 18945 : MOZ_ASSERT(mark <= bump);
113 18945 : setBump(mark);
114 18945 : }
115 :
116 612662 : bool contains(void* mark) const {
117 612662 : return bumpBase() <= mark && mark <= limit;
118 : }
119 :
120 : bool canAlloc(size_t n);
121 :
122 1294383 : size_t unused() {
123 1294383 : return limit - AlignPtr(bump);
124 : }
125 :
126 : // Try to perform an allocation of size |n|, return null if not possible.
127 : MOZ_ALWAYS_INLINE
128 575691 : void* tryAlloc(size_t n) {
129 575691 : char* aligned = AlignPtr(bump);
130 575690 : char* newBump = aligned + n;
131 :
132 575690 : if (newBump > limit)
133 4464 : return nullptr;
134 :
135 : // Check for overflow.
136 571226 : if (MOZ_UNLIKELY(newBump < bump))
137 0 : return nullptr;
138 :
139 571226 : MOZ_ASSERT(canAlloc(n)); // Ensure consistency between "can" and "try".
140 571224 : setBump(newBump);
141 571223 : return aligned;
142 : }
143 :
144 : static BumpChunk* new_(size_t chunkSize);
145 : static void delete_(BumpChunk* chunk);
146 : };
147 :
148 : } // namespace detail
149 :
150 : // LIFO bump allocator: used for phase-oriented and fast LIFO allocations.
151 : //
152 : // Note: |latest| is not necessary "last". We leave BumpChunks latent in the
153 : // chain after they've been released to avoid thrashing before a GC.
154 : class LifoAlloc
155 : {
156 : typedef detail::BumpChunk BumpChunk;
157 :
158 : BumpChunk* first;
159 : BumpChunk* latest;
160 : BumpChunk* last;
161 : size_t markCount;
162 : size_t defaultChunkSize_;
163 : size_t curSize_;
164 : size_t peakSize_;
165 : #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
166 : bool fallibleScope_;
167 : #endif
168 :
169 : void operator=(const LifoAlloc&) = delete;
170 : LifoAlloc(const LifoAlloc&) = delete;
171 :
172 : // Return a BumpChunk that can perform an allocation of at least size |n|
173 : // and add it to the chain appropriately.
174 : //
175 : // Side effect: if retval is non-null, |first| and |latest| are initialized
176 : // appropriately.
177 : BumpChunk* getOrCreateChunk(size_t n);
178 :
179 3193 : void reset(size_t defaultChunkSize) {
180 3193 : MOZ_ASSERT(mozilla::RoundUpPow2(defaultChunkSize) == defaultChunkSize);
181 3193 : first = latest = last = nullptr;
182 3193 : defaultChunkSize_ = defaultChunkSize;
183 3193 : markCount = 0;
184 3193 : curSize_ = 0;
185 3193 : }
186 :
187 : // Append unused chunks to the end of this LifoAlloc.
188 2 : void appendUnused(BumpChunk* start, BumpChunk* end) {
189 2 : MOZ_ASSERT(start && end);
190 2 : if (last)
191 1 : last->setNext(start);
192 : else
193 1 : first = latest = start;
194 2 : last = end;
195 2 : }
196 :
197 : // Append used chunks to the end of this LifoAlloc. We act as if all the
198 : // chunks in |this| are used, even if they're not, so memory may be wasted.
199 563 : void appendUsed(BumpChunk* otherFirst, BumpChunk* otherLatest, BumpChunk* otherLast) {
200 563 : MOZ_ASSERT(otherFirst && otherLatest && otherLast);
201 563 : if (last)
202 562 : last->setNext(otherFirst);
203 : else
204 1 : first = otherFirst;
205 563 : latest = otherLatest;
206 563 : last = otherLast;
207 563 : }
208 :
209 4607 : void incrementCurSize(size_t size) {
210 4607 : curSize_ += size;
211 4607 : if (curSize_ > peakSize_)
212 4522 : peakSize_ = curSize_;
213 4607 : }
214 2096 : void decrementCurSize(size_t size) {
215 2096 : MOZ_ASSERT(curSize_ >= size);
216 2096 : curSize_ -= size;
217 2096 : }
218 :
219 : MOZ_ALWAYS_INLINE
220 571229 : void* allocImpl(size_t n) {
221 : void* result;
222 571229 : if (latest && (result = latest->tryAlloc(n)))
223 565296 : return result;
224 :
225 5929 : if (!getOrCreateChunk(n))
226 0 : return nullptr;
227 :
228 : // Since we just created a large enough chunk, this can't fail.
229 5929 : result = latest->tryAlloc(n);
230 5929 : MOZ_ASSERT(result);
231 5929 : return result;
232 : }
233 :
234 : public:
235 2561 : explicit LifoAlloc(size_t defaultChunkSize)
236 2561 : : peakSize_(0)
237 : #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
238 2561 : , fallibleScope_(true)
239 : #endif
240 : {
241 2561 : reset(defaultChunkSize);
242 2561 : }
243 :
244 : // Steal allocated chunks from |other|.
245 632 : void steal(LifoAlloc* other) {
246 632 : MOZ_ASSERT(!other->markCount);
247 632 : MOZ_ASSERT(!latest);
248 :
249 : // Copy everything from |other| to |this| except for |peakSize_|, which
250 : // requires some care.
251 632 : size_t oldPeakSize = peakSize_;
252 632 : mozilla::PodAssign(this, other);
253 632 : peakSize_ = Max(oldPeakSize, curSize_);
254 :
255 632 : other->reset(defaultChunkSize_);
256 632 : }
257 :
258 : // Append all chunks from |other|. They are removed from |other|.
259 : void transferFrom(LifoAlloc* other);
260 :
261 : // Append unused chunks from |other|. They are removed from |other|.
262 : void transferUnusedFrom(LifoAlloc* other);
263 :
264 1976 : ~LifoAlloc() { freeAll(); }
265 :
266 : size_t defaultChunkSize() const { return defaultChunkSize_; }
267 :
268 : // Frees all held memory.
269 : void freeAll();
270 :
271 : static const unsigned HUGE_ALLOCATION = 50 * 1024 * 1024;
272 1903 : void freeAllIfHugeAndUnused() {
273 1903 : if (markCount == 0 && curSize_ > HUGE_ALLOCATION)
274 0 : freeAll();
275 1903 : }
276 :
277 : MOZ_ALWAYS_INLINE
278 488852 : void* alloc(size_t n) {
279 : #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
280 : // Only simulate OOMs when we are not using the LifoAlloc as an
281 : // infallible allocator.
282 488852 : if (fallibleScope_)
283 480415 : JS_OOM_POSSIBLY_FAIL();
284 : #endif
285 488853 : return allocImpl(n);
286 : }
287 :
288 : MOZ_ALWAYS_INLINE
289 82391 : void* allocInfallible(size_t n) {
290 164782 : AutoEnterOOMUnsafeRegion oomUnsafe;
291 82391 : if (void* result = allocImpl(n))
292 82391 : return result;
293 0 : oomUnsafe.crash("LifoAlloc::allocInfallible");
294 : return nullptr;
295 : }
296 :
297 : // Ensures that enough space exists to satisfy N bytes worth of
298 : // allocation requests, not necessarily contiguous. Note that this does
299 : // not guarantee a successful single allocation of N bytes.
300 : MOZ_ALWAYS_INLINE
301 114958 : MOZ_MUST_USE bool ensureUnusedApproximate(size_t n) {
302 229915 : AutoFallibleScope fallibleAllocator(this);
303 114958 : size_t total = 0;
304 1291399 : for (BumpChunk* chunk = latest; chunk; chunk = chunk->next()) {
305 1290953 : total += chunk->unused();
306 1290963 : if (total >= n)
307 114522 : return true;
308 : }
309 435 : BumpChunk* latestBefore = latest;
310 435 : if (!getOrCreateChunk(n))
311 0 : return false;
312 435 : if (latestBefore)
313 435 : latest = latestBefore;
314 435 : return true;
315 : }
316 :
317 : MOZ_ALWAYS_INLINE
318 4660 : void setAsInfallibleByDefault() {
319 : #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
320 4660 : fallibleScope_ = false;
321 : #endif
322 4660 : }
323 :
324 : class MOZ_NON_TEMPORARY_CLASS AutoFallibleScope {
325 : #if defined(DEBUG) || defined(JS_OOM_BREAKPOINT)
326 : LifoAlloc* lifoAlloc_;
327 : bool prevFallibleScope_;
328 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
329 :
330 : public:
331 480388 : explicit AutoFallibleScope(LifoAlloc* lifoAlloc MOZ_GUARD_OBJECT_NOTIFIER_PARAM) {
332 480388 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
333 480388 : lifoAlloc_ = lifoAlloc;
334 480388 : prevFallibleScope_ = lifoAlloc->fallibleScope_;
335 480388 : lifoAlloc->fallibleScope_ = true;
336 480388 : }
337 :
338 959470 : ~AutoFallibleScope() {
339 479735 : lifoAlloc_->fallibleScope_ = prevFallibleScope_;
340 479735 : }
341 : #else
342 : public:
343 : explicit AutoFallibleScope(LifoAlloc*) {}
344 : #endif
345 : };
346 :
347 : template <typename T>
348 6155 : T* newArray(size_t count) {
349 : static_assert(mozilla::IsPod<T>::value,
350 : "T must be POD so that constructors (and destructors, "
351 : "when the LifoAlloc is freed) need not be called");
352 6155 : return newArrayUninitialized<T>(count);
353 : }
354 :
355 : // Create an array with uninitialized elements of type |T|.
356 : // The caller is responsible for initialization.
357 : template <typename T>
358 6469 : T* newArrayUninitialized(size_t count) {
359 : size_t bytes;
360 6469 : if (MOZ_UNLIKELY(!CalculateAllocSize<T>(count, &bytes)))
361 0 : return nullptr;
362 6469 : return static_cast<T*>(alloc(bytes));
363 : }
364 :
365 : class Mark {
366 : BumpChunk* chunk;
367 : void* markInChunk;
368 : friend class LifoAlloc;
369 19607 : Mark(BumpChunk* chunk, void* markInChunk) : chunk(chunk), markInChunk(markInChunk) {}
370 : public:
371 2065 : Mark() : chunk(nullptr), markInChunk(nullptr) {}
372 : };
373 :
374 19763 : Mark mark() {
375 19763 : markCount++;
376 19763 : return latest ? Mark(latest, latest->mark()) : Mark();
377 : }
378 :
379 19100 : void release(Mark mark) {
380 19100 : markCount--;
381 19100 : if (!mark.chunk) {
382 155 : latest = first;
383 155 : if (latest)
384 155 : latest->resetBump();
385 : } else {
386 18945 : latest = mark.chunk;
387 18945 : latest->release(mark.markInChunk);
388 : }
389 19100 : }
390 :
391 20 : void releaseAll() {
392 20 : MOZ_ASSERT(!markCount);
393 20 : latest = first;
394 20 : if (latest)
395 20 : latest->resetBump();
396 20 : }
397 :
398 : // Get the total "used" (occupied bytes) count for the arena chunks.
399 31 : size_t used() const {
400 31 : size_t accum = 0;
401 31 : for (BumpChunk* chunk = first; chunk; chunk = chunk->next()) {
402 21 : accum += chunk->used();
403 21 : if (chunk == latest)
404 21 : break;
405 : }
406 31 : return accum;
407 : }
408 :
409 : // Return true if the LifoAlloc does not currently contain any allocations.
410 4861 : bool isEmpty() const {
411 4861 : return !latest || !latest->used();
412 : }
413 :
414 : // Return the number of bytes remaining to allocate in the current chunk.
415 : // e.g. How many bytes we can allocate before needing a new block.
416 3430 : size_t availableInCurrentChunk() const {
417 3430 : if (!latest)
418 0 : return 0;
419 3430 : return latest->unused();
420 : }
421 :
422 : // Get the total size of the arena chunks (including unused space).
423 0 : size_t sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
424 0 : size_t n = 0;
425 0 : for (BumpChunk* chunk = first; chunk; chunk = chunk->next())
426 0 : n += chunk->sizeOfIncludingThis(mallocSizeOf);
427 0 : return n;
428 : }
429 :
430 : // Get the total size of the arena chunks (including unused space).
431 51 : size_t computedSizeOfExcludingThis() const {
432 51 : size_t n = 0;
433 51 : for (BumpChunk* chunk = first; chunk; chunk = chunk->next())
434 0 : n += chunk->computedSizeOfIncludingThis();
435 51 : return n;
436 : }
437 :
438 : // Like sizeOfExcludingThis(), but includes the size of the LifoAlloc itself.
439 0 : size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const {
440 0 : return mallocSizeOf(this) + sizeOfExcludingThis(mallocSizeOf);
441 : }
442 :
443 : // Get the peak size of the arena chunks (including unused space and
444 : // bookkeeping space).
445 0 : size_t peakSizeOfExcludingThis() const { return peakSize_; }
446 :
447 : // Doesn't perform construction; useful for lazily-initialized POD types.
448 : template <typename T>
449 : MOZ_ALWAYS_INLINE
450 3430 : T* pod_malloc() {
451 3430 : return static_cast<T*>(alloc(sizeof(T)));
452 : }
453 :
454 49651 : JS_DECLARE_NEW_METHODS(new_, alloc, MOZ_ALWAYS_INLINE)
455 9724 : JS_DECLARE_NEW_METHODS(newInfallible, allocInfallible, MOZ_ALWAYS_INLINE)
456 :
457 : #ifdef DEBUG
458 0 : bool contains(void* ptr) const {
459 0 : for (BumpChunk* chunk = first; chunk; chunk = chunk->next()) {
460 0 : if (chunk->contains(ptr))
461 0 : return true;
462 : }
463 0 : return false;
464 : }
465 : #endif
466 :
467 : // A mutable enumeration of the allocated data.
468 : class Enum
469 : {
470 : friend class LifoAlloc;
471 : friend class detail::BumpChunk;
472 :
473 : LifoAlloc* alloc_; // The LifoAlloc being traversed.
474 : BumpChunk* chunk_; // The current chunk.
475 : char* position_; // The current position (must be within chunk_).
476 :
477 : // If there is not enough room in the remaining block for |size|,
478 : // advance to the next block and update the position.
479 12832 : void ensureSpaceAndAlignment(size_t size) {
480 12832 : MOZ_ASSERT(!empty());
481 12832 : char* aligned = detail::AlignPtr(position_);
482 12832 : if (aligned + size > chunk_->end()) {
483 0 : chunk_ = chunk_->next();
484 0 : position_ = static_cast<char*>(chunk_->start());
485 : } else {
486 12832 : position_ = aligned;
487 : }
488 12832 : MOZ_ASSERT(uintptr_t(position_) + size <= uintptr_t(chunk_->end()));
489 12832 : }
490 :
491 : public:
492 21 : explicit Enum(LifoAlloc& alloc)
493 21 : : alloc_(&alloc),
494 21 : chunk_(alloc.first),
495 42 : position_(static_cast<char*>(alloc.first ? alloc.first->start() : nullptr))
496 21 : {}
497 :
498 : // Return true if there are no more bytes to enumerate.
499 16061 : bool empty() {
500 16061 : return !chunk_ || (chunk_ == alloc_->latest && position_ >= chunk_->mark());
501 : }
502 :
503 : // Move the read position forward by the size of one T.
504 : template <typename T>
505 3208 : void popFront() {
506 3208 : popFront(sizeof(T));
507 3208 : }
508 :
509 : // Move the read position forward by |size| bytes.
510 6416 : void popFront(size_t size) {
511 6416 : ensureSpaceAndAlignment(size);
512 6416 : position_ = position_ + size;
513 6416 : }
514 :
515 : // Update the bytes at the current position with a new value.
516 : template <typename T>
517 : void updateFront(const T& t) {
518 : ensureSpaceAndAlignment(sizeof(T));
519 : memmove(position_, &t, sizeof(T));
520 : }
521 :
522 : // Return a pointer to the item at the current position. This
523 : // returns a pointer to the inline storage, not a copy.
524 : template <typename T>
525 6416 : T* get(size_t size = sizeof(T)) {
526 6416 : ensureSpaceAndAlignment(size);
527 6416 : return reinterpret_cast<T*>(position_);
528 : }
529 :
530 : // Return a Mark at the current position of the Enum.
531 : Mark mark() {
532 : alloc_->markCount++;
533 : return Mark(chunk_, position_);
534 : }
535 : };
536 : };
537 :
538 : class MOZ_NON_TEMPORARY_CLASS LifoAllocScope
539 : {
540 : LifoAlloc* lifoAlloc;
541 : LifoAlloc::Mark mark;
542 : LifoAlloc::AutoFallibleScope fallibleScope;
543 : bool shouldRelease;
544 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
545 :
546 : public:
547 5555 : explicit LifoAllocScope(LifoAlloc* lifoAlloc
548 : MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
549 5555 : : lifoAlloc(lifoAlloc),
550 : mark(lifoAlloc->mark()),
551 : fallibleScope(lifoAlloc),
552 5555 : shouldRelease(true)
553 : {
554 5555 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
555 5555 : }
556 :
557 9804 : ~LifoAllocScope() {
558 4902 : if (shouldRelease)
559 4902 : lifoAlloc->release(mark);
560 4902 : }
561 :
562 293372 : LifoAlloc& alloc() {
563 293372 : return *lifoAlloc;
564 : }
565 :
566 0 : void releaseEarly() {
567 0 : MOZ_ASSERT(shouldRelease);
568 0 : lifoAlloc->release(mark);
569 0 : shouldRelease = false;
570 0 : }
571 : };
572 :
573 : enum Fallibility {
574 : Fallible,
575 : Infallible
576 : };
577 :
578 : template <Fallibility fb>
579 : class LifoAllocPolicy
580 : {
581 : LifoAlloc& alloc_;
582 :
583 : public:
584 4192 : MOZ_IMPLICIT LifoAllocPolicy(LifoAlloc& alloc)
585 4192 : : alloc_(alloc)
586 4192 : {}
587 : template <typename T>
588 3284 : T* maybe_pod_malloc(size_t numElems) {
589 : size_t bytes;
590 3284 : if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes)))
591 0 : return nullptr;
592 3284 : void* p = fb == Fallible ? alloc_.alloc(bytes) : alloc_.allocInfallible(bytes);
593 3284 : return static_cast<T*>(p);
594 : }
595 : template <typename T>
596 0 : T* maybe_pod_calloc(size_t numElems) {
597 0 : T* p = maybe_pod_malloc<T>(numElems);
598 0 : if (MOZ_UNLIKELY(!p))
599 0 : return nullptr;
600 0 : memset(p, 0, numElems * sizeof(T));
601 0 : return p;
602 : }
603 : template <typename T>
604 562 : T* maybe_pod_realloc(T* p, size_t oldSize, size_t newSize) {
605 562 : T* n = maybe_pod_malloc<T>(newSize);
606 562 : if (MOZ_UNLIKELY(!n))
607 0 : return nullptr;
608 562 : MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value));
609 562 : memcpy(n, p, Min(oldSize * sizeof(T), newSize * sizeof(T)));
610 562 : return n;
611 : }
612 : template <typename T>
613 2722 : T* pod_malloc(size_t numElems) {
614 2722 : return maybe_pod_malloc<T>(numElems);
615 : }
616 : template <typename T>
617 0 : T* pod_calloc(size_t numElems) {
618 0 : return maybe_pod_calloc<T>(numElems);
619 : }
620 : template <typename T>
621 562 : T* pod_realloc(T* p, size_t oldSize, size_t newSize) {
622 562 : return maybe_pod_realloc<T>(p, oldSize, newSize);
623 : }
624 873 : void free_(void* p) {
625 873 : }
626 0 : void reportAllocOverflow() const {
627 0 : }
628 1951 : MOZ_MUST_USE bool checkSimulatedOOM() const {
629 1951 : return fb == Infallible || !js::oom::ShouldFailWithOOM();
630 : }
631 : };
632 :
633 : } // namespace js
634 :
635 : #endif /* ds_LifoAlloc_h */
|