Add single-byte opcodes for returning true/false directly, completing
the set of literal return opcodes (RETSELF, RETNIL, RETTRUE, RETFALSE).
Codegen applies peephole optimization to fuse LOADTRUE/LOADFALSE + RETURN.
Co-authored-by: Claude <noreply@anthropic.com>
Rename boolean load opcodes for consistency with LOADNIL/LOADSELF.
Backward compatibility aliases are provided in opcode.h.
Co-authored-by: Claude <noreply@anthropic.com>
Add a new opcode that returns nil without requiring LOADNIL + RETURN.
This avoids loading nil into a register by setting the return value (v)
directly. The implementation uses a separate label (L_RETURN_NIL) to
bypass v = regs[a], preserving self in regs[0] for ensure blocks.
Codegen applies peephole optimization to fuse LOADNIL + RETURN -> RETNIL.
Co-authored-by: Claude <noreply@anthropic.com>
Both opcodes had nearly identical code for creating procs and
defining methods. Now they share a common L_DEF_METHOD label,
reducing code duplication by ~10 lines.
Co-authored-by: Claude <noreply@anthropic.com>
Replace block.call(x) with yield x in core iteration methods to take
advantage of the new OP_BLKCALL optimization. This improves Integer#times
by 13% and Array#each by 7%.
Methods updated:
- Integer#times, Integer#upto, Integer#downto
- Array#each, Array#each_index
Co-authored-by: Claude <noreply@anthropic.com>
Bypass method dispatch when calling blocks via yield. The new OP_BLKCALL
instruction directly invokes the proc without looking up Proc#call,
resulting in 13-17% faster yield performance.
Co-authored-by: Claude <noreply@anthropic.com>
TDEF fuses TCLASS+METHOD+DEF for normal method definitions.
SDEF fuses SCLASS+METHOD+DEF for singleton method definitions.
Saves 4 bytes per method definition (8 bytes -> 4 bytes).
Falls back to unfused instructions if irep index exceeds 255.
Co-authored-by: Claude <noreply@anthropic.com>
Fuses MOVE+LOADI_0+GETIDX pattern into single instruction.
Saves 4 bytes per arr[0] access (7 bytes -> 3 bytes).
Co-authored-by: Claude <noreply@anthropic.com>
fuse MOVE+ADDI+MOVE and MOVE+SUBI+MOVE patterns into single instructions.
ADDILV/SUBILV add/subtract an immediate to a local variable in-place.
BBB format: a=local, b=working space for method call, c=immediate.
saves 5 bytes per instance (9->4 bytes), 40 occurrences in stdlib.
Co-authored-by: Claude <noreply@anthropic.com>
Change OP_MATCHERR from Z format (unconditional) to B format
(conditional on register). This allows fusing JMPIF + MATCHERR
sequence into a single MATCHERR instruction for simple patterns.
Before: JMPIF R2 target (4 bytes) + MATCHERR (1 byte) = 5 bytes
After: MATCHERR R2 (2 bytes)
Saves 3 bytes per pattern match with raise_on_fail.
Co-authored-by: Claude <noreply@anthropic.com>
Replace 4-instruction sequence (GETCONST + STRING + SEND + RAISEIF)
with single OP_MATCHERR instruction that raises NoMatchingPatternError
with "pattern not matched" message.
Bump RITE binary format version from 0300 to 0400 due to opcode
number shift.
Co-authored-by: Claude <noreply@anthropic.com>
- Add mrb_likely/mrb_unlikely macros to common.h for branch prediction
- Optimize OP_GETIDX array fast path:
- Cache RArray pointer to avoid repeated RARRAY() calls
- Single ARY_EMBED_P check instead of two (via RARRAY_LEN + RARRAY_PTR)
- Use unsigned comparison for bounds check
- Add branch prediction hints for common cases
- Convert switch statement to if-else chain for better branch prediction
Benchmark shows ~3% improvement for array read operations.
Co-authored-by: Claude <noreply@anthropic.com>
Add comprehensive benchmarks for measuring VM performance:
- vm_optimization_bench.rb: Ruby-level benchmarks covering dispatch,
arithmetic, method calls, array/hash access, loops, and recursion
- vm_dispatch_bench.c: C-level micro-benchmarks for precise measurement
These benchmarks are designed to measure the effect of potential VM
optimizations such as tail-call threading, register variables,
fused opcodes, and inline caching.
Usage:
# Ruby benchmark
./build/host/bin/mruby benchmark/vm_optimization_bench.rb
# C benchmark
cc -O2 -I include -I build/host/include \
benchmark/vm_dispatch_bench.c \
build/host/lib/libmruby.a -lm -o vm_dispatch_bench
./vm_dispatch_bench
Co-authored-by: Claude <noreply@anthropic.com>
Added error handling for file descriptors larger than FD_SETSIZE in mrb_hal_io_fdset_set and mrb_hal_io_fdset_isset functions, for posix hal.
I actually don't know how to fix this on windows, or if it needs fixing.
The purpose is to avoid using the `MRB_TT_CPTR` object.
The reasons are as follows:
- The `MRB_WORD_BOXING` setting involves object creation.
- If object creation fails, the `ary_set_t` data leaks memory.
expose the previously internal outer_class() function as a public API
for mrbgems to retrieve the enclosing class/module of a given class.
closes#6705.
Co-authored-by: Claude <noreply@anthropic.com>
wrap hash and eql callbacks with mrb_protect_error() to catch exceptions
during khash table rebuild. when an exception occurs (e.g., SystemStackError
from infinite recursion), return a safe default value and store the exception
in mrb->exc for later processing. this prevents memory leaks from orphaned
allocations when exceptions propagate through khash rebuild.
Co-authored-by: Claude <noreply@anthropic.com>
Function was only called once and contained just 2 lines of code.
Inlining directly reduces code size and improves clarity.
Co-authored-by: Claude <noreply@anthropic.com>
Add CPython-style parsing for base-10 string to integer conversion:
- Parse 9 digits at a time into decimal-base array
- Convert decimal-base to binary in single pass
- Use memory pool for temporary decimal buffer
- Use realloc for result buffer to reduce allocations
Also add digit_pairs lookup table for faster to_s output.
Performance: 2-5x faster for to_i, 60% fewer allocations.
Co-authored-by: Claude <noreply@anthropic.com>
- Add mrb_gc_protect() after arena_restore to prevent result from being collected before returning to caller
- Add comment to suspend_task_internal explaining why WAITING and DORMANT tasks can also be suspended
- Move argc/argv cast at the beginning of function with comment
This improves to_s performance for medium-sized bigints (40-50 limbs,
~800-1000 digits) by approximately 5x by enabling the divide-and-conquer
algorithm earlier.
Benchmark results:
40 limbs (772 digits): 88 us -> 18 us (5x faster)
50 limbs (964 digits): 134 us -> 25 us (5.4x faster)
Co-authored-by: Claude <noreply@anthropic.com>
Benchmarks show the previous threshold of 50 was too low, causing
Toom-3's setup overhead to outweigh its asymptotic benefits for
medium-sized numbers. Raising to 100 limbs provides:
- 2x faster at 300 limbs (192 -> 96 us)
- 2.5x faster at 120 limbs (42 -> 17 us)
- 2.6x faster at 80 limbs (31 -> 12 us)
Co-authored-by: Claude <noreply@anthropic.com>
When multiplying numbers where one is significantly larger than the other
(at least 2x size difference), split the larger number into chunks matching
the smaller number's size, multiply each chunk, and combine results. This
avoids pathological performance when Toom-3 pads asymmetric operands with
zeros.
Benchmarks show 6-16x speedup for size ratios from 10:1 to 40:1, with no
regression for symmetric cases.
Co-authored-by: Claude <noreply@anthropic.com>
mpz_init_heap() already allocates the requested size, so immediately
calling mpz_realloc() with the same size is a no-op. Remove these
redundant calls from mpz_and, mpz_or, mpz_xor, mpz_mod_2exp, and
mpz_abs.
Co-authored-by: Claude <noreply@anthropic.com>