compiler,reflect: fix pkgpath for struct fields
Этот коммит содержится в:
родитель
1626b50457
коммит
344e493ac8
4 изменённых файлов: 56 добавлений и 23 удалений
|
@ -84,6 +84,27 @@ func (b *builder) extractValueFromInterface(itf llvm.Value, llvmType llvm.Type)
|
|||
return b.emitPointerUnpack(valuePtr, []llvm.Type{llvmType})[0]
|
||||
}
|
||||
|
||||
func (c *compilerContext) pkgPathPtr(pkgpath string) llvm.Value {
|
||||
pkgpathName := "reflect/types.type.pkgpath.empty"
|
||||
if pkgpath != "" {
|
||||
pkgpathName = "reflect/types.type.pkgpath:" + pkgpath
|
||||
}
|
||||
|
||||
pkgpathInitializer := c.ctx.ConstString(pkgpath+"\x00", false)
|
||||
pkgpathGlobal := llvm.AddGlobal(c.mod, pkgpathInitializer.Type(), pkgpathName)
|
||||
pkgpathGlobal.SetInitializer(pkgpathInitializer)
|
||||
pkgpathGlobal.SetAlignment(1)
|
||||
pkgpathGlobal.SetUnnamedAddr(true)
|
||||
pkgpathGlobal.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
pkgpathGlobal.SetGlobalConstant(true)
|
||||
pkgPathPtr := llvm.ConstGEP(pkgpathGlobal.GlobalValueType(), pkgpathGlobal, []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
|
||||
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
|
||||
})
|
||||
|
||||
return pkgPathPtr
|
||||
}
|
||||
|
||||
// getTypeCode returns a reference to a type code.
|
||||
// A type code is a pointer to a constant global that describes the type.
|
||||
// This function returns a pointer to the 'kind' field (which might not be the
|
||||
|
@ -141,6 +162,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
|||
typeFieldTypes = append(typeFieldTypes,
|
||||
types.NewVar(token.NoPos, nil, "numFields", types.Typ[types.Uint16]),
|
||||
types.NewVar(token.NoPos, nil, "ptrTo", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "pkgpath", types.Typ[types.UnsafePointer]),
|
||||
types.NewVar(token.NoPos, nil, "fields", types.NewArray(c.getRuntimeType("structField"), int64(typ.NumFields()))),
|
||||
)
|
||||
case *types.Interface:
|
||||
|
@ -173,31 +195,15 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
|||
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
|
||||
case *types.Named:
|
||||
name := typ.Obj().Name()
|
||||
|
||||
pkg := typ.Obj().Pkg()
|
||||
var pkgpath string
|
||||
pkgpathName := "reflect/types.type.pkgpath.empty"
|
||||
if pkg != nil {
|
||||
if pkg := typ.Obj().Pkg(); pkg != nil {
|
||||
pkgpath = pkg.Path()
|
||||
pkgpathName = "reflect/types.type.pkgpath:" + pkgpath
|
||||
}
|
||||
|
||||
pkgpathInitializer := c.ctx.ConstString(pkgpath+"\x00", false)
|
||||
pkgpathGlobal := llvm.AddGlobal(c.mod, pkgpathInitializer.Type(), pkgpathName)
|
||||
pkgpathGlobal.SetInitializer(pkgpathInitializer)
|
||||
pkgpathGlobal.SetAlignment(1)
|
||||
pkgpathGlobal.SetUnnamedAddr(true)
|
||||
pkgpathGlobal.SetLinkage(llvm.LinkOnceODRLinkage)
|
||||
pkgpathGlobal.SetGlobalConstant(true)
|
||||
pkgpathPtr := llvm.ConstGEP(pkgpathGlobal.GlobalValueType(), pkgpathGlobal, []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
|
||||
llvm.ConstInt(c.ctx.Int32Type(), 0, false),
|
||||
})
|
||||
|
||||
pkgPathPtr := c.pkgPathPtr(pkgpath)
|
||||
typeFields = []llvm.Value{
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
c.getTypeCode(typ.Underlying()), // underlying
|
||||
pkgpathPtr, // pkgpath pointer
|
||||
pkgPathPtr, // pkgpath pointer
|
||||
c.ctx.ConstString(name+"\x00", false), // name
|
||||
}
|
||||
metabyte |= 1 << 5 // "named" flag
|
||||
|
@ -226,9 +232,18 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
|||
c.getTypeCode(typ.Key()), // key
|
||||
}
|
||||
case *types.Struct:
|
||||
var pkgpath string
|
||||
if typ.NumFields() > 0 {
|
||||
if pkg := typ.Field(0).Pkg(); pkg != nil {
|
||||
pkgpath = pkg.Path()
|
||||
}
|
||||
}
|
||||
pkgPathPtr := c.pkgPathPtr(pkgpath)
|
||||
|
||||
typeFields = []llvm.Value{
|
||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields
|
||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||
pkgPathPtr,
|
||||
}
|
||||
structFieldType := c.getLLVMRuntimeType("structField")
|
||||
var fields []llvm.Value
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
// meta uint8
|
||||
// numField uint16
|
||||
// ptrTo *typeStruct
|
||||
// pkgpath *byte
|
||||
// fields [...]structField // the remaining fields are all of type structField
|
||||
// - interface types (this is missing the interface methods):
|
||||
// meta uint8
|
||||
|
@ -444,6 +445,7 @@ type structType struct {
|
|||
rawType
|
||||
numField uint16
|
||||
ptrTo *rawType
|
||||
pkgpath *byte
|
||||
fields [1]structField // the remaining fields are all of type structField
|
||||
}
|
||||
|
||||
|
@ -576,7 +578,7 @@ func (t *rawType) Field(i int) StructField {
|
|||
}
|
||||
}
|
||||
|
||||
func rawStructFieldFromPointer(fieldType *rawType, data unsafe.Pointer, flagsByte uint8, name string, offset uintptr) rawStructField {
|
||||
func rawStructFieldFromPointer(descriptor *structType, fieldType *rawType, data unsafe.Pointer, flagsByte uint8, name string, offset uintptr) rawStructField {
|
||||
// Read the field tag, if there is one.
|
||||
var tag string
|
||||
if flagsByte&structFieldFlagHasTag != 0 {
|
||||
|
@ -594,7 +596,7 @@ func rawStructFieldFromPointer(fieldType *rawType, data unsafe.Pointer, flagsByt
|
|||
pkgPath := ""
|
||||
if flagsByte&structFieldFlagIsExported == 0 {
|
||||
// This field is unexported.
|
||||
pkgPath = fieldType.PkgPath()
|
||||
pkgPath = readStringZ(unsafe.Pointer(descriptor.pkgpath))
|
||||
}
|
||||
|
||||
return rawStructField{
|
||||
|
@ -646,7 +648,7 @@ func (t *rawType) rawField(n int) rawStructField {
|
|||
name := readStringZ(data)
|
||||
data = unsafe.Add(data, len(name))
|
||||
|
||||
return rawStructFieldFromPointer(field.fieldType, data, flagsByte, name, offset)
|
||||
return rawStructFieldFromPointer(descriptor, field.fieldType, data, flagsByte, name, offset)
|
||||
}
|
||||
|
||||
// rawFieldByName returns nearly the same value as FieldByName but without converting the
|
||||
|
@ -696,7 +698,7 @@ func (t *rawType) rawFieldByName(n string) (rawStructField, []int, bool) {
|
|||
data = unsafe.Add(data, len(name))
|
||||
if name == n {
|
||||
found = append(found, result{
|
||||
rawStructFieldFromPointer(field.fieldType, data, flagsByte, name, offset),
|
||||
rawStructFieldFromPointer(descriptor, field.fieldType, data, flagsByte, name, offset),
|
||||
append(ll.index, int(i)),
|
||||
})
|
||||
}
|
||||
|
|
1
testdata/reflect.go
предоставленный
1
testdata/reflect.go
предоставленный
|
@ -481,6 +481,7 @@ func showValue(rv reflect.Value, indent string) {
|
|||
for i := 0; i < rv.NumField(); i++ {
|
||||
field := rt.Field(i)
|
||||
println(indent+" field:", i, field.Name)
|
||||
println(indent+" pkg:", field.PkgPath)
|
||||
println(indent+" tag:", strconv.Quote(string(field.Tag)))
|
||||
println(indent+" embedded:", field.Anonymous)
|
||||
println(indent+" exported:", field.IsExported())
|
||||
|
|
15
testdata/reflect.txt
предоставленный
15
testdata/reflect.txt
предоставленный
|
@ -233,6 +233,7 @@ reflect type: struct
|
|||
reflect type: struct
|
||||
struct: 1
|
||||
field: 0 error
|
||||
pkg: main
|
||||
tag: ""
|
||||
embedded: true
|
||||
exported: false
|
||||
|
@ -242,18 +243,21 @@ reflect type: struct
|
|||
reflect type: struct
|
||||
struct: 3
|
||||
field: 0 a
|
||||
pkg: main
|
||||
tag: ""
|
||||
embedded: false
|
||||
exported: false
|
||||
reflect type: uint8 caninterface=false
|
||||
uint: 42
|
||||
field: 1 b
|
||||
pkg: main
|
||||
tag: ""
|
||||
embedded: false
|
||||
exported: false
|
||||
reflect type: int16 caninterface=false
|
||||
int: 321
|
||||
field: 2 c
|
||||
pkg: main
|
||||
tag: ""
|
||||
embedded: false
|
||||
exported: false
|
||||
|
@ -262,36 +266,42 @@ reflect type: struct
|
|||
reflect type: struct comparable=false
|
||||
struct: 5
|
||||
field: 0 n
|
||||
pkg: main
|
||||
tag: "foo:\"bar\""
|
||||
embedded: false
|
||||
exported: false
|
||||
reflect type: int caninterface=false
|
||||
int: 5
|
||||
field: 1 some
|
||||
pkg: main
|
||||
tag: "some\x00tag"
|
||||
embedded: false
|
||||
exported: false
|
||||
reflect type: struct caninterface=false
|
||||
struct: 2
|
||||
field: 0 X
|
||||
pkg:
|
||||
tag: ""
|
||||
embedded: false
|
||||
exported: true
|
||||
reflect type: int16 caninterface=false
|
||||
int: -5
|
||||
field: 1 Y
|
||||
pkg:
|
||||
tag: ""
|
||||
embedded: false
|
||||
exported: true
|
||||
reflect type: int16 caninterface=false
|
||||
int: 3
|
||||
field: 2 zero
|
||||
pkg: main
|
||||
tag: ""
|
||||
embedded: false
|
||||
exported: false
|
||||
reflect type: struct caninterface=false
|
||||
struct: 0
|
||||
field: 3 buf
|
||||
pkg: main
|
||||
tag: ""
|
||||
embedded: false
|
||||
exported: false
|
||||
|
@ -306,6 +316,7 @@ reflect type: struct comparable=false
|
|||
reflect type: uint8 addrable=true caninterface=false
|
||||
uint: 111
|
||||
field: 4 Buf
|
||||
pkg:
|
||||
tag: ""
|
||||
embedded: false
|
||||
exported: true
|
||||
|
@ -322,6 +333,7 @@ reflect type: ptr
|
|||
reflect type: struct settable=true addrable=true
|
||||
struct: 2
|
||||
field: 0 next
|
||||
pkg: main
|
||||
tag: "description:\"chain\""
|
||||
embedded: false
|
||||
exported: false
|
||||
|
@ -329,6 +341,7 @@ reflect type: ptr
|
|||
pointer: false struct
|
||||
nil: true
|
||||
field: 1 foo
|
||||
pkg: main
|
||||
tag: ""
|
||||
embedded: false
|
||||
exported: false
|
||||
|
@ -337,12 +350,14 @@ reflect type: ptr
|
|||
reflect type: struct
|
||||
struct: 2
|
||||
field: 0 A
|
||||
pkg:
|
||||
tag: ""
|
||||
embedded: false
|
||||
exported: true
|
||||
reflect type: uintptr
|
||||
uint: 2
|
||||
field: 1 B
|
||||
pkg:
|
||||
tag: ""
|
||||
embedded: false
|
||||
exported: true
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче