1 // This is a small "shim" program which is used when wasm32 unit tests are run
2 // in this repository. This program is intended to be run in node.js and will
3 // load a wasm module into memory, instantiate it with a set of imports, and
6 // There's a bunch of helper functions defined here in `imports.env`, but note
7 // that most of them aren't actually needed to execute most programs. Many of
8 // these are just intended for completeness or debugging. Hopefully over time
9 // nothing here is needed for completeness.
11 const fs = require('fs');
12 const process = require('process');
13 const buffer = fs.readFileSync(process.argv[2]);
15 Error.stackTraceLimit = 20;
17 let m = new WebAssembly.Module(buffer);
21 function viewstruct(data, fields) {
22 return new Uint32Array(memory.buffer).subarray(data/4, data/4 + fields);
25 function copystr(a, b) {
26 let view = new Uint8Array(memory.buffer).subarray(a, a + b);
27 return String.fromCharCode.apply(null, view);
30 function syscall_write([fd, ptr, len]) {
31 let s = copystr(ptr, len);
33 case 1: process.stdout.write(s); break;
34 case 2: process.stderr.write(s); break;
38 function syscall_exit([code]) {
42 function syscall_args(params) {
43 let [ptr, len] = params;
45 // Calculate total required buffer size
47 for (let i = 2; i < process.argv.length; ++i) {
48 totalLen += Buffer.byteLength(process.argv[i]) + 1;
50 if (totalLen < 0) { totalLen = 0; }
53 // If buffer is large enough, copy data
54 if (len >= totalLen) {
55 let view = new Uint8Array(memory.buffer);
56 for (let i = 2; i < process.argv.length; ++i) {
57 let value = process.argv[i];
58 Buffer.from(value).copy(view, ptr);
59 ptr += Buffer.byteLength(process.argv[i]) + 1;
64 function syscall_getenv(params) {
65 let [keyPtr, keyLen, valuePtr, valueLen] = params;
67 let key = copystr(keyPtr, keyLen);
68 let value = process.env[key];
71 params[4] = 0xFFFFFFFF;
73 let view = new Uint8Array(memory.buffer);
74 let totalLen = Buffer.byteLength(value);
76 if (valueLen >= totalLen) {
77 Buffer.from(value).copy(view, valuePtr);
82 function syscall_time(params) {
84 let secs = Math.floor(t / 1000);
85 let millis = t % 1000;
86 params[1] = Math.floor(secs / 0x100000000);
87 params[2] = secs % 0x100000000;
88 params[3] = Math.floor(millis * 1000000);
93 // These are generated by LLVM itself for various intrinsic calls. Hopefully
94 // one day this is not necessary and something will automatically do this.
95 fmod: function(x, y) { return x % y; },
96 exp2: function(x) { return Math.pow(2, x); },
97 exp2f: function(x) { return Math.pow(2, x); },
98 ldexp: function(x, y) { return x * Math.pow(2, y); },
99 ldexpf: function(x, y) { return x * Math.pow(2, y); },
109 rust_wasm_syscall: function(index, data) {
111 case 1: syscall_write(viewstruct(data, 3)); return true;
112 case 2: syscall_exit(viewstruct(data, 1)); return true;
113 case 3: syscall_args(viewstruct(data, 3)); return true;
114 case 4: syscall_getenv(viewstruct(data, 5)); return true;
115 case 6: syscall_time(viewstruct(data, 4)); return true;
117 console.log("Unsupported syscall: " + index);
123 let instance = new WebAssembly.Instance(m, imports);
124 memory = instance.exports.memory;
126 instance.exports.main();