From 09c8567e395e9c0de6c36f6923a2ee283178528e Mon Sep 17 00:00:00 2001 From: visualfc Date: Fri, 7 Feb 2025 12:04:54 +0800 Subject: [PATCH] runtime/internal/lib/reflectlite: implement func --- .../internal/lib/internal/reflectlite/type.go | 365 ++++++------------ .../lib/internal/reflectlite/value.go | 134 ++++--- runtime/internal/lib/reflect/type.go | 17 +- 3 files changed, 201 insertions(+), 315 deletions(-) diff --git a/runtime/internal/lib/internal/reflectlite/type.go b/runtime/internal/lib/internal/reflectlite/type.go index e6dbcecd..0c58860e 100644 --- a/runtime/internal/lib/internal/reflectlite/type.go +++ b/runtime/internal/lib/internal/reflectlite/type.go @@ -150,50 +150,41 @@ func (t rtype) exportedMethods() []abi.Method { } func (t rtype) NumMethod() int { - /* - tt := t.Type.InterfaceType() - if tt != nil { - return tt.NumMethod() - } - return len(t.exportedMethods()) - */ - panic("todo: reflectlite.rtype.NumMethod") + tt := t.Type.InterfaceType() + if tt != nil { + return tt.NumMethod() + } + return len(t.exportedMethods()) } 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: reflectlite.rtype.PkgPath") + if t.TFlag&abi.TFlagNamed == 0 { + return "" + } + ut := t.uncommon() + if ut == nil { + return "" + } + return ut.PkgPath_ } func (t rtype) Name() string { - /* - if !t.HasName() { - return "" + 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-- } - 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: reflectlite.rtype.Name") + i-- + } + return s[i+1:] } func toRType(t *abi.Type) rtype { @@ -213,14 +204,11 @@ func (t rtype) Elem() Type { } 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: reflectlite.rtype.In") + tt := t.Type.FuncType() + if tt == nil { + panic("reflect: In of non-func type") + } + return toType(tt.In[i]) } func (t rtype) Key() Type { @@ -248,36 +236,27 @@ func (t rtype) NumField() int { } 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: reflectlite.rtype.NumIn") + tt := t.Type.FuncType() + if tt == nil { + panic("reflect: NumIn of non-func type") + } + return len(tt.In) } func (t rtype) NumOut() int { - /* - tt := t.Type.FuncType() - if tt == nil { - panic("reflect: NumOut of non-func type") - } - return tt.NumOut() - */ - panic("todo: reflectlite.rtype.NumOut") + tt := t.Type.FuncType() + if tt == nil { + panic("reflect: NumOut of non-func type") + } + return len(tt.Out) } 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: reflectlite.rtype.Out") + tt := t.Type.FuncType() + if tt == nil { + panic("reflect: Out of non-func type") + } + return toType(tt.Out[i]) } // add returns p+x. @@ -322,94 +301,9 @@ func (t rtype) Comparable() bool { } // 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: reflectlite.implements") -} +// +//go:linkname implements github.com/goplus/llgo/runtime/internal/runtime.Implements +func implements(T, V *abi.Type) bool // directlyAssignable reports whether a value x of type V can be directly // assigned (using memmove) to a value of type T. @@ -460,91 +354,88 @@ func haveIdenticalUnderlyingType(T, V *abi.Type, cmpTags bool) bool { return true } - /* - // Composite types. - switch kind { - case abi.Array: - return T.Len() == V.Len() && haveIdenticalType(T.Elem(), V.Elem(), cmpTags) + // 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 - } - } + 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 len(t.Out) != len(v.Out) || len(t.In) != len(v.In) { + return false + } + for i := 0; i < len(t.In); i++ { + if !haveIdenticalType(t.In[i], v.In[i], cmpTags) { + return false + } + } + for i := 0; i < len(t.Out); 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 - */ - panic("todo: reflectlite.haveIdenticalUnderlyingType") + + 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_ != v.PkgPath_ { + return false + } + for i := range t.Fields { + tf := &t.Fields[i] + vf := &v.Fields[i] + if tf.Name_ != vf.Name_ { + return false + } + if !haveIdenticalType(tf.Typ, vf.Typ, cmpTags) { + return false + } + if cmpTags && tf.Tag_ != vf.Tag_ { + return false + } + if tf.Offset != vf.Offset { + return false + } + if tf.Embedded() != vf.Embedded() { + return false + } + } + return true + } + + return false } // toType converts from a *rtype to a Type that can be returned diff --git a/runtime/internal/lib/internal/reflectlite/value.go b/runtime/internal/lib/internal/reflectlite/value.go index 743def07..5fa0cf5b 100644 --- a/runtime/internal/lib/internal/reflectlite/value.go +++ b/runtime/internal/lib/internal/reflectlite/value.go @@ -9,6 +9,7 @@ import ( "github.com/goplus/llgo/runtime/abi" _ "github.com/goplus/llgo/runtime/internal/runtime" + "github.com/goplus/llgo/runtime/internal/runtime/goarch" ) // Value is the reflection interface to a Go value. @@ -89,16 +90,13 @@ func (f flag) ro() flag { // pointer returns the underlying pointer represented by v. // v.Kind() must be Pointer, Map, Chan, Func, or UnsafePointer func (v Value) pointer() unsafe.Pointer { - /* - if v.typ.Size() != goarch.PtrSize || !v.typ.Pointers() { - panic("can't call pointer on a non-pointer Value") - } - if v.flag&flagIndir != 0 { - return *(*unsafe.Pointer)(v.ptr) - } - return v.ptr - */ - panic("todo: reflectlite.Value.pointer") + if v.typ.Size() != goarch.PtrSize || !v.typ.Pointers() { + panic("can't call pointer on a non-pointer Value") + } + if v.flag&flagIndir != 0 { + return *(*unsafe.Pointer)(v.ptr) + } + return v.ptr } // packEface converts v to the empty interface. @@ -147,6 +145,9 @@ func unpackEface(i any) Value { return Value{} } f := flag(t.Kind()) + if t.IsClosure() { + f = flag(abi.Func) + } if ifaceIndir(t) { f |= flagIndir } @@ -229,41 +230,38 @@ func (v Value) CanSet() bool { // It panics if v's Kind is not Interface or Pointer. // It returns the zero Value if v is nil. func (v Value) Elem() Value { - /* - k := v.kind() - switch k { - case abi.Interface: - var eface any - if v.typ.NumMethod() == 0 { - eface = *(*any)(v.ptr) - } else { - eface = (any)(*(*interface { - M() - })(v.ptr)) - } - x := unpackEface(eface) - if x.flag != 0 { - x.flag |= v.flag.ro() - } - return x - case abi.Pointer: - ptr := v.ptr - if v.flag&flagIndir != 0 { - ptr = *(*unsafe.Pointer)(ptr) - } - // The returned value's address is v's value. - if ptr == nil { - return Value{} - } - tt := (*ptrType)(unsafe.Pointer(v.typ)) - typ := tt.Elem - fl := v.flag&flagRO | flagIndir | flagAddr - fl |= flag(typ.Kind()) - return Value{typ, ptr, fl} + k := v.kind() + switch k { + case abi.Interface: + var eface any + if v.typ.NumMethod() == 0 { + eface = *(*any)(v.ptr) + } else { + eface = (any)(*(*interface { + M() + })(v.ptr)) } - panic(&ValueError{"reflectlite.Value.Elem", v.kind()}) - */ - panic("todo: reflectlite.Value.Elem") + x := unpackEface(eface) + if x.flag != 0 { + x.flag |= v.flag.ro() + } + return x + case abi.Pointer: + ptr := v.ptr + if v.flag&flagIndir != 0 { + ptr = *(*unsafe.Pointer)(ptr) + } + // The returned value's address is v's value. + if ptr == nil { + return Value{} + } + tt := (*ptrType)(unsafe.Pointer(v.typ)) + typ := tt.Elem + fl := v.flag&flagRO | flagIndir | flagAddr + fl |= flag(typ.Kind()) + return Value{typ, ptr, fl} + } + panic(&ValueError{"reflectlite.Value.Elem", v.kind()}) } func valueInterface(v Value) any { @@ -329,11 +327,11 @@ func (v Value) Kind() Kind { return v.kind() } -/* TODO(xsw): -// implemented in runtime: -func chanlen(unsafe.Pointer) int -func maplen(unsafe.Pointer) int -*/ +//go:linkname chanlen github.com/goplus/llgo/runtime/internal/runtime.ChanLen +func chanlen(ch unsafe.Pointer) int + +//go:linkname maplen github.com/goplus/llgo/runtime/internal/runtime.MapLen +func maplen(ch unsafe.Pointer) int // Len returns v's length. // It panics if v's Kind is not Array, Chan, Map, Slice, or String. @@ -349,25 +347,20 @@ func (v Value) Len() int { case abi.Array: tt := (*arrayType)(unsafe.Pointer(v.typ)) return int(tt.Len) - /* TODO(xsw): - case abi.Chan: - return chanlen(v.pointer()) - case abi.Map: - return maplen(v.pointer()) - */ + case abi.Chan: + return chanlen(v.pointer()) + case abi.Map: + return maplen(v.pointer()) } panic(&ValueError{"reflect.Value.Len", v.kind()}) } // NumMethod returns the number of exported methods in the value's method set. func (v Value) numMethod() int { - /* - if v.typ == nil { - panic(&ValueError{"reflectlite.Value.NumMethod", abi.Invalid}) - } - return v.typ.NumMethod() - */ - panic("todo: reflectlite.Value.numMethod") + if v.typ == nil { + panic(&ValueError{"reflectlite.Value.NumMethod", abi.Invalid}) + } + return v.typ.NumMethod() } // Set assigns x to the value v. @@ -394,10 +387,18 @@ func (v Value) Type() Type { if f == 0 { panic(&ValueError{"reflectlite.Value.Type", abi.Invalid}) } + // closure func + if v.typ.IsClosure() { + return toRType(&v.closureFunc().Type) + } // Method values not supported. return toRType(v.typ) } +func (v Value) closureFunc() *abi.FuncType { + return v.typ.StructType().Fields[0].Typ.FuncType() +} + /* * constructors */ @@ -441,7 +442,6 @@ func (v Value) assignTo(context string, dst *abi.Type, target unsafe.Pointer) Va // Avoid the panic by returning a nil dst (e.g., Reader) explicitly. return Value{dst, nil, flag(abi.Interface)} } - /* TODO(xsw): x := valueInterface(v) if dst.NumMethod() == 0 { *(*any)(target) = x @@ -449,13 +449,10 @@ func (v Value) assignTo(context string, dst *abi.Type, target unsafe.Pointer) Va ifaceE2I(dst, x, target) } return Value{dst, target, flagIndir | flag(abi.Interface)} - */ } // Failed. - // TODO(xsw): - // panic(context + ": value of type " + toRType(v.typ).String() + " is not assignable to type " + toRType(dst).String()) - panic("todo: reflectlite.Value.assignTo") + panic(context + ": value of type " + toRType(v.typ).String() + " is not assignable to type " + toRType(dst).String()) } // arrayAt returns the i-th element of p, @@ -469,7 +466,8 @@ func arrayAt(p unsafe.Pointer, i int, eltSize uintptr, whySafe string) unsafe.Po return add(p, uintptr(i)*eltSize, "i < len") } -// func ifaceE2I(t *abi.Type, src any, dst unsafe.Pointer) +//go:linkname ifaceE2I github.com/goplus/llgo/runtime/internal/runtime.IfaceE2I +func ifaceE2I(t *abi.Type, src any, dst unsafe.Pointer) // typedmemmove copies a value of type t to dst from src. // diff --git a/runtime/internal/lib/reflect/type.go b/runtime/internal/lib/reflect/type.go index 669d4c15..060c28dd 100644 --- a/runtime/internal/lib/reflect/type.go +++ b/runtime/internal/lib/reflect/type.go @@ -903,16 +903,13 @@ func fnv1(x uint32, list ...byte) uint32 { } 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()) - */ - panic("todo: reflect.rtype.Implements") + 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 {