github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/cmd/compile/internal/gc/scope.go (about) 1 // Copyright 2017 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 gc 6 7 import ( 8 "cmd/internal/dwarf" 9 "cmd/internal/obj" 10 "cmd/internal/src" 11 "sort" 12 ) 13 14 // See golang.org/issue/20390. 15 func xposBefore(p, q src.XPos) bool { 16 return Ctxt.PosTable.Pos(p).Before(Ctxt.PosTable.Pos(q)) 17 } 18 19 func findScope(marks []Mark, pos src.XPos) ScopeID { 20 i := sort.Search(len(marks), func(i int) bool { 21 return xposBefore(pos, marks[i].Pos) 22 }) 23 if i == 0 { 24 return 0 25 } 26 return marks[i-1].Scope 27 } 28 29 func assembleScopes(fnsym *obj.LSym, fn *Node, dwarfVars []*dwarf.Var, varScopes []ScopeID) []dwarf.Scope { 30 // Initialize the DWARF scope tree based on lexical scopes. 31 dwarfScopes := make([]dwarf.Scope, 1+len(fn.Func.Parents)) 32 for i, parent := range fn.Func.Parents { 33 dwarfScopes[i+1].Parent = int32(parent) 34 } 35 36 scopeVariables(dwarfVars, varScopes, dwarfScopes) 37 scopePCs(fnsym, fn.Func.Marks, dwarfScopes) 38 return compactScopes(dwarfScopes) 39 } 40 41 // scopeVariables assigns DWARF variable records to their scopes. 42 func scopeVariables(dwarfVars []*dwarf.Var, varScopes []ScopeID, dwarfScopes []dwarf.Scope) { 43 sort.Stable(varsByScopeAndOffset{dwarfVars, varScopes}) 44 45 i0 := 0 46 for i := range dwarfVars { 47 if varScopes[i] == varScopes[i0] { 48 continue 49 } 50 dwarfScopes[varScopes[i0]].Vars = dwarfVars[i0:i] 51 i0 = i 52 } 53 if i0 < len(dwarfVars) { 54 dwarfScopes[varScopes[i0]].Vars = dwarfVars[i0:] 55 } 56 } 57 58 // A scopedPCs represents a non-empty half-open interval of PCs that 59 // share a common source position. 60 type scopedPCs struct { 61 start, end int64 62 pos src.XPos 63 scope ScopeID 64 } 65 66 // scopePCs assigns PC ranges to their scopes. 67 func scopePCs(fnsym *obj.LSym, marks []Mark, dwarfScopes []dwarf.Scope) { 68 // If there aren't any child scopes (in particular, when scope 69 // tracking is disabled), we can skip a whole lot of work. 70 if len(marks) == 0 { 71 return 72 } 73 74 // Break function text into scopedPCs. 75 var pcs []scopedPCs 76 p0 := fnsym.Func.Text 77 for p := fnsym.Func.Text; p != nil; p = p.Link { 78 if p.Pos == p0.Pos { 79 continue 80 } 81 if p0.Pc < p.Pc { 82 pcs = append(pcs, scopedPCs{start: p0.Pc, end: p.Pc, pos: p0.Pos}) 83 } 84 p0 = p 85 } 86 if p0.Pc < fnsym.Size { 87 pcs = append(pcs, scopedPCs{start: p0.Pc, end: fnsym.Size, pos: p0.Pos}) 88 } 89 90 // Assign scopes to each chunk of instructions. 91 for i := range pcs { 92 pcs[i].scope = findScope(marks, pcs[i].pos) 93 } 94 95 // Create sorted PC ranges for each DWARF scope. 96 for _, pc := range pcs { 97 r := &dwarfScopes[pc.scope].Ranges 98 if i := len(*r); i > 0 && (*r)[i-1].End == pc.start { 99 (*r)[i-1].End = pc.end 100 } else { 101 *r = append(*r, dwarf.Range{Start: pc.start, End: pc.end}) 102 } 103 } 104 } 105 106 func compactScopes(dwarfScopes []dwarf.Scope) []dwarf.Scope { 107 // Reverse pass to propagate PC ranges to parent scopes. 108 for i := len(dwarfScopes) - 1; i > 0; i-- { 109 s := &dwarfScopes[i] 110 dwarfScopes[s.Parent].UnifyRanges(s) 111 } 112 113 return dwarfScopes 114 } 115 116 type varsByScopeAndOffset struct { 117 vars []*dwarf.Var 118 scopes []ScopeID 119 } 120 121 func (v varsByScopeAndOffset) Len() int { 122 return len(v.vars) 123 } 124 125 func (v varsByScopeAndOffset) Less(i, j int) bool { 126 if v.scopes[i] != v.scopes[j] { 127 return v.scopes[i] < v.scopes[j] 128 } 129 return v.vars[i].StackOffset < v.vars[j].StackOffset 130 } 131 132 func (v varsByScopeAndOffset) Swap(i, j int) { 133 v.vars[i], v.vars[j] = v.vars[j], v.vars[i] 134 v.scopes[i], v.scopes[j] = v.scopes[j], v.scopes[i] 135 }