Bug 1286613 - Don't rely on OSX SDK malloc/malloc.h for malloc_zone struct definitions. r=njn
authorMike Hommey <mh+mozilla@glandium.org>
Wed, 18 Jan 2017 13:50:35 +0900
changeset 377554 0b74f21e41cda7e9317e756d2e497cf89df369fa
parent 377553 5cc62bcc4a538cfbea78e60437a5aa0ce542d5ac
child 377555 07cb49de060b9a2a8ab8f4db5e486c50f76bd3a8
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnjn
bugs1286613
milestone53.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1286613 - Don't rely on OSX SDK malloc/malloc.h for malloc_zone struct definitions. r=njn The SDK jemalloc is built against might be not be the latest for various reasons, but the resulting binary ought to work on newer versions of OSX. In order to ensure this, we need the fullest definitions possible, so copy what we need from the latest version of malloc/malloc.h available on opensource.apple.com. [Adapted from https://github.com/jemalloc/jemalloc/commit/c68bb4179312665e22d375aecf9f4306607c7c1a]
memory/build/zone.c
--- a/memory/build/zone.c
+++ b/memory/build/zone.c
@@ -1,16 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozmemory_wrap.h"
 
 #include <stdlib.h>
-#include <malloc/malloc.h>
+#include <mach/mach_types.h>
 #include "mozilla/Assertions.h"
 
 /*
  * Malloc implementation functions are MOZ_MEMORY_API, and jemalloc
  * specific functions MOZ_JEMALLOC_API; see mozmemory_wrap.h
  */
 #define MALLOC_DECL(name, return_type, ...) \
   MOZ_MEMORY_API return_type name ## _impl(__VA_ARGS__);
@@ -18,25 +18,98 @@
 #include "malloc_decls.h"
 
 #define MALLOC_DECL(name, return_type, ...) \
   MOZ_JEMALLOC_API return_type name ## _impl(__VA_ARGS__);
 #define MALLOC_FUNCS MALLOC_FUNCS_JEMALLOC
 #include "malloc_decls.h"
 
 /*
+ * Definitions of the following structs in malloc/malloc.h might be too old
+ * for the built binary to run on newer versions of OSX. So use the newest
+ * possible version of those structs.
+ */
+typedef struct _malloc_zone_t {
+  void *reserved1;
+  void *reserved2;
+  size_t (*size)(struct _malloc_zone_t *, const void *);
+  void *(*malloc)(struct _malloc_zone_t *, size_t);
+  void *(*calloc)(struct _malloc_zone_t *, size_t, size_t);
+  void *(*valloc)(struct _malloc_zone_t *, size_t);
+  void (*free)(struct _malloc_zone_t *, void *);
+  void *(*realloc)(struct _malloc_zone_t *, void *, size_t);
+  void (*destroy)(struct _malloc_zone_t *);
+  const char *zone_name;
+  unsigned (*batch_malloc)(struct _malloc_zone_t *, size_t, void **, unsigned);
+  void (*batch_free)(struct _malloc_zone_t *, void **, unsigned);
+  struct malloc_introspection_t *introspect;
+  unsigned version;
+  void *(*memalign)(struct _malloc_zone_t *, size_t, size_t);
+  void (*free_definite_size)(struct _malloc_zone_t *, void *, size_t);
+  size_t (*pressure_relief)(struct _malloc_zone_t *, size_t);
+} malloc_zone_t;
+
+typedef struct {
+  vm_address_t address;
+  vm_size_t size;
+} vm_range_t;
+
+typedef struct malloc_statistics_t {
+  unsigned blocks_in_use;
+  size_t size_in_use;
+  size_t max_size_in_use;
+  size_t size_allocated;
+} malloc_statistics_t;
+
+typedef kern_return_t memory_reader_t(task_t, vm_address_t, vm_size_t, void **);
+
+typedef void vm_range_recorder_t(task_t, void *, unsigned type, vm_range_t *, unsigned);
+
+typedef struct malloc_introspection_t {
+  kern_return_t (*enumerator)(task_t, void *, unsigned, vm_address_t, memory_reader_t, vm_range_recorder_t);
+  size_t (*good_size)(malloc_zone_t *, size_t);
+  boolean_t (*check)(malloc_zone_t *);
+  void (*print)(malloc_zone_t *, boolean_t);
+  void (*log)(malloc_zone_t *, void *);
+  void (*force_lock)(malloc_zone_t *);
+  void (*force_unlock)(malloc_zone_t *);
+  void (*statistics)(malloc_zone_t *, malloc_statistics_t *);
+  boolean_t (*zone_locked)(malloc_zone_t *);
+  boolean_t (*enable_discharge_checking)(malloc_zone_t *);
+  boolean_t (*disable_discharge_checking)(malloc_zone_t *);
+  void (*discharge)(malloc_zone_t *, void *);
+#ifdef __BLOCKS__
+  void (*enumerate_discharged_pointers)(malloc_zone_t *, void (^)(void *, void *));
+#else
+  void *enumerate_unavailable_without_blocks;
+#endif
+  void (*reinit_lock)(malloc_zone_t *);
+} malloc_introspection_t;
+
+extern kern_return_t malloc_get_all_zones(task_t, memory_reader_t, vm_address_t **, unsigned *);
+
+extern malloc_zone_t *malloc_default_zone(void);
+
+extern void malloc_zone_register(malloc_zone_t *zone);
+
+extern void malloc_zone_unregister(malloc_zone_t *zone);
+
+extern malloc_zone_t *malloc_default_purgeable_zone(void);
+
+
+/*
  * The following is a OSX zone allocator implementation.
  * /!\ WARNING. It assumes the underlying malloc implementation's
  * malloc_usable_size returns 0 when the given pointer is not owned by
  * the allocator. Sadly, OSX does call zone_size with pointers not
  * owned by the allocator.
  */
 
 static size_t
