Merge pull request #852 from visualfc/reflect.func
internal/lib/reflect: support method call
This commit is contained in:
101
cl/_testgo/reflect/in.go
Normal file
101
cl/_testgo/reflect/in.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
callFunc()
|
||||
callClosure()
|
||||
callMethod()
|
||||
callIMethod()
|
||||
}
|
||||
|
||||
func callFunc() {
|
||||
var f any = func(n int) int {
|
||||
println("call.func")
|
||||
return n + 1
|
||||
}
|
||||
fn := reflect.ValueOf(f)
|
||||
println("func", fn.Kind(), fn.Type().String())
|
||||
r := fn.Call([]reflect.Value{reflect.ValueOf(100)})
|
||||
println(r[0].Int())
|
||||
ifn, ok := fn.Interface().(func(int) int)
|
||||
if !ok {
|
||||
panic("error")
|
||||
}
|
||||
ifn(100)
|
||||
}
|
||||
|
||||
func callClosure() {
|
||||
m := 100
|
||||
var f any = func(n int) int {
|
||||
println("call.closure")
|
||||
return m + n + 1
|
||||
}
|
||||
fn := reflect.ValueOf(f)
|
||||
println("closure", fn.Kind(), fn.Type().String())
|
||||
r := fn.Call([]reflect.Value{reflect.ValueOf(100)})
|
||||
println(r[0].Int())
|
||||
ifn, ok := fn.Interface().(func(int) int)
|
||||
if !ok {
|
||||
panic("error")
|
||||
}
|
||||
ifn(100)
|
||||
}
|
||||
|
||||
type T struct {
|
||||
n int
|
||||
}
|
||||
|
||||
func (t *T) Add(n int) int {
|
||||
println("call.method")
|
||||
t.n += n
|
||||
return t.n
|
||||
}
|
||||
|
||||
type I interface {
|
||||
Add(n int) int
|
||||
}
|
||||
|
||||
type abi struct {
|
||||
typ unsafe.Pointer
|
||||
data unsafe.Pointer
|
||||
}
|
||||
|
||||
func callMethod() {
|
||||
t := &T{1}
|
||||
v := reflect.ValueOf(t)
|
||||
fn := v.Method(0)
|
||||
println("method", fn.Kind(), fn.Type().String())
|
||||
r := fn.Call([]reflect.Value{reflect.ValueOf(100)})
|
||||
println(r[0].Int())
|
||||
//TODO type assert
|
||||
// ifn, ok := fn.Interface().(func(int) int)
|
||||
// if !ok {
|
||||
// panic("error")
|
||||
// }
|
||||
// ifn(1)
|
||||
v2 := reflect.ValueOf(fn.Interface())
|
||||
r2 := v2.Call([]reflect.Value{reflect.ValueOf(100)})
|
||||
println(r2[0].Int())
|
||||
}
|
||||
|
||||
func callIMethod() {
|
||||
var i I = &T{1}
|
||||
v := reflect.ValueOf(i)
|
||||
fn := v.Method(0)
|
||||
println("imethod", fn.Kind(), fn.Type().String())
|
||||
r := fn.Call([]reflect.Value{reflect.ValueOf(100)})
|
||||
println(r[0].Int())
|
||||
//TODO type assert
|
||||
// ifn, ok := fn.Interface().(func(int) int)
|
||||
// if !ok {
|
||||
// panic("error")
|
||||
// }
|
||||
// ifn(1)
|
||||
v2 := reflect.ValueOf(fn.Interface())
|
||||
r2 := v2.Call([]reflect.Value{reflect.ValueOf(100)})
|
||||
println(r2[0].Int())
|
||||
}
|
||||
1027
cl/_testgo/reflect/out.ll
Normal file
1027
cl/_testgo/reflect/out.ll
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -388,11 +388,16 @@ func (t *Type) IfaceIndir() bool {
|
||||
return t.Kind_&KindDirectIface == 0
|
||||
}
|
||||
|
||||
// isDirectIface reports whether t is stored directly in an interface value.
|
||||
// IsDirectIface reports whether t is stored directly in an interface value.
|
||||
func (t *Type) IsDirectIface() bool {
|
||||
return t.Kind_&KindDirectIface != 0
|
||||
}
|
||||
|
||||
// IsClosure reports whether t is closure struct
|
||||
func (t *Type) IsClosure() bool {
|
||||
return t.TFlag&TFlagClosure != 0
|
||||
}
|
||||
|
||||
// Size returns the size of data with type t.
|
||||
func (t *Type) Size() uintptr { return t.Size_ }
|
||||
|
||||
|
||||
@@ -22,6 +22,13 @@
|
||||
|
||||
package reflect
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/internal/abi"
|
||||
"github.com/goplus/llgo/internal/runtime"
|
||||
)
|
||||
|
||||
/*
|
||||
import (
|
||||
"unsafe"
|
||||
@@ -111,42 +118,37 @@ type methodValue struct {
|
||||
// reflect can tell, but the true func representation can be handled
|
||||
// by code like Convert and Interface and Assign.
|
||||
func makeMethodValue(op string, v Value) Value {
|
||||
/*
|
||||
if v.flag&flagMethod == 0 {
|
||||
panic("reflect: internal error: invalid use of makeMethodValue")
|
||||
}
|
||||
if v.flag&flagMethod == 0 {
|
||||
panic("reflect: internal error: invalid use of makeMethodValue")
|
||||
}
|
||||
|
||||
// Ignoring the flagMethod bit, v describes the receiver, not the method type.
|
||||
fl := v.flag & (flagRO | flagAddr | flagIndir)
|
||||
fl |= flag(v.typ().Kind())
|
||||
rcvr := Value{v.typ(), v.ptr, fl}
|
||||
// Ignoring the flagMethod bit, v describes the receiver, not the method type.
|
||||
fl := v.flag & (flagRO | flagAddr | flagIndir)
|
||||
fl |= flag(v.typ().Kind())
|
||||
rcvr := Value{v.typ(), v.ptr, fl}
|
||||
|
||||
// v.Type returns the actual type of the method value.
|
||||
ftyp := (*funcType)(unsafe.Pointer(v.Type().(*rtype)))
|
||||
|
||||
code := methodValueCallCodePtr()
|
||||
|
||||
// methodValue contains a stack map for use by the runtime
|
||||
_, _, abid := funcLayout(ftyp, nil)
|
||||
fv := &methodValue{
|
||||
makeFuncCtxt: makeFuncCtxt{
|
||||
fn: code,
|
||||
stack: abid.stackPtrs,
|
||||
argLen: abid.stackCallArgsSize,
|
||||
regPtrs: abid.inRegPtrs,
|
||||
},
|
||||
method: int(v.flag) >> flagMethodShift,
|
||||
rcvr: rcvr,
|
||||
}
|
||||
|
||||
// Cause panic if method is not appropriate.
|
||||
// The panic would still happen during the call if we omit this,
|
||||
// but we want Interface() and other operations to fail early.
|
||||
methodReceiver(op, fv.rcvr, fv.method)
|
||||
|
||||
return Value{ftyp.Common(), unsafe.Pointer(fv), v.flag&flagRO | flag(Func)}
|
||||
*/
|
||||
panic("todo: reflect.makeMethodValue")
|
||||
// v.Type returns the actual type of the method value.
|
||||
ftyp := *(*funcType)(unsafe.Pointer(v.Type().(*rtype)))
|
||||
ptyp := rtypeOf(unsafe.Pointer(uintptr(0)))
|
||||
ftyp.In = append([]*abi.Type{ptyp}, ftyp.In...)
|
||||
typ := runtime.Struct("", 2*unsafe.Sizeof(0), abi.StructField{
|
||||
Name_: "llgo_ctx",
|
||||
Typ: &ftyp.Type,
|
||||
}, abi.StructField{
|
||||
Name_: "f",
|
||||
Typ: ptyp,
|
||||
Offset: unsafe.Sizeof(0),
|
||||
})
|
||||
typ.TFlag |= abi.TFlagClosure
|
||||
_, _, fn := methodReceiver(op, rcvr, int(v.flag)>>flagMethodShift)
|
||||
fv := &struct {
|
||||
fn unsafe.Pointer
|
||||
env unsafe.Pointer
|
||||
}{fn, v.ptr}
|
||||
// Cause panic if method is not appropriate.
|
||||
// The panic would still happen during the call if we omit this,
|
||||
// but we want Interface() and other operations to fail early.
|
||||
return Value{typ, unsafe.Pointer(fv), v.flag&flagRO | flagIndir | flag(Func)}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -642,58 +642,43 @@ func (t *rtype) NumField() int {
|
||||
}
|
||||
|
||||
func (t *rtype) In(i int) Type {
|
||||
/*
|
||||
if t.Kind() != Func {
|
||||
panic("reflect: In of non-func type " + t.String())
|
||||
}
|
||||
tt := (*abi.FuncType)(unsafe.Pointer(t))
|
||||
return toType(tt.InSlice()[i])
|
||||
*/
|
||||
panic("todo: reflect.rtype.In")
|
||||
if t.Kind() != Func {
|
||||
panic("reflect: In of non-func type " + t.String())
|
||||
}
|
||||
tt := (*abi.FuncType)(unsafe.Pointer(t))
|
||||
return toType(tt.In[i])
|
||||
}
|
||||
|
||||
func (t *rtype) NumIn() int {
|
||||
/*
|
||||
if t.Kind() != Func {
|
||||
panic("reflect: NumIn of non-func type " + t.String())
|
||||
}
|
||||
tt := (*abi.FuncType)(unsafe.Pointer(t))
|
||||
return tt.NumIn()
|
||||
*/
|
||||
panic("todo: reflect.rtype.NumIn")
|
||||
if t.Kind() != Func {
|
||||
panic("reflect: NumIn of non-func type " + t.String())
|
||||
}
|
||||
tt := (*abi.FuncType)(unsafe.Pointer(t))
|
||||
return len(tt.In)
|
||||
}
|
||||
|
||||
func (t *rtype) NumOut() int {
|
||||
/*
|
||||
if t.Kind() != Func {
|
||||
panic("reflect: NumOut of non-func type " + t.String())
|
||||
}
|
||||
tt := (*abi.FuncType)(unsafe.Pointer(t))
|
||||
return tt.NumOut()
|
||||
*/
|
||||
panic("todo: reflect.rtype.NumOut")
|
||||
if t.Kind() != Func {
|
||||
panic("reflect: NumOut of non-func type " + t.String())
|
||||
}
|
||||
tt := (*abi.FuncType)(unsafe.Pointer(t))
|
||||
return len(tt.Out)
|
||||
}
|
||||
|
||||
func (t *rtype) Out(i int) Type {
|
||||
/*
|
||||
if t.Kind() != Func {
|
||||
panic("reflect: Out of non-func type " + t.String())
|
||||
}
|
||||
tt := (*abi.FuncType)(unsafe.Pointer(t))
|
||||
return toType(tt.OutSlice()[i])
|
||||
*/
|
||||
panic("todo: reflect.rtype.Out")
|
||||
if t.Kind() != Func {
|
||||
panic("reflect: Out of non-func type " + t.String())
|
||||
}
|
||||
tt := (*abi.FuncType)(unsafe.Pointer(t))
|
||||
return toType(tt.Out[i])
|
||||
}
|
||||
|
||||
func (t *rtype) IsVariadic() bool {
|
||||
/*
|
||||
if t.Kind() != Func {
|
||||
panic("reflect: IsVariadic of non-func type " + t.String())
|
||||
}
|
||||
tt := (*abi.FuncType)(unsafe.Pointer(t))
|
||||
return tt.IsVariadic()
|
||||
*/
|
||||
panic("todo: reflect.rtype.IsVariadic")
|
||||
if t.Kind() != Func {
|
||||
panic("reflect: IsVariadic of non-func type " + t.String())
|
||||
}
|
||||
tt := (*abi.FuncType)(unsafe.Pointer(t))
|
||||
return tt.Variadic()
|
||||
}
|
||||
|
||||
// add returns p+x.
|
||||
@@ -1022,6 +1007,12 @@ func (t *structType) FieldByName(name string) (f StructField, present bool) {
|
||||
// If i is a nil interface value, TypeOf returns nil.
|
||||
func TypeOf(i any) Type {
|
||||
eface := *(*emptyInterface)(unsafe.Pointer(&i))
|
||||
// closure type
|
||||
if eface.typ.IsClosure() {
|
||||
ft := *eface.typ.StructType().Fields[0].Typ.FuncType()
|
||||
ft.In = ft.In[1:]
|
||||
return toType(&ft.Type)
|
||||
}
|
||||
// Noescape so this doesn't make i to escape. See the comment
|
||||
// at Value.typ for why this is safe.
|
||||
return toType((*abi.Type)(unsafe.Pointer(eface.typ)))
|
||||
|
||||
@@ -22,13 +22,14 @@ package reflect
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/x/ffi"
|
||||
|
||||
"github.com/goplus/llgo/c/bitcast"
|
||||
"github.com/goplus/llgo/internal/abi"
|
||||
"github.com/goplus/llgo/internal/runtime"
|
||||
"github.com/goplus/llgo/internal/runtime/goarch"
|
||||
"github.com/goplus/llgo/x/ffi"
|
||||
)
|
||||
|
||||
// Value is the reflection interface to a Go value.
|
||||
@@ -94,7 +95,6 @@ const (
|
||||
flagIndir flag = 1 << 7
|
||||
flagAddr flag = 1 << 8
|
||||
flagMethod flag = 1 << 9
|
||||
flagClosure flag = 1 << 10
|
||||
flagMethodShift = 10
|
||||
flagRO flag = flagStickyRO | flagEmbedRO
|
||||
)
|
||||
@@ -178,15 +178,12 @@ func unpackEface(i any) Value {
|
||||
return Value{}
|
||||
}
|
||||
f := flag(t.Kind())
|
||||
if t.IsClosure() {
|
||||
f = flag(Func)
|
||||
}
|
||||
if t.IfaceIndir() {
|
||||
f |= flagIndir
|
||||
}
|
||||
if t.TFlag&abi.TFlagClosure != 0 {
|
||||
f = (f & flag(^Struct)) | flag(Func) | flagClosure
|
||||
ft := *t.StructType().Fields[0].Typ.FuncType()
|
||||
ft.In = ft.In[1:]
|
||||
t = &ft.Type
|
||||
}
|
||||
return Value{t, e.word, f}
|
||||
}
|
||||
|
||||
@@ -320,7 +317,10 @@ func (v Value) Bool() bool {
|
||||
if v.kind() != Bool {
|
||||
v.panicNotBool()
|
||||
}
|
||||
return *(*bool)(v.ptr)
|
||||
if v.flag&flagAddr != 0 {
|
||||
return *(*bool)(v.ptr)
|
||||
}
|
||||
return uintptr(v.ptr) != 0
|
||||
}
|
||||
|
||||
func (v Value) panicNotBool() {
|
||||
@@ -341,28 +341,25 @@ func (v Value) Bytes() []byte {
|
||||
}
|
||||
|
||||
func (v Value) bytesSlow() []byte {
|
||||
/*
|
||||
switch v.kind() {
|
||||
case Slice:
|
||||
if v.typ().Elem().Kind() != abi.Uint8 {
|
||||
panic("reflect.Value.Bytes of non-byte slice")
|
||||
}
|
||||
// Slice is always bigger than a word; assume flagIndir.
|
||||
return *(*[]byte)(v.ptr)
|
||||
case Array:
|
||||
if v.typ().Elem().Kind() != abi.Uint8 {
|
||||
panic("reflect.Value.Bytes of non-byte array")
|
||||
}
|
||||
if !v.CanAddr() {
|
||||
panic("reflect.Value.Bytes of unaddressable byte array")
|
||||
}
|
||||
p := (*byte)(v.ptr)
|
||||
n := int((*arrayType)(unsafe.Pointer(v.typ())).Len)
|
||||
return unsafe.Slice(p, n)
|
||||
switch v.kind() {
|
||||
case Slice:
|
||||
if v.typ().Elem().Kind() != abi.Uint8 {
|
||||
panic("reflect.Value.Bytes of non-byte slice")
|
||||
}
|
||||
panic(&ValueError{"reflect.Value.Bytes", v.kind()})
|
||||
*/
|
||||
panic("todo: reflect.Value.byteSlow")
|
||||
// Slice is always bigger than a word; assume flagIndir.
|
||||
return *(*[]byte)(v.ptr)
|
||||
case Array:
|
||||
if v.typ().Elem().Kind() != abi.Uint8 {
|
||||
panic("reflect.Value.Bytes of non-byte array")
|
||||
}
|
||||
if !v.CanAddr() {
|
||||
panic("reflect.Value.Bytes of unaddressable byte array")
|
||||
}
|
||||
p := (*byte)(v.ptr)
|
||||
n := int((*arrayType)(unsafe.Pointer(v.typ())).Len)
|
||||
return unsafe.Slice(p, n)
|
||||
}
|
||||
panic(&ValueError{"reflect.Value.Bytes", v.kind()})
|
||||
}
|
||||
|
||||
// runes returns v's underlying value.
|
||||
@@ -397,18 +394,14 @@ func (v Value) CanSet() bool {
|
||||
// Cap returns v's capacity.
|
||||
// It panics if v's Kind is not Array, Chan, Slice or pointer to Array.
|
||||
func (v Value) Cap() int {
|
||||
/* TODO(xsw):
|
||||
// capNonSlice is split out to keep Cap inlineable for slice kinds.
|
||||
if v.kind() == Slice {
|
||||
return (*unsafeheader.Slice)(v.ptr).Cap
|
||||
return (*unsafeheaderSlice)(v.ptr).Cap
|
||||
}
|
||||
return v.capNonSlice()
|
||||
*/
|
||||
panic("todo: reflect.Value.Cap")
|
||||
}
|
||||
|
||||
func (v Value) capNonSlice() int {
|
||||
/* TODO(xsw):
|
||||
k := v.kind()
|
||||
switch k {
|
||||
case Array:
|
||||
@@ -422,8 +415,6 @@ func (v Value) capNonSlice() int {
|
||||
panic("reflect: call of reflect.Value.Cap on ptr to non-array Value")
|
||||
}
|
||||
panic(&ValueError{"reflect.Value.Cap", v.kind()})
|
||||
*/
|
||||
panic("todo: reflect.Value.capNonSlice")
|
||||
}
|
||||
|
||||
// Close closes the channel v.
|
||||
@@ -521,7 +512,6 @@ func ifaceIndir(typ *abi.Type) bool {
|
||||
// Field returns the i'th field of the struct v.
|
||||
// It panics if v's Kind is not Struct or i is out of range.
|
||||
func (v Value) Field(i int) Value {
|
||||
/* TODO(xsw):
|
||||
if v.kind() != Struct {
|
||||
panic(&ValueError{"reflect.Value.Field", v.kind()})
|
||||
}
|
||||
@@ -535,7 +525,7 @@ func (v Value) Field(i int) Value {
|
||||
// Inherit permission bits from v, but clear flagEmbedRO.
|
||||
fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind())
|
||||
// Using an unexported field forces flagRO.
|
||||
if !field.Name.IsExported() {
|
||||
if !field.Exported() {
|
||||
if field.Embedded() {
|
||||
fl |= flagEmbedRO
|
||||
} else {
|
||||
@@ -549,8 +539,6 @@ func (v Value) Field(i int) Value {
|
||||
// so v.ptr + field.offset is still the correct address.
|
||||
ptr := add(v.ptr, field.Offset, "same as non-reflect &v.field")
|
||||
return Value{typ, ptr, fl}
|
||||
*/
|
||||
panic("todo: reflect.Value.Field")
|
||||
}
|
||||
|
||||
// FieldByIndex returns the nested field corresponding to index.
|
||||
@@ -634,11 +622,20 @@ func (v Value) CanFloat() bool {
|
||||
// It panics if v's Kind is not Float32 or Float64
|
||||
func (v Value) Float() float64 {
|
||||
k := v.kind()
|
||||
switch k {
|
||||
case Float32:
|
||||
return float64(*(*float32)(v.ptr))
|
||||
case Float64:
|
||||
return *(*float64)(v.ptr)
|
||||
if v.flag&flagAddr != 0 {
|
||||
switch k {
|
||||
case Float32:
|
||||
return float64(*(*float32)(v.ptr))
|
||||
case Float64:
|
||||
return *(*float64)(v.ptr)
|
||||
}
|
||||
} else {
|
||||
switch k {
|
||||
case Float32:
|
||||
return float64(bitcast.ToFloat32(uintptr(v.ptr)))
|
||||
case Float64:
|
||||
return bitcast.ToFloat64(uintptr(v.ptr))
|
||||
}
|
||||
}
|
||||
panic(&ValueError{"reflect.Value.Float", v.kind()})
|
||||
}
|
||||
@@ -794,18 +791,15 @@ func valueInterface(v Value, safe bool) any {
|
||||
// Deprecated: The memory representation of interface values is not
|
||||
// compatible with InterfaceData.
|
||||
func (v Value) InterfaceData() [2]uintptr {
|
||||
/*
|
||||
v.mustBe(Interface)
|
||||
// The compiler loses track as it converts to uintptr. Force escape.
|
||||
escapes(v.ptr)
|
||||
// We treat this as a read operation, so we allow
|
||||
// it even for unexported data, because the caller
|
||||
// has to import "unsafe" to turn it into something
|
||||
// that can be abused.
|
||||
// Interface value is always bigger than a word; assume flagIndir.
|
||||
return *(*[2]uintptr)(v.ptr)
|
||||
*/
|
||||
panic("todo: reflect.Value.InterfaceData")
|
||||
v.mustBe(Interface)
|
||||
// The compiler loses track as it converts to uintptr. Force escape.
|
||||
escapes(v.ptr)
|
||||
// We treat this as a read operation, so we allow
|
||||
// it even for unexported data, because the caller
|
||||
// has to import "unsafe" to turn it into something
|
||||
// that can be abused.
|
||||
// Interface value is always bigger than a word; assume flagIndir.
|
||||
return *(*[2]uintptr)(v.ptr)
|
||||
}
|
||||
|
||||
// IsNil reports whether its argument v is nil. The argument must be
|
||||
@@ -847,123 +841,117 @@ func (v Value) IsValid() bool {
|
||||
// IsZero reports whether v is the zero value for its type.
|
||||
// It panics if the argument is invalid.
|
||||
func (v Value) IsZero() bool {
|
||||
/*
|
||||
switch v.kind() {
|
||||
case Bool:
|
||||
return !v.Bool()
|
||||
case Int, Int8, Int16, Int32, Int64:
|
||||
return v.Int() == 0
|
||||
case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
|
||||
return v.Uint() == 0
|
||||
case Float32, Float64:
|
||||
return math.Float64bits(v.Float()) == 0
|
||||
case Complex64, Complex128:
|
||||
c := v.Complex()
|
||||
return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0
|
||||
case Array:
|
||||
// If the type is comparable, then compare directly with zero.
|
||||
if v.typ().Equal != nil && v.typ().Size() <= maxZero {
|
||||
if v.flag&flagIndir == 0 {
|
||||
return v.ptr == nil
|
||||
}
|
||||
// v.ptr doesn't escape, as Equal functions are compiler generated
|
||||
// and never escape. The escape analysis doesn't know, as it is a
|
||||
// function pointer call.
|
||||
return v.typ().Equal(noescape(v.ptr), unsafe.Pointer(&zeroVal[0]))
|
||||
switch v.kind() {
|
||||
case Bool:
|
||||
return !v.Bool()
|
||||
case Int, Int8, Int16, Int32, Int64:
|
||||
return v.Int() == 0
|
||||
case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
|
||||
return v.Uint() == 0
|
||||
case Float32, Float64:
|
||||
return math.Float64bits(v.Float()) == 0
|
||||
case Complex64, Complex128:
|
||||
c := v.Complex()
|
||||
return math.Float64bits(real(c)) == 0 && math.Float64bits(imag(c)) == 0
|
||||
case Array:
|
||||
// If the type is comparable, then compare directly with zero.
|
||||
if v.typ().Equal != nil && v.typ().Size() <= maxZero {
|
||||
if v.flag&flagIndir == 0 {
|
||||
return v.ptr == nil
|
||||
}
|
||||
|
||||
n := v.Len()
|
||||
for i := 0; i < n; i++ {
|
||||
if !v.Index(i).IsZero() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case Chan, Func, Interface, Map, Pointer, Slice, UnsafePointer:
|
||||
return v.IsNil()
|
||||
case String:
|
||||
return v.Len() == 0
|
||||
case Struct:
|
||||
// If the type is comparable, then compare directly with zero.
|
||||
if v.typ().Equal != nil && v.typ().Size() <= maxZero {
|
||||
if v.flag&flagIndir == 0 {
|
||||
return v.ptr == nil
|
||||
}
|
||||
// See noescape justification above.
|
||||
return v.typ().Equal(noescape(v.ptr), unsafe.Pointer(&zeroVal[0]))
|
||||
}
|
||||
|
||||
n := v.NumField()
|
||||
for i := 0; i < n; i++ {
|
||||
if !v.Field(i).IsZero() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
default:
|
||||
// This should never happen, but will act as a safeguard for later,
|
||||
// as a default value doesn't makes sense here.
|
||||
panic(&ValueError{"reflect.Value.IsZero", v.Kind()})
|
||||
// v.ptr doesn't escape, as Equal functions are compiler generated
|
||||
// and never escape. The escape analysis doesn't know, as it is a
|
||||
// function pointer call.
|
||||
return v.typ().Equal(noescape(v.ptr), unsafe.Pointer(&zeroVal[0]))
|
||||
}
|
||||
*/
|
||||
panic("todo: reflect.Value.IsZero")
|
||||
|
||||
n := v.Len()
|
||||
for i := 0; i < n; i++ {
|
||||
if !v.Index(i).IsZero() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case Chan, Func, Interface, Map, Pointer, Slice, UnsafePointer:
|
||||
return v.IsNil()
|
||||
case String:
|
||||
return v.Len() == 0
|
||||
case Struct:
|
||||
// If the type is comparable, then compare directly with zero.
|
||||
if v.typ().Equal != nil && v.typ().Size() <= maxZero {
|
||||
if v.flag&flagIndir == 0 {
|
||||
return v.ptr == nil
|
||||
}
|
||||
// See noescape justification above.
|
||||
return v.typ().Equal(noescape(v.ptr), unsafe.Pointer(&zeroVal[0]))
|
||||
}
|
||||
|
||||
n := v.NumField()
|
||||
for i := 0; i < n; i++ {
|
||||
if !v.Field(i).IsZero() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
default:
|
||||
// This should never happen, but will act as a safeguard for later,
|
||||
// as a default value doesn't makes sense here.
|
||||
panic(&ValueError{"reflect.Value.IsZero", v.Kind()})
|
||||
}
|
||||
}
|
||||
|
||||
// SetZero sets v to be the zero value of v's type.
|
||||
// It panics if CanSet returns false.
|
||||
func (v Value) SetZero() {
|
||||
/*
|
||||
v.mustBeAssignable()
|
||||
switch v.kind() {
|
||||
case Bool:
|
||||
*(*bool)(v.ptr) = false
|
||||
case Int:
|
||||
*(*int)(v.ptr) = 0
|
||||
case Int8:
|
||||
*(*int8)(v.ptr) = 0
|
||||
case Int16:
|
||||
*(*int16)(v.ptr) = 0
|
||||
case Int32:
|
||||
*(*int32)(v.ptr) = 0
|
||||
case Int64:
|
||||
*(*int64)(v.ptr) = 0
|
||||
case Uint:
|
||||
*(*uint)(v.ptr) = 0
|
||||
case Uint8:
|
||||
*(*uint8)(v.ptr) = 0
|
||||
case Uint16:
|
||||
*(*uint16)(v.ptr) = 0
|
||||
case Uint32:
|
||||
*(*uint32)(v.ptr) = 0
|
||||
case Uint64:
|
||||
*(*uint64)(v.ptr) = 0
|
||||
case Uintptr:
|
||||
*(*uintptr)(v.ptr) = 0
|
||||
case Float32:
|
||||
*(*float32)(v.ptr) = 0
|
||||
case Float64:
|
||||
*(*float64)(v.ptr) = 0
|
||||
case Complex64:
|
||||
*(*complex64)(v.ptr) = 0
|
||||
case Complex128:
|
||||
*(*complex128)(v.ptr) = 0
|
||||
case String:
|
||||
*(*string)(v.ptr) = ""
|
||||
case Slice:
|
||||
*(*unsafeheader.Slice)(v.ptr) = unsafeheader.Slice{}
|
||||
case Interface:
|
||||
*(*[2]unsafe.Pointer)(v.ptr) = [2]unsafe.Pointer{}
|
||||
case Chan, Func, Map, Pointer, UnsafePointer:
|
||||
*(*unsafe.Pointer)(v.ptr) = nil
|
||||
case Array, Struct:
|
||||
typedmemclr(v.typ(), v.ptr)
|
||||
default:
|
||||
// This should never happen, but will act as a safeguard for later,
|
||||
// as a default value doesn't makes sense here.
|
||||
panic(&ValueError{"reflect.Value.SetZero", v.Kind()})
|
||||
}
|
||||
*/
|
||||
panic("todo: reflect.Value.SetZero")
|
||||
v.mustBeAssignable()
|
||||
switch v.kind() {
|
||||
case Bool:
|
||||
*(*bool)(v.ptr) = false
|
||||
case Int:
|
||||
*(*int)(v.ptr) = 0
|
||||
case Int8:
|
||||
*(*int8)(v.ptr) = 0
|
||||
case Int16:
|
||||
*(*int16)(v.ptr) = 0
|
||||
case Int32:
|
||||
*(*int32)(v.ptr) = 0
|
||||
case Int64:
|
||||
*(*int64)(v.ptr) = 0
|
||||
case Uint:
|
||||
*(*uint)(v.ptr) = 0
|
||||
case Uint8:
|
||||
*(*uint8)(v.ptr) = 0
|
||||
case Uint16:
|
||||
*(*uint16)(v.ptr) = 0
|
||||
case Uint32:
|
||||
*(*uint32)(v.ptr) = 0
|
||||
case Uint64:
|
||||
*(*uint64)(v.ptr) = 0
|
||||
case Uintptr:
|
||||
*(*uintptr)(v.ptr) = 0
|
||||
case Float32:
|
||||
*(*float32)(v.ptr) = 0
|
||||
case Float64:
|
||||
*(*float64)(v.ptr) = 0
|
||||
case Complex64:
|
||||
*(*complex64)(v.ptr) = 0
|
||||
case Complex128:
|
||||
*(*complex128)(v.ptr) = 0
|
||||
case String:
|
||||
*(*string)(v.ptr) = ""
|
||||
case Slice:
|
||||
*(*unsafeheaderSlice)(v.ptr) = unsafeheaderSlice{}
|
||||
case Interface:
|
||||
*(*[2]unsafe.Pointer)(v.ptr) = [2]unsafe.Pointer{}
|
||||
case Chan, Func, Map, Pointer, UnsafePointer:
|
||||
*(*unsafe.Pointer)(v.ptr) = nil
|
||||
case Array, Struct:
|
||||
typedmemclr(v.typ(), v.ptr)
|
||||
default:
|
||||
// This should never happen, but will act as a safeguard for later,
|
||||
// as a default value doesn't makes sense here.
|
||||
panic(&ValueError{"reflect.Value.SetZero", v.Kind()})
|
||||
}
|
||||
}
|
||||
|
||||
// Kind returns v's Kind.
|
||||
@@ -983,27 +971,24 @@ func (v Value) Len() int {
|
||||
}
|
||||
|
||||
func (v Value) lenNonSlice() int {
|
||||
/*
|
||||
switch k := v.kind(); k {
|
||||
case Array:
|
||||
tt := (*arrayType)(unsafe.Pointer(v.typ()))
|
||||
return int(tt.Len)
|
||||
case Chan:
|
||||
return chanlen(v.pointer())
|
||||
case Map:
|
||||
return maplen(v.pointer())
|
||||
case String:
|
||||
// String is bigger than a word; assume flagIndir.
|
||||
return (*unsafeheader.String)(v.ptr).Len
|
||||
case Ptr:
|
||||
if v.typ().Elem().Kind() == abi.Array {
|
||||
return v.typ().Elem().Len()
|
||||
}
|
||||
panic("reflect: call of reflect.Value.Len on ptr to non-array Value")
|
||||
switch k := v.kind(); k {
|
||||
case Array:
|
||||
tt := (*arrayType)(unsafe.Pointer(v.typ()))
|
||||
return int(tt.Len)
|
||||
case Chan:
|
||||
return chanlen(v.pointer())
|
||||
case Map:
|
||||
return maplen(v.pointer())
|
||||
case String:
|
||||
// String is bigger than a word; assume flagIndir.
|
||||
return (*unsafeheaderString)(v.ptr).Len
|
||||
case Ptr:
|
||||
if v.typ().Elem().Kind() == abi.Array {
|
||||
return v.typ().Elem().Len()
|
||||
}
|
||||
panic(&ValueError{"reflect.Value.Len", v.kind()})
|
||||
*/
|
||||
panic("todo: reflect.Value.lenNonSlice")
|
||||
panic("reflect: call of reflect.Value.Len on ptr to non-array Value")
|
||||
}
|
||||
panic(&ValueError{"reflect.Value.Len", v.kind()})
|
||||
}
|
||||
|
||||
// Pointer returns v's value as a uintptr.
|
||||
@@ -1047,6 +1032,8 @@ func (v Value) Pointer() uintptr {
|
||||
// so their Pointers are equal. The function used here must
|
||||
// match the one used in makeMethodValue.
|
||||
// return methodValueCallCodePtr()
|
||||
_, _, fn := methodReceiver("unsafePointer", v, int(v.flag)>>flagMethodShift)
|
||||
return uintptr(fn)
|
||||
}
|
||||
p := v.pointer()
|
||||
// Non-nil func value points at data block.
|
||||
@@ -1235,32 +1222,26 @@ func (v Value) SetInt(x int64) {
|
||||
// It panics if v's Kind is not Slice or if n is negative or
|
||||
// greater than the capacity of the slice.
|
||||
func (v Value) SetLen(n int) {
|
||||
/* TODO(xsw):
|
||||
v.mustBeAssignable()
|
||||
v.mustBe(Slice)
|
||||
s := (*unsafeheader.Slice)(v.ptr)
|
||||
s := (*unsafeheaderSlice)(v.ptr)
|
||||
if uint(n) > uint(s.Cap) {
|
||||
panic("reflect: slice length out of range in SetLen")
|
||||
}
|
||||
s.Len = n
|
||||
*/
|
||||
panic("todo: reflect.Value.SetLen")
|
||||
}
|
||||
|
||||
// SetCap sets v's capacity to n.
|
||||
// It panics if v's Kind is not Slice or if n is smaller than the length or
|
||||
// greater than the capacity of the slice.
|
||||
func (v Value) SetCap(n int) {
|
||||
/* TODO(xsw):
|
||||
v.mustBeAssignable()
|
||||
v.mustBe(Slice)
|
||||
s := (*unsafeheader.Slice)(v.ptr)
|
||||
s := (*unsafeheaderSlice)(v.ptr)
|
||||
if n < s.Len || n > s.Cap {
|
||||
panic("reflect: slice capacity out of range in SetCap")
|
||||
}
|
||||
s.Cap = n
|
||||
*/
|
||||
panic("todo: reflect.Value.SetCap")
|
||||
}
|
||||
|
||||
// SetMapIndex sets the element associated with key in the map v to elem.
|
||||
@@ -1360,7 +1341,6 @@ func (v Value) SetString(x string) {
|
||||
// It panics if v's Kind is not Array, Slice or String, or if v is an unaddressable array,
|
||||
// or if the indexes are out of bounds.
|
||||
func (v Value) Slice(i, j int) Value {
|
||||
/* TODO(xsw):
|
||||
var (
|
||||
cap int
|
||||
typ *sliceType
|
||||
@@ -1381,18 +1361,18 @@ func (v Value) Slice(i, j int) Value {
|
||||
|
||||
case Slice:
|
||||
typ = (*sliceType)(unsafe.Pointer(v.typ()))
|
||||
s := (*unsafeheader.Slice)(v.ptr)
|
||||
s := (*unsafeheaderSlice)(v.ptr)
|
||||
base = s.Data
|
||||
cap = s.Cap
|
||||
|
||||
case String:
|
||||
s := (*unsafeheader.String)(v.ptr)
|
||||
s := (*unsafeheaderString)(v.ptr)
|
||||
if i < 0 || j < i || j > s.Len {
|
||||
panic("reflect.Value.Slice: string slice index out of bounds")
|
||||
}
|
||||
var t unsafeheader.String
|
||||
var t unsafeheaderString
|
||||
if i < s.Len {
|
||||
t = unsafeheader.String{Data: arrayAt(s.Data, i, 1, "i < s.Len"), Len: j - i}
|
||||
t = unsafeheaderString{Data: arrayAt(s.Data, i, 1, "i < s.Len"), Len: j - i}
|
||||
}
|
||||
return Value{v.typ(), unsafe.Pointer(&t), v.flag}
|
||||
}
|
||||
@@ -1405,7 +1385,7 @@ func (v Value) Slice(i, j int) Value {
|
||||
var x []unsafe.Pointer
|
||||
|
||||
// Reinterpret as *unsafeheader.Slice to edit.
|
||||
s := (*unsafeheader.Slice)(unsafe.Pointer(&x))
|
||||
s := (*unsafeheaderSlice)(unsafe.Pointer(&x))
|
||||
s.Len = j - i
|
||||
s.Cap = cap - i
|
||||
if cap-i > 0 {
|
||||
@@ -1417,15 +1397,12 @@ func (v Value) Slice(i, j int) Value {
|
||||
|
||||
fl := v.flag.ro() | flagIndir | flag(Slice)
|
||||
return Value{typ.Common(), unsafe.Pointer(&x), fl}
|
||||
*/
|
||||
panic("todo: reflect.Value.Slice")
|
||||
}
|
||||
|
||||
// Slice3 is the 3-index form of the slice operation: it returns v[i:j:k].
|
||||
// It panics if v's Kind is not Array or Slice, or if v is an unaddressable array,
|
||||
// or if the indexes are out of bounds.
|
||||
func (v Value) Slice3(i, j, k int) Value {
|
||||
/* TODO(xsw):
|
||||
var (
|
||||
cap int
|
||||
typ *sliceType
|
||||
@@ -1446,7 +1423,7 @@ func (v Value) Slice3(i, j, k int) Value {
|
||||
|
||||
case Slice:
|
||||
typ = (*sliceType)(unsafe.Pointer(v.typ()))
|
||||
s := (*unsafeheader.Slice)(v.ptr)
|
||||
s := (*unsafeheaderSlice)(v.ptr)
|
||||
base = s.Data
|
||||
cap = s.Cap
|
||||
}
|
||||
@@ -1460,7 +1437,7 @@ func (v Value) Slice3(i, j, k int) Value {
|
||||
var x []unsafe.Pointer
|
||||
|
||||
// Reinterpret as *unsafeheader.Slice to edit.
|
||||
s := (*unsafeheader.Slice)(unsafe.Pointer(&x))
|
||||
s := (*unsafeheaderSlice)(unsafe.Pointer(&x))
|
||||
s.Len = j - i
|
||||
s.Cap = k - i
|
||||
if k-i > 0 {
|
||||
@@ -1472,8 +1449,6 @@ func (v Value) Slice3(i, j, k int) Value {
|
||||
|
||||
fl := v.flag.ro() | flagIndir | flag(Slice)
|
||||
return Value{typ.Common(), unsafe.Pointer(&x), fl}
|
||||
*/
|
||||
panic("todo: reflect.Value.Slice3")
|
||||
}
|
||||
|
||||
// String returns the string v's underlying value, as a string.
|
||||
@@ -1528,7 +1503,7 @@ func (v Value) TrySend(x Value) bool {
|
||||
|
||||
// Type returns v's type.
|
||||
func (v Value) Type() Type {
|
||||
if v.flag != 0 && v.flag&flagMethod == 0 {
|
||||
if v.flag != 0 && v.flag&flagMethod == 0 && !v.typ_.IsClosure() {
|
||||
return (*rtype)(unsafe.Pointer(v.typ_)) // inline of toRType(v.typ()), for own inlining in inline test
|
||||
}
|
||||
return v.typeSlow()
|
||||
@@ -1540,6 +1515,10 @@ func (v Value) typeSlow() Type {
|
||||
}
|
||||
|
||||
typ := v.typ()
|
||||
// closure func
|
||||
if v.typ_.IsClosure() {
|
||||
return toRType(&v.closureFunc().Type)
|
||||
}
|
||||
if v.flag&flagMethod == 0 {
|
||||
return toRType(v.typ())
|
||||
}
|
||||
@@ -1641,7 +1620,6 @@ func (v Value) UnsafeAddr() uintptr {
|
||||
// element of the slice. If the slice is nil the returned value
|
||||
// is nil. If the slice is empty but non-nil the return value is non-nil.
|
||||
func (v Value) UnsafePointer() unsafe.Pointer {
|
||||
/* TODO(xsw):
|
||||
k := v.kind()
|
||||
switch k {
|
||||
case Pointer:
|
||||
@@ -1664,8 +1642,8 @@ func (v Value) UnsafePointer() unsafe.Pointer {
|
||||
// created via reflect have the same underlying code pointer,
|
||||
// so their Pointers are equal. The function used here must
|
||||
// match the one used in makeMethodValue.
|
||||
code := methodValueCallCodePtr()
|
||||
return *(*unsafe.Pointer)(unsafe.Pointer(&code))
|
||||
_, _, fn := methodReceiver("unsafePointer", v, int(v.flag)>>flagMethodShift)
|
||||
return fn
|
||||
}
|
||||
p := v.pointer()
|
||||
// Non-nil func value points at data block.
|
||||
@@ -1676,11 +1654,9 @@ func (v Value) UnsafePointer() unsafe.Pointer {
|
||||
return p
|
||||
|
||||
case Slice:
|
||||
return (*unsafeheader.Slice)(v.ptr).Data
|
||||
return (*unsafeheaderSlice)(v.ptr).Data
|
||||
}
|
||||
panic(&ValueError{"reflect.Value.UnsafePointer", v.kind()})
|
||||
*/
|
||||
panic("todo: reflect.Value.UnsafePointer")
|
||||
}
|
||||
|
||||
//go:linkname unsafe_New github.com/goplus/llgo/internal/runtime.New
|
||||
@@ -1814,24 +1790,24 @@ func Zero(typ Type) Value {
|
||||
// must match declarations in runtime/map.go.
|
||||
const maxZero = runtime.MaxZero
|
||||
|
||||
//go:linkname zeroVal runtime.ZeroVal
|
||||
var zeroVal [maxZero]byte
|
||||
|
||||
// New returns a Value representing a pointer to a new zero value
|
||||
// for the specified type. That is, the returned Value's Type is PointerTo(typ).
|
||||
func New(typ Type) Value {
|
||||
/*
|
||||
if typ == nil {
|
||||
panic("reflect: New(nil)")
|
||||
}
|
||||
t := &typ.(*rtype).t
|
||||
pt := ptrTo(t)
|
||||
if ifaceIndir(pt) {
|
||||
// This is a pointer to a not-in-heap type.
|
||||
panic("reflect: New of type that may not be allocated in heap (possibly undefined cgo C type)")
|
||||
}
|
||||
ptr := unsafe_New(t)
|
||||
fl := flag(Pointer)
|
||||
return Value{pt, ptr, fl}
|
||||
*/
|
||||
panic("todo: reflect.New")
|
||||
if typ == nil {
|
||||
panic("reflect: New(nil)")
|
||||
}
|
||||
t := &typ.(*rtype).t
|
||||
pt := ptrTo(t)
|
||||
if ifaceIndir(pt) {
|
||||
// This is a pointer to a not-in-heap type.
|
||||
panic("reflect: New of type that may not be allocated in heap (possibly undefined cgo C type)")
|
||||
}
|
||||
ptr := unsafe_New(t)
|
||||
fl := flag(Pointer)
|
||||
return Value{pt, ptr, fl}
|
||||
}
|
||||
|
||||
// NewAt returns a Value representing a pointer to a value of the
|
||||
@@ -1902,7 +1878,9 @@ func typedmemmove(t *abi.Type, dst, src unsafe.Pointer)
|
||||
//go:linkname typedmemclr github.com/goplus/llgo/internal/runtime.Typedmemclr
|
||||
func typedmemclr(t *abi.Type, ptr unsafe.Pointer)
|
||||
|
||||
/* TODO(xsw):
|
||||
/*
|
||||
TODO(xsw):
|
||||
|
||||
// typedmemclrpartial is like typedmemclr but assumes that
|
||||
// dst points off bytes into the value and only clears size bytes.
|
||||
//
|
||||
@@ -1923,9 +1901,10 @@ func typedarrayclear(elemType *abi.Type, ptr unsafe.Pointer, len int)
|
||||
|
||||
//go:noescape
|
||||
func typehash(t *abi.Type, p unsafe.Pointer, h uintptr) uintptr
|
||||
|
||||
func verifyNotInHeapPtr(p uintptr) bool
|
||||
*/
|
||||
func verifyNotInHeapPtr(p uintptr) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
//go:linkname growslice github.com/goplus/llgo/internal/runtime.GrowSlice
|
||||
func growslice(src unsafeheaderSlice, num, etSize int) unsafeheaderSlice
|
||||
@@ -2014,6 +1993,14 @@ func (v Value) MethodByName(name string) Value {
|
||||
return v.Method(m.Index)
|
||||
}
|
||||
|
||||
// NumField returns the number of fields in the struct v.
|
||||
// It panics if v's Kind is not Struct.
|
||||
func (v Value) NumField() int {
|
||||
v.mustBe(Struct)
|
||||
tt := (*structType)(unsafe.Pointer(v.typ()))
|
||||
return len(tt.Fields)
|
||||
}
|
||||
|
||||
// Call calls the function v with the input arguments in.
|
||||
// For example, if len(in) == 3, v.Call(in) represents the Go call v(in[0], in[1], in[2]).
|
||||
// Call panics if v's Kind is not Func.
|
||||
@@ -2046,34 +2033,105 @@ type closure struct {
|
||||
env unsafe.Pointer
|
||||
}
|
||||
|
||||
func toFFIType(typ *abi.Type) *ffi.Type {
|
||||
func toFFIArg(v Value, typ *abi.Type) unsafe.Pointer {
|
||||
kind := typ.Kind()
|
||||
switch {
|
||||
case kind >= abi.Bool && kind <= abi.Complex128:
|
||||
return ffi.Typ[kind]
|
||||
case kind == abi.Pointer || kind == abi.UnsafePointer:
|
||||
return ffi.TypePointer
|
||||
switch kind {
|
||||
case abi.Bool, abi.Int, abi.Int8, abi.Int16, abi.Int32, abi.Int64,
|
||||
abi.Uint, abi.Uint8, abi.Uint16, abi.Uint32, abi.Uint64, abi.Uintptr,
|
||||
abi.Float32, abi.Float64:
|
||||
if v.flag&flagAddr != 0 {
|
||||
return v.ptr
|
||||
} else {
|
||||
return unsafe.Pointer(&v.ptr)
|
||||
}
|
||||
case abi.Complex64, abi.Complex128:
|
||||
return unsafe.Pointer(v.ptr)
|
||||
case abi.Array:
|
||||
if v.flag&flagIndir != 0 {
|
||||
return v.ptr
|
||||
}
|
||||
return unsafe.Pointer(&v.ptr)
|
||||
case abi.Chan:
|
||||
return unsafe.Pointer(&v.ptr)
|
||||
case abi.Func:
|
||||
return unsafe.Pointer(&v.ptr)
|
||||
case abi.Interface:
|
||||
i := v.Interface()
|
||||
return unsafe.Pointer(&i)
|
||||
case abi.Map:
|
||||
return unsafe.Pointer(&v.ptr)
|
||||
case abi.Pointer:
|
||||
return unsafe.Pointer(&v.ptr)
|
||||
case abi.Slice:
|
||||
return v.ptr
|
||||
case abi.String:
|
||||
return v.ptr
|
||||
case abi.Struct:
|
||||
if v.flag&flagIndir != 0 {
|
||||
return v.ptr
|
||||
}
|
||||
return unsafe.Pointer(&v.ptr)
|
||||
case abi.UnsafePointer:
|
||||
return unsafe.Pointer(&v.ptr)
|
||||
}
|
||||
panic("unsupport type " + typ.String())
|
||||
panic("reflect.toFFIArg unsupport type " + v.typ().String())
|
||||
}
|
||||
|
||||
func toFFISig(typ *abi.FuncType, closure bool) (*ffi.Signature, error) {
|
||||
var args []*ffi.Type
|
||||
if closure {
|
||||
args = append(args, ffi.TypePointer)
|
||||
var (
|
||||
ffiTypeClosure = ffi.StructOf(ffi.TypePointer, ffi.TypePointer)
|
||||
)
|
||||
|
||||
func toFFIType(typ *abi.Type) *ffi.Type {
|
||||
kind := typ.Kind()
|
||||
switch kind {
|
||||
case abi.Bool, abi.Int, abi.Int8, abi.Int16, abi.Int32, abi.Int64,
|
||||
abi.Uint, abi.Uint8, abi.Uint16, abi.Uint32, abi.Uint64, abi.Uintptr,
|
||||
abi.Float32, abi.Float64, abi.Complex64, abi.Complex128:
|
||||
return ffi.Typ[kind]
|
||||
case abi.Array:
|
||||
st := typ.ArrayType()
|
||||
return ffi.ArrayOf(toFFIType(st.Elem), int(st.Len))
|
||||
case abi.Chan:
|
||||
return ffi.TypePointer
|
||||
case abi.Func:
|
||||
return ffiTypeClosure
|
||||
case abi.Interface:
|
||||
return ffi.TypeInterface
|
||||
case abi.Map:
|
||||
return ffi.TypePointer
|
||||
case abi.Pointer:
|
||||
return ffi.TypePointer
|
||||
case abi.Slice:
|
||||
return ffi.TypeSlice
|
||||
case abi.String:
|
||||
return ffi.TypeString
|
||||
case abi.Struct:
|
||||
st := typ.StructType()
|
||||
fields := make([]*ffi.Type, len(st.Fields))
|
||||
for i, fs := range st.Fields {
|
||||
fields[i] = toFFIType(fs.Typ)
|
||||
}
|
||||
return ffi.StructOf(fields...)
|
||||
case abi.UnsafePointer:
|
||||
return ffi.TypePointer
|
||||
}
|
||||
for _, in := range typ.In {
|
||||
args = append(args, toFFIType(in))
|
||||
panic("reflect.toFFIType unsupport type " + typ.String())
|
||||
}
|
||||
|
||||
func toFFISig(tin, tout []*abi.Type) (*ffi.Signature, error) {
|
||||
args := make([]*ffi.Type, len(tin))
|
||||
for i, in := range tin {
|
||||
args[i] = toFFIType(in)
|
||||
}
|
||||
var ret *ffi.Type
|
||||
switch n := len(typ.Out); n {
|
||||
switch n := len(tout); n {
|
||||
case 0:
|
||||
ret = ffi.TypeVoid
|
||||
case 1:
|
||||
ret = toFFIType(typ.Out[0])
|
||||
ret = toFFIType(tout[0])
|
||||
default:
|
||||
fields := make([]*ffi.Type, n)
|
||||
for i, out := range typ.Out {
|
||||
for i, out := range tout {
|
||||
fields[i] = toFFIType(out)
|
||||
}
|
||||
ret = ffi.StructOf(fields...)
|
||||
@@ -2081,25 +2139,59 @@ func toFFISig(typ *abi.FuncType, closure bool) (*ffi.Signature, error) {
|
||||
return ffi.NewSignature(ret, args...)
|
||||
}
|
||||
|
||||
func (v Value) closureFunc() *abi.FuncType {
|
||||
ft := *v.typ_.StructType().Fields[0].Typ.FuncType()
|
||||
ft.In = ft.In[1:]
|
||||
return &ft
|
||||
}
|
||||
|
||||
func (v Value) call(op string, in []Value) (out []Value) {
|
||||
var (
|
||||
tin []*abi.Type
|
||||
tout []*abi.Type
|
||||
args []unsafe.Pointer
|
||||
fn unsafe.Pointer
|
||||
ret unsafe.Pointer
|
||||
args []unsafe.Pointer
|
||||
ioff int
|
||||
)
|
||||
if v.flag&flagClosure != 0 {
|
||||
c := (*closure)(v.ptr)
|
||||
if v.typ_.IsClosure() {
|
||||
ft := v.typ_.StructType().Fields[0].Typ.FuncType()
|
||||
tin = ft.In
|
||||
tout = ft.Out
|
||||
c := (*struct {
|
||||
fn unsafe.Pointer
|
||||
env unsafe.Pointer
|
||||
})(v.ptr)
|
||||
fn = c.fn
|
||||
ioff = 1
|
||||
args = append(args, unsafe.Pointer(&c.env))
|
||||
} else {
|
||||
if v.flag&flagIndir != 0 {
|
||||
fn = *(*unsafe.Pointer)(v.ptr)
|
||||
if v.flag&flagMethod != 0 {
|
||||
var (
|
||||
rcvrtype *abi.Type
|
||||
ft *abi.FuncType
|
||||
)
|
||||
rcvrtype, ft, fn = methodReceiver(op, v, int(v.flag)>>flagMethodShift)
|
||||
tin = append([]*abi.Type{rcvrtype}, ft.In...)
|
||||
tout = ft.Out
|
||||
ioff = 1
|
||||
if v.flag&flagIndir != 0 {
|
||||
args = append(args, v.ptr)
|
||||
} else {
|
||||
args = append(args, unsafe.Pointer(&v.ptr))
|
||||
}
|
||||
} else {
|
||||
fn = v.ptr
|
||||
if v.flag&flagIndir != 0 {
|
||||
fn = *(*unsafe.Pointer)(v.ptr)
|
||||
} else {
|
||||
fn = v.ptr
|
||||
}
|
||||
ft := v.typ_.FuncType()
|
||||
tin = ft.In
|
||||
tout = ft.Out
|
||||
}
|
||||
}
|
||||
ft := v.typ().FuncType()
|
||||
sig, err := toFFISig(ft, v.flag&flagClosure != 0)
|
||||
sig, err := toFFISig(tin, tout)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -2107,20 +2199,21 @@ func (v Value) call(op string, in []Value) (out []Value) {
|
||||
v := runtime.AllocZ(sig.RType.Size)
|
||||
ret = unsafe.Pointer(&v)
|
||||
}
|
||||
for _, in := range in {
|
||||
if in.flag&flagIndir != 0 {
|
||||
args = append(args, in.ptr)
|
||||
} else {
|
||||
args = append(args, unsafe.Pointer(&in.ptr))
|
||||
}
|
||||
for i, in := range in {
|
||||
args = append(args, toFFIArg(in, tin[ioff+i]))
|
||||
}
|
||||
ffi.Call(sig, fn, ret, args...)
|
||||
switch n := len(ft.Out); n {
|
||||
switch n := len(tout); n {
|
||||
case 0:
|
||||
case 1:
|
||||
return []Value{NewAt(toType(ft.Out[0]), ret).Elem()}
|
||||
return []Value{NewAt(toType(tout[0]), ret).Elem()}
|
||||
default:
|
||||
panic("TODO multi ret")
|
||||
out = make([]Value, n)
|
||||
var off uintptr
|
||||
for i, tout := range tout {
|
||||
out[i] = NewAt(toType(tout), add(ret, off, "")).Elem()
|
||||
off += tout.Size()
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -2415,3 +2508,54 @@ func (v Value) call(op string, in []Value) (out []Value) {
|
||||
|
||||
// return ret
|
||||
// }
|
||||
|
||||
// methodReceiver returns information about the receiver
|
||||
// described by v. The Value v may or may not have the
|
||||
// flagMethod bit set, so the kind cached in v.flag should
|
||||
// not be used.
|
||||
// The return value rcvrtype gives the method's actual receiver type.
|
||||
// The return value t gives the method type signature (without the receiver).
|
||||
// The return value fn is a pointer to the method code.
|
||||
func methodReceiver(op string, v Value, methodIndex int) (rcvrtype *abi.Type, t *funcType, fn unsafe.Pointer) {
|
||||
i := methodIndex
|
||||
if v.typ().Kind() == abi.Interface {
|
||||
tt := (*interfaceType)(unsafe.Pointer(v.typ()))
|
||||
if uint(i) >= uint(len(tt.Methods)) {
|
||||
panic("reflect: internal error: invalid method index")
|
||||
}
|
||||
m := &tt.Methods[i]
|
||||
if !abi.IsExported(m.Name()) {
|
||||
panic("reflect: " + op + " of unexported method")
|
||||
}
|
||||
iface := (*nonEmptyInterface)(v.ptr)
|
||||
if iface.itab == nil {
|
||||
panic("reflect: " + op + " of method on nil interface value")
|
||||
}
|
||||
rcvrtype = iface.itab.typ
|
||||
fn = unsafe.Pointer(&iface.itab.fun[i])
|
||||
t = (*funcType)(unsafe.Pointer(m.Typ_))
|
||||
} else {
|
||||
rcvrtype = v.typ()
|
||||
ms := v.typ().ExportedMethods()
|
||||
if uint(i) >= uint(len(ms)) {
|
||||
panic("reflect: internal error: invalid method index")
|
||||
}
|
||||
m := ms[i]
|
||||
if !abi.IsExported(m.Name()) {
|
||||
panic("reflect: " + op + " of unexported method")
|
||||
}
|
||||
ifn := m.Ifn_
|
||||
fn = unsafe.Pointer(ifn)
|
||||
t = (*funcType)(unsafe.Pointer(m.Mtyp_))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//go:linkname chancap github.com/goplus/llgo/internal/runtime.ChanCap
|
||||
func chancap(ch unsafe.Pointer) int
|
||||
|
||||
//go:linkname chanlen github.com/goplus/llgo/internal/runtime.ChanLen
|
||||
func chanlen(ch unsafe.Pointer) int
|
||||
|
||||
//go:linkname maplen github.com/goplus/llgo/internal/runtime.MapLen
|
||||
func maplen(ch unsafe.Pointer) int
|
||||
|
||||
Reference in New Issue
Block a user