Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit a96f6da

Browse files
Extract shared IL pattern analysis to a class
This fixes the problem discussed at dotnet#102248 (comment). Now we call into the same code from both substitutions and scanner.
1 parent e0bd776 commit a96f6da

File tree

5 files changed

+357
-198
lines changed

5 files changed

+357
-198
lines changed

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/SubstitutedILProvider.cs

Lines changed: 46 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ public MethodIL GetMethodILWithInlinedSubstitutions(MethodIL method)
235235
}
236236
}
237237

238+
var analyzer = new ILPatternAnalyzer<ILPatternAnalyzerState>(new ILPatternAnalyzerState(flags), method, methodBytes);
239+
238240
bool hasGetResourceStringCall = false;
239241

240242
// Mark all reachable basic blocks
@@ -297,7 +299,7 @@ public MethodIL GetMethodILWithInlinedSubstitutions(MethodIL method)
297299
|| opcode == ILOpcode.brtrue || opcode == ILOpcode.brtrue_s)
298300
{
299301
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))
301303
{
302304
// Can't get the constant - both branches are live.
303305
offsetsToVisit.Push(destination);
@@ -323,8 +325,8 @@ public MethodIL GetMethodILWithInlinedSubstitutions(MethodIL method)
323325
|| opcode == ILOpcode.bne_un || opcode == ILOpcode.bne_un_s)
324326
{
325327
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))
328330
{
329331
// Can't get the constant - both branches are live.
330332
offsetsToVisit.Push(destination);
@@ -654,24 +656,24 @@ public MethodIL GetMethodILWithInlinedSubstitutions(MethodIL method)
654656
return new SubstitutedMethodIL(method.GetMethodILDefinition(), newBody, newEHRegions.ToArray(), debugInfo, newStrings.ToArray());
655657
}
656658

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)
658660
{
659-
if ((flags[offset] & OpcodeFlags.BasicBlockStart) != 0)
661+
if (analyzer.State.IsBasicBlockStart(offset))
660662
{
661663
constant = 0;
662664
return false;
663665
}
664666

665667
for (int currentOffset = offset - 1; currentOffset >= 0; currentOffset--)
666668
{
667-
if ((flags[currentOffset] & OpcodeFlags.InstructionStart) == 0)
669+
if (!analyzer.State.IsInstructionStart(currentOffset))
668670
continue;
669671

670-
ILReader reader = new ILReader(body, currentOffset);
672+
ILReader reader = new ILReader(analyzer.ILBytes, currentOffset);
671673
ILOpcode opcode = reader.ReadILOpcode();
672674
if (opcode == ILOpcode.call || opcode == ILOpcode.callvirt)
673675
{
674-
MethodDesc method = (MethodDesc)methodIL.GetObject(reader.ReadILToken());
676+
MethodDesc method = (MethodDesc)analyzer.Method.GetObject(reader.ReadILToken());
675677
if (argIndex == 0)
676678
{
677679
BodySubstitution substitution = _substitutionProvider.GetSubstitution(method);
@@ -684,14 +686,14 @@ private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[
684686
else if (method.IsIntrinsic && method.Name is "op_Inequality" or "op_Equality"
685687
&& method.OwningType is MetadataType mdType
686688
&& 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))
688690
{
689691
return true;
690692
}
691693
else if (method.IsIntrinsic && method.Name is "get_IsValueType" or "get_IsEnum"
692694
&& method.OwningType is MetadataType mdt
693695
&& 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))
695697
{
696698
return true;
697699
}
@@ -712,7 +714,7 @@ private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[
712714
}
713715
else if (opcode == ILOpcode.ldsfld)
714716
{
715-
FieldDesc field = (FieldDesc)methodIL.GetObject(reader.ReadILToken());
717+
FieldDesc field = (FieldDesc)analyzer.Method.GetObject(reader.ReadILToken());
716718
if (argIndex == 0)
717719
{
718720
object substitution = _substitutionProvider.GetSubstitution(field);
@@ -762,7 +764,7 @@ private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[
762764
}
763765
else if ((opcode == ILOpcode.ldloc || opcode == ILOpcode.ldloc_s ||
764766
(opcode >= ILOpcode.ldloc_0 && opcode <= ILOpcode.ldloc_3)) &&
765-
((flags[currentOffset] & OpcodeFlags.BasicBlockStart) == 0))
767+
!analyzer.State.IsBasicBlockStart(currentOffset))
766768
{
767769
// Paired stloc/ldloc that the C# compiler generates in debug code?
768770
int locIndex = opcode switch
@@ -774,10 +776,10 @@ private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[
774776

775777
for (int potentialStlocOffset = currentOffset - 1; potentialStlocOffset >= 0; potentialStlocOffset--)
776778
{
777-
if ((flags[potentialStlocOffset] & OpcodeFlags.InstructionStart) == 0)
779+
if (!analyzer.State.IsInstructionStart(potentialStlocOffset))
778780
continue;
779781

780-
ILReader nestedReader = new ILReader(body, potentialStlocOffset);
782+
ILReader nestedReader = new ILReader(analyzer.ILBytes, potentialStlocOffset);
781783
ILOpcode otherOpcode = nestedReader.ReadILOpcode();
782784
if ((otherOpcode == ILOpcode.stloc || otherOpcode == ILOpcode.stloc_s ||
783785
(otherOpcode >= ILOpcode.stloc_0 && otherOpcode <= ILOpcode.stloc_3))
@@ -803,8 +805,8 @@ private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[
803805
{
804806
if (argIndex == 0)
805807
{
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))
808810
{
809811
constant = 0;
810812
return false;
@@ -826,15 +828,15 @@ private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[
826828
return false;
827829
}
828830

829-
if ((flags[currentOffset] & OpcodeFlags.BasicBlockStart) != 0)
831+
if (analyzer.State.IsBasicBlockStart(currentOffset))
830832
break;
831833
}
832834

833835
constant = 0;
834836
return false;
835837
}
836838

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)
838840
{
839841
// We expect to see a sequence:
840842
// ldtoken Foo
@@ -845,16 +847,16 @@ private static bool TryExpandTypeIs(MethodIL methodIL, byte[] body, OpcodeFlags[
845847
if (offset < SequenceLength)
846848
return false;
847849

848-
if ((flags[offset - SequenceLength] & OpcodeFlags.InstructionStart) == 0)
850+
if (!analyzer.State.IsInstructionStart(offset - SequenceLength))
849851
return false;
850852

851-
ILReader reader = new ILReader(body, offset - SequenceLength);
853+
ILReader reader = new ILReader(analyzer.ILBytes, offset - SequenceLength);
852854

853-
TypeDesc type = ReadLdToken(ref reader, methodIL, flags);
855+
TypeDesc type = ReadLdToken(ref reader, analyzer);
854856
if (type == null)
855857
return false;
856858

857-
if (!ReadGetTypeFromHandle(ref reader, methodIL, flags))
859+
if (!ReadGetTypeFromHandle(ref reader, analyzer))
858860
return false;
859861

860862
// 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[
873875
return true;
874876
}
875877

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)
877879
{
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))
885882
{
886883
if (op == "op_Inequality")
887884
constant ^= 1;
@@ -892,36 +889,11 @@ private bool TryExpandTypeEquality(MethodIL methodIL, byte[] body, OpcodeFlags[]
892889
return false;
893890
}
894891

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)
896893
{
897-
// We expect to see a sequence:
898-
// ldtoken Foo
899-
// call GetTypeFromHandle
900-
// ldtoken Bar
901-
// call GetTypeFromHandle
902-
// -> offset points here
903894
constant = 0;
904-
const int SequenceLength = 20;
905-
if (offset < SequenceLength)
906-
return false;
907895

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))
925897
return false;
926898

927899
// No value in making this work for definitions
@@ -943,84 +915,13 @@ private static bool TryExpandTypeEquality_TokenToken(MethodIL methodIL, byte[] b
943915
return true;
944916
}
945917

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)
947919
{
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-
957920
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;
975921

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))
999923
return false;
1000924

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-
1024925
// No value in making this work for definitions
1025926
if (knownType.IsGenericDefinition)
1026927
return false;
@@ -1045,32 +946,32 @@ private bool TryExpandTypeEquality_TokenOther(MethodIL methodIL, byte[] body, Op
1045946
return true;
1046947
}
1047948

1048-
private static TypeDesc ReadLdToken(ref ILReader reader, MethodIL methodIL, OpcodeFlags[] flags)
949+
private static TypeDesc ReadLdToken(ref ILReader reader, ILPatternAnalyzer<ILPatternAnalyzerState> analyzer)
1049950
{
1050951
ILOpcode opcode = reader.ReadILOpcode();
1051952
if (opcode != ILOpcode.ldtoken)
1052953
return null;
1053954

1054-
TypeDesc t = (TypeDesc)methodIL.GetObject(reader.ReadILToken());
955+
TypeDesc t = (TypeDesc)analyzer.Method.GetObject(reader.ReadILToken());
1055956

1056-
if ((flags[reader.Offset] & OpcodeFlags.BasicBlockStart) != 0)
957+
if (analyzer.State.IsBasicBlockStart(reader.Offset))
1057958
return null;
1058959

1059960
return t;
1060961
}
1061962

1062-
private static bool ReadGetTypeFromHandle(ref ILReader reader, MethodIL methodIL, OpcodeFlags[] flags)
963+
private static bool ReadGetTypeFromHandle(ref ILReader reader, ILPatternAnalyzer<ILPatternAnalyzerState> analyzer)
1063964
{
1064965
ILOpcode opcode = reader.ReadILOpcode();
1065966
if (opcode != ILOpcode.call)
1066967
return false;
1067968

1068-
MethodDesc method = (MethodDesc)methodIL.GetObject(reader.ReadILToken());
969+
MethodDesc method = (MethodDesc)analyzer.Method.GetObject(reader.ReadILToken());
1069970

1070971
if (!method.IsIntrinsic || method.Name != "GetTypeFromHandle")
1071972
return false;
1072973

1073-
if ((flags[reader.Offset] & OpcodeFlags.BasicBlockStart) != 0)
974+
if (analyzer.State.IsBasicBlockStart(reader.Offset))
1074975
return false;
1075976

1076977
return true;
@@ -1135,6 +1036,15 @@ public SubstitutedDebugInformation(MethodDebugInformation originalDebugInformati
11351036
public override IEnumerable<ILSequencePoint> GetSequencePoints() => _sequencePoints;
11361037
}
11371038

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+
11381048
private const int TokenTypeString = 0x70; // CorTokenType for strings
11391049
}
11401050
}

0 commit comments

Comments
 (0)