gojs: backfills errno tests and updates links (#1110)

Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
Crypt Keeper
2023-02-09 12:38:22 -05:00
committed by GitHub
parent addd312dda
commit f18bb221c4
17 changed files with 338 additions and 144 deletions

View File

@@ -149,8 +149,8 @@ jobs:
# https://github.com/tinygo-org/tinygo/blob/v0.26.0/Makefile#L271-L319
# Note:
# - index/suffixarray is extremely slow, so skip it.
# - compress/zlib is skipped as it depends on the local files https://github.com/golang/go/blob/40a0986959167e7b82ae16a35a5dd2a347609eff/src/compress/zlib/writer_test.go#L16-L30
# - debug/macho is skipped as it depends on the local files https://github.com/golang/go/blob/40a0986959167e7b82ae16a35a5dd2a347609eff/src/debug/macho/file_test.go#L25
# - compress/zlib is skipped as it depends on the local files https://github.com/golang/go/blob/go1.20/src/compress/zlib/writer_test.go#L16-L30
# - debug/macho is skipped as it depends on the local files https://github.com/golang/go/blob/go1.20/src/debug/macho/file_test.go#L25
run: |
mkdir ${{ env.BINARY_OUT }}
for value in container/heap \

View File

@@ -565,7 +565,7 @@ value (possibly `PWD`). Those unable to control the compiled code should only
use absolute paths in configuration.
See
* https://github.com/golang/go/blob/go1.19rc2/src/syscall/fs_js.go#L324
* https://github.com/golang/go/blob/go1.20/src/syscall/fs_js.go#L324
* https://github.com/WebAssembly/wasi-libc/pull/214#issue-673090117
* https://github.com/ziglang/zig/blob/53a9ee699a35a3d245ab6d1dac1f0687a4dcb42c/src/main.zig#L32
@@ -740,7 +740,7 @@ doesn't and emulating them in spite of that would result in no difference
except hire overhead to the majority of our users.
See https://pubs.opengroup.org/onlinepubs/9699919799/functions/readdir.html
See https://github.com/golang/go/blob/252324e879e32f948d885f787decf8af06f82be9/src/os/dir_unix.go#L108-L111
See https://github.com/golang/go/blob/go1.20/src/os/dir_unix.go#L108-L110
## sys.Walltime and Nanotime
@@ -793,7 +793,7 @@ See https://go.googlesource.com/proposal/+/master/design/12914-monotonic.md
WebAssembly time imports do not have the same concern. In fact even Go's
imports for clocks split walltime from nanotime readings.
See https://github.com/golang/go/blob/252324e879e32f948d885f787decf8af06f82be9/misc/wasm/wasm_exec.js#L243-L255
See https://github.com/golang/go/blob/go1.20/misc/wasm/wasm_exec.js#L243-L255
Finally, Go's clock is not an interface. WebAssembly users who want determinism
or security need to be able to substitute an alternative clock implementation
@@ -807,7 +807,7 @@ value. For now, we return fixed values of 1us for realtime and 1ns for monotonic
often lower precision than monotonic clocks. In the future, this could be improved by having OS+arch specific assembly
to make syscalls.
For example, Go implements time.Now for linux-amd64 with this [assembly](https://github.com/golang/go/blob/f19e4001808863d2ebfe9d1975476513d030c381/src/runtime/time_linux_amd64.s).
For example, Go implements time.Now for linux-amd64 with this [assembly](https://github.com/golang/go/blob/go1.20/src/runtime/time_linux_amd64.s).
Because retrieving resolution is not generally called often, unlike getting time, it could be appropriate to only
implement the fallback logic that does not use VDSO (executing syscalls in user mode). The syscall for clock_getres
is 229 and should be usable. https://pkg.go.dev/syscall#pkg-constants.
@@ -885,7 +885,7 @@ This is due to the same reason for the limitation on the number of functions abo
While the the spec does not clarify a limitation of function stack values, wazero limits this to 2^27 = 134,217,728.
The reason is that we internally represent all the values as 64-bit integers regardless of its types (including f32, f64), and 2^27 values means
1 GiB = (2^30). 1 GiB is the reasonable for most applications [as we see a Goroutine has 250 MB as a limit on the stack for 32-bit arch](https://github.com/golang/go/blob/f296b7a6f045325a230f77e9bda1470b1270f817/src/runtime/proc.go#L120), considering that WebAssembly is (currently) 32-bit environment.
1 GiB = (2^30). 1 GiB is the reasonable for most applications [as we see a Goroutine has 250 MB as a limit on the stack for 32-bit arch](https://github.com/golang/go/blob/go1.20/src/runtime/proc.go#L152-L159), considering that WebAssembly is (currently) 32-bit environment.
All the functions are statically analyzed at module instantiation phase, and if a function can potentially reach this limit, an error is returned.
@@ -948,6 +948,6 @@ In lieu of formal documentation, we infer this pattern works from other sources
* `sync.WaitGroup` by definition must support calling `Add` from other goroutines. Internally, it uses atomics.
* rsc in golang/go#5045 writes "atomics guarantee sequential consistency among the atomic variables".
See https://github.com/golang/go/blob/011fd002457da0823da5f06b099fcf6e21444b00/src/sync/waitgroup.go#L64
See https://github.com/golang/go/blob/go1.20/src/sync/waitgroup.go#L64
See https://github.com/golang/go/issues/5045#issuecomment-252730563
See https://www.youtube.com/watch?v=VmrEG-3bWyM

View File

@@ -18,4 +18,4 @@ Accordingly, wazero cannot guarantee this will work from release to release,
or that usage will be relatively free of bugs. Due to this and the
relatively high implementation overhead, most will choose TinyGo instead.
[1]: https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js
[1]: https://github.com/golang/go/blob/go1.20/misc/wasm/wasm_exec.js

114
internal/gojs/errno.go Normal file
View File

@@ -0,0 +1,114 @@
package gojs
import (
"errors"
"io/fs"
"os"
"syscall"
)
// Errno is a (GOARCH=wasm) error, which must match a key in mapJSError.
//
// See https://github.com/golang/go/blob/go1.20/src/syscall/tables_js.go#L371-L494
type Errno struct {
s string
}
// Error implements error.
func (e *Errno) Error() string {
return e.s
}
// This order match constants from wasi_snapshot_preview1.ErrnoSuccess for
// easier maintenance.
var (
// ErrnoBadf Bad file descriptor.
ErrnoBadf = &Errno{"EBADF"}
// ErrnoExist File exists.
ErrnoExist = &Errno{"EEXIST"}
// ErrnoInval Invalid argument.
ErrnoInval = &Errno{"EINVAL"}
// ErrnoIo I/O error.
ErrnoIo = &Errno{"EIO"}
// ErrnoIsdir Is a directory.
ErrnoIsdir = &Errno{"EISDIR"}
// ErrnoLoop Too many levels of symbolic links.
ErrnoLoop = &Errno{"ELOOP"}
// ErrnoNametoolong Filename too long.
ErrnoNametoolong = &Errno{"ENAMETOOLONG"}
// ErrnoNoent No such file or directory.
ErrnoNoent = &Errno{"ENOENT"}
// ErrnoNosys function not supported.
ErrnoNosys = &Errno{"ENOSYS"}
// ErrnoNotdir Not a directory or a symbolic link to a directory.
ErrnoNotdir = &Errno{"ENOTDIR"}
// ErrnoNotempty Directory not empty.
ErrnoNotempty = &Errno{"ENOTEMPTY"}
// ErrnoNotsup Not supported, or operation not supported on socket.
ErrnoNotsup = &Errno{"ENOTSUP"}
// ErrnoPerm Operation not permitted.
ErrnoPerm = &Errno{"EPERM"}
)
// ToErrno maps I/O errors as the message must be the code, ex. "EINVAL", not
// the message, e.g. "invalid argument".
//
// This should match wasi_snapshot_preview1.ToErrno for maintenance ease.
func ToErrno(err error) *Errno {
if pe, ok := err.(*os.PathError); ok {
err = pe.Unwrap()
}
if se, ok := err.(syscall.Errno); ok {
return errnoFromSyscall(se)
}
// Below are all the fs.ErrXXX in fs.go. errors.Is is more expensive, so
// try it last. Note: Once we have our own file type, we should never see
// these.
switch {
case errors.Is(err, fs.ErrInvalid):
return ErrnoInval
case errors.Is(err, fs.ErrPermission):
return ErrnoPerm
case errors.Is(err, fs.ErrExist):
return ErrnoExist
case errors.Is(err, fs.ErrNotExist):
return ErrnoNoent
case errors.Is(err, fs.ErrClosed):
return ErrnoBadf
default:
return ErrnoIo
}
}
func errnoFromSyscall(errno syscall.Errno) *Errno {
switch errno {
case syscall.EBADF:
return ErrnoBadf
case syscall.EEXIST:
return ErrnoExist
case syscall.EINVAL:
return ErrnoInval
case syscall.EIO:
return ErrnoIo
case syscall.EISDIR:
return ErrnoIsdir
case syscall.ELOOP:
return ErrnoLoop
case syscall.ENAMETOOLONG:
return ErrnoNametoolong
case syscall.ENOENT:
return ErrnoNoent
case syscall.ENOSYS:
return ErrnoNosys
case syscall.ENOTDIR:
return ErrnoNotdir
case syscall.ENOTEMPTY:
return ErrnoNotempty
case syscall.ENOTSUP:
return ErrnoNotsup
case syscall.EPERM:
return ErrnoPerm
default:
return ErrnoIo
}
}

139
internal/gojs/errno_test.go Normal file
View File

@@ -0,0 +1,139 @@
package gojs
import (
"errors"
"fmt"
"io/fs"
"os"
"syscall"
"testing"
"github.com/tetratelabs/wazero/internal/testing/require"
)
func TestToErrno(t *testing.T) {
tests := []struct {
name string
input error
expected *Errno
}{
{
name: "syscall.EBADF",
input: syscall.EBADF,
expected: ErrnoBadf,
},
{
name: "syscall.EEXIST",
input: syscall.EEXIST,
expected: ErrnoExist,
},
{
name: "syscall.EINVAL",
input: syscall.EINVAL,
expected: ErrnoInval,
},
{
name: "syscall.EIO",
input: syscall.EIO,
expected: ErrnoIo,
},
{
name: "syscall.EISDIR",
input: syscall.EISDIR,
expected: ErrnoIsdir,
},
{
name: "syscall.ELOOP",
input: syscall.ELOOP,
expected: ErrnoLoop,
},
{
name: "syscall.ENAMETOOLONG",
input: syscall.ENAMETOOLONG,
expected: ErrnoNametoolong,
},
{
name: "syscall.ENOENT",
input: syscall.ENOENT,
expected: ErrnoNoent,
},
{
name: "syscall.ENOSYS",
input: syscall.ENOSYS,
expected: ErrnoNosys,
},
{
name: "syscall.ENOTDIR",
input: syscall.ENOTDIR,
expected: ErrnoNotdir,
},
{
name: "syscall.ENOTEMPTY",
input: syscall.ENOTEMPTY,
expected: ErrnoNotempty,
},
{
name: "syscall.ENOTSUP",
input: syscall.ENOTSUP,
expected: ErrnoNotsup,
},
{
name: "syscall.EPERM",
input: syscall.EPERM,
expected: ErrnoPerm,
},
{
name: "syscall.Errno unexpected == ErrnoIo",
input: syscall.Errno(0xfe),
expected: ErrnoIo,
},
{
name: "PathError ErrInvalid",
input: &os.PathError{Err: fs.ErrInvalid},
expected: ErrnoInval,
},
{
name: "PathError ErrPermission",
input: &os.PathError{Err: fs.ErrPermission},
expected: ErrnoPerm,
},
{
name: "PathError ErrExist",
input: &os.PathError{Err: fs.ErrExist},
expected: ErrnoExist,
},
{
name: "PathError ErrNotExist",
input: &os.PathError{Err: fs.ErrNotExist},
expected: ErrnoNoent,
},
{
name: "PathError ErrClosed",
input: &os.PathError{Err: fs.ErrClosed},
expected: ErrnoBadf,
},
{
name: "PathError unknown == ErrnoIo",
input: &os.PathError{Err: errors.New("ice cream")},
expected: ErrnoIo,
},
{
name: "unknown == ErrnoIo",
input: errors.New("ice cream"),
expected: ErrnoIo,
},
{
name: "very wrapped unknown == ErrnoIo",
input: fmt.Errorf("%w", fmt.Errorf("%w", fmt.Errorf("%w", errors.New("ice cream")))),
expected: ErrnoIo,
},
}
for _, tt := range tests {
tc := tt
t.Run(tc.name, func(t *testing.T) {
errno := ToErrno(tc.input)
require.Equal(t, tc.expected, errno)
})
}
}

View File

@@ -411,7 +411,7 @@ func (processChdir) invoke(ctx context.Context, mod api.Module, args ...interfac
path := args[0].(string)
if s, err := syscallStat(mod, path); err != nil {
return nil, mapJSError(err)
return nil, ToErrno(err)
} else if !s.isDir {
return nil, syscall.ENOTDIR
} else {

View File

@@ -148,10 +148,10 @@ func (s *stack) SetResultUint32(i int, v uint32) {
// GetSP gets the stack pointer, which is needed prior to storing a value when
// in an operation that can trigger a Go event handler.
//
// See https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L210-L213
// See https://github.com/golang/go/blob/go1.20/misc/wasm/wasm_exec.js#L210-L213
func GetSP(mod api.Module) uint32 {
// Cheat by reading global[0] directly instead of through a function proxy.
// https://github.com/golang/go/blob/go1.19/src/runtime/rt0_js_wasm.s#L87-L90
// https://github.com/golang/go/blob/go1.20/src/runtime/rt0_js_wasm.s#L87-L90
return uint32(mod.(*wasm.CallContext).GlobalVal(0))
}

View File

@@ -45,7 +45,7 @@ func (v *jsVal) addFunction(method string, fn jsFn) *jsVal {
v.functions[method] = fn
// If fn returns an error, js.Call does a type lookup to verify it is a
// function.
// See https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L389
// See https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go#L389
v.properties[method] = fn
return v
}

View File

@@ -14,14 +14,14 @@ import (
// Debug has unknown use, so stubbed.
//
// See https://github.com/golang/go/blob/go1.19/src/cmd/link/internal/wasm/asm.go#L133-L138
// See https://github.com/golang/go/blob/go1.20/src/cmd/link/internal/wasm/asm.go#L131-L136
var Debug = goarch.StubFunction(custom.NameDebug)
// TODO: should this call runtime.Breakpoint()?
// WasmExit implements runtime.wasmExit which supports runtime.exit.
//
// See https://github.com/golang/go/blob/go1.19/src/runtime/sys_wasm.go#L28
// See https://github.com/golang/go/blob/go1.20/src/runtime/sys_wasm.go#L24
var WasmExit = goarch.NewFunc(custom.NameRuntimeWasmExit, wasmExit)
func wasmExit(ctx context.Context, mod api.Module, stack goarch.Stack) {
@@ -34,7 +34,7 @@ func wasmExit(ctx context.Context, mod api.Module, stack goarch.Stack) {
// WasmWrite implements runtime.wasmWrite which supports runtime.write and
// runtime.writeErr. This implements `println`.
//
// See https://github.com/golang/go/blob/go1.19/src/runtime/os_js.go#L29
// See https://github.com/golang/go/blob/go1.20/src/runtime/os_js.go#L30
var WasmWrite = goarch.NewFunc(custom.NameRuntimeWasmWrite, wasmWrite)
func wasmWrite(_ context.Context, mod api.Module, stack goarch.Stack) {
@@ -52,7 +52,7 @@ func wasmWrite(_ context.Context, mod api.Module, stack goarch.Stack) {
// ResetMemoryDataView signals wasm.OpcodeMemoryGrow happened, indicating any
// cached view of memory should be reset.
//
// See https://github.com/golang/go/blob/go1.19/src/runtime/mem_js.go#L82
// See https://github.com/golang/go/blob/go1.20/src/runtime/mem_js.go#L82
var ResetMemoryDataView = goarch.NewFunc(custom.NameRuntimeResetMemoryDataView, resetMemoryDataView)
func resetMemoryDataView(context.Context, api.Module, goarch.Stack) {
@@ -63,7 +63,7 @@ func resetMemoryDataView(context.Context, api.Module, goarch.Stack) {
// Nanotime1 implements runtime.nanotime which supports time.Since.
//
// See https://github.com/golang/go/blob/go1.19/src/runtime/sys_wasm.s#L184
// See https://github.com/golang/go/blob/go1.20/src/runtime/sys_wasm.s#L117
var Nanotime1 = goarch.NewFunc(custom.NameRuntimeNanotime1, nanotime1)
func nanotime1(_ context.Context, mod api.Module, stack goarch.Stack) {
@@ -74,7 +74,7 @@ func nanotime1(_ context.Context, mod api.Module, stack goarch.Stack) {
// Walltime implements runtime.walltime which supports time.Now.
//
// See https://github.com/golang/go/blob/go1.19/src/runtime/sys_wasm.s#L188
// See https://github.com/golang/go/blob/go1.20/src/runtime/sys_wasm.s#L121
var Walltime = goarch.NewFunc(custom.NameRuntimeWalltime, walltime)
func walltime(_ context.Context, mod api.Module, stack goarch.Stack) {
@@ -90,7 +90,7 @@ func walltime(_ context.Context, mod api.Module, stack goarch.Stack) {
// Unlike other most functions prefixed by "runtime.", this both launches a
// goroutine and invokes code compiled into wasm "resume".
//
// See https://github.com/golang/go/blob/go1.19/src/runtime/sys_wasm.s#L192
// See https://github.com/golang/go/blob/go1.20/src/runtime/sys_wasm.s#L125
var ScheduleTimeoutEvent = goarch.NewFunc(custom.NameRuntimeScheduleTimeoutEvent, scheduleTimeoutEvent)
// Note: Signal handling is not implemented in GOOS=js.
@@ -122,7 +122,7 @@ func scheduleTimeoutEvent(ctx context.Context, mod api.Module, stack goarch.Stac
// ClearTimeoutEvent implements runtime.clearTimeoutEvent which supports
// runtime.notetsleepg used by runtime.signal_recv.
//
// See https://github.com/golang/go/blob/go1.19/src/runtime/sys_wasm.s#L196
// See https://github.com/golang/go/blob/go1.20/src/runtime/sys_wasm.s#L129
var ClearTimeoutEvent = goarch.NewFunc(custom.NameRuntimeClearTimeoutEvent, clearTimeoutEvent)
// Note: Signal handling is not implemented in GOOS=js.
@@ -138,7 +138,7 @@ func clearTimeoutEvent(ctx context.Context, _ api.Module, stack goarch.Stack) {
// GetRandomData implements runtime.getRandomData, which initializes the seed
// for runtime.fastrand.
//
// See https://github.com/golang/go/blob/go1.19/src/runtime/sys_wasm.s#L200
// See https://github.com/golang/go/blob/go1.20/src/runtime/sys_wasm.s#L133
var GetRandomData = goarch.NewFunc(custom.NameRuntimeGetRandomData, getRandomData)
func getRandomData(_ context.Context, mod api.Module, stack goarch.Stack) {

View File

@@ -63,7 +63,7 @@ var NaN = math.NaN()
// LoadValue reads up to 8 bytes at the memory offset `addr` to return the
// value written by storeValue.
//
// See https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L122-L133
// See https://github.com/golang/go/blob/go1.20/misc/wasm/wasm_exec.js#L122-L133
func LoadValue(ctx context.Context, ref goos.Ref) interface{} { //nolint
switch ref {
case 0:
@@ -110,12 +110,12 @@ func LoadValue(ctx context.Context, ref goos.Ref) interface{} { //nolint
}
}
// storeRef stores a value prior to returning to wasm from a host function.
// storeValue stores a value prior to returning to wasm from a host function.
// This returns 8 bytes to represent either the value or a reference to it.
// Any side effects besides memory must be cleaned up on wasmExit.
//
// See https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L135-L183
func storeRef(ctx context.Context, v interface{}) goos.Ref { //nolint
// See https://github.com/golang/go/blob/de4748c47c67392a57f250714509f590f68ad395/misc/wasm/wasm_exec.js#L135-L183
func storeValue(ctx context.Context, v interface{}) goos.Ref { //nolint
// allow-list because we control all implementations
if v == goos.Undefined {
return goos.RefValueUndefined

View File

@@ -2,11 +2,8 @@ package gojs
import (
"context"
"errors"
"fmt"
"io/fs"
"net/http"
"syscall"
"github.com/tetratelabs/wazero/api"
"github.com/tetratelabs/wazero/internal/gojs/custom"
@@ -18,7 +15,7 @@ import (
// FinalizeRef implements js.finalizeRef, which is used as a
// runtime.SetFinalizer on the given reference.
//
// See https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L61
// See https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go#L61
var FinalizeRef = goos.NewFunc(custom.NameSyscallFinalizeRef, finalizeRef)
func finalizeRef(ctx context.Context, _ api.Module, stack goos.Stack) {
@@ -32,14 +29,14 @@ func finalizeRef(ctx context.Context, _ api.Module, stack goos.Stack) {
// StringVal implements js.stringVal, which is used to load the string for
// `js.ValueOf(x)`. For example, this is used when setting HTTP headers.
//
// See https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L212
// and https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L305-L308
// See https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go#L212
// and https://github.com/golang/go/blob/go1.20/misc/wasm/wasm_exec.js#L305-L308
var StringVal = goos.NewFunc(custom.NameSyscallStringVal, stringVal)
func stringVal(ctx context.Context, mod api.Module, stack goos.Stack) {
x := stack.ParamString(mod.Memory(), 0)
r := storeRef(ctx, x)
r := storeValue(ctx, x)
stack.SetResultRef(0, r)
}
@@ -48,8 +45,8 @@ func stringVal(ctx context.Context, mod api.Module, stack goos.Stack) {
// by name, e.g. `v.Get("address")`. Notably, this is used by js.handleEvent to
// get the pending event.
//
// See https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L295
// and https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L311-L316
// See https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go#L295
// and https://github.com/golang/go/blob/go1.20/misc/wasm/wasm_exec.js#L311-L316
var ValueGet = goos.NewFunc(custom.NameSyscallValueGet, valueGet)
func valueGet(ctx context.Context, mod api.Module, stack goos.Stack) {
@@ -64,7 +61,7 @@ func valueGet(ctx context.Context, mod api.Module, stack goos.Stack) {
case "message": // js (GOOS=js) error, can be anything.
result = e.Error()
case "code": // syscall (GOARCH=wasm) error, must match key in mapJSError in fs_js.go
result = mapJSError(e).Error()
result = ToErrno(e).Error()
default:
panic(fmt.Errorf("TODO: valueGet(v=%v, p=%s)", v, p))
}
@@ -72,7 +69,7 @@ func valueGet(ctx context.Context, mod api.Module, stack goos.Stack) {
panic(fmt.Errorf("TODO: valueGet(v=%v, p=%s)", v, p))
}
r := storeRef(ctx, result)
r := storeValue(ctx, result)
stack.SetResultRef(0, r)
}
@@ -80,8 +77,8 @@ func valueGet(ctx context.Context, mod api.Module, stack goos.Stack) {
// by name, e.g. `v.Set("address", a)`. Notably, this is used by js.handleEvent
// set the event result.
//
// See https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L309
// and https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L318-L322
// See https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go#L309
// and https://github.com/golang/go/blob/go1.20/misc/wasm/wasm_exec.js#L318-L322
var ValueSet = goos.NewFunc(custom.NameSyscallValueSet, valueSet)
func valueSet(ctx context.Context, mod api.Module, stack goos.Stack) {
@@ -114,15 +111,15 @@ func valueSet(ctx context.Context, mod api.Module, stack goos.Stack) {
// ValueDelete is stubbed as it isn't used in Go's main source tree.
//
// See https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L321
// See https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go#L321
var ValueDelete = goarch.StubFunction(custom.NameSyscallValueDelete)
// ValueIndex implements js.valueIndex, which is used to load a js.Value property
// by index, e.g. `v.Index(0)`. Notably, this is used by js.handleEvent to read
// event arguments
//
// See https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L334
// and https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L331-L334
// See https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go#L334
// and https://github.com/golang/go/blob/go1.20/misc/wasm/wasm_exec.js#L331-L334
var ValueIndex = goos.NewFunc(custom.NameSyscallValueIndex, valueIndex)
func valueIndex(ctx context.Context, _ api.Module, stack goos.Stack) {
@@ -131,21 +128,21 @@ func valueIndex(ctx context.Context, _ api.Module, stack goos.Stack) {
result := v.(*objectArray).slice[i]
r := storeRef(ctx, result)
r := storeValue(ctx, result)
stack.SetResultRef(0, r)
}
// ValueSetIndex is stubbed as it is only used for js.ValueOf when the input is
// []interface{}, which doesn't appear to occur in Go's source tree.
//
// See https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L348
// See https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go#L348
var ValueSetIndex = goarch.StubFunction(custom.NameSyscallValueSetIndex)
// ValueCall implements js.valueCall, which is used to call a js.Value function
// by name, e.g. `document.Call("createElement", "div")`.
//
// See https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L394
// and https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L343-L358
// See https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go#L394
// and https://github.com/golang/go/blob/go1.20/misc/wasm/wasm_exec.js#L343-L358
var ValueCall = goos.NewFunc(custom.NameSyscallValueCall, valueCall)
func valueCall(ctx context.Context, mod api.Module, stack goos.Stack) {
@@ -164,9 +161,9 @@ func valueCall(ctx context.Context, mod api.Module, stack goos.Stack) {
var res goos.Ref
var ok bool
if result, err := c.call(ctx, mod, vRef, m, args...); err != nil {
res = storeRef(ctx, err)
res = storeValue(ctx, err)
} else {
res = storeRef(ctx, result)
res = storeValue(ctx, result)
ok = true
}
@@ -177,14 +174,14 @@ func valueCall(ctx context.Context, mod api.Module, stack goos.Stack) {
// ValueInvoke is stubbed as it isn't used in Go's main source tree.
//
// See https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L413
// See https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go#L413
var ValueInvoke = goarch.StubFunction(custom.NameSyscallValueInvoke)
// ValueNew implements js.valueNew, which is used to call a js.Value, e.g.
// `array.New(2)`.
//
// See https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L432
// and https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L380-L391
// See https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go#L432
// and https://github.com/golang/go/blob/go1.20/misc/wasm/wasm_exec.js#L378-L392
var ValueNew = goos.NewFunc(custom.NameSyscallValueNew, valueNew)
func valueNew(ctx context.Context, mod api.Module, stack goos.Stack) {
@@ -198,7 +195,7 @@ func valueNew(ctx context.Context, mod api.Module, stack goos.Stack) {
switch vRef {
case goos.RefArrayConstructor:
result := &objectArray{}
res = storeRef(ctx, result)
res = storeValue(ctx, result)
ok = true
case goos.RefUint8ArrayConstructor:
var result interface{}
@@ -212,15 +209,15 @@ func valueNew(ctx context.Context, mod api.Module, stack goos.Stack) {
} else {
panic(fmt.Errorf("TODO: valueNew(v=%v, args=%v)", vRef, args))
}
res = storeRef(ctx, result)
res = storeValue(ctx, result)
ok = true
case goos.RefObjectConstructor:
result := &object{properties: map[string]interface{}{}}
res = storeRef(ctx, result)
res = storeValue(ctx, result)
ok = true
case goos.RefHttpHeadersConstructor:
result := &headers{headers: http.Header{}}
res = storeRef(ctx, result)
res = storeValue(ctx, result)
ok = true
case goos.RefJsDateConstructor:
res = goos.RefJsDate
@@ -237,8 +234,8 @@ func valueNew(ctx context.Context, mod api.Module, stack goos.Stack) {
// ValueLength implements js.valueLength, which is used to load the length
// property of a value, e.g. `array.length`.
//
// See https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L372
// and https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L396-L397
// See https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go#L372
// and https://github.com/golang/go/blob/go1.20/misc/wasm/wasm_exec.js#L395-L398
var ValueLength = goos.NewFunc(custom.NameSyscallValueLength, valueLength)
func valueLength(ctx context.Context, _ api.Module, stack goos.Stack) {
@@ -254,8 +251,8 @@ func valueLength(ctx context.Context, _ api.Module, stack goos.Stack) {
// number types. Notably, http.Transport uses this in RoundTrip to coerce the
// URL to a string.
//
// See https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L531
// and https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L402-L405
// See https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go#L531
// and https://github.com/golang/go/blob/go1.20/misc/wasm/wasm_exec.js#L401-L406
var ValuePrepareString = goos.NewFunc(custom.NameSyscallValuePrepareString, valuePrepareString)
func valuePrepareString(ctx context.Context, _ api.Module, stack goos.Stack) {
@@ -263,7 +260,7 @@ func valuePrepareString(ctx context.Context, _ api.Module, stack goos.Stack) {
s := valueString(v)
sRef := storeRef(ctx, s)
sRef := storeValue(ctx, s)
sLen := uint32(len(s))
stack.SetResultRef(0, sRef)
@@ -273,9 +270,8 @@ func valuePrepareString(ctx context.Context, _ api.Module, stack goos.Stack) {
// ValueLoadString implements js.valueLoadString, which is used copy a string
// value for `o.String()`.
//
// See https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L533
//
// https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L410-L412
// See https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go#L533
// and https://github.com/golang/go/blob/go1.20/misc/wasm/wasm_exec.js#L409-L413
var ValueLoadString = goos.NewFunc(custom.NameSyscallValueLoadString, valueLoadString)
func valueLoadString(ctx context.Context, mod api.Module, stack goos.Stack) {
@@ -288,7 +284,7 @@ func valueLoadString(ctx context.Context, mod api.Module, stack goos.Stack) {
// ValueInstanceOf is stubbed as it isn't used in Go's main source tree.
//
// See https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L543
// See https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go#L543
var ValueInstanceOf = goarch.StubFunction(custom.NameSyscallValueInstanceOf)
// CopyBytesToGo copies a JavaScript managed byte array to linear memory.
@@ -299,8 +295,8 @@ var ValueInstanceOf = goarch.StubFunction(custom.NameSyscallValueInstanceOf)
// - n is the count of bytes written.
// - ok is false if the src was not a uint8Array.
//
// See https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L569
// and https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L424-L433
// See https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go#L569
// and https://github.com/golang/go/blob/go1.20/misc/wasm/wasm_exec.js#L437-L449
var CopyBytesToGo = goos.NewFunc(custom.NameSyscallCopyBytesToGo, copyBytesToGo)
func copyBytesToGo(ctx context.Context, mod api.Module, stack goos.Stack) {
@@ -327,8 +323,8 @@ func copyBytesToGo(ctx context.Context, mod api.Module, stack goos.Stack) {
// - n is the count of bytes written.
// - ok is false if the dst was not a uint8Array.
//
// See https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L583
// and https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L438-L448
// See https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go#L583
// and https://github.com/golang/go/blob/go1.20/misc/wasm/wasm_exec.js#L438-L448
var CopyBytesToJS = goos.NewFunc(custom.NameSyscallCopyBytesToJS, copyBytesToJS)
func copyBytesToJS(ctx context.Context, mod api.Module, stack goos.Stack) {
@@ -349,61 +345,6 @@ func copyBytesToJS(ctx context.Context, mod api.Module, stack goos.Stack) {
stack.SetResultBool(1, ok)
}
// syscallErr is a (GOARCH=wasm) error, which must match a key in mapJSError.
//
// See https://github.com/golang/go/blob/go1.19/src/syscall/tables_js.go#L371-L494
type syscallErr struct {
s string
}
// Error implements error.
func (e *syscallErr) Error() string {
return e.s
}
// While usually I/O returns the correct errors, being explicit helps reduce
// chance of problems.
var (
ebadf = &syscallErr{"EBADF"}
einval = &syscallErr{"EBADF"}
eisdir = &syscallErr{"EISDIR"}
eexist = &syscallErr{"EEXIST"}
enoent = &syscallErr{"ENOENT"}
enosys = &syscallErr{"ENOSYS"}
enotdir = &syscallErr{"ENOTDIR"}
enotempty = &syscallErr{"ENOTEMPTY"}
)
// mapJSError maps I/O errors as the message must be the code, ex. "EINVAL",
// not the message, ex. "invalid argument".
func mapJSError(err error) *syscallErr {
if e, ok := err.(*syscallErr); ok {
return e
}
switch {
case errors.Is(err, syscall.EBADF), errors.Is(err, fs.ErrClosed):
return ebadf
case errors.Is(err, syscall.EINVAL), errors.Is(err, fs.ErrInvalid):
return einval
case errors.Is(err, syscall.EISDIR):
return eisdir
case errors.Is(err, syscall.ENOTEMPTY):
return enotempty
case errors.Is(err, syscall.EEXIST), errors.Is(err, fs.ErrExist):
return eexist
case errors.Is(err, syscall.ENOENT), errors.Is(err, fs.ErrNotExist):
return enoent
case errors.Is(err, syscall.ENOSYS):
return enosys
case errors.Is(err, syscall.ENOTDIR):
return enotdir
default:
// panic so we can map the error before reaching JavaScript, which
// can't see the error message as it just prints "object".
panic(fmt.Errorf("unmapped error: %v", err))
}
}
// funcWrapper is the result of go's js.FuncOf ("_makeFuncWrapper" here).
//
// This ID is managed on the Go side an increments (possibly rolling over).

View File

@@ -66,7 +66,7 @@ func runCallBenchmark(rt Runtime, rtCfg *RuntimeConfig, call func(Module, int) e
result := testing.Benchmark(func(b *testing.B) {
benchmarkCall(b, rt, rtCfg, call)
})
// https://github.com/golang/go/blob/fd09e88722e0af150bf8960e95e8da500ad91001/src/testing/benchmark.go#L428-L432
// https://github.com/golang/go/blob/go1.20/src/testing/benchmark.go#L428-L432
nsOp := float64(result.T.Nanoseconds()) / float64(result.N)
return nsOp
}

View File

@@ -109,7 +109,7 @@ func LoadUint32(buf []byte) (ret uint32, bytesRead uint64, err error) {
}
func decodeUint32(next nextByte) (ret uint32, bytesRead uint64, err error) {
// Derived from https://github.com/golang/go/blob/aafad20b617ee63d58fcd4f6e0d98fe27760678c/src/encoding/binary/varint.go
// Derived from https://github.com/golang/go/blob/go1.20/src/encoding/binary/varint.go
// with the modification on the overflow handling tailored for 32-bits.
var s uint32
for i := 0; i < maxVarintLen32; i++ {
@@ -136,7 +136,7 @@ func LoadUint64(buf []byte) (ret uint64, bytesRead uint64, err error) {
return 0, 0, io.EOF
}
// Derived from https://github.com/golang/go/blob/aafad20b617ee63d58fcd4f6e0d98fe27760678c/src/encoding/binary/varint.go
// Derived from https://github.com/golang/go/blob/go1.20/src/encoding/binary/varint.go
var s uint64
for i := 0; i < maxVarintLen64; i++ {
if i >= bufLen {

View File

@@ -37,7 +37,7 @@ func OpenFile(name string, flag int, perm fs.FileMode) (*os.File, error) {
}
// The following is lifted from syscall_windows.go to add support for setting FILE_SHARE_DELETE.
// https://github.com/golang/go/blob/go1.19.5/src/syscall/syscall_windows.go#L307-L375
// https://github.com/golang/go/blob/go1.20/src/syscall/syscall_windows.go#L308-L379
func open(path string, mode int, perm uint32) (fd syscall.Handle, err error) {
mode &= ^(O_DIRECTORY | O_NOFOLLOW) // erase placeholders
if len(path) == 0 {

View File

@@ -45,7 +45,7 @@ func stat(f fs.File, t os.FileInfo) (atimeNsec, mtimeNsec, ctimeNsec int64, nlin
if err = syscall.GetFileInformationByHandle(handle, &info); err != nil {
// If the file descriptor is already closed, we have to re-open just like
// os.Stat does to allow the results on the closed files.
// https://github.com/golang/go/blob/go1.19.5/src/os/stat_windows.go#L93-L101
// https://github.com/golang/go/blob/go1.20/src/os/stat_windows.go#L86
//
// TODO: once we have our File/Sta type, this shouldn't be necessary.
// But for now, ignore the error to pass the std library test for bad file descriptor.

View File

@@ -367,7 +367,7 @@ func (c *FSContext) ChangeOpenFlag(fd uint32, flag int) error {
// syscall package, the feasibility of doing so really depends on the platform. For examples:
//
// * This appendMode (bool) cannot be changed later.
// https://github.com/golang/go/blob/2da8a55584aa65ce1b67431bb8ecebf66229d462/src/os/file_unix.go#L60
// https://github.com/golang/go/blob/go1.20/src/os/file_unix.go#L60
// * On Windows, re-opening it is the only way to emulate the behavior.
// https://github.com/bytecodealliance/system-interface/blob/62b97f9776b86235f318c3a6e308395a1187439b/src/fs/fd_flags.rs#L196
//

View File

@@ -348,25 +348,25 @@ through any file system calls without filtering. Specifically,
`globalThis.fs = require("fs")` allows code compiled to wasm any file access
the host operating system's underlying controls permit.
[1]: https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js
[2]: https://github.com/golang/go/blob/go1.19/src/cmd/link/internal/wasm/asm.go
[1]: https://github.com/golang/go/blob/go1.20/misc/wasm/wasm_exec.js
[2]: https://github.com/golang/go/blob/go1.20/src/cmd/link/internal/wasm/asm.go
[3]: https://github.com/WebAssembly/wabt
[4]: https://github.com/golang/proposal/blob/master/design/42372-wasmexport.md
[5]: https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go
[6]: https://github.com/golang/go/blob/go1.19/src/cmd/internal/obj/wasm/wasmobj.go#L794-L812
[7]: https://github.com/golang/go/blob/go1.19/src/runtime/rt0_js_wasm.s#L17-L21
[8]: https://github.com/golang/go/blob/go1.19/src/syscall/syscall_js.go#L292-L306
[9]: https://github.com/golang/go/blob/go1.19/src/syscall/js/func.go#L41-L44
[10]: https://github.com/golang/go/blob/go1.19/src/runtime/internal/atomic/atomic_wasm.go#L5-L6
[4]: https://github.com/golang/proposal/blob/6130999a9134112b156deb52da81a3cf219a6509/design/42372-wasmexport.md
[5]: https://github.com/golang/go/blob/go1.20/src/syscall/js/js.go
[6]: https://github.com/golang/go/blob/go1.20/src/cmd/internal/obj/wasm/wasmobj.go#L796-L810
[7]: https://github.com/golang/go/blob/go1.20/src/runtime/rt0_js_wasm.s#L17-L21
[8]: https://github.com/golang/go/blob/go1.20/src/syscall/syscall_js.go#L292-L306
[9]: https://github.com/golang/go/blob/go1.20/src/syscall/js/func.go#L41-L51
[10]: https://github.com/golang/go/blob/go1.20/src/runtime/internal/atomic/atomic_wasm.go#L5-L6
[11]: https://github.com/WebAssembly/proposals
[12]: https://github.com/golang/go/blob/go1.19/src/cmd/link/internal/ld/data.go#L2457
[13]: https://github.com/golang/go/blob/go1.19/src/syscall/tables_js.go#L371-L494
[12]: https://github.com/golang/go/blob/go1.20/src/cmd/link/internal/ld/data.go#L2457
[13]: https://github.com/golang/go/blob/go1.20/src/syscall/tables_js.go#L371-L494
[14]: https://github.com/tetratelabs/wazero/tree/main/imports/go/example
[15]: https://www.w3.org/TR/2019/REC-wasm-core-1-20191205/
[16]: https://github.com/golang/go/blob/go1.19/src/internal/buildcfg/cfg.go#L133-L147
[16]: https://github.com/golang/go/blob/go1.20/src/internal/buildcfg/cfg.go#L136-L150
[17]: https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/nontrapping-float-to-int-conversion/Overview.md
[18]: https://github.com/WebAssembly/spec/blob/wg-2.0.draft1/proposals/sign-extension-ops/Overview.md
[19]: https://www.w3.org/TR/2022/WD-wasm-core-2-20220419/
[20]: https://github.com/golang/go/blob/go1.19/CONTRIBUTING.md
[21]: https://github.com/golang/go/blob/go1.19/src/os/os_test.go#L110-L116
[22]: https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec_node.js
[20]: https://github.com/golang/go/blob/go1.20/CONTRIBUTING.md
[21]: https://github.com/golang/go/blob/go1.20/src/os/os_test.go#L109-L116
[22]: https://github.com/golang/go/blob/go1.20/misc/wasm/wasm_exec_node.js