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  func Init() {
    46  	// Note: this has to be called explicitly instead of being
    47  	// an init function so it runs after the types package has
    48  	// been properly initialized.
    49  	Type = fromReflect(reflect.TypeOf(abi.Type{}))
    50  	ArrayType = fromReflect(reflect.TypeOf(abi.ArrayType{}))
    51  	ChanType = fromReflect(reflect.TypeOf(abi.ChanType{}))
    52  	FuncType = fromReflect(reflect.TypeOf(abi.FuncType{}))
    53  	InterfaceType = fromReflect(reflect.TypeOf(abi.InterfaceType{}))
    54  	MapType = fromReflect(reflect.TypeOf(abi.MapType{}))
    55  	PtrType = fromReflect(reflect.TypeOf(abi.PtrType{}))
    56  	SliceType = fromReflect(reflect.TypeOf(abi.SliceType{}))
    57  	StructType = fromReflect(reflect.TypeOf(abi.StructType{}))
    58  
    59  	IMethod = fromReflect(reflect.TypeOf(abi.Imethod{}))
    60  	Method = fromReflect(reflect.TypeOf(abi.Method{}))
    61  	StructField = fromReflect(reflect.TypeOf(abi.StructField{}))
    62  	UncommonType = fromReflect(reflect.TypeOf(abi.UncommonType{}))
    63  
    64  	InterfaceSwitch = fromReflect(reflect.TypeOf(abi.InterfaceSwitch{}))
    65  	TypeAssert = fromReflect(reflect.TypeOf(abi.TypeAssert{}))
    66  
    67  	// Make sure abi functions are correct. These functions are used
    68  	// by the linker which doesn't have the ability to do type layout,
    69  	// so we check the functions it uses here.
    70  	ptrSize := types.PtrSize
    71  	if got, want := int64(abi.CommonSize(ptrSize)), Type.Size(); got != want {
    72  		base.Fatalf("abi.CommonSize() == %d, want %d", got, want)
    73  	}
    74  	if got, want := int64(abi.StructFieldSize(ptrSize)), StructField.Size(); got != want {
    75  		base.Fatalf("abi.StructFieldSize() == %d, want %d", got, want)
    76  	}
    77  	if got, want := int64(abi.UncommonSize()), UncommonType.Size(); got != want {
    78  		base.Fatalf("abi.UncommonSize() == %d, want %d", got, want)
    79  	}
    80  	if got, want := int64(abi.TFlagOff(ptrSize)), Type.OffsetOf("TFlag"); got != want {
    81  		base.Fatalf("abi.TFlagOff() == %d, want %d", got, want)
    82  	}
    83  }
    84  
    85  // fromReflect translates from a host type to the equivalent target type.
    86  func fromReflect(rt reflect.Type) *types.Type {
    87  	t := reflectToType(rt)
    88  	types.CalcSize(t)
    89  	return t
    90  }
    91  
    92  // reflectToType converts from a reflect.Type (which is a compiler
    93  // host type) to a *types.Type, which is a target type.  The result
    94  // must be CalcSize'd before using.
    95  func reflectToType(rt reflect.Type) *types.Type {
    96  	switch rt.Kind() {
    97  	case reflect.Bool:
    98  		return types.Types[types.TBOOL]
    99  	case reflect.Int:
   100  		return types.Types[types.TINT]
   101  	case reflect.Int32:
   102  		return types.Types[types.TINT32]
   103  	case reflect.Uint8:
   104  		return types.Types[types.TUINT8]
   105  	case reflect.Uint16:
   106  		return types.Types[types.TUINT16]
   107  	case reflect.Uint32:
   108  		return types.Types[types.TUINT32]
   109  	case reflect.Uintptr:
   110  		return types.Types[types.TUINTPTR]
   111  	case reflect.Ptr, reflect.Func, reflect.UnsafePointer:
   112  		// TODO: there's no mechanism to distinguish different pointer types,
   113  		// so we treat them all as unsafe.Pointer.
   114  		return types.Types[types.TUNSAFEPTR]
   115  	case reflect.Slice:
   116  		return types.NewSlice(reflectToType(rt.Elem()))
   117  	case reflect.Array:
   118  		return types.NewArray(reflectToType(rt.Elem()), int64(rt.Len()))
   119  	case reflect.Struct:
   120  		fields := make([]*types.Field, rt.NumField())
   121  		for i := 0; i < rt.NumField(); i++ {
   122  			f := rt.Field(i)
   123  			ft := reflectToType(f.Type)
   124  			fields[i] = &types.Field{Sym: &types.Sym{Name: f.Name}, Type: ft}
   125  		}
   126  		return types.NewStruct(fields)
   127  	default:
   128  		base.Fatalf("unhandled kind %s", rt.Kind())
   129  		return nil
   130  	}
   131  }
   132  
   133  // A Cursor represents a typed location inside a static variable where we
   134  // are going to write.
   135  type Cursor struct {
   136  	lsym   *obj.LSym
   137  	offset int64
   138  	typ    *types.Type
   139  }
   140  
   141  // NewCursor returns a cursor starting at lsym+off and having type t.
   142  func NewCursor(lsym *obj.LSym, off int64, t *types.Type) Cursor {
   143  	return Cursor{lsym: lsym, offset: off, typ: t}
   144  }
   145  
   146  // WritePtr writes a pointer "target" to the component at the location specified by c.
   147  func (c Cursor) WritePtr(target *obj.LSym) {
   148  	if c.typ.Kind() != types.TUNSAFEPTR {
   149  		base.Fatalf("can't write ptr, it has kind %s", c.typ.Kind())
   150  	}
   151  	if target == nil {
   152  		objw.Uintptr(c.lsym, int(c.offset), 0)
   153  	} else {
   154  		objw.SymPtr(c.lsym, int(c.offset), target, 0)
   155  	}
   156  }
   157  func (c Cursor) WriteUintptr(val uint64) {
   158  	if c.typ.Kind() != types.TUINTPTR {
   159  		base.Fatalf("can't write uintptr, it has kind %s", c.typ.Kind())
   160  	}
   161  	objw.Uintptr(c.lsym, int(c.offset), val)
   162  }
   163  func (c Cursor) WriteUint32(val uint32) {
   164  	if c.typ.Kind() != types.TUINT32 {
   165  		base.Fatalf("can't write uint32, it has kind %s", c.typ.Kind())
   166  	}
   167  	objw.Uint32(c.lsym, int(c.offset), val)
   168  }
   169  func (c Cursor) WriteUint16(val uint16) {
   170  	if c.typ.Kind() != types.TUINT16 {
   171  		base.Fatalf("can't write uint16, it has kind %s", c.typ.Kind())
   172  	}
   173  	objw.Uint16(c.lsym, int(c.offset), val)
   174  }
   175  func (c Cursor) WriteUint8(val uint8) {
   176  	if c.typ.Kind() != types.TUINT8 {
   177  		base.Fatalf("can't write uint8, it has kind %s", c.typ.Kind())
   178  	}
   179  	objw.Uint8(c.lsym, int(c.offset), val)
   180  }
   181  func (c Cursor) WriteInt(val int64) {
   182  	if c.typ.Kind() != types.TINT {
   183  		base.Fatalf("can't write int, it has kind %s", c.typ.Kind())
   184  	}
   185  	objw.Uintptr(c.lsym, int(c.offset), uint64(val))
   186  }
   187  func (c Cursor) WriteInt32(val int32) {
   188  	if c.typ.Kind() != types.TINT32 {
   189  		base.Fatalf("can't write int32, it has kind %s", c.typ.Kind())
   190  	}
   191  	objw.Uint32(c.lsym, int(c.offset), uint32(val))
   192  }
   193  func (c Cursor) WriteBool(val bool) {
   194  	if c.typ.Kind() != types.TBOOL {
   195  		base.Fatalf("can't write bool, it has kind %s", c.typ.Kind())
   196  	}
   197  	objw.Bool(c.lsym, int(c.offset), val)
   198  }
   199  
   200  // WriteSymPtrOff writes a "pointer" to the given symbol. The symbol
   201  // is encoded as a uint32 offset from the start of the section.
   202  func (c Cursor) WriteSymPtrOff(target *obj.LSym, weak bool) {
   203  	if c.typ.Kind() != types.TINT32 && c.typ.Kind() != types.TUINT32 {
   204  		base.Fatalf("can't write SymPtr, it has kind %s", c.typ.Kind())
   205  	}
   206  	if target == nil {
   207  		objw.Uint32(c.lsym, int(c.offset), 0)
   208  	} else if weak {
   209  		objw.SymPtrWeakOff(c.lsym, int(c.offset), target)
   210  	} else {
   211  		objw.SymPtrOff(c.lsym, int(c.offset), target)
   212  	}
   213  }
   214  
   215  // WriteSlice writes a slice header to c. The pointer is target+off, the len and cap fields are given.
   216  func (c Cursor) WriteSlice(target *obj.LSym, off, len, cap int64) {
   217  	if c.typ.Kind() != types.TSLICE {
   218  		base.Fatalf("can't write slice, it has kind %s", c.typ.Kind())
   219  	}
   220  	objw.SymPtr(c.lsym, int(c.offset), target, int(off))
   221  	objw.Uintptr(c.lsym, int(c.offset)+types.PtrSize, uint64(len))
   222  	objw.Uintptr(c.lsym, int(c.offset)+2*types.PtrSize, uint64(cap))
   223  	// TODO: ability to switch len&cap. Maybe not needed here, as every caller
   224  	// passes the same thing for both?
   225  	if len != cap {
   226  		base.Fatalf("len != cap (%d != %d)", len, cap)
   227  	}
   228  }
   229  
   230  // Reloc adds a relocation from the current cursor position.
   231  // Reloc fills in Off and Siz fields. Caller should fill in the rest (Type, others).
   232  func (c Cursor) Reloc() *obj.Reloc {
   233  	r := obj.Addrel(c.lsym)
   234  	r.Off = int32(c.offset)
   235  	r.Siz = uint8(c.typ.Size())
   236  	return r
   237  }
   238  
   239  // Field selects the field with the given name from the struct pointed to by c.
   240  func (c Cursor) Field(name string) Cursor {
   241  	if c.typ.Kind() != types.TSTRUCT {
   242  		base.Fatalf("can't call Field on non-struct %v", c.typ)
   243  	}
   244  	for _, f := range c.typ.Fields() {
   245  		if f.Sym.Name == name {
   246  			return Cursor{lsym: c.lsym, offset: c.offset + f.Offset, typ: f.Type}
   247  		}
   248  	}
   249  	base.Fatalf("couldn't find field %s in %v", name, c.typ)
   250  	return Cursor{}
   251  }
   252  
   253  type ArrayCursor struct {
   254  	c Cursor // cursor pointing at first element
   255  	n int    // number of elements
   256  }
   257  
   258  // NewArrayCursor returns a cursor starting at lsym+off and having n copies of type t.
   259  func NewArrayCursor(lsym *obj.LSym, off int64, t *types.Type, n int) ArrayCursor {
   260  	return ArrayCursor{
   261  		c: NewCursor(lsym, off, t),
   262  		n: n,
   263  	}
   264  }
   265  
   266  // Elem selects element i of the array pointed to by c.
   267  func (a ArrayCursor) Elem(i int) Cursor {
   268  	if i < 0 || i >= a.n {
   269  		base.Fatalf("element index %d out of range [0:%d]", i, a.n)
   270  	}
   271  	return Cursor{lsym: a.c.lsym, offset: a.c.offset + int64(i)*a.c.typ.Size(), typ: a.c.typ}
   272  }
   273  
   274  // ModifyArray converts a cursor pointing at a type [k]T to a cursor pointing
   275  // at a type [n]T.
   276  // Also returns the size delta, aka (n-k)*sizeof(T).
   277  func (c Cursor) ModifyArray(n int) (ArrayCursor, int64) {
   278  	if c.typ.Kind() != types.TARRAY {
   279  		base.Fatalf("can't call ModifyArray on non-array %v", c.typ)
   280  	}
   281  	k := c.typ.NumElem()
   282  	return ArrayCursor{c: Cursor{lsym: c.lsym, offset: c.offset, typ: c.typ.Elem()}, n: n}, (int64(n) - k) * c.typ.Elem().Size()
   283  }
   284  

View as plain text