mirror of
https://github.com/golang/go.git
synced 2025-05-05 15:43:04 +00:00
[git-generate] cd src/cmd/compile/internal : Workaround rf issue with types2 tests. rm types2/*_test.go : Rewrite uses. First a type-safe rewrite, : then a second pass to fix unnecessary conversions. rf ' ex ./abi ./escape ./gc ./liveness ./noder ./reflectdata ./ssa ./ssagen ./staticinit ./typebits ./typecheck ./walk { import "cmd/compile/internal/types" var t *types.Type t.Width -> t.Size() t.Align -> uint8(t.Alignment()) } ex ./abi ./escape ./gc ./liveness ./noder ./reflectdata ./ssa ./ssagen ./staticinit ./typebits ./typecheck ./walk { import "cmd/compile/internal/types" var t *types.Type int64(uint8(t.Alignment())) -> t.Alignment() } ' : Rename fields to lower case. ( cd types rf ' mv Type.Width Type.width mv Type.Align Type.align ' ) : Revert types2 changes. git checkout HEAD^ types2 Change-Id: I42091faece104c4ef619d9d4d50514fd48c8f029 Reviewed-on: https://go-review.googlesource.com/c/go/+/345480 Trust: Matthew Dempsky <mdempsky@google.com> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
303 lines
7.8 KiB
Go
303 lines
7.8 KiB
Go
// Copyright 2009 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 gc
|
|
|
|
import (
|
|
"cmd/compile/internal/base"
|
|
"cmd/compile/internal/ir"
|
|
"cmd/compile/internal/noder"
|
|
"cmd/compile/internal/objw"
|
|
"cmd/compile/internal/reflectdata"
|
|
"cmd/compile/internal/staticdata"
|
|
"cmd/compile/internal/typecheck"
|
|
"cmd/compile/internal/types"
|
|
"cmd/internal/archive"
|
|
"cmd/internal/bio"
|
|
"cmd/internal/obj"
|
|
"cmd/internal/objabi"
|
|
"encoding/json"
|
|
"fmt"
|
|
)
|
|
|
|
// These modes say which kind of object file to generate.
|
|
// The default use of the toolchain is to set both bits,
|
|
// generating a combined compiler+linker object, one that
|
|
// serves to describe the package to both the compiler and the linker.
|
|
// In fact the compiler and linker read nearly disjoint sections of
|
|
// that file, though, so in a distributed build setting it can be more
|
|
// efficient to split the output into two files, supplying the compiler
|
|
// object only to future compilations and the linker object only to
|
|
// future links.
|
|
//
|
|
// By default a combined object is written, but if -linkobj is specified
|
|
// on the command line then the default -o output is a compiler object
|
|
// and the -linkobj output is a linker object.
|
|
const (
|
|
modeCompilerObj = 1 << iota
|
|
modeLinkerObj
|
|
)
|
|
|
|
func dumpobj() {
|
|
if base.Flag.LinkObj == "" {
|
|
dumpobj1(base.Flag.LowerO, modeCompilerObj|modeLinkerObj)
|
|
return
|
|
}
|
|
dumpobj1(base.Flag.LowerO, modeCompilerObj)
|
|
dumpobj1(base.Flag.LinkObj, modeLinkerObj)
|
|
}
|
|
|
|
func dumpobj1(outfile string, mode int) {
|
|
bout, err := bio.Create(outfile)
|
|
if err != nil {
|
|
base.FlushErrors()
|
|
fmt.Printf("can't create %s: %v\n", outfile, err)
|
|
base.ErrorExit()
|
|
}
|
|
defer bout.Close()
|
|
bout.WriteString("!<arch>\n")
|
|
|
|
if mode&modeCompilerObj != 0 {
|
|
start := startArchiveEntry(bout)
|
|
dumpCompilerObj(bout)
|
|
finishArchiveEntry(bout, start, "__.PKGDEF")
|
|
}
|
|
if mode&modeLinkerObj != 0 {
|
|
start := startArchiveEntry(bout)
|
|
dumpLinkerObj(bout)
|
|
finishArchiveEntry(bout, start, "_go_.o")
|
|
}
|
|
}
|
|
|
|
func printObjHeader(bout *bio.Writer) {
|
|
bout.WriteString(objabi.HeaderString())
|
|
if base.Flag.BuildID != "" {
|
|
fmt.Fprintf(bout, "build id %q\n", base.Flag.BuildID)
|
|
}
|
|
if types.LocalPkg.Name == "main" {
|
|
fmt.Fprintf(bout, "main\n")
|
|
}
|
|
fmt.Fprintf(bout, "\n") // header ends with blank line
|
|
}
|
|
|
|
func startArchiveEntry(bout *bio.Writer) int64 {
|
|
var arhdr [archive.HeaderSize]byte
|
|
bout.Write(arhdr[:])
|
|
return bout.Offset()
|
|
}
|
|
|
|
func finishArchiveEntry(bout *bio.Writer, start int64, name string) {
|
|
bout.Flush()
|
|
size := bout.Offset() - start
|
|
if size&1 != 0 {
|
|
bout.WriteByte(0)
|
|
}
|
|
bout.MustSeek(start-archive.HeaderSize, 0)
|
|
|
|
var arhdr [archive.HeaderSize]byte
|
|
archive.FormatHeader(arhdr[:], name, size)
|
|
bout.Write(arhdr[:])
|
|
bout.Flush()
|
|
bout.MustSeek(start+size+(size&1), 0)
|
|
}
|
|
|
|
func dumpCompilerObj(bout *bio.Writer) {
|
|
printObjHeader(bout)
|
|
noder.WriteExports(bout)
|
|
}
|
|
|
|
func dumpdata() {
|
|
numExterns := len(typecheck.Target.Externs)
|
|
numDecls := len(typecheck.Target.Decls)
|
|
|
|
dumpglobls(typecheck.Target.Externs)
|
|
reflectdata.CollectPTabs()
|
|
numExports := len(typecheck.Target.Exports)
|
|
addsignats(typecheck.Target.Externs)
|
|
reflectdata.WriteRuntimeTypes()
|
|
reflectdata.WriteTabs()
|
|
numPTabs := reflectdata.CountPTabs()
|
|
reflectdata.WriteImportStrings()
|
|
reflectdata.WriteBasicTypes()
|
|
dumpembeds()
|
|
|
|
// Calls to WriteRuntimeTypes can generate functions,
|
|
// like method wrappers and hash and equality routines.
|
|
// Compile any generated functions, process any new resulting types, repeat.
|
|
// This can't loop forever, because there is no way to generate an infinite
|
|
// number of types in a finite amount of code.
|
|
// In the typical case, we loop 0 or 1 times.
|
|
// It was not until issue 24761 that we found any code that required a loop at all.
|
|
for {
|
|
for i := numDecls; i < len(typecheck.Target.Decls); i++ {
|
|
if n, ok := typecheck.Target.Decls[i].(*ir.Func); ok {
|
|
enqueueFunc(n)
|
|
}
|
|
}
|
|
numDecls = len(typecheck.Target.Decls)
|
|
compileFunctions()
|
|
reflectdata.WriteRuntimeTypes()
|
|
if numDecls == len(typecheck.Target.Decls) {
|
|
break
|
|
}
|
|
}
|
|
|
|
// Dump extra globals.
|
|
dumpglobls(typecheck.Target.Externs[numExterns:])
|
|
|
|
if reflectdata.ZeroSize > 0 {
|
|
zero := base.PkgLinksym("go.map", "zero", obj.ABI0)
|
|
objw.Global(zero, int32(reflectdata.ZeroSize), obj.DUPOK|obj.RODATA)
|
|
zero.Set(obj.AttrStatic, true)
|
|
}
|
|
|
|
staticdata.WriteFuncSyms()
|
|
addGCLocals()
|
|
|
|
if numExports != len(typecheck.Target.Exports) {
|
|
base.Fatalf("Target.Exports changed after compile functions loop")
|
|
}
|
|
newNumPTabs := reflectdata.CountPTabs()
|
|
if newNumPTabs != numPTabs {
|
|
base.Fatalf("ptabs changed after compile functions loop")
|
|
}
|
|
}
|
|
|
|
func dumpLinkerObj(bout *bio.Writer) {
|
|
printObjHeader(bout)
|
|
|
|
if len(typecheck.Target.CgoPragmas) != 0 {
|
|
// write empty export section; must be before cgo section
|
|
fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
|
|
fmt.Fprintf(bout, "\n$$ // cgo\n")
|
|
if err := json.NewEncoder(bout).Encode(typecheck.Target.CgoPragmas); err != nil {
|
|
base.Fatalf("serializing pragcgobuf: %v", err)
|
|
}
|
|
fmt.Fprintf(bout, "\n$$\n\n")
|
|
}
|
|
|
|
fmt.Fprintf(bout, "\n!\n")
|
|
|
|
obj.WriteObjFile(base.Ctxt, bout)
|
|
}
|
|
|
|
func dumpGlobal(n *ir.Name) {
|
|
if n.Type() == nil {
|
|
base.Fatalf("external %v nil type\n", n)
|
|
}
|
|
if n.Class == ir.PFUNC {
|
|
return
|
|
}
|
|
if n.Sym().Pkg != types.LocalPkg {
|
|
return
|
|
}
|
|
types.CalcSize(n.Type())
|
|
ggloblnod(n)
|
|
base.Ctxt.DwarfGlobal(base.Ctxt.Pkgpath, types.TypeSymName(n.Type()), n.Linksym())
|
|
}
|
|
|
|
func dumpGlobalConst(n ir.Node) {
|
|
// only export typed constants
|
|
t := n.Type()
|
|
if t == nil {
|
|
return
|
|
}
|
|
if n.Sym().Pkg != types.LocalPkg {
|
|
return
|
|
}
|
|
// only export integer constants for now
|
|
if !t.IsInteger() {
|
|
return
|
|
}
|
|
v := n.Val()
|
|
if t.IsUntyped() {
|
|
// Export untyped integers as int (if they fit).
|
|
t = types.Types[types.TINT]
|
|
if ir.ConstOverflow(v, t) {
|
|
return
|
|
}
|
|
}
|
|
base.Ctxt.DwarfIntConst(base.Ctxt.Pkgpath, n.Sym().Name, types.TypeSymName(t), ir.IntVal(t, v))
|
|
}
|
|
|
|
func dumpglobls(externs []ir.Node) {
|
|
// add globals
|
|
for _, n := range externs {
|
|
switch n.Op() {
|
|
case ir.ONAME:
|
|
dumpGlobal(n.(*ir.Name))
|
|
case ir.OLITERAL:
|
|
dumpGlobalConst(n)
|
|
}
|
|
}
|
|
}
|
|
|
|
// addGCLocals adds gcargs, gclocals, gcregs, and stack object symbols to Ctxt.Data.
|
|
//
|
|
// This is done during the sequential phase after compilation, since
|
|
// global symbols can't be declared during parallel compilation.
|
|
func addGCLocals() {
|
|
for _, s := range base.Ctxt.Text {
|
|
fn := s.Func()
|
|
if fn == nil {
|
|
continue
|
|
}
|
|
for _, gcsym := range []*obj.LSym{fn.GCArgs, fn.GCLocals} {
|
|
if gcsym != nil && !gcsym.OnList() {
|
|
objw.Global(gcsym, int32(len(gcsym.P)), obj.RODATA|obj.DUPOK)
|
|
}
|
|
}
|
|
if x := fn.StackObjects; x != nil {
|
|
attr := int16(obj.RODATA)
|
|
objw.Global(x, int32(len(x.P)), attr)
|
|
x.Set(obj.AttrStatic, true)
|
|
}
|
|
if x := fn.OpenCodedDeferInfo; x != nil {
|
|
objw.Global(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
|
|
}
|
|
if x := fn.ArgInfo; x != nil {
|
|
objw.Global(x, int32(len(x.P)), obj.RODATA|obj.DUPOK)
|
|
x.Set(obj.AttrStatic, true)
|
|
x.Set(obj.AttrContentAddressable, true)
|
|
}
|
|
}
|
|
}
|
|
|
|
func ggloblnod(nam *ir.Name) {
|
|
s := nam.Linksym()
|
|
s.Gotype = reflectdata.TypeLinksym(nam.Type())
|
|
flags := 0
|
|
if nam.Readonly() {
|
|
flags = obj.RODATA
|
|
}
|
|
if nam.Type() != nil && !nam.Type().HasPointers() {
|
|
flags |= obj.NOPTR
|
|
}
|
|
base.Ctxt.Globl(s, nam.Type().Size(), flags)
|
|
if nam.LibfuzzerExtraCounter() {
|
|
s.Type = objabi.SLIBFUZZER_EXTRA_COUNTER
|
|
}
|
|
if nam.Sym().Linkname != "" {
|
|
// Make sure linkname'd symbol is non-package. When a symbol is
|
|
// both imported and linkname'd, s.Pkg may not set to "_" in
|
|
// types.Sym.Linksym because LSym already exists. Set it here.
|
|
s.Pkg = "_"
|
|
}
|
|
}
|
|
|
|
func dumpembeds() {
|
|
for _, v := range typecheck.Target.Embeds {
|
|
staticdata.WriteEmbed(v)
|
|
}
|
|
}
|
|
|
|
func addsignats(dcls []ir.Node) {
|
|
// copy types from dcl list to signatset
|
|
for _, n := range dcls {
|
|
if n.Op() == ir.OTYPE {
|
|
reflectdata.NeedRuntimeType(n.Type())
|
|
}
|
|
}
|
|
}
|