@@ -125,41 +125,50 @@ INTERNAL_HIDDEN uint64_t _iso_alloc_zone_leak_detector(iso_alloc_zone_t *zone, b
125125 uint32_t was_used = 0 ;
126126 int64_t bms = zone -> bitmap_size / sizeof (bitmap_index_t );
127127
128- for (bitmap_index_t i = 0 ; i < bms ; i ++ ) {
129- for (int j = 0 ; j < BITS_PER_QWORD ; j += BITS_PER_CHUNK ) {
130-
131- if (bm [i ] == 0 ) {
128+ for (int64_t i = 0 ; i < bms ;) {
129+ #if USE_NEON
130+ /* Two-qword quick-reject: load 16 bytes of bitmap and skip both
131+ * qwords when every chunk in those 64 slots is free and never used. */
132+ if (i + 1 < bms ) {
133+ int64x2_t v = vld1q_s64 ((const int64_t * ) & bm [i ]);
134+ if ((vgetq_lane_s64 (v , 0 ) | vgetq_lane_s64 (v , 1 )) == 0 ) {
135+ i += 2 ;
132136 continue ;
133137 }
138+ }
139+ #endif
140+ uint64_t bts = (uint64_t ) bm [i ];
141+ if (bts == 0 ) {
142+ i ++ ;
143+ continue ;
144+ }
134145
135- int64_t bit = GET_BIT (bm [i ], j );
136- int64_t bit_two = GET_BIT (bm [i ], (j + 1 ));
146+ /* was_used (encoding 01: low=0, high=1) — popcount the odd-bit
147+ * positions whose paired even bit is clear. */
148+ was_used += __builtin_popcountll ((~bts ) & (bts >> 1 ) & USED_BIT_VECTOR );
137149
138- /* Chunk was used but is now free */
139- if (bit == 0 && bit_two == 1 ) {
140- was_used ++ ;
141- }
150+ /* Chunks with low bit set are either in-use (10) or canary (11).
151+ * Walk just those positions with ctz instead of testing all 32. */
152+ uint64_t in_use_low = bts & USED_BIT_VECTOR ;
153+ while (in_use_low ) {
154+ int j = __builtin_ctzll (in_use_low );
155+ in_use_low &= in_use_low - 1 ;
156+
157+ int64_t bit_two = GET_BIT (bts , (j + 1 ));
158+ bit_slot_t bit_slot = ((bitmap_index_t ) i * BITS_PER_QWORD ) + j ;
159+ const void * leak = (zone -> user_pages_start + ((bit_slot >> 1 ) * zone -> chunk_size ));
160+
161+ if (bit_two == 1 && (check_canary_no_abort (zone , leak ) != ERR )) {
162+ continue ;
163+ } else {
164+ in_use ++ ;
142165
143- if (bit == 1 ) {
144- /* Theres no difference between a leaked and previously
145- * used chunk (11) and a canary chunk (11). So in order
146- * to accurately report on leaks we need to verify the
147- * canary value. If it doesn't validate then we assume
148- * its a true leak and increment the in_use counter */
149- bit_slot_t bit_slot = (i * BITS_PER_QWORD ) + j ;
150- const void * leak = (zone -> user_pages_start + ((bit_slot >> 1 ) * zone -> chunk_size ));
151-
152- if (bit_two == 1 && (check_canary_no_abort (zone , leak ) != ERR )) {
153- continue ;
154- } else {
155- in_use ++ ;
156-
157- if (profile == false) {
158- LOG ("Leaked chunk (%d) in zone[%d] of %d bytes detected at 0x%p (bit position = %d)" , in_use , zone -> index , zone -> chunk_size , leak , bit_slot );
159- }
166+ if (profile == false) {
167+ LOG ("Leaked chunk (%d) in zone[%d] of %d bytes detected at 0x%p (bit position = %d)" , in_use , zone -> index , zone -> chunk_size , leak , bit_slot );
160168 }
161169 }
162170 }
171+ i ++ ;
163172 }
164173
165174 if (profile == false) {
0 commit comments