diff options
author | Damian Gryski <[email protected]> | 2023-04-27 09:14:08 -0700 |
---|---|---|
committer | Ron Evans <[email protected]> | 2023-05-16 19:02:08 +0200 |
commit | 07fb3a0cadb6c02e3c2a09429b45c9c9ea29b61c (patch) | |
tree | 98e3572d589d120d499b9138e47f0aa5afca8493 /src/reflect | |
parent | 02913563df710ab05f2831429d064b6a3e615c99 (diff) | |
download | tinygo-07fb3a0cadb6c02e3c2a09429b45c9c9ea29b61c.tar.gz tinygo-07fb3a0cadb6c02e3c2a09429b45c9c9ea29b61c.zip |
compiler,reflect: make field offsets varints
Fixes #3686
Diffstat (limited to 'src/reflect')
-rw-r--r-- | src/reflect/type.go | 34 |
1 files changed, 29 insertions, 5 deletions
diff --git a/src/reflect/type.go b/src/reflect/type.go index 6d8aec399..6a37dc7d5 100644 --- a/src/reflect/type.go +++ b/src/reflect/type.go @@ -463,7 +463,6 @@ type structType struct { type structField struct { fieldType *rawType - offset uint32 data unsafe.Pointer // various bits of information, packed in a byte array } @@ -624,7 +623,7 @@ func (t *rawType) Field(i int) StructField { } } -func rawStructFieldFromPointer(descriptor *structType, 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 uint32) rawStructField { // Read the field tag, if there is one. var tag string if flagsByte&structFieldFlagHasTag != 0 { @@ -651,7 +650,7 @@ func rawStructFieldFromPointer(descriptor *structType, fieldType *rawType, data Type: fieldType, Tag: StructTag(tag), Anonymous: flagsByte&structFieldFlagAnonymous != 0, - Offset: offset, + Offset: uintptr(offset), } } @@ -673,13 +672,14 @@ func (t *rawType) rawField(n int) rawStructField { // lookup faster), but by calculating it on-the-fly a bit of storage can be // saved. 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 // field. See structFieldFlagAnonymous and similar flags. flagsByte := *(*byte)(data) data = unsafe.Add(data, 1) + offset, lenOffs := uvarint32(unsafe.Slice((*byte)(data), maxVarintLen32)) + data = unsafe.Add(data, lenOffs) name := readStringZ(data) data = unsafe.Add(data, len(name)) @@ -729,10 +729,12 @@ func (t *rawType) rawFieldByName(n string) (rawStructField, []int, bool) { flagsByte := *(*byte)(data) data = unsafe.Add(data, 1) + offset, lenOffs := uvarint32(unsafe.Slice((*byte)(data), maxVarintLen32)) + data = unsafe.Add(data, lenOffs) + 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)), @@ -1284,3 +1286,25 @@ func StructOf([]StructField) Type { func MapOf(key, value Type) Type { panic("unimplemented: reflect.MapOf()") } + +const maxVarintLen32 = 5 + +// encoding/binary.Uvarint, specialized for uint32 +func uvarint32(buf []byte) (uint32, int) { + var x uint32 + var s uint + for i, b := range buf { + if i == maxVarintLen32 { + return 0, -(i + 1) // overflow + } + if b < 0x80 { + if i == maxVarintLen32-1 && b > 1 { + return 0, -(i + 1) // overflow + } + return x | uint32(b)<<s, i + 1 + } + x |= uint32(b&0x7f) << s + s += 7 + } + return 0, 0 +} |