This commit introduces the core infrastructure for variable-sized AST
nodes, designed to improve memory efficiency. The previous fixed-size
nodes are replaced by nodes that can store data inline, such as
strings and integers, reducing pointer indirection and memory overhead.
Key changes include:
- A generic variable-sized node header (`mrb_ast_var_header`).
- A size-class-based memory allocation system for these nodes.
- Implementation of variable-sized nodes for core types: symbols,
strings, integers, and variables (lvar, gvar, ivar, cvar).
- Integration into the parser and code generator, controlled by a
feature flag.
- Centralized and improved type-casting macros for AST nodes.
Co-authored-by: Claude <noreply@anthropic.com>
This implements a memory optimization for AST nodes that stores location
information (lineno, filename_index) only in head nodes rather than in
every node, reducing memory usage for structure nodes.
Key changes:
- Split node types: mrb_ast_node (structure nodes without location),
mrb_ast_head_node (with location info). Sizes are platform-dependent:
8/12 bytes on 32-bit, 16/24 bytes on 64-bit platforms
- Separate allocation: cons() creates structure nodes, cons_head()
creates head nodes with location information
- Node recycling: all nodes are recycled when freed, but only smaller
structure nodes are reused from the free list to maintain type safety
- Updated macro: added headn() for consistent head node casting
- Removed NODE_LINENO macro: eliminated redundant location copying
since head-only optimization already provides adequate location info
- Fixed codegen to properly access location fields via head node casts
This optimization reduces AST memory usage while preserving all
debugging and location information functionality.
Co-authored-by: Claude <noreply@anthropic.com>
Add helper functions to reduce code duplication in codegen load operations:
- gen_load_op1/gen_load_op2: for simple literal load operations following
the pattern "if (!val) return; genop_X(...); push();"
- gen_load_nil: for conditional nil loading with "if (!val) return;" check
- gen_load_lit: for literal loading with push
Refactor 8 literal loading functions (codegen_self, codegen_nil, codegen_true,
codegen_false, codegen_sym, codegen_float, codegen_back_ref, codegen_nth_ref)
and multiple inline nil loading patterns throughout codegen.c.
Each refactored function reduced from 5-8 lines to 2-4 lines while maintaining
identical bytecode generation behavior. All 1730 tests pass.
Co-authored-by: Claude <noreply@anthropic.com>
Extract final complex cases (NODE_OP_ASGN, NODE_MASGN), unify while/until
loop handling, apply early return pattern to reduce indentation, and achieve
complete switch statement consistency.
The original 5000+ line monolithic function is now organized into 60+ focused
functions while preserving all functionality and performance.
Co-Authored-By: Claude <noreply@anthropic.com>
mruby does not provide `begin ... end while cond` that behave at-least-once
loop, like CRuby does. It remains in TODO.md for long time. But finally we have
implemented the behavior.
This commit introduces NODE_BEGIN as a distinct AST node type for
explicit begin...end blocks, separate from NODE_STMTS which represents
general statement sequences. This distinction will be essential for
implementing CRuby-compatible begin...end while/until constructs.
Key changes:
- Added NODE_BEGIN enum in node.h
- Added new_begin() function in parse.y using optimized cons() structure
- Modified begin...end grammar rule to generate NODE_BEGIN nodes
- Added NODE_BEGIN codegen support in codegen.c
- Added NODE_BEGIN to parser dump functionality
NODE_BEGIN uses a simpler cons() structure instead of list2() for
better memory efficiency, as it only contains a single body node.
Co-Authored-By: Claude <noreply@anthropic.com>
Rename NODE_BEGIN to NODE_STMTS to better reflect its purpose as a
container for statement sequences, not specifically begin-end blocks.
This prepares for adding a dedicated node type for explicit begin-end
constructs.
- Rename NODE_BEGIN enum to NODE_STMTS in node.h
- Update all references in parse.y and codegen.c
- Rename new_begin function to new_stmts
Co-Authored-By: Claude <noreply@anthropic.com>
ADDI/SUBI may fall back to method call that may clear block argument
place holder, which may be a live register. So we cannot directly call
ADDI/SUBI over local variables.
OP_LOADI stores an 8 bit integer to a register, so we renamed the
instruction name to describe the behavior more precisely, like
OP_LOADI16 and OP_LOADI32.
Add `OP_NOP` to distinguish `retry` and jump targets while maintaining instruction compatibility.
Ideally, it might be preferable to separate them into `OP_REDO`.
fixed#6439
Recent changes make mrb_irep_remove_lv() used no longer. Removing this
function would not make any compatibility issue, since it's an internal
function.
To avoid confusion with pools in irep, we renamed region-based memory
manager from pool to mempool.
- rename pool.c to mempool.c
- separate mempool.h
- rename all mrb_pool to mrb_mempool
So if someone is using pool.c functions (I suppose no one does though),
they need to rename all `mrb_pool` to `mrb_mempool` and include
`mruby/mempool.h` header at the top.
mrb_pool_value is a structure that represents a value in the irep
literal pool and is unrelated to mrb_pool, which performs region-based
memory management. It has been renamed mrb_irep_pool to avoid confusion.
To mark `MRB_PROC_ORPHAN` we need to keep track of passed block, even
after the assignment to the block argument. And `yield` should use the
original block; #5786, #5791, #6369