Loading...
--- libmalloc/libmalloc-409.40.6/src/magazine_large.c
+++ libmalloc/libmalloc-409.81.2/src/magazine_large.c
@@ -449,6 +449,7 @@
 #if CONFIG_LARGE_CACHE
 /*
  * Remove the entry at idx from the death row cache.
+ * If supplied, adjusts best to account for compaction.
  * Does not operate on the entry itself.
  * Caller must hold the szone lock.
  *
@@ -456,7 +457,7 @@
  * so that the caller can iterate through the buffer while removing entries.
  */
 static int
-remove_from_death_row_no_lock(szone_t *szone, int idx)
+remove_from_death_row_no_lock(szone_t *szone, int idx, int *best)
 {
 	int i, next_idx = -1;
 	// Compact live ring to fill entry now vacated at large_entry_cache[best]
@@ -467,6 +468,10 @@
 			szone->large_entry_cache[i] = szone->large_entry_cache[i + 1];
 		}
 
+		if (best && *best != -1) {
+			(*best)--;
+		}
+
 		if (idx == szone->large_entry_cache_oldest) {
 			next_idx = -1;
 		} else {
@@ -481,6 +486,10 @@
 				szone->large_entry_cache[i] = szone->large_entry_cache[i + 1];
 			}
 
+			if (best && *best != -1) {
+				(*best)--;
+			}
+
 			if (0 < szone->large_entry_cache_newest) {
 				szone->large_entry_cache_newest--;
 			} else {
@@ -497,6 +506,8 @@
 				szone->large_entry_cache[i] = szone->large_entry_cache[i - 1];
 			}
 
+			// best does not need adjustment
+
 			if (idx == szone->large_entry_cache_oldest) {
 				next_idx = -1;
 			} else {
@@ -513,6 +524,12 @@
 		// By trichotomy, large_entry_cache_newest == large_entry_cache_oldest.
 		// That implies best == large_entry_cache_newest == large_entry_cache_oldest
 		// and the ring is now empty.
+
+		// If we are removing the only entry, there must be no current best.
+		if (best && *best != -1) {
+			malloc_zone_error(szone->debug_flags, true, "Invalid best: %d\n", *best);
+		}
+
 		szone->large_entry_cache[idx].address = 0;
 		szone->large_entry_cache[idx].size = 0;
 #if CONFIG_DEFERRED_RECLAIM
@@ -552,7 +569,7 @@
 					// Kernel has already reclaimed this entry or
 					// is in the process of trying to reclaim it.
 					// Remove it from death row & keep looking
-					idx = remove_from_death_row_no_lock(szone, idx);
+					idx = remove_from_death_row_no_lock(szone, idx, &best);
 					stop_idx = szone->large_entry_cache_oldest;
 					if (idx == -1) {
 						// We've looked at all entries in the cache
@@ -588,7 +605,7 @@
 
 	entry = szone->large_entry_cache[best];
 
-	remove_from_death_row_no_lock(szone, best);
+	remove_from_death_row_no_lock(szone, best, NULL);
 
 	return entry;
 }
@@ -760,14 +777,13 @@
 					uint64_t reclaim_index = szone->large_entry_cache[idx].reclaim_index;
 					if (curr_size + 2 * large_vm_page_quanta_size <= UINT32_MAX &&
 							!mvm_reclaim_is_available(reclaim_index)) {
-						int next_idx = idx;
-
 						// Entry has been reclaimed
 						// Remove it from the cache
 
-						next_idx = remove_from_death_row_no_lock(szone, idx);
+						idx = remove_from_death_row_no_lock(szone, idx, NULL);
 						stop_idx = szone->large_entry_cache_oldest;
-						if (next_idx == -1) {
+
+						if (idx == -1) {
 							// Ring buffer is now empty
 							break;
 						}