Bug 1033442 - Remove non-pod realloc from MallocProvider and AllocPolicy; r=jonco

This commit is contained in:
Terrence Cole 2014-08-05 14:06:35 -07:00
parent 529830df2e
commit 3353a9fb7c
21 changed files with 116 additions and 93 deletions

View File

@ -563,6 +563,16 @@ js_pod_calloc(size_t numElems)
return (T *)js_calloc(numElems * sizeof(T));
}
template <class T>
static MOZ_ALWAYS_INLINE T *
js_pod_realloc(T *prior, size_t oldSize, size_t newSize)
{
MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value));
if (newSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
return nullptr;
return (T *)js_realloc(prior, newSize * sizeof(T));
}
namespace js {
template<typename T>

View File

@ -529,11 +529,14 @@ class LifoAllocPolicy
memset(p, 0, numElems * sizeof(T));
return p;
}
void *realloc_(void *p, size_t oldBytes, size_t bytes) {
void *n = malloc_(bytes);
template <typename T>
T *pod_realloc(T *p, size_t oldSize, size_t newSize) {
if (newSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
return nullptr;
T *n = (T *)malloc_(newSize * sizeof(T));
if (fb == Fallible && !n)
return nullptr;
memcpy(n, p, Min(oldBytes, bytes));
memcpy(n, p, Min(oldSize * sizeof(T), newSize * sizeof(T)));
return n;
}
void free_(void *p) {

View File

@ -585,16 +585,13 @@ ForkJoinNursery::reallocateSlots(JSObject *obj, HeapSlot *oldSlots,
if (newCount & mozilla::tl::MulOverflowMask<sizeof(HeapSlot)>::value)
return nullptr;
size_t oldSize = oldCount * sizeof(HeapSlot);
size_t newSize = newCount * sizeof(HeapSlot);
if (!isInsideNewspace(obj)) {
JS_ASSERT_IF(oldSlots, !isInsideNewspace(oldSlots));
return static_cast<HeapSlot *>(cx_->realloc_(oldSlots, oldSize, newSize));
return obj->zone()->pod_realloc<HeapSlot>(oldSlots, oldCount, newCount);
}
if (!isInsideNewspace(oldSlots))
return reallocateHugeSlots(oldSlots, oldSize, newSize);
return reallocateHugeSlots(obj, oldSlots, oldCount, newCount);
// No-op if we're shrinking, we can't make use of the freed portion.
if (newCount < oldCount)
@ -604,6 +601,7 @@ ForkJoinNursery::reallocateSlots(JSObject *obj, HeapSlot *oldSlots,
if (!newSlots)
return nullptr;
size_t oldSize = oldCount * sizeof(HeapSlot);
js_memcpy(newSlots, oldSlots, oldSize);
return newSlots;
}
@ -650,9 +648,10 @@ ForkJoinNursery::allocateHugeSlots(size_t nslots)
}
HeapSlot *
ForkJoinNursery::reallocateHugeSlots(HeapSlot *oldSlots, uint32_t oldSize, uint32_t newSize)
ForkJoinNursery::reallocateHugeSlots(JSObject *obj, HeapSlot *oldSlots,
uint32_t oldCount, uint32_t newCount)
{
HeapSlot *newSlots = static_cast<HeapSlot *>(cx_->realloc_(oldSlots, oldSize, newSize));
HeapSlot *newSlots = obj->zone()->pod_realloc<HeapSlot>(oldSlots, oldCount, newCount);
if (!newSlots)
return newSlots;

View File

@ -210,7 +210,8 @@ class ForkJoinNursery
// Reallocate an external slot array, unregister the old array and
// register the new array. If the allocation fails then leave
// everything unchanged.
HeapSlot *reallocateHugeSlots(HeapSlot *oldSlots, uint32_t oldSize, uint32_t newSize);
HeapSlot *reallocateHugeSlots(JSObject *obj, HeapSlot *oldSlots,
uint32_t oldCount, uint32_t newCount);
// Walk the list of registered slot arrays and free them all.
void sweepHugeSlots();

View File

@ -112,11 +112,15 @@ class IonAllocPolicy
memset(p, 0, numElems * sizeof(T));
return p;
}
void *realloc_(void *p, size_t oldBytes, size_t bytes) {
void *n = malloc_(bytes);
template <typename T>
T *pod_realloc(T *p, size_t oldSize, size_t newSize) {
MOZ_ASSERT(!(oldSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value));
if (newSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
return nullptr;
T *n = (T *)malloc_(newSize * sizeof(T));
if (!n)
return n;
memcpy(n, p, Min(oldBytes, bytes));
memcpy(n, p, Min(oldSize * sizeof(T), newSize * sizeof(T)));
return n;
}
void free_(void *p) {
@ -135,13 +139,6 @@ class OldIonAllocPolicy
void *malloc_(size_t bytes) {
return GetIonContext()->temp->allocate(bytes);
}
void *realloc_(void *p, size_t oldBytes, size_t bytes) {
void *n = malloc_(bytes);
if (!n)
return n;
memcpy(n, p, Min(oldBytes, bytes));
return n;
}
void free_(void *p) {
}
void reportAllocOverflow() const {

View File

@ -1054,7 +1054,7 @@ MPhi::reserveLength(size_t length)
{
// Initializes a new MPhi to have an Operand vector of at least the given
// capacity. This permits use of addInput() instead of addInputSlow(), the
// latter of which may call realloc_().
// latter of which may call realloc().
JS_ASSERT(numOperands() == 0);
#if DEBUG
capacity_ = length;

View File

@ -5250,7 +5250,7 @@ class MPhi MOZ_FINAL : public MDefinition, public InlineListNode<MPhi>
// Use only if capacity has been reserved by reserveLength
void addInput(MDefinition *ins);
// Appends a new input to the input vector. May call realloc_().
// Appends a new input to the input vector. May call realloc().
// Prefer reserveLength() and addInput() instead, where possible.
bool addInputSlow(MDefinition *ins, bool *ptypeChange = nullptr);

View File

@ -27,7 +27,9 @@ class SystemAllocPolicy
public:
void *malloc_(size_t bytes) { return js_malloc(bytes); }
template <typename T> T *pod_calloc(size_t numElems) { return js_pod_calloc<T>(numElems); }
void *realloc_(void *p, size_t oldBytes, size_t bytes) { return js_realloc(p, bytes); }
template <typename T> T *pod_realloc(T *p, size_t oldSize, size_t newSize) {
return js_pod_realloc<T>(p, oldSize, newSize);
}
void free_(void *p) { js_free(p); }
void reportAllocOverflow() const {}
};
@ -70,10 +72,11 @@ class TempAllocPolicy
return p;
}
void *realloc_(void *p, size_t oldBytes, size_t bytes) {
void *p2 = js_realloc(p, bytes);
template <typename T>
T *pod_realloc(T *prior, size_t oldSize, size_t newSize) {
T *p2 = js_pod_realloc<T>(prior, oldSize, newSize);
if (MOZ_UNLIKELY(!p2))
p2 = onOutOfMemory(p2, bytes);
p2 = (T *)onOutOfMemory(p2, newSize * sizeof(T));
return p2;
}

View File

@ -1439,11 +1439,12 @@ JS_malloc(JSContext *cx, size_t nbytes)
}
JS_PUBLIC_API(void *)
JS_realloc(JSContext *cx, void *p, size_t nbytes)
JS_realloc(JSContext *cx, void *p, size_t oldBytes, size_t newBytes)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
return cx->realloc_(p, nbytes);
return static_cast<void *>(cx->zone()->pod_realloc<uint8_t>(static_cast<uint8_t *>(p), oldBytes,
newBytes));
}
JS_PUBLIC_API(void)

View File

@ -1861,7 +1861,7 @@ extern JS_PUBLIC_API(void *)
JS_malloc(JSContext *cx, size_t nbytes);
extern JS_PUBLIC_API(void *)
JS_realloc(JSContext *cx, void *p, size_t nbytes);
JS_realloc(JSContext *cx, void *p, size_t oldBytes, size_t newBytes);
/*
* A wrapper for js_free(p) that may delay js_free(p) invocation as a

View File

@ -982,7 +982,6 @@ class ContextAllocPolicy
MOZ_IMPLICIT ContextAllocPolicy(ThreadSafeContext *cx) : cx_(cx) {}
ThreadSafeContext *context() const { return cx_; }
void *malloc_(size_t bytes) { return cx_->malloc_(bytes); }
void *realloc_(void *p, size_t oldBytes, size_t bytes) { return cx_->realloc_(p, oldBytes, bytes); }
void free_(void *p) { js_free(p); }
void reportAllocOverflow() const { js_ReportAllocationOverflow(cx_); }
};

View File

@ -499,7 +499,7 @@ ReadEvalPrintLoop(JSContext *cx, Handle<JSObject*> global, FILE *in, FILE *out,
* coincides with the end of a line.
*/
int startline = lineno;
typedef Vector<char, 32, ContextAllocPolicy> CharBuffer;
typedef Vector<char, 32> CharBuffer;
CharBuffer buffer(cx);
do {
ScheduleWatchdog(cx->runtime(), -1);
@ -1507,7 +1507,7 @@ ReadLine(JSContext *cx, unsigned argc, jsval *vp)
char *tmp;
bufsize *= 2;
if (bufsize > buflength) {
tmp = (char *) JS_realloc(cx, buf, bufsize);
tmp = static_cast<char *>(JS_realloc(cx, buf, bufsize / 2, bufsize));
} else {
JS_ReportOutOfMemory(cx);
tmp = nullptr;
@ -1529,7 +1529,7 @@ ReadLine(JSContext *cx, unsigned argc, jsval *vp)
}
/* Shrink the buffer to the real size. */
char *tmp = static_cast<char*>(JS_realloc(cx, buf, buflength));
char *tmp = static_cast<char *>(JS_realloc(cx, buf, bufsize, buflength));
if (!tmp) {
JS_free(cx, buf);
return false;

View File

@ -275,17 +275,22 @@ ArrayBufferObject::class_constructor(JSContext *cx, unsigned argc, Value *vp)
static void *
AllocateArrayBufferContents(JSContext *maybecx, uint32_t nbytes, void *oldptr = nullptr, size_t oldnbytes = 0)
{
void *p;
uint8_t *p;
// if oldptr is given, then we need to do a realloc
if (oldptr) {
p = maybecx ? maybecx->runtime()->reallocCanGC(oldptr, nbytes) : js_realloc(oldptr, nbytes);
uint8_t *prior = static_cast<uint8_t *>(oldptr);
p = maybecx
? maybecx->runtime()->pod_reallocCanGC<uint8_t>(prior, oldnbytes, nbytes)
: js_pod_realloc<uint8_t>(prior, oldnbytes, nbytes);
// if we grew the array, we need to set the new bytes to 0
if (p && nbytes > oldnbytes)
memset(reinterpret_cast<uint8_t *>(p) + oldnbytes, 0, nbytes - oldnbytes);
memset(p + oldnbytes, 0, nbytes - oldnbytes);
} else {
p = maybecx ? maybecx->runtime()->callocCanGC(nbytes) : js_calloc(nbytes);
p = maybecx
? maybecx->runtime()->pod_callocCanGC<uint8_t>(nbytes)
: js_pod_calloc<uint8_t>(nbytes);
}
if (!p && maybecx)

View File

@ -59,30 +59,6 @@ struct MallocProvider
return MOZ_LIKELY(!!p) ? p : client->onOutOfMemory(nullptr, bytes);
}
void *realloc_(void *p, size_t oldBytes, size_t newBytes) {
Client *client = static_cast<Client *>(this);
/*
* For compatibility we do not account for realloc that decreases
* previously allocated memory.
*/
if (newBytes > oldBytes)
client->updateMallocCounter(newBytes - oldBytes);
void *p2 = js_realloc(p, newBytes);
return MOZ_LIKELY(!!p2) ? p2 : client->onOutOfMemory(p, newBytes);
}
void *realloc_(void *p, size_t bytes) {
Client *client = static_cast<Client *>(this);
/*
* For compatibility we do not account for realloc that increases
* previously allocated memory.
*/
if (!p)
client->updateMallocCounter(bytes);
void *p2 = js_realloc(p, bytes);
return MOZ_LIKELY(!!p2) ? p2 : client->onOutOfMemory(p, bytes);
}
template <class T>
T *pod_malloc() {
return (T *)malloc_(sizeof(T));
@ -118,7 +94,7 @@ struct MallocProvider
template <class T>
T *
pod_calloc(size_t numElems, JSCompartment *comp = nullptr, JSContext *cx = nullptr) {
pod_calloc(size_t numElems) {
if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
Client *client = static_cast<Client *>(this);
client->reportAllocationOverflow();
@ -136,16 +112,27 @@ struct MallocProvider
template <class T>
mozilla::UniquePtr<T[], JS::FreePolicy>
make_zeroed_pod_array(size_t numElems,
JSCompartment *comp = nullptr,
JSContext *cx = nullptr)
{
return mozilla::UniquePtr<T[], JS::FreePolicy>(pod_calloc<T>(numElems, comp, cx));
make_zeroed_pod_array(size_t numElems) {
return mozilla::UniquePtr<T[], JS::FreePolicy>(pod_calloc<T>(numElems));
}
template <class T>
T *pod_realloc(T *prior, size_t oldSize, size_t newSize) {
return (T *)realloc_(prior, oldSize * sizeof(T), newSize * sizeof(T));
Client *client = static_cast<Client *>(this);
T *p = js_pod_realloc(prior, oldSize, newSize);
if (MOZ_LIKELY(p)) {
// For compatibility we do not account for realloc that decreases
// previously allocated memory.
if (newSize > oldSize)
client->updateMallocCounter((newSize - oldSize) * sizeof(T));
return p;
}
if (newSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
client->reportAllocationOverflow();
return nullptr;
}
client->onOutOfMemory(prior, newSize * sizeof(T));
return nullptr;
}
JS_DECLARE_NEW_METHODS(new_, malloc_, MOZ_ALWAYS_INLINE)

View File

@ -1371,18 +1371,28 @@ struct JSRuntime : public JS::shadow::Runtime,
static const unsigned LARGE_ALLOCATION = 25 * 1024 * 1024;
void *callocCanGC(size_t bytes) {
void *p = (void *)pod_calloc<uint8_t>(bytes);
template <typename T>
T *pod_callocCanGC(size_t numElems) {
T *p = pod_calloc<T>(numElems);
if (MOZ_LIKELY(!!p))
return p;
return onOutOfMemoryCanGC(reinterpret_cast<void *>(1), bytes);
if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
reportAllocationOverflow();
return nullptr;
}
return (T *)onOutOfMemoryCanGC(reinterpret_cast<void *>(1), numElems * sizeof(T));
}
void *reallocCanGC(void *p, size_t bytes) {
void *p2 = realloc_(p, bytes);
template <typename T>
T *pod_reallocCanGC(T *p, size_t oldSize, size_t newSize) {
T *p2 = pod_realloc<T>(p, oldSize, newSize);
if (MOZ_LIKELY(!!p2))
return p2;
return onOutOfMemoryCanGC(p, bytes);
if (newSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value) {
reportAllocationOverflow();
return nullptr;
}
return (T *)onOutOfMemoryCanGC(p, newSize * sizeof(T));
}
};
@ -1658,7 +1668,11 @@ class RuntimeAllocPolicy
return runtime->pod_calloc<T>(numElems);
}
void *realloc_(void *p, size_t bytes) { return runtime->realloc_(p, bytes); }
template <typename T>
T *pod_realloc(T *p, size_t oldSize, size_t newSize) {
return runtime->pod_realloc<T>(p, oldSize, newSize);
}
void free_(void *p) { js_free(p); }
void reportAllocOverflow() const {}
};

View File

@ -28,8 +28,7 @@ ExtractWellSized(ExclusiveContext *cx, Buffer &cb)
/* For medium/big buffers, avoid wasting more than 1/4 of the memory. */
JS_ASSERT(capacity >= length);
if (length > Buffer::sMaxInlineStorage && capacity - length > length / 4) {
size_t bytes = sizeof(CharT) * (length + 1);
CharT *tmp = (CharT *)cx->realloc_(buf, bytes);
CharT *tmp = cx->zone()->pod_realloc<CharT>(buf, capacity, length + 1);
if (!tmp) {
js_free(buf);
return nullptr;

View File

@ -33,8 +33,8 @@ class StringBuffer
* The Vector's buffer is taken by the new string so use
* ContextAllocPolicy.
*/
typedef Vector<Latin1Char, 64, ContextAllocPolicy> Latin1CharBuffer;
typedef Vector<jschar, 32, ContextAllocPolicy> TwoByteCharBuffer;
typedef Vector<Latin1Char, 64> Latin1CharBuffer;
typedef Vector<jschar, 32> TwoByteCharBuffer;
ExclusiveContext *cx;

View File

@ -213,8 +213,8 @@ private:
// nsIUnicodeDecoder::Convert may use fewer than srcLength PRUnichars
if (unicharLength + 1 < srcLength + 1) {
char16_t *shrunkUnichars =
(char16_t *)JS_realloc(cx, unichars,
(unicharLength + 1) * sizeof(char16_t));
static_cast<char16_t *>(JS_realloc(cx, unichars, srcLength + 1,
unicharLength + 1));
if (shrunkUnichars)
unichars = shrunkUnichars;
}

View File

@ -126,9 +126,12 @@ public:
}
// This realloc_ is required for this to be a JS container AllocPolicy.
static void* realloc_(void* aPtr, size_t aOldSize, size_t aNewSize)
template <typename T>
static T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize)
{
return InfallibleAllocPolicy::realloc_(aPtr, aNewSize);
if (aNewSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
return nullptr;
return (T*)InfallibleAllocPolicy::realloc_((void *)aPtr, aNewSize * sizeof(T));
}
static void* memalign_(size_t aAlignment, size_t aSize)

View File

@ -12,6 +12,8 @@
#ifndef mozilla_AllocPolicy_h
#define mozilla_AllocPolicy_h
#include "mozilla/TemplateLib.h"
#include <stddef.h>
#include <stdlib.h>
@ -28,10 +30,9 @@ namespace mozilla {
* Responsible for OOM reporting when null is returned.
* - template <typename T> T* pod_calloc(size_t)
* Responsible for OOM reporting when null is returned.
* - void* realloc_(void*, size_t, size_t)
* Responsible for OOM reporting when null is returned. The *used* bytes
* of the previous buffer is passed in (rather than the old allocation
* size), in addition to the *new* allocation size requested.
* - template <typename T> T* pod_realloc(T*, size_t, size_t)
* Responsible for OOM reporting when null is returned. The old allocation
* size is passed in, in addition to the new allocation size requested.
* - void free_(void*)
* - void reportAllocOverflow() const
* Called on allocation overflow (that is, an allocation implicitly tried
@ -61,9 +62,12 @@ public:
return static_cast<T*>(calloc(aNumElems, sizeof(T)));
}
void* realloc_(void* aPtr, size_t aOldBytes, size_t aBytes)
template <typename T>
T* pod_realloc(T* aPtr, size_t aOldSize, size_t aNewSize)
{
return realloc(aPtr, aBytes);
if (aNewSize & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
return nullptr;
return static_cast<T*>(realloc(aPtr, aNewSize * sizeof(T)));
}
void free_(void* aPtr)

View File

@ -204,9 +204,7 @@ struct VectorImpl<T, N, AP, ThisVector, true>
{
MOZ_ASSERT(!aV.usingInlineStorage());
MOZ_ASSERT(!CapacityHasExcessSpace<T>(aNewCap));
size_t oldSize = sizeof(T) * aV.mCapacity;
size_t newSize = sizeof(T) * aNewCap;
T* newbuf = reinterpret_cast<T*>(aV.realloc_(aV.mBegin, oldSize, newSize));
T* newbuf = aV.template pod_realloc<T>(aV.mBegin, aV.mCapacity, aNewCap);
if (!newbuf) {
return false;
}