diff options
author | Damian Gryski <[email protected]> | 2023-04-15 11:14:37 -0700 |
---|---|---|
committer | Ron Evans <[email protected]> | 2023-04-27 11:15:41 +0200 |
commit | 4c0fbbfc7ff3043e8ec105e4ab7988eb111f92e9 (patch) | |
tree | cf114e9eae8257d282387dca891a647d2b62777d | |
parent | 36bd66a858e1c5ef33cd9da57eecacbbdb0d9ef6 (diff) | |
download | tinygo-4c0fbbfc7ff3043e8ec105e4ab7988eb111f92e9.tar.gz tinygo-4c0fbbfc7ff3043e8ec105e4ab7988eb111f92e9.zip |
add struct size and field offsets to reflect data
-rw-r--r-- | compiler/interface.go | 7 | ||||
-rw-r--r-- | src/reflect/type.go | 33 | ||||
-rw-r--r-- | src/runtime/interface.go | 3 |
3 files changed, 17 insertions, 26 deletions
diff --git a/compiler/interface.go b/compiler/interface.go index 9e3e0a674..c6818c341 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -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, "ptrTo", 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, "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) + llvmStructType := c.getLLVMType(typ) + size := c.targetData.TypeStoreSize(llvmStructType) typeFields = []llvm.Value{ llvm.ConstInt(c.ctx.Int16Type(), uint64(ms.Len()), false), // numMethods c.getTypeCode(types.NewPointer(typ)), // ptrTo pkgPathPtr, + llvm.ConstInt(c.ctx.Int32Type(), uint64(size), false), // size llvm.ConstInt(c.ctx.Int16Type(), uint64(typ.NumFields()), false), // numFields } structFieldType := c.getLLVMRuntimeType("structField") + var fields []llvm.Value for i := 0; i < typ.NumFields(); i++ { field := typ.Field(i) + offset := c.targetData.ElementOffset(llvmStructType, i) var flags uint8 if field.Anonymous() { flags |= structFieldFlagAnonymous @@ -346,6 +352,7 @@ func (c *compilerContext) getTypeCode(typ types.Type) llvm.Value { fieldType := c.getTypeCode(field.Type()) fields = append(fields, llvm.ConstNamedStruct(structFieldType, []llvm.Value{ fieldType, + llvm.ConstInt(c.ctx.Int32Type(), uint64(offset), false), llvm.ConstGEP(dataGlobal.GlobalValueType(), dataGlobal, []llvm.Value{ llvm.ConstInt(c.ctx.Int32Type(), 0, false), llvm.ConstInt(c.ctx.Int32Type(), 0, false), diff --git a/src/reflect/type.go b/src/reflect/type.go index 814cf39a4..6d8aec399 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -39,6 +39,7 @@ // meta uint8 // nmethods uint16 // ptrTo *typeStruct +// size uint32 // pkgpath *byte // package path; null terminated // numField uint16 // fields [...]structField // the remaining fields are all of type structField @@ -455,12 +456,14 @@ type structType struct { numMethod uint16 ptrTo *rawType pkgpath *byte + size uint32 numField uint16 fields [1]structField // the remaining fields are all of type structField } type structField struct { fieldType *rawType + offset uint32 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 // lookup faster), but by calculating it on-the-fly a bit of storage can be // saved. - field := &descriptor.fields[0] - var offset uintptr = 0 - 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())) - } - + field := (*structField)(unsafe.Add(unsafe.Pointer(&descriptor.fields[0]), uintptr(n)*unsafe.Sizeof(structField{}))) + offset := uintptr(field.offset) data := field.data // 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. descriptor := (*structType)(unsafe.Pointer(ll.t.underlying())) - var offset uintptr field := &descriptor.fields[0] for i := uint16(0); i < descriptor.numField; i++ { @@ -740,6 +732,7 @@ func (t *rawType) rawFieldByName(n string) (rawStructField, []int, bool) { name := readStringZ(data) data = unsafe.Add(data, len(name)) if name == n { + offset := uintptr(field.offset) found = append(found, result{ rawStructFieldFromPointer(descriptor, field.fieldType, data, flagsByte, name, offset), 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 if i < descriptor.numField-1 { - // 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())) } } } @@ -860,12 +847,8 @@ func (t *rawType) Size() uintptr { case Array: return t.elem().Size() * uintptr(t.Len()) case Struct: - numField := t.NumField() - if numField == 0 { - return 0 - } - lastField := t.rawField(numField - 1) - return align(lastField.Offset+lastField.Type.Size(), uintptr(t.Align())) + u := t.underlying() + return uintptr((*structType)(unsafe.Pointer(u)).size) default: panic("unimplemented: size of type") } diff --git a/src/runtime/interface.go b/src/runtime/interface.go index 8718c140a..b9ff038b4 100644 --- a/src/runtime/interface.go +++ b/src/runtime/interface.go @@ -96,7 +96,8 @@ func interfaceTypeAssert(ok bool) { type structField struct { typecode unsafe.Pointer // type of this struct field - data *uint8 // pointer to byte array containing name, tag, and 'embedded' flag + offset uint32 + data *uint8 // pointer to byte array containing name, tag, and 'embedded' flag } // Pseudo function call used during a type assert. It is used during interface |