gco/gcimporter15: update importer to match new gc binary export format

This is simply a copy of std lib's go/internal/gcimporter/bimport.go
with updated header comment and build tag. No semantic changes.

This will fix part of the x/tools build break at tip. The other part
is to adjust bexport.go (next CL).

Change-Id: Ibc37fae7e0d0447fdea9e3a733aa38589735c59a
Reviewed-on: https://go-review.googlesource.com/21543
Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
Robert Griesemer 2016-04-05 12:49:32 -07:00
parent 02e8ee6893
commit 44f369b779
1 changed files with 90 additions and 55 deletions

View File

@ -19,6 +19,18 @@ import (
"unicode/utf8"
)
type importer struct {
imports map[string]*types.Package
data []byte
buf []byte // for reading strings
bufarray [64]byte // initial underlying array for buf, large enough to avoid allocation when compiling std lib
pkgList []*types.Package
typList []types.Type
debugFormat bool
read int // bytes read
}
// BImportData imports a package from the serialized package data
// and returns the number of bytes consumed and a reference to the package.
// If data is obviously malformed, an error is returned but in
@ -43,7 +55,7 @@ func BImportData(imports map[string]*types.Package, data []byte, path string) (i
// --- generic export data ---
if v := p.string(); v != "v0" {
return p.read, nil, fmt.Errorf("unknown version: %s", v)
return p.read, nil, fmt.Errorf("unknown export data version: %s", v)
}
// populate typList with predeclared "known" types
@ -73,37 +85,20 @@ func BImportData(imports map[string]*types.Package, data []byte, path string) (i
// read compiler-specific flags
p.string() // discard
// read consts
for i := p.int(); i > 0; i-- {
name := p.string()
typ := p.typ(nil)
val := p.value()
p.declare(types.NewConst(token.NoPos, pkg, name, typ, val))
// read objects of phase 1 only (see cmd/compiler/internal/gc/bexport.go)
objcount := 0
for {
tag := p.tagOrIndex()
if tag == endTag {
break
}
p.obj(tag)
objcount++
}
// read vars
for i := p.int(); i > 0; i-- {
name := p.string()
typ := p.typ(nil)
p.declare(types.NewVar(token.NoPos, pkg, name, typ))
}
// read funcs
for i := p.int(); i > 0; i-- {
name := p.string()
params, isddd := p.paramList()
result, _ := p.paramList()
sig := types.NewSignature(nil, params, result, isddd)
p.int() // read and discard index of inlined function body
p.declare(types.NewFunc(token.NoPos, pkg, name, sig))
}
// read types
for i := p.int(); i > 0; i-- {
// name is parsed as part of named type and the
// type object is added to scope via respective
// named type
_ = p.typ(nil).(*types.Named)
// self-verification
if count := p.int(); count != objcount {
panic(fmt.Sprintf("importer: got %d objects; want %d", objcount, count))
}
// ignore compiler-specific import data
@ -126,25 +121,6 @@ func BImportData(imports map[string]*types.Package, data []byte, path string) (i
return p.read, pkg, nil
}
type importer struct {
imports map[string]*types.Package
data []byte
buf []byte // for reading strings
bufarray [64]byte // initial underlying array for buf, large enough to avoid allocation when compiling std lib
pkgList []*types.Package
typList []types.Type
debugFormat bool
read int // bytes read
}
func (p *importer) declare(obj types.Object) {
if alt := p.pkgList[0].Scope().Insert(obj); alt != nil {
// This can only happen if we import a package a second time.
panic(fmt.Sprintf("%s already declared", alt.Name()))
}
}
func (p *importer) pkg() *types.Package {
// if the package was seen before, i is its index (>= 0)
i := p.tagOrIndex()
@ -182,6 +158,55 @@ func (p *importer) pkg() *types.Package {
return pkg
}
func (p *importer) declare(obj types.Object) {
pkg := obj.Pkg()
if alt := pkg.Scope().Insert(obj); alt != nil {
// This could only trigger if we import a (non-type) object a second time.
// This should never happen because 1) we only import a package once; and
// b) we ignore compiler-specific export data which may contain functions
// whose inlined function bodies refer to other functions that were already
// imported.
// (See also the comment in cmd/compile/internal/gc/bimport.go importer.obj,
// switch case importing functions).
panic(fmt.Sprintf("%s already declared", alt.Name()))
}
}
func (p *importer) obj(tag int) {
switch tag {
case constTag:
pkg, name := p.qualifiedName()
typ := p.typ(nil)
val := p.value()
p.declare(types.NewConst(token.NoPos, pkg, name, typ, val))
case typeTag:
_ = p.typ(nil)
case varTag:
pkg, name := p.qualifiedName()
typ := p.typ(nil)
p.declare(types.NewVar(token.NoPos, pkg, name, typ))
case funcTag:
pkg, name := p.qualifiedName()
params, isddd := p.paramList()
result, _ := p.paramList()
sig := types.NewSignature(nil, params, result, isddd)
p.int() // read and discard index of inlined function body
p.declare(types.NewFunc(token.NoPos, pkg, name, sig))
default:
panic("unexpected object tag")
}
}
func (p *importer) qualifiedName() (pkg *types.Package, name string) {
name = p.string()
pkg = p.pkg()
return
}
func (p *importer) record(t types.Type) {
p.typList = append(p.typList, t)
}
@ -243,11 +268,17 @@ func (p *importer) typ(parent *types.Package) types.Type {
// read associated methods
for i := p.int(); i > 0; i-- {
// TODO(gri) replace this with something closer to fieldName
name := p.string()
if !exported(name) {
p.pkg()
}
recv, _ := p.paramList() // TODO(gri) do we need a full param list for the receiver?
params, isddd := p.paramList()
result, _ := p.paramList()
p.int() // read and discard index of inlined function body
sig := types.NewSignature(recv.At(0), params, result, isddd)
t0.AddMethod(types.NewFunc(token.NoPos, parent, name, sig))
}
@ -436,18 +467,20 @@ func (p *importer) param(named bool) (*types.Var, bool) {
t = types.NewSlice(td.elem)
}
var pkg *types.Package
var name string
if named {
name = p.string()
if name == "" {
panic("expected named parameter")
}
pkg = p.pkg()
}
// read and discard compiler-specific info
p.string()
return types.NewVar(token.NoPos, nil, name, t), isddd
return types.NewVar(token.NoPos, pkg, name, t), isddd
}
func exported(name string) bool {
@ -471,9 +504,6 @@ func (p *importer) value() constant.Value {
return constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
case stringTag:
return constant.MakeString(p.string())
case unknownTag:
// (Encoded package contains type errors.)
return constant.MakeUnknown()
default:
panic(fmt.Sprintf("unexpected value tag %d", tag))
}
@ -624,8 +654,13 @@ func (p *importer) byte() byte {
// Tags. Must be < 0.
const (
// Packages
// Objects
packageTag = -(iota + 1)
constTag
typeTag
varTag
funcTag
endTag
// Types
namedTag
@ -647,7 +682,7 @@ const (
fractionTag // not used by gc
complexTag
stringTag
unknownTag // only appears in packages with errors
unknownTag // not used by gc (only appears in packages with errors)
)
var predeclared = []types.Type{