forked from middlefeng/LuaVMRead
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlcode.c
252 lines (155 loc) · 8.24 KB
/
lcode.c
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
General
-------------------------------------------------------
- luaK_code... returns the "pc" of the instruction just being generated.
- if a "luaK_..." function accepts an "expdesc" as parameter, it usually does not put
instruction into Proto::code, at least not putting the last instruction.
- A "test-mode" instruction is followed by a JMP instruction. When generating
a comp-instruction, luaK_posfix() generates it as "jmp-if-true" (the same as
"go-if-false").
in "goiftrue()", the "test-bit" shall be inverted to invert the "jmp-if-true" behavior.
Global Tables
-------------------------------------------------------
OpCode: Enum type which is the index of the following two arraies.
luaP_opnames: All OP names in "char*".
luaP_opmodes: OP mode of each instruction, indexed as the same order to "luaP_opnames".
void luaK_setoneret (FuncState *fs, expdesc *e)
==========================================================================
Set the expression of a "VVARARG" or "VCALL".
1. For VVARARG, set its "B" as 2, meaning adjusting to 1 value.
2. For VCALL, set "e->k" to "NONRELOC" and "e->u.info" to the original "A".
static int addk (FuncState *fs, TValue *key, TValue *v)
==========================================================================
Add "v" to field "k" of the "struct Proto".
Before really creating an entry in "k", it check and reuse an eixsting one whenever possible.
It check by search in "fs->h", which is a compile-time hash-index of "k".
fs->f->k grows by double if there is no enough room, and all new items are set as "nil".
The number of actually used slots is stored in fs->nk.
Returns the location in "f->k" of the newly-added constant.
static int luaK_code (FuncState *fs, Instruction i)
==========================================================================
Put Instruction "i" into "fs->f->code"
void luaK_exp2val (FuncState *fs, expdesc *e)
==========================================================================
luaK_exp2val (fs, e)
hasjumps(e)
[true]
luaK_exp2anyreg(fs, e)
[false]
luaK_dischargevars(fs, e)
static int jumponcond (FuncState *fs, expdesc *e, int cond)
==========================================================================
If "e" is a RELOC "NOT"
--------------------------------------
TEST RB(ie), !cond
JMP 0, "jpc"
Otherwise
--------------------------------------
TESTSET -1, "Rdischarge(e)", cond
JMP 0, "jpc"
static int condjump (FuncState *fs, OpCode op, int A, int B, int C)
==========================================================================
"op" A, B, C
JMP 0, "jpc"
void luaK_goiftrue (FuncState *fs, expdesc *e)
==========================================================================
For "VJMP"
-------------------------------------------------------
e->t: JMP 0, "jpc" // pre-generated, not by this function
int luaK_jump (FuncState *fs)
==========================================================================
Generate an "OP_JMP" instruction.
Put the current "fs->jpc" to the target of the instruction.
Clean "fs->jpc".
Return the instruction's "pc".
static void luaK_concat (FuncState *fs, int *l1, int l2)
==========================================================================
Add instruction at index "l2" to a chain of jump instructions.
-------------------------------------------------------
l1: address to a variable holding a "pc" index.
l2: a "pc" index.
-------------------------------------------------------
1. Noop, when l2 == NO_JUMP.
2. *l1 = l2, when l1 == NO_JUMP.
3. if "*l1" has a non-"NO_JUMP" value, trace the value to the instruction
chain (a chain of jump instructions) and set "l2" as the target of the
end instruction.
void luaK_dischargevars (FuncState *fs, expdesc *e)
==========================================================================
Gaurantee there is one value avaialbe for "e".
1. If the value already exists in a register (VCALL, VLOCAL), then no new instruction
spat out, no instruction patched. The pre-determined reg is put into "e->u.info".
2. If the value is not allocated with a register (VUPVAL, VINDEXED, VVARARG), this function
1) Spit out a "GET..." instruction for VUPVAL/VINDEXED, left the target reg pent.
2) Patch the VVARARG instruct to assign only one value (e.g. Bx=2), left the target reg pent.
----------------------------------------------------
1. VNONRELOC: in "e->u.info" register.
2. VRELOCABLE: "e->u.info" point to an instruction, whose "A" parameter is pending.
3. Other.
void luaK_setreturns (FuncState *fs, expdesc *e, int nresults)
==========================================================================
Adjust a multi-value.
1. For VCALL, patch Cx as "nresults+1".
2. For VVARARG, patch Bx as "nresults+1", patch Ax (destination reg) to a free reg slot.
static void exp2reg (FuncState *fs, expdesc *e, int reg)
==========================================================================
For e->k == VJMP and NOT following a "TESTSET"
----------------------------------------------------------
JMP 0, "e->t"
e->f: LOAD_BOOL "reg", 0, 1
e->t: LOAD_BOOL "reg", 1, 0
For anything else, just delegate to discharge2reg().
int luaK_exp2RK (FuncState *fs, expdesc *e)
==========================================================================
Make result of "e" in a register or in a constant entry (prepared for instruction accepting
RK parameters).
static void discharge2reg (FuncState *fs, expdesc *e, int reg)
==========================================================================
Make the result of "e" into register "reg".
Except for "VVOID" and "VJMP".
static void dischargejpc (FuncState *fs)
==========================================================================
Travserse the "fs->jpc" list. Modify all "TESTSET" instructions involved in the list to
"TEST" instructions. Patch all insructions' sBx to "fs->pc".
-------------------------------------------------------
patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc)
static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, int dtarget)
==========================================================================
Traverse the chain of jump instructions pointed by "list" (til a "NO_JUMP" offset appear).
1. For all instructions which do NOT follow a "TESTSET", set their sBx to "dtarget".
2. For all which follow "TESTSET"s, set the "TESTSET"'s' "register A" to "reg" and their
sBx to "vtarget".
Note:
1. If "reg" is NO_REG, then "vtarget" should be the same to "dtarget".
static int patchtestreg (FuncState *fs, int node, int reg)
==========================================================================
Patch the "register A" (i.e. the destination register) of a "TESTSET" instruction.
The "TESTSET" would be either the one prior to "node", or the "node".
1. Do nothing and returns 0 if the "node"-1 or "node" instruction is not "TESTSET".
2. If "reg" is neither "NO_REG" nor equal to "register B" of the instruction, set
it as "register A" of the instruction.
3. Otherwise, change the instruction to a "TEST" instruction, set the old
"register B" as "register A". (For a TEST, "register B" is ignored.)
static int getjump (FuncState *fs, int pc)
==========================================================================
The instruction at index "pc" must be of sBx form.
Return the target absolute index of the jump, or "NO_JUMP" when the offset is "NO_JUMP".
The absolute index of the jump is computed according to the relative jump offset obtained
from the instrcution, and the "pc" of the instruction.
static Instruction *getjumpcontrol (FuncState *fs, int pc)
==========================================================================
Test if the instruction proceeding "pc" is a "test instruction" (see "testTMode(m)" for details).
If so, return the "test instruction", otherwise return the instruction at index "pc".
static void fixjump (FuncState *fs, int pc, int dest)
==========================================================================
Write the sBx part of the instruction at index "pc" to have it jump to "dest".
testTMode(m)
==========================================================================
If the OP_ "m" is a "test"-mode instruction.
A "test"-mode instruction followed by a jump instruction.
Test mode includes:
- OP_EQ
- OP_LT
- OP_LE
- OP_TEST
- OP_TESTSET
assignment