]> Cypherpunks.ru repositories - gostls13.git/commitdiff
[dev.typeparams] all: merge master (296ddf2) into dev.typeparams
authorMatthew Dempsky <mdempsky@google.com>
Thu, 8 Jul 2021 20:04:25 +0000 (13:04 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Thu, 8 Jul 2021 20:11:32 +0000 (13:11 -0700)
Conflicts:

- src/runtime/runtime2.go

  On master, CL 317191 fixed the mentions of gc/reflect.go in comments
  to reflectdata/reflect.go; but on dev.typeparams, CL 325921 fixed
  that the same comment to reflect that deferstruct actually ended up
  in ssagen/ssa.go.

Merge List:

+ 2021-07-08 296ddf2a93 net: filter bad names from Lookup functions instead of hard failing
+ 2021-07-08 ce76298ee7 Update oudated comment
+ 2021-07-08 2ca44fe221 doc/go1.17: linkify time.UnixMilli and time.UnixMicro
+ 2021-07-07 5c59e11f5e cmd/compile: remove special-casing of blank in types.sconv{,2}
+ 2021-07-07 b003a8b1ae cmd/compile: optimize types.sconv
+ 2021-07-07 11f5df2d67 cmd/compile: extract pkgqual from symfmt
+ 2021-07-07 991fd381d5 cmd/go: don't lock .mod and .sum files for read in overlay
+ 2021-07-07 186a3bb4b0 cmd/go/internal/modfetch/codehost: skip hg tests if no hg binary is present
+ 2021-07-07 00c00558e1 cmd/go/internal/modload: remove unused functions
+ 2021-07-07 f264879f74 cmd/go/internal/modload: fix an apparent typo in the AutoRoot comment
+ 2021-07-07 c96833e5ba doc: remove stale comment about arm64 port

Change-Id: I849046b6d8f7421f60323549f3f763ef418bf9e7

1  2 
src/cmd/compile/internal/reflectdata/reflect.go
src/cmd/compile/internal/types/fmt.go
src/reflect/type.go
src/runtime/runtime2.go
src/runtime/select.go
src/runtime/type.go

index 27522ca85e5f0135b3cf67ae17e33e5849ed031c,eb9a8a6c9bc73ade1974d19e63cdbe225224935f..b20fc8cccc9ac1efc17cdb75f96a6a012f20d5c1
@@@ -28,13 -28,23 +28,13 @@@ import 
        "cmd/internal/src"
  )
  
 -type itabEntry struct {
 -      t, itype *types.Type
 -      lsym     *obj.LSym // symbol of the itab itself
 -
 -      // symbols of each method in
 -      // the itab, sorted by byte offset;
 -      // filled in by CompileITabs
 -      entries []*obj.LSym
 -}
 -
  type ptabEntry struct {
        s *types.Sym
        t *types.Type
  }
  
 -func CountTabs() (numPTabs, numITabs int) {
 -      return len(ptabs), len(itabs)
 +func CountPTabs() int {
 +      return len(ptabs)
  }
  
  // runtime interface and reflection data structures
@@@ -46,6 -56,7 +46,6 @@@ var 
        gcsymmu  sync.Mutex // protects gcsymset and gcsymslice
        gcsymset = make(map[*types.Type]struct{})
  
 -      itabs []itabEntry
        ptabs []*ir.Name
  )
  
@@@ -310,6 -321,13 +310,6 @@@ func methods(t *types.Type) []*typeSig 
        }
        typecheck.CalcMethods(mt)
  
 -      // type stored in interface word
 -      it := t
 -
 -      if !types.IsDirectIface(it) {
 -              it = types.NewPtr(t)
 -      }
 -
        // make list of methods for t,
        // generating code if necessary.
        var ms []*typeSig
  
                sig := &typeSig{
                        name:  f.Sym,
 -                      isym:  methodWrapper(it, f),
 -                      tsym:  methodWrapper(t, f),
 +                      isym:  methodWrapper(t, f, true),
 +                      tsym:  methodWrapper(t, f, false),
                        type_: typecheck.NewMethodType(f.Type, t),
                        mtype: typecheck.NewMethodType(f.Type, nil),
                }
@@@ -376,7 -394,7 +376,7 @@@ func imethods(t *types.Type) []*typeSi
                // IfaceType.Method is not in the reflect data.
                // Generate the method body, so that compiled
                // code can refer to it.
 -              methodWrapper(t, f)
 +              methodWrapper(t, f, false)
        }
  
        return methods
@@@ -651,7 -669,7 +651,7 @@@ var kinds = []int
  // tflag is documented in reflect/type.go.
  //
  // tflag values must be kept in sync with copies in:
- //    cmd/compile/internal/gc/reflect.go
+ //    cmd/compile/internal/reflectdata/reflect.go
  //    cmd/link/internal/ld/decodesym.go
  //    reflect/type.go
  //    runtime/type.go
