2015-02-27 22:57:28 -05:00
|
|
|
// Copyright 2012 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 ld
|
|
|
|
|
|
2015-05-25 16:13:50 +12:00
|
|
|
import (
|
|
|
|
|
"cmd/internal/obj"
|
|
|
|
|
"debug/elf"
|
|
|
|
|
)
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
|
|
|
// Decoding the type.* symbols. This has to be in sync with
|
|
|
|
|
// ../../runtime/type.go, or more specifically, with what
|
|
|
|
|
// ../gc/reflect.c stuffs in these.
|
|
|
|
|
|
|
|
|
|
func decode_reloc(s *LSym, off int32) *Reloc {
|
2015-03-02 12:35:15 -05:00
|
|
|
for i := 0; i < len(s.R); i++ {
|
2015-02-27 22:57:28 -05:00
|
|
|
if s.R[i].Off == off {
|
|
|
|
|
return &s.R[i:][0]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func decode_reloc_sym(s *LSym, off int32) *LSym {
|
2015-03-02 12:35:15 -05:00
|
|
|
r := decode_reloc(s, off)
|
2015-02-27 22:57:28 -05:00
|
|
|
if r == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
return r.Sym
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func decode_inuxi(p []byte, sz int) uint64 {
|
|
|
|
|
switch sz {
|
|
|
|
|
case 2:
|
|
|
|
|
return uint64(Ctxt.Arch.ByteOrder.Uint16(p))
|
|
|
|
|
case 4:
|
|
|
|
|
return uint64(Ctxt.Arch.ByteOrder.Uint32(p))
|
|
|
|
|
case 8:
|
|
|
|
|
return Ctxt.Arch.ByteOrder.Uint64(p)
|
2015-04-09 07:37:17 -04:00
|
|
|
default:
|
|
|
|
|
Exitf("dwarf: decode inuxi %d", sz)
|
|
|
|
|
panic("unreachable")
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-20 22:54:15 -05:00
|
|
|
func commonsize() int { return 6*Thearch.Ptrsize + 8 } // runtime._type
|
|
|
|
|
func structfieldSize() int { return 5 * Thearch.Ptrsize } // runtime.structfield
|
|
|
|
|
func uncommonSize() int { return 2*Thearch.Ptrsize + 2*Thearch.Intsize } // runtime.uncommontype
|
2015-02-27 22:57:28 -05:00
|
|
|
|
|
|
|
|
// Type.commonType.kind
|
|
|
|
|
func decodetype_kind(s *LSym) uint8 {
|
2015-05-04 14:37:45 -04:00
|
|
|
return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindMask) // 0x13 / 0x1f
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Type.commonType.kind
|
|
|
|
|
func decodetype_noptr(s *LSym) uint8 {
|
2015-05-04 14:37:45 -04:00
|
|
|
return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindNoPointers) // 0x13 / 0x1f
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Type.commonType.kind
|
|
|
|
|
func decodetype_usegcprog(s *LSym) uint8 {
|
2015-05-04 14:37:45 -04:00
|
|
|
return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindGCProg) // 0x13 / 0x1f
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Type.commonType.size
|
|
|
|
|
func decodetype_size(s *LSym) int64 {
|
|
|
|
|
return int64(decode_inuxi(s.P, Thearch.Ptrsize)) // 0x8 / 0x10
|
|
|
|
|
}
|
|
|
|
|
|
runtime: reintroduce ``dead'' space during GC scan
Reintroduce an optimization discarded during the initial conversion
from 4-bit heap bitmaps to 2-bit heap bitmaps: when we reach the
place in the bitmap where there are no more pointers, mark that position
for the GC so that it can avoid scanning past that place.
During heapBitsSetType we can also avoid initializing heap bitmap
beyond that location, which gives a bit of a win compared to Go 1.4.
This particular optimization (not initializing the heap bitmap) may not last:
we might change typedmemmove to use the heap bitmap, in which
case it would all need to be initialized. The early stop in the GC scan
will stay no matter what.
Compared to Go 1.4 (github.com/rsc/go, branch go14bench):
name old mean new mean delta
SetTypeNode64 80.7ns × (1.00,1.01) 57.4ns × (1.00,1.01) -28.83% (p=0.000)
SetTypeNode64Dead 80.5ns × (1.00,1.01) 13.1ns × (0.99,1.02) -83.77% (p=0.000)
SetTypeNode64Slice 2.16µs × (1.00,1.01) 1.54µs × (1.00,1.01) -28.75% (p=0.000)
SetTypeNode64DeadSlice 2.16µs × (1.00,1.01) 1.52µs × (1.00,1.00) -29.74% (p=0.000)
Compared to previous CL:
name old mean new mean delta
SetTypeNode64 56.7ns × (1.00,1.00) 57.4ns × (1.00,1.01) +1.19% (p=0.000)
SetTypeNode64Dead 57.2ns × (1.00,1.00) 13.1ns × (0.99,1.02) -77.15% (p=0.000)
SetTypeNode64Slice 1.56µs × (1.00,1.01) 1.54µs × (1.00,1.01) -0.89% (p=0.000)
SetTypeNode64DeadSlice 1.55µs × (1.00,1.01) 1.52µs × (1.00,1.00) -2.23% (p=0.000)
This is the last CL in the sequence converting from the 4-bit heap
to the 2-bit heap, with all the same optimizations reenabled.
Compared to before that process began (compared to CL 9701 patch set 1):
name old mean new mean delta
BinaryTree17 5.87s × (0.94,1.09) 5.91s × (0.96,1.06) ~ (p=0.578)
Fannkuch11 4.32s × (1.00,1.00) 4.32s × (1.00,1.00) ~ (p=0.474)
FmtFprintfEmpty 89.1ns × (0.95,1.16) 89.0ns × (0.93,1.10) ~ (p=0.942)
FmtFprintfString 283ns × (0.98,1.02) 298ns × (0.98,1.06) +5.33% (p=0.000)
FmtFprintfInt 284ns × (0.98,1.04) 286ns × (0.98,1.03) ~ (p=0.208)
FmtFprintfIntInt 486ns × (0.98,1.03) 498ns × (0.97,1.06) +2.48% (p=0.000)
FmtFprintfPrefixedInt 400ns × (0.99,1.02) 408ns × (0.98,1.02) +2.23% (p=0.000)
FmtFprintfFloat 566ns × (0.99,1.01) 587ns × (0.98,1.01) +3.69% (p=0.000)
FmtManyArgs 1.91µs × (0.99,1.02) 1.94µs × (0.99,1.02) +1.81% (p=0.000)
GobDecode 15.5ms × (0.98,1.05) 15.8ms × (0.98,1.03) +1.94% (p=0.002)
GobEncode 11.9ms × (0.97,1.03) 12.0ms × (0.96,1.09) ~ (p=0.263)
Gzip 648ms × (0.99,1.01) 648ms × (0.99,1.01) ~ (p=0.992)
Gunzip 143ms × (1.00,1.00) 143ms × (1.00,1.01) ~ (p=0.585)
HTTPClientServer 89.2µs × (0.99,1.02) 90.3µs × (0.98,1.01) +1.24% (p=0.000)
JSONEncode 32.3ms × (0.97,1.06) 31.6ms × (0.99,1.01) -2.29% (p=0.000)
JSONDecode 106ms × (0.99,1.01) 107ms × (1.00,1.01) +0.62% (p=0.000)
Mandelbrot200 6.02ms × (1.00,1.00) 6.03ms × (1.00,1.01) ~ (p=0.250)
GoParse 6.57ms × (0.97,1.06) 6.53ms × (0.99,1.03) ~ (p=0.243)
RegexpMatchEasy0_32 162ns × (1.00,1.00) 161ns × (1.00,1.01) -0.80% (p=0.000)
RegexpMatchEasy0_1K 561ns × (0.99,1.02) 541ns × (0.99,1.01) -3.67% (p=0.000)
RegexpMatchEasy1_32 145ns × (0.95,1.04) 138ns × (1.00,1.00) -5.04% (p=0.000)
RegexpMatchEasy1_1K 864ns × (0.99,1.04) 887ns × (0.99,1.01) +2.57% (p=0.000)
RegexpMatchMedium_32 255ns × (0.99,1.04) 253ns × (0.99,1.01) -1.05% (p=0.012)
RegexpMatchMedium_1K 73.9µs × (0.98,1.04) 72.8µs × (1.00,1.00) -1.51% (p=0.005)
RegexpMatchHard_32 3.92µs × (0.98,1.04) 3.85µs × (1.00,1.01) -1.88% (p=0.002)
RegexpMatchHard_1K 120µs × (0.98,1.04) 117µs × (1.00,1.01) -2.02% (p=0.001)
Revcomp 936ms × (0.95,1.08) 922ms × (0.97,1.08) ~ (p=0.234)
Template 130ms × (0.98,1.04) 126ms × (0.99,1.01) -2.99% (p=0.000)
TimeParse 638ns × (0.98,1.05) 628ns × (0.99,1.01) -1.54% (p=0.004)
TimeFormat 674ns × (0.99,1.01) 668ns × (0.99,1.01) -0.80% (p=0.001)
The slowdown of the first few benchmarks seems to be due to the new
atomic operations for certain small size allocations. But the larger
benchmarks mostly improve, probably due to the decreased memory
pressure from having half as much heap bitmap.
CL 9706, which removes the (never used anymore) wbshadow mode,
gets back what is lost in the early microbenchmarks.
Change-Id: I37423a209e8ec2a2e92538b45cac5422a6acd32d
Reviewed-on: https://go-review.googlesource.com/9705
Reviewed-by: Rick Hudson <rlh@golang.org>
2015-05-04 22:53:54 -04:00
|
|
|
// Type.commonType.ptrdata
|
|
|
|
|
func decodetype_ptrdata(s *LSym) int64 {
|
|
|
|
|
return int64(decode_inuxi(s.P[Thearch.Ptrsize:], Thearch.Ptrsize)) // 0x8 / 0x10
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-20 22:54:15 -05:00
|
|
|
// Type.commonType.tflag
|
|
|
|
|
func decodetype_hasUncommon(s *LSym) bool {
|
|
|
|
|
const tflagUncommon = 1 // see ../../../../reflect/type.go:/^type.tflag
|
|
|
|
|
return s.P[2*Thearch.Ptrsize+4]&tflagUncommon != 0
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-25 16:13:50 +12:00
|
|
|
// Find the elf.Section of a given shared library that contains a given address.
|
|
|
|
|
func findShlibSection(path string, addr uint64) *elf.Section {
|
|
|
|
|
for _, shlib := range Ctxt.Shlibs {
|
|
|
|
|
if shlib.Path == path {
|
|
|
|
|
for _, sect := range shlib.File.Sections {
|
|
|
|
|
if sect.Addr <= addr && addr <= sect.Addr+sect.Size {
|
|
|
|
|
return sect
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
// Type.commonType.gc
|
2015-05-25 16:13:50 +12:00
|
|
|
func decodetype_gcprog(s *LSym) []byte {
|
2015-04-01 16:20:44 +13:00
|
|
|
if s.Type == obj.SDYNIMPORT {
|
2015-05-25 16:13:50 +12:00
|
|
|
addr := decodetype_gcprog_shlib(s)
|
|
|
|
|
sect := findShlibSection(s.File, addr)
|
|
|
|
|
if sect != nil {
|
|
|
|
|
// A gcprog is a 4-byte uint32 indicating length, followed by
|
|
|
|
|
// the actual program.
|
|
|
|
|
progsize := make([]byte, 4)
|
|
|
|
|
sect.ReadAt(progsize, int64(addr-sect.Addr))
|
|
|
|
|
progbytes := make([]byte, Ctxt.Arch.ByteOrder.Uint32(progsize))
|
|
|
|
|
sect.ReadAt(progbytes, int64(addr-sect.Addr+4))
|
|
|
|
|
return append(progsize, progbytes...)
|
|
|
|
|
}
|
|
|
|
|
Exitf("cannot find gcprog for %s", s.Name)
|
|
|
|
|
return nil
|
2015-04-01 16:20:44 +13:00
|
|
|
}
|
2015-05-25 16:13:50 +12:00
|
|
|
return decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize)).P
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2015-05-04 14:35:35 -04:00
|
|
|
func decodetype_gcprog_shlib(s *LSym) uint64 {
|
2015-07-02 11:37:51 +12:00
|
|
|
if Thearch.Thechar == '7' {
|
|
|
|
|
for _, shlib := range Ctxt.Shlibs {
|
|
|
|
|
if shlib.Path == s.File {
|
|
|
|
|
return shlib.gcdata_addresses[s]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return 0
|
|
|
|
|
}
|
2015-05-04 14:37:45 -04:00
|
|
|
return decode_inuxi(s.P[2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize):], Thearch.Ptrsize)
|
2015-05-04 14:35:35 -04:00
|
|
|
}
|
|
|
|
|
|
2015-02-27 22:57:28 -05:00
|
|
|
func decodetype_gcmask(s *LSym) []byte {
|
2015-04-01 16:20:44 +13:00
|
|
|
if s.Type == obj.SDYNIMPORT {
|
2015-05-25 16:13:50 +12:00
|
|
|
addr := decodetype_gcprog_shlib(s)
|
|
|
|
|
ptrdata := decodetype_ptrdata(s)
|
|
|
|
|
sect := findShlibSection(s.File, addr)
|
|
|
|
|
if sect != nil {
|
|
|
|
|
r := make([]byte, ptrdata/int64(Thearch.Ptrsize))
|
|
|
|
|
sect.ReadAt(r, int64(addr-sect.Addr))
|
|
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
Exitf("cannot find gcmask for %s", s.Name)
|
|
|
|
|
return nil
|
2015-04-01 16:20:44 +13:00
|
|
|
}
|
2015-05-04 14:37:45 -04:00
|
|
|
mask := decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize))
|
2015-02-27 22:57:28 -05:00
|
|
|
return mask.P
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Type.ArrayType.elem and Type.SliceType.Elem
|
|
|
|
|
func decodetype_arrayelem(s *LSym) *LSym {
|
|
|
|
|
return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func decodetype_arraylen(s *LSym) int64 {
|
|
|
|
|
return int64(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Ptrsize))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Type.PtrType.elem
|
|
|
|
|
func decodetype_ptrelem(s *LSym) *LSym {
|
|
|
|
|
return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Type.MapType.key, elem
|
|
|
|
|
func decodetype_mapkey(s *LSym) *LSym {
|
|
|
|
|
return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func decodetype_mapvalue(s *LSym) *LSym {
|
|
|
|
|
return decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)) // 0x20 / 0x38
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Type.ChanType.elem
|
|
|
|
|
func decodetype_chanelem(s *LSym) *LSym {
|
|
|
|
|
return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Type.FuncType.dotdotdot
|
|
|
|
|
func decodetype_funcdotdotdot(s *LSym) int {
|
|
|
|
|
return int(s.P[commonsize()])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Type.FuncType.in.length
|
|
|
|
|
func decodetype_funcincount(s *LSym) int {
|
|
|
|
|
return int(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Intsize))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func decodetype_funcoutcount(s *LSym) int {
|
|
|
|
|
return int(decode_inuxi(s.P[commonsize()+3*Thearch.Ptrsize+2*Thearch.Intsize:], Thearch.Intsize))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func decodetype_funcintype(s *LSym, i int) *LSym {
|
2015-03-02 12:35:15 -05:00
|
|
|
r := decode_reloc(s, int32(commonsize())+int32(Thearch.Ptrsize))
|
2015-02-27 22:57:28 -05:00
|
|
|
if r == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
return decode_reloc_sym(r.Sym, int32(r.Add+int64(int32(i)*int32(Thearch.Ptrsize))))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func decodetype_funcouttype(s *LSym, i int) *LSym {
|
2015-03-02 12:35:15 -05:00
|
|
|
r := decode_reloc(s, int32(commonsize())+2*int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize))
|
2015-02-27 22:57:28 -05:00
|
|
|
if r == nil {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
return decode_reloc_sym(r.Sym, int32(r.Add+int64(int32(i)*int32(Thearch.Ptrsize))))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Type.StructType.fields.Slice::length
|
|
|
|
|
func decodetype_structfieldcount(s *LSym) int {
|
|
|
|
|
return int(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize:], Thearch.Intsize))
|
|
|
|
|
}
|
|
|
|
|
|
2016-02-20 22:54:15 -05:00
|
|
|
func decodetype_structfieldarrayoff(s *LSym, i int) int {
|
|
|
|
|
off := commonsize() + Thearch.Ptrsize + 2*Thearch.Intsize
|
|
|
|
|
if decodetype_hasUncommon(s) {
|
|
|
|
|
off += uncommonSize()
|
|
|
|
|
}
|
|
|
|
|
off += i * structfieldSize()
|
|
|
|
|
return off
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func decodetype_structfieldname(s *LSym, i int) string {
|
2016-02-20 22:54:15 -05:00
|
|
|
off := decodetype_structfieldarrayoff(s, i)
|
|
|
|
|
s = decode_reloc_sym(s, int32(off))
|
2015-02-27 22:57:28 -05:00
|
|
|
if s == nil { // embedded structs have a nil name.
|
|
|
|
|
return ""
|
|
|
|
|
}
|
2015-03-02 12:35:15 -05:00
|
|
|
r := decode_reloc(s, 0) // s has a pointer to the string data at offset 0
|
|
|
|
|
if r == nil { // shouldn't happen.
|
2015-02-27 22:57:28 -05:00
|
|
|
return ""
|
|
|
|
|
}
|
2016-02-18 11:08:25 -05:00
|
|
|
strlen := int64(decode_inuxi(s.P[Thearch.Ptrsize:], Thearch.Intsize))
|
|
|
|
|
return string(r.Sym.P[r.Add : r.Add+strlen])
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func decodetype_structfieldtype(s *LSym, i int) *LSym {
|
2016-02-20 22:54:15 -05:00
|
|
|
off := decodetype_structfieldarrayoff(s, i)
|
|
|
|
|
return decode_reloc_sym(s, int32(off+2*Thearch.Ptrsize))
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func decodetype_structfieldoffs(s *LSym, i int) int64 {
|
2016-02-20 22:54:15 -05:00
|
|
|
off := decodetype_structfieldarrayoff(s, i)
|
|
|
|
|
return int64(decode_inuxi(s.P[off+4*Thearch.Ptrsize:], Thearch.Intsize))
|
2015-02-27 22:57:28 -05:00
|
|
|
}
|
|
|
|
|
|
2015-03-05 13:57:36 -05:00
|
|
|
// InterfaceType.methods.length
|
2015-02-27 22:57:28 -05:00
|
|
|
func decodetype_ifacemethodcount(s *LSym) int64 {
|
|
|
|
|
return int64(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize:], Thearch.Intsize))
|
|
|
|
|
}
|