/*
 * Print a verification error.
 */
static void printError(ILImage *image, ILMethod *method, const char *msg)
{
#ifndef IL_WITHOUT_TOOLS
	ILDumpMethodType(stdout, image,
					 ILMethod_Signature(method), 0,
					 ILMethod_Owner(method),
					 ILMethod_Name(method),
					 method);
#else
	fputs(ILClass_Name(ILMethod_Owner(method)), stdout);
	fputs(".", stdout);
	fputs(ILMethod_Name(method), stdout);
#endif
	fputs(" - ", stdout);
	fputs(msg, stdout);
	putc('\n', stdout);
}
Beispiel #2
0
/*
 * Inline function to get the character at the specified indexe in a
 * string.
 */
static int _ILJitSystemStringChars(ILJITCoder *jitCoder,
								   ILMethod *method,
								   ILCoderMethodInfo *methodInfo,
								   ILJitStackItem *args,
								   ILInt32 numArgs)
{
	ILJitFunction jitFunction = ILJitFunctionFromILMethod(method);
	ILClass *stringClass = ILMethod_Owner(method);
	ILJitValue length;
	ILJitValue stringBase;
	ILJitValue returnValue;

	if(!jitFunction)
	{
		/* We need to layout the class first. */
		if(!_LayoutClass(ILExecThreadCurrent(), stringClass))
		{
			return 0;
		}
		if(!(jitFunction = ILJitFunctionFromILMethod(method)))
		{
			return 0;
		}
	}

#if !defined(IL_CONFIG_REDUCE_CODE) && !defined(IL_WITHOUT_TOOLS) && defined(_IL_JIT_ENABLE_DEBUG)
	if(jitCoder->flags & IL_CODER_FLAG_STATS)
	{
		ILMutexLock(globalTraceMutex);
		fprintf(stdout, "Inline System.String::get_Chars\n");
		ILMutexUnlock(globalTraceMutex);
	}
#endif

	_ILJitStackItemCheckNull(jitCoder, args[0]);
	length = _ILJitStringGetLength(jitCoder->jitFunction,
								   _ILJitStackItemValue(args[0]));
	JITC_START_CHECK_STRING_INDEX(jitCoder, length, _ILJitStackItemValue(args[1]))
	stringBase = _ILJitStringGetStart(jitCoder->jitFunction,
									  _ILJitStackItemValue(args[0]));
	returnValue = jit_insn_load_elem(jitCoder->jitFunction,
									 stringBase,
									 _ILJitStackItemValue(args[1]),
									 _IL_JIT_TYPE_CHAR);
	JITC_END_CHECK_STRING_INDEX(jitCoder)

	_ILJitStackPushValue(jitCoder, returnValue);
	return 1;
}
static void CVMCoder_CallInterface(ILCoder *coder, ILCoderMethodInfo *info,
								   ILEngineStackItem *returnItem,
								   ILMethod *methodInfo)
{
	ILUInt32 argSize = ComputeStackSize(coder, info->args, info->numBaseArgs);
	if(info->hasParamArray)
	{
		++argSize;
	}
#ifdef IL_USE_IMTS
	{
		ILUInt32 index = methodInfo->index;
		ILClassPrivate *classPrivate;
		classPrivate = (ILClassPrivate *)(methodInfo->member.owner->userData);
		if(classPrivate)
		{
			index += classPrivate->imtBase;
		}
		index %= IL_IMT_SIZE;
		if(info->tailCall)
		{
			CVMP_OUT_WORD2_PTR(COP_PREFIX_TAIL_CALLINTF, argSize,
							   index, methodInfo);
		}
		else
		{
			CVM_OUT_DWIDE_PTR(COP_CALL_INTERFACE, argSize,
							  index, methodInfo);
		}
	}
#else
	{
		void *ptr = ILMethod_Owner(methodInfo);
		if(info->tailCall)
		{
			CVMP_OUT_WORD2_PTR(COP_PREFIX_TAIL_CALLINTF, argSize,
							   methodInfo->index, ptr);
		}
		else
		{
			CVM_OUT_DWIDE_PTR(COP_CALL_INTERFACE, argSize,
							  methodInfo->index, ptr);
		}
	}
#endif
	AdjustForCall(coder, info, returnItem);
}
Beispiel #4
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;
}
Beispiel #5
0
void ILDAsmDumpJavaMethod(ILImage *image, FILE *outstream,
					      ILMethod *method, int flags)
{
	unsigned long addr;
	ILMethodCode code;
	ILException *clauses;
	ILException *tempClause;
	ILClass *catchClass;

	/* Read the method code and exception information */
	if(!ILMethodGetCode(method, &code))
	{
		/* If we get here, then probably the method had an RVA,
		   but the code was not IL */
		fputs("\t\t// Cannot dump the code for native methods\n", outstream);
		return;
	}
	if(!ILMethodGetExceptions(method, &code, &clauses))
	{
		return;
	}

	/* Determine the address of the first instruction in the method */
	addr = ILMethod_RVA(method);
	if((flags & ILDASM_REAL_OFFSETS) != 0)
	{
		addr = ILImageRealOffset(image, addr) + code.headerSize;
	}
	else
	{
		addr += code.headerSize;
	}

	/* Output method header information */
	fprintf(outstream, "\t\t// Start of method header: %lx\n",
			(unsigned long)(addr - code.headerSize));
	fprintf(outstream, "\t\t.maxstack  %lu\n", (unsigned long)(code.maxStack));
	fprintf(outstream, "\t\t.locals  %lu\n", (unsigned long)(code.javaLocals));

	/* Dump the instructions within the method */
	if(!DumpJavaInstructions(image, ILMethod_Owner(method),
							 outstream, (unsigned char *)(code.code),
						     code.codeLen, addr, clauses, flags))
	{
		ILMethodFreeExceptions(clauses);
		return;
	}

	/* Dump information about the exceptions */
	tempClause = clauses;
	while(tempClause != 0)
	{
		fprintf(outstream, "\t\t.try ?L%lx to ?L%lx",
				tempClause->tryOffset + addr,
				tempClause->tryOffset + tempClause->tryLength + addr);
		if((tempClause->flags & IL_META_EXCEPTION_FINALLY) != 0)
		{
			/* Finally clause */
			fprintf(outstream, " finally");
		}
		else
		{
			/* Catch clause */
			fputs(" catch ", outstream);
			catchClass = ILClass_FromToken(image, tempClause->extraArg);
			if(catchClass)
			{
				ILDumpClassName(outstream, image, catchClass, flags);
			}
			else
			{
				fputs("??", outstream);
			}
		}
		fprintf(outstream, " handler ?L%lx\n",
				tempClause->handlerOffset + addr);
		tempClause = tempClause->next;
	}

	/* Free the exception list and exit */
	ILMethodFreeExceptions(clauses);
}
Beispiel #6
0
/*
 * Dump all Java instructions in a given buffer.  Returns zero
 * if there is something wrong with the buffer's format.
 */
