@hew-lang/sandbox-vm 0.10.0-rc1 → 0.10.0
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/dist/interpreter/run-program.js +4 -0
- package/dist/interpreter/types.d.ts +1 -1
- package/dist/interpreter/v1/browser-directory.js +2 -2
- package/dist/interpreter/v1/codecs.js +2 -2
- package/dist/interpreter/v1/exec.js +144 -46
- package/dist/interpreter/v1/instructions.generated.d.ts +7 -3
- package/dist/interpreter/v1/managed-budget.js +9 -4
- package/dist/interpreter/v1/package-validator.generated.js +828 -619
- package/dist/interpreter/v1/shims.js +44 -44
- package/dist/interpreter/v1/structural.js +4 -2
- package/dist/interpreter/v1/validate.js +2 -1
- package/dist/interpreter/v1/value-operations.js +11 -10
- package/dist/interpreter/values.d.ts +10 -1
- package/dist/interpreter/values.js +65 -9
- package/package.json +4 -4
|
@@ -54,8 +54,10 @@ var SandboxExitCode;
|
|
|
54
54
|
SandboxExitCode[SandboxExitCode["HeapExceeded"] = 200] = "HeapExceeded";
|
|
55
55
|
SandboxExitCode[SandboxExitCode["IntegerOverflow"] = 201] = "IntegerOverflow";
|
|
56
56
|
SandboxExitCode[SandboxExitCode["DivideByZero"] = 202] = "DivideByZero";
|
|
57
|
+
SandboxExitCode[SandboxExitCode["SignedMinDivNegOne"] = 203] = "SignedMinDivNegOne";
|
|
57
58
|
SandboxExitCode[SandboxExitCode["ShiftOutOfRange"] = 204] = "ShiftOutOfRange";
|
|
58
59
|
SandboxExitCode[SandboxExitCode["IndexOutOfBounds"] = 205] = "IndexOutOfBounds";
|
|
60
|
+
SandboxExitCode[SandboxExitCode["StackOverflow"] = 215] = "StackOverflow";
|
|
59
61
|
SandboxExitCode[SandboxExitCode["ActorSendFailed"] = 206] = "ActorSendFailed";
|
|
60
62
|
SandboxExitCode[SandboxExitCode["MachineDispatchUnreachable"] = 207] = "MachineDispatchUnreachable";
|
|
61
63
|
SandboxExitCode[SandboxExitCode["ExhaustivenessFallthrough"] = 208] = "ExhaustivenessFallthrough";
|
|
@@ -66,6 +68,8 @@ const TRAP_EXIT_CODES = {
|
|
|
66
68
|
integer_overflow: SandboxExitCode.IntegerOverflow,
|
|
67
69
|
shift_out_of_range: SandboxExitCode.ShiftOutOfRange,
|
|
68
70
|
divide_by_zero: SandboxExitCode.DivideByZero,
|
|
71
|
+
signed_min_div_neg_one: SandboxExitCode.SignedMinDivNegOne,
|
|
72
|
+
stack_overflow: SandboxExitCode.StackOverflow,
|
|
69
73
|
invalid_local: SandboxExitCode.InternalError,
|
|
70
74
|
invalid_block: SandboxExitCode.InternalError,
|
|
71
75
|
invalid_call: SandboxExitCode.InternalError,
|
|
@@ -2,7 +2,7 @@ export type JsonValue = null | boolean | number | string | JsonValue[] | {
|
|
|
2
2
|
[key: string]: JsonValue;
|
|
3
3
|
};
|
|
4
4
|
export type SandboxBytecodePackage = import("./v1/package.js").PackageV1;
|
|
5
|
-
export type TrapKind = "
|
|
5
|
+
export type TrapKind = import("./v1/package.js").TrapName | "invalid_local" | "invalid_block" | "invalid_call" | "invalid_enum_tag" | "invalid_record_field" | "string_bounds" | "regex_compile" | "capability_missing" | "budget_exhausted" | "panic" | "unsupported_instruction" | "internal_error";
|
|
6
6
|
export type RuntimeStatus = "ok" | "compile_error" | "sandbox_rejected" | "runtime_failure" | "budget_exhausted" | "panic" | "trap";
|
|
7
7
|
export interface RuntimeFailure {
|
|
8
8
|
kind: "panic" | "trap" | "budget_exhausted" | "unsupported" | "internal_error";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { UNIT } from "../values.js";
|
|
1
|
+
import { vectorItems, UNIT } from "../values.js";
|
|
2
2
|
export const DIRECTORY_OPERATIONS = {
|
|
3
3
|
hew_dir_open_read: {
|
|
4
4
|
release: "hew_dir_read_close",
|
|
@@ -250,7 +250,7 @@ export class BrowserDirectories {
|
|
|
250
250
|
const data = args[1];
|
|
251
251
|
if (data?.kind !== "vector")
|
|
252
252
|
throw new Error("file write requires bytes");
|
|
253
|
-
const bytes = Uint8Array.from(data
|
|
253
|
+
const bytes = Uint8Array.from(vectorItems(data), (value) => {
|
|
254
254
|
if (value.kind !== "i64")
|
|
255
255
|
throw new Error("file write requires byte elements");
|
|
256
256
|
return Number(value.value);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { UNIT, stringValue } from "../values.js";
|
|
1
|
+
import { vectorItems, UNIT, stringValue } from "../values.js";
|
|
2
2
|
import { runtimeTag } from "./package.js";
|
|
3
3
|
import { collectionOperation } from "./value-operations.js";
|
|
4
4
|
class DecodeFailure extends Error {
|
|
@@ -19,7 +19,7 @@ function fields(value) {
|
|
|
19
19
|
if (value.kind === "record")
|
|
20
20
|
return value.fields;
|
|
21
21
|
if (value.kind === "vector")
|
|
22
|
-
return value
|
|
22
|
+
return vectorItems(value);
|
|
23
23
|
throw new Error(`codec aggregate received ${value.kind}`);
|
|
24
24
|
}
|
|
25
25
|
function toBridge(pkg, shape, id, value) {
|
|
@@ -11,7 +11,7 @@ import { executeCodec } from "./codecs.js";
|
|
|
11
11
|
import { actorIdentical } from "./actor-identity.js";
|
|
12
12
|
import { ActorWaits } from "./actor-waits.js";
|
|
13
13
|
import { TraceBuilder, runtimeFailure } from "../trace.js";
|
|
14
|
-
import { UNIT, cloneValue, releaseVector, byteVectorValue, vectorStorage, stringValue, toJsonValue, } from "../values.js";
|
|
14
|
+
import { UNIT, cloneValue, releaseVector, byteVectorValue, vectorStorage, vectorItems, vectorLength, vectorElement, stringValue, toJsonValue, } from "../values.js";
|
|
15
15
|
import { runtimeTag, staticOperations } from "./package.js";
|
|
16
16
|
import { StructuralRenderer } from "./structural.js";
|
|
17
17
|
import { timestampBinary } from "./timestamp.js";
|
|
@@ -26,6 +26,11 @@ import { AdmittedPackage } from "./validate.js";
|
|
|
26
26
|
import { HeapExceeded, ManagedBudget, ManagedLayouts, } from "./managed-budget.js";
|
|
27
27
|
const DEFAULT_STEP_BUDGET = 1_000_000;
|
|
28
28
|
const DEFAULT_ACTOR_STOP_NS = 5_000_000_000;
|
|
29
|
+
/// Deepest activation a task may reach below its root before a call fails
|
|
30
|
+
/// with `StackOverflow`. HEW-SPEC-2026 §2.2 guarantees 10,000 frames. Twice
|
|
31
|
+
/// that matches what a native stack admits for small frames and leaves an
|
|
32
|
+
/// unbounded recursion failing well inside the default step budget.
|
|
33
|
+
const MAX_FRAME_DEPTH = 20_000;
|
|
29
34
|
/// Ends the run. The status is already recorded on the trace.
|
|
30
35
|
class Halt extends Error {
|
|
31
36
|
status;
|
|
@@ -404,6 +409,7 @@ class ExecutorV1 {
|
|
|
404
409
|
fault: null,
|
|
405
410
|
parked: [],
|
|
406
411
|
caller,
|
|
412
|
+
depth: caller ? caller.depth + 1 : 0,
|
|
407
413
|
result,
|
|
408
414
|
normal: normal ?? undefined,
|
|
409
415
|
unwind,
|
|
@@ -523,8 +529,8 @@ class ExecutorV1 {
|
|
|
523
529
|
(row.kind === "vector" ||
|
|
524
530
|
row.kind === "array" ||
|
|
525
531
|
row.kind === "slice")
|
|
526
|
-
? value.
|
|
527
|
-
: value
|
|
532
|
+
? vectorItems(value).map((item) => this.managed.copy(item, row.element))
|
|
533
|
+
: vectorItems(value);
|
|
528
534
|
if (appended?.length) {
|
|
529
535
|
if (row.kind !== "vector" &&
|
|
530
536
|
row.kind !== "array" &&
|
|
@@ -538,6 +544,8 @@ class ExecutorV1 {
|
|
|
538
544
|
budget.checkMutation(value, {
|
|
539
545
|
...value,
|
|
540
546
|
items,
|
|
547
|
+
offset: 0,
|
|
548
|
+
length: undefined,
|
|
541
549
|
storage: { ...storage, capacity, items, owners: 1 },
|
|
542
550
|
}, detached);
|
|
543
551
|
}
|
|
@@ -1695,7 +1703,13 @@ class ExecutorV1 {
|
|
|
1695
1703
|
case "checked.binary": {
|
|
1696
1704
|
const failure = checkedFailure(term.binary_op, this.read(act, term.lhs), this.read(act, term.rhs), term.ty);
|
|
1697
1705
|
if (failure) {
|
|
1698
|
-
|
|
1706
|
+
// Earlier v1 packages fold the signed minimum by -1 into their
|
|
1707
|
+
// overflow edge, so they keep the IntegerOverflow trap their
|
|
1708
|
+
// compiler emitted.
|
|
1709
|
+
const edge = term.failures.find((candidate) => candidate.trap === failure) ??
|
|
1710
|
+
(failure === "signed_min_div_neg_one"
|
|
1711
|
+
? term.failures.find((candidate) => candidate.trap === "integer_overflow")
|
|
1712
|
+
: undefined);
|
|
1699
1713
|
if (!edge) {
|
|
1700
1714
|
throw new Error(`checked.binary names no ${failure} edge`);
|
|
1701
1715
|
}
|
|
@@ -1988,6 +2002,26 @@ class ExecutorV1 {
|
|
|
1988
2002
|
tag: deadline ? term.deadline_variant : term.fault_variant,
|
|
1989
2003
|
payload: [stringValue(faultRecoveryMessage(fault))],
|
|
1990
2004
|
};
|
|
2005
|
+
// Scope recovery must preserve the original fault even when the
|
|
2006
|
+
// current actor cannot retain its diagnostic text. Preflight the same
|
|
2007
|
+
// managed graph that completion will retain, then use the canonical
|
|
2008
|
+
// empty string on refusal without publishing an uncharged owner.
|
|
2009
|
+
const result = term.result?.value;
|
|
2010
|
+
const type = result == null ? undefined : act.managedTypes.get(result);
|
|
2011
|
+
const budget = result != null && act.owned.has(result)
|
|
2012
|
+
? act.context.actor?.budget
|
|
2013
|
+
: undefined;
|
|
2014
|
+
if (budget && type != null) {
|
|
2015
|
+
try {
|
|
2016
|
+
this.managed.stampGraph({ value, type });
|
|
2017
|
+
budget.check([{ value, type }]);
|
|
2018
|
+
}
|
|
2019
|
+
catch (error) {
|
|
2020
|
+
if (!(error instanceof HeapExceeded))
|
|
2021
|
+
throw error;
|
|
2022
|
+
value.payload[0] = stringValue("");
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
1991
2025
|
act.fault = null;
|
|
1992
2026
|
if (act.context.actor)
|
|
1993
2027
|
act.context.actor.crashing = null;
|
|
@@ -2359,13 +2393,13 @@ class ExecutorV1 {
|
|
|
2359
2393
|
if (operation === "Len") {
|
|
2360
2394
|
this.completeShim(act, term, {
|
|
2361
2395
|
kind: "i64",
|
|
2362
|
-
value: BigInt(view
|
|
2396
|
+
value: BigInt(vectorLength(view)),
|
|
2363
2397
|
});
|
|
2364
2398
|
return;
|
|
2365
2399
|
}
|
|
2366
2400
|
if (index?.kind !== "i64")
|
|
2367
2401
|
throw new Error("pool operation has no index");
|
|
2368
|
-
const value = view
|
|
2402
|
+
const value = vectorElement(view, Number(index.value));
|
|
2369
2403
|
if (operation === "Get") {
|
|
2370
2404
|
this.completeShim(act, term, this.variant(term.result_shape, value ? "OptionSome" : "OptionNone", value ? [value] : []));
|
|
2371
2405
|
return;
|
|
@@ -2402,7 +2436,7 @@ class ExecutorV1 {
|
|
|
2402
2436
|
}, (fault) => {
|
|
2403
2437
|
this.raiseFault(act, fault, term.unwind);
|
|
2404
2438
|
this.scheduler.enqueue(act.context.id, () => this.runFrame(act));
|
|
2405
|
-
});
|
|
2439
|
+
}, act.context.actor?.rcOwner ?? null, false, undefined, act);
|
|
2406
2440
|
act.context.cancel = (fault) => callback.cancel?.(fault);
|
|
2407
2441
|
};
|
|
2408
2442
|
continueRendering();
|
|
@@ -3015,6 +3049,16 @@ class ExecutorV1 {
|
|
|
3015
3049
|
return;
|
|
3016
3050
|
}
|
|
3017
3051
|
case "Safepoint": {
|
|
3052
|
+
// A function's entry safepoint is its stack check (HEW-SPEC-2026
|
|
3053
|
+
// §2.2): past the frame limit the call fails with `StackOverflow`
|
|
3054
|
+
// and its parameters follow the cancellation cleanup.
|
|
3055
|
+
if (term.cancel &&
|
|
3056
|
+
act.depth > MAX_FRAME_DEPTH &&
|
|
3057
|
+
act.block.id === act.fn.entry) {
|
|
3058
|
+
act.fault = { kind: "trap", trap: "stack_overflow" };
|
|
3059
|
+
this.takeEdge(act, term.cancel);
|
|
3060
|
+
return;
|
|
3061
|
+
}
|
|
3018
3062
|
if (act.context.pollSuppression) {
|
|
3019
3063
|
this.takeEdge(act, term.resumes[0]);
|
|
3020
3064
|
return;
|
|
@@ -3816,7 +3860,11 @@ class ExecutorV1 {
|
|
|
3816
3860
|
reply: { value: envelope, type: provider.reply },
|
|
3817
3861
|
};
|
|
3818
3862
|
}
|
|
3819
|
-
invokeFrame(actor, callable, args, returned, failed, rcOwner = actor?.rcOwner ?? null, inline = false, retainedBy
|
|
3863
|
+
invokeFrame(actor, callable, args, returned, failed, rcOwner = actor?.rcOwner ?? null, inline = false, retainedBy,
|
|
3864
|
+
// The activation this frame runs on behalf of. Its depth carries on, so a
|
|
3865
|
+
// recursion through runtime callbacks reaches the frame limit as a direct
|
|
3866
|
+
// one does.
|
|
3867
|
+
invoker = retainedBy) {
|
|
3820
3868
|
const context = {
|
|
3821
3869
|
id: actor?.id ?? "actor:root",
|
|
3822
3870
|
actor,
|
|
@@ -3834,6 +3882,8 @@ class ExecutorV1 {
|
|
|
3834
3882
|
},
|
|
3835
3883
|
};
|
|
3836
3884
|
const frame = this.activate(this.functionAt(callable), args, null, null, undefined, null, context);
|
|
3885
|
+
if (invoker)
|
|
3886
|
+
frame.depth = invoker.depth + 1;
|
|
3837
3887
|
retainedBy?.managedChildren.add(frame);
|
|
3838
3888
|
let cancelled = null;
|
|
3839
3889
|
context.cancel = (fault = { kind: "panic", message: "task cancelled", cancelled: true }) => {
|
|
@@ -4374,27 +4424,32 @@ class ExecutorV1 {
|
|
|
4374
4424
|
if (isPool && count?.kind !== "i64")
|
|
4375
4425
|
throw new Error("pool construction has no count");
|
|
4376
4426
|
const configured = isPool ? args.slice(0, -1) : args;
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
const
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4427
|
+
// Config, then each backoff child's `(initial, maximum)` pair in
|
|
4428
|
+
// declaration order.
|
|
4429
|
+
const pairs = layout.children.filter((child) => child.backoff).length;
|
|
4430
|
+
const config = configured.slice(0, configured.length - 2 * pairs);
|
|
4431
|
+
let pair = config.length;
|
|
4432
|
+
const declared = layout.children.map((child) => {
|
|
4433
|
+
if (!child.backoff)
|
|
4434
|
+
return null;
|
|
4435
|
+
const initial = configured[pair];
|
|
4436
|
+
const maximum = configured[pair + 1];
|
|
4437
|
+
pair += 2;
|
|
4438
|
+
return initial?.kind === "i64" && maximum?.kind === "i64"
|
|
4439
|
+
? { initial: initial.value, maximum: maximum.value }
|
|
4440
|
+
: undefined;
|
|
4441
|
+
});
|
|
4442
|
+
const validBackoff = declared.every((backoff) => backoff === null ||
|
|
4443
|
+
(backoff !== undefined &&
|
|
4444
|
+
((backoff.initial === 0n && backoff.maximum === 0n) ||
|
|
4445
|
+
(backoff.initial > 0n && backoff.maximum >= backoff.initial))));
|
|
4391
4446
|
if (!validBackoff ||
|
|
4392
4447
|
(count?.kind === "i64" &&
|
|
4393
4448
|
(count.value <= 0n || count.value > 2147483647n))) {
|
|
4394
4449
|
const fault = {
|
|
4395
4450
|
kind: "panic",
|
|
4396
4451
|
message: !validBackoff
|
|
4397
|
-
? "supervisor backoff requires positive initial and maximum >= initial"
|
|
4452
|
+
? "supervisor backoff requires positive initial and maximum >= initial, or both zero"
|
|
4398
4453
|
: "supervisor pool count must be between 1 and 2147483647",
|
|
4399
4454
|
};
|
|
4400
4455
|
this.running = false;
|
|
@@ -4423,7 +4478,7 @@ class ExecutorV1 {
|
|
|
4423
4478
|
teardownChild: null,
|
|
4424
4479
|
teardownCancelTimer: null,
|
|
4425
4480
|
restartTimes: [],
|
|
4426
|
-
backoff,
|
|
4481
|
+
backoffs: declared.flatMap((backoff) => Array.from({ length: members }, () => backoff ?? null)),
|
|
4427
4482
|
restartDelays: new Map(),
|
|
4428
4483
|
restartTimers: new Map(),
|
|
4429
4484
|
closed: [],
|
|
@@ -5238,7 +5293,9 @@ class ExecutorV1 {
|
|
|
5238
5293
|
? "CrashKindTimerOverdue"
|
|
5239
5294
|
: code === 213
|
|
5240
5295
|
? "CrashKindHandlerFailed"
|
|
5241
|
-
:
|
|
5296
|
+
: code === 215
|
|
5297
|
+
? "CrashKindStackOverflow"
|
|
5298
|
+
: "CrashKindFault"),
|
|
5242
5299
|
payload: [],
|
|
5243
5300
|
},
|
|
5244
5301
|
stringValue(String(message)),
|
|
@@ -5420,24 +5477,38 @@ class ExecutorV1 {
|
|
|
5420
5477
|
return;
|
|
5421
5478
|
}
|
|
5422
5479
|
if (owner.restartBusy) {
|
|
5423
|
-
owner.pendingRestarts.push({
|
|
5480
|
+
owner.pendingRestarts.push({
|
|
5481
|
+
child,
|
|
5482
|
+
debts,
|
|
5483
|
+
incarnation: owner.children[child] ?? null,
|
|
5484
|
+
});
|
|
5424
5485
|
return;
|
|
5425
5486
|
}
|
|
5426
5487
|
const now = this.trace.virtualTimeMs;
|
|
5427
|
-
|
|
5488
|
+
const backoff = owner.backoffs[child];
|
|
5489
|
+
if (backoff && backoff.initial > 0n && debts.length > 0 && !delayElapsed) {
|
|
5428
5490
|
const previous = owner.restartDelays.get(child);
|
|
5429
5491
|
const healthy = previous?.publishedAt != null &&
|
|
5430
5492
|
now - previous.publishedAt >= owner.layout.window_secs * 1000;
|
|
5431
|
-
const doubled = previous ? previous.delay * 2n :
|
|
5493
|
+
const doubled = previous ? previous.delay * 2n : backoff.initial;
|
|
5432
5494
|
const delay = !previous || healthy
|
|
5433
|
-
?
|
|
5434
|
-
: doubled <
|
|
5495
|
+
? backoff.initial
|
|
5496
|
+
: doubled < backoff.maximum
|
|
5435
5497
|
? doubled
|
|
5436
|
-
:
|
|
5498
|
+
: backoff.maximum;
|
|
5437
5499
|
owner.restartDelays.set(child, { delay, publishedAt: null });
|
|
5438
5500
|
owner.recovering.add(child);
|
|
5439
5501
|
owner.restartTimers.set(child, this.scheduler.after(delay, () => {
|
|
5440
5502
|
owner.restartTimers.delete(child);
|
|
5503
|
+
// A group restart that already replaced this role recovered its
|
|
5504
|
+
// fault; restarting again would tear down a healthy group and
|
|
5505
|
+
// charge the budget twice.
|
|
5506
|
+
if (owner.restartDelays.get(child)?.publishedAt != null) {
|
|
5507
|
+
for (const debt of debts)
|
|
5508
|
+
this.faultDebts.delete(debt);
|
|
5509
|
+
this.wakeRoles();
|
|
5510
|
+
return;
|
|
5511
|
+
}
|
|
5441
5512
|
this.restartChild(owner, child, debts, true);
|
|
5442
5513
|
}));
|
|
5443
5514
|
return;
|
|
@@ -5484,11 +5555,16 @@ class ExecutorV1 {
|
|
|
5484
5555
|
if (index === undefined) {
|
|
5485
5556
|
for (const debt of debts)
|
|
5486
5557
|
this.faultDebts.delete(debt);
|
|
5487
|
-
|
|
5558
|
+
// This group replaced a queued crash's incarnation, which recovers it.
|
|
5559
|
+
// A replacement that crashed after its own publication still needs
|
|
5560
|
+
// its restart.
|
|
5561
|
+
const replaced = (pending) => affected.includes(pending.child) &&
|
|
5562
|
+
owner.children[pending.child] !== pending.incarnation;
|
|
5563
|
+
for (const pending of owner.pendingRestarts.filter(replaced)) {
|
|
5488
5564
|
for (const debt of pending.debts)
|
|
5489
5565
|
this.faultDebts.delete(debt);
|
|
5490
5566
|
}
|
|
5491
|
-
owner.pendingRestarts = owner.pendingRestarts.filter((pending) => !
|
|
5567
|
+
owner.pendingRestarts = owner.pendingRestarts.filter((pending) => !replaced(pending));
|
|
5492
5568
|
owner.restartBusy = false;
|
|
5493
5569
|
this.wakeRoles();
|
|
5494
5570
|
const pending = owner.pendingRestarts.shift();
|
|
@@ -5500,6 +5576,12 @@ class ExecutorV1 {
|
|
|
5500
5576
|
const delay = owner.restartDelays.get(index);
|
|
5501
5577
|
if (delay)
|
|
5502
5578
|
delay.publishedAt = this.trace.virtualTimeMs;
|
|
5579
|
+
// The crashed role's replacement is the recovery that settles its
|
|
5580
|
+
// fault, as natively; a later sibling's cancelled start does not
|
|
5581
|
+
// reopen it.
|
|
5582
|
+
if (index === child)
|
|
5583
|
+
for (const debt of debts)
|
|
5584
|
+
this.faultDebts.delete(debt);
|
|
5503
5585
|
start();
|
|
5504
5586
|
}, () => {
|
|
5505
5587
|
owner.restartBusy = false;
|
|
@@ -5828,15 +5910,19 @@ function faultInfo(fault) {
|
|
|
5828
5910
|
return [-2, "Deadline"];
|
|
5829
5911
|
return [212, "UserPanic"];
|
|
5830
5912
|
}
|
|
5831
|
-
return
|
|
5832
|
-
integer_overflow: [201, "IntegerOverflow"],
|
|
5833
|
-
divide_by_zero: [202, "DivideByZero"],
|
|
5834
|
-
shift_out_of_range: [204, "ShiftOutOfRange"],
|
|
5835
|
-
vector_bounds: [205, "IndexOutOfBounds"],
|
|
5836
|
-
actor_refused: [-4, "Refused"],
|
|
5837
|
-
heap_exceeded: [200, "HeapExceeded"],
|
|
5838
|
-
}[fault.trap];
|
|
5913
|
+
return TRAP_FAULTS[fault.trap];
|
|
5839
5914
|
}
|
|
5915
|
+
/// The native exit reason each package trap reports, as code and name.
|
|
5916
|
+
const TRAP_FAULTS = {
|
|
5917
|
+
integer_overflow: [201, "IntegerOverflow"],
|
|
5918
|
+
divide_by_zero: [202, "DivideByZero"],
|
|
5919
|
+
signed_min_div_neg_one: [203, "SignedMinDivNegOne"],
|
|
5920
|
+
shift_out_of_range: [204, "ShiftOutOfRange"],
|
|
5921
|
+
vector_bounds: [205, "IndexOutOfBounds"],
|
|
5922
|
+
actor_refused: [-4, "Refused"],
|
|
5923
|
+
heap_exceeded: [200, "HeapExceeded"],
|
|
5924
|
+
stack_overflow: [215, "StackOverflow"],
|
|
5925
|
+
};
|
|
5840
5926
|
function faultApplicationMessage(fault) {
|
|
5841
5927
|
return fault.kind === "panic" &&
|
|
5842
5928
|
(fault.cancelled || fault.deadline || fault.timerOverdue)
|
|
@@ -6034,7 +6120,7 @@ function toComparable(value) {
|
|
|
6034
6120
|
case "enum":
|
|
6035
6121
|
return [value.tag, value.payload.map(toComparable)];
|
|
6036
6122
|
case "vector":
|
|
6037
|
-
return value.
|
|
6123
|
+
return vectorItems(value).map(toComparable);
|
|
6038
6124
|
case "rc":
|
|
6039
6125
|
return "Rc";
|
|
6040
6126
|
case "weak":
|
|
@@ -6074,6 +6160,8 @@ function trapMessage(trap) {
|
|
|
6074
6160
|
return "integer overflow";
|
|
6075
6161
|
case "divide_by_zero":
|
|
6076
6162
|
return "divide by zero";
|
|
6163
|
+
case "signed_min_div_neg_one":
|
|
6164
|
+
return "signed minimum divided by -1";
|
|
6077
6165
|
case "shift_out_of_range":
|
|
6078
6166
|
return "shift amount out of range";
|
|
6079
6167
|
case "vector_bounds":
|
|
@@ -6082,6 +6170,8 @@ function trapMessage(trap) {
|
|
|
6082
6170
|
return "delivery refused by interceptor";
|
|
6083
6171
|
case "heap_exceeded":
|
|
6084
6172
|
return "actor heap limit exceeded";
|
|
6173
|
+
case "stack_overflow":
|
|
6174
|
+
return "stack overflow";
|
|
6085
6175
|
}
|
|
6086
6176
|
}
|
|
6087
6177
|
/// The operand type the package records. `isize` and `usize` are 64-bit in the
|
|
@@ -6131,8 +6221,16 @@ function checkedFailure(op, lhs, rhs, ty) {
|
|
|
6131
6221
|
return null;
|
|
6132
6222
|
}
|
|
6133
6223
|
const scalar = intTy(ty);
|
|
6134
|
-
if (
|
|
6135
|
-
|
|
6224
|
+
if (op === "Divide" || op === "Modulo") {
|
|
6225
|
+
if (rhs.value === 0n)
|
|
6226
|
+
return "divide_by_zero";
|
|
6227
|
+
// Both the quotient and the remainder of the signed minimum by -1 trap,
|
|
6228
|
+
// although the remainder alone would be representable.
|
|
6229
|
+
if (scalar.signed &&
|
|
6230
|
+
rhs.value === -1n &&
|
|
6231
|
+
lhs.value === -(1n << (scalar.bits - 1n))) {
|
|
6232
|
+
return "signed_min_div_neg_one";
|
|
6233
|
+
}
|
|
6136
6234
|
}
|
|
6137
6235
|
if ((op === "Shl" || op === "Shr") &&
|
|
6138
6236
|
(rhs.value < 0n || rhs.value >= scalar.bits)) {
|
|
@@ -6316,8 +6414,8 @@ function equals(lhs, rhs) {
|
|
|
6316
6414
|
lhs.payload.every((field, at) => equals(field, rhs.payload[at])));
|
|
6317
6415
|
}
|
|
6318
6416
|
if (lhs.kind === "vector" && rhs.kind === "vector") {
|
|
6319
|
-
return (lhs
|
|
6320
|
-
lhs.
|
|
6417
|
+
return (vectorLength(lhs) === vectorLength(rhs) &&
|
|
6418
|
+
vectorItems(lhs).every((item, at) => equals(item, vectorElement(rhs, at))));
|
|
6321
6419
|
}
|
|
6322
6420
|
return canonical(lhs) === canonical(rhs);
|
|
6323
6421
|
}
|
|
@@ -776,7 +776,7 @@ export type RuntimeCallFamily = {
|
|
|
776
776
|
} | "VecRemoveAtBool" | "VecRemoveAtLayout" | "VecRemoveAtOwned" | "VecSetBool" | "VecSetLayout" | "VecSetOwned" | "VecSetOwnedMove" | {
|
|
777
777
|
VecSliceRange: VecSliceElem;
|
|
778
778
|
} | "VtableDispatchPanicOnOob";
|
|
779
|
-
export type RuntimeVariantRole = "CrashKindFault" | "CrashKindHeapExceeded" | "CrashKindPartitionDetected" | "CrashKindHandlerFailed" | "CrashKindTimerOverdue" | "OptionSome" | "OptionNone" | "ResultOk" | "ResultErr" | "ActorErrorRejected" | "ActorErrorFailed" | "ActorErrorTrapped" | "ActorErrorRefused" | "CallerActor" | "CallerTask" | "CallerTimer" | "CallerNode" | "ActorErrorDead" | "ActorErrorTimedOut" | "ActorErrorNodeNotRunning" | "ActorErrorRoutingFailed" | "ActorErrorEncodeFailed" | "ActorErrorMessageTooLarge" | "ActorErrorConnectionDropped" | "ActorErrorPartition" | "SendErrorFull" | "SendErrorClosed" | "SendErrorPartition" | "SendErrorStaleRef" | "SendErrorLocalShutdown" | "SendErrorCancelled" | "SendErrorVersionMismatch" | "SendErrorBackpressure" | "SendErrorDead" | "SendErrorUnauthorized" | "SendErrorInvalidMessage" | "SendErrorMessageTooLarge" | "SendErrorTimedOut" | "SendErrorWriteTimedOut" | "DeliveryAccepted" | "DeliveryDiscarded" | "LinkErrorNoContext";
|
|
779
|
+
export type RuntimeVariantRole = "CrashKindFault" | "CrashKindHeapExceeded" | "CrashKindPartitionDetected" | "CrashKindHandlerFailed" | "CrashKindTimerOverdue" | "CrashKindStackOverflow" | "OptionSome" | "OptionNone" | "ResultOk" | "ResultErr" | "ActorErrorRejected" | "ActorErrorFailed" | "ActorErrorTrapped" | "ActorErrorRefused" | "CallerActor" | "CallerTask" | "CallerTimer" | "CallerNode" | "ActorErrorDead" | "ActorErrorTimedOut" | "ActorErrorNodeNotRunning" | "ActorErrorRoutingFailed" | "ActorErrorEncodeFailed" | "ActorErrorMessageTooLarge" | "ActorErrorConnectionDropped" | "ActorErrorPartition" | "SendErrorFull" | "SendErrorClosed" | "SendErrorPartition" | "SendErrorStaleRef" | "SendErrorLocalShutdown" | "SendErrorCancelled" | "SendErrorVersionMismatch" | "SendErrorBackpressure" | "SendErrorDead" | "SendErrorUnauthorized" | "SendErrorInvalidMessage" | "SendErrorMessageTooLarge" | "SendErrorTimedOut" | "SendErrorWriteTimedOut" | "DeliveryAccepted" | "DeliveryDiscarded" | "LinkErrorNoContext";
|
|
780
780
|
export type SafepointDetail = {
|
|
781
781
|
budget: number;
|
|
782
782
|
};
|
|
@@ -865,6 +865,11 @@ export type SupervisorChild = {
|
|
|
865
865
|
stop_ns?: number | null;
|
|
866
866
|
stop_config?: number | null;
|
|
867
867
|
is_pool?: boolean;
|
|
868
|
+
/**
|
|
869
|
+
* Construction transfers this child's effective restart delay as an
|
|
870
|
+
* `(initial, maximum)` argument pair after the config, in declaration order.
|
|
871
|
+
*/
|
|
872
|
+
backoff?: boolean;
|
|
868
873
|
spawn: number;
|
|
869
874
|
};
|
|
870
875
|
export type SupervisorPoolOp = "Len" | "Member" | "Get";
|
|
@@ -873,7 +878,6 @@ export type SupervisorShape = {
|
|
|
873
878
|
strategy: RestartStrategy;
|
|
874
879
|
max_restarts: number;
|
|
875
880
|
window_secs: number;
|
|
876
|
-
backoff?: boolean;
|
|
877
881
|
children: Array<SupervisorChild>;
|
|
878
882
|
startup_order?: Array<number>;
|
|
879
883
|
};
|
|
@@ -1141,7 +1145,7 @@ export type TermV1 = {
|
|
|
1141
1145
|
})));
|
|
1142
1146
|
export type TimerSendPolicy = "reject" | "drop_newest";
|
|
1143
1147
|
export type TimestampBinaryOp = "Add" | "Subtract";
|
|
1144
|
-
export type TrapName = "heap_exceeded" | "integer_overflow" | "divide_by_zero" | "shift_out_of_range" | "vector_bounds" | "actor_refused";
|
|
1148
|
+
export type TrapName = "heap_exceeded" | "integer_overflow" | "divide_by_zero" | "signed_min_div_neg_one" | "shift_out_of_range" | "vector_bounds" | "actor_refused" | "stack_overflow";
|
|
1145
1149
|
export type ValueCapability = {
|
|
1146
1150
|
id: number;
|
|
1147
1151
|
capability: Capability;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { vectorStorage } from "../values.js";
|
|
1
|
+
import { vectorElement, vectorItems, vectorLength, vectorStorage, } from "../values.js";
|
|
2
2
|
import { cloneEncoding } from "./encoding-storage.js";
|
|
3
3
|
const U64_MAX = 0xffffffffffffffffn;
|
|
4
4
|
export class HeapExceeded extends Error {
|
|
@@ -128,12 +128,14 @@ export class ManagedLayouts {
|
|
|
128
128
|
if (value.kind !== "vector")
|
|
129
129
|
throw new Error("managed copy has no sequence");
|
|
130
130
|
const storage = vectorStorage(value);
|
|
131
|
-
if (row.share_on_copy && value
|
|
131
|
+
if (row.share_on_copy && vectorLength(value))
|
|
132
132
|
return value;
|
|
133
|
-
const items = value.
|
|
133
|
+
const items = vectorItems(value).map((item) => this.copy(item, row.element));
|
|
134
134
|
return {
|
|
135
135
|
...value,
|
|
136
136
|
items,
|
|
137
|
+
offset: 0,
|
|
138
|
+
length: undefined,
|
|
137
139
|
storage: { ...storage, items, capacity: items.length, owners: 1 },
|
|
138
140
|
};
|
|
139
141
|
}
|
|
@@ -274,7 +276,10 @@ export class ManagedLayouts {
|
|
|
274
276
|
throw new Error("managed sequence has no backing");
|
|
275
277
|
const storage = value.storage ?? vectorStorage(value);
|
|
276
278
|
if (storage.capacity)
|
|
277
|
-
allocation(storage, this.width(row.element, storage.capacity), () =>
|
|
279
|
+
allocation(storage, this.width(row.element, storage.capacity), () => {
|
|
280
|
+
for (let index = 0; index < vectorLength(value); index++)
|
|
281
|
+
visit(vectorElement(value, index), row.element);
|
|
282
|
+
});
|
|
278
283
|
return;
|
|
279
284
|
}
|
|
280
285
|
case "aggregate":
|