Alien-LibJIT

 view release on metacpan or  search on metacpan

libjit/jit/jit-dump.c  view on Meta::CPAN

	if((type & JIT_OPCODE_SRC1_MASK) != 0)
	{
		type >>= 4;
	}
	if((type & JIT_OPCODE_SRC2_MASK) != 0)
	{
		type >>= 8;
	}

	/* Dump the value, prefixed appropriately */
	switch(type)
	{
		case JIT_OPCODE_DEST_INT:
		{
			jit_dump_value(stream, func, value, "i");
		}
		break;

		case JIT_OPCODE_DEST_LONG:
		{
			jit_dump_value(stream, func, value, "l");
		}
		break;

		case JIT_OPCODE_DEST_FLOAT32:
		{
			jit_dump_value(stream, func, value, "f");
		}
		break;

		case JIT_OPCODE_DEST_FLOAT64:
		{
			jit_dump_value(stream, func, value, "d");
		}
		break;

		case JIT_OPCODE_DEST_NFLOAT:
		{
			jit_dump_value(stream, func, value, "D");
		}
		break;

		case JIT_OPCODE_DEST_ANY:
		{
			/* Intuit the prefix from the value if the type is "any" */
			jit_dump_value(stream, func, value, 0);
		}
		break;
	}
}

