diff options
-rw-r--r-- | lcode.c | 200 |
1 files changed, 133 insertions, 67 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lcode.c,v 1.24 2000/04/12 18:57:19 roberto Exp roberto $ | 2 | ** $Id: lcode.c,v 1.25 2000/04/13 16:51:01 roberto Exp roberto $ |
3 | ** Code generator for Lua | 3 | ** Code generator for Lua |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -304,6 +304,49 @@ void luaK_goiffalse (FuncState *fs, expdesc *v, int keepvalue) { | |||
304 | } | 304 | } |
305 | 305 | ||
306 | 306 | ||
307 | static int code_label (FuncState *fs, OpCode op, int arg) { | ||
308 | int j = luaK_getlabel(fs); | ||
309 | luaK_code1(fs, op, arg); | ||
310 | return j; | ||
311 | } | ||
312 | |||
313 | |||
314 | static void jump_to_value (FuncState *fs, expdesc *v, Instruction previous) { | ||
315 | int p_nil = NO_JUMP; /* position of an eventual PUSHNIL */ | ||
316 | int p_1 = NO_JUMP; /* position of an eventual PUSHINT */ | ||
317 | int final; /* position after whole expression */ | ||
318 | if (ISJUMP(previous)) { | ||
319 | luaK_concat(fs, &v->u.l.t, fs->pc-1); /* put `previous' in true list */ | ||
320 | p_nil = code_label(fs, OP_PUSHNILJMP, 0); | ||
321 | p_1 = code_label(fs, OP_PUSHINT, 1); | ||
322 | } | ||
323 | else { /* still may need a PUSHNIL or a PUSHINT */ | ||
324 | int need_nil = need_value(fs, v->u.l.f, OP_JMPONF); | ||
325 | int need_1 = need_value(fs, v->u.l.t, OP_JMPONT); | ||
326 | if (need_nil && need_1) { | ||
327 | int j = code_label(fs, OP_JMP, 0); /* skip both pushes */ | ||
328 | p_nil = code_label(fs, OP_PUSHNILJMP, 0); | ||
329 | p_1 = code_label(fs, OP_PUSHINT, 1); | ||
330 | luaK_patchlist(fs, j, luaK_getlabel(fs)); | ||
331 | luaK_deltastack(fs, -1); /* previous PUSHINT may be skipped */ | ||
332 | } | ||
333 | else if (need_nil || need_1) { | ||
334 | int j = code_label(fs, OP_JMP, 0); /* skip one push */ | ||
335 | if (need_nil) | ||
336 | p_nil = code_label(fs, OP_PUSHNIL, 1); | ||
337 | else /* need_1 */ | ||
338 | p_1 = code_label(fs, OP_PUSHINT, 1); | ||
339 | luaK_patchlist(fs, j, luaK_getlabel(fs)); | ||
340 | luaK_deltastack(fs, -1); /* previous PUSHs may be skipped */ | ||
341 | } | ||
342 | } | ||
343 | final = luaK_getlabel(fs); | ||
344 | luaK_patchlistaux(fs, v->u.l.f, p_nil, OP_JMPONF, final); | ||
345 | luaK_patchlistaux(fs, v->u.l.t, p_1, OP_JMPONT, final); | ||
346 | v->u.l.f = v->u.l.t = NO_JUMP; | ||
347 | } | ||
348 | |||
349 | |||
307 | void luaK_tostack (LexState *ls, expdesc *v, int onlyone) { | 350 | void luaK_tostack (LexState *ls, expdesc *v, int onlyone) { |
308 | FuncState *fs = ls->fs; | 351 | FuncState *fs = ls->fs; |
309 | if (!discharge(fs, v)) { /* `v' is an expression? */ | 352 | if (!discharge(fs, v)) { /* `v' is an expression? */ |
@@ -314,38 +357,8 @@ void luaK_tostack (LexState *ls, expdesc *v, int onlyone) { | |||
314 | if (onlyone) | 357 | if (onlyone) |
315 | luaK_setcallreturns(fs, 1); /* call must return 1 value */ | 358 | luaK_setcallreturns(fs, 1); /* call must return 1 value */ |
316 | } | 359 | } |
317 | else { /* expression has jumps... */ | 360 | else /* expression has jumps... */ |
318 | int p_nil = 0; /* position of an eventual PUSHNIL */ | 361 | jump_to_value(fs, v, previous); |
319 | int p_1 = 0; /* position of an eventual PUSHINT */ | ||
320 | int final; /* position after whole expression */ | ||
321 | if (ISJUMP(previous)) { | ||
322 | luaK_concat(fs, &v->u.l.t, fs->pc-1); /* put `previous' in true list */ | ||
323 | p_nil = luaK_code0(fs, OP_PUSHNILJMP); | ||
324 | p_1 = luaK_code1(fs, OP_PUSHINT, 1); | ||
325 | } | ||
326 | else { /* still may need a PUSHNIL or a PUSHINT */ | ||
327 | int need_nil = need_value(fs, v->u.l.f, OP_JMPONF); | ||
328 | int need_1 = need_value(fs, v->u.l.t, OP_JMPONT); | ||
329 | if (need_nil && need_1) { | ||
330 | luaK_code1(fs, OP_JMP, 2); /* skip both pushes */ | ||
331 | p_nil = luaK_code0(fs, OP_PUSHNILJMP); | ||
332 | p_1 = luaK_code1(fs, OP_PUSHINT, 1); | ||
333 | luaK_deltastack(fs, -1); /* previous PUSHINT may be skipped */ | ||
334 | } | ||
335 | else if (need_nil || need_1) { | ||
336 | luaK_code1(fs, OP_JMP, 1); /* skip one push */ | ||
337 | if (need_nil) | ||
338 | p_nil = luaK_code1(fs, OP_PUSHNIL, 1); | ||
339 | else /* need_1 */ | ||
340 | p_1 = luaK_code1(fs, OP_PUSHINT, 1); | ||
341 | luaK_deltastack(fs, -1); /* previous PUSHs may be skipped */ | ||
342 | } | ||
343 | } | ||
344 | final = luaK_getlabel(fs); | ||
345 | luaK_patchlistaux(fs, v->u.l.f, p_nil, OP_JMPONF, final); | ||
346 | luaK_patchlistaux(fs, v->u.l.t, p_1, OP_JMPONT, final); | ||
347 | v->u.l.f = v->u.l.t = NO_JUMP; | ||
348 | } | ||
349 | } | 362 | } |
350 | } | 363 | } |
351 | 364 | ||
@@ -431,37 +444,93 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) { | |||
431 | int delta = 0; | 444 | int delta = 0; |
432 | enum {iO, iU, iS, iAB, iP} mode; /* instruction format (or iP to optimize) */ | 445 | enum {iO, iU, iS, iAB, iP} mode; /* instruction format (or iP to optimize) */ |
433 | mode = iP; | 446 | mode = iP; |
447 | |||
434 | switch (o) { | 448 | switch (o) { |
435 | 449 | ||
436 | case OP_CLOSURE: delta = -arg2+1; mode = iAB; break; | 450 | case OP_CLOSURE: |
437 | case OP_SETLINE: mode = iU; break; | 451 | delta = -arg2+1; |
438 | case OP_CALL: mode = iAB; break; | 452 | mode = iAB; |
439 | case OP_PUSHINT: delta = 1; mode = iS; break; | 453 | break; |
440 | case OP_SETGLOBAL: delta = -1; mode = iU; break; | 454 | |
441 | case OP_SETTABLE: delta = -arg2; mode = iAB; break; | 455 | case OP_SETLINE: |
442 | case OP_SETLIST: delta = -(arg2+1); mode = iAB; break; | 456 | mode = iU; |
443 | case OP_SETMAP: delta = -2*(arg1+1); mode = iU; break; | 457 | break; |
444 | case OP_FORLOOP: delta = -3; arg1 = NO_JUMP; mode = iS; break; | 458 | |
459 | case OP_CALL: | ||
460 | mode = iAB; | ||
461 | break; | ||
462 | |||
463 | case OP_PUSHINT: | ||
464 | delta = 1; | ||
465 | mode = iS; | ||
466 | break; | ||
467 | |||
468 | case OP_SETTABLE: | ||
469 | delta = -arg2; | ||
470 | mode = iAB; | ||
471 | break; | ||
472 | |||
473 | case OP_SETLIST: | ||
474 | delta = -(arg2+1); | ||
475 | mode = iAB; | ||
476 | break; | ||
445 | 477 | ||
446 | case OP_FORPREP: arg1 = NO_JUMP; /* go through */ | 478 | case OP_SETMAP: |
447 | case OP_JMP: mode = iS; break; | 479 | delta = -2*(arg1+1); |
480 | mode = iU; | ||
481 | break; | ||
448 | 482 | ||
449 | case OP_END: case OP_PUSHNILJMP: case OP_NOT: | 483 | case OP_FORLOOP: |
450 | mode = iO; break; | 484 | delta = -3; |
485 | arg1 = NO_JUMP; | ||
486 | mode = iS; | ||
487 | break; | ||
451 | 488 | ||
452 | case OP_PUSHSTRING: case OP_PUSHNUM: | 489 | case OP_SETLOCAL: |
453 | case OP_PUSHNEGNUM: case OP_PUSHUPVALUE: | 490 | case OP_SETGLOBAL: |
454 | case OP_GETGLOBAL: case OP_PUSHSELF: case OP_CREATETABLE: | 491 | delta = -1; |
455 | delta = 1; mode = iU; break; | 492 | mode = iU; |
493 | break; | ||
456 | 494 | ||
457 | case OP_JMPLT: case OP_JMPLE: case OP_JMPGT: case OP_JMPGE: | 495 | case OP_FORPREP: |
458 | delta = -2; arg1 = NO_JUMP; mode = iS; break; | 496 | case OP_JMP: |
497 | arg1 = NO_JUMP; | ||
498 | mode = iS; | ||
499 | break; | ||
459 | 500 | ||
460 | case OP_MULT: case OP_DIV: case OP_POW: | 501 | case OP_END: |
461 | delta = -1; mode = iO; break; | 502 | case OP_PUSHNILJMP: |
503 | case OP_NOT: | ||
504 | mode = iO; | ||
505 | break; | ||
462 | 506 | ||
463 | case OP_SETLOCAL: /* `setlocal' default pops one value */ | 507 | case OP_PUSHSTRING: |
464 | delta = -1; arg2 = 1; mode = iAB; break; | 508 | case OP_PUSHNUM: |
509 | case OP_PUSHNEGNUM: | ||
510 | case OP_PUSHUPVALUE: | ||
511 | case OP_GETLOCAL: | ||
512 | case OP_GETGLOBAL: | ||
513 | case OP_PUSHSELF: | ||
514 | case OP_CREATETABLE: | ||
515 | delta = 1; | ||
516 | mode = iU; | ||
517 | break; | ||
518 | |||
519 | case OP_JMPLT: | ||
520 | case OP_JMPLE: | ||
521 | case OP_JMPGT: | ||
522 | case OP_JMPGE: | ||
523 | delta = -2; | ||
524 | arg1 = NO_JUMP; | ||
525 | mode = iS; | ||
526 | break; | ||
527 | |||
528 | case OP_MULT: | ||
529 | case OP_DIV: | ||
530 | case OP_POW: | ||
531 | delta = -1; | ||
532 | mode = iO; | ||
533 | break; | ||
465 | 534 | ||
466 | case OP_RETURN: | 535 | case OP_RETURN: |
467 | if (GET_OPCODE(i) == OP_CALL && GETARG_B(i) == MULT_RET) { | 536 | if (GET_OPCODE(i) == OP_CALL && GETARG_B(i) == MULT_RET) { |
@@ -483,18 +552,10 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) { | |||
483 | delta = -arg1; | 552 | delta = -arg1; |
484 | switch(GET_OPCODE(i)) { | 553 | switch(GET_OPCODE(i)) { |
485 | case OP_SETTABLE: SETARG_B(i, GETARG_B(i)+arg1); break; | 554 | case OP_SETTABLE: SETARG_B(i, GETARG_B(i)+arg1); break; |
486 | case OP_SETLOCAL: SETARG_B(i, GETARG_B(i)+arg1); break; | ||
487 | default: mode = iU; break; | 555 | default: mode = iU; break; |
488 | } | 556 | } |
489 | break; | 557 | break; |
490 | 558 | ||
491 | case OP_GETLOCAL: | ||
492 | delta = 1; | ||
493 | if (i == CREATE_AB(OP_SETLOCAL, arg1, 1)) | ||
494 | SETARG_B(i, 0); | ||
495 | else mode = iU; | ||
496 | break; | ||
497 | |||
498 | case OP_GETTABLE: | 559 | case OP_GETTABLE: |
499 | delta = -1; | 560 | delta = -1; |
500 | switch(GET_OPCODE(i)) { | 561 | switch(GET_OPCODE(i)) { |
@@ -558,7 +619,10 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) { | |||
558 | } | 619 | } |
559 | break; | 620 | break; |
560 | 621 | ||
561 | case OP_JMPT: case OP_JMPF: case OP_JMPONT: case OP_JMPONF: | 622 | case OP_JMPT: |
623 | case OP_JMPF: | ||
624 | case OP_JMPONT: | ||
625 | case OP_JMPONF: | ||
562 | delta = -1; | 626 | delta = -1; |
563 | arg1 = NO_JUMP; | 627 | arg1 = NO_JUMP; |
564 | switch (GET_OPCODE(i)) { | 628 | switch (GET_OPCODE(i)) { |
@@ -567,8 +631,10 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) { | |||
567 | } | 631 | } |
568 | break; | 632 | break; |
569 | 633 | ||
570 | case OP_GETDOTTED: case OP_GETINDEXED: | 634 | case OP_GETDOTTED: |
571 | case OP_TAILCALL: case OP_ADDI: | 635 | case OP_GETINDEXED: |
636 | case OP_TAILCALL: | ||
637 | case OP_ADDI: | ||
572 | LUA_INTERNALERROR(L, "instruction used only for optimizations"); | 638 | LUA_INTERNALERROR(L, "instruction used only for optimizations"); |
573 | return 0; /* to avoid warnings */ | 639 | return 0; /* to avoid warnings */ |
574 | 640 | ||