Exemple #1
0
/*
 * Split the basic blocks from @first at @target.
 * @hint is a guess of a very close to the target basic block. It is probed before the RB tree as it's often possible
 * to provide a near to exact guess (next block splits, switch branch targets, etc)
 *
 */
static MonoSimpleBasicBlock*
bb_split (MonoSimpleBasicBlock *first, MonoSimpleBasicBlock *hint, MonoSimpleBasicBlock **root, guint target, gboolean link_blocks, MonoMethod *method, MonoError *error)
{
	MonoSimpleBasicBlock *res, *bb = first;

	if (bb_idx_is_contained (hint, target)) {
		first = hint;
	} else if (hint->next && bb_idx_is_contained (hint->next, target)) {
		first = hint->next;
	} else {
		first = *root;
		do {
			if (bb_idx_is_contained (first, target))
				break;
			if (first->start > target)
				first = first->left;
			else
				first = first->right;
		} while (first);
	}

	if (first == NULL) {
		mono_error_set_not_verifiable (error, method, "Invalid instruction target %x", target);
		return NULL;
	}

	if (first->start == target)
		return first;

	res = g_new0 (MonoSimpleBasicBlock, 1);
	res->start = target;
	res->end = first->end;
	res->next = first->next;
	res->out_bb = first->out_bb;
	res->dead = TRUE;

	first->end = res->start;
	first->next = res;
	first->out_bb = NULL;

	if (link_blocks)
		bb_link (first, res);
	bb_insert (bb, res, root);

	return res;
}
Exemple #2
0
/*
 * mono_basic_block_split:
 *
 * Return the list of basic blocks of method. Return NULL on failure and set @error.
*/
MonoSimpleBasicBlock*
mono_basic_block_split (MonoMethod *method, MonoError *error)
{
	MonoSimpleBasicBlock *bb, *root;
	const unsigned char *start, *end;
	MonoMethodHeader *header = mono_method_get_header (method);

	mono_error_init (error);

	if (!header) {
		mono_error_set_not_verifiable (error, method, "Could not decode header");
		return NULL;
	}

	start = header->code;
	end = start + header->code_size;

	bb = g_new0 (MonoSimpleBasicBlock, 1);
	bb->start = 0;
	bb->end = end - start;
	bb->colour = BLACK;
	bb->dead = FALSE;

	root = bb;
	bb_formation_il_pass (start, end, bb, &root, method, error);
	if (!mono_error_ok (error))
		goto fail;
	
	bb_formation_eh_pass (header, bb, &root, method, error);
	if (!mono_error_ok (error))
		goto fail;

	bb_liveness (bb);

#if DEBUG_BB
	dump_bb_list (bb, &root, g_strdup_printf("AFTER LIVENESS %s", mono_method_full_name (method, TRUE)));
#endif

	mono_metadata_free_mh (header);
	return bb;

fail:
	mono_metadata_free_mh (header);
	mono_basic_block_free (bb);
	return NULL;
}
Exemple #3
0
static void
bb_formation_il_pass (const unsigned char *start, const unsigned char *end, MonoSimpleBasicBlock *bb, MonoSimpleBasicBlock **root, MonoMethod *method, MonoError *error)
{
	unsigned const char *ip = start;
	int value, size;
	guint cli_addr, offset;
	MonoSimpleBasicBlock *branch, *next, *current;
	const MonoOpcode *opcode;

	current = bb;

	while (ip < end) {
		cli_addr = ip - start;
		size = mono_opcode_value_and_size (&ip, end, &value);
		if (size < 0) {
			mono_error_set_not_verifiable (error, method, "Invalid instruction %x", *ip);
			return;
		}

		while (current && cli_addr >= current->end)
			current = current->next;
		g_assert (current);

		opcode = &mono_opcodes [value];
		switch (opcode->argument) {
		case MonoInlineNone:
			ip++;
			if (!mono_opcode_has_static_branch (value) || ip >= end)
				break;
			if (!(next = bb_split (bb, current, root, ip - start, FALSE, method, error)))
				return;

			bb_unlink (current, next);
			current = next;
			break;
		case MonoInlineString:
		case MonoInlineType:
		case MonoInlineField:
		case MonoInlineTok:
		case MonoInlineSig:
		case MonoShortInlineR:
		case MonoInlineI:
			ip += 5;
			break;

		case MonoInlineMethod:
			ip += 5;
			if (value != MONO_CEE_JMP || ip >= end)
				break;
			if (!(next = bb_split (bb, current, root, ip - start, FALSE, method, error)))
				return;

			bb_unlink (current, next);
			current = next;

			break;
		case MonoInlineVar:
			ip += 3;
			break;
		case MonoShortInlineVar:
		case MonoShortInlineI:
			ip += 2;
			break;
		case MonoInlineR:
		case MonoInlineI8:
			ip += 9;
			break;
		case MonoShortInlineBrTarget:
		case MonoInlineBrTarget:
			if (opcode->argument == MonoShortInlineBrTarget) {
				offset = cli_addr + 2 + (signed char)ip [1];
				ip += 2;
			} else {
				offset = cli_addr + 5 + (gint32)read32 (ip + 1);
				ip += 5;
			}
			
			branch = bb_split (bb, current, root, offset, TRUE, method, error);
			if (!branch)
				return;

			/*If we splitted the current BB*/
			if (offset < cli_addr && branch->start > current->start)
				current = branch;
			if (ip < end) {
				next = bb_split (bb, current, root, ip - start, opcode->flow_type != MONO_FLOW_BRANCH, method, error);
				if (!next)
					return;
			} else {
				next = NULL;
			}

			bb_link (current, branch);
			if (next && opcode->flow_type == MONO_FLOW_BRANCH && next != branch) {
				bb_unlink (current, next);
				current = next;
			}
			break;
		case MonoInlineSwitch: {
			MonoSimpleBasicBlock *tmp;
			guint32 j, n = read32 (ip + 1);

			ip += 5;
			offset = cli_addr + 5 + 4 * n;
			if (!(next = bb_split (bb, current, root, offset, TRUE, method, error)))
				return;

			bb_link (current, next);
			tmp = next;			

			for (j = 0; j < n; ++j) {
				if (ip >= end) {
					mono_error_set_not_verifiable (error, method, "Invalid switch instruction %x", cli_addr);
					return;
				}
				if (!(next = bb_split (bb, next, root, offset + (gint32)read32 (ip), TRUE, method, error)))
					return;
				bb_link (current, next);
				ip += 4;
			}
			current = tmp;
			break;
		}
		default:
			mono_error_set_not_verifiable (error, method, "Invalid instruction %x", *ip);
			return;
		}
	}
	if (ip != end)
		mono_error_set_not_verifiable (error, method, "Invalid last instruction");
}