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; }
/* * 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; }