diff options
Diffstat (limited to 'vendor/github.com/twitchyliquid64/golang-asm/src')
| -rw-r--r-- | vendor/github.com/twitchyliquid64/golang-asm/src/pos.go | 470 | ||||
| -rw-r--r-- | vendor/github.com/twitchyliquid64/golang-asm/src/xpos.go | 176 | 
2 files changed, 646 insertions, 0 deletions
| diff --git a/vendor/github.com/twitchyliquid64/golang-asm/src/pos.go b/vendor/github.com/twitchyliquid64/golang-asm/src/pos.go new file mode 100644 index 000000000..b6816a56e --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/src/pos.go @@ -0,0 +1,470 @@ +// Copyright 2016 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. + +// This file implements the encoding of source positions. + +package src + +import ( +	"bytes" +	"fmt" +	"io" +) + +// A Pos encodes a source position consisting of a (line, column) number pair +// and a position base. A zero Pos is a ready to use "unknown" position (nil +// position base and zero line number). +// +// The (line, column) values refer to a position in a file independent of any +// position base ("absolute" file position). +// +// The position base is used to determine the "relative" position, that is the +// filename and line number relative to the position base. If the base refers +// to the current file, there is no difference between absolute and relative +// positions. If it refers to a //line directive, a relative position is relative +// to that directive. A position base in turn contains the position at which it +// was introduced in the current file. +type Pos struct { +	base *PosBase +	lico +} + +// NoPos is a valid unknown position. +var NoPos Pos + +// MakePos creates a new Pos value with the given base, and (file-absolute) +// line and column. +func MakePos(base *PosBase, line, col uint) Pos { +	return Pos{base, makeLico(line, col)} +} + +// IsKnown reports whether the position p is known. +// A position is known if it either has a non-nil +// position base, or a non-zero line number. +func (p Pos) IsKnown() bool { +	return p.base != nil || p.Line() != 0 +} + +// Before reports whether the position p comes before q in the source. +// For positions in different files, ordering is by filename. +func (p Pos) Before(q Pos) bool { +	n, m := p.Filename(), q.Filename() +	return n < m || n == m && p.lico < q.lico +} + +// After reports whether the position p comes after q in the source. +// For positions in different files, ordering is by filename. +func (p Pos) After(q Pos) bool { +	n, m := p.Filename(), q.Filename() +	return n > m || n == m && p.lico > q.lico +} + +func (p Pos) LineNumber() string { +	if !p.IsKnown() { +		return "?" +	} +	return p.lico.lineNumber() +} + +func (p Pos) LineNumberHTML() string { +	if !p.IsKnown() { +		return "?" +	} +	return p.lico.lineNumberHTML() +} + +// Filename returns the name of the actual file containing this position. +func (p Pos) Filename() string { return p.base.Pos().RelFilename() } + +// Base returns the position base. +func (p Pos) Base() *PosBase { return p.base } + +// SetBase sets the position base. +func (p *Pos) SetBase(base *PosBase) { p.base = base } + +// RelFilename returns the filename recorded with the position's base. +func (p Pos) RelFilename() string { return p.base.Filename() } + +// RelLine returns the line number relative to the position's base. +func (p Pos) RelLine() uint { +	b := p.base +	if b.Line() == 0 { +		// base line is unknown => relative line is unknown +		return 0 +	} +	return b.Line() + (p.Line() - b.Pos().Line()) +} + +// RelCol returns the column number relative to the position's base. +func (p Pos) RelCol() uint { +	b := p.base +	if b.Col() == 0 { +		// base column is unknown => relative column is unknown +		// (the current specification for line directives requires +		// this to apply until the next PosBase/line directive, +		// not just until the new newline) +		return 0 +	} +	if p.Line() == b.Pos().Line() { +		// p on same line as p's base => column is relative to p's base +		return b.Col() + (p.Col() - b.Pos().Col()) +	} +	return p.Col() +} + +// AbsFilename() returns the absolute filename recorded with the position's base. +func (p Pos) AbsFilename() string { return p.base.AbsFilename() } + +// SymFilename() returns the absolute filename recorded with the position's base, +// prefixed by FileSymPrefix to make it appropriate for use as a linker symbol. +func (p Pos) SymFilename() string { return p.base.SymFilename() } + +func (p Pos) String() string { +	return p.Format(true, true) +} + +// Format formats a position as "filename:line" or "filename:line:column", +// controlled by the showCol flag and if the column is known (!= 0). +// For positions relative to line directives, the original position is +// shown as well, as in "filename:line[origfile:origline:origcolumn] if +// showOrig is set. +func (p Pos) Format(showCol, showOrig bool) string { +	buf := new(bytes.Buffer) +	p.WriteTo(buf, showCol, showOrig) +	return buf.String() +} + +// WriteTo a position to w, formatted as Format does. +func (p Pos) WriteTo(w io.Writer, showCol, showOrig bool) { +	if !p.IsKnown() { +		io.WriteString(w, "<unknown line number>") +		return +	} + +	if b := p.base; b == b.Pos().base { +		// base is file base (incl. nil) +		format(w, p.Filename(), p.Line(), p.Col(), showCol) +		return +	} + +	// base is relative +	// Print the column only for the original position since the +	// relative position's column information may be bogus (it's +	// typically generated code and we can't say much about the +	// original source at that point but for the file:line info +	// that's provided via a line directive). +	// TODO(gri) This may not be true if we have an inlining base. +	// We may want to differentiate at some point. +	format(w, p.RelFilename(), p.RelLine(), p.RelCol(), showCol) +	if showOrig { +		io.WriteString(w, "[") +		format(w, p.Filename(), p.Line(), p.Col(), showCol) +		io.WriteString(w, "]") +	} +} + +// format formats a (filename, line, col) tuple as "filename:line" (showCol +// is false or col == 0) or "filename:line:column" (showCol is true and col != 0). +func format(w io.Writer, filename string, line, col uint, showCol bool) { +	io.WriteString(w, filename) +	io.WriteString(w, ":") +	fmt.Fprint(w, line) +	// col == 0 and col == colMax are interpreted as unknown column values +	if showCol && 0 < col && col < colMax { +		io.WriteString(w, ":") +		fmt.Fprint(w, col) +	} +} + +// formatstr wraps format to return a string. +func formatstr(filename string, line, col uint, showCol bool) string { +	buf := new(bytes.Buffer) +	format(buf, filename, line, col, showCol) +	return buf.String() +} + +// ---------------------------------------------------------------------------- +// PosBase + +// A PosBase encodes a filename and base position. +// Typically, each file and line directive introduce a PosBase. +type PosBase struct { +	pos         Pos    // position at which the relative position is (line, col) +	filename    string // file name used to open source file, for error messages +	absFilename string // absolute file name, for PC-Line tables +	symFilename string // cached symbol file name, to avoid repeated string concatenation +	line, col   uint   // relative line, column number at pos +	inl         int    // inlining index (see cmd/internal/obj/inl.go) +} + +// NewFileBase returns a new *PosBase for a file with the given (relative and +// absolute) filenames. +func NewFileBase(filename, absFilename string) *PosBase { +	base := &PosBase{ +		filename:    filename, +		absFilename: absFilename, +		symFilename: FileSymPrefix + absFilename, +		line:        1, +		col:         1, +		inl:         -1, +	} +	base.pos = MakePos(base, 1, 1) +	return base +} + +// NewLinePragmaBase returns a new *PosBase for a line directive of the form +//      //line filename:line:col +//      /*line filename:line:col*/ +// at position pos. +func NewLinePragmaBase(pos Pos, filename, absFilename string, line, col uint) *PosBase { +	return &PosBase{pos, filename, absFilename, FileSymPrefix + absFilename, line, col, -1} +} + +// NewInliningBase returns a copy of the old PosBase with the given inlining +// index. If old == nil, the resulting PosBase has no filename. +func NewInliningBase(old *PosBase, inlTreeIndex int) *PosBase { +	if old == nil { +		base := &PosBase{line: 1, col: 1, inl: inlTreeIndex} +		base.pos = MakePos(base, 1, 1) +		return base +	} +	copy := *old +	base := © +	base.inl = inlTreeIndex +	if old == old.pos.base { +		base.pos.base = base +	} +	return base +} + +var noPos Pos + +// Pos returns the position at which base is located. +// If b == nil, the result is the zero position. +func (b *PosBase) Pos() *Pos { +	if b != nil { +		return &b.pos +	} +	return &noPos +} + +// Filename returns the filename recorded with the base. +// If b == nil, the result is the empty string. +func (b *PosBase) Filename() string { +	if b != nil { +		return b.filename +	} +	return "" +} + +// AbsFilename returns the absolute filename recorded with the base. +// If b == nil, the result is the empty string. +func (b *PosBase) AbsFilename() string { +	if b != nil { +		return b.absFilename +	} +	return "" +} + +const FileSymPrefix = "gofile.." + +// SymFilename returns the absolute filename recorded with the base, +// prefixed by FileSymPrefix to make it appropriate for use as a linker symbol. +// If b is nil, SymFilename returns FileSymPrefix + "??". +func (b *PosBase) SymFilename() string { +	if b != nil { +		return b.symFilename +	} +	return FileSymPrefix + "??" +} + +// Line returns the line number recorded with the base. +// If b == nil, the result is 0. +func (b *PosBase) Line() uint { +	if b != nil { +		return b.line +	} +	return 0 +} + +// Col returns the column number recorded with the base. +// If b == nil, the result is 0. +func (b *PosBase) Col() uint { +	if b != nil { +		return b.col +	} +	return 0 +} + +// InliningIndex returns the index into the global inlining +// tree recorded with the base. If b == nil or the base has +// not been inlined, the result is < 0. +func (b *PosBase) InliningIndex() int { +	if b != nil { +		return b.inl +	} +	return -1 +} + +// ---------------------------------------------------------------------------- +// lico + +// A lico is a compact encoding of a LIne and COlumn number. +type lico uint32 + +// Layout constants: 20 bits for line, 8 bits for column, 2 for isStmt, 2 for pro/epilogue +// (If this is too tight, we can either make lico 64b wide, +// or we can introduce a tiered encoding where we remove column +// information as line numbers grow bigger; similar to what gcc +// does.) +// The bitfield order is chosen to make IsStmt be the least significant +// part of a position; its use is to communicate statement edges through +// instruction scrambling in code generation, not to impose an order. +// TODO: Prologue and epilogue are perhaps better handled as pseudo-ops for the assembler, +// because they have almost no interaction with other uses of the position. +const ( +	lineBits, lineMax     = 20, 1<<lineBits - 2 +	bogusLine             = 1 // Used to disrupt infinite loops to prevent debugger looping +	isStmtBits, isStmtMax = 2, 1<<isStmtBits - 1 +	xlogueBits, xlogueMax = 2, 1<<xlogueBits - 1 +	colBits, colMax       = 32 - lineBits - xlogueBits - isStmtBits, 1<<colBits - 1 + +	isStmtShift = 0 +	isStmtMask  = isStmtMax << isStmtShift +	xlogueShift = isStmtBits + isStmtShift +	xlogueMask  = xlogueMax << xlogueShift +	colShift    = xlogueBits + xlogueShift +	lineShift   = colBits + colShift +) +const ( +	// It is expected that the front end or a phase in SSA will usually generate positions tagged with +	// PosDefaultStmt, but note statement boundaries with PosIsStmt.  Simple statements will have a single +	// boundary; for loops with initialization may have one for their entry and one for their back edge +	// (this depends on exactly how the loop is compiled; the intent is to provide a good experience to a +	// user debugging a program; the goal is that a breakpoint set on the loop line fires both on entry +	// and on iteration).  Proper treatment of non-gofmt input with multiple simple statements on a single +	// line is TBD. +	// +	// Optimizing compilation will move instructions around, and some of these will become known-bad as +	// step targets for debugging purposes (examples: register spills and reloads; code generated into +	// the entry block; invariant code hoisted out of loops) but those instructions will still have interesting +	// positions for profiling purposes. To reflect this these positions will be changed to PosNotStmt. +	// +	// When the optimizer removes an instruction marked PosIsStmt; it should attempt to find a nearby +	// instruction with the same line marked PosDefaultStmt to be the new statement boundary.  I.e., the +	// optimizer should make a best-effort to conserve statement boundary positions, and might be enhanced +	// to note when a statement boundary is not conserved. +	// +	// Code cloning, e.g. loop unrolling or loop unswitching, is an exception to the conservation rule +	// because a user running a debugger would expect to see breakpoints active in the copies of the code. +	// +	// In non-optimizing compilation there is still a role for PosNotStmt because of code generation +	// into the entry block.  PosIsStmt statement positions should be conserved. +	// +	// When code generation occurs any remaining default-marked positions are replaced with not-statement +	// positions. +	// +	PosDefaultStmt uint = iota // Default; position is not a statement boundary, but might be if optimization removes the designated statement boundary +	PosIsStmt                  // Position is a statement boundary; if optimization removes the corresponding instruction, it should attempt to find a new instruction to be the boundary. +	PosNotStmt                 // Position should not be a statement boundary, but line should be preserved for profiling and low-level debugging purposes. +) + +type PosXlogue uint + +const ( +	PosDefaultLogue PosXlogue = iota +	PosPrologueEnd +	PosEpilogueBegin +) + +func makeLicoRaw(line, col uint) lico { +	return lico(line<<lineShift | col<<colShift) +} + +// This is a not-position that will not be elided. +// Depending on the debugger (gdb or delve) it may or may not be displayed. +func makeBogusLico() lico { +	return makeLicoRaw(bogusLine, 0).withIsStmt() +} + +func makeLico(line, col uint) lico { +	if line > lineMax { +		// cannot represent line, use max. line so we have some information +		line = lineMax +	} +	if col > colMax { +		// cannot represent column, use max. column so we have some information +		col = colMax +	} +	// default is not-sure-if-statement +	return makeLicoRaw(line, col) +} + +func (x lico) Line() uint           { return uint(x) >> lineShift } +func (x lico) SameLine(y lico) bool { return 0 == (x^y)&^lico(1<<lineShift-1) } +func (x lico) Col() uint            { return uint(x) >> colShift & colMax } +func (x lico) IsStmt() uint { +	if x == 0 { +		return PosNotStmt +	} +	return uint(x) >> isStmtShift & isStmtMax +} +func (x lico) Xlogue() PosXlogue { +	return PosXlogue(uint(x) >> xlogueShift & xlogueMax) +} + +// withNotStmt returns a lico for the same location, but not a statement +func (x lico) withNotStmt() lico { +	return x.withStmt(PosNotStmt) +} + +// withDefaultStmt returns a lico for the same location, with default isStmt +func (x lico) withDefaultStmt() lico { +	return x.withStmt(PosDefaultStmt) +} + +// withIsStmt returns a lico for the same location, tagged as definitely a statement +func (x lico) withIsStmt() lico { +	return x.withStmt(PosIsStmt) +} + +// withLogue attaches a prologue/epilogue attribute to a lico +func (x lico) withXlogue(xlogue PosXlogue) lico { +	if x == 0 { +		if xlogue == 0 { +			return x +		} +		// Normalize 0 to "not a statement" +		x = lico(PosNotStmt << isStmtShift) +	} +	return lico(uint(x) & ^uint(xlogueMax<<xlogueShift) | (uint(xlogue) << xlogueShift)) +} + +// withStmt returns a lico for the same location with specified is_stmt attribute +func (x lico) withStmt(stmt uint) lico { +	if x == 0 { +		return lico(0) +	} +	return lico(uint(x) & ^uint(isStmtMax<<isStmtShift) | (stmt << isStmtShift)) +} + +func (x lico) lineNumber() string { +	return fmt.Sprintf("%d", x.Line()) +} + +func (x lico) lineNumberHTML() string { +	if x.IsStmt() == PosDefaultStmt { +		return fmt.Sprintf("%d", x.Line()) +	} +	style, pfx := "b", "+" +	if x.IsStmt() == PosNotStmt { +		style = "s" // /strike not supported in HTML5 +		pfx = "" +	} +	return fmt.Sprintf("<%s>%s%d</%s>", style, pfx, x.Line(), style) +} + +func (x lico) atColumn1() lico { +	return makeLico(x.Line(), 1).withIsStmt() +} diff --git a/vendor/github.com/twitchyliquid64/golang-asm/src/xpos.go b/vendor/github.com/twitchyliquid64/golang-asm/src/xpos.go new file mode 100644 index 000000000..867d0ab06 --- /dev/null +++ b/vendor/github.com/twitchyliquid64/golang-asm/src/xpos.go @@ -0,0 +1,176 @@ +// Copyright 2016 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. + +// This file implements the compressed encoding of source +// positions using a lookup table. + +package src + +// XPos is a more compact representation of Pos. +type XPos struct { +	index int32 +	lico +} + +// NoXPos is a valid unknown position. +var NoXPos XPos + +// IsKnown reports whether the position p is known. +// XPos.IsKnown() matches Pos.IsKnown() for corresponding +// positions. +func (p XPos) IsKnown() bool { +	return p.index != 0 || p.Line() != 0 +} + +// Before reports whether the position p comes before q in the source. +// For positions with different bases, ordering is by base index. +func (p XPos) Before(q XPos) bool { +	n, m := p.index, q.index +	return n < m || n == m && p.lico < q.lico +} + +// SameFile reports whether p and q are positions in the same file. +func (p XPos) SameFile(q XPos) bool { +	return p.index == q.index +} + +// SameFileAndLine reports whether p and q are positions on the same line in the same file. +func (p XPos) SameFileAndLine(q XPos) bool { +	return p.index == q.index && p.lico.SameLine(q.lico) +} + +// After reports whether the position p comes after q in the source. +// For positions with different bases, ordering is by base index. +func (p XPos) After(q XPos) bool { +	n, m := p.index, q.index +	return n > m || n == m && p.lico > q.lico +} + +// WithNotStmt returns the same location to be marked with DWARF is_stmt=0 +func (p XPos) WithNotStmt() XPos { +	p.lico = p.lico.withNotStmt() +	return p +} + +// WithDefaultStmt returns the same location with undetermined is_stmt +func (p XPos) WithDefaultStmt() XPos { +	p.lico = p.lico.withDefaultStmt() +	return p +} + +// WithIsStmt returns the same location to be marked with DWARF is_stmt=1 +func (p XPos) WithIsStmt() XPos { +	p.lico = p.lico.withIsStmt() +	return p +} + +// WithBogusLine returns a bogus line that won't match any recorded for the source code. +// Its use is to disrupt the statements within an infinite loop so that the debugger +// will not itself loop infinitely waiting for the line number to change. +// gdb chooses not to display the bogus line; delve shows it with a complaint, but the +// alternative behavior is to hang. +func (p XPos) WithBogusLine() XPos { +	if p.index == 0 { +		// See #35652 +		panic("Assigning a bogus line to XPos with no file will cause mysterious downstream failures.") +	} +	p.lico = makeBogusLico() +	return p +} + +// WithXlogue returns the same location but marked with DWARF function prologue/epilogue +func (p XPos) WithXlogue(x PosXlogue) XPos { +	p.lico = p.lico.withXlogue(x) +	return p +} + +// LineNumber returns a string for the line number, "?" if it is not known. +func (p XPos) LineNumber() string { +	if !p.IsKnown() { +		return "?" +	} +	return p.lico.lineNumber() +} + +// FileIndex returns a smallish non-negative integer corresponding to the +// file for this source position.  Smallish is relative; it can be thousands +// large, but not millions. +func (p XPos) FileIndex() int32 { +	return p.index +} + +func (p XPos) LineNumberHTML() string { +	if !p.IsKnown() { +		return "?" +	} +	return p.lico.lineNumberHTML() +} + +// AtColumn1 returns the same location but shifted to column 1. +func (p XPos) AtColumn1() XPos { +	p.lico = p.lico.atColumn1() +	return p +} + +// A PosTable tracks Pos -> XPos conversions and vice versa. +// Its zero value is a ready-to-use PosTable. +type PosTable struct { +	baseList []*PosBase +	indexMap map[*PosBase]int +	nameMap  map[string]int // Maps file symbol name to index for debug information. +} + +// XPos returns the corresponding XPos for the given pos, +// adding pos to t if necessary. +func (t *PosTable) XPos(pos Pos) XPos { +	m := t.indexMap +	if m == nil { +		// Create new list and map and populate with nil +		// base so that NoPos always gets index 0. +		t.baseList = append(t.baseList, nil) +		m = map[*PosBase]int{nil: 0} +		t.indexMap = m +		t.nameMap = make(map[string]int) +	} +	i, ok := m[pos.base] +	if !ok { +		i = len(t.baseList) +		t.baseList = append(t.baseList, pos.base) +		t.indexMap[pos.base] = i +		if _, ok := t.nameMap[pos.base.symFilename]; !ok { +			t.nameMap[pos.base.symFilename] = len(t.nameMap) +		} +	} +	return XPos{int32(i), pos.lico} +} + +// Pos returns the corresponding Pos for the given p. +// If p cannot be translated via t, the function panics. +func (t *PosTable) Pos(p XPos) Pos { +	var base *PosBase +	if p.index != 0 { +		base = t.baseList[p.index] +	} +	return Pos{base, p.lico} +} + +// FileIndex returns the index of the given filename(symbol) in the PosTable, or -1 if not found. +func (t *PosTable) FileIndex(filename string) int { +	if v, ok := t.nameMap[filename]; ok { +		return v +	} +	return -1 +} + +// FileTable returns a slice of all files used to build this package. +func (t *PosTable) FileTable() []string { +	// Create a LUT of the global package level file indices. This table is what +	// is written in the debug_lines header, the file[N] will be referenced as +	// N+1 in the debug_lines table. +	fileLUT := make([]string, len(t.nameMap)) +	for str, i := range t.nameMap { +		fileLUT[i] = str +	} +	return fileLUT +} | 
