Skip to content

Commit 619a4de

Browse files
committed
fix(xsnap): Thread spawn and os into xsnap
1 parent 8887cf0 commit 619a4de

File tree

3 files changed

+53
-34
lines changed

3 files changed

+53
-34
lines changed

packages/xsnap/src/xsnap.js

+27-22
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
// @ts-check
22
/* eslint no-await-in-loop: ["off"] */
33

4+
/**
5+
* @typedef {typeof import('child_process').spawn} Spawn
6+
*/
7+
48
/**
59
* @template T
610
* @typedef {import('./defer').Deferred<T>} Deferred
711
*/
812

9-
import { spawn } from 'child_process';
10-
import { type as getOsType } from 'os';
1113
import { defer } from './defer';
1214
import * as netstring from './netstring';
1315
import * as node from './node-stream';
@@ -18,26 +20,6 @@ const QUERY = '?'.charCodeAt(0);
1820

1921
const importMetaUrl = `file://${__filename}`;
2022

21-
const osType = getOsType();
22-
const platform = {
23-
Linux: 'lin',
24-
Darwin: 'mac',
25-
Windows_NT: 'win',
26-
}[osType];
27-
28-
if (platform === undefined) {
29-
throw new Error(`xsnap does not support platform ${osType}`);
30-
}
31-
32-
const xsnapBin = new URL(
33-
`../build/bin/${platform}/release/xsnap`,
34-
importMetaUrl,
35-
).pathname;
36-
const xsnapDebugBin = new URL(
37-
`../build/bin/${platform}/debug/xsnap`,
38-
importMetaUrl,
39-
).pathname;
40-
4123
const encoder = new TextEncoder();
4224
const decoder = new TextDecoder();
4325

