Repository: tetratelabs/wazero
Pull request #887 (2022-12-05 13:56:44)

Adds ResultNames to HostFunctionBuilder and FunctionDefinition
This adds ResultNames to HostFunctionBuilder and FunctionDefinition which helps for multi-results or special-cased ones.

End users can access result names in `FunctionDefinition.ResultNames` or set for their own host functions via
`HostFunctionBuilder.WithResultNames`. This change adds them for all built-in functions where result names help.

Most notably, GOOS=js uses `ProxyFunc` to allow logging when a function returns multiple results. Before, the results were returned without names: e.g. `11231,1` and now they are named like `n=11231,ok=1`.

We soon plan to allow more visibility in WASI, for example, logging results that will write to memory offsets. This infrastructure makes it possible to do that.



Patch:
diff --git a/api/wasm.go b/api/wasm.go
index 468dd098..68cdcf90 100644
--- a/api/wasm.go
+++ b/api/wasm.go
@@ -278,6 +278,10 @@ type FunctionDefinition interface {
 	//
 	// See ValueType documentation for encoding rules.
 	ResultTypes() []ValueType
+
+	// ResultNames are index-correlated with ResultTypes or nil if not
+	// available for one or more results.
+	ResultNames() []string
 }
 
 // Function is a WebAssembly function exported from an instantiated module
diff --git a/builder.go b/builder.go
index 9128777c..56fa1f3e 100644
--- a/builder.go
+++ b/builder.go
@@ -121,6 +121,12 @@ type HostFunctionBuilder interface {
 	// Note: When defined, names must be provided for all parameters.
 	WithParameterNames(names ...string) HostFunctionBuilder
 
+	// WithResultNames defines optional result names of the function
+	// signature, e.x. "errno"
+	//
+	// Note: When defined, names must be provided for all results.
+	WithResultNames(names ...string) HostFunctionBuilder
+
 	// Export exports this to the HostModuleBuilder as the given name, e.g.
 	// "random_get"
 	Export(name string) HostModuleBuilder
@@ -206,7 +212,7 @@ type hostModuleBuilder struct {
 	r            *runtime
 	moduleName   string
 	nameToGoFunc map[string]interface{}
-	funcToNames  map[string][]string
+	funcToNames  map[string]*wasm.HostFuncNames
 }
 
 // NewHostModuleBuilder implements Runtime.NewHostModuleBuilder
@@ -215,16 +221,17 @@ func (r *runtime) NewHostModuleBuilder(moduleName string) HostModuleBuilder {
 		r:            r,
 		moduleName:   moduleName,
 		nameToGoFunc: map[string]interface{}{},
-		funcToNames:  map[string][]string{},
+		funcToNames:  map[string]*wasm.HostFuncNames{},
 	}
 }
 
 // hostFunctionBuilder implements HostFunctionBuilder
 type hostFunctionBuilder struct {
-	b          *hostModuleBuilder
-	fn         interface{}
-	name       string
-	paramNames []string
+	b           *hostModuleBuilder
+	fn          interface{}
+	name        string
+	paramNames  []string
+	resultNames []string
 }
 
 // WithGoFunction implements HostFunctionBuilder.WithGoFunction
@@ -265,22 +272,32 @@ func (h *hostFunctionBuilder) WithParameterNames(names ...string) HostFunctionBu
 	return h
 }
 
+// WithResultNames implements HostFunctionBuilder.WithResultNames
+func (h *hostFunctionBuilder) WithResultNames(names ...string) HostFunctionBuilder {
+	h.resultNames = names
+	return h
+}
+
 // Export implements HostFunctionBuilder.Export
 func (h *hostFunctionBuilder) Export(exportName string) HostModuleBuilder {
 	if h.name == "" {
 		h.name = exportName
 	}
+	names := &wasm.HostFuncNames{
+		Name:        h.name,
+		ParamNames:  h.paramNames,
+		ResultNames: h.resultNames,
+	}
 	if fn, ok := h.fn.(*wasm.HostFunc); ok {
 		if fn.Name == "" {
-			fn.Name = h.name
+			fn.Name = names.Name
 		}
-		fn.ParamNames = h.paramNames
+		fn.ParamNames = names.ParamNames
+		fn.ResultNames = names.ResultNames
 		fn.ExportNames = []string{exportName}
 	}
 	h.b.nameToGoFunc[exportName] = h.fn
-	if len(h.paramNames) > 0 {
-		h.b.funcToNames[exportName] = append([]string{h.name}, h.paramNames...)
-	}
+	h.b.funcToNames[exportName] = names
 	return h.b
 }
 
diff --git a/experimental/logging/log_listener.go b/experimental/logging/log_listener.go
index fa977bc0..5c523b53 100644
--- a/experimental/logging/log_listener.go
+++ b/experimental/logging/log_listener.go
@@ -47,7 +47,18 @@ func (f *loggingListenerFactory) NewListener(fnd api.FunctionDefinition) experim
 		!exported { // not callable by the host
 		return nil
 	}
-	return &loggingListener{writer: f.writer, fnd: fnd, isWasi: fnd.ModuleName() == "wasi_snapshot_preview1"}
+
+	// special-case formatting of WASI error number until there's a generic way
+	// to stringify parameters or results.
+	wasiErrnoPos := -1
+	if fnd.ModuleName() == "wasi_snapshot_preview1" {
+		for i, n := range fnd.ResultNames() {
+			if n == "errno" {
+				wasiErrnoPos = i
+			}
+		}
+	}
+	return &loggingListener{writer: f.writer, fnd: fnd, wasiErrnoPos: wasiErrnoPos}
 }
 
 // nestLevelKey holds state between logger.Before and loggingListener.After to ensure
@@ -59,7 +70,9 @@ type nestLevelKey struct{}
 type loggingListener struct {
 	writer io.Writer
 	fnd    api.FunctionDefinition
-	isWasi bool
+
+	// wasiErrnoPos is the result index of wasi_snapshot_preview1.Errno or -1.
+	wasiErrnoPos int
 }
 
 // Before logs to stdout the module and function name, prefixed with '-->' and
@@ -96,9 +109,9 @@ func (l *loggingListener) writeIndented(before bool, err error, vals []uint64, i
 		l.writeFuncEnter(&message, vals)
 	} else { // after
 		if l.fnd.GoFunction() != nil {
-			message.WriteString("<== ")
+			message.WriteString("<==")
 		} else {
-			message.WriteString("<-- ")
+			message.WriteString("<--")
 		}
 		l.writeFuncExit(&message, err, vals)
 	}