@@@ -717,7 -735,7 +717,7 @@@ func dcommontype(lsym *obj.LSym, t *typ
        }
  
        exported := false
 -      p := t.LongString()
 +      p := t.NameString()
        // If we're writing out type T,
        // we are very likely to write out type *T as well.
        // Use the string "*T"[1:] for "T", so that the two
  // TrackSym returns the symbol for tracking use of field/method f, assumed
  // to be a member of struct/interface type t.
  func TrackSym(t *types.Type, f *types.Field) *obj.LSym {
 -      return base.PkgLinksym("go.track", t.ShortString()+"."+f.Sym.Name, obj.ABI0)
 +      return base.PkgLinksym("go.track", t.LinkString()+"."+f.Sym.Name, obj.ABI0)
  }
  
  func TypeSymPrefix(prefix string, t *types.Type) *types.Sym {
 -      p := prefix + "." + t.ShortString()
 +      p := prefix + "." + t.LinkString()
        s := types.TypeSymLookup(p)
  
        // This function is for looking up type-related generated functions
@@@ -830,16 -848,16 +830,16 @@@ func TypePtr(t *types.Type) *ir.AddrExp
        return typecheck.Expr(typecheck.NodAddr(n)).(*ir.AddrExpr)
  }
  
 -func ITabAddr(t, itype *types.Type) *ir.AddrExpr {
 -      if t == nil || (t.IsPtr() && t.Elem() == nil) || t.IsUntyped() || !itype.IsInterface() || itype.IsEmptyInterface() {
 -              base.Fatalf("ITabAddr(%v, %v)", t, itype)
 -      }
 -      s, existed := ir.Pkgs.Itab.LookupOK(t.ShortString() + "," + itype.ShortString())
 +// ITabAddr returns an expression representing a pointer to the itab
 +// for concrete type typ implementing interface iface.
 +func ITabAddr(typ, iface *types.Type) *ir.AddrExpr {
 +      s, existed := ir.Pkgs.Itab.LookupOK(typ.LinkString() + "," + iface.LinkString())
 +      lsym := s.Linksym()
 +
        if !existed {
 -              itabs = append(itabs, itabEntry{t: t, itype: itype, lsym: s.Linksym()})
 +              writeITab(lsym, typ, iface)
        }
  
 -      lsym := s.Linksym()
        n := ir.NewLinksymExpr(base.Pos, lsym, types.Types[types.TUINT8])
        return typecheck.Expr(typecheck.NodAddr(n)).(*ir.AddrExpr)
  }
@@@ -927,27 -945,25 +927,27 @@@ func writeType(t *types.Type) *obj.LSy
        if t.IsPtr() && t.Sym() == nil && t.Elem().Sym() != nil {
                tbase = t.Elem()
        }
 +      if tbase.Kind() == types.TFORW {
 +              base.Fatalf("unresolved defined type: %v", tbase)
 +      }
 +
        dupok := 0
 -      if tbase.Sym() == nil {
 +      if tbase.Sym() == nil { // TODO(mdempsky): Probably need DUPOK for instantiated types too.
                dupok = obj.DUPOK
        }
  
 -      if base.Ctxt.Pkgpath != "runtime" || (tbase != types.Types[tbase.Kind()] && tbase != types.ByteType && tbase != types.RuneType && tbase != types.ErrorType) { // int, float, etc
 -              // named types from other files are defined only by those files
 -              if tbase.Sym() != nil && tbase.Sym().Pkg != types.LocalPkg {
 -                      if i := typecheck.BaseTypeIndex(t); i >= 0 {
 -                              lsym.Pkg = tbase.Sym().Pkg.Prefix
 -                              lsym.SymIdx = int32(i)
 -                              lsym.Set(obj.AttrIndexed, true)
 -                      }
 -                      return lsym
 -              }
 -              // TODO(mdempsky): Investigate whether this can happen.
 -              if tbase.Kind() == types.TFORW {
 -                      return lsym
 +      if !NeedEmit(tbase) {
 +              if i := typecheck.BaseTypeIndex(t); i >= 0 {
 +                      lsym.Pkg = tbase.Sym().Pkg.Prefix
 +                      lsym.SymIdx = int32(i)
 +                      lsym.Set(obj.AttrIndexed, true)
                }
 +
 +              // TODO(mdempsky): Investigate whether this still happens.
 +              // If we know we don't need to emit code for a type,
 +              // we should have a link-symbol index for it.
 +              // See also TODO in NeedEmit.
 +              return lsym
        }
  
        ot := 0
@@@ -1210,6 -1226,83 +1210,6 @@@ func InterfaceMethodOffset(ityp *types.
        return int64(commonSize()+4*types.PtrSize+uncommonSize(ityp)) + i*8
  }
  
 -// for each itabEntry, gather the methods on
 -// the concrete type that implement the interface
 -func CompileITabs() {
 -      for i := range itabs {
 -              tab := &itabs[i]
 -              methods := genfun(tab.t, tab.itype)
 -              if len(methods) == 0 {
 -                      continue
 -              }
 -              tab.entries = methods
 -      }
 -}
 -
 -// for the given concrete type and interface
 -// type, return the (sorted) set of methods
 -// on the concrete type that implement the interface
 -func genfun(t, it *types.Type) []*obj.LSym {
 -      if t == nil || it == nil {
 -              return nil
 -      }
 -      sigs := imethods(it)
 -      methods := methods(t)
 -      out := make([]*obj.LSym, 0, len(sigs))
 -      // TODO(mdempsky): Short circuit before calling methods(t)?
 -      // See discussion on CL 105039.
 -      if len(sigs) == 0 {
 -              return nil
 -      }
 -
 -      // both sigs and methods are sorted by name,
 -      // so we can find the intersect in a single pass
 -      for _, m := range methods {
 -              if m.name == sigs[0].name {
 -                      out = append(out, m.isym)
 -                      sigs = sigs[1:]
 -                      if len(sigs) == 0 {
 -                              break
 -                      }
 -              }
 -      }
 -
 -      if len(sigs) != 0 {
 -              base.Fatalf("incomplete itab")
 -      }
 -
 -      return out
 -}
 -
 -// ITabSym uses the information gathered in
 -// CompileITabs to de-virtualize interface methods.
 -// Since this is called by the SSA backend, it shouldn't
 -// generate additional Nodes, Syms, etc.
 -func ITabSym(it *obj.LSym, offset int64) *obj.LSym {
 -      var syms []*obj.LSym
 -      if it == nil {
 -              return nil
 -      }
 -
 -      for i := range itabs {
 -              e := &itabs[i]
 -              if e.lsym == it {
 -                      syms = e.entries
 -                      break
 -              }
 -      }
 -      if syms == nil {
 -              return nil
 -      }
 -
 -      // keep this arithmetic in sync with *itab layout
 -      methodnum := int((offset - 2*int64(types.PtrSize) - 8) / int64(types.PtrSize))
 -      if methodnum >= len(syms) {
 -              return nil
 -      }
 -      return syms[methodnum]
 -}
 -
  // NeedRuntimeType ensures that a runtime type descriptor is emitted for t.
  func NeedRuntimeType(t *types.Type) {
        if t.HasTParam() {
@@@ -1256,57 -1349,29 +1256,57 @@@ func WriteRuntimeTypes() 
        }
  }
  
 -func WriteTabs() {
 -      // process itabs
 -      for _, i := range itabs {
 -              // dump empty itab symbol into i.sym
 -              // type itab struct {
 -              //   inter  *interfacetype
 -              //   _type  *_type
 -              //   hash   uint32
 -              //   _      [4]byte
 -              //   fun    [1]uintptr // variable sized
 -              // }
 -              o := objw.SymPtr(i.lsym, 0, writeType(i.itype), 0)
 -              o = objw.SymPtr(i.lsym, o, writeType(i.t), 0)
 -              o = objw.Uint32(i.lsym, o, types.TypeHash(i.t)) // copy of type hash
 -              o += 4                                          // skip unused field
 -              for _, fn := range genfun(i.t, i.itype) {
 -                      o = objw.SymPtrWeak(i.lsym, o, fn, 0) // method pointer for each method
 +// writeITab writes the itab for concrete type typ implementing
 +// interface iface.
 +func writeITab(lsym *obj.LSym, typ, iface *types.Type) {
 +      // TODO(mdempsky): Fix methodWrapper, geneq, and genhash (and maybe
 +      // others) to stop clobbering these.
 +      oldpos, oldfn := base.Pos, ir.CurFunc
 +      defer func() { base.Pos, ir.CurFunc = oldpos, oldfn }()
 +
 +      if typ == nil || (typ.IsPtr() && typ.Elem() == nil) || typ.IsUntyped() || iface == nil || !iface.IsInterface() || iface.IsEmptyInterface() {
 +              base.Fatalf("writeITab(%v, %v)", typ, iface)
 +      }
 +
 +      sigs := iface.AllMethods().Slice()
 +      entries := make([]*obj.LSym, 0, len(sigs))
 +
 +      // both sigs and methods are sorted by name,
 +      // so we can find the intersection in a single pass
 +      for _, m := range methods(typ) {
 +              if m.name == sigs[0].Sym {
 +                      entries = append(entries, m.isym)
 +                      sigs = sigs[1:]
 +                      if len(sigs) == 0 {
 +                              break
 +                      }
                }
 -              // Nothing writes static itabs, so they are read only.
 -              objw.Global(i.lsym, int32(o), int16(obj.DUPOK|obj.RODATA))
 -              i.lsym.Set(obj.AttrContentAddressable, true)
 +      }
 +      if len(sigs) != 0 {
 +              base.Fatalf("incomplete itab")
        }
  
 +      // dump empty itab symbol into i.sym
 +      // type itab struct {
 +      //   inter  *interfacetype
 +      //   _type  *_type
 +      //   hash   uint32
 +      //   _      [4]byte
 +      //   fun    [1]uintptr // variable sized
 +      // }
 +      o := objw.SymPtr(lsym, 0, writeType(iface), 0)
 +      o = objw.SymPtr(lsym, o, writeType(typ), 0)
 +      o = objw.Uint32(lsym, o, types.TypeHash(typ)) // copy of type hash
 +      o += 4                                        // skip unused field
 +      for _, fn := range entries {
 +              o = objw.SymPtrWeak(lsym, o, fn, 0) // method pointer for each method
 +      }
 +      // Nothing writes static itabs, so they are read only.
 +      objw.Global(lsym, int32(o), int16(obj.DUPOK|obj.RODATA))
 +      lsym.Set(obj.AttrContentAddressable, true)
 +}
 +
 +func WriteTabs() {
        // process ptabs
        if types.LocalPkg.Name == "main" && len(ptabs) > 0 {
                ot := 0
@@@ -1388,7 -1453,7 +1388,7 @@@ func WriteBasicTypes() 
  
  type typeAndStr struct {
        t       *types.Type
 -      short   string
 +      short   string // "short" here means NameString
        regular string
  }
  
@@@ -1401,13 -1466,8 +1401,13 @@@ func (a typesByString) Less(i, j int) b
        }
        // When the only difference between the types is whether
        // they refer to byte or uint8, such as **byte vs **uint8,
 -      // the types' ShortStrings can be identical.
 +      // the types' NameStrings can be identical.
        // To preserve deterministic sort ordering, sort these by String().
 +      //
 +      // TODO(mdempsky): This all seems suspect. Using LinkString would
 +      // avoid naming collisions, and there shouldn't be a reason to care
 +      // about "byte" vs "uint8": they share the same runtime type
 +      // descriptor anyway.
        if a[i].regular != a[j].regular {
                return a[i].regular < a[j].regular
        }
@@@ -1681,44 -1741,6 +1681,44 @@@ func CollectPTabs() 
        }
  }
  
 +// NeedEmit reports whether typ is a type that we need to emit code
 +// for (e.g., runtime type descriptors, method wrappers).
 +func NeedEmit(typ *types.Type) bool {
 +      // TODO(mdempsky): Export data should keep track of which anonymous
 +      // and instantiated types were emitted, so at least downstream
 +      // packages can skip re-emitting them.
 +      //
 +      // Perhaps we can just generalize the linker-symbol indexing to
 +      // track the index of arbitrary types, not just defined types, and
 +      // use its presence to detect this. The same idea would work for
 +      // instantiated generic functions too.
 +
 +      switch sym := typ.Sym(); {
 +      case sym == nil:
 +              // Anonymous type; possibly never seen before or ever again.
 +              // Need to emit to be safe (however, see TODO above).
 +              return true
 +
 +      case sym.Pkg == types.LocalPkg:
 +              // Local defined type; our responsibility.
 +              return true
 +
 +      case base.Ctxt.Pkgpath == "runtime" && (sym.Pkg == types.BuiltinPkg || sym.Pkg == ir.Pkgs.Unsafe):
 +              // Package runtime is responsible for including code for builtin
 +              // types (predeclared and package unsafe).
 +              return true
 +
 +      case typ.IsFullyInstantiated():
 +              // Instantiated type; possibly instantiated with unique type arguments.
 +              // Need to emit to be safe (however, see TODO above).
 +              return true
 +
 +      default:
 +              // Should have been emitted by an imported package.
 +              return false
 +      }
 +}
 +
  // Generate a wrapper function to convert from
  // a receiver of type T to a receiver of type U.
  // That is,
  //
  //    rcvr - U
  //    method - M func (t T)(), a TFIELD type struct
 -func methodWrapper(rcvr *types.Type, method *types.Field) *obj.LSym {
 +//
 +// Also wraps methods on instantiated generic types for use in itab entries.
 +// For an instantiated generic type G[int], we generate wrappers like:
 +// G[int] pointer shaped:
 +//    func (x G[int]) f(arg) {
 +//            .inst.G[int].f(dictionary, x, arg)
 +//    }
 +// G[int] not pointer shaped:
 +//    func (x *G[int]) f(arg) {
 +//            .inst.G[int].f(dictionary, *x, arg)
 +//    }
 +// These wrappers are always fully stenciled.
 +func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSym {
 +      orig := rcvr
 +      if forItab && !types.IsDirectIface(rcvr) {
 +              rcvr = rcvr.PtrTo()
 +      }
 +      generic := false
 +      if !types.IsInterfaceMethod(method.Type) &&
 +              (len(rcvr.RParams()) > 0 ||
 +                      rcvr.IsPtr() && len(rcvr.Elem().RParams()) > 0) { // TODO: right detection?
 +              // Don't need dictionary if we are reaching a method (possibly via
 +              // an embedded field) which is an interface method.
 +              // TODO: check that we do the right thing when method is an interface method.
 +              generic = true
 +      }
        newnam := ir.MethodSym(rcvr, method.Sym)
        lsym := newnam.Linksym()
        if newnam.Siggen() {
        }
        newnam.SetSiggen(true)
  
 -      if types.Identical(rcvr, method.Type.Recv().Type) {
 -              return lsym
 +      // Except in quirks mode, unified IR creates its own wrappers.
 +      // Complain loudly if it missed any.
 +      if base.Debug.Unified != 0 && base.Debug.UnifiedQuirks == 0 {
 +              base.FatalfAt(method.Pos, "missing wrapper for %+v (%+v, %v) / %+v / %+v", rcvr, orig, types.IsDirectIface(orig), method.Sym, newnam)
        }
  
 -      // Only generate (*T).M wrappers for T.M in T's own package.
 -      if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type &&
 -              rcvr.Elem().Sym() != nil && rcvr.Elem().Sym().Pkg != types.LocalPkg {
 +      if !generic && types.Identical(rcvr, method.Type.Recv().Type) {
                return lsym
        }
  
 -      // Only generate I.M wrappers for I in I's own package
 -      // but keep doing it for error.Error (was issue #29304).
 -      if rcvr.IsInterface() && rcvr.Sym() != nil && rcvr.Sym().Pkg != types.LocalPkg && rcvr != types.ErrorType {
 +      if !NeedEmit(rcvr) || rcvr.IsPtr() && !NeedEmit(rcvr.Elem()) {
                return lsym
        }
  
        nthis := ir.AsNode(tfn.Type().Recv().Nname)
  
        methodrcvr := method.Type.Recv().Type
 +      indirect := rcvr.IsPtr() && rcvr.Elem() == methodrcvr
  
        // generate nil pointer check for better error
 -      if rcvr.IsPtr() && rcvr.Elem() == methodrcvr {
 +      if indirect {
                // generating wrapper from *T to T.
                n := ir.NewIfStmt(base.Pos, nil, nil, nil)
                n.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, nthis, typecheck.NodNil())
        }
  
        dot := typecheck.AddImplicitDots(ir.NewSelectorExpr(base.Pos, ir.OXDOT, nthis, method.Sym))
 -
        // generate call
        // It's not possible to use a tail call when dynamic linking on ppc64le. The
        // bad scenario is when a local call is made to the wrapper: the wrapper will
        // Disable tailcall for RegabiArgs for now. The IR does not connect the
        // arguments with the OTAILCALL node, and the arguments are not marshaled
        // correctly.
 -      if !base.Flag.Cfg.Instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !types.IsInterfaceMethod(method.Type) && !(base.Ctxt.Arch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) && !buildcfg.Experiment.RegabiArgs {
 +      if !base.Flag.Cfg.Instrumenting && rcvr.IsPtr() && methodrcvr.IsPtr() && method.Embedded != 0 && !types.IsInterfaceMethod(method.Type) && !(base.Ctxt.Arch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) && !buildcfg.Experiment.RegabiArgs && !generic {
                // generate tail call: adjust pointer receiver and jump to embedded method.
                left := dot.X // skip final .M
                if !left.Type().IsPtr() {
                fn.Body.Append(ir.NewTailCallStmt(base.Pos, method.Nname.(*ir.Name)))
        } else {
                fn.SetWrapper(true) // ignore frame for panic+recover matching
 -              call := ir.NewCallExpr(base.Pos, ir.OCALL, dot, nil)
 -              call.Args = ir.ParamNames(tfn.Type())
 +              var call *ir.CallExpr
 +
 +              if generic && dot.X != nthis {
 +                      // TODO: for now, we don't try to generate dictionary wrappers for
 +                      // any methods involving embedded fields, because we're not
 +                      // generating the needed dictionaries in instantiateMethods.
 +                      generic = false
 +              }
 +
 +              if generic {
 +                      var args []ir.Node
 +                      var targs []*types.Type
 +                      if rcvr.IsPtr() { // TODO: correct condition?
 +                              targs = rcvr.Elem().RParams()
 +                      } else {
 +                              targs = rcvr.RParams()
 +                      }
 +                      if strings.HasPrefix(ir.MethodSym(orig, method.Sym).Name, ".inst.") {
 +                              fmt.Printf("%s\n", ir.MethodSym(orig, method.Sym).Name)
 +                              panic("multiple .inst.")
 +                      }
 +                      // Temporary fix: the wrapper for an auto-generated
 +                      // pointer/non-pointer receiver method should share the
 +                      // same dictionary as the corresponding original
 +                      // (user-written) method.
 +                      baseOrig := orig
 +                      if baseOrig.IsPtr() && !method.Type.Recv().Type.IsPtr() {
 +                              baseOrig = baseOrig.Elem()
 +                      } else if !baseOrig.IsPtr() && method.Type.Recv().Type.IsPtr() {
 +                              baseOrig = types.NewPtr(baseOrig)
 +                      }
 +                      args = append(args, getDictionary(ir.MethodSym(baseOrig, method.Sym), targs))
 +                      if indirect {
 +                              args = append(args, ir.NewStarExpr(base.Pos, dot.X))
 +                      } else if methodrcvr.IsPtr() && methodrcvr.Elem() == dot.X.Type() {
 +                              // Case where method call is via a non-pointer
 +                              // embedded field with a pointer method.
 +                              args = append(args, typecheck.NodAddrAt(base.Pos, dot.X))
 +                      } else {
 +                              args = append(args, dot.X)
 +                      }
 +                      args = append(args, ir.ParamNames(tfn.Type())...)
 +
 +                      // TODO: Once we enter the gcshape world, we'll need a way to look up
 +                      // the stenciled implementation to use for this concrete type. Essentially,
 +                      // erase the concrete types and replace them with gc shape representatives.
 +                      sym := typecheck.MakeInstName(ir.MethodSym(methodrcvr, method.Sym), targs, true)
 +                      if sym.Def == nil {
 +                              // Currently we make sure that we have all the instantiations
 +                              // we need by generating them all in ../noder/stencil.go:instantiateMethods
 +                              // TODO: maybe there's a better, more incremental way to generate
 +                              // only the instantiations we need?
 +                              base.Fatalf("instantiation %s not found", sym.Name)
 +                      }
 +                      target := ir.AsNode(sym.Def)
 +                      call = ir.NewCallExpr(base.Pos, ir.OCALL, target, args)
 +                      // Fill-in the generic method node that was not filled in
 +                      // in instantiateMethod.
 +                      method.Nname = fn.Nname
 +              } else {
 +                      call = ir.NewCallExpr(base.Pos, ir.OCALL, dot, nil)
 +                      call.Args = ir.ParamNames(tfn.Type())
 +              }
                call.IsDDD = tfn.Type().IsVariadic()
                if method.Type.NumResults() > 0 {
                        ret := ir.NewReturnStmt(base.Pos, nil)
        ir.CurFunc = fn
        typecheck.Stmts(fn.Body)
  
 -      // Inline calls within (*T).M wrappers. This is safe because we only
 -      // generate those wrappers within the same compilation unit as (T).M.
 -      // TODO(mdempsky): Investigate why we can't enable this more generally.
 -      if rcvr.IsPtr() && rcvr.Elem() == method.Type.Recv().Type && rcvr.Elem().Sym() != nil {
 +      if AfterGlobalEscapeAnalysis {
                inline.InlineCalls(fn)
 +              escape.Batch([]*ir.Func{fn}, false)
        }
 -      escape.Batch([]*ir.Func{fn}, false)
  
        ir.CurFunc = nil
        typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
        return lsym
  }
  
 +// AfterGlobalEscapeAnalysis tracks whether package gc has already
 +// performed the main, global escape analysis pass. If so,
 +// methodWrapper takes responsibility for escape analyzing any
 +// generated wrappers.
 +var AfterGlobalEscapeAnalysis bool
 +
  var ZeroSize int64
  
  // MarkTypeUsedInInterface marks that type t is converted to an interface.
@@@ -1968,35 -1903,3 +1968,35 @@@ func MarkUsedIfaceMethod(n *ir.CallExpr
        r.Add = InterfaceMethodOffset(ityp, midx)
        r.Type = objabi.R_USEIFACEMETHOD
  }
 +
 +// getDictionary returns the dictionary for the given named generic function
 +// or method, with the given type arguments.
 +func getDictionary(gf *types.Sym, targs []*types.Type) ir.Node {
 +      if len(targs) == 0 {
 +              base.Fatalf("%s should have type arguments", gf.Name)
 +      }
 +
 +      sym := typecheck.MakeDictName(gf, targs, true)
 +
 +      // Initialize the dictionary, if we haven't yet already.
 +      if lsym := sym.Linksym(); len(lsym.P) == 0 {
 +              base.Fatalf("Dictionary should have already been generated: %s.%s", sym.Pkg.Path, sym.Name)
 +      }
 +
 +      // Make a node referencing the dictionary symbol.
 +      n := typecheck.NewName(sym)
 +      n.SetType(types.Types[types.TUINTPTR]) // should probably be [...]uintptr, but doesn't really matter
 +      n.SetTypecheck(1)
 +      n.Class = ir.PEXTERN
 +      sym.Def = n
 +
 +      // Return the address of the dictionary.
 +      np := typecheck.NodAddr(n)
 +      // Note: treat dictionary pointers as uintptrs, so they aren't pointers
 +      // with respect to GC. That saves on stack scanning work, write barriers, etc.
 +      // We can get away with it because dictionaries are global variables.
 +      // TODO: use a cast, or is typing directly ok?
 +      np.SetType(types.Types[types.TUINTPTR])
 +      np.SetTypecheck(1)
 +      return np
 +}
index 095b795d0366f214beab85d8de317a38eb0e78b7,8b988952a78d2c689714ddfe2d61260fcdb75e19..a52dd060a015e4c5d7322adb6fa1a60e8daa9c9a
@@@ -109,14 -109,18 +109,18 @@@ func sconv(s *Sym, verb rune, mode fmtM
                return "<S>"
        }
  
-       if s.Name == "_" {
-               return "_"
+       q := pkgqual(s.Pkg, verb, mode)
+       if q == "" {
+               return s.Name
        }
        buf := fmtBufferPool.Get().(*bytes.Buffer)
        buf.Reset()
        defer fmtBufferPool.Put(buf)
  
-       symfmt(buf, s, verb, mode)
+       buf.WriteString(q)
+       buf.WriteByte('.')
+       buf.WriteString(s.Name)
        return InternString(buf.Bytes())
  }
  
@@@ -128,56 -132,49 +132,49 @@@ func sconv2(b *bytes.Buffer, s *Sym, ve
                b.WriteString("<S>")
                return
        }
-       if s.Name == "_" {
-               b.WriteString("_")
-               return
-       }
  
        symfmt(b, s, verb, mode)
  }
  
  func symfmt(b *bytes.Buffer, s *Sym, verb rune, mode fmtMode) {
+       if q := pkgqual(s.Pkg, verb, mode); q != "" {
+               b.WriteString(q)
+               b.WriteByte('.')
+       }
+       b.WriteString(s.Name)
+ }
+ // pkgqual returns the qualifier that should be used for printing
+ // symbols from the given package in the given mode.
+ // If it returns the empty string, no qualification is needed.
+ func pkgqual(pkg *Pkg, verb rune, mode fmtMode) string {
        if verb != 'S' {
                switch mode {
                case fmtGo: // This is for the user
-                       if s.Pkg == BuiltinPkg || s.Pkg == LocalPkg {
-                               b.WriteString(s.Name)
-                               return
+                       if pkg == BuiltinPkg || pkg == LocalPkg {
+                               return ""
                        }
  
                        // If the name was used by multiple packages, display the full path,
-                       if s.Pkg.Name != "" && NumImport[s.Pkg.Name] > 1 {
-                               fmt.Fprintf(b, "%q.%s", s.Pkg.Path, s.Name)
-                               return
+                       if pkg.Name != "" && NumImport[pkg.Name] > 1 {
+                               return strconv.Quote(pkg.Path)
                        }
-                       b.WriteString(s.Pkg.Name)
-                       b.WriteByte('.')
-                       b.WriteString(s.Name)
-                       return
+                       return pkg.Name
  
                case fmtDebug:
-                       b.WriteString(s.Pkg.Name)
-                       b.WriteByte('.')
-                       b.WriteString(s.Name)
-                       return
+                       return pkg.Name
  
                case fmtTypeIDName:
                        // dcommontype, typehash
-                       b.WriteString(s.Pkg.Name)
-                       b.WriteByte('.')
-                       b.WriteString(s.Name)
-                       return
+                       return pkg.Name
  
                case fmtTypeID:
                        // (methodsym), typesym, weaksym
-                       b.WriteString(s.Pkg.Prefix)
-                       b.WriteByte('.')
-                       b.WriteString(s.Name)
-                       return
+                       return pkg.Prefix
                }
        }
  
-       b.WriteString(s.Name)
+       return ""
  }
  
  // Type
@@@ -242,37 -239,17 +239,37 @@@ func (t *Type) String() string 
        return tconv(t, 0, fmtGo)
  }
  
 -// ShortString generates a short description of t.
 -// It is used in autogenerated method names, reflection,
 -// and itab names.
 -func (t *Type) ShortString() string {
 +// LinkString returns an unexpanded string description of t, suitable
 +// for use in link symbols. "Unexpanded" here means that the
 +// description uses `"".` to qualify identifiers from the current
 +// package, and "expansion" refers to the renaming step performed by
 +// the linker to replace these qualifiers with proper `path/to/pkg.`
 +// qualifiers.
 +//
 +// After expansion, the description corresponds to type identity. That
 +// is, for any pair of types t1 and t2, Identical(t1, t2) and
 +// expand(t1.LinkString()) == expand(t2.LinkString()) report the same
 +// value.
 +//
 +// Within a single compilation unit, LinkString always returns the
 +// same unexpanded description for identical types. Thus it's safe to
 +// use as a map key to implement a type-identity-keyed map. However,
 +// make sure all LinkString calls used for this purpose happen within
 +// the same compile process; the string keys are not stable across
 +// multiple processes.
 +func (t *Type) LinkString() string {
        return tconv(t, 0, fmtTypeID)
  }
  
 -// LongString generates a complete description of t.
 -// It is useful for reflection,
 -// or when a unique fingerprint or hash of a type is required.
 -func (t *Type) LongString() string {
 +// NameString generates a user-readable, mostly unique string
 +// description of t. NameString always returns the same description
 +// for identical types, even across compilation units.
 +//
 +// NameString qualifies identifiers by package name, so it has
 +// collisions when different packages share the same names and
 +// identifiers. It also does not distinguish function-scope defined
 +// types from package-scoped defined types or from each other.
 +func (t *Type) NameString() string {
        return tconv(t, 0, fmtTypeIDName)
  }
  
@@@ -339,34 -316,31 +336,34 @@@ func tconv2(b *bytes.Buffer, t *Type, v
  
        // Unless the 'L' flag was specified, if the type has a name, just print that name.
        if verb != 'L' && t.Sym() != nil && t != Types[t.Kind()] {
 -              switch mode {
 -              case fmtTypeID, fmtTypeIDName:
 -                      if verb == 'S' {
 -                              if t.Vargen != 0 {
 -                                      sconv2(b, t.Sym(), 'S', mode)
 -                                      fmt.Fprintf(b, "·%d", t.Vargen)
 -                                      return
 -                              }
 -                              sconv2(b, t.Sym(), 'S', mode)
 -                              return
 -                      }
 +              // Default to 'v' if verb is invalid.
 +              if verb != 'S' {
 +                      verb = 'v'
 +              }
  
 -                      if mode == fmtTypeIDName {
 -                              sconv2(b, t.Sym(), 'v', fmtTypeIDName)
 -                              return
 +              // In unified IR, function-scope defined types will have a ·N
 +              // suffix embedded directly in their Name. Trim this off for
 +              // non-fmtTypeID modes.
 +              sym := t.Sym()
 +              if mode != fmtTypeID {
 +                      i := len(sym.Name)
 +                      for i > 0 && sym.Name[i-1] >= '0' && sym.Name[i-1] <= '9' {
 +                              i--
                        }
 -
 -                      if t.Sym().Pkg == LocalPkg && t.Vargen != 0 {
 -                              sconv2(b, t.Sym(), 'v', mode)
 -                              fmt.Fprintf(b, "·%d", t.Vargen)
 -                              return
 +                      const dot = "·"
 +                      if i >= len(dot) && sym.Name[i-len(dot):i] == dot {
 +                              sym = &Sym{Pkg: sym.Pkg, Name: sym.Name[:i-len(dot)]}
                        }
                }
 -
 -              sconv2(b, t.Sym(), 'v', mode)
 +              sconv2(b, sym, verb, mode)
 +
 +              // TODO(mdempsky): Investigate including Vargen in fmtTypeIDName
 +              // output too. It seems like it should, but that mode is currently
 +              // used in string representation used by reflection, which is
 +              // user-visible and doesn't expect this.
 +              if mode == fmtTypeID && t.Vargen != 0 {
 +                      fmt.Fprintf(b, "·%d", t.Vargen)
 +              }
                return
        }
  
@@@ -697,7 -671,7 +694,7 @@@ func FmtConst(v constant.Value, sharp b
  
  // TypeHash computes a hash value for type t to use in type switch statements.
  func TypeHash(t *Type) uint32 {
 -      p := t.LongString()
 +      p := t.NameString()
  
        // Using MD5 is overkill, but reduces accidental collisions.
        h := md5.Sum([]byte(p))
diff --combined src/reflect/type.go
index e119354af422fa6265ce6bed57769c432f9e2f90,f672a7a5d5fc996e93a38c4c99fddd4fee76a687..278426da09e3a6431cc518d7488839f906266f88
@@@ -16,7 -16,6 +16,7 @@@
  package reflect
  
  import (
 +      "internal/goarch"
        "internal/unsafeheader"
        "strconv"
        "sync"
@@@ -229,7 -228,7 +229,7 @@@ type Type interface 
  // See https://golang.org/issue/4876 for more details.
  
  /*
-  * These data structures are known to the compiler (../../cmd/internal/gc/reflect.go).
+  * These data structures are known to the compiler (../../cmd/internal/reflectdata/reflect.go).
   * A few are known to ../runtime/type.go to convey to debuggers.
   * They are also known to ../runtime/type.go.
   */
@@@ -272,7 -271,7 +272,7 @@@ const 
  // available in the memory directly following the rtype value.
  //
  // tflag values must be kept in sync with copies in:
- //    cmd/compile/internal/gc/reflect.go
+ //    cmd/compile/internal/reflectdata/reflect.go
  //    cmd/link/internal/ld/decodesym.go
  //    runtime/type.go
  type tflag uint8
@@@ -1911,7 -1910,7 +1911,7 @@@ func MapOf(key, elem Type) Type 
  
        // Make a map type.
        // Note: flag values must match those used in the TMAP case
-       // in ../cmd/compile/internal/gc/reflect.go:writeType.
+       // in ../cmd/compile/internal/reflectdata/reflect.go:writeType.
        var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil)
        mt := **(**mapType)(unsafe.Pointer(&imap))
        mt.str = resolveReflectName(newName(s, "", false))
        }
        mt.flags = 0
        if ktyp.size > maxKeySize {
 -              mt.keysize = uint8(ptrSize)
 +              mt.keysize = uint8(goarch.PtrSize)
                mt.flags |= 1 // indirect key
        } else {
                mt.keysize = uint8(ktyp.size)
        }
        if etyp.size > maxValSize {
 -              mt.valuesize = uint8(ptrSize)
 +              mt.valuesize = uint8(goarch.PtrSize)
                mt.flags |= 2 // indirect value
        } else {
                mt.valuesize = uint8(etyp.size)
@@@ -2232,31 -2231,31 +2232,31 @@@ func bucketOf(ktyp, etyp *rtype) *rtyp
        var ptrdata uintptr
        var overflowPad uintptr
  
 -      size := bucketSize*(1+ktyp.size+etyp.size) + overflowPad + ptrSize
 +      size := bucketSize*(1+ktyp.size+etyp.size) + overflowPad + goarch.PtrSize
        if size&uintptr(ktyp.align-1) != 0 || size&uintptr(etyp.align-1) != 0 {
                panic("reflect: bad size computation in MapOf")
        }
  
        if ktyp.ptrdata != 0 || etyp.ptrdata != 0 {
 -              nptr := (bucketSize*(1+ktyp.size+etyp.size) + ptrSize) / ptrSize
 +              nptr := (bucketSize*(1+ktyp.size+etyp.size) + goarch.PtrSize) / goarch.PtrSize
                mask := make([]byte, (nptr+7)/8)
 -              base := bucketSize / ptrSize
 +              base := bucketSize / goarch.PtrSize
  
                if ktyp.ptrdata != 0 {
                        emitGCMask(mask, base, ktyp, bucketSize)
                }
 -              base += bucketSize * ktyp.size / ptrSize
 +              base += bucketSize * ktyp.size / goarch.PtrSize
  
                if etyp.ptrdata != 0 {
                        emitGCMask(mask, base, etyp, bucketSize)
                }
 -              base += bucketSize * etyp.size / ptrSize
 -              base += overflowPad / ptrSize
 +              base += bucketSize * etyp.size / goarch.PtrSize
 +              base += overflowPad / goarch.PtrSize
  
                word := base
                mask[word/8] |= 1 << (word % 8)
                gcdata = &mask[0]
 -              ptrdata = (word + 1) * ptrSize
 +              ptrdata = (word + 1) * goarch.PtrSize
  
                // overflow word must be last
                if ptrdata != size {
        }
  
        b := &rtype{
 -              align:   ptrSize,
 +              align:   goarch.PtrSize,
                size:    size,
                kind:    uint8(Struct),
                ptrdata: ptrdata,
@@@ -2289,8 -2288,8 +2289,8 @@@ func emitGCMask(out []byte, base uintpt
        if typ.kind&kindGCProg != 0 {
                panic("reflect: unexpected GC program")
        }
 -      ptrs := typ.ptrdata / ptrSize
 -      words := typ.size / ptrSize
 +      ptrs := typ.ptrdata / goarch.PtrSize
 +      words := typ.size / goarch.PtrSize
        mask := typ.gcSlice(0, (ptrs+7)/8)
        for j := uintptr(0); j < ptrs; j++ {
                if (mask[j/8]>>(j%8))&1 != 0 {
@@@ -2313,7 -2312,7 +2313,7 @@@ func appendGCProg(dst []byte, typ *rtyp
        }
  
        // Element is small with pointer mask; use as literal bits.
 -      ptrs := typ.ptrdata / ptrSize
 +      ptrs := typ.ptrdata / goarch.PtrSize
        mask := typ.gcSlice(0, (ptrs+7)/8)
  
        // Emit 120-bit chunks of full bytes (max is 127 but we avoid using partial bytes).
@@@ -2760,7 -2759,7 +2760,7 @@@ func StructOf(fields []StructField) Typ
                        }
                        // Pad to start of this field with zeros.
                        if ft.offset() > off {
 -                              n := (ft.offset() - off) / ptrSize
 +                              n := (ft.offset() - off) / goarch.PtrSize
                                prog = append(prog, 0x01, 0x00) // emit a 0 bit
                                if n > 1 {
                                        prog = append(prog, 0x81)      // repeat previous bit
@@@ -2842,7 -2841,7 +2842,7 @@@ func runtimeStructField(field StructFie
  
  // typeptrdata returns the length in bytes of the prefix of t
  // containing pointer data. Anything after this offset is scalar data.
- // keep in sync with ../cmd/compile/internal/gc/reflect.go
+ // keep in sync with ../cmd/compile/internal/reflectdata/reflect.go
  func typeptrdata(t *rtype) uintptr {
        switch t.Kind() {
        case Struct:
        }
  }
  
- // See cmd/compile/internal/gc/reflect.go for derivation of constant.
+ // See cmd/compile/internal/reflectdata/reflect.go for derivation of constant.
  const maxPtrmaskBytes = 2048
  
  // ArrayOf returns the array type with the given length and element type.
@@@ -2937,11 -2936,11 +2937,11 @@@ func ArrayOf(length int, elem Type) Typ
                array.gcdata = typ.gcdata
                array.ptrdata = typ.ptrdata
  
 -      case typ.kind&kindGCProg == 0 && array.size <= maxPtrmaskBytes*8*ptrSize:
 +      case typ.kind&kindGCProg == 0 && array.size <= maxPtrmaskBytes*8*goarch.PtrSize:
                // Element is small with pointer mask; array is still small.
                // Create direct pointer mask by turning each 1 bit in elem
                // into length 1 bits in larger mask.
 -              mask := make([]byte, (array.ptrdata/ptrSize+7)/8)
 +              mask := make([]byte, (array.ptrdata/goarch.PtrSize+7)/8)
                emitGCMask(mask, 0, typ, array.len)
                array.gcdata = &mask[0]
  
                prog := []byte{0, 0, 0, 0} // will be length of prog
                prog = appendGCProg(prog, typ)
                // Pad from ptrdata to size.
 -              elemPtrs := typ.ptrdata / ptrSize
 -              elemWords := typ.size / ptrSize
 +              elemPtrs := typ.ptrdata / goarch.PtrSize
 +              elemWords := typ.size / goarch.PtrSize
                if elemPtrs < elemWords {
                        // Emit literal 0 bit, then repeat as needed.
                        prog = append(prog, 0x01, 0x00)
@@@ -3064,13 -3063,13 +3064,13 @@@ func funcLayout(t *funcType, rcvr *rtyp
  
        // build dummy rtype holding gc program
        x := &rtype{
 -              align: ptrSize,
 +              align: goarch.PtrSize,
                // Don't add spill space here; it's only necessary in
                // reflectcall's frame, not in the allocated frame.
                // TODO(mknyszek): Remove this comment when register
                // spill space in the frame is no longer required.
 -              size:    align(abi.retOffset+abi.ret.stackBytes, ptrSize),
 -              ptrdata: uintptr(abi.stackPtrs.n) * ptrSize,
 +              size:    align(abi.retOffset+abi.ret.stackBytes, goarch.PtrSize),
 +              ptrdata: uintptr(abi.stackPtrs.n) * goarch.PtrSize,
        }
        if abi.stackPtrs.n > 0 {
                x.gcdata = &abi.stackPtrs.data[0]
@@@ -3125,14 -3124,14 +3125,14 @@@ func addTypeBits(bv *bitVector, offset 
        switch Kind(t.kind & kindMask) {
        case Chan, Func, Map, Ptr, Slice, String, UnsafePointer:
                // 1 pointer at start of representation
 -              for bv.n < uint32(offset/uintptr(ptrSize)) {
 +              for bv.n < uint32(offset/uintptr(goarch.PtrSize)) {
                        bv.append(0)
                }
                bv.append(1)
  
        case Interface:
                // 2 pointers
 -              for bv.n < uint32(offset/uintptr(ptrSize)) {
 +              for bv.n < uint32(offset/uintptr(goarch.PtrSize)) {
                        bv.append(0)
                }
                bv.append(1)
diff --combined src/runtime/runtime2.go
index 579592930148c900505f1ee782e5ff9e9a5a91b4,2a66826f34bb8d1b0af42326dc93276380339b59..d557ee8a3e49379fce0b69223bb8416b22382277
@@@ -5,8 -5,8 +5,8 @@@
  package runtime
  
  import (
 +      "internal/goarch"
        "runtime/internal/atomic"
 -      "runtime/internal/sys"
        "unsafe"
  )
  
@@@ -505,7 -505,7 +505,7 @@@ const 
        // tlsSlots is the number of pointer-sized slots reserved for TLS on some platforms,
        // like Windows.
        tlsSlots = 6
 -      tlsSize  = tlsSlots * sys.PtrSize
 +      tlsSize  = tlsSlots * goarch.PtrSize
  )
  
  type m struct {
@@@ -613,8 -613,8 +613,8 @@@ type p struct 
        pcache      pageCache
        raceprocctx uintptr
  
 -      deferpool    [5][]*_defer // pool of available defer structs of different sizes (see panic.go)
 -      deferpoolbuf [5][32]*_defer
 +      deferpool    []*_defer // pool of available defer structs (see panic.go)
 +      deferpoolbuf [32]*_defer
  
        // Cache of goroutine ids, amortizes accesses to runtime·sched.goidgen.
        goidcache    uint64
@@@ -801,9 -801,9 +801,9 @@@ type schedt struct 
        sudoglock  mutex
        sudogcache *sudog
  
 -      // Central pool of available defer structs of different sizes.
 +      // Central pool of available defer structs.
        deferlock mutex
 -      deferpool [5]*_defer
 +      deferpool *_defer
  
        // freem is the list of m's waiting to be freed when their
        // m.exited is set. Linked through m.freelink.
@@@ -895,7 -895,7 +895,7 @@@ type funcinl struct 
  // layout of Itab known to compilers
  // allocated in non-garbage-collected memory
  // Needs to be in sync with
- // ../cmd/compile/internal/gc/reflect.go:/^func.WriteTabs.
+ // ../cmd/compile/internal/reflectdata/reflect.go:/^func.WriteTabs.
  type itab struct {
        inter *interfacetype
        _type *_type
@@@ -930,7 -930,7 +930,7 @@@ func extendRandom(r []byte, n int) 
                        w = 16
                }
                h := memhash(unsafe.Pointer(&r[n-w]), uintptr(nanotime()), uintptr(w))
 -              for i := 0; i < sys.PtrSize && n < len(r); i++ {
 +              for i := 0; i < goarch.PtrSize && n < len(r); i++ {
                        r[n] = byte(h)
                        n++
                        h >>= 8
  
  // A _defer holds an entry on the list of deferred calls.
  // If you add a field here, add code to clear it in freedefer and deferProcStack
 -// This struct must match the code in cmd/compile/internal/reflectdata/reflect.go:deferstruct
 -// and cmd/compile/internal/gc/ssa.go:(*state).call.
 +// This struct must match the code in cmd/compile/internal/ssagen/ssa.go:deferstruct
 +// and cmd/compile/internal/ssagen/ssa.go:(*state).call.
  // Some defers will be allocated on the stack and some on the heap.
  // All defers are logically part of the stack, so write barriers to
  // initialize them are not required. All defers must be manually scanned,
  // and for heap defers, marked.
  type _defer struct {
 -      siz     int32 // includes both arguments and results
        started bool
        heap    bool
        // openDefer indicates that this _defer is for a frame with open-coded
diff --combined src/runtime/select.go
index 74f0c291944ecdf4678c9683dbcefbde5c5f500d,06edb69f429ba0c1ac01279de0204d10e71bda8a..ee1f95ffa9ed304fa82aaf562356ea6b10110eea
@@@ -7,7 -7,6 +7,7 @@@ package runtim
  // This file contains the implementation of Go select statements.
  
  import (
 +      "internal/abi"
        "runtime/internal/atomic"
        "unsafe"
  )
@@@ -16,15 -15,15 +16,15 @@@ const debugSelect = fals
  
  // Select case descriptor.
  // Known to compiler.
- // Changes here must also be made in src/cmd/internal/gc/select.go's scasetype.
+ // Changes here must also be made in src/cmd/compile/internal/walk/select.go's scasetype.
  type scase struct {
        c    *hchan         // chan
        elem unsafe.Pointer // data element
  }
  
  var (
 -      chansendpc = funcPC(chansend)
 -      chanrecvpc = funcPC(chanrecv)
 +      chansendpc = abi.FuncPCABIInternal(chansend)
 +      chanrecvpc = abi.FuncPCABIInternal(chanrecv)
  )
  
  func selectsetpc(pc *uintptr) {
diff --combined src/runtime/type.go
index 52e65a3bd23bb310933291a6fecb57a2413e5cc5,4039273695b106746a0582386c8834c72d6b4f15..ad01d5095e5088ad8d99d007452316b810cb2c98
@@@ -6,15 -6,12 +6,15 @@@
  
  package runtime
  
 -import "unsafe"
 +import (
 +      "internal/abi"
 +      "unsafe"
 +)
  
  // tflag is documented in reflect/type.go.
  //
  // tflag values must be kept in sync with copies in:
- //    cmd/compile/internal/gc/reflect.go
+ //    cmd/compile/internal/reflectdata/reflect.go
  //    cmd/link/internal/ld/decodesym.go
  //    reflect/type.go
  //      internal/reflectlite/type.go
@@@ -28,7 -25,7 +28,7 @@@ const 
  )
  
  // Needs to be in sync with ../cmd/link/internal/ld/decodesym.go:/^func.commonsize,
- // ../cmd/compile/internal/gc/reflect.go:/^func.dcommontype and
+ // ../cmd/compile/internal/reflectdata/reflect.go:/^func.dcommontype and
  // ../reflect/type.go:/^type.rtype.
  // ../internal/reflectlite/type.go:/^type.rtype.
  type _type struct {
@@@ -265,7 -262,7 +265,7 @@@ func (t *_type) textOff(off textOff) un
        if off == -1 {
                // -1 is the sentinel value for unreachable code.
                // See cmd/link/internal/ld/data.go:relocsym.
 -              return unsafe.Pointer(funcPC(unreachableMethod))
 +              return unsafe.Pointer(abi.FuncPCABIInternal(unreachableMethod))
        }
        base := uintptr(unsafe.Pointer(t))
        var md *moduledata
@@@ -386,7 -383,7 +386,7 @@@ type maptype struct 
  }
  
  // Note: flag values must match those used in the TMAP case
- // in ../cmd/compile/internal/gc/reflect.go:writeType.
+ // in ../cmd/compile/internal/reflectdata/reflect.go:writeType.
  func (mt *maptype) indirectkey() bool { // store ptr to key instead of key itself
        return mt.flags&1 != 0
  }