return _methods;
}
+ public override IEnumerable<MethodDesc> GetVirtualMethods()
+ {
+ return MethodDesc.EmptyMethods;
+ }
+
public MethodDesc GetArrayMethod(ArrayMethodKind kind)
{
if (_methods == null)
// BadImageFormatException
BadImageFormatGeneric,
BadImageFormatSpecific,
+
+ // MarshalDirectiveException
+ MarshalDirectiveGeneric,
}
}
}
}
+ public override IEnumerable<MethodDesc> GetVirtualMethods()
+ {
+ foreach (var typicalMethodDef in _typeDef.GetVirtualMethods())
+ {
+ yield return _typeDef.Context.GetMethodForInstantiatedType(typicalMethodDef, this);
+ }
+ }
+
// TODO: Substitutions, generics, modopts, ...
public override MethodDesc GetMethod(string name, MethodSignature signature, Instantiation substitution)
{
MethodSignature sig = targetMethod.Signature;
MethodDesc implMethod = null;
- foreach (MethodDesc candidate in currentType.GetAllMethods())
+ foreach (MethodDesc candidate in currentType.GetAllVirtualMethods())
{
- if (!candidate.IsVirtual)
- continue;
-
if (candidate.Name == name)
{
if (candidate.Signature.Equals(sig))
{
do
{
- foreach (MethodDesc m in type.GetAllMethods())
+ foreach (MethodDesc m in type.GetAllVirtualMethods())
{
- if (!m.IsVirtual)
- continue;
-
MethodDesc possibleVirtual = FindSlotDefiningMethodForVirtualMethod(m);
if (!alreadyEnumerated.Contains(possibleVirtual))
{
<data name="BadImageFormatSpecific" xml:space="preserve">
<value>The format of a DLL or executable being loaded is invalid with {0}</value>
</data>
+ <data name="MarshalDirectiveGeneric" xml:space="preserve">
+ <value>Marshaling directives are invalid</value>
+ </data>
</root>
throw new TypeSystemException.BadImageFormatException(message);
}
+ [System.Diagnostics.DebuggerHidden]
+ public static void ThrowMarshalDirectiveException()
+ {
+ throw new TypeSystemException.MarshalDirectiveException(ExceptionStringID.MarshalDirectiveGeneric);
+ }
+
private static partial class Format
{
public static string OwningModule(TypeDesc type)
return MethodDesc.EmptyMethods;
}
+ /// <summary>
+ /// Gets a subset of methods returned by <see cref="GetMethods"/> that are virtual.
+ /// </summary>
+ public virtual IEnumerable<MethodDesc> GetVirtualMethods()
+ {
+ foreach (MethodDesc method in GetMethods())
+ if (method.IsVirtual)
+ yield return method;
+ }
+
/// <summary>
/// Gets a named method on the type. This method only looks at methods defined
/// in type's metadata. The <paramref name="signature"/> parameter can be null.
return type.GetMethods();
}
+ protected internal virtual IEnumerable<MethodDesc> GetAllVirtualMethods(TypeDesc type)
+ {
+ return type.GetVirtualMethods();
+ }
+
/// <summary>
/// Abstraction to allow the type system context to affect the field layout
/// algorithm used by types to lay themselves out.
}
}
+
+ public class MarshalDirectiveException : TypeSystemException
+ {
+ internal MarshalDirectiveException(ExceptionStringID id)
+ : base(id)
+ {
+ }
+ }
}
}
return type.Context.GetAllMethods(type);
}
+ /// <summary>
+ /// Retrieves all virtual methods on a type, including the ones injected by the type system context.
+ /// </summary>
+ public static IEnumerable<MethodDesc> GetAllVirtualMethods(this TypeDesc type)
+ {
+ return type.Context.GetAllVirtualMethods(type);
+ }
+
public static IEnumerable<MethodDesc> EnumAllVirtualSlots(this TypeDesc type)
{
return type.Context.GetVirtualMethodAlgorithmForType(type).ComputeAllVirtualSlots(type);
}
if (assemblyName.StartsWith("System.Private", StringComparison.Ordinal))
- assemblyName = "S.P" + assemblyName.Substring(14);
+ {
+ sb.Append("S.P");
+ sb.Append(assemblyName, 14, assemblyName.Length - 14);
+ }
+ else
+ {
+ sb.Append(assemblyName);
+ }
- sb.Append(assemblyName);
sb.Append(']');
}
}
{
foreach (var handle in _typeDefinition.GetMethods())
{
- yield return (MethodDesc)_module.GetObject(handle);
+ yield return (EcmaMethod)_module.GetObject(handle);
+ }
+ }
+
+ public override IEnumerable<MethodDesc> GetVirtualMethods()
+ {
+ MetadataReader reader = _module.MetadataReader;
+ foreach (var handle in _typeDefinition.GetMethods())
+ {
+ MethodDefinition methodDef = reader.GetMethodDefinition(handle);
+ if ((methodDef.Attributes & MethodAttributes.Virtual) != 0)
+ yield return (EcmaMethod)_module.GetObject(handle);
}
}
{
if (stringComparer.Equals(metadataReader.GetMethodDefinition(handle).Name, name))
{
- MethodDesc method = (MethodDesc)_module.GetObject(handle);
+ var method = (EcmaMethod)_module.GetObject(handle);
if (signature == null || signature.Equals(method.Signature.ApplySubstitution(substitution)))
return method;
}
if (methodDefinition.Attributes.IsRuntimeSpecialName() &&
stringComparer.Equals(methodDefinition.Name, ".cctor"))
{
- MethodDesc method = (MethodDesc)_module.GetObject(handle);
+ var method = (EcmaMethod)_module.GetObject(handle);
return method;
}
}
if (attributes.IsRuntimeSpecialName() && attributes.IsPublic()
&& stringComparer.Equals(methodDefinition.Name, ".ctor"))
{
- MethodDesc method = (MethodDesc)_module.GetObject(handle);
+ var method = (EcmaMethod)_module.GetObject(handle);
if (method.Signature.Length != 0)
continue;
{
foreach (var handle in _typeDefinition.GetNestedTypes())
{
- yield return (MetadataType)_module.GetObject(handle);
+ yield return (EcmaType)_module.GetObject(handle);
}
}
}
if (nameMatched)
- return (MetadataType)_module.GetObject(handle);
+ return (EcmaType)_module.GetObject(handle);
}
return null;
// Note: GetOffset() returns -1 when offset was not set in the metadata
int specifiedOffset = fieldDefinition.GetOffset();
result.Offsets[index] =
- new FieldAndOffset((FieldDesc)_module.GetObject(handle), specifiedOffset == -1 ? FieldAndOffset.InvalidOffset : new LayoutInt(specifiedOffset));
+ new FieldAndOffset((EcmaField)_module.GetObject(handle), specifiedOffset == -1 ? FieldAndOffset.InvalidOffset : new LayoutInt(specifiedOffset));
index++;
}
var sequencePoints = debugInformation.GetSequencePoints();
+ DocumentHandle previousDocumentHandle = default;
+ string previousDocumentUrl = null;
+
foreach (var sequencePoint in sequencePoints)
{
- if (sequencePoint.StartLine == 0xFEEFEE)
+ if (sequencePoint.StartLine == SequencePoint.HiddenLine)
continue;
- var url = _reader.GetString(_reader.GetDocument(sequencePoint.Document).Name);
+ string url;
+ if (sequencePoint.Document == previousDocumentHandle)
+ {
+ url = previousDocumentUrl;
+ }
+ else
+ {
+ url = _reader.GetString(_reader.GetDocument(sequencePoint.Document).Name);
+ previousDocumentHandle = sequencePoint.Document;
+ previousDocumentUrl = url;
+ }
yield return new ILSequencePoint(sequencePoint.Offset, url, sequencePoint.StartLine);
}
case MarshallerKind.CBool:
return context.GetWellKnownType(WellKnownType.Byte);
+ case MarshallerKind.VariantBool:
+ return context.GetWellKnownType(WellKnownType.Int16);
+
case MarshallerKind.Enum:
case MarshallerKind.BlittableStruct:
case MarshallerKind.Decimal:
case MarshallerKind.ComInterface:
return context.GetWellKnownType(WellKnownType.IntPtr);
+#if !READYTORUN
+ case MarshallerKind.Variant:
+ return InteropTypes.GetVariant(context);
+#endif
+
+ case MarshallerKind.OleCurrency:
+ return context.GetWellKnownType(WellKnownType.Int64);
+
case MarshallerKind.Unknown:
default:
throw new NotSupportedException();
case NativeTypeKind.I1:
return MarshallerKind.CBool;
+ case NativeTypeKind.VariantBool:
+ return MarshallerKind.VariantBool;
+
default:
return MarshallerKind.Invalid;
}
return MarshallerKind.Decimal;
else if (nativeType == NativeTypeKind.LPStruct && !isField)
return MarshallerKind.BlittableStructPtr;
+ else if (nativeType == NativeTypeKind.Currency)
+ return MarshallerKind.OleCurrency;
else
return MarshallerKind.Invalid;
}
{
case NativeTypeKind.Array:
{
- if (isField || isReturn)
- return MarshallerKind.Invalid;
-
var arrayType = (ArrayType)type;
elementMarshallerKind = GetArrayElementMarshallerKind(
|| nativeType == NativeTypeKind.IUnknown)
return MarshallerKind.ComInterface;
else
- return MarshallerKind.Invalid;
+ return MarshallerKind.Variant;
}
else if (InteropTypes.IsStringBuilder(context, type))
{
return MarshallerKind.UnicodeString;
case NativeTypeKind.LPUTF8Str:
return MarshallerKind.UTF8String;
+ case NativeTypeKind.BStr:
+ case NativeTypeKind.TBStr:
+ return MarshallerKind.BSTRString;
+ case NativeTypeKind.AnsiBStr:
+ return MarshallerKind.AnsiBSTRString;
default:
return MarshallerKind.Invalid;
}
BlittableArray,
Bool, // 4 byte bool
CBool, // 1 byte bool
+ VariantBool, // Variant bool
Enum,
AnsiChar, // Marshal char (Unicode 16bits) for byte (Ansi 8bits)
UnicodeChar,
Object,
OleDateTime,
Decimal,
+ OleCurrency,
Guid,
Struct,
BlittableStruct,
public bool Return;
public bool IsManagedByRef; // Whether managed argument is passed by ref
public bool IsNativeByRef; // Whether native argument is passed by byref
- // There are special cases (such as LpStruct, and class) that
+ // There are special cases (such as LpStruct, and class) that
// isNativeByRef != IsManagedByRef
public MarshalDirection MarshalDirection;
protected PInvokeILCodeStreams _ilCodeStreams;
break;
default:
// Storing by-ref arg/local is not supported because StInd require
- // address to be pushed first. Instead we need to introduce a non-byref
+ // address to be pushed first. Instead we need to introduce a non-byref
// local and propagate value as needed for by-ref arguments
Debug.Assert(false);
break;
//
if (isOut)
{
- // Passing as [Out] by ref is always valid.
+ // Passing as [Out] by ref is always valid.
if (!marshaller.IsManagedByRef)
{
// Ignore [Out] for ValueType, string and pointers
/// <summary>
/// Propagate by-ref arg to corresponding local
- /// We can't load value + ldarg + ldind in the expected order, so
+ /// We can't load value + ldarg + ldind in the expected order, so
/// we had to use a non-by-ref local and manually propagate the value
/// </summary>
protected void PropagateFromByRefArg(ILCodeStream stream, Home home)
/// <summary>
/// Propagate local to corresponding by-ref arg
- /// We can't load value + ldarg + ldind in the expected order, so
+ /// We can't load value + ldarg + ldind in the expected order, so
/// we had to use a non-by-ref local and manually propagate the value
/// </summary>
protected void PropagateToByRefArg(ILCodeStream stream, Home home)
SetupArgumentsForFieldMarshalling();
//
// For field marshalling we expect the value of the field is already loaded
- // in the stack.
+ // in the stack.
//
StoreManagedValue(marshallingCodeStream);
}
}
+ protected override void SetupArgumentsForFieldMarshalling()
+ {
+ ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, ManagedType);
+ }
+
protected Marshaller GetElementMarshaller(MarshalDirection direction)
{
if (_elementMarshaller == null)
if (index < 0 || index >= Marshallers.Length - 1)
{
- throw new InvalidProgramException("Invalid SizeParamIndex, must be between 0 and parameter count");
+ ThrowHelper.ThrowMarshalDirectiveException();
}
//zero-th index is for return type
case TypeFlags.UIntPtr:
break;
default:
- throw new InvalidProgramException("Invalid SizeParamIndex, parameter must be of type int/uint");
+ ThrowHelper.ThrowMarshalDirectiveException();
+ break;
}
// @TODO - We can use LoadManagedValue, but that requires byref arg propagation happen in a special setup stream
// Check for null array
LoadManagedValue(codeStream);
codeStream.Emit(ILOpcode.brfalse, lNullArray);
-
+
if (IsManagedByRef)
{
base.AllocManagedToNative(codeStream);
class BooleanMarshaller : Marshaller
{
+ private int _trueValue;
+ public BooleanMarshaller(int trueValue = 1)
+ {
+ _trueValue = trueValue;
+ }
+
protected override void AllocAndTransformManagedToNative(ILCodeStream codeStream)
{
+ ILEmitter emitter = _ilCodeStreams.Emitter;
+ ILCodeLabel pLoadFalseLabel = emitter.NewCodeLabel();
+ ILCodeLabel pDoneLabel = emitter.NewCodeLabel();
+
LoadManagedValue(codeStream);
- codeStream.EmitLdc(0);
- codeStream.Emit(ILOpcode.ceq);
- codeStream.EmitLdc(0);
- codeStream.Emit(ILOpcode.ceq);
+ if (_trueValue == 1)
+ {
+ codeStream.EmitLdc(0);
+ codeStream.Emit(ILOpcode.ceq);
+ codeStream.EmitLdc(0);
+ codeStream.Emit(ILOpcode.ceq);
+ }
+ else
+ {
+ codeStream.Emit(ILOpcode.brfalse, pLoadFalseLabel);
+ codeStream.EmitLdc(_trueValue);
+ codeStream.Emit(ILOpcode.br, pDoneLabel);
+
+ codeStream.EmitLabel(pLoadFalseLabel);
+ codeStream.EmitLdc(0);
+
+ codeStream.EmitLabel(pDoneLabel);
+ }
+
StoreNativeValue(codeStream);
}
cleanupCodeStream.Emit(ILOpcode.brfalse, lNotAddrefed);
LoadManagedValue(cleanupCodeStream);
cleanupCodeStream.Emit(ILOpcode.call, emitter.NewToken(
- safeHandleType.GetKnownMethod("DangerousRelease",
+ safeHandleType.GetKnownMethod("DangerousRelease",
new MethodSignature(0, 0, Context.GetWellKnownType(WellKnownType.Void), TypeDesc.EmptyTypes))));
cleanupCodeStream.EmitLabel(lNotAddrefed);
}
// must allocate this before the native call to avoid a failure point when we already have a native resource
// allocated. We must allocate a new SafeHandle even if we have one on input since both input and output native
// handles need to be tracked and released by a SafeHandle.
- // 2) Initialize a local IntPtr that will be passed to the native call.
+ // 2) Initialize a local IntPtr that will be passed to the native call.
// 3) After the native call, the new handle value is written into the output SafeHandle and that SafeHandle
// is propagated back to the caller.
var vSafeHandle = emitter.NewLocal(ManagedType);
))));
#else
codeStream.Emit(ILOpcode.ldtoken, _ilCodeStreams.Emitter.NewToken(ManagedType));
-
+
codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken(
InteropTypes.GetPInvokeMarshal(Context).GetKnownMethod("GetDelegateForFunctionPointer",
new MethodSignature(MethodSignatureFlags.Static, 0, Context.GetWellKnownType(WellKnownType.MulticastDelegate).BaseType,
U8 = 0xa,
R4 = 0xb,
R8 = 0xc,
+ Currency = 0xf,
BStr = 0x13,
LPStr = 0x14,
LPWStr = 0x15,
SysUInt = 0x20,
AnsiBStr = 0x23,
TBStr = 0x24,
+ VariantBool = 0x25,
Func = 0x26,
AsAny = 0x28,
Array = 0x2a,
}
}
+ public override IEnumerable<MethodDesc> GetVirtualMethods()
+ {
+ foreach (var method in _rawCanonType.GetVirtualMethods())
+ {
+ yield return Context.GetMethodForRuntimeDeterminedType(method.GetTypicalMethodDefinition(), this);
+ }
+ }
+
public override MethodDesc GetMethod(string name, MethodSignature signature, Instantiation substitution)
{
MethodDesc method = _rawCanonType.GetMethod(name, signature, substitution);
foreach (var m in mdType.GetMethods())
yield return m;
}
+
+ protected override IEnumerable<MethodDesc> GetAllVirtualMethods(TypeDesc type)
+ {
+ MetadataType mdType = type as MetadataType;
+
+ if (mdType.Name == "StructWithNoEqualsAndGetHashCode"
+ || mdType.Name == "ClassWithInjectedEqualsAndGetHashCode")
+ {
+ yield return GetEqualsMethod(type);
+ yield return GetGetHashCodeMethod(type);
+ }
+
+ foreach (var m in mdType.GetVirtualMethods())
+ yield return m;
+ }
}
private partial class SyntheticMethod : MethodDesc
using System.Text;
using System.Reflection;
+using System.Runtime.CompilerServices;
namespace System.Diagnostics
{
/// <summary>
/// Constructs a StackFrame corresponding to the active stack frame.
/// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
public StackFrame()
{
InitMembers();
/// <summary>
/// Constructs a StackFrame corresponding to the active stack frame.
/// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
public StackFrame(bool needFileInfo)
{
InitMembers();
/// <summary>
/// Constructs a StackFrame corresponding to a calling stack frame.
/// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
public StackFrame(int skipFrames)
{
InitMembers();
/// <summary>
/// Constructs a StackFrame corresponding to a calling stack frame.
/// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
public StackFrame(int skipFrames, bool needFileInfo)
{
InitMembers();
/// name and line number. Use when you don't want to use the
/// debugger's line mapping logic.
/// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
public StackFrame(string? fileName, int lineNumber)
{
InitMembers();
/// name, line number and column number. Use when you don't want to
/// use the debugger's line mapping logic.
/// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
public StackFrame(string? fileName, int lineNumber, int colNumber)
- : this(fileName, lineNumber)
{
+ InitMembers();
+
+ BuildStackFrame(StackTrace.METHODS_TO_SKIP, false);
+ _fileName = fileName;
+ _lineNumber = lineNumber;
_columnNumber = colNumber;
}
/// <summary>
/// Constructs a stack trace from the current location.
/// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
public StackTrace()
{
InitializeForCurrentThread(METHODS_TO_SKIP, false);
/// <summary>
/// Constructs a stack trace from the current location.
/// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
public StackTrace(bool fNeedFileInfo)
{
InitializeForCurrentThread(METHODS_TO_SKIP, fNeedFileInfo);
/// Constructs a stack trace from the current location, in a caller's
/// frame
/// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
public StackTrace(int skipFrames)
{
if (skipFrames < 0)
/// Constructs a stack trace from the current location, in a caller's
/// frame
/// </summary>
+ [MethodImplAttribute(MethodImplOptions.NoInlining)]
public StackTrace(int skipFrames, bool fNeedFileInfo)
{
if (skipFrames < 0)
{
internal sealed class ReflectionMemberAccessor : MemberAccessor
{
+ private class ConstructorContext
+ {
+ [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
+ private readonly Type _type;
+
+ public ConstructorContext([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type)
+ => _type = type;
+
+ public object? CreateInstance()
+ => Activator.CreateInstance(_type, nonPublic: false);
+ }
+
public override JsonTypeInfo.ConstructorDelegate? CreateConstructor(
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] Type type)
{
return null;
}
- return () => Activator.CreateInstance(type, nonPublic: false);
+ return new ConstructorContext(type).CreateInstance;
}
public override JsonTypeInfo.ParameterizedConstructorDelegate<T>? CreateParameterizedConstructor<T>(ConstructorInfo constructor)