From b56924439d29620ba9d2e1b092fec2c5fdfef3e9 Mon Sep 17 00:00:00 2001 From: YiYing He Date: Fri, 10 Jul 2026 05:09:38 +0800 Subject: [PATCH 1/5] feat: update to the WasmEdge 0.17.1 C API - Wrap the new WasmEdge_LimitContext as the Limit context type, following the same structure as the other type contexts (FunctionType, etc.), with the 64-bit limit constructors for the memory64 proposal and the IsEqual API. Remove NewLimitShared (shared limits require a max in WasmEdge 0.17.1). - Widen the memory/table instance offset/size APIs to 64-bit. - Add Configure.SetRunMode/GetRunMode (interpreter/JIT/AOT) and Configure.SetWASMStandard (WASM 1.0/2.0/3.0), replacing the deprecated force-interpreter configuration. - Add SetLogLevel with the LogLevel enumeration. - Add NewWasiModuleWithFds/InitWasiWithFds. - Add VM.RegisterModuleWithAlias, VM.ForceDeleteRegisteredModule, and Executor.RegisterImportWithAlias. - Add the generic Ref value type for GC proposal references, and IsNull for FuncRef/ExternRef/Ref. - Remove all wasm-bindgen support (VM.ExecuteBindgen*, bindgen consts). - Fix nil pointer dereference in FunctionType.GetParameters/GetReturns. - Replace deprecated reflect.SliceHeader usage with unsafe.Slice. - Fix main.go smoke test which referenced a nonexistent constant. Assisted-By: Claude Fable 5 Signed-off-by: YiYing He --- main.go | 8 +- wasmedge/ast.go | 38 +++----- wasmedge/compiler.go | 2 +- wasmedge/configure.go | 36 ++++++- wasmedge/executor.go | 9 ++ wasmedge/hostfunc.go | 13 +-- wasmedge/instance.go | 83 ++++++++++++++--- wasmedge/limit.go | 118 ++++++++++++++--------- wasmedge/log.go | 15 +++ wasmedge/value.go | 211 ++++++------------------------------------ wasmedge/vm.go | 81 +++------------- 11 files changed, 262 insertions(+), 352 deletions(-) diff --git a/main.go b/main.go index 99a67ab9..d0dac42b 100644 --- a/main.go +++ b/main.go @@ -2,13 +2,13 @@ package main import ( "fmt" + "github.com/second-state/WasmEdge-go/wasmedge" ) func main() { wasmedge.SetLogOff() - conf := wasmedge.NewConfigure(wasmedge.WasmEdge_Configure_Default) - conf.Release() - fmt.Println("Success") + conf := wasmedge.NewConfigure(wasmedge.WASI) + defer conf.Release() + fmt.Println("WasmEdge version:", wasmedge.GetVersion()) } - diff --git a/wasmedge/ast.go b/wasmedge/ast.go index 4fee302f..daed3b2e 100644 --- a/wasmedge/ast.go +++ b/wasmedge/ast.go @@ -145,7 +145,7 @@ func (self *FunctionType) GetParameters() []*ValType { cvaltype = make([]C.WasmEdge_ValType, uint(ltypes)) C.WasmEdge_FunctionTypeGetParameters(self._inner, &(cvaltype[0]), ltypes) for i, val := range cvaltype { - valtype[i]._inner = val + valtype[i] = &ValType{_inner: val} } return valtype } @@ -167,7 +167,7 @@ func (self *FunctionType) GetReturns() []*ValType { cvaltype = make([]C.WasmEdge_ValType, uint(ltypes)) C.WasmEdge_FunctionTypeGetReturns(self._inner, &(cvaltype[0]), ltypes) for i, val := range cvaltype { - valtype[i]._inner = val + valtype[i] = &ValType{_inner: val} } return valtype } @@ -184,13 +184,10 @@ func (self *FunctionType) Release() { } func NewTableType(rtype *ValType, lim *Limit) *TableType { - climit := C.WasmEdge_Limit{ - HasMax: C.bool(lim.hasmax), - Shared: C.bool(lim.shared), - Min: C.uint32_t(lim.min), - Max: C.uint32_t(lim.max), + if lim == nil || lim._inner == nil { + return nil } - ttype := C.WasmEdge_TableTypeCreate(rtype._inner, climit) + ttype := C.WasmEdge_TableTypeCreate(rtype._inner, lim._inner) if ttype == nil { return nil } @@ -204,12 +201,10 @@ func (self *TableType) GetRefType() *ValType { func (self *TableType) GetLimit() *Limit { if self._inner != nil { climit := C.WasmEdge_TableTypeGetLimit(self._inner) - return &Limit{ - min: uint(climit.Min), - max: uint(climit.Max), - hasmax: bool(climit.HasMax), - shared: bool(climit.Shared), + if climit == nil { + return nil } + return &Limit{_inner: climit, _own: false} } return nil } @@ -223,13 +218,10 @@ func (self *TableType) Release() { } func NewMemoryType(lim *Limit) *MemoryType { - climit := C.WasmEdge_Limit{ - HasMax: C.bool(lim.hasmax), - Shared: C.bool(lim.shared), - Min: C.uint32_t(lim.min), - Max: C.uint32_t(lim.max), + if lim == nil || lim._inner == nil { + return nil } - mtype := C.WasmEdge_MemoryTypeCreate(climit) + mtype := C.WasmEdge_MemoryTypeCreate(lim._inner) if mtype == nil { return nil } @@ -239,12 +231,10 @@ func NewMemoryType(lim *Limit) *MemoryType { func (self *MemoryType) GetLimit() *Limit { if self._inner != nil { climit := C.WasmEdge_MemoryTypeGetLimit(self._inner) - return &Limit{ - min: uint(climit.Min), - max: uint(climit.Max), - hasmax: bool(climit.HasMax), - shared: bool(climit.Shared), + if climit == nil { + return nil } + return &Limit{_inner: climit, _own: false} } return nil } diff --git a/wasmedge/compiler.go b/wasmedge/compiler.go index 81018b66..a6a77b5c 100644 --- a/wasmedge/compiler.go +++ b/wasmedge/compiler.go @@ -40,7 +40,7 @@ func (self *Compiler) Compile(inpath string, outpath string) error { return nil } -func (self *Compiler) CompileBuffer(buf []byte, outpath string) (error) { +func (self *Compiler) CompileBuffer(buf []byte, outpath string) error { coutpath := C.CString(outpath) defer C.free(unsafe.Pointer(coutpath)) cbytes := C.WasmEdge_BytesWrap((*C.uint8_t)(unsafe.Pointer(&buf[0])), C.uint32_t(len(buf))) diff --git a/wasmedge/configure.go b/wasmedge/configure.go index 83c430bb..60f34e78 100644 --- a/wasmedge/configure.go +++ b/wasmedge/configure.go @@ -32,6 +32,28 @@ const ( WASI = HostRegistration(C.WasmEdge_HostRegistration_Wasi) ) +type RunMode C.enum_WasmEdge_RunMode + +const ( + // Run the WASM in the interpreter mode (default). + RunMode_Interpreter = RunMode(C.WasmEdge_RunMode_Interpreter) + // Run the WASM in the just-in-time compilation mode. + RunMode_JIT = RunMode(C.WasmEdge_RunMode_JIT) + // Run the WASM in the ahead-of-time compilation mode. + RunMode_AOT = RunMode(C.WasmEdge_RunMode_AOT) +) + +type WASMStandard C.enum_WasmEdge_Standard + +const ( + // The WebAssembly 1.0 standard. + Standard_WASM_1 = WASMStandard(C.WasmEdge_Standard_WASM_1) + // The WebAssembly 2.0 standard. + Standard_WASM_2 = WASMStandard(C.WasmEdge_Standard_WASM_2) + // The WebAssembly 3.0 standard. + Standard_WASM_3 = WASMStandard(C.WasmEdge_Standard_WASM_3) +) + type CompilerOptimizationLevel C.enum_WasmEdge_CompilerOptimizationLevel const ( @@ -117,19 +139,23 @@ func (self *Configure) RemoveConfig(conf interface{}) { } func (self *Configure) SetMaxMemoryPage(pagesize uint) { - C.WasmEdge_ConfigureSetMaxMemoryPage(self._inner, C.uint32_t(pagesize)) + C.WasmEdge_ConfigureSetMaxMemoryPage(self._inner, C.uint64_t(pagesize)) } func (self *Configure) GetMaxMemoryPage() uint { return uint(C.WasmEdge_ConfigureGetMaxMemoryPage(self._inner)) } -func (self *Configure) SetForceInterpreter(isinterpreter bool) { - C.WasmEdge_ConfigureSetForceInterpreter(self._inner, C.bool(isinterpreter)) +func (self *Configure) SetWASMStandard(std WASMStandard) { + C.WasmEdge_ConfigureSetWASMStandard(self._inner, C.enum_WasmEdge_Standard(std)) +} + +func (self *Configure) SetRunMode(mode RunMode) { + C.WasmEdge_ConfigureSetRunMode(self._inner, C.enum_WasmEdge_RunMode(mode)) } -func (self *Configure) IsForceInterpreter() bool { - return bool(C.WasmEdge_ConfigureIsForceInterpreter(self._inner)) +func (self *Configure) GetRunMode() RunMode { + return RunMode(C.WasmEdge_ConfigureGetRunMode(self._inner)) } func (self *Configure) SetCompilerOptimizationLevel(level CompilerOptimizationLevel) { diff --git a/wasmedge/executor.go b/wasmedge/executor.go index 987dcbc1..5fb9a23b 100644 --- a/wasmedge/executor.go +++ b/wasmedge/executor.go @@ -70,6 +70,15 @@ func (self *Executor) RegisterImport(store *Store, module *Module) error { return nil } +func (self *Executor) RegisterImportWithAlias(store *Store, module *Module, modname string) error { + modstr := toWasmEdgeStringWrap(modname) + res := C.WasmEdge_ExecutorRegisterImportWithAlias(self._inner, store._inner, module._inner, modstr) + if !C.WasmEdge_ResultOK(res) { + return newError(res) + } + return nil +} + func (self *Executor) Invoke(funcinst *Function, params ...interface{}) ([]interface{}, error) { ftype := funcinst.GetFunctionType() cparams := toWasmEdgeValueSlide(params...) diff --git a/wasmedge/hostfunc.go b/wasmedge/hostfunc.go index bde56b6d..1759e287 100644 --- a/wasmedge/hostfunc.go +++ b/wasmedge/hostfunc.go @@ -3,7 +3,6 @@ package wasmedge // #include import "C" import ( - "reflect" "sync" "unsafe" ) @@ -64,12 +63,8 @@ func wasmedgego_HostFuncInvokeImpl(fn uintptr, data *C.void, callframe *C.WasmEd } goparams := make([]interface{}, uint(paramlen)) - var cparams []C.WasmEdge_Value if paramlen > 0 { - sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&cparams))) - sliceHeader.Cap = int(paramlen) - sliceHeader.Len = int(paramlen) - sliceHeader.Data = uintptr(unsafe.Pointer(params)) + cparams := unsafe.Slice(params, int(paramlen)) for i := 0; i < int(paramlen); i++ { goparams[i] = fromWasmEdgeValue(cparams[i]) if C.WasmEdge_ValTypeIsExternRef(cparams[i].Type) == true && !goparams[i].(ExternRef)._valid { @@ -81,12 +76,8 @@ func wasmedgego_HostFuncInvokeImpl(fn uintptr, data *C.void, callframe *C.WasmEd gofunc, godata := hostfuncMgr.get(uint(fn)) goreturns, err := gofunc(godata, gocallgrame, goparams) - var creturns []C.WasmEdge_Value if returnlen > 0 && goreturns != nil { - sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&creturns))) - sliceHeader.Cap = int(returnlen) - sliceHeader.Len = int(returnlen) - sliceHeader.Data = uintptr(unsafe.Pointer(returns)) + creturns := unsafe.Slice(returns, int(returnlen)) for i, val := range goreturns { if i < int(returnlen) { creturns[i] = toWasmEdgeValue(val) diff --git a/wasmedge/instance.go b/wasmedge/instance.go index 67063540..0bee9ba5 100644 --- a/wasmedge/instance.go +++ b/wasmedge/instance.go @@ -38,7 +38,6 @@ wasmedgego_FunctionInstanceCreateBindingWrapper( import "C" import ( "errors" - "reflect" "unsafe" ) @@ -114,6 +113,39 @@ func NewWasiModule(args []string, envs []string, preopens []string) *Module { return &Module{_inner: module, _own: true} } +func NewWasiModuleWithFds(args []string, envs []string, preopens []string, stdinFd int, stdoutFd int, stderrFd int) *Module { + cargs := toCStringArray(args) + cenvs := toCStringArray(envs) + cpreopens := toCStringArray(preopens) + var ptrargs *(*C.char) = nil + var ptrenvs *(*C.char) = nil + var ptrpreopens *(*C.char) = nil + if len(cargs) > 0 { + ptrargs = &cargs[0] + } + if len(cenvs) > 0 { + ptrenvs = &cenvs[0] + } + if len(cpreopens) > 0 { + ptrpreopens = &cpreopens[0] + } + + module := C.WasmEdge_ModuleInstanceCreateWASIWithFds( + ptrargs, C.uint32_t(len(cargs)), + ptrenvs, C.uint32_t(len(cenvs)), + ptrpreopens, C.uint32_t(len(cpreopens)), + C.int32_t(stdinFd), C.int32_t(stdoutFd), C.int32_t(stderrFd)) + + freeCStringArray(cargs) + freeCStringArray(cenvs) + freeCStringArray(cpreopens) + + if module == nil { + return nil + } + return &Module{_inner: module, _own: true} +} + func (self *Module) InitWasi(args []string, envs []string, preopens []string) { cargs := toCStringArray(args) cenvs := toCStringArray(envs) @@ -141,6 +173,34 @@ func (self *Module) InitWasi(args []string, envs []string, preopens []string) { freeCStringArray(cpreopens) } +func (self *Module) InitWasiWithFds(args []string, envs []string, preopens []string, stdinFd int, stdoutFd int, stderrFd int) { + cargs := toCStringArray(args) + cenvs := toCStringArray(envs) + cpreopens := toCStringArray(preopens) + var ptrargs *(*C.char) = nil + var ptrenvs *(*C.char) = nil + var ptrpreopens *(*C.char) = nil + if len(cargs) > 0 { + ptrargs = &cargs[0] + } + if len(cenvs) > 0 { + ptrenvs = &cenvs[0] + } + if len(cpreopens) > 0 { + ptrpreopens = &cpreopens[0] + } + + C.WasmEdge_ModuleInstanceInitWASIWithFds(self._inner, + ptrargs, C.uint32_t(len(cargs)), + ptrenvs, C.uint32_t(len(cenvs)), + ptrpreopens, C.uint32_t(len(cpreopens)), + C.int32_t(stdinFd), C.int32_t(stdoutFd), C.int32_t(stderrFd)) + + freeCStringArray(cargs) + freeCStringArray(cenvs) + freeCStringArray(cpreopens) +} + func (self *Module) WasiGetExitCode() uint { return uint(C.WasmEdge_ModuleInstanceWASIGetExitCode(self._inner)) } @@ -346,7 +406,7 @@ func (self *Table) GetTableType() *TableType { func (self *Table) GetData(off uint) (interface{}, error) { cval := C.WasmEdge_Value{} - res := C.WasmEdge_TableInstanceGetData(self._inner, &cval, C.uint32_t(off)) + res := C.WasmEdge_TableInstanceGetData(self._inner, &cval, C.uint64_t(off)) if !C.WasmEdge_ResultOK(res) { return nil, newError(res) } @@ -355,7 +415,7 @@ func (self *Table) GetData(off uint) (interface{}, error) { func (self *Table) SetData(data interface{}, off uint) error { cval := toWasmEdgeValue(data) - res := C.WasmEdge_TableInstanceSetData(self._inner, cval, C.uint32_t(off)) + res := C.WasmEdge_TableInstanceSetData(self._inner, cval, C.uint64_t(off)) if !C.WasmEdge_ResultOK(res) { return newError(res) } @@ -367,7 +427,7 @@ func (self *Table) GetSize() uint { } func (self *Table) Grow(size uint) error { - res := C.WasmEdge_TableInstanceGrow(self._inner, C.uint32_t(size)) + res := C.WasmEdge_TableInstanceGrow(self._inner, C.uint64_t(size)) if !C.WasmEdge_ResultOK(res) { return newError(res) } @@ -401,17 +461,12 @@ func (self *Memory) GetMemoryType() *MemoryType { } func (self *Memory) GetData(off uint, length uint) ([]byte, error) { - p := C.WasmEdge_MemoryInstanceGetPointer(self._inner, C.uint32_t(off), C.uint32_t(length)) + p := C.WasmEdge_MemoryInstanceGetPointer(self._inner, C.uint64_t(off), C.uint64_t(length)) if p == nil { return nil, errors.New("Failed get data pointer") } - // Use SliceHeader to wrap the slice from cgo - var r []byte - s := (*reflect.SliceHeader)(unsafe.Pointer(&r)) - s.Cap = int(length) - s.Len = int(length) - s.Data = uintptr(unsafe.Pointer(p)) - return r, nil + // Wrap the WASM linear memory region from cgo as a slice view. + return unsafe.Slice((*byte)(unsafe.Pointer(p)), int(length)), nil } func (self *Memory) SetData(data []byte, off uint, length uint) error { @@ -419,7 +474,7 @@ func (self *Memory) SetData(data []byte, off uint, length uint) error { if len(data) > 0 { ptrdata = (*C.uint8_t)(unsafe.Pointer(&data[0])) } - res := C.WasmEdge_MemoryInstanceSetData(self._inner, ptrdata, C.uint32_t(off), C.uint32_t(length)) + res := C.WasmEdge_MemoryInstanceSetData(self._inner, ptrdata, C.uint64_t(off), C.uint64_t(length)) if !C.WasmEdge_ResultOK(res) { return newError(res) } @@ -431,7 +486,7 @@ func (self *Memory) GetPageSize() uint { } func (self *Memory) GrowPage(size uint) error { - res := C.WasmEdge_MemoryInstanceGrowPage(self._inner, C.uint32_t(size)) + res := C.WasmEdge_MemoryInstanceGrowPage(self._inner, C.uint64_t(size)) if !C.WasmEdge_ResultOK(res) { return newError(res) } diff --git a/wasmedge/limit.go b/wasmedge/limit.go index 01e17302..7980c58a 100644 --- a/wasmedge/limit.go +++ b/wasmedge/limit.go @@ -4,68 +4,102 @@ package wasmedge import "C" type Limit struct { - min uint - max uint - hasmax bool - shared bool + _inner *C.WasmEdge_LimitContext + _own bool } func NewLimit(minVal uint) *Limit { - l := &Limit{ - min: minVal, - max: minVal, - hasmax: false, - shared: false, + limit := C.WasmEdge_LimitCreate(C.uint64_t(minVal), C.bool(false)) + if limit == nil { + return nil } - return l + return &Limit{_inner: limit, _own: true} } func NewLimitWithMax(minVal uint, maxVal uint) *Limit { - if maxVal >= minVal { - return &Limit{ - min: minVal, - max: maxVal, - hasmax: true, - shared: false, - } + if maxVal < minVal { + return nil } - return nil + limit := C.WasmEdge_LimitCreateWithMax( + C.uint64_t(minVal), C.uint64_t(maxVal), C.bool(false), C.bool(false)) + if limit == nil { + return nil + } + return &Limit{_inner: limit, _own: true} } -func NewLimitShared(minVal uint) *Limit { - l := &Limit{ - min: minVal, - max: minVal, - hasmax: false, - shared: true, +func NewLimitSharedWithMax(minVal uint, maxVal uint) *Limit { + if maxVal < minVal { + return nil + } + limit := C.WasmEdge_LimitCreateWithMax( + C.uint64_t(minVal), C.uint64_t(maxVal), C.bool(false), C.bool(true)) + if limit == nil { + return nil } - return l + return &Limit{_inner: limit, _own: true} } -func NewLimitSharedWithMax(minVal uint, maxVal uint) *Limit { - if maxVal >= minVal { - return &Limit{ - min: minVal, - max: maxVal, - hasmax: true, - shared: true, - } +func NewLimit64(minVal uint) *Limit { + limit := C.WasmEdge_LimitCreate(C.uint64_t(minVal), C.bool(true)) + if limit == nil { + return nil + } + return &Limit{_inner: limit, _own: true} +} + +func NewLimit64WithMax(minVal uint, maxVal uint) *Limit { + if maxVal < minVal { + return nil + } + limit := C.WasmEdge_LimitCreateWithMax( + C.uint64_t(minVal), C.uint64_t(maxVal), C.bool(true), C.bool(false)) + if limit == nil { + return nil } - return nil + return &Limit{_inner: limit, _own: true} } -func (l *Limit) HasMax() bool { - return l.hasmax +func NewLimit64SharedWithMax(minVal uint, maxVal uint) *Limit { + if maxVal < minVal { + return nil + } + limit := C.WasmEdge_LimitCreateWithMax( + C.uint64_t(minVal), C.uint64_t(maxVal), C.bool(true), C.bool(true)) + if limit == nil { + return nil + } + return &Limit{_inner: limit, _own: true} } -func (l *Limit) IsShared() bool { - return l.shared +func (self *Limit) HasMax() bool { + return bool(C.WasmEdge_LimitHasMax(self._inner)) } -func (l *Limit) GetMin() uint { - return l.min +func (self *Limit) IsShared() bool { + return bool(C.WasmEdge_LimitIsShared(self._inner)) } -func (l *Limit) GetMax() uint { - return l.max +func (self *Limit) Is64Bit() bool { + return bool(C.WasmEdge_LimitIs64Bit(self._inner)) +} + +func (self *Limit) GetMin() uint { + return uint(C.WasmEdge_LimitGetMin(self._inner)) +} + +func (self *Limit) GetMax() uint { + return uint(C.WasmEdge_LimitGetMax(self._inner)) +} + +func (self *Limit) IsEqual(lim *Limit) bool { + return bool(C.WasmEdge_LimitIsEqual(self._inner, lim._inner)) +} + +func (self *Limit) Release() { + if self._own { + C.WasmEdge_LimitDelete(self._inner) + } + self._inner = nil + self._own = false } diff --git a/wasmedge/log.go b/wasmedge/log.go index 1e41433d..344497f6 100644 --- a/wasmedge/log.go +++ b/wasmedge/log.go @@ -3,6 +3,21 @@ package wasmedge // #include import "C" +type LogLevel C.WasmEdge_LogLevel + +const ( + LogLevel_Trace = LogLevel(C.WasmEdge_LogLevel_Trace) + LogLevel_Debug = LogLevel(C.WasmEdge_LogLevel_Debug) + LogLevel_Info = LogLevel(C.WasmEdge_LogLevel_Info) + LogLevel_Warn = LogLevel(C.WasmEdge_LogLevel_Warn) + LogLevel_Error = LogLevel(C.WasmEdge_LogLevel_Error) + LogLevel_Critical = LogLevel(C.WasmEdge_LogLevel_Critical) +) + +func SetLogLevel(level LogLevel) { + C.WasmEdge_LogSetLevel(C.WasmEdge_LogLevel(level)) +} + func SetLogErrorLevel() { C.WasmEdge_LogSetErrorLevel() } diff --git a/wasmedge/value.go b/wasmedge/value.go index e22a91d4..3fa9190c 100644 --- a/wasmedge/value.go +++ b/wasmedge/value.go @@ -4,8 +4,6 @@ package wasmedge import "C" import ( "encoding/binary" - "fmt" - "reflect" "sync" "unsafe" ) @@ -181,6 +179,10 @@ func NewFuncRef(funcinst *Function) FuncRef { } } +func (self FuncRef) IsNull() bool { + return bool(C.WasmEdge_ValueIsNullRef(self._inner)) +} + func (self FuncRef) GetRef() *Function { funcinst := C.WasmEdge_ValueGetFuncRef(self._inner) if funcinst != nil { @@ -205,6 +207,10 @@ func NewExternRef(ptr interface{}) ExternRef { } } +func (self ExternRef) IsNull() bool { + return bool(C.WasmEdge_ValueIsNullRef(self._inner)) +} + func (self ExternRef) Release() { self._valid = false // Change type back to WasmEdge_ValType_I64 and get the i64 value @@ -221,17 +227,27 @@ func (self ExternRef) GetRef() interface{} { return nil } +// Ref is a generic WASM reference value which is not a function or external +// reference, e.g. the GC proposal references (anyref, structref, i31ref). +type Ref struct { + _inner C.WasmEdge_Value +} + +func (self Ref) IsNull() bool { + return bool(C.WasmEdge_ValueIsNullRef(self._inner)) +} + +func (self Ref) GetValType() *ValType { + return &ValType{_inner: self._inner.Type} +} + type V128 struct { _inner C.WasmEdge_Value } func NewV128(high uint64, low uint64) V128 { var cval C.__int128 - var buf []byte - sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&buf))) - sliceHeader.Cap = 16 - sliceHeader.Len = 16 - sliceHeader.Data = uintptr(unsafe.Pointer(&cval)) + buf := unsafe.Slice((*byte)(unsafe.Pointer(&cval)), 16) binary.LittleEndian.PutUint64(buf[:8], low) binary.LittleEndian.PutUint64(buf[8:], high) return V128{ @@ -241,11 +257,7 @@ func NewV128(high uint64, low uint64) V128 { func (self V128) GetVal() (uint64, uint64) { cval := C.WasmEdge_ValueGetV128(self._inner) - var buf []byte - sliceHeader := (*reflect.SliceHeader)((unsafe.Pointer(&buf))) - sliceHeader.Cap = 16 - sliceHeader.Len = 16 - sliceHeader.Data = uintptr(unsafe.Pointer(&cval)) + buf := unsafe.Slice((*byte)(unsafe.Pointer(&cval)), 16) return binary.LittleEndian.Uint64(buf[8:]), binary.LittleEndian.Uint64(buf[:8]) } @@ -258,6 +270,8 @@ func toWasmEdgeValue(value interface{}) C.WasmEdge_Value { panic("External reference is released") } return value.(ExternRef)._inner + case Ref: + return value.(Ref)._inner case V128: return value.(V128)._inner case int: @@ -316,7 +330,7 @@ func fromWasmEdgeValue(value C.WasmEdge_Value) interface{} { return ExternRef{_inner: value, _valid: false} } if C.WasmEdge_ValTypeIsRef(value.Type) { - return "externref" + return Ref{_inner: value} } panic("Wrong argument of fromWasmEdgeValue()") } @@ -329,88 +343,6 @@ func toWasmEdgeValueSlide(vals ...interface{}) []C.WasmEdge_Value { return cvals } -func toWasmEdgeValueSlideBindgen(vm *VM, rettype bindgen, modname *string, vals ...interface{}) []C.WasmEdge_Value { - //cvals := make([]C.WasmEdge_Value, len(vals)) - cvals := []C.WasmEdge_Value{} - if rettype == Bindgen_return_array { - // Array result address = 8 - cvals = append(cvals, C.WasmEdge_ValueGenI32(C.int32_t(8))) - } else if rettype == Bindgen_return_i64 { - // wasm-bindgen magic: Set memory offset for i64 return value - cvals = append(cvals, C.WasmEdge_ValueGenI32(C.int32_t(0))) - } - for _, val := range vals { - switch t := val.(type) { - case FuncRef: - panic("toWasmEdgeValueSlideBindgen(): Not support FuncRef now") - case ExternRef: - panic("toWasmEdgeValueSlideBindgen(): Not support ExternRef now") - case V128: - panic("toWasmEdgeValueSlideBindgen(): Not support v128 now") - case int32: - cvals = append(cvals, C.WasmEdge_ValueGenI32(C.int32_t(val.(int32)))) - case uint32: - cvals = append(cvals, C.WasmEdge_ValueGenI32(C.int32_t(val.(uint32)))) - case int64: - vall := C.WasmEdge_ValueGenI32(C.int32_t(uint32(val.(int64)))) - valu := C.WasmEdge_ValueGenI32(C.int32_t(uint32(val.(int64) >> 32))) - cvals = append(cvals, vall, valu) - case uint64: - vall := C.WasmEdge_ValueGenI32(C.int32_t(uint32(val.(uint64)))) - valu := C.WasmEdge_ValueGenI32(C.int32_t(uint32(val.(uint64) >> 32))) - cvals = append(cvals, vall, valu) - case int: - panic("toWasmEdgeValueSlideBindgen(): Not support int now, please use int32 or int64 instead") - case uint: - panic("toWasmEdgeValueSlideBindgen(): Not support uint now, please use uint32 or uint64 instead") - case float32: - panic("toWasmEdgeValueSlideBindgen(): Not support float32 now") - case float64: - panic("toWasmEdgeValueSlideBindgen(): Not support float64 now") - case []byte: - // Call malloc function - mallocsize := uint32(len(val.([]byte))) - var rets []interface{} - var err error = nil - if modname == nil { - rets, err = vm.Execute("__wbindgen_malloc", mallocsize) - } else { - rets, err = vm.ExecuteRegistered(*modname, "__wbindgen_malloc", mallocsize) - } - if err != nil { - panic("toWasmEdgeValueSlideBindgen(): malloc failed") - } - if len(rets) <= 0 { - panic("toWasmEdgeValueSlideBindgen(): malloc function signature unexpected") - } - argaddr := C.WasmEdge_ValueGenI32(C.int32_t(rets[0].(int32))) - argsize := C.WasmEdge_ValueGenI32(C.int32_t(mallocsize)) - cvals = append(cvals, argaddr, argsize) - // Set bytes - var mod *Module = nil - var mem *Memory = nil - if modname == nil { - mod = vm.GetActiveModule() - } else { - store := vm.GetStore() - mod = store.FindModule(*modname) - } - if mod != nil { - memnames := mod.ListMemory() - if len(memnames) <= 0 { - panic("toWasmEdgeValueSlideBindgen(): memory instance not found") - } - mem = mod.FindMemory(memnames[0]) - mem.SetData(val.([]byte), uint(rets[0].(int32)), uint(mallocsize)) - } - default: - errorString := fmt.Sprintf("Wrong argument of toWasmEdgeValueSlideBindgen(): %T not supported", t) - panic(errorString) - } - } - return cvals -} - func fromWasmEdgeValueSlide(cvals []C.WasmEdge_Value) []interface{} { if len(cvals) > 0 { vals := make([]interface{}, len(cvals)) @@ -421,92 +353,3 @@ func fromWasmEdgeValueSlide(cvals []C.WasmEdge_Value) []interface{} { } return []interface{}{} } - -func fromWasmEdgeValueSlideBindgen(vm *VM, rettype bindgen, modname *string, cvals []C.WasmEdge_Value) (interface{}, error) { - returns := fromWasmEdgeValueSlide(cvals) - switch rettype { - case Bindgen_return_void: - return nil, nil - case Bindgen_return_i32: - if len(returns) <= 0 { - panic("Expected return i32, but got empty") - } - return returns[0], nil - case Bindgen_return_i64: - // Get memory context - var mod *Module = nil - var mem *Memory = nil - if modname == nil { - mod = vm.GetActiveModule() - } else { - store := vm.GetStore() - mod = store.FindModule(*modname) - } - if mod != nil { - memnames := mod.ListMemory() - if len(memnames) > 0 { - mem = mod.FindMemory(memnames[0]) - } - } - // Get int64 - if mem == nil { - panic("fromWasmEdgeValueSlideBindgen(): memory instance not found") - } - buf, err := mem.GetData(0, 8) - if err != nil { - return nil, err - } - var num int64 = 0 - for i, val := range buf { - num += int64(val) << (i * 8) - } - return num, nil - case Bindgen_return_array: - // Get memory context - var mod *Module = nil - var mem *Memory = nil - if modname == nil { - mod = vm.GetActiveModule() - } else { - store := vm.GetStore() - mod = store.FindModule(*modname) - } - if mod != nil { - memnames := mod.ListMemory() - if len(memnames) > 0 { - mem = mod.FindMemory(memnames[0]) - } - } - // Get address and length (array result address = 8) - if mem == nil { - panic("fromWasmEdgeValueSlideBindgen(): memory instance not found") - } - buf, err := mem.GetData(8, 8) - if err != nil { - return nil, err - } - var num int64 = 0 - for i, val := range buf { - num += int64(val) << (i * 8) - } - // Get bytes - var arraddr = int32(num) - var arrlen = int32(num >> 32) - buf, err = mem.GetData(uint(arraddr), uint(arrlen)) - if err != nil { - return nil, err - } - // Free array - if modname == nil { - _, err = vm.Execute("__wbindgen_free", arraddr, arrlen) - } else { - _, err = vm.ExecuteRegistered(*modname, "__wbindgen_free", arraddr, arrlen) - } - if err != nil { - panic("fromWasmEdgeValueSlideBindgen(): malloc failed") - } - return buf, nil - default: - panic("Wrong expected return type") - } -} diff --git a/wasmedge/vm.go b/wasmedge/vm.go index 28d14ee1..71baa403 100644 --- a/wasmedge/vm.go +++ b/wasmedge/vm.go @@ -17,15 +17,6 @@ type VM struct { _own bool } -type bindgen int - -const ( - Bindgen_return_void bindgen = iota - Bindgen_return_i32 bindgen = iota - Bindgen_return_i64 bindgen = iota - Bindgen_return_array bindgen = iota -) - func NewVM() *VM { vm := C.WasmEdge_VMCreate(nil, nil) if vm == nil { @@ -96,6 +87,20 @@ func (self *VM) RegisterModule(module *Module) error { return nil } +func (self *VM) RegisterModuleWithAlias(modname string, module *Module) error { + modstr := toWasmEdgeStringWrap(modname) + res := C.WasmEdge_VMRegisterModuleFromImportWithAlias(self._inner, modstr, module._inner) + if !C.WasmEdge_ResultOK(res) { + return newError(res) + } + return nil +} + +func (self *VM) ForceDeleteRegisteredModule(modname string) { + modstr := toWasmEdgeStringWrap(modname) + C.WasmEdge_VMForceDeleteRegisteredModule(self._inner, modstr) +} + func (self *VM) runWasm(funcname string, params ...interface{}) ([]interface{}, error) { res := C.WasmEdge_VMValidate(self._inner) if !C.WasmEdge_ResultOK(res) { @@ -266,34 +271,6 @@ func (self *VM) AsyncExecute(funcname string, params ...interface{}) *Async { return &Async{_inner: async, _own: true} } -// Special execute function for running with wasm-bindgen. -func (self *VM) ExecuteBindgen(funcname string, rettype bindgen, params ...interface{}) (interface{}, error) { - funcstr := toWasmEdgeStringWrap(funcname) - ftype := self.GetFunctionType(funcname) - if ftype == nil { - // If get function type failed, set as NULL and keep running to let the VM to handle the error. - ftype = &FunctionType{_inner: nil, _own: false} - } - cparams := toWasmEdgeValueSlideBindgen(self, rettype, nil, params...) - creturns := make([]C.WasmEdge_Value, ftype.GetReturnsLength()) - var ptrparams *C.WasmEdge_Value = nil - var ptrreturns *C.WasmEdge_Value = nil - if len(cparams) > 0 { - ptrparams = (*C.WasmEdge_Value)(unsafe.Pointer(&cparams[0])) - } - if len(creturns) > 0 { - ptrreturns = (*C.WasmEdge_Value)(unsafe.Pointer(&creturns[0])) - } - res := C.WasmEdge_VMExecute( - self._inner, funcstr, - ptrparams, C.uint32_t(len(cparams)), - ptrreturns, C.uint32_t(len(creturns))) - if !C.WasmEdge_ResultOK(res) { - return nil, newError(res) - } - return fromWasmEdgeValueSlideBindgen(self, rettype, nil, creturns) -} - func (self *VM) ExecuteRegistered(modname string, funcname string, params ...interface{}) ([]interface{}, error) { modstr := toWasmEdgeStringWrap(modname) funcstr := toWasmEdgeStringWrap(funcname) @@ -337,36 +314,6 @@ func (self *VM) AsyncExecuteRegistered(modname string, funcname string, params . return &Async{_inner: async, _own: true} } -// Special execute function for running with wasm-bindgen. -func (self *VM) ExecuteBindgenRegistered(modname string, funcname string, rettype bindgen, params ...interface{}) (interface{}, error) { - modstr := toWasmEdgeStringWrap(modname) - funcstr := toWasmEdgeStringWrap(funcname) - ftype := self.GetFunctionType(funcname) - if ftype == nil { - // If get function type failed, set as NULL and keep running to let the VM to handle the error. - ftype = &FunctionType{_inner: nil, _own: false} - } - cparams := toWasmEdgeValueSlideBindgen(self, rettype, &modname, params...) - creturns := make([]C.WasmEdge_Value, ftype.GetReturnsLength()) - var ptrparams *C.WasmEdge_Value = nil - var ptrreturns *C.WasmEdge_Value = nil - if len(cparams) > 0 { - ptrparams = (*C.WasmEdge_Value)(unsafe.Pointer(&cparams[0])) - } - if len(creturns) > 0 { - ptrreturns = (*C.WasmEdge_Value)(unsafe.Pointer(&creturns[0])) - } - - res := C.WasmEdge_VMExecuteRegistered( - self._inner, modstr, funcstr, - ptrparams, C.uint32_t(len(cparams)), - ptrreturns, C.uint32_t(len(creturns))) - if !C.WasmEdge_ResultOK(res) { - return nil, newError(res) - } - return fromWasmEdgeValueSlideBindgen(self, rettype, &modname, creturns) -} - func (self *VM) GetFunctionType(funcname string) *FunctionType { funcstr := toWasmEdgeStringWrap(funcname) cftype := C.WasmEdge_VMGetFunctionType(self._inner, funcstr) From 295c0f7aac1d1410a9d6fc924cbd4c5c0b650ac1 Mon Sep 17 00:00:00 2001 From: YiYing He Date: Fri, 10 Jul 2026 05:11:11 +0800 Subject: [PATCH 2/5] chore: require Go 1.25 as the minimum version Go 1.25 is the lowest non-EOL Go release. Assisted-By: Claude Fable 5 Signed-off-by: YiYing He --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index fab48fb5..75024dab 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/second-state/WasmEdge-go -go 1.21 +go 1.25 // Lost header in v0.9.1 version. Please use the WasmEdge-go v0.9.2 for WasmEdge 0.9.1. retract v0.9.1 From 9de05cc2cda44c94fc89b9e14e4472aa8d9230d2 Mon Sep 17 00:00:00 2001 From: YiYing He Date: Fri, 10 Jul 2026 05:26:05 +0800 Subject: [PATCH 3/5] test: add unit tests for the wasmedge package APIs Covers configure, limits, values (v128/funcref/externref), AST loading/validation and type listing, module/table/memory/global instances, host functions and calling frames, executor, store, VM workflows (incl. WASI, async, registered modules), compiler (universal and native AOT outputs), JIT/AOT run modes, statistics, results, plug-ins, and the CLI drivers, with wat2wasm-generated fixtures in wasmedge/testdata. Also fixes two issues found by the tests: - Rebuild NewExternRef on WasmEdge_ValueGenExternRef. The previous implementation forged the value from an i64 and crashed the 0.17.x runtime, which keeps reference metadata in the value payload. - Document that VM.ForceDeleteRegisteredModule destroys the module instance, and make releasing a consumed ExternRef fail loudly even on copies of the value. Assisted-By: Claude Fable 5 Signed-off-by: YiYing He --- wasmedge/ast_test.go | 265 +++++++++++++++++++++++++ wasmedge/cli_test.go | 15 ++ wasmedge/compiler_test.go | 117 +++++++++++ wasmedge/configure_test.go | 179 +++++++++++++++++ wasmedge/executor_test.go | 236 ++++++++++++++++++++++ wasmedge/instance_test.go | 259 ++++++++++++++++++++++++ wasmedge/limit_test.go | 102 +++++++++- wasmedge/log_test.go | 21 ++ wasmedge/plugin_test.go | 23 +++ wasmedge/result_test.go | 42 ++++ wasmedge/statistics_test.go | 54 ++++++ wasmedge/store_test.go | 41 ++++ wasmedge/testdata/fib.wasm | Bin 0 -> 61 bytes wasmedge/testdata/fib.wat | 8 + wasmedge/testdata/invalid.wasm | Bin 0 -> 34 bytes wasmedge/testdata/invalid.wat | 4 + wasmedge/testdata/memops.wasm | Bin 0 -> 127 bytes wasmedge/testdata/memops.wat | 11 ++ wasmedge/testdata/refs.wasm | Bin 0 -> 150 bytes wasmedge/testdata/refs.wat | 12 ++ wasmedge/testdata/trap.wasm | Bin 0 -> 56 bytes wasmedge/testdata/trap.wat | 5 + wasmedge/testdata/types.wasm | Bin 0 -> 169 bytes wasmedge/testdata/types.wat | 13 ++ wasmedge/testdata/wasi_hello.wasm | Bin 0 -> 177 bytes wasmedge/testdata/wasi_hello.wat | 13 ++ wasmedge/value.go | 44 +++-- wasmedge/value_test.go | 193 ++++++++++++++++++ wasmedge/version_test.go | 22 +++ wasmedge/vm.go | 2 + wasmedge/vm_test.go | 313 ++++++++++++++++++++++++++++++ wasmedge/wasmedge_test.go | 79 ++++++++ 32 files changed, 2057 insertions(+), 16 deletions(-) create mode 100644 wasmedge/ast_test.go create mode 100644 wasmedge/cli_test.go create mode 100644 wasmedge/compiler_test.go create mode 100644 wasmedge/configure_test.go create mode 100644 wasmedge/executor_test.go create mode 100644 wasmedge/instance_test.go create mode 100644 wasmedge/log_test.go create mode 100644 wasmedge/plugin_test.go create mode 100644 wasmedge/result_test.go create mode 100644 wasmedge/statistics_test.go create mode 100644 wasmedge/store_test.go create mode 100644 wasmedge/testdata/fib.wasm create mode 100644 wasmedge/testdata/fib.wat create mode 100644 wasmedge/testdata/invalid.wasm create mode 100644 wasmedge/testdata/invalid.wat create mode 100644 wasmedge/testdata/memops.wasm create mode 100644 wasmedge/testdata/memops.wat create mode 100644 wasmedge/testdata/refs.wasm create mode 100644 wasmedge/testdata/refs.wat create mode 100644 wasmedge/testdata/trap.wasm create mode 100644 wasmedge/testdata/trap.wat create mode 100644 wasmedge/testdata/types.wasm create mode 100644 wasmedge/testdata/types.wat create mode 100644 wasmedge/testdata/wasi_hello.wasm create mode 100644 wasmedge/testdata/wasi_hello.wat create mode 100644 wasmedge/value_test.go create mode 100644 wasmedge/version_test.go create mode 100644 wasmedge/vm_test.go create mode 100644 wasmedge/wasmedge_test.go diff --git a/wasmedge/ast_test.go b/wasmedge/ast_test.go new file mode 100644 index 00000000..b747ad7c --- /dev/null +++ b/wasmedge/ast_test.go @@ -0,0 +1,265 @@ +package wasmedge + +import ( + "os" + "testing" +) + +func TestLoader(t *testing.T) { + loader := NewLoader() + if loader == nil { + t.Fatal("NewLoader() returned nil") + } + defer loader.Release() + + ast, err := loader.LoadFile(testWasmPath("fib.wasm")) + if err != nil { + t.Fatalf("LoadFile failed: %v", err) + } + ast.Release() + + buf, err := os.ReadFile(testWasmPath("fib.wasm")) + if err != nil { + t.Fatal(err) + } + ast, err = loader.LoadBuffer(buf) + if err != nil { + t.Fatalf("LoadBuffer failed: %v", err) + } + ast.Release() + + if _, err := loader.LoadFile("testdata/no_such_file.wasm"); err == nil { + t.Error("loading a missing file should fail") + } + if _, err := loader.LoadBuffer([]byte{0x00, 0x01, 0x02, 0x03}); err == nil { + t.Error("loading malformed bytes should fail") + } +} + +func TestValidator(t *testing.T) { + validator := NewValidator() + if validator == nil { + t.Fatal("NewValidator() returned nil") + } + defer validator.Release() + + ast := loadASTFromFile(t, testWasmPath("fib.wasm")) + defer ast.Release() + if err := validator.Validate(ast); err != nil { + t.Errorf("Validate failed on a valid module: %v", err) + } + + // invalid.wasm is well-formed but fails validation (missing return value). + badAST := loadASTFromFile(t, testWasmPath("invalid.wasm")) + defer badAST.Release() + if err := validator.Validate(badAST); err == nil { + t.Error("Validate should fail on an invalid module") + } +} + +func TestASTListImports(t *testing.T) { + ast := loadASTFromFile(t, testWasmPath("types.wasm")) + defer ast.Release() + + imports := ast.ListImports() + if len(imports) != 2 { + t.Fatalf("expected 2 imports, got %d", len(imports)) + } + + byName := map[string]*ImportType{} + for _, imp := range imports { + if imp.GetModuleName() != "env" { + t.Errorf("import module name = %q, want \"env\"", imp.GetModuleName()) + } + byName[imp.GetExternalName()] = imp + } + + fn, ok := byName["host_add"] + if !ok { + t.Fatal("import host_add not found") + } + if fn.GetExternalType() != ExternType_Function { + t.Error("host_add should be a function import") + } + ftype := fn.GetExternalValue().(*FunctionType) + if ftype.GetParametersLength() != 2 || ftype.GetReturnsLength() != 1 { + t.Errorf("host_add type mismatch: %d params, %d returns", + ftype.GetParametersLength(), ftype.GetReturnsLength()) + } + params := ftype.GetParameters() + if len(params) != 2 || !params[0].IsI32() || !params[1].IsI32() { + t.Error("host_add parameters should be [i32, i32]") + } + returns := ftype.GetReturns() + if len(returns) != 1 || !returns[0].IsI32() { + t.Error("host_add returns should be [i32]") + } + + glob, ok := byName["host_glob"] + if !ok { + t.Fatal("import host_glob not found") + } + if glob.GetExternalType() != ExternType_Global { + t.Error("host_glob should be a global import") + } + gtype := glob.GetExternalValue().(*GlobalType) + if !gtype.GetValType().IsI32() || gtype.GetMutability() != ValMut_Const { + t.Error("host_glob should be a const i32 global") + } +} + +func TestASTListExports(t *testing.T) { + ast := loadASTFromFile(t, testWasmPath("types.wasm")) + defer ast.Release() + + exports := ast.ListExports() + byName := map[string]*ExportType{} + for _, exp := range exports { + byName[exp.GetExternalName()] = exp + } + if len(byName) != 6 { + t.Fatalf("expected 6 exports, got %d", len(byName)) + } + + for _, name := range []string{"add", "call_add", "get_hglob"} { + exp, ok := byName[name] + if !ok || exp.GetExternalType() != ExternType_Function { + t.Errorf("export %q should be a function", name) + } + if _, ok := exp.GetExternalValue().(*FunctionType); !ok { + t.Errorf("export %q external value should be a FunctionType", name) + } + } + + tab := byName["tab"] + if tab == nil || tab.GetExternalType() != ExternType_Table { + t.Fatal("export tab should be a table") + } + ttype := tab.GetExternalValue().(*TableType) + if !ttype.GetRefType().IsFuncRef() { + t.Error("tab should be a funcref table") + } + lim := ttype.GetLimit() + if lim.GetMin() != 5 || !lim.HasMax() || lim.GetMax() != 20 || lim.Is64Bit() { + t.Errorf("tab limit mismatch: %+v", lim) + } + + mem := byName["mem"] + if mem == nil || mem.GetExternalType() != ExternType_Memory { + t.Fatal("export mem should be a memory") + } + mtype := mem.GetExternalValue().(*MemoryType) + lim = mtype.GetLimit() + if lim.GetMin() != 1 || !lim.HasMax() || lim.GetMax() != 2 || lim.IsShared() { + t.Errorf("mem limit mismatch: %+v", lim) + } + + glob := byName["glob"] + if glob == nil || glob.GetExternalType() != ExternType_Global { + t.Fatal("export glob should be a global") + } + gtype := glob.GetExternalValue().(*GlobalType) + if !gtype.GetValType().IsI64() || gtype.GetMutability() != ValMut_Var { + t.Error("glob should be a mutable i64 global") + } +} + +func TestFunctionTypeCreate(t *testing.T) { + ftype := NewFunctionType( + []*ValType{NewValTypeI32(), NewValTypeF64()}, + []*ValType{NewValTypeV128()}) + if ftype == nil { + t.Fatal("NewFunctionType() returned nil") + } + defer ftype.Release() + + params := ftype.GetParameters() + if len(params) != 2 || !params[0].IsI32() || !params[1].IsF64() { + t.Error("parameter types mismatch") + } + returns := ftype.GetReturns() + if len(returns) != 1 || !returns[0].IsV128() { + t.Error("return types mismatch") + } + + empty := NewFunctionType(nil, nil) + if empty == nil { + t.Fatal("NewFunctionType(nil, nil) returned nil") + } + defer empty.Release() + if empty.GetParametersLength() != 0 || empty.GetReturnsLength() != 0 { + t.Error("empty function type should have no parameters and returns") + } + if empty.GetParameters() != nil || empty.GetReturns() != nil { + t.Error("empty function type should return nil slices") + } +} + +func TestTableTypeCreate(t *testing.T) { + cases := []*Limit{ + NewLimit(10), + NewLimitWithMax(10, 30), + NewLimit64(10), + NewLimit64WithMax(10, 30), + } + for i, lim := range cases { + ttype := NewTableType(NewValTypeFuncRef(), lim) + if ttype == nil { + t.Fatalf("NewTableType() returned nil for case %d", i) + } + if !ttype.GetRefType().IsFuncRef() { + t.Error("table ref type should be funcref") + } + if !ttype.GetLimit().IsEqual(lim) { + t.Errorf("table limit round-trip mismatch for case %d", i) + } + ttype.Release() + lim.Release() + } + + elim := NewLimitWithMax(1, 2) + etype := NewTableType(NewValTypeExternRef(), elim) + elim.Release() + if etype == nil { + t.Fatal("externref table type creation failed") + } + if !etype.GetRefType().IsExternRef() { + t.Error("table ref type should be externref") + } + etype.Release() +} + +func TestMemoryTypeCreate(t *testing.T) { + cases := []*Limit{ + NewLimit(1), + NewLimitWithMax(1, 4), + NewLimitSharedWithMax(1, 4), + NewLimit64(1), + NewLimit64WithMax(1, 4), + } + for i, lim := range cases { + mtype := NewMemoryType(lim) + if mtype == nil { + t.Fatalf("NewMemoryType() returned nil for case %d", i) + } + if !mtype.GetLimit().IsEqual(lim) { + t.Errorf("memory limit round-trip mismatch for case %d", i) + } + mtype.Release() + lim.Release() + } +} + +func TestGlobalTypeCreate(t *testing.T) { + gtype := NewGlobalType(NewValTypeF32(), ValMut_Var) + if gtype == nil { + t.Fatal("NewGlobalType() returned nil") + } + defer gtype.Release() + if !gtype.GetValType().IsF32() { + t.Error("global value type should be f32") + } + if gtype.GetMutability() != ValMut_Var { + t.Error("global should be mutable") + } +} diff --git a/wasmedge/cli_test.go b/wasmedge/cli_test.go new file mode 100644 index 00000000..f99becfe --- /dev/null +++ b/wasmedge/cli_test.go @@ -0,0 +1,15 @@ +package wasmedge + +import "testing" + +func TestCLIVersion(t *testing.T) { + if ret := RunWasmEdgeCLI([]string{"wasmedge", "--version"}); ret != 0 { + t.Errorf("wasmedge --version returned %d", ret) + } + if ret := RunWasmEdgeAOTCompilerCLI([]string{"wasmedgec", "--version"}); ret != 0 { + t.Errorf("wasmedgec --version returned %d", ret) + } + if ret := RunWasmEdgeUnifiedCLI([]string{"wasmedge", "--version"}); ret != 0 { + t.Errorf("unified wasmedge --version returned %d", ret) + } +} diff --git a/wasmedge/compiler_test.go b/wasmedge/compiler_test.go new file mode 100644 index 00000000..d9367fb6 --- /dev/null +++ b/wasmedge/compiler_test.go @@ -0,0 +1,117 @@ +package wasmedge + +import ( + "os" + "path/filepath" + "runtime" + "testing" +) + +func nativeLibExtension() string { + if runtime.GOOS == "darwin" { + return ".dylib" + } + return ".so" +} + +func TestCompilerUniversalWasm(t *testing.T) { + compiler := NewCompiler() + if compiler == nil { + t.Fatal("NewCompiler() returned nil") + } + defer compiler.Release() + + out := filepath.Join(t.TempDir(), "fib_aot.wasm") + if err := compiler.Compile(testWasmPath("fib.wasm"), out); err != nil { + t.Fatalf("Compile failed: %v", err) + } + + // The universal WASM output runs on a default VM. + vm := NewVM() + defer vm.Release() + rets, err := vm.RunWasmFile(out, "fib", int32(20)) + if err != nil { + t.Fatalf("running the compiled module failed: %v", err) + } + if rets[0].(int32) != 10946 { + t.Errorf("fib(20) = %v, want 10946", rets[0]) + } +} + +func TestCompilerBuffer(t *testing.T) { + conf := NewConfigure() + defer conf.Release() + conf.SetCompilerOptimizationLevel(CompilerOptLevel_O0) + compiler := NewCompilerWithConfig(conf) + defer compiler.Release() + + buf, err := os.ReadFile(testWasmPath("fib.wasm")) + if err != nil { + t.Fatal(err) + } + out := filepath.Join(t.TempDir(), "fib_buf_aot.wasm") + if err := compiler.CompileBuffer(buf, out); err != nil { + t.Fatalf("CompileBuffer failed: %v", err) + } + if _, err := os.Stat(out); err != nil { + t.Fatalf("compiled output missing: %v", err) + } +} + +func TestCompilerFailure(t *testing.T) { + compiler := NewCompiler() + defer compiler.Release() + + out := filepath.Join(t.TempDir(), "bad.wasm") + if err := compiler.Compile("testdata/no_such_file.wasm", out); err == nil { + t.Error("compiling a missing file should fail") + } + if err := compiler.CompileBuffer([]byte{0x00, 0x01}, out); err == nil { + t.Error("compiling malformed bytes should fail") + } +} + +func TestRunModeAOT(t *testing.T) { + // Compile to a native shared library and run it with the AOT run mode, + // mirroring the WasmEdge AOT spec test flow. + conf := NewConfigure() + defer conf.Release() + conf.SetCompilerOutputFormat(CompilerOutputFormat_Native) + conf.SetCompilerOptimizationLevel(CompilerOptLevel_O0) + compiler := NewCompilerWithConfig(conf) + defer compiler.Release() + + out := filepath.Join(t.TempDir(), "fib"+nativeLibExtension()) + if err := compiler.Compile(testWasmPath("fib.wasm"), out); err != nil { + t.Fatalf("native compile failed: %v", err) + } + + runconf := NewConfigure() + defer runconf.Release() + runconf.SetRunMode(RunMode_AOT) + vm := NewVMWithConfig(runconf) + defer vm.Release() + rets, err := vm.RunWasmFile(out, "fib", int32(18)) + if err != nil { + t.Fatalf("running the native module failed: %v", err) + } + if rets[0].(int32) != 4181 { + t.Errorf("fib(18) = %v, want 4181", rets[0]) + } +} + +func TestRunModeJIT(t *testing.T) { + conf := NewConfigure() + defer conf.Release() + conf.SetRunMode(RunMode_JIT) + vm := NewVMWithConfig(conf) + defer vm.Release() + + rets, err := vm.RunWasmFile(testWasmPath("fib.wasm"), "fib", int32(16)) + if err != nil { + t.Fatalf("JIT run failed: %v", err) + } + if rets[0].(int32) != 1597 { + t.Errorf("fib(16) = %v, want 1597", rets[0]) + } +} diff --git a/wasmedge/configure_test.go b/wasmedge/configure_test.go new file mode 100644 index 00000000..a254cbd7 --- /dev/null +++ b/wasmedge/configure_test.go @@ -0,0 +1,179 @@ +package wasmedge + +import "testing" + +func TestConfigureProposals(t *testing.T) { + conf := NewConfigure() + if conf == nil { + t.Fatal("NewConfigure() returned nil") + } + defer conf.Release() + + // The default configuration is the WASM 3.0 proposal set; threads is one + // of the few proposals disabled by default. + if conf.HasConfig(THREADS) { + t.Error("threads should be disabled by default") + } + if !conf.HasConfig(MULTI_MEMORIES) || !conf.HasConfig(GC) { + t.Error("the WASM 3.0 proposals should be enabled by default") + } + conf.AddConfig(THREADS) + if !conf.HasConfig(THREADS) { + t.Error("threads should be enabled after AddConfig") + } + conf.RemoveConfig(THREADS) + if conf.HasConfig(THREADS) { + t.Error("threads should be disabled after RemoveConfig") + } + + // All proposal constants should be addable and removable. + for _, prop := range []Proposal{ + IMPORT_EXPORT_MUT_GLOBALS, + NON_TRAP_FLOAT_TO_INT_CONVERSIONS, + SIGN_EXTENSION_OPERATORS, + MULTI_VALUE, + BULK_MEMORY_OPERATIONS, + REFERENCE_TYPES, + SIMD, + TAIL_CALL, + EXTENDED_CONST, + FUNCTION_REFERENCES, + GC, + MULTI_MEMORIES, + THREADS, + RELAXED_SIMD, + ANNOTATIONS, + MEMORY64, + EXCEPTION_HANDLING, + } { + conf.AddConfig(prop) + if !conf.HasConfig(prop) { + t.Errorf("proposal %d should be enabled after AddConfig", prop) + } + } +} + +func TestConfigureHostRegistration(t *testing.T) { + conf := NewConfigure(WASI) + if conf == nil { + t.Fatal("NewConfigure(WASI) returned nil") + } + defer conf.Release() + if !conf.HasConfig(WASI) { + t.Error("WASI should be registered") + } + conf.RemoveConfig(WASI) + if conf.HasConfig(WASI) { + t.Error("WASI should be removed") + } +} + +func TestConfigureWASMStandard(t *testing.T) { + conf := NewConfigure() + defer conf.Release() + + conf.SetWASMStandard(Standard_WASM_1) + if conf.HasConfig(SIMD) { + t.Error("WASM 1.0 should not include the SIMD proposal") + } + + conf.SetWASMStandard(Standard_WASM_2) + if !conf.HasConfig(SIMD) { + t.Error("WASM 2.0 should include the SIMD proposal") + } + if conf.HasConfig(TAIL_CALL) { + t.Error("WASM 2.0 should not include the tail-call proposal") + } + + conf.SetWASMStandard(Standard_WASM_3) + if !conf.HasConfig(TAIL_CALL) { + t.Error("WASM 3.0 should include the tail-call proposal") + } + if !conf.HasConfig(GC) { + t.Error("WASM 3.0 should include the GC proposal") + } +} + +func TestConfigureRunMode(t *testing.T) { + conf := NewConfigure() + defer conf.Release() + + if conf.GetRunMode() != RunMode_Interpreter { + t.Errorf("default run mode should be the interpreter, got %d", conf.GetRunMode()) + } + for _, mode := range []RunMode{RunMode_JIT, RunMode_AOT, RunMode_Interpreter} { + conf.SetRunMode(mode) + if conf.GetRunMode() != mode { + t.Errorf("run mode should be %d, got %d", mode, conf.GetRunMode()) + } + } +} + +func TestConfigureMaxMemoryPage(t *testing.T) { + conf := NewConfigure() + defer conf.Release() + + conf.SetMaxMemoryPage(1234) + if conf.GetMaxMemoryPage() != 1234 { + t.Errorf("max memory page should be 1234, got %d", conf.GetMaxMemoryPage()) + } + // The page count is 64-bit in WasmEdge 0.17.1. + const bigPages = uint(1) << 40 + conf.SetMaxMemoryPage(bigPages) + if conf.GetMaxMemoryPage() != bigPages { + t.Errorf("max memory page should be %d, got %d", bigPages, conf.GetMaxMemoryPage()) + } +} + +func TestConfigureCompilerOptions(t *testing.T) { + conf := NewConfigure() + defer conf.Release() + + for _, level := range []CompilerOptimizationLevel{ + CompilerOptLevel_O0, CompilerOptLevel_O1, CompilerOptLevel_O2, + CompilerOptLevel_O3, CompilerOptLevel_Os, CompilerOptLevel_Oz, + } { + conf.SetCompilerOptimizationLevel(level) + if conf.GetCompilerOptimizationLevel() != level { + t.Errorf("optimization level should be %d, got %d", level, conf.GetCompilerOptimizationLevel()) + } + } + + for _, format := range []CompilerOutputFormat{ + CompilerOutputFormat_Native, CompilerOutputFormat_Wasm, + } { + conf.SetCompilerOutputFormat(format) + if conf.GetCompilerOutputFormat() != format { + t.Errorf("output format should be %d, got %d", format, conf.GetCompilerOutputFormat()) + } + } + + conf.SetCompilerDumpIR(true) + if !conf.IsCompilerDumpIR() { + t.Error("dump IR should be enabled") + } + conf.SetCompilerDumpIR(false) + + conf.SetCompilerGenericBinary(true) + if !conf.IsCompilerGenericBinary() { + t.Error("generic binary should be enabled") + } +} + +func TestConfigureStatisticsOptions(t *testing.T) { + conf := NewConfigure() + defer conf.Release() + + conf.SetStatisticsInstructionCounting(true) + if !conf.IsStatisticsInstructionCounting() { + t.Error("instruction counting should be enabled") + } + conf.SetStatisticsTimeMeasuring(true) + if !conf.IsStatisticsTimeMeasuring() { + t.Error("time measuring should be enabled") + } + conf.SetStatisticsCostMeasuring(true) + if !conf.IsStatisticsCostMeasuring() { + t.Error("cost measuring should be enabled") + } +} diff --git a/wasmedge/executor_test.go b/wasmedge/executor_test.go new file mode 100644 index 00000000..78480dfb --- /dev/null +++ b/wasmedge/executor_test.go @@ -0,0 +1,236 @@ +package wasmedge + +import ( + "testing" +) + +func TestExecutorInstantiate(t *testing.T) { + store := NewStore() + defer store.Release() + executor := NewExecutor() + if executor == nil { + t.Fatal("NewExecutor() returned nil") + } + defer executor.Release() + + mod := instantiateFile(t, executor, store, testWasmPath("fib.wasm")) + defer mod.Release() + + fn := mod.FindFunction("fib") + if fn == nil { + t.Fatal("exported function fib not found") + } + rets, err := executor.Invoke(fn, int32(10)) + if err != nil { + t.Fatalf("Invoke failed: %v", err) + } + if rets[0].(int32) != 89 { + t.Errorf("fib(10) = %v, want 89", rets[0]) + } +} + +func TestExecutorHostFunction(t *testing.T) { + store := NewStore() + defer store.Release() + executor := NewExecutor() + defer executor.Release() + + // Host function checking data passing and the calling frame. + type hostData struct{ called bool } + data := &hostData{} + addfn := func(d interface{}, frame *CallingFrame, params []interface{}) ([]interface{}, Result) { + d.(*hostData).called = true + if frame.GetExecutor() == nil { + t.Error("calling frame should expose the executor") + } + if frame.GetModule() == nil { + t.Error("calling frame should expose the calling module") + } + if frame.GetMemoryByIndex(0) == nil { + t.Error("calling module has a memory at index 0") + } + return []interface{}{params[0].(int32) + params[1].(int32)}, Result_Success + } + + env := NewModule("env") + defer env.Release() + ftype := NewFunctionType( + []*ValType{NewValTypeI32(), NewValTypeI32()}, + []*ValType{NewValTypeI32()}) + env.AddFunction("host_add", NewFunction(ftype, addfn, data, 0)) + ftype.Release() + gtype := NewGlobalType(NewValTypeI32(), ValMut_Const) + env.AddGlobal("host_glob", NewGlobal(gtype, int32(777))) + gtype.Release() + + if err := executor.RegisterImport(store, env); err != nil { + t.Fatalf("RegisterImport failed: %v", err) + } + + mod := instantiateFile(t, executor, store, testWasmPath("types.wasm")) + defer mod.Release() + + rets, err := executor.Invoke(mod.FindFunction("call_add"), int32(11), int32(22)) + if err != nil { + t.Fatalf("call_add failed: %v", err) + } + if rets[0].(int32) != 33 { + t.Errorf("call_add = %v, want 33", rets[0]) + } + if !data.called { + t.Error("host function should have been called with the bound data") + } + + rets, err = executor.Invoke(mod.FindFunction("get_hglob")) + if err != nil { + t.Fatalf("get_hglob failed: %v", err) + } + if rets[0].(int32) != 777 { + t.Errorf("get_hglob = %v, want 777", rets[0]) + } +} + +func TestExecutorHostFunctionError(t *testing.T) { + store := NewStore() + defer store.Release() + executor := NewExecutor() + defer executor.Release() + + failfn := func(interface{}, *CallingFrame, []interface{}) ([]interface{}, Result) { + return nil, NewResult(ErrCategory_UserLevel, 5566) + } + env := NewModule("env") + defer env.Release() + ftype := NewFunctionType( + []*ValType{NewValTypeI32(), NewValTypeI32()}, + []*ValType{NewValTypeI32()}) + env.AddFunction("host_add", NewFunction(ftype, failfn, nil, 0)) + ftype.Release() + gtype := NewGlobalType(NewValTypeI32(), ValMut_Const) + env.AddGlobal("host_glob", NewGlobal(gtype, int32(0))) + gtype.Release() + + if err := executor.RegisterImport(store, env); err != nil { + t.Fatalf("RegisterImport failed: %v", err) + } + mod := instantiateFile(t, executor, store, testWasmPath("types.wasm")) + defer mod.Release() + + _, err := executor.Invoke(mod.FindFunction("call_add"), int32(1), int32(2)) + if err == nil { + t.Fatal("host function error should propagate") + } + res := err.(*Result) + if res.GetErrorCategory() != ErrCategory_UserLevel { + t.Errorf("error category = %d, want user-level", res.GetErrorCategory()) + } + if res.GetCode() != 5566 { + t.Errorf("error code = %d, want 5566", res.GetCode()) + } +} + +func TestExecutorRegister(t *testing.T) { + store := NewStore() + defer store.Release() + executor := NewExecutor() + defer executor.Release() + + ast := loadASTFromFile(t, testWasmPath("fib.wasm")) + defer ast.Release() + validator := NewValidator() + defer validator.Release() + if err := validator.Validate(ast); err != nil { + t.Fatal(err) + } + + mod, err := executor.Register(store, ast, "math") + if err != nil { + t.Fatalf("Register failed: %v", err) + } + defer mod.Release() + + found := store.FindModule("math") + if found == nil { + t.Fatal("registered module not found in the store") + } + rets, err := executor.Invoke(found.FindFunction("fib"), int32(5)) + if err != nil { + t.Fatalf("Invoke failed: %v", err) + } + if rets[0].(int32) != 8 { + t.Errorf("fib(5) = %v, want 8", rets[0]) + } +} + +func TestExecutorRegisterImportWithAlias(t *testing.T) { + store := NewStore() + defer store.Release() + executor := NewExecutor() + defer executor.Release() + + mod := NewModule("original_name") + defer mod.Release() + gtype := NewGlobalType(NewValTypeI32(), ValMut_Const) + mod.AddGlobal("g", NewGlobal(gtype, int32(1))) + gtype.Release() + + if err := executor.RegisterImportWithAlias(store, mod, "alias_name"); err != nil { + t.Fatalf("RegisterImportWithAlias failed: %v", err) + } + if store.FindModule("alias_name") == nil { + t.Error("module should be findable under the alias") + } + + // Registering the same alias twice must fail with a name conflict. + if err := executor.RegisterImportWithAlias(store, mod, "alias_name"); err == nil { + t.Error("duplicate alias registration should fail") + } +} + +func TestExecutorAsyncInvoke(t *testing.T) { + store := NewStore() + defer store.Release() + executor := NewExecutor() + defer executor.Release() + + mod := instantiateFile(t, executor, store, testWasmPath("fib.wasm")) + defer mod.Release() + + async := executor.AsyncInvoke(mod.FindFunction("fib"), int32(15)) + if async == nil { + t.Fatal("AsyncInvoke returned nil") + } + defer async.Release() + async.WaitFor(5000) + rets, err := async.GetResult() + if err != nil { + t.Fatalf("async fib failed: %v", err) + } + if rets[0].(int32) != 987 { + t.Errorf("fib(15) = %v, want 987", rets[0]) + } +} + +func TestExecutorTrap(t *testing.T) { + store := NewStore() + defer store.Release() + executor := NewExecutor() + defer executor.Release() + + mod := instantiateFile(t, executor, store, testWasmPath("trap.wasm")) + defer mod.Release() + + if _, err := executor.Invoke(mod.FindFunction("trap")); err == nil { + t.Error("unreachable should trap") + } + if _, err := executor.Invoke(mod.FindFunction("div"), int32(1), int32(0)); err == nil { + t.Error("division by zero should trap") + } + rets, err := executor.Invoke(mod.FindFunction("div"), int32(12), int32(3)) + if err != nil { + t.Fatalf("div failed: %v", err) + } + if rets[0].(int32) != 4 { + t.Errorf("div = %v, want 4", rets[0]) + } +} diff --git a/wasmedge/instance_test.go b/wasmedge/instance_test.go new file mode 100644 index 00000000..ffc65f47 --- /dev/null +++ b/wasmedge/instance_test.go @@ -0,0 +1,259 @@ +package wasmedge + +import ( + "bytes" + "testing" +) + +func TestModuleCreation(t *testing.T) { + mod := NewModule("host") + if mod == nil { + t.Fatal("NewModule() returned nil") + } + defer mod.Release() + if mod.GetName() != "host" { + t.Errorf("module name = %q, want \"host\"", mod.GetName()) + } + + ftype := NewFunctionType(nil, nil) + fn := NewFunction(ftype, func(interface{}, *CallingFrame, []interface{}) ([]interface{}, Result) { + return nil, Result_Success + }, nil, 0) + ftype.Release() + mod.AddFunction("f", fn) + + tlim := NewLimitWithMax(2, 4) + ttype := NewTableType(NewValTypeFuncRef(), tlim) + tlim.Release() + tab := NewTable(ttype) + ttype.Release() + if tab == nil { + t.Fatal("NewTable() returned nil") + } + mod.AddTable("t", tab) + + mlim := NewLimitWithMax(1, 2) + mtype := NewMemoryType(mlim) + mlim.Release() + mem := NewMemory(mtype) + mtype.Release() + if mem == nil { + t.Fatal("NewMemory() returned nil") + } + mod.AddMemory("m", mem) + + gtype := NewGlobalType(NewValTypeI64(), ValMut_Var) + glob := NewGlobal(gtype, int64(-99)) + gtype.Release() + if glob == nil { + t.Fatal("NewGlobal() returned nil") + } + mod.AddGlobal("g", glob) + + if got := mod.ListFunction(); len(got) != 1 || got[0] != "f" { + t.Errorf("ListFunction() = %v, want [f]", got) + } + if got := mod.ListTable(); len(got) != 1 || got[0] != "t" { + t.Errorf("ListTable() = %v, want [t]", got) + } + if got := mod.ListMemory(); len(got) != 1 || got[0] != "m" { + t.Errorf("ListMemory() = %v, want [m]", got) + } + if got := mod.ListGlobal(); len(got) != 1 || got[0] != "g" { + t.Errorf("ListGlobal() = %v, want [g]", got) + } + if got := mod.ListTag(); len(got) != 0 { + t.Errorf("ListTag() = %v, want empty", got) + } + + if mod.FindFunction("f") == nil || mod.FindTable("t") == nil || + mod.FindMemory("m") == nil || mod.FindGlobal("g") == nil { + t.Error("Find* should locate the added instances") + } + if mod.FindFunction("nope") != nil || mod.FindTable("nope") != nil || + mod.FindMemory("nope") != nil || mod.FindGlobal("nope") != nil || + mod.FindTag("nope") != nil { + t.Error("Find* should return nil for unknown names") + } +} + +func TestFunctionInstance(t *testing.T) { + ftype := NewFunctionType( + []*ValType{NewValTypeI32()}, + []*ValType{NewValTypeI32(), NewValTypeI32()}) + fn := NewFunction(ftype, func(data interface{}, frame *CallingFrame, params []interface{}) ([]interface{}, Result) { + v := params[0].(int32) + return []interface{}{v, v + 1}, Result_Success + }, nil, 0) + ftype.Release() + if fn == nil { + t.Fatal("NewFunction() returned nil") + } + defer fn.Release() + + got := fn.GetFunctionType() + if got.GetParametersLength() != 1 || got.GetReturnsLength() != 2 { + t.Error("function type mismatch") + } + + if NewFunction(nil, nil, nil, 0) != nil { + t.Error("NewFunction(nil type) should return nil") + } +} + +func TestTableInstance(t *testing.T) { + tlim := NewLimitWithMax(4, 8) + ttype := NewTableType(NewValTypeFuncRef(), tlim) + tlim.Release() + tab := NewTable(ttype) + ttype.Release() + if tab == nil { + t.Fatal("NewTable() returned nil") + } + defer tab.Release() + + if tab.GetSize() != 4 { + t.Errorf("table size = %d, want 4", tab.GetSize()) + } + lim := tab.GetTableType().GetLimit() + if lim.GetMin() != 4 || lim.GetMax() != 8 { + t.Errorf("table type limit mismatch: %+v", lim) + } + + if err := tab.Grow(3); err != nil { + t.Errorf("Grow(3) failed: %v", err) + } + if tab.GetSize() != 7 { + t.Errorf("table size after grow = %d, want 7", tab.GetSize()) + } + if err := tab.Grow(10); err == nil { + t.Error("growing beyond the max should fail") + } + + // Uninitialized slots hold null funcref values. + data, err := tab.GetData(0) + if err != nil { + t.Fatalf("GetData(0) failed: %v", err) + } + if fref, ok := data.(FuncRef); !ok || !fref.IsNull() { + t.Errorf("uninitialized slot should be a null funcref, got %T", data) + } + if _, err := tab.GetData(100); err == nil { + t.Error("out-of-bounds access should fail") + } + if err := tab.SetData(int32(1), 0); err == nil { + t.Error("setting a non-reference value should fail") + } +} + +func TestMemoryInstance(t *testing.T) { + mlim := NewLimitWithMax(1, 3) + mtype := NewMemoryType(mlim) + mlim.Release() + mem := NewMemory(mtype) + mtype.Release() + if mem == nil { + t.Fatal("NewMemory() returned nil") + } + defer mem.Release() + + if mem.GetPageSize() != 1 { + t.Errorf("page size = %d, want 1", mem.GetPageSize()) + } + + payload := []byte("wasmedge-go") + if err := mem.SetData(payload, 100, uint(len(payload))); err != nil { + t.Fatalf("SetData failed: %v", err) + } + got, err := mem.GetData(100, uint(len(payload))) + if err != nil { + t.Fatalf("GetData failed: %v", err) + } + if !bytes.Equal(got, payload) { + t.Errorf("GetData = %q, want %q", got, payload) + } + + // GetData returns a view into the WASM memory: writes through it are + // visible on subsequent reads. + got[0] = 'W' + again, err := mem.GetData(100, 1) + if err != nil { + t.Fatal(err) + } + if again[0] != 'W' { + t.Error("GetData should be a view into the linear memory") + } + + if err := mem.GrowPage(1); err != nil { + t.Errorf("GrowPage(1) failed: %v", err) + } + if mem.GetPageSize() != 2 { + t.Errorf("page size after grow = %d, want 2", mem.GetPageSize()) + } + if err := mem.GrowPage(5); err == nil { + t.Error("growing beyond the max should fail") + } + if _, err := mem.GetData(65536*2-1, 2); err == nil { + t.Error("out-of-bounds GetData should fail") + } + if err := mem.SetData(payload, 65536*2-1, uint(len(payload))); err == nil { + t.Error("out-of-bounds SetData should fail") + } +} + +func TestGlobalInstance(t *testing.T) { + gtype := NewGlobalType(NewValTypeI64(), ValMut_Var) + glob := NewGlobal(gtype, int64(1000)) + gtype.Release() + if glob == nil { + t.Fatal("NewGlobal() returned nil") + } + defer glob.Release() + + if glob.GetValue().(int64) != 1000 { + t.Errorf("global value = %v, want 1000", glob.GetValue()) + } + if err := glob.SetValue(int64(-42)); err != nil { + t.Errorf("SetValue failed: %v", err) + } + if glob.GetValue().(int64) != -42 { + t.Errorf("global value = %v, want -42", glob.GetValue()) + } + if err := glob.SetValue(int32(1)); err == nil { + t.Error("setting a value of the wrong type should fail") + } + + ctype := NewGlobalType(NewValTypeI32(), ValMut_Const) + cglob := NewGlobal(ctype, int32(7)) + ctype.Release() + defer cglob.Release() + if err := cglob.SetValue(int32(8)); err == nil { + t.Error("setting a const global should fail") + } +} + +func TestWasiModule(t *testing.T) { + wasi := NewWasiModule( + []string{"prog", "arg1"}, + []string{"KEY=VALUE"}, + []string{".:."}) + if wasi == nil { + t.Fatal("NewWasiModule() returned nil") + } + defer wasi.Release() + + if wasi.GetName() != "wasi_snapshot_preview1" { + t.Errorf("WASI module name = %q", wasi.GetName()) + } + if len(wasi.ListFunction()) == 0 { + t.Error("WASI module should export functions") + } + wasi.InitWasi([]string{"prog"}, []string{}, []string{}) + + wasiFds := NewWasiModuleWithFds([]string{"prog"}, nil, nil, 0, 1, 2) + if wasiFds == nil { + t.Fatal("NewWasiModuleWithFds() returned nil") + } + defer wasiFds.Release() + wasiFds.InitWasiWithFds([]string{"prog"}, nil, nil, 0, 1, 2) +} diff --git a/wasmedge/limit_test.go b/wasmedge/limit_test.go index 9a4012a2..830a4bba 100644 --- a/wasmedge/limit_test.go +++ b/wasmedge/limit_test.go @@ -8,15 +8,113 @@ const ( func TestNewLimit(t *testing.T) { l := NewLimit(minVal) + if l == nil { + t.Fatal("NewLimit() returned nil") + } + defer l.Release() if l.GetMin() != minVal { t.Fatal("wrong min value") } if l.HasMax() { t.Fatal("should have no max value") } + if l.IsShared() { + t.Fatal("should not be shared") + } + if l.Is64Bit() { + t.Fatal("should not be 64-bit") + } - l = NewLimitWithMax(minVal, minVal*2) - if !l.HasMax() { + lmax := NewLimitWithMax(minVal, minVal*2) + if lmax == nil { + t.Fatal("NewLimitWithMax() returned nil") + } + defer lmax.Release() + if !lmax.HasMax() { t.Fatal("should have max value") } + if lmax.GetMax() != minVal*2 { + t.Fatal("wrong max value") + } + + if NewLimitWithMax(minVal, minVal-1) != nil { + t.Fatal("max < min should be rejected") + } +} + +func TestNewLimitShared(t *testing.T) { + l := NewLimitSharedWithMax(minVal, minVal*2) + if l == nil { + t.Fatal("NewLimitSharedWithMax() returned nil") + } + defer l.Release() + if !l.IsShared() || !l.HasMax() { + t.Fatal("shared limit with max expected") + } + if NewLimitSharedWithMax(minVal, minVal-1) != nil { + t.Fatal("max < min should be rejected") + } +} + +func TestNewLimit64(t *testing.T) { + l := NewLimit64(minVal) + if l == nil { + t.Fatal("NewLimit64() returned nil") + } + defer l.Release() + if !l.Is64Bit() { + t.Fatal("should be 64-bit") + } + if l.HasMax() { + t.Fatal("should have no max value") + } + + lmax := NewLimit64WithMax(minVal, minVal*4) + if lmax == nil { + t.Fatal("NewLimit64WithMax() returned nil") + } + defer lmax.Release() + if !lmax.Is64Bit() || !lmax.HasMax() || lmax.GetMax() != minVal*4 { + t.Fatal("wrong 64-bit limit with max") + } + + lshared := NewLimit64SharedWithMax(minVal, minVal*4) + if lshared == nil { + t.Fatal("NewLimit64SharedWithMax() returned nil") + } + defer lshared.Release() + if !lshared.Is64Bit() || !lshared.IsShared() || !lshared.HasMax() { + t.Fatal("wrong 64-bit shared limit") + } + + if NewLimit64WithMax(minVal, minVal-1) != nil || + NewLimit64SharedWithMax(minVal, minVal-1) != nil { + t.Fatal("max < min should be rejected") + } +} + +func TestLimitIsEqual(t *testing.T) { + l1 := NewLimitWithMax(minVal, minVal*2) + defer l1.Release() + l2 := NewLimitWithMax(minVal, minVal*2) + defer l2.Release() + l3 := NewLimitWithMax(minVal, minVal*3) + defer l3.Release() + l4 := NewLimit64WithMax(minVal, minVal*2) + defer l4.Release() + l5 := NewLimitSharedWithMax(minVal, minVal*2) + defer l5.Release() + + if !l1.IsEqual(l2) { + t.Error("limits with the same values should be equal") + } + if l1.IsEqual(l3) { + t.Error("limits with different max values should not be equal") + } + if l1.IsEqual(l4) { + t.Error("32-bit and 64-bit limits should not be equal") + } + if l1.IsEqual(l5) { + t.Error("shared and unshared limits should not be equal") + } } diff --git a/wasmedge/log_test.go b/wasmedge/log_test.go new file mode 100644 index 00000000..bb1804ec --- /dev/null +++ b/wasmedge/log_test.go @@ -0,0 +1,21 @@ +package wasmedge + +import "testing" + +func TestLogLevels(t *testing.T) { + // The log APIs have no observable state to read back; they must simply + // not crash for every level. + for _, level := range []LogLevel{ + LogLevel_Trace, + LogLevel_Debug, + LogLevel_Info, + LogLevel_Warn, + LogLevel_Error, + LogLevel_Critical, + } { + SetLogLevel(level) + } + SetLogDebugLevel() + SetLogErrorLevel() + SetLogOff() +} diff --git a/wasmedge/plugin_test.go b/wasmedge/plugin_test.go new file mode 100644 index 00000000..60070d10 --- /dev/null +++ b/wasmedge/plugin_test.go @@ -0,0 +1,23 @@ +package wasmedge + +import "testing" + +func TestPlugin(t *testing.T) { + // No plug-in is guaranteed to be installed in the test environment; the + // APIs must behave gracefully either way. + LoadPluginDefaultPaths() + plugins := ListPlugins() + t.Logf("found plug-ins: %v", plugins) + + if FindPlugin("no_such_plugin") != nil { + t.Error("FindPlugin on an unknown name should return nil") + } + for _, name := range plugins { + plugin := FindPlugin(name) + if plugin == nil { + t.Errorf("FindPlugin(%q) should not return nil", name) + continue + } + t.Logf("plug-in %q modules: %v", name, plugin.ListModule()) + } +} diff --git a/wasmedge/result_test.go b/wasmedge/result_test.go new file mode 100644 index 00000000..f3773d9a --- /dev/null +++ b/wasmedge/result_test.go @@ -0,0 +1,42 @@ +package wasmedge + +import "testing" + +func TestResult(t *testing.T) { + if Result_Success.Error() != "success" { + t.Errorf("success message = %q", Result_Success.Error()) + } + if Result_Terminate.Error() != "terminated" { + t.Errorf("terminated message = %q", Result_Terminate.Error()) + } + + res := NewResult(ErrCategory_UserLevel, 5958) + if res.GetErrorCategory() != ErrCategory_UserLevel { + t.Errorf("category = %d, want user-level", res.GetErrorCategory()) + } + if res.GetCode() != 5958 { + t.Errorf("code = %d, want 5958", res.GetCode()) + } + + wasmres := NewResult(ErrCategory_WASM, 1) + if wasmres.GetErrorCategory() != ErrCategory_WASM { + t.Errorf("category = %d, want WASM", wasmres.GetErrorCategory()) + } +} + +func TestResultFromExecution(t *testing.T) { + vm := NewVM() + defer vm.Release() + + _, err := vm.RunWasmFile(testWasmPath("trap.wasm"), "trap") + if err == nil { + t.Fatal("trap should fail") + } + res := err.(*Result) + if res.GetErrorCategory() != ErrCategory_WASM { + t.Error("trap should be a WASM-category error") + } + if res.Error() != "unreachable" { + t.Errorf("trap message = %q, want \"unreachable\"", res.Error()) + } +} diff --git a/wasmedge/statistics_test.go b/wasmedge/statistics_test.go new file mode 100644 index 00000000..740c7875 --- /dev/null +++ b/wasmedge/statistics_test.go @@ -0,0 +1,54 @@ +package wasmedge + +import "testing" + +func TestStatistics(t *testing.T) { + conf := NewConfigure() + defer conf.Release() + conf.SetStatisticsInstructionCounting(true) + conf.SetStatisticsTimeMeasuring(true) + conf.SetStatisticsCostMeasuring(true) + + stat := NewStatistics() + if stat == nil { + t.Fatal("NewStatistics() returned nil") + } + defer stat.Release() + + costtable := make([]uint64, 512) + for i := range costtable { + costtable[i] = 1 + } + stat.SetCostTable(costtable) + stat.SetCostLimit(1000000) + + store := NewStore() + defer store.Release() + executor := NewExecutorWithConfigAndStatistics(conf, stat) + if executor == nil { + t.Fatal("NewExecutorWithConfigAndStatistics() returned nil") + } + defer executor.Release() + + mod := instantiateFile(t, executor, store, testWasmPath("fib.wasm")) + defer mod.Release() + + if _, err := executor.Invoke(mod.FindFunction("fib"), int32(10)); err != nil { + t.Fatalf("Invoke failed: %v", err) + } + if stat.GetInstrCount() == 0 { + t.Error("instruction count should be positive") + } + if stat.GetInstrPerSecond() <= 0 { + t.Error("instructions per second should be positive") + } + if stat.GetTotalCost() == 0 { + t.Error("total cost should be positive") + } + + // A tiny cost limit interrupts the execution. + stat.SetCostLimit(1) + if _, err := executor.Invoke(mod.FindFunction("fib"), int32(20)); err == nil { + t.Error("execution should fail when exceeding the cost limit") + } +} diff --git a/wasmedge/store_test.go b/wasmedge/store_test.go new file mode 100644 index 00000000..78c1e341 --- /dev/null +++ b/wasmedge/store_test.go @@ -0,0 +1,41 @@ +package wasmedge + +import "testing" + +func TestStore(t *testing.T) { + store := NewStore() + if store == nil { + t.Fatal("NewStore() returned nil") + } + defer store.Release() + + if mods := store.ListModule(); len(mods) != 0 { + t.Errorf("a new store should be empty, got %v", mods) + } + if store.FindModule("anything") != nil { + t.Error("FindModule on an empty store should return nil") + } + + executor := NewExecutor() + defer executor.Release() + ast := loadASTFromFile(t, testWasmPath("fib.wasm")) + defer ast.Release() + validator := NewValidator() + defer validator.Release() + if err := validator.Validate(ast); err != nil { + t.Fatal(err) + } + mod, err := executor.Register(store, ast, "math") + if err != nil { + t.Fatal(err) + } + defer mod.Release() + + mods := store.ListModule() + if len(mods) != 1 || mods[0] != "math" { + t.Errorf("ListModule() = %v, want [math]", mods) + } + if store.FindModule("math") == nil { + t.Error("FindModule(math) should not return nil") + } +} diff --git a/wasmedge/testdata/fib.wasm b/wasmedge/testdata/fib.wasm new file mode 100644 index 0000000000000000000000000000000000000000..68dfac98109a63d34f88724647886d12e483edb2 GIT binary patch literal 61 zcmZQbEY4+QU|?WmV@zPIXRK#tVq{=vXJk&xOk!Z*l4F!%P+)Lm@?fcVWMl=gvIRf_ Kj6f=jn;QW66bI=5 literal 0 HcmV?d00001 diff --git a/wasmedge/testdata/fib.wat b/wasmedge/testdata/fib.wat new file mode 100644 index 00000000..714e734c --- /dev/null +++ b/wasmedge/testdata/fib.wat @@ -0,0 +1,8 @@ +(module + (func $fib (export "fib") (param i32) (result i32) + (if (result i32) (i32.lt_s (local.get 0) (i32.const 2)) + (then (i32.const 1)) + (else + (i32.add + (call $fib (i32.sub (local.get 0) (i32.const 2))) + (call $fib (i32.sub (local.get 0) (i32.const 1)))))))) diff --git a/wasmedge/testdata/invalid.wasm b/wasmedge/testdata/invalid.wasm new file mode 100644 index 0000000000000000000000000000000000000000..8ecabd097102eabbfe2891b3c2ff82970ec08362 GIT binary patch literal 34 pcmZQbEY4+QU|?WmWlUgTtY>CoWMF4!WKK#42hOA|{ih@HE1bJoept0cixD8x22tq2`*Bk$sY0ycJedEh1OpCBUC zLSew5;NX&i!h%Jy5D>DRAh3+*H&L|jsU3US8KV3#_xB_mIxqX#TDe_f`RjbSrj-@m fSv^T@4DtO*aB8UhN38m8Jg$sYgIL86Vol`_8D=7O literal 0 HcmV?d00001 diff --git a/wasmedge/testdata/refs.wat b/wasmedge/testdata/refs.wat new file mode 100644 index 00000000..7d0b285c --- /dev/null +++ b/wasmedge/testdata/refs.wat @@ -0,0 +1,12 @@ +(module + (func (export "extern_id") (param externref) (result externref) + (local.get 0)) + (func (export "func_id") (param funcref) (result funcref) + (local.get 0)) + (func (export "is_null_extern") (param externref) (result i32) + (ref.is_null (local.get 0))) + (func (export "v128_id") (param v128) (result v128) + (local.get 0)) + (func (export "splat_add") (param i32 i32) (result i32) + (i32x4.extract_lane 0 + (i32x4.add (i32x4.splat (local.get 0)) (i32x4.splat (local.get 1)))))) diff --git a/wasmedge/testdata/trap.wasm b/wasmedge/testdata/trap.wasm new file mode 100644 index 0000000000000000000000000000000000000000..5dae3c35769d32e4590aeb208e98019363699374 GIT binary patch literal 56 zcmZQbEY4+QU|?Y6VoG3ONMNe3XRK#tW@2Du=VM|iDM~D0U|>$kECb5(GBGnSaI-Tg KFeotQasvSE$OoAK literal 0 HcmV?d00001 diff --git a/wasmedge/testdata/trap.wat b/wasmedge/testdata/trap.wat new file mode 100644 index 00000000..91c11a40 --- /dev/null +++ b/wasmedge/testdata/trap.wat @@ -0,0 +1,5 @@ +(module + (func (export "trap") + (unreachable)) + (func (export "div") (param i32 i32) (result i32) + (i32.div_s (local.get 0) (local.get 1)))) diff --git a/wasmedge/testdata/types.wasm b/wasmedge/testdata/types.wasm new file mode 100644 index 0000000000000000000000000000000000000000..c7e2b86e7f792a3dafc4a59d3e5285baaa2505c0 GIT binary patch literal 169 zcmW-ZK@Ng26b0Y=zfiCn7bb2op1>pMMW6_Q7%C+ zMmdT0&v!A-%Ub)c12!#_4%6Ifgc|)vCgY3QAu}W;xBT$-g|nAjw~EExPg5F5IrM8i iZZT9>-x3=7ATa62(h^rVa(7gV3Kbu&NZi92oZ)_|Y9AN? literal 0 HcmV?d00001 diff --git a/wasmedge/testdata/types.wat b/wasmedge/testdata/types.wat new file mode 100644 index 00000000..93c2e539 --- /dev/null +++ b/wasmedge/testdata/types.wat @@ -0,0 +1,13 @@ +(module + (import "env" "host_add" (func $host_add (param i32 i32) (result i32))) + (import "env" "host_glob" (global $hg i32)) + (func $add (export "add") (param i32 i32) (result i32) + (i32.add (local.get 0) (local.get 1))) + (func (export "call_add") (param i32 i32) (result i32) + (call $host_add (local.get 0) (local.get 1))) + (func (export "get_hglob") (result i32) + (global.get $hg)) + (table (export "tab") 5 20 funcref) + (elem (i32.const 0) $add) + (memory (export "mem") 1 2) + (global (export "glob") (mut i64) (i64.const 88))) diff --git a/wasmedge/testdata/wasi_hello.wasm b/wasmedge/testdata/wasi_hello.wasm new file mode 100644 index 0000000000000000000000000000000000000000..e243185decb591055a906da8cdebf92be028fe02 GIT binary patch literal 177 zcmZ{aI}XAy6a@FZ1OrKmNPG$!#1Uxd-Ea-Z0;5<;uw`2WDqo#&0Ja&8W})Lq0H`gx zGS8#jQAP*wmG_g5R>i0Gv3E)NU|!Zt=hfq`reKo+{yf$`xSKL>n?MB +/* +#include + +// Convert the external reference payload between the Go-side index and the +// pointer-typed C API. The index is never dereferenced; 0 is ref.null. +static WasmEdge_Value wasmedgego_GenExternRef(uintptr_t Idx) { + return WasmEdge_ValueGenExternRef((void *)Idx); +} +static uintptr_t wasmedgego_GetExternRef(WasmEdge_Value Val) { + return (uintptr_t)WasmEdge_ValueGetExternRef(Val); +} +*/ import "C" import ( "encoding/binary" @@ -156,6 +167,13 @@ func (self *externRefManager) get(i uint) interface{} { return self.ref[i] } +func (self *externRefManager) has(i uint) bool { + self.mu.Lock() + defer self.mu.Unlock() + _, ok := self.ref[i] + return ok +} + func (self *externRefManager) del(i uint) { self.mu.Lock() defer self.mu.Unlock() @@ -197,12 +215,11 @@ type ExternRef struct { } func NewExternRef(ptr interface{}) ExternRef { - // Gen an i64 WasmEdge_Value and change type to externref - idx := uint64(externRefMgr.add(ptr)) - val := C.WasmEdge_ValueGenI64(C.int64_t(idx)) - val.Type = C.WasmEdge_ValTypeGenExternRef() + // The external reference value holds the index into the Go-side + // reference manager instead of a real pointer. + idx := externRefMgr.add(ptr) return ExternRef{ - _inner: val, + _inner: C.wasmedgego_GenExternRef(C.uintptr_t(idx)), _valid: true, } } @@ -213,15 +230,13 @@ func (self ExternRef) IsNull() bool { func (self ExternRef) Release() { self._valid = false - // Change type back to WasmEdge_ValType_I64 and get the i64 value - idx := uint(C.WasmEdge_ValueGetI64(self._inner)) + idx := uint(C.wasmedgego_GetExternRef(self._inner)) externRefMgr.del(idx) } func (self ExternRef) GetRef() interface{} { if self._valid { - // Get the original i64 value - idx := uint(C.WasmEdge_ValueGetI64(self._inner)) + idx := uint(C.wasmedgego_GetExternRef(self._inner)) return externRefMgr.get(idx) } return nil @@ -266,10 +281,11 @@ func toWasmEdgeValue(value interface{}) C.WasmEdge_Value { case FuncRef: return value.(FuncRef)._inner case ExternRef: - if !value.(ExternRef)._valid { + ref := value.(ExternRef) + if !ref._valid || !externRefMgr.has(uint(C.wasmedgego_GetExternRef(ref._inner))) { panic("External reference is released") } - return value.(ExternRef)._inner + return ref._inner case Ref: return value.(Ref)._inner case V128: @@ -323,8 +339,8 @@ func fromWasmEdgeValue(value C.WasmEdge_Value) interface{} { return FuncRef{_inner: value} } if C.WasmEdge_ValTypeIsExternRef(value.Type) { - idx := uint(C.WasmEdge_ValueGetI64(value)) - if _, ok := externRefMgr.ref[idx]; ok { + idx := uint(C.wasmedgego_GetExternRef(value)) + if externRefMgr.has(idx) { return ExternRef{_inner: value, _valid: true} } return ExternRef{_inner: value, _valid: false} diff --git a/wasmedge/value_test.go b/wasmedge/value_test.go new file mode 100644 index 00000000..5c81004d --- /dev/null +++ b/wasmedge/value_test.go @@ -0,0 +1,193 @@ +package wasmedge + +import "testing" + +func TestValTypes(t *testing.T) { + cases := []struct { + vt *ValType + str string + want func(*ValType) bool + }{ + {NewValTypeI32(), "i32", (*ValType).IsI32}, + {NewValTypeI64(), "i64", (*ValType).IsI64}, + {NewValTypeF32(), "f32", (*ValType).IsF32}, + {NewValTypeF64(), "f64", (*ValType).IsF64}, + {NewValTypeV128(), "v128", (*ValType).IsV128}, + {NewValTypeFuncRef(), "funcref", (*ValType).IsFuncRef}, + {NewValTypeExternRef(), "externref", (*ValType).IsExternRef}, + } + for _, c := range cases { + if !c.want(c.vt) { + t.Errorf("predicate for %q returned false", c.str) + } + if c.vt.String() != c.str { + t.Errorf("String() = %q, want %q", c.vt.String(), c.str) + } + if !c.vt.IsEqual(c.vt) { + t.Errorf("%q should be equal to itself", c.str) + } + } + if NewValTypeI32().IsEqual(NewValTypeI64()) { + t.Error("i32 should not equal i64") + } + if !NewValTypeFuncRef().IsRef() || !NewValTypeExternRef().IsRef() { + t.Error("funcref/externref should be reference types") + } + if NewValTypeI32().IsRef() { + t.Error("i32 should not be a reference type") + } + if !NewValTypeFuncRef().IsRefNull() { + t.Error("plain funcref should be nullable") + } +} + +func TestValMut(t *testing.T) { + if ValMut_Const.String() != "const" || ValMut_Var.String() != "var" { + t.Error("wrong ValMut strings") + } +} + +func TestV128(t *testing.T) { + const high, low = uint64(0x0123456789abcdef), uint64(0xfedcba9876543210) + val := NewV128(high, low) + gotHigh, gotLow := val.GetVal() + if gotHigh != high || gotLow != low { + t.Errorf("V128 round-trip mismatch: got (%x, %x), want (%x, %x)", + gotHigh, gotLow, high, low) + } +} + +func TestV128ThroughWasm(t *testing.T) { + vm := NewVM() + defer vm.Release() + + const high, low = uint64(0xdeadbeefcafebabe), uint64(0x0102030405060708) + rets, err := vm.RunWasmFile(testWasmPath("refs.wasm"), "v128_id", NewV128(high, low)) + if err != nil { + t.Fatalf("v128_id failed: %v", err) + } + got, ok := rets[0].(V128) + if !ok { + t.Fatalf("v128_id returned %T, want V128", rets[0]) + } + gotHigh, gotLow := got.GetVal() + if gotHigh != high || gotLow != low { + t.Errorf("v128 through wasm mismatch: got (%x, %x)", gotHigh, gotLow) + } + + rets, err = vm.Execute("splat_add", int32(30), int32(12)) + if err != nil { + t.Fatalf("splat_add failed: %v", err) + } + if rets[0].(int32) != 42 { + t.Errorf("splat_add = %v, want 42", rets[0]) + } +} + +func TestExternRef(t *testing.T) { + vm := NewVM() + defer vm.Release() + + type payload struct{ answer int } + data := &payload{answer: 42} + ref := NewExternRef(data) + + rets, err := vm.RunWasmFile(testWasmPath("refs.wasm"), "extern_id", ref) + if err != nil { + t.Fatalf("extern_id failed: %v", err) + } + got, ok := rets[0].(ExternRef) + if !ok { + t.Fatalf("extern_id returned %T, want ExternRef", rets[0]) + } + if got.IsNull() { + t.Error("returned externref should not be null") + } + if got.GetRef().(*payload).answer != 42 { + t.Error("externref payload mismatch") + } + + rets, err = vm.Execute("is_null_extern", ref) + if err != nil { + t.Fatalf("is_null_extern failed: %v", err) + } + if rets[0].(int32) != 0 { + t.Error("live externref should not be ref.null") + } + + // After releasing, the reference cannot be used as an argument anymore. + ref.Release() + if ref.GetRef() != nil { + t.Error("released externref should return nil") + } + func() { + defer func() { + if recover() == nil { + t.Error("using a released externref should panic") + } + }() + _, _ = vm.Execute("extern_id", ref) + }() +} + +func TestFuncRef(t *testing.T) { + // Instantiate types.wasm which exports a funcref table with slot 0 + // initialized and the other slots null. + conf := NewConfigure() + defer conf.Release() + store := NewStore() + defer store.Release() + executor := NewExecutorWithConfig(conf) + defer executor.Release() + + env := buildEnvModule(t, 666) + defer env.Release() + if err := executor.RegisterImport(store, env); err != nil { + t.Fatalf("RegisterImport failed: %v", err) + } + mod := instantiateFile(t, executor, store, testWasmPath("types.wasm")) + defer mod.Release() + + tab := mod.FindTable("tab") + if tab == nil { + t.Fatal("table export not found") + } + + data, err := tab.GetData(0) + if err != nil { + t.Fatalf("Table.GetData(0) failed: %v", err) + } + fref, ok := data.(FuncRef) + if !ok { + t.Fatalf("table slot 0 is %T, want FuncRef", data) + } + if fref.IsNull() { + t.Error("table slot 0 should hold a non-null funcref") + } + fn := fref.GetRef() + if fn == nil { + t.Fatal("funcref should reference a function instance") + } + rets, err := executor.Invoke(fn, int32(20), int32(22)) + if err != nil { + t.Fatalf("invoking table function failed: %v", err) + } + if rets[0].(int32) != 42 { + t.Errorf("table function = %v, want 42", rets[0]) + } + + data, err = tab.GetData(1) + if err != nil { + t.Fatalf("Table.GetData(1) failed: %v", err) + } + fref, ok = data.(FuncRef) + if !ok { + t.Fatalf("table slot 1 is %T, want FuncRef", data) + } + if !fref.IsNull() { + t.Error("table slot 1 should be a null funcref") + } + if fref.GetRef() != nil { + t.Error("null funcref should have no function instance") + } +} diff --git a/wasmedge/version_test.go b/wasmedge/version_test.go new file mode 100644 index 00000000..2a6c660f --- /dev/null +++ b/wasmedge/version_test.go @@ -0,0 +1,22 @@ +package wasmedge + +import ( + "fmt" + "strings" + "testing" +) + +func TestVersion(t *testing.T) { + version := GetVersion() + if version == "" { + t.Fatal("GetVersion() returned an empty string") + } + if GetVersionMajor() != 0 || GetVersionMinor() != 17 { + t.Errorf("unexpected version %d.%d, the bindings target WasmEdge 0.17.x", + GetVersionMajor(), GetVersionMinor()) + } + prefix := fmt.Sprintf("%d.%d.%d", GetVersionMajor(), GetVersionMinor(), GetVersionPatch()) + if !strings.HasPrefix(version, prefix) { + t.Errorf("GetVersion() = %q does not start with %q", version, prefix) + } +} diff --git a/wasmedge/vm.go b/wasmedge/vm.go index 71baa403..1d48c9f7 100644 --- a/wasmedge/vm.go +++ b/wasmedge/vm.go @@ -96,6 +96,8 @@ func (self *VM) RegisterModuleWithAlias(modname string, module *Module) error { return nil } +// ForceDeleteRegisteredModule deletes the registered module by name and +// destroys its instance; do not Release any Go wrapper of it afterwards. func (self *VM) ForceDeleteRegisteredModule(modname string) { modstr := toWasmEdgeStringWrap(modname) C.WasmEdge_VMForceDeleteRegisteredModule(self._inner, modstr) diff --git a/wasmedge/vm_test.go b/wasmedge/vm_test.go new file mode 100644 index 00000000..c8a8e395 --- /dev/null +++ b/wasmedge/vm_test.go @@ -0,0 +1,313 @@ +package wasmedge + +import ( + "os" + "strings" + "testing" +) + +// asyncLoopWasm is a module exporting "_start" which loops forever. It is used +// for testing the cancellation of asynchronous executions. +var asyncLoopWasm = []byte{ + 0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x04, 0x01, 0x60, + 0x00, 0x00, 0x03, 0x02, 0x01, 0x00, 0x05, 0x03, 0x01, 0x00, 0x01, 0x07, + 0x0a, 0x01, 0x06, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x00, 0x0a, + 0x09, 0x01, 0x07, 0x00, 0x03, 0x40, 0x0c, 0x00, 0x0b, 0x0b, +} + +func TestVMRunWasm(t *testing.T) { + vm := NewVM() + if vm == nil { + t.Fatal("NewVM() returned nil") + } + defer vm.Release() + + rets, err := vm.RunWasmFile(testWasmPath("fib.wasm"), "fib", int32(10)) + if err != nil { + t.Fatalf("RunWasmFile failed: %v", err) + } + if rets[0].(int32) != 89 { + t.Errorf("fib(10) = %v, want 89", rets[0]) + } + + buf, err := os.ReadFile(testWasmPath("fib.wasm")) + if err != nil { + t.Fatal(err) + } + rets, err = vm.RunWasmBuffer(buf, "fib", int32(11)) + if err != nil { + t.Fatalf("RunWasmBuffer failed: %v", err) + } + if rets[0].(int32) != 144 { + t.Errorf("fib(11) = %v, want 144", rets[0]) + } + + ast := loadASTFromFile(t, testWasmPath("fib.wasm")) + defer ast.Release() + rets, err = vm.RunWasmAST(ast, "fib", int32(12)) + if err != nil { + t.Fatalf("RunWasmAST failed: %v", err) + } + if rets[0].(int32) != 233 { + t.Errorf("fib(12) = %v, want 233", rets[0]) + } +} + +func TestVMStepByStep(t *testing.T) { + vm := NewVM() + defer vm.Release() + + // Executing before instantiation is a workflow error. + if _, err := vm.Execute("fib", int32(5)); err == nil { + t.Error("Execute before instantiation should fail") + } + + if err := vm.LoadWasmFile(testWasmPath("fib.wasm")); err != nil { + t.Fatalf("LoadWasmFile failed: %v", err) + } + if err := vm.Validate(); err != nil { + t.Fatalf("Validate failed: %v", err) + } + if err := vm.Instantiate(); err != nil { + t.Fatalf("Instantiate failed: %v", err) + } + rets, err := vm.Execute("fib", int32(13)) + if err != nil { + t.Fatalf("Execute failed: %v", err) + } + if rets[0].(int32) != 377 { + t.Errorf("fib(13) = %v, want 377", rets[0]) + } + + // Unknown function. + if _, err := vm.Execute("no_such_func"); err == nil { + t.Error("executing an unknown function should fail") + } + + // Function list and type queries. + names, types := vm.GetFunctionList() + if len(names) != 1 || names[0] != "fib" || len(types) != 1 { + t.Errorf("GetFunctionList() = %v", names) + } + if vm.GetFunctionType("fib") == nil { + t.Error("GetFunctionType(fib) should not be nil") + } + if vm.GetFunctionType("nope") != nil { + t.Error("GetFunctionType(nope) should be nil") + } + if vm.GetActiveModule() == nil { + t.Error("active module should exist after instantiation") + } + + vm.Cleanup() + if vm.GetActiveModule() != nil { + t.Error("active module should be gone after Cleanup") + } +} + +func TestVMRegisteredModule(t *testing.T) { + vm := NewVM() + defer vm.Release() + + if err := vm.RegisterWasmFile("math", testWasmPath("fib.wasm")); err != nil { + t.Fatalf("RegisterWasmFile failed: %v", err) + } + rets, err := vm.ExecuteRegistered("math", "fib", int32(10)) + if err != nil { + t.Fatalf("ExecuteRegistered failed: %v", err) + } + if rets[0].(int32) != 89 { + t.Errorf("math.fib(10) = %v, want 89", rets[0]) + } + if vm.GetFunctionTypeRegistered("math", "fib") == nil { + t.Error("GetFunctionTypeRegistered should find math.fib") + } + if vm.GetRegisteredModule("math") == nil { + t.Error("GetRegisteredModule should find math") + } + + buf, err := os.ReadFile(testWasmPath("memops.wasm")) + if err != nil { + t.Fatal(err) + } + if err := vm.RegisterWasmBuffer("memops", buf); err != nil { + t.Fatalf("RegisterWasmBuffer failed: %v", err) + } + + ast := loadASTFromFile(t, testWasmPath("trap.wasm")) + defer ast.Release() + if err := vm.RegisterAST("trapmod", ast); err != nil { + t.Fatalf("RegisterAST failed: %v", err) + } + + // Plug-in provided modules may be auto-registered into the VM as well, so + // only check that the explicitly registered modules are present. + registered := map[string]bool{} + for _, name := range vm.ListRegisteredModule() { + registered[name] = true + } + for _, name := range []string{"math", "memops", "trapmod"} { + if !registered[name] { + t.Errorf("module %q missing from ListRegisteredModule()", name) + } + } + + if _, err := vm.ExecuteRegistered("trapmod", "trap"); err == nil { + t.Error("registered trap function should fail") + } + if _, err := vm.ExecuteRegistered("ghost", "fib", int32(1)); err == nil { + t.Error("executing in an unregistered module should fail") + } +} + +func TestVMRegisterHostModule(t *testing.T) { + vm := NewVM() + defer vm.Release() + + env := buildEnvModule(t, 12321) + defer env.Release() + if err := vm.RegisterModule(env); err != nil { + t.Fatalf("RegisterModule failed: %v", err) + } + rets, err := vm.RunWasmFile(testWasmPath("types.wasm"), "get_hglob") + if err != nil { + t.Fatalf("get_hglob failed: %v", err) + } + if rets[0].(int32) != 12321 { + t.Errorf("get_hglob = %v, want 12321", rets[0]) + } +} + +func TestVMRegisterModuleWithAlias(t *testing.T) { + vm := NewVM() + defer vm.Release() + + env := buildEnvModule(t, 777) + defer env.Release() + + // Register the module under an alias different from its own name. + if err := vm.RegisterModuleWithAlias("aliased_env", env); err != nil { + t.Fatalf("RegisterModuleWithAlias failed: %v", err) + } + if vm.GetRegisteredModule("aliased_env") == nil { + t.Error("module should be registered under the alias") + } + rets, err := vm.ExecuteRegistered("aliased_env", "host_add", int32(2), int32(3)) + if err != nil { + t.Fatalf("aliased host_add failed: %v", err) + } + if rets[0].(int32) != 5 { + t.Errorf("aliased host_add = %v, want 5", rets[0]) + } +} + +func TestVMForceDeleteRegisteredModule(t *testing.T) { + vm := NewVM() + defer vm.Release() + + // ForceDeleteRegisteredModule destroys the module instance, so the Go + // wrapper must not be released afterwards. + doomed := NewModule("doomed") + gtype := NewGlobalType(NewValTypeI32(), ValMut_Const) + doomed.AddGlobal("g", NewGlobal(gtype, int32(1))) + gtype.Release() + if err := vm.RegisterModule(doomed); err != nil { + t.Fatalf("RegisterModule failed: %v", err) + } + if vm.GetRegisteredModule("doomed") == nil { + t.Fatal("module should be registered") + } + + vm.ForceDeleteRegisteredModule("doomed") + if vm.GetRegisteredModule("doomed") != nil { + t.Error("module should be gone after ForceDeleteRegisteredModule") + } + // Deleting a nonexistent module must not crash. + vm.ForceDeleteRegisteredModule("no_such_module") +} + +func TestVMWasi(t *testing.T) { + conf := NewConfigure(WASI) + defer conf.Release() + vm := NewVMWithConfig(conf) + defer vm.Release() + + wasi := vm.GetImportModule(WASI) + if wasi == nil { + t.Fatal("WASI import module not found") + } + wasi.InitWasi([]string{"hello.wasm"}, []string{}, []string{}) + + if _, err := vm.RunWasmFile(testWasmPath("wasi_hello.wasm"), "_start"); err != nil { + t.Fatalf("running the WASI module failed: %v", err) + } + if code := wasi.WasiGetExitCode(); code != 21 { + t.Errorf("WASI exit code = %d, want 21", code) + } +} + +func TestVMWithStoreAndConfig(t *testing.T) { + conf := NewConfigure() + defer conf.Release() + store := NewStore() + defer store.Release() + + for _, vm := range []*VM{ + NewVMWithStore(store), + NewVMWithConfigAndStore(conf, store), + } { + if vm == nil { + t.Fatal("VM creation failed") + } + if vm.GetStore() == nil || vm.GetLoader() == nil || + vm.GetValidator() == nil || vm.GetExecutor() == nil || + vm.GetStatistics() == nil { + t.Error("VM component getters should not return nil") + } + vm.Release() + } +} + +func TestVMAsync(t *testing.T) { + vm := NewVM() + defer vm.Release() + + async := vm.AsyncRunWasmFile(testWasmPath("fib.wasm"), "fib", int32(14)) + if async == nil { + t.Fatal("AsyncRunWasmFile returned nil") + } + async.WaitFor(5000) + rets, err := async.GetResult() + if err != nil { + t.Fatalf("async fib failed: %v", err) + } + if rets[0].(int32) != 610 { + t.Errorf("fib(14) = %v, want 610", rets[0]) + } + async.Release() + + // Load + async execute. + if err := vm.LoadWasmBuffer(asyncLoopWasm); err != nil { + t.Fatal(err) + } + if err := vm.Validate(); err != nil { + t.Fatal(err) + } + if err := vm.Instantiate(); err != nil { + t.Fatal(err) + } + async = vm.AsyncExecute("_start") + if async == nil { + t.Fatal("AsyncExecute returned nil") + } + if async.WaitFor(1) { + t.Error("infinite loop should not finish within 1ms") + } + async.Cancel() + if _, err := async.GetResult(); err == nil { + t.Error("canceled execution should report an error") + } else if !strings.Contains(err.Error(), "interrupt") { + t.Errorf("canceled execution error = %q, want an interruption error", err.Error()) + } + async.Release() +} diff --git a/wasmedge/wasmedge_test.go b/wasmedge/wasmedge_test.go new file mode 100644 index 00000000..e12d861b --- /dev/null +++ b/wasmedge/wasmedge_test.go @@ -0,0 +1,79 @@ +package wasmedge + +import ( + "path/filepath" + "testing" +) + +// testWasmPath returns the path of a fixture assembled from the *.wat +// sources in testdata with wat2wasm. +func testWasmPath(name string) string { + return filepath.Join("testdata", name) +} + +// loadASTFromFile loads and returns the AST of a fixture, failing the test on +// any error. +func loadASTFromFile(t *testing.T, path string) *AST { + t.Helper() + loader := NewLoader() + if loader == nil { + t.Fatal("NewLoader() returned nil") + } + defer loader.Release() + ast, err := loader.LoadFile(path) + if err != nil { + t.Fatalf("LoadFile(%q) failed: %v", path, err) + } + return ast +} + +// buildEnvModule creates the host module matching the imports of +// testdata/types.wasm: the env.host_add function and env.host_glob global. +func buildEnvModule(t *testing.T, globVal int32) *Module { + t.Helper() + mod := NewModule("env") + if mod == nil { + t.Fatal("NewModule() returned nil") + } + + addfn := func(data interface{}, callframe *CallingFrame, params []interface{}) ([]interface{}, Result) { + return []interface{}{params[0].(int32) + params[1].(int32)}, Result_Success + } + ftype := NewFunctionType( + []*ValType{NewValTypeI32(), NewValTypeI32()}, + []*ValType{NewValTypeI32()}) + hostfn := NewFunction(ftype, addfn, nil, 0) + ftype.Release() + if hostfn == nil { + t.Fatal("NewFunction() returned nil") + } + mod.AddFunction("host_add", hostfn) + + gtype := NewGlobalType(NewValTypeI32(), ValMut_Const) + glob := NewGlobal(gtype, globVal) + gtype.Release() + if glob == nil { + t.Fatal("NewGlobal() returned nil") + } + mod.AddGlobal("host_glob", glob) + + return mod +} + +// instantiateFile loads, validates, and instantiates a WASM file into the +// given store, returning the module instance. +func instantiateFile(t *testing.T, executor *Executor, store *Store, path string) *Module { + t.Helper() + ast := loadASTFromFile(t, path) + defer ast.Release() + validator := NewValidator() + defer validator.Release() + if err := validator.Validate(ast); err != nil { + t.Fatalf("Validate(%q) failed: %v", path, err) + } + mod, err := executor.Instantiate(store, ast) + if err != nil { + t.Fatalf("Instantiate(%q) failed: %v", path, err) + } + return mod +} From 11ba9eeb1274901d2a48e7e83217260cc5cd2b19 Mon Sep 17 00:00:00 2001 From: YiYing He Date: Fri, 10 Jul 2026 05:46:24 +0800 Subject: [PATCH 4/5] test: add the WASM spec tests in interpreter, AOT, and JIT modes Add the spectest package which runs the wast2json-converted WASM spec test suites from WasmEdge/wasmedge-spectest (wasm-core-20260322) against the Go bindings, mirroring the WasmEdge C API spec tests: - All suite folders of WasmEdge test/spec except component-model: wasm-1.0/2.0/3.0, the wasm-3.0 proposal folders, and threads (including the thread/wait commands via shared module instances). - Interpreter, AOT (native output per module), and JIT modes; the exception-handling folder runs in interpreter mode only. - The suites are downloaded and cached under spectest/testdata on the first run (override with WASMEDGE_SPECTEST_PATH). Supporting changes in the bindings: - Add NewNullExternRef and support nil in NewFuncRef for null reference values, needed by the suite arguments. - The spec tests re-execute themselves with GODEBUG=asyncpreemptoff=1: the WasmEdge trap handlers are installed without SA_ONSTACK, which the Go runtime rejects when its preemption signal interrupts a compiled-code execution window. All 495 units pass in all enabled modes on macOS arm64 against WasmEdge 0.17.1. Assisted-By: Claude Fable 5 Signed-off-by: YiYing He --- .gitignore | 3 + spectest/README.md | 43 +++ spectest/harness_test.go | 709 +++++++++++++++++++++++++++++++++++++++ spectest/spec_test.go | 339 +++++++++++++++++++ spectest/suite_test.go | 148 ++++++++ wasmedge/value.go | 24 +- wasmedge/value_test.go | 32 ++ 7 files changed, 1293 insertions(+), 5 deletions(-) create mode 100644 spectest/README.md create mode 100644 spectest/harness_test.go create mode 100644 spectest/spec_test.go create mode 100644 spectest/suite_test.go diff --git a/.gitignore b/.gitignore index c54b4d27..5b934d5d 100644 --- a/.gitignore +++ b/.gitignore @@ -66,3 +66,6 @@ docs/_build pkg/ target/ Cargo.lock + +# Downloaded WASM spec test suites. +spectest/testdata/ diff --git a/spectest/README.md b/spectest/README.md new file mode 100644 index 00000000..b333feef --- /dev/null +++ b/spectest/README.md @@ -0,0 +1,43 @@ +# WASM Spec Tests + +This package runs the WebAssembly specification test suites against the +WasmEdge Go bindings, mirroring the behavior of the WasmEdge C API spec tests +(`test/api` and `test/spec` in the [WasmEdge](https://github.com/WasmEdge/WasmEdge) +repository). + +The suites are the wast2json conversions maintained in +[WasmEdge/wasmedge-spectest](https://github.com/WasmEdge/wasmedge-spectest). +They are downloaded automatically on the first run and cached under +`testdata/`. Set `WASMEDGE_SPECTEST_PATH` to use a pre-downloaded suite. + +## Running + +```bash +# Interpreter mode only (fast): +go test ./spectest/ -run TestSpecInterpreter + +# All three modes (interpreter, AOT, and JIT): +go test ./spectest/ -timeout 60m + +# A single suite folder or unit: +go test ./spectest/ -run 'TestSpecInterpreter/wasm-1.0' +go test ./spectest/ -run 'TestSpecJIT/wasm-3.0-simd/simd_splat' +``` + +The AOT mode compiles every module with the native output format before +loading it, and the JIT mode enables `RunMode_JIT` on the VM configuration. +Both are skipped with `-short` and when the WasmEdge library is built without +the LLVM-based compiler. + +## Known deviations from the C++ spec tests + +* The `component-model` folder is skipped: these bindings do not support the + component model. +* Fine-grained GC heap types of returned references (`eqref`, `structref`, + `arrayref`, `i31ref`, ...) are matched as generic references with the + correct null-ness, because the WasmEdge C API does not expose heap type + codes or payloads of internal references. +* Host-created `anyref` argument values cannot be constructed through the C + API; the few assertions using them are skipped and logged. +* `assert_exhaustion` commands are not checked, matching the C++ spec test + behavior. diff --git a/spectest/harness_test.go b/spectest/harness_test.go new file mode 100644 index 00000000..fadb7979 --- /dev/null +++ b/spectest/harness_test.go @@ -0,0 +1,709 @@ +// Package spectest runs the wast2json-converted WASM spec test suites, +// mirroring the WasmEdge C API spec tests (test/api and test/spec). +package spectest + +import ( + "encoding/binary" + "encoding/json" + "fmt" + "math" + "os" + "path/filepath" + "strconv" + "strings" + "testing" + + "github.com/second-state/WasmEdge-go/wasmedge" +) + +type suiteDoc struct { + Commands []command `json:"commands"` +} + +type command struct { + Type string `json:"type"` + Line uint64 `json:"line"` + Name string `json:"name"` + Filename string `json:"filename"` + ModuleType string `json:"module_type"` + Text string `json:"text"` + As string `json:"as"` + Definition string `json:"definition"` + Action *action `json:"action"` + Expected []valueEntry `json:"expected"` + Either []valueEntry `json:"either"` + // Thread command fields. + Shared []struct { + Module string `json:"module"` + } `json:"shared"` + Commands []command `json:"commands"` + Thread string `json:"thread"` +} + +type action struct { + Type string `json:"type"` + Module string `json:"module"` + Field string `json:"field"` + Args []valueEntry `json:"args"` +} + +// valueEntry is one wast2json value: a string, a lane string array for +// v128, or absent for opaque reference expectations. +type valueEntry struct { + Type string `json:"type"` + LaneType string `json:"lane_type"` + Value json.RawMessage `json:"value"` +} + +func (v *valueEntry) str() (string, bool) { + var s string + if v.Value != nil && json.Unmarshal(v.Value, &s) == nil { + return s, true + } + return "", false +} + +func (v *valueEntry) lanes() ([]string, bool) { + var lanes []string + if v.Value != nil && json.Unmarshal(v.Value, &lanes) == nil { + return lanes, true + } + return nil, false +} + +func parseU64(s string) uint64 { + u, err := strconv.ParseUint(s, 10, 64) + if err != nil { + panic(fmt.Sprintf("spectest: invalid numeric value %q", s)) + } + return u +} + +// buildArgs converts wast2json arguments into Go values, or returns a skip +// reason when an argument cannot be constructed through the public API. +func buildArgs(entries []valueEntry) ([]interface{}, string) { + args := make([]interface{}, 0, len(entries)) + for i := range entries { + entry := &entries[i] + if lanes, ok := entry.lanes(); ok { + args = append(args, lanesToV128(entry.LaneType, lanes)) + continue + } + s, _ := entry.str() + switch entry.Type { + case "i32": + args = append(args, int32(uint32(parseU64(s)))) + case "i64": + args = append(args, int64(parseU64(s))) + case "f32": + args = append(args, math.Float32frombits(uint32(parseU64(s)))) + case "f64": + args = append(args, math.Float64frombits(parseU64(s))) + case "externref": + if s == "null" { + args = append(args, wasmedge.NewNullExternRef()) + } else { + // Track the original number as the referenced Go value so + // that result comparison can check it after a round-trip. + args = append(args, wasmedge.NewExternRef(uint32(parseU64(s)))) + } + case "funcref": + if s == "null" { + args = append(args, wasmedge.NewFuncRef(nil)) + } else { + return nil, "non-null funcref arguments are not supported" + } + default: + // E.g. host "anyref" values cannot be constructed through the + // WasmEdge C API. + return nil, fmt.Sprintf("%s arguments are not supported", entry.Type) + } + } + return args, "" +} + +func lanesToV128(laneType string, lanes []string) wasmedge.V128 { + var buf [16]byte + switch laneType { + case "i8": + for i, lane := range lanes { + buf[i] = uint8(parseU64(lane)) + } + case "i16": + for i, lane := range lanes { + binary.LittleEndian.PutUint16(buf[i*2:], uint16(parseU64(lane))) + } + case "i32", "f32": + for i, lane := range lanes { + binary.LittleEndian.PutUint32(buf[i*4:], uint32(parseU64(lane))) + } + case "i64", "f64": + for i, lane := range lanes { + binary.LittleEndian.PutUint64(buf[i*8:], parseU64(lane)) + } + default: + panic("spectest: unknown v128 lane type " + laneType) + } + return wasmedge.NewV128( + binary.LittleEndian.Uint64(buf[8:]), binary.LittleEndian.Uint64(buf[:8])) +} + +// refMatches checks a reference expectation: "null" expects a null, empty +// matches any, and a number matches the payload (externref) or non-null. +func refMatches(valStr string, isNull bool, payload interface{}) bool { + switch valStr { + case "null": + return isNull + case "": + return true + default: + if payload != nil { + return payload == uint32(parseU64(valStr)) + } + return !isNull + } +} + +// compareValue mirrors SpecTest::compare in WasmEdge test/spec, with the GC +// heap types matched as generic references (the C API hides heap types). +func compareValue(expected *valueEntry, got interface{}) bool { + valStr, _ := expected.str() + + if strings.HasPrefix(expected.Type, "v128") || expected.LaneType != "" { + lanes, ok := expected.lanes() + if !ok { + return false + } + v, ok := got.(wasmedge.V128) + if !ok { + return false + } + return v128LanesMatch(expected.LaneType, lanes, v) + } + + if valStr != "" && strings.HasPrefix(valStr, "nan:") { + switch expected.Type { + case "f32": + f, ok := got.(float32) + return ok && math.IsNaN(float64(f)) + case "f64": + f, ok := got.(float64) + return ok && math.IsNaN(f) + } + return false + } + + switch expected.Type { + case "i32": + g, ok := got.(int32) + return ok && uint32(g) == uint32(parseU64(valStr)) + case "i64": + g, ok := got.(int64) + return ok && uint64(g) == parseU64(valStr) + case "f32": + // Compare the 32-bit pattern. + g, ok := got.(float32) + return ok && math.Float32bits(g) == uint32(parseU64(valStr)) + case "f64": + // Compare the 64-bit pattern. + g, ok := got.(float64) + return ok && math.Float64bits(g) == parseU64(valStr) + case "funcref", "nullfuncref": + g, ok := got.(wasmedge.FuncRef) + return ok && refMatches(valStr, g.IsNull(), nil) + case "externref", "nullexternref": + g, ok := got.(wasmedge.ExternRef) + return ok && refMatches(valStr, g.IsNull(), g.GetRef()) + case "anyref", "eqref", "structref", "arrayref", "i31ref", "nullref", + "exnref", "nullexnref": + // Internal references. The C API cannot distinguish the heap types, + // so accept any non-external reference with matching null-ness. + switch g := got.(type) { + case wasmedge.Ref: + return refMatches(valStr, g.IsNull(), nil) + case wasmedge.FuncRef: + return refMatches(valStr, g.IsNull(), nil) + default: + return false + } + case "ref": + // "ref" fits all reference types. + switch g := got.(type) { + case wasmedge.Ref: + return refMatches(valStr, g.IsNull(), nil) + case wasmedge.FuncRef: + return refMatches(valStr, g.IsNull(), nil) + case wasmedge.ExternRef: + return refMatches(valStr, g.IsNull(), g.GetRef()) + default: + return false + } + } + return false +} + +func v128LanesMatch(laneType string, lanes []string, v wasmedge.V128) bool { + high, low := v.GetVal() + var buf [16]byte + binary.LittleEndian.PutUint64(buf[:8], low) + binary.LittleEndian.PutUint64(buf[8:], high) + + switch laneType { + case "i8": + for i, lane := range lanes { + if buf[i] != uint8(parseU64(lane)) { + return false + } + } + case "i16": + for i, lane := range lanes { + if binary.LittleEndian.Uint16(buf[i*2:]) != uint16(parseU64(lane)) { + return false + } + } + case "i32": + for i, lane := range lanes { + if binary.LittleEndian.Uint32(buf[i*4:]) != uint32(parseU64(lane)) { + return false + } + } + case "i64": + for i, lane := range lanes { + if binary.LittleEndian.Uint64(buf[i*8:]) != parseU64(lane) { + return false + } + } + case "f32": + for i, lane := range lanes { + bits := binary.LittleEndian.Uint32(buf[i*4:]) + if strings.HasPrefix(lane, "nan:") { + if !math.IsNaN(float64(math.Float32frombits(bits))) { + return false + } + } else if bits != uint32(parseU64(lane)) { + return false + } + } + case "f64": + for i, lane := range lanes { + bits := binary.LittleEndian.Uint64(buf[i*8:]) + if strings.HasPrefix(lane, "nan:") { + if !math.IsNaN(math.Float64frombits(bits)) { + return false + } + } else if bits != parseU64(lane) { + return false + } + } + default: + return false + } + return true +} + +func compareValues(expected []valueEntry, got []interface{}) bool { + if len(expected) != len(got) { + return false + } + for i := range expected { + if !compareValue(&expected[i], got[i]) { + return false + } + } + return true +} + +// messageMatches mirrors SpecTest::stringContains: the WasmEdge error +// message must be a prefix of the expected error text from the suite. +func messageMatches(expectedText string, err error) bool { + return strings.HasPrefix(expectedText, err.Error()) +} + +// resolveRegister builds the alias map from the register commands: original +// module names (or anonymous module lines) to the registered names. +func resolveRegister(cmds []command) map[string]string { + alias := map[string]string{} + orgName := "" + lastModLine := uint64(0) + for i := range cmds { + cmd := &cmds[i] + switch cmd.Type { + case "module": + orgName = cmd.Name + lastModLine = cmd.Line + case "register": + key := cmd.Name + if key == "" { + if orgName != "" { + key = orgName + } else { + key = strconv.FormatUint(lastModLine, 10) + } + } + if _, ok := alias[key]; !ok { + alias[key] = cmd.As + } + } + } + return alias +} + +// cmdProcessor executes one command array against a VM context; thread +// commands spawn a child processor, matching SpecTest::processCommands. +type cmdProcessor struct { + t *testing.T + unit *unitContext + ctx *specVM + alias map[string]string + lastMod string + threads map[string]chan struct{} + astMap map[string]*wasmedge.AST +} + +// unitContext carries the per-unit information shared by all processors. +type unitContext struct { + root string + folder folderConfig + mode specMode + name string +} + +func (u *unitContext) filePath(filename string) string { + return filepath.Join(u.root, u.folder.name, u.name, filename) +} + +func runUnit(t *testing.T, root string, folder folderConfig, mode specMode, unitName string) { + unit := &unitContext{root: root, folder: folder, mode: mode, name: unitName} + + raw, err := os.ReadFile(unit.filePath(unitName + ".json")) + if err != nil { + t.Fatalf("failed to read the test manifest: %v", err) + } + var doc suiteDoc + if err := json.Unmarshal(raw, &doc); err != nil { + t.Fatalf("failed to parse the test manifest: %v", err) + } + + ctx := newSpecVM(t, folder, mode) + defer ctx.release() + + proc := &cmdProcessor{ + t: t, + unit: unit, + ctx: ctx, + alias: resolveRegister(doc.Commands), + threads: map[string]chan struct{}{}, + astMap: map[string]*wasmedge.AST{}, + } + defer proc.cleanup() + proc.runCommands(doc.Commands) +} + +func (p *cmdProcessor) cleanup() { + for _, ast := range p.astMap { + ast.Release() + } +} + +func (p *cmdProcessor) runCommands(cmds []command) { + for i := range cmds { + p.runCommand(&cmds[i]) + } + // Join any threads not explicitly waited on. + for _, done := range p.threads { + <-done + } +} + +func (p *cmdProcessor) fail(cmd *command, format string, args ...interface{}) { + prefix := fmt.Sprintf("%s/%s:%d (%s): ", p.unit.folder.name, p.unit.name, cmd.Line, cmd.Type) + p.t.Errorf(prefix+format, args...) +} + +// moduleName resolves the module name an action refers to, honoring the +// register aliases and the last instantiated module. +func (p *cmdProcessor) moduleName(act *action) string { + if act.Module != "" { + if as, ok := p.alias[act.Module]; ok { + return as + } + return act.Module + } + return p.lastMod +} + +func (p *cmdProcessor) invoke(act *action) ([]interface{}, error, string) { + args, skip := buildArgs(act.Args) + if skip != "" { + return nil, nil, skip + } + modName := p.moduleName(act) + if modName != "" { + rets, err := p.ctx.vm.ExecuteRegistered(modName, act.Field, args...) + return rets, err, "" + } + rets, err := p.ctx.vm.Execute(act.Field, args...) + return rets, err, "" +} + +func (p *cmdProcessor) getGlobal(act *action) (interface{}, error) { + var mod *wasmedge.Module + if name := p.moduleName(act); name != "" { + mod = p.ctx.vm.GetStore().FindModule(name) + } else { + mod = p.ctx.vm.GetActiveModule() + } + if mod == nil { + return nil, fmt.Errorf("module instance not found") + } + glob := mod.FindGlobal(act.Field) + if glob == nil { + return nil, fmt.Errorf("global instance %q not found", act.Field) + } + return glob.GetValue(), nil +} + +func (p *cmdProcessor) runCommand(cmd *command) { + switch cmd.Type { + case "module": + if cmd.ModuleType == "text" { + // WAT modules are not supported by WasmEdge. + return + } + name := cmd.Name + if name != "" { + if as, ok := p.alias[name]; ok { + name = as + } + } else if as, ok := p.alias[strconv.FormatUint(cmd.Line, 10)]; ok { + name = as + } + p.lastMod = name + + path, err := p.ctx.prepare(p.unit.filePath(cmd.Filename)) + if err != nil { + p.fail(cmd, "compilation failed: %v", err) + return + } + if name != "" { + if err := p.ctx.vm.RegisterWasmFile(name, path); err != nil { + p.fail(cmd, "module registration failed: %v", err) + } + } else { + if err := p.ctx.instantiate(path); err != nil { + p.fail(cmd, "module instantiation failed: %v", err) + } + } + + case "module_definition": + path, err := p.ctx.prepare(p.unit.filePath(cmd.Filename)) + if err != nil { + p.fail(cmd, "compilation failed: %v", err) + return + } + ast, err := p.ctx.vm.GetLoader().LoadFile(path) + if err != nil { + p.fail(cmd, "module definition loading failed: %v", err) + return + } + if err := p.ctx.vm.GetValidator().Validate(ast); err != nil { + ast.Release() + p.fail(cmd, "module definition validation failed: %v", err) + return + } + if cmd.Name != "" { + if old, ok := p.astMap[cmd.Name]; ok { + old.Release() + } + p.astMap[cmd.Name] = ast + } else { + ast.Release() + } + + case "module_instance": + ast, ok := p.astMap[cmd.Definition] + if !ok { + p.fail(cmd, "unknown module definition %q", cmd.Definition) + return + } + name := cmd.Name + if as, ok := p.alias[name]; ok { + name = as + } + if err := p.ctx.vm.RegisterAST(name, ast); err != nil { + p.fail(cmd, "module instantiation from definition failed: %v", err) + } + + case "register": + // Preprocessed into the alias map. + + case "action": + if _, err, skip := p.invoke(cmd.Action); skip != "" { + p.t.Logf("%s/%s:%d: skipped: %s", p.unit.folder.name, p.unit.name, cmd.Line, skip) + } else if err != nil { + p.fail(cmd, "action failed: %v", err) + } + + case "assert_return": + act := cmd.Action + switch act.Type { + case "invoke": + rets, err, skip := p.invoke(act) + if skip != "" { + p.t.Logf("%s/%s:%d: skipped: %s", p.unit.folder.name, p.unit.name, cmd.Line, skip) + return + } + if err != nil { + p.fail(cmd, "invocation of %q failed: %v", act.Field, err) + return + } + if cmd.Either != nil { + for i := range cmd.Either { + if compareValue(&cmd.Either[i], rets[0]) { + return + } + } + p.fail(cmd, "%q returned %v, want one of %s", act.Field, rets, entriesString(cmd.Either)) + return + } + if !compareValues(cmd.Expected, rets) { + p.fail(cmd, "%q returned %v, want %s", act.Field, rets, entriesString(cmd.Expected)) + } + case "get": + got, err := p.getGlobal(act) + if err != nil { + p.fail(cmd, "get of %q failed: %v", act.Field, err) + return + } + if !compareValue(&cmd.Expected[0], got) { + p.fail(cmd, "global %q is %v, want %s", act.Field, got, entriesString(cmd.Expected)) + } + default: + p.fail(cmd, "unknown action type %q", act.Type) + } + + case "assert_trap": + _, err, skip := p.invoke(cmd.Action) + if skip != "" { + p.t.Logf("%s/%s:%d: skipped: %s", p.unit.folder.name, p.unit.name, cmd.Line, skip) + return + } + if err == nil { + p.fail(cmd, "invocation of %q should trap with %q", cmd.Action.Field, cmd.Text) + } else if !messageMatches(cmd.Text, err) { + p.fail(cmd, "trap message %q does not match %q", err.Error(), cmd.Text) + } + + case "assert_exhaustion": + // Not checked, matching the WasmEdge spec test behavior. + + case "assert_malformed": + if cmd.ModuleType != "binary" { + return + } + if err := p.ctx.load(p.unit.filePath(cmd.Filename)); err == nil { + p.fail(cmd, "loading should fail with %q", cmd.Text) + } else if !messageMatches(cmd.Text, err) { + p.fail(cmd, "loading error %q does not match %q", err.Error(), cmd.Text) + } + + case "assert_invalid": + if cmd.ModuleType != "binary" { + return + } + if err := p.ctx.validate(p.unit.filePath(cmd.Filename)); err == nil { + p.fail(cmd, "validation should fail with %q", cmd.Text) + } else if !messageMatches(cmd.Text, err) { + p.fail(cmd, "validation error %q does not match %q", err.Error(), cmd.Text) + } + + case "assert_unlinkable", "assert_uninstantiable": + if err := p.ctx.instantiateFresh(p.unit.filePath(cmd.Filename)); err == nil { + p.fail(cmd, "instantiation should fail with %q", cmd.Text) + } else if !messageMatches(cmd.Text, err) { + p.fail(cmd, "instantiation error %q does not match %q", err.Error(), cmd.Text) + } + + case "assert_exception": + if cmd.Action.Type != "invoke" { + p.fail(cmd, "unknown action type %q", cmd.Action.Type) + return + } + if _, err, skip := p.invoke(cmd.Action); skip != "" { + p.t.Logf("%s/%s:%d: skipped: %s", p.unit.folder.name, p.unit.name, cmd.Line, skip) + } else if err == nil { + p.fail(cmd, "invocation of %q should throw an exception", cmd.Action.Field) + } + + case "thread": + // Determine the (parent name, alias name) pairs of shared modules: + // the thread's own register commands define the alias names. + sharedAlias := map[string]string{} + for i := range cmd.Commands { + sub := &cmd.Commands[i] + if sub.Type == "register" && sub.Name != "" { + sharedAlias[sub.Name] = sub.As + } + } + + child := &cmdProcessor{ + t: p.t, + unit: p.unit, + ctx: newSpecVM(p.t, p.unit.folder, p.unit.mode), + alias: resolveRegister(cmd.Commands), + threads: map[string]chan struct{}{}, + astMap: map[string]*wasmedge.AST{}, + } + parentStore := p.ctx.vm.GetStore() + for _, shared := range cmd.Shared { + parentName := shared.Module + if as, ok := p.alias[parentName]; ok { + parentName = as + } + aliasName := parentName + if as, ok := sharedAlias[shared.Module]; ok { + aliasName = as + } + if mod := parentStore.FindModule(parentName); mod != nil { + if err := child.ctx.vm.RegisterModuleWithAlias(aliasName, mod); err != nil { + p.fail(cmd, "sharing module %q failed: %v", parentName, err) + } + } + } + + done := make(chan struct{}) + p.threads[cmd.Name] = done + commands := cmd.Commands + go func() { + defer close(done) + defer child.ctx.release() + defer child.cleanup() + child.runCommands(commands) + }() + + case "wait": + if done, ok := p.threads[cmd.Thread]; ok { + <-done + delete(p.threads, cmd.Thread) + } else { + p.fail(cmd, "wait for unknown thread %q", cmd.Thread) + } + + default: + p.fail(cmd, "unknown command type") + } +} + +func entriesString(entries []valueEntry) string { + parts := make([]string, len(entries)) + for i := range entries { + if s, ok := entries[i].str(); ok { + parts[i] = entries[i].Type + ":" + s + } else if lanes, ok := entries[i].lanes(); ok { + parts[i] = entries[i].Type + entries[i].LaneType + ":" + strings.Join(lanes, " ") + } else { + parts[i] = entries[i].Type + } + } + return "[" + strings.Join(parts, ", ") + "]" +} diff --git a/spectest/spec_test.go b/spectest/spec_test.go new file mode 100644 index 00000000..900263d4 --- /dev/null +++ b/spectest/spec_test.go @@ -0,0 +1,339 @@ +package spectest + +import ( + "errors" + "fmt" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" + "testing" + + "github.com/second-state/WasmEdge-go/wasmedge" +) + +type specMode uint8 + +const ( + modeInterpreter specMode = 1 << iota + modeAOT + modeJIT + modeAll = modeInterpreter | modeAOT | modeJIT +) + +func (m specMode) String() string { + switch m { + case modeInterpreter: + return "interpreter" + case modeAOT: + return "AOT" + case modeJIT: + return "JIT" + } + return fmt.Sprintf("mode(%d)", m) +} + +type folderConfig struct { + name string + standard wasmedge.WASMStandard + proposals []wasmedge.Proposal + modes specMode +} + +// The folder configurations, mirroring TestsuiteProposals in WasmEdge +// test/spec. The component-model folder is intentionally not supported. +var folderConfigs = []folderConfig{ + {name: "wasm-1.0", standard: wasmedge.Standard_WASM_1, modes: modeAll}, + {name: "wasm-2.0", standard: wasmedge.Standard_WASM_2, modes: modeAll}, + {name: "wasm-3.0", standard: wasmedge.Standard_WASM_3, modes: modeAll}, + {name: "wasm-3.0-bulk-memory", standard: wasmedge.Standard_WASM_3, modes: modeAll}, + // The exception-handling proposal is not implemented in AOT/JIT yet. + {name: "wasm-3.0-exceptions", standard: wasmedge.Standard_WASM_3, modes: modeInterpreter}, + {name: "wasm-3.0-gc", standard: wasmedge.Standard_WASM_3, modes: modeAll}, + {name: "wasm-3.0-memory64", standard: wasmedge.Standard_WASM_3, modes: modeAll}, + {name: "wasm-3.0-multi-memory", standard: wasmedge.Standard_WASM_3, modes: modeAll}, + {name: "wasm-3.0-relaxed-simd", standard: wasmedge.Standard_WASM_3, modes: modeAll}, + {name: "wasm-3.0-simd", standard: wasmedge.Standard_WASM_3, modes: modeAll}, + {name: "threads", standard: wasmedge.Standard_WASM_2, + proposals: []wasmedge.Proposal{wasmedge.THREADS}, modes: modeAll}, +} + +// specVM bundles the per-unit execution state: a VM with the spectest host +// module registered, and the AOT compiler when running in AOT mode. +type specVM struct { + vm *wasmedge.VM + specMod *wasmedge.Module + compiler *wasmedge.Compiler + tmpdir string +} + +func newSpecVM(t *testing.T, folder folderConfig, mode specMode) *specVM { + t.Helper() + conf := wasmedge.NewConfigure() + defer conf.Release() + conf.SetWASMStandard(folder.standard) + for _, proposal := range folder.proposals { + conf.AddConfig(proposal) + } + switch mode { + case modeJIT: + conf.SetRunMode(wasmedge.RunMode_JIT) + case modeAOT: + conf.SetRunMode(wasmedge.RunMode_AOT) + } + + ctx := &specVM{} + ctx.vm = wasmedge.NewVMWithConfig(conf) + if ctx.vm == nil { + t.Fatal("failed to create the VM") + } + ctx.specMod = buildSpecTestModule(t) + if err := ctx.vm.RegisterModule(ctx.specMod); err != nil { + t.Fatalf("failed to register the spectest module: %v", err) + } + + if mode == modeAOT { + conf.SetCompilerOutputFormat(wasmedge.CompilerOutputFormat_Native) + conf.SetCompilerOptimizationLevel(wasmedge.CompilerOptLevel_O0) + ctx.compiler = wasmedge.NewCompilerWithConfig(conf) + if ctx.compiler == nil { + t.Fatal("failed to create the compiler") + } + tmpdir, err := os.MkdirTemp("", "wasmedge-spectest-aot-") + if err != nil { + t.Fatal(err) + } + ctx.tmpdir = tmpdir + } + return ctx +} + +func (c *specVM) release() { + c.vm.Release() + c.specMod.Release() + if c.compiler != nil { + c.compiler.Release() + } + if c.tmpdir != "" { + os.RemoveAll(c.tmpdir) + } +} + +// prepare returns the file to load: in AOT mode the module is compiled to +// a native shared library first, otherwise the original file is used. +func (c *specVM) prepare(path string) (string, error) { + if c.compiler == nil { + return path, nil + } + out := filepath.Join(c.tmpdir, + strings.TrimSuffix(filepath.Base(path), ".wasm")+nativeLibExtension()) + if err := c.compiler.Compile(path, out); err != nil { + return "", err + } + return out, nil +} + +// instantiate loads, validates, and instantiates an already prepared file as +// the active module of the VM. +func (c *specVM) instantiate(prepared string) error { + if err := c.vm.LoadWasmFile(prepared); err != nil { + return err + } + if err := c.vm.Validate(); err != nil { + return err + } + return c.vm.Instantiate() +} + +func (c *specVM) load(path string) error { + prepared, err := c.prepare(path) + if err != nil { + return err + } + return c.vm.LoadWasmFile(prepared) +} + +func (c *specVM) validate(path string) error { + prepared, err := c.prepare(path) + if err != nil { + return err + } + if err := c.vm.LoadWasmFile(prepared); err != nil { + return err + } + return c.vm.Validate() +} + +func (c *specVM) instantiateFresh(path string) error { + prepared, err := c.prepare(path) + if err != nil { + return err + } + return c.instantiate(prepared) +} + +func nativeLibExtension() string { + switch runtime.GOOS { + case "darwin": + return ".dylib" + case "windows": + return ".dll" + } + return ".so" +} + +// buildSpecTestModule creates the "spectest" host module required by the +// suites, mirroring createSpecTestModule in WasmEdge test/api/hostfunc_c.c. +func buildSpecTestModule(t *testing.T) *wasmedge.Module { + t.Helper() + mod := wasmedge.NewModule("spectest") + if mod == nil { + t.Fatal("failed to create the spectest module") + } + + noop := func(interface{}, *wasmedge.CallingFrame, []interface{}) ([]interface{}, wasmedge.Result) { + return nil, wasmedge.Result_Success + } + addPrint := func(name string, params ...*wasmedge.ValType) { + ftype := wasmedge.NewFunctionType(params, nil) + defer ftype.Release() + fn := wasmedge.NewFunction(ftype, noop, nil, 0) + if fn == nil { + t.Fatalf("failed to create the host function %q", name) + } + mod.AddFunction(name, fn) + } + addPrint("print") + addPrint("print_i32", wasmedge.NewValTypeI32()) + addPrint("print_i64", wasmedge.NewValTypeI64()) + addPrint("print_f32", wasmedge.NewValTypeF32()) + addPrint("print_f64", wasmedge.NewValTypeF64()) + addPrint("print_i32_f32", wasmedge.NewValTypeI32(), wasmedge.NewValTypeF32()) + addPrint("print_f64_f64", wasmedge.NewValTypeF64(), wasmedge.NewValTypeF64()) + + addTable := func(name string, lim *wasmedge.Limit) { + defer lim.Release() + ttype := wasmedge.NewTableType(wasmedge.NewValTypeFuncRef(), lim) + defer ttype.Release() + tab := wasmedge.NewTable(ttype) + if tab == nil { + t.Fatalf("failed to create the host table %q", name) + } + mod.AddTable(name, tab) + } + addTable("table", wasmedge.NewLimitWithMax(10, 20)) + addTable("table64", wasmedge.NewLimit64WithMax(10, 20)) + + addMemory := func(name string, lim *wasmedge.Limit) { + defer lim.Release() + mtype := wasmedge.NewMemoryType(lim) + defer mtype.Release() + mem := wasmedge.NewMemory(mtype) + if mem == nil { + t.Fatalf("failed to create the host memory %q", name) + } + mod.AddMemory(name, mem) + } + addMemory("memory", wasmedge.NewLimitWithMax(1, 2)) + addMemory("shared_memory", wasmedge.NewLimitSharedWithMax(1, 2)) + + addGlobal := func(name string, vtype *wasmedge.ValType, value interface{}) { + gtype := wasmedge.NewGlobalType(vtype, wasmedge.ValMut_Const) + defer gtype.Release() + glob := wasmedge.NewGlobal(gtype, value) + if glob == nil { + t.Fatalf("failed to create the host global %q", name) + } + mod.AddGlobal(name, glob) + } + addGlobal("global_i32", wasmedge.NewValTypeI32(), int32(666)) + addGlobal("global_i64", wasmedge.NewValTypeI64(), int64(666)) + addGlobal("global_f32", wasmedge.NewValTypeF32(), float32(666.6)) + addGlobal("global_f64", wasmedge.NewValTypeF64(), float64(666.6)) + + return mod +} + +// aotSupported probes whether the WasmEdge library was built with the AOT +// compiler. +func aotSupported(t *testing.T) bool { + t.Helper() + compiler := wasmedge.NewCompiler() + if compiler == nil { + return false + } + defer compiler.Release() + out := filepath.Join(t.TempDir(), "probe"+nativeLibExtension()) + // An empty module: WASM magic and version only. + err := compiler.CompileBuffer( + []byte{0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00}, out) + return err == nil +} + +func runSpecMode(t *testing.T, mode specMode) { + root := suiteRoot(t) + for _, folder := range folderConfigs { + if folder.modes&mode == 0 { + continue + } + for _, unit := range listUnits(t, root, folder.name) { + folder, unit := folder, unit + t.Run(folder.name+"/"+unit, func(t *testing.T) { + runUnit(t, root, folder, mode, unit) + }) + } + } +} + +func TestSpecInterpreter(t *testing.T) { + runSpecMode(t, modeInterpreter) +} + +func TestSpecAOT(t *testing.T) { + if testing.Short() { + t.Skip("skipping the AOT spec tests in short mode") + } + if !aotSupported(t) { + t.Skip("the WasmEdge library was built without the AOT compiler") + } + runSpecMode(t, modeAOT) +} + +func TestSpecJIT(t *testing.T) { + if testing.Short() { + t.Skip("skipping the JIT spec tests in short mode") + } + if !aotSupported(t) { + t.Skip("the WasmEdge library was built without the JIT compiler") + } + runSpecMode(t, modeJIT) +} + +func TestMain(m *testing.M) { + // The WasmEdge AOT/JIT trap signal handlers lack SA_ONSTACK, which the Go + // runtime rejects; re-run the tests with async preemption disabled. + if !strings.Contains(os.Getenv("GODEBUG"), "asyncpreemptoff=1") { + godebug := "asyncpreemptoff=1" + if prev := os.Getenv("GODEBUG"); prev != "" { + godebug = prev + ",asyncpreemptoff=1" + } + cmd := exec.Command(os.Args[0], os.Args[1:]...) + cmd.Env = append(os.Environ(), "GODEBUG="+godebug) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + if err := cmd.Run(); err != nil { + var exitErr *exec.ExitError + if errors.As(err, &exitErr) { + os.Exit(exitErr.ExitCode()) + } + fmt.Fprintln(os.Stderr, "failed to re-execute the test binary:", err) + os.Exit(1) + } + os.Exit(0) + } + + wasmedge.SetLogOff() + os.Exit(m.Run()) +} diff --git a/spectest/suite_test.go b/spectest/suite_test.go new file mode 100644 index 00000000..353f1487 --- /dev/null +++ b/spectest/suite_test.go @@ -0,0 +1,148 @@ +package spectest + +import ( + "archive/tar" + "compress/gzip" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "strings" + "testing" +) + +// The wast2json-converted spec test suite. The tag must match the suite +// used by the targeted WasmEdge release (see test/spec in WasmEdge). +const ( + suiteTag = "wasm-core-20260322" + suiteURL = "https://github.com/WasmEdge/wasmedge-spectest/archive/refs/tags/" + + suiteTag + ".tar.gz" +) + +// suiteRoot returns the extracted suite path, downloading into testdata/ on +// first use. Set WASMEDGE_SPECTEST_PATH to use a pre-downloaded suite. +func suiteRoot(t *testing.T) string { + t.Helper() + if path := os.Getenv("WASMEDGE_SPECTEST_PATH"); path != "" { + return path + } + + cache := filepath.Join("testdata", "wasmedge-spectest-"+suiteTag) + marker := filepath.Join(cache, ".complete") + if _, err := os.Stat(marker); err == nil { + return cache + } + + t.Logf("downloading the spec test suite %s ...", suiteTag) + if err := downloadSuite(cache); err != nil { + t.Fatalf("failed to download the spec test suite: %v", err) + } + if err := os.WriteFile(marker, []byte(suiteURL+"\n"), 0o644); err != nil { + t.Fatal(err) + } + return cache +} + +func downloadSuite(cache string) error { + resp, err := http.Get(suiteURL) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("GET %s: %s", suiteURL, resp.Status) + } + + tmp := cache + ".tmp" + if err := os.RemoveAll(tmp); err != nil { + return err + } + if err := extractTarGz(resp.Body, tmp); err != nil { + os.RemoveAll(tmp) + return err + } + if err := os.RemoveAll(cache); err != nil { + return err + } + return os.Rename(tmp, cache) +} + +// extractTarGz extracts a gzipped tarball into destDir, stripping the first +// path component (the "-/" prefix of GitHub archives). +func extractTarGz(r io.Reader, destDir string) error { + gz, err := gzip.NewReader(r) + if err != nil { + return err + } + defer gz.Close() + + tr := tar.NewReader(gz) + for { + hdr, err := tr.Next() + if err == io.EOF { + return nil + } + if err != nil { + return err + } + + name := hdr.Name + if idx := strings.IndexByte(name, '/'); idx >= 0 { + name = name[idx+1:] + } else { + continue + } + if name == "" { + continue + } + // Guard against path traversal in archive entries. + path := filepath.Join(destDir, filepath.FromSlash(name)) + if !strings.HasPrefix(path, filepath.Clean(destDir)+string(os.PathSeparator)) { + return fmt.Errorf("archive entry escapes destination: %q", hdr.Name) + } + + switch hdr.Typeflag { + case tar.TypeDir: + if err := os.MkdirAll(path, 0o755); err != nil { + return err + } + case tar.TypeReg: + if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil { + return err + } + f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0o644) + if err != nil { + return err + } + if _, err := io.Copy(f, tr); err != nil { + f.Close() + return err + } + if err := f.Close(); err != nil { + return err + } + } + } +} + +// listUnits returns the sorted unit names of a suite folder: the +// subdirectories containing a ".json" test manifest. +func listUnits(t *testing.T, root string, folder string) []string { + t.Helper() + entries, err := os.ReadDir(filepath.Join(root, folder)) + if err != nil { + t.Fatalf("failed to list the %q folder: %v", folder, err) + } + var units []string + for _, entry := range entries { + if !entry.IsDir() { + continue + } + name := entry.Name() + if _, err := os.Stat(filepath.Join(root, folder, name, name+".json")); err == nil { + units = append(units, name) + } + } + return units +} diff --git a/wasmedge/value.go b/wasmedge/value.go index 77d833be..86e0c42c 100644 --- a/wasmedge/value.go +++ b/wasmedge/value.go @@ -191,7 +191,14 @@ type FuncRef struct { _inner C.WasmEdge_Value } +// NewFuncRef creates a function reference value. Passing nil creates a null +// function reference. func NewFuncRef(funcinst *Function) FuncRef { + if funcinst == nil { + return FuncRef{ + _inner: C.WasmEdge_ValueGenFuncRef(nil), + } + } return FuncRef{ _inner: C.WasmEdge_ValueGenFuncRef(funcinst._inner), } @@ -224,6 +231,14 @@ func NewExternRef(ptr interface{}) ExternRef { } } +// NewNullExternRef creates a null external reference value. +func NewNullExternRef() ExternRef { + return ExternRef{ + _inner: C.wasmedgego_GenExternRef(0), + _valid: true, + } +} + func (self ExternRef) IsNull() bool { return bool(C.WasmEdge_ValueIsNullRef(self._inner)) } @@ -282,7 +297,8 @@ func toWasmEdgeValue(value interface{}) C.WasmEdge_Value { return value.(FuncRef)._inner case ExternRef: ref := value.(ExternRef) - if !ref._valid || !externRefMgr.has(uint(C.wasmedgego_GetExternRef(ref._inner))) { + if !ref._valid || + (!ref.IsNull() && !externRefMgr.has(uint(C.wasmedgego_GetExternRef(ref._inner)))) { panic("External reference is released") } return ref._inner @@ -340,10 +356,8 @@ func fromWasmEdgeValue(value C.WasmEdge_Value) interface{} { } if C.WasmEdge_ValTypeIsExternRef(value.Type) { idx := uint(C.wasmedgego_GetExternRef(value)) - if externRefMgr.has(idx) { - return ExternRef{_inner: value, _valid: true} - } - return ExternRef{_inner: value, _valid: false} + valid := externRefMgr.has(idx) || bool(C.WasmEdge_ValueIsNullRef(value)) + return ExternRef{_inner: value, _valid: valid} } if C.WasmEdge_ValTypeIsRef(value.Type) { return Ref{_inner: value} diff --git a/wasmedge/value_test.go b/wasmedge/value_test.go index 5c81004d..dba1651c 100644 --- a/wasmedge/value_test.go +++ b/wasmedge/value_test.go @@ -130,6 +130,38 @@ func TestExternRef(t *testing.T) { }() } +func TestNullRefs(t *testing.T) { + vm := NewVM() + defer vm.Release() + + nullExtern := NewNullExternRef() + if !nullExtern.IsNull() { + t.Error("NewNullExternRef() should be null") + } + if nullExtern.GetRef() != nil { + t.Error("null externref should hold no reference") + } + rets, err := vm.RunWasmFile(testWasmPath("refs.wasm"), "is_null_extern", nullExtern) + if err != nil { + t.Fatalf("is_null_extern failed: %v", err) + } + if rets[0].(int32) != 1 { + t.Error("null externref should be ref.null inside WASM") + } + + nullFunc := NewFuncRef(nil) + if !nullFunc.IsNull() { + t.Error("NewFuncRef(nil) should be null") + } + rets, err = vm.Execute("func_id", nullFunc) + if err != nil { + t.Fatalf("func_id failed: %v", err) + } + if got := rets[0].(FuncRef); !got.IsNull() { + t.Error("null funcref should round-trip as null") + } +} + func TestFuncRef(t *testing.T) { // Instantiate types.wasm which exports a funcref table with slot 0 // initialized and the other slots null. From 70aab6ce04b6645f9c654e6e369409e2f6999973 Mon Sep 17 00:00:00 2001 From: YiYing He Date: Fri, 10 Jul 2026 05:48:32 +0800 Subject: [PATCH 5/5] docs,ci: update to WasmEdge 0.17.1 and Go 1.25 - README: WasmEdge 0.17.1 with the install_v2.sh installer, Go >= 1.25, and a testing section for the unit and spec tests. - CI: build and test with Go 1.25/1.26 against WasmEdge 0.17.1, run the unit tests and all spec test modes, and drop the removed wasm-bindgen examples from the examples workflow. - Bazel: bump the module to 0.17.1, the Go SDK to 1.25.0, the wasmedge_c archives to the 0.17.1 release assets, and list the new source and test files. - Changelog: add the v0.17.1 section. Assisted-By: Claude Fable 5 Signed-off-by: YiYing He --- .CurrentChangelog.md | 98 +-- .github/workflows/build.yml | 21 +- .github/workflows/examples.yml | 136 +--- Changelog.md | 63 ++ MODULE.bazel | 18 +- MODULE.bazel.lock | 1190 +++++++++++++++++++++++++++++++- README.md | 24 +- wasmedge/BUILD.bazel | 20 +- 8 files changed, 1359 insertions(+), 211 deletions(-) diff --git a/.CurrentChangelog.md b/.CurrentChangelog.md index ab6ae5c5..110d983f 100644 --- a/.CurrentChangelog.md +++ b/.CurrentChangelog.md @@ -1,48 +1,62 @@ -### v0.14.0 (2025-02-14) +### v0.17.1 (2026-07-10) Breaking Changes: -* Removed `wasmedge.ValType` and `wasmedge.RefType` const values, and introduce the `wasmedge.ValType` struct. - * Added the `wasmedge.NewValTypeI32()` API to replace the `wasmedge.ValType_I32` const value. - * Added the `wasmedge.NewValTypeI64()` API to replace the `wasmedge.ValType_I64` const value. - * Added the `wasmedge.NewValTypeF32()` API to replace the `wasmedge.ValType_F32` const value. - * Added the `wasmedge.NewValTypeF64()` API to replace the `wasmedge.ValType_F64` const value. - * Added the `wasmedge.NewValTypeV128()` API to replace the `wasmedge.ValType_V128` const value. - * Added the `wasmedge.NewValTypeFuncRef()` API to replace the `wasmedge.ValType_FuncRef` const value. - * Added the `wasmedge.NewValTypeExternRef()` API to replace the `wasmedge.ValType_ExterunRef` const value. - * Added the `(*wasmedge.ValType).IsEqual()` API to compare the equivalent of two value types. - * Added the `(*wasmedge.ValType).IsI32()` API to specify the value type is `i32` or not. - * Added the `(*wasmedge.ValType).IsI64()` API to specify the value type is `i64` or not. - * Added the `(*wasmedge.ValType).IsF32()` API to specify the value type is `f32` or not. - * Added the `(*wasmedge.ValType).IsF64()` API to specify the value type is `f64` or not. - * Added the `(*wasmedge.ValType).IsV128()` API to specify the value type is `v128` or not. - * Added the `(*wasmedge.ValType).IsFuncRef()` API to specify the value type is `funcref` or not. - * Added the `(*wasmedge.ValType).IsExternRef()` API to specify the value type is `externref` or not. - * Added the `(*wasmedge.ValType).IsRef()` API to specify the value type is a reference type or not. - * Added the `(*wasmedge.ValType).IsRefNull()` API to specify the value type is a nullable reference type or not. -* Updated the supported WASM proposals. - * Added the `wasmedge.Proposal.GC`. - * Added the `wasmedge.Proposal.RELAXED_SIMD`. - * Added the `wasmedge.Proposal.COMPONENT_MODEL`. -* Added the error return in `(*wasmedge.Global).SetValue()` API. -* Applied the new `wasmedge.ValType` struct to all related APIs. - * `wasmedge.NewFunctionType()` accepts the new `[]*wasmedge.ValType` for parameters now. - * `(*wasmedge.FunctionType).GetParameters()` returns the new `[]*wasmedge.ValType` now. - * `(*wasmedge.FunctionType).GetReturns()` returns the new `[]*wasmedge.ValType` now. - * `wasmedge.NewTableType()` accepts the new `*wasmedge.ValType` instead of `wasmedge.RefType` for parameters now. - * `(*wasmedge.TableType).GetRefType()` returns the new `*wasmedge.ValType` now. - * `wasmedge.NewGlobalType()` accepts the new `*wasmedge.ValType` for parameters now. - * `(*wasmedge.GlobalType).GetValType()` returns the new `*wasmedge.ValType` now. +* Updated to the [WasmEdge 0.17.1](https://github.com/WasmEdge/WasmEdge/releases/tag/0.17.1) C API. +* Removed all wasm-bindgen related APIs. Please use the [wasmedge-bindgen](https://github.com/second-state/wasmedge-bindgen) project or plain WASM functions instead. + * Removed the `(*wasmedge.VM).ExecuteBindgen()` API. + * Removed the `(*wasmedge.VM).ExecuteBindgenRegistered()` API. + * Removed the `wasmedge.Bindgen_return_void`, `wasmedge.Bindgen_return_i32`, `wasmedge.Bindgen_return_i64`, and `wasmedge.Bindgen_return_array` const values. +* Removed the force-interpreter configuration in favor of the new run mode configuration. + * Removed the `(*wasmedge.Configure).SetForceInterpreter()` API. Please use the `(*wasmedge.Configure).SetRunMode()` API instead. + * Removed the `(*wasmedge.Configure).IsForceInterpreter()` API. Please use the `(*wasmedge.Configure).GetRunMode()` API instead. +* Changed the `wasmedge.Limit` into a context type like the other types, along with the `WasmEdge_LimitContext` introduced in the WasmEdge 0.17.1 C API. + * The `wasmedge.NewLimit*()` APIs create a limit context now, and developers should call the `(*wasmedge.Limit).Release()` API to destroy it after use. + * The `(*wasmedge.TableType).GetLimit()` and `(*wasmedge.MemoryType).GetLimit()` APIs return a limit reference which is valid while the type context is valid. +* Removed the `wasmedge.NewLimitShared()` API: shared limits require a maximum value in WasmEdge 0.17.1. Please use the `wasmedge.NewLimitSharedWithMax()` API instead. +* Changed the `(*wasmedge.VM).ForceDeleteRegisteredModule()` semantics along with the WasmEdge C API: the module instance is destroyed, and any Go wrapper of it must not be released afterwards. Features: -* Updated to the [WasmEdge 0.14.0](https://github.com/WasmEdge/WasmEdge/releases/tag/0.14.0). -* Added the new `(*wasmedge.Compiler).CompileBuffer()` API for compiling WASM from buffer. -* Added the tag type and tag instance for the exception-handling proposal. - * Added the `wasmedge.ExternType_Tag` const value. - * Added the `wasmedge.TagType` struct for tag type. - * Added the `(*wasmedge.TagType).GetFunctionType()` API. - * Added the `wasmedge.Tag` struct for tag instance. - * Added the `(*wasmedge.Tag).GetTagType()` API. - * Added the `(*wasmedge.Module).FindTag()` API to retrieve exported tag instances from a module instance. - * Added the `(*wasmedge.Module).ListTag()` API to list all exported tag instance names from a module instance. +* Added the run mode configuration for selecting the execution engine. + * Added the `wasmedge.RunMode_Interpreter`, `wasmedge.RunMode_JIT`, and `wasmedge.RunMode_AOT` const values. + * Added the `(*wasmedge.Configure).SetRunMode()` API. + * Added the `(*wasmedge.Configure).GetRunMode()` API. +* Added the WASM standard configuration. + * Added the `wasmedge.Standard_WASM_1`, `wasmedge.Standard_WASM_2`, and `wasmedge.Standard_WASM_3` const values. + * Added the `(*wasmedge.Configure).SetWASMStandard()` API. +* Added the log level APIs. + * Added the `wasmedge.LogLevel_Trace`, `wasmedge.LogLevel_Debug`, `wasmedge.LogLevel_Info`, `wasmedge.LogLevel_Warn`, `wasmedge.LogLevel_Error`, and `wasmedge.LogLevel_Critical` const values. + * Added the `wasmedge.SetLogLevel()` API. +* Added the 64-bit limits for the memory64 proposal. + * Added the `wasmedge.NewLimit64()`, `wasmedge.NewLimit64WithMax()`, and `wasmedge.NewLimit64SharedWithMax()` APIs. + * Added the `(*wasmedge.Limit).Is64Bit()` API. + * Added the `(*wasmedge.Limit).IsEqual()` API. + * The memory and table instance APIs use 64-bit offsets and sizes internally now. +* Added the WASI module creation with custom file descriptors. + * Added the `wasmedge.NewWasiModuleWithFds()` API. + * Added the `(*wasmedge.Module).InitWasiWithFds()` API. +* Added the module registration with alias names. + * Added the `(*wasmedge.VM).RegisterModuleWithAlias()` API. + * Added the `(*wasmedge.VM).ForceDeleteRegisteredModule()` API. + * Added the `(*wasmedge.Executor).RegisterImportWithAlias()` API. +* Added the reference value helpers. + * Added the `wasmedge.Ref` struct for the GC proposal references with the `IsNull()` and `GetValType()` APIs. + * Added the `(wasmedge.FuncRef).IsNull()` and `(wasmedge.ExternRef).IsNull()` APIs. + * Added the `wasmedge.NewNullExternRef()` API, and `wasmedge.NewFuncRef(nil)` creates a null function reference now. + +Fixes: + +* Fixed the `wasmedge.NewExternRef()` crash with WasmEdge 0.17.x: the reference values are generated through the C API now instead of forging the value payload. +* Fixed the nil pointer dereference in the `(*wasmedge.FunctionType).GetParameters()` and `(*wasmedge.FunctionType).GetReturns()` APIs. +* Fixed the maximum memory page configuration to use the full 64-bit range. + +Tests: + +* Added the unit tests for the API surface of the `wasmedge` package. +* Added the WASM specification test suites in the interpreter, AOT, and JIT modes under the `spectest` package. + +Misc: + +* Updated the minimum Go version to 1.25. +* Updated the CI workflows to WasmEdge 0.17.1 and Go 1.25/1.26, and enabled the new tests. diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5c803c1a..c9cb558d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,7 @@ jobs: USE_BAZEL_VERSION: 7.4.1 strategy: matrix: - go: [ '1.22.x', '1.23.x' ] + go: [ '1.25.x', '1.26.x' ] name: Build WasmEdge-go on Ubuntu 24.04 x86_64 with Go ${{ matrix.go }} steps: - uses: actions/checkout@v6 @@ -34,11 +34,15 @@ jobs: run: go version - name: Install wasmedge run: | - wget -qO- https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s -- -v 0.14.0 + wget -qO- https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install_v2.sh | bash -s -- -v 0.17.1 - name: Build WasmEdge-go run: | source $HOME/.wasmedge/env go build ./wasmedge/ + - name: Unit tests + run: | + source $HOME/.wasmedge/env + go test ./wasmedge/ -count=1 - name: Bazel Test run: | bazel test //... \ @@ -56,8 +60,8 @@ jobs: USE_BAZEL_VERSION: 7.4.1 strategy: matrix: - go: [ '1.22.x', '1.23.x' ] - name: Build WasmEdge-go on MacOS 14 x86_64 with Go ${{ matrix.go }} + go: [ '1.25.x', '1.26.x' ] + name: Build WasmEdge-go on macOS 14 arm64 with Go ${{ matrix.go }} steps: - uses: actions/checkout@v6 - name: Install go @@ -68,12 +72,15 @@ jobs: run: go version - name: Install wasmedge run: | - wget -qO- https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s -- -v 0.14.0 + wget -qO- https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install_v2.sh | bash -s -- -v 0.17.1 - name: Build WasmEdge-go run: | source $HOME/.wasmedge/env go build ./wasmedge/ - + - name: Unit tests + run: | + source $HOME/.wasmedge/env + go test ./wasmedge/ -count=1 - name: Bazel Test run: | bazel test //... \ @@ -82,4 +89,4 @@ jobs: --linkopt="-L$HOME/.wasmedge/lib" \ --action_env=LD_LIBRARY_PATH=$HOME/.wasmedge/lib \ --action_env=DYLD_LIBRARY_PATH=$HOME/.wasmedge/lib \ - --@io_bazel_rules_go//go/config:pure=false \ No newline at end of file + --@io_bazel_rules_go//go/config:pure=false diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index d4050b58..83c37739 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -17,11 +17,14 @@ jobs: runs-on: ubuntu-24.04 strategy: matrix: - go: [ '1.22.x', '1.23.x' ] + go: [ '1.25.x', '1.26.x' ] name: Run WasmEdge-go-examples in AOT mode with Go ${{ matrix.go }} steps: + - name: Checkout code + uses: actions/checkout@v6 + - name: Install apt-get packages run: | sudo ACCEPT_EULA=Y apt-get update @@ -38,7 +41,11 @@ jobs: - name: Install WasmEdge run: | - wget -qO- https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | sudo bash -s -- -p /usr/local --plugins wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image -v 0.14.0 + wget -qO- https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | sudo bash -s -- -p /usr/local --plugins wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image -v 0.17.1 + + - name: WASM spec tests + run: | + go test ./spectest/ -count=1 -timeout 60m - name: Install the examples run: | @@ -106,70 +113,6 @@ jobs: wasmedgec greet.wasm out.wasm ./greet_memory out.wasm - - name: go_BindgenFuncs - run: | - cd wasmedge-go-examples/go_BindgenFuncs - go get . - go build - wasmedgec rust_bindgen_funcs_lib.wasm out.wasm - ./bindgen_funcs out.wasm - - - name: go_BindgenKmeans - run: | - cd wasmedge-go-examples/go_BindgenKmeans - go get . - go build - wasmedgec rust_bindgen_kmeans_lib.wasm out.wasm - ./bindgen_kmeans out.wasm - - - name: go_BindgenWasi - run: | - cd wasmedge-go-examples/go_BindgenWasi - go get . - go build - wasmedgec rust_bindgen_wasi_lib.wasm out.wasm - ./bindgen_wasi out.wasm - - - name: go_Mobilenet - run: | - cd wasmedge-go-examples/go_Mobilenet - go get . - go build - wasmedgec rust_mobilenet_lib.wasm out.wasm - ./mobilenet out.wasm grace_hopper.jpg - - - name: go_MobilenetBirds - run: | - cd wasmedge-go-examples/go_MobilenetBirds - go get . - go build - wasmedgec rust_mobilenet_birds_lib.wasm out.wasm - ./mobilenet_birds out.wasm PurpleGallinule.jpg - - - name: go_MobilenetFood - run: | - cd wasmedge-go-examples/go_MobilenetFood - go get . - go build - wasmedgec rust_mobilenet_food_lib.wasm out.wasm - ./mobilenet_food out.wasm food.jpg - - - name: go_MobilenetInsects - run: | - cd wasmedge-go-examples/go_MobilenetInsects - go get . - go build - wasmedgec rust_mobilenet_insects_lib.wasm out.wasm - ./mobilenet_insects out.wasm ladybug.jpg - - - name: go_MobilenetPlants - run: | - cd wasmedge-go-examples/go_MobilenetPlants - go get . - go build - wasmedgec rust_mobilenet_plants_lib.wasm out.wasm - ./mobilenet_plants out.wasm sunflower.jpg - - name: go_mtcnn run: | cd wasmedge-go-examples/go_mtcnn @@ -184,7 +127,7 @@ jobs: strategy: matrix: - go: [ '1.22.x', '1.23.x' ] + go: [ '1.25.x', '1.26.x' ] name: Run WasmEdge-go-examples in interpreter mode with Go ${{ matrix.go }} steps: @@ -205,7 +148,7 @@ jobs: - name: Install WasmEdge run: | - wget -qO- https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | sudo bash -s -- -p /usr/local --plugins wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image -v 0.14.0 + wget -qO- https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | sudo bash -s -- -p /usr/local --plugins wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image -v 0.17.1 - name: Install the examples run: | @@ -274,63 +217,6 @@ jobs: go build greet_memory.go ./greet_memory greet.wasm - - name: go_BindgenFuncs - run: | - cd wasmedge-go-examples/go_BindgenFuncs - go get . - go build - ./bindgen_funcs rust_bindgen_funcs_lib.wasm - - # Not to run this example in interpreter mode to reduce CI time. - #- name: go_BindgenKmeans - # run: | - # cd wasmedge-go-examples/go_BindgenKmeans - # go get . - # go build - # ./bindgen_kmeans rust_bindgen_kmeans_lib.wasm - - - name: go_BindgenWasi - run: | - cd wasmedge-go-examples/go_BindgenWasi - go get . - go build - ./bindgen_wasi rust_bindgen_wasi_lib.wasm - - - name: go_Mobilenet - run: | - cd wasmedge-go-examples/go_Mobilenet - go get . - go build - ./mobilenet rust_mobilenet_lib.wasm grace_hopper.jpg - - - name: go_MobilenetBirds - run: | - cd wasmedge-go-examples/go_MobilenetBirds - go get . - go build - ./mobilenet_birds rust_mobilenet_birds_lib.wasm PurpleGallinule.jpg - - - name: go_MobilenetFood - run: | - cd wasmedge-go-examples/go_MobilenetFood - go get . - go build - ./mobilenet_food rust_mobilenet_food_lib.wasm food.jpg - - - name: go_MobilenetInsects - run: | - cd wasmedge-go-examples/go_MobilenetInsects - go get . - go build - ./mobilenet_insects rust_mobilenet_insects_lib.wasm ladybug.jpg - - - name: go_MobilenetPlants - run: | - cd wasmedge-go-examples/go_MobilenetPlants - go get . - go build - ./mobilenet_plants rust_mobilenet_plants_lib.wasm sunflower.jpg - - name: go_mtcnn run: | cd wasmedge-go-examples/go_mtcnn diff --git a/Changelog.md b/Changelog.md index a14c91db..2f3bd931 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,66 @@ +### v0.17.1 (2026-07-10) + +Breaking Changes: + +* Updated to the [WasmEdge 0.17.1](https://github.com/WasmEdge/WasmEdge/releases/tag/0.17.1) C API. +* Removed all wasm-bindgen related APIs. Please use the [wasmedge-bindgen](https://github.com/second-state/wasmedge-bindgen) project or plain WASM functions instead. + * Removed the `(*wasmedge.VM).ExecuteBindgen()` API. + * Removed the `(*wasmedge.VM).ExecuteBindgenRegistered()` API. + * Removed the `wasmedge.Bindgen_return_void`, `wasmedge.Bindgen_return_i32`, `wasmedge.Bindgen_return_i64`, and `wasmedge.Bindgen_return_array` const values. +* Removed the force-interpreter configuration in favor of the new run mode configuration. + * Removed the `(*wasmedge.Configure).SetForceInterpreter()` API. Please use the `(*wasmedge.Configure).SetRunMode()` API instead. + * Removed the `(*wasmedge.Configure).IsForceInterpreter()` API. Please use the `(*wasmedge.Configure).GetRunMode()` API instead. +* Changed the `wasmedge.Limit` into a context type like the other types, along with the `WasmEdge_LimitContext` introduced in the WasmEdge 0.17.1 C API. + * The `wasmedge.NewLimit*()` APIs create a limit context now, and developers should call the `(*wasmedge.Limit).Release()` API to destroy it after use. + * The `(*wasmedge.TableType).GetLimit()` and `(*wasmedge.MemoryType).GetLimit()` APIs return a limit reference which is valid while the type context is valid. +* Removed the `wasmedge.NewLimitShared()` API: shared limits require a maximum value in WasmEdge 0.17.1. Please use the `wasmedge.NewLimitSharedWithMax()` API instead. +* Changed the `(*wasmedge.VM).ForceDeleteRegisteredModule()` semantics along with the WasmEdge C API: the module instance is destroyed, and any Go wrapper of it must not be released afterwards. + +Features: + +* Added the run mode configuration for selecting the execution engine. + * Added the `wasmedge.RunMode_Interpreter`, `wasmedge.RunMode_JIT`, and `wasmedge.RunMode_AOT` const values. + * Added the `(*wasmedge.Configure).SetRunMode()` API. + * Added the `(*wasmedge.Configure).GetRunMode()` API. +* Added the WASM standard configuration. + * Added the `wasmedge.Standard_WASM_1`, `wasmedge.Standard_WASM_2`, and `wasmedge.Standard_WASM_3` const values. + * Added the `(*wasmedge.Configure).SetWASMStandard()` API. +* Added the log level APIs. + * Added the `wasmedge.LogLevel_Trace`, `wasmedge.LogLevel_Debug`, `wasmedge.LogLevel_Info`, `wasmedge.LogLevel_Warn`, `wasmedge.LogLevel_Error`, and `wasmedge.LogLevel_Critical` const values. + * Added the `wasmedge.SetLogLevel()` API. +* Added the 64-bit limits for the memory64 proposal. + * Added the `wasmedge.NewLimit64()`, `wasmedge.NewLimit64WithMax()`, and `wasmedge.NewLimit64SharedWithMax()` APIs. + * Added the `(*wasmedge.Limit).Is64Bit()` API. + * Added the `(*wasmedge.Limit).IsEqual()` API. + * The memory and table instance APIs use 64-bit offsets and sizes internally now. +* Added the WASI module creation with custom file descriptors. + * Added the `wasmedge.NewWasiModuleWithFds()` API. + * Added the `(*wasmedge.Module).InitWasiWithFds()` API. +* Added the module registration with alias names. + * Added the `(*wasmedge.VM).RegisterModuleWithAlias()` API. + * Added the `(*wasmedge.VM).ForceDeleteRegisteredModule()` API. + * Added the `(*wasmedge.Executor).RegisterImportWithAlias()` API. +* Added the reference value helpers. + * Added the `wasmedge.Ref` struct for the GC proposal references with the `IsNull()` and `GetValType()` APIs. + * Added the `(wasmedge.FuncRef).IsNull()` and `(wasmedge.ExternRef).IsNull()` APIs. + * Added the `wasmedge.NewNullExternRef()` API, and `wasmedge.NewFuncRef(nil)` creates a null function reference now. + +Fixes: + +* Fixed the `wasmedge.NewExternRef()` crash with WasmEdge 0.17.x: the reference values are generated through the C API now instead of forging the value payload. +* Fixed the nil pointer dereference in the `(*wasmedge.FunctionType).GetParameters()` and `(*wasmedge.FunctionType).GetReturns()` APIs. +* Fixed the maximum memory page configuration to use the full 64-bit range. + +Tests: + +* Added the unit tests for the API surface of the `wasmedge` package. +* Added the WASM specification test suites in the interpreter, AOT, and JIT modes under the `spectest` package. + +Misc: + +* Updated the minimum Go version to 1.25. +* Updated the CI workflows to WasmEdge 0.17.1 and Go 1.25/1.26, and enabled the new tests. + ### v0.14.0 (2025-02-14) Breaking Changes: diff --git a/MODULE.bazel b/MODULE.bazel index 5661a557..a9902602 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -1,14 +1,14 @@ module( name = "wasmedge_go", - version = "0.14.0", + version = "0.17.1", ) bazel_dep(name = "platforms", version = "0.0.11") -bazel_dep(name = "rules_go", version = "0.50.1", repo_name = "io_bazel_rules_go") -bazel_dep(name = "gazelle", version = "0.38.0") +bazel_dep(name = "rules_go", version = "0.61.1", repo_name = "io_bazel_rules_go") +bazel_dep(name = "gazelle", version = "0.51.3") go_sdk = use_extension("@io_bazel_rules_go//go:extensions.bzl", "go_sdk") -go_sdk.download(version = "1.23.0") +go_sdk.download(version = "1.25.0") use_repo(go_sdk, "go_toolchains") register_toolchains("@go_toolchains//:all") @@ -30,9 +30,7 @@ cc_library( }), hdrs = glob(["**/include/**/*"], allow_empty = True), includes = [ - "WasmEdge-0.14.0-Linux/include", - "WasmEdge-0.14.0-Darwin/include", - "WasmEdge-0.14.0-Windows/include", + "WasmEdge-0.17.1-Windows/include", "include", ".", ], @@ -40,8 +38,8 @@ cc_library( ) """, urls = [ - "https://github.com/WasmEdge/WasmEdge/releases/download/0.14.0/WasmEdge-0.14.0-ubuntu20.04_x86_64.tar.gz", - "https://github.com/WasmEdge/WasmEdge/releases/download/0.14.0/WasmEdge-0.14.0-darwin_aarch64.tar.gz", - "https://github.com/WasmEdge/WasmEdge/releases/download/0.14.0/WasmEdge-0.14.0-windows_x86_64.zip", + "https://github.com/WasmEdge/WasmEdge/releases/download/0.17.1/WasmEdge-0.17.1-ubuntu20.04_x86_64.tar.gz", + "https://github.com/WasmEdge/WasmEdge/releases/download/0.17.1/WasmEdge-0.17.1-darwin_arm64.tar.gz", + "https://github.com/WasmEdge/WasmEdge/releases/download/0.17.1/WasmEdge-0.17.1-windows.zip", ], ) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 4d2f92c5..874ba376 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -4,82 +4,153 @@ "https://bcr.bazel.build/bazel_registry.json": "8a28e4aff06ee60aed2a8c281907fb8bcbf3b753c91fb5a5c57da3215d5b3497", "https://bcr.bazel.build/modules/abseil-cpp/20210324.2/MODULE.bazel": "7cd0312e064fde87c8d1cd79ba06c876bd23630c83466e9500321be55c96ace2", "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/MODULE.bazel": "70390338f7a5106231d20620712f7cccb659cd0e9d073d1991c038eb9fc57589", - "https://bcr.bazel.build/modules/abseil-cpp/20211102.0/source.json": "7e3a9adf473e9af076ae485ed649d5641ad50ec5c11718103f34de03170d94ad", + "https://bcr.bazel.build/modules/abseil-cpp/20230125.1/MODULE.bazel": "89047429cb0207707b2dface14ba7f8df85273d484c2572755be4bab7ce9c3a0", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0.bcr.1/MODULE.bazel": "1c8cec495288dccd14fdae6e3f95f772c1c91857047a098fad772034264cc8cb", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.0/MODULE.bazel": "d253ae36a8bd9ee3c5955384096ccb6baf16a1b1e93e858370da0a3b94f77c16", + "https://bcr.bazel.build/modules/abseil-cpp/20230802.1/MODULE.bazel": "fa92e2eb41a04df73cdabeec37107316f7e5272650f81d6cc096418fe647b915", + "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/MODULE.bazel": "37bcdb4440fbb61df6a1c296ae01b327f19e9bb521f9b8e26ec854b6f97309ed", + "https://bcr.bazel.build/modules/abseil-cpp/20240116.1/source.json": "9be551b8d4e3ef76875c0d744b5d6a504a27e3ae67bc6b28f46415fd2d2957da", "https://bcr.bazel.build/modules/apple_support/1.5.0/MODULE.bazel": "50341a62efbc483e8a2a6aec30994a58749bd7b885e18dd96aa8c33031e558ef", "https://bcr.bazel.build/modules/apple_support/1.5.0/source.json": "eb98a7627c0bc486b57f598ad8da50f6625d974c8f723e9ea71bd39f709c9862", "https://bcr.bazel.build/modules/bazel_features/1.1.0/MODULE.bazel": "cfd42ff3b815a5f39554d97182657f8c4b9719568eb7fded2b9135f084bf760b", "https://bcr.bazel.build/modules/bazel_features/1.1.1/MODULE.bazel": "27b8c79ef57efe08efccbd9dd6ef70d61b4798320b8d3c134fd571f78963dbcd", "https://bcr.bazel.build/modules/bazel_features/1.11.0/MODULE.bazel": "f9382337dd5a474c3b7d334c2f83e50b6eaedc284253334cf823044a26de03e8", - "https://bcr.bazel.build/modules/bazel_features/1.11.0/source.json": "c9320aa53cd1c441d24bd6b716da087ad7e4ff0d9742a9884587596edfe53015", + "https://bcr.bazel.build/modules/bazel_features/1.15.0/MODULE.bazel": "d38ff6e517149dc509406aca0db3ad1efdd890a85e049585b7234d04238e2a4d", + "https://bcr.bazel.build/modules/bazel_features/1.17.0/MODULE.bazel": "039de32d21b816b47bd42c778e0454217e9c9caac4a3cf8e15c7231ee3ddee4d", + "https://bcr.bazel.build/modules/bazel_features/1.18.0/MODULE.bazel": "1be0ae2557ab3a72a57aeb31b29be347bcdc5d2b1eb1e70f39e3851a7e97041a", + "https://bcr.bazel.build/modules/bazel_features/1.19.0/MODULE.bazel": "59adcdf28230d220f0067b1f435b8537dd033bfff8db21335ef9217919c7fb58", + "https://bcr.bazel.build/modules/bazel_features/1.28.0/MODULE.bazel": "4b4200e6cbf8fa335b2c3f43e1d6ef3e240319c33d43d60cc0fbd4b87ece299d", + "https://bcr.bazel.build/modules/bazel_features/1.36.0/MODULE.bazel": "596cb62090b039caf1cad1d52a8bc35cf188ca9a4e279a828005e7ee49a1bec3", + "https://bcr.bazel.build/modules/bazel_features/1.36.0/source.json": "279625cafa5b63cc0a8ee8448d93bc5ac1431f6000c50414051173fd22a6df3c", "https://bcr.bazel.build/modules/bazel_features/1.4.1/MODULE.bazel": "e45b6bb2350aff3e442ae1111c555e27eac1d915e77775f6fdc4b351b758b5d7", "https://bcr.bazel.build/modules/bazel_features/1.9.1/MODULE.bazel": "8f679097876a9b609ad1f60249c49d68bfab783dd9be012faf9d82547b14815a", "https://bcr.bazel.build/modules/bazel_skylib/1.0.3/MODULE.bazel": "bcb0fd896384802d1ad283b4e4eb4d718eebd8cb820b0a2c3a347fb971afd9d8", + "https://bcr.bazel.build/modules/bazel_skylib/1.1.1/MODULE.bazel": "1add3e7d93ff2e6998f9e118022c84d163917d912f5afafb3058e3d2f1545b5e", "https://bcr.bazel.build/modules/bazel_skylib/1.2.0/MODULE.bazel": "44fe84260e454ed94ad326352a698422dbe372b21a1ac9f3eab76eb531223686", "https://bcr.bazel.build/modules/bazel_skylib/1.2.1/MODULE.bazel": "f35baf9da0efe45fa3da1696ae906eea3d615ad41e2e3def4aeb4e8bc0ef9a7a", "https://bcr.bazel.build/modules/bazel_skylib/1.3.0/MODULE.bazel": "20228b92868bf5cfc41bda7afc8a8ba2a543201851de39d990ec957b513579c5", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.1/MODULE.bazel": "a0dcb779424be33100dcae821e9e27e4f2901d9dfd5333efe5ac6a8d7ab75e1d", + "https://bcr.bazel.build/modules/bazel_skylib/1.4.2/MODULE.bazel": "3bd40978e7a1fac911d5989e6b09d8f64921865a45822d8b09e815eaa726a651", "https://bcr.bazel.build/modules/bazel_skylib/1.5.0/MODULE.bazel": "32880f5e2945ce6a03d1fbd588e9198c0a959bb42297b2cfaf1685b7bc32e138", "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/MODULE.bazel": "8fdee2dbaace6c252131c00e1de4b165dc65af02ea278476187765e1a617b917", - "https://bcr.bazel.build/modules/bazel_skylib/1.6.1/source.json": "082ed5f9837901fada8c68c2f3ddc958bb22b6d654f71dd73f3df30d45d4b749", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.0/MODULE.bazel": "0db596f4563de7938de764cc8deeabec291f55e8ec15299718b93c4423e9796d", + "https://bcr.bazel.build/modules/bazel_skylib/1.7.1/MODULE.bazel": "3120d80c5861aa616222ec015332e5f8d3171e062e3e804a2a0253e1be26e59b", + "https://bcr.bazel.build/modules/bazel_skylib/1.8.1/MODULE.bazel": "88ade7293becda963e0e3ea33e7d54d3425127e0a326e0d17da085a5f1f03ff6", + "https://bcr.bazel.build/modules/bazel_skylib/1.8.1/source.json": "7ebaefba0b03efe59cac88ed5bbc67bcf59a3eff33af937345ede2a38b2d368a", "https://bcr.bazel.build/modules/buildozer/7.1.2/MODULE.bazel": "2e8dd40ede9c454042645fd8d8d0cd1527966aa5c919de86661e62953cd73d84", "https://bcr.bazel.build/modules/buildozer/7.1.2/source.json": "c9028a501d2db85793a6996205c8de120944f50a0d570438fcae0457a5f9d1f8", "https://bcr.bazel.build/modules/gazelle/0.32.0/MODULE.bazel": "b499f58a5d0d3537f3cf5b76d8ada18242f64ec474d8391247438bf04f58c7b8", "https://bcr.bazel.build/modules/gazelle/0.33.0/MODULE.bazel": "a13a0f279b462b784fb8dd52a4074526c4a2afe70e114c7d09066097a46b3350", "https://bcr.bazel.build/modules/gazelle/0.34.0/MODULE.bazel": "abdd8ce4d70978933209db92e436deb3a8b737859e9354fb5fd11fb5c2004c8a", "https://bcr.bazel.build/modules/gazelle/0.36.0/MODULE.bazel": "e375d5d6e9a6ca59b0cb38b0540bc9a05b6aa926d322f2de268ad267a2ee74c0", - "https://bcr.bazel.build/modules/gazelle/0.38.0/MODULE.bazel": "51bb3ca009bc9320492894aece6ba5f50aae68a39fff2567844b77fc12e2d0a5", - "https://bcr.bazel.build/modules/gazelle/0.38.0/source.json": "7fedf9b531bcbbe90b009e4d3aef478a2defb8b8a6e31e931445231e425fc37c", + "https://bcr.bazel.build/modules/gazelle/0.51.3/MODULE.bazel": "618a729142f66de1e2cb776d026413763be5b80d5e3d29ffb9d3d90c5defde90", + "https://bcr.bazel.build/modules/gazelle/0.51.3/source.json": "fbe5312a01fb4a2a58caff4a0d40dcf384b6f0bda75e85546663360da1d7538a", + "https://bcr.bazel.build/modules/google_benchmark/1.8.2/MODULE.bazel": "a70cf1bba851000ba93b58ae2f6d76490a9feb74192e57ab8e8ff13c34ec50cb", "https://bcr.bazel.build/modules/googletest/1.11.0/MODULE.bazel": "3a83f095183f66345ca86aa13c58b59f9f94a2f81999c093d4eeaa2d262d12f4", - "https://bcr.bazel.build/modules/googletest/1.11.0/source.json": "c73d9ef4268c91bd0c1cd88f1f9dfa08e814b1dbe89b5f594a9f08ba0244d206", + "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/MODULE.bazel": "22c31a561553727960057361aa33bf20fb2e98584bc4fec007906e27053f80c6", + "https://bcr.bazel.build/modules/googletest/1.14.0.bcr.1/source.json": "41e9e129f80d8c8bf103a7acc337b76e54fad1214ac0a7084bf24f4cd924b8b4", + "https://bcr.bazel.build/modules/googletest/1.14.0/MODULE.bazel": "cfbcbf3e6eac06ef9d85900f64424708cc08687d1b527f0ef65aa7517af8118f", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", + "https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d", + "https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902", + "https://bcr.bazel.build/modules/package_metadata/0.0.3/MODULE.bazel": "77890552ecea9e284b5424c9de827a58099348763a4359e975c359a83d4faa83", + "https://bcr.bazel.build/modules/package_metadata/0.0.5/MODULE.bazel": "ef4f9439e3270fdd6b9fd4dbc3d2f29d13888e44c529a1b243f7a31dfbc2e8e4", + "https://bcr.bazel.build/modules/package_metadata/0.0.5/source.json": "2326db2f6592578177751c3e1f74786b79382cd6008834c9d01ec865b9126a85", "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", "https://bcr.bazel.build/modules/platforms/0.0.11/MODULE.bazel": "0daefc49732e227caa8bfa834d65dc52e8cc18a2faf80df25e8caea151a9413f", - "https://bcr.bazel.build/modules/platforms/0.0.11/source.json": "f7e188b79ebedebfe75e9e1d098b8845226c7992b307e28e1496f23112e8fc29", "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee", "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37", "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615", "https://bcr.bazel.build/modules/platforms/0.0.7/MODULE.bazel": "72fd4a0ede9ee5c021f6a8dd92b503e089f46c227ba2813ff183b71616034814", + "https://bcr.bazel.build/modules/platforms/0.0.8/MODULE.bazel": "9f142c03e348f6d263719f5074b21ef3adf0b139ee4c5133e2aa35664da9eb2d", "https://bcr.bazel.build/modules/platforms/0.0.9/MODULE.bazel": "4a87a60c927b56ddd67db50c89acaa62f4ce2a1d2149ccb63ffd871d5ce29ebc", + "https://bcr.bazel.build/modules/platforms/1.0.0/MODULE.bazel": "f05feb42b48f1b3c225e4ccf351f367be0371411a803198ec34a389fb22aa580", + "https://bcr.bazel.build/modules/platforms/1.1.0/MODULE.bazel": "1c0c09f5bdcf4b3f924720d2478a3711cb39f4977019ca5988685e5b7e18b3d2", + "https://bcr.bazel.build/modules/platforms/1.1.0/source.json": "fcf351c47596c939140ab0d333dfdd08ed1ea6ce33c2fe70c12493a301cf1344", "https://bcr.bazel.build/modules/protobuf/21.7/MODULE.bazel": "a5a29bb89544f9b97edce05642fac225a808b5b7be74038ea3640fae2f8e66a7", - "https://bcr.bazel.build/modules/protobuf/21.7/source.json": "bbe500720421e582ff2d18b0802464205138c06056f443184de39fbb8187b09b", + "https://bcr.bazel.build/modules/protobuf/27.0/MODULE.bazel": "7873b60be88844a0a1d8f80b9d5d20cfbd8495a689b8763e76c6372998d3f64c", + "https://bcr.bazel.build/modules/protobuf/27.1/MODULE.bazel": "703a7b614728bb06647f965264967a8ef1c39e09e8f167b3ca0bb1fd80449c0d", + "https://bcr.bazel.build/modules/protobuf/29.0-rc2.bcr.1/MODULE.bazel": "52f4126f63a2f0bbf36b99c2a87648f08467a4eaf92ba726bc7d6a500bbf770c", + "https://bcr.bazel.build/modules/protobuf/29.0/MODULE.bazel": "319dc8bf4c679ff87e71b1ccfb5a6e90a6dbc4693501d471f48662ac46d04e4e", + "https://bcr.bazel.build/modules/protobuf/29.0/source.json": "b857f93c796750eef95f0d61ee378f3420d00ee1dd38627b27193aa482f4f981", "https://bcr.bazel.build/modules/protobuf/3.19.0/MODULE.bazel": "6b5fbb433f760a99a22b18b6850ed5784ef0e9928a72668b66e4d7ccd47db9b0", "https://bcr.bazel.build/modules/protobuf/3.19.2/MODULE.bazel": "532ffe5f2186b69fdde039efe6df13ba726ff338c6bc82275ad433013fa10573", "https://bcr.bazel.build/modules/protobuf/3.19.6/MODULE.bazel": "9233edc5e1f2ee276a60de3eaa47ac4132302ef9643238f23128fea53ea12858", + "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/MODULE.bazel": "88af1c246226d87e65be78ed49ecd1e6f5e98648558c14ce99176da041dc378e", + "https://bcr.bazel.build/modules/pybind11_bazel/2.11.1/source.json": "be4789e951dd5301282729fe3d4938995dc4c1a81c2ff150afc9f1b0504c6022", + "https://bcr.bazel.build/modules/re2/2023-09-01/MODULE.bazel": "cb3d511531b16cfc78a225a9e2136007a48cf8a677e4264baeab57fe78a80206", + "https://bcr.bazel.build/modules/re2/2023-09-01/source.json": "e044ce89c2883cd957a2969a43e79f7752f9656f6b20050b62f90ede21ec6eb4", + "https://bcr.bazel.build/modules/rules_android/0.1.1/MODULE.bazel": "48809ab0091b07ad0182defb787c4c5328bd3a278938415c00a7b69b50c4d3a8", + "https://bcr.bazel.build/modules/rules_android/0.1.1/source.json": "e6986b41626ee10bdc864937ffb6d6bf275bb5b9c65120e6137d56e6331f089e", "https://bcr.bazel.build/modules/rules_cc/0.0.1/MODULE.bazel": "cb2aa0747f84c6c3a78dad4e2049c154f08ab9d166b1273835a8174940365647", + "https://bcr.bazel.build/modules/rules_cc/0.0.10/MODULE.bazel": "ec1705118f7eaedd6e118508d3d26deba2a4e76476ada7e0e3965211be012002", + "https://bcr.bazel.build/modules/rules_cc/0.0.13/MODULE.bazel": "0e8529ed7b323dad0775ff924d2ae5af7640b23553dfcd4d34344c7e7a867191", + "https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc", + "https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87", + "https://bcr.bazel.build/modules/rules_cc/0.0.17/MODULE.bazel": "2ae1d8f4238ec67d7185d8861cb0a2cdf4bc608697c331b95bf990e69b62e64a", "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c", + "https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f", "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", - "https://bcr.bazel.build/modules/rules_cc/0.0.9/source.json": "1f1ba6fea244b616de4a554a0f4983c91a9301640c8fe0dd1d410254115c8430", + "https://bcr.bazel.build/modules/rules_cc/0.1.5/MODULE.bazel": "88dfc9361e8b5ae1008ac38f7cdfd45ad738e4fa676a3ad67d19204f045a1fd8", + "https://bcr.bazel.build/modules/rules_cc/0.1.5/source.json": "4bb4fed7f5499775d495739f785a5494a1f854645fa1bac5de131264f5acdf01", + "https://bcr.bazel.build/modules/rules_foreign_cc/0.9.0/MODULE.bazel": "c9e8c682bf75b0e7c704166d79b599f93b72cfca5ad7477df596947891feeef6", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8", + "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/source.json": "c8b1e2c717646f1702290959a3302a178fb639d987ab61d548105019f11e527e", "https://bcr.bazel.build/modules/rules_go/0.41.0/MODULE.bazel": "55861d8e8bb0e62cbd2896f60ff303f62ffcb0eddb74ecb0e5c0cbe36fc292c8", "https://bcr.bazel.build/modules/rules_go/0.42.0/MODULE.bazel": "8cfa875b9aa8c6fce2b2e5925e73c1388173ea3c32a0db4d2b4804b453c14270", "https://bcr.bazel.build/modules/rules_go/0.46.0/MODULE.bazel": "3477df8bdcc49e698b9d25f734c4f3a9f5931ff34ee48a2c662be168f5f2d3fd", - "https://bcr.bazel.build/modules/rules_go/0.47.0/MODULE.bazel": "e425890d2a4d668abc0f59d8388b70bf63ad025edec76a385c35d85882519417", - "https://bcr.bazel.build/modules/rules_go/0.50.1/MODULE.bazel": "b91a308dc5782bb0a8021ad4330c81fea5bda77f96b9e4c117b9b9c8f6665ee0", - "https://bcr.bazel.build/modules/rules_go/0.50.1/source.json": "205765fd30216c70321f84c9a967267684bdc74350af3f3c46c857d9f80a4fa2", + "https://bcr.bazel.build/modules/rules_go/0.59.0/MODULE.bazel": "b7e43e7414a3139a7547d1b4909b29085fbe5182b6c58cbe1ed4c6272815aeae", + "https://bcr.bazel.build/modules/rules_go/0.61.1/MODULE.bazel": "b599cc67f98e8dbe040631129fbd23f190a557f7be506d4781619d0fd4dbbbec", + "https://bcr.bazel.build/modules/rules_go/0.61.1/source.json": "ff52d46fca8e2ac87c610c11f05c3a9f0fa08dc4294664c6a31449092409c5aa", "https://bcr.bazel.build/modules/rules_java/4.0.0/MODULE.bazel": "5a78a7ae82cd1a33cef56dc578c7d2a46ed0dca12643ee45edbb8417899e6f74", + "https://bcr.bazel.build/modules/rules_java/5.3.5/MODULE.bazel": "a4ec4f2db570171e3e5eb753276ee4b389bae16b96207e9d3230895c99644b86", + "https://bcr.bazel.build/modules/rules_java/6.5.2/MODULE.bazel": "1d440d262d0e08453fa0c4d8f699ba81609ed0e9a9a0f02cd10b3e7942e61e31", + "https://bcr.bazel.build/modules/rules_java/7.10.0/MODULE.bazel": "530c3beb3067e870561739f1144329a21c851ff771cd752a49e06e3dc9c2e71a", + "https://bcr.bazel.build/modules/rules_java/7.12.2/MODULE.bazel": "579c505165ee757a4280ef83cda0150eea193eed3bef50b1004ba88b99da6de6", + "https://bcr.bazel.build/modules/rules_java/7.12.2/source.json": "b0890f9cda8ff1b8e691a3ac6037b5c14b7fd4134765a3946b89f31ea02e5884", + "https://bcr.bazel.build/modules/rules_java/7.2.0/MODULE.bazel": "06c0334c9be61e6cef2c8c84a7800cef502063269a5af25ceb100b192453d4ab", + "https://bcr.bazel.build/modules/rules_java/7.6.1/MODULE.bazel": "2f14b7e8a1aa2f67ae92bc69d1ec0fa8d9f827c4e17ff5e5f02e91caa3b2d0fe", "https://bcr.bazel.build/modules/rules_java/7.6.5/MODULE.bazel": "481164be5e02e4cab6e77a36927683263be56b7e36fef918b458d7a8a1ebadb1", - "https://bcr.bazel.build/modules/rules_java/7.6.5/source.json": "a805b889531d1690e3c72a7a7e47a870d00323186a9904b36af83aa3d053ee8d", "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/MODULE.bazel": "a56b85e418c83eb1839819f0b515c431010160383306d13ec21959ac412d2fe7", - "https://bcr.bazel.build/modules/rules_jvm_external/4.4.2/source.json": "a075731e1b46bc8425098512d038d416e966ab19684a10a34f4741295642fc35", + "https://bcr.bazel.build/modules/rules_jvm_external/5.1/MODULE.bazel": "33f6f999e03183f7d088c9be518a63467dfd0be94a11d0055fe2d210f89aa909", + "https://bcr.bazel.build/modules/rules_jvm_external/5.2/MODULE.bazel": "d9351ba35217ad0de03816ef3ed63f89d411349353077348a45348b096615036", + "https://bcr.bazel.build/modules/rules_jvm_external/6.3/MODULE.bazel": "c998e060b85f71e00de5ec552019347c8bca255062c990ac02d051bb80a38df0", + "https://bcr.bazel.build/modules/rules_jvm_external/6.3/source.json": "6f5f5a5a4419ae4e37c35a5bb0a6ae657ed40b7abc5a5189111b47fcebe43197", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/MODULE.bazel": "d269a01a18ee74d0335450b10f62c9ed81f2321d7958a2934e44272fe82dcef3", + "https://bcr.bazel.build/modules/rules_kotlin/1.9.6/source.json": "2faa4794364282db7c06600b7e5e34867a564ae91bda7cae7c29c64e9466b7d5", "https://bcr.bazel.build/modules/rules_license/0.0.3/MODULE.bazel": "627e9ab0247f7d1e05736b59dbb1b6871373de5ad31c3011880b4133cafd4bd0", "https://bcr.bazel.build/modules/rules_license/0.0.7/MODULE.bazel": "088fbeb0b6a419005b89cf93fe62d9517c0a2b8bb56af3244af65ecfe37e7d5d", - "https://bcr.bazel.build/modules/rules_license/0.0.7/source.json": "355cc5737a0f294e560d52b1b7a6492d4fff2caf0bef1a315df5a298fca2d34a", + "https://bcr.bazel.build/modules/rules_license/1.0.0/MODULE.bazel": "a7fda60eefdf3d8c827262ba499957e4df06f659330bbe6cdbdb975b768bb65c", + "https://bcr.bazel.build/modules/rules_license/1.0.0/source.json": "a52c89e54cc311196e478f8382df91c15f7a2bfdf4c6cd0e2675cc2ff0b56efb", "https://bcr.bazel.build/modules/rules_pkg/0.7.0/MODULE.bazel": "df99f03fc7934a4737122518bb87e667e62d780b610910f0447665a7e2be62dc", - "https://bcr.bazel.build/modules/rules_pkg/0.7.0/source.json": "c2557066e0c0342223ba592510ad3d812d4963b9024831f7f66fd0584dd8c66c", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/MODULE.bazel": "5b1df97dbc29623bccdf2b0dcd0f5cb08e2f2c9050aab1092fd39a41e82686ff", + "https://bcr.bazel.build/modules/rules_pkg/1.0.1/source.json": "bd82e5d7b9ce2d31e380dd9f50c111d678c3bdaca190cb76b0e1c71b05e1ba8a", "https://bcr.bazel.build/modules/rules_proto/4.0.0/MODULE.bazel": "a7a7b6ce9bee418c1a760b3d84f83a299ad6952f9903c67f19e4edd964894e06", "https://bcr.bazel.build/modules/rules_proto/5.3.0-21.7/MODULE.bazel": "e8dff86b0971688790ae75528fe1813f71809b5afd57facb44dad9e8eca631b7", - "https://bcr.bazel.build/modules/rules_proto/6.0.0/MODULE.bazel": "b531d7f09f58dce456cd61b4579ce8c86b38544da75184eadaf0a7cb7966453f", - "https://bcr.bazel.build/modules/rules_proto/6.0.0/source.json": "de77e10ff0ab16acbf54e6b46eecd37a99c5b290468ea1aee6e95eb1affdaed7", + "https://bcr.bazel.build/modules/rules_proto/6.0.2/MODULE.bazel": "ce916b775a62b90b61888052a416ccdda405212b6aaeb39522f7dc53431a5e73", + "https://bcr.bazel.build/modules/rules_proto/7.0.2/MODULE.bazel": "bf81793bd6d2ad89a37a40693e56c61b0ee30f7a7fdbaf3eabbf5f39de47dea2", + "https://bcr.bazel.build/modules/rules_proto/7.0.2/source.json": "1e5e7260ae32ef4f2b52fd1d0de8d03b606a44c91b694d2f1afb1d3b28a48ce1", "https://bcr.bazel.build/modules/rules_python/0.10.2/MODULE.bazel": "cc82bc96f2997baa545ab3ce73f196d040ffb8756fd2d66125a530031cd90e5f", "https://bcr.bazel.build/modules/rules_python/0.22.1/MODULE.bazel": "26114f0c0b5e93018c0c066d6673f1a2c3737c7e90af95eff30cfee38d0bbac7", - "https://bcr.bazel.build/modules/rules_python/0.22.1/source.json": "57226905e783bae7c37c2dd662be078728e48fa28ee4324a7eabcafb5a43d014", + "https://bcr.bazel.build/modules/rules_python/0.23.1/MODULE.bazel": "49ffccf0511cb8414de28321f5fcf2a31312b47c40cc21577144b7447f2bf300", + "https://bcr.bazel.build/modules/rules_python/0.25.0/MODULE.bazel": "72f1506841c920a1afec76975b35312410eea3aa7b63267436bfb1dd91d2d382", + "https://bcr.bazel.build/modules/rules_python/0.28.0/MODULE.bazel": "cba2573d870babc976664a912539b320cbaa7114cd3e8f053c720171cde331ed", + "https://bcr.bazel.build/modules/rules_python/0.31.0/MODULE.bazel": "93a43dc47ee570e6ec9f5779b2e64c1476a6ce921c48cc9a1678a91dd5f8fd58", + "https://bcr.bazel.build/modules/rules_python/0.31.0/source.json": "a41c836d4065888eef4377f2f27b6eea0fedb9b5adb1bab1970437373fe90dc7", "https://bcr.bazel.build/modules/rules_python/0.4.0/MODULE.bazel": "9208ee05fd48bf09ac60ed269791cf17fb343db56c8226a720fbb1cdf467166c", + "https://bcr.bazel.build/modules/rules_shell/0.2.0/MODULE.bazel": "fda8a652ab3c7d8fee214de05e7a9916d8b28082234e8d2c0094505c5268ed3c", + "https://bcr.bazel.build/modules/rules_shell/0.3.0/MODULE.bazel": "de4402cd12f4cc8fda2354fce179fdb068c0b9ca1ec2d2b17b3e21b24c1a937b", + "https://bcr.bazel.build/modules/rules_shell/0.3.0/source.json": "c55ed591aa5009401ddf80ded9762ac32c358d2517ee7820be981e2de9756cf3", "https://bcr.bazel.build/modules/stardoc/0.5.1/MODULE.bazel": "1a05d92974d0c122f5ccf09291442580317cdd859f07a8655f1db9a60374f9f8", - "https://bcr.bazel.build/modules/stardoc/0.5.1/source.json": "a96f95e02123320aa015b956f29c00cb818fa891ef823d55148e1a362caacf29", + "https://bcr.bazel.build/modules/stardoc/0.5.3/MODULE.bazel": "c7f6948dae6999bf0db32c1858ae345f112cacf98f174c7a8bb707e41b974f1c", + "https://bcr.bazel.build/modules/stardoc/0.7.0/MODULE.bazel": "05e3d6d30c099b6770e97da986c53bd31844d7f13d41412480ea265ac9e8079c", "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/MODULE.bazel": "7298990c00040a0e2f121f6c32544bab27d4452f80d9ce51349b1a28f3005c43", - "https://bcr.bazel.build/modules/upb/0.0.0-20220923-a547704/source.json": "f1ef7d3f9e0e26d4b23d1c39b5f5de71f584dd7d1b4ef83d9bbba6ec7a6a6459", "https://bcr.bazel.build/modules/zlib/1.2.11/MODULE.bazel": "07b389abc85fdbca459b69e2ec656ae5622873af3f845e1c9d80fe179f3effa0", "https://bcr.bazel.build/modules/zlib/1.2.12/MODULE.bazel": "3b1a8834ada2a883674be8cbd36ede1b6ec481477ada359cd2d3ddc562340b27", "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/MODULE.bazel": "af322bc08976524477c79d1e45e241b6efbeb918c497e8840b8ab116802dda79", - "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/source.json": "2be409ac3c7601245958cd4fcdff4288be79ed23bd690b4b951f500d54ee6e7d" + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/source.json": "2be409ac3c7601245958cd4fcdff4288be79ed23bd690b4b951f500d54ee6e7d", + "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198" }, "selectedYankedVersions": {}, "moduleExtensions": { @@ -110,6 +181,1081 @@ ] ] } + }, + "@@rules_kotlin~//src/main/starlark/core/repositories:bzlmod_setup.bzl%rules_kotlin_extensions": { + "general": { + "bzlTransitiveDigest": "fus14IFJ/1LGWWGKPH/U18VnJCoMjfDt1ckahqCnM0A=", + "usagesDigest": "aJF6fLy82rR95Ff5CZPAqxNoFgOMLMN5ImfBS0nhnkg=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "com_github_jetbrains_kotlin_git": { + "bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:compiler.bzl", + "ruleClassName": "kotlin_compiler_git_repository", + "attributes": { + "urls": [ + "https://github.com/JetBrains/kotlin/releases/download/v1.9.23/kotlin-compiler-1.9.23.zip" + ], + "sha256": "93137d3aab9afa9b27cb06a824c2324195c6b6f6179d8a8653f440f5bd58be88" + } + }, + "com_github_jetbrains_kotlin": { + "bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:compiler.bzl", + "ruleClassName": "kotlin_capabilities_repository", + "attributes": { + "git_repository_name": "com_github_jetbrains_kotlin_git", + "compiler_version": "1.9.23" + } + }, + "com_github_google_ksp": { + "bzlFile": "@@rules_kotlin~//src/main/starlark/core/repositories:ksp.bzl", + "ruleClassName": "ksp_compiler_plugin_repository", + "attributes": { + "urls": [ + "https://github.com/google/ksp/releases/download/1.9.23-1.0.20/artifacts.zip" + ], + "sha256": "ee0618755913ef7fd6511288a232e8fad24838b9af6ea73972a76e81053c8c2d", + "strip_version": "1.9.23-1.0.20" + } + }, + "com_github_pinterest_ktlint": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_file", + "attributes": { + "sha256": "01b2e0ef893383a50dbeb13970fe7fa3be36ca3e83259e01649945b09d736985", + "urls": [ + "https://github.com/pinterest/ktlint/releases/download/1.3.0/ktlint" + ], + "executable": true + } + }, + "rules_android": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "sha256": "cd06d15dd8bb59926e4d65f9003bfc20f9da4b2519985c27e190cddc8b7a7806", + "strip_prefix": "rules_android-0.1.1", + "urls": [ + "https://github.com/bazelbuild/rules_android/archive/v0.1.1.zip" + ] + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_kotlin~", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@rules_python~//python/extensions:python.bzl%python": { + "general": { + "bzlTransitiveDigest": "8vDKUdCc6qEk2/YsFiPsFO1Jqgl+XPFRklapOxMAbE8=", + "usagesDigest": "IHpGmPnz4x/hXQJB4cb/bz6qK+Grwju5oLmlavyjbFo=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": { + "RULES_PYTHON_BZLMOD_DEBUG": null + }, + "generatedRepoSpecs": { + "python_3_8_aarch64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "1825b1f7220bc93ff143f2e70b5c6a79c6469e0eeb40824e07a7277f59aabfda", + "patches": [], + "platform": "aarch64-apple-darwin", + "python_version": "3.8.18", + "release_filename": "20231002/cpython-3.8.18+20231002-aarch64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.8.18+20231002-aarch64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_8_aarch64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "236a300f386ead02ca98dbddbc026ff4ef4de6701a394106e291ff8b75445ee1", + "patches": [], + "platform": "aarch64-unknown-linux-gnu", + "python_version": "3.8.18", + "release_filename": "20231002/cpython-3.8.18+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.8.18+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_8_x86_64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "fcf04532e644644213977242cd724fe5e84c0a5ac92ae038e07f1b01b474fca3", + "patches": [], + "platform": "x86_64-apple-darwin", + "python_version": "3.8.18", + "release_filename": "20231002/cpython-3.8.18+20231002-x86_64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.8.18+20231002-x86_64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_8_x86_64-pc-windows-msvc": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "a9d203e78caed94de368d154e841610cef6f6b484738573f4ae9059d37e898a5", + "patches": [], + "platform": "x86_64-pc-windows-msvc", + "python_version": "3.8.18", + "release_filename": "20231002/cpython-3.8.18+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.8.18+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_8_x86_64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "1e8a3babd1500111359b0f5675d770984bcbcb2cc8890b117394f0ed342fb9ec", + "patches": [], + "platform": "x86_64-unknown-linux-gnu", + "python_version": "3.8.18", + "release_filename": "20231002/cpython-3.8.18+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.8.18+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_8_host": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "host_toolchain", + "attributes": { + "python_version": "3.8.18", + "user_repository_name": "python_3_8", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_8": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "toolchain_aliases", + "attributes": { + "python_version": "3.8.18", + "user_repository_name": "python_3_8", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_9_aarch64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "fdc4054837e37b69798c2ef796222a480bc1f80e8ad3a01a95d0168d8282a007", + "patches": [], + "platform": "aarch64-apple-darwin", + "python_version": "3.9.18", + "release_filename": "20231002/cpython-3.9.18+20231002-aarch64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-aarch64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_9_aarch64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "1e0a3e8ce8e58901a259748c0ab640d2b8294713782d14229e882c6898b2fb36", + "patches": [], + "platform": "aarch64-unknown-linux-gnu", + "python_version": "3.9.18", + "release_filename": "20231002/cpython-3.9.18+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_9_ppc64le-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "101c38b22fb2f5a0945156da4259c8e9efa0c08de9d7f59afa51e7ce6e22a1cc", + "patches": [], + "platform": "ppc64le-unknown-linux-gnu", + "python_version": "3.9.18", + "release_filename": "20231002/cpython-3.9.18+20231002-ppc64le-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-ppc64le-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_9_s390x-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "eee31e55ffbc1f460d7b17f05dd89e45a2636f374a6f8dc29ea13d0497f7f586", + "patches": [], + "platform": "s390x-unknown-linux-gnu", + "python_version": "3.9.18", + "release_filename": "20231002/cpython-3.9.18+20231002-s390x-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-s390x-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_9_x86_64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "82231cb77d4a5c8081a1a1d5b8ae440abe6993514eb77a926c826e9a69a94fb1", + "patches": [], + "platform": "x86_64-apple-darwin", + "python_version": "3.9.18", + "release_filename": "20231002/cpython-3.9.18+20231002-x86_64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-x86_64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_9_x86_64-pc-windows-msvc": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "02ea7bb64524886bd2b05d6b6be4401035e4ba4319146f274f0bcd992822cd75", + "patches": [], + "platform": "x86_64-pc-windows-msvc", + "python_version": "3.9.18", + "release_filename": "20231002/cpython-3.9.18+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_9_x86_64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "f3ff38b1ccae7dcebd8bbf2e533c9a984fac881de0ffd1636fbb61842bd924de", + "patches": [], + "platform": "x86_64-unknown-linux-gnu", + "python_version": "3.9.18", + "release_filename": "20231002/cpython-3.9.18+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.9.18+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_9_host": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "host_toolchain", + "attributes": { + "python_version": "3.9.18", + "user_repository_name": "python_3_9", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_9": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "toolchain_aliases", + "attributes": { + "python_version": "3.9.18", + "user_repository_name": "python_3_9", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_10_aarch64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "fd027b1dedf1ea034cdaa272e91771bdf75ddef4c8653b05d224a0645aa2ca3c", + "patches": [], + "platform": "aarch64-apple-darwin", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-aarch64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-aarch64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_aarch64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "8675915ff454ed2f1597e27794bc7df44f5933c26b94aa06af510fe91b58bb97", + "patches": [], + "platform": "aarch64-unknown-linux-gnu", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-aarch64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_ppc64le-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "f3f9c43eec1a0c3f72845d0b705da17a336d3906b7df212d2640b8f47e8ff375", + "patches": [], + "platform": "ppc64le-unknown-linux-gnu", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-ppc64le-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-ppc64le-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_s390x-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "859f6cfe9aedb6e8858892fdc124037e83ab05f28d42a7acd314c6a16d6bd66c", + "patches": [], + "platform": "s390x-unknown-linux-gnu", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-s390x-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-s390x-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_x86_64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "be0b19b6af1f7d8c667e5abef5505ad06cf72e5a11bb5844970c395a7e5b1275", + "patches": [], + "platform": "x86_64-apple-darwin", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-x86_64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-x86_64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_x86_64-pc-windows-msvc": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "b8d930ce0d04bda83037ad3653d7450f8907c88e24bb8255a29b8dab8930d6f1", + "patches": [], + "platform": "x86_64-pc-windows-msvc", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-x86_64-pc-windows-msvc-shared-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_x86_64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "5d0429c67c992da19ba3eb58b3acd0b35ec5e915b8cae9a4aa8ca565c423847a", + "patches": [], + "platform": "x86_64-unknown-linux-gnu", + "python_version": "3.10.13", + "release_filename": "20231002/cpython-3.10.13+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20231002/cpython-3.10.13+20231002-x86_64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_10_host": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "host_toolchain", + "attributes": { + "python_version": "3.10.13", + "user_repository_name": "python_3_10", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_10": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "toolchain_aliases", + "attributes": { + "python_version": "3.10.13", + "user_repository_name": "python_3_10", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_11_aarch64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "b042c966920cf8465385ca3522986b12d745151a72c060991088977ca36d3883", + "patches": [], + "platform": "aarch64-apple-darwin", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-aarch64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-aarch64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11_aarch64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "b102eaf865eb715aa98a8a2ef19037b6cc3ae7dfd4a632802650f29de635aa13", + "patches": [], + "platform": "aarch64-unknown-linux-gnu", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-aarch64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-aarch64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11_ppc64le-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "b44e1b74afe75c7b19143413632c4386708ae229117f8f950c2094e9681d34c7", + "patches": [], + "platform": "ppc64le-unknown-linux-gnu", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-ppc64le-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-ppc64le-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11_s390x-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "49520e3ff494708020f306e30b0964f079170be83e956be4504f850557378a22", + "patches": [], + "platform": "s390x-unknown-linux-gnu", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-s390x-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-s390x-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11_x86_64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "a0e615eef1fafdc742da0008425a9030b7ea68a4ae4e73ac557ef27b112836d4", + "patches": [], + "platform": "x86_64-apple-darwin", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-x86_64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-x86_64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11_x86_64-pc-windows-msvc": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "67077e6fa918e4f4fd60ba169820b00be7c390c497bf9bc9cab2c255ea8e6f3e", + "patches": [], + "platform": "x86_64-pc-windows-msvc", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-x86_64-pc-windows-msvc-shared-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-x86_64-pc-windows-msvc-shared-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11_x86_64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "4a51ce60007a6facf64e5495f4cf322e311ba9f39a8cd3f3e4c026eae488e140", + "patches": [], + "platform": "x86_64-unknown-linux-gnu", + "python_version": "3.11.7", + "release_filename": "20240107/cpython-3.11.7+20240107-x86_64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.11.7+20240107-x86_64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_11_host": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "host_toolchain", + "attributes": { + "python_version": "3.11.7", + "user_repository_name": "python_3_11", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_11": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "toolchain_aliases", + "attributes": { + "python_version": "3.11.7", + "user_repository_name": "python_3_11", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_12_aarch64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "f93f8375ca6ac0a35d58ff007043cbd3a88d9609113f1cb59cf7c8d215f064af", + "patches": [], + "platform": "aarch64-apple-darwin", + "python_version": "3.12.1", + "release_filename": "20240107/cpython-3.12.1+20240107-aarch64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.12.1+20240107-aarch64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_12_aarch64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "236533ef20e665007a111c2f36efb59c87ae195ad7dca223b6dc03fb07064f0b", + "patches": [], + "platform": "aarch64-unknown-linux-gnu", + "python_version": "3.12.1", + "release_filename": "20240107/cpython-3.12.1+20240107-aarch64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.12.1+20240107-aarch64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_12_ppc64le-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "78051f0d1411ee62bc2af5edfccf6e8400ac4ef82887a2affc19a7ace6a05267", + "patches": [], + "platform": "ppc64le-unknown-linux-gnu", + "python_version": "3.12.1", + "release_filename": "20240107/cpython-3.12.1+20240107-ppc64le-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.12.1+20240107-ppc64le-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_12_s390x-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "60631211c701f8d2c56e5dd7b154e68868128a019b9db1d53a264f56c0d4aee2", + "patches": [], + "platform": "s390x-unknown-linux-gnu", + "python_version": "3.12.1", + "release_filename": "20240107/cpython-3.12.1+20240107-s390x-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.12.1+20240107-s390x-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_12_x86_64-apple-darwin": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "eca96158c1568dedd9a0b3425375637a83764d1fa74446438293089a8bfac1f8", + "patches": [], + "platform": "x86_64-apple-darwin", + "python_version": "3.12.1", + "release_filename": "20240107/cpython-3.12.1+20240107-x86_64-apple-darwin-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.12.1+20240107-x86_64-apple-darwin-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_12_x86_64-pc-windows-msvc": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "fd5a9e0f41959d0341246d3643f2b8794f638adc0cec8dd5e1b6465198eae08a", + "patches": [], + "platform": "x86_64-pc-windows-msvc", + "python_version": "3.12.1", + "release_filename": "20240107/cpython-3.12.1+20240107-x86_64-pc-windows-msvc-shared-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.12.1+20240107-x86_64-pc-windows-msvc-shared-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_12_x86_64-unknown-linux-gnu": { + "bzlFile": "@@rules_python~//python:repositories.bzl", + "ruleClassName": "python_repository", + "attributes": { + "sha256": "74e330b8212ca22fd4d9a2003b9eec14892155566738febc8e5e572f267b9472", + "patches": [], + "platform": "x86_64-unknown-linux-gnu", + "python_version": "3.12.1", + "release_filename": "20240107/cpython-3.12.1+20240107-x86_64-unknown-linux-gnu-install_only.tar.gz", + "urls": [ + "https://github.com/indygreg/python-build-standalone/releases/download/20240107/cpython-3.12.1+20240107-x86_64-unknown-linux-gnu-install_only.tar.gz" + ], + "distutils_content": "", + "strip_prefix": "python", + "coverage_tool": "", + "ignore_root_user_error": false + } + }, + "python_3_12_host": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "host_toolchain", + "attributes": { + "python_version": "3.12.1", + "user_repository_name": "python_3_12", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "python_3_12": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "toolchain_aliases", + "attributes": { + "python_version": "3.12.1", + "user_repository_name": "python_3_12", + "platforms": [ + "aarch64-apple-darwin", + "aarch64-unknown-linux-gnu", + "ppc64le-unknown-linux-gnu", + "s390x-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu" + ] + } + }, + "pythons_hub": { + "bzlFile": "@@rules_python~//python/private/bzlmod:pythons_hub.bzl", + "ruleClassName": "hub_repo", + "attributes": { + "default_python_version": "3.11", + "toolchain_prefixes": [ + "_0000_python_3_8_", + "_0001_python_3_9_", + "_0002_python_3_10_", + "_0003_python_3_12_", + "_0004_python_3_11_" + ], + "toolchain_python_versions": [ + "3.8", + "3.9", + "3.10", + "3.12", + "3.11" + ], + "toolchain_set_python_version_constraints": [ + "True", + "True", + "True", + "True", + "False" + ], + "toolchain_user_repository_names": [ + "python_3_8", + "python_3_9", + "python_3_10", + "python_3_12", + "python_3_11" + ] + } + }, + "python_versions": { + "bzlFile": "@@rules_python~//python/private:toolchains_repo.bzl", + "ruleClassName": "multi_toolchain_aliases", + "attributes": { + "python_versions": { + "3.8": "python_3_8", + "3.9": "python_3_9", + "3.10": "python_3_10", + "3.11": "python_3_11", + "3.12": "python_3_12" + } + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_python~", + "bazel_skylib", + "bazel_skylib~" + ], + [ + "rules_python~", + "bazel_tools", + "bazel_tools" + ] + ] + } + }, + "@@rules_python~//python/private/bzlmod:internal_deps.bzl%internal_deps": { + "general": { + "bzlTransitiveDigest": "7yogJIhmw7i9Wq/n9sQB8N0F84220dJbw64SjOwrmQk=", + "usagesDigest": "r7vtlnQfWxEwrL+QFXux06yzeWEkq/hrcwAssoCoSLY=", + "recordedFileInputs": {}, + "recordedDirentsInputs": {}, + "envVariables": {}, + "generatedRepoSpecs": { + "rules_python_internal": { + "bzlFile": "@@rules_python~//python/private:internal_config_repo.bzl", + "ruleClassName": "internal_config_repo", + "attributes": {} + }, + "pypi__build": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/58/91/17b00d5fac63d3dca605f1b8269ba3c65e98059e1fd99d00283e42a454f0/build-0.10.0-py3-none-any.whl", + "sha256": "af266720050a66c893a6096a2f410989eeac74ff9a68ba194b3f6473e8e26171", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__click": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/00/2e/d53fa4befbf2cfa713304affc7ca780ce4fc1fd8710527771b58311a3229/click-8.1.7-py3-none-any.whl", + "sha256": "ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__colorama": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", + "sha256": "4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__importlib_metadata": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/cc/37/db7ba97e676af155f5fcb1a35466f446eadc9104e25b83366e8088c9c926/importlib_metadata-6.8.0-py3-none-any.whl", + "sha256": "3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__installer": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/e5/ca/1172b6638d52f2d6caa2dd262ec4c811ba59eee96d54a7701930726bce18/installer-0.7.0-py3-none-any.whl", + "sha256": "05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__more_itertools": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/5a/cb/6dce742ea14e47d6f565589e859ad225f2a5de576d7696e0623b784e226b/more_itertools-10.1.0-py3-none-any.whl", + "sha256": "64e0735fcfdc6f3464ea133afe8ea4483b1c5fe3a3d69852e6503b43a0b222e6", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__packaging": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/ab/c3/57f0601a2d4fe15de7a553c00adbc901425661bf048f2a22dfc500caf121/packaging-23.1-py3-none-any.whl", + "sha256": "994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__pep517": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/ee/2f/ef63e64e9429111e73d3d6cbee80591672d16f2725e648ebc52096f3d323/pep517-0.13.0-py3-none-any.whl", + "sha256": "4ba4446d80aed5b5eac6509ade100bff3e7943a8489de249654a5ae9b33ee35b", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__pip": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/50/c2/e06851e8cc28dcad7c155f4753da8833ac06a5c704c109313b8d5a62968a/pip-23.2.1-py3-none-any.whl", + "sha256": "7ccf472345f20d35bdc9d1841ff5f313260c2c33fe417f48c30ac46cccabf5be", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__pip_tools": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/e8/df/47e6267c6b5cdae867adbdd84b437393e6202ce4322de0a5e0b92960e1d6/pip_tools-7.3.0-py3-none-any.whl", + "sha256": "8717693288720a8c6ebd07149c93ab0be1fced0b5191df9e9decd3263e20d85e", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__pyproject_hooks": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/d5/ea/9ae603de7fbb3df820b23a70f6aff92bf8c7770043254ad8d2dc9d6bcba4/pyproject_hooks-1.0.0-py3-none-any.whl", + "sha256": "283c11acd6b928d2f6a7c73fa0d01cb2bdc5f07c57a2eeb6e83d5e56b97976f8", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__setuptools": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/4f/ab/0bcfebdfc3bfa8554b2b2c97a555569c4c1ebc74ea288741ea8326c51906/setuptools-68.1.2-py3-none-any.whl", + "sha256": "3d8083eed2d13afc9426f227b24fd1659489ec107c0e86cec2ffdde5c92e790b", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__tomli": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/97/75/10a9ebee3fd790d20926a90a2547f0bf78f371b2f13aa822c759680ca7b9/tomli-2.0.1-py3-none-any.whl", + "sha256": "939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__wheel": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/b8/8b/31273bf66016be6ad22bb7345c37ff350276cfd46e389a0c2ac5da9d9073/wheel-0.41.2-py3-none-any.whl", + "sha256": "75909db2664838d015e3d9139004ee16711748a52c8f336b52882266540215d8", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + }, + "pypi__zipp": { + "bzlFile": "@@bazel_tools//tools/build_defs/repo:http.bzl", + "ruleClassName": "http_archive", + "attributes": { + "url": "https://files.pythonhosted.org/packages/8c/08/d3006317aefe25ea79d3b76c9650afabaf6d63d1c8443b236e7405447503/zipp-3.16.2-py3-none-any.whl", + "sha256": "679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0", + "type": "zip", + "build_file_content": "package(default_visibility = [\"//visibility:public\"])\n\nload(\"@rules_python//python:defs.bzl\", \"py_library\")\n\npy_library(\n name = \"lib\",\n srcs = glob([\"**/*.py\"]),\n data = glob([\"**/*\"], exclude=[\n # These entries include those put into user-installed dependencies by\n # data_exclude in /python/pip_install/tools/bazel.py\n # to avoid non-determinism following pip install's behavior.\n \"**/*.py\",\n \"**/*.pyc\",\n \"**/*.pyc.*\", # During pyc creation, temp files named *.pyc.NNN are created\n \"**/* *\",\n \"**/*.dist-info/RECORD\",\n \"BUILD\",\n \"WORKSPACE\",\n ]),\n # This makes this directory a top-level in the python import\n # search path for anything that depends on this.\n imports = [\".\"],\n)\n" + } + } + }, + "recordedRepoMappingEntries": [ + [ + "rules_python~", + "bazel_tools", + "bazel_tools" + ] + ] + } } } } diff --git a/README.md b/README.md index 8ad2d58a..461a2e30 100644 --- a/README.md +++ b/README.md @@ -8,24 +8,24 @@ The [WasmEdge](https://github.com/WasmEdge/WasmEdge) is a high performance WebAs ## Getting Started -The `WasmEdge-go` requires `golang` version >= `1.22`. Please check your `golang` version before installation. +The `WasmEdge-go` requires `golang` version >= `1.25`. Please check your `golang` version before installation. Developers can [download golang here](https://golang.org/dl/). ```bash $ go version -go version go1.23.1 linux/amd64 +go version go1.25.0 linux/amd64 ``` Developers must [install the WasmEdge shared library](https://wasmedge.org/docs/start/install) with the same `WasmEdge-go` release version. ```bash -curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s -- -v 0.14.0 +curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install_v2.sh | bash -s -- -v 0.17.1 ``` For the developers need the `WasmEdge-TensorFlow` or `WasmEdge-Image` plug-ins for `WasmEdge-go`, please install the `WasmEdge` with the corresponding plug-ins: ```bash -curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s -- --plugins wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image -v 0.14.0 +curl -sSf https://raw.githubusercontent.com/WasmEdge/WasmEdge/master/utils/install.sh | bash -s -- --plugins wasmedge_tensorflow wasmedge_tensorflowlite wasmedge_image -v 0.17.1 ``` > Note: Please refer to the [install guide for plug-ins](https://wasmedge.org/docs/start/install/#install-wasmedge-plug-ins-and-dependencies) to check that you've installed the plug-ins with their dependencies. @@ -36,6 +36,22 @@ For examples, please refer to the [example repository](https://github.com/second Please refer to the [API Documentation](https://wasmedge.org/docs/embed/go/reference/latest) for details. +## Testing + +The `wasmedge` package ships unit tests, and the `spectest` package runs the +WASM specification test suites in the interpreter, AOT, and JIT modes: + +```bash +# Unit tests of the API surface: +go test ./wasmedge/ + +# WASM spec tests (the suite is downloaded and cached on the first run): +go test ./spectest/ -run TestSpecInterpreter +go test ./spectest/ -timeout 60m # all of interpreter, AOT, and JIT +``` + +See [spectest/README.md](spectest/README.md) for details. + ## Bazel Support on Windows To use this library with Bazel on Windows, you can define the WasmEdge C library as a local dependency. Below is an example of how to configure this in your project. diff --git a/wasmedge/BUILD.bazel b/wasmedge/BUILD.bazel index 955545b0..b6e98a18 100644 --- a/wasmedge/BUILD.bazel +++ b/wasmedge/BUILD.bazel @@ -35,6 +35,24 @@ go_library( go_test( name = "go_default_test", - srcs = ["limit_test.go"], + srcs = [ + "ast_test.go", + "cli_test.go", + "compiler_test.go", + "configure_test.go", + "executor_test.go", + "instance_test.go", + "limit_test.go", + "log_test.go", + "plugin_test.go", + "result_test.go", + "statistics_test.go", + "store_test.go", + "value_test.go", + "version_test.go", + "vm_test.go", + "wasmedge_test.go", + ], + data = glob(["testdata/**"]), embed = [":go_default_library"], )