Bug 1019881 - Ensure the default purgeable zone is after the default zone on OS X. rs=njn
authorMike Hommey <mh+mozilla@glandium.org>
Wed, 11 Jun 2014 11:07:27 +0900
changeset 188055 53be05abd4aa09f05738f79e8ba28738d3038f1d
parent 188054 4e6252527455fd2d2531f4d08934f7a370875059
child 188056 98ca816eb3f2977b758b1d17a9699cb2bcd41d2e
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersnjn
bugs1019881
milestone33.0a1
Bug 1019881 - Ensure the default purgeable zone is after the default zone on OS X. rs=njn
memory/build/replace_malloc.c
memory/jemalloc/0007-Ensure-the-default-purgeable-zone-is-after-the-defau.patch
memory/jemalloc/src/src/zone.c
memory/jemalloc/update.sh
--- a/memory/build/replace_malloc.c
+++ b/memory/build/replace_malloc.c
@@ -474,32 +474,43 @@ register_zone(void)
 
   /*
    * 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
-   * a scalable_zone.  As purgeable zones only exist on >= 10.6, we need
-   * to check for the existence of malloc_default_purgeable_zone() at
-   * run time.
+   * a scalable_zone.
    */
-  malloc_default_purgeable_zone();
+  malloc_zone_t *purgeable_zone = malloc_default_purgeable_zone();
 
   /* Register the custom zone.  At this point it won't be the default. */
   malloc_zone_register(&zone);
 
-  /*
-   * Unregister and reregister the default zone.  On OSX >= 10.6,
-   * unregistering takes the last registered zone and places it at the
-   * location of the specified zone.  Unregistering the default zone thus
-   * makes the last registered one the default.  On OSX < 10.6,
-   * unregistering shifts all registered zones.  The first registered zone
-   * then becomes the default.
-   */
   do {
     malloc_zone_t *default_zone = malloc_default_zone();
+    /*
+     * Unregister and reregister the default zone.  On OSX >= 10.6,
+     * unregistering takes the last registered zone and places it at the
+     * location of the specified zone.  Unregistering the default zone thus
+     * makes the last registered one the default.  On OSX < 10.6,
+     * unregistering shifts all registered zones.  The first registered zone
+     * then becomes the default.
+     */
     malloc_zone_unregister(default_zone);
     malloc_zone_register(default_zone);
+    /*
+     * On OSX 10.6, having the default purgeable zone appear before the default
+     * zone makes some things crash because it thinks it owns the default
+     * zone allocated pointers. We thus unregister/re-register it in order to
+     * ensure it's always after the default zone. On OSX < 10.6, as
+     * unregistering shifts registered zones, this simply removes the purgeable
+     * zone from the list and adds it back at the end, after the default zone.
+     * On OSX >= 10.6, unregistering replaces the purgeable zone with the last
+     * registered zone above, i.e the default zone. Registering it again then
+     * puts it at the end, obviously after the default zone.
+     */
+    malloc_zone_unregister(purgeable_zone);
+    malloc_zone_register(purgeable_zone);
   } while (malloc_default_zone() != &zone);
 }
 #endif
