示例#1
0
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);
}
示例#2
0
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);
}