| |
| |
| |
|
|
| package coverage |
|
|
| |
| |
| |
| |
| |
| |
|
|
| import ( |
| "cmd/compile/internal/base" |
| "cmd/compile/internal/ir" |
| "cmd/compile/internal/typecheck" |
| "cmd/compile/internal/types" |
| "cmd/internal/objabi" |
| "internal/coverage" |
| "strconv" |
| "strings" |
| ) |
|
|
| |
| |
| type names struct { |
| MetaVar *ir.Name |
| PkgIdVar *ir.Name |
| InitFn *ir.Func |
| CounterMode coverage.CounterMode |
| CounterGran coverage.CounterGranularity |
| } |
|
|
| |
| |
| |
| |
| |
| |
| func Fixup() { |
| if base.Flag.Cfg.CoverageInfo == nil { |
| return |
| } |
|
|
| metaVarName := base.Flag.Cfg.CoverageInfo.MetaVar |
| pkgIdVarName := base.Flag.Cfg.CoverageInfo.PkgIdVar |
| counterMode := base.Flag.Cfg.CoverageInfo.CounterMode |
| counterGran := base.Flag.Cfg.CoverageInfo.CounterGranularity |
| counterPrefix := base.Flag.Cfg.CoverageInfo.CounterPrefix |
| var metavar *ir.Name |
| var pkgidvar *ir.Name |
|
|
| ckTypSanity := func(nm *ir.Name, tag string) { |
| if nm.Type() == nil || nm.Type().HasPointers() { |
| base.Fatalf("unsuitable %s %q mentioned in coveragecfg, improper type '%v'", tag, nm.Sym().Name, nm.Type()) |
| } |
| } |
|
|
| for _, nm := range typecheck.Target.Externs { |
| s := nm.Sym() |
| switch s.Name { |
| case metaVarName: |
| metavar = nm |
| ckTypSanity(nm, "metavar") |
| nm.MarkReadonly() |
| continue |
| case pkgIdVarName: |
| pkgidvar = nm |
| ckTypSanity(nm, "pkgidvar") |
| nm.SetCoverageAuxVar(true) |
| s := nm.Linksym() |
| s.Type = objabi.SCOVERAGE_AUXVAR |
| continue |
| } |
| if strings.HasPrefix(s.Name, counterPrefix) { |
| ckTypSanity(nm, "countervar") |
| nm.SetCoverageAuxVar(true) |
| s := nm.Linksym() |
| s.Type = objabi.SCOVERAGE_COUNTER |
| } |
| } |
| cm := coverage.ParseCounterMode(counterMode) |
| if cm == coverage.CtrModeInvalid { |
| base.Fatalf("bad setting %q for covermode in coveragecfg:", |
| counterMode) |
| } |
| var cg coverage.CounterGranularity |
| switch counterGran { |
| case "perblock": |
| cg = coverage.CtrGranularityPerBlock |
| case "perfunc": |
| cg = coverage.CtrGranularityPerFunc |
| default: |
| base.Fatalf("bad setting %q for covergranularity in coveragecfg:", |
| counterGran) |
| } |
|
|
| cnames := names{ |
| MetaVar: metavar, |
| PkgIdVar: pkgidvar, |
| CounterMode: cm, |
| CounterGran: cg, |
| } |
|
|
| for _, fn := range typecheck.Target.Funcs { |
| if ir.FuncName(fn) == "init" { |
| cnames.InitFn = fn |
| break |
| } |
| } |
| if cnames.InitFn == nil { |
| panic("unexpected (no init func for -cover build)") |
| } |
|
|
| hashv, len := metaHashAndLen() |
| if cnames.CounterMode != coverage.CtrModeTestMain { |
| registerMeta(cnames, hashv, len) |
| } |
| if base.Ctxt.Pkgpath == "main" { |
| addInitHookCall(cnames.InitFn, cnames.CounterMode) |
| } |
| } |
|
|
| func metaHashAndLen() ([16]byte, int) { |
|
|
| |
| mhash := base.Flag.Cfg.CoverageInfo.MetaHash |
| if len(mhash) != 32 { |
| base.Fatalf("unexpected: got metahash length %d want 32", len(mhash)) |
| } |
| var hv [16]byte |
| for i := 0; i < 16; i++ { |
| nib := mhash[i*2 : i*2+2] |
| x, err := strconv.ParseInt(nib, 16, 32) |
| if err != nil { |
| base.Fatalf("metahash bad byte %q", nib) |
| } |
| hv[i] = byte(x) |
| } |
|
|
| |
| return hv, base.Flag.Cfg.CoverageInfo.MetaLen |
| } |
|
|
| func registerMeta(cnames names, hashv [16]byte, mdlen int) { |
| |
| pos := cnames.InitFn.Pos() |
| elist := make([]ir.Node, 0, 16) |
| for i := 0; i < 16; i++ { |
| elem := ir.NewInt(base.Pos, int64(hashv[i])) |
| elist = append(elist, elem) |
| } |
| ht := types.NewArray(types.Types[types.TUINT8], 16) |
| hashx := ir.NewCompLitExpr(pos, ir.OCOMPLIT, ht, elist) |
|
|
| |
| mdax := typecheck.NodAddr(cnames.MetaVar) |
| mdauspx := typecheck.ConvNop(mdax, types.Types[types.TUNSAFEPTR]) |
|
|
| |
| lenx := ir.NewInt(base.Pos, int64(mdlen)) |
|
|
| |
| |
| |
| |
| fn := typecheck.LookupRuntime("addCovMeta") |
| pkid := coverage.HardCodedPkgID(base.Ctxt.Pkgpath) |
| pkIdNode := ir.NewInt(base.Pos, int64(pkid)) |
| cmodeNode := ir.NewInt(base.Pos, int64(cnames.CounterMode)) |
| cgranNode := ir.NewInt(base.Pos, int64(cnames.CounterGran)) |
| pkPathNode := ir.NewString(base.Pos, base.Ctxt.Pkgpath) |
| callx := typecheck.Call(pos, fn, []ir.Node{mdauspx, lenx, hashx, |
| pkPathNode, pkIdNode, cmodeNode, cgranNode}, false) |
| assign := callx |
| if pkid == coverage.NotHardCoded { |
| assign = typecheck.Stmt(ir.NewAssignStmt(pos, cnames.PkgIdVar, callx)) |
| } |
|
|
| |
| |
| |
| cnames.InitFn.Body.Prepend(assign) |
| } |
|
|
| |
| |
| |
| |
| func addInitHookCall(initfn *ir.Func, cmode coverage.CounterMode) { |
| typecheck.InitCoverage() |
| pos := initfn.Pos() |
| istest := cmode == coverage.CtrModeTestMain |
| initf := typecheck.LookupCoverage("initHook") |
| istestNode := ir.NewBool(base.Pos, istest) |
| args := []ir.Node{istestNode} |
| callx := typecheck.Call(pos, initf, args, false) |
| initfn.Body.Append(callx) |
| } |
|
|