From 1c7b9b1f267bbaf796cf38aa824bf072b083710b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 27 Feb 2026 18:36:09 +0900 Subject: [PATCH] architecture.md: add cross-references to standalone internal docs Replace duplicated GC, compiler, and VM details with concise summaries linking to gc.md, compiler.md, and vm.md. Co-authored-by: Claude --- doc/internal/architecture.md | 191 ++++++++--------------------------- 1 file changed, 40 insertions(+), 151 deletions(-) diff --git a/doc/internal/architecture.md b/doc/internal/architecture.md index dadccdcf8..b57e95561 100644 --- a/doc/internal/architecture.md +++ b/doc/internal/architecture.md @@ -51,172 +51,61 @@ Objects must fit within 5 words (`mrb_static_assert_object_size`). ## Virtual Machine -### Execution Context +The VM is register-based, using two stacks: a **value stack** for +registers (locals, temporaries, arguments) and a **call info stack** +for tracking method/block call frames. Each method call pushes a +`mrb_callinfo` frame with the method symbol, proc, PC, and argument +counts. -The VM uses two stacks stored in `mrb_context`: +The dispatch loop in `mrb_vm_run()` decodes opcodes and operates on +registers. Method dispatch looks up the receiver's class method table +(with a per-state method cache), then either calls a C function +directly or pushes a new call frame for Ruby methods. -```text -mrb_context -├── stbase..stend value stack (mrb_value[]) -├── cibase..ciend call info stack (mrb_callinfo[]) -├── ci current call frame (→ cibase[n]) -└── status fiber state -``` +Exception handling uses `setjmp`/`longjmp` (or C++ exceptions if +configured). Rescue/ensure handler tables are stored in each irep +and searched during stack unwinding. -Each method call pushes a `mrb_callinfo` frame: - -```text -mrb_callinfo -├── mid method symbol -├── proc current RProc -├── stack pointer into value stack -├── pc program counter (bytecode position) -├── n, nk argument counts -├── cci nonzero if called from C -└── u.env / u.target_class -``` - -The value stack is register-based: local variables and temporaries -occupy fixed register slots (determined at compile time by `nregs`). - -### Dispatch Loop - -The main loop in `mrb_vm_run()` (`src/vm.c`) decodes and dispatches -opcodes. Each opcode operates on registers: - -```text -OP_MOVE R(a) = R(b) -OP_LOADI R(a) = integer -OP_ADD R(a) = R(a) + R(a+1) -OP_SEND R(a) = call R(a).method(R(a+1)..R(a+n)) -OP_RETURN return R(a) -``` - -See [opcode.md](opcode.md) for the full instruction set. - -### Method Dispatch - -When `OP_SEND` executes: - -1. Look up method in receiver's class method table (`mt`) -2. Walk superclass chain if not found -3. If method is a C function (`MRB_METHOD_CFUNC_P`), call directly -4. If method is Ruby (irep-based), push new `mrb_callinfo` and jump - -Method tables use a hash map (`mrb_mt_tbl`). A per-state method cache -speeds up repeated lookups. - -### Exception Handling - -mruby uses `setjmp`/`longjmp` for exception unwinding (or C++ exceptions -if `enable_cxx_exception` is configured). The `rescue`/`ensure` entries -are tracked in `mrb_callinfo` entries and unwound when an exception -propagates. +See [vm.md](vm.md) for detailed VM internals, [opcode.md](opcode.md) +for the full instruction set. ## Garbage Collector -### Tri-Color Mark-and-Sweep +The GC uses **tri-color incremental mark-and-sweep** with an optional +**generational mode**. Objects are colored white (unmarked), gray +(marked, children pending), black (fully marked), or red (static/ROM). -The GC uses tri-color marking with incremental execution: +The three-phase cycle (root scan, incremental marking, sweep) runs +in small steps between VM instructions to avoid long pauses. Write +barriers (`mrb_field_write_barrier`, `mrb_write_barrier`) maintain +correctness during incremental marking. -| Color | Meaning | -| ----- | ------- | -| White | Unmarked — candidate for collection | -| Gray | Marked but children not yet scanned | -| Black | Fully marked (reachable) | -| Red | Static/ROM — never collected | +The GC arena protects newly created objects in C code. Heap regions +(`mrb_gc_add_region`) support embedded systems with fixed memory banks. -### GC Phases - -```text -GC_STATE_ROOT → GC_STATE_MARK → GC_STATE_SWEEP → GC_STATE_ROOT -``` - -1. **Root marking**: marks objects directly reachable from the VM - (stack, globals, arena) -2. **Incremental marking**: processes gray objects from `gray_stack[]`, - marking their children. Runs in small steps between VM instructions. -3. **Sweep**: iterates heap pages, freeing white objects and flipping - the white bit for the next cycle - -### Write Barriers - -When a black object stores a reference to a white object, a write -barrier is required to prevent premature collection: - -```c -mrb_field_write_barrier(mrb, parent, child); /* specific field */ -mrb_write_barrier(mrb, obj); /* general */ -``` - -The barrier paints the parent gray, adding it back to the scan queue. - -### GC Arena - -The arena (`gc.arena[]`) protects newly created objects from collection -before they are stored in a reachable location. C extensions must save -and restore the arena index when creating many temporary objects: - -```c -int ai = mrb_gc_arena_save(mrb); -/* ... create temporary objects ... */ -mrb_gc_arena_restore(mrb, ai); -``` - -See [../guides/gc-arena-howto.md](../guides/gc-arena-howto.md) for details. - -### Heap Structure - -Objects are allocated from fixed-size heap pages (`HEAP_PAGE_SIZE` -objects per page). Each page maintains a freelist of available slots. -Dead objects are returned to their page's freelist during sweep. - -The `mrb_gc_add_region()` API allows pre-allocating contiguous heap -regions for reduced fragmentation and faster allocation. - -### Generational Mode - -Optional generational GC (`mrb_gc_generational_mode_set`) treats -objects surviving a full GC as "old generation" and performs minor -collections that only scan young objects. +See [gc.md](gc.md) for detailed GC internals, +[../guides/gc-arena-howto.md](../guides/gc-arena-howto.md) for arena +usage patterns, [../guides/memory.md](../guides/memory.md) for memory +management. ## Compiler Pipeline -### Stage 1: Parser (`mrbgems/mruby-compiler/core/parse.y`) +The compiler transforms Ruby source code through three stages: -The yacc/bison grammar (~16K lines) produces an AST of `mrb_ast_node` -linked structures. The parser tracks lexer state (expression context, -heredocs, string interpolation) and local variable scopes. +1. **Parser** (`parse.y`): Lrama/Bison grammar produces an AST of + `mrb_ast_node` structures, tracking lexer state and local scopes. +2. **Code Generator** (`codegen.c`): walks the AST and emits bytecode + into `mrb_irep` structures (instruction sequence, literal pool, + symbol table, child ireps). +3. **Execution**: the irep is wrapped in an `RProc` and executed by + the VM, or serialized to `.mrb` binary format. -### Stage 2: Code Generator (`mrbgems/mruby-compiler/core/codegen.c`) +Alternative loading paths include `mrb_load_string()` (compile and +run), `mrb_load_irep()` (load precompiled bytecode), and `mrbc` +(ahead-of-time compilation). -Walks the AST and emits bytecode into `mrb_irep` structures: - -```text -mrb_irep -├── iseq[] instruction stream (bytecode) -├── pool[] constant pool (strings, numbers) -├── syms[] symbol table (method names, variable names) -├── reps[] child ireps (nested methods, blocks) -├── nlocals local variable count -└── nregs register count (locals + temporaries) -``` - -The code generator: - -- Assigns register slots for local variables and temporaries -- Emits instructions for each AST node type -- Builds jump tables for control flow (if/unless/while/for) -- Encodes exception handler ranges for rescue/ensure - -### Stage 3: Execution - -The irep is wrapped in an `RProc` and executed by the VM. Alternative -loading paths: - -- `mrb_load_string()` — compile from source and execute -- `mrb_load_irep()` — load precompiled `.mrb` bytecode -- `mrbc` tool — ahead-of-time compilation to `.mrb` or C array +See [compiler.md](compiler.md) for detailed compiler internals, +[opcode.md](opcode.md) for the instruction set. ## Source File Map