github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/dwarfgen/marker.go (about) 1 // Copyright 2021 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 dwarfgen 6 7 import ( 8 "github.com/go-asm/go/cmd/compile/base" 9 "github.com/go-asm/go/cmd/compile/ir" 10 "github.com/go-asm/go/cmd/src" 11 ) 12 13 // A ScopeMarker tracks scope nesting and boundaries for later use 14 // during DWARF generation. 15 type ScopeMarker struct { 16 parents []ir.ScopeID 17 marks []ir.Mark 18 } 19 20 // checkPos validates the given position and returns the current scope. 21 func (m *ScopeMarker) checkPos(pos src.XPos) ir.ScopeID { 22 if !pos.IsKnown() { 23 base.Fatalf("unknown scope position") 24 } 25 26 if len(m.marks) == 0 { 27 return 0 28 } 29 30 last := &m.marks[len(m.marks)-1] 31 if xposBefore(pos, last.Pos) { 32 base.FatalfAt(pos, "non-monotonic scope positions\n\t%v: previous scope position", base.FmtPos(last.Pos)) 33 } 34 return last.Scope 35 } 36 37 // Push records a transition to a new child scope of the current scope. 38 func (m *ScopeMarker) Push(pos src.XPos) { 39 current := m.checkPos(pos) 40 41 m.parents = append(m.parents, current) 42 child := ir.ScopeID(len(m.parents)) 43 44 m.marks = append(m.marks, ir.Mark{Pos: pos, Scope: child}) 45 } 46 47 // Pop records a transition back to the current scope's parent. 48 func (m *ScopeMarker) Pop(pos src.XPos) { 49 current := m.checkPos(pos) 50 51 parent := m.parents[current-1] 52 53 m.marks = append(m.marks, ir.Mark{Pos: pos, Scope: parent}) 54 } 55 56 // Unpush removes the current scope, which must be empty. 57 func (m *ScopeMarker) Unpush() { 58 i := len(m.marks) - 1 59 current := m.marks[i].Scope 60 61 if current != ir.ScopeID(len(m.parents)) { 62 base.FatalfAt(m.marks[i].Pos, "current scope is not empty") 63 } 64 65 m.parents = m.parents[:current-1] 66 m.marks = m.marks[:i] 67 } 68 69 // WriteTo writes the recorded scope marks to the given function, 70 // and resets the marker for reuse. 71 func (m *ScopeMarker) WriteTo(fn *ir.Func) { 72 m.compactMarks() 73 74 fn.Parents = make([]ir.ScopeID, len(m.parents)) 75 copy(fn.Parents, m.parents) 76 m.parents = m.parents[:0] 77 78 fn.Marks = make([]ir.Mark, len(m.marks)) 79 copy(fn.Marks, m.marks) 80 m.marks = m.marks[:0] 81 } 82 83 func (m *ScopeMarker) compactMarks() { 84 n := 0 85 for _, next := range m.marks { 86 if n > 0 && next.Pos == m.marks[n-1].Pos { 87 m.marks[n-1].Scope = next.Scope 88 continue 89 } 90 m.marks[n] = next 91 n++ 92 } 93 m.marks = m.marks[:n] 94 }