diff options
-rw-r--r-- | lcode.c | 84 | ||||
-rw-r--r-- | lopcodes.h | 4 | ||||
-rw-r--r-- | lvm.c | 24 |
3 files changed, 61 insertions, 51 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lcode.c,v 2.149 2018/01/09 11:24:12 roberto Exp roberto $ | 2 | ** $Id: lcode.c,v 2.150 2018/01/18 16:24:31 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 | */ |
@@ -60,27 +60,39 @@ static int tonumeral(const expdesc *e, TValue *v) { | |||
60 | 60 | ||
61 | 61 | ||
62 | /* | 62 | /* |
63 | ** Return the previous instruction of the current code. If there | ||
64 | ** may be a jump target between the current instruction and the | ||
65 | ** previous one, return an invalid instruction (to avoid wrong | ||
66 | ** optimizations). | ||
67 | */ | ||
68 | static Instruction *previousinstruction (FuncState *fs) { | ||
69 | static const Instruction invalidinstruction = -1; | ||
70 | if (fs->pc > fs->lasttarget) | ||
71 | return &fs->f->code[fs->pc - 1]; /* previous instruction */ | ||
72 | else | ||
73 | return cast(Instruction*, &invalidinstruction); | ||
74 | } | ||
75 | |||
76 | |||
77 | /* | ||
63 | ** Create a OP_LOADNIL instruction, but try to optimize: if the previous | 78 | ** Create a OP_LOADNIL instruction, but try to optimize: if the previous |
64 | ** instruction is also OP_LOADNIL and ranges are compatible, adjust | 79 | ** instruction is also OP_LOADNIL and ranges are compatible, adjust |
65 | ** range of previous instruction instead of emitting a new one. (For | 80 | ** range of previous instruction instead of emitting a new one. (For |
66 | ** instance, 'local a; local b' will generate a single opcode.) | 81 | ** instance, 'local a; local b' will generate a single opcode.) |
67 | */ | 82 | */ |
68 | void luaK_nil (FuncState *fs, int from, int n) { | 83 | void luaK_nil (FuncState *fs, int from, int n) { |
69 | Instruction *previous; | ||
70 | int l = from + n - 1; /* last register to set nil */ | 84 | int l = from + n - 1; /* last register to set nil */ |
71 | if (fs->pc > fs->lasttarget) { /* no jumps to current position? */ | 85 | Instruction *previous = previousinstruction(fs); |
72 | previous = &fs->f->code[fs->pc-1]; | 86 | if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */ |
73 | if (GET_OPCODE(*previous) == OP_LOADNIL) { /* previous is LOADNIL? */ | 87 | int pfrom = GETARG_A(*previous); /* get previous range */ |
74 | int pfrom = GETARG_A(*previous); /* get previous range */ | 88 | int pl = pfrom + GETARG_B(*previous); |
75 | int pl = pfrom + GETARG_B(*previous); | 89 | if ((pfrom <= from && from <= pl + 1) || |
76 | if ((pfrom <= from && from <= pl + 1) || | 90 | (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ |
77 | (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */ | 91 | if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */ |
78 | if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */ | 92 | if (pl > l) l = pl; /* l = max(l, pl) */ |
79 | if (pl > l) l = pl; /* l = max(l, pl) */ | 93 | SETARG_A(*previous, from); |
80 | SETARG_A(*previous, from); | 94 | SETARG_B(*previous, l - from); |
81 | SETARG_B(*previous, l - from); | 95 | return; |
82 | return; | ||
83 | } | ||
84 | } /* else go through */ | 96 | } /* else go through */ |
85 | } | 97 | } |
86 | luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */ | 98 | luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */ |
@@ -1432,7 +1444,7 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { | |||
1432 | break; | 1444 | break; |
1433 | } | 1445 | } |
1434 | case OPR_CONCAT: { | 1446 | case OPR_CONCAT: { |
1435 | luaK_exp2nextreg(fs, v); /* operand must be on the 'stack' */ | 1447 | luaK_exp2nextreg(fs, v); /* operand must be on the stack */ |
1436 | break; | 1448 | break; |
1437 | } | 1449 | } |
1438 | case OPR_ADD: case OPR_SUB: | 1450 | case OPR_ADD: case OPR_SUB: |
@@ -1463,12 +1475,30 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) { | |||
1463 | } | 1475 | } |
1464 | } | 1476 | } |
1465 | 1477 | ||
1478 | /* | ||
1479 | ** Create code for '(e1 .. e2)'. | ||
1480 | ** For '(e1 .. e2.1 .. e2.2)' (which is '(e1 .. (e2.1 .. e2.2))', | ||
1481 | ** because concatenation is right associative), merge both CONCATs. | ||
1482 | */ | ||
1483 | static void codeconcat (FuncState *fs, expdesc *e1, expdesc *e2, int line) { | ||
1484 | Instruction *ie2 = previousinstruction(fs); | ||
1485 | if (GET_OPCODE(*ie2) == OP_CONCAT) { /* is 'e2' a concatenation? */ | ||
1486 | int n = GETARG_B(*ie2); /* # of elements concatenated in 'e2' */ | ||
1487 | lua_assert(e1->u.info + 1 == GETARG_A(*ie2)); | ||
1488 | freeexp(fs, e2); | ||
1489 | SETARG_A(*ie2, e1->u.info); /* correct first element ('e1') */ | ||
1490 | SETARG_B(*ie2, n + 1); /* will concatenate one more element */ | ||
1491 | } | ||
1492 | else { /* 'e2' is not a concatenation */ | ||
1493 | luaK_codeABC(fs, OP_CONCAT, e1->u.info, 2, 0); /* new concat opcode */ | ||
1494 | freeexp(fs, e2); | ||
1495 | luaK_fixline(fs, line); | ||
1496 | } | ||
1497 | } | ||
1498 | |||
1466 | 1499 | ||
1467 | /* | 1500 | /* |
1468 | ** Finalize code for binary operation, after reading 2nd operand. | 1501 | ** Finalize code for binary operation, after reading 2nd operand. |
1469 | ** For '(a .. b .. c)' (which is '(a .. (b .. c))', because | ||
1470 | ** concatenation is right associative), merge second CONCAT into first | ||
1471 | ** one. | ||
1472 | */ | 1502 | */ |
1473 | void luaK_posfix (FuncState *fs, BinOpr opr, | 1503 | void luaK_posfix (FuncState *fs, BinOpr opr, |
1474 | expdesc *e1, expdesc *e2, int line) { | 1504 | expdesc *e1, expdesc *e2, int line) { |
@@ -1487,19 +1517,9 @@ void luaK_posfix (FuncState *fs, BinOpr opr, | |||
1487 | *e1 = *e2; | 1517 | *e1 = *e2; |
1488 | break; | 1518 | break; |
1489 | } | 1519 | } |
1490 | case OPR_CONCAT: { | 1520 | case OPR_CONCAT: { /* e1 .. e2 */ |
1491 | luaK_exp2val(fs, e2); | 1521 | luaK_exp2nextreg(fs, e2); |
1492 | if (e2->k == VRELOC && | 1522 | codeconcat(fs, e1, e2, line); |
1493 | GET_OPCODE(getinstruction(fs, e2)) == OP_CONCAT) { | ||
1494 | lua_assert(e1->u.info == GETARG_B(getinstruction(fs, e2))-1); | ||
1495 | freeexp(fs, e1); | ||
1496 | SETARG_B(getinstruction(fs, e2), e1->u.info); | ||
1497 | e1->k = VRELOC; e1->u.info = e2->u.info; | ||
1498 | } | ||
1499 | else { | ||
1500 | luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ | ||
1501 | codebinexpval(fs, OP_CONCAT, e1, e2, line); | ||
1502 | } | ||
1503 | break; | 1523 | break; |
1504 | } | 1524 | } |
1505 | case OPR_ADD: case OPR_MUL: { | 1525 | case OPR_ADD: case OPR_MUL: { |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lopcodes.h,v 1.182 2018/01/09 11:21:41 roberto Exp $ | 2 | ** $Id: lopcodes.h,v 1.182 2018/01/09 11:24:12 roberto Exp roberto $ |
3 | ** Opcodes for Lua virtual machine | 3 | ** Opcodes for Lua virtual machine |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -248,7 +248,7 @@ OP_BNOT,/* A B R(A) := ~R(B) */ | |||
248 | OP_NOT,/* A B R(A) := not R(B) */ | 248 | OP_NOT,/* A B R(A) := not R(B) */ |
249 | OP_LEN,/* A B R(A) := length of R(B) */ | 249 | OP_LEN,/* A B R(A) := length of R(B) */ |
250 | 250 | ||
251 | OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */ | 251 | OP_CONCAT,/* A B R(A) := R(A).. ... ..R(A + B - 1) */ |
252 | 252 | ||
253 | OP_CLOSE,/* A close all upvalues >= R(A) */ | 253 | OP_CLOSE,/* A close all upvalues >= R(A) */ |
254 | OP_JMP,/* k sJ pc += sJ (k is used in code generation) */ | 254 | OP_JMP,/* k sJ pc += sJ (k is used in code generation) */ |
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lvm.c,v 2.333 2018/01/10 19:19:27 roberto Exp roberto $ | 2 | ** $Id: lvm.c,v 2.334 2018/01/14 17:27:50 roberto Exp roberto $ |
3 | ** Lua virtual machine | 3 | ** Lua virtual machine |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -717,15 +717,13 @@ void luaV_finishOp (lua_State *L) { | |||
717 | } | 717 | } |
718 | case OP_CONCAT: { | 718 | case OP_CONCAT: { |
719 | StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */ | 719 | StkId top = L->top - 1; /* top when 'luaT_trybinTM' was called */ |
720 | int b = GETARG_B(inst); /* first element to concatenate */ | 720 | int a = GETARG_A(inst); /* first element to concatenate */ |
721 | int total = cast_int(top - 1 - (base + b)); /* yet to concatenate */ | 721 | int total = cast_int(top - 1 - (base + a)); /* yet to concatenate */ |
722 | setobjs2s(L, top - 2, top); /* put TM result in proper position */ | 722 | setobjs2s(L, top - 2, top); /* put TM result in proper position */ |
723 | if (total > 1) { /* are there elements to concat? */ | 723 | if (total > 1) { /* are there elements to concat? */ |
724 | L->top = top - 1; /* top is one after last element (at top-2) */ | 724 | L->top = top - 1; /* top is one after last element (at top-2) */ |
725 | luaV_concat(L, total); /* concat them (may yield again) */ | 725 | luaV_concat(L, total); /* concat them (may yield again) */ |
726 | } | 726 | } |
727 | /* move final result to final position */ | ||
728 | setobjs2s(L, ci->func + 1 + GETARG_A(inst), L->top - 1); | ||
729 | break; | 727 | break; |
730 | } | 728 | } |
731 | case OP_TFORCALL: case OP_CALL: case OP_TAILCALL: | 729 | case OP_TFORCALL: case OP_CALL: case OP_TAILCALL: |
@@ -1376,18 +1374,10 @@ void luaV_execute (lua_State *L, CallInfo *ci) { | |||
1376 | vmbreak; | 1374 | vmbreak; |
1377 | } | 1375 | } |
1378 | vmcase(OP_CONCAT) { | 1376 | vmcase(OP_CONCAT) { |
1379 | int b = GETARG_B(i); | 1377 | int n = GETARG_B(i); /* number of elements to concatenate */ |
1380 | int c = GETARG_C(i); | 1378 | L->top = ra + n; /* mark the end of concat operands */ |
1381 | StkId rb; | 1379 | ProtectNT(luaV_concat(L, n)); |
1382 | L->top = base + c + 1; /* mark the end of concat operands */ | 1380 | checkGC(L, L->top); /* 'luaV_concat' ensures correct top */ |
1383 | ProtectNT(luaV_concat(L, c - b + 1)); | ||
1384 | if (trap) { /* 'luaV_concat' may move the stack */ | ||
1385 | updatebase(ci); | ||
1386 | ra = RA(i); | ||
1387 | } | ||
1388 | rb = base + b; | ||
1389 | setobjs2s(L, ra, rb); | ||
1390 | checkGC(L, (ra >= rb ? ra + 1 : rb)); | ||
1391 | vmbreak; | 1381 | vmbreak; |
1392 | } | 1382 | } |
1393 | vmcase(OP_CLOSE) { | 1383 | vmcase(OP_CLOSE) { |