@polyengine/runtime 0.4.0-pre.g28b13d2 → 0.4.0-pre.g7fb65ed
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/esm/cabi/context.js +22 -5
- package/esm/embedder/mod.js +1 -1
- package/esm/embedder/resources.js +14 -1
- package/esm/embedder/streams.js +16 -1
- package/esm/embedder/values.js +14 -5
- package/package.json +1 -1
- package/types/cabi/context.d.ts +7 -4
- package/types/embedder/mod.d.ts +1 -1
- package/types/embedder/resources.d.ts +1 -0
package/esm/cabi/context.js
CHANGED
|
@@ -26,15 +26,32 @@ export class LiftLowerContext {
|
|
|
26
26
|
this.borrowScope = borrowScope;
|
|
27
27
|
}
|
|
28
28
|
/**
|
|
29
|
-
* definitions.py `LiftLowerContext.reallocate
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
29
|
+
* definitions.py `LiftLowerContext.reallocate`: the guest's realloc runs
|
|
30
|
+
* with `may_leave` cleared, so a realloc that lowers an import traps
|
|
31
|
+
* (`canon_lower`'s `trap_if(not ...may_leave)`, implemented here by
|
|
32
|
+
* exec/boundary.ts `createLoweredImport`). That bracket is implemented
|
|
33
|
+
* below. What remains deferred is only the reference's routing of the call
|
|
34
|
+
* through `canon_lift`; upstream component-model PR #705 removes that
|
|
35
|
+
* routing, leaving this bracket as the whole story. polyengine issue #147.
|
|
33
36
|
*/
|
|
34
37
|
reallocate(old, oldByteLength, alignment, newByteLength) {
|
|
35
38
|
const realloc = this.opts.realloc;
|
|
36
39
|
trapIf(realloc === null, "realloc required but not provided");
|
|
37
|
-
|
|
40
|
+
// A null instance is the value-interpreter unit-test harness only
|
|
41
|
+
// (tests/support/driver.ts `mkCx`); every real runtime path constructs
|
|
42
|
+
// this context with an instance, so there is no flag to bracket.
|
|
43
|
+
if (this.inst === null) {
|
|
44
|
+
return realloc(old, oldByteLength, alignment, newByteLength);
|
|
45
|
+
}
|
|
46
|
+
assert_(this.inst.mayLeave, "realloc with may_leave already false");
|
|
47
|
+
this.inst.mayLeave = false;
|
|
48
|
+
// NO try/finally, deliberately: same bare bracket as the post-return one
|
|
49
|
+
// in intrinsics/fact_calls.ts (#91) and the reference's `assert`/restore
|
|
50
|
+
// pair. A trapping realloc skips the restore exactly as the reference
|
|
51
|
+
// does; the host-boundary unwind and instance poisoning handle the rest.
|
|
52
|
+
const ptr = realloc(old, oldByteLength, alignment, newByteLength);
|
|
53
|
+
this.inst.mayLeave = true;
|
|
54
|
+
return ptr;
|
|
38
55
|
}
|
|
39
56
|
allocate(alignment, byteLength) {
|
|
40
57
|
return this.reallocate(0, 0, alignment, byteLength);
|
package/esm/embedder/mod.js
CHANGED
|
@@ -25,7 +25,7 @@ export { COPY_URL, RUNTIME_VERSION } from "./copy.js";
|
|
|
25
25
|
// The A9 vocabulary, re-exported unchanged: embedder code needs no import
|
|
26
26
|
// change, and consumers that want the multi-copy-robust spellings get them
|
|
27
27
|
// from the same module they already import.
|
|
28
|
-
export { copyCensus, DROPPED, ERROR_CONTEXT, FUTURE, hasBrand, INVALID_HANDLE, isDroppedError, isInvalidHandleError, isPeerTrappedError, isStreamProducerError, isSuspending, isTrap, isComponentException, PEER_TRAPPED, PROTOCOL_GENERATION, registerRuntimeCopy, RESOURCE_STATE, runtimeCopies, STREAM, STREAM_PRODUCER, SUSPENDING, TRAP, COMPONENT_EXCEPTION, } from "@polyengine/protocol";
|
|
28
|
+
export { copyCensus, defineRealmLocal, DROPPED, ERROR_CONTEXT, fromCloneable, FUTURE, hasBrand, INVALID_HANDLE, isDroppedError, isInvalidHandleError, isPeerTrappedError, isRealmLocal, isStreamProducerError, isSuspending, isTrap, isComponentException, PEER_TRAPPED, PROTOCOL_GENERATION, REALM_LOCAL, registerRuntimeCopy, RESOURCE_STATE, runtimeCopies, STREAM, STREAM_PRODUCER, SUSPENDING, toCloneable, TRAP, COMPONENT_EXCEPTION, } from "@polyengine/protocol";
|
|
29
29
|
export { artifactsFromEnvelope, instantiate, instantiateEmbedder, resolveArtifacts, } from "./instantiate.js";
|
|
30
30
|
export { requiredImports } from "./imports.js";
|
|
31
31
|
export { DroppedError, InvalidHandleError, NameCollisionError, PeerTrappedError, Trap, ComponentException, } from "./errors.js";
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
// | host receives borrow<R> | wrapper valid for the call | instance, mapping kept |
|
|
15
15
|
// | host passes own<R> | wrapper invalidated | instance registered |
|
|
16
16
|
// | host passes borrow<R> | wrapper stays valid | rep reused/allocated |
|
|
17
|
-
import { RESOURCE_STATE } from "@polyengine/protocol";
|
|
17
|
+
import { defineRealmLocal, RESOURCE_STATE } from "@polyengine/protocol";
|
|
18
18
|
import { hostDtorCall } from "../exec/boundary.js";
|
|
19
19
|
import { COPY_URL, describeCrossCopy } from "./copy.js";
|
|
20
20
|
import { InvalidHandleError } from "./errors.js";
|
|
@@ -33,6 +33,16 @@ import { camelCase, pascalCase } from "./casing.js";
|
|
|
33
33
|
const STATE = RESOURCE_STATE;
|
|
34
34
|
/** Base of every runtime-built guest-resource class. */
|
|
35
35
|
export class GuestResource {
|
|
36
|
+
constructor() {
|
|
37
|
+
// A20 (contracts/embedder-api.md §"Realm boundaries and
|
|
38
|
+
// structured-clone-safe forms"; issue #131): guest-resource wrappers are
|
|
39
|
+
// realm-local by principle (their machinery lives in the minting
|
|
40
|
+
// copy's tables, issue #129's identity rule) — the pill makes a raw
|
|
41
|
+
// structuredClone/postMessage of one throw instead of husking. NOTE:
|
|
42
|
+
// `makeWrapper` below mints via `Object.create`, which bypasses this
|
|
43
|
+
// constructor entirely — it installs the pill itself.
|
|
44
|
+
defineRealmLocal(this);
|
|
45
|
+
}
|
|
36
46
|
/** Drop the handle (alias of `[Symbol.dispose]`, so TS `using` works). */
|
|
37
47
|
drop() {
|
|
38
48
|
dropWrapper(this);
|
|
@@ -313,6 +323,9 @@ export function makeWrapper(
|
|
|
313
323
|
// deno-lint-ignore no-explicit-any
|
|
314
324
|
cls, rep, rt, owns) {
|
|
315
325
|
const w = Object.create(cls.prototype);
|
|
326
|
+
// A20: `Object.create` bypasses `GuestResource`'s constructor, so the
|
|
327
|
+
// realm-local pill is installed explicitly here (see that constructor).
|
|
328
|
+
defineRealmLocal(w);
|
|
316
329
|
initWrapper(w, {
|
|
317
330
|
rep,
|
|
318
331
|
valid: true,
|
package/esm/embedder/streams.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { despecialize } from "../cabi/types.js";
|
|
11
11
|
import { hostFuture, hostFutureFor, hostStream, hostStreamFor, } from "../exec/host_streams.js";
|
|
12
12
|
import { CopyResult, dropSharedForTeardown, poisonFailureOf, } from "../task/mod.js";
|
|
13
|
-
import { defineBrand, ERROR_CONTEXT, FUTURE, hasBrand, isStreamProducerError, STREAM, StreamProducerError, } from "@polyengine/protocol";
|
|
13
|
+
import { defineBrand, defineRealmLocal, ERROR_CONTEXT, FUTURE, hasBrand, isStreamProducerError, STREAM, StreamProducerError, } from "@polyengine/protocol";
|
|
14
14
|
import { describeCrossCopy } from "./copy.js";
|
|
15
15
|
import { DroppedError, PeerTrappedError } from "./errors.js";
|
|
16
16
|
// `StreamProducerError`'s canonical definition moved to `@polyengine/protocol`
|
|
@@ -102,6 +102,11 @@ export class Stream {
|
|
|
102
102
|
constructor(host, codec) {
|
|
103
103
|
this.#host = host;
|
|
104
104
|
this.#codec = codec;
|
|
105
|
+
// A20 (contracts/embedder-api.md §"Realm boundaries and
|
|
106
|
+
// structured-clone-safe forms"; issue #131): the realm-local pill —
|
|
107
|
+
// stateful handles must fail loud (DataCloneError) at a raw
|
|
108
|
+
// structuredClone/postMessage instead of husking silently.
|
|
109
|
+
defineRealmLocal(this);
|
|
105
110
|
}
|
|
106
111
|
/** Wrap a stream value that was lifted out of a guest. */
|
|
107
112
|
static fromLifted(value, codec) {
|
|
@@ -295,6 +300,8 @@ export class StreamWriter {
|
|
|
295
300
|
#stream;
|
|
296
301
|
constructor(stream) {
|
|
297
302
|
this.#stream = stream;
|
|
303
|
+
// A20 realm-local pill (see Stream's constructor above for rationale).
|
|
304
|
+
defineRealmLocal(this);
|
|
298
305
|
}
|
|
299
306
|
/**
|
|
300
307
|
* Offer values; resolves with how many the reader took.
|
|
@@ -376,6 +383,8 @@ export class Future {
|
|
|
376
383
|
this.#host = host;
|
|
377
384
|
this.#hostP = hostP;
|
|
378
385
|
this.#codec = codec;
|
|
386
|
+
// A20 realm-local pill (see Stream's constructor above for rationale).
|
|
387
|
+
defineRealmLocal(this);
|
|
379
388
|
}
|
|
380
389
|
static fromLifted(value, codec) {
|
|
381
390
|
const h = hostFutureFor(value);
|
|
@@ -527,6 +536,12 @@ export class ErrorContext {
|
|
|
527
536
|
constructor(internal) {
|
|
528
537
|
this.internal = internal;
|
|
529
538
|
this.message = internal.debugMessage;
|
|
539
|
+
// A20 realm-local pill (see Stream's constructor above for rationale).
|
|
540
|
+
// Note: envelope-encodable brands take precedence over the pill at
|
|
541
|
+
// toCloneable time (ErrorContext carries both ERROR_CONTEXT and the
|
|
542
|
+
// pill; it encodes) — the pill here is only the backstop for raw
|
|
543
|
+
// structuredClone/postMessage that skips toCloneable.
|
|
544
|
+
defineRealmLocal(this);
|
|
530
545
|
}
|
|
531
546
|
}
|
|
532
547
|
// A9 brands (contracts/embedder-api.md §"Module identity"): the three
|
package/esm/embedder/values.js
CHANGED
|
@@ -263,11 +263,20 @@ export function fromHost(v, t, o, inOption = false) {
|
|
|
263
263
|
}
|
|
264
264
|
if (v instanceof InternalErrorContext)
|
|
265
265
|
return v;
|
|
266
|
-
//
|
|
267
|
-
//
|
|
268
|
-
//
|
|
269
|
-
//
|
|
270
|
-
//
|
|
266
|
+
// A20 (contracts/embedder-api.md §"Error-context is message-valued";
|
|
267
|
+
// issue #131; definitions.py — an error-context's state is exactly
|
|
268
|
+
// its debug message): a branded carrier of a string `message`, from
|
|
269
|
+
// any copy (or hand-rolled), is accepted by minting a FRESH local
|
|
270
|
+
// context — never "the same" one, since there is nothing to alias.
|
|
271
|
+
if (hasBrand(v, ERROR_CONTEXT) &&
|
|
272
|
+
typeof v.message === "string") {
|
|
273
|
+
return new InternalErrorContext(v.message);
|
|
274
|
+
}
|
|
275
|
+
// Branded but no string `message` (amendment A9, superseded above only
|
|
276
|
+
// for the message-valued case): a genuinely foreign stateful handle —
|
|
277
|
+
// it lives in another copy's handle table, so it can never be lowered
|
|
278
|
+
// here — but "recognized and named" beats the generic "expected an
|
|
279
|
+
// ErrorContext" that sent issue #83 hunting in the wrong direction.
|
|
271
280
|
if (hasBrand(v, ERROR_CONTEXT)) {
|
|
272
281
|
throw new TypeError(`${o.where}: ${describeCrossCopy("this error-context")}`);
|
|
273
282
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polyengine/runtime",
|
|
3
|
-
"version": "0.4.0-pre.
|
|
3
|
+
"version": "0.4.0-pre.g7fb65ed",
|
|
4
4
|
"description": "A WebAssembly Component Model host for JavaScript engines: plan executor, canonical ABI, 0.3 task scheduler, JSPI bridge, and embedder API.",
|
|
5
5
|
"homepage": "https://github.com/polymorph-components/polyengine#readme",
|
|
6
6
|
"repository": {
|
package/types/cabi/context.d.ts
CHANGED
|
@@ -49,10 +49,13 @@ export declare class LiftLowerContext {
|
|
|
49
49
|
borrowScope: SubtaskBorrowScope | TaskBorrowScope | null;
|
|
50
50
|
constructor(opts: LiftLowerOptions, inst?: ComponentInstanceLike | null, borrowScope?: SubtaskBorrowScope | TaskBorrowScope | null);
|
|
51
51
|
/**
|
|
52
|
-
* definitions.py `LiftLowerContext.reallocate
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
52
|
+
* definitions.py `LiftLowerContext.reallocate`: the guest's realloc runs
|
|
53
|
+
* with `may_leave` cleared, so a realloc that lowers an import traps
|
|
54
|
+
* (`canon_lower`'s `trap_if(not ...may_leave)`, implemented here by
|
|
55
|
+
* exec/boundary.ts `createLoweredImport`). That bracket is implemented
|
|
56
|
+
* below. What remains deferred is only the reference's routing of the call
|
|
57
|
+
* through `canon_lift`; upstream component-model PR #705 removes that
|
|
58
|
+
* routing, leaving this bracket as the whole story. polyengine issue #147.
|
|
56
59
|
*/
|
|
57
60
|
reallocate(old: number, oldByteLength: number, alignment: number, newByteLength: number): number;
|
|
58
61
|
allocate(alignment: number, byteLength: number): number;
|
package/types/embedder/mod.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { COPY_URL, RUNTIME_VERSION } from "./copy.js";
|
|
2
|
-
export { copyCensus, DROPPED, ERROR_CONTEXT, FUTURE, hasBrand, INVALID_HANDLE, isDroppedError, isInvalidHandleError, isPeerTrappedError, isStreamProducerError, isSuspending, isTrap, isComponentException, PEER_TRAPPED, PROTOCOL_GENERATION, registerRuntimeCopy, RESOURCE_STATE, type RuntimeCopy, runtimeCopies, STREAM, STREAM_PRODUCER, SUSPENDING, TRAP, COMPONENT_EXCEPTION, } from "@polyengine/protocol";
|
|
2
|
+
export { copyCensus, defineRealmLocal, DROPPED, ERROR_CONTEXT, fromCloneable, FUTURE, hasBrand, INVALID_HANDLE, isDroppedError, isInvalidHandleError, isPeerTrappedError, isRealmLocal, isStreamProducerError, isSuspending, isTrap, isComponentException, PEER_TRAPPED, PROTOCOL_GENERATION, REALM_LOCAL, registerRuntimeCopy, RESOURCE_STATE, type RuntimeCopy, runtimeCopies, STREAM, STREAM_PRODUCER, SUSPENDING, toCloneable, TRAP, COMPONENT_EXCEPTION, } from "@polyengine/protocol";
|
|
3
3
|
export { artifactsFromEnvelope, type ComponentArtifacts, type EmbedderInstance, type EmbedderOptions, type InstantiateSource, type UntranslatedArtifacts, instantiate, instantiateEmbedder, resolveArtifacts, } from "./instantiate.js";
|
|
4
4
|
export { type FuncSummary, type ImportLeaf, type PlanLike, requiredImports } from "./imports.js";
|
|
5
5
|
export { DroppedError, InvalidHandleError, NameCollisionError, PeerTrappedError, Trap, ComponentException, } from "./errors.js";
|
|
@@ -48,6 +48,7 @@ interface WrapperState {
|
|
|
48
48
|
/** Base of every runtime-built guest-resource class. */
|
|
49
49
|
export declare class GuestResource {
|
|
50
50
|
[STATE]: WrapperState;
|
|
51
|
+
constructor();
|
|
51
52
|
/** Drop the handle (alias of `[Symbol.dispose]`, so TS `using` works). */
|
|
52
53
|
drop(): void;
|
|
53
54
|
[Symbol.dispose](): void;
|