Skip to content

Commit dfdc930

Browse files
committed
Force the allocation to be inlined
1 parent f94fe6b commit dfdc930

5 files changed

Lines changed: 63 additions & 49 deletions

File tree

include/prism/defines.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,18 @@
9191
# define inline __inline
9292
#endif
9393

94+
/**
95+
* Force a function to be inlined at every call site. Use sparingly — only for
96+
* small, hot functions where the compiler's heuristics fail to inline.
97+
*/
98+
#if defined(_MSC_VER)
99+
# define PRISM_FORCE_INLINE __forceinline
100+
#elif defined(__GNUC__) || defined(__clang__)
101+
# define PRISM_FORCE_INLINE inline __attribute__((always_inline))
102+
#else
103+
# define PRISM_FORCE_INLINE inline
104+
#endif
105+
94106
/**
95107
* Old Visual Studio versions before 2015 do not implement sprintf, but instead
96108
* implement _snprintf. We standard that here.

include/prism/util/pm_arena.h

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,16 +54,42 @@ typedef struct {
5454
*/
5555
void pm_arena_reserve(pm_arena_t *arena, size_t capacity);
5656

57+
/**
58+
* Slow path for pm_arena_alloc: allocate a new block and return a pointer to
59+
* the first `size` bytes. Do not call directly — use pm_arena_alloc instead.
60+
*
61+
* @param arena The arena to allocate from.
62+
* @param size The number of bytes to allocate.
63+
* @returns A pointer to the allocated memory.
64+
*/
65+
void * pm_arena_alloc_slow(pm_arena_t *arena, size_t size);
66+
5767
/**
5868
* Allocate memory from the arena. The returned memory is NOT zeroed. This
5969
* function is infallible — it aborts on allocation failure.
6070
*
71+
* The fast path (bump pointer within the current block) is inlined at each
72+
* call site. The slow path (new block allocation) is out-of-line.
73+
*
6174
* @param arena The arena to allocate from.
6275
* @param size The number of bytes to allocate.
6376
* @param alignment The required alignment (must be a power of 2).
6477
* @returns A pointer to the allocated memory.
6578
*/
66-
void * pm_arena_alloc(pm_arena_t *arena, size_t size, size_t alignment);
79+
static PRISM_FORCE_INLINE void *
80+
pm_arena_alloc(pm_arena_t *arena, size_t size, size_t alignment) {
81+
if (arena->current != NULL) {
82+
size_t used_aligned = (arena->current->used + alignment - 1) & ~(alignment - 1);
83+
size_t needed = used_aligned + size;
84+
85+
if (used_aligned >= arena->current->used && needed >= used_aligned && needed <= arena->current->capacity) {
86+
arena->current->used = needed;
87+
return arena->current->data + used_aligned;
88+
}
89+
}
90+
91+
return pm_arena_alloc_slow(arena, size);
92+
}
6793

6894
/**
6995
* Allocate zero-initialized memory from the arena. This function is infallible
@@ -74,7 +100,12 @@ void * pm_arena_alloc(pm_arena_t *arena, size_t size, size_t alignment);
74100
* @param alignment The required alignment (must be a power of 2).
75101
* @returns A pointer to the allocated, zero-initialized memory.
76102
*/
77-
void * pm_arena_zalloc(pm_arena_t *arena, size_t size, size_t alignment);
103+
static inline void *
104+
pm_arena_zalloc(pm_arena_t *arena, size_t size, size_t alignment) {
105+
void *ptr = pm_arena_alloc(arena, size, alignment);
106+
memset(ptr, 0, size);
107+
return ptr;
108+
}
78109

79110
/**
80111
* Allocate memory from the arena and copy the given data into it. This is a
@@ -86,7 +117,12 @@ void * pm_arena_zalloc(pm_arena_t *arena, size_t size, size_t alignment);
86117
* @param alignment The required alignment (must be a power of 2).
87118
* @returns A pointer to the allocated copy.
88119
*/
89-
void * pm_arena_memdup(pm_arena_t *arena, const void *src, size_t size, size_t alignment);
120+
static inline void *
121+
pm_arena_memdup(pm_arena_t *arena, const void *src, size_t size, size_t alignment) {
122+
void *dst = pm_arena_alloc(arena, size, alignment);
123+
memcpy(dst, src, size);
124+
return dst;
125+
}
90126

91127
/**
92128
* Free all blocks in the arena. After this call, all pointers returned by

include/prism/util/pm_char.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ size_t pm_strspn_whitespace(const uint8_t *string, ptrdiff_t length);
3030
*
3131
* @param string The string to search.
3232
* @param length The maximum number of characters to search.
33+
* @param arena The arena to allocate from when appending to line_offsets.
3334
* @param line_offsets The list of newlines to populate.
3435
* @param start_offset The offset at which the string occurs in the source, for
3536
* the purpose of tracking newlines.

include/prism/util/pm_constant_pool.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,9 @@ typedef struct {
142142
/**
143143
* Initialize a new constant pool with a given capacity.
144144
*
145+
* @param arena The arena to allocate from.
145146
* @param pool The pool to initialize.
146147
* @param capacity The initial capacity of the pool.
147-
* @return Whether the initialization succeeded.
148148
*/
149149
void pm_constant_pool_init(pm_arena_t *arena, pm_constant_pool_t *pool, uint32_t capacity);
150150

