Commit Graph

18427 Commits

Author SHA1 Message Date
Yukihiro "Matz" Matsumoto b76d92db2d NEWS.md: add object shapes entry
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-27 08:40:32 +09:00
Yukihiro "Matz" Matsumoto 8d10056aff variable.c: add object shapes for MRB_TT_OBJECT IV storage
Introduce "object shapes" (hidden classes) that share IV key
layouts across objects with the same instance variable assignment
order. This eliminates per-object key storage overhead.

Memory savings: ~22% heap reduction for object-heavy workloads
(e.g., 150k objects with 2-6 IVs). Per-object: 40->24 bytes
for 2 IVs. Objects exceeding 16 IVs or using
remove_instance_variable fall back to traditional iv_tbl.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-27 08:29:46 +09:00
Yukihiro "Matz" Matsumoto b4d2524fb4 NEWS.md: update for mruby 4.0 release
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-26 11:35:38 +09:00
Yukihiro "Matz" Matsumoto bf376a6160 memory.md: document mrb_gc_add_region() heap region API
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-26 08:56:23 +09:00
Yukihiro "Matz" Matsumoto 072855a242 gc.c: add contiguous heap region support (mrb_gc_add_region)
Allow users to provide contiguous memory buffers for GC heap pages
via mrb_gc_add_region(). Region pages are carved from user-owned
buffers and never freed by the GC. This is the foundation for
bitmap GC on embedded targets with fragmented RAM.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-26 08:54:01 +09:00
Yukihiro "Matz" Matsumoto 74fb046544 load.c: consolidate irep allocation for .mrb loading
Pack pool/syms/reps arrays into a single calloc with the irep struct,
reducing 4 allocations per irep to 1. Arrays are ordered by descending
alignment (pool/reps/syms) to eliminate inter-array padding.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-25 15:20:19 +09:00
Yukihiro "Matz" Matsumoto 3c2922a361 rom-method-table.md: fix prettier table formatting
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-25 15:20:03 +09:00
Yukihiro "Matz" Matsumoto 3b9784a263 mlc_config.json: add retry and accept 502 as alive status
GitHub sometimes returns transient 502 errors for valid URLs,
causing false positives in CI markdown link checks.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-25 15:12:57 +09:00
Yukihiro "Matz" Matsumoto 9e0eec3974 mruby-compiler: fix MRB_NO_STDIO build in codegen_pattern()
remove snprintf() call that requires <stdio.h>, which is unavailable
with MRB_NO_STDIO; use a static error message consistent with other
codegen_error() calls.

Fixes #6724.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-25 15:11:27 +09:00
Yukihiro "Matz" Matsumoto 06bce53132 fix build for MRB_NO_BOXING + MRB_INT64 on 32-bit
- array.h: disable embedded arrays when MRB_INT64 makes mrb_value
  too large to embed (fixes MRB_ARY_EMBED_LEN_MAX assertion)
- error.h: enable MRB_USE_RBREAK_VALUE_UNION for all 32-bit
  no-boxing builds (MRB_USE_FLOAT32 is irrelevant without
  word/nan boxing)
- gc.c: restrict RVALUE 8-byte alignment padding to
  MRB_WORD_BOXING builds (fixes RVALUE size assertion)
- vm.c: guard direct ary->as.ary access with MRB_ARY_NO_EMBED

Fixes #6722.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-25 15:10:24 +09:00
Yukihiro "Matz" Matsumoto 8df9a22a85 presym.rake: fix unnecessary full recompilation on single file changes
Restrict .o -> presym.list_path dependency to internal builds only
(mrbc sub-build). Regular host/cross builds don't need this because
:all => :gensym ordering guarantees presym headers exist before .o
compilation, and compiler .d files track header changes.

The broad dependency caused full recompilation because Rake's
all_prerequisite_tasks checks transitive prerequisites: every .o
transitively depended on every .pi file through presym.list_path.

