2015-02-13 14:40:36 -05:00
|
|
|
// Copyright 2011 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 (
|
2015-05-28 13:49:20 -07:00
|
|
|
"cmd/compile/internal/ssa"
|
2015-02-13 14:40:36 -05:00
|
|
|
"cmd/internal/obj"
|
2015-02-27 16:05:30 +09:00
|
|
|
"crypto/md5"
|
2015-02-13 14:40:36 -05:00
|
|
|
"fmt"
|
2016-02-25 10:35:19 -08:00
|
|
|
"sort"
|
2015-02-13 14:40:36 -05:00
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// "Portable" code generation.
|
|
|
|
|
|
|
|
|
|
var makefuncdatasym_nsym int32
|
|
|
|
|
|
|
|
|
|
func makefuncdatasym(namefmt string, funcdatakind int64) *Sym {
|
|
|
|
|
var nod Node
|
|
|
|
|
|
2015-03-06 12:02:24 -08:00
|
|
|
sym := Lookupf(namefmt, makefuncdatasym_nsym)
|
2015-02-13 14:40:36 -05:00
|
|
|
makefuncdatasym_nsym++
|
2015-02-23 16:07:24 -05:00
|
|
|
pnod := newname(sym)
|
2015-02-13 14:40:36 -05:00
|
|
|
pnod.Class = PEXTERN
|
|
|
|
|
Nodconst(&nod, Types[TINT32], funcdatakind)
|
|
|
|
|
Thearch.Gins(obj.AFUNCDATA, &nod, pnod)
|
|
|
|
|
return sym
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// gvardef inserts a VARDEF for n into the instruction stream.
|
|
|
|
|
// VARDEF is an annotation for the liveness analysis, marking a place
|
|
|
|
|
// where a complete initialization (definition) of a variable begins.
|
|
|
|
|
// Since the liveness analysis can see initialization of single-word
|
|
|
|
|
// variables quite easy, gvardef is usually only called for multi-word
|
|
|
|
|
// or 'fat' variables, those satisfying isfat(n->type).
|
|
|
|
|
// However, gvardef is also called when a non-fat variable is initialized
|
|
|
|
|
// via a block move; the only time this happens is when you have
|
|
|
|
|
// return f()
|
|
|
|
|
// for a function with multiple return values exactly matching the return
|
|
|
|
|
// types of the current function.
|
|
|
|
|
//
|
|
|
|
|
// A 'VARDEF x' annotation in the instruction stream tells the liveness
|
|
|
|
|
// analysis to behave as though the variable x is being initialized at that
|
|
|
|
|
// point in the instruction stream. The VARDEF must appear before the
|
|
|
|
|
// actual (multi-instruction) initialization, and it must also appear after
|
|
|
|
|
// any uses of the previous value, if any. For example, if compiling:
|
|
|
|
|
//
|
|
|
|
|
// x = x[1:]
|
|
|
|
|
//
|
|
|
|
|
// it is important to generate code like:
|
|
|
|
|
//
|
|
|
|
|
// base, len, cap = pieces of x[1:]
|
|
|
|
|
// VARDEF x
|
|
|
|
|
// x = {base, len, cap}
|
|
|
|
|
//
|
|
|
|
|
// If instead the generated code looked like:
|
|
|
|
|
//
|
|
|
|
|
// VARDEF x
|
|
|
|
|
// base, len, cap = pieces of x[1:]
|
|
|
|
|
// x = {base, len, cap}
|
|
|
|
|
//
|
|
|
|
|
// then the liveness analysis would decide the previous value of x was
|
|
|
|
|
// unnecessary even though it is about to be used by the x[1:] computation.
|
|
|
|
|
// Similarly, if the generated code looked like:
|
|
|
|
|
//
|
|
|
|
|
// base, len, cap = pieces of x[1:]
|
|
|
|
|
// x = {base, len, cap}
|
|
|
|
|
// VARDEF x
|
|
|
|
|
//
|
|
|
|
|
// then the liveness analysis will not preserve the new value of x, because
|
|
|
|
|
// the VARDEF appears to have "overwritten" it.
|
|
|
|
|
//
|
|
|
|
|
// VARDEF is a bit of a kludge to work around the fact that the instruction
|
|
|
|
|
// stream is working on single-word values but the liveness analysis
|
|
|
|
|
// wants to work on individual variables, which might be multi-word
|
|
|
|
|
// aggregates. It might make sense at some point to look into letting
|
|
|
|
|
// the liveness analysis work on single-word values as well, although
|
|
|
|
|
// there are complications around interface values, slices, and strings,
|
|
|
|
|
// all of which cannot be treated as individual words.
|
|
|
|
|
//
|
|
|
|
|
// VARKILL is the opposite of VARDEF: it marks a value as no longer needed,
|
|
|
|
|
// even if its address has been taken. That is, a VARKILL annotation asserts
|
|
|
|
|
// that its argument is certainly dead, for use when the liveness analysis
|
|
|
|
|
// would not otherwise be able to deduce that fact.
|
|
|
|
|
|
2016-03-07 18:00:08 -08:00
|
|
|
func gvardefx(n *Node, as obj.As) {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n == nil {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("gvardef nil")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if n.Op != ONAME {
|
2016-03-07 08:23:55 -08:00
|
|
|
Yyerror("gvardef %v; %v", Oconv(n.Op, obj.FmtSharp), n)
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch n.Class {
|
2015-04-01 09:38:44 -07:00
|
|
|
case PAUTO, PPARAM, PPARAMOUT:
|
cmd/compile: recognize Syscall-like functions for liveness analysis
Consider this code:
func f(*int)
func g() {
p := new(int)
f(p)
}
where f is an assembly function.
In general liveness analysis assumes that during the call to f, p is dead
in this frame. If f has retained p, p will be found alive in f's frame and keep
the new(int) from being garbage collected. This is all correct and works.
We use the Go func declaration for f to give the assembly function
liveness information (the arguments are assumed live for the entire call).
Now consider this code:
func h1() {
p := new(int)
syscall.Syscall(1, 2, 3, uintptr(unsafe.Pointer(p)))
}
Here syscall.Syscall is taking the place of f, but because its arguments
are uintptr, the liveness analysis and the garbage collector ignore them.
Since p is no longer live in h once the call starts, if the garbage collector
scans the stack while the system call is blocked, it will find no reference
to the new(int) and reclaim it. If the kernel is going to write to *p once
the call finishes, reclaiming the memory is a mistake.
We can't change the arguments or the liveness information for
syscall.Syscall itself, both for compatibility and because sometimes the
arguments really are integers, and the garbage collector will get quite upset
if it finds an integer where it expects a pointer. The problem is that
these arguments are fundamentally untyped.
The solution we have taken in the syscall package's wrappers in past
releases is to insert a call to a dummy function named "use", to make
it look like the argument is live during the call to syscall.Syscall:
func h2() {
p := new(int)
syscall.Syscall(1, 2, 3, uintptr(unsafe.Pointer(p)))
use(unsafe.Pointer(p))
}
Keeping p alive during the call means that if the garbage collector
scans the stack during the system call now, it will find the reference to p.
Unfortunately, this approach is not available to users outside syscall,
because 'use' is unexported, and people also have to realize they need
to use it and do so. There is much existing code using syscall.Syscall
without a 'use'-like function. That code will fail very occasionally in
mysterious ways (see #13372).
This CL fixes all that existing code by making the compiler do the right
thing automatically, without any code modifications. That is, it takes h1
above, which is incorrect code today, and makes it correct code.
Specifically, if the compiler sees a foreign func definition (one
without a body) that has uintptr arguments, it marks those arguments
as "unsafe uintptrs". If it later sees the function being called
with uintptr(unsafe.Pointer(x)) as an argument, it arranges to mark x
as having escaped, and it makes sure to hold x in a live temporary
variable until the call returns, so that the garbage collector cannot
reclaim whatever heap memory x points to.
For now I am leaving the explicit calls to use in package syscall,
but they can be removed early in a future cycle (likely Go 1.7).
The rule has no effect on escape analysis, only on liveness analysis.
Fixes #13372.
Change-Id: I2addb83f70d08db08c64d394f9d06ff0a063c500
Reviewed-on: https://go-review.googlesource.com/18584
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-01-13 00:46:28 -05:00
|
|
|
if as == obj.AVARLIVE {
|
|
|
|
|
Thearch.Gins(as, n, nil)
|
|
|
|
|
} else {
|
|
|
|
|
Thearch.Gins(as, nil, n)
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Gvardef(n *Node) {
|
|
|
|
|
gvardefx(n, obj.AVARDEF)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func gvarkill(n *Node) {
|
|
|
|
|
gvardefx(n, obj.AVARKILL)
|
|
|
|
|
}
|
|
|
|
|
|
cmd/compile: recognize Syscall-like functions for liveness analysis
Consider this code:
func f(*int)
func g() {
p := new(int)
f(p)
}
where f is an assembly function.
In general liveness analysis assumes that during the call to f, p is dead
in this frame. If f has retained p, p will be found alive in f's frame and keep
the new(int) from being garbage collected. This is all correct and works.
We use the Go func declaration for f to give the assembly function
liveness information (the arguments are assumed live for the entire call).
Now consider this code:
func h1() {
p := new(int)
syscall.Syscall(1, 2, 3, uintptr(unsafe.Pointer(p)))
}
Here syscall.Syscall is taking the place of f, but because its arguments
are uintptr, the liveness analysis and the garbage collector ignore them.
Since p is no longer live in h once the call starts, if the garbage collector
scans the stack while the system call is blocked, it will find no reference
to the new(int) and reclaim it. If the kernel is going to write to *p once
the call finishes, reclaiming the memory is a mistake.
We can't change the arguments or the liveness information for
syscall.Syscall itself, both for compatibility and because sometimes the
arguments really are integers, and the garbage collector will get quite upset
if it finds an integer where it expects a pointer. The problem is that
these arguments are fundamentally untyped.
The solution we have taken in the syscall package's wrappers in past
releases is to insert a call to a dummy function named "use", to make
it look like the argument is live during the call to syscall.Syscall:
func h2() {
p := new(int)
syscall.Syscall(1, 2, 3, uintptr(unsafe.Pointer(p)))
use(unsafe.Pointer(p))
}
Keeping p alive during the call means that if the garbage collector
scans the stack during the system call now, it will find the reference to p.
Unfortunately, this approach is not available to users outside syscall,
because 'use' is unexported, and people also have to realize they need
to use it and do so. There is much existing code using syscall.Syscall
without a 'use'-like function. That code will fail very occasionally in
mysterious ways (see #13372).
This CL fixes all that existing code by making the compiler do the right
thing automatically, without any code modifications. That is, it takes h1
above, which is incorrect code today, and makes it correct code.
Specifically, if the compiler sees a foreign func definition (one
without a body) that has uintptr arguments, it marks those arguments
as "unsafe uintptrs". If it later sees the function being called
with uintptr(unsafe.Pointer(x)) as an argument, it arranges to mark x
as having escaped, and it makes sure to hold x in a live temporary
variable until the call returns, so that the garbage collector cannot
reclaim whatever heap memory x points to.
For now I am leaving the explicit calls to use in package syscall,
but they can be removed early in a future cycle (likely Go 1.7).
The rule has no effect on escape analysis, only on liveness analysis.
Fixes #13372.
Change-Id: I2addb83f70d08db08c64d394f9d06ff0a063c500
Reviewed-on: https://go-review.googlesource.com/18584
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-01-13 00:46:28 -05:00
|
|
|
func gvarlive(n *Node) {
|
|
|
|
|
gvardefx(n, obj.AVARLIVE)
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
func removevardef(firstp *obj.Prog) {
|
2015-02-23 16:07:24 -05:00
|
|
|
for p := firstp; p != nil; p = p.Link {
|
cmd/compile: recognize Syscall-like functions for liveness analysis
Consider this code:
func f(*int)
func g() {
p := new(int)
f(p)
}
where f is an assembly function.
In general liveness analysis assumes that during the call to f, p is dead
in this frame. If f has retained p, p will be found alive in f's frame and keep
the new(int) from being garbage collected. This is all correct and works.
We use the Go func declaration for f to give the assembly function
liveness information (the arguments are assumed live for the entire call).
Now consider this code:
func h1() {
p := new(int)
syscall.Syscall(1, 2, 3, uintptr(unsafe.Pointer(p)))
}
Here syscall.Syscall is taking the place of f, but because its arguments
are uintptr, the liveness analysis and the garbage collector ignore them.
Since p is no longer live in h once the call starts, if the garbage collector
scans the stack while the system call is blocked, it will find no reference
to the new(int) and reclaim it. If the kernel is going to write to *p once
the call finishes, reclaiming the memory is a mistake.
We can't change the arguments or the liveness information for
syscall.Syscall itself, both for compatibility and because sometimes the
arguments really are integers, and the garbage collector will get quite upset
if it finds an integer where it expects a pointer. The problem is that
these arguments are fundamentally untyped.
The solution we have taken in the syscall package's wrappers in past
releases is to insert a call to a dummy function named "use", to make
it look like the argument is live during the call to syscall.Syscall:
func h2() {
p := new(int)
syscall.Syscall(1, 2, 3, uintptr(unsafe.Pointer(p)))
use(unsafe.Pointer(p))
}
Keeping p alive during the call means that if the garbage collector
scans the stack during the system call now, it will find the reference to p.
Unfortunately, this approach is not available to users outside syscall,
because 'use' is unexported, and people also have to realize they need
to use it and do so. There is much existing code using syscall.Syscall
without a 'use'-like function. That code will fail very occasionally in
mysterious ways (see #13372).
This CL fixes all that existing code by making the compiler do the right
thing automatically, without any code modifications. That is, it takes h1
above, which is incorrect code today, and makes it correct code.
Specifically, if the compiler sees a foreign func definition (one
without a body) that has uintptr arguments, it marks those arguments
as "unsafe uintptrs". If it later sees the function being called
with uintptr(unsafe.Pointer(x)) as an argument, it arranges to mark x
as having escaped, and it makes sure to hold x in a live temporary
variable until the call returns, so that the garbage collector cannot
reclaim whatever heap memory x points to.
For now I am leaving the explicit calls to use in package syscall,
but they can be removed early in a future cycle (likely Go 1.7).
The rule has no effect on escape analysis, only on liveness analysis.
Fixes #13372.
Change-Id: I2addb83f70d08db08c64d394f9d06ff0a063c500
Reviewed-on: https://go-review.googlesource.com/18584
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-01-13 00:46:28 -05:00
|
|
|
for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL || p.Link.As == obj.AVARLIVE) {
|
2015-02-13 14:40:36 -05:00
|
|
|
p.Link = p.Link.Link
|
|
|
|
|
}
|
|
|
|
|
if p.To.Type == obj.TYPE_BRANCH {
|
cmd/compile: recognize Syscall-like functions for liveness analysis
Consider this code:
func f(*int)
func g() {
p := new(int)
f(p)
}
where f is an assembly function.
In general liveness analysis assumes that during the call to f, p is dead
in this frame. If f has retained p, p will be found alive in f's frame and keep
the new(int) from being garbage collected. This is all correct and works.
We use the Go func declaration for f to give the assembly function
liveness information (the arguments are assumed live for the entire call).
Now consider this code:
func h1() {
p := new(int)
syscall.Syscall(1, 2, 3, uintptr(unsafe.Pointer(p)))
}
Here syscall.Syscall is taking the place of f, but because its arguments
are uintptr, the liveness analysis and the garbage collector ignore them.
Since p is no longer live in h once the call starts, if the garbage collector
scans the stack while the system call is blocked, it will find no reference
to the new(int) and reclaim it. If the kernel is going to write to *p once
the call finishes, reclaiming the memory is a mistake.
We can't change the arguments or the liveness information for
syscall.Syscall itself, both for compatibility and because sometimes the
arguments really are integers, and the garbage collector will get quite upset
if it finds an integer where it expects a pointer. The problem is that
these arguments are fundamentally untyped.
The solution we have taken in the syscall package's wrappers in past
releases is to insert a call to a dummy function named "use", to make
it look like the argument is live during the call to syscall.Syscall:
func h2() {
p := new(int)
syscall.Syscall(1, 2, 3, uintptr(unsafe.Pointer(p)))
use(unsafe.Pointer(p))
}
Keeping p alive during the call means that if the garbage collector
scans the stack during the system call now, it will find the reference to p.
Unfortunately, this approach is not available to users outside syscall,
because 'use' is unexported, and people also have to realize they need
to use it and do so. There is much existing code using syscall.Syscall
without a 'use'-like function. That code will fail very occasionally in
mysterious ways (see #13372).
This CL fixes all that existing code by making the compiler do the right
thing automatically, without any code modifications. That is, it takes h1
above, which is incorrect code today, and makes it correct code.
Specifically, if the compiler sees a foreign func definition (one
without a body) that has uintptr arguments, it marks those arguments
as "unsafe uintptrs". If it later sees the function being called
with uintptr(unsafe.Pointer(x)) as an argument, it arranges to mark x
as having escaped, and it makes sure to hold x in a live temporary
variable until the call returns, so that the garbage collector cannot
reclaim whatever heap memory x points to.
For now I am leaving the explicit calls to use in package syscall,
but they can be removed early in a future cycle (likely Go 1.7).
The rule has no effect on escape analysis, only on liveness analysis.
Fixes #13372.
Change-Id: I2addb83f70d08db08c64d394f9d06ff0a063c500
Reviewed-on: https://go-review.googlesource.com/18584
Reviewed-by: Ian Lance Taylor <iant@golang.org>
2016-01-13 00:46:28 -05:00
|
|
|
for p.To.Val.(*obj.Prog) != nil && (p.To.Val.(*obj.Prog).As == obj.AVARDEF || p.To.Val.(*obj.Prog).As == obj.AVARKILL || p.To.Val.(*obj.Prog).As == obj.AVARLIVE) {
|
2015-03-16 15:54:44 -04:00
|
|
|
p.To.Val = p.To.Val.(*obj.Prog).Link
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func gcsymdup(s *Sym) {
|
2015-02-23 16:07:24 -05:00
|
|
|
ls := Linksym(s)
|
2015-02-13 14:40:36 -05:00
|
|
|
if len(ls.R) > 0 {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("cannot rosymdup %s with relocations", ls.Name)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
2015-02-27 16:05:30 +09:00
|
|
|
ls.Name = fmt.Sprintf("gclocals·%x", md5.Sum(ls.P))
|
2015-02-13 14:40:36 -05:00
|
|
|
ls.Dupok = 1
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func emitptrargsmap() {
|
2015-11-04 15:54:41 -05:00
|
|
|
if Curfn.Func.Nname.Sym.Name == "_" {
|
|
|
|
|
return
|
|
|
|
|
}
|
2015-05-27 10:42:55 -04:00
|
|
|
sym := Lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Func.Nname.Sym.Name))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
nptr := int(Curfn.Type.Argwid / int64(Widthptr))
|
|
|
|
|
bv := bvalloc(int32(nptr) * 2)
|
|
|
|
|
nbitmap := 1
|
2015-02-13 14:40:36 -05:00
|
|
|
if Curfn.Type.Outtuple > 0 {
|
|
|
|
|
nbitmap = 2
|
|
|
|
|
}
|
2015-02-23 16:07:24 -05:00
|
|
|
off := duint32(sym, 0, uint32(nbitmap))
|
2015-02-13 14:40:36 -05:00
|
|
|
off = duint32(sym, off, uint32(bv.n))
|
2015-02-23 16:07:24 -05:00
|
|
|
var xoffset int64
|
2015-02-13 14:40:36 -05:00
|
|
|
if Curfn.Type.Thistuple > 0 {
|
|
|
|
|
xoffset = 0
|
cmd/internal/gc, runtime: use 1-bit bitmap for stack frames, data, bss
The bitmaps were 2 bits per pointer because we needed to distinguish
scalar, pointer, multiword, and we used the leftover value to distinguish
uninitialized from scalar, even though the garbage collector (GC) didn't care.
Now that there are no multiword structures from the GC's point of view,
cut the bitmaps down to 1 bit per pointer, recording just live pointer vs not.
The GC assumes the same layout for stack frames and for the maps
describing the global data and bss sections, so change them all in one CL.
The code still refers to 4-bit heap bitmaps and 2-bit "type bitmaps", since
the 2-bit representation lives (at least for now) in some of the reflect data.
Because these stack frame bitmaps are stored directly in the rodata in
the binary, this CL reduces the size of the 6g binary by about 1.1%.
Performance change is basically a wash, but using less memory,
and smaller binaries, and enables other bitmap reductions.
name old mean new mean delta
BenchmarkBinaryTree17 13.2s × (0.97,1.03) 13.0s × (0.99,1.01) -0.93% (p=0.005)
BenchmarkBinaryTree17-2 9.69s × (0.96,1.05) 9.51s × (0.96,1.03) -1.86% (p=0.001)
BenchmarkBinaryTree17-4 10.1s × (0.97,1.05) 10.0s × (0.96,1.05) ~ (p=0.141)
BenchmarkFannkuch11 4.35s × (0.99,1.01) 4.43s × (0.98,1.04) +1.75% (p=0.001)
BenchmarkFannkuch11-2 4.31s × (0.99,1.03) 4.32s × (1.00,1.00) ~ (p=0.095)
BenchmarkFannkuch11-4 4.32s × (0.99,1.02) 4.38s × (0.98,1.04) +1.38% (p=0.008)
BenchmarkFmtFprintfEmpty 83.5ns × (0.97,1.10) 87.3ns × (0.92,1.11) +4.55% (p=0.014)
BenchmarkFmtFprintfEmpty-2 81.8ns × (0.98,1.04) 82.5ns × (0.97,1.08) ~ (p=0.364)
BenchmarkFmtFprintfEmpty-4 80.9ns × (0.99,1.01) 82.6ns × (0.97,1.08) +2.12% (p=0.010)
BenchmarkFmtFprintfString 320ns × (0.95,1.04) 322ns × (0.97,1.05) ~ (p=0.368)
BenchmarkFmtFprintfString-2 303ns × (0.97,1.04) 304ns × (0.97,1.04) ~ (p=0.484)
BenchmarkFmtFprintfString-4 305ns × (0.97,1.05) 306ns × (0.98,1.05) ~ (p=0.543)
BenchmarkFmtFprintfInt 311ns × (0.98,1.03) 319ns × (0.97,1.03) +2.63% (p=0.000)
BenchmarkFmtFprintfInt-2 297ns × (0.98,1.04) 301ns × (0.97,1.04) +1.19% (p=0.023)
BenchmarkFmtFprintfInt-4 302ns × (0.98,1.02) 304ns × (0.97,1.03) ~ (p=0.126)
BenchmarkFmtFprintfIntInt 554ns × (0.96,1.05) 554ns × (0.97,1.03) ~ (p=0.975)
BenchmarkFmtFprintfIntInt-2 520ns × (0.98,1.03) 517ns × (0.98,1.02) ~ (p=0.153)
BenchmarkFmtFprintfIntInt-4 524ns × (0.98,1.02) 525ns × (0.98,1.03) ~ (p=0.597)
BenchmarkFmtFprintfPrefixedInt 433ns × (0.97,1.06) 434ns × (0.97,1.06) ~ (p=0.804)
BenchmarkFmtFprintfPrefixedInt-2 413ns × (0.98,1.04) 413ns × (0.98,1.03) ~ (p=0.881)
BenchmarkFmtFprintfPrefixedInt-4 420ns × (0.97,1.03) 421ns × (0.97,1.03) ~ (p=0.561)
BenchmarkFmtFprintfFloat 620ns × (0.99,1.03) 636ns × (0.97,1.03) +2.57% (p=0.000)
BenchmarkFmtFprintfFloat-2 601ns × (0.98,1.02) 617ns × (0.98,1.03) +2.58% (p=0.000)
BenchmarkFmtFprintfFloat-4 613ns × (0.98,1.03) 626ns × (0.98,1.02) +2.15% (p=0.000)
BenchmarkFmtManyArgs 2.19µs × (0.96,1.04) 2.23µs × (0.97,1.02) +1.65% (p=0.000)
BenchmarkFmtManyArgs-2 2.08µs × (0.98,1.03) 2.10µs × (0.99,1.02) +0.79% (p=0.019)
BenchmarkFmtManyArgs-4 2.10µs × (0.98,1.02) 2.13µs × (0.98,1.02) +1.72% (p=0.000)
BenchmarkGobDecode 21.3ms × (0.97,1.05) 21.1ms × (0.97,1.04) -1.36% (p=0.025)
BenchmarkGobDecode-2 20.0ms × (0.97,1.03) 19.2ms × (0.97,1.03) -4.00% (p=0.000)
BenchmarkGobDecode-4 19.5ms × (0.99,1.02) 19.0ms × (0.99,1.01) -2.39% (p=0.000)
BenchmarkGobEncode 18.3ms × (0.95,1.07) 18.1ms × (0.96,1.08) ~ (p=0.305)
BenchmarkGobEncode-2 16.8ms × (0.97,1.02) 16.4ms × (0.98,1.02) -2.79% (p=0.000)
BenchmarkGobEncode-4 15.4ms × (0.98,1.02) 15.4ms × (0.98,1.02) ~ (p=0.465)
BenchmarkGzip 650ms × (0.98,1.03) 655ms × (0.97,1.04) ~ (p=0.075)
BenchmarkGzip-2 652ms × (0.98,1.03) 655ms × (0.98,1.02) ~ (p=0.337)
BenchmarkGzip-4 656ms × (0.98,1.04) 653ms × (0.98,1.03) ~ (p=0.291)
BenchmarkGunzip 143ms × (1.00,1.01) 143ms × (1.00,1.01) ~ (p=0.507)
BenchmarkGunzip-2 143ms × (1.00,1.01) 143ms × (1.00,1.01) ~ (p=0.313)
BenchmarkGunzip-4 143ms × (1.00,1.01) 143ms × (1.00,1.01) ~ (p=0.312)
BenchmarkHTTPClientServer 110µs × (0.98,1.03) 109µs × (0.99,1.02) -1.40% (p=0.000)
BenchmarkHTTPClientServer-2 154µs × (0.90,1.08) 149µs × (0.90,1.08) -3.43% (p=0.007)
BenchmarkHTTPClientServer-4 138µs × (0.97,1.04) 138µs × (0.96,1.04) ~ (p=0.670)
BenchmarkJSONEncode 40.2ms × (0.98,1.02) 40.2ms × (0.98,1.05) ~ (p=0.828)
BenchmarkJSONEncode-2 35.1ms × (0.99,1.02) 35.2ms × (0.98,1.03) ~ (p=0.392)
BenchmarkJSONEncode-4 35.3ms × (0.98,1.03) 35.3ms × (0.98,1.02) ~ (p=0.813)
BenchmarkJSONDecode 119ms × (0.97,1.02) 117ms × (0.98,1.02) -1.80% (p=0.000)
BenchmarkJSONDecode-2 115ms × (0.99,1.02) 114ms × (0.98,1.02) -1.18% (p=0.000)
BenchmarkJSONDecode-4 116ms × (0.98,1.02) 114ms × (0.98,1.02) -1.43% (p=0.000)
BenchmarkMandelbrot200 6.03ms × (1.00,1.01) 6.03ms × (1.00,1.01) ~ (p=0.985)
BenchmarkMandelbrot200-2 6.03ms × (1.00,1.01) 6.02ms × (1.00,1.01) ~ (p=0.320)
BenchmarkMandelbrot200-4 6.03ms × (1.00,1.01) 6.03ms × (1.00,1.01) ~ (p=0.799)
BenchmarkGoParse 8.63ms × (0.89,1.10) 8.58ms × (0.93,1.09) ~ (p=0.667)
BenchmarkGoParse-2 8.20ms × (0.97,1.04) 8.37ms × (0.97,1.04) +1.96% (p=0.001)
BenchmarkGoParse-4 8.00ms × (0.98,1.02) 8.14ms × (0.99,1.02) +1.75% (p=0.000)
BenchmarkRegexpMatchEasy0_32 162ns × (1.00,1.01) 164ns × (0.98,1.04) +1.35% (p=0.011)
BenchmarkRegexpMatchEasy0_32-2 161ns × (1.00,1.01) 161ns × (1.00,1.00) ~ (p=0.185)
BenchmarkRegexpMatchEasy0_32-4 161ns × (1.00,1.00) 161ns × (1.00,1.00) -0.19% (p=0.001)
BenchmarkRegexpMatchEasy0_1K 540ns × (0.99,1.02) 566ns × (0.98,1.04) +4.98% (p=0.000)
BenchmarkRegexpMatchEasy0_1K-2 540ns × (0.99,1.01) 557ns × (0.99,1.01) +3.21% (p=0.000)
BenchmarkRegexpMatchEasy0_1K-4 541ns × (0.99,1.01) 559ns × (0.99,1.01) +3.26% (p=0.000)
BenchmarkRegexpMatchEasy1_32 139ns × (0.98,1.04) 139ns × (0.99,1.03) ~ (p=0.979)
BenchmarkRegexpMatchEasy1_32-2 139ns × (0.99,1.04) 139ns × (0.99,1.02) ~ (p=0.777)
BenchmarkRegexpMatchEasy1_32-4 139ns × (0.98,1.04) 139ns × (0.99,1.04) ~ (p=0.771)
BenchmarkRegexpMatchEasy1_1K 890ns × (0.99,1.03) 885ns × (1.00,1.01) -0.50% (p=0.004)
BenchmarkRegexpMatchEasy1_1K-2 888ns × (0.99,1.01) 885ns × (0.99,1.01) -0.37% (p=0.004)
BenchmarkRegexpMatchEasy1_1K-4 890ns × (0.99,1.02) 884ns × (1.00,1.00) -0.70% (p=0.000)
BenchmarkRegexpMatchMedium_32 252ns × (0.99,1.01) 251ns × (0.99,1.01) ~ (p=0.081)
BenchmarkRegexpMatchMedium_32-2 254ns × (0.99,1.04) 252ns × (0.99,1.01) -0.78% (p=0.027)
BenchmarkRegexpMatchMedium_32-4 253ns × (0.99,1.04) 252ns × (0.99,1.01) -0.70% (p=0.022)
BenchmarkRegexpMatchMedium_1K 72.9µs × (0.99,1.01) 72.7µs × (1.00,1.00) ~ (p=0.064)
BenchmarkRegexpMatchMedium_1K-2 74.1µs × (0.98,1.05) 72.9µs × (1.00,1.01) -1.61% (p=0.001)
BenchmarkRegexpMatchMedium_1K-4 73.6µs × (0.99,1.05) 72.8µs × (1.00,1.00) -1.13% (p=0.007)
BenchmarkRegexpMatchHard_32 3.88µs × (0.99,1.03) 3.92µs × (0.98,1.05) ~ (p=0.143)
BenchmarkRegexpMatchHard_32-2 3.89µs × (0.99,1.03) 3.93µs × (0.98,1.09) ~ (p=0.278)
BenchmarkRegexpMatchHard_32-4 3.90µs × (0.99,1.05) 3.93µs × (0.98,1.05) ~ (p=0.252)
BenchmarkRegexpMatchHard_1K 118µs × (0.99,1.01) 117µs × (0.99,1.02) -0.54% (p=0.003)
BenchmarkRegexpMatchHard_1K-2 118µs × (0.99,1.01) 118µs × (0.99,1.03) ~ (p=0.581)
BenchmarkRegexpMatchHard_1K-4 118µs × (0.99,1.02) 117µs × (0.99,1.01) -0.54% (p=0.002)
BenchmarkRevcomp 991ms × (0.95,1.10) 989ms × (0.94,1.08) ~ (p=0.879)
BenchmarkRevcomp-2 978ms × (0.95,1.11) 962ms × (0.96,1.08) ~ (p=0.257)
BenchmarkRevcomp-4 979ms × (0.96,1.07) 974ms × (0.96,1.11) ~ (p=0.678)
BenchmarkTemplate 141ms × (0.99,1.02) 145ms × (0.99,1.02) +2.75% (p=0.000)
BenchmarkTemplate-2 135ms × (0.98,1.02) 138ms × (0.99,1.02) +2.34% (p=0.000)
BenchmarkTemplate-4 136ms × (0.98,1.02) 140ms × (0.99,1.02) +2.71% (p=0.000)
BenchmarkTimeParse 640ns × (0.99,1.01) 622ns × (0.99,1.01) -2.88% (p=0.000)
BenchmarkTimeParse-2 640ns × (0.99,1.01) 622ns × (1.00,1.00) -2.81% (p=0.000)
BenchmarkTimeParse-4 640ns × (1.00,1.01) 622ns × (0.99,1.01) -2.82% (p=0.000)
BenchmarkTimeFormat 730ns × (0.98,1.02) 731ns × (0.98,1.03) ~ (p=0.767)
BenchmarkTimeFormat-2 709ns × (0.99,1.02) 707ns × (0.99,1.02) ~ (p=0.347)
BenchmarkTimeFormat-4 717ns × (0.98,1.01) 718ns × (0.98,1.02) ~ (p=0.793)
Change-Id: Ie779c47e912bf80eb918bafa13638bd8dfd6c2d9
Reviewed-on: https://go-review.googlesource.com/9406
Reviewed-by: Rick Hudson <rlh@golang.org>
2015-04-27 22:45:57 -04:00
|
|
|
onebitwalktype1(getthisx(Curfn.Type), &xoffset, bv)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if Curfn.Type.Intuple > 0 {
|
|
|
|
|
xoffset = 0
|
cmd/internal/gc, runtime: use 1-bit bitmap for stack frames, data, bss
The bitmaps were 2 bits per pointer because we needed to distinguish
scalar, pointer, multiword, and we used the leftover value to distinguish
uninitialized from scalar, even though the garbage collector (GC) didn't care.
Now that there are no multiword structures from the GC's point of view,
cut the bitmaps down to 1 bit per pointer, recording just live pointer vs not.
The GC assumes the same layout for stack frames and for the maps
describing the global data and bss sections, so change them all in one CL.
The code still refers to 4-bit heap bitmaps and 2-bit "type bitmaps", since
the 2-bit representation lives (at least for now) in some of the reflect data.
Because these stack frame bitmaps are stored directly in the rodata in
the binary, this CL reduces the size of the 6g binary by about 1.1%.
Performance change is basically a wash, but using less memory,
and smaller binaries, and enables other bitmap reductions.
name old mean new mean delta
BenchmarkBinaryTree17 13.2s × (0.97,1.03) 13.0s × (0.99,1.01) -0.93% (p=0.005)
BenchmarkBinaryTree17-2 9.69s × (0.96,1.05) 9.51s × (0.96,1.03) -1.86% (p=0.001)
BenchmarkBinaryTree17-4 10.1s × (0.97,1.05) 10.0s × (0.96,1.05) ~ (p=0.141)
BenchmarkFannkuch11 4.35s × (0.99,1.01) 4.43s × (0.98,1.04) +1.75% (p=0.001)
BenchmarkFannkuch11-2 4.31s × (0.99,1.03) 4.32s × (1.00,1.00) ~ (p=0.095)
BenchmarkFannkuch11-4 4.32s × (0.99,1.02) 4.38s × (0.98,1.04) +1.38% (p=0.008)
BenchmarkFmtFprintfEmpty 83.5ns × (0.97,1.10) 87.3ns × (0.92,1.11) +4.55% (p=0.014)
BenchmarkFmtFprintfEmpty-2 81.8ns × (0.98,1.04) 82.5ns × (0.97,1.08) ~ (p=0.364)
BenchmarkFmtFprintfEmpty-4 80.9ns × (0.99,1.01) 82.6ns × (0.97,1.08) +2.12% (p=0.010)
BenchmarkFmtFprintfString 320ns × (0.95,1.04) 322ns × (0.97,1.05) ~ (p=0.368)
BenchmarkFmtFprintfString-2 303ns × (0.97,1.04) 304ns × (0.97,1.04) ~ (p=0.484)
BenchmarkFmtFprintfString-4 305ns × (0.97,1.05) 306ns × (0.98,1.05) ~ (p=0.543)
BenchmarkFmtFprintfInt 311ns × (0.98,1.03) 319ns × (0.97,1.03) +2.63% (p=0.000)
BenchmarkFmtFprintfInt-2 297ns × (0.98,1.04) 301ns × (0.97,1.04) +1.19% (p=0.023)
BenchmarkFmtFprintfInt-4 302ns × (0.98,1.02) 304ns × (0.97,1.03) ~ (p=0.126)
BenchmarkFmtFprintfIntInt 554ns × (0.96,1.05) 554ns × (0.97,1.03) ~ (p=0.975)
BenchmarkFmtFprintfIntInt-2 520ns × (0.98,1.03) 517ns × (0.98,1.02) ~ (p=0.153)
BenchmarkFmtFprintfIntInt-4 524ns × (0.98,1.02) 525ns × (0.98,1.03) ~ (p=0.597)
BenchmarkFmtFprintfPrefixedInt 433ns × (0.97,1.06) 434ns × (0.97,1.06) ~ (p=0.804)
BenchmarkFmtFprintfPrefixedInt-2 413ns × (0.98,1.04) 413ns × (0.98,1.03) ~ (p=0.881)
BenchmarkFmtFprintfPrefixedInt-4 420ns × (0.97,1.03) 421ns × (0.97,1.03) ~ (p=0.561)
BenchmarkFmtFprintfFloat 620ns × (0.99,1.03) 636ns × (0.97,1.03) +2.57% (p=0.000)
BenchmarkFmtFprintfFloat-2 601ns × (0.98,1.02) 617ns × (0.98,1.03) +2.58% (p=0.000)
BenchmarkFmtFprintfFloat-4 613ns × (0.98,1.03) 626ns × (0.98,1.02) +2.15% (p=0.000)
BenchmarkFmtManyArgs 2.19µs × (0.96,1.04) 2.23µs × (0.97,1.02) +1.65% (p=0.000)
BenchmarkFmtManyArgs-2 2.08µs × (0.98,1.03) 2.10µs × (0.99,1.02) +0.79% (p=0.019)
BenchmarkFmtManyArgs-4 2.10µs × (0.98,1.02) 2.13µs × (0.98,1.02) +1.72% (p=0.000)
BenchmarkGobDecode 21.3ms × (0.97,1.05) 21.1ms × (0.97,1.04) -1.36% (p=0.025)
BenchmarkGobDecode-2 20.0ms × (0.97,1.03) 19.2ms × (0.97,1.03) -4.00% (p=0.000)
BenchmarkGobDecode-4 19.5ms × (0.99,1.02) 19.0ms × (0.99,1.01) -2.39% (p=0.000)
BenchmarkGobEncode 18.3ms × (0.95,1.07) 18.1ms × (0.96,1.08) ~ (p=0.305)
BenchmarkGobEncode-2 16.8ms × (0.97,1.02) 16.4ms × (0.98,1.02) -2.79% (p=0.000)
BenchmarkGobEncode-4 15.4ms × (0.98,1.02) 15.4ms × (0.98,1.02) ~ (p=0.465)
BenchmarkGzip 650ms × (0.98,1.03) 655ms × (0.97,1.04) ~ (p=0.075)
BenchmarkGzip-2 652ms × (0.98,1.03) 655ms × (0.98,1.02) ~ (p=0.337)
BenchmarkGzip-4 656ms × (0.98,1.04) 653ms × (0.98,1.03) ~ (p=0.291)
BenchmarkGunzip 143ms × (1.00,1.01) 143ms × (1.00,1.01) ~ (p=0.507)
BenchmarkGunzip-2 143ms × (1.00,1.01) 143ms × (1.00,1.01) ~ (p=0.313)
BenchmarkGunzip-4 143ms × (1.00,1.01) 143ms × (1.00,1.01) ~ (p=0.312)
BenchmarkHTTPClientServer 110µs × (0.98,1.03) 109µs × (0.99,1.02) -1.40% (p=0.000)
BenchmarkHTTPClientServer-2 154µs × (0.90,1.08) 149µs × (0.90,1.08) -3.43% (p=0.007)
BenchmarkHTTPClientServer-4 138µs × (0.97,1.04) 138µs × (0.96,1.04) ~ (p=0.670)
BenchmarkJSONEncode 40.2ms × (0.98,1.02) 40.2ms × (0.98,1.05) ~ (p=0.828)
BenchmarkJSONEncode-2 35.1ms × (0.99,1.02) 35.2ms × (0.98,1.03) ~ (p=0.392)
BenchmarkJSONEncode-4 35.3ms × (0.98,1.03) 35.3ms × (0.98,1.02) ~ (p=0.813)
BenchmarkJSONDecode 119ms × (0.97,1.02) 117ms × (0.98,1.02) -1.80% (p=0.000)
BenchmarkJSONDecode-2 115ms × (0.99,1.02) 114ms × (0.98,1.02) -1.18% (p=0.000)
BenchmarkJSONDecode-4 116ms × (0.98,1.02) 114ms × (0.98,1.02) -1.43% (p=0.000)
BenchmarkMandelbrot200 6.03ms × (1.00,1.01) 6.03ms × (1.00,1.01) ~ (p=0.985)
BenchmarkMandelbrot200-2 6.03ms × (1.00,1.01) 6.02ms × (1.00,1.01) ~ (p=0.320)
BenchmarkMandelbrot200-4 6.03ms × (1.00,1.01) 6.03ms × (1.00,1.01) ~ (p=0.799)
BenchmarkGoParse 8.63ms × (0.89,1.10) 8.58ms × (0.93,1.09) ~ (p=0.667)
BenchmarkGoParse-2 8.20ms × (0.97,1.04) 8.37ms × (0.97,1.04) +1.96% (p=0.001)
BenchmarkGoParse-4 8.00ms × (0.98,1.02) 8.14ms × (0.99,1.02) +1.75% (p=0.000)
BenchmarkRegexpMatchEasy0_32 162ns × (1.00,1.01) 164ns × (0.98,1.04) +1.35% (p=0.011)
BenchmarkRegexpMatchEasy0_32-2 161ns × (1.00,1.01) 161ns × (1.00,1.00) ~ (p=0.185)
BenchmarkRegexpMatchEasy0_32-4 161ns × (1.00,1.00) 161ns × (1.00,1.00) -0.19% (p=0.001)
BenchmarkRegexpMatchEasy0_1K 540ns × (0.99,1.02) 566ns × (0.98,1.04) +4.98% (p=0.000)
BenchmarkRegexpMatchEasy0_1K-2 540ns × (0.99,1.01) 557ns × (0.99,1.01) +3.21% (p=0.000)
BenchmarkRegexpMatchEasy0_1K-4 541ns × (0.99,1.01) 559ns × (0.99,1.01) +3.26% (p=0.000)
BenchmarkRegexpMatchEasy1_32 139ns × (0.98,1.04) 139ns × (0.99,1.03) ~ (p=0.979)
BenchmarkRegexpMatchEasy1_32-2 139ns × (0.99,1.04) 139ns × (0.99,1.02) ~ (p=0.777)
BenchmarkRegexpMatchEasy1_32-4 139ns × (0.98,1.04) 139ns × (0.99,1.04) ~ (p=0.771)
BenchmarkRegexpMatchEasy1_1K 890ns × (0.99,1.03) 885ns × (1.00,1.01) -0.50% (p=0.004)
BenchmarkRegexpMatchEasy1_1K-2 888ns × (0.99,1.01) 885ns × (0.99,1.01) -0.37% (p=0.004)
BenchmarkRegexpMatchEasy1_1K-4 890ns × (0.99,1.02) 884ns × (1.00,1.00) -0.70% (p=0.000)
BenchmarkRegexpMatchMedium_32 252ns × (0.99,1.01) 251ns × (0.99,1.01) ~ (p=0.081)
BenchmarkRegexpMatchMedium_32-2 254ns × (0.99,1.04) 252ns × (0.99,1.01) -0.78% (p=0.027)
BenchmarkRegexpMatchMedium_32-4 253ns × (0.99,1.04) 252ns × (0.99,1.01) -0.70% (p=0.022)
BenchmarkRegexpMatchMedium_1K 72.9µs × (0.99,1.01) 72.7µs × (1.00,1.00) ~ (p=0.064)
BenchmarkRegexpMatchMedium_1K-2 74.1µs × (0.98,1.05) 72.9µs × (1.00,1.01) -1.61% (p=0.001)
BenchmarkRegexpMatchMedium_1K-4 73.6µs × (0.99,1.05) 72.8µs × (1.00,1.00) -1.13% (p=0.007)
BenchmarkRegexpMatchHard_32 3.88µs × (0.99,1.03) 3.92µs × (0.98,1.05) ~ (p=0.143)
BenchmarkRegexpMatchHard_32-2 3.89µs × (0.99,1.03) 3.93µs × (0.98,1.09) ~ (p=0.278)
BenchmarkRegexpMatchHard_32-4 3.90µs × (0.99,1.05) 3.93µs × (0.98,1.05) ~ (p=0.252)
BenchmarkRegexpMatchHard_1K 118µs × (0.99,1.01) 117µs × (0.99,1.02) -0.54% (p=0.003)
BenchmarkRegexpMatchHard_1K-2 118µs × (0.99,1.01) 118µs × (0.99,1.03) ~ (p=0.581)
BenchmarkRegexpMatchHard_1K-4 118µs × (0.99,1.02) 117µs × (0.99,1.01) -0.54% (p=0.002)
BenchmarkRevcomp 991ms × (0.95,1.10) 989ms × (0.94,1.08) ~ (p=0.879)
BenchmarkRevcomp-2 978ms × (0.95,1.11) 962ms × (0.96,1.08) ~ (p=0.257)
BenchmarkRevcomp-4 979ms × (0.96,1.07) 974ms × (0.96,1.11) ~ (p=0.678)
BenchmarkTemplate 141ms × (0.99,1.02) 145ms × (0.99,1.02) +2.75% (p=0.000)
BenchmarkTemplate-2 135ms × (0.98,1.02) 138ms × (0.99,1.02) +2.34% (p=0.000)
BenchmarkTemplate-4 136ms × (0.98,1.02) 140ms × (0.99,1.02) +2.71% (p=0.000)
BenchmarkTimeParse 640ns × (0.99,1.01) 622ns × (0.99,1.01) -2.88% (p=0.000)
BenchmarkTimeParse-2 640ns × (0.99,1.01) 622ns × (1.00,1.00) -2.81% (p=0.000)
BenchmarkTimeParse-4 640ns × (1.00,1.01) 622ns × (0.99,1.01) -2.82% (p=0.000)
BenchmarkTimeFormat 730ns × (0.98,1.02) 731ns × (0.98,1.03) ~ (p=0.767)
BenchmarkTimeFormat-2 709ns × (0.99,1.02) 707ns × (0.99,1.02) ~ (p=0.347)
BenchmarkTimeFormat-4 717ns × (0.98,1.01) 718ns × (0.98,1.02) ~ (p=0.793)
Change-Id: Ie779c47e912bf80eb918bafa13638bd8dfd6c2d9
Reviewed-on: https://go-review.googlesource.com/9406
Reviewed-by: Rick Hudson <rlh@golang.org>
2015-04-27 22:45:57 -04:00
|
|
|
onebitwalktype1(getinargx(Curfn.Type), &xoffset, bv)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
for j := 0; int32(j) < bv.n; j += 32 {
|
2015-02-13 14:40:36 -05:00
|
|
|
off = duint32(sym, off, bv.b[j/32])
|
|
|
|
|
}
|
|
|
|
|
if Curfn.Type.Outtuple > 0 {
|
|
|
|
|
xoffset = 0
|
cmd/internal/gc, runtime: use 1-bit bitmap for stack frames, data, bss
The bitmaps were 2 bits per pointer because we needed to distinguish
scalar, pointer, multiword, and we used the leftover value to distinguish
uninitialized from scalar, even though the garbage collector (GC) didn't care.
Now that there are no multiword structures from the GC's point of view,
cut the bitmaps down to 1 bit per pointer, recording just live pointer vs not.
The GC assumes the same layout for stack frames and for the maps
describing the global data and bss sections, so change them all in one CL.
The code still refers to 4-bit heap bitmaps and 2-bit "type bitmaps", since
the 2-bit representation lives (at least for now) in some of the reflect data.
Because these stack frame bitmaps are stored directly in the rodata in
the binary, this CL reduces the size of the 6g binary by about 1.1%.
Performance change is basically a wash, but using less memory,
and smaller binaries, and enables other bitmap reductions.
name old mean new mean delta
BenchmarkBinaryTree17 13.2s × (0.97,1.03) 13.0s × (0.99,1.01) -0.93% (p=0.005)
BenchmarkBinaryTree17-2 9.69s × (0.96,1.05) 9.51s × (0.96,1.03) -1.86% (p=0.001)
BenchmarkBinaryTree17-4 10.1s × (0.97,1.05) 10.0s × (0.96,1.05) ~ (p=0.141)
BenchmarkFannkuch11 4.35s × (0.99,1.01) 4.43s × (0.98,1.04) +1.75% (p=0.001)
BenchmarkFannkuch11-2 4.31s × (0.99,1.03) 4.32s × (1.00,1.00) ~ (p=0.095)
BenchmarkFannkuch11-4 4.32s × (0.99,1.02) 4.38s × (0.98,1.04) +1.38% (p=0.008)
BenchmarkFmtFprintfEmpty 83.5ns × (0.97,1.10) 87.3ns × (0.92,1.11) +4.55% (p=0.014)
BenchmarkFmtFprintfEmpty-2 81.8ns × (0.98,1.04) 82.5ns × (0.97,1.08) ~ (p=0.364)
BenchmarkFmtFprintfEmpty-4 80.9ns × (0.99,1.01) 82.6ns × (0.97,1.08) +2.12% (p=0.010)
BenchmarkFmtFprintfString 320ns × (0.95,1.04) 322ns × (0.97,1.05) ~ (p=0.368)
BenchmarkFmtFprintfString-2 303ns × (0.97,1.04) 304ns × (0.97,1.04) ~ (p=0.484)
BenchmarkFmtFprintfString-4 305ns × (0.97,1.05) 306ns × (0.98,1.05) ~ (p=0.543)
BenchmarkFmtFprintfInt 311ns × (0.98,1.03) 319ns × (0.97,1.03) +2.63% (p=0.000)
BenchmarkFmtFprintfInt-2 297ns × (0.98,1.04) 301ns × (0.97,1.04) +1.19% (p=0.023)
BenchmarkFmtFprintfInt-4 302ns × (0.98,1.02) 304ns × (0.97,1.03) ~ (p=0.126)
BenchmarkFmtFprintfIntInt 554ns × (0.96,1.05) 554ns × (0.97,1.03) ~ (p=0.975)
BenchmarkFmtFprintfIntInt-2 520ns × (0.98,1.03) 517ns × (0.98,1.02) ~ (p=0.153)
BenchmarkFmtFprintfIntInt-4 524ns × (0.98,1.02) 525ns × (0.98,1.03) ~ (p=0.597)
BenchmarkFmtFprintfPrefixedInt 433ns × (0.97,1.06) 434ns × (0.97,1.06) ~ (p=0.804)
BenchmarkFmtFprintfPrefixedInt-2 413ns × (0.98,1.04) 413ns × (0.98,1.03) ~ (p=0.881)
BenchmarkFmtFprintfPrefixedInt-4 420ns × (0.97,1.03) 421ns × (0.97,1.03) ~ (p=0.561)
BenchmarkFmtFprintfFloat 620ns × (0.99,1.03) 636ns × (0.97,1.03) +2.57% (p=0.000)
BenchmarkFmtFprintfFloat-2 601ns × (0.98,1.02) 617ns × (0.98,1.03) +2.58% (p=0.000)
BenchmarkFmtFprintfFloat-4 613ns × (0.98,1.03) 626ns × (0.98,1.02) +2.15% (p=0.000)
BenchmarkFmtManyArgs 2.19µs × (0.96,1.04) 2.23µs × (0.97,1.02) +1.65% (p=0.000)
BenchmarkFmtManyArgs-2 2.08µs × (0.98,1.03) 2.10µs × (0.99,1.02) +0.79% (p=0.019)
BenchmarkFmtManyArgs-4 2.10µs × (0.98,1.02) 2.13µs × (0.98,1.02) +1.72% (p=0.000)
BenchmarkGobDecode 21.3ms × (0.97,1.05) 21.1ms × (0.97,1.04) -1.36% (p=0.025)
BenchmarkGobDecode-2 20.0ms × (0.97,1.03) 19.2ms × (0.97,1.03) -4.00% (p=0.000)
BenchmarkGobDecode-4 19.5ms × (0.99,1.02) 19.0ms × (0.99,1.01) -2.39% (p=0.000)
BenchmarkGobEncode 18.3ms × (0.95,1.07) 18.1ms × (0.96,1.08) ~ (p=0.305)
BenchmarkGobEncode-2 16.8ms × (0.97,1.02) 16.4ms × (0.98,1.02) -2.79% (p=0.000)
BenchmarkGobEncode-4 15.4ms × (0.98,1.02) 15.4ms × (0.98,1.02) ~ (p=0.465)
BenchmarkGzip 650ms × (0.98,1.03) 655ms × (0.97,1.04) ~ (p=0.075)
BenchmarkGzip-2 652ms × (0.98,1.03) 655ms × (0.98,1.02) ~ (p=0.337)
BenchmarkGzip-4 656ms × (0.98,1.04) 653ms × (0.98,1.03) ~ (p=0.291)
BenchmarkGunzip 143ms × (1.00,1.01) 143ms × (1.00,1.01) ~ (p=0.507)
BenchmarkGunzip-2 143ms × (1.00,1.01) 143ms × (1.00,1.01) ~ (p=0.313)
BenchmarkGunzip-4 143ms × (1.00,1.01) 143ms × (1.00,1.01) ~ (p=0.312)
BenchmarkHTTPClientServer 110µs × (0.98,1.03) 109µs × (0.99,1.02) -1.40% (p=0.000)
BenchmarkHTTPClientServer-2 154µs × (0.90,1.08) 149µs × (0.90,1.08) -3.43% (p=0.007)
BenchmarkHTTPClientServer-4 138µs × (0.97,1.04) 138µs × (0.96,1.04) ~ (p=0.670)
BenchmarkJSONEncode 40.2ms × (0.98,1.02) 40.2ms × (0.98,1.05) ~ (p=0.828)
BenchmarkJSONEncode-2 35.1ms × (0.99,1.02) 35.2ms × (0.98,1.03) ~ (p=0.392)
BenchmarkJSONEncode-4 35.3ms × (0.98,1.03) 35.3ms × (0.98,1.02) ~ (p=0.813)
BenchmarkJSONDecode 119ms × (0.97,1.02) 117ms × (0.98,1.02) -1.80% (p=0.000)
BenchmarkJSONDecode-2 115ms × (0.99,1.02) 114ms × (0.98,1.02) -1.18% (p=0.000)
BenchmarkJSONDecode-4 116ms × (0.98,1.02) 114ms × (0.98,1.02) -1.43% (p=0.000)
BenchmarkMandelbrot200 6.03ms × (1.00,1.01) 6.03ms × (1.00,1.01) ~ (p=0.985)
BenchmarkMandelbrot200-2 6.03ms × (1.00,1.01) 6.02ms × (1.00,1.01) ~ (p=0.320)
BenchmarkMandelbrot200-4 6.03ms × (1.00,1.01) 6.03ms × (1.00,1.01) ~ (p=0.799)
BenchmarkGoParse 8.63ms × (0.89,1.10) 8.58ms × (0.93,1.09) ~ (p=0.667)
BenchmarkGoParse-2 8.20ms × (0.97,1.04) 8.37ms × (0.97,1.04) +1.96% (p=0.001)
BenchmarkGoParse-4 8.00ms × (0.98,1.02) 8.14ms × (0.99,1.02) +1.75% (p=0.000)
BenchmarkRegexpMatchEasy0_32 162ns × (1.00,1.01) 164ns × (0.98,1.04) +1.35% (p=0.011)
BenchmarkRegexpMatchEasy0_32-2 161ns × (1.00,1.01) 161ns × (1.00,1.00) ~ (p=0.185)
BenchmarkRegexpMatchEasy0_32-4 161ns × (1.00,1.00) 161ns × (1.00,1.00) -0.19% (p=0.001)
BenchmarkRegexpMatchEasy0_1K 540ns × (0.99,1.02) 566ns × (0.98,1.04) +4.98% (p=0.000)
BenchmarkRegexpMatchEasy0_1K-2 540ns × (0.99,1.01) 557ns × (0.99,1.01) +3.21% (p=0.000)
BenchmarkRegexpMatchEasy0_1K-4 541ns × (0.99,1.01) 559ns × (0.99,1.01) +3.26% (p=0.000)
BenchmarkRegexpMatchEasy1_32 139ns × (0.98,1.04) 139ns × (0.99,1.03) ~ (p=0.979)
BenchmarkRegexpMatchEasy1_32-2 139ns × (0.99,1.04) 139ns × (0.99,1.02) ~ (p=0.777)
BenchmarkRegexpMatchEasy1_32-4 139ns × (0.98,1.04) 139ns × (0.99,1.04) ~ (p=0.771)
BenchmarkRegexpMatchEasy1_1K 890ns × (0.99,1.03) 885ns × (1.00,1.01) -0.50% (p=0.004)
BenchmarkRegexpMatchEasy1_1K-2 888ns × (0.99,1.01) 885ns × (0.99,1.01) -0.37% (p=0.004)
BenchmarkRegexpMatchEasy1_1K-4 890ns × (0.99,1.02) 884ns × (1.00,1.00) -0.70% (p=0.000)
BenchmarkRegexpMatchMedium_32 252ns × (0.99,1.01) 251ns × (0.99,1.01) ~ (p=0.081)
BenchmarkRegexpMatchMedium_32-2 254ns × (0.99,1.04) 252ns × (0.99,1.01) -0.78% (p=0.027)
BenchmarkRegexpMatchMedium_32-4 253ns × (0.99,1.04) 252ns × (0.99,1.01) -0.70% (p=0.022)
BenchmarkRegexpMatchMedium_1K 72.9µs × (0.99,1.01) 72.7µs × (1.00,1.00) ~ (p=0.064)
BenchmarkRegexpMatchMedium_1K-2 74.1µs × (0.98,1.05) 72.9µs × (1.00,1.01) -1.61% (p=0.001)
BenchmarkRegexpMatchMedium_1K-4 73.6µs × (0.99,1.05) 72.8µs × (1.00,1.00) -1.13% (p=0.007)
BenchmarkRegexpMatchHard_32 3.88µs × (0.99,1.03) 3.92µs × (0.98,1.05) ~ (p=0.143)
BenchmarkRegexpMatchHard_32-2 3.89µs × (0.99,1.03) 3.93µs × (0.98,1.09) ~ (p=0.278)
BenchmarkRegexpMatchHard_32-4 3.90µs × (0.99,1.05) 3.93µs × (0.98,1.05) ~ (p=0.252)
BenchmarkRegexpMatchHard_1K 118µs × (0.99,1.01) 117µs × (0.99,1.02) -0.54% (p=0.003)
BenchmarkRegexpMatchHard_1K-2 118µs × (0.99,1.01) 118µs × (0.99,1.03) ~ (p=0.581)
BenchmarkRegexpMatchHard_1K-4 118µs × (0.99,1.02) 117µs × (0.99,1.01) -0.54% (p=0.002)
BenchmarkRevcomp 991ms × (0.95,1.10) 989ms × (0.94,1.08) ~ (p=0.879)
BenchmarkRevcomp-2 978ms × (0.95,1.11) 962ms × (0.96,1.08) ~ (p=0.257)
BenchmarkRevcomp-4 979ms × (0.96,1.07) 974ms × (0.96,1.11) ~ (p=0.678)
BenchmarkTemplate 141ms × (0.99,1.02) 145ms × (0.99,1.02) +2.75% (p=0.000)
BenchmarkTemplate-2 135ms × (0.98,1.02) 138ms × (0.99,1.02) +2.34% (p=0.000)
BenchmarkTemplate-4 136ms × (0.98,1.02) 140ms × (0.99,1.02) +2.71% (p=0.000)
BenchmarkTimeParse 640ns × (0.99,1.01) 622ns × (0.99,1.01) -2.88% (p=0.000)
BenchmarkTimeParse-2 640ns × (0.99,1.01) 622ns × (1.00,1.00) -2.81% (p=0.000)
BenchmarkTimeParse-4 640ns × (1.00,1.01) 622ns × (0.99,1.01) -2.82% (p=0.000)
BenchmarkTimeFormat 730ns × (0.98,1.02) 731ns × (0.98,1.03) ~ (p=0.767)
BenchmarkTimeFormat-2 709ns × (0.99,1.02) 707ns × (0.99,1.02) ~ (p=0.347)
BenchmarkTimeFormat-4 717ns × (0.98,1.01) 718ns × (0.98,1.02) ~ (p=0.793)
Change-Id: Ie779c47e912bf80eb918bafa13638bd8dfd6c2d9
Reviewed-on: https://go-review.googlesource.com/9406
Reviewed-by: Rick Hudson <rlh@golang.org>
2015-04-27 22:45:57 -04:00
|
|
|
onebitwalktype1(getoutargx(Curfn.Type), &xoffset, bv)
|
2015-02-23 16:07:24 -05:00
|
|
|
for j := 0; int32(j) < bv.n; j += 32 {
|
2015-02-13 14:40:36 -05:00
|
|
|
off = duint32(sym, off, bv.b[j/32])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-18 08:14:08 +12:00
|
|
|
ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-09-15 21:43:53 +02:00
|
|
|
// cmpstackvarlt reports whether the stack variable a sorts before b.
|
2015-09-19 23:55:27 +02:00
|
|
|
//
|
2015-02-13 14:40:36 -05:00
|
|
|
// Sort the list of stack variables. Autos after anything else,
|
|
|
|
|
// within autos, unused after used, within used, things with
|
|
|
|
|
// pointers first, zeroed things first, and then decreasing size.
|
|
|
|
|
// Because autos are laid out in decreasing addresses
|
|
|
|
|
// on the stack, pointers first, zeroed things first and decreasing size
|
|
|
|
|
// really means, in memory, things with pointers needing zeroing at
|
|
|
|
|
// the top of the stack and increasing in size.
|
|
|
|
|
// Non-autos sort on offset.
|
2015-09-19 23:55:27 +02:00
|
|
|
func cmpstackvarlt(a, b *Node) bool {
|
2016-02-20 21:36:12 -08:00
|
|
|
if (a.Class == PAUTO) != (b.Class == PAUTO) {
|
|
|
|
|
return b.Class == PAUTO
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if a.Class != PAUTO {
|
2016-02-20 21:36:12 -08:00
|
|
|
return a.Xoffset < b.Xoffset
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-06 21:18:41 +11:00
|
|
|
if a.Used != b.Used {
|
2015-09-19 23:55:27 +02:00
|
|
|
return a.Used
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-09-19 23:55:27 +02:00
|
|
|
ap := haspointers(a.Type)
|
|
|
|
|
bp := haspointers(b.Type)
|
2015-02-13 14:40:36 -05:00
|
|
|
if ap != bp {
|
2015-09-19 23:55:27 +02:00
|
|
|
return ap
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-09-19 23:55:27 +02:00
|
|
|
ap = a.Name.Needzero
|
|
|
|
|
bp = b.Name.Needzero
|
2015-02-13 14:40:36 -05:00
|
|
|
if ap != bp {
|
2015-09-19 23:55:27 +02:00
|
|
|
return ap
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-20 21:36:12 -08:00
|
|
|
if a.Type.Width != b.Type.Width {
|
|
|
|
|
return a.Type.Width > b.Type.Width
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-09-19 23:55:27 +02:00
|
|
|
return a.Sym.Name < b.Sym.Name
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-25 10:35:19 -08:00
|
|
|
// byStackvar implements sort.Interface for []*Node using cmpstackvarlt.
|
|
|
|
|
type byStackVar []*Node
|
|
|
|
|
|
|
|
|
|
func (s byStackVar) Len() int { return len(s) }
|
|
|
|
|
func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
|
|
|
|
|
func (s byStackVar) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
|
|
|
|
|
2015-05-26 21:30:20 -04:00
|
|
|
// stkdelta records the stack offset delta for a node
|
|
|
|
|
// during the compaction of the stack frame to remove
|
|
|
|
|
// unused stack slots.
|
|
|
|
|
var stkdelta = map[*Node]int64{}
|
|
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
|
|
|
|
|
func allocauto(ptxt *obj.Prog) {
|
|
|
|
|
Stksize = 0
|
|
|
|
|
stkptrsize = 0
|
|
|
|
|
|
2016-02-25 10:35:19 -08:00
|
|
|
if len(Curfn.Func.Dcl) == 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Mark the PAUTO's unused.
|
2016-02-25 10:35:19 -08:00
|
|
|
for _, ln := range Curfn.Func.Dcl {
|
|
|
|
|
if ln.Class == PAUTO {
|
|
|
|
|
ln.Used = false
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
markautoused(ptxt)
|
|
|
|
|
|
2016-02-25 10:35:19 -08:00
|
|
|
sort.Sort(byStackVar(Curfn.Func.Dcl))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// Unused autos are at the end, chop 'em off.
|
2016-02-25 10:35:19 -08:00
|
|
|
n := Curfn.Func.Dcl[0]
|
2015-03-06 21:18:41 +11:00
|
|
|
if n.Class == PAUTO && n.Op == ONAME && !n.Used {
|
2015-02-13 14:40:36 -05:00
|
|
|
// No locals used at all
|
2015-03-25 19:33:01 -07:00
|
|
|
Curfn.Func.Dcl = nil
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
fixautoused(ptxt)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-25 10:35:19 -08:00
|
|
|
for i := 1; i < len(Curfn.Func.Dcl); i++ {
|
|
|
|
|
n = Curfn.Func.Dcl[i]
|
2015-03-06 21:18:41 +11:00
|
|
|
if n.Class == PAUTO && n.Op == ONAME && !n.Used {
|
2016-02-25 10:35:19 -08:00
|
|
|
Curfn.Func.Dcl = Curfn.Func.Dcl[:i]
|
2015-02-13 14:40:36 -05:00
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reassign stack offsets of the locals that are still there.
|
2015-02-23 16:07:24 -05:00
|
|
|
var w int64
|
2016-02-25 10:35:19 -08:00
|
|
|
for _, n := range Curfn.Func.Dcl {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Class != PAUTO || n.Op != ONAME {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dowidth(n.Type)
|
|
|
|
|
w = n.Type.Width
|
|
|
|
|
if w >= Thearch.MAXWIDTH || w < 0 {
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("bad width")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
Stksize += w
|
|
|
|
|
Stksize = Rnd(Stksize, int64(n.Type.Align))
|
|
|
|
|
if haspointers(n.Type) {
|
|
|
|
|
stkptrsize = Stksize
|
|
|
|
|
}
|
2015-09-10 11:33:09 -04:00
|
|
|
if Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
|
2015-02-13 14:40:36 -05:00
|
|
|
Stksize = Rnd(Stksize, int64(Widthptr))
|
|
|
|
|
}
|
|
|
|
|
if Stksize >= 1<<31 {
|
|
|
|
|
setlineno(Curfn)
|
|
|
|
|
Yyerror("stack frame too large (>2GB)")
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-26 21:30:20 -04:00
|
|
|
stkdelta[n] = -Stksize - n.Xoffset
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Stksize = Rnd(Stksize, int64(Widthreg))
|
|
|
|
|
stkptrsize = Rnd(stkptrsize, int64(Widthreg))
|
|
|
|
|
|
|
|
|
|
fixautoused(ptxt)
|
|
|
|
|
|
|
|
|
|
// The debug information needs accurate offsets on the symbols.
|
2016-02-25 10:35:19 -08:00
|
|
|
for _, ln := range Curfn.Func.Dcl {
|
|
|
|
|
if ln.Class != PAUTO || ln.Op != ONAME {
|
2015-02-13 14:40:36 -05:00
|
|
|
continue
|
|
|
|
|
}
|
2016-02-25 10:35:19 -08:00
|
|
|
ln.Xoffset += stkdelta[ln]
|
|
|
|
|
delete(stkdelta, ln)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Cgen_checknil(n *Node) {
|
|
|
|
|
if Disable_checknil != 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ideally we wouldn't see any integer types here, but we do.
|
2015-03-01 07:54:01 +00:00
|
|
|
if n.Type == nil || (!Isptr[n.Type.Etype] && !Isint[n.Type.Etype] && n.Type.Etype != TUNSAFEPTR) {
|
2015-02-13 14:40:36 -05:00
|
|
|
Dump("checknil", n)
|
2015-08-30 23:10:03 +02:00
|
|
|
Fatalf("bad checknil")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-09-10 11:33:09 -04:00
|
|
|
if ((Thearch.Thechar == '0' || Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
|
2015-02-23 16:07:24 -05:00
|
|
|
var reg Node
|
2015-03-18 17:26:36 -04:00
|
|
|
Regalloc(®, Types[Tptr], n)
|
|
|
|
|
Cgen(n, ®)
|
2015-02-13 14:40:36 -05:00
|
|
|
Thearch.Gins(obj.ACHECKNIL, ®, nil)
|
2015-03-18 17:26:36 -04:00
|
|
|
Regfree(®)
|
2015-02-13 14:40:36 -05:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Thearch.Gins(obj.ACHECKNIL, n, nil)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func compile(fn *Node) {
|
|
|
|
|
if Newproc == nil {
|
|
|
|
|
Newproc = Sysfunc("newproc")
|
|
|
|
|
Deferproc = Sysfunc("deferproc")
|
|
|
|
|
Deferreturn = Sysfunc("deferreturn")
|
|
|
|
|
Panicindex = Sysfunc("panicindex")
|
|
|
|
|
panicslice = Sysfunc("panicslice")
|
2015-10-28 13:55:46 -04:00
|
|
|
panicdivide = Sysfunc("panicdivide")
|
2015-02-13 14:40:36 -05:00
|
|
|
throwreturn = Sysfunc("throwreturn")
|
2015-09-18 15:11:30 -07:00
|
|
|
growslice = Sysfunc("growslice")
|
2016-01-25 17:06:54 -08:00
|
|
|
writebarrierptr = Sysfunc("writebarrierptr")
|
|
|
|
|
typedmemmove = Sysfunc("typedmemmove")
|
2015-09-18 15:11:30 -07:00
|
|
|
panicdottype = Sysfunc("panicdottype")
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
lno := setlineno(fn)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
Curfn = fn
|
|
|
|
|
dowidth(Curfn.Type)
|
|
|
|
|
|
2015-02-23 16:07:24 -05:00
|
|
|
var nod1 Node
|
|
|
|
|
var ptxt *obj.Prog
|
|
|
|
|
var pl *obj.Plist
|
|
|
|
|
var p *obj.Prog
|
|
|
|
|
var n *Node
|
|
|
|
|
var nam *Node
|
|
|
|
|
var gcargs *Sym
|
|
|
|
|
var gclocals *Sym
|
2015-05-12 11:06:44 -07:00
|
|
|
var ssafn *ssa.Func
|
2016-02-27 14:31:33 -08:00
|
|
|
if len(fn.Nbody.Slice()) == 0 {
|
2015-05-27 10:42:55 -04:00
|
|
|
if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
|
|
|
|
|
Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
|
2015-02-13 14:40:36 -05:00
|
|
|
goto ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if Debug['A'] != 0 {
|
|
|
|
|
goto ret
|
|
|
|
|
}
|
|
|
|
|
emitptrargsmap()
|
|
|
|
|
goto ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
saveerrors()
|
|
|
|
|
|
|
|
|
|
// set up domain for labels
|
|
|
|
|
clearlabels()
|
|
|
|
|
|
2015-09-08 03:51:30 +02:00
|
|
|
if Curfn.Type.Outnamed {
|
2015-02-13 14:40:36 -05:00
|
|
|
// add clearing of the output parameters
|
2015-02-23 16:07:24 -05:00
|
|
|
var save Iter
|
|
|
|
|
t := Structfirst(&save, Getoutarg(Curfn.Type))
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
for t != nil {
|
|
|
|
|
if t.Nname != nil {
|
|
|
|
|
n = Nod(OAS, t.Nname, nil)
|
|
|
|
|
typecheck(&n, Etop)
|
2016-02-27 14:31:33 -08:00
|
|
|
Curfn.Nbody.Set(append([]*Node{n}, Curfn.Nbody.Slice()...))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t = structnext(&save)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
order(Curfn)
|
|
|
|
|
if nerrors != 0 {
|
|
|
|
|
goto ret
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-07 22:19:30 +02:00
|
|
|
hasdefer = false
|
2015-02-13 14:40:36 -05:00
|
|
|
walk(Curfn)
|
|
|
|
|
if nerrors != 0 {
|
|
|
|
|
goto ret
|
|
|
|
|
}
|
2015-10-20 10:00:07 -07:00
|
|
|
if instrumenting {
|
|
|
|
|
instrument(Curfn)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
if nerrors != 0 {
|
|
|
|
|
goto ret
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-12 11:01:13 -07:00
|
|
|
// Build an SSA backend function.
|
2015-12-11 20:41:52 -08:00
|
|
|
if shouldssa(Curfn) {
|
|
|
|
|
ssafn = buildssa(Curfn)
|
2015-10-19 11:36:07 -04:00
|
|
|
}
|
2015-04-15 15:51:25 -07:00
|
|
|
|
2015-02-13 14:40:36 -05:00
|
|
|
continpc = nil
|
|
|
|
|
breakpc = nil
|
|
|
|
|
|
|
|
|
|
pl = newplist()
|
2015-05-27 10:42:55 -04:00
|
|
|
pl.Name = Linksym(Curfn.Func.Nname.Sym)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
setlineno(Curfn)
|
|
|
|
|
|
|
|
|
|
Nodconst(&nod1, Types[TINT32], 0)
|
2015-05-27 10:42:55 -04:00
|
|
|
nam = Curfn.Func.Nname
|
2015-02-13 14:40:36 -05:00
|
|
|
if isblank(nam) {
|
|
|
|
|
nam = nil
|
|
|
|
|
}
|
|
|
|
|
ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1)
|
2015-06-07 21:45:39 -04:00
|
|
|
Afunclit(&ptxt.From, Curfn.Func.Nname)
|
2015-05-27 15:01:44 -04:00
|
|
|
ptxt.From3 = new(obj.Addr)
|
2015-03-25 19:33:01 -07:00
|
|
|
if fn.Func.Dupok {
|
2015-02-13 14:40:36 -05:00
|
|
|
ptxt.From3.Offset |= obj.DUPOK
|
|
|
|
|
}
|
2015-03-25 19:33:01 -07:00
|
|
|
if fn.Func.Wrapper {
|
2015-02-13 14:40:36 -05:00
|
|
|
ptxt.From3.Offset |= obj.WRAPPER
|
|
|
|
|
}
|
2015-03-25 19:33:01 -07:00
|
|
|
if fn.Func.Needctxt {
|
2015-02-13 14:40:36 -05:00
|
|
|
ptxt.From3.Offset |= obj.NEEDCTXT
|
|
|
|
|
}
|
2016-02-26 13:32:28 -08:00
|
|
|
if fn.Func.Pragma&Nosplit != 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
ptxt.From3.Offset |= obj.NOSPLIT
|
|
|
|
|
}
|
2016-02-26 13:32:28 -08:00
|
|
|
if fn.Func.Pragma&Systemstack != 0 {
|
2015-06-07 21:45:39 -04:00
|
|
|
ptxt.From.Sym.Cfunc = 1
|
|
|
|
|
}
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// Clumsy but important.
|
|
|
|
|
// See test/recover.go for test cases and src/reflect/value.go
|
|
|
|
|
// for the actual functions being considered.
|
|
|
|
|
if myimportpath != "" && myimportpath == "reflect" {
|
2015-05-27 10:42:55 -04:00
|
|
|
if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" {
|
2015-02-13 14:40:36 -05:00
|
|
|
ptxt.From3.Offset |= obj.WRAPPER
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-18 17:26:36 -04:00
|
|
|
ginit()
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
gcargs = makefuncdatasym("gcargs·%d", obj.FUNCDATA_ArgsPointerMaps)
|
|
|
|
|
gclocals = makefuncdatasym("gclocals·%d", obj.FUNCDATA_LocalsPointerMaps)
|
|
|
|
|
|
2015-05-26 21:49:31 -04:00
|
|
|
for _, t := range Curfn.Func.Fieldtrack {
|
|
|
|
|
gtrack(tracksym(t))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2016-02-25 10:35:19 -08:00
|
|
|
for _, n := range fn.Func.Dcl {
|
2015-02-13 14:40:36 -05:00
|
|
|
if n.Op != ONAME { // might be OTYPE or OLITERAL
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
switch n.Class {
|
2015-04-01 09:38:44 -07:00
|
|
|
case PAUTO, PPARAM, PPARAMOUT:
|
2016-02-25 10:35:19 -08:00
|
|
|
Nodconst(&nod1, Types[TUINTPTR], n.Type.Width)
|
|
|
|
|
p = Thearch.Gins(obj.ATYPE, n, &nod1)
|
|
|
|
|
p.From.Gotype = Linksym(ngotype(n))
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-11 20:41:52 -08:00
|
|
|
if ssafn != nil {
|
2015-05-12 11:06:44 -07:00
|
|
|
genssa(ssafn, ptxt, gcargs, gclocals)
|
2015-11-02 08:10:26 -08:00
|
|
|
if Curfn.Func.Endlineno != 0 {
|
|
|
|
|
lineno = Curfn.Func.Endlineno
|
|
|
|
|
}
|
2016-01-28 13:46:30 -08:00
|
|
|
ssafn.Free()
|
2015-05-12 11:06:44 -07:00
|
|
|
return
|
|
|
|
|
}
|
2016-03-03 15:08:25 -08:00
|
|
|
Genlist(Curfn.Func.Enter)
|
|
|
|
|
Genlist(Curfn.Nbody)
|
2015-03-18 17:26:36 -04:00
|
|
|
gclean()
|
2015-02-13 14:40:36 -05:00
|
|
|
checklabels()
|
|
|
|
|
if nerrors != 0 {
|
|
|
|
|
goto ret
|
|
|
|
|
}
|
2015-03-25 19:33:01 -07:00
|
|
|
if Curfn.Func.Endlineno != 0 {
|
|
|
|
|
lineno = Curfn.Func.Endlineno
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if Curfn.Type.Outtuple != 0 {
|
2015-03-18 17:26:36 -04:00
|
|
|
Ginscall(throwreturn, 0)
|
2015-02-13 14:40:36 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-18 17:26:36 -04:00
|
|
|
ginit()
|
2015-02-13 14:40:36 -05:00
|
|
|
|
|
|
|
|
// TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
|
2015-03-18 17:26:36 -04:00
|
|
|
cgen_ret(nil)
|
2015-02-13 14:40:36 -05:00
|
|
|
|
2015-09-07 22:19:30 +02:00
|
|
|
if hasdefer {
|
2015-02-13 14:40:36 -05:00
|
|
|
// deferreturn pretends to have one uintptr argument.
|
|
|
|
|
// Reserve space for it so stack scanner is happy.
|
|
|
|
|
if Maxarg < int64(Widthptr) {
|
|
|
|
|
Maxarg = int64(Widthptr)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-18 17:26:36 -04:00
|
|
|
gclean()
|
2015-02-13 14:40:36 -05:00
|
|
|
if nerrors != 0 {
|
|
|
|
|
goto ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Pc.As = obj.ARET // overwrite AEND
|
|
|
|
|
Pc.Lineno = lineno
|
|
|
|
|
|
|
|
|
|
fixjmp(ptxt)
|
2015-02-17 22:13:49 -05:00
|
|
|
if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 {
|
2015-02-13 14:40:36 -05:00
|
|
|
regopt(ptxt)
|
|
|
|
|
nilopt(ptxt)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Thearch.Expandchecks(ptxt)
|
|
|
|
|
|
|
|
|
|
allocauto(ptxt)
|
|
|
|
|
|
|
|
|
|
setlineno(Curfn)
|
2016-03-03 15:49:04 -08:00
|
|
|
if Stksize+Maxarg > 1<<31 {
|
2015-02-13 14:40:36 -05:00
|
|
|
Yyerror("stack frame too large (>2GB)")
|
|
|
|
|
goto ret
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Emit garbage collection symbols.
|
|
|
|
|
liveness(Curfn, ptxt, gcargs, gclocals)
|
|
|
|
|
|
|
|
|
|
gcsymdup(gcargs)
|
|
|
|
|
gcsymdup(gclocals)
|
|
|
|
|
|
|
|
|
|
Thearch.Defframe(ptxt)
|
|
|
|
|
|
|
|
|
|
if Debug['f'] != 0 {
|
|
|
|
|
frame(0)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Remove leftover instrumentation from the instruction stream.
|
|
|
|
|
removevardef(ptxt)
|
|
|
|
|
|
|
|
|
|
ret:
|
|
|
|
|
lineno = lno
|
|
|
|
|
}
|