diff --git a/internal/abi/llgo_autogen.lla b/internal/abi/llgo_autogen.lla index 0d23b976..6e0de50e 100644 Binary files a/internal/abi/llgo_autogen.lla and b/internal/abi/llgo_autogen.lla differ diff --git a/internal/abi/type.go b/internal/abi/type.go index b43621a9..a6a01d85 100644 --- a/internal/abi/type.go +++ b/internal/abi/type.go @@ -240,6 +240,11 @@ type Method struct { Tfn_ Text // fn used for normal method call } +// Exported reports whether the method is exported. +func (p *Method) Exported() bool { + return p.Name_.IsExported() +} + // UncommonType is present only for defined types or types with methods // (if T is a defined type, the uncommonTypes for T and *T have methods). // Using a pointer to this struct reduces the overall size required @@ -285,6 +290,70 @@ func (t *Type) Common() *Type { return t } +type structTypeUncommon struct { + StructType + u UncommonType +} + +// Uncommon returns a pointer to T's "uncommon" data if there is any, otherwise nil +func (t *Type) Uncommon() *UncommonType { + if t.TFlag&TFlagUncommon == 0 { + return nil + } + switch t.Kind() { + case Struct: + return &(*structTypeUncommon)(unsafe.Pointer(t)).u + case Pointer: + type u struct { + PtrType + u UncommonType + } + return &(*u)(unsafe.Pointer(t)).u + case Func: + type u struct { + FuncType + u UncommonType + } + return &(*u)(unsafe.Pointer(t)).u + case Slice: + type u struct { + SliceType + u UncommonType + } + return &(*u)(unsafe.Pointer(t)).u + case Array: + type u struct { + ArrayType + u UncommonType + } + return &(*u)(unsafe.Pointer(t)).u + case Chan: + type u struct { + ChanType + u UncommonType + } + return &(*u)(unsafe.Pointer(t)).u + case Map: + type u struct { + MapType + u UncommonType + } + return &(*u)(unsafe.Pointer(t)).u + case Interface: + type u struct { + InterfaceType + u UncommonType + } + return &(*u)(unsafe.Pointer(t)).u + default: + type u struct { + Type + u UncommonType + } + return &(*u)(unsafe.Pointer(t)).u + } +} + // Len returns the length of t if t is an array type, otherwise 0 func (t *Type) Len() int { if t.Kind() == Array { diff --git a/internal/runtime/c/c.go b/internal/runtime/c/c.go index eb502d92..3d200e36 100644 --- a/internal/runtime/c/c.go +++ b/internal/runtime/c/c.go @@ -42,8 +42,8 @@ var Stderr FilePtr //go:linkname Str llgo.cstr func Str(string) *Char -//go:linkname Advance llgo.advance -func Advance(ptr Pointer, offset int) Pointer +// llgo:link Advance llgo.advance +func Advance[PtrT any](ptr PtrT, offset int) PtrT { return ptr } //go:linkname Alloca llgo.alloca func Alloca(size uintptr) Pointer diff --git a/internal/runtime/llgo_autogen.lla b/internal/runtime/llgo_autogen.lla deleted file mode 100644 index e2f90b84..00000000 Binary files a/internal/runtime/llgo_autogen.lla and /dev/null differ diff --git a/internal/runtime/runtime2.go b/internal/runtime/runtime2.go deleted file mode 100644 index 69d80ae1..00000000 --- a/internal/runtime/runtime2.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2009 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package runtime - -import ( - "unsafe" -) - -type eface struct { - _type *_type - data unsafe.Pointer -} - -type iface struct { - tab *itab - data unsafe.Pointer -} - -// layout of Itab known to compilers -// allocated in non-garbage-collected memory -// Needs to be in sync with -// ../cmd/compile/internal/reflectdata/reflect.go:/^func.WriteTabs. -type itab struct { - inter *interfacetype - _type *_type - hash uint32 // copy of _type.hash. Used for type switches. - _ [4]byte - fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter. -} - -/* -func efaceOf(ep *any) *eface { - return (*eface)(unsafe.Pointer(ep)) -} - -func MakeInterface(inter *InterfaceType, typ *Type, data unsafe.Pointer) Interface { - tab := &itab{inter: inter, _type: typ, hash: 0, fun: [1]uintptr{0}} - return Interface{ - tab: tab, data: data, - } -} -*/ diff --git a/internal/runtime/z_face.go b/internal/runtime/z_face.go new file mode 100644 index 00000000..28409f1e --- /dev/null +++ b/internal/runtime/z_face.go @@ -0,0 +1,209 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package runtime + +import ( + "unsafe" + + "github.com/goplus/llgo/internal/abi" + "github.com/goplus/llgo/internal/runtime/c" +) + +type eface struct { + _type *_type + data unsafe.Pointer +} + +type iface struct { + tab *itab + data unsafe.Pointer +} + +// layout of Itab known to compilers +// allocated in non-garbage-collected memory +// Needs to be in sync with +// ../cmd/compile/internal/reflectdata/reflect.go:/^func.WriteTabs. +type itab struct { + inter *interfacetype + _type *_type + hash uint32 // copy of _type.hash. Used for type switches. + _ [4]byte + fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter. +} + +// ----------------------------------------------------------------------------- + +type ( + Eface = eface + Iface = iface + Itab = itab +) + +type FuncType = abi.FuncType +type InterfaceType = abi.InterfaceType + +// ToEface converts an iface to an eface. +func ToEface(i Iface) Eface { + return Eface{i.tab._type, i.data} +} + +// ----------------------------------------------------------------------------- + +const ( + typeHdrSize = unsafe.Sizeof(abi.Type{}) + funcTypeHdrSize = unsafe.Sizeof(abi.FuncType{}) + uncommonTypeHdrSize = unsafe.Sizeof(abi.UncommonType{}) + methodSize = unsafe.Sizeof(abi.Method{}) + pointerSize = unsafe.Sizeof(uintptr(0)) + itabHdrSize = unsafe.Sizeof(itab{}) - pointerSize +) + +// Func returns a function type. +func Func(in, out []*Type, variadic bool) *FuncType { + n := len(in) + len(out) + ptr := AllocU(funcTypeHdrSize + uintptr(n)*pointerSize) + c.Memset(ptr, 0, funcTypeHdrSize) + + ret := (*abi.FuncType)(ptr) + ret.Size_ = pointerSize + ret.Hash = uint32(abi.Func) // TODO(xsw): hash + ret.Kind_ = uint8(abi.Func) + ret.InCount = uint16(len(in)) + ret.OutCount = uint16(len(out)) + if variadic { + ret.OutCount |= 1 << 15 + } + + data := (**Type)(c.Advance(ptr, int(funcTypeHdrSize))) + params := unsafe.Slice(data, n) + copy(params, in) + copy(params[len(in):], out) + return ret +} + +// Imethod returns an interface method. +func Imethod(name Name, typ *FuncType) abi.Imethod { + return abi.Imethod{ + Name_: name, + Typ_: typ, + } +} + +// Method returns a method. +func Method(name Name, typ *FuncType, ifn, tfn abi.Text) abi.Method { + return abi.Method{ + Name_: name, + Mtyp_: typ, + Ifn_: ifn, + Tfn_: tfn, + } +} + +// Named returns a named type. +func Named(pkgPath, name Name, underlying *Type, methods []abi.Method) *Type { + tflag := underlying.TFlag + size := typeHdrSize + n := len(methods) + if n > 0 || pkgPath.Bytes != nil { + size += uncommonTypeHdrSize + uintptr(n)*methodSize + tflag |= abi.TFlagUncommon + } + ptr := AllocU(size) + + ret := (*Type)(ptr) + *ret = *underlying + ret.TFlag = tflag | abi.TFlagNamed + ret.Str_ = name + + xcount := 0 + for _, m := range methods { + if !m.Exported() { + break + } + xcount++ + } + + uncommon := (*abi.UncommonType)(c.Advance(ptr, int(typeHdrSize))) + *uncommon = abi.UncommonType{ + PkgPath_: pkgPath, + Mcount: uint16(n), + Xcount: uint16(xcount), + Moff: uint32(uncommonTypeHdrSize), + } + + data := (*abi.Method)(c.Advance(ptr, int(typeHdrSize+uncommonTypeHdrSize))) + copy(unsafe.Slice(data, n), methods) + return ret +} + +// Interface returns an interface type. +func Interface(pkgPath string, methods []abi.Imethod) *Type { + var npkg abi.Name + if len(pkgPath) > 0 { + npkg = abi.NewName(pkgPath, "", false, false) + } + ret := &abi.InterfaceType{ + Type: Type{ + Size_: unsafe.Sizeof(eface{}), + Hash: uint32(abi.Interface), // TODO(xsw): hash + Kind_: uint8(abi.Interface), + }, + PkgPath: npkg, + Methods: methods, + } + return &ret.Type +} + +// NewItab returns a new itab. +func NewItab(inter *InterfaceType, typ *Type) *Itab { + n := len(inter.Methods) + size := itabHdrSize + uintptr(n)*pointerSize + ptr := AllocU(size) + + ret := (*Itab)(ptr) + ret.inter = inter + ret._type = typ + ret.hash = typ.Hash + + u := typ.Uncommon() + if u == nil { + ret.fun[0] = 0 + } else { + data := (*uintptr)(c.Advance(ptr, int(itabHdrSize))) + mthds := methods(u, inter.PkgPath) + for i, m := range inter.Methods { + fn := findMethod(mthds, m) + if fn == nil { + ret.fun[0] = 0 + break + } + *c.Advance(data, i) = uintptr(fn) + } + } + return ret +} + +func findMethod(mthds []abi.Method, im abi.Imethod) abi.Text { + imName := im.Name_.Name() + for _, m := range mthds { + mName := m.Name_.Name() + if mName >= imName { + if mName == imName && m.Mtyp_ == im.Typ_ { + return m.Ifn_ + } + break + } + } + return nil +} + +func methods(u *abi.UncommonType, from abi.Name) []abi.Method { + if u.PkgPath_.Name() == from.Name() { + return u.Methods() + } + return u.ExportedMethods() +} + +// ----------------------------------------------------------------------------- diff --git a/internal/runtime/z_type.go b/internal/runtime/z_type.go index 403c37b0..dfe2a4d4 100644 --- a/internal/runtime/z_type.go +++ b/internal/runtime/z_type.go @@ -20,103 +20,25 @@ import ( "unsafe" "github.com/goplus/llgo/internal/abi" - "github.com/goplus/llgo/internal/runtime/c" -) - -type ( - Eface = eface - Iface = iface - Itab = itab ) type Kind = abi.Kind +type Name = abi.Name type Type = abi.Type -type FuncType = abi.FuncType -type InterfaceType = abi.InterfaceType - // ----------------------------------------------------------------------------- -// Func returns a function type. -func Func(in, out []*Type, variadic bool) *FuncType { - const ( - funcTypeHdrSize = unsafe.Sizeof(abi.FuncType{}) - pointerSize = unsafe.Sizeof(uintptr(0)) - ) - - n := len(in) + len(out) - ptr := AllocU(funcTypeHdrSize + uintptr(n)*pointerSize) - c.Memset(ptr, 0, funcTypeHdrSize) - - ret := (*abi.FuncType)(ptr) - ret.Size_ = pointerSize - ret.Hash = uint32(abi.Func) // TODO(xsw): hash - ret.Kind_ = uint8(abi.Func) - ret.InCount = uint16(len(in)) - ret.OutCount = uint16(len(out)) - if variadic { - ret.OutCount |= 1 << 15 - } - - data := (**Type)(c.Advance(ptr, int(funcTypeHdrSize))) - params := unsafe.Slice(data, n) - copy(params, in) - copy(params[len(in):], out) - return ret +// NewName creates a new name. +func NewName(name string, exported bool) Name { + return abi.NewName(name, "", exported, false) } -// Imethod returns an interface method. -func Imethod(name string, typ *FuncType, exported bool) abi.Imethod { - n := abi.NewName(name, "", exported, false) - return abi.Imethod{ - Name_: n, - Typ_: typ, - } -} - -// Method returns a method. -func Method(name string, typ *FuncType, fn abi.Text, exported bool) abi.Method { - n := abi.NewName(name, "", exported, false) - return abi.Method{ - Name_: n, - Mtyp_: typ, - Ifn_: fn, - Tfn_: fn, - } -} - -// ----------------------------------------------------------------------------- - -// Named returns a named type. -func Named(name string, typ *Type) *Type { - ret := *typ // TODO(xsw): named type - return &ret -} - -// Interface returns an interface type. -func Interface(pkgPath string) *Type { - // TODO(xsw): pkgPath - // npkg := abi.NewName(pkgPath, "", false, false) - ret := &abi.InterfaceType{ - Type: Type{ - Size_: unsafe.Sizeof(eface{}), - Hash: uint32(abi.Interface), // TODO(xsw): hash - Kind_: uint8(abi.Interface), - }, - //PkgPath: npkg, - Methods: nil, - } - return &ret.Type -} - -// NewItab returns a new itab. -func NewItab(inter *InterfaceType, typ *Type) *Itab { - return &itab{ - inter: inter, - _type: typ, - hash: typ.Hash, - //fun: nil, TODO(xsw) +// NewPkgName creates a package name. +func NewPkgName(pkgPath string) (ret Name) { + if len(pkgPath) > 0 { + ret = abi.NewName(pkgPath, "", false, false) } + return } // ----------------------------------------------------------------------------- @@ -190,21 +112,21 @@ func StructField(name string, typ *Type, off uintptr, tag string, exported, embe } // Struct returns a struct type. -func Struct(size uintptr, pkgPath string, fields ...abi.StructField) *Type { - // TODO(xsw): pkgPath - // npkg := abi.NewName(pkgPath, "", false, false) +func Struct(pkgPath Name, size uintptr, fields ...abi.StructField) *Type { ret := &abi.StructType{ Type: Type{ Size_: size, Hash: uint32(abi.Struct), // TODO(xsw): hash Kind_: uint8(abi.Struct), }, - // PkgPath: npkg, - Fields: fields, + PkgPath: pkgPath, + Fields: fields, } return &ret.Type } +// ----------------------------------------------------------------------------- + // Pointer returns a pointer type. func Pointer(elem *Type) *Type { ret := &abi.PtrType{ diff --git a/ssa/interface.go b/ssa/interface.go index 51d8ab37..6d33fc44 100644 --- a/ssa/interface.go +++ b/ssa/interface.go @@ -88,7 +88,7 @@ func (b Builder) abiStructOf(t *types.Struct) Expr { params := strucAbi.raw.Type.(*types.Signature).Params() tSlice := prog.rawType(params.At(params.Len() - 1).Type().(*types.Slice)) fldSlice := b.SliceLit(tSlice, flds...) - return b.Call(strucAbi, pkgPath, fldSlice) + return b.Call(pkgPath, strucAbi, fldSlice) } // func StructField(name string, typ *abi.Type, off uintptr, tag string, exported, embedded bool) abi.StructField