Repository navigation
Expand file tree
/
Copy pathdebug.go
More file actions
149 lines (141 loc) · 4.03 KB
/
Copy pathdebug.go
File metadata and controls
149 lines (141 loc) · 4.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
package glua
import "fmt"
// Debug information is cold: it is read only to build error messages and tracebacks.
// lineAt returns the source line of the code word at pc, or 0.
func (p *proto) lineAt(pc int) int {
if pc >= 0 && pc < len(p.lines) {
return int(p.lines[pc])
}
return 0
}
// localName returns the name of the local in register reg at pc, or "".
func (p *proto) localName(reg, pc int) string {
name := ""
for _, lv := range p.locvars {
if lv.reg == reg && lv.startpc <= pc && (lv.endpc < 0 || pc < lv.endpc) {
name = lv.name // the innermost, declared last, wins
}
}
return name
}
// setsReg reports whether the instruction i writes register reg.
func setsReg(i uint32, reg int) bool {
a, b, c := decA(i), decB(i), decC(i)
switch uint8(i) {
case opMove, opLoadK, opLoadKX, opLoadI, opLoadF, opLoadFalse, opLoadTrue, opGetUpval, opGetUpCell,
opNewCell, opGetCell, opGetGlobal, opGetEnv, opGetTable, opGetIndex, opGetField, opNewTable,
opAdd, opSub, opMul, opDiv, opMod, opPow, opIDiv, opBAnd, opBOr, opBXor, opShl, opShr,
opAddK, opSubK, opMulK, opDivK, opModK, opPowK, opIDivK, opBAndK, opBOrK, opBXorK, opShlK, opShrK,
opUnm, opNot, opLen, opBNot, opConcat, opTestSet, opClosure:
return reg == a
case opLoadNil:
return a <= reg && reg <= a+b
case opSelf:
return reg == a || reg == a+1
case opForPrep, opForLoop:
return a <= reg && reg <= a+3
case opTForCall:
return reg >= a+4 && reg < a+3+c
case opCall, opTailCall, opVararg:
return reg >= a
}
return false
}
// findSetReg finds the last instruction before lastpc that sets reg, as C Lua's findsetreg
// does. An instruction inside a stretch that a jump skips may not have run, so it does not
// count.
func (p *proto) findSetReg(lastpc, reg int) int {
setreg, jmptarget := -1, 0
for pc := 0; pc < lastpc; pc++ {
i := p.code[pc]
op := uint8(i)
target := -1
switch {
case op == opJmp:
target = pc + 1 + int(int16(decBx(i)))
case hasAux[op] && opTable[op].aux == oJumpX:
target = pc + 2 + int(int32(p.code[pc+1]))
}
if target > pc && target <= lastpc && target > jmptarget {
jmptarget = target
}
if setsReg(i, reg) {
if pc < jmptarget {
setreg = -1 // conditional: it may not have run
} else {
setreg = pc
}
}
if hasAux[op] {
pc++
}
}
return setreg
}
// varInfo describes where register reg got its value at pc, as C Lua's getobjname does:
// "local 'x'", "global 'x'", "field 'x'", "upvalue 'x'", "method 'x'" or "constant 'x'".
// It returns "" when it cannot tell.
func (p *proto) varInfo(pc, reg int) string {
kind, name := p.objName(pc, reg)
if kind == "" {
return ""
}
return fmt.Sprintf("%s '%s'", kind, name)
}
func (p *proto) objName(lastpc, reg int) (kind, name string) {
if n := p.localName(reg, lastpc); n != "" {
return "local", n
}
pc := p.findSetReg(lastpc, reg)
if pc < 0 {
return "", ""
}
i := p.code[pc]
switch uint8(i) {
case opMove:
if b := decB(i); b < decA(i) {
return p.objName(pc, b)
}
case opGetCell:
if n := p.localName(decB(i), pc); n != "" {
return "local", n
}
case opGetUpval, opGetUpCell:
if b := decB(i); b < len(p.upnames) {
return "upvalue", p.upnames[b]
}
case opGetGlobal:
return "global", p.k[decBx(i)].str()
case opGetField:
key := p.k[decC(i)].str()
if k, n := p.objName(pc, decB(i)); n == "_ENV" && (k == "local" || k == "upvalue") {
return "global", key
}
return "field", key
case opGetTable:
k, n := p.objName(pc, decC(i))
if k != "constant" {
return "field", "?"
}
if a := decA(i); decC(i) == a && decB(i) == a+1 {
return "method", n // a method call whose name is past the SELF constant limit
}
if tk, tn := p.objName(pc, decB(i)); tn == "_ENV" && (tk == "local" || tk == "upvalue") {
return "global", n
}
return "field", n
case opGetIndex:
return "field", "integer index"
case opSelf:
return "method", p.k[decC(i)].str()
case opLoadK:
if k := p.k[decBx(i)]; k.isString() {
return "constant", k.str()
}
case opLoadKX:
if k := p.k[p.code[pc+1]]; k.isString() {
return "constant", k.str()
}
}
return "", ""
}