/*@
 * @deftypefun void jit_dump_insn (FILE *@var{stream}, jit_function_t @var{func}, jit_value_t @var{value})
 * Dump the contents of an instruction to a stdio stream.
 * @end deftypefun
@*/
void jit_dump_insn(FILE *stream, jit_function_t func, jit_insn_t insn)
{
	const char *name;
	const char *infix_name;
	int opcode, flags;
	jit_nint reg;

	/* Bail out if we have insufficient information for the dump */
	if(!stream || !func || !insn)
	{
		return;
	}

	/* Get the opcode details */
	opcode = insn->opcode;
	if(opcode < JIT_OP_NOP || opcode >= JIT_OP_NUM_OPCODES)
	{
		fprintf(stream, "unknown opcode %d\n", opcode);
		return;
	}
	name = jit_opcodes[opcode].name;
	flags = jit_opcodes[opcode].flags;
	infix_name = 0;

	/* Dump branch, call, or register information */
	if((flags & JIT_OPCODE_IS_BRANCH) != 0)
	{
		if(opcode == JIT_OP_BR)
		{
			fprintf(stream, "goto .L%ld", (long)(jit_insn_get_label(insn)));
			return;
		}
		if(opcode == JIT_OP_CALL_FINALLY || opcode == JIT_OP_CALL_FILTER)
		{
			fprintf(stream, "%s .L%ld", name, (long)(jit_insn_get_label(insn)));
			return;
		}
		fprintf(stream, "if ");
	}
	else if((flags & JIT_OPCODE_IS_CALL) != 0)
	{
		if(insn->value1)
			fprintf(stream, "%s %s", name, (const char *)(insn->value1));
		else
			fprintf(stream, "%s 0x08%lx", name, (long)(jit_nuint)(insn->dest));
		return;
	}
	else if((flags & JIT_OPCODE_IS_CALL_EXTERNAL) != 0)
	{
		if(insn->value1)
			fprintf(stream, "%s %s (0x%08lx)", name,
					(const char *)(insn->value1),
					(long)(jit_nuint)(insn->dest));
		else
			fprintf(stream, "%s 0x08%lx", name,
					(long)(jit_nuint)(insn->dest));
		return;
	}
	else if((flags & JIT_OPCODE_IS_REG) != 0)
	{
		reg = jit_value_get_nint_constant(jit_insn_get_value2(insn));
		fputs(name, stream);
		putc('(', stream);
		jit_dump_value(stream, func, jit_insn_get_value1(insn), 0);
		fputs(", ", stream);
		fputs(jit_reg_name(reg), stream);
		putc(')', stream);
		return;
	}
	else if((flags & JIT_OPCODE_IS_ADDROF_LABEL) != 0)
	{
		dump_value(stream, func, jit_insn_get_dest(insn), flags & JIT_OPCODE_DEST_MASK);
		fprintf(stream, " = ");
		fprintf(stream, "address_of_label .L%ld",
				(long)(jit_insn_get_label(insn)));
		return;
	}
	else if((flags & JIT_OPCODE_IS_JUMP_TABLE) != 0)
	{
		jit_label_t *labels;
		jit_nint num_labels, label;
		labels = (jit_label_t *)jit_value_get_nint_constant(jit_insn_get_value1(insn));
		num_labels = jit_value_get_nint_constant(jit_insn_get_value2(insn));
		fprintf(stream, "%s ", name);
		dump_value(stream, func, jit_insn_get_dest(insn), flags & JIT_OPCODE_DEST_MASK);
		printf(" : {");
		for(label = 0; label < num_labels; label++)
		{
			printf(" .L%ld", (long) labels[label]);
		}
		printf(" }");
		return;
	}

	/* Output the destination information */
	if((flags & JIT_OPCODE_DEST_MASK) != JIT_OPCODE_DEST_EMPTY &&
	   !jit_insn_dest_is_value(insn))
	{
		dump_value(stream, func, jit_insn_get_dest(insn),
				   flags & JIT_OPCODE_DEST_MASK);
		fprintf(stream, " = ");
	}

	/* Dump the details of the operation */
	switch(flags & JIT_OPCODE_OPER_MASK)
	{
		case JIT_OPCODE_OPER_ADD:			infix_name = " + ";   break;
		case JIT_OPCODE_OPER_SUB:			infix_name = " - ";   break;
		case JIT_OPCODE_OPER_MUL:			infix_name = " * ";   break;
		case JIT_OPCODE_OPER_DIV:			infix_name = " / ";   break;
		case JIT_OPCODE_OPER_REM:			infix_name = " % ";   break;
		case JIT_OPCODE_OPER_NEG:			infix_name = "-";    break;
		case JIT_OPCODE_OPER_AND:			infix_name = " & ";   break;
		case JIT_OPCODE_OPER_OR:			infix_name = " | ";   break;
		case JIT_OPCODE_OPER_XOR:			infix_name = " ^ ";   break;
		case JIT_OPCODE_OPER_NOT:			infix_name = "~";    break;
		case JIT_OPCODE_OPER_EQ:			infix_name = " == ";  break;
		case JIT_OPCODE_OPER_NE:			infix_name = " != ";  break;
		case JIT_OPCODE_OPER_LT:			infix_name = " < ";   break;
		case JIT_OPCODE_OPER_LE:			infix_name = " <= ";  break;
		case JIT_OPCODE_OPER_GT:			infix_name = " > ";   break;
		case JIT_OPCODE_OPER_GE:			infix_name = " >= ";  break;
		case JIT_OPCODE_OPER_SHL:			infix_name = " << ";  break;
		case JIT_OPCODE_OPER_SHR:			infix_name = " >> ";  break;
		case JIT_OPCODE_OPER_SHR_UN:		infix_name = " >>> "; break;
		case JIT_OPCODE_OPER_COPY:			infix_name = "";      break;
		case JIT_OPCODE_OPER_ADDRESS_OF:	infix_name = "&";    break;
	}
	if(infix_name)
	{
		if((flags & JIT_OPCODE_SRC2_MASK) != 0)
		{
			/* Binary operation with a special operator name */
			dump_value(stream, func, jit_insn_get_value1(insn),
				   	   flags & JIT_OPCODE_SRC1_MASK);
			fputs(infix_name, stream);
			dump_value(stream, func, jit_insn_get_value2(insn),
				   	   flags & JIT_OPCODE_SRC2_MASK);
		}
		else
		{
			/* Unary operation with a special operator name */
			fputs(infix_name, stream);
			dump_value(stream, func, jit_insn_get_value1(insn),
				   	   flags & JIT_OPCODE_SRC1_MASK);
		}
	}
	else
	{
		/* Not a special operator, so use the opcode name */
		if(!jit_strncmp(name, "br_", 3))
		{
			name += 3;
		}
		fputs(name, stream);
		if((flags & (JIT_OPCODE_SRC1_MASK | JIT_OPCODE_SRC2_MASK)) != 0)
		{
			putc('(', stream);
			if(jit_insn_dest_is_value(insn))
			{
				dump_value(stream, func, jit_insn_get_dest(insn),
					   	   flags & JIT_OPCODE_DEST_MASK);
				fputs(", ", stream);
			}
			dump_value(stream, func, jit_insn_get_value1(insn),
				   	   flags & JIT_OPCODE_SRC1_MASK);
			if((flags & JIT_OPCODE_SRC2_MASK) != 0)
			{
				fputs(", ", stream);
				dump_value(stream, func, jit_insn_get_value2(insn),
					   	   flags & JIT_OPCODE_SRC2_MASK);
			}
			putc(')', stream);
		}
	}

	/* Dump the "then" information on a conditional branch */
	if((flags & JIT_OPCODE_IS_BRANCH) != 0)
	{
		fprintf(stream, " then goto .L%ld", (long)(jit_insn_get_label(insn)));
	}
}

