Source file src/cmd/compile/internal/rttype/rttype.go

     1  // Copyright 2023 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package rttype allows the compiler to share type information with
     6  // the runtime. The shared type information is stored in
     7  // internal/abi. This package translates those types from the host
     8  // machine on which the compiler runs to the target machine on which
     9  // the compiled program will run. In particular, this package handles
    10  // layout differences between e.g. a 64 bit compiler and 32 bit
    11  // target.
    12  package rttype
    13  
    14  import (
    15  	"cmd/compile/internal/base"
    16  	"cmd/compile/internal/objw"
    17  	"cmd/compile/internal/types"
    18  	"cmd/internal/obj"
    19  	"internal/abi"
    20  	"reflect"
    21  )
    22  
    23  // The type structures shared with the runtime.
    24  var Type *types.Type
    25  
    26  var ArrayType *types.Type
    27  var ChanType *types.Type
    28  var FuncType *types.Type
    29  var InterfaceType *types.Type
    30  var MapType *types.Type
    31  var PtrType *types.Type
    32  var SliceType *types.Type
    33  var StructType *types.Type
    34  
    35  // Types that are parts of the types above.
    36  var IMethod *types.Type
    37  var Method *types.Type
    38  var StructField *types.Type
    39  var UncommonType *types.Type
    40  
    41  // Type switches and asserts
    42  var InterfaceSwitch *types.Type
    43  var TypeAssert *types.Type
    44  
    45  // Interface tables (itabs)
    46  var ITab *types.Type
    47  
    48  func Init() {
    49  	// Note: this has to be called explicitly instead of being
    50  	// an init function so it runs after the types package has
    51  	// been properly initialized.
    52  	Type = FromReflect(reflect.TypeFor[abi.Type]())
    53  	ArrayType = FromReflect(reflect.TypeFor[abi.ArrayType]())
    54  	ChanType = FromReflect(reflect.TypeFor[abi.ChanType]())
    55  	FuncType = FromReflect(reflect.TypeFor[abi.FuncType]())
    56  	InterfaceType = FromReflect(reflect.TypeFor[abi.InterfaceType]())
    57  	MapType = FromReflect(reflect.TypeFor[abi.MapType]())
    58  	PtrType = FromReflect(reflect.TypeFor[abi.PtrType]())
    59  	SliceType = FromReflect(reflect.TypeFor[abi.SliceType]())
    60  	StructType = FromReflect(reflect.TypeFor[abi.StructType]())
    61  
    62  	IMethod = FromReflect(reflect.TypeFor[abi.Imethod]())
    63  	Method = FromReflect(reflect.TypeFor[abi.Method]())
    64  	StructField = FromReflect(reflect.TypeFor[abi.StructField]())
    65  	UncommonType = FromReflect(reflect.TypeFor[abi.UncommonType]())
    66  
    67  	InterfaceSwitch = FromReflect(reflect.TypeFor[abi.InterfaceSwitch]())
    68  	TypeAssert = FromReflect(reflect.TypeFor[abi.TypeAssert]())
    69  
    70  	ITab = FromReflect(reflect.TypeFor[abi.ITab]())
    71  
    72  	// Make sure abi functions are correct. These functions are used
    73  	// by the linker which doesn't have the ability to do type layout,
    74  	// so we check the functions it uses here.
    75  	ptrSize := types.PtrSize
    76  	if got, want := int64(abi.CommonSize(ptrSize)), Type.Size(); got != want {
    77  		base.Fatalf("abi.CommonSize() == %d, want %d", got, want)
    78  	}
    79  	if got, want := int64(abi.StructFieldSize(ptrSize)), StructField.Size(); got != want {
    80  		base.Fatalf("abi.StructFieldSize() == %d, want %d", got, want)
    81  	}
    82  	if got, want := int64(abi.UncommonSize()), UncommonType.Size(); got != want {
    83  		base.Fatalf("abi.UncommonSize() == %d, want %d", got, want)
    84  	}
    85  	if got, want := int64(abi.TFlagOff(ptrSize)), Type.OffsetOf("TFlag"); got != want {
    86  		base.Fatalf("abi.TFlagOff() == %d, want %d", got, want)
    87  	}
    88  	if got, want := int64(abi.ITabTypeOff(ptrSize)), ITab.OffsetOf("Type"); got != want {
    89  		base.Fatalf("abi.ITabTypeOff() == %d, want %d", got, want)
    90  	}
    91  	for _, test := range []struct {
    92  		kind abi.Kind
    93  		typ  *types.Type
    94  		name string
    95  	}{
    96  		{abi.Struct, StructType, "Struct"},
    97  		{abi.Pointer, PtrType, "Pointer"},
    98  		{abi.Func, FuncType, "Func"},
    99  		{abi.Slice, SliceType, "Slice"},
   100  		{abi.Array, ArrayType, "Array"},
   101  		{abi.Chan, ChanType, "Chan"},
   102  		{abi.Map, MapType, "Map"},
   103  		{abi.Interface, InterfaceType, "Interface"},
   104  	} {
   105  		if got, want := int64(abi.RTypeSize(test.kind, ptrSize)), test.typ.Size(); got != want {
   106  			base.Fatalf("abi.RTypeSize(%s) == %d, want %d", test.name, got, want)
   107  		}
   108  	}
   109  }
   110  
   111  // FromReflect translates from a host type to the equivalent target type.
   112  func FromReflect(rt reflect.Type) *types.Type {
   113  	t := reflectToType(rt)
   114  	types.CalcSize(t)
   115  	return t
   116  }
   117  
   118  // reflectToType converts from a reflect.Type (which is a compiler
   119  // host type) to a *types.Type, which is a target type.  The result
   120  // must be CalcSize'd before using.
   121  func reflectToType(rt reflect.Type) *types.Type {
   122  	switch rt.Kind() {
   123  	case reflect.Bool:
   124  		return types.Types[types.TBOOL]
   125  	case reflect.Int:
   126  		return types.Types[types.TINT]
   127  	case reflect.Int8:
   128  		return types.Types[types.TINT8]
   129  	case reflect.Int16:
   130  		return types.Types[types.TINT16]
   131  	case reflect.Int32:
   132  		return types.Types[types.TINT32]
   133  	case reflect.Uint8:
   134  		return types.Types[types.TUINT8]
   135  	case reflect.Uint16:
   136  		return types.Types[types.TUINT16]
   137  	case reflect.Uint32:
   138  		return types.Types[types.TUINT32]
   139  	case reflect.Float32:
   140  		return types.Types[types.TFLOAT32]
   141  	case reflect.Float64:
   142  		return types.Types[types.TFLOAT64]
   143  	case reflect.Uintptr:
   144  		return types.Types[types.TUINTPTR]
   145  	case reflect.Ptr:
   146  		return types.NewPtr(reflectToType(rt.Elem()))
   147  	case reflect.Func, reflect.UnsafePointer:
   148  		// TODO: there's no mechanism to distinguish different pointer types,
   149  		// so we treat them all as unsafe.Pointer.
   150  		return types.Types[types.TUNSAFEPTR]
   151  	case reflect.Slice:
   152  		return types.NewSlice(reflectToType(rt.Elem()))
   153  	case reflect.Array:
   154  		return types.NewArray(reflectToType(rt.Elem()), int64(rt.Len()))
   155  	case reflect.Struct:
   156  		fields := make([]*types.Field, rt.NumField())
   157  		for i := 0; i < rt.NumField(); i++ {
   158  			f := rt.Field(i)
   159  			ft := reflectToType(f.Type)
   160  			fields[i] = &types.Field{Sym: &types.Sym{Name: f.Name}, Type: ft}
   161  		}
   162  		return types.NewStruct(fields)
   163  	case reflect.Chan:
   164  		return types.NewChan(reflectToType(rt.Elem()), types.ChanDir(rt.ChanDir()))
   165  	case reflect.String:
   166  		return types.Types[types.TSTRING]
   167  	case reflect.Complex128:
   168  		return types.Types[types.TCOMPLEX128]
   169  	default:
   170  		base.Fatalf("unhandled kind %s", rt.Kind())
   171  		return nil
   172  	}
   173  }
   174  
   175  // A Cursor represents a typed location inside a static variable where we
   176  // are going to write.
   177  type Cursor struct {
   178  	lsym   *obj.LSym
   179  	offset int64
   180  	typ    *types.Type
   181  }
   182  
   183  // NewCursor returns a cursor starting at lsym+off and having type t.
   184  func NewCursor(lsym *obj.LSym, off int64, t *types.Type) Cursor {
   185  	return Cursor{lsym: lsym, offset: off, typ: t}
   186  }
   187  
   188  // WritePtr writes a pointer "target" to the component at the location specified by c.
   189  func (c Cursor) WritePtr(target *obj.LSym) {
   190  	if c.typ.Kind() != types.TUNSAFEPTR && c.typ.Kind() != types.TPTR {
   191  		base.Fatalf("can't write ptr, it has kind %s", c.typ.Kind())
   192  	}
   193  	if target == nil {
   194  		objw.Uintptr(c.lsym, int(c.offset), 0)
   195  	} else {
   196  		objw.SymPtr(c.lsym, int(c.offset), target, 0)
   197  	}
   198  }
   199  func (c Cursor) WritePtrWeak(target *obj.LSym) {
   200  	if c.typ.Kind() != types.TUINTPTR {
   201  		base.Fatalf("can't write ptr, it has kind %s", c.typ.Kind())
   202  	}
   203  	objw.SymPtrWeak(c.lsym, int(c.offset), target, 0)
   204  }
   205  func (c Cursor) WriteUintptr(val uint64) {
   206  	if c.typ.Kind() != types.TUINTPTR {
   207  		base.Fatalf("can't write uintptr, it has kind %s", c.typ.Kind())
   208  	}
   209  	objw.Uintptr(c.lsym, int(c.offset), val)
   210  }
   211  func (c Cursor) WriteUint32(val uint32) {
   212  	if c.typ.Kind() != types.TUINT32 {
   213  		base.Fatalf("can't write uint32, it has kind %s", c.typ.Kind())
   214  	}
   215  	objw.Uint32(c.lsym, int(c.offset), val)
   216  }
   217  func (c Cursor) WriteUint16(val uint16) {
   218  	if c.typ.Kind() != types.TUINT16 {
   219  		base.Fatalf("can't write uint16, it has kind %s", c.typ.Kind())
   220  	}
   221  	objw.Uint16(c.lsym, int(c.offset), val)
   222  }
   223  func (c Cursor) WriteUint8(val uint8) {
   224  	if c.typ.Kind() != types.TUINT8 {
   225  		base.Fatalf("can't write uint8, it has kind %s", c.typ.Kind())
   226  	}
   227  	objw.Uint8(c.lsym, int(c.offset), val)
   228  }
   229  func (c Cursor) WriteInt(val int64) {
   230  	if c.typ.Kind() != types.TINT {
   231  		base.Fatalf("can't write int, it has kind %s", c.typ.Kind())
   232  	}
   233  	objw.Uintptr(c.lsym, int(c.offset), uint64(val))
   234  }
   235  func (c Cursor) WriteInt32(val int32) {
   236  	if c.typ.Kind() != types.TINT32 {
   237  		base.Fatalf("can't write int32, it has kind %s", c.typ.Kind())
   238  	}
   239  	objw.Uint32(c.lsym, int(c.offset), uint32(val))
   240  }
   241  func (c Cursor) WriteBool(val bool) {
   242  	if c.typ.Kind() != types.TBOOL {
   243  		base.Fatalf("can't write bool, it has kind %s", c.typ.Kind())
   244  	}
   245  	objw.Bool(c.lsym, int(c.offset), val)
   246  }
   247  
   248  // WriteSymPtrOff writes a "pointer" to the given symbol. The symbol
   249  // is encoded as a uint32 offset from the start of the section.
   250  func (c Cursor) WriteSymPtrOff(target *obj.LSym, weak bool) {
   251  	if c.typ.Kind() != types.TINT32 && c.typ.Kind() != types.TUINT32 {
   252  		base.Fatalf("can't write SymPtr, it has kind %s", c.typ.Kind())
   253  	}
   254  	if target == nil {
   255  		objw.Uint32(c.lsym, int(c.offset), 0)
   256  	} else if weak {
   257  		objw.SymPtrWeakOff(c.lsym, int(c.offset), target)
   258  	} else {
   259  		objw.SymPtrOff(c.lsym, int(c.offset), target)
   260  	}
   261  }
   262  
   263  // WriteSlice writes a slice header to c. The pointer is target+off, the len and cap fields are given.
   264  func (c Cursor) WriteSlice(target *obj.LSym, off, len, cap int64) {
   265  	if c.typ.Kind() != types.TSLICE {
   266  		base.Fatalf("can't write slice, it has kind %s", c.typ.Kind())
   267  	}
   268  	objw.SymPtr(c.lsym, int(c.offset), target, int(off))
   269  	objw.Uintptr(c.lsym, int(c.offset)+types.PtrSize, uint64(len))
   270  	objw.Uintptr(c.lsym, int(c.offset)+2*types.PtrSize, uint64(cap))
   271  	// TODO: ability to switch len&cap. Maybe not needed here, as every caller
   272  	// passes the same thing for both?
   273  	if len != cap {
   274  		base.Fatalf("len != cap (%d != %d)", len, cap)
   275  	}
   276  }
   277  
   278  // Reloc adds a relocation from the current cursor position.
   279  // Reloc fills in Off and Siz fields. Caller should fill in the rest (Type, others).
   280  func (c Cursor) Reloc(rel obj.Reloc) {
   281  	rel.Off = int32(c.offset)
   282  	rel.Siz = uint8(c.typ.Size())
   283  	c.lsym.AddRel(base.Ctxt, rel)
   284  }
   285  
   286  // Field selects the field with the given name from the struct pointed to by c.
   287  func (c Cursor) Field(name string) Cursor {
   288  	if c.typ.Kind() != types.TSTRUCT {
   289  		base.Fatalf("can't call Field on non-struct %v", c.typ)
   290  	}
   291  	for _, f := range c.typ.Fields() {
   292  		if f.Sym.Name == name {
   293  			return Cursor{lsym: c.lsym, offset: c.offset + f.Offset, typ: f.Type}
   294  		}
   295  	}
   296  	base.Fatalf("couldn't find field %s in %v", name, c.typ)
   297  	return Cursor{}
   298  }
   299  
   300  func (c Cursor) Elem(i int64) Cursor {
   301  	if c.typ.Kind() != types.TARRAY {
   302  		base.Fatalf("can't call Elem on non-array %v", c.typ)
   303  	}
   304  	if i < 0 || i >= c.typ.NumElem() {
   305  		base.Fatalf("element access out of bounds [%d] in [0:%d]", i, c.typ.NumElem())
   306  	}
   307  	elem := c.typ.Elem()
   308  	return Cursor{lsym: c.lsym, offset: c.offset + i*elem.Size(), typ: elem}
   309  }
   310  
   311  type ArrayCursor struct {
   312  	c Cursor // cursor pointing at first element
   313  	n int    // number of elements
   314  }
   315  
   316  // NewArrayCursor returns a cursor starting at lsym+off and having n copies of type t.
   317  func NewArrayCursor(lsym *obj.LSym, off int64, t *types.Type, n int) ArrayCursor {
   318  	return ArrayCursor{
   319  		c: NewCursor(lsym, off, t),
   320  		n: n,
   321  	}
   322  }
   323  
   324  // Elem selects element i of the array pointed to by c.
   325  func (a ArrayCursor) Elem(i int) Cursor {
   326  	if i < 0 || i >= a.n {
   327  		base.Fatalf("element index %d out of range [0:%d]", i, a.n)
   328  	}
   329  	return Cursor{lsym: a.c.lsym, offset: a.c.offset + int64(i)*a.c.typ.Size(), typ: a.c.typ}
   330  }
   331  
   332  // ModifyArray converts a cursor pointing at a type [k]T to a cursor pointing
   333  // at a type [n]T.
   334  // Also returns the size delta, aka (n-k)*sizeof(T).
   335  func (c Cursor) ModifyArray(n int) (ArrayCursor, int64) {
   336  	if c.typ.Kind() != types.TARRAY {
   337  		base.Fatalf("can't call ModifyArray on non-array %v", c.typ)
   338  	}
   339  	k := c.typ.NumElem()
   340  	return ArrayCursor{c: Cursor{lsym: c.lsym, offset: c.offset, typ: c.typ.Elem()}, n: n}, (int64(n) - k) * c.typ.Elem().Size()
   341  }
   342  

View as plain text