Ruby 4.1.0dev (2026-03-23 revision f8459601271ebbc5e1efb101387da955ed1faabb)
arena.c
1#include "prism/internal/arena.h"
2
3#include "prism/internal/allocator.h"
4
5#include <assert.h>
6#include <stdio.h>
7#include <stdlib.h>
8
13#define PM_ARENA_BLOCK_SIZE(data_size) (offsetof(pm_arena_block_t, data) + (data_size))
14
16#define PM_ARENA_INITIAL_SIZE 8192
17
19#define PM_ARENA_GROWTH_INTERVAL 8
20
22#define PM_ARENA_MAX_SIZE (1024 * 1024)
23
27static size_t
28pm_arena_next_block_size(const pm_arena_t *arena, size_t min_size) {
29 size_t size = PM_ARENA_INITIAL_SIZE;
30
31 for (size_t exp = PM_ARENA_GROWTH_INTERVAL; exp <= arena->block_count; exp += PM_ARENA_GROWTH_INTERVAL) {
32 if (size < PM_ARENA_MAX_SIZE) size *= 2;
33 }
34
35 return size > min_size ? size : min_size;
36}
37
42static pm_arena_block_t *
43pm_arena_block_new(pm_arena_t *arena, size_t data_size, size_t initial_used) {
44 assert(initial_used <= data_size);
45 pm_arena_block_t *block = (pm_arena_block_t *) xmalloc(PM_ARENA_BLOCK_SIZE(data_size));
46
47 if (block == NULL) {
48 fprintf(stderr, "prism: out of memory; aborting\n");
49 abort();
50 }
51
52 block->capacity = data_size;
53 block->used = initial_used;
54 block->prev = arena->current;
55 arena->current = block;
56 arena->block_count++;
57
58 return block;
59}
60
66void
67pm_arena_reserve(pm_arena_t *arena, size_t capacity) {
68 if (capacity <= PM_ARENA_INITIAL_SIZE) return;
69 if (arena->current != NULL && (arena->current->capacity - arena->current->used) >= capacity) return;
70 pm_arena_block_new(arena, capacity, 0);
71}
72
77void *
78pm_arena_alloc_slow(pm_arena_t *arena, size_t size) {
79 size_t block_data_size = pm_arena_next_block_size(arena, size);
80 pm_arena_block_t *block = pm_arena_block_new(arena, block_data_size, size);
81 return block->data;
82}
83
88pm_arena_new(void) {
89 pm_arena_t *arena = (pm_arena_t *) xcalloc(1, sizeof(pm_arena_t));
90 if (arena == NULL) abort();
91 return arena;
92}
93
97void
98pm_arena_cleanup(pm_arena_t *arena) {
99 pm_arena_block_t *block = arena->current;
100
101 while (block != NULL) {
102 pm_arena_block_t *prev = block->prev;
103 xfree_sized(block, PM_ARENA_BLOCK_SIZE(block->capacity));
104 block = prev;
105 }
106
107 *arena = (pm_arena_t) { 0 };
108}
109
113void
114pm_arena_free(pm_arena_t *arena) {
115 pm_arena_cleanup(arena);
116 xfree_sized(arena, sizeof(pm_arena_t));
117}
#define xmalloc
Old name of ruby_xmalloc.
Definition xmalloc.h:53
#define xcalloc
Old name of ruby_xcalloc.
Definition xmalloc.h:55