forked from sellicott/tcc-riscv32
-
Notifications
You must be signed in to change notification settings - Fork 5
/
test.js
99 lines (85 loc) · 2.98 KB
/
test.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
const fs = require('fs');
const source = fs.readFileSync("./tcc-wasm.wasm");
const typedArray = new Uint8Array(source);
// Log WebAssembly Messages from Zig to JavaScript Console
// https://github.com/daneelsan/zig-wasm-logger/blob/master/script.js
const text_decoder = new TextDecoder();
let console_log_buffer = "";
// WebAssembly Helper Functions
const wasm = {
// WebAssembly Instance
instance: undefined,
// Init the WebAssembly Instance
init: function (obj) {
this.instance = obj.instance;
},
// Fetch the Zig String from a WebAssembly Pointer
getString: function (ptr, len) {
const memory = this.instance.exports.memory;
return text_decoder.decode(
new Uint8Array(memory.buffer, ptr, len)
);
},
};
// Load the WebAssembly
WebAssembly.instantiate(typedArray, {
env: {
// Write to JavaScript Console from Zig
// https://github.com/daneelsan/zig-wasm-logger/blob/master/script.js
jsConsoleLogWrite: function(ptr, len) {
console_log_buffer += wasm.getString(ptr, len);
},
// Flush JavaScript Console from Zig
// https://github.com/daneelsan/zig-wasm-logger/blob/master/script.js
jsConsoleLogFlush: function() {
console.log(console_log_buffer);
console_log_buffer = "";
},
}
}).then(result => {
// Store references to WebAssembly Functions and Memory exported by Zig
wasm.init(result);
// Allocate a String for passing the Compiler Options to Zig
const options = ["-c", "hello.c"];
const options_ptr = allocateString(JSON.stringify(options));
// Allocate a String for passing Program Code to Zig
const code_ptr = allocateString(`
int main(int argc, char *argv[]) {
printf("Hello, World!!\\n");
return 0;
}
`);
// Call TCC to compile a program
const ptr = wasm.instance.exports
.compile_program(options_ptr, code_ptr);
console.log(`ptr=${ptr}`);
// Get the `a.out` size from first 4 bytes returned
const memory = wasm.instance.exports.memory;
const data_len = new Uint8Array(memory.buffer, ptr, 4);
const len = data_len[0] | data_len[1] << 8 | data_len[2] << 16 | data_len[3] << 24;
console.log(`main: len=${len}`);
if (len <= 0) { return; }
// Save the `a.out` data from the rest of the bytes returned
const data = new Uint8Array(memory.buffer, ptr + 4, len);
fs.writeFileSync("/tmp/a.out", Buffer.from(data));
console.log("TCC Output saved to /tmp/a.out");
});
// Allocate a String for passing to Zig
// https://blog.battlefy.com/zig-made-it-easy-to-pass-strings-back-and-forth-with-webassembly
const allocateString = (string) => {
// WebAssembly Memory exported by Zig
const memory = wasm.instance.exports.memory;
const buffer = new TextEncoder().encode(string);
// Ask Zig to allocate memory
const pointer = wasm.instance.exports
.allocUint8(buffer.length + 1);
const slice = new Uint8Array(
memory.buffer,
pointer,
buffer.length + 1
);
slice.set(buffer);
// Terminate the string with null
slice[buffer.length] = 0;
return pointer;
};