2021-03-15 20:50:19 +03:00
|
|
|
package runtime
|
|
|
|
|
2021-03-16 13:44:32 +03:00
|
|
|
import (
|
|
|
|
"reflect"
|
|
|
|
"unsafe"
|
|
|
|
)
|
2021-03-15 20:50:19 +03:00
|
|
|
|
|
|
|
type SliceHeader struct {
|
|
|
|
Data unsafe.Pointer
|
|
|
|
Len int
|
|
|
|
Cap int
|
|
|
|
}
|
2021-03-16 13:44:32 +03:00
|
|
|
|
|
|
|
const (
|
|
|
|
maxAcceptableTypeAddrRange = 1024 * 1024 * 2 // 2 Mib
|
|
|
|
)
|
|
|
|
|
|
|
|
type TypeAddr struct {
|
|
|
|
BaseTypeAddr uintptr
|
|
|
|
MaxTypeAddr uintptr
|
|
|
|
AddrRange uintptr
|
2021-05-04 03:00:10 +03:00
|
|
|
AddrShift uintptr
|
2021-03-16 13:44:32 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
var (
|
|
|
|
typeAddr *TypeAddr
|
|
|
|
alreadyAnalyzed bool
|
|
|
|
)
|
|
|
|
|
|
|
|
//go:linkname typelinks reflect.typelinks
|
|
|
|
func typelinks() ([]unsafe.Pointer, [][]int32)
|
|
|
|
|
|
|
|
//go:linkname rtypeOff reflect.rtypeOff
|
|
|
|
func rtypeOff(unsafe.Pointer, int32) unsafe.Pointer
|
|
|
|
|
|
|
|
func AnalyzeTypeAddr() *TypeAddr {
|
|
|
|
defer func() {
|
|
|
|
alreadyAnalyzed = true
|
|
|
|
}()
|
|
|
|
if alreadyAnalyzed {
|
|
|
|
return typeAddr
|
|
|
|
}
|
|
|
|
sections, offsets := typelinks()
|
|
|
|
if len(sections) != 1 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if len(offsets) != 1 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
section := sections[0]
|
|
|
|
offset := offsets[0]
|
|
|
|
var (
|
2021-05-04 03:00:10 +03:00
|
|
|
min uintptr = uintptr(^uint(0))
|
|
|
|
max uintptr = 0
|
|
|
|
isAligned64 = true
|
|
|
|
isAligned32 = true
|
2021-03-16 13:44:32 +03:00
|
|
|
)
|
|
|
|
for i := 0; i < len(offset); i++ {
|
|
|
|
typ := (*Type)(rtypeOff(section, offset[i]))
|
|
|
|
addr := uintptr(unsafe.Pointer(typ))
|
|
|
|
if min > addr {
|
|
|
|
min = addr
|
|
|
|
}
|
|
|
|
if max < addr {
|
|
|
|
max = addr
|
|
|
|
}
|
|
|
|
if typ.Kind() == reflect.Ptr {
|
|
|
|
addr = uintptr(unsafe.Pointer(typ.Elem()))
|
|
|
|
if min > addr {
|
|
|
|
min = addr
|
|
|
|
}
|
|
|
|
if max < addr {
|
|
|
|
max = addr
|
|
|
|
}
|
|
|
|
}
|
2021-05-04 03:00:10 +03:00
|
|
|
isAligned64 = isAligned64 && (addr-min)&63 == 0
|
|
|
|
isAligned32 = isAligned32 && (addr-min)&31 == 0
|
2021-03-16 13:44:32 +03:00
|
|
|
}
|
|
|
|
addrRange := max - min
|
|
|
|
if addrRange == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
2021-05-04 03:00:10 +03:00
|
|
|
var addrShift uintptr
|
|
|
|
if isAligned64 {
|
|
|
|
addrShift = 6
|
|
|
|
} else if isAligned32 {
|
|
|
|
addrShift = 5
|
|
|
|
}
|
|
|
|
cacheSize := addrRange >> addrShift
|
|
|
|
if cacheSize > maxAcceptableTypeAddrRange {
|
2021-03-16 13:44:32 +03:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
typeAddr = &TypeAddr{
|
|
|
|
BaseTypeAddr: min,
|
|
|
|
MaxTypeAddr: max,
|
|
|
|
AddrRange: addrRange,
|
2021-05-04 03:00:10 +03:00
|
|
|
AddrShift: addrShift,
|
2021-03-16 13:44:32 +03:00
|
|
|
}
|
|
|
|
return typeAddr
|
|
|
|
}
|