add struct size and field offsets to reflect data

Этот коммит содержится в:
Damian Gryski 2023-04-15 11:14:37 -07:00 коммит произвёл Ron Evans
родитель 36bd66a858
коммит 4c0fbbfc7f
3 изменённых файлов: 17 добавлений и 26 удалений

Просмотреть файл

@ -205,6 +205,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
types.NewVar(token.NoPos, nil, "numMethods", types.Typ[types.Uint16]), types.NewVar(token.NoPos, nil, "numMethods", 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, "pkgpath", types.Typ[types.UnsafePointer]),
types.NewVar(token.NoPos, nil, "size", types.Typ[types.Uint32]),
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, "fields", types.NewArray(c.getRuntimeType("structField"), int64(typ.NumFields()))), types.NewVar(token.NoPos, nil, "fields", types.NewArray(c.getRuntimeType("structField"), int64(typ.NumFields()))),
) )
@ -306,16 +307,21 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
} }
pkgPathPtr := c.pkgPathPtr(pkgpath) pkgPathPtr := c.pkgPathPtr(pkgpath)
llvmStructType := c.getLLVMType(typ)
size := c.targetData.TypeStoreSize(llvmStructType)
typeFields = []llvm.Value{ typeFields = []llvm.Value{
llvm.ConstInt(c.ctx.Int16Type(), uint64(ms.Len()), false), // numMethods llvm.ConstInt(c.ctx.Int16Type(), uint64(ms.Len()), false), // numMethods
c.getTypeCode(types.NewPointer(typ)), // ptrTo c.getTypeCode(types.NewPointer(typ)), // ptrTo
pkgPathPtr, pkgPathPtr,
llvm.ConstInt(c.ctx.Int32Type(), uint64(size), false), // size
llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields
} }
structFieldType := c.getLLVMRuntimeType("structField") structFieldType := c.getLLVMRuntimeType("structField")
var fields []llvm.Value var fields []llvm.Value
for i := 0; i < typ.NumFields(); i++ { for i := 0; i < typ.NumFields(); i++ {
field := typ.Field(i) field := typ.Field(i)
offset := c.targetData.ElementOffset(llvmStructType, i)
var flags uint8 var flags uint8
if field.Anonymous() { if field.Anonymous() {
flags |= structFieldFlagAnonymous flags |= structFieldFlagAnonymous
@ -346,6 +352,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value {
fieldType := c.getTypeCode(field.Type()) fieldType := c.getTypeCode(field.Type())
fields = append(fields, llvm.ConstNamedStruct(structFieldType, []llvm.Value{ fields = append(fields, llvm.ConstNamedStruct(structFieldType, []llvm.Value{
fieldType, fieldType,
llvm.ConstInt(c.ctx.Int32Type(), uint64(offset), false),
llvm.ConstGEP(dataGlobal.GlobalValueType(), dataGlobal, []llvm.Value{ llvm.ConstGEP(dataGlobal.GlobalValueType(), dataGlobal, []llvm.Value{
llvm.ConstInt(c.ctx.Int32Type(), 0, false), llvm.ConstInt(c.ctx.Int32Type(), 0, false),
llvm.ConstInt(c.ctx.Int32Type(), 0, false), llvm.ConstInt(c.ctx.Int32Type(), 0, false),

Просмотреть файл

@ -39,6 +39,7 @@
// meta uint8 // meta uint8
// nmethods uint16 // nmethods uint16
// ptrTo *typeStruct // ptrTo *typeStruct
// size uint32
// pkgpath *byte // package path; null terminated // pkgpath *byte // package path; null terminated
// numField uint16 // numField uint16
// fields [...]structField // the remaining fields are all of type structField // fields [...]structField // the remaining fields are all of type structField
@ -455,12 +456,14 @@ type structType struct {
numMethod uint16 numMethod uint16
ptrTo *rawType ptrTo *rawType
pkgpath *byte pkgpath *byte
size uint32
numField uint16 numField uint16
fields [1]structField // the remaining fields are all of type structField fields [1]structField // the remaining fields are all of type structField
} }
type structField struct { type structField struct {
fieldType *rawType fieldType *rawType
offset uint32
data unsafe.Pointer // various bits of information, packed in a byte array data unsafe.Pointer // various bits of information, packed in a byte array
} }
@ -669,18 +672,8 @@ func (t *rawType) rawField(n int) rawStructField {
// This offset could have been stored directly in the array (to make the // This offset could have been stored directly in the array (to make the
// lookup faster), but by calculating it on-the-fly a bit of storage can be // lookup faster), but by calculating it on-the-fly a bit of storage can be
// saved. // saved.
field := &descriptor.fields[0] field := (*structField)(unsafe.Add(unsafe.Pointer(&descriptor.fields[0]), uintptr(n)*unsafe.Sizeof(structField{})))
var offset uintptr = 0 offset := uintptr(field.offset)
for i := 0; i < n; i++ {
offset += field.fieldType.Size()
// Increment pointer to the next field.
field = (*structField)(unsafe.Add(unsafe.Pointer(field), unsafe.Sizeof(structField{})))
// Align the offset for the next field.
offset = align(offset, uintptr(field.fieldType.Align()))
}
data := field.data data := field.data
// Read some flags of this field, like whether the field is an embedded // Read some flags of this field, like whether the field is an embedded
@ -726,7 +719,6 @@ func (t *rawType) rawFieldByName(n string) (rawStructField, []int, bool) {
// Also calculate field offset. // Also calculate field offset.
descriptor := (*structType)(unsafe.Pointer(ll.t.underlying())) descriptor := (*structType)(unsafe.Pointer(ll.t.underlying()))
var offset uintptr
field := &descriptor.fields[0] field := &descriptor.fields[0]
for i := uint16(0); i < descriptor.numField; i++ { for i := uint16(0); i < descriptor.numField; i++ {
@ -740,6 +732,7 @@ func (t *rawType) rawFieldByName(n string) (rawStructField, []int, bool) {
name := readStringZ(data) name := readStringZ(data)
data = unsafe.Add(data, len(name)) data = unsafe.Add(data, len(name))
if name == n { if name == n {
offset := uintptr(field.offset)
found = append(found, result{ found = append(found, result{
rawStructFieldFromPointer(descriptor, field.fieldType, data, flagsByte, name, offset), rawStructFieldFromPointer(descriptor, field.fieldType, data, flagsByte, name, offset),
append(ll.index, int(i)), append(ll.index, int(i)),
@ -759,16 +752,10 @@ func (t *rawType) rawFieldByName(n string) (rawStructField, []int, bool) {
}) })
} }
offset += field.fieldType.Size()
// update offset/field pointer if there *is* a next field // update offset/field pointer if there *is* a next field
if i < descriptor.numField-1 { if i < descriptor.numField-1 {
// Increment pointer to the next field. // Increment pointer to the next field.
field = (*structField)(unsafe.Add(unsafe.Pointer(field), unsafe.Sizeof(structField{}))) field = (*structField)(unsafe.Add(unsafe.Pointer(field), unsafe.Sizeof(structField{})))
// Align the offset for the next field.
offset = align(offset, uintptr(field.fieldType.Align()))
} }
} }
} }
@ -860,12 +847,8 @@ func (t *rawType) Size() uintptr {
case Array: case Array:
return t.elem().Size() * uintptr(t.Len()) return t.elem().Size() * uintptr(t.Len())
case Struct: case Struct:
numField := t.NumField() u := t.underlying()
if numField == 0 { return uintptr((*structType)(unsafe.Pointer(u)).size)
return 0
}
lastField := t.rawField(numField - 1)
return align(lastField.Offset+lastField.Type.Size(), uintptr(t.Align()))
default: default:
panic("unimplemented: size of type") panic("unimplemented: size of type")
} }

Просмотреть файл

@ -96,6 +96,7 @@ func interfaceTypeAssert(ok bool) {
type structField struct { type structField struct {
typecode unsafe.Pointer // type of this struct field typecode unsafe.Pointer // type of this struct field
offset uint32
data *uint8 // pointer to byte array containing name, tag, and 'embedded' flag data *uint8 // pointer to byte array containing name, tag, and 'embedded' flag
} }