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]
|
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.
|
// getTypeCode returns a reference to a type code.
|
||||||
// A type code is a pointer to a constant global that describes the type.
|
// 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
|
// 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,
|
typeFieldTypes = append(typeFieldTypes,
|
||||||
types.NewVar(token.NoPos, nil, "numFields", types.Typ[types.Uint16]),
|
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, "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()))),
|
types.NewVar(token.NoPos, nil, "fields", types.NewArray(c.getRuntimeType("structField"), int64(typ.NumFields()))),
|
||||||
)
|
)
|
||||||
case *types.Interface:
|
case *types.Interface:
|
||||||
|
@ -173,31 +195,15 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||||
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
|
typeFields = []llvm.Value{c.getTypeCode(types.NewPointer(typ))}
|
||||||
case *types.Named:
|
case *types.Named:
|
||||||
name := typ.Obj().Name()
|
name := typ.Obj().Name()
|
||||||
|
|
||||||
pkg := typ.Obj().Pkg()
|
|
||||||
var pkgpath string
|
var pkgpath string
|
||||||
pkgpathName := "reflect/types.type.pkgpath.empty"
|
if pkg := typ.Obj().Pkg(); pkg != nil {
|
||||||
if pkg != nil {
|
|
||||||
pkgpath = pkg.Path()
|
pkgpath = pkg.Path()
|
||||||
pkgpathName = "reflect/types.type.pkgpath:" + pkgpath
|
|
||||||
}
|
}
|
||||||
|
pkgPathPtr := c.pkgPathPtr(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),
|
|
||||||
})
|
|
||||||
|
|
||||||
typeFields = []llvm.Value{
|
typeFields = []llvm.Value{
|
||||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||||
c.getTypeCode(typ.Underlying()), // underlying
|
c.getTypeCode(typ.Underlying()), // underlying
|
||||||
pkgpathPtr, // pkgpath pointer
|
pkgPathPtr, // pkgpath pointer
|
||||||
c.ctx.ConstString(name+"\x00", false), // name
|
c.ctx.ConstString(name+"\x00", false), // name
|
||||||
}
|
}
|
||||||
metabyte |= 1 << 5 // "named" flag
|
metabyte |= 1 << 5 // "named" flag
|
||||||
|
@ -226,9 +232,18 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
|
||||||
c.getTypeCode(typ.Key()), // key
|
c.getTypeCode(typ.Key()), // key
|
||||||
}
|
}
|
||||||
case *types.Struct:
|
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{
|
typeFields = []llvm.Value{
|
||||||
llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields
|
llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields
|
||||||
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
c.getTypeCode(types.NewPointer(typ)), // ptrTo
|
||||||
|
pkgPathPtr,
|
||||||
}
|
}
|
||||||
structFieldType := c.getLLVMRuntimeType("structField")
|
structFieldType := c.getLLVMRuntimeType("structField")
|
||||||
var fields []llvm.Value
|
var fields []llvm.Value
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
// meta uint8
|
// meta uint8
|
||||||
// numField uint16
|
// numField uint16
|
||||||
// ptrTo *typeStruct
|
// ptrTo *typeStruct
|
||||||
|
// pkgpath *byte
|
||||||
// fields [...]structField // the remaining fields are all of type structField
|
// fields [...]structField // the remaining fields are all of type structField
|
||||||
// - interface types (this is missing the interface methods):
|
// - interface types (this is missing the interface methods):
|
||||||
// meta uint8
|
// meta uint8
|
||||||
|
@ -444,6 +445,7 @@ type structType struct {
|
||||||
rawType
|
rawType
|
||||||
numField uint16
|
numField uint16
|
||||||
ptrTo *rawType
|
ptrTo *rawType
|
||||||
|
pkgpath *byte
|
||||||
fields [1]structField // the remaining fields are all of type structField
|
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.
|
// Read the field tag, if there is one.
|
||||||
var tag string
|
var tag string
|
||||||
if flagsByte&structFieldFlagHasTag != 0 {
|
if flagsByte&structFieldFlagHasTag != 0 {
|
||||||
|
@ -594,7 +596,7 @@ func rawStructFieldFromPointer(fieldType *rawType, data unsafe.Pointer, flagsByt
|
||||||
pkgPath := ""
|
pkgPath := ""
|
||||||
if flagsByte&structFieldFlagIsExported == 0 {
|
if flagsByte&structFieldFlagIsExported == 0 {
|
||||||
// This field is unexported.
|
// This field is unexported.
|
||||||
pkgPath = fieldType.PkgPath()
|
pkgPath = readStringZ(unsafe.Pointer(descriptor.pkgpath))
|
||||||
}
|
}
|
||||||
|
|
||||||
return rawStructField{
|
return rawStructField{
|
||||||
|
@ -646,7 +648,7 @@ func (t *rawType) rawField(n int) rawStructField {
|
||||||
name := readStringZ(data)
|
name := readStringZ(data)
|
||||||
data = unsafe.Add(data, len(name))
|
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
|
// 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))
|
data = unsafe.Add(data, len(name))
|
||||||
if name == n {
|
if name == n {
|
||||||
found = append(found, result{
|
found = append(found, result{
|
||||||
rawStructFieldFromPointer(field.fieldType, data, flagsByte, name, offset),
|
rawStructFieldFromPointer(descriptor, field.fieldType, data, flagsByte, name, offset),
|
||||||
append(ll.index, int(i)),
|
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++ {
|
for i := 0; i < rv.NumField(); i++ {
|
||||||
field := rt.Field(i)
|
field := rt.Field(i)
|
||||||
println(indent+" field:", i, field.Name)
|
println(indent+" field:", i, field.Name)
|
||||||
|
println(indent+" pkg:", field.PkgPath)
|
||||||
println(indent+" tag:", strconv.Quote(string(field.Tag)))
|
println(indent+" tag:", strconv.Quote(string(field.Tag)))
|
||||||
println(indent+" embedded:", field.Anonymous)
|
println(indent+" embedded:", field.Anonymous)
|
||||||
println(indent+" exported:", field.IsExported())
|
println(indent+" exported:", field.IsExported())
|
||||||
|
|
15
testdata/reflect.txt
предоставленный
15
testdata/reflect.txt
предоставленный
|
@ -233,6 +233,7 @@ reflect type: struct
|
||||||
reflect type: struct
|
reflect type: struct
|
||||||
struct: 1
|
struct: 1
|
||||||
field: 0 error
|
field: 0 error
|
||||||
|
pkg: main
|
||||||
tag: ""
|
tag: ""
|
||||||
embedded: true
|
embedded: true
|
||||||
exported: false
|
exported: false
|
||||||
|
@ -242,18 +243,21 @@ reflect type: struct
|
||||||
reflect type: struct
|
reflect type: struct
|
||||||
struct: 3
|
struct: 3
|
||||||
field: 0 a
|
field: 0 a
|
||||||
|
pkg: main
|
||||||
tag: ""
|
tag: ""
|
||||||
embedded: false
|
embedded: false
|
||||||
exported: false
|
exported: false
|
||||||
reflect type: uint8 caninterface=false
|
reflect type: uint8 caninterface=false
|
||||||
uint: 42
|
uint: 42
|
||||||
field: 1 b
|
field: 1 b
|
||||||
|
pkg: main
|
||||||
tag: ""
|
tag: ""
|
||||||
embedded: false
|
embedded: false
|
||||||
exported: false
|
exported: false
|
||||||
reflect type: int16 caninterface=false
|
reflect type: int16 caninterface=false
|
||||||
int: 321
|
int: 321
|
||||||
field: 2 c
|
field: 2 c
|
||||||
|
pkg: main
|
||||||
tag: ""
|
tag: ""
|
||||||
embedded: false
|
embedded: false
|
||||||
exported: false
|
exported: false
|
||||||
|
@ -262,36 +266,42 @@ reflect type: struct
|
||||||
reflect type: struct comparable=false
|
reflect type: struct comparable=false
|
||||||
struct: 5
|
struct: 5
|
||||||
field: 0 n
|
field: 0 n
|
||||||
|
pkg: main
|
||||||
tag: "foo:\"bar\""
|
tag: "foo:\"bar\""
|
||||||
embedded: false
|
embedded: false
|
||||||
exported: false
|
exported: false
|
||||||
reflect type: int caninterface=false
|
reflect type: int caninterface=false
|
||||||
int: 5
|
int: 5
|
||||||
field: 1 some
|
field: 1 some
|
||||||
|
pkg: main
|
||||||
tag: "some\x00tag"
|
tag: "some\x00tag"
|
||||||
embedded: false
|
embedded: false
|
||||||
exported: false
|
exported: false
|
||||||
reflect type: struct caninterface=false
|
reflect type: struct caninterface=false
|
||||||
struct: 2
|
struct: 2
|
||||||
field: 0 X
|
field: 0 X
|
||||||
|
pkg:
|
||||||
tag: ""
|
tag: ""
|
||||||
embedded: false
|
embedded: false
|
||||||
exported: true
|
exported: true
|
||||||
reflect type: int16 caninterface=false
|
reflect type: int16 caninterface=false
|
||||||
int: -5
|
int: -5
|
||||||
field: 1 Y
|
field: 1 Y
|
||||||
|
pkg:
|
||||||
tag: ""
|
tag: ""
|
||||||
embedded: false
|
embedded: false
|
||||||
exported: true
|
exported: true
|
||||||
reflect type: int16 caninterface=false
|
reflect type: int16 caninterface=false
|
||||||
int: 3
|
int: 3
|
||||||
field: 2 zero
|
field: 2 zero
|
||||||
|
pkg: main
|
||||||
tag: ""
|
tag: ""
|
||||||
embedded: false
|
embedded: false
|
||||||
exported: false
|
exported: false
|
||||||
reflect type: struct caninterface=false
|
reflect type: struct caninterface=false
|
||||||
struct: 0
|
struct: 0
|
||||||
field: 3 buf
|
field: 3 buf
|
||||||
|
pkg: main
|
||||||
tag: ""
|
tag: ""
|
||||||
embedded: false
|
embedded: false
|
||||||
exported: false
|
exported: false
|
||||||
|
@ -306,6 +316,7 @@ reflect type: struct comparable=false
|
||||||
reflect type: uint8 addrable=true caninterface=false
|
reflect type: uint8 addrable=true caninterface=false
|
||||||
uint: 111
|
uint: 111
|
||||||
field: 4 Buf
|
field: 4 Buf
|
||||||
|
pkg:
|
||||||
tag: ""
|
tag: ""
|
||||||
embedded: false
|
embedded: false
|
||||||
exported: true
|
exported: true
|
||||||
|
@ -322,6 +333,7 @@ reflect type: ptr
|
||||||
reflect type: struct settable=true addrable=true
|
reflect type: struct settable=true addrable=true
|
||||||
struct: 2
|
struct: 2
|
||||||
field: 0 next
|
field: 0 next
|
||||||
|
pkg: main
|
||||||
tag: "description:\"chain\""
|
tag: "description:\"chain\""
|
||||||
embedded: false
|
embedded: false
|
||||||
exported: false
|
exported: false
|
||||||
|
@ -329,6 +341,7 @@ reflect type: ptr
|
||||||
pointer: false struct
|
pointer: false struct
|
||||||
nil: true
|
nil: true
|
||||||
field: 1 foo
|
field: 1 foo
|
||||||
|
pkg: main
|
||||||
tag: ""
|
tag: ""
|
||||||
embedded: false
|
embedded: false
|
||||||
exported: false
|
exported: false
|
||||||
|
@ -337,12 +350,14 @@ reflect type: ptr
|
||||||
reflect type: struct
|
reflect type: struct
|
||||||
struct: 2
|
struct: 2
|
||||||
field: 0 A
|
field: 0 A
|
||||||
|
pkg:
|
||||||
tag: ""
|
tag: ""
|
||||||
embedded: false
|
embedded: false
|
||||||
exported: true
|
exported: true
|
||||||
reflect type: uintptr
|
reflect type: uintptr
|
||||||
uint: 2
|
uint: 2
|
||||||
field: 1 B
|
field: 1 B
|
||||||
|
pkg:
|
||||||
tag: ""
|
tag: ""
|
||||||
embedded: false
|
embedded: false
|
||||||
exported: true
|
exported: true
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче