//go:build !purego package assembler import ( "errors" "fmt" "git.gammaspectra.live/WeebDataHoarder/compute-go/assembler/obj" memory "git.gammaspectra.live/WeebDataHoarder/compute-go/malloc" "git.gammaspectra.live/WeebDataHoarder/compute-go/types" "reflect" "unsafe" ) type CreateFunctionArgNone struct{} type CreateFunctionCallback func(b *Builder, params []AddressableList, returns []AddressableList, regs *RegisterAllocator, data *DataAllocator) (frameSize, textFlag int, err error) type CreateFunctionData struct { Code []byte Listing []ListingEntry } type AddressableList []types.Addressable func (a AddressableList) One() types.Addressable { if len(a) != 1 { panic("invalid") } return a[0] } func CreateFunction[FuncType any](b *Builder, abi obj.ABI, name string, callback CreateFunctionCallback, data *CreateFunctionData) (f FuncType, free func() error, err error) { var zeroVal FuncType fType := reflect.TypeFor[FuncType]() if fType.Kind() != reflect.Func { return zeroVal, nil, errors.New("not a function") } info := b.FuncArgs(fType, abi) var params, returns []AddressableList for i := range len(info.InParams()) { params = append(params, b.funcParam(info, info.InParam(i), fmt.Sprintf("param%d", i))) } for i := range len(info.OutParams()) { returns = append(returns, b.funcParam(info, info.OutParam(i), fmt.Sprintf("return%d", i))) } regAllocator := NewRegisterAllocator(b.abiDef) //reserve parameter registers for _, regs := range params { for _, reg := range regs { addr := reg.Addr() if addr.Type == obj.TYPE_REG { regAllocator.Reserve(types.Register(addr.Reg)) } } } dataAllocator := NewDataAllocator(b.abiDef) frameSize, textFlag, err := callback(b, params, returns, regAllocator, dataAllocator) if err != nil { dataAllocator.FreeAll() return zeroVal, nil, err } var listing *[]ListingEntry if data != nil { listing = &data.Listing } code, errs := b.Function(name, info, frameSize, textFlag, listing) if errs != nil { dataAllocator.FreeAll() return zeroVal, nil, errs[0] } if data != nil { data.Code = code } mem, err := b.pageAllocator.AllocMemory(uint64(len(code))) if err != nil { return zeroVal, nil, err } copy(mem, code) err = memory.PageReadExecute(mem) if err != nil { dataAllocator.FreeAll() b.pageAllocator.FreeMemory(mem) return zeroVal, nil, err } var fVal FuncType fMem := &mem fVal = *(*FuncType)(unsafe.Pointer(&fMem)) return fVal, func() error { dataAllocator.FreeAll() return b.pageAllocator.FreeMemory(mem) }, nil }