@@ -29,6 +29,7 @@ internal class Instrumenter
2929 private FieldDefinition _customTrackerHitsFilePath ;
3030 private ILProcessor _customTrackerClassConstructorIl ;
3131 private TypeDefinition _customTrackerTypeDef ;
32+ private MethodReference _customTrackerRegisterUnloadEventsMethod ;
3233 private MethodReference _customTrackerRecordHitMethod ;
3334
3435 public Instrumenter ( string module , string identifier , string [ ] excludeFilters , string [ ] includeFilters , string [ ] excludedFiles , string [ ] excludedAttributes )
@@ -95,13 +96,50 @@ private void InstrumentModule()
9596 }
9697
9798 // Fixup the custom tracker class constructor, according to all instrumented types
99+ if ( _customTrackerRegisterUnloadEventsMethod == null )
100+ {
101+ _customTrackerRegisterUnloadEventsMethod = new MethodReference (
102+ nameof ( ModuleTrackerTemplate . RegisterUnloadEvents ) , module . TypeSystem . Void , _customTrackerTypeDef ) ;
103+ }
104+
98105 Instruction lastInstr = _customTrackerClassConstructorIl . Body . Instructions . Last ( ) ;
106+
107+ var isCoreLibrary = module . Equals ( module . TypeSystem . Void . Module ) ;
108+ if ( ! isCoreLibrary )
109+ {
110+ // For "normal" cases, where the instrumented assembly is not the core library, we add a call to
111+ // RegisterUnloadEvents to the static constructor of the generated custom tracker. Due to static
112+ // initialization constraints, the core library is handled separately below.
113+ _customTrackerClassConstructorIl . InsertBefore ( lastInstr , Instruction . Create ( OpCodes . Call , _customTrackerRegisterUnloadEventsMethod ) ) ;
114+ }
115+
99116 _customTrackerClassConstructorIl . InsertBefore ( lastInstr , Instruction . Create ( OpCodes . Ldc_I4 , _result . HitCandidates . Count ) ) ;
100117 _customTrackerClassConstructorIl . InsertBefore ( lastInstr , Instruction . Create ( OpCodes . Newarr , module . TypeSystem . Int32 ) ) ;
101118 _customTrackerClassConstructorIl . InsertBefore ( lastInstr , Instruction . Create ( OpCodes . Stsfld , _customTrackerHitsArray ) ) ;
102119 _customTrackerClassConstructorIl . InsertBefore ( lastInstr , Instruction . Create ( OpCodes . Ldstr , _result . HitsFilePath ) ) ;
103120 _customTrackerClassConstructorIl . InsertBefore ( lastInstr , Instruction . Create ( OpCodes . Stsfld , _customTrackerHitsFilePath ) ) ;
104121
122+ if ( isCoreLibrary )
123+ {
124+ // Handle the core library by instrumenting System.AppContext.OnProcessExit to directly call
125+ // the UnloadModule method of the custom tracker type. This avoids loops between the static
126+ // initialization of the custom tracker and the static initialization of the hosting AppDomain
127+ // (which for the core library case will be instrumented code).
128+ var eventArgsType = new TypeReference ( nameof ( System ) , nameof ( EventArgs ) , module , module . TypeSystem . CoreLibrary ) . Resolve ( ) ;
129+ var customTrackerUnloadModule = new MethodReference ( nameof ( ModuleTrackerTemplate . UnloadModule ) , module . TypeSystem . Void , _customTrackerTypeDef ) ;
130+ customTrackerUnloadModule . Parameters . Add ( new ParameterDefinition ( module . TypeSystem . Object ) ) ;
131+ customTrackerUnloadModule . Parameters . Add ( new ParameterDefinition ( eventArgsType ) ) ;
132+
133+ var appContextType = new TypeReference ( nameof ( System ) , nameof ( AppContext ) , module , module . TypeSystem . CoreLibrary ) . Resolve ( ) ;
134+ var onProcessExitMethod = new MethodReference ( "OnProcessExit" , module . TypeSystem . Void , appContextType ) . Resolve ( ) ;
135+ var onProcessExitIl = onProcessExitMethod . Body . GetILProcessor ( ) ;
136+
137+ lastInstr = onProcessExitIl . Body . Instructions . Last ( ) ;
138+ onProcessExitIl . InsertBefore ( lastInstr , Instruction . Create ( OpCodes . Ldnull ) ) ;
139+ onProcessExitIl . InsertBefore ( lastInstr , Instruction . Create ( OpCodes . Ldnull ) ) ;
140+ onProcessExitIl . InsertBefore ( lastInstr , Instruction . Create ( OpCodes . Call , customTrackerUnloadModule ) ) ;
141+ }
142+
105143 module . Write ( stream ) ;
106144 }
107145 }
@@ -135,12 +173,9 @@ private void AddCustomModuleTrackerToModule(ModuleDefinition module)
135173 {
136174 MethodDefinition methodOnCustomType = new MethodDefinition ( methodDef . Name , methodDef . Attributes , methodDef . ReturnType ) ;
137175
138- if ( methodDef . Name == "RecordHit" )
176+ foreach ( var parameter in methodDef . Parameters )
139177 {
140- foreach ( var parameter in methodDef . Parameters )
141- {
142- methodOnCustomType . Parameters . Add ( new ParameterDefinition ( module . ImportReference ( parameter . ParameterType ) ) ) ;
143- }
178+ methodOnCustomType . Parameters . Add ( new ParameterDefinition ( module . ImportReference ( parameter . ParameterType ) ) ) ;
144179 }
145180
146181 foreach ( var variable in methodDef . Body . Variables )
0 commit comments