@bytecodealliance/preview2-shim 0.17.2 → 0.17.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/README.md +47 -0
- package/lib/browser/cli.js +76 -103
- package/lib/browser/clocks.js +30 -29
- package/lib/browser/config.js +6 -0
- package/lib/browser/environment.js +29 -0
- package/lib/browser/filesystem.js +299 -255
- 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 +134 -0
- package/lib/io/calls.js +8 -5
- package/lib/io/worker-http.js +179 -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 +255 -241
- package/lib/io/worker-thread.js +837 -754
- package/lib/nodejs/cli.js +64 -63
- package/lib/nodejs/clocks.js +51 -45
- package/lib/nodejs/filesystem.js +785 -651
- package/lib/nodejs/http.js +697 -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 +11 -5
- package/types/index.d.ts +0 -1
- package/types/instantiation.d.ts +136 -0
package/lib/io/worker-thread.js
CHANGED
|
@@ -1,160 +1,163 @@
|
|
|
1
|
-
import { createReadStream, createWriteStream } from
|
|
2
|
-
import { hrtime, stderr, stdout } from
|
|
3
|
-
import { PassThrough } from
|
|
4
|
-
import {
|
|
5
|
-
import { runAsWorker } from "../synckit/index.js";
|
|
1
|
+
import { createReadStream, createWriteStream } from 'node:fs';
|
|
2
|
+
import { hrtime, stderr, stdout } from 'node:process';
|
|
3
|
+
import { PassThrough } from 'node:stream';
|
|
4
|
+
import { runAsWorker } from '../synckit/index.js';
|
|
6
5
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
6
|
+
clearOutgoingResponse,
|
|
7
|
+
createHttpRequest,
|
|
8
|
+
setOutgoingResponse,
|
|
9
|
+
startHttpServer,
|
|
10
|
+
stopHttpServer,
|
|
11
|
+
getHttpServerAddress,
|
|
12
|
+
} from './worker-http.js';
|
|
13
|
+
import { Readable } from 'node:stream';
|
|
14
|
+
import { read } from 'node:fs';
|
|
15
|
+
import { nextTick } from 'node:process';
|
|
16
16
|
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
17
|
+
CALL_MASK,
|
|
18
|
+
CALL_TYPE_MASK,
|
|
19
|
+
CLOCKS_DURATION_SUBSCRIBE,
|
|
20
|
+
CLOCKS_INSTANT_SUBSCRIBE,
|
|
21
|
+
FILE,
|
|
22
|
+
FUTURE_DISPOSE,
|
|
23
|
+
FUTURE_SUBSCRIBE,
|
|
24
|
+
FUTURE_TAKE_VALUE,
|
|
25
|
+
HTTP,
|
|
26
|
+
HTTP_CREATE_REQUEST,
|
|
27
|
+
HTTP_OUTGOING_BODY_DISPOSE,
|
|
28
|
+
HTTP_OUTPUT_STREAM_FINISH,
|
|
29
|
+
HTTP_SERVER_CLEAR_OUTGOING_RESPONSE,
|
|
30
|
+
HTTP_SERVER_SET_OUTGOING_RESPONSE,
|
|
31
|
+
HTTP_SERVER_START,
|
|
32
|
+
HTTP_SERVER_STOP,
|
|
33
|
+
HTTP_SERVER_GET_ADDRESS,
|
|
34
|
+
INPUT_STREAM_BLOCKING_READ,
|
|
35
|
+
INPUT_STREAM_BLOCKING_SKIP,
|
|
36
|
+
INPUT_STREAM_CREATE,
|
|
37
|
+
INPUT_STREAM_DISPOSE,
|
|
38
|
+
INPUT_STREAM_READ,
|
|
39
|
+
INPUT_STREAM_SKIP,
|
|
40
|
+
INPUT_STREAM_SUBSCRIBE,
|
|
41
|
+
OUTPUT_STREAM_BLOCKING_FLUSH,
|
|
42
|
+
OUTPUT_STREAM_BLOCKING_SPLICE,
|
|
43
|
+
OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH,
|
|
44
|
+
OUTPUT_STREAM_BLOCKING_WRITE_ZEROES_AND_FLUSH,
|
|
45
|
+
OUTPUT_STREAM_CHECK_WRITE,
|
|
46
|
+
OUTPUT_STREAM_CREATE,
|
|
47
|
+
OUTPUT_STREAM_DISPOSE,
|
|
48
|
+
OUTPUT_STREAM_FLUSH,
|
|
49
|
+
OUTPUT_STREAM_SPLICE,
|
|
50
|
+
OUTPUT_STREAM_SUBSCRIBE,
|
|
51
|
+
OUTPUT_STREAM_WRITE,
|
|
52
|
+
OUTPUT_STREAM_WRITE_ZEROES,
|
|
53
|
+
POLL_POLLABLE_BLOCK,
|
|
54
|
+
POLL_POLLABLE_DISPOSE,
|
|
55
|
+
POLL_POLLABLE_READY,
|
|
56
|
+
POLL_POLL_LIST,
|
|
57
|
+
SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST,
|
|
58
|
+
SOCKET_RESOLVE_ADDRESS_SUBSCRIBE_REQUEST,
|
|
59
|
+
SOCKET_RESOLVE_ADDRESS_DISPOSE_REQUEST,
|
|
60
|
+
SOCKET_RESOLVE_ADDRESS_TAKE_REQUEST,
|
|
61
|
+
SOCKET_GET_DEFAULT_RECEIVE_BUFFER_SIZE,
|
|
62
|
+
SOCKET_GET_DEFAULT_SEND_BUFFER_SIZE,
|
|
63
|
+
SOCKET_TCP_ACCEPT,
|
|
64
|
+
SOCKET_TCP_BIND_FINISH,
|
|
65
|
+
SOCKET_TCP_BIND_START,
|
|
66
|
+
SOCKET_TCP_CONNECT_FINISH,
|
|
67
|
+
SOCKET_TCP_CONNECT_START,
|
|
68
|
+
SOCKET_TCP_CREATE_HANDLE,
|
|
69
|
+
SOCKET_TCP_DISPOSE,
|
|
70
|
+
SOCKET_TCP_GET_LOCAL_ADDRESS,
|
|
71
|
+
SOCKET_TCP_GET_REMOTE_ADDRESS,
|
|
72
|
+
SOCKET_TCP_IS_LISTENING,
|
|
73
|
+
SOCKET_TCP_LISTEN_FINISH,
|
|
74
|
+
SOCKET_TCP_LISTEN_START,
|
|
75
|
+
SOCKET_TCP_SET_KEEP_ALIVE,
|
|
76
|
+
SOCKET_TCP_SET_LISTEN_BACKLOG_SIZE,
|
|
77
|
+
SOCKET_TCP_SHUTDOWN,
|
|
78
|
+
SOCKET_TCP_SUBSCRIBE,
|
|
79
|
+
SOCKET_UDP_BIND_FINISH,
|
|
80
|
+
SOCKET_UDP_BIND_START,
|
|
81
|
+
SOCKET_UDP_CREATE_HANDLE,
|
|
82
|
+
SOCKET_UDP_DISPOSE,
|
|
83
|
+
SOCKET_UDP_GET_LOCAL_ADDRESS,
|
|
84
|
+
SOCKET_UDP_GET_RECEIVE_BUFFER_SIZE,
|
|
85
|
+
SOCKET_UDP_GET_REMOTE_ADDRESS,
|
|
86
|
+
SOCKET_UDP_GET_SEND_BUFFER_SIZE,
|
|
87
|
+
SOCKET_UDP_GET_UNICAST_HOP_LIMIT,
|
|
88
|
+
SOCKET_UDP_SET_RECEIVE_BUFFER_SIZE,
|
|
89
|
+
SOCKET_UDP_SET_SEND_BUFFER_SIZE,
|
|
90
|
+
SOCKET_UDP_SET_UNICAST_HOP_LIMIT,
|
|
91
|
+
SOCKET_UDP_STREAM,
|
|
92
|
+
SOCKET_UDP_SUBSCRIBE,
|
|
93
|
+
SOCKET_INCOMING_DATAGRAM_STREAM_RECEIVE,
|
|
94
|
+
SOCKET_OUTGOING_DATAGRAM_STREAM_CHECK_SEND,
|
|
95
|
+
SOCKET_OUTGOING_DATAGRAM_STREAM_SEND,
|
|
96
|
+
SOCKET_DATAGRAM_STREAM_SUBSCRIBE,
|
|
97
|
+
SOCKET_DATAGRAM_STREAM_DISPOSE,
|
|
98
|
+
STDERR,
|
|
99
|
+
STDIN,
|
|
100
|
+
STDOUT,
|
|
101
|
+
reverseMap,
|
|
102
|
+
} from './calls.js';
|
|
102
103
|
import {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
} from
|
|
104
|
+
SOCKET_STATE_BIND,
|
|
105
|
+
SOCKET_STATE_BOUND,
|
|
106
|
+
SOCKET_STATE_CONNECT,
|
|
107
|
+
SOCKET_STATE_CONNECTION,
|
|
108
|
+
SOCKET_STATE_LISTEN,
|
|
109
|
+
SOCKET_STATE_LISTENER,
|
|
110
|
+
socketResolveAddress,
|
|
111
|
+
getDefaultSendBufferSize,
|
|
112
|
+
getDefaultReceiveBufferSize,
|
|
113
|
+
} from './worker-sockets.js';
|
|
113
114
|
import {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
} from
|
|
115
|
+
createTcpSocket,
|
|
116
|
+
socketTcpAccept,
|
|
117
|
+
socketTcpBindStart,
|
|
118
|
+
socketTcpConnectStart,
|
|
119
|
+
socketTcpDispose,
|
|
120
|
+
socketTcpFinish,
|
|
121
|
+
socketTcpGetLocalAddress,
|
|
122
|
+
socketTcpGetRemoteAddress,
|
|
123
|
+
socketTcpListenStart,
|
|
124
|
+
socketTcpSetKeepAlive,
|
|
125
|
+
socketTcpSetListenBacklogSize,
|
|
126
|
+
socketTcpShutdown,
|
|
127
|
+
tcpSockets,
|
|
128
|
+
} from './worker-socket-tcp.js';
|
|
128
129
|
import {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
} from
|
|
149
|
-
import process from
|
|
150
|
-
|
|
151
|
-
function log(msg) {
|
|
152
|
-
|
|
130
|
+
createUdpSocket,
|
|
131
|
+
datagramStreams,
|
|
132
|
+
socketDatagramStreamDispose,
|
|
133
|
+
socketIncomingDatagramStreamReceive,
|
|
134
|
+
socketOutgoingDatagramStreamCheckSend,
|
|
135
|
+
socketOutgoingDatagramStreamSend,
|
|
136
|
+
socketUdpBindFinish,
|
|
137
|
+
socketUdpBindStart,
|
|
138
|
+
socketUdpDispose,
|
|
139
|
+
socketUdpGetLocalAddress,
|
|
140
|
+
socketUdpGetReceiveBufferSize,
|
|
141
|
+
socketUdpGetRemoteAddress,
|
|
142
|
+
socketUdpGetSendBufferSize,
|
|
143
|
+
socketUdpGetUnicastHopLimit,
|
|
144
|
+
socketUdpSetReceiveBufferSize,
|
|
145
|
+
socketUdpSetSendBufferSize,
|
|
146
|
+
socketUdpSetUnicastHopLimit,
|
|
147
|
+
socketUdpStream,
|
|
148
|
+
udpSockets,
|
|
149
|
+
} from './worker-socket-udp.js';
|
|
150
|
+
import process from 'node:process';
|
|
151
|
+
|
|
152
|
+
export function log(msg) {
|
|
153
|
+
if (debug) {
|
|
154
|
+
process._rawDebug(msg);
|
|
155
|
+
}
|
|
153
156
|
}
|
|
154
157
|
|
|
155
158
|
let pollCnt = 0,
|
|
156
|
-
|
|
157
|
-
|
|
159
|
+
streamCnt = 0,
|
|
160
|
+
futureCnt = 0;
|
|
158
161
|
|
|
159
162
|
/**
|
|
160
163
|
* @typedef {{
|
|
@@ -189,68 +192,68 @@ export const streams = new Map();
|
|
|
189
192
|
export const futures = new Map();
|
|
190
193
|
|
|
191
194
|
export function createReadableStreamPollState(nodeStream) {
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
195
|
+
const pollState = {
|
|
196
|
+
ready: true,
|
|
197
|
+
listener: null,
|
|
198
|
+
polls: [],
|
|
199
|
+
parentStream: nodeStream,
|
|
200
|
+
};
|
|
201
|
+
function pollDone() {
|
|
202
|
+
pollStateReady(pollState);
|
|
203
|
+
nodeStream.off('end', pollDone);
|
|
204
|
+
nodeStream.off('close', pollDone);
|
|
205
|
+
nodeStream.off('error', pollDone);
|
|
206
|
+
}
|
|
207
|
+
nodeStream.on('end', pollDone);
|
|
208
|
+
nodeStream.on('close', pollDone);
|
|
209
|
+
nodeStream.on('error', pollDone);
|
|
210
|
+
return pollState;
|
|
208
211
|
}
|
|
209
212
|
|
|
210
213
|
/**
|
|
211
214
|
* @param {NodeJS.ReadableStream | NodeJS.WritableStream} stream
|
|
212
215
|
*/
|
|
213
216
|
export function createReadableStream(
|
|
214
|
-
|
|
215
|
-
|
|
217
|
+
nodeStream,
|
|
218
|
+
pollState = createReadableStreamPollState(nodeStream)
|
|
216
219
|
) {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
220
|
+
const stream = {
|
|
221
|
+
stream: nodeStream,
|
|
222
|
+
flushPromise: null,
|
|
223
|
+
pollState,
|
|
224
|
+
};
|
|
225
|
+
streams.set(++streamCnt, stream);
|
|
226
|
+
return streamCnt;
|
|
224
227
|
}
|
|
225
228
|
|
|
226
229
|
export function createWritableStream(nodeStream) {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
230
|
+
const pollState = {
|
|
231
|
+
ready: true,
|
|
232
|
+
listener: null,
|
|
233
|
+
polls: [],
|
|
234
|
+
parentStream: null,
|
|
235
|
+
};
|
|
236
|
+
const stream = {
|
|
237
|
+
stream: nodeStream,
|
|
238
|
+
flushPromise: null,
|
|
239
|
+
pollState,
|
|
240
|
+
};
|
|
241
|
+
streams.set(++streamCnt, stream);
|
|
242
|
+
function pollReady() {
|
|
243
|
+
pollStateReady(pollState);
|
|
244
|
+
}
|
|
245
|
+
function pollDone() {
|
|
246
|
+
pollStateReady(pollState);
|
|
247
|
+
nodeStream.off('drain', pollReady);
|
|
248
|
+
nodeStream.off('finish', pollDone);
|
|
249
|
+
nodeStream.off('error', pollDone);
|
|
250
|
+
nodeStream.off('close', pollDone);
|
|
251
|
+
}
|
|
252
|
+
nodeStream.on('drain', pollReady);
|
|
253
|
+
nodeStream.on('finish', pollDone);
|
|
254
|
+
nodeStream.on('error', pollDone);
|
|
255
|
+
nodeStream.on('close', pollDone);
|
|
256
|
+
return streamCnt;
|
|
254
257
|
}
|
|
255
258
|
|
|
256
259
|
// Stdio
|
|
@@ -263,10 +266,10 @@ createWritableStream(stderr);
|
|
|
263
266
|
* @param {NodeJS.ReadableStream | NodeJS.WritableStream} stream
|
|
264
267
|
*/
|
|
265
268
|
function streamError(err) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
269
|
+
return {
|
|
270
|
+
tag: 'last-operation-failed',
|
|
271
|
+
val: { code: err.code, message: err.message, stack: err.stack },
|
|
272
|
+
};
|
|
270
273
|
}
|
|
271
274
|
|
|
272
275
|
/**
|
|
@@ -274,15 +277,21 @@ function streamError(err) {
|
|
|
274
277
|
* @returns {{ stream: NodeJS.ReadableStream | NodeJS.WritableStream, polls: number[] }}
|
|
275
278
|
*/
|
|
276
279
|
export function getStreamOrThrow(streamId) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
280
|
+
if (!streamId) {
|
|
281
|
+
throw new Error('wasi-io trap: no stream id provided');
|
|
282
|
+
}
|
|
283
|
+
const stream = streams.get(streamId);
|
|
284
|
+
// not in unfinished streams <=> closed
|
|
285
|
+
if (!stream) {
|
|
286
|
+
throw { tag: 'closed' };
|
|
287
|
+
}
|
|
288
|
+
if (stream.stream.errored) {
|
|
289
|
+
throw streamError(stream.stream.errored);
|
|
290
|
+
}
|
|
291
|
+
if (stream.stream.closed) {
|
|
292
|
+
throw { tag: 'closed' };
|
|
293
|
+
}
|
|
294
|
+
return stream;
|
|
286
295
|
}
|
|
287
296
|
|
|
288
297
|
/**
|
|
@@ -292,604 +301,677 @@ export function getStreamOrThrow(streamId) {
|
|
|
292
301
|
* @returns {Promise<any>}
|
|
293
302
|
*/
|
|
294
303
|
function handle(call, id, payload) {
|
|
295
|
-
|
|
296
|
-
|
|
304
|
+
if (uncaughtException) {
|
|
305
|
+
throw uncaughtException;
|
|
306
|
+
}
|
|
307
|
+
switch (call) {
|
|
297
308
|
// Http
|
|
298
309
|
case HTTP_CREATE_REQUEST: {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
310
|
+
const {
|
|
311
|
+
method,
|
|
312
|
+
scheme,
|
|
313
|
+
authority,
|
|
314
|
+
pathWithQuery,
|
|
315
|
+
headers,
|
|
316
|
+
body,
|
|
317
|
+
connectTimeout,
|
|
318
|
+
betweenBytesTimeout,
|
|
319
|
+
firstByteTimeout,
|
|
320
|
+
} = payload;
|
|
321
|
+
return createFuture(
|
|
322
|
+
createHttpRequest(
|
|
323
|
+
method,
|
|
324
|
+
scheme,
|
|
325
|
+
authority,
|
|
326
|
+
pathWithQuery,
|
|
327
|
+
headers,
|
|
328
|
+
body,
|
|
329
|
+
connectTimeout,
|
|
330
|
+
betweenBytesTimeout,
|
|
331
|
+
firstByteTimeout
|
|
332
|
+
)
|
|
333
|
+
);
|
|
323
334
|
}
|
|
324
335
|
case OUTPUT_STREAM_CREATE | HTTP: {
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
336
|
+
const stream = new PassThrough();
|
|
337
|
+
// content length is passed as payload
|
|
338
|
+
stream.contentLength = payload;
|
|
339
|
+
stream.bytesRemaining = payload;
|
|
340
|
+
return createWritableStream(stream);
|
|
330
341
|
}
|
|
331
342
|
case OUTPUT_STREAM_SUBSCRIBE | HTTP:
|
|
332
343
|
case OUTPUT_STREAM_FLUSH | HTTP:
|
|
333
344
|
case OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH | HTTP: {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
345
|
+
// http flush is a noop
|
|
346
|
+
const { stream } = getStreamOrThrow(id);
|
|
347
|
+
if (call === (OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH | HTTP)) {
|
|
348
|
+
stream.bytesRemaining -= payload.byteLength;
|
|
349
|
+
if (stream.bytesRemaining < 0) {
|
|
350
|
+
throw {
|
|
351
|
+
tag: 'last-operation-failed',
|
|
352
|
+
val: {
|
|
353
|
+
tag: 'HTTP-request-body-size',
|
|
354
|
+
val: stream.contentLength - stream.bytesRemaining,
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
// otherwise fall through to generic implementation
|
|
360
|
+
return handle(call & ~HTTP, id, payload);
|
|
350
361
|
}
|
|
351
362
|
case OUTPUT_STREAM_WRITE | HTTP: {
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
363
|
+
const { stream } = getStreamOrThrow(id);
|
|
364
|
+
stream.bytesRemaining -= payload.byteLength;
|
|
365
|
+
if (stream.bytesRemaining < 0) {
|
|
366
|
+
throw {
|
|
367
|
+
tag: 'last-operation-failed',
|
|
368
|
+
val: {
|
|
369
|
+
tag: 'HTTP-request-body-size',
|
|
370
|
+
val: stream.contentLength - stream.bytesRemaining,
|
|
371
|
+
},
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
const output = handle(OUTPUT_STREAM_WRITE, id, payload);
|
|
375
|
+
return output;
|
|
365
376
|
}
|
|
366
377
|
case OUTPUT_STREAM_DISPOSE | HTTP:
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
378
|
+
throw new Error(
|
|
379
|
+
'wasi-io trap: Output stream dispose not implemented as an IO-call for HTTP'
|
|
380
|
+
);
|
|
370
381
|
case HTTP_OUTPUT_STREAM_FINISH: {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
382
|
+
let stream;
|
|
383
|
+
try {
|
|
384
|
+
({ stream } = getStreamOrThrow(id));
|
|
385
|
+
} catch (e) {
|
|
386
|
+
if (e.tag === 'closed') {
|
|
387
|
+
throw { tag: 'internal-error', val: 'stream closed' };
|
|
388
|
+
}
|
|
389
|
+
if (e.tag === 'last-operation-failed') {
|
|
390
|
+
throw { tag: 'internal-error', val: e.val.message };
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (stream.bytesRemaining > 0) {
|
|
394
|
+
throw {
|
|
395
|
+
tag: 'HTTP-request-body-size',
|
|
396
|
+
val: stream.contentLength - stream.bytesRemaining,
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
if (stream.bytesRemaining < 0) {
|
|
400
|
+
throw {
|
|
401
|
+
tag: 'HTTP-request-body-size',
|
|
402
|
+
val: stream.contentLength - stream.bytesRemaining,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
stream.end();
|
|
406
|
+
return;
|
|
394
407
|
}
|
|
395
408
|
case HTTP_OUTGOING_BODY_DISPOSE:
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
409
|
+
if (debug && !streams.has(id)) {
|
|
410
|
+
console.warn(`wasi-io: stream ${id} not found to dispose`);
|
|
411
|
+
}
|
|
412
|
+
streams.delete(id);
|
|
413
|
+
return;
|
|
400
414
|
case HTTP_SERVER_START:
|
|
401
|
-
|
|
415
|
+
return startHttpServer(id, payload);
|
|
402
416
|
case HTTP_SERVER_STOP:
|
|
403
|
-
|
|
417
|
+
return stopHttpServer(id);
|
|
404
418
|
case HTTP_SERVER_SET_OUTGOING_RESPONSE:
|
|
405
|
-
|
|
419
|
+
return setOutgoingResponse(id, payload);
|
|
406
420
|
case HTTP_SERVER_CLEAR_OUTGOING_RESPONSE:
|
|
407
|
-
|
|
421
|
+
return clearOutgoingResponse(id);
|
|
422
|
+
case HTTP_SERVER_GET_ADDRESS:
|
|
423
|
+
return getHttpServerAddress(id);
|
|
408
424
|
|
|
409
|
-
|
|
425
|
+
// Sockets name resolution
|
|
410
426
|
case SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST:
|
|
411
|
-
|
|
427
|
+
return createFuture(socketResolveAddress(payload));
|
|
412
428
|
case SOCKET_RESOLVE_ADDRESS_SUBSCRIBE_REQUEST:
|
|
413
|
-
|
|
429
|
+
return createPoll(futures.get(id).pollState);
|
|
414
430
|
case SOCKET_RESOLVE_ADDRESS_DISPOSE_REQUEST:
|
|
415
|
-
|
|
431
|
+
return void futureDispose(id, true);
|
|
416
432
|
case SOCKET_RESOLVE_ADDRESS_TAKE_REQUEST: {
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
433
|
+
const val = futureTakeValue(id);
|
|
434
|
+
if (val === undefined) {
|
|
435
|
+
throw 'would-block';
|
|
436
|
+
}
|
|
437
|
+
// double take avoidance is ensured
|
|
438
|
+
return val.val;
|
|
421
439
|
}
|
|
422
440
|
|
|
423
441
|
// Sockets TCP
|
|
424
442
|
case SOCKET_TCP_ACCEPT:
|
|
425
|
-
|
|
443
|
+
return socketTcpAccept(id);
|
|
426
444
|
case SOCKET_TCP_CREATE_HANDLE:
|
|
427
|
-
|
|
445
|
+
return createTcpSocket();
|
|
428
446
|
case SOCKET_TCP_BIND_START:
|
|
429
|
-
|
|
447
|
+
return socketTcpBindStart(id, payload.localAddress, payload.family);
|
|
430
448
|
case SOCKET_TCP_BIND_FINISH:
|
|
431
|
-
|
|
449
|
+
return socketTcpFinish(id, SOCKET_STATE_BIND, SOCKET_STATE_BOUND);
|
|
432
450
|
case SOCKET_TCP_CONNECT_START:
|
|
433
|
-
|
|
451
|
+
return socketTcpConnectStart(
|
|
452
|
+
id,
|
|
453
|
+
payload.remoteAddress,
|
|
454
|
+
payload.family
|
|
455
|
+
);
|
|
434
456
|
case SOCKET_TCP_CONNECT_FINISH:
|
|
435
|
-
|
|
457
|
+
return socketTcpFinish(
|
|
458
|
+
id,
|
|
459
|
+
SOCKET_STATE_CONNECT,
|
|
460
|
+
SOCKET_STATE_CONNECTION
|
|
461
|
+
);
|
|
436
462
|
case SOCKET_TCP_LISTEN_START:
|
|
437
|
-
|
|
463
|
+
return socketTcpListenStart(id);
|
|
438
464
|
case SOCKET_TCP_LISTEN_FINISH:
|
|
439
|
-
|
|
465
|
+
return socketTcpFinish(
|
|
466
|
+
id,
|
|
467
|
+
SOCKET_STATE_LISTEN,
|
|
468
|
+
SOCKET_STATE_LISTENER
|
|
469
|
+
);
|
|
440
470
|
case SOCKET_TCP_IS_LISTENING:
|
|
441
|
-
|
|
471
|
+
return tcpSockets.get(id).state === SOCKET_STATE_LISTENER;
|
|
442
472
|
case SOCKET_GET_DEFAULT_SEND_BUFFER_SIZE:
|
|
443
|
-
|
|
473
|
+
return getDefaultSendBufferSize(id);
|
|
444
474
|
case SOCKET_GET_DEFAULT_RECEIVE_BUFFER_SIZE:
|
|
445
|
-
|
|
475
|
+
return getDefaultReceiveBufferSize(id);
|
|
446
476
|
case SOCKET_TCP_SET_LISTEN_BACKLOG_SIZE:
|
|
447
|
-
|
|
477
|
+
return socketTcpSetListenBacklogSize(id);
|
|
448
478
|
case SOCKET_TCP_GET_LOCAL_ADDRESS:
|
|
449
|
-
|
|
479
|
+
return socketTcpGetLocalAddress(id);
|
|
450
480
|
case SOCKET_TCP_GET_REMOTE_ADDRESS:
|
|
451
|
-
|
|
481
|
+
return socketTcpGetRemoteAddress(id);
|
|
452
482
|
case SOCKET_TCP_SHUTDOWN:
|
|
453
|
-
|
|
483
|
+
return socketTcpShutdown(id, payload);
|
|
454
484
|
case SOCKET_TCP_SUBSCRIBE:
|
|
455
|
-
|
|
485
|
+
return createPoll(tcpSockets.get(id).pollState);
|
|
456
486
|
case SOCKET_TCP_SET_KEEP_ALIVE:
|
|
457
|
-
|
|
487
|
+
return socketTcpSetKeepAlive(id, payload);
|
|
458
488
|
case SOCKET_TCP_DISPOSE:
|
|
459
|
-
|
|
489
|
+
return socketTcpDispose(id);
|
|
460
490
|
|
|
461
|
-
|
|
491
|
+
// Sockets UDP
|
|
462
492
|
case SOCKET_UDP_CREATE_HANDLE:
|
|
463
|
-
|
|
493
|
+
return createUdpSocket(payload);
|
|
464
494
|
case SOCKET_UDP_BIND_START:
|
|
465
|
-
|
|
495
|
+
return socketUdpBindStart(id, payload.localAddress, payload.family);
|
|
466
496
|
case SOCKET_UDP_BIND_FINISH:
|
|
467
|
-
|
|
497
|
+
return socketUdpBindFinish(id);
|
|
468
498
|
case SOCKET_UDP_STREAM:
|
|
469
|
-
|
|
499
|
+
return socketUdpStream(id, payload);
|
|
470
500
|
case SOCKET_UDP_SUBSCRIBE:
|
|
471
|
-
|
|
501
|
+
return createPoll(udpSockets.get(id).pollState);
|
|
472
502
|
case SOCKET_UDP_GET_LOCAL_ADDRESS:
|
|
473
|
-
|
|
503
|
+
return socketUdpGetLocalAddress(id);
|
|
474
504
|
case SOCKET_UDP_GET_REMOTE_ADDRESS:
|
|
475
|
-
|
|
505
|
+
return socketUdpGetRemoteAddress(id);
|
|
476
506
|
case SOCKET_UDP_SET_RECEIVE_BUFFER_SIZE:
|
|
477
|
-
|
|
507
|
+
return socketUdpSetReceiveBufferSize(id, payload);
|
|
478
508
|
case SOCKET_UDP_SET_SEND_BUFFER_SIZE:
|
|
479
|
-
|
|
509
|
+
return socketUdpSetSendBufferSize(id, payload);
|
|
480
510
|
case SOCKET_UDP_SET_UNICAST_HOP_LIMIT:
|
|
481
|
-
|
|
511
|
+
return socketUdpSetUnicastHopLimit(id, payload);
|
|
482
512
|
case SOCKET_UDP_GET_RECEIVE_BUFFER_SIZE:
|
|
483
|
-
|
|
513
|
+
return socketUdpGetReceiveBufferSize(id);
|
|
484
514
|
case SOCKET_UDP_GET_SEND_BUFFER_SIZE:
|
|
485
|
-
|
|
515
|
+
return socketUdpGetSendBufferSize(id);
|
|
486
516
|
case SOCKET_UDP_GET_UNICAST_HOP_LIMIT:
|
|
487
|
-
|
|
517
|
+
return socketUdpGetUnicastHopLimit(id);
|
|
488
518
|
case SOCKET_UDP_DISPOSE:
|
|
489
|
-
|
|
519
|
+
return socketUdpDispose(id);
|
|
490
520
|
|
|
491
521
|
case SOCKET_INCOMING_DATAGRAM_STREAM_RECEIVE:
|
|
492
|
-
|
|
522
|
+
return socketIncomingDatagramStreamReceive(id, payload);
|
|
493
523
|
case SOCKET_OUTGOING_DATAGRAM_STREAM_CHECK_SEND:
|
|
494
|
-
|
|
524
|
+
return socketOutgoingDatagramStreamCheckSend(id);
|
|
495
525
|
case SOCKET_OUTGOING_DATAGRAM_STREAM_SEND:
|
|
496
|
-
|
|
526
|
+
return socketOutgoingDatagramStreamSend(id, payload);
|
|
497
527
|
case SOCKET_DATAGRAM_STREAM_SUBSCRIBE:
|
|
498
|
-
|
|
528
|
+
return createPoll(datagramStreams.get(id).pollState);
|
|
499
529
|
case SOCKET_DATAGRAM_STREAM_DISPOSE:
|
|
500
|
-
|
|
530
|
+
return socketDatagramStreamDispose(id);
|
|
501
531
|
|
|
502
|
-
|
|
532
|
+
// Stdio
|
|
503
533
|
case OUTPUT_STREAM_BLOCKING_FLUSH | STDOUT:
|
|
504
534
|
case OUTPUT_STREAM_BLOCKING_FLUSH | STDERR:
|
|
505
|
-
|
|
506
|
-
|
|
535
|
+
// no blocking flush for stdio in Node.js
|
|
536
|
+
return;
|
|
507
537
|
case OUTPUT_STREAM_DISPOSE | STDOUT:
|
|
508
538
|
case OUTPUT_STREAM_DISPOSE | STDERR:
|
|
509
|
-
|
|
539
|
+
return;
|
|
510
540
|
case INPUT_STREAM_CREATE | STDIN: {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
541
|
+
return createReadableStream(
|
|
542
|
+
new Readable({
|
|
543
|
+
read(n) {
|
|
544
|
+
if (n <= 0) {
|
|
545
|
+
return void this.push(null);
|
|
546
|
+
}
|
|
547
|
+
let buf = Buffer.allocUnsafeSlow(n);
|
|
548
|
+
read(0, buf, 0, n, null, (err, bytesRead) => {
|
|
549
|
+
if (err) {
|
|
550
|
+
if (err.code === 'EAGAIN') {
|
|
551
|
+
nextTick(() => void this._read(n));
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
this.destroy(err);
|
|
555
|
+
} else if (bytesRead > 0) {
|
|
556
|
+
if (bytesRead !== buf.length) {
|
|
557
|
+
const dst =
|
|
558
|
+
Buffer.allocUnsafeSlow(bytesRead);
|
|
559
|
+
buf.copy(dst, 0, 0, bytesRead);
|
|
560
|
+
buf = dst;
|
|
561
|
+
}
|
|
562
|
+
this.push(buf);
|
|
563
|
+
} else {
|
|
564
|
+
this.push(null);
|
|
565
|
+
}
|
|
566
|
+
});
|
|
567
|
+
},
|
|
568
|
+
})
|
|
569
|
+
);
|
|
537
570
|
}
|
|
538
571
|
|
|
539
572
|
// Clocks
|
|
540
573
|
case CLOCKS_DURATION_SUBSCRIBE:
|
|
541
|
-
|
|
542
|
-
|
|
574
|
+
payload = hrtime.bigint() + payload;
|
|
575
|
+
// fallthrough
|
|
543
576
|
case CLOCKS_INSTANT_SUBSCRIBE: {
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
577
|
+
const pollState = {
|
|
578
|
+
ready: false,
|
|
579
|
+
listener: null,
|
|
580
|
+
polls: [],
|
|
581
|
+
parentStream: null,
|
|
582
|
+
};
|
|
583
|
+
subscribeInstant(pollState, payload);
|
|
584
|
+
return createPoll(pollState);
|
|
552
585
|
}
|
|
553
586
|
|
|
554
587
|
// Filesystem
|
|
555
588
|
case INPUT_STREAM_CREATE | FILE: {
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
589
|
+
const { fd, offset } = payload;
|
|
590
|
+
const stream = createReadStream(null, {
|
|
591
|
+
fd,
|
|
592
|
+
autoClose: false,
|
|
593
|
+
highWaterMark: 64 * 1024,
|
|
594
|
+
start: Number(offset),
|
|
595
|
+
});
|
|
596
|
+
return createReadableStream(stream);
|
|
564
597
|
}
|
|
565
598
|
case OUTPUT_STREAM_CREATE | FILE: {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
599
|
+
const { fd, offset } = payload;
|
|
600
|
+
const stream = createWriteStream(null, {
|
|
601
|
+
fd,
|
|
602
|
+
autoClose: false,
|
|
603
|
+
emitClose: false,
|
|
604
|
+
highWaterMark: 64 * 1024,
|
|
605
|
+
start: Number(offset),
|
|
606
|
+
});
|
|
607
|
+
return createWritableStream(stream);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
// Generic call implementations (streams + polls)
|
|
612
|
+
switch (call & CALL_MASK) {
|
|
580
613
|
case INPUT_STREAM_READ: {
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
614
|
+
const stream = getStreamOrThrow(id);
|
|
615
|
+
if (!stream.pollState.ready) {
|
|
616
|
+
return new Uint8Array();
|
|
617
|
+
}
|
|
618
|
+
const res = stream.stream.read(
|
|
619
|
+
Math.min(stream.stream.readableLength, Number(payload))
|
|
620
|
+
);
|
|
621
|
+
if (res) {
|
|
622
|
+
return res;
|
|
623
|
+
}
|
|
624
|
+
if (stream.stream.readableEnded) {
|
|
625
|
+
throw { tag: 'closed' };
|
|
626
|
+
}
|
|
627
|
+
return new Uint8Array();
|
|
589
628
|
}
|
|
590
629
|
case INPUT_STREAM_BLOCKING_READ: {
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
630
|
+
const { pollState } = streams.get(id);
|
|
631
|
+
pollStateCheck(pollState);
|
|
632
|
+
if (pollState.ready) {
|
|
633
|
+
return handle(
|
|
634
|
+
INPUT_STREAM_READ | (call & CALL_TYPE_MASK),
|
|
635
|
+
id,
|
|
636
|
+
payload
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
return new Promise(
|
|
640
|
+
(resolve) => void (pollState.listener = resolve)
|
|
641
|
+
).then(() =>
|
|
642
|
+
handle(INPUT_STREAM_READ | (call & CALL_TYPE_MASK), id, payload)
|
|
643
|
+
);
|
|
598
644
|
}
|
|
599
645
|
case INPUT_STREAM_SKIP:
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
646
|
+
return handle(
|
|
647
|
+
INPUT_STREAM_READ | (call & CALL_TYPE_MASK),
|
|
648
|
+
id,
|
|
649
|
+
new Uint8Array(Number(payload))
|
|
650
|
+
);
|
|
605
651
|
case INPUT_STREAM_BLOCKING_SKIP:
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
652
|
+
return handle(
|
|
653
|
+
INPUT_STREAM_BLOCKING_READ | (call & CALL_TYPE_MASK),
|
|
654
|
+
id,
|
|
655
|
+
new Uint8Array(Number(payload))
|
|
656
|
+
);
|
|
611
657
|
case INPUT_STREAM_SUBSCRIBE:
|
|
612
|
-
|
|
658
|
+
return createPoll(streams.get(id).pollState);
|
|
613
659
|
case INPUT_STREAM_DISPOSE: {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
660
|
+
const stream = streams.get(id);
|
|
661
|
+
verifyPollsDroppedForDrop(stream.pollState, 'input stream');
|
|
662
|
+
streams.delete(id);
|
|
663
|
+
return;
|
|
618
664
|
}
|
|
619
665
|
case OUTPUT_STREAM_CHECK_WRITE: {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
666
|
+
const { stream, pollState } = getStreamOrThrow(id);
|
|
667
|
+
const bytes = stream.writableHighWaterMark - stream.writableLength;
|
|
668
|
+
if (bytes === 0) {
|
|
669
|
+
pollState.ready = false;
|
|
670
|
+
}
|
|
671
|
+
return BigInt(bytes);
|
|
624
672
|
}
|
|
625
673
|
case OUTPUT_STREAM_WRITE: {
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
674
|
+
const { stream } = getStreamOrThrow(id);
|
|
675
|
+
if (
|
|
676
|
+
payload.byteLength >
|
|
677
|
+
stream.writableHighWaterMark - stream.writableLength
|
|
678
|
+
) {
|
|
679
|
+
throw new Error(
|
|
680
|
+
'wasi-io trap: attempt to write too many bytes'
|
|
681
|
+
);
|
|
682
|
+
}
|
|
683
|
+
return void stream.write(payload);
|
|
633
684
|
}
|
|
634
685
|
case OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH: {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
686
|
+
const stream = getStreamOrThrow(id);
|
|
687
|
+
// if an existing flush, try again after that
|
|
688
|
+
if (stream.flushPromise) {
|
|
689
|
+
return stream.flushPromise.then(() =>
|
|
690
|
+
handle(call, id, payload)
|
|
691
|
+
);
|
|
692
|
+
}
|
|
693
|
+
if (
|
|
694
|
+
payload.byteLength >
|
|
695
|
+
stream.stream.writableHighWaterMark -
|
|
696
|
+
stream.stream.writableLength
|
|
697
|
+
) {
|
|
698
|
+
throw new Error(
|
|
699
|
+
'wasi-io trap: Cannot write more than permitted writable length'
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
stream.pollState.ready = false;
|
|
703
|
+
return (stream.flushPromise = new Promise((resolve, reject) => {
|
|
704
|
+
if (stream.stream === stdout || stream.stream === stderr) {
|
|
705
|
+
// Inside workers, NodeJS actually queues writes destined for
|
|
706
|
+
// stdout/stderr in a port that is only flushed on exit of the worker.
|
|
707
|
+
//
|
|
708
|
+
// In this case, we cannot attempt to wait for the promise.
|
|
709
|
+
//
|
|
710
|
+
// This code may have to be reworked for browsers.
|
|
711
|
+
//
|
|
712
|
+
// see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker/io.js#L288
|
|
713
|
+
// see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker.js#L303
|
|
714
|
+
// see: https://github.com/nodejs/node/blob/v22.12.0/typings/internalBinding/messaging.d.ts#L27
|
|
715
|
+
stream.stream.write(payload);
|
|
716
|
+
stream.flushPromise = null;
|
|
717
|
+
pollStateReady(stream.pollState);
|
|
718
|
+
resolve(BigInt(payload.byteLength));
|
|
719
|
+
} else {
|
|
720
|
+
stream.stream.write(payload, (err) => {
|
|
721
|
+
stream.flushPromise = null;
|
|
722
|
+
pollStateReady(stream.pollState);
|
|
723
|
+
if (err) {
|
|
724
|
+
return void reject(streamError(err));
|
|
725
|
+
}
|
|
726
|
+
resolve(BigInt(payload.byteLength));
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
}));
|
|
673
730
|
}
|
|
674
731
|
case OUTPUT_STREAM_FLUSH: {
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
732
|
+
const stream = getStreamOrThrow(id);
|
|
733
|
+
if (stream.flushPromise) {
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
stream.pollState.ready = false;
|
|
737
|
+
stream.flushPromise = new Promise((resolve, reject) => {
|
|
738
|
+
if (stream.stream === stdout || stream.stream === stderr) {
|
|
739
|
+
// Inside workers, NodeJS actually queues writes destined for
|
|
740
|
+
// stdout/stderr in a port that is only flushed on exit of the worker.
|
|
741
|
+
//
|
|
742
|
+
// In this case, we cannot attempt to wait for the promise.
|
|
743
|
+
//
|
|
744
|
+
// This code may have to be reworked for browsers.
|
|
745
|
+
//
|
|
746
|
+
// see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker/io.js#L288
|
|
747
|
+
// see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker.js#L303
|
|
748
|
+
// see: https://github.com/nodejs/node/blob/v22.12.0/typings/internalBinding/messaging.d.ts#L27
|
|
749
|
+
stream.flushPromise = null;
|
|
750
|
+
pollStateReady(stream.pollState);
|
|
751
|
+
resolve();
|
|
752
|
+
} else {
|
|
753
|
+
// For all other writes, we can perform the actual write and expect the write to complete
|
|
754
|
+
// and trigger the relevant callback
|
|
755
|
+
stream.stream.write(new Uint8Array([]), (err) => {
|
|
756
|
+
stream.flushPromise = null;
|
|
757
|
+
pollStateReady(stream.pollState);
|
|
758
|
+
if (err) {
|
|
759
|
+
return void reject(streamError(err));
|
|
760
|
+
}
|
|
761
|
+
resolve();
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
return stream.flushPromise;
|
|
705
766
|
}
|
|
706
767
|
case OUTPUT_STREAM_BLOCKING_FLUSH: {
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
768
|
+
const stream = getStreamOrThrow(id);
|
|
769
|
+
if (stream.flushPromise) {
|
|
770
|
+
return stream.flushPromise;
|
|
771
|
+
}
|
|
772
|
+
return new Promise((resolve, reject) => {
|
|
773
|
+
if (stream.stream === stdout || stream.stream === stderr) {
|
|
774
|
+
// Inside workers, NodeJS actually queues writes destined for
|
|
775
|
+
// stdout/stderr in a port that is only flushed on exit of the worker.
|
|
776
|
+
//
|
|
777
|
+
// In this case, we cannot attempt to wait for the promise.
|
|
778
|
+
//
|
|
779
|
+
// This code may have to be reworked for browsers.
|
|
780
|
+
//
|
|
781
|
+
// see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker/io.js#L288
|
|
782
|
+
// see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker.js#L303
|
|
783
|
+
// see: https://github.com/nodejs/node/blob/v22.12.0/typings/internalBinding/messaging.d.ts#L27
|
|
784
|
+
resolve();
|
|
785
|
+
} else {
|
|
786
|
+
// For all other writes, we can perform the actual write and expect the write to complete
|
|
787
|
+
// and trigger the relevant callback
|
|
788
|
+
stream.stream.write(new Uint8Array([]), (err) =>
|
|
789
|
+
err ? reject(streamError(err)) : resolve()
|
|
790
|
+
);
|
|
791
|
+
}
|
|
792
|
+
});
|
|
730
793
|
}
|
|
731
794
|
case OUTPUT_STREAM_WRITE_ZEROES:
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
795
|
+
return handle(
|
|
796
|
+
OUTPUT_STREAM_WRITE | (call & CALL_TYPE_MASK),
|
|
797
|
+
id,
|
|
798
|
+
new Uint8Array(Number(payload))
|
|
799
|
+
);
|
|
737
800
|
case OUTPUT_STREAM_BLOCKING_WRITE_ZEROES_AND_FLUSH:
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
801
|
+
return handle(
|
|
802
|
+
OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH |
|
|
803
|
+
(call & CALL_TYPE_MASK),
|
|
804
|
+
id,
|
|
805
|
+
new Uint8Array(Number(payload))
|
|
806
|
+
);
|
|
743
807
|
case OUTPUT_STREAM_SPLICE: {
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
808
|
+
const outputStream = getStreamOrThrow(id);
|
|
809
|
+
const inputStream = getStreamOrThrow(payload.src);
|
|
810
|
+
let bytesRemaining = Number(payload.len);
|
|
811
|
+
let chunk;
|
|
812
|
+
while (
|
|
813
|
+
bytesRemaining > 0 &&
|
|
814
|
+
(chunk = inputStream.stream.read(
|
|
815
|
+
Math.min(
|
|
816
|
+
outputStream.writableHighWaterMark -
|
|
817
|
+
outputStream.writableLength,
|
|
818
|
+
bytesRemaining
|
|
819
|
+
)
|
|
820
|
+
))
|
|
821
|
+
) {
|
|
822
|
+
bytesRemaining -= chunk.byteLength;
|
|
823
|
+
outputStream.stream.write(chunk);
|
|
824
|
+
}
|
|
825
|
+
if (inputStream.stream.errored) {
|
|
826
|
+
throw streamError(inputStream.stream.errored);
|
|
827
|
+
}
|
|
828
|
+
if (outputStream.stream.errored) {
|
|
829
|
+
throw streamError(outputStream.stream.errored);
|
|
830
|
+
}
|
|
831
|
+
return payload.len - BigInt(bytesRemaining);
|
|
765
832
|
}
|
|
766
833
|
case OUTPUT_STREAM_SUBSCRIBE:
|
|
767
|
-
|
|
834
|
+
return createPoll(streams.get(id).pollState);
|
|
768
835
|
case OUTPUT_STREAM_BLOCKING_SPLICE: {
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
836
|
+
const outputStream = getStreamOrThrow(id);
|
|
837
|
+
let promise = Promise.resolve();
|
|
838
|
+
let resolve, reject;
|
|
839
|
+
if (outputStream.stream.writableNeedDrain) {
|
|
840
|
+
promise = new Promise((_resolve, _reject) => {
|
|
841
|
+
outputStream.stream
|
|
842
|
+
.once('drain', (resolve = _resolve))
|
|
843
|
+
.once('error', (reject = _reject));
|
|
844
|
+
}).then(
|
|
845
|
+
() => {
|
|
846
|
+
outputStream.stream.off('error', reject);
|
|
847
|
+
},
|
|
848
|
+
(err) => {
|
|
849
|
+
outputStream.stream.off('drain', resolve);
|
|
850
|
+
throw streamError(err);
|
|
851
|
+
}
|
|
852
|
+
);
|
|
853
|
+
}
|
|
854
|
+
const inputStream = getStreamOrThrow(payload.src);
|
|
855
|
+
if (!inputStream.stream.readable) {
|
|
856
|
+
promise = promise.then(() =>
|
|
857
|
+
new Promise((_resolve, _reject) => {
|
|
858
|
+
inputStream.stream
|
|
859
|
+
.once('readable', (resolve = _resolve))
|
|
860
|
+
.once('error', (reject = _reject));
|
|
861
|
+
}).then(
|
|
862
|
+
() => {
|
|
863
|
+
inputStream.stream.off('error', reject);
|
|
864
|
+
},
|
|
865
|
+
(err) => {
|
|
866
|
+
inputStream.stream.off('readable', resolve);
|
|
867
|
+
throw streamError(err);
|
|
868
|
+
}
|
|
869
|
+
)
|
|
870
|
+
);
|
|
871
|
+
}
|
|
872
|
+
return promise.then(() =>
|
|
873
|
+
handle(OUTPUT_STREAM_SPLICE, id, payload)
|
|
803
874
|
);
|
|
804
|
-
}
|
|
805
|
-
return promise.then(() => handle(OUTPUT_STREAM_SPLICE, id, payload));
|
|
806
875
|
}
|
|
807
876
|
case OUTPUT_STREAM_DISPOSE: {
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
877
|
+
const stream = streams.get(id);
|
|
878
|
+
verifyPollsDroppedForDrop(stream.pollState, 'output stream');
|
|
879
|
+
stream.stream.end();
|
|
880
|
+
streams.delete(id);
|
|
881
|
+
return;
|
|
813
882
|
}
|
|
814
883
|
|
|
815
884
|
case POLL_POLLABLE_READY:
|
|
816
|
-
|
|
885
|
+
return polls.get(id).ready;
|
|
817
886
|
case POLL_POLLABLE_BLOCK:
|
|
818
|
-
|
|
819
|
-
|
|
887
|
+
payload = [id];
|
|
888
|
+
// [intentional case fall-through]
|
|
820
889
|
case POLL_POLL_LIST: {
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
pollStateCheck(pollState);
|
|
827
|
-
if (pollState.ready) doneList.push(idx);
|
|
828
|
-
}
|
|
829
|
-
if (doneList.length > 0) {
|
|
830
|
-
return new Uint32Array(doneList);
|
|
831
|
-
}
|
|
832
|
-
let readyPromiseResolve;
|
|
833
|
-
const readyPromise = new Promise(
|
|
834
|
-
(resolve) => void (readyPromiseResolve = resolve)
|
|
835
|
-
);
|
|
836
|
-
for (const poll of pollList) {
|
|
837
|
-
poll.listener = readyPromiseResolve;
|
|
838
|
-
}
|
|
839
|
-
return readyPromise.then(() => {
|
|
890
|
+
if (payload.length === 0) {
|
|
891
|
+
throw new Error('wasi-io trap: attempt to poll on empty list');
|
|
892
|
+
}
|
|
893
|
+
const doneList = [];
|
|
894
|
+
const pollList = payload.map((pollId) => polls.get(pollId));
|
|
840
895
|
for (const [idx, pollState] of pollList.entries()) {
|
|
841
|
-
|
|
842
|
-
|
|
896
|
+
pollStateCheck(pollState);
|
|
897
|
+
if (pollState.ready) {
|
|
898
|
+
doneList.push(idx);
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
if (doneList.length > 0) {
|
|
902
|
+
return new Uint32Array(doneList);
|
|
843
903
|
}
|
|
844
|
-
|
|
845
|
-
|
|
904
|
+
let readyPromiseResolve;
|
|
905
|
+
const readyPromise = new Promise(
|
|
906
|
+
(resolve) => void (readyPromiseResolve = resolve)
|
|
907
|
+
);
|
|
908
|
+
for (const poll of pollList) {
|
|
909
|
+
poll.listener = readyPromiseResolve;
|
|
910
|
+
}
|
|
911
|
+
return readyPromise.then(() => {
|
|
912
|
+
for (const [idx, pollState] of pollList.entries()) {
|
|
913
|
+
pollState.listener = null;
|
|
914
|
+
if (pollState.ready) {
|
|
915
|
+
doneList.push(idx);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
return new Uint32Array(doneList);
|
|
919
|
+
});
|
|
846
920
|
}
|
|
847
921
|
case POLL_POLLABLE_DISPOSE:
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
922
|
+
if (!polls.delete(id)) {
|
|
923
|
+
throw new Error(
|
|
924
|
+
`wasi-io trap: Disposed a poll ${id} that does not exist`
|
|
925
|
+
);
|
|
926
|
+
}
|
|
927
|
+
return;
|
|
853
928
|
|
|
854
929
|
case FUTURE_TAKE_VALUE:
|
|
855
|
-
|
|
930
|
+
return futureTakeValue(id);
|
|
856
931
|
|
|
857
932
|
case FUTURE_SUBSCRIBE: {
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
933
|
+
const { pollState } = futures.get(id);
|
|
934
|
+
const pollId = ++pollCnt;
|
|
935
|
+
polls.set(pollId, pollState);
|
|
936
|
+
return pollId;
|
|
862
937
|
}
|
|
863
938
|
case FUTURE_DISPOSE:
|
|
864
|
-
|
|
939
|
+
return void futureDispose(id, true);
|
|
865
940
|
default:
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
941
|
+
throw new Error(
|
|
942
|
+
`wasi-io trap: Unknown call ${call} (${reverseMap[call]}) with type ${
|
|
943
|
+
reverseMap[call & CALL_TYPE_MASK]
|
|
944
|
+
}`
|
|
945
|
+
);
|
|
946
|
+
}
|
|
872
947
|
}
|
|
873
948
|
|
|
874
949
|
/**
|
|
875
950
|
* @param {PollState} pollState
|
|
876
951
|
*/
|
|
877
952
|
function createPoll(pollState) {
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
953
|
+
const pollId = ++pollCnt;
|
|
954
|
+
pollState.polls.push(pollId);
|
|
955
|
+
polls.set(pollId, pollState);
|
|
956
|
+
return pollId;
|
|
882
957
|
}
|
|
883
958
|
|
|
884
959
|
function subscribeInstant(pollState, instant) {
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
960
|
+
const duration = instant - hrtime.bigint();
|
|
961
|
+
if (duration <= 0) {
|
|
962
|
+
return pollStateReady(pollState);
|
|
963
|
+
}
|
|
964
|
+
function cb() {
|
|
965
|
+
if (hrtime.bigint() < instant) {
|
|
966
|
+
return subscribeInstant(pollState, instant);
|
|
967
|
+
}
|
|
968
|
+
pollStateReady(pollState);
|
|
969
|
+
}
|
|
970
|
+
if (duration < 10e6) {
|
|
971
|
+
setImmediate(cb);
|
|
972
|
+
} else {
|
|
973
|
+
setTimeout(cb, Number(duration) / 1e6);
|
|
974
|
+
}
|
|
893
975
|
}
|
|
894
976
|
|
|
895
977
|
/**
|
|
@@ -897,13 +979,14 @@ function subscribeInstant(pollState, instant) {
|
|
|
897
979
|
* @param {string} polledResourceDebugName
|
|
898
980
|
*/
|
|
899
981
|
export function verifyPollsDroppedForDrop(pollState, polledResourceDebugName) {
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
982
|
+
for (const pollId of pollState.polls) {
|
|
983
|
+
const poll = polls.get(pollId);
|
|
984
|
+
if (poll) {
|
|
985
|
+
throw new Error(
|
|
986
|
+
`wasi-io trap: Cannot drop ${polledResourceDebugName} as it has a child poll resource which has not yet been dropped`
|
|
987
|
+
);
|
|
988
|
+
}
|
|
989
|
+
}
|
|
907
990
|
}
|
|
908
991
|
|
|
909
992
|
/**
|
|
@@ -911,41 +994,41 @@ export function verifyPollsDroppedForDrop(pollState, polledResourceDebugName) {
|
|
|
911
994
|
* @param {bool} finished
|
|
912
995
|
*/
|
|
913
996
|
export function pollStateReady(pollState) {
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
997
|
+
if (pollState.ready && pollState.listener) {
|
|
998
|
+
uncaughtException = new Error(
|
|
999
|
+
'wasi-io trap: poll already ready with listener attached'
|
|
1000
|
+
);
|
|
1001
|
+
}
|
|
1002
|
+
pollState.ready = true;
|
|
1003
|
+
if (pollState.listener) {
|
|
1004
|
+
pollState.listener();
|
|
1005
|
+
pollState.listener = null;
|
|
1006
|
+
}
|
|
924
1007
|
}
|
|
925
1008
|
|
|
926
1009
|
/**
|
|
927
1010
|
* @param {PollState} pollState
|
|
928
1011
|
*/
|
|
929
1012
|
function pollStateCheck(pollState) {
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
1013
|
+
if (pollState.ready && pollState.parentStream) {
|
|
1014
|
+
// stream ONLY applies to readable streams here
|
|
1015
|
+
const stream = pollState.parentStream;
|
|
1016
|
+
const res = stream.read(0);
|
|
1017
|
+
if (res !== null) {
|
|
1018
|
+
throw new Error('wasi-io trap: got data for a null read');
|
|
1019
|
+
}
|
|
1020
|
+
if (
|
|
1021
|
+
pollState.ready &&
|
|
1022
|
+
stream.readableLength === 0 &&
|
|
1023
|
+
!stream.readableEnded &&
|
|
1024
|
+
!stream.errored
|
|
1025
|
+
) {
|
|
1026
|
+
pollState.ready = false;
|
|
1027
|
+
stream.once('readable', () => {
|
|
1028
|
+
pollStateReady(pollState);
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
947
1031
|
}
|
|
948
|
-
}
|
|
949
1032
|
}
|
|
950
1033
|
|
|
951
1034
|
/**
|
|
@@ -955,31 +1038,31 @@ function pollStateCheck(pollState) {
|
|
|
955
1038
|
* @returns {number}
|
|
956
1039
|
*/
|
|
957
1040
|
export function createFuture(promise, pollState) {
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
1041
|
+
const futureId = ++futureCnt;
|
|
1042
|
+
if (pollState) {
|
|
1043
|
+
pollState.ready = false;
|
|
1044
|
+
} else {
|
|
1045
|
+
pollState = {
|
|
1046
|
+
ready: false,
|
|
1047
|
+
listener: null,
|
|
1048
|
+
polls: [],
|
|
1049
|
+
parent: null,
|
|
1050
|
+
};
|
|
1051
|
+
}
|
|
1052
|
+
const future = { tag: 'ok', val: null };
|
|
1053
|
+
futures.set(futureId, { future, pollState });
|
|
1054
|
+
promise.then(
|
|
1055
|
+
(value) => {
|
|
1056
|
+
pollStateReady(pollState);
|
|
1057
|
+
future.val = value;
|
|
1058
|
+
},
|
|
1059
|
+
(value) => {
|
|
1060
|
+
pollStateReady(pollState);
|
|
1061
|
+
future.tag = 'err';
|
|
1062
|
+
future.val = value;
|
|
1063
|
+
}
|
|
1064
|
+
);
|
|
1065
|
+
return futureId;
|
|
983
1066
|
}
|
|
984
1067
|
|
|
985
1068
|
/**
|
|
@@ -988,29 +1071,29 @@ export function createFuture(promise, pollState) {
|
|
|
988
1071
|
* @throws {undefined}
|
|
989
1072
|
*/
|
|
990
1073
|
export function futureTakeValue(id) {
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
1074
|
+
const future = futures.get(id);
|
|
1075
|
+
// Not ready = return undefined
|
|
1076
|
+
if (!future.pollState.ready) {
|
|
1077
|
+
return undefined;
|
|
1078
|
+
}
|
|
1079
|
+
// Ready but already taken = return { tag: 'err', val: undefined }
|
|
1080
|
+
if (!future.future) {
|
|
1081
|
+
return { tag: 'err', val: undefined };
|
|
1082
|
+
}
|
|
1083
|
+
const out = { tag: 'ok', val: future.future };
|
|
1084
|
+
future.future = null;
|
|
1085
|
+
return out;
|
|
999
1086
|
}
|
|
1000
1087
|
|
|
1001
1088
|
export function futureDispose(id, ownsState) {
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1089
|
+
const { pollState } = futures.get(id);
|
|
1090
|
+
if (ownsState) {
|
|
1091
|
+
verifyPollsDroppedForDrop(pollState, 'future');
|
|
1092
|
+
}
|
|
1093
|
+
return void futures.delete(id);
|
|
1005
1094
|
}
|
|
1006
1095
|
|
|
1007
1096
|
let uncaughtException;
|
|
1008
|
-
process.on(
|
|
1009
|
-
|
|
1010
|
-
// eslint-disable-next-line no-unused-vars
|
|
1011
|
-
function trace(msg) {
|
|
1012
|
-
const tmpErr = new Error(format(msg));
|
|
1013
|
-
log(tmpErr.stack);
|
|
1014
|
-
}
|
|
1097
|
+
process.on('uncaughtException', (err) => (uncaughtException = err));
|
|
1015
1098
|
|
|
1016
1099
|
const debug = runAsWorker(handle);
|