diff options
Diffstat (limited to 'lcode.c')
| -rw-r--r-- | lcode.c | 182 |
1 files changed, 96 insertions, 86 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: lcode.c,v 1.12 2000/03/15 20:50:33 roberto Exp roberto $ | 2 | ** $Id: lcode.c,v 1.13 2000/03/16 18:03:09 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 | */ |
| @@ -22,130 +22,147 @@ void luaK_error (LexState *ls, const char *msg) { | |||
| 22 | } | 22 | } |
| 23 | 23 | ||
| 24 | 24 | ||
| 25 | int luaK_code (FuncState *fs, Instruction i, int delta) { | ||
| 26 | luaK_deltastack(fs, delta); | ||
| 27 | luaM_growvector(fs->L, fs->f->code, fs->pc, 1, Instruction, codeEM, MAX_INT); | ||
| 28 | fs->f->code[fs->pc] = i; | ||
| 29 | return fs->pc++; | ||
| 30 | } | ||
| 31 | |||
| 32 | int luaK_0(FuncState *fs, OpCode o, int d) { | ||
| 33 | return luaK_code(fs, CREATE_0(o), d); | ||
| 34 | } | ||
| 35 | |||
| 36 | int luaK_U(FuncState *fs, OpCode o, int u, int d) { | ||
| 37 | return luaK_code(fs, CREATE_U(o,u), d); | ||
| 38 | } | ||
| 39 | |||
| 40 | int luaK_S(FuncState *fs, OpCode o, int s, int d) { | ||
| 41 | return luaK_code(fs, CREATE_S(o,s), d); | ||
| 42 | } | ||
| 43 | |||
| 44 | int luaK_AB(FuncState *fs, OpCode o, int a, int b, int d) { | ||
| 45 | return luaK_code(fs, CREATE_AB(o,a,b), d); | ||
| 46 | } | ||
| 47 | |||
| 48 | |||
| 25 | /* | 49 | /* |
| 26 | ** Returns the address of the previous instruction, for optimizations. | 50 | ** Returns the the previous instruction, for optimizations. |
| 27 | ** If there is a jump target between this and the current instruction, | 51 | ** If there is a jump target between this and the current instruction, |
| 28 | ** returns the address of a dummy instruction to avoid wrong optimizations. | 52 | ** returns a dummy instruction to avoid wrong optimizations. |
| 29 | */ | 53 | */ |
| 30 | static Instruction *previous_instruction (FuncState *fs) { | 54 | static Instruction previous_instruction (FuncState *fs) { |
| 31 | if (fs->pc > fs->lasttarget) /* no jumps to current position? */ | 55 | if (fs->pc > fs->lasttarget) /* no jumps to current position? */ |
| 32 | return &fs->f->code[fs->pc-1]; /* returns previous instruction */ | 56 | return fs->f->code[fs->pc-1]; /* returns previous instruction */ |
| 33 | else { | 57 | else |
| 34 | static Instruction dummy = CREATE_0(OP_END); | 58 | return CREATE_0(OP_END); /* no optimizations after an `END' */ |
| 35 | return &dummy; /* no optimizations after an `END' */ | ||
| 36 | } | ||
| 37 | } | 59 | } |
| 38 | 60 | ||
| 39 | 61 | ||
| 40 | static int luaK_primitivecode (FuncState *fs, Instruction i) { | 62 | static Instruction prepare (FuncState *fs, Instruction i, int delta) { |
| 41 | luaM_growvector(fs->L, fs->f->code, fs->pc, 1, Instruction, codeEM, MAX_INT); | 63 | Instruction previous = previous_instruction(fs); |
| 42 | fs->f->code[fs->pc] = i; | 64 | luaK_code(fs, i, delta); |
| 43 | return fs->pc++; | 65 | return previous; |
| 66 | } | ||
| 67 | |||
| 68 | |||
| 69 | static void setprevious (FuncState *fs, Instruction i) { | ||
| 70 | fs->pc--; /* remove last instruction */ | ||
| 71 | fs->f->code[fs->pc-1] = i; /* change previous instruction */ | ||
| 44 | } | 72 | } |
| 45 | 73 | ||
| 46 | 74 | ||
| 47 | static void luaK_minus (FuncState *fs) { | 75 | static void luaK_minus (FuncState *fs) { |
| 48 | Instruction *previous = previous_instruction(fs); | 76 | Instruction previous = prepare(fs, CREATE_0(OP_MINUS), 0); |
| 49 | switch(GET_OPCODE(*previous)) { | 77 | switch(GET_OPCODE(previous)) { |
| 50 | case OP_PUSHINT: SETARG_S(*previous, -GETARG_S(*previous)); return; | 78 | case OP_PUSHINT: SETARG_S(previous, -GETARG_S(previous)); break; |
| 51 | case OP_PUSHNUM: SET_OPCODE(*previous, OP_PUSHNEGNUM); return; | 79 | case OP_PUSHNUM: SET_OPCODE(previous, OP_PUSHNEGNUM); break; |
| 52 | case OP_PUSHNEGNUM: SET_OPCODE(*previous, OP_PUSHNUM); return; | 80 | case OP_PUSHNEGNUM: SET_OPCODE(previous, OP_PUSHNUM); break; |
| 53 | default: luaK_primitivecode(fs, CREATE_0(OP_MINUS)); | 81 | default: return; |
| 54 | } | 82 | } |
| 83 | setprevious(fs, previous); | ||
| 55 | } | 84 | } |
| 56 | 85 | ||
| 57 | 86 | ||
| 58 | static void luaK_gettable (FuncState *fs) { | 87 | static void luaK_gettable (FuncState *fs) { |
| 59 | Instruction *previous = previous_instruction(fs); | 88 | Instruction previous = prepare(fs, CREATE_0(OP_GETTABLE), -1); |
| 60 | luaK_deltastack(fs, -1); | 89 | switch(GET_OPCODE(previous)) { |
| 61 | switch(GET_OPCODE(*previous)) { | 90 | case OP_PUSHSTRING: SET_OPCODE(previous, OP_GETDOTTED); break; |
| 62 | case OP_PUSHSTRING: SET_OPCODE(*previous, OP_GETDOTTED); break; | 91 | default: return; |
| 63 | default: luaK_primitivecode(fs, CREATE_0(OP_GETTABLE)); | ||
| 64 | } | 92 | } |
| 93 | setprevious(fs, previous); | ||
| 65 | } | 94 | } |
| 66 | 95 | ||
| 67 | 96 | ||
| 68 | static void luaK_add (FuncState *fs) { | 97 | static void luaK_add (FuncState *fs) { |
| 69 | Instruction *previous = previous_instruction(fs); | 98 | Instruction previous = prepare(fs, CREATE_0(OP_ADD), -1); |
| 70 | luaK_deltastack(fs, -1); | 99 | switch(GET_OPCODE(previous)) { |
| 71 | switch(GET_OPCODE(*previous)) { | 100 | case OP_PUSHINT: SET_OPCODE(previous, OP_ADDI); break; |
| 72 | case OP_PUSHINT: SET_OPCODE(*previous, OP_ADDI); break; | 101 | default: return; |
| 73 | default: luaK_primitivecode(fs, CREATE_0(OP_ADD)); | ||
| 74 | } | 102 | } |
| 103 | setprevious(fs, previous); | ||
| 75 | } | 104 | } |
| 76 | 105 | ||
| 77 | 106 | ||
| 78 | static void luaK_sub (FuncState *fs) { | 107 | static void luaK_sub (FuncState *fs) { |
| 79 | Instruction *previous = previous_instruction(fs); | 108 | Instruction previous = prepare(fs, CREATE_0(OP_SUB), -1); |
| 80 | luaK_deltastack(fs, -1); | 109 | switch(GET_OPCODE(previous)) { |
| 81 | switch(GET_OPCODE(*previous)) { | ||
| 82 | case OP_PUSHINT: | 110 | case OP_PUSHINT: |
| 83 | SET_OPCODE(*previous, OP_ADDI); | 111 | SET_OPCODE(previous, OP_ADDI); |
| 84 | SETARG_S(*previous, -GETARG_S(*previous)); | 112 | SETARG_S(previous, -GETARG_S(previous)); |
| 85 | break; | 113 | break; |
| 86 | default: luaK_primitivecode(fs, CREATE_0(OP_SUB)); | 114 | default: return; |
| 87 | } | 115 | } |
| 116 | setprevious(fs, previous); | ||
| 88 | } | 117 | } |
| 89 | 118 | ||
| 90 | 119 | ||
| 91 | static void luaK_conc (FuncState *fs) { | 120 | static void luaK_conc (FuncState *fs) { |
| 92 | Instruction *previous = previous_instruction(fs); | 121 | Instruction previous = prepare(fs, CREATE_U(OP_CONC, 2), -1); |
| 93 | luaK_deltastack(fs, -1); | 122 | switch(GET_OPCODE(previous)) { |
| 94 | switch(GET_OPCODE(*previous)) { | 123 | case OP_CONC: SETARG_U(previous, GETARG_U(previous)+1); break; |
| 95 | case OP_CONC: SETARG_U(*previous, GETARG_U(*previous)+1); break; | 124 | default: return; |
| 96 | default: luaK_primitivecode(fs, CREATE_U(OP_CONC, 2)); | ||
| 97 | } | 125 | } |
| 126 | setprevious(fs, previous); | ||
| 98 | } | 127 | } |
| 99 | 128 | ||
| 100 | 129 | ||
| 101 | static void luaK_eq (FuncState *fs) { | 130 | static void luaK_eq (FuncState *fs) { |
| 102 | Instruction *previous = previous_instruction(fs); | 131 | Instruction previous = prepare(fs, CREATE_S(OP_IFEQJMP, 0), -2); |
| 103 | if (*previous == CREATE_U(OP_PUSHNIL, 1)) { | 132 | if (previous == CREATE_U(OP_PUSHNIL, 1)) { |
| 104 | *previous = CREATE_0(OP_NOT); | 133 | setprevious(fs, CREATE_0(OP_NOT)); |
| 105 | luaK_deltastack(fs, -1); /* undo effect of PUSHNIL */ | 134 | luaK_deltastack(fs, 1); /* undo delta from `prepare' */ |
| 106 | } | 135 | } |
| 107 | else | ||
| 108 | luaK_S(fs, OP_IFEQJMP, 0, -2); | ||
| 109 | } | 136 | } |
| 110 | 137 | ||
| 111 | 138 | ||
| 112 | static void luaK_neq (FuncState *fs) { | 139 | static void luaK_neq (FuncState *fs) { |
| 113 | Instruction *previous = previous_instruction(fs); | 140 | Instruction previous = prepare(fs, CREATE_S(OP_IFNEQJMP, 0), -2); |
| 114 | if (*previous == CREATE_U(OP_PUSHNIL, 1)) { | 141 | if (previous == CREATE_U(OP_PUSHNIL, 1)) { |
| 115 | fs->pc--; /* remove PUSHNIL */ | 142 | fs->pc -= 2; /* remove PUSHNIL and IFNEQJMP */ |
| 116 | luaK_deltastack(fs, -1); /* undo effect of PUSHNIL */ | 143 | luaK_deltastack(fs, 1); /* undo delta from `prepare' */ |
| 117 | luaK_getlabel(fs); /* previous instruction could be a (closed) call */ | ||
| 118 | } | 144 | } |
| 119 | else | ||
| 120 | luaK_S(fs, OP_IFNEQJMP, 0, -2); | ||
| 121 | } | 145 | } |
| 122 | 146 | ||
| 123 | 147 | ||
| 124 | void luaK_retcode (FuncState *fs, int nlocals, int nexps) { | 148 | void luaK_retcode (FuncState *fs, int nlocals, int nexps) { |
| 125 | Instruction *previous = previous_instruction(fs); | 149 | Instruction previous = prepare(fs, CREATE_U(OP_RETURN, nlocals), 0); |
| 126 | if (nexps > 0 && GET_OPCODE(*previous) == OP_CALL) { | 150 | if (nexps > 0 && GET_OPCODE(previous) == OP_CALL) { |
| 127 | LUA_ASSERT(fs->L, GETARG_B(*previous) == MULT_RET, "call should be open"); | 151 | LUA_ASSERT(fs->L, GETARG_B(previous) == MULT_RET, "call should be open"); |
| 128 | SET_OPCODE(*previous, OP_TAILCALL); | 152 | SET_OPCODE(previous, OP_TAILCALL); |
| 129 | SETARG_B(*previous, nlocals); | 153 | SETARG_B(previous, nlocals); |
| 154 | setprevious(fs, previous); | ||
| 130 | } | 155 | } |
| 131 | else | ||
| 132 | luaK_primitivecode(fs, CREATE_U(OP_RETURN, nlocals)); | ||
| 133 | } | 156 | } |
| 134 | 157 | ||
| 135 | 158 | ||
| 136 | static void luaK_pushnil (FuncState *fs, int n) { | 159 | static void luaK_pushnil (FuncState *fs, int n) { |
| 137 | Instruction *previous = previous_instruction(fs); | 160 | Instruction previous = prepare(fs, CREATE_U(OP_PUSHNIL, n), n); |
| 138 | luaK_deltastack(fs, n); | 161 | switch(GET_OPCODE(previous)) { |
| 139 | switch(GET_OPCODE(*previous)) { | 162 | case OP_PUSHNIL: SETARG_U(previous, GETARG_U(previous)+n); break; |
| 140 | case OP_PUSHNIL: SETARG_U(*previous, GETARG_U(*previous)+n); break; | 163 | default: return; |
| 141 | default: luaK_primitivecode(fs, CREATE_U(OP_PUSHNIL, n)); | ||
| 142 | } | 164 | } |
| 143 | } | 165 | setprevious(fs, previous); |
| 144 | |||
| 145 | |||
| 146 | int luaK_code (FuncState *fs, Instruction i, int delta) { | ||
| 147 | luaK_deltastack(fs, delta); | ||
| 148 | return luaK_primitivecode(fs, i); | ||
| 149 | } | 166 | } |
| 150 | 167 | ||
| 151 | 168 | ||
| @@ -232,21 +249,17 @@ void luaK_adjuststack (FuncState *fs, int n) { | |||
| 232 | 249 | ||
| 233 | 250 | ||
| 234 | int luaK_lastisopen (FuncState *fs) { | 251 | int luaK_lastisopen (FuncState *fs) { |
| 235 | /* check whether last instruction is an (open) function call */ | 252 | /* check whether last instruction is an open function call */ |
| 236 | Instruction *i = previous_instruction(fs); | 253 | Instruction i = previous_instruction(fs); |
| 237 | if (GET_OPCODE(*i) == OP_CALL) { | 254 | if (GET_OPCODE(i) == OP_CALL && GETARG_B(i) == MULT_RET) |
| 238 | LUA_ASSERT(fs->L, GETARG_B(*i) == MULT_RET, "call should be open"); | ||
| 239 | return 1; | 255 | return 1; |
| 240 | } | ||
| 241 | else return 0; | 256 | else return 0; |
| 242 | } | 257 | } |
| 243 | 258 | ||
| 244 | 259 | ||
| 245 | void luaK_setcallreturns (FuncState *fs, int nresults) { | 260 | void luaK_setcallreturns (FuncState *fs, int nresults) { |
| 246 | Instruction *i = previous_instruction(fs); | 261 | if (luaK_lastisopen(fs)) { /* expression is an open function call? */ |
| 247 | if (GET_OPCODE(*i) == OP_CALL) { /* expression is a function call? */ | 262 | SETARG_B(fs->f->code[fs->pc-1], nresults); /* set number of results */ |
| 248 | LUA_ASSERT(fs->L, GETARG_B(*i) == MULT_RET, "call should be open"); | ||
| 249 | SETARG_B(*i, nresults); /* set nresults */ | ||
| 250 | luaK_deltastack(fs, nresults); /* push results */ | 263 | luaK_deltastack(fs, nresults); /* push results */ |
| 251 | } | 264 | } |
| 252 | } | 265 | } |
| @@ -323,12 +336,9 @@ static OpCode invertjump (OpCode op) { | |||
| 323 | 336 | ||
| 324 | 337 | ||
| 325 | static void luaK_jump (FuncState *fs, OpCode jump) { | 338 | static void luaK_jump (FuncState *fs, OpCode jump) { |
| 326 | Instruction *previous = previous_instruction(fs); | 339 | Instruction previous = prepare(fs, CREATE_S(jump, 0), -1); |
| 327 | luaK_deltastack(fs, -1); | 340 | if (previous == CREATE_0(OP_NOT)) |
| 328 | if (*previous == CREATE_0(OP_NOT)) | 341 | setprevious(fs, CREATE_S(invertjump(jump), 0)); |
| 329 | *previous = CREATE_S(invertjump(jump), 0); | ||
| 330 | else | ||
| 331 | luaK_primitivecode(fs, CREATE_S(jump, 0)); | ||
| 332 | } | 342 | } |
| 333 | 343 | ||
| 334 | 344 | ||
