diff --git a/_examples/assets/polyfill_performance.js b/_examples/assets/polyfill_performance.js deleted file mode 100644 index 8096d10..0000000 --- a/_examples/assets/polyfill_performance.js +++ /dev/null @@ -1,36 +0,0 @@ -// @license http://opensource.org/licenses/MIT -// copyright Paul Irish 2015 - - -// Date.now() is supported everywhere except IE8. For IE8 we use the Date.now polyfill -// github.com/Financial-Times/polyfill-service/blob/master/polyfills/Date.now/polyfill.js -// as Safari 6 doesn't have support for NavigationTiming, we use a Date.now() timestamp for relative values - -// if you want values similar to what you'd get with real perf.now, place this towards the head of the page -// but in reality, you're just getting the delta between now() calls, so it's not terribly important where it's placed - - -(function(){ - - if ("performance" in globalThis == false) { - globalThis.performance = {}; - } - - Date.now = (Date.now || function () { // thanks IE8 - return new Date().getTime(); - }); - - if ("now" in globalThis.performance == false){ - - var nowOffset = Date.now(); - - if (performance.timing && performance.timing.navigationStart){ - nowOffset = performance.timing.navigationStart - } - - globalThis.performance.now = function now(){ - return Date.now() - nowOffset; - } - } - -})(); diff --git a/_examples/assets/shim.mjs b/_examples/assets/shim.mjs deleted file mode 100644 index 7112ee7..0000000 --- a/_examples/assets/shim.mjs +++ /dev/null @@ -1,24 +0,0 @@ -import "./polyfill_performance.js"; -import "./wasm_exec.js"; - -const go = new Go(); - -let mod; - -export function init(m) { - mod = m; -} - -async function run() { - const readyPromise = new Promise((resolve) => { - globalThis.ready = resolve; - }); - const instance = new WebAssembly.Instance(mod, go.importObject); - go.run(instance); - await readyPromise; -} - -export async function fetch(req, env, ctx) { - await run(); - return handleRequest(req, { env, ctx }); -} diff --git a/_examples/assets/wasm_exec.js b/_examples/assets/wasm_exec.js deleted file mode 100644 index 3920013..0000000 --- a/_examples/assets/wasm_exec.js +++ /dev/null @@ -1,543 +0,0 @@ -// 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("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("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("util").TextEncoder; - } - - if (!global.TextDecoder) { - global.TextDecoder = require("util").TextDecoder; - } - */ - - // End of polyfills for common API. - - const encoder = new TextEncoder("utf-8"); - const decoder = new TextDecoder("utf-8"); - var logLine = []; - - 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 setInt64 = (addr, v) => { - mem().setUint32(addr + 0, v, true); - mem().setUint32(addr + 4, Math.floor(v / 4294967296), true); - } - - const getInt64 = (addr) => { - const low = mem().getUint32(addr + 0, true); - const high = mem().getInt32(addr + 4, true); - return low + high * 4294967296; - } - - const loadValue = (addr) => { - const f = mem().getFloat64(addr, true); - if (f === 0) { - return undefined; - } - if (!isNaN(f)) { - return f; - } - - const id = mem().getUint32(addr, true); - return this._values[id]; - } - - const storeValue = (addr, v) => { - const nanHead = 0x7FF80000; - - if (typeof v === "number") { - if (isNaN(v)) { - mem().setUint32(addr + 4, nanHead, true); - mem().setUint32(addr, 0, true); - return; - } - if (v === 0) { - mem().setUint32(addr + 4, nanHead, true); - mem().setUint32(addr, 1, true); - return; - } - mem().setFloat64(addr, v, true); - return; - } - - switch (v) { - case undefined: - mem().setFloat64(addr, 0, true); - return; - case null: - mem().setUint32(addr + 4, nanHead, true); - mem().setUint32(addr, 2, true); - return; - case true: - mem().setUint32(addr + 4, nanHead, true); - mem().setUint32(addr, 3, true); - return; - case false: - mem().setUint32(addr + 4, nanHead, true); - mem().setUint32(addr, 4, 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 = 1; - switch (typeof v) { - case "string": - typeFlag = 2; - break; - case "symbol": - typeFlag = 3; - break; - case "function": - typeFlag = 4; - break; - } - mem().setUint32(addr + 4, nanHead | typeFlag, true); - mem().setUint32(addr, id, 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) => { - if (global.process) { - // Node.js - process.exit(code); - } else { - // Can't exit in a browser. - throw 'trying to exit with code ' + code; - } - }, - random_get: (bufPtr, bufLen) => { - crypto.getRandomValues(loadSlice(bufPtr, bufLen)); - return 0; - }, - }, - env: { - // func ticks() float64 - "runtime.ticks": () => { - return timeOrigin + performance.now(); - }, - - // func sleepTicks(timeout float64) - "runtime.sleepTicks": (timeout) => { - // Do not sleep, only reactivate scheduler after the given timeout. - setTimeout(this._inst.exports.go_scheduler, timeout); - }, - - // func finalizeRef(v ref) - "syscall/js.finalizeRef": (sp) => { - // Note: TinyGo does not support finalizers so this should never be - // called. - // console.error('syscall/js.finalizeRef not implemented'); - }, - - // func stringVal(value string) ref - "syscall/js.stringVal": (ret_ptr, value_ptr, value_len) => { - const s = loadString(value_ptr, value_len); - storeValue(ret_ptr, s); - }, - - // func valueGet(v ref, p string) ref - "syscall/js.valueGet": (retval, v_addr, p_ptr, p_len) => { - let prop = loadString(p_ptr, p_len); - let value = loadValue(v_addr); - let result = Reflect.get(value, prop); - storeValue(retval, result); - }, - - // func valueSet(v ref, p string, x ref) - "syscall/js.valueSet": (v_addr, p_ptr, p_len, x_addr) => { - const v = loadValue(v_addr); - const p = loadString(p_ptr, p_len); - const x = loadValue(x_addr); - Reflect.set(v, p, x); - }, - - // func valueDelete(v ref, p string) - "syscall/js.valueDelete": (v_addr, p_ptr, p_len) => { - const v = loadValue(v_addr); - const p = loadString(p_ptr, p_len); - Reflect.deleteProperty(v, p); - }, - - // func valueIndex(v ref, i int) ref - "syscall/js.valueIndex": (ret_addr, v_addr, i) => { - storeValue(ret_addr, Reflect.get(loadValue(v_addr), i)); - }, - - // valueSetIndex(v ref, i int, x ref) - "syscall/js.valueSetIndex": (v_addr, i, x_addr) => { - Reflect.set(loadValue(v_addr), i, loadValue(x_addr)); - }, - - // func valueCall(v ref, m string, args []ref) (ref, bool) - "syscall/js.valueCall": (ret_addr, v_addr, m_ptr, m_len, args_ptr, args_len, args_cap) => { - const v = loadValue(v_addr); - 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_addr, args_ptr, args_len, args_cap) => { - try { - const v = loadValue(v_addr); - 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_addr, args_ptr, args_len, args_cap) => { - const v = loadValue(v_addr); - 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_addr) => { - return loadValue(v_addr).length; - }, - - // valuePrepareString(v ref) (ref, int) - "syscall/js.valuePrepareString": (ret_addr, v_addr) => { - const s = String(loadValue(v_addr)); - const str = encoder.encode(s); - storeValue(ret_addr, str); - setInt64(ret_addr + 8, str.length); - }, - - // valueLoadString(v ref, b []byte) - "syscall/js.valueLoadString": (v_addr, slice_ptr, slice_len, slice_cap) => { - const str = loadValue(v_addr); - loadSlice(slice_ptr, slice_len, slice_cap).set(str); - }, - - // func valueInstanceOf(v ref, t ref) bool - "syscall/js.valueInstanceOf": (v_addr, t_addr) => { - return loadValue(v_addr) instanceof loadValue(t_addr); - }, - - // func copyBytesToGo(dst []byte, src ref) (int, bool) - "syscall/js.copyBytesToGo": (ret_addr, dest_addr, dest_len, dest_cap, source_addr) => { - 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 = loadValue(source_addr); - 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); - setInt64(num_bytes_copied_addr, toCopy.length); - 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, dest_addr, source_addr, source_len, source_cap) => { - let num_bytes_copied_addr = ret_addr; - let returned_status_addr = ret_addr + 4; // Address of returned boolean status variable - - const dst = loadValue(dest_addr); - const src = loadSlice(source_addr, source_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); - setInt64(num_bytes_copied_addr, toCopy.length); - mem().setUint8(returned_status_addr, 1); // Return "ok" status - }, - } - }; - } - - 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 - - const mem = new DataView(this._inst.exports.memory.buffer) - - while (true) { - const callbackPromise = new Promise((resolve) => { - this._resolveCallbackPromise = () => { - if (this.exited) { - throw new Error("bad callback: Go program has already exited"); - } - setTimeout(resolve, 0); // make sure it is asynchronous - }; - }); - this._inst.exports._start(); - if (this.exited) { - break; - } - await callbackPromise; - } - } - - _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; - }; - } - } - - 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); - }); - } -})(); \ No newline at end of file diff --git a/_examples/durable-object-counter/Makefile b/_examples/durable-object-counter/Makefile index ff8d860..019492c 100644 --- a/_examples/durable-object-counter/Makefile +++ b/_examples/durable-object-counter/Makefile @@ -4,7 +4,7 @@ dev: .PHONY: build build: - mkdir -p build + go run ../../cmd/workers-assets-gen tinygo build -o ./build/app.wasm -target wasm -no-debug ./... .PHONY: deploy diff --git a/_examples/durable-object-counter/worker.mjs b/_examples/durable-object-counter/worker.mjs index 751e9e0..1b7a277 100644 --- a/_examples/durable-object-counter/worker.mjs +++ b/_examples/durable-object-counter/worker.mjs @@ -1,9 +1,5 @@ -import * as imports from "../assets/shim.mjs"; -import mod from "./build/app.wasm"; - -imports.init(mod); - -export default { fetch: imports.fetch } +// export auto-generated entrypoint script +export { default } from "./build/worker.mjs"; // Durable Object @@ -15,7 +11,7 @@ export class Counter { // Handle HTTP requests from clients. async fetch(request) { // Apply requested action. - let url = new URL(request.url); + const url = new URL(request.url); // Durable Object storage is automatically cached in-memory, so reading the // same key every request is fast. (That said, you could also store the