diff options
author | Damian Gryski <[email protected]> | 2023-03-08 12:28:51 -0800 |
---|---|---|
committer | Ayke <[email protected]> | 2023-03-15 21:53:57 +0100 |
commit | 344e493ac8fa3a3f3bcfcd0ec91e237f01d01dc1 (patch) | |
tree | acf992732b20db4e11c3da53c9b8ba507cd4dc16 | |
parent | 1626b50457c5941e6747b0da1f77aa311b91bda6 (diff) | |
download | tinygo-344e493ac8fa3a3f3bcfcd0ec91e237f01d01dc1.tar.gz tinygo-344e493ac8fa3a3f3bcfcd0ec91e237f01d01dc1.zip |
compiler,reflect: fix pkgpath for struct fields
-rw-r--r-- | compiler/interface.go | 53 | ||||
-rw-r--r-- | src/reflect/type.go | 10 | ||||
-rw-r--r-- | testdata/reflect.go | 1 | ||||
-rw-r--r-- | testdata/reflect.txt | 15 |
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 |