github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/cmd/compile/internal/gc/bimport.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Binary package import. 6 // Based loosely on x/tools/go/importer. 7 8 package gc 9 10 import ( 11 "cmd/compile/internal/big" 12 "cmd/internal/obj" 13 "encoding/binary" 14 ) 15 16 // The overall structure of Import is symmetric to Export: For each 17 // export method in bexport.go there is a matching and symmetric method 18 // in bimport.go. Changing the export format requires making symmetric 19 // changes to bimport.go and bexport.go. 20 21 // Import populates importpkg from the serialized package data. 22 func Import(in *obj.Biobuf) { 23 p := importer{in: in} 24 p.buf = p.bufarray[:] 25 26 // read low-level encoding format 27 switch format := p.byte(); format { 28 case 'c': 29 // compact format - nothing to do 30 case 'd': 31 p.debugFormat = true 32 default: 33 Fatalf("invalid encoding format in export data: got %q; want 'c' or 'd'", format) 34 } 35 36 // --- generic export data --- 37 38 if v := p.string(); v != exportVersion { 39 Fatalf("unknown export data version: %s", v) 40 } 41 42 // populate typList with predeclared "known" types 43 p.typList = append(p.typList, predeclared()...) 44 45 // read package data 46 p.pkg() 47 if p.pkgList[0] != importpkg { 48 Fatalf("imported package not found in pkgList[0]") 49 } 50 51 // read compiler-specific flags 52 importpkg.Safe = p.string() == "safe" 53 54 // defer some type-checking until all types are read in completely 55 // (go.y:import_there) 56 tcok := typecheckok 57 typecheckok = true 58 defercheckwidth() 59 60 // read consts 61 for i := p.int(); i > 0; i-- { 62 sym := p.localname() 63 typ := p.typ() 64 val := p.value(typ) 65 if isideal(typ) { 66 // canonicalize ideal types 67 typ = Types[TIDEAL] 68 } 69 importconst(sym, typ, nodlit(val)) 70 } 71 72 // read vars 73 for i := p.int(); i > 0; i-- { 74 sym := p.localname() 75 typ := p.typ() 76 importvar(sym, typ) 77 } 78 79 // read funcs 80 for i := p.int(); i > 0; i-- { 81 // go.y:hidden_fndcl 82 sym := p.localname() 83 typ := p.typ() 84 // TODO(gri) fix this 85 p.int() // read and discard index of inlined function body for now 86 87 importsym(sym, ONAME) 88 if sym.Def != nil && sym.Def.Op == ONAME && !Eqtype(typ, sym.Def.Type) { 89 Fatalf("inconsistent definition for func %v during import\n\t%v\n\t%v", sym, sym.Def.Type, typ) 90 } 91 92 n := newfuncname(sym) 93 n.Type = typ 94 declare(n, PFUNC) 95 funchdr(n) 96 97 // go.y:hidden_import 98 n.Func.Inl = nil 99 funcbody(n) 100 importlist = append(importlist, n) // TODO(gri) do this only if body is inlineable? 101 } 102 103 // read types 104 for i := p.int(); i > 0; i-- { 105 // name is parsed as part of named type 106 p.typ() 107 } 108 109 // --- compiler-specific export data --- 110 111 for i := p.int(); i > 0; i-- { 112 p.body() 113 } 114 115 // --- end of export data --- 116 117 typecheckok = tcok 118 resumecheckwidth() 119 120 testdclstack() // debugging only 121 } 122 123 type importer struct { 124 in *obj.Biobuf 125 buf []byte // for reading strings 126 bufarray [64]byte // initial underlying array for buf, large enough to avoid allocation when compiling std lib 127 pkgList []*Pkg 128 typList []*Type 129 130 debugFormat bool 131 read int // bytes read 132 } 133 134 func (p *importer) pkg() *Pkg { 135 // if the package was seen before, i is its index (>= 0) 136 i := p.tagOrIndex() 137 if i >= 0 { 138 return p.pkgList[i] 139 } 140 141 // otherwise, i is the package tag (< 0) 142 if i != packageTag { 143 Fatalf("expected package tag, found tag = %d", i) 144 } 145 146 // read package data 147 name := p.string() 148 path := p.string() 149 150 // we should never see an empty package name 151 if name == "" { 152 Fatalf("empty package name in import") 153 } 154 155 // we should never see a bad import path 156 if isbadimport(path) { 157 Fatalf("bad path in import: %q", path) 158 } 159 160 // an empty path denotes the package we are currently importing 161 pkg := importpkg 162 if path != "" { 163 pkg = mkpkg(path) 164 } 165 if pkg.Name == "" { 166 pkg.Name = name 167 } else if pkg.Name != name { 168 Fatalf("inconsistent package names: got %s; want %s (path = %s)", pkg.Name, name, path) 169 } 170 p.pkgList = append(p.pkgList, pkg) 171 172 return pkg 173 } 174 175 func (p *importer) localname() *Sym { 176 // go.y:hidden_importsym 177 name := p.string() 178 if name == "" { 179 Fatalf("unexpected anonymous name") 180 } 181 structpkg = importpkg // go.y:hidden_pkg_importsym 182 return importpkg.Lookup(name) 183 } 184 185 func (p *importer) newtyp(etype EType) *Type { 186 t := typ(etype) 187 p.typList = append(p.typList, t) 188 return t 189 } 190 191 func (p *importer) typ() *Type { 192 // if the type was seen before, i is its index (>= 0) 193 i := p.tagOrIndex() 194 if i >= 0 { 195 return p.typList[i] 196 } 197 198 // otherwise, i is the type tag (< 0) 199 var t *Type 200 switch i { 201 case namedTag: 202 // go.y:hidden_importsym 203 tsym := p.qualifiedName() 204 205 // go.y:hidden_pkgtype 206 t = pkgtype(tsym) 207 importsym(tsym, OTYPE) 208 p.typList = append(p.typList, t) 209 210 // read underlying type 211 // go.y:hidden_type 212 t0 := p.typ() 213 importtype(t, t0) // go.y:hidden_import 214 215 // interfaces don't have associated methods 216 if t0.Etype == TINTER { 217 break 218 } 219 220 // read associated methods 221 for i := p.int(); i > 0; i-- { 222 // go.y:hidden_fndcl 223 name := p.string() 224 recv := p.paramList() // TODO(gri) do we need a full param list for the receiver? 225 params := p.paramList() 226 result := p.paramList() 227 // TODO(gri) fix this 228 p.int() // read and discard index of inlined function body for now 229 230 pkg := localpkg 231 if !exportname(name) { 232 pkg = tsym.Pkg 233 } 234 sym := pkg.Lookup(name) 235 236 n := methodname1(newname(sym), recv.N.Right) 237 n.Type = functype(recv.N, params, result) 238 checkwidth(n.Type) 239 // addmethod uses the global variable structpkg to verify consistency 240 { 241 saved := structpkg 242 structpkg = tsym.Pkg 243 addmethod(sym, n.Type, false, nointerface) 244 structpkg = saved 245 } 246 nointerface = false 247 funchdr(n) 248 249 // (comment from go.y) 250 // inl.C's inlnode in on a dotmeth node expects to find the inlineable body as 251 // (dotmeth's type).Nname.Inl, and dotmeth's type has been pulled 252 // out by typecheck's lookdot as this $$.ttype. So by providing 253 // this back link here we avoid special casing there. 254 n.Type.Nname = n 255 256 // go.y:hidden_import 257 n.Func.Inl = nil 258 funcbody(n) 259 importlist = append(importlist, n) // TODO(gri) do this only if body is inlineable? 260 } 261 262 case arrayTag, sliceTag: 263 t = p.newtyp(TARRAY) 264 t.Bound = -1 265 if i == arrayTag { 266 t.Bound = p.int64() 267 } 268 t.Type = p.typ() 269 270 case dddTag: 271 t = p.newtyp(T_old_DARRAY) 272 t.Bound = -1 273 t.Type = p.typ() 274 275 case structTag: 276 t = p.newtyp(TSTRUCT) 277 tostruct0(t, p.fieldList()) 278 279 case pointerTag: 280 t = p.newtyp(Tptr) 281 t.Type = p.typ() 282 283 case signatureTag: 284 t = p.newtyp(TFUNC) 285 params := p.paramList() 286 result := p.paramList() 287 functype0(t, nil, params, result) 288 289 case interfaceTag: 290 t = p.newtyp(TINTER) 291 if p.int() != 0 { 292 Fatalf("unexpected embedded interface") 293 } 294 tointerface0(t, p.methodList()) 295 296 case mapTag: 297 t = p.newtyp(TMAP) 298 t.Down = p.typ() // key 299 t.Type = p.typ() // val 300 301 case chanTag: 302 t = p.newtyp(TCHAN) 303 t.Chan = uint8(p.int()) 304 t.Type = p.typ() 305 306 default: 307 Fatalf("unexpected type (tag = %d)", i) 308 } 309 310 if t == nil { 311 Fatalf("nil type (type tag = %d)", i) 312 } 313 314 return t 315 } 316 317 func (p *importer) qualifiedName() *Sym { 318 name := p.string() 319 pkg := p.pkg() 320 return pkg.Lookup(name) 321 } 322 323 // go.y:hidden_structdcl_list 324 func (p *importer) fieldList() *NodeList { 325 i := p.int() 326 if i == 0 { 327 return nil 328 } 329 n := list1(p.field()) 330 for i--; i > 0; i-- { 331 n = list(n, p.field()) 332 } 333 return n 334 } 335 336 // go.y:hidden_structdcl 337 func (p *importer) field() *Node { 338 sym := p.fieldName() 339 typ := p.typ() 340 note := p.note() 341 342 var n *Node 343 if sym.Name != "" { 344 n = Nod(ODCLFIELD, newname(sym), typenod(typ)) 345 } else { 346 // anonymous field - typ must be T or *T and T must be a type name 347 s := typ.Sym 348 if s == nil && Isptr[typ.Etype] { 349 s = typ.Type.Sym // deref 350 } 351 pkg := importpkg 352 if sym != nil { 353 pkg = sym.Pkg 354 } 355 n = embedded(s, pkg) 356 n.Right = typenod(typ) 357 } 358 n.SetVal(note) 359 360 return n 361 } 362 363 func (p *importer) note() (v Val) { 364 if s := p.string(); s != "" { 365 v.U = s 366 } 367 return 368 } 369 370 // go.y:hidden_interfacedcl_list 371 func (p *importer) methodList() *NodeList { 372 i := p.int() 373 if i == 0 { 374 return nil 375 } 376 n := list1(p.method()) 377 for i--; i > 0; i-- { 378 n = list(n, p.method()) 379 } 380 return n 381 } 382 383 // go.y:hidden_interfacedcl 384 func (p *importer) method() *Node { 385 sym := p.fieldName() 386 params := p.paramList() 387 result := p.paramList() 388 return Nod(ODCLFIELD, newname(sym), typenod(functype(fakethis(), params, result))) 389 } 390 391 // go.y:sym,hidden_importsym 392 func (p *importer) fieldName() *Sym { 393 name := p.string() 394 pkg := localpkg 395 if name == "_" { 396 // During imports, unqualified non-exported identifiers are from builtinpkg 397 // (see go.y:sym). The binary exporter only exports blank as a non-exported 398 // identifier without qualification. 399 pkg = builtinpkg 400 } else if name == "?" || name != "" && !exportname(name) { 401 if name == "?" { 402 name = "" 403 } 404 pkg = p.pkg() 405 } 406 return pkg.Lookup(name) 407 } 408 409 // go.y:ohidden_funarg_list 410 func (p *importer) paramList() *NodeList { 411 i := p.int() 412 if i == 0 { 413 return nil 414 } 415 // negative length indicates unnamed parameters 416 named := true 417 if i < 0 { 418 i = -i 419 named = false 420 } 421 // i > 0 422 n := list1(p.param(named)) 423 i-- 424 for ; i > 0; i-- { 425 n = list(n, p.param(named)) 426 } 427 return n 428 } 429 430 // go.y:hidden_funarg 431 func (p *importer) param(named bool) *Node { 432 typ := p.typ() 433 434 isddd := false 435 if typ.Etype == T_old_DARRAY { 436 // T_old_DARRAY indicates ... type 437 typ.Etype = TARRAY 438 isddd = true 439 } 440 441 n := Nod(ODCLFIELD, nil, typenod(typ)) 442 n.Isddd = isddd 443 444 if named { 445 name := p.string() 446 if name == "" { 447 Fatalf("expected named parameter") 448 } 449 // The parameter package doesn't matter; it's never consulted. 450 // We use the builtinpkg per go.y:sym (line 1181). 451 n.Left = newname(builtinpkg.Lookup(name)) 452 } 453 454 // TODO(gri) This is compiler-specific (escape info). 455 // Move into compiler-specific section eventually? 456 n.SetVal(p.note()) 457 458 return n 459 } 460 461 func (p *importer) value(typ *Type) (x Val) { 462 switch tag := p.tagOrIndex(); tag { 463 case falseTag: 464 x.U = false 465 case trueTag: 466 x.U = true 467 case int64Tag: 468 u := new(Mpint) 469 Mpmovecfix(u, p.int64()) 470 u.Rune = typ == idealrune 471 x.U = u 472 case floatTag: 473 f := newMpflt() 474 p.float(f) 475 if typ == idealint || Isint[typ.Etype] { 476 // uncommon case: large int encoded as float 477 u := new(Mpint) 478 mpmovefltfix(u, f) 479 x.U = u 480 break 481 } 482 x.U = f 483 case complexTag: 484 u := new(Mpcplx) 485 p.float(&u.Real) 486 p.float(&u.Imag) 487 x.U = u 488 case stringTag: 489 x.U = p.string() 490 default: 491 Fatalf("unexpected value tag %d", tag) 492 } 493 494 // verify ideal type 495 if isideal(typ) && untype(x.Ctype()) != typ { 496 Fatalf("value %v and type %v don't match", x, typ) 497 } 498 499 return 500 } 501 502 func (p *importer) float(x *Mpflt) { 503 sign := p.int() 504 if sign == 0 { 505 Mpmovecflt(x, 0) 506 return 507 } 508 509 exp := p.int() 510 mant := new(big.Int).SetBytes([]byte(p.string())) 511 512 m := x.Val.SetInt(mant) 513 m.SetMantExp(m, exp-mant.BitLen()) 514 if sign < 0 { 515 m.Neg(m) 516 } 517 } 518 519 // ---------------------------------------------------------------------------- 520 // Inlined function bodies 521 522 func (p *importer) body() { 523 p.int() 524 p.block() 525 } 526 527 func (p *importer) block() { 528 for i := p.int(); i > 0; i-- { 529 p.stmt() 530 } 531 } 532 533 func (p *importer) stmt() { 534 // TODO(gri) do something sensible here 535 p.string() 536 } 537 538 // ---------------------------------------------------------------------------- 539 // Low-level decoders 540 541 func (p *importer) tagOrIndex() int { 542 if p.debugFormat { 543 p.marker('t') 544 } 545 546 return int(p.rawInt64()) 547 } 548 549 func (p *importer) int() int { 550 x := p.int64() 551 if int64(int(x)) != x { 552 Fatalf("exported integer too large") 553 } 554 return int(x) 555 } 556 557 func (p *importer) int64() int64 { 558 if p.debugFormat { 559 p.marker('i') 560 } 561 562 return p.rawInt64() 563 } 564 565 func (p *importer) string() string { 566 if p.debugFormat { 567 p.marker('s') 568 } 569 570 if n := int(p.rawInt64()); n > 0 { 571 if cap(p.buf) < n { 572 p.buf = make([]byte, n) 573 } else { 574 p.buf = p.buf[:n] 575 } 576 for i := 0; i < n; i++ { 577 p.buf[i] = p.byte() 578 } 579 return string(p.buf) 580 } 581 582 return "" 583 } 584 585 func (p *importer) marker(want byte) { 586 if got := p.byte(); got != want { 587 Fatalf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read) 588 } 589 590 pos := p.read 591 if n := int(p.rawInt64()); n != pos { 592 Fatalf("incorrect position: got %d; want %d", n, pos) 593 } 594 } 595 596 // rawInt64 should only be used by low-level decoders 597 func (p *importer) rawInt64() int64 { 598 i, err := binary.ReadVarint(p) 599 if err != nil { 600 Fatalf("read error: %v", err) 601 } 602 return i 603 } 604 605 // needed for binary.ReadVarint in rawInt64 606 func (p *importer) ReadByte() (byte, error) { 607 return p.byte(), nil 608 } 609 610 // byte is the bottleneck interface for reading from p.in. 611 // It unescapes '|' 'S' to '$' and '|' '|' to '|'. 612 func (p *importer) byte() byte { 613 c := obj.Bgetc(p.in) 614 p.read++ 615 if c < 0 { 616 Fatalf("read error") 617 } 618 if c == '|' { 619 c = obj.Bgetc(p.in) 620 p.read++ 621 if c < 0 { 622 Fatalf("read error") 623 } 624 switch c { 625 case 'S': 626 c = '$' 627 case '|': 628 // nothing to do 629 default: 630 Fatalf("unexpected escape sequence in export data") 631 } 632 } 633 return byte(c) 634 }