void rec_bytecode(TProtoFunc* func, int* inst) { int n_op = num_opcodes(func); int i, newsize; Opcode *opcode_list = luaM_newvector(n_op, Opcode); Byte* p = func->code; //Change const index i = 0; newsize = 0; while (1) { p += INFO(func, p, &opcode_list[i]); Opcode &op = opcode_list[i]; //Change const index, if needed if (op.op_class == PUSHCONSTANT || op.op_class == GETGLOBAL || op.op_class == SETGLOBAL || op.op_class == GETDOTTED || op.op_class == PUSHSELF) if (op.arg != inst[op.arg]) { op.arg = inst[op.arg]; fix_op(&op); } newsize += op.size; ++i; if (op.op == ENDCODE) break; } luaM_free(func->code); Byte *code = (Byte*)luaM_malloc(newsize); func->code = code; //Compile bytecode Byte out[4]; //Out stacksize and arguments number code[0] = (byte)opcode_list[0].arg; if (opcode_list[1].op == VARARGS) code[1] = (byte)opcode_list[1].arg + ZEROVARARG; else code[1] = (byte)opcode_list[1].arg; code += 2; for (i = 2; i < n_op; ++i) { Opcode &op = opcode_list[i]; //Out opcode out[0] = (byte)op.op; //Out args if (op.op == SETLIST || op.op == CLOSURE || op.op == CALLFUNC) { out[1] = (byte)op.arg; out[2] = (byte)op.arg2; } else if (op.size == 2) out[1] = (byte)op.arg; else if (op.size >= 3) WRITE_LE_UINT16(out + 1, op.arg); if (op.op == SETLISTW) out[3] = (byte)op.arg2; memcpy(code, out, op.size); code += op.size; } luaM_free(opcode_list); }
void rec_bytecode(TProtoFunc* func, int* inst) { int n_op = num_opcodes(func); int i, newsize; Opcode *opcode_list = luaM_newvector(n_op, Opcode); Byte* p = func->code; //Load opcodes in a more descriptive structure i = 0; do p += INFO(func, p, &opcode_list[i]); while (opcode_list[i++].op != ENDCODE); luaM_free(func->code); func->code = NULL; //For jump instructions, calculate the number of //instructions to skip/rewind, from the number of //bytes to skip/rewind. The result is improperly //stored in op.arg2, since it's a unused field. for (i = 0; opcode_list[i].op != ENDCODE; ++i) { Opcode &op = opcode_list[i]; int bytesToSkip, instToSkip, bytesToRewind, instToRewind, j; switch (op.op_class) { //Forward jump case ONTJMP: case ONFJMP: case JMP: case IFFJMP: bytesToSkip = op.arg; instToSkip = 0; j = i; while (bytesToSkip > 0) { instToSkip++; bytesToSkip -= opcode_list[++j].size; } assert(bytesToSkip == 0); op.arg2 = instToSkip; break; //Backwards jump case IFTUPJMP: case IFFUPJMP: bytesToRewind = op.arg; instToRewind = 0; j = i; while (bytesToRewind > 0) { bytesToRewind -= opcode_list[j--].size; instToRewind++; } assert(bytesToRewind == 0); op.arg2 = instToRewind; break; } } //Change const index for (i = 0; opcode_list[i].op != ENDCODE; ++i) { Opcode &op = opcode_list[i]; //Change const index, if needed if (op.op_class == PUSHCONSTANT || op.op_class == GETGLOBAL || op.op_class == SETGLOBAL || op.op_class == GETDOTTED || op.op_class == PUSHSELF) if (op.arg != inst[op.arg]) { op.arg = inst[op.arg]; fix_op(&op); } } //Recalculate the number of bytes to jump bool expJmp; do { expJmp = false; for (i = 0; opcode_list[i].op != ENDCODE; ++i) { Opcode &op = opcode_list[i]; int bytesToSkip, instToSkip, bytesToRewind, instToRewind, j; switch (op.op_class) { //Forward jump case ONTJMP: case ONFJMP: case JMP: case IFFJMP: bytesToSkip = 0; instToSkip = op.arg2; j = i; while (instToSkip > 0) { instToSkip--; bytesToSkip += opcode_list[++j].size; } assert(instToSkip == 0); op.arg = bytesToSkip; break; //Backwards jump case IFTUPJMP: case IFFUPJMP: bytesToRewind = 0; instToRewind = op.arg2; j = i; while (instToRewind > 0) { bytesToRewind += opcode_list[j--].size; instToRewind--; } assert(instToRewind == 0); op.arg = bytesToRewind; break; default: continue; } //Expand JMPs to JMPWs, if needed. //It set also the expJmp flag, in order //to make another cycle, since this //action changed again the code size if (op.size == 2 && op.arg > 255) { op.op++; op.size++; expJmp = true; } } } while (expJmp); //Calculate the size of new bytecode and //alloc the space for it i = 0; newsize = 0; do newsize += opcode_list[i].size; while (opcode_list[i++].op != ENDCODE); Byte *code = (Byte*)luaM_malloc(newsize); func->code = code; //Compile bytecode Byte out[4]; //Out stacksize and arguments number code[0] = (byte)opcode_list[0].arg; if (opcode_list[1].op == VARARGS) code[1] = (byte)opcode_list[1].arg + ZEROVARARG; else code[1] = (byte)opcode_list[1].arg; code += 2; for (i = 2; i < n_op; ++i) { Opcode &op = opcode_list[i]; //Out opcode out[0] = (byte)op.op; //Out args if (op.op == SETLIST || op.op == CLOSURE || op.op == CALLFUNC) { out[1] = (byte)op.arg; out[2] = (byte)op.arg2; } else if (op.size == 2) out[1] = (byte)op.arg; else if (op.size >= 3) WRITE_LE_UINT16(out + 1, op.arg); if (op.op == SETLISTW) out[3] = (byte)op.arg2; memcpy(code, out, op.size); code += op.size; } luaM_free(opcode_list); }