poe-code 13.0.2 → 13.0.4
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/index.js +14764 -13923
- package/dist/index.js.map +4 -4
- package/dist/metafile.json +1 -1
- package/package.json +1 -1
- package/packages/safe-js/dist/chunks/{chunk-RIQRHKCB.js → chunk-WGS5B4OT.js} +14518 -13706
- package/packages/safe-js/dist/chunks/chunk-WGS5B4OT.js.map +7 -0
- package/packages/safe-js/dist/chunks/{chunk-JP474LP7.js → chunk-ZGWWEL43.js} +2 -2
- package/packages/safe-js/dist/cli.js +2 -2
- package/packages/safe-js/dist/core.js +1 -1
- package/packages/safe-js/dist/index.d.ts +11 -3
- package/packages/safe-js/dist/index.js +14 -6
- package/packages/safe-js/dist/index.js.map +4 -4
- package/packages/safe-js/dist/interp/async.d.ts +2 -0
- package/packages/safe-js/dist/interp/async.js +31 -15
- package/packages/safe-js/dist/interp/budget.d.ts +29 -0
- package/packages/safe-js/dist/interp/budget.js +143 -0
- package/packages/safe-js/dist/interp/globals/console-json.d.ts +2 -1
- package/packages/safe-js/dist/interp/globals/console-json.js +24 -6
- package/packages/safe-js/dist/interp/globals/regex.d.ts +2 -1
- package/packages/safe-js/dist/interp/globals/regex.js +24 -3
- package/packages/safe-js/dist/interp/host-bridge.d.ts +2 -1
- package/packages/safe-js/dist/interp/host-bridge.js +98 -55
- package/packages/safe-js/dist/interp/host-call.d.ts +3 -2
- package/packages/safe-js/dist/interp/host-call.js +91 -52
- package/packages/safe-js/dist/interp/interpreter.d.ts +4 -1
- package/packages/safe-js/dist/interp/interpreter.js +115 -79
- package/packages/safe-js/dist/interp/methods/array.js +136 -71
- package/packages/safe-js/dist/interp/methods/string.d.ts +2 -1
- package/packages/safe-js/dist/interp/methods/string.js +111 -100
- package/packages/safe-js/dist/interp/regex/compile-guard.d.ts +33 -0
- package/packages/safe-js/dist/interp/regex/compile-guard.js +179 -0
- package/packages/safe-js/dist/interp/regex/parse.d.ts +2 -1
- package/packages/safe-js/dist/interp/regex/parse.js +87 -16
- package/packages/safe-js/dist/interp/values.d.ts +7 -2
- package/packages/safe-js/dist/interp/values.js +91 -9
- package/packages/safe-js/dist/modules/registry.d.ts +2 -1
- package/packages/safe-js/dist/modules/registry.js +1 -0
- package/packages/safe-js/dist/parse/hash.d.ts +2 -1
- package/packages/safe-js/dist/parse/hash.js +7 -4
- package/packages/safe-js/dist/parse/parser.d.ts +5 -3
- package/packages/safe-js/dist/parse/parser.js +53 -27
- package/packages/safe-js/dist/parse/tokenizer.d.ts +2 -0
- package/packages/safe-js/dist/parse/tokenizer.js +48 -26
- package/packages/safe-js/dist/parse.d.ts +3 -1
- package/packages/safe-js/dist/parse.js +3 -1
- package/packages/safe-js/dist/restore.d.ts +2 -1
- package/packages/safe-js/dist/restore.js +3 -3
- package/packages/safe-js/dist/run.js +289 -263
- package/packages/safe-js/dist/snapshot/migration.d.ts +3 -2
- package/packages/safe-js/dist/snapshot/migration.js +12 -5
- package/packages/safe-js/dist/snapshot/replay-data.d.ts +2 -1
- package/packages/safe-js/dist/snapshot/replay-data.js +172 -162
- package/packages/safe-js/dist/snapshot/replay-inputs.d.ts +2 -1
- package/packages/safe-js/dist/snapshot/replay-inputs.js +18 -11
- package/packages/safe-js/dist/snapshot/restore.d.ts +2 -2
- package/packages/safe-js/dist/snapshot/restore.js +142 -113
- package/packages/safe-js/dist/chunks/chunk-RIQRHKCB.js.map +0 -7
- /package/packages/safe-js/dist/chunks/{chunk-JP474LP7.js.map → chunk-ZGWWEL43.js.map} +0 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
-
import { hashSource } from "./parse/hash.js";
|
|
2
|
+
import { hashParsedAst, hashSource } from "./parse/hash.js";
|
|
3
3
|
import { withRunResources } from "./interp/resources.js";
|
|
4
4
|
import { createReplayableRandom } from "./random.js";
|
|
5
5
|
import { attachErrorSpan, describeThrownValue, materializeWrappedErrorCause, replaceErrorStack } from "./error/shape.js";
|
|
6
|
-
import { parseExecutableModule } from "./parse/parser.js";
|
|
6
|
+
import { findRegexLiteral, parseExecutableModule } from "./parse/parser.js";
|
|
7
7
|
import { restore } from "./restore.js";
|
|
8
8
|
import { Budget } from "./interp/budget.js";
|
|
9
|
+
import { CompileScope } from "./interp/regex/compile-guard.js";
|
|
9
10
|
import { PromiseReplay, promiseReplayContext } from "./interp/promise-replay.js";
|
|
10
11
|
import { wrapCancelableBindings } from "./interp/cancel.js";
|
|
11
12
|
import { enterSnapshotRun } from "./interp/running-state.js";
|
|
@@ -22,7 +23,7 @@ import { createObjectArrayGlobals } from "./interp/globals/object-array.js";
|
|
|
22
23
|
import { declareHostOperation, wrapCallerInjectedBindings } from "./interp/host-bridge.js";
|
|
23
24
|
import { interpret, Scope } from "./interp/interpreter.js";
|
|
24
25
|
import { consumeSettledHostCall, createPromiseGlobals } from "./interp/promise.js";
|
|
25
|
-
import { deepCopyToSandbox, isSandboxClosure, isSandboxPromise, measureSandboxData } from "./interp/values.js";
|
|
26
|
+
import { deepCopyToSandbox, isSandboxClosure, isSandboxPromise, measureSandboxData, reconcileCompiledValues } from "./interp/values.js";
|
|
26
27
|
import { resolveModuleImports } from "./modules/registry.js";
|
|
27
28
|
import { activateOtelSink, getActiveOtelSpan, safeAddEvent } from "./observability/otel.js";
|
|
28
29
|
import { attachDumpController, createDumpController } from "./snapshot/dump.js";
|
|
@@ -51,207 +52,175 @@ export function run(source, options = {}) {
|
|
|
51
52
|
const promiseTracker = createSandboxPromiseRejectionTracker();
|
|
52
53
|
let completedSnapshot;
|
|
53
54
|
const execute = async () => {
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const restoredSnapshot = options.snapshot === undefined ? undefined : restore(options.snapshot, { source });
|
|
75
|
-
const executionSemantics = restoredSnapshot?.executionSemantics === "jobs-v6" ? "jobs-v6" : EXECUTION_SEMANTICS;
|
|
76
|
-
const convertInitialInput = (convert) => executionSemantics === "jobs-v6" ? convert() : promiseReplayContext.exit(convert);
|
|
77
|
-
if (restoredSnapshot !== undefined) {
|
|
78
|
-
leaveSnapshotRun = enterSnapshotRun(restoredSnapshot);
|
|
79
|
-
}
|
|
80
|
-
const budget = options.budget ?? new Budget({ maxCallDepth: DEFAULT_MAX_CALL_DEPTH });
|
|
81
|
-
budget.reset();
|
|
82
|
-
promiseReplay.attachBudget(budget);
|
|
83
|
-
const filename = options.filename ?? "<input>";
|
|
84
|
-
const module = parseExecutableModule(source, filename);
|
|
85
|
-
promiseReplay.validateNodes(module);
|
|
86
|
-
const sourceHash = hashSource(source);
|
|
87
|
-
const hostCalls = new HostCallJournal(sourceHash, readHostCallSnapshot(restoredSnapshot), options.hostCallResumeProvider, restoredSnapshot?.replay, budget);
|
|
88
|
-
leaveHostReplay = hostCalls.dispose.bind(hostCalls);
|
|
89
|
-
promiseReplay.validateCallbacks(hostCalls.callbackPositions());
|
|
90
|
-
const generator = options.random ??
|
|
91
|
-
createReplayableRandom({ seed: options.randomSeed, snapshot: restoredSnapshot });
|
|
92
|
-
const random = { seed: generator.seed, initialState: generator.snapshot(), generator };
|
|
93
|
-
const interpreterSnapshot = restoredSnapshot?.replay === undefined && hasLoopIterationSnapshot(restoredSnapshot)
|
|
94
|
-
? {
|
|
95
|
-
...restoredSnapshot,
|
|
96
|
-
resumeNodeId: restoredSnapshot.pendingAwaits?.[0]?.nodeId
|
|
55
|
+
const budget = options.budget ?? new Budget({ maxCallDepth: DEFAULT_MAX_CALL_DEPTH });
|
|
56
|
+
const operation = budget.acquireCompileOwner(true);
|
|
57
|
+
const compilation = new CompileScope(operation.owner);
|
|
58
|
+
try {
|
|
59
|
+
const promiseReplay = new PromiseReplay(options.snapshot?.promiseReplay);
|
|
60
|
+
return await promiseReplayContext.run(promiseReplay, async () => {
|
|
61
|
+
const deactivateOtelSink = activateOtelSink(options.otelSink);
|
|
62
|
+
let leaveSnapshotRun;
|
|
63
|
+
let leaveHostReplay;
|
|
64
|
+
let leaveInputReplay;
|
|
65
|
+
let createFailureSnapshot;
|
|
66
|
+
let cancellationSnapshot;
|
|
67
|
+
let cancellationSnapshotError;
|
|
68
|
+
let snapshotScheduler;
|
|
69
|
+
const captureCancellationSnapshot = () => {
|
|
70
|
+
try {
|
|
71
|
+
cancellationSnapshot = createFailureSnapshot?.();
|
|
72
|
+
}
|
|
73
|
+
catch (reason) {
|
|
74
|
+
cancellationSnapshotError = { reason };
|
|
97
75
|
}
|
|
98
|
-
: undefined;
|
|
99
|
-
const callerBindings = convertInitialInput(() => options.bindings === undefined
|
|
100
|
-
? {}
|
|
101
|
-
: wrapCallerInjectedBindings(options.bindings, {
|
|
102
|
-
budget,
|
|
103
|
-
hostCalls,
|
|
104
|
-
moduleId: "<bindings>",
|
|
105
|
-
signal: options.signal,
|
|
106
|
-
lifecycle
|
|
107
|
-
}));
|
|
108
|
-
const builtinBindings = {
|
|
109
|
-
...createConsoleJsonGlobals({
|
|
110
|
-
budget,
|
|
111
|
-
hostCalls,
|
|
112
|
-
sink: options.sink
|
|
113
|
-
}),
|
|
114
|
-
...createCollectionGlobals({ budget }),
|
|
115
|
-
Float32Array: createFloat32ArrayGlobal(budget),
|
|
116
|
-
...createErrorGlobals({
|
|
117
|
-
budget
|
|
118
|
-
}),
|
|
119
|
-
...createMathGlobals({
|
|
120
|
-
random: random?.generator.next
|
|
121
|
-
}),
|
|
122
|
-
...createObjectArrayGlobals({
|
|
123
|
-
budget
|
|
124
|
-
}),
|
|
125
|
-
...createMiscGlobals({
|
|
126
|
-
budget
|
|
127
|
-
}),
|
|
128
|
-
...createPromiseGlobals({
|
|
129
|
-
budget
|
|
130
|
-
}),
|
|
131
|
-
...createRegexGlobals()
|
|
132
76
|
};
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
throw new TypeError("import.meta.migration is reserved for migrated checkpoint state.");
|
|
137
|
-
Object.defineProperty(importMeta, "migration", {
|
|
138
|
-
value: decodeReplayData(restoredSnapshot.migration.state),
|
|
139
|
-
enumerable: true,
|
|
140
|
-
configurable: true,
|
|
141
|
-
writable: true
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
const initialInputs = prepareReplayInputs({
|
|
145
|
-
bindings: callerBindings,
|
|
146
|
-
imports: convertInitialInput(() => resolveModuleImports(module, options.modules, {
|
|
147
|
-
budget,
|
|
148
|
-
hostCalls,
|
|
149
|
-
signal: options.signal,
|
|
150
|
-
allowMissing: restoredSnapshot?.initialInputs !== undefined
|
|
151
|
-
})),
|
|
152
|
-
entryPointArgs: convertInitialInput(() => options.entryPointArgs === undefined
|
|
77
|
+
options.signal?.addEventListener("abort", captureCancellationSnapshot, { once: true });
|
|
78
|
+
try {
|
|
79
|
+
const restoredSnapshot = options.snapshot === undefined
|
|
153
80
|
? undefined
|
|
154
|
-
:
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
if (
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
const
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
81
|
+
: restore(options.snapshot, { source }, operation.owner);
|
|
82
|
+
const executionSemantics = restoredSnapshot?.executionSemantics === "jobs-v6" ? "jobs-v6" : EXECUTION_SEMANTICS;
|
|
83
|
+
const convertInitialInput = (convert) => executionSemantics === "jobs-v6" ? convert() : promiseReplayContext.exit(convert);
|
|
84
|
+
if (restoredSnapshot !== undefined) {
|
|
85
|
+
leaveSnapshotRun = enterSnapshotRun(restoredSnapshot);
|
|
86
|
+
}
|
|
87
|
+
promiseReplay.attachBudget(budget);
|
|
88
|
+
const filename = options.filename ?? "<input>";
|
|
89
|
+
const module = parseExecutableModule(source, filename, operation.owner);
|
|
90
|
+
promiseReplay.validateNodes(module);
|
|
91
|
+
const sourceHash = findRegexLiteral(module) === undefined
|
|
92
|
+
? hashSource(source, operation.owner)
|
|
93
|
+
: hashParsedAst(module);
|
|
94
|
+
const hostCalls = new HostCallJournal(sourceHash, readHostCallSnapshot(restoredSnapshot), options.hostCallResumeProvider, restoredSnapshot?.replay, budget, operation.owner);
|
|
95
|
+
leaveHostReplay = hostCalls.dispose.bind(hostCalls);
|
|
96
|
+
promiseReplay.validateCallbacks(hostCalls.callbackPositions());
|
|
97
|
+
const generator = options.random ??
|
|
98
|
+
createReplayableRandom({ seed: options.randomSeed, snapshot: restoredSnapshot });
|
|
99
|
+
const random = { seed: generator.seed, initialState: generator.snapshot(), generator };
|
|
100
|
+
const interpreterSnapshot = restoredSnapshot?.replay === undefined && hasLoopIterationSnapshot(restoredSnapshot)
|
|
101
|
+
? {
|
|
102
|
+
...restoredSnapshot,
|
|
103
|
+
resumeNodeId: restoredSnapshot.pendingAwaits?.[0]?.nodeId
|
|
104
|
+
}
|
|
105
|
+
: undefined;
|
|
106
|
+
const callerBindings = convertInitialInput(() => options.bindings === undefined
|
|
107
|
+
? {}
|
|
108
|
+
: wrapCallerInjectedBindings(options.bindings, {
|
|
109
|
+
budget,
|
|
110
|
+
compileOwner: operation.owner,
|
|
111
|
+
hostCalls,
|
|
112
|
+
moduleId: "<bindings>",
|
|
113
|
+
signal: options.signal,
|
|
114
|
+
lifecycle
|
|
115
|
+
}));
|
|
116
|
+
const builtinBindings = {
|
|
117
|
+
...createConsoleJsonGlobals({
|
|
118
|
+
compileOwner: operation.owner,
|
|
119
|
+
budget,
|
|
120
|
+
hostCalls,
|
|
121
|
+
sink: options.sink
|
|
122
|
+
}),
|
|
123
|
+
...createCollectionGlobals({ budget }),
|
|
124
|
+
Float32Array: createFloat32ArrayGlobal(budget),
|
|
125
|
+
...createErrorGlobals({
|
|
126
|
+
budget
|
|
127
|
+
}),
|
|
128
|
+
...createMathGlobals({
|
|
129
|
+
random: random?.generator.next
|
|
130
|
+
}),
|
|
131
|
+
...createObjectArrayGlobals({
|
|
132
|
+
budget
|
|
133
|
+
}),
|
|
134
|
+
...createMiscGlobals({
|
|
135
|
+
budget
|
|
136
|
+
}),
|
|
137
|
+
...createPromiseGlobals({
|
|
138
|
+
budget
|
|
139
|
+
}),
|
|
140
|
+
...createRegexGlobals(operation.owner)
|
|
141
|
+
};
|
|
142
|
+
const importMeta = convertInitialInput(() => deepCopyToSandbox(options.importMeta ?? {}));
|
|
143
|
+
if (restoredSnapshot?.migration !== undefined) {
|
|
144
|
+
if (Object.hasOwn(importMeta, "migration"))
|
|
145
|
+
throw new TypeError("import.meta.migration is reserved for migrated checkpoint state.");
|
|
146
|
+
Object.defineProperty(importMeta, "migration", {
|
|
147
|
+
value: decodeReplayData(restoredSnapshot.migration.state, {}, compilation),
|
|
148
|
+
enumerable: true,
|
|
149
|
+
configurable: true,
|
|
150
|
+
writable: true
|
|
214
151
|
});
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
152
|
+
}
|
|
153
|
+
const initialInputs = prepareReplayInputs({
|
|
154
|
+
bindings: callerBindings,
|
|
155
|
+
imports: convertInitialInput(() => resolveModuleImports(module, options.modules, {
|
|
156
|
+
budget,
|
|
157
|
+
compileOwner: operation.owner,
|
|
158
|
+
hostCalls,
|
|
159
|
+
signal: options.signal,
|
|
160
|
+
allowMissing: restoredSnapshot?.initialInputs !== undefined
|
|
161
|
+
})),
|
|
162
|
+
entryPointArgs: convertInitialInput(() => options.entryPointArgs === undefined
|
|
163
|
+
? undefined
|
|
164
|
+
: deepCopyToSandbox([...options.entryPointArgs])),
|
|
165
|
+
importMeta
|
|
166
|
+
}, restoredSnapshot?.initialInputs, (promise, id) => {
|
|
167
|
+
if (promise !== undefined)
|
|
168
|
+
observeSandboxPromise(promise);
|
|
169
|
+
const operation = declareHostOperation(() => {
|
|
170
|
+
if (promise === undefined)
|
|
171
|
+
throw new TypeError(`Missing initial promise '${id}'.`);
|
|
172
|
+
return promise.promise;
|
|
173
|
+
}, "read-side-effect");
|
|
174
|
+
const binding = wrapCallerInjectedBindings({ [id]: operation }, {
|
|
175
|
+
budget,
|
|
176
|
+
hostCalls,
|
|
177
|
+
moduleId: "<inputs>",
|
|
178
|
+
compileOwner: compilation.owner,
|
|
179
|
+
signal: options.signal,
|
|
180
|
+
lifecycle
|
|
181
|
+
})[id];
|
|
182
|
+
if (!isSandboxClosure(binding))
|
|
183
|
+
throw new TypeError("Invalid initial promise operation.");
|
|
184
|
+
return binding.call([]);
|
|
185
|
+
}, hostCalls.rebindHostCapability.bind(hostCalls), compilation);
|
|
186
|
+
hostCalls.validateHostCapabilities();
|
|
187
|
+
const inputTickets = new Set();
|
|
188
|
+
const inputSize = measureSandboxData([
|
|
189
|
+
...Object.values(initialInputs.values.bindings),
|
|
190
|
+
...Object.values(initialInputs.values.imports),
|
|
191
|
+
...(initialInputs.values.entryPointArgs ?? []),
|
|
192
|
+
initialInputs.values.importMeta
|
|
193
|
+
], { ignoreClosureCaptures: true, compileTickets: inputTickets });
|
|
194
|
+
budget.reconcileCompileData(inputSize, inputTickets, inputTickets, initialInputs);
|
|
195
|
+
leaveInputReplay = () => budget.setRetainedDataUsage(initialInputs, 0);
|
|
196
|
+
const entryPointArgs = initialInputs.values.entryPointArgs;
|
|
197
|
+
const cancelableCallerBindings = wrapCancelableBindings(initialInputs.values.bindings, options.signal);
|
|
198
|
+
const scope = new Scope(builtinBindings, undefined, undefined, { chargeData: false }, interpreterSnapshot?.bindings);
|
|
199
|
+
const callerScope = scope.child(cancelableCallerBindings);
|
|
200
|
+
const executionScope = new Scope(initialInputs.values.imports, callerScope, initialInputs.values.importMeta, { functionBoundary: true });
|
|
201
|
+
const activeSnapshotScheduler = createSnapshotScheduler({
|
|
202
|
+
snapshotBackend: options.snapshotBackend,
|
|
203
|
+
snapshotIntervalMs: options.snapshotIntervalMs,
|
|
204
|
+
snapshotPath: options.snapshotPath
|
|
205
|
+
});
|
|
206
|
+
snapshotScheduler = activeSnapshotScheduler;
|
|
207
|
+
createFailureSnapshot = () => createRunSnapshot({
|
|
208
|
+
executionSemantics,
|
|
209
|
+
migration: restoredSnapshot?.migration,
|
|
210
|
+
bindings: executionScope.snapshot().bindings,
|
|
211
|
+
clock: options.clock,
|
|
212
|
+
hostCalls: hostCalls.snapshot(),
|
|
213
|
+
replay: hostCalls.snapshotReplay(),
|
|
214
|
+
initialInputs: initialInputs.snapshot,
|
|
215
|
+
promiseReplay: promiseReplay.snapshot(),
|
|
216
|
+
random,
|
|
217
|
+
sourceHash
|
|
218
|
+
});
|
|
219
|
+
let snapshotIteration = 0;
|
|
220
|
+
const topLevelResult = await interpret(createExecutableNode(module), {
|
|
221
|
+
compilation,
|
|
251
222
|
budget,
|
|
252
223
|
captureReplayState: random.generator.snapshot,
|
|
253
|
-
filename,
|
|
254
|
-
module,
|
|
255
224
|
onYield: (yieldPoint) => {
|
|
256
225
|
snapshotIteration += 1;
|
|
257
226
|
safeAddEvent(yieldPoint.otelSpan ?? getActiveOtelSpan(), "snapshot.saved", {
|
|
@@ -275,9 +244,7 @@ export function run(source, options = {}) {
|
|
|
275
244
|
initialInputs: initialInputs.snapshot,
|
|
276
245
|
promiseReplay: promiseReplay.snapshot(),
|
|
277
246
|
random,
|
|
278
|
-
randomResumeState: typeof yieldPoint.replayState === "number"
|
|
279
|
-
? yieldPoint.replayState
|
|
280
|
-
: undefined,
|
|
247
|
+
randomResumeState: typeof yieldPoint.replayState === "number" ? yieldPoint.replayState : undefined,
|
|
281
248
|
sourceHash
|
|
282
249
|
});
|
|
283
250
|
return snapshot;
|
|
@@ -287,75 +254,133 @@ export function run(source, options = {}) {
|
|
|
287
254
|
},
|
|
288
255
|
scope: executionScope,
|
|
289
256
|
signal: options.signal,
|
|
290
|
-
snapshot: interpreterSnapshot
|
|
257
|
+
snapshot: interpreterSnapshot,
|
|
258
|
+
surfaceUnhandledThrows: true,
|
|
259
|
+
useScopeDirectly: true
|
|
291
260
|
});
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
261
|
+
const result = entryPointArgs === undefined || !topLevelResult.ok
|
|
262
|
+
? topLevelResult
|
|
263
|
+
: await callEntryPoint({
|
|
264
|
+
args: entryPointArgs,
|
|
265
|
+
budget,
|
|
266
|
+
compilation,
|
|
267
|
+
captureReplayState: random.generator.snapshot,
|
|
268
|
+
filename,
|
|
269
|
+
module,
|
|
270
|
+
onYield: (yieldPoint) => {
|
|
271
|
+
snapshotIteration += 1;
|
|
272
|
+
safeAddEvent(yieldPoint.otelSpan ?? getActiveOtelSpan(), "snapshot.saved", {
|
|
273
|
+
iteration: snapshotIteration
|
|
274
|
+
});
|
|
275
|
+
let snapshot;
|
|
276
|
+
const createSnapshot = () => {
|
|
277
|
+
if (snapshot !== undefined) {
|
|
278
|
+
return snapshot;
|
|
279
|
+
}
|
|
280
|
+
const interpreterSnapshot = yieldPoint.snapshot();
|
|
281
|
+
snapshot = createRunSnapshot({
|
|
282
|
+
executionSemantics,
|
|
283
|
+
migration: restoredSnapshot?.migration,
|
|
284
|
+
bindings: interpreterSnapshot.bindings,
|
|
285
|
+
clock: options.clock,
|
|
286
|
+
hostCalls: hostCalls.snapshot(),
|
|
287
|
+
loopIterations: interpreterSnapshot.loopIterations,
|
|
288
|
+
pendingAwaits: [createPendingAwaitSnapshot(yieldPoint)],
|
|
289
|
+
replay: hostCalls.snapshotReplay(),
|
|
290
|
+
initialInputs: initialInputs.snapshot,
|
|
291
|
+
promiseReplay: promiseReplay.snapshot(),
|
|
292
|
+
random,
|
|
293
|
+
randomResumeState: typeof yieldPoint.replayState === "number"
|
|
294
|
+
? yieldPoint.replayState
|
|
295
|
+
: undefined,
|
|
296
|
+
sourceHash
|
|
297
|
+
});
|
|
298
|
+
return snapshot;
|
|
299
|
+
};
|
|
300
|
+
activeSnapshotScheduler.onYield(createSnapshot);
|
|
301
|
+
dumpController.onYield(createSnapshot);
|
|
302
|
+
},
|
|
303
|
+
scope: executionScope,
|
|
304
|
+
signal: options.signal,
|
|
305
|
+
snapshot: interpreterSnapshot
|
|
306
|
+
});
|
|
307
|
+
await throwIfReturnedPromiseRejected(result);
|
|
308
|
+
await throwIfUnhandledPromiseRejected(promiseTracker);
|
|
309
|
+
await activeSnapshotScheduler.finish();
|
|
310
|
+
let replay;
|
|
311
|
+
let replayError;
|
|
330
312
|
try {
|
|
331
|
-
|
|
332
|
-
throw cancellationSnapshotError.reason;
|
|
333
|
-
const snapshot = cancellationSnapshot ?? createFailureSnapshot();
|
|
334
|
-
dumpController.finalize(snapshot);
|
|
335
|
-
await snapshotScheduler.write(snapshot);
|
|
313
|
+
replay = hostCalls.snapshotReplay();
|
|
336
314
|
}
|
|
337
|
-
catch (
|
|
338
|
-
if (
|
|
339
|
-
|
|
315
|
+
catch (error) {
|
|
316
|
+
if (!(error instanceof MissingReplayCapabilityError))
|
|
317
|
+
throw error;
|
|
318
|
+
replayError = error.message;
|
|
319
|
+
}
|
|
320
|
+
const snapshot = createRunSnapshot({
|
|
321
|
+
executionSemantics,
|
|
322
|
+
migration: restoredSnapshot?.migration,
|
|
323
|
+
bindings: executionScope.snapshot().bindings,
|
|
324
|
+
clock: options.clock,
|
|
325
|
+
hostCalls: hostCalls.snapshot(),
|
|
326
|
+
replay,
|
|
327
|
+
initialInputs: initialInputs.snapshot,
|
|
328
|
+
promiseReplay: promiseReplay.snapshot(),
|
|
329
|
+
random,
|
|
330
|
+
sourceHash
|
|
331
|
+
});
|
|
332
|
+
if (replayError !== undefined)
|
|
333
|
+
snapshot.replayError = replayError;
|
|
334
|
+
dumpController.finalize(snapshot);
|
|
335
|
+
completedSnapshot = snapshot;
|
|
336
|
+
reconcileCompiledValues(budget, [
|
|
337
|
+
...Object.values(result.snapshot.bindings),
|
|
338
|
+
...(result.ok && "returnValue" in result ? [result.returnValue] : []),
|
|
339
|
+
...budget.retainedValues()
|
|
340
|
+
], compilation);
|
|
341
|
+
return {
|
|
342
|
+
...result,
|
|
343
|
+
snapshot
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
catch (error) {
|
|
347
|
+
promiseReplay.fail(error);
|
|
348
|
+
materializeWrappedErrorCause(error);
|
|
349
|
+
if (createFailureSnapshot !== undefined && snapshotScheduler !== undefined) {
|
|
350
|
+
try {
|
|
351
|
+
if (cancellationSnapshotError !== undefined)
|
|
352
|
+
throw cancellationSnapshotError.reason;
|
|
353
|
+
const snapshot = cancellationSnapshot ?? createFailureSnapshot();
|
|
354
|
+
dumpController.finalize(snapshot);
|
|
355
|
+
await snapshotScheduler.write(snapshot);
|
|
340
356
|
}
|
|
341
|
-
|
|
342
|
-
|
|
357
|
+
catch (snapshotError) {
|
|
358
|
+
if (snapshotError instanceof UnsnapshotableValueError) {
|
|
359
|
+
console.warn(`Skipping failure snapshot: ${snapshotError.message}`);
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
console.warn("Failed to write failure snapshot.", snapshotError);
|
|
363
|
+
}
|
|
343
364
|
}
|
|
344
365
|
}
|
|
366
|
+
dumpController.fail(error);
|
|
367
|
+
throw error;
|
|
345
368
|
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
369
|
+
finally {
|
|
370
|
+
lifecycle.hostCallbackContext.disable();
|
|
371
|
+
options.signal?.removeEventListener("abort", captureCancellationSnapshot);
|
|
372
|
+
leaveInputReplay?.();
|
|
373
|
+
leaveHostReplay?.();
|
|
374
|
+
promiseReplay.dispose();
|
|
375
|
+
leaveSnapshotRun?.();
|
|
376
|
+
deactivateOtelSink();
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
finally {
|
|
381
|
+
compilation.dispose();
|
|
382
|
+
operation.release();
|
|
383
|
+
}
|
|
359
384
|
};
|
|
360
385
|
const result = withRunResources(options.signal, () => withSandboxPromiseRejectionTracker(promiseTracker, execute)).catch(async (error) => {
|
|
361
386
|
if (completedSnapshot !== undefined) {
|
|
@@ -409,6 +434,7 @@ async function callEntryPoint(input) {
|
|
|
409
434
|
...argumentBindings
|
|
410
435
|
});
|
|
411
436
|
return interpret(createEntryPointAwait(input.args.length, input.module.span), {
|
|
437
|
+
compilation: input.compilation,
|
|
412
438
|
signal: input.signal,
|
|
413
439
|
budget: input.budget,
|
|
414
440
|
captureReplayState: input.captureReplayState,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type HostCallReplay } from "../interp/host-call.js";
|
|
2
2
|
import { type ReplayData } from "./replay-data.js";
|
|
3
|
+
import type { CompileOwner } from "../interp/budget.js";
|
|
3
4
|
export type SnapshotMigrationResolution = {
|
|
4
5
|
callId: string;
|
|
5
6
|
disposition: "not-performed";
|
|
@@ -29,6 +30,6 @@ export type SnapshotMigration = {
|
|
|
29
30
|
}>;
|
|
30
31
|
};
|
|
31
32
|
export declare function validateMigrationSemantics(value: unknown): asserts value is string;
|
|
32
|
-
export declare function validateMigrationJournal(sourceHash: string, replay: unknown, hostCalls?: unknown): HostCallReplay;
|
|
33
|
+
export declare function validateMigrationJournal(sourceHash: string, replay: unknown, hostCalls?: unknown, owner?: CompileOwner): HostCallReplay;
|
|
33
34
|
export declare function validateMigrationReconciliation(value: unknown, checkpointDigest: string, calls: HostCallReplay["calls"]): asserts value is SnapshotMigrationReconciliation;
|
|
34
|
-
export declare function validateSnapshotMigration(value: unknown, sourceHash: string): SnapshotMigration | undefined;
|
|
35
|
+
export declare function validateSnapshotMigration(value: unknown, sourceHash: string, owner?: CompileOwner): SnapshotMigration | undefined;
|