mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-08-17 11:13:27 +00:00
wasm: patch wasm_exec.js and wasm_exec_node.js from Go 1.18+ (#5483)
* wasm: patch wasm_exec.js and wasm_exec_node.js from Go 1.18+ Port this commit https://github.com/golang/go/commit/680caf15355057ca84857a2a291b6f5c44e73329 removing polyfills from `wasm_exec.js`, now the environment is expected to provide all the required polyfills. `wasm_exec.js` now only provides stub fallbacks for globalThis.fs and globalThis.process. All NodeJS specific code is now in a separate file `wasm_exec_node.js` with its required polyfills. * feat: bump minimum node version to 22 Drops official support for NodeJS 18 for WASM by removing the provided polyfills in the `wasm_exec.js`. Now the environment is expected to provide the polyfill if it is running on older NodeJS versions The new minimum required version for WASM is NodeJS 22+. * chore: removed wrong comment `wasm_exec_node.js` no longer contains the polyfill for NodeJS 18
This commit is contained in:
@@ -209,7 +209,7 @@ jobs:
|
|||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v6
|
uses: actions/setup-node@v6
|
||||||
with:
|
with:
|
||||||
node-version: '18'
|
node-version: '22'
|
||||||
- name: Install wasmtime
|
- name: Install wasmtime
|
||||||
uses: bytecodealliance/actions/wasmtime/setup@v1
|
uses: bytecodealliance/actions/wasmtime/setup@v1
|
||||||
with:
|
with:
|
||||||
|
|||||||
+1
-1
@@ -304,7 +304,7 @@ wasi-cm:
|
|||||||
rsync -rv --delete --exclude go.mod --exclude '*_test.go' --exclude '*_json.go' --exclude '*.md' --exclude LICENSE $(shell go list -m -f {{.Dir}} $(WASM_TOOLS_MODULE)/cm)/ ./src/internal/cm
|
rsync -rv --delete --exclude go.mod --exclude '*_test.go' --exclude '*_json.go' --exclude '*.md' --exclude LICENSE $(shell go list -m -f {{.Dir}} $(WASM_TOOLS_MODULE)/cm)/ ./src/internal/cm
|
||||||
|
|
||||||
# Check for Node.js used during WASM tests.
|
# Check for Node.js used during WASM tests.
|
||||||
MIN_NODEJS_VERSION=18
|
MIN_NODEJS_VERSION=22
|
||||||
|
|
||||||
.PHONY: check-nodejs-version
|
.PHONY: check-nodejs-version
|
||||||
check-nodejs-version:
|
check-nodejs-version:
|
||||||
|
|||||||
+1
-1
@@ -27,5 +27,5 @@
|
|||||||
"src/runtime/asm_tinygowasm.S",
|
"src/runtime/asm_tinygowasm.S",
|
||||||
"src/runtime/gc_boehm.c"
|
"src/runtime/gc_boehm.c"
|
||||||
],
|
],
|
||||||
"emulator": "node {root}/targets/wasm_exec.js {}"
|
"emulator": "node {root}/targets/wasm_exec_node.js {}"
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-86
@@ -3,51 +3,25 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
//
|
//
|
||||||
// This file has been modified for use by the TinyGo compiler.
|
// This file has been modified for use by the TinyGo compiler.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
// 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 enosys = () => {
|
||||||
const err = new Error("not implemented");
|
const err = new Error("not implemented");
|
||||||
err.code = "ENOSYS";
|
err.code = "ENOSYS";
|
||||||
return err;
|
return err;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!global.fs) {
|
if (!globalThis.fs) {
|
||||||
let outputBuf = "";
|
let outputBuf = "";
|
||||||
global.fs = {
|
globalThis.fs = {
|
||||||
constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1 }, // unused
|
constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1, O_DIRECTORY: -1 }, // unused
|
||||||
writeSync(fd, buf) {
|
writeSync(fd, buf) {
|
||||||
outputBuf += decoder.decode(buf);
|
outputBuf += decoder.decode(buf);
|
||||||
const nl = outputBuf.lastIndexOf("\n");
|
const nl = outputBuf.lastIndexOf("\n");
|
||||||
if (nl != -1) {
|
if (nl != -1) {
|
||||||
console.log(outputBuf.substr(0, nl));
|
console.log(outputBuf.substring(0, nl));
|
||||||
outputBuf = outputBuf.substr(nl + 1);
|
outputBuf = outputBuf.substring(nl + 1);
|
||||||
}
|
}
|
||||||
return buf.length;
|
return buf.length;
|
||||||
},
|
},
|
||||||
@@ -85,8 +59,8 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!global.process) {
|
if (!globalThis.process) {
|
||||||
global.process = {
|
globalThis.process = {
|
||||||
getuid() { return -1; },
|
getuid() { return -1; },
|
||||||
getgid() { return -1; },
|
getgid() { return -1; },
|
||||||
geteuid() { return -1; },
|
geteuid() { return -1; },
|
||||||
@@ -100,41 +74,29 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!global.crypto) {
|
if (!globalThis.crypto) {
|
||||||
const nodeCrypto = require("node:crypto");
|
throw new Error("globalThis.crypto is not available, polyfill required (crypto.getRandomValues only)");
|
||||||
global.crypto = {
|
|
||||||
getRandomValues(b) {
|
|
||||||
nodeCrypto.randomFillSync(b);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!global.performance) {
|
if (!globalThis.performance) {
|
||||||
global.performance = {
|
throw new Error("globalThis.performance is not available, polyfill required (performance.now only)");
|
||||||
now() {
|
|
||||||
const [sec, nsec] = process.hrtime();
|
|
||||||
return sec * 1000 + nsec / 1000000;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!global.TextEncoder) {
|
if (!globalThis.TextEncoder) {
|
||||||
global.TextEncoder = require("node:util").TextEncoder;
|
throw new Error("globalThis.TextEncoder is not available, polyfill required");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!global.TextDecoder) {
|
if (!globalThis.TextDecoder) {
|
||||||
global.TextDecoder = require("node:util").TextDecoder;
|
throw new Error("globalThis.TextDecoder is not available, polyfill required");
|
||||||
}
|
}
|
||||||
|
|
||||||
// End of polyfills for common API.
|
|
||||||
|
|
||||||
const encoder = new TextEncoder("utf-8");
|
const encoder = new TextEncoder("utf-8");
|
||||||
const decoder = new TextDecoder("utf-8");
|
const decoder = new TextDecoder("utf-8");
|
||||||
let reinterpretBuf = new DataView(new ArrayBuffer(8));
|
let reinterpretBuf = new DataView(new ArrayBuffer(8));
|
||||||
var logLine = [];
|
var logLine = [];
|
||||||
const wasmExit = {}; // thrown to exit via proc_exit (not an error)
|
const wasmExit = {}; // thrown to exit via proc_exit (not an error)
|
||||||
|
|
||||||
global.Go = class {
|
globalThis.Go = class {
|
||||||
constructor() {
|
constructor() {
|
||||||
this._callbackTimeouts = new Map();
|
this._callbackTimeouts = new Map();
|
||||||
this._nextCallbackTimeoutID = 1;
|
this._nextCallbackTimeoutID = 1;
|
||||||
@@ -248,13 +210,13 @@
|
|||||||
nwritten_ptr >>>= 0;
|
nwritten_ptr >>>= 0;
|
||||||
let nwritten = 0;
|
let nwritten = 0;
|
||||||
if (fd == 1) {
|
if (fd == 1) {
|
||||||
for (let iovs_i=0; iovs_i<iovs_len;iovs_i++) {
|
for (let iovs_i = 0; iovs_i < iovs_len; iovs_i++) {
|
||||||
let iov_ptr = iovs_ptr+iovs_i*8; // assuming wasm32
|
let iov_ptr = iovs_ptr + iovs_i * 8; // assuming wasm32
|
||||||
let ptr = mem().getUint32(iov_ptr + 0, true);
|
let ptr = mem().getUint32(iov_ptr + 0, true);
|
||||||
let len = mem().getUint32(iov_ptr + 4, true);
|
let len = mem().getUint32(iov_ptr + 4, true);
|
||||||
nwritten += len;
|
nwritten += len;
|
||||||
for (let i=0; i<len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
let c = mem().getUint8(ptr+i);
|
let c = mem().getUint8(ptr + i);
|
||||||
if (c == 13) { // CR
|
if (c == 13) { // CR
|
||||||
// ignore
|
// ignore
|
||||||
} else if (c == 10) { // LF
|
} else if (c == 10) { // LF
|
||||||
@@ -316,7 +278,7 @@
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e !== wasmExit) throw e;
|
if (e !== wasmExit) throw e;
|
||||||
}
|
}
|
||||||
}, Number(timeout)/1e6);
|
}, Number(timeout) / 1e6);
|
||||||
},
|
},
|
||||||
|
|
||||||
// func finalizeRef(v ref)
|
// func finalizeRef(v ref)
|
||||||
@@ -432,7 +394,7 @@
|
|||||||
mem().setUint8(ret_addr + 8, 1);
|
mem().setUint8(ret_addr + 8, 1);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
storeValue(ret_addr, err);
|
storeValue(ret_addr, err);
|
||||||
mem().setUint8(ret_addr+ 8, 0);
|
mem().setUint8(ret_addr + 8, 0);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -460,7 +422,7 @@
|
|||||||
|
|
||||||
// func valueInstanceOf(v ref, t ref) bool
|
// func valueInstanceOf(v ref, t ref) bool
|
||||||
"syscall/js.valueInstanceOf": (v_ref, t_ref) => {
|
"syscall/js.valueInstanceOf": (v_ref, t_ref) => {
|
||||||
return unboxValue(v_ref) instanceof unboxValue(t_ref);
|
return unboxValue(v_ref) instanceof unboxValue(t_ref);
|
||||||
},
|
},
|
||||||
|
|
||||||
// func copyBytesToGo(dst []byte, src ref) (int, bool)
|
// func copyBytesToGo(dst []byte, src ref) (int, bool)
|
||||||
@@ -520,7 +482,7 @@
|
|||||||
null,
|
null,
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
global,
|
globalThis,
|
||||||
this,
|
this,
|
||||||
];
|
];
|
||||||
this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id
|
this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id
|
||||||
@@ -565,7 +527,7 @@
|
|||||||
|
|
||||||
_makeFuncWrapper(id) {
|
_makeFuncWrapper(id) {
|
||||||
const go = this;
|
const go = this;
|
||||||
return function () {
|
return function() {
|
||||||
const event = { id: id, this: this, args: arguments };
|
const event = { id: id, this: this, args: arguments };
|
||||||
go._pendingEvent = event;
|
go._pendingEvent = event;
|
||||||
go._resume();
|
go._resume();
|
||||||
@@ -573,26 +535,5 @@
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
// Copyright 2021 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.
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
if (process.argv.length < 3) {
|
||||||
|
console.error("usage: go_js_wasm_exec [wasm binary] [arguments]");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
globalThis.require = require;
|
||||||
|
globalThis.fs = require("fs");
|
||||||
|
|
||||||
|
globalThis.performance = {
|
||||||
|
now() {
|
||||||
|
const [sec, nsec] = process.hrtime();
|
||||||
|
return sec * 1000 + nsec / 1000000;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
require("./wasm_exec");
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
Vendored
+2
@@ -1,3 +1,5 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
|
||||||
require('../targets/wasm_exec.js');
|
require('../targets/wasm_exec.js');
|
||||||
|
|
||||||
function runTests() {
|
function runTests() {
|
||||||
|
|||||||
Vendored
+2
@@ -1,3 +1,5 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
|
||||||
require('../targets/wasm_exec.js');
|
require('../targets/wasm_exec.js');
|
||||||
|
|
||||||
function runTests() {
|
function runTests() {
|
||||||
|
|||||||
Vendored
+2
@@ -1,3 +1,5 @@
|
|||||||
|
const fs = require('fs')
|
||||||
|
|
||||||
require('../targets/wasm_exec.js');
|
require('../targets/wasm_exec.js');
|
||||||
|
|
||||||
var callback;
|
var callback;
|
||||||
|
|||||||
Reference in New Issue
Block a user