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>
The previous code computed `frac_part * pow10_negative[n]`, where
pow10_negative[n] is already a rounded approximation of 10^-n (since
10^-n is not exactly representable in binary). The multiplication then
adds another rounding step, leaving up to ~1 ulp of error.
Dividing `frac_part` by `pow10_positive[n]` is exact for n <= 22 (the
range where 10^n fits exactly in a double), so the division is the
only rounding and the result is correctly rounded. For example,
"0.3".to_f now matches the 0.3 literal's bit pattern (and libc strtod).
build_config/host-cxx.rb defaulted to MRuby::Build.new (no name),
which is equivalent to MRuby::Build.new('host'), so it shared
build/host/ with build_config/host-debug.rb.
The two configs produce ABI-incompatible object files (C linkage
vs. C++-mangled). Switching between configs without a clean step
silently mixes stale objects, leading to confusing undefined
reference errors at link time.
Name the C++ build 'host-cxx' so it gets its own build/host-cxx/
directory. No external paths reference build/host/ in a way that
this change would break.
Co-authored-by: Claude <noreply@anthropic.com>
MPZ_CTX_INIT used a compound literal with designated initializers:
mpz_ctx_t ctx##_struct = ((mpz_ctx_t){.mrb = ..., .pool = ...});
Both features are C99-only, and are not accepted by legacy C++
compilers (notably gcc 4.x) when mruby is pulled into a C++
translation unit via the -cxx.cxx wrapper.
Replace with plain member assignment so the macro expands to code
that is valid under C89/C++98 as well.
Co-authored-by: Claude <noreply@anthropic.com>
Older C++ compilers (notably gcc 4.x) do not support C99 struct field
designators (.func = ...) even as an extension, which blocks building
mruby when it is included from a C++ translation unit under such
toolchains.
Reorder union mrb_mt_ptr so that mrb_func_t is the first member, and
switch MRB_MT_ENTRY to positional aggregate initialization. Both are
compatible with pre-C99 / pre-C++20 compilers.
Fixes#6789
Co-authored-by: Claude <noreply@anthropic.com>
`mrb_class_get_id()` may call the `#const_missing` method.
Therefore, if the `mesg` string originates from a string object, it may reference an invalid address.
And since `errno` might also change during the call to `#const_missing`, save this as well beforehand.
Also, while `mrb_class_defined_id()` does not currently call the `#const_defined?` method, it is unclear whether this will remain the case in the future.
Compress the 24-bit aspec into 13 free flag bits on RProc (bits 0-6
and 14-19) when wrapping cfunc methods. Field widths: req/opt 3 bits
(max 7), post/key 2 bits (max 3), rest/kdict/block 1 bit each. Values
exceeding the compressed range are clamped and rest is forced to 1.
This enables Proc#arity and Proc#parameters to return correct results
for cfunc-backed Procs (e.g. from Method#to_proc) with zero memory
overhead -- no struct change needed.
Closes#6764