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

This commit is contained in:
Terrence Cole 2014-08-05 14:06:35 -07:00
parent 2ee3959bc7
commit 255bf6c3fb
16 changed files with 87 additions and 64 deletions

View File

@ -1080,7 +1080,7 @@ class HashTable : private AllocPolicy
"newly-calloc'd tables have to be considered empty");
static_assert(sMaxCapacity <= SIZE_MAX / sizeof(Entry),
"would overflow allocating max number of entries");
return static_cast<Entry*>(alloc.calloc_(capacity * sizeof(Entry)));
return alloc.template pod_calloc<Entry>(capacity);
}
static void destroyTable(AllocPolicy &alloc, Entry *oldTable, uint32_t capacity)

View File

@ -519,11 +519,14 @@ class LifoAllocPolicy
void *malloc_(size_t bytes) {
return fb == Fallible ? alloc_.alloc(bytes) : alloc_.allocInfallible(bytes);
}
void *calloc_(size_t bytes) {
void *p = malloc_(bytes);
template <typename T>
T *pod_calloc(size_t numElems) {
if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
return nullptr;
T *p = (T *)malloc_(numElems * sizeof(T));
if (fb == Fallible && !p)
return nullptr;
memset(p, 0, bytes);
memset(p, 0, numElems * sizeof(T));
return p;
}
void *realloc_(void *p, size_t oldBytes, size_t bytes) {

View File

@ -103,10 +103,13 @@ class IonAllocPolicy
void *malloc_(size_t bytes) {
return alloc_.allocate(bytes);
}
void *calloc_(size_t bytes) {
void *p = alloc_.allocate(bytes);
template <typename T>
T *pod_calloc(size_t numElems) {
if (numElems & mozilla::tl::MulOverflowMask<sizeof(T)>::value)
return nullptr;
T *p = (T *)alloc_.allocate(numElems * sizeof(T));
if (p)
memset(p, 0, bytes);
memset(p, 0, numElems * sizeof(T));
return p;
}
void *realloc_(void *p, size_t oldBytes, size_t bytes) {
@ -132,12 +135,6 @@ class OldIonAllocPolicy
void *malloc_(size_t bytes) {
return GetIonContext()->temp->allocate(bytes);
}
void *calloc_(size_t bytes) {
void *p = GetIonContext()->temp->allocate(bytes);
if (p)
memset(p, 0, bytes);
return p;
}
void *realloc_(void *p, size_t oldBytes, size_t bytes) {
void *n = malloc_(bytes);
if (!n)

View File

@ -52,7 +52,7 @@ RematerializedFrame::New(ThreadSafeContext *cx, uint8_t *top, InlineFrameIterato
(numActualArgs + iter.script()->nfixed()) * sizeof(Value) -
sizeof(Value); // 1 Value included in sizeof(RematerializedFrame)
void *buf = cx->calloc_(numBytes);
void *buf = cx->pod_calloc<uint8_t>(numBytes);
if (!buf)
return nullptr;

View File

@ -26,7 +26,7 @@ class SystemAllocPolicy
{
public:
void *malloc_(size_t bytes) { return js_malloc(bytes); }
void *calloc_(size_t bytes) { return js_calloc(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); }
void free_(void *p) { js_free(p); }
void reportAllocOverflow() const {}
@ -62,10 +62,11 @@ class TempAllocPolicy
return p;
}
void *calloc_(size_t bytes) {
void *p = js_calloc(bytes);
template <typename T>
T *pod_calloc(size_t numElems) {
T *p = js_pod_calloc<T>(numElems);
if (MOZ_UNLIKELY(!p))
p = onOutOfMemory(nullptr, bytes);
p = (T *)onOutOfMemory(reinterpret_cast<void *>(1), numElems * sizeof(T));
return p;
}

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 *calloc_(size_t bytes) { return cx_->calloc_(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

@ -3389,7 +3389,7 @@ CheckNewScriptProperties(JSContext *cx, TypeObject *type, JSFunction *fun)
size_t numBytes = sizeof(TypeNewScript)
+ (initializerList.length() * sizeof(TypeNewScript::Initializer));
TypeNewScript *newScript = (TypeNewScript *) cx->calloc_(numBytes);
TypeNewScript *newScript = (TypeNewScript *) type->zone()->pod_calloc<uint8_t>(numBytes);
if (!newScript)
return;
@ -3552,7 +3552,7 @@ JSScript::makeTypes(JSContext *cx)
unsigned count = TypeScript::NumTypeSets(this);
TypeScript *typeScript = (TypeScript *)
cx->calloc_(TypeScript::SizeIncludingTypeArray(count));
zone()->pod_calloc<uint8_t>(TypeScript::SizeIncludingTypeArray(count));
if (!typeScript)
return false;

View File

@ -1784,7 +1784,7 @@ js_NewGenerator(JSContext *cx, const InterpreterRegs &stackRegs)
JS_ASSERT(nbytes % sizeof(Value) == 0);
JS_STATIC_ASSERT(sizeof(InterpreterFrame) % sizeof(HeapValue) == 0);
JSGenerator *gen = (JSGenerator *) cx->calloc_(nbytes);
JSGenerator *gen = (JSGenerator *) obj->zone()->pod_calloc<uint8_t>(nbytes);
if (!gen)
return nullptr;

View File

@ -1138,8 +1138,8 @@ JSScript::initScriptCounts(JSContext *cx)
for (jsbytecode *pc = code(); pc < codeEnd(); pc += GetBytecodeLength(pc))
n += PCCounts::numCounts(JSOp(*pc));
size_t bytes = (length() * sizeof(PCCounts)) + (n * sizeof(double));
char *base = (char *) cx->calloc_(bytes);
size_t nbytes = (length() * sizeof(PCCounts)) + (n * sizeof(double));
uint8_t *base = zone()->pod_calloc<uint8_t>(nbytes);
if (!base)
return false;
@ -1155,7 +1155,7 @@ JSScript::initScriptCounts(JSContext *cx)
compartment()->scriptCountsMap = map;
}
char *cursor = base;
uint8_t *cursor = base;
ScriptCounts scriptCounts;
scriptCounts.pcCountsVector = (PCCounts *) cursor;
@ -1177,7 +1177,7 @@ JSScript::initScriptCounts(JSContext *cx)
}
hasScriptCounts_ = true; // safe to set this; we can't fail after this point
JS_ASSERT(size_t(cursor - base) == bytes);
JS_ASSERT(size_t(cursor - base) == nbytes);
/* Enable interrupts in any interpreter frames running on this script. */
for (ActivationIterator iter(cx->runtime()); !iter.done(); ++iter) {
@ -2358,14 +2358,15 @@ JSScript::Create(ExclusiveContext *cx, HandleObject enclosingScope, bool savedCa
}
static inline uint8_t *
AllocScriptData(ExclusiveContext *cx, size_t size)
AllocScriptData(JS::Zone *zone, size_t size)
{
uint8_t *data = static_cast<uint8_t *>(cx->calloc_(JS_ROUNDUP(size, sizeof(Value))));
if (!data)
if (!size)
return nullptr;
// All script data is optional, so size might be 0. In that case, we don't care about alignment.
JS_ASSERT(size == 0 || size_t(data) % sizeof(Value) == 0);
uint8_t *data = zone->pod_calloc<uint8_t>(JS_ROUNDUP(size, sizeof(Value)));
if (!data)
return nullptr;
JS_ASSERT(size_t(data) % sizeof(Value) == 0);
return data;
}
@ -2376,13 +2377,9 @@ JSScript::partiallyInit(ExclusiveContext *cx, HandleScript script, uint32_t ncon
{
size_t size = ScriptDataSize(script->bindings.count(), nconsts, nobjects, nregexps, ntrynotes,
nblockscopes);
if (size > 0) {
script->data = AllocScriptData(cx, size);
if (!script->data)
return false;
} else {
script->data = nullptr;
}
script->data = AllocScriptData(script->zone(), size);
if (size && !script->data)
return false;
script->dataSize_ = size;
JS_ASSERT(nTypeSets <= UINT16_MAX);
@ -2890,8 +2887,8 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun,
/* Script data */
size_t size = src->dataSize();
uint8_t *data = AllocScriptData(cx, size);
if (!data)
uint8_t *data = AllocScriptData(cx->zone(), size);
if (size && !data)
return nullptr;
/* Bindings */
@ -3152,7 +3149,7 @@ JSScript::ensureHasDebugScript(JSContext *cx)
return true;
size_t nbytes = offsetof(DebugScript, breakpoints) + length() * sizeof(BreakpointSite*);
DebugScript *debug = (DebugScript *) cx->calloc_(nbytes);
DebugScript *debug = (DebugScript *) zone()->pod_calloc<uint8_t>(nbytes);
if (!debug)
return false;

View File

@ -23,6 +23,10 @@
* - TempAllocPolicy: Adds automatic error reporting to the provided
* Context when allocations fail.
*
* - ContextAllocPolicy: forwards to the JSContext MallocProvider.
*
* - RuntimeAllocPolicy: forwards to the JSRuntime MallocProvider.
*
* - MallocProvider. A mixin base class that handles automatically updating
* the GC's state in response to allocations that are tied to a GC lifetime
* or are for a particular GC purpose. These allocators must only be used
@ -55,13 +59,6 @@ struct MallocProvider
return MOZ_LIKELY(!!p) ? p : client->onOutOfMemory(nullptr, bytes);
}
void *calloc_(size_t bytes) {
Client *client = static_cast<Client *>(this);
client->updateMallocCounter(bytes);
void *p = js_calloc(bytes);
return MOZ_LIKELY(!!p) ? p : client->onOutOfMemory(reinterpret_cast<void *>(1), bytes);
}
void *realloc_(void *p, size_t oldBytes, size_t newBytes) {
Client *client = static_cast<Client *>(this);
/*
@ -93,7 +90,14 @@ struct MallocProvider
template <class T>
T *pod_calloc() {
return (T *)calloc_(sizeof(T));
Client *client = static_cast<Client *>(this);
client->updateMallocCounter(sizeof(T));
T *p = js_pod_calloc<T>();
if (MOZ_UNLIKELY(!p)) {
client->onOutOfMemory(reinterpret_cast<void *>(1), sizeof(T));
return nullptr;
}
return p;
}
template <class T>
@ -120,7 +124,14 @@ struct MallocProvider
client->reportAllocationOverflow();
return nullptr;
}
return (T *)calloc_(numElems * sizeof(T));
Client *client = static_cast<Client *>(this);
client->updateMallocCounter(numElems * sizeof(T));
T *p = js_pod_calloc<T>(numElems);
if (MOZ_UNLIKELY(!p)) {
client->onOutOfMemory(reinterpret_cast<void *>(1), sizeof(T));
return nullptr;
}
return p;
}
template <class T>
@ -137,7 +148,6 @@ struct MallocProvider
return (T *)realloc_(prior, oldSize * sizeof(T), newSize * sizeof(T));
}
JS_DECLARE_NEW_METHODS(new_, malloc_, MOZ_ALWAYS_INLINE)
JS_DECLARE_MAKE_METHODS(make_unique, new_, MOZ_ALWAYS_INLINE)
};

View File

@ -1370,7 +1370,7 @@ struct JSRuntime : public JS::shadow::Runtime,
static const unsigned LARGE_ALLOCATION = 25 * 1024 * 1024;
void *callocCanGC(size_t bytes) {
void *p = calloc_(bytes);
void *p = (void *)pod_calloc<uint8_t>(bytes);
if (MOZ_LIKELY(!!p))
return p;
return onOutOfMemoryCanGC(reinterpret_cast<void *>(1), bytes);
@ -1650,7 +1650,12 @@ class RuntimeAllocPolicy
public:
MOZ_IMPLICIT RuntimeAllocPolicy(JSRuntime *rt) : runtime(rt) {}
void *malloc_(size_t bytes) { return runtime->malloc_(bytes); }
void *calloc_(size_t bytes) { return runtime->calloc_(bytes); }
template <typename T>
T *pod_calloc(size_t numElems) {
return runtime->pod_calloc<T>(numElems);
}
void *realloc_(void *p, size_t bytes) { return runtime->realloc_(p, bytes); }
void free_(void *p) { js_free(p); }
void reportAllocOverflow() const {}

View File

@ -45,10 +45,10 @@ ShapeTable::init(ThreadSafeContext *cx, Shape *lastProp)
sizeLog2 = MIN_SIZE_LOG2;
/*
* Use rt->calloc_ for memory accounting and overpressure handling
* Use rt->calloc for memory accounting and overpressure handling
* without OOM reporting. See ShapeTable::change.
*/
entries = (Shape **) cx->calloc_(sizeOfEntries(JS_BIT(sizeLog2)));
entries = cx->pod_calloc<Shape *>(JS_BIT(sizeLog2));
if (!entries)
return false;
@ -260,7 +260,7 @@ ShapeTable::change(int log2Delta, ThreadSafeContext *cx)
int newlog2 = oldlog2 + log2Delta;
uint32_t oldsize = JS_BIT(oldlog2);
uint32_t newsize = JS_BIT(newlog2);
Shape **newTable = (Shape **) cx->calloc_(sizeOfEntries(newsize));
Shape **newTable = cx->pod_calloc<Shape *>(newsize);
if (!newTable)
return false;

View File

@ -161,9 +161,6 @@ struct ShapeTable {
/* By definition, hashShift = HASH_BITS - log2(capacity). */
uint32_t capacity() const { return JS_BIT(HASH_BITS - hashShift); }
/* Computes the size of the entries array for a given capacity. */
static size_t sizeOfEntries(size_t cap) { return cap * sizeof(Shape *); }
/*
* This counts the ShapeTable object itself (which must be
* heap-allocated) and its |entries| array.
@ -187,7 +184,7 @@ struct ShapeTable {
/*
* NB: init and change are fallible but do not report OOM, so callers can
* cope or ignore. They do however use the context's calloc_ method in
* cope or ignore. They do however use the context's calloc method in
* order to update the malloc counter on success.
*/
bool init(ThreadSafeContext *cx, Shape *lastProp);

View File

@ -61,7 +61,12 @@ private:
class SystemAllocPolicy {
public:
void *malloc_(size_t bytes) { return ::malloc(bytes); }
void *calloc_(size_t bytes) { return ::calloc(bytes, 1); }
template <typename T>
T *pod_calloc(size_t numElems) {
return static_cast<T *>(::calloc(numElems, sizeof(T)));
}
void *realloc_(void *p, size_t bytes) { return ::realloc(p, bytes); }
void free_(void *p) { ::free(p); }
void reportAllocOverflow() const {}

View File

@ -109,6 +109,14 @@ public:
return p;
}
template <typename T>
static T* pod_calloc(size_t aNumElems)
{
void* p = gMallocTable->calloc(aNumElems, sizeof(T));
ExitOnFailure(p);
return (T*)p;
}
// This realloc_ is the one we use for direct reallocs within DMD.
static void* realloc_(void* aPtr, size_t aNewSize)
{

View File

@ -26,7 +26,7 @@ namespace mozilla {
* - public copy constructor, assignment, destructor
* - void* malloc_(size_t)
* Responsible for OOM reporting when null is returned.
* - void* calloc_(size_t)
* - 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
@ -55,9 +55,10 @@ public:
return malloc(aBytes);
}
void* calloc_(size_t aBytes)
template <typename T>
T* pod_calloc(size_t aNumElems)
{
return calloc(aBytes, 1);
return static_cast<T*>(calloc(aNumElems, sizeof(T)));
}
void* realloc_(void* aPtr, size_t aOldBytes, size_t aBytes)