|
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