static int DumpJavaInstructions(ILImage *image, ILClass *classInfo,
							    FILE *outstream,
								unsigned char *buf, unsigned long size,
							    unsigned long addr, ILException *clauses,
							    int flags)
{
	ILUInt32 *jumpPoints;
	int result = 0;
	unsigned char *temp;
	unsigned char *temp2;
	unsigned long tsize;
	unsigned long offset;
	unsigned long dest;
	unsigned long isize;
	unsigned long args;
	const ILOpcodeInfo *info;
	int argType;
	unsigned long numItems;
	unsigned long item;
	int isWide;

	/* Allocate a helper array to mark jump points within the code */
	jumpPoints = (ILUInt32 *)ILCalloc(((size + 3) & ~3), 1);
	if(!jumpPoints)
	{
		fprintf(stderr, "out of memory\n");
		exit(1);
	}

	/* Mark the entry point to the method so we get a label for it */
	jumpPoints[0] |= (ILUInt32)1;

	/* Mark the position of exception clauses */
	while(clauses != 0)
	{
		MarkDest(clauses->tryOffset);
		MarkDest(clauses->tryOffset + clauses->tryLength);
		MarkDest(clauses->handlerOffset);
		clauses = clauses->next;
	}

	/* Scan the instruction list to locate jump points */
	temp = buf;
	tsize = size;
	offset = 0;
	while(tsize > 0)
	{
		isize = JavaInsnSize(temp, tsize, offset);
		if(!isize)
		{
			fprintf(outstream, "\t\t// unknown instruction 0x%02X\n",
					((int)(temp[0])) & 0xFF);
			goto cleanup;
		}
		info = &(ILJavaOpcodeTable[((int)(temp[0])) & 0xFF]);
		if(info->args == IL_OPCODE_ARGS_SHORT_JUMP)
		{
			dest = (unsigned long)(((long)offset) +
								   (long)(IL_BREAD_INT16(temp + 1)));
			MarkDest(dest);
		}
		else if(info->args == IL_OPCODE_ARGS_LONG_JUMP)
		{
			dest = (unsigned long)(((long)offset) +
								   (long)(IL_BREAD_INT32(temp + 1)));
			MarkDest(dest);
		}
		else if(info->args == IL_OPCODE_ARGS_SWITCH)
		{
			/* Align the switch instruction's arguments */
			args = 1;
			while(((offset + args) & 3) != 0)
			{
				++args;
			}

			/* Mark the default label */
			dest = (unsigned long)(((long)offset) +
								   (long)(IL_BREAD_INT32(temp + args)));
			MarkDest(dest);

			/* Process the bulk of the switch */
			if(temp[0] == JAVA_OP_TABLESWITCH)
			{
				/* Mark all of the labels in a table-based switch */
				item = (unsigned long)(IL_BREAD_INT32(temp + args + 8) -
									   IL_BREAD_INT32(temp + args + 4) + 1);
				temp2 = temp + args + 12;
				while(item > 0)
				{
					dest = (unsigned long)(((long)offset) +
										   (long)(IL_BREAD_INT32(temp2)));
					MarkDest(dest);
					--item;
					temp2 += 4;
				}
			}
			else
			{
				/* Mark all of the labels in a lookup-based switch */
				item = (unsigned long)(IL_BREAD_UINT32(temp + args + 4));
				temp2 = temp + args + 8 + 4;
				while(item > 0)
				{
					dest = (unsigned long)(((long)offset) +
										   (long)(IL_BREAD_INT32(temp2)));
					MarkDest(dest);
					--item;
					temp2 += 8;
				}
			}
		}
		offset += isize;
		temp += isize;
		tsize -= isize;
	}

	/* Dump the instructions */
	temp = buf;
	tsize = size;
	offset = 0;
	while(tsize > 0)
	{
		/* If this is a jump point, then print a label for it */
		if((jumpPoints[offset / 32] & (ILUInt32)(1L << (offset % 32))) != 0)
		{
			fprintf(outstream, "\t?L%lx:\n", offset + addr);
		}

		/* Extract the instruction from the method input stream */
		isize = JavaInsnSize(temp, tsize, offset);
		info = &(ILJavaOpcodeTable[((int)(temp[0])) & 0xFF]);
		if(*temp == JAVA_OP_WIDE)
		{
			/* Process a wide instruction */
			info = &(ILJavaOpcodeTable[((int)(temp[1])) & 0xFF]);
			isWide = 1;
			args = 2;
		}
		else
		{
			/* Process an ordinary instruction */
			isWide = 0;
			args = 1;
		}

		/* Dump the instruction based on its argument type */
		argType = info->args;
		putc('\t', outstream);
		putc('\t', outstream);
		fputs(info->name, outstream);
		if(argType != IL_OPCODE_ARGS_INVALID &&
		   argType != IL_OPCODE_ARGS_NONE)
		{
			numItems = (unsigned long)(strlen(info->name));
			while(numItems < 10)
			{
				putc(' ', outstream);
				++numItems;
			}
			putc(' ', outstream);
		}
		switch(argType)
		{
			case IL_OPCODE_ARGS_INVALID:	break;
			case IL_OPCODE_ARGS_NONE:		break;

			case IL_OPCODE_ARGS_INT8:
			{
				fprintf(outstream, "%d", (int)(ILInt8)(temp[args]));
			}
			break;

			case IL_OPCODE_ARGS_INT16:
			{
				fprintf(outstream, "%d",
				        (int)(ILInt16)(IL_BREAD_UINT16(temp + args)));
			}
			break;

			case IL_OPCODE_ARGS_TOKEN:
			case IL_OPCODE_ARGS_CALL:
			{
				/* An instruction that takes a constant pool entry argument */
				if(temp[0] == JAVA_OP_LDC)
				{
					item = (unsigned long)(temp[args]);
				}
				else
				{
					item = (unsigned long)(IL_BREAD_UINT16(temp + args));
				}
				switch(ILJavaGetConstType(classInfo, (ILUInt32)item))
				{
					case JAVA_CONST_UTF8:
					{
						const char *str;
						ILUInt32 len;
						str = ILJavaGetUTF8String
							(classInfo, (ILUInt32)item, &len);
						if(str && len)
						{
							ILDumpStringLen(outstream, str, (int)len);
						}
						else
						{
							fputs("\"\"", outstream);
						}
					}
					break;

					case JAVA_CONST_INTEGER:
					{
						ILInt32 value;
						if(ILJavaGetInteger(classInfo, (ILUInt32)item, &value))
						{
							fprintf(outstream, "%ld", (long)value);
						}
						else
						{
							fputs("??", outstream);
						}
					}
					break;

					case JAVA_CONST_FLOAT:
					{
						ILFloat value;
						unsigned char buf[4];
						if(ILJavaGetFloat(classInfo, (ILUInt32)item, &value))
						{
							IL_WRITE_FLOAT(buf, value);
							fprintf(outstream, "float32(0x%02X%02X%02X%02X)",
									(((int)(buf[3])) & 0xFF),
									(((int)(buf[2])) & 0xFF),
									(((int)(buf[1])) & 0xFF),
									(((int)(buf[0])) & 0xFF));
						}
						else
						{
							fputs("??", outstream);
						}
					}
					break;

					case JAVA_CONST_LONG:
					{
						ILInt64 value;
						if(ILJavaGetLong(classInfo, (ILUInt32)item, &value))
						{
							fprintf(outstream, "0x%08lX%08lX",
									(long)((value >> 32) & (long)0xFFFFFFFF),
									(long)(value & (long)0xFFFFFFFF));
						}
						else
						{
							fputs("??", outstream);
						}
					}
					break;

					case JAVA_CONST_DOUBLE:
					{
						ILDouble value;
						unsigned char buf[8];
						if(ILJavaGetDouble(classInfo, (ILUInt32)item, &value))
						{
							IL_WRITE_DOUBLE(buf, value);
							fprintf(outstream,
								"float64(0x%02X%02X%02X%02X%02X%02X%02X%02X)",
								(((int)(buf[7])) & 0xFF),
								(((int)(buf[6])) & 0xFF),
								(((int)(buf[5])) & 0xFF),
								(((int)(buf[4])) & 0xFF),
								(((int)(buf[3])) & 0xFF),
								(((int)(buf[2])) & 0xFF),
								(((int)(buf[1])) & 0xFF),
								(((int)(buf[0])) & 0xFF));
						}
						else
						{
							fputs("??", outstream);
						}
					}
					break;

					case JAVA_CONST_CLASS:
					{
						ILClass *ref;
						ref = ILJavaGetClass(classInfo, (ILUInt32)item, 1);
						if(ref)
						{
							ILDumpClassName(outstream, image, ref, flags);
						}
						else
						{
							fputs("??", outstream);
						}
					}
					break;

					case JAVA_CONST_STRING:
					{
						const char *str;
						ILUInt32 len;
						str = ILJavaGetString(classInfo, (ILUInt32)item, &len);
						if(str && len)
						{
							ILDumpStringLen(outstream, str, (int)len);
						}
						else
						{
							fputs("\"\"", outstream);
						}
					}
					break;

					case JAVA_CONST_FIELDREF:
					{
						ILField *field;
						ILClass *info;
						field = ILJavaGetField(classInfo, (ILUInt32)item, 1,
									(temp[0] == JAVA_OP_GETSTATIC ||
									 temp[0] == JAVA_OP_PUTSTATIC));
						if(field)
						{
							ILDumpType(outstream, image,
									   ILField_Type(field), flags);
							putc(' ', outstream);
							info = ILField_Owner(field);
							if(ILClassIsValueType(info))
							{
								fputs("valuetype ", outstream);
							}
							else
							{
								fputs("class ", outstream);
							}
							ILDumpClassName(outstream, image, info, flags);
							fputs("::", outstream);
							ILDumpIdentifier(outstream,
											 ILField_Name(field), 0, flags);
						}
						else
						{
							fputs("??", outstream);
						}
					}
					break;

					case JAVA_CONST_METHODREF:
					{
						ILMethod *method;
						method = ILJavaGetMethod(classInfo, (ILUInt32)item, 1,
									(temp[0] == JAVA_OP_INVOKESTATIC));
						if(method)
						{
							ILDumpMethodType(outstream, image,
											 ILMethod_Signature(method), flags,
											 ILMethod_Owner(method),
											 ILMethod_Name(method),
											 method);
						}
						else
						{
							fputs("??", outstream);
						}
					}
					break;

					default:
					{
						fputs("??", outstream);
					}
					break;
				}
			}
			break;

			case IL_OPCODE_ARGS_NEW:
			{
				/* "newarray" instruction */
				switch(temp[args])
				{
					case JAVA_ARRAY_OF_BOOL:
					{
						fputs("bool", outstream);
					}
					break;

					case JAVA_ARRAY_OF_CHAR:
					{
						fputs("char", outstream);
					}
					break;

					case JAVA_ARRAY_OF_FLOAT:
					{
						fputs("float32", outstream);
					}
					break;

					case JAVA_ARRAY_OF_DOUBLE:
					{
						fputs("float64", outstream);
					}
					break;

					case JAVA_ARRAY_OF_BYTE:
					{
						fputs("int8", outstream);
					}
					break;

					case JAVA_ARRAY_OF_SHORT:
					{
						fputs("int16", outstream);
					}
					break;

					case JAVA_ARRAY_OF_INT:
					{
						fputs("int32", outstream);
					}
					break;

					case JAVA_ARRAY_OF_LONG:
					{
						fputs("int64", outstream);
					}
					break;

					default:
					{
						fprintf(outstream, "%d", ((int)(temp[args])) & 0xFF);
					}
					break;
				}
			}
			break;

			case IL_OPCODE_ARGS_SHORT_VAR:
			{
				if(!isWide)
				{
					fprintf(outstream, "%d", ((int)(temp[args])) & 0xFF);
				}
				else
				{
					fprintf(outstream, "%d",
							((int)(IL_BREAD_UINT16(temp + args))));
				}
			}
			break;

			case IL_OPCODE_ARGS_SHORT_JUMP:
			{
				dest = (unsigned long)(((long)offset) +
								       (long)(IL_BREAD_INT16(temp + 1)));
				fprintf(outstream, "?L%lx", dest + addr);
			}
			break;

			case IL_OPCODE_ARGS_LONG_JUMP:
			{
				dest = (unsigned long)(((long)offset) +
									   (long)(IL_BREAD_UINT32(temp + 1)));
				fprintf(outstream, "?L%lx", dest + addr);
			}
			break;

			case IL_OPCODE_ARGS_CALLI:
			{
				/* Dump a call to an interface method */
				ILMethod *method;
				item = (unsigned long)(IL_BREAD_UINT16(temp + args));
				method = ILJavaGetMethod(classInfo, (ILUInt32)item, 1, 0);
				if(method)
				{
					ILDumpMethodType(outstream, image,
									 ILMethod_Signature(method), flags,
									 ILMethod_Owner(method),
									 ILMethod_Name(method),
									 method);
				}
				else
				{
					fputs("??", outstream);
				}
				fprintf(outstream, " %d", (int)(ILUInt8)(temp[args + 2]));
			}
			break;

			case IL_OPCODE_ARGS_SWITCH:
			{
				/* Align the switch instruction's arguments */
				while(((offset + args) & 3) != 0)
				{
					++args;
				}

				/* Output the default label */
				dest = (unsigned long)(((long)offset) +
									   (long)(IL_BREAD_INT32(temp + args)));
				fprintf(outstream, "?L%lx (", dest + addr);

				/* Dump the bulk of the switch instruction */
				if(temp[0] == JAVA_OP_TABLESWITCH)
				{
					/* Dump the base value for the table-based switch */
					fprintf(outstream, "%ld : ",
						    (long)(IL_BREAD_INT32(temp + args + 4)));

					/* Determine the number of items */
					numItems = (unsigned long)
							(IL_BREAD_INT32(temp + args + 8) -
							 IL_BREAD_INT32(temp + args + 4) + 1);

					/* Dump the labels for the items */
					temp2 = temp + args + 12;
					for(item = 0; item < numItems; ++item)
					{
						if(item != 0)
						{
							putc(',', outstream);
							putc(' ', outstream);
						}
						dest = (unsigned long)(((long)offset) +
									   		   (long)(IL_BREAD_INT32(temp2)));
						fprintf(outstream, "?L%lx", dest + addr);
						temp2 += 4;
					}
				}
				else
				{
					/* Lookup-based switch instruction */
					numItems = (unsigned long)
							(IL_BREAD_UINT32(temp + args + 4));
					temp2 = temp + args + 8;
					for(item = 0; item < numItems; ++item)
					{
						if(item != 0)
						{
							putc(',', outstream);
							putc(' ', outstream);
						}
						fprintf(outstream, "%ld : ",
								(long)(IL_BREAD_INT32(temp2)));
						dest = (unsigned long)(((long)offset) +
								   		   (long)(IL_BREAD_INT32(temp2 + 4)));
						fprintf(outstream, "?L%lx", dest + addr);
						temp2 += 8;
					}
				}

				/* Terminate the switch instruction */
				putc(')', outstream);
			}
			break;

			case IL_OPCODE_ARGS_ANN_ARG:
			{
				/* Used to indicate the "iinc" instruction */
				if(!isWide)
				{
					fprintf(outstream, "%d, %d",
							((int)(temp[args])) & 0xFF,
							((int)((ILInt8)(temp[args + 1]))));
				}
				else
				{
					fprintf(outstream, "%d, %d",
							((int)(IL_BREAD_UINT16(temp + args))),
							((int)(IL_BREAD_INT16(temp + args + 2))));
				}
			}
			break;

			default:	break;
		}
/*
 * 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;
}
Beispiel #8
0
void *_ILMakeCifForConstructor(ILExecProcess *process, ILMethod *method, int isInternal)
{
	ILType *signature = ILMethod_Signature(method);
	ILUInt32 numArgs;
	ILUInt32 numParams;
	ffi_cif *cif;
	ffi_type **args;
	ffi_type *rtype;
	ILUInt32 arg;
	ILUInt32 param;

	/* Determine the number of argument blocks that we need */
	numArgs = numParams = ILTypeNumParams(signature);
	if(isInternal)
	{
		/* This is an "internalcall" or "runtime" method
		   which needs an extra argument for the thread */
		++numArgs;
	}

	/* Allocate space for the cif */
	cif = (ffi_cif *)ILMalloc(sizeof(ffi_cif) +
							  sizeof(ffi_type *) * numArgs);
	if(!cif)
	{
		return 0;
	}
	args = ((ffi_type **)(cif + 1));

	/* The return value is always a pointer, indicating the object
	   that was just allocated by the constructor */
	rtype = &ffi_type_pointer;

	/* Convert the argument types */
	arg = 0;
	if(isInternal)
	{
		/* Pointer argument for the thread */
		args[arg++] = &ffi_type_pointer;
	}
	for(param = 1; param <= numParams; ++param)
	{
		args[arg++] = TypeToFFI(process, ILTypeGetEnumType
									(ILTypeGetParam(signature, param)),
							    isInternal);
	}

	/* Limit the number of arguments if we cannot use raw mode */
	if(!_ILCVMCanUseRawCalls(method, isInternal) &&
	   numArgs > (CVM_MAX_NATIVE_ARGS + 1))
	{
		numArgs = CVM_MAX_NATIVE_ARGS + 1;
	}

	/* Prepare the "ffi_cif" structure for the call */
	if(ffi_prep_cif(cif, FFI_DEFAULT_ABI, numArgs, rtype, args) != FFI_OK)
	{
		fprintf(stderr, "Cannot marshal a type in the definition of %s::%s\n",
				ILClass_Name(ILMethod_Owner(method)), ILMethod_Name(method));
		return 0;
	}

	/* Ready to go */
	return (void *)cif;
}
Beispiel #9
0
/*
 * Inline function to create a new string with the given length 
 */
static int _ILJitSystemStringNew(ILJITCoder *jitCoder,
								 ILMethod *method,
								 ILCoderMethodInfo *methodInfo,
								 ILJitStackItem *args,
								 ILInt32 numArgs)
{
	ILJitFunction jitFunction = ILJitFunctionFromILMethod(method);
	ILClass *stringClass = ILMethod_Owner(method);
	ILJitValue newString;
	ILJitValue callArgs[2];

	if(!jitFunction)
	{
		/* We need to layout the class first. */
		if(!_LayoutClass(ILExecThreadCurrent(), stringClass))
		{
			return 0;
		}
		if(!(jitFunction = ILJitFunctionFromILMethod(method)))
		{
			return 0;
		}
	}

#if !defined(IL_CONFIG_REDUCE_CODE) && !defined(IL_WITHOUT_TOOLS) && defined(_IL_JIT_ENABLE_DEBUG)
	if(jitCoder->flags & IL_CODER_FLAG_STATS)
	{
		ILMutexLock(globalTraceMutex);
		fprintf(stdout, "Inline System.String::NewString\n");
		ILMutexUnlock(globalTraceMutex);
	}
#endif

	/* We call the alloc functions. */
	/* They thow an out of memory exception so we don't need to care. */
	callArgs[0] = jit_value_create_nint_constant(jitCoder->jitFunction,
												 _IL_JIT_TYPE_VPTR,
												 (jit_nint)stringClass);
	if(!callArgs[0])
	{
		return 0;
	}
	callArgs[1] = _ILJitValueConvertImplicit(jitCoder->jitFunction,
						 					 _ILJitStackItemValue(args[0]),
											 _IL_JIT_TYPE_UINT32);
	if(!callArgs[1])
	{
		return 0;
	}
	newString = jit_insn_call_native(jitCoder->jitFunction,
									 "_ILJitStringAlloc",
									 _ILJitStringAlloc,
									 _ILJitSignature_ILJitStringAlloc,
				 					 callArgs, 2, 0);
	if(!newString)
	{
		return 0;
	}

	_ILJitStackPushValue(jitCoder, newString);
	return 1;
}