"cmd/compile/internal/compare"
"cmd/compile/internal/ir"
"cmd/compile/internal/objw"
+ "cmd/compile/internal/rttype"
"cmd/compile/internal/staticdata"
"cmd/compile/internal/typebits"
"cmd/compile/internal/typecheck"
func structfieldSize() int { return abi.StructFieldSize(types.PtrSize) } // Sizeof(runtime.structfield{})
func imethodSize() int { return abi.IMethodSize(types.PtrSize) } // Sizeof(runtime.imethod{})
-func commonSize() int { return abi.CommonSize(types.PtrSize) } // Sizeof(runtime._type{})
+func commonSize() int { return int(rttype.Type.Size()) } // Sizeof(runtime._type{})
func uncommonSize(t *types.Type) int { // Sizeof(runtime.uncommontype{})
if t.Sym() == nil && len(methods(t)) == 0 {
// str nameOff
// ptrToThis typeOff
// }
- ot := 0
- ot = objw.Uintptr(lsym, ot, uint64(t.Size()))
- ot = objw.Uintptr(lsym, ot, uint64(ptrdata))
- ot = objw.Uint32(lsym, ot, types.TypeHash(t))
+ rt := rttype.Type
+ rt.WriteUintptr(lsym, "Size_", uint64(t.Size()))
+ rt.WriteUintptr(lsym, "PtrBytes", uint64(ptrdata))
+ rt.WriteUint32(lsym, "Hash", types.TypeHash(t))
var tflag abi.TFlag
if uncommonSize(t) != 0 {
// this should optimize away completely
panic("Unexpected change in size of abi.TFlag")
}
- ot = objw.Uint8(lsym, ot, uint8(tflag))
+ rt.WriteUint8(lsym, "TFlag", uint8(tflag))
// runtime (and common sense) expects alignment to be a power of two.
i := int(uint8(t.Alignment()))
if i&(i-1) != 0 {
base.Fatalf("invalid alignment %d for %v", uint8(t.Alignment()), t)
}
- ot = objw.Uint8(lsym, ot, uint8(t.Alignment())) // align
- ot = objw.Uint8(lsym, ot, uint8(t.Alignment())) // fieldAlign
+ rt.WriteUint8(lsym, "Align_", uint8(t.Alignment()))
+ rt.WriteUint8(lsym, "FieldAlign_", uint8(t.Alignment()))
i = kinds[t.Kind()]
if types.IsDirectIface(t) {
if useGCProg {
i |= objabi.KindGCProg
}
- ot = objw.Uint8(lsym, ot, uint8(i)) // kind
- if eqfunc != nil {
- ot = objw.SymPtr(lsym, ot, eqfunc, 0) // equality function
- } else {
- ot = objw.Uintptr(lsym, ot, 0) // type we can't do == with
- }
- ot = objw.SymPtr(lsym, ot, gcsym, 0) // gcdata
+ rt.WriteUint8(lsym, "Kind_", uint8(i))
+
+ rt.WritePtr(lsym, "Equal", eqfunc)
+ rt.WritePtr(lsym, "GCData", gcsym)
nsym := dname(p, "", nil, exported, false)
- ot = objw.SymPtrOff(lsym, ot, nsym) // str
- // ptrToThis
- if sptr == nil {
- ot = objw.Uint32(lsym, ot, 0)
- } else if sptrWeak {
- ot = objw.SymPtrWeakOff(lsym, ot, sptr)
- } else {
- ot = objw.SymPtrOff(lsym, ot, sptr)
- }
+ rt.WriteSymPtrOff(lsym, "Str", nsym, false)
+ rt.WriteSymPtrOff(lsym, "PtrToThis", sptr, sptrWeak)
- return ot
+ return int(rt.Size())
}
// TrackSym returns the symbol for tracking use of field/method f, assumed
--- /dev/null
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package rttype allows the compiler to share type information with
+// the runtime. The shared type information is stored in
+// internal/abi. This package translates those types from the host
+// machine on which the compiler runs to the target machine on which
+// the compiled program will run. In particular, this package handles
+// layout differences between e.g. a 64 bit compiler and 32 bit
+// target.
+package rttype
+
+import (
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/objw"
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+ "fmt"
+ "internal/abi"
+ "reflect"
+)
+
+type RuntimeType struct {
+ // A *types.Type representing a type used at runtime.
+ t *types.Type
+ // components maps from component names to their location in the type.
+ components map[string]location
+}
+
+type location struct {
+ offset int64
+ kind types.Kind // Just used for bug detection
+}
+
+// Types shared with the runtime via internal/abi.
+// TODO: add more
+var Type *RuntimeType
+
+func Init() {
+ // Note: this has to be called explicitly instead of being
+ // an init function so it runs after the types package has
+ // been properly initialized.
+ Type = fromReflect(reflect.TypeOf(abi.Type{}))
+
+ // Make sure abi functions are correct. These functions are used
+ // by the linker which doesn't have the ability to do type layout,
+ // so we check the functions it uses here.
+ ptrSize := types.PtrSize
+ if got, want := int64(abi.CommonSize(ptrSize)), Type.Size(); got != want {
+ base.Fatalf("abi.CommonSize() == %d, want %d", got, want)
+ }
+ if got, want := int64(abi.TFlagOff(ptrSize)), Type.Offset("TFlag"); got != want {
+ base.Fatalf("abi.TFlagOff() == %d, want %d", got, want)
+ }
+}
+
+// fromReflect translates from a host type to the equivalent
+// target type.
+func fromReflect(rt reflect.Type) *RuntimeType {
+ t := reflectToType(rt)
+ types.CalcSize(t)
+ return &RuntimeType{t: t, components: unpack(t)}
+}
+
+// reflectToType converts from a reflect.Type (which is a compiler
+// host type) to a *types.Type, which is a target type. The result
+// must be CalcSize'd before using.
+func reflectToType(rt reflect.Type) *types.Type {
+ switch rt.Kind() {
+ case reflect.Bool:
+ return types.Types[types.TBOOL]
+ case reflect.Int:
+ return types.Types[types.TINT]
+ case reflect.Int32:
+ return types.Types[types.TINT32]
+ case reflect.Uint8:
+ return types.Types[types.TUINT8]
+ case reflect.Uint16:
+ return types.Types[types.TUINT16]
+ case reflect.Uint32:
+ return types.Types[types.TUINT32]
+ case reflect.Uintptr:
+ return types.Types[types.TUINTPTR]
+ case reflect.Ptr, reflect.Func, reflect.UnsafePointer:
+ // TODO: there's no mechanism to distinguish different pointer types,
+ // so we treat them all as unsafe.Pointer.
+ return types.Types[types.TUNSAFEPTR]
+ case reflect.Array:
+ return types.NewArray(reflectToType(rt.Elem()), int64(rt.Len()))
+ case reflect.Struct:
+ fields := make([]*types.Field, rt.NumField())
+ for i := 0; i < rt.NumField(); i++ {
+ f := rt.Field(i)
+ ft := reflectToType(f.Type)
+ fields[i] = &types.Field{Sym: &types.Sym{Name: f.Name}, Type: ft}
+ }
+ return types.NewStruct(fields)
+ default:
+ base.Fatalf("unhandled kind %s", rt.Kind())
+ return nil
+ }
+}
+
+// Unpack generates a set of components of a *types.Type.
+// The type must have already been CalcSize'd.
+func unpack(t *types.Type) map[string]location {
+ components := map[string]location{}
+ switch t.Kind() {
+ default:
+ components[""] = location{0, t.Kind()}
+ case types.TARRAY:
+ // TODO: not used yet
+ elemSize := t.Elem().Size()
+ for name, loc := range unpack(t.Elem()) {
+ for i := int64(0); i < t.NumElem(); i++ {
+ components[fmt.Sprintf("[%d]%s", i, name)] = location{i*elemSize + loc.offset, loc.kind}
+ }
+ }
+ case types.TSTRUCT:
+ for _, f := range t.Fields() {
+ for name, loc := range unpack(f.Type) {
+ n := f.Sym.Name
+ if name != "" {
+ n += "." + name
+ }
+ components[n] = location{f.Offset + loc.offset, loc.kind}
+ }
+ }
+ }
+ return components
+}
+
+func (r *RuntimeType) Size() int64 {
+ return r.t.Size()
+}
+
+func (r *RuntimeType) Alignment() int64 {
+ return r.t.Alignment()
+}
+
+func (r *RuntimeType) Offset(name string) int64 {
+ return r.components[name].offset
+}
+
+// WritePtr writes a pointer "target" to the component named "name" in the
+// static object "lsym".
+func (r *RuntimeType) WritePtr(lsym *obj.LSym, name string, target *obj.LSym) {
+ loc := r.components[name]
+ if loc.kind != types.TUNSAFEPTR {
+ base.Fatalf("can't write ptr to field %s, it has kind %s", name, loc.kind)
+ }
+ if target == nil {
+ objw.Uintptr(lsym, int(loc.offset), 0)
+ } else {
+ objw.SymPtr(lsym, int(loc.offset), target, 0)
+ }
+}
+func (r *RuntimeType) WriteUintptr(lsym *obj.LSym, name string, val uint64) {
+ loc := r.components[name]
+ if loc.kind != types.TUINTPTR {
+ base.Fatalf("can't write uintptr to field %s, it has kind %s", name, loc.kind)
+ }
+ objw.Uintptr(lsym, int(loc.offset), val)
+}
+func (r *RuntimeType) WriteUint32(lsym *obj.LSym, name string, val uint32) {
+ loc := r.components[name]
+ if loc.kind != types.TUINT32 {
+ base.Fatalf("can't write uint32 to field %s, it has kind %s", name, loc.kind)
+ }
+ objw.Uint32(lsym, int(loc.offset), val)
+}
+func (r *RuntimeType) WriteUint8(lsym *obj.LSym, name string, val uint8) {
+ loc := r.components[name]
+ if loc.kind != types.TUINT8 {
+ base.Fatalf("can't write uint8 to field %s, it has kind %s", name, loc.kind)
+ }
+ objw.Uint8(lsym, int(loc.offset), val)
+}
+func (r *RuntimeType) WriteSymPtrOff(lsym *obj.LSym, name string, target *obj.LSym, weak bool) {
+ loc := r.components[name]
+ if loc.kind != types.TINT32 {
+ base.Fatalf("can't write SymPtr to field %s, it has kind %s", name, loc.kind)
+ }
+ if target == nil {
+ objw.Uint32(lsym, int(loc.offset), 0)
+ } else if weak {
+ objw.SymPtrWeakOff(lsym, int(loc.offset), target)
+ } else {
+ objw.SymPtrOff(lsym, int(loc.offset), target)
+ }
+}