@polyengine/runtime 0.1.0-pre.g633468a
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +23 -0
- package/esm/cabi/async_values.js +162 -0
- package/esm/cabi/bulk_lists.js +198 -0
- package/esm/cabi/context.js +42 -0
- package/esm/cabi/flatten.js +145 -0
- package/esm/cabi/float.js +67 -0
- package/esm/cabi/handles.js +253 -0
- package/esm/cabi/layout.js +149 -0
- package/esm/cabi/lift.js +196 -0
- package/esm/cabi/load.js +146 -0
- package/esm/cabi/lower.js +141 -0
- package/esm/cabi/memory.js +182 -0
- package/esm/cabi/mod.js +22 -0
- package/esm/cabi/store.js +186 -0
- package/esm/cabi/strings.js +336 -0
- package/esm/cabi/trap.js +38 -0
- package/esm/cabi/types.js +264 -0
- package/esm/cabi/values.js +64 -0
- package/esm/cache/core.js +156 -0
- package/esm/cache/dir.js +170 -0
- package/esm/cache/mod.js +4 -0
- package/esm/cache/web.js +136 -0
- package/esm/digest/digest.js +332 -0
- package/esm/digest/mod.js +3 -0
- package/esm/digest/verify.js +129 -0
- package/esm/embedder/casing.js +56 -0
- package/esm/embedder/copy.js +42 -0
- package/esm/embedder/errors.js +26 -0
- package/esm/embedder/imports.js +63 -0
- package/esm/embedder/instantiate.js +978 -0
- package/esm/embedder/mod.js +40 -0
- package/esm/embedder/resources.js +406 -0
- package/esm/embedder/streams.js +770 -0
- package/esm/embedder/values.js +450 -0
- package/esm/embedder/version.js +273 -0
- package/esm/exec/boundary.js +1902 -0
- package/esm/exec/executor.js +1004 -0
- package/esm/exec/host_streams.js +818 -0
- package/esm/exec/mod.js +4 -0
- package/esm/intrinsics/async_builtins.js +510 -0
- package/esm/intrinsics/context.js +90 -0
- package/esm/intrinsics/errors.js +13 -0
- package/esm/intrinsics/fact_calls.js +865 -0
- package/esm/intrinsics/mod.js +564 -0
- package/esm/intrinsics/stream_builtins.js +578 -0
- package/esm/intrinsics/transcode.js +443 -0
- package/esm/jspi/bridge.js +579 -0
- package/esm/jspi/mechanics.js +89 -0
- package/esm/jspi/mod.js +5 -0
- package/esm/jspi/suspending.js +15 -0
- package/esm/jspi/types.js +29 -0
- package/esm/package.json +3 -0
- package/esm/plan/format.js +5 -0
- package/esm/plan/loader.js +657 -0
- package/esm/plan/mod.js +3 -0
- package/esm/shim/mod.js +2 -0
- package/esm/shim/translator.js +94 -0
- package/esm/task/mod.js +483 -0
- package/esm/task/scheduler.js +1028 -0
- package/esm/task/streams.js +786 -0
- package/esm/task/subtask.js +135 -0
- package/esm/task/thread.js +255 -0
- package/esm/task/waitable.js +144 -0
- package/package.json +91 -0
- package/types/cabi/async_values.d.ts +35 -0
- package/types/cabi/bulk_lists.d.ts +18 -0
- package/types/cabi/context.d.ts +59 -0
- package/types/cabi/flatten.d.ts +14 -0
- package/types/cabi/float.d.ts +14 -0
- package/types/cabi/handles.d.ts +70 -0
- package/types/cabi/layout.d.ts +13 -0
- package/types/cabi/lift.d.ts +25 -0
- package/types/cabi/load.d.ts +14 -0
- package/types/cabi/lower.d.ts +10 -0
- package/types/cabi/memory.d.ts +58 -0
- package/types/cabi/mod.d.ts +15 -0
- package/types/cabi/store.d.ts +12 -0
- package/types/cabi/strings.d.ts +23 -0
- package/types/cabi/trap.d.ts +11 -0
- package/types/cabi/types.d.ts +206 -0
- package/types/cabi/values.d.ts +5 -0
- package/types/cache/core.d.ts +97 -0
- package/types/cache/dir.d.ts +6 -0
- package/types/cache/mod.d.ts +3 -0
- package/types/cache/web.d.ts +10 -0
- package/types/digest/digest.d.ts +17 -0
- package/types/digest/mod.d.ts +2 -0
- package/types/digest/verify.d.ts +48 -0
- package/types/embedder/casing.d.ts +40 -0
- package/types/embedder/copy.d.ts +24 -0
- package/types/embedder/errors.d.ts +11 -0
- package/types/embedder/imports.d.ts +47 -0
- package/types/embedder/instantiate.d.ts +88 -0
- package/types/embedder/mod.d.ts +11 -0
- package/types/embedder/resources.d.ts +158 -0
- package/types/embedder/streams.d.ts +202 -0
- package/types/embedder/values.d.ts +70 -0
- package/types/embedder/version.d.ts +85 -0
- package/types/exec/boundary.d.ts +360 -0
- package/types/exec/executor.d.ts +125 -0
- package/types/exec/host_streams.d.ts +165 -0
- package/types/exec/mod.d.ts +3 -0
- package/types/intrinsics/async_builtins.d.ts +69 -0
- package/types/intrinsics/context.d.ts +28 -0
- package/types/intrinsics/errors.d.ts +5 -0
- package/types/intrinsics/fact_calls.d.ts +120 -0
- package/types/intrinsics/mod.d.ts +187 -0
- package/types/intrinsics/stream_builtins.d.ts +113 -0
- package/types/intrinsics/transcode.d.ts +21 -0
- package/types/jspi/bridge.d.ts +227 -0
- package/types/jspi/mechanics.d.ts +50 -0
- package/types/jspi/mod.d.ts +3 -0
- package/types/jspi/suspending.d.ts +1 -0
- package/types/jspi/types.d.ts +26 -0
- package/types/plan/format.d.ts +369 -0
- package/types/plan/loader.d.ts +113 -0
- package/types/plan/mod.d.ts +2 -0
- package/types/shim/mod.d.ts +1 -0
- package/types/shim/translator.d.ts +55 -0
- package/types/task/mod.d.ts +257 -0
- package/types/task/scheduler.d.ts +421 -0
- package/types/task/streams.d.ts +370 -0
- package/types/task/subtask.d.ts +96 -0
- package/types/task/thread.d.ts +73 -0
- package/types/task/waitable.d.ts +67 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { type FuncType, ResourceTypeInfo, type ValType } from "../cabi/types.js";
|
|
2
|
+
import type { WireErrorDetail, WirePlan, WireValType } from "./format.js";
|
|
3
|
+
/** Fault in the plan document itself (version/shape/reference errors). */
|
|
4
|
+
export declare class PlanError extends Error {
|
|
5
|
+
constructor(message: string);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* A structured translation verdict from the shim (envelope `errorDetail`).
|
|
9
|
+
*
|
|
10
|
+
* Distinguished from `PlanError` on purpose: a `TranslateError` with
|
|
11
|
+
* `phase === "validation"` is *the translator's judgment about the input
|
|
12
|
+
* component* and is the only failure that satisfies `assert_invalid` /
|
|
13
|
+
* `assert_malformed`. `PlanError` and the other phases are failures of our
|
|
14
|
+
* own pipeline and must never be scored as conformance passes.
|
|
15
|
+
*/
|
|
16
|
+
export declare class TranslateError extends Error {
|
|
17
|
+
readonly phase: WireErrorDetail["phase"];
|
|
18
|
+
readonly detail: string;
|
|
19
|
+
constructor(d: WireErrorDetail);
|
|
20
|
+
/** True iff the shim judged the *input component* invalid or malformed. */
|
|
21
|
+
get isValidationVerdict(): boolean;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The single formatVersion this executor understands.
|
|
25
|
+
*
|
|
26
|
+
* v4 (2026-08-17, polyengine#13): `exports[]` gained the `"module"` kind — a
|
|
27
|
+
* component exporting one of its own embedded core modules, surfaced as the
|
|
28
|
+
* already-compiled `WebAssembly.Module`.
|
|
29
|
+
* v3 (2026-08-10, polyengine#89): `errorContextTables` — the index space the
|
|
30
|
+
* `error-context-transfer` trampoline actually uses (it was resolved through
|
|
31
|
+
* the *resource*-table mapping before, a different space) — and
|
|
32
|
+
* `task-return`'s `resultType` / raw `results` split, which lets a FACT
|
|
33
|
+
* callee task carry its declared result type.
|
|
34
|
+
* v2 (M2 phase 2c): `streamTables` / `futureTables` — the element types the
|
|
35
|
+
* stream and future built-ins need to size their copy buffers.
|
|
36
|
+
* v1 (contracts/plan-format.md v0.3): `CoreDef` gained `"unsafe-intrinsic"`.
|
|
37
|
+
* The change is purely additive, but the contract's compat rule is a strict
|
|
38
|
+
* equality check ("Validate `formatVersion` and fail fast on mismatch",
|
|
39
|
+
* producer and consumer bumped in the same commit), so v0 plans are refused
|
|
40
|
+
* rather than best-effort accepted — a stale cached artifact must be a loud
|
|
41
|
+
* failure, not a subtly different execution.
|
|
42
|
+
*/
|
|
43
|
+
export declare const SUPPORTED_FORMAT_VERSION = 4;
|
|
44
|
+
/** A types-table entry after conversion. */
|
|
45
|
+
export type LoadedType = {
|
|
46
|
+
kind: "func";
|
|
47
|
+
funcType: FuncType;
|
|
48
|
+
paramNames: string[];
|
|
49
|
+
} | {
|
|
50
|
+
kind: "value";
|
|
51
|
+
type: ValType;
|
|
52
|
+
};
|
|
53
|
+
export interface LoadedPlan {
|
|
54
|
+
wire: WirePlan;
|
|
55
|
+
/** Converted types table, index-aligned with `wire.types`. */
|
|
56
|
+
types: LoadedType[];
|
|
57
|
+
/**
|
|
58
|
+
* Identity tokens for resource tables, index-aligned with
|
|
59
|
+
* `wire.resourceTables`. The executor fills `impl`/`dtor` while running
|
|
60
|
+
* `resource` initializers.
|
|
61
|
+
*/
|
|
62
|
+
resourceTokens: ResourceTypeInfo[];
|
|
63
|
+
/**
|
|
64
|
+
* Number of imported resource types. `ResourceIndex =
|
|
65
|
+
* numImportedResources + DefinedResourceIndex`
|
|
66
|
+
* (plan-format.md v0.1 amendment #2 / v0.2 `importedResources`).
|
|
67
|
+
*/
|
|
68
|
+
numImportedResources: number;
|
|
69
|
+
/** Element type per stream table (plan v2); `null` = zero-width payload. */
|
|
70
|
+
streamElems: (ValType | null)[];
|
|
71
|
+
/** Element type per future table (plan v2). */
|
|
72
|
+
futureElems: (ValType | null)[];
|
|
73
|
+
/** Owning component instance per stream/future table (plan v2). */
|
|
74
|
+
streamTableInstances: number[];
|
|
75
|
+
futureTableInstances: number[];
|
|
76
|
+
/**
|
|
77
|
+
* Owning component instance per error-context table (plan v3), index space
|
|
78
|
+
* == `TypeComponentLocalErrorContextTableIndex`.
|
|
79
|
+
*/
|
|
80
|
+
errorContextTableInstances: number[];
|
|
81
|
+
/**
|
|
82
|
+
* Raw wasmtime `TypeTupleIndex` -> `plan.types` index, collected from the
|
|
83
|
+
* `task-return` trampolines (plan v3). The key is what FACT's
|
|
84
|
+
* `prepare-call` passes as `task_return_type` at runtime; the value is the
|
|
85
|
+
* interned tuple type. A callee with no `task.return` trampoline of its own
|
|
86
|
+
* (a sync-lifted callee) contributes no entry, and the lookup then reports
|
|
87
|
+
* "unknown" rather than guessing.
|
|
88
|
+
*/
|
|
89
|
+
resultTupleTypes: Map<number, number>;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Validate a plan document and convert its type tables. Fails fast on
|
|
93
|
+
* formatVersion mismatch per contracts/plan-format.md "Executor obligations".
|
|
94
|
+
*/
|
|
95
|
+
export declare function loadPlan(wire: WirePlan): LoadedPlan;
|
|
96
|
+
/**
|
|
97
|
+
* Component-wide `ResourceIndex` for a `DefinedResourceIndex` (the `index`
|
|
98
|
+
* field of a `resource` initializer). Mirrors wasmtime
|
|
99
|
+
* `Component::resource_index` (wasmtime-environ 47.0.3
|
|
100
|
+
* `component/info.rs:222`).
|
|
101
|
+
*/
|
|
102
|
+
export declare function resourceIndexOfDefined(plan: LoadedPlan, definedIndex: number): number;
|
|
103
|
+
/**
|
|
104
|
+
* Parse the shim's C-ABI JSON envelope into a validated wire plan + adapter
|
|
105
|
+
* bytes. The plan is validated (formatVersion, type tables) but returned in
|
|
106
|
+
* wire form: the executor re-runs `loadPlan` per instantiation so resource
|
|
107
|
+
* identity tokens are fresh per component instance.
|
|
108
|
+
*/
|
|
109
|
+
export declare function loadEnvelope(json: string): {
|
|
110
|
+
wire: WirePlan;
|
|
111
|
+
adapters: Map<string, Uint8Array>;
|
|
112
|
+
};
|
|
113
|
+
export declare function loadValType(t: WireValType, resourceTokens: ResourceTypeInfo[], where: string): ValType;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./translator.js";
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { WirePlan } from "../plan/format.js";
|
|
2
|
+
export interface TranslationResult {
|
|
3
|
+
plan: WirePlan;
|
|
4
|
+
/** Adapter artifacts keyed by `plan.modules[].file`. */
|
|
5
|
+
adapters: Map<string, Uint8Array>;
|
|
6
|
+
/** The raw envelope JSON (byte-exact; useful for determinism checks). */
|
|
7
|
+
envelopeJson: string;
|
|
8
|
+
}
|
|
9
|
+
/** An instantiated translator shim. One instance is reusable across calls. */
|
|
10
|
+
export declare class Translator {
|
|
11
|
+
#private;
|
|
12
|
+
/**
|
|
13
|
+
* sha256 of the shim wasm bytes this instance was built from, hex-encoded;
|
|
14
|
+
* `null` when constructed from a pre-compiled `WebAssembly.Module` with no
|
|
15
|
+
* bytes available (module identity can't be recovered post-compile).
|
|
16
|
+
*
|
|
17
|
+
* This is the honest translator "build hash" for the artifact cache
|
|
18
|
+
* (docs/architecture.md §10): the wire envelope's `producer` block records
|
|
19
|
+
* `{shimVersion, wasmtimeEnviron, features}`, which does NOT change when
|
|
20
|
+
* the shim wasm is rebuilt from the same source versions (e.g. a local
|
|
21
|
+
* patch or a different toolchain producing different codegen) — see the
|
|
22
|
+
* M3-B dispatch. Digesting the actual bytes is the only sound cache key
|
|
23
|
+
* component for translator identity.
|
|
24
|
+
*/
|
|
25
|
+
readonly buildHash: string | null;
|
|
26
|
+
private constructor();
|
|
27
|
+
/** Instantiate from compiled module or raw wasm bytes. */
|
|
28
|
+
static create(source: WebAssembly.Module | Uint8Array): Promise<Translator>;
|
|
29
|
+
/**
|
|
30
|
+
* Wrap an ALREADY-INSTANTIATED shim — the ESM wasm-module import path
|
|
31
|
+
* (issue #16 delivery design): `import * as shim from ".../translator_shim.wasm"`
|
|
32
|
+
* hands back an instantiated namespace (the shim imports nothing, so the
|
|
33
|
+
* ESM integration instantiates it trivially), and this wraps it with no
|
|
34
|
+
* further compile or copy.
|
|
35
|
+
*
|
|
36
|
+
* Sharing note: ESM gives ONE instance per realm, so every `fromExports`
|
|
37
|
+
* wrapper over the same namespace shares linear memory. That is safe by
|
|
38
|
+
* construction — `translate` is synchronous end-to-end (alloc → call →
|
|
39
|
+
* copy out → dealloc within one JS frame), so calls can never interleave —
|
|
40
|
+
* but treat the wrappers as equivalent, not independent.
|
|
41
|
+
*
|
|
42
|
+
* `buildHash` (hex sha-256 of the shim wasm bytes) cannot be recovered
|
|
43
|
+
* from an instance; pass it when known — a published package can ship the
|
|
44
|
+
* hash of the exact asset it carries — or leave it absent and the
|
|
45
|
+
* artifact cache politely refuses to key on translator identity
|
|
46
|
+
* (cache/core.ts).
|
|
47
|
+
*/
|
|
48
|
+
static fromExports(exports: object, opts?: {
|
|
49
|
+
buildHash?: string;
|
|
50
|
+
}): Translator;
|
|
51
|
+
/** Translate a component binary into plan v0 + adapter artifacts. */
|
|
52
|
+
translate(componentBytes: Uint8Array): TranslationResult;
|
|
53
|
+
/** Translate, returning the raw envelope JSON without validation. */
|
|
54
|
+
translateRaw(componentBytes: Uint8Array): string;
|
|
55
|
+
}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { Table } from "../cabi/handles.js";
|
|
2
|
+
import type { ComponentInstanceLike } from "../cabi/context.js";
|
|
3
|
+
import type { ComponentValue, FuncType } from "../cabi/types.js";
|
|
4
|
+
import { type Cancelled, Store } from "./scheduler.js";
|
|
5
|
+
import { Thread } from "./thread.js";
|
|
6
|
+
import { Waitable, WaitableSet } from "./waitable.js";
|
|
7
|
+
import { Subtask } from "./subtask.js";
|
|
8
|
+
export * from "./scheduler.js";
|
|
9
|
+
export * from "./thread.js";
|
|
10
|
+
export * from "./waitable.js";
|
|
11
|
+
export * from "./subtask.js";
|
|
12
|
+
export * from "./streams.js";
|
|
13
|
+
/** Constructor marker: "this one IS the root, do not give it a parent". */
|
|
14
|
+
declare const ROOT_TOKEN: unique symbol;
|
|
15
|
+
/** Anything a component instance's handle table can hold. */
|
|
16
|
+
export type HandleTableEntry = unknown;
|
|
17
|
+
/**
|
|
18
|
+
* Per-component-instance runtime state (definitions.py `ComponentInstance`,
|
|
19
|
+
* line 191).
|
|
20
|
+
*
|
|
21
|
+
* `mayLeave` is backed by a real `WebAssembly.Global(i32, mutable)` because
|
|
22
|
+
* FACT adapters import that global (`flags` namespace) and read/write it as
|
|
23
|
+
* the may_leave boolean (wasmtime 47 FACT treats the whole flags global as
|
|
24
|
+
* may_leave; there is no bitmask). Initial value 1 (true). `mayEnter` is
|
|
25
|
+
* host-side state: nothing wasm-visible reads it.
|
|
26
|
+
*/
|
|
27
|
+
export declare class ComponentInstanceState implements ComponentInstanceLike {
|
|
28
|
+
readonly index: number;
|
|
29
|
+
readonly flags: WebAssembly.Global;
|
|
30
|
+
handles: Table<HandleTableEntry>;
|
|
31
|
+
/** definitions.py `ComponentInstance.threads` — a Table, so `thread.index`. */
|
|
32
|
+
readonly threads: Table<Thread>;
|
|
33
|
+
mayEnter: boolean;
|
|
34
|
+
/** definitions.py `backpressure: int` — a *counter* (backpressure.{inc,dec}). */
|
|
35
|
+
backpressure: number;
|
|
36
|
+
/** definitions.py `num_waiting_to_enter`. */
|
|
37
|
+
numWaitingToEnter: number;
|
|
38
|
+
/** definitions.py `exclusive_thread`. */
|
|
39
|
+
exclusiveThread: Thread | null;
|
|
40
|
+
/**
|
|
41
|
+
* definitions.py `ComponentInstance.parent`.
|
|
42
|
+
*
|
|
43
|
+
* The plan still gives us a flat instance space, but the tree is no longer
|
|
44
|
+
* needed: every instance of one instantiation gets the same **synthetic
|
|
45
|
+
* root** as its parent (contracts/plan-format.md v3 amendment 4 /
|
|
46
|
+
* polyengine#101). See `enteringSet` for why that is observably equivalent to
|
|
47
|
+
* the real chain. The root itself has no parent.
|
|
48
|
+
*/
|
|
49
|
+
parent: ComponentInstanceState | null;
|
|
50
|
+
readonly store: Store;
|
|
51
|
+
/**
|
|
52
|
+
* The synthetic per-instantiation root (v3 amendment 4). One per `Store`:
|
|
53
|
+
* a `Store` is exactly one component instantiation's scheduling scope, so
|
|
54
|
+
* "all `ComponentInstanceState`s sharing a `Store`" is the set that shares
|
|
55
|
+
* a top-level component — which is the granularity wasmtime's own
|
|
56
|
+
* top-level-instance-id comparison uses (concurrent.rs:1876-1886).
|
|
57
|
+
*
|
|
58
|
+
* It is a real `ComponentInstanceState` (index -1) rather than a bare flag
|
|
59
|
+
* so it flows through `selfAndAncestors`/`enteringSet` unchanged; its
|
|
60
|
+
* handle table stays empty and no task ever runs on it.
|
|
61
|
+
*/
|
|
62
|
+
static rootOf(store: Store): ComponentInstanceState;
|
|
63
|
+
/** Is this the synthetic root (never a real component instance)? */
|
|
64
|
+
get isSyntheticRoot(): boolean;
|
|
65
|
+
constructor(index: number, store?: Store, root?: typeof ROOT_TOKEN);
|
|
66
|
+
/**
|
|
67
|
+
* Release the synthetic root after a trap broke the enter/leave bracket
|
|
68
|
+
* (v3 amendment 4, and a **named divergence** from the reference).
|
|
69
|
+
*
|
|
70
|
+
* definitions.py poisons the whole entering set: `Store.lift` never reaches
|
|
71
|
+
* `leave_to`, so the root — which is in every host entry's entering set —
|
|
72
|
+
* stays `may_enter == False` forever and NO instance of the component can
|
|
73
|
+
* be entered again. wasmtime is the same by other means (it poisons the
|
|
74
|
+
* store). polyengine deliberately supports post-trap re-entry of instances the
|
|
75
|
+
* trap did not touch (exec/boundary.ts `poison`: "sibling instances stay
|
|
76
|
+
* usable, which is why the lock is released per-instance rather than by
|
|
77
|
+
* poisoning a whole store the way wasmtime does"), and the synthetic root
|
|
78
|
+
* must not silently convert that documented divergence into store-wide
|
|
79
|
+
* poisoning. So a trap poisons the LEAF set only, and the root is released
|
|
80
|
+
* here — the reentrance gate the root exists for (a *second, concurrent*
|
|
81
|
+
* host entry) is about a live entry, and after a trap unwinds to the host
|
|
82
|
+
* there is none.
|
|
83
|
+
*/
|
|
84
|
+
releaseSyntheticRootOnPoison(): void;
|
|
85
|
+
get mayLeave(): boolean;
|
|
86
|
+
set mayLeave(v: boolean);
|
|
87
|
+
/** definitions.py `ComponentInstance.self_and_ancestors` (line 236). */
|
|
88
|
+
selfAndAncestors(): Set<ComponentInstanceState>;
|
|
89
|
+
/**
|
|
90
|
+
* definitions.py `ComponentInstance.entering_set` (line 230):
|
|
91
|
+
* `self_and_ancestors() - caller.self_and_ancestors()`.
|
|
92
|
+
*
|
|
93
|
+
* CONTRACT (contracts/plan-format.md v3 amendment 4, polyengine#101): the plan
|
|
94
|
+
* still carries no wire form for the component-instance tree, and it no
|
|
95
|
+
* longer needs one. Every instance's parent is the synthetic
|
|
96
|
+
* per-instantiation root, so:
|
|
97
|
+
*
|
|
98
|
+
* * host entry (`caller === null`): `{this, root}` — the reference's
|
|
99
|
+
* entering set for a host entry is `self_and_ancestors()`, which always
|
|
100
|
+
* contains the top-level root, so a second host entry anywhere in the
|
|
101
|
+
* tree trips on the root either way. This is the divergence #101
|
|
102
|
+
* reported (host -> A.f -> host import -> host enters a *different*
|
|
103
|
+
* instance): now caught.
|
|
104
|
+
* * guest-to-guest (`caller !== null`): `{this}` — the root is in the
|
|
105
|
+
* caller's ancestor set and cancels out. Intermediate ancestors would
|
|
106
|
+
* be the only difference from the real chain, and they are never
|
|
107
|
+
* reachably consulted: FACT compiles same-instance and ancestor calls
|
|
108
|
+
* to unconditional compile-time traps, and sibling cycles are
|
|
109
|
+
* unreachable because instance imports form a DAG (polyengine#99
|
|
110
|
+
* adjudication).
|
|
111
|
+
*
|
|
112
|
+
* So the synthetic root is observably equivalent to the full chain, and it
|
|
113
|
+
* matches wasmtime's own shortcut — a top-level instance-id comparison
|
|
114
|
+
* (concurrent.rs:1876-1886) — by construction. This reopens only if some
|
|
115
|
+
* future upstream shape makes nesting depth observable.
|
|
116
|
+
*
|
|
117
|
+
* One deliberate departure remains, at the trap path rather than here: see
|
|
118
|
+
* `releaseSyntheticRootOnPoison`.
|
|
119
|
+
*/
|
|
120
|
+
enteringSet(caller: ComponentInstanceState | null): Set<ComponentInstanceState>;
|
|
121
|
+
/** definitions.py `ComponentInstance.may_enter_from` (line 214). */
|
|
122
|
+
mayEnterFrom(caller: ComponentInstanceState | null): boolean;
|
|
123
|
+
/** definitions.py `ComponentInstance.enter_from` (line 220). */
|
|
124
|
+
enterFrom(caller: ComponentInstanceState | null): void;
|
|
125
|
+
/** definitions.py `ComponentInstance.leave_to` (line 225). */
|
|
126
|
+
leaveTo(caller: ComponentInstanceState | null): void;
|
|
127
|
+
/** Backwards-compatible host-entry helpers (the M0 spelling). */
|
|
128
|
+
enter(): void;
|
|
129
|
+
leave(): void;
|
|
130
|
+
}
|
|
131
|
+
/** definitions.py `Task.State` (line 445). */
|
|
132
|
+
export type TaskState = "initial" | "started" | "pending-cancel" | "cancel-delivered" | "resolved";
|
|
133
|
+
export type OnStart = () => ComponentValue[];
|
|
134
|
+
export type OnResolve = (result: ComponentValue[] | null) => void;
|
|
135
|
+
/**
|
|
136
|
+
* Canonical options as the task model needs to see them (definitions.py
|
|
137
|
+
* `Task.opts`): only the two flags that change task *semantics*.
|
|
138
|
+
*/
|
|
139
|
+
export interface TaskOptions {
|
|
140
|
+
async_: boolean;
|
|
141
|
+
callback: boolean;
|
|
142
|
+
/**
|
|
143
|
+
* The two fields definitions.py's `LiftOptions.equal` (line 643) compares.
|
|
144
|
+
* `canon_task_return` requires the options at the `task.return` site to
|
|
145
|
+
* equal the ones the task was lifted with, so the task has to remember
|
|
146
|
+
* them.
|
|
147
|
+
*/
|
|
148
|
+
stringEncoding: string;
|
|
149
|
+
memory: unknown | null;
|
|
150
|
+
}
|
|
151
|
+
/** definitions.py `LiftOptions.equal` (line 643): encoding + memory identity. */
|
|
152
|
+
export declare function liftOptionsEqual(a: {
|
|
153
|
+
stringEncoding: string;
|
|
154
|
+
memory: unknown | null;
|
|
155
|
+
}, b: {
|
|
156
|
+
stringEncoding: string;
|
|
157
|
+
memory: unknown | null;
|
|
158
|
+
}): boolean;
|
|
159
|
+
export declare class Task {
|
|
160
|
+
ft: FuncType;
|
|
161
|
+
opts: TaskOptions;
|
|
162
|
+
inst: ComponentInstanceState;
|
|
163
|
+
onStart: OnStart;
|
|
164
|
+
onResolve: OnResolve;
|
|
165
|
+
state: TaskState;
|
|
166
|
+
/** TaskBorrowScope (cabi/context.ts): live borrows lowered into this task. */
|
|
167
|
+
numBorrows: number;
|
|
168
|
+
implicitThread: Thread | null;
|
|
169
|
+
readonly threads: Thread[];
|
|
170
|
+
/**
|
|
171
|
+
* True for a task created by a FACT cross-component call
|
|
172
|
+
* (`prepare-call`, see intrinsics/fact_calls.ts).
|
|
173
|
+
*
|
|
174
|
+
* Such a task's `onStart` / `onResolve` carry **flat core values**, not
|
|
175
|
+
* lifted component values: FACT fuses the caller-side lift and callee-side
|
|
176
|
+
* lower into a pair of adapter functions (`[async-start]` / `[async-return]`)
|
|
177
|
+
* that run *in wasm*, so the host only shuttles the core values between
|
|
178
|
+
* them. definitions.py has no analogue because it has no fused adapters —
|
|
179
|
+
* there, `canon_lift` lowers the params and `canon_lower`'s `on_resolve`
|
|
180
|
+
* lifts the results, both in the host. The observable semantics are
|
|
181
|
+
* identical; only which side of the boundary performs the copy differs.
|
|
182
|
+
*
|
|
183
|
+
* `canon_task_return` consults this to decide whether to lift its flat
|
|
184
|
+
* arguments (host-boundary task) or pass them straight through (FACT task).
|
|
185
|
+
*/
|
|
186
|
+
factPassthrough: boolean;
|
|
187
|
+
/**
|
|
188
|
+
* Plan v3: does `ft.results` hold this FACT task's *declared* result type?
|
|
189
|
+
*
|
|
190
|
+
* A FACT callee task's result type arrives as the raw wasmtime
|
|
191
|
+
* `TypeTupleIndex` `prepare-call` passes as `task_return_type`; v3's
|
|
192
|
+
* `task-return.results` / `resultType` pair is the dictionary for it
|
|
193
|
+
* (contracts/plan-format.md v3 amendment 3). It resolves for every callee
|
|
194
|
+
* that has a `task.return` trampoline of its own — which is every callee
|
|
195
|
+
* that can call `task.return` — but a callee with none (sync-lifted,
|
|
196
|
+
* reached through an async-to-sync adapter) contributes no entry, and then
|
|
197
|
+
* `ft.results` is the empty placeholder it was before v3. Only when this is
|
|
198
|
+
* true may `canon_task_return` compare against it.
|
|
199
|
+
*/
|
|
200
|
+
factResultTypesKnown: boolean;
|
|
201
|
+
/**
|
|
202
|
+
* In-flight FACT sync-call brackets for THIS task
|
|
203
|
+
* (`enter-sync-call`/`exit-sync-call`).
|
|
204
|
+
*
|
|
205
|
+
* MOVED to `Thread` (see `Thread.syncCallStack`). Per-task was already an
|
|
206
|
+
* improvement on per-executor, but it is still not the right unit: a task
|
|
207
|
+
* can own several threads, so one activation's `exit-sync-call` could pop a
|
|
208
|
+
* sibling activation's scope. Tracing big-interleaving showed exactly that
|
|
209
|
+
* -- tasks whose `enter` count exceeded their `exit` count by one, and other
|
|
210
|
+
* tasks taking an `exit` at depth 0, with the `ctx` fallback never firing.
|
|
211
|
+
*
|
|
212
|
+
* The bracket belongs to the ACTIVATION that opened it: FACT emits the
|
|
213
|
+
* matching `enter-sync-call` and `exit-sync-call` from the same wasm
|
|
214
|
+
* activation by construction, so riding the activation identity makes the
|
|
215
|
+
* exit find the same stack the enter used no matter which task the scheduler
|
|
216
|
+
* considers current in between (the 3i bracket-spans-suspension ruling).
|
|
217
|
+
*/
|
|
218
|
+
constructor(ft: FuncType, opts: TaskOptions, inst: ComponentInstanceState, onStart: OnStart, onResolve: OnResolve);
|
|
219
|
+
/**
|
|
220
|
+
* definitions.py `Task.needs_exclusive` (line 473): an async-typed task
|
|
221
|
+
* needs the instance's exclusive thread unless it is a *stackful* async
|
|
222
|
+
* lift. Sync-lowered (`not opts.async_`) and callback-ABI tasks both do.
|
|
223
|
+
*/
|
|
224
|
+
needsExclusive(): boolean;
|
|
225
|
+
/**
|
|
226
|
+
* definitions.py `Task.enter_implicit_thread` (line 477) — the backpressure
|
|
227
|
+
* and exclusivity gate, in full.
|
|
228
|
+
*
|
|
229
|
+
* Returns false when the task was cancelled while waiting to enter, in
|
|
230
|
+
* which case the caller must return immediately (the task is already
|
|
231
|
+
* resolved by `cancel()`).
|
|
232
|
+
*/
|
|
233
|
+
enterImplicitThread(thread: Thread): Generator<import("./scheduler.js").BlockRequest, boolean, Cancelled>;
|
|
234
|
+
/** definitions.py `Task.register_thread` (line 497). */
|
|
235
|
+
registerThread(thread: Thread): void;
|
|
236
|
+
/** definitions.py `Task.exit_implicit_thread` (line 503). */
|
|
237
|
+
exitImplicitThread(thread: Thread): void;
|
|
238
|
+
/** definitions.py `Task.unregister_thread` (line 510). */
|
|
239
|
+
unregisterThread(thread: Thread): void;
|
|
240
|
+
/**
|
|
241
|
+
* definitions.py `Task.request_cancellation` (line 519). Delivered to a
|
|
242
|
+
* cancellable thread if one exists and the instance is enterable; otherwise
|
|
243
|
+
* recorded as pending, to be picked up at the next cancellable block point
|
|
244
|
+
* (`deliverPendingCancel`).
|
|
245
|
+
*/
|
|
246
|
+
requestCancellation(caller: ComponentInstanceState | null): void;
|
|
247
|
+
/** definitions.py `Task.deliver_pending_cancel` (line 536). */
|
|
248
|
+
deliverPendingCancel(cancellable: boolean): boolean;
|
|
249
|
+
/** definitions.py `Task.start` (line 542). */
|
|
250
|
+
start(): ComponentValue[];
|
|
251
|
+
/** definitions.py `Task.return_` (line 547). */
|
|
252
|
+
return_(result: ComponentValue[]): void;
|
|
253
|
+
/** definitions.py `Task.cancel` (line 554). */
|
|
254
|
+
cancel(): void;
|
|
255
|
+
}
|
|
256
|
+
/** Convenience re-exports so `../task/mod.ts` remains the single entry point. */
|
|
257
|
+
export { Store, Subtask, Thread, Waitable, WaitableSet };
|