1package lua
2
3import (
4	"fmt"
5)
6
7/*
8  gopherlua uses Lua 5.1.4's opcodes.
9  Lua 5.1.4 opcodes layout:
10
11          instruction = 32bit(fixed length)
12
13  +---------------------------------------------+
14  |0-5(6bits)|6-13(8bit)|14-22(9bit)|23-31(9bit)|
15  |==========+==========+===========+===========|
16  |  opcode  |    A     |     C     |    B      |
17  |----------+----------+-----------+-----------|
18  |  opcode  |    A     |      Bx(unsigned)     |
19  |----------+----------+-----------+-----------|
20  |  opcode  |    A     |      sBx(signed)      |
21  +---------------------------------------------+
22*/
23
24const opInvalidInstruction = ^uint32(0)
25
26const opSizeCode = 6
27const opSizeA = 8
28const opSizeB = 9
29const opSizeC = 9
30const opSizeBx = 18
31const opSizesBx = 18
32
33const opMaxArgsA = (1 << opSizeA) - 1
34const opMaxArgsB = (1 << opSizeB) - 1
35const opMaxArgsC = (1 << opSizeC) - 1
36const opMaxArgBx = (1 << opSizeBx) - 1
37const opMaxArgSbx = opMaxArgBx >> 1
38
39const (
40	OP_MOVE     int = iota /*      A B     R(A) := R(B)                            */
41	OP_MOVEN               /*      A B     R(A) := R(B); followed by R(C) MOVE ops */
42	OP_LOADK               /*     A Bx    R(A) := Kst(Bx)                          */
43	OP_LOADBOOL            /*  A B C   R(A) := (Bool)B; if (C) pc++                */
44	OP_LOADNIL             /*   A B     R(A) := ... := R(B) := nil                 */
45	OP_GETUPVAL            /*  A B     R(A) := UpValue[B]                          */
46
47	OP_GETGLOBAL  /* A Bx    R(A) := Gbl[Kst(Bx)]                            */
48	OP_GETTABLE   /*  A B C   R(A) := R(B)[RK(C)]                             */
49	OP_GETTABLEKS /*  A B C   R(A) := R(B)[RK(C)] ; RK(C) is constant string */
50
51	OP_SETGLOBAL  /* A Bx    Gbl[Kst(Bx)] := R(A)                            */
52	OP_SETUPVAL   /*  A B     UpValue[B] := R(A)                              */
53	OP_SETTABLE   /*  A B C   R(A)[RK(B)] := RK(C)                            */
54	OP_SETTABLEKS /*  A B C   R(A)[RK(B)] := RK(C) ; RK(B) is constant string */
55
56	OP_NEWTABLE /*  A B C   R(A) := {} (size = BC)                         */
57
58	OP_SELF /*      A B C   R(A+1) := R(B); R(A) := R(B)[RK(C)]             */
59
60	OP_ADD /*       A B C   R(A) := RK(B) + RK(C)                           */
61	OP_SUB /*       A B C   R(A) := RK(B) - RK(C)                           */
62	OP_MUL /*       A B C   R(A) := RK(B) * RK(C)                           */
63	OP_DIV /*       A B C   R(A) := RK(B) / RK(C)                           */
64	OP_MOD /*       A B C   R(A) := RK(B) % RK(C)                           */
65	OP_POW /*       A B C   R(A) := RK(B) ^ RK(C)                           */
66	OP_UNM /*       A B     R(A) := -R(B)                                   */
67	OP_NOT /*       A B     R(A) := not R(B)                                */
68	OP_LEN /*       A B     R(A) := length of R(B)                          */
69
70	OP_CONCAT /*    A B C   R(A) := R(B).. ... ..R(C)                       */
71
72	OP_JMP /*       sBx     pc+=sBx                                 */
73
74	OP_EQ /*        A B C   if ((RK(B) == RK(C)) ~= A) then pc++            */
75	OP_LT /*        A B C   if ((RK(B) <  RK(C)) ~= A) then pc++            */
76	OP_LE /*        A B C   if ((RK(B) <= RK(C)) ~= A) then pc++            */
77
78	OP_TEST    /*      A C     if not (R(A) <=> C) then pc++                   */
79	OP_TESTSET /*   A B C   if (R(B) <=> C) then R(A) := R(B) else pc++     */
80
81	OP_CALL     /*      A B C   R(A) ... R(A+C-2) := R(A)(R(A+1) ... R(A+B-1)) */
82	OP_TAILCALL /*  A B C   return R(A)(R(A+1) ... R(A+B-1))              */
83	OP_RETURN   /*    A B     return R(A) ... R(A+B-2)      (see note)      */
84
85	OP_FORLOOP /*   A sBx   R(A)+=R(A+2);
86	     if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
87	OP_FORPREP /*   A sBx   R(A)-=R(A+2); pc+=sBx                           */
88
89	OP_TFORLOOP /*  A C     R(A+3) ... R(A+3+C) := R(A)(R(A+1) R(A+2));
90	    if R(A+3) ~= nil then { pc++; R(A+2)=R(A+3); }  */
91	OP_SETLIST /*   A B C   R(A)[(C-1)*FPF+i] := R(A+i) 1 <= i <= B        */
92
93	OP_CLOSE   /*     A       close all variables in the stack up to (>=) R(A)*/
94	OP_CLOSURE /*   A Bx    R(A) := closure(KPROTO[Bx] R(A) ... R(A+n))  */
95
96	OP_VARARG /*     A B     R(A) R(A+1) ... R(A+B-1) = vararg            */
97
98	OP_NOP /* NOP */
99)
100const opCodeMax = OP_NOP
101
102type opArgMode int
103
104const (
105	opArgModeN opArgMode = iota
106	opArgModeU
107	opArgModeR
108	opArgModeK
109)
110
111type opType int
112
113const (
114	opTypeABC = iota
115	opTypeABx
116	opTypeASbx
117)
118
119type opProp struct {
120	Name     string
121	IsTest   bool
122	SetRegA  bool
123	ModeArgB opArgMode
124	ModeArgC opArgMode
125	Type     opType
126}
127
128var opProps = []opProp{
129	opProp{"MOVE", false, true, opArgModeR, opArgModeN, opTypeABC},
130	opProp{"MOVEN", false, true, opArgModeR, opArgModeN, opTypeABC},
131	opProp{"LOADK", false, true, opArgModeK, opArgModeN, opTypeABx},
132	opProp{"LOADBOOL", false, true, opArgModeU, opArgModeU, opTypeABC},
133	opProp{"LOADNIL", false, true, opArgModeR, opArgModeN, opTypeABC},
134	opProp{"GETUPVAL", false, true, opArgModeU, opArgModeN, opTypeABC},
135	opProp{"GETGLOBAL", false, true, opArgModeK, opArgModeN, opTypeABx},
136	opProp{"GETTABLE", false, true, opArgModeR, opArgModeK, opTypeABC},
137	opProp{"GETTABLEKS", false, true, opArgModeR, opArgModeK, opTypeABC},
138	opProp{"SETGLOBAL", false, false, opArgModeK, opArgModeN, opTypeABx},
139	opProp{"SETUPVAL", false, false, opArgModeU, opArgModeN, opTypeABC},
140	opProp{"SETTABLE", false, false, opArgModeK, opArgModeK, opTypeABC},
141	opProp{"SETTABLEKS", false, false, opArgModeK, opArgModeK, opTypeABC},
142	opProp{"NEWTABLE", false, true, opArgModeU, opArgModeU, opTypeABC},
143	opProp{"SELF", false, true, opArgModeR, opArgModeK, opTypeABC},
144	opProp{"ADD", false, true, opArgModeK, opArgModeK, opTypeABC},
145	opProp{"SUB", false, true, opArgModeK, opArgModeK, opTypeABC},
146	opProp{"MUL", false, true, opArgModeK, opArgModeK, opTypeABC},
147	opProp{"DIV", false, true, opArgModeK, opArgModeK, opTypeABC},
148	opProp{"MOD", false, true, opArgModeK, opArgModeK, opTypeABC},
149	opProp{"POW", false, true, opArgModeK, opArgModeK, opTypeABC},
150	opProp{"UNM", false, true, opArgModeR, opArgModeN, opTypeABC},
151	opProp{"NOT", false, true, opArgModeR, opArgModeN, opTypeABC},
152	opProp{"LEN", false, true, opArgModeR, opArgModeN, opTypeABC},
153	opProp{"CONCAT", false, true, opArgModeR, opArgModeR, opTypeABC},
154	opProp{"JMP", false, false, opArgModeR, opArgModeN, opTypeASbx},
155	opProp{"EQ", true, false, opArgModeK, opArgModeK, opTypeABC},
156	opProp{"LT", true, false, opArgModeK, opArgModeK, opTypeABC},
157	opProp{"LE", true, false, opArgModeK, opArgModeK, opTypeABC},
158	opProp{"TEST", true, true, opArgModeR, opArgModeU, opTypeABC},
159	opProp{"TESTSET", true, true, opArgModeR, opArgModeU, opTypeABC},
160	opProp{"CALL", false, true, opArgModeU, opArgModeU, opTypeABC},
161	opProp{"TAILCALL", false, true, opArgModeU, opArgModeU, opTypeABC},
162	opProp{"RETURN", false, false, opArgModeU, opArgModeN, opTypeABC},
163	opProp{"FORLOOP", false, true, opArgModeR, opArgModeN, opTypeASbx},
164	opProp{"FORPREP", false, true, opArgModeR, opArgModeN, opTypeASbx},
165	opProp{"TFORLOOP", true, false, opArgModeN, opArgModeU, opTypeABC},
166	opProp{"SETLIST", false, false, opArgModeU, opArgModeU, opTypeABC},
167	opProp{"CLOSE", false, false, opArgModeN, opArgModeN, opTypeABC},
168	opProp{"CLOSURE", false, true, opArgModeU, opArgModeN, opTypeABx},
169	opProp{"VARARG", false, true, opArgModeU, opArgModeN, opTypeABC},
170	opProp{"NOP", false, false, opArgModeR, opArgModeN, opTypeASbx},
171}
172
173func opGetOpCode(inst uint32) int {
174	return int(inst >> 26)
175}
176
177func opSetOpCode(inst *uint32, opcode int) {
178	*inst = (*inst & 0x3ffffff) | uint32(opcode<<26)
179}
180
181func opGetArgA(inst uint32) int {
182	return int(inst>>18) & 0xff
183}
184
185func opSetArgA(inst *uint32, arg int) {
186	*inst = (*inst & 0xfc03ffff) | uint32((arg&0xff)<<18)
187}
188
189func opGetArgB(inst uint32) int {
190	return int(inst & 0x1ff)
191}
192
193func opSetArgB(inst *uint32, arg int) {
194	*inst = (*inst & 0xfffffe00) | uint32(arg&0x1ff)
195}
196
197func opGetArgC(inst uint32) int {
198	return int(inst>>9) & 0x1ff
199}
200
201func opSetArgC(inst *uint32, arg int) {
202	*inst = (*inst & 0xfffc01ff) | uint32((arg&0x1ff)<<9)
203}
204
205func opGetArgBx(inst uint32) int {
206	return int(inst & 0x3ffff)
207}
208
209func opSetArgBx(inst *uint32, arg int) {
210	*inst = (*inst & 0xfffc0000) | uint32(arg&0x3ffff)
211}
212
213func opGetArgSbx(inst uint32) int {
214	return opGetArgBx(inst) - opMaxArgSbx
215}
216
217func opSetArgSbx(inst *uint32, arg int) {
218	opSetArgBx(inst, arg+opMaxArgSbx)
219}
220
221func opCreateABC(op int, a int, b int, c int) uint32 {
222	var inst uint32 = 0
223	opSetOpCode(&inst, op)
224	opSetArgA(&inst, a)
225	opSetArgB(&inst, b)
226	opSetArgC(&inst, c)
227	return inst
228}
229
230func opCreateABx(op int, a int, bx int) uint32 {
231	var inst uint32 = 0
232	opSetOpCode(&inst, op)
233	opSetArgA(&inst, a)
234	opSetArgBx(&inst, bx)
235	return inst
236}
237
238func opCreateASbx(op int, a int, sbx int) uint32 {
239	var inst uint32 = 0
240	opSetOpCode(&inst, op)
241	opSetArgA(&inst, a)
242	opSetArgSbx(&inst, sbx)
243	return inst
244}
245
246const opBitRk = 1 << (opSizeB - 1)
247const opMaxIndexRk = opBitRk - 1
248
249func opIsK(value int) bool {
250	return bool((value & opBitRk) != 0)
251}
252
253func opIndexK(value int) int {
254	return value & ^opBitRk
255}
256
257func opRkAsk(value int) int {
258	return value | opBitRk
259}
260
261func opToString(inst uint32) string {
262	op := opGetOpCode(inst)
263	if op > opCodeMax {
264		return ""
265	}
266	prop := &(opProps[op])
267
268	arga := opGetArgA(inst)
269	argb := opGetArgB(inst)
270	argc := opGetArgC(inst)
271	argbx := opGetArgBx(inst)
272	argsbx := opGetArgSbx(inst)
273
274	buf := ""
275	switch prop.Type {
276	case opTypeABC:
277		buf = fmt.Sprintf("%s      |  %d, %d, %d", prop.Name, arga, argb, argc)
278	case opTypeABx:
279		buf = fmt.Sprintf("%s      |  %d, %d", prop.Name, arga, argbx)
280	case opTypeASbx:
281		buf = fmt.Sprintf("%s      |  %d, %d", prop.Name, arga, argsbx)
282	}
283
284	switch op {
285	case OP_MOVE:
286		buf += fmt.Sprintf("; R(%v) := R(%v)", arga, argb)
287	case OP_MOVEN:
288		buf += fmt.Sprintf("; R(%v) := R(%v); followed by %v MOVE ops", arga, argb, argc)
289	case OP_LOADK:
290		buf += fmt.Sprintf("; R(%v) := Kst(%v)", arga, argbx)
291	case OP_LOADBOOL:
292		buf += fmt.Sprintf("; R(%v) := (Bool)%v; if (%v) pc++", arga, argb, argc)
293	case OP_LOADNIL:
294		buf += fmt.Sprintf("; R(%v) := ... := R(%v) := nil", arga, argb)
295	case OP_GETUPVAL:
296		buf += fmt.Sprintf("; R(%v) := UpValue[%v]", arga, argb)
297	case OP_GETGLOBAL:
298		buf += fmt.Sprintf("; R(%v) := Gbl[Kst(%v)]", arga, argbx)
299	case OP_GETTABLE:
300		buf += fmt.Sprintf("; R(%v) := R(%v)[RK(%v)]", arga, argb, argc)
301	case OP_GETTABLEKS:
302		buf += fmt.Sprintf("; R(%v) := R(%v)[RK(%v)] ; RK(%v) is constant string", arga, argb, argc, argc)
303	case OP_SETGLOBAL:
304		buf += fmt.Sprintf("; Gbl[Kst(%v)] := R(%v)", argbx, arga)
305	case OP_SETUPVAL:
306		buf += fmt.Sprintf("; UpValue[%v] := R(%v)", argb, arga)
307	case OP_SETTABLE:
308		buf += fmt.Sprintf("; R(%v)[RK(%v)] := RK(%v)", arga, argb, argc)
309	case OP_SETTABLEKS:
310		buf += fmt.Sprintf("; R(%v)[RK(%v)] := RK(%v) ; RK(%v) is constant string", arga, argb, argc, argb)
311	case OP_NEWTABLE:
312		buf += fmt.Sprintf("; R(%v) := {} (size = BC)", arga)
313	case OP_SELF:
314		buf += fmt.Sprintf("; R(%v+1) := R(%v); R(%v) := R(%v)[RK(%v)]", arga, argb, arga, argb, argc)
315	case OP_ADD:
316		buf += fmt.Sprintf("; R(%v) := RK(%v) + RK(%v)", arga, argb, argc)
317	case OP_SUB:
318		buf += fmt.Sprintf("; R(%v) := RK(%v) - RK(%v)", arga, argb, argc)
319	case OP_MUL:
320		buf += fmt.Sprintf("; R(%v) := RK(%v) * RK(%v)", arga, argb, argc)
321	case OP_DIV:
322		buf += fmt.Sprintf("; R(%v) := RK(%v) / RK(%v)", arga, argb, argc)
323	case OP_MOD:
324		buf += fmt.Sprintf("; R(%v) := RK(%v) %% RK(%v)", arga, argb, argc)
325	case OP_POW:
326		buf += fmt.Sprintf("; R(%v) := RK(%v) ^ RK(%v)", arga, argb, argc)
327	case OP_UNM:
328		buf += fmt.Sprintf("; R(%v) := -R(%v)", arga, argb)
329	case OP_NOT:
330		buf += fmt.Sprintf("; R(%v) := not R(%v)", arga, argb)
331	case OP_LEN:
332		buf += fmt.Sprintf("; R(%v) := length of R(%v)", arga, argb)
333	case OP_CONCAT:
334		buf += fmt.Sprintf("; R(%v) := R(%v).. ... ..R(%v)", arga, argb, argc)
335	case OP_JMP:
336		buf += fmt.Sprintf("; pc+=%v", argsbx)
337	case OP_EQ:
338		buf += fmt.Sprintf("; if ((RK(%v) == RK(%v)) ~= %v) then pc++", argb, argc, arga)
339	case OP_LT:
340		buf += fmt.Sprintf("; if ((RK(%v) <  RK(%v)) ~= %v) then pc++", argb, argc, arga)
341	case OP_LE:
342		buf += fmt.Sprintf("; if ((RK(%v) <= RK(%v)) ~= %v) then pc++", argb, argc, arga)
343	case OP_TEST:
344		buf += fmt.Sprintf("; if not (R(%v) <=> %v) then pc++", arga, argc)
345	case OP_TESTSET:
346		buf += fmt.Sprintf("; if (R(%v) <=> %v) then R(%v) := R(%v) else pc++", argb, argc, arga, argb)
347	case OP_CALL:
348		buf += fmt.Sprintf("; R(%v) ... R(%v+%v-2) := R(%v)(R(%v+1) ... R(%v+%v-1))", arga, arga, argc, arga, arga, arga, argb)
349	case OP_TAILCALL:
350		buf += fmt.Sprintf("; return R(%v)(R(%v+1) ... R(%v+%v-1))", arga, arga, arga, argb)
351	case OP_RETURN:
352		buf += fmt.Sprintf("; return R(%v) ... R(%v+%v-2)", arga, arga, argb)
353	case OP_FORLOOP:
354		buf += fmt.Sprintf("; R(%v)+=R(%v+2); if R(%v) <?= R(%v+1) then { pc+=%v; R(%v+3)=R(%v) }", arga, arga, arga, arga, argsbx, arga, arga)
355	case OP_FORPREP:
356		buf += fmt.Sprintf("; R(%v)-=R(%v+2); pc+=%v", arga, arga, argsbx)
357	case OP_TFORLOOP:
358		buf += fmt.Sprintf("; R(%v+3) ... R(%v+3+%v) := R(%v)(R(%v+1) R(%v+2)); if R(%v+3) ~= nil then { pc++; R(%v+2)=R(%v+3); }", arga, arga, argc, arga, arga, arga, arga, arga, arga)
359	case OP_SETLIST:
360		buf += fmt.Sprintf("; R(%v)[(%v-1)*FPF+i] := R(%v+i) 1 <= i <= %v", arga, argc, arga, argb)
361	case OP_CLOSE:
362		buf += fmt.Sprintf("; close all variables in the stack up to (>=) R(%v)", arga)
363	case OP_CLOSURE:
364		buf += fmt.Sprintf("; R(%v) := closure(KPROTO[%v] R(%v) ... R(%v+n))", arga, argbx, arga, arga)
365	case OP_VARARG:
366		buf += fmt.Sprintf(";  R(%v) R(%v+1) ... R(%v+%v-1) = vararg", arga, arga, arga, argb)
367	case OP_NOP:
368		/* nothing to do */
369	}
370	return buf
371}
372