Skip to content
Snippets Groups Projects
reader.go 43 KiB
Newer Older
  • Learn to ignore specific revisions
  • // UNREVIEWED
    
    // Copyright 2021 The Go Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style
    // license that can be found in the LICENSE file.
    
    package noder
    
    import (
    	"bytes"
    	"fmt"
    	"go/constant"
    	"strings"
    
    	"cmd/compile/internal/base"
    	"cmd/compile/internal/deadcode"
    	"cmd/compile/internal/dwarfgen"
    	"cmd/compile/internal/ir"
    	"cmd/compile/internal/typecheck"
    	"cmd/compile/internal/types"
    	"cmd/internal/obj"
    	"cmd/internal/src"
    )
    
    // TODO(mdempsky): Suppress duplicate type/const errors that can arise
    // during typecheck due to naive type substitution (e.g., see #42758).
    // I anticipate these will be handled as a consequence of adding
    // dictionaries support, so it's probably not important to focus on
    // this until after that's done.
    
    type pkgReader struct {
    	pkgDecoder
    
    	posBases []*src.PosBase
    	pkgs     []*types.Pkg
    	typs     []*types.Type
    
    	// offset for rewriting the given index into the output,
    	// but bitwise inverted so we can detect if we're missing the entry or not.
    	newindex []int
    }
    
    func newPkgReader(pr pkgDecoder) *pkgReader {
    	return &pkgReader{
    		pkgDecoder: pr,
    
    		posBases: make([]*src.PosBase, pr.numElems(relocPosBase)),
    		pkgs:     make([]*types.Pkg, pr.numElems(relocPkg)),
    		typs:     make([]*types.Type, pr.numElems(relocType)),
    
    		newindex: make([]int, pr.totalElems()),
    	}
    }
    
    type pkgReaderIndex struct {
    	pr        *pkgReader
    	idx       int
    	implicits []*types.Type
    }
    
    func (pri pkgReaderIndex) asReader(k reloc, marker syncMarker) *reader {
    	r := pri.pr.newReader(k, pri.idx, marker)
    	r.implicits = pri.implicits
    	return r
    }
    
    func (pr *pkgReader) newReader(k reloc, idx int, marker syncMarker) *reader {
    	return &reader{
    		decoder: pr.newDecoder(k, idx, marker),
    		p:       pr,
    	}
    }
    
    type reader struct {
    	decoder
    
    	p *pkgReader
    
    	// Implicit and explicit type arguments in use for reading the
    	// current object. For example:
    	//
    	//	func F[T any]() {
    	//		type X[U any] struct { t T; u U }
    	//		var _ X[string]
    	//	}
    	//
    	//	var _ = F[int]
    	//
    	// While instantiating F[int], we need to in turn instantiate
    	// X[string]. [int] and [string] are explicit type arguments for F
    	// and X, respectively; but [int] is also the implicit type
    	// arguments for X.
    	//
    	// (As an analogy to function literals, explicits are the function
    	// literal's formal parameters, while implicits are variables
    	// captured by the function literal.)
    	implicits []*types.Type
    	explicits []*types.Type
    
    	ext *reader
    
    	// TODO(mdempsky): The state below is all specific to reading
    	// function bodies. It probably makes sense to split it out
    	// separately so that it doesn't take up space in every reader
    	// instance.
    
    	curfn  *ir.Func
    	locals []*ir.Name
    
    	funarghack bool
    
    	// scopeVars is a stack tracking the number of variables declared in
    	// the current function at the moment each open scope was opened.
    	scopeVars         []int
    	marker            dwarfgen.ScopeMarker
    	lastCloseScopePos src.XPos
    
    	// === details for handling inline body expansion ===
    
    	// If we're reading in a function body because of inlining, this is
    	// the call that we're inlining for.
    	inlCaller    *ir.Func
    	inlCall      *ir.CallExpr
    	inlFunc      *ir.Func
    	inlTreeIndex int
    	inlPosBases  map[*src.PosBase]*src.PosBase
    
    	delayResults bool
    
    	// Label to return to.
    	retlabel *types.Sym
    
    	inlvars, retvars ir.Nodes
    }
    
    func (r *reader) setType(n ir.Node, typ *types.Type) {
    	n.SetType(typ)
    	n.SetTypecheck(1)
    
    	if name, ok := n.(*ir.Name); ok {
    		name.SetWalkdef(1)
    		name.Ntype = ir.TypeNode(name.Type())
    	}
    }
    
    func (r *reader) setValue(name *ir.Name, val constant.Value) {
    	name.SetVal(val)
    	name.Defn = nil
    }
    
    // @@@ Positions
    
    func (r *reader) pos() src.XPos {
    	return base.Ctxt.PosTable.XPos(r.pos0())
    }
    
    func (r *reader) pos0() src.Pos {
    	r.sync(syncPos)
    	if !r.bool() {
    		return src.NoPos
    	}
    
    	posBase := r.posBase()
    	line := r.uint()
    	col := r.uint()
    	return src.MakePos(posBase, line, col)
    }
    
    func (r *reader) posBase() *src.PosBase {
    	return r.inlPosBase(r.p.posBaseIdx(r.reloc(relocPosBase)))
    }
    
    func (pr *pkgReader) posBaseIdx(idx int) *src.PosBase {
    	if b := pr.posBases[idx]; b != nil {
    		return b
    	}
    
    	r := pr.newReader(relocPosBase, idx, syncPosBase)
    	var b *src.PosBase
    
    	fn := r.string()
    	absfn := r.string()
    
    	if r.bool() {
    		b = src.NewFileBase(fn, absfn)
    	} else {
    		pos := r.pos0()
    		line := r.uint()
    		col := r.uint()
    		b = src.NewLinePragmaBase(pos, fn, absfn, line, col)
    	}
    
    	pr.posBases[idx] = b
    	return b
    }
    
    func (r *reader) inlPosBase(oldBase *src.PosBase) *src.PosBase {
    	if r.inlCall == nil {
    		return oldBase
    	}
    
    	if newBase, ok := r.inlPosBases[oldBase]; ok {
    		return newBase
    	}
    
    	newBase := src.NewInliningBase(oldBase, r.inlTreeIndex)
    	r.inlPosBases[oldBase] = newBase
    	return newBase
    }
    
    func (r *reader) updatePos(xpos src.XPos) src.XPos {
    	pos := base.Ctxt.PosTable.Pos(xpos)
    	pos.SetBase(r.inlPosBase(pos.Base()))
    	return base.Ctxt.PosTable.XPos(pos)
    }
    
    func (r *reader) origPos(xpos src.XPos) src.XPos {
    	if r.inlCall == nil {
    		return xpos
    	}
    
    	pos := base.Ctxt.PosTable.Pos(xpos)
    	for old, new := range r.inlPosBases {
    		if pos.Base() == new {
    			pos.SetBase(old)
    			return base.Ctxt.PosTable.XPos(pos)
    		}
    	}
    
    	base.FatalfAt(xpos, "pos base missing from inlPosBases")
    	panic("unreachable")
    }
    
    // @@@ Packages
    
    func (r *reader) pkg() *types.Pkg {
    	r.sync(syncPkg)
    	return r.p.pkgIdx(r.reloc(relocPkg))
    }
    
    func (pr *pkgReader) pkgIdx(idx int) *types.Pkg {
    	if pkg := pr.pkgs[idx]; pkg != nil {
    		return pkg
    	}
    
    	pkg := pr.newReader(relocPkg, idx, syncPkgDef).doPkg()
    	pr.pkgs[idx] = pkg
    	return pkg
    }
    
    func (r *reader) doPkg() *types.Pkg {
    	path := r.string()
    	if path == "builtin" {
    		return types.BuiltinPkg
    	}
    	if path == "" {
    		path = r.p.pkgPath
    	}
    
    	name := r.string()
    	height := r.len()
    
    	pkg := types.NewPkg(path, "")
    
    	if pkg.Name == "" {
    		pkg.Name = name
    	} else {
    		assert(pkg.Name == name)
    	}
    
    	if pkg.Height == 0 {
    		pkg.Height = height
    	} else {
    		assert(pkg.Height == height)
    	}
    
    	return pkg
    }
    
    // @@@ Types
    
    func (r *reader) typ() *types.Type {
    	r.sync(syncType)
    	return r.p.typIdx(r.reloc(relocType), r.implicits, r.explicits)
    }
    
    func (pr *pkgReader) typIdx(idx int, implicits, explicits []*types.Type) *types.Type {
    	if typ := pr.typs[idx]; typ != nil {
    		return typ
    	}
    
    	r := pr.newReader(relocType, idx, syncTypeIdx)
    	r.implicits = implicits
    	r.explicits = explicits
    	typ := r.doTyp()
    	assert(typ != nil)
    
    
    	// For recursive type declarations involving interfaces and aliases,
    	// above r.doTyp() call may have already set pr.typs[idx], so just
    	// double check and return the type.
    	//
    	// Example:
    	//
    	//     type F = func(I)
    	//
    	//     type I interface {
    	//         m(F)
    	//     }
    	//
    	// The writer writes data types in following index order:
    	//
    	//     0: func(I)
    	//     1: I
    	//     2: interface{m(func(I))}
    	//
    	// The reader resolves it in following index order:
    	//
    	//     0 -> 1 -> 2 -> 0 -> 1
    	//
    	// and can divide in logically 2 steps:
    	//
    	//  - 0 -> 1     : first time the reader reach type I,
    	//                 it creates new named type with symbol I.
    	//
    	//  - 2 -> 0 -> 1: the reader ends up reaching symbol I again,
    	//                 now the symbol I was setup in above step, so
    	//                 the reader just return the named type.
    	//
    	// Now, the functions called return, the pr.typs looks like below:
    	//
    	//  - 0 -> 1 -> 2 -> 0 : [<T> I <T>]
    	//  - 0 -> 1 -> 2      : [func(I) I <T>]
    	//  - 0 -> 1           : [func(I) I interface { "".m(func("".I)) }]
    	//
    	// The idx 1, corresponding with type I was resolved successfully
    	// after r.doTyp() call.
    
    337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828
    	if typ := pr.typs[idx]; typ != nil {
    		return typ
    	}
    
    	// If we have type parameters, the type might refer to them, and it
    	// wouldn't be safe to reuse those in other contexts. So we
    	// conservatively avoid caching them in that case.
    	//
    	// TODO(mdempsky): If we're clever, we should be able to still cache
    	// types by tracking which type parameters are used. However, in my
    	// attempts so far, I haven't yet succeeded in being clever enough.
    	if len(implicits)+len(explicits) == 0 {
    		pr.typs[idx] = typ
    	}
    
    	if !typ.IsUntyped() {
    		types.CheckSize(typ)
    	}
    
    	return typ
    }
    
    func (r *reader) doTyp() *types.Type {
    	switch tag := codeType(r.code(syncType)); tag {
    	default:
    		panic(fmt.Sprintf("unexpected type: %v", tag))
    
    	case typeBasic:
    		return *basics[r.len()]
    
    	case typeNamed:
    		obj := r.obj()
    		assert(obj.Op() == ir.OTYPE)
    		return obj.Type()
    
    	case typeTypeParam:
    		idx := r.len()
    		if idx < len(r.implicits) {
    			return r.implicits[idx]
    		}
    		return r.explicits[idx-len(r.implicits)]
    
    	case typeArray:
    		len := int64(r.uint64())
    		return types.NewArray(r.typ(), len)
    	case typeChan:
    		dir := dirs[r.len()]
    		return types.NewChan(r.typ(), dir)
    	case typeMap:
    		return types.NewMap(r.typ(), r.typ())
    	case typePointer:
    		return types.NewPtr(r.typ())
    	case typeSignature:
    		return r.signature(types.LocalPkg, nil)
    	case typeSlice:
    		return types.NewSlice(r.typ())
    	case typeStruct:
    		return r.structType()
    	case typeInterface:
    		return r.interfaceType()
    	}
    }
    
    func (r *reader) interfaceType() *types.Type {
    	tpkg := types.LocalPkg // TODO(mdempsky): Remove after iexport is gone.
    
    	nmethods, nembeddeds := r.len(), r.len()
    
    	fields := make([]*types.Field, nmethods+nembeddeds)
    	methods, embeddeds := fields[:nmethods], fields[nmethods:]
    
    	for i := range methods {
    		pos := r.pos()
    		pkg, sym := r.selector()
    		tpkg = pkg
    		mtyp := r.signature(pkg, typecheck.FakeRecv())
    		methods[i] = types.NewField(pos, sym, mtyp)
    	}
    	for i := range embeddeds {
    		embeddeds[i] = types.NewField(src.NoXPos, nil, r.typ())
    	}
    
    	if len(fields) == 0 {
    		return types.Types[types.TINTER] // empty interface
    	}
    	return types.NewInterface(tpkg, fields)
    }
    
    func (r *reader) structType() *types.Type {
    	tpkg := types.LocalPkg // TODO(mdempsky): Remove after iexport is gone.
    	fields := make([]*types.Field, r.len())
    	for i := range fields {
    		pos := r.pos()
    		pkg, sym := r.selector()
    		tpkg = pkg
    		ftyp := r.typ()
    		tag := r.string()
    		embedded := r.bool()
    
    		f := types.NewField(pos, sym, ftyp)
    		f.Note = tag
    		if embedded {
    			f.Embedded = 1
    		}
    		fields[i] = f
    	}
    	return types.NewStruct(tpkg, fields)
    }
    
    func (r *reader) signature(tpkg *types.Pkg, recv *types.Field) *types.Type {
    	r.sync(syncSignature)
    
    	params := r.params(&tpkg)
    	results := r.params(&tpkg)
    	if r.bool() { // variadic
    		params[len(params)-1].SetIsDDD(true)
    	}
    
    	return types.NewSignature(tpkg, recv, nil, params, results)
    }
    
    func (r *reader) params(tpkg **types.Pkg) []*types.Field {
    	r.sync(syncParams)
    	fields := make([]*types.Field, r.len())
    	for i := range fields {
    		*tpkg, fields[i] = r.param()
    	}
    	return fields
    }
    
    func (r *reader) param() (*types.Pkg, *types.Field) {
    	r.sync(syncParam)
    
    	pos := r.pos()
    	pkg, sym := r.localIdent()
    	typ := r.typ()
    
    	return pkg, types.NewField(pos, sym, typ)
    }
    
    // @@@ Objects
    
    var objReader = map[*types.Sym]pkgReaderIndex{}
    
    func (r *reader) obj() ir.Node {
    	r.sync(syncObject)
    
    	idx := r.reloc(relocObj)
    
    	explicits := make([]*types.Type, r.len())
    	for i := range explicits {
    		explicits[i] = r.typ()
    	}
    
    	return r.p.objIdx(idx, r.implicits, explicits)
    }
    
    func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node {
    	r := pr.newReader(relocObj, idx, syncObject1)
    	r.ext = pr.newReader(relocObjExt, idx, syncObject1)
    
    	_, sym := r.qualifiedIdent()
    
    	// Middle dot indicates local defined type; see writer.sym.
    	// TODO(mdempsky): Come up with a better way to handle this.
    	if strings.Contains(sym.Name, "·") {
    		r.implicits = implicits
    		r.ext.implicits = implicits
    	}
    	r.explicits = explicits
    	r.ext.explicits = explicits
    
    	origSym := sym
    
    	sym = r.mangle(sym)
    	if !sym.IsBlank() && sym.Def != nil {
    		return sym.Def.(ir.Node)
    	}
    
    	r.typeParamBounds(origSym)
    	tag := codeObj(r.code(syncCodeObj))
    
    	do := func(op ir.Op, hasTParams bool) *ir.Name {
    		pos := r.pos()
    		if hasTParams {
    			r.typeParamNames()
    		}
    
    		name := ir.NewDeclNameAt(pos, op, sym)
    		name.Class = ir.PEXTERN // may be overridden later
    		if !sym.IsBlank() {
    			if sym.Def != nil {
    				base.FatalfAt(name.Pos(), "already have a definition for %v", name)
    			}
    			assert(sym.Def == nil)
    			sym.Def = name
    		}
    		return name
    	}
    
    	switch tag {
    	default:
    		panic("unexpected object")
    
    	case objStub:
    		if pri, ok := objReader[origSym]; ok {
    			return pri.pr.objIdx(pri.idx, pri.implicits, r.explicits)
    		}
    		if haveLegacyImports {
    			assert(len(r.implicits)+len(r.explicits) == 0)
    			return typecheck.Resolve(ir.NewIdent(src.NoXPos, origSym))
    		}
    		base.Fatalf("unresolved stub: %v", origSym)
    		panic("unreachable")
    
    	case objAlias:
    		name := do(ir.OTYPE, false)
    		r.setType(name, r.typ())
    		name.SetAlias(true)
    		return name
    
    	case objConst:
    		name := do(ir.OLITERAL, false)
    		typ, val := r.value()
    		r.setType(name, typ)
    		r.setValue(name, val)
    		return name
    
    	case objFunc:
    		if sym.Name == "init" {
    			sym = renameinit()
    		}
    		name := do(ir.ONAME, true)
    		r.setType(name, r.signature(sym.Pkg, nil))
    
    		name.Func = ir.NewFunc(r.pos())
    		name.Func.Nname = name
    
    		r.ext.funcExt(name)
    		return name
    
    	case objType:
    		name := do(ir.OTYPE, true)
    		typ := types.NewNamed(name)
    		r.setType(name, typ)
    
    		// Important: We need to do this before SetUnderlying.
    		r.ext.typeExt(name)
    
    		// We need to defer CheckSize until we've called SetUnderlying to
    		// handle recursive types.
    		types.DeferCheckSize()
    		typ.SetUnderlying(r.typ())
    		types.ResumeCheckSize()
    
    		methods := make([]*types.Field, r.len())
    		for i := range methods {
    			methods[i] = r.method()
    		}
    		if len(methods) != 0 {
    			typ.Methods().Set(methods)
    		}
    
    		return name
    
    	case objVar:
    		name := do(ir.ONAME, false)
    		r.setType(name, r.typ())
    		r.ext.varExt(name)
    		return name
    	}
    }
    
    func (r *reader) mangle(sym *types.Sym) *types.Sym {
    	if len(r.implicits)+len(r.explicits) == 0 {
    		return sym
    	}
    
    	var buf bytes.Buffer
    	buf.WriteString(sym.Name)
    	buf.WriteByte('[')
    	for i, targs := range [2][]*types.Type{r.implicits, r.explicits} {
    		if i > 0 && len(r.implicits) != 0 && len(r.explicits) != 0 {
    			buf.WriteByte(';')
    		}
    		for j, targ := range targs {
    			if j > 0 {
    				buf.WriteByte(',')
    			}
    			// TODO(mdempsky): We need the linker to replace "" in the symbol
    			// names here.
    			buf.WriteString(targ.ShortString())
    		}
    	}
    	buf.WriteByte(']')
    	return sym.Pkg.Lookup(buf.String())
    }
    
    func (r *reader) typeParamBounds(sym *types.Sym) {
    	r.sync(syncTypeParamBounds)
    
    	nimplicits := r.len()
    	nexplicits := r.len()
    
    	if len(r.implicits) != nimplicits || len(r.explicits) != nexplicits {
    		base.Fatalf("%v has %v+%v params, but instantiated with %v+%v args", sym, nimplicits, nexplicits, len(r.implicits), len(r.explicits))
    	}
    
    	// For stenciling, we can just skip over the type parameters.
    
    	for range r.explicits {
    		// Skip past bounds without actually evaluating them.
    		r.sync(syncType)
    		r.reloc(relocType)
    	}
    }
    
    func (r *reader) typeParamNames() {
    	r.sync(syncTypeParamNames)
    
    	for range r.explicits {
    		r.pos()
    		r.localIdent()
    	}
    }
    
    func (r *reader) value() (*types.Type, constant.Value) {
    	r.sync(syncValue)
    	typ := r.typ()
    	return typ, FixValue(typ, r.rawValue())
    }
    
    func (r *reader) method() *types.Field {
    	r.sync(syncMethod)
    	pos := r.pos()
    	pkg, sym := r.selector()
    	r.typeParamNames()
    	_, recv := r.param()
    	typ := r.signature(pkg, recv)
    
    	fnsym := sym
    	fnsym = ir.MethodSym(recv.Type, fnsym)
    	name := ir.NewNameAt(pos, fnsym)
    	r.setType(name, typ)
    
    	name.Func = ir.NewFunc(r.pos())
    	name.Func.Nname = name
    
    	// TODO(mdempsky): Make sure we're handling //go:nointerface
    	// correctly. I don't think this is exercised within the Go repo.
    
    	r.ext.funcExt(name)
    
    	meth := types.NewField(name.Func.Pos(), sym, typ)
    	meth.Nname = name
    	return meth
    }
    
    func (r *reader) qualifiedIdent() (pkg *types.Pkg, sym *types.Sym) {
    	r.sync(syncSym)
    	pkg = r.pkg()
    	if name := r.string(); name != "" {
    		sym = pkg.Lookup(name)
    	}
    	return
    }
    
    func (r *reader) localIdent() (pkg *types.Pkg, sym *types.Sym) {
    	r.sync(syncLocalIdent)
    	pkg = r.pkg()
    	if name := r.string(); name != "" {
    		sym = pkg.Lookup(name)
    	}
    	return
    }
    
    func (r *reader) selector() (origPkg *types.Pkg, sym *types.Sym) {
    	r.sync(syncSelector)
    	origPkg = r.pkg()
    	name := r.string()
    	pkg := origPkg
    	if types.IsExported(name) {
    		pkg = types.LocalPkg
    	}
    	sym = pkg.Lookup(name)
    	return
    }
    
    // @@@ Compiler extensions
    
    func (r *reader) funcExt(name *ir.Name) {
    	r.sync(syncFuncExt)
    
    	name.Class = 0 // so MarkFunc doesn't complain
    	ir.MarkFunc(name)
    
    	fn := name.Func
    
    	// XXX: Workaround because linker doesn't know how to copy Pos.
    	if !fn.Pos().IsKnown() {
    		fn.SetPos(name.Pos())
    	}
    
    	// TODO(mdempsky): Remember why I wrote this code. I think it has to
    	// do with how ir.VisitFuncsBottomUp works?
    	if name.Sym().Pkg == types.LocalPkg || len(r.implicits)+len(r.explicits) != 0 {
    		name.Defn = fn
    	}
    
    	fn.Pragma = r.pragmaFlag()
    	r.linkname(name)
    
    	if r.bool() {
    		fn.ABI = obj.ABI(r.uint64())
    
    		// Escape analysis.
    		for _, fs := range &types.RecvsParams {
    			for _, f := range fs(name.Type()).FieldSlice() {
    				f.Note = r.string()
    			}
    		}
    
    		if r.bool() {
    			fn.Inl = &ir.Inline{
    				Cost:            int32(r.len()),
    				CanDelayResults: r.bool(),
    			}
    			r.addBody(name.Func)
    		}
    	} else {
    		r.addBody(name.Func)
    	}
    	r.sync(syncEOF)
    }
    
    func (r *reader) typeExt(name *ir.Name) {
    	r.sync(syncTypeExt)
    
    	typ := name.Type()
    
    	if len(r.implicits)+len(r.explicits) != 0 {
    		// Set "RParams" (really type arguments here, not parameters) so
    		// this type is treated as "fully instantiated". This ensures the
    		// type descriptor is written out as DUPOK and method wrappers are
    		// generated even for imported types.
    		var targs []*types.Type
    		targs = append(targs, r.implicits...)
    		targs = append(targs, r.explicits...)
    		typ.SetRParams(targs)
    	}
    
    	name.SetPragma(r.pragmaFlag())
    	if name.Pragma()&ir.NotInHeap != 0 {
    		typ.SetNotInHeap(true)
    	}
    
    	typecheck.SetBaseTypeIndex(typ, r.int64(), r.int64())
    }
    
    func (r *reader) varExt(name *ir.Name) {
    	r.sync(syncVarExt)
    	r.linkname(name)
    }
    
    func (r *reader) linkname(name *ir.Name) {
    	assert(name.Op() == ir.ONAME)
    	r.sync(syncLinkname)
    
    	if idx := r.int64(); idx >= 0 {
    		lsym := name.Linksym()
    		lsym.SymIdx = int32(idx)
    		lsym.Set(obj.AttrIndexed, true)
    	} else {
    		name.Sym().Linkname = r.string()
    	}
    }
    
    func (r *reader) pragmaFlag() ir.PragmaFlag {
    	r.sync(syncPragma)
    	return ir.PragmaFlag(r.int())
    }
    
    // @@@ Function bodies
    
    // bodyReader tracks where the serialized IR for a function's body can
    // be found.
    var bodyReader = map[*ir.Func]pkgReaderIndex{}
    
    // todoBodies holds the list of function bodies that still need to be
    // constructed.
    var todoBodies []*ir.Func
    
    
    // Keep in sync with writer.implicitTypes
    // Also see comment there for why r.implicits and r.explicits should
    // never both be non-empty.
    func (r *reader) implicitTypes() []*types.Type {
    	r.sync(syncImplicitTypes)
    
    
    	implicits := r.implicits
    	if len(implicits) == 0 {
    		implicits = r.explicits
    	} else {
    		assert(len(r.explicits) == 0)
    	}
    
    	return implicits
    }
    
    func (r *reader) addBody(fn *ir.Func) {
    	r.sync(syncAddBody)
    
    	pri := pkgReaderIndex{r.p, r.reloc(relocBody), implicits}
    	bodyReader[fn] = pri
    
    	if r.curfn == nil {
    		todoBodies = append(todoBodies, fn)
    		return
    	}
    
    	pri.funcBody(fn)
    }
    
    func (pri pkgReaderIndex) funcBody(fn *ir.Func) {
    	r := pri.asReader(relocBody, syncFuncBody)
    	r.funcBody(fn)
    }
    
    func (r *reader) funcBody(fn *ir.Func) {
    	r.curfn = fn
    	r.locals = fn.ClosureVars
    
    	// TODO(mdempsky): Get rid of uses of typecheck.NodAddrAt so we
    	// don't have to set ir.CurFunc.
    	outerCurFunc := ir.CurFunc
    	ir.CurFunc = fn
    
    	r.funcargs(fn)
    
    	if r.bool() {
    		body := r.stmts()
    		if body == nil {
    			pos := src.NoXPos
    			if quirksMode() {
    				pos = funcParamsEndPos(fn)
    			}
    			body = []ir.Node{ir.NewBlockStmt(pos, nil)}
    		}
    		fn.Body = body
    		fn.Endlineno = r.pos()
    	}
    
    	ir.CurFunc = outerCurFunc
    	r.marker.WriteTo(fn)
    }
    
    func (r *reader) funcargs(fn *ir.Func) {
    	sig := fn.Nname.Type()
    
    	if recv := sig.Recv(); recv != nil {
    		r.funcarg(recv, recv.Sym, ir.PPARAM)
    	}
    	for _, param := range sig.Params().FieldSlice() {
    		r.funcarg(param, param.Sym, ir.PPARAM)
    	}
    
    	for i, param := range sig.Results().FieldSlice() {
    		sym := types.OrigSym(param.Sym)
    
    		if sym == nil || sym.IsBlank() {
    			prefix := "~r"
    			if r.inlCall != nil {
    				prefix = "~R"
    			} else if sym != nil {
    				prefix = "~b"
    			}
    			sym = typecheck.LookupNum(prefix, i)
    		}
    
    		r.funcarg(param, sym, ir.PPARAMOUT)
    	}
    }
    
    func (r *reader) funcarg(param *types.Field, sym *types.Sym, ctxt ir.Class) {
    	if sym == nil {
    		assert(ctxt == ir.PPARAM)
    		if r.inlCall != nil {
    			r.inlvars.Append(ir.BlankNode)
    		}
    		return
    	}
    
    	name := ir.NewNameAt(r.updatePos(param.Pos), sym)
    	r.setType(name, param.Type)
    	r.addLocal(name, ctxt)
    
    	if r.inlCall == nil {
    		if !r.funarghack {
    			param.Sym = sym
    			param.Nname = name
    		}
    	} else {
    		if ctxt == ir.PPARAMOUT {
    			r.retvars.Append(name)
    		} else {
    			r.inlvars.Append(name)
    		}
    	}
    }
    
    func (r *reader) addLocal(name *ir.Name, ctxt ir.Class) {
    	assert(ctxt == ir.PAUTO || ctxt == ir.PPARAM || ctxt == ir.PPARAMOUT)
    
    	r.sync(syncAddLocal)
    
    		want := r.int()
    		if have := len(r.locals); have != want {
    			base.FatalfAt(name.Pos(), "locals table has desynced")
    		}
    	}
    
    	name.SetUsed(true)
    	r.locals = append(r.locals, name)
    
    	// TODO(mdempsky): Move earlier.
    	if ir.IsBlank(name) {
    		return
    	}
    
    	if r.inlCall != nil {
    		if ctxt == ir.PAUTO {
    			name.SetInlLocal(true)
    		} else {
    			name.SetInlFormal(true)
    			ctxt = ir.PAUTO
    		}
    
    		// TODO(mdempsky): Rethink this hack.
    		if strings.HasPrefix(name.Sym().Name, "~") || base.Flag.GenDwarfInl == 0 {
    			name.SetPos(r.inlCall.Pos())
    			name.SetInlFormal(false)
    			name.SetInlLocal(false)
    		}
    	}
    
    	name.Class = ctxt
    	name.Curfn = r.curfn
    
    	r.curfn.Dcl = append(r.curfn.Dcl, name)
    
    	if ctxt == ir.PAUTO {
    		name.SetFrameOffset(0)
    	}
    }
    
    func (r *reader) useLocal() *ir.Name {
    	r.sync(syncUseObjLocal)
    	return r.locals[r.len()]
    }
    
    func (r *reader) openScope() {
    	r.sync(syncOpenScope)
    	pos := r.pos()
    
    	if base.Flag.Dwarf {