** Try to find last instruction before 'lastpc' that modified register 'reg'. */
| 468 | ** Try to find last instruction before 'lastpc' that modified register 'reg'. |
| 469 | */ |
| 470 | static int findsetreg (const Proto *p, int lastpc, int reg) { |
| 471 | int pc; |
| 472 | int setreg = -1; /* keep last instruction that changed 'reg' */ |
| 473 | int jmptarget = 0; /* any code before this address is conditional */ |
| 474 | if (testMMMode(GET_OPCODE(p->code[lastpc]))) |
| 475 | lastpc--; /* previous instruction was not actually executed */ |
| 476 | for (pc = 0; pc < lastpc; pc++) { |
| 477 | Instruction i = p->code[pc]; |
| 478 | OpCode op = GET_OPCODE(i); |
| 479 | int a = GETARG_A(i); |
| 480 | int change; /* true if current instruction changed 'reg' */ |
| 481 | switch (op) { |
| 482 | case OP_LOADNIL: { /* set registers from 'a' to 'a+b' */ |
| 483 | int b = GETARG_B(i); |
| 484 | change = (a <= reg && reg <= a + b); |
| 485 | break; |
| 486 | } |
| 487 | case OP_TFORCALL: { /* affect all regs above its base */ |
| 488 | change = (reg >= a + 2); |
| 489 | break; |
| 490 | } |
| 491 | case OP_CALL: |
| 492 | case OP_TAILCALL: { /* affect all registers above base */ |
| 493 | change = (reg >= a); |
| 494 | break; |
| 495 | } |
| 496 | case OP_JMP: { /* doesn't change registers, but changes 'jmptarget' */ |
| 497 | int b = GETARG_sJ(i); |
| 498 | int dest = pc + 1 + b; |
| 499 | /* jump does not skip 'lastpc' and is larger than current one? */ |
| 500 | if (dest <= lastpc && dest > jmptarget) |
| 501 | jmptarget = dest; /* update 'jmptarget' */ |
| 502 | change = 0; |
| 503 | break; |
| 504 | } |
| 505 | default: /* any instruction that sets A */ |
| 506 | change = (testAMode(op) && reg == a); |
| 507 | break; |
| 508 | } |
| 509 | if (change) |
| 510 | setreg = filterpc(pc, jmptarget); |
| 511 | } |
| 512 | return setreg; |
| 513 | } |
| 514 | |
| 515 | |
| 516 | /* |
no test coverage detected