@@ -72,36 +72,37 @@ public DynamicInvokeInfo(MethodBase method, IntPtr invokeThunk)
7272 {
7373 Transform transform = default ;
7474
75- Type argumentType = parameters [ i ] . ParameterType ;
75+ var argumentType = ( RuntimeType ) parameters [ i ] . ParameterType ;
7676 if ( argumentType . IsByRef )
7777 {
7878 _needsCopyBack = true ;
7979 transform |= Transform . ByRef ;
80- argumentType = argumentType . GetElementType ( ) ! ;
80+ argumentType = ( RuntimeType ) argumentType . GetElementType ( ) ! ;
8181 }
8282 Debug . Assert ( ! argumentType . IsByRef ) ;
8383
84- EETypePtr eeArgumentType = argumentType . TypeHandle . ToEETypePtr ( ) ;
85-
86- if ( eeArgumentType . IsValueType )
84+ // This can return a null MethodTable for reference types.
85+ // The compiler makes sure it returns a non-null MT for everything else.
86+ EETypePtr eeArgumentType = argumentType . ToEETypePtrMayBeNull ( ) ;
87+ if ( argumentType . IsValueType )
8788 {
88- Debug . Assert ( argumentType . IsValueType ) ;
89+ Debug . Assert ( eeArgumentType . IsValueType ) ;
8990
9091 if ( eeArgumentType . IsByRefLike )
9192 _argumentCount = ArgumentCount_NotSupported_ByRefLike ;
9293
9394 if ( eeArgumentType . IsNullable )
9495 transform |= Transform . Nullable ;
9596 }
96- else if ( eeArgumentType . IsPointer )
97+ else if ( argumentType . IsPointer )
9798 {
98- Debug . Assert ( argumentType . IsPointer ) ;
99+ Debug . Assert ( eeArgumentType . IsPointer ) ;
99100
100101 transform |= Transform . Pointer ;
101102 }
102- else if ( eeArgumentType . IsFunctionPointer )
103+ else if ( argumentType . IsFunctionPointer )
103104 {
104- Debug . Assert ( argumentType . IsFunctionPointer ) ;
105+ Debug . Assert ( eeArgumentType . IsFunctionPointer ) ;
105106
106107 transform |= Transform . FunctionPointer ;
107108 }
@@ -119,19 +120,18 @@ public DynamicInvokeInfo(MethodBase method, IntPtr invokeThunk)
119120 {
120121 Transform transform = default ;
121122
122- Type returnType = methodInfo . ReturnType ;
123+ var returnType = ( RuntimeType ) methodInfo . ReturnType ;
123124 if ( returnType . IsByRef )
124125 {
125126 transform |= Transform . ByRef ;
126- returnType = returnType . GetElementType ( ) ! ;
127+ returnType = ( RuntimeType ) returnType . GetElementType ( ) ! ;
127128 }
128129 Debug . Assert ( ! returnType . IsByRef ) ;
129130
130- EETypePtr eeReturnType = returnType . TypeHandle . ToEETypePtr ( ) ;
131-
132- if ( eeReturnType . IsValueType )
131+ EETypePtr eeReturnType = returnType . ToEETypePtrMayBeNull ( ) ;
132+ if ( returnType . IsValueType )
133133 {
134- Debug . Assert ( returnType . IsValueType ) ;
134+ Debug . Assert ( eeReturnType . IsValueType ) ;
135135
136136 if ( returnType != typeof ( void ) )
137137 {
@@ -150,17 +150,17 @@ public DynamicInvokeInfo(MethodBase method, IntPtr invokeThunk)
150150 _argumentCount = ArgumentCount_NotSupported ; // ByRef to void return
151151 }
152152 }
153- else if ( eeReturnType . IsPointer )
153+ else if ( returnType . IsPointer )
154154 {
155- Debug . Assert ( returnType . IsPointer ) ;
155+ Debug . Assert ( eeReturnType . IsPointer ) ;
156156
157157 transform |= Transform . Pointer ;
158158 if ( ( transform & Transform . ByRef ) == 0 )
159159 transform |= Transform . AllocateReturnBox ;
160160 }
161- else if ( eeReturnType . IsFunctionPointer )
161+ else if ( returnType . IsFunctionPointer )
162162 {
163- Debug . Assert ( returnType . IsFunctionPointer ) ;
163+ Debug . Assert ( eeReturnType . IsFunctionPointer ) ;
164164
165165 transform |= Transform . FunctionPointer ;
166166 if ( ( transform & Transform . ByRef ) == 0 )
@@ -597,6 +597,12 @@ private unsafe ref byte InvokeDirectWithFewArguments(
597597 return defaultValue ;
598598 }
599599
600+ private void ThrowForNeverValidNonNullArgument ( EETypePtr srcEEType , int index )
601+ {
602+ Debug . Assert ( index != 0 || _isStatic ) ;
603+ throw InvokeUtils . CreateChangeTypeArgumentException ( srcEEType , Method . GetParametersAsSpan ( ) [ index - ( _isStatic ? 0 : 1 ) ] . ParameterType , destinationIsByRef : false ) ;
604+ }
605+
600606 private unsafe void CheckArguments (
601607 Span < object ? > copyOfParameters ,
602608 void * byrefParameters ,
@@ -636,16 +642,25 @@ private unsafe void CheckArguments(
636642 EETypePtr srcEEType = arg . GetEETypePtr ( ) ;
637643 EETypePtr dstEEType = argumentInfo . Type ;
638644
639- if ( ! ( srcEEType . RawValue == dstEEType . RawValue ||
640- RuntimeImports . AreTypesAssignable ( srcEEType , dstEEType ) ||
641- ( dstEEType . IsInterface && arg is System . Runtime . InteropServices . IDynamicInterfaceCastable castable
642- && castable . IsInterfaceImplemented ( new RuntimeTypeHandle ( dstEEType ) , throwIfNotImplemented : false ) ) ) )
645+ if ( srcEEType . RawValue != dstEEType . RawValue )
643646 {
644- // ByRefs have to be exact match
645- if ( ( argumentInfo . Transform & Transform . ByRef ) != 0 )
646- throw InvokeUtils . CreateChangeTypeArgumentException ( srcEEType , argumentInfo . Type , destinationIsByRef : true ) ;
647+ // Destination type can be null if we don't have a MethodTable for this type. This means one cannot
648+ // possibly pass a valid non-null object instance here.
649+ if ( dstEEType . IsNull )
650+ {
651+ ThrowForNeverValidNonNullArgument ( srcEEType , i ) ;
652+ }
647653
648- arg = InvokeUtils . CheckArgumentConversions ( arg , argumentInfo . Type , InvokeUtils . CheckArgumentSemantics . DynamicInvoke , binderBundle ) ;
654+ if ( ! ( RuntimeImports . AreTypesAssignable ( srcEEType , dstEEType ) ||
655+ ( dstEEType . IsInterface && arg is System . Runtime . InteropServices . IDynamicInterfaceCastable castable
656+ && castable . IsInterfaceImplemented ( new RuntimeTypeHandle ( dstEEType ) , throwIfNotImplemented : false ) ) ) )
657+ {
658+ // ByRefs have to be exact match
659+ if ( ( argumentInfo . Transform & Transform . ByRef ) != 0 )
660+ throw InvokeUtils . CreateChangeTypeArgumentException ( srcEEType , argumentInfo . Type , destinationIsByRef : true ) ;
661+
662+ arg = InvokeUtils . CheckArgumentConversions ( arg , argumentInfo . Type , InvokeUtils . CheckArgumentSemantics . DynamicInvoke , binderBundle ) ;
663+ }
649664 }
650665
651666 if ( ( argumentInfo . Transform & Transform . Reference ) == 0 )
@@ -704,16 +719,25 @@ private unsafe void CheckArguments(
704719 EETypePtr srcEEType = arg . GetEETypePtr ( ) ;
705720 EETypePtr dstEEType = argumentInfo . Type ;
706721
707- if ( ! ( srcEEType . RawValue == dstEEType . RawValue ||
708- RuntimeImports . AreTypesAssignable ( srcEEType , dstEEType ) ||
709- ( dstEEType . IsInterface && arg is System . Runtime . InteropServices . IDynamicInterfaceCastable castable
710- && castable . IsInterfaceImplemented ( new RuntimeTypeHandle ( dstEEType ) , throwIfNotImplemented : false ) ) ) )
722+ if ( srcEEType . RawValue != dstEEType . RawValue )
711723 {
712- // ByRefs have to be exact match
713- if ( ( argumentInfo . Transform & Transform . ByRef ) != 0 )
714- throw InvokeUtils . CreateChangeTypeArgumentException ( srcEEType , argumentInfo . Type , destinationIsByRef : true ) ;
724+ // Destination type can be null if we don't have a MethodTable for this type. This means one cannot
725+ // possibly pass a valid non-null object instance here.
726+ if ( dstEEType . IsNull )
727+ {
728+ ThrowForNeverValidNonNullArgument ( srcEEType , i ) ;
729+ }
715730
716- arg = InvokeUtils . CheckArgumentConversions ( arg , argumentInfo . Type , InvokeUtils . CheckArgumentSemantics . DynamicInvoke , binderBundle : null ) ;
731+ if ( ! ( RuntimeImports . AreTypesAssignable ( srcEEType , dstEEType ) ||
732+ ( dstEEType . IsInterface && arg is System . Runtime . InteropServices . IDynamicInterfaceCastable castable
733+ && castable . IsInterfaceImplemented ( new RuntimeTypeHandle ( dstEEType ) , throwIfNotImplemented : false ) ) ) )
734+ {
735+ // ByRefs have to be exact match
736+ if ( ( argumentInfo . Transform & Transform . ByRef ) != 0 )
737+ throw InvokeUtils . CreateChangeTypeArgumentException ( srcEEType , argumentInfo . Type , destinationIsByRef : true ) ;
738+
739+ arg = InvokeUtils . CheckArgumentConversions ( arg , argumentInfo . Type , InvokeUtils . CheckArgumentSemantics . DynamicInvoke , binderBundle : null ) ;
740+ }
717741 }
718742
719743 if ( ( argumentInfo . Transform & Transform . Reference ) == 0 )
0 commit comments