Fixes #6721.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-25 15:10:05 +09:00
Yukihiro "Matz" Matsumoto b9007a8f0a cmdprint.c: extract next_print_no() helper
Consolidate the duplicated print_no increment-and-wrap logic
from dbgcmd_print() and dbgcmd_info_local() into a single
next_print_no() function.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-24 09:05:02 +09:00
Yukihiro "Matz" Matsumoto d3dfe83aa1 apibreak.c: simplify get_break_index()
Return directly from the loop instead of using a hit flag
and separate index variable.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-24 09:04:25 +09:00
Yukihiro "Matz" Matsumoto e35c011537 cmdmisc.c: extract parse_file_line_spec() from parse_listcmd_args()
Flatten 4-level nested parsing of list command arguments into
a separate parse_file_line_spec() function.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-24 09:03:59 +09:00
Yukihiro "Matz" Matsumoto 1d52c7a3dd mrdb.c: extract check_breakpoint_hit() from mrb_code_fetch_hook()
Combine method and line breakpoint checks into a single
check_breakpoint_hit() helper, simplifying the DBG_RUN case.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-24 09:03:28 +09:00
Yukihiro "Matz" Matsumoto 8702244a42 mrdb.c: decompose parse_command() into lookup helpers
Extract find_command_by_word1() and find_command_by_words()
from parse_command(), separating command-table lookup from
tokenization logic.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-24 09:02:47 +09:00
Yukihiro "Matz" Matsumoto eedc95460c mruby-bin-debugger: extract raise_debugger_exception() helper
Both dbgcmd_run() and dbgcmd_quit() defined an exception class
and raised it with identical code. Add a shared static inline
helper in mrdb.h.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-24 09:02:11 +09:00
Yukihiro "Matz" Matsumoto 811741eb8e cmdbreak.c: unify delete/enable/disable via dbgcmd_set_breakpoint()
The three commands shared identical dispatch logic. Extract a
shared dbgcmd_set_breakpoint() that takes function pointers,
reducing each command to a one-line wrapper.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-24 09:01:19 +09:00
Yukihiro "Matz" Matsumoto 2c21e1a959 apibreak.c: extract alloc_breakpoint() helper
Extract common breakpoint slot allocation logic from
mrb_debug_set_break_line() and mrb_debug_set_break_method()
into a shared alloc_breakpoint() helper.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-24 09:00:49 +09:00
Yukihiro "Matz" Matsumoto 9a0e8e33ed mirb: use ISSPACE/ISALNUM from mruby.h, remove stale ctype.h
Remove redundant local ISSPACE/ISALNUM definitions from
mirb_completion.c and unused ctype.h includes from both
mirb_completion.c and mirb.c. The locale-independent macros
from mruby.h are already available via <mruby.h>.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-23 15:49:36 +09:00
Yukihiro "Matz" Matsumoto 48c38c822f mirb_editor.c: table-drive block keywords in calc_indent_level()
Replace the strncmp() if-else chain for block-opening and closing
keywords with a data-driven indent_table, matching the existing
dedent_table pattern. Also use mirb_is_word_char() for the word
boundary check.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-23 15:46:28 +09:00
Yukihiro "Matz" Matsumoto f3dc8d4ae3 mirb_buffer.c: extract buffer_join_line_up() helper
Replace duplicate line-joining logic in mirb_buffer_delete_back()
and mirb_buffer_delete_forward() with a shared helper that appends
a line's content to the previous line, then removes it.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-23 15:35:09 +09:00
Yukihiro "Matz" Matsumoto 0b07cc1381 mirb_buffer.c: extract buffer_ensure_line_cap() helper
Replace three identical 7-line blocks that grow the lines array
with a single buffer_ensure_line_cap() helper function, matching
the existing line_ensure_cap() naming pattern.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-23 14:05:38 +09:00
Yukihiro "Matz" Matsumoto c23536daf9 mirb_completion.c: unify global completion contexts
Replace three separate global contexts (g_readline_ctx,
g_linenoise_ctx, g_editor_ctx) with a single g_ctx and shared
init_completion_ctx() helper. Consolidate the three identical
cleanup functions into mirb_cleanup_completion().

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-23 09:59:02 +09:00
Yukihiro "Matz" Matsumoto 9b24e120bc mirb_editor.c: table-drive is_dedent_keyword()
Replace the if-else chain with a data table that encodes each
dedent keyword, its valid delimiters, and whether it can appear
at end of line.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-23 09:57:06 +09:00
Yukihiro "Matz" Matsumoto d6b06634ec mirb: share is_word_char() and COLOR_RESET across modules
Move is_word_char() to mirb_buffer.h as mirb_is_word_char() static
inline, removing duplicate definitions from mirb_buffer.c and
mirb_highlight.c. Move COLOR_RESET to mirb_highlight.h, removing
the duplicate from mirb_editor.c.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-23 09:53:09 +09:00
Yukihiro "Matz" Matsumoto 9feb47f334 mirb.c: unify cleanup paths in main() using goto
Replace the cleanup() function and duplicated end-of-main cleanup
with a single goto cleanup label. This also fixes a minor resource
leak where cxt was not freed when library loading failed.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-23 08:32:26 +09:00
Yukihiro "Matz" Matsumoto 5394b71a60 mruby-bin-mirb: consolidate duplicate keyword lists
Move the Ruby keyword array from static definitions in both
mirb_highlight.c and mirb_completion.c to a single shared
mirb_keywords[] defined in mirb_highlight.c and declared in
mirb_highlight.h.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-23 08:09:33 +09:00
Yukihiro "Matz" Matsumoto aafa05522d mirb_editor.c: refactor duplicated indent calculation logic
Extract three helpers (calc_expected_indent, adjust_line_indent,
insert_indent_spaces) to eliminate repeated indent computation and
whitespace adjustment code in perform_dedent, reindent_line,
handle_tab_indent, and the Enter key handler.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-23 08:05:04 +09:00
Yukihiro "Matz" Matsumoto 1de46b2051 cdump.c: use IREP_TT_SSTR for pool strings in mrbc -C output
pool strings generated by mrbc -C are C string literals inside
static const structs, which reside in ROM. mark them as
IREP_TT_SSTR (static) instead of IREP_TT_STR (dynamic) so the
VM uses mrb_str_new_static() and mrb_intern_static() instead of
mrb_str_new() and mrb_intern(). this avoids unnecessary
malloc+memcpy for string literals longer than the embed threshold,
especially on embedded platforms where mrb_ro_data_p() returns
FALSE.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-23 00:00:25 +09:00
Yukihiro "Matz" Matsumoto 14a5cfb87f etc.c: lossless rotation encoding for 32-bit float32 word boxing
replace lossy 2-bit truncation with rotation-based encoding for
32-bit + MRB_USE_FLOAT32, matching the technique used for 64-bit
float64. rotl32(bits - ADDEND, 3) maps biased exponents [95, 158]
(actual [-32, +31]) to properly tagged inline values with zero
precision loss. special values (0, Inf, NaN) use sentinel constants;
out-of-range floats fall back to heap-allocated RFloat.

