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  }