Commit ebcf43c9 authored by Steven's avatar Steven

chore: update gomark.wasm

parent cfb50f19
// Copyright 2018 The Go Authors. All rights reserved. // Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
//
"use strict"; // This file has been modified for use by the TinyGo compiler.
(() => { (() => {
const enosys = () => { // Map multiple JavaScript environments to a single common API,
const err = new Error("not implemented"); // preferring web standards over Node.js API.
err.code = "ENOSYS"; //
return err; // Environments considered:
}; // - Browsers
// - Node.js
if (!globalThis.fs) { // - Electron
let outputBuf = ""; // - Parcel
globalThis.fs = {
constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused if (typeof global !== "undefined") {
writeSync(fd, buf) { // global already exists
outputBuf += decoder.decode(buf); } else if (typeof window !== "undefined") {
const nl = outputBuf.lastIndexOf("\n"); window.global = window;
if (nl != -1) { } else if (typeof self !== "undefined") {
console.log(outputBuf.substring(0, nl)); self.global = self;
outputBuf = outputBuf.substring(nl + 1); } else {
} throw new Error("cannot export Go (neither global, window nor self is defined)");
return buf.length; }
},
write(fd, buf, offset, length, position, callback) { if (!global.require && typeof require !== "undefined") {
if (offset !== 0 || length !== buf.length || position !== null) { global.require = require;
callback(enosys()); }
return;
} if (!global.fs && global.require) {
const n = this.writeSync(fd, buf); global.fs = require("fs");
callback(null, n); }
},
chmod(path, mode, callback) { callback(enosys()); }, const enosys = () => {
chown(path, uid, gid, callback) { callback(enosys()); }, const err = new Error("not implemented");
close(fd, callback) { callback(enosys()); }, err.code = "ENOSYS";
fchmod(fd, mode, callback) { callback(enosys()); }, return err;
fchown(fd, uid, gid, callback) { callback(enosys()); }, };
fstat(fd, callback) { callback(enosys()); },
fsync(fd, callback) { callback(null); }, if (!global.fs) {
ftruncate(fd, length, callback) { callback(enosys()); }, let outputBuf = "";
lchown(path, uid, gid, callback) { callback(enosys()); }, global.fs = {
link(path, link, callback) { callback(enosys()); }, constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused
lstat(path, callback) { callback(enosys()); }, writeSync(fd, buf) {
mkdir(path, perm, callback) { callback(enosys()); }, outputBuf += decoder.decode(buf);
open(path, flags, mode, callback) { callback(enosys()); }, const nl = outputBuf.lastIndexOf("\n");
read(fd, buffer, offset, length, position, callback) { callback(enosys()); }, if (nl != -1) {
readdir(path, callback) { callback(enosys()); }, console.log(outputBuf.substr(0, nl));
readlink(path, callback) { callback(enosys()); }, outputBuf = outputBuf.substr(nl + 1);
rename(from, to, callback) { callback(enosys()); }, }
rmdir(path, callback) { callback(enosys()); }, return buf.length;
stat(path, callback) { callback(enosys()); }, },
symlink(path, link, callback) { callback(enosys()); }, write(fd, buf, offset, length, position, callback) {
truncate(path, length, callback) { callback(enosys()); }, if (offset !== 0 || length !== buf.length || position !== null) {
unlink(path, callback) { callback(enosys()); }, callback(enosys());
utimes(path, atime, mtime, callback) { callback(enosys()); }, return;
}; }
} const n = this.writeSync(fd, buf);
callback(null, n);
if (!globalThis.process) { },
globalThis.process = { chmod(path, mode, callback) {
getuid() { return -1; }, callback(enosys());
getgid() { return -1; }, },
geteuid() { return -1; }, chown(path, uid, gid, callback) {
getegid() { return -1; }, callback(enosys());
getgroups() { throw enosys(); }, },
pid: -1, close(fd, callback) {
ppid: -1, callback(enosys());
umask() { throw enosys(); }, },
cwd() { throw enosys(); }, fchmod(fd, mode, callback) {
chdir() { throw enosys(); }, callback(enosys());
} },
} fchown(fd, uid, gid, callback) {
callback(enosys());
if (!globalThis.crypto) { },
throw new Error("globalThis.crypto is not available, polyfill required (crypto.getRandomValues only)"); fstat(fd, callback) {
} callback(enosys());
},
if (!globalThis.performance) { fsync(fd, callback) {
throw new Error("globalThis.performance is not available, polyfill required (performance.now only)"); callback(null);
} },
ftruncate(fd, length, callback) {
if (!globalThis.TextEncoder) { callback(enosys());
throw new Error("globalThis.TextEncoder is not available, polyfill required"); },
} lchown(path, uid, gid, callback) {
callback(enosys());
if (!globalThis.TextDecoder) { },
throw new Error("globalThis.TextDecoder is not available, polyfill required"); link(path, link, callback) {
} callback(enosys());
},
const encoder = new TextEncoder("utf-8"); lstat(path, callback) {
const decoder = new TextDecoder("utf-8"); callback(enosys());
},
globalThis.Go = class { mkdir(path, perm, callback) {
constructor() { callback(enosys());
this.argv = ["js"]; },
this.env = {}; open(path, flags, mode, callback) {
this.exit = (code) => { callback(enosys());
if (code !== 0) { },
console.warn("exit code:", code); read(fd, buffer, offset, length, position, callback) {
} callback(enosys());
}; },
this._exitPromise = new Promise((resolve) => { readdir(path, callback) {
this._resolveExitPromise = resolve; callback(enosys());
}); },
this._pendingEvent = null; readlink(path, callback) {
this._scheduledTimeouts = new Map(); callback(enosys());
this._nextCallbackTimeoutID = 1; },
rename(from, to, callback) {
const setInt64 = (addr, v) => { callback(enosys());
this.mem.setUint32(addr + 0, v, true); },
this.mem.setUint32(addr + 4, Math.floor(v / 4294967296), true); rmdir(path, callback) {
} callback(enosys());
},
const setInt32 = (addr, v) => { stat(path, callback) {
this.mem.setUint32(addr + 0, v, true); callback(enosys());
} },
symlink(path, link, callback) {
const getInt64 = (addr) => { callback(enosys());
const low = this.mem.getUint32(addr + 0, true); },
const high = this.mem.getInt32(addr + 4, true); truncate(path, length, callback) {
return low + high * 4294967296; callback(enosys());
} },
unlink(path, callback) {
const loadValue = (addr) => { callback(enosys());
const f = this.mem.getFloat64(addr, true); },
if (f === 0) { utimes(path, atime, mtime, callback) {
return undefined; callback(enosys());
} },
if (!isNaN(f)) { };
return f; }
}
if (!global.process) {
const id = this.mem.getUint32(addr, true); global.process = {
return this._values[id]; getuid() {
} return -1;
},
const storeValue = (addr, v) => { getgid() {
const nanHead = 0x7FF80000; return -1;
},
if (typeof v === "number" && v !== 0) { geteuid() {
if (isNaN(v)) { return -1;
this.mem.setUint32(addr + 4, nanHead, true); },
this.mem.setUint32(addr, 0, true); getegid() {
return; return -1;
} },
this.mem.setFloat64(addr, v, true); getgroups() {
return; throw enosys();
} },
pid: -1,
if (v === undefined) { ppid: -1,
this.mem.setFloat64(addr, 0, true); umask() {
return; throw enosys();
} },
cwd() {
let id = this._ids.get(v); throw enosys();
if (id === undefined) { },
id = this._idPool.pop(); chdir() {
if (id === undefined) { throw enosys();
id = this._values.length; },
} };
this._values[id] = v; }
this._goRefCounts[id] = 0;
this._ids.set(v, id); if (!global.crypto) {
} const nodeCrypto = require("crypto");
this._goRefCounts[id]++; global.crypto = {
let typeFlag = 0; getRandomValues(b) {
switch (typeof v) { nodeCrypto.randomFillSync(b);
case "object": },
if (v !== null) { };
typeFlag = 1; }
}
break; if (!global.performance) {
case "string": global.performance = {
typeFlag = 2; now() {
break; const [sec, nsec] = process.hrtime();
case "symbol": return sec * 1000 + nsec / 1000000;
typeFlag = 3; },
break; };
case "function": }
typeFlag = 4;
break; if (!global.TextEncoder) {
} global.TextEncoder = require("util").TextEncoder;
this.mem.setUint32(addr + 4, nanHead | typeFlag, true); }
this.mem.setUint32(addr, id, true);
} if (!global.TextDecoder) {
global.TextDecoder = require("util").TextDecoder;
const loadSlice = (addr) => { }
const array = getInt64(addr + 0);
const len = getInt64(addr + 8); // End of polyfills for common API.
return new Uint8Array(this._inst.exports.mem.buffer, array, len);
} const encoder = new TextEncoder("utf-8");
const decoder = new TextDecoder("utf-8");
const loadSliceOfValues = (addr) => { let reinterpretBuf = new DataView(new ArrayBuffer(8));
const array = getInt64(addr + 0); var logLine = [];
const len = getInt64(addr + 8);
const a = new Array(len); global.Go = class {
for (let i = 0; i < len; i++) { constructor() {
a[i] = loadValue(array + i * 8); this._callbackTimeouts = new Map();
} this._nextCallbackTimeoutID = 1;
return a;
} const mem = () => {
// The buffer may change when requesting more memory.
const loadString = (addr) => { return new DataView(this._inst.exports.memory.buffer);
const saddr = getInt64(addr + 0); };
const len = getInt64(addr + 8);
return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len)); const unboxValue = (v_ref) => {
} reinterpretBuf.setBigInt64(0, v_ref, true);
const f = reinterpretBuf.getFloat64(0, true);
const timeOrigin = Date.now() - performance.now(); if (f === 0) {
this.importObject = { return undefined;
_gotest: { }
add: (a, b) => a + b, if (!isNaN(f)) {
}, return f;
gojs: { }
// 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 const id = v_ref & 0xffffffffn;
// function. A goroutine can switch to a new stack if the current stack is too small (see morestack function). return this._values[id];
// This changes the SP, thus we have to update the SP used by the imported function. };
// func wasmExit(code int32) const loadValue = (addr) => {
"runtime.wasmExit": (sp) => { let v_ref = mem().getBigUint64(addr, true);
sp >>>= 0; return unboxValue(v_ref);
const code = this.mem.getInt32(sp + 8, true); };
this.exited = true;
delete this._inst; const boxValue = (v) => {
delete this._values; const nanHead = 0x7ff80000n;
delete this._goRefCounts;
delete this._ids; if (typeof v === "number") {
delete this._idPool; if (isNaN(v)) {
this.exit(code); return nanHead << 32n;
}, }
if (v === 0) {
// func wasmWrite(fd uintptr, p unsafe.Pointer, n int32) return (nanHead << 32n) | 1n;
"runtime.wasmWrite": (sp) => { }
sp >>>= 0; reinterpretBuf.setFloat64(0, v, true);
const fd = getInt64(sp + 8); return reinterpretBuf.getBigInt64(0, true);
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)); switch (v) {
}, case undefined:
return 0n;
// func resetMemoryDataView() case null:
"runtime.resetMemoryDataView": (sp) => { return (nanHead << 32n) | 2n;
sp >>>= 0; case true:
this.mem = new DataView(this._inst.exports.mem.buffer); return (nanHead << 32n) | 3n;
}, case false:
return (nanHead << 32n) | 4n;
// func nanotime1() int64 }
"runtime.nanotime1": (sp) => {
sp >>>= 0; let id = this._ids.get(v);
setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000); if (id === undefined) {
}, id = this._idPool.pop();
if (id === undefined) {
// func walltime() (sec int64, nsec int32) id = BigInt(this._values.length);
"runtime.walltime": (sp) => { }
sp >>>= 0; this._values[id] = v;
const msec = (new Date).getTime(); this._goRefCounts[id] = 0;
setInt64(sp + 8, msec / 1000); this._ids.set(v, id);
this.mem.setInt32(sp + 16, (msec % 1000) * 1000000, true); }
}, this._goRefCounts[id]++;
let typeFlag = 1n;
// func scheduleTimeoutEvent(delay int64) int32 switch (typeof v) {
"runtime.scheduleTimeoutEvent": (sp) => { case "string":
sp >>>= 0; typeFlag = 2n;
const id = this._nextCallbackTimeoutID; break;
this._nextCallbackTimeoutID++; case "symbol":
this._scheduledTimeouts.set(id, setTimeout( typeFlag = 3n;
() => { break;
this._resume(); case "function":
while (this._scheduledTimeouts.has(id)) { typeFlag = 4n;
// for some reason Go failed to register the timeout event, log and try again break;
// (temporary workaround for https://github.com/golang/go/issues/28975) }
console.warn("scheduleTimeoutEvent: missed timeout event"); return id | ((nanHead | typeFlag) << 32n);
this._resume(); };
}
}, const storeValue = (addr, v) => {
getInt64(sp + 8), let v_ref = boxValue(v);
)); mem().setBigUint64(addr, v_ref, true);
this.mem.setInt32(sp + 16, id, true); };
},
const loadSlice = (array, len, cap) => {
// func clearTimeoutEvent(id int32) return new Uint8Array(this._inst.exports.memory.buffer, array, len);
"runtime.clearTimeoutEvent": (sp) => { };
sp >>>= 0;
const id = this.mem.getInt32(sp + 8, true); const loadSliceOfValues = (array, len, cap) => {
clearTimeout(this._scheduledTimeouts.get(id)); const a = new Array(len);
this._scheduledTimeouts.delete(id); for (let i = 0; i < len; i++) {
}, a[i] = loadValue(array + i * 8);
}
// func getRandomData(r []byte) return a;
"runtime.getRandomData": (sp) => { };
sp >>>= 0;
crypto.getRandomValues(loadSlice(sp + 8)); const loadString = (ptr, len) => {
}, return decoder.decode(new DataView(this._inst.exports.memory.buffer, ptr, len));
};
// func finalizeRef(v ref)
"syscall/js.finalizeRef": (sp) => { const timeOrigin = Date.now() - performance.now();
sp >>>= 0; this.importObject = {
const id = this.mem.getUint32(sp + 8, true); wasi_snapshot_preview1: {
this._goRefCounts[id]--; // https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_write
if (this._goRefCounts[id] === 0) { fd_write: function (fd, iovs_ptr, iovs_len, nwritten_ptr) {
const v = this._values[id]; let nwritten = 0;
this._values[id] = null; if (fd == 1) {
this._ids.delete(v); for (let iovs_i = 0; iovs_i < iovs_len; iovs_i++) {
this._idPool.push(id); let iov_ptr = iovs_ptr + iovs_i * 8; // assuming wasm32
} let ptr = mem().getUint32(iov_ptr + 0, true);
}, let len = mem().getUint32(iov_ptr + 4, true);
nwritten += len;
// func stringVal(value string) ref for (let i = 0; i < len; i++) {
"syscall/js.stringVal": (sp) => { let c = mem().getUint8(ptr + i);
sp >>>= 0; if (c == 13) {
storeValue(sp + 24, loadString(sp + 8)); // CR
}, // ignore
} else if (c == 10) {
// func valueGet(v ref, p string) ref // LF
"syscall/js.valueGet": (sp) => { // write line
sp >>>= 0; let line = decoder.decode(new Uint8Array(logLine));
const result = Reflect.get(loadValue(sp + 8), loadString(sp + 16)); logLine = [];
sp = this._inst.exports.getsp() >>> 0; // see comment above console.log(line);
storeValue(sp + 32, result); } else {
}, logLine.push(c);
}
// func valueSet(v ref, p string, x ref) }
"syscall/js.valueSet": (sp) => { }
sp >>>= 0; } else {
Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32)); console.error("invalid file descriptor:", fd);
}, }
mem().setUint32(nwritten_ptr, nwritten, true);
// func valueDelete(v ref, p string) return 0;
"syscall/js.valueDelete": (sp) => { },
sp >>>= 0; fd_close: () => 0, // dummy
Reflect.deleteProperty(loadValue(sp + 8), loadString(sp + 16)); fd_fdstat_get: () => 0, // dummy
}, fd_seek: () => 0, // dummy
proc_exit: (code) => {
// func valueIndex(v ref, i int) ref if (global.process) {
"syscall/js.valueIndex": (sp) => { // Node.js
sp >>>= 0; process.exit(code);
storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16))); } else {
}, // Can't exit in a browser.
throw "trying to exit with code " + code;
// valueSetIndex(v ref, i int, x ref) }
"syscall/js.valueSetIndex": (sp) => { },
sp >>>= 0; random_get: (bufPtr, bufLen) => {
Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24)); crypto.getRandomValues(loadSlice(bufPtr, bufLen));
}, return 0;
},
// func valueCall(v ref, m string, args []ref) (ref, bool) },
"syscall/js.valueCall": (sp) => { gojs: {
sp >>>= 0; // func ticks() float64
try { "runtime.ticks": () => {
const v = loadValue(sp + 8); return timeOrigin + performance.now();
const m = Reflect.get(v, loadString(sp + 16)); },
const args = loadSliceOfValues(sp + 32);
const result = Reflect.apply(m, v, args); // func sleepTicks(timeout float64)
sp = this._inst.exports.getsp() >>> 0; // see comment above "runtime.sleepTicks": (timeout) => {
storeValue(sp + 56, result); // Do not sleep, only reactivate scheduler after the given timeout.
this.mem.setUint8(sp + 64, 1); setTimeout(this._inst.exports.go_scheduler, timeout);
} catch (err) { },
sp = this._inst.exports.getsp() >>> 0; // see comment above
storeValue(sp + 56, err); // func finalizeRef(v ref)
this.mem.setUint8(sp + 64, 0); "syscall/js.finalizeRef": (v_ref) => {
} // Note: TinyGo does not support finalizers so this should never be
}, // called.
},
// func valueInvoke(v ref, args []ref) (ref, bool)
"syscall/js.valueInvoke": (sp) => { // func stringVal(value string) ref
sp >>>= 0; "syscall/js.stringVal": (value_ptr, value_len) => {
try { const s = loadString(value_ptr, value_len);
const v = loadValue(sp + 8); return boxValue(s);
const args = loadSliceOfValues(sp + 16); },
const result = Reflect.apply(v, undefined, args);
sp = this._inst.exports.getsp() >>> 0; // see comment above // func valueGet(v ref, p string) ref
storeValue(sp + 40, result); "syscall/js.valueGet": (v_ref, p_ptr, p_len) => {
this.mem.setUint8(sp + 48, 1); let prop = loadString(p_ptr, p_len);
} catch (err) { let v = unboxValue(v_ref);
sp = this._inst.exports.getsp() >>> 0; // see comment above let result = Reflect.get(v, prop);
storeValue(sp + 40, err); return boxValue(result);
this.mem.setUint8(sp + 48, 0); },
}
}, // func valueSet(v ref, p string, x ref)
"syscall/js.valueSet": (v_ref, p_ptr, p_len, x_ref) => {
// func valueNew(v ref, args []ref) (ref, bool) const v = unboxValue(v_ref);
"syscall/js.valueNew": (sp) => { const p = loadString(p_ptr, p_len);
sp >>>= 0; const x = unboxValue(x_ref);
try { Reflect.set(v, p, x);
const v = loadValue(sp + 8); },
const args = loadSliceOfValues(sp + 16);
const result = Reflect.construct(v, args); // func valueDelete(v ref, p string)
sp = this._inst.exports.getsp() >>> 0; // see comment above "syscall/js.valueDelete": (v_ref, p_ptr, p_len) => {
storeValue(sp + 40, result); const v = unboxValue(v_ref);
this.mem.setUint8(sp + 48, 1); const p = loadString(p_ptr, p_len);
} catch (err) { Reflect.deleteProperty(v, p);
sp = this._inst.exports.getsp() >>> 0; // see comment above },
storeValue(sp + 40, err);
this.mem.setUint8(sp + 48, 0); // func valueIndex(v ref, i int) ref
} "syscall/js.valueIndex": (v_ref, i) => {
}, return boxValue(Reflect.get(unboxValue(v_ref), i));
},
// func valueLength(v ref) int
"syscall/js.valueLength": (sp) => { // valueSetIndex(v ref, i int, x ref)
sp >>>= 0; "syscall/js.valueSetIndex": (v_ref, i, x_ref) => {
setInt64(sp + 16, parseInt(loadValue(sp + 8).length)); Reflect.set(unboxValue(v_ref), i, unboxValue(x_ref));
}, },
// valuePrepareString(v ref) (ref, int) // func valueCall(v ref, m string, args []ref) (ref, bool)
"syscall/js.valuePrepareString": (sp) => { "syscall/js.valueCall": (ret_addr, v_ref, m_ptr, m_len, args_ptr, args_len, args_cap) => {
sp >>>= 0; const v = unboxValue(v_ref);
const str = encoder.encode(String(loadValue(sp + 8))); const name = loadString(m_ptr, m_len);
storeValue(sp + 16, str); const args = loadSliceOfValues(args_ptr, args_len, args_cap);
setInt64(sp + 24, str.length); try {
}, const m = Reflect.get(v, name);
storeValue(ret_addr, Reflect.apply(m, v, args));
// valueLoadString(v ref, b []byte) mem().setUint8(ret_addr + 8, 1);
"syscall/js.valueLoadString": (sp) => { } catch (err) {
sp >>>= 0; storeValue(ret_addr, err);
const str = loadValue(sp + 8); mem().setUint8(ret_addr + 8, 0);
loadSlice(sp + 16).set(str); }
}, },
// func valueInstanceOf(v ref, t ref) bool // func valueInvoke(v ref, args []ref) (ref, bool)
"syscall/js.valueInstanceOf": (sp) => { "syscall/js.valueInvoke": (ret_addr, v_ref, args_ptr, args_len, args_cap) => {
sp >>>= 0; try {
this.mem.setUint8(sp + 24, (loadValue(sp + 8) instanceof loadValue(sp + 16)) ? 1 : 0); const v = unboxValue(v_ref);
}, const args = loadSliceOfValues(args_ptr, args_len, args_cap);
storeValue(ret_addr, Reflect.apply(v, undefined, args));
// func copyBytesToGo(dst []byte, src ref) (int, bool) mem().setUint8(ret_addr + 8, 1);
"syscall/js.copyBytesToGo": (sp) => { } catch (err) {
sp >>>= 0; storeValue(ret_addr, err);
const dst = loadSlice(sp + 8); mem().setUint8(ret_addr + 8, 0);
const src = loadValue(sp + 32); }
if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) { },
this.mem.setUint8(sp + 48, 0);
return; // func valueNew(v ref, args []ref) (ref, bool)
} "syscall/js.valueNew": (ret_addr, v_ref, args_ptr, args_len, args_cap) => {
const toCopy = src.subarray(0, dst.length); const v = unboxValue(v_ref);
dst.set(toCopy); const args = loadSliceOfValues(args_ptr, args_len, args_cap);
setInt64(sp + 40, toCopy.length); try {
this.mem.setUint8(sp + 48, 1); storeValue(ret_addr, Reflect.construct(v, args));
}, mem().setUint8(ret_addr + 8, 1);
} catch (err) {
// func copyBytesToJS(dst ref, src []byte) (int, bool) storeValue(ret_addr, err);
"syscall/js.copyBytesToJS": (sp) => { mem().setUint8(ret_addr + 8, 0);
sp >>>= 0; }
const dst = loadValue(sp + 8); },
const src = loadSlice(sp + 16);
if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) { // func valueLength(v ref) int
this.mem.setUint8(sp + 48, 0); "syscall/js.valueLength": (v_ref) => {
return; return unboxValue(v_ref).length;
} },
const toCopy = src.subarray(0, dst.length);
dst.set(toCopy); // valuePrepareString(v ref) (ref, int)
setInt64(sp + 40, toCopy.length); "syscall/js.valuePrepareString": (ret_addr, v_ref) => {
this.mem.setUint8(sp + 48, 1); const s = String(unboxValue(v_ref));
}, const str = encoder.encode(s);
storeValue(ret_addr, str);
"debug": (value) => { mem().setInt32(ret_addr + 8, str.length, true);
console.log(value); },
},
} // 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);
async run(instance) { },
if (!(instance instanceof WebAssembly.Instance)) {
throw new Error("Go.run: WebAssembly.Instance expected"); // func valueInstanceOf(v ref, t ref) bool
} "syscall/js.valueInstanceOf": (v_ref, t_ref) => {
this._inst = instance; return unboxValue(v_ref) instanceof unboxValue(t_ref);
this.mem = new DataView(this._inst.exports.mem.buffer); },
this._values = [ // JS values that Go currently has references to, indexed by reference id
NaN, // func copyBytesToGo(dst []byte, src ref) (int, bool)
0, "syscall/js.copyBytesToGo": (ret_addr, dest_addr, dest_len, dest_cap, src_ref) => {
null, let num_bytes_copied_addr = ret_addr;
true, let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable
false,
globalThis, const dst = loadSlice(dest_addr, dest_len);
this, const src = unboxValue(src_ref);
]; if (!(src instanceof Uint8Array || src instanceof Uint8ClampedArray)) {
this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id mem().setUint8(returned_status_addr, 0); // Return "not ok" status
this._ids = new Map([ // mapping from JS values to reference ids return;
[0, 1], }
[null, 2], const toCopy = src.subarray(0, dst.length);
[true, 3], dst.set(toCopy);
[false, 4], mem().setUint32(num_bytes_copied_addr, toCopy.length, true);
[globalThis, 5], mem().setUint8(returned_status_addr, 1); // Return "ok" status
[this, 6], },
]);
this._idPool = []; // unused ids that have been garbage collected // copyBytesToJS(dst ref, src []byte) (int, bool)
this.exited = false; // whether the Go program has exited // Originally copied from upstream Go project, then modified:
// https://github.com/golang/go/blob/3f995c3f3b43033013013e6c7ccc93a9b1411ca9/misc/wasm/wasm_exec.js#L404-L416
// Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory. "syscall/js.copyBytesToJS": (ret_addr, dst_ref, src_addr, src_len, src_cap) => {
let offset = 4096; let num_bytes_copied_addr = ret_addr;
let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable
const strPtr = (str) => {
const ptr = offset; const dst = unboxValue(dst_ref);
const bytes = encoder.encode(str + "\0"); const src = loadSlice(src_addr, src_len);
new Uint8Array(this.mem.buffer, offset, bytes.length).set(bytes); if (!(dst instanceof Uint8Array || dst instanceof Uint8ClampedArray)) {
offset += bytes.length; mem().setUint8(returned_status_addr, 0); // Return "not ok" status
if (offset % 8 !== 0) { return;
offset += 8 - (offset % 8); }
} const toCopy = src.subarray(0, dst.length);
return ptr; dst.set(toCopy);
}; mem().setUint32(num_bytes_copied_addr, toCopy.length, true);
mem().setUint8(returned_status_addr, 1); // Return "ok" status
const argc = this.argv.length; },
},
const argvPtrs = []; };
this.argv.forEach((arg) => {
argvPtrs.push(strPtr(arg)); // Go 1.20 uses 'env'. Go 1.21 uses 'gojs'.
}); // For compatibility, we use both as long as Go 1.20 is supported.
argvPtrs.push(0); this.importObject.env = this.importObject.gojs;
}
const keys = Object.keys(this.env).sort();
keys.forEach((key) => { async run(instance) {
argvPtrs.push(strPtr(`${key}=${this.env[key]}`)); this._inst = instance;
}); this._values = [
argvPtrs.push(0); // JS values that Go currently has references to, indexed by reference id
NaN,
const argv = offset; 0,
argvPtrs.forEach((ptr) => { null,
this.mem.setUint32(offset, ptr, true); true,
this.mem.setUint32(offset + 4, 0, true); false,
offset += 8; global,
}); this,
];
// The linker guarantees global data starts from at least wasmMinDataAddr. this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id
// Keep in sync with cmd/link/internal/ld/data.go:wasmMinDataAddr. this._ids = new Map(); // mapping from JS values to reference ids
const wasmMinDataAddr = 4096 + 8192; this._idPool = []; // unused ids that have been garbage collected
if (offset >= wasmMinDataAddr) { this.exited = false; // whether the Go program has exited
throw new Error("total length of command line and environment variables exceeds limit");
} while (true) {
const callbackPromise = new Promise((resolve) => {
this._inst.exports.run(argc, argv); this._resolveCallbackPromise = () => {
if (this.exited) { if (this.exited) {
this._resolveExitPromise(); throw new Error("bad callback: Go program has already exited");
} }
await this._exitPromise; setTimeout(resolve, 0); // make sure it is asynchronous
} };
});
_resume() { this._inst.exports._start();
if (this.exited) { if (this.exited) {
throw new Error("Go program has already exited"); break;
} }
this._inst.exports.resume(); await callbackPromise;
if (this.exited) { }
this._resolveExitPromise(); }
}
} _resume() {
if (this.exited) {
_makeFuncWrapper(id) { throw new Error("Go program has already exited");
const go = this; }
return function () { this._inst.exports.resume();
const event = { id: id, this: this, args: arguments }; if (this.exited) {
go._pendingEvent = event; this._resolveExitPromise();
go._resume(); }
return event.result; }
};
} _makeFuncWrapper(id) {
} const go = this;
})(); return function () {
\ No newline at end of file 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((result) => {
return go.run(result.instance);
})
.catch((err) => {
console.error(err);
process.exit(1);
});
}
})();
...@@ -17,8 +17,7 @@ import theme from "./theme"; ...@@ -17,8 +17,7 @@ import theme from "./theme";
(async () => { (async () => {
const go = new window.Go(); const go = new window.Go();
const responsePromise = fetch(gomarkWasm); const { instance } = await WebAssembly.instantiateStreaming(fetch(gomarkWasm), go.importObject);
const { instance } = await WebAssembly.instantiateStreaming(responsePromise, go.importObject);
go.run(instance); go.run(instance);
const container = document.getElementById("root"); const container = document.getElementById("root");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment