diff options
Diffstat (limited to 'vendor/github.com/tetratelabs/wazero/internal/wasm/gofunc.go')
-rw-r--r-- | vendor/github.com/tetratelabs/wazero/internal/wasm/gofunc.go | 279 |
1 files changed, 0 insertions, 279 deletions
diff --git a/vendor/github.com/tetratelabs/wazero/internal/wasm/gofunc.go b/vendor/github.com/tetratelabs/wazero/internal/wasm/gofunc.go deleted file mode 100644 index 9510c2588..000000000 --- a/vendor/github.com/tetratelabs/wazero/internal/wasm/gofunc.go +++ /dev/null @@ -1,279 +0,0 @@ -package wasm - -import ( - "bytes" - "context" - "errors" - "fmt" - "math" - "reflect" - - "github.com/tetratelabs/wazero/api" -) - -type paramsKind byte - -const ( - paramsKindNoContext paramsKind = iota - paramsKindContext - paramsKindContextModule -) - -// Below are reflection code to get the interface type used to parse functions and set values. - -var ( - moduleType = reflect.TypeOf((*api.Module)(nil)).Elem() - goContextType = reflect.TypeOf((*context.Context)(nil)).Elem() - errorType = reflect.TypeOf((*error)(nil)).Elem() -) - -// compile-time check to ensure reflectGoModuleFunction implements -// api.GoModuleFunction. -var _ api.GoModuleFunction = (*reflectGoModuleFunction)(nil) - -type reflectGoModuleFunction struct { - fn *reflect.Value - params, results []ValueType -} - -// Call implements the same method as documented on api.GoModuleFunction. -func (f *reflectGoModuleFunction) Call(ctx context.Context, mod api.Module, stack []uint64) { - callGoFunc(ctx, mod, f.fn, stack) -} - -// EqualTo is exposed for testing. -func (f *reflectGoModuleFunction) EqualTo(that interface{}) bool { - if f2, ok := that.(*reflectGoModuleFunction); !ok { - return false - } else { - // TODO compare reflect pointers - return bytes.Equal(f.params, f2.params) && bytes.Equal(f.results, f2.results) - } -} - -// compile-time check to ensure reflectGoFunction implements api.GoFunction. -var _ api.GoFunction = (*reflectGoFunction)(nil) - -type reflectGoFunction struct { - fn *reflect.Value - pk paramsKind - params, results []ValueType -} - -// EqualTo is exposed for testing. -func (f *reflectGoFunction) EqualTo(that interface{}) bool { - if f2, ok := that.(*reflectGoFunction); !ok { - return false - } else { - // TODO compare reflect pointers - return f.pk == f2.pk && - bytes.Equal(f.params, f2.params) && bytes.Equal(f.results, f2.results) - } -} - -// Call implements the same method as documented on api.GoFunction. -func (f *reflectGoFunction) Call(ctx context.Context, stack []uint64) { - if f.pk == paramsKindNoContext { - ctx = nil - } - callGoFunc(ctx, nil, f.fn, stack) -} - -// callGoFunc executes the reflective function by converting params to Go -// types. The results of the function call are converted back to api.ValueType. -func callGoFunc(ctx context.Context, mod api.Module, fn *reflect.Value, stack []uint64) { - tp := fn.Type() - - var in []reflect.Value - pLen := tp.NumIn() - if pLen != 0 { - in = make([]reflect.Value, pLen) - - i := 0 - if ctx != nil { - in[0] = newContextVal(ctx) - i++ - } - if mod != nil { - in[1] = newModuleVal(mod) - i++ - } - - for j := 0; i < pLen; i++ { - next := tp.In(i) - val := reflect.New(next).Elem() - k := next.Kind() - raw := stack[j] - j++ - - switch k { - case reflect.Float32: - val.SetFloat(float64(math.Float32frombits(uint32(raw)))) - case reflect.Float64: - val.SetFloat(math.Float64frombits(raw)) - case reflect.Uint32, reflect.Uint64, reflect.Uintptr: - val.SetUint(raw) - case reflect.Int32, reflect.Int64: - val.SetInt(int64(raw)) - default: - panic(fmt.Errorf("BUG: param[%d] has an invalid type: %v", i, k)) - } - in[i] = val - } - } - - // Execute the host function and push back the call result onto the stack. - for i, ret := range fn.Call(in) { - switch ret.Kind() { - case reflect.Float32: - stack[i] = uint64(math.Float32bits(float32(ret.Float()))) - case reflect.Float64: - stack[i] = math.Float64bits(ret.Float()) - case reflect.Uint32, reflect.Uint64, reflect.Uintptr: - stack[i] = ret.Uint() - case reflect.Int32, reflect.Int64: - stack[i] = uint64(ret.Int()) - default: - panic(fmt.Errorf("BUG: result[%d] has an invalid type: %v", i, ret.Kind())) - } - } -} - -func newContextVal(ctx context.Context) reflect.Value { - val := reflect.New(goContextType).Elem() - val.Set(reflect.ValueOf(ctx)) - return val -} - -func newModuleVal(m api.Module) reflect.Value { - val := reflect.New(moduleType).Elem() - val.Set(reflect.ValueOf(m)) - return val -} - -// MustParseGoReflectFuncCode parses Code from the go function or panics. -// -// Exposing this simplifies FunctionDefinition of host functions in built-in host -// modules and tests. -func MustParseGoReflectFuncCode(fn interface{}) Code { - _, _, code, err := parseGoReflectFunc(fn) - if err != nil { - panic(err) - } - return code -} - -func parseGoReflectFunc(fn interface{}) (params, results []ValueType, code Code, err error) { - fnV := reflect.ValueOf(fn) - p := fnV.Type() - - if fnV.Kind() != reflect.Func { - err = fmt.Errorf("kind != func: %s", fnV.Kind().String()) - return - } - - pk, kindErr := kind(p) - if kindErr != nil { - err = kindErr - return - } - - pOffset := 0 - switch pk { - case paramsKindNoContext: - case paramsKindContext: - pOffset = 1 - case paramsKindContextModule: - pOffset = 2 - } - - pCount := p.NumIn() - pOffset - if pCount > 0 { - params = make([]ValueType, pCount) - } - for i := 0; i < len(params); i++ { - pI := p.In(i + pOffset) - if t, ok := getTypeOf(pI.Kind()); ok { - params[i] = t - continue - } - - // Now, we will definitely err, decide which message is best - var arg0Type reflect.Type - if hc := pI.Implements(moduleType); hc { - arg0Type = moduleType - } else if gc := pI.Implements(goContextType); gc { - arg0Type = goContextType - } - - if arg0Type != nil { - err = fmt.Errorf("param[%d] is a %s, which may be defined only once as param[0]", i+pOffset, arg0Type) - } else { - err = fmt.Errorf("param[%d] is unsupported: %s", i+pOffset, pI.Kind()) - } - return - } - - rCount := p.NumOut() - if rCount > 0 { - results = make([]ValueType, rCount) - } - for i := 0; i < len(results); i++ { - rI := p.Out(i) - if t, ok := getTypeOf(rI.Kind()); ok { - results[i] = t - continue - } - - // Now, we will definitely err, decide which message is best - if rI.Implements(errorType) { - err = fmt.Errorf("result[%d] is an error, which is unsupported", i) - } else { - err = fmt.Errorf("result[%d] is unsupported: %s", i, rI.Kind()) - } - return - } - - code = Code{} - if pk == paramsKindContextModule { - code.GoFunc = &reflectGoModuleFunction{fn: &fnV, params: params, results: results} - } else { - code.GoFunc = &reflectGoFunction{pk: pk, fn: &fnV, params: params, results: results} - } - return -} - -func kind(p reflect.Type) (paramsKind, error) { - pCount := p.NumIn() - if pCount > 0 && p.In(0).Kind() == reflect.Interface { - p0 := p.In(0) - if p0.Implements(moduleType) { - return 0, errors.New("invalid signature: api.Module parameter must be preceded by context.Context") - } else if p0.Implements(goContextType) { - if pCount >= 2 && p.In(1).Implements(moduleType) { - return paramsKindContextModule, nil - } - return paramsKindContext, nil - } - } - // Without context param allows portability with reflective runtimes. - // This allows people to more easily port to wazero. - return paramsKindNoContext, nil -} - -func getTypeOf(kind reflect.Kind) (ValueType, bool) { - switch kind { - case reflect.Float64: - return ValueTypeF64, true - case reflect.Float32: - return ValueTypeF32, true - case reflect.Int32, reflect.Uint32: - return ValueTypeI32, true - case reflect.Int64, reflect.Uint64: - return ValueTypeI64, true - case reflect.Uintptr: - return ValueTypeExternref, true - default: - return 0x00, false - } -} |