Commit Graph

5567 Commits

Author SHA1 Message Date
Yukihiro "Matz" Matsumoto 4617263030 mruby-compiler: fix JMPNOT-to-MATCHERR rewriting in pattern match codegen
The MATCHERR optimization replaced JMPNOT (BS, 4 bytes) with
MATCHERR (B, 2 bytes) and rewound s->pc by 2. When pattern
alternation (e.g. a|B) dispatched a success jump to s->pc before
the optimization, the rewind shifted subsequent instructions and
the jump landed in the middle of the next instruction, causing
out-of-bounds access at runtime.

Replace JMPNOT in-place with MATCHERR+NOP+NOP to keep the same
4-byte size, so s->pc does not change and jump targets stay valid.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-10 11:12:27 +09:00
Yukihiro "Matz" Matsumoto b287c12e48 mruby-compiler: raise error for pin operator with undefined variable
CRuby raises SyntaxError for `^a` in pattern matching when `a` is
not a local variable. Previously mruby silently generated an
unconditional fail jump, which also led to bytecode corruption
when combined with alternation patterns.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-10 11:12:27 +09:00
Yukihiro "Matz" Matsumoto eea9e30979 mruby-compiler: fix heap-buffer-overflow in pattern alternation codegen
The JMPNOT-to-JMPIF optimization in NODE_PAT_ALT assumed the fail
chain always ends with OP_JMPNOT (format BS), but NODE_PAT_PIN
generates OP_JMP (format S) when the pinned variable is undefined.
Writing OP_JMPIF at left_fail-2 then corrupts the preceding
instruction's operand, causing out-of-bounds pool access at runtime.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-10 11:12:27 +09:00
Yukihiro "Matz" Matsumoto 06d6d0b0a5 bigint.c: fix memory leak in powm with oversized modulus
Barrett and Montgomery reduction compute 2^(2k) internally where k
is the modulus bit length. When this exceeds MRB_BIGINT_BIT_LIMIT,
mrb_raise() via longjmp skips cleanup of allocated temporaries.
Add early modulus size check before any heap allocation.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-10 11:12:26 +09:00
Yukihiro "Matz" Matsumoto edce0a338f bigint.c: fix stack buffer overflow in Montgomery reduction
The work buffer size in mpz_montgomery_reduce() was calculated as
x_len + k + 2, which assumed x_len >= k. However, when R^2 mod n
produces a small result, x_len can be much smaller than k.

The Montgomery reduction loop writes k limbs at work[i] for each
iteration i=0..k-1, so the maximum index accessed is work[2k-1].
This requires at least 2k limbs in the work buffer.

Fixed by ensuring work_size is at least 2*k+2 limbs when x_len < k.

Also initialize b->as.heap before mpz_move in bint_set() to ensure
the destination mpz_t has valid initial state.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-10 11:12:26 +09:00
Yukihiro "Matz" Matsumoto cafbf8ca6b bigint.c: fix memory leak in mpz_mul_sparse and bint_mul
mpz_mul_sparse allocated temporary mpz_t variables (shifted, temp) that
were leaked when an exception was raised (e.g., RangeError from shift
width too large). bint_mul had the same issue with its output mpz_t z.

Wrap both functions with MRB_ENSURE to guarantee cleanup runs regardless
of exceptions, following the existing pattern used by mpz_mul_all_ones.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-10 11:12:26 +09:00
Yukihiro "Matz" Matsumoto 1713d4a2e7 mruby-bin-mirb: syntax highlight result values and hash key symbols
Use syntax highlighter for result values instead of single color.
Add support for hash key symbol syntax (e.g., `a:` in `{a: 1}`).

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-10 11:12:26 +09:00
Yukihiro "Matz" Matsumoto e8e2e76fd6 mruby-bin-mirb: add colored output for results and errors
Result values are shown in cyan, errors in bold red.
The arrow " => " uses gray for subtle appearance.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-10 11:12:26 +09:00
Yukihiro "Matz" Matsumoto db4c8d91ea mruby-bin-mirb: add OSC 11 terminal background color detection
Automatically detect terminal background color using OSC 11 escape
sequence to select appropriate syntax highlighting theme (dark/light).

Detection priority: MIRB_THEME env > OSC 11 > COLORFGBG env > dark default.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-10 11:12:26 +09:00
dearblue d94ec9786e Fixes identity for proc object
Previously, the identity of the proc object was verified solely based on the identity of irep.
This patch makes the behavior consistent with CRuby.

The reason I noticed this issue was that when adding multiple proc objects with the same irep to a set object, only one was added.

```ruby
p Set.new(Array.new(3) { -> {} }).size
# => 3 (Ruby 4.0)
# => 1 (mruby without this patch)
```

