hostmodule.go

 1package wazevo
 2
 3import (
 4	"encoding/binary"
 5	"reflect"
 6	"unsafe"
 7
 8	"github.com/tetratelabs/wazero/experimental"
 9	"github.com/tetratelabs/wazero/internal/wasm"
10)
11
12func buildHostModuleOpaque(m *wasm.Module, listeners []experimental.FunctionListener) moduleContextOpaque {
13	size := len(m.CodeSection)*16 + 32
14	ret := newAlignedOpaque(size)
15
16	binary.LittleEndian.PutUint64(ret[0:], uint64(uintptr(unsafe.Pointer(m))))
17
18	if len(listeners) > 0 {
19		//nolint:staticcheck
20		sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&listeners))
21		binary.LittleEndian.PutUint64(ret[8:], uint64(sliceHeader.Data))
22		binary.LittleEndian.PutUint64(ret[16:], uint64(sliceHeader.Len))
23		binary.LittleEndian.PutUint64(ret[24:], uint64(sliceHeader.Cap))
24	}
25
26	offset := 32
27	for i := range m.CodeSection {
28		goFn := m.CodeSection[i].GoFunc
29		writeIface(goFn, ret[offset:])
30		offset += 16
31	}
32	return ret
33}
34
35func hostModuleFromOpaque(opaqueBegin uintptr) *wasm.Module {
36	var opaqueViewOverSlice []byte
37	//nolint:staticcheck
38	sh := (*reflect.SliceHeader)(unsafe.Pointer(&opaqueViewOverSlice))
39	sh.Data = opaqueBegin
40	sh.Len = 32
41	sh.Cap = 32
42	return *(**wasm.Module)(unsafe.Pointer(&opaqueViewOverSlice[0]))
43}
44
45func hostModuleListenersSliceFromOpaque(opaqueBegin uintptr) []experimental.FunctionListener {
46	var opaqueViewOverSlice []byte
47	//nolint:staticcheck
48	sh := (*reflect.SliceHeader)(unsafe.Pointer(&opaqueViewOverSlice))
49	sh.Data = opaqueBegin
50	sh.Len = 32
51	sh.Cap = 32
52
53	b := binary.LittleEndian.Uint64(opaqueViewOverSlice[8:])
54	l := binary.LittleEndian.Uint64(opaqueViewOverSlice[16:])
55	c := binary.LittleEndian.Uint64(opaqueViewOverSlice[24:])
56	var ret []experimental.FunctionListener
57	//nolint:staticcheck
58	sh = (*reflect.SliceHeader)(unsafe.Pointer(&ret))
59	sh.Data = uintptr(b)
60	sh.Len = int(l)
61	sh.Cap = int(c)
62	return ret
63}
64
65func hostModuleGoFuncFromOpaque[T any](index int, opaqueBegin uintptr) T {
66	offset := uintptr(index*16) + 32
67	ptr := opaqueBegin + offset
68
69	var opaqueViewOverFunction []byte
70	//nolint:staticcheck
71	sh := (*reflect.SliceHeader)(unsafe.Pointer(&opaqueViewOverFunction))
72	sh.Data = ptr
73	sh.Len = 16
74	sh.Cap = 16
75	return readIface(opaqueViewOverFunction).(T)
76}
77
78func writeIface(goFn interface{}, buf []byte) {
79	goFnIface := *(*[2]uint64)(unsafe.Pointer(&goFn))
80	binary.LittleEndian.PutUint64(buf, goFnIface[0])
81	binary.LittleEndian.PutUint64(buf[8:], goFnIface[1])
82}
83
84func readIface(buf []byte) interface{} {
85	b := binary.LittleEndian.Uint64(buf)
86	s := binary.LittleEndian.Uint64(buf[8:])
87	return *(*interface{})(unsafe.Pointer(&[2]uint64{b, s}))
88}