diff --git a/crates/oxc_allocator/src/address.rs b/crates/oxc_allocator/src/address.rs index 290b04d8ddec1..19a6eb6b079ba 100644 --- a/crates/oxc_allocator/src/address.rs +++ b/crates/oxc_allocator/src/address.rs @@ -14,13 +14,59 @@ impl Address { /// Get the memory address of a pointer to an AST node in arena. /// - /// The pointer must point to an AST node in the arena (not on the stack), - /// or the returned `Address` will be meaningless. + /// **This method is an escape hatch only.** + /// Prefer using `GetAddress::address` instead, because it is more likely to produce a stable `Address`. /// /// If the AST node is in a `Box`, the address is guaranteed to be a unique identifier /// for the duration of the arena's existence. - /// If the node is in a `Vec`, then the `Address` may not remain accurate if the `Vec` + /// + /// But if the node is in a `Vec`, then the `Address` may not remain accurate if the `Vec` /// is resized or has elements added or removed before this node. + /// + /// The pointer must point to an AST node in the arena (not on the stack), + /// or the returned `Address` will be meaningless. + /// + /// # Example + /// + /// Demonstration of the difference between `Address::from_ptr` and `GetAddress::address`: + /// + /// ```ignore + /// use oxc_allocator::{Address, GetAddress, Vec}; + /// use oxc_span::SPAN; + /// + /// // Create a `Vec` containing a single `BlockStatement` + /// let mut stmts = Vec::with_capacity_in(1, &allocator); + /// stmts.push(ast_builder.statement_block(SPAN, Vec::new_in(&allocator))); + /// + /// let block_address = stmts[0].address(); + /// let stmt_address = Address::from_ptr(&stmts[0]); + /// + /// // Add another `Statement` to the `Vec`. + /// // This causes the `Vec` to grow and reallocate. + /// stmts.push(ast_builder.statement_empty(SPAN)); + /// + /// let block_address_after_push = stmts[0].address(); + /// let stmt_address_after_push = Address::from_ptr(&stmts[0]); + /// + /// // Address of the `BlockStatement` is unchanged + /// // (because the `Box`'s pointer still points to same memory location) + /// assert!(block_address_after_push == block_address); + /// // Address of the `Statement` has changed + /// // (because the `Vec` reallocated, so its contents have moved in memory) + /// assert!(stmt_address_after_push != stmt_address); + /// + /// // Insert a new `Statement` at start of the `Vec`. + /// // The `BlockStatement` is now at index 1. + /// stmts.insert(0, ast_builder.statement_empty(SPAN)); + /// + /// let block_address_after_insert = stmts[1].address(); + /// let stmt_address_after_insert = Address::from_ptr(&stmts[1]); + /// + /// // Address of the `BlockStatement` is still unchanged + /// assert!(block_address_after_insert == block_address_after_push); + /// // Address of the `Statement` has changed again + /// assert!(stmt_address_after_insert != stmt_address_after_push); + /// ``` #[inline] pub fn from_ptr(p: *const T) -> Self { Self(p as usize)