vm-ext: phase D — extensions/ subtree + test_ext + opcode_name lookup
lib/extensions/ becomes the new home for VM extensions, wired in via (include_subdirs unqualified). README documents the registration pattern, opcode-ID range conventions (200-209 guest_vm, 210-219 inline test, 220-229 test_ext, 230-247 ports), and naming rules. extensions/test_ext.ml is the canonical worked example — two operand-less opcodes (220 push 42, 221 double TOS) carrying a per- extension state slot (TestExtState invocation counter). Test_ext.register called from run_tests.ml at the start of the Phase D suite, on top of the inline test_reg from earlier suites (disjoint opcode IDs). Sx_vm.opcode_name now consults extension_opcode_name_ref (forward ref in the same style as extension_dispatch_ref), so disassemble shows extension opcodes by name instead of UNKNOWN_n. Registry maintains name_of_id_table and installs the lookup at module init. Tests: 5 new foundation cases — primitive resolves test_ext name, end-to-end bytecode (push + double + return → 84), disassemble shows "test_ext.OP_TEST_PUSH_42" / "test_ext.OP_TEST_DOUBLE_TOS", unregistered ext opcodes still fall back to UNKNOWN_n, invocation counter records the two dispatches. +5 pass vs Phase C baseline, no regressions across 11 conformance suites.
This commit is contained in:
@@ -298,10 +298,10 @@ Compiler test: write SX that triggers the test compiler-extension to emit
|
||||
`OP_TEST_PUSH_42`, then verify the VM executes it correctly via
|
||||
`bytecode-inspect` and `vm-trace`.
|
||||
|
||||
- [ ] `test_ext.ml` registers two opcodes.
|
||||
- [ ] Wired into the build (extensions registered at startup).
|
||||
- [ ] Bytecode emission via name lookup produces the right ID.
|
||||
- [ ] `bytecode-inspect` shows the opcode by name.
|
||||
- [x] `test_ext.ml` registers two opcodes.
|
||||
- [x] Wired into the build (extensions registered at startup).
|
||||
- [x] Bytecode emission via name lookup produces the right ID.
|
||||
- [x] `bytecode-inspect` shows the opcode by name.
|
||||
|
||||
**Tests:**
|
||||
- Bytecode emission via name lookup produces the right ID.
|
||||
@@ -457,6 +457,29 @@ familiarity.
|
||||
|
||||
Newest first.
|
||||
|
||||
- **2026-05-15** — Phase D done. New `hosts/ocaml/lib/extensions/` subtree
|
||||
wired into the `sx` library via `(include_subdirs unqualified)`.
|
||||
`extensions/test_ext.ml` is the canonical worked example: two
|
||||
operand-less opcodes (`test_ext.OP_TEST_PUSH_42` = 220,
|
||||
`test_ext.OP_TEST_DOUBLE_TOS` = 221) carrying `TestExtState` (an
|
||||
invocation counter that exercises the per-extension state slot).
|
||||
`extensions/README.md` documents the registration pattern, opcode-ID
|
||||
range conventions, and naming rules.
|
||||
|
||||
`Sx_vm.opcode_name` now consults `extension_opcode_name_ref` (forward
|
||||
ref) so disassembly shows extension opcodes by name instead of
|
||||
`UNKNOWN_n`. Registry maintains `name_of_id_table` (reverse of
|
||||
`by_name`) and installs the lookup at module init alongside the
|
||||
dispatch ref. 5 new foundation tests (`extensions/test_ext` suite):
|
||||
`extension-opcode-id` finds OP_TEST_PUSH_42, end-to-end bytecode runs
|
||||
to 84, disassemble shows opcode names, unregistered ext opcodes still
|
||||
fall back to UNKNOWN_n, per-extension state counter increments.
|
||||
+5 pass vs Phase C baseline (4826 vs 4821), 1111 pre-existing failures
|
||||
unchanged. Conformance suites green: erlang 530/530, haskell 285/285,
|
||||
datalog 276/276, prolog 590/590, smalltalk 847/847, common-lisp
|
||||
487/487, apl 562/562, js 148/148, forth 632/638 (pre-existing), tcl
|
||||
3/4 (pre-existing), ocaml-on-sx unit 607/607.
|
||||
|
||||
- **2026-05-15** — Phase C done. `extension-opcode-id` SX primitive
|
||||
registered from `sx_vm_extensions.ml` module init (avoids the
|
||||
`sx_primitives ↔ sx_vm` cycle by registering downstream of both).
|
||||
|
||||
Reference in New Issue
Block a user