mrb_include_module() and mrb_prepend_module() did not invalidate
the constant cache. stale cache entries caused incorrect constant
resolution after include changed the ancestor chain.
Co-authored-by: Claude <noreply@anthropic.com>
mrb_vm_define_module() and mrb_vm_define_class() incorrectly
reopened modules/classes accessible through include rather than
creating new ones. CRuby only reopens modules directly defined
on the outer scope.
the internal define_module()/define_class() use
mrb_const_defined_at() which walks ancestors for Object class.
bypass them and create modules/classes directly in the VM 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>
attr_reader-generated getter methods silently ignored any arguments
passed to them. CRuby raises ArgumentError in this case.
Add mrb_get_args(mrb, "") to enforce zero arguments, matching CRuby.
Since presym is now mandatory, mruby.h includes presym.h so that
MRB_SYM() macros are available everywhere without explicit include.
Remove redundant #include <mruby/presym.h> from all source files.
Co-authored-by: Claude <noreply@anthropic.com>
On 32-bit with MRB_WORDBOX_NO_FLOAT_TRUNCATE, RFloat stores a double
(8-byte alignment) but GC heap slots only guarantee 4-byte alignment.
Use char array + memcpy accessors to avoid misaligned access (SIGBUS
on MIPS, undefined behavior per C standard).
Co-authored-by: Claude <noreply@anthropic.com>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
Previously, removing a ROM method required flattening all chain layers
into a single mutable table. This was O(n) and allocated RAM for all
previously-ROM methods.
Use a tombstone marker (MT_FUNC flag with func=NULL) instead. The
mt_get() lookup treats this as "not found" and stops the chain walk,
hiding the ROM entry while allowing superclass lookup.
Co-authored-by: Claude <noreply@anthropic.com>
Presym is now always enabled. Remove #ifndef MRB_NO_PRESYM
guards and their #else fallback branches from all core files.
Co-authored-by: Claude <noreply@anthropic.com>
Move String's 46 method definitions from runtime
mrb_define_method_id() calls to a static ROM method table
sorted at init time. mrb_mt_init_rom() sorts the parallel
vals/keys arrays by presym ID and sets the readonly flag.
Expose mt_tbl and related types in internal.h so ROM tables
can be defined in individual source files.
When MRB_NO_PRESYM is defined, falls back to traditional
runtime method registration.
Co-authored-by: Claude <noreply@anthropic.com>
Add next pointer and readonly flag to mt_tbl struct to support
chained ROM method table layers. mt_get() walks the chain,
mt_copy() shares ROM layers, mt_free() and mrb_gc_mark_mt() skip
readonly layers. COW in mrb_define_method_raw() creates a mutable
top layer when the existing table is readonly. mt_flatten() merges
all layers for the rare remove_method case.
No ROM tables exist yet -- all tables have next==NULL and no
readonly flag, so behavior is identical to the previous code.
Co-authored-by: Claude <noreply@anthropic.com>
Replace lossy 2-bit truncation with rotation-based encoding for
64-bit word boxing with float64. The new scheme uses
rotl64(float_bits - ADDEND, 3) to embed floats inline with full
52-bit mantissa precision. Floats with exponents outside [-255,+256]
(0.0, NaN, Inf, very small/large values) fall back to heap-allocated
RFloat.
Co-authored-by: Claude <noreply@anthropic.com>
remove per-object gcnext pointer from MRB_OBJECT_HEADER, saving one
word (8 bytes on 64-bit) per object slot. the gray list for tri-color
marking is replaced by a fixed-size stack (MRB_GRAY_STACK_SIZE=1024)
in mrb_gc. when the stack overflows, a linear heap rescan recovers
gray objects.
object slot size: 48 -> 40 bytes (16.7% reduction on 64-bit).
benchmarks show up to 12% RSS reduction on object-heavy workloads
with neutral performance impact.
Co-authored-by: Claude <noreply@anthropic.com>
Same reasoning as the vm.c change - the keyword hash arriving at
C functions via mrb_get_args() is always freshly constructed at the
call site, so duplication is unnecessary.
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>
Replace XML-style markup tags in comments with markdown equivalents:
- <code>...</code> to `...` (inline code)
- <tt>...</tt> to `...` (teletype/monospace)
- <i>...</i> to *...* (italics/emphasis)
- +...+ to `...` (parameter/variable references)
Updated 80+ files across core source, headers, mrbgems, and libraries
to use consistent markdown formatting in documentation comments.
Handled edge cases including special characters like <=> operators.
Co-authored-by: Atlassian Rovo Dev
Add comprehensive call-seq comments for Ruby methods including include,
prepend, ancestors, and extend. Add brief comments for internal helper
functions including method table operations, class setup, and singleton
class management.
Remove doxygen-style parameter documentation and replace with concise
helper function comments to improve code readability and maintainability.
Co-authored-by: Atlassian Rovo Dev
The purpose is to force the setting of the type tag.
This is in preparation for subsequent commits that will prevent the creation of instances with `MRB_TT_FALSE`.
During mrb_state initialization, especially when defining core classes and methods,
the method cache is repeatedly cleared. This causes significant overhead in
scenarios like mrbtest where mrb_state is initialized multiple times.
This commit introduces a `bootstrapping` flag in `struct mrb_state`.
When this flag is TRUE (during mrb_open_core), method cache clears
triggered by `mrb_define_method_raw` and `include_module_at` are suppressed.
The cache is cleared only once at the very end of `mrb_open_core` after
all core methods are defined, and the flag is then set to FALSE.
This optimization significantly reduces the number of method cache clears
during initialization, improving performance for repeated mrb_state creations.
Co-authored-by: Gemini <gemini@google.com>
This commit introduces memory prefetching to the `bsearch_idx` functions
in `src/class.c` and `src/variable.c` to improve performance.
A new macro `MRB_MEM_PREFETCH` is defined in `include/mruby/variable.h`
which uses `__builtin_prefetch` if available.
Co-authored-by: Gemini <gemini@google.com>
Fixes a null pointer dereference in `find_visibility_scope` when defining a
singleton method inside `instance_eval`.
This was caused by `ci->u.env` being `NULL` in this context. The fix adds a
`NULL` check to prevent the crash.
Co-authored-by: Gemini <gemini@google.com>
This commit replaces the method table search algorithm with a
branch-free binary search. This avoids conditional branches,
which can prevent CPU pipeline stalls from branch misprediction,
leading to faster method lookups.
The new `bsearch_idx` function is used for finding, inserting,
and deleting methods in the method table.
This commit adds C-style block comments to all MRB_API functions
defined in the src/class.c file. The comments explain the purpose
of each function, its parameters, and its return value, aiming to
improve code readability and maintainability.
The sorted array binary search implementation no longer uses the inline
cache array, so remove all MRB_INLINE_METHOD_CACHE definitions and
related code.
By replacing the open‐addressing hash with a sorted array and binary
search, we eliminate tombstone management and improve cache locality of
method entries. This preserves the original contiguous values+keys
layout and peak memory usage, while simplifying growth logic and
delivering lookup performance gains.
My previous attempts to improve method table (mt_tbl) performance by introducing a load factor and adjusting the initial allocation size unfortunately led to undesirable increases in memory consumption.
Given that memory usage is a primary concern, I've reverted the following changes:
- Removed the load factor based rehashing logic.
- Removed the related definitions for the load factor.
- Ensured the initial allocation size is 8.
This restores the method table to its original behavior, where it rehashes only when the table is completely full or during initial allocation. This should bring memory usage back to its baseline level prior to these optimization attempts.
The method table (mt_tbl) in src/class.c previously only rehashed when it became completely full. With linear probing, this could lead to significant performance degradation for lookups and insertions as the table approached full capacity.
This change introduces a load factor (MT_LOAD_FACTOR_NUM/MT_LOAD_FACTOR_DEN, set to 3/4 or 0.75). The mt_put function now checks if adding a new element would cause the table's size to meet or exceed this load factor relative to its allocated capacity. If so, it triggers a rehash before inserting the new element.
This helps maintain more empty slots in the hash table, improving the average-case performance of linear probing and reducing the likelihood of worst-case scenarios. The existing initial allocation size and doubling strategy for rehashing are retained.