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. 12package rttype 13 14import ( 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. 24var Type *types.Type 25 26var ArrayType *types.Type 27var ChanType *types.Type 28var FuncType *types.Type 29var InterfaceType *types.Type 30var MapType *types.Type 31var PtrType *types.Type 32var SliceType *types.Type 33var StructType *types.Type 34 35// Types that are parts of the types above. 36var IMethod *types.Type 37var Method *types.Type 38var StructField *types.Type 39var UncommonType *types.Type 40 41// Type switches and asserts 42var InterfaceSwitch *types.Type 43var TypeAssert *types.Type 44 45// Interface tables (itabs) 46var ITab *types.Type 47 48func 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.TypeOf(abi.Type{})) 53 ArrayType = fromReflect(reflect.TypeOf(abi.ArrayType{})) 54 ChanType = fromReflect(reflect.TypeOf(abi.ChanType{})) 55 FuncType = fromReflect(reflect.TypeOf(abi.FuncType{})) 56 InterfaceType = fromReflect(reflect.TypeOf(abi.InterfaceType{})) 57 MapType = fromReflect(reflect.TypeOf(abi.MapType{})) 58 PtrType = fromReflect(reflect.TypeOf(abi.PtrType{})) 59 SliceType = fromReflect(reflect.TypeOf(abi.SliceType{})) 60 StructType = fromReflect(reflect.TypeOf(abi.StructType{})) 61 62 IMethod = fromReflect(reflect.TypeOf(abi.Imethod{})) 63 Method = fromReflect(reflect.TypeOf(abi.Method{})) 64 StructField = fromReflect(reflect.TypeOf(abi.StructField{})) 65 UncommonType = fromReflect(reflect.TypeOf(abi.UncommonType{})) 66 67 InterfaceSwitch = fromReflect(reflect.TypeOf(abi.InterfaceSwitch{})) 68 TypeAssert = fromReflect(reflect.TypeOf(abi.TypeAssert{})) 69 70 ITab = fromReflect(reflect.TypeOf(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} 92 93// fromReflect translates from a host type to the equivalent target type. 94func fromReflect(rt reflect.Type) *types.Type { 95 t := reflectToType(rt) 96 types.CalcSize(t) 97 return t 98} 99 100// reflectToType converts from a reflect.Type (which is a compiler 101// host type) to a *types.Type, which is a target type. The result 102// must be CalcSize'd before using. 103func reflectToType(rt reflect.Type) *types.Type { 104 switch rt.Kind() { 105 case reflect.Bool: 106 return types.Types[types.TBOOL] 107 case reflect.Int: 108 return types.Types[types.TINT] 109 case reflect.Int32: 110 return types.Types[types.TINT32] 111 case reflect.Uint8: 112 return types.Types[types.TUINT8] 113 case reflect.Uint16: 114 return types.Types[types.TUINT16] 115 case reflect.Uint32: 116 return types.Types[types.TUINT32] 117 case reflect.Uintptr: 118 return types.Types[types.TUINTPTR] 119 case reflect.Ptr, reflect.Func, reflect.UnsafePointer: 120 // TODO: there's no mechanism to distinguish different pointer types, 121 // so we treat them all as unsafe.Pointer. 122 return types.Types[types.TUNSAFEPTR] 123 case reflect.Slice: 124 return types.NewSlice(reflectToType(rt.Elem())) 125 case reflect.Array: 126 return types.NewArray(reflectToType(rt.Elem()), int64(rt.Len())) 127 case reflect.Struct: 128 fields := make([]*types.Field, rt.NumField()) 129 for i := 0; i < rt.NumField(); i++ { 130 f := rt.Field(i) 131 ft := reflectToType(f.Type) 132 fields[i] = &types.Field{Sym: &types.Sym{Name: f.Name}, Type: ft} 133 } 134 return types.NewStruct(fields) 135 default: 136 base.Fatalf("unhandled kind %s", rt.Kind()) 137 return nil 138 } 139} 140 141// A Cursor represents a typed location inside a static variable where we 142// are going to write. 143type Cursor struct { 144 lsym *obj.LSym 145 offset int64 146 typ *types.Type 147} 148 149// NewCursor returns a cursor starting at lsym+off and having type t. 150func NewCursor(lsym *obj.LSym, off int64, t *types.Type) Cursor { 151 return Cursor{lsym: lsym, offset: off, typ: t} 152} 153 154// WritePtr writes a pointer "target" to the component at the location specified by c. 155func (c Cursor) WritePtr(target *obj.LSym) { 156 if c.typ.Kind() != types.TUNSAFEPTR { 157 base.Fatalf("can't write ptr, it has kind %s", c.typ.Kind()) 158 } 159 if target == nil { 160 objw.Uintptr(c.lsym, int(c.offset), 0) 161 } else { 162 objw.SymPtr(c.lsym, int(c.offset), target, 0) 163 } 164} 165func (c Cursor) WritePtrWeak(target *obj.LSym) { 166 if c.typ.Kind() != types.TUINTPTR { 167 base.Fatalf("can't write ptr, it has kind %s", c.typ.Kind()) 168 } 169 objw.SymPtrWeak(c.lsym, int(c.offset), target, 0) 170} 171func (c Cursor) WriteUintptr(val uint64) { 172 if c.typ.Kind() != types.TUINTPTR { 173 base.Fatalf("can't write uintptr, it has kind %s", c.typ.Kind()) 174 } 175 objw.Uintptr(c.lsym, int(c.offset), val) 176} 177func (c Cursor) WriteUint32(val uint32) { 178 if c.typ.Kind() != types.TUINT32 { 179 base.Fatalf("can't write uint32, it has kind %s", c.typ.Kind()) 180 } 181 objw.Uint32(c.lsym, int(c.offset), val) 182} 183func (c Cursor) WriteUint16(val uint16) { 184 if c.typ.Kind() != types.TUINT16 { 185 base.Fatalf("can't write uint16, it has kind %s", c.typ.Kind()) 186 } 187 objw.Uint16(c.lsym, int(c.offset), val) 188} 189func (c Cursor) WriteUint8(val uint8) { 190 if c.typ.Kind() != types.TUINT8 { 191 base.Fatalf("can't write uint8, it has kind %s", c.typ.Kind()) 192 } 193 objw.Uint8(c.lsym, int(c.offset), val) 194} 195func (c Cursor) WriteInt(val int64) { 196 if c.typ.Kind() != types.TINT { 197 base.Fatalf("can't write int, it has kind %s", c.typ.Kind()) 198 } 199 objw.Uintptr(c.lsym, int(c.offset), uint64(val)) 200} 201func (c Cursor) WriteInt32(val int32) { 202 if c.typ.Kind() != types.TINT32 { 203 base.Fatalf("can't write int32, it has kind %s", c.typ.Kind()) 204 } 205 objw.Uint32(c.lsym, int(c.offset), uint32(val)) 206} 207func (c Cursor) WriteBool(val bool) { 208 if c.typ.Kind() != types.TBOOL { 209 base.Fatalf("can't write bool, it has kind %s", c.typ.Kind()) 210 } 211 objw.Bool(c.lsym, int(c.offset), val) 212} 213 214// WriteSymPtrOff writes a "pointer" to the given symbol. The symbol 215// is encoded as a uint32 offset from the start of the section. 216func (c Cursor) WriteSymPtrOff(target *obj.LSym, weak bool) { 217 if c.typ.Kind() != types.TINT32 && c.typ.Kind() != types.TUINT32 { 218 base.Fatalf("can't write SymPtr, it has kind %s", c.typ.Kind()) 219 } 220 if target == nil { 221 objw.Uint32(c.lsym, int(c.offset), 0) 222 } else if weak { 223 objw.SymPtrWeakOff(c.lsym, int(c.offset), target) 224 } else { 225 objw.SymPtrOff(c.lsym, int(c.offset), target) 226 } 227} 228 229// WriteSlice writes a slice header to c. The pointer is target+off, the len and cap fields are given. 230func (c Cursor) WriteSlice(target *obj.LSym, off, len, cap int64) { 231 if c.typ.Kind() != types.TSLICE { 232 base.Fatalf("can't write slice, it has kind %s", c.typ.Kind()) 233 } 234 objw.SymPtr(c.lsym, int(c.offset), target, int(off)) 235 objw.Uintptr(c.lsym, int(c.offset)+types.PtrSize, uint64(len)) 236 objw.Uintptr(c.lsym, int(c.offset)+2*types.PtrSize, uint64(cap)) 237 // TODO: ability to switch len&cap. Maybe not needed here, as every caller 238 // passes the same thing for both? 239 if len != cap { 240 base.Fatalf("len != cap (%d != %d)", len, cap) 241 } 242} 243 244// Reloc adds a relocation from the current cursor position. 245// Reloc fills in Off and Siz fields. Caller should fill in the rest (Type, others). 246func (c Cursor) Reloc() *obj.Reloc { 247 r := obj.Addrel(c.lsym) 248 r.Off = int32(c.offset) 249 r.Siz = uint8(c.typ.Size()) 250 return r 251} 252 253// Field selects the field with the given name from the struct pointed to by c. 254func (c Cursor) Field(name string) Cursor { 255 if c.typ.Kind() != types.TSTRUCT { 256 base.Fatalf("can't call Field on non-struct %v", c.typ) 257 } 258 for _, f := range c.typ.Fields() { 259 if f.Sym.Name == name { 260 return Cursor{lsym: c.lsym, offset: c.offset + f.Offset, typ: f.Type} 261 } 262 } 263 base.Fatalf("couldn't find field %s in %v", name, c.typ) 264 return Cursor{} 265} 266 267func (c Cursor) Elem(i int64) Cursor { 268 if c.typ.Kind() != types.TARRAY { 269 base.Fatalf("can't call Elem on non-array %v", c.typ) 270 } 271 if i < 0 || i >= c.typ.NumElem() { 272 base.Fatalf("element access out of bounds [%d] in [0:%d]", i, c.typ.NumElem()) 273 } 274 elem := c.typ.Elem() 275 return Cursor{lsym: c.lsym, offset: c.offset + i*elem.Size(), typ: elem} 276} 277 278type ArrayCursor struct { 279 c Cursor // cursor pointing at first element 280 n int // number of elements 281} 282 283// NewArrayCursor returns a cursor starting at lsym+off and having n copies of type t. 284func NewArrayCursor(lsym *obj.LSym, off int64, t *types.Type, n int) ArrayCursor { 285 return ArrayCursor{ 286 c: NewCursor(lsym, off, t), 287 n: n, 288 } 289} 290 291// Elem selects element i of the array pointed to by c. 292func (a ArrayCursor) Elem(i int) Cursor { 293 if i < 0 || i >= a.n { 294 base.Fatalf("element index %d out of range [0:%d]", i, a.n) 295 } 296 return Cursor{lsym: a.c.lsym, offset: a.c.offset + int64(i)*a.c.typ.Size(), typ: a.c.typ} 297} 298 299// ModifyArray converts a cursor pointing at a type [k]T to a cursor pointing 300// at a type [n]T. 301// Also returns the size delta, aka (n-k)*sizeof(T). 302func (c Cursor) ModifyArray(n int) (ArrayCursor, int64) { 303 if c.typ.Kind() != types.TARRAY { 304 base.Fatalf("can't call ModifyArray on non-array %v", c.typ) 305 } 306 k := c.typ.NumElem() 307 return ArrayCursor{c: Cursor{lsym: c.lsym, offset: c.offset, typ: c.typ.Elem()}, n: n}, (int64(n) - k) * c.typ.Elem().Size() 308} 309