Ruby 4.1.0dev (2026-10-28 revision b62abdae8b2606aaf4a38fa193f2d04ba1749fdc)
arena.c
1#include "prism/internal/arena.h"
2
3#include "prism/internal/allocator.h"
4#include "prism/internal/oom.h"
5
6#include <assert.h>
7#include <stdlib.h>
8
13#define PM_ARENA_BLOCK_SIZE(data_size) (offsetof(pm_arena_block_t, data) + (data_size))
14
19#ifndef PM_ARENA_INITIAL_SIZE
20#define PM_ARENA_INITIAL_SIZE 8192
21#endif
22
24#define PM_ARENA_GROWTH_INTERVAL 8
25
27#define PM_ARENA_MAX_SIZE (1024 * 1024)
28
32static size_t
33pm_arena_next_block_size(const pm_arena_t *arena, size_t min_size) {
34 size_t size = PM_ARENA_INITIAL_SIZE;
35
36 for (size_t exp = PM_ARENA_GROWTH_INTERVAL; exp <= arena->block_count; exp += PM_ARENA_GROWTH_INTERVAL) {
37 if (size < PM_ARENA_MAX_SIZE) size *= 2;
38 }
39
40 return size > min_size ? size : min_size;
41}
42
47static pm_arena_block_t *
48pm_arena_block_new(pm_arena_t *arena, size_t data_size, size_t initial_used) {
49 assert(initial_used <= data_size);
50 pm_arena_block_t *block = (pm_arena_block_t *) xmalloc(PM_ARENA_BLOCK_SIZE(data_size));
51 if (block == NULL) PRISM_OOM();
52
53 block->capacity = data_size;
54 block->used = initial_used;
55 block->prev = arena->current;
56 arena->current = block;
57 arena->block_count++;
58
59 return block;
60}
61
67void
68pm_arena_reserve(pm_arena_t *arena, size_t capacity) {
69 if (capacity <= PM_ARENA_INITIAL_SIZE) return;
70 if (arena->current != NULL && (arena->current->capacity - arena->current->used) >= capacity) return;
71 pm_arena_block_new(arena, capacity, 0);
72}
73
78void *
79pm_arena_alloc_slow(pm_arena_t *arena, size_t size) {
80 size_t block_data_size = pm_arena_next_block_size(arena, size);
81 pm_arena_block_t *block = pm_arena_block_new(arena, block_data_size, size);
82 return block->data;
83}
84
89pm_arena_new(void) {
90 pm_arena_t *arena = (pm_arena_t *) xcalloc(1, sizeof(pm_arena_t));
91 if (arena == NULL) PRISM_OOM();
92 return arena;
93}
94
98void
99pm_arena_cleanup(pm_arena_t *arena) {
100 pm_arena_block_t *block = arena->current;
101
102 while (block != NULL) {
103 pm_arena_block_t *prev = block->prev;
104 xfree_sized(block, PM_ARENA_BLOCK_SIZE(block->capacity));
105 block = prev;
106 }
107
108 *arena = (pm_arena_t) { 0 };
109}
110
114void
115pm_arena_free(pm_arena_t *arena) {
116 pm_arena_cleanup(arena);
117 xfree_sized(arena, sizeof(pm_arena_t));
118}
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define xcalloc
Old name of ruby_xcalloc.
Definition xmalloc.h:55