diff --git a/src/emulate.c b/src/emulate.c index b9650383..a8cfbbb5 100644 --- a/src/emulate.c +++ b/src/emulate.c @@ -1238,7 +1238,8 @@ static inline int count_consecutive_shift(rv_insn_t *ir) } /* Allocate and rewrite a fused sequence. - * Returns true on success, false on malloc failure (graceful degradation). + * Returns true on success, false on allocation failure (graceful degradation). + * Uses pooled allocation for fuse arrays up to FUSE_MAX_ENTRIES. */ static inline bool try_fuse_sequence(riscv_t *rv, block_t *block, @@ -1249,11 +1250,13 @@ static inline bool try_fuse_sequence(riscv_t *rv, if (count <= 1) return false; - /* Overflow check for allocation size */ - if (unlikely((size_t) count > SIZE_MAX / sizeof(opcode_fuse_t))) + /* Reject sequences exceeding pool slot size - rare case with diminishing + * returns. This also handles the overflow check implicitly. + */ + if (unlikely(count > FUSE_MAX_ENTRIES)) return false; - opcode_fuse_t *fuse_data = malloc((size_t) count * sizeof(opcode_fuse_t)); + opcode_fuse_t *fuse_data = mpool_alloc(rv->fuse_mp); if (unlikely(!fuse_data)) return false; @@ -1857,7 +1860,7 @@ static block_t *block_find_or_translate(riscv_t *rv) next_ir = ir->next; if (ir->fuse) - free(ir->fuse); + mpool_free(rv->fuse_mp, ir->fuse); mpool_free(rv->block_ir_mp, ir); } diff --git a/src/riscv.c b/src/riscv.c index b14490f8..bfa6f0a0 100644 --- a/src/riscv.c +++ b/src/riscv.c @@ -70,7 +70,8 @@ void block_map_clear(riscv_t *rv) rv_insn_t *ir, *next; for (idx = 0, ir = block->ir_head; idx < block->n_insn; idx++, ir = next) { - free(ir->fuse); + if (ir->fuse) + mpool_free(rv->fuse_mp, ir->fuse); free(ir->branch_table); next = ir->next; mpool_free(rv->block_ir_mp, ir); @@ -88,6 +89,7 @@ static void block_map_destroy(riscv_t *rv) mpool_destroy(rv->block_mp); mpool_destroy(rv->block_ir_mp); + mpool_destroy(rv->fuse_mp); } #endif @@ -825,6 +827,11 @@ riscv_t *rv_create(riscv_user_t rv_attr) sizeof(block_t)); rv->block_ir_mp = mpool_create( sizeof(rv_insn_t) << BLOCK_IR_MAP_CAPACITY_BITS, sizeof(rv_insn_t)); + /* Fuse pool: fixed-size slots for macro-op fusion arrays. + * Each slot holds up to FUSE_MAX_ENTRIES opcode_fuse_t structures. + */ + rv->fuse_mp = mpool_create(FUSE_SLOT_SIZE << BLOCK_IR_MAP_CAPACITY_BITS, + FUSE_SLOT_SIZE); #if !RV32_HAS(JIT) /* initialize the block map */ @@ -870,6 +877,7 @@ riscv_t *rv_create(riscv_user_t rv_attr) fail_jit_state: mpool_destroy(rv->block_ir_mp); mpool_destroy(rv->block_mp); + mpool_destroy(rv->fuse_mp); map_delete(attr->fd_map); memory_delete(attr->mem); free(rv); @@ -992,6 +1000,9 @@ void rv_delete(riscv_t *rv) #endif jit_state_exit(rv->jit_state); cache_free(rv->block_cache); + mpool_destroy(rv->block_ir_mp); + mpool_destroy(rv->block_mp); + mpool_destroy(rv->fuse_mp); #endif #if RV32_HAS(SYSTEM_MMIO) u8250_delete(attr->uart); diff --git a/src/riscv_private.h b/src/riscv_private.h index eab25648..a2caa91c 100644 --- a/src/riscv_private.h +++ b/src/riscv_private.h @@ -23,6 +23,12 @@ #define PRIV(x) ((vm_attr_t *) x->data) +/* Maximum entries per fuse slot - limits fusion to 16 consecutive instructions. + * Larger sequences are rare and provide diminishing returns. + */ +#define FUSE_MAX_ENTRIES 16 +#define FUSE_SLOT_SIZE (FUSE_MAX_ENTRIES * sizeof(opcode_fuse_t)) + /* CSRs */ enum { /* floating point */ @@ -258,7 +264,7 @@ struct riscv_internal { void *jit_state; void *jit_cache; #endif - struct mpool *block_mp, *block_ir_mp; + struct mpool *block_mp, *block_ir_mp, *fuse_mp; #if RV32_HAS(GDBSTUB) /* gdbstub instance */