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