Bug 1052582 Part 1 - Support an arena parameter for js_pod_malloc and friends. r?sfink draft
authorMatt Howell <mhowell@mozilla.com>
Fri, 29 Jun 2018 13:06:14 -0700
changeset 816165 463609da4378dc2fa1dd93187c1600c55783594c
parent 816164 9302fd8c95c05e5a5cd295dde3bbdac2d58d6256
child 816166 2e61e1c039c5f6448034c2437f2d44650d5351a5
push id115761
push usermhowell@mozilla.com
push dateTue, 10 Jul 2018 16:58:42 +0000
reviewerssfink
bugs1052582
milestone63.0a1
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
js/public/Utility.h
js/src/gc/Zone.h
js/src/vm/MallocProvider.h
testing/mochitest/leaks.py
--- 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")