From cb5534c1c6d80727cb38a602f3ad5ba1a8b693d5 Mon Sep 17 00:00:00 2001 From: Russ Cox Date: Sat, 12 Nov 2022 12:27:33 -0500 Subject: [PATCH] cmd/compile: do not emit a few more basic types from every compilation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We already emit types for any and func(error) string in runtime.a but unlike the other pre-emitted types, we don't then exclude them from being emitted in other packages. Fix that. Also add slices of non-func types that we already emit. Saves 0.3% of .a files in std cmd deps, computed by adding sizes from: ls -l $(go list -export -f '{{.Export}}' -deps std cmd The effect is small and not worth doing on its own. The real improvement is making “what to write always in runtime” and “what not to write in other packages” more obviously aligned. Change-Id: Ie5cb5fd7e5a3025d2776d9b4cece775fdf92d3b6 Reviewed-on: https://go-review.googlesource.com/c/go/+/450135 Reviewed-by: Keith Randall Run-TryBot: Russ Cox TryBot-Result: Gopher Robot Auto-Submit: Russ Cox Reviewed-by: Cuong Manh Le Reviewed-by: Keith Randall --- .../compile/internal/reflectdata/reflect.go | 64 ++++++++++++++----- src/cmd/link/internal/ld/dwarf.go | 3 + 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index f4996668b6..9dcc0a0e04 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -1395,6 +1395,35 @@ func WriteImportStrings() { } } +// writtenByWriteBasicTypes reports whether typ is written by WriteBasicTypes. +// WriteBasicTypes always writes pointer types; any pointer has been stripped off typ already. +func writtenByWriteBasicTypes(typ *types.Type) bool { + if typ.Sym() == nil && typ.Kind() == types.TFUNC { + f := typ.FuncType() + // func(error) string + if f.Receiver.NumFields() == 0 && f.TParams.NumFields() == 0 && + f.Params.NumFields() == 1 && f.Results.NumFields() == 1 && + f.Params.FieldType(0) == types.ErrorType && + f.Results.FieldType(0) == types.Types[types.TSTRING] { + return true + } + } + + // Now we have left the basic types plus any and error, plus slices of them. + // Strip the slice. + if typ.Sym() == nil && typ.IsSlice() { + typ = typ.Elem() + } + + // Basic types. + sym := typ.Sym() + if sym != nil && (sym.Pkg == types.BuiltinPkg || sym.Pkg == types.UnsafePkg) { + return true + } + // any or error + return (sym == nil && typ.IsEmptyInterface()) || typ == types.ErrorType +} + func WriteBasicTypes() { // do basic types if compiling package runtime. // they have to be in at least one package, @@ -1402,23 +1431,30 @@ func WriteBasicTypes() { // so this is as good as any. // another possible choice would be package main, // but using runtime means fewer copies in object files. + // The code here needs to be in sync with writtenByWriteBasicTypes above. if base.Ctxt.Pkgpath == "runtime" { + // Note: always write NewPtr(t) because NeedEmit's caller strips the pointer. + var list []*types.Type for i := types.Kind(1); i <= types.TBOOL; i++ { - writeType(types.NewPtr(types.Types[i])) + list = append(list, types.Types[i]) + } + list = append(list, + types.Types[types.TSTRING], + types.Types[types.TUNSAFEPTR], + types.AnyType, + types.ErrorType) + for _, t := range list { + writeType(types.NewPtr(t)) + writeType(types.NewPtr(types.NewSlice(t))) } - writeType(types.NewPtr(types.Types[types.TSTRING])) - writeType(types.NewPtr(types.Types[types.TUNSAFEPTR])) - writeType(types.AnyType) - // emit type structs for error and func(error) string. - // The latter is the type of an auto-generated wrapper. - writeType(types.NewPtr(types.ErrorType)) - - writeType(types.NewSignature(types.NoPkg, nil, nil, []*types.Field{ + // emit type for func(error) string, + // which is the type of an auto-generated wrapper. + writeType(types.NewPtr(types.NewSignature(types.NoPkg, nil, nil, []*types.Field{ types.NewField(base.Pos, nil, types.ErrorType), }, []*types.Field{ types.NewField(base.Pos, nil, types.Types[types.TSTRING]), - })) + }))) // add paths for runtime and main, which 6l imports implicitly. dimportpath(ir.Pkgs.Runtime) @@ -1759,6 +1795,9 @@ func NeedEmit(typ *types.Type) bool { // instantiated generic functions too. switch sym := typ.Sym(); { + case writtenByWriteBasicTypes(typ): + return base.Ctxt.Pkgpath == "runtime" + case sym == nil: // Anonymous type; possibly never seen before or ever again. // Need to emit to be safe (however, see TODO above). @@ -1768,11 +1807,6 @@ func NeedEmit(typ *types.Type) bool { // Local defined type; our responsibility. return true - case base.Ctxt.Pkgpath == "runtime" && (sym.Pkg == types.BuiltinPkg || sym.Pkg == types.UnsafePkg): - // Package runtime is responsible for including code for builtin - // types (predeclared and package unsafe). - return true - case typ.IsFullyInstantiated(): // Instantiated type; possibly instantiated with unique type arguments. // Need to emit to be safe (however, see TODO above). diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 75fabb4bd8..feea8640d6 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -539,6 +539,9 @@ func (d *dwctxt) newtype(gotype loader.Sym) *dwarf.DWDie { sn := d.ldr.SymName(gotype) name := sn[5:] // could also decode from Type.string tdata := d.ldr.Data(gotype) + if len(tdata) == 0 { + d.linkctxt.Errorf(gotype, "missing type") + } kind := decodetypeKind(d.arch, tdata) bytesize := decodetypeSize(d.arch, tdata)