/* * Convert a method reference type into a method block. * Returns NULL if not a method reference type. */ static ILMethod *MethodRefToMethod(ILType *type) { if(type != 0 && ILType_IsComplex(type) && ILType_Kind(type) == IL_TYPE_COMPLEX_METHOD_REF) { return (ILMethod *)(ILType_Ref(type)); } else { return 0; } }
/* * Determine if a type contains unsafe pointers. */ static IL_INLINE int IsUnsafeType(ILType *type) { if(!type || !ILType_IsComplex(type)) { return 0; } else if(ILType_Kind(type) == IL_TYPE_COMPLEX_PTR) { return 1; } else { return 0; } }
ILProgramItem *ILProgramItemFromType(ILImage *image, ILType *type) { if(!type) { return 0; } if(ILType_IsComplex(type)) { switch(ILType_Kind(type)) { case IL_TYPE_COMPLEX_WITH: case IL_TYPE_COMPLEX_ARRAY: case IL_TYPE_COMPLEX_ARRAY_CONTINUE: case IL_TYPE_COMPLEX_PTR: case IL_TYPE_COMPLEX_METHOD: case (IL_TYPE_COMPLEX_METHOD | IL_TYPE_COMPLEX_METHOD_SENTINEL): { ILTypeSpec *spec; spec = ILTypeSpecCreate(image, 0, type); return ILToProgramItem(spec); } } } else { ILClass *info; info = ILClassFromType(image, 0, type, 0); if(info) { info = ILClassImport(image, info); } return ILToProgramItem(info); } return 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; } }
/* * Convert a type into an engine type. */ static ILEngineType TypeToEngineType(ILType *type) { type = ILTypeGetEnumType(type); if(ILType_IsPrimitive(type)) { switch(ILType_ToElement(type)) { case IL_META_ELEMTYPE_BOOLEAN: case IL_META_ELEMTYPE_I1: case IL_META_ELEMTYPE_U1: case IL_META_ELEMTYPE_I2: case IL_META_ELEMTYPE_U2: case IL_META_ELEMTYPE_CHAR: case IL_META_ELEMTYPE_I4: case IL_META_ELEMTYPE_U4: return ILEngineType_I4; case IL_META_ELEMTYPE_I8: case IL_META_ELEMTYPE_U8: return ILEngineType_I8; case IL_META_ELEMTYPE_I: case IL_META_ELEMTYPE_U: return ILEngineType_I; case IL_META_ELEMTYPE_R4: case IL_META_ELEMTYPE_R8: case IL_META_ELEMTYPE_R: return ILEngineType_F; case IL_META_ELEMTYPE_TYPEDBYREF: return ILEngineType_TypedRef; } return ILEngineType_I4; } else if(ILType_IsValueType(type)) { return ILEngineType_MV; } else if(ILType_IsComplex(type) && type != 0) { switch(ILType_Kind(type)) { case IL_TYPE_COMPLEX_PTR: { /* Unsafe pointers are represented as native integers */ return ILEngineType_I; } /* Not reached */ case IL_TYPE_COMPLEX_BYREF: { /* Reference values are managed pointers */ return ILEngineType_M; } /* Not reached */ case IL_TYPE_COMPLEX_PINNED: { /* Pinned types are the same as their underlying type */ return TypeToEngineType(ILType_Ref(type)); } /* Not reached */ case IL_TYPE_COMPLEX_CMOD_REQD: case IL_TYPE_COMPLEX_CMOD_OPT: { /* Strip the modifier and inspect the underlying type */ return TypeToEngineType(type->un.modifier__.type__); } /* Not reached */ case IL_TYPE_COMPLEX_METHOD: case IL_TYPE_COMPLEX_METHOD | IL_TYPE_COMPLEX_METHOD_SENTINEL: { /* Pass method pointers around the system as "I". Higher level code will also set the "typeInfo" field to reflect the signature so that method pointers become verifiable */ return ILEngineType_I; } /* Not reached */ } } return ILEngineType_O; }
/* * Get type size information. */ static void GetTypeSize(ILSizeInfo *info, ILType *type) { unsigned long num; unsigned long posn; /* Only complex types have a non-zero memory size */ if(type == 0 || !ILType_IsComplex(type)) { return; } /* Account for the size of the complex type header */ info->loadedMeta += sizeof(ILType); /* Account for element information */ switch(ILType_Kind(type)) { case IL_TYPE_COMPLEX_BYREF: case IL_TYPE_COMPLEX_PTR: case IL_TYPE_COMPLEX_PINNED: { GetTypeSize(info, ILType_Ref(type)); } break; case IL_TYPE_COMPLEX_ARRAY: case IL_TYPE_COMPLEX_ARRAY_CONTINUE: { GetTypeSize(info, ILType_ElemType(type)); } break; case IL_TYPE_COMPLEX_CMOD_REQD: case IL_TYPE_COMPLEX_CMOD_OPT: { GetTypeSize(info, type->un.modifier__.type__); } break; case IL_TYPE_COMPLEX_LOCALS: { num = ILTypeNumLocals(type); for(posn = 0; posn < num; ++posn) { GetTypeSize(info, ILTypeGetLocalWithPrefixes(type, posn)); } } break; case IL_TYPE_COMPLEX_WITH: { num = ILTypeNumWithParams(type); GetTypeSize(info, ILTypeGetWithMainWithPrefixes(type)); for(posn = 1; posn <= num; ++posn) { GetTypeSize(info, ILTypeGetWithParamWithPrefixes(type, posn)); } } break; case IL_TYPE_COMPLEX_PROPERTY: case IL_TYPE_COMPLEX_METHOD: case IL_TYPE_COMPLEX_METHOD | IL_TYPE_COMPLEX_METHOD_SENTINEL: { num = ILTypeNumParams(type); GetTypeSize(info, ILTypeGetReturnWithPrefixes(type)); for(posn = 1; posn <= num; ++posn) { GetTypeSize(info, ILTypeGetParamWithPrefixes(type, posn)); } } break; } }
/* * Pack the parameters for a delegate closure call onto the CVM stack. */ static int PackDelegateParams(ILExecThread *thread, ILMethod *method, int isCtor, void *_this, void *userData) { void **args = ((PackDelegateUserData *)userData)->args; ILMethod *pinvokeInfo = ((PackDelegateUserData *)userData)->pinvokeInfo; ILType *signature = ILMethod_Signature(method); CVMWord *stacktop, *stacklimit; ILUInt32 param, numParams; ILType *paramType; void *ptr; ILUInt32 size, sizeInWords; ILNativeFloat tempFloat; ILUInt32 marshalType; char *customName; int customNameLen; char *customCookie; int customCookieLen; char *strValue; /* Get the top and extent of the stack */ stacktop = thread->stackTop; stacklimit = thread->stackLimit; /* Push the arguments onto the evaluation stack */ if(ILType_HasThis(signature)) { /* Push the "this" argument */ CHECK_SPACE(1); if(((PackDelegateUserData *)userData)->needThis) { /* We get the "this" value from the incoming arguments */ stacktop->ptrValue = *((void **)(*args)); ++args; } else { /* We get the "this" value from the delegate object */ stacktop->ptrValue = _this; } ++stacktop; } numParams = ILTypeNumParams(signature); for(param = 1; param <= numParams; ++param) { /* Marshal parameters that need special handling */ marshalType = ILPInvokeGetMarshalType(0, pinvokeInfo, param, &customName, &customNameLen, &customCookie, &customCookieLen, ILTypeGetParam(signature, param)); if(marshalType != IL_META_MARSHAL_DIRECT) { switch(marshalType) { case IL_META_MARSHAL_ANSI_STRING: { /* Marshal an ANSI string from the native world */ CHECK_SPACE(1); strValue = *((char **)(*args)); if(strValue) { stacktop->ptrValue = ILStringCreate(thread, strValue); /* Free the native string */ ILFreeNativeString(strValue); if(!(stacktop->ptrValue)) { return 1; } } else { stacktop->ptrValue = 0; } ++args; ++stacktop; } continue; case IL_META_MARSHAL_UTF8_STRING: { /* Marshal a UTF-8 string from the native world */ CHECK_SPACE(1); strValue = *((char **)(*args)); if(strValue) { stacktop->ptrValue = ILStringCreateUTF8(thread, strValue); /* Free the native string */ ILFreeNativeString(strValue); if(!(stacktop->ptrValue)) { return 1; } } else { stacktop->ptrValue = 0; } ++args; ++stacktop; } continue; case IL_META_MARSHAL_UTF16_STRING: { /* Marshal a UTF-16 string from the native world */ CHECK_SPACE(1); strValue = *((char **)(*args)); if(strValue) { stacktop->ptrValue = ILStringWCreate(thread, (ILUInt16 *)strValue); /* Free the native string */ ILFreeNativeString(strValue); if(!(stacktop->ptrValue)) { return 1; } } else { stacktop->ptrValue = 0; } ++args; ++stacktop; } continue; case IL_META_MARSHAL_CUSTOM: { /* Marshal a custom value from the native world */ CHECK_SPACE(1); stacktop->ptrValue = _ILCustomToObject (thread, *((void **)(*args)), customName, customNameLen, customCookie, customCookieLen); if(_ILExecThreadHasException(thread)) { return 1; } ++args; ++stacktop; } continue; } } /* Marshal the parameter directly */ paramType = ILTypeGetEnumType(ILTypeGetParam(signature, param)); if(ILType_IsPrimitive(paramType)) { /* Process a primitive value */ switch(ILType_ToElement(paramType)) { case IL_META_ELEMTYPE_VOID: break; case IL_META_ELEMTYPE_BOOLEAN: case IL_META_ELEMTYPE_I1: case IL_META_ELEMTYPE_U1: case IL_META_ELEMTYPE_I2: case IL_META_ELEMTYPE_U2: case IL_META_ELEMTYPE_CHAR: case IL_META_ELEMTYPE_I4: case IL_META_ELEMTYPE_U4: #ifdef IL_NATIVE_INT32 case IL_META_ELEMTYPE_I: case IL_META_ELEMTYPE_U: #endif { CHECK_SPACE(1); stacktop->intValue = *((ILInt32 *)(*args)); ++args; ++stacktop; } break; case IL_META_ELEMTYPE_I8: case IL_META_ELEMTYPE_U8: #ifdef IL_NATIVE_INT64 case IL_META_ELEMTYPE_I: case IL_META_ELEMTYPE_U: #endif { CHECK_SPACE(CVM_WORDS_PER_LONG); ILMemCpy(stacktop, *args, sizeof(ILInt64)); ++args; stacktop += CVM_WORDS_PER_LONG; } break; case IL_META_ELEMTYPE_R4: { CHECK_SPACE(CVM_WORDS_PER_NATIVE_FLOAT); tempFloat = (ILNativeFloat)(*((ILFloat *)(*args))); ILMemCpy(stacktop, &tempFloat, sizeof(ILNativeFloat)); ++args; stacktop += CVM_WORDS_PER_NATIVE_FLOAT; } break; case IL_META_ELEMTYPE_R8: { CHECK_SPACE(CVM_WORDS_PER_NATIVE_FLOAT); tempFloat = (ILNativeFloat)(*((ILDouble *)(*args))); ILMemCpy(stacktop, &tempFloat, sizeof(ILNativeFloat)); ++args; stacktop += CVM_WORDS_PER_NATIVE_FLOAT; } break; case IL_META_ELEMTYPE_R: { CHECK_SPACE(CVM_WORDS_PER_NATIVE_FLOAT); ILMemCpy(stacktop, *args, sizeof(ILNativeFloat)); ++args; stacktop += CVM_WORDS_PER_NATIVE_FLOAT; } break; case IL_META_ELEMTYPE_TYPEDBYREF: { CHECK_SPACE(CVM_WORDS_PER_TYPED_REF); ILMemCpy(stacktop, *args, sizeof(ILTypedRef)); ++args; stacktop += CVM_WORDS_PER_TYPED_REF; } break; } } else if(ILType_IsClass(paramType)) { /* Process an object reference */ CHECK_SPACE(1); stacktop->ptrValue = *((void **)(*args)); ++args; ++stacktop; } else if(ILType_IsValueType(paramType)) { /* Process a value type which was passed by value */ ptr = *args; ++args; size = ILSizeOfType(thread, paramType); sizeInWords = ((size + sizeof(CVMWord) - 1) / sizeof(CVMWord)); CHECK_SPACE(sizeInWords); ILMemCpy(stacktop, ptr, size); stacktop += sizeInWords; } else if(paramType != 0 && ILType_IsComplex(paramType) && (ILType_Kind(paramType) == IL_TYPE_COMPLEX_BYREF || ILType_Kind(paramType) == IL_TYPE_COMPLEX_PTR)) { /* Process a value that is being passed by reference */ CHECK_SPACE(1); stacktop->ptrValue = *((void **)(*args)); ++args; ++stacktop; } else { /* Assume that everything else is an object reference */ CHECK_SPACE(1); stacktop->ptrValue = *args; ++args; ++stacktop; } } /* Update the stack top */ thread->stackTop = stacktop; return 0; }
ILUInt32 ILPInvokeGetMarshalType(ILPInvoke *pinvoke, ILMethod *method, unsigned long param, char **customName, int *customNameLen, char **customCookie, int *customCookieLen, ILType *type) { ILParameter *parameter; ILFieldMarshal *marshal; const unsigned char *nativeType; unsigned long nativeTypeLen; int nativeTypeCode; /* Find the parameter information block */ if(method) { if(!(method->parameters)) { _ILMethodLoadParams(method); } parameter = method->parameters; while(parameter != 0 && parameter->paramNum != param) { parameter = parameter->next; } } else { parameter = 0; } /* See if we have native type information for the parameter */ nativeType = 0; nativeTypeLen = 0; nativeTypeCode = IL_META_NATIVETYPE_END; if(parameter != 0) { marshal = ILFieldMarshalGetFromOwner(&(parameter->programItem)); if(marshal != 0) { nativeType = (const unsigned char *) ILFieldMarshalGetType(marshal, &nativeTypeLen); if(nativeTypeLen > 0) { nativeTypeCode = (int)(nativeType[0]); } } } /* Initialize the custom name return information to nothing */ *customName = 0; *customNameLen = 0; *customCookie = 0; *customCookieLen = 0; /* If the native type is "interface", then always marshal directly. This is normally used to force strings, delegates, and arrays to be passed as objects */ if(nativeTypeCode == IL_META_NATIVETYPE_INTF) { return IL_META_MARSHAL_DIRECT; } /* Check for custom marshalling */ if(nativeTypeCode == IL_META_NATIVETYPE_CUSTOMMARSHALER && ILTypeIsReference(type)) { ILMetaDataRead reader; reader.data = nativeType + 1; reader.len = nativeTypeLen - 1; reader.error = 0; ExtractCustomString(customName, customNameLen); /* Unused GUID */ ExtractCustomString(customName, customNameLen); /* Unused native name */ ExtractCustomString(customName, customNameLen); ExtractCustomString(customCookie, customCookieLen); if(*customNameLen > 0) { return IL_META_MARSHAL_CUSTOM; } else { return IL_META_MARSHAL_DIRECT; } } /* Determine what to do based on the parameter type */ if(ILTypeIsStringClass(type)) { /* Value string type */ if(nativeTypeCode == IL_META_NATIVETYPE_LPWSTR) { #ifdef IL_WIN32_PLATFORM return IL_META_MARSHAL_UTF16_STRING; #else return IL_META_MARSHAL_UTF8_STRING; #endif } else if(nativeTypeCode == IL_META_NATIVETYPE_LPSTR) { return IL_META_MARSHAL_ANSI_STRING; } else { return ILPInvokeGetCharSet(pinvoke, method); } } else if(ILTypeIsDelegateSubClass(type)) { /* Delegate type */ return IL_META_MARSHAL_FNPTR; } else if(ILType_IsSimpleArray(type)) { if(ILTypeIsStringClass(ILTypeGetElemType(type))) { /* Array of strings, passed as "char **" */ switch(ILPInvokeGetCharSet(pinvoke, method)) { case IL_META_MARSHAL_UTF8_STRING: { return IL_META_MARSHAL_UTF8_ARRAY; } /* not reached */ case IL_META_MARSHAL_UTF16_STRING: { return IL_META_MARSHAL_UTF16_ARRAY; } /* not reached */ default: { return IL_META_MARSHAL_ANSI_ARRAY; } /* not reached */ } } else { /* Array type, passed in by pointer to the first element */ return IL_META_MARSHAL_ARRAY; } } else if(type != 0 && ILType_IsComplex(type) && ILType_Kind(type) == IL_TYPE_COMPLEX_BYREF) { /* Check for "ref String[]", which is used by Gtk# when calling the "gtk_init" function */ if(ILType_IsSimpleArray(ILType_Ref(type)) && ILTypeIsStringClass(ILTypeGetElemType(ILType_Ref(type)))) { switch(ILPInvokeGetCharSet(pinvoke, method)) { case IL_META_MARSHAL_UTF8_STRING: { return IL_META_MARSHAL_REF_UTF8_ARRAY; } /* not reached */ case IL_META_MARSHAL_UTF16_STRING: { return IL_META_MARSHAL_REF_UTF16_ARRAY; } /* not reached */ default: { return IL_META_MARSHAL_REF_ANSI_ARRAY; } /* not reached */ } return IL_META_MARSHAL_REF_ANSI_ARRAY; } } /* Marshal the parameter directly */ return IL_META_MARSHAL_DIRECT; }