mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-30 16:48:40 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8e7a288bb4 | |||
| 0edeaf657f | |||
| 76d5b3d786 | |||
| 915132645e |
@@ -27,7 +27,6 @@ jobs:
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Install Dependencies
|
||||
shell: bash
|
||||
run: |
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install qemu binaryen
|
||||
- name: Checkout
|
||||
@@ -72,7 +71,6 @@ jobs:
|
||||
path: llvm-build
|
||||
- name: Build LLVM
|
||||
if: steps.cache-llvm-build.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
run: |
|
||||
# fetch LLVM source
|
||||
rm -rf llvm-project
|
||||
@@ -100,14 +98,12 @@ jobs:
|
||||
- name: make gen-device
|
||||
run: make -j3 gen-device
|
||||
- name: Test TinyGo
|
||||
shell: bash
|
||||
run: make test GOTESTFLAGS="-short"
|
||||
- name: Build TinyGo release tarball
|
||||
run: make release -j3
|
||||
- name: Test stdlib packages
|
||||
run: make tinygo-test
|
||||
- name: Make release artifact
|
||||
shell: bash
|
||||
run: cp -p build/release.tar.gz build/tinygo.darwin-${{ matrix.goarch }}.tar.gz
|
||||
- name: Publish release artifact
|
||||
# Note: this release artifact is double-zipped, see:
|
||||
@@ -121,7 +117,6 @@ jobs:
|
||||
name: darwin-${{ matrix.goarch }}-double-zipped
|
||||
path: build/tinygo.darwin-${{ matrix.goarch }}.tar.gz
|
||||
- name: Smoke tests
|
||||
shell: bash
|
||||
run: make smoketest TINYGO=$(PWD)/build/tinygo
|
||||
test-macos-homebrew:
|
||||
name: homebrew-install
|
||||
|
||||
@@ -452,7 +452,7 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
||||
"--stack-first",
|
||||
"--no-demangle",
|
||||
)
|
||||
spec.Emulator = "wasmtime --dir={tmpDir}::/tmp {}"
|
||||
spec.Emulator = "wasmtime run --dir={tmpDir}::/tmp {}"
|
||||
spec.ExtraFiles = append(spec.ExtraFiles,
|
||||
"src/runtime/asm_tinygowasm.S",
|
||||
"src/internal/task/task_asyncify_wasm.S",
|
||||
|
||||
@@ -769,22 +769,18 @@ func Run(pkgName string, options *compileopts.Options, cmdArgs []string) error {
|
||||
// passes command line arguments and environment variables in a way appropriate
|
||||
// for the given emulator.
|
||||
func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, cmdArgs, environmentVars []string, timeout time.Duration, run func(cmd *exec.Cmd, result builder.BuildResult) error) (builder.BuildResult, error) {
|
||||
|
||||
isSingleFile := strings.HasSuffix(pkgName, ".go")
|
||||
|
||||
// Determine whether we're on a system that supports environment variables
|
||||
// and command line parameters (operating systems, WASI) or not (baremetal,
|
||||
// WebAssembly in the browser). If we're on a system without an environment,
|
||||
// we need to pass command line arguments and environment variables through
|
||||
// global variables (built into the binary directly) instead of the
|
||||
// conventional way.
|
||||
needsEnvInVars := config.GOOS() == "js"
|
||||
// and command line parameters (operating systems, WASI) or not (baremetal).
|
||||
// If we're on a system without an environment, we need to pass command line
|
||||
// arguments and environment variables through global variables (built into
|
||||
// the binary directly) instead of the conventional way.
|
||||
needsEnvInVars := false
|
||||
for _, tag := range config.BuildTags() {
|
||||
if tag == "baremetal" {
|
||||
needsEnvInVars = true
|
||||
}
|
||||
}
|
||||
var args, emuArgs, env []string
|
||||
var args, env []string
|
||||
var extraCmdEnv []string
|
||||
if needsEnvInVars {
|
||||
runtimeGlobals := make(map[string]string)
|
||||
@@ -804,20 +800,6 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
||||
"runtime": runtimeGlobals,
|
||||
}
|
||||
}
|
||||
} else if config.EmulatorName() == "wasmtime" {
|
||||
for _, v := range environmentVars {
|
||||
emuArgs = append(emuArgs, "--env", v)
|
||||
}
|
||||
|
||||
// Use of '--' argument no longer necessary as of Wasmtime v14:
|
||||
// https://github.com/bytecodealliance/wasmtime/pull/6946
|
||||
// args = append(args, "--")
|
||||
args = append(args, cmdArgs...)
|
||||
|
||||
// Set this for nicer backtraces during tests, but don't override the user.
|
||||
if _, ok := os.LookupEnv("WASMTIME_BACKTRACE_DETAILS"); !ok {
|
||||
extraCmdEnv = append(extraCmdEnv, "WASMTIME_BACKTRACE_DETAILS=1")
|
||||
}
|
||||
} else {
|
||||
// Pass environment variables and command line parameters as usual.
|
||||
// This also works on qemu-aarch64 etc.
|
||||
@@ -860,7 +842,7 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
||||
return result, err
|
||||
}
|
||||
|
||||
name = emulator[0]
|
||||
name, emulator = emulator[0], emulator[1:]
|
||||
|
||||
// wasmtime is a WebAssembly runtime CLI with WASI enabled by default.
|
||||
// By default, only stdio is allowed. For example, while STDOUT routes
|
||||
@@ -869,11 +851,24 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
||||
// outside the package directory. Other tests require temporary
|
||||
// writeable directories. We allow this by adding wasmtime flags below.
|
||||
if name == "wasmtime" {
|
||||
var emuArgs []string
|
||||
|
||||
// Extract the wasmtime subcommand (e.g. "run" or "serve")
|
||||
if len(emulator) > 1 {
|
||||
emuArgs = append(emuArgs, emulator[0])
|
||||
emulator = emulator[1:]
|
||||
}
|
||||
|
||||
wd, _ := os.Getwd()
|
||||
|
||||
// Below adds additional wasmtime flags in case a test reads files
|
||||
// outside its directory, like "../testdata/e.txt". This allows any
|
||||
// relative directory up to the module root, even if the test never
|
||||
// reads any files.
|
||||
if config.TestConfig.CompileTestBinary {
|
||||
// Set working directory to package dir
|
||||
wd = result.MainDir
|
||||
|
||||
// Add relative dirs (../, ../..) up to module root (for wasip1)
|
||||
dirs := dirsToModuleRootRel(result.MainDir, result.ModuleRoot)
|
||||
|
||||
@@ -883,19 +878,25 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
||||
for _, d := range dirs {
|
||||
emuArgs = append(emuArgs, "--dir="+d)
|
||||
}
|
||||
} else {
|
||||
emuArgs = append(emuArgs, "--dir=.")
|
||||
}
|
||||
|
||||
dir := result.MainDir
|
||||
if isSingleFile {
|
||||
dir, _ = os.Getwd()
|
||||
emuArgs = append(emuArgs, "--dir="+wd)
|
||||
emuArgs = append(emuArgs, "--env=PWD="+wd)
|
||||
for _, v := range environmentVars {
|
||||
emuArgs = append(emuArgs, "--env", v)
|
||||
}
|
||||
emuArgs = append(emuArgs, "--dir=.")
|
||||
emuArgs = append(emuArgs, "--dir="+dir)
|
||||
emuArgs = append(emuArgs, "--env=PWD="+dir)
|
||||
|
||||
// Set this for nicer backtraces during tests, but don't override the user.
|
||||
if _, ok := os.LookupEnv("WASMTIME_BACKTRACE_DETAILS"); !ok {
|
||||
extraCmdEnv = append(extraCmdEnv, "WASMTIME_BACKTRACE_DETAILS=1")
|
||||
}
|
||||
|
||||
emulator = append(emuArgs, emulator...)
|
||||
}
|
||||
|
||||
emuArgs = append(emuArgs, emulator[1:]...)
|
||||
args = append(emuArgs, args...)
|
||||
args = append(emulator, args...)
|
||||
}
|
||||
var cmd *exec.Cmd
|
||||
if ctx != nil {
|
||||
@@ -925,7 +926,7 @@ func buildAndRun(pkgName string, config *compileopts.Config, stdout io.Writer, c
|
||||
|
||||
// Run binary.
|
||||
if config.Options.PrintCommands != nil {
|
||||
config.Options.PrintCommands(cmd.Path, cmd.Args...)
|
||||
config.Options.PrintCommands(cmd.Path, cmd.Args[1:]...)
|
||||
}
|
||||
err = run(cmd, result)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build baremetal || js || wasm_unknown
|
||||
//go:build baremetal || wasm_unknown
|
||||
|
||||
package runtime
|
||||
|
||||
|
||||
@@ -29,6 +29,44 @@ func proc_exit(exitcode uint32)
|
||||
//export __stdio_exit
|
||||
func __stdio_exit()
|
||||
|
||||
var args []string
|
||||
|
||||
//go:linkname os_runtime_args os.runtime_args
|
||||
func os_runtime_args() []string {
|
||||
if args == nil {
|
||||
// Read the number of args (argc) and the buffer size required to store
|
||||
// all these args (argv).
|
||||
var argc, argv_buf_size uint32
|
||||
args_sizes_get(&argc, &argv_buf_size)
|
||||
if argc == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Obtain the command line arguments
|
||||
argsSlice := make([]unsafe.Pointer, argc)
|
||||
buf := make([]byte, argv_buf_size)
|
||||
args_get(&argsSlice[0], unsafe.Pointer(&buf[0]))
|
||||
|
||||
// Convert the array of C strings to an array of Go strings.
|
||||
args = make([]string, argc)
|
||||
for i, cstr := range argsSlice {
|
||||
length := strlen(cstr)
|
||||
argString := _string{
|
||||
length: length,
|
||||
ptr: (*byte)(cstr),
|
||||
}
|
||||
args[i] = *(*string)(unsafe.Pointer(&argString))
|
||||
}
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
//go:wasmimport wasi_snapshot_preview1 args_get
|
||||
func args_get(argv *unsafe.Pointer, argv_buf unsafe.Pointer) (errno uint16)
|
||||
|
||||
//go:wasmimport wasi_snapshot_preview1 args_sizes_get
|
||||
func args_sizes_get(argc *uint32, argv_buf_size *uint32) (errno uint16)
|
||||
|
||||
const (
|
||||
putcharBufferSize = 120
|
||||
stdout = 1
|
||||
|
||||
@@ -2,10 +2,6 @@
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type timeUnit int64
|
||||
|
||||
// libc constructors
|
||||
@@ -21,38 +17,6 @@ func init() {
|
||||
__wasm_call_ctors()
|
||||
}
|
||||
|
||||
var args []string
|
||||
|
||||
//go:linkname os_runtime_args os.runtime_args
|
||||
func os_runtime_args() []string {
|
||||
if args == nil {
|
||||
// Read the number of args (argc) and the buffer size required to store
|
||||
// all these args (argv).
|
||||
var argc, argv_buf_size uint32
|
||||
args_sizes_get(&argc, &argv_buf_size)
|
||||
if argc == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Obtain the command line arguments
|
||||
argsSlice := make([]unsafe.Pointer, argc)
|
||||
buf := make([]byte, argv_buf_size)
|
||||
args_get(&argsSlice[0], unsafe.Pointer(&buf[0]))
|
||||
|
||||
// Convert the array of C strings to an array of Go strings.
|
||||
args = make([]string, argc)
|
||||
for i, cstr := range argsSlice {
|
||||
length := strlen(cstr)
|
||||
argString := _string{
|
||||
length: length,
|
||||
ptr: (*byte)(cstr),
|
||||
}
|
||||
args[i] = *(*string)(unsafe.Pointer(&argString))
|
||||
}
|
||||
}
|
||||
return args
|
||||
}
|
||||
|
||||
func ticksToNanoseconds(ticks timeUnit) int64 {
|
||||
return int64(ticks)
|
||||
}
|
||||
@@ -97,12 +61,6 @@ func beforeExit() {
|
||||
|
||||
// Implementations of WASI APIs
|
||||
|
||||
//go:wasmimport wasi_snapshot_preview1 args_get
|
||||
func args_get(argv *unsafe.Pointer, argv_buf unsafe.Pointer) (errno uint16)
|
||||
|
||||
//go:wasmimport wasi_snapshot_preview1 args_sizes_get
|
||||
func args_sizes_get(argc *uint32, argv_buf_size *uint32) (errno uint16)
|
||||
|
||||
//go:wasmimport wasi_snapshot_preview1 clock_time_get
|
||||
func clock_time_get(clockid uint32, precision uint64, time *uint64) (errno uint16)
|
||||
|
||||
|
||||
+6
-23
@@ -3,12 +3,10 @@ package sync
|
||||
import (
|
||||
"internal/task"
|
||||
_ "unsafe"
|
||||
|
||||
"runtime/volatile"
|
||||
)
|
||||
|
||||
type Mutex struct {
|
||||
state uint8 // Set to non-zero if locked.
|
||||
locked bool
|
||||
blocked task.Stack
|
||||
}
|
||||
|
||||
@@ -16,18 +14,18 @@ type Mutex struct {
|
||||
func scheduleTask(*task.Task)
|
||||
|
||||
func (m *Mutex) Lock() {
|
||||
if m.islocked() {
|
||||
if m.locked {
|
||||
// Push self onto stack of blocked tasks, and wait to be resumed.
|
||||
m.blocked.Push(task.Current())
|
||||
task.Pause()
|
||||
return
|
||||
}
|
||||
|
||||
m.setlock(true)
|
||||
m.locked = true
|
||||
}
|
||||
|
||||
func (m *Mutex) Unlock() {
|
||||
if !m.islocked() {
|
||||
if !m.locked {
|
||||
panic("sync: unlock of unlocked Mutex")
|
||||
}
|
||||
|
||||
@@ -35,7 +33,7 @@ func (m *Mutex) Unlock() {
|
||||
if t := m.blocked.Pop(); t != nil {
|
||||
scheduleTask(t)
|
||||
} else {
|
||||
m.setlock(false)
|
||||
m.locked = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,28 +43,13 @@ func (m *Mutex) Unlock() {
|
||||
// and use of TryLock is often a sign of a deeper problem
|
||||
// in a particular use of mutexes.
|
||||
func (m *Mutex) TryLock() bool {
|
||||
if m.islocked() {
|
||||
if m.locked {
|
||||
return false
|
||||
}
|
||||
m.Lock()
|
||||
return true
|
||||
}
|
||||
|
||||
func (m *Mutex) islocked() bool {
|
||||
return volatile.LoadUint8(&m.state) != 0
|
||||
}
|
||||
|
||||
func (m *Mutex) setlock(b bool) {
|
||||
volatile.StoreUint8(&m.state, boolToU8(b))
|
||||
}
|
||||
|
||||
func boolToU8(b bool) uint8 {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type RWMutex struct {
|
||||
// waitingWriters are all of the tasks waiting for write locks.
|
||||
waitingWriters task.Stack
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build nintendoswitch || wasip1
|
||||
//go:build js || nintendoswitch || wasip1
|
||||
|
||||
package syscall
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build !wasip1 && !wasip2
|
||||
//go:build !js && !wasip1 && !wasip2
|
||||
|
||||
package syscall
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build wasip1
|
||||
//go:build js || wasip1
|
||||
|
||||
package syscall
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build nintendoswitch || wasip1 || wasip2
|
||||
//go:build js || nintendoswitch || wasip1 || wasip2
|
||||
|
||||
package syscall
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build wasip1 || wasip2
|
||||
//go:build js || wasip1 || wasip2
|
||||
|
||||
package syscall
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//go:build baremetal || js || wasm_unknown
|
||||
//go:build baremetal || wasm_unknown
|
||||
|
||||
package syscall
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build baremetal || nintendoswitch || js || wasm_unknown
|
||||
//go:build baremetal || nintendoswitch || wasm_unknown
|
||||
|
||||
package syscall
|
||||
|
||||
|
||||
+1
-1
@@ -23,5 +23,5 @@
|
||||
"extra-files": [
|
||||
"src/runtime/asm_tinygowasm.S"
|
||||
],
|
||||
"emulator": "wasmtime --dir={tmpDir}::/tmp {}"
|
||||
"emulator": "wasmtime run --dir={tmpDir}::/tmp {}"
|
||||
}
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@
|
||||
"extra-files": [
|
||||
"src/runtime/asm_tinygowasm.S"
|
||||
],
|
||||
"emulator": "wasmtime --wasm component-model -Sinherit-network -Sallow-ip-name-lookup --dir={tmpDir}::/tmp {}",
|
||||
"emulator": "wasmtime run --wasm component-model -Sinherit-network -Sallow-ip-name-lookup --dir={tmpDir}::/tmp {}",
|
||||
"wit-package": "{root}/lib/wasi-cli/wit/",
|
||||
"wit-world": "wasi:cli/command"
|
||||
}
|
||||
|
||||
@@ -24,5 +24,5 @@
|
||||
"extra-files": [
|
||||
"src/runtime/asm_tinygowasm.S"
|
||||
],
|
||||
"emulator": "wasmtime --dir={tmpDir}::/tmp {}"
|
||||
"emulator": "wasmtime run --dir={tmpDir}::/tmp {}"
|
||||
}
|
||||
|
||||
+54
-1
@@ -135,6 +135,8 @@
|
||||
|
||||
global.Go = class {
|
||||
constructor() {
|
||||
this.argv = ["js"];
|
||||
this.env = {};
|
||||
this._callbackTimeouts = new Map();
|
||||
this._nextCallbackTimeoutID = 1;
|
||||
|
||||
@@ -235,9 +237,58 @@
|
||||
return decoder.decode(new DataView(this._inst.exports.memory.buffer, ptr, len));
|
||||
}
|
||||
|
||||
const storeStringArraySizes = (array, num_ptr, buf_size_ptr) => {
|
||||
let buf_size = 0;
|
||||
for (let s of array) {
|
||||
buf_size += s.length + 1;
|
||||
}
|
||||
mem().setUint32(num_ptr, array.length, true);
|
||||
mem().setUint32(buf_size_ptr, buf_size, true);
|
||||
}
|
||||
|
||||
const storeStringArray = (array, ptrs_ptr, buf_ptr) => {
|
||||
for (let s of array) {
|
||||
// Put string data in buffer.
|
||||
let data = encoder.encode(s);
|
||||
let dest = new Uint8Array(this._inst.exports.memory.buffer, buf_ptr, data.length);
|
||||
dest.set(data);
|
||||
mem().setUint8(buf_ptr+data.length, 0);
|
||||
|
||||
// Put pointer to buffer in pointers array.
|
||||
mem().setUint32(ptrs_ptr, buf_ptr, true);
|
||||
|
||||
// Advance to the next element in the array.
|
||||
ptrs_ptr += 4;
|
||||
buf_ptr += data.length + 1;
|
||||
}
|
||||
}
|
||||
|
||||
const envArray = () => {
|
||||
let array = [];
|
||||
for (let [key, value] of Object.entries(this.env)) {
|
||||
array.push(`${key}=${value}`);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
const timeOrigin = Date.now() - performance.now();
|
||||
this.importObject = {
|
||||
wasi_snapshot_preview1: {
|
||||
args_sizes_get: (argc_ptr, argv_buf_size_ptr) => {
|
||||
storeStringArraySizes(this.argv, argc_ptr, argv_buf_size_ptr);
|
||||
return 0;
|
||||
},
|
||||
args_get: (argv_ptr, argv_buf_ptr) => {
|
||||
storeStringArray(this.argv, argv_ptr, argv_buf_ptr);
|
||||
return 0;
|
||||
},
|
||||
environ_get: (env_ptr, env_buf_ptr) => {
|
||||
storeStringArray(envArray(), env_ptr, env_buf_ptr);
|
||||
},
|
||||
environ_sizes_get: (env_ptr, env_buf_size_ptr) => {
|
||||
storeStringArraySizes(envArray(), env_ptr, env_buf_size_ptr);
|
||||
return 0;
|
||||
},
|
||||
// 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;
|
||||
@@ -504,12 +555,14 @@
|
||||
global.process.versions &&
|
||||
!global.process.versions.electron
|
||||
) {
|
||||
if (process.argv.length != 3) {
|
||||
if (process.argv.length < 3) {
|
||||
console.error("usage: go_js_wasm_exec [wasm binary] [arguments]");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const go = new Go();
|
||||
go.argv = process.argv.slice(2);
|
||||
go.env = process.env;
|
||||
WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => {
|
||||
return go.run(result.instance);
|
||||
}).catch((err) => {
|
||||
|
||||
Reference in New Issue
Block a user