aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDamian Gryski <[email protected]>2023-03-08 12:28:51 -0800
committerAyke <[email protected]>2023-03-15 21:53:57 +0100
commit344e493ac8fa3a3f3bcfcd0ec91e237f01d01dc1 (patch)
treeacf992732b20db4e11c3da53c9b8ba507cd4dc16
parent1626b50457c5941e6747b0da1f77aa311b91bda6 (diff)
downloadtinygo-344e493ac8fa3a3f3bcfcd0ec91e237f01d01dc1.tar.gz
tinygo-344e493ac8fa3a3f3bcfcd0ec91e237f01d01dc1.zip
compiler,reflect: fix pkgpath for struct fields
-rw-r--r--compiler/interface.go53
-rw-r--r--src/reflect/type.go10
-rw-r--r--testdata/reflect.go1
-rw-r--r--testdata/reflect.txt15
4 files changed, 56 insertions, 23 deletions
diff --git a/compiler/interface.go b/compiler/interface.go
index b57c59744..d6ed420db 100644
--- a/compiler/interface.go
+++ b/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
diff --git a/src/reflect/type.go b/src/reflect/type.go
index ef9bc1c2b..134711a72 100644
--- a/src/reflect/type.go
+++ b/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)),
})
}
diff --git a/testdata/reflect.go b/testdata/reflect.go
index f7c6616c4..1a92e47ab 100644
--- a/testdata/reflect.go
+++ b/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())
diff --git a/testdata/reflect.txt b/testdata/reflect.txt
index b8f93715c..e4a92a5e1 100644
--- a/testdata/reflect.txt
+++ b/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