
These variants uses an unsafe.Pointer instead of uintptr so that the pointer/non-pointer fields match those of real slices and strings. This may be necessary in the future once we switch to a precise garbage collector.
60 строки
1,8 КиБ
Go
60 строки
1,8 КиБ
Go
package reflect
|
|
|
|
import (
|
|
"unsafe"
|
|
)
|
|
|
|
// This stores a varint for each named type. Named types are identified by their
|
|
// name instead of by their type. The named types stored in this struct are
|
|
// non-basic types: pointer, struct, and channel.
|
|
//go:extern reflect.namedNonBasicTypesSidetable
|
|
var namedNonBasicTypesSidetable uintptr
|
|
|
|
//go:extern reflect.structTypesSidetable
|
|
var structTypesSidetable byte
|
|
|
|
//go:extern reflect.structNamesSidetable
|
|
var structNamesSidetable byte
|
|
|
|
//go:extern reflect.arrayTypesSidetable
|
|
var arrayTypesSidetable byte
|
|
|
|
// readStringSidetable reads a string from the given table (like
|
|
// structNamesSidetable) and returns this string. No heap allocation is
|
|
// necessary because it makes the string point directly to the raw bytes of the
|
|
// table.
|
|
func readStringSidetable(table unsafe.Pointer, index uintptr) string {
|
|
nameLen, namePtr := readVarint(unsafe.Pointer(uintptr(table) + index))
|
|
return *(*string)(unsafe.Pointer(&stringHeader{
|
|
data: namePtr,
|
|
len: nameLen,
|
|
}))
|
|
}
|
|
|
|
// readVarint decodes a varint as used in the encoding/binary package.
|
|
// It has an input pointer and returns the read varint and the pointer
|
|
// incremented to the next field in the data structure, just after the varint.
|
|
//
|
|
// Details:
|
|
// https://github.com/golang/go/blob/e37a1b1c/src/encoding/binary/varint.go#L7-L25
|
|
func readVarint(buf unsafe.Pointer) (uintptr, unsafe.Pointer) {
|
|
var n uintptr
|
|
shift := uintptr(0)
|
|
for {
|
|
// Read the next byte in the buffer.
|
|
c := *(*byte)(buf)
|
|
|
|
// Decode the bits from this byte and add them to the output number.
|
|
n |= uintptr(c&0x7f) << shift
|
|
shift += 7
|
|
|
|
// Increment the buf pointer (pointer arithmetic!).
|
|
buf = unsafe.Pointer(uintptr(buf) + 1)
|
|
|
|
// Check whether this is the last byte of this varint. The upper bit
|
|
// (msb) indicates whether any bytes follow.
|
|
if c>>7 == 0 {
|
|
return n, buf
|
|
}
|
|
}
|
|
}
|