Skip to content

Commit 848a2ca

Browse files
authored
Refinements, lexical-scope reflection, and definition-site line numbers (#1064)
1 parent 17fbf38 commit 848a2ca

30 files changed

Lines changed: 3264 additions & 315 deletions

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ monoruby/ # Workspace root
8787
│ ├── refresh-prism-vendored # Rebuild/force-push the prism vendored branch
8888
│ └── irm # Launch REPL (cargo run --bin irm)
8989
├── doc/ # Architecture documentation
90+
│ ├── README.md # Index of every document, with kind + language
9091
│ ├── jit.md # JIT stub code details
9192
│ ├── method_args.md # Method argument handling
9293
│ └── progress_2025-2026.md # Progress notes

doc/README.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# `doc/` — index
2+
3+
Design records and implementation notes for monoruby's runtime. Start
4+
here; `CLAUDE.md` at the repository root covers the layout, the build and
5+
the conventions, and points back into this directory for anything deeper.
6+
7+
Two things to know before reading:
8+
9+
- **Language.** Some documents are written in Japanese and some in
10+
English; the table below says which.
11+
- **Kind.** A document is one of three things, and they age differently:
12+
- **reference** — describes what the code does now, and is kept in step
13+
with it. Trust it, and update it when you change the subsystem.
14+
- **design record** — why a subsystem is shaped the way it is, with the
15+
measurements and the rejected alternatives. Still true about the
16+
*reasoning* even where the code has moved on.
17+
- **plan / history** — a proposal or a snapshot in time. Read for
18+
context, not as a description of the present.
19+
20+
---
21+
22+
## Execution core
23+
24+
| Document | Lang | Kind | Answers |
25+
|---|---|---|---|
26+
| [`stack_frame.md`](stack_frame.md) | EN | reference | What a local frame looks like in memory: LFP / CFP offsets, where `self`, the block and the registers sit. |
27+
| [`method_args.md`](method_args.md) | JA | reference | What `pos_num`, `req_num`, `optional`, `rest` actually count, and what they exclude. |
28+
| [`native_func.md`](native_func.md) | EN | reference | How to declare a builtin that takes optional / rest / keyword parameters. |
29+
| [`super_resolution.md`](super_resolution.md) | JA | design record | The two non-obvious questions `super` has to answer — *which* name, and *which* position in the chain — and how monoruby answers them from the frame rather than from a method entry. |
30+
| [`exception_handling.md`](exception_handling.md) | EN | reference | Raise, unwind, catch and report, and where monoruby is deliberately lazier than CRuby (backtraces are not formatted until asked for). |
31+
| [`cref.md`](cref.md) | EN | reference | The lexical state that is not local variables: default definee, constant scopes, `Module.nesting`, visibility toggles. Contrasts CRuby's per-frame CREF with monoruby's stack. |
32+
| [`refinements.md`](refinements.md) | EN | design record | What refinements do to method resolution, why every cache in the tree was keyed without the caller's scope, and the interned-set design that adds them without costing a refinement-free program anything. |
33+
34+
## Codegen and IR
35+
36+
| Document | Lang | Kind | Answers |
37+
|---|---|---|---|
38+
| [`jit.md`](jit.md) | EN | reference | The stub a method starts life behind, and how it is rewritten as the method goes from cold to compiled. |
39+
| [`inline.md`](inline.md) | EN | reference | Inline asm builtins: emitting a method's body straight into the caller instead of dispatching, and trial-inlining. |
40+
| [`lir.md`](lir.md) | EN | design record | The arch-neutral machine-level IR between `AsmIR` and per-arch emission — the design and the migration log. |
41+
| [`regalloc_separation.md`](regalloc_separation.md) | EN | design record | Separating the abstract interpreter from register allocation. The largest document here; the structural groundwork the LIR work builds on. |
42+
| [`arch_difference.md`](arch_difference.md) | EN | reference | How the x86-64 and aarch64 backends differ, `AsmInst` by `AsmInst`. Read before touching either. |
43+
| [`arg_forwarding_jit.md`](arg_forwarding_jit.md) | JA | design record | JIT strategy for `def f(a, ...) g(...) end`, staged, with the deopt-safety argument. |
44+
| [`handoff_record_stream.md`](handoff_record_stream.md) | EN | plan / history | Handoff note for the record-driven lowering work; a summary of `regalloc_separation.md` §12–21 as of that branch. |
45+
46+
## Runtime services
47+
48+
| Document | Lang | Kind | Answers |
49+
|---|---|---|---|
50+
| [`safepoint.md`](safepoint.md) | JA | reference | The one mechanism GC, preemption and signal delivery all go through. Read this before any of the three below. |
51+
| [`gc.md`](gc.md) | JA | reference | The collector as it actually is — non-moving, single-threaded, stop-the-world, generational — plus the `GC` module's real numbers. |
52+
| [`signal.md`](signal.md) | JA | reference | Deferred signal delivery: set a flag, convert it to a Ruby exception or a `Signal.trap` handler at the next safepoint. |
53+
| [`threads.md`](threads.md) | JA | reference | M:1 green threads, Fibers, non-blocking IO and time-slice preemption. |
54+
| [`scheduler_state_diagram.md`](scheduler_state_diagram.md) | JA | reference | `ThreadState` and `FiberState` transitions — the companion diagrams to `threads.md`. |
55+
56+
Diagrams referenced by the above: [`fiber_state_diagram.svg`](fiber_state_diagram.svg),
57+
[`thread_state_diagram.svg`](thread_state_diagram.svg),
58+
[`gc_state_transitions.svg`](gc_state_transitions.svg),
59+
[`gc_write_barrier.svg`](gc_write_barrier.svg).
60+
61+
## Strings and encodings
62+
63+
| Document | Lang | Kind | Answers |
64+
|---|---|---|---|
65+
| [`encoding_char_iteration_design.md`](encoding_char_iteration_design.md) | EN | plan | Removing the "every String is UTF-8" assumption via a per-encoding character-boundary layer. Marked *proposed*. |
66+
67+
## Compatibility and performance
68+
69+
| Document | Lang | Kind | Answers |
70+
|---|---|---|---|
71+
| [`ruby_spec_skip_tags.md`](ruby_spec_skip_tags.md) | JA | reference | How the ruby/spec suite avoids hangs, and the audit that cut a coarse file-level skip list down to the handful that genuinely cannot run. |
72+
| [`optcarrot_opt_profile.md`](optcarrot_opt_profile.md) | JA | design record | Where `bin/optcarrot --opt` spends its time, measured with `perf` and `--features profile`, and the optimizations that came out of it. |
73+
74+
## Plans and history
75+
76+
| Document | Lang | Kind | Answers |
77+
|---|---|---|---|
78+
| [`c_extention.md`](c_extention.md) | JA | plan | Design study for loading CRuby C extensions (`.so`). |
79+
| [`plan-activerecord.md`](plan-activerecord.md) | JA | plan | Staged plan for running ActiveRecord, and what it depends on. |
80+
| [`progress_2025-2026.md`](progress_2025-2026.md) | EN | history | What changed over ~500 commits, April 2025 to April 2026. |
81+
82+
Images: [`benchmark.png`](benchmark.png), [`chart.png`](chart.png),
83+
[`optcarrot_benchmark.png`](optcarrot_benchmark.png),
84+
[`optcarrot_fps_history.png`](optcarrot_fps_history.png),
85+
[`optcarrot_fps_history_opt.png`](optcarrot_fps_history_opt.png).
86+
87+
---
88+
89+
## Where to start
90+
91+
- **Adding a builtin**`native_func.md`, then `method_args.md`.
92+
- **Changing method dispatch**`cref.md` and `refinements.md` for what
93+
resolution depends on; `super_resolution.md` if `super` is involved.
94+
- **Touching the JIT**`jit.md` for the entry states, `arch_difference.md`
95+
before anything arch-specific, `lir.md` and `regalloc_separation.md` for
96+
the layering.
97+
- **Anything asynchronous** (GC, signals, threads) → `safepoint.md` first.
98+
- **A ruby/spec failure that hangs**`ruby_spec_skip_tags.md`.
99+
100+
## Adding a document
101+
102+
Put it here, add a row above, and say which of the three kinds it is. A
103+
design record earns its place by recording the *rejected* options and the
104+
measurements, not just the chosen one — that is what makes it still
105+
useful once the code has moved.

doc/cref.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,10 @@ parent CREFs via `CREF_FL_OMOD_SHARED`). `using Foo` populates the
148148
*current* CREF's hash; the lookup walks the chain.
149149

150150
monoruby does not implement refinements; the `Cref` struct has no
151-
`refinements` field.
151+
`refinements` field. See `doc/refinements.md` for what the missing field
152+
is the smallest part of — the per-frame CREF this document describes is a
153+
prerequisite, and every method-resolution cache in the tree is keyed
154+
without a cref.
152155

153156
---
154157

0 commit comments

Comments
 (0)