github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/engine/wazevo/hostmodule.go (about)

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