Skip to content

Commit

Permalink
Merge pull request #106 from Peefy/feat-kcl-go-wasm-lib-example
Browse files Browse the repository at this point in the history
feat: add kcl-go wasm lib example
  • Loading branch information
Peefy authored Jul 12, 2024
2 parents f32a73e + 2fc760b commit 9b5a823
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 0 deletions.
27 changes: 27 additions & 0 deletions wasm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,33 @@ fn main() -> Result<()> {
}
```

### Go

```go
package main

import (
"fmt"

"github.com/kcl-lang/wasm-lib/pkg/module"
)

func main() {
m, err := module.New("../../kcl.wasm")
if err != nil {
panic(err)
}
result, err := m.Run(&module.RunOptions{
Filename: "test.k",
Source: "a = 1",
})
if err != nil {
panic(err)
}
fmt.Println(result)
}
```

## Developing

- Install `node.js`
Expand Down
5 changes: 5 additions & 0 deletions wasm/examples/go/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/kcl-lang/wasm-lib

go 1.22.1

require github.com/bytecodealliance/wasmtime-go/v22 v22.0.1
10 changes: 10 additions & 0 deletions wasm/examples/go/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
github.com/bytecodealliance/wasmtime-go/v22 v22.0.1 h1:/wWcvXyffeWeDQQte3Db/fHVEov8HhxfVJ43gz9xVcM=
github.com/bytecodealliance/wasmtime-go/v22 v22.0.1/go.mod h1:knqkvjTLavLtAXnA5NJUM0qbRiPJCVWPLXfYu75kZSo=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
22 changes: 22 additions & 0 deletions wasm/examples/go/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package main

import (
"fmt"

"github.com/kcl-lang/wasm-lib/pkg/module"
)

func main() {
m, err := module.New("../../kcl.wasm")
if err != nil {
panic(err)
}
result, err := m.Run(&module.RunOptions{
Filename: "test.k",
Source: "a = 1",
})
if err != nil {
panic(err)
}
fmt.Println(result)
}
108 changes: 108 additions & 0 deletions wasm/examples/go/pkg/module/module.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package module

import (
"fmt"
"log"
"os"
"path/filepath"

"github.com/bytecodealliance/wasmtime-go/v22"
)

type RunOptions struct {
Filename string
Source string
}

type KCLModule struct {
Instance *wasmtime.Instance
Store *wasmtime.Store
Memory *wasmtime.Memory
KclMalloc *wasmtime.Func
KclFree *wasmtime.Func
KclRun *wasmtime.Func
}

func New(path string) (*KCLModule, error) {
dir, err := os.MkdirTemp("", "out")
if err != nil {
log.Fatal(err)
}
defer os.RemoveAll(dir)
stdoutPath := filepath.Join(dir, "stdout")
engine := wasmtime.NewEngine()
module, err := wasmtime.NewModuleFromFile(engine, path)
if err != nil {
return nil, err
}
linker := wasmtime.NewLinker(engine)
err = linker.DefineWasi()
linker.FuncWrap("env", "kclvm_plugin_invoke_json_wasm", func(_name int32, _args int32, _kwargs int32) int32 {
return 0
})
if err != nil {
return nil, err
}
wasiConfig := wasmtime.NewWasiConfig()
wasiConfig.SetStdoutFile(stdoutPath)
store := wasmtime.NewStore(engine)
store.SetWasi(wasiConfig)
instance, err := linker.Instantiate(store, module)
if err != nil {
return nil, err
}
memory := instance.Exports(store)[0].Memory()
malloc := instance.GetFunc(store, "kcl_malloc")
free := instance.GetFunc(store, "kcl_free")
run := instance.GetFunc(store, "kcl_run")
return &KCLModule{
Instance: instance,
Store: store,
Memory: memory,
KclMalloc: malloc,
KclFree: free,
KclRun: run,
}, nil
}

func (m *KCLModule) Run(opts *RunOptions) (string, error) {
filenamePtr, filenameLen, err := copyStringToWasmMemory(m.Store, m.KclMalloc, m.Memory, opts.Filename)
if err != nil {
return "", err
}
defer func() {
err := freeMemory(m.Store, m.KclFree, filenamePtr, filenameLen)
if err != nil {
fmt.Println("Failed to free filename memory:", err)
}
}()

sourcePtr, sourceLen, err := copyStringToWasmMemory(m.Store, m.KclMalloc, m.Memory, opts.Source)
if err != nil {
return "", err
}
defer func() {
err := freeMemory(m.Store, m.KclFree, sourcePtr, sourceLen)
if err != nil {
fmt.Println("Failed to free source memory:", err)
}
}()

resultPtr, err := m.KclRun.Call(m.Store, filenamePtr, sourcePtr)
if err != nil {
return "", err
}

result, _, err := copyCStrFromWasmMemory(m.Store, m.Memory, resultPtr.(int32))
if err != nil {
return "", err
}
defer func() {
err := freeMemory(m.Store, m.KclFree, resultPtr.(int32), int32(len(result)))
if err != nil {
fmt.Println("Failed to free result memory:", err)
}
}()

return result, nil
}
45 changes: 45 additions & 0 deletions wasm/examples/go/pkg/module/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package module

import "github.com/bytecodealliance/wasmtime-go/v22"

func copyStringToWasmMemory(
store *wasmtime.Store,
malloc *wasmtime.Func,
memory *wasmtime.Memory,
str string,
) (int32, int32, error) {
bytes := []byte(str)
length := len(bytes)
ptr, err := malloc.Call(store, int32(length))
if err != nil {
return 0, 0, err
}
data := memory.UnsafeData(store)
idx := ptr.(int32)
copy(data[idx:(int(idx)+length)], bytes)
return idx, int32(length), nil
}

func copyCStrFromWasmMemory(
store *wasmtime.Store,
memory *wasmtime.Memory,
ptr int32,
) (string, int32, error) {
data := memory.UnsafeData(store)
end := ptr
for data[end] != 0 {
end++
}
result := string(data[ptr:end])
return result, end + 1 - ptr, nil
}

func freeMemory(
store *wasmtime.Store,
free *wasmtime.Func,
ptr int32,
length int32,
) error {
_, err := free.Call(store, ptr, length)
return err
}

0 comments on commit 9b5a823

Please sign in to comment.