@@ -172,6 +172,7 @@ pm_constant_id_t pm_constant_pool_find(const pm_constant_pool_t *pool, const uin
172172
* Insert a constant into a constant pool that is a slice of a source string.
173173
* Returns the id of the constant, or 0 if any potential calls to resize fail.
174174
*
175+
* @param arena The arena to allocate from.
175176
* @param pool The pool to insert the constant into.
176177
* @param start A pointer to the start of the constant.
177178
* @param length The length of the constant.
@@ -184,6 +185,7 @@ pm_constant_id_t pm_constant_pool_insert_shared(pm_arena_t *arena, pm_constant_p
184185
* constant pool. Returns the id of the constant, or 0 if any potential calls to
185186
* resize fail.
186187
*
188+
* @param arena The arena to allocate from.
187189
* @param pool The pool to insert the constant into.
188190
* @param start A pointer to the start of the constant.
189191
* @param length The length of the constant.
@@ -195,6 +197,7 @@ pm_constant_id_t pm_constant_pool_insert_owned(pm_arena_t *arena, pm_constant_po
195197
* Insert a constant into a constant pool from memory that is constant. Returns
196198
* the id of the constant, or 0 if any potential calls to resize fail.
197199
*
200+
* @param arena The arena to allocate from.
198201
* @param pool The pool to insert the constant into.
199202
* @param start A pointer to the start of the constant.
200203
* @param length The length of the constant.

src/util/pm_arena.c

Lines changed: 7 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ static size_t
2424
pm_arena_next_block_size(const pm_arena_t *arena, size_t min_size) {
2525
size_t size = PM_ARENA_INITIAL_SIZE;
2626

27-
for (size_t i = PM_ARENA_GROWTH_INTERVAL; i <= arena->block_count; i += PM_ARENA_GROWTH_INTERVAL) {
27+
for (size_t exp = PM_ARENA_GROWTH_INTERVAL; exp <= arena->block_count; exp += PM_ARENA_GROWTH_INTERVAL) {
2828
if (size < PM_ARENA_MAX_SIZE) size *= 2;
2929
}
3030

@@ -36,7 +36,7 @@ pm_arena_next_block_size(const pm_arena_t *arena, size_t min_size) {
3636
* into the arena, and return it. Aborts on allocation failure.
3737
*/
3838
static pm_arena_block_t *
39-
pm_arena_new_block(pm_arena_t *arena, size_t data_size, size_t initial_used) {
39+
pm_arena_block_new(pm_arena_t *arena, size_t data_size, size_t initial_used) {
4040
assert(initial_used <= data_size);
4141
pm_arena_block_t *block = (pm_arena_block_t *) xmalloc(PM_ARENA_BLOCK_SIZE(data_size));
4242

@@ -63,58 +63,20 @@ void
6363
pm_arena_reserve(pm_arena_t *arena, size_t capacity) {
6464
if (capacity <= PM_ARENA_INITIAL_SIZE) return;
6565
if (arena->current != NULL && (arena->current->capacity - arena->current->used) >= capacity) return;
66-
67-
pm_arena_new_block(arena, capacity, 0);
66+
pm_arena_block_new(arena, capacity, 0);
6867
}
6968

7069
/**
71-
* Allocate memory from the arena. The returned memory is NOT zeroed. This
72-
* function is infallible — it aborts on allocation failure.
70+
* Slow path for pm_arena_alloc: allocate a new block and return a pointer to
71+
* the first `size` bytes. Called when the current block has insufficient space.
7372
*/
7473
void *
75-
pm_arena_alloc(pm_arena_t *arena, size_t size, size_t alignment) {
76-
// Try current block.
77-
if (arena->current != NULL) {
78-
size_t used_aligned = (arena->current->used + alignment - 1) & ~(alignment - 1);
79-
size_t needed = used_aligned + size;
80-
81-
// Guard against overflow in the alignment or size arithmetic.
82-
if (used_aligned >= arena->current->used && needed >= used_aligned && needed <= arena->current->capacity) {
83-
arena->current->used = needed;
84-
return arena->current->data + used_aligned;
85-
}
86-
}
87-
88-
// Allocate new block via xmalloc — memory is NOT zeroed.
89-
// New blocks from xmalloc are max-aligned, so data[] starts aligned for
90-
// any C type. No padding needed at the start.
74+
pm_arena_alloc_slow(pm_arena_t *arena, size_t size) {
9175
size_t block_data_size = pm_arena_next_block_size(arena, size);
92-
pm_arena_block_t *block = pm_arena_new_block(arena, block_data_size, size);
93-
76+
pm_arena_block_t *block = pm_arena_block_new(arena, block_data_size, size);
9477
return block->data;
9578
}
9679

97-
/**
98-
* Allocate zero-initialized memory from the arena. This function is infallible
99-
* — it aborts on allocation failure.
100-
*/
101-
void *
102-
pm_arena_zalloc(pm_arena_t *arena, size_t size, size_t alignment) {
103-
void *ptr = pm_arena_alloc(arena, size, alignment);
104-
memset(ptr, 0, size);
105-
return ptr;
106-
}
107-
108-
/**
109-
* Allocate memory from the arena and copy the given data into it.
110-
*/
111-
void *
112-
pm_arena_memdup(pm_arena_t *arena, const void *src, size_t size, size_t alignment) {
113-
void *dst = pm_arena_alloc(arena, size, alignment);
114-
memcpy(dst, src, size);
115-
return dst;
116-
}
117-
11880
/**
11981
* Free all blocks in the arena.
12082
*/

0 commit comments

Comments
 (0)