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