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.
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>
When the output and input are the same variable, avoid unnecessary
heap allocations by modifying in place:
- mpz_neg: just flip the sign
- mpz_abs: just make sign positive
- ulshift: use mpn_lshift in-place (safe since it processes high-to-low)
Co-authored-by: Claude <noreply@anthropic.com>
Add mpz_sqr_toom3() that performs Toom-3 squaring with reduced memory
and computation:
- Only evaluates x (not y), reducing evaluation buffer from 6 to 3
- Uses recursive squaring instead of multiplication for all 5 products
- Simplifies interpolation since squared values are always positive
The specialized squaring uses the same Toom-3 structure but avoids
redundant computation when both operands are the same number.
Co-authored-by: Claude <noreply@anthropic.com>
The mpn_divexact_3 function used ap[i] in the borrow computation after
writing to rp[i]. When rp == ap (in-place operation), this read the
modified value instead of the original input, causing incorrect borrow
propagation.
This bug caused Toom-3 multiplication to produce wrong results for
certain input patterns where t6 - t5 had non-zero values followed by
zeros. The corrupted r3 coefficient then propagated errors to the final
result.
Fix by saving the original ap[i] value before writing rp[i].
Co-authored-by: Claude <noreply@anthropic.com>
move in-place optimization directly into mpz_sub() so callers
just use mpz_sub(ctx, x, x, y) and get automatic optimization.
remove separate mpz_sub_inplace() function.
Co-authored-by: Claude <noreply@anthropic.com>
when destination equals source in mpz_div_2exp(), use memmove
and mpn_rshift in-place instead of allocating a temporary.
reduces sqrt allocations by 49% since Newton iteration uses
in-place division by 2 on each iteration.
Co-authored-by: Claude <noreply@anthropic.com>
add usub_inplace() and mpz_sub_inplace() for allocation-free
subtraction when the minuend is larger than the subtrahend.
apply to Mersenne multiplication which reduces allocations by
17% and improves performance by 7-9% for small numbers.
Co-authored-by: Claude <noreply@anthropic.com>
skip two's complement conversion in mpz_and, mpz_or, mpz_xor when both
operands are positive. this avoids the per-limb make_2comp overhead and
provides up to 1.6x speedup for large bigints.
Co-authored-by: Claude <noreply@anthropic.com>
convert mpz_init_heap to mpz_init_temp for temporary quotient and
remainder variables in div_limb. these variables are now allocated
from the memory pool when possible, reducing heap allocation overhead.
the div_limb function already uses pool_save/pool_restore, so these
temporary variables are proper candidates for pool allocation.
Co-authored-by: Claude <noreply@anthropic.com>
when the allocator can extend the block in place, realloc avoids
the overhead of malloc+memcpy+free. the keys are moved to their
new position with memmove and extended regions are cleared.
Co-authored-by: Claude <noreply@anthropic.com>
saves 40% memory (60 -> 36 bytes) for objects with 1-2 instance
variables, which is common for simple value objects like Point(@x, @y).
the trade-off is one extra reallocation when growing from 2 to 4 IVs,
but this is negligible since reallocations are rare compared to lookups.
Co-authored-by: Claude <noreply@anthropic.com>
Replace Karatsuba multiplication (O(n^1.585)) with Toom-3 (O(n^1.465))
for large number multiplication. Toom-3 splits numbers into thirds and
evaluates at 5 points, providing better asymptotic performance.
Threshold is 50 limbs (~1600 bits). For operands below threshold or
highly asymmetric sizes, schoolbook multiplication is used.
Co-authored-by: Claude <noreply@anthropic.com>
Remove automatic downgrade to 16-bit limbs on 32-bit Windows.
Modern compilers (including MSVC) have supported uint64_t for decades.
MRB_NO_MPZ64BIT remains available for constrained platforms.
Adjust BATCH_DIVISOR and BATCH_DIGITS for 16-bit limb compatibility:
- 32-bit limbs: 10^9 (9 digits per batch)
- 16-bit limbs: 10^4 (4 digits per batch)
Co-authored-by: Claude <noreply@anthropic.com>
Add trim() after mpz_set in early return paths to prevent propagation
of inflated sz values. When an mpz_t has sz larger than actual allocated
limbs, copying it without trim causes subsequent operations to read
beyond allocated memory.
Fixed functions:
- mpz_add: when one operand is zero
- mpz_neg: when copying operand
- mpz_mod_2exp: when x < 2^e
Co-authored-by: Claude <noreply@anthropic.com>
Document that this header is for mruby core internal use only and
should not be included in user code or mrbgems. When MRB_USE_CXX_EXCEPTION
is defined, C source files including this header fail to compile.
Add example showing mrb_protect_error() as the recommended alternative.
Co-authored-by: Claude <noreply@anthropic.com>
Use mrb_protect_error API instead of direct MRB_TRY/MRB_CATCH to handle
exceptions in mpz_mul_all_ones and mpz_to_s_dc. This maintains C++
compatibility (issue #6702) while ensuring temporary mpz_t allocations
are properly freed even when exceptions occur.
Co-authored-by: Claude <noreply@anthropic.com>
Remove MRB_TRY/MRB_CATCH exception handling from bigint.c to fix
compilation errors when using mruby-bigint in C++ projects with
MRB_USE_CXX_EXCEPTION enabled.
The exception handling was added for cleanup on error, but it requires
throw.h which doesn't work when a C file is compiled in a C++ context
with C++ exceptions enabled. Accepting potential memory leaks on
exception (rare) is preferable to breaking C++ builds.
Fixes#6702
Co-authored-by: Claude <noreply@anthropic.com>
The JMPNOT-to-JMPIF optimization assumed fail_pos always came from a
4-byte JMPNOT instruction. When a pinned variable is undefined,
NODE_PAT_PIN generates a 3-byte OP_JMP instead, causing fail_pos - 2
to point into the previous instruction and corrupt its operand.
Add a check to verify the instruction at fail_pos - 2 is actually
OP_JMPNOT before modifying it.
Fixes#6701
Co-authored-by: Claude <noreply@anthropic.com>
Replace the two-buffer swap pattern in D&C to_s base case with
in-place division using new mpn_div10_9 function. This eliminates
the q_base scratch buffer and reduces per-iteration overhead.
Compilers optimize the constant division by 10^9 to multiplication
and shift operations for better performance.
Co-authored-by: Claude <noreply@anthropic.com>
Replace per-call lo allocation with depth-indexed lo_stack buffers
that are reused across recursion levels. Each buffer is allocated
on first use at that depth with appropriate size.
This reduces 493 malloc/free calls (5%) and 580KB of memory (2%)
for large number to_s conversions while maintaining performance.
Co-authored-by: Claude <noreply@anthropic.com>
Instead of allocating a separate hi buffer for the upper part of the
split, reuse q5 by shifting it in place after extracting the lower
bits to q5_low.
This eliminates one mpz_t allocation per recursive call:
- Extract q5_low = q5 mod 2^k first (copy lower bits)
- Shift q5 right in place (memmove + mpn_rshift) to get hi
- q5 now serves as hi for the recursive call
Benchmark results (2.4M bit number):
- Memory: -3.5% (5.58MB -> 5.38MB peak heap)
- Instructions: -16.5%
- Speed: unchanged (within measurement noise)
Co-authored-by: Claude <noreply@anthropic.com>