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