gojs: backfills errno tests and updates links (#1110)
Signed-off-by: Adrian Cole <adrian@tetrate.io>
This commit is contained in:
114
internal/gojs/errno.go
Normal file
114
internal/gojs/errno.go
Normal 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
139
internal/gojs/errno_test.go
Normal 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)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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).
|
||||
|
||||
Reference in New Issue
Block a user