Arena Allocation — Asignador por Bloques

Archivo: src/arena.rs (291 líneas)

¿Por qué existe?

Reemplaza los miles de Box::new(), Vec::push() y String::clone() individuales del compilador por un asignador que reserva memoria en chunks grandes y la libera toda de golpe al final. El impacto se siente principalmente en la velocidad de compilación (lexer, parser, optimizer), no en el runtime del código generado.

Arquitectura

La arena mantiene un vector de Chunks de memoria cruda. Cada chunk tiene un bump offset (Cell<usize>) que avanza por alineación con cada asignación. Al asignar, se busca el primer chunk con espacio (has_space) y, si ninguno lo tiene, se crea uno nuevo de tamaño default_chunk_size.max(size + align).

ComponenteDescripción
ChunkBloque de memoria cruda con bump allocation: ptr, size, offset; libera en Drop
ArenaAllocator principal: alloc_raw, alloc, alloc_slice, reset y métricas (bytes_allocated, chunk_count, memory_reserved)
ScopedArenaArena con push_scope/pop_scope que permite liberar memoria por nivel

API Pública

FunciónDescripción
new() / with_chunk_size(n)Crea la arena con chunk por defecto de 64 KB o con tamaño personalizado
alloc<T>(value) -> &mut TAsigna un valor y retorna referencia mutable (patrón secuencial de compiladores)
alloc_raw<T>(value) -> *mut TAsigna y retorna raw pointer; el caller debe garantizar que la arena viva más que el puntero
alloc_slice<T: Clone>(&[T]) -> &[T]Asigna un slice clonando cada elemento en la arena
reset()Libera toda la memoria: resetea los offsets de todos los chunks (se reutilizan) y pone total_allocated en 0

Cómo se integra

Se usa en las fases de compilación que producen muchas estructuras temporales de vida acotada (AST, símbolos, IR intermedio). Al final de cada pasada, reset() recupera toda la memoria de una sola vez sin costo de free individual. ScopedArena permite, además, marcar niveles: push_scope guarda el total_allocated actual y pop_scope rebobina los chunks a ese punto.

⚠️ alloc<T> solo funciona correctamente cuando no se mantienen referencias previas al hacer nuevas asignaciones (los chunks pueden reubicarse o crearse nuevos). Usá alloc_raw si necesitás punteros estables.
💡 pop_scope invalida todas las referencias asignadas desde el push_scope correspondiente: es el mecanismo de "liberar por nivel" que evita leaks en pasadas anidadas del compilador.