@agoric/xsnap 0.14.3-dev-032c215.0 → 0.14.3-dev-285beb4.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/package.json +6 -5
- package/src/xsnap.js +93 -74
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/xsnap",
|
|
3
|
-
"version": "0.14.3-dev-
|
|
3
|
+
"version": "0.14.3-dev-285beb4.0+285beb4",
|
|
4
4
|
"description": "Snapshotting VM worker based on Moddable's XS Javascript engine",
|
|
5
5
|
"author": "Agoric",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
"test:xs": "exit 0"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@agoric/assert": "0.6.1-dev-
|
|
31
|
-
"@agoric/internal": "0.3.3-dev-
|
|
32
|
-
"@agoric/xsnap-lockdown": "0.14.1-dev-
|
|
30
|
+
"@agoric/assert": "0.6.1-dev-285beb4.0+285beb4",
|
|
31
|
+
"@agoric/internal": "0.3.3-dev-285beb4.0+285beb4",
|
|
32
|
+
"@agoric/xsnap-lockdown": "0.14.1-dev-285beb4.0+285beb4",
|
|
33
33
|
"@endo/bundle-source": "^3.2.3",
|
|
34
34
|
"@endo/eventual-send": "^1.2.2",
|
|
35
35
|
"@endo/init": "^1.1.2",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@endo/base64": "^1.0.5",
|
|
45
|
+
"@endo/nat": "^5.0.7",
|
|
45
46
|
"@types/glob": "^8.1.0",
|
|
46
47
|
"ava": "^5.3.0",
|
|
47
48
|
"c8": "^9.1.0"
|
|
@@ -76,5 +77,5 @@
|
|
|
76
77
|
"typeCoverage": {
|
|
77
78
|
"atLeast": 94.04
|
|
78
79
|
},
|
|
79
|
-
"gitHead": "
|
|
80
|
+
"gitHead": "285beb4fca085be5188e874af17ff02202b6bfce"
|
|
80
81
|
}
|
package/src/xsnap.js
CHANGED
|
@@ -56,6 +56,81 @@ function echoCommand(arg) {
|
|
|
56
56
|
const safeHintFromDescription = description =>
|
|
57
57
|
description.replaceAll(/[^a-zA-Z0-9_.-]/g, '-');
|
|
58
58
|
|
|
59
|
+
/**
|
|
60
|
+
* @typedef {object} SnapshotLoader
|
|
61
|
+
* @property {string} snapPath
|
|
62
|
+
* where XS can load the snapshot from, either a filesystem path or a string
|
|
63
|
+
* like `@${fileDescriptorNumber}:${readableDescription}`
|
|
64
|
+
* @property {(destStream?: Writable) => Promise<void>} afterSpawn
|
|
65
|
+
* callback for providing a destination stream to which the data should be
|
|
66
|
+
* piped (only relevant for a stream-based loader)
|
|
67
|
+
* @property {() => Promise<void>} cleanup
|
|
68
|
+
* callback to free resources when the loader is no longer needed
|
|
69
|
+
*/
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @callback MakeSnapshotLoader
|
|
73
|
+
* @param {AsyncIterable<Uint8Array>} sourceBytes
|
|
74
|
+
* @param {string} description
|
|
75
|
+
* @param {{fs: Pick<typeof import('fs/promises'), 'open' | 'unlink'>, ptmpName: (opts: import('tmp').TmpNameOptions) => Promise<string>}} ioPowers
|
|
76
|
+
* @returns {Promise<SnapshotLoader>}
|
|
77
|
+
*/
|
|
78
|
+
|
|
79
|
+
/** @type {MakeSnapshotLoader} */
|
|
80
|
+
const makeSnapshotLoaderWithFS = async (
|
|
81
|
+
sourceBytes,
|
|
82
|
+
description,
|
|
83
|
+
{ fs, ptmpName },
|
|
84
|
+
) => {
|
|
85
|
+
const snapPath = await ptmpName({
|
|
86
|
+
template: `load-snapshot-${safeHintFromDescription(description)}-XXXXXX.xss`,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
const afterSpawn = async () => {};
|
|
90
|
+
const cleanup = async () => fs.unlink(snapPath);
|
|
91
|
+
|
|
92
|
+
try {
|
|
93
|
+
const tmpSnap = await fs.open(snapPath, 'w');
|
|
94
|
+
// @ts-expect-error incorrect typings; writeFile does support AsyncIterable
|
|
95
|
+
await tmpSnap.writeFile(sourceBytes);
|
|
96
|
+
await tmpSnap.close();
|
|
97
|
+
} catch (e) {
|
|
98
|
+
await cleanup();
|
|
99
|
+
throw e;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return harden({
|
|
103
|
+
snapPath,
|
|
104
|
+
afterSpawn,
|
|
105
|
+
cleanup,
|
|
106
|
+
});
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/** @type {MakeSnapshotLoader} */
|
|
110
|
+
const makeSnapshotLoaderWithPipe = async (
|
|
111
|
+
sourceBytes,
|
|
112
|
+
description,
|
|
113
|
+
_ioPowers,
|
|
114
|
+
) => {
|
|
115
|
+
let done = Promise.resolve();
|
|
116
|
+
|
|
117
|
+
const cleanup = async () => done;
|
|
118
|
+
|
|
119
|
+
const afterSpawn = async destStream => {
|
|
120
|
+
const sourceStream = Readable.from(sourceBytes);
|
|
121
|
+
sourceStream.pipe(destStream, { end: false });
|
|
122
|
+
|
|
123
|
+
done = finished(sourceStream);
|
|
124
|
+
void done.catch(noop).then(() => sourceStream.unpipe(destStream));
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
return harden({
|
|
128
|
+
snapPath: `@${SNAPSHOT_LOAD_FD}:${safeHintFromDescription(description)}`,
|
|
129
|
+
afterSpawn,
|
|
130
|
+
cleanup,
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
|
|
59
134
|
/**
|
|
60
135
|
* @param {XSnapOptions} options
|
|
61
136
|
*
|
|
@@ -87,7 +162,7 @@ export async function xsnap(options) {
|
|
|
87
162
|
netstringMaxChunkSize = undefined,
|
|
88
163
|
parserBufferSize = undefined,
|
|
89
164
|
snapshotStream,
|
|
90
|
-
snapshotDescription =
|
|
165
|
+
snapshotDescription = 'unknown',
|
|
91
166
|
snapshotUseFs = false,
|
|
92
167
|
stdout = 'ignore',
|
|
93
168
|
stderr = 'ignore',
|
|
@@ -105,65 +180,6 @@ export async function xsnap(options) {
|
|
|
105
180
|
throw Error(`xsnap does not support platform ${os}`);
|
|
106
181
|
}
|
|
107
182
|
|
|
108
|
-
/** @type {(opts: import('tmp').TmpNameOptions) => Promise<string>} */
|
|
109
|
-
const ptmpName = fs.tmpName && promisify(fs.tmpName);
|
|
110
|
-
|
|
111
|
-
const makeLoadSnapshotHandlerWithFS = async () => {
|
|
112
|
-
assert(snapshotStream);
|
|
113
|
-
const snapPath = await ptmpName({
|
|
114
|
-
template: `load-snapshot-${safeHintFromDescription(
|
|
115
|
-
snapshotDescription,
|
|
116
|
-
)}-XXXXXX.xss`,
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
const afterSpawn = async () => {};
|
|
120
|
-
const cleanup = async () => fs.unlink(snapPath);
|
|
121
|
-
|
|
122
|
-
try {
|
|
123
|
-
const tmpSnap = await fs.open(snapPath, 'w');
|
|
124
|
-
await tmpSnap.writeFile(
|
|
125
|
-
// @ts-expect-error incorrect typings, does support AsyncIterable
|
|
126
|
-
snapshotStream,
|
|
127
|
-
);
|
|
128
|
-
await tmpSnap.close();
|
|
129
|
-
} catch (e) {
|
|
130
|
-
await cleanup();
|
|
131
|
-
throw e;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return harden({
|
|
135
|
-
snapPath,
|
|
136
|
-
afterSpawn,
|
|
137
|
-
cleanup,
|
|
138
|
-
});
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
const makeLoadSnapshotHandlerWithPipe = async () => {
|
|
142
|
-
let done = Promise.resolve();
|
|
143
|
-
|
|
144
|
-
const cleanup = async () => done;
|
|
145
|
-
|
|
146
|
-
/** @param {Writable} loadSnapshotsStream */
|
|
147
|
-
const afterSpawn = async loadSnapshotsStream => {
|
|
148
|
-
assert(snapshotStream);
|
|
149
|
-
const destStream = loadSnapshotsStream;
|
|
150
|
-
|
|
151
|
-
const sourceStream = Readable.from(snapshotStream);
|
|
152
|
-
sourceStream.pipe(destStream, { end: false });
|
|
153
|
-
|
|
154
|
-
done = finished(sourceStream);
|
|
155
|
-
void done.catch(noop).then(() => sourceStream.unpipe(destStream));
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
return harden({
|
|
159
|
-
snapPath: `@${SNAPSHOT_LOAD_FD}:${safeHintFromDescription(
|
|
160
|
-
snapshotDescription,
|
|
161
|
-
)}`,
|
|
162
|
-
afterSpawn,
|
|
163
|
-
cleanup,
|
|
164
|
-
});
|
|
165
|
-
};
|
|
166
|
-
|
|
167
183
|
let bin = new URL(
|
|
168
184
|
`../xsnap-native/xsnap/build/bin/${platform}/${
|
|
169
185
|
debug ? 'debug' : 'release'
|
|
@@ -176,15 +192,18 @@ export async function xsnap(options) {
|
|
|
176
192
|
|
|
177
193
|
assert(!/^-/.test(name), `name '${name}' cannot start with hyphen`);
|
|
178
194
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
195
|
+
/** @type {(opts: import('tmp').TmpNameOptions) => Promise<string>} */
|
|
196
|
+
const ptmpName = fs.tmpName && promisify(fs.tmpName);
|
|
197
|
+
const makeSnapshotLoader = snapshotUseFs
|
|
198
|
+
? makeSnapshotLoaderWithFS
|
|
199
|
+
: makeSnapshotLoaderWithPipe;
|
|
200
|
+
let snapshotLoader = await (snapshotStream &&
|
|
201
|
+
makeSnapshotLoader(snapshotStream, snapshotDescription, { fs, ptmpName }));
|
|
183
202
|
|
|
184
203
|
let args = [name];
|
|
185
204
|
|
|
186
|
-
if (
|
|
187
|
-
args.push('-r',
|
|
205
|
+
if (snapshotLoader) {
|
|
206
|
+
args.push('-r', snapshotLoader.snapPath);
|
|
188
207
|
}
|
|
189
208
|
|
|
190
209
|
if (meteringLimit) {
|
|
@@ -255,13 +274,13 @@ export async function xsnap(options) {
|
|
|
255
274
|
const snapshotSaveStream = xsnapProcessStdio[SNAPSHOT_SAVE_FD];
|
|
256
275
|
const snapshotLoadStream = xsnapProcessStdio[SNAPSHOT_LOAD_FD];
|
|
257
276
|
|
|
258
|
-
await
|
|
277
|
+
await snapshotLoader?.afterSpawn(snapshotLoadStream);
|
|
259
278
|
|
|
260
|
-
if (
|
|
279
|
+
if (snapshotLoader) {
|
|
261
280
|
void vatExit.promise.catch(noop).then(() => {
|
|
262
|
-
if (
|
|
263
|
-
const { cleanup } =
|
|
264
|
-
|
|
281
|
+
if (snapshotLoader) {
|
|
282
|
+
const { cleanup } = snapshotLoader;
|
|
283
|
+
snapshotLoader = undefined;
|
|
265
284
|
return cleanup();
|
|
266
285
|
}
|
|
267
286
|
});
|
|
@@ -283,9 +302,9 @@ export async function xsnap(options) {
|
|
|
283
302
|
async function runToIdle() {
|
|
284
303
|
for await (const _ of forever) {
|
|
285
304
|
const iteration = await messagesFromXsnap.next(undefined);
|
|
286
|
-
if (
|
|
287
|
-
const { cleanup } =
|
|
288
|
-
|
|
305
|
+
if (snapshotLoader) {
|
|
306
|
+
const { cleanup } = snapshotLoader;
|
|
307
|
+
snapshotLoader = undefined;
|
|
289
308
|
await cleanup();
|
|
290
309
|
}
|
|
291
310
|
if (iteration.done) {
|