If the block scope is the same, there is only one in CRuby as well.
However, in CRuby, the result of `Proc#to_s` is not affected by the block scope, so it has been changed to be based on the object's address.
The reason no test for `Proc#to_s` was added is that I couldn't determine whether it should be based on `Proc#hash` or the object's address.

```ruby
b = []
t = 3
while t > 0
  b << -> {}
  t -= 1
end

p Set.new(b).size
# => 1 (Ruby 4.0 and mruby)

p b[0].to_s == b[1].to_s
# => false (Ruby 4.0)
# => true (mruby without this patch)
```
2026-02-07 16:47:39 +09:00
Yukihiro "Matz" Matsumoto 7d08c6246d codegen.c: fix sign-compare warning in gen_binop()
Co-authored-by: Claude <noreply@anthropic.com>
2026-01-27 16:03:08 +09:00
Yukihiro "Matz" Matsumoto 661ad9fb03 codegen.c: fix keyword arguments in super and yield
The first keyword argument was dropped because gen_hash() was
called with callargs->keyword_args->cdr instead of
callargs->keyword_args.

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-27 15:59:20 +09:00
Yukihiro "Matz" Matsumoto f78334b3bf parse.y: allow trailing comma in method definition parameters
Co-authored-by: Claude <noreply@anthropic.com>
2026-01-27 15:20:22 +09:00
Yukihiro "Matz" Matsumoto 32a27216bb test: add parentheses to method calls on assignment RHS
Preparation for future grammar simplification that may
require parentheses for method calls with arguments on
the right-hand side of assignments.

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-27 14:58:14 +09:00
Yukihiro "Matz" Matsumoto 9123ef46eb vm: add OP_SEND0 and OP_SSEND0 for zero-argument method calls
These opcodes use BB format instead of BBB, saving 1 byte per call.
In the standard library, this saves ~790 bytes (568 SEND0 + 222 SSEND0).

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-27 14:57:27 +09:00
Yukihiro "Matz" Matsumoto 7f13422f2f vm: add OP_RETTRUE and OP_RETFALSE for returning boolean literals
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>
2026-01-27 14:57:27 +09:00
Yukihiro "Matz" Matsumoto a1567be5da ops.h: rename OP_LOADT/OP_LOADF to OP_LOADTRUE/OP_LOADFALSE
Rename boolean load opcodes for consistency with LOADNIL/LOADSELF.
Backward compatibility aliases are provided in opcode.h.

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-27 14:57:26 +09:00
Yukihiro "Matz" Matsumoto 0b1af858e2 vm: add OP_RETNIL for returning nil directly
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>
2026-01-27 14:57:26 +09:00
Yukihiro "Matz" Matsumoto 52bee49ad2 vm: add OP_BLKCALL for direct block call without method dispatch
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>
2026-01-27 14:57:26 +09:00
Yukihiro "Matz" Matsumoto 48a88ed79b vm: add OP_TDEF/OP_SDEF for fused method definition
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>
2026-01-27 14:57:25 +09:00
Yukihiro "Matz" Matsumoto 51e8da6614 vm: add OP_GETIDX0 for fast array[0] access
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>
2026-01-27 14:57:25 +09:00
Yukihiro "Matz" Matsumoto 5475ea573a vm: add OP_ADDILV/OP_SUBILV for local variable increment
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>
2026-01-27 14:57:25 +09:00
Yukihiro "Matz" Matsumoto 724a2e2638 vm: add OP_RETSELF instruction for returning self
Fuse LOADSELF + RETURN sequence into single RETSELF instruction.
Saves 2 bytes per occurrence (3 bytes -> 1 byte).

