diff --git a/go/gcimporter15/bimport.go b/go/gcimporter15/bimport.go index 0d725f6e..ee96a5aa 100644 --- a/go/gcimporter15/bimport.go +++ b/go/gcimporter15/bimport.go @@ -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{