typeinfo.mx raw
1 package asn1
2
3 // Unsafe type introspection for encoding/asn1, replacing reflect.
4 // Reads the compiler's type descriptors directly (same layout as
5 // internal/reflectlite/type.mx and runtime/typekind.mx).
6
7 import "unsafe"
8
9 // Kind constants matching the compiler's type descriptor format.
10 type aKind uint8
11
12 const (
13 akInvalid aKind = iota
14 akBool
15 akInt
16 akInt8
17 akInt16
18 akInt32
19 akInt64
20 akUint
21 akUint8
22 akUint16
23 akUint32
24 akUint64
25 akUintptr
26 akFloat32
27 akFloat64
28 akComplex64
29 akComplex128
30 akBytes // 17: unified string=[]byte
31 akUnsafePointer
32 akChan
33 akInterface
34 akPointer
35 akSlice
36 akArray
37 akFunc
38 akMap
39 akStruct
40 )
41
42 const (
43 _kindMask = 31
44 _flagNamed = 32
45 )
46
47 // Struct field flags from the field descriptor data blob.
48 const (
49 _sfAnonymous = 1 << iota
50 _sfHasTag
51 _sfExported
52 )
53
54 // _ifacePair is the interface{} memory layout.
55 type _ifacePair struct {
56 typecode unsafe.Pointer
57 value unsafe.Pointer
58 }
59
60 // _rawType is the base type descriptor.
61 type _rawType struct {
62 meta uint8
63 }
64
65 // _elemType: named, chan, slice, array, map.
66 type _elemType struct {
67 _rawType
68 numMethod uint16
69 ptrTo *_rawType
70 elem *_rawType
71 }
72
73 // _ptrType: pointer types (no ptrTo field).
74 type _ptrType struct {
75 _rawType
76 numMethod uint16
77 elem *_rawType
78 }
79
80 // _structType: struct types.
81 type _structType struct {
82 _rawType
83 numMethod uint16
84 ptrTo *_rawType
85 pkgpath *byte
86 size uint32
87 numField uint16
88 fields [1]_structFieldDesc
89 }
90
91 type _structFieldDesc struct {
92 fieldType *_rawType
93 data unsafe.Pointer
94 }
95
96 // _sliceHeader is the memory layout of a slice.
97 type _sliceHeader struct {
98 data unsafe.Pointer
99 len int
100 cap int
101 }
102
103 func (t *_rawType) kind() aKind {
104 if t == nil {
105 return akInvalid
106 }
107 if uintptr(unsafe.Pointer(t))&0b11 != 0 {
108 return akPointer
109 }
110 return aKind(t.meta & _kindMask)
111 }
112
113 func (t *_rawType) isNamed() bool {
114 if uintptr(unsafe.Pointer(t))&0b11 != 0 {
115 return false
116 }
117 return t.meta&_flagNamed != 0
118 }
119
120 func (t *_rawType) underlying() *_rawType {
121 if t.isNamed() {
122 return (*_elemType)(unsafe.Pointer(t)).elem
123 }
124 return t
125 }
126
127 func (t *_rawType) size() uintptr {
128 switch t.kind() {
129 case akBool, akInt8, akUint8:
130 return 1
131 case akInt16, akUint16:
132 return 2
133 case akInt32, akUint32, akFloat32:
134 return 4
135 case akInt64, akUint64, akFloat64:
136 return 8
137 case akInt, akUint:
138 return unsafe.Sizeof(int(0))
139 case akUintptr:
140 return unsafe.Sizeof(uintptr(0))
141 case akBytes:
142 return unsafe.Sizeof("")
143 case akUnsafePointer, akChan, akMap, akPointer:
144 return unsafe.Sizeof(uintptr(0))
145 case akSlice:
146 return unsafe.Sizeof([]int{})
147 case akInterface:
148 return unsafe.Sizeof(interface{}(nil))
149 case akStruct:
150 return uintptr((*_structType)(unsafe.Pointer(t.underlying())).size)
151 default:
152 return 0
153 }
154 }
155
156 func (t *_rawType) elem() *_rawType {
157 if tag := uintptr(unsafe.Pointer(t)) & 0b11; tag != 0 {
158 // Tagged pointer: peel one pointer level.
159 return (*_rawType)(unsafe.Pointer(uintptr(unsafe.Pointer(t)) - 1))
160 }
161 u := t.underlying()
162 if u.kind() == akPointer {
163 return (*_ptrType)(unsafe.Pointer(u)).elem
164 }
165 return (*_elemType)(unsafe.Pointer(u)).elem
166 }
167
168 func (t *_rawType) numField() int {
169 return int((*_structType)(unsafe.Pointer(t.underlying())).numField)
170 }
171
172 func (t *_rawType) fieldDesc(i int) *_structFieldDesc {
173 st := (*_structType)(unsafe.Pointer(t.underlying()))
174 return (*_structFieldDesc)(unsafe.Add(
175 unsafe.Pointer(&st.fields[0]),
176 uintptr(i)*unsafe.Sizeof(_structFieldDesc{}),
177 ))
178 }
179
180 func (t *_rawType) fieldType(i int) *_rawType {
181 return t.fieldDesc(i).fieldType
182 }
183
184 // fieldData reads the field descriptor data blob for the i-th field.
185 // Returns: flags, field offset, name, and tag.
186 func (t *_rawType) fieldData(i int) (flags uint8, offset uintptr, name []byte, tag []byte) {
187 fd := t.fieldDesc(i)
188 p := (*byte)(fd.data)
189
190 // flags byte
191 flags = *p
192 p = (*byte)(unsafe.Add(unsafe.Pointer(p), 1))
193
194 // varint-encoded offset
195 var shift uint
196 for {
197 b := *p
198 offset |= uintptr(b&0x7f) << shift
199 if b&0x80 == 0 {
200 p = (*byte)(unsafe.Add(unsafe.Pointer(p), 1))
201 break
202 }
203 shift += 7
204 p = (*byte)(unsafe.Add(unsafe.Pointer(p), 1))
205 }
206
207 // null-terminated name
208 nameStart := unsafe.Pointer(p)
209 nameLen := 0
210 for *p != 0 {
211 nameLen++
212 p = (*byte)(unsafe.Add(unsafe.Pointer(p), 1))
213 }
214 name = unsafe.Slice((*byte)(nameStart), nameLen)
215 p = (*byte)(unsafe.Add(unsafe.Pointer(p), 1)) // skip null
216
217 // tag (if present)
218 if flags&_sfHasTag != 0 {
219 tagLen := int(*p)
220 p = (*byte)(unsafe.Add(unsafe.Pointer(p), 1))
221 tag = unsafe.Slice((*byte)(unsafe.Pointer(p)), tagLen)
222 }
223 return
224 }
225
226 func (t *_rawType) fieldOffset(i int) uintptr {
227 _, off, _, _ := t.fieldData(i)
228 return off
229 }
230
231 func (t *_rawType) fieldTag(i int) []byte {
232 _, _, _, tag := t.fieldData(i)
233 return tag
234 }
235
236 func (t *_rawType) fieldExported(i int) bool {
237 flags, _, _, _ := t.fieldData(i)
238 return flags&_sfExported != 0
239 }
240
241 func (t *_rawType) fieldName(i int) []byte {
242 _, _, name, _ := t.fieldData(i)
243 return name
244 }
245
246 // typeName returns the type's name (empty for unnamed types).
247 func (t *_rawType) typeName() []byte {
248 if !t.isNamed() {
249 return nil
250 }
251 // namedType has: rawType, numMethod, ptrTo, elem, pkg, name[1]
252 // name starts after pkg (*byte) field.
253 type _namedType struct {
254 _rawType
255 numMethod uint16
256 ptrTo *_rawType
257 elem *_rawType
258 pkg *byte
259 name [1]byte
260 }
261 nt := (*_namedType)(unsafe.Pointer(t))
262 p := &nt.name[0]
263 n := 0
264 for *(*byte)(unsafe.Add(unsafe.Pointer(p), uintptr(n))) != 0 {
265 n++
266 }
267 return unsafe.Slice(p, n)
268 }
269
270 // typeCodeOf extracts the raw type code pointer from an interface value.
271 func typeCodeOf(val any) *_rawType {
272 return (*_rawType)((*_ifacePair)(unsafe.Pointer(&val)).typecode)
273 }
274
275 // dataOf extracts the data pointer from an interface value, dereferencing
276 // the interface packing (small values are stored directly in the pointer slot).
277 func dataOf(val any) unsafe.Pointer {
278 iface := (*_ifacePair)(unsafe.Pointer(&val))
279 t := (*_rawType)(iface.typecode)
280 if t.size() <= unsafe.Sizeof(uintptr(0)) {
281 return unsafe.Pointer(&iface.value)
282 }
283 return iface.value
284 }
285
286 // derefPtr extracts the element type and data pointer from an interface
287 // holding a pointer type. Returns the pointed-to type and data pointer.
288 func derefPtr(val any) (*_rawType, unsafe.Pointer) {
289 iface := (*_ifacePair)(unsafe.Pointer(&val))
290 t := (*_rawType)(iface.typecode)
291 if t.kind() != akPointer {
292 return nil, nil
293 }
294 elemType := t.elem()
295 // Pointer is a small type (size == pointer size), so iface.value IS the pointer.
296 dataPtr := iface.value
297 return elemType, dataPtr
298 }
299
300 // ptrToIface constructs an interface{} from a pointer to data.
301 // The resulting interface holds a *T where T has type code t.
302 func ptrToIface(t *_rawType, ptr unsafe.Pointer) any {
303 // Need the *T type code. For named types, ptrTo is in the elemType layout.
304 var ptrType *_rawType
305 if t.isNamed() {
306 ptrType = (*_elemType)(unsafe.Pointer(t)).ptrTo
307 } else {
308 switch t.kind() {
309 case akStruct:
310 ptrType = (*_structType)(unsafe.Pointer(t)).ptrTo
311 default:
312 // For other types, the ptrTo field is at the same offset as elemType.ptrTo
313 ptrType = (*_elemType)(unsafe.Pointer(t)).ptrTo
314 }
315 }
316 if ptrType == nil {
317 // Fallback: can't construct typed pointer interface.
318 return nil
319 }
320 // Construct _ifacePair with pointer type code and the pointer as value.
321 // Pointer is small (fits in pointer slot), so value IS the pointer.
322 iface := _ifacePair{typecode: unsafe.Pointer(ptrType), value: ptr}
323 return *(*any)(unsafe.Pointer(&iface))
324 }
325
326 // valToIface constructs an interface{} from a type and data pointer.
327 func valToIface(t *_rawType, ptr unsafe.Pointer) any {
328 iface := _ifacePair{typecode: unsafe.Pointer(t), value: ptr}
329 if t.size() <= unsafe.Sizeof(uintptr(0)) {
330 // Small value: copy the value into the pointer slot.
331 iface.value = *(*unsafe.Pointer)(ptr)
332 }
333 return *(*any)(unsafe.Pointer(&iface))
334 }
335
336 // makeZero allocates a zeroed value of the given type and returns a pointer to it.
337 func makeZero(t *_rawType) unsafe.Pointer {
338 sz := t.size()
339 buf := make([]byte, sz)
340 return unsafe.Pointer(&buf[0])
341 }
342
343 // makeSliceOf creates a new slice with the given element type, length, and capacity.
344 // Returns a pointer to the slice header.
345 func makeSliceOf(elemType *_rawType, length, capacity int) unsafe.Pointer {
346 elemSize := elemType.size()
347 buf := make([]byte, elemSize*uintptr(capacity))
348 var dataPtr unsafe.Pointer
349 if len(buf) > 0 {
350 dataPtr = unsafe.Pointer(&buf[0])
351 }
352 p := &_sliceHeader{data: dataPtr, len: length, cap: capacity}
353 return unsafe.Pointer(p)
354 }
355
356 // sliceAppend grows a slice by one element (zeroed) and returns the
357 // updated slice header pointer. elemType is the element type.
358 func sliceAppend(slicePtr unsafe.Pointer, elemType *_rawType) unsafe.Pointer {
359 hdr := (*_sliceHeader)(slicePtr)
360 elemSize := elemType.size()
361 if hdr.len >= hdr.cap {
362 // Grow: double capacity or set to 4 minimum.
363 newCap := hdr.cap * 2
364 if newCap < 4 {
365 newCap = 4
366 }
367 newBuf := make([]byte, elemSize*uintptr(newCap))
368 var newData unsafe.Pointer
369 if len(newBuf) > 0 {
370 newData = unsafe.Pointer(&newBuf[0])
371 }
372 // Copy old data.
373 if hdr.data != nil && hdr.len > 0 {
374 memcpy(newData, hdr.data, elemSize*uintptr(hdr.len))
375 }
376 hdr.data = newData
377 hdr.cap = newCap
378 }
379 hdr.len++
380 return slicePtr
381 }
382
383 // sliceIndex returns a pointer to the i-th element of a slice.
384 func sliceIndex(slicePtr unsafe.Pointer, elemType *_rawType, i int) unsafe.Pointer {
385 hdr := (*_sliceHeader)(slicePtr)
386 return unsafe.Add(hdr.data, elemType.size()*uintptr(i))
387 }
388
389 //go:linkname memcpy runtime.memcpy
390 func memcpy(dst, src unsafe.Pointer, n uintptr)
391