@@ -235,6 +235,8 @@ public MethodIL GetMethodILWithInlinedSubstitutions(MethodIL method)
235
235
}
236
236
}
237
237
238
+ var analyzer = new ILPatternAnalyzer < ILPatternAnalyzerState > ( new ILPatternAnalyzerState ( flags ) , method , methodBytes ) ;
239
+
238
240
bool hasGetResourceStringCall = false ;
239
241
240
242
// Mark all reachable basic blocks
@@ -297,7 +299,7 @@ public MethodIL GetMethodILWithInlinedSubstitutions(MethodIL method)
297
299
|| opcode == ILOpcode . brtrue || opcode == ILOpcode . brtrue_s )
298
300
{
299
301
int destination = reader . ReadBranchDestination ( opcode ) ;
300
- if ( ! TryGetConstantArgument ( method , methodBytes , flags , offset , 0 , out int constant ) )
302
+ if ( ! TryGetConstantArgument ( analyzer , offset , 0 , out int constant ) )
301
303
{
302
304
// Can't get the constant - both branches are live.
303
305
offsetsToVisit . Push ( destination ) ;
@@ -323,8 +325,8 @@ public MethodIL GetMethodILWithInlinedSubstitutions(MethodIL method)
323
325
|| opcode == ILOpcode . bne_un || opcode == ILOpcode . bne_un_s )
324
326
{
325
327
int destination = reader . ReadBranchDestination ( opcode ) ;
326
- if ( ! TryGetConstantArgument ( method , methodBytes , flags , offset , 0 , out int left )
327
- || ! TryGetConstantArgument ( method , methodBytes , flags , offset , 1 , out int right ) )
328
+ if ( ! TryGetConstantArgument ( analyzer , offset , 0 , out int left )
329
+ || ! TryGetConstantArgument ( analyzer , offset , 1 , out int right ) )
328
330
{
329
331
// Can't get the constant - both branches are live.
330
332
offsetsToVisit . Push ( destination ) ;
@@ -654,24 +656,24 @@ public MethodIL GetMethodILWithInlinedSubstitutions(MethodIL method)
654
656
return new SubstitutedMethodIL ( method . GetMethodILDefinition ( ) , newBody , newEHRegions . ToArray ( ) , debugInfo , newStrings . ToArray ( ) ) ;
655
657
}
656
658
657
- private bool TryGetConstantArgument ( MethodIL methodIL , byte [ ] body , OpcodeFlags [ ] flags , int offset , int argIndex , out int constant )
659
+ private bool TryGetConstantArgument ( ILPatternAnalyzer < ILPatternAnalyzerState > analyzer , int offset , int argIndex , out int constant )
658
660
{
659
- if ( ( flags [ offset ] & OpcodeFlags . BasicBlockStart ) != 0 )
661
+ if ( analyzer . State . IsBasicBlockStart ( offset ) )
660
662
{
661
663
constant = 0 ;
662
664
return false ;
663
665
}
664
666
665
667
for ( int currentOffset = offset - 1 ; currentOffset >= 0 ; currentOffset -- )
666
668
{
667
- if ( ( flags [ currentOffset ] & OpcodeFlags . InstructionStart ) == 0 )
669
+ if ( ! analyzer . State . IsInstructionStart ( currentOffset ) )
668
670
continue ;
669
671
670
- ILReader reader = new ILReader ( body , currentOffset ) ;
672
+ ILReader reader = new ILReader ( analyzer . ILBytes , currentOffset ) ;
671
673
ILOpcode opcode = reader . ReadILOpcode ( ) ;
672
674
if ( opcode == ILOpcode . call || opcode == ILOpcode . callvirt )
673
675
{
674
- MethodDesc method = ( MethodDesc ) methodIL . GetObject ( reader . ReadILToken ( ) ) ;
676
+ MethodDesc method = ( MethodDesc ) analyzer . Method . GetObject ( reader . ReadILToken ( ) ) ;
675
677
if ( argIndex == 0 )
676
678
{
677
679
BodySubstitution substitution = _substitutionProvider . GetSubstitution ( method ) ;
@@ -684,14 +686,14 @@ private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[
684
686
else if ( method . IsIntrinsic && method . Name is "op_Inequality" or "op_Equality"
685
687
&& method . OwningType is MetadataType mdType
686
688
&& mdType . Name == "Type" && mdType . Namespace == "System" && mdType . Module == mdType . Context . SystemModule
687
- && TryExpandTypeEquality ( methodIL , body , flags , currentOffset , method . Name , out constant ) )
689
+ && TryExpandTypeEquality ( analyzer , currentOffset , method . Name , out constant ) )
688
690
{
689
691
return true ;
690
692
}
691
693
else if ( method . IsIntrinsic && method . Name is "get_IsValueType" or "get_IsEnum"
692
694
&& method . OwningType is MetadataType mdt
693
695
&& mdt . Name == "Type" && mdt . Namespace == "System" && mdt . Module == mdt . Context . SystemModule
694
- && TryExpandTypeIs ( methodIL , body , flags , currentOffset , method . Name , out constant ) )
696
+ && TryExpandTypeIs ( analyzer , currentOffset , method . Name , out constant ) )
695
697
{
696
698
return true ;
697
699
}
@@ -712,7 +714,7 @@ private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[
712
714
}
713
715
else if ( opcode == ILOpcode . ldsfld )
714
716
{
715
- FieldDesc field = ( FieldDesc ) methodIL . GetObject ( reader . ReadILToken ( ) ) ;
717
+ FieldDesc field = ( FieldDesc ) analyzer . Method . GetObject ( reader . ReadILToken ( ) ) ;
716
718
if ( argIndex == 0 )
717
719
{
718
720
object substitution = _substitutionProvider . GetSubstitution ( field ) ;
@@ -762,7 +764,7 @@ private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[
762
764
}
763
765
else if ( ( opcode == ILOpcode . ldloc || opcode == ILOpcode . ldloc_s ||
764
766
( opcode >= ILOpcode . ldloc_0 && opcode <= ILOpcode . ldloc_3 ) ) &&
765
- ( ( flags [ currentOffset ] & OpcodeFlags . BasicBlockStart ) == 0 ) )
767
+ ! analyzer . State . IsBasicBlockStart ( currentOffset ) )
766
768
{
767
769
// Paired stloc/ldloc that the C# compiler generates in debug code?
768
770
int locIndex = opcode switch
@@ -774,10 +776,10 @@ private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[
774
776
775
777
for ( int potentialStlocOffset = currentOffset - 1 ; potentialStlocOffset >= 0 ; potentialStlocOffset -- )
776
778
{
777
- if ( ( flags [ potentialStlocOffset ] & OpcodeFlags . InstructionStart ) == 0 )
779
+ if ( ! analyzer . State . IsInstructionStart ( potentialStlocOffset ) )
778
780
continue ;
779
781
780
- ILReader nestedReader = new ILReader ( body , potentialStlocOffset ) ;
782
+ ILReader nestedReader = new ILReader ( analyzer . ILBytes , potentialStlocOffset ) ;
781
783
ILOpcode otherOpcode = nestedReader . ReadILOpcode ( ) ;
782
784
if ( ( otherOpcode == ILOpcode . stloc || otherOpcode == ILOpcode . stloc_s ||
783
785
( otherOpcode >= ILOpcode . stloc_0 && otherOpcode <= ILOpcode . stloc_3 ) )
@@ -803,8 +805,8 @@ private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[
803
805
{
804
806
if ( argIndex == 0 )
805
807
{
806
- if ( ! TryGetConstantArgument ( methodIL , body , flags , currentOffset , 0 , out int left )
807
- || ! TryGetConstantArgument ( methodIL , body , flags , currentOffset , 1 , out int right ) )
808
+ if ( ! TryGetConstantArgument ( analyzer , currentOffset , 0 , out int left )
809
+ || ! TryGetConstantArgument ( analyzer , currentOffset , 1 , out int right ) )
808
810
{
809
811
constant = 0 ;
810
812
return false ;
@@ -826,15 +828,15 @@ private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[
826
828
return false ;
827
829
}
828
830
829
- if ( ( flags [ currentOffset ] & OpcodeFlags . BasicBlockStart ) != 0 )
831
+ if ( analyzer . State . IsBasicBlockStart ( currentOffset ) )
830
832
break ;
831
833
}
832
834
833
835
constant = 0 ;
834
836
return false ;
835
837
}
836
838
837
- private static bool TryExpandTypeIs ( MethodIL methodIL , byte [ ] body , OpcodeFlags [ ] flags , int offset , string name , out int constant )
839
+ private static bool TryExpandTypeIs ( ILPatternAnalyzer < ILPatternAnalyzerState > analyzer , int offset , string name , out int constant )
838
840
{
839
841
// We expect to see a sequence:
840
842
// ldtoken Foo
@@ -845,16 +847,16 @@ private static bool TryExpandTypeIs(MethodIL methodIL, byte[] body, OpcodeFlags[
845
847
if ( offset < SequenceLength )
846
848
return false ;
847
849
848
- if ( ( flags [ offset - SequenceLength ] & OpcodeFlags . InstructionStart ) == 0 )
850
+ if ( ! analyzer . State . IsInstructionStart ( offset - SequenceLength ) )
849
851
return false ;
850
852
851
- ILReader reader = new ILReader ( body , offset - SequenceLength ) ;
853
+ ILReader reader = new ILReader ( analyzer . ILBytes , offset - SequenceLength ) ;
852
854
853
- TypeDesc type = ReadLdToken ( ref reader , methodIL , flags ) ;
855
+ TypeDesc type = ReadLdToken ( ref reader , analyzer ) ;
854
856
if ( type == null )
855
857
return false ;
856
858
857
- if ( ! ReadGetTypeFromHandle ( ref reader , methodIL , flags ) )
859
+ if ( ! ReadGetTypeFromHandle ( ref reader , analyzer ) )
858
860
return false ;
859
861
860
862
// Dataflow runs on top of uninstantiated IL and we can't answer some questions there.
@@ -873,15 +875,10 @@ private static bool TryExpandTypeIs(MethodIL methodIL, byte[] body, OpcodeFlags[
873
875
return true ;
874
876
}
875
877
876
- private bool TryExpandTypeEquality ( MethodIL methodIL , byte [ ] body , OpcodeFlags [ ] flags , int offset , string op , out int constant )
878
+ private bool TryExpandTypeEquality ( ILPatternAnalyzer < ILPatternAnalyzerState > analyzer , int offset , string op , out int constant )
877
879
{
878
- if ( TryExpandTypeEquality_TokenToken ( methodIL , body , flags , offset , out constant )
879
- || TryExpandTypeEquality_TokenOther ( methodIL , body , flags , offset , 1 , expectGetType : false , out constant )
880
- || TryExpandTypeEquality_TokenOther ( methodIL , body , flags , offset , 2 , expectGetType : false , out constant )
881
- || TryExpandTypeEquality_TokenOther ( methodIL , body , flags , offset , 3 , expectGetType : false , out constant )
882
- || TryExpandTypeEquality_TokenOther ( methodIL , body , flags , offset , 1 , expectGetType : true , out constant )
883
- || TryExpandTypeEquality_TokenOther ( methodIL , body , flags , offset , 2 , expectGetType : true , out constant )
884
- || TryExpandTypeEquality_TokenOther ( methodIL , body , flags , offset , 3 , expectGetType : true , out constant ) )
880
+ if ( TryExpandTypeEquality_TokenToken ( analyzer , offset , out constant )
881
+ || TryExpandTypeEquality_TokenOther ( analyzer , offset , out constant ) )
885
882
{
886
883
if ( op == "op_Inequality" )
887
884
constant ^= 1 ;
@@ -892,36 +889,11 @@ private bool TryExpandTypeEquality(MethodIL methodIL, byte[] body, OpcodeFlags[]
892
889
return false ;
893
890
}
894
891
895
- private static bool TryExpandTypeEquality_TokenToken ( MethodIL methodIL , byte [ ] body , OpcodeFlags [ ] flags , int offset , out int constant )
892
+ private static bool TryExpandTypeEquality_TokenToken ( ILPatternAnalyzer < ILPatternAnalyzerState > analyzer , int offset , out int constant )
896
893
{
897
- // We expect to see a sequence:
898
- // ldtoken Foo
899
- // call GetTypeFromHandle
900
- // ldtoken Bar
901
- // call GetTypeFromHandle
902
- // -> offset points here
903
894
constant = 0 ;
904
- const int SequenceLength = 20 ;
905
- if ( offset < SequenceLength )
906
- return false ;
907
895
908
- if ( ( flags [ offset - SequenceLength ] & OpcodeFlags . InstructionStart ) == 0 )
909
- return false ;
910
-
911
- ILReader reader = new ILReader ( body , offset - SequenceLength ) ;
912
-
913
- TypeDesc type1 = ReadLdToken ( ref reader , methodIL , flags ) ;
914
- if ( type1 == null )
915
- return false ;
916
-
917
- if ( ! ReadGetTypeFromHandle ( ref reader , methodIL , flags ) )
918
- return false ;
919
-
920
- TypeDesc type2 = ReadLdToken ( ref reader , methodIL , flags ) ;
921
- if ( type2 == null )
922
- return false ;
923
-
924
- if ( ! ReadGetTypeFromHandle ( ref reader , methodIL , flags ) )
896
+ if ( ! analyzer . TryAnalyzeTypeEquality_TokenToken ( offset , offsetIsAtTypeEquals : true , out TypeDesc type1 , out TypeDesc type2 ) )
925
897
return false ;
926
898
927
899
// No value in making this work for definitions
@@ -943,84 +915,13 @@ private static bool TryExpandTypeEquality_TokenToken(MethodIL methodIL, byte[] b
943
915
return true ;
944
916
}
945
917
946
- private bool TryExpandTypeEquality_TokenOther ( MethodIL methodIL , byte [ ] body , OpcodeFlags [ ] flags , int offset , int ldInstructionSize , bool expectGetType , out int constant )
918
+ private bool TryExpandTypeEquality_TokenOther ( ILPatternAnalyzer < ILPatternAnalyzerState > analyzer , int offset , out int constant )
947
919
{
948
- // We expect to see a sequence:
949
- // ldtoken Foo
950
- // call GetTypeFromHandle
951
- // ldloc.X/ldloc_s X/ldarg.X/ldarg_s X
952
- // [optional] call Object.GetType
953
- // -> offset points here
954
- //
955
- // The ldtoken part can potentially be in the second argument position
956
-
957
920
constant = 0 ;
958
- int sequenceLength = 5 + 5 + ldInstructionSize + ( expectGetType ? 5 : 0 ) ;
959
- if ( offset < sequenceLength )
960
- return false ;
961
-
962
- if ( ( flags [ offset - sequenceLength ] & OpcodeFlags . InstructionStart ) == 0 )
963
- return false ;
964
-
965
- ILReader reader = new ILReader ( body , offset - sequenceLength ) ;
966
-
967
- TypeDesc knownType = null ;
968
-
969
- // Is the ldtoken in the first position?
970
- if ( reader . PeekILOpcode ( ) == ILOpcode . ldtoken )
971
- {
972
- knownType = ReadLdToken ( ref reader , methodIL , flags ) ;
973
- if ( knownType == null )
974
- return false ;
975
921
976
- if ( ! ReadGetTypeFromHandle ( ref reader , methodIL , flags ) )
977
- return false ;
978
- }
979
-
980
- ILOpcode opcode = reader . ReadILOpcode ( ) ;
981
- if ( ldInstructionSize == 1 && opcode is ( >= ILOpcode . ldloc_0 and <= ILOpcode . ldloc_3 ) or ( >= ILOpcode . ldarg_0 and <= ILOpcode . ldarg_3 ) )
982
- {
983
- // Nothing to read
984
- }
985
- else if ( ldInstructionSize == 2 && opcode is ILOpcode . ldloc_s or ILOpcode . ldarg_s )
986
- {
987
- reader . ReadILByte ( ) ;
988
- }
989
- else if ( ldInstructionSize == 3 && opcode is ILOpcode . ldloc or ILOpcode . ldarg )
990
- {
991
- reader . ReadILUInt16 ( ) ;
992
- }
993
- else
994
- {
995
- return false ;
996
- }
997
-
998
- if ( ( flags [ reader . Offset ] & OpcodeFlags . BasicBlockStart ) != 0 )
922
+ if ( ! analyzer . TryAnalyzeTypeEquality_TokenOther ( offset , offsetIsAtTypeEquals : true , out TypeDesc knownType ) )
999
923
return false ;
1000
924
1001
- if ( expectGetType )
1002
- {
1003
- if ( reader . ReadILOpcode ( ) is not ILOpcode . callvirt and not ILOpcode . call )
1004
- return false ;
1005
-
1006
- // We don't actually mind if this is not Object.GetType
1007
- reader . ReadILToken ( ) ;
1008
-
1009
- if ( ( flags [ reader . Offset ] & OpcodeFlags . BasicBlockStart ) != 0 )
1010
- return false ;
1011
- }
1012
-
1013
- // If the ldtoken wasn't in the first position, it must be in the other
1014
- if ( knownType == null )
1015
- {
1016
- knownType = ReadLdToken ( ref reader , methodIL , flags ) ;
1017
- if ( knownType == null )
1018
- return false ;
1019
-
1020
- if ( ! ReadGetTypeFromHandle ( ref reader , methodIL , flags ) )
1021
- return false ;
1022
- }
1023
-
1024
925
// No value in making this work for definitions
1025
926
if ( knownType . IsGenericDefinition )
1026
927
return false ;
@@ -1045,32 +946,32 @@ private bool TryExpandTypeEquality_TokenOther(MethodIL methodIL, byte[] body, Op
1045
946
return true ;
1046
947
}
1047
948
1048
- private static TypeDesc ReadLdToken ( ref ILReader reader , MethodIL methodIL , OpcodeFlags [ ] flags )
949
+ private static TypeDesc ReadLdToken ( ref ILReader reader , ILPatternAnalyzer < ILPatternAnalyzerState > analyzer )
1049
950
{
1050
951
ILOpcode opcode = reader . ReadILOpcode ( ) ;
1051
952
if ( opcode != ILOpcode . ldtoken )
1052
953
return null ;
1053
954
1054
- TypeDesc t = ( TypeDesc ) methodIL . GetObject ( reader . ReadILToken ( ) ) ;
955
+ TypeDesc t = ( TypeDesc ) analyzer . Method . GetObject ( reader . ReadILToken ( ) ) ;
1055
956
1056
- if ( ( flags [ reader . Offset ] & OpcodeFlags . BasicBlockStart ) != 0 )
957
+ if ( analyzer . State . IsBasicBlockStart ( reader . Offset ) )
1057
958
return null ;
1058
959
1059
960
return t ;
1060
961
}
1061
962
1062
- private static bool ReadGetTypeFromHandle ( ref ILReader reader , MethodIL methodIL , OpcodeFlags [ ] flags )
963
+ private static bool ReadGetTypeFromHandle ( ref ILReader reader , ILPatternAnalyzer < ILPatternAnalyzerState > analyzer )
1063
964
{
1064
965
ILOpcode opcode = reader . ReadILOpcode ( ) ;
1065
966
if ( opcode != ILOpcode . call )
1066
967
return false ;
1067
968
1068
- MethodDesc method = ( MethodDesc ) methodIL . GetObject ( reader . ReadILToken ( ) ) ;
969
+ MethodDesc method = ( MethodDesc ) analyzer . Method . GetObject ( reader . ReadILToken ( ) ) ;
1069
970
1070
971
if ( ! method . IsIntrinsic || method . Name != "GetTypeFromHandle" )
1071
972
return false ;
1072
973
1073
- if ( ( flags [ reader . Offset ] & OpcodeFlags . BasicBlockStart ) != 0 )
974
+ if ( analyzer . State . IsBasicBlockStart ( reader . Offset ) )
1074
975
return false ;
1075
976
1076
977
return true ;
@@ -1135,6 +1036,15 @@ public SubstitutedDebugInformation(MethodDebugInformation originalDebugInformati
1135
1036
public override IEnumerable < ILSequencePoint > GetSequencePoints ( ) => _sequencePoints ;
1136
1037
}
1137
1038
1039
+ private struct ILPatternAnalyzerState : ILPatternAnalyzerTraits
1040
+ {
1041
+ private readonly OpcodeFlags [ ] _flags ;
1042
+ public ILPatternAnalyzerState ( OpcodeFlags [ ] flags ) => _flags = flags ;
1043
+
1044
+ public bool IsBasicBlockStart ( int offset ) => ( _flags [ offset ] & OpcodeFlags . BasicBlockStart ) != 0 ;
1045
+ public bool IsInstructionStart ( int offset ) => ( _flags [ offset ] & OpcodeFlags . InstructionStart ) != 0 ;
1046
+ }
1047
+
1138
1048
private const int TokenTypeString = 0x70 ; // CorTokenType for strings
1139
1049
}
1140
1050
}
0 commit comments