diff --git a/_demo/sortdemo/sort.go b/_demo/sortdemo/sort.go index c138cec9..8232924a 100644 --- a/_demo/sortdemo/sort.go +++ b/_demo/sortdemo/sort.go @@ -8,4 +8,16 @@ func main() { for _, v := range vals { println(v) } + + texts := []string{"apple", "banana", "cherry", "date", "elderberry", "fig"} + sort.Slice(texts, func(i, j int) bool { + leni, lenj := len(texts[i]), len(texts[j]) + if leni != lenj { + return leni < lenj + } + return texts[i] < texts[j] + }) + for _, v := range texts { + println(v) + } } diff --git a/internal/abi/type.go b/internal/abi/type.go index b2a01833..42ed2054 100644 --- a/internal/abi/type.go +++ b/internal/abi/type.go @@ -100,6 +100,44 @@ const ( KindMask = (1 << 5) - 1 ) +// String returns the name of k. +func (k Kind) String() string { + if int(k) < len(kindNames) { + return kindNames[k] + } + return kindNames[0] +} + +var kindNames = []string{ + Invalid: "invalid", + Bool: "bool", + Int: "int", + Int8: "int8", + Int16: "int16", + Int32: "int32", + Int64: "int64", + Uint: "uint", + Uint8: "uint8", + Uint16: "uint16", + Uint32: "uint32", + Uint64: "uint64", + Uintptr: "uintptr", + Float32: "float32", + Float64: "float64", + Complex64: "complex64", + Complex128: "complex128", + Array: "array", + Chan: "chan", + Func: "func", + Interface: "interface", + Map: "map", + Pointer: "ptr", + Slice: "slice", + String: "string", + Struct: "struct", + UnsafePointer: "unsafe.Pointer", +} + // TFlag is used by a Type to signal what extra type information is // available in the memory directly following the Type value. type TFlag uint8 diff --git a/internal/build/build.go b/internal/build/build.go index dcc7891e..28cf2087 100644 --- a/internal/build/build.go +++ b/internal/build/build.go @@ -30,6 +30,7 @@ import ( "path/filepath" "runtime" "strings" + "unsafe" "golang.org/x/tools/go/ssa" @@ -111,10 +112,6 @@ const ( loadSyntax = loadTypes | packages.NeedSyntax | packages.NeedTypesInfo ) -var overlayFiles = map[string]string{ - "math/exp_amd64.go": "package math;", -} - func Do(args []string, conf *Config) { flags, patterns, verbose := ParseArgs(args, buildFlags) cfg := &packages.Config{ @@ -126,7 +123,8 @@ func Do(args []string, conf *Config) { if len(overlayFiles) > 0 { cfg.Overlay = make(map[string][]byte) for file, src := range overlayFiles { - cfg.Overlay[filepath.Join(runtime.GOROOT(), "src", file)] = []byte(src) + overlay := unsafe.Slice(unsafe.StringData(src), len(src)) + cfg.Overlay[filepath.Join(runtime.GOROOT(), "src", file)] = overlay } } @@ -765,6 +763,10 @@ var hasAltPkg = map[string]none{ "runtime": {}, } +var overlayFiles = map[string]string{ + "math/exp_amd64.go": "package math;", +} + func check(err error) { if err != nil { panic(err) diff --git a/internal/lib/internal/reflectlite/swapper.go b/internal/lib/internal/reflectlite/swapper.go new file mode 100644 index 00000000..5ab4bca0 --- /dev/null +++ b/internal/lib/internal/reflectlite/swapper.go @@ -0,0 +1,80 @@ +// Copyright 2016 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package reflectlite + +import ( + "unsafe" +) + +const ( + goarchPtrSize = unsafe.Sizeof(uintptr(0)) +) + +// Swapper returns a function that swaps the elements in the provided +// slice. +// +// Swapper panics if the provided interface is not a slice. +func Swapper(slice any) func(i, j int) { + v := ValueOf(slice) + if v.Kind() != Slice { + panic(&ValueError{Method: "Swapper", Kind: v.Kind()}) + } + // Fast path for slices of size 0 and 1. Nothing to swap. + switch v.Len() { + case 0: + return func(i, j int) { panic("reflect: slice index out of range") } + case 1: + return func(i, j int) { + if i != 0 || j != 0 { + panic("reflect: slice index out of range") + } + } + } + + typ := v.Type().Elem().common() + size := typ.Size() + hasPtr := typ.PtrBytes != 0 + + // Some common & small cases, without using memmove: + if hasPtr { + if size == goarchPtrSize { + ps := *(*[]unsafe.Pointer)(v.ptr) + return func(i, j int) { ps[i], ps[j] = ps[j], ps[i] } + } + if typ.Kind() == String { + ss := *(*[]string)(v.ptr) + return func(i, j int) { ss[i], ss[j] = ss[j], ss[i] } + } + } else { + switch size { + case 8: + is := *(*[]int64)(v.ptr) + return func(i, j int) { is[i], is[j] = is[j], is[i] } + case 4: + is := *(*[]int32)(v.ptr) + return func(i, j int) { is[i], is[j] = is[j], is[i] } + case 2: + is := *(*[]int16)(v.ptr) + return func(i, j int) { is[i], is[j] = is[j], is[i] } + case 1: + is := *(*[]int8)(v.ptr) + return func(i, j int) { is[i], is[j] = is[j], is[i] } + } + } + + s := (*unsafeheaderSlice)(v.ptr) + tmp := unsafe_New(typ) // swap scratch space + + return func(i, j int) { + if uint(i) >= uint(s.Len) || uint(j) >= uint(s.Len) { + panic("reflect: slice index out of range") + } + val1 := arrayAt(s.Data, i, size, "i < s.Len") + val2 := arrayAt(s.Data, j, size, "j < s.Len") + typedmemmove(typ, tmp, val1) + typedmemmove(typ, val1, val2) + typedmemmove(typ, val2, tmp) + } +} diff --git a/internal/lib/internal/reflectlite/type.go b/internal/lib/internal/reflectlite/type.go new file mode 100644 index 00000000..e1670162 --- /dev/null +++ b/internal/lib/internal/reflectlite/type.go @@ -0,0 +1,565 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package reflectlite implements lightweight version of reflect, not using +// any package except for "runtime", "unsafe", and "internal/abi" +package reflectlite + +import ( + "unsafe" + + "github.com/goplus/llgo/internal/abi" +) + +// Type is the representation of a Go type. +// +// Not all methods apply to all kinds of types. Restrictions, +// if any, are noted in the documentation for each method. +// Use the Kind method to find out the kind of type before +// calling kind-specific methods. Calling a method +// inappropriate to the kind of type causes a run-time panic. +// +// Type values are comparable, such as with the == operator, +// so they can be used as map keys. +// Two Type values are equal if they represent identical types. +type Type interface { + // Methods applicable to all types. + + // Name returns the type's name within its package for a defined type. + // For other (non-defined) types it returns the empty string. + Name() string + + // PkgPath returns a defined type's package path, that is, the import path + // that uniquely identifies the package, such as "encoding/base64". + // If the type was predeclared (string, error) or not defined (*T, struct{}, + // []int, or A where A is an alias for a non-defined type), the package path + // will be the empty string. + PkgPath() string + + // Size returns the number of bytes needed to store + // a value of the given type; it is analogous to unsafe.Sizeof. + Size() uintptr + + // Kind returns the specific kind of this type. + Kind() Kind + + // Implements reports whether the type implements the interface type u. + Implements(u Type) bool + + // AssignableTo reports whether a value of the type is assignable to type u. + AssignableTo(u Type) bool + + // Comparable reports whether values of this type are comparable. + Comparable() bool + + // String returns a string representation of the type. + // The string representation may use shortened package names + // (e.g., base64 instead of "encoding/base64") and is not + // guaranteed to be unique among types. To test for type identity, + // compare the Types directly. + String() string + + // Elem returns a type's element type. + // It panics if the type's Kind is not Ptr. + Elem() Type + + common() *abi.Type + uncommon() *uncommonType +} + +/* + * These data structures are known to the compiler (../../cmd/internal/reflectdata/reflect.go). + * A few are known to ../runtime/type.go to convey to debuggers. + * They are also known to ../runtime/type.go. + */ + +// A Kind represents the specific kind of type that a Type represents. +// The zero Kind is not a valid kind. +type Kind = abi.Kind + +const Ptr = abi.Pointer + +const ( + // Import-and-export these constants as necessary + Interface = abi.Interface + Slice = abi.Slice + String = abi.String + Struct = abi.Struct +) + +type rtype struct { + *abi.Type +} + +// uncommonType is present only for defined types or types with methods +// (if T is a defined type, the uncommonTypes for T and *T have methods). +// Using a pointer to this struct reduces the overall size required +// to describe a non-defined type with no methods. +type uncommonType = abi.UncommonType + +// arrayType represents a fixed array type. +type arrayType = abi.ArrayType + +// chanType represents a channel type. +type chanType = abi.ChanType + +type funcType = abi.FuncType + +type interfaceType = abi.InterfaceType + +// mapType represents a map type. +type mapType struct { + rtype + Key *abi.Type // map key type + Elem *abi.Type // map element (value) type + Bucket *abi.Type // internal bucket structure + // function for hashing keys (ptr to key, seed) -> hash + Hasher func(unsafe.Pointer, uintptr) uintptr + KeySize uint8 // size of key slot + ValueSize uint8 // size of value slot + BucketSize uint16 // size of bucket + Flags uint32 +} + +// ptrType represents a pointer type. +type ptrType = abi.PtrType + +// sliceType represents a slice type. +type sliceType = abi.SliceType + +// structType represents a struct type. +type structType = abi.StructType + +func (t rtype) uncommon() *uncommonType { + return t.Uncommon() +} + +func (t rtype) String() string { + return t.Type.String() +} + +func (t rtype) common() *abi.Type { return t.Type } + +func (t rtype) exportedMethods() []abi.Method { + ut := t.uncommon() + if ut == nil { + return nil + } + return ut.ExportedMethods() +} + +func (t rtype) NumMethod() int { + /* + tt := t.Type.InterfaceType() + if tt != nil { + return tt.NumMethod() + } + return len(t.exportedMethods()) + */ + panic("todo") +} + +func (t rtype) PkgPath() string { + /* + if t.TFlag&abi.TFlagNamed == 0 { + return "" + } + ut := t.uncommon() + if ut == nil { + return "" + } + return t.nameOff(ut.PkgPath).Name() + */ + panic("todo") +} + +func (t rtype) Name() string { + /* + if !t.HasName() { + return "" + } + s := t.String() + i := len(s) - 1 + sqBrackets := 0 + for i >= 0 && (s[i] != '.' || sqBrackets != 0) { + switch s[i] { + case ']': + sqBrackets++ + case '[': + sqBrackets-- + } + i-- + } + return s[i+1:] + */ + panic("todo") +} + +func toRType(t *abi.Type) rtype { + return rtype{t} +} + +func elem(t *abi.Type) *abi.Type { + et := t.Elem() + if et != nil { + return et + } + panic("reflect: Elem of invalid type " + toRType(t).String()) +} + +func (t rtype) Elem() Type { + return toType(elem(t.common())) +} + +func (t rtype) In(i int) Type { + /* + tt := t.Type.FuncType() + if tt == nil { + panic("reflect: In of non-func type") + } + return toType(tt.InSlice()[i]) + */ + panic("todo") +} + +func (t rtype) Key() Type { + tt := t.Type.MapType() + if tt == nil { + panic("reflect: Key of non-map type") + } + return toType(tt.Key) +} + +func (t rtype) Len() int { + tt := t.Type.ArrayType() + if tt == nil { + panic("reflect: Len of non-array type") + } + return int(tt.Len) +} + +func (t rtype) NumField() int { + tt := t.Type.StructType() + if tt == nil { + panic("reflect: NumField of non-struct type") + } + return len(tt.Fields) +} + +func (t rtype) NumIn() int { + /* + tt := t.Type.FuncType() + if tt == nil { + panic("reflect: NumIn of non-func type") + } + return int(tt.InCount) + */ + panic("todo") +} + +func (t rtype) NumOut() int { + /* + tt := t.Type.FuncType() + if tt == nil { + panic("reflect: NumOut of non-func type") + } + return tt.NumOut() + */ + panic("todo") +} + +func (t rtype) Out(i int) Type { + /* + tt := t.Type.FuncType() + if tt == nil { + panic("reflect: Out of non-func type") + } + return toType(tt.OutSlice()[i]) + */ + panic("todo") +} + +// add returns p+x. +// +// The whySafe string is ignored, so that the function still inlines +// as efficiently as p+x, but all call sites should use the string to +// record why the addition is safe, which is to say why the addition +// does not cause x to advance to the very end of p's allocation +// and therefore point incorrectly at the next block in memory. +func add(p unsafe.Pointer, x uintptr, whySafe string) unsafe.Pointer { + return unsafe.Pointer(uintptr(p) + x) +} + +// TypeOf returns the reflection Type that represents the dynamic type of i. +// If i is a nil interface value, TypeOf returns nil. +func TypeOf(i any) Type { + eface := *(*emptyInterface)(unsafe.Pointer(&i)) + return toType(eface.typ) +} + +func (t rtype) Implements(u Type) bool { + if u == nil { + panic("reflect: nil type passed to Type.Implements") + } + if u.Kind() != Interface { + panic("reflect: non-interface type passed to Type.Implements") + } + return implements(u.common(), t.common()) +} + +func (t rtype) AssignableTo(u Type) bool { + if u == nil { + panic("reflect: nil type passed to Type.AssignableTo") + } + uu := u.common() + tt := t.common() + return directlyAssignable(uu, tt) || implements(uu, tt) +} + +func (t rtype) Comparable() bool { + return t.Equal != nil +} + +// implements reports whether the type V implements the interface type T. +func implements(T, V *abi.Type) bool { + /* + t := T.InterfaceType() + if t == nil { + return false + } + if len(t.Methods) == 0 { + return true + } + rT := toRType(T) + rV := toRType(V) + + // The same algorithm applies in both cases, but the + // method tables for an interface type and a concrete type + // are different, so the code is duplicated. + // In both cases the algorithm is a linear scan over the two + // lists - T's methods and V's methods - simultaneously. + // Since method tables are stored in a unique sorted order + // (alphabetical, with no duplicate method names), the scan + // through V's methods must hit a match for each of T's + // methods along the way, or else V does not implement T. + // This lets us run the scan in overall linear time instead of + // the quadratic time a naive search would require. + // See also ../runtime/iface.go. + if V.Kind() == Interface { + v := (*interfaceType)(unsafe.Pointer(V)) + i := 0 + for j := 0; j < len(v.Methods); j++ { + tm := &t.Methods[i] + tmName := rT.nameOff(tm.Name) + vm := &v.Methods[j] + vmName := rV.nameOff(vm.Name) + if vmName.Name() == tmName.Name() && rV.typeOff(vm.Typ) == rT.typeOff(tm.Typ) { + if !tmName.IsExported() { + tmPkgPath := pkgPath(tmName) + if tmPkgPath == "" { + tmPkgPath = t.PkgPath.Name() + } + vmPkgPath := pkgPath(vmName) + if vmPkgPath == "" { + vmPkgPath = v.PkgPath.Name() + } + if tmPkgPath != vmPkgPath { + continue + } + } + if i++; i >= len(t.Methods) { + return true + } + } + } + return false + } + + v := V.Uncommon() + if v == nil { + return false + } + i := 0 + vmethods := v.Methods() + for j := 0; j < int(v.Mcount); j++ { + tm := &t.Methods[i] + tmName := rT.nameOff(tm.Name) + vm := vmethods[j] + vmName := rV.nameOff(vm.Name) + if vmName.Name() == tmName.Name() && rV.typeOff(vm.Mtyp) == rT.typeOff(tm.Typ) { + if !tmName.IsExported() { + tmPkgPath := pkgPath(tmName) + if tmPkgPath == "" { + tmPkgPath = t.PkgPath.Name() + } + vmPkgPath := pkgPath(vmName) + if vmPkgPath == "" { + vmPkgPath = rV.nameOff(v.PkgPath).Name() + } + if tmPkgPath != vmPkgPath { + continue + } + } + if i++; i >= len(t.Methods) { + return true + } + } + } + return false + */ + panic("todo") +} + +// directlyAssignable reports whether a value x of type V can be directly +// assigned (using memmove) to a value of type T. +// https://golang.org/doc/go_spec.html#Assignability +// Ignoring the interface rules (implemented elsewhere) +// and the ideal constant rules (no ideal constants at run time). +func directlyAssignable(T, V *abi.Type) bool { + // x's type V is identical to T? + if T == V { + return true + } + + // Otherwise at least one of T and V must not be defined + // and they must have the same kind. + if T.HasName() && V.HasName() || T.Kind() != V.Kind() { + return false + } + + // x's type T and V must have identical underlying types. + return haveIdenticalUnderlyingType(T, V, true) +} + +func haveIdenticalType(T, V *abi.Type, cmpTags bool) bool { + if cmpTags { + return T == V + } + + if toRType(T).Name() != toRType(V).Name() || T.Kind() != V.Kind() { + return false + } + + return haveIdenticalUnderlyingType(T, V, false) +} + +func haveIdenticalUnderlyingType(T, V *abi.Type, cmpTags bool) bool { + if T == V { + return true + } + + kind := T.Kind() + if kind != V.Kind() { + return false + } + + // Non-composite types of equal kind have same underlying type + // (the predefined instance of the type). + if abi.Bool <= kind && kind <= abi.Complex128 || kind == abi.String || kind == abi.UnsafePointer { + return true + } + + /* + // Composite types. + switch kind { + case abi.Array: + return T.Len() == V.Len() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) + + case abi.Chan: + // Special case: + // x is a bidirectional channel value, T is a channel type, + // and x's type V and T have identical element types. + if V.ChanDir() == abi.BothDir && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) { + return true + } + + // Otherwise continue test for identical underlying type. + return V.ChanDir() == T.ChanDir() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) + + case abi.Func: + t := (*funcType)(unsafe.Pointer(T)) + v := (*funcType)(unsafe.Pointer(V)) + if t.OutCount != v.OutCount || t.InCount != v.InCount { + return false + } + for i := 0; i < t.NumIn(); i++ { + if !haveIdenticalType(t.In(i), v.In(i), cmpTags) { + return false + } + } + for i := 0; i < t.NumOut(); i++ { + if !haveIdenticalType(t.Out(i), v.Out(i), cmpTags) { + return false + } + } + return true + + case Interface: + t := (*interfaceType)(unsafe.Pointer(T)) + v := (*interfaceType)(unsafe.Pointer(V)) + if len(t.Methods) == 0 && len(v.Methods) == 0 { + return true + } + // Might have the same methods but still + // need a run time conversion. + return false + + case abi.Map: + return haveIdenticalType(T.Key(), V.Key(), cmpTags) && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) + + case Ptr, abi.Slice: + return haveIdenticalType(T.Elem(), V.Elem(), cmpTags) + + case abi.Struct: + t := (*structType)(unsafe.Pointer(T)) + v := (*structType)(unsafe.Pointer(V)) + if len(t.Fields) != len(v.Fields) { + return false + } + if t.PkgPath.Name() != v.PkgPath.Name() { + return false + } + for i := range t.Fields { + tf := &t.Fields[i] + vf := &v.Fields[i] + if tf.Name.Name() != vf.Name.Name() { + return false + } + if !haveIdenticalType(tf.Typ, vf.Typ, cmpTags) { + return false + } + if cmpTags && tf.Name.Tag() != vf.Name.Tag() { + return false + } + if tf.Offset != vf.Offset { + return false + } + if tf.Embedded() != vf.Embedded() { + return false + } + } + return true + } + + return false + */ + panic("todo") +} + +// toType converts from a *rtype to a Type that can be returned +// to the client of package reflect. In gc, the only concern is that +// a nil *rtype must be replaced by a nil Type, but in gccgo this +// function takes care of ensuring that multiple *rtype for the same +// type are coalesced into a single Type. +func toType(t *abi.Type) Type { + if t == nil { + return nil + } + return toRType(t) +} + +// ifaceIndir reports whether t is stored indirectly in an interface value. +func ifaceIndir(t *abi.Type) bool { + return t.Kind_&abi.KindDirectIface == 0 +} diff --git a/internal/lib/internal/reflectlite/unsafeheader.go b/internal/lib/internal/reflectlite/unsafeheader.go new file mode 100644 index 00000000..33b4730b --- /dev/null +++ b/internal/lib/internal/reflectlite/unsafeheader.go @@ -0,0 +1,32 @@ +// Copyright 2020 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package reflectlite + +import ( + "unsafe" +) + +// unsafeheaderSlice is the runtime representation of a slice. +// It cannot be used safely or portably and its representation may +// change in a later release. +// +// Unlike reflect.SliceHeader, its Data field is sufficient to guarantee the +// data it references will not be garbage collected. +type unsafeheaderSlice struct { + Data unsafe.Pointer + Len int + Cap int +} + +// unsafeheaderString is the runtime representation of a string. +// It cannot be used safely or portably and its representation may +// change in a later release. +// +// Unlike reflect.StringHeader, its Data field is sufficient to guarantee the +// data it references will not be garbage collected. +type unsafeheaderString struct { + Data unsafe.Pointer + Len int +} diff --git a/internal/lib/internal/reflectlite/value.go b/internal/lib/internal/reflectlite/value.go new file mode 100644 index 00000000..bc12cb00 --- /dev/null +++ b/internal/lib/internal/reflectlite/value.go @@ -0,0 +1,476 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package reflectlite + +import ( + "unsafe" + + "github.com/goplus/llgo/internal/abi" +) + +// Value is the reflection interface to a Go value. +// +// Not all methods apply to all kinds of values. Restrictions, +// if any, are noted in the documentation for each method. +// Use the Kind method to find out the kind of value before +// calling kind-specific methods. Calling a method +// inappropriate to the kind of type causes a run time panic. +// +// The zero Value represents no value. +// Its IsValid method returns false, its Kind method returns Invalid, +// its String method returns "", and all other methods panic. +// Most functions and methods never return an invalid value. +// If one does, its documentation states the conditions explicitly. +// +// A Value can be used concurrently by multiple goroutines provided that +// the underlying Go value can be used concurrently for the equivalent +// direct operations. +// +// To compare two Values, compare the results of the Interface method. +// Using == on two Values does not compare the underlying values +// they represent. +type Value struct { + // typ holds the type of the value represented by a Value. + typ *abi.Type + + // Pointer-valued data or, if flagIndir is set, pointer to data. + // Valid when either flagIndir is set or typ.pointers() is true. + ptr unsafe.Pointer + + // flag holds metadata about the value. + // The lowest bits are flag bits: + // - flagStickyRO: obtained via unexported not embedded field, so read-only + // - flagEmbedRO: obtained via unexported embedded field, so read-only + // - flagIndir: val holds a pointer to the data + // - flagAddr: v.CanAddr is true (implies flagIndir) + // Value cannot represent method values. + // The next five bits give the Kind of the value. + // This repeats typ.Kind() except for method values. + // The remaining 23+ bits give a method number for method values. + // If flag.kind() != Func, code can assume that flagMethod is unset. + // If ifaceIndir(typ), code can assume that flagIndir is set. + flag + + // A method value represents a curried method invocation + // like r.Read for some receiver r. The typ+val+flag bits describe + // the receiver r, but the flag's Kind bits say Func (methods are + // functions), and the top bits of the flag give the method number + // in r's type's method table. +} + +type flag uintptr + +const ( + flagKindWidth = 5 // there are 27 kinds + flagKindMask flag = 1<= len, +// because then the result will point outside the array. +// whySafe must explain why i < len. (Passing "i < len" is fine; +// the benefit is to surface this assumption at the call site.) +func arrayAt(p unsafe.Pointer, i int, eltSize uintptr, whySafe string) unsafe.Pointer { + return add(p, uintptr(i)*eltSize, "i < len") +} + +// func ifaceE2I(t *abi.Type, src any, dst unsafe.Pointer) + +// typedmemmove copies a value of type t to dst from src. +// +//go:linkname typedmemmove github.com/goplus/llgo/internal/runtime.Typedmemmove +func typedmemmove(t *abi.Type, dst, src unsafe.Pointer)