blob: 93582e1373e27223b472b0b96f81e39120dfbccb [file] [log] [blame]
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package ssa
import (
"cmd/internal/src"
"fmt"
)
type lineRange struct {
first, last uint32
}
// An xposmap is a map from fileindex and line of src.XPos to int32,
// implemented sparsely to save space (column and statement status are ignored).
// The sparse skeleton is constructed once, and then reused by ssa phases
// that (re)move values with statements attached.
type xposmap struct {
// A map from file index to maps from line range to integers (block numbers)
maps map[int32]*biasedSparseMap
// The next two fields provide a single-item cache for common case of repeated lines from same file.
lastIndex int32 // -1 means no entry in cache
lastMap *biasedSparseMap // map found at maps[lastIndex]
}
// newXposmap constructs an xposmap valid for inputs which have a file index in the keys of x,
// and line numbers in the range x[file index].
// The resulting xposmap will panic if a caller attempts to set or add an XPos not in that range.
func newXposmap(x map[int]lineRange) *xposmap {
maps := make(map[int32]*biasedSparseMap)
for i, p := range x {
maps[int32(i)] = newBiasedSparseMap(int(p.first), int(p.last))
}
return &xposmap{maps: maps, lastIndex: -1} // zero for the rest is okay
}
// clear removes data from the map but leaves the sparse skeleton.
func (m *xposmap) clear() {
for _, l := range m.maps {
if l != nil {
l.clear()
}
}
m.lastIndex = -1
m.lastMap = nil
}
// mapFor returns the line range map for a given file index.
func (m *xposmap) mapFor(index int32) *biasedSparseMap {
if index == m.lastIndex {
return m.lastMap
}
mf := m.maps[index]
m.lastIndex = index
m.lastMap = mf
return mf
}
// set inserts p->v into the map.
// If p does not fall within the set of fileindex->lineRange used to construct m, this will panic.
func (m *xposmap) set(p src.XPos, v int32) {
s := m.mapFor(p.FileIndex())
if s == nil {
panic(fmt.Sprintf("xposmap.set(%d), file index not found in map\n", p.FileIndex()))
}
s.set(p.Line(), v)
}
// get returns the int32 associated with the file index and line of p.
func (m *xposmap) get(p src.XPos) int32 {
s := m.mapFor(p.FileIndex())
if s == nil {
return -1
}
return s.get(p.Line())
}
// add adds p to m, treating m as a set instead of as a map.
// If p does not fall within the set of fileindex->lineRange used to construct m, this will panic.
// Use clear() in between set/map interpretations of m.
func (m *xposmap) add(p src.XPos) {
m.set(p, 0)
}
// contains returns whether the file index and line of p are in m,
// treating m as a set instead of as a map.
func (m *xposmap) contains(p src.XPos) bool {
s := m.mapFor(p.FileIndex())
if s == nil {
return false
}
return s.contains(p.Line())
}
// remove removes the file index and line for p from m,
// whether m is currently treated as a map or set.
func (m *xposmap) remove(p src.XPos) {
s := m.mapFor(p.FileIndex())
if s == nil {
return
}
s.remove(p.Line())
}
// foreachEntry applies f to each (fileindex, line, value) triple in m.
func (m *xposmap) foreachEntry(f func(j int32, l uint, v int32)) {
for j, mm := range m.maps {
s := mm.size()
for i := 0; i < s; i++ {
l, v := mm.getEntry(i)
f(j, l, v)
}
}
}