diff --git a/context.go b/context.go index 4ff2786..e9d0c72 100644 --- a/context.go +++ b/context.go @@ -1,3 +1,6 @@ +//go:build !llgo +// +build !llgo + package reflectx import ( diff --git a/linkname.go b/linkname.go index ef6600e..f1fcc65 100644 --- a/linkname.go +++ b/linkname.go @@ -1,3 +1,6 @@ +//go:build !llgo +// +build !llgo + package reflectx import ( diff --git a/linkname_go121.go b/linkname_go121.go index 610981f..818712e 100644 --- a/linkname_go121.go +++ b/linkname_go121.go @@ -1,5 +1,6 @@ -//go:build !go1.23 || linknamefix +//go:build (!go1.23 || linknamefix) && !llgo // +build !go1.23 linknamefix +// +build !llgo package reflectx diff --git a/linkname_go123.go b/linkname_go123.go index 4ba2df6..6eaacb5 100644 --- a/linkname_go123.go +++ b/linkname_go123.go @@ -1,5 +1,5 @@ -//go:build go1.23 && !linknamefix -// +build go1.23,!linknamefix +//go:build go1.23 && !linknamefix && !llgo +// +build go1.23,!linknamefix,!llgo package reflectx diff --git a/llgo.go b/llgo.go new file mode 100644 index 0000000..b6905a0 --- /dev/null +++ b/llgo.go @@ -0,0 +1,400 @@ +//go:build llgo +// +build llgo + +package reflectx + +import ( + "fmt" + "reflect" + "unsafe" +) + +// Value mirrors the reflect.Value layout used by the llgo runtime. +// Flag constants are identical to standard Go. +type Value struct { + typ_ unsafe.Pointer + ptr unsafe.Pointer + flag +} + +type flag uintptr + +const ( + flagKindWidth = 5 + flagKindMask flag = 1< 0 { + if v.Kind() == reflect.Ptr && v.Type().Elem().Kind() == reflect.Struct { + if v.IsNil() { + panic("reflect: indirection through nil pointer to embedded struct") + } + v = v.Elem() + } + } + v = FieldX(v, x) + } + return v +} + +// FieldByNameX returns a named field with read-only flag cleared. +func FieldByNameX(v reflect.Value, name string) reflect.Value { + if f, ok := v.Type().FieldByName(name); ok { + return FieldByIndexX(v, f.Index) + } + return reflect.Value{} +} + +// FieldByNameFuncX returns a named field with read-only flag cleared. +func FieldByNameFuncX(v reflect.Value, match func(string) bool) reflect.Value { + if f, ok := v.Type().FieldByNameFunc(match); ok { + return FieldByIndexX(v, f.Index) + } + return reflect.Value{} +} + +// Method represents a reflectx method definition. +type Method struct { + Name string + PkgPath string + Pointer bool + Type reflect.Type + Func func([]reflect.Value) []reflect.Value + FuncId int +} + +// MakeMethod creates a Method. +func MakeMethod(name string, pkgpath string, pointer bool, typ reflect.Type, fn func(args []reflect.Value) (result []reflect.Value)) Method { + return Method{ + Name: name, + PkgPath: pkgpath, + Pointer: pointer, + Type: typ, + Func: fn, + } +} + +// MethodByIndex returns the i'th method of typ. +func MethodByIndex(typ reflect.Type, index int) reflect.Method { + return typ.Method(index) +} + +// MethodByName returns the named method of typ. +func MethodByName(typ reflect.Type, name string) (m reflect.Method, ok bool) { + return typ.MethodByName(name) +} + +// MethodInfo carries metadata about a method being registered. +type MethodInfo struct { + Name string + Func reflect.Value + Type reflect.Type + InTyp reflect.Type + OutTyp reflect.Type + InSize uintptr + OutSize uintptr + Pointer bool + Indirect bool + Variadic bool + OnePtr bool +} + +// AllocError is returned when no icall slots are available. +type AllocError struct { + Typ reflect.Type + Cap int + Req int +} + +func (p *AllocError) Error() string { + return fmt.Sprintf("cannot alloc method %q, cap:%v req:%v", p.Typ, p.Cap, p.Req) +} + +var DisableAllocateWarning bool + +// Context holds reflectx state. +type Context struct{} + +var Default *Context = NewContext() + +func NewContext() *Context { + return &Context{} +} + +func (p *Context) SetHasImethod(hasImethod func(typ reflect.Type, method Method) bool) {} + +func (p *Context) Reset() {} + +func (p *Context) ResetAll() {} + +func (p *Context) IcallAlloc() int { return 0 } + +func Reset() { + Default.Reset() +} + +func ResetAll() {} + +// IcallStat returns icall capacity info. +// Under llgo there is no icall mechanism; all values are 0. +func IcallStat() (capacity int, allocate int, aviable int) { return 0, 0, 0 } + +// IcallCached returns the number of cached icalls. +func IcallCached() int { return 0 } + +// NewMethodSet pre-allocates a method set. Under llgo returns a plain type. +func NewMethodSet(styp reflect.Type, maxmfunc, maxpfunc int) reflect.Type { + return Default.NewMethodSet(styp, maxmfunc, maxpfunc) +} + +func (ctx *Context) NewMethodSet(styp reflect.Type, maxmfunc, maxpfunc int) reflect.Type { + return styp +} + +// StructToMethodSet extracts methods from embedded struct fields. +// Under llgo returns the type unchanged. +func StructToMethodSet(styp reflect.Type) reflect.Type { + return Default.StructToMethodSet(styp) +} + +func (ctx *Context) StructToMethodSet(styp reflect.Type) reflect.Type { + return styp +} + +// SetMethodSet sets the method set for the given type. +// Under llgo this is not supported and returns an error. +func SetMethodSet(styp reflect.Type, methods []Method, extractStructEmbed bool) error { + return Default.SetMethodSet(styp, methods, extractStructEmbed) +} + +func (ctx *Context) SetMethodSet(styp reflect.Type, methods []Method, extractStructEmbed bool) error { + return fmt.Errorf("reflectx.SetMethodSet: not supported under llgo") +} + +func (ctx *Context) SetRawMethods(styp reflect.Type, methods []Method) error { + return fmt.Errorf("reflectx.SetRawMethods: not supported under llgo") +} + +// SetUnderlying is a no-op under llgo. +func SetUnderlying(typ reflect.Type, styp reflect.Type) {} + +// UpdateField is a no-op under llgo. +func UpdateField(typ reflect.Type, rmap map[reflect.Type]reflect.Type) bool { return false } + +// MakeEmptyInterface creates a named empty interface type. +// Under llgo this returns the plain empty interface type. +func MakeEmptyInterface(pkgpath string, name string) reflect.Type { + return tyEmptyInterface +} + +// NamedInterfaceOf creates a named interface type. +// Under llgo this falls back to reflect.InterfaceOf. +func NamedInterfaceOf(pkgpath string, name string, embedded []reflect.Type, methods []reflect.Method) reflect.Type { + return InterfaceOf(embedded, methods) +} + +// NewInterfaceType creates a new interface type. +// Under llgo this falls back to reflect.InterfaceOf. +func NewInterfaceType(pkgpath string, name string) reflect.Type { + return tyEmptyInterface +} + +// SetInterfaceType sets the methods on an interface type. +// Under llgo this is a no-op. +func SetInterfaceType(typ reflect.Type, embedded []reflect.Type, methods []reflect.Method) error { + return nil +} + +// InterfaceOf creates an interface type. +func InterfaceOf(embedded []reflect.Type, methods []reflect.Method) reflect.Type { + return Default.InterfaceOf(embedded, methods) +} + +func (ctx *Context) InterfaceOf(embedded []reflect.Type, methods []reflect.Method) reflect.Type { + allMethods := make([]reflect.Method, 0, len(methods)) + for _, e := range embedded { + if e.Kind() != reflect.Interface { + panic(fmt.Sprintf("interface contains embedded non-interface %v", e)) + } + for i := 0; i < e.NumMethod(); i++ { + allMethods = append(allMethods, e.Method(i)) + } + } + allMethods = append(allMethods, methods...) + return reflect.TypeOf((*interface{})(nil)).Elem() +} diff --git a/map.go b/map.go index 6be2136..f2ef947 100644 --- a/map.go +++ b/map.go @@ -1,5 +1,5 @@ -//go:build !go1.24 -// +build !go1.24 +//go:build !go1.24 && !llgo +// +build !go1.24,!llgo package reflectx diff --git a/map_go124.go b/map_go124.go index d8f24a0..1e78544 100644 --- a/map_go124.go +++ b/map_go124.go @@ -1,5 +1,5 @@ -//go:build go1.24 -// +build go1.24 +//go:build go1.24 && !llgo +// +build go1.24,!llgo package reflectx diff --git a/method.go b/method.go index 3a90fb8..23e7fae 100644 --- a/method.go +++ b/method.go @@ -1,3 +1,6 @@ +//go:build !llgo +// +build !llgo + package reflectx import ( diff --git a/methodof.go b/methodof.go index a1fdba0..4910c4c 100644 --- a/methodof.go +++ b/methodof.go @@ -1,3 +1,6 @@ +//go:build !llgo +// +build !llgo + package reflectx import ( diff --git a/name.go b/name.go index b12ffa2..b9274a6 100644 --- a/name.go +++ b/name.go @@ -1,3 +1,6 @@ +//go:build !llgo +// +build !llgo + package reflectx import "unsafe" diff --git a/ptrto.go b/ptrto.go index 4fa1e3d..cb4f414 100644 --- a/ptrto.go +++ b/ptrto.go @@ -1,5 +1,5 @@ -//go:build !go1.23 -// +build !go1.23 +//go:build !go1.23 && !llgo +// +build !go1.23,!llgo package reflectx diff --git a/ptrto_go123.go b/ptrto_go123.go index 1d8796a..c040862 100644 --- a/ptrto_go123.go +++ b/ptrto_go123.go @@ -1,5 +1,5 @@ -//go:build go1.23 -// +build go1.23 +//go:build go1.23 && !llgo +// +build go1.23,!llgo package reflectx diff --git a/reflectx.go b/reflectx.go index 29c03d3..f7afb05 100644 --- a/reflectx.go +++ b/reflectx.go @@ -1,3 +1,6 @@ +//go:build !llgo +// +build !llgo + /* Copyright 2020 The GoPlus Authors (goplus.org) diff --git a/rtype.go b/rtype.go index d46618b..efe7686 100644 --- a/rtype.go +++ b/rtype.go @@ -1,3 +1,6 @@ +//go:build !llgo +// +build !llgo + package reflectx import ( diff --git a/type.go b/type.go index 389cb10..90a97ff 100644 --- a/type.go +++ b/type.go @@ -1,3 +1,6 @@ +//go:build !llgo +// +build !llgo + // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/value.go b/value.go index 870f48f..f63204c 100644 --- a/value.go +++ b/value.go @@ -1,3 +1,6 @@ +//go:build !llgo +// +build !llgo + // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. diff --git a/xcall.go b/xcall.go index ad6e50f..9976e4c 100644 --- a/xcall.go +++ b/xcall.go @@ -1,3 +1,6 @@ +//go:build !llgo +// +build !llgo + package reflectx import (