go/gcimporter15: update gcexporter to match gc export format
Change-Id: Icd84cbef6463ba584a2a29f01b23c7e4542d0101 Reviewed-on: https://go-review.googlesource.com/21618 Reviewed-by: Alan Donovan <adonovan@google.com>
This commit is contained in:
parent
f07cde3d91
commit
83f918d66b
|
@ -24,12 +24,31 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// If debugFormat is set, each integer and string value is preceded by a marker
|
||||||
|
// and position information in the encoding. This mechanism permits an importer
|
||||||
|
// to recognize immediately when it is out of sync. The importer recognizes this
|
||||||
|
// mode automatically (i.e., it can import export data produced with debugging
|
||||||
|
// support even if debugFormat is not set at the time of import). This mode will
|
||||||
|
// lead to massively larger export data (by a factor of 2 to 3) and should only
|
||||||
|
// be enabled during development and debugging.
|
||||||
|
//
|
||||||
|
// NOTE: This flag is the first flag to enable if importing dies because of
|
||||||
|
// (suspected) format errors, and whenever a change is made to the format.
|
||||||
|
const debugFormat = false // default: false
|
||||||
|
|
||||||
|
// If trace is set, debugging output is printed to std out.
|
||||||
|
const trace = false // default: false
|
||||||
|
|
||||||
const exportVersion = "v0"
|
const exportVersion = "v0"
|
||||||
|
|
||||||
const (
|
type exporter struct {
|
||||||
debugFormat = false // use debugging format for export data (emits a lot of additional data)
|
out bytes.Buffer
|
||||||
trace = false
|
pkgIndex map[*types.Package]int
|
||||||
)
|
typIndex map[types.Type]int
|
||||||
|
|
||||||
|
written int // bytes written
|
||||||
|
indent int // for trace
|
||||||
|
}
|
||||||
|
|
||||||
// BExportData returns binary export data for pkg.
|
// BExportData returns binary export data for pkg.
|
||||||
func BExportData(pkg *types.Package) []byte {
|
func BExportData(pkg *types.Package) []byte {
|
||||||
|
@ -38,7 +57,7 @@ func BExportData(pkg *types.Package) []byte {
|
||||||
typIndex: make(map[types.Type]int),
|
typIndex: make(map[types.Type]int),
|
||||||
}
|
}
|
||||||
|
|
||||||
// write low-level encoding format
|
// first byte indicates low-level encoding format
|
||||||
var format byte = 'c' // compact
|
var format byte = 'c' // compact
|
||||||
if debugFormat {
|
if debugFormat {
|
||||||
format = 'd'
|
format = 'd'
|
||||||
|
@ -50,10 +69,13 @@ func BExportData(pkg *types.Package) []byte {
|
||||||
if trace {
|
if trace {
|
||||||
p.tracef("\n--- generic export data ---\n")
|
p.tracef("\n--- generic export data ---\n")
|
||||||
if p.indent != 0 {
|
if p.indent != 0 {
|
||||||
log.Fatalf("incorrect indentation %d", p.indent)
|
log.Fatalf("gcimporter: incorrect indentation %d", p.indent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if trace {
|
||||||
|
p.tracef("version = ")
|
||||||
|
}
|
||||||
p.string(exportVersion)
|
p.string(exportVersion)
|
||||||
if trace {
|
if trace {
|
||||||
p.tracef("\n")
|
p.tracef("\n")
|
||||||
|
@ -64,97 +86,41 @@ func BExportData(pkg *types.Package) []byte {
|
||||||
p.typIndex[typ] = index
|
p.typIndex[typ] = index
|
||||||
}
|
}
|
||||||
if len(p.typIndex) != len(predeclared) {
|
if len(p.typIndex) != len(predeclared) {
|
||||||
log.Fatalf("duplicate entries in type map?")
|
log.Fatalf("gcimporter: duplicate entries in type map?")
|
||||||
}
|
}
|
||||||
|
|
||||||
// write package data
|
// write package data
|
||||||
p.pkg(pkg, true)
|
p.pkg(pkg, true)
|
||||||
|
|
||||||
// write compiler-specific flags
|
// write compiler-specific flags
|
||||||
p.string("")
|
p.string("") // no flags to write in our case
|
||||||
|
|
||||||
if trace {
|
if trace {
|
||||||
p.tracef("\n")
|
p.tracef("\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Collect objects to export, already sorted by name.
|
// write objects
|
||||||
var consts []*types.Const
|
objcount := 0
|
||||||
var vars []*types.Var
|
|
||||||
var funcs []*types.Func
|
|
||||||
var typs []*types.TypeName
|
|
||||||
scope := pkg.Scope()
|
scope := pkg.Scope()
|
||||||
for _, name := range scope.Names() {
|
for _, name := range scope.Names() {
|
||||||
if !ast.IsExported(name) {
|
if !ast.IsExported(name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch obj := scope.Lookup(name).(type) {
|
|
||||||
case *types.Const:
|
|
||||||
consts = append(consts, obj)
|
|
||||||
case *types.Var:
|
|
||||||
vars = append(vars, obj)
|
|
||||||
case *types.Func:
|
|
||||||
funcs = append(funcs, obj)
|
|
||||||
case *types.TypeName:
|
|
||||||
typs = append(typs, obj)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// write consts
|
|
||||||
p.int(len(consts))
|
|
||||||
for _, obj := range consts {
|
|
||||||
p.string(obj.Name())
|
|
||||||
p.typ(obj.Type())
|
|
||||||
p.value(obj.Val())
|
|
||||||
}
|
|
||||||
|
|
||||||
// write vars
|
|
||||||
p.int(len(vars))
|
|
||||||
for _, obj := range vars {
|
|
||||||
p.string(obj.Name())
|
|
||||||
p.typ(obj.Type())
|
|
||||||
}
|
|
||||||
|
|
||||||
// write funcs
|
|
||||||
p.int(len(funcs))
|
|
||||||
for _, obj := range funcs {
|
|
||||||
p.string(obj.Name())
|
|
||||||
sig := obj.Type().(*types.Signature)
|
|
||||||
p.paramList(sig.Params(), sig.Variadic())
|
|
||||||
p.paramList(sig.Results(), false)
|
|
||||||
p.int(-1) // no inlined function bodies
|
|
||||||
}
|
|
||||||
|
|
||||||
// Determine which types are still left to write.
|
|
||||||
i := 0
|
|
||||||
for _, t := range typs {
|
|
||||||
if _, ok := p.typIndex[t.Type()]; !ok {
|
|
||||||
typs[i] = t
|
|
||||||
i++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
typs = typs[:i]
|
|
||||||
|
|
||||||
// Write types.
|
|
||||||
p.int(len(typs))
|
|
||||||
for _, t := range typs {
|
|
||||||
// Writing a type may further reduce the number of types
|
|
||||||
// that are left to be written, but at this point we don't
|
|
||||||
// care.
|
|
||||||
p.typ(t.Type())
|
|
||||||
}
|
|
||||||
|
|
||||||
if trace {
|
if trace {
|
||||||
p.tracef("\n")
|
p.tracef("\n")
|
||||||
}
|
}
|
||||||
|
p.obj(scope.Lookup(name))
|
||||||
|
objcount++
|
||||||
|
}
|
||||||
|
|
||||||
// --- compiler-specific export data ---
|
// indicate end of list
|
||||||
|
|
||||||
if trace {
|
if trace {
|
||||||
p.tracef("\n--- compiler specific export data ---\n")
|
p.tracef("\n")
|
||||||
if p.indent != 0 {
|
|
||||||
log.Fatalf("incorrect indentation")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
p.tag(endTag)
|
||||||
|
|
||||||
|
// for self-verification only (redundant)
|
||||||
|
p.int(objcount)
|
||||||
|
|
||||||
if trace {
|
if trace {
|
||||||
p.tracef("\n")
|
p.tracef("\n")
|
||||||
|
@ -165,19 +131,9 @@ func BExportData(pkg *types.Package) []byte {
|
||||||
return p.out.Bytes()
|
return p.out.Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
type exporter struct {
|
|
||||||
out bytes.Buffer
|
|
||||||
pkgIndex map[*types.Package]int
|
|
||||||
typIndex map[types.Type]int
|
|
||||||
|
|
||||||
written int // bytes written
|
|
||||||
indent int // for trace
|
|
||||||
trace bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *exporter) pkg(pkg *types.Package, emptypath bool) {
|
func (p *exporter) pkg(pkg *types.Package, emptypath bool) {
|
||||||
if pkg == nil {
|
if pkg == nil {
|
||||||
log.Fatalf("unexpected nil pkg")
|
log.Fatalf("gcimporter: unexpected nil pkg")
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we saw the package before, write its index (>= 0)
|
// if we saw the package before, write its index (>= 0)
|
||||||
|
@ -202,9 +158,44 @@ func (p *exporter) pkg(pkg *types.Package, emptypath bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *exporter) obj(obj types.Object) {
|
||||||
|
switch obj := obj.(type) {
|
||||||
|
case *types.Const:
|
||||||
|
p.tag(constTag)
|
||||||
|
p.qualifiedName(obj)
|
||||||
|
p.typ(obj.Type())
|
||||||
|
p.value(obj.Val())
|
||||||
|
|
||||||
|
case *types.TypeName:
|
||||||
|
p.tag(typeTag)
|
||||||
|
p.typ(obj.Type())
|
||||||
|
|
||||||
|
case *types.Var:
|
||||||
|
p.tag(varTag)
|
||||||
|
p.qualifiedName(obj)
|
||||||
|
p.typ(obj.Type())
|
||||||
|
|
||||||
|
case *types.Func:
|
||||||
|
p.tag(funcTag)
|
||||||
|
p.qualifiedName(obj)
|
||||||
|
sig := obj.Type().(*types.Signature)
|
||||||
|
p.paramList(sig.Params(), sig.Variadic())
|
||||||
|
p.paramList(sig.Results(), false)
|
||||||
|
p.int(-1) // no inlined function bodies
|
||||||
|
|
||||||
|
default:
|
||||||
|
log.Fatalf("gcimporter: unexpected object %v (%T)", obj, obj)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *exporter) qualifiedName(obj types.Object) {
|
||||||
|
p.string(obj.Name())
|
||||||
|
p.pkg(obj.Pkg(), false)
|
||||||
|
}
|
||||||
|
|
||||||
func (p *exporter) typ(t types.Type) {
|
func (p *exporter) typ(t types.Type) {
|
||||||
if t == nil {
|
if t == nil {
|
||||||
log.Fatalf("nil type")
|
log.Fatalf("gcimporter: nil type")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Possible optimization: Anonymous pointer types *T where
|
// Possible optimization: Anonymous pointer types *T where
|
||||||
|
@ -236,7 +227,7 @@ func (p *exporter) typ(t types.Type) {
|
||||||
p.qualifiedName(t.Obj())
|
p.qualifiedName(t.Obj())
|
||||||
p.typ(t.Underlying())
|
p.typ(t.Underlying())
|
||||||
if !types.IsInterface(t) {
|
if !types.IsInterface(t) {
|
||||||
p.declaredMethods(t)
|
p.assocMethods(t)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *types.Array:
|
case *types.Array:
|
||||||
|
@ -280,13 +271,11 @@ func (p *exporter) typ(t types.Type) {
|
||||||
p.typ(t.Elem())
|
p.typ(t.Elem())
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Fatalf("unexpected type %T: %s", t, t)
|
log.Fatalf("gcimporter: unexpected type %T: %s", t, t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *exporter) declaredMethods(named *types.Named) {
|
func (p *exporter) assocMethods(named *types.Named) {
|
||||||
p.int(named.NumMethods())
|
|
||||||
|
|
||||||
// Sort methods (for determinism).
|
// Sort methods (for determinism).
|
||||||
var methods []*types.Func
|
var methods []*types.Func
|
||||||
for i := 0; i < named.NumMethods(); i++ {
|
for i := 0; i < named.NumMethods(); i++ {
|
||||||
|
@ -294,6 +283,8 @@ func (p *exporter) declaredMethods(named *types.Named) {
|
||||||
}
|
}
|
||||||
sort.Sort(methodsByName(methods))
|
sort.Sort(methodsByName(methods))
|
||||||
|
|
||||||
|
p.int(len(methods))
|
||||||
|
|
||||||
if trace && methods != nil {
|
if trace && methods != nil {
|
||||||
p.tracef("associated methods {>\n")
|
p.tracef("associated methods {>\n")
|
||||||
}
|
}
|
||||||
|
@ -302,9 +293,15 @@ func (p *exporter) declaredMethods(named *types.Named) {
|
||||||
if trace && i > 0 {
|
if trace && i > 0 {
|
||||||
p.tracef("\n")
|
p.tracef("\n")
|
||||||
}
|
}
|
||||||
p.string(m.Name())
|
|
||||||
|
name := m.Name()
|
||||||
|
p.string(name)
|
||||||
|
if !exported(name) {
|
||||||
|
p.pkg(m.Pkg(), false)
|
||||||
|
}
|
||||||
|
|
||||||
sig := m.Type().(*types.Signature)
|
sig := m.Type().(*types.Signature)
|
||||||
p.recv(sig.Recv())
|
p.paramList(types.NewTuple(sig.Recv()), false)
|
||||||
p.paramList(sig.Params(), sig.Variadic())
|
p.paramList(sig.Params(), sig.Variadic())
|
||||||
p.paramList(sig.Results(), false)
|
p.paramList(sig.Results(), false)
|
||||||
p.int(-1) // no inlining
|
p.int(-1) // no inlining
|
||||||
|
@ -321,24 +318,6 @@ func (x methodsByName) Len() int { return len(x) }
|
||||||
func (x methodsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
func (x methodsByName) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
|
||||||
func (x methodsByName) Less(i, j int) bool { return x[i].Name() < x[j].Name() }
|
func (x methodsByName) Less(i, j int) bool { return x[i].Name() < x[j].Name() }
|
||||||
|
|
||||||
func (p *exporter) recv(recv *types.Var) {
|
|
||||||
// Use negative length to indicate unnamed parameter.
|
|
||||||
if recv.Name() == "" {
|
|
||||||
p.int(-1)
|
|
||||||
p.typ(recv.Type())
|
|
||||||
} else {
|
|
||||||
p.int(1)
|
|
||||||
p.typ(recv.Type())
|
|
||||||
p.string(recv.Name())
|
|
||||||
}
|
|
||||||
p.string("")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *exporter) qualifiedName(obj types.Object) {
|
|
||||||
p.string(obj.Name())
|
|
||||||
p.pkg(obj.Pkg(), false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *exporter) fieldList(t *types.Struct) {
|
func (p *exporter) fieldList(t *types.Struct) {
|
||||||
if trace && t.NumFields() > 0 {
|
if trace && t.NumFields() > 0 {
|
||||||
p.tracef("fields {>\n")
|
p.tracef("fields {>\n")
|
||||||
|
@ -357,7 +336,7 @@ func (p *exporter) fieldList(t *types.Struct) {
|
||||||
|
|
||||||
func (p *exporter) field(f *types.Var) {
|
func (p *exporter) field(f *types.Var) {
|
||||||
if !f.IsField() {
|
if !f.IsField() {
|
||||||
log.Fatalf("field expected")
|
log.Fatalf("gcimporter: field expected")
|
||||||
}
|
}
|
||||||
|
|
||||||
p.fieldName(f)
|
p.fieldName(f)
|
||||||
|
@ -386,7 +365,7 @@ func (p *exporter) iface(t *types.Interface) {
|
||||||
func (p *exporter) method(m *types.Func) {
|
func (p *exporter) method(m *types.Func) {
|
||||||
sig := m.Type().(*types.Signature)
|
sig := m.Type().(*types.Signature)
|
||||||
if sig.Recv() == nil {
|
if sig.Recv() == nil {
|
||||||
log.Fatalf("method expected")
|
log.Fatalf("gcimporter: method expected")
|
||||||
}
|
}
|
||||||
|
|
||||||
p.string(m.Name())
|
p.string(m.Name())
|
||||||
|
@ -440,8 +419,9 @@ func (p *exporter) paramList(params *types.Tuple, variadic bool) {
|
||||||
p.typ(t)
|
p.typ(t)
|
||||||
if n > 0 {
|
if n > 0 {
|
||||||
p.string(q.Name())
|
p.string(q.Name())
|
||||||
|
p.pkg(q.Pkg(), false)
|
||||||
}
|
}
|
||||||
p.string("")
|
p.string("") // no compiler-specific info
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,17 +464,17 @@ func (p *exporter) value(x constant.Value) {
|
||||||
p.string(constant.StringVal(x))
|
p.string(constant.StringVal(x))
|
||||||
|
|
||||||
case constant.Unknown:
|
case constant.Unknown:
|
||||||
// (Package contains type errors.)
|
// package contains type errors
|
||||||
p.tag(unknownTag)
|
p.tag(unknownTag)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Fatalf("unexpected value %v (%T)", x, x)
|
log.Fatalf("gcimporter: unexpected value %v (%T)", x, x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *exporter) float(x constant.Value) {
|
func (p *exporter) float(x constant.Value) {
|
||||||
if x.Kind() != constant.Float {
|
if x.Kind() != constant.Float {
|
||||||
log.Fatalf("unexpected constant %v, want float", x)
|
log.Fatalf("gcimporter: unexpected constant %v, want float", x)
|
||||||
}
|
}
|
||||||
// extract sign (there is no -0)
|
// extract sign (there is no -0)
|
||||||
sign := constant.Sign(x)
|
sign := constant.Sign(x)
|
||||||
|
@ -529,7 +509,7 @@ func (p *exporter) float(x constant.Value) {
|
||||||
m.SetMantExp(&m, int(m.MinPrec()))
|
m.SetMantExp(&m, int(m.MinPrec()))
|
||||||
mant, acc := m.Int(nil)
|
mant, acc := m.Int(nil)
|
||||||
if acc != big.Exact {
|
if acc != big.Exact {
|
||||||
log.Fatalf("internal error")
|
log.Fatalf("gcimporter: internal error")
|
||||||
}
|
}
|
||||||
|
|
||||||
p.int(sign)
|
p.int(sign)
|
||||||
|
@ -552,7 +532,7 @@ func valueToRat(x constant.Value) *big.Rat {
|
||||||
|
|
||||||
func (p *exporter) index(marker byte, index int) {
|
func (p *exporter) index(marker byte, index int) {
|
||||||
if index < 0 {
|
if index < 0 {
|
||||||
log.Fatalf("invalid index < 0")
|
log.Fatalf("gcimporter: invalid index < 0")
|
||||||
}
|
}
|
||||||
if debugFormat {
|
if debugFormat {
|
||||||
p.marker('t')
|
p.marker('t')
|
||||||
|
@ -565,7 +545,7 @@ func (p *exporter) index(marker byte, index int) {
|
||||||
|
|
||||||
func (p *exporter) tag(tag int) {
|
func (p *exporter) tag(tag int) {
|
||||||
if tag >= 0 {
|
if tag >= 0 {
|
||||||
log.Fatalf("invalid tag >= 0")
|
log.Fatalf("gcimporter: invalid tag >= 0")
|
||||||
}
|
}
|
||||||
if debugFormat {
|
if debugFormat {
|
||||||
p.marker('t')
|
p.marker('t')
|
||||||
|
@ -608,6 +588,11 @@ func (p *exporter) string(s string) {
|
||||||
// debugFormat format only.
|
// debugFormat format only.
|
||||||
func (p *exporter) marker(m byte) {
|
func (p *exporter) marker(m byte) {
|
||||||
p.byte(m)
|
p.byte(m)
|
||||||
|
// Enable this for help tracking down the location
|
||||||
|
// of an incorrect marker when running in debugFormat.
|
||||||
|
if false && trace {
|
||||||
|
p.tracef("#%d ", p.written)
|
||||||
|
}
|
||||||
p.rawInt64(int64(p.written))
|
p.rawInt64(int64(p.written))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -504,6 +504,8 @@ func (p *importer) value() constant.Value {
|
||||||
return constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
|
return constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
|
||||||
case stringTag:
|
case stringTag:
|
||||||
return constant.MakeString(p.string())
|
return constant.MakeString(p.string())
|
||||||
|
case unknownTag:
|
||||||
|
return constant.MakeUnknown()
|
||||||
default:
|
default:
|
||||||
panic(fmt.Sprintf("unexpected value tag %d", tag))
|
panic(fmt.Sprintf("unexpected value tag %d", tag))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue