Skip to content

Add Machine HostCall#935

Merged
DrEverr merged 10 commits intomainfrom
maso-machine
Apr 6, 2026
Merged

Add Machine HostCall#935
DrEverr merged 10 commits intomainfrom
maso-machine

Conversation

@DrEverr
Copy link
Copy Markdown
Member

@DrEverr DrEverr commented Mar 25, 2026

No description provided.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 25, 2026

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Machine initialization is now fully functional with support for sequential machine ID allocation and configurable program counter positions.

Walkthrough

This pull request implements RefineExternalitiesImpl.machineInit to deblob incoming program bytes, create and reset an inner PVM instance using the configured backend, allocate the minimal free sequential MachineId and insert the machine into a sorted machines container, and return the MachineId. It adds a pvmBackend parameter to RefineExternalitiesParams, updates InCore.createRefineExternalities to pass the backend, extends IPvmInterpreter with resetGeneric, adds runtime PVM-related dependencies, and adds tests covering successful init, sequential ID allocation, invalid/empty blobs, and non-zero program counter handling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Initial refine #859: Introduced the stubbed RefineExternalitiesImpl.machineInit signature and scaffolding that this PR implements.
  • Add exportSegment refine HC #929: Modified RefineExternalitiesImpl parameters and creation paths similar to the changes in this PR.
  • Clean up PVM packages #801: Adjusted PVM packages and interpreter APIs which this PR relies on (e.g., new interpreter reset entrypoint).

Suggested reviewers

  • tomusdrw
  • skoszuta

Poem

🐰 I munched the blob and found the code,
I nudged the PVM down a sleepy road,
Carrot-IDs handed out in line,
Machines awake and feeling fine,
Tiny paws clap—now they run, hop, go! 🥕

🚥 Pre-merge checks | ❌ 3

