mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
load.c: consolidate irep allocation for .mrb loading
Pack pool/syms/reps arrays into a single calloc with the irep struct, reducing 4 allocations per irep to 1. Arrays are ordered by descending alignment (pool/reps/syms) to eliminate inter-array padding. Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -82,6 +82,7 @@ struct mrb_irep {
|
||||
#define MRB_ISEQ_NO_FREE 1
|
||||
#define MRB_IREP_NO_FREE 2
|
||||
#define MRB_IREP_STATIC (MRB_ISEQ_NO_FREE | MRB_IREP_NO_FREE)
|
||||
#define MRB_IREP_CONSOLIDATED 4 /* pool/syms/reps packed with irep struct */
|
||||
|
||||
MRB_API mrb_irep *mrb_add_irep(mrb_state *mrb);
|
||||
|
||||
|
||||
+123
-26
@@ -59,6 +59,95 @@ str_to_double(mrb_state *mrb, const char *p)
|
||||
}
|
||||
#endif
|
||||
|
||||
#define ALIGN_UP(x, a) (((x) + (a) - 1) & ~((size_t)(a) - 1))
|
||||
|
||||
/*
|
||||
* Lightweight prescan of pool/syms binary data to learn plen and slen
|
||||
* without allocating. Must stay in sync with the pool/syms parsing
|
||||
* in read_irep_record_1().
|
||||
*/
|
||||
static mrb_bool
|
||||
prescan_pool_syms(const uint8_t *src, const uint8_t *end, uint16_t *plenp, uint16_t *slenp)
|
||||
{
|
||||
uint16_t plen;
|
||||
int i;
|
||||
|
||||
if (src + sizeof(uint16_t) > end) return FALSE;
|
||||
plen = bin_to_uint16(src);
|
||||
src += sizeof(uint16_t);
|
||||
|
||||
for (i = 0; i < plen; i++) {
|
||||
if (src >= end) return FALSE;
|
||||
switch (*src++) {
|
||||
case IREP_TT_INT32:
|
||||
src += sizeof(uint32_t);
|
||||
break;
|
||||
case IREP_TT_INT64:
|
||||
src += sizeof(uint32_t) * 2;
|
||||
break;
|
||||
case IREP_TT_BIGINT:
|
||||
if (src >= end) return FALSE;
|
||||
src += bin_to_uint8(src) + 2;
|
||||
break;
|
||||
case IREP_TT_FLOAT:
|
||||
src += sizeof(double);
|
||||
break;
|
||||
case IREP_TT_STR:
|
||||
if (src + sizeof(uint16_t) > end) return FALSE;
|
||||
src += sizeof(uint16_t) + bin_to_uint16(src) + 1;
|
||||
break;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
if (src > end) return FALSE;
|
||||
}
|
||||
|
||||
if (src + sizeof(uint16_t) > end) return FALSE;
|
||||
*plenp = plen;
|
||||
*slenp = bin_to_uint16(src);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Single consolidated allocation for irep struct + pool + syms + reps arrays.
|
||||
* Memory layout: [mrb_irep] [mrb_irep_pool[plen]] [mrb_irep*[rlen]] [mrb_sym[slen]]
|
||||
* Ordered by descending alignment to minimize inter-array padding.
|
||||
*/
|
||||
static mrb_irep*
|
||||
irep_alloc_consolidated(mrb_state *mrb, uint16_t plen, uint16_t slen, uint16_t rlen)
|
||||
{
|
||||
size_t off = sizeof(mrb_irep);
|
||||
size_t pool_off = 0, syms_off = 0, reps_off = 0;
|
||||
uint8_t *block;
|
||||
mrb_irep *irep;
|
||||
|
||||
/* pool (8-byte aligned: contains int64_t/double in union) */
|
||||
if (plen > 0) {
|
||||
pool_off = ALIGN_UP(off, 8);
|
||||
off = pool_off + sizeof(mrb_irep_pool) * plen;
|
||||
}
|
||||
/* reps (pointer-aligned: naturally follows 8-byte-aligned pool) */
|
||||
if (rlen > 0) {
|
||||
reps_off = ALIGN_UP(off, sizeof(void*));
|
||||
off = reps_off + sizeof(mrb_irep*) * rlen;
|
||||
}
|
||||
/* syms (4-byte aligned: naturally follows pointer-aligned reps) */
|
||||
if (slen > 0) {
|
||||
syms_off = ALIGN_UP(off, sizeof(mrb_sym));
|
||||
off = syms_off + sizeof(mrb_sym) * slen;
|
||||
}
|
||||
|
||||
block = (uint8_t*)mrb_calloc(mrb, 1, off);
|
||||
irep = (mrb_irep*)block;
|
||||
irep->flags = MRB_IREP_CONSOLIDATED;
|
||||
irep->refcnt = 1;
|
||||
if (plen > 0) irep->pool = (const mrb_irep_pool*)(block + pool_off);
|
||||
if (slen > 0) irep->syms = (const mrb_sym*)(block + syms_off);
|
||||
if (rlen > 0) irep->reps = (const struct mrb_irep *const*)(block + reps_off);
|
||||
|
||||
return irep;
|
||||
}
|
||||
|
||||
static mrb_bool
|
||||
read_irep_record_1(mrb_state *mrb, const uint8_t *bin, const uint8_t *end, size_t *len, uint8_t flags, mrb_irep **irepp)
|
||||
{
|
||||
@@ -66,43 +155,58 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, const uint8_t *end, size_
|
||||
const uint8_t *src = bin;
|
||||
ptrdiff_t diff;
|
||||
uint16_t tt, pool_data_len, snl;
|
||||
uint16_t nlocals, nregs, rlen, clen;
|
||||
uint32_t ilen;
|
||||
int plen;
|
||||
mrb_irep_pool *pool;
|
||||
mrb_sym *syms;
|
||||
mrb_irep *irep;
|
||||
int ai = mrb_gc_arena_save(mrb);
|
||||
mrb_irep *irep = mrb_add_irep(mrb);
|
||||
|
||||
*irepp = irep;
|
||||
|
||||
/* skip record size */
|
||||
src += sizeof(uint32_t);
|
||||
|
||||
/* number of local variable */
|
||||
irep->nlocals = bin_to_uint16(src);
|
||||
/* parse header into local variables */
|
||||
nlocals = bin_to_uint16(src);
|
||||
src += sizeof(uint16_t);
|
||||
|
||||
/* number of register variable */
|
||||
irep->nregs = bin_to_uint16(src);
|
||||
nregs = bin_to_uint16(src);
|
||||
src += sizeof(uint16_t);
|
||||
|
||||
/* number of child irep */
|
||||
irep->rlen = bin_to_uint16(src);
|
||||
rlen = bin_to_uint16(src);
|
||||
src += sizeof(uint16_t);
|
||||
|
||||
/* Binary Data Section */
|
||||
/* ISEQ BLOCK (and CATCH HANDLER TABLE BLOCK) */
|
||||
irep->clen = bin_to_uint16(src); /* number of catch handler */
|
||||
clen = bin_to_uint16(src); /* number of catch handler */
|
||||
src += sizeof(uint16_t);
|
||||
irep->ilen = bin_to_uint32(src);
|
||||
ilen = bin_to_uint32(src);
|
||||
src += sizeof(uint32_t);
|
||||
|
||||
/* prescan pool/syms to learn counts for consolidated allocation */
|
||||
{
|
||||
const uint8_t *pool_start = src;
|
||||
uint16_t pre_plen, pre_slen;
|
||||
if (ilen > 0) {
|
||||
size_t iseq_len;
|
||||
if (SIZE_ERROR_MUL(ilen, sizeof(mrb_code))) return FALSE;
|
||||
iseq_len = sizeof(mrb_code) * ilen +
|
||||
sizeof(struct mrb_irep_catch_handler) * clen;
|
||||
if (src + iseq_len > end) return FALSE;
|
||||
pool_start = src + iseq_len;
|
||||
}
|
||||
if (!prescan_pool_syms(pool_start, end, &pre_plen, &pre_slen)) return FALSE;
|
||||
irep = irep_alloc_consolidated(mrb, pre_plen, pre_slen, rlen);
|
||||
}
|
||||
*irepp = irep;
|
||||
irep->nlocals = nlocals;
|
||||
irep->nregs = nregs;
|
||||
irep->rlen = rlen;
|
||||
irep->clen = clen;
|
||||
irep->ilen = ilen;
|
||||
|
||||
if (irep->ilen > 0) {
|
||||
size_t data_len = sizeof(mrb_code) * irep->ilen +
|
||||
sizeof(struct mrb_irep_catch_handler) * irep->clen;
|
||||
mrb_static_assert(sizeof(struct mrb_irep_catch_handler) == 13);
|
||||
if (SIZE_ERROR_MUL(irep->ilen, sizeof(mrb_code))) {
|
||||
return FALSE;
|
||||
}
|
||||
if (src + data_len > end) return FALSE;
|
||||
if ((flags & FLAG_SRC_MALLOC) == 0) {
|
||||
irep->iseq = (mrb_code*)src;
|
||||
@@ -121,10 +225,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, const uint8_t *end, size_
|
||||
src += sizeof(uint16_t);
|
||||
if (src > end) return FALSE;
|
||||
if (plen > 0) {
|
||||
if (SIZE_ERROR_MUL(plen, sizeof(mrb_value))) {
|
||||
return FALSE;
|
||||
}
|
||||
irep->pool = pool = (mrb_irep_pool*)mrb_calloc(mrb, sizeof(mrb_irep_pool), plen);
|
||||
pool = (mrb_irep_pool*)irep->pool; /* in consolidated block */
|
||||
|
||||
for (i = 0; i < plen; i++) {
|
||||
mrb_bool st = (flags & FLAG_SRC_MALLOC)==0;
|
||||
@@ -217,10 +318,7 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, const uint8_t *end, size_
|
||||
src += sizeof(uint16_t);
|
||||
if (src > end) return FALSE;
|
||||
if (irep->slen > 0) {
|
||||
if (SIZE_ERROR_MUL(irep->slen, sizeof(mrb_sym))) {
|
||||
return FALSE;
|
||||
}
|
||||
irep->syms = syms = (mrb_sym*)mrb_malloc(mrb, sizeof(mrb_sym) * irep->slen);
|
||||
syms = (mrb_sym*)irep->syms; /* in consolidated block */
|
||||
|
||||
for (i = 0; i < irep->slen; i++) {
|
||||
snl = bin_to_uint16(src); /* symbol name length */
|
||||
@@ -263,8 +361,7 @@ read_irep_record(mrb_state *mrb, const uint8_t *bin, const uint8_t *end, size_t
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
reps = (mrb_irep**)mrb_calloc(mrb, (*irepp)->rlen, sizeof(mrb_irep*));
|
||||
(*irepp)->reps = (const mrb_irep**)reps;
|
||||
reps = (mrb_irep**)(*irepp)->reps; /* in consolidated block */
|
||||
|
||||
bin += *len;
|
||||
for (i=0; i<(*irepp)->rlen; i++) {
|
||||
|
||||
+5
-3
@@ -134,8 +134,10 @@ void
|
||||
mrb_irep_free(mrb_state *mrb, mrb_irep *irep)
|
||||
{
|
||||
int i;
|
||||
mrb_bool consolidated;
|
||||
|
||||
if (irep->flags & MRB_IREP_NO_FREE) return;
|
||||
consolidated = (irep->flags & MRB_IREP_CONSOLIDATED) != 0;
|
||||
if (!(irep->flags & MRB_ISEQ_NO_FREE))
|
||||
mrb_free(mrb, (void*)irep->iseq);
|
||||
if (irep->pool) {
|
||||
@@ -145,15 +147,15 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep)
|
||||
mrb_free(mrb, (void*)irep->pool[i].u.str);
|
||||
}
|
||||
}
|
||||
mrb_free(mrb, (void*)irep->pool);
|
||||
if (!consolidated) mrb_free(mrb, (void*)irep->pool);
|
||||
}
|
||||
mrb_free(mrb, (void*)irep->syms);
|
||||
if (!consolidated) mrb_free(mrb, (void*)irep->syms);
|
||||
if (irep->reps) {
|
||||
for (i=0; i<irep->rlen; i++) {
|
||||
if (irep->reps[i])
|
||||
mrb_irep_decref(mrb, (mrb_irep*)irep->reps[i]);
|
||||
}
|
||||
mrb_free(mrb, (void*)irep->reps);
|
||||
if (!consolidated) mrb_free(mrb, (void*)irep->reps);
|
||||
}
|
||||
mrb_free(mrb, (void*)irep->lv);
|
||||
mrb_debug_info_free(mrb, irep->debug_info);
|
||||
|
||||
Reference in New Issue
Block a user