]> git.lizzy.rs Git - rust.git/blob - src/etc/wasm32-shim.js
Rollup merge of #53001 - petrochenkov:master, r=estebank
[rust.git] / src / etc / wasm32-shim.js
1 // Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 // This is a small "shim" program which is used when wasm32 unit tests are run
12 // in this repository. This program is intended to be run in node.js and will
13 // load a wasm module into memory, instantiate it with a set of imports, and
14 // then run it.
15 //
16 // There's a bunch of helper functions defined here in `imports.env`, but note
17 // that most of them aren't actually needed to execute most programs. Many of
18 // these are just intended for completeness or debugging. Hopefully over time
19 // nothing here is needed for completeness.
20
21 const fs = require('fs');
22 const process = require('process');
23 const buffer = fs.readFileSync(process.argv[2]);
24
25 Error.stackTraceLimit = 20;
26
27 let m = new WebAssembly.Module(buffer);
28
29 let memory = null;
30
31 function viewstruct(data, fields) {
32   return new Uint32Array(memory.buffer).subarray(data/4, data/4 + fields);
33 }
34
35 function copystr(a, b) {
36   let view = new Uint8Array(memory.buffer).subarray(a, a + b);
37   return String.fromCharCode.apply(null, view);
38 }
39
40 function syscall_write([fd, ptr, len]) {
41   let s = copystr(ptr, len);
42   switch (fd) {
43     case 1: process.stdout.write(s); break;
44     case 2: process.stderr.write(s); break;
45   }
46 }
47
48 function syscall_exit([code]) {
49   process.exit(code);
50 }
51
52 function syscall_args(params) {
53   let [ptr, len] = params;
54
55   // Calculate total required buffer size
56   let totalLen = -1;
57   for (let i = 2; i < process.argv.length; ++i) {
58     totalLen += Buffer.byteLength(process.argv[i]) + 1;
59   }
60   if (totalLen < 0) { totalLen = 0; }
61   params[2] = totalLen;
62
63   // If buffer is large enough, copy data
64   if (len >= totalLen) {
65     let view = new Uint8Array(memory.buffer);
66     for (let i = 2; i < process.argv.length; ++i) {
67       let value = process.argv[i];
68       Buffer.from(value).copy(view, ptr);
69       ptr += Buffer.byteLength(process.argv[i]) + 1;
70     }
71   }
72 }
73
74 function syscall_getenv(params) {
75   let [keyPtr, keyLen, valuePtr, valueLen] = params;
76
77   let key = copystr(keyPtr, keyLen);
78   let value = process.env[key];
79
80   if (value == null) {
81     params[4] = 0xFFFFFFFF;
82   } else {
83     let view = new Uint8Array(memory.buffer);
84     let totalLen = Buffer.byteLength(value);
85     params[4] = totalLen;
86     if (valueLen >= totalLen) {
87       Buffer.from(value).copy(view, valuePtr);
88     }
89   }
90 }
91
92 function syscall_time(params) {
93   let t = Date.now();
94   let secs = Math.floor(t / 1000);
95   let millis = t % 1000;
96   params[1] = Math.floor(secs / 0x100000000);
97   params[2] = secs % 0x100000000;
98   params[3] = Math.floor(millis * 1000000);
99 }
100
101 let imports = {};
102 imports.env = {
103   // These are generated by LLVM itself for various intrinsic calls. Hopefully
104   // one day this is not necessary and something will automatically do this.
105   fmod: function(x, y) { return x % y; },
106   exp2: function(x) { return Math.pow(2, x); },
107   exp2f: function(x) { return Math.pow(2, x); },
108   ldexp: function(x, y) { return x * Math.pow(2, y); },
109   ldexpf: function(x, y) { return x * Math.pow(2, y); },
110   sin: Math.sin,
111   sinf: Math.sin,
112   cos: Math.cos,
113   cosf: Math.cos,
114   log: Math.log,
115   log2: Math.log2,
116   log10: Math.log10,
117   log10f: Math.log10,
118
119   rust_wasm_syscall: function(index, data) {
120     switch (index) {
121       case 1: syscall_write(viewstruct(data, 3)); return true;
122       case 2: syscall_exit(viewstruct(data, 1)); return true;
123       case 3: syscall_args(viewstruct(data, 3)); return true;
124       case 4: syscall_getenv(viewstruct(data, 5)); return true;
125       case 6: syscall_time(viewstruct(data, 4)); return true;
126       default:
127         console.log("Unsupported syscall: " + index);
128         return false;
129     }
130   }
131 };
132
133 let instance = new WebAssembly.Instance(m, imports);
134 memory = instance.exports.memory;
135 try {
136   instance.exports.main();
137 } catch (e) {
138   console.error(e);
139   process.exit(101);
140 }