@@ -379,11 +379,11 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
379379 // and resetting it would lead to unpredictable analysis durations.
380380 int baseInstructionCounter = instructionCounter ;
381381 Status status = nestedPreinit . TryScanMethod ( field . OwningType . GetStaticConstructor ( ) , null , recursionProtect , ref instructionCounter , out Value _ ) ;
382+ recursionProtect . Pop ( ) ;
382383 if ( ! status . IsSuccessful )
383384 {
384385 return Status . Fail ( methodIL . OwningMethod , opcode , "Nested cctor failed to preinit" ) ;
385386 }
386- recursionProtect . Pop ( ) ;
387387 Value value = nestedPreinit . _fieldValues [ field ] ;
388388 if ( value is ValueTypeValue )
389389 stack . PushFromLocation ( field . FieldType , value ) ;
@@ -489,17 +489,16 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
489489 }
490490
491491 Value retVal ;
492- if ( ! method . IsIntrinsic || ! TryHandleIntrinsicCall ( method , methodParams , out retVal ) )
492+ if ( ! method . IsIntrinsic && method . Name != "FastAllocateString" || ! TryHandleIntrinsicCall ( context , method , methodParams , out retVal ) )
493493 {
494494 recursionProtect ??= new Stack < MethodDesc > ( ) ;
495495 recursionProtect . Push ( methodIL . OwningMethod ) ;
496496 Status callResult = TryScanMethod ( method , methodParams , recursionProtect , ref instructionCounter , out retVal ) ;
497+ recursionProtect . Pop ( ) ;
497498 if ( ! callResult . IsSuccessful )
498499 {
499- recursionProtect . Pop ( ) ;
500500 return callResult ;
501501 }
502- recursionProtect . Pop ( ) ;
503502 }
504503
505504 if ( ! methodSig . ReturnType . IsVoid )
@@ -665,13 +664,11 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
665664 recursionProtect ??= new Stack < MethodDesc > ( ) ;
666665 recursionProtect . Push ( methodIL . OwningMethod ) ;
667666 Status ctorCallResult = TryScanMethod ( ctor , ctorParameters , recursionProtect , ref instructionCounter , out _ ) ;
667+ recursionProtect . Pop ( ) ;
668668 if ( ! ctorCallResult . IsSuccessful )
669669 {
670- recursionProtect . Pop ( ) ;
671670 return ctorCallResult ;
672671 }
673-
674- recursionProtect . Pop ( ) ;
675672 }
676673
677674 stack . PushFromLocation ( owningType , instance ) ;
@@ -824,6 +821,8 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
824821 case ILOpcode . conv_u2 :
825822 case ILOpcode . conv_u4 :
826823 case ILOpcode . conv_u8 :
824+ case ILOpcode . conv_r4 :
825+ case ILOpcode . conv_r8 :
827826 {
828827 StackEntry popped = stack . Pop ( ) ;
829828 if ( popped . ValueKind . WithNormalizedNativeInt ( context ) == StackValueKind . Int32 )
@@ -863,6 +862,12 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
863862 case ILOpcode . conv_u8 :
864863 stack . Push ( StackValueKind . Int64 , ValueTypeValue . FromInt64 ( ( uint ) val ) ) ;
865864 break ;
865+ case ILOpcode . conv_r4 :
866+ stack . Push ( StackValueKind . Float , ValueTypeValue . FromDouble ( ( float ) val ) ) ;
867+ break ;
868+ case ILOpcode . conv_r8 :
869+ stack . Push ( StackValueKind . Float , ValueTypeValue . FromDouble ( val ) ) ;
870+ break ;
866871 default :
867872 return Status . Fail ( methodIL . OwningMethod , opcode ) ;
868873 }
@@ -901,6 +906,12 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
901906 case ILOpcode . conv_u8 :
902907 stack . Push ( StackValueKind . Int64 , ValueTypeValue . FromInt64 ( val ) ) ;
903908 break ;
909+ case ILOpcode . conv_r4 :
910+ stack . Push ( StackValueKind . Float , ValueTypeValue . FromDouble ( ( float ) val ) ) ;
911+ break ;
912+ case ILOpcode . conv_r8 :
913+ stack . Push ( StackValueKind . Float , ValueTypeValue . FromDouble ( val ) ) ;
914+ break ;
904915 default :
905916 return Status . Fail ( methodIL . OwningMethod , opcode ) ;
906917 }
@@ -910,15 +921,47 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
910921 double val = popped . Value . AsDouble ( ) ;
911922 switch ( opcode )
912923 {
924+ case ILOpcode . conv_u :
925+ case ILOpcode . conv_i :
926+ stack . Push ( StackValueKind . NativeInt ,
927+ context . Target . PointerSize == 8 ? ValueTypeValue . FromInt64 ( ( long ) val ) : ValueTypeValue . FromInt32 ( ( int ) val ) ) ;
928+ break ;
929+ case ILOpcode . conv_i1 :
930+ stack . Push ( StackValueKind . Int32 , ValueTypeValue . FromInt32 ( ( sbyte ) val ) ) ;
931+ break ;
932+ case ILOpcode . conv_i2 :
933+ stack . Push ( StackValueKind . Int32 , ValueTypeValue . FromInt32 ( ( short ) val ) ) ;
934+ break ;
935+ case ILOpcode . conv_i4 :
936+ stack . Push ( StackValueKind . Int32 , ValueTypeValue . FromInt32 ( ( int ) val ) ) ;
937+ break ;
913938 case ILOpcode . conv_i8 :
914939 stack . Push ( StackValueKind . Int64 , ValueTypeValue . FromInt64 ( ( long ) val ) ) ;
915940 break ;
941+ case ILOpcode . conv_u1 :
942+ stack . Push ( StackValueKind . Int32 , ValueTypeValue . FromInt32 ( ( byte ) val ) ) ;
943+ break ;
944+ case ILOpcode . conv_u2 :
945+ stack . Push ( StackValueKind . Int32 , ValueTypeValue . FromInt32 ( ( ushort ) val ) ) ;
946+ break ;
947+ case ILOpcode . conv_u4 :
948+ stack . Push ( StackValueKind . Int32 , ValueTypeValue . FromInt32 ( ( int ) val ) ) ;
949+ break ;
950+ case ILOpcode . conv_u8 :
951+ stack . Push ( StackValueKind . Int64 , ValueTypeValue . FromInt64 ( ( long ) val ) ) ;
952+ break ;
953+ case ILOpcode . conv_r4 :
954+ stack . Push ( StackValueKind . Float , ValueTypeValue . FromDouble ( ( float ) val ) ) ;
955+ break ;
956+ case ILOpcode . conv_r8 :
957+ stack . Push ( StackValueKind . Float , ValueTypeValue . FromDouble ( val ) ) ;
958+ break ;
916959 default :
917960 return Status . Fail ( methodIL . OwningMethod , opcode ) ;
918961 }
919962 }
920963 else if ( popped . ValueKind == StackValueKind . ByRef
921- && ( opcode == ILOpcode . conv_i || opcode == ILOpcode . conv_u )
964+ && ( opcode is ILOpcode . conv_i or ILOpcode . conv_u )
922965 && ( reader . PeekILOpcode ( ) is ( >= ILOpcode . ldind_i1 and <= ILOpcode . ldind_ref ) or ILOpcode . ldobj ) )
923966 {
924967 // In the interpreter memory model, there's no conversion from a byref to an integer.
@@ -1379,13 +1422,29 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
13791422 StackEntry value = stack . Pop ( ) ;
13801423 if ( value . ValueKind == StackValueKind . Int32 )
13811424 stack . Push ( StackValueKind . Int32 , ValueTypeValue . FromInt32 ( - value . Value . AsInt32 ( ) ) ) ;
1425+ else if ( value . ValueKind == StackValueKind . Int64 )
1426+ stack . Push ( StackValueKind . Int64 , ValueTypeValue . FromInt64 ( - value . Value . AsInt64 ( ) ) ) ;
1427+ else
1428+ return Status . Fail ( methodIL . OwningMethod , opcode ) ;
1429+ }
1430+ break ;
1431+
1432+ case ILOpcode . not :
1433+ {
1434+ StackEntry value = stack . Pop ( ) ;
1435+ if ( value . ValueKind == StackValueKind . Int32 )
1436+ stack . Push ( StackValueKind . Int32 , ValueTypeValue . FromInt32 ( ~ value . Value . AsInt32 ( ) ) ) ;
1437+ else if ( value . ValueKind == StackValueKind . Int64 )
1438+ stack . Push ( StackValueKind . Int64 , ValueTypeValue . FromInt64 ( ~ value . Value . AsInt64 ( ) ) ) ;
13821439 else
13831440 return Status . Fail ( methodIL . OwningMethod , opcode ) ;
13841441 }
13851442 break ;
13861443
13871444 case ILOpcode . or :
1445+ case ILOpcode . xor :
13881446 case ILOpcode . shl :
1447+ case ILOpcode . shr :
13891448 case ILOpcode . add :
13901449 case ILOpcode . sub :
13911450 case ILOpcode . mul :
@@ -1395,13 +1454,24 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
13951454 case ILOpcode . rem :
13961455 case ILOpcode . rem_un :
13971456 {
1398- bool isDivRem = opcode == ILOpcode . div || opcode == ILOpcode . div_un
1399- || opcode == ILOpcode . rem || opcode == ILOpcode . rem_un ;
1457+ bool isDivRem = opcode is ILOpcode . div or ILOpcode . div_un
1458+ or ILOpcode . rem or ILOpcode . rem_un ;
14001459
14011460 StackEntry value2 = stack . Pop ( ) ;
14021461 StackEntry value1 = stack . Pop ( ) ;
14031462
14041463 bool isNint = value1 . ValueKind == StackValueKind . NativeInt || value2 . ValueKind == StackValueKind . NativeInt ;
1464+ if ( isNint && context . Target . PointerSize == 8 )
1465+ {
1466+ if ( value1 . ValueKind == StackValueKind . Int32 )
1467+ {
1468+ value1 = new StackEntry ( StackValueKind . NativeInt , ValueTypeValue . FromInt64 ( value1 . Value . AsInt32 ( ) ) ) ;
1469+ }
1470+ else if ( value2 . ValueKind == StackValueKind . Int32 )
1471+ {
1472+ value2 = new StackEntry ( StackValueKind . NativeInt , ValueTypeValue . FromInt64 ( value2 . Value . AsInt32 ( ) ) ) ;
1473+ }
1474+ }
14051475
14061476 if ( value1 . ValueKind . WithNormalizedNativeInt ( context ) == StackValueKind . Int32 && value2 . ValueKind . WithNormalizedNativeInt ( context ) == StackValueKind . Int32 )
14071477 {
@@ -1411,7 +1481,9 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
14111481 int result = opcode switch
14121482 {
14131483 ILOpcode . or => value1 . Value . AsInt32 ( ) | value2 . Value . AsInt32 ( ) ,
1484+ ILOpcode . xor => value1 . Value . AsInt32 ( ) ^ value2 . Value . AsInt32 ( ) ,
14141485 ILOpcode . shl => value1 . Value . AsInt32 ( ) << value2 . Value . AsInt32 ( ) ,
1486+ ILOpcode . shr => value1 . Value . AsInt32 ( ) >> value2 . Value . AsInt32 ( ) ,
14151487 ILOpcode . add => value1 . Value . AsInt32 ( ) + value2 . Value . AsInt32 ( ) ,
14161488 ILOpcode . sub => value1 . Value . AsInt32 ( ) - value2 . Value . AsInt32 ( ) ,
14171489 ILOpcode . and => value1 . Value . AsInt32 ( ) & value2 . Value . AsInt32 ( ) ,
@@ -1433,6 +1505,7 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
14331505 long result = opcode switch
14341506 {
14351507 ILOpcode . or => value1 . Value . AsInt64 ( ) | value2 . Value . AsInt64 ( ) ,
1508+ ILOpcode . xor => value1 . Value . AsInt64 ( ) ^ value2 . Value . AsInt64 ( ) ,
14361509 ILOpcode . add => value1 . Value . AsInt64 ( ) + value2 . Value . AsInt64 ( ) ,
14371510 ILOpcode . sub => value1 . Value . AsInt64 ( ) - value2 . Value . AsInt64 ( ) ,
14381511 ILOpcode . and => value1 . Value . AsInt64 ( ) & value2 . Value . AsInt64 ( ) ,
@@ -1451,7 +1524,7 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
14511524 if ( isDivRem && value2 . Value . AsDouble ( ) == 0 )
14521525 return Status . Fail ( methodIL . OwningMethod , opcode , "Division by zero" ) ;
14531526
1454- if ( opcode == ILOpcode . or || opcode == ILOpcode . shl || opcode == ILOpcode . and || opcode == ILOpcode . div_un || opcode == ILOpcode . rem_un )
1527+ if ( opcode is ILOpcode . or or ILOpcode . xor or ILOpcode . shl or ILOpcode . shr or ILOpcode . and or ILOpcode . div_un or ILOpcode . rem_un )
14551528 ThrowHelper . ThrowInvalidProgramException ( ) ;
14561529
14571530 double result = opcode switch
@@ -1467,9 +1540,14 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
14671540 stack . Push ( StackValueKind . Float , ValueTypeValue . FromDouble ( result ) ) ;
14681541 }
14691542 else if ( value1 . ValueKind == StackValueKind . Int64 && value2 . ValueKind == StackValueKind . Int32
1470- && opcode == ILOpcode . shl )
1543+ && opcode is ILOpcode . shl or ILOpcode . shr )
14711544 {
1472- long result = value1 . Value . AsInt64 ( ) << value2 . Value . AsInt32 ( ) ;
1545+ long result = opcode switch
1546+ {
1547+ ILOpcode . shl => value1 . Value . AsInt64 ( ) << value2 . Value . AsInt32 ( ) ,
1548+ ILOpcode . shr => value1 . Value . AsInt64 ( ) >> value2 . Value . AsInt32 ( ) ,
1549+ _ => throw new NotImplementedException ( ) , // unreachable
1550+ } ;
14731551 stack . Push ( isNint ? StackValueKind . NativeInt : StackValueKind . Int64 , ValueTypeValue . FromInt64 ( result ) ) ;
14741552 }
14751553 else if ( ( value1 . ValueKind == StackValueKind . ByRef && value2 . ValueKind != StackValueKind . ByRef )
@@ -1679,6 +1757,8 @@ private Status TryScanMethod(MethodIL methodIL, Value[] parameters, Stack<Method
16791757 case ILOpcode . ldind_i4 :
16801758 case ILOpcode . ldind_u4 :
16811759 case ILOpcode . ldind_i8 :
1760+ case ILOpcode . ldind_r4 :
1761+ case ILOpcode . ldind_r8 :
16821762 {
16831763 if ( opcode == ILOpcode . ldobj )
16841764 {
@@ -1864,12 +1944,49 @@ private static BaseValueTypeValue NewUninitializedLocationValue(TypeDesc locatio
18641944 }
18651945 }
18661946
1867- private bool TryHandleIntrinsicCall ( MethodDesc method , Value [ ] parameters , out Value retVal )
1947+ private bool TryHandleIntrinsicCall ( TypeSystemContext context , MethodDesc method , Value [ ] parameters , out Value retVal )
18681948 {
18691949 retVal = default ;
18701950
18711951 switch ( method . Name )
18721952 {
1953+ case "Memmove" :
1954+ if ( method . OwningType is MetadataType spanHelpersType
1955+ && spanHelpersType . Name == "SpanHelpers" && spanHelpersType . Namespace == "System"
1956+ && spanHelpersType . Module == spanHelpersType . Context . SystemModule
1957+ && parameters [ 0 ] is ByRefValue dest
1958+ && parameters [ 1 ] is ByRefValue src
1959+ && parameters [ 2 ] is ValueTypeValue len )
1960+ {
1961+ int length = context . Target . PointerSize == 8 ? checked ( ( int ) len . AsInt64 ( ) ) : len . AsInt32 ( ) ;
1962+ var srcSpan = new Span < byte > ( src . PointedToBytes , src . PointedToOffset , length ) ;
1963+ var dstSpan = new Span < byte > ( dest . PointedToBytes , dest . PointedToOffset , length ) ;
1964+ srcSpan . CopyTo ( dstSpan ) ;
1965+ return true ;
1966+ }
1967+ return false ;
1968+ case "IsReferenceOrContainsReferences" :
1969+ if ( method . OwningType is MetadataType rtType
1970+ && rtType . Name == "RuntimeHelpers" && rtType . Namespace == "System.Runtime.CompilerServices"
1971+ && rtType . Module == rtType . Context . SystemModule
1972+ && method . Instantiation . Length == 1 )
1973+ {
1974+ var type = method . Instantiation [ 0 ] ;
1975+ bool result = type . IsGCPointer || ( type is DefType { ContainsGCPointers : true } ) ;
1976+ retVal = ValueTypeValue . FromSByte ( result ? ( sbyte ) 1 : ( sbyte ) 0 ) ;
1977+ return true ;
1978+ }
1979+ return false ;
1980+ case "FastAllocateString" :
1981+ if ( method . OwningType is MetadataType stringType
1982+ && stringType . Name == "String" && stringType . Namespace == "System"
1983+ && stringType . Module == stringType . Context . SystemModule
1984+ && parameters [ 0 ] is ValueTypeValue strSize )
1985+ {
1986+ retVal = new StringInstance ( context . GetWellKnownType ( WellKnownType . String ) , new string ( '\0 ' , strSize . AsInt32 ( ) ) ) ;
1987+ return true ;
1988+ }
1989+ return false ;
18731990 case "InitializeArray" :
18741991 if ( method . OwningType is MetadataType mdType
18751992 && mdType . Name == "RuntimeHelpers" && mdType . Namespace == "System.Runtime.CompilerServices"
0 commit comments