From 529830df2e988109843d2780ce6764738391c125 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Tue, 5 Aug 2014 14:06:35 -0700 Subject: [PATCH] Bug 1033442 - Remove non-pod calloc from MallocProvider and AllocPolicy; r=jonco --- js/public/HashTable.h | 2 +- js/src/ds/LifoAlloc.h | 9 +++++--- js/src/jit/IonAllocPolicy.h | 15 +++++-------- js/src/jit/RematerializedFrame.cpp | 2 +- js/src/jsalloc.h | 9 ++++---- js/src/jscntxt.h | 1 - js/src/jsinfer.cpp | 4 ++-- js/src/jsiter.cpp | 2 +- js/src/jsscript.cpp | 35 ++++++++++++++---------------- js/src/vm/MallocProvider.h | 30 ++++++++++++++++--------- js/src/vm/Runtime.h | 9 ++++++-- js/src/vm/Shape.cpp | 6 ++--- js/src/vm/Shape.h | 5 +---- layout/style/nsNthIndexCache.h | 7 +++++- memory/replace/dmd/DMD.cpp | 8 +++++++ mfbt/AllocPolicy.h | 7 +++--- 16 files changed, 87 insertions(+), 64 deletions(-) diff --git a/js/public/HashTable.h b/js/public/HashTable.h index 4c27308b5eb5..1c4f0d702bf3 100644 --- a/js/public/HashTable.h +++ b/js/public/HashTable.h @@ -1067,7 +1067,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(alloc.calloc_(capacity * sizeof(Entry))); + return alloc.template pod_calloc(capacity); } static void destroyTable(AllocPolicy &alloc, Entry *oldTable, uint32_t capacity) diff --git a/js/src/ds/LifoAlloc.h b/js/src/ds/LifoAlloc.h index 29fa677efc95..555d3b256442 100644 --- a/js/src/ds/LifoAlloc.h +++ b/js/src/ds/LifoAlloc.h @@ -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 + T *pod_calloc(size_t numElems) { + if (numElems & mozilla::tl::MulOverflowMask::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) { diff --git a/js/src/jit/IonAllocPolicy.h b/js/src/jit/IonAllocPolicy.h index d1e0f319e3ac..831851c1999e 100644 --- a/js/src/jit/IonAllocPolicy.h +++ b/js/src/jit/IonAllocPolicy.h @@ -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 + T *pod_calloc(size_t numElems) { + if (numElems & mozilla::tl::MulOverflowMask::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) diff --git a/js/src/jit/RematerializedFrame.cpp b/js/src/jit/RematerializedFrame.cpp index 4fd724893761..1c72e47bd6d9 100644 --- a/js/src/jit/RematerializedFrame.cpp +++ b/js/src/jit/RematerializedFrame.cpp @@ -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(numBytes); if (!buf) return nullptr; diff --git a/js/src/jsalloc.h b/js/src/jsalloc.h index a1e547cec942..a026e7bd0393 100644 --- a/js/src/jsalloc.h +++ b/js/src/jsalloc.h @@ -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 T *pod_calloc(size_t numElems) { return js_pod_calloc(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 + T *pod_calloc(size_t numElems) { + T *p = js_pod_calloc(numElems); if (MOZ_UNLIKELY(!p)) - p = onOutOfMemory(nullptr, bytes); + p = (T *)onOutOfMemory(reinterpret_cast(1), numElems * sizeof(T)); return p; } diff --git a/js/src/jscntxt.h b/js/src/jscntxt.h index b184934a8610..7f7a8add373d 100644 --- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -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_); } diff --git a/js/src/jsinfer.cpp b/js/src/jsinfer.cpp index 6d83363deef5..27e1b1cc04f4 100644 --- a/js/src/jsinfer.cpp +++ b/js/src/jsinfer.cpp @@ -3443,7 +3443,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(numBytes); if (!newScript) return; @@ -3606,7 +3606,7 @@ JSScript::makeTypes(JSContext *cx) unsigned count = TypeScript::NumTypeSets(this); TypeScript *typeScript = (TypeScript *) - cx->calloc_(TypeScript::SizeIncludingTypeArray(count)); + zone()->pod_calloc(TypeScript::SizeIncludingTypeArray(count)); if (!typeScript) return false; diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index c2652f035ad7..17dba45ac105 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -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(nbytes); if (!gen) return nullptr; diff --git a/js/src/jsscript.cpp b/js/src/jsscript.cpp index 15f9d97d609b..ff6f3eb1b001 100644 --- a/js/src/jsscript.cpp +++ b/js/src/jsscript.cpp @@ -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(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(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(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(nbytes); if (!debug) return false; diff --git a/js/src/vm/MallocProvider.h b/js/src/vm/MallocProvider.h index 40f902f3303d..a9ef261bbbd6 100644 --- a/js/src/vm/MallocProvider.h +++ b/js/src/vm/MallocProvider.h @@ -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(this); - client->updateMallocCounter(bytes); - void *p = js_calloc(bytes); - return MOZ_LIKELY(!!p) ? p : client->onOutOfMemory(reinterpret_cast(1), bytes); - } - void *realloc_(void *p, size_t oldBytes, size_t newBytes) { Client *client = static_cast(this); /* @@ -93,7 +90,14 @@ struct MallocProvider template T *pod_calloc() { - return (T *)calloc_(sizeof(T)); + Client *client = static_cast(this); + client->updateMallocCounter(sizeof(T)); + T *p = js_pod_calloc(); + if (MOZ_UNLIKELY(!p)) { + client->onOutOfMemory(reinterpret_cast(1), sizeof(T)); + return nullptr; + } + return p; } template @@ -120,7 +124,14 @@ struct MallocProvider client->reportAllocationOverflow(); return nullptr; } - return (T *)calloc_(numElems * sizeof(T)); + Client *client = static_cast(this); + client->updateMallocCounter(numElems * sizeof(T)); + T *p = js_pod_calloc(numElems); + if (MOZ_UNLIKELY(!p)) { + client->onOutOfMemory(reinterpret_cast(1), sizeof(T)); + return nullptr; + } + return p; } template @@ -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) }; diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index 9364cc13dc11..222acbd73ad7 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -1372,7 +1372,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(bytes); if (MOZ_LIKELY(!!p)) return p; return onOutOfMemoryCanGC(reinterpret_cast(1), bytes); @@ -1652,7 +1652,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 + T *pod_calloc(size_t numElems) { + return runtime->pod_calloc(numElems); + } + void *realloc_(void *p, size_t bytes) { return runtime->realloc_(p, bytes); } void free_(void *p) { js_free(p); } void reportAllocOverflow() const {} diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index 705b74501fe5..fdd3baf54eae 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -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(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(newsize); if (!newTable) return false; diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index 7eceb7ff6369..e334c466cfde 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -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); diff --git a/layout/style/nsNthIndexCache.h b/layout/style/nsNthIndexCache.h index 06ef28a94d5b..23a1c8f3082a 100644 --- a/layout/style/nsNthIndexCache.h +++ b/layout/style/nsNthIndexCache.h @@ -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 + T *pod_calloc(size_t numElems) { + return static_cast(::calloc(numElems, sizeof(T))); + } + void *realloc_(void *p, size_t bytes) { return ::realloc(p, bytes); } void free_(void *p) { ::free(p); } void reportAllocOverflow() const {} diff --git a/memory/replace/dmd/DMD.cpp b/memory/replace/dmd/DMD.cpp index 3861df1c36b2..91dd23daedd5 100644 --- a/memory/replace/dmd/DMD.cpp +++ b/memory/replace/dmd/DMD.cpp @@ -109,6 +109,14 @@ public: return p; } + template + 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) { diff --git a/mfbt/AllocPolicy.h b/mfbt/AllocPolicy.h index 357c632a02bb..c2fcd83d4fc5 100644 --- a/mfbt/AllocPolicy.h +++ b/mfbt/AllocPolicy.h @@ -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 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 + T* pod_calloc(size_t aNumElems) { - return calloc(aBytes, 1); + return static_cast(calloc(aNumElems, sizeof(T))); } void* realloc_(void* aPtr, size_t aOldBytes, size_t aBytes)