123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681 |
- // Copyright 2018 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // @ts-nocheck
- (() => {
- // Map multiple JavaScript environments to a single common API,
- // preferring web standards over Node.js API.
- //
- // Environments considered:
- // - Browsers
- // - Node.js
- // - Electron
- // - Parcel
- // - Webpack
- if (typeof window !== 'undefined') {
- window.global = window;
- } else if (typeof self !== 'undefined') {
- self.global = self;
- } else {
- throw new Error(
- 'cannot export Go (neither global, window nor self is defined)'
- );
- }
- const enosys = () => {
- const err = new Error('not implemented');
- err.code = 'ENOSYS';
- return err;
- };
- if (!global.fs) {
- let outputBuf = '';
- global.fs = {
- constants: {
- O_WRONLY: -1,
- O_RDWR: -1,
- O_CREAT: -1,
- O_TRUNC: -1,
- O_APPEND: -1,
- O_EXCL: -1,
- }, // unused
- writeSync(fd, buf) {
- outputBuf += decoder.decode(buf);
- const nl = outputBuf.lastIndexOf('\n');
- if (nl != -1) {
- // console.log(outputBuf.substr(0, nl));
- outputBuf = outputBuf.substr(nl + 1);
- }
- return buf.length;
- },
- write(fd, buf, offset, length, position, callback) {
- if (offset !== 0 || length !== buf.length || position !== null) {
- callback(enosys());
- return;
- }
- const n = this.writeSync(fd, buf);
- callback(null, n);
- },
- chmod(path, mode, callback) {
- callback(enosys());
- },
- chown(path, uid, gid, callback) {
- callback(enosys());
- },
- close(fd, callback) {
- callback(enosys());
- },
- fchmod(fd, mode, callback) {
- callback(enosys());
- },
- fchown(fd, uid, gid, callback) {
- callback(enosys());
- },
- fstat(fd, callback) {
- callback(enosys());
- },
- fsync(fd, callback) {
- callback(null);
- },
- ftruncate(fd, length, callback) {
- callback(enosys());
- },
- lchown(path, uid, gid, callback) {
- callback(enosys());
- },
- link(path, link, callback) {
- callback(enosys());
- },
- lstat(path, callback) {
- callback(enosys());
- },
- mkdir(path, perm, callback) {
- callback(enosys());
- },
- open(path, flags, mode, callback) {
- callback(enosys());
- },
- read(fd, buffer, offset, length, position, callback) {
- callback(enosys());
- },
- readdir(path, callback) {
- callback(enosys());
- },
- readlink(path, callback) {
- callback(enosys());
- },
- rename(from, to, callback) {
- callback(enosys());
- },
- rmdir(path, callback) {
- callback(enosys());
- },
- stat(path, callback) {
- callback(enosys());
- },
- symlink(path, link, callback) {
- callback(enosys());
- },
- truncate(path, length, callback) {
- callback(enosys());
- },
- unlink(path, callback) {
- callback(enosys());
- },
- utimes(path, atime, mtime, callback) {
- callback(enosys());
- },
- };
- }
- if (!global.process) {
- global.process = {
- getuid() {
- return -1;
- },
- getgid() {
- return -1;
- },
- geteuid() {
- return -1;
- },
- getegid() {
- return -1;
- },
- getgroups() {
- throw enosys();
- },
- pid: -1,
- ppid: -1,
- umask() {
- throw enosys();
- },
- cwd() {
- throw enosys();
- },
- chdir() {
- throw enosys();
- },
- };
- }
- if (!global.crypto) {
- throw new Error(
- 'global.crypto is not available, polyfill required (getRandomValues only)'
- );
- }
- if (!global.performance) {
- global.performance = {
- now() {
- const [sec, nsec] = process.hrtime();
- return sec * 1000 + nsec / 1000000;
- },
- };
- }
- if (!global.TextEncoder) {
- throw new Error('global.TextEncoder is not available, polyfill required');
- }
- if (!global.TextDecoder) {
- throw new Error('global.TextDecoder is not available, polyfill required');
- }
- // End of polyfills for common API.
- const encoder = new TextEncoder('utf-8');
- const decoder = new TextDecoder('utf-8');
- global.Go = class {
- constructor() {
- this.argv = ['js'];
- this.env = {};
- this.exit = code => {
- if (code !== 0) {
- console.warn('exit code:', code);
- }
- };
- this._exitPromise = new Promise(resolve => {
- this._resolveExitPromise = resolve;
- });
- this._pendingEvent = null;
- this._scheduledTimeouts = new Map();
- this._nextCallbackTimeoutID = 1;
- const setInt64 = (addr, v) => {
- this.mem.setUint32(addr + 0, v, true);
- this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true);
- };
- const getInt64 = addr => {
- const low = this.mem.getUint32(addr + 0, true);
- const high = this.mem.getInt32(addr + 4, true);
- return low + high * 4294967296;
- };
- const loadValue = addr => {
- const f = this.mem.getFloat64(addr, true);
- if (f === 0) {
- return undefined;
- }
- if (!isNaN(f)) {
- return f;
- }
- const id = this.mem.getUint32(addr, true);
- return this._values[id];
- };
- const storeValue = (addr, v) => {
- const nanHead = 0x7ff80000;
- if (typeof v === 'number' && v !== 0) {
- if (isNaN(v)) {
- this.mem.setUint32(addr + 4, nanHead, true);
- this.mem.setUint32(addr, 0, true);
- return;
- }
- this.mem.setFloat64(addr, v, true);
- return;
- }
- if (v === undefined) {
- this.mem.setFloat64(addr, 0, true);
- return;
- }
- let id = this._ids.get(v);
- if (id === undefined) {
- id = this._idPool.pop();
- if (id === undefined) {
- id = this._values.length;
- }
- this._values[id] = v;
- this._goRefCounts[id] = 0;
- this._ids.set(v, id);
- }
- this._goRefCounts[id]++;
- let typeFlag = 0;
- switch (typeof v) {
- case 'object':
- if (v !== null) {
- typeFlag = 1;
- }
- break;
- case 'string':
- typeFlag = 2;
- break;
- case 'symbol':
- typeFlag = 3;
- break;
- case 'function':
- typeFlag = 4;
- break;
- }
- this.mem.setUint32(addr + 4, nanHead | typeFlag, true);
- this.mem.setUint32(addr, id, true);
- };
- const loadSlice = addr => {
- const array = getInt64(addr + 0);
- const len = getInt64(addr + 8);
- return new Uint8Array(this._inst.exports.mem.buffer, array, len);
- };
- const loadSliceOfValues = addr => {
- const array = getInt64(addr + 0);
- const len = getInt64(addr + 8);
- const a = new Array(len);
- for (let i = 0; i < len; i++) {
- a[i] = loadValue(array + i * 8);
- }
- return a;
- };
- const loadString = addr => {
- const saddr = getInt64(addr + 0);
- const len = getInt64(addr + 8);
- return decoder.decode(
- new DataView(this._inst.exports.mem.buffer, saddr, len)
- );
- };
- const timeOrigin = Date.now() - performance.now();
- this.importObject = {
- go: {
- // Go's SP does not change as long as no Go code is running. Some operations (e.g. calls, getters and setters)
- // may synchronously trigger a Go event handler. This makes Go code get executed in the middle of the imported
- // function. A goroutine can switch to a new stack if the current stack is too small (see morestack function).
- // This changes the SP, thus we have to update the SP used by the imported function.
- // func wasmExit(code int32)
- 'runtime.wasmExit': sp => {
- sp >>>= 0;
- const code = this.mem.getInt32(sp + 8, true);
- this.exited = true;
- delete this._inst;
- delete this._values;
- delete this._goRefCounts;
- delete this._ids;
- delete this._idPool;
- this.exit(code);
- },
- // func wasmWrite(fd uintptr, p unsafe.Pointer, n int32)
- 'runtime.wasmWrite': sp => {
- sp >>>= 0;
- const fd = getInt64(sp + 8);
- const p = getInt64(sp + 16);
- const n = this.mem.getInt32(sp + 24, true);
- fs.writeSync(
- fd,
- new Uint8Array(this._inst.exports.mem.buffer, p, n)
- );
- },
- // func resetMemoryDataView()
- 'runtime.resetMemoryDataView': sp => {
- sp >>>= 0;
- this.mem = new DataView(this._inst.exports.mem.buffer);
- },
- // func nanotime1() int64
- 'runtime.nanotime1': sp => {
- sp >>>= 0;
- setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000);
- },
- // func walltime() (sec int64, nsec int32)
- 'runtime.walltime': sp => {
- sp >>>= 0;
- const msec = new Date().getTime();
- setInt64(sp + 8, msec / 1000);
- this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true);
- },
- // func scheduleTimeoutEvent(delay int64) int32
- 'runtime.scheduleTimeoutEvent': sp => {
- sp >>>= 0;
- const id = this._nextCallbackTimeoutID;
- this._nextCallbackTimeoutID++;
- this._scheduledTimeouts.set(
- id,
- setTimeout(
- () => {
- this._resume();
- while (this._scheduledTimeouts.has(id)) {
- // for some reason Go failed to register the timeout event, log and try again
- // (temporary workaround for https://github.com/golang/go/issues/28975)
- console.warn('scheduleTimeoutEvent: missed timeout event');
- this._resume();
- }
- },
- getInt64(sp + 8) + 1 // setTimeout has been seen to fire up to 1 millisecond early
- )
- );
- this.mem.setInt32(sp + 16, id, true);
- },
- // func clearTimeoutEvent(id int32)
- 'runtime.clearTimeoutEvent': sp => {
- sp >>>= 0;
- const id = this.mem.getInt32(sp + 8, true);
- clearTimeout(this._scheduledTimeouts.get(id));
- this._scheduledTimeouts.delete(id);
- },
- // func getRandomData(r []byte)
- 'runtime.getRandomData': sp => {
- sp >>>= 0;
- crypto.getRandomValues(loadSlice(sp + 8));
- },
- // func finalizeRef(v ref)
- 'syscall/js.finalizeRef': sp => {
- sp >>>= 0;
- const id = this.mem.getUint32(sp + 8, true);
- this._goRefCounts[id]--;
- if (this._goRefCounts[id] === 0) {
- const v = this._values[id];
- this._values[id] = null;
- this._ids.delete(v);
- this._idPool.push(id);
- }
- },
- // func stringVal(value string) ref
- 'syscall/js.stringVal': sp => {
- sp >>>= 0;
- storeValue(sp + 24, loadString(sp + 8));
- },
- // func valueGet(v ref, p string) ref
- 'syscall/js.valueGet': sp => {
- sp >>>= 0;
- const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16));
- sp = this._inst.exports.getsp() >>> 0; // see comment above
- storeValue(sp + 32, result);
- },
- // func valueSet(v ref, p string, x ref)
- 'syscall/js.valueSet': sp => {
- sp >>>= 0;
- Reflect.set(
- loadValue(sp + 8),
- loadString(sp + 16),
- loadValue(sp + 32)
- );
- },
- // func valueDelete(v ref, p string)
- 'syscall/js.valueDelete': sp => {
- sp >>>= 0;
- Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16));
- },
- // func valueIndex(v ref, i int) ref
- 'syscall/js.valueIndex': sp => {
- sp >>>= 0;
- storeValue(
- sp + 24,
- Reflect.get(loadValue(sp + 8), getInt64(sp + 16))
- );
- },
- // valueSetIndex(v ref, i int, x ref)
- 'syscall/js.valueSetIndex': sp => {
- sp >>>= 0;
- Reflect.set(
- loadValue(sp + 8),
- getInt64(sp + 16),
- loadValue(sp + 24)
- );
- },
- // func valueCall(v ref, m string, args []ref) (ref, bool)
- 'syscall/js.valueCall': sp => {
- sp >>>= 0;
- try {
- const v = loadValue(sp + 8);
- const m = Reflect.get(v, loadString(sp + 16));
- const args = loadSliceOfValues(sp + 32);
- const result = Reflect.apply(m, v, args);
- sp = this._inst.exports.getsp() >>> 0; // see comment above
- storeValue(sp + 56, result);
- this.mem.setUint8(sp + 64, 1);
- } catch (err) {
- sp = this._inst.exports.getsp() >>> 0; // see comment above
- storeValue(sp + 56, err);
- this.mem.setUint8(sp + 64, 0);
- }
- },
- // func valueInvoke(v ref, args []ref) (ref, bool)
- 'syscall/js.valueInvoke': sp => {
- sp >>>= 0;
- try {
- const v = loadValue(sp + 8);
- const args = loadSliceOfValues(sp + 16);
- const result = Reflect.apply(v, undefined, args);
- sp = this._inst.exports.getsp() >>> 0; // see comment above
- storeValue(sp + 40, result);
- this.mem.setUint8(sp + 48, 1);
- } catch (err) {
- sp = this._inst.exports.getsp() >>> 0; // see comment above
- storeValue(sp + 40, err);
- this.mem.setUint8(sp + 48, 0);
- }
- },
- // func valueNew(v ref, args []ref) (ref, bool)
- 'syscall/js.valueNew': sp => {
- sp >>>= 0;
- try {
- const v = loadValue(sp + 8);
- const args = loadSliceOfValues(sp + 16);
- const result = Reflect.construct(v, args);
- sp = this._inst.exports.getsp() >>> 0; // see comment above
- storeValue(sp + 40, result);
- this.mem.setUint8(sp + 48, 1);
- } catch (err) {
- sp = this._inst.exports.getsp() >>> 0; // see comment above
- storeValue(sp + 40, err);
- this.mem.setUint8(sp + 48, 0);
- }
- },
- // func valueLength(v ref) int
- 'syscall/js.valueLength': sp => {
- sp >>>= 0;
- setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
- },
- // valuePrepareString(v ref) (ref, int)
- 'syscall/js.valuePrepareString': sp => {
- sp >>>= 0;
- const str = encoder.encode(String(loadValue(sp + 8)));
- storeValue(sp + 16, str);
- setInt64(sp + 24, str.length);
- },
- // valueLoadString(v ref, b []byte)
- 'syscall/js.valueLoadString': sp => {
- sp >>>= 0;
- const str = loadValue(sp + 8);
- loadSlice(sp + 16).set(str);
- },
- // func valueInstanceOf(v ref, t ref) bool
- 'syscall/js.valueInstanceOf': sp => {
- sp >>>= 0;
- this.mem.setUint8(
- sp + 24,
- loadValue(sp + 8) instanceof loadValue(sp + 16) ? 1 : 0
- );
- },
- // func copyBytesToGo(dst []byte, src ref) (int, bool)
- 'syscall/js.copyBytesToGo': sp => {
- sp >>>= 0;
- const dst = loadSlice(sp + 8);
- const src = loadValue(sp + 32);
- if (
- !(src instanceof Uint8Array || src instanceof Uint8ClampedArray)
- ) {
- this.mem.setUint8(sp + 48, 0);
- return;
- }
- const toCopy = src.subarray(0, dst.length);
- dst.set(toCopy);
- setInt64(sp + 40, toCopy.length);
- this.mem.setUint8(sp + 48, 1);
- },
- // func copyBytesToJS(dst ref, src []byte) (int, bool)
- 'syscall/js.copyBytesToJS': sp => {
- sp >>>= 0;
- const dst = loadValue(sp + 8);
- const src = loadSlice(sp + 16);
- if (
- !(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)
- ) {
- this.mem.setUint8(sp + 48, 0);
- return;
- }
- const toCopy = src.subarray(0, dst.length);
- dst.set(toCopy);
- setInt64(sp + 40, toCopy.length);
- this.mem.setUint8(sp + 48, 1);
- },
- debug: value => {
- console.log(value);
- },
- },
- };
- }
- async run(instance) {
- if (!(instance instanceof WebAssembly.Instance)) {
- throw new Error('Go.run: WebAssembly.Instance expected');
- }
- this._inst = instance;
- this.mem = new DataView(this._inst.exports.mem.buffer);
- this._values = [
- // JS values that Go currently has references to, indexed by reference id
- NaN,
- 0,
- null,
- true,
- false,
- global,
- this,
- ];
- this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id
- this._ids = new Map([
- // mapping from JS values to reference ids
- [0, 1],
- [null, 2],
- [true, 3],
- [false, 4],
- [global, 5],
- [this, 6],
- ]);
- this._idPool = []; // unused ids that have been garbage collected
- this.exited = false; // whether the Go program has exited
- // Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory.
- let offset = 4096;
- const strPtr = str => {
- const ptr = offset;
- const bytes = encoder.encode(str + '\0');
- new Uint8Array(this.mem.buffer, offset, bytes.length).set(bytes);
- offset += bytes.length;
- if (offset % 8 !== 0) {
- offset += 8 - (offset % 8);
- }
- return ptr;
- };
- const argc = this.argv.length;
- const argvPtrs = [];
- this.argv.forEach(arg => {
- argvPtrs.push(strPtr(arg));
- });
- argvPtrs.push(0);
- const keys = Object.keys(this.env).sort();
- keys.forEach(key => {
- argvPtrs.push(strPtr(`${key}=${this.env[key]}`));
- });
- argvPtrs.push(0);
- const argv = offset;
- argvPtrs.forEach(ptr => {
- this.mem.setUint32(offset, ptr, true);
- this.mem.setUint32(offset + 4, 0, true);
- offset += 8;
- });
- // The linker guarantees global data starts from at least wasmMinDataAddr.
- // Keep in sync with cmd/link/internal/ld/data.go:wasmMinDataAddr.
- const wasmMinDataAddr = 4096 + 8192;
- if (offset >= wasmMinDataAddr) {
- throw new Error(
- 'total length of command line and environment variables exceeds limit'
- );
- }
- this._inst.exports.run(argc, argv);
- if (this.exited) {
- this._resolveExitPromise();
- }
- await this._exitPromise;
- }
- _resume() {
- if (this.exited) {
- throw new Error('Go program has already exited');
- }
- this._inst.exports.resume();
- if (this.exited) {
- this._resolveExitPromise();
- }
- }
- _makeFuncWrapper(id) {
- const go = this;
- return function () {
- const event = { id: id, this: this, args: arguments };
- go._pendingEvent = event;
- go._resume();
- return event.result;
- };
- }
- };
- })();
|