cmd/compile, etc: store method tables as offsets

This CL introduces the typeOff type and a lookup method of the same
name that can turn a typeOff offset into an *rtype.

In a typical Go binary (built with buildmode=exe, pie, c-archive, or
c-shared), there is one moduledata and all typeOff values are offsets
relative to firstmoduledata.types. This makes computing the pointer
cheap in typical programs.

With buildmode=shared (and one day, buildmode=plugin) there are
multiple modules whose relative offset is determined at runtime.
We identify a type in the general case by the pair of the original
*rtype that references it and its typeOff value. We determine
the module from the original pointer, and then use the typeOff from
there to compute the final *rtype.

To ensure there is only one *rtype representing each type, the
runtime initializes a typemap for each module, using any identical
type from an earlier module when resolving that offset. This means
that types computed from an offset match the type mapped by the
pointer dynamic relocations.

A series of followup CLs will replace other *rtype values with typeOff
(and name/*string with nameOff).

For types created at runtime by reflect, type offsets are treated as
global IDs and reference into a reflect offset map kept by the runtime.

darwin/amd64:
	cmd/go:  -57KB (0.6%)
	jujud:  -557KB (0.8%)

linux/amd64 PIE:
	cmd/go: -361KB (3.0%)
	jujud:  -3.5MB (4.2%)

For #6853.

Change-Id: Icf096fd884a0a0cb9f280f46f7a26c70a9006c96
Reviewed-on: https://go-review.googlesource.com/21285
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Run-TryBot: David Crawshaw <crawshaw@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
David Crawshaw 2016-03-28 10:32:27 -04:00
parent e0611b1664
commit 7d469179e6
12 changed files with 637 additions and 128 deletions

View file

@ -19,7 +19,7 @@ import (
//
// This flood fill is wrapped in logic for pruning unused methods.
// All methods are mentioned by relocations on their receiver's *rtype.
// These relocations are specially defined as R_METHOD by the compiler
// These relocations are specially defined as R_METHODOFF by the compiler
// so we can detect and manipulated them here.
//
// There are three ways a method of a reachable type can be invoked:
@ -100,7 +100,7 @@ func deadcode(ctxt *Link) {
d.flood()
}
// Remove all remaining unreached R_METHOD relocations.
// Remove all remaining unreached R_METHODOFF relocations.
for _, m := range d.markableMethods {
for _, r := range m.r {
d.cleanupReloc(r)
@ -167,7 +167,7 @@ var markextra = []string{
type methodref struct {
m methodsig
src *LSym // receiver type symbol
r [3]*Reloc // R_METHOD relocations to fields of runtime.method
r [3]*Reloc // R_METHODOFF relocations to fields of runtime.method
}
func (m methodref) ifn() *LSym { return m.r[1].Sym }
@ -190,7 +190,7 @@ type deadcodepass struct {
func (d *deadcodepass) cleanupReloc(r *Reloc) {
if r.Sym.Attr.Reachable() {
r.Type = obj.R_ADDR
r.Type = obj.R_ADDROFF
} else {
if Debug['v'] > 1 {
fmt.Fprintf(d.ctxt.Bso, "removing method %s\n", r.Sym.Name)
@ -217,7 +217,7 @@ func (d *deadcodepass) mark(s, parent *LSym) {
func (d *deadcodepass) markMethod(m methodref) {
for _, r := range m.r {
d.mark(r.Sym, m.src)
r.Type = obj.R_ADDR
r.Type = obj.R_ADDROFF
}
}
@ -291,14 +291,14 @@ func (d *deadcodepass) flood() {
}
}
mpos := 0 // 0-3, the R_METHOD relocs of runtime.uncommontype
mpos := 0 // 0-3, the R_METHODOFF relocs of runtime.uncommontype
var methods []methodref
for i := 0; i < len(s.R); i++ {
r := &s.R[i]
if r.Sym == nil {
continue
}
if r.Type != obj.R_METHOD {
if r.Type != obj.R_METHODOFF {
d.mark(r.Sym, s)
continue
}