#if defined(JIT_BACKEND_INTERP)

/*
 * Dump the interpreted bytecode representation of a function.
 */
static void dump_interp_code(FILE *stream, void **pc, void **end)
{
	int opcode;
	const jit_opcode_info_t *info;
	while(pc < end)
	{
		/* Fetch the next opcode */
		opcode = (int)(jit_nint)(*pc);

		/* Dump the address of the opcode */
		fprintf(stream, "\t%08lX: ", (long)(jit_nint)pc);
		++pc;

		/* Get information about this opcode */
		if(opcode < JIT_OP_NUM_OPCODES)
		{
			info = &(jit_opcodes[opcode]);
		}
		else
		{
			info = &(_jit_interp_opcodes[opcode - JIT_OP_NUM_OPCODES]);
		}

		/* Dump the name of the opcode */
		fputs(info->name, stream);

		/* Dump additional parameters from the opcode stream */
		switch(info->flags & JIT_OPCODE_INTERP_ARGS_MASK)
		{
			case JIT_OPCODE_NINT_ARG:
			{
				fprintf(stream, " %ld", (long)(jit_nint)(*pc));
				++pc;
			}
			break;

			case JIT_OPCODE_NINT_ARG_TWO:
			{
				fprintf(stream, " %ld, %ld",
						(long)(jit_nint)(pc[0]), (long)(jit_nint)(pc[1]));
				pc += 2;
			}
			break;

			case JIT_OPCODE_CONST_LONG:
			{
				jit_ulong value;
				jit_memcpy(&value, pc, sizeof(jit_ulong));
				pc += (sizeof(jit_ulong) + sizeof(void *) - 1) /
					  sizeof(void *);
				fprintf(stream, " 0x%lX%08lX",
						(long)((value >> 32) & jit_max_uint),
						(long)(value & jit_max_uint));
			}
			break;

			case JIT_OPCODE_CONST_FLOAT32:
			{
				jit_float32 value;
				jit_memcpy(&value, pc, sizeof(jit_float32));
				pc += (sizeof(jit_float32) + sizeof(void *) - 1) /
					  sizeof(void *);
				fprintf(stream, " %f", (double)value);
			}
			break;

			case JIT_OPCODE_CONST_FLOAT64:
			{
				jit_float64 value;
				jit_memcpy(&value, pc, sizeof(jit_float64));
				pc += (sizeof(jit_float64) + sizeof(void *) - 1) /
					  sizeof(void *);
				fprintf(stream, " %f", (double)value);
			}
			break;

			case JIT_OPCODE_CONST_NFLOAT:
			{
				jit_nfloat value;
				jit_memcpy(&value, pc, sizeof(jit_nfloat));
				pc += (sizeof(jit_nfloat) + sizeof(void *) - 1) /
					  sizeof(void *);
				fprintf(stream, " %f", (double)value);
			}
			break;

			case JIT_OPCODE_CALL_INDIRECT_ARGS:
			{
				fprintf(stream, " %ld", (long)(jit_nint)(pc[1]));
				pc += 2;
			}
			break;

			default:
			{
				if((info->flags & (JIT_OPCODE_IS_BRANCH |
								   JIT_OPCODE_IS_ADDROF_LABEL)) != 0)
				{
					fprintf(stream, " %08lX",
							(long)(jit_nint)((pc - 1) + (jit_nint)(*pc)));
					++pc;
				}
				else if((info->flags & JIT_OPCODE_IS_CALL) != 0)
				{
					fprintf(stream, " 0x%lX", (long)(jit_nint)(*pc));
					++pc;
				}
				else if((info->flags & JIT_OPCODE_IS_CALL_EXTERNAL) != 0)
				{
					fprintf(stream, " 0x%lX, %ld",
							(long)(jit_nint)(pc[1]), (long)(jit_nint)(pc[2]));
					pc += 3;
				}
				else if((info->flags & JIT_OPCODE_IS_JUMP_TABLE) != 0)
				{
					jit_nint label, num_labels;
					num_labels = (jit_nint)pc[0];
					for(label = 1; label <= num_labels; label++)
					{
						fprintf(stream,	" %lX",
							(long)(jit_nint)pc[label]);
					}
					pc += 1 + num_labels;
				}
			}
			break;
		}

		/* Terminate the current disassembly line */
		putc('\n', stream);
	}
}