❌ Failed checks (2 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning No pull request description was provided by the author, making it impossible to assess whether documentation of changes exists. Add a pull request description that explains the purpose of the changes, the implementation approach, and how the new machineInit functionality integrates with the PVM backend.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Add Machine HostCall' is vague and doesn't clearly describe the main changes, which involve implementing machineInit functionality with PVM backend integration and new dependencies. Consider a more descriptive title such as 'Implement machineInit with PVM backend support' to clearly convey the primary change.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch maso-machine

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@DrEverr DrEverr marked this pull request as ready for review March 25, 2026 16:02
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
packages/jam/in-core/externalities/refine.test.ts (1)

22-23: Consider adding a brief comment explaining the minimal program structure.

The MINIMAL_PROGRAM bytes are used across multiple tests but the format isn't documented. A brief comment indicating what these bytes represent (e.g., header bytes + instruction) would improve test maintainability.

📝 Suggested documentation
+// Minimal valid PVM program blob: [ro_len_lo, ro_len_hi, rw_len_lo, rw_len_hi, instruction]
 const MINIMAL_PROGRAM = new Uint8Array([0, 1, 1, 0, 0x00]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/jam/in-core/externalities/refine.test.ts` around lines 22 - 23, Add
a short inline comment above the MINIMAL_PROGRAM constant in refine.test.ts
describing what each byte represents (e.g., which bytes are the header/metadata
and which byte is the actual instruction/opcode), for example noting that
MINIMAL_PROGRAM is a 5-byte array composed of X header bytes and a final
opcode/terminator byte; reference the MINIMAL_PROGRAM identifier so tests
clearly understand the structure and purpose of those bytes.
packages/jam/in-core/externalities/refine.ts (1)

121-124: ID allocation loop could be simplified to a counter.

Since machineExpunge is not implemented (throws error), machines are never removed, so this.machines.has(id) will always be false for the next sequential ID. A simple incrementing counter would be clearer:

♻️ Suggested simplification
+  /** Next machine ID to allocate. */
+  private nextMachineId = 0n;
   /** Map of inner PVM instances keyed by MachineId. */
   private machines: Map<bigint, Interpreter> = new Map();

Then in machineInit:

-    let id = 0n;
-    while (this.machines.has(id)) {
-      id++;
-    }
-
-    const machineId = tryAsMachineId(id);
+    const machineId = tryAsMachineId(this.nextMachineId++);
+    const id = BigInt(machineId);

Note: If machineExpunge will later allow ID reuse, the current approach is appropriate. Otherwise, a counter is simpler.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/jam/in-core/externalities/refine.ts` around lines 121 - 124, Replace
the ID allocation loop in machineInit (the while loop that checks
this.machines.has(id) and increments id) with a simple monotonic counter field
(e.g. this.nextMachineId) that you increment and assign for each new machine;
update machineInit to use and increment that counter when creating an ID, and
add/initialize the counter on the class so it starts at 0n; keep the current
loop approach only if machineExpunge will be implemented to allow ID reuse.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/jam/in-core/externalities/refine.test.ts`:
- Around line 22-23: Add a short inline comment above the MINIMAL_PROGRAM
constant in refine.test.ts describing what each byte represents (e.g., which
bytes are the header/metadata and which byte is the actual instruction/opcode),
for example noting that MINIMAL_PROGRAM is a 5-byte array composed of X header
bytes and a final opcode/terminator byte; reference the MINIMAL_PROGRAM
identifier so tests clearly understand the structure and purpose of those bytes.

In `@packages/jam/in-core/externalities/refine.ts`:
- Around line 121-124: Replace the ID allocation loop in machineInit (the while
loop that checks this.machines.has(id) and increments id) with a simple
monotonic counter field (e.g. this.nextMachineId) that you increment and assign
for each new machine; update machineInit to use and increment that counter when
creating an ID, and add/initialize the counter on the class so it starts at 0n;
keep the current loop approach only if machineExpunge will be implemented to
allow ID reuse.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 29e3efa9-ebb9-4eaf-ac05-174869c1a1e8

📥 Commits

Reviewing files that changed from the base of the PR and between 6cb1bd5 and 931e6ba.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • packages/jam/in-core/externalities/refine.test.ts
  • packages/jam/in-core/externalities/refine.ts
  • packages/jam/in-core/package.json

@DrEverr DrEverr requested a review from tomusdrw March 25, 2026 16:19
@DrEverr DrEverr mentioned this pull request Mar 25, 2026
Comment thread packages/jam/in-core/externalities/refine.ts
Comment thread packages/jam/in-core/externalities/refine.ts Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/jam/in-core/externalities/refine.ts (1)

136-137: Consider reusing PvmInstanceManager across machineInit calls.

A new PvmInstanceManager is created for each machineInit invocation. If machineInit is called frequently, this adds overhead. Consider storing a single manager instance (or a pool) at the class level and reusing it for subsequent calls.

♻️ Sketch of manager reuse
 export class RefineExternalitiesImpl implements RefineExternalities {
   /** Inner PVM instances sorted by MachineId. */
   private machines: SortedArray<MachineEntry> = SortedArray.fromSortedArray(machineComparator);
+  /** Cached PvmInstanceManager for creating inner machines. */
+  private manager: PvmInstanceManager | null = null;
   // ...

   async machineInit(code: BytesBlob, programCounter: ProgramCounter): Promise<Result<MachineId, ProgramDecoderError>> {
     // ...
-    const manager = await PvmInstanceManager.new(this.pvmBackend);
-    const innerPvm = await manager.getInstance();
+    if (this.manager === null) {
+      this.manager = await PvmInstanceManager.new(this.pvmBackend);
+    }
+    const innerPvm = await this.manager.getInstance();
     // ...
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/jam/in-core/externalities/refine.ts` around lines 136 - 137, The
code creates a new PvmInstanceManager on every machineInit call (const manager =
await PvmInstanceManager.new(this.pvmBackend); const innerPvm = await
manager.getInstance();) which is wasteful; refactor to store and reuse a single
manager (or a pool) on the class (e.g., this.pvmInstanceManager) so machineInit
reuses this.pvmInstanceManager.getInstance() instead of calling
PvmInstanceManager.new each time, lazily initialize the manager when null and
ensure proper lifecycle/cleanup where the class currently constructs or disposes
resources.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/jam/in-core/externalities/refine.ts`:
- Around line 136-137: The code creates a new PvmInstanceManager on every
machineInit call (const manager = await PvmInstanceManager.new(this.pvmBackend);
const innerPvm = await manager.getInstance();) which is wasteful; refactor to
store and reuse a single manager (or a pool) on the class (e.g.,
this.pvmInstanceManager) so machineInit reuses
this.pvmInstanceManager.getInstance() instead of calling PvmInstanceManager.new
each time, lazily initialize the manager when null and ensure proper
lifecycle/cleanup where the class currently constructs or disposes resources.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6c76cfce-5d5c-4da9-82d1-30e877a9d4ba

📥 Commits

Reviewing files that changed from the base of the PR and between 931e6ba and e3bc5cc.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (5)
  • packages/core/pvm-interface/pvm.ts
  • packages/jam/in-core/externalities/refine.test.ts
  • packages/jam/in-core/externalities/refine.ts
  • packages/jam/in-core/in-core.ts
  • packages/jam/in-core/package.json
✅ Files skipped from review due to trivial changes (2)
  • packages/jam/in-core/externalities/refine.test.ts
  • packages/jam/in-core/package.json

@DrEverr DrEverr requested a review from tomusdrw April 1, 2026 11:56
Comment thread packages/jam/in-core/externalities/refine.ts
@DrEverr DrEverr enabled auto-merge April 6, 2026 18:01
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/jam/in-core/externalities/refine.ts (1)

134-134: Program blob is decoded twice.

ProgramDecoder.deblob validates the blob at line 134, but resetGeneric internally creates another ProgramDecoder from the same raw bytes (per interpreter.ts:137). This duplicates the parsing work.

Consider adding a resetWithDecoded(...) variant to IPvmInterpreter that accepts pre-decoded program data, or caching/reusing the decode result if the interface supports it in the future.

Also applies to: 142-142

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/jam/in-core/externalities/refine.ts` at line 134,
ProgramDecoder.deblob is being called to decode code.raw but resetGeneric on
IPvmInterpreter ends up re-decoding the same raw bytes (see ProgramDecoder usage
and resetGeneric), causing duplicate work; add a new method like
resetWithDecoded on IPvmInterpreter that accepts the already-decoded
ProgramDecoder result (or a decoded program structure) and update callers (where
deblobResult is computed) to call resetWithDecoded instead of resetGeneric, or
alternatively implement a small cache/reuse layer around ProgramDecoder in the
interpreter so resetGeneric can accept an optional predecoded payload; update
all affected call sites (the spots around the current deblob usage and the
second occurrence at line ~142) to use the new API.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/jam/in-core/externalities/refine.ts`:
- Around line 158-161: The call to tryAsMachineId(low) can throw and must be
converted to a Result-returning path: wrap the conversion in a try/catch (or
pre-validate low against U64 bounds) and on failure return a Result.err with a
descriptive message instead of letting an exception escape; if successful
continue to call this.machines.insert([machineId, innerPvm]) and return
Result.ok(machineId). Ensure you reference tryAsMachineId, low, innerPvm,
this.machines.insert and Result.ok when making the change so the thrown
assertion is handled consistently with the codebase's Result-based error
handling.

---

Nitpick comments:
In `@packages/jam/in-core/externalities/refine.ts`:
- Line 134: ProgramDecoder.deblob is being called to decode code.raw but
resetGeneric on IPvmInterpreter ends up re-decoding the same raw bytes (see
ProgramDecoder usage and resetGeneric), causing duplicate work; add a new method
like resetWithDecoded on IPvmInterpreter that accepts the already-decoded
ProgramDecoder result (or a decoded program structure) and update callers (where
deblobResult is computed) to call resetWithDecoded instead of resetGeneric, or
alternatively implement a small cache/reuse layer around ProgramDecoder in the
interpreter so resetGeneric can accept an optional predecoded payload; update
all affected call sites (the spots around the current deblob usage and the
second occurrence at line ~142) to use the new API.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a1fa609b-3049-4e16-93a2-6967cf1d1419

📥 Commits

Reviewing files that changed from the base of the PR and between e3bc5cc and 15bf66e.

📒 Files selected for processing (1)
  • packages/jam/in-core/externalities/refine.ts

Comment thread packages/jam/in-core/externalities/refine.ts
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 6, 2026

View all
File Benchmark Ops
bytes/hex-from.ts[0] parse hex using Number with NaN checking 63301.03 ±2.63% 86.11% slower
bytes/hex-from.ts[1] parse hex from char codes 455614.04 ±0.48% fastest ✅
bytes/hex-from.ts[2] parse hex from string nibbles 259989.99 ±0.56% 42.94% slower
bytes/hex-to.ts[0] number toString + padding 89723.72 ±0.67% fastest ✅
bytes/hex-to.ts[1] manual 7397.42 ±0.5% 91.76% slower
codec/bigint.compare.ts[0] compare custom 93787506.95 ±5.54% fastest ✅
codec/bigint.compare.ts[1] compare bigint 92683220.31 ±5.06% 1.18% slower
codec/bigint.decode.ts[0] decode custom 70806384.77 ±3.17% 25.41% slower
codec/bigint.decode.ts[1] decode bigint 94923286.55 ±4.5% fastest ✅
codec/decoding.ts[0] manual decode 9450903.22 ±2.13% 85.97% slower
codec/decoding.ts[1] int32array decode 65393991.23 ±3.99% 2.89% slower
codec/decoding.ts[2] dataview decode 67342169.61 ±3.2% fastest ✅
codec/encoding.ts[0] manual encode 1076352.21 ±0.54% 13.17% slower
codec/encoding.ts[1] int32array encode 1239560.3 ±0.56% fastest ✅
codec/encoding.ts[2] dataview encode 1196682.84 ±0.46% 3.46% slower
collections/map-set.ts[0] 2 gets + conditional set 71729.34 ±0.19% fastest ✅
collections/map-set.ts[1] 1 get 1 set 46531.61 ±0.11% 35.13% slower
logger/index.ts[0] console.log with string concat 4961574.82 ±42.56% fastest ✅
logger/index.ts[1] console.log with args 1277701.95 ±78.74% 74.25% slower
math/add_one_overflow.ts[0] add and take modulus 91079904.86 ±5.28% 4.39% slower
math/add_one_overflow.ts[1] condition before calculation 95259628.57 ±4.01% fastest ✅
math/count-bits-u32.ts[0] standard method 39109448.54 ±2.22% 56.21% slower
math/count-bits-u32.ts[1] magic 89301538.07 ±4.74% fastest ✅
math/count-bits-u64.ts[0] standard method 4790294.17 ±1.17% 81.15% slower
math/count-bits-u64.ts[1] magic 25409318.73 ±1.28% fastest ✅
math/mul_overflow.ts[0] multiply and bring back to u32 95678069.79 ±4.64% 0.07% slower
math/mul_overflow.ts[1] multiply and take modulus 95741581.74 ±4.59% fastest ✅
math/switch.ts[0] switch 94844028.33 ±5.44% 1.76% slower
math/switch.ts[1] if 96546918.19 ±5.31% fastest ✅
hash/index.ts[0] hash with numeric representation 67.86 ±0.25% 30.73% slower
hash/index.ts[1] hash with string representation 42.06 ±3.08% 57.07% slower
hash/index.ts[2] hash with symbol representation 65.41 ±0.77% 33.23% slower
hash/index.ts[3] hash with uint8 representation 75.68 ±0.27% 22.75% slower
hash/index.ts[4] hash with packed representation 97.97 ±0.4% fastest ✅
hash/index.ts[5] hash with bigint representation 76.43 ±0.17% 21.99% slower
hash/index.ts[6] hash with uint32 representation 91.07 ±0.72% 7.04% slower
bytes/bytes-to-number.ts[0] Conversion with bitops 3240.22 ±5.64% fastest ✅
bytes/bytes-to-number.ts[1] Conversion without bitops 1239.6 ±82.38% 61.74% slower
bytes/compare.ts[0] Comparing Uint32 bytes 10944.64 ±0.28% 3.93% slower
bytes/compare.ts[1] Comparing raw bytes 11391.86 ±0.35% fastest ✅
codec/view_vs_collection.ts[0] Get first element from Decoded 14763.59 ±0.77% 54.83% slower
codec/view_vs_collection.ts[1] Get first element from View 32683.73 ±0.94% fastest ✅
codec/view_vs_collection.ts[2] Get 50th element from Decoded 14835.26 ±0.52% 54.61% slower
codec/view_vs_collection.ts[3] Get 50th element from View 17252.18 ±0.54% 47.21% slower
codec/view_vs_collection.ts[4] Get last element from Decoded 14881.94 ±0.26% 54.47% slower
codec/view_vs_collection.ts[5] Get last element from View 12021.1 ±0.32% 63.22% slower
codec/view_vs_object.ts[0] Get the first field from Decoded 194025.05 ±0.97% 2.89% slower
codec/view_vs_object.ts[1] Get the first field from View 49209.04 ±0.44% 75.37% slower
codec/view_vs_object.ts[2] Get the first field as view from View 48555.56 ±0.45% 75.7% slower
codec/view_vs_object.ts[3] Get two fields from Decoded 197174.14 ±0.54% 1.31% slower
codec/view_vs_object.ts[4] Get two fields from View 39145.81 ±0.36% 80.41% slower
codec/view_vs_object.ts[5] Get two fields from materialized from View 80287.53 ±0.4% 59.82% slower
codec/view_vs_object.ts[6] Get two fields as views from View 38661.21 ±0.9% 80.65% slower
codec/view_vs_object.ts[7] Get only third field from Decoded 199795.55 ±0.45% fastest ✅
codec/view_vs_object.ts[8] Get only third field from View 48964.78 ±0.32% 75.49% slower
codec/view_vs_object.ts[9] Get only third field as view from View 48351.93 ±0.39% 75.8% slower
collections/map_vs_sorted.ts[0] Map 93409.09 ±0.27% fastest ✅
collections/map_vs_sorted.ts[1] Map-array 44602.12 ±1.25% 52.25% slower
collections/map_vs_sorted.ts[2] Array 52506.29 ±0.31% 43.79% slower
collections/map_vs_sorted.ts[3] SortedArray 79990.72 ±0.37% 14.37% slower
collections/hash-dict-vs-blob-dict_delete.ts[0] StringHashDictionary 2657.1 ±0.46% 0.98% slower
collections/hash-dict-vs-blob-dict_delete.ts[1] BlobDictionary(1) 2680.93 ±0.3% 0.09% slower
collections/hash-dict-vs-blob-dict_delete.ts[2] BlobDictionary(2) 2671.61 ±0.41% 0.44% slower
collections/hash-dict-vs-blob-dict_delete.ts[3] BlobDictionary(3) 2683.34 ±0.4% fastest ✅
collections/hash-dict-vs-blob-dict_delete.ts[4] BlobDictionary(4) 2648.47 ±0.36% 1.3% slower
collections/hash-dict-vs-blob-dict_delete.ts[5] BlobDictionary(5) 2649.26 ±0.5% 1.27% slower
collections/hash-dict-vs-blob-dict_get.ts[0] StringHashDictionary 3020.26 ±0.48% fastest ✅
collections/hash-dict-vs-blob-dict_get.ts[1] BlobDictionary(1) 2959.09 ±0.71% 2.03% slower
collections/hash-dict-vs-blob-dict_get.ts[2] BlobDictionary(2) 2783.02 ±1.86% 7.85% slower
collections/hash-dict-vs-blob-dict_get.ts[3] BlobDictionary(3) 2858.96 ±0.55% 5.34% slower
collections/hash-dict-vs-blob-dict_get.ts[4] BlobDictionary(4) 2807.38 ±0.62% 7.05% slower
collections/hash-dict-vs-blob-dict_get.ts[5] BlobDictionary(5) 1784.39 ±73.85% 40.92% slower
collections/hash-dict-vs-blob-dict_set.ts[0] StringHashDictionary 2050.67 ±1.59% 9.42% slower
collections/hash-dict-vs-blob-dict_set.ts[1] BlobDictionary(1) 1819.44 ±8.65% 19.63% slower
collections/hash-dict-vs-blob-dict_set.ts[2] BlobDictionary(2) 2263.89 ±0.57% fastest ✅
collections/hash-dict-vs-blob-dict_set.ts[3] BlobDictionary(3) 2237.43 ±1.5% 1.17% slower
collections/hash-dict-vs-blob-dict_set.ts[4] BlobDictionary(4) 2142.45 ±1.5% 5.36% slower
collections/hash-dict-vs-blob-dict_set.ts[5] BlobDictionary(5) 2140.95 ±1.82% 5.43% slower
hash/blake2b.ts[0] our hasher 1.03 ±0.34% fastest ✅
hash/blake2b.ts[1] blake2b js 0.03 ±2.66% 97.09% slower
crypto/ed25519.ts[0] native crypto 5.5 ±1.22% fastest ✅
crypto/ed25519.ts[1] wasm lib 2.14 ±1.15% 61.09% slower
crypto/ed25519.ts[2] wasm lib batch 2.1 ±0.83% 61.82% slower

Benchmarks summary: 83/83 OK ✅

@DrEverr DrEverr added this pull request to the merge queue Apr 6, 2026
Merged via the queue into main with commit 9567cee Apr 6, 2026
14 checks passed
@DrEverr DrEverr deleted the maso-machine branch April 6, 2026 21:18
@coderabbitai coderabbitai Bot mentioned this pull request Apr 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants