2015-02-13 14:40:36 -05: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.
|
|
|
|
|
|
|
|
|
|
package gc
|
|
|
|
|
|
|
|
|
|
import (
|
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"
|
2017-04-18 12:53:25 -07:00
|
|
|
"cmd/internal/objabi"
|
2016-12-06 17:08:06 -08:00
|
|
|
"cmd/internal/src"
|
2015-02-27 16:05:30 +09:00
|
|
|
"crypto/md5"
|
|
|
|
|
"encoding/binary"
|
2015-02-13 14:40:36 -05:00
|
|
|
"fmt"
|
|
|
|
|
"os"
|
2016-03-31 09:29:32 -07:00
|
|
|
"runtime/debug"
|
2015-02-13 14:40:36 -05:00
|
|
|
"sort"
|
2016-03-19 18:17:58 -07:00
|
|
|
"strconv"
|
2015-02-13 14:40:36 -05:00
|
|
|
"strings"
|
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
|
|
|
"sync"
|
2015-02-13 14:40:36 -05:00
|
|
|
"unicode"
|
|
|
|
|
"unicode/utf8"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type Error struct {
|
2016-12-15 17:17:01 -08:00
|
|
|
pos src.XPos
|
2016-12-07 17:40:46 -08:00
|
|
|
msg string
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var errors []Error
|
|
|
|
|
|
2018-10-25 06:23:54 -07:00
|
|
|
// largeStack is info about a function whose stack frame is too large (rare).
|
|
|
|
|
type largeStack struct {
|
|
|
|
|
locals int64
|
|
|
|
|
args int64
|
|
|
|
|
callee int64
|
|
|
|
|
pos src.XPos
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
var (
|
|
|
|
|
largeStackFramesMu sync.Mutex // protects largeStackFrames
|
2018-10-25 06:23:54 -07:00
|
|
|
largeStackFrames []largeStack
|
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
|
|
|
)
|
cmd/compile: rework reporting of oversized stack frames
We don't support stack frames over 2GB.
Rather than detect this during backend compilation,
check for it at the end of compilation.
This is arguably a more accurate check anyway,
since it takes into account the full frame,
including local stack, arguments, and arch-specific
rounding, although it's unlikely anyone would ever notice.
Also, rather than reporting the error right away,
take note of it and report it later, at the top level.
This is not relevant now, but it will help with making
the backend concurrent, as the append to the list of
oversized functions can be cheaply protected by a plain mutex.
Updates #15756
Updates #19250
Change-Id: Id3fa21906616d62e9dc66e27a17fd5f83304e96e
Reviewed-on: https://go-review.googlesource.com/38972
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
2017-03-30 11:46:45 -07:00
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
func errorexit() {
|
2016-09-15 15:45:10 +10:00
|
|
|
flusherrors()
|
2015-02-13 14:40:36 -05:00
|
|
|
if outfile != "" {
|
|
|
|
|
os.Remove(outfile)
|
|
|
|
|
}
|
|
|
|
|
os.Exit(2)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func adderrorname(n *Node) {
|
|
|
|
|
if n.Op != ODOT {
|
|
|
|
|
return
|
|
|
|
|
}
|
2015-04-17 12:03:22 -04:00
|
|
|
old := fmt.Sprintf("%v: undefined: %v\n", n.Line(), n.Left)
|
2016-12-07 17:40:46 -08:00
|
|
|
if len(errors) > 0 && errors[len(errors)-1].pos.Line() == n.Pos.Line() && errors[len(errors)-1].msg == old {
|
2015-04-17 12:03:22 -04:00
|
|
|
errors[len(errors)-1].msg = fmt.Sprintf("%v: undefined: %v in %v\n", n.Line(), n.Left, n)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-15 17:17:01 -08:00
|
|
|
func adderr(pos src.XPos, format string, args ...interface{}) {
|
2015-02-13 14:40:36 -05:00
|
|
|
errors = append(errors, Error{
|
2016-12-07 17:40:46 -08:00
|
|
|
pos: pos,
|
|
|
|
|
msg: fmt.Sprintf("%v: %s\n", linestr(pos), fmt.Sprintf(format, args...)),
|
2015-02-13 14:40:36 -05:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-07 17:40:46 -08:00
|
|
|
// byPos sorts errors by source position.
|
|
|
|
|
type byPos []Error
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-12-07 17:40:46 -08:00
|
|
|
func (x byPos) Len() int { return len(x) }
|
|
|
|
|
func (x byPos) Less(i, j int) bool { return x[i].pos.Before(x[j].pos) }
|
|
|
|
|
func (x byPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-11-11 16:56:07 -08:00
|
|
|
// flusherrors sorts errors seen so far by line number, prints them to stdout,
|
|
|
|
|
// and empties the errors array.
|
2016-09-15 15:45:10 +10:00
|
|
|
func flusherrors() {
|
2016-09-13 14:05:14 -07:00
|
|
|
Ctxt.Bso.Flush()
|
2015-02-13 14:40:36 -05:00
|
|
|
if len(errors) == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
2016-12-07 17:40:46 -08:00
|
|
|
sort.Stable(byPos(errors))
|
2018-03-14 10:50:49 +00:00
|
|
|
for i, err := range errors {
|
|
|
|
|
if i == 0 || err.msg != errors[i-1].msg {
|
|
|
|
|
fmt.Printf("%s", err.msg)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
errors = errors[:0]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func hcrash() {
|
|
|
|
|
if Debug['h'] != 0 {
|
2016-09-15 15:45:10 +10:00
|
|
|
flusherrors()
|
2015-02-13 14:40:36 -05:00
|
|
|
if outfile != "" {
|
|
|
|
|
os.Remove(outfile)
|
|
|
|
|
}
|
|
|
|
|
var x *int
|
|
|
|
|
*x = 0
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-15 17:17:01 -08:00
|
|
|
func linestr(pos src.XPos) string {
|
2017-11-10 11:38:51 -08:00
|
|
|
return Ctxt.OutermostPos(pos).Format(Debug['C'] == 0, Debug['L'] == 1)
|
2016-03-02 11:30:29 -08:00
|
|
|
}
|
|
|
|
|
|
2016-05-18 17:43:15 -07:00
|
|
|
// lasterror keeps track of the most recently issued error.
|
|
|
|
|
// It is used to avoid multiple error messages on the same
|
|
|
|
|
// line.
|
|
|
|
|
var lasterror struct {
|
2016-12-15 17:17:01 -08:00
|
|
|
syntax src.XPos // source position of last syntax error
|
|
|
|
|
other src.XPos // source position of last non-syntax error
|
|
|
|
|
msg string // error message of last non-syntax error
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-12-09 17:15:05 -08:00
|
|
|
// sameline reports whether two positions a, b are on the same line.
|
2016-12-15 17:17:01 -08:00
|
|
|
func sameline(a, b src.XPos) bool {
|
|
|
|
|
p := Ctxt.PosTable.Pos(a)
|
|
|
|
|
q := Ctxt.PosTable.Pos(b)
|
|
|
|
|
return p.Base() == q.Base() && p.Line() == q.Line()
|
2016-12-09 17:15:05 -08:00
|
|
|
}
|
|
|
|
|
|
2016-12-15 17:17:01 -08:00
|
|
|
func yyerrorl(pos src.XPos, format string, args ...interface{}) {
|
2015-04-02 17:01:14 -07:00
|
|
|
msg := fmt.Sprintf(format, args...)
|
2016-05-18 17:43:15 -07:00
|
|
|
|
2015-04-02 17:01:14 -07:00
|
|
|
if strings.HasPrefix(msg, "syntax error") {
|
2015-02-13 14:40:36 -05:00
|
|
|
nsyntaxerrors++
|
2016-05-18 17:43:15 -07:00
|
|
|
// only one syntax error per line, no matter what error
|
2016-12-09 17:15:05 -08:00
|
|
|
if sameline(lasterror.syntax, pos) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
2016-12-09 17:15:05 -08:00
|
|
|
lasterror.syntax = pos
|
2016-05-18 17:43:15 -07:00
|
|
|
} else {
|
|
|
|
|
// only one of multiple equal non-syntax errors per line
|
2016-09-15 15:45:10 +10:00
|
|
|
// (flusherrors shows only one of them, so we filter them
|
2016-05-18 17:43:15 -07:00
|
|
|
// here as best as we can (they may not appear in order)
|
|
|
|
|
// so that we don't count them here and exit early, and
|
|
|
|
|
// then have nothing to show for.)
|
2016-12-09 17:15:05 -08:00
|
|
|
if sameline(lasterror.other, pos) && lasterror.msg == msg {
|
2016-05-18 17:43:15 -07:00
|
|
|
return
|
|
|
|
|
}
|
2016-12-09 17:15:05 -08:00
|
|
|
lasterror.other = pos
|
2016-05-18 17:43:15 -07:00
|
|
|
lasterror.msg = msg
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-12-09 17:15:05 -08:00
|
|
|
adderr(pos, "%s", msg)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
hcrash()
|
|
|
|
|
nerrors++
|
2015-02-17 22:13:49 -05:00
|
|
|
if nsavederrors+nerrors >= 10 && Debug['e'] == 0 {
|
2016-09-15 15:45:10 +10:00
|
|
|
flusherrors()
|
2016-12-09 17:15:05 -08:00
|
|
|
fmt.Printf("%v: too many errors\n", linestr(pos))
|
2015-02-13 14:40:36 -05:00
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-15 15:45:10 +10:00
|
|
|
func yyerror(format string, args ...interface{}) {
|
2016-05-18 17:43:15 -07:00
|
|
|
yyerrorl(lineno, format, args...)
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
func Warn(fmt_ string, args ...interface{}) {
|
2016-03-02 11:01:25 -08:00
|
|
|
adderr(lineno, fmt_, args...)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
hcrash()
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-15 17:17:01 -08:00
|
|
|
func Warnl(line src.XPos, fmt_ string, args ...interface{}) {
|
2015-04-02 17:01:14 -07:00
|
|
|
adderr(line, fmt_, args...)
|
2015-02-13 14:40:36 -05:00
|
|
|
if Debug['m'] != 0 {
|
2016-09-15 15:45:10 +10:00
|
|
|
flusherrors()
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-30 23:10:03 +02:00
|
|
|
func Fatalf(fmt_ string, args ...interface{}) {
|
2016-09-15 15:45:10 +10:00
|
|
|
flusherrors()
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2017-10-13 14:47:45 -07:00
|
|
|
if Debug_panic != 0 || nsavederrors+nerrors == 0 {
|
|
|
|
|
fmt.Printf("%v: internal compiler error: ", linestr(lineno))
|
|
|
|
|
fmt.Printf(fmt_, args...)
|
2015-02-13 14:40:36 -05:00
|
|
|
fmt.Printf("\n")
|
2017-10-13 14:47:45 -07:00
|
|
|
|
|
|
|
|
// If this is a released compiler version, ask for a bug report.
|
|
|
|
|
if strings.HasPrefix(objabi.Version, "go") {
|
|
|
|
|
fmt.Printf("\n")
|
|
|
|
|
fmt.Printf("Please file a bug report including a short program that triggers the error.\n")
|
|
|
|
|
fmt.Printf("https://golang.org/issue/new\n")
|
|
|
|
|
} else {
|
|
|
|
|
// Not a release; dump a stack trace, too.
|
|
|
|
|
fmt.Println()
|
|
|
|
|
os.Stdout.Write(debug.Stack())
|
|
|
|
|
fmt.Println()
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
hcrash()
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-15 17:17:01 -08:00
|
|
|
func setlineno(n *Node) src.XPos {
|
2015-02-23 16:07:24 -05:00
|
|
|
lno := lineno
|
2015-02-13 14:40:36 -05:00
|
|
|
if n != nil {
|
|
|
|
|
switch n.Op {
|
2016-10-25 15:43:05 -07:00
|
|
|
case ONAME, OPACK:
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
|
|
2016-10-25 15:43:05 -07:00
|
|
|
case OLITERAL, OTYPE:
|
2015-06-28 23:12:21 -04:00
|
|
|
if n.Sym != nil {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
fallthrough
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
default:
|
2016-12-07 17:40:46 -08:00
|
|
|
lineno = n.Pos
|
2016-12-07 16:02:42 -08:00
|
|
|
if !lineno.IsKnown() {
|
2015-02-13 14:40:36 -05:00
|
|
|
if Debug['K'] != 0 {
|
2016-12-07 16:02:42 -08:00
|
|
|
Warn("setlineno: unknown position (line 0)")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
lineno = lno
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return lno
|
|
|
|
|
}
|
|
|
|
|
|
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 lookup(name string) *types.Sym {
|
2015-03-02 16:21:15 -05:00
|
|
|
return localpkg.Lookup(name)
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-09-15 15:45:10 +10:00
|
|
|
// lookupN looks up the symbol starting with prefix and ending with
|
|
|
|
|
// the decimal n. If prefix is too long, lookupN panics.
|
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 lookupN(prefix string, n int) *types.Sym {
|
2016-03-19 18:17:58 -07:00
|
|
|
var buf [20]byte // plenty long enough for all current users
|
|
|
|
|
copy(buf[:], prefix)
|
|
|
|
|
b := strconv.AppendInt(buf[:len(prefix)], int64(n), 10)
|
2017-03-30 14:04:54 -07:00
|
|
|
return localpkg.LookupBytes(b)
|
2016-03-19 18:17:58 -07:00
|
|
|
}
|
|
|
|
|
|
2016-06-01 10:15:02 -07:00
|
|
|
// autolabel generates a new Name node for use with
|
|
|
|
|
// an automatically generated label.
|
2016-08-15 21:09:39 -07:00
|
|
|
// prefix is a short mnemonic (e.g. ".s" for switch)
|
2016-06-01 10:15:02 -07:00
|
|
|
// to help with debugging.
|
2016-08-15 21:09:39 -07:00
|
|
|
// It should begin with "." to avoid conflicts with
|
|
|
|
|
// user labels.
|
2018-10-26 20:10:23 -07:00
|
|
|
func autolabel(prefix string) *types.Sym {
|
2016-08-15 21:09:39 -07:00
|
|
|
if prefix[0] != '.' {
|
|
|
|
|
Fatalf("autolabel prefix must start with '.', have %q", prefix)
|
|
|
|
|
}
|
2016-06-01 10:15:02 -07:00
|
|
|
fn := Curfn
|
|
|
|
|
if Curfn == nil {
|
|
|
|
|
Fatalf("autolabel outside function")
|
|
|
|
|
}
|
|
|
|
|
n := fn.Func.Label
|
|
|
|
|
fn.Func.Label++
|
2018-10-26 20:10:23 -07:00
|
|
|
return lookupN(prefix, int(n))
|
2016-06-01 10:15:02 -07: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 restrictlookup(name string, pkg *types.Pkg) *types.Sym {
|
2018-04-09 15:22:01 -07:00
|
|
|
if !types.IsExported(name) && pkg != localpkg {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("cannot refer to unexported name %s.%s", pkg.Name, name)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2017-03-30 13:19:18 -07:00
|
|
|
return pkg.Lookup(name)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// find all the exported symbols in package opkg
|
|
|
|
|
// and make them available in the current 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
|
|
|
func importdot(opkg *types.Pkg, pack *Node) {
|
2015-02-23 16:07:24 -05:00
|
|
|
n := 0
|
2015-03-02 16:21:15 -05:00
|
|
|
for _, s := range opkg.Syms {
|
|
|
|
|
if s.Def == nil {
|
|
|
|
|
continue
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2018-04-09 15:22:01 -07:00
|
|
|
if !types.IsExported(s.Name) || strings.ContainsRune(s.Name, 0xb7) { // 0xb7 = center dot
|
2015-03-02 16:21:15 -05:00
|
|
|
continue
|
|
|
|
|
}
|
2017-10-11 10:14:31 +01:00
|
|
|
s1 := lookup(s.Name)
|
2015-03-02 16:21:15 -05:00
|
|
|
if s1.Def != nil {
|
2017-10-11 10:14:31 +01:00
|
|
|
pkgerror := fmt.Sprintf("during import %q", opkg.Path)
|
2018-04-02 17:33:38 -07:00
|
|
|
redeclare(lineno, s1, pkgerror)
|
2015-03-02 16:21:15 -05:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s1.Def = s.Def
|
|
|
|
|
s1.Block = s.Block
|
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 asNode(s1.Def).Name == nil {
|
|
|
|
|
Dump("s1def", asNode(s1.Def))
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("missing Name")
|
2015-05-26 23:08:39 -04: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
|
|
|
asNode(s1.Def).Name.Pack = pack
|
2015-03-02 16:21:15 -05:00
|
|
|
s1.Origpkg = opkg
|
|
|
|
|
n++
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if n == 0 {
|
|
|
|
|
// can't possibly be used - there were no symbols
|
2016-12-07 17:40:46 -08:00
|
|
|
yyerrorl(pack.Pos, "imported and not used: %q", opkg.Path)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-24 15:57:12 -07:00
|
|
|
func nod(op Op, nleft, nright *Node) *Node {
|
|
|
|
|
return nodl(lineno, op, nleft, nright)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func nodl(pos src.XPos, op Op, nleft, nright *Node) *Node {
|
2017-01-31 14:32:11 -08:00
|
|
|
var n *Node
|
2015-03-10 21:37:13 -07:00
|
|
|
switch op {
|
|
|
|
|
case OCLOSURE, ODCLFUNC:
|
2017-01-31 14:32:11 -08:00
|
|
|
var x struct {
|
|
|
|
|
Node
|
|
|
|
|
Func
|
|
|
|
|
}
|
|
|
|
|
n = &x.Node
|
|
|
|
|
n.Func = &x.Func
|
2015-04-03 17:43:38 -07:00
|
|
|
case ONAME:
|
2017-03-24 15:57:12 -07:00
|
|
|
Fatalf("use newname instead")
|
2015-05-26 23:18:27 -04:00
|
|
|
case OLABEL, OPACK:
|
2017-01-31 14:32:11 -08:00
|
|
|
var x struct {
|
|
|
|
|
Node
|
|
|
|
|
Name
|
|
|
|
|
}
|
|
|
|
|
n = &x.Node
|
|
|
|
|
n.Name = &x.Name
|
|
|
|
|
default:
|
|
|
|
|
n = new(Node)
|
2015-03-10 21:37:13 -07:00
|
|
|
}
|
2017-01-31 14:32:11 -08:00
|
|
|
n.Op = op
|
|
|
|
|
n.Left = nleft
|
|
|
|
|
n.Right = nright
|
2017-03-24 15:57:12 -07:00
|
|
|
n.Pos = pos
|
2017-01-31 14:32:11 -08:00
|
|
|
n.Xoffset = BADWIDTH
|
|
|
|
|
n.Orig = n
|
2017-03-24 15:57:12 -07:00
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// newname returns a new ONAME Node associated with symbol s.
|
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 newname(s *types.Sym) *Node {
|
2017-03-31 11:10:01 -07:00
|
|
|
n := newnamel(lineno, s)
|
|
|
|
|
n.Name.Curfn = Curfn
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// newname returns a new ONAME Node associated with symbol s at position pos.
|
|
|
|
|
// The caller is responsible for setting n.Name.Curfn.
|
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 newnamel(pos src.XPos, s *types.Sym) *Node {
|
2017-03-24 15:57:12 -07:00
|
|
|
if s == nil {
|
2017-03-31 11:10:01 -07:00
|
|
|
Fatalf("newnamel nil")
|
2017-03-24 15:57:12 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var x struct {
|
|
|
|
|
Node
|
|
|
|
|
Name
|
|
|
|
|
Param
|
2015-05-27 07:31:56 -04:00
|
|
|
}
|
2017-03-24 15:57:12 -07:00
|
|
|
n := &x.Node
|
|
|
|
|
n.Name = &x.Name
|
|
|
|
|
n.Name.Param = &x.Param
|
|
|
|
|
|
|
|
|
|
n.Op = ONAME
|
2017-03-31 11:10:01 -07:00
|
|
|
n.Pos = pos
|
2017-03-24 15:57:12 -07:00
|
|
|
n.Orig = n
|
|
|
|
|
|
|
|
|
|
n.Sym = s
|
|
|
|
|
n.SetAddable(true)
|
2015-02-13 14:40:36 -05:00
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-15 15:45:10 +10:00
|
|
|
// nodSym makes a Node with Op op and with the Left field set to left
|
cmd/compile: change ODOT and friends to use Sym, not Right
The Node type ODOT and its variants all represent a selector, with a
simple name to the right of the dot. Before this change this was
represented by using an ONAME Node in the Right field. This ONAME node
served no useful purpose. This CL changes these Node types to store the
symbol in the Sym field instead, thus not requiring allocating a Node
for each selector.
When compiling x/tools/go/types this CL eliminates nearly 5000 calls to
newname and reduces the total number of Nodes allocated by about 6.6%.
It seems to cut compilation time by 1 to 2 percent.
Getting this right was somewhat subtle, and I added two dubious changes
to produce the exact same output as before. One is to ishairy in
inl.go: the ONAME node increased the cost of ODOT and friends by 1, and
I retained that, although really ODOT is not more expensive than any
other node. The other is to varexpr in walk.go: because the ONAME in
the Right field of an ODOT has no class, varexpr would always return
false for an ODOT, although in fact for some ODOT's it seemingly ought
to return true; I added an && false for now. I will send separate CLs,
that will break toolstash -cmp, to clean these up.
This CL passes toolstash -cmp.
Change-Id: I4af8a10cc59078c436130ce472f25abc3a9b2f80
Reviewed-on: https://go-review.googlesource.com/20890
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2016-03-18 16:52:30 -07:00
|
|
|
// and the Sym field set to sym. This is for ODOT and friends.
|
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 nodSym(op Op, left *Node, sym *types.Sym) *Node {
|
2016-09-16 11:00:54 +10:00
|
|
|
n := nod(op, left, nil)
|
cmd/compile: change ODOT and friends to use Sym, not Right
The Node type ODOT and its variants all represent a selector, with a
simple name to the right of the dot. Before this change this was
represented by using an ONAME Node in the Right field. This ONAME node
served no useful purpose. This CL changes these Node types to store the
symbol in the Sym field instead, thus not requiring allocating a Node
for each selector.
When compiling x/tools/go/types this CL eliminates nearly 5000 calls to
newname and reduces the total number of Nodes allocated by about 6.6%.
It seems to cut compilation time by 1 to 2 percent.
Getting this right was somewhat subtle, and I added two dubious changes
to produce the exact same output as before. One is to ishairy in
inl.go: the ONAME node increased the cost of ODOT and friends by 1, and
I retained that, although really ODOT is not more expensive than any
other node. The other is to varexpr in walk.go: because the ONAME in
the Right field of an ODOT has no class, varexpr would always return
false for an ODOT, although in fact for some ODOT's it seemingly ought
to return true; I added an && false for now. I will send separate CLs,
that will break toolstash -cmp, to clean these up.
This CL passes toolstash -cmp.
Change-Id: I4af8a10cc59078c436130ce472f25abc3a9b2f80
Reviewed-on: https://go-review.googlesource.com/20890
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2016-03-18 16:52:30 -07:00
|
|
|
n.Sym = sym
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-20 15:22:33 -07:00
|
|
|
// rawcopy returns a shallow copy of n.
|
|
|
|
|
// Note: copy or sepcopy (rather than rawcopy) is usually the
|
|
|
|
|
// correct choice (see comment with Node.copy, below).
|
|
|
|
|
func (n *Node) rawcopy() *Node {
|
|
|
|
|
copy := *n
|
|
|
|
|
return ©
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// sepcopy returns a separate shallow copy of n, with the copy's
|
|
|
|
|
// Orig pointing to itself.
|
|
|
|
|
func (n *Node) sepcopy() *Node {
|
|
|
|
|
copy := *n
|
|
|
|
|
copy.Orig = ©
|
|
|
|
|
return ©
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// copy returns shallow copy of n and adjusts the copy's Orig if
|
|
|
|
|
// necessary: In general, if n.Orig points to itself, the copy's
|
|
|
|
|
// Orig should point to itself as well. Otherwise, if n is modified,
|
|
|
|
|
// the copy's Orig node appears modified, too, and then doesn't
|
|
|
|
|
// represent the original node anymore.
|
|
|
|
|
// (This caused the wrong complit Op to be used when printing error
|
|
|
|
|
// messages; see issues #26855, #27765).
|
2017-10-23 19:57:07 +01:00
|
|
|
func (n *Node) copy() *Node {
|
2018-09-20 15:22:33 -07:00
|
|
|
copy := *n
|
|
|
|
|
if n.Orig == n {
|
|
|
|
|
copy.Orig = ©
|
|
|
|
|
}
|
|
|
|
|
return ©
|
2017-10-23 19:57:07 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-09 13:57:56 -07:00
|
|
|
// methcmp sorts methods by symbol.
|
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
|
|
|
type methcmp []*types.Field
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2018-04-09 13:57:56 -07:00
|
|
|
func (x methcmp) Len() int { return len(x) }
|
|
|
|
|
func (x methcmp) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
|
|
|
|
func (x methcmp) Less(i, j int) bool { return x[i].Sym.Less(x[j].Sym) }
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-09-15 14:34:20 +10:00
|
|
|
func nodintconst(v int64) *Node {
|
2018-03-31 15:53:21 -07:00
|
|
|
u := new(Mpint)
|
|
|
|
|
u.SetInt64(v)
|
|
|
|
|
return nodlit(Val{u})
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func nodfltconst(v *Mpflt) *Node {
|
2018-03-31 15:53:21 -07:00
|
|
|
u := newMpflt()
|
|
|
|
|
u.Set(v)
|
|
|
|
|
return nodlit(Val{u})
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func nodnil() *Node {
|
2018-03-31 15:53:21 -07:00
|
|
|
return nodlit(Val{new(NilVal)})
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-09-15 15:45:10 +10:00
|
|
|
func nodbool(b bool) *Node {
|
2018-03-31 15:53:21 -07:00
|
|
|
return nodlit(Val{b})
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2017-05-21 15:18:08 -07:00
|
|
|
func nodstr(s string) *Node {
|
|
|
|
|
return nodlit(Val{s})
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-22 22:01:01 -04:00
|
|
|
// treecopy recursively copies n, with the exception of
|
|
|
|
|
// ONAME, OLITERAL, OTYPE, and non-iota ONONAME leaves.
|
|
|
|
|
// Copies of iota ONONAME nodes are assigned the current
|
2016-12-09 17:15:05 -08:00
|
|
|
// value of iota_. If pos.IsKnown(), it sets the source
|
|
|
|
|
// position of newly allocated nodes to pos.
|
2016-12-15 17:17:01 -08:00
|
|
|
func treecopy(n *Node, pos src.XPos) *Node {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch n.Op {
|
|
|
|
|
default:
|
2018-09-20 15:22:33 -07:00
|
|
|
m := n.sepcopy()
|
2016-12-09 17:15:05 -08:00
|
|
|
m.Left = treecopy(n.Left, pos)
|
|
|
|
|
m.Right = treecopy(n.Right, pos)
|
|
|
|
|
m.List.Set(listtreecopy(n.List.Slice(), pos))
|
|
|
|
|
if pos.IsKnown() {
|
|
|
|
|
m.Pos = pos
|
2015-05-22 22:01:01 -04:00
|
|
|
}
|
2015-05-27 00:44:05 -04:00
|
|
|
if m.Name != nil && n.Op != ODCLFIELD {
|
2015-05-26 22:19:27 -04:00
|
|
|
Dump("treecopy", n)
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("treecopy Name")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2017-10-23 19:57:07 +01:00
|
|
|
return m
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-04-12 17:46:41 -07:00
|
|
|
case OPACK:
|
|
|
|
|
// OPACK nodes are never valid in const value declarations,
|
|
|
|
|
// but allow them like any other declared symbol to avoid
|
|
|
|
|
// crashing (golang.org/issue/11361).
|
|
|
|
|
fallthrough
|
|
|
|
|
|
2016-10-31 16:20:42 -07:00
|
|
|
case ONAME, ONONAME, OLITERAL, OTYPE:
|
2016-03-23 16:01:15 +11:00
|
|
|
return n
|
2016-04-12 17:46:41 -07:00
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-08 13:39:10 +01:00
|
|
|
// isNil reports whether n represents the universal untyped zero value "nil".
|
|
|
|
|
func (n *Node) isNil() bool {
|
2015-12-04 14:44:27 -08:00
|
|
|
// Check n.Orig because constant propagation may produce typed nil constants,
|
|
|
|
|
// which don't exist in the Go spec.
|
|
|
|
|
return Isconst(n.Orig, CTNIL)
|
2015-02-13 14:40:36 -05: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 isptrto(t *types.Type, et types.EType) bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
if t == nil {
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-03-30 15:09:25 -07:00
|
|
|
if !t.IsPtr() {
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-03-30 10:57:47 -07:00
|
|
|
t = t.Elem()
|
2015-02-13 14:40:36 -05:00
|
|
|
if t == nil {
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-09-24 23:21:18 +02:00
|
|
|
if t.Etype != et {
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2018-04-08 13:39:10 +01:00
|
|
|
func (n *Node) isBlank() bool {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n == nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
2017-04-21 07:51:41 -07:00
|
|
|
return n.Sym.IsBlank()
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-08-30 13:43:37 -07:00
|
|
|
// methtype returns the underlying type, if any,
|
|
|
|
|
// that owns methods with receiver parameter t.
|
|
|
|
|
// The result is either a named type or an anonymous struct.
|
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 methtype(t *types.Type) *types.Type {
|
2015-02-13 14:40:36 -05:00
|
|
|
if t == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-30 13:43:37 -07:00
|
|
|
// Strip away pointer if it's there.
|
2016-03-30 15:09:25 -07:00
|
|
|
if t.IsPtr() {
|
2015-02-13 14:40:36 -05:00
|
|
|
if t.Sym != nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
2016-03-30 10:57:47 -07:00
|
|
|
t = t.Elem()
|
2015-02-13 14:40:36 -05:00
|
|
|
if t == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-30 13:43:37 -07:00
|
|
|
// Must be a named type or anonymous struct.
|
|
|
|
|
if t.Sym == nil && !t.IsStruct() {
|
2015-02-13 14:40:36 -05:00
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-30 13:43:37 -07:00
|
|
|
// Check types.
|
|
|
|
|
if issimple[t.Etype] {
|
|
|
|
|
return t
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-08-30 13:43:37 -07:00
|
|
|
switch t.Etype {
|
|
|
|
|
case TARRAY, TCHAN, TFUNC, TMAP, TSLICE, TSTRING, TSTRUCT:
|
|
|
|
|
return t
|
|
|
|
|
}
|
|
|
|
|
return nil
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Are t1 and t2 equal struct types when field names are ignored?
|
|
|
|
|
// For deciding whether the result struct from g can be copied
|
|
|
|
|
// directly when compiling f(g()).
|
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 eqtypenoname(t1 *types.Type, t2 *types.Type) bool {
|
2016-03-30 14:56:08 -07:00
|
|
|
if t1 == nil || t2 == nil || !t1.IsStruct() || !t2.IsStruct() {
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2017-04-05 19:38:21 -07:00
|
|
|
if t1.NumFields() != t2.NumFields() {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
for i, f1 := range t1.FieldSlice() {
|
|
|
|
|
f2 := t2.Field(i)
|
2018-10-18 15:24:50 -07:00
|
|
|
if !types.Identical(f1.Type, f2.Type) {
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
2017-04-05 19:38:21 -07:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Is type src assignment compatible to type dst?
|
|
|
|
|
// If so, return op code to use in conversion.
|
|
|
|
|
// If not, return 0.
|
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 assignop(src *types.Type, dst *types.Type, why *string) Op {
|
2015-02-13 14:40:36 -05:00
|
|
|
if why != nil {
|
|
|
|
|
*why = ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if src == dst {
|
|
|
|
|
return OCONVNOP
|
|
|
|
|
}
|
|
|
|
|
if src == nil || dst == nil || src.Etype == TFORW || dst.Etype == TFORW || src.Orig == nil || dst.Orig == nil {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 1. src type is identical to dst.
|
2018-10-18 15:24:50 -07:00
|
|
|
if types.Identical(src, dst) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return OCONVNOP
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2. src and dst have identical underlying types
|
|
|
|
|
// and either src or dst is not a named type or
|
|
|
|
|
// both are empty interface types.
|
|
|
|
|
// For assignable but different non-empty interface types,
|
2017-01-11 16:40:24 -08:00
|
|
|
// we want to recompute the itab. Recomputing the itab ensures
|
|
|
|
|
// that itabs are unique (thus an interface with a compile-time
|
|
|
|
|
// type I has an itab with interface type I).
|
2018-10-18 15:24:50 -07:00
|
|
|
if types.Identical(src.Orig, dst.Orig) {
|
2017-01-11 16:40:24 -08:00
|
|
|
if src.IsEmptyInterface() {
|
|
|
|
|
// Conversion between two empty interfaces
|
|
|
|
|
// requires no code.
|
|
|
|
|
return OCONVNOP
|
|
|
|
|
}
|
|
|
|
|
if (src.Sym == nil || dst.Sym == nil) && !src.IsInterface() {
|
|
|
|
|
// Conversion between two types, at least one unnamed,
|
|
|
|
|
// needs no conversion. The exception is nonempty interfaces
|
|
|
|
|
// which need to have their itab updated.
|
|
|
|
|
return OCONVNOP
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3. dst is an interface type and src implements dst.
|
2016-03-30 14:56:08 -07:00
|
|
|
if dst.IsInterface() && src.Etype != TNIL {
|
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
|
|
|
var missing, have *types.Field
|
2015-02-23 16:07:24 -05:00
|
|
|
var ptr int
|
2015-02-17 22:13:49 -05:00
|
|
|
if implements(src, dst, &missing, &have, &ptr) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return OCONVIFACE
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// we'll have complained about this method anyway, suppress spurious messages.
|
2017-02-27 19:56:38 +02:00
|
|
|
if have != nil && have.Sym == missing.Sym && (have.Type.Broke() || missing.Type.Broke()) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return OCONVIFACE
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if why != nil {
|
2015-02-17 22:13:49 -05:00
|
|
|
if isptrto(src, TINTER) {
|
2015-04-17 12:03:22 -04:00
|
|
|
*why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src)
|
2017-02-27 19:56:38 +02:00
|
|
|
} else if have != nil && have.Sym == missing.Sym && have.Nointerface() {
|
2015-04-17 12:03:22 -04:00
|
|
|
*why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else if have != nil && have.Sym == missing.Sym {
|
2016-09-09 21:08:46 -07:00
|
|
|
*why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+
|
|
|
|
|
"\t\thave %v%0S\n\t\twant %v%0S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else if ptr != 0 {
|
2015-04-17 12:03:22 -04:00
|
|
|
*why = fmt.Sprintf(":\n\t%v does not implement %v (%v method has pointer receiver)", src, dst, missing.Sym)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else if have != nil {
|
2016-09-09 21:08:46 -07:00
|
|
|
*why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)\n"+
|
|
|
|
|
"\t\thave %v%0S\n\t\twant %v%0S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2015-04-17 12:03:22 -04:00
|
|
|
*why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
if isptrto(dst, TINTER) {
|
2015-02-13 14:40:36 -05:00
|
|
|
if why != nil {
|
2015-04-17 12:03:22 -04:00
|
|
|
*why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-30 14:56:08 -07:00
|
|
|
if src.IsInterface() && dst.Etype != TBLANK {
|
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
|
|
|
var missing, have *types.Field
|
2015-02-23 16:07:24 -05:00
|
|
|
var ptr int
|
2015-02-17 22:13:49 -05:00
|
|
|
if why != nil && implements(dst, src, &missing, &have, &ptr) {
|
2015-02-13 14:40:36 -05:00
|
|
|
*why = ": need type assertion"
|
|
|
|
|
}
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4. src is a bidirectional channel value, dst is a channel type,
|
|
|
|
|
// src and dst have identical element types, and
|
|
|
|
|
// either src or dst is not a named type.
|
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 src.IsChan() && src.ChanDir() == types.Cboth && dst.IsChan() {
|
2018-10-18 15:24:50 -07:00
|
|
|
if types.Identical(src.Elem(), dst.Elem()) && (src.Sym == nil || dst.Sym == nil) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return OCONVNOP
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 5. src is the predeclared identifier nil and dst is a nillable type.
|
|
|
|
|
if src.Etype == TNIL {
|
|
|
|
|
switch dst.Etype {
|
2017-11-06 14:50:30 -08:00
|
|
|
case TPTR,
|
2015-02-13 14:40:36 -05:00
|
|
|
TFUNC,
|
|
|
|
|
TMAP,
|
|
|
|
|
TCHAN,
|
2016-04-18 14:02:08 -07:00
|
|
|
TINTER,
|
|
|
|
|
TSLICE:
|
2015-02-13 14:40:36 -05:00
|
|
|
return OCONVNOP
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 6. rule about untyped constants - already converted by defaultlit.
|
|
|
|
|
|
|
|
|
|
// 7. Any typed value can be assigned to the blank identifier.
|
|
|
|
|
if dst.Etype == TBLANK {
|
|
|
|
|
return OCONVNOP
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Can we convert a value of type src to a value of type dst?
|
|
|
|
|
// If so, return op code to use in conversion (maybe OCONVNOP).
|
|
|
|
|
// If not, return 0.
|
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 convertop(src *types.Type, dst *types.Type, why *string) Op {
|
2015-02-13 14:40:36 -05:00
|
|
|
if why != nil {
|
|
|
|
|
*why = ""
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if src == dst {
|
|
|
|
|
return OCONVNOP
|
|
|
|
|
}
|
|
|
|
|
if src == nil || dst == nil {
|
|
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
cmd/compile: add go:notinheap type pragma
This adds a //go:notinheap pragma for declarations of types that must
not be heap allocated. We ensure these rules by disallowing new(T),
make([]T), append([]T), or implicit allocation of T, by disallowing
conversions to notinheap types, and by propagating notinheap to any
struct or array that contains notinheap elements.
The utility of this pragma is that we can eliminate write barriers for
writes to pointers to go:notinheap types, since the write barrier is
guaranteed to be a no-op. This will let us mark several scheduler and
memory allocator structures as go:notinheap, which will let us
disallow write barriers in the scheduler and memory allocator much
more thoroughly and also eliminate some problematic hybrid write
barriers.
This also makes go:nowritebarrierrec and go:yeswritebarrierrec much
more powerful. Currently we use go:nowritebarrier all over the place,
but it's almost never what you actually want: when write barriers are
illegal, they're typically illegal for a whole dynamic scope. Partly
this is because go:nowritebarrier has been around longer, but it's
also because go:nowritebarrierrec couldn't be used in situations that
had no-op write barriers or where some nested scope did allow write
barriers. go:notinheap eliminates many no-op write barriers and
go:yeswritebarrierrec makes it possible to opt back in to write
barriers, so these two changes will let us use go:nowritebarrierrec
far more liberally.
This updates #13386, which is about controlling pointers from non-GC'd
memory to GC'd memory. That would require some additional pragma (or
pragmas), but could build on this pragma.
Change-Id: I6314f8f4181535dd166887c9ec239977b54940bd
Reviewed-on: https://go-review.googlesource.com/30939
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2016-10-11 22:53:27 -04:00
|
|
|
// Conversions from regular to go:notinheap are not allowed
|
2018-10-16 15:31:07 -07:00
|
|
|
// (unless it's unsafe.Pointer). These are runtime-specific
|
|
|
|
|
// rules.
|
|
|
|
|
// (a) Disallow (*T) to (*U) where T is go:notinheap but U isn't.
|
2017-02-27 19:56:38 +02:00
|
|
|
if src.IsPtr() && dst.IsPtr() && dst.Elem().NotInHeap() && !src.Elem().NotInHeap() {
|
cmd/compile: add go:notinheap type pragma
This adds a //go:notinheap pragma for declarations of types that must
not be heap allocated. We ensure these rules by disallowing new(T),
make([]T), append([]T), or implicit allocation of T, by disallowing
conversions to notinheap types, and by propagating notinheap to any
struct or array that contains notinheap elements.
The utility of this pragma is that we can eliminate write barriers for
writes to pointers to go:notinheap types, since the write barrier is
guaranteed to be a no-op. This will let us mark several scheduler and
memory allocator structures as go:notinheap, which will let us
disallow write barriers in the scheduler and memory allocator much
more thoroughly and also eliminate some problematic hybrid write
barriers.
This also makes go:nowritebarrierrec and go:yeswritebarrierrec much
more powerful. Currently we use go:nowritebarrier all over the place,
but it's almost never what you actually want: when write barriers are
illegal, they're typically illegal for a whole dynamic scope. Partly
this is because go:nowritebarrier has been around longer, but it's
also because go:nowritebarrierrec couldn't be used in situations that
had no-op write barriers or where some nested scope did allow write
barriers. go:notinheap eliminates many no-op write barriers and
go:yeswritebarrierrec makes it possible to opt back in to write
barriers, so these two changes will let us use go:nowritebarrierrec
far more liberally.
This updates #13386, which is about controlling pointers from non-GC'd
memory to GC'd memory. That would require some additional pragma (or
pragmas), but could build on this pragma.
Change-Id: I6314f8f4181535dd166887c9ec239977b54940bd
Reviewed-on: https://go-review.googlesource.com/30939
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2016-10-11 22:53:27 -04:00
|
|
|
if why != nil {
|
|
|
|
|
*why = fmt.Sprintf(":\n\t%v is go:notinheap, but %v is not", dst.Elem(), src.Elem())
|
|
|
|
|
}
|
|
|
|
|
return 0
|
|
|
|
|
}
|
2018-10-16 15:31:07 -07:00
|
|
|
// (b) Disallow string to []T where T is go:notinheap.
|
|
|
|
|
if src.IsString() && dst.IsSlice() && dst.Elem().NotInHeap() && (dst.Elem().Etype == types.Bytetype.Etype || dst.Elem().Etype == types.Runetype.Etype) {
|
|
|
|
|
if why != nil {
|
|
|
|
|
*why = fmt.Sprintf(":\n\t%v is go:notinheap", dst.Elem())
|
|
|
|
|
}
|
|
|
|
|
return 0
|
|
|
|
|
}
|
cmd/compile: add go:notinheap type pragma
This adds a //go:notinheap pragma for declarations of types that must
not be heap allocated. We ensure these rules by disallowing new(T),
make([]T), append([]T), or implicit allocation of T, by disallowing
conversions to notinheap types, and by propagating notinheap to any
struct or array that contains notinheap elements.
The utility of this pragma is that we can eliminate write barriers for
writes to pointers to go:notinheap types, since the write barrier is
guaranteed to be a no-op. This will let us mark several scheduler and
memory allocator structures as go:notinheap, which will let us
disallow write barriers in the scheduler and memory allocator much
more thoroughly and also eliminate some problematic hybrid write
barriers.
This also makes go:nowritebarrierrec and go:yeswritebarrierrec much
more powerful. Currently we use go:nowritebarrier all over the place,
but it's almost never what you actually want: when write barriers are
illegal, they're typically illegal for a whole dynamic scope. Partly
this is because go:nowritebarrier has been around longer, but it's
also because go:nowritebarrierrec couldn't be used in situations that
had no-op write barriers or where some nested scope did allow write
barriers. go:notinheap eliminates many no-op write barriers and
go:yeswritebarrierrec makes it possible to opt back in to write
barriers, so these two changes will let us use go:nowritebarrierrec
far more liberally.
This updates #13386, which is about controlling pointers from non-GC'd
memory to GC'd memory. That would require some additional pragma (or
pragmas), but could build on this pragma.
Change-Id: I6314f8f4181535dd166887c9ec239977b54940bd
Reviewed-on: https://go-review.googlesource.com/30939
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
2016-10-11 22:53:27 -04:00
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
// 1. src can be assigned to dst.
|
2015-02-23 16:07:24 -05:00
|
|
|
op := assignop(src, dst, why)
|
2015-02-13 14:40:36 -05:00
|
|
|
if op != 0 {
|
|
|
|
|
return op
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// The rules for interfaces are no different in conversions
|
2016-03-01 23:21:55 +00:00
|
|
|
// than assignments. If interfaces are involved, stop now
|
2015-02-13 14:40:36 -05:00
|
|
|
// with the good message from assignop.
|
|
|
|
|
// Otherwise clear the error.
|
2016-03-30 14:56:08 -07:00
|
|
|
if src.IsInterface() || dst.IsInterface() {
|
2015-02-13 14:40:36 -05:00
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
if why != nil {
|
|
|
|
|
*why = ""
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-03 11:40:43 -07:00
|
|
|
// 2. Ignoring struct tags, src and dst have identical underlying types.
|
2018-10-18 15:24:50 -07:00
|
|
|
if types.IdenticalIgnoreTags(src.Orig, dst.Orig) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return OCONVNOP
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-03 11:40:43 -07:00
|
|
|
// 3. src and dst are unnamed pointer types and, ignoring struct tags,
|
|
|
|
|
// their base types have identical underlying types.
|
2016-03-30 15:09:25 -07:00
|
|
|
if src.IsPtr() && dst.IsPtr() && src.Sym == nil && dst.Sym == nil {
|
2018-10-18 15:24:50 -07:00
|
|
|
if types.IdenticalIgnoreTags(src.Elem().Orig, dst.Elem().Orig) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return OCONVNOP
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4. src and dst are both integer or floating point types.
|
2016-03-30 15:09:25 -07:00
|
|
|
if (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) {
|
2016-09-16 00:33:29 +10:00
|
|
|
if simtype[src.Etype] == simtype[dst.Etype] {
|
2015-02-13 14:40:36 -05:00
|
|
|
return OCONVNOP
|
|
|
|
|
}
|
|
|
|
|
return OCONV
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 5. src and dst are both complex types.
|
2016-03-30 15:09:25 -07:00
|
|
|
if src.IsComplex() && dst.IsComplex() {
|
2016-09-16 00:33:29 +10:00
|
|
|
if simtype[src.Etype] == simtype[dst.Etype] {
|
2015-02-13 14:40:36 -05:00
|
|
|
return OCONVNOP
|
|
|
|
|
}
|
|
|
|
|
return OCONV
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 6. src is an integer or has type []byte or []rune
|
|
|
|
|
// and dst is a string type.
|
2016-03-30 15:09:25 -07:00
|
|
|
if src.IsInteger() && dst.IsString() {
|
2015-02-13 14:40:36 -05:00
|
|
|
return ORUNESTR
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-30 14:56:08 -07:00
|
|
|
if src.IsSlice() && dst.IsString() {
|
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 src.Elem().Etype == types.Bytetype.Etype {
|
2015-02-13 14:40:36 -05:00
|
|
|
return OARRAYBYTESTR
|
|
|
|
|
}
|
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 src.Elem().Etype == types.Runetype.Etype {
|
2015-02-13 14:40:36 -05:00
|
|
|
return OARRAYRUNESTR
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 7. src is a string and dst is []byte or []rune.
|
|
|
|
|
// String to slice.
|
2016-03-30 14:56:08 -07:00
|
|
|
if src.IsString() && dst.IsSlice() {
|
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 dst.Elem().Etype == types.Bytetype.Etype {
|
2015-02-13 14:40:36 -05:00
|
|
|
return OSTRARRAYBYTE
|
|
|
|
|
}
|
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 dst.Elem().Etype == types.Runetype.Etype {
|
2015-02-13 14:40:36 -05:00
|
|
|
return OSTRARRAYRUNE
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 8. src is a pointer or uintptr and dst is unsafe.Pointer.
|
2016-03-30 15:09:25 -07:00
|
|
|
if (src.IsPtr() || src.Etype == TUINTPTR) && dst.Etype == TUNSAFEPTR {
|
2015-02-13 14:40:36 -05:00
|
|
|
return OCONVNOP
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 9. src is unsafe.Pointer and dst is a pointer or uintptr.
|
2016-03-30 15:09:25 -07:00
|
|
|
if src.Etype == TUNSAFEPTR && (dst.IsPtr() || dst.Etype == TUINTPTR) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return OCONVNOP
|
|
|
|
|
}
|
|
|
|
|
|
2017-09-02 18:46:59 +02:00
|
|
|
// src is map and dst is a pointer to corresponding hmap.
|
|
|
|
|
// This rule is needed for the implementation detail that
|
|
|
|
|
// go gc maps are implemented as a pointer to a hmap struct.
|
|
|
|
|
if src.Etype == TMAP && dst.IsPtr() &&
|
|
|
|
|
src.MapType().Hmap == dst.Elem() {
|
|
|
|
|
return OCONVNOP
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
return 0
|
|
|
|
|
}
|
|
|
|
|
|
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 assignconv(n *Node, t *types.Type, context string) *Node {
|
2015-03-12 18:45:30 -04:00
|
|
|
return assignconvfn(n, t, func() string { return context })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert node n for assignment to type t.
|
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 assignconvfn(n *Node, t *types.Type, context func() string) *Node {
|
2017-02-27 19:56:38 +02:00
|
|
|
if n == nil || n.Type == nil || n.Type.Broke() {
|
2015-02-13 14:40:36 -05:00
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if t.Etype == TBLANK && n.Type.Etype == TNIL {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("use of untyped nil")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
old := n
|
2017-02-27 19:56:38 +02:00
|
|
|
od := old.Diag()
|
|
|
|
|
old.SetDiag(true) // silence errors about n; we'll issue one below
|
cmd/compile: reduce use of **Node parameters
Escape analysis has a hard time with tree-like
structures (see #13493 and #14858).
This is unlikely to change.
As a result, when invoking a function that accepts
a **Node parameter, we usually allocate a *Node
on the heap. This happens a whole lot.
This CL changes functions from taking a **Node
to acting more like append: It both modifies
the input and returns a replacement for it.
Because of the cascading nature of escape analysis,
in order to get the benefits, I had to modify
almost all such functions. The remaining functions
are in racewalk and the backend. I would be happy
to update them as well in a separate CL.
This CL was created by manually updating the
function signatures and the directly impacted
bits of code. The callsites were then automatically
updated using a bespoke script:
https://gist.github.com/josharian/046b1be7aceae244de39
For ease of reviewing and future understanding,
this CL is also broken down into four CLs,
mailed separately, which show the manual
and the automated changes separately.
They are CLs 20990, 20991, 20992, and 20993.
Passes toolstash -cmp.
name old time/op new time/op delta
Template 335ms ± 5% 324ms ± 5% -3.35% (p=0.000 n=23+24)
Unicode 176ms ± 9% 165ms ± 6% -6.12% (p=0.000 n=23+24)
GoTypes 1.10s ± 4% 1.07s ± 2% -2.77% (p=0.000 n=24+24)
Compiler 5.31s ± 3% 5.15s ± 3% -2.95% (p=0.000 n=24+24)
MakeBash 41.6s ± 1% 41.7s ± 2% ~ (p=0.586 n=23+23)
name old alloc/op new alloc/op delta
Template 63.3MB ± 0% 62.4MB ± 0% -1.36% (p=0.000 n=25+23)
Unicode 42.4MB ± 0% 41.6MB ± 0% -1.99% (p=0.000 n=24+25)
GoTypes 220MB ± 0% 217MB ± 0% -1.11% (p=0.000 n=25+25)
Compiler 994MB ± 0% 973MB ± 0% -2.08% (p=0.000 n=24+25)
name old allocs/op new allocs/op delta
Template 681k ± 0% 574k ± 0% -15.71% (p=0.000 n=24+25)
Unicode 518k ± 0% 413k ± 0% -20.34% (p=0.000 n=25+24)
GoTypes 2.08M ± 0% 1.78M ± 0% -14.62% (p=0.000 n=25+25)
Compiler 9.26M ± 0% 7.64M ± 0% -17.48% (p=0.000 n=25+25)
name old text-bytes new text-bytes delta
HelloSize 578k ± 0% 578k ± 0% ~ (all samples are equal)
CmdGoSize 6.46M ± 0% 6.46M ± 0% ~ (all samples are equal)
name old data-bytes new data-bytes delta
HelloSize 128k ± 0% 128k ± 0% ~ (all samples are equal)
CmdGoSize 281k ± 0% 281k ± 0% ~ (all samples are equal)
name old exe-bytes new exe-bytes delta
HelloSize 921k ± 0% 921k ± 0% ~ (all samples are equal)
CmdGoSize 9.86M ± 0% 9.86M ± 0% ~ (all samples are equal)
Change-Id: I277d95bd56d51c166ef7f560647aeaa092f3f475
Reviewed-on: https://go-review.googlesource.com/20959
Reviewed-by: Dave Cheney <dave@cheney.net>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-03-20 08:03:31 -07:00
|
|
|
n = defaultlit(n, t)
|
2017-02-27 19:56:38 +02:00
|
|
|
old.SetDiag(od)
|
2015-02-13 14:40:36 -05:00
|
|
|
if t.Etype == TBLANK {
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Convert ideal bool from comparison to plain bool
|
|
|
|
|
// if the next step is non-bool (like interface{}).
|
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 n.Type == types.Idealbool && !t.IsBoolean() {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Op == ONAME || n.Op == OLITERAL {
|
2016-09-16 11:00:54 +10:00
|
|
|
r := nod(OCONVNOP, n, nil)
|
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
|
|
|
r.Type = types.Types[TBOOL]
|
2017-04-25 18:02:43 -07:00
|
|
|
r.SetTypecheck(1)
|
2017-02-27 19:56:38 +02:00
|
|
|
r.SetImplicit(true)
|
2015-02-13 14:40:36 -05:00
|
|
|
n = r
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-18 15:24:50 -07:00
|
|
|
if types.Identical(n.Type, t) {
|
2015-02-13 14:40:36 -05:00
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var why string
|
|
|
|
|
op := assignop(n.Type, t, &why)
|
2015-02-13 14:40:36 -05:00
|
|
|
if op == 0 {
|
2017-04-13 10:42:16 +02:00
|
|
|
if !old.Diag() {
|
|
|
|
|
yyerror("cannot use %L as type %v in %s%s", n, t, context(), why)
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
op = OCONV
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-16 11:00:54 +10:00
|
|
|
r := nod(op, n, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
r.Type = t
|
2017-04-25 18:02:43 -07:00
|
|
|
r.SetTypecheck(1)
|
2017-02-27 19:56:38 +02:00
|
|
|
r.SetImplicit(true)
|
2015-02-13 14:40:36 -05:00
|
|
|
r.Orig = n.Orig
|
|
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-11 14:43:37 -07:00
|
|
|
// IsMethod reports whether n is a method.
|
|
|
|
|
// n must be a function or a method.
|
|
|
|
|
func (n *Node) IsMethod() bool {
|
|
|
|
|
return n.Type.Recv() != nil
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-21 11:55:33 -07:00
|
|
|
// SliceBounds returns n's slice bounds: low, high, and max in expr[low:high:max].
|
|
|
|
|
// n must be a slice expression. max is nil if n is a simple slice expression.
|
|
|
|
|
func (n *Node) SliceBounds() (low, high, max *Node) {
|
2016-04-21 19:35:26 -07:00
|
|
|
if n.List.Len() == 0 {
|
|
|
|
|
return nil, nil, nil
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-21 11:55:33 -07:00
|
|
|
switch n.Op {
|
|
|
|
|
case OSLICE, OSLICEARR, OSLICESTR:
|
2016-04-21 19:35:26 -07:00
|
|
|
s := n.List.Slice()
|
|
|
|
|
return s[0], s[1], nil
|
2016-04-21 11:55:33 -07:00
|
|
|
case OSLICE3, OSLICE3ARR:
|
2016-04-21 19:35:26 -07:00
|
|
|
s := n.List.Slice()
|
|
|
|
|
return s[0], s[1], s[2]
|
2016-04-21 11:55:33 -07:00
|
|
|
}
|
2016-09-09 21:08:46 -07:00
|
|
|
Fatalf("SliceBounds op %v: %v", n.Op, n)
|
2016-04-21 11:55:33 -07:00
|
|
|
return nil, nil, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetSliceBounds sets n's slice bounds, where n is a slice expression.
|
|
|
|
|
// n must be a slice expression. If max is non-nil, n must be a full slice expression.
|
|
|
|
|
func (n *Node) SetSliceBounds(low, high, max *Node) {
|
|
|
|
|
switch n.Op {
|
|
|
|
|
case OSLICE, OSLICEARR, OSLICESTR:
|
|
|
|
|
if max != nil {
|
2016-09-09 21:08:46 -07:00
|
|
|
Fatalf("SetSliceBounds %v given three bounds", n.Op)
|
2016-04-21 11:55:33 -07:00
|
|
|
}
|
2016-04-21 19:35:26 -07:00
|
|
|
s := n.List.Slice()
|
|
|
|
|
if s == nil {
|
|
|
|
|
if low == nil && high == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
2017-02-19 15:57:58 +01:00
|
|
|
n.List.Set2(low, high)
|
2016-04-21 11:55:33 -07:00
|
|
|
return
|
|
|
|
|
}
|
2016-04-21 19:35:26 -07:00
|
|
|
s[0] = low
|
|
|
|
|
s[1] = high
|
2016-04-21 11:55:33 -07:00
|
|
|
return
|
|
|
|
|
case OSLICE3, OSLICE3ARR:
|
2016-04-21 19:35:26 -07:00
|
|
|
s := n.List.Slice()
|
|
|
|
|
if s == nil {
|
|
|
|
|
if low == nil && high == nil && max == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
2017-02-19 15:57:58 +01:00
|
|
|
n.List.Set3(low, high, max)
|
2016-04-21 19:35:26 -07:00
|
|
|
return
|
2016-04-21 11:55:33 -07:00
|
|
|
}
|
2016-04-21 19:35:26 -07:00
|
|
|
s[0] = low
|
|
|
|
|
s[1] = high
|
|
|
|
|
s[2] = max
|
2016-04-21 11:55:33 -07:00
|
|
|
return
|
|
|
|
|
}
|
2016-09-09 21:08:46 -07:00
|
|
|
Fatalf("SetSliceBounds op %v: %v", n.Op, n)
|
2016-04-21 11:55:33 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// IsSlice3 reports whether o is a slice3 op (OSLICE3, OSLICE3ARR).
|
|
|
|
|
// o must be a slicing op.
|
|
|
|
|
func (o Op) IsSlice3() bool {
|
|
|
|
|
switch o {
|
|
|
|
|
case OSLICE, OSLICEARR, OSLICESTR:
|
|
|
|
|
return false
|
|
|
|
|
case OSLICE3, OSLICE3ARR:
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
Fatalf("IsSlice3 op %v", o)
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-14 11:05:03 -07:00
|
|
|
// labeledControl returns the control flow Node (for, switch, select)
|
|
|
|
|
// associated with the label n, if any.
|
|
|
|
|
func (n *Node) labeledControl() *Node {
|
|
|
|
|
if n.Op != OLABEL {
|
|
|
|
|
Fatalf("labeledControl %v", n.Op)
|
|
|
|
|
}
|
|
|
|
|
ctl := n.Name.Defn
|
|
|
|
|
if ctl == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
switch ctl.Op {
|
|
|
|
|
case OFOR, OFORUNTIL, OSWITCH, OSELECT:
|
|
|
|
|
return ctl
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-04 15:19:06 -08:00
|
|
|
func syslook(name string) *Node {
|
2017-03-30 13:19:18 -07:00
|
|
|
s := Runtimepkg.Lookup(name)
|
2015-02-13 14:40:36 -05:00
|
|
|
if s == nil || s.Def == nil {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("syslook: can't find runtime.%s", name)
|
2015-02-13 14:40:36 -05: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
|
|
|
return asNode(s.Def)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-11-06 11:08:08 -08:00
|
|
|
// typehash computes a hash value for type t to use in type switch statements.
|
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 typehash(t *types.Type) uint32 {
|
2016-11-06 11:08:08 -08:00
|
|
|
p := t.LongString()
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-03-17 01:39:59 -07:00
|
|
|
// Using MD5 is overkill, but reduces accidental collisions.
|
2015-02-27 16:05:30 +09:00
|
|
|
h := md5.Sum([]byte(p))
|
|
|
|
|
return binary.LittleEndian.Uint32(h[:4])
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2017-03-03 13:38:49 -08:00
|
|
|
// updateHasCall checks whether expression n contains any function
|
|
|
|
|
// calls and sets the n.HasCall flag if so.
|
|
|
|
|
func updateHasCall(n *Node) {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n == nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
2017-10-20 11:56:31 +01:00
|
|
|
n.SetHasCall(calcHasCall(n))
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2017-10-20 11:56:31 +01:00
|
|
|
func calcHasCall(n *Node) bool {
|
2016-03-08 15:10:26 -08:00
|
|
|
if n.Ninit.Len() != 0 {
|
2017-03-03 13:38:49 -08:00
|
|
|
// TODO(mdempsky): This seems overly conservative.
|
2017-10-20 11:56:31 +01:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch n.Op {
|
2017-03-24 16:15:10 -07:00
|
|
|
case OLITERAL, ONAME, OTYPE:
|
2017-10-20 11:56:31 +01:00
|
|
|
if n.HasCall() {
|
2017-03-24 16:15:10 -07:00
|
|
|
Fatalf("OLITERAL/ONAME/OTYPE should never have calls: %+v", n)
|
|
|
|
|
}
|
2017-10-20 11:56:31 +01:00
|
|
|
return false
|
2016-12-19 10:30:44 -08:00
|
|
|
case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
|
2017-10-20 11:56:31 +01:00
|
|
|
return true
|
2015-04-01 09:38:44 -07:00
|
|
|
case OANDAND, OOROR:
|
2017-03-03 13:38:49 -08:00
|
|
|
// hard with instrumented code
|
2015-10-20 10:00:07 -07:00
|
|
|
if instrumenting {
|
2017-10-20 11:56:31 +01:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-11-01 15:28:10 -07:00
|
|
|
case OINDEX, OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR,
|
2016-11-02 17:55:53 -07:00
|
|
|
OIND, ODOTPTR, ODOTTYPE, ODIV, OMOD:
|
2016-11-01 15:28:10 -07:00
|
|
|
// These ops might panic, make sure they are done
|
|
|
|
|
// before we start marshaling args for a call. See issue 16760.
|
2017-10-20 11:56:31 +01:00
|
|
|
return true
|
2017-11-10 18:08:48 +01:00
|
|
|
|
|
|
|
|
// When using soft-float, these ops might be rewritten to function calls
|
|
|
|
|
// so we ensure they are evaluated first.
|
|
|
|
|
case OADD, OSUB, OMINUS:
|
|
|
|
|
if thearch.SoftFloat && (isFloat[n.Type.Etype] || isComplex[n.Type.Etype]) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
case OLT, OEQ, ONE, OLE, OGE, OGT:
|
|
|
|
|
if thearch.SoftFloat && (isFloat[n.Left.Type.Etype] || isComplex[n.Left.Type.Etype]) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
case OCONV:
|
|
|
|
|
if thearch.SoftFloat && ((isFloat[n.Type.Etype] || isComplex[n.Type.Etype]) || (isFloat[n.Left.Type.Etype] || isComplex[n.Left.Type.Etype])) {
|
|
|
|
|
return true
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2017-03-03 13:38:49 -08:00
|
|
|
if n.Left != nil && n.Left.HasCall() {
|
2017-10-20 11:56:31 +01:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2017-03-03 13:38:49 -08:00
|
|
|
if n.Right != nil && n.Right.HasCall() {
|
2017-10-20 11:56:31 +01:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2017-10-20 11:56:31 +01:00
|
|
|
return false
|
2015-02-13 14:40:36 -05: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 badtype(op Op, tl *types.Type, tr *types.Type) {
|
2015-02-23 16:07:24 -05:00
|
|
|
fmt_ := ""
|
2015-02-13 14:40:36 -05:00
|
|
|
if tl != nil {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt_ += fmt.Sprintf("\n\t%v", tl)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if tr != nil {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt_ += fmt.Sprintf("\n\t%v", tr)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// common mistake: *struct and *interface.
|
2016-03-30 15:09:25 -07:00
|
|
|
if tl != nil && tr != nil && tl.IsPtr() && tr.IsPtr() {
|
2016-03-30 14:56:08 -07:00
|
|
|
if tl.Elem().IsStruct() && tr.Elem().IsInterface() {
|
2015-02-28 20:31:32 +00:00
|
|
|
fmt_ += "\n\t(*struct vs *interface)"
|
2016-03-30 14:56:08 -07:00
|
|
|
} else if tl.Elem().IsInterface() && tr.Elem().IsStruct() {
|
2015-02-28 20:31:32 +00:00
|
|
|
fmt_ += "\n\t(*interface vs *struct)"
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
s := fmt_
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("illegal types for operand: %v%s", op, s)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-09-15 15:45:10 +10:00
|
|
|
// brcom returns !(op).
|
|
|
|
|
// For example, brcom(==) is !=.
|
|
|
|
|
func brcom(op Op) Op {
|
2015-09-24 23:21:18 +02:00
|
|
|
switch op {
|
2015-02-13 14:40:36 -05:00
|
|
|
case OEQ:
|
|
|
|
|
return ONE
|
|
|
|
|
case ONE:
|
|
|
|
|
return OEQ
|
|
|
|
|
case OLT:
|
|
|
|
|
return OGE
|
|
|
|
|
case OGT:
|
|
|
|
|
return OLE
|
|
|
|
|
case OLE:
|
|
|
|
|
return OGT
|
|
|
|
|
case OGE:
|
|
|
|
|
return OLT
|
|
|
|
|
}
|
2016-04-27 15:10:10 +10:00
|
|
|
Fatalf("brcom: no com for %v\n", op)
|
2015-09-24 23:21:18 +02:00
|
|
|
return op
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-09-15 15:45:10 +10:00
|
|
|
// brrev returns reverse(op).
|
2015-04-06 19:36:36 -07:00
|
|
|
// For example, Brrev(<) is >.
|
2016-09-15 15:45:10 +10:00
|
|
|
func brrev(op Op) Op {
|
2015-09-24 23:21:18 +02:00
|
|
|
switch op {
|
2015-02-13 14:40:36 -05:00
|
|
|
case OEQ:
|
|
|
|
|
return OEQ
|
|
|
|
|
case ONE:
|
|
|
|
|
return ONE
|
|
|
|
|
case OLT:
|
|
|
|
|
return OGT
|
|
|
|
|
case OGT:
|
|
|
|
|
return OLT
|
|
|
|
|
case OLE:
|
|
|
|
|
return OGE
|
|
|
|
|
case OGE:
|
|
|
|
|
return OLE
|
|
|
|
|
}
|
2016-04-27 15:10:10 +10:00
|
|
|
Fatalf("brrev: no rev for %v\n", op)
|
2015-09-24 23:21:18 +02:00
|
|
|
return op
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-10-22 09:51:12 +09:00
|
|
|
// return side effect-free n, appending side effects to init.
|
|
|
|
|
// result is assignable if n is.
|
2016-03-07 22:54:46 -08:00
|
|
|
func safeexpr(n *Node, init *Nodes) *Node {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-08 15:10:26 -08:00
|
|
|
if n.Ninit.Len() != 0 {
|
2016-03-07 22:54:46 -08:00
|
|
|
walkstmtlist(n.Ninit.Slice())
|
|
|
|
|
init.AppendNodes(&n.Ninit)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch n.Op {
|
2015-04-01 09:38:44 -07:00
|
|
|
case ONAME, OLITERAL:
|
2015-02-13 14:40:36 -05:00
|
|
|
return n
|
|
|
|
|
|
cmd/internal/gc: optimize slice + write barrier
The code generated for a slice x[i:j] or x[i:j:k] computes the entire
new slice (base, len, cap) and then uses it as the evaluation of the
slice expression.
If the slice is part of an update x = x[i:j] or x = x[i:j:k], there are
opportunities to avoid computing some of these fields.
For x = x[0:i], we know that only the len is changing;
base can be ignored completely, and cap can be left unmodified.
For x = x[0:i:j], we know that only len and cap are changing;
base can be ignored completely.
For x = x[i:i], we know that the resulting cap is zero, and we don't
adjust the base during a slice producing a zero-cap result,
so again base can be ignored completely.
No write to base, no write barrier.
The old slice code was trying to work at a Go syntax level, mainly
because that was how you wrote code just once instead of once
per architecture. Now the compiler is factored a bit better and we
can implement slice during code generation but still have one copy
of the code. So the new code is working at that lower level.
(It must, to update only parts of the result.)
This CL by itself:
name old mean new mean delta
BinaryTree17 5.81s × (0.98,1.03) 5.71s × (0.96,1.05) ~ (p=0.101)
Fannkuch11 4.35s × (1.00,1.00) 4.39s × (1.00,1.00) +0.79% (p=0.000)
FmtFprintfEmpty 86.0ns × (0.94,1.11) 82.6ns × (0.98,1.04) -3.86% (p=0.048)
FmtFprintfString 276ns × (0.98,1.04) 273ns × (0.98,1.02) ~ (p=0.235)
FmtFprintfInt 274ns × (0.98,1.06) 270ns × (0.99,1.01) ~ (p=0.119)
FmtFprintfIntInt 506ns × (0.99,1.01) 475ns × (0.99,1.01) -6.02% (p=0.000)
FmtFprintfPrefixedInt 391ns × (0.99,1.01) 393ns × (1.00,1.01) ~ (p=0.139)
FmtFprintfFloat 566ns × (0.99,1.01) 574ns × (1.00,1.01) +1.33% (p=0.001)
FmtManyArgs 1.91µs × (0.99,1.01) 1.87µs × (0.99,1.02) -1.83% (p=0.000)
GobDecode 15.3ms × (0.99,1.02) 15.0ms × (0.98,1.05) -1.84% (p=0.042)
GobEncode 11.5ms × (0.97,1.03) 11.4ms × (0.99,1.03) ~ (p=0.152)
Gzip 645ms × (0.99,1.01) 647ms × (0.99,1.01) ~ (p=0.265)
Gunzip 142ms × (1.00,1.00) 143ms × (1.00,1.01) +0.90% (p=0.000)
HTTPClientServer 90.5µs × (0.97,1.04) 88.5µs × (0.99,1.03) -2.27% (p=0.014)
JSONEncode 32.0ms × (0.98,1.03) 29.6ms × (0.98,1.01) -7.51% (p=0.000)
JSONDecode 114ms × (0.99,1.01) 104ms × (1.00,1.01) -8.60% (p=0.000)
Mandelbrot200 6.04ms × (1.00,1.01) 6.02ms × (1.00,1.00) ~ (p=0.057)
GoParse 6.47ms × (0.97,1.05) 6.37ms × (0.97,1.04) ~ (p=0.105)
RegexpMatchEasy0_32 171ns × (0.93,1.07) 152ns × (0.99,1.01) -11.09% (p=0.000)
RegexpMatchEasy0_1K 550ns × (0.98,1.01) 530ns × (1.00,1.00) -3.78% (p=0.000)
RegexpMatchEasy1_32 135ns × (0.99,1.02) 134ns × (0.99,1.01) -1.33% (p=0.002)
RegexpMatchEasy1_1K 879ns × (1.00,1.01) 865ns × (1.00,1.00) -1.58% (p=0.000)
RegexpMatchMedium_32 243ns × (1.00,1.00) 233ns × (1.00,1.00) -4.30% (p=0.000)
RegexpMatchMedium_1K 70.3µs × (1.00,1.00) 69.5µs × (1.00,1.00) -1.13% (p=0.000)
RegexpMatchHard_32 3.82µs × (1.00,1.01) 3.74µs × (1.00,1.00) -1.95% (p=0.000)
RegexpMatchHard_1K 117µs × (1.00,1.00) 115µs × (1.00,1.00) -1.69% (p=0.000)
Revcomp 917ms × (0.97,1.04) 920ms × (0.97,1.04) ~ (p=0.786)
Template 114ms × (0.99,1.01) 117ms × (0.99,1.01) +2.58% (p=0.000)
TimeParse 622ns × (0.99,1.01) 615ns × (0.99,1.00) -1.06% (p=0.000)
TimeFormat 665ns × (0.99,1.01) 654ns × (0.99,1.00) -1.70% (p=0.000)
This CL and previous CL (append) combined:
name old mean new mean delta
BinaryTree17 5.68s × (0.97,1.04) 5.71s × (0.96,1.05) ~ (p=0.638)
Fannkuch11 4.41s × (0.98,1.03) 4.39s × (1.00,1.00) ~ (p=0.474)
FmtFprintfEmpty 92.7ns × (0.91,1.16) 82.6ns × (0.98,1.04) -10.89% (p=0.004)
FmtFprintfString 281ns × (0.96,1.08) 273ns × (0.98,1.02) ~ (p=0.078)
FmtFprintfInt 288ns × (0.97,1.06) 270ns × (0.99,1.01) -6.37% (p=0.000)
FmtFprintfIntInt 493ns × (0.97,1.04) 475ns × (0.99,1.01) -3.53% (p=0.002)
FmtFprintfPrefixedInt 423ns × (0.97,1.04) 393ns × (1.00,1.01) -7.07% (p=0.000)
FmtFprintfFloat 598ns × (0.99,1.01) 574ns × (1.00,1.01) -4.02% (p=0.000)
FmtManyArgs 1.89µs × (0.98,1.05) 1.87µs × (0.99,1.02) ~ (p=0.305)
GobDecode 14.8ms × (0.98,1.03) 15.0ms × (0.98,1.05) ~ (p=0.237)
GobEncode 12.3ms × (0.98,1.01) 11.4ms × (0.99,1.03) -6.95% (p=0.000)
Gzip 656ms × (0.99,1.05) 647ms × (0.99,1.01) ~ (p=0.101)
Gunzip 142ms × (1.00,1.00) 143ms × (1.00,1.01) +0.58% (p=0.001)
HTTPClientServer 91.2µs × (0.97,1.04) 88.5µs × (0.99,1.03) -3.02% (p=0.003)
JSONEncode 32.6ms × (0.97,1.08) 29.6ms × (0.98,1.01) -9.10% (p=0.000)
JSONDecode 114ms × (0.97,1.05) 104ms × (1.00,1.01) -8.74% (p=0.000)
Mandelbrot200 6.11ms × (0.98,1.04) 6.02ms × (1.00,1.00) ~ (p=0.090)
GoParse 6.66ms × (0.97,1.04) 6.37ms × (0.97,1.04) -4.41% (p=0.000)
RegexpMatchEasy0_32 159ns × (0.99,1.00) 152ns × (0.99,1.01) -4.69% (p=0.000)
RegexpMatchEasy0_1K 538ns × (1.00,1.01) 530ns × (1.00,1.00) -1.57% (p=0.000)
RegexpMatchEasy1_32 138ns × (1.00,1.00) 134ns × (0.99,1.01) -2.91% (p=0.000)
RegexpMatchEasy1_1K 869ns × (0.99,1.01) 865ns × (1.00,1.00) -0.51% (p=0.012)
RegexpMatchMedium_32 252ns × (0.99,1.01) 233ns × (1.00,1.00) -7.85% (p=0.000)
RegexpMatchMedium_1K 72.7µs × (1.00,1.00) 69.5µs × (1.00,1.00) -4.43% (p=0.000)
RegexpMatchHard_32 3.85µs × (1.00,1.00) 3.74µs × (1.00,1.00) -2.74% (p=0.000)
RegexpMatchHard_1K 118µs × (1.00,1.00) 115µs × (1.00,1.00) -2.24% (p=0.000)
Revcomp 920ms × (0.97,1.07) 920ms × (0.97,1.04) ~ (p=0.998)
Template 129ms × (0.98,1.03) 117ms × (0.99,1.01) -9.79% (p=0.000)
TimeParse 619ns × (0.99,1.01) 615ns × (0.99,1.00) -0.57% (p=0.011)
TimeFormat 661ns × (0.98,1.04) 654ns × (0.99,1.00) ~ (p=0.223)
Change-Id: If054d81ab2c71d8d62cf54b5b1fac2af66b387fc
Reviewed-on: https://go-review.googlesource.com/9813
Reviewed-by: David Chase <drchase@google.com>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2015-05-06 12:35:53 -04:00
|
|
|
case ODOT, OLEN, OCAP:
|
2015-02-23 16:07:24 -05:00
|
|
|
l := safeexpr(n.Left, init)
|
2015-02-13 14:40:36 -05:00
|
|
|
if l == n.Left {
|
|
|
|
|
return n
|
|
|
|
|
}
|
2017-10-23 19:57:07 +01:00
|
|
|
r := n.copy()
|
2015-02-13 14:40:36 -05:00
|
|
|
r.Left = l
|
cmd/compile: reduce use of **Node parameters
Escape analysis has a hard time with tree-like
structures (see #13493 and #14858).
This is unlikely to change.
As a result, when invoking a function that accepts
a **Node parameter, we usually allocate a *Node
on the heap. This happens a whole lot.
This CL changes functions from taking a **Node
to acting more like append: It both modifies
the input and returns a replacement for it.
Because of the cascading nature of escape analysis,
in order to get the benefits, I had to modify
almost all such functions. The remaining functions
are in racewalk and the backend. I would be happy
to update them as well in a separate CL.
This CL was created by manually updating the
function signatures and the directly impacted
bits of code. The callsites were then automatically
updated using a bespoke script:
https://gist.github.com/josharian/046b1be7aceae244de39
For ease of reviewing and future understanding,
this CL is also broken down into four CLs,
mailed separately, which show the manual
and the automated changes separately.
They are CLs 20990, 20991, 20992, and 20993.
Passes toolstash -cmp.
name old time/op new time/op delta
Template 335ms ± 5% 324ms ± 5% -3.35% (p=0.000 n=23+24)
Unicode 176ms ± 9% 165ms ± 6% -6.12% (p=0.000 n=23+24)
GoTypes 1.10s ± 4% 1.07s ± 2% -2.77% (p=0.000 n=24+24)
Compiler 5.31s ± 3% 5.15s ± 3% -2.95% (p=0.000 n=24+24)
MakeBash 41.6s ± 1% 41.7s ± 2% ~ (p=0.586 n=23+23)
name old alloc/op new alloc/op delta
Template 63.3MB ± 0% 62.4MB ± 0% -1.36% (p=0.000 n=25+23)
Unicode 42.4MB ± 0% 41.6MB ± 0% -1.99% (p=0.000 n=24+25)
GoTypes 220MB ± 0% 217MB ± 0% -1.11% (p=0.000 n=25+25)
Compiler 994MB ± 0% 973MB ± 0% -2.08% (p=0.000 n=24+25)
name old allocs/op new allocs/op delta
Template 681k ± 0% 574k ± 0% -15.71% (p=0.000 n=24+25)
Unicode 518k ± 0% 413k ± 0% -20.34% (p=0.000 n=25+24)
GoTypes 2.08M ± 0% 1.78M ± 0% -14.62% (p=0.000 n=25+25)
Compiler 9.26M ± 0% 7.64M ± 0% -17.48% (p=0.000 n=25+25)
name old text-bytes new text-bytes delta
HelloSize 578k ± 0% 578k ± 0% ~ (all samples are equal)
CmdGoSize 6.46M ± 0% 6.46M ± 0% ~ (all samples are equal)
name old data-bytes new data-bytes delta
HelloSize 128k ± 0% 128k ± 0% ~ (all samples are equal)
CmdGoSize 281k ± 0% 281k ± 0% ~ (all samples are equal)
name old exe-bytes new exe-bytes delta
HelloSize 921k ± 0% 921k ± 0% ~ (all samples are equal)
CmdGoSize 9.86M ± 0% 9.86M ± 0% ~ (all samples are equal)
Change-Id: I277d95bd56d51c166ef7f560647aeaa092f3f475
Reviewed-on: https://go-review.googlesource.com/20959
Reviewed-by: Dave Cheney <dave@cheney.net>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-03-20 08:03:31 -07:00
|
|
|
r = typecheck(r, Erv)
|
|
|
|
|
r = walkexpr(r, init)
|
2015-02-13 14:40:36 -05:00
|
|
|
return r
|
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case ODOTPTR, OIND:
|
2015-02-23 16:07:24 -05:00
|
|
|
l := safeexpr(n.Left, init)
|
2015-02-13 14:40:36 -05:00
|
|
|
if l == n.Left {
|
|
|
|
|
return n
|
|
|
|
|
}
|
2017-10-23 19:57:07 +01:00
|
|
|
a := n.copy()
|
2015-02-13 14:40:36 -05:00
|
|
|
a.Left = l
|
cmd/compile: reduce use of **Node parameters
Escape analysis has a hard time with tree-like
structures (see #13493 and #14858).
This is unlikely to change.
As a result, when invoking a function that accepts
a **Node parameter, we usually allocate a *Node
on the heap. This happens a whole lot.
This CL changes functions from taking a **Node
to acting more like append: It both modifies
the input and returns a replacement for it.
Because of the cascading nature of escape analysis,
in order to get the benefits, I had to modify
almost all such functions. The remaining functions
are in racewalk and the backend. I would be happy
to update them as well in a separate CL.
This CL was created by manually updating the
function signatures and the directly impacted
bits of code. The callsites were then automatically
updated using a bespoke script:
https://gist.github.com/josharian/046b1be7aceae244de39
For ease of reviewing and future understanding,
this CL is also broken down into four CLs,
mailed separately, which show the manual
and the automated changes separately.
They are CLs 20990, 20991, 20992, and 20993.
Passes toolstash -cmp.
name old time/op new time/op delta
Template 335ms ± 5% 324ms ± 5% -3.35% (p=0.000 n=23+24)
Unicode 176ms ± 9% 165ms ± 6% -6.12% (p=0.000 n=23+24)
GoTypes 1.10s ± 4% 1.07s ± 2% -2.77% (p=0.000 n=24+24)
Compiler 5.31s ± 3% 5.15s ± 3% -2.95% (p=0.000 n=24+24)
MakeBash 41.6s ± 1% 41.7s ± 2% ~ (p=0.586 n=23+23)
name old alloc/op new alloc/op delta
Template 63.3MB ± 0% 62.4MB ± 0% -1.36% (p=0.000 n=25+23)
Unicode 42.4MB ± 0% 41.6MB ± 0% -1.99% (p=0.000 n=24+25)
GoTypes 220MB ± 0% 217MB ± 0% -1.11% (p=0.000 n=25+25)
Compiler 994MB ± 0% 973MB ± 0% -2.08% (p=0.000 n=24+25)
name old allocs/op new allocs/op delta
Template 681k ± 0% 574k ± 0% -15.71% (p=0.000 n=24+25)
Unicode 518k ± 0% 413k ± 0% -20.34% (p=0.000 n=25+24)
GoTypes 2.08M ± 0% 1.78M ± 0% -14.62% (p=0.000 n=25+25)
Compiler 9.26M ± 0% 7.64M ± 0% -17.48% (p=0.000 n=25+25)
name old text-bytes new text-bytes delta
HelloSize 578k ± 0% 578k ± 0% ~ (all samples are equal)
CmdGoSize 6.46M ± 0% 6.46M ± 0% ~ (all samples are equal)
name old data-bytes new data-bytes delta
HelloSize 128k ± 0% 128k ± 0% ~ (all samples are equal)
CmdGoSize 281k ± 0% 281k ± 0% ~ (all samples are equal)
name old exe-bytes new exe-bytes delta
HelloSize 921k ± 0% 921k ± 0% ~ (all samples are equal)
CmdGoSize 9.86M ± 0% 9.86M ± 0% ~ (all samples are equal)
Change-Id: I277d95bd56d51c166ef7f560647aeaa092f3f475
Reviewed-on: https://go-review.googlesource.com/20959
Reviewed-by: Dave Cheney <dave@cheney.net>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-03-20 08:03:31 -07:00
|
|
|
a = walkexpr(a, init)
|
2015-02-13 14:40:36 -05:00
|
|
|
return a
|
|
|
|
|
|
2015-04-01 09:38:44 -07:00
|
|
|
case OINDEX, OINDEXMAP:
|
2015-02-23 16:07:24 -05:00
|
|
|
l := safeexpr(n.Left, init)
|
|
|
|
|
r := safeexpr(n.Right, init)
|
2015-02-13 14:40:36 -05:00
|
|
|
if l == n.Left && r == n.Right {
|
|
|
|
|
return n
|
|
|
|
|
}
|
2017-10-23 19:57:07 +01:00
|
|
|
a := n.copy()
|
2015-02-13 14:40:36 -05:00
|
|
|
a.Left = l
|
|
|
|
|
a.Right = r
|
cmd/compile: reduce use of **Node parameters
Escape analysis has a hard time with tree-like
structures (see #13493 and #14858).
This is unlikely to change.
As a result, when invoking a function that accepts
a **Node parameter, we usually allocate a *Node
on the heap. This happens a whole lot.
This CL changes functions from taking a **Node
to acting more like append: It both modifies
the input and returns a replacement for it.
Because of the cascading nature of escape analysis,
in order to get the benefits, I had to modify
almost all such functions. The remaining functions
are in racewalk and the backend. I would be happy
to update them as well in a separate CL.
This CL was created by manually updating the
function signatures and the directly impacted
bits of code. The callsites were then automatically
updated using a bespoke script:
https://gist.github.com/josharian/046b1be7aceae244de39
For ease of reviewing and future understanding,
this CL is also broken down into four CLs,
mailed separately, which show the manual
and the automated changes separately.
They are CLs 20990, 20991, 20992, and 20993.
Passes toolstash -cmp.
name old time/op new time/op delta
Template 335ms ± 5% 324ms ± 5% -3.35% (p=0.000 n=23+24)
Unicode 176ms ± 9% 165ms ± 6% -6.12% (p=0.000 n=23+24)
GoTypes 1.10s ± 4% 1.07s ± 2% -2.77% (p=0.000 n=24+24)
Compiler 5.31s ± 3% 5.15s ± 3% -2.95% (p=0.000 n=24+24)
MakeBash 41.6s ± 1% 41.7s ± 2% ~ (p=0.586 n=23+23)
name old alloc/op new alloc/op delta
Template 63.3MB ± 0% 62.4MB ± 0% -1.36% (p=0.000 n=25+23)
Unicode 42.4MB ± 0% 41.6MB ± 0% -1.99% (p=0.000 n=24+25)
GoTypes 220MB ± 0% 217MB ± 0% -1.11% (p=0.000 n=25+25)
Compiler 994MB ± 0% 973MB ± 0% -2.08% (p=0.000 n=24+25)
name old allocs/op new allocs/op delta
Template 681k ± 0% 574k ± 0% -15.71% (p=0.000 n=24+25)
Unicode 518k ± 0% 413k ± 0% -20.34% (p=0.000 n=25+24)
GoTypes 2.08M ± 0% 1.78M ± 0% -14.62% (p=0.000 n=25+25)
Compiler 9.26M ± 0% 7.64M ± 0% -17.48% (p=0.000 n=25+25)
name old text-bytes new text-bytes delta
HelloSize 578k ± 0% 578k ± 0% ~ (all samples are equal)
CmdGoSize 6.46M ± 0% 6.46M ± 0% ~ (all samples are equal)
name old data-bytes new data-bytes delta
HelloSize 128k ± 0% 128k ± 0% ~ (all samples are equal)
CmdGoSize 281k ± 0% 281k ± 0% ~ (all samples are equal)
name old exe-bytes new exe-bytes delta
HelloSize 921k ± 0% 921k ± 0% ~ (all samples are equal)
CmdGoSize 9.86M ± 0% 9.86M ± 0% ~ (all samples are equal)
Change-Id: I277d95bd56d51c166ef7f560647aeaa092f3f475
Reviewed-on: https://go-review.googlesource.com/20959
Reviewed-by: Dave Cheney <dave@cheney.net>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-03-20 08:03:31 -07:00
|
|
|
a = walkexpr(a, init)
|
2015-02-13 14:40:36 -05:00
|
|
|
return a
|
2016-04-19 12:26:28 -07:00
|
|
|
|
2016-06-19 07:20:28 -07:00
|
|
|
case OSTRUCTLIT, OARRAYLIT, OSLICELIT:
|
2016-04-19 12:26:28 -07:00
|
|
|
if isStaticCompositeLiteral(n) {
|
|
|
|
|
return n
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// make a copy; must not be used as an lvalue
|
2015-02-17 22:13:49 -05:00
|
|
|
if islvalue(n) {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("missing lvalue case in safeexpr: %v", n)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
return cheapexpr(n, init)
|
|
|
|
|
}
|
|
|
|
|
|
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 copyexpr(n *Node, t *types.Type, init *Nodes) *Node {
|
2015-02-23 16:07:24 -05:00
|
|
|
l := temp(t)
|
2016-09-16 11:00:54 +10:00
|
|
|
a := nod(OAS, l, n)
|
cmd/compile: reduce use of **Node parameters
Escape analysis has a hard time with tree-like
structures (see #13493 and #14858).
This is unlikely to change.
As a result, when invoking a function that accepts
a **Node parameter, we usually allocate a *Node
on the heap. This happens a whole lot.
This CL changes functions from taking a **Node
to acting more like append: It both modifies
the input and returns a replacement for it.
Because of the cascading nature of escape analysis,
in order to get the benefits, I had to modify
almost all such functions. The remaining functions
are in racewalk and the backend. I would be happy
to update them as well in a separate CL.
This CL was created by manually updating the
function signatures and the directly impacted
bits of code. The callsites were then automatically
updated using a bespoke script:
https://gist.github.com/josharian/046b1be7aceae244de39
For ease of reviewing and future understanding,
this CL is also broken down into four CLs,
mailed separately, which show the manual
and the automated changes separately.
They are CLs 20990, 20991, 20992, and 20993.
Passes toolstash -cmp.
name old time/op new time/op delta
Template 335ms ± 5% 324ms ± 5% -3.35% (p=0.000 n=23+24)
Unicode 176ms ± 9% 165ms ± 6% -6.12% (p=0.000 n=23+24)
GoTypes 1.10s ± 4% 1.07s ± 2% -2.77% (p=0.000 n=24+24)
Compiler 5.31s ± 3% 5.15s ± 3% -2.95% (p=0.000 n=24+24)
MakeBash 41.6s ± 1% 41.7s ± 2% ~ (p=0.586 n=23+23)
name old alloc/op new alloc/op delta
Template 63.3MB ± 0% 62.4MB ± 0% -1.36% (p=0.000 n=25+23)
Unicode 42.4MB ± 0% 41.6MB ± 0% -1.99% (p=0.000 n=24+25)
GoTypes 220MB ± 0% 217MB ± 0% -1.11% (p=0.000 n=25+25)
Compiler 994MB ± 0% 973MB ± 0% -2.08% (p=0.000 n=24+25)
name old allocs/op new allocs/op delta
Template 681k ± 0% 574k ± 0% -15.71% (p=0.000 n=24+25)
Unicode 518k ± 0% 413k ± 0% -20.34% (p=0.000 n=25+24)
GoTypes 2.08M ± 0% 1.78M ± 0% -14.62% (p=0.000 n=25+25)
Compiler 9.26M ± 0% 7.64M ± 0% -17.48% (p=0.000 n=25+25)
name old text-bytes new text-bytes delta
HelloSize 578k ± 0% 578k ± 0% ~ (all samples are equal)
CmdGoSize 6.46M ± 0% 6.46M ± 0% ~ (all samples are equal)
name old data-bytes new data-bytes delta
HelloSize 128k ± 0% 128k ± 0% ~ (all samples are equal)
CmdGoSize 281k ± 0% 281k ± 0% ~ (all samples are equal)
name old exe-bytes new exe-bytes delta
HelloSize 921k ± 0% 921k ± 0% ~ (all samples are equal)
CmdGoSize 9.86M ± 0% 9.86M ± 0% ~ (all samples are equal)
Change-Id: I277d95bd56d51c166ef7f560647aeaa092f3f475
Reviewed-on: https://go-review.googlesource.com/20959
Reviewed-by: Dave Cheney <dave@cheney.net>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-03-20 08:03:31 -07:00
|
|
|
a = typecheck(a, Etop)
|
|
|
|
|
a = walkexpr(a, init)
|
2016-03-07 22:54:46 -08:00
|
|
|
init.Append(a)
|
2015-02-13 14:40:36 -05:00
|
|
|
return l
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-22 09:51:12 +09:00
|
|
|
// return side-effect free and cheap n, appending side effects to init.
|
|
|
|
|
// result may not be assignable.
|
2016-03-07 22:54:46 -08:00
|
|
|
func cheapexpr(n *Node, init *Nodes) *Node {
|
2015-02-13 14:40:36 -05:00
|
|
|
switch n.Op {
|
2015-04-01 09:38:44 -07:00
|
|
|
case ONAME, OLITERAL:
|
2015-02-13 14:40:36 -05:00
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return copyexpr(n, n.Type, init)
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-25 20:29:09 -08:00
|
|
|
// Code to resolve elided DOTs in embedded types.
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-25 20:29:09 -08:00
|
|
|
// A Dlist stores a pointer to a TFIELD Type embedded within
|
|
|
|
|
// a TSTRUCT or TINTER Type.
|
|
|
|
|
type Dlist struct {
|
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
|
|
|
field *types.Field
|
2016-02-25 20:29:09 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// dotlist is used by adddot1 to record the path of embedded fields
|
|
|
|
|
// used to access a target field or method.
|
|
|
|
|
// Must be non-nil so that dotpath returns a non-nil slice even if d is zero.
|
|
|
|
|
var dotlist = make([]Dlist, 10)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-25 20:29:09 -08:00
|
|
|
// lookdot0 returns the number of fields or methods named s associated
|
|
|
|
|
// with Type t. If exactly one exists, it will be returned in *save
|
|
|
|
|
// (if save is not nil).
|
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 lookdot0(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) int {
|
2015-02-23 16:07:24 -05:00
|
|
|
u := t
|
2016-03-30 15:09:25 -07:00
|
|
|
if u.IsPtr() {
|
2016-03-30 10:57:47 -07:00
|
|
|
u = u.Elem()
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
c := 0
|
2016-03-30 14:56:08 -07:00
|
|
|
if u.IsStruct() || u.IsInterface() {
|
2016-03-17 01:32:18 -07:00
|
|
|
for _, f := range u.Fields().Slice() {
|
2016-03-17 01:47:16 -07:00
|
|
|
if f.Sym == s || (ignorecase && f.Type.Etype == TFUNC && f.Type.Recv() != nil && strings.EqualFold(f.Sym.Name, s.Name)) {
|
2015-02-13 14:40:36 -05:00
|
|
|
if save != nil {
|
|
|
|
|
*save = f
|
|
|
|
|
}
|
|
|
|
|
c++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-30 13:43:37 -07:00
|
|
|
u = methtype(t)
|
2015-02-13 14:40:36 -05:00
|
|
|
if u != nil {
|
2016-03-17 01:32:18 -07:00
|
|
|
for _, f := range u.Methods().Slice() {
|
2016-02-25 20:36:02 -08:00
|
|
|
if f.Embedded == 0 && (f.Sym == s || (ignorecase && strings.EqualFold(f.Sym.Name, s.Name))) {
|
2015-02-13 14:40:36 -05:00
|
|
|
if save != nil {
|
|
|
|
|
*save = f
|
|
|
|
|
}
|
|
|
|
|
c++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return c
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-25 20:29:09 -08:00
|
|
|
// adddot1 returns the number of fields or methods named s at depth d in Type t.
|
|
|
|
|
// If exactly one exists, it will be returned in *save (if save is not nil),
|
|
|
|
|
// and dotlist will contain the path of embedded fields traversed to find it,
|
|
|
|
|
// in reverse order. If none exist, more will indicate whether t contains any
|
|
|
|
|
// embedded fields at depth d, so callers can decide whether to retry at
|
|
|
|
|
// a greater depth.
|
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 adddot1(s *types.Sym, t *types.Type, d int, save **types.Field, ignorecase bool) (c int, more bool) {
|
2017-03-29 21:00:55 -07:00
|
|
|
if t.Recur() {
|
2016-02-25 20:29:09 -08:00
|
|
|
return
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2017-03-29 21:00:55 -07:00
|
|
|
t.SetRecur(true)
|
2017-10-20 11:56:31 +01:00
|
|
|
defer t.SetRecur(false)
|
2015-02-13 14:40:36 -05: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
|
|
|
var u *types.Type
|
2016-02-25 20:29:09 -08:00
|
|
|
d--
|
|
|
|
|
if d < 0 {
|
|
|
|
|
// We've reached our target depth. If t has any fields/methods
|
|
|
|
|
// named s, then we're done. Otherwise, we still need to check
|
|
|
|
|
// below for embedded fields.
|
2015-02-13 14:40:36 -05:00
|
|
|
c = lookdot0(s, t, save, ignorecase)
|
2016-02-25 20:29:09 -08:00
|
|
|
if c != 0 {
|
2017-10-20 11:56:31 +01:00
|
|
|
return c, false
|
2016-02-25 20:29:09 -08:00
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u = t
|
2016-03-30 15:09:25 -07:00
|
|
|
if u.IsPtr() {
|
2016-03-30 10:57:47 -07:00
|
|
|
u = u.Elem()
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-03-30 14:56:08 -07:00
|
|
|
if !u.IsStruct() && !u.IsInterface() {
|
2017-10-20 11:56:31 +01:00
|
|
|
return c, false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-17 01:32:18 -07:00
|
|
|
for _, f := range u.Fields().Slice() {
|
2016-02-25 20:29:09 -08:00
|
|
|
if f.Embedded == 0 || f.Sym == nil {
|
2015-02-13 14:40:36 -05:00
|
|
|
continue
|
|
|
|
|
}
|
2016-02-25 20:29:09 -08:00
|
|
|
if d < 0 {
|
|
|
|
|
// Found an embedded field at target depth.
|
2017-10-20 11:56:31 +01:00
|
|
|
return c, true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-02-25 20:29:09 -08:00
|
|
|
a, more1 := adddot1(s, f.Type, d, save, ignorecase)
|
2015-02-13 14:40:36 -05:00
|
|
|
if a != 0 && c == 0 {
|
|
|
|
|
dotlist[d].field = f
|
|
|
|
|
}
|
|
|
|
|
c += a
|
2016-02-25 20:29:09 -08:00
|
|
|
if more1 {
|
|
|
|
|
more = true
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-25 20:29:09 -08:00
|
|
|
return c, more
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// dotpath computes the unique shortest explicit selector path to fully qualify
|
|
|
|
|
// a selection expression x.f, where x is of type t and f is the symbol s.
|
|
|
|
|
// If no such path exists, dotpath returns nil.
|
|
|
|
|
// If there are multiple shortest paths to the same depth, ambig is true.
|
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 dotpath(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) (path []Dlist, ambig bool) {
|
2016-02-25 20:29:09 -08:00
|
|
|
// The embedding of types within structs imposes a tree structure onto
|
|
|
|
|
// types: structs parent the types they embed, and types parent their
|
|
|
|
|
// fields or methods. Our goal here is to find the shortest path to
|
|
|
|
|
// a field or method named s in the subtree rooted at t. To accomplish
|
|
|
|
|
// that, we iteratively perform depth-first searches of increasing depth
|
|
|
|
|
// until we either find the named field/method or exhaust the tree.
|
|
|
|
|
for d := 0; ; d++ {
|
|
|
|
|
if d > len(dotlist) {
|
|
|
|
|
dotlist = append(dotlist, Dlist{})
|
|
|
|
|
}
|
|
|
|
|
if c, more := adddot1(s, t, d, save, ignorecase); c == 1 {
|
|
|
|
|
return dotlist[:d], false
|
|
|
|
|
} else if c > 1 {
|
|
|
|
|
return nil, true
|
|
|
|
|
} else if !more {
|
|
|
|
|
return nil, false
|
|
|
|
|
}
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// in T.field
|
|
|
|
|
// find missing fields that
|
|
|
|
|
// will give shortest unique addressing.
|
|
|
|
|
// modify the tree with missing type names.
|
|
|
|
|
func adddot(n *Node) *Node {
|
cmd/compile: reduce use of **Node parameters
Escape analysis has a hard time with tree-like
structures (see #13493 and #14858).
This is unlikely to change.
As a result, when invoking a function that accepts
a **Node parameter, we usually allocate a *Node
on the heap. This happens a whole lot.
This CL changes functions from taking a **Node
to acting more like append: It both modifies
the input and returns a replacement for it.
Because of the cascading nature of escape analysis,
in order to get the benefits, I had to modify
almost all such functions. The remaining functions
are in racewalk and the backend. I would be happy
to update them as well in a separate CL.
This CL was created by manually updating the
function signatures and the directly impacted
bits of code. The callsites were then automatically
updated using a bespoke script:
https://gist.github.com/josharian/046b1be7aceae244de39
For ease of reviewing and future understanding,
this CL is also broken down into four CLs,
mailed separately, which show the manual
and the automated changes separately.
They are CLs 20990, 20991, 20992, and 20993.
Passes toolstash -cmp.
name old time/op new time/op delta
Template 335ms ± 5% 324ms ± 5% -3.35% (p=0.000 n=23+24)
Unicode 176ms ± 9% 165ms ± 6% -6.12% (p=0.000 n=23+24)
GoTypes 1.10s ± 4% 1.07s ± 2% -2.77% (p=0.000 n=24+24)
Compiler 5.31s ± 3% 5.15s ± 3% -2.95% (p=0.000 n=24+24)
MakeBash 41.6s ± 1% 41.7s ± 2% ~ (p=0.586 n=23+23)
name old alloc/op new alloc/op delta
Template 63.3MB ± 0% 62.4MB ± 0% -1.36% (p=0.000 n=25+23)
Unicode 42.4MB ± 0% 41.6MB ± 0% -1.99% (p=0.000 n=24+25)
GoTypes 220MB ± 0% 217MB ± 0% -1.11% (p=0.000 n=25+25)
Compiler 994MB ± 0% 973MB ± 0% -2.08% (p=0.000 n=24+25)
name old allocs/op new allocs/op delta
Template 681k ± 0% 574k ± 0% -15.71% (p=0.000 n=24+25)
Unicode 518k ± 0% 413k ± 0% -20.34% (p=0.000 n=25+24)
GoTypes 2.08M ± 0% 1.78M ± 0% -14.62% (p=0.000 n=25+25)
Compiler 9.26M ± 0% 7.64M ± 0% -17.48% (p=0.000 n=25+25)
name old text-bytes new text-bytes delta
HelloSize 578k ± 0% 578k ± 0% ~ (all samples are equal)
CmdGoSize 6.46M ± 0% 6.46M ± 0% ~ (all samples are equal)
name old data-bytes new data-bytes delta
HelloSize 128k ± 0% 128k ± 0% ~ (all samples are equal)
CmdGoSize 281k ± 0% 281k ± 0% ~ (all samples are equal)
name old exe-bytes new exe-bytes delta
HelloSize 921k ± 0% 921k ± 0% ~ (all samples are equal)
CmdGoSize 9.86M ± 0% 9.86M ± 0% ~ (all samples are equal)
Change-Id: I277d95bd56d51c166ef7f560647aeaa092f3f475
Reviewed-on: https://go-review.googlesource.com/20959
Reviewed-by: Dave Cheney <dave@cheney.net>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-03-20 08:03:31 -07:00
|
|
|
n.Left = typecheck(n.Left, Etype|Erv)
|
2017-02-27 19:56:38 +02:00
|
|
|
if n.Left.Diag() {
|
|
|
|
|
n.SetDiag(true)
|
2016-10-27 11:44:51 +02:00
|
|
|
}
|
2015-02-23 16:07:24 -05:00
|
|
|
t := n.Left.Type
|
2015-02-13 14:40:36 -05:00
|
|
|
if t == nil {
|
2015-03-02 12:35:15 -05:00
|
|
|
return n
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if n.Left.Op == OTYPE {
|
2015-03-02 12:35:15 -05:00
|
|
|
return n
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
cmd/compile: change ODOT and friends to use Sym, not Right
The Node type ODOT and its variants all represent a selector, with a
simple name to the right of the dot. Before this change this was
represented by using an ONAME Node in the Right field. This ONAME node
served no useful purpose. This CL changes these Node types to store the
symbol in the Sym field instead, thus not requiring allocating a Node
for each selector.
When compiling x/tools/go/types this CL eliminates nearly 5000 calls to
newname and reduces the total number of Nodes allocated by about 6.6%.
It seems to cut compilation time by 1 to 2 percent.
Getting this right was somewhat subtle, and I added two dubious changes
to produce the exact same output as before. One is to ishairy in
inl.go: the ONAME node increased the cost of ODOT and friends by 1, and
I retained that, although really ODOT is not more expensive than any
other node. The other is to varexpr in walk.go: because the ONAME in
the Right field of an ODOT has no class, varexpr would always return
false for an ODOT, although in fact for some ODOT's it seemingly ought
to return true; I added an && false for now. I will send separate CLs,
that will break toolstash -cmp, to clean these up.
This CL passes toolstash -cmp.
Change-Id: I4af8a10cc59078c436130ce472f25abc3a9b2f80
Reviewed-on: https://go-review.googlesource.com/20890
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
2016-03-18 16:52:30 -07:00
|
|
|
s := n.Sym
|
2015-02-13 14:40:36 -05:00
|
|
|
if s == nil {
|
2015-03-02 12:35:15 -05:00
|
|
|
return n
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-25 20:36:02 -08:00
|
|
|
switch path, ambig := dotpath(s, t, nil, false); {
|
2016-02-25 20:29:09 -08:00
|
|
|
case path != nil:
|
|
|
|
|
// rebuild elided dots
|
|
|
|
|
for c := len(path) - 1; c >= 0; c-- {
|
2016-09-15 15:45:10 +10:00
|
|
|
n.Left = nodSym(ODOT, n.Left, path[c].field.Sym)
|
2017-02-27 19:56:38 +02:00
|
|
|
n.Left.SetImplicit(true)
|
2014-12-09 07:59:24 -08:00
|
|
|
}
|
2016-02-25 20:29:09 -08:00
|
|
|
case ambig:
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("ambiguous selector %v", n)
|
2016-02-25 20:29:09 -08:00
|
|
|
n.Left = nil
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-27 01:05:48 -07:00
|
|
|
// Code to help generate trampoline functions for methods on embedded
|
|
|
|
|
// types. These are approx the same as the corresponding adddot
|
|
|
|
|
// routines except that they expect to be called with unique tasks and
|
|
|
|
|
// they return the actual methods.
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
type Symlink struct {
|
2018-03-27 01:05:48 -07:00
|
|
|
field *types.Field
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-17 00:44:07 -07:00
|
|
|
var slist []Symlink
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2018-03-27 01:05:48 -07:00
|
|
|
func expand0(t *types.Type) {
|
2015-02-23 16:07:24 -05:00
|
|
|
u := t
|
2016-03-30 15:09:25 -07:00
|
|
|
if u.IsPtr() {
|
2016-03-30 10:57:47 -07:00
|
|
|
u = u.Elem()
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-30 14:56:08 -07:00
|
|
|
if u.IsInterface() {
|
2016-03-17 01:32:18 -07:00
|
|
|
for _, f := range u.Fields().Slice() {
|
2017-03-06 20:00:54 +02:00
|
|
|
if f.Sym.Uniq() {
|
2015-02-13 14:40:36 -05:00
|
|
|
continue
|
|
|
|
|
}
|
2017-03-06 20:00:54 +02:00
|
|
|
f.Sym.SetUniq(true)
|
2018-03-27 01:05:48 -07:00
|
|
|
slist = append(slist, Symlink{field: f})
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-30 13:43:37 -07:00
|
|
|
u = methtype(t)
|
2015-02-13 14:40:36 -05:00
|
|
|
if u != nil {
|
2016-03-17 01:32:18 -07:00
|
|
|
for _, f := range u.Methods().Slice() {
|
2017-03-06 20:00:54 +02:00
|
|
|
if f.Sym.Uniq() {
|
2015-02-13 14:40:36 -05:00
|
|
|
continue
|
|
|
|
|
}
|
2017-03-06 20:00:54 +02:00
|
|
|
f.Sym.SetUniq(true)
|
2018-03-27 01:05:48 -07:00
|
|
|
slist = append(slist, Symlink{field: f})
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-27 01:05:48 -07:00
|
|
|
func expand1(t *types.Type, top bool) {
|
2017-03-29 21:00:55 -07:00
|
|
|
if t.Recur() {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
2017-03-29 21:00:55 -07:00
|
|
|
t.SetRecur(true)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-25 20:29:09 -08:00
|
|
|
if !top {
|
2018-03-27 01:05:48 -07:00
|
|
|
expand0(t)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
u := t
|
2016-03-30 15:09:25 -07:00
|
|
|
if u.IsPtr() {
|
2016-03-30 10:57:47 -07:00
|
|
|
u = u.Elem()
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2017-10-20 11:56:31 +01:00
|
|
|
if u.IsStruct() || u.IsInterface() {
|
|
|
|
|
for _, f := range u.Fields().Slice() {
|
|
|
|
|
if f.Embedded == 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if f.Sym == nil {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2018-03-27 01:05:48 -07:00
|
|
|
expand1(f.Type, false)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-29 21:00:55 -07:00
|
|
|
t.SetRecur(false)
|
2015-02-13 14:40:36 -05: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 expandmeth(t *types.Type) {
|
2016-03-17 00:44:07 -07:00
|
|
|
if t == nil || t.AllMethods().Len() != 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// mark top-level method symbols
|
|
|
|
|
// so that expand1 doesn't consider them.
|
2016-03-17 01:32:18 -07:00
|
|
|
for _, f := range t.Methods().Slice() {
|
2017-03-06 20:00:54 +02:00
|
|
|
f.Sym.SetUniq(true)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// generate all reachable methods
|
2016-03-17 00:44:07 -07:00
|
|
|
slist = slist[:0]
|
2018-03-27 01:05:48 -07:00
|
|
|
expand1(t, true)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// check each method to be uniquely reachable
|
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
|
|
|
var ms []*types.Field
|
2016-03-17 00:44:07 -07:00
|
|
|
for i, sl := range slist {
|
|
|
|
|
slist[i].field = nil
|
2017-03-06 20:00:54 +02:00
|
|
|
sl.field.Sym.SetUniq(false)
|
2016-03-17 00:44:07 -07: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
|
|
|
var f *types.Field
|
2018-03-27 01:05:48 -07:00
|
|
|
path, _ := dotpath(sl.field.Sym, t, &f, false)
|
|
|
|
|
if path == nil {
|
2016-02-25 20:29:09 -08:00
|
|
|
continue
|
|
|
|
|
}
|
2016-03-17 00:44:07 -07:00
|
|
|
|
2016-02-25 20:29:09 -08:00
|
|
|
// dotpath may have dug out arbitrary fields, we only want methods.
|
2016-03-17 01:47:16 -07:00
|
|
|
if f.Type.Etype != TFUNC || f.Type.Recv() == nil {
|
2016-03-17 00:44:07 -07:00
|
|
|
continue
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2016-03-17 00:44:07 -07:00
|
|
|
|
|
|
|
|
// add it to the base type method list
|
|
|
|
|
f = f.Copy()
|
|
|
|
|
f.Embedded = 1 // needs a trampoline
|
2018-03-27 01:05:48 -07:00
|
|
|
for _, d := range path {
|
|
|
|
|
if d.field.Type.IsPtr() {
|
|
|
|
|
f.Embedded = 2
|
|
|
|
|
break
|
|
|
|
|
}
|
2016-03-17 00:44:07 -07:00
|
|
|
}
|
|
|
|
|
ms = append(ms, f)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-17 01:32:18 -07:00
|
|
|
for _, f := range t.Methods().Slice() {
|
2017-03-06 20:00:54 +02:00
|
|
|
f.Sym.SetUniq(false)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-17 00:44:07 -07:00
|
|
|
ms = append(ms, t.Methods().Slice()...)
|
2018-03-15 13:14:41 -07:00
|
|
|
sort.Sort(methcmp(ms))
|
2016-03-17 00:44:07 -07:00
|
|
|
t.AllMethods().Set(ms)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-10-22 09:51:12 +09:00
|
|
|
// Given funarg struct list, return list of ODCLFIELD Node fn args.
|
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 structargs(tl *types.Type, mustname bool) []*Node {
|
2016-03-04 17:28:07 -08:00
|
|
|
var args []*Node
|
2015-02-23 16:07:24 -05:00
|
|
|
gen := 0
|
2016-03-17 01:32:18 -07:00
|
|
|
for _, t := range tl.Fields().Slice() {
|
cmd/compile: replace Field.Nname.Pos with Field.Pos
For struct fields and methods, Field.Nname was only used to store
position information, which means we're allocating an entire ONAME
Node+Name+Param structure just for one field. We can optimize away
these ONAME allocations by instead adding a Field.Pos field.
Unfortunately, we can't get rid of Field.Nname, because it's needed
for function parameters, so Field grows a little bit and now has more
redundant information in those cases. However, that was already the
case (e.g., Field.Sym and Field.Nname.Sym), and it's still a net win
for allocations as demonstrated by the benchmarks below.
Additionally, by moving the ONAME allocation for function parameters
to funcargs, we can avoid allocating them for function parameters that
aren't used in corresponding function bodies (e.g., interface methods,
function-typed variables, and imported functions/methods without
inline bodies).
name old time/op new time/op delta
Template 254ms ± 6% 251ms ± 6% -1.04% (p=0.000 n=487+488)
Unicode 128ms ± 7% 128ms ± 7% ~ (p=0.294 n=482+467)
GoTypes 862ms ± 5% 860ms ± 4% ~ (p=0.075 n=488+471)
Compiler 3.91s ± 4% 3.90s ± 4% -0.39% (p=0.000 n=468+473)
name old user-time/op new user-time/op delta
Template 339ms ±14% 336ms ±14% -1.02% (p=0.001 n=498+494)
Unicode 176ms ±18% 176ms ±25% ~ (p=0.940 n=491+499)
GoTypes 1.13s ± 8% 1.13s ± 9% ~ (p=0.157 n=496+493)
Compiler 5.24s ± 6% 5.21s ± 6% -0.57% (p=0.000 n=485+489)
name old alloc/op new alloc/op delta
Template 38.3MB ± 0% 37.3MB ± 0% -2.58% (p=0.000 n=499+497)
Unicode 29.1MB ± 0% 29.1MB ± 0% -0.03% (p=0.000 n=500+493)
GoTypes 116MB ± 0% 115MB ± 0% -0.65% (p=0.000 n=498+499)
Compiler 492MB ± 0% 487MB ± 0% -1.00% (p=0.000 n=497+498)
name old allocs/op new allocs/op delta
Template 364k ± 0% 360k ± 0% -1.15% (p=0.000 n=499+499)
Unicode 336k ± 0% 336k ± 0% -0.01% (p=0.000 n=500+493)
GoTypes 1.16M ± 0% 1.16M ± 0% -0.30% (p=0.000 n=499+499)
Compiler 4.54M ± 0% 4.51M ± 0% -0.58% (p=0.000 n=494+495)
Passes toolstash-check -gcflags=-dwarf=false. Changes DWARF output
because position information is now tracked more precisely for
function parameters.
Change-Id: Ib8077d70d564cc448c5e4290baceab3a4396d712
Reviewed-on: https://go-review.googlesource.com/108217
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
2018-04-18 22:57:10 -07:00
|
|
|
s := t.Sym
|
|
|
|
|
if mustname && (s == nil || s.Name == "_") {
|
2015-02-13 14:40:36 -05:00
|
|
|
// invent a name so that we can refer to it in the trampoline
|
cmd/compile: replace Field.Nname.Pos with Field.Pos
For struct fields and methods, Field.Nname was only used to store
position information, which means we're allocating an entire ONAME
Node+Name+Param structure just for one field. We can optimize away
these ONAME allocations by instead adding a Field.Pos field.
Unfortunately, we can't get rid of Field.Nname, because it's needed
for function parameters, so Field grows a little bit and now has more
redundant information in those cases. However, that was already the
case (e.g., Field.Sym and Field.Nname.Sym), and it's still a net win
for allocations as demonstrated by the benchmarks below.
Additionally, by moving the ONAME allocation for function parameters
to funcargs, we can avoid allocating them for function parameters that
aren't used in corresponding function bodies (e.g., interface methods,
function-typed variables, and imported functions/methods without
inline bodies).
name old time/op new time/op delta
Template 254ms ± 6% 251ms ± 6% -1.04% (p=0.000 n=487+488)
Unicode 128ms ± 7% 128ms ± 7% ~ (p=0.294 n=482+467)
GoTypes 862ms ± 5% 860ms ± 4% ~ (p=0.075 n=488+471)
Compiler 3.91s ± 4% 3.90s ± 4% -0.39% (p=0.000 n=468+473)
name old user-time/op new user-time/op delta
Template 339ms ±14% 336ms ±14% -1.02% (p=0.001 n=498+494)
Unicode 176ms ±18% 176ms ±25% ~ (p=0.940 n=491+499)
GoTypes 1.13s ± 8% 1.13s ± 9% ~ (p=0.157 n=496+493)
Compiler 5.24s ± 6% 5.21s ± 6% -0.57% (p=0.000 n=485+489)
name old alloc/op new alloc/op delta
Template 38.3MB ± 0% 37.3MB ± 0% -2.58% (p=0.000 n=499+497)
Unicode 29.1MB ± 0% 29.1MB ± 0% -0.03% (p=0.000 n=500+493)
GoTypes 116MB ± 0% 115MB ± 0% -0.65% (p=0.000 n=498+499)
Compiler 492MB ± 0% 487MB ± 0% -1.00% (p=0.000 n=497+498)
name old allocs/op new allocs/op delta
Template 364k ± 0% 360k ± 0% -1.15% (p=0.000 n=499+499)
Unicode 336k ± 0% 336k ± 0% -0.01% (p=0.000 n=500+493)
GoTypes 1.16M ± 0% 1.16M ± 0% -0.30% (p=0.000 n=499+499)
Compiler 4.54M ± 0% 4.51M ± 0% -0.58% (p=0.000 n=494+495)
Passes toolstash-check -gcflags=-dwarf=false. Changes DWARF output
because position information is now tracked more precisely for
function parameters.
Change-Id: Ib8077d70d564cc448c5e4290baceab3a4396d712
Reviewed-on: https://go-review.googlesource.com/108217
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
2018-04-18 22:57:10 -07:00
|
|
|
s = lookupN(".anon", gen)
|
2015-02-13 14:40:36 -05:00
|
|
|
gen++
|
|
|
|
|
}
|
cmd/compile: replace Field.Nname.Pos with Field.Pos
For struct fields and methods, Field.Nname was only used to store
position information, which means we're allocating an entire ONAME
Node+Name+Param structure just for one field. We can optimize away
these ONAME allocations by instead adding a Field.Pos field.
Unfortunately, we can't get rid of Field.Nname, because it's needed
for function parameters, so Field grows a little bit and now has more
redundant information in those cases. However, that was already the
case (e.g., Field.Sym and Field.Nname.Sym), and it's still a net win
for allocations as demonstrated by the benchmarks below.
Additionally, by moving the ONAME allocation for function parameters
to funcargs, we can avoid allocating them for function parameters that
aren't used in corresponding function bodies (e.g., interface methods,
function-typed variables, and imported functions/methods without
inline bodies).
name old time/op new time/op delta
Template 254ms ± 6% 251ms ± 6% -1.04% (p=0.000 n=487+488)
Unicode 128ms ± 7% 128ms ± 7% ~ (p=0.294 n=482+467)
GoTypes 862ms ± 5% 860ms ± 4% ~ (p=0.075 n=488+471)
Compiler 3.91s ± 4% 3.90s ± 4% -0.39% (p=0.000 n=468+473)
name old user-time/op new user-time/op delta
Template 339ms ±14% 336ms ±14% -1.02% (p=0.001 n=498+494)
Unicode 176ms ±18% 176ms ±25% ~ (p=0.940 n=491+499)
GoTypes 1.13s ± 8% 1.13s ± 9% ~ (p=0.157 n=496+493)
Compiler 5.24s ± 6% 5.21s ± 6% -0.57% (p=0.000 n=485+489)
name old alloc/op new alloc/op delta
Template 38.3MB ± 0% 37.3MB ± 0% -2.58% (p=0.000 n=499+497)
Unicode 29.1MB ± 0% 29.1MB ± 0% -0.03% (p=0.000 n=500+493)
GoTypes 116MB ± 0% 115MB ± 0% -0.65% (p=0.000 n=498+499)
Compiler 492MB ± 0% 487MB ± 0% -1.00% (p=0.000 n=497+498)
name old allocs/op new allocs/op delta
Template 364k ± 0% 360k ± 0% -1.15% (p=0.000 n=499+499)
Unicode 336k ± 0% 336k ± 0% -0.01% (p=0.000 n=500+493)
GoTypes 1.16M ± 0% 1.16M ± 0% -0.30% (p=0.000 n=499+499)
Compiler 4.54M ± 0% 4.51M ± 0% -0.58% (p=0.000 n=494+495)
Passes toolstash-check -gcflags=-dwarf=false. Changes DWARF output
because position information is now tracked more precisely for
function parameters.
Change-Id: Ib8077d70d564cc448c5e4290baceab3a4396d712
Reviewed-on: https://go-review.googlesource.com/108217
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
2018-04-18 22:57:10 -07:00
|
|
|
a := symfield(s, t.Type)
|
2018-04-01 01:55:55 -07:00
|
|
|
a.Pos = t.Pos
|
2017-02-27 19:56:38 +02:00
|
|
|
a.SetIsddd(t.Isddd())
|
2016-03-04 17:28:07 -08:00
|
|
|
args = append(args, a)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return args
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-22 09:51:12 +09:00
|
|
|
// Generate a wrapper function to convert from
|
|
|
|
|
// a receiver of type T to a receiver of type U.
|
|
|
|
|
// That is,
|
|
|
|
|
//
|
|
|
|
|
// func (t T) M() {
|
|
|
|
|
// ...
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// already exists; this function generates
|
|
|
|
|
//
|
|
|
|
|
// func (u U) M() {
|
|
|
|
|
// u.M()
|
|
|
|
|
// }
|
|
|
|
|
//
|
|
|
|
|
// where the types T and U are such that u.M() is valid
|
|
|
|
|
// and calls the T.M method.
|
|
|
|
|
// The resulting function is for use in method tables.
|
|
|
|
|
//
|
|
|
|
|
// rcvr - U
|
|
|
|
|
// method - M func (t T)(), a TFIELD type struct
|
|
|
|
|
// newnam - the eventual mangled name of this function
|
2018-04-04 21:49:49 -07:00
|
|
|
func genwrapper(rcvr *types.Type, method *types.Field, newnam *types.Sym) {
|
2015-02-13 14:40:36 -05:00
|
|
|
if false && Debug['r'] != 0 {
|
2015-04-17 12:03:22 -04:00
|
|
|
fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2017-10-30 12:16:30 -07:00
|
|
|
// Only generate (*T).M wrappers for T.M in T's own package.
|
|
|
|
|
if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type &&
|
|
|
|
|
rcvr.Elem().Sym != nil && rcvr.Elem().Sym.Pkg != localpkg {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-10 15:13:49 -07:00
|
|
|
// Only generate I.M wrappers for I in I's own package.
|
|
|
|
|
if rcvr.IsInterface() && rcvr.Sym != nil && rcvr.Sym.Pkg != localpkg {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-28 13:52:14 -07:00
|
|
|
lineno = autogeneratedPos
|
2015-02-13 14:40:36 -05:00
|
|
|
dclcontext = PEXTERN
|
|
|
|
|
|
2018-04-18 23:22:26 -07:00
|
|
|
tfn := nod(OTFUNC, nil, nil)
|
|
|
|
|
tfn.Left = namedfield(".this", rcvr)
|
|
|
|
|
tfn.List.Set(structargs(method.Type.Params(), true))
|
|
|
|
|
tfn.Rlist.Set(structargs(method.Type.Results(), false))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2018-04-18 23:22:26 -07:00
|
|
|
disableExport(newnam)
|
|
|
|
|
fn := dclfunc(newnam, tfn)
|
2017-03-14 14:00:38 -07:00
|
|
|
fn.Func.SetDupok(true)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2018-04-18 23:22:26 -07:00
|
|
|
nthis := asNode(tfn.Type.Recv().Nname)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-03-09 20:54:59 -08:00
|
|
|
methodrcvr := method.Type.Recv().Type
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// generate nil pointer check for better error
|
2016-03-30 15:09:25 -07:00
|
|
|
if rcvr.IsPtr() && rcvr.Elem() == methodrcvr {
|
2015-02-13 14:40:36 -05:00
|
|
|
// generating wrapper from *T to T.
|
2016-09-16 11:00:54 +10:00
|
|
|
n := nod(OIF, nil, nil)
|
2018-04-18 23:22:26 -07:00
|
|
|
n.Left = nod(OEQ, nthis, nodnil())
|
2016-09-16 11:00:54 +10:00
|
|
|
call := nod(OCALL, syslook("panicwrap"), nil)
|
2016-03-10 10:13:42 -08:00
|
|
|
n.Nbody.Set1(call)
|
2016-02-27 14:31:33 -08:00
|
|
|
fn.Nbody.Append(n)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2018-04-18 23:22:26 -07:00
|
|
|
dot := adddot(nodSym(OXDOT, nthis, method.Sym))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// generate call
|
2016-05-27 15:41:55 +12:00
|
|
|
// It's not possible to use a tail call when dynamic linking on ppc64le. The
|
|
|
|
|
// bad scenario is when a local call is made to the wrapper: the wrapper will
|
|
|
|
|
// call the implementation, which might be in a different module and so set
|
|
|
|
|
// the TOC to the appropriate value for that module. But if it returns
|
|
|
|
|
// directly to the wrapper's caller, nothing will reset it to the correct
|
|
|
|
|
// value for that function.
|
2017-03-17 13:35:36 -07:00
|
|
|
if !instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !isifacemethod(method.Type) && !(thearch.LinkArch.Name == "ppc64le" && Ctxt.Flag_dynlink) {
|
2015-02-13 14:40:36 -05:00
|
|
|
// generate tail call: adjust pointer receiver and jump to embedded method.
|
|
|
|
|
dot = dot.Left // skip final .M
|
2016-02-25 20:29:09 -08:00
|
|
|
// TODO(mdempsky): Remove dependency on dotlist.
|
2016-03-30 15:09:25 -07:00
|
|
|
if !dotlist[0].field.Type.IsPtr() {
|
2016-09-16 11:00:54 +10:00
|
|
|
dot = nod(OADDR, dot, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2018-05-10 13:25:39 +02:00
|
|
|
as := nod(OAS, nthis, convnop(dot, rcvr))
|
2016-02-27 14:31:33 -08:00
|
|
|
fn.Nbody.Append(as)
|
2018-04-04 18:42:39 -07:00
|
|
|
fn.Nbody.Append(nodSym(ORETJMP, nil, methodSym(methodrcvr, method.Sym)))
|
2015-02-13 14:40:36 -05:00
|
|
|
} else {
|
2017-02-27 19:56:38 +02:00
|
|
|
fn.Func.SetWrapper(true) // ignore frame for panic+recover matching
|
2016-09-16 11:00:54 +10:00
|
|
|
call := nod(OCALL, dot, nil)
|
2018-04-18 23:22:26 -07:00
|
|
|
call.List.Set(paramNnames(tfn.Type))
|
|
|
|
|
call.SetIsddd(tfn.Type.IsVariadic())
|
2017-05-02 09:16:22 -07:00
|
|
|
if method.Type.NumResults() > 0 {
|
2016-09-16 11:00:54 +10:00
|
|
|
n := nod(ORETURN, nil, nil)
|
2016-03-10 10:13:42 -08:00
|
|
|
n.List.Set1(call)
|
2015-02-13 14:40:36 -05:00
|
|
|
call = n
|
|
|
|
|
}
|
2016-02-27 14:31:33 -08:00
|
|
|
fn.Nbody.Append(call)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if false && Debug['r'] != 0 {
|
2016-03-04 13:16:48 -08:00
|
|
|
dumplist("genwrapper body", fn.Nbody)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2017-08-09 16:13:09 +09:00
|
|
|
funcbody()
|
2017-01-11 13:53:34 -08:00
|
|
|
if debug_dclstack != 0 {
|
|
|
|
|
testdclstack()
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
cmd/compile: reduce use of **Node parameters
Escape analysis has a hard time with tree-like
structures (see #13493 and #14858).
This is unlikely to change.
As a result, when invoking a function that accepts
a **Node parameter, we usually allocate a *Node
on the heap. This happens a whole lot.
This CL changes functions from taking a **Node
to acting more like append: It both modifies
the input and returns a replacement for it.
Because of the cascading nature of escape analysis,
in order to get the benefits, I had to modify
almost all such functions. The remaining functions
are in racewalk and the backend. I would be happy
to update them as well in a separate CL.
This CL was created by manually updating the
function signatures and the directly impacted
bits of code. The callsites were then automatically
updated using a bespoke script:
https://gist.github.com/josharian/046b1be7aceae244de39
For ease of reviewing and future understanding,
this CL is also broken down into four CLs,
mailed separately, which show the manual
and the automated changes separately.
They are CLs 20990, 20991, 20992, and 20993.
Passes toolstash -cmp.
name old time/op new time/op delta
Template 335ms ± 5% 324ms ± 5% -3.35% (p=0.000 n=23+24)
Unicode 176ms ± 9% 165ms ± 6% -6.12% (p=0.000 n=23+24)
GoTypes 1.10s ± 4% 1.07s ± 2% -2.77% (p=0.000 n=24+24)
Compiler 5.31s ± 3% 5.15s ± 3% -2.95% (p=0.000 n=24+24)
MakeBash 41.6s ± 1% 41.7s ± 2% ~ (p=0.586 n=23+23)
name old alloc/op new alloc/op delta
Template 63.3MB ± 0% 62.4MB ± 0% -1.36% (p=0.000 n=25+23)
Unicode 42.4MB ± 0% 41.6MB ± 0% -1.99% (p=0.000 n=24+25)
GoTypes 220MB ± 0% 217MB ± 0% -1.11% (p=0.000 n=25+25)
Compiler 994MB ± 0% 973MB ± 0% -2.08% (p=0.000 n=24+25)
name old allocs/op new allocs/op delta
Template 681k ± 0% 574k ± 0% -15.71% (p=0.000 n=24+25)
Unicode 518k ± 0% 413k ± 0% -20.34% (p=0.000 n=25+24)
GoTypes 2.08M ± 0% 1.78M ± 0% -14.62% (p=0.000 n=25+25)
Compiler 9.26M ± 0% 7.64M ± 0% -17.48% (p=0.000 n=25+25)
name old text-bytes new text-bytes delta
HelloSize 578k ± 0% 578k ± 0% ~ (all samples are equal)
CmdGoSize 6.46M ± 0% 6.46M ± 0% ~ (all samples are equal)
name old data-bytes new data-bytes delta
HelloSize 128k ± 0% 128k ± 0% ~ (all samples are equal)
CmdGoSize 281k ± 0% 281k ± 0% ~ (all samples are equal)
name old exe-bytes new exe-bytes delta
HelloSize 921k ± 0% 921k ± 0% ~ (all samples are equal)
CmdGoSize 9.86M ± 0% 9.86M ± 0% ~ (all samples are equal)
Change-Id: I277d95bd56d51c166ef7f560647aeaa092f3f475
Reviewed-on: https://go-review.googlesource.com/20959
Reviewed-by: Dave Cheney <dave@cheney.net>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-03-20 08:03:31 -07:00
|
|
|
fn = typecheck(fn, Etop)
|
2018-04-18 23:22:26 -07:00
|
|
|
|
|
|
|
|
Curfn = fn
|
2016-03-19 17:02:01 -07:00
|
|
|
typecheckslice(fn.Nbody.Slice(), Etop)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2018-09-17 14:08:03 -05:00
|
|
|
// Inline calls within (*T).M wrappers. This is safe because we only
|
|
|
|
|
// generate those wrappers within the same compilation unit as (T).M.
|
|
|
|
|
// TODO(mdempsky): Investigate why we can't enable this more generally.
|
|
|
|
|
if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && rcvr.Elem().Sym != nil {
|
2018-04-01 01:55:55 -07:00
|
|
|
inlcalls(fn)
|
|
|
|
|
}
|
2015-09-05 12:30:13 +10:00
|
|
|
escAnalyze([]*Node{fn}, false)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
Curfn = nil
|
|
|
|
|
funccompile(fn)
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-18 23:22:26 -07:00
|
|
|
func paramNnames(ft *types.Type) []*Node {
|
|
|
|
|
args := make([]*Node, ft.NumParams())
|
|
|
|
|
for i, f := range ft.Params().FieldSlice() {
|
|
|
|
|
args[i] = asNode(f.Nname)
|
|
|
|
|
}
|
|
|
|
|
return args
|
|
|
|
|
}
|
|
|
|
|
|
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 hashmem(t *types.Type) *Node {
|
2017-03-30 13:19:18 -07:00
|
|
|
sym := Runtimepkg.Lookup("memhash")
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
n := newname(sym)
|
2017-04-25 18:14:12 -07:00
|
|
|
n.SetClass(PFUNC)
|
2017-04-07 15:39:36 -07:00
|
|
|
n.Type = functype(nil, []*Node{
|
|
|
|
|
anonfield(types.NewPtr(t)),
|
|
|
|
|
anonfield(types.Types[TUINTPTR]),
|
|
|
|
|
anonfield(types.Types[TUINTPTR]),
|
|
|
|
|
}, []*Node{
|
|
|
|
|
anonfield(types.Types[TUINTPTR]),
|
|
|
|
|
})
|
2015-02-13 14:40:36 -05:00
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-24 17:15:30 +01:00
|
|
|
func ifacelookdot(s *types.Sym, t *types.Type, ignorecase bool) (m *types.Field, followptr bool) {
|
2015-02-13 14:40:36 -05:00
|
|
|
if t == nil {
|
2017-10-24 17:15:30 +01:00
|
|
|
return nil, false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-25 20:29:09 -08:00
|
|
|
path, ambig := dotpath(s, t, &m, ignorecase)
|
|
|
|
|
if path == nil {
|
|
|
|
|
if ambig {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("%v.%v is ambiguous", t, s)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2017-10-24 17:15:30 +01:00
|
|
|
return nil, false
|
2016-02-25 20:29:09 -08:00
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2016-02-25 20:29:09 -08:00
|
|
|
for _, d := range path {
|
2016-03-30 15:09:25 -07:00
|
|
|
if d.field.Type.IsPtr() {
|
2017-10-24 17:15:30 +01:00
|
|
|
followptr = true
|
2016-02-25 20:29:09 -08:00
|
|
|
break
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-17 01:47:16 -07:00
|
|
|
if m.Type.Etype != TFUNC || m.Type.Recv() == nil {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("%v.%v is a field, not a method", t, s)
|
2017-10-24 17:15:30 +01:00
|
|
|
return nil, followptr
|
2016-02-25 20:29:09 -08:00
|
|
|
}
|
|
|
|
|
|
2017-10-24 17:15:30 +01:00
|
|
|
return m, followptr
|
2015-02-13 14:40:36 -05: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 implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool {
|
2015-02-23 16:07:24 -05:00
|
|
|
t0 := t
|
2015-02-13 14:40:36 -05:00
|
|
|
if t == nil {
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-03-30 14:56:08 -07:00
|
|
|
if t.IsInterface() {
|
2018-03-15 13:14:41 -07:00
|
|
|
i := 0
|
|
|
|
|
tms := t.Fields().Slice()
|
2016-03-17 01:32:18 -07:00
|
|
|
for _, im := range iface.Fields().Slice() {
|
2018-03-15 13:14:41 -07:00
|
|
|
for i < len(tms) && tms[i].Sym != im.Sym {
|
|
|
|
|
i++
|
|
|
|
|
}
|
|
|
|
|
if i == len(tms) {
|
|
|
|
|
*m = im
|
|
|
|
|
*samename = nil
|
|
|
|
|
*ptr = 0
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
tm := tms[i]
|
2018-10-18 15:24:50 -07:00
|
|
|
if !types.Identical(tm.Type, im.Type) {
|
2018-03-15 13:14:41 -07:00
|
|
|
*m = im
|
|
|
|
|
*samename = tm
|
|
|
|
|
*ptr = 0
|
|
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-08-30 13:43:37 -07:00
|
|
|
t = methtype(t)
|
2018-03-15 13:14:41 -07:00
|
|
|
var tms []*types.Field
|
2015-02-13 14:40:36 -05:00
|
|
|
if t != nil {
|
|
|
|
|
expandmeth(t)
|
2018-03-15 13:14:41 -07:00
|
|
|
tms = t.AllMethods().Slice()
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2018-03-15 13:14:41 -07:00
|
|
|
i := 0
|
2016-03-17 01:32:18 -07:00
|
|
|
for _, im := range iface.Fields().Slice() {
|
2017-02-27 19:56:38 +02:00
|
|
|
if im.Broke() {
|
2015-08-21 22:24:20 -04:00
|
|
|
continue
|
|
|
|
|
}
|
2018-03-15 13:14:41 -07:00
|
|
|
for i < len(tms) && tms[i].Sym != im.Sym {
|
|
|
|
|
i++
|
|
|
|
|
}
|
|
|
|
|
if i == len(tms) {
|
|
|
|
|
*m = im
|
|
|
|
|
*samename, _ = ifacelookdot(im.Sym, t, true)
|
|
|
|
|
*ptr = 0
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
tm := tms[i]
|
2018-10-18 15:24:50 -07:00
|
|
|
if tm.Nointerface() || !types.Identical(tm.Type, im.Type) {
|
2015-02-13 14:40:36 -05:00
|
|
|
*m = im
|
|
|
|
|
*samename = tm
|
|
|
|
|
*ptr = 0
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2018-03-15 13:14:41 -07:00
|
|
|
followptr := tm.Embedded == 2
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// if pointer receiver in method,
|
|
|
|
|
// the method does not exist for value types.
|
2016-03-14 01:20:49 -07:00
|
|
|
rcvr := tm.Type.Recv().Type
|
2016-03-30 15:09:25 -07:00
|
|
|
if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !isifacemethod(tm.Type) {
|
2015-02-13 14:40:36 -05:00
|
|
|
if false && Debug['r'] != 0 {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("interface pointer mismatch")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*m = im
|
|
|
|
|
*samename = nil
|
|
|
|
|
*ptr = 1
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
cmd/compile: de-virtualize interface calls
With this change, code like
h := sha1.New()
h.Write(buf)
sum := h.Sum()
gets compiled into static calls rather than
interface calls, because the compiler is able
to prove that 'h' is really a *sha1.digest.
The InterCall re-write rule hits a few dozen times
during make.bash, and hundreds of times during all.bash.
The most common pattern identified by the compiler
is a constructor like
func New() Interface { return &impl{...} }
where the constructor gets inlined into the caller,
and the result is used immediately. Examples include
{sha1,md5,crc32,crc64,...}.New, base64.NewEncoder,
base64.NewDecoder, errors.New, net.Pipe, and so on.
Some existing benchmarks that change on darwin/amd64:
Crc64/ISO4KB-8 2.67µs ± 1% 2.66µs ± 0% -0.36% (p=0.015 n=10+10)
Crc64/ISO1KB-8 694ns ± 0% 690ns ± 1% -0.59% (p=0.001 n=10+10)
Adler32KB-8 473ns ± 1% 471ns ± 0% -0.39% (p=0.010 n=10+9)
On architectures like amd64, the reduction in code size
appears to contribute more to benchmark improvements than just
removing the indirect call, since that branch gets predicted
accurately when called in a loop.
Updates #19361
Change-Id: I57d4dc21ef40a05ec0fbd55a9bb0eb74cdc67a3d
Reviewed-on: https://go-review.googlesource.com/38139
Run-TryBot: Philip Hofer <phofer@umich.edu>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
2017-03-13 15:03:17 -07:00
|
|
|
// We're going to emit an OCONVIFACE.
|
|
|
|
|
// Call itabname so that (t, iface)
|
|
|
|
|
// gets added to itabs early, which allows
|
|
|
|
|
// us to de-virtualize calls through this
|
|
|
|
|
// type/interface pair later. See peekitabs in reflect.go
|
|
|
|
|
if isdirectiface(t0) && !iface.IsEmptyInterface() {
|
|
|
|
|
itabname(t0, iface)
|
|
|
|
|
}
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-12-15 17:17:01 -08:00
|
|
|
func listtreecopy(l []*Node, pos src.XPos) []*Node {
|
2016-03-04 17:28:07 -08:00
|
|
|
var out []*Node
|
2016-03-08 15:10:26 -08:00
|
|
|
for _, n := range l {
|
2016-12-09 17:15:05 -08:00
|
|
|
out = append(out, treecopy(n, pos))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
return out
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-08 10:26:20 -08:00
|
|
|
func liststmt(l []*Node) *Node {
|
2016-09-16 11:00:54 +10:00
|
|
|
n := nod(OBLOCK, nil, nil)
|
2016-03-08 15:10:26 -08:00
|
|
|
n.List.Set(l)
|
2016-03-09 20:29:21 -08:00
|
|
|
if len(l) != 0 {
|
2016-12-07 17:40:46 -08:00
|
|
|
n.Pos = l[0].Pos
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-27 14:48:24 -07:00
|
|
|
func (l Nodes) asblock() *Node {
|
|
|
|
|
n := nod(OBLOCK, nil, nil)
|
|
|
|
|
n.List = l
|
|
|
|
|
if l.Len() != 0 {
|
|
|
|
|
n.Pos = l.First().Pos
|
|
|
|
|
}
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
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 ngotype(n *Node) *types.Sym {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Type != nil {
|
|
|
|
|
return typenamesym(n.Type)
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
cmd/compile: reduce use of **Node parameters
Escape analysis has a hard time with tree-like
structures (see #13493 and #14858).
This is unlikely to change.
As a result, when invoking a function that accepts
a **Node parameter, we usually allocate a *Node
on the heap. This happens a whole lot.
This CL changes functions from taking a **Node
to acting more like append: It both modifies
the input and returns a replacement for it.
Because of the cascading nature of escape analysis,
in order to get the benefits, I had to modify
almost all such functions. The remaining functions
are in racewalk and the backend. I would be happy
to update them as well in a separate CL.
This CL was created by manually updating the
function signatures and the directly impacted
bits of code. The callsites were then automatically
updated using a bespoke script:
https://gist.github.com/josharian/046b1be7aceae244de39
For ease of reviewing and future understanding,
this CL is also broken down into four CLs,
mailed separately, which show the manual
and the automated changes separately.
They are CLs 20990, 20991, 20992, and 20993.
Passes toolstash -cmp.
name old time/op new time/op delta
Template 335ms ± 5% 324ms ± 5% -3.35% (p=0.000 n=23+24)
Unicode 176ms ± 9% 165ms ± 6% -6.12% (p=0.000 n=23+24)
GoTypes 1.10s ± 4% 1.07s ± 2% -2.77% (p=0.000 n=24+24)
Compiler 5.31s ± 3% 5.15s ± 3% -2.95% (p=0.000 n=24+24)
MakeBash 41.6s ± 1% 41.7s ± 2% ~ (p=0.586 n=23+23)
name old alloc/op new alloc/op delta
Template 63.3MB ± 0% 62.4MB ± 0% -1.36% (p=0.000 n=25+23)
Unicode 42.4MB ± 0% 41.6MB ± 0% -1.99% (p=0.000 n=24+25)
GoTypes 220MB ± 0% 217MB ± 0% -1.11% (p=0.000 n=25+25)
Compiler 994MB ± 0% 973MB ± 0% -2.08% (p=0.000 n=24+25)
name old allocs/op new allocs/op delta
Template 681k ± 0% 574k ± 0% -15.71% (p=0.000 n=24+25)
Unicode 518k ± 0% 413k ± 0% -20.34% (p=0.000 n=25+24)
GoTypes 2.08M ± 0% 1.78M ± 0% -14.62% (p=0.000 n=25+25)
Compiler 9.26M ± 0% 7.64M ± 0% -17.48% (p=0.000 n=25+25)
name old text-bytes new text-bytes delta
HelloSize 578k ± 0% 578k ± 0% ~ (all samples are equal)
CmdGoSize 6.46M ± 0% 6.46M ± 0% ~ (all samples are equal)
name old data-bytes new data-bytes delta
HelloSize 128k ± 0% 128k ± 0% ~ (all samples are equal)
CmdGoSize 281k ± 0% 281k ± 0% ~ (all samples are equal)
name old exe-bytes new exe-bytes delta
HelloSize 921k ± 0% 921k ± 0% ~ (all samples are equal)
CmdGoSize 9.86M ± 0% 9.86M ± 0% ~ (all samples are equal)
Change-Id: I277d95bd56d51c166ef7f560647aeaa092f3f475
Reviewed-on: https://go-review.googlesource.com/20959
Reviewed-by: Dave Cheney <dave@cheney.net>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-03-20 08:03:31 -07:00
|
|
|
// The result of addinit MUST be assigned back to n, e.g.
|
|
|
|
|
// n.Left = addinit(n.Left, init)
|
|
|
|
|
func addinit(n *Node, init []*Node) *Node {
|
2016-03-09 20:29:21 -08:00
|
|
|
if len(init) == 0 {
|
cmd/compile: reduce use of **Node parameters
Escape analysis has a hard time with tree-like
structures (see #13493 and #14858).
This is unlikely to change.
As a result, when invoking a function that accepts
a **Node parameter, we usually allocate a *Node
on the heap. This happens a whole lot.
This CL changes functions from taking a **Node
to acting more like append: It both modifies
the input and returns a replacement for it.
Because of the cascading nature of escape analysis,
in order to get the benefits, I had to modify
almost all such functions. The remaining functions
are in racewalk and the backend. I would be happy
to update them as well in a separate CL.
This CL was created by manually updating the
function signatures and the directly impacted
bits of code. The callsites were then automatically
updated using a bespoke script:
https://gist.github.com/josharian/046b1be7aceae244de39
For ease of reviewing and future understanding,
this CL is also broken down into four CLs,
mailed separately, which show the manual
and the automated changes separately.
They are CLs 20990, 20991, 20992, and 20993.
Passes toolstash -cmp.
name old time/op new time/op delta
Template 335ms ± 5% 324ms ± 5% -3.35% (p=0.000 n=23+24)
Unicode 176ms ± 9% 165ms ± 6% -6.12% (p=0.000 n=23+24)
GoTypes 1.10s ± 4% 1.07s ± 2% -2.77% (p=0.000 n=24+24)
Compiler 5.31s ± 3% 5.15s ± 3% -2.95% (p=0.000 n=24+24)
MakeBash 41.6s ± 1% 41.7s ± 2% ~ (p=0.586 n=23+23)
name old alloc/op new alloc/op delta
Template 63.3MB ± 0% 62.4MB ± 0% -1.36% (p=0.000 n=25+23)
Unicode 42.4MB ± 0% 41.6MB ± 0% -1.99% (p=0.000 n=24+25)
GoTypes 220MB ± 0% 217MB ± 0% -1.11% (p=0.000 n=25+25)
Compiler 994MB ± 0% 973MB ± 0% -2.08% (p=0.000 n=24+25)
name old allocs/op new allocs/op delta
Template 681k ± 0% 574k ± 0% -15.71% (p=0.000 n=24+25)
Unicode 518k ± 0% 413k ± 0% -20.34% (p=0.000 n=25+24)
GoTypes 2.08M ± 0% 1.78M ± 0% -14.62% (p=0.000 n=25+25)
Compiler 9.26M ± 0% 7.64M ± 0% -17.48% (p=0.000 n=25+25)
name old text-bytes new text-bytes delta
HelloSize 578k ± 0% 578k ± 0% ~ (all samples are equal)
CmdGoSize 6.46M ± 0% 6.46M ± 0% ~ (all samples are equal)
name old data-bytes new data-bytes delta
HelloSize 128k ± 0% 128k ± 0% ~ (all samples are equal)
CmdGoSize 281k ± 0% 281k ± 0% ~ (all samples are equal)
name old exe-bytes new exe-bytes delta
HelloSize 921k ± 0% 921k ± 0% ~ (all samples are equal)
CmdGoSize 9.86M ± 0% 9.86M ± 0% ~ (all samples are equal)
Change-Id: I277d95bd56d51c166ef7f560647aeaa092f3f475
Reviewed-on: https://go-review.googlesource.com/20959
Reviewed-by: Dave Cheney <dave@cheney.net>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-03-20 08:03:31 -07:00
|
|
|
return n
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2017-03-28 07:12:57 -07:00
|
|
|
if n.mayBeShared() {
|
|
|
|
|
// Introduce OCONVNOP to hold init list.
|
2016-09-16 11:00:54 +10:00
|
|
|
n = nod(OCONVNOP, n, nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
n.Type = n.Left.Type
|
2017-04-25 18:02:43 -07:00
|
|
|
n.SetTypecheck(1)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-09-14 13:19:20 -07:00
|
|
|
n.Ninit.Prepend(init...)
|
2017-03-03 13:38:49 -08:00
|
|
|
n.SetHasCall(true)
|
cmd/compile: reduce use of **Node parameters
Escape analysis has a hard time with tree-like
structures (see #13493 and #14858).
This is unlikely to change.
As a result, when invoking a function that accepts
a **Node parameter, we usually allocate a *Node
on the heap. This happens a whole lot.
This CL changes functions from taking a **Node
to acting more like append: It both modifies
the input and returns a replacement for it.
Because of the cascading nature of escape analysis,
in order to get the benefits, I had to modify
almost all such functions. The remaining functions
are in racewalk and the backend. I would be happy
to update them as well in a separate CL.
This CL was created by manually updating the
function signatures and the directly impacted
bits of code. The callsites were then automatically
updated using a bespoke script:
https://gist.github.com/josharian/046b1be7aceae244de39
For ease of reviewing and future understanding,
this CL is also broken down into four CLs,
mailed separately, which show the manual
and the automated changes separately.
They are CLs 20990, 20991, 20992, and 20993.
Passes toolstash -cmp.
name old time/op new time/op delta
Template 335ms ± 5% 324ms ± 5% -3.35% (p=0.000 n=23+24)
Unicode 176ms ± 9% 165ms ± 6% -6.12% (p=0.000 n=23+24)
GoTypes 1.10s ± 4% 1.07s ± 2% -2.77% (p=0.000 n=24+24)
Compiler 5.31s ± 3% 5.15s ± 3% -2.95% (p=0.000 n=24+24)
MakeBash 41.6s ± 1% 41.7s ± 2% ~ (p=0.586 n=23+23)
name old alloc/op new alloc/op delta
Template 63.3MB ± 0% 62.4MB ± 0% -1.36% (p=0.000 n=25+23)
Unicode 42.4MB ± 0% 41.6MB ± 0% -1.99% (p=0.000 n=24+25)
GoTypes 220MB ± 0% 217MB ± 0% -1.11% (p=0.000 n=25+25)
Compiler 994MB ± 0% 973MB ± 0% -2.08% (p=0.000 n=24+25)
name old allocs/op new allocs/op delta
Template 681k ± 0% 574k ± 0% -15.71% (p=0.000 n=24+25)
Unicode 518k ± 0% 413k ± 0% -20.34% (p=0.000 n=25+24)
GoTypes 2.08M ± 0% 1.78M ± 0% -14.62% (p=0.000 n=25+25)
Compiler 9.26M ± 0% 7.64M ± 0% -17.48% (p=0.000 n=25+25)
name old text-bytes new text-bytes delta
HelloSize 578k ± 0% 578k ± 0% ~ (all samples are equal)
CmdGoSize 6.46M ± 0% 6.46M ± 0% ~ (all samples are equal)
name old data-bytes new data-bytes delta
HelloSize 128k ± 0% 128k ± 0% ~ (all samples are equal)
CmdGoSize 281k ± 0% 281k ± 0% ~ (all samples are equal)
name old exe-bytes new exe-bytes delta
HelloSize 921k ± 0% 921k ± 0% ~ (all samples are equal)
CmdGoSize 9.86M ± 0% 9.86M ± 0% ~ (all samples are equal)
Change-Id: I277d95bd56d51c166ef7f560647aeaa092f3f475
Reviewed-on: https://go-review.googlesource.com/20959
Reviewed-by: Dave Cheney <dave@cheney.net>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-03-20 08:03:31 -07:00
|
|
|
return n
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2018-01-11 17:37:16 -08:00
|
|
|
// The linker uses the magic symbol prefixes "go." and "type."
|
|
|
|
|
// Avoid potential confusion between import paths and symbols
|
|
|
|
|
// by rejecting these reserved imports for now. Also, people
|
|
|
|
|
// "can do weird things in GOPATH and we'd prefer they didn't
|
|
|
|
|
// do _that_ weird thing" (per rsc). See also #4257.
|
2015-02-13 14:40:36 -05:00
|
|
|
var reservedimports = []string{
|
|
|
|
|
"go",
|
|
|
|
|
"type",
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-16 14:48:38 -07:00
|
|
|
func isbadimport(path string, allowSpace bool) bool {
|
2015-03-02 16:03:26 -05:00
|
|
|
if strings.Contains(path, "\x00") {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("import path contains NUL")
|
2015-02-13 14:40:36 -05:00
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-08 22:22:44 +02:00
|
|
|
for _, ri := range reservedimports {
|
|
|
|
|
if path == ri {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("import path %q is reserved and cannot be used", path)
|
2015-02-13 14:40:36 -05:00
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-02 16:03:26 -05:00
|
|
|
for _, r := range path {
|
2015-02-13 14:40:36 -05:00
|
|
|
if r == utf8.RuneError {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("import path contains invalid UTF-8 sequence: %q", path)
|
2015-02-13 14:40:36 -05:00
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if r < 0x20 || r == 0x7f {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("import path contains control character: %q", path)
|
2015-02-13 14:40:36 -05:00
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if r == '\\' {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("import path contains backslash; use slash: %q", path)
|
2015-02-13 14:40:36 -05:00
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-16 14:48:38 -07:00
|
|
|
if !allowSpace && unicode.IsSpace(r) {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("import path contains space character: %q", path)
|
2015-02-13 14:40:36 -05:00
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if strings.ContainsRune("!\"#$%&'()*,:;<=>?[]^`{|}", r) {
|
2016-09-15 15:45:10 +10:00
|
|
|
yyerror("import path contains invalid character '%c': %q", r, path)
|
2015-02-13 14:40:36 -05:00
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-07 22:54:46 -08:00
|
|
|
func checknil(x *Node, init *Nodes) {
|
cmd/compile: fix liveness computation for heap-escaped parameters
The liveness computation of parameters generally was never
correct, but forcing all parameters to be live throughout the
function covered up that problem. The new SSA back end is
too clever: even though it currently keeps the parameter values live
throughout the function, it may find optimizations that mean
the current values are not written back to the original parameter
stack slots immediately or ever (for example if a parameter is set
to nil, SSA constant propagation may replace all later uses of the
parameter with a constant nil, eliminating the need to write the nil
value back to the stack slot), so the liveness code must now
track the actual operations on the stack slots, exposing these
problems.
One small problem in the handling of arguments is that nodarg
can return ONAME PPARAM nodes with adjusted offsets, so that
there are actually multiple *Node pointers for the same parameter
in the instruction stream. This might be possible to correct, but
not in this CL. For now, we fix this by using n.Orig instead of n
when considering PPARAM and PPARAMOUT nodes.
The major problem in the handling of arguments is general
confusion in the liveness code about the meaning of PPARAM|PHEAP
and PPARAMOUT|PHEAP nodes, especially as contrasted with PAUTO|PHEAP.
The difference between these two is that when a local variable "moves"
to the heap, it's really just allocated there to start with; in contrast,
when an argument moves to the heap, the actual data has to be copied
there from the stack at the beginning of the function, and when a
result "moves" to the heap the value in the heap has to be copied
back to the stack when the function returns
This general confusion is also present in the SSA back end.
The PHEAP bit worked decently when I first introduced it 7 years ago (!)
in 391425ae. The back end did nothing sophisticated, and in particular
there was no analysis at all: no escape analysis, no liveness analysis,
and certainly no SSA back end. But the complications caused in the
various downstream consumers suggest that this should be a detail
kept mainly in the front end.
This CL therefore eliminates both the PHEAP bit and even the idea of
"heap variables" from the back ends.
First, it replaces the PPARAM|PHEAP, PPARAMOUT|PHEAP, and PAUTO|PHEAP
variable classes with the single PAUTOHEAP, a pseudo-class indicating
a variable maintained on the heap and available by indirecting a
local variable kept on the stack (a plain PAUTO).
Second, walkexpr replaces all references to PAUTOHEAP variables
with indirections of the corresponding PAUTO variable.
The back ends and the liveness code now just see plain indirected
variables. This may actually produce better code, but the real goal
here is to eliminate these little-used and somewhat suspect code
paths in the back end analyses.
The OPARAM node type goes away too.
A followup CL will do the same to PPARAMREF. I'm not sure that
the back ends (SSA in particular) are handling those right either,
and with the framework established in this CL that change is trivial
and the result clearly more correct.
Fixes #15747.
Change-Id: I2770b1ce3cbc93981bfc7166be66a9da12013d74
Reviewed-on: https://go-review.googlesource.com/23393
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
2016-05-25 01:33:24 -04:00
|
|
|
x = walkexpr(x, nil) // caller has not done this yet
|
2016-03-30 14:45:47 -07:00
|
|
|
if x.Type.IsInterface() {
|
2016-09-16 11:00:54 +10:00
|
|
|
x = nod(OITAB, x, nil)
|
cmd/compile: reduce use of **Node parameters
Escape analysis has a hard time with tree-like
structures (see #13493 and #14858).
This is unlikely to change.
As a result, when invoking a function that accepts
a **Node parameter, we usually allocate a *Node
on the heap. This happens a whole lot.
This CL changes functions from taking a **Node
to acting more like append: It both modifies
the input and returns a replacement for it.
Because of the cascading nature of escape analysis,
in order to get the benefits, I had to modify
almost all such functions. The remaining functions
are in racewalk and the backend. I would be happy
to update them as well in a separate CL.
This CL was created by manually updating the
function signatures and the directly impacted
bits of code. The callsites were then automatically
updated using a bespoke script:
https://gist.github.com/josharian/046b1be7aceae244de39
For ease of reviewing and future understanding,
this CL is also broken down into four CLs,
mailed separately, which show the manual
and the automated changes separately.
They are CLs 20990, 20991, 20992, and 20993.
Passes toolstash -cmp.
name old time/op new time/op delta
Template 335ms ± 5% 324ms ± 5% -3.35% (p=0.000 n=23+24)
Unicode 176ms ± 9% 165ms ± 6% -6.12% (p=0.000 n=23+24)
GoTypes 1.10s ± 4% 1.07s ± 2% -2.77% (p=0.000 n=24+24)
Compiler 5.31s ± 3% 5.15s ± 3% -2.95% (p=0.000 n=24+24)
MakeBash 41.6s ± 1% 41.7s ± 2% ~ (p=0.586 n=23+23)
name old alloc/op new alloc/op delta
Template 63.3MB ± 0% 62.4MB ± 0% -1.36% (p=0.000 n=25+23)
Unicode 42.4MB ± 0% 41.6MB ± 0% -1.99% (p=0.000 n=24+25)
GoTypes 220MB ± 0% 217MB ± 0% -1.11% (p=0.000 n=25+25)
Compiler 994MB ± 0% 973MB ± 0% -2.08% (p=0.000 n=24+25)
name old allocs/op new allocs/op delta
Template 681k ± 0% 574k ± 0% -15.71% (p=0.000 n=24+25)
Unicode 518k ± 0% 413k ± 0% -20.34% (p=0.000 n=25+24)
GoTypes 2.08M ± 0% 1.78M ± 0% -14.62% (p=0.000 n=25+25)
Compiler 9.26M ± 0% 7.64M ± 0% -17.48% (p=0.000 n=25+25)
name old text-bytes new text-bytes delta
HelloSize 578k ± 0% 578k ± 0% ~ (all samples are equal)
CmdGoSize 6.46M ± 0% 6.46M ± 0% ~ (all samples are equal)
name old data-bytes new data-bytes delta
HelloSize 128k ± 0% 128k ± 0% ~ (all samples are equal)
CmdGoSize 281k ± 0% 281k ± 0% ~ (all samples are equal)
name old exe-bytes new exe-bytes delta
HelloSize 921k ± 0% 921k ± 0% ~ (all samples are equal)
CmdGoSize 9.86M ± 0% 9.86M ± 0% ~ (all samples are equal)
Change-Id: I277d95bd56d51c166ef7f560647aeaa092f3f475
Reviewed-on: https://go-review.googlesource.com/20959
Reviewed-by: Dave Cheney <dave@cheney.net>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-03-20 08:03:31 -07:00
|
|
|
x = typecheck(x, Erv)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-09-16 11:00:54 +10:00
|
|
|
n := nod(OCHECKNIL, x, nil)
|
2017-04-25 18:02:43 -07:00
|
|
|
n.SetTypecheck(1)
|
2016-03-07 22:54:46 -08:00
|
|
|
init.Append(n)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-10-22 09:51:12 +09:00
|
|
|
// Can this type be stored directly in an interface word?
|
|
|
|
|
// Yes, if the representation is a single pointer.
|
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 isdirectiface(t *types.Type) bool {
|
2017-11-28 13:42:04 -08:00
|
|
|
if t.Broke() {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
switch t.Etype {
|
2017-11-06 14:50:30 -08:00
|
|
|
case TPTR,
|
2015-02-13 14:40:36 -05:00
|
|
|
TCHAN,
|
|
|
|
|
TMAP,
|
|
|
|
|
TFUNC,
|
|
|
|
|
TUNSAFEPTR:
|
2015-02-17 22:13:49 -05:00
|
|
|
return true
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case TARRAY:
|
2016-03-10 05:22:14 -08:00
|
|
|
// Array of 1 direct iface type can be direct.
|
2016-03-31 14:46:04 -07:00
|
|
|
return t.NumElem() == 1 && isdirectiface(t.Elem())
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
case TSTRUCT:
|
2016-03-10 05:22:14 -08:00
|
|
|
// Struct with 1 field of direct iface type can be direct.
|
2016-03-17 13:26:08 -07:00
|
|
|
return t.NumFields() == 1 && isdirectiface(t.Field(0).Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-17 22:13:49 -05:00
|
|
|
return false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-03-17 13:56:29 -07:00
|
|
|
|
2016-06-06 08:29:52 -07:00
|
|
|
// itabType loads the _type field from a runtime.itab struct.
|
|
|
|
|
func itabType(itab *Node) *Node {
|
2016-09-15 15:45:10 +10:00
|
|
|
typ := nodSym(ODOTPTR, itab, nil)
|
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
|
|
|
typ.Type = types.NewPtr(types.Types[TUINT8])
|
2017-04-25 18:02:43 -07:00
|
|
|
typ.SetTypecheck(1)
|
2016-06-06 08:29:52 -07:00
|
|
|
typ.Xoffset = int64(Widthptr) // offset of _type in runtime.itab
|
2017-02-27 19:56:38 +02:00
|
|
|
typ.SetBounded(true) // guaranteed not to fault
|
2016-06-06 08:29:52 -07:00
|
|
|
return typ
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-06 12:38:19 -07:00
|
|
|
// ifaceData loads the data field from an interface.
|
|
|
|
|
// The concrete type must be known to have type t.
|
|
|
|
|
// It follows the pointer if !isdirectiface(t).
|
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 ifaceData(n *Node, t *types.Type) *Node {
|
2016-09-15 15:45:10 +10:00
|
|
|
ptr := nodSym(OIDATA, n, nil)
|
2016-06-06 12:38:19 -07:00
|
|
|
if isdirectiface(t) {
|
|
|
|
|
ptr.Type = t
|
2017-04-25 18:02:43 -07:00
|
|
|
ptr.SetTypecheck(1)
|
2016-06-06 12:38:19 -07:00
|
|
|
return ptr
|
|
|
|
|
}
|
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
|
|
|
ptr.Type = types.NewPtr(t)
|
2017-02-27 19:56:38 +02:00
|
|
|
ptr.SetBounded(true)
|
2017-04-25 18:02:43 -07:00
|
|
|
ptr.SetTypecheck(1)
|
2016-09-16 11:00:54 +10:00
|
|
|
ind := nod(OIND, ptr, nil)
|
2016-06-06 12:38:19 -07:00
|
|
|
ind.Type = t
|
2017-04-25 18:02:43 -07:00
|
|
|
ind.SetTypecheck(1)
|
2016-06-06 12:38:19 -07:00
|
|
|
return ind
|
|
|
|
|
}
|