nuxt-ai-ready 2.5.2 → 2.5.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/dist/module.json +1 -1
- package/dist/runtime/server/middleware/markdown.js +3 -3
- package/dist/runtime/server/utils/negotiation-response.d.ts +1 -1
- package/dist/runtime/server/utils/negotiation-response.js +17 -2
- package/node_modules/mdream/node_modules/@emnapi/core/node_modules/@emnapi/wasi-threads/LICENSE +21 -0
- package/node_modules/mdream/node_modules/@emnapi/core/node_modules/@emnapi/wasi-threads/README.md +203 -0
- package/node_modules/mdream/node_modules/@emnapi/core/node_modules/@emnapi/wasi-threads/dist/wasi-threads.d.ts +236 -0
- package/node_modules/mdream/node_modules/@emnapi/core/node_modules/@emnapi/wasi-threads/dist/wasi-threads.js +1086 -0
- package/node_modules/mdream/node_modules/@emnapi/core/node_modules/@emnapi/wasi-threads/package.json +35 -0
- package/node_modules/mdream/node_modules/@emnapi/core/node_modules/@emnapi/wasi-threads/rollup.config.js +6 -0
- package/node_modules/mdream/node_modules/@emnapi/wasi-threads/dist/wasi-threads.d.ts +4 -0
- package/node_modules/mdream/node_modules/@emnapi/wasi-threads/dist/wasi-threads.js +48 -16
- package/node_modules/mdream/node_modules/@emnapi/wasi-threads/package.json +1 -1
- package/node_modules/mdream/node_modules/@napi-rs/wasm-runtime/dist/fs.js +3339 -4021
- package/node_modules/mdream/node_modules/@napi-rs/wasm-runtime/package.json +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,1086 @@
|
|
|
1
|
+
//#region src/util.ts
|
|
2
|
+
const _WebAssembly = typeof WebAssembly !== 'undefined'
|
|
3
|
+
? WebAssembly
|
|
4
|
+
: typeof WXWebAssembly !== 'undefined'
|
|
5
|
+
? WXWebAssembly
|
|
6
|
+
: undefined;
|
|
7
|
+
const ENVIRONMENT_IS_NODE = typeof process === 'object' && process !== null &&
|
|
8
|
+
typeof process.versions === 'object' && process.versions !== null &&
|
|
9
|
+
typeof process.versions.node === 'string';
|
|
10
|
+
function getPostMessage(options) {
|
|
11
|
+
return typeof options?.postMessage === 'function'
|
|
12
|
+
? options.postMessage
|
|
13
|
+
: typeof postMessage === 'function'
|
|
14
|
+
? postMessage
|
|
15
|
+
: undefined;
|
|
16
|
+
}
|
|
17
|
+
function normalizeError(value) {
|
|
18
|
+
if (value instanceof Error)
|
|
19
|
+
return value;
|
|
20
|
+
if (typeof value === 'object' && value !== null && 'error' in value) {
|
|
21
|
+
const nested = value.error;
|
|
22
|
+
if (nested !== undefined && nested !== value)
|
|
23
|
+
return normalizeError(nested);
|
|
24
|
+
}
|
|
25
|
+
const record = typeof value === 'object' && value !== null
|
|
26
|
+
? value
|
|
27
|
+
: undefined;
|
|
28
|
+
const message = record?.message !== undefined
|
|
29
|
+
? String(record.message)
|
|
30
|
+
: typeof value === 'string'
|
|
31
|
+
? value
|
|
32
|
+
: 'Worker sent an unknown error';
|
|
33
|
+
const name = record?.name !== undefined ? String(record.name) : 'Error';
|
|
34
|
+
let error;
|
|
35
|
+
try {
|
|
36
|
+
const ErrorConstructor = name === 'RuntimeError'
|
|
37
|
+
? (_WebAssembly?.RuntimeError ?? Error)
|
|
38
|
+
: Error;
|
|
39
|
+
error = new ErrorConstructor(message);
|
|
40
|
+
}
|
|
41
|
+
catch (_) {
|
|
42
|
+
error = new Error(message);
|
|
43
|
+
}
|
|
44
|
+
error.name = name;
|
|
45
|
+
if (record?.stack !== undefined) {
|
|
46
|
+
Object.defineProperty(error, 'stack', {
|
|
47
|
+
value: String(record.stack),
|
|
48
|
+
writable: true,
|
|
49
|
+
enumerable: false,
|
|
50
|
+
configurable: true
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
if (record?.cause !== undefined) {
|
|
54
|
+
Object.defineProperty(error, 'cause', {
|
|
55
|
+
value: record.cause,
|
|
56
|
+
writable: true,
|
|
57
|
+
enumerable: false,
|
|
58
|
+
configurable: true
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return error;
|
|
62
|
+
}
|
|
63
|
+
function serializeError(value) {
|
|
64
|
+
const error = normalizeError(value);
|
|
65
|
+
const serialized = {
|
|
66
|
+
name: error.name,
|
|
67
|
+
message: error.message
|
|
68
|
+
};
|
|
69
|
+
if (error.stack !== undefined)
|
|
70
|
+
serialized.stack = error.stack;
|
|
71
|
+
if ('cause' in error && error.cause !== undefined)
|
|
72
|
+
serialized.cause = error.cause;
|
|
73
|
+
return serialized;
|
|
74
|
+
}
|
|
75
|
+
function deserializeError(value) {
|
|
76
|
+
return normalizeError(value);
|
|
77
|
+
}
|
|
78
|
+
function serializeErrorToBuffer(sab, code, error) {
|
|
79
|
+
const i32array = new Int32Array(sab);
|
|
80
|
+
Atomics.store(i32array, 0, code);
|
|
81
|
+
if (code > 1 && error) {
|
|
82
|
+
const name = error.name;
|
|
83
|
+
const message = error.message;
|
|
84
|
+
const stack = error.stack ?? '';
|
|
85
|
+
const nameBuffer = new TextEncoder().encode(name);
|
|
86
|
+
const messageBuffer = new TextEncoder().encode(message);
|
|
87
|
+
const stackBuffer = new TextEncoder().encode(stack);
|
|
88
|
+
Atomics.store(i32array, 1, nameBuffer.length);
|
|
89
|
+
Atomics.store(i32array, 2, messageBuffer.length);
|
|
90
|
+
Atomics.store(i32array, 3, stackBuffer.length);
|
|
91
|
+
const buffer = new Uint8Array(sab);
|
|
92
|
+
buffer.set(nameBuffer, 16);
|
|
93
|
+
buffer.set(messageBuffer, 16 + nameBuffer.length);
|
|
94
|
+
buffer.set(stackBuffer, 16 + nameBuffer.length + messageBuffer.length);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function deserializeErrorFromBuffer(sab) {
|
|
98
|
+
const i32array = new Int32Array(sab);
|
|
99
|
+
const status = Atomics.load(i32array, 0);
|
|
100
|
+
if (status <= 1) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
const nameLength = Atomics.load(i32array, 1);
|
|
104
|
+
const messageLength = Atomics.load(i32array, 2);
|
|
105
|
+
const stackLength = Atomics.load(i32array, 3);
|
|
106
|
+
const buffer = new Uint8Array(sab);
|
|
107
|
+
const nameBuffer = buffer.slice(16, 16 + nameLength);
|
|
108
|
+
const messageBuffer = buffer.slice(16 + nameLength, 16 + nameLength + messageLength);
|
|
109
|
+
const stackBuffer = buffer.slice(16 + nameLength + messageLength, 16 + nameLength + messageLength + stackLength);
|
|
110
|
+
const name = new TextDecoder().decode(nameBuffer);
|
|
111
|
+
const message = new TextDecoder().decode(messageBuffer);
|
|
112
|
+
const stack = new TextDecoder().decode(stackBuffer);
|
|
113
|
+
const ErrorConstructor = globalThis[name] ?? (name === 'RuntimeError' ? (_WebAssembly.RuntimeError ?? Error) : Error);
|
|
114
|
+
const error = new ErrorConstructor(message);
|
|
115
|
+
Object.defineProperty(error, 'stack', {
|
|
116
|
+
value: stack,
|
|
117
|
+
writable: true,
|
|
118
|
+
enumerable: false,
|
|
119
|
+
configurable: true
|
|
120
|
+
});
|
|
121
|
+
return error;
|
|
122
|
+
}
|
|
123
|
+
const deserizeErrorFromBuffer = deserializeErrorFromBuffer;
|
|
124
|
+
function isSharedArrayBuffer(value) {
|
|
125
|
+
return ((typeof SharedArrayBuffer === 'function' && value instanceof SharedArrayBuffer) ||
|
|
126
|
+
(Object.prototype.toString.call(value) === '[object SharedArrayBuffer]'));
|
|
127
|
+
}
|
|
128
|
+
function isTrapError(e) {
|
|
129
|
+
try {
|
|
130
|
+
return e instanceof _WebAssembly.RuntimeError || e?.name === 'RuntimeError';
|
|
131
|
+
}
|
|
132
|
+
catch (_) {
|
|
133
|
+
return e?.name === 'RuntimeError';
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
//#endregion src/util.ts
|
|
138
|
+
|
|
139
|
+
//#region src/command.ts
|
|
140
|
+
function createMessage(type, payload) {
|
|
141
|
+
return {
|
|
142
|
+
__emnapi__: {
|
|
143
|
+
type,
|
|
144
|
+
payload
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
//#endregion src/command.ts
|
|
150
|
+
|
|
151
|
+
//#region src/thread-manager.ts
|
|
152
|
+
const WASI_THREADS_MAX_TID = 0x1FFFFFFF;
|
|
153
|
+
function checkSharedWasmMemory(wasmMemory) {
|
|
154
|
+
if (wasmMemory) {
|
|
155
|
+
if (!isSharedArrayBuffer(wasmMemory.buffer)) {
|
|
156
|
+
throw new Error('Multithread features require shared wasm memory. ' +
|
|
157
|
+
'Try to compile with `-matomics -mbulk-memory` and use `--import-memory --shared-memory` during linking, ' +
|
|
158
|
+
'then create WebAssembly.Memory with `shared: true` option');
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
if (typeof SharedArrayBuffer === 'undefined') {
|
|
163
|
+
throw new Error('Current environment does not support SharedArrayBuffer, threads are not available!');
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
function getReuseWorker(value) {
|
|
168
|
+
if (typeof value === 'boolean') {
|
|
169
|
+
return value ? { size: 0, strict: false } : false;
|
|
170
|
+
}
|
|
171
|
+
if (typeof value === 'number') {
|
|
172
|
+
if (!(value >= 0)) {
|
|
173
|
+
throw new RangeError('reuseWorker: size must be a non-negative integer');
|
|
174
|
+
}
|
|
175
|
+
return { size: value, strict: false };
|
|
176
|
+
}
|
|
177
|
+
if (!value) {
|
|
178
|
+
return false;
|
|
179
|
+
}
|
|
180
|
+
const size = Number(value.size) || 0;
|
|
181
|
+
const strict = Boolean(value.strict);
|
|
182
|
+
if (!(size > 0) && strict) {
|
|
183
|
+
throw new RangeError('reuseWorker: size must be set to positive integer if strict is set to true');
|
|
184
|
+
}
|
|
185
|
+
return { size, strict };
|
|
186
|
+
}
|
|
187
|
+
let nextWorkerID = 0;
|
|
188
|
+
class ThreadManager {
|
|
189
|
+
get nextWorkerID() { return nextWorkerID; }
|
|
190
|
+
constructor(options) {
|
|
191
|
+
this.unusedWorkers = [];
|
|
192
|
+
this.pthreads = Object.create(null);
|
|
193
|
+
this.wasmModule = null;
|
|
194
|
+
this.wasmMemory = null;
|
|
195
|
+
this.messageEvents = new WeakMap();
|
|
196
|
+
this.registeredWorkers = new Set();
|
|
197
|
+
this.expectedTerminations = new WeakSet();
|
|
198
|
+
this.loadRejects = new WeakMap();
|
|
199
|
+
if (!options) {
|
|
200
|
+
throw new TypeError('ThreadManager(): options is not provided');
|
|
201
|
+
}
|
|
202
|
+
if ('childThread' in options) {
|
|
203
|
+
this._childThread = Boolean(options.childThread);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
this._childThread = false;
|
|
207
|
+
}
|
|
208
|
+
if (this._childThread) {
|
|
209
|
+
this._onCreateWorker = undefined;
|
|
210
|
+
this._reuseWorker = false;
|
|
211
|
+
this._beforeLoad = undefined;
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
this._onCreateWorker = options.onCreateWorker;
|
|
215
|
+
this._reuseWorker = getReuseWorker(options.reuseWorker);
|
|
216
|
+
this._beforeLoad = options.beforeLoad;
|
|
217
|
+
}
|
|
218
|
+
this.printErr = options.printErr ?? console.error.bind(console);
|
|
219
|
+
this.threadSpawn = options.threadSpawn;
|
|
220
|
+
}
|
|
221
|
+
init() {
|
|
222
|
+
if (!this._childThread) {
|
|
223
|
+
this.initMainThread();
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
initMainThread() {
|
|
227
|
+
this.preparePool();
|
|
228
|
+
}
|
|
229
|
+
preparePool() {
|
|
230
|
+
if (this._reuseWorker) {
|
|
231
|
+
if (this._reuseWorker.size) {
|
|
232
|
+
let pthreadPoolSize = this._reuseWorker.size;
|
|
233
|
+
while (pthreadPoolSize--) {
|
|
234
|
+
const worker = this.allocateUnusedWorker();
|
|
235
|
+
if (ENVIRONMENT_IS_NODE) {
|
|
236
|
+
worker.once('message', () => { });
|
|
237
|
+
worker.unref();
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
shouldPreloadWorkers() {
|
|
244
|
+
return !this._childThread && this._reuseWorker && this._reuseWorker.size > 0;
|
|
245
|
+
}
|
|
246
|
+
loadWasmModuleToAllWorkers() {
|
|
247
|
+
const promises = Array(this.unusedWorkers.length);
|
|
248
|
+
for (let i = 0; i < this.unusedWorkers.length; ++i) {
|
|
249
|
+
const worker = this.unusedWorkers[i];
|
|
250
|
+
if (ENVIRONMENT_IS_NODE)
|
|
251
|
+
worker.ref();
|
|
252
|
+
promises[i] = this.loadWasmModuleToWorker(worker).then((w) => {
|
|
253
|
+
if (ENVIRONMENT_IS_NODE)
|
|
254
|
+
worker.unref();
|
|
255
|
+
return w;
|
|
256
|
+
}, (e) => {
|
|
257
|
+
if (ENVIRONMENT_IS_NODE)
|
|
258
|
+
worker.unref();
|
|
259
|
+
throw e;
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
return Promise.all(promises).catch((err) => {
|
|
263
|
+
this.terminateAllThreads();
|
|
264
|
+
throw err;
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
preloadWorkers() {
|
|
268
|
+
if (this.shouldPreloadWorkers()) {
|
|
269
|
+
return this.loadWasmModuleToAllWorkers();
|
|
270
|
+
}
|
|
271
|
+
return Promise.resolve([]);
|
|
272
|
+
}
|
|
273
|
+
setup(wasmModule, wasmMemory) {
|
|
274
|
+
this.wasmModule = wasmModule;
|
|
275
|
+
this.wasmMemory = wasmMemory;
|
|
276
|
+
}
|
|
277
|
+
assertRunning() {
|
|
278
|
+
if (this._fatalError)
|
|
279
|
+
throw this._fatalError;
|
|
280
|
+
}
|
|
281
|
+
fail(value, rethrow) {
|
|
282
|
+
if (this._fatalError)
|
|
283
|
+
return;
|
|
284
|
+
this._fatalError = normalizeError(value);
|
|
285
|
+
this.shutdownAllWorkers(false, this._fatalError);
|
|
286
|
+
if (rethrow) {
|
|
287
|
+
const error = this._fatalError;
|
|
288
|
+
Promise.resolve().then(() => { throw error; });
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
markId(worker) {
|
|
292
|
+
this.assertRunning();
|
|
293
|
+
if (worker.__emnapi_tid)
|
|
294
|
+
return worker.__emnapi_tid;
|
|
295
|
+
const tid = nextWorkerID + 43;
|
|
296
|
+
nextWorkerID = (nextWorkerID + 1) % (WASI_THREADS_MAX_TID - 42);
|
|
297
|
+
this.pthreads[tid] = worker;
|
|
298
|
+
worker.__emnapi_tid = tid;
|
|
299
|
+
return tid;
|
|
300
|
+
}
|
|
301
|
+
returnWorkerToPool(worker) {
|
|
302
|
+
if (this._fatalError) {
|
|
303
|
+
this.terminateWorker(worker);
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
var tid = worker.__emnapi_tid;
|
|
307
|
+
if (tid !== undefined) {
|
|
308
|
+
delete this.pthreads[tid];
|
|
309
|
+
}
|
|
310
|
+
this.unusedWorkers.push(worker);
|
|
311
|
+
delete worker.__emnapi_tid;
|
|
312
|
+
if (ENVIRONMENT_IS_NODE) {
|
|
313
|
+
worker.unref();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
loadWasmModuleToWorker(worker, sab) {
|
|
317
|
+
this.assertRunning();
|
|
318
|
+
if (worker.whenLoaded)
|
|
319
|
+
return worker.whenLoaded;
|
|
320
|
+
this.registeredWorkers.add(worker);
|
|
321
|
+
const err = this.printErr;
|
|
322
|
+
const beforeLoad = this._beforeLoad;
|
|
323
|
+
const _this = this;
|
|
324
|
+
worker.whenLoaded = new Promise((resolve, reject) => {
|
|
325
|
+
const handleError = function (e) {
|
|
326
|
+
if (_this.expectedTerminations.has(worker))
|
|
327
|
+
return;
|
|
328
|
+
let message = 'worker sent an error!';
|
|
329
|
+
if (worker.__emnapi_tid !== undefined) {
|
|
330
|
+
message = 'worker (tid = ' + worker.__emnapi_tid + ') sent an error!';
|
|
331
|
+
}
|
|
332
|
+
const error = normalizeError(e);
|
|
333
|
+
if (error.message) {
|
|
334
|
+
err(message + ' ' + error.message);
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
err(message);
|
|
338
|
+
}
|
|
339
|
+
if (!worker.loaded) {
|
|
340
|
+
reject(error);
|
|
341
|
+
_this.loadRejects.delete(worker);
|
|
342
|
+
_this.terminateWorker(worker);
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
_this.fail(error, !ENVIRONMENT_IS_NODE);
|
|
346
|
+
if (ENVIRONMENT_IS_NODE)
|
|
347
|
+
throw error;
|
|
348
|
+
};
|
|
349
|
+
const handleMessage = (data) => {
|
|
350
|
+
if (data.__emnapi__) {
|
|
351
|
+
const type = data.__emnapi__.type;
|
|
352
|
+
const payload = data.__emnapi__.payload;
|
|
353
|
+
if (type === 'loaded') {
|
|
354
|
+
worker.loaded = true;
|
|
355
|
+
this.loadRejects.delete(worker);
|
|
356
|
+
if (ENVIRONMENT_IS_NODE && !worker.__emnapi_tid) {
|
|
357
|
+
worker.unref();
|
|
358
|
+
}
|
|
359
|
+
resolve(worker);
|
|
360
|
+
}
|
|
361
|
+
else if (type === 'cleanup-thread') {
|
|
362
|
+
if (payload.tid in this.pthreads) {
|
|
363
|
+
this.cleanThread(worker, payload.tid);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
else if (type === 'spawn-thread') {
|
|
367
|
+
this.threadSpawn(payload.startArg, payload.errorOrTid);
|
|
368
|
+
}
|
|
369
|
+
else if (type === 'terminate-all-threads') {
|
|
370
|
+
this.terminateAllThreads();
|
|
371
|
+
}
|
|
372
|
+
else if (type === 'thread-error') {
|
|
373
|
+
const threadError = payload;
|
|
374
|
+
const error = deserializeError(threadError.error);
|
|
375
|
+
if (!worker.loaded && threadError.phase === 'load') {
|
|
376
|
+
reject(error);
|
|
377
|
+
this.loadRejects.delete(worker);
|
|
378
|
+
this.terminateWorker(worker);
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
this.fail(error, true);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
worker.onmessage = (e) => {
|
|
387
|
+
handleMessage(e.data);
|
|
388
|
+
this.fireMessageEvent(worker, e);
|
|
389
|
+
};
|
|
390
|
+
worker.onerror = handleError;
|
|
391
|
+
worker.onmessageerror = (e) => {
|
|
392
|
+
handleError(normalizeError(e));
|
|
393
|
+
};
|
|
394
|
+
if (ENVIRONMENT_IS_NODE) {
|
|
395
|
+
worker.on('message', function (data) {
|
|
396
|
+
worker.onmessage?.({
|
|
397
|
+
data
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
worker.on('error', function (e) {
|
|
401
|
+
worker.onerror?.(e);
|
|
402
|
+
});
|
|
403
|
+
worker.on('messageerror', function (e) {
|
|
404
|
+
handleError(normalizeError(e));
|
|
405
|
+
});
|
|
406
|
+
worker.on('exit', function (code) {
|
|
407
|
+
if (!_this.expectedTerminations.has(worker)) {
|
|
408
|
+
handleError(new Error('Worker stopped with exit code ' + code));
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
worker.on('detachedExit', function () { });
|
|
412
|
+
}
|
|
413
|
+
this.loadRejects.set(worker, reject);
|
|
414
|
+
try {
|
|
415
|
+
if (typeof beforeLoad === 'function') {
|
|
416
|
+
beforeLoad(worker);
|
|
417
|
+
}
|
|
418
|
+
worker.postMessage(createMessage('load', {
|
|
419
|
+
wasmModule: this.wasmModule,
|
|
420
|
+
wasmMemory: this.wasmMemory,
|
|
421
|
+
sab
|
|
422
|
+
}));
|
|
423
|
+
}
|
|
424
|
+
catch (caughtError) {
|
|
425
|
+
let error = caughtError;
|
|
426
|
+
try {
|
|
427
|
+
checkSharedWasmMemory(this.wasmMemory);
|
|
428
|
+
}
|
|
429
|
+
catch (memoryError) {
|
|
430
|
+
error = memoryError;
|
|
431
|
+
}
|
|
432
|
+
reject(error);
|
|
433
|
+
this.loadRejects.delete(worker);
|
|
434
|
+
this.terminateWorker(worker);
|
|
435
|
+
}
|
|
436
|
+
});
|
|
437
|
+
return worker.whenLoaded;
|
|
438
|
+
}
|
|
439
|
+
allocateUnusedWorker() {
|
|
440
|
+
this.assertRunning();
|
|
441
|
+
const _onCreateWorker = this._onCreateWorker;
|
|
442
|
+
if (typeof _onCreateWorker !== 'function') {
|
|
443
|
+
throw new TypeError('`options.onCreateWorker` is not provided');
|
|
444
|
+
}
|
|
445
|
+
const worker = _onCreateWorker({ type: 'thread', name: 'emnapi-pthread' });
|
|
446
|
+
this.registeredWorkers.add(worker);
|
|
447
|
+
this.unusedWorkers.push(worker);
|
|
448
|
+
return worker;
|
|
449
|
+
}
|
|
450
|
+
getNewWorker(sab) {
|
|
451
|
+
this.assertRunning();
|
|
452
|
+
if (this._reuseWorker) {
|
|
453
|
+
if (this.unusedWorkers.length === 0) {
|
|
454
|
+
if (this._reuseWorker.strict) {
|
|
455
|
+
if (!ENVIRONMENT_IS_NODE) {
|
|
456
|
+
const err = this.printErr;
|
|
457
|
+
err('Tried to spawn a new thread, but the thread pool is exhausted.\n' +
|
|
458
|
+
'This might result in a deadlock unless some threads eventually exit or the code explicitly breaks out to the event loop.');
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
const worker = this.allocateUnusedWorker();
|
|
463
|
+
this.loadWasmModuleToWorker(worker, sab);
|
|
464
|
+
}
|
|
465
|
+
return this.unusedWorkers.pop();
|
|
466
|
+
}
|
|
467
|
+
const worker = this.allocateUnusedWorker();
|
|
468
|
+
this.loadWasmModuleToWorker(worker, sab);
|
|
469
|
+
return this.unusedWorkers.pop();
|
|
470
|
+
}
|
|
471
|
+
cleanThread(worker, tid, force) {
|
|
472
|
+
if (!force && this._reuseWorker) {
|
|
473
|
+
this.returnWorkerToPool(worker);
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
delete this.pthreads[tid];
|
|
477
|
+
this.terminateWorker(worker);
|
|
478
|
+
delete worker.__emnapi_tid;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
terminateWorker(worker) {
|
|
482
|
+
const tid = worker.__emnapi_tid;
|
|
483
|
+
this.expectedTerminations.add(worker);
|
|
484
|
+
this.registeredWorkers.delete(worker);
|
|
485
|
+
this.loadRejects.delete(worker);
|
|
486
|
+
worker.terminate();
|
|
487
|
+
this.messageEvents.get(worker)?.clear();
|
|
488
|
+
this.messageEvents.delete(worker);
|
|
489
|
+
worker.onmessage = (e) => {
|
|
490
|
+
if (e.data.__emnapi__) {
|
|
491
|
+
const err = this.printErr;
|
|
492
|
+
err('received "' + e.data.__emnapi__.type + '" command from terminated worker: ' + tid);
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
terminateAllThreads() {
|
|
497
|
+
this.shutdownAllWorkers(true);
|
|
498
|
+
}
|
|
499
|
+
shutdownAllWorkers(recreatePool, reason) {
|
|
500
|
+
const workers = new Set([
|
|
501
|
+
...this.registeredWorkers,
|
|
502
|
+
...Object.values(this.pthreads),
|
|
503
|
+
...this.unusedWorkers
|
|
504
|
+
]);
|
|
505
|
+
workers.forEach((worker) => {
|
|
506
|
+
if (reason)
|
|
507
|
+
this.loadRejects.get(worker)?.(reason);
|
|
508
|
+
this.terminateWorker(worker);
|
|
509
|
+
});
|
|
510
|
+
this.unusedWorkers = [];
|
|
511
|
+
this.pthreads = Object.create(null);
|
|
512
|
+
if (recreatePool && !this._fatalError)
|
|
513
|
+
this.preparePool();
|
|
514
|
+
}
|
|
515
|
+
addMessageEventListener(worker, onMessage) {
|
|
516
|
+
let listeners = this.messageEvents.get(worker);
|
|
517
|
+
if (!listeners) {
|
|
518
|
+
listeners = new Set();
|
|
519
|
+
this.messageEvents.set(worker, listeners);
|
|
520
|
+
}
|
|
521
|
+
listeners.add(onMessage);
|
|
522
|
+
return () => {
|
|
523
|
+
listeners?.delete(onMessage);
|
|
524
|
+
};
|
|
525
|
+
}
|
|
526
|
+
fireMessageEvent(worker, e) {
|
|
527
|
+
const listeners = this.messageEvents.get(worker);
|
|
528
|
+
if (!listeners)
|
|
529
|
+
return;
|
|
530
|
+
const err = this.printErr;
|
|
531
|
+
listeners.forEach((listener) => {
|
|
532
|
+
try {
|
|
533
|
+
listener(e);
|
|
534
|
+
}
|
|
535
|
+
catch (e) {
|
|
536
|
+
err(e.stack);
|
|
537
|
+
}
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
//#endregion src/thread-manager.ts
|
|
543
|
+
|
|
544
|
+
//#region src/proxy.ts
|
|
545
|
+
const kIsProxy = Symbol('kIsProxy');
|
|
546
|
+
function createInstanceProxy(instance, memory) {
|
|
547
|
+
if (instance[kIsProxy])
|
|
548
|
+
return instance;
|
|
549
|
+
const originalExports = instance.exports;
|
|
550
|
+
const createHandler = function (target) {
|
|
551
|
+
const handlers = [
|
|
552
|
+
'apply',
|
|
553
|
+
'construct',
|
|
554
|
+
'defineProperty',
|
|
555
|
+
'deleteProperty',
|
|
556
|
+
'get',
|
|
557
|
+
'getOwnPropertyDescriptor',
|
|
558
|
+
'getPrototypeOf',
|
|
559
|
+
'has',
|
|
560
|
+
'isExtensible',
|
|
561
|
+
'ownKeys',
|
|
562
|
+
'preventExtensions',
|
|
563
|
+
'set',
|
|
564
|
+
'setPrototypeOf'
|
|
565
|
+
];
|
|
566
|
+
const handler = {};
|
|
567
|
+
for (let i = 0; i < handlers.length; i++) {
|
|
568
|
+
const name = handlers[i];
|
|
569
|
+
handler[name] = function () {
|
|
570
|
+
const args = Array.prototype.slice.call(arguments, 1);
|
|
571
|
+
args.unshift(target);
|
|
572
|
+
return Reflect[name].apply(Reflect, args);
|
|
573
|
+
};
|
|
574
|
+
}
|
|
575
|
+
return handler;
|
|
576
|
+
};
|
|
577
|
+
const handler = createHandler(originalExports);
|
|
578
|
+
const _initialize = () => { };
|
|
579
|
+
const _start = () => 0;
|
|
580
|
+
handler.get = function (_target, p, receiver) {
|
|
581
|
+
if (p === 'memory') {
|
|
582
|
+
return (typeof memory === 'function' ? memory() : memory) ?? Reflect.get(originalExports, p, receiver);
|
|
583
|
+
}
|
|
584
|
+
if (p === '_initialize') {
|
|
585
|
+
return p in originalExports ? _initialize : undefined;
|
|
586
|
+
}
|
|
587
|
+
if (p === '_start') {
|
|
588
|
+
return p in originalExports ? _start : undefined;
|
|
589
|
+
}
|
|
590
|
+
return Reflect.get(originalExports, p, receiver);
|
|
591
|
+
};
|
|
592
|
+
handler.has = function (_target, p) {
|
|
593
|
+
if (p === 'memory')
|
|
594
|
+
return true;
|
|
595
|
+
return Reflect.has(originalExports, p);
|
|
596
|
+
};
|
|
597
|
+
const exportsProxy = new Proxy(Object.create(null), handler);
|
|
598
|
+
return new Proxy(instance, {
|
|
599
|
+
get(target, p, receiver) {
|
|
600
|
+
if (p === 'exports') {
|
|
601
|
+
return exportsProxy;
|
|
602
|
+
}
|
|
603
|
+
if (p === kIsProxy) {
|
|
604
|
+
return true;
|
|
605
|
+
}
|
|
606
|
+
return Reflect.get(target, p, receiver);
|
|
607
|
+
}
|
|
608
|
+
});
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
//#endregion src/proxy.ts
|
|
612
|
+
|
|
613
|
+
//#region src/wasi-threads.ts
|
|
614
|
+
const patchedWasiInstances = new WeakMap();
|
|
615
|
+
const THREAD_SPAWN_RESULT_SIZE = Int32Array.BYTES_PER_ELEMENT * 2;
|
|
616
|
+
const sharedArrayBufferByteLength = typeof SharedArrayBuffer === 'function'
|
|
617
|
+
? Object.getOwnPropertyDescriptor(SharedArrayBuffer.prototype, 'byteLength').get
|
|
618
|
+
: undefined;
|
|
619
|
+
function isConclusivelySharedArrayBuffer(buffer) {
|
|
620
|
+
if (sharedArrayBufferByteLength === undefined)
|
|
621
|
+
return false;
|
|
622
|
+
try {
|
|
623
|
+
sharedArrayBufferByteLength.call(buffer);
|
|
624
|
+
return true;
|
|
625
|
+
}
|
|
626
|
+
catch (_) {
|
|
627
|
+
return false;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
function getThreadSpawnResultView(memory, address, wasm64) {
|
|
631
|
+
const offset = typeof address === 'bigint' ? Number(address) : address >>> 0;
|
|
632
|
+
let buffer = memory.buffer;
|
|
633
|
+
if (offset + THREAD_SPAWN_RESULT_SIZE > buffer.byteLength &&
|
|
634
|
+
isConclusivelySharedArrayBuffer(buffer)) {
|
|
635
|
+
if (wasm64) {
|
|
636
|
+
memory.grow(BigInt(0));
|
|
637
|
+
}
|
|
638
|
+
else {
|
|
639
|
+
memory.grow(0);
|
|
640
|
+
}
|
|
641
|
+
buffer = memory.buffer;
|
|
642
|
+
}
|
|
643
|
+
return new Int32Array(buffer, offset, 2);
|
|
644
|
+
}
|
|
645
|
+
class WASIThreads {
|
|
646
|
+
constructor(options) {
|
|
647
|
+
if (!options) {
|
|
648
|
+
throw new TypeError('WASIThreads(): options is not provided');
|
|
649
|
+
}
|
|
650
|
+
if (!options.wasi) {
|
|
651
|
+
throw new TypeError('WASIThreads(): options.wasi is not provided');
|
|
652
|
+
}
|
|
653
|
+
patchedWasiInstances.set(this, new WeakSet());
|
|
654
|
+
const wasi = options.wasi;
|
|
655
|
+
patchWasiInstance(this, wasi);
|
|
656
|
+
this.wasi = wasi;
|
|
657
|
+
if ('childThread' in options) {
|
|
658
|
+
this.childThread = Boolean(options.childThread);
|
|
659
|
+
}
|
|
660
|
+
else {
|
|
661
|
+
this.childThread = false;
|
|
662
|
+
}
|
|
663
|
+
this.PThread = undefined;
|
|
664
|
+
if ('threadManager' in options) {
|
|
665
|
+
if (typeof options.threadManager === 'function') {
|
|
666
|
+
this.PThread = options.threadManager();
|
|
667
|
+
}
|
|
668
|
+
else {
|
|
669
|
+
this.PThread = options.threadManager;
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
else {
|
|
673
|
+
if (!this.childThread) {
|
|
674
|
+
this.PThread = new ThreadManager(options);
|
|
675
|
+
this.PThread.init();
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
let waitThreadStart = false;
|
|
679
|
+
if ('waitThreadStart' in options) {
|
|
680
|
+
waitThreadStart = typeof options.waitThreadStart === 'number' ? options.waitThreadStart : Boolean(options.waitThreadStart);
|
|
681
|
+
}
|
|
682
|
+
const postMessage = getPostMessage(options);
|
|
683
|
+
if (this.childThread && typeof postMessage !== 'function') {
|
|
684
|
+
throw new TypeError('options.postMessage is not a function');
|
|
685
|
+
}
|
|
686
|
+
this.postMessage = postMessage;
|
|
687
|
+
const wasm64 = Boolean(options.wasm64);
|
|
688
|
+
const threadSpawn = (startArg, errorOrTid) => {
|
|
689
|
+
const EAGAIN = 6;
|
|
690
|
+
const isNewABI = errorOrTid !== undefined;
|
|
691
|
+
try {
|
|
692
|
+
checkSharedWasmMemory(this.wasmMemory);
|
|
693
|
+
}
|
|
694
|
+
catch (err) {
|
|
695
|
+
this.PThread?.printErr(err.stack);
|
|
696
|
+
if (isNewABI) {
|
|
697
|
+
const struct = getThreadSpawnResultView(this.wasmMemory, errorOrTid, wasm64);
|
|
698
|
+
Atomics.store(struct, 0, 1);
|
|
699
|
+
Atomics.store(struct, 1, EAGAIN);
|
|
700
|
+
Atomics.notify(struct, 1);
|
|
701
|
+
return 1;
|
|
702
|
+
}
|
|
703
|
+
else {
|
|
704
|
+
return -EAGAIN;
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
if (!isNewABI) {
|
|
708
|
+
const malloc = this.wasmInstance.exports.malloc;
|
|
709
|
+
errorOrTid = wasm64 ? Number(malloc(BigInt(8))) : (malloc(8) >>> 0);
|
|
710
|
+
if (!errorOrTid) {
|
|
711
|
+
return -48;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
const _free = this.wasmInstance.exports.free;
|
|
715
|
+
const free = wasm64 ? (ptr) => { _free(BigInt(ptr)); } : _free;
|
|
716
|
+
const struct = getThreadSpawnResultView(this.wasmMemory, errorOrTid, wasm64);
|
|
717
|
+
Atomics.store(struct, 0, 0);
|
|
718
|
+
Atomics.store(struct, 1, 0);
|
|
719
|
+
if (this.childThread) {
|
|
720
|
+
postMessage(createMessage('spawn-thread', {
|
|
721
|
+
startArg,
|
|
722
|
+
errorOrTid: errorOrTid
|
|
723
|
+
}));
|
|
724
|
+
Atomics.wait(struct, 1, 0);
|
|
725
|
+
const isError = Atomics.load(struct, 0);
|
|
726
|
+
const result = Atomics.load(struct, 1);
|
|
727
|
+
if (isNewABI) {
|
|
728
|
+
return isError;
|
|
729
|
+
}
|
|
730
|
+
free(errorOrTid);
|
|
731
|
+
return isError ? -result : result;
|
|
732
|
+
}
|
|
733
|
+
const shouldWait = waitThreadStart || (waitThreadStart === 0);
|
|
734
|
+
let sab;
|
|
735
|
+
if (shouldWait) {
|
|
736
|
+
sab = new Int32Array(new SharedArrayBuffer(16 + 8192));
|
|
737
|
+
Atomics.store(sab, 0, 0);
|
|
738
|
+
}
|
|
739
|
+
let worker;
|
|
740
|
+
let tid;
|
|
741
|
+
const PThread = this.PThread;
|
|
742
|
+
try {
|
|
743
|
+
worker = PThread.getNewWorker(sab);
|
|
744
|
+
if (!worker) {
|
|
745
|
+
throw new Error('failed to get new worker');
|
|
746
|
+
}
|
|
747
|
+
tid = PThread.markId(worker);
|
|
748
|
+
if (ENVIRONMENT_IS_NODE) {
|
|
749
|
+
worker.unref();
|
|
750
|
+
}
|
|
751
|
+
worker.postMessage(createMessage('start', {
|
|
752
|
+
tid,
|
|
753
|
+
arg: startArg,
|
|
754
|
+
sab
|
|
755
|
+
}));
|
|
756
|
+
if (shouldWait) {
|
|
757
|
+
if (typeof waitThreadStart === 'number') {
|
|
758
|
+
const waitResult = Atomics.wait(sab, 0, 0, waitThreadStart);
|
|
759
|
+
if (waitResult === 'timed-out') {
|
|
760
|
+
throw new Error('Spawning thread timed out. Please check if the worker is created successfully and if message is handled properly in the worker.');
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
else {
|
|
764
|
+
Atomics.wait(sab, 0, 0);
|
|
765
|
+
}
|
|
766
|
+
const r = Atomics.load(sab, 0);
|
|
767
|
+
if (r > 1) {
|
|
768
|
+
throw deserizeErrorFromBuffer(sab.buffer);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
catch (e) {
|
|
773
|
+
if (worker !== undefined && tid !== undefined) {
|
|
774
|
+
try {
|
|
775
|
+
PThread.cleanThread(worker, tid, true);
|
|
776
|
+
}
|
|
777
|
+
catch (_) { }
|
|
778
|
+
}
|
|
779
|
+
Atomics.store(struct, 0, 1);
|
|
780
|
+
Atomics.store(struct, 1, EAGAIN);
|
|
781
|
+
Atomics.notify(struct, 1);
|
|
782
|
+
PThread?.printErr(e.stack);
|
|
783
|
+
if (isNewABI) {
|
|
784
|
+
return 1;
|
|
785
|
+
}
|
|
786
|
+
free(errorOrTid);
|
|
787
|
+
return -EAGAIN;
|
|
788
|
+
}
|
|
789
|
+
Atomics.store(struct, 0, 0);
|
|
790
|
+
Atomics.store(struct, 1, tid);
|
|
791
|
+
Atomics.notify(struct, 1);
|
|
792
|
+
if (!shouldWait) {
|
|
793
|
+
worker.whenLoaded.catch((err) => {
|
|
794
|
+
delete worker.whenLoaded;
|
|
795
|
+
PThread.cleanThread(worker, tid, true);
|
|
796
|
+
throw err;
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
if (isNewABI) {
|
|
800
|
+
return 0;
|
|
801
|
+
}
|
|
802
|
+
free(errorOrTid);
|
|
803
|
+
return tid;
|
|
804
|
+
};
|
|
805
|
+
this.threadSpawn = threadSpawn;
|
|
806
|
+
if (this.PThread) {
|
|
807
|
+
this.PThread.threadSpawn = threadSpawn;
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
getImportObject() {
|
|
811
|
+
return {
|
|
812
|
+
wasi: {
|
|
813
|
+
'thread-spawn': this.threadSpawn
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
setup(wasmInstance, wasmModule, wasmMemory) {
|
|
818
|
+
wasmMemory ??= wasmInstance.exports.memory;
|
|
819
|
+
this.wasmInstance = wasmInstance;
|
|
820
|
+
this.wasmMemory = wasmMemory;
|
|
821
|
+
if (this.PThread) {
|
|
822
|
+
this.PThread.setup(wasmModule, wasmMemory);
|
|
823
|
+
}
|
|
824
|
+
}
|
|
825
|
+
preloadWorkers() {
|
|
826
|
+
if (this.PThread) {
|
|
827
|
+
return this.PThread.preloadWorkers();
|
|
828
|
+
}
|
|
829
|
+
return Promise.resolve([]);
|
|
830
|
+
}
|
|
831
|
+
initialize(instance, module, memory) {
|
|
832
|
+
const exports = instance.exports;
|
|
833
|
+
memory ??= exports.memory;
|
|
834
|
+
if (this.childThread) {
|
|
835
|
+
instance = createInstanceProxy(instance, memory);
|
|
836
|
+
}
|
|
837
|
+
this.setup(instance, module, memory);
|
|
838
|
+
const wasi = this.wasi;
|
|
839
|
+
if (('_start' in exports) && (typeof exports._start === 'function')) {
|
|
840
|
+
if (this.childThread) {
|
|
841
|
+
wasi.start(instance);
|
|
842
|
+
try {
|
|
843
|
+
const kStarted = getWasiSymbol(wasi, 'kStarted');
|
|
844
|
+
wasi[kStarted] = false;
|
|
845
|
+
}
|
|
846
|
+
catch (_) { }
|
|
847
|
+
}
|
|
848
|
+
else {
|
|
849
|
+
setupInstance(wasi, instance);
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
else {
|
|
853
|
+
wasi.initialize(instance);
|
|
854
|
+
}
|
|
855
|
+
return instance;
|
|
856
|
+
}
|
|
857
|
+
start(instance, module, memory) {
|
|
858
|
+
const exports = instance.exports;
|
|
859
|
+
memory ??= exports.memory;
|
|
860
|
+
if (this.childThread) {
|
|
861
|
+
instance = createInstanceProxy(instance, memory);
|
|
862
|
+
}
|
|
863
|
+
this.setup(instance, module, memory);
|
|
864
|
+
const exitCode = this.wasi.start(instance);
|
|
865
|
+
return { exitCode, instance };
|
|
866
|
+
}
|
|
867
|
+
terminateAllThreads() {
|
|
868
|
+
if (!this.childThread) {
|
|
869
|
+
this.PThread?.terminateAllThreads();
|
|
870
|
+
}
|
|
871
|
+
else {
|
|
872
|
+
this.postMessage(createMessage('terminate-all-threads', {}));
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
function patchWasiInstance(wasiThreads, wasi) {
|
|
877
|
+
const patched = patchedWasiInstances.get(wasiThreads);
|
|
878
|
+
if (patched.has(wasi)) {
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
const _this = wasiThreads;
|
|
882
|
+
const wasiImport = wasi.wasiImport;
|
|
883
|
+
if (wasiImport) {
|
|
884
|
+
const proc_exit = wasiImport.proc_exit;
|
|
885
|
+
wasiImport.proc_exit = function (code) {
|
|
886
|
+
_this.terminateAllThreads();
|
|
887
|
+
return proc_exit.call(this, code);
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
if (!_this.childThread) {
|
|
891
|
+
const start = wasi.start;
|
|
892
|
+
if (typeof start === 'function') {
|
|
893
|
+
wasi.start = function (instance) {
|
|
894
|
+
try {
|
|
895
|
+
return start.call(this, instance);
|
|
896
|
+
}
|
|
897
|
+
catch (err) {
|
|
898
|
+
if (isTrapError(err)) {
|
|
899
|
+
_this.terminateAllThreads();
|
|
900
|
+
}
|
|
901
|
+
throw err;
|
|
902
|
+
}
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
patched.add(wasi);
|
|
907
|
+
}
|
|
908
|
+
function getWasiSymbol(wasi, description) {
|
|
909
|
+
const symbols = Object.getOwnPropertySymbols(wasi);
|
|
910
|
+
const selectDescription = (description) => (s) => {
|
|
911
|
+
if (s.description) {
|
|
912
|
+
return s.description === description;
|
|
913
|
+
}
|
|
914
|
+
return s.toString() === `Symbol(${description})`;
|
|
915
|
+
};
|
|
916
|
+
if (Array.isArray(description)) {
|
|
917
|
+
return description.map(d => symbols.filter(selectDescription(d))[0]);
|
|
918
|
+
}
|
|
919
|
+
return symbols.filter(selectDescription(description))[0];
|
|
920
|
+
}
|
|
921
|
+
function setupInstance(wasi, instance) {
|
|
922
|
+
const [kInstance, kSetMemory] = getWasiSymbol(wasi, ['kInstance', 'kSetMemory']);
|
|
923
|
+
wasi[kInstance] = instance;
|
|
924
|
+
wasi[kSetMemory](instance.exports.memory);
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
//#endregion src/wasi-threads.ts
|
|
928
|
+
|
|
929
|
+
//#region src/worker.ts
|
|
930
|
+
class ThreadMessageHandler {
|
|
931
|
+
constructor(options) {
|
|
932
|
+
const postMsg = getPostMessage(options);
|
|
933
|
+
if (typeof postMsg !== 'function') {
|
|
934
|
+
throw new TypeError('options.postMessage is not a function');
|
|
935
|
+
}
|
|
936
|
+
this.postMessage = postMsg;
|
|
937
|
+
this.onLoad = options?.onLoad;
|
|
938
|
+
this.onError = typeof options?.onError === 'function' ? options.onError : (error) => { throw error; };
|
|
939
|
+
this.instance = undefined;
|
|
940
|
+
this.messagesBeforeLoad = [];
|
|
941
|
+
}
|
|
942
|
+
instantiate(data) {
|
|
943
|
+
if (typeof this.onLoad === 'function') {
|
|
944
|
+
return this.onLoad(data);
|
|
945
|
+
}
|
|
946
|
+
throw new Error('ThreadMessageHandler.prototype.instantiate is not implemented');
|
|
947
|
+
}
|
|
948
|
+
handle(e) {
|
|
949
|
+
if (e?.data?.__emnapi__) {
|
|
950
|
+
const type = e.data.__emnapi__.type;
|
|
951
|
+
const payload = e.data.__emnapi__.payload;
|
|
952
|
+
try {
|
|
953
|
+
if (type === 'load') {
|
|
954
|
+
this._load(payload);
|
|
955
|
+
}
|
|
956
|
+
else if (type === 'start') {
|
|
957
|
+
this.handleAfterLoad(e, () => {
|
|
958
|
+
this._start(payload);
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
catch (err) {
|
|
963
|
+
const tid = type === 'start' ? payload.tid : undefined;
|
|
964
|
+
this.reportError(err, type, tid);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
_load(payload) {
|
|
969
|
+
if (this.instance !== undefined)
|
|
970
|
+
return;
|
|
971
|
+
let source;
|
|
972
|
+
try {
|
|
973
|
+
source = this.instantiate(payload);
|
|
974
|
+
}
|
|
975
|
+
catch (err) {
|
|
976
|
+
this._loaded(err, null, payload);
|
|
977
|
+
return;
|
|
978
|
+
}
|
|
979
|
+
const then = source && 'then' in source ? source.then : undefined;
|
|
980
|
+
if (typeof then === 'function') {
|
|
981
|
+
then.call(source, (source) => { this._loaded(null, source, payload); }, (err) => {
|
|
982
|
+
try {
|
|
983
|
+
this._loaded(normalizeError(err), null, payload);
|
|
984
|
+
}
|
|
985
|
+
catch (loadError) {
|
|
986
|
+
this.reportError(loadError, 'load');
|
|
987
|
+
}
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
else {
|
|
991
|
+
this._loaded(null, source, payload);
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
_start(payload) {
|
|
995
|
+
const wasi_thread_start = this.instance.exports.wasi_thread_start;
|
|
996
|
+
if (typeof wasi_thread_start !== 'function') {
|
|
997
|
+
const err = new TypeError('wasi_thread_start is not exported');
|
|
998
|
+
notifyPthreadCreateResult(payload.sab, 2, err);
|
|
999
|
+
throw err;
|
|
1000
|
+
}
|
|
1001
|
+
const postMessage = this.postMessage;
|
|
1002
|
+
const tid = payload.tid;
|
|
1003
|
+
const startArg = payload.arg;
|
|
1004
|
+
notifyPthreadCreateResult(payload.sab, 1);
|
|
1005
|
+
try {
|
|
1006
|
+
wasi_thread_start(tid, startArg);
|
|
1007
|
+
}
|
|
1008
|
+
catch (err) {
|
|
1009
|
+
if (err !== 'unwind') {
|
|
1010
|
+
throw err;
|
|
1011
|
+
}
|
|
1012
|
+
else {
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
postMessage(createMessage('cleanup-thread', { tid }));
|
|
1017
|
+
}
|
|
1018
|
+
_loaded(err, source, payload) {
|
|
1019
|
+
if (err) {
|
|
1020
|
+
notifyPthreadCreateResult(payload.sab, 2, err);
|
|
1021
|
+
throw err;
|
|
1022
|
+
}
|
|
1023
|
+
if (source == null) {
|
|
1024
|
+
const err = new TypeError('onLoad should return an object');
|
|
1025
|
+
notifyPthreadCreateResult(payload.sab, 2, err);
|
|
1026
|
+
throw err;
|
|
1027
|
+
}
|
|
1028
|
+
const instance = source.instance;
|
|
1029
|
+
if (!instance) {
|
|
1030
|
+
const err = new TypeError('onLoad should return an object which includes "instance"');
|
|
1031
|
+
notifyPthreadCreateResult(payload.sab, 2, err);
|
|
1032
|
+
throw err;
|
|
1033
|
+
}
|
|
1034
|
+
this.instance = instance;
|
|
1035
|
+
const postMessage = this.postMessage;
|
|
1036
|
+
postMessage(createMessage('loaded', {}));
|
|
1037
|
+
const messages = this.messagesBeforeLoad;
|
|
1038
|
+
this.messagesBeforeLoad = [];
|
|
1039
|
+
for (let i = 0; i < messages.length; i++) {
|
|
1040
|
+
const data = messages[i];
|
|
1041
|
+
this.handle({ data });
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
handleAfterLoad(e, f) {
|
|
1045
|
+
if (this.instance !== undefined) {
|
|
1046
|
+
f.call(this, e);
|
|
1047
|
+
}
|
|
1048
|
+
else {
|
|
1049
|
+
this.messagesBeforeLoad.push(e.data);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
beforeReportError(_error, _type, _tid) { }
|
|
1053
|
+
reportError(value, type, tid) {
|
|
1054
|
+
const error = normalizeError(value);
|
|
1055
|
+
this.beforeReportError(error, type, tid);
|
|
1056
|
+
const phase = type === 'async-worker-init' ? 'async-work' : type;
|
|
1057
|
+
const report = () => {
|
|
1058
|
+
try {
|
|
1059
|
+
this.postMessage(createMessage('thread-error', {
|
|
1060
|
+
error: serializeError(error),
|
|
1061
|
+
phase,
|
|
1062
|
+
tid
|
|
1063
|
+
}));
|
|
1064
|
+
}
|
|
1065
|
+
catch (_) { }
|
|
1066
|
+
};
|
|
1067
|
+
if (ENVIRONMENT_IS_NODE) {
|
|
1068
|
+
this.onError(error, type);
|
|
1069
|
+
report();
|
|
1070
|
+
}
|
|
1071
|
+
else {
|
|
1072
|
+
report();
|
|
1073
|
+
this.onError(error, type);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
function notifyPthreadCreateResult(sab, result, error) {
|
|
1078
|
+
if (sab) {
|
|
1079
|
+
serializeErrorToBuffer(sab.buffer, result, error);
|
|
1080
|
+
Atomics.notify(sab, 0);
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
//#endregion src/worker.ts
|
|
1085
|
+
|
|
1086
|
+
export { ThreadManager, ThreadMessageHandler, WASIThreads, createInstanceProxy, isSharedArrayBuffer, isTrapError };
|