Merge pull request #852 from visualfc/reflect.func

internal/lib/reflect: support method call
This commit is contained in:
xushiwei
2024-11-21 07:42:18 +08:00
committed by GitHub
7 changed files with 6004 additions and 4607 deletions

101
cl/_testgo/reflect/in.go Normal file
View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -388,11 +388,16 @@ func (t *Type) IfaceIndir() bool {
return t.Kind_&KindDirectIface == 0 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 { func (t *Type) IsDirectIface() bool {
return t.Kind_&KindDirectIface != 0 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. // Size returns the size of data with type t.
func (t *Type) Size() uintptr { return t.Size_ } func (t *Type) Size() uintptr { return t.Size_ }

View File

@@ -22,6 +22,13 @@
package reflect package reflect
import (
"unsafe"
"github.com/goplus/llgo/internal/abi"
"github.com/goplus/llgo/internal/runtime"
)
/* /*
import ( import (
"unsafe" "unsafe"
@@ -111,7 +118,6 @@ type methodValue struct {
// reflect can tell, but the true func representation can be handled // reflect can tell, but the true func representation can be handled
// by code like Convert and Interface and Assign. // by code like Convert and Interface and Assign.
func makeMethodValue(op string, v Value) Value { func makeMethodValue(op string, v Value) Value {
/*
if v.flag&flagMethod == 0 { if v.flag&flagMethod == 0 {
panic("reflect: internal error: invalid use of makeMethodValue") panic("reflect: internal error: invalid use of makeMethodValue")
} }
@@ -122,31 +128,27 @@ func makeMethodValue(op string, v Value) Value {
rcvr := Value{v.typ(), v.ptr, fl} rcvr := Value{v.typ(), v.ptr, fl}
// v.Type returns the actual type of the method value. // v.Type returns the actual type of the method value.
ftyp := (*funcType)(unsafe.Pointer(v.Type().(*rtype))) ftyp := *(*funcType)(unsafe.Pointer(v.Type().(*rtype)))
ptyp := rtypeOf(unsafe.Pointer(uintptr(0)))
code := methodValueCallCodePtr() ftyp.In = append([]*abi.Type{ptyp}, ftyp.In...)
typ := runtime.Struct("", 2*unsafe.Sizeof(0), abi.StructField{
// methodValue contains a stack map for use by the runtime Name_: "llgo_ctx",
_, _, abid := funcLayout(ftyp, nil) Typ: &ftyp.Type,
fv := &methodValue{ }, abi.StructField{
makeFuncCtxt: makeFuncCtxt{ Name_: "f",
fn: code, Typ: ptyp,
stack: abid.stackPtrs, Offset: unsafe.Sizeof(0),
argLen: abid.stackCallArgsSize, })
regPtrs: abid.inRegPtrs, typ.TFlag |= abi.TFlagClosure
}, _, _, fn := methodReceiver(op, rcvr, int(v.flag)>>flagMethodShift)
method: int(v.flag) >> flagMethodShift, fv := &struct {
rcvr: rcvr, fn unsafe.Pointer
} env unsafe.Pointer
}{fn, v.ptr}
// Cause panic if method is not appropriate. // Cause panic if method is not appropriate.
// The panic would still happen during the call if we omit this, // The panic would still happen during the call if we omit this,
// but we want Interface() and other operations to fail early. // but we want Interface() and other operations to fail early.
methodReceiver(op, fv.rcvr, fv.method) return Value{typ, unsafe.Pointer(fv), v.flag&flagRO | flagIndir | flag(Func)}
return Value{ftyp.Common(), unsafe.Pointer(fv), v.flag&flagRO | flag(Func)}
*/
panic("todo: reflect.makeMethodValue")
} }
/* /*

View File

@@ -642,58 +642,43 @@ func (t *rtype) NumField() int {
} }
func (t *rtype) In(i int) Type { func (t *rtype) In(i int) Type {
/*
if t.Kind() != Func { if t.Kind() != Func {
panic("reflect: In of non-func type " + t.String()) panic("reflect: In of non-func type " + t.String())
} }
tt := (*abi.FuncType)(unsafe.Pointer(t)) tt := (*abi.FuncType)(unsafe.Pointer(t))
return toType(tt.InSlice()[i]) return toType(tt.In[i])
*/
panic("todo: reflect.rtype.In")
} }
func (t *rtype) NumIn() int { func (t *rtype) NumIn() int {
/*
if t.Kind() != Func { if t.Kind() != Func {
panic("reflect: NumIn of non-func type " + t.String()) panic("reflect: NumIn of non-func type " + t.String())
} }
tt := (*abi.FuncType)(unsafe.Pointer(t)) tt := (*abi.FuncType)(unsafe.Pointer(t))
return tt.NumIn() return len(tt.In)
*/
panic("todo: reflect.rtype.NumIn")
} }
func (t *rtype) NumOut() int { func (t *rtype) NumOut() int {
/*
if t.Kind() != Func { if t.Kind() != Func {
panic("reflect: NumOut of non-func type " + t.String()) panic("reflect: NumOut of non-func type " + t.String())
} }
tt := (*abi.FuncType)(unsafe.Pointer(t)) tt := (*abi.FuncType)(unsafe.Pointer(t))
return tt.NumOut() return len(tt.Out)
*/
panic("todo: reflect.rtype.NumOut")
} }
func (t *rtype) Out(i int) Type { func (t *rtype) Out(i int) Type {
/*
if t.Kind() != Func { if t.Kind() != Func {
panic("reflect: Out of non-func type " + t.String()) panic("reflect: Out of non-func type " + t.String())
} }
tt := (*abi.FuncType)(unsafe.Pointer(t)) tt := (*abi.FuncType)(unsafe.Pointer(t))
return toType(tt.OutSlice()[i]) return toType(tt.Out[i])
*/
panic("todo: reflect.rtype.Out")
} }
func (t *rtype) IsVariadic() bool { func (t *rtype) IsVariadic() bool {
/*
if t.Kind() != Func { if t.Kind() != Func {
panic("reflect: IsVariadic of non-func type " + t.String()) panic("reflect: IsVariadic of non-func type " + t.String())
} }
tt := (*abi.FuncType)(unsafe.Pointer(t)) tt := (*abi.FuncType)(unsafe.Pointer(t))
return tt.IsVariadic() return tt.Variadic()
*/
panic("todo: reflect.rtype.IsVariadic")
} }
// add returns p+x. // 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. // If i is a nil interface value, TypeOf returns nil.
func TypeOf(i any) Type { func TypeOf(i any) Type {
eface := *(*emptyInterface)(unsafe.Pointer(&i)) 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 // Noescape so this doesn't make i to escape. See the comment
// at Value.typ for why this is safe. // at Value.typ for why this is safe.
return toType((*abi.Type)(unsafe.Pointer(eface.typ))) return toType((*abi.Type)(unsafe.Pointer(eface.typ)))

View File

@@ -22,13 +22,14 @@ package reflect
import ( import (
"errors" "errors"
"math"
"unsafe" "unsafe"
"github.com/goplus/llgo/x/ffi" "github.com/goplus/llgo/c/bitcast"
"github.com/goplus/llgo/internal/abi" "github.com/goplus/llgo/internal/abi"
"github.com/goplus/llgo/internal/runtime" "github.com/goplus/llgo/internal/runtime"
"github.com/goplus/llgo/internal/runtime/goarch" "github.com/goplus/llgo/internal/runtime/goarch"
"github.com/goplus/llgo/x/ffi"
) )
// Value is the reflection interface to a Go value. // Value is the reflection interface to a Go value.
@@ -94,7 +95,6 @@ const (
flagIndir flag = 1 << 7 flagIndir flag = 1 << 7
flagAddr flag = 1 << 8 flagAddr flag = 1 << 8
flagMethod flag = 1 << 9 flagMethod flag = 1 << 9
flagClosure flag = 1 << 10
flagMethodShift = 10 flagMethodShift = 10
flagRO flag = flagStickyRO | flagEmbedRO flagRO flag = flagStickyRO | flagEmbedRO
) )
@@ -178,15 +178,12 @@ func unpackEface(i any) Value {
return Value{} return Value{}
} }
f := flag(t.Kind()) f := flag(t.Kind())
if t.IsClosure() {
f = flag(Func)
}
if t.IfaceIndir() { if t.IfaceIndir() {
f |= flagIndir 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} return Value{t, e.word, f}
} }
@@ -320,7 +317,10 @@ func (v Value) Bool() bool {
if v.kind() != Bool { if v.kind() != Bool {
v.panicNotBool() v.panicNotBool()
} }
if v.flag&flagAddr != 0 {
return *(*bool)(v.ptr) return *(*bool)(v.ptr)
}
return uintptr(v.ptr) != 0
} }
func (v Value) panicNotBool() { func (v Value) panicNotBool() {
@@ -341,7 +341,6 @@ func (v Value) Bytes() []byte {
} }
func (v Value) bytesSlow() []byte { func (v Value) bytesSlow() []byte {
/*
switch v.kind() { switch v.kind() {
case Slice: case Slice:
if v.typ().Elem().Kind() != abi.Uint8 { if v.typ().Elem().Kind() != abi.Uint8 {
@@ -361,8 +360,6 @@ func (v Value) bytesSlow() []byte {
return unsafe.Slice(p, n) return unsafe.Slice(p, n)
} }
panic(&ValueError{"reflect.Value.Bytes", v.kind()}) panic(&ValueError{"reflect.Value.Bytes", v.kind()})
*/
panic("todo: reflect.Value.byteSlow")
} }
// runes returns v's underlying value. // runes returns v's underlying value.
@@ -397,18 +394,14 @@ func (v Value) CanSet() bool {
// Cap returns v's capacity. // Cap returns v's capacity.
// It panics if v's Kind is not Array, Chan, Slice or pointer to Array. // It panics if v's Kind is not Array, Chan, Slice or pointer to Array.
func (v Value) Cap() int { func (v Value) Cap() int {
/* TODO(xsw):
// capNonSlice is split out to keep Cap inlineable for slice kinds. // capNonSlice is split out to keep Cap inlineable for slice kinds.
if v.kind() == Slice { if v.kind() == Slice {
return (*unsafeheader.Slice)(v.ptr).Cap return (*unsafeheaderSlice)(v.ptr).Cap
} }
return v.capNonSlice() return v.capNonSlice()
*/
panic("todo: reflect.Value.Cap")
} }
func (v Value) capNonSlice() int { func (v Value) capNonSlice() int {
/* TODO(xsw):
k := v.kind() k := v.kind()
switch k { switch k {
case Array: 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("reflect: call of reflect.Value.Cap on ptr to non-array Value")
} }
panic(&ValueError{"reflect.Value.Cap", v.kind()}) panic(&ValueError{"reflect.Value.Cap", v.kind()})
*/
panic("todo: reflect.Value.capNonSlice")
} }
// Close closes the channel v. // 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. // 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. // It panics if v's Kind is not Struct or i is out of range.
func (v Value) Field(i int) Value { func (v Value) Field(i int) Value {
/* TODO(xsw):
if v.kind() != Struct { if v.kind() != Struct {
panic(&ValueError{"reflect.Value.Field", v.kind()}) 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. // Inherit permission bits from v, but clear flagEmbedRO.
fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind()) fl := v.flag&(flagStickyRO|flagIndir|flagAddr) | flag(typ.Kind())
// Using an unexported field forces flagRO. // Using an unexported field forces flagRO.
if !field.Name.IsExported() { if !field.Exported() {
if field.Embedded() { if field.Embedded() {
fl |= flagEmbedRO fl |= flagEmbedRO
} else { } else {
@@ -549,8 +539,6 @@ func (v Value) Field(i int) Value {
// so v.ptr + field.offset is still the correct address. // so v.ptr + field.offset is still the correct address.
ptr := add(v.ptr, field.Offset, "same as non-reflect &v.field") ptr := add(v.ptr, field.Offset, "same as non-reflect &v.field")
return Value{typ, ptr, fl} return Value{typ, ptr, fl}
*/
panic("todo: reflect.Value.Field")
} }
// FieldByIndex returns the nested field corresponding to index. // FieldByIndex returns the nested field corresponding to index.
@@ -634,12 +622,21 @@ func (v Value) CanFloat() bool {
// It panics if v's Kind is not Float32 or Float64 // It panics if v's Kind is not Float32 or Float64
func (v Value) Float() float64 { func (v Value) Float() float64 {
k := v.kind() k := v.kind()
if v.flag&flagAddr != 0 {
switch k { switch k {
case Float32: case Float32:
return float64(*(*float32)(v.ptr)) return float64(*(*float32)(v.ptr))
case Float64: case Float64:
return *(*float64)(v.ptr) 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()}) panic(&ValueError{"reflect.Value.Float", v.kind()})
} }
@@ -794,7 +791,6 @@ func valueInterface(v Value, safe bool) any {
// Deprecated: The memory representation of interface values is not // Deprecated: The memory representation of interface values is not
// compatible with InterfaceData. // compatible with InterfaceData.
func (v Value) InterfaceData() [2]uintptr { func (v Value) InterfaceData() [2]uintptr {
/*
v.mustBe(Interface) v.mustBe(Interface)
// The compiler loses track as it converts to uintptr. Force escape. // The compiler loses track as it converts to uintptr. Force escape.
escapes(v.ptr) escapes(v.ptr)
@@ -804,8 +800,6 @@ func (v Value) InterfaceData() [2]uintptr {
// that can be abused. // that can be abused.
// Interface value is always bigger than a word; assume flagIndir. // Interface value is always bigger than a word; assume flagIndir.
return *(*[2]uintptr)(v.ptr) return *(*[2]uintptr)(v.ptr)
*/
panic("todo: reflect.Value.InterfaceData")
} }
// IsNil reports whether its argument v is nil. The argument must be // IsNil reports whether its argument v is nil. The argument must be
@@ -847,7 +841,6 @@ func (v Value) IsValid() bool {
// IsZero reports whether v is the zero value for its type. // IsZero reports whether v is the zero value for its type.
// It panics if the argument is invalid. // It panics if the argument is invalid.
func (v Value) IsZero() bool { func (v Value) IsZero() bool {
/*
switch v.kind() { switch v.kind() {
case Bool: case Bool:
return !v.Bool() return !v.Bool()
@@ -905,14 +898,11 @@ func (v Value) IsZero() bool {
// as a default value doesn't makes sense here. // as a default value doesn't makes sense here.
panic(&ValueError{"reflect.Value.IsZero", v.Kind()}) panic(&ValueError{"reflect.Value.IsZero", v.Kind()})
} }
*/
panic("todo: reflect.Value.IsZero")
} }
// SetZero sets v to be the zero value of v's type. // SetZero sets v to be the zero value of v's type.
// It panics if CanSet returns false. // It panics if CanSet returns false.
func (v Value) SetZero() { func (v Value) SetZero() {
/*
v.mustBeAssignable() v.mustBeAssignable()
switch v.kind() { switch v.kind() {
case Bool: case Bool:
@@ -950,7 +940,7 @@ func (v Value) SetZero() {
case String: case String:
*(*string)(v.ptr) = "" *(*string)(v.ptr) = ""
case Slice: case Slice:
*(*unsafeheader.Slice)(v.ptr) = unsafeheader.Slice{} *(*unsafeheaderSlice)(v.ptr) = unsafeheaderSlice{}
case Interface: case Interface:
*(*[2]unsafe.Pointer)(v.ptr) = [2]unsafe.Pointer{} *(*[2]unsafe.Pointer)(v.ptr) = [2]unsafe.Pointer{}
case Chan, Func, Map, Pointer, UnsafePointer: case Chan, Func, Map, Pointer, UnsafePointer:
@@ -962,8 +952,6 @@ func (v Value) SetZero() {
// as a default value doesn't makes sense here. // as a default value doesn't makes sense here.
panic(&ValueError{"reflect.Value.SetZero", v.Kind()}) panic(&ValueError{"reflect.Value.SetZero", v.Kind()})
} }
*/
panic("todo: reflect.Value.SetZero")
} }
// Kind returns v's Kind. // Kind returns v's Kind.
@@ -983,7 +971,6 @@ func (v Value) Len() int {
} }
func (v Value) lenNonSlice() int { func (v Value) lenNonSlice() int {
/*
switch k := v.kind(); k { switch k := v.kind(); k {
case Array: case Array:
tt := (*arrayType)(unsafe.Pointer(v.typ())) tt := (*arrayType)(unsafe.Pointer(v.typ()))
@@ -994,7 +981,7 @@ func (v Value) lenNonSlice() int {
return maplen(v.pointer()) return maplen(v.pointer())
case String: case String:
// String is bigger than a word; assume flagIndir. // String is bigger than a word; assume flagIndir.
return (*unsafeheader.String)(v.ptr).Len return (*unsafeheaderString)(v.ptr).Len
case Ptr: case Ptr:
if v.typ().Elem().Kind() == abi.Array { if v.typ().Elem().Kind() == abi.Array {
return v.typ().Elem().Len() return v.typ().Elem().Len()
@@ -1002,8 +989,6 @@ func (v Value) lenNonSlice() int {
panic("reflect: call of reflect.Value.Len on ptr to non-array Value") panic("reflect: call of reflect.Value.Len on ptr to non-array Value")
} }
panic(&ValueError{"reflect.Value.Len", v.kind()}) panic(&ValueError{"reflect.Value.Len", v.kind()})
*/
panic("todo: reflect.Value.lenNonSlice")
} }
// Pointer returns v's value as a uintptr. // 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 // so their Pointers are equal. The function used here must
// match the one used in makeMethodValue. // match the one used in makeMethodValue.
// return methodValueCallCodePtr() // return methodValueCallCodePtr()
_, _, fn := methodReceiver("unsafePointer", v, int(v.flag)>>flagMethodShift)
return uintptr(fn)
} }
p := v.pointer() p := v.pointer()
// Non-nil func value points at data block. // 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 // It panics if v's Kind is not Slice or if n is negative or
// greater than the capacity of the slice. // greater than the capacity of the slice.
func (v Value) SetLen(n int) { func (v Value) SetLen(n int) {
/* TODO(xsw):
v.mustBeAssignable() v.mustBeAssignable()
v.mustBe(Slice) v.mustBe(Slice)
s := (*unsafeheader.Slice)(v.ptr) s := (*unsafeheaderSlice)(v.ptr)
if uint(n) > uint(s.Cap) { if uint(n) > uint(s.Cap) {
panic("reflect: slice length out of range in SetLen") panic("reflect: slice length out of range in SetLen")
} }
s.Len = n s.Len = n
*/
panic("todo: reflect.Value.SetLen")
} }
// SetCap sets v's capacity to n. // 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 // 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. // greater than the capacity of the slice.
func (v Value) SetCap(n int) { func (v Value) SetCap(n int) {
/* TODO(xsw):
v.mustBeAssignable() v.mustBeAssignable()
v.mustBe(Slice) v.mustBe(Slice)
s := (*unsafeheader.Slice)(v.ptr) s := (*unsafeheaderSlice)(v.ptr)
if n < s.Len || n > s.Cap { if n < s.Len || n > s.Cap {
panic("reflect: slice capacity out of range in SetCap") panic("reflect: slice capacity out of range in SetCap")
} }
s.Cap = n s.Cap = n
*/
panic("todo: reflect.Value.SetCap")
} }
// SetMapIndex sets the element associated with key in the map v to elem. // 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, // 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. // or if the indexes are out of bounds.
func (v Value) Slice(i, j int) Value { func (v Value) Slice(i, j int) Value {
/* TODO(xsw):
var ( var (
cap int cap int
typ *sliceType typ *sliceType
@@ -1381,18 +1361,18 @@ func (v Value) Slice(i, j int) Value {
case Slice: case Slice:
typ = (*sliceType)(unsafe.Pointer(v.typ())) typ = (*sliceType)(unsafe.Pointer(v.typ()))
s := (*unsafeheader.Slice)(v.ptr) s := (*unsafeheaderSlice)(v.ptr)
base = s.Data base = s.Data
cap = s.Cap cap = s.Cap
case String: case String:
s := (*unsafeheader.String)(v.ptr) s := (*unsafeheaderString)(v.ptr)
if i < 0 || j < i || j > s.Len { if i < 0 || j < i || j > s.Len {
panic("reflect.Value.Slice: string slice index out of bounds") panic("reflect.Value.Slice: string slice index out of bounds")
} }
var t unsafeheader.String var t unsafeheaderString
if i < s.Len { 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} 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 var x []unsafe.Pointer
// Reinterpret as *unsafeheader.Slice to edit. // Reinterpret as *unsafeheader.Slice to edit.
s := (*unsafeheader.Slice)(unsafe.Pointer(&x)) s := (*unsafeheaderSlice)(unsafe.Pointer(&x))
s.Len = j - i s.Len = j - i
s.Cap = cap - i s.Cap = cap - i
if cap-i > 0 { if cap-i > 0 {
@@ -1417,15 +1397,12 @@ func (v Value) Slice(i, j int) Value {
fl := v.flag.ro() | flagIndir | flag(Slice) fl := v.flag.ro() | flagIndir | flag(Slice)
return Value{typ.Common(), unsafe.Pointer(&x), fl} 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]. // 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, // 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. // or if the indexes are out of bounds.
func (v Value) Slice3(i, j, k int) Value { func (v Value) Slice3(i, j, k int) Value {
/* TODO(xsw):
var ( var (
cap int cap int
typ *sliceType typ *sliceType
@@ -1446,7 +1423,7 @@ func (v Value) Slice3(i, j, k int) Value {
case Slice: case Slice:
typ = (*sliceType)(unsafe.Pointer(v.typ())) typ = (*sliceType)(unsafe.Pointer(v.typ()))
s := (*unsafeheader.Slice)(v.ptr) s := (*unsafeheaderSlice)(v.ptr)
base = s.Data base = s.Data
cap = s.Cap cap = s.Cap
} }
@@ -1460,7 +1437,7 @@ func (v Value) Slice3(i, j, k int) Value {
var x []unsafe.Pointer var x []unsafe.Pointer
// Reinterpret as *unsafeheader.Slice to edit. // Reinterpret as *unsafeheader.Slice to edit.
s := (*unsafeheader.Slice)(unsafe.Pointer(&x)) s := (*unsafeheaderSlice)(unsafe.Pointer(&x))
s.Len = j - i s.Len = j - i
s.Cap = k - i s.Cap = k - i
if k-i > 0 { if k-i > 0 {
@@ -1472,8 +1449,6 @@ func (v Value) Slice3(i, j, k int) Value {
fl := v.flag.ro() | flagIndir | flag(Slice) fl := v.flag.ro() | flagIndir | flag(Slice)
return Value{typ.Common(), unsafe.Pointer(&x), fl} return Value{typ.Common(), unsafe.Pointer(&x), fl}
*/
panic("todo: reflect.Value.Slice3")
} }
// String returns the string v's underlying value, as a string. // 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. // Type returns v's type.
func (v Value) Type() 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 (*rtype)(unsafe.Pointer(v.typ_)) // inline of toRType(v.typ()), for own inlining in inline test
} }
return v.typeSlow() return v.typeSlow()
@@ -1540,6 +1515,10 @@ func (v Value) typeSlow() Type {
} }
typ := v.typ() typ := v.typ()
// closure func
if v.typ_.IsClosure() {
return toRType(&v.closureFunc().Type)
}
if v.flag&flagMethod == 0 { if v.flag&flagMethod == 0 {
return toRType(v.typ()) 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 // 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. // is nil. If the slice is empty but non-nil the return value is non-nil.
func (v Value) UnsafePointer() unsafe.Pointer { func (v Value) UnsafePointer() unsafe.Pointer {
/* TODO(xsw):
k := v.kind() k := v.kind()
switch k { switch k {
case Pointer: case Pointer:
@@ -1664,8 +1642,8 @@ func (v Value) UnsafePointer() unsafe.Pointer {
// created via reflect have the same underlying code pointer, // created via reflect have the same underlying code pointer,
// so their Pointers are equal. The function used here must // so their Pointers are equal. The function used here must
// match the one used in makeMethodValue. // match the one used in makeMethodValue.
code := methodValueCallCodePtr() _, _, fn := methodReceiver("unsafePointer", v, int(v.flag)>>flagMethodShift)
return *(*unsafe.Pointer)(unsafe.Pointer(&code)) return fn
} }
p := v.pointer() p := v.pointer()
// Non-nil func value points at data block. // Non-nil func value points at data block.
@@ -1676,11 +1654,9 @@ func (v Value) UnsafePointer() unsafe.Pointer {
return p return p
case Slice: case Slice:
return (*unsafeheader.Slice)(v.ptr).Data return (*unsafeheaderSlice)(v.ptr).Data
} }
panic(&ValueError{"reflect.Value.UnsafePointer", v.kind()}) panic(&ValueError{"reflect.Value.UnsafePointer", v.kind()})
*/
panic("todo: reflect.Value.UnsafePointer")
} }
//go:linkname unsafe_New github.com/goplus/llgo/internal/runtime.New //go:linkname unsafe_New github.com/goplus/llgo/internal/runtime.New
@@ -1814,10 +1790,12 @@ func Zero(typ Type) Value {
// must match declarations in runtime/map.go. // must match declarations in runtime/map.go.
const maxZero = runtime.MaxZero 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 // 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). // for the specified type. That is, the returned Value's Type is PointerTo(typ).
func New(typ Type) Value { func New(typ Type) Value {
/*
if typ == nil { if typ == nil {
panic("reflect: New(nil)") panic("reflect: New(nil)")
} }
@@ -1830,8 +1808,6 @@ func New(typ Type) Value {
ptr := unsafe_New(t) ptr := unsafe_New(t)
fl := flag(Pointer) fl := flag(Pointer)
return Value{pt, ptr, fl} return Value{pt, ptr, fl}
*/
panic("todo: reflect.New")
} }
// NewAt returns a Value representing a pointer to a value of the // 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 //go:linkname typedmemclr github.com/goplus/llgo/internal/runtime.Typedmemclr
func typedmemclr(t *abi.Type, ptr unsafe.Pointer) func typedmemclr(t *abi.Type, ptr unsafe.Pointer)
/* TODO(xsw): /*
TODO(xsw):
// typedmemclrpartial is like typedmemclr but assumes that // typedmemclrpartial is like typedmemclr but assumes that
// dst points off bytes into the value and only clears size bytes. // 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 //go:noescape
func typehash(t *abi.Type, p unsafe.Pointer, h uintptr) uintptr 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 //go:linkname growslice github.com/goplus/llgo/internal/runtime.GrowSlice
func growslice(src unsafeheaderSlice, num, etSize int) unsafeheaderSlice func growslice(src unsafeheaderSlice, num, etSize int) unsafeheaderSlice
@@ -2014,6 +1993,14 @@ func (v Value) MethodByName(name string) Value {
return v.Method(m.Index) 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. // 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]). // 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. // Call panics if v's Kind is not Func.
@@ -2046,34 +2033,105 @@ type closure struct {
env unsafe.Pointer env unsafe.Pointer
} }
func toFFIType(typ *abi.Type) *ffi.Type { func toFFIArg(v Value, typ *abi.Type) unsafe.Pointer {
kind := typ.Kind() kind := typ.Kind()
switch { switch kind {
case kind >= abi.Bool && kind <= abi.Complex128: case abi.Bool, abi.Int, abi.Int8, abi.Int16, abi.Int32, abi.Int64,
return ffi.Typ[kind] abi.Uint, abi.Uint8, abi.Uint16, abi.Uint32, abi.Uint64, abi.Uintptr,
case kind == abi.Pointer || kind == abi.UnsafePointer: abi.Float32, abi.Float64:
return ffi.TypePointer if v.flag&flagAddr != 0 {
return v.ptr
} else {
return unsafe.Pointer(&v.ptr)
} }
panic("unsupport type " + typ.String()) 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("reflect.toFFIArg unsupport type " + v.typ().String())
} }
func toFFISig(typ *abi.FuncType, closure bool) (*ffi.Signature, error) { var (
var args []*ffi.Type ffiTypeClosure = ffi.StructOf(ffi.TypePointer, ffi.TypePointer)
if closure { )
args = append(args, 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)
} }
for _, in := range typ.In { return ffi.StructOf(fields...)
args = append(args, toFFIType(in)) case abi.UnsafePointer:
return ffi.TypePointer
}
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 var ret *ffi.Type
switch n := len(typ.Out); n { switch n := len(tout); n {
case 0: case 0:
ret = ffi.TypeVoid ret = ffi.TypeVoid
case 1: case 1:
ret = toFFIType(typ.Out[0]) ret = toFFIType(tout[0])
default: default:
fields := make([]*ffi.Type, n) fields := make([]*ffi.Type, n)
for i, out := range typ.Out { for i, out := range tout {
fields[i] = toFFIType(out) fields[i] = toFFIType(out)
} }
ret = ffi.StructOf(fields...) ret = ffi.StructOf(fields...)
@@ -2081,25 +2139,59 @@ func toFFISig(typ *abi.FuncType, closure bool) (*ffi.Signature, error) {
return ffi.NewSignature(ret, args...) 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) { func (v Value) call(op string, in []Value) (out []Value) {
var ( var (
tin []*abi.Type
tout []*abi.Type
args []unsafe.Pointer
fn unsafe.Pointer fn unsafe.Pointer
ret unsafe.Pointer ret unsafe.Pointer
args []unsafe.Pointer ioff int
) )
if v.flag&flagClosure != 0 { if v.typ_.IsClosure() {
c := (*closure)(v.ptr) 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 fn = c.fn
ioff = 1
args = append(args, unsafe.Pointer(&c.env)) args = append(args, unsafe.Pointer(&c.env))
} else {
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 { } else {
if v.flag&flagIndir != 0 { if v.flag&flagIndir != 0 {
fn = *(*unsafe.Pointer)(v.ptr) fn = *(*unsafe.Pointer)(v.ptr)
} else { } else {
fn = v.ptr 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 { if err != nil {
panic(err) panic(err)
} }
@@ -2107,20 +2199,21 @@ func (v Value) call(op string, in []Value) (out []Value) {
v := runtime.AllocZ(sig.RType.Size) v := runtime.AllocZ(sig.RType.Size)
ret = unsafe.Pointer(&v) ret = unsafe.Pointer(&v)
} }
for _, in := range in { for i, in := range in {
if in.flag&flagIndir != 0 { args = append(args, toFFIArg(in, tin[ioff+i]))
args = append(args, in.ptr)
} else {
args = append(args, unsafe.Pointer(&in.ptr))
}
} }
ffi.Call(sig, fn, ret, args...) ffi.Call(sig, fn, ret, args...)
switch n := len(ft.Out); n { switch n := len(tout); n {
case 0: case 0:
case 1: case 1:
return []Value{NewAt(toType(ft.Out[0]), ret).Elem()} return []Value{NewAt(toType(tout[0]), ret).Elem()}
default: 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 return
} }
@@ -2415,3 +2508,54 @@ func (v Value) call(op string, in []Value) (out []Value) {
// return ret // 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