99
1010using Debug = System . Diagnostics . Debug ;
1111using DependencyList = ILCompiler . DependencyAnalysisFramework . DependencyNodeCore < ILCompiler . DependencyAnalysis . NodeFactory > . DependencyList ;
12+ using CombinedDependencyList = System . Collections . Generic . List < ILCompiler . DependencyAnalysisFramework . DependencyNodeCore < ILCompiler . DependencyAnalysis . NodeFactory > . CombinedDependencyListEntry > ;
13+ using DependencyListEntry = ILCompiler . DependencyAnalysisFramework . DependencyNodeCore < ILCompiler . DependencyAnalysis . NodeFactory > . DependencyListEntry ;
1214
1315#pragma warning disable IDE0060
1416
@@ -28,7 +30,7 @@ internal partial class ILImporter
2830
2931 private readonly MethodDesc _canonMethod ;
3032
31- private DependencyList _dependencies = new DependencyList ( ) ;
33+ private DependencyList _unconditionalDependencies = new DependencyList ( ) ;
3234
3335 private readonly byte [ ] _ilBytes ;
3436
@@ -51,11 +53,17 @@ public enum ImportState : byte
5153 public bool TryStart ;
5254 public bool FilterStart ;
5355 public bool HandlerStart ;
56+
57+ public object Condition ;
58+ public DependencyList Dependencies ;
5459 }
5560
5661 private bool _isReadOnly ;
5762 private TypeDesc _constrained ;
5863
64+ private DependencyList _dependencies ;
65+ private BasicBlock _lateBasicBlocks ;
66+
5967 private sealed class ExceptionRegion
6068 {
6169 public ILExceptionRegion ILRegion ;
@@ -107,9 +115,11 @@ public ILImporter(ILScanner compilation, MethodDesc method, MethodIL methodIL =
107115 {
108116 _exceptionRegions [ i ] = new ExceptionRegion ( ) { ILRegion = ilExceptionRegions [ i ] } ;
109117 }
118+
119+ _dependencies = _unconditionalDependencies ;
110120 }
111121
112- public DependencyList Import ( )
122+ public ( DependencyList , CombinedDependencyList ) Import ( )
113123 {
114124 TypeDesc owningType = _canonMethod . OwningType ;
115125 if ( _compilation . HasLazyStaticConstructor ( owningType ) )
@@ -172,9 +182,21 @@ public DependencyList Import()
172182 FindBasicBlocks ( ) ;
173183 ImportBasicBlocks ( ) ;
174184
175- CodeBasedDependencyAlgorithm . AddDependenciesDueToMethodCodePresence ( ref _dependencies , _factory , _canonMethod , _canonMethodIL ) ;
185+ CombinedDependencyList conditionalDependencies = null ;
186+ foreach ( BasicBlock bb in _basicBlocks )
187+ {
188+ if ( bb ? . Condition == null )
189+ continue ;
190+
191+ conditionalDependencies ??= new CombinedDependencyList ( ) ;
192+ foreach ( DependencyListEntry dep in bb . Dependencies )
193+ conditionalDependencies . Add ( new ( dep . Node , bb . Condition , dep . Reason ) ) ;
194+ }
195+
196+ CodeBasedDependencyAlgorithm . AddDependenciesDueToMethodCodePresence ( ref _unconditionalDependencies , _factory , _canonMethod , _canonMethodIL ) ;
197+ CodeBasedDependencyAlgorithm . AddConditionalDependenciesDueToMethodCodePresence ( ref conditionalDependencies , _factory , _canonMethod ) ;
176198
177- return _dependencies ;
199+ return ( _unconditionalDependencies , conditionalDependencies ) ;
178200 }
179201
180202 private ISymbolNode GetGenericLookupHelper ( ReadyToRunHelperId helperId , object helperArgument )
@@ -199,19 +221,29 @@ private ISymbolNode GetHelperEntrypoint(ReadyToRunHelper helper)
199221 }
200222
201223 private static void MarkInstructionBoundary ( ) { }
202- private static void EndImportingBasicBlock ( BasicBlock basicBlock ) { }
224+
225+ private void EndImportingBasicBlock ( BasicBlock basicBlock )
226+ {
227+ if ( _pendingBasicBlocks == null )
228+ {
229+ _pendingBasicBlocks = _lateBasicBlocks ;
230+ _lateBasicBlocks = null ;
231+ }
232+ }
203233
204234 private void StartImportingBasicBlock ( BasicBlock basicBlock )
205235 {
236+ _dependencies = basicBlock . Condition != null ? basicBlock . Dependencies : _unconditionalDependencies ;
237+
206238 // Import all associated EH regions
207239 foreach ( ExceptionRegion ehRegion in _exceptionRegions )
208240 {
209241 ILExceptionRegion region = ehRegion . ILRegion ;
210242 if ( region . TryOffset == basicBlock . StartOffset )
211243 {
212- MarkBasicBlock ( _basicBlocks [ region . HandlerOffset ] ) ;
244+ ImportBasicBlockEdge ( basicBlock , _basicBlocks [ region . HandlerOffset ] ) ;
213245 if ( region . Kind == ILExceptionRegionKind . Filter )
214- MarkBasicBlock ( _basicBlocks [ region . FilterOffset ] ) ;
246+ ImportBasicBlockEdge ( basicBlock , _basicBlocks [ region . FilterOffset ] ) ;
215247
216248 if ( region . Kind == ILExceptionRegionKind . Catch )
217249 {
@@ -789,10 +821,26 @@ private void ImportCalli(int token)
789821
790822 private void ImportBranch ( ILOpcode opcode , BasicBlock target , BasicBlock fallthrough )
791823 {
824+ object condition = null ;
825+
826+ if ( opcode == ILOpcode . brfalse
827+ && _typeEqualityPatternAnalyzer . IsTypeEqualityBranch
828+ && ! _typeEqualityPatternAnalyzer . IsTwoTokens
829+ && ! _typeEqualityPatternAnalyzer . IsInequality )
830+ {
831+ TypeDesc typeEqualityCheckType = ( TypeDesc ) _canonMethodIL . GetObject ( _typeEqualityPatternAnalyzer . Token1 ) ;
832+ if ( ! typeEqualityCheckType . IsGenericDefinition
833+ && ConstructedEETypeNode . CreationAllowed ( typeEqualityCheckType )
834+ && ! typeEqualityCheckType . ConvertToCanonForm ( CanonicalFormKind . Specific ) . IsCanonicalSubtype ( CanonicalFormKind . Any ) )
835+ {
836+ condition = _factory . MaximallyConstructableType ( typeEqualityCheckType ) ;
837+ }
838+ }
839+
792840 ImportFallthrough ( target ) ;
793841
794842 if ( fallthrough != null )
795- ImportFallthrough ( fallthrough ) ;
843+ ImportFallthrough ( fallthrough , condition ) ;
796844 }
797845
798846 private void ImportSwitchJump ( int jmpBase , int [ ] jmpDelta , BasicBlock fallthrough )
@@ -1278,9 +1326,56 @@ private void ImportConvert(WellKnownType wellKnownType, bool checkOverflow, bool
12781326 }
12791327 }
12801328
1281- private void ImportFallthrough ( BasicBlock next )
1329+ private void ImportBasicBlockEdge ( BasicBlock source , BasicBlock next , object condition = null )
1330+ {
1331+ // We don't track multiple conditions; if the source basic block is only reachable under a condition,
1332+ // this condition will be used for the next basic block, irrespective if we could make it more narrow.
1333+ object effectiveCondition = source . Condition ?? condition ;
1334+
1335+ // Did we already look at this basic block?
1336+ if ( next . State != BasicBlock . ImportState . Unmarked )
1337+ {
1338+ // If next is not conditioned, it stays not conditioned.
1339+ // If it was conditioned on something else, it needs to become unconditional.
1340+ // If the conditions match, it stays conditioned on the same thing.
1341+ if ( next . Condition != null && next . Condition != effectiveCondition )
1342+ {
1343+ // Now we need to make `next` not conditioned. We move all of its dependencies to
1344+ // unconditional dependencies, and do this for all basic blocks that are reachable
1345+ // from it.
1346+ // TODO-SIZE: below doesn't do it for all basic blocks reachable from `next`, but
1347+ // for all basic blocks with the same conditon. This is a shortcut. It likely
1348+ // doesn't matter in practice.
1349+ object conditionToRemove = next . Condition ;
1350+ foreach ( BasicBlock bb in _basicBlocks )
1351+ {
1352+ if ( bb ? . Condition == conditionToRemove )
1353+ {
1354+ _unconditionalDependencies . AddRange ( bb . Dependencies ) ;
1355+ bb . Dependencies = null ;
1356+ bb . Condition = null ;
1357+ }
1358+ }
1359+ }
1360+ }
1361+ else
1362+ {
1363+ if ( effectiveCondition != null )
1364+ {
1365+ next . Condition = effectiveCondition ;
1366+ next . Dependencies = new DependencyList ( ) ;
1367+ MarkBasicBlock ( next , ref _lateBasicBlocks ) ;
1368+ }
1369+ else
1370+ {
1371+ MarkBasicBlock ( next ) ;
1372+ }
1373+ }
1374+ }
1375+
1376+ private void ImportFallthrough ( BasicBlock next , object condition = null )
12821377 {
1283- MarkBasicBlock ( next ) ;
1378+ ImportBasicBlockEdge ( _currentBasicBlock , next , condition ) ;
12841379 }
12851380
12861381 private int ReadILTokenAt ( int ilOffset )
0 commit comments