@@ -125,28 +138,40 @@ func (l *loggingListener) writeFuncEnter(message *strings.Builder, vals []uint64
 
 func (l *loggingListener) writeFuncExit(message *strings.Builder, err error, vals []uint64) {
 	if err != nil {
-		message.WriteString("error: ")
+		message.WriteString(" error: ")
 		message.WriteString(err.Error())
 		return
-	} else if l.isWasi {
-		message.WriteString(wasi_snapshot_preview1.ErrnoName(uint32(vals[0])))
-		return
 	}
 	valLen := len(vals)
-	message.WriteByte('(')
+	if valLen == 0 {
+		return
+	}
+	message.WriteByte(' ')
 	switch valLen {
-	case 0:
+	case 1:
+		l.writeResult(message, 0, vals)
 	default:
+		message.WriteByte('(')
 		i := l.writeResult(message, 0, vals)
 		for i < valLen {
 			message.WriteByte(',')
 			i = l.writeResult(message, i, vals)
 		}
+		message.WriteByte(')')
 	}
-	message.WriteByte(')')
 }
 
 func (l *loggingListener) writeResult(message *strings.Builder, i int, vals []uint64) int {
+	if i == l.wasiErrnoPos {
+		message.WriteString(wasi_snapshot_preview1.ErrnoName(uint32(vals[i])))
+		return i + 1
+	}
+
+	if len(l.fnd.ResultNames()) > 0 {
+		message.WriteString(l.fnd.ResultNames()[i])
+		message.WriteByte('=')
+	}
+
 	return l.writeVal(message, l.fnd.ResultTypes()[i], i, vals)
 }
 
diff --git a/imports/assemblyscript/assemblyscript.go b/imports/assemblyscript/assemblyscript.go
index 3492b6e4..8ce04404 100644
--- a/imports/assemblyscript/assemblyscript.go
+++ b/imports/assemblyscript/assemblyscript.go
@@ -272,6 +272,7 @@ var seed = &wasm.HostFunc{
 	ExportNames: []string{functionSeed},
 	Name:        "~lib/builtins/seed",
 	ResultTypes: []api.ValueType{f64},
+	ResultNames: []string{"rand"},
 	Code: &wasm.Code{
 		IsHostFunction: true,
 		GoFunc: api.GoModuleFunc(func(ctx context.Context, mod api.Module, stack []uint64) {
diff --git a/imports/wasi_snapshot_preview1/args.go b/imports/wasi_snapshot_preview1/args.go
index e549a624..5fb040d8 100644
--- a/imports/wasi_snapshot_preview1/args.go
+++ b/imports/wasi_snapshot_preview1/args.go
@@ -8,11 +8,11 @@ import (
 )
 
 const (
-	functionArgsGet      = "args_get"
-	functionArgsSizesGet = "args_sizes_get"
+	argsGetName      = "args_get"
+	argsSizesGetName = "args_sizes_get"
 )
 
-// argsGet is the WASI function named functionArgsGet that reads command-line
+// argsGet is the WASI function named argsGetName that reads command-line
 // argument data.
 //
 // # Parameters
@@ -44,17 +44,7 @@ const (
 // See argsSizesGet
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#args_get
 // See https://en.wikipedia.org/wiki/Null-terminated_string
-var argsGet = &wasm.HostFunc{
-	ExportNames: []string{functionArgsGet},
-	Name:        functionArgsGet,
-	ParamTypes:  []api.ValueType{i32, i32},
-	ParamNames:  []string{"argv", "argv_buf"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(argsGetFn),
-	},
-}
+var argsGet = newHostFunc(argsGetName, argsGetFn, []api.ValueType{i32, i32}, "argv", "argv_buf")
 
 func argsGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	sysCtx := mod.(*wasm.CallContext).Sys
@@ -62,7 +52,7 @@ func argsGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	return writeOffsetsAndNullTerminatedValues(ctx, mod.Memory(), sysCtx.Args(), argv, argvBuf, sysCtx.ArgsSize())
 }
 
-// argsSizesGet is the WASI function named functionArgsSizesGet that reads
+// argsSizesGet is the WASI function named argsSizesGetName that reads
 // command-line argument sizes.
 //
 // # Parameters
@@ -91,17 +81,7 @@ func argsGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 // See argsGet
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#args_sizes_get
 // See https://en.wikipedia.org/wiki/Null-terminated_string
-var argsSizesGet = &wasm.HostFunc{
-	ExportNames: []string{functionArgsSizesGet},
-	Name:        functionArgsSizesGet,
-	ParamTypes:  []api.ValueType{i32, i32},
-	ParamNames:  []string{"result.argc", "result.argv_len"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(argsSizesGetFn),
-	},
-}
+var argsSizesGet = newHostFunc(argsSizesGetName, argsSizesGetFn, []api.ValueType{i32, i32}, "result.argc", "result.argv_len")
 
 func argsSizesGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	sysCtx := mod.(*wasm.CallContext).Sys
diff --git a/imports/wasi_snapshot_preview1/clock.go b/imports/wasi_snapshot_preview1/clock.go
index 16a091fb..f6e46d0d 100644
--- a/imports/wasi_snapshot_preview1/clock.go
+++ b/imports/wasi_snapshot_preview1/clock.go
@@ -9,8 +9,8 @@ import (
 )
 
 const (
-	functionClockResGet  = "clock_res_get"
-	functionClockTimeGet = "clock_time_get"
+	clockResGetName  = "clock_res_get"
+	clockTimeGetName = "clock_time_get"
 )
 
 // https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clockid-enumu32
@@ -23,7 +23,7 @@ const (
 	// WASI maintainers: https://github.com/WebAssembly/wasi-libc/pull/294
 )
 
-// clockResGet is the WASI function named functionClockResGet that returns the
+// clockResGet is the WASI function named clockResGetName that returns the
 // resolution of time values returned by clockTimeGet.
 //
 // # Parameters
@@ -51,17 +51,7 @@ const (
 // Note: This is similar to `clock_getres` in POSIX.
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clock_res_getid-clockid---errno-timestamp
 // See https://linux.die.net/man/3/clock_getres
-var clockResGet = &wasm.HostFunc{
-	ExportNames: []string{functionClockResGet},
-	Name:        functionClockResGet,
-	ParamTypes:  []api.ValueType{i32, i32},
-	ParamNames:  []string{"id", "result.resolution"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(clockResGetFn),
-	},
-}
+var clockResGet = newHostFunc(clockResGetName, clockResGetFn, []api.ValueType{i32, i32}, "id", "result.resolution")
 
 func clockResGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	sysCtx := mod.(*wasm.CallContext).Sys
@@ -83,7 +73,7 @@ func clockResGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	return ErrnoSuccess
 }
 
-// clockTimeGet is the WASI function named functionClockTimeGet that returns
+// clockTimeGet is the WASI function named clockTimeGetName that returns
 // the time value of a name (time.Now).
 //
 // # Parameters
@@ -114,17 +104,7 @@ func clockResGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 // Note: This is similar to `clock_gettime` in POSIX.
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-clock_time_getid-clockid-precision-timestamp---errno-timestamp
 // See https://linux.die.net/man/3/clock_gettime
-var clockTimeGet = &wasm.HostFunc{
-	ExportNames: []string{functionClockTimeGet},
-	Name:        functionClockTimeGet,
-	ParamTypes:  []api.ValueType{i32, i64, i32},
-	ParamNames:  []string{"id", "precision", "result.timestamp"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(clockTimeGetFn),
-	},
-}
+var clockTimeGet = newHostFunc(clockTimeGetName, clockTimeGetFn, []api.ValueType{i32, i64, i32}, "id", "precision", "result.timestamp")
 
 func clockTimeGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	sysCtx := mod.(*wasm.CallContext).Sys
diff --git a/imports/wasi_snapshot_preview1/environ.go b/imports/wasi_snapshot_preview1/environ.go
index d5b75cd7..9169f8f9 100644
--- a/imports/wasi_snapshot_preview1/environ.go
+++ b/imports/wasi_snapshot_preview1/environ.go
@@ -8,11 +8,11 @@ import (
 )
 
 const (
-	functionEnvironGet      = "environ_get"
-	functionEnvironSizesGet = "environ_sizes_get"
+	environGetName      = "environ_get"
+	environSizesGetName = "environ_sizes_get"
 )
 
-// environGet is the WASI function named functionEnvironGet that reads
+// environGet is the WASI function named environGetName that reads
 // environment variables.
 //
 // # Parameters
@@ -44,17 +44,7 @@ const (
 // See environSizesGet
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#environ_get
 // See https://en.wikipedia.org/wiki/Null-terminated_string
-var environGet = &wasm.HostFunc{
-	ExportNames: []string{functionEnvironGet},
-	Name:        functionEnvironGet,
-	ParamTypes:  []api.ValueType{i32, i32},
-	ParamNames:  []string{"environ", "environ_buf"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(environGetFn),
-	},
-}
+var environGet = newHostFunc(environGetName, environGetFn, []api.ValueType{i32, i32}, "environ", "environ_buf")
 
 func environGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	sysCtx := mod.(*wasm.CallContext).Sys
@@ -63,7 +53,7 @@ func environGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	return writeOffsetsAndNullTerminatedValues(ctx, mod.Memory(), sysCtx.Environ(), environ, environBuf, sysCtx.EnvironSize())
 }
 
-// environSizesGet is the WASI function named functionEnvironSizesGet that
+// environSizesGet is the WASI function named environSizesGetName that
 // reads environment variable sizes.
 //
 // # Parameters
@@ -94,17 +84,7 @@ func environGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 // See environGet
 // https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#environ_sizes_get
 // and https://en.wikipedia.org/wiki/Null-terminated_string
-var environSizesGet = &wasm.HostFunc{
-	ExportNames: []string{functionEnvironSizesGet},
-	Name:        functionEnvironSizesGet,
-	ParamTypes:  []api.ValueType{i32, i32},
-	ParamNames:  []string{"result.environc", "result.environv_len"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(environSizesGetFn),
-	},
-}
+var environSizesGet = newHostFunc(environSizesGetName, environSizesGetFn, []api.ValueType{i32, i32}, "result.environc", "result.environv_len")
 
 func environSizesGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	sysCtx := mod.(*wasm.CallContext).Sys
diff --git a/imports/wasi_snapshot_preview1/fs.go b/imports/wasi_snapshot_preview1/fs.go
index 6ab67110..6b0fe9f8 100644
--- a/imports/wasi_snapshot_preview1/fs.go
+++ b/imports/wasi_snapshot_preview1/fs.go
@@ -16,38 +16,38 @@ import (
 )
 
 const (
-	functionFdAdvise           = "fd_advise"
-	functionFdAllocate         = "fd_allocate"
-	functionFdClose            = "fd_close"
-	functionFdDatasync         = "fd_datasync"
-	functionFdFdstatGet        = "fd_fdstat_get"
-	functionFdFdstatSetFlags   = "fd_fdstat_set_flags"
-	functionFdFdstatSetRights  = "fd_fdstat_set_rights"
-	functionFdFilestatGet      = "fd_filestat_get"
-	functionFdFilestatSetSize  = "fd_filestat_set_size"
-	functionFdFilestatSetTimes = "fd_filestat_set_times"
-	functionFdPread            = "fd_pread"
-	functionFdPrestatGet       = "fd_prestat_get"
-	functionFdPrestatDirName   = "fd_prestat_dir_name"
-	functionFdPwrite           = "fd_pwrite"
-	functionFdRead             = "fd_read"
-	functionFdReaddir          = "fd_readdir"
-	functionFdRenumber         = "fd_renumber"
-	functionFdSeek             = "fd_seek"
-	functionFdSync             = "fd_sync"
-	functionFdTell             = "fd_tell"
-	functionFdWrite            = "fd_write"
-
-	functionPathCreateDirectory  = "path_create_directory"
-	functionPathFilestatGet      = "path_filestat_get"
-	functionPathFilestatSetTimes = "path_filestat_set_times"
-	functionPathLink             = "path_link"
-	functionPathOpen             = "path_open"
-	functionPathReadlink         = "path_readlink"
-	functionPathRemoveDirectory  = "path_remove_directory"
-	functionPathRename           = "path_rename"
-	functionPathSymlink          = "path_symlink"
-	functionPathUnlinkFile       = "path_unlink_file"
+	fdAdviseName           = "fd_advise"
+	fdAllocateName         = "fd_allocate"
+	fdCloseName            = "fd_close"
+	fdDatasyncName         = "fd_datasync"
+	fdFdstatGetName        = "fd_fdstat_get"
+	fdFdstatSetFlagsName   = "fd_fdstat_set_flags"
+	fdFdstatSetRightsName  = "fd_fdstat_set_rights"
+	fdFilestatGetName      = "fd_filestat_get"
+	fdFilestatSetSizeName  = "fd_filestat_set_size"
+	fdFilestatSetTimesName = "fd_filestat_set_times"
+	fdPreadName            = "fd_pread"
+	fdPrestatGetName       = "fd_prestat_get"
+	fdPrestatDirNameName   = "fd_prestat_dir_name"
+	fdPwriteName           = "fd_pwrite"
+	fdReadName             = "fd_read"
+	fdReaddirName          = "fd_readdir"
+	fdRenumberName         = "fd_renumber"
+	fdSeekName             = "fd_seek"
+	fdSyncName             = "fd_sync"
+	fdTellName             = "fd_tell"
+	fdWriteName            = "fd_write"
+
+	pathCreateDirectoryName  = "path_create_directory"
+	pathFilestatGetName      = "path_filestat_get"
+	pathFilestatSetTimesName = "path_filestat_set_times"
+	pathLinkName             = "path_link"
+	pathOpenName             = "path_open"
+	pathReadlinkName         = "path_readlink"
+	pathRemoveDirectoryName  = "path_remove_directory"
+	pathRenameName           = "path_rename"
+	pathSymlinkName          = "path_symlink"
+	pathUnlinkFileName       = "path_unlink_file"
 )
 
 // fdAdvise is the WASI function named functionFdAdvise which provides file
@@ -55,9 +55,9 @@ const (
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_advisefd-fd-offset-filesize-len-filesize-advice-advice---errno
 var fdAdvise = stubFunction(
-	functionFdAdvise,
+	fdAdviseName,
 	[]wasm.ValueType{i32, i64, i64, i32},
-	[]string{"fd", "offset", "len", "result.advice"},
+	"fd", "offset", "len", "result.advice",
 )
 
 // fdAllocate is the WASI function named functionFdAllocate which forces the
@@ -65,9 +65,9 @@ var fdAdvise = stubFunction(
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_allocatefd-fd-offset-filesize-len-filesize---errno
 var fdAllocate = stubFunction(
-	functionFdAllocate,
+	fdAllocateName,
 	[]wasm.ValueType{i32, i64, i64},
-	[]string{"fd", "offset", "len"},
+	"fd", "offset", "len",
 )
 
 // fdClose is the WASI function named functionFdClose which closes a file
@@ -85,17 +85,7 @@ var fdAllocate = stubFunction(
 // Note: This is similar to `close` in POSIX.
 // See https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#fd_close
 // and https://linux.die.net/man/3/close
-var fdClose = &wasm.HostFunc{
-	ExportNames: []string{functionFdClose},
-	Name:        functionFdClose,
-	ParamTypes:  []api.ValueType{i32},
-	ParamNames:  []string{"fd"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(fdCloseFn),
-	},
-}
+var fdClose = newHostFunc(fdCloseName, fdCloseFn, []api.ValueType{i32}, "fd")
 
 func fdCloseFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	sysCtx := mod.(*wasm.CallContext).Sys
@@ -111,11 +101,7 @@ func fdCloseFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 // the data of a file to disk.
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_datasyncfd-fd---errno
-var fdDatasync = stubFunction(
-	functionFdDatasync,
-	[]wasm.ValueType{i32},
-	[]string{"fd"},
-)
+var fdDatasync = stubFunction(fdDatasyncName, []wasm.ValueType{i32}, "fd")
 
 // fdFdstatGet is the WASI function named functionFdFdstatGet which returns the
 // attributes of a file descriptor.
@@ -154,17 +140,7 @@ var fdDatasync = stubFunction(
 // well as additional fields.
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fdstat
 // and https://linux.die.net/man/3/fsync
-var fdFdstatGet = &wasm.HostFunc{
-	ExportNames: []string{functionFdFdstatGet},
-	Name:        functionFdFdstatGet,
-	ParamTypes:  []api.ValueType{i32, i32},
-	ParamNames:  []string{"fd", "result.stat"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(fdFdstatGetFn),
-	},
-}
+var fdFdstatGet = newHostFunc(fdFdstatGetName, fdFdstatGetFn, []api.ValueType{i32, i32}, "fd", "result.stat")
 
 func fdFdstatGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	sysCtx := mod.(*wasm.CallContext).Sys
@@ -181,19 +157,15 @@ func fdFdstatGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 // adjusts the flags associated with a file descriptor.
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_fdstat_set_flagsfd-fd-flags-fdflags---errnoand is stubbed for GrainLang per #271
-var fdFdstatSetFlags = stubFunction(
-	functionFdFdstatSetFlags,
-	[]wasm.ValueType{i32, i32},
-	[]string{"fd", "flags"},
-)
+var fdFdstatSetFlags = stubFunction(fdFdstatSetFlagsName, []wasm.ValueType{i32, i32}, "fd", "flags")
 
 // fdFdstatSetRights will not be implemented as rights were removed from WASI.
 //
 // See https://github.com/bytecodealliance/wasmtime/pull/4666
 var fdFdstatSetRights = stubFunction(
-	functionFdFdstatSetRights,
+	fdFdstatSetRightsName,
 	[]wasm.ValueType{i32, i64, i64},
-	[]string{"fd", "fs_rights_base", "fs_rights_inheriting"},
+	"fd", "fs_rights_base", "fs_rights_inheriting",
 )
 
 // fdFilestatGet is the WASI function named functionFdFilestatGet which returns
@@ -243,17 +215,7 @@ var fdFdstatSetRights = stubFunction(
 // Note: This is similar to `fstat` in POSIX.
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_filestat_getfd-fd---errno-filestat
 // and https://linux.die.net/man/3/fstat
-var fdFilestatGet = &wasm.HostFunc{
-	ExportNames: []string{functionFdFilestatGet},
-	Name:        functionFdFilestatGet,
-	ParamTypes:  []api.ValueType{i32, i32},
-	ParamNames:  []string{"fd", "result.buf"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(fdFilestatGetFn),
-	},
-}
+var fdFilestatGet = newHostFunc(fdFilestatGetName, fdFilestatGetFn, []api.ValueType{i32, i32}, "fd", "result.buf")
 
 type wasiFiletype uint8
 
@@ -319,20 +281,16 @@ func fdFilestatGetFunc(ctx context.Context, mod api.Module, fd, resultBuf uint32
 // adjusts the size of an open file.
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_filestat_set_sizefd-fd-size-filesize---errno
-var fdFilestatSetSize = stubFunction(
-	functionFdFilestatSetSize,
-	[]wasm.ValueType{i32, i64},
-	[]string{"fd", "size"},
-)
+var fdFilestatSetSize = stubFunction(fdFilestatSetSizeName, []wasm.ValueType{i32, i64}, "fd", "size")
 
 // fdFilestatSetTimes is the WASI function named functionFdFilestatSetTimes
 // which adjusts the times of an open file.
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_filestat_set_timesfd-fd-atim-timestamp-mtim-timestamp-fst_flags-fstflags---errno
 var fdFilestatSetTimes = stubFunction(
-	functionFdFilestatSetTimes,
+	fdFilestatSetTimesName,
 	[]wasm.ValueType{i32, i64, i64, i32},
-	[]string{"fd", "atim", "mtim", "fst_flags"},
+	"fd", "atim", "mtim", "fst_flags",
 )
 
 // fdPread is the WASI function named functionFdPread which reads from a file
@@ -341,17 +299,11 @@ var fdFilestatSetTimes = stubFunction(
 // Except for handling offset, this implementation is identical to fdRead.
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_preadfd-fd-iovs-iovec_array-offset-filesize---errno-size
-var fdPread = &wasm.HostFunc{
-	ExportNames: []string{functionFdPread},
-	Name:        functionFdPread,
-	ParamTypes:  []api.ValueType{i32, i32, i32, i64, i32},
-	ParamNames:  []string{"fd", "iovs", "iovs_len", "offset", "result.size"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(fdPreadFn),
-	},
-}
+var fdPread = newHostFunc(
+	fdPreadName, fdPreadFn,
+	[]api.ValueType{i32, i32, i32, i64, i32},
+	"fd", "iovs", "iovs_len", "offset", "result.size",
+)
 
 func fdPreadFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	return fdReadOrPread(ctx, mod, params, true)
@@ -388,17 +340,7 @@ func fdPreadFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 //
 // See fdPrestatDirName and
 // https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#prestat
-var fdPrestatGet = &wasm.HostFunc{
-	ExportNames: []string{functionFdPrestatGet},
-	Name:        functionFdPrestatGet,
-	ParamTypes:  []api.ValueType{i32, i32},
-	ParamNames:  []string{"fd", "result.prestat"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(fdPrestatGetFn),
-	},
-}
+var fdPrestatGet = newHostFunc(fdPrestatGetName, fdPrestatGetFn, []api.ValueType{i32, i32}, "fd", "result.prestat")
 
 func fdPrestatGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	sysCtx := mod.(*wasm.CallContext).Sys
@@ -451,17 +393,11 @@ func fdPrestatGetFn(ctx context.Context, mod api.Module, params []uint64) Errno
 //
 // See fdPrestatGet
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_prestat_dir_name
-var fdPrestatDirName = &wasm.HostFunc{
-	ExportNames: []string{functionFdPrestatDirName},
-	Name:        functionFdPrestatDirName,
-	ParamTypes:  []api.ValueType{i32, i32, i32},
-	ParamNames:  []string{"fd", "path", "path_len"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(fdPrestatDirNameFn),
-	},
-}
+var fdPrestatDirName = newHostFunc(
+	fdPrestatDirNameName, fdPrestatDirNameFn,
+	[]api.ValueType{i32, i32, i32},
+	"fd", "path", "path_len",
+)
 
 func fdPrestatDirNameFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	sysCtx := mod.(*wasm.CallContext).Sys
@@ -489,9 +425,10 @@ func fdPrestatDirNameFn(ctx context.Context, mod api.Module, params []uint64) Er
 // descriptor, without using and updating the file descriptor's offset.
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_pwritefd-fd-iovs-ciovec_array-offset-filesize---errno-size
-var fdPwrite = stubFunction(functionFdPwrite,
+var fdPwrite = stubFunction(
+	fdPwriteName,
 	[]wasm.ValueType{i32, i32, i32, i64, i32},
-	[]string{"fd", "iovs", "iovs_len", "offset", "result.nwritten"},
+	"fd", "iovs", "iovs_len", "offset", "result.nwritten",
 )
 
 // fdRead is the WASI function named functionFdRead which reads from a file
@@ -543,17 +480,11 @@ var fdPwrite = stubFunction(functionFdPwrite,
 //
 // See fdWrite
 // and https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_read
-var fdRead = &wasm.HostFunc{
-	ExportNames: []string{functionFdRead},
-	Name:        functionFdRead,
-	ParamTypes:  []api.ValueType{i32, i32, i32, i32},
-	ParamNames:  []string{"fd", "iovs", "iovs_len", "result.size"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(fdReadFn),
-	},
-}
+var fdRead = newHostFunc(
+	fdReadName, fdReadFn,
+	[]api.ValueType{i32, i32, i32, i32},
+	"fd", "iovs", "iovs_len", "result.size",
+)
 
 func fdReadFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	return fdReadOrPread(ctx, mod, params, false)
@@ -644,17 +575,11 @@ func fdRead_shouldContinueRead(n, l uint32, err error) (bool, Errno) {
 // entries from a directory.
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_readdirfd-fd-buf-pointeru8-buf_len-size-cookie-dircookie---errno-size
-var fdReaddir = &wasm.HostFunc{
-	ExportNames: []string{functionFdReaddir},
-	Name:        functionFdReaddir,
-	ParamTypes:  []wasm.ValueType{i32, i32, i32, i64, i32},
-	ParamNames:  []string{"fd", "buf", "buf_len", "cookie", "result.bufused"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(fdReaddirFn),
-	},
-}
+var fdReaddir = newHostFunc(
+	fdReaddirName, fdReaddirFn,
+	[]wasm.ValueType{i32, i32, i32, i64, i32},
+	"fd", "buf", "buf_len", "cookie", "result.bufused",
+)
 
 func fdReaddirFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	fd := uint32(params[0])
@@ -911,11 +836,7 @@ func openedDir(ctx context.Context, mod api.Module, fd uint32) (fs.ReadDirFile,
 // replaces a file descriptor by renumbering another file descriptor.
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_renumberfd-fd-to-fd---errno
-var fdRenumber = stubFunction(
-	functionFdRenumber,
-	[]wasm.ValueType{i32, i32},
-	[]string{"fd", "to"},
-)
+var fdRenumber = stubFunction(fdRenumberName, []wasm.ValueType{i32, i32}, "fd", "to")
 
 // fdSeek is the WASI function named functionFdSeek which moves the offset of a
 // file descriptor.
@@ -954,17 +875,11 @@ var fdRenumber = stubFunction(
 //
 // See io.Seeker
 // and https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_seek
-var fdSeek = &wasm.HostFunc{
-	ExportNames: []string{functionFdSeek},
-	Name:        functionFdSeek,
-	ParamTypes:  []api.ValueType{i32, i64, i32, i32},
-	ParamNames:  []string{"fd", "offset", "whence", "result.newoffset"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(fdSeekFn),
-	},
-}
+var fdSeek = newHostFunc(
+	fdSeekName, fdSeekFn,
+	[]api.ValueType{i32, i64, i32, i32},
+	"fd", "offset", "whence", "result.newoffset",
+)
 
 func fdSeekFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	sysCtx := mod.(*wasm.CallContext).Sys
@@ -1000,21 +915,13 @@ func fdSeekFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 // and metadata of a file to disk.
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_syncfd-fd---errno
-var fdSync = stubFunction(
-	functionFdSync,
-	[]wasm.ValueType{i32},
-	[]string{"fd"},
-)
+var fdSync = stubFunction(fdSyncName, []wasm.ValueType{i32}, "fd")
 
 // fdTell is the WASI function named functionFdTell which returns the current
 // offset of a file descriptor.
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-fd_tellfd-fd---errno-filesize
-var fdTell = stubFunction(
-	functionFdTell,
-	[]wasm.ValueType{i32, i32},
-	[]string{"fd", "result.offset"},
-)
+var fdTell = stubFunction(fdTellName, []wasm.ValueType{i32, i32}, "fd", "result.offset")
 
 // fdWrite is the WASI function named functionFdWrite which writes to a file
 // descriptor.
@@ -1073,17 +980,11 @@ var fdTell = stubFunction(
 // See fdRead
 // https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#ciovec
 // and https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#fd_write
-var fdWrite = &wasm.HostFunc{
-	ExportNames: []string{functionFdWrite},
-	Name:        functionFdWrite,
-	ParamTypes:  []api.ValueType{i32, i32, i32, i32},
-	ParamNames:  []string{"fd", "iovs", "iovs_len", "result.size"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(fdWriteFn),
-	},
-}
+var fdWrite = newHostFunc(
+	fdWriteName, fdWriteFn,
+	[]api.ValueType{i32, i32, i32, i32},
+	"fd", "iovs", "iovs_len", "result.size",
+)
 
 func fdWriteFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	fd := uint32(params[0])
@@ -1138,9 +1039,9 @@ func fdWriteFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_create_directoryfd-fd-path-string---errno
 var pathCreateDirectory = stubFunction(
-	functionPathCreateDirectory,
+	pathCreateDirectoryName,
 	[]wasm.ValueType{i32, i32, i32},
-	[]string{"fd", "path", "path_len"},
+	"fd", "path", "path_len",
 )
 
 // pathFilestatGet is the WASI function named functionPathFilestatGet which
@@ -1171,17 +1072,11 @@ var pathCreateDirectory = stubFunction(
 // Note: This is similar to `fstatat` in POSIX.
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_filestat_getfd-fd-flags-lookupflags-path-string---errno-filestat
 // and https://linux.die.net/man/2/fstatat
-var pathFilestatGet = &wasm.HostFunc{
-	ExportNames: []string{functionPathFilestatGet},
-	Name:        functionPathFilestatGet,
-	ParamTypes:  []api.ValueType{i32, i32, i32, i32, i32},
-	ParamNames:  []string{"fd", "flags", "path", "path_len", "result.buf"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(pathFilestatGetFn),
-	},
-}
+var pathFilestatGet = newHostFunc(
+	pathFilestatGetName, pathFilestatGetFn,
+	[]api.ValueType{i32, i32, i32, i32, i32},
+	"fd", "flags", "path", "path_len", "result.buf",
+)
 
 func pathFilestatGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	sysCtx := mod.(*wasm.CallContext).Sys
@@ -1229,9 +1124,9 @@ func pathFilestatGetFn(ctx context.Context, mod api.Module, params []uint64) Err
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_filestat_set_timesfd-fd-flags-lookupflags-path-string-atim-timestamp-mtim-timestamp-fst_flags-fstflags---errno
 var pathFilestatSetTimes = stubFunction(
-	functionPathFilestatSetTimes,
+	pathFilestatSetTimesName,
 	[]wasm.ValueType{i32, i32, i32, i32, i64, i64, i32},
-	[]string{"fd", "flags", "path", "path_len", "atim", "mtim", "fst_flags"},
+	"fd", "flags", "path", "path_len", "atim", "mtim", "fst_flags",
 )
 
 // pathLink is the WASI function named functionPathLink which adjusts the
@@ -1239,9 +1134,9 @@ var pathFilestatSetTimes = stubFunction(
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#path_link
 var pathLink = stubFunction(
-	functionPathLink,
+	pathLinkName,
 	[]wasm.ValueType{i32, i32, i32, i32, i32, i32, i32},
-	[]string{"old_fd", "old_flags", "old_path", "old_path_len", "new_fd", "new_path", "new_path_len"},
+	"old_fd", "old_flags", "old_path", "old_path_len", "new_fd", "new_path", "new_path_len",
 )
 
 // pathOpen is the WASI function named functionPathOpen which opens a file or
@@ -1297,17 +1192,11 @@ var pathLink = stubFunction(
 //   - The returned file descriptor is not guaranteed to be the lowest-number
 //
 // See https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#path_open
-var pathOpen = &wasm.HostFunc{
-	ExportNames: []string{functionPathOpen},
-	Name:        functionPathOpen,
-	ParamTypes:  []api.ValueType{i32, i32, i32, i32, i32, i64, i64, i32, i32},
-	ParamNames:  []string{"fd", "dirflags", "path", "path_len", "oflags", "fs_rights_base", "fs_rights_inheriting", "fdflags", "result.opened_fd"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(pathOpenFn),
-	},
-}
+var pathOpen = newHostFunc(
+	pathOpenName, pathOpenFn,
+	[]api.ValueType{i32, i32, i32, i32, i32, i64, i64, i32, i32},
+	"fd", "dirflags", "path", "path_len", "oflags", "fs_rights_base", "fs_rights_inheriting", "fdflags", "result.opened_fd",
+)
 
 func pathOpenFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	sysCtx := mod.(*wasm.CallContext).Sys
@@ -1349,9 +1238,9 @@ func pathOpenFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 //
 // See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_readlinkfd-fd-path-string-buf-pointeru8-buf_len-size---errno-size
 var pathReadlink = stubFunction(
-	functionPathReadlink,
+	pathReadlinkName,
 	[]wasm.ValueType{i32, i32, i32, i32, i32, i32},
-	[]string{"fd", "path", "path_len", "buf", "buf_len", "result.bufused"},
+	"fd", "path", "path_len", "buf", "buf_len", "result.bufused",
 )
 
 // pathRemoveDirectory is the WASI function named functionPathRemoveDirectory
@@ -1359,17 +1248,17 @@ var pathReadlink = stubFunction(
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_remove_directoryfd-fd-path-string---errno
 var pathRemoveDirectory = stubFunction(
-	functionPathRemoveDirectory,
+	pathRemoveDirectoryName,
 	[]wasm.ValueType{i32, i32, i32},
-	[]string{"fd", "path", "path_len"},
+	"fd", "path", "path_len",
 )
 
 // pathRename is the WASI function named functionPathRename which renames a
 // file or directory.
 var pathRename = stubFunction(
-	functionPathRename,
+	pathRenameName,
 	[]wasm.ValueType{i32, i32, i32, i32, i32, i32},
-	[]string{"fd", "old_path", "old_path_len", "new_fd", "new_path", "new_path_len"},
+	"fd", "old_path", "old_path_len", "new_fd", "new_path", "new_path_len",
 )
 
 // pathSymlink is the WASI function named functionPathSymlink which creates a
@@ -1377,9 +1266,9 @@ var pathRename = stubFunction(
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#path_symlink
 var pathSymlink = stubFunction(
-	functionPathSymlink,
+	pathSymlinkName,
 	[]wasm.ValueType{i32, i32, i32, i32, i32},
-	[]string{"old_path", "old_path_len", "fd", "new_path", "new_path_len"},
+	"old_path", "old_path_len", "fd", "new_path", "new_path_len",
 )
 
 // pathUnlinkFile is the WASI function named functionPathUnlinkFile which
@@ -1387,9 +1276,9 @@ var pathSymlink = stubFunction(
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-path_unlink_filefd-fd-path-string---errno
 var pathUnlinkFile = stubFunction(
-	functionPathUnlinkFile,
+	pathUnlinkFileName,
 	[]wasm.ValueType{i32, i32, i32},
-	[]string{"fd", "path", "path_len"},
+	"fd", "path", "path_len",
 )
 
 // openFile attempts to open the file at the given path. Errors coerce to WASI
diff --git a/imports/wasi_snapshot_preview1/poll.go b/imports/wasi_snapshot_preview1/poll.go
index 7365df6d..8c94ff70 100644
--- a/imports/wasi_snapshot_preview1/poll.go
+++ b/imports/wasi_snapshot_preview1/poll.go
@@ -9,7 +9,7 @@ import (
 	"github.com/tetratelabs/wazero/internal/wasm"
 )
 
-const functionPollOneoff = "poll_oneoff"
+const pollOneoffName = "poll_oneoff"
 
 // https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-eventtype-enumu8
 const (
@@ -21,7 +21,7 @@ const (
 	eventTypeFdWrite
 )
 
-// pollOneoff is the WASI function named functionPollOneoff that concurrently
+// pollOneoff is the WASI function named pollOneoffName that concurrently
 // polls for the occurrence of a set of events.
 //
 // # Parameters
@@ -47,17 +47,11 @@ const (
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#poll_oneoff
 // See https://linux.die.net/man/3/poll
-var pollOneoff = &wasm.HostFunc{
-	ExportNames: []string{functionPollOneoff},
-	Name:        functionPollOneoff,
-	ParamTypes:  []api.ValueType{i32, i32, i32, i32},
-	ParamNames:  []string{"in", "out", "nsubscriptions", "result.nevents"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(pollOneoffFn),
-	},
-}
+var pollOneoff = newHostFunc(
+	pollOneoffName, pollOneoffFn,
+	[]api.ValueType{i32, i32, i32, i32},
+	"in", "out", "nsubscriptions", "result.nevents",
+)
 
 func pollOneoffFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	in := uint32(params[0])
diff --git a/imports/wasi_snapshot_preview1/proc.go b/imports/wasi_snapshot_preview1/proc.go
index b0c76763..597e1910 100644
--- a/imports/wasi_snapshot_preview1/proc.go
+++ b/imports/wasi_snapshot_preview1/proc.go
@@ -9,11 +9,11 @@ import (
 )
 
 const (
-	functionProcExit  = "proc_exit"
-	functionProcRaise = "proc_raise"
+	procExitName  = "proc_exit"
+	procRaiseName = "proc_raise"
 )
 
-// procExit is the WASI function named functionProcExit that terminates the
+// procExit is the WASI function named procExitName that terminates the
 // execution of the module with an exit code. The only successful exit code is
 // zero.
 //
@@ -23,17 +23,17 @@ const (
 //
 // See https://github.com/WebAssembly/WASI/blob/main/phases/snapshot/docs.md#proc_exit
 var procExit = &wasm.HostFunc{
-	ExportNames: []string{functionProcExit},
-	Name:        functionProcExit,
+	ExportNames: []string{procExitName},
+	Name:        procExitName,
 	ParamTypes:  []api.ValueType{i32},
 	ParamNames:  []string{"rval"},
 	Code: &wasm.Code{
 		IsHostFunction: true,
-		GoFunc:         wasiFunc(procExitFn),
+		GoFunc:         api.GoModuleFunc(procExitFn),
 	},
 }
 
-func procExitFn(ctx context.Context, mod api.Module, params []uint64) Errno {
+func procExitFn(ctx context.Context, mod api.Module, params []uint64) {
 	exitCode := uint32(params[0])
 
 	// Ensure other callers see the exit code.
@@ -48,4 +48,4 @@ func procExitFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 // procRaise is stubbed and will never be supported, as it was removed.
 //
 // See https://github.com/WebAssembly/WASI/pull/136
-var procRaise = stubFunction(functionProcRaise, []wasm.ValueType{i32}, []string{"sig"})
+var procRaise = stubFunction(procRaiseName, []wasm.ValueType{i32}, "sig")
diff --git a/imports/wasi_snapshot_preview1/random.go b/imports/wasi_snapshot_preview1/random.go
index 66936105..e94b4f39 100644
--- a/imports/wasi_snapshot_preview1/random.go
+++ b/imports/wasi_snapshot_preview1/random.go
@@ -8,9 +8,9 @@ import (
 	"github.com/tetratelabs/wazero/internal/wasm"
 )
 
-const functionRandomGet = "random_get"
+const randomGetName = "random_get"
 
-// randomGet is the WASI function named functionRandomGet which writes random
+// randomGet is the WASI function named randomGetName which writes random
 // data to a buffer.
 //
 // # Parameters
@@ -34,17 +34,7 @@ const functionRandomGet = "random_get"
 //	    buf --^
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-random_getbuf-pointeru8-bufLen-size---errno
-var randomGet = &wasm.HostFunc{
-	ExportNames: []string{functionRandomGet},
-	Name:        functionRandomGet,
-	ParamTypes:  []api.ValueType{i32, i32},
-	ParamNames:  []string{"buf", "buf_len"},
-	ResultTypes: []api.ValueType{i32},
-	Code: &wasm.Code{
-		IsHostFunction: true,
-		GoFunc:         wasiFunc(randomGetFn),
-	},
-}
+var randomGet = newHostFunc(randomGetName, randomGetFn, []api.ValueType{i32, i32}, "buf", "buf_len")
 
 func randomGetFn(ctx context.Context, mod api.Module, params []uint64) Errno {
 	sysCtx := mod.(*wasm.CallContext).Sys
diff --git a/imports/wasi_snapshot_preview1/sched.go b/imports/wasi_snapshot_preview1/sched.go
index 65e74bf5..54c03641 100644
--- a/imports/wasi_snapshot_preview1/sched.go
+++ b/imports/wasi_snapshot_preview1/sched.go
@@ -1,9 +1,9 @@
 package wasi_snapshot_preview1
 
-const functionSchedYield = "sched_yield"
+const schedYieldName = "sched_yield"
 
-// schedYield is the WASI function named functionSchedYield which temporarily
+// schedYield is the WASI function named schedYieldName which temporarily
 // yields execution of the calling thread.
 //
 // See https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sched_yield---errno
-var schedYield = stubFunction(functionSchedYield, nil, nil)
+var schedYield = stubFunction(schedYieldName, nil)
diff --git a/imports/wasi_snapshot_preview1/sock.go b/imports/wasi_snapshot_preview1/sock.go
index 90147168..0d3c1caa 100644
--- a/imports/wasi_snapshot_preview1/sock.go
+++ b/imports/wasi_snapshot_preview1/sock.go
@@ -3,49 +3,45 @@ package wasi_snapshot_preview1
 import "github.com/tetratelabs/wazero/internal/wasm"
 
 const (
-	functionSockAccept   = "sock_accept"
-	functionSockRecv     = "sock_recv"
-	functionSockSend     = "sock_send"
-	functionSockShutdown = "sock_shutdown"
+	sockAcceptName   = "sock_accept"
+	sockRecvName     = "sock_recv"
+	sockSendName     = "sock_send"
+	sockShutdownName = "sock_shutdown"
 )
 
-// sockAccept is the WASI function named functionSockAccept which accepts a new
+// sockAccept is the WASI function named sockAcceptName which accepts a new
 // incoming connection.
 //
 // See: https://github.com/WebAssembly/WASI/blob/0ba0c5e2e37625ca5a6d3e4255a998dfaa3efc52/phases/snapshot/docs.md#sock_accept
 // and https://github.com/WebAssembly/WASI/pull/458
 var sockAccept = stubFunction(
-	functionSockAccept,
+	sockAcceptName,
 	[]wasm.ValueType{i32, i32, i32},
-	[]string{"fd", "flags", "result.fd"},
+	"fd", "flags", "result.fd",
 )
 
-// sockRecv is the WASI function named functionSockRecv which receives a
+// sockRecv is the WASI function named sockRecvName which receives a
 // message from a socket.
 //
 // See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sock_recvfd-fd-ri_data-iovec_array-ri_flags-riflags---errno-size-roflags
 var sockRecv = stubFunction(
-	functionSockRecv,
+	sockRecvName,
 	[]wasm.ValueType{i32, i32, i32, i32, i32, i32},
-	[]string{"fd", "ri_data", "ri_data_count", "ri_flags", "result.ro_datalen", "result.ro_flags"},
+	"fd", "ri_data", "ri_data_count", "ri_flags", "result.ro_datalen", "result.ro_flags",
 )
 
-// sockSend is the WASI function named functionSockSend which sends a message
+// sockSend is the WASI function named sockSendName which sends a message
 // on a socket.
 //
 // See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sock_sendfd-fd-si_data-ciovec_array-si_flags-siflags---errno-size
 var sockSend = stubFunction(
-	functionSockSend,
+	sockSendName,
 	[]wasm.ValueType{i32, i32, i32, i32, i32},
-	[]string{"fd", "si_data", "si_data_count", "si_flags", "result.so_datalen"},
+	"fd", "si_data", "si_data_count", "si_flags", "result.so_datalen",
 )
 
-// sockShutdown is the WASI function named functionSockShutdown which shuts
+// sockShutdown is the WASI function named sockShutdownName which shuts
 // down socket send and receive channels.
 //
 // See: https://github.com/WebAssembly/WASI/blob/snapshot-01/phases/snapshot/docs.md#-sock_shutdownfd-fd-how-sdflags---errno
-var sockShutdown = stubFunction(
-	functionSockShutdown,
-	[]wasm.ValueType{i32, i32},
-	[]string{"fd", "how"},
-)
+var sockShutdown = stubFunction(sockShutdownName, []wasm.ValueType{i32, i32}, "fd", "how")
diff --git a/imports/wasi_snapshot_preview1/wasi.go b/imports/wasi_snapshot_preview1/wasi.go
index 9d3cd10c..9002f310 100644
--- a/imports/wasi_snapshot_preview1/wasi.go
+++ b/imports/wasi_snapshot_preview1/wasi.go
@@ -255,6 +255,18 @@ func writeOffsetsAndNullTerminatedValues(ctx context.Context, mem api.Memory, va
 	return ErrnoSuccess
 }
 
+func newHostFunc(name string, goFunc wasiFunc, paramTypes []api.ValueType, paramNames ...string) *wasm.HostFunc {
+	return &wasm.HostFunc{
+		ExportNames: []string{name},
+		Name:        name,
+		ParamTypes:  paramTypes,
+		ParamNames:  paramNames,
+		ResultTypes: []api.ValueType{i32},
+		ResultNames: []string{"errno"},
+		Code:        &wasm.Code{IsHostFunction: true, GoFunc: goFunc},
+	}
+}
+
 // wasiFunc special cases that all WASI functions return a single Errno
 // result. The returned value will be written back to the stack at index zero.
 type wasiFunc func(ctx context.Context, mod api.Module, params []uint64) Errno
@@ -266,13 +278,14 @@ func (f wasiFunc) Call(ctx context.Context, mod api.Module, stack []uint64) {
 }
 
 // stubFunction stubs for GrainLang per #271.
-func stubFunction(name string, paramTypes []wasm.ValueType, paramNames []string) *wasm.HostFunc {
+func stubFunction(name string, paramTypes []wasm.ValueType, paramNames ...string) *wasm.HostFunc {
 	return &wasm.HostFunc{
 		Name:        name,
 		ExportNames: []string{name},
 		ParamTypes:  paramTypes,
 		ParamNames:  paramNames,
 		ResultTypes: []wasm.ValueType{i32},
+		ResultNames: []string{"errno"},
 		Code: &wasm.Code{
 			IsHostFunction: true,
 			Body:           []byte{wasm.OpcodeI32Const, byte(ErrnoNosys), wasm.OpcodeEnd},
diff --git a/internal/gojs/runtime.go b/internal/gojs/runtime.go
index 89068fc3..483f94b4 100644
--- a/internal/gojs/runtime.go
+++ b/internal/gojs/runtime.go
@@ -13,22 +13,22 @@ import (
 const (
 	i32, i64 = api.ValueTypeI32, api.ValueTypeI64
 
-	functionWasmExit             = "runtime.wasmExit"
-	functionWasmWrite            = "runtime.wasmWrite"
-	functionResetMemoryDataView  = "runtime.resetMemoryDataView"
-	functionNanotime1            = "runtime.nanotime1"
-	functionWalltime             = "runtime.walltime"
-	functionScheduleTimeoutEvent = "runtime.scheduleTimeoutEvent" // TODO: trigger usage
-	functionClearTimeoutEvent    = "runtime.clearTimeoutEvent"    // TODO: trigger usage
-	functionGetRandomData        = "runtime.getRandomData"
+	wasmExitName             = "runtime.wasmExit"
+	wasmWriteName            = "runtime.wasmWrite"
+	resetMemoryDataViewName  = "runtime.resetMemoryDataView"
+	nanotime1Name            = "runtime.nanotime1"
+	walltimeName             = "runtime.walltime"
+	scheduleTimeoutEventName = "runtime.scheduleTimeoutEvent" // TODO: trigger usage
+	clearTimeoutEventName    = "runtime.clearTimeoutEvent"    // TODO: trigger usage
+	getRandomDataName        = "runtime.getRandomData"
 )
 
 // WasmExit implements runtime.wasmExit which supports runtime.exit.
 //
 // See https://github.com/golang/go/blob/go1.19/src/runtime/sys_wasm.go#L28
 var WasmExit = spfunc.MustCallFromSP(false, &wasm.HostFunc{
-	ExportNames: []string{functionWasmExit},
-	Name:        functionWasmExit,
+	ExportNames: []string{wasmExitName},
+	Name:        wasmExitName,
 	ParamTypes:  []api.ValueType{i32},
 	ParamNames:  []string{"code"},
 	Code: &wasm.Code{
@@ -49,8 +49,8 @@ func wasmExit(ctx context.Context, mod api.Module, stack []uint64) {
 //
 // See https://github.com/golang/go/blob/go1.19/src/runtime/os_js.go#L29
 var WasmWrite = spfunc.MustCallFromSP(false, &wasm.HostFunc{
-	ExportNames: []string{functionWasmWrite},
-	Name:        functionWasmWrite,
+	ExportNames: []string{wasmWriteName},
+	Name:        wasmWriteName,
 	ParamTypes:  []api.ValueType{i32, i32, i32},
 	ParamNames:  []string{"fd", "p", "n"},
 	Code: &wasm.Code{
@@ -84,8 +84,8 @@ func wasmWrite(ctx context.Context, mod api.Module, stack []uint64) {
 //
 // See https://github.com/golang/go/blob/go1.19/src/runtime/mem_js.go#L82
 var ResetMemoryDataView = &wasm.HostFunc{
-	ExportNames: []string{functionResetMemoryDataView},
-	Name:        functionResetMemoryDataView,
+	ExportNames: []string{resetMemoryDataViewName},
+	Name:        resetMemoryDataViewName,
 	ParamTypes:  []wasm.ValueType{wasm.ValueTypeI32},
 	ParamNames:  []string{parameterSp},
 	// TODO: Compiler-based memory.grow callbacks are ignored until we have a generic solution #601
@@ -96,8 +96,8 @@ var ResetMemoryDataView = &wasm.HostFunc{
 //
 // See https://github.com/golang/go/blob/go1.19/src/runtime/sys_wasm.s#L184
 var Nanotime1 = spfunc.MustCallFromSP(false, &wasm.HostFunc{
-	ExportNames: []string{functionNanotime1},
-	Name:        functionNanotime1,
+	ExportNames: []string{nanotime1Name},
+	Name:        nanotime1Name,
 	ResultTypes: []api.ValueType{i64},
 	Code: &wasm.Code{
 		IsHostFunction: true,
@@ -114,9 +114,10 @@ func nanotime1(ctx context.Context, mod api.Module, stack []uint64) {
 //
 // See https://github.com/golang/go/blob/go1.19/src/runtime/sys_wasm.s#L188
 var Walltime = spfunc.MustCallFromSP(false, &wasm.HostFunc{
-	ExportNames: []string{functionWalltime},
-	Name:        functionWalltime,
+	ExportNames: []string{walltimeName},
+	Name:        walltimeName,
 	ResultTypes: []api.ValueType{i64, i32},
+	ResultNames: []string{"sec", "nsec"},
 	Code: &wasm.Code{
 		IsHostFunction: true,
 		GoFunc:         api.GoModuleFunc(walltime),
@@ -136,7 +137,7 @@ func walltime(ctx context.Context, mod api.Module, stack []uint64) {
 // goroutine and invokes code compiled into wasm "resume".
 //
 // See https://github.com/golang/go/blob/go1.19/src/runtime/sys_wasm.s#L192
-var ScheduleTimeoutEvent = stubFunction(functionScheduleTimeoutEvent)
+var ScheduleTimeoutEvent = stubFunction(scheduleTimeoutEventName)
 
 // ^^ stubbed because signal handling is not implemented in GOOS=js
 
@@ -144,7 +145,7 @@ var ScheduleTimeoutEvent = stubFunction(functionScheduleTimeoutEvent)
 // runtime.notetsleepg used by runtime.signal_recv.
 //
 // See https://github.com/golang/go/blob/go1.19/src/runtime/sys_wasm.s#L196
-var ClearTimeoutEvent = stubFunction(functionClearTimeoutEvent)
+var ClearTimeoutEvent = stubFunction(clearTimeoutEventName)
 
 // ^^ stubbed because signal handling is not implemented in GOOS=js
 
@@ -153,8 +154,8 @@ var ClearTimeoutEvent = stubFunction(functionClearTimeoutEvent)
 //
 // See https://github.com/golang/go/blob/go1.19/src/runtime/sys_wasm.s#L200
 var GetRandomData = spfunc.MustCallFromSP(false, &wasm.HostFunc{
-	ExportNames: []string{functionGetRandomData},
-	Name:        functionGetRandomData,
+	ExportNames: []string{getRandomDataName},
+	Name:        getRandomDataName,
 	ParamTypes:  []api.ValueType{i32, i32},
 	ParamNames:  []string{"buf", "bufLen"},
 	Code: &wasm.Code{
diff --git a/internal/gojs/spfunc/spfunc.go b/internal/gojs/spfunc/spfunc.go
index 3a42db1e..666d210f 100644
--- a/internal/gojs/spfunc/spfunc.go
+++ b/internal/gojs/spfunc/spfunc.go
@@ -165,8 +165,9 @@ func callFromSP(expectSP bool, proxied *wasm.HostFunc) (*wasm.ProxyFunc, error)
 		Proxied: &wasm.HostFunc{
 			Name:        proxied.Name,
 			ParamTypes:  proxied.ParamTypes,
-			ResultTypes: proxied.ResultTypes,
 			ParamNames:  proxied.ParamNames,
+			ResultTypes: proxied.ResultTypes,
+			ResultNames: proxied.ResultNames,
 			Code:        proxied.Code,
 		},
 		CallBodyPos: callFuncPos,
diff --git a/internal/gojs/syscall.go b/internal/gojs/syscall.go
index 66ecd321..884b077c 100644
--- a/internal/gojs/syscall.go
+++ b/internal/gojs/syscall.go
@@ -16,22 +16,22 @@ import (
 )
 
 const (
-	functionFinalizeRef        = "syscall/js.finalizeRef"
-	functionStringVal          = "syscall/js.stringVal"
-	functionValueGet           = "syscall/js.valueGet"
-	functionValueSet           = "syscall/js.valueSet"
-	functionValueDelete        = "syscall/js.valueDelete" // stubbed
-	functionValueIndex         = "syscall/js.valueIndex"
-	functionValueSetIndex      = "syscall/js.valueSetIndex" // stubbed
-	functionValueCall          = "syscall/js.valueCall"
-	functionValueInvoke        = "syscall/js.valueInvoke" // stubbed
-	functionValueNew           = "syscall/js.valueNew"
-	functionValueLength        = "syscall/js.valueLength"
-	functionValuePrepareString = "syscall/js.valuePrepareString"
-	functionValueLoadString    = "syscall/js.valueLoadString"
-	functionValueInstanceOf    = "syscall/js.valueInstanceOf" // stubbed
-	functionCopyBytesToGo      = "syscall/js.copyBytesToGo"
-	functionCopyBytesToJS      = "syscall/js.copyBytesToJS"
+	finalizeRefName        = "syscall/js.finalizeRef"
+	stringValName          = "syscall/js.stringVal"
+	valueGetName           = "syscall/js.valueGet"
+	valueSetName           = "syscall/js.valueSet"
+	valueDeleteName        = "syscall/js.valueDelete" // stubbed
+	valueIndexName         = "syscall/js.valueIndex"
+	valueSetIndexName      = "syscall/js.valueSetIndex" // stubbed
+	valueCallName          = "syscall/js.valueCall"
+	valueInvokeName        = "syscall/js.valueInvoke" // stubbed
+	valueNewName           = "syscall/js.valueNew"
+	valueLengthName        = "syscall/js.valueLength"
+	valuePrepareStringName = "syscall/js.valuePrepareString"
+	valueLoadStringName    = "syscall/js.valueLoadString"
+	valueInstanceOfName    = "syscall/js.valueInstanceOf" // stubbed
+	copyBytesToGoName      = "syscall/js.copyBytesToGo"
+	copyBytesToJSName      = "syscall/js.copyBytesToJS"
 )
 
 // FinalizeRef implements js.finalizeRef, which is used as a
@@ -39,8 +39,8 @@ const (
 //
 // See https://github.com/golang/go/blob/go1.19/src/syscall/js/js.go#L61
 var FinalizeRef = spfunc.MustCallFromSP(false, &wasm.HostFunc{
-	ExportNames: []string{functionFinalizeRef},
-	Name:        functionFinalizeRef,
+	ExportNames: []string{finalizeRefName},
+	Name:        finalizeRefName,
 	ParamTypes:  []api.ValueType{i32},
 	ParamNames:  []string{"r"},
 	Code: &wasm.Code{
@@ -61,11 +61,12 @@ func finalizeRef(ctx context.Context, stack []uint64) {
 // 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
 var StringVal = spfunc.MustCallFromSP(false, &wasm.HostFunc{
-	ExportNames: []string{functionStringVal},
-	Name:        functionStringVal,
+	ExportNames: []string{stringValName},
+	Name:        stringValName,
 	ParamTypes:  []api.ValueType{i32, i32},
 	ParamNames:  []string{"xAddr", "xLen"},
 	ResultTypes: []api.ValueType{i64},
+	ResultNames: []string{"ref"},
 	Code: &wasm.Code{
 		IsHostFunction: true,
 		GoFunc:         api.GoModuleFunc(stringVal),
@@ -87,11 +88,12 @@ func stringVal(ctx context.Context, mod api.Module, stack []uint64) {
 // 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
 var ValueGet = spfunc.MustCallFromSP(false, &wasm.HostFunc{
-	ExportNames: []string{functionValueGet},
-	Name:        functionValueGet,
+	ExportNames: []string{valueGetName},
+	Name:        valueGetName,
 	ParamTypes:  []api.ValueType{i64, i32, i32},
 	ParamNames:  []string{"v", "pAddr", "pLen"},
 	ResultTypes: []api.ValueType{i64},
+	ResultNames: []string{"ref"},
 	Code: &wasm.Code{
 		IsHostFunction: true,
 		GoFunc:         api.GoModuleFunc(valueGet),
@@ -132,8 +134,8 @@ func valueGet(ctx context.Context, mod api.Module, stack []uint64) {
 // 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
 var ValueSet = spfunc.MustCallFromSP(false, &wasm.HostFunc{
-	ExportNames: []string{functionValueSet},
-	Name:        functionValueSet,
+	ExportNames: []string{valueSetName},
+	Name:        valueSetName,
 	ParamTypes:  []api.ValueType{i64, i32, i32, i64},
 	ParamNames:  []string{"v", "pAddr", "pLen", "x"},
 	Code: &wasm.Code{
@@ -175,7 +177,7 @@ func valueSet(ctx context.Context, mod api.Module, stack []uint64) {
 // 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
-var ValueDelete = stubFunction(functionValueDelete)
+var ValueDelete = stubFunction(valueDeleteName)
 
 // 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
@@ -184,11 +186,12 @@ var ValueDelete = stubFunction(functionValueDelete)
 // 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
 var ValueIndex = spfunc.MustCallFromSP(false, &wasm.HostFunc{
-	ExportNames: []string{functionValueIndex},
-	Name:        functionValueIndex,
+	ExportNames: []string{valueIndexName},
+	Name:        valueIndexName,
 	ParamTypes:  []api.ValueType{i64, i32},
 	ParamNames:  []string{"v", "i"},
 	ResultTypes: []api.ValueType{i64},
+	ResultNames: []string{"ref"},
 	Code: &wasm.Code{
 		IsHostFunction: true,
 		GoFunc:         api.GoFunc(valueIndex),
@@ -209,20 +212,20 @@ func valueIndex(ctx context.Context, stack []uint64) {
 // []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
-var ValueSetIndex = stubFunction(functionValueSetIndex)
+var ValueSetIndex = stubFunction(valueSetIndexName)
 
 // 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
-//
-//	https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L343-L358
+// and https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L343-L358
 var ValueCall = spfunc.MustCallFromSP(true, &wasm.HostFunc{
-	ExportNames: []string{functionValueCall},
-	Name:        functionValueCall,
+	ExportNames: []string{valueCallName},
+	Name:        valueCallName,
 	ParamTypes:  []api.ValueType{i64, i32, i32, i32, i32},
 	ParamNames:  []string{"v", "mAddr", "mLen", "argsArray", "argsLen"},
 	ResultTypes: []api.ValueType{i64, i32, i32},
+	ResultNames: []string{"ref", "ok", "sp"},
 	Code: &wasm.Code{
 		IsHostFunction: true,
 		GoFunc:         api.GoModuleFunc(valueCall),
@@ -260,7 +263,7 @@ func valueCall(ctx context.Context, mod api.Module, stack []uint64) {
 // 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
-var ValueInvoke = stubFunction(functionValueInvoke)
+var ValueInvoke = stubFunction(valueInvokeName)
 
 // ValueNew implements js.valueNew, which is used to call a js.Value, e.g.
 // `array.New(2)`.
@@ -268,11 +271,12 @@ var ValueInvoke = stubFunction(functionValueInvoke)
 // 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
 var ValueNew = spfunc.MustCallFromSP(true, &wasm.HostFunc{
-	ExportNames: []string{functionValueNew},
-	Name:        functionValueNew,
+	ExportNames: []string{valueNewName},
+	Name:        valueNewName,
 	ParamTypes:  []api.ValueType{i64, i32, i32},
 	ParamNames:  []string{"v", "argsArray", "argsLen"},
 	ResultTypes: []api.ValueType{i64, i32, i32},
+	ResultNames: []string{"ref", "ok", "sp"},
 	Code: &wasm.Code{
 		IsHostFunction: true,
 		GoFunc:         api.GoModuleFunc(valueNew),
@@ -335,8 +339,8 @@ func valueNew(ctx context.Context, mod api.Module, stack []uint64) {
 // 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
 var ValueLength = spfunc.MustCallFromSP(false, &wasm.HostFunc{
-	ExportNames: []string{functionValueLength},
-	Name:        functionValueLength,
+	ExportNames: []string{valueLengthName},
+	Name:        valueLengthName,
 	ParamTypes:  []api.ValueType{i64},
 	ParamNames:  []string{"v"},
 	ResultTypes: []api.ValueType{i32},
@@ -363,11 +367,12 @@ func valueLength(ctx context.Context, stack []uint64) {
 // 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
 var ValuePrepareString = spfunc.MustCallFromSP(false, &wasm.HostFunc{
-	ExportNames: []string{functionValuePrepareString},
-	Name:        functionValuePrepareString,
+	ExportNames: []string{valuePrepareStringName},
+	Name:        valuePrepareStringName,
 	ParamTypes:  []api.ValueType{i64},
 	ParamNames:  []string{"v"},
 	ResultTypes: []api.ValueType{i64, i32},
+	ResultNames: []string{"ref", "len"},
 	Code: &wasm.Code{
 		IsHostFunction: true,
 		GoFunc:         api.GoFunc(valuePrepareString),
@@ -393,8 +398,8 @@ func valuePrepareString(ctx context.Context, stack []uint64) {
 //
 //	https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L410-L412
 var ValueLoadString = spfunc.MustCallFromSP(false, &wasm.HostFunc{
-	ExportNames: []string{functionValueLoadString},
-	Name:        functionValueLoadString,
+	ExportNames: []string{valueLoadStringName},
+	Name:        valueLoadStringName,
 	ParamTypes:  []api.ValueType{i64, i32, i32},
 	ParamNames:  []string{"v", "bAddr", "bLen"},
 	Code: &wasm.Code{
@@ -417,7 +422,7 @@ func valueLoadString(ctx context.Context, mod api.Module, stack []uint64) {
 // 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
-var ValueInstanceOf = stubFunction(functionValueInstanceOf)
+var ValueInstanceOf = stubFunction(valueInstanceOfName)
 
 // CopyBytesToGo copies a JavaScript managed byte array to linear memory.
 // For example, this is used to read an HTTP response body.
@@ -430,11 +435,12 @@ var ValueInstanceOf = stubFunction(functionValueInstanceOf)
 // 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
 var CopyBytesToGo = spfunc.MustCallFromSP(false, &wasm.HostFunc{
-	ExportNames: []string{functionCopyBytesToGo},
-	Name:        functionCopyBytesToGo,
+	ExportNames: []string{copyBytesToGoName},
+	Name:        copyBytesToGoName,
 	ParamTypes:  []api.ValueType{i32, i32, i32, i64},
 	ParamNames:  []string{"dstAddr", "dstLen", "_", "src"},
 	ResultTypes: []api.ValueType{i32, i32},
+	ResultNames: []string{"n", "ok"},
 	Code: &wasm.Code{
 		IsHostFunction: true,
 		GoFunc:         api.GoModuleFunc(copyBytesToGo),
@@ -468,14 +474,14 @@ func copyBytesToGo(ctx context.Context, mod api.Module, stack []uint64) {
 //   - 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
-//
-//	https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L438-L448
+// and https://github.com/golang/go/blob/go1.19/misc/wasm/wasm_exec.js#L438-L448
 var CopyBytesToJS = spfunc.MustCallFromSP(false, &wasm.HostFunc{
-	ExportNames: []string{functionCopyBytesToJS},
-	Name:        functionCopyBytesToJS,
+	ExportNames: []string{copyBytesToJSName},
+	Name:        copyBytesToJSName,
 	ParamTypes:  []api.ValueType{i64, i32, i32, i32},
 	ParamNames:  []string{"dst", "srcAddr", "srcLen", "_"},
 	ResultTypes: []api.ValueType{i32, i32},
+	ResultNames: []string{"n", "ok"},
 	Code: &wasm.Code{
 		IsHostFunction: true,
 		GoFunc:         api.GoModuleFunc(copyBytesToJS),
diff --git a/internal/wasm/function_definition.go b/internal/wasm/function_definition.go
index 358ca329..77a8c526 100644
--- a/internal/wasm/function_definition.go
+++ b/internal/wasm/function_definition.go
@@ -40,11 +40,12 @@ func (m *Module) BuildFunctionDefinitions() {
 
 	var moduleName string
 	var functionNames NameMap
-	var localNames IndirectNameMap
+	var localNames, resultNames IndirectNameMap
 	if m.NameSection != nil {
 		moduleName = m.NameSection.ModuleName
 		functionNames = m.NameSection.FunctionNames
 		localNames = m.NameSection.LocalNames
+		resultNames = m.NameSection.ResultNames
 	}
 
 	importCount := m.ImportFuncCount()
@@ -93,6 +94,7 @@ func (m *Module) BuildFunctionDefinitions() {
 		d.name = funcName
 		d.debugName = wasmdebug.FuncName(moduleName, funcName, funcIdx)
 		d.paramNames = paramNames(localNames, funcIdx, len(d.funcType.Params))
+		d.resultNames = paramNames(resultNames, funcIdx, len(d.funcType.Results))
 
 		for _, e := range m.ExportSection {
 			if e.Type == ExternTypeFunc && e.Index == funcIdx {
@@ -113,6 +115,7 @@ type FunctionDefinition struct {
 	importDesc  *[2]string
 	exportNames []string
 	paramNames  []string
+	resultNames []string
 }
 
 // ModuleName implements the same method as documented on api.FunctionDefinition.
@@ -148,22 +151,27 @@ func (f *FunctionDefinition) ExportNames() []string {
 	return f.exportNames
 }
 
-// GoFunc implements the same method as documented on api.FunctionDefinition.
+// GoFunction implements the same method as documented on api.FunctionDefinition.
 func (f *FunctionDefinition) GoFunction() interface{} {
 	return f.goFunc
 }
 
-// ParamNames implements the same method as documented on api.FunctionDefinition.
-func (f *FunctionDefinition) ParamNames() []string {
-	return f.paramNames
-}
-
 // ParamTypes implements api.FunctionDefinition ParamTypes.
 func (f *FunctionDefinition) ParamTypes() []ValueType {
 	return f.funcType.Params
 }
 
+// ParamNames implements the same method as documented on api.FunctionDefinition.
+func (f *FunctionDefinition) ParamNames() []string {
+	return f.paramNames
+}
+
 // ResultTypes implements api.FunctionDefinition ResultTypes.
 func (f *FunctionDefinition) ResultTypes() []ValueType {
 	return f.funcType.Results
 }
+
+// ResultNames implements the same method as documented on api.FunctionDefinition.
+func (f *FunctionDefinition) ResultNames() []string {
+	return f.resultNames
+}
diff --git a/internal/wasm/host.go b/internal/wasm/host.go
index 3faa6320..c610d715 100644
--- a/internal/wasm/host.go
+++ b/internal/wasm/host.go
@@ -38,21 +38,24 @@ type HostFuncExporter interface {
 // HostFunc is a function with an inlined type, used for NewHostModule.
 // Any corresponding FunctionType will be reused or added to the Module.
 type HostFunc struct {
-	// ExportNames is equivalent to  the same method on api.FunctionDefinition.
+	// ExportNames is equivalent to the same method on api.FunctionDefinition.
 	ExportNames []string
 
-	// Name is equivalent to  the same method on api.FunctionDefinition.
+	// Name is equivalent to the same method on api.FunctionDefinition.
 	Name string
 
-	// ParamTypes is equivalent to  the same method on api.FunctionDefinition.
+	// ParamTypes is equivalent to the same method on api.FunctionDefinition.
 	ParamTypes []ValueType
 
-	// ParamNames is equivalent to  the same method on api.FunctionDefinition.
+	// ParamNames is equivalent to the same method on api.FunctionDefinition.
 	ParamNames []string
 
-	// ResultTypes is equivalent to  the same method on api.FunctionDefinition.
+	// ResultTypes is equivalent to the same method on api.FunctionDefinition.
 	ResultTypes []ValueType
 
+	// ResultNames is equivalent to the same method on api.FunctionDefinition.
+	ResultNames []string
+
 	// Code is the equivalent function in the SectionIDCode.
 	Code *Code
 }
@@ -98,11 +101,17 @@ func (f *HostFunc) WithWasm(body []byte) *HostFunc {
 	return &ret
 }
 
+type HostFuncNames struct {
+	Name        string
+	ParamNames  []string
+	ResultNames []string
+}
+
 // NewHostModule is defined internally for use in WASI tests and to keep the code size in the root directory small.
 func NewHostModule(
 	moduleName string,
 	nameToGoFunc map[string]interface{},
-	funcToNames map[string][]string,
+	funcToNames map[string]*HostFuncNames,
 	enabledFeatures api.CoreFeatures,
 ) (m *Module, err error) {
 	if moduleName != "" {
@@ -135,7 +144,7 @@ const maxProxiedFuncIdx = 127
 func addFuncs(
 	m *Module,
 	nameToGoFunc map[string]interface{},
-	funcToNames map[string][]string,
+	funcToNames map[string]*HostFuncNames,
 	enabledFeatures api.CoreFeatures,
 ) (err error) {
 	if m.NameSection == nil {
@@ -192,14 +201,25 @@ func addFuncs(
 				ResultTypes: results,
 				Code:        code,
 			}
-			if names := funcToNames[k]; names != nil {
-				namesLen := len(names)
-				if namesLen > 1 && namesLen-1 != len(params) {
-					return fmt.Errorf("func[%s.%s] has %d params, but %d param names", moduleName, k, namesLen-1, len(params))
+
+			// Assign names to the function, if they exist.
+			ns := funcToNames[k]
+			if name := ns.Name; name != "" {
+				hf.Name = ns.Name
+			}
+			if paramNames := ns.ParamNames; paramNames != nil {
+				if paramNamesLen := len(paramNames); paramNamesLen != len(params) {
+					return fmt.Errorf("func[%s.%s] has %d params, but %d params names", moduleName, k, paramNamesLen, len(params))
 				}
-				hf.Name = names[0]
-				hf.ParamNames = names[1:]
+				hf.ParamNames = paramNames
 			}
+			if resultNames := ns.ResultNames; resultNames != nil {
+				if resultNamesLen := len(resultNames); resultNamesLen != len(results) {
+					return fmt.Errorf("func[%s.%s] has %d results, but %d results names", moduleName, k, resultNamesLen, len(results))
+				}
+				hf.ResultNames = resultNames
+			}
+
 			nameToFunc[k] = hf
 			funcNames = append(funcNames, k)
 		}
@@ -225,6 +245,7 @@ func addFuncs(
 			m.ExportSection = append(m.ExportSection, &Export{Type: ExternTypeFunc, Name: export, Index: idx})
 		}
 		m.NameSection.FunctionNames = append(m.NameSection.FunctionNames, &NameAssoc{Index: idx, Name: hf.Name})
+
 		if len(hf.ParamNames) > 0 {
 			localNames := &NameMapAssoc{Index: idx}
 			for i, n := range hf.ParamNames {
@@ -232,6 +253,13 @@ func addFuncs(
 			}
 			m.NameSection.LocalNames = append(m.NameSection.LocalNames, localNames)
 		}
+		if len(hf.ResultNames) > 0 {
+			resultNames := &NameMapAssoc{Index: idx}
+			for i, n := range hf.ResultNames {
+				resultNames.NameMap = append(resultNames.NameMap, &NameAssoc{Index: Index(i), Name: n})
+			}
+			m.NameSection.ResultNames = append(m.NameSection.ResultNames, resultNames)
+		}
 		idx++
 	}
 	return nil
diff --git a/internal/wasm/module.go b/internal/wasm/module.go
index 8665cc90..20e54792 100644
--- a/internal/wasm/module.go
+++ b/internal/wasm/module.go
@@ -890,6 +890,9 @@ type NameSection struct {
 	// Note: LocalNames are only used for debugging. At runtime, locals are called based on raw numeric index.
 	// Note: This can be nil for any reason including configuration.
 	LocalNames IndirectNameMap
+
+	// ResultNames is a wazero-specific mechanism to store result names.
+	ResultNames IndirectNameMap
 }
 
 // CustomSection contains the name and raw data of a custom section.


Test patch:
diff --git a/builder_test.go b/builder_test.go
index 47e4b83e..7779bd18 100644
--- a/builder_test.go
+++ b/builder_test.go
@@ -89,6 +89,29 @@ func TestNewHostModuleBuilder_Compile(t *testing.T) {
 				},
 			},
 		},
+		{
+			name: "WithFunc WithName WithResultNames",
+			input: func(r Runtime) HostModuleBuilder {
+				return r.NewHostModuleBuilder("").NewFunctionBuilder().
+					WithFunc(uint32_uint32).
+					WithName("get").WithResultNames("x").
+					Export("1")
+			},
+			expected: &wasm.Module{
+				TypeSection: []*wasm.FunctionType{
+					{Params: []api.ValueType{i32}, Results: []api.ValueType{i32}},
+				},
+				FunctionSection: []wasm.Index{0},
+				CodeSection:     []*wasm.Code{wasm.MustParseGoReflectFuncCode(uint32_uint32)},
+				ExportSection: []*wasm.Export{
+					{Name: "1", Type: wasm.ExternTypeFunc, Index: 0},
+				},
+				NameSection: &wasm.NameSection{
+					FunctionNames: wasm.NameMap{{Index: 0, Name: "get"}},
+					ResultNames:   []*wasm.NameMapAssoc{{Index: 0, NameMap: wasm.NameMap{{Index: 0, Name: "x"}}}},
+				},
+			},
+		},
 		{
 			name: "WithFunc overwrites existing",
 			input: func(r Runtime) HostModuleBuilder {
diff --git a/experimental/logging/log_listener_example_test.go b/experimental/logging/log_listener_example_test.go
index d21d31de..de6e4639 100644
--- a/experimental/logging/log_listener_example_test.go
+++ b/experimental/logging/log_listener_example_test.go
@@ -54,7 +54,7 @@ func Example_newHostLoggingListenerFactory() {
 	//	<== ESUCCESS
 	//	==> wasi_snapshot_preview1.random_get(buf=8,buf_len=4)
 	//	<== ESUCCESS
-	//<-- ()
+	//<--
 }
 
 // This example shows how to see all function calls, including between host
@@ -93,6 +93,6 @@ func Example_newLoggingListenerFactory() {
 	//		<== ESUCCESS
 	//		==> wasi_snapshot_preview1.random_get(buf=8,buf_len=4)
 	//		<== ESUCCESS
-	//	<-- ()
-	//<-- ()
+	//	<--
+	//<--
 }
diff --git a/experimental/logging/log_listener_test.go b/experimental/logging/log_listener_test.go
index 3587505e..9f4fffbb 100644
--- a/experimental/logging/log_listener_test.go
+++ b/experimental/logging/log_listener_test.go
@@ -21,26 +21,27 @@ func Test_loggingListener(t *testing.T) {
 	wasiFuncName := "random_get"
 	wasiFuncType := &wasm.FunctionType{
 		Params:  []api.ValueType{api.ValueTypeI32, api.ValueTypeI32},
-		Results: []api.ValueType{api.ValueTypeI32, api.ValueTypeI32},
+		Results: []api.ValueType{api.ValueTypeI32},
 	}
 	wasiParamNames := []string{"buf", "buf_len"}
 	wasiParams := []uint64{0, 8}
+	wasiResultNames := []string{"errno"}
 
 	tests := []struct {
-		name                 string
-		moduleName, funcName string
-		functype             *wasm.FunctionType
-		isHostFunc           bool
-		paramNames           []string
-		params, results      []uint64
-		err                  error
-		expected             string
+		name                    string
+		moduleName, funcName    string
+		functype                *wasm.FunctionType
+		isHostFunc              bool
+		paramNames, resultNames []string
+		params, results         []uint64
+		err                     error
+		expected                string
 	}{
 		{
 			name:     "v_v",
 			functype: &wasm.FunctionType{},
 			expected: `--> test.fn()
-<-- ()
+<--
 `,
 		},
 		{
@@ -56,44 +57,47 @@ func Test_loggingListener(t *testing.T) {
 			functype:   &wasm.FunctionType{},
 			isHostFunc: true,
 			expected: `==> test.fn()
-<== ()
+<==
 `,
 		},
 		{
-			name:       "wasi",
-			functype:   wasiFuncType,
-			moduleName: wasi_snapshot_preview1.ModuleName,
-			funcName:   wasiFuncName,
-			paramNames: wasiParamNames,
-			isHostFunc: true,
-			params:     wasiParams,
-			results:    []uint64{uint64(wasi_snapshot_preview1.ErrnoSuccess)},
+			name:        "wasi",
+			functype:    wasiFuncType,
+			moduleName:  wasi_snapshot_preview1.ModuleName,
+			funcName:    wasiFuncName,
+			paramNames:  wasiParamNames,
+			resultNames: wasiResultNames,
+			isHostFunc:  true,
+			params:      wasiParams,
+			results:     []uint64{uint64(wasi_snapshot_preview1.ErrnoSuccess)},
 			expected: `==> wasi_snapshot_preview1.random_get(buf=0,buf_len=8)
 <== ESUCCESS
 `,
 		},
 		{
-			name:       "wasi errno",
-			functype:   wasiFuncType,
-			moduleName: wasi_snapshot_preview1.ModuleName,
-			funcName:   wasiFuncName,
-			paramNames: wasiParamNames,
-			isHostFunc: true,
-			params:     wasiParams,
-			results:    []uint64{uint64(wasi_snapshot_preview1.ErrnoFault)},
+			name:        "wasi errno",
+			functype:    wasiFuncType,
+			moduleName:  wasi_snapshot_preview1.ModuleName,
+			funcName:    wasiFuncName,
+			paramNames:  wasiParamNames,
+			resultNames: wasiResultNames,
+			isHostFunc:  true,
+			params:      wasiParams,
+			results:     []uint64{uint64(wasi_snapshot_preview1.ErrnoFault)},
 			expected: `==> wasi_snapshot_preview1.random_get(buf=0,buf_len=8)
 <== EFAULT
 `,
 		},
 		{
-			name:       "wasi error",
-			functype:   wasiFuncType,
-			moduleName: wasi_snapshot_preview1.ModuleName,
-			funcName:   wasiFuncName,
-			paramNames: wasiParamNames,
-			isHostFunc: true,
-			params:     wasiParams,
-			err:        io.EOF, // not possible as we coerce errors to numbers, but test anyway!
+			name:        "wasi error",
+			functype:    wasiFuncType,
+			moduleName:  wasi_snapshot_preview1.ModuleName,
+			funcName:    wasiFuncName,
+			paramNames:  wasiParamNames,
+			resultNames: wasiResultNames,
+			isHostFunc:  true,
+			params:      wasiParams,
+			err:         io.EOF, // not possible as we coerce errors to numbers, but test anyway!
 			expected: `==> wasi_snapshot_preview1.random_get(buf=0,buf_len=8)
 <== error: EOF
 `,
@@ -103,7 +107,7 @@ func Test_loggingListener(t *testing.T) {
 			functype: &wasm.FunctionType{Params: []api.ValueType{api.ValueTypeI32}},
 			params:   []uint64{math.MaxUint32},
 			expected: `--> test.fn(4294967295)
-<-- ()
+<--
 `,
 		},
 		{
@@ -112,7 +116,7 @@ func Test_loggingListener(t *testing.T) {
 			params:     []uint64{math.MaxUint32},
 			paramNames: []string{"x"},
 			expected: `--> test.fn(x=4294967295)
-<-- ()
+<--
 `,
 		},
 		{
@@ -120,7 +124,7 @@ func Test_loggingListener(t *testing.T) {
 			functype: &wasm.FunctionType{Params: []api.ValueType{api.ValueTypeI64}},
 			params:   []uint64{math.MaxUint64},
 			expected: `--> test.fn(18446744073709551615)
-<-- ()
+<--
 `,
 		},
 		{
@@ -129,7 +133,7 @@ func Test_loggingListener(t *testing.T) {
 			params:     []uint64{math.MaxUint64},
 			paramNames: []string{"x"},
 			expected: `--> test.fn(x=18446744073709551615)
-<-- ()
+<--
 `,
 		},
 		{
@@ -137,7 +141,7 @@ func Test_loggingListener(t *testing.T) {
 			functype: &wasm.FunctionType{Params: []api.ValueType{api.ValueTypeF32}},
 			params:   []uint64{api.EncodeF32(math.MaxFloat32)},
 			expected: `--> test.fn(3.4028235e+38)
-<-- ()
+<--
 `,
 		},
 		{
@@ -146,7 +150,7 @@ func Test_loggingListener(t *testing.T) {
 			params:     []uint64{api.EncodeF32(math.MaxFloat32)},
 			paramNames: []string{"x"},
 			expected: `--> test.fn(x=3.4028235e+38)
-<-- ()
+<--
 `,
 		},
 		{
@@ -154,7 +158,7 @@ func Test_loggingListener(t *testing.T) {
 			functype: &wasm.FunctionType{Params: []api.ValueType{api.ValueTypeF64}},
 			params:   []uint64{api.EncodeF64(math.MaxFloat64)},
 			expected: `--> test.fn(1.7976931348623157e+308)
-<-- ()
+<--
 `,
 		},
 		{
@@ -163,7 +167,7 @@ func Test_loggingListener(t *testing.T) {
 			params:     []uint64{api.EncodeF64(math.MaxFloat64)},
 			paramNames: []string{"x"},
 			expected: `--> test.fn(x=1.7976931348623157e+308)
-<-- ()
+<--
 `,
 		},
 		{
@@ -171,7 +175,7 @@ func Test_loggingListener(t *testing.T) {
 			functype: &wasm.FunctionType{Params: []api.ValueType{api.ValueTypeExternref}},
 			params:   []uint64{0},
 			expected: `--> test.fn(0000000000000000)
-<-- ()
+<--
 `,
 		},
 		{
@@ -180,7 +184,7 @@ func Test_loggingListener(t *testing.T) {
 			params:     []uint64{0},
 			paramNames: []string{"x"},
 			expected: `--> test.fn(x=0000000000000000)
-<-- ()
+<--
 `,
 		},
 		{
@@ -188,7 +192,7 @@ func Test_loggingListener(t *testing.T) {
 			functype: &wasm.FunctionType{Params: []api.ValueType{0x7b}},
 			params:   []uint64{0, 1},
 			expected: `--> test.fn(00000000000000000000000000000001)
-<-- ()
+<--
 `,
 		},
 		{
@@ -197,7 +201,7 @@ func Test_loggingListener(t *testing.T) {
 			params:     []uint64{0, 1},
 			paramNames: []string{"x"},
 			expected: `--> test.fn(x=00000000000000000000000000000001)
-<-- ()
+<--
 `,
 		},
 		{
@@ -205,7 +209,7 @@ func Test_loggingListener(t *testing.T) {
 			functype: &wasm.FunctionType{Params: []api.ValueType{0x70}},
 			params:   []uint64{0},
 			expected: `--> test.fn(0000000000000000)
-<-- ()
+<--
 `,
 		},
 		{
@@ -214,7 +218,7 @@ func Test_loggingListener(t *testing.T) {
 			params:     []uint64{0},
 			paramNames: []string{"x"},
 			expected: `--> test.fn(x=0000000000000000)
-<-- ()
+<--
 `,
 		},
 		{
@@ -222,7 +226,7 @@ func Test_loggingListener(t *testing.T) {
 			functype: &wasm.FunctionType{Results: []api.ValueType{api.ValueTypeI32}},
 			results:  []uint64{math.MaxUint32},
 			expected: `--> test.fn()
-<-- (4294967295)
+<-- 4294967295
 `,
 		},
 		{
@@ -234,7 +238,7 @@ func Test_loggingListener(t *testing.T) {
 			params:  []uint64{math.MaxUint32},
 			results: []uint64{api.EncodeF32(math.MaxFloat32)},
 			expected: `--> test.fn(4294967295)
-<-- (3.4028235e+38)
+<-- 3.4028235e+38
 `,
 		},
 		{
@@ -283,6 +287,7 @@ func Test_loggingListener(t *testing.T) {
 					ModuleName:    tc.moduleName,
 					FunctionNames: wasm.NameMap{{Name: tc.funcName}},
 					LocalNames:    wasm.IndirectNameMap{{NameMap: toNameMap(tc.paramNames)}},
+					ResultNames:   wasm.IndirectNameMap{{NameMap: toNameMap(tc.resultNames)}},
 				},
 			}
 
@@ -338,7 +343,7 @@ func Test_loggingListener_indentation(t *testing.T) {
 	l1.After(ctx, def1, nil, []uint64{})
 	require.Equal(t, `--> test.fn1()
 	--> test.fn2()
-	<-- ()
-<-- ()
+	<--
+<--
 `, out.String())
 }
diff --git a/imports/assemblyscript/assemblyscript_test.go b/imports/assemblyscript/assemblyscript_test.go
index 0a19133d..96c3544a 100644
--- a/imports/assemblyscript/assemblyscript_test.go
+++ b/imports/assemblyscript/assemblyscript_test.go
@@ -132,8 +132,8 @@ func TestSeed(t *testing.T) {
 	require.Equal(t, `
 --> proxy.seed()
 	==> env.~lib/builtins/seed()
-	<== (4.958153677776298e-175)
-<-- (4.958153677776298e-175)
+	<== rand=4.958153677776298e-175
+<-- 4.958153677776298e-175
 `, "\n"+log.String())
 
 	require.Equal(t, "538c7f96b164bf1b", hex.EncodeToString(u64.LeBytes(ret[0])))
@@ -186,8 +186,8 @@ func TestFunctionExporter_Trace(t *testing.T) {
 	noArgsLog := `
 --> proxy.trace(message=4,nArgs=0,arg0=0,arg1=0,arg2=0,arg3=0,arg4=0)
 	==> env.~lib/builtins/trace(message=4,nArgs=0,arg0=0,arg1=0,arg2=0,arg3=0,arg4=0)
-	<== ()
-<-- ()
+	<==
+<--
 `
 
 	tests := []struct {
@@ -228,8 +228,8 @@ func TestFunctionExporter_Trace(t *testing.T) {
 			expectedLog: `
 --> proxy.trace(message=4,nArgs=1,arg0=1,arg1=0,arg2=0,arg3=0,arg4=0)
 	==> env.~lib/builtins/trace(message=4,nArgs=1,arg0=1,arg1=0,arg2=0,arg3=0,arg4=0)
-	<== ()
-<-- ()
+	<==
+<--
 `,
 		},
 		{
@@ -240,8 +240,8 @@ func TestFunctionExporter_Trace(t *testing.T) {
 			expectedLog: `
 --> proxy.trace(message=4,nArgs=2,arg0=1,arg1=2,arg2=0,arg3=0,arg4=0)
 	==> env.~lib/builtins/trace(message=4,nArgs=2,arg0=1,arg1=2,arg2=0,arg3=0,arg4=0)
-	<== ()
-<-- ()
+	<==
+<--
 `,
 		},
 		{
@@ -260,8 +260,8 @@ func TestFunctionExporter_Trace(t *testing.T) {
 			expectedLog: `
 --> proxy.trace(message=4,nArgs=5,arg0=1,arg1=2,arg2=3.3,arg3=4.4,arg4=5)
 	==> env.~lib/builtins/trace(message=4,nArgs=5,arg0=1,arg1=2,arg2=3.3,arg3=4.4,arg4=5)
-	<== ()
-<-- ()
+	<==
+<--
 `,
 		},
 		{
diff --git a/imports/emscripten/emscripten_test.go b/imports/emscripten/emscripten_test.go
index 487a2aad..1e84b17a 100644
--- a/imports/emscripten/emscripten_test.go
+++ b/imports/emscripten/emscripten_test.go
@@ -81,9 +81,9 @@ func TestInvoke(t *testing.T) {
 			expectedLog: `--> .call_v_i32(0)
 	==> env.invoke_i(index=0)
 		--> .v_i32()
-		<-- (42)
-	<== (42)
-<-- (42)
+		<-- 42
+	<== 42
+<-- 42
 `,
 		},
 		{
@@ -95,9 +95,9 @@ func TestInvoke(t *testing.T) {
 			expectedLog: `--> .call_i32_i32(2,42)
 	==> env.invoke_ii(index=2,a1=42)
 		--> .i32_i32(42)
-		<-- (42)
-	<== (42)
-<-- (42)
+		<-- 42
+	<== 42
+<-- 42
 `,
 		},
 		{
@@ -109,9 +109,9 @@ func TestInvoke(t *testing.T) {
 			expectedLog: `--> .call_i32i32_i32(4,1,2)
 	==> env.invoke_iii(index=4,a1=1,a2=2)
 		--> .i32i32_i32(1,2)
-		<-- (3)
-	<== (3)
-<-- (3)
+		<-- 3
+	<== 3
+<-- 3
 `,
 		},
 		{
@@ -123,9 +123,9 @@ func TestInvoke(t *testing.T) {
 			expectedLog: `--> .call_i32i32i32_i32(6,1,2,4)
 	==> env.invoke_iiii(index=6,a1=1,a2=2,a3=4)
 		--> .i32i32i32_i32(1,2,4)
-		<-- (7)
-	<== (7)
-<-- (7)
+		<-- 7
+	<== 7
+<-- 7
 `,
 		},
 		{
@@ -137,9 +137,9 @@ func TestInvoke(t *testing.T) {
 			expectedLog: `--> .calli32_i32i32i32i32_i32(8,1,2,4,8)
 	==> env.invoke_iiiii(index=8,a1=1,a2=2,a3=4,a4=8)
 		--> .i32i32i32i32_i32(1,2,4,8)
-		<-- (15)
-	<== (15)
-<-- (15)
+		<-- 15
+	<== 15
+<-- 15
 `,
 		},
 		{
@@ -149,9 +149,9 @@ func TestInvoke(t *testing.T) {
 			expectedLog: `--> .call_v_v(10)
 	==> env.invoke_v(index=10)
 		--> .v_v()
-		<-- ()
-	<== ()
-<-- ()
+		<--
+	<==
+<--
 `,
 		},
 		{
@@ -162,9 +162,9 @@ func TestInvoke(t *testing.T) {
 			expectedLog: `--> .call_i32_v(12,42)
 	==> env.invoke_vi(index=12,a1=42)
 		--> .i32_v(42)
-		<-- ()
-	<== ()
-<-- ()
+		<--
+	<==
+<--
 `,
 		},
 		{
@@ -175,9 +175,9 @@ func TestInvoke(t *testing.T) {
 			expectedLog: `--> .call_i32i32_v(14,1,2)
 	==> env.invoke_vii(index=14,a1=1,a2=2)
 		--> .i32i32_v(1,2)
-		<-- ()
-	<== ()
-<-- ()
+		<--
+	<==
+<--
 `,
 		},
 		{
@@ -188,9 +188,9 @@ func TestInvoke(t *testing.T) {
 			expectedLog: `--> .call_i32i32i32_v(16,1,2,4)
 	==> env.invoke_viii(index=16,a1=1,a2=2,a3=4)
 		--> .i32i32i32_v(1,2,4)
-		<-- ()
-	<== ()
-<-- ()
+		<--
+	<==
+<--
 `,
 		},
 		{
@@ -201,9 +201,9 @@ func TestInvoke(t *testing.T) {
 			expectedLog: `--> .calli32_i32i32i32i32_v(18,1,2,4,8)
 	==> env.invoke_viiii(index=18,a1=1,a2=2,a3=4,a4=8)
 		--> .i32i32i32i32_v(1,2,4,8)
-		<-- ()
-	<== ()
-<-- ()
+		<--
+	<==
+<--
 `,
 		},
 	}
diff --git a/imports/wasi_snapshot_preview1/args_test.go b/imports/wasi_snapshot_preview1/args_test.go
index 33a3bd1f..087d61f6 100644
--- a/imports/wasi_snapshot_preview1/args_test.go
+++ b/imports/wasi_snapshot_preview1/args_test.go
@@ -25,12 +25,12 @@ func Test_argsGet(t *testing.T) {
 	maskMemory(t, testCtx, mod, len(expectedMemory))
 
 	// Invoke argsGet and check the memory side effects.
-	requireErrno(t, ErrnoSuccess, mod, functionArgsGet, uint64(argv), uint64(argvBuf))
+	requireErrno(t, ErrnoSuccess, mod, argsGetName, uint64(argv), uint64(argvBuf))
 	require.Equal(t, `
 --> proxy.args_get(argv=7,argv_buf=1)
 	==> wasi_snapshot_preview1.args_get(argv=7,argv_buf=1)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `, "\n"+log.String())
 
 	actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(expectedMemory)))
@@ -58,7 +58,7 @@ func Test_argsGet_Errors(t *testing.T) {
 --> proxy.args_get(argv=65536,argv_buf=0)
 	==> wasi_snapshot_preview1.args_get(argv=65536,argv_buf=0)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -69,7 +69,7 @@ func Test_argsGet_Errors(t *testing.T) {
 --> proxy.args_get(argv=0,argv_buf=65536)
 	==> wasi_snapshot_preview1.args_get(argv=0,argv_buf=65536)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -81,7 +81,7 @@ func Test_argsGet_Errors(t *testing.T) {
 --> proxy.args_get(argv=65529,argv_buf=0)
 	==> wasi_snapshot_preview1.args_get(argv=65529,argv_buf=0)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -93,7 +93,7 @@ func Test_argsGet_Errors(t *testing.T) {
 --> proxy.args_get(argv=0,argv_buf=65532)
 	==> wasi_snapshot_preview1.args_get(argv=0,argv_buf=65532)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 	}
@@ -104,7 +104,7 @@ func Test_argsGet_Errors(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			defer log.Reset()
 
-			requireErrno(t, ErrnoFault, mod, functionArgsGet, uint64(tc.argv), uint64(tc.argvBuf))
+			requireErrno(t, ErrnoFault, mod, argsGetName, uint64(tc.argv), uint64(tc.argvBuf))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 		})
 	}
@@ -127,12 +127,12 @@ func Test_argsSizesGet(t *testing.T) {
 	maskMemory(t, testCtx, mod, len(expectedMemory))
 
 	// Invoke argsSizesGet and check the memory side effects.
-	requireErrno(t, ErrnoSuccess, mod, functionArgsSizesGet, uint64(resultArgc), uint64(resultArgvLen))
+	requireErrno(t, ErrnoSuccess, mod, argsSizesGetName, uint64(resultArgc), uint64(resultArgvLen))
 	require.Equal(t, `
 --> proxy.args_sizes_get(result.argc=1,result.argv_len=6)
 	==> wasi_snapshot_preview1.args_sizes_get(result.argc=1,result.argv_len=6)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `, "\n"+log.String())
 
 	actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(expectedMemory)))
@@ -160,7 +160,7 @@ func Test_argsSizesGet_Errors(t *testing.T) {
 --> proxy.args_sizes_get(result.argc=65536,result.argv_len=0)
 	==> wasi_snapshot_preview1.args_sizes_get(result.argc=65536,result.argv_len=0)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -171,7 +171,7 @@ func Test_argsSizesGet_Errors(t *testing.T) {
 --> proxy.args_sizes_get(result.argc=0,result.argv_len=65536)
 	==> wasi_snapshot_preview1.args_sizes_get(result.argc=0,result.argv_len=65536)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -182,7 +182,7 @@ func Test_argsSizesGet_Errors(t *testing.T) {
 --> proxy.args_sizes_get(result.argc=65533,result.argv_len=0)
 	==> wasi_snapshot_preview1.args_sizes_get(result.argc=65533,result.argv_len=0)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -193,7 +193,7 @@ func Test_argsSizesGet_Errors(t *testing.T) {
 --> proxy.args_sizes_get(result.argc=0,result.argv_len=65533)
 	==> wasi_snapshot_preview1.args_sizes_get(result.argc=0,result.argv_len=65533)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 	}
@@ -204,7 +204,7 @@ func Test_argsSizesGet_Errors(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			defer log.Reset()
 
-			requireErrno(t, ErrnoFault, mod, functionArgsSizesGet, uint64(tc.argc), uint64(tc.argvLen))
+			requireErrno(t, ErrnoFault, mod, argsSizesGetName, uint64(tc.argc), uint64(tc.argvLen))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 		})
 	}
diff --git a/imports/wasi_snapshot_preview1/clock_test.go b/imports/wasi_snapshot_preview1/clock_test.go
index 420c66f3..1cee43d1 100644
--- a/imports/wasi_snapshot_preview1/clock_test.go
+++ b/imports/wasi_snapshot_preview1/clock_test.go
@@ -38,7 +38,7 @@ func Test_clockResGet(t *testing.T) {
 --> proxy.clock_res_get(id=0,result.resolution=1)
 	==> wasi_snapshot_preview1.clock_res_get(id=0,result.resolution=1)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `,
 		},
 		{
@@ -49,7 +49,7 @@ func Test_clockResGet(t *testing.T) {
 --> proxy.clock_res_get(id=1,result.resolution=1)
 	==> wasi_snapshot_preview1.clock_res_get(id=1,result.resolution=1)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `,
 		},
 	}
@@ -63,7 +63,7 @@ func Test_clockResGet(t *testing.T) {
 			maskMemory(t, testCtx, mod, len(tc.expectedMemory))
 
 			resultResolution := uint32(1) // arbitrary offset
-			requireErrno(t, ErrnoSuccess, mod, functionClockResGet, uint64(tc.clockID), uint64(resultResolution))
+			requireErrno(t, ErrnoSuccess, mod, clockResGetName, uint64(tc.clockID), uint64(resultResolution))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
 			actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(tc.expectedMemory)))
@@ -91,7 +91,7 @@ func Test_clockResGet_Unsupported(t *testing.T) {
 --> proxy.clock_res_get(id=2,result.resolution=1)
 	==> wasi_snapshot_preview1.clock_res_get(id=2,result.resolution=1)
 	<== EINVAL
-<-- (28)
+<-- 28
 `,
 		},
 		{
@@ -102,7 +102,7 @@ func Test_clockResGet_Unsupported(t *testing.T) {
 --> proxy.clock_res_get(id=3,result.resolution=1)
 	==> wasi_snapshot_preview1.clock_res_get(id=3,result.resolution=1)
 	<== EINVAL
-<-- (28)
+<-- 28
 `,
 		},
 		{
@@ -113,7 +113,7 @@ func Test_clockResGet_Unsupported(t *testing.T) {
 --> proxy.clock_res_get(id=100,result.resolution=1)
 	==> wasi_snapshot_preview1.clock_res_get(id=100,result.resolution=1)
 	<== EINVAL
-<-- (28)
+<-- 28
 `,
 		},
 	}
@@ -125,7 +125,7 @@ func Test_clockResGet_Unsupported(t *testing.T) {
 			defer log.Reset()
 
 			resultResolution := uint32(1) // arbitrary offset
-			requireErrno(t, tc.expectedErrno, mod, functionClockResGet, uint64(tc.clockID), uint64(resultResolution))
+			requireErrno(t, tc.expectedErrno, mod, clockResGetName, uint64(tc.clockID), uint64(resultResolution))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 		})
 	}
@@ -153,7 +153,7 @@ func Test_clockTimeGet(t *testing.T) {
 --> proxy.clock_time_get(id=0,precision=0,result.timestamp=1)
 	==> wasi_snapshot_preview1.clock_time_get(id=0,precision=0,result.timestamp=1)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `,
 		},
 		{
@@ -168,7 +168,7 @@ func Test_clockTimeGet(t *testing.T) {
 --> proxy.clock_time_get(id=1,precision=0,result.timestamp=1)
 	==> wasi_snapshot_preview1.clock_time_get(id=1,precision=0,result.timestamp=1)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `,
 		},
 	}
@@ -181,7 +181,7 @@ func Test_clockTimeGet(t *testing.T) {
 			maskMemory(t, testCtx, mod, len(tc.expectedMemory))
 
 			resultTimestamp := uint32(1) // arbitrary offset
-			requireErrno(t, ErrnoSuccess, mod, functionClockTimeGet, uint64(tc.clockID), 0 /* TODO: precision */, uint64(resultTimestamp))
+			requireErrno(t, ErrnoSuccess, mod, clockTimeGetName, uint64(tc.clockID), 0 /* TODO: precision */, uint64(resultTimestamp))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
 			actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(tc.expectedMemory)))
@@ -209,7 +209,7 @@ func Test_clockTimeGet_Unsupported(t *testing.T) {
 --> proxy.clock_time_get(id=2,precision=0,result.timestamp=1)
 	==> wasi_snapshot_preview1.clock_time_get(id=2,precision=0,result.timestamp=1)
 	<== EINVAL
-<-- (28)
+<-- 28
 `,
 		},
 		{
@@ -220,7 +220,7 @@ func Test_clockTimeGet_Unsupported(t *testing.T) {
 --> proxy.clock_time_get(id=3,precision=0,result.timestamp=1)
 	==> wasi_snapshot_preview1.clock_time_get(id=3,precision=0,result.timestamp=1)
 	<== EINVAL
-<-- (28)
+<-- 28
 `,
 		},
 		{
@@ -231,7 +231,7 @@ func Test_clockTimeGet_Unsupported(t *testing.T) {
 --> proxy.clock_time_get(id=100,precision=0,result.timestamp=1)
 	==> wasi_snapshot_preview1.clock_time_get(id=100,precision=0,result.timestamp=1)
 	<== EINVAL
-<-- (28)
+<-- 28
 `,
 		},
 	}
@@ -244,7 +244,7 @@ func Test_clockTimeGet_Unsupported(t *testing.T) {
 
 			resultTimestamp := uint32(1) // arbitrary offset
 
-			requireErrno(t, tc.expectedErrno, mod, functionClockTimeGet, uint64(tc.clockID), uint64(0) /* TODO: precision */, uint64(resultTimestamp))
+			requireErrno(t, tc.expectedErrno, mod, clockTimeGetName, uint64(tc.clockID), uint64(0) /* TODO: precision */, uint64(resultTimestamp))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 		})
 	}
@@ -268,7 +268,7 @@ func Test_clockTimeGet_Errors(t *testing.T) {
 --> proxy.clock_time_get(id=0,precision=0,result.timestamp=65536)
 	==> wasi_snapshot_preview1.clock_time_get(id=0,precision=0,result.timestamp=65536)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -278,7 +278,7 @@ func Test_clockTimeGet_Errors(t *testing.T) {
 --> proxy.clock_time_get(id=0,precision=0,result.timestamp=65533)
 	==> wasi_snapshot_preview1.clock_time_get(id=0,precision=0,result.timestamp=65533)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 	}
@@ -289,7 +289,7 @@ func Test_clockTimeGet_Errors(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			defer log.Reset()
 
-			requireErrno(t, ErrnoFault, mod, functionClockTimeGet, uint64(0) /* TODO: id */, uint64(0) /* TODO: precision */, uint64(tc.resultTimestamp))
+			requireErrno(t, ErrnoFault, mod, clockTimeGetName, uint64(0) /* TODO: id */, uint64(0) /* TODO: precision */, uint64(tc.resultTimestamp))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 		})
 	}
diff --git a/imports/wasi_snapshot_preview1/environ_test.go b/imports/wasi_snapshot_preview1/environ_test.go
index da7ec1da..5d2bf088 100644
--- a/imports/wasi_snapshot_preview1/environ_test.go
+++ b/imports/wasi_snapshot_preview1/environ_test.go
@@ -27,12 +27,12 @@ func Test_environGet(t *testing.T) {
 	maskMemory(t, testCtx, mod, len(expectedMemory))
 
 	// Invoke environGet and check the memory side effects.
-	requireErrno(t, ErrnoSuccess, mod, functionEnvironGet, uint64(resultEnviron), uint64(resultEnvironBuf))
+	requireErrno(t, ErrnoSuccess, mod, environGetName, uint64(resultEnviron), uint64(resultEnvironBuf))
 	require.Equal(t, `
 --> proxy.environ_get(environ=11,environ_buf=1)
 	==> wasi_snapshot_preview1.environ_get(environ=11,environ_buf=1)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `, "\n"+log.String())
 
 	actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(expectedMemory)))
@@ -61,7 +61,7 @@ func Test_environGet_Errors(t *testing.T) {
 --> proxy.environ_get(environ=65536,environ_buf=0)
 	==> wasi_snapshot_preview1.environ_get(environ=65536,environ_buf=0)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -72,7 +72,7 @@ func Test_environGet_Errors(t *testing.T) {
 --> proxy.environ_get(environ=0,environ_buf=65536)
 	==> wasi_snapshot_preview1.environ_get(environ=0,environ_buf=65536)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -84,7 +84,7 @@ func Test_environGet_Errors(t *testing.T) {
 --> proxy.environ_get(environ=65529,environ_buf=0)
 	==> wasi_snapshot_preview1.environ_get(environ=65529,environ_buf=0)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -96,7 +96,7 @@ func Test_environGet_Errors(t *testing.T) {
 --> proxy.environ_get(environ=0,environ_buf=65527)
 	==> wasi_snapshot_preview1.environ_get(environ=0,environ_buf=65527)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 	}
@@ -107,7 +107,7 @@ func Test_environGet_Errors(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			defer log.Reset()
 
-			requireErrno(t, ErrnoFault, mod, functionEnvironGet, uint64(tc.environ), uint64(tc.environBuf))
+			requireErrno(t, ErrnoFault, mod, environGetName, uint64(tc.environ), uint64(tc.environBuf))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 		})
 	}
@@ -131,12 +131,12 @@ func Test_environSizesGet(t *testing.T) {
 	maskMemory(t, testCtx, mod, len(expectedMemory))
 
 	// Invoke environSizesGet and check the memory side effects.
-	requireErrno(t, ErrnoSuccess, mod, functionEnvironSizesGet, uint64(resultEnvironc), uint64(resultEnvironvLen))
+	requireErrno(t, ErrnoSuccess, mod, environSizesGetName, uint64(resultEnvironc), uint64(resultEnvironvLen))
 	require.Equal(t, `
 --> proxy.environ_sizes_get(result.environc=1,result.environv_len=6)
 	==> wasi_snapshot_preview1.environ_sizes_get(result.environc=1,result.environv_len=6)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `, "\n"+log.String())
 
 	actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(expectedMemory)))
@@ -165,7 +165,7 @@ func Test_environSizesGet_Errors(t *testing.T) {
 --> proxy.environ_sizes_get(result.environc=65536,result.environv_len=0)
 	==> wasi_snapshot_preview1.environ_sizes_get(result.environc=65536,result.environv_len=0)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -176,7 +176,7 @@ func Test_environSizesGet_Errors(t *testing.T) {
 --> proxy.environ_sizes_get(result.environc=0,result.environv_len=65536)
 	==> wasi_snapshot_preview1.environ_sizes_get(result.environc=0,result.environv_len=65536)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -187,7 +187,7 @@ func Test_environSizesGet_Errors(t *testing.T) {
 --> proxy.environ_sizes_get(result.environc=65533,result.environv_len=0)
 	==> wasi_snapshot_preview1.environ_sizes_get(result.environc=65533,result.environv_len=0)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -198,7 +198,7 @@ func Test_environSizesGet_Errors(t *testing.T) {
 --> proxy.environ_sizes_get(result.environc=0,result.environv_len=65533)
 	==> wasi_snapshot_preview1.environ_sizes_get(result.environc=0,result.environv_len=65533)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 	}
@@ -209,7 +209,7 @@ func Test_environSizesGet_Errors(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			defer log.Reset()
 
-			requireErrno(t, ErrnoFault, mod, functionEnvironSizesGet, uint64(tc.environc), uint64(tc.environLen))
+			requireErrno(t, ErrnoFault, mod, environSizesGetName, uint64(tc.environc), uint64(tc.environLen))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 		})
 	}
diff --git a/imports/wasi_snapshot_preview1/fs_test.go b/imports/wasi_snapshot_preview1/fs_test.go
index 6931971d..6a65d18f 100644
--- a/imports/wasi_snapshot_preview1/fs_test.go
+++ b/imports/wasi_snapshot_preview1/fs_test.go
@@ -21,23 +21,23 @@ import (
 
 // Test_fdAdvise only tests it is stubbed for GrainLang per #271
 func Test_fdAdvise(t *testing.T) {
-	log := requireErrnoNosys(t, functionFdAdvise, 0, 0, 0, 0)
+	log := requireErrnoNosys(t, fdAdviseName, 0, 0, 0, 0)
 	require.Equal(t, `
 --> proxy.fd_advise(fd=0,offset=0,len=0,result.advice=0)
 	--> wasi_snapshot_preview1.fd_advise(fd=0,offset=0,len=0,result.advice=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
 // Test_fdAllocate only tests it is stubbed for GrainLang per #271
 func Test_fdAllocate(t *testing.T) {
-	log := requireErrnoNosys(t, functionFdAllocate, 0, 0, 0)
+	log := requireErrnoNosys(t, fdAllocateName, 0, 0, 0)
 	require.Equal(t, `
 --> proxy.fd_allocate(fd=0,offset=0,len=0)
 	--> wasi_snapshot_preview1.fd_allocate(fd=0,offset=0,len=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
@@ -59,12 +59,12 @@ func Test_fdClose(t *testing.T) {
 	require.NoError(t, err)
 
 	// Close
-	requireErrno(t, ErrnoSuccess, mod, functionFdClose, uint64(fdToClose))
+	requireErrno(t, ErrnoSuccess, mod, fdCloseName, uint64(fdToClose))
 	require.Equal(t, `
 --> proxy.fd_close(fd=4)
 	==> wasi_snapshot_preview1.fd_close(fd=4)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `, "\n"+log.String())
 
 	// Verify fdToClose is closed and removed from the opened FDs.
@@ -77,24 +77,24 @@ func Test_fdClose(t *testing.T) {
 
 	log.Reset()
 	t.Run("ErrnoBadF for an invalid FD", func(t *testing.T) {
-		requireErrno(t, ErrnoBadf, mod, functionFdClose, uint64(42)) // 42 is an arbitrary invalid FD
+		requireErrno(t, ErrnoBadf, mod, fdCloseName, uint64(42)) // 42 is an arbitrary invalid FD
 		require.Equal(t, `
 --> proxy.fd_close(fd=42)
 	==> wasi_snapshot_preview1.fd_close(fd=42)
 	<== EBADF
-<-- (8)
+<-- 8
 `, "\n"+log.String())
 	})
 }
 
 // Test_fdDatasync only tests it is stubbed for GrainLang per #271
 func Test_fdDatasync(t *testing.T) {
-	log := requireErrnoNosys(t, functionFdDatasync, 0)
+	log := requireErrnoNosys(t, fdDatasyncName, 0)
 	require.Equal(t, `
 --> proxy.fd_datasync(fd=0)
 	--> wasi_snapshot_preview1.fd_datasync(fd=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
@@ -130,7 +130,7 @@ func Test_fdFdstatGet(t *testing.T) {
 --> proxy.fd_fdstat_get(fd=4,result.stat=0)
 	==> wasi_snapshot_preview1.fd_fdstat_get(fd=4,result.stat=0)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `,
 		},
 		{
@@ -141,7 +141,7 @@ func Test_fdFdstatGet(t *testing.T) {
 --> proxy.fd_fdstat_get(fd=5,result.stat=0)
 	==> wasi_snapshot_preview1.fd_fdstat_get(fd=5,result.stat=0)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `,
 		},
 		{
@@ -152,7 +152,7 @@ func Test_fdFdstatGet(t *testing.T) {
 --> proxy.fd_fdstat_get(fd=4294967295,result.stat=0)
 	==> wasi_snapshot_preview1.fd_fdstat_get(fd=4294967295,result.stat=0)
 	<== EBADF
-<-- (8)
+<-- 8
 `,
 		},
 		{
@@ -164,7 +164,7 @@ func Test_fdFdstatGet(t *testing.T) {
 --> proxy.fd_fdstat_get(fd=5,result.stat=65513)
 	==> wasi_snapshot_preview1.fd_fdstat_get(fd=5,result.stat=65513)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `,
 		},
 	}
@@ -175,7 +175,7 @@ func Test_fdFdstatGet(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			defer log.Reset()
 
-			requireErrno(t, tc.expectedErrno, mod, functionFdFdstatGet, uint64(tc.fd), uint64(tc.resultStat))
+			requireErrno(t, tc.expectedErrno, mod, fdFdstatGetName, uint64(tc.fd), uint64(tc.resultStat))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 		})
 	}
@@ -183,23 +183,23 @@ func Test_fdFdstatGet(t *testing.T) {
 
 // Test_fdFdstatSetFlags only tests it is stubbed for GrainLang per #271
 func Test_fdFdstatSetFlags(t *testing.T) {
-	log := requireErrnoNosys(t, functionFdFdstatSetFlags, 0, 0)
+	log := requireErrnoNosys(t, fdFdstatSetFlagsName, 0, 0)
 	require.Equal(t, `
 --> proxy.fd_fdstat_set_flags(fd=0,flags=0)
 	--> wasi_snapshot_preview1.fd_fdstat_set_flags(fd=0,flags=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
 // Test_fdFdstatSetRights only tests it is stubbed for GrainLang per #271
 func Test_fdFdstatSetRights(t *testing.T) {
-	log := requireErrnoNosys(t, functionFdFdstatSetRights, 0, 0, 0)
+	log := requireErrnoNosys(t, fdFdstatSetRightsName, 0, 0, 0)
 	require.Equal(t, `
 --> proxy.fd_fdstat_set_rights(fd=0,fs_rights_base=0,fs_rights_inheriting=0)
 	--> wasi_snapshot_preview1.fd_fdstat_set_rights(fd=0,fs_rights_base=0,fs_rights_inheriting=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
@@ -244,7 +244,7 @@ func Test_fdFilestatGet(t *testing.T) {
 --> proxy.fd_filestat_get(fd=4,result.buf=0)
 	==> wasi_snapshot_preview1.fd_filestat_get(fd=4,result.buf=0)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `,
 		},
 		{
@@ -264,7 +264,7 @@ func Test_fdFilestatGet(t *testing.T) {
 --> proxy.fd_filestat_get(fd=5,result.buf=0)
 	==> wasi_snapshot_preview1.fd_filestat_get(fd=5,result.buf=0)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `,
 		},
 		{
@@ -275,7 +275,7 @@ func Test_fdFilestatGet(t *testing.T) {
 --> proxy.fd_filestat_get(fd=4294967295,result.buf=0)
 	==> wasi_snapshot_preview1.fd_filestat_get(fd=4294967295,result.buf=0)
 	<== EBADF
-<-- (8)
+<-- 8
 `,
 		},
 		{
@@ -287,7 +287,7 @@ func Test_fdFilestatGet(t *testing.T) {
 --> proxy.fd_filestat_get(fd=5,result.buf=65473)
 	==> wasi_snapshot_preview1.fd_filestat_get(fd=5,result.buf=65473)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 	}
@@ -300,7 +300,7 @@ func Test_fdFilestatGet(t *testing.T) {
 
 			maskMemory(t, testCtx, mod, len(tc.expectedMemory))
 
-			requireErrno(t, tc.expectedErrno, mod, functionFdFilestatGet, uint64(tc.fd), uint64(tc.resultFilestat))
+			requireErrno(t, tc.expectedErrno, mod, fdFilestatGetName, uint64(tc.fd), uint64(tc.resultFilestat))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
 			actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(tc.expectedMemory)))
@@ -312,23 +312,23 @@ func Test_fdFilestatGet(t *testing.T) {
 
 // Test_fdFilestatSetSize only tests it is stubbed for GrainLang per #271
 func Test_fdFilestatSetSize(t *testing.T) {
-	log := requireErrnoNosys(t, functionFdFilestatSetSize, 0, 0)
+	log := requireErrnoNosys(t, fdFilestatSetSizeName, 0, 0)
 	require.Equal(t, `
 --> proxy.fd_filestat_set_size(fd=0,size=0)
 	--> wasi_snapshot_preview1.fd_filestat_set_size(fd=0,size=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
 // Test_fdFilestatSetTimes only tests it is stubbed for GrainLang per #271
 func Test_fdFilestatSetTimes(t *testing.T) {
-	log := requireErrnoNosys(t, functionFdFilestatSetTimes, 0, 0, 0, 0)
+	log := requireErrnoNosys(t, fdFilestatSetTimesName, 0, 0, 0, 0)
 	require.Equal(t, `
 --> proxy.fd_filestat_set_times(fd=0,atim=0,mtim=0,fst_flags=0)
 	--> wasi_snapshot_preview1.fd_filestat_set_times(fd=0,atim=0,mtim=0,fst_flags=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
@@ -371,7 +371,7 @@ func Test_fdPread(t *testing.T) {
 --> proxy.fd_pread(fd=4,iovs=1,iovs_len=2,offset=0,result.size=26)
 	==> wasi_snapshot_preview1.fd_pread(fd=4,iovs=1,iovs_len=2,offset=0,result.size=26)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `,
 		},
 		{
@@ -388,7 +388,7 @@ func Test_fdPread(t *testing.T) {
 --> proxy.fd_pread(fd=4,iovs=1,iovs_len=2,offset=2,result.size=26)
 	==> wasi_snapshot_preview1.fd_pread(fd=4,iovs=1,iovs_len=2,offset=2,result.size=26)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `,
 		},
 	}
@@ -403,7 +403,7 @@ func Test_fdPread(t *testing.T) {
 			ok := mod.Memory().Write(testCtx, 0, initialMemory)
 			require.True(t, ok)
 
-			requireErrno(t, ErrnoSuccess, mod, functionFdPread, uint64(fd), uint64(iovs), uint64(iovsCount), uint64(tc.offset), uint64(resultSize))
+			requireErrno(t, ErrnoSuccess, mod, fdPreadName, uint64(fd), uint64(iovs), uint64(iovsCount), uint64(tc.offset), uint64(resultSize))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
 			actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(tc.expectedMemory)))
@@ -434,7 +434,7 @@ func Test_fdPread_Errors(t *testing.T) {
 --> proxy.fd_pread(fd=42,iovs=65536,iovs_len=65536,offset=0,result.size=65536)
 	==> wasi_snapshot_preview1.fd_pread(fd=42,iovs=65536,iovs_len=65536,offset=0,result.size=65536)
 	<== EBADF
-<-- (8)
+<-- 8
 `,
 		},
 		{
@@ -446,7 +446,7 @@ func Test_fdPread_Errors(t *testing.T) {
 --> proxy.fd_pread(fd=4,iovs=65536,iovs_len=65536,offset=7,result.size=65536)
 	==> wasi_snapshot_preview1.fd_pread(fd=4,iovs=65536,iovs_len=65536,offset=7,result.size=65536)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -459,7 +459,7 @@ func Test_fdPread_Errors(t *testing.T) {
 --> proxy.fd_pread(fd=4,iovs=65536,iovs_len=65535,offset=0,result.size=65535)
 	==> wasi_snapshot_preview1.fd_pread(fd=4,iovs=65536,iovs_len=65535,offset=0,result.size=65535)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -475,7 +475,7 @@ func Test_fdPread_Errors(t *testing.T) {
 --> proxy.fd_pread(fd=4,iovs=65532,iovs_len=65532,offset=0,result.size=65531)
 	==> wasi_snapshot_preview1.fd_pread(fd=4,iovs=65532,iovs_len=65532,offset=0,result.size=65531)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -492,7 +492,7 @@ func Test_fdPread_Errors(t *testing.T) {
 --> proxy.fd_pread(fd=4,iovs=65528,iovs_len=65528,offset=0,result.size=65527)
 	==> wasi_snapshot_preview1.fd_pread(fd=4,iovs=65528,iovs_len=65528,offset=0,result.size=65527)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -510,7 +510,7 @@ func Test_fdPread_Errors(t *testing.T) {
 --> proxy.fd_pread(fd=4,iovs=65527,iovs_len=65527,offset=0,result.size=65526)
 	==> wasi_snapshot_preview1.fd_pread(fd=4,iovs=65527,iovs_len=65527,offset=0,result.size=65526)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -529,7 +529,7 @@ func Test_fdPread_Errors(t *testing.T) {
 --> proxy.fd_pread(fd=4,iovs=65527,iovs_len=65527,offset=0,result.size=65536)
 	==> wasi_snapshot_preview1.fd_pread(fd=4,iovs=65527,iovs_len=65527,offset=0,result.size=65536)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 	}
@@ -544,7 +544,7 @@ func Test_fdPread_Errors(t *testing.T) {
 			memoryWriteOK := mod.Memory().Write(testCtx, offset, tc.memory)
 			require.True(t, memoryWriteOK)
 
-			requireErrno(t, tc.expectedErrno, mod, functionFdPread, uint64(tc.fd), uint64(tc.iovs+offset), uint64(tc.iovsCount+offset), uint64(tc.offset), uint64(tc.resultSize+offset))
+			requireErrno(t, tc.expectedErrno, mod, fdPreadName, uint64(tc.fd), uint64(tc.iovs+offset), uint64(tc.iovsCount+offset), uint64(tc.offset), uint64(tc.resultSize+offset))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 		})
 	}
@@ -567,12 +567,12 @@ func Test_fdPrestatGet(t *testing.T) {
 
 	maskMemory(t, testCtx, mod, len(expectedMemory))
 
-	requireErrno(t, ErrnoSuccess, mod, functionFdPrestatGet, uint64(fd), uint64(resultPrestat))
+	requireErrno(t, ErrnoSuccess, mod, fdPrestatGetName, uint64(fd), uint64(resultPrestat))
 	require.Equal(t, `
 --> proxy.fd_prestat_get(fd=4,result.prestat=1)
 	==> wasi_snapshot_preview1.fd_prestat_get(fd=4,result.prestat=1)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `, "\n"+log.String())
 
 	actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(expectedMemory)))
@@ -602,7 +602,7 @@ func Test_fdPrestatGet_Errors(t *testing.T) {
 --> proxy.fd_prestat_get(fd=42,result.prestat=0)
 	==> wasi_snapshot_preview1.fd_prestat_get(fd=42,result.prestat=0)
 	<== EBADF
-<-- (8)
+<-- 8
 `,
 		},
 		{
@@ -614,7 +614,7 @@ func Test_fdPrestatGet_Errors(t *testing.T) {
 --> proxy.fd_prestat_get(fd=4,result.prestat=65536)
 	==> wasi_snapshot_preview1.fd_prestat_get(fd=4,result.prestat=65536)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		// TODO: non pre-opened file == api.ErrnoBadf
@@ -626,7 +626,7 @@ func Test_fdPrestatGet_Errors(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			defer log.Reset()
 
-			requireErrno(t, tc.expectedErrno, mod, functionFdPrestatGet, uint64(tc.fd), uint64(tc.resultPrestat))
+			requireErrno(t, tc.expectedErrno, mod, fdPrestatGetName, uint64(tc.fd), uint64(tc.resultPrestat))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 		})
 	}
@@ -647,12 +647,12 @@ func Test_fdPrestatDirName(t *testing.T) {
 
 	maskMemory(t, testCtx, mod, len(expectedMemory))
 
-	requireErrno(t, ErrnoSuccess, mod, functionFdPrestatDirName, uint64(fd), uint64(path), uint64(pathLen))
+	requireErrno(t, ErrnoSuccess, mod, fdPrestatDirNameName, uint64(fd), uint64(path), uint64(pathLen))
 	require.Equal(t, `
 --> proxy.fd_prestat_dir_name(fd=4,path=1,path_len=3)
 	==> wasi_snapshot_preview1.fd_prestat_dir_name(fd=4,path=1,path_len=3)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `, "\n"+log.String())
 
 	actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(expectedMemory)))
@@ -687,7 +687,7 @@ func Test_fdPrestatDirName_Errors(t *testing.T) {
 --> proxy.fd_prestat_dir_name(fd=4,path=65536,path_len=4)
 	==> wasi_snapshot_preview1.fd_prestat_dir_name(fd=4,path=65536,path_len=4)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -700,7 +700,7 @@ func Test_fdPrestatDirName_Errors(t *testing.T) {
 --> proxy.fd_prestat_dir_name(fd=4,path=65533,path_len=4)
 	==> wasi_snapshot_preview1.fd_prestat_dir_name(fd=4,path=65533,path_len=4)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -713,7 +713,7 @@ func Test_fdPrestatDirName_Errors(t *testing.T) {
 --> proxy.fd_prestat_dir_name(fd=4,path=0,path_len=5)
 	==> wasi_snapshot_preview1.fd_prestat_dir_name(fd=4,path=0,path_len=5)
 	<== ENAMETOOLONG
-<-- (37)
+<-- 37
 `,
 		},
 		{
@@ -726,7 +726,7 @@ func Test_fdPrestatDirName_Errors(t *testing.T) {
 --> proxy.fd_prestat_dir_name(fd=42,path=0,path_len=4)
 	==> wasi_snapshot_preview1.fd_prestat_dir_name(fd=42,path=0,path_len=4)
 	<== EBADF
-<-- (8)
+<-- 8
 `,
 		},
 		// TODO: non pre-opened file == ErrnoBadf
@@ -738,7 +738,7 @@ func Test_fdPrestatDirName_Errors(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			defer log.Reset()
 
-			requireErrno(t, tc.expectedErrno, mod, functionFdPrestatDirName, uint64(tc.fd), uint64(tc.path), uint64(tc.pathLen))
+			requireErrno(t, tc.expectedErrno, mod, fdPrestatDirNameName, uint64(tc.fd), uint64(tc.path), uint64(tc.pathLen))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 		})
 	}
@@ -746,12 +746,12 @@ func Test_fdPrestatDirName_Errors(t *testing.T) {
 
 // Test_fdPwrite only tests it is stubbed for GrainLang per #271
 func Test_fdPwrite(t *testing.T) {
-	log := requireErrnoNosys(t, functionFdPwrite, 0, 0, 0, 0, 0)
+	log := requireErrnoNosys(t, fdPwriteName, 0, 0, 0, 0, 0)
 	require.Equal(t, `
 --> proxy.fd_pwrite(fd=0,iovs=0,iovs_len=0,offset=0,result.nwritten=0)
 	--> wasi_snapshot_preview1.fd_pwrite(fd=0,iovs=0,iovs_len=0,offset=0,result.nwritten=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
@@ -785,12 +785,12 @@ func Test_fdRead(t *testing.T) {
 	ok := mod.Memory().Write(testCtx, 0, initialMemory)
 	require.True(t, ok)
 
-	requireErrno(t, ErrnoSuccess, mod, functionFdRead, uint64(fd), uint64(iovs), uint64(iovsCount), uint64(resultSize))
+	requireErrno(t, ErrnoSuccess, mod, fdReadName, uint64(fd), uint64(iovs), uint64(iovsCount), uint64(resultSize))
 	require.Equal(t, `
 --> proxy.fd_read(fd=4,iovs=1,iovs_len=2,result.size=26)
 	==> wasi_snapshot_preview1.fd_read(fd=4,iovs=1,iovs_len=2,result.size=26)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `, "\n"+log.String())
 
 	actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(expectedMemory)))
@@ -817,7 +817,7 @@ func Test_fdRead_Errors(t *testing.T) {
 --> proxy.fd_read(fd=42,iovs=65536,iovs_len=65536,result.size=65536)
 	==> wasi_snapshot_preview1.fd_read(fd=42,iovs=65536,iovs_len=65536,result.size=65536)
 	<== EBADF
-<-- (8)
+<-- 8
 `,
 		},
 		{
@@ -830,7 +830,7 @@ func Test_fdRead_Errors(t *testing.T) {
 --> proxy.fd_read(fd=4,iovs=65536,iovs_len=65535,result.size=65535)
 	==> wasi_snapshot_preview1.fd_read(fd=4,iovs=65536,iovs_len=65535,result.size=65535)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -846,7 +846,7 @@ func Test_fdRead_Errors(t *testing.T) {
 --> proxy.fd_read(fd=4,iovs=65532,iovs_len=65532,result.size=65531)
 	==> wasi_snapshot_preview1.fd_read(fd=4,iovs=65532,iovs_len=65532,result.size=65531)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -863,7 +863,7 @@ func Test_fdRead_Errors(t *testing.T) {
 --> proxy.fd_read(fd=4,iovs=65528,iovs_len=65528,result.size=65527)
 	==> wasi_snapshot_preview1.fd_read(fd=4,iovs=65528,iovs_len=65528,result.size=65527)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -881,7 +881,7 @@ func Test_fdRead_Errors(t *testing.T) {
 --> proxy.fd_read(fd=4,iovs=65527,iovs_len=65527,result.size=65526)
 	==> wasi_snapshot_preview1.fd_read(fd=4,iovs=65527,iovs_len=65527,result.size=65526)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -900,7 +900,7 @@ func Test_fdRead_Errors(t *testing.T) {
 --> proxy.fd_read(fd=4,iovs=65527,iovs_len=65527,result.size=65536)
 	==> wasi_snapshot_preview1.fd_read(fd=4,iovs=65527,iovs_len=65527,result.size=65536)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 	}
@@ -915,7 +915,7 @@ func Test_fdRead_Errors(t *testing.T) {
 			memoryWriteOK := mod.Memory().Write(testCtx, offset, tc.memory)
 			require.True(t, memoryWriteOK)
 
-			requireErrno(t, tc.expectedErrno, mod, functionFdRead, uint64(tc.fd), uint64(tc.iovs+offset), uint64(tc.iovsCount+offset), uint64(tc.resultSize+offset))
+			requireErrno(t, tc.expectedErrno, mod, fdReadName, uint64(tc.fd), uint64(tc.iovs+offset), uint64(tc.iovsCount+offset), uint64(tc.resultSize+offset))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 		})
 	}
@@ -1319,7 +1319,7 @@ func Test_fdReaddir(t *testing.T) {
 
 			// use an arbitrarily high value for the buf used position.
 			resultBufused := uint32(16192)
-			requireErrno(t, ErrnoSuccess, mod, functionFdReaddir,
+			requireErrno(t, ErrnoSuccess, mod, fdReaddirName,
 				uint64(fd), uint64(tc.buf), uint64(tc.bufLen), uint64(tc.cookie), uint64(resultBufused))
 
 			// read back the bufused and compare memory against it
@@ -1374,7 +1374,7 @@ func Test_fdReaddir_Errors(t *testing.T) {
 --> proxy.fd_readdir(fd=4,buf=65536,buf_len=1000,cookie=0,result.bufused=0)
 	==> wasi_snapshot_preview1.fd_readdir(fd=4,buf=65536,buf_len=1000,cookie=0,result.bufused=0)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -1385,7 +1385,7 @@ func Test_fdReaddir_Errors(t *testing.T) {
 --> proxy.fd_readdir(fd=42,buf=0,buf_len=0,cookie=0,result.bufused=0)
 	==> wasi_snapshot_preview1.fd_readdir(fd=42,buf=0,buf_len=0,cookie=0,result.bufused=0)
 	<== EBADF
-<-- (8)
+<-- 8
 `,
 		},
 		{
@@ -1396,7 +1396,7 @@ func Test_fdReaddir_Errors(t *testing.T) {
 --> proxy.fd_readdir(fd=5,buf=0,buf_len=0,cookie=0,result.bufused=0)
 	==> wasi_snapshot_preview1.fd_readdir(fd=5,buf=0,buf_len=0,cookie=0,result.bufused=0)
 	<== ENOTDIR
-<-- (54)
+<-- 54
 `,
 		},
 		{
@@ -1409,7 +1409,7 @@ func Test_fdReaddir_Errors(t *testing.T) {
 --> proxy.fd_readdir(fd=4,buf=65536,buf_len=1000,cookie=0,result.bufused=0)
 	==> wasi_snapshot_preview1.fd_readdir(fd=4,buf=65536,buf_len=1000,cookie=0,result.bufused=0)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -1422,7 +1422,7 @@ func Test_fdReaddir_Errors(t *testing.T) {
 --> proxy.fd_readdir(fd=4,buf=65535,buf_len=1000,cookie=0,result.bufused=0)
 	==> wasi_snapshot_preview1.fd_readdir(fd=4,buf=65535,buf_len=1000,cookie=0,result.bufused=0)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -1435,7 +1435,7 @@ func Test_fdReaddir_Errors(t *testing.T) {
 --> proxy.fd_readdir(fd=4,buf=0,buf_len=1,cookie=0,result.bufused=65536)
 	==> wasi_snapshot_preview1.fd_readdir(fd=4,buf=0,buf_len=1,cookie=0,result.bufused=65536)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -1449,7 +1449,7 @@ func Test_fdReaddir_Errors(t *testing.T) {
 --> proxy.fd_readdir(fd=4,buf=0,buf_len=1000,cookie=1,result.bufused=2000)
 	==> wasi_snapshot_preview1.fd_readdir(fd=4,buf=0,buf_len=1000,cookie=1,result.bufused=2000)
 	<== EINVAL
-<-- (28)
+<-- 28
 `,
 		},
 		{
@@ -1464,7 +1464,7 @@ func Test_fdReaddir_Errors(t *testing.T) {
 --> proxy.fd_readdir(fd=4,buf=0,buf_len=1000,cookie=18446744073709551615,result.bufused=2000)
 	==> wasi_snapshot_preview1.fd_readdir(fd=4,buf=0,buf_len=1000,cookie=18446744073709551615,result.bufused=2000)
 	<== EINVAL
-<-- (28)
+<-- 28
 `,
 		},
 	}
@@ -1484,7 +1484,7 @@ func Test_fdReaddir_Errors(t *testing.T) {
 				file.ReadDir = nil
 			}
 
-			requireErrno(t, tc.expectedErrno, mod, functionFdReaddir,
+			requireErrno(t, tc.expectedErrno, mod, fdReaddirName,
 				uint64(tc.fd), uint64(tc.buf), uint64(tc.bufLen), uint64(tc.cookie), uint64(tc.resultBufused))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 		})
@@ -1716,12 +1716,12 @@ func Test_writeDirents(t *testing.T) {
 
 // Test_fdRenumber only tests it is stubbed for GrainLang per #271
 func Test_fdRenumber(t *testing.T) {
-	log := requireErrnoNosys(t, functionFdRenumber, 0, 0)
+	log := requireErrnoNosys(t, fdRenumberName, 0, 0)
 	require.Equal(t, `
 --> proxy.fd_renumber(fd=0,to=0)
 	--> wasi_snapshot_preview1.fd_renumber(fd=0,to=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
@@ -1753,7 +1753,7 @@ func Test_fdSeek(t *testing.T) {
 --> proxy.fd_seek(fd=4,offset=4,whence=0,result.newoffset=1)
 	==> wasi_snapshot_preview1.fd_seek(fd=4,offset=4,whence=0,result.newoffset=1)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `,
 		},
 		{
@@ -1770,7 +1770,7 @@ func Test_fdSeek(t *testing.T) {
 --> proxy.fd_seek(fd=4,offset=1,whence=1,result.newoffset=1)
 	==> wasi_snapshot_preview1.fd_seek(fd=4,offset=1,whence=1,result.newoffset=1)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `,
 		},
 		{
@@ -1787,7 +1787,7 @@ func Test_fdSeek(t *testing.T) {
 --> proxy.fd_seek(fd=4,offset=18446744073709551615,whence=2,result.newoffset=1)
 	==> wasi_snapshot_preview1.fd_seek(fd=4,offset=18446744073709551615,whence=2,result.newoffset=1)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `,
 		},
 	}
@@ -1810,7 +1810,7 @@ func Test_fdSeek(t *testing.T) {
 			require.NoError(t, err)
 			require.Equal(t, int64(1), offset)
 
-			requireErrno(t, ErrnoSuccess, mod, functionFdSeek, uint64(fd), uint64(tc.offset), uint64(tc.whence), uint64(resultNewoffset))
+			requireErrno(t, ErrnoSuccess, mod, fdSeekName, uint64(fd), uint64(tc.offset), uint64(tc.whence), uint64(resultNewoffset))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
 			actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(tc.expectedMemory)))
@@ -1846,7 +1846,7 @@ func Test_fdSeek_Errors(t *testing.T) {
 --> proxy.fd_seek(fd=42,offset=0,whence=0,result.newoffset=0)
 	==> wasi_snapshot_preview1.fd_seek(fd=42,offset=0,whence=0,result.newoffset=0)
 	<== EBADF
-<-- (8)
+<-- 8
 `,
 		},
 		{
@@ -1858,7 +1858,7 @@ func Test_fdSeek_Errors(t *testing.T) {
 --> proxy.fd_seek(fd=4,offset=0,whence=3,result.newoffset=0)
 	==> wasi_snapshot_preview1.fd_seek(fd=4,offset=0,whence=3,result.newoffset=0)
 	<== EINVAL
-<-- (28)
+<-- 28
 `,
 		},
 		{
@@ -1870,7 +1870,7 @@ func Test_fdSeek_Errors(t *testing.T) {
 --> proxy.fd_seek(fd=4,offset=0,whence=0,result.newoffset=65536)
 	==> wasi_snapshot_preview1.fd_seek(fd=4,offset=0,whence=0,result.newoffset=65536)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 	}
@@ -1880,7 +1880,7 @@ func Test_fdSeek_Errors(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			defer log.Reset()
 
-			requireErrno(t, tc.expectedErrno, mod, functionFdSeek, uint64(tc.fd), tc.offset, uint64(tc.whence), uint64(tc.resultNewoffset))
+			requireErrno(t, tc.expectedErrno, mod, fdSeekName, uint64(tc.fd), tc.offset, uint64(tc.whence), uint64(tc.resultNewoffset))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 		})
 	}
@@ -1888,23 +1888,23 @@ func Test_fdSeek_Errors(t *testing.T) {
 
 // Test_fdSync only tests it is stubbed for GrainLang per #271
 func Test_fdSync(t *testing.T) {
-	log := requireErrnoNosys(t, functionFdSync, 0)
+	log := requireErrnoNosys(t, fdSyncName, 0)
 	require.Equal(t, `
 --> proxy.fd_sync(fd=0)
 	--> wasi_snapshot_preview1.fd_sync(fd=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
 // Test_fdTell only tests it is stubbed for GrainLang per #271
 func Test_fdTell(t *testing.T) {
-	log := requireErrnoNosys(t, functionFdTell, 0, 0)
+	log := requireErrnoNosys(t, fdTellName, 0, 0)
 	require.Equal(t, `
 --> proxy.fd_tell(fd=0,result.offset=0)
 	--> wasi_snapshot_preview1.fd_tell(fd=0,result.offset=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
@@ -1939,12 +1939,12 @@ func Test_fdWrite(t *testing.T) {
 	ok := mod.Memory().Write(testCtx, 0, initialMemory)
 	require.True(t, ok)
 
-	requireErrno(t, ErrnoSuccess, mod, functionFdWrite, uint64(fd), uint64(iovs), uint64(iovsCount), uint64(resultSize))
+	requireErrno(t, ErrnoSuccess, mod, fdWriteName, uint64(fd), uint64(iovs), uint64(iovsCount), uint64(resultSize))
 	require.Equal(t, `
 --> proxy.fd_write(fd=4,iovs=1,iovs_len=2,result.size=26)
 	==> wasi_snapshot_preview1.fd_write(fd=4,iovs=1,iovs_len=2,result.size=26)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `, "\n"+log.String())
 
 	actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(expectedMemory)))
@@ -1992,12 +1992,12 @@ func Test_fdWrite_discard(t *testing.T) {
 	require.True(t, ok)
 
 	fd := 1 // stdout
-	requireErrno(t, ErrnoSuccess, mod, functionFdWrite, uint64(fd), uint64(iovs), uint64(iovsCount), uint64(resultSize))
+	requireErrno(t, ErrnoSuccess, mod, fdWriteName, uint64(fd), uint64(iovs), uint64(iovsCount), uint64(resultSize))
 	require.Equal(t, `
 --> proxy.fd_write(fd=1,iovs=1,iovs_len=2,result.size=26)
 	==> wasi_snapshot_preview1.fd_write(fd=1,iovs=1,iovs_len=2,result.size=26)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `, "\n"+log.String())
 
 	actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(expectedMemory)))
@@ -2034,7 +2034,7 @@ func Test_fdWrite_Errors(t *testing.T) {
 --> proxy.fd_write(fd=42,iovs=0,iovs_len=1,result.size=0)
 	==> wasi_snapshot_preview1.fd_write(fd=42,iovs=0,iovs_len=1,result.size=0)
 	<== EBADF
-<-- (8)
+<-- 8
 `,
 		},
 		{
@@ -2046,7 +2046,7 @@ func Test_fdWrite_Errors(t *testing.T) {
 --> proxy.fd_write(fd=4,iovs=0,iovs_len=1,result.size=0)
 	==> wasi_snapshot_preview1.fd_write(fd=4,iovs=0,iovs_len=1,result.size=0)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -2058,7 +2058,7 @@ func Test_fdWrite_Errors(t *testing.T) {
 --> proxy.fd_write(fd=4,iovs=0,iovs_len=1,result.size=0)
 	==> wasi_snapshot_preview1.fd_write(fd=4,iovs=0,iovs_len=1,result.size=0)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -2070,7 +2070,7 @@ func Test_fdWrite_Errors(t *testing.T) {
 --> proxy.fd_write(fd=4,iovs=0,iovs_len=1,result.size=0)
 	==> wasi_snapshot_preview1.fd_write(fd=4,iovs=0,iovs_len=1,result.size=0)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -2082,7 +2082,7 @@ func Test_fdWrite_Errors(t *testing.T) {
 --> proxy.fd_write(fd=4,iovs=0,iovs_len=1,result.size=0)
 	==> wasi_snapshot_preview1.fd_write(fd=4,iovs=0,iovs_len=1,result.size=0)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -2095,7 +2095,7 @@ func Test_fdWrite_Errors(t *testing.T) {
 --> proxy.fd_write(fd=4,iovs=0,iovs_len=1,result.size=10)
 	==> wasi_snapshot_preview1.fd_write(fd=4,iovs=0,iovs_len=1,result.size=10)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 	}
@@ -2107,7 +2107,7 @@ func Test_fdWrite_Errors(t *testing.T) {
 
 			mod.Memory().(*wasm.MemoryInstance).Buffer = tc.memory
 
-			requireErrno(t, tc.expectedErrno, mod, functionFdWrite, uint64(tc.fd), uint64(iovs), uint64(iovsCount),
+			requireErrno(t, tc.expectedErrno, mod, fdWriteName, uint64(tc.fd), uint64(iovs), uint64(iovsCount),
 				uint64(tc.resultSize))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 		})
@@ -2116,12 +2116,12 @@ func Test_fdWrite_Errors(t *testing.T) {
 
 // Test_pathCreateDirectory only tests it is stubbed for GrainLang per #271
 func Test_pathCreateDirectory(t *testing.T) {
-	log := requireErrnoNosys(t, functionPathCreateDirectory, 0, 0, 0)
+	log := requireErrnoNosys(t, pathCreateDirectoryName, 0, 0, 0)
 	require.Equal(t, `
 --> proxy.path_create_directory(fd=0,path=0,path_len=0)
 	--> wasi_snapshot_preview1.path_create_directory(fd=0,path=0,path_len=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
@@ -2180,7 +2180,7 @@ func Test_pathFilestatGet(t *testing.T) {
 --> proxy.path_filestat_get(fd=3,flags=0,path=1,path_len=1,result.buf=2)
 	==> wasi_snapshot_preview1.path_filestat_get(fd=3,flags=0,path=1,path_len=1,result.buf=2)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `,
 		},
 		{
@@ -2204,7 +2204,7 @@ func Test_pathFilestatGet(t *testing.T) {
 --> proxy.path_filestat_get(fd=5,flags=0,path=1,path_len=1,result.buf=2)
 	==> wasi_snapshot_preview1.path_filestat_get(fd=5,flags=0,path=1,path_len=1,result.buf=2)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `,
 		},
 		{
@@ -2228,7 +2228,7 @@ func Test_pathFilestatGet(t *testing.T) {
 --> proxy.path_filestat_get(fd=3,flags=0,path=1,path_len=1,result.buf=2)
 	==> wasi_snapshot_preview1.path_filestat_get(fd=3,flags=0,path=1,path_len=1,result.buf=2)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `,
 		},
 		{
@@ -2239,7 +2239,7 @@ func Test_pathFilestatGet(t *testing.T) {
 --> proxy.path_filestat_get(fd=4294967295,flags=0,path=1,path_len=0,result.buf=0)
 	==> wasi_snapshot_preview1.path_filestat_get(fd=4294967295,flags=0,path=1,path_len=0,result.buf=0)
 	<== EBADF
-<-- (8)
+<-- 8
 `,
 		},
 		{
@@ -2253,7 +2253,7 @@ func Test_pathFilestatGet(t *testing.T) {
 --> proxy.path_filestat_get(fd=4,flags=0,path=1,path_len=1,result.buf=2)
 	==> wasi_snapshot_preview1.path_filestat_get(fd=4,flags=0,path=1,path_len=1,result.buf=2)
 	<== ENOTDIR
-<-- (54)
+<-- 54
 `,
 		},
 		{
@@ -2267,7 +2267,7 @@ func Test_pathFilestatGet(t *testing.T) {
 --> proxy.path_filestat_get(fd=3,flags=0,path=1,path_len=1,result.buf=2)
 	==> wasi_snapshot_preview1.path_filestat_get(fd=3,flags=0,path=1,path_len=1,result.buf=2)
 	<== ENOENT
-<-- (44)
+<-- 44
 `,
 		},
 		{
@@ -2281,7 +2281,7 @@ func Test_pathFilestatGet(t *testing.T) {
 --> proxy.path_filestat_get(fd=5,flags=0,path=1,path_len=1,result.buf=2)
 	==> wasi_snapshot_preview1.path_filestat_get(fd=5,flags=0,path=1,path_len=1,result.buf=2)
 	<== ENOENT
-<-- (44)
+<-- 44
 `,
 		},
 		{
@@ -2295,7 +2295,7 @@ func Test_pathFilestatGet(t *testing.T) {
 --> proxy.path_filestat_get(fd=5,flags=0,path=1,path_len=6,result.buf=7)
 	==> wasi_snapshot_preview1.path_filestat_get(fd=5,flags=0,path=1,path_len=6,result.buf=7)
 	<== ENOENT
-<-- (44)
+<-- 44
 `,
 		},
 		{
@@ -2308,7 +2308,7 @@ func Test_pathFilestatGet(t *testing.T) {
 --> proxy.path_filestat_get(fd=3,flags=0,path=1,path_len=65536,result.buf=0)
 	==> wasi_snapshot_preview1.path_filestat_get(fd=3,flags=0,path=1,path_len=65536,result.buf=0)
 	<== ENAMETOOLONG
-<-- (37)
+<-- 37
 `,
 		},
 		{
@@ -2322,7 +2322,7 @@ func Test_pathFilestatGet(t *testing.T) {
 --> proxy.path_filestat_get(fd=3,flags=0,path=1,path_len=1,result.buf=65473)
 	==> wasi_snapshot_preview1.path_filestat_get(fd=3,flags=0,path=1,path_len=1,result.buf=65473)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 	}
@@ -2336,7 +2336,7 @@ func Test_pathFilestatGet(t *testing.T) {
 			maskMemory(t, testCtx, mod, len(tc.expectedMemory))
 			mod.Memory().Write(testCtx, 0, tc.memory)
 
-			requireErrno(t, tc.expectedErrno, mod, functionPathFilestatGet, uint64(tc.fd), uint64(0), uint64(1), uint64(tc.pathLen), uint64(tc.resultFilestat))
+			requireErrno(t, tc.expectedErrno, mod, pathFilestatGetName, uint64(tc.fd), uint64(0), uint64(1), uint64(tc.pathLen), uint64(tc.resultFilestat))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
 			actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(tc.expectedMemory)))
@@ -2348,23 +2348,23 @@ func Test_pathFilestatGet(t *testing.T) {
 
 // Test_pathFilestatSetTimes only tests it is stubbed for GrainLang per #271
 func Test_pathFilestatSetTimes(t *testing.T) {
-	log := requireErrnoNosys(t, functionPathFilestatSetTimes, 0, 0, 0, 0, 0, 0, 0)
+	log := requireErrnoNosys(t, pathFilestatSetTimesName, 0, 0, 0, 0, 0, 0, 0)
 	require.Equal(t, `
 --> proxy.path_filestat_set_times(fd=0,flags=0,path=0,path_len=0,atim=0,mtim=0,fst_flags=0)
 	--> wasi_snapshot_preview1.path_filestat_set_times(fd=0,flags=0,path=0,path_len=0,atim=0,mtim=0,fst_flags=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
 // Test_pathLink only tests it is stubbed for GrainLang per #271
 func Test_pathLink(t *testing.T) {
-	log := requireErrnoNosys(t, functionPathLink, 0, 0, 0, 0, 0, 0, 0)
+	log := requireErrnoNosys(t, pathLinkName, 0, 0, 0, 0, 0, 0, 0)
 	require.Equal(t, `
 --> proxy.path_link(old_fd=0,old_flags=0,old_path=0,old_path_len=0,new_fd=0,new_path=0,new_path_len=0)
 	--> wasi_snapshot_preview1.path_link(old_fd=0,old_flags=0,old_path=0,old_path_len=0,new_fd=0,new_path=0,new_path_len=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
@@ -2399,13 +2399,13 @@ func Test_pathOpen(t *testing.T) {
 	ok := mod.Memory().Write(testCtx, 0, initialMemory)
 	require.True(t, ok)
 
-	requireErrno(t, ErrnoSuccess, mod, functionPathOpen, uint64(rootFD), uint64(dirflags), uint64(path),
+	requireErrno(t, ErrnoSuccess, mod, pathOpenName, uint64(rootFD), uint64(dirflags), uint64(path),
 		uint64(pathLen), uint64(oflags), fsRightsBase, fsRightsInheriting, uint64(fdflags), uint64(resultOpenedFd))
 	require.Equal(t, `
 --> proxy.path_open(fd=3,dirflags=0,path=1,path_len=6,oflags=0,fs_rights_base=1,fs_rights_inheriting=2,fdflags=0,result.opened_fd=8)
 	==> wasi_snapshot_preview1.path_open(fd=3,dirflags=0,path=1,path_len=6,oflags=0,fs_rights_base=1,fs_rights_inheriting=2,fdflags=0,result.opened_fd=8)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `, "\n"+log.String())
 
 	actual, ok := mod.Memory().Read(testCtx, 0, uint32(len(expectedMemory)))
@@ -2443,7 +2443,7 @@ func Test_pathOpen_Errors(t *testing.T) {
 --> proxy.path_open(fd=42,dirflags=0,path=0,path_len=0,oflags=0,fs_rights_base=0,fs_rights_inheriting=0,fdflags=0,result.opened_fd=0)
 	==> wasi_snapshot_preview1.path_open(fd=42,dirflags=0,path=0,path_len=0,oflags=0,fs_rights_base=0,fs_rights_inheriting=0,fdflags=0,result.opened_fd=0)
 	<== EBADF
-<-- (8)
+<-- 8
 `,
 		},
 		{
@@ -2456,7 +2456,7 @@ func Test_pathOpen_Errors(t *testing.T) {
 --> proxy.path_open(fd=3,dirflags=0,path=65536,path_len=6,oflags=0,fs_rights_base=0,fs_rights_inheriting=0,fdflags=0,result.opened_fd=0)
 	==> wasi_snapshot_preview1.path_open(fd=3,dirflags=0,path=65536,path_len=6,oflags=0,fs_rights_base=0,fs_rights_inheriting=0,fdflags=0,result.opened_fd=0)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -2470,7 +2470,7 @@ func Test_pathOpen_Errors(t *testing.T) {
 --> proxy.path_open(fd=3,dirflags=0,path=0,path_len=6,oflags=0,fs_rights_base=0,fs_rights_inheriting=0,fdflags=0,result.opened_fd=0)
 	==> wasi_snapshot_preview1.path_open(fd=3,dirflags=0,path=0,path_len=6,oflags=0,fs_rights_base=0,fs_rights_inheriting=0,fdflags=0,result.opened_fd=0)
 	<== ENOENT
-<-- (44)
+<-- 44
 `,
 		},
 		{
@@ -2483,7 +2483,7 @@ func Test_pathOpen_Errors(t *testing.T) {
 --> proxy.path_open(fd=3,dirflags=0,path=0,path_len=65537,oflags=0,fs_rights_base=0,fs_rights_inheriting=0,fdflags=0,result.opened_fd=0)
 	==> wasi_snapshot_preview1.path_open(fd=3,dirflags=0,path=0,path_len=65537,oflags=0,fs_rights_base=0,fs_rights_inheriting=0,fdflags=0,result.opened_fd=0)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -2497,7 +2497,7 @@ func Test_pathOpen_Errors(t *testing.T) {
 --> proxy.path_open(fd=3,dirflags=0,path=0,path_len=5,oflags=0,fs_rights_base=0,fs_rights_inheriting=0,fdflags=0,result.opened_fd=0)
 	==> wasi_snapshot_preview1.path_open(fd=3,dirflags=0,path=0,path_len=5,oflags=0,fs_rights_base=0,fs_rights_inheriting=0,fdflags=0,result.opened_fd=0)
 	<== ENOENT
-<-- (44)
+<-- 44
 `,
 		},
 		{
@@ -2512,7 +2512,7 @@ func Test_pathOpen_Errors(t *testing.T) {
 --> proxy.path_open(fd=3,dirflags=0,path=0,path_len=6,oflags=0,fs_rights_base=0,fs_rights_inheriting=0,fdflags=0,result.opened_fd=65536)
 	==> wasi_snapshot_preview1.path_open(fd=3,dirflags=0,path=0,path_len=6,oflags=0,fs_rights_base=0,fs_rights_inheriting=0,fdflags=0,result.opened_fd=65536)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 	}
@@ -2524,7 +2524,7 @@ func Test_pathOpen_Errors(t *testing.T) {
 
 			mod.Memory().Write(testCtx, validPath, []byte(tc.pathName))
 
-			requireErrno(t, tc.expectedErrno, mod, functionPathOpen, uint64(tc.fd), uint64(0), uint64(tc.path),
+			requireErrno(t, tc.expectedErrno, mod, pathOpenName, uint64(tc.fd), uint64(0), uint64(tc.path),
 				uint64(tc.pathLen), uint64(tc.oflags), 0, 0, 0, uint64(tc.resultOpenedFd))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 		})
@@ -2533,56 +2533,56 @@ func Test_pathOpen_Errors(t *testing.T) {
 
 // Test_pathReadlink only tests it is stubbed for GrainLang per #271
 func Test_pathReadlink(t *testing.T) {
-	log := requireErrnoNosys(t, functionPathReadlink, 0, 0, 0, 0, 0, 0)
+	log := requireErrnoNosys(t, pathReadlinkName, 0, 0, 0, 0, 0, 0)
 	require.Equal(t, `
 --> proxy.path_readlink(fd=0,path=0,path_len=0,buf=0,buf_len=0,result.bufused=0)
 	--> wasi_snapshot_preview1.path_readlink(fd=0,path=0,path_len=0,buf=0,buf_len=0,result.bufused=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
 // Test_pathRemoveDirectory only tests it is stubbed for GrainLang per #271
 func Test_pathRemoveDirectory(t *testing.T) {
-	log := requireErrnoNosys(t, functionPathRemoveDirectory, 0, 0, 0)
+	log := requireErrnoNosys(t, pathRemoveDirectoryName, 0, 0, 0)
 	require.Equal(t, `
 --> proxy.path_remove_directory(fd=0,path=0,path_len=0)
 	--> wasi_snapshot_preview1.path_remove_directory(fd=0,path=0,path_len=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
 // Test_pathRename only tests it is stubbed for GrainLang per #271
 func Test_pathRename(t *testing.T) {
-	log := requireErrnoNosys(t, functionPathRename, 0, 0, 0, 0, 0, 0)
+	log := requireErrnoNosys(t, pathRenameName, 0, 0, 0, 0, 0, 0)
 	require.Equal(t, `
 --> proxy.path_rename(fd=0,old_path=0,old_path_len=0,new_fd=0,new_path=0,new_path_len=0)
 	--> wasi_snapshot_preview1.path_rename(fd=0,old_path=0,old_path_len=0,new_fd=0,new_path=0,new_path_len=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
 // Test_pathSymlink only tests it is stubbed for GrainLang per #271
 func Test_pathSymlink(t *testing.T) {
-	log := requireErrnoNosys(t, functionPathSymlink, 0, 0, 0, 0, 0)
+	log := requireErrnoNosys(t, pathSymlinkName, 0, 0, 0, 0, 0)
 	require.Equal(t, `
 --> proxy.path_symlink(old_path=0,old_path_len=0,fd=0,new_path=0,new_path_len=0)
 	--> wasi_snapshot_preview1.path_symlink(old_path=0,old_path_len=0,fd=0,new_path=0,new_path_len=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
 // Test_pathUnlinkFile only tests it is stubbed for GrainLang per #271
 func Test_pathUnlinkFile(t *testing.T) {
-	log := requireErrnoNosys(t, functionPathUnlinkFile, 0, 0, 0)
+	log := requireErrnoNosys(t, pathUnlinkFileName, 0, 0, 0)
 	require.Equal(t, `
 --> proxy.path_unlink_file(fd=0,path=0,path_len=0)
 	--> wasi_snapshot_preview1.path_unlink_file(fd=0,path=0,path_len=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
diff --git a/imports/wasi_snapshot_preview1/poll_test.go b/imports/wasi_snapshot_preview1/poll_test.go
index 1a30f45f..b85f0503 100644
--- a/imports/wasi_snapshot_preview1/poll_test.go
+++ b/imports/wasi_snapshot_preview1/poll_test.go
@@ -38,13 +38,13 @@ func Test_pollOneoff(t *testing.T) {
 	maskMemory(t, testCtx, mod, 1024)
 	mod.Memory().Write(testCtx, in, mem)
 
-	requireErrno(t, ErrnoSuccess, mod, functionPollOneoff, uint64(in), uint64(out), uint64(nsubscriptions),
+	requireErrno(t, ErrnoSuccess, mod, pollOneoffName, uint64(in), uint64(out), uint64(nsubscriptions),
 		uint64(resultNevents))
 	require.Equal(t, `
 --> proxy.poll_oneoff(in=0,out=128,nsubscriptions=1,result.nevents=512)
 	==> wasi_snapshot_preview1.poll_oneoff(in=0,out=128,nsubscriptions=1,result.nevents=512)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `, "\n"+log.String())
 
 	outMem, ok := mod.Memory().Read(testCtx, out, uint32(len(expectedMem)))
@@ -79,7 +79,7 @@ func Test_pollOneoff_Errors(t *testing.T) {
 --> proxy.poll_oneoff(in=65536,out=128,nsubscriptions=1,result.nevents=512)
 	==> wasi_snapshot_preview1.poll_oneoff(in=65536,out=128,nsubscriptions=1,result.nevents=512)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -92,7 +92,7 @@ func Test_pollOneoff_Errors(t *testing.T) {
 --> proxy.poll_oneoff(in=0,out=65536,nsubscriptions=1,result.nevents=512)
 	==> wasi_snapshot_preview1.poll_oneoff(in=0,out=65536,nsubscriptions=1,result.nevents=512)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -104,7 +104,7 @@ func Test_pollOneoff_Errors(t *testing.T) {
 --> proxy.poll_oneoff(in=0,out=0,nsubscriptions=1,result.nevents=65536)
 	==> wasi_snapshot_preview1.poll_oneoff(in=0,out=0,nsubscriptions=1,result.nevents=65536)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -116,7 +116,7 @@ func Test_pollOneoff_Errors(t *testing.T) {
 --> proxy.poll_oneoff(in=0,out=128,nsubscriptions=0,result.nevents=512)
 	==> wasi_snapshot_preview1.poll_oneoff(in=0,out=128,nsubscriptions=0,result.nevents=512)
 	<== EINVAL
-<-- (28)
+<-- 28
 `,
 		},
 		{
@@ -141,7 +141,7 @@ func Test_pollOneoff_Errors(t *testing.T) {
 --> proxy.poll_oneoff(in=0,out=128,nsubscriptions=1,result.nevents=512)
 	==> wasi_snapshot_preview1.poll_oneoff(in=0,out=128,nsubscriptions=1,result.nevents=512)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `,
 		},
 	}
@@ -157,7 +157,7 @@ func Test_pollOneoff_Errors(t *testing.T) {
 				mod.Memory().Write(testCtx, tc.in, tc.mem)
 			}
 
-			requireErrno(t, tc.expectedErrno, mod, functionPollOneoff, uint64(tc.in), uint64(tc.out),
+			requireErrno(t, tc.expectedErrno, mod, pollOneoffName, uint64(tc.in), uint64(tc.out),
 				uint64(tc.nsubscriptions), uint64(tc.resultNevents))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 
diff --git a/imports/wasi_snapshot_preview1/proc_test.go b/imports/wasi_snapshot_preview1/proc_test.go
index a342216f..3e931c38 100644
--- a/imports/wasi_snapshot_preview1/proc_test.go
+++ b/imports/wasi_snapshot_preview1/proc_test.go
@@ -42,7 +42,7 @@ func Test_procExit(t *testing.T) {
 			defer log.Reset()
 
 			// Since procExit panics, any opcodes afterwards cannot be reached.
-			_, err := mod.ExportedFunction(functionProcExit).Call(testCtx, uint64(tc.exitCode))
+			_, err := mod.ExportedFunction(procExitName).Call(testCtx, uint64(tc.exitCode))
 			require.Error(t, err)
 			sysErr, ok := err.(*sys.ExitError)
 			require.True(t, ok, err)
@@ -54,11 +54,11 @@ func Test_procExit(t *testing.T) {
 
 // Test_procRaise only tests it is stubbed for GrainLang per #271
 func Test_procRaise(t *testing.T) {
-	log := requireErrnoNosys(t, functionProcRaise, 0)
+	log := requireErrnoNosys(t, procRaiseName, 0)
 	require.Equal(t, `
 --> proxy.proc_raise(sig=0)
 	--> wasi_snapshot_preview1.proc_raise(sig=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
diff --git a/imports/wasi_snapshot_preview1/random_test.go b/imports/wasi_snapshot_preview1/random_test.go
index 53b42147..63cb510d 100644
--- a/imports/wasi_snapshot_preview1/random_test.go
+++ b/imports/wasi_snapshot_preview1/random_test.go
@@ -27,12 +27,12 @@ func Test_randomGet(t *testing.T) {
 	maskMemory(t, testCtx, mod, len(expectedMemory))
 
 	// Invoke randomGet and check the memory side effects!
-	requireErrno(t, ErrnoSuccess, mod, functionRandomGet, uint64(offset), uint64(length))
+	requireErrno(t, ErrnoSuccess, mod, randomGetName, uint64(offset), uint64(length))
 	require.Equal(t, `
 --> proxy.random_get(buf=1,buf_len=5)
 	==> wasi_snapshot_preview1.random_get(buf=1,buf_len=5)
 	<== ESUCCESS
-<-- (0)
+<-- 0
 `, "\n"+log.String())
 
 	actual, ok := mod.Memory().Read(testCtx, 0, offset+length+1)
@@ -59,7 +59,7 @@ func Test_randomGet_Errors(t *testing.T) {
 --> proxy.random_get(buf=65536,buf_len=1)
 	==> wasi_snapshot_preview1.random_get(buf=65536,buf_len=1)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 		{
@@ -70,7 +70,7 @@ func Test_randomGet_Errors(t *testing.T) {
 --> proxy.random_get(buf=0,buf_len=65537)
 	==> wasi_snapshot_preview1.random_get(buf=0,buf_len=65537)
 	<== EFAULT
-<-- (21)
+<-- 21
 `,
 		},
 	}
@@ -81,7 +81,7 @@ func Test_randomGet_Errors(t *testing.T) {
 		t.Run(tc.name, func(t *testing.T) {
 			defer log.Reset()
 
-			requireErrno(t, ErrnoFault, mod, functionRandomGet, uint64(tc.offset), uint64(tc.length))
+			requireErrno(t, ErrnoFault, mod, randomGetName, uint64(tc.offset), uint64(tc.length))
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 		})
 	}
@@ -100,7 +100,7 @@ func Test_randomGet_SourceError(t *testing.T) {
 --> proxy.random_get(buf=1,buf_len=5)
 	==> wasi_snapshot_preview1.random_get(buf=1,buf_len=5)
 	<== EIO
-<-- (29)
+<-- 29
 `,
 		},
 		{
@@ -110,7 +110,7 @@ func Test_randomGet_SourceError(t *testing.T) {
 --> proxy.random_get(buf=1,buf_len=5)
 	==> wasi_snapshot_preview1.random_get(buf=1,buf_len=5)
 	<== EIO
-<-- (29)
+<-- 29
 `,
 		},
 	}
@@ -122,7 +122,7 @@ func Test_randomGet_SourceError(t *testing.T) {
 				WithRandSource(tc.randSource))
 			defer r.Close(testCtx)
 
-			requireErrno(t, ErrnoIo, mod, functionRandomGet, uint64(1), uint64(5)) // arbitrary offset and length
+			requireErrno(t, ErrnoIo, mod, randomGetName, uint64(1), uint64(5)) // arbitrary offset and length
 			require.Equal(t, tc.expectedLog, "\n"+log.String())
 		})
 	}
diff --git a/imports/wasi_snapshot_preview1/sched_test.go b/imports/wasi_snapshot_preview1/sched_test.go
index 0ef45e63..ade41edb 100644
--- a/imports/wasi_snapshot_preview1/sched_test.go
+++ b/imports/wasi_snapshot_preview1/sched_test.go
@@ -8,11 +8,11 @@ import (
 
 // Test_schedYield only tests it is stubbed for GrainLang per #271
 func Test_schedYield(t *testing.T) {
-	log := requireErrnoNosys(t, functionSchedYield)
+	log := requireErrnoNosys(t, schedYieldName)
 	require.Equal(t, `
 --> proxy.sched_yield()
 	--> wasi_snapshot_preview1.sched_yield()
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
diff --git a/imports/wasi_snapshot_preview1/sock_test.go b/imports/wasi_snapshot_preview1/sock_test.go
index d21e8490..89dacc8a 100644
--- a/imports/wasi_snapshot_preview1/sock_test.go
+++ b/imports/wasi_snapshot_preview1/sock_test.go
@@ -8,44 +8,44 @@ import (
 
 // Test_sockAccept only tests it is stubbed for GrainLang per #271
 func Test_sockAccept(t *testing.T) {
-	log := requireErrnoNosys(t, functionSockAccept, 0, 0, 0)
+	log := requireErrnoNosys(t, sockAcceptName, 0, 0, 0)
 	require.Equal(t, `
 --> proxy.sock_accept(fd=0,flags=0,result.fd=0)
 	--> wasi_snapshot_preview1.sock_accept(fd=0,flags=0,result.fd=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
 // Test_sockRecv only tests it is stubbed for GrainLang per #271
 func Test_sockRecv(t *testing.T) {
-	log := requireErrnoNosys(t, functionSockRecv, 0, 0, 0, 0, 0, 0)
+	log := requireErrnoNosys(t, sockRecvName, 0, 0, 0, 0, 0, 0)
 	require.Equal(t, `
 --> proxy.sock_recv(fd=0,ri_data=0,ri_data_count=0,ri_flags=0,result.ro_datalen=0,result.ro_flags=0)
 	--> wasi_snapshot_preview1.sock_recv(fd=0,ri_data=0,ri_data_count=0,ri_flags=0,result.ro_datalen=0,result.ro_flags=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
 // Test_sockSend only tests it is stubbed for GrainLang per #271
 func Test_sockSend(t *testing.T) {
-	log := requireErrnoNosys(t, functionSockSend, 0, 0, 0, 0, 0)
+	log := requireErrnoNosys(t, sockSendName, 0, 0, 0, 0, 0)
 	require.Equal(t, `
 --> proxy.sock_send(fd=0,si_data=0,si_data_count=0,si_flags=0,result.so_datalen=0)
 	--> wasi_snapshot_preview1.sock_send(fd=0,si_data=0,si_data_count=0,si_flags=0,result.so_datalen=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
 
 // Test_sockShutdown only tests it is stubbed for GrainLang per #271
 func Test_sockShutdown(t *testing.T) {
-	log := requireErrnoNosys(t, functionSockShutdown, 0, 0)
+	log := requireErrnoNosys(t, sockShutdownName, 0, 0)
 	require.Equal(t, `
 --> proxy.sock_shutdown(fd=0,how=0)
 	--> wasi_snapshot_preview1.sock_shutdown(fd=0,how=0)
 	<-- ENOSYS
-<-- (52)
+<-- 52
 `, log)
 }
diff --git a/imports/wasi_snapshot_preview1/wasi_bench_test.go b/imports/wasi_snapshot_preview1/wasi_bench_test.go
index cdb2adab..40ba524b 100644
--- a/imports/wasi_snapshot_preview1/wasi_bench_test.go
+++ b/imports/wasi_snapshot_preview1/wasi_bench_test.go
@@ -25,10 +25,10 @@ func Benchmark_ArgsEnviron(b *testing.B) {
 	}
 
 	for _, n := range []string{
-		functionArgsGet,
-		functionArgsSizesGet,
-		functionEnvironGet,
-		functionEnvironSizesGet,
+		argsGetName,
+		argsSizesGetName,
+		environGetName,
+		environSizesGetName,
 	} {
 		n := n
 		fn := mod.ExportedFunction(n)
diff --git a/internal/engine/compiler/engine_test.go b/internal/engine/compiler/engine_test.go
index 3e11d1f5..d5985d87 100644
--- a/internal/engine/compiler/engine_test.go
+++ b/internal/engine/compiler/engine_test.go
@@ -94,45 +94,45 @@ func TestCompiler_ModuleEngine_Call_Errors(t *testing.T) {
 	//	<== DivByZero
 	require.Equal(t, `
 --> imported.div_by.wasm(1)
-<-- (1)
+<-- 1
 --> imported.div_by.wasm(1)
-<-- (1)
+<-- 1
 --> imported.div_by.wasm(0)
 --> imported.div_by.wasm(1)
-<-- (1)
+<-- 1
 --> imported.call->div_by.go(4294967295)
 	==> host.div_by.go(4294967295)
 --> imported.call->div_by.go(1)
 	==> host.div_by.go(1)
-	<== (1)
-<-- (1)
+	<== 1
+<-- 1
 --> importing.call_import->call->div_by.go(0)
 	--> imported.call->div_by.go(0)
 		==> host.div_by.go(0)
 --> importing.call_import->call->div_by.go(1)
 	--> imported.call->div_by.go(1)
 		==> host.div_by.go(1)
-		<== (1)
-	<-- (1)
-<-- (1)
+		<== 1
+	<-- 1
+<-- 1
 --> importing.call_import->call->div_by.go(4294967295)
 	--> imported.call->div_by.go(4294967295)
 		==> host.div_by.go(4294967295)
 --> importing.call_import->call->div_by.go(1)
 	--> imported.call->div_by.go(1)
 		==> host.div_by.go(1)
-		<== (1)
-	<-- (1)
-<-- (1)
+		<== 1
+	<-- 1
+<-- 1
 --> importing.call_import->call->div_by.go(0)
 	--> imported.call->div_by.go(0)
 		==> host.div_by.go(0)
 --> importing.call_import->call->div_by.go(1)
 	--> imported.call->div_by.go(1)
 		==> host.div_by.go(1)
-		<== (1)
-	<-- (1)
-<-- (1)
+		<== 1
+	<-- 1
+<-- 1
 `, "\n"+functionLog.String())
 }
 
@@ -254,7 +254,7 @@ func TestCompiler_SliceAllocatedOnHeap(t *testing.T) {
 		// Trigger relocation of goroutine stack because at this point we have the majority of
 		// goroutine stack unused after recursive call.
 		runtime.GC()
-	}}, nil, enabledFeatures)
+	}}, map[string]*wasm.HostFuncNames{hostFnName: {}}, enabledFeatures)
 	require.NoError(t, err)
 
 	err = s.Engine.CompileModule(testCtx, hm, nil)
diff --git a/internal/engine/interpreter/interpreter_test.go b/internal/engine/interpreter/interpreter_test.go
index d9523499..61c09554 100644
--- a/internal/engine/interpreter/interpreter_test.go
+++ b/internal/engine/interpreter/interpreter_test.go
@@ -133,45 +133,45 @@ func TestInterpreter_ModuleEngine_Call_Errors(t *testing.T) {
 	//	<== DivByZero
 	require.Equal(t, `
 --> imported.div_by.wasm(1)
-<-- (1)
+<-- 1
 --> imported.div_by.wasm(1)
-<-- (1)
+<-- 1
 --> imported.div_by.wasm(0)
 --> imported.div_by.wasm(1)
-<-- (1)
+<-- 1
 --> imported.call->div_by.go(4294967295)
 	==> host.div_by.go(4294967295)
 --> imported.call->div_by.go(1)
 	==> host.div_by.go(1)
-	<== (1)
-<-- (1)
+	<== 1
+<-- 1
 --> importing.call_import->call->div_by.go(0)
 	--> imported.call->div_by.go(0)
 		==> host.div_by.go(0)
 --> importing.call_import->call->div_by.go(1)
 	--> imported.call->div_by.go(1)
 		==> host.div_by.go(1)
-		<== (1)
-	<-- (1)
-<-- (1)
+		<== 1
+	<-- 1
+<-- 1
 --> importing.call_import->call->div_by.go(4294967295)
 	--> imported.call->div_by.go(4294967295)
 		==> host.div_by.go(4294967295)
 --> importing.call_import->call->div_by.go(1)
 	--> imported.call->div_by.go(1)
 		==> host.div_by.go(1)
-		<== (1)
-	<-- (1)
-<-- (1)
+		<== 1
+	<-- 1
+<-- 1
 --> importing.call_import->call->div_by.go(0)
 	--> imported.call->div_by.go(0)
 		==> host.div_by.go(0)
 --> importing.call_import->call->div_by.go(1)
 	--> imported.call->div_by.go(1)
 		==> host.div_by.go(1)
-		<== (1)
-	<-- (1)
-<-- (1)
+		<== 1
+	<-- 1
+<-- 1
 `, "\n"+functionLog.String())
 }
 
diff --git a/internal/gojs/spfunc/spfunc_test.go b/internal/gojs/spfunc/spfunc_test.go
index f254fe2c..33a5e81c 100644
--- a/internal/gojs/spfunc/spfunc_test.go
+++ b/internal/gojs/spfunc/spfunc_test.go
@@ -69,6 +69,7 @@ func Test_callFromSP(t *testing.T) {
 				ParamTypes:  []wasm.ValueType{wasm.ValueTypeI32},
 				ParamNames:  []string{"x"},
 				ResultTypes: []wasm.ValueType{wasm.ValueTypeI32},
+				ResultNames: []string{"y"},
 				Code:        &wasm.Code{IsHostFunction: true, Body: []byte{wasm.OpcodeI32Const, 1, wasm.OpcodeEnd}},
 			},
 			expected: &wasm.ProxyFunc{
@@ -97,6 +98,7 @@ func Test_callFromSP(t *testing.T) {
 					ParamTypes:  []wasm.ValueType{wasm.ValueTypeI32},
 					ParamNames:  []string{"x"},
 					ResultTypes: []wasm.ValueType{wasm.ValueTypeI32},
+					ResultNames: []string{"y"},
 					Code:        &wasm.Code{IsHostFunction: true, Body: []byte{wasm.OpcodeI32Const, 1, wasm.OpcodeEnd}},
 				},
 				CallBodyPos: 9,
@@ -110,6 +112,7 @@ func Test_callFromSP(t *testing.T) {
 				ParamTypes:  []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32},
 				ParamNames:  []string{"x", "y"},
 				ResultTypes: []wasm.ValueType{wasm.ValueTypeI64},
+				ResultNames: []string{"z"},
 				Code:        &wasm.Code{IsHostFunction: true, Body: []byte{wasm.OpcodeI64Const, 1, wasm.OpcodeEnd}},
 			},
 			expected: &wasm.ProxyFunc{
@@ -140,6 +143,7 @@ func Test_callFromSP(t *testing.T) {
 					ParamTypes:  []wasm.ValueType{wasm.ValueTypeI32, wasm.ValueTypeI32},
 					ParamNames:  []string{"x", "y"},
 					ResultTypes: []wasm.ValueType{wasm.ValueTypeI64},
+					ResultNames: []string{"z"},
 					Code:        &wasm.Code{IsHostFunction: true, Body: []byte{wasm.OpcodeI64Const, 1, wasm.OpcodeEnd}},
 				},
 				CallBodyPos: 17,
diff --git a/internal/wasm/function_definition_test.go b/internal/wasm/function_definition_test.go
index efb09a19..790bb20a 100644
--- a/internal/wasm/function_definition_test.go
+++ b/internal/wasm/function_definition_test.go
@@ -9,7 +9,7 @@ import (
 
 func TestModule_BuildFunctionDefinitions(t *testing.T) {
 	nopCode := &Code{Body: []byte{OpcodeEnd}}
-	fn := func() {}
+	fn := func(uint32) uint32 { return 1 }
 	tests := []struct {
 		name            string
 		m               *Module
@@ -33,16 +33,26 @@ func TestModule_BuildFunctionDefinitions(t *testing.T) {
 		{
 			name: "host func go",
 			m: &Module{
-				TypeSection:     []*FunctionType{v_v},
+				TypeSection:     []*FunctionType{i32_i32},
 				FunctionSection: []Index{0},
 				CodeSection:     []*Code{MustParseGoReflectFuncCode(fn)},
+				NameSection: &NameSection{
+					ModuleName:    "m",
+					FunctionNames: NameMap{{Index: Index(0), Name: "fn"}},
+					LocalNames:    IndirectNameMap{{Index: Index(0), NameMap: NameMap{{Index: Index(0), Name: "x"}}}},
+					ResultNames:   IndirectNameMap{{Index: Index(0), NameMap: NameMap{{Index: Index(0), Name: "y"}}}},
+				},
 			},
 			expected: []*FunctionDefinition{
 				{
-					index:     0,
-					debugName: ".$0",
-					goFunc:    MustParseGoReflectFuncCode(fn).GoFunc,
-					funcType:  v_v,
+					index:       0,
+					name:        "fn",
+					moduleName:  "m",
+					debugName:   "m.fn",
+					goFunc:      MustParseGoReflectFuncCode(fn).GoFunc,
+					funcType:    i32_i32,
+					paramNames:  []string{"x"},
+					resultNames: []string{"y"},
 				},
 			},
 			expectedExports: map[string]api.FunctionDefinition{},
diff --git a/internal/wasm/host_test.go b/internal/wasm/host_test.go
index b76a8d14..3ecf97e7 100644
--- a/internal/wasm/host_test.go
+++ b/internal/wasm/host_test.go
@@ -21,13 +21,14 @@ func swap(ctx context.Context, x, y uint32) (uint32, uint32) {
 }
 
 func TestNewHostModule(t *testing.T) {
-	functionArgsSizesGet := "args_sizes_get"
-	functionFdWrite := "fd_write"
-	functionSwap := "swap"
+	argsSizesGetName := "args_sizes_get"
+	fdWriteName := "fd_write"
+	swapName := "swap"
 
 	tests := []struct {
 		name, moduleName string
 		nameToGoFunc     map[string]interface{}
+		funcToNames      map[string]*HostFuncNames
 		expected         *Module
 	}{
 		{
@@ -43,8 +44,20 @@ func TestNewHostModule(t *testing.T) {
 			name:       "funcs",
 			moduleName: "wasi_snapshot_preview1",
 			nameToGoFunc: map[string]interface{}{
-				functionArgsSizesGet: argsSizesGet,
-				functionFdWrite:      fdWrite,
+				argsSizesGetName: argsSizesGet,
+				fdWriteName:      fdWrite,
+			},
+			funcToNames: map[string]*HostFuncNames{
+				argsSizesGetName: {
+					Name:        argsSizesGetName,
+					ParamNames:  []string{"result.argc", "result.argv_len"},
+					ResultNames: []string{"errno"},
+				},
+				fdWriteName: {
+					Name:        fdWriteName,
+					ParamNames:  []string{"fd", "iovs", "iovs_len", "result.size"},
+					ResultNames: []string{"errno"},
+				},
 			},
 			expected: &Module{
 				TypeSection: []*FunctionType{
@@ -63,6 +76,22 @@ func TestNewHostModule(t *testing.T) {
 						{Index: 0, Name: "args_sizes_get"},
 						{Index: 1, Name: "fd_write"},
 					},
+					LocalNames: IndirectNameMap{
+						{Index: 0, NameMap: NameMap{
+							{Index: 0, Name: "result.argc"},
+							{Index: 1, Name: "result.argv_len"},
+						}},
+						{Index: 1, NameMap: NameMap{
+							{Index: 0, Name: "fd"},
+							{Index: 1, Name: "iovs"},
+							{Index: 2, Name: "iovs_len"},
+							{Index: 3, Name: "result.size"},
+						}},
+					},
+					ResultNames: IndirectNameMap{
+						{Index: 0, NameMap: NameMap{{Index: 0, Name: "errno"}}},
+						{Index: 1, NameMap: NameMap{{Index: 0, Name: "errno"}}},
+					},
 				},
 			},
 		},
@@ -70,8 +99,9 @@ func TestNewHostModule(t *testing.T) {
 			name:       "multi-value",
 			moduleName: "swapper",
 			nameToGoFunc: map[string]interface{}{
-				functionSwap: swap,
+				swapName: swap,
 			},
+			funcToNames: map[string]*HostFuncNames{swapName: {}},
 			expected: &Module{
 				TypeSection:     []*FunctionType{{Params: []ValueType{i32, i32}, Results: []ValueType{i32, i32}}},
 				FunctionSection: []Index{0},
@@ -86,8 +116,7 @@ func TestNewHostModule(t *testing.T) {
 		tc := tt
 
 		t.Run(tc.name, func(t *testing.T) {
-			m, e := NewHostModule(tc.moduleName, tc.nameToGoFunc, nil,
-				api.CoreFeaturesV1|api.CoreFeatureMultiValue)
+			m, e := NewHostModule(tc.moduleName, tc.nameToGoFunc, tc.funcToNames, api.CoreFeaturesV2)
 			require.NoError(t, e)
 			requireHostModuleEquals(t, tc.expected, m)
 		})
@@ -126,16 +155,19 @@ func TestNewHostModule_Errors(t *testing.T) {
 	tests := []struct {
 		name, moduleName string
 		nameToGoFunc     map[string]interface{}
+		funcToNames      map[string]*HostFuncNames
 		expectedErr      string
 	}{
 		{
 			name:         "not a function",
 			nameToGoFunc: map[string]interface{}{"fn": t},
+			funcToNames:  map[string]*HostFuncNames{"fn": {}},
 			expectedErr:  "func[.fn] kind != func: ptr",
 		},
 		{
 			name:         "function has multiple results",
 			nameToGoFunc: map[string]interface{}{"fn": func() (uint32, uint32) { return 0, 0 }},
+			funcToNames:  map[string]*HostFuncNames{"fn": {}},
 			expectedErr:  "func[.fn] multiple result types invalid as feature \"multi-value\" is disabled",
 		},
 	}
@@ -144,7 +176,7 @@ func TestNewHostModule_Errors(t *testing.T) {
 		tc := tt
 
 		t.Run(tc.name, func(t *testing.T) {
-			_, e := NewHostModule(tc.moduleName, tc.nameToGoFunc, nil, api.CoreFeaturesV1)
+			_, e := NewHostModule(tc.moduleName, tc.nameToGoFunc, tc.funcToNames, api.CoreFeaturesV1)
 			require.EqualError(t, e, tc.expectedErr)
 		})
 	}
diff --git a/internal/wasm/store_test.go b/internal/wasm/store_test.go
index dbbe9955..d414540a 100644
--- a/internal/wasm/store_test.go
+++ b/internal/wasm/store_test.go
@@ -92,7 +92,7 @@ func TestModuleInstance_Memory(t *testing.T) {
 
 func TestStore_Instantiate(t *testing.T) {
 	s, ns := newStore()
-	m, err := NewHostModule("", map[string]interface{}{"fn": func() {}}, nil, api.CoreFeaturesV1)
+	m, err := NewHostModule("", map[string]interface{}{"fn": func() {}}, map[string]*HostFuncNames{"fn": {}}, api.CoreFeaturesV1)
 	require.NoError(t, err)
 
 	sysCtx := sys.DefaultContext(nil)
@@ -170,7 +170,7 @@ func TestStore_CloseWithExitCode(t *testing.T) {
 func TestStore_hammer(t *testing.T) {
 	const importedModuleName = "imported"
 
-	m, err := NewHostModule(importedModuleName, map[string]interface{}{"fn": func() {}}, nil, api.CoreFeaturesV1)
+	m, err := NewHostModule(importedModuleName, map[string]interface{}{"fn": func() {}}, map[string]*HostFuncNames{"fn": {}}, api.CoreFeaturesV1)
 	require.NoError(t, err)
 
 	s, ns := newStore()
@@ -224,7 +224,7 @@ func TestStore_Instantiate_Errors(t *testing.T) {
 	const importedModuleName = "imported"
 	const importingModuleName = "test"
 
-	m, err := NewHostModule(importedModuleName, map[string]interface{}{"fn": func() {}}, nil, api.CoreFeaturesV1)
+	m, err := NewHostModule(importedModuleName, map[string]interface{}{"fn": func() {}}, map[string]*HostFuncNames{"fn": {}}, api.CoreFeaturesV1)
 	require.NoError(t, err)
 
 	t.Run("Fails if module name already in use", func(t *testing.T) {
@@ -315,7 +315,7 @@ func TestStore_Instantiate_Errors(t *testing.T) {
 }
 
 func TestCallContext_ExportedFunction(t *testing.T) {
-	host, err := NewHostModule("host", map[string]interface{}{"host_fn": func() {}}, nil, api.CoreFeaturesV1)
+	host, err := NewHostModule("host", map[string]interface{}{"host_fn": func() {}}, map[string]*HostFuncNames{"host_fn": {}}, api.CoreFeaturesV1)
 	require.NoError(t, err)
 
 	s, ns := newStore()