github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/go/internal/gcimporter/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 package gcimporter 6 7 import ( 8 "encoding/binary" 9 "fmt" 10 "go/constant" 11 "go/token" 12 "go/types" 13 "sort" 14 "unicode" 15 "unicode/utf8" 16 ) 17 18 // BImportData imports a package from the serialized package data 19 // and returns the number of bytes consumed and a reference to the package. 20 // If data is obviously malformed, an error is returned but in 21 // general it is not recommended to call BImportData on untrusted data. 22 func BImportData(imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) { 23 p := importer{ 24 imports: imports, 25 data: data, 26 } 27 p.buf = p.bufarray[:] 28 29 // read low-level encoding format 30 switch format := p.byte(); format { 31 case 'c': 32 // compact format - nothing to do 33 case 'd': 34 p.debugFormat = true 35 default: 36 return p.read, nil, fmt.Errorf("invalid encoding format in export data: got %q; want 'c' or 'd'", format) 37 } 38 39 // --- generic export data --- 40 41 if v := p.string(); v != "v0" { 42 return p.read, nil, fmt.Errorf("unknown version: %s", v) 43 } 44 45 // populate typList with predeclared "known" types 46 p.typList = append(p.typList, predeclared...) 47 48 // read package data 49 // TODO(gri) clean this up 50 i := p.tagOrIndex() 51 if i != packageTag { 52 panic(fmt.Sprintf("package tag expected, got %d", i)) 53 } 54 name := p.string() 55 if s := p.string(); s != "" { 56 panic(fmt.Sprintf("empty path expected, got %s", s)) 57 } 58 pkg := p.imports[path] 59 if pkg == nil { 60 pkg = types.NewPackage(path, name) 61 p.imports[path] = pkg 62 } 63 p.pkgList = append(p.pkgList, pkg) 64 65 if debug && p.pkgList[0] != pkg { 66 panic("imported packaged not found in pkgList[0]") 67 } 68 69 // read compiler-specific flags 70 p.string() // discard 71 72 // read consts 73 for i := p.int(); i > 0; i-- { 74 name := p.string() 75 typ := p.typ() 76 val := p.value() 77 p.declare(types.NewConst(token.NoPos, pkg, name, typ, val)) 78 } 79 80 // read vars 81 for i := p.int(); i > 0; i-- { 82 name := p.string() 83 typ := p.typ() 84 p.declare(types.NewVar(token.NoPos, pkg, name, typ)) 85 } 86 87 // read funcs 88 for i := p.int(); i > 0; i-- { 89 name := p.string() 90 sig := p.typ().(*types.Signature) 91 p.int() // read and discard index of inlined function body 92 p.declare(types.NewFunc(token.NoPos, pkg, name, sig)) 93 } 94 95 // read types 96 for i := p.int(); i > 0; i-- { 97 // name is parsed as part of named type and the 98 // type object is added to scope via respective 99 // named type 100 _ = p.typ().(*types.Named) 101 } 102 103 // ignore compiler-specific import data 104 105 // complete interfaces 106 for _, typ := range p.typList { 107 if it, ok := typ.(*types.Interface); ok { 108 it.Complete() 109 } 110 } 111 112 // record all referenced packages as imports 113 list := append(([]*types.Package)(nil), p.pkgList[1:]...) 114 sort.Sort(byPath(list)) 115 pkg.SetImports(list) 116 117 // package was imported completely and without errors 118 pkg.MarkComplete() 119 120 return p.read, pkg, nil 121 } 122 123 type importer struct { 124 imports map[string]*types.Package 125 data []byte 126 buf []byte // for reading strings 127 bufarray [64]byte // initial underlying array for buf, large enough to avoid allocation when compiling std lib 128 pkgList []*types.Package 129 typList []types.Type 130 131 debugFormat bool 132 read int // bytes read 133 } 134 135 func (p *importer) declare(obj types.Object) { 136 if alt := p.pkgList[0].Scope().Insert(obj); alt != nil { 137 // This can only happen if we import a package a second time. 138 panic(fmt.Sprintf("%s already declared", alt.Name())) 139 } 140 } 141 142 func (p *importer) pkg() *types.Package { 143 // if the package was seen before, i is its index (>= 0) 144 i := p.tagOrIndex() 145 if i >= 0 { 146 return p.pkgList[i] 147 } 148 149 // otherwise, i is the package tag (< 0) 150 if i != packageTag { 151 panic(fmt.Sprintf("unexpected package tag %d", i)) 152 } 153 154 // read package data 155 name := p.string() 156 path := p.string() 157 158 // we should never see an empty package name 159 if name == "" { 160 panic("empty package name in import") 161 } 162 163 // we should never see an empty import path 164 if path == "" { 165 panic("empty import path") 166 } 167 168 // if the package was imported before, use that one; otherwise create a new one 169 pkg := p.imports[path] 170 if pkg == nil { 171 pkg = types.NewPackage(path, name) 172 p.imports[path] = pkg 173 } 174 p.pkgList = append(p.pkgList, pkg) 175 176 return pkg 177 } 178 179 func (p *importer) record(t types.Type) { 180 p.typList = append(p.typList, t) 181 } 182 183 // A dddSlice is a types.Type representing ...T parameters. 184 // It only appears for parameter types and does not escape 185 // the importer. 186 type dddSlice struct { 187 elem types.Type 188 } 189 190 func (t *dddSlice) Underlying() types.Type { return t } 191 func (t *dddSlice) String() string { return "..." + t.elem.String() } 192 193 func (p *importer) typ() types.Type { 194 // if the type was seen before, i is its index (>= 0) 195 i := p.tagOrIndex() 196 if i >= 0 { 197 return p.typList[i] 198 } 199 200 // otherwise, i is the type tag (< 0) 201 switch i { 202 case namedTag: 203 // read type object 204 name := p.string() 205 tpkg := p.pkg() 206 scope := tpkg.Scope() 207 obj := scope.Lookup(name) 208 209 // if the object doesn't exist yet, create and insert it 210 if obj == nil { 211 obj = types.NewTypeName(token.NoPos, tpkg, name, nil) 212 scope.Insert(obj) 213 } 214 215 if _, ok := obj.(*types.TypeName); !ok { 216 panic(fmt.Sprintf("pkg = %s, name = %s => %s", tpkg, name, obj)) 217 } 218 219 // associate new named type with obj if it doesn't exist yet 220 t0 := types.NewNamed(obj.(*types.TypeName), nil, nil) 221 222 // but record the existing type, if any 223 t := obj.Type().(*types.Named) 224 p.record(t) 225 226 // read underlying type 227 t0.SetUnderlying(p.typ()) 228 229 // interfaces don't have associated methods 230 if _, ok := t0.Underlying().(*types.Interface); ok { 231 return t 232 } 233 234 // read associated methods 235 for i := p.int(); i > 0; i-- { 236 name := p.string() 237 recv, _ := p.paramList() // TODO(gri) do we need a full param list for the receiver? 238 params, isddd := p.paramList() 239 result, _ := p.paramList() 240 p.int() // read and discard index of inlined function body 241 sig := types.NewSignature(recv.At(0), params, result, isddd) 242 t0.AddMethod(types.NewFunc(token.NoPos, tpkg, name, sig)) 243 } 244 245 return t 246 247 case arrayTag: 248 t := new(types.Array) 249 p.record(t) 250 251 n := p.int64() 252 *t = *types.NewArray(p.typ(), n) 253 return t 254 255 case sliceTag: 256 t := new(types.Slice) 257 p.record(t) 258 259 *t = *types.NewSlice(p.typ()) 260 return t 261 262 case dddTag: 263 t := new(dddSlice) 264 p.record(t) 265 266 t.elem = p.typ() 267 return t 268 269 case structTag: 270 t := new(types.Struct) 271 p.record(t) 272 273 n := p.int() 274 fields := make([]*types.Var, n) 275 tags := make([]string, n) 276 for i := range fields { 277 fields[i] = p.field() 278 tags[i] = p.string() 279 } 280 *t = *types.NewStruct(fields, tags) 281 return t 282 283 case pointerTag: 284 t := new(types.Pointer) 285 p.record(t) 286 287 *t = *types.NewPointer(p.typ()) 288 return t 289 290 case signatureTag: 291 t := new(types.Signature) 292 p.record(t) 293 294 params, isddd := p.paramList() 295 result, _ := p.paramList() 296 *t = *types.NewSignature(nil, params, result, isddd) 297 return t 298 299 case interfaceTag: 300 // Create a dummy entry in the type list. This is safe because we 301 // cannot expect the interface type to appear in a cycle, as any 302 // such cycle must contain a named type which would have been 303 // first defined earlier. 304 n := len(p.typList) 305 p.record(nil) 306 307 // no embedded interfaces with gc compiler 308 if p.int() != 0 { 309 panic("unexpected embedded interface") 310 } 311 312 // read methods 313 methods := make([]*types.Func, p.int()) 314 for i := range methods { 315 pkg, name := p.fieldName() 316 params, isddd := p.paramList() 317 result, _ := p.paramList() 318 sig := types.NewSignature(nil, params, result, isddd) 319 methods[i] = types.NewFunc(token.NoPos, pkg, name, sig) 320 } 321 322 t := types.NewInterface(methods, nil) 323 p.typList[n] = t 324 return t 325 326 case mapTag: 327 t := new(types.Map) 328 p.record(t) 329 330 key := p.typ() 331 val := p.typ() 332 *t = *types.NewMap(key, val) 333 return t 334 335 case chanTag: 336 t := new(types.Chan) 337 p.record(t) 338 339 var dir types.ChanDir 340 // tag values must match the constants in cmd/compile/internal/gc/go.go 341 switch d := p.int(); d { 342 case 1 /* Crecv */ : 343 dir = types.RecvOnly 344 case 2 /* Csend */ : 345 dir = types.SendOnly 346 case 3 /* Cboth */ : 347 dir = types.SendRecv 348 default: 349 panic(fmt.Sprintf("unexpected channel dir %d", d)) 350 } 351 val := p.typ() 352 *t = *types.NewChan(dir, val) 353 return t 354 355 default: 356 panic(fmt.Sprintf("unexpected type tag %d", i)) 357 } 358 } 359 360 func (p *importer) field() *types.Var { 361 pkg, name := p.fieldName() 362 typ := p.typ() 363 364 anonymous := false 365 if name == "" { 366 // anonymous field - typ must be T or *T and T must be a type name 367 switch typ := deref(typ).(type) { 368 case *types.Basic: // basic types are named types 369 name = typ.Name() 370 case *types.Named: 371 pkg = p.pkgList[0] 372 name = typ.Obj().Name() 373 default: 374 panic("anonymous field expected") 375 } 376 anonymous = true 377 } 378 379 return types.NewField(token.NoPos, pkg, name, typ, anonymous) 380 } 381 382 func (p *importer) fieldName() (*types.Package, string) { 383 name := p.string() 384 if name == "" { 385 return nil, "" // anonymous field 386 } 387 pkg := p.pkgList[0] 388 if name == "?" || name != "_" && !exported(name) { 389 if name == "?" { 390 name = "" 391 } 392 pkg = p.pkg() 393 } 394 return pkg, name 395 } 396 397 func (p *importer) paramList() (*types.Tuple, bool) { 398 n := p.int() 399 if n == 0 { 400 return nil, false 401 } 402 // negative length indicates unnamed parameters 403 named := true 404 if n < 0 { 405 n = -n 406 named = false 407 } 408 // n > 0 409 params := make([]*types.Var, n) 410 isddd := false 411 for i := range params { 412 params[i], isddd = p.param(named) 413 } 414 return types.NewTuple(params...), isddd 415 } 416 417 func (p *importer) param(named bool) (*types.Var, bool) { 418 t := p.typ() 419 td, isddd := t.(*dddSlice) 420 if isddd { 421 t = types.NewSlice(td.elem) 422 } 423 424 var name string 425 if named { 426 name = p.string() 427 if name == "" { 428 panic("expected named parameter") 429 } 430 } 431 432 // read and discard compiler-specific info 433 p.string() 434 435 return types.NewVar(token.NoPos, nil, name, t), isddd 436 } 437 438 func exported(name string) bool { 439 ch, _ := utf8.DecodeRuneInString(name) 440 return unicode.IsUpper(ch) 441 } 442 443 func (p *importer) value() constant.Value { 444 switch tag := p.tagOrIndex(); tag { 445 case falseTag: 446 return constant.MakeBool(false) 447 case trueTag: 448 return constant.MakeBool(true) 449 case int64Tag: 450 return constant.MakeInt64(p.int64()) 451 case floatTag: 452 return p.float() 453 case complexTag: 454 re := p.float() 455 im := p.float() 456 return constant.BinaryOp(re, token.ADD, constant.MakeImag(im)) 457 case stringTag: 458 return constant.MakeString(p.string()) 459 default: 460 panic(fmt.Sprintf("unexpected value tag %d", tag)) 461 } 462 } 463 464 func (p *importer) float() constant.Value { 465 sign := p.int() 466 if sign == 0 { 467 return constant.MakeInt64(0) 468 } 469 470 exp := p.int() 471 mant := []byte(p.string()) // big endian 472 473 // remove leading 0's if any 474 for len(mant) > 0 && mant[0] == 0 { 475 mant = mant[1:] 476 } 477 478 // convert to little endian 479 // TODO(gri) go/constant should have a more direct conversion function 480 // (e.g., once it supports a big.Float based implementation) 481 for i, j := 0, len(mant)-1; i < j; i, j = i+1, j-1 { 482 mant[i], mant[j] = mant[j], mant[i] 483 } 484 485 // adjust exponent (constant.MakeFromBytes creates an integer value, 486 // but mant represents the mantissa bits such that 0.5 <= mant < 1.0) 487 exp -= len(mant) << 3 488 if len(mant) > 0 { 489 for msd := mant[len(mant)-1]; msd&0x80 == 0; msd <<= 1 { 490 exp++ 491 } 492 } 493 494 x := constant.MakeFromBytes(mant) 495 switch { 496 case exp < 0: 497 d := constant.Shift(constant.MakeInt64(1), token.SHL, uint(-exp)) 498 x = constant.BinaryOp(x, token.QUO, d) 499 case exp > 0: 500 x = constant.Shift(x, token.SHL, uint(exp)) 501 } 502 503 if sign < 0 { 504 x = constant.UnaryOp(token.SUB, x, 0) 505 } 506 return x 507 } 508 509 // ---------------------------------------------------------------------------- 510 // Low-level decoders 511 512 func (p *importer) tagOrIndex() int { 513 if p.debugFormat { 514 p.marker('t') 515 } 516 517 return int(p.rawInt64()) 518 } 519 520 func (p *importer) int() int { 521 x := p.int64() 522 if int64(int(x)) != x { 523 panic("exported integer too large") 524 } 525 return int(x) 526 } 527 528 func (p *importer) int64() int64 { 529 if p.debugFormat { 530 p.marker('i') 531 } 532 533 return p.rawInt64() 534 } 535 536 func (p *importer) string() string { 537 if p.debugFormat { 538 p.marker('s') 539 } 540 541 if n := int(p.rawInt64()); n > 0 { 542 if cap(p.buf) < n { 543 p.buf = make([]byte, n) 544 } else { 545 p.buf = p.buf[:n] 546 } 547 for i := 0; i < n; i++ { 548 p.buf[i] = p.byte() 549 } 550 return string(p.buf) 551 } 552 553 return "" 554 } 555 556 func (p *importer) marker(want byte) { 557 if got := p.byte(); got != want { 558 panic(fmt.Sprintf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)) 559 } 560 561 pos := p.read 562 if n := int(p.rawInt64()); n != pos { 563 panic(fmt.Sprintf("incorrect position: got %d; want %d", n, pos)) 564 } 565 } 566 567 // rawInt64 should only be used by low-level decoders 568 func (p *importer) rawInt64() int64 { 569 i, err := binary.ReadVarint(p) 570 if err != nil { 571 panic(fmt.Sprintf("read error: %v", err)) 572 } 573 return i 574 } 575 576 // needed for binary.ReadVarint in rawInt64 577 func (p *importer) ReadByte() (byte, error) { 578 return p.byte(), nil 579 } 580 581 // byte is the bottleneck interface for reading p.data. 582 // It unescapes '|' 'S' to '$' and '|' '|' to '|'. 583 func (p *importer) byte() byte { 584 b := p.data[0] 585 r := 1 586 if b == '|' { 587 b = p.data[1] 588 r = 2 589 switch b { 590 case 'S': 591 b = '$' 592 case '|': 593 // nothing to do 594 default: 595 panic("unexpected escape sequence in export data") 596 } 597 } 598 p.data = p.data[r:] 599 p.read += r 600 return b 601 602 } 603 604 // ---------------------------------------------------------------------------- 605 // Export format 606 607 // Tags. Must be < 0. 608 const ( 609 // Packages 610 packageTag = -(iota + 1) 611 612 // Types 613 namedTag 614 arrayTag 615 sliceTag 616 dddTag 617 structTag 618 pointerTag 619 signatureTag 620 interfaceTag 621 mapTag 622 chanTag 623 624 // Values 625 falseTag 626 trueTag 627 int64Tag 628 floatTag 629 fractionTag // not used by gc 630 complexTag 631 stringTag 632 ) 633 634 var predeclared = []types.Type{ 635 // basic types 636 types.Typ[types.Bool], 637 types.Typ[types.Int], 638 types.Typ[types.Int8], 639 types.Typ[types.Int16], 640 types.Typ[types.Int32], 641 types.Typ[types.Int64], 642 types.Typ[types.Uint], 643 types.Typ[types.Uint8], 644 types.Typ[types.Uint16], 645 types.Typ[types.Uint32], 646 types.Typ[types.Uint64], 647 types.Typ[types.Uintptr], 648 types.Typ[types.Float32], 649 types.Typ[types.Float64], 650 types.Typ[types.Complex64], 651 types.Typ[types.Complex128], 652 types.Typ[types.String], 653 654 // aliases 655 types.Universe.Lookup("byte").Type(), 656 types.Universe.Lookup("rune").Type(), 657 658 // error 659 types.Universe.Lookup("error").Type(), 660 661 // untyped types 662 types.Typ[types.UntypedBool], 663 types.Typ[types.UntypedInt], 664 types.Typ[types.UntypedRune], 665 types.Typ[types.UntypedFloat], 666 types.Typ[types.UntypedComplex], 667 types.Typ[types.UntypedString], 668 types.Typ[types.UntypedNil], 669 670 // package unsafe 671 types.Typ[types.UnsafePointer], 672 }