Example #1
0
/*
 * public static bool ClrSetTypedReference(TypedReference target,
 *										   Object value);
 */
ILBool _IL_TypedReference_ClrSetTypedReference(ILExecThread *_thread,
										       ILTypedRef target,
										       ILObject *value)
{
	ILType *type;
	if(target.type == 0 || target.value == 0)
	{
		/* This is an invalid typed reference */
		return 0;
	}
	type = ILClassToType(target.type);
	if(ILType_IsPrimitive(type) || ILType_IsValueType(type))
	{
		if(!ILExecThreadUnbox(_thread, type, value, target.value))
		{
			return 0;
		}
		return 1;
	}
	else if(ILTypeAssignCompatible
				(ILProgramItem_Image(_thread->method),
			     (value ? ILClassToType(GetObjectClass(value)) : 0),
			     type))
	{
		*((ILObject **)(target.value)) = value;
		return 1;
	}
	else
	{
		return 0;
	}
}
Example #2
0
/*
 * Get the full size information for a class and its members.
 */
static void GetClassSize(ILSizeInfo *info, ILClass *classInfo)
{
	ILImage *image = ILProgramItem_Image(classInfo);
	ILImplements *impl;
	ILClassLayout *layout;
	ILMember *member;
	int hasEvents, hasProperties;
	ILFieldLayout *fieldLayout;
	ILFieldRVA *fieldRVA;
	ILConstant *constant;
	ILUInt32 type;

	/* Get the size information for the class itself */
	GetMetadataSizeWithAttrs(info, ILToProgramItem(classInfo));

	/* Collect up size information for the interface declarations */
	impl = 0;
	while((impl = ILClassNextImplements(classInfo, impl)) != 0)
	{
		GetMetadataSize(info, ILToProgramItem(impl));
	}

	/* Account for class layout information */
	layout = ILClassLayoutGetFromOwner(classInfo);
	if(layout)
	{
		GetMetadataSize(info, ILToProgramItem(layout));
	}

	/* Account for the nested class declaration */
	if(ILClass_NestedParent(classInfo) != 0)
	{
		info->meta += image->tokenSize[IL_META_TOKEN_NESTED_CLASS >> 24];
		info->loadedMeta += sizeof(ILNestedInfo);
	}
Example #3
0
/*
 * Get blob size information.
 */
static void GetBlobSize(ILSizeInfo *info, ILProgramItem *item, ILUInt32 offset)
{
	ILUInt32 len;
	unsigned char lenbuf[IL_META_COMPRESS_MAX_SIZE];
	if(ILImageGetBlob(ILProgramItem_Image(item), offset, &len))
	{
		info->meta += len;
		info->meta += (unsigned long)(long)ILMetaCompressData(lenbuf, len);
	}
}
Example #4
0
/*
 * private static Assembly LoadFromName(String name, out int error,
 *										Assembly parent);
 */
ILObject *_IL_AppDomain_LoadFromName(ILExecThread *thread,
									ILObject *appDomain,
									ILString *name,
									ILInt32 *error,
									ILObject *parent)
{
	if(!IsAppDomainUnloaded(thread, (ILExecProcess *)appDomain))
	{
		ILProgramItem *item = (ILProgramItem *)_ILClrFromObject(thread, parent);
		ILImage *image = ((item != 0) ? ILProgramItem_Image(item) : 0);
		char *str = ILStringToUTF8(thread, name);
		if(image && str)
		{
			int len;
			int loadError;
			ILImage *newImage;
			len = strlen(str);
			if(len > 4 && str[len - 4] == '.' &&
				(str[len - 3] == 'd' || str[len - 3] == 'D') &&
				(str[len - 2] == 'l' || str[len - 2] == 'L') &&
		 		(str[len - 1] == 'l' || str[len - 1] == 'L'))
			{
				/* Remove ".dll", to get the assembly name */
				str[len - 4] = '\0';
			}
			loadError = ILImageLoadAssembly(str, ((ILExecProcess *)appDomain)->context,
										image, &newImage);
			if(loadError == 0)
			{
				return ImageToAssembly(thread, newImage);
			}
			else if(loadError == -1)
			{
				*error = LoadError_FileNotFound;
				return 0;
			}
			else if(loadError == IL_LOADERR_MEMORY)
			{
				ILExecThreadThrowOutOfMemory(thread);
				return 0;
			}
			else
			{
				*error = LoadError_BadImage;
				return 0;
			}
		}
		else
		{
			*error = LoadError_FileNotFound;
			return 0;
		}
	}
	return 0;
}
Example #5
0
/*
 * Inner version of "_ILConvertMethod", which detects the type of
 * exception to throw, but does not throw it.
 * This method is invoked only during on demand compilation of a jitted IL method
 * and is secured through libjit.
 */
static unsigned char *ConvertMethod(ILExecThread *thread, ILMethod *method,
								    int *errorCode, const char **errorInfo)
{
	ILMethodCode code;
	ILCoder *coder = thread->process->coder;
	unsigned char *start;

#ifndef IL_CONFIG_VARARGS
	/* Vararg methods are not supported */
	if((ILMethod_CallConv(method) & IL_META_CALLCONV_MASK) ==
			IL_META_CALLCONV_VARARG)
	{
		*errorCode = IL_CONVERT_NOT_IMPLEMENTED;
		return 0;
	}
#endif

	/* Get the method code */
	if(!ILMethodGetCode(method, &code))
	{
		code.code = 0;
	}

	/* The conversion is different depending upon whether the
	   method is written in IL or not */
	if(code.code)
	{
		/* Use the bytecode verifier and coder to convert the method */
		if(!_ILVerify(coder, &start, method, &code,
					  ILImageIsSecure(ILProgramItem_Image(method)), thread))
		{
			*errorCode = IL_CONVERT_VERIFY_FAILED;
			return 0;
		}
	}
	else
	{
		/* All other cases should be handled in the jit coder. */

		*errorCode = IL_CONVERT_OUT_OF_MEMORY;
		return 0;
	}

	/* The method is converted now */
	*errorCode = IL_CONVERT_OK;
	return (unsigned char *)1;
}
Example #6
0
int _ILVerify(ILCoder *coder, unsigned char **start, ILMethod *method,
			  ILMethodCode *code, int unsafeAllowed, ILExecThread *thread)
{
	TempAllocator allocator;
	ILCoderExceptions coderExceptions;
	ILCoderExceptionBlock *coderException;
	ILCoderExceptionBlock *currentCoderException;
	int numHandlers;
	int extraCodeLen;
	unsigned long *jumpMask;
	unsigned char *pc;
	ILUInt32 len;
	int result;
	unsigned opcode;
	ILUInt32 insnSize;
	int isStatic, isSynchronized;
	int insnType;
	ILUInt32 offset = 0;
	ILEngineStackItem *stack;
	ILUInt32 stackSize;
#ifdef IL_VERIFY_DEBUG
	const ILOpcodeInfo *insn = 0;
	#define	MAIN_OPCODE_TABLE	ILMainOpcodeTable
	#define	PREFIX_OPCODE_TABLE	ILPrefixOpcodeTable
#else
	const ILOpcodeSmallInfo *insn = 0;
	#define	MAIN_OPCODE_TABLE	ILMainOpcodeSmallTable
	#define	PREFIX_OPCODE_TABLE	ILPrefixOpcodeSmallTable
#endif
	ILType *signature;
	ILType *type;
	ILUInt32 numArgs;
	ILUInt32 numLocals;
	ILType *localVars;
	int lastWasJump;
	ILException *exceptions;
	ILException *exception;
	int hasRethrow;
	int tryInlineType;
	int coderFlags;
	unsigned int tryInlineOpcode;
	unsigned char *tryInlinePc;
	ILUInt32 optimizationLevel;
	ILBool lastInsnWasPrefix;
	ILCoderPrefixInfo prefixInfo;
#ifdef IL_CONFIG_DEBUG_LINES
	int haveDebug = ILDebugPresent(ILProgramItem_Image(method));
#else
	int haveDebug = 0;
#endif

	/* Include local variables that are required by the include files */
#define IL_VERIFY_LOCALS
#include "verify_var.c"
#include "verify_const.c"
#include "verify_arith.c"
#include "verify_conv.c"
#include "verify_stack.c"
#include "verify_ptr.c"
#include "verify_obj.c"
#include "verify_call.c"
#include "verify_branch.c"
#include "verify_except.c"
#include "verify_ann.c"
#undef IL_VERIFY_LOCALS

	/* Get the exception list */
	if(!ILMethodGetExceptions(method, code, &exceptions))
	{
		return 0;
	}

	/* Clear the exception management structure */
	ILMemZero(&coderExceptions, sizeof(ILCoderExceptions));
	/*
	 * Initialize the size of the additional code generated for
	 * synchronization.
	 */
	extraCodeLen = 0;
	/* And set the last label to the code length */
	coderExceptions.lastLabel = code->codeLen;
	
	/* Initialize the memory allocator that is used for temporary
	   allocation during bytecode verification */
	ILMemZero(allocator.buffer, sizeof(allocator.buffer));
	allocator.posn = 0;
	allocator.overflow = 0;

	coderFlags = ILCoderGetFlags(coder);
	optimizationLevel = ILCoderGetOptimizationLevel(coder);
	isStatic = ILMethod_IsStatic(method);
	isSynchronized = ILMethod_IsSynchronized(method);

	result = 0;
	if(exceptions || isSynchronized)
	{
		numHandlers = 0;
		exception = exceptions;
		while(exception)
		{
			++numHandlers;
			exception = exception->next;
		}
		if(isSynchronized)
		{
			/* We'll need an extra try and fault block for synchronization */
			++numHandlers;
		}
		/*
		 * Allocate memory for the exception infos.
		 * There might be create 3 coder exception blocks for one
		 * IL exception.
		 * So we allocate memory for the worst case here.
		 */
		coderExceptions.blocks = ILCalloc(sizeof(ILCoderExceptionBlock),
										  numHandlers * 3);
		if(!coderExceptions.blocks)
		{
			return 0;
		}

		/* Now setup the exception structure */
		exception = exceptions;
		while(exception)
		{
			switch(_ILCoderAddExceptionBlock(&coderExceptions, method,
											 exception))
			{
				case IL_CODER_BRANCH_ERR:
				{
					VERIFY_BRANCH_ERROR();
				}
				break;

				case IL_CODER_TYPE_ERR:
				{
					VERIFY_TYPE_ERROR();
				}
				break;
			}
			exception = exception->next;
		}
		/*
		 * Now check if all exception block limits are in the code.
		 */
		len = code->codeLen;
		coderException = coderExceptions.firstBlock;
		if(coderException)
		{
			/*
			 * Check the start offset of the first exception block in the
			 * lowest list.
			 */
			if(coderException->startOffset > len)
			{
				VERIFY_BRANCH_ERROR();
			}
			/*
			 * Look for the last exception block in the lowest list.
			 */
			while(coderException->nextNested)
			{
				coderException = coderException->nextNested;
			}
			/*
			 * Check the end offset of the last exception block in the
			 * lowest list.
			 * All other exceprion blocks end at or before this offset.
			 */
			if(coderException->endOffset > len)
			{
				VERIFY_BRANCH_ERROR();
			}
		}
		if(isSynchronized)
		{
			/*
			 * Wrap the whole function in a try block with a fault handler.
			 */
			ILException tempException;

			tempException.flags = IL_META_EXCEPTION_FAULT;
			tempException.tryOffset = 0;
			tempException.tryLength = len;
			tempException.handlerOffset = len;
			tempException.handlerLength = 1;
			tempException.extraArg = 0;
			tempException.userData = 0;
			tempException.ptrUserData = 0;
			tempException.next = 0;

			switch(_ILCoderAddExceptionBlock(&coderExceptions, method,
											 &tempException))
			{
				case IL_CODER_BRANCH_ERR:
				{
					VERIFY_BRANCH_ERROR();
				}
				break;

				case IL_CODER_TYPE_ERR:
				{
					VERIFY_TYPE_ERROR();
				}
				break;
			}
			extraCodeLen = 2;
		}
	}

restart:
	result = 0;
	labelList = 0;
	hasRethrow = 0;

	/* Reset the prefix information */
	ILMemZero(&prefixInfo, sizeof(ILCoderPrefixInfo));

	/* Allocate the jump target mask */
	jumpMask = (unsigned long *)TempAllocate
					(&allocator, BYTES_FOR_MASK(code->codeLen + extraCodeLen));
	if(!jumpMask)
	{
		VERIFY_MEMORY_ERROR();
	}

	/* Scan the code looking for all jump targets, and validating
	   that all instructions are more or less valid */
	pc = code->code;
	len = code->codeLen;
	while(len > 0)
	{
		/* Mark this position in the jump mask as an instruction start */
		MarkInsnStart(jumpMask, (ILUInt32)(pc - (unsigned char *)(code->code)));

		/* Fetch the instruction size and type */
		opcode = (unsigned)(pc[0]);
		if(opcode != IL_OP_PREFIX)
		{
			/* Regular opcode */
			insnSize = (ILUInt32)(MAIN_OPCODE_TABLE[opcode].size);
			if(len < insnSize)
			{
				VERIFY_TRUNCATED();
			}
			insnType = MAIN_OPCODE_TABLE[opcode].args;
		}
		else
		{
			/* Prefixed opcode */
			if(len < 2)
			{
				VERIFY_TRUNCATED();
			}
			opcode = (unsigned)(pc[1]);
			insnSize = (ILUInt32)(PREFIX_OPCODE_TABLE[opcode].size);
			if(len < insnSize)
			{
				VERIFY_TRUNCATED();
			}
			insnType = PREFIX_OPCODE_TABLE[opcode].args;
			if(opcode == IL_PREFIX_OP_RETHROW)
			{
				hasRethrow = 1;
			}
			opcode += IL_OP_PREFIX;
		}

		/* Determine how to handle this type of instruction */
		switch(insnType)
		{
			case IL_OPCODE_ARGS_SHORT_JUMP:
			{
				/* 8-bit jump offset */
				offset = (ILUInt32)((pc + insnSize) -
										(unsigned char *)(code->code)) +
						 (ILUInt32)(ILInt32)(ILInt8)(pc[1]);
				if(offset >= code->codeLen)
				{
					VERIFY_BRANCH_ERROR();
				}
				MarkJumpTarget(jumpMask, offset);
			}
			break;

			case IL_OPCODE_ARGS_LONG_JUMP:
			{
				/* 32-bit jump offset */
				offset = (ILUInt32)((pc + insnSize) -
										(unsigned char *)(code->code)) +
						 (ILUInt32)(IL_READ_INT32(pc + 1));
				if(offset >= code->codeLen)
				{
					VERIFY_BRANCH_ERROR();
				}
				MarkJumpTarget(jumpMask, offset);
			}
			break;

			case IL_OPCODE_ARGS_SWITCH:
			{
				/* Switch statement */
				if(len < 5)
				{
					VERIFY_TRUNCATED();
				}
				numArgs = IL_READ_UINT32(pc + 1);
				insnSize = 5 + numArgs * 4;
				if(numArgs >= 0x20000000 || len < insnSize)
				{
					VERIFY_TRUNCATED();
				}
				while(numArgs > 0)
				{
					--numArgs;
					offset = (ILUInt32)((pc + insnSize) -
											(unsigned char *)(code->code)) +
							 (ILUInt32)(IL_READ_INT32(pc + 5 + numArgs * 4));
					if(offset >= code->codeLen)
					{
						VERIFY_BRANCH_ERROR();
					}
					MarkJumpTarget(jumpMask, offset);
				}
			}
			break;

			case IL_OPCODE_ARGS_ANN_DATA:
			{
				/* Variable-length annotation data */
				if(opcode == IL_OP_ANN_DATA_S)
				{
					if(len < 2)
					{
						VERIFY_TRUNCATED();
					}
					insnSize = (((ILUInt32)(pc[1])) & 0xFF) + 2;
					if(len < insnSize)
					{
						VERIFY_TRUNCATED();
					}
				}
				else
				{
					if(len < 6)
					{
						VERIFY_TRUNCATED();
					}
					insnSize = (IL_READ_UINT32(pc + 2) + 6);
					if(len < insnSize)
					{
						VERIFY_TRUNCATED();
					}
				}
			}
			break;

			case IL_OPCODE_ARGS_ANN_PHI:
			{
				/* Variable-length annotation data */
				if(len < 3)
				{
					VERIFY_TRUNCATED();
				}
				insnSize = ((ILUInt32)IL_READ_UINT16(pc + 1)) * 2 + 3;
				if(len < insnSize)
				{
					VERIFY_TRUNCATED();
				}
			}
			break;

			case IL_OPCODE_ARGS_INVALID:
			{
				VERIFY_INSN_ERROR();
			}
			break;

			default: break;
		}

		/* Advance to the next instruction */
		pc += insnSize;
		len -= insnSize;
	}

	/* Mark the start and end of exception blocks as special jump targets */
	numHandlers = 0;
	while(numHandlers < coderExceptions.numBlocks)
	{
		coderException = &(coderExceptions.blocks[numHandlers]);
		MarkJumpTarget(jumpMask, coderException->startOffset);
		MarkSpecialJumpTarget(jumpMask, coderException->startOffset);
		MarkJumpTarget(jumpMask, coderException->endOffset);
		MarkSpecialJumpTarget(jumpMask, coderException->endOffset);
		switch(coderException->flags)
		{
			case IL_CODER_HANDLER_TYPE_TRY:
			{
				/* Nothing to do here */
			}
			break;

			case IL_CODER_HANDLER_TYPE_CATCH:
			{
				/* This is a typed catch block */
				classInfo = coderException->un.handlerBlock.exceptionClass;
				/*
				 * This block will be called with an object of the given
				 * type on the stack.
				 */
				SET_TARGET_STACK(coderException->startOffset, classInfo);
			}
			break;

			case IL_CODER_HANDLER_TYPE_FINALLY:
			case IL_CODER_HANDLER_TYPE_FAULT:
			{
				/* This is a finally or fault clause */
				/* The clause will be called with nothing on the stack */
				SET_TARGET_STACK_EMPTY(coderException->startOffset);
			}
			break;

			case IL_CODER_HANDLER_TYPE_FILTER:
			case IL_CODER_HANDLER_TYPE_FILTEREDCATCH:
			{
				/* This is an exception filter or the corresponding catch block */
				/* 
				 * The block will be called with an object on the stack,
				 * so record that in the label list for later
				 */
				classInfo = ILClassResolveSystem(ILProgramItem_Image(method),
												 0, "Object", "System");
				if(!classInfo)
				{
					/* Ran out of memory trying to create "System.Object" */
					VERIFY_MEMORY_ERROR();
				}
				SET_TARGET_STACK(coderException->startOffset, classInfo);
			}
			break;
		}
		++numHandlers;
	}

	/* Make sure that all jump targets are instruction starts */
	len = code->codeLen;
	while(len > 0)
	{
		--len;
		if(IsJumpTarget(jumpMask, len) && !IsInsnStart(jumpMask, len))
		{
			VERIFY_BRANCH_ERROR();
		}
	}

	/* Create the stack.  We need two extra "slop" items to allow for
	   stack expansion during object construction.  See "verify_call.c"
	   for further details */
	stack = (ILEngineStackItem *)TempAllocate
				(&allocator, sizeof(ILEngineStackItem) * (code->maxStack + 2));
	if(!stack)
	{
		VERIFY_MEMORY_ERROR();
	}
	stackSize = 0;

	/* Get the method signature, plus the number of arguments and locals */
	signature = ILMethod_Signature(method);
	numArgs = ILTypeNumParams(signature);
	if(ILType_HasThis(signature))
	{
		/* Account for the "this" argument */
		++numArgs;
	}
	if(code->localVarSig)
	{
		localVars = ILStandAloneSigGetType(code->localVarSig);
		numLocals = ILTypeNumLocals(localVars);
		if(ILTypeNeedsInstantiation(localVars) &&
		   ILMember_IsGenericInstance(method))
		{
			ILType *classTypeArgs = ILMethodGetClassTypeArguments(method);
			ILType *methodTypeArgs = ILMethodGetMethodTypeArguments(method);

			localVars = ILTypeInstantiate(ILImageToContext(ILProgramItem_Image(method)),
										  localVars,
										  classTypeArgs, 
										  methodTypeArgs);
		}
	}
	else
	{
		localVars = 0;
		numLocals = 0;
	}

	/* Set up the coder to process the method */
	if(!ILCoderSetup(coder, start, method, code, &coderExceptions, hasRethrow))
	{
		VERIFY_MEMORY_ERROR();
	}

	if((coderFlags & IL_CODER_FLAG_METHOD_PROFILE) != 0)
	{
		ILCoderProfileStart(coder);
	}

	/* Verify the code */
	pc = code->code;
	len = code->codeLen;
	lastWasJump = 0;

	/* If the method is synchronized then generate the Monitor.Enter call */
	if (isSynchronized)
	{
		PUSH_SYNC_OBJECT();
		ILCoderCallInlineable(coder, IL_INLINEMETHOD_MONITOR_ENTER, 0, 0);
	}

	lastInsnWasPrefix = 0;
	while(len > 0)
	{
		/* Fetch the instruction information block */
		offset = (ILUInt32)(pc - (unsigned char *)(code->code));
		opcode = pc[0];
		if(opcode != IL_OP_PREFIX)
		{
			insn = &(MAIN_OPCODE_TABLE[opcode]);
		}
		else
		{
			opcode = pc[1];
			insn = &(PREFIX_OPCODE_TABLE[opcode]);
			opcode += IL_OP_PREFIX;
		}
		insnSize = (ILUInt32)(insn->size);

		/* Is this a jump target? */
		if(IsJumpTarget(jumpMask, offset))
		{
			/* Validate the stack information */
			VALIDATE_TARGET_STACK(offset);

			/* Notify the coder of a label at this position */
		#ifdef IL_USE_JIT
			ILCoderStackRefresh(coder, stack, stackSize);
			ILCoderLabel(coder, offset);
		#else
			ILCoderLabel(coder, offset);
			ILCoderStackRefresh(coder, stack, stackSize);
		#endif
		}
		else if(lastWasJump)
		{
			/* An instruction just after an opcode that jumps to
			   somewhere else in the flow of control.  As this
			   isn't a jump target, we assume that the stack
			   must be empty at this point.  The validate code
			   will ensure that this is checked */
			VALIDATE_TARGET_STACK(offset);

			/* Reset the coder's notion of the stack to empty */
			ILCoderStackRefresh(coder, stack, stackSize);
		}

		/* Mark this offset if the method has debug information */
		if(haveDebug)
		{
			ILCoderMarkBytecode(coder, offset);
		}

		/* Validate the stack height changes */
		if(stackSize < ((ILUInt32)(insn->popped)) ||
		   (stackSize - ((ILUInt32)(insn->popped)) + ((ILUInt32)(insn->pushed)))
				> code->maxStack)
		{
			VERIFY_STACK_ERROR();
		}

		/*
		 * Check if all prefix flags are zero, otherwise an invalid prefix
		 * was used for the last instruction.
		 */
		if(!lastInsnWasPrefix)
		{
			if((prefixInfo.prefixFlags != 0) || (prefixInfo.noFlags != 0))
			{
				VERIFY_PREFIX_ERROR();
			}
		}

		/* Verify the instruction */
		lastWasJump = 0;
		lastInsnWasPrefix = 0;
		switch(opcode)
		{
			case IL_OP_NOP:   break;

			/* IL breakpoints are ignored - the coder inserts its
			   own breakpoint handlers where required */
			case IL_OP_BREAK: break;

#define	IL_VERIFY_CODE
#include "verify_var.c"
#include "verify_const.c"
#include "verify_arith.c"
#include "verify_conv.c"
#include "verify_stack.c"
#include "verify_ptr.c"
#include "verify_obj.c"
#include "verify_branch.c"
#include "verify_call.c"
#include "verify_except.c"
#include "verify_ann.c"
#undef IL_VERIFY_CODE

		}

		/* Advance to the next instruction */
		pc += insnSize;
		len -= insnSize;
	}

	/* If the last instruction was not a jump, then the code
	   may fall off the end of the method */
	if(!lastWasJump)
	{
		VERIFY_INSN_ERROR();
	}

	/*
	 * Generate the code for the fault block for synchronization.
	 */
	if(isSynchronized)
	{
		coderException = _ILCoderFindExceptionBlock(&coderExceptions, code->codeLen);
		/*
		 * This check is for catching bugs.
		 */
		if(!coderException ||
		   ((coderException->flags & IL_CODER_HANDLER_TYPE_FINALLY) == 0))
		{
			VERIFY_BRANCH_ERROR();
		}
		/*
		 * Insert the start label for the fault handler.
		 */
		ILCoderLabel(coder, code->codeLen);

		/*
		 * Call the Monitor.Exit method.
		 */
		PUSH_SYNC_OBJECT();
		ILCoderCallInlineable(coder, IL_INLINEMETHOD_MONITOR_EXIT, 0, 0);
		/*
		 * Leave the fault block.
		 */
		ILCoderRetFromFinally(coder);
		/*
		 * Insert the end label for the fault handler.
		 */
		ILCoderLabel(coder, code->codeLen + 1);
	}
	
	/* Mark the end of the method */
	ILCoderMarkEnd(coder);

	/* Output the exception handler table, if necessary */
	if(coderExceptions.numBlocks > 0)
	{
		ILCoderOutputExceptionTable(coder, &coderExceptions);
	}

	/* Finish processing using the coder */
	result = ILCoderFinish(coder);

	/* Do we need to restart due to cache exhaustion in the coder? */
	if(result == IL_CODER_END_RESTART)
	{
		TempAllocatorDestroy(&allocator);
		/* Reinitialize the memory allocator that is used for temporary
		   allocation during bytecode verification */
		ILMemZero(allocator.buffer, sizeof(allocator.buffer));
		allocator.posn = 0;
		allocator.overflow = 0;

		/*
		 * Reset the userdata in the exception blocks.
		 */
		numHandlers = 0;
		while(numHandlers < coderExceptions.numBlocks)
		{
			coderException = &(coderExceptions.blocks[numHandlers]);
			coderException->userData = 0;
			coderException->ptrUserData = 0;
			++numHandlers;
		}
		
		goto restart;
	}
#ifdef IL_VERIFY_DEBUG
	else if(result == IL_CODER_END_TOO_BIG)
	{
		ILMethodCode code;
		ILMethodGetCode(method,&code);
		fprintf(stderr,
			"%s::%s - method is too big to be converted (%d%s bytes)\n",
							ILClass_Name(ILMethod_Owner(method)),
							ILMethod_Name(method),
							code.codeLen,
							(code.moreSections != 0) ? "+" : "");
	}
#endif
	result = (result == IL_CODER_END_OK);

	/* Clean up and exit */
cleanup:
	TempAllocatorDestroy(&allocator);
	if(exceptions)
	{
		ILMethodFreeExceptions(exceptions);
	}
	if(coderExceptions.blocks)
	{
		ILFree(coderExceptions.blocks);
	}

	return result;
}
Example #7
0
/*
 * Determine if a stack item is assignment-compatible with
 * a particular memory slot (argument, local, field, etc).
 */
static int AssignCompatible(ILMethod *method, ILEngineStackItem *item,
							ILType *type, int unsafeAllowed)
{
	ILImage *image;
	ILClass *classInfo;
	ILClass *classInfo2;
	ILMethod *methodRef;
	ILType *objType;

	/* Check for safe and unsafe pointer assignments */
	if(item->engineType == ILEngineType_I)
	{
		methodRef = MethodRefToMethod(item->typeInfo);
		if(methodRef)
		{
			/* Assigning a method reference, obtained via "ldftn"
			   or "ldvirtftn", to a method pointer destination */
			if(ILTypeIdentical(ILMethod_Signature(methodRef), type))
			{
				return 1;
			}
		}
		else if(item->typeInfo != 0 && ILType_IsComplex(item->typeInfo))
		{
			/* May be trying to assign a method pointer to a method type */
			if(ILType_IsMethod(item->typeInfo))
			{
				if(ILTypeIdentical(item->typeInfo, type))
				{
					return 1;
				}
			}
		}
		if(unsafeAllowed)
		{
			if(type != 0 && ILType_IsComplex(type))
			{
				if((ILType_Kind(type) & IL_TYPE_COMPLEX_METHOD) != 0 ||
				   ILType_Kind(type) == IL_TYPE_COMPLEX_PTR)
				{
					return 1;
				}
			}
		}
	}

	/* Check for regular assignments */
	if(item->engineType == ILEngineType_I4 ||
	   item->engineType == ILEngineType_I)
	{
		type = ILTypeGetEnumType(type);
		switch((unsigned long)type)
		{
			case (unsigned long)ILType_Boolean:
			case (unsigned long)ILType_Int8:
			case (unsigned long)ILType_UInt8:
			case (unsigned long)ILType_Int16:
			case (unsigned long)ILType_UInt16:
			case (unsigned long)ILType_Char:
			case (unsigned long)ILType_Int32:
			case (unsigned long)ILType_UInt32:
			case (unsigned long)ILType_Int:
			case (unsigned long)ILType_UInt:	return 1;
			default: break;
		}

		if(!unsafeAllowed)
		{
			return 0;
		}

		/* Allow a native int to be assigned to a complex type */
		if(type != 0 && ILType_IsComplex(type) && 
						item->engineType == ILEngineType_I)
		{
			if(ILType_Kind(type) == IL_TYPE_COMPLEX_PTR ||
			  ILType_Kind(type) == IL_TYPE_COMPLEX_BYREF) 
			{
				return 1;
			}
		}
		return 0;
	}
	else if(item->engineType == ILEngineType_I8)
	{
		type = ILTypeGetEnumType(type);
		return (type == ILType_Int64 || type == ILType_UInt64);
	}
	else if(item->engineType == ILEngineType_F)
	{
		return (type == ILType_Float32 ||
		        type == ILType_Float64 ||
		        type == ILType_Float);
	}
	else if(item->engineType == ILEngineType_O)
	{
		if(!(item->typeInfo))
		{
			/* A "null" constant was pushed, which is
			   compatible with any object reference type */
			return IsObjectRef(type);
		}
		if(!IsObjectRef(type) || !IsObjectRef(item->typeInfo))
		{
			/* Both types must be object references */
			return 0;
		}
		/* make a copy to avoid unecessary complications */
		objType=item->typeInfo;
		if(ILType_IsArray(type) && ILType_IsArray(objType) &&
			(ILTypeGetRank(type) == ILTypeGetRank(objType)))
		{
			objType=ILTypeGetElemType(objType);
			type=ILTypeGetElemType(type);
		}
		image = ILProgramItem_Image(method);
		classInfo = ILClassResolve(ILClassFromType(image, 0, type, 0));
		classInfo2 = ILClassResolve
			(ILClassFromType(image, 0, objType, 0));
		if(classInfo && classInfo2)
		{
			/* Is the type a regular class or an interface? */
			if(!ILClass_IsInterface(classInfo))
			{
				/* Regular class: the value must inherit from the type */
				if(ILClassInheritsFrom(classInfo2, classInfo))
				{
					return 1;
				}

				/* If "classInfo2" is an interface, then the conversion
				   is OK if "type" is "System.Object", because all
				   interfaces inherit from "System.Object", even though
				   the metadata doesn't explicitly say so */
				if(ILClass_IsInterface(classInfo2))
				{
					return ILTypeIsObjectClass(type);
				}

				/* The conversion is not OK */
				return 0;
			}
			else
			{
				/* Interface which the value must implement or inherit from */
				return ILClassImplements(classInfo2, classInfo) ||
				       ILClassInheritsFrom(classInfo2, classInfo);
			}
		}
		else
		{
			return 0;
		}
	}
	else if(item->engineType == ILEngineType_MV)
	{
		/* Can only assign managed values to an exact type destination */
		return ILTypeIdentical(item->typeInfo, type);
	}
	else if(item->engineType == ILEngineType_TypedRef)
	{
		/* The type must be "typedref" */
		return (type == ILType_TypedRef);
	}
	else if(item->engineType == ILEngineType_M ||
	        item->engineType == ILEngineType_T)
	{
		/* Cannot assign managed pointers to variables or fields,
		   unless we are in "unsafe" mode */
		if(!unsafeAllowed)
		{
			return 0;
		}

		/* Allow an assignment to any pointer, reference, or native
		   destination, regardless of type.  This allows C/C++ code
		   to arbitrarily cast pointers via assignment */
		if(type != 0 && ILType_IsComplex(type))
		{
			if(ILType_Kind(type) == IL_TYPE_COMPLEX_PTR ||
			   ILType_Kind(type) == IL_TYPE_COMPLEX_BYREF ||
			   (ILType_Kind(type) & IL_TYPE_COMPLEX_METHOD) != 0)
			{
				return 1;
			}
		}
		else if(type == ILType_Int || type == ILType_UInt)
		{
			return 1;
		}
		return 0;
	}
	else
	{
		/* Invalid type: never assignment-compatible with anything */
		return 0;
	}
}
Example #8
0
/*
 * Get the metadata size information for a program item,
 * both on-disk and in-memory.
 */
static void GetMetadataSize(ILSizeInfo *info, ILProgramItem *item)
{
	ILImage *image = ILProgramItem_Image(item);
	if(!item)
	{
		return;
	}
	info->meta += image->tokenSize[ILProgramItem_Token(item) >> 24];
	switch(ILProgramItem_Token(item) & IL_META_TOKEN_MASK)
	{
		case IL_META_TOKEN_MODULE:
			GetStringSize(info, ILModule_Name((ILModule *)item));
			info->meta += 16;		/* GUID size */
			info->loadedMeta += sizeof(ILModule);
			break;

		case IL_META_TOKEN_MODULE_REF:
			GetStringSize(info, ILModule_Name((ILModule *)item));
			info->loadedMeta += sizeof(ILModule);
			break;

		case IL_META_TOKEN_TYPE_REF:
			info->loadedMeta += sizeof(ILClass);
			info->loadedMeta += sizeof(ILProgramItemLink);
			GetClassNameSize(info, (ILClass *)item);
			break;

		case IL_META_TOKEN_TYPE_DEF:
			info->loadedMeta += sizeof(ILClass);
			GetClassNameSize(info, (ILClass *)item);
			break;

		case IL_META_TOKEN_FIELD_DEF:
			info->loadedMeta += sizeof(ILField);
			GetStringSize(info, ILMember_Name(item));
			GetBlobSize(info, item, ((ILMember *)item)->signatureBlob);
			GetTypeSize(info, ILMember_Signature(item));
			break;

		case IL_META_TOKEN_METHOD_DEF:
			info->loadedMeta += sizeof(ILMethod);
			GetStringSize(info, ILMember_Name(item));
			GetBlobSize(info, item, ((ILMember *)item)->signatureBlob);
			GetTypeSize(info, ILMember_Signature(item));
			break;

		case IL_META_TOKEN_PARAM_DEF:
			info->loadedMeta += sizeof(ILParameter);
			GetStringSize(info, ILParameter_Name((ILParameter *)item));
			break;

		case IL_META_TOKEN_INTERFACE_IMPL:
			info->loadedMeta += sizeof(ILImplements);
			break;

		case IL_META_TOKEN_MEMBER_REF:
			if(ILMemberGetKind((ILMember *)item) == IL_META_MEMBERKIND_METHOD)
			{
				info->loadedMeta += sizeof(ILMethod);
			}
			else
			{
				info->loadedMeta += sizeof(ILField);
			}
			info->loadedMeta += sizeof(ILProgramItemLink);
			GetStringSize(info, ILMember_Name(item));
			GetBlobSize(info, item, ((ILMember *)item)->signatureBlob);
			GetTypeSize(info, ILMember_Signature(item));
			break;

		case IL_META_TOKEN_CONSTANT:
			info->loadedMeta += sizeof(ILConstant);
			GetBlobSize(info, item, ((ILConstant *)item)->value);
			break;

		case IL_META_TOKEN_CUSTOM_ATTRIBUTE:
			info->loadedMeta += sizeof(ILAttribute);
			GetBlobSize(info, item, ((ILAttribute *)item)->value);
			break;

		case IL_META_TOKEN_FIELD_MARSHAL:
			info->loadedMeta += sizeof(ILFieldMarshal);
			GetBlobSize(info, item, ((ILFieldMarshal *)item)->type);
			break;

		case IL_META_TOKEN_DECL_SECURITY:
			info->loadedMeta += sizeof(ILDeclSecurity);
			GetBlobSize(info, item, ((ILDeclSecurity *)item)->blob);
			break;

		case IL_META_TOKEN_CLASS_LAYOUT:
			info->loadedMeta += sizeof(ILClassLayout);
			break;

		case IL_META_TOKEN_FIELD_LAYOUT:
			info->loadedMeta += sizeof(ILFieldLayout);
			break;

		case IL_META_TOKEN_STAND_ALONE_SIG:
			info->loadedMeta += sizeof(ILStandAloneSig);
			GetBlobSize(info, item, ((ILStandAloneSig *)item)->typeBlob);
			GetTypeSize(info, ((ILStandAloneSig *)item)->type);
			break;

		case IL_META_TOKEN_EVENT_MAP:
			info->loadedMeta += sizeof(ILEventMap);
			break;

		case IL_META_TOKEN_EVENT:
			info->loadedMeta += sizeof(ILEvent);
			break;

		case IL_META_TOKEN_PROPERTY_MAP:
			info->loadedMeta += sizeof(ILPropertyMap);
			break;

		case IL_META_TOKEN_PROPERTY:
			info->loadedMeta += sizeof(ILProperty);
			break;

		case IL_META_TOKEN_METHOD_SEMANTICS:
			info->loadedMeta += sizeof(ILMethodSem);
			break;

		case IL_META_TOKEN_METHOD_IMPL:
			info->loadedMeta += sizeof(ILOverride);
			break;

		case IL_META_TOKEN_TYPE_SPEC:
			info->loadedMeta += sizeof(ILTypeSpec);
			GetBlobSize(info, item, ((ILTypeSpec *)item)->typeBlob);
			GetTypeSize(info, ((ILTypeSpec *)item)->type);
			break;

		case IL_META_TOKEN_IMPL_MAP:
			info->loadedMeta += sizeof(ILPInvoke);
			GetStringSize(info, ILPInvoke_Alias((ILPInvoke *)item));
			break;

		case IL_META_TOKEN_FIELD_RVA:
			info->loadedMeta += sizeof(ILFieldRVA);
			break;

		case IL_META_TOKEN_ASSEMBLY:
			info->loadedMeta += sizeof(ILAssembly);
			GetStringSize(info, ILAssembly_Name((ILAssembly *)item));
			GetStringSize(info, ILAssembly_Locale((ILAssembly *)item));
			break;

		case IL_META_TOKEN_ASSEMBLY_REF:
			info->loadedMeta += sizeof(ILAssembly);
			info->loadedMeta += sizeof(ILProgramItemLink);
			GetStringSize(info, ILAssembly_Name((ILAssembly *)item));
			GetStringSize(info, ILAssembly_Locale((ILAssembly *)item));
			break;

		case IL_META_TOKEN_PROCESSOR_DEF:
		case IL_META_TOKEN_PROCESSOR_REF:
			info->loadedMeta += sizeof(ILProcessorInfo);
			break;

		case IL_META_TOKEN_OS_DEF:
		case IL_META_TOKEN_OS_REF:
			info->loadedMeta += sizeof(ILOSInfo);
			break;

		case IL_META_TOKEN_FILE:
			info->loadedMeta += sizeof(ILFileDecl);
			GetStringSize(info, ILFileDecl_Name((ILFileDecl *)item));
			GetBlobSize(info, item, ((ILFileDecl *)item)->hash);
			break;

		case IL_META_TOKEN_EXPORTED_TYPE:
			info->loadedMeta += sizeof(ILExportedType);
			info->loadedMeta += sizeof(ILProgramItemLink);
			GetClassNameSize(info, (ILClass *)item);
			break;

		case IL_META_TOKEN_MANIFEST_RESOURCE:
			info->loadedMeta += sizeof(ILManifestRes);
			GetStringSize(info, ILManifestRes_Name((ILManifestRes *)item));
			break;

		case IL_META_TOKEN_NESTED_CLASS:
			info->loadedMeta += sizeof(ILNestedInfo);
			break;

		case IL_META_TOKEN_GENERIC_PAR:
			info->loadedMeta += sizeof(ILGenericPar);
			GetStringSize(info, ILGenericPar_Name((ILGenericPar *)item));
			break;

		case IL_META_TOKEN_METHOD_SPEC:
			info->loadedMeta += sizeof(ILMethodSpec);
			GetBlobSize(info, item, ((ILMethodSpec *)item)->typeBlob);
			GetTypeSize(info, ((ILMethodSpec *)item)->type);
			break;
	}
}
Example #9
0
/*
 * Inner version of "_ILConvertMethod", which detects the type of
 * exception to throw, but does not throw it.
 */
static unsigned char *ConvertMethod(ILExecThread *thread, ILMethod *method,
								    int *errorCode, const char **errorInfo)
{
	ILMethodCode code;
	ILPInvoke *pinv;
	ILCoder *coder = thread->process->coder;
	unsigned char *start;
	void *cif;
	void *ctorcif;
	int isConstructor;
#ifdef IL_CONFIG_PINVOKE
	ILModule *module;
	const char *name;
	void *moduleHandle;
#endif
	int result;
	ILInternalInfo fnInfo;
	ILInternalInfo ctorfnInfo;

	/* We need the metadata write lock */
	METADATA_WRLOCK(thread);

	/* Handle locked methods while cctors are executed. */
	if((start = (unsigned char *)ILCoderHandleLockedMethod(coder, method)))
	{
		METADATA_UNLOCK(thread);
		*errorCode = IL_CONVERT_OK;
		return start;
	}

	/* Is the method already converted? */
	if((start = (unsigned char *)(method->userData)) != 0)
	{
		METADATA_UNLOCK(thread);
		*errorCode = IL_CONVERT_OK;
		return start;
	}

#ifndef IL_CONFIG_VARARGS
	/* Vararg methods are not supported */
	if((ILMethod_CallConv(method) & IL_META_CALLCONV_MASK) ==
			IL_META_CALLCONV_VARARG)
	{
		METADATA_UNLOCK(thread);
		*errorCode = IL_CONVERT_NOT_IMPLEMENTED;
		return 0;
	}
#endif

	/* Make sure that we can lay out the method's class */
	if(!_ILLayoutClass(_ILExecThreadProcess(thread), ILMethod_Owner(method)))
	{
		METADATA_UNLOCK(thread);
		*errorCode = IL_CONVERT_TYPE_INIT;
		return 0;
	}

	/* Get the method code */
	if(!ILMethodGetCode(method, &code))
	{
		code.code = 0;
	}

	/* The conversion is different depending upon whether the
	   method is written in IL or not */
	if(code.code)
	{
		/* Use the bytecode verifier and coder to convert the method */
		if(!_ILVerify(coder, &start, method, &code,
					  ILImageIsSecure(ILProgramItem_Image(method)), thread))
		{
			METADATA_UNLOCK(thread);
			*errorCode = IL_CONVERT_VERIFY_FAILED;
			return 0;
		}
	}
	else
	{
		/* This is a "PInvoke", "internalcall", or "runtime" method */
		pinv = ILPInvokeFind(method);
		fnInfo.func = 0;
		fnInfo.marshal = 0;
		ctorfnInfo.func = 0;
		ctorfnInfo.marshal = 0;
		isConstructor = ILMethod_IsConstructor(method);
		switch(method->implementAttrs &
					(IL_META_METHODIMPL_CODE_TYPE_MASK |
					 IL_META_METHODIMPL_INTERNAL_CALL |
					 IL_META_METHODIMPL_JAVA))
		{
			case IL_META_METHODIMPL_IL:
			case IL_META_METHODIMPL_OPTIL:
			{
				/* If we don't have a PInvoke record, then we don't
				   know what to map this method call to */
				if(!pinv)
				{
					METADATA_UNLOCK(thread);
					*errorCode = IL_CONVERT_ENTRY_POINT;
					return 0;
				}

			#ifdef IL_CONFIG_PINVOKE
				/* Find the module for the PInvoke record */
				module = ILPInvoke_Module(pinv);
				if(!module)
				{
					METADATA_UNLOCK(thread);
					*errorCode = IL_CONVERT_ENTRY_POINT;
					return 0;
				}
				name = ILModule_Name(module);
				if(!name || *name == '\0')
				{
					METADATA_UNLOCK(thread);
					*errorCode = IL_CONVERT_ENTRY_POINT;
					return 0;
				}
				moduleHandle = LocateExternalModule
									(thread->process, name, pinv);
				if(!moduleHandle)
				{
					METADATA_UNLOCK(thread);
					*errorCode = IL_CONVERT_DLL_NOT_FOUND;
					*errorInfo = name;
					return 0;
				}

				/* Get the name of the function within the module */
				name = ILPInvoke_Alias(pinv);
				if(!name || *name == '\0')
				{
					name = ILMethod_Name(method);
				}

			#ifdef IL_WIN32_PLATFORM

				if(!(pinv->member.attributes & IL_META_PINVOKE_NO_MANGLE))
				{
					/* We have to append an A or W to the function */
					/* name depending on the characterset used. */
					/* On Windows we have only either Ansi or Utf16 */
					int nameLength = strlen(name);
					ILUInt32 charSetUsed = ILPInvokeGetCharSet(pinv, method);
					char newName[nameLength + 2];

					strcpy(newName, name);
					if(charSetUsed == IL_META_MARSHAL_UTF16_STRING)
					{
						newName[nameLength] = 'W';
					}
					else
					{
						newName[nameLength] = 'A';
					}
					newName[nameLength + 1] = '\0';

					/* Look up the method within the module */
					fnInfo.func = ILDynLibraryGetSymbol(moduleHandle, newName);
				}
				if(!fnInfo.func)
				{
					/* Look up the method within the module */
					fnInfo.func = ILDynLibraryGetSymbol(moduleHandle, name);
				}
			#else	/* !IL_WIN32_PLATFORM */
				/* Look up the method within the module */
				fnInfo.func = ILDynLibraryGetSymbol(moduleHandle, name);
			#endif	/* !IL_WIN32_PLATFORM */
			#else /* !IL_CONFIG_PINVOKE */
				METADATA_UNLOCK(thread);
				*errorCode = IL_CONVERT_NOT_IMPLEMENTED;
				return 0;
			#endif /* IL_CONFIG_PINVOKE */
			}
			break;

			case IL_META_METHODIMPL_RUNTIME:
			case IL_META_METHODIMPL_IL | IL_META_METHODIMPL_INTERNAL_CALL:
			{
				/* "internalcall" and "runtime" methods must not
				   have PInvoke records associated with them */
				if(pinv)
				{
					METADATA_UNLOCK(thread);
					*errorCode = IL_CONVERT_VERIFY_FAILED;
					return 0;
				}

				/* Look up the internalcall function details */
				if(!_ILFindInternalCall(ILExecThreadGetProcess(thread),
										method, 0, &fnInfo))
				{
					if(isConstructor)
					{
						if(!_ILFindInternalCall(ILExecThreadGetProcess(thread),
												method, 1, &ctorfnInfo))
						{
							METADATA_UNLOCK(thread);
							*errorCode = IL_CONVERT_NOT_IMPLEMENTED;
							return 0;
						}
					}
					else
					{
						METADATA_UNLOCK(thread);
						*errorCode = IL_CONVERT_NOT_IMPLEMENTED;
						return 0;
					}
				}
				else if(isConstructor)
				{
					_ILFindInternalCall(ILExecThreadGetProcess(thread),
										method, 1, &ctorfnInfo);
				}
			}
			break;

			default:
			{
				/* No idea how to invoke this method */
				METADATA_UNLOCK(thread);
				*errorCode = IL_CONVERT_VERIFY_FAILED;
				return 0;
			}
			/* Not reached */
		}

		/* Bail out if we did not find the underlying native method */
		if(!(fnInfo.func) && !(ctorfnInfo.func))
		{
			METADATA_UNLOCK(thread);
			if(pinv)
				*errorCode = IL_CONVERT_ENTRY_POINT;
			else
				*errorCode = IL_CONVERT_NOT_IMPLEMENTED;
			return 0;
		}

	#if defined(HAVE_LIBFFI)
		/* Generate a "cif" structure to handle the native call details */
		if(fnInfo.func)
		{
			/* Make the "cif" structure for the normal method entry */
			cif = _ILMakeCifForMethod(_ILExecThreadProcess(thread),
										method, (pinv == 0));
			if(!cif)
			{
				METADATA_UNLOCK(thread);
				*errorCode = IL_CONVERT_OUT_OF_MEMORY;
				return 0;
			}
		}
		else
		{
			cif = 0;
		}
		if(ctorfnInfo.func)
		{
			/* Make the "cif" structure for the allocating constructor */
			ctorcif = _ILMakeCifForConstructor(_ILExecThreadProcess(thread),
												method, (pinv == 0));
			if(!ctorcif)
			{
				METADATA_UNLOCK(thread);
				*errorCode = IL_CONVERT_OUT_OF_MEMORY;
				return 0;
			}
		}
		else
		{
			ctorcif = 0;
		}
	#else
		/* Use the marshalling function pointer as the cif if no libffi */
		cif = fnInfo.marshal;
		ctorcif = ctorfnInfo.marshal;
	#endif

		/* Generate the coder stub for marshalling the call */
		if(!isConstructor)
		{
			/* We only need the method entry point */
			if(!ILCoderSetupExtern(coder, &start, method,
								   fnInfo.func, cif, (pinv == 0)))
			{
				METADATA_UNLOCK(thread);
				*errorCode = IL_CONVERT_OUT_OF_MEMORY;
				return 0;
			}
			while((result = ILCoderFinish(coder)) != IL_CODER_END_OK)
			{
				/* Do we need a coder restart due to cache overflow? */
				if(result != IL_CODER_END_RESTART)
				{
					METADATA_UNLOCK(thread);
					*errorCode = IL_CONVERT_OUT_OF_MEMORY;
					return 0;
				}
				if(!ILCoderSetupExtern(coder, &start, method,
									   fnInfo.func, cif, (pinv == 0)))
				{
					METADATA_UNLOCK(thread);
					*errorCode = IL_CONVERT_OUT_OF_MEMORY;
					return 0;
				}
			}
		}
		else
		{
			/* We need both the method and constructor entry points */
			if(!ILCoderSetupExternCtor(coder, &start, method,
								       fnInfo.func, cif,
									   ctorfnInfo.func, ctorcif,
									   (pinv == 0)))
			{
				METADATA_UNLOCK(thread);
				*errorCode = IL_CONVERT_OUT_OF_MEMORY;
				return 0;
			}
			while((result = ILCoderFinish(coder)) != IL_CODER_END_OK)
			{
				/* Do we need a coder restart due to cache overflow? */
				if(result != IL_CODER_END_RESTART)
				{
					METADATA_UNLOCK(thread);
					*errorCode = IL_CONVERT_OUT_OF_MEMORY;
					return 0;
				}
				if(!ILCoderSetupExternCtor(coder, &start, method,
									       fnInfo.func, cif,
										   ctorfnInfo.func, ctorcif,
										   (pinv == 0)))
				{
					METADATA_UNLOCK(thread);
					*errorCode = IL_CONVERT_OUT_OF_MEMORY;
					return 0;
				}
			}
		}
	}

	/* The method is converted now */
	/* Run the needed cctors and unlock the metadata too */
	ILCoderRunCCtors(coder, start);
	*errorCode = IL_CONVERT_OK;
	return start;
}
/*
 * Output a table of exception matching directives.
 * Each table entry specifies a region of code for the
 * directive.  Whenever an exception occurs in this
 * region, the method will jump to the instructions
 * contained in the table entry.  These instructions
 * will typically call "finally" handlers, and then
 * attempt to match the exception against the rules.
 */
static void OutputExceptionTable(ILCoder *coder, ILMethod *method,
								 ILException *exceptions, int hasRethrow)
{
	ILUInt32 offset;
	ILUInt32 end;
	int isStatic;
	ILException *exception;
	ILClass *classInfo;
	
	/* Process all regions in the method */
	offset = 0;
	for(;;)
	{
		/* Find the end of the region that starts at "offset" */
		end = IL_MAX_UINT32;
		exception = exceptions;
		while(exception != 0)
		{
			if(offset < exception->tryOffset)
			{
				/* We are in the code before this exception region */
				if(end > exception->tryOffset)
				{
					end = exception->tryOffset;
				}
			}
			else if(offset >= exception->tryOffset &&
			        offset < (exception->tryOffset + exception->tryLength))
			{
				/* We are in code in the middle of this exception region */
				if(end > (exception->tryOffset + exception->tryLength))
				{
					end = exception->tryOffset + exception->tryLength;
				}
			}
			exception = exception->next;
		}
		if(end == IL_MAX_UINT32)
		{
			break;
		}

		/* Output the region information to the table */
		ILCoderTryHandlerStart(coder, offset, end);

		/* Output exception matching code for this region */
		exception = exceptions;
		while(exception != 0)
		{
			if(offset >= exception->tryOffset &&
			   offset < (exception->tryOffset + exception->tryLength))
			{
				if((exception->flags & (IL_META_EXCEPTION_FINALLY |
										IL_META_EXCEPTION_FAULT)) != 0)
				{
					/* Call a "finally" or "fault" clause */
					ILCoderFinally(coder, exception, exception->handlerOffset);					
				}
				else if((exception->flags & IL_META_EXCEPTION_FILTER) == 0)
				{
					/* Match against a "catch" clause */
					classInfo = ILProgramItemToClass
						((ILProgramItem *)ILImageTokenInfo
							(ILProgramItem_Image(method), exception->extraArg));

					ILCoderCatch(coder, exception, classInfo, hasRethrow);
				}
				else
				{
					/* TODO: handle a "filter" clause */
				}
			}
			exception = exception->next;
		}

		/* If execution falls off the end of the matching code,
		   then throw the exception to the calling method */
		ILCoderThrow(coder, 0);

		/* Mark the end of the handler */
		ILCoderTryHandlerEnd(coder);

		/* Advance to the next region within the code */
		offset = end;
	}

	/* If execution gets here, then there were no applicable catch blocks,
	   so we always throw the exception to the calling method */
	ILCoderTryHandlerStart(coder, 0, IL_MAX_UINT32);
	
	if (ILMethod_IsSynchronized(method))
	{
		/* Exit the sync lock before throwing to the calling method */
		isStatic = ILMethod_IsStatic(method);
		PUSH_SYNC_OBJECT();
		ILCoderCallInlineable(coder, IL_INLINEMETHOD_MONITOR_EXIT, 0);
	}

	ILCoderThrow(coder, 0);
	ILCoderTryHandlerEnd(coder);
}
		return 0;
	}
}

/*
 * Emit code to throw a system-level exception.
 */
static void _ThrowSystem(ILCoder *coder, ILMethod *method, int hasExceptions,
						 const char *name, const char *namespace)
{
	ILClass *classInfo;
	ILMethod *ctor;
	ILCoderMethodInfo callInfo;

	/* Find the no-argument constructor for the class */
	classInfo = ILClassResolveSystem(ILProgramItem_Image(method), 0,
								     name, namespace);
	if(!classInfo)
	{
		return;
	}
	ctor = 0;
	while((ctor = (ILMethod *)ILClassNextMemberByKind
			(classInfo, (ILMember *)ctor, IL_META_MEMBERKIND_METHOD)) != 0)
	{
		if(ILMethod_IsConstructor(ctor) &&
		   ILTypeNumParams(ILMethod_Signature(ctor)) == 0)
		{
			break;
		}
	}