@bytecodealliance/preview2-shim 0.17.2 → 0.17.3
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/lib/browser/cli.js +91 -94
- package/lib/browser/clocks.js +30 -29
- package/lib/browser/filesystem.js +298 -251
- package/lib/browser/http.js +129 -128
- package/lib/browser/index.js +8 -16
- package/lib/browser/io.js +143 -135
- package/lib/browser/random.js +44 -42
- package/lib/browser/sockets.js +68 -166
- package/lib/common/instantiation.js +127 -0
- package/lib/io/calls.js +7 -5
- package/lib/io/worker-http.js +175 -157
- package/lib/io/worker-io.js +402 -386
- package/lib/io/worker-socket-tcp.js +271 -219
- package/lib/io/worker-socket-udp.js +494 -429
- package/lib/io/worker-sockets.js +276 -262
- package/lib/io/worker-thread.js +943 -864
- package/lib/nodejs/cli.js +64 -63
- package/lib/nodejs/clocks.js +51 -45
- package/lib/nodejs/filesystem.js +788 -654
- package/lib/nodejs/http.js +693 -617
- package/lib/nodejs/index.js +8 -16
- package/lib/nodejs/random.js +32 -28
- package/lib/nodejs/sockets.js +538 -474
- package/lib/synckit/index.js +94 -85
- package/package.json +9 -5
- package/types/index.d.ts +0 -1
- package/types/instantiation.d.ts +112 -0
package/lib/io/worker-io.js
CHANGED
|
@@ -1,106 +1,109 @@
|
|
|
1
|
-
import { fileURLToPath } from
|
|
2
|
-
import { createSyncFn } from
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
2
|
+
import { createSyncFn } from '../synckit/index.js';
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
} from
|
|
36
|
-
import nodeProcess, { exit, stderr, stdout, env } from
|
|
4
|
+
CALL_MASK,
|
|
5
|
+
CALL_TYPE_MASK,
|
|
6
|
+
FILE,
|
|
7
|
+
HTTP_SERVER_INCOMING_HANDLER,
|
|
8
|
+
HTTP,
|
|
9
|
+
INPUT_STREAM_BLOCKING_READ,
|
|
10
|
+
INPUT_STREAM_BLOCKING_SKIP,
|
|
11
|
+
INPUT_STREAM_DISPOSE,
|
|
12
|
+
INPUT_STREAM_READ,
|
|
13
|
+
INPUT_STREAM_SKIP,
|
|
14
|
+
INPUT_STREAM_SUBSCRIBE,
|
|
15
|
+
OUTPUT_STREAM_BLOCKING_FLUSH,
|
|
16
|
+
OUTPUT_STREAM_BLOCKING_SPLICE,
|
|
17
|
+
OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH,
|
|
18
|
+
OUTPUT_STREAM_BLOCKING_WRITE_ZEROES_AND_FLUSH,
|
|
19
|
+
OUTPUT_STREAM_CHECK_WRITE,
|
|
20
|
+
OUTPUT_STREAM_DISPOSE,
|
|
21
|
+
OUTPUT_STREAM_FLUSH,
|
|
22
|
+
OUTPUT_STREAM_SPLICE,
|
|
23
|
+
OUTPUT_STREAM_SUBSCRIBE,
|
|
24
|
+
OUTPUT_STREAM_WRITE_ZEROES,
|
|
25
|
+
OUTPUT_STREAM_WRITE,
|
|
26
|
+
POLL_POLL_LIST,
|
|
27
|
+
POLL_POLLABLE_BLOCK,
|
|
28
|
+
POLL_POLLABLE_DISPOSE,
|
|
29
|
+
POLL_POLLABLE_READY,
|
|
30
|
+
SOCKET_TCP,
|
|
31
|
+
STDERR,
|
|
32
|
+
STDIN,
|
|
33
|
+
STDOUT,
|
|
34
|
+
reverseMap,
|
|
35
|
+
} from './calls.js';
|
|
36
|
+
import nodeProcess, { exit, stderr, stdout, env } from 'node:process';
|
|
37
37
|
|
|
38
38
|
const _rawDebug = nodeProcess._rawDebug || console.error.bind(console);
|
|
39
39
|
|
|
40
40
|
const workerPath = fileURLToPath(
|
|
41
|
-
|
|
41
|
+
new URL('./worker-thread.js', import.meta.url)
|
|
42
42
|
);
|
|
43
43
|
|
|
44
44
|
const httpIncomingHandlers = new Map();
|
|
45
45
|
export function registerIncomingHttpHandler(id, handler) {
|
|
46
|
-
|
|
46
|
+
httpIncomingHandlers.set(id, handler);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
const instanceId = Math.round(Math.random() * 1000).toString();
|
|
50
50
|
const DEBUG_DEFAULT = false;
|
|
51
51
|
const DEBUG =
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
env.PREVIEW2_SHIM_DEBUG === '0'
|
|
53
|
+
? false
|
|
54
|
+
: env.PREVIEW2_SHIM_DEBUG === '1'
|
|
55
|
+
? true
|
|
56
|
+
: DEBUG_DEFAULT;
|
|
57
57
|
|
|
58
58
|
/**
|
|
59
59
|
* @type {(call: number, id: number | null, payload: any) -> any}
|
|
60
60
|
*/
|
|
61
61
|
export let ioCall = createSyncFn(workerPath, DEBUG, (type, id, payload) => {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
62
|
+
// 'callbacks' from the worker
|
|
63
|
+
// ONLY happens for an http server incoming handler, and NOTHING else (not even sockets, since accept is sync!)
|
|
64
|
+
if (type !== HTTP_SERVER_INCOMING_HANDLER) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
'Internal error: only incoming handler callback is permitted'
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
const handler = httpIncomingHandlers.get(id);
|
|
70
|
+
if (!handler) {
|
|
71
|
+
throw new Error(
|
|
72
|
+
`Internal error: no incoming handler registered for server ${id}`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
handler(payload);
|
|
74
76
|
});
|
|
75
77
|
if (DEBUG) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
78
|
+
const _ioCall = ioCall;
|
|
79
|
+
ioCall = function ioCall(num, id, payload) {
|
|
80
|
+
if (typeof id !== 'number' && id !== null) {
|
|
81
|
+
throw new Error('id must be a number or null');
|
|
82
|
+
}
|
|
83
|
+
let ret;
|
|
84
|
+
try {
|
|
85
|
+
_rawDebug(
|
|
86
|
+
instanceId,
|
|
87
|
+
reverseMap[num & CALL_MASK],
|
|
88
|
+
reverseMap[num & CALL_TYPE_MASK],
|
|
89
|
+
id,
|
|
90
|
+
payload
|
|
91
|
+
);
|
|
92
|
+
ret = _ioCall(num, id, payload);
|
|
93
|
+
return ret;
|
|
94
|
+
} catch (e) {
|
|
95
|
+
ret = e;
|
|
96
|
+
throw ret;
|
|
97
|
+
} finally {
|
|
98
|
+
_rawDebug(instanceId, '->', ret);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
98
101
|
}
|
|
99
102
|
|
|
100
|
-
const symbolDispose = Symbol.dispose || Symbol.for(
|
|
103
|
+
const symbolDispose = Symbol.dispose || Symbol.for('dispose');
|
|
101
104
|
|
|
102
105
|
const finalizationRegistry = new FinalizationRegistry(
|
|
103
|
-
|
|
106
|
+
(dispose) => void dispose()
|
|
104
107
|
);
|
|
105
108
|
|
|
106
109
|
const dummySymbol = Symbol();
|
|
@@ -113,148 +116,152 @@ const dummySymbol = Symbol();
|
|
|
113
116
|
* @param {(number) => void} disposeFn
|
|
114
117
|
*/
|
|
115
118
|
export function registerDispose(resource, parentResource, id, disposeFn) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
119
|
+
// While strictly speaking all components should handle their disposal,
|
|
120
|
+
// this acts as a last-resort to catch all missed drops through the JS GC.
|
|
121
|
+
// Mainly for two cases - (1) components which are long lived, that get shut
|
|
122
|
+
// down and (2) users that interface with low-level WASI APIs directly in JS
|
|
123
|
+
// for various reasons may end up leaning on JS GC inadvertantly.
|
|
124
|
+
function finalizer() {
|
|
125
|
+
// This has no functional purpose other than to pin a strong reference
|
|
126
|
+
// from the child resource's finalizer to the parent resource, to ensure
|
|
127
|
+
// that we can never finalize a parent resource before a child resource.
|
|
128
|
+
// This makes the generational JS GC become piecewise over child resource
|
|
129
|
+
// graphs (generational at each resource hierarchy level at least).
|
|
130
|
+
if (parentResource?.[dummySymbol]) {
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
disposeFn(id);
|
|
134
|
+
}
|
|
135
|
+
finalizationRegistry.register(resource, finalizer, finalizer);
|
|
136
|
+
return finalizer;
|
|
132
137
|
}
|
|
133
138
|
|
|
134
139
|
export function earlyDispose(finalizer) {
|
|
135
|
-
|
|
136
|
-
|
|
140
|
+
finalizationRegistry.unregister(finalizer);
|
|
141
|
+
finalizer();
|
|
137
142
|
}
|
|
138
143
|
|
|
139
144
|
const _Error = Error;
|
|
140
145
|
const IoError = class Error extends _Error {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
constructor(payload) {
|
|
147
|
+
super(payload);
|
|
148
|
+
this.payload = payload;
|
|
149
|
+
}
|
|
150
|
+
toDebugString() {
|
|
151
|
+
return this.message;
|
|
152
|
+
}
|
|
148
153
|
};
|
|
149
154
|
|
|
150
155
|
function streamIoErrorCall(call, id, payload) {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
156
|
+
try {
|
|
157
|
+
return ioCall(call, id, payload);
|
|
158
|
+
} catch (e) {
|
|
159
|
+
if (e.tag === 'closed') {
|
|
160
|
+
throw e;
|
|
161
|
+
}
|
|
162
|
+
if (e.tag === 'last-operation-failed') {
|
|
163
|
+
e.val = new IoError(Object.assign(new Error(e.val.message), e.val));
|
|
164
|
+
throw e;
|
|
165
|
+
}
|
|
166
|
+
// any invalid error is a trap
|
|
167
|
+
console.trace(e);
|
|
168
|
+
exit(1);
|
|
158
169
|
}
|
|
159
|
-
// any invalid error is a trap
|
|
160
|
-
console.trace(e);
|
|
161
|
-
exit(1);
|
|
162
|
-
}
|
|
163
170
|
}
|
|
164
171
|
|
|
165
172
|
class InputStream {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
blockingRead(len) {
|
|
177
|
-
return streamIoErrorCall(
|
|
178
|
-
INPUT_STREAM_BLOCKING_READ | this.#streamType,
|
|
179
|
-
this.#id,
|
|
180
|
-
len
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
skip(len) {
|
|
184
|
-
return streamIoErrorCall(
|
|
185
|
-
INPUT_STREAM_SKIP | this.#streamType,
|
|
186
|
-
this.#id,
|
|
187
|
-
len
|
|
188
|
-
);
|
|
189
|
-
}
|
|
190
|
-
blockingSkip(len) {
|
|
191
|
-
return streamIoErrorCall(
|
|
192
|
-
INPUT_STREAM_BLOCKING_SKIP | this.#streamType,
|
|
193
|
-
this.#id,
|
|
194
|
-
len
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
subscribe() {
|
|
198
|
-
return pollableCreate(
|
|
199
|
-
ioCall(INPUT_STREAM_SUBSCRIBE | this.#streamType, this.#id),
|
|
200
|
-
this
|
|
201
|
-
);
|
|
202
|
-
}
|
|
203
|
-
static _id(stream) {
|
|
204
|
-
return stream.#id;
|
|
205
|
-
}
|
|
206
|
-
/**
|
|
207
|
-
* @param {FILE | SOCKET_TCP | STDIN | HTTP} streamType
|
|
208
|
-
*/
|
|
209
|
-
static _create(streamType, id) {
|
|
210
|
-
const stream = new InputStream();
|
|
211
|
-
stream.#id = id;
|
|
212
|
-
stream.#streamType = streamType;
|
|
213
|
-
let disposeFn;
|
|
214
|
-
switch (streamType) {
|
|
215
|
-
case FILE:
|
|
216
|
-
disposeFn = fileInputStreamDispose;
|
|
217
|
-
break;
|
|
218
|
-
case SOCKET_TCP:
|
|
219
|
-
disposeFn = socketTcpInputStreamDispose;
|
|
220
|
-
break;
|
|
221
|
-
case STDIN:
|
|
222
|
-
disposeFn = stdinInputStreamDispose;
|
|
223
|
-
break;
|
|
224
|
-
case HTTP:
|
|
225
|
-
disposeFn = httpInputStreamDispose;
|
|
226
|
-
break;
|
|
227
|
-
default:
|
|
228
|
-
throw new Error(
|
|
229
|
-
"wasi-io trap: Dispose function not created for stream type " +
|
|
230
|
-
reverseMap[streamType]
|
|
173
|
+
#id;
|
|
174
|
+
#streamType;
|
|
175
|
+
#finalizer;
|
|
176
|
+
read(len) {
|
|
177
|
+
return streamIoErrorCall(
|
|
178
|
+
INPUT_STREAM_READ | this.#streamType,
|
|
179
|
+
this.#id,
|
|
180
|
+
len
|
|
231
181
|
);
|
|
232
182
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
183
|
+
blockingRead(len) {
|
|
184
|
+
return streamIoErrorCall(
|
|
185
|
+
INPUT_STREAM_BLOCKING_READ | this.#streamType,
|
|
186
|
+
this.#id,
|
|
187
|
+
len
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
skip(len) {
|
|
191
|
+
return streamIoErrorCall(
|
|
192
|
+
INPUT_STREAM_SKIP | this.#streamType,
|
|
193
|
+
this.#id,
|
|
194
|
+
len
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
blockingSkip(len) {
|
|
198
|
+
return streamIoErrorCall(
|
|
199
|
+
INPUT_STREAM_BLOCKING_SKIP | this.#streamType,
|
|
200
|
+
this.#id,
|
|
201
|
+
len
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
subscribe() {
|
|
205
|
+
return pollableCreate(
|
|
206
|
+
ioCall(INPUT_STREAM_SUBSCRIBE | this.#streamType, this.#id),
|
|
207
|
+
this
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
static _id(stream) {
|
|
211
|
+
return stream.#id;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* @param {FILE | SOCKET_TCP | STDIN | HTTP} streamType
|
|
215
|
+
*/
|
|
216
|
+
static _create(streamType, id) {
|
|
217
|
+
const stream = new InputStream();
|
|
218
|
+
stream.#id = id;
|
|
219
|
+
stream.#streamType = streamType;
|
|
220
|
+
let disposeFn;
|
|
221
|
+
switch (streamType) {
|
|
222
|
+
case FILE:
|
|
223
|
+
disposeFn = fileInputStreamDispose;
|
|
224
|
+
break;
|
|
225
|
+
case SOCKET_TCP:
|
|
226
|
+
disposeFn = socketTcpInputStreamDispose;
|
|
227
|
+
break;
|
|
228
|
+
case STDIN:
|
|
229
|
+
disposeFn = stdinInputStreamDispose;
|
|
230
|
+
break;
|
|
231
|
+
case HTTP:
|
|
232
|
+
disposeFn = httpInputStreamDispose;
|
|
233
|
+
break;
|
|
234
|
+
default:
|
|
235
|
+
throw new Error(
|
|
236
|
+
'wasi-io trap: Dispose function not created for stream type ' +
|
|
237
|
+
reverseMap[streamType]
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
stream.#finalizer = registerDispose(stream, null, id, disposeFn);
|
|
241
|
+
return stream;
|
|
242
|
+
}
|
|
243
|
+
[symbolDispose]() {
|
|
244
|
+
if (this.#finalizer) {
|
|
245
|
+
earlyDispose(this.#finalizer);
|
|
246
|
+
this.#finalizer = null;
|
|
247
|
+
}
|
|
240
248
|
}
|
|
241
|
-
}
|
|
242
249
|
}
|
|
243
250
|
|
|
244
251
|
function fileInputStreamDispose(id) {
|
|
245
|
-
|
|
252
|
+
ioCall(INPUT_STREAM_DISPOSE | FILE, id, null);
|
|
246
253
|
}
|
|
247
254
|
|
|
248
255
|
function socketTcpInputStreamDispose(id) {
|
|
249
|
-
|
|
256
|
+
ioCall(INPUT_STREAM_DISPOSE | SOCKET_TCP, id, null);
|
|
250
257
|
}
|
|
251
258
|
|
|
252
259
|
function stdinInputStreamDispose(id) {
|
|
253
|
-
|
|
260
|
+
ioCall(INPUT_STREAM_DISPOSE | STDIN, id, null);
|
|
254
261
|
}
|
|
255
262
|
|
|
256
263
|
function httpInputStreamDispose(id) {
|
|
257
|
-
|
|
264
|
+
ioCall(INPUT_STREAM_DISPOSE | HTTP, id, null);
|
|
258
265
|
}
|
|
259
266
|
|
|
260
267
|
export const inputStreamCreate = InputStream._create;
|
|
@@ -264,137 +271,142 @@ export const inputStreamId = InputStream._id;
|
|
|
264
271
|
delete InputStream._id;
|
|
265
272
|
|
|
266
273
|
class OutputStream {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
}
|
|
277
|
-
write(buf) {
|
|
278
|
-
if (this.#streamType <= STDERR) return this.blockingWriteAndFlush(buf);
|
|
279
|
-
return streamIoErrorCall(
|
|
280
|
-
OUTPUT_STREAM_WRITE | this.#streamType,
|
|
281
|
-
this.#id,
|
|
282
|
-
buf
|
|
283
|
-
);
|
|
284
|
-
}
|
|
285
|
-
blockingWriteAndFlush(buf) {
|
|
286
|
-
if (this.#streamType <= STDERR) {
|
|
287
|
-
const stream = this.#streamType === STDERR ? stderr : stdout;
|
|
288
|
-
return void stream.write(buf);
|
|
274
|
+
#id;
|
|
275
|
+
#streamType;
|
|
276
|
+
#finalizer;
|
|
277
|
+
checkWrite(len) {
|
|
278
|
+
return streamIoErrorCall(
|
|
279
|
+
OUTPUT_STREAM_CHECK_WRITE | this.#streamType,
|
|
280
|
+
this.#id,
|
|
281
|
+
len
|
|
282
|
+
);
|
|
289
283
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}
|
|
299
|
-
blockingFlush() {
|
|
300
|
-
return streamIoErrorCall(
|
|
301
|
-
OUTPUT_STREAM_BLOCKING_FLUSH | this.#streamType,
|
|
302
|
-
this.#id
|
|
303
|
-
);
|
|
304
|
-
}
|
|
305
|
-
writeZeroes(len) {
|
|
306
|
-
return streamIoErrorCall(
|
|
307
|
-
OUTPUT_STREAM_WRITE_ZEROES | this.#streamType,
|
|
308
|
-
this.#id,
|
|
309
|
-
len
|
|
310
|
-
);
|
|
311
|
-
}
|
|
312
|
-
blockingWriteZeroesAndFlush(len) {
|
|
313
|
-
return streamIoErrorCall(
|
|
314
|
-
OUTPUT_STREAM_BLOCKING_WRITE_ZEROES_AND_FLUSH | this.#streamType,
|
|
315
|
-
this.#id,
|
|
316
|
-
len
|
|
317
|
-
);
|
|
318
|
-
}
|
|
319
|
-
splice(src, len) {
|
|
320
|
-
return streamIoErrorCall(
|
|
321
|
-
OUTPUT_STREAM_SPLICE | this.#streamType,
|
|
322
|
-
this.#id,
|
|
323
|
-
{ src: src.#id, len }
|
|
324
|
-
);
|
|
325
|
-
}
|
|
326
|
-
blockingSplice(src, len) {
|
|
327
|
-
return streamIoErrorCall(
|
|
328
|
-
OUTPUT_STREAM_BLOCKING_SPLICE | this.#streamType,
|
|
329
|
-
this.#id,
|
|
330
|
-
{ src: inputStreamId(src), len }
|
|
331
|
-
);
|
|
332
|
-
}
|
|
333
|
-
subscribe() {
|
|
334
|
-
return pollableCreate(
|
|
335
|
-
ioCall(OUTPUT_STREAM_SUBSCRIBE | this.#streamType, this.#id)
|
|
336
|
-
);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
static _id(outputStream) {
|
|
340
|
-
return outputStream.#id;
|
|
341
|
-
}
|
|
342
|
-
/**
|
|
343
|
-
* @param {OutputStreamType} streamType
|
|
344
|
-
* @param {any} createPayload
|
|
345
|
-
*/
|
|
346
|
-
static _create(streamType, id) {
|
|
347
|
-
const stream = new OutputStream();
|
|
348
|
-
stream.#id = id;
|
|
349
|
-
stream.#streamType = streamType;
|
|
350
|
-
let disposeFn;
|
|
351
|
-
switch (streamType) {
|
|
352
|
-
case STDOUT:
|
|
353
|
-
disposeFn = stdoutOutputStreamDispose;
|
|
354
|
-
break;
|
|
355
|
-
case STDERR:
|
|
356
|
-
disposeFn = stderrOutputStreamDispose;
|
|
357
|
-
break;
|
|
358
|
-
case SOCKET_TCP:
|
|
359
|
-
disposeFn = socketTcpOutputStreamDispose;
|
|
360
|
-
break;
|
|
361
|
-
case FILE:
|
|
362
|
-
disposeFn = fileOutputStreamDispose;
|
|
363
|
-
break;
|
|
364
|
-
case HTTP:
|
|
365
|
-
return stream;
|
|
366
|
-
default:
|
|
367
|
-
throw new Error(
|
|
368
|
-
"wasi-io trap: Dispose function not created for stream type " +
|
|
369
|
-
reverseMap[streamType]
|
|
284
|
+
write(buf) {
|
|
285
|
+
if (this.#streamType <= STDERR) {
|
|
286
|
+
return this.blockingWriteAndFlush(buf);
|
|
287
|
+
}
|
|
288
|
+
return streamIoErrorCall(
|
|
289
|
+
OUTPUT_STREAM_WRITE | this.#streamType,
|
|
290
|
+
this.#id,
|
|
291
|
+
buf
|
|
370
292
|
);
|
|
371
293
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
294
|
+
blockingWriteAndFlush(buf) {
|
|
295
|
+
if (this.#streamType <= STDERR) {
|
|
296
|
+
const stream = this.#streamType === STDERR ? stderr : stdout;
|
|
297
|
+
return void stream.write(buf);
|
|
298
|
+
}
|
|
299
|
+
return streamIoErrorCall(
|
|
300
|
+
OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH | this.#streamType,
|
|
301
|
+
this.#id,
|
|
302
|
+
buf
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
flush() {
|
|
306
|
+
return streamIoErrorCall(
|
|
307
|
+
OUTPUT_STREAM_FLUSH | this.#streamType,
|
|
308
|
+
this.#id
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
blockingFlush() {
|
|
312
|
+
return streamIoErrorCall(
|
|
313
|
+
OUTPUT_STREAM_BLOCKING_FLUSH | this.#streamType,
|
|
314
|
+
this.#id
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
writeZeroes(len) {
|
|
318
|
+
return streamIoErrorCall(
|
|
319
|
+
OUTPUT_STREAM_WRITE_ZEROES | this.#streamType,
|
|
320
|
+
this.#id,
|
|
321
|
+
len
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
blockingWriteZeroesAndFlush(len) {
|
|
325
|
+
return streamIoErrorCall(
|
|
326
|
+
OUTPUT_STREAM_BLOCKING_WRITE_ZEROES_AND_FLUSH | this.#streamType,
|
|
327
|
+
this.#id,
|
|
328
|
+
len
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
splice(src, len) {
|
|
332
|
+
return streamIoErrorCall(
|
|
333
|
+
OUTPUT_STREAM_SPLICE | this.#streamType,
|
|
334
|
+
this.#id,
|
|
335
|
+
{ src: src.#id, len }
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
blockingSplice(src, len) {
|
|
339
|
+
return streamIoErrorCall(
|
|
340
|
+
OUTPUT_STREAM_BLOCKING_SPLICE | this.#streamType,
|
|
341
|
+
this.#id,
|
|
342
|
+
{ src: inputStreamId(src), len }
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
subscribe() {
|
|
346
|
+
return pollableCreate(
|
|
347
|
+
ioCall(OUTPUT_STREAM_SUBSCRIBE | this.#streamType, this.#id)
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
static _id(outputStream) {
|
|
352
|
+
return outputStream.#id;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* @param {OutputStreamType} streamType
|
|
356
|
+
* @param {any} createPayload
|
|
357
|
+
*/
|
|
358
|
+
static _create(streamType, id) {
|
|
359
|
+
const stream = new OutputStream();
|
|
360
|
+
stream.#id = id;
|
|
361
|
+
stream.#streamType = streamType;
|
|
362
|
+
let disposeFn;
|
|
363
|
+
switch (streamType) {
|
|
364
|
+
case STDOUT:
|
|
365
|
+
disposeFn = stdoutOutputStreamDispose;
|
|
366
|
+
break;
|
|
367
|
+
case STDERR:
|
|
368
|
+
disposeFn = stderrOutputStreamDispose;
|
|
369
|
+
break;
|
|
370
|
+
case SOCKET_TCP:
|
|
371
|
+
disposeFn = socketTcpOutputStreamDispose;
|
|
372
|
+
break;
|
|
373
|
+
case FILE:
|
|
374
|
+
disposeFn = fileOutputStreamDispose;
|
|
375
|
+
break;
|
|
376
|
+
case HTTP:
|
|
377
|
+
return stream;
|
|
378
|
+
default:
|
|
379
|
+
throw new Error(
|
|
380
|
+
'wasi-io trap: Dispose function not created for stream type ' +
|
|
381
|
+
reverseMap[streamType]
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
stream.#finalizer = registerDispose(stream, null, id, disposeFn);
|
|
385
|
+
return stream;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
[symbolDispose]() {
|
|
389
|
+
if (this.#finalizer) {
|
|
390
|
+
earlyDispose(this.#finalizer);
|
|
391
|
+
this.#finalizer = null;
|
|
392
|
+
}
|
|
380
393
|
}
|
|
381
|
-
}
|
|
382
394
|
}
|
|
383
395
|
|
|
384
396
|
function stdoutOutputStreamDispose(id) {
|
|
385
|
-
|
|
397
|
+
ioCall(OUTPUT_STREAM_DISPOSE | STDOUT, id);
|
|
386
398
|
}
|
|
387
399
|
|
|
388
400
|
function stderrOutputStreamDispose(id) {
|
|
389
|
-
|
|
401
|
+
ioCall(OUTPUT_STREAM_DISPOSE | STDERR, id);
|
|
390
402
|
}
|
|
391
403
|
|
|
392
404
|
function socketTcpOutputStreamDispose(id) {
|
|
393
|
-
|
|
405
|
+
ioCall(OUTPUT_STREAM_DISPOSE | SOCKET_TCP, id);
|
|
394
406
|
}
|
|
395
407
|
|
|
396
408
|
function fileOutputStreamDispose(id) {
|
|
397
|
-
|
|
409
|
+
ioCall(OUTPUT_STREAM_DISPOSE | FILE, id);
|
|
398
410
|
}
|
|
399
411
|
|
|
400
412
|
export const outputStreamCreate = OutputStream._create;
|
|
@@ -408,113 +420,117 @@ export const error = { Error: IoError };
|
|
|
408
420
|
export const streams = { InputStream, OutputStream };
|
|
409
421
|
|
|
410
422
|
function pollableDispose(id) {
|
|
411
|
-
|
|
423
|
+
ioCall(POLL_POLLABLE_DISPOSE, id);
|
|
412
424
|
}
|
|
413
425
|
|
|
414
|
-
const rep = Symbol.for(
|
|
426
|
+
const rep = Symbol.for('cabiRep');
|
|
415
427
|
|
|
416
428
|
class Pollable {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
429
|
+
#finalizer;
|
|
430
|
+
ready() {
|
|
431
|
+
return ioCall(POLL_POLLABLE_READY, this[rep]);
|
|
432
|
+
}
|
|
433
|
+
block() {
|
|
434
|
+
ioCall(POLL_POLLABLE_BLOCK, this[rep]);
|
|
435
|
+
}
|
|
436
|
+
static _create(id, parent) {
|
|
437
|
+
const pollable = new Pollable();
|
|
438
|
+
pollable[rep] = id;
|
|
439
|
+
pollable.#finalizer = registerDispose(
|
|
440
|
+
pollable,
|
|
441
|
+
parent,
|
|
442
|
+
id,
|
|
443
|
+
pollableDispose
|
|
444
|
+
);
|
|
445
|
+
return pollable;
|
|
446
|
+
}
|
|
447
|
+
[symbolDispose]() {
|
|
448
|
+
if (this.#finalizer && this[rep]) {
|
|
449
|
+
earlyDispose(this.#finalizer);
|
|
450
|
+
this.#finalizer = null;
|
|
451
|
+
}
|
|
439
452
|
}
|
|
440
|
-
}
|
|
441
453
|
}
|
|
442
454
|
|
|
443
|
-
const cabiLowerSymbol = Symbol.for(
|
|
455
|
+
const cabiLowerSymbol = Symbol.for('cabiLower');
|
|
444
456
|
const T_FLAG = 1 << 30;
|
|
445
457
|
|
|
446
|
-
Pollable.prototype.ready[cabiLowerSymbol] = function
|
|
447
|
-
|
|
458
|
+
Pollable.prototype.ready[cabiLowerSymbol] = function({
|
|
459
|
+
resourceTables: [table],
|
|
448
460
|
}) {
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
461
|
+
return function pollableReady(handle) {
|
|
462
|
+
const rep = table[(handle << 1) + 1] & ~T_FLAG;
|
|
463
|
+
const ready = ioCall(POLL_POLLABLE_READY, rep);
|
|
464
|
+
return ready ? 1 : 0;
|
|
465
|
+
};
|
|
454
466
|
};
|
|
455
467
|
|
|
456
|
-
Pollable.prototype.block[cabiLowerSymbol] = function
|
|
457
|
-
|
|
468
|
+
Pollable.prototype.block[cabiLowerSymbol] = function({
|
|
469
|
+
resourceTables: [table],
|
|
458
470
|
}) {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
471
|
+
return function pollableBlock(handle) {
|
|
472
|
+
const rep = table[(handle << 1) + 1] & ~T_FLAG;
|
|
473
|
+
ioCall(POLL_POLLABLE_BLOCK, rep);
|
|
474
|
+
};
|
|
463
475
|
};
|
|
464
476
|
|
|
465
|
-
Pollable[Symbol.for(
|
|
466
|
-
|
|
477
|
+
Pollable[Symbol.for('cabiDispose')] = function pollableDispose(rep) {
|
|
478
|
+
ioCall(POLL_POLLABLE_DISPOSE, rep);
|
|
467
479
|
};
|
|
468
480
|
|
|
469
481
|
export const pollableCreate = Pollable._create;
|
|
470
482
|
delete Pollable._create;
|
|
471
483
|
|
|
472
484
|
export const poll = {
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
485
|
+
Pollable,
|
|
486
|
+
poll(list) {
|
|
487
|
+
return ioCall(
|
|
488
|
+
POLL_POLL_LIST,
|
|
489
|
+
null,
|
|
490
|
+
list.map((pollable) => pollable[rep])
|
|
491
|
+
);
|
|
492
|
+
},
|
|
481
493
|
};
|
|
482
494
|
|
|
483
|
-
poll.poll[cabiLowerSymbol] = function
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
495
|
+
poll.poll[cabiLowerSymbol] = function({
|
|
496
|
+
memory,
|
|
497
|
+
realloc,
|
|
498
|
+
resourceTables: [table],
|
|
499
|
+
}) {
|
|
500
|
+
return function pollPollList(listPtr, len, retptr) {
|
|
501
|
+
const handleList = new Uint32Array(memory.buffer, listPtr, len);
|
|
502
|
+
const repList = Array(len);
|
|
503
|
+
for (let i = 0; i < len; i++) {
|
|
504
|
+
const handle = handleList[i];
|
|
505
|
+
repList[i] = table[(handle << 1) + 1] & ~T_FLAG;
|
|
506
|
+
}
|
|
507
|
+
const result = ioCall(POLL_POLL_LIST, null, repList);
|
|
508
|
+
const ptr = realloc(0, 0, 4, result.byteLength);
|
|
509
|
+
const out = new Uint32Array(memory.buffer, ptr, result.length);
|
|
510
|
+
out.set(result);
|
|
511
|
+
const ret = new Uint32Array(memory.buffer, retptr, 2);
|
|
512
|
+
ret[0] = ptr;
|
|
513
|
+
ret[1] = result.length;
|
|
514
|
+
return retptr;
|
|
515
|
+
};
|
|
500
516
|
};
|
|
501
517
|
|
|
502
518
|
export function createPoll(call, id, initPayload) {
|
|
503
|
-
|
|
519
|
+
return pollableCreate(ioCall(call, id, initPayload));
|
|
504
520
|
}
|
|
505
521
|
|
|
506
522
|
export function createPollLower(call, id, table) {
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
523
|
+
return function(initPayload) {
|
|
524
|
+
const rep = ioCall(call, id, initPayload);
|
|
525
|
+
const free = table[0] & ~T_FLAG;
|
|
526
|
+
if (free === 0) {
|
|
527
|
+
table.push(0);
|
|
528
|
+
table.push(rep | T_FLAG);
|
|
529
|
+
return (table.length >> 1) - 1;
|
|
530
|
+
}
|
|
531
|
+
table[0] = table[free << 1];
|
|
532
|
+
table[free << 1] = 0;
|
|
533
|
+
table[(free << 1) + 1] = rep | T_FLAG;
|
|
534
|
+
return free;
|
|
535
|
+
};
|
|
520
536
|
}
|