5
5
using System . Collections . Generic ;
6
6
using System . IO ;
7
7
using System . Reflection ;
8
+ using System . Runtime . CompilerServices ;
8
9
using System . Runtime . InteropServices ;
9
10
using System . Text ;
10
11
@@ -827,8 +828,20 @@ static string ILLinkify(string rootedAssembly)
827
828
. UseILProvider ( ilProvider )
828
829
. UsePreinitializationManager ( preinitManager ) ;
829
830
830
- ILScanResults scanResults = null ;
831
+ #if DEBUG
832
+ List < TypeDesc > scannerConstructedTypes = null ;
833
+ List < MethodDesc > scannerCompiledMethods = null ;
834
+ #endif
835
+
831
836
if ( useScanner )
837
+ {
838
+ // Run the scanner in a separate stack frame so that there's no dangling references to
839
+ // it once we're done with it and it can be garbage collected.
840
+ RunScanner ( ) ;
841
+ }
842
+
843
+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
844
+ void RunScanner ( )
832
845
{
833
846
ILScannerBuilder scannerBuilder = builder . GetILScannerBuilder ( )
834
847
. UseCompilationRoots ( compilationRoots )
@@ -842,11 +855,43 @@ static string ILLinkify(string rootedAssembly)
842
855
843
856
IILScanner scanner = scannerBuilder . ToILScanner ( ) ;
844
857
845
- scanResults = scanner . Scan ( ) ;
858
+ ILScanResults scanResults = scanner . Scan ( ) ;
859
+
860
+ #if DEBUG
861
+ scannerCompiledMethods = new List < MethodDesc > ( scanResults . CompiledMethodBodies ) ;
862
+ scannerConstructedTypes = new List < TypeDesc > ( scanResults . ConstructedEETypes ) ;
863
+ #endif
864
+
865
+ if ( _scanDgmlLogFileName != null )
866
+ scanResults . WriteDependencyLog ( _scanDgmlLogFileName ) ;
846
867
847
868
metadataManager = ( ( UsageBasedMetadataManager ) metadataManager ) . ToAnalysisBasedMetadataManager ( ) ;
848
869
849
870
interopStubManager = scanResults . GetInteropStubManager ( interopStateManager , pinvokePolicy ) ;
871
+
872
+ // If we have a scanner, feed the vtable analysis results to the compilation.
873
+ // This could be a command line switch if we really wanted to.
874
+ builder . UseVTableSliceProvider ( scanResults . GetVTableLayoutInfo ( ) ) ;
875
+
876
+ // If we have a scanner, feed the generic dictionary results to the compilation.
877
+ // This could be a command line switch if we really wanted to.
878
+ builder . UseGenericDictionaryLayoutProvider ( scanResults . GetDictionaryLayoutInfo ( ) ) ;
879
+
880
+ // If we have a scanner, we can drive devirtualization using the information
881
+ // we collected at scanning time (effectively sealing unsealed types if possible).
882
+ // This could be a command line switch if we really wanted to.
883
+ builder . UseDevirtualizationManager ( scanResults . GetDevirtualizationManager ( ) ) ;
884
+
885
+ // If we use the scanner's result, we need to consult it to drive inlining.
886
+ // This prevents e.g. devirtualizing and inlining methods on types that were
887
+ // never actually allocated.
888
+ builder . UseInliningPolicy ( scanResults . GetInliningPolicy ( ) ) ;
889
+
890
+ // Use an error provider that prevents us from re-importing methods that failed
891
+ // to import with an exception during scanning phase. We would see the same failure during
892
+ // compilation, but before RyuJIT gets there, it might ask questions that we don't
893
+ // have answers for because we didn't scan the entire method.
894
+ builder . UseMethodImportationErrorProvider ( scanResults . GetMethodImportationErrorProvider ( ) ) ;
850
895
}
851
896
852
897
DebugInformationProvider debugInfoProvider = _enableDebugInfo ?
@@ -874,33 +919,6 @@ static string ILLinkify(string rootedAssembly)
874
919
. UseDebugInfoProvider ( debugInfoProvider )
875
920
. UseDwarf5 ( _useDwarf5 ) ;
876
921
877
- if ( scanResults != null )
878
- {
879
- // If we have a scanner, feed the vtable analysis results to the compilation.
880
- // This could be a command line switch if we really wanted to.
881
- builder . UseVTableSliceProvider ( scanResults . GetVTableLayoutInfo ( ) ) ;
882
-
883
- // If we have a scanner, feed the generic dictionary results to the compilation.
884
- // This could be a command line switch if we really wanted to.
885
- builder . UseGenericDictionaryLayoutProvider ( scanResults . GetDictionaryLayoutInfo ( ) ) ;
886
-
887
- // If we have a scanner, we can drive devirtualization using the information
888
- // we collected at scanning time (effectively sealing unsealed types if possible).
889
- // This could be a command line switch if we really wanted to.
890
- builder . UseDevirtualizationManager ( scanResults . GetDevirtualizationManager ( ) ) ;
891
-
892
- // If we use the scanner's result, we need to consult it to drive inlining.
893
- // This prevents e.g. devirtualizing and inlining methods on types that were
894
- // never actually allocated.
895
- builder . UseInliningPolicy ( scanResults . GetInliningPolicy ( ) ) ;
896
-
897
- // Use an error provider that prevents us from re-importing methods that failed
898
- // to import with an exception during scanning phase. We would see the same failure during
899
- // compilation, but before RyuJIT gets there, it might ask questions that we don't
900
- // have answers for because we didn't scan the entire method.
901
- builder . UseMethodImportationErrorProvider ( scanResults . GetMethodImportationErrorProvider ( ) ) ;
902
- }
903
-
904
922
builder . UseResilience ( _resilient ) ;
905
923
906
924
ICompilation compilation = builder . ToCompilation ( ) ;
@@ -925,21 +943,19 @@ static string ILLinkify(string rootedAssembly)
925
943
if ( _dgmlLogFileName != null )
926
944
compilationResults . WriteDependencyLog ( _dgmlLogFileName ) ;
927
945
928
- if ( scanResults != null )
946
+ #if DEBUG
947
+ if ( scannerConstructedTypes != null )
929
948
{
930
- if ( _scanDgmlLogFileName != null )
931
- scanResults . WriteDependencyLog ( _scanDgmlLogFileName ) ;
932
-
933
949
// If the scanner and compiler don't agree on what to compile, the outputs of the scanner might not actually be usable.
934
950
// We are going to check this two ways:
935
951
// 1. The methods and types generated during compilation are a subset of method and types scanned
936
952
// 2. The methods and types scanned are a subset of methods and types compiled (this has a chance to hold for unoptimized builds only).
937
953
938
954
// Check that methods and types generated during compilation are a subset of method and types scanned
939
955
bool scanningFail = false ;
940
- DiffCompilationResults ( ref scanningFail , compilationResults . CompiledMethodBodies , scanResults . CompiledMethodBodies ,
956
+ DiffCompilationResults ( ref scanningFail , compilationResults . CompiledMethodBodies , scannerCompiledMethods ,
941
957
"Methods" , "compiled" , "scanned" , method => ! ( method . GetTypicalMethodDefinition ( ) is EcmaMethod ) || IsRelatedToInvalidInput ( method ) ) ;
942
- DiffCompilationResults ( ref scanningFail , compilationResults . ConstructedEETypes , scanResults . ConstructedEETypes ,
958
+ DiffCompilationResults ( ref scanningFail , compilationResults . ConstructedEETypes , scannerConstructedTypes ,
943
959
"EETypes" , "compiled" , "scanned" , type => ! ( type . GetTypeDefinition ( ) is EcmaType ) ) ;
944
960
945
961
static bool IsRelatedToInvalidInput ( MethodDesc method )
@@ -963,15 +979,16 @@ static bool IsRelatedToInvalidInput(MethodDesc method)
963
979
964
980
// We additionally skip methods in SIMD module because there's just too many intrisics to handle and IL scanner
965
981
// doesn't expand them. They would show up as noisy diffs.
966
- DiffCompilationResults ( ref dummy , scanResults . CompiledMethodBodies , compilationResults . CompiledMethodBodies ,
982
+ DiffCompilationResults ( ref dummy , scannerCompiledMethods , compilationResults . CompiledMethodBodies ,
967
983
"Methods" , "scanned" , "compiled" , method => ! ( method . GetTypicalMethodDefinition ( ) is EcmaMethod ) || method . OwningType . IsIntrinsic ) ;
968
- DiffCompilationResults ( ref dummy , scanResults . ConstructedEETypes , compilationResults . ConstructedEETypes ,
984
+ DiffCompilationResults ( ref dummy , scannerConstructedTypes , compilationResults . ConstructedEETypes ,
969
985
"EETypes" , "scanned" , "compiled" , type => ! ( type . GetTypeDefinition ( ) is EcmaType ) ) ;
970
986
}
971
987
972
988
if ( scanningFail )
973
989
throw new Exception ( "Scanning failure" ) ;
974
990
}
991
+ #endif
975
992
976
993
if ( debugInfoProvider is IDisposable )
977
994
( ( IDisposable ) debugInfoProvider ) . Dispose ( ) ;
@@ -981,7 +998,6 @@ static bool IsRelatedToInvalidInput(MethodDesc method)
981
998
return 0 ;
982
999
}
983
1000
984
- [ System . Diagnostics . Conditional ( "DEBUG" ) ]
985
1001
private void DiffCompilationResults < T > ( ref bool result , IEnumerable < T > set1 , IEnumerable < T > set2 , string prefix ,
986
1002
string set1name , string set2name , Predicate < T > filter )
987
1003
{
0 commit comments