1package reflect 2 3import ( 4 "unsafe" 5) 6 7// This stores a varint for each named type. Named types are identified by their 8// name instead of by their type. The named types stored in this struct are 9// non-basic types: pointer, struct, and channel. 10//go:extern reflect.namedNonBasicTypesSidetable 11var namedNonBasicTypesSidetable uintptr 12 13//go:extern reflect.structTypesSidetable 14var structTypesSidetable byte 15 16//go:extern reflect.structNamesSidetable 17var structNamesSidetable byte 18 19//go:extern reflect.arrayTypesSidetable 20var arrayTypesSidetable byte 21 22// readStringSidetable reads a string from the given table (like 23// structNamesSidetable) and returns this string. No heap allocation is 24// necessary because it makes the string point directly to the raw bytes of the 25// table. 26func readStringSidetable(table unsafe.Pointer, index uintptr) string { 27 nameLen, namePtr := readVarint(unsafe.Pointer(uintptr(table) + index)) 28 return *(*string)(unsafe.Pointer(&StringHeader{ 29 Data: uintptr(namePtr), 30 Len: nameLen, 31 })) 32} 33 34// readVarint decodes a varint as used in the encoding/binary package. 35// It has an input pointer and returns the read varint and the pointer 36// incremented to the next field in the data structure, just after the varint. 37// 38// Details: 39// https://github.com/golang/go/blob/e37a1b1c/src/encoding/binary/varint.go#L7-L25 40func readVarint(buf unsafe.Pointer) (uintptr, unsafe.Pointer) { 41 var n uintptr 42 shift := uintptr(0) 43 for { 44 // Read the next byte in the buffer. 45 c := *(*byte)(buf) 46 47 // Decode the bits from this byte and add them to the output number. 48 n |= uintptr(c&0x7f) << shift 49 shift += 7 50 51 // Increment the buf pointer (pointer arithmetic!). 52 buf = unsafe.Pointer(uintptr(buf) + 1) 53 54 // Check whether this is the last byte of this varint. The upper bit 55 // (msb) indicates whether any bytes follow. 56 if c>>7 == 0 { 57 return n, buf 58 } 59 } 60} 61