2a9c9e78a3229dbb8d0d3cba3970084730485c5f
[platform/upstream/coreclr.git] / src / vm / rejit.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //
5 // ReJit.cpp
6 //
7
8 // 
9 // This module implements the tracking and execution of rejit requests. In order to avoid
10 // any overhead on the non-profiled case we don't intrude on any 'normal' data structures
11 // except one member on the AppDomain to hold our main hashtable and crst (the
12 // ReJitManager). See comments in rejit.h to understand relationships between ReJitInfo,
13 // SharedReJitInfo, and ReJitManager, particularly SharedReJitInfo::InternalFlags which
14 // capture the state of a rejit request, and ReJitInfo::InternalFlags which captures the
15 // state of a particular MethodDesc from a rejit request.
16 // 
17 // A ReJIT request (tracked via SharedReJitInfo) is made at the level of a (Module *,
18 // methodDef) pair, and thus affects all instantiations of a generic. Each MethodDesc
19 // affected by a ReJIT request has its state tracked via a ReJitInfo instance. A
20 // ReJitInfo can represent a rejit request against an already-jitted MethodDesc, or a
21 // rejit request against a not-yet-jitted MethodDesc (called a "pre-rejit" request). A
22 // Pre-ReJIT request happens when a profiler specifies a (Module *, methodDef) pair that
23 // has not yet been JITted, or that represents a generic function which always has the
24 // potential to JIT new instantiations in the future.
25 // 
26 // Top-level functions in this file of most interest are:
27 // 
28 // * (static) code:ReJitManager::RequestReJIT:
29 // Profiling API just delegates all rejit requests directly to this function. It is
30 // responsible for recording the request into the appropriate ReJITManagers and for
31 // jump-stamping any already-JITted functions affected by the request (so that future
32 // calls hit the prestub)
33 // 
34 // * code:ReJitManager::DoReJitIfNecessary:
35 // MethodDesc::DoPrestub calls this to determine whether it's been invoked to do a rejit.
36 // If so, ReJitManager::DoReJitIfNecessary is responsible for (indirectly) gathering the
37 // appropriate IL and codegen flags, calling UnsafeJitFunction(), and redirecting the
38 // jump-stamp from the prestub to the newly-rejitted code.
39 // 
40 // * code:PublishMethodHolder::PublishMethodHolder
41 // MethodDesc::MakeJitWorker() calls this to determine if there's an outstanding
42 // "pre-rejit" request for a MethodDesc that has just been jitted for the first time. We
43 // also call this from MethodDesc::CheckRestore when restoring generic methods.
44 // The holder applies the jump-stamp to the
45 // top of the originally JITted code, with the jump target being the prestub.
46 // When ReJIT is enabled this holder enters the ReJIT
47 // lock to enforce atomicity of doing the pre-rejit-jmp-stamp & publishing/restoring
48 // the PCODE, which is required to avoid races with a profiler that calls RequestReJIT
49 // just as the method finishes compiling/restoring.
50 //
51 // * code:PublishMethodTableHolder::PublishMethodTableHolder
52 // Does the same thing as PublishMethodHolder except iterating over every
53 // method in the MethodTable. This is called from MethodTable::SetIsRestored.
54 // 
55 // * code:ReJitManager::GetCurrentReJitFlags:
56 // CEEInfo::canInline() calls this as part of its calculation of whether it may inline a
57 // given method. (Profilers may specify on a per-rejit-request basis whether the rejit of
58 // a method may inline callees.)
59 // 
60 //
61 // #Invariants:
62 //
63 // For a given Module/MethodDef there is at most 1 SharedReJitInfo that is not Reverted,
64 // though there may be many that are in the Reverted state. If a method is rejitted
65 // multiple times, with multiple versions actively in use on the stacks, then all but the
66 // most recent are put into the Reverted state even though they may not yet be physically
67 // reverted and pitched yet.
68 //
69 // For a given MethodDesc there is at most 1 ReJitInfo in the kJumpToPrestub or kJumpToRejittedCode
70 // state.
71 // 
72 // The ReJitManager::m_crstTable lock is held whenever reading or writing to that
73 // ReJitManager instance's table (including state transitions applied to the ReJitInfo &
74 // SharedReJitInfo instances stored in that table).
75 //
76 // The ReJitManager::m_crstTable lock is never held during callbacks to the profiler
77 // such as GetReJITParameters, ReJITStarted, JITComplete, ReportReJITError
78 //
79 // Any thread holding the ReJitManager::m_crstTable lock can't block during runtime suspension
80 // therefore it can't call any GC_TRIGGERS functions
81 //
82 // Transitions between SharedRejitInfo states happen only in the following cicumstances:
83 //   1) New SharedRejitInfo added to table (Requested State)
84 //      Inside RequestRejit
85 //      Global Crst held, table Crst held
86 //
87 //   2) Requested -> GettingReJITParameters
88 //      Inside DoRejitIfNecessary
89 //      Global Crst NOT held, table Crst held
90 //
91 //   3) GettingReJITParameters -> Active
92 //      Inside DoRejitIfNecessary
93 //      Global Crst NOT held, table Crst held
94 //
95 //   4) * -> Reverted
96 //      Inside RequestRejit or RequestRevert
97 //      Global Crst held, table Crst held
98 //
99 //
100 // Transitions between RejitInfo states happen only in the following circumstances:
101 //   1) New RejitInfo added to table (kJumpNone state)
102 //      Inside RequestRejit, DoJumpStampIfNecessary
103 //      Global Crst MAY/MAY NOT be held, table Crst held
104 //      Allowed SharedReJit states: Requested, GettingReJITParameters, Active
105 //
106 //   2) kJumpNone -> kJumpToPrestub
107 //      Inside RequestRejit, DoJumpStampIfNecessary
108 //      Global Crst MAY/MAY NOT be held, table Crst held
109 //      Allowed SharedReJit states: Requested, GettingReJITParameters, Active
110 //
111 //   3) kJumpToPreStub -> kJumpToRejittedCode
112 //      Inside DoReJitIfNecessary
113 //      Global Crst NOT held, table Crst held
114 //      Allowed SharedReJit states: Active
115 //
116 //   4) * -> kJumpNone
117 //      Inside RequestRevert, RequestRejit
118 //      Global Crst held, table crst held
119 //      Allowed SharedReJit states: Reverted
120 //
121 //
122 // #Beware Invariant misconceptions - don't make bad assumptions!
123 //   Even if a SharedReJitInfo is in the Reverted state:
124 //     a) RejitInfos may still be in the kJumpToPreStub or kJumpToRejittedCode state
125 //        Reverted really just means the runtime has started reverting, but it may not
126 //        be complete yet on the thread executing Revert or RequestRejit.
127 //     b) The code for this version of the method may be executing on any number of
128 //        threads. Even after transitioning all rejit infos to kJumpNone state we
129 //        have no power to abort or hijack threads already running the rejitted code.
130 //
131 //   Even if a SharedReJitInfo is in the Active state:
132 //     a) The corresponding ReJitInfos may not be jump-stamped yet.
133 //        Some thread is still in the progress of getting this thread jump-stamped
134 //        OR it is a place-holder ReJitInfo.
135 //     b) An older ReJitInfo linked to a reverted SharedReJitInfo could still be
136 //        in kJumpToPreStub or kJumpToReJittedCode state. RequestRejit is still in
137 //        progress on some thread.
138 //
139 //
140 // #Known issues with REJIT at this time:
141 //   NGEN inlined methods will not be properly rejitted
142 //   Exception callstacks through rejitted code do not produce correct StackTraces
143 //   Live debugging is not supported when rejit is enabled
144 //   Rejit leaks rejitted methods, RejitInfos, and SharedRejitInfos until AppDomain unload
145 //   Dump debugging doesn't correctly locate RejitInfos that are keyed by MethodDesc
146 //   Metadata update creates large memory increase switching to RW (not specifically a rejit issue)
147 // 
148 // ======================================================================================
149
150 #include "common.h"
151 #include "rejit.h"
152 #include "method.hpp"
153 #include "eeconfig.h"
154 #include "methoditer.h"
155 #include "dbginterface.h"
156 #include "threadsuspend.h"
157
158 #ifdef FEATURE_REJIT
159 #ifdef FEATURE_CODE_VERSIONING
160
161 #include "../debug/ee/debugger.h"
162 #include "../debug/ee/walker.h"
163 #include "../debug/ee/controller.h"
164 #include "codeversion.h"
165
166 // This HRESULT is only used as a private implementation detail. Corerror.xml has a comment in it
167 //  reserving this value for our use but it doesn't appear in the public headers.
168 #define CORPROF_E_RUNTIME_SUSPEND_REQUIRED 0x80131381
169
170 // This is just used as a unique id. Overflow is OK. If we happen to have more than 4+Billion rejits
171 // and somehow manage to not run out of memory, we'll just have to redefine ReJITID as size_t.
172 /* static */
173 static ReJITID s_GlobalReJitId = 1;
174
175 /* static */
176 CrstStatic ReJitManager::s_csGlobalRequest;
177
178
179 //---------------------------------------------------------------------------------------
180 // Helpers
181
182 //static
183 CORJIT_FLAGS ReJitManager::JitFlagsFromProfCodegenFlags(DWORD dwCodegenFlags)
184 {
185     LIMITED_METHOD_DAC_CONTRACT;
186
187     CORJIT_FLAGS jitFlags;
188     if ((dwCodegenFlags & COR_PRF_CODEGEN_DISABLE_ALL_OPTIMIZATIONS) != 0)
189     {
190         jitFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_DEBUG_CODE);
191     }
192     if ((dwCodegenFlags & COR_PRF_CODEGEN_DISABLE_INLINING) != 0)
193     {
194         jitFlags.Set(CORJIT_FLAGS::CORJIT_FLAG_NO_INLINING);
195     }
196
197     // In the future more flags may be added that need to be converted here (e.g.,
198     // COR_PRF_CODEGEN_ENTERLEAVE / CORJIT_FLAG_PROF_ENTERLEAVE)
199
200     return jitFlags;
201 }
202
203 //---------------------------------------------------------------------------------------
204 // ProfilerFunctionControl implementation
205
206 ProfilerFunctionControl::ProfilerFunctionControl(LoaderHeap * pHeap) :
207     m_refCount(1),
208     m_pHeap(pHeap),
209     m_dwCodegenFlags(0),
210     m_cbIL(0),
211     m_pbIL(NULL),
212     m_cInstrumentedMapEntries(0),
213     m_rgInstrumentedMapEntries(NULL)
214 {
215     LIMITED_METHOD_CONTRACT;
216 }
217
218 ProfilerFunctionControl::~ProfilerFunctionControl()
219 {
220     LIMITED_METHOD_CONTRACT;
221
222     // Intentionally not deleting m_pbIL or m_rgInstrumentedMapEntries, as its ownership gets transferred to the
223     // SharedReJitInfo that manages that rejit request.
224 }
225
226
227 HRESULT ProfilerFunctionControl::QueryInterface(REFIID id, void** pInterface)
228 {
229     LIMITED_METHOD_CONTRACT;
230
231     if ((id != IID_IUnknown) &&
232         (id != IID_ICorProfilerFunctionControl))
233     {
234         *pInterface = NULL;
235         return E_NOINTERFACE;
236     }
237
238     *pInterface = this;
239     this->AddRef();
240     return S_OK;
241 }
242
243 ULONG ProfilerFunctionControl::AddRef()
244 {
245     LIMITED_METHOD_CONTRACT;
246
247     return InterlockedIncrement(&m_refCount);
248 }
249
250 ULONG ProfilerFunctionControl::Release()
251 {
252     LIMITED_METHOD_CONTRACT;
253
254     ULONG refCount = InterlockedDecrement(&m_refCount);
255
256     if (0 == refCount)
257     {
258         delete this;
259     }
260
261     return refCount;
262 }
263
264 //---------------------------------------------------------------------------------------
265 //
266 // Profiler calls this to specify a set of flags from COR_PRF_CODEGEN_FLAGS
267 // to control rejitting a particular methodDef.
268 //
269 // Arguments:
270 //    * flags - set of flags from COR_PRF_CODEGEN_FLAGS
271 //
272 // Return Value:
273 //    Always S_OK;
274 //
275
276 HRESULT ProfilerFunctionControl::SetCodegenFlags(DWORD flags)
277 {
278     LIMITED_METHOD_CONTRACT;
279
280     m_dwCodegenFlags = flags;
281     return S_OK;
282 }
283
284 //---------------------------------------------------------------------------------------
285 //
286 // Profiler calls this to specify the IL to use when rejitting a particular methodDef.
287 //
288 // Arguments:
289 //    * cbNewILMethodHeader - Size in bytes of pbNewILMethodHeader
290 //    * pbNewILMethodHeader - Pointer to beginning of IL header + IL bytes.
291 //
292 // Return Value:
293 //    HRESULT indicating success or failure.
294 //
295 // Notes:
296 //    Caller owns allocating and freeing pbNewILMethodHeader as expected. 
297 //    SetILFunctionBody copies pbNewILMethodHeader into a separate buffer.
298 //
299
300 HRESULT ProfilerFunctionControl::SetILFunctionBody(ULONG cbNewILMethodHeader, LPCBYTE pbNewILMethodHeader)
301 {
302     CONTRACTL
303     {
304         NOTHROW;
305         GC_NOTRIGGER;
306         MODE_ANY;
307     }
308     CONTRACTL_END;
309
310     if (cbNewILMethodHeader == 0)
311     {
312         return E_INVALIDARG;
313     }
314
315     if (pbNewILMethodHeader == NULL)
316     {
317         return E_INVALIDARG;
318     }
319
320     _ASSERTE(m_cbIL == 0);
321     _ASSERTE(m_pbIL == NULL);
322
323 #ifdef DACCESS_COMPILE
324     m_pbIL = new (nothrow) BYTE[cbNewILMethodHeader];
325 #else
326     // IL is stored on the appropriate loader heap, and its memory will be owned by the
327     // SharedReJitInfo we copy the pointer to.
328     m_pbIL = (LPBYTE) (void *) m_pHeap->AllocMem_NoThrow(S_SIZE_T(cbNewILMethodHeader));
329 #endif
330     if (m_pbIL == NULL)
331     {
332         return E_OUTOFMEMORY;
333     }
334
335     m_cbIL = cbNewILMethodHeader;
336     memcpy(m_pbIL, pbNewILMethodHeader, cbNewILMethodHeader);
337
338     return S_OK;
339 }
340
341 HRESULT ProfilerFunctionControl::SetILInstrumentedCodeMap(ULONG cILMapEntries, COR_IL_MAP * rgILMapEntries)
342 {
343 #ifdef DACCESS_COMPILE
344     // I'm not sure why any of these methods would need to be compiled in DAC? Could we remove the
345     // entire class from the DAC'ized code build?
346     _ASSERTE(!"This shouldn't be called in DAC");
347     return E_NOTIMPL;
348 #else
349
350     CONTRACTL
351     {
352         NOTHROW;
353         GC_NOTRIGGER;
354         MODE_ANY;
355     }
356     CONTRACTL_END;
357
358     if (cILMapEntries >= (MAXULONG / sizeof(COR_IL_MAP)))
359     {
360         // Too big!  The allocation below would overflow when calculating the size.
361         return E_INVALIDARG;
362     }
363
364     if (g_pDebugInterface == NULL)
365     {
366         return CORPROF_E_DEBUGGING_DISABLED;
367     }
368
369
370     // copy the il map and il map entries into the corresponding fields.
371     m_cInstrumentedMapEntries = cILMapEntries;
372
373     // IL is stored on the appropriate loader heap, and its memory will be owned by the
374     // SharedReJitInfo we copy the pointer to.
375     m_rgInstrumentedMapEntries = (COR_IL_MAP*) (void *) m_pHeap->AllocMem_NoThrow(S_SIZE_T(cILMapEntries * sizeof(COR_IL_MAP)));
376
377     if (m_rgInstrumentedMapEntries == NULL)
378         return E_OUTOFMEMORY;
379
380
381     memcpy_s(m_rgInstrumentedMapEntries, sizeof(COR_IL_MAP) * cILMapEntries, rgILMapEntries, sizeof(COR_IL_MAP) * cILMapEntries);
382
383     return S_OK;
384 #endif // DACCESS_COMPILE
385 }
386
387 //---------------------------------------------------------------------------------------
388 //
389 // ReJitManager may use this to access the codegen flags the profiler had set on this
390 // ICorProfilerFunctionControl.
391 //
392 // Return Value:
393 //     * codegen flags previously set via SetCodegenFlags; 0 if none were set.
394 //
395 DWORD ProfilerFunctionControl::GetCodegenFlags()
396 {
397     return m_dwCodegenFlags;
398 }
399
400 //---------------------------------------------------------------------------------------
401 //
402 // ReJitManager may use this to access the IL header + instructions the
403 // profiler had set on this ICorProfilerFunctionControl via SetIL
404 //
405 // Return Value:
406 //     * Pointer to ProfilerFunctionControl-allocated buffer containing the
407 //         IL header and instructions the profiler had provided.
408 //
409 LPBYTE ProfilerFunctionControl::GetIL()
410 {
411     return m_pbIL;
412 }
413
414 //---------------------------------------------------------------------------------------
415 //
416 // ReJitManager may use this to access the count of instrumented map entry flags the 
417 // profiler had set on this ICorProfilerFunctionControl.
418 //
419 // Return Value:
420 //    * size of the instrumented map entry array
421 //
422 ULONG ProfilerFunctionControl::GetInstrumentedMapEntryCount()
423 {
424     return m_cInstrumentedMapEntries;
425 }
426
427 //---------------------------------------------------------------------------------------
428 //
429 // ReJitManager may use this to access the instrumented map entries the 
430 // profiler had set on this ICorProfilerFunctionControl.
431 //
432 // Return Value:
433 //    * the array of instrumented map entries
434 //
435 COR_IL_MAP* ProfilerFunctionControl::GetInstrumentedMapEntries()
436 {
437     return m_rgInstrumentedMapEntries;
438 }
439
440 //---------------------------------------------------------------------------------------
441 // ReJitManager implementation
442
443 // All the state-changey stuff is kept up here in the !DACCESS_COMPILE block.
444 // The more read-only inspection-y stuff follows the block.
445
446 #ifndef DACCESS_COMPILE
447
448 //---------------------------------------------------------------------------------------
449 //
450 // ICorProfilerInfo4::RequestReJIT calls into this guy to do most of the
451 // work. Takes care of finding the appropriate ReJitManager instances to
452 // record the rejit requests and perform jmp-stamping.
453 //
454 // Arguments:
455 //    * cFunctions - Element count of rgModuleIDs & rgMethodDefs
456 //    * rgModuleIDs - Parallel array of ModuleIDs to rejit
457 //    * rgMethodDefs - Parallel array of methodDefs to rejit
458 //
459 // Return Value:
460 //      HRESULT indicating success or failure of the overall operation.  Each
461 //      individual methodDef (or MethodDesc associated with the methodDef)
462 //      may encounter its own failure, which is reported by the ReJITError()
463 //      callback, which is called into the profiler directly.
464 //
465
466 // static
467 HRESULT ReJitManager::RequestReJIT(
468     ULONG       cFunctions,
469     ModuleID    rgModuleIDs[],
470     mdMethodDef rgMethodDefs[])
471 {
472     return ReJitManager::UpdateActiveILVersions(cFunctions, rgModuleIDs, rgMethodDefs, NULL, FALSE);
473 }
474
475
476     // static
477 HRESULT ReJitManager::UpdateActiveILVersions(
478     ULONG       cFunctions,
479     ModuleID    rgModuleIDs[],
480     mdMethodDef rgMethodDefs[],
481     HRESULT     rgHrStatuses[],
482     BOOL        fIsRevert)
483 {
484     CONTRACTL
485     {
486         NOTHROW;
487         GC_TRIGGERS;
488         CAN_TAKE_LOCK;
489         MODE_PREEMPTIVE;
490     }
491     CONTRACTL_END;
492
493     // Serialize all RequestReJIT() and Revert() calls against each other (even across AppDomains)
494     CrstHolder ch(&(s_csGlobalRequest));
495
496     HRESULT hr = S_OK;
497
498     // Request at least 1 method to reJIT!
499     _ASSERTE ((cFunctions != 0) && (rgModuleIDs != NULL) && (rgMethodDefs != NULL));
500
501     // Temporary storage to batch up all the ReJitInfos that will get jump stamped
502     // later when the runtime is suspended.
503     //
504     //DESKTOP WARNING: On CoreCLR we are safe but if this code ever gets ported back
505     //there aren't any protections against domain unload. Any of these moduleIDs
506     //code version managers, or code versions would become invalid if the domain which
507     //contains them was unloaded.
508     SHash<CodeActivationBatchTraits> mgrToCodeActivationBatch;
509     CDynArray<CodeVersionManager::CodePublishError> errorRecords;
510     for (ULONG i = 0; i < cFunctions; i++)
511     {
512         Module * pModule = reinterpret_cast< Module * >(rgModuleIDs[i]);
513         if (pModule == NULL || TypeFromToken(rgMethodDefs[i]) != mdtMethodDef)
514         {
515             ReportReJITError(pModule, rgMethodDefs[i], NULL, E_INVALIDARG);
516             continue;
517         }
518
519         if (pModule->IsBeingUnloaded())
520         {
521             ReportReJITError(pModule, rgMethodDefs[i], NULL, CORPROF_E_DATAINCOMPLETE);
522             continue;
523         }
524
525         if (pModule->IsReflection())
526         {
527             ReportReJITError(pModule, rgMethodDefs[i], NULL, CORPROF_E_MODULE_IS_DYNAMIC);
528             continue;
529         }
530
531         if (!pModule->GetMDImport()->IsValidToken(rgMethodDefs[i]))
532         {
533             ReportReJITError(pModule, rgMethodDefs[i], NULL, E_INVALIDARG);
534             continue;
535         }
536
537         MethodDesc * pMD = pModule->LookupMethodDef(rgMethodDefs[i]);
538
539         if (pMD != NULL)
540         {
541             _ASSERTE(!pMD->IsNoMetadata());
542
543             // Weird, non-user functions can't be rejitted
544             if (!pMD->IsIL())
545             {
546                 // Intentionally not reporting an error in this case, to be consistent
547                 // with the pre-rejit case, as we have no opportunity to report an error
548                 // in a pre-rejit request for a non-IL method, since the rejit manager
549                 // never gets a call from the prestub worker for non-IL methods.  Thus,
550                 // since pre-rejit requests silently ignore rejit requests for non-IL
551                 // methods, regular rejit requests will also silently ignore rejit requests for
552                 // non-IL methods to be consistent.
553                 continue;
554             }
555         }
556
557         CodeVersionManager * pCodeVersionManager = pModule->GetCodeVersionManager();
558         _ASSERTE(pCodeVersionManager != NULL);
559         CodeActivationBatch * pCodeActivationBatch = mgrToCodeActivationBatch.Lookup(pCodeVersionManager);
560         if (pCodeActivationBatch == NULL)
561         {
562             pCodeActivationBatch = new (nothrow)CodeActivationBatch(pCodeVersionManager);
563             if (pCodeActivationBatch == NULL)
564             {
565                 return E_OUTOFMEMORY;
566             }
567
568             hr = S_OK;
569             EX_TRY
570             {
571                 // This guy throws when out of memory, but remains internally
572                 // consistent (without adding the new element)
573                 mgrToCodeActivationBatch.Add(pCodeActivationBatch);
574             }
575             EX_CATCH_HRESULT(hr);
576
577             _ASSERT(hr == S_OK || hr == E_OUTOFMEMORY);
578             if (FAILED(hr))
579             {
580                 return hr;
581             }
582         }
583
584         {
585             CodeVersionManager::TableLockHolder lock(pCodeVersionManager);
586
587             // Bind the il code version
588             ILCodeVersion* pILCodeVersion = pCodeActivationBatch->m_methodsToActivate.Append();
589             if (pILCodeVersion == NULL)
590             {
591                 return E_OUTOFMEMORY;
592             }
593             if (fIsRevert)
594             {
595                 // activate the original version
596                 *pILCodeVersion = ILCodeVersion(pModule, rgMethodDefs[i]);
597             }
598             else
599             {
600                 // activate an unused or new IL version
601                 hr = ReJitManager::BindILVersion(pCodeVersionManager, pModule, rgMethodDefs[i], pILCodeVersion);
602                 if (FAILED(hr))
603                 {
604                     _ASSERTE(hr == E_OUTOFMEMORY);
605                     return hr;
606                 }
607             }
608         }
609     }   // for (ULONG i = 0; i < cFunctions; i++)
610
611     // For each code versioning mgr, if there's work to do, suspend EE if needed,
612     // enter the code versioning mgr's crst, and do the batched work.
613     BOOL fEESuspended = FALSE;
614     SHash<CodeActivationBatchTraits>::Iterator beginIter = mgrToCodeActivationBatch.Begin();
615     SHash<CodeActivationBatchTraits>::Iterator endIter = mgrToCodeActivationBatch.End();
616     for (SHash<CodeActivationBatchTraits>::Iterator iter = beginIter; iter != endIter; iter++)
617     {
618         CodeActivationBatch * pCodeActivationBatch = *iter;
619         CodeVersionManager * pCodeVersionManager = pCodeActivationBatch->m_pCodeVersionManager;
620
621         int cMethodsToActivate = pCodeActivationBatch->m_methodsToActivate.Count();
622         if (cMethodsToActivate == 0)
623         {
624             continue;
625         }
626         if(!fEESuspended)
627         {
628             // As a potential future optimization we could speculatively try to update the jump stamps without
629             // suspending the runtime. That needs to be plumbed through BatchUpdateJumpStamps though.
630             ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_REJIT);
631             fEESuspended = TRUE;
632         }
633
634         _ASSERTE(ThreadStore::HoldingThreadStore());
635         hr = pCodeVersionManager->SetActiveILCodeVersions(pCodeActivationBatch->m_methodsToActivate.Ptr(), pCodeActivationBatch->m_methodsToActivate.Count(), fEESuspended, &errorRecords);
636         if (FAILED(hr))
637             break;
638     }
639     if (fEESuspended)
640     {
641         ThreadSuspend::RestartEE(FALSE, TRUE);
642     }
643
644     if (FAILED(hr))
645     {
646         _ASSERTE(hr == E_OUTOFMEMORY);
647         return hr;
648     }
649
650     // Report any errors that were batched up
651     for (int i = 0; i < errorRecords.Count(); i++)
652     {
653         if (rgHrStatuses != NULL)
654         {
655             for (DWORD j = 0; j < cFunctions; j++)
656             {
657                 if (rgMethodDefs[j] == errorRecords[i].methodDef &&
658                     reinterpret_cast<Module*>(rgModuleIDs[j]) == errorRecords[i].pModule)
659                 {
660                     rgHrStatuses[j] = errorRecords[i].hrStatus;
661                 }
662             }
663         }
664         else
665         {
666             ReportReJITError(&(errorRecords[i]));
667         }
668         
669     }
670
671     // We got through processing everything, but profiler will need to see the individual ReJITError
672     // callbacks to know what, if anything, failed.
673     return S_OK;
674 }
675
676 // static
677 HRESULT ReJitManager::BindILVersion(
678     CodeVersionManager* pCodeVersionManager,
679     PTR_Module pModule,
680     mdMethodDef methodDef,
681     ILCodeVersion *pILCodeVersion)
682 {
683     CONTRACTL
684     {
685         NOTHROW;
686         GC_NOTRIGGER;
687         MODE_PREEMPTIVE;
688         CAN_TAKE_LOCK;
689         PRECONDITION(CheckPointer(pCodeVersionManager));
690         PRECONDITION(CheckPointer(pModule));
691         PRECONDITION(CheckPointer(pILCodeVersion));
692     }
693     CONTRACTL_END;
694
695     _ASSERTE(pCodeVersionManager->LockOwnedByCurrentThread());
696     _ASSERTE((pModule != NULL) && (methodDef != mdTokenNil));
697
698     // Check if there was there a previous rejit request for this method that hasn't been exposed back
699     // to the profiler yet
700     ILCodeVersion ilCodeVersion = pCodeVersionManager->GetActiveILCodeVersion(pModule, methodDef);
701
702     if (ilCodeVersion.GetRejitState() == ILCodeVersion::kStateRequested)
703     {
704         // We can 'reuse' this instance because the profiler doesn't know about
705         // it yet. (This likely happened because a profiler called RequestReJIT
706         // twice in a row, without us having a chance to jmp-stamp the code yet OR
707         // while iterating through instantiations of a generic, the iterator found
708         // duplicate entries for the same instantiation.)
709         _ASSERTE(ilCodeVersion.GetILNoThrow() == NULL);
710
711         *pILCodeVersion = ilCodeVersion;
712         return S_FALSE;
713     }
714
715     // Either there was no ILCodeVersion yet for this MethodDesc OR whatever we've found
716     // couldn't be reused (and needed to be reverted).  Create a new ILCodeVersion to return
717     // to the caller.
718     return pCodeVersionManager->AddILCodeVersion(pModule, methodDef, InterlockedIncrement(reinterpret_cast<LONG*>(&s_GlobalReJitId)), pILCodeVersion);
719 }
720
721 //---------------------------------------------------------------------------------------
722 //
723 // ICorProfilerInfo4::RequestRevert calls into this guy to do most of the
724 // work. Takes care of finding the appropriate ReJitManager instances to
725 // perform the revert
726 //
727 // Arguments:
728 //    * cFunctions - Element count of rgModuleIDs & rgMethodDefs
729 //    * rgModuleIDs - Parallel array of ModuleIDs to revert
730 //    * rgMethodDefs - Parallel array of methodDefs to revert
731 //    * rgHrStatuses - [out] Parallel array of HRESULTs indicating success/failure
732 //        of reverting each (ModuleID, methodDef).
733 //
734 // Return Value:
735 //      HRESULT indicating success or failure of the overall operation.  Each
736 //      individual methodDef (or MethodDesc associated with the methodDef)
737 //      may encounter its own failure, which is reported by the rgHrStatuses
738 //      [out] parameter.
739 //
740
741 // static
742 HRESULT ReJitManager::RequestRevert(
743     ULONG       cFunctions,
744     ModuleID    rgModuleIDs[],
745     mdMethodDef rgMethodDefs[],
746     HRESULT     rgHrStatuses[])
747 {
748     CONTRACTL
749     {
750         NOTHROW;
751         GC_TRIGGERS;
752         CAN_TAKE_LOCK;
753         MODE_PREEMPTIVE;
754     }
755     CONTRACTL_END;
756
757     return UpdateActiveILVersions(cFunctions, rgModuleIDs, rgMethodDefs, rgHrStatuses, TRUE);
758 }
759
760 // static
761 HRESULT ReJitManager::ConfigureILCodeVersion(ILCodeVersion ilCodeVersion)
762 {
763     STANDARD_VM_CONTRACT;
764
765     CodeVersionManager* pCodeVersionManager = ilCodeVersion.GetModule()->GetCodeVersionManager();
766     _ASSERTE(!pCodeVersionManager->LockOwnedByCurrentThread());
767
768
769     HRESULT hr = S_OK;
770     Module* pModule = ilCodeVersion.GetModule();
771     mdMethodDef methodDef = ilCodeVersion.GetMethodDef();
772     BOOL fNeedsParameters = FALSE;
773     BOOL fWaitForParameters = FALSE;
774
775     {
776         // Serialize access to the rejit state
777         CodeVersionManager::TableLockHolder lock(pCodeVersionManager);
778         switch (ilCodeVersion.GetRejitState())
779         {
780         case ILCodeVersion::kStateRequested:
781             ilCodeVersion.SetRejitState(ILCodeVersion::kStateGettingReJITParameters);
782             fNeedsParameters = TRUE;
783             break;
784
785         case ILCodeVersion::kStateGettingReJITParameters:
786             fWaitForParameters = TRUE;
787             break;
788
789         default:
790             return S_OK;
791         }
792     }
793
794     if (fNeedsParameters)
795     {
796         // Here's where we give a chance for the rejit requestor to
797         // examine and modify the IL & codegen flags before it gets to
798         // the JIT. This allows one to add probe calls for things like
799         // code coverage, performance, or whatever. These will be
800         // stored in pShared.
801         _ASSERTE(pModule != NULL);
802         _ASSERTE(methodDef != mdTokenNil);
803         ReleaseHolder<ProfilerFunctionControl> pFuncControl =
804             new (nothrow)ProfilerFunctionControl(pModule->GetLoaderAllocator()->GetLowFrequencyHeap());
805         HRESULT hr = S_OK;
806         if (pFuncControl == NULL)
807         {
808             hr = E_OUTOFMEMORY;
809         }
810         else
811         {
812             BEGIN_PIN_PROFILER(CORProfilerPresent());
813             hr = g_profControlBlock.pProfInterface->GetReJITParameters(
814                 (ModuleID)pModule,
815                 methodDef,
816                 pFuncControl);
817             END_PIN_PROFILER();
818         }
819
820         if (FAILED(hr))
821         {
822             {
823                 // Historically on failure we would revert to the kRequested state and fall-back
824                 // to the initial code gen. The next time the method ran it would try again.
825                 //
826                 // Preserving that behavior is possible, but a bit awkward now that we have
827                 // Precode swapping as well. Instead of doing that I am acting as if GetReJITParameters
828                 // had succeeded, using the original IL, no jit flags, and no modified IL mapping.
829                 // This is similar to a fallback except the profiler won't get any further attempts
830                 // to provide the parameters correctly. If the profiler wants another attempt it would
831                 // need to call RequestRejit again.
832                 CodeVersionManager::TableLockHolder lock(pCodeVersionManager);
833                 if (ilCodeVersion.GetRejitState() == ILCodeVersion::kStateGettingReJITParameters)
834                 {
835                     ilCodeVersion.SetRejitState(ILCodeVersion::kStateActive);
836                     ilCodeVersion.SetIL(ILCodeVersion(pModule, methodDef).GetIL());
837                 }
838             }
839             ReportReJITError(pModule, methodDef, pModule->LookupMethodDef(methodDef), hr);
840             return S_OK;
841         }
842         else
843         {
844             CodeVersionManager::TableLockHolder lock(pCodeVersionManager);
845             if (ilCodeVersion.GetRejitState() == ILCodeVersion::kStateGettingReJITParameters)
846             {
847                 // Inside the above call to ICorProfilerCallback4::GetReJITParameters, the profiler
848                 // will have used the specified pFuncControl to provide its IL and codegen flags. 
849                 // So now we transfer it out to the SharedReJitInfo.
850                 ilCodeVersion.SetJitFlags(pFuncControl->GetCodegenFlags());
851                 ilCodeVersion.SetIL((COR_ILMETHOD*)pFuncControl->GetIL());
852                 // ilCodeVersion is now the owner of the memory for the IL buffer
853                 ilCodeVersion.SetInstrumentedILMap(pFuncControl->GetInstrumentedMapEntryCount(),
854                     pFuncControl->GetInstrumentedMapEntries());
855                 ilCodeVersion.SetRejitState(ILCodeVersion::kStateActive);
856             }
857         }
858     }
859     else if (fWaitForParameters)
860     {
861         // This feels lame, but it doesn't appear like we have the good threading primitves
862         // for this. What I would like is an AutoResetEvent that atomically exits the table
863         // Crst when I wait on it. From what I can tell our AutoResetEvent doesn't have
864         // that atomic transition which means this ordering could occur:
865         // [Thread 1] detect kStateGettingParameters and exit table lock
866         // [Thread 2] enter table lock, transition kStateGettingParameters -> kStateActive
867         // [Thread 2] signal AutoResetEvent
868         // [Thread 2] exit table lock
869         // [Thread 1] wait on AutoResetEvent (which may never be signaled again)
870         //
871         // Another option would be ManualResetEvents, one for each SharedReJitInfo, but
872         // that feels like a lot of memory overhead to handle a case which occurs rarely.
873         // A third option would be dynamically creating ManualResetEvents in a side
874         // dictionary on demand, but that feels like a lot of complexity for an event 
875         // that occurs rarely.
876         //
877         // I just ended up with this simple polling loop. Assuming profiler
878         // writers implement GetReJITParameters performantly we will only iterate
879         // this loop once, and even then only in the rare case of threads racing
880         // to JIT the same IL. If this really winds up causing performance issues
881         // We can build something more sophisticated.
882         while (true)
883         {
884             {
885                 CodeVersionManager::TableLockHolder lock(pCodeVersionManager);
886                 if (ilCodeVersion.GetRejitState() == ILCodeVersion::kStateActive)
887                 {
888                     break; // the other thread got the parameters succesfully, go race to rejit
889                 }
890             }
891             ClrSleepEx(1, FALSE);
892         }
893     }
894     
895     return S_OK;
896 }
897
898 #endif // DACCESS_COMPILE
899 // The rest of the ReJitManager methods are safe to compile for DAC
900
901 //---------------------------------------------------------------------------------------
902 //
903 // Used by profiler to get the ReJITID corrseponding to a (MethodDesc *, PCODE) pair. 
904 // Can also be used to determine whether (MethodDesc *, PCODE) corresponds to a rejit
905 // (vs. a regular JIT) for the purposes of deciding whether to notify the debugger about
906 // the rejit (and building the debugger JIT info structure).
907 //
908 // Arguments:
909 //      * pMD - MethodDesc * of interestg
910 //      * pCodeStart - PCODE of the particular interesting JITting of that MethodDesc *
911 //
912 // Return Value:
913 //      0 if no such ReJITID found (e.g., PCODE is from a JIT and not a rejit), else the
914 //      ReJITID requested.
915 //
916 // static
917 ReJITID ReJitManager::GetReJitId(PTR_MethodDesc pMD, PCODE pCodeStart)
918 {
919     CONTRACTL
920     {
921         NOTHROW;
922         CAN_TAKE_LOCK;
923         GC_TRIGGERS;
924         PRECONDITION(CheckPointer(pMD));
925         PRECONDITION(pCodeStart != NULL);
926     }
927     CONTRACTL_END;
928
929     // Fast-path: If the rejit map is empty, no need to look up anything. Do this outside
930     // of a lock to impact our caller (the prestub worker) as little as possible. If the
931     // map is nonempty, we'll acquire the lock at that point and do the lookup for real.
932     CodeVersionManager* pCodeVersionManager = pMD->GetCodeVersionManager();
933     if (pCodeVersionManager->GetNonDefaultILVersionCount() == 0)
934     {
935         return 0;
936     }
937
938     CodeVersionManager::TableLockHolder ch(pCodeVersionManager);
939     return ReJitManager::GetReJitIdNoLock(pMD, pCodeStart);
940 }
941
942 //---------------------------------------------------------------------------------------
943 //
944 // See comment above code:ReJitManager::GetReJitId for main details of what this does.
945 // 
946 // This function is basically the same as GetReJitId, except caller is expected to take
947 // the ReJitManager lock directly (via ReJitManager::TableLockHolder). This exists so
948 // that ETW can explicitly take the triggering ReJitManager lock up front, and in the
949 // proper order, to avoid lock leveling issues, and triggering issues with other locks it
950 // takes that are CRST_UNSAFE_ANYMODE
951 // 
952
953 ReJITID ReJitManager::GetReJitIdNoLock(PTR_MethodDesc pMD, PCODE pCodeStart)
954 {
955     CONTRACTL
956     {
957         NOTHROW;
958         CANNOT_TAKE_LOCK;
959         GC_NOTRIGGER;
960         PRECONDITION(CheckPointer(pMD));
961         PRECONDITION(pCodeStart != NULL);
962     }
963     CONTRACTL_END;
964
965     // Caller must ensure this lock is taken!
966     CodeVersionManager* pCodeVersionManager = pMD->GetCodeVersionManager();
967     _ASSERTE(pCodeVersionManager->LockOwnedByCurrentThread());
968
969     NativeCodeVersion nativeCodeVersion = pCodeVersionManager->GetNativeCodeVersion(pMD, pCodeStart);
970     if (nativeCodeVersion.IsNull())
971     {
972         return 0;
973     }
974     return nativeCodeVersion.GetILCodeVersion().GetVersionId();
975 }
976
977 //---------------------------------------------------------------------------------------
978 //
979 // Called by profiler to retrieve an array of ReJITIDs corresponding to a MethodDesc *
980 //
981 // Arguments:
982 //      * pMD - MethodDesc * to look up
983 //      * cReJitIds - Element count capacity of reJitIds
984 //      * pcReJitIds - [out] Place total count of ReJITIDs found here; may be more than
985 //          cReJitIds if profiler passed an array that's too small to hold them all
986 //      * reJitIds - [out] Place ReJITIDs found here. Count of ReJITIDs returned here is
987 //          min(cReJitIds, *pcReJitIds)
988 //
989 // Return Value:
990 //      * S_OK: ReJITIDs successfully returned, array is big enough
991 //      * S_FALSE: ReJITIDs successfully found, but array was not big enough. Only
992 //          cReJitIds were returned and cReJitIds < *pcReJitId (latter being the total
993 //          number of ReJITIDs available).
994 //
995 // static
996 HRESULT ReJitManager::GetReJITIDs(PTR_MethodDesc pMD, ULONG cReJitIds, ULONG * pcReJitIds, ReJITID reJitIds[])
997 {
998     CONTRACTL
999     {
1000         NOTHROW;
1001         CAN_TAKE_LOCK;
1002         GC_NOTRIGGER;
1003         PRECONDITION(CheckPointer(pMD));
1004         PRECONDITION(pcReJitIds != NULL);
1005         PRECONDITION(reJitIds != NULL);
1006     }
1007     CONTRACTL_END;
1008
1009     CodeVersionManager* pCodeVersionManager = pMD->GetCodeVersionManager();
1010     CodeVersionManager::TableLockHolder lock(pCodeVersionManager);
1011
1012     ULONG cnt = 0;
1013
1014     ILCodeVersionCollection ilCodeVersions = pCodeVersionManager->GetILCodeVersions(pMD);
1015     for (ILCodeVersionIterator iter = ilCodeVersions.Begin(), end = ilCodeVersions.End();
1016         iter != end; 
1017         iter++)
1018     {
1019         ILCodeVersion curILVersion = *iter;
1020
1021         if (curILVersion.GetRejitState() == ILCodeVersion::kStateActive)
1022         {
1023             if (cnt < cReJitIds)
1024             {
1025                 reJitIds[cnt] = curILVersion.GetVersionId();
1026             }
1027             ++cnt;
1028
1029             // no overflow
1030             _ASSERTE(cnt != 0);
1031         }
1032     }
1033     *pcReJitIds = cnt;
1034
1035     return (cnt > cReJitIds) ? S_FALSE : S_OK;
1036 }
1037
1038 #endif // FEATURE_CODE_VERSIONING
1039 #else // FEATURE_REJIT
1040
1041 // On architectures that don't support rejit, just keep around some do-nothing
1042 // stubs so the rest of the VM doesn't have to be littered with #ifdef FEATURE_REJIT
1043
1044 // static
1045 HRESULT ReJitManager::RequestReJIT(
1046     ULONG       cFunctions,
1047     ModuleID    rgModuleIDs[],
1048     mdMethodDef rgMethodDefs[])
1049 {
1050     return E_NOTIMPL;
1051 }
1052
1053 // static
1054 HRESULT ReJitManager::RequestRevert(
1055         ULONG       cFunctions,
1056         ModuleID    rgModuleIDs[],
1057         mdMethodDef rgMethodDefs[],
1058         HRESULT     rgHrStatuses[])
1059 {
1060     return E_NOTIMPL;
1061 }
1062
1063 ReJITID ReJitManager::GetReJitId(PTR_MethodDesc pMD, PCODE pCodeStart)
1064 {
1065     return 0;
1066 }
1067
1068 ReJITID ReJitManager::GetReJitIdNoLock(PTR_MethodDesc pMD, PCODE pCodeStart)
1069 {
1070     return 0;
1071 }
1072
1073 HRESULT ReJitManager::GetReJITIDs(PTR_MethodDesc pMD, ULONG cReJitIds, ULONG * pcReJitIds, ReJITID reJitIds[])
1074 {
1075     return E_NOTIMPL;
1076 }
1077
1078 #endif // FEATURE_REJIT