From be50055eef0f460695adb8db2b130392dc367fe7 Mon Sep 17 00:00:00 2001 From: Johan Brandhorst-Satzkorn Date: Fri, 24 Mar 2023 23:11:55 -0700 Subject: [PATCH] runtime: add remaining wasip1 files Implements OS interactions and memory management. For #58141 Co-authored-by: Richard Musiol Co-authored-by: Achille Roussel Co-authored-by: Julien Fabre Co-authored-by: Evan Phoenix Change-Id: I876e7b033090c2fe2d76d2535bb63d52efa36185 Reviewed-on: https://go-review.googlesource.com/c/go/+/479618 TryBot-Result: Gopher Robot Reviewed-by: Cherry Mui Reviewed-by: Ian Lance Taylor Run-TryBot: Cherry Mui Auto-Submit: Ian Lance Taylor Run-TryBot: Ian Lance Taylor --- src/internal/testenv/testenv.go | 18 +++ src/runtime/lock_wasip1.go | 107 ++++++++++++++ src/runtime/mem_js.go | 19 +-- src/runtime/mem_wasip1.go | 13 ++ src/runtime/mem_wasm.go | 20 +++ src/runtime/netpoll.go | 2 +- src/runtime/netpoll_fake.go | 6 +- src/runtime/os_js.go | 143 +----------------- src/runtime/os_wasip1.go | 251 ++++++++++++++++++++++++++++++++ src/runtime/os_wasm.go | 152 +++++++++++++++++++ src/runtime/pprof/pprof_test.go | 6 + src/runtime/pprof/proto_test.go | 2 +- src/runtime/runtime_test.go | 4 +- src/runtime/semasleep_test.go | 2 +- src/runtime/stubs2.go | 2 +- src/runtime/stubs3.go | 2 +- src/runtime/sys_wasm.s | 9 -- src/runtime/timestub2.go | 2 +- src/runtime/trace/trace_test.go | 10 +- 19 files changed, 588 insertions(+), 182 deletions(-) create mode 100644 src/runtime/lock_wasip1.go create mode 100644 src/runtime/mem_wasip1.go create mode 100644 src/runtime/mem_wasm.go create mode 100644 src/runtime/os_wasip1.go create mode 100644 src/runtime/os_wasm.go diff --git a/src/internal/testenv/testenv.go b/src/internal/testenv/testenv.go index 94cec0b8bd..565230e24c 100644 --- a/src/internal/testenv/testenv.go +++ b/src/internal/testenv/testenv.go @@ -78,6 +78,24 @@ func MustHaveGoRun(t testing.TB) { } } +// HasParallelism reports whether the current system can execute multiple +// threads in parallel. +func HasParallelism() bool { + switch runtime.GOOS { + case "js", "wasip1": + return false + } + return true +} + +// MustHaveParallelism checks that the current system can execute multiple +// threads in parallel. If not, MustHaveParallelism calls t.Skip with an explanation. +func MustHaveParallelism(t testing.TB) { + if !HasParallelism() { + t.Skipf("skipping test: no parallelism available on %s/%s", runtime.GOOS, runtime.GOARCH) + } +} + // GoToolPath reports the path to the Go tool. // It is a convenience wrapper around GoTool. // If the tool is unavailable GoToolPath calls t.Skip. diff --git a/src/runtime/lock_wasip1.go b/src/runtime/lock_wasip1.go new file mode 100644 index 0000000000..c4fc59f6cc --- /dev/null +++ b/src/runtime/lock_wasip1.go @@ -0,0 +1,107 @@ +// Copyright 2023 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. + +//go:build wasip1 + +package runtime + +// wasm has no support for threads yet. There is no preemption. +// See proposal: https://github.com/WebAssembly/threads +// Waiting for a mutex or timeout is implemented as a busy loop +// while allowing other goroutines to run. + +const ( + mutex_unlocked = 0 + mutex_locked = 1 + + active_spin = 4 + active_spin_cnt = 30 +) + +func lock(l *mutex) { + lockWithRank(l, getLockRank(l)) +} + +func lock2(l *mutex) { + if l.key == mutex_locked { + // wasm is single-threaded so we should never + // observe this. + throw("self deadlock") + } + gp := getg() + if gp.m.locks < 0 { + throw("lock count") + } + gp.m.locks++ + l.key = mutex_locked +} + +func unlock(l *mutex) { + unlockWithRank(l) +} + +func unlock2(l *mutex) { + if l.key == mutex_unlocked { + throw("unlock of unlocked lock") + } + gp := getg() + gp.m.locks-- + if gp.m.locks < 0 { + throw("lock count") + } + l.key = mutex_unlocked +} + +// One-time notifications. +func noteclear(n *note) { + n.key = 0 +} + +func notewakeup(n *note) { + if n.key != 0 { + print("notewakeup - double wakeup (", n.key, ")\n") + throw("notewakeup - double wakeup") + } + n.key = 1 +} + +func notesleep(n *note) { + throw("notesleep not supported by wasi") +} + +func notetsleep(n *note, ns int64) bool { + throw("notetsleep not supported by wasi") + return false +} + +// same as runtime·notetsleep, but called on user g (not g0) +func notetsleepg(n *note, ns int64) bool { + gp := getg() + if gp == gp.m.g0 { + throw("notetsleepg on g0") + } + + deadline := nanotime() + ns + for { + if n.key != 0 { + return true + } + if sched_yield() != 0 { + throw("sched_yield failed") + } + Gosched() + if ns >= 0 && nanotime() >= deadline { + return false + } + } +} + +func beforeIdle(int64, int64) (*g, bool) { + return nil, false +} + +func checkTimeouts() {} + +//go:wasmimport wasi_snapshot_preview1 sched_yield +func sched_yield() errno diff --git a/src/runtime/mem_js.go b/src/runtime/mem_js.go index 3aaf6ca5e7..080b1abc67 100644 --- a/src/runtime/mem_js.go +++ b/src/runtime/mem_js.go @@ -2,27 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build js && wasm +//go:build js package runtime -import "unsafe" - -func sbrk(n uintptr) unsafe.Pointer { - grow := divRoundUp(n, physPageSize) - size := currentMemory() - - if growMemory(int32(grow)) < 0 { - return nil - } - - resetMemoryDataView() - return unsafe.Pointer(uintptr(size) * physPageSize) -} - -func currentMemory() int32 -func growMemory(pages int32) int32 - // resetMemoryDataView signals the JS front-end that WebAssembly's memory.grow instruction has been used. // This allows the front-end to replace the old DataView object with a new one. // diff --git a/src/runtime/mem_wasip1.go b/src/runtime/mem_wasip1.go new file mode 100644 index 0000000000..41ffa0ddc2 --- /dev/null +++ b/src/runtime/mem_wasip1.go @@ -0,0 +1,13 @@ +// Copyright 2023 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. + +//go:build wasip1 + +package runtime + +func resetMemoryDataView() { + // This function is a no-op on WASI, it is only used to notify the browser + // that its view of the WASM memory needs to be updated when compiling for + // GOOS=js. +} diff --git a/src/runtime/mem_wasm.go b/src/runtime/mem_wasm.go new file mode 100644 index 0000000000..d9d32705bb --- /dev/null +++ b/src/runtime/mem_wasm.go @@ -0,0 +1,20 @@ +// Copyright 2023 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. + +package runtime + +import "unsafe" + +func sbrk(n uintptr) unsafe.Pointer { + grow := divRoundUp(n, physPageSize) + size := growMemory(int32(grow)) + if size < 0 { + return nil + } + resetMemoryDataView() + return unsafe.Pointer(uintptr(size) * physPageSize) +} + +// Implemented in src/runtime/sys_wasm.s +func growMemory(pages int32) int32 diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go index 5ac1f37048..b4eb7330c3 100644 --- a/src/runtime/netpoll.go +++ b/src/runtime/netpoll.go @@ -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 unix || (js && wasm) || windows +//go:build unix || (js && wasm) || wasip1 || windows package runtime diff --git a/src/runtime/netpoll_fake.go b/src/runtime/netpoll_fake.go index de1dcae7ac..5782c78515 100644 --- a/src/runtime/netpoll_fake.go +++ b/src/runtime/netpoll_fake.go @@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Fake network poller for wasm/js. -// Should never be used, because wasm/js network connections do not honor "SetNonblock". +// Fake network poller for js/wasm and wasip1/wasm. +// Should never be used, because wasm network connections do not honor "SetNonblock". -//go:build js && wasm +//go:build (js && wasm) || wasip1 package runtime diff --git a/src/runtime/os_js.go b/src/runtime/os_js.go index 20ac524552..65fb499de6 100644 --- a/src/runtime/os_js.go +++ b/src/runtime/os_js.go @@ -7,7 +7,6 @@ package runtime import ( - "runtime/internal/atomic" "unsafe" ) @@ -21,154 +20,18 @@ func write1(fd uintptr, p unsafe.Pointer, n int32) int32 { return n } -// Stubs so tests can link correctly. These should never be called. -func open(name *byte, mode, perm int32) int32 { panic("not implemented") } -func closefd(fd int32) int32 { panic("not implemented") } -func read(fd int32, p unsafe.Pointer, n int32) int32 { panic("not implemented") } - //go:wasmimport gojs runtime.wasmWrite //go:noescape func wasmWrite(fd uintptr, p unsafe.Pointer, n int32) -func usleep(usec uint32) - -//go:nosplit -func usleep_no_g(usec uint32) { - usleep(usec) -} - -func exitThread(wait *atomic.Uint32) - -type mOS struct{} - -func osyield() - -//go:nosplit -func osyield_no_g() { - osyield() -} - -const _SIGSEGV = 0xb - -func sigpanic() { - gp := getg() - if !canpanic() { - throw("unexpected signal during runtime execution") - } - - // js only invokes the exception handler for memory faults. - gp.sig = _SIGSEGV - panicmem() -} - -type sigset struct{} - -// Called to initialize a new m (including the bootstrap m). -// Called on the parent thread (main thread in case of bootstrap), can allocate memory. -func mpreinit(mp *m) { - mp.gsignal = malg(32 * 1024) - mp.gsignal.m = mp -} - -//go:nosplit -func sigsave(p *sigset) { -} - -//go:nosplit -func msigrestore(sigmask sigset) { -} - -//go:nosplit -//go:nowritebarrierrec -func clearSignalHandlers() { -} - -//go:nosplit -func sigblock(exiting bool) { -} - -// Called to initialize a new m (including the bootstrap m). -// Called on the new thread, cannot allocate memory. -func minit() { -} - -// Called from dropm to undo the effect of an minit. -func unminit() { -} - -// Called from exitm, but not from drop, to undo the effect of thread-owned -// resources in minit, semacreate, or elsewhere. Do not take locks after calling this. -func mdestroy(mp *m) { -} - -func osinit() { - // https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances - physPageSize = 64 * 1024 - initBloc() - ncpu = 1 - getg().m.procid = 2 -} - -// wasm has no signals -const _NSIG = 0 - -func signame(sig uint32) string { - return "" -} - -func crash() { - *(*int32)(nil) = 0 +func usleep(usec uint32) { + // TODO(neelance): implement usleep } //go:wasmimport gojs runtime.getRandomData +//go:noescape func getRandomData(r []byte) func goenvs() { goenvs_unix() } - -func initsig(preinit bool) { -} - -// May run with m.p==nil, so write barriers are not allowed. -// -//go:nowritebarrier -func newosproc(mp *m) { - throw("newosproc: not implemented") -} - -func setProcessCPUProfiler(hz int32) {} -func setThreadCPUProfiler(hz int32) {} -func sigdisable(uint32) {} -func sigenable(uint32) {} -func sigignore(uint32) {} - -//go:linkname os_sigpipe os.sigpipe -func os_sigpipe() { - throw("too many writes on closed pipe") -} - -//go:nosplit -func cputicks() int64 { - // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand(). - // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler. - return nanotime() -} - -//go:linkname syscall_now syscall.now -func syscall_now() (sec int64, nsec int32) { - sec, nsec, _ = time_now() - return -} - -// gsignalStack is unused on js. -type gsignalStack struct{} - -const preemptMSupported = false - -func preemptM(mp *m) { - // No threads, so nothing to do. -} - -// getcallerfp returns the address of the frame pointer in the callers frame or 0 if not implemented. -func getcallerfp() uintptr { return 0 } diff --git a/src/runtime/os_wasip1.go b/src/runtime/os_wasip1.go new file mode 100644 index 0000000000..cd02a18dfe --- /dev/null +++ b/src/runtime/os_wasip1.go @@ -0,0 +1,251 @@ +// Copyright 2023 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. + +//go:build wasip1 + +package runtime + +import "unsafe" + +// GOARCH=wasm currently has 64 bits pointers, but the WebAssembly host expects +// pointers to be 32 bits so we use this type alias to represent pointers in +// structs and arrays passed as arguments to WASI functions. +// +// Note that the use of an integer type prevents the compiler from tracking +// pointers passed to WASI functions, so we must use KeepAlive to explicitly +// retain the objects that could otherwise be reclaimed by the GC. +type uintptr32 = uint32 + +// https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-size-u32 +type size = uint32 + +// https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-errno-variant +type errno = uint32 + +// https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-filesize-u64 +type filesize = uint64 + +// https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-timestamp-u64 +type timestamp = uint64 + +// https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-clockid-variant +type clockid = uint32 + +const ( + clockRealtime clockid = 0 + clockMonotonic clockid = 1 +) + +// https://github.com/WebAssembly/WASI/blob/a2b96e81c0586125cc4dc79a5be0b78d9a059925/legacy/preview1/docs.md#-iovec-record +type iovec struct { + buf uintptr32 + bufLen size +} + +//go:wasmimport wasi_snapshot_preview1 proc_exit +func exit(code int32) + +//go:wasmimport wasi_snapshot_preview1 args_get +//go:noescape +func args_get(argv *uintptr32, argvBuf *byte) errno + +//go:wasmimport wasi_snapshot_preview1 args_sizes_get +//go:noescape +func args_sizes_get(argc *size, argvBufLen *size) errno + +//go:wasmimport wasi_snapshot_preview1 clock_time_get +//go:noescape +func clock_time_get(clock_id clockid, precision timestamp, time *timestamp) errno + +//go:wasmimport wasi_snapshot_preview1 environ_get +//go:noescape +func environ_get(environ *uintptr32, environBuf *byte) errno + +//go:wasmimport wasi_snapshot_preview1 environ_sizes_get +//go:noescape +func environ_sizes_get(environCount *size, environBufLen *size) errno + +//go:wasmimport wasi_snapshot_preview1 fd_write +//go:noescape +func fd_write(fd int32, iovs *iovec, iovsLen size, nwritten *size) errno + +//go:wasmimport wasi_snapshot_preview1 random_get +//go:noescape +func random_get(buf *byte, bufLen size) errno + +type eventtype = uint8 + +const ( + eventtypeClock eventtype = iota + eventtypeFdRead + eventtypeFdWrite +) + +type eventrwflags = uint16 + +const ( + fdReadwriteHangup eventrwflags = 1 << iota +) + +type userdata = uint64 + +// The go:wasmimport directive currently does not accept values of type uint16 +// in arguments or returns of the function signature. Most WASI imports return +// an errno value, which we have to define as uint32 because of that limitation. +// However, the WASI errno type is intended to be a 16 bits integer, and in the +// event struct the error field should be of type errno. If we used the errno +// type for the error field it would result in a mismatching field alignment and +// struct size because errno is declared as a 32 bits type, so we declare the +// error field as a plain uint16. +type event struct { + userdata userdata + error uint16 + typ eventtype + fdReadwrite eventFdReadwrite +} + +type eventFdReadwrite struct { + nbytes filesize + flags eventrwflags +} + +type subclockflags = uint16 + +const ( + subscriptionClockAbstime subclockflags = 1 << iota +) + +type subscriptionClock struct { + id clockid + timeout timestamp + precision timestamp + flags subclockflags +} + +type subscription struct { + userdata userdata + u subscriptionUnion +} + +type subscriptionUnion [5]uint64 + +func (u *subscriptionUnion) eventtype() *eventtype { + return (*eventtype)(unsafe.Pointer(&u[0])) +} + +func (u *subscriptionUnion) subscriptionClock() *subscriptionClock { + return (*subscriptionClock)(unsafe.Pointer(&u[1])) +} + +//go:wasmimport wasi_snapshot_preview1 poll_oneoff +//go:noescape +func poll_oneoff(in *subscription, out *event, nsubscriptions size, nevents *size) errno + +func write1(fd uintptr, p unsafe.Pointer, n int32) int32 { + iov := iovec{ + buf: uintptr32(uintptr(p)), + bufLen: size(n), + } + var nwritten size + if fd_write(int32(fd), &iov, 1, &nwritten) != 0 { + throw("fd_write failed") + } + return int32(nwritten) +} + +func usleep(usec uint32) { + var in subscription + var out event + var nevents size + + eventtype := in.u.eventtype() + *eventtype = eventtypeClock + + subscription := in.u.subscriptionClock() + subscription.id = clockMonotonic + subscription.timeout = timestamp(usec) * 1e3 + subscription.precision = 1e3 + + if poll_oneoff(&in, &out, 1, &nevents) != 0 { + throw("wasi_snapshot_preview1.poll_oneoff") + } +} + +func getRandomData(r []byte) { + if random_get(&r[0], size(len(r))) != 0 { + throw("random_get failed") + } +} + +func goenvs() { + // arguments + var argc size + var argvBufLen size + if args_sizes_get(&argc, &argvBufLen) != 0 { + throw("args_sizes_get failed") + } + + argslice = make([]string, argc) + if argc > 0 { + argv := make([]uintptr32, argc) + argvBuf := make([]byte, argvBufLen) + if args_get(&argv[0], &argvBuf[0]) != 0 { + throw("args_get failed") + } + + for i := range argslice { + start := argv[i] - uintptr32(uintptr(unsafe.Pointer(&argvBuf[0]))) + end := start + for argvBuf[end] != 0 { + end++ + } + argslice[i] = string(argvBuf[start:end]) + } + } + + // environment + var environCount size + var environBufLen size + if environ_sizes_get(&environCount, &environBufLen) != 0 { + throw("environ_sizes_get failed") + } + + envs = make([]string, environCount) + if environCount > 0 { + environ := make([]uintptr32, environCount) + environBuf := make([]byte, environBufLen) + if environ_get(&environ[0], &environBuf[0]) != 0 { + throw("environ_get failed") + } + + for i := range envs { + start := environ[i] - uintptr32(uintptr(unsafe.Pointer(&environBuf[0]))) + end := start + for environBuf[end] != 0 { + end++ + } + envs[i] = string(environBuf[start:end]) + } + } +} + +func walltime() (sec int64, nsec int32) { + return walltime1() +} + +func walltime1() (sec int64, nsec int32) { + var time timestamp + if clock_time_get(clockRealtime, 0, &time) != 0 { + throw("clock_time_get failed") + } + return int64(time / 1000000000), int32(time % 1000000000) +} + +func nanotime1() int64 { + var time timestamp + if clock_time_get(clockMonotonic, 0, &time) != 0 { + throw("clock_time_get failed") + } + return int64(time) +} diff --git a/src/runtime/os_wasm.go b/src/runtime/os_wasm.go new file mode 100644 index 0000000000..1a6f7d802f --- /dev/null +++ b/src/runtime/os_wasm.go @@ -0,0 +1,152 @@ +// Copyright 2023 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. + +package runtime + +import ( + "runtime/internal/atomic" + "unsafe" +) + +func osinit() { + // https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances + physPageSize = 64 * 1024 + initBloc() + ncpu = 1 + getg().m.procid = 2 +} + +const _SIGSEGV = 0xb + +func sigpanic() { + gp := getg() + if !canpanic() { + throw("unexpected signal during runtime execution") + } + + // js only invokes the exception handler for memory faults. + gp.sig = _SIGSEGV + panicmem() +} + +// func exitThread(wait *uint32) +// FIXME: wasm doesn't have atomic yet +func exitThread(wait *atomic.Uint32) + +type mOS struct{} + +func osyield() + +//go:nosplit +func osyield_no_g() { + osyield() +} + +type sigset struct{} + +// Called to initialize a new m (including the bootstrap m). +// Called on the parent thread (main thread in case of bootstrap), can allocate memory. +func mpreinit(mp *m) { + mp.gsignal = malg(32 * 1024) + mp.gsignal.m = mp +} + +//go:nosplit +func usleep_no_g(usec uint32) { + usleep(usec) +} + +//go:nosplit +func sigsave(p *sigset) { +} + +//go:nosplit +func msigrestore(sigmask sigset) { +} + +//go:nosplit +//go:nowritebarrierrec +func clearSignalHandlers() { +} + +//go:nosplit +func sigblock(exiting bool) { +} + +// Called to initialize a new m (including the bootstrap m). +// Called on the new thread, cannot allocate memory. +func minit() { +} + +// Called from dropm to undo the effect of an minit. +func unminit() { +} + +// Called from exitm, but not from drop, to undo the effect of thread-owned +// resources in minit, semacreate, or elsewhere. Do not take locks after calling this. +func mdestroy(mp *m) { +} + +// wasm has no signals +const _NSIG = 0 + +func signame(sig uint32) string { + return "" +} + +func crash() { + *(*int32)(nil) = 0 +} + +func initsig(preinit bool) { +} + +// May run with m.p==nil, so write barriers are not allowed. +// +//go:nowritebarrier +func newosproc(mp *m) { + throw("newosproc: not implemented") +} + +//go:linkname os_sigpipe os.sigpipe +func os_sigpipe() { + throw("too many writes on closed pipe") +} + +//go:linkname syscall_now syscall.now +func syscall_now() (sec int64, nsec int32) { + sec, nsec, _ = time_now() + return +} + +//go:nosplit +func cputicks() int64 { + // Currently cputicks() is used in blocking profiler and to seed runtime·fastrand(). + // runtime·nanotime() is a poor approximation of CPU ticks that is enough for the profiler. + // TODO: need more entropy to better seed fastrand. + return nanotime() +} + +// gsignalStack is unused on js. +type gsignalStack struct{} + +const preemptMSupported = false + +func preemptM(mp *m) { + // No threads, so nothing to do. +} + +// getcallerfp returns the address of the frame pointer in the callers frame or 0 if not implemented. +func getcallerfp() uintptr { return 0 } + +func setProcessCPUProfiler(hz int32) {} +func setThreadCPUProfiler(hz int32) {} +func sigdisable(uint32) {} +func sigenable(uint32) {} +func sigignore(uint32) {} + +// Stubs so tests can link correctly. These should never be called. +func open(name *byte, mode, perm int32) int32 { panic("not implemented") } +func closefd(fd int32) int32 { panic("not implemented") } +func read(fd int32, p unsafe.Pointer, n int32) int32 { panic("not implemented") } diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go index b19ac16170..56ba6d9803 100644 --- a/src/runtime/pprof/pprof_test.go +++ b/src/runtime/pprof/pprof_test.go @@ -448,6 +448,8 @@ func testCPUProfile(t *testing.T, matches profileMatchFunc, f func(dur time.Dura t.Logf("uname -a: %v", vers) case "plan9": t.Skip("skipping on plan9") + case "wasip1": + t.Skip("skipping on wasip1") } broken := cpuProfilingBroken() @@ -1457,6 +1459,8 @@ func containsCountsLabels(prof *profile.Profile, countLabels map[int64]map[strin } func TestGoroutineProfileConcurrency(t *testing.T) { + testenv.MustHaveParallelism(t) + goroutineProf := Lookup("goroutine") profilerCalls := func(s string) int { @@ -1785,6 +1789,7 @@ func TestCPUProfileLabel(t *testing.T) { } func TestLabelRace(t *testing.T) { + testenv.MustHaveParallelism(t) // Test the race detector annotations for synchronization // between setting labels and consuming them from the // profile. @@ -1809,6 +1814,7 @@ func TestLabelRace(t *testing.T) { } func TestGoroutineProfileLabelRace(t *testing.T) { + testenv.MustHaveParallelism(t) // Test the race detector annotations for synchronization // between setting labels and consuming them from the // goroutine profile. See issue #50292. diff --git a/src/runtime/pprof/proto_test.go b/src/runtime/pprof/proto_test.go index e05a1a60a7..8ec9c9109a 100644 --- a/src/runtime/pprof/proto_test.go +++ b/src/runtime/pprof/proto_test.go @@ -131,7 +131,7 @@ func testPCs(t *testing.T) (addr1, addr2 uint64, map1, map2 *profile.Mapping) { BuildID: peBuildID(exe), HasFunctions: true, } - case "js": + case "js", "wasip1": addr1 = uint64(abi.FuncPCABIInternal(f1)) addr2 = uint64(abi.FuncPCABIInternal(f2)) default: diff --git a/src/runtime/runtime_test.go b/src/runtime/runtime_test.go index 2faf06e2b9..0839cd96b7 100644 --- a/src/runtime/runtime_test.go +++ b/src/runtime/runtime_test.go @@ -207,8 +207,8 @@ func TestSetPanicOnFault(t *testing.T) { // //go:nocheckptr func testSetPanicOnFault(t *testing.T, addr uintptr, nfault *int) { - if GOOS == "js" { - t.Skip("js does not support catching faults") + if GOOS == "js" || GOOS == "wasip1" { + t.Skip(GOOS + " does not support catching faults") } defer func() { diff --git a/src/runtime/semasleep_test.go b/src/runtime/semasleep_test.go index 7262853465..711d5df735 100644 --- a/src/runtime/semasleep_test.go +++ b/src/runtime/semasleep_test.go @@ -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 !plan9 && !windows && !js +//go:build !plan9 && !windows && !js && !wasip1 package runtime_test diff --git a/src/runtime/stubs2.go b/src/runtime/stubs2.go index 0d83deb2af..9637347a35 100644 --- a/src/runtime/stubs2.go +++ b/src/runtime/stubs2.go @@ -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 !aix && !darwin && !js && !openbsd && !plan9 && !solaris && !windows +//go:build !aix && !darwin && !js && !openbsd && !plan9 && !solaris && !wasip1 && !windows package runtime diff --git a/src/runtime/stubs3.go b/src/runtime/stubs3.go index 95306971b4..c3749f34ed 100644 --- a/src/runtime/stubs3.go +++ b/src/runtime/stubs3.go @@ -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 !aix && !darwin && !freebsd && !openbsd && !plan9 && !solaris +//go:build !aix && !darwin && !freebsd && !openbsd && !plan9 && !solaris && !wasip1 package runtime diff --git a/src/runtime/sys_wasm.s b/src/runtime/sys_wasm.s index bd60e1d419..1e73adadd5 100644 --- a/src/runtime/sys_wasm.s +++ b/src/runtime/sys_wasm.s @@ -86,15 +86,6 @@ TEXT runtime·exitThread(SB), NOSPLIT, $0-0 TEXT runtime·osyield(SB), NOSPLIT, $0-0 UNDEF -TEXT runtime·usleep(SB), NOSPLIT, $0-0 - RET // TODO(neelance): implement usleep - -TEXT runtime·currentMemory(SB), NOSPLIT, $0 - Get SP - CurrentMemory - I32Store ret+0(FP) - RET - TEXT runtime·growMemory(SB), NOSPLIT, $0 Get SP I32Load pages+0(FP) diff --git a/src/runtime/timestub2.go b/src/runtime/timestub2.go index b0eae502da..49bfeb60c8 100644 --- a/src/runtime/timestub2.go +++ b/src/runtime/timestub2.go @@ -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 !aix && !darwin && !freebsd && !openbsd && !solaris && !windows && !(linux && amd64) +//go:build !aix && !darwin && !freebsd && !openbsd && !solaris && !wasip1 && !windows && !(linux && amd64) package runtime diff --git a/src/runtime/trace/trace_test.go b/src/runtime/trace/trace_test.go index 1203e34a58..04a43a05f4 100644 --- a/src/runtime/trace/trace_test.go +++ b/src/runtime/trace/trace_test.go @@ -184,8 +184,9 @@ func testBrokenTimestamps(t *testing.T, data []byte) { } func TestTraceStress(t *testing.T) { - if runtime.GOOS == "js" { - t.Skip("no os.Pipe on js") + switch runtime.GOOS { + case "js", "wasip1": + t.Skip("no os.Pipe on " + runtime.GOOS) } if IsEnabled() { t.Skip("skipping because -test.trace is set") @@ -348,8 +349,9 @@ func isMemoryConstrained() bool { // Do a bunch of various stuff (timers, GC, network, etc) in a separate goroutine. // And concurrently with all that start/stop trace 3 times. func TestTraceStressStartStop(t *testing.T) { - if runtime.GOOS == "js" { - t.Skip("no os.Pipe on js") + switch runtime.GOOS { + case "js", "wasip1": + t.Skip("no os.Pipe on " + runtime.GOOS) } if IsEnabled() { t.Skip("skipping because -test.trace is set")