+#if SIZEOF_VOID_P != 8
+ {
+ int i, num_empty_blocks_orig, num_blocks, arr_length;
+ void *block;
+ void **empty_block_arr;
+ void **rebuild_next;
+
+#ifdef TARGET_WIN32
+ /*
+ * sgen_free_os_memory () asserts in mono_vfree () because windows doesn't like freeing the middle of
+ * a VirtualAlloc ()-ed block.
+ */
+ return;
+#endif
+
+ if (num_empty_blocks <= section_reserve)
+ return;
+ SGEN_ASSERT (0, num_empty_blocks > 0, "section reserve can't be negative");
+
+ num_empty_blocks_orig = num_empty_blocks;
+ empty_block_arr = (void**)sgen_alloc_internal_dynamic (sizeof (void*) * num_empty_blocks_orig,
+ INTERNAL_MEM_MS_BLOCK_INFO_SORT, FALSE);
+ if (!empty_block_arr)
+ goto fallback;
+
+ i = 0;
+ for (block = empty_blocks; block; block = *(void**)block)
+ empty_block_arr [i++] = block;
+ SGEN_ASSERT (0, i == num_empty_blocks, "empty block count wrong");
+
+ sgen_qsort (empty_block_arr, num_empty_blocks, sizeof (void*), compare_pointers);
+
+ /*
+ * We iterate over the free blocks, trying to find MS_BLOCK_ALLOC_NUM
+ * contiguous ones. If we do, we free them. If that's not enough to get to
+ * section_reserve, we halve the number of contiguous blocks we're looking
+ * for and have another go, until we're done with looking for pairs of
+ * blocks, at which point we give up and go to the fallback.
+ */
+ arr_length = num_empty_blocks_orig;
+ num_blocks = MS_BLOCK_ALLOC_NUM;
+ while (num_empty_blocks > section_reserve && num_blocks > 1) {
+ int first = -1;
+ int dest = 0;
+
+ dest = 0;
+ for (i = 0; i < arr_length; ++i) {
+ int d = dest;
+ void *block = empty_block_arr [i];
+ SGEN_ASSERT (0, block, "we're not shifting correctly");
+ if (i != dest) {
+ empty_block_arr [dest] = block;
+ /*
+ * This is not strictly necessary, but we're
+ * cautious.
+ */
+ empty_block_arr [i] = NULL;
+ }
+ ++dest;
+
+ if (first < 0) {
+ first = d;
+ continue;
+ }
+
+ SGEN_ASSERT (0, first >= 0 && d > first, "algorithm is wrong");
+
+ if ((char*)block != ((char*)empty_block_arr [d-1]) + MS_BLOCK_SIZE) {
+ first = d;
+ continue;
+ }
+
+ if (d + 1 - first == num_blocks) {
+ /*
+ * We found num_blocks contiguous blocks. Free them
+ * and null their array entries. As an optimization
+ * we could, instead of nulling the entries, shift
+ * the following entries over to the left, while
+ * we're iterating.
+ */
+ int j;
+ sgen_free_os_memory (empty_block_arr [first], MS_BLOCK_SIZE * num_blocks, SGEN_ALLOC_HEAP);
+ for (j = first; j <= d; ++j)
+ empty_block_arr [j] = NULL;
+ dest = first;
+ first = -1;
+
+ num_empty_blocks -= num_blocks;
+
+ stat_major_blocks_freed += num_blocks;
+ if (num_blocks == MS_BLOCK_ALLOC_NUM)
+ stat_major_blocks_freed_ideal += num_blocks;
+ else
+ stat_major_blocks_freed_less_ideal += num_blocks;
+
+ }
+ }
+
+ SGEN_ASSERT (0, dest <= i && dest <= arr_length, "array length is off");
+ arr_length = dest;
+ SGEN_ASSERT (0, arr_length == num_empty_blocks, "array length is off");
+
+ num_blocks >>= 1;
+ }
+
+ /* rebuild empty_blocks free list */
+ rebuild_next = (void**)&empty_blocks;
+ for (i = 0; i < arr_length; ++i) {
+ void *block = empty_block_arr [i];
+ SGEN_ASSERT (0, block, "we're missing blocks");
+ *rebuild_next = block;
+ rebuild_next = (void**)block;
+ }
+ *rebuild_next = NULL;
+
+ /* free array */
+ sgen_free_internal_dynamic (empty_block_arr, sizeof (void*) * num_empty_blocks_orig, INTERNAL_MEM_MS_BLOCK_INFO_SORT);
+ }
+
+ SGEN_ASSERT (0, num_empty_blocks >= 0, "we freed more blocks than we had in the first place?");
+
+ fallback: