From 8b767568df81e77e3d45c0c285b412683c88e01d Mon Sep 17 00:00:00 2001 From: HASUMI Hitoshi Date: Mon, 26 Oct 2026 16:18:04 +0900 Subject: [PATCH 1/3] Let an embedder set PM_ARENA_INITIAL_SIZE The arena's first block is 8 KB, sized for a host. An embedder on a small heap parses short programs (a REPL line uses about 6 KB in two arenas) and pays two 8 KB blocks for each; with the constant under #ifndef it can build with -DPM_ARENA_INITIAL_SIZE=2048 instead. --- src/arena.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/arena.c b/src/arena.c index 64a731649d..323c5bdc7d 100644 --- a/src/arena.c +++ b/src/arena.c @@ -12,8 +12,13 @@ */ #define PM_ARENA_BLOCK_SIZE(data_size) (offsetof(pm_arena_block_t, data) + (data_size)) -/** Initial block data size: 8 KB. */ +/** + * Initial block data size: 8 KB. An embedder on a small heap can define a + * smaller one; a parse of a short program then takes blocks of that size. + */ +#ifndef PM_ARENA_INITIAL_SIZE #define PM_ARENA_INITIAL_SIZE 8192 +#endif /** Double the block size every this many blocks. */ #define PM_ARENA_GROWTH_INTERVAL 8 From 5ec4cc209902cdc5f841dc9ab5a2f6034fab1f0b Mon Sep 17 00:00:00 2001 From: HASUMI Hitoshi Date: Mon, 26 Oct 2026 16:18:04 +0900 Subject: [PATCH 2/3] Include sys/types.h before inttypes.h again, for newlib 61ebe5123 made defines.h include ahead of : with an arm-none-eabi toolchain whose is GCC's own, newlib's never sees the marker it tests before defining the 64-bit PRI macros, and PRIu64 goes undefined while PRIu32 does not. 400b21739 ("Remove defines") took the header out and the workaround with it, so a cross build of integer.c and errors_format.c, the two files that include now, fails on such a toolchain (Debian's gcc-arm-none-eabi 13.2.1 with newlib). Put the include back in those two files, with the note. --- src/errors_format.c | 4 ++++ src/integer.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/errors_format.c b/src/errors_format.c index 32956a613a..afb6ee1214 100644 --- a/src/errors_format.c +++ b/src/errors_format.c @@ -8,6 +8,10 @@ #include "prism/internal/parser.h" #include +// Include sys/types.h before inttypes.h to work around an issue with certain +// versions of GCC and newlib which causes omission of the 64-bit PRI macros +// (see 61ebe5123; the removal of defines.h dropped it). +#include #include #include #include diff --git a/src/integer.c b/src/integer.c index 104052412d..deb317695a 100644 --- a/src/integer.c +++ b/src/integer.c @@ -4,6 +4,10 @@ #include "prism/internal/buffer.h" #include +// Include sys/types.h before inttypes.h to work around an issue with certain +// versions of GCC and newlib which causes omission of PRIu64 and the other +// 64-bit macros (see 61ebe5123; the removal of defines.h dropped it). +#include #include #include #include From d2bd15ae6e736bba5d8aaed4e4ca505522e14cb0 Mon Sep 17 00:00:00 2001 From: HASUMI Hitoshi Date: Mon, 26 Oct 2026 17:54:56 +0900 Subject: [PATCH 3/3] Let an embedder set PM_CONSTANT_POOL_MIN_CAPACITY The constant pool starts at source size / 120 entries, 4 at the least, and doubles at a load of 3/4; each outgrown pair of arrays stays in the metadata arena. An embedder that interns a fixed set of names into the pool at every parse (mruby's compiler puts its 58 presyms there, as its symbol table) grows a short program's pool from 4 to 128 and leaves about 3 KB behind, as much as the pool itself. With the minimum under #ifndef it can build with -DPM_CONSTANT_POOL_MIN_CAPACITY=128: measured on a 32-bit build with 2 KB arena blocks, parsing one REPL line then holds 6 KB instead of 10 KB. The default stays 4. --- src/prism.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/prism.c b/src/prism.c index 5bdab809a2..01b91fee91 100644 --- a/src/prism.c +++ b/src/prism.c @@ -23254,6 +23254,16 @@ pm_parser_init_shebang(pm_parser_t *parser, const pm_options_t *options, const c parser->frozen_string_literal = next_options.frozen_string_literal; } +/** + * The smallest capacity the constant pool starts with, whatever the source + * size suggests. An embedder that interns a fixed set of names into the pool + * at every parse (a symbol table) can raise it to that set's size, so the + * pool does not grow to hold them and leave each outgrown array in the arena. + */ +#ifndef PM_CONSTANT_POOL_MIN_CAPACITY +#define PM_CONSTANT_POOL_MIN_CAPACITY 4 +#endif + /** * Initialize a parser with the given start and end pointers. */ @@ -23331,7 +23341,8 @@ pm_parser_init(pm_arena_t *arena, pm_parser_t *parser, const uint8_t *source, si * frequency. Resizes are cheap with arena allocation, so we lean toward * under-estimating. */ uint32_t constant_size = ((uint32_t) size) / 120; - pm_constant_pool_init(&parser->metadata_arena, &parser->constant_pool, constant_size < 4 ? 4 : constant_size); + if (constant_size < PM_CONSTANT_POOL_MIN_CAPACITY) constant_size = PM_CONSTANT_POOL_MIN_CAPACITY; + pm_constant_pool_init(&parser->metadata_arena, &parser->constant_pool, constant_size); /* Initialize the line offset list. Similar to the constant pool, we are * going to estimate the number of newlines that we will need based on the