Browse Source

compiler,reflect: fix pkgpath for struct fields

pull/3565/head
Damian Gryski 2 years ago
committed by Ayke
parent
commit
344e493ac8
  1. 53
      compiler/interface.go
  2. 10
      src/reflect/type.go
  3. 1
      testdata/reflect.go
  4. 15
      testdata/reflect.txt

53
compiler/interface.go

@ -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

10
src/reflect/type.go

@ -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

@ -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

@ -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

Loading…
Cancel
Save