three functions differed only in the trailing character check ('=',
'?', '!'). replace with a single parameterized function.
Co-authored-by: Claude <noreply@anthropic.com>
both opcodes share identical proc dispatch logic (alias resolution,
callinfo setup, cfunc/irep branching). the only difference is how
nargs is computed (ci_bidx vs operand b).
Co-authored-by: Claude <noreply@anthropic.com>
Decrement gc_debt by the actual number of objects processed
instead of the fixed GC_STEP_SIZE. This makes step_ratio
directly affect debt repayment: larger steps repay more debt,
naturally reducing GC invocation frequency.
Co-authored-by: Claude <noreply@anthropic.com>
Expose gc_debt directly as :debt in GC.stat without sign negation.
The debt model has no threshold ceiling, so :threshold was a
misleading name. Negative debt means credit, positive means GC
is behind on collection work.
Co-authored-by: Claude <noreply@anthropic.com>
Use -gc_debt as the :threshold key in GC.stat for familiarity.
Positive means credit remaining, negative means GC is overdue.
Co-authored-by: Claude <noreply@anthropic.com>
Replace the threshold-based GC trigger (gc->threshold vs gc->live)
with a debt model (gc->gc_debt). Each allocation increments debt;
each GC step decrements by GC_STEP_SIZE. When a cycle completes,
credit is proportional to live_after_mark * interval_ratio, giving
a natural feedback loop that adapts to allocation rate.
Co-authored-by: Claude <noreply@anthropic.com>
GC.step_limit caps the per-step work in incremental GC,
enabling more predictable pause times for real-time use.
GC.malloc_threshold triggers GC based on allocation bytes,
addressing memory pressure from large buffers.
Both default to 0 (disabled), preserving existing behavior.
Co-authored-by: Claude <noreply@anthropic.com>
mrb_ccontext functions are implemented in mruby-compiler (y.tab.c),
causing linker errors when the compiler is excluded from the build.
Replace with mrb_load_irep_file() which is in core (src/load.c).
Also fix incorrect *argv in error message and remove dead fname field.
Co-authored-by: Claude <noreply@anthropic.com>
The `mrb` command executes only precompiled RiteBinary (.mrb) files
without depending on mruby-compiler. This enables smaller binaries
for embedded deployments where scripts are precompiled on a
development machine.
Co-authored-by: Claude <noreply@anthropic.com>
Leaf types (String, Integer, BigInt, Complex, CPTR) have no children
besides their class pointer. Mark them black immediately in
mrb_gc_mark() instead of pushing to the gray stack, reducing gray
stack pressure and overflow frequency.
Co-authored-by: Claude <noreply@anthropic.com>
Return a Hash with GC statistics: live, threshold, state,
generational, full. When MRB_GC_STATS is defined, also includes
total, minor, major counters.
Co-authored-by: Claude <noreply@anthropic.com>
Add gc_total_count, minor_gc_count, major_gc_count (uint32_t) to
mrb_gc, guarded by MRB_GC_STATS. Zero cost when disabled.
Co-authored-by: Claude <noreply@anthropic.com>
Phase 2 of opcode handler extraction. these opcodes use
L_SEND_SYM/L_SENDB_SYM fallback for generic method dispatch when
the fast path (Array/Hash/String/Integer/Float) does not apply.
add VM_SEND_SYM and VM_SENDB_SYM return codes. move TYPES2 macro
to file scope for use by vm_op_div.
Co-authored-by: Claude <noreply@anthropic.com>
extract the three largest self-contained opcode handlers from the
mrb_vm_exec() dispatch loop into static functions. add
__attribute__((flatten)) to mrb_vm_exec() so that the compiler
inlines them back, producing identical binary output while keeping
the source clean.
Co-authored-by: Claude <noreply@anthropic.com>
ENV is a plain Object with singleton methods and Enumerable,
matching CRuby's behavior. C methods wrap getenv/setenv/unsetenv
with platform support for POSIX, macOS, and Windows.
Co-authored-by: Claude <noreply@anthropic.com>
Use uscale-based shortest() to compute the minimal decimal string
that uniquely identifies each double. This guarantees perfect
round-trip (parse(to_s(x)) == x) while keeping output concise
(e.g. 0.1 prints as "0.1", not "0.10000000000000001").
Co-authored-by: Claude <noreply@anthropic.com>
Replace separate float formatting (fmt_fp.c) and parsing (readfloat.c)
implementations with a unified fp_uscale.c using 128-bit unrounded
scaling. Both mrb_format_float() and mrb_read_float() now share a
single pow10 table and uscale() primitive for decimal/binary conversion.
This fixes subnormal parsing accuracy (old code returned 0.0 for the
smallest subnormals) and corrects %.2f rounding for values like
12345.125. Table size grows from ~5KB to ~11KB in .rodata.
Co-authored-by: Claude <noreply@anthropic.com>
Remove the per-entry generation field and per-state generation
counter. Invalidation now clears entries directly, removing one
comparison from every OP_GETCONST hot path.
Co-authored-by: Claude <noreply@anthropic.com>
Right-shift class pointer by 4 before hashing to remove
always-zero alignment bits, improving hash distribution.
Organize 256 cache entries as 128 sets x 2 ways to reduce
conflict misses when multiple methods share a hash bucket.
Co-authored-by: Claude <noreply@anthropic.com>
Cache OP_GETCONST results in a global direct-mapped cache (64 entries)
keyed by (irep, sym). Invalidate all entries via a generation counter
bumped on mrb_const_set(), mrb_const_remove(), and
mrb_define_const_id(). ~10% faster on constant-heavy code; disabled
with MRB_NO_CONST_CACHE.
Co-authored-by: Claude <noreply@anthropic.com>