Bug 1052582 Part 1 - Support an arena parameter for js_pod_malloc and friends. r?sfink
This patch adds new functions taking the arena parameter rather than overloading
existing functions, because there are already overloads of calloc that take
two size_t parameters (which arena_id_t is an alias for), so it couldn't have
been done that way, and malloc and realloc needed to be consistent with calloc.
MozReview-Commit-ID: 1MUXoCUgJWO
--- a/js/public/Utility.h
+++ b/js/public/Utility.h
@@ -376,43 +376,57 @@ namespace js {
extern JS_PUBLIC_DATA(arena_id_t) MallocArena;
extern void InitMallocAllocator();
extern void ShutDownMallocAllocator();
} /* namespace js */
+static inline void* js_arena_malloc(arena_id_t arena, size_t bytes)
+{
+ JS_OOM_POSSIBLY_FAIL();
+ return moz_arena_malloc(arena, bytes);
+}
+
static inline void* js_malloc(size_t bytes)
{
+ return js_arena_malloc(js::MallocArena, bytes);
+}
+
+static inline void* js_arena_calloc(arena_id_t arena, size_t nmemb, size_t size)
+{
JS_OOM_POSSIBLY_FAIL();
- return moz_arena_malloc(js::MallocArena, bytes);
+ return moz_arena_calloc(arena, nmemb, size);
}
static inline void* js_calloc(size_t bytes)
{
- JS_OOM_POSSIBLY_FAIL();
- return moz_arena_calloc(js::MallocArena, bytes, 1);
+ return js_arena_calloc(js::MallocArena, bytes, 1);
}
static inline void* js_calloc(size_t nmemb, size_t size)
{
- JS_OOM_POSSIBLY_FAIL();
- return moz_arena_calloc(js::MallocArena, nmemb, size);
+ return js_arena_calloc(js::MallocArena, nmemb, size);
}
-static inline void* js_realloc(void* p, size_t bytes)
+static inline void* js_arena_realloc(arena_id_t arena, void* p, size_t bytes)
{
// realloc() with zero size is not portable, as some implementations may
// return nullptr on success and free |p| for this. We assume nullptr
// indicates failure and that |p| is still valid.
MOZ_ASSERT(bytes != 0);
JS_OOM_POSSIBLY_FAIL();
- return moz_arena_realloc(js::MallocArena, p, bytes);
+ return moz_arena_realloc(arena, p, bytes);
+}
+
+static inline void* js_realloc(void* p, size_t bytes)
+{
+ return js_arena_realloc(js::MallocArena, p, bytes);
}
static inline void js_free(void* p)
{
// TODO: This should call |moz_arena_free(js::MallocArena, p)| but we
// currently can't enforce that all memory freed here was allocated by
// js_malloc().
free(p);
@@ -557,46 +571,60 @@ js_delete_poison(const T* p)
p->~T();
memset(static_cast<void*>(const_cast<T*>(p)), 0x3B, sizeof(T));
js_free(const_cast<T*>(p));
}
}
template <class T>
static MOZ_ALWAYS_INLINE T*
+js_pod_arena_malloc(arena_id_t arena, size_t numElems)
+{
+ size_t bytes;
+ if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes)))
+ return nullptr;
+ return static_cast<T*>(js_arena_malloc(arena, bytes));
+}
+
+template <class T>
+static MOZ_ALWAYS_INLINE T*
+js_pod_malloc(size_t numElems)
+{
+ return js_pod_arena_malloc<T>(js::MallocArena, numElems);
+}
+
+template <class T>
+static MOZ_ALWAYS_INLINE T*
js_pod_malloc()
{
- return static_cast<T*>(js_malloc(sizeof(T)));
+ return js_pod_malloc<T>(sizeof(T));
+}
+
+template <class T>
+static MOZ_ALWAYS_INLINE T*
+js_pod_arena_calloc(arena_id_t arena, size_t numElems)
+{
+ size_t bytes;
+ if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes)))
+ return nullptr;
+ return static_cast<T*>(js_arena_calloc(arena, bytes, 1));
+}
+
+template <class T>
+static MOZ_ALWAYS_INLINE T*
+js_pod_calloc(size_t numElems)
+{
+ return js_pod_arena_calloc<T>(js::MallocArena, numElems);
}
template <class T>
static MOZ_ALWAYS_INLINE T*
js_pod_calloc()
{
- return static_cast<T*>(js_calloc(sizeof(T)));
-}
-
-template <class T>
-static MOZ_ALWAYS_INLINE T*
-js_pod_malloc(size_t numElems)
-{
- size_t bytes;
- if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes)))
- return nullptr;
- return static_cast<T*>(js_malloc(bytes));
-}
-
-template <class T>
-static MOZ_ALWAYS_INLINE T*
-js_pod_calloc(size_t numElems)
-{
- size_t bytes;
- if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes)))
- return nullptr;
- return static_cast<T*>(js_calloc(bytes));
+ return js_pod_calloc<T>(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));
size_t bytes;
--- a/js/src/gc/Zone.h
+++ b/js/src/gc/Zone.h
@@ -710,18 +710,18 @@ class Zone : public JS::shadow::Zone,
// Delete an empty compartment after its contents have been merged.
void deleteEmptyCompartment(JS::Compartment* comp);
/*
* This variation of calloc will call the large-allocation-failure callback
* on OOM and retry the allocation.
*/
template <typename T>
- T* pod_callocCanGC(size_t numElems) {
- T* p = pod_calloc<T>(numElems);
+ T* pod_callocCanGC(size_t numElems, arena_id_t arena = js::MallocArena) {
+ T* p = pod_calloc<T>(numElems, arena);
if (MOZ_LIKELY(!!p))
return p;
size_t bytes;
if (MOZ_UNLIKELY(!js::CalculateAllocSize<T>(numElems, &bytes))) {
reportAllocationOverflow();
return nullptr;
}
JSRuntime* rt = runtimeFromMainThread();
--- a/js/src/vm/MallocProvider.h
+++ b/js/src/vm/MallocProvider.h
@@ -53,18 +53,18 @@ struct MallocProvider
T* maybe_pod_malloc(size_t numElems) {
T* p = js_pod_malloc<T>(numElems);
if (MOZ_LIKELY(p))
client()->updateMallocCounter(numElems * sizeof(T));
return p;
}
template <class T>
- T* maybe_pod_calloc(size_t numElems) {
- T* p = js_pod_calloc<T>(numElems);
+ T* maybe_pod_calloc(size_t numElems, arena_id_t arena = js::MallocArena) {
+ T* p = js_pod_arena_calloc<T>(arena, numElems);
if (MOZ_LIKELY(p))
client()->updateMallocCounter(numElems * sizeof(T));
return p;
}
template <class T>
T* maybe_pod_realloc(T* prior, size_t oldSize, size_t newSize) {
T* p = js_pod_realloc(prior, oldSize, newSize);
@@ -118,23 +118,18 @@ struct MallocProvider
template <class T>
UniquePtr<T[], JS::FreePolicy>
make_pod_array(size_t numElems) {
return UniquePtr<T[], JS::FreePolicy>(pod_malloc<T>(numElems));
}
template <class T>
- T* pod_calloc() {
- return pod_calloc<T>(1);
- }
-
- template <class T>
- T* pod_calloc(size_t numElems) {
- T* p = maybe_pod_calloc<T>(numElems);
+ T* pod_calloc(size_t numElems = 1, arena_id_t arena = js::MallocArena) {
+ T* p = maybe_pod_calloc<T>(numElems, arena);
if (MOZ_LIKELY(p))
return p;
size_t bytes;
if (MOZ_UNLIKELY(!CalculateAllocSize<T>(numElems, &bytes))) {
client()->reportAllocationOverflow();
return nullptr;
}
p = (T*)client()->onOutOfMemory(AllocFunction::Calloc, bytes);
--- a/testing/mochitest/leaks.py
+++ b/testing/mochitest/leaks.py
@@ -178,19 +178,22 @@ class LSANLeaks(object):
self.foundFrames = set([])
self.recordMoreFrames = None
self.currStack = None
self.maxNumRecordedFrames = 4
# Don't various allocation-related stack frames, as they do not help much to
# distinguish different leaks.
unescapedSkipList = [
- "malloc", "js_malloc", "malloc_", "__interceptor_malloc", "moz_xmalloc",
- "calloc", "js_calloc", "calloc_", "__interceptor_calloc", "moz_xcalloc",
- "realloc", "js_realloc", "realloc_", "__interceptor_realloc", "moz_xrealloc",
+ "malloc", "js_malloc", "js_arena_malloc", "malloc_",
+ "__interceptor_malloc", "moz_xmalloc",
+ "calloc", "js_calloc", "js_arena_calloc", "calloc_",
+ "__interceptor_calloc", "moz_xcalloc",
+ "realloc", "js_realloc", "js_arena_realloc", "realloc_",
+ "__interceptor_realloc", "moz_xrealloc",
"new",
"js::MallocProvider",
]
self.skipListRegExp = re.compile(
"^" + "|".join([re.escape(f) for f in unescapedSkipList]) + "$")
self.startRegExp = re.compile(
"==\d+==ERROR: LeakSanitizer: detected memory leaks")