Ruby 4.1.0dev (2026-03-07 revision 66e61d0cffca501f335175c6ca4948d535a0e86d)
pm_arena.c
2
7#define PM_ARENA_BLOCK_SIZE(data_size) (offsetof(pm_arena_block_t, data) + (data_size))
8
10#define PM_ARENA_INITIAL_SIZE 8192
11
13#define PM_ARENA_GROWTH_INTERVAL 8
14
16#define PM_ARENA_MAX_SIZE (1024 * 1024)
17
21static size_t
22pm_arena_next_block_size(const pm_arena_t *arena, size_t min_size) {
23 size_t size = PM_ARENA_INITIAL_SIZE;
24
25 for (size_t i = PM_ARENA_GROWTH_INTERVAL; i <= arena->block_count; i += PM_ARENA_GROWTH_INTERVAL) {
26 if (size < PM_ARENA_MAX_SIZE) size *= 2;
27 }
28
29 return size > min_size ? size : min_size;
30}
31
36void *
37pm_arena_alloc(pm_arena_t *arena, size_t size, size_t alignment) {
38 // Try current block.
39 if (arena->current != NULL) {
40 size_t used_aligned = (arena->current->used + alignment - 1) & ~(alignment - 1);
41 size_t needed = used_aligned + size;
42
43 // Guard against overflow in the alignment or size arithmetic.
44 if (used_aligned >= arena->current->used && needed >= used_aligned && needed <= arena->current->capacity) {
45 arena->current->used = needed;
46 return arena->current->data + used_aligned;
47 }
48 }
49
50 // Allocate new block via xmalloc — memory is NOT zeroed.
51 // New blocks from xmalloc are max-aligned, so data[] starts aligned for
52 // any C type. No padding needed at the start.
53 size_t block_data_size = pm_arena_next_block_size(arena, size);
54 pm_arena_block_t *block = (pm_arena_block_t *) xmalloc(PM_ARENA_BLOCK_SIZE(block_data_size));
55
56 if (block == NULL) {
57 fprintf(stderr, "prism: out of memory; aborting\n");
58 abort();
59 }
60
61 block->capacity = block_data_size;
62 block->used = size;
63 block->prev = arena->current;
64 arena->current = block;
65 arena->block_count++;
66
67 return block->data;
68}
69
74void *
75pm_arena_zalloc(pm_arena_t *arena, size_t size, size_t alignment) {
76 void *ptr = pm_arena_alloc(arena, size, alignment);
77 memset(ptr, 0, size);
78 return ptr;
79}
80
84void *
85pm_arena_memdup(pm_arena_t *arena, const void *src, size_t size, size_t alignment) {
86 void *dst = pm_arena_alloc(arena, size, alignment);
87 memcpy(dst, src, size);
88 return dst;
89}
90
94void
95pm_arena_free(pm_arena_t *arena) {
96 pm_arena_block_t *block = arena->current;
97
98 while (block != NULL) {
99 pm_arena_block_t *prev = block->prev;
100 xfree_sized(block, PM_ARENA_BLOCK_SIZE(block->capacity));
101 block = prev;
102 }
103
104 *arena = (pm_arena_t) { 0 };
105}
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
A bump allocator for the prism parser.
A single block of memory in the arena.
Definition pm_arena.h:20
struct pm_arena_block * prev
The previous block in the chain (for freeing).
Definition pm_arena.h:22
char data[PM_FLEX_ARY_LEN]
The block's data.
Definition pm_arena.h:31
size_t used
The number of bytes consumed so far.
Definition pm_arena.h:28
size_t capacity
The total usable bytes in data[].
Definition pm_arena.h:25
A bump allocator.
Definition pm_arena.h:39
size_t block_count
The number of blocks allocated.
Definition pm_arena.h:44
pm_arena_block_t * current
The active block (allocate from here).
Definition pm_arena.h:41