Skip to content

Commit 2bca3a0

Browse files
update js/wasm_exec.js - the Go WASM JS glue
1 parent e8e278e commit 2bca3a0

File tree

1 file changed

+35
-103
lines changed

1 file changed

+35
-103
lines changed

doc/js/wasm_exec.js

+35-103
Original file line numberDiff line numberDiff line change
@@ -2,54 +2,25 @@
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

5-
(() => {
6-
// Map multiple JavaScript environments to a single common API,
7-
// preferring web standards over Node.js API.
8-
//
9-
// Environments considered:
10-
// - Browsers
11-
// - Node.js
12-
// - Electron
13-
// - Parcel
14-
// - Webpack
15-
16-
if (typeof global !== "undefined") {
17-
// global already exists
18-
} else if (typeof window !== "undefined") {
19-
window.global = window;
20-
} else if (typeof self !== "undefined") {
21-
self.global = self;
22-
} else {
23-
throw new Error("cannot export Go (neither global, window nor self is defined)");
24-
}
25-
26-
if (!global.require && typeof require !== "undefined") {
27-
global.require = require;
28-
}
29-
30-
if (!global.fs && global.require) {
31-
const fs = require("fs");
32-
if (typeof fs === "object" && fs !== null && Object.keys(fs).length !== 0) {
33-
global.fs = fs;
34-
}
35-
}
5+
"use strict";
366

7+
(() => {
378
const enosys = () => {
389
const err = new Error("not implemented");
3910
err.code = "ENOSYS";
4011
return err;
4112
};
4213

43-
if (!global.fs) {
14+
if (!globalThis.fs) {
4415
let outputBuf = "";
45-
global.fs = {
16+
globalThis.fs = {
4617
constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused
4718
writeSync(fd, buf) {
4819
outputBuf += decoder.decode(buf);
4920
const nl = outputBuf.lastIndexOf("\n");
5021
if (nl != -1) {
51-
console.log(outputBuf.substr(0, nl));
52-
outputBuf = outputBuf.substr(nl + 1);
22+
console.log(outputBuf.substring(0, nl));
23+
outputBuf = outputBuf.substring(nl + 1);
5324
}
5425
return buf.length;
5526
},
@@ -87,8 +58,8 @@
8758
};
8859
}
8960

90-
if (!global.process) {
91-
global.process = {
61+
if (!globalThis.process) {
62+
globalThis.process = {
9263
getuid() { return -1; },
9364
getgid() { return -1; },
9465
geteuid() { return -1; },
@@ -102,47 +73,26 @@
10273
}
10374
}
10475

105-
if (!global.crypto && global.require) {
106-
const nodeCrypto = require("crypto");
107-
global.crypto = {
108-
getRandomValues(b) {
109-
nodeCrypto.randomFillSync(b);
110-
},
111-
};
112-
}
113-
if (!global.crypto) {
114-
throw new Error("global.crypto is not available, polyfill required (getRandomValues only)");
76+
if (!globalThis.crypto) {
77+
throw new Error("globalThis.crypto is not available, polyfill required (crypto.getRandomValues only)");
11578
}
11679

117-
if (!global.performance) {
118-
global.performance = {
119-
now() {
120-
const [sec, nsec] = process.hrtime();
121-
return sec * 1000 + nsec / 1000000;
122-
},
123-
};
80+
if (!globalThis.performance) {
81+
throw new Error("globalThis.performance is not available, polyfill required (performance.now only)");
12482
}
12583

126-
if (!global.TextEncoder && global.require) {
127-
global.TextEncoder = require("util").TextEncoder;
128-
}
129-
if (!global.TextEncoder) {
130-
throw new Error("global.TextEncoder is not available, polyfill required");
84+
if (!globalThis.TextEncoder) {
85+
throw new Error("globalThis.TextEncoder is not available, polyfill required");
13186
}
13287

133-
if (!global.TextDecoder && global.require) {
134-
global.TextDecoder = require("util").TextDecoder;
88+
if (!globalThis.TextDecoder) {
89+
throw new Error("globalThis.TextDecoder is not available, polyfill required");
13590
}
136-
if (!global.TextDecoder) {
137-
throw new Error("global.TextDecoder is not available, polyfill required");
138-
}
139-
140-
// End of polyfills for common API.
14191

14292
const encoder = new TextEncoder("utf-8");
14393
const decoder = new TextDecoder("utf-8");
14494

145-
global.Go = class {
95+
globalThis.Go = class {
14696
constructor() {
14797
this.argv = ["js"];
14898
this.env = {};
@@ -163,6 +113,10 @@
163113
this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true);
164114
}
165115

116+
const setInt32 = (addr, v) => {
117+
this.mem.setUint32(addr + 0, v, true);
118+
}
119+
166120
const getInt64 = (addr) => {
167121
const low = this.mem.getUint32(addr + 0, true);
168122
const high = this.mem.getInt32(addr + 4, true);
@@ -256,7 +210,10 @@
256210

257211
const timeOrigin = Date.now() - performance.now();
258212
this.importObject = {
259-
go: {
213+
_gotest: {
214+
add: (a, b) => a + b,
215+
},
216+
gojs: {
260217
// Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
261218
// may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported
262219
// function. A goroutine can switch to a new stack if the current stack is too small (see morestack function).
@@ -319,7 +276,7 @@
319276
this._resume();
320277
}
321278
},
322-
getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early
279+
getInt64(sp + 8),
323280
));
324281
this.mem.setInt32(sp + 16, id, true);
325282
},
@@ -517,7 +474,7 @@
517474
null,
518475
true,
519476
false,
520-
global,
477+
globalThis,
521478
this,
522479
];
523480
this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id
@@ -526,7 +483,7 @@
526483
[null, 2],
527484
[true, 3],
528485
[false, 4],
529-
[global, 5],
486+
[globalThis, 5],
530487
[this, 6],
531488
]);
532489
this._idPool = []; // unused ids that have been garbage collected
@@ -567,6 +524,13 @@
567524
offset += 8;
568525
});
569526

527+
// The linker guarantees global data starts from at least wasmMinDataAddr.
528+
// Keep in sync with cmd/link/internal/ld/data.go:wasmMinDataAddr.
529+
const wasmMinDataAddr = 4096 + 8192;
530+
if (offset >= wasmMinDataAddr) {
531+
throw new Error("total length of command line and environment variables exceeds limit");
532+
}
533+
570534
this._inst.exports.run(argc, argv);
571535
if (this.exited) {
572536
this._resolveExitPromise();
@@ -594,36 +558,4 @@
594558
};
595559
}
596560
}
597-
598-
if (
599-
typeof module !== "undefined" &&
600-
global.require &&
601-
global.require.main === module &&
602-
global.process &&
603-
global.process.versions &&
604-
!global.process.versions.electron
605-
) {
606-
if (process.argv.length < 3) {
607-
console.error("usage: go_js_wasm_exec [wasm binary] [arguments]");
608-
process.exit(1);
609-
}
610-
611-
const go = new Go();
612-
go.argv = process.argv.slice(2);
613-
go.env = Object.assign({ TMPDIR: require("os").tmpdir() }, process.env);
614-
go.exit = process.exit;
615-
WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => {
616-
process.on("exit", (code) => { // Node.js exits if no event handler is pending
617-
if (code === 0 && !go.exited) {
618-
// deadlock, make Go print error and stack traces
619-
go._pendingEvent = { id: 0 };
620-
go._resume();
621-
}
622-
});
623-
return go.run(result.instance);
624-
}).catch((err) => {
625-
console.error(err);
626-
process.exit(1);
627-
});
628-
}
629561
})();

0 commit comments

Comments
 (0)