]> git.lizzy.rs Git - rust.git/blob - src/etc/wasm32-shim.js
Rollup merge of #59880 - solson:transmute-float, r=alexcrichton
[rust.git] / src / etc / wasm32-shim.js
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
4 // then run it.
5 //
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.
10
11 const fs = require('fs');
12 const process = require('process');
13 const buffer = fs.readFileSync(process.argv[2]);
14
15 Error.stackTraceLimit = 20;
16
17 let m = new WebAssembly.Module(buffer);
18
19 let memory = null;
20
21 function viewstruct(data, fields) {
22   return new Uint32Array(memory.buffer).subarray(data/4, data/4 + fields);
23 }
24
25 function copystr(a, b) {
26   let view = new Uint8Array(memory.buffer).subarray(a, a + b);
27   return String.fromCharCode.apply(null, view);
28 }
29
30 function syscall_write([fd, ptr, len]) {
31   let s = copystr(ptr, len);
32   switch (fd) {
33     case 1: process.stdout.write(s); break;
34     case 2: process.stderr.write(s); break;
35   }
36 }
37
38 function syscall_exit([code]) {
39   process.exit(code);
40 }
41
42 function syscall_args(params) {
43   let [ptr, len] = params;
44
45   // Calculate total required buffer size
46   let totalLen = -1;
47   for (let i = 2; i < process.argv.length; ++i) {
48     totalLen += Buffer.byteLength(process.argv[i]) + 1;
49   }
50   if (totalLen < 0) { totalLen = 0; }
51   params[2] = totalLen;
52
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;
60     }
61   }
62 }
63
64 function syscall_getenv(params) {
65   let [keyPtr, keyLen, valuePtr, valueLen] = params;
66
67   let key = copystr(keyPtr, keyLen);
68   let value = process.env[key];
69
70   if (value == null) {
71     params[4] = 0xFFFFFFFF;
72   } else {
73     let view = new Uint8Array(memory.buffer);
74     let totalLen = Buffer.byteLength(value);
75     params[4] = totalLen;
76     if (valueLen >= totalLen) {
77       Buffer.from(value).copy(view, valuePtr);
78     }
79   }
80 }
81
82 function syscall_time(params) {
83   let t = Date.now();
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);
89 }
90
91 let imports = {};
92 imports.env = {
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); },
100   sin: Math.sin,
101   sinf: Math.sin,
102   cos: Math.cos,
103   cosf: Math.cos,
104   log: Math.log,
105   log2: Math.log2,
106   log10: Math.log10,
107   log10f: Math.log10,
108
109   rust_wasm_syscall: function(index, data) {
110     switch (index) {
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;
116       default:
117         console.log("Unsupported syscall: " + index);
118         return false;
119     }
120   }
121 };
122
123 let instance = new WebAssembly.Instance(m, imports);
124 memory = instance.exports.memory;
125 try {
126   instance.exports.main();
127 } catch (e) {
128   console.error(e);
129   process.exit(101);
130 }