also fix a pre-existing alignment issue: RVALUE was 20 bytes on
32-bit, causing 4-byte-aligned objects to be misidentified as
immediates by word boxing (WORDBOX_IMMEDIATE_MASK=0x07 requires
8-byte alignment). pad RVALUE to 24 bytes on 32-bit + float32.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-22 17:51:01 +09:00
Yukihiro "Matz" Matsumoto 2031ae9f90 random.c: fix rand() with float range producing out-of-range values
rand_range_float() incorrectly added +1.0 to span for inclusive
ranges, logic copied from integer range handling. For float ranges,
the span should simply be end-begin without adjustment.

Fixes #6720.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-21 07:12:52 +09:00
Yukihiro "Matz" Matsumoto 71cb3c2e3a class.c: allocate ROM table wrappers per mrb_state
ROM method tables used static mrb_mt_tbl variables shared
across the process. The next pointer in each wrapper was
mutated by mrb_mt_init_rom(), causing cross-state
contamination when multiple mrb_state instances existed.

Allocate mrb_mt_tbl wrappers per-state via mrb_malloc().
The const mrb_mt_entry[] arrays remain static and shared.
Wrappers are tracked in mrb->rom_mt and freed at mrb_close().

Remove MRB_MT_ROM_TAB macro; add MRB_MT_INIT_ROM macro that
auto-computes size and calls the new mrb_mt_init_rom().

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-20 22:24:31 +09:00
Yukihiro "Matz" Matsumoto 10f36a0cbb class.h: move ROM method table types from internal.h
The ROM table types (mrb_mt_entry, mrb_mt_tbl) and macros
(MRB_MT_ENTRY, MRB_MT_ROM_TAB, etc.) are used by 34 files
across core and gems -- they are part of the public method
registration API, not internal implementation details.
Move them to class.h where the rest of the method table API
lives, eliminating the #ifdef MRUBY_CLASS_H guard that was
needed in internal.h.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-20 17:11:49 +09:00
Yukihiro "Matz" Matsumoto ea938c531f align MRB_MT_ENTRY columns and ISO section comments in ROM tables
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-20 15:02:27 +09:00
Yukihiro "Matz" Matsumoto b460554d33 vm.c: generalize pre-dispatch argument count check for C methods
Replace check_method_noarg() with check_argument_count() that validates
min <= argc <= max using the full aspec stored in mrb_method_t.flags.
This catches ArgumentError earlier at dispatch time, before entering
the C function.