@@ -51,6 +33,8 @@ function echoSysCall(arg) {
5133

5234
/**
5335
* @param {Object} options
36+
* @param {string} options.os
37+
* @param {Spawn} options.spawn
5438
* @param {(request:Uint8Array) => Promise<Uint8Array>} [options.answerSysCall]
5539
* @param {string=} [options.name]
5640
* @param {boolean=} [options.debug]
@@ -60,6 +44,8 @@ function echoSysCall(arg) {
6044
*/
6145
export function xsnap(options) {
6246
const {
47+
os,
48+
spawn,
6349
name = '<unnamed xsnap worker>',
6450
answerSysCall = echoSysCall,
6551
debug = false,
@@ -68,6 +54,25 @@ export function xsnap(options) {
6854
stderr = 'inherit',
6955
} = options;
7056

57+
const platform = {
58+
Linux: 'lin',
59+
Darwin: 'mac',
60+
Windows_NT: 'win',
61+
}[os];
62+
63+
if (platform === undefined) {
64+
throw new Error(`xsnap does not support platform ${os}`);
65+
}
66+
67+
const xsnapBin = new URL(
68+
`../build/bin/${platform}/release/xsnap`,
69+
importMetaUrl,
70+
).pathname;
71+
const xsnapDebugBin = new URL(
72+
`../build/bin/${platform}/debug/xsnap`,
73+
importMetaUrl,
74+
).pathname;
75+
7176
/** @type {Deferred<Error?>} */
7277
const vatExit = defer();
7378

packages/xsnap/src/xsrepl.js

+10-3
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,20 @@
66
* @template T
77
* @typedef {import('./defer').Deferred<T>} Deferred
88
*/
9+
import * as childProcess from 'child_process';
10+
import * as os from 'os';
911
import * as readline from 'readline';
1012
import { xsnap } from './xsnap';
1113
import { defer } from './defer';
1214

1315
const decoder = new TextDecoder();
1416

1517
async function main() {
18+
const xsnapOptions = {
19+
spawn: childProcess.spawn,
20+
os: os.type(),
21+
};
22+
1623
/**
1724
* For the purposes of the REPL, the only syscall is effectively `print`.
1825
*
@@ -25,11 +32,11 @@ async function main() {
2532
}
2633

2734
const rl = readline.createInterface({
28-
input: process.stdin,
35+
input: /** @type {NodeJS.ReadableStream} */ (process.stdin),
2936
output: process.stdout,
3037
});
3138

32-
let vat = xsnap({ answerSysCall });
39+
let vat = xsnap({ ...xsnapOptions, answerSysCall });
3340

3441
await vat.evaluate(`
3542
const compartment = new Compartment();
@@ -60,7 +67,7 @@ async function main() {
6067
} else if (answer === 'load') {
6168
const file = await ask('file> ');
6269
await vat.close();
63-
vat = xsnap({ answerSysCall, snapshot: file });
70+
vat = xsnap({ ...xsnapOptions, answerSysCall, snapshot: file });
6471
} else if (answer === 'save') {
6572
const file = await ask('file> ');
6673
await vat.snapshot(file);

packages/xsnap/test/test-xsnap.js

+16-9
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
11
import test from 'ava';
2+
import * as childProcess from 'child_process';
3+
import * as os from 'os';
24
import { xsnap } from '../src/xsnap';
35

46
const importMetaUrl = `file://${__filename}`;
57

68
const decoder = new TextDecoder();
79
const encoder = new TextEncoder();
810

11+
const xsnapOptions = {
12+
spawn: childProcess.spawn,
13+
os: os.type(),
14+
};
15+
916
test('evaluate and sysCall', async t => {
1017
const messages = [];
1118
async function answerSysCall(message) {
1219
messages.push(decoder.decode(message));
1320
return new Uint8Array();
1421
}
15-
const vat = xsnap({ answerSysCall });
22+
const vat = xsnap({ ...xsnapOptions, answerSysCall });
1623
await vat.evaluate(`sysCall(ArrayBuffer.fromString("Hello, World!"));`);
1724
await vat.close();
1825
t.deepEqual(['Hello, World!'], messages);
@@ -24,7 +31,7 @@ test('evaluate until idle', async t => {
2431
messages.push(decoder.decode(message));
2532
return new Uint8Array();
2633
}
27-
const vat = xsnap({ answerSysCall });
34+
const vat = xsnap({ ...xsnapOptions, answerSysCall });
2835
await vat.evaluate(`
2936
(async () => {
3037
sysCall(ArrayBuffer.fromString("Hello, World!"));
@@ -40,7 +47,7 @@ test('run script until idle', async t => {
4047
messages.push(decoder.decode(message));
4148
return new Uint8Array();
4249
}
43-
const vat = xsnap({ answerSysCall });
50+
const vat = xsnap({ ...xsnapOptions, answerSysCall });
4451
await vat.execute(new URL('fixture-xsnap-script.js', importMetaUrl).pathname);
4552
await vat.close();
4653
t.deepEqual(['Hello, World!'], messages);
@@ -55,7 +62,7 @@ test('sysCall is synchronous inside, async outside', async t => {
5562
await Promise.resolve(null);
5663
return encoder.encode(`${number + 1}`);
5764
}
58-
const vat = xsnap({ answerSysCall });
65+
const vat = xsnap({ ...xsnapOptions, answerSysCall });
5966
await vat.evaluate(`
6067
const response = sysCall(ArrayBuffer.fromString('0'));
6168
const number = +String.fromArrayBuffer(response);
@@ -71,7 +78,7 @@ test('deliver a message', async t => {
7178
messages.push(+decoder.decode(message));
7279
return new Uint8Array();
7380
}
74-
const vat = xsnap({ answerSysCall });
81+
const vat = xsnap({ ...xsnapOptions, answerSysCall });
7582
await vat.evaluate(`
7683
function answerSysCall(message) {
7784
const number = +String.fromArrayBuffer(message);
@@ -91,7 +98,7 @@ test.only('receive a response', async t => {
9198
messages.push(+decoder.decode(message));
9299
return new Uint8Array();
93100
}
94-
const vat = xsnap({ answerSysCall });
101+
const vat = xsnap({ ...xsnapOptions, answerSysCall });
95102
await vat.evaluate(`
96103
function answerSysCall(message) {
97104
const number = +String.fromArrayBuffer(message);
@@ -116,7 +123,7 @@ test('serialize concurrent messages', async t => {
116123
messages.push(+decoder.decode(message));
117124
return new Uint8Array();
118125
}
119-
const vat = xsnap({ answerSysCall });
126+
const vat = xsnap({ ...xsnapOptions, answerSysCall });
120127
await vat.evaluate(`
121128
globalThis.answerSysCall = message => {
122129
const number = +String.fromArrayBuffer(message);
@@ -137,14 +144,14 @@ test('write and read snapshot', async t => {
137144

138145
const snapshot = new URL('fixture-snapshot.xss', importMetaUrl).pathname;
139146

140-
const vat0 = xsnap({ answerSysCall });
147+
const vat0 = xsnap({ ...xsnapOptions, answerSysCall });
141148
await vat0.evaluate(`
142149
globalThis.hello = "Hello, World!";
143150
`);
144151
await vat0.snapshot(snapshot);
145152
await vat0.close();
146153

147-
const vat1 = xsnap({ answerSysCall, snapshot });
154+
const vat1 = xsnap({ ...xsnapOptions, answerSysCall, snapshot });
148155
await vat1.evaluate(`
149156
sysCall(ArrayBuffer.fromString(hello));
150157
`);

0 commit comments

Comments
 (0)