diff options
Diffstat (limited to 'lcode.c')
-rw-r--r-- | lcode.c | 258 |
1 files changed, 119 insertions, 139 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lcode.c,v 1.29 2000/05/08 19:32:53 roberto Exp roberto $ | 2 | ** $Id: lcode.c,v 1.30 2000/05/15 19:48:04 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 | */ |
@@ -37,7 +37,7 @@ static Instruction previous_instruction (FuncState *fs) { | |||
37 | 37 | ||
38 | 38 | ||
39 | int luaK_jump (FuncState *fs) { | 39 | int luaK_jump (FuncState *fs) { |
40 | int j = luaK_code0(fs, OP_JMP); | 40 | int j = luaK_code1(fs, OP_JMP, NO_JUMP); |
41 | if (j == fs->lasttarget) { /* possible jumps to this jump? */ | 41 | if (j == fs->lasttarget) { /* possible jumps to this jump? */ |
42 | luaK_concat(fs, &j, fs->jlt); /* keep them on hold */ | 42 | luaK_concat(fs, &j, fs->jlt); /* keep them on hold */ |
43 | fs->jlt = NO_JUMP; | 43 | fs->jlt = NO_JUMP; |
@@ -279,7 +279,7 @@ static void luaK_testgo (FuncState *fs, expdesc *v, int invert, OpCode jump) { | |||
279 | SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous))); | 279 | SET_OPCODE(*previous, invertjump(GET_OPCODE(*previous))); |
280 | } | 280 | } |
281 | else | 281 | else |
282 | luaK_code0(fs, jump); | 282 | luaK_code1(fs, jump, NO_JUMP); |
283 | luaK_concat(fs, exitlist, fs->pc-1); /* insert last jump in `exitlist' */ | 283 | luaK_concat(fs, exitlist, fs->pc-1); /* insert last jump in `exitlist' */ |
284 | luaK_patchlist(fs, *golist, luaK_getlabel(fs)); | 284 | luaK_patchlist(fs, *golist, luaK_getlabel(fs)); |
285 | *golist = NO_JUMP; | 285 | *golist = NO_JUMP; |
@@ -324,10 +324,11 @@ void luaK_tostack (LexState *ls, expdesc *v, int onlyone) { | |||
324 | if (ISJUMP(previous)) | 324 | if (ISJUMP(previous)) |
325 | luaK_concat(fs, &v->u.l.t, fs->pc-1); /* put `previous' in t. list */ | 325 | luaK_concat(fs, &v->u.l.t, fs->pc-1); /* put `previous' in t. list */ |
326 | else { | 326 | else { |
327 | j = code_label(fs, OP_JMP, 0); /* to jump over both pushes */ | 327 | j = code_label(fs, OP_JMP, NO_JUMP); /* to jump over both pushes */ |
328 | luaK_deltastack(fs, -1); /* next PUSHes may be skipped */ | 328 | luaK_deltastack(fs, -1); /* next PUSHes may be skipped */ |
329 | } | 329 | } |
330 | p_nil = code_label(fs, OP_PUSHNILJMP, 0); | 330 | p_nil = code_label(fs, OP_PUSHNILJMP, 0); |
331 | luaK_deltastack(fs, -1); /* next PUSH is skipped */ | ||
331 | p_1 = code_label(fs, OP_PUSHINT, 1); | 332 | p_1 = code_label(fs, OP_PUSHINT, 1); |
332 | luaK_patchlist(fs, j, luaK_getlabel(fs)); | 333 | luaK_patchlist(fs, j, luaK_getlabel(fs)); |
333 | } | 334 | } |
@@ -394,12 +395,12 @@ void luaK_posfix (LexState *ls, int op, expdesc *v1, expdesc *v2) { | |||
394 | case '/': luaK_code0(fs, OP_DIV); break; | 395 | case '/': luaK_code0(fs, OP_DIV); break; |
395 | case '^': luaK_code0(fs, OP_POW); break; | 396 | case '^': luaK_code0(fs, OP_POW); break; |
396 | case TK_CONCAT: luaK_code1(fs, OP_CONCAT, 2); break; | 397 | case TK_CONCAT: luaK_code1(fs, OP_CONCAT, 2); break; |
397 | case TK_EQ: luaK_code0(fs, OP_JMPEQ); break; | 398 | case TK_EQ: luaK_code1(fs, OP_JMPEQ, NO_JUMP); break; |
398 | case TK_NE: luaK_code0(fs, OP_JMPNE); break; | 399 | case TK_NE: luaK_code1(fs, OP_JMPNE, NO_JUMP); break; |
399 | case '>': luaK_code0(fs, OP_JMPGT); break; | 400 | case '>': luaK_code1(fs, OP_JMPGT, NO_JUMP); break; |
400 | case '<': luaK_code0(fs, OP_JMPLT); break; | 401 | case '<': luaK_code1(fs, OP_JMPLT, NO_JUMP); break; |
401 | case TK_GE: luaK_code0(fs, OP_JMPGE); break; | 402 | case TK_GE: luaK_code1(fs, OP_JMPGE, NO_JUMP); break; |
402 | case TK_LE: luaK_code0(fs, OP_JMPLE); break; | 403 | case TK_LE: luaK_code1(fs, OP_JMPLE, NO_JUMP); break; |
403 | } | 404 | } |
404 | } | 405 | } |
405 | } | 406 | } |
@@ -415,196 +416,120 @@ int luaK_code1 (FuncState *fs, OpCode o, int arg1) { | |||
415 | } | 416 | } |
416 | 417 | ||
417 | 418 | ||
419 | #define VD 100 /* flag for variable delta */ | ||
420 | |||
418 | 421 | ||
419 | int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) { | 422 | int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) { |
420 | Instruction i = previous_instruction(fs); | 423 | Instruction i = previous_instruction(fs); |
421 | int delta = 0; | 424 | int delta = luaK_opproperties[o].delta; |
422 | enum {iO, iU, iS, iAB, iP} mode; /* instruction format (or iP to optimize) */ | 425 | int optm = 0; /* 1 when there is an optimization */ |
423 | mode = iP; | ||
424 | |||
425 | switch (o) { | 426 | switch (o) { |
426 | 427 | ||
427 | case OP_CLOSURE: | 428 | case OP_CLOSURE: |
428 | delta = -arg2+1; | 429 | delta = -arg2+1; |
429 | mode = iAB; | ||
430 | break; | ||
431 | |||
432 | case OP_SETLINE: | ||
433 | mode = iU; | ||
434 | break; | ||
435 | |||
436 | case OP_CALL: | ||
437 | mode = iAB; | ||
438 | break; | ||
439 | |||
440 | case OP_PUSHINT: | ||
441 | delta = 1; | ||
442 | mode = iS; | ||
443 | break; | 430 | break; |
444 | 431 | ||
445 | case OP_SETTABLE: | 432 | case OP_SETTABLE: |
446 | delta = -arg2; | ||
447 | mode = iAB; | ||
448 | break; | ||
449 | |||
450 | case OP_SETLIST: | 433 | case OP_SETLIST: |
451 | delta = -(arg2+1); | 434 | delta = -arg2; |
452 | mode = iAB; | ||
453 | break; | 435 | break; |
454 | 436 | ||
455 | case OP_SETMAP: | 437 | case OP_SETMAP: |
456 | delta = -2*(arg1+1); | 438 | delta = -2*(arg1+1); |
457 | mode = iU; | ||
458 | break; | ||
459 | |||
460 | case OP_FORLOOP: | ||
461 | delta = -3; | ||
462 | arg1 = NO_JUMP; | ||
463 | mode = iS; | ||
464 | break; | ||
465 | |||
466 | case OP_SETLOCAL: | ||
467 | case OP_SETGLOBAL: | ||
468 | delta = -1; | ||
469 | mode = iU; | ||
470 | break; | ||
471 | |||
472 | case OP_FORPREP: | ||
473 | case OP_JMP: | ||
474 | arg1 = NO_JUMP; | ||
475 | mode = iS; | ||
476 | break; | ||
477 | |||
478 | case OP_LFORPREP: | ||
479 | delta = 3; | ||
480 | arg1 = NO_JUMP; | ||
481 | mode = iS; | ||
482 | break; | ||
483 | |||
484 | case OP_LFORLOOP: | ||
485 | delta = -4; | ||
486 | arg1 = NO_JUMP; | ||
487 | mode = iS; | ||
488 | break; | ||
489 | |||
490 | case OP_END: | ||
491 | case OP_PUSHNILJMP: | ||
492 | case OP_NOT: | ||
493 | mode = iO; | ||
494 | break; | ||
495 | |||
496 | case OP_PUSHSTRING: | ||
497 | case OP_PUSHNUM: | ||
498 | case OP_PUSHNEGNUM: | ||
499 | case OP_PUSHUPVALUE: | ||
500 | case OP_GETLOCAL: | ||
501 | case OP_GETGLOBAL: | ||
502 | case OP_PUSHSELF: | ||
503 | case OP_CREATETABLE: | ||
504 | delta = 1; | ||
505 | mode = iU; | ||
506 | break; | ||
507 | |||
508 | case OP_JMPLT: | ||
509 | case OP_JMPLE: | ||
510 | case OP_JMPGT: | ||
511 | case OP_JMPGE: | ||
512 | delta = -2; | ||
513 | arg1 = NO_JUMP; | ||
514 | mode = iS; | ||
515 | break; | ||
516 | |||
517 | case OP_MULT: | ||
518 | case OP_DIV: | ||
519 | case OP_POW: | ||
520 | delta = -1; | ||
521 | mode = iO; | ||
522 | break; | 439 | break; |
523 | 440 | ||
524 | case OP_RETURN: | 441 | case OP_RETURN: |
525 | if (GET_OPCODE(i) == OP_CALL && GETARG_B(i) == MULT_RET) { | 442 | if (GET_OPCODE(i) == OP_CALL && GETARG_B(i) == MULT_RET) { |
526 | SET_OPCODE(i, OP_TAILCALL); | 443 | SET_OPCODE(i, OP_TAILCALL); |
527 | SETARG_B(i, arg1); | 444 | SETARG_B(i, arg1); |
445 | optm = 1; | ||
528 | } | 446 | } |
529 | else mode = iU; | ||
530 | break; | 447 | break; |
531 | 448 | ||
532 | case OP_PUSHNIL: | 449 | case OP_PUSHNIL: |
533 | delta = arg1; | 450 | delta = arg1; |
534 | switch(GET_OPCODE(i)) { | 451 | switch(GET_OPCODE(i)) { |
535 | case OP_PUSHNIL: SETARG_U(i, GETARG_U(i)+arg1); break; | 452 | case OP_PUSHNIL: SETARG_U(i, GETARG_U(i)+arg1); optm = 1; break; |
536 | default: mode = iU; break; | 453 | default: break; |
537 | } | 454 | } |
538 | break; | 455 | break; |
539 | 456 | ||
540 | case OP_POP: | 457 | case OP_POP: |
541 | delta = -arg1; | 458 | delta = -arg1; |
542 | switch(GET_OPCODE(i)) { | 459 | switch(GET_OPCODE(i)) { |
543 | case OP_SETTABLE: SETARG_B(i, GETARG_B(i)+arg1); break; | 460 | case OP_SETTABLE: SETARG_B(i, GETARG_B(i)+arg1); optm = 1; break; |
544 | default: mode = iU; break; | 461 | default: break; |
545 | } | 462 | } |
546 | break; | 463 | break; |
547 | 464 | ||
548 | case OP_GETTABLE: | 465 | case OP_GETTABLE: |
549 | delta = -1; | ||
550 | switch(GET_OPCODE(i)) { | 466 | switch(GET_OPCODE(i)) { |
551 | case OP_PUSHSTRING: SET_OPCODE(i, OP_GETDOTTED); break; /* `t.x' */ | 467 | case OP_PUSHSTRING: /* `t.x' */ |
552 | case OP_GETLOCAL: SET_OPCODE(i, OP_GETINDEXED); break; /* `t[i]' */ | 468 | SET_OPCODE(i, OP_GETDOTTED); |
553 | default: mode = iO; break; | 469 | optm = 1; |
470 | break; | ||
471 | case OP_GETLOCAL: /* `t[i]' */ | ||
472 | SET_OPCODE(i, OP_GETINDEXED); | ||
473 | optm = 1; | ||
474 | break; | ||
475 | default: break; | ||
554 | } | 476 | } |
555 | break; | 477 | break; |
556 | 478 | ||
557 | case OP_ADD: | 479 | case OP_ADD: |
558 | delta = -1; | ||
559 | switch(GET_OPCODE(i)) { | 480 | switch(GET_OPCODE(i)) { |
560 | case OP_PUSHINT: SET_OPCODE(i, OP_ADDI); break; /* `a+k' */ | 481 | case OP_PUSHINT: SET_OPCODE(i, OP_ADDI); optm = 1; break; /* `a+k' */ |
561 | default: mode = iO; break; | 482 | default: break; |
562 | } | 483 | } |
563 | break; | 484 | break; |
564 | 485 | ||
565 | case OP_SUB: | 486 | case OP_SUB: |
566 | delta = -1; | ||
567 | switch(GET_OPCODE(i)) { | 487 | switch(GET_OPCODE(i)) { |
568 | case OP_PUSHINT: i = CREATE_S(OP_ADDI, -GETARG_S(i)); break; /* `a-k' */ | 488 | case OP_PUSHINT: /* `a-k' */ |
569 | default: mode = iO; break; | 489 | i = CREATE_S(OP_ADDI, -GETARG_S(i)); |
490 | optm = 1; | ||
491 | break; | ||
492 | default: break; | ||
570 | } | 493 | } |
571 | break; | 494 | break; |
572 | 495 | ||
573 | case OP_CONCAT: | 496 | case OP_CONCAT: |
574 | delta = -arg1+1; | 497 | delta = -arg1+1; |
575 | switch(GET_OPCODE(i)) { | 498 | switch(GET_OPCODE(i)) { |
576 | case OP_CONCAT: SETARG_U(i, GETARG_U(i)+1); break; /* `a..b..c' */ | 499 | case OP_CONCAT: /* `a..b..c' */ |
577 | default: mode = iU; break; | 500 | SETARG_U(i, GETARG_U(i)+1); |
501 | optm = 1; | ||
502 | break; | ||
503 | default: break; | ||
578 | } | 504 | } |
579 | break; | 505 | break; |
580 | 506 | ||
581 | case OP_MINUS: | 507 | case OP_MINUS: |
582 | switch(GET_OPCODE(i)) { | 508 | switch(GET_OPCODE(i)) { |
583 | case OP_PUSHINT: SETARG_S(i, -GETARG_S(i)); break; /* `-k' */ | 509 | case OP_PUSHINT: /* `-k' */ |
584 | case OP_PUSHNUM: SET_OPCODE(i, OP_PUSHNEGNUM); break; /* `-k' */ | 510 | SETARG_S(i, -GETARG_S(i)); |
585 | default: mode = iO; break; | 511 | optm = 1; |
512 | break; | ||
513 | case OP_PUSHNUM: /* `-k' */ | ||
514 | SET_OPCODE(i, OP_PUSHNEGNUM); | ||
515 | optm = 1; | ||
516 | break; | ||
517 | default: break; | ||
586 | } | 518 | } |
587 | break; | 519 | break; |
588 | 520 | ||
589 | case OP_JMPNE: | 521 | case OP_JMPNE: |
590 | delta = -2; | 522 | if (i == CREATE_U(OP_PUSHNIL, 1)) { /* `a~=nil' */ |
591 | if (i == CREATE_U(OP_PUSHNIL, 1)) /* `a~=nil' */ | ||
592 | i = CREATE_S(OP_JMPT, NO_JUMP); | 523 | i = CREATE_S(OP_JMPT, NO_JUMP); |
593 | else { | 524 | optm = 1; |
594 | arg1 = NO_JUMP; | ||
595 | mode = iS; | ||
596 | } | 525 | } |
597 | break; | 526 | break; |
598 | 527 | ||
599 | case OP_JMPEQ: | 528 | case OP_JMPEQ: |
600 | delta = -2; | ||
601 | if (i == CREATE_U(OP_PUSHNIL, 1)) { /* `a==nil' */ | 529 | if (i == CREATE_U(OP_PUSHNIL, 1)) { /* `a==nil' */ |
602 | i = CREATE_0(OP_NOT); | 530 | i = CREATE_0(OP_NOT); |
603 | delta = -1; /* just undo effect of previous PUSHNIL */ | 531 | delta = -1; /* just undo effect of previous PUSHNIL */ |
604 | } | 532 | optm = 1; |
605 | else { | ||
606 | arg1 = NO_JUMP; | ||
607 | mode = iS; | ||
608 | } | 533 | } |
609 | break; | 534 | break; |
610 | 535 | ||
@@ -612,11 +537,9 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) { | |||
612 | case OP_JMPF: | 537 | case OP_JMPF: |
613 | case OP_JMPONT: | 538 | case OP_JMPONT: |
614 | case OP_JMPONF: | 539 | case OP_JMPONF: |
615 | delta = -1; | ||
616 | arg1 = NO_JUMP; | ||
617 | switch (GET_OPCODE(i)) { | 540 | switch (GET_OPCODE(i)) { |
618 | case OP_NOT: i = CREATE_S(invertjump(o), NO_JUMP); break; | 541 | case OP_NOT: i = CREATE_S(invertjump(o), NO_JUMP); optm = 1; break; |
619 | default: mode = iS; break; | 542 | default: break; |
620 | } | 543 | } |
621 | break; | 544 | break; |
622 | 545 | ||
@@ -625,19 +548,23 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) { | |||
625 | case OP_TAILCALL: | 548 | case OP_TAILCALL: |
626 | case OP_ADDI: | 549 | case OP_ADDI: |
627 | LUA_INTERNALERROR(L, "instruction used only for optimizations"); | 550 | LUA_INTERNALERROR(L, "instruction used only for optimizations"); |
628 | return 0; /* to avoid warnings */ | 551 | break; |
552 | |||
553 | default: | ||
554 | LUA_ASSERT(L, delta != VD, "invalid delta"); | ||
555 | break; | ||
629 | 556 | ||
630 | } | 557 | } |
631 | luaK_deltastack(fs, delta); | 558 | luaK_deltastack(fs, delta); |
632 | switch (mode) { /* handle instruction formats */ | 559 | if (optm) { /* optimize: put instruction in place of last one */ |
560 | fs->f->code[fs->pc-1] = i; /* change previous instruction */ | ||
561 | return fs->pc-1; /* do not generate new instruction */ | ||
562 | } | ||
563 | switch ((enum Mode)luaK_opproperties[o].mode) { | ||
633 | case iO: i = CREATE_0(o); break; | 564 | case iO: i = CREATE_0(o); break; |
634 | case iU: i = CREATE_U(o, arg1); break; | 565 | case iU: i = CREATE_U(o, arg1); break; |
635 | case iS: i = CREATE_S(o, arg1); break; | 566 | case iS: i = CREATE_S(o, arg1); break; |
636 | case iAB: i = CREATE_AB(o, arg1, arg2); break; | 567 | case iAB: i = CREATE_AB(o, arg1, arg2); break; |
637 | case iP: { /* optimize: put instruction in place of last one */ | ||
638 | fs->f->code[fs->pc-1] = i; /* change previous instruction */ | ||
639 | return fs->pc-1; | ||
640 | } | ||
641 | } | 568 | } |
642 | /* actually create the new instruction */ | 569 | /* actually create the new instruction */ |
643 | luaM_growvector(fs->L, fs->f->code, fs->pc, 1, Instruction, codeEM, MAX_INT); | 570 | luaM_growvector(fs->L, fs->f->code, fs->pc, 1, Instruction, codeEM, MAX_INT); |
@@ -645,3 +572,56 @@ int luaK_code2 (FuncState *fs, OpCode o, int arg1, int arg2) { | |||
645 | return fs->pc++; | 572 | return fs->pc++; |
646 | } | 573 | } |
647 | 574 | ||
575 | |||
576 | const struct OpProperties luaK_opproperties[OP_SETLINE+1] = { | ||
577 | {iO, 0}, /* OP_END */ | ||
578 | {iU, 0}, /* OP_RETURN */ | ||
579 | {iAB, 0}, /* OP_CALL */ | ||
580 | {iAB, 0}, /* OP_TAILCALL */ | ||
581 | {iU, VD}, /* OP_PUSHNIL */ | ||
582 | {iU, VD}, /* OP_POP */ | ||
583 | {iS, 1}, /* OP_PUSHINT */ | ||
584 | {iU, 1}, /* OP_PUSHSTRING */ | ||
585 | {iU, 1}, /* OP_PUSHNUM */ | ||
586 | {iU, 1}, /* OP_PUSHNEGNUM */ | ||
587 | {iU, 1}, /* OP_PUSHUPVALUE */ | ||
588 | {iU, 1}, /* OP_GETLOCAL */ | ||
589 | {iU, 1}, /* OP_GETGLOBAL */ | ||
590 | {iO, -1}, /* OP_GETTABLE */ | ||
591 | {iU, 0}, /* OP_GETDOTTED */ | ||
592 | {iU, 0}, /* OP_GETINDEXED */ | ||
593 | {iU, 1}, /* OP_PUSHSELF */ | ||
594 | {iU, 1}, /* OP_CREATETABLE */ | ||
595 | {iU, -1}, /* OP_SETLOCAL */ | ||
596 | {iU, -1}, /* OP_SETGLOBAL */ | ||
597 | {iAB, VD}, /* OP_SETTABLE */ | ||
598 | {iAB, VD}, /* OP_SETLIST */ | ||
599 | {iU, VD}, /* OP_SETMAP */ | ||
600 | {iO, -1}, /* OP_ADD */ | ||
601 | {iS, 0}, /* OP_ADDI */ | ||
602 | {iO, -1}, /* OP_SUB */ | ||
603 | {iO, -1}, /* OP_MULT */ | ||
604 | {iO, -1}, /* OP_DIV */ | ||
605 | {iO, -1}, /* OP_POW */ | ||
606 | {iU, VD}, /* OP_CONCAT */ | ||
607 | {iO, 0}, /* OP_MINUS */ | ||
608 | {iO, 0}, /* OP_NOT */ | ||
609 | {iS, -2}, /* OP_JMPNE */ | ||
610 | {iS, -2}, /* OP_JMPEQ */ | ||
611 | {iS, -2}, /* OP_JMPLT */ | ||
612 | {iS, -2}, /* OP_JMPLE */ | ||
613 | {iS, -2}, /* OP_JMPGT */ | ||
614 | {iS, -2}, /* OP_JMPGE */ | ||
615 | {iS, -1}, /* OP_JMPT */ | ||
616 | {iS, -1}, /* OP_JMPF */ | ||
617 | {iS, -1}, /* OP_JMPONT */ | ||
618 | {iS, -1}, /* OP_JMPONF */ | ||
619 | {iS, 0}, /* OP_JMP */ | ||
620 | {iO, 1}, /* OP_PUSHNILJMP */ | ||
621 | {iS, 0}, /* OP_FORPREP */ | ||
622 | {iS, -3}, /* OP_FORLOOP */ | ||
623 | {iS, 3}, /* OP_LFORPREP */ | ||
624 | {iS, -4}, /* OP_LFORLOOP */ | ||
625 | {iAB, VD}, /* OP_CLOSURE */ | ||
626 | {iU, 0} /* OP_SETLINE */ | ||
627 | }; | ||