bail if profiler is terminated
[platform/upstream/coreclr.git] / src / vm / proftoeeinterfaceimpl.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 // FILE: ProfToEEInterfaceImpl.cpp
6 //
7 // This module implements the ICorProfilerInfo* interfaces, which allow the 
8 // Profiler to communicate with the EE.  This allows the Profiler DLL to get
9 // access to private EE data structures and other things that should never be
10 // exported outside of the EE.
11 //
12
13 // 
14 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
15 // NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! 
16 //
17 // PLEASE READ!
18 //
19 // There are strict rules for how to implement ICorProfilerInfo* methods.  Please read
20 // https://github.com/dotnet/coreclr/blob/master/Documentation/botr/profilability.md
21 // to understand the rules and why they exist.
22 //
23 // As a reminder, here is a short summary of your responsibilities.  Every PUBLIC
24 // ENTRYPOINT (from profiler to EE) must have:
25 //
26 // - An entrypoint macro at the top (see code:#P2CLRRestrictionsOverview).  Your choices are:
27 //       PROFILER_TO_CLR_ENTRYPOINT_SYNC (typical choice):
28 //          Indicates the method may only be called by the profiler from within
29 //          a callback (from EE to profiler).
30 //       PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY
31 //          Even more restrictive, this indicates the method may only be called
32 //          from within the Initialize() callback
33 //       PROFILER_TO_CLR_ENTRYPOINT_ASYNC
34 //          Indicates this method may be called anytime.
35 //          THIS IS DANGEROUS.  PLEASE READ ABOVE DOC FOR GUIDANCE ON HOW TO SAFELY
36 //          CODE AN ASYNCHRONOUS METHOD.
37 //   You may use variants of these macros ending in _EX that accept bit flags (see
38 //   code:ProfToClrEntrypointFlags) if you need to specify additional parameters to how
39 //   the entrypoint should behave, though typically you can omit the flags and the
40 //   default (kP2EENone) will be used.
41 //
42 // - A complete contract block with comments over every contract choice.  Wherever
43 //   possible, use the preferred contracts (if not possible, you must comment why):
44 //       NOTHROW
45 //       GC_NOTRIGGER
46 //       MODE_ANY
47 //       CANNOT_TAKE_LOCK
48 //       (EE_THREAD_(NOT)_REQUIRED are unenforced and are thus optional.  If you wish
49 //       to specify these, EE_THREAD_NOT_REQUIRED is preferred.)
50 //   Note that the preferred contracts in this file are DIFFERENT than the preferred
51 //   contracts for eetoprofinterfaceimpl.cpp.
52 //
53 // Private helper functions in this file do not have the same preferred contracts as
54 // public entrypoints, and they should be contracted following the same guidelines
55 // as per the rest of the EE.
56 //
57 // NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! 
58 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
59 //
60 //
61 // #P2CLRRestrictionsOverview
62 // 
63 // The public ICorProfilerInfo(N) functions below have different restrictions on when
64 // they're allowed to be called. Listed roughly in order from most to least restrictive:
65 //     * PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY: Functions that are only
66 //         allowed to be called while the profiler is initializing on startup, from
67 //         inside the profiler's ICorProfilerCallback::Initialize method
68 //     * PROFILER_TO_CLR_ENTRYPOINT_SYNC: Functions that may be called from within any of
69 //         the profiler's callbacks, or anytime from a thread created by the profiler.
70 //         These functions may only be called by profilers loaded on startup
71 //     * PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach): Same as above,
72 //         except these may be called by startup AND attaching profilers.
73 //     * PROFILER_TO_CLR_ENTRYPOINT_ASYNC: Functions that may be called at any time and
74 //         from any thread by a profiler loaded on startup
75 //     * PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach): Same as above,
76 //         except these may be called by startup AND attaching profilers.
77 //         
78 //  The above restrictions are lifted for certain tests that run with these environment
79 //  variables set. (These are only available on DEBUG builds--including chk--not retail
80 //  builds.)
81 //    * COMPlus_TestOnlyEnableSlowELTHooks:
82 //         * If nonzero, then on startup the runtime will act as if a profiler was loaded
83 //             on startup and requested ELT slow-path (even if no profiler is loaded on
84 //             startup). This will also allow the SetEnterLeaveFunctionHooks(2) info
85 //             functions to be called outside of Initialize(). If a profiler later
86 //             attaches and calls these functions, then the slow-path wrapper will call
87 //             into the profiler's ELT hooks.
88 //    * COMPlus_TestOnlyEnableObjectAllocatedHook:
89 //         * If nonzero, then on startup the runtime will act as if a profiler was loaded
90 //             on startup and requested ObjectAllocated callback (even if no profiler is loaded
91 //             on startup). If a profiler later attaches and calls these functions, then the 
92 //             ObjectAllocated notifications will call into the profiler's ObjectAllocated callback.
93 //    * COMPlus_TestOnlyEnableICorProfilerInfo:
94 //         * If nonzero, then attaching profilers allows to call ICorProfilerInfo inteface, 
95 //             which would otherwise be disallowed for attaching profilers
96 //    * COMPlus_TestOnlyAllowedEventMask
97 //         * If a profiler needs to work around the restrictions of either
98 //             COR_PRF_ALLOWABLE_AFTER_ATTACH or COR_PRF_MONITOR_IMMUTABLE it may set
99 //             this environment variable. Its value should be a bitmask containing all
100 //             the flags that are:
101 //             * normally immutable or disallowed after attach, AND
102 //             * that the test plans to set after startup and / or by an attaching
103 //                 profiler.
104 //     
105 //
106
107 // 
108 // ======================================================================================
109
110 #include "common.h"
111 #include <posterror.h>
112 #include "proftoeeinterfaceimpl.h"
113 #include "proftoeeinterfaceimpl.inl"
114 #include "dllimport.h"
115 #include "threads.h"
116 #include "method.hpp"
117 #include "vars.hpp"
118 #include "dbginterface.h"
119 #include "corprof.h"
120 #include "class.h"
121 #include "object.h"
122 #include "ceegen.h"
123 #include "eeconfig.h"
124 #include "generics.h"
125 #include "gcinfo.h"
126 #include "safemath.h"
127 #include "threadsuspend.h"
128 #include "inlinetracking.h"
129
130 #ifdef PROFILING_SUPPORTED
131 #include "profilinghelper.h"
132 #include "profilinghelper.inl"
133 #include "eetoprofinterfaceimpl.inl"
134 #include "profilingenumerators.h"
135 #endif
136
137 #include "profdetach.h"
138
139 #include "metadataexports.h"
140
141 //---------------------------------------------------------------------------------------
142 // Helpers
143
144 // An OR'd combination of these flags may be specified in the _EX entrypoint macros to
145 // customize the behavior.
146 enum ProfToClrEntrypointFlags
147 {
148     // Just use the default behavior (this one is used if the non-_EX entrypoint macro is
149     // specified without any flags).
150     kP2EENone                       = 0x00000000,
151     
152     // By default, Info functions are not allowed to be used by an attaching profiler. 
153     // Specify this flag to override the default.
154     kP2EEAllowableAfterAttach       = 0x00000001,
155
156     // This info method has a GC_TRIGGERS contract.  Whereas contracts are debug-only,
157     // this flag is used in retail builds as well.
158     kP2EETriggers                   = 0x00000002,
159 };
160
161 // Default versions of the entrypoint macros use kP2EENone if no
162 // ProfToClrEntrypointFlags are specified
163
164 #define PROFILER_TO_CLR_ENTRYPOINT_ASYNC(logParams)             \
165     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EENone, logParams)
166
167 #define PROFILER_TO_CLR_ENTRYPOINT_SYNC(logParams)              \
168     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EENone, logParams)
169
170 // ASYNC entrypoints log and ensure an attaching profiler isn't making a call that's
171 // only supported by startup profilers.
172
173 #define CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED_HELPER(p2eeFlags)                           \
174     do                                                                                     \
175     {                                                                                      \
176         if ((((p2eeFlags) & kP2EEAllowableAfterAttach) == 0) &&                            \
177             (g_profControlBlock.pProfInterface->IsLoadedViaAttach()))                      \
178         {                                                                                  \
179             LOG((LF_CORPROF,                                                               \
180                  LL_ERROR,                                                                 \
181                  "**PROF: ERROR: Returning CORPROF_E_UNSUPPORTED_FOR_ATTACHING_PROFILER "  \
182                  "due to a call illegally made by an attaching profiler \n"));             \
183             return CORPROF_E_UNSUPPORTED_FOR_ATTACHING_PROFILER;                           \
184         }                                                                                  \
185     } while(0)
186
187 #ifdef _DEBUG
188
189 #define CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED(p2eeFlags)                           \
190     do                                                                              \
191     {                                                                               \
192         if (!((&g_profControlBlock)->fTestOnlyEnableICorProfilerInfo))              \
193         {                                                                           \
194             CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED_HELPER(p2eeFlags);               \
195         }                                                                           \
196     } while(0)
197
198
199
200 #else  //_DEBUG
201
202 #define CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED(p2eeFlags)                           \
203     do                                                                              \
204     {                                                                               \
205         CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED_HELPER(p2eeFlags);                   \
206     } while(0)
207
208 #endif //_DEBUG
209
210 #define PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(p2eeFlags, logParams)                           \
211     do                                                                                      \
212     {                                                                                       \
213         INCONTRACT(AssertTriggersContract(((p2eeFlags) & kP2EETriggers)));                  \
214         _ASSERTE(g_profControlBlock.curProfStatus.Get() != kProfStatusNone);                \
215         LOG(logParams);                                                                     \
216         /* If profiler was neutered, disallow call */                                       \
217         if (g_profControlBlock.curProfStatus.Get() == kProfStatusDetaching)                 \
218         {                                                                                   \
219             LOG((LF_CORPROF,                                                                \
220                  LL_ERROR,                                                                  \
221                  "**PROF: ERROR: Returning CORPROF_E_PROFILER_DETACHING "                   \
222                  "due to a post-neutered profiler call\n"));                                \
223             return CORPROF_E_PROFILER_DETACHING;                                            \
224         }                                                                                   \
225         CHECK_IF_ATTACHING_PROFILER_IS_ALLOWED(p2eeFlags);                                  \
226     } while(0)
227
228 // SYNC entrypoints must ensure the current EE Thread shows evidence that we're
229 // inside a callback.  If there's no EE Thread, then we automatically "pass"
230 // the check, and the SYNC call is allowed.
231 #define PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(p2eeFlags, logParams)                    \
232     do                                                                              \
233     {                                                                               \
234         PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(p2eeFlags, logParams);                  \
235         DWORD __dwExpectedCallbackState = COR_PRF_CALLBACKSTATE_INCALLBACK;         \
236         if (((p2eeFlags) & kP2EETriggers) != 0)                                     \
237         {                                                                           \
238             __dwExpectedCallbackState |= COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE;   \
239         }                                                                           \
240         if (!AreCallbackStateFlagsSet(__dwExpectedCallbackState))                   \
241         {                                                                           \
242             LOG((LF_CORPROF,                                                        \
243                  LL_ERROR,                                                          \
244                  "**PROF: ERROR: Returning CORPROF_E_UNSUPPORTED_CALL_SEQUENCE "    \
245                  "due to illegal asynchronous profiler call\n"));                   \
246             return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;                             \
247         }                                                                           \
248     } while(0)
249
250 // INIT_ONLY entrypoints must ensure we're executing inside the profiler's
251 // Initialize() implementation on startup (attach init doesn't count!).
252 #define PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY(logParams)                             \
253     do                                                                                          \
254     {                                                                                           \
255         PROFILER_TO_CLR_ENTRYPOINT_ASYNC(logParams);                                            \
256         if (g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForStartupLoad &&  \
257             g_profControlBlock.curProfStatus.Get() != kProfStatusInitializingForAttachLoad)     \
258         {                                                                                       \
259             return CORPROF_E_CALL_ONLY_FROM_INIT;                                               \
260         }                                                                                       \
261     } while(0)
262
263 // This macro is used to ensure that the current thread is not in a forbid
264 // suspend region.   Some methods are allowed to be called asynchronously,
265 // but some of them call JIT functions that take a reader lock.  So we need to ensure
266 // the current thread hasn't been hijacked by a profiler while it was holding the writer lock.
267 // Checking the ForbidSuspendThread region is a sufficient test for this
268 #define FAIL_IF_IN_FORBID_SUSPEND_REGION()                                  \
269     do                                                                      \
270     {                                                                       \
271         Thread * __pThread = GetThreadNULLOk();                             \
272         if ((__pThread != NULL) && (__pThread->IsInForbidSuspendRegion()))  \
273         {                                                                   \
274         return CORPROF_E_ASYNCHRONOUS_UNSAFE;                               \
275         }                                                                   \
276     } while(0)
277     
278 //
279 // This type is an overlay onto the exported type COR_PRF_FRAME_INFO.
280 // The first four fields *must* line up with the same fields in the
281 // exported type.  After that, we can add to the end as we wish.
282 //
283 typedef struct _COR_PRF_FRAME_INFO_INTERNAL {
284     USHORT size;
285     USHORT version;
286     FunctionID funcID;
287     UINT_PTR IP;
288     void *extraArg;
289     LPVOID thisArg;
290 } COR_PRF_FRAME_INFO_INTERNAL, *PCOR_PRF_FRAME_INFO_INTERNAL;
291
292 //
293 // After we ship a product with a certain struct type for COR_PRF_FRAME_INFO_INTERNAL
294 // we have that as a version.  If we change that in a later product, we can increment
295 // the counter below and then we can properly do versioning.
296 //
297 #define COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION 1
298
299
300 //---------------------------------------------------------------------------------------
301 //
302 // Converts TypeHandle to a ClassID
303 //
304 // Arguments:
305 //      th - TypeHandle to convert
306 //
307 // Return Value:
308 //      Requested ClassID.
309 //
310
311 ClassID TypeHandleToClassID(TypeHandle th)
312 {
313     WRAPPER_NO_CONTRACT;
314     return reinterpret_cast<ClassID> (th.AsPtr());
315 }
316
317 //---------------------------------------------------------------------------------------
318 //
319 // Converts TypeHandle for a non-generic type to a ClassID
320 //
321 // Arguments:
322 //      th - TypeHandle to convert
323 //
324 // Return Value:
325 //      Requested ClassID.  NULL if th represents a generic type
326 //
327 #ifdef PROFILING_SUPPORTED
328
329 static ClassID NonGenericTypeHandleToClassID(TypeHandle th)
330 {
331     CONTRACTL
332     {
333         NOTHROW;
334         GC_NOTRIGGER;
335         MODE_ANY;
336     } CONTRACTL_END;
337     
338     if ((!th.IsNull()) && (th.HasInstantiation()))
339 {
340         return NULL;
341 }
342
343     return TypeHandleToClassID(th);
344 }
345
346 //---------------------------------------------------------------------------------------
347 //
348 // Converts MethodDesc * to FunctionID
349 //
350 // Arguments:
351 //      pMD - MethodDesc * to convert
352 //
353 // Return Value:
354 //      Requested FunctionID
355 //
356
357 static FunctionID MethodDescToFunctionID(MethodDesc * pMD)
358 {
359     LIMITED_METHOD_CONTRACT;
360     return reinterpret_cast< FunctionID > (pMD);
361 }
362
363 #endif
364
365 //---------------------------------------------------------------------------------------
366 //
367 // Converts FunctionID to MethodDesc *
368 //
369 // Arguments:
370 //      functionID - FunctionID to convert
371 //
372 // Return Value:
373 //      MethodDesc * requested
374 //
375
376 MethodDesc *FunctionIdToMethodDesc(FunctionID functionID)
377 {
378     LIMITED_METHOD_CONTRACT;
379     
380     MethodDesc *pMethodDesc;
381
382     pMethodDesc = reinterpret_cast< MethodDesc* >(functionID);
383
384     _ASSERTE(pMethodDesc != NULL);
385     return pMethodDesc;
386 }
387
388 // (See comments for ArrayKindFromTypeHandle below.)
389 typedef enum
390 {
391     ARRAY_KIND_TYPEDESC,        // Normal, garden-variety typedesc array
392     ARRAY_KIND_METHODTABLE,  // Weirdo array with its own unshared methodtable (e.g., System.Object[])
393     ARRAY_KIND_NOTARRAY,       // Not an array
394 } ARRAY_KIND;
395
396 //---------------------------------------------------------------------------------------
397 //
398 // A couple Info calls need to understand what constitutes an "array", and what
399 // kinds of arrays there are.  ArrayKindFromTypeHandle tries to put some of this
400 // knowledge in a single place
401 //
402 // Arguments:
403 //      th - TypeHandle to inspect
404 //
405 // Return Value:
406 //      ARRAY_KIND describing th
407 //
408
409 inline ARRAY_KIND ArrayKindFromTypeHandle(TypeHandle th)
410 {
411     LIMITED_METHOD_CONTRACT;
412
413     if (th.IsArray())
414     {
415         return ARRAY_KIND_TYPEDESC;
416     }
417
418     if (!th.IsTypeDesc() && th.GetMethodTable()->IsArray())
419     {
420         return ARRAY_KIND_METHODTABLE;
421     }
422
423     return ARRAY_KIND_NOTARRAY;
424 }
425
426 #ifdef PROFILING_SUPPORTED
427
428 //---------------------------------------------------------------------------------------
429 // ModuleILHeap IUnknown implementation
430 //
431 // Function headers unnecessary, as MSDN adequately documents IUnknown
432 //
433
434 ULONG ModuleILHeap::AddRef()
435 {
436     // Lifetime of this object is controlled entirely by the CLR.  This
437     // is created on first request, and is automatically destroyed when
438     // the profiler is detached.
439     return 1;
440 }
441
442
443 ULONG ModuleILHeap::Release()
444 {
445     // Lifetime of this object is controlled entirely by the CLR.  This
446     // is created on first request, and is automatically destroyed when
447     // the profiler is detached.
448     return 1;
449 }
450
451
452 HRESULT ModuleILHeap::QueryInterface(REFIID riid, void ** pp)
453 {
454     HRESULT     hr = S_OK;
455
456     if (pp == NULL)
457     {
458         return E_POINTER;
459     }
460
461     *pp = 0;
462     if (riid == IID_IUnknown)
463     {
464         *pp = static_cast<IUnknown *>(this);
465     }
466     else if (riid == IID_IMethodMalloc)
467     {
468         *pp = static_cast<IMethodMalloc *>(this);
469     }
470     else
471     {
472         hr = E_NOINTERFACE;
473     }
474
475     if (hr == S_OK)
476     {
477         // CLR manages lifetime of this object, but in case that changes (or
478         // this code gets copied/pasted elsewhere), we'll still AddRef here so
479         // QI remains a good citizen either way.
480         AddRef();
481     }
482     return hr;
483 }
484
485 //---------------------------------------------------------------------------------------
486 // Profiler entrypoint to allocate space from this module's heap.
487 //
488 // Arguments
489 //      cb - size in bytes of allocation request
490 //
491 // Return value
492 //      pointer to allocated memory, or NULL if there was an error
493
494 void * STDMETHODCALLTYPE ModuleILHeap::Alloc(ULONG cb)
495 {
496     CONTRACTL
497     {
498         // Yay!
499         NOTHROW;
500     
501         // (see GC_TRIGGERS comment below)
502         CAN_TAKE_LOCK;
503
504         // Allocations using loader heaps below enter a critsec, which switches
505         // to preemptive, which is effectively a GC trigger
506         GC_TRIGGERS;
507
508         // Yay!
509         MODE_ANY;
510
511     } 
512     CONTRACTL_END;
513
514     LOG((LF_CORPROF, LL_INFO1000, "**PROF: ModuleILHeap::Alloc 0x%08xp.\n", cb));
515
516     if (cb == 0)
517     {
518         return NULL;
519     }
520
521     return new (nothrow) BYTE[cb];
522 }
523
524 //---------------------------------------------------------------------------------------
525 // The one and only instance of the IL heap
526
527 ModuleILHeap ModuleILHeap::s_Heap;
528
529 //---------------------------------------------------------------------------------------
530 // Implementation of ProfToEEInterfaceImpl's IUnknown
531
532 //
533 // The VM controls the lifetime of ProfToEEInterfaceImpl, not the
534 // profiler.  We'll automatically take care of cleanup when profilers
535 // unload and detach.
536 //
537
538 ULONG STDMETHODCALLTYPE ProfToEEInterfaceImpl::AddRef()
539     {
540     LIMITED_METHOD_CONTRACT;
541     return 1; 
542 }
543
544 ULONG STDMETHODCALLTYPE ProfToEEInterfaceImpl::Release()
545 {
546     LIMITED_METHOD_CONTRACT;
547     return 1; 
548 }
549
550 COM_METHOD ProfToEEInterfaceImpl::QueryInterface(REFIID id, void ** pInterface)
551 {
552     if (pInterface == NULL)
553     {
554         return E_POINTER;
555     }
556
557     if (id == IID_ICorProfilerInfo)
558     {
559         *pInterface = static_cast<ICorProfilerInfo *>(this);
560     }
561     else if (id == IID_ICorProfilerInfo2)
562     {
563         *pInterface = static_cast<ICorProfilerInfo2 *>(this);
564     }
565     else if (id == IID_ICorProfilerInfo3)
566     {
567         *pInterface = static_cast<ICorProfilerInfo3 *>(this);
568     }
569     else if (id == IID_ICorProfilerInfo4)
570     {
571         *pInterface = static_cast<ICorProfilerInfo4 *>(this);
572     }
573     else if (id == IID_ICorProfilerInfo5)
574     {
575         *pInterface = static_cast<ICorProfilerInfo5 *>(this);
576     }
577     else if (id == IID_ICorProfilerInfo6)
578     {
579         *pInterface = static_cast<ICorProfilerInfo6 *>(this);
580     }
581     else if (id == IID_ICorProfilerInfo7)
582     {
583         *pInterface = static_cast<ICorProfilerInfo7 *>(this);
584     }
585     else if (id == IID_ICorProfilerInfo8)
586     {
587         *pInterface = static_cast<ICorProfilerInfo8 *>(this);
588     }
589     else if (id == IID_ICorProfilerInfo9)
590     {
591         *pInterface = static_cast<ICorProfilerInfo9 *>(this);
592     }
593     else if (id == IID_ICorProfilerInfo10)
594     {
595         *pInterface = static_cast<ICorProfilerInfo10 *>(this);
596     }
597     else if (id == IID_IUnknown)
598     {
599         *pInterface = static_cast<IUnknown *>(static_cast<ICorProfilerInfo *>(this));
600     }
601     else
602     {
603         *pInterface = NULL;
604         return E_NOINTERFACE;
605     }
606
607     // CLR manages lifetime of this object, but in case that changes (or
608     // this code gets copied/pasted elsewhere), we'll still AddRef here so
609     // QI remains a good citizen either way.
610     AddRef();
611
612     return S_OK;
613 }
614 #endif // PROFILING_SUPPORTED
615
616 //---------------------------------------------------------------------------------------
617 //
618 // GC-related helpers.  These are called from elsewhere in the EE to determine profiler
619 // state, and to update the profiling API with info from the GC.
620 //
621
622 //---------------------------------------------------------------------------------------
623 //
624 // ProfilerObjectAllocatedCallback is called if a profiler is attached, requesting
625 // ObjectAllocated callbacks.
626 //
627 // Arguments:
628 //      objref - Reference to newly-allocated object
629 //      classId - ClassID of newly-allocated object
630 //
631
632 void __stdcall ProfilerObjectAllocatedCallback(OBJECTREF objref, ClassID classId)
633 {
634     CONTRACTL 
635 {
636         THROWS;
637         GC_TRIGGERS;
638         MODE_COOPERATIVE;
639     } 
640     CONTRACTL_END;
641     
642     TypeHandle th = OBJECTREFToObject(objref)->GetTypeHandle();
643
644     // WARNING: objref can move as a result of the ObjectAllocated() call below if
645     // the profiler causes a GC, so any operations on the objref should occur above
646     // this comment (unless you're prepared to add a GCPROTECT around the objref).  
647
648 #ifdef PROFILING_SUPPORTED
649     // Notify the profiler of the allocation
650
651     {
652         BEGIN_PIN_PROFILER(CORProfilerTrackAllocations() || CORProfilerTrackLargeAllocations());
653         // Note that for generic code we always return uninstantiated ClassIDs and FunctionIDs.
654         // Thus we strip any instantiations of the ClassID (which is really a type handle) here.
655         g_profControlBlock.pProfInterface->ObjectAllocated(
656                 (ObjectID) OBJECTREFToObject(objref), 
657                 classId);
658         END_PIN_PROFILER();
659     }
660 #endif // PROFILING_SUPPORTED
661 }
662
663 //---------------------------------------------------------------------------------------
664 //
665 // Wrapper around the GC Started callback
666 //
667 // Arguments:
668 //      generation - Generation being collected
669 //      induced - Was this GC induced by GC.Collect?
670 //
671
672 void __stdcall GarbageCollectionStartedCallback(int generation, BOOL induced)
673 {
674     CONTRACTL 
675     {
676         NOTHROW;
677         GC_NOTRIGGER;
678         MODE_ANY; // can be called even on GC threads
679     } 
680     CONTRACTL_END;
681
682 #ifdef PROFILING_SUPPORTED
683     //
684     // Mark that we are starting a GC.  This will allow profilers to do limited object inspection
685     // during callbacks that occur while a GC is happening.
686     //
687     g_profControlBlock.fGCInProgress = TRUE;
688
689     // Notify the profiler of start of the collection
690     {
691         BEGIN_PIN_PROFILER(CORProfilerTrackGC() || CORProfilerTrackBasicGC());
692         BOOL generationCollected[COR_PRF_GC_LARGE_OBJECT_HEAP+1];
693         if (generation == COR_PRF_GC_GEN_2)
694             generation = COR_PRF_GC_LARGE_OBJECT_HEAP;
695         for (int gen = 0; gen <= COR_PRF_GC_LARGE_OBJECT_HEAP; gen++)
696             generationCollected[gen] = gen <= generation;
697
698         g_profControlBlock.pProfInterface->GarbageCollectionStarted(
699             COR_PRF_GC_LARGE_OBJECT_HEAP+1, 
700             generationCollected, 
701             induced ? COR_PRF_GC_INDUCED : COR_PRF_GC_OTHER);
702         END_PIN_PROFILER();
703     }
704 #endif // PROFILING_SUPPORTED
705 }
706
707 //---------------------------------------------------------------------------------------
708 //
709 // Wrapper around the GC Finished callback
710 //
711
712 void __stdcall GarbageCollectionFinishedCallback()
713 {
714     CONTRACTL 
715     {
716         NOTHROW;
717         GC_NOTRIGGER;
718         MODE_ANY; // can be called even on GC threads        
719     } 
720     CONTRACTL_END;
721
722 #ifdef PROFILING_SUPPORTED
723     // Notify the profiler of end of the collection
724     {
725         BEGIN_PIN_PROFILER(CORProfilerTrackGC() || CORProfilerTrackBasicGC());
726         g_profControlBlock.pProfInterface->GarbageCollectionFinished();
727         END_PIN_PROFILER();
728     }
729
730     // Mark that GC is finished.
731     g_profControlBlock.fGCInProgress = FALSE;
732 #endif // PROFILING_SUPPORTED
733 }
734
735 #ifdef PROFILING_SUPPORTED
736 //---------------------------------------------------------------------------------------
737 //
738 // Describes a GC generation by number and address range
739 //
740
741 struct GenerationDesc
742 {
743     int generation;
744     BYTE *rangeStart;
745     BYTE *rangeEnd;
746     BYTE *rangeEndReserved;
747 };
748
749 struct GenerationTable
750 {
751     ULONG count;
752     ULONG capacity;
753     static const ULONG defaultCapacity = 4; // that's the minimum for 3 generation plus the large object heap
754     GenerationTable *prev;
755     GenerationDesc *genDescTable;
756 #ifdef  _DEBUG
757     ULONG magic;
758 #define GENERATION_TABLE_MAGIC 0x34781256
759 #define GENERATION_TABLE_BAD_MAGIC 0x55aa55aa
760 #endif
761 };
762
763
764 //---------------------------------------------------------------------------------------
765 //
766 // This is a callback used by the GC when we call GCHeapUtilities::DiagDescrGenerations
767 // (from UpdateGenerationBounds() below).  The GC gives us generation information through
768 // this callback, which we use to update the GenerationDesc in the corresponding
769 // GenerationTable
770 //
771 // Arguments:
772 //      context - The containing GenerationTable
773 //      generation - Generation number
774 //      rangeStart - Address where generation starts
775 //      rangeEnd - Address where generation ends
776 //      rangeEndReserved - Address where generation reserved space ends
777 //
778
779 // static
780 static void GenWalkFunc(void * context,
781                         int generation, 
782                         BYTE * rangeStart, 
783                         BYTE * rangeEnd,
784                         BYTE * rangeEndReserved)
785 {
786     CONTRACT_VOID
787     {
788         NOTHROW;
789         GC_NOTRIGGER;
790         MODE_ANY; // can be called even on GC threads        
791         PRECONDITION(CheckPointer(context));
792         PRECONDITION(0 <= generation && generation <= 3);
793         PRECONDITION(CheckPointer(rangeStart));
794         PRECONDITION(CheckPointer(rangeEnd));
795         PRECONDITION(CheckPointer(rangeEndReserved));
796     } CONTRACT_END;
797
798     GenerationTable *generationTable = (GenerationTable *)context;
799
800     _ASSERTE(generationTable->magic == GENERATION_TABLE_MAGIC);
801
802     ULONG count = generationTable->count;
803     if (count >= generationTable->capacity)
804     {
805         ULONG newCapacity = generationTable->capacity == 0 ? GenerationTable::defaultCapacity : generationTable->capacity * 2;
806         GenerationDesc *newGenDescTable = new (nothrow) GenerationDesc[newCapacity];
807         if (newGenDescTable == NULL)
808         {
809             // if we can't allocate a bigger table, we'll have to ignore this call
810             RETURN;
811         }
812         memcpy(newGenDescTable, generationTable->genDescTable, sizeof(generationTable->genDescTable[0]) * generationTable->count);
813         delete[] generationTable->genDescTable;
814         generationTable->genDescTable = newGenDescTable;
815         generationTable->capacity = newCapacity;
816     }
817     _ASSERTE(count < generationTable->capacity);
818
819     GenerationDesc *genDescTable = generationTable->genDescTable;
820
821     genDescTable[count].generation = generation;
822     genDescTable[count].rangeStart = rangeStart;
823     genDescTable[count].rangeEnd = rangeEnd;
824     genDescTable[count].rangeEndReserved = rangeEndReserved;
825
826     generationTable->count = count + 1;
827 }
828
829 // This is the table of generation bounds updated by the gc 
830 // and read by the profiler. So this is a single writer,
831 // multiple readers scenario.
832 static GenerationTable *s_currentGenerationTable;
833
834 // The generation table is updated atomically by replacing the
835 // pointer to it. The only tricky part is knowing when
836 // the old table can be deleted.
837 static Volatile<LONG> s_generationTableLock;
838
839 // This is just so we can assert there's a single writer
840 #ifdef  ENABLE_CONTRACTS
841 static Volatile<LONG> s_generationTableWriterCount;
842 #endif
843 #endif // PROFILING_SUPPORTED
844
845 //---------------------------------------------------------------------------------------
846 //
847 // This is called from the gc to push a new set of generation bounds
848 //
849
850 void __stdcall UpdateGenerationBounds()
851 {
852     CONTRACT_VOID
853     {
854         NOTHROW;
855         GC_NOTRIGGER;
856         MODE_ANY; // can be called even on GC threads        
857 #ifdef PROFILING_SUPPORTED
858         PRECONDITION(FastInterlockIncrement(&s_generationTableWriterCount) == 1);
859         POSTCONDITION(FastInterlockDecrement(&s_generationTableWriterCount) == 0);
860 #endif // PROFILING_SUPPORTED
861     } CONTRACT_END;
862
863 #ifdef PROFILING_SUPPORTED
864     // Notify the profiler of start of the collection
865     if (CORProfilerTrackGC() || CORProfilerTrackBasicGC())
866     {
867         // generate a new generation table
868         GenerationTable *newGenerationTable = new (nothrow) GenerationTable();
869         if (newGenerationTable == NULL)
870             RETURN;
871         newGenerationTable->count = 0;
872         newGenerationTable->capacity = GenerationTable::defaultCapacity;
873         // if there is already a current table, use its count as a guess for the capacity
874         if (s_currentGenerationTable != NULL)
875             newGenerationTable->capacity = s_currentGenerationTable->count;
876         newGenerationTable->prev = NULL;
877         newGenerationTable->genDescTable = new (nothrow) GenerationDesc[newGenerationTable->capacity];
878         if (newGenerationTable->genDescTable == NULL)
879             newGenerationTable->capacity = 0;
880
881 #ifdef  _DEBUG
882         newGenerationTable->magic = GENERATION_TABLE_MAGIC;
883 #endif
884         // fill in the values by calling back into the gc, which will report
885         // the ranges by calling GenWalkFunc for each one
886         IGCHeap *hp = GCHeapUtilities::GetGCHeap();
887         hp->DiagDescrGenerations(GenWalkFunc, newGenerationTable);
888
889         // remember the old table and plug in the new one
890         GenerationTable *oldGenerationTable = s_currentGenerationTable;
891         s_currentGenerationTable = newGenerationTable;
892
893         // WARNING: tricky code!
894         //
895         // We sample the generation table lock *after* plugging in the new table
896         // We do so using an interlocked operation so the cpu can't reorder
897         // the write to the s_currentGenerationTable with the increment.
898         // If the interlocked increment returns 1, we know nobody can be using
899         // the old table (readers increment the lock before using the table,
900         // and decrement it afterwards). Any new readers coming in
901         // will use the new table. So it's safe to delete the old
902         // table.
903         // On the other hand, if the interlocked increment returns
904         // something other than one, we put the old table on a list
905         // dangling off of the new one. Next time around, we'll try again
906         // deleting any old tables.
907         if (FastInterlockIncrement(&s_generationTableLock) == 1)
908         {
909             // We know nobody can be using any of the old tables
910             while (oldGenerationTable != NULL)
911             {
912                 _ASSERTE(oldGenerationTable->magic == GENERATION_TABLE_MAGIC);
913 #ifdef  _DEBUG
914                 oldGenerationTable->magic = GENERATION_TABLE_BAD_MAGIC;
915 #endif
916                 GenerationTable *temp = oldGenerationTable;
917                 oldGenerationTable = oldGenerationTable->prev;
918                 delete[] temp->genDescTable;
919                 delete temp;
920             }
921         }
922         else
923         {
924             // put the old table on a list
925             newGenerationTable->prev = oldGenerationTable;
926         }
927         FastInterlockDecrement(&s_generationTableLock);
928     }
929 #endif // PROFILING_SUPPORTED
930     RETURN;
931 }
932
933 #ifdef PROFILING_SUPPORTED
934
935 //---------------------------------------------------------------------------------------
936 //
937 // Determines whether we are in a window to allow object inspection.
938 //
939 // Return Value:
940 //      Returns S_OK if we can determine that we are in a window to allow object
941 //      inspection.  Otherwise a failure HRESULT is returned
942 //
943
944 HRESULT AllowObjectInspection()
945 {
946     CONTRACTL
947     {
948         NOTHROW;
949         GC_NOTRIGGER;
950         MODE_ANY; // tests for preemptive mode dynamically as its main function so contract enforcement is not appropriate
951     } 
952     CONTRACTL_END;
953
954     //
955     // Check first to see if we are in the process of doing a GC and presume that the profiler
956     // is making this object inspection from the same thread that notified of a valid ObjectID.
957     //
958     if (g_profControlBlock.fGCInProgress)
959     {
960         return S_OK;
961     }
962
963     //
964     // Thus we must have a managed thread, and it must be in coop mode.
965     // (That will also guarantee we're in a callback).
966     //
967     Thread * pThread = GetThreadNULLOk();
968
969     if (pThread == NULL)
970     {
971         return CORPROF_E_NOT_MANAGED_THREAD;
972     }
973
974     // Note this is why we don't enforce the contract of being in cooperative mode the whole point
975     // is that clients of this fellow want to return a robust error if not cooperative
976     // so technically they are mode_any although the only true preemptive support they offer
977     // is graceful failure in that case
978     if (!pThread->PreemptiveGCDisabled())
979     {
980         return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
981     }
982
983     return S_OK;
984 }
985
986 //---------------------------------------------------------------------------------------
987 //
988 // helper functions for the GC events
989 //
990
991
992 #endif // PROFILING_SUPPORTED
993
994 #if defined(PROFILING_SUPPORTED) || defined(FEATURE_EVENT_TRACE)
995
996 //---------------------------------------------------------------------------------------
997 //
998 // It's generally unsafe for profiling API code to call Get(GCSafe)TypeHandle() on
999 // objects, since we can encounter objects on the heap whose types belong to unloading
1000 // AppDomains. In such cases, getting the type handle of the object could AV.  Use this
1001 // function instead, which will return NULL for potentially unloaded types.
1002 // 
1003 // Arguments:
1004 //      pObj - Object * whose ClassID is desired
1005 //
1006 // Return Value:
1007 //      ClassID of the object, if it's safe to look it up. Else NULL.
1008 //
1009
1010 ClassID SafeGetClassIDFromObject(Object * pObj)
1011 {
1012     CONTRACTL
1013     {
1014         NOTHROW;
1015         GC_NOTRIGGER;
1016     } 
1017     CONTRACTL_END;
1018
1019     TypeHandle th = pObj->GetGCSafeTypeHandleIfPossible();
1020     if(th == NULL)
1021     {
1022         return NULL;
1023     }
1024
1025     return TypeHandleToClassID(th);
1026 }
1027
1028 //---------------------------------------------------------------------------------------
1029 //
1030 // Callback of type walk_fn used by IGCHeap::DiagWalkObject.  Keeps a count of each
1031 // object reference found.
1032 //
1033 // Arguments:
1034 //      pBO - Object reference encountered in walk
1035 //      context - running count of object references encountered
1036 //
1037 // Return Value:
1038 //      Always returns TRUE to object walker so it walks the entire object
1039 //
1040
1041 bool CountContainedObjectRef(Object * pBO, void * context)
1042 {
1043     LIMITED_METHOD_CONTRACT;
1044     // Increase the count
1045     (*((size_t *)context))++;
1046
1047     return TRUE;
1048 }
1049
1050 //---------------------------------------------------------------------------------------
1051 //
1052 // Callback of type walk_fn used by IGCHeap::DiagWalkObject.  Stores each object reference
1053 // encountered into an array.
1054 //
1055 // Arguments:
1056 //      pBO - Object reference encountered in walk
1057 //      context - Array of locations within the walked object that point to other
1058 //                objects.  On entry, (*context) points to the next unfilled array
1059 //                entry.  On exit, that location is filled, and (*context) is incremented
1060 //                to point to the next entry.
1061 //
1062 // Return Value:
1063 //      Always returns TRUE to object walker so it walks the entire object
1064 //
1065
1066 bool SaveContainedObjectRef(Object * pBO, void * context)
1067 {
1068     LIMITED_METHOD_CONTRACT;
1069     // Assign the value
1070     **((Object ***)context) = pBO;
1071
1072     // Now increment the array pointer
1073     //
1074     // Note that HeapWalkHelper has already walked the references once to count them up,
1075     // and then allocated an array big enough to hold those references.  First time this
1076     // callback is called for a given object, (*context) points to the first entry in the
1077     // array.  So "blindly" incrementing (*context) here and using it next time around
1078     // for the next reference, over and over again, should be safe.
1079     (*((Object ***)context))++;
1080
1081     return TRUE;
1082 }
1083
1084 //---------------------------------------------------------------------------------------
1085 //
1086 // Callback of type walk_fn used by the GC when walking the heap, to help profapi and ETW
1087 // track objects.  This guy orchestrates the use of the above callbacks which dig
1088 // into object references contained each object encountered by this callback.
1089 // This method is defined when either GC_PROFILING is defined or FEATURE_EVENT_TRACING
1090 // is defined and can operate fully when only one of the two is defined.
1091 //
1092 // Arguments:
1093 //      pBO - Object reference encountered on the heap
1094 //      pvContext - Pointer to ProfilerWalkHeapContext, containing ETW context built up
1095 //       during this GC, and which remembers if profapi-profiler is supposed to be called.
1096 //
1097 // Return Value:
1098 //      BOOL indicating whether the heap walk should continue.
1099 //      TRUE=continue
1100 //      FALSE=stop
1101 //
1102 extern bool s_forcedGCInProgress;
1103
1104 bool HeapWalkHelper(Object * pBO, void * pvContext)
1105 {
1106     CONTRACTL
1107     {
1108         NOTHROW;
1109         GC_NOTRIGGER;
1110         MODE_ANY;
1111     }
1112     CONTRACTL_END;
1113
1114     OBJECTREF *   arrObjRef      = NULL;
1115     size_t        cNumRefs       = 0;
1116     bool          bOnStack       = false;
1117     MethodTable * pMT            = pBO->GetMethodTable();
1118
1119     ProfilerWalkHeapContext * pProfilerWalkHeapContext = (ProfilerWalkHeapContext *) pvContext;
1120
1121     if (pMT->ContainsPointersOrCollectible())
1122     {
1123         // First round through calculates the number of object refs for this class
1124         GCHeapUtilities::GetGCHeap()->DiagWalkObject(pBO, &CountContainedObjectRef, (void *)&cNumRefs);
1125
1126         if (cNumRefs > 0)
1127         {
1128             // Create an array to contain all of the refs for this object
1129             bOnStack = cNumRefs <= 32 ? true : false;
1130
1131             if (bOnStack)
1132             {
1133                 // It's small enough, so just allocate on the stack
1134                 arrObjRef = (OBJECTREF *)_alloca(cNumRefs * sizeof(OBJECTREF));
1135             }
1136             else
1137             {
1138                 // Otherwise, allocate from the heap
1139                 arrObjRef = new (nothrow) OBJECTREF[cNumRefs];
1140
1141                 if (!arrObjRef)
1142                 {
1143                     return FALSE;
1144                 }
1145             }
1146
1147             // Second round saves off all of the ref values
1148             OBJECTREF * pCurObjRef = arrObjRef;
1149             GCHeapUtilities::GetGCHeap()->DiagWalkObject(pBO, &SaveContainedObjectRef, (void *)&pCurObjRef);
1150         }
1151     }
1152
1153     HRESULT hr = E_FAIL;
1154
1155 #if defined(GC_PROFILING)
1156     if (pProfilerWalkHeapContext->fProfilerPinned)
1157     {
1158         // It is not safe and could be overflowed to downcast size_t to ULONG on WIN64.
1159         // However, we have to do this dangerous downcast here to comply with the existing Profiling COM interface.
1160         // We are currently evaluating ways to fix this potential overflow issue.
1161         hr = g_profControlBlock.pProfInterface->ObjectReference(
1162             (ObjectID) pBO, 
1163             SafeGetClassIDFromObject(pBO),
1164             (ULONG) cNumRefs, 
1165             (ObjectID *) arrObjRef);
1166     }
1167 #endif
1168
1169 #ifdef FEATURE_EVENT_TRACE
1170     if (s_forcedGCInProgress &&
1171         ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context, 
1172                                      TRACE_LEVEL_INFORMATION, 
1173                                      CLR_GCHEAPDUMP_KEYWORD))
1174     {
1175         ETW::GCLog::ObjectReference(
1176             pProfilerWalkHeapContext,
1177             pBO,
1178             (ULONGLONG) SafeGetClassIDFromObject(pBO),
1179             cNumRefs,
1180             (Object **) arrObjRef);
1181
1182     }
1183 #endif // FEATURE_EVENT_TRACE
1184
1185     // If the data was not allocated on the stack, need to clean it up.
1186     if ((arrObjRef != NULL) && !bOnStack)
1187     {
1188         delete [] arrObjRef;
1189     }
1190
1191     // Return TRUE iff we want to the heap walk to continue. The only way we'd abort the
1192     // heap walk is if we're issuing profapi callbacks, and the profapi profiler
1193     // intentionally returned a failed HR (as its request that we stop the walk). There's
1194     // a potential conflict here. If a profapi profiler and an ETW profiler are both
1195     // monitoring the heap dump, and the profapi profiler requests to abort the walk (but
1196     // the ETW profiler may not want to abort the walk), then what do we do? The profapi
1197     // profiler gets precedence. We don't want to accidentally send more callbacks to a
1198     // profapi profiler that explicitly requested an abort. The ETW profiler will just
1199     // have to deal. In theory, I could make the code more complex by remembering that a
1200     // profapi profiler requested to abort the dump but an ETW profiler is still
1201     // attached, and then intentionally inhibit the remainder of the profapi callbacks
1202     // for this GC. But that's unnecessary complexity. In practice, it should be
1203     // extremely rare that a profapi profiler is monitoring heap dumps AND an ETW
1204     // profiler is also monitoring heap dumps.
1205     return (pProfilerWalkHeapContext->fProfilerPinned) ? SUCCEEDED(hr) : TRUE;
1206 }
1207
1208 #endif // defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACING)
1209
1210 #ifdef PROFILING_SUPPORTED
1211 //---------------------------------------------------------------------------------------
1212 //
1213 // Callback of type walk_fn used by the GC when walking the heap, to help profapi
1214 // track objects.  This is really just a wrapper around
1215 // EEToProfInterfaceImpl::AllocByClass, which does the real work
1216 //
1217 // Arguments:
1218 //      pBO - Object reference encountered on the heap
1219 //      pv - Structure used by EEToProfInterfaceImpl::AllocByClass to do its work.
1220 //
1221 // Return Value:
1222 //      BOOL indicating whether the heap walk should continue.
1223 //      TRUE=continue
1224 //      FALSE=stop
1225 //      Currently always returns TRUE
1226 //
1227
1228 bool AllocByClassHelper(Object * pBO, void * pv)
1229 {
1230     CONTRACTL
1231     {
1232         NOTHROW;
1233         GC_NOTRIGGER;
1234         MODE_ANY;
1235     }
1236     CONTRACTL_END;
1237     _ASSERTE(pv != NULL);
1238
1239     {
1240         BEGIN_PIN_PROFILER(CORProfilerPresent());
1241         // Pass along the call
1242         g_profControlBlock.pProfInterface->AllocByClass(
1243             (ObjectID) pBO, 
1244             SafeGetClassIDFromObject(pBO), 
1245             pv);
1246         END_PIN_PROFILER();
1247     }
1248
1249     return TRUE;
1250 }
1251
1252 #endif // PROFILING_SUPPORTED
1253 #if defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
1254
1255 //---------------------------------------------------------------------------------------
1256 //
1257 // Callback of type promote_func called by GC while scanning roots (in GCProfileWalkHeap,
1258 // called after the collection).  Wrapper around EEToProfInterfaceImpl::RootReference2,
1259 // which does the real work.
1260 //
1261 // Arguments:
1262 //      pObj - Object reference encountered
1263 ///     ppRoot - Address that references ppObject (can be interior pointer)
1264 //      pSC - ProfilingScanContext * containing the root kind and GCReferencesData used
1265 //            by RootReference2 
1266 //      dwFlags - Properties of the root as GC_CALL* constants (this function converts
1267 //                to COR_PRF_GC_ROOT_FLAGS.
1268 //
1269
1270 void ScanRootsHelper(Object* pObj, Object ** ppRoot, ScanContext *pSC, uint32_t dwFlags)
1271 {
1272     CONTRACTL
1273     {
1274         NOTHROW;
1275         GC_NOTRIGGER;
1276         MODE_ANY;
1277     }
1278     CONTRACTL_END;
1279
1280     // RootReference2 can return E_OUTOFMEMORY, and we're swallowing that.
1281     // Furthermore, we can't really handle it because we're callable during GC promotion.
1282     // On the other hand, this only means profiling information will be incomplete,
1283     // so it's ok to swallow E_OUTOFMEMORY.
1284     //
1285     FAULT_NOT_FATAL();
1286
1287     ProfilingScanContext *pPSC = (ProfilingScanContext *)pSC;
1288
1289     DWORD dwEtwRootFlags = 0;
1290     if (dwFlags & GC_CALL_INTERIOR)
1291         dwEtwRootFlags |= kEtwGCRootFlagsInterior;
1292     if (dwFlags & GC_CALL_PINNED)
1293         dwEtwRootFlags |= kEtwGCRootFlagsPinning;
1294
1295 #if defined(GC_PROFILING)
1296     void *rootID = NULL;
1297     switch (pPSC->dwEtwRootKind)
1298     {
1299     case    kEtwGCRootKindStack:
1300         rootID = pPSC->pMD;
1301         break;
1302
1303     case    kEtwGCRootKindHandle:
1304         _ASSERT(!"Shouldn't see handle here");
1305
1306     case    kEtwGCRootKindFinalizer:
1307     default:
1308         break;
1309     }
1310
1311     // Notify profiling API of the root
1312     if (pPSC->fProfilerPinned)
1313     {
1314         // Let the profiling code know about this root reference
1315         g_profControlBlock.pProfInterface->
1316             RootReference2((BYTE *)pObj, pPSC->dwEtwRootKind, (EtwGCRootFlags)dwEtwRootFlags, (BYTE *)rootID, &((pPSC)->pHeapId));
1317     }
1318 #endif
1319
1320 #ifdef FEATURE_EVENT_TRACE
1321     // Notify ETW of the root
1322     if (s_forcedGCInProgress &&
1323         ETW_TRACING_CATEGORY_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context, 
1324                                      TRACE_LEVEL_INFORMATION, 
1325                                      CLR_GCHEAPDUMP_KEYWORD))
1326     {
1327         ETW::GCLog::RootReference(
1328             NULL,           // handle is NULL, cuz this is a non-HANDLE root
1329             pObj,           // object being rooted
1330             NULL,           // pSecondaryNodeForDependentHandle is NULL, cuz this isn't a dependent handle
1331             FALSE,          // is dependent handle
1332             pPSC,
1333             dwFlags,        // dwGCFlags
1334             dwEtwRootFlags);
1335     }
1336 #endif // FEATURE_EVENT_TRACE
1337 }
1338
1339 #endif // defined(GC_PROFILING) || defined(FEATURE_EVENT_TRACE)
1340 #ifdef PROFILING_SUPPORTED
1341
1342 //---------------------------------------------------------------------------------------
1343 //
1344 // Private ProfToEEInterfaceImpl maintenance functions
1345 //
1346
1347
1348 //---------------------------------------------------------------------------------------
1349 //
1350 // Initialize ProfToEEInterfaceImpl (including ModuleILHeap statics)
1351 //
1352 // Return Value:
1353 //      HRESULT indicating success
1354 //
1355
1356 HRESULT ProfToEEInterfaceImpl::Init()
1357 {
1358     CONTRACTL
1359     {
1360         NOTHROW;
1361         CANNOT_TAKE_LOCK;
1362         GC_NOTRIGGER;
1363         MODE_ANY;
1364     } 
1365     CONTRACTL_END;
1366
1367     LOG((LF_CORPROF, LL_INFO1000, "**PROF: Init.\n"));
1368
1369 #ifdef _DEBUG
1370     if (ProfilingAPIUtility::ShouldInjectProfAPIFault(kProfAPIFault_StartupInternal))
1371     {
1372         return E_OUTOFMEMORY;
1373     }
1374 #endif //_DEBUG
1375     
1376     return S_OK;
1377 }
1378
1379
1380 //---------------------------------------------------------------------------------------
1381 //
1382 // Destroy ProfToEEInterfaceImpl (including ModuleILHeap statics)
1383 //
1384     
1385 ProfToEEInterfaceImpl::~ProfToEEInterfaceImpl()
1386 {
1387     CONTRACTL
1388     {
1389         NOTHROW;
1390         GC_NOTRIGGER;
1391         MODE_ANY;
1392     }
1393     CONTRACTL_END;
1394
1395     LOG((LF_CORPROF, LL_INFO1000, "**PROF: Terminate.\n"));
1396 }
1397
1398 //---------------------------------------------------------------------------------------
1399 //
1400 // Obsolete info functions
1401 //
1402
1403 HRESULT ProfToEEInterfaceImpl::GetInprocInspectionInterface(IUnknown **)
1404 {
1405     LIMITED_METHOD_CONTRACT;
1406     return E_NOTIMPL; 
1407 }
1408
1409 HRESULT ProfToEEInterfaceImpl::GetInprocInspectionIThisThread(IUnknown **)
1410 {
1411     LIMITED_METHOD_CONTRACT;
1412     return E_NOTIMPL; 
1413 }
1414
1415 HRESULT ProfToEEInterfaceImpl::BeginInprocDebugging(BOOL, DWORD *)
1416 {
1417     LIMITED_METHOD_CONTRACT;
1418     return E_NOTIMPL; 
1419 }
1420
1421 HRESULT ProfToEEInterfaceImpl::EndInprocDebugging(DWORD)
1422 {
1423     LIMITED_METHOD_CONTRACT;
1424     return E_NOTIMPL; 
1425 }
1426
1427 HRESULT ProfToEEInterfaceImpl::SetFunctionReJIT(FunctionID)
1428 {
1429     LIMITED_METHOD_CONTRACT;
1430     return E_NOTIMPL; 
1431 }
1432
1433
1434
1435
1436 //---------------------------------------------------------------------------------------
1437 //
1438 // *******************************
1439 // Public Profiler->EE entrypoints
1440 // *******************************
1441 //
1442 // ProfToEEInterfaceImpl implementation of public ICorProfilerInfo* methods
1443 //
1444 // NOTE: All ICorProfilerInfo* method implementations must follow the rules stated
1445 // at the top of this file!
1446 //
1447
1448 // See corprof.idl / MSDN for detailed comments about each of these public
1449 // functions, their parameters, return values, etc.
1450
1451 HRESULT ProfToEEInterfaceImpl::SetEventMask(DWORD dwEventMask)
1452 {
1453     CONTRACTL
1454     {
1455         // Yay!
1456         NOTHROW;
1457
1458         // Yay!
1459         GC_NOTRIGGER;
1460
1461         // Yay!
1462         MODE_ANY;
1463
1464         // Yay!
1465         EE_THREAD_NOT_REQUIRED;
1466
1467         CANNOT_TAKE_LOCK;
1468
1469     }
1470     CONTRACTL_END;
1471
1472     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1473         (LF_CORPROF, 
1474         LL_INFO1000, 
1475         "**PROF: SetEventMask 0x%08x.\n",
1476         dwEventMask));
1477
1478     _ASSERTE(CORProfilerPresentOrInitializing());
1479
1480     return g_profControlBlock.pProfInterface->SetEventMask(dwEventMask, 0 /* No high bits */);
1481 }
1482
1483 HRESULT ProfToEEInterfaceImpl::SetEventMask2(DWORD dwEventsLow, DWORD dwEventsHigh)
1484 {
1485     CONTRACTL
1486     {
1487         // Yay!
1488         NOTHROW;
1489
1490         // Yay!
1491         GC_NOTRIGGER;
1492
1493         // Yay!
1494         MODE_ANY;
1495
1496         // Yay!
1497         EE_THREAD_NOT_REQUIRED;
1498
1499         CANNOT_TAKE_LOCK;
1500
1501     }
1502     CONTRACTL_END;
1503
1504     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1505         (LF_CORPROF, 
1506         LL_INFO1000, 
1507         "**PROF: SetEventMask2 0x%08x, 0x%08x.\n",
1508         dwEventsLow, dwEventsHigh));
1509
1510     _ASSERTE(CORProfilerPresentOrInitializing());
1511  
1512     return g_profControlBlock.pProfInterface->SetEventMask(dwEventsLow, dwEventsHigh);
1513 }
1514
1515
1516 HRESULT ProfToEEInterfaceImpl::GetHandleFromThread(ThreadID threadId, HANDLE *phThread)
1517 {
1518     CONTRACTL
1519 {
1520         // Yay!
1521         NOTHROW;
1522
1523         // Yay!
1524         GC_NOTRIGGER;
1525     
1526         // Yay!
1527         MODE_ANY;
1528
1529         // Yay!
1530         EE_THREAD_NOT_REQUIRED;
1531
1532         // Yay!
1533         CANNOT_TAKE_LOCK;
1534     
1535     }
1536     CONTRACTL_END;
1537
1538     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1539         (LF_CORPROF, 
1540         LL_INFO1000, 
1541         "**PROF: GetHandleFromThread 0x%p.\n", 
1542         threadId));
1543
1544     if (!IsManagedThread(threadId))
1545     {
1546         return E_INVALIDARG;
1547     }
1548
1549     HRESULT hr = S_OK;
1550
1551     HANDLE hThread = ((Thread *)threadId)->GetThreadHandle();
1552
1553     if (hThread == INVALID_HANDLE_VALUE)
1554         hr = E_INVALIDARG;
1555
1556     else if (phThread)
1557         *phThread = hThread;
1558
1559     return (hr);
1560 }
1561
1562 HRESULT ProfToEEInterfaceImpl::GetObjectSize(ObjectID objectId, ULONG *pcSize)
1563 {
1564     CONTRACTL
1565     {
1566         // Yay!
1567         NOTHROW;
1568
1569         // Yay!
1570         GC_NOTRIGGER;
1571
1572         // Yay!  Fail at runtime if in preemptive mode via AllowObjectInspection()
1573         MODE_ANY;
1574
1575         // Yay!
1576         EE_THREAD_NOT_REQUIRED;
1577
1578         // Yay!
1579         CANNOT_TAKE_LOCK;
1580
1581     }
1582     CONTRACTL_END;
1583
1584     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1585         (LF_CORPROF, 
1586          LL_INFO1000, 
1587          "**PROF: GetObjectSize 0x%p.\n", 
1588          objectId));
1589     
1590     if (objectId == NULL)
1591     {
1592         return E_INVALIDARG;
1593     }
1594
1595     HRESULT hr = AllowObjectInspection();
1596     if (FAILED(hr))
1597     {
1598         return hr;
1599     }
1600     
1601     // Get the object pointer
1602     Object *pObj = reinterpret_cast<Object *>(objectId);
1603
1604     // Get the size
1605     if (pcSize)
1606     {
1607         SIZE_T size = pObj->GetSize();
1608
1609         if(size < MIN_OBJECT_SIZE)
1610         {
1611             size = PtrAlign(size);
1612         }
1613
1614         if (size > ULONG_MAX)
1615         {
1616             *pcSize = ULONG_MAX;
1617             return COR_E_OVERFLOW;
1618         }
1619         *pcSize = (ULONG)size; 
1620     }
1621
1622     // Indicate success
1623     return (S_OK);
1624 }
1625
1626 HRESULT ProfToEEInterfaceImpl::GetObjectSize2(ObjectID objectId, SIZE_T *pcSize)
1627 {
1628     CONTRACTL
1629     {
1630         // Yay!
1631         NOTHROW;
1632
1633         // Yay!
1634         GC_NOTRIGGER;
1635
1636         // Yay!  Fail at runtime if in preemptive mode via AllowObjectInspection()
1637         MODE_ANY;
1638
1639         // Yay!
1640         EE_THREAD_NOT_REQUIRED;
1641
1642         // Yay!
1643         CANNOT_TAKE_LOCK;
1644
1645     }
1646     CONTRACTL_END;
1647
1648     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1649         (LF_CORPROF, 
1650          LL_INFO1000, 
1651          "**PROF: GetObjectSize2 0x%p.\n", 
1652          objectId));
1653     
1654     if (objectId == NULL)
1655     {
1656         return E_INVALIDARG;
1657     }
1658
1659     HRESULT hr = AllowObjectInspection();
1660     if (FAILED(hr))
1661     {
1662         return hr;
1663     }
1664     
1665     // Get the object pointer
1666     Object *pObj = reinterpret_cast<Object *>(objectId);
1667
1668     // Get the size
1669     if (pcSize)
1670     {
1671         SIZE_T size = pObj->GetSize();
1672
1673         if(size < MIN_OBJECT_SIZE)
1674         {
1675             size = PtrAlign(size);
1676         }
1677
1678         *pcSize = size; 
1679     }
1680
1681     // Indicate success
1682     return (S_OK);
1683 }
1684
1685
1686 HRESULT ProfToEEInterfaceImpl::IsArrayClass(
1687     /* [in] */  ClassID classId,
1688     /* [out] */ CorElementType *pBaseElemType,
1689     /* [out] */ ClassID *pBaseClassId,
1690     /* [out] */ ULONG   *pcRank)
1691 {
1692     CONTRACTL
1693     {
1694         NOTHROW;
1695
1696         GC_NOTRIGGER;
1697         
1698         // Yay!
1699         MODE_ANY;
1700
1701         // Yay!
1702         EE_THREAD_NOT_REQUIRED;
1703
1704         // Yay!
1705         CANNOT_TAKE_LOCK;
1706
1707     }
1708     CONTRACTL_END;
1709
1710     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1711         (LF_CORPROF, 
1712          LL_INFO1000, 
1713          "**PROF: IsArrayClass 0x%p.\n",
1714          classId));
1715
1716     HRESULT hr;
1717     
1718     if (classId == NULL)
1719     {
1720         return E_INVALIDARG;
1721     }
1722
1723     TypeHandle th = TypeHandle::FromPtr((void *)classId);
1724
1725     ARRAY_KIND arrayKind = ArrayKindFromTypeHandle(th);
1726         
1727     // If this is indeed an array class, get some info about it
1728     switch (arrayKind)
1729     {
1730         default:
1731         {
1732             _ASSERTE(!"Unexpected return from ArrayKindFromTypeHandle()");
1733             hr = E_UNEXPECTED;
1734             break;
1735         }
1736             
1737         case ARRAY_KIND_TYPEDESC:
1738         {
1739             // This is actually an array, so cast it up
1740             ArrayTypeDesc *pArr = th.AsArray();
1741
1742             // Fill in the type if they want it
1743             if (pBaseElemType != NULL)
1744             {
1745                 *pBaseElemType = pArr->GetArrayElementTypeHandle().GetVerifierCorElementType();
1746             }
1747
1748             // If this is an array of classes and they wish to have the base type
1749             // If there is no associated class with this type, then there's no problem
1750             // because GetClass returns NULL which is the default we want to return in
1751             // this case.
1752             // Note that for generic code we always return uninstantiated ClassIDs and FunctionIDs
1753             if (pBaseClassId != NULL)
1754             {
1755                 *pBaseClassId = TypeHandleToClassID(pArr->GetTypeParam());
1756             }
1757
1758             // If they want the number of dimensions of the array
1759             if (pcRank != NULL)
1760             {
1761                 *pcRank = (ULONG) pArr->GetRank();
1762             }
1763
1764             // S_OK indicates that this was indeed an array
1765             hr = S_OK;
1766             break;
1767         }
1768         case ARRAY_KIND_METHODTABLE:
1769         {
1770             MethodTable *pArrMT = th.GetMethodTable();
1771
1772             // Fill in the type if they want it
1773             if (pBaseElemType != NULL)
1774             {
1775                 *pBaseElemType = pArrMT->GetArrayElementType();
1776             }
1777
1778             // If this is an array of classes and they wish to have the base type.
1779             if (pBaseClassId != NULL)
1780             {
1781                 *pBaseClassId = TypeHandleToClassID(pArrMT->GetApproxArrayElementTypeHandle());
1782             }
1783
1784             // If they want the number of dimensions of the array
1785             if (pcRank != NULL)
1786             {
1787                 *pcRank = (ULONG) pArrMT->GetRank();
1788             }
1789
1790             // S_OK indicates that this was indeed an array
1791             hr = S_OK;
1792             break;
1793         }
1794         case ARRAY_KIND_NOTARRAY:
1795         {
1796             if (pBaseClassId != NULL)
1797             {
1798                 *pBaseClassId = NULL;
1799             }
1800             
1801             // This is not an array, S_FALSE indicates so.
1802             hr = S_FALSE;
1803             break;
1804         }
1805     }
1806
1807     return hr;
1808 }
1809     
1810 HRESULT ProfToEEInterfaceImpl::GetThreadInfo(ThreadID threadId, DWORD *pdwWin32ThreadId)
1811 {
1812     CONTRACTL
1813     {
1814         // Yay!
1815         NOTHROW;
1816
1817         // Yay!
1818         GC_NOTRIGGER;
1819
1820         // Yay!
1821         MODE_ANY;
1822
1823         // Yay!
1824         EE_THREAD_NOT_REQUIRED;
1825
1826         // Yay!
1827         CANNOT_TAKE_LOCK;
1828
1829     }
1830     CONTRACTL_END;
1831
1832     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
1833         (LF_CORPROF, 
1834          LL_INFO1000, 
1835          "**PROF: GetThreadInfo 0x%p.\n", 
1836          threadId));  
1837     
1838     if (!IsManagedThread(threadId))
1839     {
1840         return E_INVALIDARG;
1841     }
1842     
1843     if (pdwWin32ThreadId)
1844     {
1845         *pdwWin32ThreadId = ((Thread *)threadId)->GetOSThreadId();
1846     }
1847
1848     return S_OK;
1849 }
1850
1851 HRESULT ProfToEEInterfaceImpl::GetCurrentThreadID(ThreadID *pThreadId)
1852 {
1853     CONTRACTL
1854     {
1855         // Yay!
1856         NOTHROW;
1857
1858         // Yay!
1859         GC_NOTRIGGER;
1860
1861         // Yay!
1862         MODE_ANY;
1863
1864         // Yay!
1865         EE_THREAD_NOT_REQUIRED;
1866
1867         // Yay!
1868         CANNOT_TAKE_LOCK;
1869
1870     }
1871     CONTRACTL_END;
1872
1873     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
1874         (LF_CORPROF, 
1875         LL_INFO1000, 
1876         "**PROF: GetCurrentThreadID.\n"));    
1877
1878     HRESULT hr = S_OK;
1879
1880     // No longer assert that GetThread doesn't return NULL, since callbacks
1881     // can now occur on non-managed threads (such as the GC helper threads)
1882     Thread * pThread = GetThreadNULLOk();
1883
1884     // If pThread is null, then the thread has never run managed code and
1885     // so has no ThreadID
1886     if (!IsManagedThread(pThread))
1887         hr = CORPROF_E_NOT_MANAGED_THREAD;
1888
1889     // Only provide value if they want it
1890     else if (pThreadId)
1891         *pThreadId = (ThreadID) pThread;
1892
1893     return (hr);
1894 }
1895
1896 //---------------------------------------------------------------------------------------
1897 //
1898 // Internal helper function to wrap a call into the JIT manager to get information about
1899 // a managed function based on IP
1900 //
1901 // Arguments:
1902 //      ip - IP address inside managed function of interest
1903 //      ppCodeInfo - [out] information about the managed function based on IP
1904 //
1905 // Return Value:
1906 //     HRESULT indicating success or failure.
1907 //
1908 //
1909
1910 HRESULT GetFunctionInfoInternal(LPCBYTE ip, EECodeInfo * pCodeInfo)
1911 {
1912     CONTRACTL
1913     {
1914         NOTHROW;
1915
1916         GC_NOTRIGGER;
1917         EE_THREAD_NOT_REQUIRED;
1918         CAN_TAKE_LOCK;
1919         CANNOT_RETAKE_LOCK;
1920
1921
1922         // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
1923         // host (SQL).  Corners will be cut to ensure this is the case
1924         if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
1925     }
1926     CONTRACTL_END;
1927
1928     // Before calling into the code manager, ensure the GC heap has been
1929     // initialized--else the code manager will assert trying to get info from the heap.
1930     if (!IsGarbageCollectorFullyInitialized())
1931     {
1932         return CORPROF_E_NOT_YET_AVAILABLE;
1933     }
1934
1935     if (ShouldAvoidHostCalls())
1936     {
1937         ExecutionManager::ReaderLockHolder rlh(NoHostCalls);
1938         if (!rlh.Acquired())
1939         {
1940             // Couldn't get the info.  Try again later
1941             return CORPROF_E_ASYNCHRONOUS_UNSAFE;
1942         }
1943
1944         pCodeInfo->Init((PCODE)ip, ExecutionManager::ScanNoReaderLock);
1945     }
1946     else
1947     {
1948         pCodeInfo->Init((PCODE)ip);
1949     }
1950
1951     if (!pCodeInfo->IsValid())
1952     {
1953         return E_FAIL;
1954     }
1955
1956     return S_OK;
1957 }
1958
1959
1960 HRESULT GetFunctionFromIPInternal(LPCBYTE ip, EECodeInfo * pCodeInfo, BOOL failOnNoMetadata)
1961 {
1962     CONTRACTL
1963     {
1964         NOTHROW;
1965         GC_NOTRIGGER;
1966         MODE_ANY;
1967         EE_THREAD_NOT_REQUIRED;
1968         CAN_TAKE_LOCK;
1969     }
1970     CONTRACTL_END;
1971
1972     _ASSERTE (pCodeInfo != NULL);
1973
1974     HRESULT hr = GetFunctionInfoInternal(ip, pCodeInfo);
1975     if (FAILED(hr))
1976     {
1977         return hr;
1978     }
1979
1980     if (failOnNoMetadata)
1981     {
1982         // never return a method that the user of the profiler API cannot use
1983         if (pCodeInfo->GetMethodDesc()->IsNoMetadata())
1984         {
1985             return E_FAIL;
1986         }
1987     }
1988
1989     return S_OK;
1990 }
1991
1992
1993 HRESULT ProfToEEInterfaceImpl::GetFunctionFromIP(LPCBYTE ip, FunctionID * pFunctionId)
1994 {
1995     CONTRACTL
1996     {
1997         // Yay!
1998         NOTHROW;
1999
2000         // Yay!
2001         GC_NOTRIGGER;
2002
2003         // Yay!
2004         MODE_ANY;
2005
2006         // Yay!
2007         EE_THREAD_NOT_REQUIRED;
2008
2009         // Querying the code manager requires a reader lock.  However, see
2010         // code:#DisableLockOnAsyncCalls
2011         DISABLED(CAN_TAKE_LOCK);
2012
2013         // Asynchronous functions can be called at arbitrary times when runtime 
2014         // is holding locks that cannot be reentered without causing deadlock.
2015         // This contract detects any attempts to reenter locks held at the time 
2016         // this function was called.  
2017         CANNOT_RETAKE_LOCK;
2018
2019
2020         // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2021         // host (SQL).  Corners will be cut to ensure this is the case
2022         if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2023     }
2024     CONTRACTL_END;
2025
2026     // See code:#DisableLockOnAsyncCalls
2027     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2028
2029     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2030         (LF_CORPROF, 
2031         LL_INFO1000, 
2032         "**PROF: GetFunctionFromIP 0x%p.\n", 
2033         ip));  
2034
2035     // This call is allowed asynchronously, but the JIT functions take a reader lock.  
2036     // So we need to ensure the current thread hasn't been hijacked by a profiler while
2037     // it was holding the writer lock.  Checking the ForbidSuspendThread region is a
2038     // sufficient test for this
2039     FAIL_IF_IN_FORBID_SUSPEND_REGION();
2040
2041     HRESULT hr = S_OK;
2042
2043     EECodeInfo codeInfo;
2044
2045     hr = GetFunctionFromIPInternal(ip, &codeInfo, /* failOnNoMetadata */ TRUE);
2046     if (FAILED(hr))
2047     {
2048         return hr;
2049     }
2050
2051     if (pFunctionId)
2052     {
2053         *pFunctionId = MethodDescToFunctionID(codeInfo.GetMethodDesc());
2054     }
2055
2056     return S_OK;
2057 }
2058
2059
2060 HRESULT ProfToEEInterfaceImpl::GetFunctionFromIP2(LPCBYTE ip, FunctionID * pFunctionId, ReJITID * pReJitId)
2061 {
2062     CONTRACTL
2063     {
2064         // Yay!
2065         NOTHROW;
2066
2067         // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
2068         // which can switch us to preemptive mode and trigger GCs
2069         GC_TRIGGERS;
2070
2071         // Yay!
2072         MODE_ANY;
2073     
2074         // Yay!
2075         EE_THREAD_NOT_REQUIRED;
2076
2077         // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
2078         CAN_TAKE_LOCK;
2079
2080     }
2081     CONTRACTL_END;
2082
2083     // See code:#DisableLockOnAsyncCalls
2084     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2085
2086     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
2087         kP2EEAllowableAfterAttach | kP2EETriggers,
2088         (LF_CORPROF, 
2089         LL_INFO1000, 
2090         "**PROF: GetFunctionFromIP2 0x%p.\n", 
2091         ip));  
2092
2093     HRESULT hr = S_OK;
2094
2095     EECodeInfo codeInfo;
2096
2097     hr = GetFunctionFromIPInternal(ip, &codeInfo, /* failOnNoMetadata */ TRUE);
2098     if (FAILED(hr))
2099     {
2100         return hr;
2101     }
2102
2103     if (pFunctionId)
2104     {
2105         *pFunctionId = MethodDescToFunctionID(codeInfo.GetMethodDesc());
2106     }
2107
2108     if (pReJitId != NULL)
2109     {
2110         MethodDesc * pMD = codeInfo.GetMethodDesc();
2111         *pReJitId = ReJitManager::GetReJitId(pMD, codeInfo.GetStartAddress());
2112     }
2113
2114     return S_OK;
2115 }
2116
2117 //*****************************************************************************
2118 // Given a function id, retrieve the metadata token and a reader api that
2119 // can be used against the token.
2120 //*****************************************************************************
2121 HRESULT ProfToEEInterfaceImpl::GetTokenAndMetaDataFromFunction(
2122     FunctionID  functionId,
2123     REFIID      riid,
2124     IUnknown    **ppOut,
2125     mdToken     *pToken)
2126 {
2127     CONTRACTL
2128     {
2129         // Yay!
2130         NOTHROW;
2131
2132         // Yay!
2133         GC_NOTRIGGER;
2134
2135         // Yay!
2136         MODE_ANY;
2137
2138         // Yay!
2139         EE_THREAD_NOT_REQUIRED;
2140
2141         // PEFile::GetRWImporter and GetReadablePublicMetaDataInterface take locks
2142         CAN_TAKE_LOCK;
2143
2144     }
2145     CONTRACTL_END;
2146
2147     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2148         (LF_CORPROF, 
2149          LL_INFO1000, 
2150          "**PROF: GetTokenAndMetaDataFromFunction 0x%p.\n", 
2151          functionId));  
2152     
2153     if (functionId == NULL)
2154     {
2155         return E_INVALIDARG;
2156     }
2157     
2158     HRESULT     hr = S_OK;
2159
2160     MethodDesc *pMD = FunctionIdToMethodDesc(functionId);
2161
2162     // it's not safe to examine a methoddesc that has not been restored so do not do so
2163     if (!pMD->IsRestored())
2164         return CORPROF_E_DATAINCOMPLETE;
2165     
2166     if (pToken)
2167     {
2168         *pToken = pMD->GetMemberDef();
2169     }
2170
2171     // don't bother with any of this module fetching if the metadata access isn't requested
2172     if (ppOut)
2173     {
2174         Module * pMod = pMD->GetModule();
2175         hr = pMod->GetReadablePublicMetaDataInterface(ofRead, riid, (LPVOID *) ppOut);
2176     }
2177
2178     return hr;
2179 }
2180
2181 //---------------------------------------------------------------------------------------
2182 // What follows are the GetCodeInfo* APIs and their helpers.  The two helpers factor out
2183 // some of the common code to validate parameters and then determine the code info from
2184 // the start of the code.  Each individual GetCodeInfo* API differs in how it uses these
2185 // helpers, particuarly in how it determines the start of the code (GetCodeInfo3 needs
2186 // to use the rejit manager to determine the code start, whereas the others do not). 
2187 // Factoring out like this allows us to have statically determined contracts that differ
2188 // based on whether we need to use the rejit manager, which requires locking and
2189 // may trigger GCs.
2190 //---------------------------------------------------------------------------------------
2191
2192
2193 HRESULT ValidateParametersForGetCodeInfo(
2194     MethodDesc * pMethodDesc,
2195     ULONG32  cCodeInfos,
2196     COR_PRF_CODE_INFO codeInfos[])
2197 {
2198     LIMITED_METHOD_CONTRACT;
2199
2200     if (pMethodDesc == NULL)
2201     {
2202         return E_INVALIDARG;
2203     }
2204
2205     if ((cCodeInfos != 0) && (codeInfos == NULL))
2206     {
2207         return E_INVALIDARG;
2208     }
2209
2210     // it's not safe to examine a methoddesc that has not been restored so do not do so
2211     if (!pMethodDesc->IsRestored())
2212         return CORPROF_E_DATAINCOMPLETE;
2213
2214     if (pMethodDesc->HasClassOrMethodInstantiation() && pMethodDesc->IsTypicalMethodDefinition())
2215     {
2216         // In this case, we used to replace pMethodDesc with its canonical instantiation
2217         // (FindOrCreateTypicalSharedInstantiation).  However, a profiler should never be able
2218         // to get to this point anyway, since any MethodDesc a profiler gets from us
2219         // cannot be typical (i.e., cannot be a generic with types still left uninstantiated).
2220         // We assert here just in case a test proves me wrong, but generally we will
2221         // disallow this code path.
2222         _ASSERTE(!"Profiler passed a typical method desc (a generic with types still left uninstantiated) to GetCodeInfo2");
2223         return E_INVALIDARG;
2224     }
2225
2226     return S_OK;
2227 }
2228
2229 HRESULT GetCodeInfoFromCodeStart(
2230     PCODE start,
2231     ULONG32  cCodeInfos,
2232     ULONG32 * pcCodeInfos,
2233     COR_PRF_CODE_INFO codeInfos[])
2234 {
2235     CONTRACTL
2236     {
2237         NOTHROW;
2238         GC_NOTRIGGER;
2239         MODE_ANY;
2240
2241         // We need to take the ExecutionManager reader lock to find the
2242         // appropriate jit manager.
2243         CAN_TAKE_LOCK;
2244
2245
2246         // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2247         // host (SQL).  Corners will be cut to ensure this is the case
2248         if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2249     }
2250     CONTRACTL_END;
2251
2252     ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
2253
2254     ///////////////////////////////////
2255     // Get the code region info for this function. This is a multi step process.
2256     //
2257     // MethodDesc ==> Code Address ==> JitMananger ==>
2258     // MethodToken ==> MethodRegionInfo
2259     // 
2260     // (Our caller handled the first step: MethodDesc ==> Code Address.)
2261     //
2262     // <WIN64-ONLY>
2263     //
2264     // On WIN64 we have a choice of where to go to find out the function address range size:
2265     // GC info (which is what we're doing below on all architectures) or the OS unwind
2266     // info, stored in the RUNTIME_FUNCTION structure.  The latter produces
2267     // a SMALLER size than the former, because the latter excludes some data from
2268     // the set we report to the OS for unwind info.  For example, switch tables can be
2269     // separated out from the regular code and not be reported as OS unwind info, and thus
2270     // those addresses will not appear in the range reported by the RUNTIME_FUNCTION gotten via:
2271     //
2272     //      IJitManager* pJitMan = ExecutionManager::FindJitMan((PBYTE)codeInfos[0].startAddress);
2273     //      PRUNTIME_FUNCTION pfe = pJitMan->GetUnwindInfo((PBYTE)codeInfos[0].startAddress);
2274     //      *pcCodeInfos = (ULONG) (pfe->EndAddress - pfe->BeginAddress);
2275     //
2276     // (Note that GCInfo & OS unwind info report the same start address--it's the size that's
2277     // different.)
2278     //
2279     // The advantage of using the GC info is that it's available on all architectures,
2280     // and it gives you a more complete picture of the addresses belonging to the function.
2281     //
2282     // A disadvantage of using GC info is we'll report those extra addresses (like switch
2283     // tables) that a profiler might turn back around and use in a call to
2284     // GetFunctionFromIP.  A profiler may expect we'd be able to map back any address
2285     // in the function's GetCodeInfo ranges back to that function's FunctionID (methoddesc).  But
2286     // querying these extra addresses will cause GetFunctionFromIP to fail, as they're not
2287     // actually valid instruction addresses that the IP register can be set to.
2288     // 
2289     // The advantage wins out, so we're going with GC info everywhere.
2290     //
2291     // </WIN64-ONLY>
2292
2293     HRESULT hr;
2294
2295     if (start == NULL)
2296     {
2297         return CORPROF_E_FUNCTION_NOT_COMPILED;
2298     }
2299
2300     EECodeInfo codeInfo;
2301     hr = GetFunctionInfoInternal(
2302         (LPCBYTE) start,
2303         &codeInfo);
2304     if (hr == CORPROF_E_ASYNCHRONOUS_UNSAFE)
2305     {
2306         _ASSERTE(ShouldAvoidHostCalls());
2307         return hr;
2308     }
2309     if (FAILED(hr))
2310     {
2311         return CORPROF_E_FUNCTION_NOT_COMPILED;
2312     }
2313
2314     IJitManager::MethodRegionInfo methodRegionInfo;
2315     codeInfo.GetMethodRegionInfo(&methodRegionInfo);
2316
2317     //
2318     // Fill out the codeInfo structures with valuse from the
2319     // methodRegion
2320     //
2321     // Note that we're assuming that a method will never be split into
2322     // more than two regions ... this is unlikely to change any time in
2323     // the near future.
2324     //
2325     if (NULL != codeInfos)
2326     {
2327         if (cCodeInfos > 0)
2328         {
2329             //
2330             // We have to return the two regions in the order that they would appear
2331             // if straight-line compiled
2332             //
2333             if (PCODEToPINSTR(start) == methodRegionInfo.hotStartAddress)
2334             {
2335                 codeInfos[0].startAddress =
2336                     (UINT_PTR)methodRegionInfo.hotStartAddress;
2337                 codeInfos[0].size = methodRegionInfo.hotSize;
2338             }
2339             else
2340             {
2341                 _ASSERTE(methodRegionInfo.coldStartAddress != NULL);
2342                 codeInfos[0].startAddress =
2343                     (UINT_PTR)methodRegionInfo.coldStartAddress;
2344                 codeInfos[0].size = methodRegionInfo.coldSize;
2345             }
2346
2347             if (NULL != methodRegionInfo.coldStartAddress)
2348             {
2349                 if (cCodeInfos > 1)
2350                 {
2351                     if (PCODEToPINSTR(start) == methodRegionInfo.hotStartAddress)
2352                     {
2353                         codeInfos[1].startAddress =
2354                             (UINT_PTR)methodRegionInfo.coldStartAddress;
2355                         codeInfos[1].size = methodRegionInfo.coldSize;
2356                     }
2357                     else
2358                     {
2359                         codeInfos[1].startAddress =
2360                             (UINT_PTR)methodRegionInfo.hotStartAddress;
2361                         codeInfos[1].size = methodRegionInfo.hotSize;
2362                     }
2363                 }
2364             }
2365         }
2366     }
2367
2368     if (NULL != pcCodeInfos)
2369     {
2370         *pcCodeInfos = (NULL != methodRegionInfo.coldStartAddress) ? 2 : 1;
2371     }
2372
2373
2374     return S_OK;
2375 }
2376
2377 //*****************************************************************************
2378 // Gets the location and size of a jitted function
2379 //*****************************************************************************
2380
2381 HRESULT ProfToEEInterfaceImpl::GetCodeInfo(FunctionID functionId, LPCBYTE * pStart, ULONG * pcSize)
2382 {
2383     CONTRACTL
2384     {
2385         // Yay!
2386         NOTHROW;
2387
2388         // Yay!
2389         GC_NOTRIGGER;
2390
2391         // Yay!
2392         MODE_ANY;
2393
2394         // Yay!
2395         EE_THREAD_NOT_REQUIRED;
2396
2397         // (See locking contract comment in GetCodeInfoHelper.)
2398         DISABLED(CAN_TAKE_LOCK);
2399         
2400         // (See locking contract comment in GetCodeInfoHelper.)
2401         CANNOT_RETAKE_LOCK;
2402
2403
2404         // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2405         // host (SQL).  Corners will be cut to ensure this is the case
2406         if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2407     }
2408     CONTRACTL_END;
2409
2410     // See code:#DisableLockOnAsyncCalls
2411     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2412
2413     // This is called asynchronously, but GetCodeInfoHelper() will
2414     // ensure we're not called at a dangerous time
2415     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2416         (LF_CORPROF, 
2417         LL_INFO1000, 
2418         "**PROF: GetCodeInfo 0x%p.\n", 
2419         functionId));
2420
2421     // GetCodeInfo may be called asynchronously, and the JIT functions take a reader
2422     // lock.  So we need to ensure the current thread hasn't been hijacked by a profiler while
2423     // it was holding the writer lock.  Checking the ForbidSuspendThread region is a sufficient test for this
2424     FAIL_IF_IN_FORBID_SUSPEND_REGION();
2425     
2426     if (functionId == 0)
2427     {
2428         return E_INVALIDARG;
2429     }
2430
2431     MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
2432
2433     COR_PRF_CODE_INFO codeInfos[2];
2434     ULONG32 cCodeInfos;
2435
2436     HRESULT hr = GetCodeInfoFromCodeStart(
2437         pMethodDesc->GetNativeCode(),
2438         _countof(codeInfos),
2439         &cCodeInfos, 
2440         codeInfos);
2441
2442     if ((FAILED(hr)) || (0 == cCodeInfos))
2443     {
2444         return hr;
2445     }
2446
2447     if (NULL != pStart)
2448     {
2449         *pStart = reinterpret_cast< LPCBYTE >(codeInfos[0].startAddress);
2450     }
2451
2452     if (NULL != pcSize)
2453     {
2454         if (!FitsIn<ULONG>(codeInfos[0].size))
2455         {
2456             return E_UNEXPECTED;
2457         }
2458         *pcSize = static_cast<ULONG>(codeInfos[0].size);
2459     }
2460
2461     return hr;
2462 }
2463
2464 HRESULT ProfToEEInterfaceImpl::GetCodeInfo2(FunctionID functionId,
2465                                             ULONG32  cCodeInfos,
2466                                             ULONG32 * pcCodeInfos,
2467                                             COR_PRF_CODE_INFO codeInfos[])
2468 {
2469     CONTRACTL
2470     {
2471         // Yay!
2472         NOTHROW;
2473
2474         // Yay!
2475         GC_NOTRIGGER;
2476
2477         // Yay!
2478         MODE_ANY;
2479
2480         // Yay!
2481         EE_THREAD_NOT_REQUIRED;
2482
2483         // (See locking contract comment in GetCodeInfoHelper.)
2484         DISABLED(CAN_TAKE_LOCK);
2485
2486         // (See locking contract comment in GetCodeInfoHelper.)
2487         CANNOT_RETAKE_LOCK;
2488
2489         
2490         // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
2491         // host (SQL).  Corners will be cut to ensure this is the case
2492         if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
2493
2494         PRECONDITION(CheckPointer(pcCodeInfos, NULL_OK));
2495         PRECONDITION(CheckPointer(codeInfos, NULL_OK));
2496     }
2497     CONTRACTL_END;
2498
2499     // See code:#DisableLockOnAsyncCalls
2500     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2501
2502     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2503         (LF_CORPROF, 
2504         LL_INFO1000, 
2505         "**PROF: GetCodeInfo2 0x%p.\n", 
2506         functionId));         
2507
2508     HRESULT hr = S_OK; 
2509
2510     EX_TRY
2511     {
2512         MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
2513
2514         hr = ValidateParametersForGetCodeInfo(pMethodDesc, cCodeInfos, codeInfos);
2515         if (SUCCEEDED(hr))
2516         {
2517             hr = GetCodeInfoFromCodeStart(
2518                 pMethodDesc->GetNativeCode(),
2519                 cCodeInfos,
2520                 pcCodeInfos,
2521                 codeInfos);
2522         }
2523     }
2524     EX_CATCH_HRESULT(hr);
2525
2526     return hr;
2527 }
2528
2529
2530 HRESULT ProfToEEInterfaceImpl::GetCodeInfo3(FunctionID functionId,
2531                                             ReJITID  reJitId,
2532                                             ULONG32  cCodeInfos,
2533                                             ULONG32* pcCodeInfos,
2534                                             COR_PRF_CODE_INFO codeInfos[])
2535
2536
2537 {
2538     CONTRACTL
2539     {
2540         // Yay!
2541         NOTHROW;
2542
2543         // We need to access the rejitmanager, which means taking locks, which means we
2544         // may trigger a GC
2545         GC_TRIGGERS;
2546
2547         // Yay!
2548         MODE_ANY;
2549
2550         // Yay!
2551         EE_THREAD_NOT_REQUIRED;
2552
2553         // We need to access the rejitmanager, which means taking locks
2554         CAN_TAKE_LOCK;
2555         
2556
2557         PRECONDITION(CheckPointer(pcCodeInfos, NULL_OK));
2558         PRECONDITION(CheckPointer(codeInfos, NULL_OK));
2559     }
2560     CONTRACTL_END;
2561
2562     // See code:#DisableLockOnAsyncCalls
2563     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
2564
2565     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
2566         kP2EEAllowableAfterAttach | kP2EETriggers,
2567         (LF_CORPROF, 
2568         LL_INFO1000, 
2569         "**PROF: GetCodeInfo3 0x%p 0x%p.\n", 
2570         functionId, reJitId));         
2571
2572     HRESULT hr = S_OK; 
2573
2574     EX_TRY
2575     {
2576         MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
2577
2578         hr = ValidateParametersForGetCodeInfo(pMethodDesc, cCodeInfos, codeInfos);
2579         if (SUCCEEDED(hr))
2580         {
2581             PCODE pCodeStart = NULL;
2582             CodeVersionManager* pCodeVersionManager = pMethodDesc->GetCodeVersionManager();
2583             {
2584                 CodeVersionManager::TableLockHolder lockHolder(pCodeVersionManager);
2585                 
2586                 ILCodeVersion ilCodeVersion = pCodeVersionManager->GetILCodeVersion(pMethodDesc, reJitId);
2587
2588                 NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMethodDesc);
2589                 for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++)
2590                 {
2591                     // Now that tiered compilation can create more than one jitted code version for the same rejit id
2592                     // we are arbitrarily choosing the first one to return.  To address a specific version of native code
2593                     // use GetCodeInfo4.
2594                     pCodeStart = iter->GetNativeCode();
2595                     break;
2596                 }
2597             }
2598             
2599             hr = GetCodeInfoFromCodeStart(pCodeStart,
2600                                           cCodeInfos,
2601                                           pcCodeInfos,
2602                                           codeInfos);
2603         }
2604     }
2605     EX_CATCH_HRESULT(hr);
2606
2607     return hr;
2608 }
2609
2610
2611 HRESULT ProfToEEInterfaceImpl::GetEventMask(DWORD * pdwEvents)
2612 {
2613     CONTRACTL
2614     {
2615         // Yay!
2616         NOTHROW;
2617
2618         // Yay!
2619         GC_NOTRIGGER;
2620
2621         // Yay!
2622         MODE_ANY;
2623
2624         // Yay!
2625         EE_THREAD_NOT_REQUIRED;
2626
2627         // Yay!
2628         CANNOT_TAKE_LOCK;
2629
2630     }
2631     CONTRACTL_END;
2632
2633
2634     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach, 
2635         (LF_CORPROF, 
2636         LL_INFO10, 
2637         "**PROF: GetEventMask.\n"));
2638     
2639     if (pdwEvents == NULL)
2640     {
2641         return E_INVALIDARG;
2642     }
2643
2644     *pdwEvents = g_profControlBlock.dwEventMask;
2645     return S_OK;
2646 }
2647
2648 HRESULT ProfToEEInterfaceImpl::GetEventMask2(DWORD *pdwEventsLow, DWORD *pdwEventsHigh)
2649 {
2650     CONTRACTL
2651     {
2652         // Yay!
2653         NOTHROW;
2654
2655         // Yay!
2656         GC_NOTRIGGER;
2657
2658         // Yay!
2659         MODE_ANY;
2660
2661         // Yay!
2662         EE_THREAD_NOT_REQUIRED;
2663
2664         // Yay!
2665         CANNOT_TAKE_LOCK;
2666
2667     }
2668     CONTRACTL_END;
2669
2670
2671     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach, 
2672         (LF_CORPROF, 
2673         LL_INFO10, 
2674         "**PROF: GetEventMask2.\n"));
2675     
2676     if ((pdwEventsLow == NULL) || (pdwEventsHigh == NULL))
2677     {
2678         return E_INVALIDARG;
2679     }
2680
2681     *pdwEventsLow = g_profControlBlock.dwEventMask;
2682     *pdwEventsHigh = g_profControlBlock.dwEventMaskHigh;
2683     return S_OK;
2684 }
2685
2686 // static
2687 void ProfToEEInterfaceImpl::MethodTableCallback(void* context, void* objectUNSAFE)
2688 {
2689     CONTRACTL
2690     {
2691         NOTHROW;
2692         GC_NOTRIGGER;
2693         MODE_ANY;
2694     } 
2695     CONTRACTL_END;
2696
2697     // each callback identifies the address of a method table within the frozen object segment
2698     // that pointer is an object ID by definition -- object references point to the method table
2699     CDynArray< ObjectID >* objects = reinterpret_cast< CDynArray< ObjectID >* >(context);
2700
2701     *objects->Append() = reinterpret_cast< ObjectID >(objectUNSAFE);
2702 }
2703
2704 // static
2705 void ProfToEEInterfaceImpl::ObjectRefCallback(void* context, void* objectUNSAFE)
2706 {
2707     // we don't care about embedded object references, ignore them
2708 }
2709
2710
2711 HRESULT ProfToEEInterfaceImpl::EnumModuleFrozenObjects(ModuleID moduleID,
2712                                                        ICorProfilerObjectEnum** ppEnum)
2713 {
2714     CONTRACTL
2715     {
2716         // Yay!
2717         NOTHROW;
2718
2719         // Yay!
2720         GC_NOTRIGGER;
2721
2722         // Yay!
2723         MODE_ANY;
2724
2725         // Yay!
2726         EE_THREAD_NOT_REQUIRED;
2727
2728         // Yay!
2729         CANNOT_TAKE_LOCK;
2730
2731     }
2732     CONTRACTL_END;
2733
2734     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2735         (LF_CORPROF, 
2736          LL_INFO1000, 
2737          "**PROF: EnumModuleFrozenObjects 0x%p.\n", 
2738          moduleID));             
2739     
2740     if (NULL == ppEnum)
2741     {
2742         return E_INVALIDARG;
2743     }
2744
2745     Module* pModule = reinterpret_cast< Module* >(moduleID);
2746     if (pModule == NULL || pModule->IsBeingUnloaded())
2747     {
2748         return CORPROF_E_DATAINCOMPLETE;
2749     }
2750     
2751     HRESULT hr = S_OK;
2752
2753     EX_TRY
2754     {
2755         // If we don't support frozen objects at all, then just return empty
2756         // enumerator.
2757         *ppEnum = new ProfilerObjectEnum();
2758     }
2759     EX_CATCH_HRESULT(hr);
2760
2761     return hr;
2762 }
2763
2764
2765
2766 /*
2767  * GetArrayObjectInfo
2768  *
2769  * This function returns informatin about array objects.  In particular, the dimensions
2770  * and where the data buffer is stored.
2771  *
2772  */
2773 HRESULT ProfToEEInterfaceImpl::GetArrayObjectInfo(ObjectID objectId,
2774                     ULONG32 cDimensionSizes,
2775                     ULONG32 pDimensionSizes[],
2776                     int pDimensionLowerBounds[],
2777                     BYTE    **ppData)
2778 {
2779     CONTRACTL
2780     {
2781         // Yay!
2782         NOTHROW;
2783
2784         // Yay!
2785         GC_NOTRIGGER;
2786
2787         // Yay!  Fail at runtime if in preemptive mode via AllowObjectInspection()
2788         MODE_ANY;
2789
2790         // Yay!
2791         CANNOT_TAKE_LOCK;
2792
2793     }
2794     CONTRACTL_END;
2795
2796     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2797         (LF_CORPROF, 
2798          LL_INFO1000, 
2799          "**PROF: GetArrayObjectInfo 0x%p.\n", 
2800          objectId));
2801     
2802     if (objectId == NULL)
2803     {
2804         return E_INVALIDARG;
2805     }
2806
2807     if ((pDimensionSizes == NULL) ||
2808         (pDimensionLowerBounds == NULL) ||
2809         (ppData == NULL))
2810     {
2811         return E_INVALIDARG;
2812     }
2813
2814     HRESULT hr = AllowObjectInspection();
2815     if (FAILED(hr))
2816     {
2817         return hr;
2818     }
2819
2820     Object * pObj = reinterpret_cast<Object *>(objectId);
2821
2822     // GC callbacks may come from a non-EE thread, which is considered permanently preemptive.
2823     // We are about calling some object inspection functions, which require to be in co-op mode.
2824     // Given that none managed objects can be changed by managed code until GC resumes the 
2825     // runtime, it is safe to violate the mode contract and to inspect managed objects from a 
2826     // non-EE thread when GetArrayObjectInfo is called within GC callbacks.
2827     if (NativeThreadInGC())
2828     {
2829         CONTRACT_VIOLATION(ModeViolation);
2830         return GetArrayObjectInfoHelper(pObj, cDimensionSizes, pDimensionSizes, pDimensionLowerBounds, ppData);
2831     }
2832
2833     return GetArrayObjectInfoHelper(pObj, cDimensionSizes, pDimensionSizes, pDimensionLowerBounds, ppData);
2834 }
2835
2836 HRESULT ProfToEEInterfaceImpl::GetArrayObjectInfoHelper(Object * pObj,
2837                     ULONG32 cDimensionSizes,
2838                     __out_ecount(cDimensionSizes) ULONG32 pDimensionSizes[],
2839                     __out_ecount(cDimensionSizes) int pDimensionLowerBounds[],
2840                     BYTE    **ppData)
2841 {
2842     CONTRACTL
2843     {
2844         // Yay!
2845         NOTHROW;
2846
2847         // Yay!
2848         GC_NOTRIGGER;
2849
2850         // Because of the object pointer parameter, we must be either in CO-OP mode, 
2851         // or on a non-EE thread in the process of doing a GC .
2852         if (!NativeThreadInGC()) { MODE_COOPERATIVE; }
2853
2854         // Yay!
2855         CANNOT_TAKE_LOCK;
2856
2857     }
2858     CONTRACTL_END;
2859
2860     // Must have an array.
2861     MethodTable * pMT = pObj->GetMethodTable();
2862     if (!pMT->IsArray())
2863     {
2864         return E_INVALIDARG;
2865     }
2866
2867     ArrayBase * pArray = static_cast<ArrayBase*> (pObj);
2868
2869     unsigned rank = pArray->GetRank();
2870
2871     if (cDimensionSizes < rank)
2872     {
2873         return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
2874     }
2875
2876     // Copy range for each dimension (rank)
2877     int * pBounds      = pArray->GetBoundsPtr();
2878     int * pLowerBounds = pArray->GetLowerBoundsPtr();
2879
2880     unsigned i;
2881     for(i = 0; i < rank; i++)
2882     {
2883         pDimensionSizes[i]       = pBounds[i];
2884         pDimensionLowerBounds[i] = pLowerBounds[i];
2885     }
2886
2887     // Pointer to data.
2888     *ppData = pArray->GetDataPtr();
2889
2890     return S_OK;
2891 }
2892
2893 /*
2894  * GetBoxClassLayout
2895  *
2896  * Returns information about how a particular value type is laid out.
2897  *
2898  */
2899 HRESULT ProfToEEInterfaceImpl::GetBoxClassLayout(ClassID classId,
2900                                                 ULONG32 *pBufferOffset)
2901 {
2902     CONTRACTL
2903     {
2904         // Yay!
2905         NOTHROW;
2906
2907         // Yay!
2908         GC_NOTRIGGER;
2909
2910         // Yay!
2911         MODE_ANY;
2912
2913         // Yay!
2914         EE_THREAD_NOT_REQUIRED;
2915
2916         // Yay!
2917         CANNOT_TAKE_LOCK;
2918
2919     }
2920     CONTRACTL_END;
2921
2922     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
2923         (LF_CORPROF, 
2924          LL_INFO1000, 
2925          "**PROF: GetBoxClassLayout 0x%p.\n", 
2926          classId));             
2927     
2928     if (pBufferOffset == NULL)
2929     {
2930         return E_INVALIDARG;
2931     }
2932
2933     if (classId == NULL)
2934     {
2935         return E_INVALIDARG;
2936     }
2937
2938     TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
2939
2940     //
2941     // This is the incorrect API for arrays.  Use GetArrayInfo and GetArrayLayout.
2942     //
2943     if (!typeHandle.IsValueType())
2944     {
2945         return E_INVALIDARG;
2946     }
2947
2948     *pBufferOffset = Object::GetOffsetOfFirstField();
2949
2950     return S_OK;
2951 }
2952
2953 /*
2954  * GetThreadAppDomain
2955  *
2956  * Returns the app domain currently associated with the given thread.
2957  *
2958  */
2959 HRESULT ProfToEEInterfaceImpl::GetThreadAppDomain(ThreadID threadId,
2960                                                   AppDomainID *pAppDomainId)
2961
2962 {
2963     CONTRACTL
2964     {
2965         // Yay!
2966         NOTHROW;
2967
2968         // Yay!
2969         GC_NOTRIGGER;
2970
2971         // Yay!
2972         MODE_ANY;
2973
2974         // Yay!
2975         EE_THREAD_NOT_REQUIRED;
2976
2977         // Yay!
2978         CANNOT_TAKE_LOCK;
2979
2980     }
2981     CONTRACTL_END;
2982
2983     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
2984         (LF_CORPROF,
2985          LL_INFO1000, 
2986          "**PROF: GetThreadAppDomain 0x%p.\n", 
2987          threadId));
2988
2989     if (pAppDomainId == NULL)
2990     {
2991         return E_INVALIDARG;
2992     }
2993
2994     Thread *pThread;
2995
2996     if (threadId == NULL)
2997     {
2998         pThread = GetThreadNULLOk();
2999     }
3000     else
3001     {
3002         pThread = (Thread *)threadId;
3003     }
3004
3005     //
3006     // If pThread is null, then the thread has never run managed code and
3007     // so has no ThreadID.
3008     //
3009     if (!IsManagedThread(pThread))
3010     {
3011         return CORPROF_E_NOT_MANAGED_THREAD;
3012     }
3013
3014     *pAppDomainId = (AppDomainID)pThread->GetDomain();
3015
3016     return S_OK;
3017 }
3018
3019
3020 /*
3021  * GetRVAStaticAddress
3022  *
3023  * This function returns the absolute address of the given field in the given
3024  * class.  The field must be an RVA Static token.
3025  *
3026  * Parameters:
3027  *    classId - the containing class.
3028  *    fieldToken - the field we are querying.
3029  *    pAddress - location for storing the resulting address location.
3030  *
3031  * Returns:
3032  *    S_OK on success,
3033  *    E_INVALIDARG if not an RVA static,
3034  *    CORPROF_E_DATAINCOMPLETE if not yet initialized.
3035  *
3036  */
3037 HRESULT ProfToEEInterfaceImpl::GetRVAStaticAddress(ClassID classId,
3038                                                    mdFieldDef fieldToken,
3039                                                    void **ppAddress)
3040 {
3041     CONTRACTL
3042     {
3043         // Yay!
3044         NOTHROW;
3045
3046         // Yay!
3047         GC_NOTRIGGER;
3048
3049         // Yay!
3050         MODE_ANY;
3051
3052         // FieldDesc::GetStaticAddress takes a lock
3053         CAN_TAKE_LOCK;
3054
3055     }
3056     CONTRACTL_END;
3057
3058     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3059         (LF_CORPROF, 
3060          LL_INFO1000, 
3061          "**PROF: GetRVAStaticAddress 0x%p, 0x%08x.\n", 
3062          classId, 
3063          fieldToken));
3064     
3065     //
3066     // Check for NULL parameters
3067     //
3068     if ((classId == NULL) || (ppAddress == NULL))
3069     {
3070         return E_INVALIDARG;
3071     }
3072
3073     if (GetThread() == NULL)
3074     {
3075         return CORPROF_E_NOT_MANAGED_THREAD;
3076     }
3077
3078     if (GetAppDomain() == NULL)
3079     {
3080         return E_FAIL;
3081     }
3082
3083     TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3084
3085     //
3086     // If this class is not fully restored, that is all the information we can get at this time.
3087     //
3088     if (!typeHandle.IsRestored())
3089     {
3090         return CORPROF_E_DATAINCOMPLETE;
3091     }
3092
3093     //
3094     // Get the field descriptor object
3095     //
3096     FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3097
3098     if (pFieldDesc == NULL)
3099     {
3100         return E_INVALIDARG;
3101     }
3102
3103     //
3104     // Verify this field is of the right type
3105     //
3106     if(!pFieldDesc->IsStatic() ||
3107        !pFieldDesc->IsRVA() ||
3108        pFieldDesc->IsThreadStatic())
3109     {
3110         return E_INVALIDARG;
3111     }
3112
3113     // It may seem redundant to try to retrieve the same method table from GetEnclosingMethodTable, but classId 
3114     // leads to the instantiated method table while GetEnclosingMethodTable returns the uninstantiated one.
3115     MethodTable *pMethodTable = pFieldDesc->GetEnclosingMethodTable();
3116
3117     //
3118     // Check that the data is available
3119     //
3120     if (!IsClassOfMethodTableInited(pMethodTable))
3121     {
3122         return CORPROF_E_DATAINCOMPLETE;
3123     }
3124
3125     //
3126     // Store the result and return
3127     //
3128     PTR_VOID pAddress = pFieldDesc->GetStaticAddress(NULL);
3129     if (pAddress == NULL)
3130     {
3131         return CORPROF_E_DATAINCOMPLETE;
3132     }
3133
3134     *ppAddress = pAddress;
3135
3136     return S_OK;
3137 }
3138
3139
3140 /*
3141  * GetAppDomainStaticAddress
3142  *
3143  * This function returns the absolute address of the given field in the given
3144  * class in the given app domain.  The field must be an App Domain Static token.
3145  *
3146  * Parameters:
3147  *    classId - the containing class.
3148  *    fieldToken - the field we are querying.
3149  *    appDomainId - the app domain container.
3150  *    pAddress - location for storing the resulting address location.
3151  *
3152  * Returns:
3153  *    S_OK on success,
3154  *    E_INVALIDARG if not an app domain static,
3155  *    CORPROF_E_DATAINCOMPLETE if not yet initialized.
3156  *
3157  */
3158 HRESULT ProfToEEInterfaceImpl::GetAppDomainStaticAddress(ClassID classId,
3159                                                          mdFieldDef fieldToken,
3160                                                          AppDomainID appDomainId,
3161                                                          void **ppAddress)
3162 {
3163     CONTRACTL
3164     {
3165         // Yay!
3166         NOTHROW;
3167
3168         // Yay!
3169         GC_NOTRIGGER;
3170
3171         // Yay!
3172         MODE_ANY;
3173
3174         // Yay!
3175         EE_THREAD_NOT_REQUIRED;
3176
3177         // FieldDesc::GetStaticAddress & FieldDesc::GetBase take locks
3178         CAN_TAKE_LOCK;
3179
3180     }
3181     CONTRACTL_END;
3182
3183     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3184         (LF_CORPROF, 
3185          LL_INFO1000, 
3186          "**PROF: GetAppDomainStaticAddress 0x%p, 0x%08x, 0x%p.\n",
3187          classId, 
3188          fieldToken, 
3189          appDomainId));
3190     
3191     //
3192     // Check for NULL parameters
3193     //
3194     if ((classId == NULL) || (appDomainId == NULL) || (ppAddress == NULL))
3195     {
3196         return E_INVALIDARG;
3197     }
3198
3199     // Some domains, like the system domain, aren't APP domains, and thus don't contain any
3200     // statics.  See if the profiler is trying to be naughty.
3201     if (!((BaseDomain*) appDomainId)->IsAppDomain())
3202     {
3203         return E_INVALIDARG;
3204     }
3205
3206     TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3207
3208     //
3209     // If this class is not fully restored, that is all the information we can get at this time.
3210     //
3211     if (!typeHandle.IsRestored())
3212     {
3213         return CORPROF_E_DATAINCOMPLETE;
3214     }
3215
3216     //
3217     // Get the field descriptor object
3218     //
3219     FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3220
3221     if (pFieldDesc == NULL)
3222     {
3223         //
3224         // Give specific error code for literals.
3225         //
3226         DWORD dwFieldAttrs;
3227         if (FAILED(typeHandle.GetModule()->GetMDImport()->GetFieldDefProps(fieldToken, &dwFieldAttrs)))
3228         {
3229             return E_INVALIDARG;
3230         }
3231         
3232         if (IsFdLiteral(dwFieldAttrs))
3233         {
3234             return CORPROF_E_LITERALS_HAVE_NO_ADDRESS;
3235         }
3236
3237         return E_INVALIDARG;
3238     }
3239
3240     //
3241     // Verify this field is of the right type
3242     //
3243     if(!pFieldDesc->IsStatic() ||
3244        pFieldDesc->IsRVA() ||
3245        pFieldDesc->IsThreadStatic())
3246     {
3247         return E_INVALIDARG;
3248     }
3249
3250     // It may seem redundant to try to retrieve the same method table from GetEnclosingMethodTable, but classId 
3251     // leads to the instantiated method table while GetEnclosingMethodTable returns the uninstantiated one.
3252     MethodTable *pMethodTable = pFieldDesc->GetEnclosingMethodTable();
3253     AppDomain * pAppDomain = (AppDomain *)appDomainId;
3254
3255     //
3256     // Check that the data is available
3257     //
3258     if (!IsClassOfMethodTableInited(pMethodTable))
3259     {
3260         return CORPROF_E_DATAINCOMPLETE;
3261     }
3262
3263     //
3264     // Get the address
3265     //
3266     void *base = (void*)pFieldDesc->GetBase();
3267
3268     if (base == NULL)
3269     {
3270         return CORPROF_E_DATAINCOMPLETE;
3271     }
3272
3273     //
3274     // Store the result and return
3275     //
3276     PTR_VOID pAddress = pFieldDesc->GetStaticAddress(base);
3277     if (pAddress == NULL)
3278     {
3279         return E_INVALIDARG;
3280     }
3281
3282     *ppAddress = pAddress;
3283
3284     return S_OK;
3285 }
3286
3287 /*
3288  * GetThreadStaticAddress
3289  *
3290  * This function returns the absolute address of the given field in the given
3291  * class on the given thread.  The field must be an Thread Static token. threadId 
3292  * must be the current thread ID or NULL, which means using curernt thread ID.
3293  *
3294  * Parameters:
3295  *    classId - the containing class.
3296  *    fieldToken - the field we are querying.
3297  *    threadId - the thread container, which has to be the current managed thread or 
3298  *               NULL, which means to use the current managed thread.
3299  *    pAddress - location for storing the resulting address location.
3300  *
3301  * Returns:
3302  *    S_OK on success,
3303  *    E_INVALIDARG if not a thread static,
3304  *    CORPROF_E_DATAINCOMPLETE if not yet initialized.
3305  *
3306  */
3307 HRESULT ProfToEEInterfaceImpl::GetThreadStaticAddress(ClassID classId,
3308                                                       mdFieldDef fieldToken,
3309                                                       ThreadID threadId,
3310                                                       void **ppAddress)
3311 {
3312     CONTRACTL
3313     {
3314         // Yay!
3315         NOTHROW;
3316
3317         // Yay!
3318         GC_NOTRIGGER;
3319
3320         // Yay!
3321         MODE_ANY;
3322
3323         // Yay!
3324         CANNOT_TAKE_LOCK;
3325
3326     }
3327     CONTRACTL_END;
3328
3329     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3330         (LF_CORPROF, 
3331          LL_INFO1000, 
3332          "**PROF: GetThreadStaticAddress 0x%p, 0x%08x, 0x%p.\n",
3333          classId, 
3334          fieldToken, 
3335          threadId));
3336
3337     //
3338     // Verify the value of threadId, which must be the current thread ID or NULL, which means using curernt thread ID.
3339     //
3340     if ((threadId != NULL) && (threadId != ((ThreadID)GetThread())))
3341     {
3342         return E_INVALIDARG;
3343     }
3344
3345     threadId = reinterpret_cast<ThreadID>(GetThread());
3346     AppDomainID appDomainId = reinterpret_cast<AppDomainID>(GetAppDomain());
3347
3348     //
3349     // Check for NULL parameters
3350     //
3351     if ((classId == NULL) || (ppAddress == NULL) || !IsManagedThread(threadId) || (appDomainId == NULL))
3352     {
3353         return E_INVALIDARG;
3354     }
3355
3356     return GetThreadStaticAddress2(classId,
3357                                    fieldToken,
3358                                    appDomainId,
3359                                    threadId,
3360                                    ppAddress);
3361 }
3362
3363 /*
3364  * GetThreadStaticAddress2
3365  *
3366  * This function returns the absolute address of the given field in the given
3367  * class on the given thread.  The field must be an Thread Static token.
3368  *
3369  * Parameters:
3370  *    classId - the containing class.
3371  *    fieldToken - the field we are querying.
3372  *    appDomainId - the AppDomain container.
3373  *    threadId - the thread container.
3374  *    pAddress - location for storing the resulting address location.
3375  *
3376  * Returns:
3377  *    S_OK on success,
3378  *    E_INVALIDARG if not a thread static,
3379  *    CORPROF_E_DATAINCOMPLETE if not yet initialized.
3380  *
3381  */
3382 HRESULT ProfToEEInterfaceImpl::GetThreadStaticAddress2(ClassID classId,
3383                                                        mdFieldDef fieldToken,
3384                                                        AppDomainID appDomainId,
3385                                                        ThreadID threadId,
3386                                                        void **ppAddress)
3387 {
3388     CONTRACTL
3389     {
3390         // Yay!
3391         NOTHROW;
3392
3393         // Yay!
3394         GC_NOTRIGGER;
3395
3396         // Yay!
3397         MODE_ANY;
3398
3399         // Yay!
3400         CANNOT_TAKE_LOCK;
3401
3402     }
3403     CONTRACTL_END;
3404
3405     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3406         (LF_CORPROF, 
3407          LL_INFO1000, 
3408          "**PROF: GetThreadStaticAddress2 0x%p, 0x%08x, 0x%p, 0x%p.\n",
3409          classId,
3410          fieldToken,
3411          appDomainId,
3412          threadId));
3413
3414
3415     if (threadId == NULL)
3416     {
3417         if (GetThread() == NULL)
3418         {
3419             return CORPROF_E_NOT_MANAGED_THREAD;
3420         }
3421
3422         threadId = reinterpret_cast<ThreadID>(GetThread());
3423     }
3424
3425     //
3426     // Check for NULL parameters
3427     //
3428     if ((classId == NULL) || (ppAddress == NULL) || !IsManagedThread(threadId) || (appDomainId == NULL))
3429     {
3430         return E_INVALIDARG;
3431     }
3432
3433     // Some domains, like the system domain, aren't APP domains, and thus don't contain any
3434     // statics.  See if the profiler is trying to be naughty.
3435     if (!((BaseDomain*) appDomainId)->IsAppDomain())
3436     {
3437         return E_INVALIDARG;
3438     }
3439
3440     TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3441
3442     //
3443     // If this class is not fully restored, that is all the information we can get at this time.
3444     //
3445     if (!typeHandle.IsRestored())
3446     {
3447         return CORPROF_E_DATAINCOMPLETE;
3448     }
3449
3450     //
3451     // Get the field descriptor object
3452     //
3453     FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3454
3455     if (pFieldDesc == NULL)
3456     {
3457         return E_INVALIDARG;
3458     }
3459
3460     //
3461     // Verify this field is of the right type
3462     //
3463     if(!pFieldDesc->IsStatic() ||
3464        !pFieldDesc->IsThreadStatic() ||
3465        pFieldDesc->IsRVA())
3466     {
3467         return E_INVALIDARG;
3468     }
3469
3470     // It may seem redundant to try to retrieve the same method table from GetEnclosingMethodTable, but classId 
3471     // leads to the instantiated method table while GetEnclosingMethodTable returns the uninstantiated one.
3472     MethodTable *pMethodTable = pFieldDesc->GetEnclosingMethodTable();
3473
3474     //
3475     // Check that the data is available
3476     //
3477     if (!IsClassOfMethodTableInited(pMethodTable))
3478     {
3479         return CORPROF_E_DATAINCOMPLETE;
3480     }
3481
3482     //
3483     // Store the result and return
3484     //
3485     PTR_VOID pAddress = (void *)(((Thread *)threadId)->GetStaticFieldAddrNoCreate(pFieldDesc));
3486     if (pAddress == NULL)
3487     {
3488         return E_INVALIDARG;
3489     }
3490
3491     *ppAddress = pAddress;
3492
3493     return S_OK;
3494 }
3495
3496 /*
3497  * GetContextStaticAddress
3498  *
3499  * This function returns the absolute address of the given field in the given
3500  * class in the given context.  The field must be an Context Static token.
3501  *
3502  * Parameters:
3503  *    classId - the containing class.
3504  *    fieldToken - the field we are querying.
3505  *    contextId - the context container.
3506  *    pAddress - location for storing the resulting address location.
3507  *
3508  * Returns:
3509  *    E_NOTIMPL
3510  *
3511  */
3512 HRESULT ProfToEEInterfaceImpl::GetContextStaticAddress(ClassID classId,
3513                                                        mdFieldDef fieldToken,
3514                                                        ContextID contextId,
3515                                                        void **ppAddress)
3516 {
3517     CONTRACTL
3518     {
3519         // Yay!
3520         NOTHROW;
3521
3522         // Yay!
3523         GC_NOTRIGGER;
3524
3525         // Yay!
3526         MODE_ANY;
3527
3528         // Yay!
3529         CANNOT_TAKE_LOCK;
3530
3531     }
3532     CONTRACTL_END;
3533
3534     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3535         (LF_CORPROF, 
3536          LL_INFO1000, 
3537          "**PROF: GetContextStaticAddress 0x%p, 0x%08x, 0x%p.\n", 
3538          classId, 
3539          fieldToken, 
3540          contextId));
3541     
3542     return E_NOTIMPL;
3543 }
3544
3545 /*
3546  * GetAppDomainsContainingModule
3547  *
3548  * This function returns the AppDomains in which the given module has been loaded    
3549  *
3550  * Parameters:
3551  *    moduleId - the module with static variables.
3552  *    cAppDomainIds - the input size of appDomainIds array.
3553  *    pcAppDomainIds - the output size of appDomainIds array.
3554  *    appDomainIds - the array to be filled up with AppDomainIDs containing initialized 
3555  *                   static variables from the moduleId's moudle.
3556  *
3557  * Returns:
3558  *    S_OK on success,
3559  *    E_INVALIDARG for invalid parameters,
3560  *    CORPROF_E_DATAINCOMPLETE if moduleId's module is not yet initialized.
3561  *
3562  */
3563 HRESULT ProfToEEInterfaceImpl::GetAppDomainsContainingModule(ModuleID moduleId,
3564                                                              ULONG32 cAppDomainIds,
3565                                                              ULONG32 * pcAppDomainIds, 
3566                                                              AppDomainID appDomainIds[])
3567 {
3568     CONTRACTL
3569     {
3570         // Yay!
3571         NOTHROW;
3572
3573         // This method iterates over AppDomains, which adds, then releases, a reference on 
3574         // each AppDomain iterated.  This causes locking, and can cause triggering if the 
3575         // AppDomain gets destroyed as a result of the release. (See code:AppDomainIterator::Next 
3576         // and its call to code:AppDomain::Release.)
3577         GC_TRIGGERS;
3578
3579         // Yay!
3580         MODE_ANY;
3581
3582         // (See comment above GC_TRIGGERS.)
3583         CAN_TAKE_LOCK;
3584
3585     }
3586     CONTRACTL_END;
3587
3588     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
3589         kP2EEAllowableAfterAttach | kP2EETriggers,
3590         (LF_CORPROF, 
3591          LL_INFO1000, 
3592          "**PROF: GetAppDomainsContainingModule 0x%p, 0x%08x, 0x%p, 0x%p.\n",
3593          moduleId,
3594          cAppDomainIds,
3595          pcAppDomainIds,
3596          appDomainIds));
3597
3598
3599     //
3600     // Check for NULL parameters
3601     //
3602     if ((moduleId == NULL) || ((appDomainIds == NULL) && (cAppDomainIds != 0)) || (pcAppDomainIds == NULL))
3603     {
3604         return E_INVALIDARG;
3605     }
3606    
3607     Module* pModule = reinterpret_cast< Module* >(moduleId);
3608     if (pModule->IsBeingUnloaded())
3609     {
3610         return CORPROF_E_DATAINCOMPLETE;
3611     }
3612
3613     // IterateAppDomainContainingModule uses AppDomainIterator, which cannot be called while the current thread
3614     // is holding the ThreadStore lock.
3615     if (ThreadStore::HoldingThreadStore())
3616     {
3617         return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
3618     }
3619
3620     IterateAppDomainContainingModule iterateAppDomainContainingModule(pModule, cAppDomainIds, pcAppDomainIds, appDomainIds);
3621
3622     return iterateAppDomainContainingModule.PopulateArray();
3623 }
3624
3625
3626
3627 /*
3628  * GetStaticFieldInfo
3629  *
3630  * This function returns a bit mask of the type of statics the
3631  * given field is.
3632  *
3633  * Parameters:
3634  *    classId - the containing class.
3635  *    fieldToken - the field we are querying.
3636  *    pFieldInfo - location for storing the resulting bit mask.
3637  *
3638  * Returns:
3639  *    S_OK on success,
3640  *    E_INVALIDARG if pFieldInfo is NULL
3641  *
3642  */
3643 HRESULT ProfToEEInterfaceImpl::GetStaticFieldInfo(ClassID classId,
3644                                                   mdFieldDef fieldToken,
3645                                                   COR_PRF_STATIC_TYPE *pFieldInfo)
3646 {
3647     CONTRACTL
3648     {
3649         // Yay!
3650         NOTHROW;
3651
3652         // Yay!
3653         GC_NOTRIGGER;
3654
3655         // Yay!
3656         MODE_ANY;
3657
3658         // Yay!
3659         EE_THREAD_NOT_REQUIRED;
3660
3661         // Yay!
3662         CANNOT_TAKE_LOCK;
3663
3664     }
3665     CONTRACTL_END;
3666
3667     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
3668         (LF_CORPROF, 
3669          LL_INFO1000, 
3670          "**PROF: GetStaticFieldInfo 0x%p, 0x%08x.\n", 
3671          classId, 
3672          fieldToken));
3673     
3674     //
3675     // Check for NULL parameters
3676     //
3677     if ((classId == NULL) || (pFieldInfo == NULL))
3678     {
3679         return E_INVALIDARG;
3680     }
3681
3682     TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3683
3684     //
3685     // If this class is not fully restored, that is all the information we can get at this time.
3686     //
3687     if (!typeHandle.IsRestored())
3688     {
3689         return CORPROF_E_DATAINCOMPLETE;
3690     }
3691
3692     //
3693     // Get the field descriptor object
3694     //
3695     FieldDesc *pFieldDesc = typeHandle.GetModule()->LookupFieldDef(fieldToken);
3696
3697     if (pFieldDesc == NULL)
3698     {
3699         return E_INVALIDARG;
3700     }
3701
3702     *pFieldInfo = COR_PRF_FIELD_NOT_A_STATIC;
3703
3704     if (pFieldDesc->IsRVA())
3705     {
3706         *pFieldInfo = (COR_PRF_STATIC_TYPE)(*pFieldInfo | COR_PRF_FIELD_RVA_STATIC);
3707     }
3708
3709     if (pFieldDesc->IsThreadStatic())
3710     {
3711         *pFieldInfo = (COR_PRF_STATIC_TYPE)(*pFieldInfo | COR_PRF_FIELD_THREAD_STATIC);
3712     }
3713
3714     if ((*pFieldInfo == COR_PRF_FIELD_NOT_A_STATIC) && pFieldDesc->IsStatic())
3715     {
3716         *pFieldInfo = (COR_PRF_STATIC_TYPE)(*pFieldInfo | COR_PRF_FIELD_APP_DOMAIN_STATIC);
3717     }
3718
3719     return S_OK;
3720 }
3721
3722
3723
3724 /*
3725  * GetClassIDInfo2
3726  *
3727  * This function generalizes GetClassIDInfo for all types, both generic and non-generic.  It returns
3728  * the module, type token, and an array of instantiation classIDs that were used to instantiate the
3729  * given classId.
3730  *
3731  * Parameters:
3732  *   classId - The classId (TypeHandle) to query information about.
3733  *   pParentClassId - The ClassID (TypeHandle) of the parent class.
3734  *   pModuleId - An optional parameter for returning the module of the class.
3735  *   pTypeDefToken - An optional parameter for returning the metadata token of the class.
3736  *   cNumTypeArgs - The count of the size of the array typeArgs
3737  *   pcNumTypeArgs - Returns the number of elements of typeArgs filled in, or if typeArgs is NULL
3738  *         the number that would be needed.
3739  *   typeArgs - An array to store generic type parameters for the class.
3740  *
3741  * Returns:
3742  *   S_OK if successful.
3743  */
3744 HRESULT ProfToEEInterfaceImpl::GetClassIDInfo2(ClassID classId,
3745                                             ModuleID *pModuleId,
3746                                             mdTypeDef *pTypeDefToken,
3747                                             ClassID *pParentClassId,
3748                                             ULONG32 cNumTypeArgs,
3749                                             ULONG32 *pcNumTypeArgs,
3750                                             ClassID typeArgs[])
3751 {
3752
3753     CONTRACTL
3754     {
3755         // Yay!
3756         NOTHROW;
3757
3758         // Yay!
3759         GC_NOTRIGGER;
3760
3761         // Yay!
3762         MODE_ANY;
3763
3764         // Yay!
3765         EE_THREAD_NOT_REQUIRED;
3766
3767         // Yay!
3768         CANNOT_TAKE_LOCK;
3769
3770
3771         PRECONDITION(CheckPointer(pParentClassId, NULL_OK));
3772         PRECONDITION(CheckPointer(pModuleId, NULL_OK));
3773         PRECONDITION(CheckPointer(pTypeDefToken,  NULL_OK));
3774         PRECONDITION(CheckPointer(pcNumTypeArgs, NULL_OK));
3775         PRECONDITION(CheckPointer(typeArgs, NULL_OK));
3776     }
3777     CONTRACTL_END;
3778
3779     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
3780         (LF_CORPROF, 
3781         LL_INFO1000, 
3782         "**PROF: GetClassIDInfo2 0x%p.\n", 
3783         classId));
3784     
3785     //
3786     // Verify parameters.
3787     //
3788     if (classId == NULL)
3789     {
3790         return E_INVALIDARG;
3791     }
3792
3793     if ((cNumTypeArgs != 0) && (typeArgs == NULL))
3794     {
3795         return E_INVALIDARG;
3796     }
3797
3798     TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
3799
3800     //
3801     // If this class is not fully restored, that is all the information we can get at this time.
3802     //
3803     if (!typeHandle.IsRestored())
3804     {
3805         return CORPROF_E_DATAINCOMPLETE;
3806     }
3807
3808     //
3809     // Handle globals which don't have the instances.
3810     //
3811     if (classId == PROFILER_GLOBAL_CLASS)
3812     {
3813         if (pParentClassId != NULL)
3814         {
3815             *pParentClassId = NULL;
3816         }
3817
3818         if (pModuleId != NULL)
3819         {
3820             *pModuleId = PROFILER_GLOBAL_MODULE;
3821         }
3822
3823         if (pTypeDefToken != NULL)
3824         {
3825             *pTypeDefToken = mdTokenNil;
3826         }
3827
3828         return S_OK;
3829     }
3830
3831     //
3832     // Do not do arrays via this API
3833     //
3834     ARRAY_KIND arrayKind = ArrayKindFromTypeHandle(typeHandle); 
3835     if (arrayKind == ARRAY_KIND_TYPEDESC || arrayKind == ARRAY_KIND_METHODTABLE)
3836     {
3837         return CORPROF_E_CLASSID_IS_ARRAY;
3838     }
3839
3840     _ASSERTE (arrayKind == ARRAY_KIND_NOTARRAY);
3841     
3842     if (typeHandle.IsTypeDesc())
3843     {
3844         // Not an array, but still a typedesc?  We don't know how to
3845         // deal with those.
3846         return CORPROF_E_CLASSID_IS_COMPOSITE;
3847     }
3848
3849     //
3850     // Fill in the basic information
3851     //
3852     if (pParentClassId != NULL)
3853     {
3854         TypeHandle parentTypeHandle = typeHandle.GetParent();
3855         if (!parentTypeHandle.IsNull())
3856         {
3857             *pParentClassId = TypeHandleToClassID(parentTypeHandle);
3858         }
3859         else
3860         {
3861             *pParentClassId = NULL;
3862         }
3863     }
3864
3865     if (pModuleId != NULL)
3866     {
3867         *pModuleId = (ModuleID) typeHandle.GetModule();
3868         _ASSERTE(*pModuleId != NULL);
3869     }
3870
3871     if (pTypeDefToken != NULL)
3872     {
3873         *pTypeDefToken = typeHandle.GetCl();
3874         _ASSERTE(*pTypeDefToken != NULL);
3875     }
3876
3877     //
3878     // See if they are just looking to get the buffer size.
3879     //
3880     if (cNumTypeArgs == 0)
3881     {
3882         if (pcNumTypeArgs != NULL)
3883         {
3884             *pcNumTypeArgs = typeHandle.GetMethodTable()->GetNumGenericArgs();
3885         }
3886         return S_OK;
3887     }
3888
3889     //
3890     // Adjust the count for the size of the given array.
3891     //
3892     if (cNumTypeArgs > typeHandle.GetMethodTable()->GetNumGenericArgs())
3893     {
3894         cNumTypeArgs = typeHandle.GetMethodTable()->GetNumGenericArgs();
3895     }
3896
3897     if (pcNumTypeArgs != NULL)
3898     {
3899         *pcNumTypeArgs = cNumTypeArgs;
3900     }
3901
3902     //
3903     // Copy over the instantiating types.
3904     //
3905     ULONG32 count;
3906     Instantiation inst = typeHandle.GetMethodTable()->GetInstantiation();
3907
3908     for (count = 0; count < cNumTypeArgs; count ++)
3909     {
3910         typeArgs[count] = TypeHandleToClassID(inst[count]);
3911     }
3912
3913     return S_OK;
3914 }
3915
3916 HRESULT ProfToEEInterfaceImpl::GetModuleInfo(ModuleID     moduleId,
3917     LPCBYTE *    ppBaseLoadAddress,
3918     ULONG        cchName,
3919     ULONG *      pcchName,
3920     __out_ecount_part_opt(cchName, *pcchName) WCHAR wszName[],
3921     AssemblyID * pAssemblyId)
3922 {
3923     CONTRACTL
3924     {
3925         // Yay!
3926         NOTHROW;
3927         
3928         // Yay!
3929         GC_NOTRIGGER; 
3930
3931         // See comment in code:ProfToEEInterfaceImpl::GetModuleInfo2
3932         CAN_TAKE_LOCK;
3933
3934         // Yay!
3935         MODE_ANY;
3936
3937         // Yay!
3938         EE_THREAD_NOT_REQUIRED;
3939
3940
3941         PRECONDITION(CheckPointer((Module *)moduleId, NULL_OK));
3942         PRECONDITION(CheckPointer(ppBaseLoadAddress,  NULL_OK));
3943         PRECONDITION(CheckPointer(pcchName, NULL_OK));
3944         PRECONDITION(CheckPointer(wszName, NULL_OK));
3945         PRECONDITION(CheckPointer(pAssemblyId, NULL_OK));
3946     }
3947     CONTRACTL_END;
3948
3949     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
3950         (LF_CORPROF, 
3951         LL_INFO1000, 
3952         "**PROF: GetModuleInfo 0x%p.\n", 
3953         moduleId));    
3954
3955     // Paramter validation is taken care of in GetModuleInfo2.
3956
3957     return GetModuleInfo2(
3958         moduleId,
3959         ppBaseLoadAddress,
3960         cchName,
3961         pcchName,
3962         wszName,
3963         pAssemblyId,
3964         NULL);          // Don't need module type
3965 }
3966
3967 //---------------------------------------------------------------------------------------
3968 //
3969 // Helper used by GetModuleInfo2 to determine the bitmask of COR_PRF_MODULE_FLAGS for
3970 // the specified module. 
3971 //
3972 // Arguments:
3973 //      pModule - Module to get the flags for
3974 //
3975 // Return Value:
3976 //      Bitmask of COR_PRF_MODULE_FLAGS corresponding to pModule
3977 //
3978
3979 DWORD ProfToEEInterfaceImpl::GetModuleFlags(Module * pModule)
3980 {
3981     CONTRACTL
3982     {
3983         NOTHROW;
3984         GC_NOTRIGGER; 
3985         CAN_TAKE_LOCK;     // IsWindowsRuntimeModule accesses metadata directly, which takes locks
3986         MODE_ANY;
3987     }
3988     CONTRACTL_END;
3989
3990     PEFile * pPEFile = pModule->GetFile();
3991     if (pPEFile == NULL)
3992     {
3993         // Hopefully this should never happen; but just in case, don't try to determine the
3994         // flags without a PEFile.
3995         return 0;
3996     }
3997
3998     DWORD dwRet = 0;
3999
4000     // First, set the flags that are dependent on which PEImage / layout we look at
4001     // inside the Module (disk/ngen/flat)
4002     
4003     if (pModule->HasNativeImage())
4004     {
4005         // NGEN
4006         dwRet |= (COR_PRF_MODULE_DISK | COR_PRF_MODULE_NGEN);
4007
4008         // Intentionally not checking for flat, since NGEN PEImages never have flat
4009         // layouts.
4010     }
4011     else
4012     {
4013 #ifdef FEATURE_READYTORUN 
4014         // pModule->HasNativeImage() returns false for ReadyToRun images
4015         if (pModule->IsReadyToRun())
4016         {
4017             // Ready To Run
4018             dwRet |= (COR_PRF_MODULE_DISK | COR_PRF_MODULE_NGEN);
4019         }
4020 #endif
4021         // Not NGEN or ReadyToRun.
4022         if (pPEFile->HasOpenedILimage())
4023         {
4024             PEImage * pILImage = pPEFile->GetOpenedILimage();
4025             if (pILImage->IsFile())
4026             {
4027                 dwRet |= COR_PRF_MODULE_DISK;
4028             }           
4029             if (pPEFile->GetLoadedIL()->IsFlat())
4030             {
4031                 dwRet |= COR_PRF_MODULE_FLAT_LAYOUT;
4032             }
4033         }
4034     }
4035
4036     if (pModule->IsReflection())
4037     {
4038         dwRet |= COR_PRF_MODULE_DYNAMIC;
4039     }
4040
4041     if (pModule->IsCollectible())
4042     {
4043         dwRet |= COR_PRF_MODULE_COLLECTIBLE;
4044     }
4045
4046     if (pModule->IsResource())
4047     {
4048         dwRet |= COR_PRF_MODULE_RESOURCE;
4049     }
4050
4051     if (pModule->IsWindowsRuntimeModule())
4052     {
4053         dwRet |= COR_PRF_MODULE_WINDOWS_RUNTIME;
4054     }
4055     
4056     return dwRet;
4057 }
4058
4059 HRESULT ProfToEEInterfaceImpl::GetModuleInfo2(ModuleID     moduleId,
4060     LPCBYTE *    ppBaseLoadAddress,
4061     ULONG        cchName,
4062     ULONG *      pcchName,
4063     __out_ecount_part_opt(cchName, *pcchName) WCHAR wszName[],
4064     AssemblyID * pAssemblyId,
4065     DWORD *      pdwModuleFlags)
4066 {
4067     CONTRACTL
4068     {
4069         // Yay!
4070         NOTHROW;
4071         
4072         // Yay!
4073         GC_NOTRIGGER; 
4074
4075         // The pModule->GetScopeName() call below can result in locks getting taken to
4076         // access the metadata implementation.  However, these locks do not do a mode
4077         // change.
4078         CAN_TAKE_LOCK;
4079
4080         // Yay!
4081         MODE_ANY;
4082
4083         // Yay!
4084         EE_THREAD_NOT_REQUIRED;
4085
4086
4087         PRECONDITION(CheckPointer((Module *)moduleId, NULL_OK));
4088         PRECONDITION(CheckPointer(ppBaseLoadAddress,  NULL_OK));
4089         PRECONDITION(CheckPointer(pcchName, NULL_OK));
4090         PRECONDITION(CheckPointer(wszName, NULL_OK));
4091         PRECONDITION(CheckPointer(pAssemblyId, NULL_OK));
4092     }
4093     CONTRACTL_END;
4094
4095     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4096         (LF_CORPROF, 
4097         LL_INFO1000, 
4098         "**PROF: GetModuleInfo2 0x%p.\n", 
4099         moduleId));    
4100
4101     if (moduleId == NULL)
4102     {
4103         return E_INVALIDARG;
4104     }
4105     
4106     Module * pModule = (Module *) moduleId;
4107     if (pModule->IsBeingUnloaded())
4108     {
4109         return CORPROF_E_DATAINCOMPLETE;
4110     }
4111     
4112     HRESULT     hr = S_OK;
4113
4114     EX_TRY
4115     {
4116         
4117         PEFile * pFile = pModule->GetFile();
4118
4119         // Pick some safe defaults to begin with.
4120         if (ppBaseLoadAddress != NULL)
4121             *ppBaseLoadAddress = 0;
4122         if (wszName != NULL)
4123             *wszName = 0;
4124         if (pcchName != NULL)
4125             *pcchName = 0;
4126         if (pAssemblyId != NULL)
4127             *pAssemblyId = PROFILER_PARENT_UNKNOWN;
4128
4129         // Module flags can be determined first without fear of error
4130         if (pdwModuleFlags != NULL)
4131             *pdwModuleFlags = GetModuleFlags(pModule);
4132
4133         // Get the module file name
4134         LPCWSTR wszFileName = pFile->GetPath();
4135         _ASSERTE(wszFileName != NULL);
4136         PREFIX_ASSUME(wszFileName != NULL);
4137
4138         // If there is no filename, which is the case for RefEmit modules and for SQL
4139         // modules, then rather than returning an empty string for the name, just use the
4140         // module name from metadata (a.k.a. Module.ScopeName). This is required to
4141         // support SQL F1 sampling profiling.
4142         StackSString strScopeName;
4143         LPCUTF8 szScopeName = NULL;
4144         if ((*wszFileName == W('\0')) && SUCCEEDED(pModule->GetScopeName(&szScopeName)))
4145         {
4146             strScopeName.SetUTF8(szScopeName);
4147             strScopeName.Normalize();
4148             wszFileName = strScopeName.GetUnicode();
4149         }
4150
4151         ULONG trueLen = (ULONG)(wcslen(wszFileName) + 1);
4152
4153         // Return name of module as required.
4154         if (wszName && cchName > 0)
4155         {
4156             if (cchName < trueLen)
4157             {
4158                 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
4159             }
4160             else
4161             {
4162                 wcsncpy_s(wszName, cchName, wszFileName, trueLen);
4163             }
4164         }
4165
4166         // If they request the actual length of the name
4167         if (pcchName)
4168             *pcchName = trueLen;
4169
4170         if (ppBaseLoadAddress != NULL && !pFile->IsDynamic())
4171         {
4172             if (pModule->IsProfilerNotified())
4173             {
4174                 // Set the base load address -- this could be null in certain error conditions
4175                 *ppBaseLoadAddress = pModule->GetProfilerBase();
4176             }
4177             else
4178             {
4179                 *ppBaseLoadAddress = NULL;
4180             }
4181
4182             if (*ppBaseLoadAddress == NULL)
4183             {
4184                 hr = CORPROF_E_DATAINCOMPLETE;
4185             }
4186         }
4187
4188         // Return the parent assembly for this module if desired.
4189         if (pAssemblyId != NULL)
4190         {
4191             // Lie and say the assembly isn't avaialable until we are loaded (even though it is.)
4192             // This is for backward compatibilty - we may want to change it
4193             if (pModule->IsProfilerNotified())
4194             {
4195                 Assembly *pAssembly = pModule->GetAssembly();
4196                 _ASSERTE(pAssembly);
4197
4198                 *pAssemblyId = (AssemblyID) pAssembly;
4199             }
4200             else
4201             {
4202                 hr = CORPROF_E_DATAINCOMPLETE;
4203             }
4204         }
4205     }
4206     EX_CATCH_HRESULT(hr);
4207
4208     return (hr);
4209 }
4210
4211
4212 /*
4213  * Get a metadata interface instance which maps to the given module.
4214  * One may ask for the metadata to be opened in read+write mode, but
4215  * this will result in slower metadata execution of the program, because
4216  * changes made to the metadata cannot be optimized as they were from
4217  * the compiler.
4218  */
4219 HRESULT ProfToEEInterfaceImpl::GetModuleMetaData(ModuleID    moduleId,
4220     DWORD       dwOpenFlags,
4221     REFIID      riid,
4222     IUnknown    **ppOut)
4223 {
4224     CONTRACTL
4225     {
4226         // Yay!
4227         NOTHROW;
4228
4229         // Yay!
4230         GC_NOTRIGGER;
4231
4232         // Yay!
4233         MODE_ANY;
4234
4235         // Currently, this function is technically EE_THREAD_REQUIRED because
4236         // some functions in synch.cpp assert that there is a Thread object,
4237         // but we might be able to lift that restriction and make this be
4238         // EE_THREAD_NOT_REQUIRED.
4239
4240         // PEFile::GetRWImporter & PEFile::GetEmitter &
4241         // GetReadablePublicMetaDataInterface take locks
4242         CAN_TAKE_LOCK;
4243
4244     }
4245     CONTRACTL_END;
4246
4247     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
4248         (LF_CORPROF, 
4249         LL_INFO1000, 
4250         "**PROF: GetModuleMetaData 0x%p, 0x%08x.\n", 
4251         moduleId, 
4252         dwOpenFlags));
4253
4254     if (moduleId == NULL)
4255     {
4256         return E_INVALIDARG;
4257     }
4258
4259     // Check for unsupported bits, and return E_INVALIDARG if present
4260     if ((dwOpenFlags & ~(ofNoTransform | ofRead | ofWrite)) != 0)
4261     {
4262         return E_INVALIDARG;
4263     }
4264
4265     Module * pModule;
4266     HRESULT hr = S_OK;
4267
4268     pModule = (Module *) moduleId;
4269     _ASSERTE(pModule != NULL);
4270     if (pModule->IsBeingUnloaded())
4271     {
4272         return CORPROF_E_DATAINCOMPLETE;
4273     }
4274
4275     // Make sure we can get the importer first
4276     if (pModule->IsResource())
4277     {
4278         if (ppOut)
4279             *ppOut = NULL;
4280         return S_FALSE;
4281     }
4282
4283     // Decide which type of open mode we are in to see which you require.
4284     if ((dwOpenFlags & ofWrite) == 0)
4285     {
4286         // Readable interface
4287         return pModule->GetReadablePublicMetaDataInterface(dwOpenFlags, riid, (LPVOID *) ppOut);
4288     }
4289
4290     // Writeable interface
4291     IUnknown *pObj = NULL;
4292     EX_TRY
4293     {
4294         pObj = pModule->GetValidatedEmitter();
4295     }
4296     EX_CATCH_HRESULT_NO_ERRORINFO(hr);
4297
4298     // Ask for the interface the caller wanted, only if they provide a out param
4299     if (SUCCEEDED(hr) && ppOut)
4300         hr = pObj->QueryInterface(riid, (void **) ppOut);
4301
4302     return (hr);
4303 }
4304
4305
4306 /*
4307  * Retrieve a pointer to the body of a method starting at it's header.
4308  * A method is scoped by the module it lives in.  Because this function
4309  * is designed to give a tool access to IL before it has been loaded
4310  * by the Runtime, it uses the metadata token of the method to find
4311  * the instance desired.  Note that this function has no effect on
4312  * already compiled code.
4313  */
4314 HRESULT ProfToEEInterfaceImpl::GetILFunctionBody(ModuleID    moduleId,
4315     mdMethodDef methodId,
4316     LPCBYTE     *ppMethodHeader,
4317     ULONG       *pcbMethodSize)
4318 {
4319     CONTRACTL
4320     {
4321         // Yay!
4322         NOTHROW;
4323
4324         // Yay!
4325         GC_NOTRIGGER;
4326
4327         // Yay!
4328         MODE_ANY;
4329
4330         // PEFile::CheckLoaded & Module::GetDynamicIL both take a lock
4331         CAN_TAKE_LOCK;
4332
4333     }
4334     CONTRACTL_END;
4335
4336     
4337     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(
4338         kP2EEAllowableAfterAttach,
4339         (LF_CORPROF, 
4340          LL_INFO1000, 
4341          "**PROF: GetILFunctionBody 0x%p, 0x%08x.\n",
4342          moduleId, 
4343          methodId));    
4344
4345     Module *    pModule;                // Working pointer for real class.
4346     ULONG       RVA;                    // Return RVA of the method body.
4347     DWORD       dwImplFlags;            // Flags for the item.
4348     
4349     if ((moduleId == NULL) ||
4350         (methodId == mdMethodDefNil) ||
4351         (methodId == 0) ||
4352         (TypeFromToken(methodId) != mdtMethodDef))
4353     {
4354         return E_INVALIDARG;
4355     }
4356     
4357     pModule = (Module *) moduleId;
4358     _ASSERTE(pModule != NULL && methodId != mdMethodDefNil);
4359     if (pModule->IsBeingUnloaded())
4360     {
4361         return CORPROF_E_DATAINCOMPLETE;
4362     }
4363
4364     // Find the method body based on metadata.
4365     IMDInternalImport *pImport = pModule->GetMDImport();
4366     _ASSERTE(pImport);
4367
4368     PEFile *pFile = pModule->GetFile();
4369
4370     if (!pFile->CheckLoaded())
4371         return (CORPROF_E_DATAINCOMPLETE);
4372
4373     LPCBYTE pbMethod = NULL;
4374
4375     // Don't return rewritten IL, use the new API to get that.
4376     pbMethod = (LPCBYTE) pModule->GetDynamicIL(methodId, FALSE);
4377
4378     // Method not overriden - get the original copy of the IL by going to metadata
4379     if (pbMethod == NULL)
4380     {
4381         HRESULT hr = S_OK;
4382         IfFailRet(pImport->GetMethodImplProps(methodId, &RVA, &dwImplFlags));
4383         
4384         // Check to see if the method has associated IL
4385         if ((RVA == 0 && !pFile->IsDynamic()) || !(IsMiIL(dwImplFlags) || IsMiOPTIL(dwImplFlags) || IsMiInternalCall(dwImplFlags)))
4386         {
4387             return (CORPROF_E_FUNCTION_NOT_IL);
4388         }
4389         
4390         EX_TRY
4391         {
4392             // Get the location of the IL
4393             pbMethod = (LPCBYTE) (pModule->GetIL(RVA));
4394         }
4395         EX_CATCH_HRESULT(hr);
4396         
4397         if (FAILED(hr))
4398         {
4399             return hr;
4400         }
4401     }
4402     
4403     // Fill out param if provided
4404     if (ppMethodHeader)
4405         *ppMethodHeader = pbMethod;
4406
4407     // Calculate the size of the method itself.
4408     if (pcbMethodSize)
4409     {
4410         if (!FitsIn<ULONG>(PEDecoder::ComputeILMethodSize((TADDR)pbMethod)))
4411         {
4412             return E_UNEXPECTED;
4413         }
4414         *pcbMethodSize = static_cast<ULONG>(PEDecoder::ComputeILMethodSize((TADDR)pbMethod));
4415     }
4416     return (S_OK);
4417 }
4418
4419 //---------------------------------------------------------------------------------------
4420 // Retrieves an IMethodMalloc pointer around a ModuleILHeap instance that will own
4421 // allocating heap space for this module (for IL rewriting).
4422 //
4423 // Arguments:
4424 //      moduleId - ModuleID this allocator shall allocate for
4425 //      ppMalloc - [out] IMethodMalloc pointer the profiler will use for allocation requests
4426 //                       against this module
4427 //
4428 // Return value
4429 //      HRESULT indicating success / failure
4430 //
4431 // Notes
4432 //        IL method bodies used to have the requirement that they must be referenced as
4433 //        RVA's to the loaded module, which means they come after the module within
4434 //        METHOD_MAX_RVA.  In order to make it easier for a tool to swap out the body of
4435 //        a method, this allocator will ensure memory allocated after that point.
4436 //
4437 //        Now that requirement is completely gone, so there's nothing terribly special
4438 //        about this allocator, we just keep it around for legacy purposes.
4439
4440 HRESULT ProfToEEInterfaceImpl::GetILFunctionBodyAllocator(ModuleID         moduleId,
4441                                                           IMethodMalloc ** ppMalloc)
4442 {
4443     CONTRACTL
4444     {
4445         // Yay!
4446         NOTHROW;
4447
4448         // ModuleILHeap::FindOrCreateHeap may take a Crst if it
4449         // needs to create a new allocator and add it to the list.  Taking a crst
4450         // switches to preemptive, which is effectively a GC trigger
4451         GC_TRIGGERS;
4452
4453         // Yay!
4454         MODE_ANY;
4455
4456         // Yay!
4457         EE_THREAD_NOT_REQUIRED;
4458
4459         // (see GC_TRIGGERS comment)
4460         CAN_TAKE_LOCK;
4461
4462     }
4463     CONTRACTL_END;
4464     
4465     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
4466         kP2EEAllowableAfterAttach | kP2EETriggers,
4467         (LF_CORPROF, 
4468         LL_INFO1000, 
4469         "**PROF: GetILFunctionBodyAllocator 0x%p.\n", 
4470         moduleId));
4471     
4472     if ((moduleId == NULL) || (ppMalloc == NULL))
4473     {
4474         return E_INVALIDARG;
4475     }
4476
4477     Module * pModule = (Module *) moduleId;
4478
4479     if (pModule->IsBeingUnloaded() ||
4480         !pModule->GetFile()->CheckLoaded())
4481     {
4482         return (CORPROF_E_DATAINCOMPLETE);
4483     }
4484
4485     *ppMalloc = &ModuleILHeap::s_Heap;
4486     return S_OK;
4487 }
4488
4489 /*
4490  * Replaces the method body for a function in a module.  This will replace
4491  * the RVA of the method in the metadata to point to this new method body,
4492  * and adjust any internal data structures as required.  This function can
4493  * only be called on those methods which have never been compiled by a JITTER.
4494  * Please use the GetILFunctionBodyAllocator to allocate space for the new method to
4495  * ensure the buffer is compatible.
4496  */
4497 HRESULT ProfToEEInterfaceImpl::SetILFunctionBody(ModuleID    moduleId,
4498     mdMethodDef methodId,
4499     LPCBYTE     pbNewILMethodHeader)
4500 {
4501     CONTRACTL
4502     {
4503         // PEFile::GetEmitter, Module::SetDynamicIL all throw
4504         THROWS;
4505         
4506         // Locks are taken (see CAN_TAKE_LOCK below), which may cause mode switch to
4507         // preemptive, which is triggers.
4508         GC_TRIGGERS;
4509
4510         // Yay!
4511         MODE_ANY;
4512
4513         // Module::SetDynamicIL & PEFile::CheckLoaded & PEFile::GetEmitter take locks
4514         CAN_TAKE_LOCK;
4515
4516     }
4517     CONTRACTL_END;
4518
4519     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
4520         kP2EEAllowableAfterAttach | kP2EETriggers,
4521         (LF_CORPROF, 
4522          LL_INFO1000, 
4523          "**PROF: SetILFunctionBody 0x%p, 0x%08x.\n",
4524          moduleId, 
4525          methodId));        
4526     
4527     if ((moduleId == NULL) ||
4528         (methodId == mdMethodDefNil) ||
4529         (TypeFromToken(methodId) != mdtMethodDef) ||
4530         (pbNewILMethodHeader == NULL))
4531     {
4532         return E_INVALIDARG;
4533     }
4534     
4535     Module      *pModule;               // Working pointer for real class.
4536     HRESULT     hr = S_OK;
4537
4538     // Cannot set the body for anything other than a method def
4539     if (TypeFromToken(methodId) != mdtMethodDef)
4540         return (E_INVALIDARG);
4541
4542     // Cast module to appropriate type
4543     pModule = (Module *) moduleId;
4544     _ASSERTE (pModule != NULL); // Enforced in CorProfInfo::SetILFunctionBody
4545     if (pModule->IsBeingUnloaded())
4546     {
4547         return CORPROF_E_DATAINCOMPLETE;
4548     }
4549
4550     // Remember the profiler is doing this, as that means we must never detach it!
4551     g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
4552
4553     // This action is not temporary!
4554     // If the profiler want to be able to revert, they need to use
4555     // the new ReJIT APIs.
4556     pModule->SetDynamicIL(methodId, (TADDR)pbNewILMethodHeader, FALSE);
4557
4558     return (hr);
4559 }
4560
4561 /*
4562  * Sets the codemap for the replaced IL function body
4563  */
4564 HRESULT ProfToEEInterfaceImpl::SetILInstrumentedCodeMap(FunctionID functionId,
4565         BOOL fStartJit,
4566         ULONG cILMapEntries,
4567         COR_IL_MAP rgILMapEntries[])
4568 {
4569     CONTRACTL
4570     {
4571         // Debugger::SetILInstrumentedCodeMap throws
4572         THROWS;
4573
4574         // Debugger::SetILInstrumentedCodeMap triggers
4575         GC_TRIGGERS;
4576
4577         // Yay!
4578         MODE_ANY;
4579
4580         // Yay!
4581         EE_THREAD_NOT_REQUIRED;
4582
4583         // Debugger::SetILInstrumentedCodeMap takes a lock when it calls Debugger::GetOrCreateMethodInfo
4584         CAN_TAKE_LOCK;
4585
4586     }
4587     CONTRACTL_END;
4588
4589     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
4590         kP2EEAllowableAfterAttach | kP2EETriggers,
4591         (LF_CORPROF, 
4592          LL_INFO1000, 
4593          "**PROF: SetILInstrumentedCodeMap 0x%p, %d.\n",
4594          functionId, 
4595          fStartJit));        
4596        
4597     if (functionId == NULL)
4598     {
4599         return E_INVALIDARG;
4600     }
4601
4602     if (cILMapEntries >= (MAXULONG / sizeof(COR_IL_MAP)))
4603     {
4604         // Too big!  The allocation below would overflow when calculating the size.
4605         return E_INVALIDARG;
4606     }
4607     
4608     
4609 #ifdef DEBUGGING_SUPPORTED
4610
4611     MethodDesc *pMethodDesc = FunctionIdToMethodDesc(functionId);
4612
4613     // it's not safe to examine a methoddesc that has not been restored so do not do so
4614     if (!pMethodDesc ->IsRestored())
4615         return CORPROF_E_DATAINCOMPLETE;
4616
4617     if (g_pDebugInterface == NULL)
4618     {
4619         return CORPROF_E_DEBUGGING_DISABLED;
4620     }
4621
4622     COR_IL_MAP * rgNewILMapEntries = new (nothrow) COR_IL_MAP[cILMapEntries];
4623
4624     if (rgNewILMapEntries == NULL)
4625         return E_OUTOFMEMORY;
4626
4627     memcpy_s(rgNewILMapEntries, sizeof(COR_IL_MAP) * cILMapEntries, rgILMapEntries, sizeof(COR_IL_MAP) * cILMapEntries);
4628
4629     return g_pDebugInterface->SetILInstrumentedCodeMap(pMethodDesc,
4630                                                        fStartJit,
4631                                                        cILMapEntries,
4632                                                        rgNewILMapEntries);
4633
4634 #else //DEBUGGING_SUPPORTED
4635     return E_NOTIMPL;
4636 #endif //DEBUGGING_SUPPORTED
4637 }
4638
4639 HRESULT ProfToEEInterfaceImpl::ForceGC()
4640 {
4641     CONTRACTL
4642     {
4643         // GC calls "new" which throws
4644         THROWS;
4645
4646         // Uh duh, look at the name of the function, dude
4647         GC_TRIGGERS;
4648
4649         // Yay!
4650         MODE_ANY;
4651
4652         // Yay!
4653         EE_THREAD_NOT_REQUIRED;
4654
4655         // Initiating a GC causes a runtime suspension which requires the
4656         // mother of all locks: the thread store lock.
4657         CAN_TAKE_LOCK;
4658
4659     }
4660     CONTRACTL_END;
4661
4662     ASSERT_NO_EE_LOCKS_HELD();
4663
4664     // We need to use IsGarbageCollectorFullyInitialized() instead of IsGCHeapInitialized() because
4665     // there are other GC initialization being done after IsGCHeapInitialized() becomes TRUE, 
4666     // and before IsGarbageCollectorFullyInitialized() becomes TRUE.
4667     if (!IsGarbageCollectorFullyInitialized())
4668     {
4669         return CORPROF_E_NOT_YET_AVAILABLE;
4670     }
4671
4672     // Disallow the cases where a profiler calls this off a hijacked CLR thread 
4673     // or inside a profiler callback.  (Allow cases where this is a native thread, or a
4674     // thread which previously successfully called ForceGC.)
4675     Thread * pThread = GetThreadNULLOk();
4676     if ((pThread != NULL) &&
4677             (!AreCallbackStateFlagsSet(COR_PRF_CALLBACKSTATE_FORCEGC_WAS_CALLED)) &&
4678             (pThread->GetFrame() != FRAME_TOP
4679             || AreCallbackStateFlagsSet(COR_PRF_CALLBACKSTATE_INCALLBACK)))
4680     {
4681         LOG((LF_CORPROF,
4682              LL_ERROR,
4683              "**PROF: ERROR: Returning CORPROF_E_UNSUPPORTED_CALL_SEQUENCE "
4684              "due to illegal hijacked profiler call or call from inside another callback\n"));
4685         return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
4686     }
4687
4688     // NOTE: We cannot use the standard macro PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX
4689     // here because the macro ensures that either the current thread is not an 
4690     // EE thread, or, if it is, that the CALLBACK flag is set. In classic apps
4691     // a profiler-owned native thread will not get an EE thread associated with 
4692     // it, however, in AppX apps, during the first call into the GC on a
4693     // profiler-owned thread, the EE will associate an EE-thread with the profiler
4694     // thread. As a consequence the second call to ForceGC on the same thread
4695     // would fail, since this is now an EE thread and this API is not called from
4696     // a callback.
4697
4698     // First part of the PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX macro:
4699     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(
4700         kP2EEAllowableAfterAttach | kP2EETriggers,
4701         (LF_CORPROF, 
4702         LL_INFO1000, 
4703         "**PROF: ForceGC.\n"));        
4704
4705 #ifdef FEATURE_EVENT_TRACE
4706     // This helper, used by ETW and profAPI ensures a managed thread gets created for
4707     // this thread before forcing the GC (to work around Jupiter issues where it's
4708     // expected this thread is already managed before starting the GC).
4709     HRESULT hr = ETW::GCLog::ForceGCForDiagnostics();
4710 #else // !FEATURE_EVENT_TRACE
4711     HRESULT hr = E_FAIL;
4712 #endif // FEATURE_EVENT_TRACE
4713  
4714     // If a Thread object was just created for this thread, remember the fact that it
4715     // was a ForceGC() thread, so we can be more lenient when doing
4716     // COR_PRF_CALLBACKSTATE_INCALLBACK later on from other APIs
4717     pThread = GetThreadNULLOk();
4718     if (pThread != NULL)
4719     {
4720         pThread->SetProfilerCallbackStateFlags(COR_PRF_CALLBACKSTATE_FORCEGC_WAS_CALLED);
4721     }
4722
4723     return hr;
4724 }
4725
4726
4727 /*
4728  * Returns the ContextID for the current thread.
4729  */
4730 HRESULT ProfToEEInterfaceImpl::GetThreadContext(ThreadID threadId,
4731                                                 ContextID *pContextId)
4732 {
4733     CONTRACTL
4734     {
4735         // Yay!
4736         NOTHROW;
4737
4738         // Yay!
4739         GC_NOTRIGGER;
4740
4741         // Yay!
4742         MODE_ANY;
4743
4744         // Yay!
4745         EE_THREAD_NOT_REQUIRED;
4746
4747         // Yay!
4748         CANNOT_TAKE_LOCK;
4749
4750     }
4751     CONTRACTL_END;
4752
4753     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4754         (LF_CORPROF, 
4755          LL_INFO1000, 
4756          "**PROF: GetThreadContext 0x%p.\n", 
4757          threadId));
4758     
4759     if (!IsManagedThread(threadId))
4760     {
4761         return E_INVALIDARG;
4762     }
4763
4764     // Cast to right type
4765     Thread *pThread = reinterpret_cast<Thread *>(threadId);
4766
4767     // Get the context for the Thread* provided
4768     AppDomain *pContext = pThread->GetDomain(); // Context is same as AppDomain in CoreCLR
4769     _ASSERTE(pContext);
4770
4771     // If there's no current context, return incomplete info
4772     if (!pContext)
4773         return (CORPROF_E_DATAINCOMPLETE);
4774
4775     // Set the result and return
4776     if (pContextId)
4777         *pContextId = reinterpret_cast<ContextID>(pContext);
4778
4779     return (S_OK);
4780 }
4781
4782 HRESULT ProfToEEInterfaceImpl::GetClassIDInfo(ClassID classId,
4783     ModuleID *pModuleId,
4784     mdTypeDef *pTypeDefToken)
4785 {
4786     CONTRACTL
4787     {
4788         // Yay!
4789         NOTHROW;
4790
4791         // Yay!
4792         GC_NOTRIGGER;
4793
4794         // Yay!
4795         MODE_ANY;
4796
4797         // Yay!
4798         EE_THREAD_NOT_REQUIRED;
4799
4800         // Yay!
4801         CANNOT_TAKE_LOCK;
4802
4803     }
4804     CONTRACTL_END;
4805     
4806     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4807         (LF_CORPROF, 
4808         LL_INFO1000, 
4809         "**PROF: GetClassIDInfo 0x%p.\n",
4810         classId));
4811
4812     if (classId == NULL)
4813     {
4814         return E_INVALIDARG;
4815     }
4816     
4817     if (pModuleId != NULL)
4818     {
4819         *pModuleId = NULL;
4820     }
4821
4822     if (pTypeDefToken != NULL)
4823     {
4824         *pTypeDefToken = NULL;
4825     }
4826
4827     // Handle globals which don't have the instances.
4828     if (classId == PROFILER_GLOBAL_CLASS)
4829     {
4830         if (pModuleId != NULL)
4831         {
4832             *pModuleId = PROFILER_GLOBAL_MODULE;
4833         }
4834
4835         if (pTypeDefToken != NULL)
4836         {
4837             *pTypeDefToken = mdTokenNil;
4838     }
4839     }
4840     else if (classId == NULL)
4841     {
4842         return E_INVALIDARG;
4843     }
4844     // Get specific data.
4845     else
4846     {
4847         TypeHandle th = TypeHandle::FromPtr((void *)classId);
4848
4849         if (!th.IsTypeDesc())
4850         {
4851             if (!th.IsArray())
4852             {
4853                 //
4854                 // If this class is not fully restored, that is all the information we can get at this time.
4855                 //
4856                 if (!th.IsRestored())
4857                 {
4858                     return CORPROF_E_DATAINCOMPLETE;
4859                 }
4860
4861                 if (pModuleId != NULL)
4862                 {
4863                     *pModuleId = (ModuleID) th.GetModule();
4864                     _ASSERTE(*pModuleId != NULL);
4865                 }
4866
4867                 if (pTypeDefToken != NULL)
4868                 {
4869                     *pTypeDefToken = th.GetCl();
4870                     _ASSERTE(*pTypeDefToken != NULL);
4871                 }
4872             }
4873         }
4874     }
4875
4876     return (S_OK);
4877 }
4878
4879
4880 HRESULT ProfToEEInterfaceImpl::GetFunctionInfo(FunctionID functionId,
4881     ClassID *pClassId,
4882     ModuleID *pModuleId,
4883     mdToken *pToken)
4884 {
4885     CONTRACTL
4886     {
4887         // Yay!
4888         NOTHROW;
4889
4890         // Yay!
4891         GC_NOTRIGGER;
4892
4893         // Yay!
4894         MODE_ANY;
4895
4896         // Yay!
4897         EE_THREAD_NOT_REQUIRED;
4898
4899         // Yay!
4900         CANNOT_TAKE_LOCK;
4901
4902     }
4903     CONTRACTL_END;
4904
4905     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
4906         (LF_CORPROF, 
4907         LL_INFO1000, 
4908         "**PROF: GetFunctionInfo 0x%p.\n",
4909         functionId));
4910     
4911     if (functionId == NULL)
4912     {
4913         return E_INVALIDARG;
4914     }
4915
4916     MethodDesc *pMDesc = (MethodDesc *) functionId;
4917     if (!pMDesc->IsRestored())
4918     {
4919         return CORPROF_E_DATAINCOMPLETE;
4920     }
4921
4922     MethodTable *pMT = pMDesc->GetMethodTable();
4923     if (!pMT->IsRestored())
4924     {
4925         return CORPROF_E_DATAINCOMPLETE;
4926     }
4927
4928     ClassID classId = PROFILER_GLOBAL_CLASS;
4929
4930     if (pMT != NULL)
4931     {
4932         classId = NonGenericTypeHandleToClassID(TypeHandle(pMT));
4933     }
4934
4935     if (pClassId != NULL)
4936     {
4937         *pClassId = classId;
4938     }
4939
4940     if (pModuleId != NULL)
4941     {
4942         *pModuleId = (ModuleID) pMDesc->GetModule();
4943     }
4944
4945     if (pToken != NULL)
4946     {
4947         *pToken = pMDesc->GetMemberDef();
4948     }
4949
4950     return (S_OK);
4951 }
4952
4953 /*
4954  * GetILToNativeMapping returns a map from IL offsets to native
4955  * offsets for this code. An array of COR_DEBUG_IL_TO_NATIVE_MAP
4956  * structs will be returned, and some of the ilOffsets in this array
4957  * may be the values specified in CorDebugIlToNativeMappingTypes.
4958  */
4959 HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping(FunctionID functionId,
4960                                                     ULONG32 cMap,
4961                                                     ULONG32 * pcMap,    // [out]
4962                                                     COR_DEBUG_IL_TO_NATIVE_MAP map[]) // [out]
4963 {
4964     CONTRACTL
4965     {
4966         // MethodDesc::FindOrCreateTypicalSharedInstantiation throws
4967         THROWS;
4968
4969         // MethodDesc::FindOrCreateTypicalSharedInstantiation triggers, but shouldn't trigger when
4970         // called from here.  Since the profiler has a valid functionId, the methoddesc for
4971         // this code will already have been created.  We should be able to enforce this by
4972         // passing allowCreate=FALSE  to FindOrCreateTypicalSharedInstantiation.
4973         DISABLED(GC_NOTRIGGER);
4974     
4975         // Yay!
4976         MODE_ANY;
4977     
4978         // The call to g_pDebugInterface->GetILToNativeMapping() below may call
4979         // Debugger::AcquireDebuggerLock
4980         CAN_TAKE_LOCK;
4981
4982     }
4983     CONTRACTL_END;
4984
4985     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
4986         (LF_CORPROF, 
4987         LL_INFO1000, 
4988         "**PROF: GetILToNativeMapping 0x%p.\n",
4989         functionId));
4990
4991     return GetILToNativeMapping2(functionId, 0, cMap, pcMap, map);
4992 }
4993
4994 HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping2(FunctionID functionId,
4995                                                     ReJITID reJitId,
4996                                                     ULONG32 cMap,
4997                                                     ULONG32 * pcMap,    // [out]
4998                                                     COR_DEBUG_IL_TO_NATIVE_MAP map[]) // [out]
4999 {
5000     CONTRACTL
5001     {
5002         // MethodDesc::FindOrCreateTypicalSharedInstantiation throws
5003         THROWS;
5004
5005         // MethodDesc::FindOrCreateTypicalSharedInstantiation triggers, but shouldn't trigger when
5006         // called from here.  Since the profiler has a valid functionId, the methoddesc for
5007         // this code will already have been created.  We should be able to enforce this by
5008         // passing allowCreate=FALSE  to FindOrCreateTypicalSharedInstantiation.
5009         DISABLED(GC_NOTRIGGER);
5010
5011         // Yay!
5012         MODE_ANY;
5013     
5014         // The call to g_pDebugInterface->GetILToNativeMapping() below may call
5015         // Debugger::AcquireDebuggerLock
5016         CAN_TAKE_LOCK;
5017
5018     }
5019     CONTRACTL_END;
5020
5021     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5022         (LF_CORPROF, 
5023         LL_INFO1000, 
5024         "**PROF: GetILToNativeMapping2 0x%p 0x%p.\n",
5025         functionId, reJitId));
5026
5027     if (functionId == NULL)
5028     {
5029         return E_INVALIDARG;
5030     }
5031
5032     if ((cMap > 0) && 
5033         ((pcMap == NULL) || (map == NULL)))
5034     {
5035         return E_INVALIDARG;
5036     }
5037
5038     HRESULT hr = S_OK;
5039
5040     EX_TRY
5041     {
5042         // Cast to proper type
5043         MethodDesc * pMD = FunctionIdToMethodDesc(functionId);
5044
5045         if (pMD->HasClassOrMethodInstantiation() && pMD->IsTypicalMethodDefinition())
5046         {
5047             // In this case, we used to replace pMD with its canonical instantiation
5048             // (FindOrCreateTypicalSharedInstantiation).  However, a profiler should never be able
5049             // to get to this point anyway, since any MethodDesc a profiler gets from us
5050             // cannot be typical (i.e., cannot be a generic with types still left uninstantiated).
5051             // We assert here just in case a test proves me wrong, but generally we will
5052             // disallow this code path.
5053             _ASSERTE(!"Profiler passed a typical method desc (a generic with types still left uninstantiated) to GetILToNativeMapping2");
5054             hr = E_INVALIDARG;
5055         }
5056         else
5057         {
5058             PCODE pCodeStart = NULL;
5059             CodeVersionManager *pCodeVersionManager = pMD->GetCodeVersionManager();
5060             ILCodeVersion ilCodeVersion = NULL;
5061             {
5062                 CodeVersionManager::TableLockHolder lockHolder(pCodeVersionManager);
5063
5064                 pCodeVersionManager->GetILCodeVersion(pMD, reJitId);
5065         
5066                 NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMD);
5067                 for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++)
5068                 {
5069                     // Now that tiered compilation can create more than one jitted code version for the same rejit id
5070                     // we are arbitrarily choosing the first one to return.  To address a specific version of native code
5071                     // use GetILToNativeMapping3.
5072                     pCodeStart = iter->GetNativeCode();
5073                     break;
5074                 }
5075             }
5076
5077             hr = GetILToNativeMapping3(pCodeStart, cMap, pcMap, map);
5078         }
5079     }
5080     EX_CATCH_HRESULT(hr);
5081
5082     return hr;
5083 }
5084
5085
5086
5087 //*****************************************************************************
5088 // Given an ObjectID, go get the EE ClassID for it.
5089 //*****************************************************************************
5090 HRESULT ProfToEEInterfaceImpl::GetClassFromObject(ObjectID objectId,
5091                                                   ClassID * pClassId)
5092 {
5093     CONTRACTL
5094     {
5095         // Yay!
5096         NOTHROW;
5097
5098         // Yay!
5099         GC_NOTRIGGER;
5100
5101         // Yay!  Fail at runtime if in preemptive mode via AllowObjectInspection()
5102         MODE_ANY;
5103
5104         // Object::GetTypeHandle takes a lock
5105         CAN_TAKE_LOCK;
5106
5107     }
5108     CONTRACTL_END;
5109
5110     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5111         (LF_CORPROF, 
5112          LL_INFO1000, 
5113          "**PROF: GetClassFromObject 0x%p.\n",
5114          objectId));    
5115     
5116     if (objectId == NULL)
5117     {
5118         return E_INVALIDARG;
5119     }
5120     
5121     HRESULT hr = AllowObjectInspection();
5122     if (FAILED(hr))
5123     {
5124         return hr;
5125     }
5126
5127     // Cast the ObjectID as a Object
5128     Object *pObj = reinterpret_cast<Object *>(objectId);
5129
5130     // Set the out param and indicate success
5131     // Note that for generic code we always return uninstantiated ClassIDs and FunctionIDs
5132     if (pClassId)
5133     {
5134         *pClassId = SafeGetClassIDFromObject(pObj);
5135     }
5136
5137     return S_OK;
5138 }
5139
5140 //*****************************************************************************
5141 // Given a module and a token for a class, go get the EE data structure for it.
5142 //*****************************************************************************
5143 HRESULT ProfToEEInterfaceImpl::GetClassFromToken(ModuleID    moduleId,
5144     mdTypeDef   typeDef,
5145     ClassID     *pClassId)
5146 {
5147     CONTRACTL
5148     {
5149         // Yay!
5150         NOTHROW;
5151
5152         // ClassLoader::LoadTypeDefOrRefThrowing triggers
5153         GC_TRIGGERS;
5154
5155         // Yay!
5156         MODE_ANY;
5157
5158         // ClassLoader::LoadTypeDefOrRefThrowing takes a lock
5159         CAN_TAKE_LOCK;
5160
5161     }
5162     CONTRACTL_END;
5163
5164     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5165         kP2EEAllowableAfterAttach | kP2EETriggers,
5166         (LF_CORPROF, 
5167          LL_INFO1000, 
5168          "**PROF: GetClassFromToken 0x%p, 0x%08x.\n",
5169          moduleId, 
5170          typeDef));    
5171         
5172     if ((moduleId == NULL) || (typeDef == mdTypeDefNil) || (typeDef == NULL))
5173     {
5174         return E_INVALIDARG;
5175     }
5176     
5177     if (!g_profControlBlock.fBaseSystemClassesLoaded)
5178     {
5179         return CORPROF_E_RUNTIME_UNINITIALIZED;
5180     }
5181
5182     // Get the module
5183     Module *pModule = (Module *) moduleId;
5184
5185     // No module, or it's disassociated from metadata
5186     if ((pModule == NULL) || (pModule->IsBeingUnloaded()))
5187     {
5188         return CORPROF_E_DATAINCOMPLETE;
5189     }
5190
5191     // First, check the RID map. This is important since it
5192     // works during teardown (and the below doesn't)
5193     TypeHandle th;
5194     th = pModule->LookupTypeDef(typeDef);
5195     if (th.IsNull())
5196     {
5197         HRESULT hr = S_OK;
5198
5199         EX_TRY {
5200             th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, typeDef,
5201                                                       ClassLoader::ThrowIfNotFound,
5202                                                       ClassLoader::PermitUninstDefOrRef);
5203         }
5204         EX_CATCH_HRESULT(hr);
5205
5206         if (FAILED(hr))
5207         {
5208             return hr;
5209         }
5210     }
5211
5212     if (!th.GetMethodTable())
5213     {
5214         return CORPROF_E_DATAINCOMPLETE;
5215     }
5216
5217     //
5218     // Check if it is generic
5219     //
5220     ClassID classId = NonGenericTypeHandleToClassID(th);
5221
5222     if (classId == NULL)
5223     {
5224         return CORPROF_E_TYPE_IS_PARAMETERIZED;
5225     }
5226
5227     // Return value if necessary
5228     if (pClassId)
5229     {
5230         *pClassId = classId;
5231     }
5232
5233     return S_OK;
5234 }
5235
5236
5237 HRESULT ProfToEEInterfaceImpl::GetClassFromTokenAndTypeArgs(ModuleID moduleID,
5238                                                             mdTypeDef typeDef,
5239                                                             ULONG32 cTypeArgs,
5240                                                             ClassID typeArgs[],
5241                                                             ClassID* pClassID)
5242 {
5243     CONTRACTL
5244     {
5245         // Yay!
5246         NOTHROW;
5247
5248         // LoadGenericInstantiationThrowing may load
5249         GC_TRIGGERS;
5250
5251         // Yay!
5252         MODE_ANY;
5253
5254         // ClassLoader::LoadGenericInstantiationThrowing takes a lock
5255         CAN_TAKE_LOCK;
5256
5257     }
5258     CONTRACTL_END;
5259         
5260     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5261         kP2EEAllowableAfterAttach | kP2EETriggers,
5262         (LF_CORPROF, 
5263          LL_INFO1000, 
5264          "**PROF: GetClassFromTokenAndTypeArgs 0x%p, 0x%08x.\n",
5265          moduleID, 
5266          typeDef));    
5267     
5268     if (!g_profControlBlock.fBaseSystemClassesLoaded)
5269     {
5270         return CORPROF_E_RUNTIME_UNINITIALIZED;
5271     }
5272
5273     Module* pModule = reinterpret_cast< Module* >(moduleID);
5274
5275     if (pModule == NULL || pModule->IsBeingUnloaded())
5276     {
5277         return CORPROF_E_DATAINCOMPLETE;
5278     }
5279
5280     // This array needs to be accessible at least until the call to
5281     // ClassLoader::LoadGenericInstantiationThrowing
5282     TypeHandle* genericParameters = new (nothrow) TypeHandle[cTypeArgs];
5283     NewArrayHolder< TypeHandle > holder(genericParameters);
5284
5285     if (NULL == genericParameters)
5286     {
5287         return E_OUTOFMEMORY;
5288     }
5289
5290     for (ULONG32 i = 0; i < cTypeArgs; ++i)
5291     {
5292         genericParameters[i] = TypeHandle(reinterpret_cast< MethodTable* >(typeArgs[i]));
5293     }
5294
5295     //
5296     // nickbe 11/24/2003 10:12:56
5297     //
5298     // In RTM/Everett we decided to load the class if it hadn't been loaded yet
5299     // (see ProfToEEInterfaceImpl::GetClassFromToken). For compatibility we're
5300     // going to make the same decision here. It's potentially confusing to tell
5301     // someone a type doesn't exist at one point in time, but does exist later,
5302     // and there is no good way for us to determing that a class may eventually
5303     // be loaded without going ahead and loading it
5304     //
5305     TypeHandle th;
5306     HRESULT hr = S_OK;
5307
5308     EX_TRY
5309     {
5310         // Not sure if this is a valid override or not - making this a VIOLATION
5311         // until we're sure.
5312         CONTRACT_VIOLATION(LoadsTypeViolation);
5313     
5314         if (GetThreadNULLOk() == NULL)
5315         {
5316             // Type system will try to validate as part of its contract if the current 
5317             // AppDomain returned by GetAppDomain can load types in specified module's 
5318             // assembly.   On a non-EE thread it results in an AV in a check build 
5319             // since the type system tries to dereference NULL returned by GetAppDomain.  
5320             // More importantly, loading a type on a non-EE thread is not allowed.
5321             //
5322             // ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE() states that callers will not 
5323             // try to load a type, so that type system will not try to test type 
5324             // loadability in the current AppDomain.  However, 
5325             // ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE does not prevent callers from 
5326             // loading a type.   It is profiler's responsibility not to attempt to load
5327             // a type in unsupported ways (e.g. from a non-EE thread).  It doesn't 
5328             // impact retail builds, in which contracts are not available. 
5329             ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
5330
5331             // ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE also defines FAULT_FORBID, which 
5332             // causes Scanruntime to flag a fault violation in AssemblySpec::InitializeSpec,
5333             // which is defined as FAULTS.   It only happens in a type-loading path, which
5334             // is not supported on a non-EE thread.  Suppressing a contract violation in an
5335             // unsupported execution path is more preferable than causing AV when calling
5336             // GetClassFromTokenAndTypeArgs on a non-EE thread in a check build.  See Dev10 
5337             // 682526 for more details.
5338             FAULT_NOT_FATAL();
5339
5340             th = ClassLoader::LoadGenericInstantiationThrowing(pModule,
5341                                                                typeDef,
5342                                                                Instantiation(genericParameters, cTypeArgs),
5343                                                                ClassLoader::LoadTypes);
5344         }
5345         else
5346         {
5347             th = ClassLoader::LoadGenericInstantiationThrowing(pModule,
5348                                                                typeDef,
5349                                                                Instantiation(genericParameters, cTypeArgs),
5350                                                                ClassLoader::LoadTypes);
5351         }
5352     }
5353     EX_CATCH_HRESULT(hr);
5354
5355     if (FAILED(hr))
5356     {
5357         return hr;
5358     }
5359
5360     if (th.IsNull())
5361     {
5362         // Hmm, the type isn't loaded yet.
5363         return CORPROF_E_DATAINCOMPLETE;
5364     }
5365
5366     *pClassID = TypeHandleToClassID(th);
5367
5368     return S_OK;
5369 }
5370
5371 //*****************************************************************************
5372 // Given the token for a method, return the fucntion id.
5373 //*****************************************************************************
5374 HRESULT ProfToEEInterfaceImpl::GetFunctionFromToken(ModuleID moduleId,
5375     mdToken typeDef,
5376     FunctionID *pFunctionId)
5377 {
5378     CONTRACTL
5379     {
5380         // Yay!
5381         NOTHROW;
5382
5383         // Yay!
5384         GC_NOTRIGGER;
5385
5386         // Yay!
5387         MODE_ANY;
5388
5389         // Yay!
5390         EE_THREAD_NOT_REQUIRED;
5391
5392         // Yay!
5393         CANNOT_TAKE_LOCK;
5394
5395     }
5396     CONTRACTL_END;
5397
5398     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5399         (LF_CORPROF, 
5400          LL_INFO1000, 
5401          "**PROF: GetFunctionFromToken 0x%p, 0x%08x.\n",
5402          moduleId, 
5403          typeDef));    
5404         
5405     if ((moduleId == NULL) || (typeDef == mdTokenNil))
5406     {
5407         return E_INVALIDARG;
5408     }
5409     
5410     if (!g_profControlBlock.fBaseSystemClassesLoaded)
5411     {
5412         return CORPROF_E_RUNTIME_UNINITIALIZED;
5413     }
5414
5415     // Default HRESULT
5416     HRESULT hr = S_OK;
5417
5418     // Get the module
5419     Module *pModule = (Module *) moduleId;
5420
5421     // No module, or disassociated from metadata
5422     if (pModule == NULL || pModule->IsBeingUnloaded())
5423     {
5424         return CORPROF_E_DATAINCOMPLETE;
5425     }
5426
5427     // Default return value of NULL
5428     MethodDesc *pDesc = NULL;
5429
5430     // Different lookup depending on whether it's a Def or Ref
5431     if (TypeFromToken(typeDef) == mdtMethodDef)
5432     {
5433         pDesc = pModule->LookupMethodDef(typeDef);
5434     }
5435     else if (TypeFromToken(typeDef) == mdtMemberRef)
5436     {
5437         pDesc = pModule->LookupMemberRefAsMethod(typeDef);
5438     }
5439     else
5440     {
5441         return E_INVALIDARG;
5442     }
5443
5444     if (NULL == pDesc)
5445     {
5446         return E_INVALIDARG;
5447     }
5448
5449     //
5450     // Check that this is a non-generic method
5451     //
5452     if (pDesc->HasClassOrMethodInstantiation())
5453     {
5454         return CORPROF_E_FUNCTION_IS_PARAMETERIZED;
5455     }
5456
5457     if (pFunctionId && SUCCEEDED(hr))
5458     {
5459         *pFunctionId = MethodDescToFunctionID(pDesc);
5460     }
5461
5462     return (hr);
5463 }
5464
5465 HRESULT ProfToEEInterfaceImpl::GetFunctionFromTokenAndTypeArgs(ModuleID moduleID,
5466                                                                mdMethodDef funcDef,
5467                                                                ClassID classId,
5468                                                                ULONG32 cTypeArgs,
5469                                                                ClassID typeArgs[],
5470                                                                FunctionID* pFunctionID)
5471 {
5472     CONTRACTL
5473     {
5474         // Yay!
5475         NOTHROW;
5476
5477         // It can trigger type loads
5478         GC_TRIGGERS;
5479
5480         // Yay!
5481         MODE_ANY;
5482
5483         // MethodDesc::FindOrCreateAssociatedMethodDesc enters a Crst
5484         CAN_TAKE_LOCK;
5485
5486     }
5487     CONTRACTL_END;
5488
5489     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5490         kP2EEAllowableAfterAttach | kP2EETriggers,
5491         (LF_CORPROF, 
5492          LL_INFO1000, 
5493          "**PROF: GetFunctionFromTokenAndTypeArgs 0x%p, 0x%08x, 0x%p.\n",
5494          moduleID, 
5495          funcDef, 
5496          classId));        
5497     
5498     TypeHandle typeHandle = TypeHandle::FromPtr((void *)classId);
5499     Module* pModule = reinterpret_cast< Module* >(moduleID);
5500
5501     if ((pModule == NULL) || typeHandle.IsNull())
5502     {
5503         return E_INVALIDARG;
5504     }
5505          
5506     if (!g_profControlBlock.fBaseSystemClassesLoaded)
5507     {
5508         return CORPROF_E_RUNTIME_UNINITIALIZED;
5509     }
5510
5511     if (pModule->IsBeingUnloaded())
5512     {
5513         return CORPROF_E_DATAINCOMPLETE;
5514     }
5515
5516     MethodDesc* pMethodDesc = NULL;
5517
5518     if (mdtMethodDef == TypeFromToken(funcDef))
5519     {
5520         pMethodDesc = pModule->LookupMethodDef(funcDef);
5521     }
5522     else if (mdtMemberRef == TypeFromToken(funcDef))
5523     {
5524         pMethodDesc = pModule->LookupMemberRefAsMethod(funcDef);
5525     }
5526     else
5527     {
5528         return E_INVALIDARG;
5529     }
5530
5531     MethodTable* pMethodTable = typeHandle.GetMethodTable();
5532
5533     if (pMethodTable == NULL || !pMethodTable->IsRestored() || 
5534         pMethodDesc == NULL || !pMethodDesc->IsRestored())
5535     {
5536         return CORPROF_E_DATAINCOMPLETE;
5537     }
5538
5539     // This array needs to be accessible at least until the call to
5540     // MethodDesc::FindOrCreateAssociatedMethodDesc
5541     TypeHandle* genericParameters = new (nothrow) TypeHandle[cTypeArgs];
5542     NewArrayHolder< TypeHandle > holder(genericParameters);
5543
5544     if (NULL == genericParameters)
5545     {
5546         return E_OUTOFMEMORY;
5547     }
5548
5549     for (ULONG32 i = 0; i < cTypeArgs; ++i)
5550     {
5551         genericParameters[i] = TypeHandle(reinterpret_cast< MethodTable* >(typeArgs[i]));
5552     }
5553
5554     MethodDesc* result = NULL;
5555     HRESULT hr = S_OK;
5556
5557     EX_TRY
5558     {
5559         result = MethodDesc::FindOrCreateAssociatedMethodDesc(pMethodDesc,
5560                                                               pMethodTable,
5561                                                               FALSE,
5562                                                               Instantiation(genericParameters, cTypeArgs),
5563                                                               TRUE);
5564     }
5565     EX_CATCH_HRESULT(hr);
5566
5567     if (NULL != result)
5568     {
5569         *pFunctionID = MethodDescToFunctionID(result);
5570     }
5571
5572     return hr;
5573 }
5574
5575 //*****************************************************************************
5576 // Retrieve information about a given application domain, which is like a
5577 // sub-process.
5578 //*****************************************************************************
5579 HRESULT ProfToEEInterfaceImpl::GetAppDomainInfo(AppDomainID appDomainId,
5580     ULONG       cchName,
5581     ULONG       *pcchName,
5582     __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[],
5583     ProcessID   *pProcessId)
5584 {
5585     CONTRACTL
5586     {
5587         // Yay!
5588         NOTHROW;
5589
5590         // AppDomain::GetFriendlyNameForDebugger triggers
5591         GC_TRIGGERS;
5592
5593         // Yay!
5594         MODE_ANY;
5595
5596         // AppDomain::GetFriendlyNameForDebugger takes a lock
5597         CAN_TAKE_LOCK;
5598
5599     }
5600     CONTRACTL_END;
5601
5602     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
5603         kP2EEAllowableAfterAttach | kP2EETriggers,
5604         (LF_CORPROF, 
5605          LL_INFO1000, 
5606          "**PROF: GetAppDomainInfo 0x%p.\n",
5607          appDomainId));
5608     
5609     if (appDomainId == NULL)
5610     {
5611         return E_INVALIDARG;
5612     }
5613     
5614     BaseDomain   *pDomain;            // Internal data structure.
5615     HRESULT     hr = S_OK;
5616
5617     // <TODO>@todo:
5618     // Right now, this ID is not a true AppDomain, since we use the old
5619     // AppDomain/SystemDomain model in the profiling API.  This means that
5620     // the profiler exposes the SharedDomain and the SystemDomain to the
5621     // outside world. It's not clear whether this is actually the right thing
5622     // to do or not. - seantrow
5623     //
5624     // Postponed to V2.
5625     // </TODO>
5626
5627     pDomain = (BaseDomain *) appDomainId;
5628
5629     // Make sure they've passed in a valid appDomainId
5630     if (pDomain == NULL)
5631         return (E_INVALIDARG);
5632
5633     // Pick sensible defaults.
5634     if (pcchName)
5635         *pcchName = 0;
5636     if (szName)
5637         *szName = 0;
5638     if (pProcessId)
5639         *pProcessId = 0;
5640
5641     LPCWSTR szFriendlyName;
5642     if (pDomain == SystemDomain::System())
5643         szFriendlyName = g_pwBaseLibrary;
5644     else
5645         szFriendlyName = ((AppDomain*)pDomain)->GetFriendlyNameForDebugger();
5646
5647     if (szFriendlyName != NULL)
5648     {
5649         // Get the module file name
5650         ULONG trueLen = (ULONG)(wcslen(szFriendlyName) + 1);
5651
5652         // Return name of module as required.
5653         if (szName && cchName > 0)
5654         {
5655             ULONG copyLen = trueLen;
5656
5657             if (copyLen >= cchName)
5658             {
5659                 copyLen = cchName - 1;
5660             }
5661
5662             wcsncpy_s(szName, cchName, szFriendlyName, copyLen);
5663         }
5664
5665         // If they request the actual length of the name
5666         if (pcchName)
5667             *pcchName = trueLen;
5668     }
5669
5670     // If we don't have a friendly name but the call was requesting it, then return incomplete data HR
5671     else
5672     {
5673         if ((szName != NULL && cchName > 0) || pcchName)
5674             hr = CORPROF_E_DATAINCOMPLETE;
5675     }
5676
5677     if (pProcessId)
5678         *pProcessId = (ProcessID) GetCurrentProcessId();
5679
5680     return (hr);
5681 }
5682
5683
5684 //*****************************************************************************
5685 // Retrieve information about an assembly, which is a collection of dll's.
5686 //*****************************************************************************
5687 HRESULT ProfToEEInterfaceImpl::GetAssemblyInfo(AssemblyID    assemblyId,
5688     ULONG       cchName,
5689     ULONG       *pcchName,
5690     __out_ecount_part_opt(cchName, *pcchName) WCHAR szName[],
5691     AppDomainID *pAppDomainId,
5692     ModuleID    *pModuleId)
5693 {
5694     CONTRACTL
5695     {
5696         // SString::SString throws
5697         THROWS;
5698
5699         // Yay!
5700         GC_NOTRIGGER;
5701
5702         // Yay!
5703         MODE_ANY;
5704
5705         // Yay!
5706         EE_THREAD_NOT_REQUIRED;
5707
5708         // PEAssembly::GetSimpleName() enters a lock via use of the metadata interface
5709         CAN_TAKE_LOCK;
5710
5711     }
5712     CONTRACTL_END;
5713
5714     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
5715         (LF_CORPROF, 
5716          LL_INFO1000, 
5717          "**PROF: GetAssemblyInfo 0x%p.\n", 
5718          assemblyId));    
5719     
5720     if (assemblyId == NULL)
5721     {
5722         return E_INVALIDARG;
5723     }
5724     
5725     HRESULT hr = S_OK;
5726
5727     Assembly    *pAssembly;             // Internal data structure for assembly.
5728
5729     pAssembly = (Assembly *) assemblyId;
5730     _ASSERTE(pAssembly != NULL);
5731
5732     if (pcchName || szName)
5733     {
5734         // Get the friendly name of the assembly
5735         SString name(SString::Utf8, pAssembly->GetSimpleName());
5736
5737         const COUNT_T nameLength = name.GetCount() + 1;
5738
5739         if ((NULL != szName) && (cchName > 0))
5740         {
5741             wcsncpy_s(szName, cchName, name.GetUnicode(), min(nameLength, cchName - 1));
5742         }
5743
5744         if (NULL != pcchName)
5745         {
5746             *pcchName = nameLength;
5747         }
5748     }
5749
5750     // Get the parent application domain.
5751     if (pAppDomainId)
5752     {
5753         *pAppDomainId = (AppDomainID) pAssembly->GetDomain();
5754         _ASSERTE(*pAppDomainId != NULL);
5755     }
5756
5757     // Find the module the manifest lives in.
5758     if (pModuleId)
5759     {
5760         *pModuleId = (ModuleID) pAssembly->GetManifestModule();
5761
5762         // This is the case where the profiler has called GetAssemblyInfo
5763         // on an assembly that has been completely created yet.
5764         if (!*pModuleId)
5765             hr = CORPROF_E_DATAINCOMPLETE;
5766     }
5767
5768     return (hr);
5769 }
5770
5771 // Setting ELT hooks is only allowed from within Initialize().  However, test-only
5772 // profilers may need to set those hooks from an attaching profiling.  See
5773 // code:ProfControlBlock#TestOnlyELT
5774 #ifdef PROF_TEST_ONLY_FORCE_ELT
5775 #define PROFILER_TO_CLR_ENTRYPOINT_SET_ELT(logParams)                                   \
5776     do                                                                                  \
5777     {                                                                                   \
5778         if (g_profControlBlock.fTestOnlyForceEnterLeave)                                \
5779         {                                                                               \
5780             PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach, logParams);  \
5781         }                                                                               \
5782         else                                                                            \
5783         {                                                                               \
5784             PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY(logParams);                \
5785         }                                                                               \
5786     } while(0)
5787 #else //  PROF_TEST_ONLY_FORCE_ELT
5788 #define PROFILER_TO_CLR_ENTRYPOINT_SET_ELT                                              \
5789     PROFILER_TO_CLR_ENTRYPOINT_CALLABLE_ON_INIT_ONLY
5790 #endif //  PROF_TEST_ONLY_FORCE_ELT
5791
5792
5793 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks(FunctionEnter * pFuncEnter,
5794                                                           FunctionLeave * pFuncLeave,
5795                                                           FunctionTailcall * pFuncTailcall)
5796 {
5797     CONTRACTL
5798     {
5799         // Yay!
5800         NOTHROW;
5801
5802         // Yay!
5803         GC_NOTRIGGER;
5804
5805         // Yay!
5806         MODE_ANY;
5807
5808         // Yay!
5809         EE_THREAD_NOT_REQUIRED;
5810
5811         CANNOT_TAKE_LOCK;
5812
5813     }
5814     CONTRACTL_END;
5815
5816     // The profiler must call SetEnterLeaveFunctionHooks during initialization, since
5817     // the enter/leave events are immutable and must also be set during initialization.
5818     PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF, 
5819                                         LL_INFO10, 
5820                                         "**PROF: SetEnterLeaveFunctionHooks 0x%p, 0x%p, 0x%p.\n",
5821                                         pFuncEnter, 
5822                                         pFuncLeave, 
5823                                         pFuncTailcall));
5824
5825     return g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks(pFuncEnter, pFuncLeave, pFuncTailcall);
5826 }
5827
5828
5829 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks2(FunctionEnter2 * pFuncEnter,
5830                                                            FunctionLeave2 * pFuncLeave,
5831                                                            FunctionTailcall2 * pFuncTailcall)
5832 {
5833     CONTRACTL
5834     {
5835         // Yay!
5836         NOTHROW;
5837
5838         // Yay!
5839         GC_NOTRIGGER;
5840
5841         // Yay!
5842         MODE_ANY;
5843
5844         // Yay!
5845         EE_THREAD_NOT_REQUIRED;
5846
5847         CANNOT_TAKE_LOCK;
5848
5849     }
5850     CONTRACTL_END;
5851
5852     // The profiler must call SetEnterLeaveFunctionHooks2 during initialization, since
5853     // the enter/leave events are immutable and must also be set during initialization.
5854     PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF, 
5855                                         LL_INFO10, 
5856                                         "**PROF: SetEnterLeaveFunctionHooks2 0x%p, 0x%p, 0x%p.\n", 
5857                                         pFuncEnter, 
5858                                         pFuncLeave, 
5859                                         pFuncTailcall));    
5860
5861     return 
5862         g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks2(pFuncEnter, pFuncLeave, pFuncTailcall);
5863 }
5864
5865
5866 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks3(FunctionEnter3 * pFuncEnter3,
5867                                                            FunctionLeave3 * pFuncLeave3,
5868                                                            FunctionTailcall3 * pFuncTailcall3)
5869 {
5870     CONTRACTL
5871     {
5872         // Yay!
5873         NOTHROW;
5874
5875         // Yay!
5876         GC_NOTRIGGER;
5877
5878         // Yay!
5879         MODE_ANY;
5880
5881         // Yay!
5882         EE_THREAD_NOT_REQUIRED;
5883
5884         CANNOT_TAKE_LOCK;
5885
5886     }
5887     CONTRACTL_END;
5888
5889     // The profiler must call SetEnterLeaveFunctionHooks3 during initialization, since
5890     // the enter/leave events are immutable and must also be set during initialization.
5891     PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF, 
5892                                         LL_INFO10, 
5893                                         "**PROF: SetEnterLeaveFunctionHooks3 0x%p, 0x%p, 0x%p.\n", 
5894                                         pFuncEnter3, 
5895                                         pFuncLeave3, 
5896                                         pFuncTailcall3));    
5897
5898     return 
5899         g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks3(pFuncEnter3, 
5900                                                                        pFuncLeave3, 
5901                                                                        pFuncTailcall3);
5902 }
5903
5904
5905
5906 HRESULT ProfToEEInterfaceImpl::SetEnterLeaveFunctionHooks3WithInfo(FunctionEnter3WithInfo * pFuncEnter3WithInfo,
5907                                                                    FunctionLeave3WithInfo * pFuncLeave3WithInfo,
5908                                                                    FunctionTailcall3WithInfo * pFuncTailcall3WithInfo)
5909 {
5910     CONTRACTL
5911     {
5912         // Yay!
5913         NOTHROW;
5914
5915         // Yay!
5916         GC_NOTRIGGER;
5917
5918         // Yay!
5919         MODE_ANY;
5920
5921         // Yay!
5922         EE_THREAD_NOT_REQUIRED;
5923
5924         CANNOT_TAKE_LOCK;
5925
5926     }
5927     CONTRACTL_END;
5928
5929     // The profiler must call SetEnterLeaveFunctionHooks3WithInfo during initialization, since
5930     // the enter/leave events are immutable and must also be set during initialization.
5931     PROFILER_TO_CLR_ENTRYPOINT_SET_ELT((LF_CORPROF,
5932                                         LL_INFO10, 
5933                                         "**PROF: SetEnterLeaveFunctionHooks3WithInfo 0x%p, 0x%p, 0x%p.\n", 
5934                                         pFuncEnter3WithInfo, 
5935                                         pFuncLeave3WithInfo, 
5936                                         pFuncTailcall3WithInfo));    
5937
5938     return 
5939         g_profControlBlock.pProfInterface->SetEnterLeaveFunctionHooks3WithInfo(pFuncEnter3WithInfo, 
5940                                                                                pFuncLeave3WithInfo, 
5941                                                                                pFuncTailcall3WithInfo);
5942 }
5943
5944
5945 HRESULT ProfToEEInterfaceImpl::SetFunctionIDMapper(FunctionIDMapper *pFunc)
5946 {
5947     CONTRACTL
5948     {
5949         // Yay!
5950         NOTHROW;
5951
5952         // Yay!
5953         GC_NOTRIGGER;
5954
5955         // Yay!
5956         MODE_ANY;
5957
5958         // Yay!
5959         EE_THREAD_NOT_REQUIRED;
5960
5961         // Yay!
5962         CANNOT_TAKE_LOCK;
5963     
5964     }
5965     CONTRACTL_END;
5966     
5967     PROFILER_TO_CLR_ENTRYPOINT_ASYNC((LF_CORPROF, 
5968                                       LL_INFO10, 
5969                                       "**PROF: SetFunctionIDMapper 0x%p.\n",
5970                                       pFunc));
5971     
5972     g_profControlBlock.pProfInterface->SetFunctionIDMapper(pFunc);
5973
5974     return (S_OK);
5975 }
5976
5977 HRESULT ProfToEEInterfaceImpl::SetFunctionIDMapper2(FunctionIDMapper2 *pFunc, void * clientData)
5978 {
5979     CONTRACTL
5980     {
5981         // Yay!
5982         NOTHROW;
5983
5984         // Yay!
5985         GC_NOTRIGGER;
5986
5987         // Yay!
5988         MODE_ANY;
5989
5990         // Yay!
5991         EE_THREAD_NOT_REQUIRED;
5992
5993         // Yay!
5994         CANNOT_TAKE_LOCK;
5995     
5996     }
5997     CONTRACTL_END;
5998     
5999     PROFILER_TO_CLR_ENTRYPOINT_ASYNC((LF_CORPROF, 
6000                                       LL_INFO10, 
6001                                       "**PROF: SetFunctionIDMapper2. pFunc: 0x%p. clientData: 0x%p.\n",
6002                                       pFunc,
6003                                       clientData));
6004     
6005     g_profControlBlock.pProfInterface->SetFunctionIDMapper2(pFunc, clientData);
6006
6007     return (S_OK);
6008 }
6009
6010 /*
6011  * GetFunctionInfo2
6012  *
6013  * This function takes the frameInfo returned from a profiler callback and splays it
6014  * out into as much information as possible.
6015  *
6016  * Parameters:
6017  *   funcId - The function that is being requested.
6018  *   frameInfo - Frame specific information from a callback (for resolving generics).
6019  *   pClassId - An optional parameter for returning the class id of the function.
6020  *   pModuleId - An optional parameter for returning the module of the function.
6021  *   pToken - An optional parameter for returning the metadata token of the function.
6022  *   cTypeArgs - The count of the size of the array typeArgs
6023  *   pcTypeArgs - Returns the number of elements of typeArgs filled in, or if typeArgs is NULL
6024  *         the number that would be needed.
6025  *   typeArgs - An array to store generic type parameters for the function.
6026  *
6027  * Returns:
6028  *   S_OK if successful.
6029  */
6030 HRESULT ProfToEEInterfaceImpl::GetFunctionInfo2(FunctionID funcId,
6031                                              COR_PRF_FRAME_INFO frameInfo,
6032                                              ClassID *pClassId,
6033                                              ModuleID *pModuleId,
6034                                              mdToken *pToken,
6035                                              ULONG32 cTypeArgs,
6036                                              ULONG32 *pcTypeArgs,
6037                                              ClassID typeArgs[])
6038 {
6039     CONTRACTL
6040     {
6041         // Yay!
6042         NOTHROW;
6043
6044         // Yay!
6045         GC_NOTRIGGER;
6046
6047         // Yay!
6048         MODE_ANY;
6049
6050         // Yay!
6051         EE_THREAD_NOT_REQUIRED;
6052
6053         // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation eventually
6054         // reads metadata which causes us to take a reader lock.  However, see
6055         // code:#DisableLockOnAsyncCalls
6056         DISABLED(CAN_TAKE_LOCK);
6057
6058         // Asynchronous functions can be called at arbitrary times when runtime 
6059         // is holding locks that cannot be reentered without causing deadlock.
6060         // This contract detects any attempts to reenter locks held at the time 
6061         // this function was called.  
6062         CANNOT_RETAKE_LOCK;
6063
6064
6065         PRECONDITION(CheckPointer(pClassId, NULL_OK));
6066         PRECONDITION(CheckPointer(pModuleId, NULL_OK));
6067         PRECONDITION(CheckPointer(pToken,  NULL_OK));
6068         PRECONDITION(CheckPointer(pcTypeArgs, NULL_OK));
6069         PRECONDITION(CheckPointer(typeArgs, NULL_OK));
6070     }
6071     CONTRACTL_END;
6072
6073     // See code:#DisableLockOnAsyncCalls
6074     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6075
6076     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6077         (LF_CORPROF, 
6078         LL_INFO1000, 
6079         "**PROF: GetFunctionInfo2 0x%p.\n",
6080         funcId));
6081
6082     //
6083     // Verify parameters.
6084     //
6085     COR_PRF_FRAME_INFO_INTERNAL *pFrameInfo = (COR_PRF_FRAME_INFO_INTERNAL *)frameInfo;
6086
6087     if ((funcId == NULL) ||
6088         ((pFrameInfo != NULL) && (pFrameInfo->funcID != funcId)))
6089     {
6090         return E_INVALIDARG;
6091     }
6092
6093     MethodDesc *pMethDesc = FunctionIdToMethodDesc(funcId);
6094
6095     if (pMethDesc == NULL)
6096     {
6097         return E_INVALIDARG;
6098     }
6099
6100     if ((cTypeArgs != 0) && (typeArgs == NULL))
6101     {
6102         return E_INVALIDARG;
6103     }
6104
6105     // it's not safe to examine a methoddesc that has not been restored so do not do so
6106     if (!pMethDesc ->IsRestored())
6107         return CORPROF_E_DATAINCOMPLETE;      
6108
6109     //
6110     // Find the exact instantiation of this function.
6111     //
6112     TypeHandle specificClass;
6113     MethodDesc* pActualMethod;
6114
6115     ClassID classId = NULL;
6116
6117     if (pMethDesc->IsSharedByGenericInstantiations())
6118     {
6119         BOOL exactMatch;
6120         OBJECTREF pThis = NULL;
6121
6122         if (pFrameInfo != NULL)
6123         {
6124             // If FunctionID represents a generic methoddesc on a struct, then pFrameInfo->thisArg
6125             // isn't an Object*.  It's a pointer directly into the struct's members (i.e., it's not pointing at the
6126             // method table).  That means pFrameInfo->thisArg cannot be casted to an OBJECTREF for
6127             // use by Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation.  However,
6128             // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation won't even need a this pointer
6129             // for the methoddesc it's processing if the methoddesc is on a value type.  So we
6130             // can safely pass NULL for the methoddesc's this in such a case.
6131             if (pMethDesc->GetMethodTable()->IsValueType())
6132             {
6133                 _ASSERTE(!pMethDesc->AcquiresInstMethodTableFromThis());
6134                 _ASSERTE(pThis == NULL);
6135             }
6136             else
6137             {
6138                 pThis = ObjectToOBJECTREF((PTR_Object)(pFrameInfo->thisArg));
6139             }
6140         }
6141
6142         exactMatch = Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation(
6143             pMethDesc,
6144             pThis,
6145             PTR_VOID((pFrameInfo != NULL) ? pFrameInfo->extraArg : NULL),
6146             &specificClass,
6147             &pActualMethod);
6148
6149         if (exactMatch)
6150         {
6151             classId = TypeHandleToClassID(specificClass);
6152         }
6153         else if (!specificClass.HasInstantiation() || !specificClass.IsSharedByGenericInstantiations())
6154         {
6155             //
6156             // In this case we could not get the type args for the method, but if the class 
6157             // is not a generic class or is instantiated with value types, this value is correct.
6158             //
6159             classId = TypeHandleToClassID(specificClass);
6160         }
6161         else
6162         {
6163             //
6164             // We could not get any class information.
6165             //
6166             classId = NULL;
6167         }
6168     }
6169     else
6170     {
6171         TypeHandle typeHandle(pMethDesc->GetMethodTable());
6172         classId = TypeHandleToClassID(typeHandle);
6173         pActualMethod = pMethDesc;
6174     }
6175
6176
6177     //
6178     // Fill in the ClassId, if desired
6179     //
6180     if (pClassId != NULL)
6181     {
6182         *pClassId = classId;
6183     }
6184
6185     //
6186     // Fill in the ModuleId, if desired.
6187     //
6188     if (pModuleId != NULL)
6189     {
6190         *pModuleId = (ModuleID)pMethDesc->GetModule();
6191     }
6192
6193     //
6194     // Fill in the token, if desired.
6195     //
6196     if (pToken != NULL)
6197     {
6198         *pToken = (mdToken)pMethDesc->GetMemberDef();
6199     }
6200
6201     if ((cTypeArgs == 0) && (pcTypeArgs != NULL))
6202     {
6203         //
6204         // They are searching for the size of the array needed, we can return that now and
6205         // short-circuit all the work below.
6206         //
6207         if (pcTypeArgs != NULL)
6208         {
6209             *pcTypeArgs = pActualMethod->GetNumGenericMethodArgs();
6210         }
6211         return S_OK;
6212     }
6213
6214     //
6215     // If no place to store resulting count, quit now.
6216     //
6217     if (pcTypeArgs == NULL)
6218     {
6219         return S_OK;
6220     }
6221
6222     //
6223     // Fill in the type args
6224     //
6225     DWORD cArgsToFill = pActualMethod->GetNumGenericMethodArgs();
6226
6227     if (cArgsToFill > cTypeArgs)
6228     {
6229         cArgsToFill = cTypeArgs;
6230     }
6231
6232     *pcTypeArgs = cArgsToFill;
6233
6234     if (cArgsToFill == 0)
6235     {
6236         return S_OK;
6237     }
6238
6239     Instantiation inst = pActualMethod->GetMethodInstantiation();
6240
6241     for (DWORD i = 0; i < cArgsToFill; i++)
6242     {
6243         typeArgs[i] = TypeHandleToClassID(inst[i]);
6244     }
6245
6246     return S_OK;
6247 }
6248
6249 /*
6250 * IsFunctionDynamic
6251 *
6252 * This function takes a functionId that maybe of a metadata-less method like an IL Stub
6253 * or LCG method and returns true in the pHasNoMetadata if it is indeed a metadata-less
6254 * method.
6255 *
6256 * Parameters:
6257 *   functionId - The function that is being requested.
6258 *   isDynamic - An optional parameter for returning if the function has metadata or not.
6259 *
6260 * Returns:
6261 *   S_OK if successful.
6262 */
6263 HRESULT ProfToEEInterfaceImpl::IsFunctionDynamic(FunctionID functionId, BOOL *isDynamic)
6264 {
6265     CONTRACTL
6266     {
6267         NOTHROW;
6268         GC_NOTRIGGER;
6269         MODE_ANY;
6270         EE_THREAD_NOT_REQUIRED;
6271
6272         // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation eventually
6273         // reads metadata which causes us to take a reader lock.  However, see
6274         // code:#DisableLockOnAsyncCalls
6275         DISABLED(CAN_TAKE_LOCK);
6276
6277         // Asynchronous functions can be called at arbitrary times when runtime 
6278         // is holding locks that cannot be reentered without causing deadlock.
6279         // This contract detects any attempts to reenter locks held at the time 
6280         // this function was called.  
6281         CANNOT_RETAKE_LOCK;
6282
6283
6284         PRECONDITION(CheckPointer(isDynamic, NULL_OK));
6285     }
6286     CONTRACTL_END;
6287
6288     // See code:#DisableLockOnAsyncCalls
6289     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6290
6291     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6292         (LF_CORPROF,
6293             LL_INFO1000,
6294             "**PROF: IsFunctionDynamic 0x%p.\n",
6295             functionId));
6296
6297     //
6298     // Verify parameters.
6299     //
6300
6301     if (functionId == NULL)
6302     {
6303         return E_INVALIDARG;
6304     }
6305
6306     MethodDesc *pMethDesc = FunctionIdToMethodDesc(functionId);
6307
6308     if (pMethDesc == NULL)
6309     {
6310         return E_INVALIDARG;
6311     }
6312
6313     // it's not safe to examine a methoddesc that has not been restored so do not do so
6314     if (!pMethDesc->IsRestored())
6315         return CORPROF_E_DATAINCOMPLETE;
6316
6317     //
6318     // Fill in the pHasNoMetadata, if desired.
6319     //
6320     if (isDynamic != NULL)
6321     {
6322         *isDynamic = pMethDesc->IsNoMetadata();
6323     }
6324
6325     return S_OK;
6326 }
6327
6328 /*
6329 * GetFunctionFromIP3
6330 *
6331 * This function takes an IP and determines if it is a managed function returning its
6332 * FunctionID. This method is different from GetFunctionFromIP in that will return
6333 * FunctionIDs even if they have no associated metadata.
6334 *
6335 * Parameters:
6336 *   ip - The instruction pointer.
6337 *   pFunctionId - An optional parameter for returning the FunctionID.
6338 *   pReJitId - The ReJIT id.
6339 *
6340 * Returns:
6341 *   S_OK if successful.
6342 */
6343 HRESULT ProfToEEInterfaceImpl::GetFunctionFromIP3(LPCBYTE ip, FunctionID * pFunctionId, ReJITID * pReJitId)
6344 {
6345     CONTRACTL
6346     {
6347         NOTHROW;
6348
6349         // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
6350         // which can switch us to preemptive mode and trigger GCs
6351         GC_TRIGGERS;
6352         MODE_ANY;
6353         EE_THREAD_NOT_REQUIRED;
6354
6355         // Grabbing the rejitid requires entering the rejit manager's hash table & lock,
6356         CAN_TAKE_LOCK;
6357
6358     }
6359     CONTRACTL_END;
6360
6361     // See code:#DisableLockOnAsyncCalls
6362     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6363
6364     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6365         kP2EEAllowableAfterAttach | kP2EETriggers,
6366         (LF_CORPROF,
6367             LL_INFO1000,
6368             "**PROF: GetFunctionFromIP3 0x%p.\n",
6369             ip));
6370
6371     HRESULT hr = S_OK;
6372
6373     EECodeInfo codeInfo;
6374
6375     hr = GetFunctionFromIPInternal(ip, &codeInfo, /* failOnNoMetadata */ FALSE);
6376     if (FAILED(hr))
6377     {
6378         return hr;
6379     }
6380
6381     if (pFunctionId)
6382     {
6383         *pFunctionId = MethodDescToFunctionID(codeInfo.GetMethodDesc());
6384     }
6385
6386     if (pReJitId != NULL)
6387     {
6388         MethodDesc * pMD = codeInfo.GetMethodDesc();
6389         *pReJitId = ReJitManager::GetReJitId(pMD, codeInfo.GetStartAddress());
6390     }
6391
6392     return S_OK;
6393 }
6394
6395 /*
6396 * GetDynamicFunctionInfo
6397 *
6398 * This function takes a functionId that maybe of a metadata-less method like an IL Stub
6399 * or LCG method and gives information about it without failing like GetFunctionInfo.
6400 *
6401 * Parameters:
6402 *   functionId - The function that is being requested.
6403 *   pModuleId - An optional parameter for returning the module of the function.
6404 *   ppvSig -  An optional parameter for returning the signature of the function.
6405 *   pbSig - An optional parameter for returning the size of the signature of the function.
6406 *   cchName - A parameter for indicating the size of buffer for the wszName parameter.
6407 *   pcchName - An optional parameter for returning the true size of the wszName parameter.
6408 *   wszName - A parameter to the caller allocated buffer of size cchName
6409 *
6410 * Returns:
6411 *   S_OK if successful.
6412 */
6413 HRESULT ProfToEEInterfaceImpl::GetDynamicFunctionInfo(FunctionID functionId,
6414                                                       ModuleID *pModuleId,
6415                                                       PCCOR_SIGNATURE* ppvSig,
6416                                                       ULONG* pbSig,
6417                                                       ULONG cchName,
6418                                                       ULONG *pcchName,
6419             __out_ecount_part_opt(cchName, *pcchName) WCHAR wszName[])
6420 {
6421     CONTRACTL
6422     {
6423         NOTHROW;
6424         GC_NOTRIGGER;
6425         MODE_ANY;
6426         EE_THREAD_NOT_REQUIRED;
6427
6428         // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation eventually
6429         // reads metadata which causes us to take a reader lock.  However, see
6430         // code:#DisableLockOnAsyncCalls
6431         DISABLED(CAN_TAKE_LOCK);
6432
6433         // Asynchronous functions can be called at arbitrary times when runtime 
6434         // is holding locks that cannot be reentered without causing deadlock.
6435         // This contract detects any attempts to reenter locks held at the time 
6436         // this function was called.  
6437         CANNOT_RETAKE_LOCK;
6438
6439
6440         PRECONDITION(CheckPointer(pModuleId, NULL_OK));
6441         PRECONDITION(CheckPointer(ppvSig, NULL_OK));
6442         PRECONDITION(CheckPointer(pbSig,  NULL_OK));
6443         PRECONDITION(CheckPointer(pcchName, NULL_OK));
6444     }
6445     CONTRACTL_END;
6446
6447     // See code:#DisableLockOnAsyncCalls
6448     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
6449
6450     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6451         (LF_CORPROF,
6452             LL_INFO1000,
6453             "**PROF: GetDynamicFunctionInfo 0x%p.\n",
6454             functionId));
6455
6456     //
6457     // Verify parameters.
6458     //
6459
6460     if (functionId == NULL)
6461     {
6462         return E_INVALIDARG;
6463     }
6464
6465     MethodDesc *pMethDesc = FunctionIdToMethodDesc(functionId);
6466
6467     if (pMethDesc == NULL)
6468     {
6469         return E_INVALIDARG;
6470     }
6471
6472     // it's not safe to examine a methoddesc that has not been restored so do not do so
6473     if (!pMethDesc->IsRestored())
6474         return CORPROF_E_DATAINCOMPLETE;
6475
6476
6477     if (!pMethDesc->IsNoMetadata())
6478         return E_INVALIDARG;
6479
6480     //
6481     // Fill in the ModuleId, if desired.
6482     //
6483     if (pModuleId != NULL)
6484     {
6485         *pModuleId = (ModuleID)pMethDesc->GetModule();
6486     }
6487
6488     //
6489     // Fill in the ppvSig and pbSig, if desired
6490     //
6491     if (ppvSig != NULL && pbSig != NULL)
6492     {
6493         pMethDesc->GetSig(ppvSig, pbSig);
6494     }
6495
6496     HRESULT hr = S_OK;
6497
6498     EX_TRY
6499     {
6500         if (wszName != NULL)
6501             *wszName = 0;
6502         if (pcchName != NULL)
6503             *pcchName = 0;
6504
6505         StackSString ss;
6506         ss.SetUTF8(pMethDesc->GetName());
6507         ss.Normalize();
6508         LPCWSTR methodName = ss.GetUnicode();
6509
6510         ULONG trueLen = (ULONG)(wcslen(methodName) + 1);
6511
6512         // Return name of method as required.
6513         if (wszName && cchName > 0)
6514         {
6515             if (cchName < trueLen)
6516             {
6517                 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6518             }
6519             else
6520             {
6521                 wcsncpy_s(wszName, cchName, methodName, trueLen);
6522             }
6523         }
6524
6525         // If they request the actual length of the name
6526         if (pcchName)
6527             *pcchName = trueLen;
6528     }
6529     EX_CATCH_HRESULT(hr);
6530
6531     return (hr);
6532 }
6533
6534 /*
6535  * GetNativeCodeStartAddresses
6536  * 
6537  * Gets all of the native code addresses associated with a particular function. iered compilation 
6538  * potentially creates different native code versions for a method, and this function allows profilers
6539  * to view all native versions of a method.
6540  * 
6541  * Parameters:
6542  *      functionID           - The function that is being requested.
6543  *      reJitId              - The ReJIT id.
6544  *      cCodeStartAddresses  - A parameter for indicating the size of buffer for the codeStartAddresses parameter.
6545  *      pcCodeStartAddresses - An optional parameter for returning the true size of the codeStartAddresses parameter.
6546  *      codeStartAddresses   - The array to be filled up with native code addresses.
6547  * 
6548  * Returns:
6549  *   S_OK if successful
6550  *
6551  */
6552 HRESULT ProfToEEInterfaceImpl::GetNativeCodeStartAddresses(FunctionID functionID, 
6553                                                            ReJITID reJitId, 
6554                                                            ULONG32 cCodeStartAddresses, 
6555                                                            ULONG32 *pcCodeStartAddresses, 
6556                                                            UINT_PTR codeStartAddresses[])
6557 {
6558     CONTRACTL
6559     {
6560         NOTHROW;
6561         GC_NOTRIGGER;
6562         MODE_ANY;
6563         EE_THREAD_NOT_REQUIRED;
6564         CAN_TAKE_LOCK;
6565
6566
6567         PRECONDITION(CheckPointer(pcCodeStartAddresses, NULL_OK));
6568         PRECONDITION(CheckPointer(codeStartAddresses, NULL_OK));
6569     }
6570     CONTRACTL_END;
6571
6572     if (functionID == NULL)
6573     {
6574         return E_INVALIDARG;
6575     }
6576
6577     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
6578     (LF_CORPROF,
6579         LL_INFO1000,
6580         "**PROF: GetNativeCodeStartAddresses 0x%p 0x%p.\n",
6581         functionID, reJitId));
6582     
6583     HRESULT hr = S_OK;
6584    
6585     EX_TRY
6586     {
6587         if (pcCodeStartAddresses != NULL)
6588         {
6589             *pcCodeStartAddresses = 0;
6590         }
6591
6592         MethodDesc * methodDesc = FunctionIdToMethodDesc(functionID);
6593         PTR_MethodDesc pMD = PTR_MethodDesc(methodDesc);
6594         ULONG32 trueLen = 0;
6595         StackSArray<UINT_PTR> addresses;
6596
6597         CodeVersionManager *pCodeVersionManager = pMD->GetCodeVersionManager();
6598
6599         ILCodeVersion ilCodeVersion = NULL;
6600         {
6601             CodeVersionManager::TableLockHolder lockHolder(pCodeVersionManager);
6602
6603             ilCodeVersion = pCodeVersionManager->GetILCodeVersion(pMD, reJitId);
6604             
6605             NativeCodeVersionCollection nativeCodeVersions = ilCodeVersion.GetNativeCodeVersions(pMD);
6606             for (NativeCodeVersionIterator iter = nativeCodeVersions.Begin(); iter != nativeCodeVersions.End(); iter++)
6607             {
6608                 addresses.Append((*iter).GetNativeCode());
6609
6610                 ++trueLen;
6611             }
6612         }
6613
6614         if (pcCodeStartAddresses != NULL)
6615         {
6616             *pcCodeStartAddresses = trueLen;
6617         }
6618
6619         if (codeStartAddresses != NULL)
6620         {
6621             if (cCodeStartAddresses < trueLen)
6622             {
6623                 hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
6624             }
6625             else
6626             {
6627                 for(ULONG32 i = 0; i < trueLen; ++i)
6628                 {
6629                     codeStartAddresses[i] = addresses[i];
6630                 }
6631             }
6632         }
6633     }
6634     EX_CATCH_HRESULT(hr);
6635     
6636     return hr;
6637 }
6638
6639 /*
6640  * GetILToNativeMapping3
6641  * 
6642  * This overload behaves the same as GetILToNativeMapping2, except it allows the profiler
6643  * to address specific native code versions instead of defaulting to the first one.
6644  * 
6645  * Parameters:
6646  *      pNativeCodeStartAddress - start address of the native code version, returned by GetNativeCodeStartAddresses
6647  *      cMap                    - size of the map array
6648  *      pcMap                   - how many items are returned in the map array
6649  *      map                     - an array to store the il to native mappings in
6650  *
6651  * Returns:
6652  *   S_OK if successful
6653  *
6654  */
6655 HRESULT ProfToEEInterfaceImpl::GetILToNativeMapping3(UINT_PTR pNativeCodeStartAddress, 
6656                                                      ULONG32 cMap, 
6657                                                      ULONG32 *pcMap, 
6658                                                      COR_DEBUG_IL_TO_NATIVE_MAP map[])
6659 {
6660     CONTRACTL
6661     {
6662         THROWS;
6663         DISABLED(GC_NOTRIGGER);
6664         MODE_ANY;
6665         CAN_TAKE_LOCK;
6666
6667
6668         PRECONDITION(CheckPointer(pcMap, NULL_OK));
6669         PRECONDITION(CheckPointer(map, NULL_OK));
6670     }
6671     CONTRACTL_END;
6672
6673     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
6674         (LF_CORPROF, 
6675         LL_INFO1000, 
6676         "**PROF: GetILToNativeMapping3 0x%p.\n",
6677         pNativeCodeStartAddress));
6678
6679     if (pNativeCodeStartAddress == NULL)
6680     {
6681         return E_INVALIDARG;
6682     }
6683
6684     if ((cMap > 0) && 
6685         ((pcMap == NULL) || (map == NULL)))
6686     {
6687         return E_INVALIDARG;
6688     }
6689
6690 #ifdef DEBUGGING_SUPPORTED
6691     if (g_pDebugInterface == NULL)
6692     {
6693         return CORPROF_E_DEBUGGING_DISABLED;
6694     }
6695
6696     return (g_pDebugInterface->GetILToNativeMapping(pNativeCodeStartAddress, cMap, pcMap, map));
6697 #else
6698     return E_NOTIMPL;
6699 #endif
6700 }
6701
6702 /*
6703  * GetCodeInfo4
6704  * 
6705  * Gets the location and size of a jitted function. Tiered compilation potentially creates different native code 
6706  * versions for a method, and this overload allows profilers to specify which native version it would like the 
6707  * code info for.
6708  * 
6709  * Parameters:
6710  *      pNativeCodeStartAddress - start address of the native code version, returned by GetNativeCodeStartAddresses
6711  *      cCodeInfos              - size of the codeInfos array
6712  *      pcCodeInfos             - how many items are returned in the codeInfos array
6713  *      codeInfos               - an array to store the code infos in
6714  *
6715  * Returns:
6716  *   S_OK if successful
6717  *
6718  */
6719 HRESULT ProfToEEInterfaceImpl::GetCodeInfo4(UINT_PTR pNativeCodeStartAddress, 
6720                                             ULONG32 cCodeInfos, 
6721                                             ULONG32* pcCodeInfos, 
6722                                             COR_PRF_CODE_INFO codeInfos[])
6723 {
6724     CONTRACTL
6725     {
6726         NOTHROW;
6727         GC_TRIGGERS;
6728         MODE_ANY;
6729         EE_THREAD_NOT_REQUIRED;
6730         CAN_TAKE_LOCK;
6731         
6732
6733         PRECONDITION(CheckPointer(pcCodeInfos, NULL_OK));
6734         PRECONDITION(CheckPointer(codeInfos, NULL_OK));
6735     }
6736     CONTRACTL_END;
6737
6738     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6739         kP2EEAllowableAfterAttach | kP2EETriggers,
6740         (LF_CORPROF, 
6741         LL_INFO1000, 
6742         "**PROF: GetCodeInfo4 0x%p.\n", 
6743         pNativeCodeStartAddress));  
6744
6745     if ((cCodeInfos != 0) && (codeInfos == NULL))
6746     {
6747         return E_INVALIDARG;
6748     }
6749
6750     return GetCodeInfoFromCodeStart(pNativeCodeStartAddress,
6751                                     cCodeInfos,
6752                                     pcCodeInfos,
6753                                     codeInfos);
6754 }
6755
6756 HRESULT ProfToEEInterfaceImpl::RequestReJITWithInliners(
6757             DWORD       dwRejitFlags,
6758             ULONG       cFunctions,
6759             ModuleID    moduleIds[],
6760             mdMethodDef methodIds[])
6761 {
6762     CONTRACTL
6763     {
6764         NOTHROW;
6765         GC_TRIGGERS;
6766         MODE_ANY;
6767         CAN_TAKE_LOCK;
6768         PRECONDITION(CheckPointer(moduleIds, NULL_OK));
6769         PRECONDITION(CheckPointer(methodIds, NULL_OK));
6770     }
6771     CONTRACTL_END;
6772
6773     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6774         kP2EETriggers | kP2EEAllowableAfterAttach,
6775         (LF_CORPROF, 
6776          LL_INFO1000, 
6777          "**PROF: RequestReJITWithInliners.\n"));
6778
6779     if (!g_profControlBlock.pProfInterface->IsCallback4Supported())
6780     {
6781         return CORPROF_E_CALLBACK4_REQUIRED;
6782     }
6783
6784     if (!CORProfilerEnableRejit())
6785     {
6786         return CORPROF_E_REJIT_NOT_ENABLED;
6787     }
6788
6789     if (!ReJitManager::IsReJITInlineTrackingEnabled())
6790     {
6791         return CORPROF_E_REJIT_INLINING_DISABLED;
6792     }
6793
6794     // Request at least 1 method to reJIT!
6795     if ((cFunctions == 0) || (moduleIds == NULL) || (methodIds == NULL))
6796     {
6797         return E_INVALIDARG;
6798     }
6799
6800     // We only support disabling inlining currently
6801     if ((dwRejitFlags & COR_PRF_REJIT_BLOCK_INLINING) != COR_PRF_REJIT_BLOCK_INLINING)
6802     {
6803         return E_INVALIDARG;
6804     }
6805
6806     // Remember the profiler is doing this, as that means we must never detach it!
6807     g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
6808
6809     HRESULT hr = SetupThreadForReJIT();
6810     if (FAILED(hr))
6811     {
6812         return hr;
6813     }
6814     
6815     GCX_PREEMP();
6816     return ReJitManager::RequestReJIT(cFunctions, moduleIds, methodIds, static_cast<COR_PRF_REJIT_FLAGS>(dwRejitFlags));
6817 }
6818
6819 /*
6820  * EnumerateObjectReferences
6821  * 
6822  * Enumerates the object references (if any) from the ObjectID.
6823  * 
6824  * Parameters:
6825  *      objectId        - object id of interest
6826  *      callback        - callback to call for each object reference
6827  *      clientData      - client data for the profiler to pass and receive for each reference
6828  *
6829  * Returns:
6830  *   S_OK if successful, S_FALSE if no references
6831  *
6832  */
6833 HRESULT ProfToEEInterfaceImpl::EnumerateObjectReferences(ObjectID objectId, ObjectReferenceCallback callback, void* clientData)
6834 {
6835     CONTRACTL
6836     {
6837         NOTHROW;
6838         GC_NOTRIGGER;
6839         MODE_ANY;
6840         EE_THREAD_NOT_REQUIRED;
6841         CANNOT_TAKE_LOCK;
6842     }
6843     CONTRACTL_END;
6844
6845     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6846         kP2EEAllowableAfterAttach,
6847         (LF_CORPROF,
6848         LL_INFO1000,
6849         "**PROF: EnumerateObjectReferences 0x%p.\n",
6850         objectId));
6851
6852     if (callback == nullptr)
6853     {
6854         return E_INVALIDARG;
6855     }
6856
6857     Object* pBO = (Object*)objectId;
6858     MethodTable *pMT = pBO->GetMethodTable();
6859
6860     if (pMT->ContainsPointersOrCollectible())
6861     {
6862         GCHeapUtilities::GetGCHeap()->DiagWalkObject2(pBO, (walk_fn2)callback, clientData);
6863         return S_OK;
6864     }
6865     else
6866     {
6867         return S_FALSE;
6868     }
6869 }
6870
6871 /*
6872  * IsFrozenObject
6873  * 
6874  * Determines whether the object is in a read-only segment
6875  * 
6876  * Parameters:
6877  *      objectId        - object id of interest
6878  *
6879  * Returns:
6880  *   S_OK if successful
6881  *
6882  */
6883 HRESULT ProfToEEInterfaceImpl::IsFrozenObject(ObjectID objectId, BOOL *pbFrozen)
6884 {
6885     CONTRACTL
6886     {
6887         NOTHROW;
6888         GC_NOTRIGGER;
6889         MODE_ANY;
6890         EE_THREAD_NOT_REQUIRED;
6891         CANNOT_TAKE_LOCK;
6892     }
6893     CONTRACTL_END;
6894
6895     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6896         kP2EEAllowableAfterAttach,
6897         (LF_CORPROF,
6898         LL_INFO1000,
6899         "**PROF: IsFrozenObject 0x%p.\n",
6900         objectId));
6901
6902     *pbFrozen = GCHeapUtilities::GetGCHeap()->IsInFrozenSegment((Object*)objectId) ? TRUE : FALSE;
6903
6904     return S_OK;
6905 }
6906
6907 /*
6908  * GetLOHObjectSizeThreshold
6909  * 
6910  * Gets the value of the configured LOH Threshold.
6911  * 
6912  * Parameters:
6913  *      pThreshold        - value of the threshold in bytes
6914  *
6915  * Returns:
6916  *   S_OK if successful
6917  *
6918  */
6919 HRESULT ProfToEEInterfaceImpl::GetLOHObjectSizeThreshold(DWORD *pThreshold)
6920 {
6921     CONTRACTL
6922     {
6923         NOTHROW;
6924         GC_NOTRIGGER;
6925         MODE_ANY;
6926         EE_THREAD_NOT_REQUIRED;
6927         CANNOT_TAKE_LOCK;
6928     }
6929     CONTRACTL_END;
6930
6931     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6932         kP2EEAllowableAfterAttach,
6933         (LF_CORPROF,
6934         LL_INFO1000,
6935         "**PROF: GetLOHObjectSizeThreshold\n"));
6936
6937     if (pThreshold == nullptr)
6938     {
6939         return E_INVALIDARG;
6940     }
6941
6942     *pThreshold = g_pConfig->GetGCLOHThreshold();
6943
6944     return S_OK;
6945 }
6946
6947 HRESULT ProfToEEInterfaceImpl::SuspendRuntime()
6948 {
6949     CONTRACTL
6950     {
6951         NOTHROW;
6952         GC_TRIGGERS;
6953         MODE_ANY;
6954         CAN_TAKE_LOCK;
6955         EE_THREAD_NOT_REQUIRED;
6956     }
6957     CONTRACTL_END;
6958
6959     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6960         kP2EEAllowableAfterAttach | kP2EETriggers,
6961         (LF_CORPROF,
6962         LL_INFO1000,
6963         "**PROF: SuspendRuntime\n"));
6964
6965     if (!g_fEEStarted)
6966     {
6967         return CORPROF_E_RUNTIME_UNINITIALIZED;
6968     }
6969
6970     if (ThreadSuspend::SysIsSuspendInProgress() || (ThreadSuspend::GetSuspensionThread() != 0))
6971     {
6972         return CORPROF_E_SUSPENSION_IN_PROGRESS;
6973     }
6974     
6975     g_profControlBlock.fProfilerRequestedRuntimeSuspend = TRUE;
6976     ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_REASON::SUSPEND_FOR_PROFILER);
6977     return S_OK;
6978 }
6979
6980 HRESULT ProfToEEInterfaceImpl::ResumeRuntime()
6981 {
6982     CONTRACTL
6983     {
6984         NOTHROW;
6985         GC_TRIGGERS;
6986         MODE_ANY;
6987         CAN_TAKE_LOCK;
6988     }
6989     CONTRACTL_END;
6990
6991     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6992         kP2EEAllowableAfterAttach | kP2EETriggers,
6993         (LF_CORPROF,
6994         LL_INFO1000,
6995         "**PROF: ResumeRuntime\n"));
6996     
6997     if (!g_fEEStarted)
6998     {
6999         return CORPROF_E_RUNTIME_UNINITIALIZED;
7000     }
7001
7002     if (!g_profControlBlock.fProfilerRequestedRuntimeSuspend)
7003     {
7004         return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
7005     }
7006
7007     ThreadSuspend::RestartEE(FALSE /* bFinishedGC */, TRUE /* SuspendSucceeded */);
7008     g_profControlBlock.fProfilerRequestedRuntimeSuspend = FALSE;
7009     return S_OK;
7010 }
7011
7012 /*
7013  * GetStringLayout
7014  *
7015  * This function describes to a profiler the internal layout of a string.
7016  *
7017  * Parameters:
7018  *   pBufferLengthOffset - Offset within an OBJECTREF of a string of the ArrayLength field.
7019  *   pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
7020  *   pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
7021  *
7022  * Returns:
7023  *   S_OK if successful.
7024  */
7025 HRESULT ProfToEEInterfaceImpl::GetStringLayout(ULONG *pBufferLengthOffset,
7026                                              ULONG *pStringLengthOffset,
7027                                              ULONG *pBufferOffset)
7028 {
7029     CONTRACTL
7030     {
7031         // Yay!
7032         NOTHROW;
7033
7034         // Yay!
7035         GC_NOTRIGGER;
7036
7037         // Yay!
7038         MODE_ANY;
7039
7040         // Yay!
7041         EE_THREAD_NOT_REQUIRED;
7042
7043         // Yay!
7044         CANNOT_TAKE_LOCK;
7045
7046
7047         PRECONDITION(CheckPointer(pBufferLengthOffset, NULL_OK));
7048         PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
7049         PRECONDITION(CheckPointer(pBufferOffset,  NULL_OK));
7050     }
7051     CONTRACTL_END;
7052
7053     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
7054         (LF_CORPROF, 
7055         LL_INFO1000, 
7056         "**PROF: GetStringLayout.\n"));
7057
7058     return this->GetStringLayoutHelper(pBufferLengthOffset, pStringLengthOffset, pBufferOffset);
7059 }
7060
7061 /*
7062  * GetStringLayout2
7063  *
7064  * This function describes to a profiler the internal layout of a string.
7065  *
7066  * Parameters:
7067  *   pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
7068  *   pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
7069  *
7070  * Returns:
7071  *   S_OK if successful.
7072  */
7073 HRESULT ProfToEEInterfaceImpl::GetStringLayout2(ULONG *pStringLengthOffset,
7074                                              ULONG *pBufferOffset)
7075 {
7076     CONTRACTL
7077     {
7078         // Yay!
7079         NOTHROW;
7080
7081         // Yay!
7082         GC_NOTRIGGER;
7083
7084         // Yay!
7085         MODE_ANY;
7086
7087         // Yay!
7088         EE_THREAD_NOT_REQUIRED;
7089
7090         // Yay!
7091         CANNOT_TAKE_LOCK;
7092
7093
7094         PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
7095         PRECONDITION(CheckPointer(pBufferOffset,  NULL_OK));
7096     }
7097     CONTRACTL_END;
7098
7099     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
7100         (LF_CORPROF, 
7101         LL_INFO1000, 
7102         "**PROF: GetStringLayout2.\n"));
7103
7104     ULONG dummyBufferLengthOffset;
7105     return this->GetStringLayoutHelper(&dummyBufferLengthOffset, pStringLengthOffset, pBufferOffset);
7106 }
7107
7108 /*
7109  * GetStringLayoutHelper
7110  *
7111  * This function describes to a profiler the internal layout of a string.
7112  *
7113  * Parameters:
7114  *   pBufferLengthOffset - Offset within an OBJECTREF of a string of the ArrayLength field.
7115  *   pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
7116  *   pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
7117  *
7118  * Returns:
7119  *   S_OK if successful.
7120  */
7121 HRESULT ProfToEEInterfaceImpl::GetStringLayoutHelper(ULONG *pBufferLengthOffset,
7122                                              ULONG *pStringLengthOffset,
7123                                              ULONG *pBufferOffset)
7124 {
7125     CONTRACTL
7126     {
7127         // Yay!
7128         NOTHROW;
7129
7130         // Yay!
7131         GC_NOTRIGGER;
7132
7133         // Yay!
7134         MODE_ANY;
7135
7136         // Yay!
7137         EE_THREAD_NOT_REQUIRED;
7138
7139         // Yay!
7140         CANNOT_TAKE_LOCK;
7141
7142
7143         PRECONDITION(CheckPointer(pBufferLengthOffset, NULL_OK));
7144         PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
7145         PRECONDITION(CheckPointer(pBufferOffset,  NULL_OK));
7146     }
7147     CONTRACTL_END;
7148
7149     // The String class no longer has a bufferLength field in it.
7150     // We are returning the offset of the stringLength because that is the closest we can get
7151     // This is most certainly a breaking change and a new method 
7152     // ICorProfilerInfo3::GetStringLayout2 has been added on the interface ICorProfilerInfo3
7153     if (pBufferLengthOffset != NULL)
7154     {
7155         *pBufferLengthOffset = StringObject::GetStringLengthOffset();
7156     }
7157
7158     if (pStringLengthOffset != NULL)
7159     {
7160         *pStringLengthOffset = StringObject::GetStringLengthOffset();
7161     }
7162
7163     if (pBufferOffset != NULL)
7164     {
7165         *pBufferOffset = StringObject::GetBufferOffset();
7166     }
7167
7168     return S_OK;
7169 }
7170
7171 /*
7172  * GetClassLayout
7173  *
7174  * This function describes to a profiler the internal layout of a class.
7175  *
7176  * Parameters:
7177  *   classID - The class that is being queried.  It is really a TypeHandle.
7178  *   rFieldOffset - An array to store information about each field in the class.
7179  *   cFieldOffset - Count of the number of elements in rFieldOffset.
7180  *   pcFieldOffset - Upon return contains the number of elements filled in, or if
7181  *         cFieldOffset is zero, the number of elements needed.
7182  *   pulClassSize - Optional parameter for containing the size in bytes of the underlying
7183  *         internal class structure.
7184  *
7185  * Returns:
7186  *   S_OK if successful.
7187  */
7188 HRESULT ProfToEEInterfaceImpl::GetClassLayout(ClassID classID,
7189                                              COR_FIELD_OFFSET rFieldOffset[],
7190                                              ULONG cFieldOffset,
7191                                              ULONG *pcFieldOffset,
7192                                              ULONG *pulClassSize)
7193 {
7194     CONTRACTL
7195     {
7196         // Yay!
7197         NOTHROW;
7198
7199         // Yay!
7200         GC_NOTRIGGER;
7201
7202         // Yay!
7203         MODE_ANY;
7204
7205         // Yay!
7206         EE_THREAD_NOT_REQUIRED;
7207
7208         // Yay!
7209         CANNOT_TAKE_LOCK;
7210
7211
7212         PRECONDITION(CheckPointer(rFieldOffset, NULL_OK));
7213         PRECONDITION(CheckPointer(pcFieldOffset));
7214         PRECONDITION(CheckPointer(pulClassSize,  NULL_OK));
7215     }
7216     CONTRACTL_END;
7217     
7218     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
7219         (LF_CORPROF, 
7220         LL_INFO1000, 
7221         "**PROF: GetClassLayout 0x%p.\n", 
7222         classID));
7223     
7224     //
7225     // Verify parameters
7226     //
7227     if ((pcFieldOffset == NULL) || (classID == NULL))
7228     {
7229          return E_INVALIDARG;
7230     }
7231
7232     if ((cFieldOffset != 0) && (rFieldOffset == NULL))
7233     {
7234         return E_INVALIDARG;
7235     }
7236
7237     TypeHandle typeHandle = TypeHandle::FromPtr((void *)classID);
7238
7239     //
7240     // This is the incorrect API for arrays or strings.  Use GetArrayObjectInfo, and GetStringLayout
7241     //
7242     if (typeHandle.IsTypeDesc() || typeHandle.AsMethodTable()->IsArray())
7243     {
7244         return E_INVALIDARG;
7245     }
7246
7247     //
7248     // We used to have a bug where this API incorrectly succeeded for strings during startup. Profilers
7249     // took dependency on this bug. Let the API to succeed for strings during startup for backward compatibility.
7250     //
7251     if (typeHandle.AsMethodTable()->IsString() && g_profControlBlock.fBaseSystemClassesLoaded)
7252     {
7253         return E_INVALIDARG;
7254     }
7255
7256     //
7257     // If this class is not fully restored, that is all the information we can get at this time.
7258     //
7259     if (!typeHandle.IsRestored())
7260     {
7261         return CORPROF_E_DATAINCOMPLETE;
7262     }
7263
7264     // Types can be pre-restored, but they still aren't expected to handle queries before
7265     // eager fixups have run. This is a targetted band-aid for a bug intellitrace was
7266     // running into - attempting to get the class layout for all types at module load time.
7267     // If we don't detect this the runtime will AV during the field iteration below. Feel
7268     // free to eliminate this check when a more complete solution is available.
7269     if (MethodTable::IsParentMethodTableTagged(typeHandle.AsMethodTable()))
7270     {
7271         return CORPROF_E_DATAINCOMPLETE;
7272     }
7273
7274     // !IsValueType = IsArray || IsReferenceType   Since IsArry has been ruled out above, it must 
7275     // be a reference type if !IsValueType.
7276     BOOL fReferenceType = !typeHandle.IsValueType();
7277
7278     //
7279     // Fill in class size now
7280     //
7281     // Move after the check for typeHandle.GetMethodTable()->IsRestored() 
7282     // because an unrestored MethodTable may have a bad EE class pointer
7283     // which will be used by MethodTable::GetNumInstanceFieldBytes
7284     //
7285     if (pulClassSize != NULL)
7286     {
7287         if (fReferenceType)
7288         {
7289             // aligned size including the object header for reference types
7290             *pulClassSize = typeHandle.GetMethodTable()->GetBaseSize();
7291         }
7292         else
7293         {
7294             // unboxed and unaligned size for value types
7295             *pulClassSize = typeHandle.GetMethodTable()->GetNumInstanceFieldBytes();
7296         }
7297     }
7298
7299     ApproxFieldDescIterator fieldDescIterator(typeHandle.GetMethodTable(), ApproxFieldDescIterator::INSTANCE_FIELDS);
7300
7301     ULONG cFields = fieldDescIterator.Count();
7302
7303     //
7304     // If they are looking to just get the count, return that.
7305     //
7306     if ((cFieldOffset == 0)  || (rFieldOffset == NULL))
7307     {
7308         *pcFieldOffset = cFields;
7309         return S_OK;
7310     }
7311
7312     //
7313     // Dont put too many in the array.
7314     //
7315     if (cFields > cFieldOffset)
7316     {
7317         cFields = cFieldOffset;
7318     }
7319
7320     *pcFieldOffset = cFields;
7321
7322     //
7323     // Now fill in the array
7324     //
7325     ULONG i;
7326     FieldDesc *pField;
7327
7328     for (i = 0; i < cFields; i++)
7329     {
7330         pField = fieldDescIterator.Next();
7331         rFieldOffset[i].ridOfField = (ULONG)pField->GetMemberDef();
7332         rFieldOffset[i].ulOffset = (ULONG)pField->GetOffset() + (fReferenceType ? Object::GetOffsetOfFirstField() : 0);
7333     }
7334
7335     return S_OK;
7336 }
7337
7338
7339 typedef struct _PROFILER_STACK_WALK_DATA
7340 {
7341     StackSnapshotCallback *callback;
7342     ULONG32 infoFlags;
7343     ULONG32 contextFlags;
7344     void *clientData;
7345     
7346 #ifdef WIN64EXCEPTIONS
7347     StackFrame sfParent;
7348 #endif
7349 } PROFILER_STACK_WALK_DATA;
7350
7351
7352 /*
7353  * ProfilerStackWalkCallback
7354  *
7355  * This routine is used as the callback from the general stack walker for
7356  * doing snapshot stack walks
7357  *
7358  */
7359 StackWalkAction ProfilerStackWalkCallback(CrawlFrame *pCf, PROFILER_STACK_WALK_DATA *pData)
7360 {
7361     CONTRACTL
7362     {
7363         NOTHROW;  // throw is RIGHT out... the throw at minimum allocates the thrown object which we *must* not do
7364         GC_NOTRIGGER; // the stack is not necessarily crawlable at this state !!!) we must not induce a GC 
7365     } 
7366     CONTRACTL_END;
7367
7368     MethodDesc *pFunc = pCf->GetFunction();
7369
7370     COR_PRF_FRAME_INFO_INTERNAL frameInfo;
7371     ULONG32 contextSize = 0;
7372     BYTE *context = NULL;
7373
7374     UINT_PTR currentIP = 0;
7375     REGDISPLAY *pRegDisplay = pCf->GetRegisterSet();
7376 #if defined(_TARGET_X86_)
7377     CONTEXT builtContext;
7378 #endif
7379
7380     //
7381     // For Unmanaged-to-managed transitions we get a NativeMarker back, which we want
7382     // to return to the profiler as the context seed if it wants to walk the unmanaged
7383     // stack frame, so we report the functionId as NULL to indicate this.
7384     //
7385     if (pCf->IsNativeMarker())
7386     {
7387         pFunc = NULL;
7388     }
7389
7390     //
7391     // Skip all Lightweight reflection/emit functions
7392     //
7393     if ((pFunc != NULL) && pFunc->IsNoMetadata())
7394     {
7395         return SWA_CONTINUE;
7396     }
7397
7398     //
7399     // If this is not a transition of any sort and not a managed
7400     // method, ignore it.
7401     //
7402     if (!pCf->IsNativeMarker() && !pCf->IsFrameless())
7403     {
7404         return SWA_CONTINUE;
7405     }
7406
7407     currentIP = (UINT_PTR)pRegDisplay->ControlPC;
7408
7409     frameInfo.size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
7410     frameInfo.version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
7411
7412     if (pFunc != NULL)
7413     {
7414         frameInfo.funcID = MethodDescToFunctionID(pFunc);
7415         frameInfo.extraArg = NULL;
7416     }
7417     else
7418     {
7419         frameInfo.funcID = NULL;
7420         frameInfo.extraArg = NULL;
7421     }
7422
7423     frameInfo.IP = currentIP;
7424     frameInfo.thisArg = NULL;
7425
7426     if (pData->infoFlags & COR_PRF_SNAPSHOT_REGISTER_CONTEXT)
7427     {
7428 #if defined(_TARGET_X86_)
7429         //
7430         // X86 stack walking does not keep the context up-to-date during the
7431         // walk.  Instead it keeps the REGDISPLAY up-to-date.  Thus, we need to
7432         // build a CONTEXT from the REGDISPLAY.
7433         //
7434
7435         memset(&builtContext, 0, sizeof(builtContext));
7436         builtContext.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
7437         CopyRegDisplay(pRegDisplay, NULL, &builtContext);
7438         context = (BYTE *)(&builtContext);
7439 #else
7440         context = (BYTE *)pRegDisplay->pCurrentContext;
7441 #endif
7442         contextSize = sizeof(CONTEXT);
7443     }
7444     
7445     // NOTE:  We are intentionally not setting any callback state flags here (i.e., not using
7446     // SetCallbackStateFlagsHolder), as we want the DSS callback to "inherit" the
7447     // same callback state that DSS has:  if DSS was called asynchronously, then consider
7448     // the DSS callback to be called asynchronously.
7449     if (pData->callback(frameInfo.funcID,
7450                         frameInfo.IP,
7451                         (COR_PRF_FRAME_INFO)&frameInfo,
7452                         contextSize,
7453                         context,
7454                         pData->clientData) == S_OK)
7455     {
7456         return SWA_CONTINUE;
7457     }
7458
7459     return SWA_ABORT;
7460 }
7461
7462 #ifdef _TARGET_X86_
7463
7464 //---------------------------------------------------------------------------------------
7465 // Normally, calling GetFunction() on the frame is sufficient to ensure
7466 // HelperMethodFrames are intialized. However, sometimes we need to be able to specify
7467 // that we should not enter the host while initializing, so we need to initialize such
7468 // frames more directly. This small helper function directly forces the initialization,
7469 // and ensures we don't enter the host as a result if we're executing in an asynchronous
7470 // call (i.e., hijacked thread)
7471 //
7472 // Arguments:
7473 //      pFrame - Frame to initialize.
7474 //
7475 // Return Value:
7476 //     TRUE iff pFrame was successfully initialized (or was already initialized). If
7477 //     pFrame is not a HelperMethodFrame (or derived type), this returns TRUE
7478 //     immediately. FALSE indicates we tried to initialize w/out entering the host, and
7479 //     had to abort as a result when a reader lock was needed but unavailable.
7480 //
7481
7482 static BOOL EnsureFrameInitialized(Frame * pFrame)
7483 {
7484     CONTRACTL
7485     {
7486         NOTHROW;
7487         GC_NOTRIGGER;
7488
7489         // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
7490         // host (SQL).  Corners will be cut to ensure this is the case
7491         if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
7492
7493         SUPPORTS_DAC;
7494     }
7495     CONTRACTL_END;
7496
7497     if (pFrame->GetFrameType() != Frame::TYPE_HELPER_METHOD_FRAME)
7498     {
7499         // This frame is not a HelperMethodFrame or a frame derived from
7500         // HelperMethodFrame, so HMF-specific lazy initialization is not an issue.
7501         return TRUE;
7502     }
7503
7504     HelperMethodFrame * pHMF = (HelperMethodFrame *) pFrame;
7505
7506     if (pHMF->InsureInit(
7507         false,                      // initialInit
7508         NULL,                       // unwindState
7509         (ShouldAvoidHostCalls() ?
7510             NoHostCalls :
7511             AllowHostCalls)
7512         ) != NULL)
7513     {
7514         // InsureInit() succeeded and found the return address
7515         return TRUE;
7516     }
7517
7518     // No return address was found. It must be because we asked InsureInit() to bail if
7519     // it would have entered the host
7520     _ASSERTE(ShouldAvoidHostCalls());
7521     return FALSE;
7522 }
7523
7524 //---------------------------------------------------------------------------------------
7525 //
7526 // Implements the COR_PRF_SNAPSHOT_X86_OPTIMIZED algorithm called by DoStackSnapshot. 
7527 // Does a simple EBP walk, rather than invoking all of StackWalkFramesEx.
7528 //
7529 // Arguments:
7530 //      pThreadToSnapshot - Thread whose stack should be walked
7531 //      pctxSeed - Register context with which to seed the walk
7532 //      callback - Function to call at each frame found during the walk
7533 //      clientData - Parameter to pass through to callback
7534 //
7535 // Return Value:
7536 //     HRESULT indicating success or failure.
7537 //
7538
7539 HRESULT ProfToEEInterfaceImpl::ProfilerEbpWalker(
7540     Thread * pThreadToSnapshot, 
7541     LPCONTEXT pctxSeed, 
7542     StackSnapshotCallback * callback, 
7543     void * clientData)
7544 {
7545     CONTRACTL
7546     {
7547         GC_NOTRIGGER;
7548         NOTHROW;
7549         MODE_ANY;
7550         EE_THREAD_NOT_REQUIRED;
7551
7552         // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
7553         // host (SQL).  Corners will be cut to ensure this is the case
7554         if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
7555     }
7556     CONTRACTL_END;
7557
7558     HRESULT hr;
7559
7560     // We haven't set the stackwalker thread type flag yet (see next line), so it shouldn't be set. Only
7561     // exception to this is if the current call is made by a hijacking profiler which
7562     // redirected this thread while it was previously in the middle of another stack walk
7563     _ASSERTE(IsCalledAsynchronously() || !IsStackWalkerThread());
7564
7565     // Remember that we're walking the stack.  This holder will reinstate the original
7566     // value of the stackwalker flag (from the thread type mask) in its destructor.
7567     ClrFlsValueSwitch _threadStackWalking(TlsIdx_StackWalkerWalkingThread, pThreadToSnapshot);
7568    
7569     // This flag remembers if we reported a managed frame since the last unmanaged block
7570     // we reported. It's used to avoid reporting two unmanaged blocks in a row.
7571     BOOL fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = FALSE;
7572
7573     Frame * pFrameCur = pThreadToSnapshot->GetFrame();
7574
7575     CONTEXT ctxCur;
7576     ZeroMemory(&ctxCur, sizeof(ctxCur));
7577
7578     // Use seed if we got one.  Otherwise, EE explicit Frame chain will seed the walk.
7579     if (pctxSeed != NULL)
7580     {
7581         ctxCur.Ebp = pctxSeed->Ebp;
7582         ctxCur.Eip = pctxSeed->Eip;
7583         ctxCur.Esp = pctxSeed->Esp;
7584     }
7585
7586     while (TRUE)
7587     {
7588         // At each iteration of the loop:
7589         //     * Analyze current frame (get managed data if it's a managed frame)
7590         //     * Report current frame via callback()
7591         //     * Walk down to next frame
7592         
7593         // **** Managed or unmanaged frame? ****
7594         
7595         EECodeInfo codeInfo;
7596         MethodDesc * pMethodDescCur = NULL;
7597
7598         if (ctxCur.Eip != 0)
7599         {
7600             hr = GetFunctionInfoInternal(
7601                 (LPCBYTE) ctxCur.Eip, 
7602                 &codeInfo);
7603             if (hr == CORPROF_E_ASYNCHRONOUS_UNSAFE)
7604             {
7605                 _ASSERTE(ShouldAvoidHostCalls());
7606                 return hr;
7607             }
7608             if (SUCCEEDED(hr))
7609             {
7610                 pMethodDescCur = codeInfo.GetMethodDesc();
7611             }
7612         }
7613
7614         // **** Report frame to profiler ****
7615
7616         if (
7617             // Make sure the frame gave us an IP
7618             (ctxCur.Eip != 0) &&              
7619
7620             // Make sure any managed frame isn't for an IL stub or LCG
7621             ((pMethodDescCur == NULL) || !pMethodDescCur->IsNoMetadata()) &&
7622
7623             // Only report unmanaged frames if the last frame we reported was managed
7624             // (avoid reporting two unmanaged blocks in a row)
7625             ((pMethodDescCur != NULL) || fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock))
7626         {
7627             // Around the call to the profiler, temporarily clear the
7628             // ThreadType_StackWalker type flag, as we have no control over what the
7629             // profiler may do inside its callback (it could theoretically attempt to
7630             // load other types, though I don't personally know of profilers that
7631             // currently do this).
7632             
7633             CLEAR_THREAD_TYPE_STACKWALKER();
7634             hr = callback(
7635                 (FunctionID) pMethodDescCur, 
7636                 ctxCur.Eip, 
7637                 NULL,               // COR_PRF_FRAME_INFO
7638                 sizeof(ctxCur),     // contextSize,
7639                 (LPBYTE) &ctxCur,   // context,
7640                 clientData);
7641             SET_THREAD_TYPE_STACKWALKER(pThreadToSnapshot);
7642             
7643             if (hr != S_OK)
7644             {
7645                 return hr;
7646             }
7647             if (pMethodDescCur == NULL)
7648             {
7649                 // Just reported an unmanaged block, so reset the flag
7650                 fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = FALSE;
7651             }
7652             else
7653             {
7654                 // Just reported a managed block, so remember it
7655                 fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = TRUE;
7656             }
7657         }
7658
7659         // **** Walk down to next frame ****
7660
7661         // Is current frame managed or unmanaged?
7662         if (pMethodDescCur == NULL)
7663         {
7664             // Unmanaged frame.  Use explicit EE Frame chain to help
7665
7666             REGDISPLAY frameRD;
7667             ZeroMemory(&frameRD, sizeof(frameRD));
7668
7669             while (pFrameCur != FRAME_TOP)
7670             {
7671                 // Frame is only useful if it will contain register context info
7672                 if (!pFrameCur->NeedsUpdateRegDisplay())
7673                 {
7674                     goto Loop;
7675                 }
7676
7677
7678                 // This should be the first call we make to the Frame, as it will
7679                 // ensure we force lazy initialize of HelperMethodFrames
7680                 if (!EnsureFrameInitialized(pFrameCur))
7681                 {
7682                     return CORPROF_E_ASYNCHRONOUS_UNSAFE;
7683                 }
7684                     
7685                 // This frame is only useful if it gives us an actual return address,
7686                 // and is situated on the stack at or below our current ESP (stack
7687                 // grows up)
7688                 if ((pFrameCur->GetReturnAddress() != NULL) &&
7689                     (dac_cast<TADDR>(pFrameCur) >= dac_cast<TADDR>(ctxCur.Esp)))
7690                 {
7691                     pFrameCur->UpdateRegDisplay(&frameRD);
7692                     break;
7693                 }
7694
7695 Loop:
7696                 pFrameCur = pFrameCur->PtrNextFrame();
7697             }
7698
7699             if (pFrameCur == FRAME_TOP)
7700             {
7701                 // No more frames.  Stackwalk is over
7702                 return S_OK;
7703             }
7704
7705             // Update ctxCur based on frame
7706             ctxCur.Eip = pFrameCur->GetReturnAddress();
7707             ctxCur.Ebp = GetRegdisplayFP(&frameRD);
7708             ctxCur.Esp = GetRegdisplaySP(&frameRD);
7709         }
7710         else
7711         {
7712             // Managed frame.
7713
7714             // GC info will assist us in determining whether this is a non-EBP frame and
7715             // info about pushed arguments.
7716             GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
7717             PTR_VOID gcInfo = gcInfoToken.Info;
7718             InfoHdr header;
7719             unsigned uiMethodSizeDummy;
7720             PTR_CBYTE table = PTR_CBYTE(gcInfo);
7721             table += decodeUnsigned(table, &uiMethodSizeDummy);
7722             table = decodeHeader(table, gcInfoToken.Version, &header);
7723
7724             // Ok, GCInfo, can we do a simple EBP walk or what?
7725
7726             if ((codeInfo.GetRelOffset() < header.prologSize) || 
7727                 (!header.ebpFrame && !header.doubleAlign))
7728             {
7729                 // We're either in the prolog or we're not in an EBP frame, in which case
7730                 // we'll just defer to the code manager to unwind for us. This condition
7731                 // is relatively rare, but can occur if:
7732                 // 
7733                 //     * The profiler did a DSS from its Enter hook, in which case we're
7734                 //         still inside the prolog, OR
7735                 //     * The seed context or explicit EE Frame chain seeded us with a
7736                 //         non-EBP frame function. In this case, using a naive EBP
7737                 //         unwinding algorithm would actually skip over the next EBP
7738                 //         frame, and would get SP all wrong as we try skipping over
7739                 //         the pushed parameters. So let's just ask the code manager for
7740                 //         help.
7741                 // 
7742                 // Note that there are yet more conditions (much more rare) where the EBP
7743                 // walk could get lost (e.g., we're inside an epilog). But we only care
7744                 // about the most likely cases, and it's ok if the unlikely cases result
7745                 // in truncated stacks, as unlikely cases will be statistically
7746                 // irrelevant to CPU performance sampling profilers
7747                 CodeManState codeManState;
7748                 codeManState.dwIsSet = 0;
7749                 REGDISPLAY rd;
7750                 FillRegDisplay(&rd, &ctxCur);
7751
7752                 rd.SetEbpLocation(&ctxCur.Ebp);
7753                 rd.SP = ctxCur.Esp;
7754                 rd.ControlPC = ctxCur.Eip;
7755
7756                 codeInfo.GetCodeManager()->UnwindStackFrame(
7757                     &rd, 
7758                     &codeInfo, 
7759                     SpeculativeStackwalk, 
7760                     &codeManState, 
7761                     NULL);
7762
7763                 ctxCur.Ebp = *rd.GetEbpLocation();
7764                 ctxCur.Esp = rd.SP;
7765                 ctxCur.Eip = rd.ControlPC;
7766             }
7767             else
7768             {
7769                 // We're in an actual EBP frame, so we can simplistically walk down to
7770                 // the next frame using EBP.
7771                 
7772                 // Return address is stored just below saved EBP (stack grows up)
7773                 ctxCur.Eip = *(DWORD *) (ctxCur.Ebp + sizeof(DWORD));
7774                 
7775                 ctxCur.Esp = 
7776                     // Stack location where current function pushed its EBP
7777                     ctxCur.Ebp +
7778
7779                     // Skip past that EBP
7780                     sizeof(DWORD) +
7781                     
7782                     // Skip past return address pushed by caller
7783                     sizeof(DWORD) + 
7784                     
7785                     // Skip past arguments to current function that were pushed by caller. 
7786                     // (Caller will pop varargs, so don't count those.)
7787                     (header.varargs ? 0 : (header.argCount * sizeof(DWORD)));
7788
7789                 // EBP for frame below us (stack grows up) has been saved onto our own
7790                 // frame. Dereference it now.
7791                 ctxCur.Ebp = *(DWORD *) ctxCur.Ebp;
7792             }
7793         }
7794     }
7795 }
7796 #endif // _TARGET_X86_
7797
7798 //*****************************************************************************
7799 //  The profiler stackwalk Wrapper
7800 //*****************************************************************************
7801 HRESULT ProfToEEInterfaceImpl::ProfilerStackWalkFramesWrapper(Thread * pThreadToSnapshot, PROFILER_STACK_WALK_DATA * pData, unsigned flags)
7802 {
7803     STATIC_CONTRACT_WRAPPER;
7804
7805     StackWalkAction swaRet = pThreadToSnapshot->StackWalkFrames(
7806         (PSTACKWALKFRAMESCALLBACK)ProfilerStackWalkCallback,
7807          pData,
7808          flags,
7809          NULL);
7810
7811     switch (swaRet)
7812     {
7813     default:
7814         _ASSERTE(!"Unexpected StackWalkAction returned from Thread::StackWalkFrames");
7815         return E_FAIL;
7816         
7817     case SWA_FAILED:
7818         return E_FAIL;
7819         
7820     case SWA_ABORT:
7821         return CORPROF_E_STACKSNAPSHOT_ABORTED;
7822
7823     case SWA_DONE:
7824         return S_OK;
7825     }
7826 }
7827
7828 //---------------------------------------------------------------------------------------
7829 //
7830 // DoStackSnapshot helper to call FindJitMan to determine if the specified
7831 // context is in managed code.
7832 //
7833 // Arguments:
7834 //      pCtx - Context to look at
7835 //      hostCallPreference - Describes how to acquire the reader lock--either AllowHostCalls
7836 //          or NoHostCalls (see code:HostCallPreference).
7837 //
7838 // Return Value:
7839 //      S_OK: The context is in managed code
7840 //      S_FALSE: The context is not in managed code.
7841 //      Error: Unable to determine (typically because hostCallPreference was NoHostCalls
7842 //         and the reader lock was unattainable without yielding)
7843 //
7844
7845 HRESULT IsContextInManagedCode(const CONTEXT * pCtx, HostCallPreference hostCallPreference)
7846 {
7847     WRAPPER_NO_CONTRACT;
7848     BOOL fFailedReaderLock = FALSE;
7849
7850     // if there's no Jit Manager for the IP, it's not managed code.
7851     BOOL fIsManagedCode = ExecutionManager::IsManagedCode(GetIP(pCtx), hostCallPreference, &fFailedReaderLock);
7852     if (fFailedReaderLock)
7853     {
7854         return CORPROF_E_ASYNCHRONOUS_UNSAFE;
7855     }
7856     
7857     return fIsManagedCode ? S_OK : S_FALSE;
7858 }
7859
7860 //*****************************************************************************
7861 // Perform a stack walk, calling back to callback at each managed frame.
7862 //*****************************************************************************
7863 HRESULT ProfToEEInterfaceImpl::DoStackSnapshot(ThreadID thread,
7864                                               StackSnapshotCallback *callback,
7865                                               ULONG32 infoFlags,
7866                                               void *clientData,
7867                                                BYTE * pbContext,
7868                                               ULONG32 contextSize)
7869 {
7870     CONTRACTL
7871     {
7872         // Yay!  (Note: NOTHROW is vital.  The throw at minimum allocates
7873         // the thrown object which we *must* not do.)
7874         NOTHROW;
7875
7876         // Yay!  (Note: this is called asynchronously to view the stack at arbitrary times,
7877         // so the stack is not necessarily crawlable for GC at this state!)
7878         GC_NOTRIGGER;
7879
7880         // Yay!
7881         MODE_ANY;
7882
7883         // Yay!
7884         EE_THREAD_NOT_REQUIRED;
7885
7886         // #DisableLockOnAsyncCalls
7887         // This call is allowed asynchronously, however it does take locks.  Therefore,
7888         // we will hit contract asserts if we happen to be in a CANNOT_TAKE_LOCK zone when
7889         // a hijacking profiler hijacks this thread to run DoStackSnapshot.  CANNOT_RETAKE_LOCK
7890         // is a more granular locking contract that says "I promise that if I take locks, I 
7891         // won't reenter any locks that were taken before this function was called".  
7892         DISABLED(CAN_TAKE_LOCK);
7893
7894         // Asynchronous functions can be called at arbitrary times when runtime 
7895         // is holding locks that cannot be reentered without causing deadlock.
7896         // This contract detects any attempts to reenter locks held at the time 
7897         // this function was called.  
7898         CANNOT_RETAKE_LOCK;
7899
7900     }
7901     CONTRACTL_END;
7902
7903     // This CONTRACT_VIOLATION is still needed because DISABLED(CAN_TAKE_LOCK) does not 
7904     // turn off contract violations.
7905     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
7906
7907     LPCONTEXT pctxSeed = reinterpret_cast<LPCONTEXT> (pbContext);
7908
7909     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
7910         (LF_CORPROF, 
7911         LL_INFO1000, 
7912         "**PROF: DoStackSnapshot 0x%p, 0x%p, 0x%08x, 0x%p, 0x%p, 0x%08x.\n", 
7913         thread, 
7914         callback, 
7915         infoFlags, 
7916         clientData, 
7917         pctxSeed, 
7918         contextSize));
7919    
7920     HRESULT hr = E_UNEXPECTED;
7921     // (hr assignment is to appease the compiler; we won't actually return without explicitly setting hr again)
7922     
7923     Thread *pThreadToSnapshot = NULL;
7924     Thread * pCurrentThread = GetThreadNULLOk();
7925     BOOL fResumeThread = FALSE;
7926     INDEBUG(ULONG ulForbidTypeLoad = 0;)
7927     BOOL fResetSnapshotThreadExternalCount = FALSE;
7928     int cRefsSnapshotThread = 0;
7929     
7930     // Remember whether we've already determined the current context of the target thread
7931     // is in managed (S_OK), not in managed (S_FALSE), or unknown (error).
7932     HRESULT hrCurrentContextIsManaged = E_FAIL;
7933
7934     CONTEXT ctxCurrent;
7935     memset(&ctxCurrent, 0, sizeof(ctxCurrent));
7936
7937     REGDISPLAY rd;
7938
7939     PROFILER_STACK_WALK_DATA data;
7940
7941     if (!g_fEEStarted )
7942     {
7943         // no managed code has run and things are likely in a very bad have loaded state
7944         // this is a bad time to try to walk the stack
7945         
7946         // Returning directly as there is nothing to cleanup yet
7947         return CORPROF_E_STACKSNAPSHOT_UNSAFE;
7948     }
7949
7950     if (!CORProfilerStackSnapshotEnabled())
7951     {
7952         // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7953         return CORPROF_E_INCONSISTENT_WITH_FLAGS;
7954     }
7955
7956     if (thread == NULL)
7957     {
7958         pThreadToSnapshot = pCurrentThread;
7959     }
7960     else
7961     {
7962         pThreadToSnapshot = (Thread *)thread;
7963     }
7964
7965 #ifdef _TARGET_X86_
7966     if ((infoFlags & ~(COR_PRF_SNAPSHOT_REGISTER_CONTEXT | COR_PRF_SNAPSHOT_X86_OPTIMIZED)) != 0)
7967 #else
7968     if ((infoFlags & ~(COR_PRF_SNAPSHOT_REGISTER_CONTEXT)) != 0)
7969 #endif
7970     {
7971         // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7972         return E_INVALIDARG;
7973     }
7974
7975     if (!IsManagedThread(pThreadToSnapshot) || !IsGarbageCollectorFullyInitialized())
7976     {
7977         //
7978         // No managed frames, return now.
7979         //
7980         // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7981         return S_OK;
7982     }
7983
7984     // We must make sure no other thread tries to hijack the thread we're about to walk
7985     // Hijacking means Thread::HijackThread, i.e. bashing return addresses which would break the stack walk
7986     Thread::HijackLockHolder hijackLockHolder(pThreadToSnapshot);
7987     if (!hijackLockHolder.Acquired())
7988     {
7989         // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7990         return CORPROF_E_STACKSNAPSHOT_UNSAFE;
7991     }
7992
7993     if (pThreadToSnapshot != pCurrentThread         // Walking separate thread
7994         && pCurrentThread != NULL                         // Walker (current) thread is a managed / VM thread
7995         && ThreadSuspend::SysIsSuspendInProgress())          // EE is trying suspend itself
7996     {
7997         // Since we're walking a separate thread, we'd have to suspend it first (see below).
7998         // And since the current thread is a VM thread, that means the current thread's
7999         // m_dwForbidSuspendThread count will go up while it's trying to suspend the
8000         // target thread (see Thread::SuspendThread).  THAT means no one will be able
8001         // to suspend the current thread until its m_dwForbidSuspendThread is decremented
8002         // (which happens as soon as the target thread of DoStackSnapshot has been suspended).
8003         // Since we're in the process of suspending the entire runtime, now would be a bad time to
8004         // make the walker thread un-suspendable (see VsWhidbey bug 454936).  So let's just abort
8005         // now.  Note that there is no synchronization around calling Thread::SysIsSuspendInProgress().
8006         // So we will get occasional false positives or false negatives.  But that's benign, as the worst
8007         // that might happen is we might occasionally delay the EE suspension a little bit, or we might
8008         // too eagerly fail from ProfToEEInterfaceImpl::DoStackSnapshot sometimes.  But there won't
8009         // be any corruption or AV.  
8010         //
8011         // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
8012         return CORPROF_E_STACKSNAPSHOT_UNSAFE;
8013     }
8014
8015     // We only allow stackwalking if:
8016     // 1) Target thread to walk == current thread OR Target thread is suspended, AND
8017     // 2) Target thread to walk is currently executing JITted / NGENd code, AND
8018     // 3) Target thread to walk is seeded OR currently NOT unwinding the stack, AND
8019     // 4) Target thread to walk != current thread OR current thread is NOT in a can't stop or forbid suspend region
8020
8021     // If the thread is in a forbid suspend region, it's dangerous to do anything:
8022     // - The code manager datastructures accessed during the stackwalk may be in inconsistent state.
8023     // - Thread::Suspend won't be able to suspend the thread.
8024     if (pThreadToSnapshot->IsInForbidSuspendRegion())
8025     {
8026         hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8027         goto Cleanup;
8028     }
8029
8030     HostCallPreference hostCallPreference;
8031     
8032     // First, check "1) Target thread to walk == current thread OR Target thread is suspended"
8033     if (pThreadToSnapshot != pCurrentThread && !g_profControlBlock.fProfilerRequestedRuntimeSuspend)
8034     {
8035 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8036         hr = E_NOTIMPL;
8037         goto Cleanup;
8038 #else
8039         // Walking separate thread, so it must be suspended.  First, ensure that
8040         // target thread exists.
8041         //
8042         // NOTE: We're using the "dangerous" variant of this refcount function, because we
8043         // rely on the profiler to ensure it never tries to walk a thread being destroyed.
8044         // (Profiler must block in its ThreadDestroyed() callback until all uses of that thread,
8045         // such as walking its stack, are complete.)
8046         cRefsSnapshotThread = pThreadToSnapshot->IncExternalCountDANGEROUSProfilerOnly();
8047         fResetSnapshotThreadExternalCount = TRUE;
8048
8049         if (cRefsSnapshotThread == 1 || !pThreadToSnapshot->HasValidThreadHandle())
8050         {
8051             // At this point, we've modified the VM state based on bad input
8052             // (pThreadToSnapshot) from the profiler.  This could cause
8053             // memory corruption and leave us vulnerable to security problems.
8054             // So destroy the process.
8055             _ASSERTE(!"Profiler trying to walk destroyed thread");
8056             EEPOLICY_HANDLE_FATAL_ERROR(CORPROF_E_STACKSNAPSHOT_INVALID_TGT_THREAD);
8057         }
8058
8059         // Thread::SuspendThread() ensures that no one else should try to suspend us
8060         // while we're suspending pThreadToSnapshot.
8061         //
8062         // TRUE: OneTryOnly.  Don't loop waiting for others to get out of our way in
8063         // order to suspend the thread.  If it's not safe, just return an error immediately.
8064         Thread::SuspendThreadResult str = pThreadToSnapshot->SuspendThread(TRUE);
8065         if (str == Thread::STR_Success)
8066         {
8067             fResumeThread = TRUE;
8068         }
8069         else
8070         {
8071             hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8072             goto Cleanup;            
8073         }
8074 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8075     }
8076
8077     hostCallPreference =
8078         ShouldAvoidHostCalls() ?
8079             NoHostCalls :       // Async call: Ensure this thread won't yield & re-enter host
8080             AllowHostCalls;     // Synchronous calls may re-enter host just fine
8081
8082     // If target thread is in pre-emptive mode, the profiler's seed context is unnecessary
8083     // because our frame chain is good enough: it will give us at least as accurate a
8084     // starting point as the profiler could.  Also, since profiler contexts cannot be
8085     // trusted, we don't want to set the thread's profiler filter context to this, as a GC
8086     // that interrupts the profiler's stackwalk will end up using the profiler's (potentially
8087     // bogus) filter context.
8088     if (!pThreadToSnapshot->PreemptiveGCDisabledOther())
8089     {
8090         // Thread to be walked is in preemptive mode.  Throw out seed.
8091         pctxSeed = NULL;
8092     }
8093     else if (pThreadToSnapshot != pCurrentThread)
8094     {
8095     // With cross-thread stack-walks, the target thread's context could be unreliable.
8096     // That would shed doubt on either a profiler-provided context, or a default
8097     // context we chose.  So check if we're in a potentially unreliable case, and return
8098     // an error if so.
8099     // 
8100     // These heurisitics are based on an actual bug where GetThreadContext returned a
8101     // self-consistent, but stale, context for a thread suspended after being redirected by
8102     // the GC (TFS Dev 10 bug # 733263).
8103         //
8104         // (Note that this whole block is skipped if pThreadToSnapshot is in preemptive mode (the IF
8105         // above), as the context is unused in such a case--the EE Frame chain is used
8106         // to seed the walk instead.)
8107 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8108         hr = E_NOTIMPL;
8109         goto Cleanup;
8110 #else
8111         if (!pThreadToSnapshot->GetSafelyRedirectableThreadContext(Thread::kDefaultChecks, &ctxCurrent, &rd))
8112         {
8113             LOG((LF_CORPROF, LL_INFO100, "**PROF: GetSafelyRedirectableThreadContext failure leads to CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
8114             hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8115             goto Cleanup;
8116         }
8117
8118         hrCurrentContextIsManaged = IsContextInManagedCode(&ctxCurrent, hostCallPreference);
8119         if (FAILED(hrCurrentContextIsManaged))
8120         {
8121             // Couldn't get the info.  Try again later
8122             _ASSERTE(ShouldAvoidHostCalls());
8123             hr = CORPROF_E_ASYNCHRONOUS_UNSAFE;
8124             goto Cleanup;
8125         }
8126
8127         if ((hrCurrentContextIsManaged == S_OK) &&
8128             (!pThreadToSnapshot->PreemptiveGCDisabledOther()))
8129         {
8130             // Thread is in preemptive mode while executing managed code?!  This lie is
8131             // an early warning sign that the context is bogus.  Bail.
8132             LOG((LF_CORPROF, LL_INFO100, "**PROF: Target thread context is likely bogus.  Returning CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
8133             hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8134             goto Cleanup;
8135         }
8136
8137         Frame * pFrame = pThreadToSnapshot->GetFrame();
8138         if (pFrame != FRAME_TOP)
8139         {
8140             TADDR spTargetThread = GetSP(&ctxCurrent);
8141             if (dac_cast<TADDR>(pFrame) < spTargetThread)
8142             {
8143                 // An Explicit EE Frame is more recent on the stack than the current
8144                 // stack pointer itself?  This lie is an early warning sign that the
8145                 // context is bogus. Bail.
8146                 LOG((LF_CORPROF, LL_INFO100, "**PROF: Target thread context is likely bogus.  Returning CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
8147                 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8148                 goto Cleanup;
8149             }
8150         }
8151
8152         // If the profiler did not specify a seed context of its own, use the current one we
8153         // just produced.
8154         //            
8155         // Failing to seed the walk can cause us to to "miss" functions on the stack.  This is
8156         // because StackWalkFrames(), when doing an unseeded stackwalk, sets the
8157         // starting regdisplay's IP/SP to 0.  This, in turn causes StackWalkFramesEx
8158         // to set cf.isFrameless = (pEEJM != NULL); (which is FALSE, since we have no
8159         // jit manager, since we have no IP).  Once frameless is false, we look solely to
8160         // the Frame chain for our goodies, rather than looking at the code actually
8161         // being executed by the thread.  The problem with the frame chain is that some
8162         // frames (e.g., GCFrame) don't point to any functions being executed.  So
8163         // StackWalkFramesEx just skips such frames and moves to the next one.  That
8164         // can cause a chunk of calls to be skipped.  To prevent this from happening, we
8165         // "fake" a seed by just seeding the thread with its current context.  This forces
8166         // StackWalkFramesEx() to look at the IP rather than just the frame chain.
8167         if (pctxSeed == NULL)
8168         {
8169             pctxSeed = &ctxCurrent;
8170         }
8171 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8172     }
8173
8174     // Second, check "2) Target thread to walk is currently executing JITted / NGENd code"
8175     // To do this, we need to find the proper context to investigate.  Start with
8176     // the seeded context, if available.  If not, use the target thread's current context.
8177     if (pctxSeed != NULL)
8178     {
8179         BOOL fSeedIsManaged;
8180
8181         // Short cut: If we're just using the current context as the seed, we may
8182         // already have determined whether it's in managed code.  If so, just use that
8183         // result rather than calculating it again
8184         if ((pctxSeed == &ctxCurrent) && SUCCEEDED(hrCurrentContextIsManaged))
8185         {
8186             fSeedIsManaged = (hrCurrentContextIsManaged == S_OK);
8187         }
8188         else
8189         {
8190             hr = IsContextInManagedCode(pctxSeed, hostCallPreference);
8191             if (FAILED(hr))
8192             {
8193                 hr = CORPROF_E_ASYNCHRONOUS_UNSAFE;
8194                 goto Cleanup;
8195             }
8196             fSeedIsManaged = (hr == S_OK);
8197         }
8198
8199         if (!fSeedIsManaged)
8200         {
8201             hr = CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX;
8202             goto Cleanup;
8203         }
8204     }
8205
8206 #ifdef _DEBUG
8207     //
8208     // Sanity check: If we are doing a cross-thread walk and there is no seed context, then
8209     // we better not be in managed code, otw we do not have a Frame on the stack from which to start
8210     // walking and we may miss the leaf-most chain of managed calls due to the way StackWalkFrames 
8211     // is implemented.  However, there is an exception when the leaf-most EE frame of pThreadToSnapshot
8212     // is an InlinedCallFrame, which has an active call, implying pThreadToShanpshot is inside an 
8213     // inlined P/Invoke.  In this case, the InlinedCallFrame will be used to help start off our
8214     // stackwalk at the top of the stack.
8215     //
8216     if (pThreadToSnapshot != pCurrentThread && !g_profControlBlock.fProfilerRequestedRuntimeSuspend)
8217     {
8218 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8219         hr = E_NOTIMPL;
8220         goto Cleanup;
8221 #else
8222         if (pctxSeed == NULL)
8223         {
8224             if (pThreadToSnapshot->GetSafelyRedirectableThreadContext(Thread::kDefaultChecks, &ctxCurrent, &rd))
8225             {
8226                 BOOL fFailedReaderLock = FALSE;
8227                 BOOL fIsManagedCode = ExecutionManager::IsManagedCode(GetIP(&ctxCurrent), hostCallPreference, &fFailedReaderLock);
8228
8229                 if (!fFailedReaderLock)
8230                 {
8231                     // not in jitted or ngend code or inside an inlined P/Invoke (the leaf-most EE Frame is
8232                     // an InlinedCallFrame with an active call)
8233                     _ASSERTE(!fIsManagedCode ||
8234                              (InlinedCallFrame::FrameHasActiveCall(pThreadToSnapshot->GetFrame())));
8235                 }
8236             }
8237         }
8238 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8239     }
8240 #endif //_DEBUG
8241     // Third, verify the target thread is seeded or not in the midst of an unwind.
8242     if (pctxSeed == NULL)
8243     {
8244         ThreadExceptionState* pExState = pThreadToSnapshot->GetExceptionState();
8245
8246         // this tests to see if there is an exception in flight
8247         if (pExState->IsExceptionInProgress() && pExState->GetFlags()->UnwindHasStarted())
8248         {
8249             EHClauseInfo *pCurrentEHClauseInfo = pThreadToSnapshot->GetExceptionState()->GetCurrentEHClauseInfo();
8250
8251             // if the exception code is telling us that we have entered a managed context then all is well
8252             if (!pCurrentEHClauseInfo->IsManagedCodeEntered())
8253             {
8254                 hr = CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX;
8255                 goto Cleanup;
8256             }
8257         }
8258     }
8259
8260     // Check if the exception state is consistent.  See the comment for ThreadExceptionFlag for more information. 
8261     if (pThreadToSnapshot->GetExceptionState()->HasThreadExceptionFlag(ThreadExceptionState::TEF_InconsistentExceptionState))
8262     {
8263         hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8264         goto Cleanup;
8265     }
8266
8267     data.callback = callback;
8268     data.infoFlags = infoFlags;
8269     data.contextFlags = 0;
8270     data.clientData = clientData;
8271 #ifdef WIN64EXCEPTIONS
8272     data.sfParent.Clear();
8273 #endif
8274
8275     // workaround: The ForbidTypeLoad book keeping in the stackwalker is not robust against exceptions.
8276     // Unfortunately, it is hard to get it right in the stackwalker since it has to be exception 
8277     // handling free (frame unwinding may never return). We restore the ForbidTypeLoad counter here
8278     // in case it got messed up by exception thrown during the stackwalk.
8279     INDEBUG(if (pCurrentThread) ulForbidTypeLoad = pCurrentThread->m_ulForbidTypeLoad;)
8280
8281     {
8282         // An AV during a profiler stackwalk is an isolated event and shouldn't bring
8283         // down the runtime.  Need to place the holder here, outside of ProfilerStackWalkFramesWrapper
8284         // since ProfilerStackWalkFramesWrapper uses __try, which doesn't like objects
8285         // with destructors.
8286         AVInRuntimeImplOkayHolder AVOkay;
8287
8288         hr = DoStackSnapshotHelper(
8289                  pThreadToSnapshot, 
8290                  &data, 
8291                  HANDLESKIPPEDFRAMES |
8292                      FUNCTIONSONLY |
8293                      NOTIFY_ON_U2M_TRANSITIONS |
8294                      ((pThreadToSnapshot == pCurrentThread) ?
8295                          0 : 
8296                          ALLOW_ASYNC_STACK_WALK | THREAD_IS_SUSPENDED) |
8297                      THREAD_EXECUTING_MANAGED_CODE |
8298                      PROFILER_DO_STACK_SNAPSHOT |
8299                      ALLOW_INVALID_OBJECTS, // stack walk logic should not look at objects - we could be in the middle of a gc.
8300                  pctxSeed);
8301     }
8302
8303     INDEBUG(if (pCurrentThread) pCurrentThread->m_ulForbidTypeLoad = ulForbidTypeLoad;)
8304
8305 Cleanup:
8306 #if defined(PLATFORM_SUPPORTS_SAFE_THREADSUSPEND)
8307     if (fResumeThread)
8308     {
8309         pThreadToSnapshot->ResumeThread();
8310     }
8311 #endif // PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8312     if (fResetSnapshotThreadExternalCount)
8313     {
8314         pThreadToSnapshot->DecExternalCountDANGEROUSProfilerOnly();
8315     }
8316
8317     return hr;
8318 }
8319
8320
8321 //---------------------------------------------------------------------------------------
8322 //
8323 // Exception swallowing wrapper around the profiler stackwalk
8324 //
8325 // Arguments:
8326 //      pThreadToSnapshot - Thread whose stack should be walked
8327 //      pData - data for stack walker
8328 //      flags - flags parameter to pass to StackWalkFramesEx, and StackFrameIterator 
8329 //      pctxSeed - Register context with which to seed the walk
8330 //
8331 // Return Value:
8332 //     HRESULT indicating success or failure.
8333 //
8334 HRESULT ProfToEEInterfaceImpl::DoStackSnapshotHelper(Thread * pThreadToSnapshot,
8335                                                      PROFILER_STACK_WALK_DATA * pData,
8336                                                      unsigned flags,
8337                                                      LPCONTEXT pctxSeed)
8338 {
8339     STATIC_CONTRACT_NOTHROW;
8340
8341     // We want to catch and swallow AVs here. For example, if the profiler gives 
8342     // us a bogus seed context (this happens), we could AV when inspecting memory pointed to 
8343     // by the (bogus) EBP register.
8344     //
8345     // EX_TRY/EX_CATCH does a lot of extras that we do not need and that can go wrong for us. 
8346     // E.g. It asserts in debug build for AVs in mscorwks or it synthetizes an object for the exception.
8347     // We use a plain PAL_TRY/PAL_EXCEPT since it is all we need.
8348     struct Param {
8349         HRESULT                     hr;
8350         Thread *                    pThreadToSnapshot;
8351         PROFILER_STACK_WALK_DATA *  pData;
8352         unsigned                    flags;
8353         ProfToEEInterfaceImpl *     pProfToEE;
8354         LPCONTEXT                   pctxSeed;
8355         BOOL                        fResetProfilerFilterContext;
8356     };
8357
8358     Param param;
8359     param.hr = E_UNEXPECTED;
8360     param.pThreadToSnapshot = pThreadToSnapshot;
8361     param.pData = pData;
8362     param.flags = flags; 
8363     param.pProfToEE = this;
8364     param.pctxSeed = pctxSeed;
8365     param.fResetProfilerFilterContext = FALSE;
8366
8367     PAL_TRY(Param *, pParam, &param)
8368     {
8369         if ((pParam->pData->infoFlags & COR_PRF_SNAPSHOT_X86_OPTIMIZED) != 0)
8370         {
8371 #ifndef _TARGET_X86_
8372             // If check in the begining of DoStackSnapshot (to return E_INVALIDARG) should 
8373             // make this unreachable
8374             _ASSERTE(!"COR_PRF_SNAPSHOT_X86_OPTIMIZED on non-X86 should be unreachable!");
8375 #else
8376             // New, simple EBP walker
8377             pParam->hr = pParam->pProfToEE->ProfilerEbpWalker(
8378                              pParam->pThreadToSnapshot,
8379                              pParam->pctxSeed,
8380                              pParam->pData->callback,
8381                              pParam->pData->clientData);
8382 #endif  // _TARGET_X86_
8383         }
8384         else
8385         {
8386             // We're now fairly confident the stackwalk should be ok, so set
8387             // the context seed, if one was provided or cooked up.
8388             if (pParam->pctxSeed != NULL)
8389             {
8390                 pParam->pThreadToSnapshot->SetProfilerFilterContext(pParam->pctxSeed);
8391                 pParam->fResetProfilerFilterContext = TRUE;
8392             }
8393
8394             // Whidbey-style walker, uses StackWalkFramesEx
8395             pParam->hr = pParam->pProfToEE->ProfilerStackWalkFramesWrapper(
8396                              pParam->pThreadToSnapshot,
8397                              pParam->pData,
8398                              pParam->flags);
8399         }
8400     }
8401     PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
8402     {
8403         param.hr = E_UNEXPECTED;
8404     }
8405     PAL_ENDTRY;
8406
8407     // Undo the context seeding & thread suspend we did (if any)
8408     // to ensure that the thread we walked stayed suspended
8409     if (param.fResetProfilerFilterContext)
8410     {
8411         pThreadToSnapshot->SetProfilerFilterContext(NULL);
8412     }
8413
8414     return param.hr;
8415 }
8416
8417
8418 HRESULT ProfToEEInterfaceImpl::GetGenerationBounds(ULONG cObjectRanges,
8419                                                    ULONG *pcObjectRanges,
8420                                                    COR_PRF_GC_GENERATION_RANGE ranges[])
8421 {
8422     CONTRACTL
8423     {
8424         // Yay!
8425         NOTHROW;
8426
8427         // Yay!
8428         GC_NOTRIGGER;
8429
8430         // Yay!
8431         MODE_ANY;
8432
8433         // Yay!
8434         EE_THREAD_NOT_REQUIRED;
8435
8436         // Yay!
8437         CANNOT_TAKE_LOCK;
8438
8439
8440         PRECONDITION(CheckPointer(pcObjectRanges));
8441         PRECONDITION(cObjectRanges <= 0 || ranges != NULL);
8442         PRECONDITION(s_generationTableLock >= 0);
8443     }
8444     CONTRACTL_END;
8445
8446     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8447         (LF_CORPROF, 
8448         LL_INFO1000, 
8449         "**PROF: GetGenerationBounds.\n"));
8450     
8451     // Announce we are using the generation table now
8452     CounterHolder genTableLock(&s_generationTableLock);
8453
8454     GenerationTable *generationTable = s_currentGenerationTable;
8455
8456     if (generationTable == NULL)
8457     {
8458         return E_FAIL;
8459     }
8460
8461     _ASSERTE(generationTable->magic == GENERATION_TABLE_MAGIC);
8462
8463     GenerationDesc *genDescTable = generationTable->genDescTable;
8464     ULONG count = min(generationTable->count, cObjectRanges);
8465     for (ULONG i = 0; i < count; i++)
8466     {
8467         ranges[i].generation          = (COR_PRF_GC_GENERATION)genDescTable[i].generation;
8468         ranges[i].rangeStart          = (ObjectID)genDescTable[i].rangeStart;
8469         ranges[i].rangeLength         = genDescTable[i].rangeEnd         - genDescTable[i].rangeStart;
8470         ranges[i].rangeLengthReserved = genDescTable[i].rangeEndReserved - genDescTable[i].rangeStart;
8471     }
8472
8473     *pcObjectRanges = generationTable->count;
8474
8475     return S_OK;
8476 }
8477
8478
8479 HRESULT ProfToEEInterfaceImpl::GetNotifiedExceptionClauseInfo(COR_PRF_EX_CLAUSE_INFO * pinfo)
8480 {
8481     CONTRACTL
8482     {
8483         // Yay!
8484         NOTHROW;
8485
8486         // Yay!
8487         GC_NOTRIGGER;
8488
8489         // Yay!
8490         MODE_ANY;
8491
8492         // Yay!
8493         CANNOT_TAKE_LOCK;
8494
8495
8496         PRECONDITION(CheckPointer(pinfo));
8497     }
8498     CONTRACTL_END;
8499
8500     PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF, 
8501                                      LL_INFO1000, 
8502                                      "**PROF: GetNotifiedExceptionClauseInfo.\n"));    
8503     
8504     HRESULT hr = S_OK;
8505
8506     ThreadExceptionState* pExState             = NULL;
8507     EHClauseInfo*         pCurrentEHClauseInfo = NULL;
8508
8509     // notification requires that we are on a managed thread with an exception in flight
8510     Thread *pThread = GetThread();
8511
8512     // If pThread is null, then the thread has never run managed code 
8513     if (pThread == NULL)
8514     {
8515         hr = CORPROF_E_NOT_MANAGED_THREAD;
8516         goto NullReturn;
8517     }
8518
8519     pExState = pThread->GetExceptionState();
8520     if (!pExState->IsExceptionInProgress())
8521     {
8522         // no exception is in flight -- successful failure
8523         hr = S_FALSE;
8524         goto NullReturn;
8525     }
8526
8527     pCurrentEHClauseInfo = pExState->GetCurrentEHClauseInfo();
8528     if (pCurrentEHClauseInfo->GetClauseType() == COR_PRF_CLAUSE_NONE)
8529     {
8530         // no exception is in flight -- successful failure
8531         hr = S_FALSE;
8532         goto NullReturn;
8533     }
8534
8535     pinfo->clauseType     = pCurrentEHClauseInfo->GetClauseType();
8536     pinfo->programCounter = pCurrentEHClauseInfo->GetIPForEHClause();
8537     pinfo->framePointer   = pCurrentEHClauseInfo->GetFramePointerForEHClause();
8538     pinfo->shadowStackPointer = 0;
8539
8540     return S_OK;
8541
8542 NullReturn:
8543     memset(pinfo, 0, sizeof(*pinfo));
8544     return hr;
8545 }
8546
8547
8548 HRESULT ProfToEEInterfaceImpl::GetObjectGeneration(ObjectID objectId,
8549                                                    COR_PRF_GC_GENERATION_RANGE *range)
8550 {
8551     CONTRACTL
8552     {
8553         // Yay!
8554         NOTHROW;
8555
8556         // Yay!
8557         GC_NOTRIGGER;
8558
8559         // Yay!
8560         MODE_ANY;
8561
8562         // Yay!
8563         EE_THREAD_NOT_REQUIRED;
8564
8565         // Yay!
8566         CANNOT_TAKE_LOCK;
8567
8568
8569         PRECONDITION(objectId != NULL);
8570         PRECONDITION(CheckPointer(range));
8571         PRECONDITION(s_generationTableLock >= 0);
8572     }
8573     CONTRACTL_END;
8574
8575     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8576                                        (LF_CORPROF, 
8577                                        LL_INFO1000, 
8578                                        "**PROF: GetObjectGeneration 0x%p.\n",
8579                                        objectId));        
8580
8581     BEGIN_GETTHREAD_ALLOWED;
8582     _ASSERTE((GetThread() == NULL) || (GetThread()->PreemptiveGCDisabled()));
8583     END_GETTHREAD_ALLOWED;
8584     
8585     // Announce we are using the generation table now
8586     CounterHolder genTableLock(&s_generationTableLock);
8587
8588     GenerationTable *generationTable = s_currentGenerationTable;
8589
8590     if (generationTable == NULL)
8591     {
8592         return E_FAIL;
8593     }
8594
8595     _ASSERTE(generationTable->magic == GENERATION_TABLE_MAGIC);
8596
8597     GenerationDesc *genDescTable = generationTable->genDescTable;
8598     ULONG count = generationTable->count;
8599     for (ULONG i = 0; i < count; i++)
8600     {
8601         if (genDescTable[i].rangeStart <= (BYTE *)objectId && (BYTE *)objectId < genDescTable[i].rangeEndReserved)
8602         {
8603             range->generation          = (COR_PRF_GC_GENERATION)genDescTable[i].generation;
8604             range->rangeStart          = (ObjectID)genDescTable[i].rangeStart;
8605             range->rangeLength         = genDescTable[i].rangeEnd         - genDescTable[i].rangeStart;
8606             range->rangeLengthReserved = genDescTable[i].rangeEndReserved - genDescTable[i].rangeStart;
8607
8608             return S_OK;
8609         }
8610     }
8611
8612     return E_FAIL;
8613 }
8614
8615 HRESULT ProfToEEInterfaceImpl::GetReJITIDs(
8616                            FunctionID          functionId,  // in
8617                            ULONG               cReJitIds,   // in
8618                            ULONG *             pcReJitIds,  // out
8619                            ReJITID             reJitIds[])  // out
8620 {
8621     CONTRACTL
8622     {
8623         // Yay!
8624         NOTHROW;
8625
8626         // taking a lock causes a GC
8627         GC_TRIGGERS;
8628
8629         // Yay!
8630         MODE_ANY;
8631
8632         // The rejit tables use a lock
8633         CAN_TAKE_LOCK;
8634
8635
8636         PRECONDITION(CheckPointer(pcReJitIds, NULL_OK));
8637         PRECONDITION(CheckPointer(reJitIds, NULL_OK));
8638
8639     }
8640     CONTRACTL_END;
8641
8642     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8643         kP2EEAllowableAfterAttach,
8644         (LF_CORPROF, 
8645         LL_INFO1000, 
8646         "**PROF: GetReJITIDs 0x%p.\n", 
8647          functionId));     
8648
8649     if (functionId == 0)
8650     {
8651         return E_INVALIDARG;
8652     }
8653
8654     if ((cReJitIds == 0) || (pcReJitIds == NULL) || (reJitIds == NULL))
8655     {
8656         return E_INVALIDARG;
8657     }
8658
8659     MethodDesc * pMD = FunctionIdToMethodDesc(functionId);
8660
8661     return ReJitManager::GetReJITIDs(pMD, cReJitIds, pcReJitIds, reJitIds);
8662 }
8663
8664
8665 HRESULT ProfToEEInterfaceImpl::SetupThreadForReJIT()
8666 {
8667     LIMITED_METHOD_CONTRACT;
8668
8669     HRESULT hr = S_OK;
8670     EX_TRY
8671     {
8672         if (GetThread() == NULL)
8673         {
8674             SetupThread();
8675         }
8676
8677         Thread *pThread = GetThread();
8678         pThread->SetProfilerCallbackStateFlags(COR_PRF_CALLBACKSTATE_REJIT_WAS_CALLED);
8679     }
8680     EX_CATCH_HRESULT(hr);
8681
8682     return hr;
8683 }
8684
8685 HRESULT ProfToEEInterfaceImpl::RequestReJIT(ULONG       cFunctions,   // in
8686                                             ModuleID    moduleIds[],  // in
8687                                             mdMethodDef methodIds[])  // in
8688 {
8689     CONTRACTL
8690     {
8691         // Yay!
8692         NOTHROW;
8693
8694         // When we suspend the runtime we drop into premptive mode
8695         GC_TRIGGERS;
8696
8697         // Yay!
8698         MODE_ANY;
8699
8700         // We need to suspend the runtime, this takes a lot of locks!
8701         CAN_TAKE_LOCK;
8702
8703
8704         PRECONDITION(CheckPointer(moduleIds, NULL_OK));
8705         PRECONDITION(CheckPointer(methodIds, NULL_OK));
8706     }
8707     CONTRACTL_END;
8708
8709     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8710         kP2EETriggers | kP2EEAllowableAfterAttach,
8711         (LF_CORPROF, 
8712          LL_INFO1000, 
8713          "**PROF: RequestReJIT.\n"));
8714
8715     if (!g_profControlBlock.pProfInterface->IsCallback4Supported())
8716     {
8717         return CORPROF_E_CALLBACK4_REQUIRED;
8718     }
8719
8720     if (!CORProfilerEnableRejit())
8721     {
8722         return CORPROF_E_REJIT_NOT_ENABLED;
8723     }
8724
8725     // Request at least 1 method to reJIT!
8726     if ((cFunctions == 0) || (moduleIds == NULL) || (methodIds == NULL))
8727     {
8728         return E_INVALIDARG;
8729     }
8730
8731     // Remember the profiler is doing this, as that means we must never detach it!
8732     g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
8733     
8734     HRESULT hr = SetupThreadForReJIT();
8735     if (FAILED(hr))
8736     {
8737         return hr;
8738     }
8739     
8740     GCX_PREEMP();
8741     return ReJitManager::RequestReJIT(cFunctions, moduleIds, methodIds, static_cast<COR_PRF_REJIT_FLAGS>(0));
8742 }
8743
8744 HRESULT ProfToEEInterfaceImpl::RequestRevert(ULONG       cFunctions,  // in
8745                                              ModuleID    moduleIds[], // in
8746                                              mdMethodDef methodIds[], // in
8747                                              HRESULT     rgHrStatuses[])    // out
8748 {
8749     CONTRACTL
8750     {
8751         // Yay!
8752         NOTHROW;
8753
8754         // The rejit manager requires a lock to iterate through methods to revert, and
8755         // taking the lock can drop us into preemptive mode.
8756         GC_TRIGGERS;
8757
8758         // Yay!
8759         MODE_ANY;
8760
8761         // The rejit manager requires a lock to iterate through methods to revert
8762         CAN_TAKE_LOCK;
8763
8764
8765         PRECONDITION(CheckPointer(moduleIds, NULL_OK));
8766         PRECONDITION(CheckPointer(methodIds, NULL_OK));
8767         PRECONDITION(CheckPointer(rgHrStatuses, NULL_OK));
8768     }
8769     CONTRACTL_END;
8770
8771     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8772         kP2EEAllowableAfterAttach | kP2EETriggers,
8773         (LF_CORPROF, 
8774          LL_INFO1000, 
8775          "**PROF: RequestRevert.\n"));
8776
8777     if (!CORProfilerEnableRejit())
8778     {
8779         return CORPROF_E_REJIT_NOT_ENABLED;
8780     }
8781
8782     // Request at least 1 method to revert!
8783     if ((cFunctions == 0) || (moduleIds == NULL) || (methodIds == NULL))
8784     {
8785         return E_INVALIDARG;
8786     }
8787
8788     // Remember the profiler is doing this, as that means we must never detach it!
8789     g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
8790
8791     // Initialize the status array
8792     if (rgHrStatuses != NULL)
8793     {
8794         memset(rgHrStatuses, 0, sizeof(HRESULT) * cFunctions);
8795         _ASSERTE(S_OK == rgHrStatuses[0]);
8796     }
8797     
8798     HRESULT hr = SetupThreadForReJIT();
8799     if (FAILED(hr))
8800     {
8801         return hr;
8802     }
8803
8804     GCX_PREEMP();
8805     return ReJitManager::RequestRevert(cFunctions, moduleIds, methodIds, rgHrStatuses);
8806 }
8807
8808
8809 HRESULT ProfToEEInterfaceImpl::EnumJITedFunctions(ICorProfilerFunctionEnum ** ppEnum)
8810 {
8811     CONTRACTL
8812     {
8813         // Yay!
8814         NOTHROW;
8815
8816         // Yay!
8817         GC_NOTRIGGER;
8818
8819         // Yay!
8820         MODE_ANY;
8821
8822         // If we're in preemptive mode we need to take a read lock to safely walk
8823         // the JIT data structures.
8824         CAN_TAKE_LOCK;
8825
8826
8827         PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8828
8829     }
8830     CONTRACTL_END;
8831
8832     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8833         (LF_CORPROF, 
8834         LL_INFO10, 
8835         "**PROF: EnumJITedFunctions.\n"));
8836
8837     if (ppEnum == NULL)
8838     {
8839         return E_INVALIDARG;
8840     }
8841
8842     *ppEnum = NULL;
8843
8844     NewHolder<ProfilerFunctionEnum> pJitEnum(new (nothrow) ProfilerFunctionEnum());
8845     if (pJitEnum == NULL)
8846     {
8847         return E_OUTOFMEMORY;
8848     }
8849
8850     if (!pJitEnum->Init())
8851     {
8852         return E_OUTOFMEMORY;
8853     }
8854
8855     // Ownership transferred to [out] param.  Caller must Release() when done with this.
8856     *ppEnum = (ICorProfilerFunctionEnum *)pJitEnum.Extract();
8857
8858     return S_OK;
8859 }
8860
8861 HRESULT ProfToEEInterfaceImpl::EnumJITedFunctions2(ICorProfilerFunctionEnum ** ppEnum)
8862 {
8863     CONTRACTL
8864     {
8865         // Yay!
8866         NOTHROW;
8867
8868         // Gathering rejitids requires taking a lock and that lock might switch to
8869         // preemptimve mode... 
8870         GC_TRIGGERS;
8871
8872         // Yay!
8873         MODE_ANY;
8874
8875         // If we're in preemptive mode we need to take a read lock to safely walk
8876         // the JIT data structures.
8877         // Gathering RejitIDs also takes a lock.
8878         CAN_TAKE_LOCK;
8879
8880
8881         PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8882
8883     }
8884     CONTRACTL_END;
8885
8886     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8887         kP2EEAllowableAfterAttach | kP2EETriggers,
8888         (LF_CORPROF, 
8889         LL_INFO10, 
8890         "**PROF: EnumJITedFunctions.\n"));
8891
8892     if (ppEnum == NULL)
8893     {
8894         return E_INVALIDARG;
8895     }
8896
8897     *ppEnum = NULL;
8898
8899     NewHolder<ProfilerFunctionEnum> pJitEnum(new (nothrow) ProfilerFunctionEnum());
8900     if (pJitEnum == NULL)
8901     {
8902         return E_OUTOFMEMORY;
8903     }
8904
8905     if (!pJitEnum->Init(TRUE /* fWithReJITIDs */))
8906     {
8907         // If it fails, it's because of OOM.
8908         return E_OUTOFMEMORY;
8909     }
8910
8911     // Ownership transferred to [out] param.  Caller must Release() when done with this.
8912     *ppEnum = (ICorProfilerFunctionEnum *)pJitEnum.Extract();
8913
8914     return S_OK;
8915 }
8916
8917 HRESULT ProfToEEInterfaceImpl::EnumModules(ICorProfilerModuleEnum ** ppEnum)
8918 {
8919     CONTRACTL
8920     {
8921         // Yay!
8922         NOTHROW;
8923
8924         // This method populates the enumerator, which requires iterating over
8925         // AppDomains, which adds, then releases, a reference on each AppDomain iterated.
8926         // This causes locking, and can cause triggering if the AppDomain gets destroyed
8927         // as a result of the release. (See code:AppDomainIterator::Next and its call to
8928         // code:AppDomain::Release.)
8929         GC_TRIGGERS;
8930
8931         // Yay!
8932         MODE_ANY;
8933
8934         // (See comment above GC_TRIGGERS.)
8935         CAN_TAKE_LOCK;
8936
8937
8938         PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8939
8940     }
8941     CONTRACTL_END;
8942
8943     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8944         kP2EEAllowableAfterAttach | kP2EETriggers,
8945         (LF_CORPROF, 
8946         LL_INFO10, 
8947         "**PROF: EnumModules.\n"));
8948
8949     HRESULT hr;
8950
8951     if (ppEnum == NULL)
8952     {
8953         return E_INVALIDARG;
8954     }
8955
8956     *ppEnum = NULL;
8957
8958     // ProfilerModuleEnum uese AppDomainIterator, which cannot be called while the current thead
8959     // is holding the ThreadStore lock.
8960     if (ThreadStore::HoldingThreadStore())
8961     {
8962         return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
8963     }
8964
8965     NewHolder<ProfilerModuleEnum> pModuleEnum(new (nothrow) ProfilerModuleEnum);
8966     if (pModuleEnum == NULL)
8967     {
8968         return E_OUTOFMEMORY;
8969     }
8970
8971     hr = pModuleEnum->Init();
8972     if (FAILED(hr))
8973     {
8974         return hr;
8975     }
8976
8977     // Ownership transferred to [out] param.  Caller must Release() when done with this.
8978     *ppEnum = (ICorProfilerModuleEnum *) pModuleEnum.Extract();
8979
8980     return S_OK;
8981 }
8982
8983 HRESULT ProfToEEInterfaceImpl::GetRuntimeInformation(USHORT * pClrInstanceId,
8984                                                      COR_PRF_RUNTIME_TYPE * pRuntimeType,
8985                                                      USHORT * pMajorVersion,
8986                                                      USHORT * pMinorVersion,
8987                                                      USHORT * pBuildNumber,
8988                                                      USHORT * pQFEVersion,
8989                                                      ULONG  cchVersionString,
8990                                                      ULONG  * pcchVersionString,
8991                                                      __out_ecount_part_opt(cchVersionString, *pcchVersionString) WCHAR  szVersionString[])
8992 {
8993     CONTRACTL
8994     {
8995         // Yay!
8996         NOTHROW;
8997
8998         // Yay!
8999         GC_NOTRIGGER;
9000
9001         // Yay!
9002         MODE_ANY;
9003
9004         // Yay!
9005         EE_THREAD_NOT_REQUIRED;
9006
9007         // Yay!
9008         CANNOT_TAKE_LOCK;
9009
9010     }
9011     CONTRACTL_END;
9012
9013     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
9014         (LF_CORPROF, 
9015         LL_INFO1000, 
9016         "**PROF: GetRuntimeInformation.\n"));
9017
9018     if ((szVersionString != NULL) && (pcchVersionString == NULL))
9019     {
9020         return E_INVALIDARG;
9021     }
9022
9023     if (pcchVersionString != NULL)
9024     {
9025         HRESULT hr = GetCORVersionInternal(szVersionString, (DWORD)cchVersionString, (DWORD *)pcchVersionString);
9026         if (FAILED(hr))
9027             return hr;
9028     }    
9029
9030     if (pClrInstanceId != NULL)
9031         *pClrInstanceId = static_cast<USHORT>(GetClrInstanceId());
9032
9033     if (pRuntimeType != NULL)
9034     {
9035         *pRuntimeType = COR_PRF_CORE_CLR;
9036     }
9037
9038     if (pMajorVersion != NULL)
9039         *pMajorVersion = CLR_MAJOR_VERSION;
9040
9041     if (pMinorVersion != NULL)
9042         *pMinorVersion = CLR_MINOR_VERSION;
9043
9044     if (pBuildNumber != NULL)
9045         *pBuildNumber = CLR_BUILD_VERSION;
9046
9047     if (pQFEVersion != NULL)
9048         *pQFEVersion = CLR_BUILD_VERSION_QFE;
9049
9050     return S_OK;
9051 }
9052
9053
9054 HRESULT ProfToEEInterfaceImpl::RequestProfilerDetach(DWORD dwExpectedCompletionMilliseconds)
9055 {
9056     CONTRACTL
9057     {
9058        // Yay!
9059         NOTHROW;
9060
9061         // Crst is used in ProfilingAPIDetach::RequestProfilerDetach so GC may be triggered
9062         GC_TRIGGERS;
9063
9064         // Yay!
9065         MODE_ANY;
9066
9067         // Yay!
9068         EE_THREAD_NOT_REQUIRED;
9069
9070         // Crst is used in ProfilingAPIDetach::RequestProfilerDetach
9071         CAN_TAKE_LOCK;
9072     }
9073     CONTRACTL_END;
9074
9075     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9076         kP2EEAllowableAfterAttach | kP2EETriggers,
9077         (LF_CORPROF, 
9078         LL_INFO1000, 
9079         "**PROF: RequestProfilerDetach.\n"));    
9080
9081 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
9082     return ProfilingAPIDetach::RequestProfilerDetach(dwExpectedCompletionMilliseconds);
9083 #else // FEATURE_PROFAPI_ATTACH_DETACH
9084     return E_NOTIMPL;
9085 #endif // FEATURE_PROFAPI_ATTACH_DETACH
9086 }
9087
9088 typedef struct _COR_PRF_ELT_INFO_INTERNAL
9089 {
9090     // Point to a platform dependent structure ASM helper push on the stack
9091     void * platformSpecificHandle;
9092
9093     // startAddress of COR_PRF_FUNCTION_ARGUMENT_RANGE structure needs to point 
9094     // TO the argument value, not BE the argument value.  So, when the argument 
9095     // is this, we need to point TO this.  Because of the calling sequence change
9096     // in ELT3, we need to reserve the pointer here instead of using one of our 
9097     // stack variables.
9098     void * pThis;
9099
9100     // Reserve space for output parameter COR_PRF_FRAME_INFO of 
9101     // GetFunctionXXXX3Info functions
9102     COR_PRF_FRAME_INFO_INTERNAL frameInfo;
9103
9104 } COR_PRF_ELT_INFO_INTERNAL;
9105
9106 //---------------------------------------------------------------------------------------
9107 //
9108 // ProfilingGetFunctionEnter3Info provides frame information and argument infomation of 
9109 // the function ELT callback is inspecting.  It is called either by the profiler or the 
9110 // C helper function.
9111 // 
9112 // Arguments:
9113 //      * functionId - [in] FunctionId of the function being inspected by ELT3
9114 //      * eltInfo - [in] The opaque pointer FunctionEnter3WithInfo callback passed to the profiler
9115 //      * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect 
9116 //                     generic types
9117 //      * pcbArgumentInfo - [in, out] Pointer to ULONG that specifies the size of structure 
9118 //                          pointed by pArgumentInfo
9119 //      * pArgumentInfo - [out] Pointer to COR_PRF_FUNCTION_ARGUMENT_INFO structure the profiler
9120 //                        must preserve enough space for the function it is inspecting
9121 //          
9122 // Return Value:
9123 //    HRESULT indicating success or failure.
9124 //    
9125
9126 HRESULT ProfilingGetFunctionEnter3Info(FunctionID functionId,                              // in
9127                                        COR_PRF_ELT_INFO eltInfo,                           // in
9128                                        COR_PRF_FRAME_INFO * pFrameInfo,                    // out
9129                                        ULONG * pcbArgumentInfo,                            // in, out
9130                                        COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo)     // out
9131 {
9132     CONTRACTL
9133     {
9134         // Yay!
9135         NOTHROW;
9136
9137         // Yay!
9138         GC_NOTRIGGER;
9139
9140         // Yay!
9141         MODE_ANY;
9142
9143         // ProfileArgIterator::ProfileArgIterator may take locks
9144         CAN_TAKE_LOCK;
9145
9146
9147     }
9148     CONTRACTL_END;
9149
9150     if ((functionId == NULL) || (eltInfo == NULL))
9151     {
9152         return E_INVALIDARG;
9153     }
9154
9155     COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9156     ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9157
9158     // The loader won't trigger a GC or throw for already loaded argument types.
9159     ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9160
9161     //
9162     // Find the method this is referring to, so we can get the signature
9163     //
9164     MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9165     MetaSig metaSig(pMethodDesc);
9166
9167     NewHolder<ProfileArgIterator> pProfileArgIterator;
9168
9169     {
9170         // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9171         FAULT_NOT_FATAL();
9172
9173         pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9174
9175         if (pProfileArgIterator == NULL)
9176         {
9177             return E_UNEXPECTED;
9178         }
9179     }
9180
9181     if (CORProfilerFrameInfoEnabled())
9182     {
9183         if (pFrameInfo == NULL)
9184         {
9185             return E_INVALIDARG;
9186         }
9187
9188         //
9189         // Setup the COR_PRF_FRAME_INFO structure first.
9190         //
9191         COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9192
9193         pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9194         pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9195         pCorPrfFrameInfo->funcID = functionId;
9196         pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9197         pCorPrfFrameInfo->extraArg = pProfileArgIterator->GetHiddenArgValue();
9198         pCorPrfFrameInfo->thisArg = pProfileArgIterator->GetThis();
9199
9200         *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9201     }
9202
9203     //
9204     // Do argument processing if desired.
9205     //
9206     if (CORProfilerFunctionArgsEnabled())
9207     {
9208         if (pcbArgumentInfo == NULL)
9209         {
9210             return E_INVALIDARG;
9211         }
9212
9213         if ((*pcbArgumentInfo != 0) && (pArgumentInfo == NULL))
9214         {
9215             return E_INVALIDARG;
9216         }
9217
9218         ULONG32 count = pProfileArgIterator->GetNumArgs();
9219
9220         if (metaSig.HasThis())
9221         {
9222             count++;
9223         }
9224
9225         ULONG ulArgInfoSize = sizeof(COR_PRF_FUNCTION_ARGUMENT_INFO) + (count * sizeof(COR_PRF_FUNCTION_ARGUMENT_RANGE));
9226
9227         if (*pcbArgumentInfo < ulArgInfoSize)
9228         {
9229             *pcbArgumentInfo = ulArgInfoSize;
9230             return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
9231         }
9232
9233         _ASSERTE(pArgumentInfo != NULL);
9234
9235         pArgumentInfo->numRanges         = count;
9236         pArgumentInfo->totalArgumentSize = 0;
9237
9238         count = 0;
9239
9240         if (metaSig.HasThis())
9241         {
9242             pELTInfo->pThis = pProfileArgIterator->GetThis();
9243             pArgumentInfo->ranges[count].startAddress = (UINT_PTR) (&(pELTInfo->pThis));
9244
9245             UINT length = sizeof(pELTInfo->pThis);
9246             pArgumentInfo->ranges[count].length = length;
9247             pArgumentInfo->totalArgumentSize += length;
9248             count++;
9249         }
9250
9251         while (count < pArgumentInfo->numRanges)
9252         {
9253             pArgumentInfo->ranges[count].startAddress = (UINT_PTR)(pProfileArgIterator->GetNextArgAddr());
9254
9255             UINT length = pProfileArgIterator->GetArgSize();
9256             pArgumentInfo->ranges[count].length = length;
9257             pArgumentInfo->totalArgumentSize += length;
9258             count++;
9259         }
9260     }
9261
9262     return S_OK;
9263 }
9264
9265
9266
9267 HRESULT ProfToEEInterfaceImpl::GetFunctionEnter3Info(FunctionID functionId,                              // in
9268                                                      COR_PRF_ELT_INFO eltInfo,                           // in
9269                                                      COR_PRF_FRAME_INFO * pFrameInfo,                    // out
9270                                                      ULONG * pcbArgumentInfo,                            // in, out
9271                                                      COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo)     // out
9272 {
9273     CONTRACTL
9274     {
9275         // Yay!
9276         NOTHROW;
9277
9278         // Yay!
9279         GC_NOTRIGGER;
9280
9281         // Yay!
9282         MODE_ANY;
9283
9284         // ProfilingGetFunctionEnter3Info may take locks
9285         CAN_TAKE_LOCK;
9286
9287
9288     }
9289     CONTRACTL_END;
9290
9291     PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF, 
9292                                     LL_INFO1000, 
9293                                     "**PROF: GetFunctionEnter3Info.\n"));
9294
9295     _ASSERTE(g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() != NULL);
9296
9297     if (!CORProfilerELT3SlowPathEnterEnabled())
9298     {
9299         return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9300     }
9301
9302     return ProfilingGetFunctionEnter3Info(functionId, eltInfo, pFrameInfo, pcbArgumentInfo, pArgumentInfo);
9303 }
9304
9305 //---------------------------------------------------------------------------------------
9306 //
9307 // ProfilingGetFunctionLeave3Info provides frame information and return value infomation 
9308 // of the function ELT callback is inspecting.  It is called either by the profiler or the 
9309 // C helper function.
9310 // 
9311 // Arguments:
9312 //      * functionId - [in] FunctionId of the function being inspected by ELT3
9313 //      * eltInfo - [in] The opaque pointer FunctionLeave3WithInfo callback passed to the profiler
9314 //      * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect 
9315 //                     generic types
9316 //      * pRetvalRange - [out] Pointer to COR_PRF_FUNCTION_ARGUMENT_RANGE to store return value
9317 //          
9318 // Return Value:
9319 //    HRESULT indicating success or failure.
9320 //    
9321
9322 HRESULT ProfilingGetFunctionLeave3Info(FunctionID functionId,                              // in
9323                                        COR_PRF_ELT_INFO eltInfo,                           // in
9324                                        COR_PRF_FRAME_INFO * pFrameInfo,                    // out
9325                                        COR_PRF_FUNCTION_ARGUMENT_RANGE * pRetvalRange)     // out
9326 {
9327     CONTRACTL
9328     {
9329         // Yay!
9330         NOTHROW;
9331
9332         // Yay!
9333         GC_NOTRIGGER;
9334
9335         // Yay!
9336         MODE_ANY;
9337
9338         // ProfileArgIterator::ProfileArgIterator may take locks
9339         CAN_TAKE_LOCK;
9340
9341     }
9342     CONTRACTL_END;
9343
9344     if ((pFrameInfo == NULL) || (eltInfo == NULL))
9345     {
9346         return E_INVALIDARG;
9347     }
9348
9349     COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9350     ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9351
9352     // The loader won't trigger a GC or throw for already loaded argument types.
9353     ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9354
9355     //
9356     // Find the method this is referring to, so we can get the signature
9357     //
9358     MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9359     MetaSig metaSig(pMethodDesc);
9360
9361     NewHolder<ProfileArgIterator> pProfileArgIterator;
9362
9363     {
9364         // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9365         FAULT_NOT_FATAL();
9366
9367         pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9368
9369         if (pProfileArgIterator == NULL)
9370         {
9371             return E_UNEXPECTED;
9372         }
9373     }
9374
9375     if (CORProfilerFrameInfoEnabled())
9376     {
9377         if (pFrameInfo == NULL)
9378         {
9379             return E_INVALIDARG;
9380         }
9381
9382         COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9383
9384         //
9385         // Setup the COR_PRF_FRAME_INFO structure first.
9386         //
9387         pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9388         pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9389         pCorPrfFrameInfo->funcID = functionId;
9390         pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9391
9392         // Upon entering Leave hook, the register assigned to store this pointer on function calls may 
9393         // already be reused and is likely not to contain this pointer.
9394         pCorPrfFrameInfo->extraArg = NULL;
9395         pCorPrfFrameInfo->thisArg = NULL;
9396
9397         *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9398     }
9399
9400     //
9401     // Do argument processing if desired.
9402     //
9403     if (CORProfilerFunctionReturnValueEnabled())
9404     {
9405         if (pRetvalRange == NULL)
9406         {
9407             return E_INVALIDARG;
9408         }
9409
9410         if (!metaSig.IsReturnTypeVoid())
9411         {
9412             pRetvalRange->length = metaSig.GetReturnTypeSize();
9413             pRetvalRange->startAddress = (UINT_PTR)pProfileArgIterator->GetReturnBufferAddr();
9414         }
9415         else
9416         {
9417             pRetvalRange->length = 0;
9418             pRetvalRange->startAddress = 0;
9419         }
9420     }
9421
9422     return S_OK;
9423 }
9424
9425
9426 HRESULT ProfToEEInterfaceImpl::GetFunctionLeave3Info(FunctionID functionId,                              // in
9427                                                      COR_PRF_ELT_INFO eltInfo,                           // in
9428                                                      COR_PRF_FRAME_INFO * pFrameInfo,                    // out
9429                                                      COR_PRF_FUNCTION_ARGUMENT_RANGE * pRetvalRange)     // out
9430 {
9431     CONTRACTL
9432     {
9433         // Yay!
9434         NOTHROW;
9435
9436         // Yay!
9437         GC_NOTRIGGER;
9438
9439         // Yay!
9440         MODE_ANY;
9441
9442         // ProfilingGetFunctionLeave3Info may take locks
9443         CAN_TAKE_LOCK;
9444
9445
9446     }
9447     CONTRACTL_END;
9448
9449     PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF, 
9450                                     LL_INFO1000, 
9451                                     "**PROF: GetFunctionLeave3Info.\n"));
9452
9453     _ASSERTE(g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() != NULL);
9454
9455     if (!CORProfilerELT3SlowPathLeaveEnabled())
9456     {
9457         return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9458     }
9459
9460     return ProfilingGetFunctionLeave3Info(functionId, eltInfo, pFrameInfo, pRetvalRange);
9461 }
9462
9463 //---------------------------------------------------------------------------------------
9464 //
9465 // ProfilingGetFunctionTailcall3Info provides frame information of the function ELT callback 
9466 // is inspecting.  It is called either by the profiler or the C helper function.
9467 // 
9468 // Arguments:
9469 //      * functionId - [in] FunctionId of the function being inspected by ELT3
9470 //      * eltInfo - [in] The opaque pointer FunctionTailcall3WithInfo callback passed to the 
9471 //                  profiler
9472 //      * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect 
9473 //                     generic types
9474 //          
9475 // Return Value:
9476 //    HRESULT indicating success or failure.
9477 //    
9478
9479 HRESULT ProfilingGetFunctionTailcall3Info(FunctionID functionId,                              // in
9480                                           COR_PRF_ELT_INFO eltInfo,                           // in
9481                                           COR_PRF_FRAME_INFO * pFrameInfo)                    // out
9482 {
9483     CONTRACTL
9484     {
9485         // Yay!
9486         NOTHROW;
9487
9488         // Yay!
9489         GC_NOTRIGGER;
9490
9491         // Yay!
9492         MODE_ANY;
9493
9494         // ProfileArgIterator::ProfileArgIterator may take locks
9495         CAN_TAKE_LOCK;
9496
9497
9498     }
9499     CONTRACTL_END;
9500
9501     if ((functionId == NULL) || (eltInfo == NULL) || (pFrameInfo == NULL))
9502     {
9503         return E_INVALIDARG;
9504     }
9505
9506     COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9507     ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9508
9509     // The loader won't trigger a GC or throw for already loaded argument types.
9510     ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9511
9512     //
9513     // Find the method this is referring to, so we can get the signature
9514     //
9515     MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9516     MetaSig metaSig(pMethodDesc);
9517
9518     NewHolder<ProfileArgIterator> pProfileArgIterator;
9519
9520     {
9521         // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9522         FAULT_NOT_FATAL();
9523
9524         pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9525
9526         if (pProfileArgIterator == NULL)
9527         {
9528             return E_UNEXPECTED;
9529         }
9530     }
9531
9532     COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9533
9534     //
9535     // Setup the COR_PRF_FRAME_INFO structure first.
9536     //
9537     pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9538     pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9539     pCorPrfFrameInfo->funcID = functionId;
9540     pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9541
9542     // Tailcall is designed to report the caller, not the callee.  But the taillcall hook is invoked 
9543     // with registers containing parameters passed to the callee before calling into the callee.  
9544     // This pointer we get here is for the callee.  Because of the constraints imposed on tailcall
9545     // optimization, this pointer passed to the callee accidentally happens to be the same this pointer 
9546     // passed to the caller.  
9547     // 
9548     // It is a fragile coincidence we should not depend on because JIT is free to change the 
9549     // implementation details in the future.
9550     pCorPrfFrameInfo->extraArg = NULL;
9551     pCorPrfFrameInfo->thisArg = NULL;
9552
9553     *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9554
9555     return S_OK;
9556 }
9557
9558
9559 HRESULT ProfToEEInterfaceImpl::GetFunctionTailcall3Info(FunctionID functionId,                              // in
9560                                                         COR_PRF_ELT_INFO eltInfo,                           // in
9561                                                         COR_PRF_FRAME_INFO * pFrameInfo)                    // out
9562 {
9563     CONTRACTL
9564     {
9565         // Yay!
9566         NOTHROW;
9567
9568         // Yay!
9569         GC_NOTRIGGER;
9570
9571         // Yay!
9572         MODE_ANY;
9573
9574         // ProfilingGetFunctionTailcall3Info may take locks
9575         CAN_TAKE_LOCK;
9576
9577
9578     }
9579     CONTRACTL_END;
9580
9581     PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF, 
9582                                     LL_INFO1000, 
9583                                     "**PROF: GetFunctionTailcall3Info.\n"));
9584
9585     _ASSERTE(g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() != NULL);
9586
9587     if (!CORProfilerELT3SlowPathTailcallEnabled())
9588     {
9589         return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9590     }
9591
9592     return ProfilingGetFunctionTailcall3Info(functionId, eltInfo, pFrameInfo);
9593 }
9594
9595 HRESULT ProfToEEInterfaceImpl::EnumThreads(
9596     /* out */ ICorProfilerThreadEnum ** ppEnum)
9597 {
9598
9599     CONTRACTL
9600     {
9601         // Yay!
9602         NOTHROW;
9603
9604         // Yay!
9605         GC_NOTRIGGER;
9606
9607         // Yay!
9608         MODE_ANY;
9609
9610         // Need to acquire the thread store lock
9611         CAN_TAKE_LOCK;
9612         
9613
9614         PRECONDITION(CheckPointer(ppEnum, NULL_OK));
9615
9616     }
9617     CONTRACTL_END;
9618
9619     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9620         kP2EEAllowableAfterAttach,
9621         (LF_CORPROF, 
9622         LL_INFO10, 
9623         "**PROF: EnumThreads.\n"));
9624
9625     HRESULT hr;
9626
9627     if (ppEnum == NULL)
9628     {
9629         return E_INVALIDARG;
9630     }
9631
9632     *ppEnum = NULL;
9633
9634     NewHolder<ProfilerThreadEnum> pThreadEnum(new (nothrow) ProfilerThreadEnum);
9635     if (pThreadEnum == NULL)
9636     {
9637         return E_OUTOFMEMORY;
9638     }
9639
9640     hr = pThreadEnum->Init();
9641     if (FAILED(hr))
9642     {
9643         return hr;
9644     }
9645
9646     // Ownership transferred to [out] param.  Caller must Release() when done with this.
9647     *ppEnum = (ICorProfilerThreadEnum *) pThreadEnum.Extract();
9648
9649     return S_OK;
9650 }
9651
9652 // This function needs to be called on any thread before making any ICorProfilerInfo* calls and must be 
9653 // made before any thread is suspended by this profiler.
9654 // As you might have already figured out, this is done to avoid deadlocks situation when 
9655 // the suspended thread holds on the loader lock / heap lock while the current thread is trying to obtain
9656 // the same lock.
9657 HRESULT ProfToEEInterfaceImpl::InitializeCurrentThread()
9658 {
9659
9660     CONTRACTL
9661     {
9662         // Yay!
9663         NOTHROW;
9664
9665         // Yay!
9666         GC_NOTRIGGER;
9667
9668         // Yay!
9669         MODE_ANY;
9670
9671         // May take thread store lock and OS APIs may also take locks
9672         CAN_TAKE_LOCK;
9673         
9674     }
9675     CONTRACTL_END;
9676     
9677    
9678     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9679             kP2EEAllowableAfterAttach,
9680             (LF_CORPROF, 
9681             LL_INFO10, 
9682             "**PROF: InitializeCurrentThread.\n"));
9683
9684     HRESULT hr = S_OK;
9685     
9686     EX_TRY
9687     {
9688         CExecutionEngine::SetupTLSForThread(GetThread());
9689     }
9690     EX_CATCH_HRESULT(hr);
9691
9692     if (FAILED(hr))
9693         return hr;
9694     
9695      return S_OK;
9696 }
9697
9698 struct InternalProfilerModuleEnum : public ProfilerModuleEnum
9699 {
9700     CDynArray<ModuleID> *GetRawElementsArray()
9701     {
9702         return &m_elements;
9703     }
9704 };
9705
9706 HRESULT ProfToEEInterfaceImpl::EnumNgenModuleMethodsInliningThisMethod(
9707     ModuleID    inlinersModuleId,
9708     ModuleID    inlineeModuleId,
9709     mdMethodDef inlineeMethodId,
9710     BOOL       *incompleteData,
9711     ICorProfilerMethodEnum** ppEnum)
9712 {
9713     CONTRACTL
9714     {
9715         NOTHROW;
9716         GC_TRIGGERS; 
9717         MODE_ANY;
9718         CAN_TAKE_LOCK;
9719         PRECONDITION(CheckPointer(ppEnum));
9720     }
9721     CONTRACTL_END;
9722
9723     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EETriggers, (LF_CORPROF, LL_INFO1000,  "**PROF: EnumNgenModuleMethodsInliningThisMethod.\n"));
9724
9725     if (ppEnum == NULL)
9726     {
9727         return E_INVALIDARG;
9728     }
9729     *ppEnum = NULL;
9730     HRESULT hr = S_OK;
9731
9732     Module *inlineeOwnerModule = reinterpret_cast<Module *>(inlineeModuleId);
9733     if (inlineeOwnerModule == NULL)
9734     {
9735         return E_INVALIDARG;
9736     }
9737     if (inlineeOwnerModule->IsBeingUnloaded())
9738     {
9739         return CORPROF_E_DATAINCOMPLETE;
9740     }
9741
9742     Module  *inlinersModule = reinterpret_cast<Module *>(inlinersModuleId);
9743     if (inlinersModule == NULL)
9744     {
9745         return E_INVALIDARG;
9746     }
9747     if(inlinersModule->IsBeingUnloaded())
9748     {
9749         return CORPROF_E_DATAINCOMPLETE;
9750     }
9751
9752     if (!inlinersModule->HasNativeOrReadyToRunInlineTrackingMap())
9753     {
9754         return CORPROF_E_DATAINCOMPLETE;
9755     }
9756
9757     CDynArray<COR_PRF_METHOD> results;
9758     const COUNT_T staticBufferSize = 10;
9759     MethodInModule staticBuffer[staticBufferSize];
9760     NewArrayHolder<MethodInModule> dynamicBuffer;
9761     MethodInModule *methodsBuffer = staticBuffer;
9762     EX_TRY
9763     {
9764         // Trying to use static buffer
9765         COUNT_T methodsAvailable = inlinersModule->GetNativeOrReadyToRunInliners(inlineeOwnerModule, inlineeMethodId, staticBufferSize, staticBuffer, incompleteData);
9766
9767         // If static buffer is not enough, allocate an array.
9768         if (methodsAvailable > staticBufferSize)
9769         {
9770             DWORD dynamicBufferSize = methodsAvailable;
9771             dynamicBuffer = methodsBuffer = new MethodInModule[dynamicBufferSize];
9772             methodsAvailable = inlinersModule->GetNativeOrReadyToRunInliners(inlineeOwnerModule, inlineeMethodId, dynamicBufferSize, dynamicBuffer, incompleteData);                
9773             if (methodsAvailable > dynamicBufferSize)
9774             {
9775                 _ASSERTE(!"Ngen image inlining info changed, this shouldn't be possible.");
9776                 methodsAvailable = dynamicBufferSize;
9777             }
9778         }
9779
9780         //Go through all inliners found in the inlinersModule and prepare them to export via results.
9781         results.AllocateBlockThrowing(methodsAvailable);
9782         for (COUNT_T j = 0; j < methodsAvailable; j++)
9783         {
9784             COR_PRF_METHOD *newPrfMethod = &results[j];
9785             newPrfMethod->moduleId = reinterpret_cast<ModuleID>(methodsBuffer[j].m_module);
9786             newPrfMethod->methodId = methodsBuffer[j].m_methodDef;
9787         }
9788         *ppEnum = new ProfilerMethodEnum(&results);
9789     }
9790     EX_CATCH_HRESULT(hr);
9791
9792     return hr;
9793 }
9794
9795 HRESULT ProfToEEInterfaceImpl::GetInMemorySymbolsLength(
9796     ModuleID moduleId,
9797     DWORD* pCountSymbolBytes)
9798 {
9799
9800     CONTRACTL
9801     {
9802         NOTHROW;
9803         GC_NOTRIGGER;
9804         MODE_ANY;
9805     }
9806     CONTRACTL_END;
9807
9808
9809     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9810         kP2EEAllowableAfterAttach,
9811         (LF_CORPROF,
9812             LL_INFO10,
9813             "**PROF: GetInMemorySymbolsLength.\n"));
9814
9815     HRESULT hr = S_OK;
9816     if (pCountSymbolBytes == NULL)
9817     {
9818         return E_INVALIDARG;
9819     }
9820     *pCountSymbolBytes = 0;
9821
9822     Module* pModule = reinterpret_cast< Module* >(moduleId);
9823     if (pModule == NULL)
9824     {
9825         return E_INVALIDARG;
9826     }
9827     if (pModule->IsBeingUnloaded())
9828     {
9829         return CORPROF_E_DATAINCOMPLETE;
9830     }
9831
9832     //This method would work fine on reflection.emit, but there would be no way to know
9833     //if some other thread was changing the size of the symbols before this method returned.
9834     //Adding events or locks to detect/prevent changes would make the scenario workable
9835     if (pModule->IsReflection())
9836     {
9837         return COR_PRF_MODULE_DYNAMIC;
9838     }
9839     
9840     CGrowableStream* pStream = pModule->GetInMemorySymbolStream();
9841     if (pStream == NULL)
9842     {
9843         return S_OK;
9844     }
9845
9846     STATSTG SizeData = { 0 };
9847     hr = pStream->Stat(&SizeData, STATFLAG_NONAME);
9848     if (FAILED(hr))
9849     {
9850         return hr;
9851     }
9852     if (SizeData.cbSize.u.HighPart > 0)
9853     {
9854         return COR_E_OVERFLOW;
9855     }
9856     *pCountSymbolBytes = SizeData.cbSize.u.LowPart;
9857
9858     return S_OK;
9859 }
9860
9861 HRESULT ProfToEEInterfaceImpl::ReadInMemorySymbols(
9862     ModuleID moduleId,
9863     DWORD symbolsReadOffset,
9864     BYTE* pSymbolBytes,
9865     DWORD countSymbolBytes,
9866     DWORD* pCountSymbolBytesRead)
9867 {
9868     CONTRACTL
9869     {
9870         NOTHROW;
9871         GC_NOTRIGGER;
9872         MODE_ANY;
9873     }
9874     CONTRACTL_END;
9875
9876     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9877         kP2EEAllowableAfterAttach,
9878         (LF_CORPROF,
9879             LL_INFO10,
9880             "**PROF: ReadInMemorySymbols.\n"));
9881
9882     HRESULT hr = S_OK;
9883     if (pSymbolBytes == NULL)
9884     {
9885         return E_INVALIDARG;
9886     }
9887     if (pCountSymbolBytesRead == NULL)
9888     {
9889         return E_INVALIDARG;
9890     }
9891     *pCountSymbolBytesRead = 0;
9892
9893     Module* pModule = reinterpret_cast< Module* >(moduleId);
9894     if (pModule == NULL)
9895     {
9896         return E_INVALIDARG;
9897     }
9898     if (pModule->IsBeingUnloaded())
9899     {
9900         return CORPROF_E_DATAINCOMPLETE;
9901     }
9902
9903     //This method would work fine on reflection.emit, but there would be no way to know
9904     //if some other thread was changing the size of the symbols before this method returned.
9905     //Adding events or locks to detect/prevent changes would make the scenario workable
9906     if (pModule->IsReflection())
9907     {
9908         return COR_PRF_MODULE_DYNAMIC;
9909     }
9910
9911     CGrowableStream* pStream = pModule->GetInMemorySymbolStream();
9912     if (pStream == NULL)
9913     {
9914         return E_INVALIDARG;
9915     }
9916
9917     STATSTG SizeData = { 0 };
9918     hr = pStream->Stat(&SizeData, STATFLAG_NONAME);
9919     if (FAILED(hr))
9920     {
9921         return hr;
9922     }
9923     if (SizeData.cbSize.u.HighPart > 0)
9924     {
9925         return COR_E_OVERFLOW;
9926     }
9927     DWORD streamSize = SizeData.cbSize.u.LowPart;
9928     if (symbolsReadOffset >= streamSize)
9929     {
9930         return E_INVALIDARG;
9931     }
9932
9933     *pCountSymbolBytesRead = min(streamSize - symbolsReadOffset, countSymbolBytes);
9934     memcpy_s(pSymbolBytes, countSymbolBytes, ((BYTE*)pStream->GetRawBuffer().StartAddress()) + symbolsReadOffset, *pCountSymbolBytesRead);
9935
9936     return S_OK;
9937 }
9938
9939 HRESULT ProfToEEInterfaceImpl::ApplyMetaData(
9940     ModuleID    moduleId)
9941 {
9942     CONTRACTL
9943     {
9944         NOTHROW;
9945         GC_TRIGGERS;
9946         MODE_ANY;
9947     }
9948     CONTRACTL_END;
9949
9950     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach | kP2EETriggers, (LF_CORPROF, LL_INFO1000, "**PROF: ApplyMetaData.\n"));
9951
9952     if (moduleId == NULL)
9953     {
9954         return E_INVALIDARG;
9955     }
9956
9957     HRESULT hr = S_OK;
9958     EX_TRY
9959     {
9960         Module *pModule = (Module *)moduleId;
9961         _ASSERTE(pModule != NULL);
9962         if (pModule->IsBeingUnloaded())
9963         {
9964             hr = CORPROF_E_DATAINCOMPLETE;
9965         }
9966        else
9967        {
9968             pModule->ApplyMetaData();
9969        }
9970     }
9971     EX_CATCH_HRESULT(hr);
9972     return hr;
9973 }
9974
9975 //---------------------------------------------------------------------------------------
9976 //
9977 // Simple wrapper around EEToProfInterfaceImpl::ManagedToUnmanagedTransition.  This
9978 // can be called by C++ code and directly by generated stubs.
9979 //
9980 // Arguments:
9981 //      pMD - MethodDesc for the managed function involved in the transition
9982 //      reason - Passed on to profiler to indicate why the transition is occurring
9983 //
9984
9985 void __stdcall ProfilerManagedToUnmanagedTransitionMD(MethodDesc *pMD,
9986                                                       COR_PRF_TRANSITION_REASON reason)
9987 {
9988     CONTRACTL
9989     {
9990         NOTHROW;
9991         GC_TRIGGERS;
9992         MODE_PREEMPTIVE;
9993     }
9994     CONTRACTL_END;
9995
9996     // This function is called within the runtime, not directly from managed code.
9997     // Also, the only case MD is NULL is the calli pinvoke case, and we still
9998     // want to notify the profiler in that case.
9999
10000     // Do not notify the profiler about QCalls
10001     if (pMD == NULL || !pMD->IsQCall())
10002     {
10003         BEGIN_PIN_PROFILER(CORProfilerPresent());
10004         g_profControlBlock.pProfInterface->ManagedToUnmanagedTransition(MethodDescToFunctionID(pMD),
10005                                                                         reason);
10006         END_PIN_PROFILER();
10007     }
10008 }
10009
10010 //---------------------------------------------------------------------------------------
10011 //
10012 // Simple wrapper around EEToProfInterfaceImpl::UnmanagedToManagedTransition.  This
10013 // can be called by C++ code and directly by generated stubs.
10014 //
10015 // Arguments:
10016 //      pMD - MethodDesc for the managed function involved in the transition
10017 //      reason - Passed on to profiler to indicate why the transition is occurring
10018 //
10019
10020 void __stdcall ProfilerUnmanagedToManagedTransitionMD(MethodDesc *pMD,
10021                                                       COR_PRF_TRANSITION_REASON reason)
10022 {
10023     CONTRACTL
10024     {
10025         NOTHROW;
10026         GC_TRIGGERS;
10027         MODE_PREEMPTIVE;
10028     }
10029     CONTRACTL_END;
10030
10031     // This function is called within the runtime, not directly from managed code.
10032     // Also, the only case MD is NULL is the calli pinvoke case, and we still
10033     // want to notify the profiler in that case.
10034
10035     // Do not notify the profiler about QCalls
10036     if (pMD == NULL || !pMD->IsQCall())
10037     {
10038         BEGIN_PIN_PROFILER(CORProfilerPresent());
10039         g_profControlBlock.pProfInterface->UnmanagedToManagedTransition(MethodDescToFunctionID(pMD),
10040                                                                         reason);
10041         END_PIN_PROFILER();
10042     }
10043 }
10044
10045
10046
10047 #endif // PROFILING_SUPPORTED
10048
10049
10050 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemoting)
10051 {
10052     FCALL_CONTRACT;
10053
10054 #ifdef PROFILING_SUPPORTED
10055     FC_RETURN_BOOL(CORProfilerTrackRemoting());
10056 #else // !PROFILING_SUPPORTED
10057     FC_RETURN_BOOL(FALSE);
10058 #endif // !PROFILING_SUPPORTED
10059 }
10060 FCIMPLEND
10061
10062 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemotingCookie)
10063 {
10064     FCALL_CONTRACT;
10065
10066 #ifdef PROFILING_SUPPORTED
10067     FC_RETURN_BOOL(CORProfilerTrackRemotingCookie());
10068 #else // !PROFILING_SUPPORTED
10069     FC_RETURN_BOOL(FALSE);
10070 #endif // !PROFILING_SUPPORTED
10071 }
10072 FCIMPLEND
10073
10074 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemotingAsync)
10075 {
10076     FCALL_CONTRACT;
10077
10078 #ifdef PROFILING_SUPPORTED
10079     FC_RETURN_BOOL(CORProfilerTrackRemotingAsync());
10080 #else // !PROFILING_SUPPORTED
10081     FC_RETURN_BOOL(FALSE);
10082 #endif // !PROFILING_SUPPORTED
10083 }
10084 FCIMPLEND
10085
10086 FCIMPL2(void, ProfilingFCallHelper::FC_RemotingClientSendingMessage, GUID *pId, CLR_BOOL fIsAsync)
10087 {
10088     FCALL_CONTRACT;
10089
10090 #ifdef PROFILING_SUPPORTED
10091     // Need to erect a GC frame so that GCs can occur without a problem
10092     // within the profiler code.
10093
10094     // Note that we don't need to worry about pId moving around since
10095     // it is a value class declared on the stack and so GC doesn't
10096     // know about it.
10097
10098     _ASSERTE (!GCHeapUtilities::GetGCHeap()->IsHeapPointer(pId));     // should be on the stack, not in the heap
10099     HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10100
10101     {
10102         BEGIN_PIN_PROFILER(CORProfilerPresent());
10103         GCX_PREEMP();
10104         if (CORProfilerTrackRemotingCookie())
10105         {
10106             g_profControlBlock.pProfInterface->GetGUID(pId);
10107             _ASSERTE(pId->Data1);
10108
10109             g_profControlBlock.pProfInterface->RemotingClientSendingMessage(pId, fIsAsync);
10110         }
10111         else
10112         {
10113             g_profControlBlock.pProfInterface->RemotingClientSendingMessage(NULL, fIsAsync);
10114         }
10115         END_PIN_PROFILER();
10116     }
10117     HELPER_METHOD_FRAME_END_POLL();
10118 #endif // PROFILING_SUPPORTED
10119 }
10120 FCIMPLEND
10121
10122
10123 FCIMPL2_VI(void, ProfilingFCallHelper::FC_RemotingClientReceivingReply, GUID id, CLR_BOOL fIsAsync)
10124 {
10125     FCALL_CONTRACT;
10126
10127 #ifdef PROFILING_SUPPORTED
10128     // Need to erect a GC frame so that GCs can occur without a problem
10129     // within the profiler code.
10130
10131     // Note that we don't need to worry about pId moving around since
10132     // it is a value class declared on the stack and so GC doesn't
10133     // know about it.
10134
10135     HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10136
10137
10138     {
10139         BEGIN_PIN_PROFILER(CORProfilerPresent());
10140         GCX_PREEMP();
10141         if (CORProfilerTrackRemotingCookie())
10142         {
10143             g_profControlBlock.pProfInterface->RemotingClientReceivingReply(&id, fIsAsync);
10144         }
10145         else
10146         {
10147             g_profControlBlock.pProfInterface->RemotingClientReceivingReply(NULL, fIsAsync);
10148         }
10149         END_PIN_PROFILER();
10150     }
10151
10152     HELPER_METHOD_FRAME_END_POLL();
10153 #endif // PROFILING_SUPPORTED
10154 }
10155 FCIMPLEND
10156
10157
10158 FCIMPL2_VI(void, ProfilingFCallHelper::FC_RemotingServerReceivingMessage, GUID id, CLR_BOOL fIsAsync)
10159 {
10160     FCALL_CONTRACT;
10161
10162 #ifdef PROFILING_SUPPORTED
10163     // Need to erect a GC frame so that GCs can occur without a problem
10164     // within the profiler code.
10165
10166     // Note that we don't need to worry about pId moving around since
10167     // it is a value class declared on the stack and so GC doesn't
10168     // know about it.
10169
10170     HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10171
10172     {
10173         BEGIN_PIN_PROFILER(CORProfilerPresent());
10174         GCX_PREEMP();
10175         if (CORProfilerTrackRemotingCookie())
10176         {
10177             g_profControlBlock.pProfInterface->RemotingServerReceivingMessage(&id, fIsAsync);
10178         }
10179         else
10180         {
10181             g_profControlBlock.pProfInterface->RemotingServerReceivingMessage(NULL, fIsAsync);
10182         }
10183         END_PIN_PROFILER();
10184     }
10185
10186     HELPER_METHOD_FRAME_END_POLL();
10187 #endif // PROFILING_SUPPORTED
10188 }
10189 FCIMPLEND
10190
10191 FCIMPL2(void, ProfilingFCallHelper::FC_RemotingServerSendingReply, GUID *pId, CLR_BOOL fIsAsync)
10192 {
10193     FCALL_CONTRACT;
10194
10195 #ifdef PROFILING_SUPPORTED
10196     // Need to erect a GC frame so that GCs can occur without a problem
10197     // within the profiler code.
10198
10199     // Note that we don't need to worry about pId moving around since
10200     // it is a value class declared on the stack and so GC doesn't
10201     // know about it.
10202
10203     HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10204
10205     {
10206         BEGIN_PIN_PROFILER(CORProfilerPresent());
10207         GCX_PREEMP();
10208         if (CORProfilerTrackRemotingCookie())
10209         {
10210             g_profControlBlock.pProfInterface->GetGUID(pId);
10211             _ASSERTE(pId->Data1);
10212
10213             g_profControlBlock.pProfInterface->RemotingServerSendingReply(pId, fIsAsync);
10214         }
10215         else
10216         {
10217             g_profControlBlock.pProfInterface->RemotingServerSendingReply(NULL, fIsAsync);
10218         }
10219         END_PIN_PROFILER();
10220     }
10221
10222     HELPER_METHOD_FRAME_END_POLL();
10223 #endif // PROFILING_SUPPORTED
10224 }
10225 FCIMPLEND
10226
10227
10228 //*******************************************************************************************
10229 // These do a lot of work for us, setting up Frames, gathering arg info and resolving generics.
10230   //*******************************************************************************************
10231
10232 HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecificHandle)
10233 {
10234     FCALL_CONTRACT;
10235
10236 #ifdef PROFILING_SUPPORTED
10237
10238     // We might have already torn down the profiler, if so we need to abort.
10239     if (g_profControlBlock.curProfStatus.Get() != kProfStatusActive 
10240 #ifdef PROF_TEST_ONLY_FORCE_ELT
10241         // If this test-only flag is set, it's possible we might not have a profiler
10242         // attached, or might not have any of the hooks set. See
10243         // code:ProfControlBlock#TestOnlyELT
10244         || g_profControlBlock.fTestOnlyForceEnterLeave
10245 #endif // PROF_TEST_ONLY_FORCE_ELT
10246         )
10247     {
10248         if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10249             (
10250                 (g_profControlBlock.pProfInterface->GetEnterHook()          == NULL) &&
10251                 (g_profControlBlock.pProfInterface->GetEnter2Hook()         == NULL) &&
10252                 (g_profControlBlock.pProfInterface->GetEnter3Hook()         == NULL) &&
10253                 (g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() == NULL)
10254             )
10255            )
10256         {
10257             return;
10258         }
10259     }       
10260
10261     // ELT3 Fast-Path hooks should be NULL when ELT intermediary is used.
10262     _ASSERTE(g_profControlBlock.pProfInterface->GetEnter3Hook() == NULL);
10263     _ASSERTE(GetThread()->PreemptiveGCDisabled());
10264     _ASSERTE(platformSpecificHandle != NULL);
10265
10266     // Set up a frame
10267     HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
10268
10269     // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10270     // frame, like we're about to do.
10271     SetCallbackStateFlagsHolder csf(
10272         COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10273    
10274     COR_PRF_ELT_INFO_INTERNAL eltInfo;
10275     eltInfo.platformSpecificHandle = platformSpecificHandle;
10276
10277     //
10278     // CLR v4 Slow-Path ELT
10279     //
10280     if (g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() != NULL)
10281     {
10282         FunctionIDOrClientID functionIDOrClientID;
10283         functionIDOrClientID.clientID = clientData;
10284         g_profControlBlock.pProfInterface->GetEnter3WithInfoHook()(
10285             functionIDOrClientID, 
10286             (COR_PRF_ELT_INFO)&eltInfo);
10287         goto LExit;
10288     }
10289
10290     if (g_profControlBlock.pProfInterface->GetEnter2Hook() != NULL)
10291     {
10292         // We have run out of heap memory, so the content of the mapping table becomes stale.
10293         // All Whidbey ETL hooks must be turned off.
10294         if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10295         {
10296             goto LExit;
10297         }
10298
10299         // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes 
10300         // instead of using clientID because the profiler may map several functionIDs to a clientID to 
10301         // do things like code coverage analysis.  FunctionID to clientID has the one-on-one relationship, 
10302         // while the reverse may not have this one-on-one mapping.  Therefore, FunctionID is used as the 
10303         // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10304         FunctionID functionId = clientData;
10305         _ASSERTE(functionId != NULL);
10306         clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10307
10308         //
10309         // Whidbey Fast-Path ELT
10310         //
10311         if (CORProfilerELT2FastPathEnterEnabled())
10312         {
10313             g_profControlBlock.pProfInterface->GetEnter2Hook()(
10314                 functionId,
10315                 clientData, 
10316                 NULL,
10317                 NULL);
10318             goto LExit;
10319         }
10320
10321         //
10322         // Whidbey Slow-Path ELT
10323         //
10324         ProfileSetFunctionIDInPlatformSpecificHandle(platformSpecificHandle, functionId);
10325
10326         COR_PRF_FRAME_INFO frameInfo = NULL;
10327         COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo = NULL;
10328         ULONG ulArgInfoSize = 0;
10329
10330         if (CORProfilerFunctionArgsEnabled())
10331         {
10332             // The loader won't trigger a GC or throw for already loaded argument types.
10333             ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
10334
10335             //
10336             // Find the method this is referring to, so we can get the signature
10337             //
10338             MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
10339             MetaSig metaSig(pMethodDesc);
10340
10341             NewHolder<ProfileArgIterator> pProfileArgIterator;
10342
10343             {
10344                 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
10345                 FAULT_NOT_FATAL();
10346
10347                 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, platformSpecificHandle);
10348
10349                 if (pProfileArgIterator == NULL)
10350                 {
10351                     goto LExit;
10352                 }
10353             }
10354
10355             ULONG32 count = pProfileArgIterator->GetNumArgs();
10356
10357             if (metaSig.HasThis())
10358             {
10359                 count++;
10360             }
10361             
10362             ulArgInfoSize = sizeof(COR_PRF_FUNCTION_ARGUMENT_INFO) + count * sizeof(COR_PRF_FUNCTION_ARGUMENT_RANGE);
10363             pArgumentInfo = (COR_PRF_FUNCTION_ARGUMENT_INFO *)_alloca(ulArgInfoSize);
10364         }
10365
10366         HRESULT hr = ProfilingGetFunctionEnter3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo, &ulArgInfoSize, pArgumentInfo);
10367
10368         _ASSERTE(hr == S_OK);
10369         g_profControlBlock.pProfInterface->GetEnter2Hook()(functionId, clientData, frameInfo, pArgumentInfo);
10370
10371         goto LExit;
10372     }
10373
10374
10375     // We will not be here unless the jit'd or ngen'd function we're about to enter
10376     // was backpatched with this wrapper around the profiler's hook, and that
10377     // wouldn't have happened unless the profiler supplied us with a hook
10378     // in the first place.  (Note that SetEnterLeaveFunctionHooks* will return
10379     // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10380     // its mind about where the hooks are.)
10381     _ASSERTE(g_profControlBlock.pProfInterface->GetEnterHook() != NULL);
10382
10383     // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10384     // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10385     // to enable the jitter to add enter/leave callouts independently of whether
10386     // the profiler actually has enter/leave hooks.  (If the profiler has no such hooks,
10387     // the callouts quickly return and do nothing.)
10388
10389     //
10390     // Everett ELT
10391     //
10392     {
10393         g_profControlBlock.pProfInterface->GetEnterHook()((FunctionID)clientData);
10394     }
10395
10396 LExit:
10397     ;
10398
10399     HELPER_METHOD_FRAME_END();      // Un-link the frame
10400
10401 #endif // PROFILING_SUPPORTED
10402 }
10403 HCIMPLEND
10404
10405 HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecificHandle)
10406 {
10407     FCALL_CONTRACT;
10408
10409     FC_GC_POLL_NOT_NEEDED();            // we pulse GC mode, so we are doing a poll
10410
10411 #ifdef PROFILING_SUPPORTED
10412
10413     // We might have already torn down the profiler, if so we need to abort.
10414     if (g_profControlBlock.curProfStatus.Get() != kProfStatusActive 
10415 #ifdef PROF_TEST_ONLY_FORCE_ELT
10416         // If this test-only flag is set, it's possible we might not have a profiler
10417         // attached, or might not have any of the hooks set. See
10418         // code:ProfControlBlock#TestOnlyELT
10419         || g_profControlBlock.fTestOnlyForceEnterLeave
10420 #endif // PROF_TEST_ONLY_FORCE_ELT
10421         )
10422     {
10423         if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10424             (
10425                 (g_profControlBlock.pProfInterface->GetLeaveHook()          == NULL) &&
10426                 (g_profControlBlock.pProfInterface->GetLeave2Hook()         == NULL) &&
10427                 (g_profControlBlock.pProfInterface->GetLeave3Hook()         == NULL) &&
10428                 (g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() == NULL)
10429             )
10430            )
10431         {
10432             return;
10433         }
10434     }
10435
10436     // ELT3 Fast-Path hooks should be NULL when ELT intermediary is used.
10437     _ASSERTE(g_profControlBlock.pProfInterface->GetLeave3Hook() == NULL);
10438     _ASSERTE(GetThread()->PreemptiveGCDisabled());
10439     _ASSERTE(platformSpecificHandle != NULL);
10440
10441     // Set up a frame
10442     HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2); 
10443
10444     // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10445     // frame, like we're about to do.
10446     SetCallbackStateFlagsHolder csf(
10447         COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10448     
10449     COR_PRF_ELT_INFO_INTERNAL eltInfo;
10450     eltInfo.platformSpecificHandle = platformSpecificHandle;
10451     
10452     //
10453     // CLR v4 Slow-Path ELT
10454     //
10455     if (g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() != NULL)
10456     {
10457         FunctionIDOrClientID functionIDOrClientID;
10458         functionIDOrClientID.clientID = clientData;
10459         g_profControlBlock.pProfInterface->GetLeave3WithInfoHook()(
10460             functionIDOrClientID, 
10461             (COR_PRF_ELT_INFO)&eltInfo);
10462         goto LExit;
10463     }
10464
10465     if (g_profControlBlock.pProfInterface->GetLeave2Hook() != NULL)
10466     {
10467         // We have run out of heap memory, so the content of the mapping table becomes stale.
10468         // All Whidbey ETL hooks must be turned off.
10469         if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10470         {
10471             goto LExit;
10472         }
10473
10474         // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes 
10475         // instead of using clientID because the profiler may map several functionIDs to a clientID to 
10476         // do things like code coverage analysis.  FunctionID to clientID has the one-on-one relationship, 
10477         // while the reverse may not have this one-on-one mapping.  Therefore, FunctionID is used as the 
10478         // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10479         FunctionID functionId = clientData;
10480         _ASSERTE(functionId != NULL);
10481         clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10482
10483         //
10484         // Whidbey Fast-Path ELT
10485         //
10486         if (CORProfilerELT2FastPathLeaveEnabled())
10487         {
10488             g_profControlBlock.pProfInterface->GetLeave2Hook()(
10489                 functionId,
10490                 clientData, 
10491                 NULL,
10492                 NULL);
10493             goto LExit;
10494         }
10495
10496         //
10497         // Whidbey Slow-Path ELT
10498         //
10499         COR_PRF_FRAME_INFO frameInfo = NULL;
10500         COR_PRF_FUNCTION_ARGUMENT_RANGE argumentRange;
10501
10502         HRESULT hr = ProfilingGetFunctionLeave3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo, &argumentRange);
10503         _ASSERTE(hr == S_OK);
10504
10505         g_profControlBlock.pProfInterface->GetLeave2Hook()(functionId, clientData, frameInfo, &argumentRange);
10506         goto LExit;
10507     }
10508
10509     // We will not be here unless the jit'd or ngen'd function we're about to leave
10510     // was backpatched with this wrapper around the profiler's hook, and that
10511     // wouldn't have happened unless the profiler supplied us with a hook
10512     // in the first place.  (Note that SetEnterLeaveFunctionHooks* will return
10513     // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10514     // its mind about where the hooks are.)
10515     _ASSERTE(g_profControlBlock.pProfInterface->GetLeaveHook() != NULL);
10516
10517     // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10518     // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10519     // to enable the jitter to add enter/leave callouts independently of whether
10520     // the profiler actually has enter/leave hooks.  (If the profiler has no such hooks,
10521     // the callouts quickly return and do nothing.)
10522
10523     //
10524     // Everett ELT
10525     //
10526     {
10527         g_profControlBlock.pProfInterface->GetLeaveHook()((FunctionID)clientData);
10528     }
10529
10530 LExit:
10531
10532     ;
10533
10534     HELPER_METHOD_FRAME_END();      // Un-link the frame
10535
10536 #endif // PROFILING_SUPPORTED
10537 }
10538 HCIMPLEND
10539
10540 HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpecificHandle)
10541 {
10542     FCALL_CONTRACT;
10543
10544     FC_GC_POLL_NOT_NEEDED();            // we pulse GC mode, so we are doing a poll
10545
10546 #ifdef PROFILING_SUPPORTED
10547
10548     // We might have already torn down the profiler, if so we need to abort.
10549     if (g_profControlBlock.curProfStatus.Get() != kProfStatusActive 
10550 #ifdef PROF_TEST_ONLY_FORCE_ELT
10551         // If this test-only flag is set, it's possible we might not have a profiler
10552         // attached, or might not have any of the hooks set. See
10553         // code:ProfControlBlock#TestOnlyELT
10554         || g_profControlBlock.fTestOnlyForceEnterLeave
10555 #endif // PROF_TEST_ONLY_FORCE_ELT
10556         )
10557     {
10558         if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10559             (
10560                 (g_profControlBlock.pProfInterface->GetTailcallHook()          == NULL) &&
10561                 (g_profControlBlock.pProfInterface->GetTailcall2Hook()         == NULL) &&
10562                 (g_profControlBlock.pProfInterface->GetTailcall3Hook()         == NULL) &&
10563                 (g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() == NULL)
10564             )
10565            )
10566         {
10567             return;
10568         }
10569     }
10570
10571     // ELT3 fast-path hooks should be NULL when ELT intermediary is used.
10572     _ASSERTE(g_profControlBlock.pProfInterface->GetTailcall3Hook() == NULL);
10573     _ASSERTE(GetThread()->PreemptiveGCDisabled());
10574     _ASSERTE(platformSpecificHandle != NULL);
10575
10576     // Set up a frame
10577     HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
10578
10579     // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10580     // frame, like we're about to do.
10581     SetCallbackStateFlagsHolder csf(
10582         COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10583     
10584     COR_PRF_ELT_INFO_INTERNAL eltInfo;
10585     eltInfo.platformSpecificHandle = platformSpecificHandle;
10586
10587     //
10588     // CLR v4 Slow-Path ELT
10589     //
10590     if (g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() != NULL)
10591     {
10592         FunctionIDOrClientID functionIDOrClientID;
10593         functionIDOrClientID.clientID = clientData;
10594         g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook()(
10595             functionIDOrClientID, 
10596             (COR_PRF_ELT_INFO)&eltInfo);
10597         goto LExit;
10598     }
10599
10600     if (g_profControlBlock.pProfInterface->GetTailcall2Hook() != NULL)
10601     {
10602         // We have run out of heap memory, so the content of the mapping table becomes stale.
10603         // All Whidbey ETL hooks must be turned off.
10604         if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10605         {
10606             goto LExit;
10607         }
10608
10609         // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes 
10610         // instead of using clientID because the profiler may map several functionIDs to a clientID to 
10611         // do things like code coverage analysis.  FunctionID to clientID has the one-on-one relationship, 
10612         // while the reverse may not have this one-on-one mapping.  Therefore, FunctionID is used as the 
10613         // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10614         FunctionID functionId = clientData;
10615         _ASSERTE(functionId != NULL);
10616         clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10617
10618         //
10619         // Whidbey Fast-Path ELT
10620         //
10621         if (CORProfilerELT2FastPathTailcallEnabled())
10622         {
10623             g_profControlBlock.pProfInterface->GetTailcall2Hook()(
10624                 functionId,
10625                 clientData, 
10626                 NULL);
10627             goto LExit;
10628         }
10629
10630         //
10631         // Whidbey Slow-Path ELT
10632         //
10633         COR_PRF_FRAME_INFO frameInfo = NULL;
10634
10635         HRESULT hr = ProfilingGetFunctionTailcall3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo);
10636         _ASSERTE(hr == S_OK);
10637
10638         g_profControlBlock.pProfInterface->GetTailcall2Hook()(functionId, clientData, frameInfo);
10639         goto LExit;
10640     }
10641
10642     // We will not be here unless the jit'd or ngen'd function we're about to tailcall
10643     // was backpatched with this wrapper around the profiler's hook, and that
10644     // wouldn't have happened unless the profiler supplied us with a hook
10645     // in the first place.  (Note that SetEnterLeaveFunctionHooks* will return
10646     // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10647     // its mind about where the hooks are.)
10648     _ASSERTE(g_profControlBlock.pProfInterface->GetTailcallHook() != NULL);
10649
10650     // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10651     // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10652     // to enable the jitter to add enter/leave callouts independently of whether
10653     // the profiler actually has enter/leave hooks.  (If the profiler has no such hooks,
10654     // the callouts quickly return and do nothing.)
10655     
10656     //
10657     // Everett ELT
10658     //
10659     g_profControlBlock.pProfInterface->GetTailcallHook()((FunctionID)clientData);
10660
10661 LExit:
10662
10663     ;
10664
10665     HELPER_METHOD_FRAME_END();      // Un-link the frame
10666
10667 #endif // PROFILING_SUPPORTED
10668 }
10669 HCIMPLEND
10670