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