bool isArrayElement = false)
{
TypeSystemContext context = type.Context;
- NativeTypeKind nativeType = NativeTypeKind.Invalid;
+ NativeTypeKind nativeType = NativeTypeKind.Default;
if (marshalAs != null)
{
nativeType = isArrayElement ? marshalAs.ArraySubType : marshalAs.Type;
MarshallerType marshallerType,
out MarshallerKind elementMarshallerKind)
{
+ elementMarshallerKind = MarshallerKind.Invalid;
+
+ bool isByRef = false;
if (type.IsByRef)
{
+ isByRef = true;
+
type = type.GetParameterType();
+
+ // Compat note: CLR allows ref returning blittable structs for IJW
+ if (isReturn)
+ return MarshallerKind.Invalid;
}
TypeSystemContext context = type.Context;
- NativeTypeKind nativeType = NativeTypeKind.Invalid;
+ NativeTypeKind nativeType = NativeTypeKind.Default;
bool isField = marshallerType == MarshallerType.Field;
if (marshalAs != null)
- nativeType = (NativeTypeKind)marshalAs.Type;
-
-
- elementMarshallerKind = MarshallerKind.Invalid;
+ nativeType = marshalAs.Type;
//
// Determine MarshalerKind
case TypeFlags.Boolean:
switch (nativeType)
{
- case NativeTypeKind.Invalid:
+ case NativeTypeKind.Default:
case NativeTypeKind.Boolean:
return MarshallerKind.Bool;
case NativeTypeKind.U2:
return MarshallerKind.UnicodeChar;
- case NativeTypeKind.Invalid:
+ case NativeTypeKind.Default:
if (isAnsi)
return MarshallerKind.AnsiChar;
else
case TypeFlags.SByte:
case TypeFlags.Byte:
- if (nativeType == NativeTypeKind.I1 || nativeType == NativeTypeKind.U1 || nativeType == NativeTypeKind.Invalid)
+ if (nativeType == NativeTypeKind.I1 || nativeType == NativeTypeKind.U1 || nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableValue;
else
return MarshallerKind.Invalid;
case TypeFlags.Int16:
case TypeFlags.UInt16:
- if (nativeType == NativeTypeKind.I2 || nativeType == NativeTypeKind.U2 || nativeType == NativeTypeKind.Invalid)
+ if (nativeType == NativeTypeKind.I2 || nativeType == NativeTypeKind.U2 || nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableValue;
else
return MarshallerKind.Invalid;
case TypeFlags.Int32:
case TypeFlags.UInt32:
- if (nativeType == NativeTypeKind.I4 || nativeType == NativeTypeKind.U4 || nativeType == NativeTypeKind.Invalid)
+ if (nativeType == NativeTypeKind.I4 || nativeType == NativeTypeKind.U4 || nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableValue;
else
return MarshallerKind.Invalid;
case TypeFlags.Int64:
case TypeFlags.UInt64:
- if (nativeType == NativeTypeKind.I8 || nativeType == NativeTypeKind.U8 || nativeType == NativeTypeKind.Invalid)
+ if (nativeType == NativeTypeKind.I8 || nativeType == NativeTypeKind.U8 || nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableValue;
else
return MarshallerKind.Invalid;
case TypeFlags.IntPtr:
case TypeFlags.UIntPtr:
- if (nativeType == NativeTypeKind.Invalid)
+ if (nativeType == NativeTypeKind.SysInt || nativeType == NativeTypeKind.SysUInt || nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableValue;
else
return MarshallerKind.Invalid;
case TypeFlags.Single:
- if (nativeType == NativeTypeKind.R4 || nativeType == NativeTypeKind.Invalid)
+ if (nativeType == NativeTypeKind.R4 || nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableValue;
else
return MarshallerKind.Invalid;
case TypeFlags.Double:
- if (nativeType == NativeTypeKind.R8 || nativeType == NativeTypeKind.Invalid)
+ if (nativeType == NativeTypeKind.R8 || nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableValue;
else
return MarshallerKind.Invalid;
if (InteropTypes.IsSystemDateTime(context, type))
{
- if (nativeType == NativeTypeKind.Invalid ||
+ if (nativeType == NativeTypeKind.Default ||
nativeType == NativeTypeKind.Struct)
return MarshallerKind.OleDateTime;
else
}
else if (InteropTypes.IsHandleRef(context, type))
{
- if (nativeType == NativeTypeKind.Invalid)
+ if (nativeType == NativeTypeKind.Default)
return MarshallerKind.HandleRef;
else
return MarshallerKind.Invalid;
}
-
- switch (nativeType)
+ else if (InteropTypes.IsSystemDecimal(context, type))
{
- case NativeTypeKind.Invalid:
- case NativeTypeKind.Struct:
- if (InteropTypes.IsSystemDecimal(context, type))
- return MarshallerKind.Decimal;
- break;
-
- case NativeTypeKind.LPStruct:
- if (InteropTypes.IsSystemGuid(context, type) ||
- InteropTypes.IsSystemDecimal(context, type))
- {
- if (isField || isReturn)
- return MarshallerKind.Invalid;
- else
- return MarshallerKind.BlittableStructPtr;
- }
- break;
-
- default:
+ if (nativeType == NativeTypeKind.Struct || nativeType == NativeTypeKind.Default)
+ return MarshallerKind.Decimal;
+ else if (nativeType == NativeTypeKind.LPStruct && !isField && !isReturn)
+ return MarshallerKind.BlittableStructPtr;
+ else
return MarshallerKind.Invalid;
}
+ else if (InteropTypes.IsSystemGuid(context, type))
+ {
+ if (nativeType == NativeTypeKind.Struct || nativeType == NativeTypeKind.Default)
+ return MarshallerKind.BlittableStruct;
+ else if (nativeType == NativeTypeKind.LPStruct && !isField && !isReturn)
+ return MarshallerKind.BlittableStructPtr;
+ else
+ return MarshallerKind.Invalid;
+ }
+ else if (InteropTypes.IsSystemArgIterator(context, type))
+ {
+ // Don't want to fall through to the blittable/haslayout case
+ return MarshallerKind.Invalid;
+ }
- if (type is MetadataType)
+ if (type.HasInstantiation)
{
- MetadataType metadataType = (MetadataType)type;
- // the struct type need to be either sequential or explicit. If it is
- // auto layout we will throw exception.
- if (!metadataType.HasLayout())
- {
- throw new InvalidProgramException("The specified structure " + metadataType.Name + " has invalid StructLayout information. It must be either Sequential or Explicit.");
- }
+ // Generic types cannot be marshaled.
+ return MarshallerKind.Invalid;
}
if (MarshalUtils.IsBlittableType(type))
{
+ if (nativeType != NativeTypeKind.Default && nativeType != NativeTypeKind.Struct)
+ return MarshallerKind.Invalid;
+
return MarshallerKind.BlittableStruct;
}
- else
+ else if (((MetadataType)type).HasLayout())
{
+ if (nativeType != NativeTypeKind.Default && nativeType != NativeTypeKind.Struct)
+ return MarshallerKind.Invalid;
+
return MarshallerKind.Struct;
}
+ else
+ {
+ return MarshallerKind.Invalid;
+ }
}
else if (type.IsSzArray)
{
- if (nativeType == NativeTypeKind.Invalid)
+#if READYTORUN
+ // We don't want the additional test/maintenance cost of this in R2R.
+ if (isByRef)
+ return MarshallerKind.Invalid;
+#else
+ _ = isByRef;
+#endif
+
+ if (nativeType == NativeTypeKind.Default)
nativeType = NativeTypeKind.Array;
switch (nativeType)
return MarshallerKind.Invalid;
}
}
- else if (type.IsPointer || type.IsFunctionPointer)
+ else if (type.IsPointer)
+ {
+ TypeDesc parameterType = ((PointerType)type).ParameterType;
+
+ if ((!parameterType.IsEnum
+ && !parameterType.IsPrimitive
+ && !MarshalUtils.IsBlittableType(parameterType))
+ || parameterType.IsGCPointer)
+ {
+ // Pointers cannot reference marshaled structures. Use ByRef instead.
+ return MarshallerKind.Invalid;
+ }
+
+ if (nativeType == NativeTypeKind.Default)
+ return MarshallerKind.BlittableValue;
+ else
+ return MarshallerKind.Invalid;
+ }
+ else if (type.IsFunctionPointer)
{
- if (nativeType == NativeTypeKind.Invalid)
+ if (nativeType == NativeTypeKind.Func || nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableValue;
else
return MarshallerKind.Invalid;
}
else if (type.IsDelegate)
{
- if (nativeType == NativeTypeKind.Invalid || nativeType == NativeTypeKind.Func)
+ if (type.HasInstantiation)
+ {
+ // Generic types cannot be marshaled.
+ return MarshallerKind.Invalid;
+ }
+
+ if (nativeType == NativeTypeKind.Default || nativeType == NativeTypeKind.Func)
return MarshallerKind.FunctionPointer;
else
return MarshallerKind.Invalid;
return MarshallerKind.ByValUnicodeString;
}
- case NativeTypeKind.Invalid:
+ case NativeTypeKind.Default:
if (isAnsi)
return MarshallerKind.AnsiString;
else
{
switch (nativeType)
{
- case NativeTypeKind.Invalid:
+ case NativeTypeKind.Default:
if (isAnsi)
{
return MarshallerKind.AnsiStringBuilder;
}
else if (InteropTypes.IsSafeHandle(context, type))
{
- if (nativeType == NativeTypeKind.Invalid)
+ if (nativeType == NativeTypeKind.Default)
return MarshallerKind.SafeHandle;
else
return MarshallerKind.Invalid;
}
else if (InteropTypes.IsCriticalHandle(context, type))
{
- if (nativeType == NativeTypeKind.Invalid)
+ if (nativeType == NativeTypeKind.Default)
return MarshallerKind.CriticalHandle;
else
return MarshallerKind.Invalid;
}
else if (type is MetadataType mdType && mdType.HasLayout())
{
- if (!isField && nativeType == NativeTypeKind.Invalid || nativeType == NativeTypeKind.LPStruct)
+ if (type.HasInstantiation)
+ {
+ // Generic types cannot be marshaled.
+ return MarshallerKind.Invalid;
+ }
+
+ if (!isField && nativeType == NativeTypeKind.Default || nativeType == NativeTypeKind.LPStruct)
return MarshallerKind.LayoutClassPtr;
- else if (isField && (nativeType == NativeTypeKind.Invalid || nativeType == NativeTypeKind.Struct))
+ else if (isField && (nativeType == NativeTypeKind.Default || nativeType == NativeTypeKind.Struct))
return MarshallerKind.LayoutClass;
else
return MarshallerKind.Invalid;
bool isAnsi)
{
TypeDesc elementType = arrayType.ElementType;
- NativeTypeKind nativeType = NativeTypeKind.Invalid;
+ NativeTypeKind nativeType = NativeTypeKind.Default;
TypeSystemContext context = arrayType.Context;
if (marshalAs != null)
case NativeTypeKind.I1:
case NativeTypeKind.U1:
return MarshallerKind.CBool;
- case NativeTypeKind.Invalid:
+ case NativeTypeKind.Default:
default:
return MarshallerKind.Bool;
}
{
switch (nativeType)
{
- case NativeTypeKind.Invalid:
+ case NativeTypeKind.Default:
case NativeTypeKind.Struct:
return MarshallerKind.Decimal;
{
switch (nativeType)
{
- case NativeTypeKind.Invalid:
+ case NativeTypeKind.Default:
case NativeTypeKind.Struct:
return MarshallerKind.BlittableValue;
}
else if (InteropTypes.IsSystemDateTime(context, elementType))
{
- if (nativeType == NativeTypeKind.Invalid ||
+ if (nativeType == NativeTypeKind.Default ||
nativeType == NativeTypeKind.Struct)
{
return MarshallerKind.OleDateTime;
}
else if (InteropTypes.IsHandleRef(context, elementType))
{
- if (nativeType == NativeTypeKind.Invalid)
+ if (nativeType == NativeTypeKind.Default)
return MarshallerKind.HandleRef;
else
return MarshallerKind.Invalid;
{
switch (nativeType)
{
- case NativeTypeKind.Invalid:
+ case NativeTypeKind.Default:
case NativeTypeKind.Struct:
return MarshallerKind.BlittableStruct;
}
else if (elementType.IsPointer || elementType.IsFunctionPointer)
{
- if (nativeType == NativeTypeKind.Invalid)
+ if (nativeType == NativeTypeKind.Default)
return MarshallerKind.BlittableValue;
else
return MarshallerKind.Invalid;
{
switch (nativeType)
{
- case NativeTypeKind.Invalid:
+ case NativeTypeKind.Default:
if (isAnsi)
return MarshallerKind.AnsiString;
else
ILEmitter emitter = _ilCodeStreams.Emitter;
ILCodeLabel lNullArray = emitter.NewCodeLabel();
- LoadNativeAddr(codeStream);
- codeStream.Emit(ILOpcode.initobj, emitter.NewToken(NativeType));
+ codeStream.EmitLdc(0);
+ codeStream.Emit(ILOpcode.conv_u);
+ StoreNativeValue(codeStream);
// Check for null array
LoadManagedValue(codeStream);
codeStream.Emit(ILOpcode.mul_ovf);
codeStream.Emit(ILOpcode.call, emitter.NewToken(
- Context.GetHelperEntryPoint("InteropHelpers", "CoTaskMemAllocAndZeroMemory")));
+ InteropTypes.GetMarshal(Context).GetKnownMethod("AllocCoTaskMem", null)));
StoreNativeValue(codeStream);
codeStream.EmitLabel(lNullArray);
ILCodeLabel lRangeCheck = emitter.NewCodeLabel();
ILCodeLabel lLoopHeader = emitter.NewCodeLabel();
var lNullArray = emitter.NewCodeLabel();
-
- // Check for null array
- LoadManagedValue(codeStream);
- codeStream.Emit(ILOpcode.brfalse, lNullArray);
+ // Check for null array
+ if (!IsManagedByRef)
+ {
+ LoadManagedValue(codeStream);
+ codeStream.Emit(ILOpcode.brfalse, lNullArray);
+ }
EmitElementCount(codeStream, MarshalDirection.Reverse);
codeStream.EmitStLoc(vLength);
+
+ if (IsManagedByRef)
+ {
+ codeStream.EmitLdLoc(vLength);
+ codeStream.Emit(ILOpcode.newarr, emitter.NewToken(ManagedElementType));
+ StoreManagedValue(codeStream);
+ }
+
codeStream.Emit(ILOpcode.sizeof_, emitter.NewToken(nativeElementType));
codeStream.EmitStLoc(vSizeOf);
protected override void AllocAndTransformManagedToNative(ILCodeStream codeStream)
{
ILEmitter emitter = _ilCodeStreams.Emitter;
- var arrayType = (ArrayType)ManagedType;
- Debug.Assert(arrayType.IsSzArray);
-
- ILLocalVariable vPinnedFirstElement = emitter.NewLocal(arrayType.ParameterType.MakeByRefType(), true);
ILCodeLabel lNullArray = emitter.NewCodeLabel();
- // Check for null array, or 0 element array.
- LoadManagedValue(codeStream);
- codeStream.Emit(ILOpcode.brfalse, lNullArray);
+ MethodDesc getRawSzArrayDataMethod = InteropTypes.GetRuntimeHelpers(Context).GetKnownMethod("GetRawSzArrayData", null);
+
+ // Check for null array
LoadManagedValue(codeStream);
- codeStream.Emit(ILOpcode.ldlen);
- codeStream.Emit(ILOpcode.conv_i4);
codeStream.Emit(ILOpcode.brfalse, lNullArray);
+
+ if (IsManagedByRef)
+ {
+ base.AllocManagedToNative(codeStream);
- // Array has elements.
- LoadManagedValue(codeStream);
- codeStream.EmitLdc(0);
- codeStream.Emit(ILOpcode.ldelema, emitter.NewToken(arrayType.ElementType));
- codeStream.EmitStLoc(vPinnedFirstElement);
+ LoadNativeValue(codeStream);
+ LoadManagedValue(codeStream);
+ codeStream.Emit(ILOpcode.call, emitter.NewToken(getRawSzArrayDataMethod));
+ EmitElementCount(codeStream, MarshalDirection.Forward);
+ codeStream.Emit(ILOpcode.sizeof_, emitter.NewToken(ManagedElementType));
+ codeStream.Emit(ILOpcode.mul_ovf);
+ codeStream.Emit(ILOpcode.cpblk);
- // Fall through. If array didn't have elements, vPinnedFirstElement is zeroinit.
- codeStream.EmitLabel(lNullArray);
- codeStream.EmitLdLoc(vPinnedFirstElement);
- codeStream.Emit(ILOpcode.conv_i);
- StoreNativeValue(codeStream);
+ codeStream.EmitLabel(lNullArray);
+ }
+ else
+ {
+ ILLocalVariable vPinnedFirstElement = emitter.NewLocal(ManagedElementType.MakeByRefType(), true);
+
+ LoadManagedValue(codeStream);
+ codeStream.Emit(ILOpcode.call, emitter.NewToken(getRawSzArrayDataMethod));
+ codeStream.EmitStLoc(vPinnedFirstElement);
+
+ // Fall through. If array didn't have elements, vPinnedFirstElement is zeroinit.
+ codeStream.EmitLabel(lNullArray);
+ codeStream.EmitLdLoc(vPinnedFirstElement);
+ codeStream.Emit(ILOpcode.conv_i);
+ StoreNativeValue(codeStream);
+ }
}
protected override void ReInitNativeTransform(ILCodeStream codeStream)
protected override void TransformNativeToManaged(ILCodeStream codeStream)
{
- if ((IsManagedByRef && !In) || (MarshalDirection == MarshalDirection.Reverse && MarshallerType == MarshallerType.Argument))
+ if (IsManagedByRef || (MarshalDirection == MarshalDirection.Reverse && MarshallerType == MarshallerType.Argument))
base.TransformNativeToManaged(codeStream);
}
protected override void EmitCleanupManaged(ILCodeStream codeStream)
{
- if (IsManagedByRef && !In)
+ if (IsManagedByRef)
base.EmitCleanupManaged(codeStream);
}
}