| 
2 | 2 | // Use of this source code is governed by a BSD-style  | 
3 | 3 | // license that can be found in the LICENSE file.  | 
4 | 4 | 
 
  | 
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";  | 
36 | 6 | 
 
  | 
 | 7 | +(() => {  | 
37 | 8 | 	const enosys = () => {  | 
38 | 9 | 		const err = new Error("not implemented");  | 
39 | 10 | 		err.code = "ENOSYS";  | 
40 | 11 | 		return err;  | 
41 | 12 | 	};  | 
42 | 13 | 
 
  | 
43 |  | -	if (!global.fs) {  | 
 | 14 | +	if (!globalThis.fs) {  | 
44 | 15 | 		let outputBuf = "";  | 
45 |  | -		global.fs = {  | 
 | 16 | +		globalThis.fs = {  | 
46 | 17 | 			constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused  | 
47 | 18 | 			writeSync(fd, buf) {  | 
48 | 19 | 				outputBuf += decoder.decode(buf);  | 
49 | 20 | 				const nl = outputBuf.lastIndexOf("\n");  | 
50 | 21 | 				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);  | 
53 | 24 | 				}  | 
54 | 25 | 				return buf.length;  | 
55 | 26 | 			},  | 
 | 
87 | 58 | 		};  | 
88 | 59 | 	}  | 
89 | 60 | 
 
  | 
90 |  | -	if (!global.process) {  | 
91 |  | -		global.process = {  | 
 | 61 | +	if (!globalThis.process) {  | 
 | 62 | +		globalThis.process = {  | 
92 | 63 | 			getuid() { return -1; },  | 
93 | 64 | 			getgid() { return -1; },  | 
94 | 65 | 			geteuid() { return -1; },  | 
 | 
102 | 73 | 		}  | 
103 | 74 | 	}  | 
104 | 75 | 
 
  | 
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)");  | 
115 | 78 | 	}  | 
116 | 79 | 
 
  | 
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)");  | 
124 | 82 | 	}  | 
125 | 83 | 
 
  | 
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");  | 
131 | 86 | 	}  | 
132 | 87 | 
 
  | 
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");  | 
135 | 90 | 	}  | 
136 |  | -	if (!global.TextDecoder) {  | 
137 |  | -		throw new Error("global.TextDecoder is not available, polyfill required");  | 
138 |  | -	}  | 
139 |  | - | 
140 |  | -	// End of polyfills for common API.  | 
141 | 91 | 
 
  | 
142 | 92 | 	const encoder = new TextEncoder("utf-8");  | 
143 | 93 | 	const decoder = new TextDecoder("utf-8");  | 
144 | 94 | 
 
  | 
145 |  | -	global.Go = class {  | 
 | 95 | +	globalThis.Go = class {  | 
146 | 96 | 		constructor() {  | 
147 | 97 | 			this.argv = ["js"];  | 
148 | 98 | 			this.env = {};  | 
 | 
163 | 113 | 				this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true);  | 
164 | 114 | 			}  | 
165 | 115 | 
 
  | 
 | 116 | +			const setInt32 = (addr, v) => {  | 
 | 117 | +				this.mem.setUint32(addr + 0, v, true);  | 
 | 118 | +			}  | 
 | 119 | + | 
166 | 120 | 			const getInt64 = (addr) => {  | 
167 | 121 | 				const low = this.mem.getUint32(addr + 0, true);  | 
168 | 122 | 				const high = this.mem.getInt32(addr + 4, true);  | 
 | 
256 | 210 | 
 
  | 
257 | 211 | 			const timeOrigin = Date.now() - performance.now();  | 
258 | 212 | 			this.importObject = {  | 
259 |  | -				go: {  | 
 | 213 | +				_gotest: {  | 
 | 214 | +					add: (a, b) => a + b,  | 
 | 215 | +				},  | 
 | 216 | +				gojs: {  | 
260 | 217 | 					// Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)  | 
261 | 218 | 					// may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported  | 
262 | 219 | 					// function. A goroutine can switch to a new stack if the current stack is too small (see morestack function).  | 
 | 
319 | 276 | 									this._resume();  | 
320 | 277 | 								}  | 
321 | 278 | 							},  | 
322 |  | -							getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early  | 
 | 279 | +							getInt64(sp + 8),  | 
323 | 280 | 						));  | 
324 | 281 | 						this.mem.setInt32(sp + 16, id, true);  | 
325 | 282 | 					},  | 
 | 
517 | 474 | 				null,  | 
518 | 475 | 				true,  | 
519 | 476 | 				false,  | 
520 |  | -				global,  | 
 | 477 | +				globalThis,  | 
521 | 478 | 				this,  | 
522 | 479 | 			];  | 
523 | 480 | 			this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id  | 
 | 
526 | 483 | 				[null, 2],  | 
527 | 484 | 				[true, 3],  | 
528 | 485 | 				[false, 4],  | 
529 |  | -				[global, 5],  | 
 | 486 | +				[globalThis, 5],  | 
530 | 487 | 				[this, 6],  | 
531 | 488 | 			]);  | 
532 | 489 | 			this._idPool = [];   // unused ids that have been garbage collected  | 
 | 
567 | 524 | 				offset += 8;  | 
568 | 525 | 			});  | 
569 | 526 | 
 
  | 
 | 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 | + | 
570 | 534 | 			this._inst.exports.run(argc, argv);  | 
571 | 535 | 			if (this.exited) {  | 
572 | 536 | 				this._resolveExitPromise();  | 
 | 
594 | 558 | 			};  | 
595 | 559 | 		}  | 
596 | 560 | 	}  | 
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 |  | -	}  | 
629 | 561 | })();  | 
0 commit comments