Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Differences with Wasmtime

Jco and Wasmtime implement the Component Model in different host environments. The Canonical ABI defines the behavior of guest-visible operations; each embedding also provides lifecycle and integration APIs beyond those operations. Similar host APIs need not have identical cleanup mechanisms or completion guarantees.

Jco runs in browsers and Node.js, where JavaScript garbage collection and platform I/O APIs control much of an application’s lifetime. A host can retain a promise, iterator, exported function, or resource after guest execution ends. Jco therefore provides explicit lifecycle operations to settle outstanding work, notify sources of disposal, and release resources that would otherwise depend on application cleanup or garbage collection. These operations give hosts more deterministic control over execution and cleanup initiation; they cannot force the platform to reclaim all memory immediately.

Stopping and shutting down instances

Jco’s instance._util.stop() permanently stops the entire generated instantiation, including its nested components. Its scope is comparable to destroying a Wasmtime store, which owns its component instances. Wasmtime’s component Instance is a handle into that store rather than an independently destructible owner. See the Wasmtime Store API and component Instance API.

For instructions on using Jco’s API, see Stopping running instances.

Teardown behavior

The comparison below describes Jco’s explicit stop operation and Wasmtime store destruction. A trapped or poisoned store is a separate state: preventing further execution alone does not perform all the cleanup associated with destroying the store.

ConcernJco _util.stop()Wasmtime store destruction
Pending executionExplicitly rejects pending guest calls and prevents guest execution from resuming.Disposes fibers and drops store-owned futures.
Pending stream readsRejects interrupted host reads with code: "ERR_COMPONENT_STOPPED".Drops channel state and associated host machinery; teardown does not promise a final EOF notification.
Pending future readsRejects host reads still waiting for a value.Drops the relevant machinery; externally observed cancellation depends on the host implementation.
Host sourcesExplicitly invokes iterator return or disposal hooks for discarded sources.Rust destruction releases stored producers, consumers, and their captured state.
Host resources owned by the guestCalls Symbol.dispose on captured owned objects.Cleanup follows ownership of host data and resource tables; canonical resource-destructor callbacks are separate operations.
MemoryObjects may remain reachable after stop; JavaScript GC can reclaim them when references are released.Destruction releases store-owned instance allocations.
Cleanup completionReturns synchronously without awaiting asynchronous host disposal.Rust Drop runs synchronously; separately owned external work can still outlive the store.
Cleanup failuresSynchronous resource-disposal errors are aggregated after other cleanup; deferred source-disposal errors are reported separately.Drop has no returned cleanup result; the embedder defines how its own cleanup failures are handled.

This is a source-level comparison against Wasmtime revision 67d70b4e. Its store destructor runs manual cleanup, drops host data and internal state, and deallocates instances. The component cleanup path disposes fibers and drops pending host futures. It does not walk every stream or future through the ordinary reader/writer close operations as a final protocol exchange.

Wasmtime still cleans up host sources: its channel state owns producer and consumer closures, and releasing these can run Rust destructors. Jco needs explicit hooks because losing interest in a JavaScript promise or retaining a stopped instance does not provide the same deterministic destruction mechanism. Pending JavaScript operations may remain observable to their callers, so settling them is useful independently of memory reclamation.

Resource ownership

Wasmtime’s Resource<T> contract leaves host-resource destruction to the embedder. Normal Store<T> destruction drops its host data T; Store::into_data() destroys the store while returning that data to the caller. Store destruction is therefore not a promise to invoke each resource’s canonical destructor. Explicit ResourceAny::resource_drop is the operation that can invoke such a destructor.

Jco adds an explicit cleanup policy for host objects still owned by the guest. It does not dispose borrowed host objects or host resources already returned to the caller, and it does not execute guest Wasm destructors during stop. A value that needs the stopped guest to execute code can no longer use that guest, even if its JavaScript wrapper remains reachable.

Channel ownership and payload ownership are also separate. After a future delivers its payload to the host, disposing that future releases the channel without disposing the delivered value. The recipient owns that value and its eventual cleanup.

Interruption versus normal end of stream

A Jco host stream read interrupted by instance stop rejects with an error whose code is "ERR_COMPONENT_STOPPED". Subsequent reads on the interrupted stream also reject. Ordinary EOF remains done: true: shutdown does not turn a stream that already ended or was explicitly closed into an error. Reads that already copied data still deliver it before a later read reports shutdown. See Recognize an interrupted stream.

The Canonical ABI’s copy results distinguish COMPLETED, DROPPED, and CANCELLED, but do not carry a reason identifying instance shutdown. CANCELLED describes cancellation of a copy operation; it should not be repurposed as a shutdown reason. Jco’s rejection is an additional host-binding policy. It leaves guest-visible copy result codes, transferred counts, and ordinary guest drop validation unchanged. It does not require a matching teardown notification in Wasmtime or other embeddings.

Waiting and cleanup completion

Waiting for guest task exit, draining output, and completing host disposal are different conditions. Waiting for guest tasks to exit before calling stop() allows application work to finish normally. Long-lived tasks need an application-specific request to finish, or the host can choose to abandon them with stop().

A wait that resolves when an instance is stopped establishes that further guest execution has ended. It does not establish that asynchronous host disposers, network operations, or output destinations have finished. Hosts that require those guarantees must await the completion signals supplied by their own providers as well.

Jco’s Preview 3 output helpers are one such provider-specific mechanism. See Preview 3 output flush and shutdown for draining stdout and stderr. Neither Jco stop nor Wasmtime store destruction is a general graceful completion protocol for arbitrary external I/O.

Relationship to the Canonical ABI

Jco’s dedicated instance-stop hooks are a host embedding convenience, separate from ordinary canonical channel drops. They can close pending copies and unwritten future writers during teardown while preserving the ordinary guest drop checks. Wasmtime’s store destruction is likewise a host lifecycle operation. The ABI remains the authority for guest operations; it does not require identical teardown notifications between the two hosts.