-zone_size(malloc_zone_t *zone, void *ptr)
+zone_size(malloc_zone_t *zone, const void *ptr)
 {
   return malloc_usable_size_impl(ptr);
 }
 
 static void *
 zone_malloc(malloc_zone_t *zone, size_t size)
 {
   return malloc_impl(size);
@@ -88,17 +161,17 @@ zone_memalign(malloc_zone_t *zone, size_
 }
 
 static void *
 zone_valloc(malloc_zone_t *zone, size_t size)
 {
   return valloc_impl(size);
 }
 
-static void *
+static void
 zone_destroy(malloc_zone_t *zone)
 {
   /* This function should never be called. */
   MOZ_CRASH();
 }
 
 static size_t
 zone_good_size(malloc_zone_t *zone, size_t size)
@@ -125,18 +198,16 @@ zone_force_unlock(malloc_zone_t *zone)
   /* /!\ This calls into jemalloc. It works because we're linked in the
    * same library. Stolen from jemalloc's zone.c. */
   if (isthreaded)
     jemalloc_postfork_parent();
 }
 
 #else
 
-#define JEMALLOC_ZONE_VERSION 6
-
 extern void _malloc_prefork(void);
 extern void _malloc_postfork(void);
 
 static void
 zone_force_lock(malloc_zone_t *zone)
 {
   /* /!\ This calls into mozjemalloc. It works because we're linked in the
    * same library. */
@@ -186,56 +257,52 @@ static malloc_zone_t *get_default_zone()
 #ifdef MOZ_REPLACE_MALLOC
 __attribute__((constructor))
 #endif
 void
 register_zone(void)
 {
   malloc_zone_t *default_zone = get_default_zone();
 
-  zone.size = (void *)zone_size;
-  zone.malloc = (void *)zone_malloc;
-  zone.calloc = (void *)zone_calloc;
-  zone.valloc = (void *)zone_valloc;
-  zone.free = (void *)zone_free;
-  zone.realloc = (void *)zone_realloc;
-  zone.destroy = (void *)zone_destroy;
+  zone.size = zone_size;
+  zone.malloc = zone_malloc;
+  zone.calloc = zone_calloc;
+  zone.valloc = zone_valloc;
+  zone.free = zone_free;
+  zone.realloc = zone_realloc;
+  zone.destroy = zone_destroy;
 #ifdef MOZ_REPLACE_MALLOC
   zone.zone_name = "replace_malloc_zone";
 #else
   zone.zone_name = "jemalloc_zone";
 #endif
   zone.batch_malloc = NULL;
   zone.batch_free = NULL;
   zone.introspect = &zone_introspect;
-  zone.version = JEMALLOC_ZONE_VERSION;
+  zone.version = 8;
   zone.memalign = zone_memalign;
   zone.free_definite_size = zone_free_definite_size;
-#if (JEMALLOC_ZONE_VERSION >= 8)
   zone.pressure_relief = NULL;
-#endif
   zone_introspect.enumerator = NULL;
-  zone_introspect.good_size = (void *)zone_good_size;
+  zone_introspect.good_size = zone_good_size;
   zone_introspect.check = NULL;
   zone_introspect.print = NULL;
   zone_introspect.log = NULL;
-  zone_introspect.force_lock = (void *)zone_force_lock;
-  zone_introspect.force_unlock = (void *)zone_force_unlock;
+  zone_introspect.force_lock = zone_force_lock;
+  zone_introspect.force_unlock = zone_force_unlock;
   zone_introspect.statistics = NULL;
   zone_introspect.zone_locked = NULL;
-#if (JEMALLOC_ZONE_VERSION >= 7)
   zone_introspect.enable_discharge_checking = NULL;
   zone_introspect.disable_discharge_checking = NULL;
   zone_introspect.discharge = NULL;
 #ifdef __BLOCKS__
   zone_introspect.enumerate_discharged_pointers = NULL;
 #else
   zone_introspect.enumerate_unavailable_without_blocks = NULL;
 #endif
-#endif
 
   /*
    * The default purgeable zone is created lazily by OSX's libc.  It uses
    * the default zone when it is created for "small" allocations
    * (< 15 KiB), but assumes the default zone is a scalable_zone.  This
    * obviously fails when the default zone is the jemalloc zone, so
    * malloc_default_purgeable_zone is called beforehand so that the
    * default purgeable zone is created when the default zone is still