tlog.app/go/tlog@v0.23.1/tlwire/location.go (about)

     1  package tlwire
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  
     7  	"tlog.app/go/loc"
     8  )
     9  
    10  var (
    11  	locmu    sync.Mutex
    12  	loccache = map[loc.PC][]byte{}
    13  )
    14  
    15  func (e Encoder) AppendPC(b []byte, pc loc.PC) []byte {
    16  	b = append(b, Semantic|Caller)
    17  
    18  	if pc == 0 {
    19  		return append(b, Special|Nil)
    20  	}
    21  
    22  	return e.AppendUint64(b, uint64(pc))
    23  }
    24  
    25  func (e Encoder) AppendPCs(b []byte, pcs loc.PCs) []byte {
    26  	b = append(b, Semantic|Caller)
    27  
    28  	if pcs == nil {
    29  		return append(b, Special|Nil)
    30  	}
    31  
    32  	b = e.AppendTag(b, Array, len(pcs))
    33  
    34  	for _, pc := range pcs {
    35  		b = e.AppendUint64(b, uint64(pc))
    36  	}
    37  
    38  	return b
    39  }
    40  
    41  func (e Encoder) AppendCaller(b []byte, pc loc.PC) []byte {
    42  	b = append(b, Semantic|Caller)
    43  
    44  	return e.appendPC(b, pc)
    45  }
    46  
    47  func (e Encoder) AppendCallers(b []byte, pcs loc.PCs) []byte {
    48  	b = append(b, Semantic|Caller)
    49  	b = e.AppendTag(b, Array, len(pcs))
    50  
    51  	for _, pc := range pcs {
    52  		b = e.appendPC(b, pc)
    53  	}
    54  
    55  	return b
    56  }
    57  
    58  func (e Encoder) appendPC(b []byte, pc loc.PC) []byte {
    59  	if pc == 0 {
    60  		return append(b, Special|Nil)
    61  	}
    62  
    63  	locmu.Lock()
    64  	c, ok := loccache[pc]
    65  	locmu.Unlock()
    66  
    67  	if ok {
    68  		return append(b, c...)
    69  	}
    70  
    71  	fe := pc.FuncEntry()
    72  
    73  	st := len(b)
    74  
    75  	l := byte(4)
    76  	if fe != pc {
    77  		l++
    78  	}
    79  
    80  	b = append(b, Map|l)
    81  
    82  	b = e.AppendString(b, "p")
    83  	b = e.AppendUint64(b, uint64(pc))
    84  
    85  	name, file, line := pc.NameFileLine()
    86  
    87  	b = e.AppendString(b, "n")
    88  	b = e.AppendString(b, name)
    89  
    90  	b = e.AppendString(b, "f")
    91  	b = e.AppendString(b, file)
    92  
    93  	b = e.AppendString(b, "l")
    94  	b = e.AppendInt(b, line)
    95  
    96  	if fe != pc {
    97  		b = e.AppendString(b, "e")
    98  		b = e.AppendUint64(b, uint64(fe))
    99  	}
   100  
   101  	c = make([]byte, len(b)-st)
   102  	copy(c, b[st:])
   103  
   104  	locmu.Lock()
   105  	loccache[pc] = c
   106  	locmu.Unlock()
   107  
   108  	return b
   109  }
   110  
   111  func (d Decoder) Caller(p []byte, st int) (pc loc.PC, i int) {
   112  	if p[st] != Semantic|Caller {
   113  		panic("not a caller")
   114  	}
   115  
   116  	tag, sub, i := d.Tag(p, st+1)
   117  
   118  	if tag == Int || tag == Map {
   119  		return d.caller(p, st+1)
   120  	}
   121  
   122  	if tag == Special && sub == Nil {
   123  		return
   124  	}
   125  
   126  	if tag != Array {
   127  		panic(fmt.Sprintf("unsupported caller tag: %x", tag))
   128  	}
   129  
   130  	if sub == 0 {
   131  		return
   132  	}
   133  
   134  	pc, i = d.caller(p, i)
   135  
   136  	for el := 1; el < int(sub); el++ {
   137  		_, i = d.caller(p, i)
   138  	}
   139  
   140  	return
   141  }
   142  
   143  func (d Decoder) Callers(p []byte, st int) (pc loc.PC, pcs loc.PCs, i int) {
   144  	if p[st] != Semantic|Caller {
   145  		panic("not a caller")
   146  	}
   147  
   148  	tag, sub, i := d.Tag(p, st+1)
   149  
   150  	switch {
   151  	case tag == Int, tag == Map:
   152  		pc, i = d.caller(p, st+1)
   153  		return
   154  	case tag == Array:
   155  	case tag == Special && sub == Nil:
   156  		return
   157  	default:
   158  		panic(fmt.Sprintf("unsupported caller tag: %x", tag))
   159  	}
   160  
   161  	if sub == 0 {
   162  		return
   163  	}
   164  
   165  	pcs = make(loc.PCs, sub)
   166  
   167  	for el := 0; el < int(sub); el++ {
   168  		pcs[el], i = d.caller(p, i)
   169  	}
   170  
   171  	pc = pcs[0]
   172  
   173  	return
   174  }
   175  
   176  func (d Decoder) caller(p []byte, st int) (pc loc.PC, i int) {
   177  	i = st
   178  
   179  	tag, sub, i := d.Tag(p, i)
   180  
   181  	if tag == Int {
   182  		pc = loc.PC(sub)
   183  
   184  		if pc != 0 && !loc.Cached(pc) {
   185  			loc.SetCache(pc, "_", ".", 0)
   186  		}
   187  
   188  		return
   189  	}
   190  
   191  	var v uint64
   192  	var k []byte
   193  	var name, file []byte
   194  	var line int
   195  
   196  	for el := 0; el < int(sub); el++ {
   197  		k, i = d.Bytes(p, i)
   198  
   199  		switch string(k) {
   200  		case "p":
   201  			v, i = d.Unsigned(p, i)
   202  
   203  			pc = loc.PC(v)
   204  		case "l":
   205  			v, i = d.Unsigned(p, i)
   206  
   207  			line = int(v)
   208  		case "n":
   209  			name, i = d.Bytes(p, i)
   210  		case "f":
   211  			file, i = d.Bytes(p, i)
   212  		default:
   213  			i = d.Skip(p, i)
   214  		}
   215  	}
   216  
   217  	if pc == 0 {
   218  		return
   219  	}
   220  
   221  	loc.SetCacheBytes(pc, name, file, line)
   222  
   223  	return
   224  }