@@ -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  ||  ! 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