@@ -7,11 +7,13 @@ package ir
77import (
88 "cmd/compile/internal/base"
99 "cmd/compile/internal/types"
10+ "cmd/internal/hash"
1011 "cmd/internal/obj"
1112 "cmd/internal/objabi"
1213 "cmd/internal/src"
14+ "encoding/base64"
1315 "fmt"
14- "strings "
16+ "io "
1517 "unicode/utf8"
1618)
1719
@@ -430,10 +432,9 @@ func ClosureDebugRuntimeCheck(clo *ClosureExpr) {
430432var globClosgen int32
431433
432434// closureName generates a new unique name for a closure within outerfn at pos.
433- func closureName (outerfn * Func , pos src.XPos , why Op ) * types.Sym {
434- if outerfn .OClosure != nil && outerfn .OClosure .Func .RangeParent != nil {
435- outerfn = outerfn .OClosure .Func .RangeParent
436- }
435+ // gen is an optional counter for the closure name. If it is 0, the counter
436+ // will be computed based on outerfn.
437+ func closureName (outerfn * Func , pos src.XPos , why Op , gen int ) * types.Sym {
437438 pkg := types .LocalPkg
438439 outer := "glob."
439440 var suffix string = "."
@@ -451,38 +452,64 @@ func closureName(outerfn *Func, pos src.XPos, why Op) *types.Sym {
451452 case ODEFER :
452453 suffix = ".deferwrap"
453454 }
454- gen := & globClosgen
455455
456456 // There may be multiple functions named "_". In those
457457 // cases, we can't use their individual Closgens as it
458458 // would lead to name clashes.
459459 if ! IsBlank (outerfn .Nname ) {
460460 pkg = outerfn .Sym ().Pkg
461461 outer = FuncName (outerfn )
462-
463- switch why {
464- case OCLOSURE :
465- gen = & outerfn .funcLitGen
466- case ORANGE :
467- gen = & outerfn .rangeLitGen
468- default :
469- gen = & outerfn .goDeferGen
470- }
471462 }
472463
473- // If this closure was created due to inlining, then incorporate any
474- // inlined functions' names into the closure's linker symbol name
475- // too (#60324).
464+ // If this closure was created due to inlining, find the original
465+ // outer function's name for the closure (#60324).
466+ var inlHash string
476467 if inlIndex := base .Ctxt .InnermostPos (pos ).Base ().InliningIndex (); inlIndex >= 0 {
477- names := []string {outer }
468+ // The compiler doesn't like multiple symbols with the same
469+ // name. We make a unique suffix temporarily for the
470+ // compiler, and strip it during object file writing, so
471+ // it will not be the linker symbol name. For linking,
472+ // we use a content hash to disambiguate instead.
473+ // We choose the suffix as a hash of the inline call stack.
474+ h := hash .New32 ()
475+ io .WriteString (h , outer )
478476 base .Ctxt .InlTree .AllParents (inlIndex , func (call obj.InlinedCall ) {
479- names = append ( names , call .Name )
477+ io . WriteString ( h , call .Name + ":" + call . Pos . LineNumber () + ":" + call . Pos . ColumnNumber () )
480478 })
481- outer = strings .Join (names , "." )
479+ inlHash = base64 .StdEncoding .EncodeToString (h .Sum (nil )[:8 ])
480+
481+ outer = base .Ctxt .InlTree .InlinedFuncName (inlIndex )
482+ if pkgPath := base .Ctxt .InlTree .InlinedFuncPkg (inlIndex ); pkgPath != "" {
483+ pkg = types .NewPkg (pkgPath , "" )
484+ }
482485 }
483486
484- * gen ++
485- return pkg .Lookup (fmt .Sprintf ("%s%s%d" , outer , suffix , * gen ))
487+ if gen == 0 {
488+ p := & globClosgen
489+ if ! IsBlank (outerfn .Nname ) {
490+ switch why {
491+ case OCLOSURE :
492+ p = & outerfn .funcLitGen
493+ case ORANGE :
494+ p = & outerfn .rangeLitGen
495+ default :
496+ p = & outerfn .goDeferGen
497+ }
498+ }
499+ * p ++
500+ gen = int (* p )
501+ }
502+
503+ name := fmt .Sprintf ("%s%s%d" , outer , suffix , gen )
504+ if inlHash != "" {
505+ // Attach the inline hash (see the comment above).
506+ // If it already has a hash, trim it, so we don't include
507+ // two hashes for nested closures. The new hash should be
508+ // enough to disambiguate.
509+ name = obj .TrimInlineHash (name ) + "#" + inlHash + "#"
510+ }
511+
512+ return pkg .Lookup (name )
486513}
487514
488515// NewClosureFunc creates a new Func to represent a function literal
@@ -500,14 +527,19 @@ func closureName(outerfn *Func, pos src.XPos, why Op) *types.Sym {
500527// why is the reason we're generating this Func. It can be OCLOSURE
501528// (for a normal function literal) or OGO or ODEFER (for wrapping a
502529// call expression that has parameters or results).
503- func NewClosureFunc (fpos , cpos src.XPos , why Op , typ * types.Type , outerfn * Func , pkg * Package ) * Func {
530+ //
531+ // gen is an optional counter for the closure name. If it is 0,
532+ // the counter will be computed based on outerfn.
533+ func NewClosureFunc (fpos , cpos src.XPos , why Op , typ * types.Type , outerfn * Func , pkg * Package , gen int ) * Func {
504534 if outerfn == nil {
505535 base .FatalfAt (fpos , "outerfn is nil" )
506536 }
507537
508- fn := NewFunc (fpos , fpos , closureName (outerfn , cpos , why ), typ )
538+ fn := NewFunc (fpos , fpos , closureName (outerfn , cpos , why , gen ), typ )
509539 fn .SetDupok (outerfn .Dupok ()) // if the outer function is dupok, so is the closure
510540
541+ fn .Linksym ().Set (obj .AttrContentAddressable , true )
542+
511543 clo := & ClosureExpr {Func : fn }
512544 clo .op = OCLOSURE
513545 clo .pos = cpos
0 commit comments