Found 25 occurrences in mrblib, saving 50 bytes total.

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-27 14:57:25 +09:00
Yukihiro "Matz" Matsumoto dece8cb343 vm: fuse JMPIF and MATCHERR into conditional MATCHERR
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>
2026-01-27 14:57:24 +09:00
Yukihiro "Matz" Matsumoto 2fa99a73c2 vm: add OP_MATCHERR instruction for pattern matching errors
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>
2026-01-27 14:57:24 +09:00
Yukihiro "Matz" Matsumoto 92010e9fe4 Merge pull request #6709 from dearblue/mrb_ensure 2026-01-27 13:49:48 +09:00
Hendrik c836b096af Add error handling for fdset size limit
This should fix it for Windows.
2026-01-25 16:04:23 +01:00
Hendrik 8769f37868 Improve error handling for file descriptor range 2026-01-25 15:46:56 +01:00
Hendrik 44831711fc Fix out of bounds read and write in IO.select
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.
2026-01-25 15:42:17 +01:00
dearblue 5bc08befae Use the specialized MRB_ENSURE() instead of mrb_protect_error() 2026-01-24 11:34:02 +09:00
dearblue da75e4b049 Use MRB_ENSURE() instead of mrb_ensure()
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.
2026-01-24 11:32:57 +09:00
Yukihiro "Matz" Matsumoto c25b562256 Merge pull request #6706 from Asmod4n/patch-4 2026-01-20 13:28:25 +09:00
Yukihiro "Matz" Matsumoto aadd23cc70 Merge pull request #6699 from hasumikin/fix/mruby-task 2026-01-20 12:37:29 +09:00
Hendrik 3d5bb929ab Refactor task class to use symbol IDs 2026-01-17 19:31:24 +01:00
Yukihiro "Matz" Matsumoto 0ba48a2a5b mruby-set: fix memory leak in khash rebuild using mrb_protect_error()
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>
2026-01-17 13:00:45 +09:00
Yukihiro "Matz" Matsumoto 27c9356f99 Revert "mruby-set: fix memory leak caused by recursive hash computation"
This reverts commit c9e3af60e1.
2026-01-17 12:55:50 +09:00
Yukihiro "Matz" Matsumoto a9f02eb6a4 bigint.c: add inline to limb_popcount()
Small helper called in a loop from mpz_popcount().

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-17 11:13:59 +09:00
Yukihiro "Matz" Matsumoto 8d15caec14 bigint.c: add inline to mpn_add_n() and mpn_sub_n()
Both functions are small helpers called only from mpn_add()
and mpn_sub() respectively.

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-17 11:07:14 +09:00
Yukihiro "Matz" Matsumoto 632391fba2 bigint.c: add inline to mpn_div_batch()
Co-authored-by: Claude <noreply@anthropic.com>
2026-01-16 18:06:46 +09:00
Yukihiro "Matz" Matsumoto 6ebb6f3f4e bigint.c: use mpn_cmp() in ucmp()
Move mpn_cmp() before ucmp() and simplify ucmp() to use it
instead of duplicating the comparison loop.

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-16 17:17:18 +09:00
Yukihiro "Matz" Matsumoto 2a415f1640 bigint.c: remove unused mpn_submul_1()
Co-authored-by: Claude <noreply@anthropic.com>
2026-01-16 17:14:43 +09:00
Yukihiro "Matz" Matsumoto 8089fdadf0 bigint.c: inline usub_inplace() at call site
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>
2026-01-16 17:11:43 +09:00
Yukihiro "Matz" Matsumoto ad1254e3cc bigint.c: optimize decimal string parsing with chunked conversion
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>
2026-01-16 16:59:27 +09:00
HASUMI Hitoshi 219588091b Improve task.c code clarity and fix potential GC issue
- 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
2026-01-16 08:56:49 +09:00
Yukihiro "Matz" Matsumoto 9e6f2809ce bigint.c: optimize decimal string conversion with base conversion algorithm
Replace the repeated-division approach with Knuth's base conversion
algorithm for decimal string conversion. This processes each input
limb once (MSB to LSB) and builds the decimal representation
incrementally, which is faster than dividing the entire number
repeatedly.

Performance improvement for to_s on numbers under D&C threshold:
- 128 bits:  2.5x faster (0.80 -> 0.32 us)
- 256 bits:  3.6x faster (1.47 -> 0.41 us)
- 512 bits:  5.0x faster (3.47 -> 0.69 us)
- 1024 bits: 6.1x faster (9.37 -> 1.55 us)
- 2048 bits: 6.4x faster (31.0 -> 4.82 us)

Also includes:
- Montgomery reduction for modular exponentiation (powm)
- Adjusted Barrett reduction threshold to >= 4 limbs

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-16 08:46:11 +09:00
Yukihiro "Matz" Matsumoto 27816e7482 bigint.c: lower DC_GET_STR_THRESHOLD from 1000 to 700
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>
2026-01-15 16:52:57 +09:00
Yukihiro "Matz" Matsumoto 85e81072cf mruby-bigint: add Karatsuba multiplication for medium-sized numbers
Implement Karatsuba algorithm for operands with 32-99 limbs, providing
~10-25% speedup over schoolbook multiplication in this range.

Algorithm hierarchy is now:
  - Schoolbook: < 32 limbs
  - Karatsuba:  32-99 limbs
  - Toom-3:     >= 100 limbs

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-15 16:12:45 +09:00
Yukihiro "Matz" Matsumoto b0c1a31961 mruby-bigint: raise Toom-3 threshold from 50 to 100 limbs
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>
2026-01-15 14:46:00 +09:00
Yukihiro "Matz" Matsumoto 0220ec2b62 mruby-bigint: add balance multiplication for asymmetric operands
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>
2026-01-15 14:37:18 +09:00
Yukihiro "Matz" Matsumoto 1fd4cd989b bigint.c: remove redundant mpz_realloc() calls after mpz_init_heap()
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>
2026-01-15 11:51:17 +09:00