github.com/3JoB/go-json@v0.10.4/internal/runtime/type.go (about) 1 package runtime 2 3 import ( 4 "unsafe" 5 6 "reflect" 7 ) 8 9 type SliceHeader struct { 10 Data unsafe.Pointer 11 Len int 12 Cap int 13 } 14 15 const ( 16 maxAcceptableTypeAddrRange = 1024 * 1024 * 2 // 2 Mib 17 ) 18 19 type TypeAddr struct { 20 BaseTypeAddr uintptr 21 MaxTypeAddr uintptr 22 AddrRange uintptr 23 AddrShift uintptr 24 } 25 26 var ( 27 typeAddr *TypeAddr 28 alreadyAnalyzed bool 29 ) 30 31 //go:linkname typelinks reflect.typelinks 32 func typelinks() ([]unsafe.Pointer, [][]int32) 33 34 //go:linkname rtypeOff reflect.rtypeOff 35 func rtypeOff(unsafe.Pointer, int32) unsafe.Pointer 36 37 func AnalyzeTypeAddr() *TypeAddr { 38 defer func() { 39 alreadyAnalyzed = true 40 }() 41 if alreadyAnalyzed { 42 return typeAddr 43 } 44 sections, offsets := typelinks() 45 if len(sections) != 1 { 46 return nil 47 } 48 if len(offsets) != 1 { 49 return nil 50 } 51 section := sections[0] 52 offset := offsets[0] 53 var ( 54 min uintptr = uintptr(^uint(0)) 55 max uintptr = 0 56 isAligned64 = true 57 isAligned32 = true 58 ) 59 for i := 0; i < len(offset); i++ { 60 typ := (*Type)(rtypeOff(section, offset[i])) 61 addr := uintptr(unsafe.Pointer(typ)) 62 if min > addr { 63 min = addr 64 } 65 if max < addr { 66 max = addr 67 } 68 if typ.Kind() == reflect.Ptr { 69 addr = uintptr(unsafe.Pointer(typ.Elem())) 70 if min > addr { 71 min = addr 72 } 73 if max < addr { 74 max = addr 75 } 76 } 77 isAligned64 = isAligned64 && (addr-min)&63 == 0 78 isAligned32 = isAligned32 && (addr-min)&31 == 0 79 } 80 addrRange := max - min 81 if addrRange == 0 { 82 return nil 83 } 84 var addrShift uintptr 85 if isAligned64 { 86 addrShift = 6 87 } else if isAligned32 { 88 addrShift = 5 89 } 90 cacheSize := addrRange >> addrShift 91 if cacheSize > maxAcceptableTypeAddrRange { 92 return nil 93 } 94 typeAddr = &TypeAddr{ 95 BaseTypeAddr: min, 96 MaxTypeAddr: max, 97 AddrRange: addrRange, 98 AddrShift: addrShift, 99 } 100 return typeAddr 101 }