PageSourceSearch

https://wasmbyexample.dev/examples/hello-world/demo/go/wasm_exec.js

js wasmbyexample.dev collected 2026-10-02 05:25:21 UTC 18,471 bytes, 633 lines download raw bytes

1// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4//
5// This file has been modified for use by the TinyGo compiler.
6
7(() => {
8  // Map multiple JavaScript environments to a single common API,
9  // preferring web standards over Node.js API.
10  //
11  // Environments considered:
12  // - Browsers
13  // - Node.js
14  // - Electron
15  // - Parcel
16
17  if (typeof global !== "undefined") {
18    // global already exists
19  } else if (typeof window !== "undefined") {
20    window.global = window;
21  } else if (typeof self !== "undefined") {
22    self.global = self;
23  } else {
24    throw new Error(
25      "cannot export Go (neither global, window nor self is defined)"
26    );
27  }
28
29  if (!global.require && typeof require !== "undefined") {
30    global.require = require;
31  }
32
33  if (!global.fs && global.require) {
34    global.fs = require("fs");
35  }
36
37  const enosys = () => {
38    const err = new Error("not implemented");
39    err.code = "ENOSYS";
40    return err;
41  };
42
43  if (!global.fs) {
44    let outputBuf = "";
45    global.fs = {
46      constants: {
47        O_WRONLY: -1,
48        O_RDWR: -1,
49        O_CREAT: -1,
50        O_TRUNC: -1,
51        O_APPEND: -1,
52        O_EXCL: -1
53      }, // unused
54      writeSync(fd, buf) {
55        outputBuf += decoder.decode(buf);
56        const nl = outputBuf.lastIndexOf("\n");
57        if (nl != -1) {
58          console.log(outputBuf.substr(0, nl));
59          outputBuf = outputBuf.substr(nl + 1);
60        }
61        return buf.length;
62      },
63      write(fd, buf, offset, length, position, callback) {
64        if (offset !== 0 || length !== buf.length || position !== null) {
65          callback(enosys());
66          return;
67        }
68        const n = this.writeSync(fd, buf);
69        callback(null, n);
70      },
71      chmod(path, mode, callback) {
72        callback(enosys());
73      },
74      chown(path, uid, gid, callback) {
75        callback(enosys());
76      },
77      close(fd, callback) {
78        callback(enosys());
79      },
80      fchmod(fd, mode, callback) {
81        callback(enosys());
82      },
83      fchown(fd, uid, gid, callback) {
84        callback(enosys());
85      },
86      fstat(fd, callback) {
87        callback(enosys());
88      },
89      fsync(fd, callback) {
90        callback(null);
91      },
92      ftruncate(fd, length, callback) {
93        callback(enosys());
94      },
95      lchown(path, uid, gid, callback) {
96        callback(enosys());
97      },
98      link(path, link, callback) {
99        callback(enosys());
100      },
101      lstat(path, callback) {
102        callback(enosys());
103      },
104      mkdir(path, perm, callback) {
105        callback(enosys());
106      },
107      open(path, flags, mode, callback) {
108        callback(enosys());
109      },
110      read(fd, buffer, offset, length, position, callback) {
111        callback(enosys());
112      },
113      readdir(path, callback) {
114        callback(enosys());
115      },
116      readlink(path, callback) {
117        callback(enosys());
118      },
119      rename(from, to, callback) {
120        callback(enosys());
121      },
122      rmdir(path, callback) {
123        callback(enosys());
124      },
125      stat(path, callback) {
126        callback(enosys());
127      },
128      symlink(path, link, callback) {
129        callback(enosys());
130      },
131      truncate(path, length, callback) {
132        callback(enosys());
133      },
134      unlink(path, callback) {
135        callback(enosys());
136      },
137      utimes(path, atime, mtime, callback) {
138        callback(enosys());
139      }
140    };
141  }
142
143  if (!global.process) {
144    global.process = {
145      getuid() {
146        return -1;
147      },
148      getgid() {
149        return -1;
150      },
151      geteuid() {
152        return -1;
153      },
154      getegid() {
155        return -1;
156      },
157      getgroups() {
158        throw enosys();
159      },
160      pid: -1,
161      ppid: -1,
162      umask() {
163        throw enosys();
164      },
165      cwd() {
166        throw enosys();
167      },
168      chdir() {
169        throw enosys();
170      }
171    };
172  }
173
174  if (!global.crypto) {
175    const nodeCrypto = require("crypto");
176    global.crypto = {
177      getRandomValues(b) {
178        nodeCrypto.randomFillSync(b);
179      }
180    };
181  }
182
183  if (!global.performance) {
184    global.performance = {
185      now() {
186        const [sec, nsec] = process.hrtime();
187        return sec * 1000 + nsec / 1000000;
188      }
189    };
190  }
191
192  if (!global.TextEncoder) {
193    global.TextEncoder = require("util").TextEncoder;
194  }
195
196  if (!global.TextDecoder) {
197    global.TextDecoder = require("util").TextDecoder;
198  }
199
200  // End of polyfills for common API.
201
202  const encoder = new TextEncoder("utf-8");
203  const decoder = new TextDecoder("utf-8");
204  var logLine = [];
205
206  global.Go = class {
207    constructor() {
208      this._callbackTimeouts = new Map();
209      this._nextCallbackTimeoutID = 1;
210
211      const mem = () => {
212        // The buffer may change when requesting more memory.
213        return new DataView(this._inst.exports.memory.buffer);
214      };
215
216      const setInt64 = (addr, v) => {
217        mem().setUint32(addr + 0, v, true);
218        mem().setUint32(addr + 4, Math.floor(v / 4294967296), true);
219      };
220
221      const getInt64 = addr => {
222        const low = mem().getUint32(addr + 0, true);
223        const high = mem().getInt32(addr + 4, true);
224        return low + high * 4294967296;
225      };
226
227      const loadValue = addr => {
228        const f = mem().getFloat64(addr, true);
229        if (f === 0) {
230          return undefined;
231        }
232        if (!isNaN(f)) {
233          return f;
234        }
235
236        const id = mem().getUint32(addr, true);
237        return this._values[id];
238      };
239
240      const storeValue = (addr, v) => {
241        const nanHead = 0x7ff80000;
242
243        if (typeof v === "number") {
244          if (isNaN(v)) {
245            mem().setUint32(addr + 4, nanHead, true);
246            mem().setUint32(addr, 0, true);
247            return;
248          }
249          if (v === 0) {
250            mem().setUint32(addr + 4, nanHead, true);
251            mem().setUint32(addr, 1, true);
252            return;
253          }
254          mem().setFloat64(addr, v, true);
255          return;
256        }
257
258        switch (v) {
259          case undefined:
260            mem().setFloat64(addr, 0, true);
261            return;
262          case null:
263            mem().setUint32(addr + 4, nanHead, true);
264            mem().setUint32(addr, 2, true);
265            return;
266          case true:
267            mem().setUint32(addr + 4, nanHead, true);
268            mem().setUint32(addr, 3, true);
269            return;
270          case false:
271            mem().setUint32(addr + 4, nanHead, true);
272            mem().setUint32(addr, 4, true);
273            return;
274        }
275
276        let id = this._ids.get(v);
277        if (id === undefined) {
278          id = this._idPool.pop();
279          if (id === undefined) {
280            id = this._values.length;
281          }
282          this._values[id] = v;
283          this._goRefCounts[id] = 0;
284          this._ids.set(v, id);
285        }
286        this._goRefCounts[id]++;
287        let typeFlag = 1;
288        switch (typeof v) {
289          case "string":
290            typeFlag = 2;
291            break;
292          case "symbol":
293            typeFlag = 3;
294            break;
295          case "function":
296            typeFlag = 4;
297            break;
298        }
299        mem().setUint32(addr + 4, nanHead | typeFlag, true);
300        mem().setUint32(addr, id, true);
301      };
302
303      const loadSlice = (array, len, cap) => {
304        return new Uint8Array(this._inst.exports.memory.buffer, array, len);
305      };
306
307      const loadSliceOfValues = (array, len, cap) => {
308        const a = new Array(len);
309        for (let i = 0; i < len; i++) {
310          a[i] = loadValue(array + i * 8);
311        }
312        return a;
313      };
314
315      const loadString = (ptr, len) => {
316        return decoder.decode(
317          new DataView(this._inst.exports.memory.buffer, ptr, len)
318        );
319      };
320
321      const timeOrigin = Date.now() - performance.now();
322      this.importObject = {
323        wasi_unstable: {
324          // https://github.com/bytecodealliance/wasmtime/blob/master/docs/WASI-api.md#__wasi_fd_write
325          fd_write: function(fd, iovs_ptr, iovs_len, nwritten_ptr) {
326            let nwritten = 0;
327            if (fd == 1) {
328              for (let iovs_i = 0; iovs_i < iovs_len; iovs_i++) {
329                let iov_ptr = iovs_ptr + iovs_i * 8; // assuming wasm32
330                let ptr = mem().getUint32(iov_ptr + 0, true);
331                let len = mem().getUint32(iov_ptr + 4, true);
332                for (let i = 0; i < len; i++) {
333                  let c = mem().getUint8(ptr + i);
334                  if (c == 13) {
335                    // CR
336                    // ignore
337                  } else if (c == 10) {
338                    // LF
339                    // write line
340                    let line = decoder.decode(new Uint8Array(logLine));
341                    logLine = [];
342                    console.log(line);
343                  } else {
344                    logLine.push(c);
345                  }
346                }
347              }
348            } else {
349              console.error("invalid file descriptor:", fd);
350            }
351            mem().setUint32(nwritten_ptr, nwritten, true);
352            return 0;
353          }
354        },
355        env: {
356          // func ticks() float64
357          "runtime.ticks": () => {
358            return timeOrigin + performance.now();
359          },
360
361          // func sleepTicks(timeout float64)
362          "runtime.sleepTicks": timeout => {
363            // Do not sleep, only reactivate scheduler after the given timeout.
364            setTimeout(this._inst.exports.go_scheduler, timeout);
365          },
366
367          // func finalizeRef(v ref)
368          "syscall/js.finalizeRef": sp => {
369            // Note: TinyGo does not support finalizers so this should never be
370            // called.
371            console.error("syscall/js.finalizeRef not implemented");
372          },
373
374          // func stringVal(value string) ref
375          "syscall/js.stringVal": (ret_ptr, value_ptr, value_len) => {
376            const s = loadString(value_ptr, value_len);
377            storeValue(ret_ptr, s);
378          },
379
380          // func valueGet(v ref, p string) ref
381          "syscall/js.valueGet": (retval, v_addr, p_ptr, p_len) => {
382            let prop = loadString(p_ptr, p_len);
383            let value = loadValue(v_addr);
384            let result = Reflect.get(value, prop);
385            storeValue(retval, result);
386          },
387
388          // func valueSet(v ref, p string, x ref)
389          "syscall/js.valueSet": (v_addr, p_ptr, p_len, x_addr) => {
390            const v = loadValue(v_addr);
391            const p = loadString(p_ptr, p_len);
392            const x = loadValue(x_addr);
393            Reflect.set(v, p, x);
394          },
395
396          // func valueDelete(v ref, p string)
397          "syscall/js.valueDelete": (v_addr, p_ptr, p_len) => {
398            const v = loadValue(v_addr);
399            const p = loadString(p_ptr, p_len);
400            Reflect.deleteProperty(v, p);
401          },
402
403          // func valueIndex(v ref, i int) ref
404          "syscall/js.valueIndex": (ret_addr, v_addr, i) => {
405            storeValue(ret_addr, Reflect.get(loadValue(v_addr), i));
406          },
407
408          // valueSetIndex(v ref, i int, x ref)
409          "syscall/js.valueSetIndex": (v_addr, i, x_addr) => {
410            Reflect.set(loadValue(v_addr), i, loadValue(x_addr));
411          },
412
413          // func valueCall(v ref, m string, args []ref) (ref, bool)
414          "syscall/js.valueCall": (
415            ret_addr,
416            v_addr,
417            m_ptr,
418            m_len,
419            args_ptr,
420            args_len,
421            args_cap
422          ) => {
423            const v = loadValue(v_addr);
424            const name = loadString(m_ptr, m_len);
425            const args = loadSliceOfValues(args_ptr, args_len, args_cap);
426            try {
427              const m = Reflect.get(v, name);
428              storeValue(ret_addr, Reflect.apply(m, v, args));
429              mem().setUint8(ret_addr + 8, 1);
430            } catch (err) {
431              storeValue(ret_addr, err);
432              mem().setUint8(ret_addr + 8, 0);
433            }
434          },
435
436          // func valueInvoke(v ref, args []ref) (ref, bool)
437          "syscall/js.valueInvoke": (
438            ret_addr,
439            v_addr,
440            args_ptr,
441            args_len,
442            args_cap
443          ) => {
444            try {
445              const v = loadValue(v_addr);
446              const args = loadSliceOfValues(args_ptr, args_len, args_cap);
447              storeValue(ret_addr, Reflect.apply(v, undefined, args));
448              mem().setUint8(ret_addr + 8, 1);
449            } catch (err) {
450              storeValue(ret_addr, err);
451              mem().setUint8(ret_addr + 8, 0);
452            }
453          },
454
455          // func valueNew(v ref, args []ref) (ref, bool)
456          "syscall/js.valueNew": (
457            ret_addr,
458            v_addr,
459            args_ptr,
460            args_len,
461            args_cap
462          ) => {
463            const v = loadValue(v_addr);
464            const args = loadSliceOfValues(args_ptr, args_len, args_cap);
465            try {
466              storeValue(ret_addr, Reflect.construct(v, args));
467              mem().setUint8(ret_addr + 8, 1);
468            } catch (err) {
469              storeValue(ret_addr, err);
470              mem().setUint8(ret_addr + 8, 0);
471            }
472          },
473
474          // func valueLength(v ref) int
475          "syscall/js.valueLength": v_addr => {
476            return loadValue(v_addr).length;
477          },
478
479          // valuePrepareString(v ref) (ref, int)
480          "syscall/js.valuePrepareString": (ret_addr, v_addr) => {
481            const s = String(loadValue(v_addr));
482            const str = encoder.encode(s);
483            storeValue(ret_addr, str);
484            setInt64(ret_addr + 8, str.length);
485          },
486
487          // valueLoadString(v ref, b []byte)
488          "syscall/js.valueLoadString": (
489            v_addr,
490            slice_ptr,
491            slice_len,
492            slice_cap
493          ) => {
494            const str = loadValue(v_addr);
495            loadSlice(slice_ptr, slice_len, slice_cap).set(str);
496          },
497
498          // func valueInstanceOf(v ref, t ref) bool
499          //"syscall/js.valueInstanceOf": (sp) => {
500          //	mem().setUint8(sp + 24, loadValue(sp + 8) instanceof loadValue(sp + 16));
501          //},
502
503          // func copyBytesToGo(dst []byte, src ref) (int, bool)
504          "syscall/js.copyBytesToGo": (
505            ret_addr,
506            dest_addr,
507            dest_len,
508            dest_cap,
509            source_addr
510          ) => {
511            let num_bytes_copied_addr = ret_addr;
512            let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable
513
514            const dst = loadSlice(dest_addr, dest_len);
515            const src = loadValue(source_addr);
516            if (!(src instanceof Uint8Array)) {
517              mem().setUint8(returned_status_addr, 0); // Return "not ok" status
518              return;
519            }
520            const toCopy = src.subarray(0, dst.length);
521            dst.set(toCopy);
522            setInt64(num_bytes_copied_addr, toCopy.length);
523            mem().setUint8(returned_status_addr, 1); // Return "ok" status
524          },
525
526          // copyBytesToJS(dst ref, src []byte) (int, bool)
527          // Originally copied from upstream Go project, then modified:
528          //   https://github.com/golang/go/blob/3f995c3f3b43033013013e6c7ccc93a9b1411ca9/misc/wasm/wasm_exec.js#L404-L416
529          "syscall/js.copyBytesToJS": (
530            ret_addr,
531            dest_addr,
532            source_addr,
533            source_len,
534            source_cap
535          ) => {
536            let num_bytes_copied_addr = ret_addr;
537            let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable
538
539            const dst = loadValue(dest_addr);
540            const src = loadSlice(source_addr, source_len);
541            if (!(dst instanceof Uint8Array)) {
542              mem().setUint8(returned_status_addr, 0); // Return "not ok" status
543              return;
544            }
545            const toCopy = src.subarray(0, dst.length);
546            dst.set(toCopy);
547            setInt64(num_bytes_copied_addr, toCopy.length);
548            mem().setUint8(returned_status_addr, 1); // Return "ok" status
549          }
550        }
551      };
552    }
553
554    async run(instance) {
555      this._inst = instance;
556      this._values = [
557        // JS values that Go currently has references to, indexed by reference id
558        NaN,
559        0,
560        null,
561        true,
562        false,
563        global,
564        this
565      ];
566      this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id
567      this._ids = new Map(); // mapping from JS values to reference ids
568      this._idPool = []; // unused ids that have been garbage collected
569      this.exited = false; // whether the Go program has exited
570
571      const mem = new DataView(this._inst.exports.memory.buffer);
572
573      while (true) {
574        const callbackPromise = new Promise(resolve => {
575          this._resolveCallbackPromise = () => {
576            if (this.exited) {
577              throw new Error("bad callback: Go program has already exited");
578            }
579            setTimeout(resolve, 0); // make sure it is asynchronous
580          };
581        });
582        this._inst.exports._start();
583        if (this.exited) {
584          break;
585        }
586        await callbackPromise;
587      }
588    }
589
590    _resume() {
591      if (this.exited) {
592        throw new Error("Go program has already exited");
593      }
594      this._inst.exports.resume();
595      if (this.exited) {
596        this._resolveExitPromise();
597      }
598    }
599
600    _makeFuncWrapper(id) {
601      const go = this;
602      return function() {
603        const event = { id: id, this: this, args: arguments };
604        go._pendingEvent = event;
605        go._resume();
606        return event.result;
607      };
608    }
609  };
610
611  if (
612    global.require &&
613    global.require.main === module &&
614    global.process &&
615    global.process.versions &&
616    !global.process.versions.electron
617  ) {
618    if (process.argv.length != 3) {
619      console.error("usage: go_js_wasm_exec [wasm binary] [arguments]");
620      process.exit(1);
621    }
622
623    const go = new Go();
624    WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject)
625      .then(result => {
626        return go.run(result.instance);
627      })
628      .catch(err => {
629        console.error(err);
630        process.exit(1);
631      });
632  }
633})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.