-
Notifications
You must be signed in to change notification settings - Fork 117
/
Copy pathwasm_withWorker.js
102 lines (98 loc) · 3.74 KB
/
wasm_withWorker.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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
102
// make the "require" function available to all
Tarp.require({expose: true});
// Have a global variable:
if (typeof window !== 'undefined') {
window.global = window;
}
// and Buffer and process variables
var Buffer = require('buffer').Buffer;
var process = require('process');
// (we don't use "require" anymore, but JavaScript files calling JSC might need it)
// This file handles communication between the system and
// the WebWorker in charge of executing WebAssembly.
// Everything related to WebAssembly is in wasm_worker_wasm.js
const sab = new SharedArrayBuffer(8196);
const sharedArray = new Int32Array(sab)
const wasmWorker = new Worker("wasm_worker_wasm.js");
var inputString = ''; // stores keyboard input
var commandIsRunning = false;
function wakeUpWorker(chunkSize) {
const d = new Date();
let resultStorage = -1;
let resultNotify = -1;
let tries = 0;
resultStorage = Atomics.store(sharedArray, 0, chunkSize + 1);
resultNotify = Atomics.notify(sharedArray, 0);
while ((resultStorage != chunkSize +1) && (resultNotify != 0) && (tries < 10)) {
resultStorage = Atomics.store(sharedArray, 0, chunkSize + 1);
resultNotify = Atomics.notify(sharedArray, 0);
tries += 1;
}
}
function executeWebAssembly(bufferString, args, cwd, tty, env) {
inputString = '';
commandIsRunning = true;
// create a webWorker to run webAssembly code:
wasmWorker.postMessage([bufferString, args, cwd, tty, env, sab]);
let result = "";
// Dealing with communications with the system:
wasmWorker.onmessage =(e) => {
// system calls go through the "prompt()" command
// Easiest way to make it synchronous
if (e.data[0] == "prompt") {
sharedArray[0] = 0;
Atomics.store(sharedArray, 0, 0);
result = prompt(e.data[1]);
// Sending the data to the worker by slices of 2047 bytes:
// (need to keep one for length of each chunk)
// The CPU side has already truncated data at ^D.
let chunkSize = result.length;
if (chunkSize > 8192) chunkSize = 8192;
let chunk = result.substring(0, chunkSize);
for (var i = 0, j = 1; i < chunkSize; i+=4, j++) {
sharedArray[j] = chunk.charCodeAt(i)
| (chunk.charCodeAt(i+1) << 8)
| (chunk.charCodeAt(i+2) << 16)
| (chunk.charCodeAt(i+3) << 24);
}
result = result.substring(chunkSize);
wakeUpWorker(chunkSize);
} else if (e.data[0] == "keyboard") { // keyboard input
let length = Number(e.data[1]);
result = inputString.substring(0, length); // send what was asked
let chunkSize = result.length;
if (chunkSize > 2047) chunkSize = 2047;
let chunk = result.substring(0, chunkSize);
for (var i = 0; i < chunkSize; i++) {
sharedArray[i+1] = chunk.charCodeAt(i);
// cut after ^D if present, only send up to ^D
if (chunk.charCodeAt(i) == 4)
break;
}
chunkSize = chunk.length;
result = result.substring(chunkSize);
inputString = inputString.substring(chunkSize); // remove what's already been sent
Atomics.store(sharedArray, 0, chunkSize + 1);
Atomics.notify(sharedArray, 0);
} else if (e.data[0] == "sendNextChunk") {
sharedArray[0] = 0;
Atomics.store(sharedArray, 0, 0);
let chunkSize = result.length;
if (chunkSize > 8192) chunkSize = 8192;
let chunk = result.substring(0, chunkSize);
for (var i = 0, j=1; i < chunkSize; i+=4, j++) {
sharedArray[j] = chunk.charCodeAt(i)
| (chunk.charCodeAt(i+1) << 8)
| (chunk.charCodeAt(i+2) << 16)
| (chunk.charCodeAt(i+3) << 24);
}
result = result.substring(chunkSize);
wakeUpWorker(chunkSize);
} else if (e.data[0] == "commandTerminated") {
// We need the "command is finished" signal to be in sync with the printing,
// so it uses the same signal transmission system:
commandIsRunning = false;
prompt("libc\ncommandTerminated\n" + e.data[1] + "\n" + e.data[2]);
}
}
}