@@ -86,6 +86,35 @@ sym_validate_len(mrb_state *mrb, size_t len)
8686 }
8787}
888889+/* Chunk-based string pool for heap-allocated symbol names */
90+#define MRB_SYM_POOL_CHUNK_SIZE 4096
91+92+struct sym_pool_chunk {
93+struct sym_pool_chunk *next;
94+size_t used;
95+char buf[]; /* flexible array */
96+};
97+98+static char*
99+sym_pool_alloc(mrb_state *mrb, size_t size)
100+{
101+/* round up to even size to keep pointers even-aligned (LSB tagging) */
102+size_t asize = (size + 1) & ~(size_t)1;
103+struct sym_pool_chunk *chunk = (struct sym_pool_chunk*)mrb->sym_pool;
104+if (chunk && chunk->used + asize <= MRB_SYM_POOL_CHUNK_SIZE) {
105+char *p = chunk->buf + chunk->used;
106+chunk->used += asize;
107+return p;
108+ }
109+size_t csize = asize > MRB_SYM_POOL_CHUNK_SIZE ? asize : MRB_SYM_POOL_CHUNK_SIZE;
110+chunk = (struct sym_pool_chunk*)mrb_malloc(mrb,
111+ offsetof(struct sym_pool_chunk, buf) + csize);
112+chunk->next = (struct sym_pool_chunk*)mrb->sym_pool;
113+chunk->used = asize;
114+mrb->sym_pool = (void*)chunk;
115+return chunk->buf;
116+}
117+89118/* Hash table for symbols (allocated on demand when symbols exceed threshold) */
90119struct mrb_sym_hash_table {
91120uint8_t *symlink; /* collision resolution chains */
@@ -316,7 +345,7 @@ sym_intern_common(mrb_state *mrb, const char *name, size_t len, mrb_bool lit)
316345/* Always heap-allocate when not explicitly literal */
317346uint32_t ulen = (uint32_t)len;
318347size_t ilen = mrb_packed_int_len(ulen);
319-char *p = (char*)mrb_malloc(mrb, len+ilen+1);
348+char *p = sym_pool_alloc(mrb, len+ilen+1);
320349mrb_packed_int_encode(ulen, (uint8_t*)p);
321350memcpy(p+ilen, name, len);
322351p[ilen+len] = 0;
@@ -604,16 +633,15 @@ mrb_sym_name_len(mrb_state *mrb, mrb_sym sym, mrb_int *lenp)
604633void
605634mrb_free_symtbl(mrb_state *mrb)
606635{
607-mrb_sym i, lim;
608-609-for (i=1,lim=mrb->symidx+1; i<lim; i++) {
610-const char *tagged_ptr = mrb->symtbl[i];
611-if (!symtbl_is_literal(tagged_ptr)) {
612-/* CRITICAL: Untag before mrb_free */
613-const char *clean_ptr = symtbl_get_ptr(tagged_ptr);
614-mrb_free(mrb, (char*)clean_ptr);
615- }
636+/* Free symbol string pool chunks */
637+struct sym_pool_chunk *chunk = (struct sym_pool_chunk*)mrb->sym_pool;
638+while (chunk) {
639+struct sym_pool_chunk *next = chunk->next;
640+mrb_free(mrb, chunk);
641+chunk = next;
616642 }
643+mrb->sym_pool = NULL;
644+617645mrb_free(mrb, (void*)mrb->symtbl);
618646619647/* Free hash table if allocated */
@@ -629,6 +657,7 @@ mrb_init_symtbl(mrb_state *mrb)
629657{
630658/* Initialize in linear mode - hash table allocated on demand */
631659mrb->symhash = NULL;
660+mrb->sym_pool = NULL;
632661}
633662634663/**********************************************************************