Fixes os.ReadDir segfault caused by package path mismatch between llgo overlay packages and canonical standard library paths. The issue occurred in: os.ReadDir → sort.Slice → reflectlite.Swapper where internal/reflectlite.Type interface has private methods common() and uncommon(). Using mPkg.Path() returned the overlay path 'github.com/goplus/llgo/runtime/internal/lib/internal/reflectlite' instead of the canonical 'internal/reflectlite', causing runtime to only fill public methods and leave private method pointers NULL. Changed to use abi.PathOf() which returns the correct canonical package path for matching, ensuring all interface methods (both public and private) are properly filled in the interface table. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
519 lines
14 KiB
Go
519 lines
14 KiB
Go
/*
|
|
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package ssa
|
|
|
|
import (
|
|
"go/token"
|
|
"go/types"
|
|
"unsafe"
|
|
|
|
"github.com/goplus/llgo/ssa/abi"
|
|
"github.com/goplus/llvm"
|
|
"golang.org/x/tools/go/types/typeutil"
|
|
)
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
// abiBasic returns the abi type of the specified basic kind.
|
|
func (b Builder) abiBasic(t *types.Basic) func() Expr {
|
|
/*
|
|
TODO(xsw):
|
|
return b.abiExtern(abi.BasicName(t))
|
|
*/
|
|
return func() Expr {
|
|
kind := int(abi.BasicKind(t))
|
|
dk, _, _ := abi.DataKindOf(t, 0, b.Prog.is32Bits)
|
|
switch dk {
|
|
case abi.Integer, abi.BitCast, abi.Pointer:
|
|
const kindDirectIface = 1 << 5
|
|
kind |= kindDirectIface
|
|
}
|
|
return b.InlineCall(b.Pkg.rtFunc("Basic"), b.Prog.Val(kind))
|
|
}
|
|
}
|
|
|
|
/*
|
|
func (b Builder) abiExtern(name string) Expr {
|
|
g := b.Pkg.NewVarFrom(name, b.Prog.AbiTypePtrPtr())
|
|
return b.Load(g.Expr)
|
|
}
|
|
*/
|
|
|
|
func (b Builder) abiTypeOf(t types.Type) func() Expr {
|
|
switch t := t.(type) {
|
|
case *types.Basic:
|
|
return b.abiBasic(t)
|
|
case *types.Pointer:
|
|
return b.abiPointerOf(t)
|
|
case *types.Struct:
|
|
return b.abiStructOf(t)
|
|
case *types.Named:
|
|
if _, ok := t.Underlying().(*types.Interface); ok {
|
|
return b.abiNamedInterfaceOf(t)
|
|
}
|
|
return b.abiNamedOf(t)
|
|
case *types.Interface:
|
|
return b.abiInterfaceOf(t)
|
|
case *types.Signature:
|
|
return b.abiFuncOf(t)
|
|
case *types.Slice:
|
|
return b.abiSliceOf(t)
|
|
case *types.Array:
|
|
return b.abiArrayOf(t)
|
|
case *types.Chan:
|
|
return b.abiChanOf(t)
|
|
case *types.Map:
|
|
return b.abiMapOf(t)
|
|
case *types.Alias:
|
|
return b.abiTypeOf(types.Unalias(t))
|
|
}
|
|
panic("todo")
|
|
}
|
|
|
|
func (b Builder) abiTupleOf(t *types.Tuple) func() Expr {
|
|
n := t.Len()
|
|
tuple := make([]func() Expr, n)
|
|
for i := 0; i < n; i++ {
|
|
tuple[i] = b.abiTypeOf(t.At(i).Type())
|
|
}
|
|
return func() Expr {
|
|
prog := b.Prog
|
|
tSlice := prog.Slice(prog.AbiTypePtr())
|
|
elts := make([]Expr, n)
|
|
for i := 0; i < n; i++ {
|
|
elts[i] = tuple[i]()
|
|
}
|
|
return b.SliceLit(tSlice, elts...)
|
|
}
|
|
}
|
|
|
|
// func Func(in, out []*Type, variadic bool)
|
|
func (b Builder) abiFuncOf(sig *types.Signature) func() Expr {
|
|
params := b.abiTupleOf(sig.Params())
|
|
results := b.abiTupleOf(sig.Results())
|
|
return func() Expr {
|
|
prog := b.Prog
|
|
pkg := b.Pkg
|
|
fn := pkg.rtFunc("Func")
|
|
variadic := prog.Val(sig.Variadic())
|
|
return b.Call(fn, params(), results(), variadic)
|
|
}
|
|
}
|
|
|
|
// Imethod{name string, typ *FuncType}
|
|
func (b Builder) abiImethodOf(mName string, typ Expr) Expr {
|
|
prog := b.Prog
|
|
name := b.Str(mName)
|
|
return b.aggregateValue(prog.rtType("Imethod"), name.impl, typ.impl)
|
|
}
|
|
|
|
func (b Builder) abiMethods(t *types.Named) (ret, pret int) {
|
|
methods := typeutil.IntuitiveMethodSet(t, nil)
|
|
pret = len(methods)
|
|
for _, m := range methods {
|
|
if _, ok := m.Recv().(*types.Pointer); ok {
|
|
continue
|
|
}
|
|
ret++
|
|
}
|
|
return
|
|
}
|
|
|
|
// Method{name string, typ *FuncType, ifn, tfn abi.Text}
|
|
func (b Builder) abiMethodOf(mPkg *types.Package, mName string, mSig *types.Signature /*, bg Background = InGo */) (mthd, ptrMthd Expr) {
|
|
prog := b.Prog
|
|
name := b.Str(mName).impl
|
|
if !token.IsExported(mName) {
|
|
name = b.Str(abi.FullName(mPkg, mName)).impl
|
|
}
|
|
abiSigGo := types.NewSignatureType(nil, nil, nil, mSig.Params(), mSig.Results(), mSig.Variadic())
|
|
abiSig := prog.FuncDecl(abiSigGo, InGo).raw.Type
|
|
abiTyp := b.abiType(abiSig)
|
|
abiTypImpl := abiTyp.impl
|
|
|
|
recv := mSig.Recv()
|
|
recvType := recv.Type()
|
|
if _, ok := recvType.(*types.Pointer); ok {
|
|
ptrMthd, _ = b.abiMthd(mPkg, mName, mSig, name, abiTypImpl, llvm.Value{})
|
|
return
|
|
}
|
|
ptrRecv := types.NewVar(0, nil, "", types.NewPointer(recvType))
|
|
ptrSig := types.NewSignatureType(ptrRecv, nil, nil, mSig.Params(), mSig.Results(), mSig.Variadic())
|
|
ptrMthd, ifn := b.abiMthd(mPkg, mName, ptrSig, name, abiTypImpl, llvm.Value{})
|
|
mthd, _ = b.abiMthd(mPkg, mName, mSig, name, abiTypImpl, ifn)
|
|
return
|
|
}
|
|
|
|
func (b Builder) abiMthd(mPkg *types.Package, mName string, mSig *types.Signature, name, abiTyp, ifn llvm.Value) (ret Expr, tfn llvm.Value) {
|
|
fullName := FuncName(mPkg, mName, mSig.Recv(), false)
|
|
if mSig.TypeParams().Len() > 0 || mSig.RecvTypeParams().Len() > 0 {
|
|
if !b.Pkg.Prog.FuncCompiled(fullName) {
|
|
return
|
|
}
|
|
}
|
|
if b.Pkg.fnlink != nil {
|
|
fullName = b.Pkg.fnlink(fullName)
|
|
}
|
|
tfn = b.Pkg.NewFunc(fullName, mSig, InGo).impl // TODO(xsw): use rawType to speed up
|
|
if ifn.IsNil() {
|
|
ifn = tfn
|
|
}
|
|
ret = b.aggregateValue(b.Prog.rtType("Method"), name, abiTyp, ifn, tfn)
|
|
return
|
|
}
|
|
|
|
// func Interface(pkgPath, name string, methods []abi.Imethod)
|
|
func (b Builder) abiInterfaceOf(t *types.Interface) func() Expr {
|
|
n := t.NumMethods()
|
|
typs := make([]Expr, n)
|
|
for i := 0; i < n; i++ {
|
|
m := t.Method(i)
|
|
typs[i] = b.abiType(m.Type())
|
|
}
|
|
return func() Expr {
|
|
prog := b.Prog
|
|
methods := make([]Expr, n)
|
|
pkgPath := ""
|
|
for i := 0; i < n; i++ {
|
|
m := t.Method(i)
|
|
mName := m.Name()
|
|
if !token.IsExported(mName) {
|
|
if pkgPath == "" {
|
|
if mPkg := m.Pkg(); mPkg != nil {
|
|
pkgPath = abi.PathOf(mPkg)
|
|
}
|
|
}
|
|
mName = abi.FullName(m.Pkg(), mName)
|
|
}
|
|
methods[i] = b.abiImethodOf(mName, typs[i])
|
|
}
|
|
pkg := b.Pkg
|
|
if pkgPath == "" {
|
|
pkgPath = pkg.Path()
|
|
}
|
|
fn := pkg.rtFunc("Interface")
|
|
tSlice := lastParamType(prog, fn)
|
|
methodSlice := b.SliceLit(tSlice, methods...)
|
|
return b.Call(fn, b.Str(pkgPath), methodSlice)
|
|
}
|
|
}
|
|
|
|
func (b Builder) abiInitNamedInterface(ret Expr, t *types.Interface) func() Expr {
|
|
n := t.NumMethods()
|
|
typs := make([]Expr, n)
|
|
for i := 0; i < n; i++ {
|
|
m := t.Method(i)
|
|
typs[i] = b.abiType(m.Type())
|
|
}
|
|
return func() Expr {
|
|
prog := b.Prog
|
|
methods := make([]Expr, n)
|
|
for i := 0; i < n; i++ {
|
|
m := t.Method(i)
|
|
mName := m.Name()
|
|
if !token.IsExported(mName) {
|
|
mName = abi.FullName(m.Pkg(), mName)
|
|
}
|
|
methods[i] = b.abiImethodOf(mName, typs[i])
|
|
}
|
|
fn := b.Pkg.rtFunc("InitNamedInterface")
|
|
tSlice := lastParamType(prog, fn)
|
|
methodSlice := b.SliceLit(tSlice, methods...)
|
|
return b.Call(fn, ret, methodSlice)
|
|
}
|
|
}
|
|
|
|
// func NewNamed(kind abi.Kind, methods, ptrMethods int)
|
|
func (b Builder) abiNamedOf(t *types.Named) func() Expr {
|
|
expr := b.abiNamed(t)
|
|
return func() Expr {
|
|
return expr
|
|
}
|
|
}
|
|
|
|
func (b Builder) abiNamed(t *types.Named) Expr {
|
|
pkg := b.Pkg
|
|
tunder := t.Underlying()
|
|
kind := int(abi.UnderlyingKind(tunder))
|
|
size := b.sizeof(tunder)
|
|
numMethods, numPtrMethods := b.abiMethods(t)
|
|
newNamed := pkg.rtFunc("NewNamed")
|
|
obj := t.Obj()
|
|
expr := b.Call(newNamed, b.Str(abi.PathOf(obj.Pkg())), b.Str(abi.NamedName(t)), b.Prog.Val(kind), b.Prog.IntVal(uint64(size), b.Prog.Uintptr()), b.Prog.Val(numMethods), b.Prog.Val(numPtrMethods))
|
|
return expr
|
|
}
|
|
|
|
func (b Builder) abiNamedInterfaceOf(t *types.Named) func() Expr {
|
|
obj := t.Obj()
|
|
fn := b.Pkg.rtFunc("NewNamedInterface")
|
|
expr := b.Call(fn, b.Str(abi.PathOf(obj.Pkg())), b.Str(obj.Name()))
|
|
return func() Expr {
|
|
return expr
|
|
}
|
|
}
|
|
|
|
func (b Builder) sizeof(t types.Type) int64 {
|
|
sizes := (*goProgram)(unsafe.Pointer(b.Prog))
|
|
return sizes.Sizeof(t)
|
|
}
|
|
|
|
// func InitNamed(ret *Type, pkgPath, name string, underlying *Type, methods, ptrMethods []Method)
|
|
func (b Builder) abiInitNamed(ret Expr, t *types.Named) func() Expr {
|
|
under := b.abiType(t.Underlying())
|
|
return func() Expr {
|
|
pkg := b.Pkg
|
|
prog := b.Prog
|
|
var initNamed = pkg.rtFunc("InitNamed")
|
|
var tSlice = lastParamType(prog, initNamed)
|
|
mset := typeutil.IntuitiveMethodSet(t, nil)
|
|
n := len(mset)
|
|
var methods, ptrMethods Expr
|
|
if n == 0 {
|
|
methods = prog.Zero(tSlice)
|
|
ptrMethods = methods
|
|
} else {
|
|
var mthds []Expr
|
|
var ptrMthds = make([]Expr, 0, n)
|
|
for i := 0; i < n; i++ {
|
|
var mPkg *types.Package
|
|
var mSig *types.Signature
|
|
m := mset[i]
|
|
obj := m.Obj()
|
|
mName := obj.Name()
|
|
if token.IsExported(mName) {
|
|
mPkg = t.Obj().Pkg()
|
|
mSig = m.Type().(*types.Signature)
|
|
} else {
|
|
mPkg = obj.Pkg()
|
|
mSig = obj.Type().(*types.Signature)
|
|
}
|
|
mthd, ptrMthd := b.abiMethodOf(mPkg, mName, mSig)
|
|
if !mthd.IsNil() {
|
|
mthds = append(mthds, mthd)
|
|
}
|
|
if !ptrMthd.IsNil() {
|
|
ptrMthds = append(ptrMthds, ptrMthd)
|
|
}
|
|
}
|
|
if len(mthds) > 0 {
|
|
methods = b.SliceLit(tSlice, mthds...)
|
|
} else {
|
|
methods = prog.Zero(tSlice)
|
|
}
|
|
if len(ptrMthds) > 0 {
|
|
ptrMethods = b.SliceLit(tSlice, ptrMthds...)
|
|
} else {
|
|
ptrMethods = prog.Zero(tSlice)
|
|
}
|
|
}
|
|
return b.Call(initNamed, ret, under, methods, ptrMethods)
|
|
}
|
|
}
|
|
|
|
func (b Builder) abiPointerOf(t *types.Pointer) func() Expr {
|
|
elem := b.abiTypeOf(t.Elem())
|
|
return func() Expr {
|
|
return b.Call(b.Pkg.rtFunc("PointerTo"), elem())
|
|
}
|
|
}
|
|
|
|
func (b Builder) abiSliceOf(t *types.Slice) func() Expr {
|
|
elem := b.abiTypeOf(t.Elem())
|
|
return func() Expr {
|
|
return b.Call(b.Pkg.rtFunc("SliceOf"), elem())
|
|
}
|
|
}
|
|
|
|
func (b Builder) abiArrayOf(t *types.Array) func() Expr {
|
|
elem := b.abiTypeOf(t.Elem())
|
|
return func() Expr {
|
|
n := b.Prog.IntVal(uint64(t.Len()), b.Prog.Uintptr())
|
|
return b.Call(b.Pkg.rtFunc("ArrayOf"), n, elem())
|
|
}
|
|
}
|
|
|
|
func (b Builder) abiChanOf(t *types.Chan) func() Expr {
|
|
elem := b.abiTypeOf(t.Elem())
|
|
return func() Expr {
|
|
dir, s := abi.ChanDir(t.Dir())
|
|
return b.Call(b.Pkg.rtFunc("ChanOf"), b.Prog.IntVal(uint64(dir), b.Prog.Int()), b.Str(s), elem())
|
|
}
|
|
}
|
|
|
|
func (b Builder) abiMapOf(t *types.Map) func() Expr {
|
|
key := b.abiTypeOf(t.Key())
|
|
elem := b.abiTypeOf(t.Elem())
|
|
sizes := (*goProgram)(unsafe.Pointer(b.Prog))
|
|
bucket := b.abiTypeOf(abi.MapBucketType(t, sizes))
|
|
flags := abi.MapTypeFlags(t, sizes)
|
|
return func() Expr {
|
|
return b.Call(b.Pkg.rtFunc("MapOf"), key(), elem(), bucket(), b.Prog.Val(flags))
|
|
}
|
|
}
|
|
|
|
// func StructField(name string, typ *abi.Type, off uintptr, tag string, embedded bool)
|
|
// func Struct(pkgPath string, size uintptr, fields []abi.StructField)
|
|
func (b Builder) abiStructOf(t *types.Struct) func() Expr {
|
|
n := t.NumFields()
|
|
typs := make([]func() Expr, n)
|
|
for i := 0; i < n; i++ {
|
|
f := t.Field(i)
|
|
typs[i] = b.abiTypeOf(f.Type())
|
|
}
|
|
return func() Expr {
|
|
pkg := b.Pkg
|
|
prog := b.Prog
|
|
flds := make([]Expr, n)
|
|
strucAbi := pkg.rtFunc("Struct")
|
|
sfAbi := pkg.rtFunc("StructField")
|
|
tStruc := prog.rawType(t)
|
|
for i := 0; i < n; i++ {
|
|
f := t.Field(i)
|
|
off := uintptr(prog.OffsetOf(tStruc, i))
|
|
name := b.Str(f.Name())
|
|
tag := b.Str(t.Tag(i))
|
|
embedded := prog.Val(f.Embedded())
|
|
flds[i] = b.Call(sfAbi, name, typs[i](), prog.Val(off), tag, embedded)
|
|
}
|
|
pkgPath := b.Str(pkg.Path())
|
|
tSlice := lastParamType(prog, strucAbi)
|
|
fldSlice := b.SliceLit(tSlice, flds...)
|
|
size := prog.IntVal(prog.SizeOf(tStruc), prog.Uintptr())
|
|
return b.Call(strucAbi, pkgPath, size, fldSlice)
|
|
}
|
|
}
|
|
|
|
func lastParamType(prog Program, fn Expr) Type {
|
|
params := fn.raw.Type.(*types.Signature).Params()
|
|
return prog.rawType(params.At(params.Len() - 1).Type())
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
|
|
func (p Package) patchType(t types.Type) types.Type {
|
|
switch t := t.(type) {
|
|
case *types.Pointer:
|
|
return types.NewPointer(p.patchType(t.Elem()))
|
|
}
|
|
return p.patch(t)
|
|
}
|
|
|
|
func (p Package) abiTypeInit(g Global, t types.Type, pub bool) {
|
|
b := p.afterBuilder()
|
|
if p.patch != nil {
|
|
t = p.patchType(t)
|
|
}
|
|
tabi := b.abiTypeOf(t)
|
|
expr := g.Expr
|
|
var eq Expr
|
|
var blks []BasicBlock
|
|
if pub {
|
|
eq = b.BinOp(token.EQL, b.Load(expr), b.Prog.Nil(expr.Type))
|
|
blks = b.Func.MakeBlocks(2)
|
|
b.If(eq, blks[0], blks[1])
|
|
b.SetBlockEx(blks[0], AtEnd, false)
|
|
}
|
|
vexpr := tabi()
|
|
prog := p.Prog
|
|
if kind, _, _ := abi.DataKindOf(t, 0, prog.is32Bits); kind == abi.Pointer {
|
|
b.InlineCall(b.Pkg.rtFunc("SetDirectIface"), vexpr)
|
|
}
|
|
b.Store(expr, vexpr)
|
|
if pub {
|
|
b.Jump(blks[1])
|
|
b.SetBlockEx(blks[1], AtEnd, false)
|
|
b.blk.last = blks[1].last
|
|
}
|
|
|
|
if t, ok := t.(*types.Named); ok {
|
|
if iface, ok := t.Underlying().(*types.Interface); ok {
|
|
tabi = b.abiInitNamedInterface(vexpr, iface)
|
|
} else {
|
|
tabi = b.abiInitNamed(vexpr, t)
|
|
}
|
|
if pub {
|
|
blks = b.Func.MakeBlocks(2)
|
|
b.If(eq, blks[0], blks[1])
|
|
b.SetBlockEx(blks[0], AtEnd, false)
|
|
}
|
|
tabi()
|
|
if pub {
|
|
b.Jump(blks[1])
|
|
b.SetBlockEx(blks[1], AtEnd, false)
|
|
b.blk.last = blks[1].last
|
|
}
|
|
}
|
|
}
|
|
|
|
// abiType returns the abi type of the specified type.
|
|
func (b Builder) abiType(t types.Type) Expr {
|
|
switch t := t.(type) {
|
|
case *types.Pointer:
|
|
b.checkAbi(t.Elem())
|
|
case *types.Array:
|
|
b.checkAbi(t.Elem())
|
|
case *types.Map:
|
|
b.checkAbi(t.Key())
|
|
b.checkAbi(t.Elem())
|
|
case *types.Slice:
|
|
b.checkAbi(t.Elem())
|
|
case *types.Chan:
|
|
b.checkAbi(t.Elem())
|
|
case *types.Struct:
|
|
for i := 0; i < t.NumFields(); i++ {
|
|
b.checkAbi(t.Field(i).Type())
|
|
}
|
|
case *types.Interface:
|
|
for i := 0; i < t.NumMethods(); i++ {
|
|
b.checkAbi(t.Method(i).Type())
|
|
}
|
|
case *types.Signature:
|
|
for i := 0; i < t.Params().Len(); i++ {
|
|
b.checkAbi(t.Params().At(i).Type())
|
|
}
|
|
for i := 0; i < t.Results().Len(); i++ {
|
|
b.checkAbi(t.Results().At(i).Type())
|
|
}
|
|
}
|
|
g := b.loadType(t)
|
|
return b.Load(g.Expr)
|
|
}
|
|
|
|
func (b Builder) checkAbi(t types.Type) {
|
|
if b.Pkg.chkabi[t] {
|
|
return
|
|
}
|
|
b.abiType(t)
|
|
}
|
|
|
|
func (b Builder) loadType(t types.Type) Global {
|
|
b.Pkg.chkabi[t] = true
|
|
pkg := b.Pkg
|
|
name, pub := pkg.abi.TypeName(t)
|
|
g := pkg.VarOf(name)
|
|
if g == nil {
|
|
prog := b.Prog
|
|
g = pkg.doNewVar(name, prog.AbiTypePtrPtr())
|
|
g.InitNil()
|
|
g.impl.SetLinkage(llvm.LinkOnceAnyLinkage)
|
|
pkg.abiTypeInit(g, t, pub)
|
|
}
|
|
return g
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|