diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2007-12-27 11:02:25 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2007-12-27 11:02:25 -0200 |
commit | f5ae26ec6c2eb69f03f316e59c1e1977c52c7c23 (patch) | |
tree | b4c761dac7648caea2cc20f8ebc2dd5b27a3fa1e /lcode.c | |
parent | 98194db4295726069137d13b8d24fca8cbf892b6 (diff) | |
download | lua-f5ae26ec6c2eb69f03f316e59c1e1977c52c7c23.tar.gz lua-f5ae26ec6c2eb69f03f316e59c1e1977c52c7c23.tar.bz2 lua-f5ae26ec6c2eb69f03f316e59c1e1977c52c7c23.zip |
official branch for Lua 5.1
Diffstat (limited to 'lcode.c')
-rw-r--r-- | lcode.c | 823 |
1 files changed, 0 insertions, 823 deletions
diff --git a/lcode.c b/lcode.c deleted file mode 100644 index b8ba2a98..00000000 --- a/lcode.c +++ /dev/null | |||
@@ -1,823 +0,0 @@ | |||
1 | /* | ||
2 | ** $Id: lcode.c,v 2.24 2005/12/22 16:19:56 roberto Exp roberto $ | ||
3 | ** Code generator for Lua | ||
4 | ** See Copyright Notice in lua.h | ||
5 | */ | ||
6 | |||
7 | |||
8 | #include <stdlib.h> | ||
9 | |||
10 | #define lcode_c | ||
11 | #define LUA_CORE | ||
12 | |||
13 | #include "lua.h" | ||
14 | |||
15 | #include "lcode.h" | ||
16 | #include "ldebug.h" | ||
17 | #include "ldo.h" | ||
18 | #include "lgc.h" | ||
19 | #include "llex.h" | ||
20 | #include "lmem.h" | ||
21 | #include "lobject.h" | ||
22 | #include "lopcodes.h" | ||
23 | #include "lparser.h" | ||
24 | #include "ltable.h" | ||
25 | |||
26 | |||
27 | #define hasjumps(e) ((e)->t != (e)->f) | ||
28 | |||
29 | |||
30 | static int isnumeral(expdesc *e) { | ||
31 | return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP); | ||
32 | } | ||
33 | |||
34 | |||
35 | void luaK_nil (FuncState *fs, int from, int n) { | ||
36 | Instruction *previous; | ||
37 | if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ | ||
38 | if (fs->pc == 0) /* function start? */ | ||
39 | return; /* positions are already clean */ | ||
40 | if (GET_OPCODE(*(previous = &fs->f->code[fs->pc-1])) == OP_LOADNIL) { | ||
41 | int pfrom = GETARG_A(*previous); | ||
42 | int pto = GETARG_B(*previous); | ||
43 | if (pfrom <= from && from <= pto+1) { /* can connect both? */ | ||
44 | if (from+n-1 > pto) | ||
45 | SETARG_B(*previous, from+n-1); | ||
46 | return; | ||
47 | } | ||
48 | } | ||
49 | } | ||
50 | luaK_codeABC(fs, OP_LOADNIL, from, from+n-1, 0); /* else no optimization */ | ||
51 | } | ||
52 | |||
53 | |||
54 | int luaK_jump (FuncState *fs) { | ||
55 | int jpc = fs->jpc; /* save list of jumps to here */ | ||
56 | int j; | ||
57 | fs->jpc = NO_JUMP; | ||
58 | j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP); | ||
59 | luaK_concat(fs, &j, jpc); /* keep them on hold */ | ||
60 | return j; | ||
61 | } | ||
62 | |||
63 | |||
64 | void luaK_ret (FuncState *fs, int first, int nret) { | ||
65 | luaK_codeABC(fs, OP_RETURN, first, nret+1, 0); | ||
66 | } | ||
67 | |||
68 | |||
69 | static int condjump (FuncState *fs, OpCode op, int A, int B, int C) { | ||
70 | luaK_codeABC(fs, op, A, B, C); | ||
71 | return luaK_jump(fs); | ||
72 | } | ||
73 | |||
74 | |||
75 | static void fixjump (FuncState *fs, int pc, int dest) { | ||
76 | Instruction *jmp = &fs->f->code[pc]; | ||
77 | int offset = dest-(pc+1); | ||
78 | lua_assert(dest != NO_JUMP); | ||
79 | if (abs(offset) > MAXARG_sBx) | ||
80 | luaX_syntaxerror(fs->ls, "control structure too long"); | ||
81 | SETARG_sBx(*jmp, offset); | ||
82 | } | ||
83 | |||
84 | |||
85 | /* | ||
86 | ** returns current `pc' and marks it as a jump target (to avoid wrong | ||
87 | ** optimizations with consecutive instructions not in the same basic block). | ||
88 | */ | ||
89 | int luaK_getlabel (FuncState *fs) { | ||
90 | fs->lasttarget = fs->pc; | ||
91 | return fs->pc; | ||
92 | } | ||
93 | |||
94 | |||
95 | static int getjump (FuncState *fs, int pc) { | ||
96 | int offset = GETARG_sBx(fs->f->code[pc]); | ||
97 | if (offset == NO_JUMP) /* point to itself represents end of list */ | ||
98 | return NO_JUMP; /* end of list */ | ||
99 | else | ||
100 | return (pc+1)+offset; /* turn offset into absolute position */ | ||
101 | } | ||
102 | |||
103 | |||
104 | static Instruction *getjumpcontrol (FuncState *fs, int pc) { | ||
105 | Instruction *pi = &fs->f->code[pc]; | ||
106 | if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1)))) | ||
107 | return pi-1; | ||
108 | else | ||
109 | return pi; | ||
110 | } | ||
111 | |||
112 | |||
113 | /* | ||
114 | ** check whether list has any jump that do not produce a value | ||
115 | ** (or produce an inverted value) | ||
116 | */ | ||
117 | static int need_value (FuncState *fs, int list) { | ||
118 | for (; list != NO_JUMP; list = getjump(fs, list)) { | ||
119 | Instruction i = *getjumpcontrol(fs, list); | ||
120 | if (GET_OPCODE(i) != OP_TESTSET) return 1; | ||
121 | } | ||
122 | return 0; /* not found */ | ||
123 | } | ||
124 | |||
125 | |||
126 | static int patchtestreg (FuncState *fs, int node, int reg) { | ||
127 | Instruction *i = getjumpcontrol(fs, node); | ||
128 | if (GET_OPCODE(*i) != OP_TESTSET) | ||
129 | return 0; /* cannot patch other instructions */ | ||
130 | if (reg != NO_REG && reg != GETARG_B(*i)) | ||
131 | SETARG_A(*i, reg); | ||
132 | else /* no register to put value or register already has the value */ | ||
133 | *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i)); | ||
134 | |||
135 | return 1; | ||
136 | } | ||
137 | |||
138 | |||
139 | static void removevalues (FuncState *fs, int list) { | ||
140 | for (; list != NO_JUMP; list = getjump(fs, list)) | ||
141 | patchtestreg(fs, list, NO_REG); | ||
142 | } | ||
143 | |||
144 | |||
145 | static void patchlistaux (FuncState *fs, int list, int vtarget, int reg, | ||
146 | int dtarget) { | ||
147 | while (list != NO_JUMP) { | ||
148 | int next = getjump(fs, list); | ||
149 | if (patchtestreg(fs, list, reg)) | ||
150 | fixjump(fs, list, vtarget); | ||
151 | else | ||
152 | fixjump(fs, list, dtarget); /* jump to default target */ | ||
153 | list = next; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | |||
158 | static void dischargejpc (FuncState *fs) { | ||
159 | patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc); | ||
160 | fs->jpc = NO_JUMP; | ||
161 | } | ||
162 | |||
163 | |||
164 | void luaK_patchlist (FuncState *fs, int list, int target) { | ||
165 | if (target == fs->pc) | ||
166 | luaK_patchtohere(fs, list); | ||
167 | else { | ||
168 | lua_assert(target < fs->pc); | ||
169 | patchlistaux(fs, list, target, NO_REG, target); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | |||
174 | void luaK_patchtohere (FuncState *fs, int list) { | ||
175 | luaK_getlabel(fs); | ||
176 | luaK_concat(fs, &fs->jpc, list); | ||
177 | } | ||
178 | |||
179 | |||
180 | void luaK_concat (FuncState *fs, int *l1, int l2) { | ||
181 | if (l2 == NO_JUMP) return; | ||
182 | else if (*l1 == NO_JUMP) | ||
183 | *l1 = l2; | ||
184 | else { | ||
185 | int list = *l1; | ||
186 | int next; | ||
187 | while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */ | ||
188 | list = next; | ||
189 | fixjump(fs, list, l2); | ||
190 | } | ||
191 | } | ||
192 | |||
193 | |||
194 | void luaK_checkstack (FuncState *fs, int n) { | ||
195 | int newstack = fs->freereg + n; | ||
196 | if (newstack > fs->f->maxstacksize) { | ||
197 | if (newstack >= MAXSTACK) | ||
198 | luaX_syntaxerror(fs->ls, "function or expression too complex"); | ||
199 | fs->f->maxstacksize = cast_byte(newstack); | ||
200 | } | ||
201 | } | ||
202 | |||
203 | |||
204 | void luaK_reserveregs (FuncState *fs, int n) { | ||
205 | luaK_checkstack(fs, n); | ||
206 | fs->freereg += n; | ||
207 | } | ||
208 | |||
209 | |||
210 | static void freereg (FuncState *fs, int reg) { | ||
211 | if (!ISK(reg) && reg >= fs->nactvar) { | ||
212 | fs->freereg--; | ||
213 | lua_assert(reg == fs->freereg); | ||
214 | } | ||
215 | } | ||
216 | |||
217 | |||
218 | static void freeexp (FuncState *fs, expdesc *e) { | ||
219 | if (e->k == VNONRELOC) | ||
220 | freereg(fs, e->u.s.info); | ||
221 | } | ||
222 | |||
223 | |||
224 | static int addk (FuncState *fs, TValue *k, TValue *v) { | ||
225 | lua_State *L = fs->L; | ||
226 | TValue *idx = luaH_set(L, fs->h, k); | ||
227 | Proto *f = fs->f; | ||
228 | int oldsize = f->sizek; | ||
229 | if (ttisnumber(idx)) { | ||
230 | lua_assert(luaO_rawequalObj(&fs->f->k[cast_int(nvalue(idx))], v)); | ||
231 | return cast_int(nvalue(idx)); | ||
232 | } | ||
233 | else { /* constant not found; create a new entry */ | ||
234 | setnvalue(idx, cast_num(fs->nk)); | ||
235 | luaM_growvector(L, f->k, fs->nk, f->sizek, TValue, | ||
236 | MAXARG_Bx, "constant table overflow"); | ||
237 | while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]); | ||
238 | setobj(L, &f->k[fs->nk], v); | ||
239 | luaC_barrier(L, f, v); | ||
240 | return fs->nk++; | ||
241 | } | ||
242 | } | ||
243 | |||
244 | |||
245 | int luaK_stringK (FuncState *fs, TString *s) { | ||
246 | TValue o; | ||
247 | setsvalue(fs->L, &o, s); | ||
248 | return addk(fs, &o, &o); | ||
249 | } | ||
250 | |||
251 | |||
252 | int luaK_numberK (FuncState *fs, lua_Number r) { | ||
253 | TValue o; | ||
254 | setnvalue(&o, r); | ||
255 | return addk(fs, &o, &o); | ||
256 | } | ||
257 | |||
258 | |||
259 | static int boolK (FuncState *fs, int b) { | ||
260 | TValue o; | ||
261 | setbvalue(&o, b); | ||
262 | return addk(fs, &o, &o); | ||
263 | } | ||
264 | |||
265 | |||
266 | static int nilK (FuncState *fs) { | ||
267 | TValue k, v; | ||
268 | setnilvalue(&v); | ||
269 | /* cannot use nil as key; instead use table itself to represent nil */ | ||
270 | sethvalue(fs->L, &k, fs->h); | ||
271 | return addk(fs, &k, &v); | ||
272 | } | ||
273 | |||
274 | |||
275 | void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) { | ||
276 | if (e->k == VCALL) { /* expression is an open function call? */ | ||
277 | SETARG_C(getcode(fs, e), nresults+1); | ||
278 | } | ||
279 | else if (e->k == VVARARG) { | ||
280 | SETARG_B(getcode(fs, e), nresults+1); | ||
281 | SETARG_A(getcode(fs, e), fs->freereg); | ||
282 | luaK_reserveregs(fs, 1); | ||
283 | } | ||
284 | } | ||
285 | |||
286 | |||
287 | void luaK_setoneret (FuncState *fs, expdesc *e) { | ||
288 | if (e->k == VCALL) { /* expression is an open function call? */ | ||
289 | e->k = VNONRELOC; | ||
290 | e->u.s.info = GETARG_A(getcode(fs, e)); | ||
291 | } | ||
292 | else if (e->k == VVARARG) { | ||
293 | SETARG_B(getcode(fs, e), 2); | ||
294 | e->k = VRELOCABLE; /* can relocate its simple result */ | ||
295 | } | ||
296 | } | ||
297 | |||
298 | |||
299 | void luaK_dischargevars (FuncState *fs, expdesc *e) { | ||
300 | switch (e->k) { | ||
301 | case VLOCAL: { | ||
302 | e->k = VNONRELOC; | ||
303 | break; | ||
304 | } | ||
305 | case VUPVAL: { | ||
306 | e->u.s.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.s.info, 0); | ||
307 | e->k = VRELOCABLE; | ||
308 | break; | ||
309 | } | ||
310 | case VGLOBAL: { | ||
311 | e->u.s.info = luaK_codeABx(fs, OP_GETGLOBAL, 0, e->u.s.info); | ||
312 | e->k = VRELOCABLE; | ||
313 | break; | ||
314 | } | ||
315 | case VINDEXED: { | ||
316 | freereg(fs, e->u.s.aux); | ||
317 | freereg(fs, e->u.s.info); | ||
318 | e->u.s.info = luaK_codeABC(fs, OP_GETTABLE, 0, e->u.s.info, e->u.s.aux); | ||
319 | e->k = VRELOCABLE; | ||
320 | break; | ||
321 | } | ||
322 | case VVARARG: | ||
323 | case VCALL: { | ||
324 | luaK_setoneret(fs, e); | ||
325 | break; | ||
326 | } | ||
327 | default: break; /* there is one value available (somewhere) */ | ||
328 | } | ||
329 | } | ||
330 | |||
331 | |||
332 | static int code_label (FuncState *fs, int A, int b, int jump) { | ||
333 | luaK_getlabel(fs); /* those instructions may be jump targets */ | ||
334 | return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump); | ||
335 | } | ||
336 | |||
337 | |||
338 | static void discharge2reg (FuncState *fs, expdesc *e, int reg) { | ||
339 | luaK_dischargevars(fs, e); | ||
340 | switch (e->k) { | ||
341 | case VNIL: { | ||
342 | luaK_nil(fs, reg, 1); | ||
343 | break; | ||
344 | } | ||
345 | case VFALSE: case VTRUE: { | ||
346 | luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0); | ||
347 | break; | ||
348 | } | ||
349 | case VK: { | ||
350 | luaK_codeABx(fs, OP_LOADK, reg, e->u.s.info); | ||
351 | break; | ||
352 | } | ||
353 | case VKNUM: { | ||
354 | luaK_codeABx(fs, OP_LOADK, reg, luaK_numberK(fs, e->u.nval)); | ||
355 | break; | ||
356 | } | ||
357 | case VRELOCABLE: { | ||
358 | Instruction *pc = &getcode(fs, e); | ||
359 | SETARG_A(*pc, reg); | ||
360 | break; | ||
361 | } | ||
362 | case VNONRELOC: { | ||
363 | if (reg != e->u.s.info) | ||
364 | luaK_codeABC(fs, OP_MOVE, reg, e->u.s.info, 0); | ||
365 | break; | ||
366 | } | ||
367 | default: { | ||
368 | lua_assert(e->k == VVOID || e->k == VJMP); | ||
369 | return; /* nothing to do... */ | ||
370 | } | ||
371 | } | ||
372 | e->u.s.info = reg; | ||
373 | e->k = VNONRELOC; | ||
374 | } | ||
375 | |||
376 | |||
377 | static void discharge2anyreg (FuncState *fs, expdesc *e) { | ||
378 | if (e->k != VNONRELOC) { | ||
379 | luaK_reserveregs(fs, 1); | ||
380 | discharge2reg(fs, e, fs->freereg-1); | ||
381 | } | ||
382 | } | ||
383 | |||
384 | |||
385 | static void exp2reg (FuncState *fs, expdesc *e, int reg) { | ||
386 | discharge2reg(fs, e, reg); | ||
387 | if (e->k == VJMP) | ||
388 | luaK_concat(fs, &e->t, e->u.s.info); /* put this jump in `t' list */ | ||
389 | if (hasjumps(e)) { | ||
390 | int final; /* position after whole expression */ | ||
391 | int p_f = NO_JUMP; /* position of an eventual LOAD false */ | ||
392 | int p_t = NO_JUMP; /* position of an eventual LOAD true */ | ||
393 | if (need_value(fs, e->t) || need_value(fs, e->f)) { | ||
394 | int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs); | ||
395 | p_f = code_label(fs, reg, 0, 1); | ||
396 | p_t = code_label(fs, reg, 1, 0); | ||
397 | luaK_patchtohere(fs, fj); | ||
398 | } | ||
399 | final = luaK_getlabel(fs); | ||
400 | patchlistaux(fs, e->f, final, reg, p_f); | ||
401 | patchlistaux(fs, e->t, final, reg, p_t); | ||
402 | } | ||
403 | e->f = e->t = NO_JUMP; | ||
404 | e->u.s.info = reg; | ||
405 | e->k = VNONRELOC; | ||
406 | } | ||
407 | |||
408 | |||
409 | void luaK_exp2nextreg (FuncState *fs, expdesc *e) { | ||
410 | luaK_dischargevars(fs, e); | ||
411 | freeexp(fs, e); | ||
412 | luaK_reserveregs(fs, 1); | ||
413 | exp2reg(fs, e, fs->freereg - 1); | ||
414 | } | ||
415 | |||
416 | |||
417 | int luaK_exp2anyreg (FuncState *fs, expdesc *e) { | ||
418 | luaK_dischargevars(fs, e); | ||
419 | if (e->k == VNONRELOC) { | ||
420 | if (!hasjumps(e)) return e->u.s.info; /* exp is already in a register */ | ||
421 | if (e->u.s.info >= fs->nactvar) { /* reg. is not a local? */ | ||
422 | exp2reg(fs, e, e->u.s.info); /* put value on it */ | ||
423 | return e->u.s.info; | ||
424 | } | ||
425 | } | ||
426 | luaK_exp2nextreg(fs, e); /* default */ | ||
427 | return e->u.s.info; | ||
428 | } | ||
429 | |||
430 | |||
431 | void luaK_exp2val (FuncState *fs, expdesc *e) { | ||
432 | if (hasjumps(e)) | ||
433 | luaK_exp2anyreg(fs, e); | ||
434 | else | ||
435 | luaK_dischargevars(fs, e); | ||
436 | } | ||
437 | |||
438 | |||
439 | int luaK_exp2RK (FuncState *fs, expdesc *e) { | ||
440 | luaK_exp2val(fs, e); | ||
441 | switch (e->k) { | ||
442 | case VKNUM: | ||
443 | case VTRUE: | ||
444 | case VFALSE: | ||
445 | case VNIL: { | ||
446 | if (fs->nk <= MAXINDEXRK) { /* constant fit in RK operand? */ | ||
447 | e->u.s.info = (e->k == VNIL) ? nilK(fs) : | ||
448 | (e->k == VKNUM) ? luaK_numberK(fs, e->u.nval) : | ||
449 | boolK(fs, (e->k == VTRUE)); | ||
450 | e->k = VK; | ||
451 | return RKASK(e->u.s.info); | ||
452 | } | ||
453 | else break; | ||
454 | } | ||
455 | case VK: { | ||
456 | if (e->u.s.info <= MAXINDEXRK) /* constant fit in argC? */ | ||
457 | return RKASK(e->u.s.info); | ||
458 | else break; | ||
459 | } | ||
460 | default: break; | ||
461 | } | ||
462 | /* not a constant in the right range: put it in a register */ | ||
463 | return luaK_exp2anyreg(fs, e); | ||
464 | } | ||
465 | |||
466 | |||
467 | void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) { | ||
468 | switch (var->k) { | ||
469 | case VLOCAL: { | ||
470 | freeexp(fs, ex); | ||
471 | exp2reg(fs, ex, var->u.s.info); | ||
472 | return; | ||
473 | } | ||
474 | case VUPVAL: { | ||
475 | int e = luaK_exp2anyreg(fs, ex); | ||
476 | luaK_codeABC(fs, OP_SETUPVAL, e, var->u.s.info, 0); | ||
477 | break; | ||
478 | } | ||
479 | case VGLOBAL: { | ||
480 | int e = luaK_exp2anyreg(fs, ex); | ||
481 | luaK_codeABx(fs, OP_SETGLOBAL, e, var->u.s.info); | ||
482 | break; | ||
483 | } | ||
484 | case VINDEXED: { | ||
485 | int e = luaK_exp2RK(fs, ex); | ||
486 | luaK_codeABC(fs, OP_SETTABLE, var->u.s.info, var->u.s.aux, e); | ||
487 | break; | ||
488 | } | ||
489 | default: { | ||
490 | lua_assert(0); /* invalid var kind to store */ | ||
491 | break; | ||
492 | } | ||
493 | } | ||
494 | freeexp(fs, ex); | ||
495 | } | ||
496 | |||
497 | |||
498 | void luaK_self (FuncState *fs, expdesc *e, expdesc *key) { | ||
499 | int func; | ||
500 | luaK_exp2anyreg(fs, e); | ||
501 | freeexp(fs, e); | ||
502 | func = fs->freereg; | ||
503 | luaK_reserveregs(fs, 2); | ||
504 | luaK_codeABC(fs, OP_SELF, func, e->u.s.info, luaK_exp2RK(fs, key)); | ||
505 | freeexp(fs, key); | ||
506 | e->u.s.info = func; | ||
507 | e->k = VNONRELOC; | ||
508 | } | ||
509 | |||
510 | |||
511 | static void invertjump (FuncState *fs, expdesc *e) { | ||
512 | Instruction *pc = getjumpcontrol(fs, e->u.s.info); | ||
513 | lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET && | ||
514 | GET_OPCODE(*pc) != OP_TEST); | ||
515 | SETARG_A(*pc, !(GETARG_A(*pc))); | ||
516 | } | ||
517 | |||
518 | |||
519 | static int jumponcond (FuncState *fs, expdesc *e, int cond) { | ||
520 | if (e->k == VRELOCABLE) { | ||
521 | Instruction ie = getcode(fs, e); | ||
522 | if (GET_OPCODE(ie) == OP_NOT) { | ||
523 | fs->pc--; /* remove previous OP_NOT */ | ||
524 | return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond); | ||
525 | } | ||
526 | /* else go through */ | ||
527 | } | ||
528 | discharge2anyreg(fs, e); | ||
529 | freeexp(fs, e); | ||
530 | return condjump(fs, OP_TESTSET, NO_REG, e->u.s.info, cond); | ||
531 | } | ||
532 | |||
533 | |||
534 | void luaK_goiftrue (FuncState *fs, expdesc *e) { | ||
535 | int pc; /* pc of last jump */ | ||
536 | luaK_dischargevars(fs, e); | ||
537 | switch (e->k) { | ||
538 | case VK: case VKNUM: case VTRUE: { | ||
539 | pc = NO_JUMP; /* always true; do nothing */ | ||
540 | break; | ||
541 | } | ||
542 | case VFALSE: { | ||
543 | pc = luaK_jump(fs); /* always jump */ | ||
544 | break; | ||
545 | } | ||
546 | case VJMP: { | ||
547 | invertjump(fs, e); | ||
548 | pc = e->u.s.info; | ||
549 | break; | ||
550 | } | ||
551 | default: { | ||
552 | pc = jumponcond(fs, e, 0); | ||
553 | break; | ||
554 | } | ||
555 | } | ||
556 | luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */ | ||
557 | luaK_patchtohere(fs, e->t); | ||
558 | e->t = NO_JUMP; | ||
559 | } | ||
560 | |||
561 | |||
562 | static void luaK_goiffalse (FuncState *fs, expdesc *e) { | ||
563 | int pc; /* pc of last jump */ | ||
564 | luaK_dischargevars(fs, e); | ||
565 | switch (e->k) { | ||
566 | case VNIL: case VFALSE: { | ||
567 | pc = NO_JUMP; /* always false; do nothing */ | ||
568 | break; | ||
569 | } | ||
570 | case VTRUE: { | ||
571 | pc = luaK_jump(fs); /* always jump */ | ||
572 | break; | ||
573 | } | ||
574 | case VJMP: { | ||
575 | pc = e->u.s.info; | ||
576 | break; | ||
577 | } | ||
578 | default: { | ||
579 | pc = jumponcond(fs, e, 1); | ||
580 | break; | ||
581 | } | ||
582 | } | ||
583 | luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */ | ||
584 | luaK_patchtohere(fs, e->f); | ||
585 | e->f = NO_JUMP; | ||
586 | } | ||
587 | |||
588 | |||
589 | static void codenot (FuncState *fs, expdesc *e) { | ||
590 | luaK_dischargevars(fs, e); | ||
591 | switch (e->k) { | ||
592 | case VNIL: case VFALSE: { | ||
593 | e->k = VTRUE; | ||
594 | break; | ||
595 | } | ||
596 | case VK: case VKNUM: case VTRUE: { | ||
597 | e->k = VFALSE; | ||
598 | break; | ||
599 | } | ||
600 | case VJMP: { | ||
601 | invertjump(fs, e); | ||
602 | break; | ||
603 | } | ||
604 | case VRELOCABLE: | ||
605 | case VNONRELOC: { | ||
606 | discharge2anyreg(fs, e); | ||
607 | freeexp(fs, e); | ||
608 | e->u.s.info = luaK_codeABC(fs, OP_NOT, 0, e->u.s.info, 0); | ||
609 | e->k = VRELOCABLE; | ||
610 | break; | ||
611 | } | ||
612 | default: { | ||
613 | lua_assert(0); /* cannot happen */ | ||
614 | break; | ||
615 | } | ||
616 | } | ||
617 | /* interchange true and false lists */ | ||
618 | { int temp = e->f; e->f = e->t; e->t = temp; } | ||
619 | removevalues(fs, e->f); | ||
620 | removevalues(fs, e->t); | ||
621 | } | ||
622 | |||
623 | |||
624 | void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { | ||
625 | t->u.s.aux = luaK_exp2RK(fs, k); | ||
626 | t->k = VINDEXED; | ||
627 | } | ||
628 | |||
629 | |||
630 | static int constfolding (OpCode op, expdesc *e1, expdesc *e2) { | ||
631 | lua_Number v1, v2, r; | ||
632 | if (!isnumeral(e1) || !isnumeral(e2)) return 0; | ||
633 | v1 = e1->u.nval; | ||
634 | v2 = e2->u.nval; | ||
635 | switch (op) { | ||
636 | case OP_ADD: r = luai_numadd(v1, v2); break; | ||
637 | case OP_SUB: r = luai_numsub(v1, v2); break; | ||
638 | case OP_MUL: r = luai_nummul(v1, v2); break; | ||
639 | case OP_DIV: | ||
640 | if (v2 == 0) return 0; /* do not attempt to divide by 0 */ | ||
641 | r = luai_numdiv(v1, v2); break; | ||
642 | case OP_MOD: | ||
643 | if (v2 == 0) return 0; /* do not attempt to divide by 0 */ | ||
644 | r = luai_nummod(v1, v2); break; | ||
645 | case OP_POW: r = luai_numpow(v1, v2); break; | ||
646 | case OP_UNM: r = luai_numunm(v1); break; | ||
647 | case OP_LEN: return 0; /* no constant folding for 'len' */ | ||
648 | default: lua_assert(0); r = 0; break; | ||
649 | } | ||
650 | if (luai_numisnan(r)) return 0; /* do not attempt to produce NaN */ | ||
651 | e1->u.nval = r; | ||
652 | return 1; | ||
653 | } | ||
654 | |||
655 | |||
656 | static void codearith (FuncState *fs, OpCode op, expdesc *e1, expdesc *e2) { | ||
657 | if (constfolding(op, e1, e2)) | ||
658 | return; | ||
659 | else { | ||
660 | int o1 = luaK_exp2RK(fs, e1); | ||
661 | int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0; | ||
662 | freeexp(fs, e2); | ||
663 | freeexp(fs, e1); | ||
664 | e1->u.s.info = luaK_codeABC(fs, op, 0, o1, o2); | ||
665 | e1->k = VRELOCABLE; | ||
666 | } | ||
667 | } | ||
668 | |||
669 | |||
670 | static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, | ||
671 | expdesc *e2) { | ||
672 | int o1 = luaK_exp2RK(fs, e1); | ||
673 | int o2 = luaK_exp2RK(fs, e2); | ||
674 | freeexp(fs, e2); | ||
675 | freeexp(fs, e1); | ||
676 | if (cond == 0 && op != OP_EQ) { | ||
677 | int temp; /* exchange args to replace by `<' or `<=' */ | ||
678 | temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ | ||
679 | cond = 1; | ||
680 | } | ||
681 | e1->u.s.info = condjump(fs, op, cond, o1, o2); | ||
682 | e1->k = VJMP; | ||
683 | } | ||
684 | |||
685 | |||
686 | void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e) { | ||
687 | expdesc e2; | ||
688 | e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0; | ||
689 | switch (op) { | ||
690 | case OPR_MINUS: { | ||
691 | if (e->k == VK) | ||
692 | luaK_exp2anyreg(fs, e); /* cannot operate on non-numeric constants */ | ||
693 | codearith(fs, OP_UNM, e, &e2); | ||
694 | break; | ||
695 | } | ||
696 | case OPR_NOT: codenot(fs, e); break; | ||
697 | case OPR_LEN: { | ||
698 | luaK_exp2anyreg(fs, e); /* cannot operate on constants */ | ||
699 | codearith(fs, OP_LEN, e, &e2); | ||
700 | break; | ||
701 | } | ||
702 | default: lua_assert(0); | ||
703 | } | ||
704 | } | ||
705 | |||
706 | |||
707 | void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { | ||
708 | switch (op) { | ||
709 | case OPR_AND: { | ||
710 | luaK_goiftrue(fs, v); | ||
711 | break; | ||
712 | } | ||
713 | case OPR_OR: { | ||
714 | luaK_goiffalse(fs, v); | ||
715 | break; | ||
716 | } | ||
717 | case OPR_CONCAT: { | ||
718 | luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */ | ||
719 | break; | ||
720 | } | ||
721 | default: { | ||
722 | if (!isnumeral(v)) luaK_exp2RK(fs, v); | ||
723 | break; | ||
724 | } | ||
725 | } | ||
726 | } | ||
727 | |||
728 | |||
729 | void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { | ||
730 | switch (op) { | ||
731 | case OPR_AND: { | ||
732 | lua_assert(e1->t == NO_JUMP); /* list must be closed */ | ||
733 | luaK_dischargevars(fs, e2); | ||
734 | luaK_concat(fs, &e2->f, e1->f); | ||
735 | *e1 = *e2; | ||
736 | break; | ||
737 | } | ||
738 | case OPR_OR: { | ||
739 | lua_assert(e1->f == NO_JUMP); /* list must be closed */ | ||
740 | luaK_dischargevars(fs, e2); | ||
741 | luaK_concat(fs, &e2->t, e1->t); | ||
742 | *e1 = *e2; | ||
743 | break; | ||
744 | } | ||
745 | case OPR_CONCAT: { | ||
746 | luaK_exp2val(fs, e2); | ||
747 | if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) { | ||
748 | lua_assert(e1->u.s.info == GETARG_B(getcode(fs, e2))-1); | ||
749 | freeexp(fs, e1); | ||
750 | SETARG_B(getcode(fs, e2), e1->u.s.info); | ||
751 | e1->k = VRELOCABLE; e1->u.s.info = e2->u.s.info; | ||
752 | } | ||
753 | else { | ||
754 | luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ | ||
755 | codearith(fs, OP_CONCAT, e1, e2); | ||
756 | } | ||
757 | break; | ||
758 | } | ||
759 | case OPR_ADD: codearith(fs, OP_ADD, e1, e2); break; | ||
760 | case OPR_SUB: codearith(fs, OP_SUB, e1, e2); break; | ||
761 | case OPR_MUL: codearith(fs, OP_MUL, e1, e2); break; | ||
762 | case OPR_DIV: codearith(fs, OP_DIV, e1, e2); break; | ||
763 | case OPR_MOD: codearith(fs, OP_MOD, e1, e2); break; | ||
764 | case OPR_POW: codearith(fs, OP_POW, e1, e2); break; | ||
765 | case OPR_EQ: codecomp(fs, OP_EQ, 1, e1, e2); break; | ||
766 | case OPR_NE: codecomp(fs, OP_EQ, 0, e1, e2); break; | ||
767 | case OPR_LT: codecomp(fs, OP_LT, 1, e1, e2); break; | ||
768 | case OPR_LE: codecomp(fs, OP_LE, 1, e1, e2); break; | ||
769 | case OPR_GT: codecomp(fs, OP_LT, 0, e1, e2); break; | ||
770 | case OPR_GE: codecomp(fs, OP_LE, 0, e1, e2); break; | ||
771 | default: lua_assert(0); | ||
772 | } | ||
773 | } | ||
774 | |||
775 | |||
776 | void luaK_fixline (FuncState *fs, int line) { | ||
777 | fs->f->lineinfo[fs->pc - 1] = line; | ||
778 | } | ||
779 | |||
780 | |||
781 | static int luaK_code (FuncState *fs, Instruction i, int line) { | ||
782 | Proto *f = fs->f; | ||
783 | dischargejpc(fs); /* `pc' will change */ | ||
784 | /* put new instruction in code array */ | ||
785 | luaM_growvector(fs->L, f->code, fs->pc, f->sizecode, Instruction, | ||
786 | MAX_INT, "code size overflow"); | ||
787 | f->code[fs->pc] = i; | ||
788 | /* save corresponding line information */ | ||
789 | luaM_growvector(fs->L, f->lineinfo, fs->pc, f->sizelineinfo, int, | ||
790 | MAX_INT, "code size overflow"); | ||
791 | f->lineinfo[fs->pc] = line; | ||
792 | return fs->pc++; | ||
793 | } | ||
794 | |||
795 | |||
796 | int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) { | ||
797 | lua_assert(getOpMode(o) == iABC); | ||
798 | lua_assert(getBMode(o) != OpArgN || b == 0); | ||
799 | lua_assert(getCMode(o) != OpArgN || c == 0); | ||
800 | return luaK_code(fs, CREATE_ABC(o, a, b, c), fs->ls->lastline); | ||
801 | } | ||
802 | |||
803 | |||
804 | int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) { | ||
805 | lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx); | ||
806 | lua_assert(getCMode(o) == OpArgN); | ||
807 | return luaK_code(fs, CREATE_ABx(o, a, bc), fs->ls->lastline); | ||
808 | } | ||
809 | |||
810 | |||
811 | void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) { | ||
812 | int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1; | ||
813 | int b = (tostore == LUA_MULTRET) ? 0 : tostore; | ||
814 | lua_assert(tostore != 0); | ||
815 | if (c <= MAXARG_C) | ||
816 | luaK_codeABC(fs, OP_SETLIST, base, b, c); | ||
817 | else { | ||
818 | luaK_codeABC(fs, OP_SETLIST, base, b, 0); | ||
819 | luaK_code(fs, cast(Instruction, c), fs->ls->lastline); | ||
820 | } | ||
821 | fs->freereg = base + 1; /* free registers with list values */ | ||
822 | } | ||
823 | |||