The old check only handled the special case of aspec==0 (NOARG).
The new check extracts REQ, OPT, REST, POST, KEY, and KDICT from
the aspec and validates accordingly. Keyword hash is counted as
a positional arg only when the method doesn't accept keywords.

Remove MRB_METHOD_NOARG_P macro from proc.h (subsumed by aspec check).
Fix 15 incorrect aspec declarations across the codebase that were
exposed by the stricter enforcement.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-20 14:25:48 +09:00
Yukihiro "Matz" Matsumoto 4a097525df proc.h: unify method flag layout; eliminate aspec shifting
Move MRB_METHOD_FUNC_FL to bit 24 and visibility flags to
bits 25-26 so that MRB_ARGS_*() values (bits 0-23) can be
stored directly without shifting. This makes MRB_MT_PRIVATE
and MRB_METHOD_PRIVATE_FL the same value, eliminating the
dual-constant confusion and simplifying the MRB_MT_ENTRY()
macro to a single OR operation.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-20 13:49:17 +09:00
Yukihiro "Matz" Matsumoto ada229d2b0 proc.h: remove MRB_METHOD_NOARG flag; derive from aspec
The NOARG flag (bit 2) is now redundant since the full aspec is
stored in bits 4+ of the flags field. Replace the dedicated bit
check with aspec==0 check. Store aspec in define_method_id() for
dynamically defined methods too.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-20 11:51:59 +09:00
Yukihiro "Matz" Matsumoto 483c155a41 class.c: store aspec in ROM method table entries
Restore MRB_ARGS_* argument specs and ISO section comments to all
709 ROM method table entries. The aspec is encoded in bits 4-27 of
the flags field; MRB_MT_NOARG is now auto-derived from aspec==0.

Add MRB_MT_ENTRY_PRIVATE() macro for private methods (53 entries)
and MRB_MT_ASPEC() accessor for extracting aspec from flags.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-20 11:44:28 +09:00
Yukihiro "Matz" Matsumoto 20b9002214 class.c: merge conditional methods into ROM tables
Move conditional mrb_define_method_id() calls into ROM entry
arrays using #ifdef guards. With linear search, sizeof in
MRB_MT_ROM_TAB() adjusts automatically after preprocessing.

Cross-class ROM tables (methods a gem defines on a class it does
not own) are reverted to mrb_define_method_id(). Multiple gems
should not add ROM table layers to the same class; each layer
costs a 16-byte mrb_mt_tbl struct in RAM and deepens the lookup
chain. Use mrb_define_method_id() for cross-class methods.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-20 11:05:03 +09:00
Yukihiro "Matz" Matsumoto 8adba34bd9 class.c: auto-set MRB_MT_FUNC in MRB_MT_ENTRY macro
Since ROM table entries are always C functions, have the
MRB_MT_ENTRY() macro set MRB_MT_FUNC automatically. This
simplifies entry definitions across all 32 source files.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-20 10:37:06 +09:00
Yukihiro "Matz" Matsumoto 0fab703028 class.c: use linear search for method tables; make ROM entries const
Replace binary search with linear scan in mt_get(), mt_put(),
mt_del(), mt_chain_has(), and mrb_mt_foreach(). The method cache
makes repeated lookups O(1), so linear scan on cache misses is
acceptable.

This removes the sorting requirement, allowing ROM entry arrays
to be declared const. On embedded systems, const static data
resides in flash/ROM instead of RAM, saving ~8.4KB for ~700
method entries on 32-bit MCUs.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-20 08:26:05 +09:00
Yukihiro "Matz" Matsumoto ce8ce3f96d class.c: separate flags from symbol key in mrb_mt_entry
Add a dedicated uint32_t flags field to mrb_mt_entry instead of
packing flags into the lower bits of mrb_sym via MRB_MT_KEY().
The key field now stores the pure symbol ID with no shift.