#else /* !JIT_BACKEND_INTERP */

/*
 * Dump the native object code representation of a function to stream.
 */
static void dump_object_code(FILE *stream, void *start, void *end)
{
	char cmdline[BUFSIZ];
	unsigned char *pc = (unsigned char *)start;
	FILE *file;
	int ch;

#if JIT_WIN32_PLATFORM
	/*
	 * NOTE: If libjit is compiled on cygwin with -mno-cygwin flag then
	 * fopen("/tmp/foo.s", ...) will use the root folder of the current
	 * drive. That is the full file name will be like "c:/tmp/foo". But
	 * the ``as'' and ``objdump'' utilities still use the cygwin's root.
	 * So "as /tmp/foo.s" will look for "c:/cygwin/tmp/foo.s". To avoid
	 * this ambiguity the file name has to contian the drive spec (e.g.
	 * fopen("c:/tmp/foo.s", ...) and "as c;/tmp/foo.s"). Here we assume
	 * that the TMP or TEMP environment variables always contain it.
	 */
	char s_path[BUFSIZ];
	char o_path[BUFSIZ];
	char *tmp_dir = getenv("TMP");
	if(tmp_dir == NULL)
	{
		tmp_dir = getenv("TEMP");
		if(tmp_dir == NULL)
		{
			tmp_dir = "c:/tmp";
		}
	}
	sprintf(s_path, "%s/libjit-dump.s", tmp_dir);
	sprintf(o_path, "%s/libjit-dump.o", tmp_dir);
#else
	const char *s_path = "/tmp/libjit-dump.s";
	const char *o_path = "/tmp/libjit-dump.o";
#endif

	file = fopen(s_path, "w");
	if(!file)
	{
		return;
	}
	fflush(stream);
	while(pc < (unsigned char *)end)
	{
		fprintf(file, ".byte %d\n", (int)(*pc));
		++pc;
	}
	fclose(file);
	sprintf(cmdline, "as %s -o %s", s_path, o_path);
	system(cmdline);
	sprintf(cmdline, "objdump --adjust-vma=%ld -d %s > %s",
			(long)(jit_nint)start, o_path, s_path);
	system(cmdline);
	file = fopen(s_path, "r");
	if(file)
	{
		while((ch = getc(file)) != EOF)
		{
			putc(ch, stream);
		}
		fclose(file);
	}
	unlink(s_path);
	unlink(o_path);
	putc('\n', stream);
	fflush(stream);
}

#endif /* !JIT_BACKEND_INTERP */



( run in 1.509 second using v1.01-cache-2.11-cpan-796a6f069b2 )