interface.mx raw

   1  package runtime
   2  
   3  // This file implements Go interfaces.
   4  //
   5  // Interfaces are represented as a pair of {typecode, value}, where value can be
   6  // anything (including non-pointers).
   7  
   8  import "unsafe"
   9  
  10  type _interface struct {
  11  	typecode unsafe.Pointer
  12  	value    unsafe.Pointer
  13  }
  14  
  15  //go:inline
  16  func composeInterface(typecode, value unsafe.Pointer) _interface {
  17  	return _interface{typecode, value}
  18  }
  19  
  20  //go:inline
  21  func decomposeInterface(i _interface) (unsafe.Pointer, unsafe.Pointer) {
  22  	return i.typecode, i.value
  23  }
  24  
  25  // Return true iff both interfaces are equal.
  26  func interfaceEqual(x, y interface{}) bool {
  27  	xi := (*_interface)(unsafe.Pointer(&x))
  28  	yi := (*_interface)(unsafe.Pointer(&y))
  29  	return rawValueEqual(xi.typecode, xi.value, yi.typecode, yi.value)
  30  }
  31  
  32  // rawValueEqual compares two values by their raw type codes and value pointers.
  33  // xt/yt are type code pointers; xv/yv are interface value slots (small values
  34  // packed directly, large values as pointers to data).
  35  func rawValueEqual(xt, xv, yt, yv unsafe.Pointer) bool {
  36  	if xt == nil || yt == nil {
  37  		return xt == yt
  38  	}
  39  	if xt != yt {
  40  		return false
  41  	}
  42  
  43  	t := (*rawType)(xt)
  44  
  45  	// Convert interface value representation to direct data pointer.
  46  	// Small values (fit in a pointer) are stored directly in the value slot.
  47  	// Large values are stored as a pointer to the data.
  48  	xp, yp := xv, yv
  49  	if t.size() <= unsafe.Sizeof(uintptr(0)) {
  50  		xp = unsafe.Pointer(&xv)
  51  		yp = unsafe.Pointer(&yv)
  52  	}
  53  
  54  	return rawPtrEqual(t, xp, yp)
  55  }
  56  
  57  // rawPtrEqual compares two values where xp and yp always point directly to the
  58  // value data. Used for recursive comparison of struct fields and array elements
  59  // where we already have direct pointers (no interface packing).
  60  func rawPtrEqual(t *rawType, xp, yp unsafe.Pointer) bool {
  61  	k := t.kind()
  62  
  63  	switch k {
  64  	case Bool:
  65  		return *(*bool)(xp) == *(*bool)(yp)
  66  	case Int:
  67  		return *(*int)(xp) == *(*int)(yp)
  68  	case Int8:
  69  		return *(*int8)(xp) == *(*int8)(yp)
  70  	case Int16:
  71  		return *(*int16)(xp) == *(*int16)(yp)
  72  	case Int32:
  73  		return *(*int32)(xp) == *(*int32)(yp)
  74  	case Int64:
  75  		return *(*int64)(xp) == *(*int64)(yp)
  76  	case Uint:
  77  		return *(*uint)(xp) == *(*uint)(yp)
  78  	case Uint8:
  79  		return *(*uint8)(xp) == *(*uint8)(yp)
  80  	case Uint16:
  81  		return *(*uint16)(xp) == *(*uint16)(yp)
  82  	case Uint32:
  83  		return *(*uint32)(xp) == *(*uint32)(yp)
  84  	case Uint64:
  85  		return *(*uint64)(xp) == *(*uint64)(yp)
  86  	case Uintptr:
  87  		return *(*uintptr)(xp) == *(*uintptr)(yp)
  88  	case Float32:
  89  		return *(*float32)(xp) == *(*float32)(yp)
  90  	case Float64:
  91  		return *(*float64)(xp) == *(*float64)(yp)
  92  	case Complex64:
  93  		return *(*complex64)(xp) == *(*complex64)(yp)
  94  	case Complex128:
  95  		return *(*complex128)(xp) == *(*complex128)(yp)
  96  	case kindBytes:
  97  		xs := *(*_string)(xp)
  98  		ys := *(*_string)(yp)
  99  		if xs.length != ys.length {
 100  			return false
 101  		}
 102  		return memequal(unsafe.Pointer(xs.ptr), unsafe.Pointer(ys.ptr), xs.length)
 103  	case kindChan, kindPointer, kindUnsafePointer:
 104  		return *(*uintptr)(xp) == *(*uintptr)(yp)
 105  	case kindArray:
 106  		elemType := t.elem()
 107  		elemSize := elemType.size()
 108  		length := t.arrayLen()
 109  		for i := 0; i < length; i++ {
 110  			ex := unsafe.Add(xp, uintptr(i)*elemSize)
 111  			ey := unsafe.Add(yp, uintptr(i)*elemSize)
 112  			if !rawPtrEqual(elemType, ex, ey) {
 113  				return false
 114  			}
 115  		}
 116  		return true
 117  	case kindStruct:
 118  		nf := t.numField()
 119  		for i := 0; i < nf; i++ {
 120  			ft := t.structFieldType(i)
 121  			off := t.structFieldOffset(i)
 122  			fx := unsafe.Add(xp, off)
 123  			fy := unsafe.Add(yp, off)
 124  			if !rawPtrEqual(ft, fx, fy) {
 125  				return false
 126  			}
 127  		}
 128  		return true
 129  	case kindInterface:
 130  		xi := (*_interface)(xp)
 131  		yi := (*_interface)(yp)
 132  		return rawValueEqual(xi.typecode, xi.value, yi.typecode, yi.value)
 133  	default:
 134  		runtimePanic("comparing un-comparable type")
 135  		return false
 136  	}
 137  }
 138  
 139  // interfaceTypeAssert is called when a type assert without comma-ok still
 140  // returns false.
 141  func interfaceTypeAssert(ok bool) {
 142  	if !ok {
 143  		runtimePanic("type assert failed")
 144  	}
 145  }
 146  
 147  // The following declarations are only used during IR construction. They are
 148  // lowered to inline IR in the interface lowering pass.
 149  // See compiler/interface-lowering.go for details.
 150  
 151  type structField struct {
 152  	typecode unsafe.Pointer // type of this struct field
 153  	data     *uint8         // pointer to byte array containing name, tag, varint-encoded offset, and some flags
 154  }
 155  
 156  // Pseudo function call used during a type assert. It is used during interface
 157  // lowering, to assign the lowest type numbers to the types with the most type
 158  // asserts. Also, it is replaced with const false if this type assert can never
 159  // happen.
 160  func typeAssert(actualType unsafe.Pointer, assertedType *uint8) bool
 161