** Try to find last instruction before 'lastpc' that modified register 'reg'. */
| 431 | ** Try to find last instruction before 'lastpc' that modified register 'reg'. |
| 432 | */ |
| 433 | static int findsetreg (const Proto *p, int lastpc, int reg) { |
| 434 | int pc; |
| 435 | int setreg = -1; /* keep last instruction that changed 'reg' */ |
| 436 | int jmptarget = 0; /* any code before this address is conditional */ |
| 437 | if (testMMMode(GET_OPCODE(p->code[lastpc]))) |
| 438 | lastpc--; /* previous instruction was not actually executed */ |
| 439 | for (pc = 0; pc < lastpc; pc++) { |
| 440 | Instruction i = p->code[pc]; |
| 441 | OpCode op = GET_OPCODE(i); |
| 442 | int a = GETARG_A(i); |
| 443 | int change; /* true if current instruction changed 'reg' */ |
| 444 | switch (op) { |
| 445 | case OP_LOADNIL: { /* set registers from 'a' to 'a+b' */ |
| 446 | int b = GETARG_B(i); |
| 447 | change = (a <= reg && reg <= a + b); |
| 448 | break; |
| 449 | } |
| 450 | case OP_TFORCALL: { /* affect all regs above its base */ |
| 451 | change = (reg >= a + 2); |
| 452 | break; |
| 453 | } |
| 454 | case OP_CALL: |
| 455 | case OP_TAILCALL: { /* affect all registers above base */ |
| 456 | change = (reg >= a); |
| 457 | break; |
| 458 | } |
| 459 | case OP_JMP: { /* doesn't change registers, but changes 'jmptarget' */ |
| 460 | int b = GETARG_sJ(i); |
| 461 | int dest = pc + 1 + b; |
| 462 | /* jump does not skip 'lastpc' and is larger than current one? */ |
| 463 | if (dest <= lastpc && dest > jmptarget) |
| 464 | jmptarget = dest; /* update 'jmptarget' */ |
| 465 | change = 0; |
| 466 | break; |
| 467 | } |
| 468 | default: /* any instruction that sets A */ |
| 469 | change = (testAMode(op) && reg == a); |
| 470 | break; |
| 471 | } |
| 472 | if (change) |
| 473 | setreg = filterpc(pc, jmptarget); |
| 474 | } |
| 475 | return setreg; |
| 476 | } |
| 477 | |
| 478 | |
| 479 | /* |
no test coverage detected