@@ -214,7 +214,20 @@ use oxc_data_structures::assert_unchecked;
214214/// [`HashMap::new_in`]: crate::HashMap::new_in
215215#[ derive( Default ) ]
216216pub struct Allocator {
217+ #[ cfg( not( all( feature = "track_allocations" , not( feature = "disable_track_allocations" ) ) ) ) ]
217218 bump : Bump ,
219+ // NOTE: We need to expose `bump` publicly here for calculating its field offset in memory.
220+ #[ cfg( all( feature = "track_allocations" , not( feature = "disable_track_allocations" ) ) ) ]
221+ #[ doc( hidden) ]
222+ pub bump : Bump ,
223+ /// Used to track the total number of allocations made in this allocator when the `track_allocations` feature is enabled.
224+ #[ cfg( all( feature = "track_allocations" , not( feature = "disable_track_allocations" ) ) ) ]
225+ #[ doc( hidden) ]
226+ pub num_alloc : std:: sync:: atomic:: AtomicUsize ,
227+ /// Used to track the total number of re-allocations made in this allocator when the `track_allocations` feature is enabled.
228+ #[ cfg( all( feature = "track_allocations" , not( feature = "disable_track_allocations" ) ) ) ]
229+ #[ doc( hidden) ]
230+ pub num_realloc : std:: sync:: atomic:: AtomicUsize ,
218231}
219232
220233impl Allocator {
@@ -241,7 +254,13 @@ impl Allocator {
241254 #[ expect( clippy:: inline_always) ]
242255 #[ inline( always) ]
243256 pub fn new ( ) -> Self {
244- Self { bump : Bump :: new ( ) }
257+ Self {
258+ bump : Bump :: new ( ) ,
259+ #[ cfg( all( feature = "track_allocations" , not( feature = "disable_track_allocations" ) ) ) ]
260+ num_alloc : std:: sync:: atomic:: AtomicUsize :: new ( 0 ) ,
261+ #[ cfg( all( feature = "track_allocations" , not( feature = "disable_track_allocations" ) ) ) ]
262+ num_realloc : std:: sync:: atomic:: AtomicUsize :: new ( 0 ) ,
263+ }
245264 }
246265
247266 /// Create a new [`Allocator`] with specified capacity.
@@ -252,7 +271,13 @@ impl Allocator {
252271 #[ expect( clippy:: inline_always) ]
253272 #[ inline( always) ]
254273 pub fn with_capacity ( capacity : usize ) -> Self {
255- Self { bump : Bump :: with_capacity ( capacity) }
274+ Self {
275+ bump : Bump :: with_capacity ( capacity) ,
276+ #[ cfg( all( feature = "track_allocations" , not( feature = "disable_track_allocations" ) ) ) ]
277+ num_alloc : std:: sync:: atomic:: AtomicUsize :: new ( 0 ) ,
278+ #[ cfg( all( feature = "track_allocations" , not( feature = "disable_track_allocations" ) ) ) ]
279+ num_realloc : std:: sync:: atomic:: AtomicUsize :: new ( 0 ) ,
280+ }
256281 }
257282
258283 /// Allocate an object in this [`Allocator`] and return an exclusive reference to it.
@@ -276,6 +301,9 @@ impl Allocator {
276301 pub fn alloc < T > ( & self , val : T ) -> & mut T {
277302 const { assert ! ( !std:: mem:: needs_drop:: <T >( ) , "Cannot allocate Drop type in arena" ) } ;
278303
304+ #[ cfg( all( feature = "track_allocations" , not( feature = "disable_track_allocations" ) ) ) ]
305+ self . num_alloc . fetch_add ( 1 , std:: sync:: atomic:: Ordering :: SeqCst ) ;
306+
279307 self . bump . alloc ( val)
280308 }
281309
@@ -297,6 +325,9 @@ impl Allocator {
297325 #[ expect( clippy:: inline_always) ]
298326 #[ inline( always) ]
299327 pub fn alloc_str < ' alloc > ( & ' alloc self , src : & str ) -> & ' alloc str {
328+ #[ cfg( all( feature = "track_allocations" , not( feature = "disable_track_allocations" ) ) ) ]
329+ self . num_alloc . fetch_add ( 1 , std:: sync:: atomic:: Ordering :: SeqCst ) ;
330+
300331 self . bump . alloc_str ( src)
301332 }
302333
@@ -317,6 +348,9 @@ impl Allocator {
317348 #[ expect( clippy:: inline_always) ]
318349 #[ inline( always) ]
319350 pub fn alloc_slice_copy < T : Copy > ( & self , src : & [ T ] ) -> & mut [ T ] {
351+ #[ cfg( all( feature = "track_allocations" , not( feature = "disable_track_allocations" ) ) ) ]
352+ self . num_alloc . fetch_add ( 1 , std:: sync:: atomic:: Ordering :: SeqCst ) ;
353+
320354 self . bump . alloc_slice_copy ( src)
321355 }
322356
@@ -329,6 +363,9 @@ impl Allocator {
329363 ///
330364 /// Panics if reserving space matching `layout` fails.
331365 pub fn alloc_layout ( & self , layout : Layout ) -> NonNull < u8 > {
366+ #[ cfg( all( feature = "track_allocations" , not( feature = "disable_track_allocations" ) ) ) ]
367+ self . num_alloc . fetch_add ( 1 , std:: sync:: atomic:: Ordering :: SeqCst ) ;
368+
332369 self . bump . alloc_layout ( layout)
333370 }
334371
@@ -379,6 +416,9 @@ impl Allocator {
379416 "attempted to create a string longer than `isize::MAX` bytes"
380417 ) ;
381418
419+ #[ cfg( all( feature = "track_allocations" , not( feature = "disable_track_allocations" ) ) ) ]
420+ self . num_alloc . fetch_add ( 1 , std:: sync:: atomic:: Ordering :: SeqCst ) ;
421+
382422 // Create actual `&str` in a separate function, to ensure that `alloc_concat_strs_array`
383423 // is inlined, so that compiler has knowledge to remove the overflow checks above.
384424 // When some of `strings` are static, this function is usually only a few instructions.
@@ -471,6 +511,12 @@ impl Allocator {
471511 #[ expect( clippy:: inline_always) ]
472512 #[ inline( always) ]
473513 pub fn reset ( & mut self ) {
514+ #[ cfg( all( feature = "track_allocations" , not( feature = "disable_track_allocations" ) ) ) ]
515+ {
516+ self . num_alloc . store ( 0 , std:: sync:: atomic:: Ordering :: SeqCst ) ;
517+ self . num_realloc . store ( 0 , std:: sync:: atomic:: Ordering :: SeqCst ) ;
518+ }
519+
474520 self . bump . reset ( ) ;
475521 }
476522
@@ -592,7 +638,13 @@ impl Allocator {
592638 #[ expect( clippy:: inline_always) ]
593639 #[ inline( always) ]
594640 pub ( crate ) fn from_bump ( bump : Bump ) -> Self {
595- Self { bump }
641+ Self {
642+ bump,
643+ #[ cfg( all( feature = "track_allocations" , not( feature = "disable_track_allocations" ) ) ) ]
644+ num_alloc : std:: sync:: atomic:: AtomicUsize :: new ( 0 ) ,
645+ #[ cfg( all( feature = "track_allocations" , not( feature = "disable_track_allocations" ) ) ) ]
646+ num_realloc : std:: sync:: atomic:: AtomicUsize :: new ( 0 ) ,
647+ }
596648 }
597649}
598650
0 commit comments