new file mode 100644
--- /dev/null
+++ b/memory/jemalloc/0007-Ensure-the-default-purgeable-zone-is-after-the-defau.patch
@@ -0,0 +1,59 @@
+diff --git a/src/zone.c b/src/zone.c
+index e0302ef..a722287 100644
+--- a/src/zone.c
++++ b/src/zone.c
+@@ -176,6 +176,7 @@ register_zone(void)
+ 	 * register jemalloc's.
+ 	 */
+ 	malloc_zone_t *default_zone = malloc_default_zone();
++	malloc_zone_t *purgeable_zone = NULL;
+ 	if (!default_zone->zone_name ||
+ 	    strcmp(default_zone->zone_name, "DefaultMallocZone") != 0) {
+ 		return;
+@@ -237,22 +238,37 @@ register_zone(void)
+ 	 * run time.
+ 	 */
+ 	if (malloc_default_purgeable_zone != NULL)
+-		malloc_default_purgeable_zone();
++		purgeable_zone = malloc_default_purgeable_zone();
+ 
+ 	/* Register the custom zone.  At this point it won't be the default. */
+ 	malloc_zone_register(&zone);
+ 
+-	/*
+-	 * Unregister and reregister the default zone.  On OSX >= 10.6,
+-	 * unregistering takes the last registered zone and places it at the
+-	 * location of the specified zone.  Unregistering the default zone thus
+-	 * makes the last registered one the default.  On OSX < 10.6,
+-	 * unregistering shifts all registered zones.  The first registered zone
+-	 * then becomes the default.
+-	 */
+ 	do {
+ 		default_zone = malloc_default_zone();
++		/*
++		 * Unregister and reregister the default zone.  On OSX >= 10.6,
++		 * unregistering takes the last registered zone and places it
++		 * at the location of the specified zone.  Unregistering the
++		 * default zone thus makes the last registered one the default.
++		 * On OSX < 10.6, unregistering shifts all registered zones.
++		 * The first registered zone then becomes the default.
++		 */
+ 		malloc_zone_unregister(default_zone);
+ 		malloc_zone_register(default_zone);
++		/*
++		 * On OSX 10.6, having the default purgeable zone appear before
++		 * the default zone makes some things crash because it thinks it
++		 * owns the default zone allocated pointers. We thus unregister/
++		 * re-register it in order to ensure it's always after the
++		 * default zone. On OSX < 10.6, there is no purgeable zone, so
++		 * this does nothing. On OSX >= 10.6, unregistering replaces the
++		 * purgeable zone with the last registered zone above, i.e the
++		 * default zone. Registering it again then puts it at the end,
++		 * obviously after the default zone.
++		 */
++		if (purgeable_zone) {
++			malloc_zone_unregister(purgeable_zone);
++			malloc_zone_register(purgeable_zone);
++		}
+ 	} while (malloc_default_zone() != &zone);
+ }
--- a/memory/jemalloc/src/src/zone.c
+++ b/memory/jemalloc/src/src/zone.c
@@ -171,16 +171,17 @@ void
 register_zone(void)
 {
 
 	/*
 	 * If something else replaced the system default zone allocator, don't
 	 * register jemalloc's.
 	 */
 	malloc_zone_t *default_zone = malloc_default_zone();
+	malloc_zone_t *purgeable_zone = NULL;
 	if (!default_zone->zone_name ||
 	    strcmp(default_zone->zone_name, "DefaultMallocZone") != 0) {
 		return;
 	}
 
 	zone.size = (void *)zone_size;
 	zone.malloc = (void *)zone_malloc;
 	zone.calloc = (void *)zone_calloc;
@@ -232,27 +233,42 @@ register_zone(void)
 	 * 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
 	 * a scalable_zone.  As purgeable zones only exist on >= 10.6, we need
 	 * to check for the existence of malloc_default_purgeable_zone() at
 	 * run time.
 	 */
 	if (malloc_default_purgeable_zone != NULL)
-		malloc_default_purgeable_zone();
+		purgeable_zone = malloc_default_purgeable_zone();
 
 	/* Register the custom zone.  At this point it won't be the default. */
 	malloc_zone_register(&zone);
 
-	/*
-	 * Unregister and reregister the default zone.  On OSX >= 10.6,
-	 * unregistering takes the last registered zone and places it at the
-	 * location of the specified zone.  Unregistering the default zone thus
-	 * makes the last registered one the default.  On OSX < 10.6,
-	 * unregistering shifts all registered zones.  The first registered zone
-	 * then becomes the default.
-	 */
 	do {
 		default_zone = malloc_default_zone();
+		/*
+		 * Unregister and reregister the default zone.  On OSX >= 10.6,
+		 * unregistering takes the last registered zone and places it
+		 * at the location of the specified zone.  Unregistering the
+		 * default zone thus makes the last registered one the default.
+		 * On OSX < 10.6, unregistering shifts all registered zones.
+		 * The first registered zone then becomes the default.
+		 */
 		malloc_zone_unregister(default_zone);
 		malloc_zone_register(default_zone);
+		/*
+		 * On OSX 10.6, having the default purgeable zone appear before
+		 * the default zone makes some things crash because it thinks it
+		 * owns the default zone allocated pointers. We thus unregister/
+		 * re-register it in order to ensure it's always after the
+		 * default zone. On OSX < 10.6, there is no purgeable zone, so
+		 * this does nothing. On OSX >= 10.6, unregistering replaces the
+		 * purgeable zone with the last registered zone above, i.e the
+		 * default zone. Registering it again then puts it at the end,
+		 * obviously after the default zone.
+		 */
+		if (purgeable_zone) {
+			malloc_zone_unregister(purgeable_zone);
+			malloc_zone_register(purgeable_zone);
+		}
 	} while (malloc_default_zone() != &zone);
 }
--- a/memory/jemalloc/update.sh
+++ b/memory/jemalloc/update.sh
@@ -15,13 +15,14 @@ git describe --long --abbrev=40 > VERSIO
 rm -rf .git .gitignore autom4te.cache
 
 patch -p1 < ../0001-Use-a-configure-test-to-detect-whether-to-use-a-cons.patch
 patch -p1 < ../0002-Use-ULL-prefix-instead-of-LLU-for-unsigned-long-long.patch
 patch -p1 < ../0003-Don-t-use-msvc_compat-s-C99-headers-with-MSVC-versio.patch
 patch -p1 < ../0004-Try-to-use-__builtin_ffsl-if-ffsl-is-unavailable.patch
 patch -p1 < ../0005-Check-for-__builtin_ffsl-before-ffsl.patch
 patch -p1 < ../0006-Fix-clang-warnings.patch
+patch -p1 < ../0007-Ensure-the-default-purgeable-zone-is-after-the-defau.patch
 
 cd ..
 hg addremove -q src
 
 echo "jemalloc has now been updated.  Don't forget to run hg commit!"