From 8710da338b4c0c40511e1f79eabcc95ba0430355 Mon Sep 17 00:00:00 2001 From: Arthur Lu Date: Mon, 6 Jul 2026 20:37:48 +0000 Subject: [PATCH] add wfa-js as submodule, consolidate build process --- .gitmodules | 3 + Makefile | 8 +- WFA-JS | 1 + web/modules/wfa.js | 581 ++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 589 insertions(+), 4 deletions(-) create mode 160000 WFA-JS diff --git a/.gitmodules b/.gitmodules index 69f71d5..41fb0f1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "proxmoxaas-common-lib"] path = proxmoxaas-common-lib url = https://git.tronnet.net/tronnet/proxmoxaas-common-lib +[submodule "WFA-JS"] + path = WFA-JS + url = https://git.tronnet.net/alu/WFA-JS diff --git a/Makefile b/Makefile index 7098afc..63f3963 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,15 @@ -.PHONY: build test clean +.PHONY: build test clean wfa-js -build: clean +build: clean wfa-js @echo "======================== Building Binary =======================" # resolve symbolic links in web by copying it into dist/web/ cp -rL web/ dist/web/ CGO_ENABLED=0 go build -tags release -ldflags="-s -w" -v -o dist/ . +wfa-js: + $(MAKE) -C WFA-JS + cp -f WFA-JS/dist/* web/modules + test: clean go run . diff --git a/WFA-JS b/WFA-JS new file mode 160000 index 0000000..05cd2d7 --- /dev/null +++ b/WFA-JS @@ -0,0 +1 @@ +Subproject commit 05cd2d79df22a1264de3c42e2411cabc54a9f20a diff --git a/web/modules/wfa.js b/web/modules/wfa.js index 7a35cc3..f99b95d 100644 --- a/web/modules/wfa.js +++ b/web/modules/wfa.js @@ -1,2 +1,579 @@ -(()=>{if(typeof global!="undefined");else 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)");!global.require&&typeof require!="undefined"&&(global.require=require),!global.fs&&global.require&&(global.fs=require("node:fs"));const e=()=>{const e=new Error("not implemented");return e.code="ENOSYS",e};if(!global.fs){let t="";global.fs={constants:{O_WRONLY:-1,O_RDWR:-1,O_CREAT:-1,O_TRUNC:-1,O_APPEND:-1,O_EXCL:-1},writeSync(e,n){t+=s.decode(n);const o=t.lastIndexOf(` -`);return o!=-1&&(console.log(t.substr(0,o)),t=t.substr(o+1)),n.length},write(t,n,s,o,i,a){if(s!==0||o!==n.length||i!==null){a(e());return}const r=this.writeSync(t,n);a(null,r)},chmod(t,n,s){s(e())},chown(t,n,s,o){o(e())},close(t,n){n(e())},fchmod(t,n,s){s(e())},fchown(t,n,s,o){o(e())},fstat(t,n){n(e())},fsync(e,t){t(null)},ftruncate(t,n,s){s(e())},lchown(t,n,s,o){o(e())},link(t,n,s){s(e())},lstat(t,n){n(e())},mkdir(t,n,s){s(e())},open(t,n,s,o){o(e())},read(t,n,s,o,i,a){a(e())},readdir(t,n){n(e())},readlink(t,n){n(e())},rename(t,n,s){s(e())},rmdir(t,n){n(e())},stat(t,n){n(e())},symlink(t,n,s){s(e())},truncate(t,n,s){s(e())},unlink(t,n){n(e())},utimes(t,n,s,o){o(e())}}}if(global.process||(global.process={getuid(){return-1},getgid(){return-1},geteuid(){return-1},getegid(){return-1},getgroups(){throw e()},pid:-1,ppid:-1,umask(){throw e()},cwd(){throw e()},chdir(){throw e()}}),!global.crypto){const e=require("node:crypto");global.crypto={getRandomValues(t){e.randomFillSync(t)}}}global.performance||(global.performance={now(){const[e,t]=process.hrtime();return e*1e3+t/1e6}}),global.TextEncoder||(global.TextEncoder=require("node:util").TextEncoder),global.TextDecoder||(global.TextDecoder=require("node:util").TextDecoder);const i=new TextEncoder("utf-8"),s=new TextDecoder("utf-8");let t=new DataView(new ArrayBuffer(8));var o=[];const n={};if(global.Go=class{constructor(){this._callbackTimeouts=new Map,this._nextCallbackTimeoutID=1;const e=()=>new DataView(this._inst.exports.memory.buffer),a=e=>{t.setBigInt64(0,e,!0);const n=t.getFloat64(0,!0);if(n===0)return 0[0];if(!isNaN(n))return n;const s=e&4294967295n;return this._values[s]},h=t=>{let n=e().getBigUint64(t,!0);return a(n)},l=e=>{const s=2146959360n;if(typeof e=="number")return isNaN(e)?s<<32n:e===0?s<<32n|1n:(t.setFloat64(0,e,!0),t.getBigInt64(0,!0));switch(e){case 0[0]:return 0n;case null:return s<<32n|2n;case!0:return s<<32n|3n;case!1:return s<<32n|4n}let n=this._ids.get(e);n===0[0]&&(n=this._idPool.pop(),n===0[0]&&(n=BigInt(this._values.length)),this._values[n]=e,this._goRefCounts[n]=0,this._ids.set(e,n)),this._goRefCounts[n]++;let o=1n;switch(typeof e){case"string":o=2n;break;case"symbol":o=3n;break;case"function":o=4n;break}return n|(s|o)<<32n},r=(t,n)=>{let s=l(n);e().setBigUint64(t,s,!0)},d=(e,t)=>new Uint8Array(this._inst.exports.memory.buffer,e,t),u=(e,t)=>{const s=new Array(t);for(let n=0;ns.decode(new DataView(this._inst.exports.memory.buffer,e,t)),m=Date.now()-performance.now();this.importObject={wasi_snapshot_preview1:{fd_write:function(t,n,i,a){let r=0;if(t==1)for(let t=0;t0,fd_fdstat_get:()=>0,fd_seek:()=>0,proc_exit:e=>{throw this.exited=!0,this.exitCode=e,this._resolveExitPromise(),n},random_get:(e,t)=>(crypto.getRandomValues(d(e,t)),0)},gojs:{"runtime.ticks":()=>BigInt((m+performance.now())*1e6),"runtime.sleepTicks":e=>{setTimeout(()=>{if(this.exited)return;try{this._inst.exports.go_scheduler()}catch(e){if(e!==n)throw e}},Number(e)/1e6)},"syscall/js.finalizeRef":e=>{const t=e&4294967295n;if(this._goRefCounts?.[t]!==0[0]){if(this._goRefCounts[t]--,this._goRefCounts[t]===0){const e=this._values[t];this._values[t]=null,this._ids.delete(e),this._idPool.push(t)}}else console.error("syscall/js.finalizeRef: unknown id",t)},"syscall/js.stringVal":(e,t)=>{e>>>=0;const n=c(e,t);return l(n)},"syscall/js.valueGet":(e,t,n)=>{let s=c(t,n),o=a(e),i=Reflect.get(o,s);return l(i)},"syscall/js.valueSet":(e,t,n,s)=>{const o=a(e),i=c(t,n),r=a(s);Reflect.set(o,i,r)},"syscall/js.valueDelete":(e,t,n)=>{const s=a(e),o=c(t,n);Reflect.deleteProperty(s,o)},"syscall/js.valueIndex":(e,t)=>l(Reflect.get(a(e),t)),"syscall/js.valueSetIndex":(e,t,n)=>{Reflect.set(a(e),t,a(n))},"syscall/js.valueCall":(t,n,s,o,i,l,d)=>{const h=a(n),m=c(s,o),f=u(i,l,d);try{const n=Reflect.get(h,m);r(t,Reflect.apply(n,h,f)),e().setUint8(t+8,1)}catch(n){r(t,n),e().setUint8(t+8,0)}},"syscall/js.valueInvoke":(t,n,s,o,i)=>{try{const c=a(n),l=u(s,o,i);r(t,Reflect.apply(c,0[0],l)),e().setUint8(t+8,1)}catch(n){r(t,n),e().setUint8(t+8,0)}},"syscall/js.valueNew":(t,n,s,o,i)=>{const c=a(n),l=u(s,o,i);try{r(t,Reflect.construct(c,l)),e().setUint8(t+8,1)}catch(n){r(t,n),e().setUint8(t+8,0)}},"syscall/js.valueLength":e=>a(e).length,"syscall/js.valuePrepareString":(t,n)=>{const o=String(a(n)),s=i.encode(o);r(t,s),e().setInt32(t+8,s.length,!0)},"syscall/js.valueLoadString":(e,t,n,s)=>{const o=a(e);d(t,n,s).set(o)},"syscall/js.valueInstanceOf":(e,t)=>a(e)instanceof a(t),"syscall/js.copyBytesToGo":(t,n,s,o,i)=>{let h=t,c=t+4;const l=d(n,s),r=a(i);if(!(r instanceof Uint8Array||r instanceof Uint8ClampedArray)){e().setUint8(c,0);return}const u=r.subarray(0,l.length);l.set(u),e().setUint32(h,u.length,!0),e().setUint8(c,1)},"syscall/js.copyBytesToJS":(t,n,s,o)=>{let u=t,c=t+4;const r=a(n),h=d(s,o);if(!(r instanceof Uint8Array||r instanceof Uint8ClampedArray)){e().setUint8(c,0);return}const l=h.subarray(0,r.length);r.set(l),e().setUint32(u,l.length,!0),e().setUint8(c,1)}}},this.importObject.env=this.importObject.gojs}async run(e){if(this._inst=e,this._values=[NaN,0,null,!0,!1,global,this],this._goRefCounts=[],this._ids=new Map,this._idPool=[],this.exited=!1,this.exitCode=0,this._inst.exports._start){let e=new Promise((e)=>{this._resolveExitPromise=e});try{this._inst.exports._start()}catch(e){if(e!==n)throw e}return await e,this.exitCode}this._inst.exports._initialize()}_resume(){if(this.exited)throw new Error("Go program has already exited");try{this._inst.exports.resume()}catch(e){if(e!==n)throw e}this.exited&&this._resolveExitPromise()}_makeFuncWrapper(e){const t=this;return function(){const n={id:e,this:this,args:arguments};return t._pendingEvent=n,t._resume(),n.result}}},global.require&&global.require.main===module&&global.process&&global.process.versions&&!global.process.versions.electron){process.argv.length!=3&&(console.error("usage: go_js_wasm_exec [wasm binary] [arguments]"),process.exit(1));const e=new Go;WebAssembly.instantiate(fs.readFileSync(process.argv[2]),e.importObject).then(async t=>{let n=await e.run(t.instance);process.exit(n)}).catch(e=>{console.error(e),process.exit(1)})}})();export default function(e){return new Promise(t=>{const n=new Go,s=e=>{const s=e.instance;global.wfa=s,n.run(s),t()};"instantiateStreaming"in WebAssembly?WebAssembly.instantiateStreaming(fetch(e),n.importObject).then(function(e){s(e)}):fetch(e).then(e=>e.arrayBuffer()).then(e=>WebAssembly.instantiate(e,n.importObject).then(function(e){s(e)}))})} \ No newline at end of file +// 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. +// +// This file has been modified for use by the TinyGo compiler. + +(() => { + // Map multiple JavaScript environments to a single common API, + // preferring web standards over Node.js API. + // + // Environments considered: + // - Browsers + // - Node.js + // - Electron + // - Parcel + + if (typeof global !== "undefined") { + // global already exists + } else 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)"); + } + + if (!global.require && typeof require !== "undefined") { + global.require = require; + } + + if (!global.fs && global.require) { + global.fs = require("node:fs"); + } + + 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) { + const nodeCrypto = require("node:crypto"); + global.crypto = { + getRandomValues(b) { + nodeCrypto.randomFillSync(b); + }, + }; + } + + if (!global.performance) { + global.performance = { + now() { + const [sec, nsec] = process.hrtime(); + return sec * 1000 + nsec / 1000000; + }, + }; + } + + if (!global.TextEncoder) { + global.TextEncoder = require("node:util").TextEncoder; + } + + if (!global.TextDecoder) { + global.TextDecoder = require("node:util").TextDecoder; + } + + // End of polyfills for common API. + + const encoder = new TextEncoder("utf-8"); + const decoder = new TextDecoder("utf-8"); + let reinterpretBuf = new DataView(new ArrayBuffer(8)); + var logLine = []; + const wasmExit = {}; // thrown to exit via proc_exit (not an error) + + global.Go = class { + constructor() { + this._callbackTimeouts = new Map(); + this._nextCallbackTimeoutID = 1; + + const mem = () => { + // The buffer may change when requesting more memory. + return new DataView(this._inst.exports.memory.buffer); + } + + const unboxValue = (v_ref) => { + reinterpretBuf.setBigInt64(0, v_ref, true); + const f = reinterpretBuf.getFloat64(0, true); + if (f === 0) { + return undefined; + } + if (!isNaN(f)) { + return f; + } + + const id = v_ref & 0xffffffffn; + return this._values[id]; + } + + + const loadValue = (addr) => { + let v_ref = mem().getBigUint64(addr, true); + return unboxValue(v_ref); + } + + const boxValue = (v) => { + const nanHead = 0x7FF80000n; + + if (typeof v === "number") { + if (isNaN(v)) { + return nanHead << 32n; + } + if (v === 0) { + return (nanHead << 32n) | 1n; + } + reinterpretBuf.setFloat64(0, v, true); + return reinterpretBuf.getBigInt64(0, true); + } + + switch (v) { + case undefined: + return 0n; + case null: + return (nanHead << 32n) | 2n; + case true: + return (nanHead << 32n) | 3n; + case false: + return (nanHead << 32n) | 4n; + } + + let id = this._ids.get(v); + if (id === undefined) { + id = this._idPool.pop(); + if (id === undefined) { + id = BigInt(this._values.length); + } + this._values[id] = v; + this._goRefCounts[id] = 0; + this._ids.set(v, id); + } + this._goRefCounts[id]++; + let typeFlag = 1n; + switch (typeof v) { + case "string": + typeFlag = 2n; + break; + case "symbol": + typeFlag = 3n; + break; + case "function": + typeFlag = 4n; + break; + } + return id | ((nanHead | typeFlag) << 32n); + } + + const storeValue = (addr, v) => { + let v_ref = boxValue(v); + mem().setBigUint64(addr, v_ref, true); + } + + const loadSlice = (array, len, cap) => { + return new Uint8Array(this._inst.exports.memory.buffer, array, len); + } + + const loadSliceOfValues = (array, len, cap) => { + const a = new Array(len); + for (let i = 0; i < len; i++) { + a[i] = loadValue(array + i * 8); + } + return a; + } + + const loadString = (ptr, len) => { + return decoder.decode(new DataView(this._inst.exports.memory.buffer, ptr, len)); + } + + const timeOrigin = Date.now() - performance.now(); + this.importObject = { + wasi_snapshot_preview1: { + // https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_write + fd_write: function(fd, iovs_ptr, iovs_len, nwritten_ptr) { + let nwritten = 0; + if (fd == 1) { + for (let iovs_i=0; iovs_i 0, // dummy + fd_fdstat_get: () => 0, // dummy + fd_seek: () => 0, // dummy + proc_exit: (code) => { + this.exited = true; + this.exitCode = code; + this._resolveExitPromise(); + throw wasmExit; + }, + random_get: (bufPtr, bufLen) => { + crypto.getRandomValues(loadSlice(bufPtr, bufLen)); + return 0; + }, + }, + gojs: { + // func ticks() int64 + "runtime.ticks": () => { + return BigInt((timeOrigin + performance.now()) * 1e6); + }, + + // func sleepTicks(timeout int64) + "runtime.sleepTicks": (timeout) => { + // Do not sleep, only reactivate scheduler after the given timeout. + setTimeout(() => { + if (this.exited) return; + try { + this._inst.exports.go_scheduler(); + } catch (e) { + if (e !== wasmExit) throw e; + } + }, Number(timeout)/1e6); + }, + + // func finalizeRef(v ref) + "syscall/js.finalizeRef": (v_ref) => { + // Note: TinyGo does not support finalizers so this is only called + // for one specific case, by js.go:jsString. and can/might leak memory. + const id = v_ref & 0xffffffffn; + if (this._goRefCounts?.[id] !== undefined) { + 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); + } + } else { + console.error("syscall/js.finalizeRef: unknown id", id); + } + }, + + // func stringVal(value string) ref + "syscall/js.stringVal": (value_ptr, value_len) => { + value_ptr >>>= 0; + const s = loadString(value_ptr, value_len); + return boxValue(s); + }, + + // func valueGet(v ref, p string) ref + "syscall/js.valueGet": (v_ref, p_ptr, p_len) => { + let prop = loadString(p_ptr, p_len); + let v = unboxValue(v_ref); + let result = Reflect.get(v, prop); + return boxValue(result); + }, + + // func valueSet(v ref, p string, x ref) + "syscall/js.valueSet": (v_ref, p_ptr, p_len, x_ref) => { + const v = unboxValue(v_ref); + const p = loadString(p_ptr, p_len); + const x = unboxValue(x_ref); + Reflect.set(v, p, x); + }, + + // func valueDelete(v ref, p string) + "syscall/js.valueDelete": (v_ref, p_ptr, p_len) => { + const v = unboxValue(v_ref); + const p = loadString(p_ptr, p_len); + Reflect.deleteProperty(v, p); + }, + + // func valueIndex(v ref, i int) ref + "syscall/js.valueIndex": (v_ref, i) => { + return boxValue(Reflect.get(unboxValue(v_ref), i)); + }, + + // valueSetIndex(v ref, i int, x ref) + "syscall/js.valueSetIndex": (v_ref, i, x_ref) => { + Reflect.set(unboxValue(v_ref), i, unboxValue(x_ref)); + }, + + // func valueCall(v ref, m string, args []ref) (ref, bool) + "syscall/js.valueCall": (ret_addr, v_ref, m_ptr, m_len, args_ptr, args_len, args_cap) => { + const v = unboxValue(v_ref); + const name = loadString(m_ptr, m_len); + const args = loadSliceOfValues(args_ptr, args_len, args_cap); + try { + const m = Reflect.get(v, name); + storeValue(ret_addr, Reflect.apply(m, v, args)); + mem().setUint8(ret_addr + 8, 1); + } catch (err) { + storeValue(ret_addr, err); + mem().setUint8(ret_addr + 8, 0); + } + }, + + // func valueInvoke(v ref, args []ref) (ref, bool) + "syscall/js.valueInvoke": (ret_addr, v_ref, args_ptr, args_len, args_cap) => { + try { + const v = unboxValue(v_ref); + const args = loadSliceOfValues(args_ptr, args_len, args_cap); + storeValue(ret_addr, Reflect.apply(v, undefined, args)); + mem().setUint8(ret_addr + 8, 1); + } catch (err) { + storeValue(ret_addr, err); + mem().setUint8(ret_addr + 8, 0); + } + }, + + // func valueNew(v ref, args []ref) (ref, bool) + "syscall/js.valueNew": (ret_addr, v_ref, args_ptr, args_len, args_cap) => { + const v = unboxValue(v_ref); + const args = loadSliceOfValues(args_ptr, args_len, args_cap); + try { + storeValue(ret_addr, Reflect.construct(v, args)); + mem().setUint8(ret_addr + 8, 1); + } catch (err) { + storeValue(ret_addr, err); + mem().setUint8(ret_addr+ 8, 0); + } + }, + + // func valueLength(v ref) int + "syscall/js.valueLength": (v_ref) => { + return unboxValue(v_ref).length; + }, + + // valuePrepareString(v ref) (ref, int) + "syscall/js.valuePrepareString": (ret_addr, v_ref) => { + const s = String(unboxValue(v_ref)); + const str = encoder.encode(s); + storeValue(ret_addr, str); + mem().setInt32(ret_addr + 8, str.length, true); + }, + + // valueLoadString(v ref, b []byte) + "syscall/js.valueLoadString": (v_ref, slice_ptr, slice_len, slice_cap) => { + const str = unboxValue(v_ref); + loadSlice(slice_ptr, slice_len, slice_cap).set(str); + }, + + // func valueInstanceOf(v ref, t ref) bool + "syscall/js.valueInstanceOf": (v_ref, t_ref) => { + return unboxValue(v_ref) instanceof unboxValue(t_ref); + }, + + // func copyBytesToGo(dst []byte, src ref) (int, bool) + "syscall/js.copyBytesToGo": (ret_addr, dest_addr, dest_len, dest_cap, src_ref) => { + let num_bytes_copied_addr = ret_addr; + let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable + + const dst = loadSlice(dest_addr, dest_len); + const src = unboxValue(src_ref); + if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) { + mem().setUint8(returned_status_addr, 0); // Return "not ok" status + return; + } + const toCopy = src.subarray(0, dst.length); + dst.set(toCopy); + mem().setUint32(num_bytes_copied_addr, toCopy.length, true); + mem().setUint8(returned_status_addr, 1); // Return "ok" status + }, + + // copyBytesToJS(dst ref, src []byte) (int, bool) + // Originally copied from upstream Go project, then modified: + // https://github.com/golang/go/blob/3f995c3f3b43033013013e6c7ccc93a9b1411ca9/misc/wasm/wasm_exec.js#L404-L416 + "syscall/js.copyBytesToJS": (ret_addr, dst_ref, src_addr, src_len, src_cap) => { + let num_bytes_copied_addr = ret_addr; + let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable + + const dst = unboxValue(dst_ref); + const src = loadSlice(src_addr, src_len); + if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) { + mem().setUint8(returned_status_addr, 0); // Return "not ok" status + return; + } + const toCopy = src.subarray(0, dst.length); + dst.set(toCopy); + mem().setUint32(num_bytes_copied_addr, toCopy.length, true); + mem().setUint8(returned_status_addr, 1); // Return "ok" status + }, + } + }; + + // Go 1.20 uses 'env'. Go 1.21 uses 'gojs'. + // For compatibility, we use both as long as Go 1.20 is supported. + this.importObject.env = this.importObject.gojs; + } + + async run(instance) { + this._inst = instance; + this._values = [ // JS values that Go currently has references to, indexed by reference id + NaN, + 0, + null, + true, + false, + global, + this, + ]; + this._goRefCounts = []; // 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 + this._idPool = []; // unused ids that have been garbage collected + this.exited = false; // whether the Go program has exited + this.exitCode = 0; + + if (this._inst.exports._start) { + let exitPromise = new Promise((resolve, reject) => { + this._resolveExitPromise = resolve; + }); + + // Run program, but catch the wasmExit exception that's thrown + // to return back here. + try { + this._inst.exports._start(); + } catch (e) { + if (e !== wasmExit) throw e; + } + + await exitPromise; + return this.exitCode; + } else { + this._inst.exports._initialize(); + } + } + + _resume() { + if (this.exited) { + throw new Error("Go program has already exited"); + } + try { + this._inst.exports.resume(); + } catch (e) { + if (e !== wasmExit) throw e; + } + 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; + }; + } + } + + if ( + global.require && + global.require.main === module && + global.process && + global.process.versions && + !global.process.versions.electron + ) { + if (process.argv.length != 3) { + console.error("usage: go_js_wasm_exec [wasm binary] [arguments]"); + process.exit(1); + } + + const go = new Go(); + WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then(async (result) => { + let exitCode = await go.run(result.instance); + process.exit(exitCode); + }).catch((err) => { + console.error(err); + process.exit(1); + }); + } +})(); + +// wasm setup code +export default function init (path) { + return new Promise ((res) => { + const go = new Go(); + const run = (obj) => { + const wasm = obj.instance; + global.wfa = wasm + go.run(wasm); + res() + } + if ('instantiateStreaming' in WebAssembly) { + WebAssembly.instantiateStreaming(fetch(path), go.importObject).then(function (obj) { + run(obj) + }) + } else { + fetch(path).then(resp => + resp.arrayBuffer() + ).then(bytes => + WebAssembly.instantiate(bytes, go.importObject).then(function (obj) { + run(obj) + }) + ) + } + }) +} \ No newline at end of file