@@ -125,71 +125,30 @@ 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 (int64_t i = 0 ; i < bms ;) {
128129#if USE_NEON
129- /* Process the bitmap two qwords at a time. The common case is that a
130- * qword is entirely zero (every chunk in those 32 slots is free and
131- * never used) — vectorising the zero-check lets us skip both qwords at
132- * once. For each non-zero qword we popcount the was_used pattern in
133- * O(1) and walk only the chunks whose low bit is set with ctz, instead
134- * of scanning all 32 pairs. */
135- int64_t i = 0 ;
136- const int64_t bms_pair = bms & ~(int64_t ) 1 ;
137-
138- for (; i < bms_pair ; i += 2 ) {
139- int64x2_t v = vld1q_s64 ((const int64_t * ) & bm [i ]);
140- const uint64_t lane0 = (uint64_t ) vgetq_lane_s64 (v , 0 );
141- const uint64_t lane1 = (uint64_t ) vgetq_lane_s64 (v , 1 );
142-
143- if ((lane0 | lane1 ) == 0 ) {
144- continue ;
145- }
146-
147- const uint64_t lanes [2 ] = {lane0 , lane1 };
148- for (int k = 0 ; k < 2 ; k ++ ) {
149- uint64_t bts = lanes [k ];
150- if (bts == 0 ) {
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 ;
151136 continue ;
152137 }
153-
154- /* was_used: chunks encoded 01 (low=0, high=1). The mask of
155- * odd-bit positions whose paired even bit is clear is
156- * (~bts) & (bts >> 1) & USED_BIT_VECTOR. */
157- uint64_t was_used_mask = (~bts ) & (bts >> 1 ) & USED_BIT_VECTOR ;
158- was_used += __builtin_popcountll (was_used_mask );
159-
160- /* Chunks with low bit set are either in-use (10) or canary
161- * (11). Walk just those positions to verify canaries. */
162- uint64_t in_use_low = bts & USED_BIT_VECTOR ;
163- while (in_use_low ) {
164- int j = __builtin_ctzll (in_use_low );
165- in_use_low &= in_use_low - 1 ;
166-
167- int64_t bit_two = GET_BIT (bts , (j + 1 ));
168- bit_slot_t bit_slot = (((bitmap_index_t ) (i + k )) * BITS_PER_QWORD ) + j ;
169- const void * leak = (zone -> user_pages_start + ((bit_slot >> 1 ) * zone -> chunk_size ));
170-
171- if (bit_two == 1 && (check_canary_no_abort (zone , leak ) != ERR )) {
172- continue ;
173- } else {
174- in_use ++ ;
175-
176- if (profile == false) {
177- 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 );
178- }
179- }
180- }
181138 }
182- }
183-
184- for (; i < bms ; i ++ ) {
139+ #endif
185140 uint64_t bts = (uint64_t ) bm [i ];
186141 if (bts == 0 ) {
142+ i ++ ;
187143 continue ;
188144 }
189145
190- uint64_t was_used_mask = (~bts ) & (bts >> 1 ) & USED_BIT_VECTOR ;
191- was_used += __builtin_popcountll (was_used_mask );
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 );
192149
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. */
193152 uint64_t in_use_low = bts & USED_BIT_VECTOR ;
194153 while (in_use_low ) {
195154 int j = __builtin_ctzll (in_use_low );
@@ -209,45 +168,8 @@ INTERNAL_HIDDEN uint64_t _iso_alloc_zone_leak_detector(iso_alloc_zone_t *zone, b
209168 }
210169 }
211170 }
171+ i ++ ;
212172 }
213- #else
214- for (bitmap_index_t i = 0 ; i < bms ; i ++ ) {
215- for (int j = 0 ; j < BITS_PER_QWORD ; j += BITS_PER_CHUNK ) {
216-
217- if (bm [i ] == 0 ) {
218- continue ;
219- }
220-
221- int64_t bit = GET_BIT (bm [i ], j );
222- int64_t bit_two = GET_BIT (bm [i ], (j + 1 ));
223-
224- /* Chunk was used but is now free */
225- if (bit == 0 && bit_two == 1 ) {
226- was_used ++ ;
227- }
228-
229- if (bit == 1 ) {
230- /* Theres no difference between a leaked and previously
231- * used chunk (11) and a canary chunk (11). So in order
232- * to accurately report on leaks we need to verify the
233- * canary value. If it doesn't validate then we assume
234- * its a true leak and increment the in_use counter */
235- bit_slot_t bit_slot = (i * BITS_PER_QWORD ) + j ;
236- const void * leak = (zone -> user_pages_start + ((bit_slot >> 1 ) * zone -> chunk_size ));
237-
238- if (bit_two == 1 && (check_canary_no_abort (zone , leak ) != ERR )) {
239- continue ;
240- } else {
241- in_use ++ ;
242-
243- if (profile == false) {
244- 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 );
245- }
246- }
247- }
248- }
249- }
250- #endif
251173
252174 if (profile == false) {
253175 LOG ("Zone[%d] Total number of %d byte chunks(%d) used and free'd (%d) (%d percent), in use = %d" , zone -> index , zone -> chunk_size , zone -> chunk_count ,
0 commit comments