From 088a1bbd4d56a01754242a4131583c4c303dfae8 Mon Sep 17 00:00:00 2001 From: Zachary Whitley Date: Mon, 14 Sep 2026 07:38:23 -0400 Subject: [PATCH] feat(wasm-encoder): ComponentBuilder::start() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Second wasmos-required helper on the same fork branch as `instantiate_exports`. Emits a component start section, invoking `function_index` at instantiation time with `args` (each an index into the component value index space) and producing `results` new values. Returns the index of the first produced value so callers can register the newly-populated value-index slots for downstream consumers (canonical option refs, exports, etc.). Subsequent produced values occupy `first+1`, `first+2`, …, `first+results-1`. Component start is a singleton section (spec allows at most one per component); this helper does not enforce that, matching the underlying `ComponentStartSection` encoder's posture. Flushes any prior aggregating section before emitting so section ordering stays coherent. Unblocks wasmos-component-opt's `SectionItem::ComponentStart` writer arm, which previously `bail!`'d pending this method. See `docs/upstream-needs.md` in that crate for the full context. --- crates/wasm-encoder/src/component/builder.rs | 34 ++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/crates/wasm-encoder/src/component/builder.rs b/crates/wasm-encoder/src/component/builder.rs index 8259f11609..e7cf7baf8a 100644 --- a/crates/wasm-encoder/src/component/builder.rs +++ b/crates/wasm-encoder/src/component/builder.rs @@ -448,6 +448,40 @@ impl ComponentBuilder { self.instances.add(debug_name) } + /// Emits a component start section, invoking `function_index` + /// at instantiation time with `args` (each an index into the + /// component value index space) and producing `results` new + /// values. + /// + /// Returns the index of the FIRST produced value in the + /// component value index space (subsequent produced values + /// occupy `first+1`, `first+2`, …, `first+results-1`). If + /// `results == 0` the return value is still the current + /// value-index cursor but no new values are added; callers + /// typically ignore it in that case. + /// + /// The Component Model spec permits at most one start section + /// per component. This helper does NOT enforce that; passing + /// the responsibility to the caller matches how the underlying + /// `ComponentStartSection` encoder behaves. + pub fn start(&mut self, function_index: u32, args: Vec, results: u32) -> u32 { + // Component start is a singleton section rather than an + // aggregating one, so we don't route it through the + // section-accessor macro. Flush any last section first so + // section ordering stays coherent. + self.flush(); + self.component.section(&ComponentStartSection { + function_index, + args, + results, + }); + let base = self.values.count; + for _ in 0..results { + self.values.add(None); + } + base + } + /// Declares a new `resource.drop` intrinsic. pub fn resource_drop(&mut self, ty: u32) -> u32 { self.canonical_functions().resource_drop(ty);