@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.
Files changed (2) hide show
  1. package/package.json +6 -5
  2. 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-032c215.0+032c215",
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-032c215.0+032c215",
31
- "@agoric/internal": "0.3.3-dev-032c215.0+032c215",
32
- "@agoric/xsnap-lockdown": "0.14.1-dev-032c215.0+032c215",
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": "032c215d7144c84fcdbdaecac5a9fbe5a5497e4a"
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 = snapshotStream && 'unknown',
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
- let loadSnapshotHandler = await (snapshotStream &&
180
- (snapshotUseFs
181
- ? makeLoadSnapshotHandlerWithFS
182
- : makeLoadSnapshotHandlerWithPipe)());
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 (loadSnapshotHandler) {
187
- args.push('-r', loadSnapshotHandler.snapPath);
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 loadSnapshotHandler?.afterSpawn(snapshotLoadStream);
277
+ await snapshotLoader?.afterSpawn(snapshotLoadStream);
259
278
 
260
- if (loadSnapshotHandler) {
279
+ if (snapshotLoader) {
261
280
  void vatExit.promise.catch(noop).then(() => {
262
- if (loadSnapshotHandler) {
263
- const { cleanup } = loadSnapshotHandler;
264
- loadSnapshotHandler = undefined;
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 (loadSnapshotHandler) {
287
- const { cleanup } = loadSnapshotHandler;
288
- loadSnapshotHandler = undefined;
305
+ if (snapshotLoader) {
306
+ const { cleanup } = snapshotLoader;
307
+ snapshotLoader = undefined;
289
308
  await cleanup();
290
309
  }
291
310
  if (iteration.done) {