On 64-bit, the flags field fills the alignment gap after mrb_sym,
so entry size remains 16 bytes (zero overhead). On 32-bit, entry
size grows from 8 to 12 bytes.

This eliminates the risk of symbol ID overflow from the 4-bit
shift, and the flags field can later store aspec (MRB_ARGS_*)
information that was previously discarded.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-20 07:57:02 +09:00
Yukihiro "Matz" Matsumoto bde2202100 class.c: refactor ROM method tables to array-of-structs layout
Replace the parallel-arrays (struct-of-arrays) ROM method table
layout with an array-of-structs layout where each mrb_mt_entry
bundles its function pointer and symbol key together.

New MRB_MT_ENTRY() and MRB_MT_ROM_TAB() macros simplify ROM table
definitions from a 3-part pattern (SIZE define + anonymous struct +
mrb_mt_tbl) to a 2-part pattern (entries array + mrb_mt_tbl).

Internal mt_* functions in class.c are simplified: single memmove/
memcpy operations replace paired key+value operations.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-19 23:59:30 +09:00
Yukihiro "Matz" Matsumoto cfd9214b3d class.c: add MRB_MT_FROZEN_BIT for method table layers
When mrb_mt_init_rom() is called on a class that already has a
mutable method table (from prior mrb_define_method_id() calls),
the mutable top layer is now frozen in place instead of being
left as a writable layer that wastes RAM on embedded systems.

The frozen bit (bit 29 of alloc field) marks heap-allocated
method table layers as temporarily immutable. Unlike the
readonly bit (bit 30, for true ROM), frozen layers are
automatically unfrozen when methods are later added via
mrb_define_method_raw() or removed via mrb_remove_method().
This preserves the c->mt pointer, which is critical because
iclasses (from module inclusion) hold a copy of it.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-19 23:25:16 +09:00
Yukihiro "Matz" Matsumoto a208440c4f numeric.c: fix SEGV in int_divmod when argument is not numeric
int_divmod passed an integer mrb_value directly to flo_divmod, which
used mrb_float() to extract the value. In word boxing mode, this caused
a misaligned pointer dereference. Use mrb_ensure_float_type() to safely
convert the integer to float before passing to flo_divmod.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-19 20:31:45 +09:00
Yukihiro "Matz" Matsumoto a1ee420aea test/t/syntax.rb: add test for &nil in formal parameters
Co-authored-by: Claude <noreply@anthropic.com>
2026-02-19 17:26:04 +09:00
Yukihiro "Matz" Matsumoto b07518e85c parse.y: implement &nil in formal parameters
`&nil` is recently introduced in CRuby to explicitly declare that
a method does not accept a block. When a block is passed,
ArgumentError "no block accepted" is raised. This is analogous to
`**nil` for keyword arguments.

The noblock flag is encoded in bit 23 of OP_ENTER's aspec operand
(24=n1:m5:o5:r1:m5:k5:d1:b1), avoiding the need for a new opcode.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-19 16:54:17 +09:00
Yukihiro "Matz" Matsumoto 337cf4bfd5 etc.c: fix undefined behavior in WORDBOX_FLOAT_ADDEND
Left-shifting a negative int64_t is undefined behavior in C.
Cast to uint64_t before the shift to produce the same bit pattern
using well-defined unsigned arithmetic.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-19 15:44:54 +09:00
Yukihiro "Matz" Matsumoto 0ed26f8352 class.c: rename mt_/MT_ to mrb_mt_/MRB_MT_ for non-static identifiers
Follow mruby's naming convention: non-static types, macros, and
functions use the mrb_/MRB_ prefix. Renamed:
- union mt_ptr -> union mrb_mt_ptr
- mt_tbl -> mrb_mt_tbl
- MT_KEY(), MT_FUNC, MT_NOARG, MT_PUBLIC, MT_PRIVATE -> MRB_MT_*
- MT_KEY_SHIFT, MT_READONLY_BIT, MT_REMOVED_P -> MRB_MT_*
- mt_init_rom() -> mrb_mt_init_rom()
File-local static functions and macros in class.c are unchanged.

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-19 15:22:55 +09:00