2016-03-11 14:28:16 -08:00
|
|
|
// 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.
|
|
|
|
|
|
|
|
|
|
//go:generate go run mkbuiltin.go
|
|
|
|
|
|
|
|
|
|
package gc
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bufio"
|
2016-06-24 15:03:04 -07:00
|
|
|
"bytes"
|
2020-11-19 20:49:23 -05:00
|
|
|
"cmd/compile/internal/base"
|
[dev.regabi] cmd/compile: introduce cmd/compile/internal/ir [generated]
If we want to break up package gc at all, we will need to move
the compiler IR it defines into a separate package that can be
imported by packages that gc itself imports. This CL does that.
It also removes the TINT8 etc aliases so that all code is clear
about which package things are coming from.
This CL is automatically generated by the script below.
See the comments in the script for details about the changes.
[git-generate]
cd src/cmd/compile/internal/gc
rf '
# These names were never fully qualified
# when the types package was added.
# Do it now, to avoid confusion about where they live.
inline -rm \
Txxx \
TINT8 \
TUINT8 \
TINT16 \
TUINT16 \
TINT32 \
TUINT32 \
TINT64 \
TUINT64 \
TINT \
TUINT \
TUINTPTR \
TCOMPLEX64 \
TCOMPLEX128 \
TFLOAT32 \
TFLOAT64 \
TBOOL \
TPTR \
TFUNC \
TSLICE \
TARRAY \
TSTRUCT \
TCHAN \
TMAP \
TINTER \
TFORW \
TANY \
TSTRING \
TUNSAFEPTR \
TIDEAL \
TNIL \
TBLANK \
TFUNCARGS \
TCHANARGS \
NTYPE \
BADWIDTH
# esc.go and escape.go do not need to be split.
# Append esc.go onto the end of escape.go.
mv esc.go escape.go
# Pull out the type format installation from func Main,
# so it can be carried into package ir.
mv Main:/Sconv.=/-0,/TypeLinkSym/-1 InstallTypeFormats
# Names that need to be exported for use by code left in gc.
mv Isconst IsConst
mv asNode AsNode
mv asNodes AsNodes
mv asTypesNode AsTypesNode
mv basicnames BasicTypeNames
mv builtinpkg BuiltinPkg
mv consttype ConstType
mv dumplist DumpList
mv fdumplist FDumpList
mv fmtMode FmtMode
mv goopnames OpNames
mv inspect Inspect
mv inspectList InspectList
mv localpkg LocalPkg
mv nblank BlankNode
mv numImport NumImport
mv opprec OpPrec
mv origSym OrigSym
mv stmtwithinit StmtWithInit
mv dump DumpAny
mv fdump FDumpAny
mv nod Nod
mv nodl NodAt
mv newname NewName
mv newnamel NewNameAt
mv assertRepresents AssertValidTypeForConst
mv represents ValidTypeForConst
mv nodlit NewLiteral
# Types and fields that need to be exported for use by gc.
mv nowritebarrierrecCallSym SymAndPos
mv SymAndPos.lineno SymAndPos.Pos
mv SymAndPos.target SymAndPos.Sym
mv Func.lsym Func.LSym
mv Func.setWBPos Func.SetWBPos
mv Func.numReturns Func.NumReturns
mv Func.numDefers Func.NumDefers
mv Func.nwbrCalls Func.NWBRCalls
# initLSym is an algorithm left behind in gc,
# not an operation on Func itself.
mv Func.initLSym initLSym
mv nodeQueue NodeQueue
mv NodeQueue.empty NodeQueue.Empty
mv NodeQueue.popLeft NodeQueue.PopLeft
mv NodeQueue.pushRight NodeQueue.PushRight
# Many methods on Node are actually algorithms that
# would apply to any node implementation.
# Those become plain functions.
mv Node.funcname FuncName
mv Node.isBlank IsBlank
mv Node.isGoConst isGoConst
mv Node.isNil IsNil
mv Node.isParamHeapCopy isParamHeapCopy
mv Node.isParamStackCopy isParamStackCopy
mv Node.isSimpleName isSimpleName
mv Node.mayBeShared MayBeShared
mv Node.pkgFuncName PkgFuncName
mv Node.backingArrayPtrLen backingArrayPtrLen
mv Node.isterminating isTermNode
mv Node.labeledControl labeledControl
mv Nodes.isterminating isTermNodes
mv Nodes.sigerr fmtSignature
mv Node.MethodName methodExprName
mv Node.MethodFunc methodExprFunc
mv Node.IsMethod IsMethod
# Every node will need to implement RawCopy;
# Copy and SepCopy algorithms will use it.
mv Node.rawcopy Node.RawCopy
mv Node.copy Copy
mv Node.sepcopy SepCopy
# Extract Node.Format method body into func FmtNode,
# but leave method wrapper behind.
mv Node.Format:0,$ FmtNode
# Formatting helpers that will apply to all node implementations.
mv Node.Line Line
mv Node.exprfmt exprFmt
mv Node.jconv jconvFmt
mv Node.modeString modeString
mv Node.nconv nconvFmt
mv Node.nodedump nodeDumpFmt
mv Node.nodefmt nodeFmt
mv Node.stmtfmt stmtFmt
# Constant support needed for code moving to ir.
mv okforconst OKForConst
mv vconv FmtConst
mv int64Val Int64Val
mv float64Val Float64Val
mv Node.ValueInterface ConstValue
# Organize code into files.
mv LocalPkg BuiltinPkg ir.go
mv NumImport InstallTypeFormats Line fmt.go
mv syntax.go Nod NodAt NewNameAt Class Pxxx PragmaFlag Nointerface SymAndPos \
AsNode AsTypesNode BlankNode OrigSym \
Node.SliceBounds Node.SetSliceBounds Op.IsSlice3 \
IsConst Node.Int64Val Node.CanInt64 Node.Uint64Val Node.BoolVal Node.StringVal \
Node.RawCopy SepCopy Copy \
IsNil IsBlank IsMethod \
Node.Typ Node.StorageClass node.go
mv ConstType ConstValue Int64Val Float64Val AssertValidTypeForConst ValidTypeForConst NewLiteral idealType OKForConst val.go
# Move files to new ir package.
mv bitset.go class_string.go dump.go fmt.go \
ir.go node.go op_string.go val.go \
sizeof_test.go cmd/compile/internal/ir
'
: # fix mkbuiltin.go to generate the changes made to builtin.go during rf
sed -i '' '
s/\[T/[types.T/g
s/\*Node/*ir.Node/g
/internal\/types/c \
fmt.Fprintln(&b, `import (`) \
fmt.Fprintln(&b, ` "cmd/compile/internal/ir"`) \
fmt.Fprintln(&b, ` "cmd/compile/internal/types"`) \
fmt.Fprintln(&b, `)`)
' mkbuiltin.go
gofmt -w mkbuiltin.go
: # update cmd/dist to add internal/ir
cd ../../../dist
sed -i '' '/compile.internal.gc/a\
"cmd/compile/internal/ir",
' buildtool.go
gofmt -w buildtool.go
: # update cmd/compile TestFormats
cd ../..
go install std cmd
cd cmd/compile
go test -u || go test # first one updates but fails; second passes
Change-Id: I5f7caf6b20629b51970279e81231a3574d5b51db
Reviewed-on: https://go-review.googlesource.com/c/go/+/273008
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2020-11-19 21:09:22 -05:00
|
|
|
"cmd/compile/internal/ir"
|
cmd/compile: add framework for logging optimizer (non)actions to LSP
This is intended to allow IDEs to note where the optimizer
was not able to improve users' code. There may be other
applications for this, for example in studying effectiveness
of optimizer changes more quickly than running benchmarks,
or in verifying that code changes did not accidentally disable
optimizations in performance-critical code.
Logging of nilcheck (bad) for amd64 is implemented as
proof-of-concept. In general, the intent is that optimizations
that didn't happen are what will be logged, because that is
believed to be what IDE users want.
Added flag -json=version,dest
Check that version=0. (Future compilers will support a
few recent versions, I hope that version is always <=3.)
Dest is expected to be one of:
/path (or \path in Windows)
will create directory /path and fill it w/ json files
file://path
will create directory path, intended either for
I:\dont\know\enough\about\windows\paths
trustme_I_know_what_I_am_doing_probably_testing
Not passing an absolute path name usually leads to
json splattered all over source directories,
or failure when those directories are not writeable.
If you want a foot-gun, you have to ask for it.
The JSON output is directed to subdirectories of dest,
where each subdirectory is net/url.PathEscape of the
package name, and each for each foo.go in the package,
net/url.PathEscape(foo).json is created. The first line
of foo.json contains version and context information,
and subsequent lines contains LSP-conforming JSON
describing the missing optimizations.
Change-Id: Ib83176a53a8c177ee9081aefc5ae05604ccad8a0
Reviewed-on: https://go-review.googlesource.com/c/go/+/204338
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2019-10-24 13:48:17 -04:00
|
|
|
"cmd/compile/internal/logopt"
|
2020-11-16 01:44:47 -05:00
|
|
|
"cmd/compile/internal/ssa"
|
cmd/compile: factor out Pkg, Sym, and Type into package types
- created new package cmd/compile/internal/types
- moved Pkg, Sym, Type to new package
- to break cycles, for now we need the (ugly) types/utils.go
file which contains a handful of functions that must be installed
early by the gc frontend
- to break cycles, for now we need two functions to convert between
*gc.Node and *types.Node (the latter is a dummy type)
- adjusted the gc's code to use the new package and the conversion
functions as needed
- made several Pkg, Sym, and Type methods functions as needed
- renamed constructors typ, typPtr, typArray, etc. to types.New,
types.NewPtr, types.NewArray, etc.
Passes toolstash-check -all.
Change-Id: I8adfa5e85c731645d0a7fd2030375ed6ebf54b72
Reviewed-on: https://go-review.googlesource.com/39855
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-04-04 17:54:02 -07:00
|
|
|
"cmd/compile/internal/types"
|
2018-04-17 14:59:13 -07:00
|
|
|
"cmd/internal/bio"
|
2017-10-17 17:09:54 -04:00
|
|
|
"cmd/internal/dwarf"
|
2020-08-02 19:36:28 -04:00
|
|
|
"cmd/internal/goobj"
|
2016-03-11 14:28:16 -08:00
|
|
|
"cmd/internal/obj"
|
2017-04-18 12:53:25 -07:00
|
|
|
"cmd/internal/objabi"
|
2016-12-06 17:08:06 -08:00
|
|
|
"cmd/internal/src"
|
2016-03-11 14:28:16 -08:00
|
|
|
"flag"
|
|
|
|
|
"fmt"
|
2020-11-13 23:36:48 -08:00
|
|
|
"go/constant"
|
2019-04-19 16:09:17 +00:00
|
|
|
"internal/goversion"
|
2016-03-11 14:28:16 -08:00
|
|
|
"io"
|
2017-05-31 11:19:54 -04:00
|
|
|
"io/ioutil"
|
2016-03-11 14:28:16 -08:00
|
|
|
"log"
|
|
|
|
|
"os"
|
|
|
|
|
"path"
|
2018-10-24 15:49:32 -07:00
|
|
|
"regexp"
|
2016-03-21 14:37:57 +11:00
|
|
|
"runtime"
|
2019-04-30 15:23:14 -04:00
|
|
|
"sort"
|
2016-03-11 14:28:16 -08:00
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func hidePanic() {
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Debug.Panic == 0 && base.Errors() > 0 {
|
2016-03-11 14:28:16 -08:00
|
|
|
// If we've already complained about things
|
|
|
|
|
// in the program, don't bother complaining
|
|
|
|
|
// about a panic too; let the user clean up
|
|
|
|
|
// the code and try again.
|
|
|
|
|
if err := recover(); err != nil {
|
2020-11-30 09:34:34 -05:00
|
|
|
if err == "-h" {
|
|
|
|
|
panic(err)
|
|
|
|
|
}
|
2020-11-19 20:49:23 -05:00
|
|
|
base.ErrorExit()
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-21 01:29:02 -05:00
|
|
|
// Target is the package being compiled.
|
|
|
|
|
var Target *ir.Package
|
|
|
|
|
|
2016-06-24 15:03:04 -07:00
|
|
|
// timing data for compiler phases
|
|
|
|
|
var timings Timings
|
|
|
|
|
|
cmd/compile: improve coverage of nowritebarrierrec check
The current go:nowritebarrierrec checker has two problems that limit
its coverage:
1. It doesn't understand that systemstack calls its argument, which
means there are several cases where we fail to detect prohibited write
barriers.
2. It only observes calls in the AST, so calls constructed during
lowering by SSA aren't followed.
This CL completely rewrites this checker to address these issues.
The current checker runs entirely after walk and uses visitBottomUp,
which introduces several problems for checking across systemstack.
First, visitBottomUp itself doesn't understand systemstack calls, so
the callee may be ordered after the caller, causing the checker to
fail to propagate constraints. Second, many systemstack calls are
passed a closure, which is quite difficult to resolve back to the
function definition after transformclosure and walk have run. Third,
visitBottomUp works exclusively on the AST, so it can't observe calls
created by SSA.
To address these problems, this commit splits the check into two
phases and rewrites it to use a call graph generated during SSA
lowering. The first phase runs before transformclosure/walk and simply
records systemstack arguments when they're easy to get. Then, it
modifies genssa to record static call edges at the point where we're
lowering to Progs (which is the latest point at which position
information is conveniently available). Finally, the second phase runs
after all functions have been lowered and uses a direct BFS walk of
the call graph (combining systemstack calls with static calls) to find
prohibited write barriers and construct nice error messages.
Fixes #22384.
For #22460.
Change-Id: I39668f7f2366ab3c1ab1a71eaf25484d25349540
Reviewed-on: https://go-review.googlesource.com/72773
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-10-22 16:36:27 -04:00
|
|
|
var nowritebarrierrecCheck *nowritebarrierrecChecker
|
|
|
|
|
|
2016-11-11 16:56:07 -08:00
|
|
|
// Main parses flags and Go source files specified in the command-line
|
|
|
|
|
// arguments, type-checks the parsed Go package, compiles functions to machine
|
|
|
|
|
// code, and finally writes the compiled package definition to disk.
|
2017-03-17 13:35:31 -07:00
|
|
|
func Main(archInit func(*Arch)) {
|
2016-06-24 15:03:04 -07:00
|
|
|
timings.Start("fe", "init")
|
|
|
|
|
|
2016-03-11 14:28:16 -08:00
|
|
|
defer hidePanic()
|
|
|
|
|
|
2017-03-17 13:35:36 -07:00
|
|
|
archInit(&thearch)
|
2017-03-17 13:35:31 -07:00
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Ctxt = obj.Linknew(thearch.LinkArch)
|
|
|
|
|
base.Ctxt.DiagFunc = base.Errorf
|
|
|
|
|
base.Ctxt.DiagFlush = base.FlushErrors
|
|
|
|
|
base.Ctxt.Bso = bufio.NewWriter(os.Stdout)
|
2016-03-11 14:28:16 -08:00
|
|
|
|
2019-04-02 17:26:49 -04:00
|
|
|
// UseBASEntries is preferred because it shaves about 2% off build time, but LLDB, dsymutil, and dwarfdump
|
|
|
|
|
// on Darwin don't support it properly, especially since macOS 10.14 (Mojave). This is exposed as a flag
|
|
|
|
|
// to allow testing with LLVM tools on Linux, and to help with reporting this bug to the LLVM project.
|
|
|
|
|
// See bugs 31188 and 21945 (CLs 170638, 98075, 72371).
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Ctxt.UseBASEntries = base.Ctxt.Headtype != objabi.Hdarwin
|
2019-04-02 17:26:49 -04:00
|
|
|
|
2020-12-06 13:54:50 -05:00
|
|
|
types.LocalPkg = types.NewPkg("", "")
|
|
|
|
|
types.LocalPkg.Prefix = "\"\""
|
2016-03-11 14:28:16 -08:00
|
|
|
|
2018-04-05 14:29:32 -07:00
|
|
|
// We won't know localpkg's height until after import
|
|
|
|
|
// processing. In the mean time, set to MaxPkgHeight to ensure
|
|
|
|
|
// height comparisons at least work until then.
|
2020-12-06 13:54:50 -05:00
|
|
|
types.LocalPkg.Height = types.MaxPkgHeight
|
2018-04-05 14:29:32 -07:00
|
|
|
|
2016-03-11 14:28:16 -08:00
|
|
|
// pseudo-package, for scoping
|
2020-12-06 13:54:50 -05:00
|
|
|
types.BuiltinPkg = types.NewPkg("go.builtin", "") // TODO(gri) name this package go.builtin?
|
|
|
|
|
types.BuiltinPkg.Prefix = "go.builtin" // not go%2ebuiltin
|
2016-03-11 14:28:16 -08:00
|
|
|
|
|
|
|
|
// pseudo-package, accessed by import "unsafe"
|
2017-04-19 10:27:19 -07:00
|
|
|
unsafepkg = types.NewPkg("unsafe", "unsafe")
|
2016-03-11 14:28:16 -08:00
|
|
|
|
2017-02-28 15:51:29 -08:00
|
|
|
// Pseudo-package that contains the compiler's builtin
|
|
|
|
|
// declarations for package runtime. These are declared in a
|
|
|
|
|
// separate package to avoid conflicts with package runtime's
|
|
|
|
|
// actual declarations, which may differ intentionally but
|
|
|
|
|
// insignificantly.
|
2017-04-19 10:27:19 -07:00
|
|
|
Runtimepkg = types.NewPkg("go.runtime", "runtime")
|
2017-02-28 15:51:29 -08:00
|
|
|
Runtimepkg.Prefix = "runtime"
|
2016-03-11 14:28:16 -08:00
|
|
|
|
|
|
|
|
// pseudo-packages used in symbol tables
|
2017-04-19 10:27:19 -07:00
|
|
|
itabpkg = types.NewPkg("go.itab", "go.itab")
|
2016-03-11 14:28:16 -08:00
|
|
|
itabpkg.Prefix = "go.itab" // not go%2eitab
|
|
|
|
|
|
2017-04-19 10:27:19 -07:00
|
|
|
itablinkpkg = types.NewPkg("go.itablink", "go.itablink")
|
2016-03-17 06:18:13 -07:00
|
|
|
itablinkpkg.Prefix = "go.itablink" // not go%2eitablink
|
|
|
|
|
|
2017-04-19 10:27:19 -07:00
|
|
|
trackpkg = types.NewPkg("go.track", "go.track")
|
2016-03-11 14:28:16 -08:00
|
|
|
trackpkg.Prefix = "go.track" // not go%2etrack
|
|
|
|
|
|
2016-04-19 08:31:04 -07:00
|
|
|
// pseudo-package used for map zero values
|
2017-04-19 10:27:19 -07:00
|
|
|
mappkg = types.NewPkg("go.map", "go.map")
|
2016-04-19 08:31:04 -07:00
|
|
|
mappkg.Prefix = "go.map"
|
|
|
|
|
|
2018-04-04 18:42:39 -07:00
|
|
|
// pseudo-package used for methods with anonymous receivers
|
|
|
|
|
gopkg = types.NewPkg("go", "")
|
|
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
base.DebugSSA = ssa.PhaseOption
|
|
|
|
|
base.ParseFlags()
|
cmd/compile: add framework for logging optimizer (non)actions to LSP
This is intended to allow IDEs to note where the optimizer
was not able to improve users' code. There may be other
applications for this, for example in studying effectiveness
of optimizer changes more quickly than running benchmarks,
or in verifying that code changes did not accidentally disable
optimizations in performance-critical code.
Logging of nilcheck (bad) for amd64 is implemented as
proof-of-concept. In general, the intent is that optimizations
that didn't happen are what will be logged, because that is
believed to be what IDE users want.
Added flag -json=version,dest
Check that version=0. (Future compilers will support a
few recent versions, I hope that version is always <=3.)
Dest is expected to be one of:
/path (or \path in Windows)
will create directory /path and fill it w/ json files
file://path
will create directory path, intended either for
I:\dont\know\enough\about\windows\paths
trustme_I_know_what_I_am_doing_probably_testing
Not passing an absolute path name usually leads to
json splattered all over source directories,
or failure when those directories are not writeable.
If you want a foot-gun, you have to ask for it.
The JSON output is directed to subdirectories of dest,
where each subdirectory is net/url.PathEscape of the
package name, and each for each foo.go in the package,
net/url.PathEscape(foo).json is created. The first line
of foo.json contains version and context information,
and subsequent lines contains LSP-conforming JSON
describing the missing optimizations.
Change-Id: Ib83176a53a8c177ee9081aefc5ae05604ccad8a0
Reviewed-on: https://go-review.googlesource.com/c/go/+/204338
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2019-10-24 13:48:17 -04:00
|
|
|
|
2020-11-16 01:15:33 -05:00
|
|
|
// Record flags that affect the build result. (And don't
|
|
|
|
|
// record flags that don't, since that would cause spurious
|
|
|
|
|
// changes in the binary.)
|
|
|
|
|
recordFlags("B", "N", "l", "msan", "race", "shared", "dynlink", "dwarflocationlists", "dwarfbasentries", "smallframes", "spectre")
|
|
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
if !enableTrace && base.Flag.LowerT {
|
2020-11-16 01:15:33 -05:00
|
|
|
log.Fatalf("compiler not built with support for -t")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Enable inlining (after recordFlags, to avoid recording the rewritten -l). For now:
|
|
|
|
|
// default: inlining on. (Flag.LowerL == 1)
|
|
|
|
|
// -l: inlining off (Flag.LowerL == 0)
|
|
|
|
|
// -l=2, -l=3: inlining on again, with extra debugging (Flag.LowerL > 1)
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.LowerL <= 1 {
|
|
|
|
|
base.Flag.LowerL = 1 - base.Flag.LowerL
|
2020-11-16 01:15:33 -05:00
|
|
|
}
|
|
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.SmallFrames {
|
2020-11-16 01:15:33 -05:00
|
|
|
maxStackVarSize = 128 * 1024
|
|
|
|
|
maxImplicitStackVarSize = 16 * 1024
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.Dwarf {
|
|
|
|
|
base.Ctxt.DebugInfo = debuginfo
|
|
|
|
|
base.Ctxt.GenAbstractFunc = genAbstractFunc
|
|
|
|
|
base.Ctxt.DwFixups = obj.NewDwarfFixupTable(base.Ctxt)
|
2020-11-16 01:15:33 -05:00
|
|
|
} else {
|
|
|
|
|
// turn off inline generation if no dwarf at all
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Flag.GenDwarfInl = 0
|
|
|
|
|
base.Ctxt.Flag_locationlists = false
|
2020-11-16 01:15:33 -05:00
|
|
|
}
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Ctxt.Flag_locationlists && len(base.Ctxt.Arch.DWARFRegisters) == 0 {
|
|
|
|
|
log.Fatalf("location lists requested but register mapping not available on %v", base.Ctxt.Arch.Name)
|
2020-11-16 01:15:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
checkLang()
|
|
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.SymABIs != "" {
|
|
|
|
|
readSymABIs(base.Flag.SymABIs, base.Ctxt.Pkgpath)
|
2020-11-16 01:15:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ispkgin(omit_pkgs) {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Flag.Race = false
|
|
|
|
|
base.Flag.MSan = false
|
2020-11-16 01:15:33 -05:00
|
|
|
}
|
|
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
thearch.LinkArch.Init(base.Ctxt)
|
2020-11-16 01:15:33 -05:00
|
|
|
startProfile()
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.Race {
|
2020-11-16 01:15:33 -05:00
|
|
|
racepkg = types.NewPkg("runtime/race", "")
|
|
|
|
|
}
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.MSan {
|
2020-11-16 01:15:33 -05:00
|
|
|
msanpkg = types.NewPkg("runtime/msan", "")
|
|
|
|
|
}
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.Race || base.Flag.MSan {
|
2020-11-16 01:15:33 -05:00
|
|
|
instrumenting = true
|
|
|
|
|
}
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.Dwarf {
|
|
|
|
|
dwarf.EnableLogging(base.Debug.DwarfInl != 0)
|
2020-11-16 01:15:33 -05:00
|
|
|
}
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Debug.SoftFloat != 0 {
|
2020-11-16 01:15:33 -05:00
|
|
|
thearch.SoftFloat = true
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.JSON != "" { // parse version,destination from json logging optimization.
|
|
|
|
|
logopt.LogJsonOption(base.Flag.JSON)
|
2020-11-16 01:15:33 -05:00
|
|
|
}
|
|
|
|
|
|
2018-07-24 13:04:35 +03:00
|
|
|
ssaDump = os.Getenv("GOSSAFUNC")
|
2020-08-31 14:29:58 -04:00
|
|
|
ssaDir = os.Getenv("GOSSADIR")
|
2018-10-16 13:03:35 +03:00
|
|
|
if ssaDump != "" {
|
|
|
|
|
if strings.HasSuffix(ssaDump, "+") {
|
|
|
|
|
ssaDump = ssaDump[:len(ssaDump)-1]
|
|
|
|
|
ssaDumpStdout = true
|
|
|
|
|
}
|
|
|
|
|
spl := strings.Split(ssaDump, ":")
|
|
|
|
|
if len(spl) > 1 {
|
|
|
|
|
ssaDump = spl[0]
|
|
|
|
|
ssaDumpCFG = spl[1]
|
|
|
|
|
}
|
2018-07-24 10:39:00 +03:00
|
|
|
}
|
2018-07-24 13:04:35 +03:00
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
trackScopes = base.Flag.Dwarf
|
2017-05-02 16:46:01 +02:00
|
|
|
|
2017-03-17 13:35:36 -07:00
|
|
|
Widthptr = thearch.LinkArch.PtrSize
|
|
|
|
|
Widthreg = thearch.LinkArch.RegSize
|
2016-03-11 14:28:16 -08:00
|
|
|
|
2020-12-21 01:29:02 -05:00
|
|
|
Target = new(ir.Package)
|
|
|
|
|
|
cmd/compile: factor out Pkg, Sym, and Type into package types
- created new package cmd/compile/internal/types
- moved Pkg, Sym, Type to new package
- to break cycles, for now we need the (ugly) types/utils.go
file which contains a handful of functions that must be installed
early by the gc frontend
- to break cycles, for now we need two functions to convert between
*gc.Node and *types.Node (the latter is a dummy type)
- adjusted the gc's code to use the new package and the conversion
functions as needed
- made several Pkg, Sym, and Type methods functions as needed
- renamed constructors typ, typPtr, typArray, etc. to types.New,
types.NewPtr, types.NewArray, etc.
Passes toolstash-check -all.
Change-Id: I8adfa5e85c731645d0a7fd2030375ed6ebf54b72
Reviewed-on: https://go-review.googlesource.com/39855
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-04-04 17:54:02 -07:00
|
|
|
// initialize types package
|
|
|
|
|
// (we need to do this to break dependencies that otherwise
|
|
|
|
|
// would lead to import cycles)
|
2020-11-24 18:09:00 -05:00
|
|
|
initializeTypesPackage()
|
2016-03-11 14:28:16 -08:00
|
|
|
|
[dev.regabi] cmd/compile: introduce cmd/compile/internal/ir [generated]
If we want to break up package gc at all, we will need to move
the compiler IR it defines into a separate package that can be
imported by packages that gc itself imports. This CL does that.
It also removes the TINT8 etc aliases so that all code is clear
about which package things are coming from.
This CL is automatically generated by the script below.
See the comments in the script for details about the changes.
[git-generate]
cd src/cmd/compile/internal/gc
rf '
# These names were never fully qualified
# when the types package was added.
# Do it now, to avoid confusion about where they live.
inline -rm \
Txxx \
TINT8 \
TUINT8 \
TINT16 \
TUINT16 \
TINT32 \
TUINT32 \
TINT64 \
TUINT64 \
TINT \
TUINT \
TUINTPTR \
TCOMPLEX64 \
TCOMPLEX128 \
TFLOAT32 \
TFLOAT64 \
TBOOL \
TPTR \
TFUNC \
TSLICE \
TARRAY \
TSTRUCT \
TCHAN \
TMAP \
TINTER \
TFORW \
TANY \
TSTRING \
TUNSAFEPTR \
TIDEAL \
TNIL \
TBLANK \
TFUNCARGS \
TCHANARGS \
NTYPE \
BADWIDTH
# esc.go and escape.go do not need to be split.
# Append esc.go onto the end of escape.go.
mv esc.go escape.go
# Pull out the type format installation from func Main,
# so it can be carried into package ir.
mv Main:/Sconv.=/-0,/TypeLinkSym/-1 InstallTypeFormats
# Names that need to be exported for use by code left in gc.
mv Isconst IsConst
mv asNode AsNode
mv asNodes AsNodes
mv asTypesNode AsTypesNode
mv basicnames BasicTypeNames
mv builtinpkg BuiltinPkg
mv consttype ConstType
mv dumplist DumpList
mv fdumplist FDumpList
mv fmtMode FmtMode
mv goopnames OpNames
mv inspect Inspect
mv inspectList InspectList
mv localpkg LocalPkg
mv nblank BlankNode
mv numImport NumImport
mv opprec OpPrec
mv origSym OrigSym
mv stmtwithinit StmtWithInit
mv dump DumpAny
mv fdump FDumpAny
mv nod Nod
mv nodl NodAt
mv newname NewName
mv newnamel NewNameAt
mv assertRepresents AssertValidTypeForConst
mv represents ValidTypeForConst
mv nodlit NewLiteral
# Types and fields that need to be exported for use by gc.
mv nowritebarrierrecCallSym SymAndPos
mv SymAndPos.lineno SymAndPos.Pos
mv SymAndPos.target SymAndPos.Sym
mv Func.lsym Func.LSym
mv Func.setWBPos Func.SetWBPos
mv Func.numReturns Func.NumReturns
mv Func.numDefers Func.NumDefers
mv Func.nwbrCalls Func.NWBRCalls
# initLSym is an algorithm left behind in gc,
# not an operation on Func itself.
mv Func.initLSym initLSym
mv nodeQueue NodeQueue
mv NodeQueue.empty NodeQueue.Empty
mv NodeQueue.popLeft NodeQueue.PopLeft
mv NodeQueue.pushRight NodeQueue.PushRight
# Many methods on Node are actually algorithms that
# would apply to any node implementation.
# Those become plain functions.
mv Node.funcname FuncName
mv Node.isBlank IsBlank
mv Node.isGoConst isGoConst
mv Node.isNil IsNil
mv Node.isParamHeapCopy isParamHeapCopy
mv Node.isParamStackCopy isParamStackCopy
mv Node.isSimpleName isSimpleName
mv Node.mayBeShared MayBeShared
mv Node.pkgFuncName PkgFuncName
mv Node.backingArrayPtrLen backingArrayPtrLen
mv Node.isterminating isTermNode
mv Node.labeledControl labeledControl
mv Nodes.isterminating isTermNodes
mv Nodes.sigerr fmtSignature
mv Node.MethodName methodExprName
mv Node.MethodFunc methodExprFunc
mv Node.IsMethod IsMethod
# Every node will need to implement RawCopy;
# Copy and SepCopy algorithms will use it.
mv Node.rawcopy Node.RawCopy
mv Node.copy Copy
mv Node.sepcopy SepCopy
# Extract Node.Format method body into func FmtNode,
# but leave method wrapper behind.
mv Node.Format:0,$ FmtNode
# Formatting helpers that will apply to all node implementations.
mv Node.Line Line
mv Node.exprfmt exprFmt
mv Node.jconv jconvFmt
mv Node.modeString modeString
mv Node.nconv nconvFmt
mv Node.nodedump nodeDumpFmt
mv Node.nodefmt nodeFmt
mv Node.stmtfmt stmtFmt
# Constant support needed for code moving to ir.
mv okforconst OKForConst
mv vconv FmtConst
mv int64Val Int64Val
mv float64Val Float64Val
mv Node.ValueInterface ConstValue
# Organize code into files.
mv LocalPkg BuiltinPkg ir.go
mv NumImport InstallTypeFormats Line fmt.go
mv syntax.go Nod NodAt NewNameAt Class Pxxx PragmaFlag Nointerface SymAndPos \
AsNode AsTypesNode BlankNode OrigSym \
Node.SliceBounds Node.SetSliceBounds Op.IsSlice3 \
IsConst Node.Int64Val Node.CanInt64 Node.Uint64Val Node.BoolVal Node.StringVal \
Node.RawCopy SepCopy Copy \
IsNil IsBlank IsMethod \
Node.Typ Node.StorageClass node.go
mv ConstType ConstValue Int64Val Float64Val AssertValidTypeForConst ValidTypeForConst NewLiteral idealType OKForConst val.go
# Move files to new ir package.
mv bitset.go class_string.go dump.go fmt.go \
ir.go node.go op_string.go val.go \
sizeof_test.go cmd/compile/internal/ir
'
: # fix mkbuiltin.go to generate the changes made to builtin.go during rf
sed -i '' '
s/\[T/[types.T/g
s/\*Node/*ir.Node/g
/internal\/types/c \
fmt.Fprintln(&b, `import (`) \
fmt.Fprintln(&b, ` "cmd/compile/internal/ir"`) \
fmt.Fprintln(&b, ` "cmd/compile/internal/types"`) \
fmt.Fprintln(&b, `)`)
' mkbuiltin.go
gofmt -w mkbuiltin.go
: # update cmd/dist to add internal/ir
cd ../../../dist
sed -i '' '/compile.internal.gc/a\
"cmd/compile/internal/ir",
' buildtool.go
gofmt -w buildtool.go
: # update cmd/compile TestFormats
cd ../..
go install std cmd
cd cmd/compile
go test -u || go test # first one updates but fails; second passes
Change-Id: I5f7caf6b20629b51970279e81231a3574d5b51db
Reviewed-on: https://go-review.googlesource.com/c/go/+/273008
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2020-11-19 21:09:22 -05:00
|
|
|
dclcontext = ir.PEXTERN
|
2016-03-11 14:28:16 -08:00
|
|
|
|
2017-03-28 13:52:14 -07:00
|
|
|
autogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
|
|
|
|
|
|
2016-06-24 15:03:04 -07:00
|
|
|
timings.Start("fe", "loadsys")
|
2016-03-11 14:28:16 -08:00
|
|
|
loadsys()
|
|
|
|
|
|
2016-06-24 15:03:04 -07:00
|
|
|
timings.Start("fe", "parse")
|
2017-01-11 15:31:48 -08:00
|
|
|
lines := parseFiles(flag.Args())
|
2016-06-24 15:03:04 -07:00
|
|
|
timings.Stop()
|
2016-12-09 17:15:05 -08:00
|
|
|
timings.AddEvent(int64(lines), "lines")
|
2016-03-11 14:28:16 -08:00
|
|
|
|
2016-03-11 15:22:21 -08:00
|
|
|
finishUniverse()
|
2016-03-11 14:28:16 -08:00
|
|
|
|
2019-02-25 13:56:18 +01:00
|
|
|
recordPackageName()
|
|
|
|
|
|
2016-03-11 14:28:16 -08:00
|
|
|
typecheckok = true
|
|
|
|
|
|
|
|
|
|
// Process top-level declarations in phases.
|
|
|
|
|
|
2018-10-29 12:35:59 -07:00
|
|
|
// Phase 1: const, type, and names and types of funcs.
|
2016-03-11 14:28:16 -08:00
|
|
|
// This will gather all the information about types
|
|
|
|
|
// and methods but doesn't depend on any of it.
|
2018-11-02 23:28:26 -07:00
|
|
|
//
|
|
|
|
|
// We also defer type alias declarations until phase 2
|
|
|
|
|
// to avoid cycles like #18640.
|
|
|
|
|
// TODO(gri) Remove this again once we have a fix for #25838.
|
2016-03-11 14:28:16 -08:00
|
|
|
|
2020-12-21 01:29:02 -05:00
|
|
|
// Don't use range--typecheck can add closures to Target.Decls.
|
2016-06-24 15:03:04 -07:00
|
|
|
timings.Start("fe", "typecheck", "top1")
|
2020-12-21 01:29:02 -05:00
|
|
|
for i := 0; i < len(Target.Decls); i++ {
|
|
|
|
|
n := Target.Decls[i]
|
2020-12-10 18:48:33 -05:00
|
|
|
if op := n.Op(); op != ir.ODCL && op != ir.OAS && op != ir.OAS2 && (op != ir.ODCLTYPE || !n.(*ir.Decl).Left().Name().Alias()) {
|
2020-12-21 01:29:02 -05:00
|
|
|
Target.Decls[i] = typecheck(n, ctxStmt)
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-29 12:35:59 -07:00
|
|
|
// Phase 2: Variable assignments.
|
2018-05-29 18:25:18 +02:00
|
|
|
// To check interface assignments, depends on phase 1.
|
|
|
|
|
|
2020-12-21 01:29:02 -05:00
|
|
|
// Don't use range--typecheck can add closures to Target.Decls.
|
2018-10-29 12:35:59 -07:00
|
|
|
timings.Start("fe", "typecheck", "top2")
|
2020-12-21 01:29:02 -05:00
|
|
|
for i := 0; i < len(Target.Decls); i++ {
|
|
|
|
|
n := Target.Decls[i]
|
2020-12-10 18:48:33 -05:00
|
|
|
if op := n.Op(); op == ir.ODCL || op == ir.OAS || op == ir.OAS2 || op == ir.ODCLTYPE && n.(*ir.Decl).Left().Name().Alias() {
|
2020-12-21 01:29:02 -05:00
|
|
|
Target.Decls[i] = typecheck(n, ctxStmt)
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Phase 3: Type check function bodies.
|
2020-12-21 01:29:02 -05:00
|
|
|
// Don't use range--typecheck can add closures to Target.Decls.
|
2016-06-24 15:03:04 -07:00
|
|
|
timings.Start("fe", "typecheck", "func")
|
|
|
|
|
var fcount int64
|
2020-12-21 01:29:02 -05:00
|
|
|
for i := 0; i < len(Target.Decls); i++ {
|
|
|
|
|
n := Target.Decls[i]
|
2020-11-22 09:59:15 -05:00
|
|
|
if n.Op() == ir.ODCLFUNC {
|
2020-11-28 07:31:18 -05:00
|
|
|
Curfn = n.(*ir.Func)
|
2016-03-11 14:28:16 -08:00
|
|
|
decldepth = 1
|
2020-11-19 20:49:23 -05:00
|
|
|
errorsBefore := base.Errors()
|
2020-11-22 09:59:15 -05:00
|
|
|
typecheckslice(Curfn.Body().Slice(), ctxStmt)
|
2016-03-11 14:28:16 -08:00
|
|
|
checkreturn(Curfn)
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Errors() > errorsBefore {
|
2020-11-22 09:59:15 -05:00
|
|
|
Curfn.PtrBody().Set(nil) // type errors; do not compile
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
2017-03-27 11:38:20 -07:00
|
|
|
// Now that we've checked whether n terminates,
|
|
|
|
|
// we can eliminate some obviously dead code.
|
|
|
|
|
deadcode(Curfn)
|
2016-06-24 15:03:04 -07:00
|
|
|
fcount++
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
}
|
2020-12-13 23:01:34 -08:00
|
|
|
|
|
|
|
|
// Phase 3.11: Check external declarations.
|
|
|
|
|
// TODO(mdempsky): This should be handled when type checking their
|
|
|
|
|
// corresponding ODCL nodes.
|
|
|
|
|
timings.Start("fe", "typecheck", "externdcls")
|
2020-12-21 01:29:02 -05:00
|
|
|
for i, n := range Target.Externs {
|
2020-12-13 23:01:34 -08:00
|
|
|
if n.Op() == ir.ONAME {
|
2020-12-21 01:29:02 -05:00
|
|
|
Target.Externs[i] = typecheck(Target.Externs[i], ctxExpr)
|
2020-12-13 23:01:34 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-13 10:35:20 -08:00
|
|
|
// Phase 3.14: With all user code type-checked, it's now safe to verify map keys
|
|
|
|
|
// and unused dot imports.
|
2017-11-01 17:38:07 -07:00
|
|
|
checkMapKeys()
|
2020-12-13 10:35:20 -08:00
|
|
|
checkDotImports()
|
2020-11-19 20:49:23 -05:00
|
|
|
base.ExitIfErrors()
|
2016-03-11 14:28:16 -08:00
|
|
|
|
2020-11-16 11:08:38 -05:00
|
|
|
timings.AddEvent(fcount, "funcs")
|
2018-06-05 10:19:03 -07:00
|
|
|
|
2020-12-21 01:29:02 -05:00
|
|
|
fninit(Target.Decls)
|
2020-09-14 12:56:37 -07:00
|
|
|
|
2016-03-11 14:28:16 -08:00
|
|
|
// Phase 4: Decide how to capture closed variables.
|
|
|
|
|
// This needs to run before escape analysis,
|
|
|
|
|
// because variables captured by value do not escape.
|
2016-06-24 15:03:04 -07:00
|
|
|
timings.Start("fe", "capturevars")
|
2020-12-21 01:29:02 -05:00
|
|
|
for _, n := range Target.Decls {
|
2020-11-22 09:59:15 -05:00
|
|
|
if n.Op() == ir.ODCLFUNC && n.Func().OClosure != nil {
|
2020-11-28 07:31:18 -05:00
|
|
|
Curfn = n.(*ir.Func)
|
|
|
|
|
capturevars(Curfn)
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
}
|
cmd/compile: don't update outer variables after capturevars is complete
When compiling concurrently, we walk all functions before compiling
any of them. Walking functions can cause variables to switch from
being non-addrtaken to addrtaken, e.g. to prepare for a runtime call.
Typechecking propagates addrtaken-ness of closure variables to
their outer variables, so that capturevars can decide whether to
pass the variable's value or a pointer to it.
When all functions are compiled immediately, as long as the containing
function is compiled prior to the closure, this propagation has no effect.
When compilation is deferred, though, in rare cases, this results in
a change in the addrtaken-ness of a variable in the outer function,
which in turn changes the compiler's output.
(This is rare because in a great many cases, a temporary has been
introduced, insulating the outer variable from modification.)
But concurrent compilation must generate identical results.
To fix this, track whether capturevars has run.
If it has, there is no need to update outer variables
when closure variables change.
Capturevars always runs before any functions are walked or compiled.
The remainder of the changes in this CL are to support the test.
In particular, -d=compilelater forces the compiler to walk all
functions before compiling any of them, despite being non-concurrent.
This is useful because -live is fundamentally incompatible with
concurrent compilation, but we want -c=1 to have no behavior changes.
Fixes #20250
Change-Id: I89bcb54268a41e8588af1ac8cc37fbef856a90c2
Reviewed-on: https://go-review.googlesource.com/42853
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
2017-05-05 15:22:59 -07:00
|
|
|
capturevarscomplete = true
|
2016-03-11 14:28:16 -08:00
|
|
|
Curfn = nil
|
2020-11-19 20:49:23 -05:00
|
|
|
base.ExitIfErrors()
|
2016-03-11 14:28:16 -08:00
|
|
|
|
|
|
|
|
// Phase 5: Inlining
|
2016-06-24 15:03:04 -07:00
|
|
|
timings.Start("fe", "inlining")
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Debug.TypecheckInl != 0 {
|
2020-10-19 11:31:10 +02:00
|
|
|
// Typecheck imported function bodies if Debug.l > 1,
|
2016-03-11 14:28:16 -08:00
|
|
|
// otherwise lazily when used or re-exported.
|
|
|
|
|
for _, n := range importlist {
|
2020-11-28 07:31:18 -05:00
|
|
|
if n.Inl != nil {
|
2016-03-11 14:28:16 -08:00
|
|
|
typecheckinl(n)
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-11-19 20:49:23 -05:00
|
|
|
base.ExitIfErrors()
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.LowerL != 0 {
|
2016-03-11 14:28:16 -08:00
|
|
|
// Find functions that can be inlined and clone them before walk expands them.
|
2020-12-21 01:29:02 -05:00
|
|
|
visitBottomUp(Target.Decls, func(list []*ir.Func, recursive bool) {
|
2020-03-31 20:24:05 -07:00
|
|
|
numfns := numNonClosures(list)
|
2016-03-23 16:35:50 +01:00
|
|
|
for _, n := range list {
|
2020-03-31 20:24:05 -07:00
|
|
|
if !recursive || numfns > 1 {
|
|
|
|
|
// We allow inlining if there is no
|
|
|
|
|
// recursion, or the recursion cycle is
|
|
|
|
|
// across more than one function.
|
2016-03-11 14:28:16 -08:00
|
|
|
caninl(n)
|
2016-05-03 17:21:32 -07:00
|
|
|
} else {
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.LowerM > 1 {
|
2020-11-28 07:31:18 -05:00
|
|
|
fmt.Printf("%v: cannot inline %v: recursive\n", ir.Line(n), n.Nname)
|
2016-05-03 17:21:32 -07:00
|
|
|
}
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
2016-05-05 11:45:27 -07:00
|
|
|
inlcalls(n)
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2020-12-21 01:29:02 -05:00
|
|
|
for _, n := range Target.Decls {
|
2020-11-22 09:59:15 -05:00
|
|
|
if n.Op() == ir.ODCLFUNC {
|
2020-11-28 07:31:18 -05:00
|
|
|
devirtualize(n.(*ir.Func))
|
2020-10-28 18:49:10 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Curfn = nil
|
|
|
|
|
|
2016-03-11 14:28:16 -08:00
|
|
|
// Phase 6: Escape analysis.
|
|
|
|
|
// Required for moving heap allocations onto stack,
|
|
|
|
|
// which in turn is required by the closure implementation,
|
|
|
|
|
// which stores the addresses of stack variables into the closure.
|
|
|
|
|
// If the closure does not escape, it needs to be on the stack
|
|
|
|
|
// or else the stack copier will not update it.
|
|
|
|
|
// Large values are also moved off stack in escape analysis;
|
|
|
|
|
// because large values may contain pointers, it must happen early.
|
2016-06-24 15:03:04 -07:00
|
|
|
timings.Start("fe", "escapes")
|
2020-12-21 01:29:02 -05:00
|
|
|
escapes(Target.Decls)
|
2016-03-11 14:28:16 -08:00
|
|
|
|
2018-10-16 12:49:17 -07:00
|
|
|
// Collect information for go:nowritebarrierrec
|
|
|
|
|
// checking. This must happen before transformclosure.
|
|
|
|
|
// We'll do the final check after write barriers are
|
|
|
|
|
// inserted.
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.CompilingRuntime {
|
2018-10-16 12:49:17 -07:00
|
|
|
nowritebarrierrecCheck = newNowritebarrierrecChecker()
|
|
|
|
|
}
|
cmd/compile: improve coverage of nowritebarrierrec check
The current go:nowritebarrierrec checker has two problems that limit
its coverage:
1. It doesn't understand that systemstack calls its argument, which
means there are several cases where we fail to detect prohibited write
barriers.
2. It only observes calls in the AST, so calls constructed during
lowering by SSA aren't followed.
This CL completely rewrites this checker to address these issues.
The current checker runs entirely after walk and uses visitBottomUp,
which introduces several problems for checking across systemstack.
First, visitBottomUp itself doesn't understand systemstack calls, so
the callee may be ordered after the caller, causing the checker to
fail to propagate constraints. Second, many systemstack calls are
passed a closure, which is quite difficult to resolve back to the
function definition after transformclosure and walk have run. Third,
visitBottomUp works exclusively on the AST, so it can't observe calls
created by SSA.
To address these problems, this commit splits the check into two
phases and rewrites it to use a call graph generated during SSA
lowering. The first phase runs before transformclosure/walk and simply
records systemstack arguments when they're easy to get. Then, it
modifies genssa to record static call edges at the point where we're
lowering to Progs (which is the latest point at which position
information is conveniently available). Finally, the second phase runs
after all functions have been lowered and uses a direct BFS walk of
the call graph (combining systemstack calls with static calls) to find
prohibited write barriers and construct nice error messages.
Fixes #22384.
For #22460.
Change-Id: I39668f7f2366ab3c1ab1a71eaf25484d25349540
Reviewed-on: https://go-review.googlesource.com/72773
Run-TryBot: Austin Clements <austin@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-10-22 16:36:27 -04:00
|
|
|
|
2018-10-16 12:49:17 -07:00
|
|
|
// Phase 7: Transform closure bodies to properly reference captured variables.
|
|
|
|
|
// This needs to happen before walk, because closures must be transformed
|
|
|
|
|
// before walk reaches a call of a closure.
|
|
|
|
|
timings.Start("fe", "xclosures")
|
2020-12-21 01:29:02 -05:00
|
|
|
for _, n := range Target.Decls {
|
2020-11-22 09:59:15 -05:00
|
|
|
if n.Op() == ir.ODCLFUNC && n.Func().OClosure != nil {
|
2020-11-28 07:31:18 -05:00
|
|
|
Curfn = n.(*ir.Func)
|
|
|
|
|
transformclosure(Curfn)
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
2018-10-16 12:49:17 -07:00
|
|
|
}
|
2016-03-11 14:28:16 -08:00
|
|
|
|
2018-10-16 12:49:17 -07:00
|
|
|
// Prepare for SSA compilation.
|
|
|
|
|
// This must be before peekitabs, because peekitabs
|
|
|
|
|
// can trigger function compilation.
|
|
|
|
|
initssaconfig()
|
|
|
|
|
|
|
|
|
|
// Just before compilation, compile itabs found on
|
|
|
|
|
// the right side of OCONVIFACE so that methods
|
|
|
|
|
// can be de-virtualized during compilation.
|
|
|
|
|
Curfn = nil
|
|
|
|
|
peekitabs()
|
2016-03-11 14:28:16 -08:00
|
|
|
|
2018-10-16 12:49:17 -07:00
|
|
|
// Phase 8: Compile top level functions.
|
2020-12-21 01:29:02 -05:00
|
|
|
// Don't use range--walk can add functions to Target.Decls.
|
2018-10-16 12:49:17 -07:00
|
|
|
timings.Start("be", "compilefuncs")
|
|
|
|
|
fcount = 0
|
2020-12-21 01:29:02 -05:00
|
|
|
for i := 0; i < len(Target.Decls); i++ {
|
|
|
|
|
n := Target.Decls[i]
|
2020-11-22 09:59:15 -05:00
|
|
|
if n.Op() == ir.ODCLFUNC {
|
2020-11-28 07:31:18 -05:00
|
|
|
funccompile(n.(*ir.Func))
|
2018-10-16 12:49:17 -07:00
|
|
|
fcount++
|
cmd/compile: add -dolinkobj flag
When set to false, the -dolinkobj flag instructs the compiler
not to generate or emit linker information.
This is handy when you need the compiler's export data,
e.g. for use with go/importer,
but you want to avoid the cost of full compilation.
This must be used with care, since the resulting
files are unusable for linking.
This CL interacts with #18369,
where adding gcflags and ldflags to buildid has been mooted.
On the one hand, adding gcflags would make safe use of this
flag easier, since if the full object files were needed,
a simple 'go install' would fix it.
On the other hand, this would mean that
'go install -gcflags=-dolinkobj=false' would rebuild the object files,
although any existing object files would probably suffice.
Change-Id: I8dc75ab5a40095c785c1a4d2260aeb63c4d10f73
Reviewed-on: https://go-review.googlesource.com/37384
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-02-22 00:05:18 -08:00
|
|
|
}
|
2018-10-16 12:49:17 -07:00
|
|
|
}
|
|
|
|
|
timings.AddEvent(fcount, "funcs")
|
2016-03-11 14:28:16 -08:00
|
|
|
|
2018-10-16 12:49:17 -07:00
|
|
|
compileFunctions()
|
cmd/compile: add initial backend concurrency support
This CL adds initial support for concurrent backend compilation.
BACKGROUND
The compiler currently consists (very roughly) of the following phases:
1. Initialization.
2. Lexing and parsing into the cmd/compile/internal/syntax AST.
3. Translation into the cmd/compile/internal/gc AST.
4. Some gc AST passes: typechecking, escape analysis, inlining,
closure handling, expression evaluation ordering (order.go),
and some lowering and optimization (walk.go).
5. Translation into the cmd/compile/internal/ssa SSA form.
6. Optimization and lowering of SSA form.
7. Translation from SSA form to assembler instructions.
8. Translation from assembler instructions to machine code.
9. Writing lots of output: machine code, DWARF symbols,
type and reflection info, export data.
Phase 2 was already concurrent as of Go 1.8.
Phase 3 is planned for eventual removal;
we hope to go straight from syntax AST to SSA.
Phases 5–8 are per-function; this CL adds support for
processing multiple functions concurrently.
The slowest phases in the compiler are 5 and 6,
so this offers the opportunity for some good speed-ups.
Unfortunately, it's not quite that straightforward.
In the current compiler, the latter parts of phase 4
(order, walk) are done function-at-a-time as needed.
Making order and walk concurrency-safe proved hard,
and they're not particularly slow, so there wasn't much reward.
To enable phases 5–8 to be done concurrently,
when concurrent backend compilation is requested,
we complete phase 4 for all functions
before starting later phases for any functions.
Also, in reality, we automatically generate new
functions in phase 9, such as method wrappers
and equality and has routines.
Those new functions then go through phases 4–8.
This CL disables concurrent backend compilation
after the first, big, user-provided batch of
functions has been compiled.
This is done to keep things simple,
and because the autogenerated functions
tend to be small, few, simple, and fast to compile.
USAGE
Concurrent backend compilation still defaults to off.
To set the number of functions that may be backend-compiled
concurrently, use the compiler flag -c.
In future work, cmd/go will automatically set -c.
Furthermore, this CL has been intentionally written
so that the c=1 path has no backend concurrency whatsoever,
not even spawning any goroutines.
This helps ensure that, should problems arise
late in the development cycle,
we can simply have cmd/go set c=1 always,
and revert to the original compiler behavior.
MUTEXES
Most of the work required to make concurrent backend
compilation safe has occurred over the past month.
This CL adds a handful of mutexes to get the rest of the way there;
they are the mutexes that I didn't see a clean way to avoid.
Some of them may still be eliminable in future work.
In no particular order:
* gc.funcsymsmu. The global funcsyms slice is populated
lazily when we need function symbols for closures.
This occurs during gc AST to SSA translation.
The function funcsym also does a package lookup,
which is a source of races on types.Pkg.Syms;
funcsymsmu also covers that package lookup.
This mutex is low priority: it adds a single global,
it is in an infrequently used code path, and it is low contention.
Since funcsyms may now be added in any order,
we must sort them to preserve reproducible builds.
* gc.largeStackFramesMu. We don't discover until after SSA compilation
that a function's stack frame is gigantic.
Recording that error happens basically never,
but it does happen concurrently.
Fix with a low priority mutex and sorting.
* obj.Link.hashmu. ctxt.hash stores the mapping from
types.Syms (compiler symbols) to obj.LSyms (linker symbols).
It is accessed fairly heavily through all the phases.
This is the only heavily contended mutex.
* gc.signatlistmu. The global signatlist map is
populated with types through several of the concurrent phases,
including notably via ngotype during DWARF generation.
It is low priority for removal.
* gc.typepkgmu. Looking up symbols in the types package
happens a fair amount during backend compilation
and DWARF generation, particularly via ngotype.
This mutex helps us to avoid a broader mutex on types.Pkg.Syms.
It has low-to-moderate contention.
* types.internedStringsmu. gc AST to SSA conversion and
some SSA work introduce new autotmps.
Those autotmps have their names interned to reduce allocations.
That interning requires protecting types.internedStrings.
The autotmp names are heavily re-used, and the mutex
overhead and contention here are low, so it is probably
a worthwhile performance optimization to keep this mutex.
TESTING
I have been testing this code locally by running
'go install -race cmd/compile'
and then doing
'go build -a -gcflags=-c=128 std cmd'
for all architectures and a variety of compiler flags.
This obviously needs to be made part of the builders,
but it is too expensive to make part of all.bash.
I have filed #19962 for this.
REPRODUCIBLE BUILDS
This version of the compiler generates reproducible builds.
Testing reproducible builds also needs automation, however,
and is also too expensive for all.bash.
This is #19961.
Also of note is that some of the compiler flags used by 'toolstash -cmp'
are currently incompatible with concurrent backend compilation.
They still work fine with c=1.
Time will tell whether this is a problem.
NEXT STEPS
* Continue to find and fix races and bugs,
using a combination of code inspection, fuzzing,
and hopefully some community experimentation.
I do not know of any outstanding races,
but there probably are some.
* Improve testing.
* Improve performance, for many values of c.
* Integrate with cmd/go and fine tune.
* Support concurrent compilation with the -race flag.
It is a sad irony that it does not yet work.
* Minor code cleanup that has been deferred during
the last month due to uncertainty about the
ultimate shape of this CL.
PERFORMANCE
Here's the buried lede, at last. :)
All benchmarks are from my 8 core 2.9 GHz Intel Core i7 darwin/amd64 laptop.
First, going from tip to this CL with c=1 has almost no impact.
name old time/op new time/op delta
Template 195ms ± 3% 194ms ± 5% ~ (p=0.370 n=30+29)
Unicode 86.6ms ± 3% 87.0ms ± 7% ~ (p=0.958 n=29+30)
GoTypes 548ms ± 3% 555ms ± 4% +1.35% (p=0.001 n=30+28)
Compiler 2.51s ± 2% 2.54s ± 2% +1.17% (p=0.000 n=28+30)
SSA 5.16s ± 3% 5.16s ± 2% ~ (p=0.910 n=30+29)
Flate 124ms ± 5% 124ms ± 4% ~ (p=0.947 n=30+30)
GoParser 146ms ± 3% 146ms ± 3% ~ (p=0.150 n=29+28)
Reflect 354ms ± 3% 352ms ± 4% ~ (p=0.096 n=29+29)
Tar 107ms ± 5% 106ms ± 3% ~ (p=0.370 n=30+29)
XML 200ms ± 4% 201ms ± 4% ~ (p=0.313 n=29+28)
[Geo mean] 332ms 333ms +0.10%
name old user-time/op new user-time/op delta
Template 227ms ± 5% 225ms ± 5% ~ (p=0.457 n=28+27)
Unicode 109ms ± 4% 109ms ± 5% ~ (p=0.758 n=29+29)
GoTypes 713ms ± 4% 721ms ± 5% ~ (p=0.051 n=30+29)
Compiler 3.36s ± 2% 3.38s ± 3% ~ (p=0.146 n=30+30)
SSA 7.46s ± 3% 7.47s ± 3% ~ (p=0.804 n=30+29)
Flate 146ms ± 7% 147ms ± 3% ~ (p=0.833 n=29+27)
GoParser 179ms ± 5% 179ms ± 5% ~ (p=0.866 n=30+30)
Reflect 431ms ± 4% 429ms ± 4% ~ (p=0.593 n=29+30)
Tar 124ms ± 5% 123ms ± 5% ~ (p=0.140 n=29+29)
XML 243ms ± 4% 242ms ± 7% ~ (p=0.404 n=29+29)
[Geo mean] 415ms 415ms +0.02%
name old obj-bytes new obj-bytes delta
Template 382k ± 0% 382k ± 0% ~ (all equal)
Unicode 203k ± 0% 203k ± 0% ~ (all equal)
GoTypes 1.18M ± 0% 1.18M ± 0% ~ (all equal)
Compiler 3.98M ± 0% 3.98M ± 0% ~ (all equal)
SSA 8.28M ± 0% 8.28M ± 0% ~ (all equal)
Flate 230k ± 0% 230k ± 0% ~ (all equal)
GoParser 287k ± 0% 287k ± 0% ~ (all equal)
Reflect 1.00M ± 0% 1.00M ± 0% ~ (all equal)
Tar 190k ± 0% 190k ± 0% ~ (all equal)
XML 416k ± 0% 416k ± 0% ~ (all equal)
[Geo mean] 660k 660k +0.00%
Comparing this CL to itself, from c=1 to c=2
improves real times 20-30%, costs 5-10% more CPU time,
and adds about 2% alloc.
The allocation increase comes from allocating more ssa.Caches.
name old time/op new time/op delta
Template 202ms ± 3% 149ms ± 3% -26.15% (p=0.000 n=49+49)
Unicode 87.4ms ± 4% 84.2ms ± 3% -3.68% (p=0.000 n=48+48)
GoTypes 560ms ± 2% 398ms ± 2% -28.96% (p=0.000 n=49+49)
Compiler 2.46s ± 3% 1.76s ± 2% -28.61% (p=0.000 n=48+46)
SSA 6.17s ± 2% 4.04s ± 1% -34.52% (p=0.000 n=49+49)
Flate 126ms ± 3% 92ms ± 2% -26.81% (p=0.000 n=49+48)
GoParser 148ms ± 4% 107ms ± 2% -27.78% (p=0.000 n=49+48)
Reflect 361ms ± 3% 281ms ± 3% -22.10% (p=0.000 n=49+49)
Tar 109ms ± 4% 86ms ± 3% -20.81% (p=0.000 n=49+47)
XML 204ms ± 3% 144ms ± 2% -29.53% (p=0.000 n=48+45)
name old user-time/op new user-time/op delta
Template 246ms ± 9% 246ms ± 4% ~ (p=0.401 n=50+48)
Unicode 109ms ± 4% 111ms ± 4% +1.47% (p=0.000 n=44+50)
GoTypes 728ms ± 3% 765ms ± 3% +5.04% (p=0.000 n=46+50)
Compiler 3.33s ± 3% 3.41s ± 2% +2.31% (p=0.000 n=49+48)
SSA 8.52s ± 2% 9.11s ± 2% +6.93% (p=0.000 n=49+47)
Flate 149ms ± 4% 161ms ± 3% +8.13% (p=0.000 n=50+47)
GoParser 181ms ± 5% 192ms ± 2% +6.40% (p=0.000 n=49+46)
Reflect 452ms ± 9% 474ms ± 2% +4.99% (p=0.000 n=50+48)
Tar 126ms ± 6% 136ms ± 4% +7.95% (p=0.000 n=50+49)
XML 247ms ± 5% 264ms ± 3% +6.94% (p=0.000 n=48+50)
name old alloc/op new alloc/op delta
Template 38.8MB ± 0% 39.3MB ± 0% +1.48% (p=0.008 n=5+5)
Unicode 29.8MB ± 0% 30.2MB ± 0% +1.19% (p=0.008 n=5+5)
GoTypes 113MB ± 0% 114MB ± 0% +0.69% (p=0.008 n=5+5)
Compiler 443MB ± 0% 447MB ± 0% +0.95% (p=0.008 n=5+5)
SSA 1.25GB ± 0% 1.26GB ± 0% +0.89% (p=0.008 n=5+5)
Flate 25.3MB ± 0% 25.9MB ± 1% +2.35% (p=0.008 n=5+5)
GoParser 31.7MB ± 0% 32.2MB ± 0% +1.59% (p=0.008 n=5+5)
Reflect 78.2MB ± 0% 78.9MB ± 0% +0.91% (p=0.008 n=5+5)
Tar 26.6MB ± 0% 27.0MB ± 0% +1.80% (p=0.008 n=5+5)
XML 42.4MB ± 0% 43.4MB ± 0% +2.35% (p=0.008 n=5+5)
name old allocs/op new allocs/op delta
Template 379k ± 0% 378k ± 0% ~ (p=0.421 n=5+5)
Unicode 322k ± 0% 321k ± 0% ~ (p=0.222 n=5+5)
GoTypes 1.14M ± 0% 1.14M ± 0% ~ (p=0.548 n=5+5)
Compiler 4.12M ± 0% 4.11M ± 0% -0.14% (p=0.032 n=5+5)
SSA 9.72M ± 0% 9.72M ± 0% ~ (p=0.421 n=5+5)
Flate 234k ± 1% 234k ± 0% ~ (p=0.421 n=5+5)
GoParser 316k ± 1% 315k ± 0% ~ (p=0.222 n=5+5)
Reflect 980k ± 0% 979k ± 0% ~ (p=0.095 n=5+5)
Tar 249k ± 1% 249k ± 1% ~ (p=0.841 n=5+5)
XML 392k ± 0% 391k ± 0% ~ (p=0.095 n=5+5)
From c=1 to c=4, real time is down ~40%, CPU usage up 10-20%, alloc up ~5%:
name old time/op new time/op delta
Template 203ms ± 3% 131ms ± 5% -35.45% (p=0.000 n=50+50)
Unicode 87.2ms ± 4% 84.1ms ± 2% -3.61% (p=0.000 n=48+47)
GoTypes 560ms ± 4% 310ms ± 2% -44.65% (p=0.000 n=50+49)
Compiler 2.47s ± 3% 1.41s ± 2% -43.10% (p=0.000 n=50+46)
SSA 6.17s ± 2% 3.20s ± 2% -48.06% (p=0.000 n=49+49)
Flate 126ms ± 4% 74ms ± 2% -41.06% (p=0.000 n=49+48)
GoParser 148ms ± 4% 89ms ± 3% -39.97% (p=0.000 n=49+50)
Reflect 360ms ± 3% 242ms ± 3% -32.81% (p=0.000 n=49+49)
Tar 108ms ± 4% 73ms ± 4% -32.48% (p=0.000 n=50+49)
XML 203ms ± 3% 119ms ± 3% -41.56% (p=0.000 n=49+48)
name old user-time/op new user-time/op delta
Template 246ms ± 9% 287ms ± 9% +16.98% (p=0.000 n=50+50)
Unicode 109ms ± 4% 118ms ± 5% +7.56% (p=0.000 n=46+50)
GoTypes 735ms ± 4% 806ms ± 2% +9.62% (p=0.000 n=50+50)
Compiler 3.34s ± 4% 3.56s ± 2% +6.78% (p=0.000 n=49+49)
SSA 8.54s ± 3% 10.04s ± 3% +17.55% (p=0.000 n=50+50)
Flate 149ms ± 6% 176ms ± 3% +17.82% (p=0.000 n=50+48)
GoParser 181ms ± 5% 213ms ± 3% +17.47% (p=0.000 n=50+50)
Reflect 453ms ± 6% 499ms ± 2% +10.11% (p=0.000 n=50+48)
Tar 126ms ± 5% 149ms ±11% +18.76% (p=0.000 n=50+50)
XML 246ms ± 5% 287ms ± 4% +16.53% (p=0.000 n=49+50)
name old alloc/op new alloc/op delta
Template 38.8MB ± 0% 40.4MB ± 0% +4.21% (p=0.008 n=5+5)
Unicode 29.8MB ± 0% 30.9MB ± 0% +3.68% (p=0.008 n=5+5)
GoTypes 113MB ± 0% 116MB ± 0% +2.71% (p=0.008 n=5+5)
Compiler 443MB ± 0% 455MB ± 0% +2.75% (p=0.008 n=5+5)
SSA 1.25GB ± 0% 1.27GB ± 0% +1.84% (p=0.008 n=5+5)
Flate 25.3MB ± 0% 26.9MB ± 1% +6.31% (p=0.008 n=5+5)
GoParser 31.7MB ± 0% 33.2MB ± 0% +4.61% (p=0.008 n=5+5)
Reflect 78.2MB ± 0% 80.2MB ± 0% +2.53% (p=0.008 n=5+5)
Tar 26.6MB ± 0% 27.9MB ± 0% +5.19% (p=0.008 n=5+5)
XML 42.4MB ± 0% 44.6MB ± 0% +5.20% (p=0.008 n=5+5)
name old allocs/op new allocs/op delta
Template 380k ± 0% 379k ± 0% -0.39% (p=0.032 n=5+5)
Unicode 321k ± 0% 321k ± 0% ~ (p=0.841 n=5+5)
GoTypes 1.14M ± 0% 1.14M ± 0% ~ (p=0.421 n=5+5)
Compiler 4.12M ± 0% 4.14M ± 0% +0.52% (p=0.008 n=5+5)
SSA 9.72M ± 0% 9.76M ± 0% +0.37% (p=0.008 n=5+5)
Flate 234k ± 1% 234k ± 1% ~ (p=0.690 n=5+5)
GoParser 316k ± 0% 317k ± 1% ~ (p=0.841 n=5+5)
Reflect 981k ± 0% 981k ± 0% ~ (p=1.000 n=5+5)
Tar 250k ± 0% 249k ± 1% ~ (p=0.151 n=5+5)
XML 393k ± 0% 392k ± 0% ~ (p=0.056 n=5+5)
Going beyond c=4 on my machine tends to increase CPU time and allocs
without impacting real time.
The CPU time numbers matter, because when there are many concurrent
compilation processes, that will impact the overall throughput.
The numbers above are in many ways the best case scenario;
we can take full advantage of all cores.
Fortunately, the most common compilation scenario is incremental
re-compilation of a single package during a build/test cycle.
Updates #15756
Change-Id: I6725558ca2069edec0ac5b0d1683105a9fff6bea
Reviewed-on: https://go-review.googlesource.com/40693
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-03-19 08:27:26 -07:00
|
|
|
|
2018-10-16 12:49:17 -07:00
|
|
|
if nowritebarrierrecCheck != nil {
|
|
|
|
|
// Write barriers are now known. Check the
|
|
|
|
|
// call graph.
|
|
|
|
|
nowritebarrierrecCheck.check()
|
|
|
|
|
nowritebarrierrecCheck = nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Finalize DWARF inline routine DIEs, then explicitly turn off
|
|
|
|
|
// DWARF inlining gen so as to avoid problems with generated
|
|
|
|
|
// method wrappers.
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Ctxt.DwFixups != nil {
|
|
|
|
|
base.Ctxt.DwFixups.Finalize(base.Ctxt.Pkgpath, base.Debug.DwarfInl != 0)
|
|
|
|
|
base.Ctxt.DwFixups = nil
|
|
|
|
|
base.Flag.GenDwarfInl = 0
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
|
2016-11-11 16:56:07 -08:00
|
|
|
// Write object data to disk.
|
2016-06-24 15:03:04 -07:00
|
|
|
timings.Start("be", "dumpobj")
|
2019-09-11 16:03:59 -04:00
|
|
|
dumpdata()
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Ctxt.NumberSyms()
|
2016-03-11 14:28:16 -08:00
|
|
|
dumpobj()
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.AsmHdr != "" {
|
2016-03-11 14:28:16 -08:00
|
|
|
dumpasmhdr()
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-29 16:44:36 -07:00
|
|
|
// Check whether any of the functions we have compiled have gigantic stack frames.
|
2019-04-30 15:23:14 -04:00
|
|
|
sort.Slice(largeStackFrames, func(i, j int) bool {
|
2018-10-25 06:23:54 -07:00
|
|
|
return largeStackFrames[i].pos.Before(largeStackFrames[j].pos)
|
2018-05-29 16:44:36 -07:00
|
|
|
})
|
2018-10-25 06:23:54 -07:00
|
|
|
for _, large := range largeStackFrames {
|
|
|
|
|
if large.callee != 0 {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.ErrorfAt(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args + %d MB callee", large.locals>>20, large.args>>20, large.callee>>20)
|
2018-10-25 06:23:54 -07:00
|
|
|
} else {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.ErrorfAt(large.pos, "stack frame too large (>1GB): %d MB locals + %d MB args", large.locals>>20, large.args>>20)
|
2018-10-25 06:23:54 -07:00
|
|
|
}
|
2018-05-29 16:44:36 -07:00
|
|
|
}
|
|
|
|
|
|
2020-09-14 12:53:36 -07:00
|
|
|
if len(funcStack) != 0 {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Fatalf("funcStack is non-empty: %v", len(funcStack))
|
2020-09-14 12:53:36 -07:00
|
|
|
}
|
cmd/compile: add initial backend concurrency support
This CL adds initial support for concurrent backend compilation.
BACKGROUND
The compiler currently consists (very roughly) of the following phases:
1. Initialization.
2. Lexing and parsing into the cmd/compile/internal/syntax AST.
3. Translation into the cmd/compile/internal/gc AST.
4. Some gc AST passes: typechecking, escape analysis, inlining,
closure handling, expression evaluation ordering (order.go),
and some lowering and optimization (walk.go).
5. Translation into the cmd/compile/internal/ssa SSA form.
6. Optimization and lowering of SSA form.
7. Translation from SSA form to assembler instructions.
8. Translation from assembler instructions to machine code.
9. Writing lots of output: machine code, DWARF symbols,
type and reflection info, export data.
Phase 2 was already concurrent as of Go 1.8.
Phase 3 is planned for eventual removal;
we hope to go straight from syntax AST to SSA.
Phases 5–8 are per-function; this CL adds support for
processing multiple functions concurrently.
The slowest phases in the compiler are 5 and 6,
so this offers the opportunity for some good speed-ups.
Unfortunately, it's not quite that straightforward.
In the current compiler, the latter parts of phase 4
(order, walk) are done function-at-a-time as needed.
Making order and walk concurrency-safe proved hard,
and they're not particularly slow, so there wasn't much reward.
To enable phases 5–8 to be done concurrently,
when concurrent backend compilation is requested,
we complete phase 4 for all functions
before starting later phases for any functions.
Also, in reality, we automatically generate new
functions in phase 9, such as method wrappers
and equality and has routines.
Those new functions then go through phases 4–8.
This CL disables concurrent backend compilation
after the first, big, user-provided batch of
functions has been compiled.
This is done to keep things simple,
and because the autogenerated functions
tend to be small, few, simple, and fast to compile.
USAGE
Concurrent backend compilation still defaults to off.
To set the number of functions that may be backend-compiled
concurrently, use the compiler flag -c.
In future work, cmd/go will automatically set -c.
Furthermore, this CL has been intentionally written
so that the c=1 path has no backend concurrency whatsoever,
not even spawning any goroutines.
This helps ensure that, should problems arise
late in the development cycle,
we can simply have cmd/go set c=1 always,
and revert to the original compiler behavior.
MUTEXES
Most of the work required to make concurrent backend
compilation safe has occurred over the past month.
This CL adds a handful of mutexes to get the rest of the way there;
they are the mutexes that I didn't see a clean way to avoid.
Some of them may still be eliminable in future work.
In no particular order:
* gc.funcsymsmu. The global funcsyms slice is populated
lazily when we need function symbols for closures.
This occurs during gc AST to SSA translation.
The function funcsym also does a package lookup,
which is a source of races on types.Pkg.Syms;
funcsymsmu also covers that package lookup.
This mutex is low priority: it adds a single global,
it is in an infrequently used code path, and it is low contention.
Since funcsyms may now be added in any order,
we must sort them to preserve reproducible builds.
* gc.largeStackFramesMu. We don't discover until after SSA compilation
that a function's stack frame is gigantic.
Recording that error happens basically never,
but it does happen concurrently.
Fix with a low priority mutex and sorting.
* obj.Link.hashmu. ctxt.hash stores the mapping from
types.Syms (compiler symbols) to obj.LSyms (linker symbols).
It is accessed fairly heavily through all the phases.
This is the only heavily contended mutex.
* gc.signatlistmu. The global signatlist map is
populated with types through several of the concurrent phases,
including notably via ngotype during DWARF generation.
It is low priority for removal.
* gc.typepkgmu. Looking up symbols in the types package
happens a fair amount during backend compilation
and DWARF generation, particularly via ngotype.
This mutex helps us to avoid a broader mutex on types.Pkg.Syms.
It has low-to-moderate contention.
* types.internedStringsmu. gc AST to SSA conversion and
some SSA work introduce new autotmps.
Those autotmps have their names interned to reduce allocations.
That interning requires protecting types.internedStrings.
The autotmp names are heavily re-used, and the mutex
overhead and contention here are low, so it is probably
a worthwhile performance optimization to keep this mutex.
TESTING
I have been testing this code locally by running
'go install -race cmd/compile'
and then doing
'go build -a -gcflags=-c=128 std cmd'
for all architectures and a variety of compiler flags.
This obviously needs to be made part of the builders,
but it is too expensive to make part of all.bash.
I have filed #19962 for this.
REPRODUCIBLE BUILDS
This version of the compiler generates reproducible builds.
Testing reproducible builds also needs automation, however,
and is also too expensive for all.bash.
This is #19961.
Also of note is that some of the compiler flags used by 'toolstash -cmp'
are currently incompatible with concurrent backend compilation.
They still work fine with c=1.
Time will tell whether this is a problem.
NEXT STEPS
* Continue to find and fix races and bugs,
using a combination of code inspection, fuzzing,
and hopefully some community experimentation.
I do not know of any outstanding races,
but there probably are some.
* Improve testing.
* Improve performance, for many values of c.
* Integrate with cmd/go and fine tune.
* Support concurrent compilation with the -race flag.
It is a sad irony that it does not yet work.
* Minor code cleanup that has been deferred during
the last month due to uncertainty about the
ultimate shape of this CL.
PERFORMANCE
Here's the buried lede, at last. :)
All benchmarks are from my 8 core 2.9 GHz Intel Core i7 darwin/amd64 laptop.
First, going from tip to this CL with c=1 has almost no impact.
name old time/op new time/op delta
Template 195ms ± 3% 194ms ± 5% ~ (p=0.370 n=30+29)
Unicode 86.6ms ± 3% 87.0ms ± 7% ~ (p=0.958 n=29+30)
GoTypes 548ms ± 3% 555ms ± 4% +1.35% (p=0.001 n=30+28)
Compiler 2.51s ± 2% 2.54s ± 2% +1.17% (p=0.000 n=28+30)
SSA 5.16s ± 3% 5.16s ± 2% ~ (p=0.910 n=30+29)
Flate 124ms ± 5% 124ms ± 4% ~ (p=0.947 n=30+30)
GoParser 146ms ± 3% 146ms ± 3% ~ (p=0.150 n=29+28)
Reflect 354ms ± 3% 352ms ± 4% ~ (p=0.096 n=29+29)
Tar 107ms ± 5% 106ms ± 3% ~ (p=0.370 n=30+29)
XML 200ms ± 4% 201ms ± 4% ~ (p=0.313 n=29+28)
[Geo mean] 332ms 333ms +0.10%
name old user-time/op new user-time/op delta
Template 227ms ± 5% 225ms ± 5% ~ (p=0.457 n=28+27)
Unicode 109ms ± 4% 109ms ± 5% ~ (p=0.758 n=29+29)
GoTypes 713ms ± 4% 721ms ± 5% ~ (p=0.051 n=30+29)
Compiler 3.36s ± 2% 3.38s ± 3% ~ (p=0.146 n=30+30)
SSA 7.46s ± 3% 7.47s ± 3% ~ (p=0.804 n=30+29)
Flate 146ms ± 7% 147ms ± 3% ~ (p=0.833 n=29+27)
GoParser 179ms ± 5% 179ms ± 5% ~ (p=0.866 n=30+30)
Reflect 431ms ± 4% 429ms ± 4% ~ (p=0.593 n=29+30)
Tar 124ms ± 5% 123ms ± 5% ~ (p=0.140 n=29+29)
XML 243ms ± 4% 242ms ± 7% ~ (p=0.404 n=29+29)
[Geo mean] 415ms 415ms +0.02%
name old obj-bytes new obj-bytes delta
Template 382k ± 0% 382k ± 0% ~ (all equal)
Unicode 203k ± 0% 203k ± 0% ~ (all equal)
GoTypes 1.18M ± 0% 1.18M ± 0% ~ (all equal)
Compiler 3.98M ± 0% 3.98M ± 0% ~ (all equal)
SSA 8.28M ± 0% 8.28M ± 0% ~ (all equal)
Flate 230k ± 0% 230k ± 0% ~ (all equal)
GoParser 287k ± 0% 287k ± 0% ~ (all equal)
Reflect 1.00M ± 0% 1.00M ± 0% ~ (all equal)
Tar 190k ± 0% 190k ± 0% ~ (all equal)
XML 416k ± 0% 416k ± 0% ~ (all equal)
[Geo mean] 660k 660k +0.00%
Comparing this CL to itself, from c=1 to c=2
improves real times 20-30%, costs 5-10% more CPU time,
and adds about 2% alloc.
The allocation increase comes from allocating more ssa.Caches.
name old time/op new time/op delta
Template 202ms ± 3% 149ms ± 3% -26.15% (p=0.000 n=49+49)
Unicode 87.4ms ± 4% 84.2ms ± 3% -3.68% (p=0.000 n=48+48)
GoTypes 560ms ± 2% 398ms ± 2% -28.96% (p=0.000 n=49+49)
Compiler 2.46s ± 3% 1.76s ± 2% -28.61% (p=0.000 n=48+46)
SSA 6.17s ± 2% 4.04s ± 1% -34.52% (p=0.000 n=49+49)
Flate 126ms ± 3% 92ms ± 2% -26.81% (p=0.000 n=49+48)
GoParser 148ms ± 4% 107ms ± 2% -27.78% (p=0.000 n=49+48)
Reflect 361ms ± 3% 281ms ± 3% -22.10% (p=0.000 n=49+49)
Tar 109ms ± 4% 86ms ± 3% -20.81% (p=0.000 n=49+47)
XML 204ms ± 3% 144ms ± 2% -29.53% (p=0.000 n=48+45)
name old user-time/op new user-time/op delta
Template 246ms ± 9% 246ms ± 4% ~ (p=0.401 n=50+48)
Unicode 109ms ± 4% 111ms ± 4% +1.47% (p=0.000 n=44+50)
GoTypes 728ms ± 3% 765ms ± 3% +5.04% (p=0.000 n=46+50)
Compiler 3.33s ± 3% 3.41s ± 2% +2.31% (p=0.000 n=49+48)
SSA 8.52s ± 2% 9.11s ± 2% +6.93% (p=0.000 n=49+47)
Flate 149ms ± 4% 161ms ± 3% +8.13% (p=0.000 n=50+47)
GoParser 181ms ± 5% 192ms ± 2% +6.40% (p=0.000 n=49+46)
Reflect 452ms ± 9% 474ms ± 2% +4.99% (p=0.000 n=50+48)
Tar 126ms ± 6% 136ms ± 4% +7.95% (p=0.000 n=50+49)
XML 247ms ± 5% 264ms ± 3% +6.94% (p=0.000 n=48+50)
name old alloc/op new alloc/op delta
Template 38.8MB ± 0% 39.3MB ± 0% +1.48% (p=0.008 n=5+5)
Unicode 29.8MB ± 0% 30.2MB ± 0% +1.19% (p=0.008 n=5+5)
GoTypes 113MB ± 0% 114MB ± 0% +0.69% (p=0.008 n=5+5)
Compiler 443MB ± 0% 447MB ± 0% +0.95% (p=0.008 n=5+5)
SSA 1.25GB ± 0% 1.26GB ± 0% +0.89% (p=0.008 n=5+5)
Flate 25.3MB ± 0% 25.9MB ± 1% +2.35% (p=0.008 n=5+5)
GoParser 31.7MB ± 0% 32.2MB ± 0% +1.59% (p=0.008 n=5+5)
Reflect 78.2MB ± 0% 78.9MB ± 0% +0.91% (p=0.008 n=5+5)
Tar 26.6MB ± 0% 27.0MB ± 0% +1.80% (p=0.008 n=5+5)
XML 42.4MB ± 0% 43.4MB ± 0% +2.35% (p=0.008 n=5+5)
name old allocs/op new allocs/op delta
Template 379k ± 0% 378k ± 0% ~ (p=0.421 n=5+5)
Unicode 322k ± 0% 321k ± 0% ~ (p=0.222 n=5+5)
GoTypes 1.14M ± 0% 1.14M ± 0% ~ (p=0.548 n=5+5)
Compiler 4.12M ± 0% 4.11M ± 0% -0.14% (p=0.032 n=5+5)
SSA 9.72M ± 0% 9.72M ± 0% ~ (p=0.421 n=5+5)
Flate 234k ± 1% 234k ± 0% ~ (p=0.421 n=5+5)
GoParser 316k ± 1% 315k ± 0% ~ (p=0.222 n=5+5)
Reflect 980k ± 0% 979k ± 0% ~ (p=0.095 n=5+5)
Tar 249k ± 1% 249k ± 1% ~ (p=0.841 n=5+5)
XML 392k ± 0% 391k ± 0% ~ (p=0.095 n=5+5)
From c=1 to c=4, real time is down ~40%, CPU usage up 10-20%, alloc up ~5%:
name old time/op new time/op delta
Template 203ms ± 3% 131ms ± 5% -35.45% (p=0.000 n=50+50)
Unicode 87.2ms ± 4% 84.1ms ± 2% -3.61% (p=0.000 n=48+47)
GoTypes 560ms ± 4% 310ms ± 2% -44.65% (p=0.000 n=50+49)
Compiler 2.47s ± 3% 1.41s ± 2% -43.10% (p=0.000 n=50+46)
SSA 6.17s ± 2% 3.20s ± 2% -48.06% (p=0.000 n=49+49)
Flate 126ms ± 4% 74ms ± 2% -41.06% (p=0.000 n=49+48)
GoParser 148ms ± 4% 89ms ± 3% -39.97% (p=0.000 n=49+50)
Reflect 360ms ± 3% 242ms ± 3% -32.81% (p=0.000 n=49+49)
Tar 108ms ± 4% 73ms ± 4% -32.48% (p=0.000 n=50+49)
XML 203ms ± 3% 119ms ± 3% -41.56% (p=0.000 n=49+48)
name old user-time/op new user-time/op delta
Template 246ms ± 9% 287ms ± 9% +16.98% (p=0.000 n=50+50)
Unicode 109ms ± 4% 118ms ± 5% +7.56% (p=0.000 n=46+50)
GoTypes 735ms ± 4% 806ms ± 2% +9.62% (p=0.000 n=50+50)
Compiler 3.34s ± 4% 3.56s ± 2% +6.78% (p=0.000 n=49+49)
SSA 8.54s ± 3% 10.04s ± 3% +17.55% (p=0.000 n=50+50)
Flate 149ms ± 6% 176ms ± 3% +17.82% (p=0.000 n=50+48)
GoParser 181ms ± 5% 213ms ± 3% +17.47% (p=0.000 n=50+50)
Reflect 453ms ± 6% 499ms ± 2% +10.11% (p=0.000 n=50+48)
Tar 126ms ± 5% 149ms ±11% +18.76% (p=0.000 n=50+50)
XML 246ms ± 5% 287ms ± 4% +16.53% (p=0.000 n=49+50)
name old alloc/op new alloc/op delta
Template 38.8MB ± 0% 40.4MB ± 0% +4.21% (p=0.008 n=5+5)
Unicode 29.8MB ± 0% 30.9MB ± 0% +3.68% (p=0.008 n=5+5)
GoTypes 113MB ± 0% 116MB ± 0% +2.71% (p=0.008 n=5+5)
Compiler 443MB ± 0% 455MB ± 0% +2.75% (p=0.008 n=5+5)
SSA 1.25GB ± 0% 1.27GB ± 0% +1.84% (p=0.008 n=5+5)
Flate 25.3MB ± 0% 26.9MB ± 1% +6.31% (p=0.008 n=5+5)
GoParser 31.7MB ± 0% 33.2MB ± 0% +4.61% (p=0.008 n=5+5)
Reflect 78.2MB ± 0% 80.2MB ± 0% +2.53% (p=0.008 n=5+5)
Tar 26.6MB ± 0% 27.9MB ± 0% +5.19% (p=0.008 n=5+5)
XML 42.4MB ± 0% 44.6MB ± 0% +5.20% (p=0.008 n=5+5)
name old allocs/op new allocs/op delta
Template 380k ± 0% 379k ± 0% -0.39% (p=0.032 n=5+5)
Unicode 321k ± 0% 321k ± 0% ~ (p=0.841 n=5+5)
GoTypes 1.14M ± 0% 1.14M ± 0% ~ (p=0.421 n=5+5)
Compiler 4.12M ± 0% 4.14M ± 0% +0.52% (p=0.008 n=5+5)
SSA 9.72M ± 0% 9.76M ± 0% +0.37% (p=0.008 n=5+5)
Flate 234k ± 1% 234k ± 1% ~ (p=0.690 n=5+5)
GoParser 316k ± 0% 317k ± 1% ~ (p=0.841 n=5+5)
Reflect 981k ± 0% 981k ± 0% ~ (p=1.000 n=5+5)
Tar 250k ± 0% 249k ± 1% ~ (p=0.151 n=5+5)
XML 393k ± 0% 392k ± 0% ~ (p=0.056 n=5+5)
Going beyond c=4 on my machine tends to increase CPU time and allocs
without impacting real time.
The CPU time numbers matter, because when there are many concurrent
compilation processes, that will impact the overall throughput.
The numbers above are in many ways the best case scenario;
we can take full advantage of all cores.
Fortunately, the most common compilation scenario is incremental
re-compilation of a single package during a build/test cycle.
Updates #15756
Change-Id: I6725558ca2069edec0ac5b0d1683105a9fff6bea
Reviewed-on: https://go-review.googlesource.com/40693
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-03-19 08:27:26 -07:00
|
|
|
if len(compilequeue) != 0 {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Fatalf("%d uncompiled functions", len(compilequeue))
|
cmd/compile: add initial backend concurrency support
This CL adds initial support for concurrent backend compilation.
BACKGROUND
The compiler currently consists (very roughly) of the following phases:
1. Initialization.
2. Lexing and parsing into the cmd/compile/internal/syntax AST.
3. Translation into the cmd/compile/internal/gc AST.
4. Some gc AST passes: typechecking, escape analysis, inlining,
closure handling, expression evaluation ordering (order.go),
and some lowering and optimization (walk.go).
5. Translation into the cmd/compile/internal/ssa SSA form.
6. Optimization and lowering of SSA form.
7. Translation from SSA form to assembler instructions.
8. Translation from assembler instructions to machine code.
9. Writing lots of output: machine code, DWARF symbols,
type and reflection info, export data.
Phase 2 was already concurrent as of Go 1.8.
Phase 3 is planned for eventual removal;
we hope to go straight from syntax AST to SSA.
Phases 5–8 are per-function; this CL adds support for
processing multiple functions concurrently.
The slowest phases in the compiler are 5 and 6,
so this offers the opportunity for some good speed-ups.
Unfortunately, it's not quite that straightforward.
In the current compiler, the latter parts of phase 4
(order, walk) are done function-at-a-time as needed.
Making order and walk concurrency-safe proved hard,
and they're not particularly slow, so there wasn't much reward.
To enable phases 5–8 to be done concurrently,
when concurrent backend compilation is requested,
we complete phase 4 for all functions
before starting later phases for any functions.
Also, in reality, we automatically generate new
functions in phase 9, such as method wrappers
and equality and has routines.
Those new functions then go through phases 4–8.
This CL disables concurrent backend compilation
after the first, big, user-provided batch of
functions has been compiled.
This is done to keep things simple,
and because the autogenerated functions
tend to be small, few, simple, and fast to compile.
USAGE
Concurrent backend compilation still defaults to off.
To set the number of functions that may be backend-compiled
concurrently, use the compiler flag -c.
In future work, cmd/go will automatically set -c.
Furthermore, this CL has been intentionally written
so that the c=1 path has no backend concurrency whatsoever,
not even spawning any goroutines.
This helps ensure that, should problems arise
late in the development cycle,
we can simply have cmd/go set c=1 always,
and revert to the original compiler behavior.
MUTEXES
Most of the work required to make concurrent backend
compilation safe has occurred over the past month.
This CL adds a handful of mutexes to get the rest of the way there;
they are the mutexes that I didn't see a clean way to avoid.
Some of them may still be eliminable in future work.
In no particular order:
* gc.funcsymsmu. The global funcsyms slice is populated
lazily when we need function symbols for closures.
This occurs during gc AST to SSA translation.
The function funcsym also does a package lookup,
which is a source of races on types.Pkg.Syms;
funcsymsmu also covers that package lookup.
This mutex is low priority: it adds a single global,
it is in an infrequently used code path, and it is low contention.
Since funcsyms may now be added in any order,
we must sort them to preserve reproducible builds.
* gc.largeStackFramesMu. We don't discover until after SSA compilation
that a function's stack frame is gigantic.
Recording that error happens basically never,
but it does happen concurrently.
Fix with a low priority mutex and sorting.
* obj.Link.hashmu. ctxt.hash stores the mapping from
types.Syms (compiler symbols) to obj.LSyms (linker symbols).
It is accessed fairly heavily through all the phases.
This is the only heavily contended mutex.
* gc.signatlistmu. The global signatlist map is
populated with types through several of the concurrent phases,
including notably via ngotype during DWARF generation.
It is low priority for removal.
* gc.typepkgmu. Looking up symbols in the types package
happens a fair amount during backend compilation
and DWARF generation, particularly via ngotype.
This mutex helps us to avoid a broader mutex on types.Pkg.Syms.
It has low-to-moderate contention.
* types.internedStringsmu. gc AST to SSA conversion and
some SSA work introduce new autotmps.
Those autotmps have their names interned to reduce allocations.
That interning requires protecting types.internedStrings.
The autotmp names are heavily re-used, and the mutex
overhead and contention here are low, so it is probably
a worthwhile performance optimization to keep this mutex.
TESTING
I have been testing this code locally by running
'go install -race cmd/compile'
and then doing
'go build -a -gcflags=-c=128 std cmd'
for all architectures and a variety of compiler flags.
This obviously needs to be made part of the builders,
but it is too expensive to make part of all.bash.
I have filed #19962 for this.
REPRODUCIBLE BUILDS
This version of the compiler generates reproducible builds.
Testing reproducible builds also needs automation, however,
and is also too expensive for all.bash.
This is #19961.
Also of note is that some of the compiler flags used by 'toolstash -cmp'
are currently incompatible with concurrent backend compilation.
They still work fine with c=1.
Time will tell whether this is a problem.
NEXT STEPS
* Continue to find and fix races and bugs,
using a combination of code inspection, fuzzing,
and hopefully some community experimentation.
I do not know of any outstanding races,
but there probably are some.
* Improve testing.
* Improve performance, for many values of c.
* Integrate with cmd/go and fine tune.
* Support concurrent compilation with the -race flag.
It is a sad irony that it does not yet work.
* Minor code cleanup that has been deferred during
the last month due to uncertainty about the
ultimate shape of this CL.
PERFORMANCE
Here's the buried lede, at last. :)
All benchmarks are from my 8 core 2.9 GHz Intel Core i7 darwin/amd64 laptop.
First, going from tip to this CL with c=1 has almost no impact.
name old time/op new time/op delta
Template 195ms ± 3% 194ms ± 5% ~ (p=0.370 n=30+29)
Unicode 86.6ms ± 3% 87.0ms ± 7% ~ (p=0.958 n=29+30)
GoTypes 548ms ± 3% 555ms ± 4% +1.35% (p=0.001 n=30+28)
Compiler 2.51s ± 2% 2.54s ± 2% +1.17% (p=0.000 n=28+30)
SSA 5.16s ± 3% 5.16s ± 2% ~ (p=0.910 n=30+29)
Flate 124ms ± 5% 124ms ± 4% ~ (p=0.947 n=30+30)
GoParser 146ms ± 3% 146ms ± 3% ~ (p=0.150 n=29+28)
Reflect 354ms ± 3% 352ms ± 4% ~ (p=0.096 n=29+29)
Tar 107ms ± 5% 106ms ± 3% ~ (p=0.370 n=30+29)
XML 200ms ± 4% 201ms ± 4% ~ (p=0.313 n=29+28)
[Geo mean] 332ms 333ms +0.10%
name old user-time/op new user-time/op delta
Template 227ms ± 5% 225ms ± 5% ~ (p=0.457 n=28+27)
Unicode 109ms ± 4% 109ms ± 5% ~ (p=0.758 n=29+29)
GoTypes 713ms ± 4% 721ms ± 5% ~ (p=0.051 n=30+29)
Compiler 3.36s ± 2% 3.38s ± 3% ~ (p=0.146 n=30+30)
SSA 7.46s ± 3% 7.47s ± 3% ~ (p=0.804 n=30+29)
Flate 146ms ± 7% 147ms ± 3% ~ (p=0.833 n=29+27)
GoParser 179ms ± 5% 179ms ± 5% ~ (p=0.866 n=30+30)
Reflect 431ms ± 4% 429ms ± 4% ~ (p=0.593 n=29+30)
Tar 124ms ± 5% 123ms ± 5% ~ (p=0.140 n=29+29)
XML 243ms ± 4% 242ms ± 7% ~ (p=0.404 n=29+29)
[Geo mean] 415ms 415ms +0.02%
name old obj-bytes new obj-bytes delta
Template 382k ± 0% 382k ± 0% ~ (all equal)
Unicode 203k ± 0% 203k ± 0% ~ (all equal)
GoTypes 1.18M ± 0% 1.18M ± 0% ~ (all equal)
Compiler 3.98M ± 0% 3.98M ± 0% ~ (all equal)
SSA 8.28M ± 0% 8.28M ± 0% ~ (all equal)
Flate 230k ± 0% 230k ± 0% ~ (all equal)
GoParser 287k ± 0% 287k ± 0% ~ (all equal)
Reflect 1.00M ± 0% 1.00M ± 0% ~ (all equal)
Tar 190k ± 0% 190k ± 0% ~ (all equal)
XML 416k ± 0% 416k ± 0% ~ (all equal)
[Geo mean] 660k 660k +0.00%
Comparing this CL to itself, from c=1 to c=2
improves real times 20-30%, costs 5-10% more CPU time,
and adds about 2% alloc.
The allocation increase comes from allocating more ssa.Caches.
name old time/op new time/op delta
Template 202ms ± 3% 149ms ± 3% -26.15% (p=0.000 n=49+49)
Unicode 87.4ms ± 4% 84.2ms ± 3% -3.68% (p=0.000 n=48+48)
GoTypes 560ms ± 2% 398ms ± 2% -28.96% (p=0.000 n=49+49)
Compiler 2.46s ± 3% 1.76s ± 2% -28.61% (p=0.000 n=48+46)
SSA 6.17s ± 2% 4.04s ± 1% -34.52% (p=0.000 n=49+49)
Flate 126ms ± 3% 92ms ± 2% -26.81% (p=0.000 n=49+48)
GoParser 148ms ± 4% 107ms ± 2% -27.78% (p=0.000 n=49+48)
Reflect 361ms ± 3% 281ms ± 3% -22.10% (p=0.000 n=49+49)
Tar 109ms ± 4% 86ms ± 3% -20.81% (p=0.000 n=49+47)
XML 204ms ± 3% 144ms ± 2% -29.53% (p=0.000 n=48+45)
name old user-time/op new user-time/op delta
Template 246ms ± 9% 246ms ± 4% ~ (p=0.401 n=50+48)
Unicode 109ms ± 4% 111ms ± 4% +1.47% (p=0.000 n=44+50)
GoTypes 728ms ± 3% 765ms ± 3% +5.04% (p=0.000 n=46+50)
Compiler 3.33s ± 3% 3.41s ± 2% +2.31% (p=0.000 n=49+48)
SSA 8.52s ± 2% 9.11s ± 2% +6.93% (p=0.000 n=49+47)
Flate 149ms ± 4% 161ms ± 3% +8.13% (p=0.000 n=50+47)
GoParser 181ms ± 5% 192ms ± 2% +6.40% (p=0.000 n=49+46)
Reflect 452ms ± 9% 474ms ± 2% +4.99% (p=0.000 n=50+48)
Tar 126ms ± 6% 136ms ± 4% +7.95% (p=0.000 n=50+49)
XML 247ms ± 5% 264ms ± 3% +6.94% (p=0.000 n=48+50)
name old alloc/op new alloc/op delta
Template 38.8MB ± 0% 39.3MB ± 0% +1.48% (p=0.008 n=5+5)
Unicode 29.8MB ± 0% 30.2MB ± 0% +1.19% (p=0.008 n=5+5)
GoTypes 113MB ± 0% 114MB ± 0% +0.69% (p=0.008 n=5+5)
Compiler 443MB ± 0% 447MB ± 0% +0.95% (p=0.008 n=5+5)
SSA 1.25GB ± 0% 1.26GB ± 0% +0.89% (p=0.008 n=5+5)
Flate 25.3MB ± 0% 25.9MB ± 1% +2.35% (p=0.008 n=5+5)
GoParser 31.7MB ± 0% 32.2MB ± 0% +1.59% (p=0.008 n=5+5)
Reflect 78.2MB ± 0% 78.9MB ± 0% +0.91% (p=0.008 n=5+5)
Tar 26.6MB ± 0% 27.0MB ± 0% +1.80% (p=0.008 n=5+5)
XML 42.4MB ± 0% 43.4MB ± 0% +2.35% (p=0.008 n=5+5)
name old allocs/op new allocs/op delta
Template 379k ± 0% 378k ± 0% ~ (p=0.421 n=5+5)
Unicode 322k ± 0% 321k ± 0% ~ (p=0.222 n=5+5)
GoTypes 1.14M ± 0% 1.14M ± 0% ~ (p=0.548 n=5+5)
Compiler 4.12M ± 0% 4.11M ± 0% -0.14% (p=0.032 n=5+5)
SSA 9.72M ± 0% 9.72M ± 0% ~ (p=0.421 n=5+5)
Flate 234k ± 1% 234k ± 0% ~ (p=0.421 n=5+5)
GoParser 316k ± 1% 315k ± 0% ~ (p=0.222 n=5+5)
Reflect 980k ± 0% 979k ± 0% ~ (p=0.095 n=5+5)
Tar 249k ± 1% 249k ± 1% ~ (p=0.841 n=5+5)
XML 392k ± 0% 391k ± 0% ~ (p=0.095 n=5+5)
From c=1 to c=4, real time is down ~40%, CPU usage up 10-20%, alloc up ~5%:
name old time/op new time/op delta
Template 203ms ± 3% 131ms ± 5% -35.45% (p=0.000 n=50+50)
Unicode 87.2ms ± 4% 84.1ms ± 2% -3.61% (p=0.000 n=48+47)
GoTypes 560ms ± 4% 310ms ± 2% -44.65% (p=0.000 n=50+49)
Compiler 2.47s ± 3% 1.41s ± 2% -43.10% (p=0.000 n=50+46)
SSA 6.17s ± 2% 3.20s ± 2% -48.06% (p=0.000 n=49+49)
Flate 126ms ± 4% 74ms ± 2% -41.06% (p=0.000 n=49+48)
GoParser 148ms ± 4% 89ms ± 3% -39.97% (p=0.000 n=49+50)
Reflect 360ms ± 3% 242ms ± 3% -32.81% (p=0.000 n=49+49)
Tar 108ms ± 4% 73ms ± 4% -32.48% (p=0.000 n=50+49)
XML 203ms ± 3% 119ms ± 3% -41.56% (p=0.000 n=49+48)
name old user-time/op new user-time/op delta
Template 246ms ± 9% 287ms ± 9% +16.98% (p=0.000 n=50+50)
Unicode 109ms ± 4% 118ms ± 5% +7.56% (p=0.000 n=46+50)
GoTypes 735ms ± 4% 806ms ± 2% +9.62% (p=0.000 n=50+50)
Compiler 3.34s ± 4% 3.56s ± 2% +6.78% (p=0.000 n=49+49)
SSA 8.54s ± 3% 10.04s ± 3% +17.55% (p=0.000 n=50+50)
Flate 149ms ± 6% 176ms ± 3% +17.82% (p=0.000 n=50+48)
GoParser 181ms ± 5% 213ms ± 3% +17.47% (p=0.000 n=50+50)
Reflect 453ms ± 6% 499ms ± 2% +10.11% (p=0.000 n=50+48)
Tar 126ms ± 5% 149ms ±11% +18.76% (p=0.000 n=50+50)
XML 246ms ± 5% 287ms ± 4% +16.53% (p=0.000 n=49+50)
name old alloc/op new alloc/op delta
Template 38.8MB ± 0% 40.4MB ± 0% +4.21% (p=0.008 n=5+5)
Unicode 29.8MB ± 0% 30.9MB ± 0% +3.68% (p=0.008 n=5+5)
GoTypes 113MB ± 0% 116MB ± 0% +2.71% (p=0.008 n=5+5)
Compiler 443MB ± 0% 455MB ± 0% +2.75% (p=0.008 n=5+5)
SSA 1.25GB ± 0% 1.27GB ± 0% +1.84% (p=0.008 n=5+5)
Flate 25.3MB ± 0% 26.9MB ± 1% +6.31% (p=0.008 n=5+5)
GoParser 31.7MB ± 0% 33.2MB ± 0% +4.61% (p=0.008 n=5+5)
Reflect 78.2MB ± 0% 80.2MB ± 0% +2.53% (p=0.008 n=5+5)
Tar 26.6MB ± 0% 27.9MB ± 0% +5.19% (p=0.008 n=5+5)
XML 42.4MB ± 0% 44.6MB ± 0% +5.20% (p=0.008 n=5+5)
name old allocs/op new allocs/op delta
Template 380k ± 0% 379k ± 0% -0.39% (p=0.032 n=5+5)
Unicode 321k ± 0% 321k ± 0% ~ (p=0.841 n=5+5)
GoTypes 1.14M ± 0% 1.14M ± 0% ~ (p=0.421 n=5+5)
Compiler 4.12M ± 0% 4.14M ± 0% +0.52% (p=0.008 n=5+5)
SSA 9.72M ± 0% 9.76M ± 0% +0.37% (p=0.008 n=5+5)
Flate 234k ± 1% 234k ± 1% ~ (p=0.690 n=5+5)
GoParser 316k ± 0% 317k ± 1% ~ (p=0.841 n=5+5)
Reflect 981k ± 0% 981k ± 0% ~ (p=1.000 n=5+5)
Tar 250k ± 0% 249k ± 1% ~ (p=0.151 n=5+5)
XML 393k ± 0% 392k ± 0% ~ (p=0.056 n=5+5)
Going beyond c=4 on my machine tends to increase CPU time and allocs
without impacting real time.
The CPU time numbers matter, because when there are many concurrent
compilation processes, that will impact the overall throughput.
The numbers above are in many ways the best case scenario;
we can take full advantage of all cores.
Fortunately, the most common compilation scenario is incremental
re-compilation of a single package during a build/test cycle.
Updates #15756
Change-Id: I6725558ca2069edec0ac5b0d1683105a9fff6bea
Reviewed-on: https://go-review.googlesource.com/40693
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-03-19 08:27:26 -07:00
|
|
|
}
|
|
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
logopt.FlushLoggedOpts(base.Ctxt, base.Ctxt.Pkgpath)
|
|
|
|
|
base.ExitIfErrors()
|
2016-03-11 14:28:16 -08:00
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
base.FlushErrors()
|
2016-06-24 15:03:04 -07:00
|
|
|
timings.Stop()
|
|
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.Bench != "" {
|
|
|
|
|
if err := writebench(base.Flag.Bench); err != nil {
|
2016-06-24 15:03:04 -07:00
|
|
|
log.Fatalf("cannot write benchmark data: %v", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-31 20:24:05 -07:00
|
|
|
// numNonClosures returns the number of functions in list which are not closures.
|
2020-11-28 07:31:18 -05:00
|
|
|
func numNonClosures(list []*ir.Func) int {
|
2020-03-31 20:24:05 -07:00
|
|
|
count := 0
|
2020-11-28 07:31:18 -05:00
|
|
|
for _, fn := range list {
|
|
|
|
|
if fn.OClosure == nil {
|
2020-03-31 20:24:05 -07:00
|
|
|
count++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return count
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-24 15:03:04 -07:00
|
|
|
func writebench(filename string) error {
|
|
|
|
|
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
2017-04-18 12:53:25 -07:00
|
|
|
fmt.Fprintln(&buf, "commit:", objabi.Version)
|
2016-06-24 15:03:04 -07:00
|
|
|
fmt.Fprintln(&buf, "goos:", runtime.GOOS)
|
|
|
|
|
fmt.Fprintln(&buf, "goarch:", runtime.GOARCH)
|
2020-11-19 20:49:23 -05:00
|
|
|
timings.Write(&buf, "BenchmarkCompile:"+base.Ctxt.Pkgpath+":")
|
2016-06-24 15:03:04 -07:00
|
|
|
|
|
|
|
|
n, err := f.Write(buf.Bytes())
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
if n != buf.Len() {
|
|
|
|
|
panic("bad writer")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return f.Close()
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
|
2018-10-22 10:10:23 -04:00
|
|
|
// symabiDefs and symabiRefs record the defined and referenced ABIs of
|
|
|
|
|
// symbols required by non-Go code. These are keyed by link symbol
|
|
|
|
|
// name, where the local package prefix is always `"".`
|
|
|
|
|
var symabiDefs, symabiRefs map[string]obj.ABI
|
|
|
|
|
|
|
|
|
|
// readSymABIs reads a symabis file that specifies definitions and
|
|
|
|
|
// references of text symbols by ABI.
|
|
|
|
|
//
|
|
|
|
|
// The symabis format is a set of lines, where each line is a sequence
|
|
|
|
|
// of whitespace-separated fields. The first field is a verb and is
|
|
|
|
|
// either "def" for defining a symbol ABI or "ref" for referencing a
|
|
|
|
|
// symbol using an ABI. For both "def" and "ref", the second field is
|
|
|
|
|
// the symbol name and the third field is the ABI name, as one of the
|
|
|
|
|
// named cmd/internal/obj.ABI constants.
|
|
|
|
|
func readSymABIs(file, myimportpath string) {
|
|
|
|
|
data, err := ioutil.ReadFile(file)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("-symabis: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
symabiDefs = make(map[string]obj.ABI)
|
|
|
|
|
symabiRefs = make(map[string]obj.ABI)
|
|
|
|
|
|
|
|
|
|
localPrefix := ""
|
|
|
|
|
if myimportpath != "" {
|
|
|
|
|
// Symbols in this package may be written either as
|
|
|
|
|
// "".X or with the package's import path already in
|
|
|
|
|
// the symbol.
|
|
|
|
|
localPrefix = objabi.PathToPrefix(myimportpath) + "."
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for lineNum, line := range strings.Split(string(data), "\n") {
|
|
|
|
|
lineNum++ // 1-based
|
|
|
|
|
line = strings.TrimSpace(line)
|
|
|
|
|
if line == "" || strings.HasPrefix(line, "#") {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
parts := strings.Fields(line)
|
|
|
|
|
switch parts[0] {
|
|
|
|
|
case "def", "ref":
|
|
|
|
|
// Parse line.
|
|
|
|
|
if len(parts) != 3 {
|
|
|
|
|
log.Fatalf(`%s:%d: invalid symabi: syntax is "%s sym abi"`, file, lineNum, parts[0])
|
|
|
|
|
}
|
2020-10-07 12:31:05 -04:00
|
|
|
sym, abistr := parts[1], parts[2]
|
|
|
|
|
abi, valid := obj.ParseABI(abistr)
|
|
|
|
|
if !valid {
|
|
|
|
|
log.Fatalf(`%s:%d: invalid symabi: unknown abi "%s"`, file, lineNum, abistr)
|
2018-10-22 10:10:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If the symbol is already prefixed with
|
|
|
|
|
// myimportpath, rewrite it to start with ""
|
|
|
|
|
// so it matches the compiler's internal
|
|
|
|
|
// symbol names.
|
|
|
|
|
if localPrefix != "" && strings.HasPrefix(sym, localPrefix) {
|
|
|
|
|
sym = `"".` + sym[len(localPrefix):]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Record for later.
|
|
|
|
|
if parts[0] == "def" {
|
2020-10-07 12:31:05 -04:00
|
|
|
symabiDefs[sym] = abi
|
2018-10-22 10:10:23 -04:00
|
|
|
} else {
|
2020-10-07 12:31:05 -04:00
|
|
|
symabiRefs[sym] = abi
|
2018-10-22 10:10:23 -04:00
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
log.Fatalf(`%s:%d: invalid symabi type "%s"`, file, lineNum, parts[0])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-11 14:28:16 -08:00
|
|
|
func arsize(b *bufio.Reader, name string) int {
|
|
|
|
|
var buf [ArhdrSize]byte
|
|
|
|
|
if _, err := io.ReadFull(b, buf[:]); err != nil {
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
aname := strings.Trim(string(buf[0:16]), " ")
|
|
|
|
|
if !strings.HasPrefix(aname, name) {
|
|
|
|
|
return -1
|
|
|
|
|
}
|
|
|
|
|
asize := strings.Trim(string(buf[48:58]), " ")
|
|
|
|
|
i, _ := strconv.Atoi(asize)
|
|
|
|
|
return i
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func isDriveLetter(b byte) bool {
|
|
|
|
|
return 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z'
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-19 22:33:51 +02:00
|
|
|
// is this path a local name? begins with ./ or ../ or /
|
2016-03-11 14:28:16 -08:00
|
|
|
func islocalname(name string) bool {
|
|
|
|
|
return strings.HasPrefix(name, "/") ||
|
2016-03-21 14:37:57 +11:00
|
|
|
runtime.GOOS == "windows" && len(name) >= 3 && isDriveLetter(name[0]) && name[1] == ':' && name[2] == '/' ||
|
2016-03-11 14:28:16 -08:00
|
|
|
strings.HasPrefix(name, "./") || name == "." ||
|
|
|
|
|
strings.HasPrefix(name, "../") || name == ".."
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func findpkg(name string) (file string, ok bool) {
|
|
|
|
|
if islocalname(name) {
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.NoLocalImports {
|
2016-03-11 14:28:16 -08:00
|
|
|
return "", false
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.Cfg.PackageFile != nil {
|
|
|
|
|
file, ok = base.Flag.Cfg.PackageFile[name]
|
2017-05-31 11:19:54 -04:00
|
|
|
return file, ok
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-11 14:28:16 -08:00
|
|
|
// try .a before .6. important for building libraries:
|
|
|
|
|
// if there is an array.6 in the array.a library,
|
|
|
|
|
// want to find all of array.a, not just array.6.
|
|
|
|
|
file = fmt.Sprintf("%s.a", name)
|
|
|
|
|
if _, err := os.Stat(file); err == nil {
|
|
|
|
|
return file, true
|
|
|
|
|
}
|
|
|
|
|
file = fmt.Sprintf("%s.o", name)
|
|
|
|
|
if _, err := os.Stat(file); err == nil {
|
|
|
|
|
return file, true
|
|
|
|
|
}
|
|
|
|
|
return "", false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// local imports should be canonicalized already.
|
|
|
|
|
// don't want to see "encoding/../encoding/base64"
|
|
|
|
|
// as different from "encoding/base64".
|
|
|
|
|
if q := path.Clean(name); q != name {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Errorf("non-canonical import path %q (should be %q)", name, q)
|
2016-03-11 14:28:16 -08:00
|
|
|
return "", false
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.Cfg.PackageFile != nil {
|
|
|
|
|
file, ok = base.Flag.Cfg.PackageFile[name]
|
2017-05-31 11:19:54 -04:00
|
|
|
return file, ok
|
|
|
|
|
}
|
|
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
for _, dir := range base.Flag.Cfg.ImportDirs {
|
2016-03-11 14:28:16 -08:00
|
|
|
file = fmt.Sprintf("%s/%s.a", dir, name)
|
|
|
|
|
if _, err := os.Stat(file); err == nil {
|
|
|
|
|
return file, true
|
|
|
|
|
}
|
|
|
|
|
file = fmt.Sprintf("%s/%s.o", dir, name)
|
|
|
|
|
if _, err := os.Stat(file); err == nil {
|
|
|
|
|
return file, true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
if objabi.GOROOT != "" {
|
2016-03-11 14:28:16 -08:00
|
|
|
suffix := ""
|
|
|
|
|
suffixsep := ""
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.InstallSuffix != "" {
|
2016-03-11 14:28:16 -08:00
|
|
|
suffixsep = "_"
|
2020-11-19 20:49:23 -05:00
|
|
|
suffix = base.Flag.InstallSuffix
|
|
|
|
|
} else if base.Flag.Race {
|
2016-03-11 14:28:16 -08:00
|
|
|
suffixsep = "_"
|
|
|
|
|
suffix = "race"
|
2020-11-19 20:49:23 -05:00
|
|
|
} else if base.Flag.MSan {
|
2016-03-11 14:28:16 -08:00
|
|
|
suffixsep = "_"
|
|
|
|
|
suffix = "msan"
|
|
|
|
|
}
|
|
|
|
|
|
2017-04-18 12:53:25 -07:00
|
|
|
file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name)
|
2016-03-11 14:28:16 -08:00
|
|
|
if _, err := os.Stat(file); err == nil {
|
|
|
|
|
return file, true
|
|
|
|
|
}
|
2017-04-18 12:53:25 -07:00
|
|
|
file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name)
|
2016-03-11 14:28:16 -08:00
|
|
|
if _, err := os.Stat(file); err == nil {
|
|
|
|
|
return file, true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "", false
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-18 16:11:50 -07:00
|
|
|
// loadsys loads the definitions for the low-level runtime functions,
|
2016-03-11 14:28:16 -08:00
|
|
|
// so that the compiler can generate calls to them,
|
2016-10-18 16:11:50 -07:00
|
|
|
// but does not make them visible to user code.
|
2016-03-11 14:28:16 -08:00
|
|
|
func loadsys() {
|
2017-04-06 20:57:46 -07:00
|
|
|
types.Block = 1
|
2016-03-11 14:28:16 -08:00
|
|
|
|
2017-03-23 17:39:28 -07:00
|
|
|
inimport = true
|
2016-10-18 16:11:50 -07:00
|
|
|
typecheckok = true
|
|
|
|
|
|
|
|
|
|
typs := runtimeTypes()
|
2019-11-01 18:12:27 +07:00
|
|
|
for _, d := range &runtimeDecls {
|
2017-03-30 13:19:18 -07:00
|
|
|
sym := Runtimepkg.Lookup(d.name)
|
2016-10-18 16:11:50 -07:00
|
|
|
typ := typs[d.typ]
|
|
|
|
|
switch d.tag {
|
|
|
|
|
case funcTag:
|
2018-04-17 14:40:56 -07:00
|
|
|
importfunc(Runtimepkg, src.NoXPos, sym, typ)
|
2016-10-18 16:11:50 -07:00
|
|
|
case varTag:
|
2018-04-17 14:40:56 -07:00
|
|
|
importvar(Runtimepkg, src.NoXPos, sym, typ)
|
2016-10-18 16:11:50 -07:00
|
|
|
default:
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Fatalf("unhandled declaration tag %v", d.tag)
|
2016-10-18 16:11:50 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typecheckok = false
|
2017-03-23 17:39:28 -07:00
|
|
|
inimport = false
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
|
2018-04-05 14:29:32 -07:00
|
|
|
// myheight tracks the local package's height based on packages
|
|
|
|
|
// imported so far.
|
|
|
|
|
var myheight int
|
|
|
|
|
|
2020-11-13 23:36:48 -08:00
|
|
|
func importfile(f constant.Value) *types.Pkg {
|
|
|
|
|
if f.Kind() != constant.String {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Errorf("import path must be a string")
|
2017-03-23 17:39:28 -07:00
|
|
|
return nil
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
|
2020-11-13 23:36:48 -08:00
|
|
|
path_ := constant.StringVal(f)
|
2016-03-11 14:28:16 -08:00
|
|
|
if len(path_) == 0 {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Errorf("import path is empty")
|
2017-03-23 17:39:28 -07:00
|
|
|
return nil
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
|
2017-06-16 14:48:38 -07:00
|
|
|
if isbadimport(path_, false) {
|
2017-03-23 17:39:28 -07:00
|
|
|
return nil
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The package name main is no longer reserved,
|
|
|
|
|
// but we reserve the import path "main" to identify
|
|
|
|
|
// the main package, just as we reserve the import
|
|
|
|
|
// path "math" to identify the standard math package.
|
|
|
|
|
if path_ == "main" {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Errorf("cannot import \"main\"")
|
|
|
|
|
base.ErrorExit()
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Ctxt.Pkgpath != "" && path_ == base.Ctxt.Pkgpath {
|
|
|
|
|
base.Errorf("import %q while compiling that package (import cycle)", path_)
|
|
|
|
|
base.ErrorExit()
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
if mapped, ok := base.Flag.Cfg.ImportMap[path_]; ok {
|
2016-03-11 14:28:16 -08:00
|
|
|
path_ = mapped
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if path_ == "unsafe" {
|
2017-03-23 17:39:28 -07:00
|
|
|
return unsafepkg
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if islocalname(path_) {
|
|
|
|
|
if path_[0] == '/' {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Errorf("import path cannot be absolute path")
|
2017-03-23 17:39:28 -07:00
|
|
|
return nil
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
prefix := base.Ctxt.Pathname
|
|
|
|
|
if base.Flag.D != "" {
|
|
|
|
|
prefix = base.Flag.D
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
path_ = path.Join(prefix, path_)
|
|
|
|
|
|
2017-06-16 14:48:38 -07:00
|
|
|
if isbadimport(path_, true) {
|
2017-03-23 17:39:28 -07:00
|
|
|
return nil
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file, found := findpkg(path_)
|
|
|
|
|
if !found {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Errorf("can't find import: %q", path_)
|
|
|
|
|
base.ErrorExit()
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
|
2017-04-19 10:27:19 -07:00
|
|
|
importpkg := types.NewPkg(path_, "")
|
2016-03-11 14:28:16 -08:00
|
|
|
if importpkg.Imported {
|
2017-03-23 17:39:28 -07:00
|
|
|
return importpkg
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
importpkg.Imported = true
|
|
|
|
|
|
2018-04-17 14:59:13 -07:00
|
|
|
imp, err := bio.Open(file)
|
2016-03-11 14:28:16 -08:00
|
|
|
if err != nil {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Errorf("can't open import: %q: %v", path_, err)
|
|
|
|
|
base.ErrorExit()
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
2018-04-17 14:59:13 -07:00
|
|
|
defer imp.Close()
|
2016-03-11 14:28:16 -08:00
|
|
|
|
|
|
|
|
// check object header
|
|
|
|
|
p, err := imp.ReadString('\n')
|
|
|
|
|
if err != nil {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Errorf("import %s: reading input: %v", file, err)
|
|
|
|
|
base.ErrorExit()
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
|
2018-04-17 14:59:13 -07:00
|
|
|
if p == "!<arch>\n" { // package archive
|
2017-06-01 14:26:55 -04:00
|
|
|
// package export block should be first
|
2018-04-17 14:59:13 -07:00
|
|
|
sz := arsize(imp.Reader, "__.PKGDEF")
|
2017-06-01 14:26:55 -04:00
|
|
|
if sz <= 0 {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Errorf("import %s: not a package file", file)
|
|
|
|
|
base.ErrorExit()
|
2017-06-01 14:26:55 -04:00
|
|
|
}
|
|
|
|
|
p, err = imp.ReadString('\n')
|
|
|
|
|
if err != nil {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Errorf("import %s: reading input: %v", file, err)
|
|
|
|
|
base.ErrorExit()
|
2017-06-01 14:26:55 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-17 14:59:13 -07:00
|
|
|
if !strings.HasPrefix(p, "go object ") {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Errorf("import %s: not a go object file: %s", file, p)
|
|
|
|
|
base.ErrorExit()
|
2018-04-17 14:59:13 -07:00
|
|
|
}
|
|
|
|
|
q := fmt.Sprintf("%s %s %s %s\n", objabi.GOOS, objabi.GOARCH, objabi.Version, objabi.Expstring())
|
|
|
|
|
if p[10:] != q {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Errorf("import %s: object is [%s] expected [%s]", file, p[10:], q)
|
|
|
|
|
base.ErrorExit()
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
|
2016-05-20 11:19:19 -07:00
|
|
|
// process header lines
|
|
|
|
|
for {
|
|
|
|
|
p, err = imp.ReadString('\n')
|
|
|
|
|
if err != nil {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Errorf("import %s: reading input: %v", file, err)
|
|
|
|
|
base.ErrorExit()
|
2016-05-20 11:19:19 -07:00
|
|
|
}
|
|
|
|
|
if p == "\n" {
|
|
|
|
|
break // header ends with blank line
|
|
|
|
|
}
|
2016-09-13 15:33:55 -07:00
|
|
|
}
|
2016-05-20 11:19:19 -07:00
|
|
|
|
2020-11-24 22:09:57 -05:00
|
|
|
// Expect $$B\n to signal binary import format.
|
2016-03-11 14:28:16 -08:00
|
|
|
|
|
|
|
|
// look for $$
|
|
|
|
|
var c byte
|
|
|
|
|
for {
|
|
|
|
|
c, err = imp.ReadByte()
|
|
|
|
|
if err != nil {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
if c == '$' {
|
|
|
|
|
c, err = imp.ReadByte()
|
|
|
|
|
if c == '$' || err != nil {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get character after $$
|
|
|
|
|
if err == nil {
|
|
|
|
|
c, _ = imp.ReadByte()
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-02 19:36:28 -04:00
|
|
|
var fingerprint goobj.FingerprintType
|
2016-03-11 14:28:16 -08:00
|
|
|
switch c {
|
|
|
|
|
case '\n':
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Errorf("cannot import %s: old export format no longer supported (recompile library)", path_)
|
2017-03-23 17:39:28 -07:00
|
|
|
return nil
|
2016-03-11 14:28:16 -08:00
|
|
|
|
|
|
|
|
case 'B':
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Debug.Export != 0 {
|
2016-03-18 17:21:32 -07:00
|
|
|
fmt.Printf("importing %s (%s)\n", path_, file)
|
|
|
|
|
}
|
2016-03-11 14:28:16 -08:00
|
|
|
imp.ReadByte() // skip \n after $$B
|
2018-04-01 01:55:55 -07:00
|
|
|
|
|
|
|
|
c, err = imp.ReadByte()
|
|
|
|
|
if err != nil {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Errorf("import %s: reading input: %v", file, err)
|
|
|
|
|
base.ErrorExit()
|
2018-04-01 01:55:55 -07:00
|
|
|
}
|
|
|
|
|
|
2018-10-03 10:56:23 -07:00
|
|
|
// Indexed format is distinguished by an 'i' byte,
|
|
|
|
|
// whereas previous export formats started with 'c', 'd', or 'v'.
|
|
|
|
|
if c != 'i' {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Errorf("import %s: unexpected package format byte: %v", file, c)
|
|
|
|
|
base.ErrorExit()
|
2018-04-01 01:55:55 -07:00
|
|
|
}
|
[dev.link] cmd/internal/goobj2: add index fingerprint to object file
The new object files use indices for symbol references, instead
of names. Fundamental to the design, it requires that the
importing and imported packages have consistent view of symbol
indices. The Go command should already ensure this, when using
"go build". But in case it goes wrong, it could lead to obscure
errors like run-time crashes. It would be better to check the
index consistency at build time.
To do that, we add a fingerprint to each object file, which is
a hash of symbol indices. In the object file it records the
fingerprints of all imported packages, as well as its own
fingerprint. At link time, the linker checks that a package's
fingerprint matches the fingerprint recorded in the importing
packages, and issue an error if they don't match.
This CL does the first part: introducing the fingerprint in the
object file, and propagating fingerprints through
importing/exporting by the compiler. It is not yet used by the
linker. Next CL will do.
Change-Id: I0aa372da652e4afb11f2867cb71689a3e3f9966e
Reviewed-on: https://go-review.googlesource.com/c/go/+/229617
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-04-22 19:21:30 -04:00
|
|
|
fingerprint = iimport(importpkg, imp)
|
2016-03-11 14:28:16 -08:00
|
|
|
|
|
|
|
|
default:
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Errorf("no import in %q", path_)
|
|
|
|
|
base.ErrorExit()
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
2017-03-23 17:39:28 -07:00
|
|
|
|
[dev.link] cmd/internal/goobj2: add index fingerprint to object file
The new object files use indices for symbol references, instead
of names. Fundamental to the design, it requires that the
importing and imported packages have consistent view of symbol
indices. The Go command should already ensure this, when using
"go build". But in case it goes wrong, it could lead to obscure
errors like run-time crashes. It would be better to check the
index consistency at build time.
To do that, we add a fingerprint to each object file, which is
a hash of symbol indices. In the object file it records the
fingerprints of all imported packages, as well as its own
fingerprint. At link time, the linker checks that a package's
fingerprint matches the fingerprint recorded in the importing
packages, and issue an error if they don't match.
This CL does the first part: introducing the fingerprint in the
object file, and propagating fingerprints through
importing/exporting by the compiler. It is not yet used by the
linker. Next CL will do.
Change-Id: I0aa372da652e4afb11f2867cb71689a3e3f9966e
Reviewed-on: https://go-review.googlesource.com/c/go/+/229617
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-04-22 19:21:30 -04:00
|
|
|
// assume files move (get installed) so don't record the full path
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.Cfg.PackageFile != nil {
|
[dev.link] cmd/internal/goobj2: add index fingerprint to object file
The new object files use indices for symbol references, instead
of names. Fundamental to the design, it requires that the
importing and imported packages have consistent view of symbol
indices. The Go command should already ensure this, when using
"go build". But in case it goes wrong, it could lead to obscure
errors like run-time crashes. It would be better to check the
index consistency at build time.
To do that, we add a fingerprint to each object file, which is
a hash of symbol indices. In the object file it records the
fingerprints of all imported packages, as well as its own
fingerprint. At link time, the linker checks that a package's
fingerprint matches the fingerprint recorded in the importing
packages, and issue an error if they don't match.
This CL does the first part: introducing the fingerprint in the
object file, and propagating fingerprints through
importing/exporting by the compiler. It is not yet used by the
linker. Next CL will do.
Change-Id: I0aa372da652e4afb11f2867cb71689a3e3f9966e
Reviewed-on: https://go-review.googlesource.com/c/go/+/229617
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-04-22 19:21:30 -04:00
|
|
|
// If using a packageFile map, assume path_ can be recorded directly.
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Ctxt.AddImport(path_, fingerprint)
|
[dev.link] cmd/internal/goobj2: add index fingerprint to object file
The new object files use indices for symbol references, instead
of names. Fundamental to the design, it requires that the
importing and imported packages have consistent view of symbol
indices. The Go command should already ensure this, when using
"go build". But in case it goes wrong, it could lead to obscure
errors like run-time crashes. It would be better to check the
index consistency at build time.
To do that, we add a fingerprint to each object file, which is
a hash of symbol indices. In the object file it records the
fingerprints of all imported packages, as well as its own
fingerprint. At link time, the linker checks that a package's
fingerprint matches the fingerprint recorded in the importing
packages, and issue an error if they don't match.
This CL does the first part: introducing the fingerprint in the
object file, and propagating fingerprints through
importing/exporting by the compiler. It is not yet used by the
linker. Next CL will do.
Change-Id: I0aa372da652e4afb11f2867cb71689a3e3f9966e
Reviewed-on: https://go-review.googlesource.com/c/go/+/229617
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-04-22 19:21:30 -04:00
|
|
|
} else {
|
|
|
|
|
// For file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a".
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Ctxt.AddImport(file[len(file)-len(path_)-len(".a"):], fingerprint)
|
[dev.link] cmd/internal/goobj2: add index fingerprint to object file
The new object files use indices for symbol references, instead
of names. Fundamental to the design, it requires that the
importing and imported packages have consistent view of symbol
indices. The Go command should already ensure this, when using
"go build". But in case it goes wrong, it could lead to obscure
errors like run-time crashes. It would be better to check the
index consistency at build time.
To do that, we add a fingerprint to each object file, which is
a hash of symbol indices. In the object file it records the
fingerprints of all imported packages, as well as its own
fingerprint. At link time, the linker checks that a package's
fingerprint matches the fingerprint recorded in the importing
packages, and issue an error if they don't match.
This CL does the first part: introducing the fingerprint in the
object file, and propagating fingerprints through
importing/exporting by the compiler. It is not yet used by the
linker. Next CL will do.
Change-Id: I0aa372da652e4afb11f2867cb71689a3e3f9966e
Reviewed-on: https://go-review.googlesource.com/c/go/+/229617
Reviewed-by: Austin Clements <austin@google.com>
Reviewed-by: Than McIntosh <thanm@google.com>
Reviewed-by: Jeremy Faller <jeremy@golang.org>
2020-04-22 19:21:30 -04:00
|
|
|
}
|
|
|
|
|
|
2018-04-05 14:29:32 -07:00
|
|
|
if importpkg.Height >= myheight {
|
|
|
|
|
myheight = importpkg.Height + 1
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-23 17:39:28 -07:00
|
|
|
return importpkg
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
|
2016-12-15 17:17:01 -08:00
|
|
|
func pkgnotused(lineno src.XPos, path string, name string) {
|
2016-03-11 14:28:16 -08:00
|
|
|
// If the package was imported with a name other than the final
|
|
|
|
|
// import path element, show it explicitly in the error message.
|
|
|
|
|
// Note that this handles both renamed imports and imports of
|
|
|
|
|
// packages containing unconventional package declarations.
|
|
|
|
|
// Note that this uses / always, even on Windows, because Go import
|
|
|
|
|
// paths always use forward slashes.
|
|
|
|
|
elem := path
|
|
|
|
|
if i := strings.LastIndex(elem, "/"); i >= 0 {
|
|
|
|
|
elem = elem[i+1:]
|
|
|
|
|
}
|
|
|
|
|
if name == "" || elem == name {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.ErrorfAt(lineno, "imported and not used: %q", path)
|
2016-03-11 14:28:16 -08:00
|
|
|
} else {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.ErrorfAt(lineno, "imported and not used: %q as %s", path, name)
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func mkpackage(pkgname string) {
|
2020-12-06 13:54:50 -05:00
|
|
|
if types.LocalPkg.Name == "" {
|
2016-03-11 14:28:16 -08:00
|
|
|
if pkgname == "_" {
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Errorf("invalid package name _")
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
2020-12-06 13:54:50 -05:00
|
|
|
types.LocalPkg.Name = pkgname
|
2016-03-11 14:28:16 -08:00
|
|
|
} else {
|
2020-12-06 13:54:50 -05:00
|
|
|
if pkgname != types.LocalPkg.Name {
|
|
|
|
|
base.Errorf("package %s; expected %s", pkgname, types.LocalPkg.Name)
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
2017-01-11 15:20:38 -08:00
|
|
|
}
|
|
|
|
|
}
|
2016-03-11 14:28:16 -08:00
|
|
|
|
2017-01-11 15:20:38 -08:00
|
|
|
func clearImports() {
|
2017-05-09 08:22:43 -07:00
|
|
|
type importedPkg struct {
|
|
|
|
|
pos src.XPos
|
|
|
|
|
path string
|
|
|
|
|
name string
|
|
|
|
|
}
|
|
|
|
|
var unused []importedPkg
|
|
|
|
|
|
2020-12-06 13:54:50 -05:00
|
|
|
for _, s := range types.LocalPkg.Syms {
|
[dev.regabi] cmd/compile: introduce cmd/compile/internal/ir [generated]
If we want to break up package gc at all, we will need to move
the compiler IR it defines into a separate package that can be
imported by packages that gc itself imports. This CL does that.
It also removes the TINT8 etc aliases so that all code is clear
about which package things are coming from.
This CL is automatically generated by the script below.
See the comments in the script for details about the changes.
[git-generate]
cd src/cmd/compile/internal/gc
rf '
# These names were never fully qualified
# when the types package was added.
# Do it now, to avoid confusion about where they live.
inline -rm \
Txxx \
TINT8 \
TUINT8 \
TINT16 \
TUINT16 \
TINT32 \
TUINT32 \
TINT64 \
TUINT64 \
TINT \
TUINT \
TUINTPTR \
TCOMPLEX64 \
TCOMPLEX128 \
TFLOAT32 \
TFLOAT64 \
TBOOL \
TPTR \
TFUNC \
TSLICE \
TARRAY \
TSTRUCT \
TCHAN \
TMAP \
TINTER \
TFORW \
TANY \
TSTRING \
TUNSAFEPTR \
TIDEAL \
TNIL \
TBLANK \
TFUNCARGS \
TCHANARGS \
NTYPE \
BADWIDTH
# esc.go and escape.go do not need to be split.
# Append esc.go onto the end of escape.go.
mv esc.go escape.go
# Pull out the type format installation from func Main,
# so it can be carried into package ir.
mv Main:/Sconv.=/-0,/TypeLinkSym/-1 InstallTypeFormats
# Names that need to be exported for use by code left in gc.
mv Isconst IsConst
mv asNode AsNode
mv asNodes AsNodes
mv asTypesNode AsTypesNode
mv basicnames BasicTypeNames
mv builtinpkg BuiltinPkg
mv consttype ConstType
mv dumplist DumpList
mv fdumplist FDumpList
mv fmtMode FmtMode
mv goopnames OpNames
mv inspect Inspect
mv inspectList InspectList
mv localpkg LocalPkg
mv nblank BlankNode
mv numImport NumImport
mv opprec OpPrec
mv origSym OrigSym
mv stmtwithinit StmtWithInit
mv dump DumpAny
mv fdump FDumpAny
mv nod Nod
mv nodl NodAt
mv newname NewName
mv newnamel NewNameAt
mv assertRepresents AssertValidTypeForConst
mv represents ValidTypeForConst
mv nodlit NewLiteral
# Types and fields that need to be exported for use by gc.
mv nowritebarrierrecCallSym SymAndPos
mv SymAndPos.lineno SymAndPos.Pos
mv SymAndPos.target SymAndPos.Sym
mv Func.lsym Func.LSym
mv Func.setWBPos Func.SetWBPos
mv Func.numReturns Func.NumReturns
mv Func.numDefers Func.NumDefers
mv Func.nwbrCalls Func.NWBRCalls
# initLSym is an algorithm left behind in gc,
# not an operation on Func itself.
mv Func.initLSym initLSym
mv nodeQueue NodeQueue
mv NodeQueue.empty NodeQueue.Empty
mv NodeQueue.popLeft NodeQueue.PopLeft
mv NodeQueue.pushRight NodeQueue.PushRight
# Many methods on Node are actually algorithms that
# would apply to any node implementation.
# Those become plain functions.
mv Node.funcname FuncName
mv Node.isBlank IsBlank
mv Node.isGoConst isGoConst
mv Node.isNil IsNil
mv Node.isParamHeapCopy isParamHeapCopy
mv Node.isParamStackCopy isParamStackCopy
mv Node.isSimpleName isSimpleName
mv Node.mayBeShared MayBeShared
mv Node.pkgFuncName PkgFuncName
mv Node.backingArrayPtrLen backingArrayPtrLen
mv Node.isterminating isTermNode
mv Node.labeledControl labeledControl
mv Nodes.isterminating isTermNodes
mv Nodes.sigerr fmtSignature
mv Node.MethodName methodExprName
mv Node.MethodFunc methodExprFunc
mv Node.IsMethod IsMethod
# Every node will need to implement RawCopy;
# Copy and SepCopy algorithms will use it.
mv Node.rawcopy Node.RawCopy
mv Node.copy Copy
mv Node.sepcopy SepCopy
# Extract Node.Format method body into func FmtNode,
# but leave method wrapper behind.
mv Node.Format:0,$ FmtNode
# Formatting helpers that will apply to all node implementations.
mv Node.Line Line
mv Node.exprfmt exprFmt
mv Node.jconv jconvFmt
mv Node.modeString modeString
mv Node.nconv nconvFmt
mv Node.nodedump nodeDumpFmt
mv Node.nodefmt nodeFmt
mv Node.stmtfmt stmtFmt
# Constant support needed for code moving to ir.
mv okforconst OKForConst
mv vconv FmtConst
mv int64Val Int64Val
mv float64Val Float64Val
mv Node.ValueInterface ConstValue
# Organize code into files.
mv LocalPkg BuiltinPkg ir.go
mv NumImport InstallTypeFormats Line fmt.go
mv syntax.go Nod NodAt NewNameAt Class Pxxx PragmaFlag Nointerface SymAndPos \
AsNode AsTypesNode BlankNode OrigSym \
Node.SliceBounds Node.SetSliceBounds Op.IsSlice3 \
IsConst Node.Int64Val Node.CanInt64 Node.Uint64Val Node.BoolVal Node.StringVal \
Node.RawCopy SepCopy Copy \
IsNil IsBlank IsMethod \
Node.Typ Node.StorageClass node.go
mv ConstType ConstValue Int64Val Float64Val AssertValidTypeForConst ValidTypeForConst NewLiteral idealType OKForConst val.go
# Move files to new ir package.
mv bitset.go class_string.go dump.go fmt.go \
ir.go node.go op_string.go val.go \
sizeof_test.go cmd/compile/internal/ir
'
: # fix mkbuiltin.go to generate the changes made to builtin.go during rf
sed -i '' '
s/\[T/[types.T/g
s/\*Node/*ir.Node/g
/internal\/types/c \
fmt.Fprintln(&b, `import (`) \
fmt.Fprintln(&b, ` "cmd/compile/internal/ir"`) \
fmt.Fprintln(&b, ` "cmd/compile/internal/types"`) \
fmt.Fprintln(&b, `)`)
' mkbuiltin.go
gofmt -w mkbuiltin.go
: # update cmd/dist to add internal/ir
cd ../../../dist
sed -i '' '/compile.internal.gc/a\
"cmd/compile/internal/ir",
' buildtool.go
gofmt -w buildtool.go
: # update cmd/compile TestFormats
cd ../..
go install std cmd
cd cmd/compile
go test -u || go test # first one updates but fails; second passes
Change-Id: I5f7caf6b20629b51970279e81231a3574d5b51db
Reviewed-on: https://go-review.googlesource.com/c/go/+/273008
Trust: Russ Cox <rsc@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2020-11-19 21:09:22 -05:00
|
|
|
n := ir.AsNode(s.Def)
|
2017-05-09 08:22:43 -07:00
|
|
|
if n == nil {
|
2017-01-11 15:20:38 -08:00
|
|
|
continue
|
|
|
|
|
}
|
2020-11-22 09:59:15 -05:00
|
|
|
if n.Op() == ir.OPACK {
|
2017-05-09 08:22:43 -07:00
|
|
|
// throw away top-level package name left over
|
2017-01-11 15:20:38 -08:00
|
|
|
// from previous file.
|
|
|
|
|
// leave s->block set to cause redeclaration
|
|
|
|
|
// errors if a conflicting top-level name is
|
|
|
|
|
// introduced by a different file.
|
2020-11-28 01:11:49 -05:00
|
|
|
p := n.(*ir.PkgName)
|
|
|
|
|
if !p.Used && base.SyntaxErrors() == 0 {
|
|
|
|
|
unused = append(unused, importedPkg{p.Pos(), p.Pkg.Path, s.Name})
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
2017-01-11 15:20:38 -08:00
|
|
|
s.Def = nil
|
|
|
|
|
continue
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
cmd/compile: factor out Pkg, Sym, and Type into package types
- created new package cmd/compile/internal/types
- moved Pkg, Sym, Type to new package
- to break cycles, for now we need the (ugly) types/utils.go
file which contains a handful of functions that must be installed
early by the gc frontend
- to break cycles, for now we need two functions to convert between
*gc.Node and *types.Node (the latter is a dummy type)
- adjusted the gc's code to use the new package and the conversion
functions as needed
- made several Pkg, Sym, and Type methods functions as needed
- renamed constructors typ, typPtr, typArray, etc. to types.New,
types.NewPtr, types.NewArray, etc.
Passes toolstash-check -all.
Change-Id: I8adfa5e85c731645d0a7fd2030375ed6ebf54b72
Reviewed-on: https://go-review.googlesource.com/39855
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-04-04 17:54:02 -07:00
|
|
|
if IsAlias(s) {
|
2017-01-11 15:20:38 -08:00
|
|
|
// throw away top-level name left over
|
|
|
|
|
// from previous import . "x"
|
2020-12-13 10:35:20 -08:00
|
|
|
// We'll report errors after type checking in checkDotImports.
|
2017-01-11 15:20:38 -08:00
|
|
|
s.Def = nil
|
|
|
|
|
continue
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
|
|
|
|
}
|
2017-05-09 08:22:43 -07:00
|
|
|
|
2019-04-30 15:23:14 -04:00
|
|
|
sort.Slice(unused, func(i, j int) bool { return unused[i].pos.Before(unused[j].pos) })
|
2017-05-09 08:22:43 -07:00
|
|
|
for _, pkg := range unused {
|
|
|
|
|
pkgnotused(pkg.pos, pkg.path, pkg.name)
|
|
|
|
|
}
|
2016-03-11 14:28:16 -08:00
|
|
|
}
|
cmd/compile: factor out Pkg, Sym, and Type into package types
- created new package cmd/compile/internal/types
- moved Pkg, Sym, Type to new package
- to break cycles, for now we need the (ugly) types/utils.go
file which contains a handful of functions that must be installed
early by the gc frontend
- to break cycles, for now we need two functions to convert between
*gc.Node and *types.Node (the latter is a dummy type)
- adjusted the gc's code to use the new package and the conversion
functions as needed
- made several Pkg, Sym, and Type methods functions as needed
- renamed constructors typ, typPtr, typArray, etc. to types.New,
types.NewPtr, types.NewArray, etc.
Passes toolstash-check -all.
Change-Id: I8adfa5e85c731645d0a7fd2030375ed6ebf54b72
Reviewed-on: https://go-review.googlesource.com/39855
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-04-04 17:54:02 -07:00
|
|
|
|
|
|
|
|
func IsAlias(sym *types.Sym) bool {
|
2020-12-01 11:37:30 -08:00
|
|
|
return sym.Def != nil && sym.Def.Sym() != sym
|
cmd/compile: factor out Pkg, Sym, and Type into package types
- created new package cmd/compile/internal/types
- moved Pkg, Sym, Type to new package
- to break cycles, for now we need the (ugly) types/utils.go
file which contains a handful of functions that must be installed
early by the gc frontend
- to break cycles, for now we need two functions to convert between
*gc.Node and *types.Node (the latter is a dummy type)
- adjusted the gc's code to use the new package and the conversion
functions as needed
- made several Pkg, Sym, and Type methods functions as needed
- renamed constructors typ, typPtr, typArray, etc. to types.New,
types.NewPtr, types.NewArray, etc.
Passes toolstash-check -all.
Change-Id: I8adfa5e85c731645d0a7fd2030375ed6ebf54b72
Reviewed-on: https://go-review.googlesource.com/39855
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2017-04-04 17:54:02 -07:00
|
|
|
}
|
cmd/compile: add initial backend concurrency support
This CL adds initial support for concurrent backend compilation.
BACKGROUND
The compiler currently consists (very roughly) of the following phases:
1. Initialization.
2. Lexing and parsing into the cmd/compile/internal/syntax AST.
3. Translation into the cmd/compile/internal/gc AST.
4. Some gc AST passes: typechecking, escape analysis, inlining,
closure handling, expression evaluation ordering (order.go),
and some lowering and optimization (walk.go).
5. Translation into the cmd/compile/internal/ssa SSA form.
6. Optimization and lowering of SSA form.
7. Translation from SSA form to assembler instructions.
8. Translation from assembler instructions to machine code.
9. Writing lots of output: machine code, DWARF symbols,
type and reflection info, export data.
Phase 2 was already concurrent as of Go 1.8.
Phase 3 is planned for eventual removal;
we hope to go straight from syntax AST to SSA.
Phases 5–8 are per-function; this CL adds support for
processing multiple functions concurrently.
The slowest phases in the compiler are 5 and 6,
so this offers the opportunity for some good speed-ups.
Unfortunately, it's not quite that straightforward.
In the current compiler, the latter parts of phase 4
(order, walk) are done function-at-a-time as needed.
Making order and walk concurrency-safe proved hard,
and they're not particularly slow, so there wasn't much reward.
To enable phases 5–8 to be done concurrently,
when concurrent backend compilation is requested,
we complete phase 4 for all functions
before starting later phases for any functions.
Also, in reality, we automatically generate new
functions in phase 9, such as method wrappers
and equality and has routines.
Those new functions then go through phases 4–8.
This CL disables concurrent backend compilation
after the first, big, user-provided batch of
functions has been compiled.
This is done to keep things simple,
and because the autogenerated functions
tend to be small, few, simple, and fast to compile.
USAGE
Concurrent backend compilation still defaults to off.
To set the number of functions that may be backend-compiled
concurrently, use the compiler flag -c.
In future work, cmd/go will automatically set -c.
Furthermore, this CL has been intentionally written
so that the c=1 path has no backend concurrency whatsoever,
not even spawning any goroutines.
This helps ensure that, should problems arise
late in the development cycle,
we can simply have cmd/go set c=1 always,
and revert to the original compiler behavior.
MUTEXES
Most of the work required to make concurrent backend
compilation safe has occurred over the past month.
This CL adds a handful of mutexes to get the rest of the way there;
they are the mutexes that I didn't see a clean way to avoid.
Some of them may still be eliminable in future work.
In no particular order:
* gc.funcsymsmu. The global funcsyms slice is populated
lazily when we need function symbols for closures.
This occurs during gc AST to SSA translation.
The function funcsym also does a package lookup,
which is a source of races on types.Pkg.Syms;
funcsymsmu also covers that package lookup.
This mutex is low priority: it adds a single global,
it is in an infrequently used code path, and it is low contention.
Since funcsyms may now be added in any order,
we must sort them to preserve reproducible builds.
* gc.largeStackFramesMu. We don't discover until after SSA compilation
that a function's stack frame is gigantic.
Recording that error happens basically never,
but it does happen concurrently.
Fix with a low priority mutex and sorting.
* obj.Link.hashmu. ctxt.hash stores the mapping from
types.Syms (compiler symbols) to obj.LSyms (linker symbols).
It is accessed fairly heavily through all the phases.
This is the only heavily contended mutex.
* gc.signatlistmu. The global signatlist map is
populated with types through several of the concurrent phases,
including notably via ngotype during DWARF generation.
It is low priority for removal.
* gc.typepkgmu. Looking up symbols in the types package
happens a fair amount during backend compilation
and DWARF generation, particularly via ngotype.
This mutex helps us to avoid a broader mutex on types.Pkg.Syms.
It has low-to-moderate contention.
* types.internedStringsmu. gc AST to SSA conversion and
some SSA work introduce new autotmps.
Those autotmps have their names interned to reduce allocations.
That interning requires protecting types.internedStrings.
The autotmp names are heavily re-used, and the mutex
overhead and contention here are low, so it is probably
a worthwhile performance optimization to keep this mutex.
TESTING
I have been testing this code locally by running
'go install -race cmd/compile'
and then doing
'go build -a -gcflags=-c=128 std cmd'
for all architectures and a variety of compiler flags.
This obviously needs to be made part of the builders,
but it is too expensive to make part of all.bash.
I have filed #19962 for this.
REPRODUCIBLE BUILDS
This version of the compiler generates reproducible builds.
Testing reproducible builds also needs automation, however,
and is also too expensive for all.bash.
This is #19961.
Also of note is that some of the compiler flags used by 'toolstash -cmp'
are currently incompatible with concurrent backend compilation.
They still work fine with c=1.
Time will tell whether this is a problem.
NEXT STEPS
* Continue to find and fix races and bugs,
using a combination of code inspection, fuzzing,
and hopefully some community experimentation.
I do not know of any outstanding races,
but there probably are some.
* Improve testing.
* Improve performance, for many values of c.
* Integrate with cmd/go and fine tune.
* Support concurrent compilation with the -race flag.
It is a sad irony that it does not yet work.
* Minor code cleanup that has been deferred during
the last month due to uncertainty about the
ultimate shape of this CL.
PERFORMANCE
Here's the buried lede, at last. :)
All benchmarks are from my 8 core 2.9 GHz Intel Core i7 darwin/amd64 laptop.
First, going from tip to this CL with c=1 has almost no impact.
name old time/op new time/op delta
Template 195ms ± 3% 194ms ± 5% ~ (p=0.370 n=30+29)
Unicode 86.6ms ± 3% 87.0ms ± 7% ~ (p=0.958 n=29+30)
GoTypes 548ms ± 3% 555ms ± 4% +1.35% (p=0.001 n=30+28)
Compiler 2.51s ± 2% 2.54s ± 2% +1.17% (p=0.000 n=28+30)
SSA 5.16s ± 3% 5.16s ± 2% ~ (p=0.910 n=30+29)
Flate 124ms ± 5% 124ms ± 4% ~ (p=0.947 n=30+30)
GoParser 146ms ± 3% 146ms ± 3% ~ (p=0.150 n=29+28)
Reflect 354ms ± 3% 352ms ± 4% ~ (p=0.096 n=29+29)
Tar 107ms ± 5% 106ms ± 3% ~ (p=0.370 n=30+29)
XML 200ms ± 4% 201ms ± 4% ~ (p=0.313 n=29+28)
[Geo mean] 332ms 333ms +0.10%
name old user-time/op new user-time/op delta
Template 227ms ± 5% 225ms ± 5% ~ (p=0.457 n=28+27)
Unicode 109ms ± 4% 109ms ± 5% ~ (p=0.758 n=29+29)
GoTypes 713ms ± 4% 721ms ± 5% ~ (p=0.051 n=30+29)
Compiler 3.36s ± 2% 3.38s ± 3% ~ (p=0.146 n=30+30)
SSA 7.46s ± 3% 7.47s ± 3% ~ (p=0.804 n=30+29)
Flate 146ms ± 7% 147ms ± 3% ~ (p=0.833 n=29+27)
GoParser 179ms ± 5% 179ms ± 5% ~ (p=0.866 n=30+30)
Reflect 431ms ± 4% 429ms ± 4% ~ (p=0.593 n=29+30)
Tar 124ms ± 5% 123ms ± 5% ~ (p=0.140 n=29+29)
XML 243ms ± 4% 242ms ± 7% ~ (p=0.404 n=29+29)
[Geo mean] 415ms 415ms +0.02%
name old obj-bytes new obj-bytes delta
Template 382k ± 0% 382k ± 0% ~ (all equal)
Unicode 203k ± 0% 203k ± 0% ~ (all equal)
GoTypes 1.18M ± 0% 1.18M ± 0% ~ (all equal)
Compiler 3.98M ± 0% 3.98M ± 0% ~ (all equal)
SSA 8.28M ± 0% 8.28M ± 0% ~ (all equal)
Flate 230k ± 0% 230k ± 0% ~ (all equal)
GoParser 287k ± 0% 287k ± 0% ~ (all equal)
Reflect 1.00M ± 0% 1.00M ± 0% ~ (all equal)
Tar 190k ± 0% 190k ± 0% ~ (all equal)
XML 416k ± 0% 416k ± 0% ~ (all equal)
[Geo mean] 660k 660k +0.00%
Comparing this CL to itself, from c=1 to c=2
improves real times 20-30%, costs 5-10% more CPU time,
and adds about 2% alloc.
The allocation increase comes from allocating more ssa.Caches.
name old time/op new time/op delta
Template 202ms ± 3% 149ms ± 3% -26.15% (p=0.000 n=49+49)
Unicode 87.4ms ± 4% 84.2ms ± 3% -3.68% (p=0.000 n=48+48)
GoTypes 560ms ± 2% 398ms ± 2% -28.96% (p=0.000 n=49+49)
Compiler 2.46s ± 3% 1.76s ± 2% -28.61% (p=0.000 n=48+46)
SSA 6.17s ± 2% 4.04s ± 1% -34.52% (p=0.000 n=49+49)
Flate 126ms ± 3% 92ms ± 2% -26.81% (p=0.000 n=49+48)
GoParser 148ms ± 4% 107ms ± 2% -27.78% (p=0.000 n=49+48)
Reflect 361ms ± 3% 281ms ± 3% -22.10% (p=0.000 n=49+49)
Tar 109ms ± 4% 86ms ± 3% -20.81% (p=0.000 n=49+47)
XML 204ms ± 3% 144ms ± 2% -29.53% (p=0.000 n=48+45)
name old user-time/op new user-time/op delta
Template 246ms ± 9% 246ms ± 4% ~ (p=0.401 n=50+48)
Unicode 109ms ± 4% 111ms ± 4% +1.47% (p=0.000 n=44+50)
GoTypes 728ms ± 3% 765ms ± 3% +5.04% (p=0.000 n=46+50)
Compiler 3.33s ± 3% 3.41s ± 2% +2.31% (p=0.000 n=49+48)
SSA 8.52s ± 2% 9.11s ± 2% +6.93% (p=0.000 n=49+47)
Flate 149ms ± 4% 161ms ± 3% +8.13% (p=0.000 n=50+47)
GoParser 181ms ± 5% 192ms ± 2% +6.40% (p=0.000 n=49+46)
Reflect 452ms ± 9% 474ms ± 2% +4.99% (p=0.000 n=50+48)
Tar 126ms ± 6% 136ms ± 4% +7.95% (p=0.000 n=50+49)
XML 247ms ± 5% 264ms ± 3% +6.94% (p=0.000 n=48+50)
name old alloc/op new alloc/op delta
Template 38.8MB ± 0% 39.3MB ± 0% +1.48% (p=0.008 n=5+5)
Unicode 29.8MB ± 0% 30.2MB ± 0% +1.19% (p=0.008 n=5+5)
GoTypes 113MB ± 0% 114MB ± 0% +0.69% (p=0.008 n=5+5)
Compiler 443MB ± 0% 447MB ± 0% +0.95% (p=0.008 n=5+5)
SSA 1.25GB ± 0% 1.26GB ± 0% +0.89% (p=0.008 n=5+5)
Flate 25.3MB ± 0% 25.9MB ± 1% +2.35% (p=0.008 n=5+5)
GoParser 31.7MB ± 0% 32.2MB ± 0% +1.59% (p=0.008 n=5+5)
Reflect 78.2MB ± 0% 78.9MB ± 0% +0.91% (p=0.008 n=5+5)
Tar 26.6MB ± 0% 27.0MB ± 0% +1.80% (p=0.008 n=5+5)
XML 42.4MB ± 0% 43.4MB ± 0% +2.35% (p=0.008 n=5+5)
name old allocs/op new allocs/op delta
Template 379k ± 0% 378k ± 0% ~ (p=0.421 n=5+5)
Unicode 322k ± 0% 321k ± 0% ~ (p=0.222 n=5+5)
GoTypes 1.14M ± 0% 1.14M ± 0% ~ (p=0.548 n=5+5)
Compiler 4.12M ± 0% 4.11M ± 0% -0.14% (p=0.032 n=5+5)
SSA 9.72M ± 0% 9.72M ± 0% ~ (p=0.421 n=5+5)
Flate 234k ± 1% 234k ± 0% ~ (p=0.421 n=5+5)
GoParser 316k ± 1% 315k ± 0% ~ (p=0.222 n=5+5)
Reflect 980k ± 0% 979k ± 0% ~ (p=0.095 n=5+5)
Tar 249k ± 1% 249k ± 1% ~ (p=0.841 n=5+5)
XML 392k ± 0% 391k ± 0% ~ (p=0.095 n=5+5)
From c=1 to c=4, real time is down ~40%, CPU usage up 10-20%, alloc up ~5%:
name old time/op new time/op delta
Template 203ms ± 3% 131ms ± 5% -35.45% (p=0.000 n=50+50)
Unicode 87.2ms ± 4% 84.1ms ± 2% -3.61% (p=0.000 n=48+47)
GoTypes 560ms ± 4% 310ms ± 2% -44.65% (p=0.000 n=50+49)
Compiler 2.47s ± 3% 1.41s ± 2% -43.10% (p=0.000 n=50+46)
SSA 6.17s ± 2% 3.20s ± 2% -48.06% (p=0.000 n=49+49)
Flate 126ms ± 4% 74ms ± 2% -41.06% (p=0.000 n=49+48)
GoParser 148ms ± 4% 89ms ± 3% -39.97% (p=0.000 n=49+50)
Reflect 360ms ± 3% 242ms ± 3% -32.81% (p=0.000 n=49+49)
Tar 108ms ± 4% 73ms ± 4% -32.48% (p=0.000 n=50+49)
XML 203ms ± 3% 119ms ± 3% -41.56% (p=0.000 n=49+48)
name old user-time/op new user-time/op delta
Template 246ms ± 9% 287ms ± 9% +16.98% (p=0.000 n=50+50)
Unicode 109ms ± 4% 118ms ± 5% +7.56% (p=0.000 n=46+50)
GoTypes 735ms ± 4% 806ms ± 2% +9.62% (p=0.000 n=50+50)
Compiler 3.34s ± 4% 3.56s ± 2% +6.78% (p=0.000 n=49+49)
SSA 8.54s ± 3% 10.04s ± 3% +17.55% (p=0.000 n=50+50)
Flate 149ms ± 6% 176ms ± 3% +17.82% (p=0.000 n=50+48)
GoParser 181ms ± 5% 213ms ± 3% +17.47% (p=0.000 n=50+50)
Reflect 453ms ± 6% 499ms ± 2% +10.11% (p=0.000 n=50+48)
Tar 126ms ± 5% 149ms ±11% +18.76% (p=0.000 n=50+50)
XML 246ms ± 5% 287ms ± 4% +16.53% (p=0.000 n=49+50)
name old alloc/op new alloc/op delta
Template 38.8MB ± 0% 40.4MB ± 0% +4.21% (p=0.008 n=5+5)
Unicode 29.8MB ± 0% 30.9MB ± 0% +3.68% (p=0.008 n=5+5)
GoTypes 113MB ± 0% 116MB ± 0% +2.71% (p=0.008 n=5+5)
Compiler 443MB ± 0% 455MB ± 0% +2.75% (p=0.008 n=5+5)
SSA 1.25GB ± 0% 1.27GB ± 0% +1.84% (p=0.008 n=5+5)
Flate 25.3MB ± 0% 26.9MB ± 1% +6.31% (p=0.008 n=5+5)
GoParser 31.7MB ± 0% 33.2MB ± 0% +4.61% (p=0.008 n=5+5)
Reflect 78.2MB ± 0% 80.2MB ± 0% +2.53% (p=0.008 n=5+5)
Tar 26.6MB ± 0% 27.9MB ± 0% +5.19% (p=0.008 n=5+5)
XML 42.4MB ± 0% 44.6MB ± 0% +5.20% (p=0.008 n=5+5)
name old allocs/op new allocs/op delta
Template 380k ± 0% 379k ± 0% -0.39% (p=0.032 n=5+5)
Unicode 321k ± 0% 321k ± 0% ~ (p=0.841 n=5+5)
GoTypes 1.14M ± 0% 1.14M ± 0% ~ (p=0.421 n=5+5)
Compiler 4.12M ± 0% 4.14M ± 0% +0.52% (p=0.008 n=5+5)
SSA 9.72M ± 0% 9.76M ± 0% +0.37% (p=0.008 n=5+5)
Flate 234k ± 1% 234k ± 1% ~ (p=0.690 n=5+5)
GoParser 316k ± 0% 317k ± 1% ~ (p=0.841 n=5+5)
Reflect 981k ± 0% 981k ± 0% ~ (p=1.000 n=5+5)
Tar 250k ± 0% 249k ± 1% ~ (p=0.151 n=5+5)
XML 393k ± 0% 392k ± 0% ~ (p=0.056 n=5+5)
Going beyond c=4 on my machine tends to increase CPU time and allocs
without impacting real time.
The CPU time numbers matter, because when there are many concurrent
compilation processes, that will impact the overall throughput.
The numbers above are in many ways the best case scenario;
we can take full advantage of all cores.
Fortunately, the most common compilation scenario is incremental
re-compilation of a single package during a build/test cycle.
Updates #15756
Change-Id: I6725558ca2069edec0ac5b0d1683105a9fff6bea
Reviewed-on: https://go-review.googlesource.com/40693
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2017-03-19 08:27:26 -07:00
|
|
|
|
2017-10-17 17:09:54 -04:00
|
|
|
// recordFlags records the specified command-line flags to be placed
|
|
|
|
|
// in the DWARF info.
|
|
|
|
|
func recordFlags(flags ...string) {
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Ctxt.Pkgpath == "" {
|
2017-10-17 17:09:54 -04:00
|
|
|
// We can't record the flags if we don't know what the
|
|
|
|
|
// package name is.
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type BoolFlag interface {
|
|
|
|
|
IsBoolFlag() bool
|
|
|
|
|
}
|
|
|
|
|
type CountFlag interface {
|
|
|
|
|
IsCountFlag() bool
|
|
|
|
|
}
|
|
|
|
|
var cmd bytes.Buffer
|
|
|
|
|
for _, name := range flags {
|
|
|
|
|
f := flag.Lookup(name)
|
|
|
|
|
if f == nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
getter := f.Value.(flag.Getter)
|
|
|
|
|
if getter.String() == f.DefValue {
|
|
|
|
|
// Flag has default value, so omit it.
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if bf, ok := f.Value.(BoolFlag); ok && bf.IsBoolFlag() {
|
|
|
|
|
val, ok := getter.Get().(bool)
|
|
|
|
|
if ok && val {
|
|
|
|
|
fmt.Fprintf(&cmd, " -%s", f.Name)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if cf, ok := f.Value.(CountFlag); ok && cf.IsCountFlag() {
|
|
|
|
|
val, ok := getter.Get().(int)
|
|
|
|
|
if ok && val == 1 {
|
|
|
|
|
fmt.Fprintf(&cmd, " -%s", f.Name)
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(&cmd, " -%s=%v", f.Name, getter.Get())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cmd.Len() == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
2020-11-19 20:49:23 -05:00
|
|
|
s := base.Ctxt.Lookup(dwarf.CUInfoPrefix + "producer." + base.Ctxt.Pkgpath)
|
2020-05-20 13:51:59 -04:00
|
|
|
s.Type = objabi.SDWARFCUINFO
|
2017-10-18 20:14:29 -04:00
|
|
|
// Sometimes (for example when building tests) we can link
|
|
|
|
|
// together two package main archives. So allow dups.
|
|
|
|
|
s.Set(obj.AttrDuplicateOK, true)
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Ctxt.Data = append(base.Ctxt.Data, s)
|
2017-10-17 17:09:54 -04:00
|
|
|
s.P = cmd.Bytes()[1:]
|
|
|
|
|
}
|
2018-10-24 15:49:32 -07:00
|
|
|
|
2019-02-25 13:56:18 +01:00
|
|
|
// recordPackageName records the name of the package being
|
|
|
|
|
// compiled, so that the linker can save it in the compile unit's DIE.
|
|
|
|
|
func recordPackageName() {
|
2020-11-19 20:49:23 -05:00
|
|
|
s := base.Ctxt.Lookup(dwarf.CUInfoPrefix + "packagename." + base.Ctxt.Pkgpath)
|
2020-05-20 13:51:59 -04:00
|
|
|
s.Type = objabi.SDWARFCUINFO
|
2019-02-25 13:56:18 +01:00
|
|
|
// Sometimes (for example when building tests) we can link
|
|
|
|
|
// together two package main archives. So allow dups.
|
|
|
|
|
s.Set(obj.AttrDuplicateOK, true)
|
2020-11-19 20:49:23 -05:00
|
|
|
base.Ctxt.Data = append(base.Ctxt.Data, s)
|
2020-12-06 13:54:50 -05:00
|
|
|
s.P = []byte(types.LocalPkg.Name)
|
2019-02-25 13:56:18 +01:00
|
|
|
}
|
|
|
|
|
|
2018-11-13 15:36:02 -08:00
|
|
|
// currentLang returns the current language version.
|
|
|
|
|
func currentLang() string {
|
2019-04-19 16:09:17 +00:00
|
|
|
return fmt.Sprintf("go1.%d", goversion.Version)
|
2018-10-24 15:49:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// goVersionRE is a regular expression that matches the valid
|
|
|
|
|
// arguments to the -lang flag.
|
|
|
|
|
var goVersionRE = regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`)
|
|
|
|
|
|
|
|
|
|
// A lang is a language version broken into major and minor numbers.
|
|
|
|
|
type lang struct {
|
|
|
|
|
major, minor int
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// langWant is the desired language version set by the -lang flag.
|
2018-11-13 15:36:02 -08:00
|
|
|
// If the -lang flag is not set, this is the zero value, meaning that
|
|
|
|
|
// any language version is supported.
|
2018-10-24 15:49:32 -07:00
|
|
|
var langWant lang
|
|
|
|
|
|
2019-11-07 15:54:59 -08:00
|
|
|
// langSupported reports whether language version major.minor is
|
|
|
|
|
// supported in a particular package.
|
|
|
|
|
func langSupported(major, minor int, pkg *types.Pkg) bool {
|
|
|
|
|
if pkg == nil {
|
|
|
|
|
// TODO(mdempsky): Set Pkg for local types earlier.
|
2020-12-06 13:54:50 -05:00
|
|
|
pkg = types.LocalPkg
|
2019-11-07 15:54:59 -08:00
|
|
|
}
|
2020-12-06 13:54:50 -05:00
|
|
|
if pkg != types.LocalPkg {
|
2019-11-07 15:54:59 -08:00
|
|
|
// Assume imported packages passed type-checking.
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-13 15:36:02 -08:00
|
|
|
if langWant.major == 0 && langWant.minor == 0 {
|
|
|
|
|
return true
|
|
|
|
|
}
|
2018-10-24 15:49:32 -07:00
|
|
|
return langWant.major > major || (langWant.major == major && langWant.minor >= minor)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// checkLang verifies that the -lang flag holds a valid value, and
|
|
|
|
|
// exits if not. It initializes data used by langSupported.
|
|
|
|
|
func checkLang() {
|
2020-11-19 20:49:23 -05:00
|
|
|
if base.Flag.Lang == "" {
|
2018-11-13 15:36:02 -08:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-24 15:49:32 -07:00
|
|
|
var err error
|
2020-11-19 20:49:23 -05:00
|
|
|
langWant, err = parseLang(base.Flag.Lang)
|
2018-10-24 15:49:32 -07:00
|
|
|
if err != nil {
|
2020-11-19 20:49:23 -05:00
|
|
|
log.Fatalf("invalid value %q for -lang: %v", base.Flag.Lang, err)
|
2018-10-24 15:49:32 -07:00
|
|
|
}
|
|
|
|
|
|
2020-11-19 20:49:23 -05:00
|
|
|
if def := currentLang(); base.Flag.Lang != def {
|
2018-10-24 15:49:32 -07:00
|
|
|
defVers, err := parseLang(def)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("internal error parsing default lang %q: %v", def, err)
|
|
|
|
|
}
|
2018-11-12 10:38:02 -08:00
|
|
|
if langWant.major > defVers.major || (langWant.major == defVers.major && langWant.minor > defVers.minor) {
|
2020-11-19 20:49:23 -05:00
|
|
|
log.Fatalf("invalid value %q for -lang: max known version is %q", base.Flag.Lang, def)
|
2018-10-24 15:49:32 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// parseLang parses a -lang option into a langVer.
|
|
|
|
|
func parseLang(s string) (lang, error) {
|
|
|
|
|
matches := goVersionRE.FindStringSubmatch(s)
|
|
|
|
|
if matches == nil {
|
|
|
|
|
return lang{}, fmt.Errorf(`should be something like "go1.12"`)
|
|
|
|
|
}
|
|
|
|
|
major, err := strconv.Atoi(matches[1])
|
|
|
|
|
if err != nil {
|
|
|
|
|
return lang{}, err
|
|
|
|
|
}
|
|
|
|
|
minor, err := strconv.Atoi(matches[2])
|
|
|
|
|
if err != nil {
|
|
|
|
|
return lang{}, err
|
|
|
|
|
}
|
|
|
|
|
return lang{major: major, minor: minor}, nil
|
|
|
|
|
}
|
2020-11-24 18:09:00 -05:00
|
|
|
|
|
|
|
|
func initializeTypesPackage() {
|
|
|
|
|
types.Widthptr = Widthptr
|
|
|
|
|
types.Dowidth = dowidth
|
|
|
|
|
types.TypeLinkSym = func(t *types.Type) *obj.LSym {
|
|
|
|
|
return typenamesym(t).Linksym()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
initUniverse()
|
|
|
|
|
}
|