typekind.mx raw

   1  package runtime
   2  
   3  // Minimal type introspection for interface equality and hashmap hashing.
   4  // Replaces the reflectlite dependency in runtime.
   5  // These constants and types mirror internal/reflectlite but are defined
   6  // locally to break the runtime→reflectlite→runtime cycle.
   7  //
   8  // CRITICAL: struct layouts must exactly match those in
   9  // internal/reflectlite/type.mx — the compiler generates type descriptors
  10  // in that format.
  11  
  12  import "unsafe"
  13  
  14  type Kind uint8
  15  
  16  const (
  17  	Invalid Kind = iota
  18  	Bool
  19  	Int
  20  	Int8
  21  	Int16
  22  	Int32
  23  	Int64
  24  	Uint
  25  	Uint8
  26  	Uint16
  27  	Uint32
  28  	Uint64
  29  	Uintptr
  30  	Float32
  31  	Float64
  32  	Complex64
  33  	Complex128
  34  	kindBytes // kind 17: unified string=[]byte
  35  	kindUnsafePointer
  36  	kindChan
  37  	kindInterface
  38  	kindPointer
  39  	kindSlice
  40  	kindArray
  41  	kindFunc
  42  	kindMap
  43  	kindStruct
  44  )
  45  
  46  const (
  47  	kindMask       = 31
  48  	flagNamed      = 32
  49  	flagComparable = 64
  50  	flagIsBinary   = 128
  51  )
  52  
  53  // rawType is the base type descriptor. All type descriptors start with this.
  54  type rawType struct {
  55  	meta uint8
  56  }
  57  
  58  // rtElemType: named, chan, slice, array, map — types with elem pointer.
  59  // Layout: meta(1) pad(1) numMethod(2) pad(4) ptrTo(8) elem(8) = 24 bytes
  60  type rtElemType struct {
  61  	rawType
  62  	numMethod uint16
  63  	ptrTo     *rawType
  64  	elem      *rawType
  65  }
  66  
  67  // rtPtrType: pointer types — no ptrTo field.
  68  // Layout: meta(1) pad(1) numMethod(2) pad(4) elem(8) = 16 bytes
  69  type rtPtrType struct {
  70  	rawType
  71  	numMethod uint16
  72  	elem      *rawType
  73  }
  74  
  75  // rtArrayType: array types.
  76  // Layout: meta(1) pad(1) numMethod(2) pad(4) ptrTo(8) elem(8) arrayLen(8) slicePtr(8) = 40 bytes
  77  type rtArrayType struct {
  78  	rtElemType
  79  	arrayLen uintptr
  80  	slicePtr *rawType
  81  }
  82  
  83  // rtStructType: struct types. Does NOT have elem field — has pkgpath instead.
  84  // Layout: meta(1) pad(1) numMethod(2) pad(4) ptrTo(8) pkgpath(8) size(4) numField(2) pad(2) fields(...)
  85  type rtStructType struct {
  86  	rawType
  87  	numMethod uint16
  88  	ptrTo     *rawType
  89  	pkgpath   *byte
  90  	size      uint32
  91  	numField  uint16
  92  	fields    [1]rtStructFieldDesc // flexible array member
  93  }
  94  
  95  // rtStructFieldDesc is a struct field descriptor.
  96  type rtStructFieldDesc struct {
  97  	fieldType *rawType
  98  	data      unsafe.Pointer
  99  }
 100  
 101  func (t *rawType) isNamed() bool {
 102  	if uintptr(unsafe.Pointer(t))&0b11 != 0 {
 103  		return false
 104  	}
 105  	return t.meta&flagNamed != 0
 106  }
 107  
 108  func (t *rawType) kind() Kind {
 109  	if t == nil {
 110  		return Invalid
 111  	}
 112  	if tag := uintptr(unsafe.Pointer(t)) & 0b11; tag != 0 {
 113  		return kindPointer
 114  	}
 115  	return Kind(t.meta & kindMask)
 116  }
 117  
 118  func (t *rawType) size() uintptr {
 119  	switch t.kind() {
 120  	case Bool, Int8, Uint8:
 121  		return 1
 122  	case Int16, Uint16:
 123  		return 2
 124  	case Int32, Uint32, Float32:
 125  		return 4
 126  	case Int64, Uint64, Float64:
 127  		return 8
 128  	case Int, Uint:
 129  		return unsafe.Sizeof(int(0))
 130  	case Uintptr:
 131  		return unsafe.Sizeof(uintptr(0))
 132  	case Complex64:
 133  		return 8
 134  	case Complex128:
 135  		return 16
 136  	case kindBytes:
 137  		return unsafe.Sizeof("")
 138  	case kindUnsafePointer, kindChan, kindMap, kindPointer:
 139  		return unsafe.Sizeof(uintptr(0))
 140  	case kindSlice:
 141  		return unsafe.Sizeof([]int{})
 142  	case kindInterface:
 143  		return unsafe.Sizeof(interface{}(nil))
 144  	case kindFunc:
 145  		var f func()
 146  		return unsafe.Sizeof(f)
 147  	case kindArray:
 148  		return t.elem().size() * uintptr(t.arrayLen())
 149  	case kindStruct:
 150  		return uintptr(t.structSize())
 151  	default:
 152  		return 0
 153  	}
 154  }
 155  
 156  // underlying returns the underlying type. For named types, follows the
 157  // elem pointer in the namedType/elemType layout to the underlying type.
 158  func (t *rawType) underlying() *rawType {
 159  	if t.isNamed() {
 160  		// namedType has same layout as elemType: elem is at the same offset.
 161  		return (*rtElemType)(unsafe.Pointer(t)).elem
 162  	}
 163  	return t
 164  }
 165  
 166  // elem returns the element type for pointer, chan, slice, array, map types.
 167  func (t *rawType) elem() *rawType {
 168  	if tag := uintptr(unsafe.Pointer(t)) & 0b11; tag != 0 {
 169  		// Tagged pointer: peel one pointer level.
 170  		return (*rawType)(unsafe.Pointer(uintptr(unsafe.Pointer(t)) - 1))
 171  	}
 172  	u := t.underlying()
 173  	switch u.kind() {
 174  	case kindPointer:
 175  		return (*rtPtrType)(unsafe.Pointer(u)).elem
 176  	default:
 177  		return (*rtElemType)(unsafe.Pointer(u)).elem
 178  	}
 179  }
 180  
 181  func (t *rawType) arrayLen() int {
 182  	u := t.underlying()
 183  	return int((*rtArrayType)(unsafe.Pointer(u)).arrayLen)
 184  }
 185  
 186  func (t *rawType) structSize() uint32 {
 187  	u := t.underlying()
 188  	return (*rtStructType)(unsafe.Pointer(u)).size
 189  }
 190  
 191  func (t *rawType) numField() int {
 192  	u := t.underlying()
 193  	return int((*rtStructType)(unsafe.Pointer(u)).numField)
 194  }
 195  
 196  // structFieldType returns the type of the i-th field of a struct.
 197  func (t *rawType) structFieldType(i int) *rawType {
 198  	u := t.underlying()
 199  	st := (*rtStructType)(unsafe.Pointer(u))
 200  	fd := (*rtStructFieldDesc)(unsafe.Add(
 201  		unsafe.Pointer(&st.fields[0]),
 202  		uintptr(i)*unsafe.Sizeof(rtStructFieldDesc{}),
 203  	))
 204  	return fd.fieldType
 205  }
 206  
 207  // structFieldOffset returns the offset of the i-th field by reading the
 208  // varint-encoded offset from the field descriptor's data pointer.
 209  // Data format: flags(1 byte) + varint(offset) + name(null-term) + ...
 210  func (t *rawType) structFieldOffset(i int) uintptr {
 211  	u := t.underlying()
 212  	st := (*rtStructType)(unsafe.Pointer(u))
 213  	fd := (*rtStructFieldDesc)(unsafe.Add(
 214  		unsafe.Pointer(&st.fields[0]),
 215  		uintptr(i)*unsafe.Sizeof(rtStructFieldDesc{}),
 216  	))
 217  	p := (*uint8)(fd.data)
 218  	// skip flags byte
 219  	p = (*uint8)(unsafe.Add(unsafe.Pointer(p), 1))
 220  	// read varint-encoded offset
 221  	var offset uintptr
 222  	var shift uint
 223  	for {
 224  		b := *p
 225  		offset |= uintptr(b&0x7f) << shift
 226  		if b&0x80 == 0 {
 227  			break
 228  		}
 229  		shift += 7
 230  		p = (*uint8)(unsafe.Add(unsafe.Pointer(p), 1))
 231  	}
 232  	return offset
 233  }
 234