mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
internal/pkgbits: extract unified IR coding-level logic
This logic is needed for the go/types unified IR importer, so extract it into a separate internal package so we can reuse a single copy. Change-Id: I5f734b76e580fdb69ee39e45ac553c22d01c5909 Reviewed-on: https://go-review.googlesource.com/c/go/+/386000 Run-TryBot: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> TryBot-Result: Gopher Robot <gobot@golang.org> Trust: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
6d881da9c8
commit
7c151f3280
19 changed files with 1310 additions and 1272 deletions
|
|
@ -7,6 +7,7 @@
|
|||
package noder
|
||||
|
||||
import (
|
||||
"internal/pkgbits"
|
||||
"io"
|
||||
|
||||
"cmd/compile/internal/base"
|
||||
|
|
@ -29,26 +30,30 @@ import (
|
|||
// multiple parts into a cohesive whole"... e.g., "assembler" and
|
||||
// "compiler" are also already taken.
|
||||
|
||||
// TODO(mdempsky): Should linker go into pkgbits? Probably the
|
||||
// low-level linking details can be moved there, but the logic for
|
||||
// handling extension data needs to stay in the compiler.
|
||||
|
||||
type linker struct {
|
||||
pw pkgEncoder
|
||||
pw pkgbits.PkgEncoder
|
||||
|
||||
pkgs map[string]int
|
||||
decls map[*types.Sym]int
|
||||
}
|
||||
|
||||
func (l *linker) relocAll(pr *pkgReader, relocs []relocEnt) []relocEnt {
|
||||
res := make([]relocEnt, len(relocs))
|
||||
func (l *linker) relocAll(pr *pkgReader, relocs []pkgbits.RelocEnt) []pkgbits.RelocEnt {
|
||||
res := make([]pkgbits.RelocEnt, len(relocs))
|
||||
for i, rent := range relocs {
|
||||
rent.idx = l.relocIdx(pr, rent.kind, rent.idx)
|
||||
rent.Idx = l.relocIdx(pr, rent.Kind, rent.Idx)
|
||||
res[i] = rent
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func (l *linker) relocIdx(pr *pkgReader, k reloc, idx int) int {
|
||||
func (l *linker) relocIdx(pr *pkgReader, k pkgbits.RelocKind, idx int) int {
|
||||
assert(pr != nil)
|
||||
|
||||
absIdx := pr.absIdx(k, idx)
|
||||
absIdx := pr.AbsIdx(k, idx)
|
||||
|
||||
if newidx := pr.newindex[absIdx]; newidx != 0 {
|
||||
return ^newidx
|
||||
|
|
@ -56,11 +61,11 @@ func (l *linker) relocIdx(pr *pkgReader, k reloc, idx int) int {
|
|||
|
||||
var newidx int
|
||||
switch k {
|
||||
case relocString:
|
||||
case pkgbits.RelocString:
|
||||
newidx = l.relocString(pr, idx)
|
||||
case relocPkg:
|
||||
case pkgbits.RelocPkg:
|
||||
newidx = l.relocPkg(pr, idx)
|
||||
case relocObj:
|
||||
case pkgbits.RelocObj:
|
||||
newidx = l.relocObj(pr, idx)
|
||||
|
||||
default:
|
||||
|
|
@ -70,9 +75,9 @@ func (l *linker) relocIdx(pr *pkgReader, k reloc, idx int) int {
|
|||
// every section could be deduplicated. This would also be easier
|
||||
// if we do external relocations.
|
||||
|
||||
w := l.pw.newEncoderRaw(k)
|
||||
w := l.pw.NewEncoderRaw(k)
|
||||
l.relocCommon(pr, &w, k, idx)
|
||||
newidx = w.idx
|
||||
newidx = w.Idx
|
||||
}
|
||||
|
||||
pr.newindex[absIdx] = ^newidx
|
||||
|
|
@ -81,43 +86,43 @@ func (l *linker) relocIdx(pr *pkgReader, k reloc, idx int) int {
|
|||
}
|
||||
|
||||
func (l *linker) relocString(pr *pkgReader, idx int) int {
|
||||
return l.pw.stringIdx(pr.stringIdx(idx))
|
||||
return l.pw.StringIdx(pr.StringIdx(idx))
|
||||
}
|
||||
|
||||
func (l *linker) relocPkg(pr *pkgReader, idx int) int {
|
||||
path := pr.peekPkgPath(idx)
|
||||
path := pr.PeekPkgPath(idx)
|
||||
|
||||
if newidx, ok := l.pkgs[path]; ok {
|
||||
return newidx
|
||||
}
|
||||
|
||||
r := pr.newDecoder(relocPkg, idx, syncPkgDef)
|
||||
w := l.pw.newEncoder(relocPkg, syncPkgDef)
|
||||
l.pkgs[path] = w.idx
|
||||
r := pr.NewDecoder(pkgbits.RelocPkg, idx, pkgbits.SyncPkgDef)
|
||||
w := l.pw.NewEncoder(pkgbits.RelocPkg, pkgbits.SyncPkgDef)
|
||||
l.pkgs[path] = w.Idx
|
||||
|
||||
// TODO(mdempsky): We end up leaving an empty string reference here
|
||||
// from when the package was originally written as "". Probably not
|
||||
// a big deal, but a little annoying. Maybe relocating
|
||||
// cross-references in place is the way to go after all.
|
||||
w.relocs = l.relocAll(pr, r.relocs)
|
||||
w.Relocs = l.relocAll(pr, r.Relocs)
|
||||
|
||||
_ = r.string() // original path
|
||||
w.string(path)
|
||||
_ = r.String() // original path
|
||||
w.String(path)
|
||||
|
||||
io.Copy(&w.data, &r.data)
|
||||
io.Copy(&w.Data, &r.Data)
|
||||
|
||||
return w.flush()
|
||||
return w.Flush()
|
||||
}
|
||||
|
||||
func (l *linker) relocObj(pr *pkgReader, idx int) int {
|
||||
path, name, tag := pr.peekObj(idx)
|
||||
path, name, tag := pr.PeekObj(idx)
|
||||
sym := types.NewPkg(path, "").Lookup(name)
|
||||
|
||||
if newidx, ok := l.decls[sym]; ok {
|
||||
return newidx
|
||||
}
|
||||
|
||||
if tag == objStub && path != "builtin" && path != "unsafe" {
|
||||
if tag == pkgbits.ObjStub && path != "builtin" && path != "unsafe" {
|
||||
pri, ok := objReader[sym]
|
||||
if !ok {
|
||||
base.Fatalf("missing reader for %q.%v", path, name)
|
||||
|
|
@ -127,25 +132,25 @@ func (l *linker) relocObj(pr *pkgReader, idx int) int {
|
|||
pr = pri.pr
|
||||
idx = pri.idx
|
||||
|
||||
path2, name2, tag2 := pr.peekObj(idx)
|
||||
path2, name2, tag2 := pr.PeekObj(idx)
|
||||
sym2 := types.NewPkg(path2, "").Lookup(name2)
|
||||
assert(sym == sym2)
|
||||
assert(tag2 != objStub)
|
||||
assert(tag2 != pkgbits.ObjStub)
|
||||
}
|
||||
|
||||
w := l.pw.newEncoderRaw(relocObj)
|
||||
wext := l.pw.newEncoderRaw(relocObjExt)
|
||||
wname := l.pw.newEncoderRaw(relocName)
|
||||
wdict := l.pw.newEncoderRaw(relocObjDict)
|
||||
w := l.pw.NewEncoderRaw(pkgbits.RelocObj)
|
||||
wext := l.pw.NewEncoderRaw(pkgbits.RelocObjExt)
|
||||
wname := l.pw.NewEncoderRaw(pkgbits.RelocName)
|
||||
wdict := l.pw.NewEncoderRaw(pkgbits.RelocObjDict)
|
||||
|
||||
l.decls[sym] = w.idx
|
||||
assert(wext.idx == w.idx)
|
||||
assert(wname.idx == w.idx)
|
||||
assert(wdict.idx == w.idx)
|
||||
l.decls[sym] = w.Idx
|
||||
assert(wext.Idx == w.Idx)
|
||||
assert(wname.Idx == w.Idx)
|
||||
assert(wdict.Idx == w.Idx)
|
||||
|
||||
l.relocCommon(pr, &w, relocObj, idx)
|
||||
l.relocCommon(pr, &wname, relocName, idx)
|
||||
l.relocCommon(pr, &wdict, relocObjDict, idx)
|
||||
l.relocCommon(pr, &w, pkgbits.RelocObj, idx)
|
||||
l.relocCommon(pr, &wname, pkgbits.RelocName, idx)
|
||||
l.relocCommon(pr, &wdict, pkgbits.RelocObjDict, idx)
|
||||
|
||||
var obj *ir.Name
|
||||
if path == "" {
|
||||
|
|
@ -162,70 +167,70 @@ func (l *linker) relocObj(pr *pkgReader, idx int) int {
|
|||
}
|
||||
|
||||
if obj != nil {
|
||||
wext.sync(syncObject1)
|
||||
wext.Sync(pkgbits.SyncObject1)
|
||||
switch tag {
|
||||
case objFunc:
|
||||
case pkgbits.ObjFunc:
|
||||
l.relocFuncExt(&wext, obj)
|
||||
case objType:
|
||||
case pkgbits.ObjType:
|
||||
l.relocTypeExt(&wext, obj)
|
||||
case objVar:
|
||||
case pkgbits.ObjVar:
|
||||
l.relocVarExt(&wext, obj)
|
||||
}
|
||||
wext.flush()
|
||||
wext.Flush()
|
||||
} else {
|
||||
l.relocCommon(pr, &wext, relocObjExt, idx)
|
||||
l.relocCommon(pr, &wext, pkgbits.RelocObjExt, idx)
|
||||
}
|
||||
|
||||
return w.idx
|
||||
return w.Idx
|
||||
}
|
||||
|
||||
func (l *linker) relocCommon(pr *pkgReader, w *encoder, k reloc, idx int) {
|
||||
r := pr.newDecoderRaw(k, idx)
|
||||
w.relocs = l.relocAll(pr, r.relocs)
|
||||
io.Copy(&w.data, &r.data)
|
||||
w.flush()
|
||||
func (l *linker) relocCommon(pr *pkgReader, w *pkgbits.Encoder, k pkgbits.RelocKind, idx int) {
|
||||
r := pr.NewDecoderRaw(k, idx)
|
||||
w.Relocs = l.relocAll(pr, r.Relocs)
|
||||
io.Copy(&w.Data, &r.Data)
|
||||
w.Flush()
|
||||
}
|
||||
|
||||
func (l *linker) pragmaFlag(w *encoder, pragma ir.PragmaFlag) {
|
||||
w.sync(syncPragma)
|
||||
w.int(int(pragma))
|
||||
func (l *linker) pragmaFlag(w *pkgbits.Encoder, pragma ir.PragmaFlag) {
|
||||
w.Sync(pkgbits.SyncPragma)
|
||||
w.Int(int(pragma))
|
||||
}
|
||||
|
||||
func (l *linker) relocFuncExt(w *encoder, name *ir.Name) {
|
||||
w.sync(syncFuncExt)
|
||||
func (l *linker) relocFuncExt(w *pkgbits.Encoder, name *ir.Name) {
|
||||
w.Sync(pkgbits.SyncFuncExt)
|
||||
|
||||
l.pragmaFlag(w, name.Func.Pragma)
|
||||
l.linkname(w, name)
|
||||
|
||||
// Relocated extension data.
|
||||
w.bool(true)
|
||||
w.Bool(true)
|
||||
|
||||
// Record definition ABI so cross-ABI calls can be direct.
|
||||
// This is important for the performance of calling some
|
||||
// common functions implemented in assembly (e.g., bytealg).
|
||||
w.uint64(uint64(name.Func.ABI))
|
||||
w.Uint64(uint64(name.Func.ABI))
|
||||
|
||||
// Escape analysis.
|
||||
for _, fs := range &types.RecvsParams {
|
||||
for _, f := range fs(name.Type()).FieldSlice() {
|
||||
w.string(f.Note)
|
||||
w.String(f.Note)
|
||||
}
|
||||
}
|
||||
|
||||
if inl := name.Func.Inl; w.bool(inl != nil) {
|
||||
w.len(int(inl.Cost))
|
||||
w.bool(inl.CanDelayResults)
|
||||
if inl := name.Func.Inl; w.Bool(inl != nil) {
|
||||
w.Len(int(inl.Cost))
|
||||
w.Bool(inl.CanDelayResults)
|
||||
|
||||
pri, ok := bodyReader[name.Func]
|
||||
assert(ok)
|
||||
w.reloc(relocBody, l.relocIdx(pri.pr, relocBody, pri.idx))
|
||||
w.Reloc(pkgbits.RelocBody, l.relocIdx(pri.pr, pkgbits.RelocBody, pri.idx))
|
||||
}
|
||||
|
||||
w.sync(syncEOF)
|
||||
w.Sync(pkgbits.SyncEOF)
|
||||
}
|
||||
|
||||
func (l *linker) relocTypeExt(w *encoder, name *ir.Name) {
|
||||
w.sync(syncTypeExt)
|
||||
func (l *linker) relocTypeExt(w *pkgbits.Encoder, name *ir.Name) {
|
||||
w.Sync(pkgbits.SyncTypeExt)
|
||||
|
||||
typ := name.Type()
|
||||
|
||||
|
|
@ -242,55 +247,28 @@ func (l *linker) relocTypeExt(w *encoder, name *ir.Name) {
|
|||
}
|
||||
}
|
||||
|
||||
func (l *linker) relocVarExt(w *encoder, name *ir.Name) {
|
||||
w.sync(syncVarExt)
|
||||
func (l *linker) relocVarExt(w *pkgbits.Encoder, name *ir.Name) {
|
||||
w.Sync(pkgbits.SyncVarExt)
|
||||
l.linkname(w, name)
|
||||
}
|
||||
|
||||
func (l *linker) linkname(w *encoder, name *ir.Name) {
|
||||
w.sync(syncLinkname)
|
||||
func (l *linker) linkname(w *pkgbits.Encoder, name *ir.Name) {
|
||||
w.Sync(pkgbits.SyncLinkname)
|
||||
|
||||
linkname := name.Sym().Linkname
|
||||
if !l.lsymIdx(w, linkname, name.Linksym()) {
|
||||
w.string(linkname)
|
||||
w.String(linkname)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *linker) lsymIdx(w *encoder, linkname string, lsym *obj.LSym) bool {
|
||||
func (l *linker) lsymIdx(w *pkgbits.Encoder, linkname string, lsym *obj.LSym) bool {
|
||||
if lsym.PkgIdx > goobj.PkgIdxSelf || (lsym.PkgIdx == goobj.PkgIdxInvalid && !lsym.Indexed()) || linkname != "" {
|
||||
w.int64(-1)
|
||||
w.Int64(-1)
|
||||
return false
|
||||
}
|
||||
|
||||
// For a defined symbol, export its index.
|
||||
// For re-exporting an imported symbol, pass its index through.
|
||||
w.int64(int64(lsym.SymIdx))
|
||||
w.Int64(int64(lsym.SymIdx))
|
||||
return true
|
||||
}
|
||||
|
||||
// @@@ Helpers
|
||||
|
||||
// TODO(mdempsky): These should probably be removed. I think they're a
|
||||
// smell that the export data format is not yet quite right.
|
||||
|
||||
func (pr *pkgDecoder) peekPkgPath(idx int) string {
|
||||
r := pr.newDecoder(relocPkg, idx, syncPkgDef)
|
||||
path := r.string()
|
||||
if path == "" {
|
||||
path = pr.pkgPath
|
||||
}
|
||||
return path
|
||||
}
|
||||
|
||||
func (pr *pkgDecoder) peekObj(idx int) (string, string, codeObj) {
|
||||
r := pr.newDecoder(relocName, idx, syncObject1)
|
||||
r.sync(syncSym)
|
||||
r.sync(syncPkg)
|
||||
path := pr.peekPkgPath(r.reloc(relocPkg))
|
||||
name := r.string()
|
||||
assert(name != "")
|
||||
|
||||
tag := codeObj(r.code(syncCodeObj))
|
||||
|
||||
return path, name, tag
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue