f2387232a62fb6b6382406b52498c6bbd111b13a
[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     GCX_PREEMP();
6810     return ReJitManager::RequestReJIT(cFunctions, moduleIds, methodIds, static_cast<COR_PRF_REJIT_FLAGS>(dwRejitFlags));
6811 }
6812
6813 /*
6814  * EnumerateObjectReferences
6815  * 
6816  * Enumerates the object references (if any) from the ObjectID.
6817  * 
6818  * Parameters:
6819  *      objectId        - object id of interest
6820  *      callback        - callback to call for each object reference
6821  *      clientData      - client data for the profiler to pass and receive for each reference
6822  *
6823  * Returns:
6824  *   S_OK if successful, S_FALSE if no references
6825  *
6826  */
6827 HRESULT ProfToEEInterfaceImpl::EnumerateObjectReferences(ObjectID objectId, ObjectReferenceCallback callback, void* clientData)
6828 {
6829     CONTRACTL
6830     {
6831         NOTHROW;
6832         GC_NOTRIGGER;
6833         MODE_ANY;
6834         EE_THREAD_NOT_REQUIRED;
6835         CANNOT_TAKE_LOCK;
6836     }
6837     CONTRACTL_END;
6838
6839     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6840         kP2EEAllowableAfterAttach,
6841         (LF_CORPROF,
6842         LL_INFO1000,
6843         "**PROF: EnumerateObjectReferences 0x%p.\n",
6844         objectId));
6845
6846     if (callback == nullptr)
6847     {
6848         return E_INVALIDARG;
6849     }
6850
6851     Object* pBO = (Object*)objectId;
6852     MethodTable *pMT = pBO->GetMethodTable();
6853
6854     if (pMT->ContainsPointersOrCollectible())
6855     {
6856         GCHeapUtilities::GetGCHeap()->DiagWalkObject2(pBO, (walk_fn2)callback, clientData);
6857         return S_OK;
6858     }
6859     else
6860     {
6861         return S_FALSE;
6862     }
6863 }
6864
6865 /*
6866  * IsFrozenObject
6867  * 
6868  * Determines whether the object is in a read-only segment
6869  * 
6870  * Parameters:
6871  *      objectId        - object id of interest
6872  *
6873  * Returns:
6874  *   S_OK if successful
6875  *
6876  */
6877 HRESULT ProfToEEInterfaceImpl::IsFrozenObject(ObjectID objectId, BOOL *pbFrozen)
6878 {
6879     CONTRACTL
6880     {
6881         NOTHROW;
6882         GC_NOTRIGGER;
6883         MODE_ANY;
6884         EE_THREAD_NOT_REQUIRED;
6885         CANNOT_TAKE_LOCK;
6886     }
6887     CONTRACTL_END;
6888
6889     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6890         kP2EEAllowableAfterAttach,
6891         (LF_CORPROF,
6892         LL_INFO1000,
6893         "**PROF: IsFrozenObject 0x%p.\n",
6894         objectId));
6895
6896     *pbFrozen = GCHeapUtilities::GetGCHeap()->IsInFrozenSegment((Object*)objectId) ? TRUE : FALSE;
6897
6898     return S_OK;
6899 }
6900
6901 /*
6902  * GetLOHObjectSizeThreshold
6903  * 
6904  * Gets the value of the configured LOH Threshold.
6905  * 
6906  * Parameters:
6907  *      pThreshold        - value of the threshold in bytes
6908  *
6909  * Returns:
6910  *   S_OK if successful
6911  *
6912  */
6913 HRESULT ProfToEEInterfaceImpl::GetLOHObjectSizeThreshold(DWORD *pThreshold)
6914 {
6915     CONTRACTL
6916     {
6917         NOTHROW;
6918         GC_NOTRIGGER;
6919         MODE_ANY;
6920         EE_THREAD_NOT_REQUIRED;
6921         CANNOT_TAKE_LOCK;
6922     }
6923     CONTRACTL_END;
6924
6925     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6926         kP2EEAllowableAfterAttach,
6927         (LF_CORPROF,
6928         LL_INFO1000,
6929         "**PROF: GetLOHObjectSizeThreshold\n"));
6930
6931     if (pThreshold == nullptr)
6932     {
6933         return E_INVALIDARG;
6934     }
6935
6936     *pThreshold = g_pConfig->GetGCLOHThreshold();
6937
6938     return S_OK;
6939 }
6940
6941 HRESULT ProfToEEInterfaceImpl::SuspendRuntime()
6942 {
6943     CONTRACTL
6944     {
6945         NOTHROW;
6946         GC_TRIGGERS;
6947         MODE_ANY;
6948         CAN_TAKE_LOCK;
6949         EE_THREAD_NOT_REQUIRED;
6950     }
6951     CONTRACTL_END;
6952
6953     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6954         kP2EEAllowableAfterAttach | kP2EETriggers,
6955         (LF_CORPROF,
6956         LL_INFO1000,
6957         "**PROF: SuspendRuntime\n"));
6958
6959     if (!g_fEEStarted)
6960     {
6961         return CORPROF_E_RUNTIME_UNINITIALIZED;
6962     }
6963
6964     if (ThreadSuspend::SysIsSuspendInProgress() || (ThreadSuspend::GetSuspensionThread() != 0))
6965     {
6966         return CORPROF_E_SUSPENSION_IN_PROGRESS;
6967     }
6968     
6969     g_profControlBlock.fProfilerRequestedRuntimeSuspend = TRUE;
6970     ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_REASON::SUSPEND_FOR_PROFILER);
6971     return S_OK;
6972 }
6973
6974 HRESULT ProfToEEInterfaceImpl::ResumeRuntime()
6975 {
6976     CONTRACTL
6977     {
6978         NOTHROW;
6979         GC_TRIGGERS;
6980         MODE_ANY;
6981         CAN_TAKE_LOCK;
6982     }
6983     CONTRACTL_END;
6984
6985     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
6986         kP2EEAllowableAfterAttach | kP2EETriggers,
6987         (LF_CORPROF,
6988         LL_INFO1000,
6989         "**PROF: ResumeRuntime\n"));
6990     
6991     if (!g_fEEStarted)
6992     {
6993         return CORPROF_E_RUNTIME_UNINITIALIZED;
6994     }
6995
6996     if (!g_profControlBlock.fProfilerRequestedRuntimeSuspend)
6997     {
6998         return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
6999     }
7000
7001     ThreadSuspend::RestartEE(FALSE /* bFinishedGC */, TRUE /* SuspendSucceeded */);
7002     g_profControlBlock.fProfilerRequestedRuntimeSuspend = FALSE;
7003     return S_OK;
7004 }
7005
7006 /*
7007  * GetStringLayout
7008  *
7009  * This function describes to a profiler the internal layout of a string.
7010  *
7011  * Parameters:
7012  *   pBufferLengthOffset - Offset within an OBJECTREF of a string of the ArrayLength field.
7013  *   pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
7014  *   pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
7015  *
7016  * Returns:
7017  *   S_OK if successful.
7018  */
7019 HRESULT ProfToEEInterfaceImpl::GetStringLayout(ULONG *pBufferLengthOffset,
7020                                              ULONG *pStringLengthOffset,
7021                                              ULONG *pBufferOffset)
7022 {
7023     CONTRACTL
7024     {
7025         // Yay!
7026         NOTHROW;
7027
7028         // Yay!
7029         GC_NOTRIGGER;
7030
7031         // Yay!
7032         MODE_ANY;
7033
7034         // Yay!
7035         EE_THREAD_NOT_REQUIRED;
7036
7037         // Yay!
7038         CANNOT_TAKE_LOCK;
7039
7040
7041         PRECONDITION(CheckPointer(pBufferLengthOffset, NULL_OK));
7042         PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
7043         PRECONDITION(CheckPointer(pBufferOffset,  NULL_OK));
7044     }
7045     CONTRACTL_END;
7046
7047     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
7048         (LF_CORPROF, 
7049         LL_INFO1000, 
7050         "**PROF: GetStringLayout.\n"));
7051
7052     return this->GetStringLayoutHelper(pBufferLengthOffset, pStringLengthOffset, pBufferOffset);
7053 }
7054
7055 /*
7056  * GetStringLayout2
7057  *
7058  * This function describes to a profiler the internal layout of a string.
7059  *
7060  * Parameters:
7061  *   pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
7062  *   pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
7063  *
7064  * Returns:
7065  *   S_OK if successful.
7066  */
7067 HRESULT ProfToEEInterfaceImpl::GetStringLayout2(ULONG *pStringLengthOffset,
7068                                              ULONG *pBufferOffset)
7069 {
7070     CONTRACTL
7071     {
7072         // Yay!
7073         NOTHROW;
7074
7075         // Yay!
7076         GC_NOTRIGGER;
7077
7078         // Yay!
7079         MODE_ANY;
7080
7081         // Yay!
7082         EE_THREAD_NOT_REQUIRED;
7083
7084         // Yay!
7085         CANNOT_TAKE_LOCK;
7086
7087
7088         PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
7089         PRECONDITION(CheckPointer(pBufferOffset,  NULL_OK));
7090     }
7091     CONTRACTL_END;
7092
7093     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
7094         (LF_CORPROF, 
7095         LL_INFO1000, 
7096         "**PROF: GetStringLayout2.\n"));
7097
7098     ULONG dummyBufferLengthOffset;
7099     return this->GetStringLayoutHelper(&dummyBufferLengthOffset, pStringLengthOffset, pBufferOffset);
7100 }
7101
7102 /*
7103  * GetStringLayoutHelper
7104  *
7105  * This function describes to a profiler the internal layout of a string.
7106  *
7107  * Parameters:
7108  *   pBufferLengthOffset - Offset within an OBJECTREF of a string of the ArrayLength field.
7109  *   pStringLengthOffset - Offset within an OBJECTREF of a string of the StringLength field.
7110  *   pBufferOffset - Offset within an OBJECTREF of a string of the Buffer field.
7111  *
7112  * Returns:
7113  *   S_OK if successful.
7114  */
7115 HRESULT ProfToEEInterfaceImpl::GetStringLayoutHelper(ULONG *pBufferLengthOffset,
7116                                              ULONG *pStringLengthOffset,
7117                                              ULONG *pBufferOffset)
7118 {
7119     CONTRACTL
7120     {
7121         // Yay!
7122         NOTHROW;
7123
7124         // Yay!
7125         GC_NOTRIGGER;
7126
7127         // Yay!
7128         MODE_ANY;
7129
7130         // Yay!
7131         EE_THREAD_NOT_REQUIRED;
7132
7133         // Yay!
7134         CANNOT_TAKE_LOCK;
7135
7136
7137         PRECONDITION(CheckPointer(pBufferLengthOffset, NULL_OK));
7138         PRECONDITION(CheckPointer(pStringLengthOffset, NULL_OK));
7139         PRECONDITION(CheckPointer(pBufferOffset,  NULL_OK));
7140     }
7141     CONTRACTL_END;
7142
7143     // The String class no longer has a bufferLength field in it.
7144     // We are returning the offset of the stringLength because that is the closest we can get
7145     // This is most certainly a breaking change and a new method 
7146     // ICorProfilerInfo3::GetStringLayout2 has been added on the interface ICorProfilerInfo3
7147     if (pBufferLengthOffset != NULL)
7148     {
7149         *pBufferLengthOffset = StringObject::GetStringLengthOffset();
7150     }
7151
7152     if (pStringLengthOffset != NULL)
7153     {
7154         *pStringLengthOffset = StringObject::GetStringLengthOffset();
7155     }
7156
7157     if (pBufferOffset != NULL)
7158     {
7159         *pBufferOffset = StringObject::GetBufferOffset();
7160     }
7161
7162     return S_OK;
7163 }
7164
7165 /*
7166  * GetClassLayout
7167  *
7168  * This function describes to a profiler the internal layout of a class.
7169  *
7170  * Parameters:
7171  *   classID - The class that is being queried.  It is really a TypeHandle.
7172  *   rFieldOffset - An array to store information about each field in the class.
7173  *   cFieldOffset - Count of the number of elements in rFieldOffset.
7174  *   pcFieldOffset - Upon return contains the number of elements filled in, or if
7175  *         cFieldOffset is zero, the number of elements needed.
7176  *   pulClassSize - Optional parameter for containing the size in bytes of the underlying
7177  *         internal class structure.
7178  *
7179  * Returns:
7180  *   S_OK if successful.
7181  */
7182 HRESULT ProfToEEInterfaceImpl::GetClassLayout(ClassID classID,
7183                                              COR_FIELD_OFFSET rFieldOffset[],
7184                                              ULONG cFieldOffset,
7185                                              ULONG *pcFieldOffset,
7186                                              ULONG *pulClassSize)
7187 {
7188     CONTRACTL
7189     {
7190         // Yay!
7191         NOTHROW;
7192
7193         // Yay!
7194         GC_NOTRIGGER;
7195
7196         // Yay!
7197         MODE_ANY;
7198
7199         // Yay!
7200         EE_THREAD_NOT_REQUIRED;
7201
7202         // Yay!
7203         CANNOT_TAKE_LOCK;
7204
7205
7206         PRECONDITION(CheckPointer(rFieldOffset, NULL_OK));
7207         PRECONDITION(CheckPointer(pcFieldOffset));
7208         PRECONDITION(CheckPointer(pulClassSize,  NULL_OK));
7209     }
7210     CONTRACTL_END;
7211     
7212     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
7213         (LF_CORPROF, 
7214         LL_INFO1000, 
7215         "**PROF: GetClassLayout 0x%p.\n", 
7216         classID));
7217     
7218     //
7219     // Verify parameters
7220     //
7221     if ((pcFieldOffset == NULL) || (classID == NULL))
7222     {
7223          return E_INVALIDARG;
7224     }
7225
7226     if ((cFieldOffset != 0) && (rFieldOffset == NULL))
7227     {
7228         return E_INVALIDARG;
7229     }
7230
7231     TypeHandle typeHandle = TypeHandle::FromPtr((void *)classID);
7232
7233     //
7234     // This is the incorrect API for arrays or strings.  Use GetArrayObjectInfo, and GetStringLayout
7235     //
7236     if (typeHandle.IsTypeDesc() || typeHandle.AsMethodTable()->IsArray())
7237     {
7238         return E_INVALIDARG;
7239     }
7240
7241     //
7242     // We used to have a bug where this API incorrectly succeeded for strings during startup. Profilers
7243     // took dependency on this bug. Let the API to succeed for strings during startup for backward compatibility.
7244     //
7245     if (typeHandle.AsMethodTable()->IsString() && g_profControlBlock.fBaseSystemClassesLoaded)
7246     {
7247         return E_INVALIDARG;
7248     }
7249
7250     //
7251     // If this class is not fully restored, that is all the information we can get at this time.
7252     //
7253     if (!typeHandle.IsRestored())
7254     {
7255         return CORPROF_E_DATAINCOMPLETE;
7256     }
7257
7258     // Types can be pre-restored, but they still aren't expected to handle queries before
7259     // eager fixups have run. This is a targetted band-aid for a bug intellitrace was
7260     // running into - attempting to get the class layout for all types at module load time.
7261     // If we don't detect this the runtime will AV during the field iteration below. Feel
7262     // free to eliminate this check when a more complete solution is available.
7263     if (MethodTable::IsParentMethodTableTagged(typeHandle.AsMethodTable()))
7264     {
7265         return CORPROF_E_DATAINCOMPLETE;
7266     }
7267
7268     // !IsValueType = IsArray || IsReferenceType   Since IsArry has been ruled out above, it must 
7269     // be a reference type if !IsValueType.
7270     BOOL fReferenceType = !typeHandle.IsValueType();
7271
7272     //
7273     // Fill in class size now
7274     //
7275     // Move after the check for typeHandle.GetMethodTable()->IsRestored() 
7276     // because an unrestored MethodTable may have a bad EE class pointer
7277     // which will be used by MethodTable::GetNumInstanceFieldBytes
7278     //
7279     if (pulClassSize != NULL)
7280     {
7281         if (fReferenceType)
7282         {
7283             // aligned size including the object header for reference types
7284             *pulClassSize = typeHandle.GetMethodTable()->GetBaseSize();
7285         }
7286         else
7287         {
7288             // unboxed and unaligned size for value types
7289             *pulClassSize = typeHandle.GetMethodTable()->GetNumInstanceFieldBytes();
7290         }
7291     }
7292
7293     ApproxFieldDescIterator fieldDescIterator(typeHandle.GetMethodTable(), ApproxFieldDescIterator::INSTANCE_FIELDS);
7294
7295     ULONG cFields = fieldDescIterator.Count();
7296
7297     //
7298     // If they are looking to just get the count, return that.
7299     //
7300     if ((cFieldOffset == 0)  || (rFieldOffset == NULL))
7301     {
7302         *pcFieldOffset = cFields;
7303         return S_OK;
7304     }
7305
7306     //
7307     // Dont put too many in the array.
7308     //
7309     if (cFields > cFieldOffset)
7310     {
7311         cFields = cFieldOffset;
7312     }
7313
7314     *pcFieldOffset = cFields;
7315
7316     //
7317     // Now fill in the array
7318     //
7319     ULONG i;
7320     FieldDesc *pField;
7321
7322     for (i = 0; i < cFields; i++)
7323     {
7324         pField = fieldDescIterator.Next();
7325         rFieldOffset[i].ridOfField = (ULONG)pField->GetMemberDef();
7326         rFieldOffset[i].ulOffset = (ULONG)pField->GetOffset() + (fReferenceType ? Object::GetOffsetOfFirstField() : 0);
7327     }
7328
7329     return S_OK;
7330 }
7331
7332
7333 typedef struct _PROFILER_STACK_WALK_DATA
7334 {
7335     StackSnapshotCallback *callback;
7336     ULONG32 infoFlags;
7337     ULONG32 contextFlags;
7338     void *clientData;
7339     
7340 #ifdef WIN64EXCEPTIONS
7341     StackFrame sfParent;
7342 #endif
7343 } PROFILER_STACK_WALK_DATA;
7344
7345
7346 /*
7347  * ProfilerStackWalkCallback
7348  *
7349  * This routine is used as the callback from the general stack walker for
7350  * doing snapshot stack walks
7351  *
7352  */
7353 StackWalkAction ProfilerStackWalkCallback(CrawlFrame *pCf, PROFILER_STACK_WALK_DATA *pData)
7354 {
7355     CONTRACTL
7356     {
7357         NOTHROW;  // throw is RIGHT out... the throw at minimum allocates the thrown object which we *must* not do
7358         GC_NOTRIGGER; // the stack is not necessarily crawlable at this state !!!) we must not induce a GC 
7359     } 
7360     CONTRACTL_END;
7361
7362     MethodDesc *pFunc = pCf->GetFunction();
7363
7364     COR_PRF_FRAME_INFO_INTERNAL frameInfo;
7365     ULONG32 contextSize = 0;
7366     BYTE *context = NULL;
7367
7368     UINT_PTR currentIP = 0;
7369     REGDISPLAY *pRegDisplay = pCf->GetRegisterSet();
7370 #if defined(_TARGET_X86_)
7371     CONTEXT builtContext;
7372 #endif
7373
7374     //
7375     // For Unmanaged-to-managed transitions we get a NativeMarker back, which we want
7376     // to return to the profiler as the context seed if it wants to walk the unmanaged
7377     // stack frame, so we report the functionId as NULL to indicate this.
7378     //
7379     if (pCf->IsNativeMarker())
7380     {
7381         pFunc = NULL;
7382     }
7383
7384     //
7385     // Skip all Lightweight reflection/emit functions
7386     //
7387     if ((pFunc != NULL) && pFunc->IsNoMetadata())
7388     {
7389         return SWA_CONTINUE;
7390     }
7391
7392     //
7393     // If this is not a transition of any sort and not a managed
7394     // method, ignore it.
7395     //
7396     if (!pCf->IsNativeMarker() && !pCf->IsFrameless())
7397     {
7398         return SWA_CONTINUE;
7399     }
7400
7401     currentIP = (UINT_PTR)pRegDisplay->ControlPC;
7402
7403     frameInfo.size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
7404     frameInfo.version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
7405
7406     if (pFunc != NULL)
7407     {
7408         frameInfo.funcID = MethodDescToFunctionID(pFunc);
7409         frameInfo.extraArg = NULL;
7410     }
7411     else
7412     {
7413         frameInfo.funcID = NULL;
7414         frameInfo.extraArg = NULL;
7415     }
7416
7417     frameInfo.IP = currentIP;
7418     frameInfo.thisArg = NULL;
7419
7420     if (pData->infoFlags & COR_PRF_SNAPSHOT_REGISTER_CONTEXT)
7421     {
7422 #if defined(_TARGET_X86_)
7423         //
7424         // X86 stack walking does not keep the context up-to-date during the
7425         // walk.  Instead it keeps the REGDISPLAY up-to-date.  Thus, we need to
7426         // build a CONTEXT from the REGDISPLAY.
7427         //
7428
7429         memset(&builtContext, 0, sizeof(builtContext));
7430         builtContext.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL;
7431         CopyRegDisplay(pRegDisplay, NULL, &builtContext);
7432         context = (BYTE *)(&builtContext);
7433 #else
7434         context = (BYTE *)pRegDisplay->pCurrentContext;
7435 #endif
7436         contextSize = sizeof(CONTEXT);
7437     }
7438     
7439     // NOTE:  We are intentionally not setting any callback state flags here (i.e., not using
7440     // SetCallbackStateFlagsHolder), as we want the DSS callback to "inherit" the
7441     // same callback state that DSS has:  if DSS was called asynchronously, then consider
7442     // the DSS callback to be called asynchronously.
7443     if (pData->callback(frameInfo.funcID,
7444                         frameInfo.IP,
7445                         (COR_PRF_FRAME_INFO)&frameInfo,
7446                         contextSize,
7447                         context,
7448                         pData->clientData) == S_OK)
7449     {
7450         return SWA_CONTINUE;
7451     }
7452
7453     return SWA_ABORT;
7454 }
7455
7456 #ifdef _TARGET_X86_
7457
7458 //---------------------------------------------------------------------------------------
7459 // Normally, calling GetFunction() on the frame is sufficient to ensure
7460 // HelperMethodFrames are intialized. However, sometimes we need to be able to specify
7461 // that we should not enter the host while initializing, so we need to initialize such
7462 // frames more directly. This small helper function directly forces the initialization,
7463 // and ensures we don't enter the host as a result if we're executing in an asynchronous
7464 // call (i.e., hijacked thread)
7465 //
7466 // Arguments:
7467 //      pFrame - Frame to initialize.
7468 //
7469 // Return Value:
7470 //     TRUE iff pFrame was successfully initialized (or was already initialized). If
7471 //     pFrame is not a HelperMethodFrame (or derived type), this returns TRUE
7472 //     immediately. FALSE indicates we tried to initialize w/out entering the host, and
7473 //     had to abort as a result when a reader lock was needed but unavailable.
7474 //
7475
7476 static BOOL EnsureFrameInitialized(Frame * pFrame)
7477 {
7478     CONTRACTL
7479     {
7480         NOTHROW;
7481         GC_NOTRIGGER;
7482
7483         // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
7484         // host (SQL).  Corners will be cut to ensure this is the case
7485         if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
7486
7487         SUPPORTS_DAC;
7488     }
7489     CONTRACTL_END;
7490
7491     if (pFrame->GetFrameType() != Frame::TYPE_HELPER_METHOD_FRAME)
7492     {
7493         // This frame is not a HelperMethodFrame or a frame derived from
7494         // HelperMethodFrame, so HMF-specific lazy initialization is not an issue.
7495         return TRUE;
7496     }
7497
7498     HelperMethodFrame * pHMF = (HelperMethodFrame *) pFrame;
7499
7500     if (pHMF->InsureInit(
7501         false,                      // initialInit
7502         NULL,                       // unwindState
7503         (ShouldAvoidHostCalls() ?
7504             NoHostCalls :
7505             AllowHostCalls)
7506         ) != NULL)
7507     {
7508         // InsureInit() succeeded and found the return address
7509         return TRUE;
7510     }
7511
7512     // No return address was found. It must be because we asked InsureInit() to bail if
7513     // it would have entered the host
7514     _ASSERTE(ShouldAvoidHostCalls());
7515     return FALSE;
7516 }
7517
7518 //---------------------------------------------------------------------------------------
7519 //
7520 // Implements the COR_PRF_SNAPSHOT_X86_OPTIMIZED algorithm called by DoStackSnapshot. 
7521 // Does a simple EBP walk, rather than invoking all of StackWalkFramesEx.
7522 //
7523 // Arguments:
7524 //      pThreadToSnapshot - Thread whose stack should be walked
7525 //      pctxSeed - Register context with which to seed the walk
7526 //      callback - Function to call at each frame found during the walk
7527 //      clientData - Parameter to pass through to callback
7528 //
7529 // Return Value:
7530 //     HRESULT indicating success or failure.
7531 //
7532
7533 HRESULT ProfToEEInterfaceImpl::ProfilerEbpWalker(
7534     Thread * pThreadToSnapshot, 
7535     LPCONTEXT pctxSeed, 
7536     StackSnapshotCallback * callback, 
7537     void * clientData)
7538 {
7539     CONTRACTL
7540     {
7541         GC_NOTRIGGER;
7542         NOTHROW;
7543         MODE_ANY;
7544         EE_THREAD_NOT_REQUIRED;
7545
7546         // If this is called asynchronously (from a hijacked thread, as with F1), it must not re-enter the
7547         // host (SQL).  Corners will be cut to ensure this is the case
7548         if (ShouldAvoidHostCalls()) { HOST_NOCALLS; } else { HOST_CALLS; }
7549     }
7550     CONTRACTL_END;
7551
7552     HRESULT hr;
7553
7554     // We haven't set the stackwalker thread type flag yet (see next line), so it shouldn't be set. Only
7555     // exception to this is if the current call is made by a hijacking profiler which
7556     // redirected this thread while it was previously in the middle of another stack walk
7557     _ASSERTE(IsCalledAsynchronously() || !IsStackWalkerThread());
7558
7559     // Remember that we're walking the stack.  This holder will reinstate the original
7560     // value of the stackwalker flag (from the thread type mask) in its destructor.
7561     ClrFlsValueSwitch _threadStackWalking(TlsIdx_StackWalkerWalkingThread, pThreadToSnapshot);
7562    
7563     // This flag remembers if we reported a managed frame since the last unmanaged block
7564     // we reported. It's used to avoid reporting two unmanaged blocks in a row.
7565     BOOL fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = FALSE;
7566
7567     Frame * pFrameCur = pThreadToSnapshot->GetFrame();
7568
7569     CONTEXT ctxCur;
7570     ZeroMemory(&ctxCur, sizeof(ctxCur));
7571
7572     // Use seed if we got one.  Otherwise, EE explicit Frame chain will seed the walk.
7573     if (pctxSeed != NULL)
7574     {
7575         ctxCur.Ebp = pctxSeed->Ebp;
7576         ctxCur.Eip = pctxSeed->Eip;
7577         ctxCur.Esp = pctxSeed->Esp;
7578     }
7579
7580     while (TRUE)
7581     {
7582         // At each iteration of the loop:
7583         //     * Analyze current frame (get managed data if it's a managed frame)
7584         //     * Report current frame via callback()
7585         //     * Walk down to next frame
7586         
7587         // **** Managed or unmanaged frame? ****
7588         
7589         EECodeInfo codeInfo;
7590         MethodDesc * pMethodDescCur = NULL;
7591
7592         if (ctxCur.Eip != 0)
7593         {
7594             hr = GetFunctionInfoInternal(
7595                 (LPCBYTE) ctxCur.Eip, 
7596                 &codeInfo);
7597             if (hr == CORPROF_E_ASYNCHRONOUS_UNSAFE)
7598             {
7599                 _ASSERTE(ShouldAvoidHostCalls());
7600                 return hr;
7601             }
7602             if (SUCCEEDED(hr))
7603             {
7604                 pMethodDescCur = codeInfo.GetMethodDesc();
7605             }
7606         }
7607
7608         // **** Report frame to profiler ****
7609
7610         if (
7611             // Make sure the frame gave us an IP
7612             (ctxCur.Eip != 0) &&              
7613
7614             // Make sure any managed frame isn't for an IL stub or LCG
7615             ((pMethodDescCur == NULL) || !pMethodDescCur->IsNoMetadata()) &&
7616
7617             // Only report unmanaged frames if the last frame we reported was managed
7618             // (avoid reporting two unmanaged blocks in a row)
7619             ((pMethodDescCur != NULL) || fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock))
7620         {
7621             // Around the call to the profiler, temporarily clear the
7622             // ThreadType_StackWalker type flag, as we have no control over what the
7623             // profiler may do inside its callback (it could theoretically attempt to
7624             // load other types, though I don't personally know of profilers that
7625             // currently do this).
7626             
7627             CLEAR_THREAD_TYPE_STACKWALKER();
7628             hr = callback(
7629                 (FunctionID) pMethodDescCur, 
7630                 ctxCur.Eip, 
7631                 NULL,               // COR_PRF_FRAME_INFO
7632                 sizeof(ctxCur),     // contextSize,
7633                 (LPBYTE) &ctxCur,   // context,
7634                 clientData);
7635             SET_THREAD_TYPE_STACKWALKER(pThreadToSnapshot);
7636             
7637             if (hr != S_OK)
7638             {
7639                 return hr;
7640             }
7641             if (pMethodDescCur == NULL)
7642             {
7643                 // Just reported an unmanaged block, so reset the flag
7644                 fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = FALSE;
7645             }
7646             else
7647             {
7648                 // Just reported a managed block, so remember it
7649                 fReportedAtLeastOneManagedFrameSinceLastUnmanagedBlock = TRUE;
7650             }
7651         }
7652
7653         // **** Walk down to next frame ****
7654
7655         // Is current frame managed or unmanaged?
7656         if (pMethodDescCur == NULL)
7657         {
7658             // Unmanaged frame.  Use explicit EE Frame chain to help
7659
7660             REGDISPLAY frameRD;
7661             ZeroMemory(&frameRD, sizeof(frameRD));
7662
7663             while (pFrameCur != FRAME_TOP)
7664             {
7665                 // Frame is only useful if it will contain register context info
7666                 if (!pFrameCur->NeedsUpdateRegDisplay())
7667                 {
7668                     goto Loop;
7669                 }
7670
7671
7672                 // This should be the first call we make to the Frame, as it will
7673                 // ensure we force lazy initialize of HelperMethodFrames
7674                 if (!EnsureFrameInitialized(pFrameCur))
7675                 {
7676                     return CORPROF_E_ASYNCHRONOUS_UNSAFE;
7677                 }
7678                     
7679                 // This frame is only useful if it gives us an actual return address,
7680                 // and is situated on the stack at or below our current ESP (stack
7681                 // grows up)
7682                 if ((pFrameCur->GetReturnAddress() != NULL) &&
7683                     (dac_cast<TADDR>(pFrameCur) >= dac_cast<TADDR>(ctxCur.Esp)))
7684                 {
7685                     pFrameCur->UpdateRegDisplay(&frameRD);
7686                     break;
7687                 }
7688
7689 Loop:
7690                 pFrameCur = pFrameCur->PtrNextFrame();
7691             }
7692
7693             if (pFrameCur == FRAME_TOP)
7694             {
7695                 // No more frames.  Stackwalk is over
7696                 return S_OK;
7697             }
7698
7699             // Update ctxCur based on frame
7700             ctxCur.Eip = pFrameCur->GetReturnAddress();
7701             ctxCur.Ebp = GetRegdisplayFP(&frameRD);
7702             ctxCur.Esp = GetRegdisplaySP(&frameRD);
7703         }
7704         else
7705         {
7706             // Managed frame.
7707
7708             // GC info will assist us in determining whether this is a non-EBP frame and
7709             // info about pushed arguments.
7710             GCInfoToken gcInfoToken = codeInfo.GetGCInfoToken();
7711             PTR_VOID gcInfo = gcInfoToken.Info;
7712             InfoHdr header;
7713             unsigned uiMethodSizeDummy;
7714             PTR_CBYTE table = PTR_CBYTE(gcInfo);
7715             table += decodeUnsigned(table, &uiMethodSizeDummy);
7716             table = decodeHeader(table, gcInfoToken.Version, &header);
7717
7718             // Ok, GCInfo, can we do a simple EBP walk or what?
7719
7720             if ((codeInfo.GetRelOffset() < header.prologSize) || 
7721                 (!header.ebpFrame && !header.doubleAlign))
7722             {
7723                 // We're either in the prolog or we're not in an EBP frame, in which case
7724                 // we'll just defer to the code manager to unwind for us. This condition
7725                 // is relatively rare, but can occur if:
7726                 // 
7727                 //     * The profiler did a DSS from its Enter hook, in which case we're
7728                 //         still inside the prolog, OR
7729                 //     * The seed context or explicit EE Frame chain seeded us with a
7730                 //         non-EBP frame function. In this case, using a naive EBP
7731                 //         unwinding algorithm would actually skip over the next EBP
7732                 //         frame, and would get SP all wrong as we try skipping over
7733                 //         the pushed parameters. So let's just ask the code manager for
7734                 //         help.
7735                 // 
7736                 // Note that there are yet more conditions (much more rare) where the EBP
7737                 // walk could get lost (e.g., we're inside an epilog). But we only care
7738                 // about the most likely cases, and it's ok if the unlikely cases result
7739                 // in truncated stacks, as unlikely cases will be statistically
7740                 // irrelevant to CPU performance sampling profilers
7741                 CodeManState codeManState;
7742                 codeManState.dwIsSet = 0;
7743                 REGDISPLAY rd;
7744                 ZeroMemory(&rd, sizeof(rd));
7745
7746                 rd.SetEbpLocation(&ctxCur.Ebp);
7747                 rd.SP = ctxCur.Esp;
7748                 rd.ControlPC = ctxCur.Eip;
7749
7750                 codeInfo.GetCodeManager()->UnwindStackFrame(
7751                     &rd, 
7752                     &codeInfo, 
7753                     SpeculativeStackwalk, 
7754                     &codeManState, 
7755                     NULL);
7756
7757                 ctxCur.Ebp = *rd.GetEbpLocation();
7758                 ctxCur.Esp = rd.SP;
7759                 ctxCur.Eip = rd.ControlPC;
7760             }
7761             else
7762             {
7763                 // We're in an actual EBP frame, so we can simplistically walk down to
7764                 // the next frame using EBP.
7765                 
7766                 // Return address is stored just below saved EBP (stack grows up)
7767                 ctxCur.Eip = *(DWORD *) (ctxCur.Ebp + sizeof(DWORD));
7768                 
7769                 ctxCur.Esp = 
7770                     // Stack location where current function pushed its EBP
7771                     ctxCur.Ebp +
7772
7773                     // Skip past that EBP
7774                     sizeof(DWORD) +
7775                     
7776                     // Skip past return address pushed by caller
7777                     sizeof(DWORD) + 
7778                     
7779                     // Skip past arguments to current function that were pushed by caller. 
7780                     // (Caller will pop varargs, so don't count those.)
7781                     (header.varargs ? 0 : (header.argCount * sizeof(DWORD)));
7782
7783                 // EBP for frame below us (stack grows up) has been saved onto our own
7784                 // frame. Dereference it now.
7785                 ctxCur.Ebp = *(DWORD *) ctxCur.Ebp;
7786             }
7787         }
7788     }
7789 }
7790 #endif // _TARGET_X86_
7791
7792 //*****************************************************************************
7793 //  The profiler stackwalk Wrapper
7794 //*****************************************************************************
7795 HRESULT ProfToEEInterfaceImpl::ProfilerStackWalkFramesWrapper(Thread * pThreadToSnapshot, PROFILER_STACK_WALK_DATA * pData, unsigned flags)
7796 {
7797     STATIC_CONTRACT_WRAPPER;
7798
7799     StackWalkAction swaRet = pThreadToSnapshot->StackWalkFrames(
7800         (PSTACKWALKFRAMESCALLBACK)ProfilerStackWalkCallback,
7801          pData,
7802          flags,
7803          NULL);
7804
7805     switch (swaRet)
7806     {
7807     default:
7808         _ASSERTE(!"Unexpected StackWalkAction returned from Thread::StackWalkFrames");
7809         return E_FAIL;
7810         
7811     case SWA_FAILED:
7812         return E_FAIL;
7813         
7814     case SWA_ABORT:
7815         return CORPROF_E_STACKSNAPSHOT_ABORTED;
7816
7817     case SWA_DONE:
7818         return S_OK;
7819     }
7820 }
7821
7822 //---------------------------------------------------------------------------------------
7823 //
7824 // DoStackSnapshot helper to call FindJitMan to determine if the specified
7825 // context is in managed code.
7826 //
7827 // Arguments:
7828 //      pCtx - Context to look at
7829 //      hostCallPreference - Describes how to acquire the reader lock--either AllowHostCalls
7830 //          or NoHostCalls (see code:HostCallPreference).
7831 //
7832 // Return Value:
7833 //      S_OK: The context is in managed code
7834 //      S_FALSE: The context is not in managed code.
7835 //      Error: Unable to determine (typically because hostCallPreference was NoHostCalls
7836 //         and the reader lock was unattainable without yielding)
7837 //
7838
7839 HRESULT IsContextInManagedCode(const CONTEXT * pCtx, HostCallPreference hostCallPreference)
7840 {
7841     WRAPPER_NO_CONTRACT;
7842     BOOL fFailedReaderLock = FALSE;
7843
7844     // if there's no Jit Manager for the IP, it's not managed code.
7845     BOOL fIsManagedCode = ExecutionManager::IsManagedCode(GetIP(pCtx), hostCallPreference, &fFailedReaderLock);
7846     if (fFailedReaderLock)
7847     {
7848         return CORPROF_E_ASYNCHRONOUS_UNSAFE;
7849     }
7850     
7851     return fIsManagedCode ? S_OK : S_FALSE;
7852 }
7853
7854 //*****************************************************************************
7855 // Perform a stack walk, calling back to callback at each managed frame.
7856 //*****************************************************************************
7857 HRESULT ProfToEEInterfaceImpl::DoStackSnapshot(ThreadID thread,
7858                                               StackSnapshotCallback *callback,
7859                                               ULONG32 infoFlags,
7860                                               void *clientData,
7861                                                BYTE * pbContext,
7862                                               ULONG32 contextSize)
7863 {
7864     CONTRACTL
7865     {
7866         // Yay!  (Note: NOTHROW is vital.  The throw at minimum allocates
7867         // the thrown object which we *must* not do.)
7868         NOTHROW;
7869
7870         // Yay!  (Note: this is called asynchronously to view the stack at arbitrary times,
7871         // so the stack is not necessarily crawlable for GC at this state!)
7872         GC_NOTRIGGER;
7873
7874         // Yay!
7875         MODE_ANY;
7876
7877         // Yay!
7878         EE_THREAD_NOT_REQUIRED;
7879
7880         // #DisableLockOnAsyncCalls
7881         // This call is allowed asynchronously, however it does take locks.  Therefore,
7882         // we will hit contract asserts if we happen to be in a CANNOT_TAKE_LOCK zone when
7883         // a hijacking profiler hijacks this thread to run DoStackSnapshot.  CANNOT_RETAKE_LOCK
7884         // is a more granular locking contract that says "I promise that if I take locks, I 
7885         // won't reenter any locks that were taken before this function was called".  
7886         DISABLED(CAN_TAKE_LOCK);
7887
7888         // Asynchronous functions can be called at arbitrary times when runtime 
7889         // is holding locks that cannot be reentered without causing deadlock.
7890         // This contract detects any attempts to reenter locks held at the time 
7891         // this function was called.  
7892         CANNOT_RETAKE_LOCK;
7893
7894     }
7895     CONTRACTL_END;
7896
7897     // This CONTRACT_VIOLATION is still needed because DISABLED(CAN_TAKE_LOCK) does not 
7898     // turn off contract violations.
7899     PERMANENT_CONTRACT_VIOLATION(TakesLockViolation, ReasonProfilerAsyncCannotRetakeLock);
7900
7901     LPCONTEXT pctxSeed = reinterpret_cast<LPCONTEXT> (pbContext);
7902
7903     PROFILER_TO_CLR_ENTRYPOINT_ASYNC_EX(kP2EEAllowableAfterAttach,
7904         (LF_CORPROF, 
7905         LL_INFO1000, 
7906         "**PROF: DoStackSnapshot 0x%p, 0x%p, 0x%08x, 0x%p, 0x%p, 0x%08x.\n", 
7907         thread, 
7908         callback, 
7909         infoFlags, 
7910         clientData, 
7911         pctxSeed, 
7912         contextSize));
7913    
7914     HRESULT hr = E_UNEXPECTED;
7915     // (hr assignment is to appease the compiler; we won't actually return without explicitly setting hr again)
7916     
7917     Thread *pThreadToSnapshot = NULL;
7918     Thread * pCurrentThread = GetThreadNULLOk();
7919     BOOL fResumeThread = FALSE;
7920     INDEBUG(ULONG ulForbidTypeLoad = 0;)
7921     BOOL fResetSnapshotThreadExternalCount = FALSE;
7922     int cRefsSnapshotThread = 0;
7923     
7924     // Remember whether we've already determined the current context of the target thread
7925     // is in managed (S_OK), not in managed (S_FALSE), or unknown (error).
7926     HRESULT hrCurrentContextIsManaged = E_FAIL;
7927
7928     CONTEXT ctxCurrent;
7929     memset(&ctxCurrent, 0, sizeof(ctxCurrent));
7930
7931     REGDISPLAY rd;
7932
7933     PROFILER_STACK_WALK_DATA data;
7934
7935     if (!g_fEEStarted )
7936     {
7937         // no managed code has run and things are likely in a very bad have loaded state
7938         // this is a bad time to try to walk the stack
7939         
7940         // Returning directly as there is nothing to cleanup yet
7941         return CORPROF_E_STACKSNAPSHOT_UNSAFE;
7942     }
7943
7944     if (!CORProfilerStackSnapshotEnabled())
7945     {
7946         // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7947         return CORPROF_E_INCONSISTENT_WITH_FLAGS;
7948     }
7949
7950     if (thread == NULL)
7951     {
7952         pThreadToSnapshot = pCurrentThread;
7953     }
7954     else
7955     {
7956         pThreadToSnapshot = (Thread *)thread;
7957     }
7958
7959 #ifdef _TARGET_X86_
7960     if ((infoFlags & ~(COR_PRF_SNAPSHOT_REGISTER_CONTEXT | COR_PRF_SNAPSHOT_X86_OPTIMIZED)) != 0)
7961 #else
7962     if ((infoFlags & ~(COR_PRF_SNAPSHOT_REGISTER_CONTEXT)) != 0)
7963 #endif
7964     {
7965         // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7966         return E_INVALIDARG;
7967     }
7968
7969     if (!IsManagedThread(pThreadToSnapshot) || !IsGarbageCollectorFullyInitialized())
7970     {
7971         //
7972         // No managed frames, return now.
7973         //
7974         // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7975         return S_OK;
7976     }
7977
7978     // We must make sure no other thread tries to hijack the thread we're about to walk
7979     // Hijacking means Thread::HijackThread, i.e. bashing return addresses which would break the stack walk
7980     Thread::HijackLockHolder hijackLockHolder(pThreadToSnapshot);
7981     if (!hijackLockHolder.Acquired())
7982     {
7983         // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
7984         return CORPROF_E_STACKSNAPSHOT_UNSAFE;
7985     }
7986
7987     if (pThreadToSnapshot != pCurrentThread         // Walking separate thread
7988         && pCurrentThread != NULL                         // Walker (current) thread is a managed / VM thread
7989         && ThreadSuspend::SysIsSuspendInProgress())          // EE is trying suspend itself
7990     {
7991         // Since we're walking a separate thread, we'd have to suspend it first (see below).
7992         // And since the current thread is a VM thread, that means the current thread's
7993         // m_dwForbidSuspendThread count will go up while it's trying to suspend the
7994         // target thread (see Thread::SuspendThread).  THAT means no one will be able
7995         // to suspend the current thread until its m_dwForbidSuspendThread is decremented
7996         // (which happens as soon as the target thread of DoStackSnapshot has been suspended).
7997         // Since we're in the process of suspending the entire runtime, now would be a bad time to
7998         // make the walker thread un-suspendable (see VsWhidbey bug 454936).  So let's just abort
7999         // now.  Note that there is no synchronization around calling Thread::SysIsSuspendInProgress().
8000         // So we will get occasional false positives or false negatives.  But that's benign, as the worst
8001         // that might happen is we might occasionally delay the EE suspension a little bit, or we might
8002         // too eagerly fail from ProfToEEInterfaceImpl::DoStackSnapshot sometimes.  But there won't
8003         // be any corruption or AV.  
8004         //
8005         // Returning directly as there is nothing to cleanup yet, and can't skip gcholder ctor
8006         return CORPROF_E_STACKSNAPSHOT_UNSAFE;
8007     }
8008
8009     // We only allow stackwalking if:
8010     // 1) Target thread to walk == current thread OR Target thread is suspended, AND
8011     // 2) Target thread to walk is currently executing JITted / NGENd code, AND
8012     // 3) Target thread to walk is seeded OR currently NOT unwinding the stack, AND
8013     // 4) Target thread to walk != current thread OR current thread is NOT in a can't stop or forbid suspend region
8014
8015     // If the thread is in a forbid suspend region, it's dangerous to do anything:
8016     // - The code manager datastructures accessed during the stackwalk may be in inconsistent state.
8017     // - Thread::Suspend won't be able to suspend the thread.
8018     if (pThreadToSnapshot->IsInForbidSuspendRegion())
8019     {
8020         hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8021         goto Cleanup;
8022     }
8023
8024     HostCallPreference hostCallPreference;
8025     
8026     // First, check "1) Target thread to walk == current thread OR Target thread is suspended"
8027     if (pThreadToSnapshot != pCurrentThread && !g_profControlBlock.fProfilerRequestedRuntimeSuspend)
8028     {
8029 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8030         hr = E_NOTIMPL;
8031         goto Cleanup;
8032 #else
8033         // Walking separate thread, so it must be suspended.  First, ensure that
8034         // target thread exists.
8035         //
8036         // NOTE: We're using the "dangerous" variant of this refcount function, because we
8037         // rely on the profiler to ensure it never tries to walk a thread being destroyed.
8038         // (Profiler must block in its ThreadDestroyed() callback until all uses of that thread,
8039         // such as walking its stack, are complete.)
8040         cRefsSnapshotThread = pThreadToSnapshot->IncExternalCountDANGEROUSProfilerOnly();
8041         fResetSnapshotThreadExternalCount = TRUE;
8042
8043         if (cRefsSnapshotThread == 1 || !pThreadToSnapshot->HasValidThreadHandle())
8044         {
8045             // At this point, we've modified the VM state based on bad input
8046             // (pThreadToSnapshot) from the profiler.  This could cause
8047             // memory corruption and leave us vulnerable to security problems.
8048             // So destroy the process.
8049             _ASSERTE(!"Profiler trying to walk destroyed thread");
8050             EEPOLICY_HANDLE_FATAL_ERROR(CORPROF_E_STACKSNAPSHOT_INVALID_TGT_THREAD);
8051         }
8052
8053         // Thread::SuspendThread() ensures that no one else should try to suspend us
8054         // while we're suspending pThreadToSnapshot.
8055         //
8056         // TRUE: OneTryOnly.  Don't loop waiting for others to get out of our way in
8057         // order to suspend the thread.  If it's not safe, just return an error immediately.
8058         Thread::SuspendThreadResult str = pThreadToSnapshot->SuspendThread(TRUE);
8059         if (str == Thread::STR_Success)
8060         {
8061             fResumeThread = TRUE;
8062         }
8063         else
8064         {
8065             hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8066             goto Cleanup;            
8067         }
8068 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8069     }
8070
8071     hostCallPreference =
8072         ShouldAvoidHostCalls() ?
8073             NoHostCalls :       // Async call: Ensure this thread won't yield & re-enter host
8074             AllowHostCalls;     // Synchronous calls may re-enter host just fine
8075
8076     // If target thread is in pre-emptive mode, the profiler's seed context is unnecessary
8077     // because our frame chain is good enough: it will give us at least as accurate a
8078     // starting point as the profiler could.  Also, since profiler contexts cannot be
8079     // trusted, we don't want to set the thread's profiler filter context to this, as a GC
8080     // that interrupts the profiler's stackwalk will end up using the profiler's (potentially
8081     // bogus) filter context.
8082     if (!pThreadToSnapshot->PreemptiveGCDisabledOther())
8083     {
8084         // Thread to be walked is in preemptive mode.  Throw out seed.
8085         pctxSeed = NULL;
8086     }
8087     else if (pThreadToSnapshot != pCurrentThread)
8088     {
8089     // With cross-thread stack-walks, the target thread's context could be unreliable.
8090     // That would shed doubt on either a profiler-provided context, or a default
8091     // context we chose.  So check if we're in a potentially unreliable case, and return
8092     // an error if so.
8093     // 
8094     // These heurisitics are based on an actual bug where GetThreadContext returned a
8095     // self-consistent, but stale, context for a thread suspended after being redirected by
8096     // the GC (TFS Dev 10 bug # 733263).
8097         //
8098         // (Note that this whole block is skipped if pThreadToSnapshot is in preemptive mode (the IF
8099         // above), as the context is unused in such a case--the EE Frame chain is used
8100         // to seed the walk instead.)
8101 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8102         hr = E_NOTIMPL;
8103         goto Cleanup;
8104 #else
8105         if (!pThreadToSnapshot->GetSafelyRedirectableThreadContext(Thread::kDefaultChecks, &ctxCurrent, &rd))
8106         {
8107             LOG((LF_CORPROF, LL_INFO100, "**PROF: GetSafelyRedirectableThreadContext failure leads to CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
8108             hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8109             goto Cleanup;
8110         }
8111
8112         hrCurrentContextIsManaged = IsContextInManagedCode(&ctxCurrent, hostCallPreference);
8113         if (FAILED(hrCurrentContextIsManaged))
8114         {
8115             // Couldn't get the info.  Try again later
8116             _ASSERTE(ShouldAvoidHostCalls());
8117             hr = CORPROF_E_ASYNCHRONOUS_UNSAFE;
8118             goto Cleanup;
8119         }
8120
8121         if ((hrCurrentContextIsManaged == S_OK) &&
8122             (!pThreadToSnapshot->PreemptiveGCDisabledOther()))
8123         {
8124             // Thread is in preemptive mode while executing managed code?!  This lie is
8125             // an early warning sign that the context is bogus.  Bail.
8126             LOG((LF_CORPROF, LL_INFO100, "**PROF: Target thread context is likely bogus.  Returning CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
8127             hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8128             goto Cleanup;
8129         }
8130
8131         Frame * pFrame = pThreadToSnapshot->GetFrame();
8132         if (pFrame != FRAME_TOP)
8133         {
8134             TADDR spTargetThread = GetSP(&ctxCurrent);
8135             if (dac_cast<TADDR>(pFrame) < spTargetThread)
8136             {
8137                 // An Explicit EE Frame is more recent on the stack than the current
8138                 // stack pointer itself?  This lie is an early warning sign that the
8139                 // context is bogus. Bail.
8140                 LOG((LF_CORPROF, LL_INFO100, "**PROF: Target thread context is likely bogus.  Returning CORPROF_E_STACKSNAPSHOT_UNSAFE.\n"));
8141                 hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8142                 goto Cleanup;
8143             }
8144         }
8145
8146         // If the profiler did not specify a seed context of its own, use the current one we
8147         // just produced.
8148         //            
8149         // Failing to seed the walk can cause us to to "miss" functions on the stack.  This is
8150         // because StackWalkFrames(), when doing an unseeded stackwalk, sets the
8151         // starting regdisplay's IP/SP to 0.  This, in turn causes StackWalkFramesEx
8152         // to set cf.isFrameless = (pEEJM != NULL); (which is FALSE, since we have no
8153         // jit manager, since we have no IP).  Once frameless is false, we look solely to
8154         // the Frame chain for our goodies, rather than looking at the code actually
8155         // being executed by the thread.  The problem with the frame chain is that some
8156         // frames (e.g., GCFrame) don't point to any functions being executed.  So
8157         // StackWalkFramesEx just skips such frames and moves to the next one.  That
8158         // can cause a chunk of calls to be skipped.  To prevent this from happening, we
8159         // "fake" a seed by just seeding the thread with its current context.  This forces
8160         // StackWalkFramesEx() to look at the IP rather than just the frame chain.
8161         if (pctxSeed == NULL)
8162         {
8163             pctxSeed = &ctxCurrent;
8164         }
8165 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8166     }
8167
8168     // Second, check "2) Target thread to walk is currently executing JITted / NGENd code"
8169     // To do this, we need to find the proper context to investigate.  Start with
8170     // the seeded context, if available.  If not, use the target thread's current context.
8171     if (pctxSeed != NULL)
8172     {
8173         BOOL fSeedIsManaged;
8174
8175         // Short cut: If we're just using the current context as the seed, we may
8176         // already have determined whether it's in managed code.  If so, just use that
8177         // result rather than calculating it again
8178         if ((pctxSeed == &ctxCurrent) && SUCCEEDED(hrCurrentContextIsManaged))
8179         {
8180             fSeedIsManaged = (hrCurrentContextIsManaged == S_OK);
8181         }
8182         else
8183         {
8184             hr = IsContextInManagedCode(pctxSeed, hostCallPreference);
8185             if (FAILED(hr))
8186             {
8187                 hr = CORPROF_E_ASYNCHRONOUS_UNSAFE;
8188                 goto Cleanup;
8189             }
8190             fSeedIsManaged = (hr == S_OK);
8191         }
8192
8193         if (!fSeedIsManaged)
8194         {
8195             hr = CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX;
8196             goto Cleanup;
8197         }
8198     }
8199
8200 #ifdef _DEBUG
8201     //
8202     // Sanity check: If we are doing a cross-thread walk and there is no seed context, then
8203     // we better not be in managed code, otw we do not have a Frame on the stack from which to start
8204     // walking and we may miss the leaf-most chain of managed calls due to the way StackWalkFrames 
8205     // is implemented.  However, there is an exception when the leaf-most EE frame of pThreadToSnapshot
8206     // is an InlinedCallFrame, which has an active call, implying pThreadToShanpshot is inside an 
8207     // inlined P/Invoke.  In this case, the InlinedCallFrame will be used to help start off our
8208     // stackwalk at the top of the stack.
8209     //
8210     if (pThreadToSnapshot != pCurrentThread && !g_profControlBlock.fProfilerRequestedRuntimeSuspend)
8211     {
8212 #ifndef PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8213         hr = E_NOTIMPL;
8214         goto Cleanup;
8215 #else
8216         if (pctxSeed == NULL)
8217         {
8218             if (pThreadToSnapshot->GetSafelyRedirectableThreadContext(Thread::kDefaultChecks, &ctxCurrent, &rd))
8219             {
8220                 BOOL fFailedReaderLock = FALSE;
8221                 BOOL fIsManagedCode = ExecutionManager::IsManagedCode(GetIP(&ctxCurrent), hostCallPreference, &fFailedReaderLock);
8222
8223                 if (!fFailedReaderLock)
8224                 {
8225                     // not in jitted or ngend code or inside an inlined P/Invoke (the leaf-most EE Frame is
8226                     // an InlinedCallFrame with an active call)
8227                     _ASSERTE(!fIsManagedCode ||
8228                              (InlinedCallFrame::FrameHasActiveCall(pThreadToSnapshot->GetFrame())));
8229                 }
8230             }
8231         }
8232 #endif // !PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8233     }
8234 #endif //_DEBUG
8235     // Third, verify the target thread is seeded or not in the midst of an unwind.
8236     if (pctxSeed == NULL)
8237     {
8238         ThreadExceptionState* pExState = pThreadToSnapshot->GetExceptionState();
8239
8240         // this tests to see if there is an exception in flight
8241         if (pExState->IsExceptionInProgress() && pExState->GetFlags()->UnwindHasStarted())
8242         {
8243             EHClauseInfo *pCurrentEHClauseInfo = pThreadToSnapshot->GetExceptionState()->GetCurrentEHClauseInfo();
8244
8245             // if the exception code is telling us that we have entered a managed context then all is well
8246             if (!pCurrentEHClauseInfo->IsManagedCodeEntered())
8247             {
8248                 hr = CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX;
8249                 goto Cleanup;
8250             }
8251         }
8252     }
8253
8254     // Check if the exception state is consistent.  See the comment for ThreadExceptionFlag for more information. 
8255     if (pThreadToSnapshot->GetExceptionState()->HasThreadExceptionFlag(ThreadExceptionState::TEF_InconsistentExceptionState))
8256     {
8257         hr = CORPROF_E_STACKSNAPSHOT_UNSAFE;
8258         goto Cleanup;
8259     }
8260
8261     data.callback = callback;
8262     data.infoFlags = infoFlags;
8263     data.contextFlags = 0;
8264     data.clientData = clientData;
8265 #ifdef WIN64EXCEPTIONS
8266     data.sfParent.Clear();
8267 #endif
8268
8269     // workaround: The ForbidTypeLoad book keeping in the stackwalker is not robust against exceptions.
8270     // Unfortunately, it is hard to get it right in the stackwalker since it has to be exception 
8271     // handling free (frame unwinding may never return). We restore the ForbidTypeLoad counter here
8272     // in case it got messed up by exception thrown during the stackwalk.
8273     INDEBUG(if (pCurrentThread) ulForbidTypeLoad = pCurrentThread->m_ulForbidTypeLoad;)
8274
8275     {
8276         // An AV during a profiler stackwalk is an isolated event and shouldn't bring
8277         // down the runtime.  Need to place the holder here, outside of ProfilerStackWalkFramesWrapper
8278         // since ProfilerStackWalkFramesWrapper uses __try, which doesn't like objects
8279         // with destructors.
8280         AVInRuntimeImplOkayHolder AVOkay;
8281
8282         hr = DoStackSnapshotHelper(
8283                  pThreadToSnapshot, 
8284                  &data, 
8285                  HANDLESKIPPEDFRAMES |
8286                      FUNCTIONSONLY |
8287                      NOTIFY_ON_U2M_TRANSITIONS |
8288                      ((pThreadToSnapshot == pCurrentThread) ?
8289                          0 : 
8290                          ALLOW_ASYNC_STACK_WALK | THREAD_IS_SUSPENDED) |
8291                      THREAD_EXECUTING_MANAGED_CODE |
8292                      PROFILER_DO_STACK_SNAPSHOT |
8293                      ALLOW_INVALID_OBJECTS, // stack walk logic should not look at objects - we could be in the middle of a gc.
8294                  pctxSeed);
8295     }
8296
8297     INDEBUG(if (pCurrentThread) pCurrentThread->m_ulForbidTypeLoad = ulForbidTypeLoad;)
8298
8299 Cleanup:
8300 #if defined(PLATFORM_SUPPORTS_SAFE_THREADSUSPEND)
8301     if (fResumeThread)
8302     {
8303         pThreadToSnapshot->ResumeThread();
8304     }
8305 #endif // PLATFORM_SUPPORTS_SAFE_THREADSUSPEND
8306     if (fResetSnapshotThreadExternalCount)
8307     {
8308         pThreadToSnapshot->DecExternalCountDANGEROUSProfilerOnly();
8309     }
8310
8311     return hr;
8312 }
8313
8314
8315 //---------------------------------------------------------------------------------------
8316 //
8317 // Exception swallowing wrapper around the profiler stackwalk
8318 //
8319 // Arguments:
8320 //      pThreadToSnapshot - Thread whose stack should be walked
8321 //      pData - data for stack walker
8322 //      flags - flags parameter to pass to StackWalkFramesEx, and StackFrameIterator 
8323 //      pctxSeed - Register context with which to seed the walk
8324 //
8325 // Return Value:
8326 //     HRESULT indicating success or failure.
8327 //
8328 HRESULT ProfToEEInterfaceImpl::DoStackSnapshotHelper(Thread * pThreadToSnapshot,
8329                                                      PROFILER_STACK_WALK_DATA * pData,
8330                                                      unsigned flags,
8331                                                      LPCONTEXT pctxSeed)
8332 {
8333     STATIC_CONTRACT_NOTHROW;
8334
8335     // We want to catch and swallow AVs here. For example, if the profiler gives 
8336     // us a bogus seed context (this happens), we could AV when inspecting memory pointed to 
8337     // by the (bogus) EBP register.
8338     //
8339     // EX_TRY/EX_CATCH does a lot of extras that we do not need and that can go wrong for us. 
8340     // E.g. It asserts in debug build for AVs in mscorwks or it synthetizes an object for the exception.
8341     // We use a plain PAL_TRY/PAL_EXCEPT since it is all we need.
8342     struct Param {
8343         HRESULT                     hr;
8344         Thread *                    pThreadToSnapshot;
8345         PROFILER_STACK_WALK_DATA *  pData;
8346         unsigned                    flags;
8347         ProfToEEInterfaceImpl *     pProfToEE;
8348         LPCONTEXT                   pctxSeed;
8349         BOOL                        fResetProfilerFilterContext;
8350     };
8351
8352     Param param;
8353     param.hr = E_UNEXPECTED;
8354     param.pThreadToSnapshot = pThreadToSnapshot;
8355     param.pData = pData;
8356     param.flags = flags; 
8357     param.pProfToEE = this;
8358     param.pctxSeed = pctxSeed;
8359     param.fResetProfilerFilterContext = FALSE;
8360
8361     PAL_TRY(Param *, pParam, &param)
8362     {
8363         if ((pParam->pData->infoFlags & COR_PRF_SNAPSHOT_X86_OPTIMIZED) != 0)
8364         {
8365 #ifndef _TARGET_X86_
8366             // If check in the begining of DoStackSnapshot (to return E_INVALIDARG) should 
8367             // make this unreachable
8368             _ASSERTE(!"COR_PRF_SNAPSHOT_X86_OPTIMIZED on non-X86 should be unreachable!");
8369 #else
8370             // New, simple EBP walker
8371             pParam->hr = pParam->pProfToEE->ProfilerEbpWalker(
8372                              pParam->pThreadToSnapshot,
8373                              pParam->pctxSeed,
8374                              pParam->pData->callback,
8375                              pParam->pData->clientData);
8376 #endif  // _TARGET_X86_
8377         }
8378         else
8379         {
8380             // We're now fairly confident the stackwalk should be ok, so set
8381             // the context seed, if one was provided or cooked up.
8382             if (pParam->pctxSeed != NULL)
8383             {
8384                 pParam->pThreadToSnapshot->SetProfilerFilterContext(pParam->pctxSeed);
8385                 pParam->fResetProfilerFilterContext = TRUE;
8386             }
8387
8388             // Whidbey-style walker, uses StackWalkFramesEx
8389             pParam->hr = pParam->pProfToEE->ProfilerStackWalkFramesWrapper(
8390                              pParam->pThreadToSnapshot,
8391                              pParam->pData,
8392                              pParam->flags);
8393         }
8394     }
8395     PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
8396     {
8397         param.hr = E_UNEXPECTED;
8398     }
8399     PAL_ENDTRY;
8400
8401     // Undo the context seeding & thread suspend we did (if any)
8402     // to ensure that the thread we walked stayed suspended
8403     if (param.fResetProfilerFilterContext)
8404     {
8405         pThreadToSnapshot->SetProfilerFilterContext(NULL);
8406     }
8407
8408     return param.hr;
8409 }
8410
8411
8412 HRESULT ProfToEEInterfaceImpl::GetGenerationBounds(ULONG cObjectRanges,
8413                                                    ULONG *pcObjectRanges,
8414                                                    COR_PRF_GC_GENERATION_RANGE ranges[])
8415 {
8416     CONTRACTL
8417     {
8418         // Yay!
8419         NOTHROW;
8420
8421         // Yay!
8422         GC_NOTRIGGER;
8423
8424         // Yay!
8425         MODE_ANY;
8426
8427         // Yay!
8428         EE_THREAD_NOT_REQUIRED;
8429
8430         // Yay!
8431         CANNOT_TAKE_LOCK;
8432
8433
8434         PRECONDITION(CheckPointer(pcObjectRanges));
8435         PRECONDITION(cObjectRanges <= 0 || ranges != NULL);
8436         PRECONDITION(s_generationTableLock >= 0);
8437     }
8438     CONTRACTL_END;
8439
8440     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8441         (LF_CORPROF, 
8442         LL_INFO1000, 
8443         "**PROF: GetGenerationBounds.\n"));
8444     
8445     // Announce we are using the generation table now
8446     CounterHolder genTableLock(&s_generationTableLock);
8447
8448     GenerationTable *generationTable = s_currentGenerationTable;
8449
8450     if (generationTable == NULL)
8451     {
8452         return E_FAIL;
8453     }
8454
8455     _ASSERTE(generationTable->magic == GENERATION_TABLE_MAGIC);
8456
8457     GenerationDesc *genDescTable = generationTable->genDescTable;
8458     ULONG count = min(generationTable->count, cObjectRanges);
8459     for (ULONG i = 0; i < count; i++)
8460     {
8461         ranges[i].generation          = (COR_PRF_GC_GENERATION)genDescTable[i].generation;
8462         ranges[i].rangeStart          = (ObjectID)genDescTable[i].rangeStart;
8463         ranges[i].rangeLength         = genDescTable[i].rangeEnd         - genDescTable[i].rangeStart;
8464         ranges[i].rangeLengthReserved = genDescTable[i].rangeEndReserved - genDescTable[i].rangeStart;
8465     }
8466
8467     *pcObjectRanges = generationTable->count;
8468
8469     return S_OK;
8470 }
8471
8472
8473 HRESULT ProfToEEInterfaceImpl::GetNotifiedExceptionClauseInfo(COR_PRF_EX_CLAUSE_INFO * pinfo)
8474 {
8475     CONTRACTL
8476     {
8477         // Yay!
8478         NOTHROW;
8479
8480         // Yay!
8481         GC_NOTRIGGER;
8482
8483         // Yay!
8484         MODE_ANY;
8485
8486         // Yay!
8487         CANNOT_TAKE_LOCK;
8488
8489
8490         PRECONDITION(CheckPointer(pinfo));
8491     }
8492     CONTRACTL_END;
8493
8494     PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF, 
8495                                      LL_INFO1000, 
8496                                      "**PROF: GetNotifiedExceptionClauseInfo.\n"));    
8497     
8498     HRESULT hr = S_OK;
8499
8500     ThreadExceptionState* pExState             = NULL;
8501     EHClauseInfo*         pCurrentEHClauseInfo = NULL;
8502
8503     // notification requires that we are on a managed thread with an exception in flight
8504     Thread *pThread = GetThread();
8505
8506     // If pThread is null, then the thread has never run managed code 
8507     if (pThread == NULL)
8508     {
8509         hr = CORPROF_E_NOT_MANAGED_THREAD;
8510         goto NullReturn;
8511     }
8512
8513     pExState = pThread->GetExceptionState();
8514     if (!pExState->IsExceptionInProgress())
8515     {
8516         // no exception is in flight -- successful failure
8517         hr = S_FALSE;
8518         goto NullReturn;
8519     }
8520
8521     pCurrentEHClauseInfo = pExState->GetCurrentEHClauseInfo();
8522     if (pCurrentEHClauseInfo->GetClauseType() == COR_PRF_CLAUSE_NONE)
8523     {
8524         // no exception is in flight -- successful failure
8525         hr = S_FALSE;
8526         goto NullReturn;
8527     }
8528
8529     pinfo->clauseType     = pCurrentEHClauseInfo->GetClauseType();
8530     pinfo->programCounter = pCurrentEHClauseInfo->GetIPForEHClause();
8531     pinfo->framePointer   = pCurrentEHClauseInfo->GetFramePointerForEHClause();
8532     pinfo->shadowStackPointer = 0;
8533
8534     return S_OK;
8535
8536 NullReturn:
8537     memset(pinfo, 0, sizeof(*pinfo));
8538     return hr;
8539 }
8540
8541
8542 HRESULT ProfToEEInterfaceImpl::GetObjectGeneration(ObjectID objectId,
8543                                                    COR_PRF_GC_GENERATION_RANGE *range)
8544 {
8545     CONTRACTL
8546     {
8547         // Yay!
8548         NOTHROW;
8549
8550         // Yay!
8551         GC_NOTRIGGER;
8552
8553         // Yay!
8554         MODE_ANY;
8555
8556         // Yay!
8557         EE_THREAD_NOT_REQUIRED;
8558
8559         // Yay!
8560         CANNOT_TAKE_LOCK;
8561
8562
8563         PRECONDITION(objectId != NULL);
8564         PRECONDITION(CheckPointer(range));
8565         PRECONDITION(s_generationTableLock >= 0);
8566     }
8567     CONTRACTL_END;
8568
8569     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8570                                        (LF_CORPROF, 
8571                                        LL_INFO1000, 
8572                                        "**PROF: GetObjectGeneration 0x%p.\n",
8573                                        objectId));        
8574
8575     BEGIN_GETTHREAD_ALLOWED;
8576     _ASSERTE((GetThread() == NULL) || (GetThread()->PreemptiveGCDisabled()));
8577     END_GETTHREAD_ALLOWED;
8578     
8579     // Announce we are using the generation table now
8580     CounterHolder genTableLock(&s_generationTableLock);
8581
8582     GenerationTable *generationTable = s_currentGenerationTable;
8583
8584     if (generationTable == NULL)
8585     {
8586         return E_FAIL;
8587     }
8588
8589     _ASSERTE(generationTable->magic == GENERATION_TABLE_MAGIC);
8590
8591     GenerationDesc *genDescTable = generationTable->genDescTable;
8592     ULONG count = generationTable->count;
8593     for (ULONG i = 0; i < count; i++)
8594     {
8595         if (genDescTable[i].rangeStart <= (BYTE *)objectId && (BYTE *)objectId < genDescTable[i].rangeEndReserved)
8596         {
8597             range->generation          = (COR_PRF_GC_GENERATION)genDescTable[i].generation;
8598             range->rangeStart          = (ObjectID)genDescTable[i].rangeStart;
8599             range->rangeLength         = genDescTable[i].rangeEnd         - genDescTable[i].rangeStart;
8600             range->rangeLengthReserved = genDescTable[i].rangeEndReserved - genDescTable[i].rangeStart;
8601
8602             return S_OK;
8603         }
8604     }
8605
8606     return E_FAIL;
8607 }
8608
8609 HRESULT ProfToEEInterfaceImpl::GetReJITIDs(
8610                            FunctionID          functionId,  // in
8611                            ULONG               cReJitIds,   // in
8612                            ULONG *             pcReJitIds,  // out
8613                            ReJITID             reJitIds[])  // out
8614 {
8615     CONTRACTL
8616     {
8617         // Yay!
8618         NOTHROW;
8619
8620         // taking a lock causes a GC
8621         GC_TRIGGERS;
8622
8623         // Yay!
8624         MODE_ANY;
8625
8626         // The rejit tables use a lock
8627         CAN_TAKE_LOCK;
8628
8629
8630         PRECONDITION(CheckPointer(pcReJitIds, NULL_OK));
8631         PRECONDITION(CheckPointer(reJitIds, NULL_OK));
8632
8633     }
8634     CONTRACTL_END;
8635
8636     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8637         kP2EEAllowableAfterAttach,
8638         (LF_CORPROF, 
8639         LL_INFO1000, 
8640         "**PROF: GetReJITIDs 0x%p.\n", 
8641          functionId));     
8642
8643     if (functionId == 0)
8644     {
8645         return E_INVALIDARG;
8646     }
8647
8648     if ((cReJitIds == 0) || (pcReJitIds == NULL) || (reJitIds == NULL))
8649     {
8650         return E_INVALIDARG;
8651     }
8652
8653     MethodDesc * pMD = FunctionIdToMethodDesc(functionId);
8654
8655     return ReJitManager::GetReJITIDs(pMD, cReJitIds, pcReJitIds, reJitIds);
8656 }
8657
8658 HRESULT ProfToEEInterfaceImpl::RequestReJIT(ULONG       cFunctions,   // in
8659                                             ModuleID    moduleIds[],  // in
8660                                             mdMethodDef methodIds[])  // in
8661 {
8662     CONTRACTL
8663     {
8664         // Yay!
8665         NOTHROW;
8666
8667         // When we suspend the runtime we drop into premptive mode
8668         GC_TRIGGERS;
8669
8670         // Yay!
8671         MODE_ANY;
8672
8673         // We need to suspend the runtime, this takes a lot of locks!
8674         CAN_TAKE_LOCK;
8675
8676
8677         PRECONDITION(CheckPointer(moduleIds, NULL_OK));
8678         PRECONDITION(CheckPointer(methodIds, NULL_OK));
8679     }
8680     CONTRACTL_END;
8681
8682     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8683         kP2EETriggers | kP2EEAllowableAfterAttach,
8684         (LF_CORPROF, 
8685          LL_INFO1000, 
8686          "**PROF: RequestReJIT.\n"));
8687
8688     if (!g_profControlBlock.pProfInterface->IsCallback4Supported())
8689     {
8690         return CORPROF_E_CALLBACK4_REQUIRED;
8691     }
8692
8693     if (!CORProfilerEnableRejit())
8694     {
8695         return CORPROF_E_REJIT_NOT_ENABLED;
8696     }
8697
8698     // Request at least 1 method to reJIT!
8699     if ((cFunctions == 0) || (moduleIds == NULL) || (methodIds == NULL))
8700     {
8701         return E_INVALIDARG;
8702     }
8703
8704     // Remember the profiler is doing this, as that means we must never detach it!
8705     g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
8706     
8707     GCX_PREEMP();
8708     return ReJitManager::RequestReJIT(cFunctions, moduleIds, methodIds, static_cast<COR_PRF_REJIT_FLAGS>(0));
8709 }
8710
8711 HRESULT ProfToEEInterfaceImpl::RequestRevert(ULONG       cFunctions,  // in
8712                                              ModuleID    moduleIds[], // in
8713                                              mdMethodDef methodIds[], // in
8714                                              HRESULT     rgHrStatuses[])    // out
8715 {
8716     CONTRACTL
8717     {
8718         // Yay!
8719         NOTHROW;
8720
8721         // The rejit manager requires a lock to iterate through methods to revert, and
8722         // taking the lock can drop us into preemptive mode.
8723         GC_TRIGGERS;
8724
8725         // Yay!
8726         MODE_ANY;
8727
8728         // The rejit manager requires a lock to iterate through methods to revert
8729         CAN_TAKE_LOCK;
8730
8731
8732         PRECONDITION(CheckPointer(moduleIds, NULL_OK));
8733         PRECONDITION(CheckPointer(methodIds, NULL_OK));
8734         PRECONDITION(CheckPointer(rgHrStatuses, NULL_OK));
8735     }
8736     CONTRACTL_END;
8737
8738     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8739         kP2EEAllowableAfterAttach | kP2EETriggers,
8740         (LF_CORPROF, 
8741          LL_INFO1000, 
8742          "**PROF: RequestRevert.\n"));
8743
8744     if (!CORProfilerEnableRejit())
8745     {
8746         return CORPROF_E_REJIT_NOT_ENABLED;
8747     }
8748
8749     // Request at least 1 method to revert!
8750     if ((cFunctions == 0) || (moduleIds == NULL) || (methodIds == NULL))
8751     {
8752         return E_INVALIDARG;
8753     }
8754
8755     // Remember the profiler is doing this, as that means we must never detach it!
8756     g_profControlBlock.pProfInterface->SetUnrevertiblyModifiedILFlag();
8757
8758     // Initialize the status array
8759     if (rgHrStatuses != NULL)
8760     {
8761         memset(rgHrStatuses, 0, sizeof(HRESULT) * cFunctions);
8762         _ASSERTE(S_OK == rgHrStatuses[0]);
8763     }
8764
8765     GCX_PREEMP();
8766     return ReJitManager::RequestRevert(cFunctions, moduleIds, methodIds, rgHrStatuses);
8767 }
8768
8769
8770 HRESULT ProfToEEInterfaceImpl::EnumJITedFunctions(ICorProfilerFunctionEnum ** ppEnum)
8771 {
8772     CONTRACTL
8773     {
8774         // Yay!
8775         NOTHROW;
8776
8777         // Yay!
8778         GC_NOTRIGGER;
8779
8780         // Yay!
8781         MODE_ANY;
8782
8783         // If we're in preemptive mode we need to take a read lock to safely walk
8784         // the JIT data structures.
8785         CAN_TAKE_LOCK;
8786
8787
8788         PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8789
8790     }
8791     CONTRACTL_END;
8792
8793     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8794         (LF_CORPROF, 
8795         LL_INFO10, 
8796         "**PROF: EnumJITedFunctions.\n"));
8797
8798     if (ppEnum == NULL)
8799     {
8800         return E_INVALIDARG;
8801     }
8802
8803     *ppEnum = NULL;
8804
8805     NewHolder<ProfilerFunctionEnum> pJitEnum(new (nothrow) ProfilerFunctionEnum());
8806     if (pJitEnum == NULL)
8807     {
8808         return E_OUTOFMEMORY;
8809     }
8810
8811     if (!pJitEnum->Init())
8812     {
8813         return E_OUTOFMEMORY;
8814     }
8815
8816     // Ownership transferred to [out] param.  Caller must Release() when done with this.
8817     *ppEnum = (ICorProfilerFunctionEnum *)pJitEnum.Extract();
8818
8819     return S_OK;
8820 }
8821
8822 HRESULT ProfToEEInterfaceImpl::EnumJITedFunctions2(ICorProfilerFunctionEnum ** ppEnum)
8823 {
8824     CONTRACTL
8825     {
8826         // Yay!
8827         NOTHROW;
8828
8829         // Gathering rejitids requires taking a lock and that lock might switch to
8830         // preemptimve mode... 
8831         GC_TRIGGERS;
8832
8833         // Yay!
8834         MODE_ANY;
8835
8836         // If we're in preemptive mode we need to take a read lock to safely walk
8837         // the JIT data structures.
8838         // Gathering RejitIDs also takes a lock.
8839         CAN_TAKE_LOCK;
8840
8841
8842         PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8843
8844     }
8845     CONTRACTL_END;
8846
8847     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8848         kP2EEAllowableAfterAttach | kP2EETriggers,
8849         (LF_CORPROF, 
8850         LL_INFO10, 
8851         "**PROF: EnumJITedFunctions.\n"));
8852
8853     if (ppEnum == NULL)
8854     {
8855         return E_INVALIDARG;
8856     }
8857
8858     *ppEnum = NULL;
8859
8860     NewHolder<ProfilerFunctionEnum> pJitEnum(new (nothrow) ProfilerFunctionEnum());
8861     if (pJitEnum == NULL)
8862     {
8863         return E_OUTOFMEMORY;
8864     }
8865
8866     if (!pJitEnum->Init(TRUE /* fWithReJITIDs */))
8867     {
8868         // If it fails, it's because of OOM.
8869         return E_OUTOFMEMORY;
8870     }
8871
8872     // Ownership transferred to [out] param.  Caller must Release() when done with this.
8873     *ppEnum = (ICorProfilerFunctionEnum *)pJitEnum.Extract();
8874
8875     return S_OK;
8876 }
8877
8878 HRESULT ProfToEEInterfaceImpl::EnumModules(ICorProfilerModuleEnum ** ppEnum)
8879 {
8880     CONTRACTL
8881     {
8882         // Yay!
8883         NOTHROW;
8884
8885         // This method populates the enumerator, which requires iterating over
8886         // AppDomains, which adds, then releases, a reference on each AppDomain iterated.
8887         // This causes locking, and can cause triggering if the AppDomain gets destroyed
8888         // as a result of the release. (See code:AppDomainIterator::Next and its call to
8889         // code:AppDomain::Release.)
8890         GC_TRIGGERS;
8891
8892         // Yay!
8893         MODE_ANY;
8894
8895         // (See comment above GC_TRIGGERS.)
8896         CAN_TAKE_LOCK;
8897
8898
8899         PRECONDITION(CheckPointer(ppEnum, NULL_OK));
8900
8901     }
8902     CONTRACTL_END;
8903
8904     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
8905         kP2EEAllowableAfterAttach | kP2EETriggers,
8906         (LF_CORPROF, 
8907         LL_INFO10, 
8908         "**PROF: EnumModules.\n"));
8909
8910     HRESULT hr;
8911
8912     if (ppEnum == NULL)
8913     {
8914         return E_INVALIDARG;
8915     }
8916
8917     *ppEnum = NULL;
8918
8919     // ProfilerModuleEnum uese AppDomainIterator, which cannot be called while the current thead
8920     // is holding the ThreadStore lock.
8921     if (ThreadStore::HoldingThreadStore())
8922     {
8923         return CORPROF_E_UNSUPPORTED_CALL_SEQUENCE;
8924     }
8925
8926     NewHolder<ProfilerModuleEnum> pModuleEnum(new (nothrow) ProfilerModuleEnum);
8927     if (pModuleEnum == NULL)
8928     {
8929         return E_OUTOFMEMORY;
8930     }
8931
8932     hr = pModuleEnum->Init();
8933     if (FAILED(hr))
8934     {
8935         return hr;
8936     }
8937
8938     // Ownership transferred to [out] param.  Caller must Release() when done with this.
8939     *ppEnum = (ICorProfilerModuleEnum *) pModuleEnum.Extract();
8940
8941     return S_OK;
8942 }
8943
8944 HRESULT ProfToEEInterfaceImpl::GetRuntimeInformation(USHORT * pClrInstanceId,
8945                                                      COR_PRF_RUNTIME_TYPE * pRuntimeType,
8946                                                      USHORT * pMajorVersion,
8947                                                      USHORT * pMinorVersion,
8948                                                      USHORT * pBuildNumber,
8949                                                      USHORT * pQFEVersion,
8950                                                      ULONG  cchVersionString,
8951                                                      ULONG  * pcchVersionString,
8952                                                      __out_ecount_part_opt(cchVersionString, *pcchVersionString) WCHAR  szVersionString[])
8953 {
8954     CONTRACTL
8955     {
8956         // Yay!
8957         NOTHROW;
8958
8959         // Yay!
8960         GC_NOTRIGGER;
8961
8962         // Yay!
8963         MODE_ANY;
8964
8965         // Yay!
8966         EE_THREAD_NOT_REQUIRED;
8967
8968         // Yay!
8969         CANNOT_TAKE_LOCK;
8970
8971     }
8972     CONTRACTL_END;
8973
8974     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach,
8975         (LF_CORPROF, 
8976         LL_INFO1000, 
8977         "**PROF: GetRuntimeInformation.\n"));
8978
8979     if ((szVersionString != NULL) && (pcchVersionString == NULL))
8980     {
8981         return E_INVALIDARG;
8982     }
8983
8984     if (pcchVersionString != NULL)
8985     {
8986         HRESULT hr = GetCORVersionInternal(szVersionString, (DWORD)cchVersionString, (DWORD *)pcchVersionString);
8987         if (FAILED(hr))
8988             return hr;
8989     }    
8990
8991     if (pClrInstanceId != NULL)
8992         *pClrInstanceId = static_cast<USHORT>(GetClrInstanceId());
8993
8994     if (pRuntimeType != NULL)
8995     {
8996         *pRuntimeType = COR_PRF_CORE_CLR;
8997     }
8998
8999     if (pMajorVersion != NULL)
9000         *pMajorVersion = CLR_MAJOR_VERSION;
9001
9002     if (pMinorVersion != NULL)
9003         *pMinorVersion = CLR_MINOR_VERSION;
9004
9005     if (pBuildNumber != NULL)
9006         *pBuildNumber = CLR_BUILD_VERSION;
9007
9008     if (pQFEVersion != NULL)
9009         *pQFEVersion = CLR_BUILD_VERSION_QFE;
9010
9011     return S_OK;
9012 }
9013
9014
9015 HRESULT ProfToEEInterfaceImpl::RequestProfilerDetach(DWORD dwExpectedCompletionMilliseconds)
9016 {
9017     CONTRACTL
9018     {
9019        // Yay!
9020         NOTHROW;
9021
9022         // Crst is used in ProfilingAPIDetach::RequestProfilerDetach so GC may be triggered
9023         GC_TRIGGERS;
9024
9025         // Yay!
9026         MODE_ANY;
9027
9028         // Yay!
9029         EE_THREAD_NOT_REQUIRED;
9030
9031         // Crst is used in ProfilingAPIDetach::RequestProfilerDetach
9032         CAN_TAKE_LOCK;
9033     }
9034     CONTRACTL_END;
9035
9036     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9037         kP2EEAllowableAfterAttach | kP2EETriggers,
9038         (LF_CORPROF, 
9039         LL_INFO1000, 
9040         "**PROF: RequestProfilerDetach.\n"));    
9041
9042 #ifdef FEATURE_PROFAPI_ATTACH_DETACH
9043     return ProfilingAPIDetach::RequestProfilerDetach(dwExpectedCompletionMilliseconds);
9044 #else // FEATURE_PROFAPI_ATTACH_DETACH
9045     return E_NOTIMPL;
9046 #endif // FEATURE_PROFAPI_ATTACH_DETACH
9047 }
9048
9049 typedef struct _COR_PRF_ELT_INFO_INTERNAL
9050 {
9051     // Point to a platform dependent structure ASM helper push on the stack
9052     void * platformSpecificHandle;
9053
9054     // startAddress of COR_PRF_FUNCTION_ARGUMENT_RANGE structure needs to point 
9055     // TO the argument value, not BE the argument value.  So, when the argument 
9056     // is this, we need to point TO this.  Because of the calling sequence change
9057     // in ELT3, we need to reserve the pointer here instead of using one of our 
9058     // stack variables.
9059     void * pThis;
9060
9061     // Reserve space for output parameter COR_PRF_FRAME_INFO of 
9062     // GetFunctionXXXX3Info functions
9063     COR_PRF_FRAME_INFO_INTERNAL frameInfo;
9064
9065 } COR_PRF_ELT_INFO_INTERNAL;
9066
9067 //---------------------------------------------------------------------------------------
9068 //
9069 // ProfilingGetFunctionEnter3Info provides frame information and argument infomation of 
9070 // the function ELT callback is inspecting.  It is called either by the profiler or the 
9071 // C helper function.
9072 // 
9073 // Arguments:
9074 //      * functionId - [in] FunctionId of the function being inspected by ELT3
9075 //      * eltInfo - [in] The opaque pointer FunctionEnter3WithInfo callback passed to the profiler
9076 //      * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect 
9077 //                     generic types
9078 //      * pcbArgumentInfo - [in, out] Pointer to ULONG that specifies the size of structure 
9079 //                          pointed by pArgumentInfo
9080 //      * pArgumentInfo - [out] Pointer to COR_PRF_FUNCTION_ARGUMENT_INFO structure the profiler
9081 //                        must preserve enough space for the function it is inspecting
9082 //          
9083 // Return Value:
9084 //    HRESULT indicating success or failure.
9085 //    
9086
9087 HRESULT ProfilingGetFunctionEnter3Info(FunctionID functionId,                              // in
9088                                        COR_PRF_ELT_INFO eltInfo,                           // in
9089                                        COR_PRF_FRAME_INFO * pFrameInfo,                    // out
9090                                        ULONG * pcbArgumentInfo,                            // in, out
9091                                        COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo)     // out
9092 {
9093     CONTRACTL
9094     {
9095         // Yay!
9096         NOTHROW;
9097
9098         // Yay!
9099         GC_NOTRIGGER;
9100
9101         // Yay!
9102         MODE_ANY;
9103
9104         // ProfileArgIterator::ProfileArgIterator may take locks
9105         CAN_TAKE_LOCK;
9106
9107
9108     }
9109     CONTRACTL_END;
9110
9111     if ((functionId == NULL) || (eltInfo == NULL))
9112     {
9113         return E_INVALIDARG;
9114     }
9115
9116     COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9117     ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9118
9119     // The loader won't trigger a GC or throw for already loaded argument types.
9120     ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9121
9122     //
9123     // Find the method this is referring to, so we can get the signature
9124     //
9125     MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9126     MetaSig metaSig(pMethodDesc);
9127
9128     NewHolder<ProfileArgIterator> pProfileArgIterator;
9129
9130     {
9131         // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9132         FAULT_NOT_FATAL();
9133
9134         pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9135
9136         if (pProfileArgIterator == NULL)
9137         {
9138             return E_UNEXPECTED;
9139         }
9140     }
9141
9142     if (CORProfilerFrameInfoEnabled())
9143     {
9144         if (pFrameInfo == NULL)
9145         {
9146             return E_INVALIDARG;
9147         }
9148
9149         //
9150         // Setup the COR_PRF_FRAME_INFO structure first.
9151         //
9152         COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9153
9154         pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9155         pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9156         pCorPrfFrameInfo->funcID = functionId;
9157         pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9158         pCorPrfFrameInfo->extraArg = pProfileArgIterator->GetHiddenArgValue();
9159         pCorPrfFrameInfo->thisArg = pProfileArgIterator->GetThis();
9160
9161         *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9162     }
9163
9164     //
9165     // Do argument processing if desired.
9166     //
9167     if (CORProfilerFunctionArgsEnabled())
9168     {
9169         if (pcbArgumentInfo == NULL)
9170         {
9171             return E_INVALIDARG;
9172         }
9173
9174         if ((*pcbArgumentInfo != 0) && (pArgumentInfo == NULL))
9175         {
9176             return E_INVALIDARG;
9177         }
9178
9179         ULONG32 count = pProfileArgIterator->GetNumArgs();
9180
9181         if (metaSig.HasThis())
9182         {
9183             count++;
9184         }
9185
9186         ULONG ulArgInfoSize = sizeof(COR_PRF_FUNCTION_ARGUMENT_INFO) + (count * sizeof(COR_PRF_FUNCTION_ARGUMENT_RANGE));
9187
9188         if (*pcbArgumentInfo < ulArgInfoSize)
9189         {
9190             *pcbArgumentInfo = ulArgInfoSize;
9191             return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
9192         }
9193
9194         _ASSERTE(pArgumentInfo != NULL);
9195
9196         pArgumentInfo->numRanges         = count;
9197         pArgumentInfo->totalArgumentSize = 0;
9198
9199         count = 0;
9200
9201         if (metaSig.HasThis())
9202         {
9203             pELTInfo->pThis = pProfileArgIterator->GetThis();
9204             pArgumentInfo->ranges[count].startAddress = (UINT_PTR) (&(pELTInfo->pThis));
9205
9206             UINT length = sizeof(pELTInfo->pThis);
9207             pArgumentInfo->ranges[count].length = length;
9208             pArgumentInfo->totalArgumentSize += length;
9209             count++;
9210         }
9211
9212         while (count < pArgumentInfo->numRanges)
9213         {
9214             pArgumentInfo->ranges[count].startAddress = (UINT_PTR)(pProfileArgIterator->GetNextArgAddr());
9215
9216             UINT length = pProfileArgIterator->GetArgSize();
9217             pArgumentInfo->ranges[count].length = length;
9218             pArgumentInfo->totalArgumentSize += length;
9219             count++;
9220         }
9221     }
9222
9223     return S_OK;
9224 }
9225
9226
9227
9228 HRESULT ProfToEEInterfaceImpl::GetFunctionEnter3Info(FunctionID functionId,                              // in
9229                                                      COR_PRF_ELT_INFO eltInfo,                           // in
9230                                                      COR_PRF_FRAME_INFO * pFrameInfo,                    // out
9231                                                      ULONG * pcbArgumentInfo,                            // in, out
9232                                                      COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo)     // out
9233 {
9234     CONTRACTL
9235     {
9236         // Yay!
9237         NOTHROW;
9238
9239         // Yay!
9240         GC_NOTRIGGER;
9241
9242         // Yay!
9243         MODE_ANY;
9244
9245         // ProfilingGetFunctionEnter3Info may take locks
9246         CAN_TAKE_LOCK;
9247
9248
9249     }
9250     CONTRACTL_END;
9251
9252     PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF, 
9253                                     LL_INFO1000, 
9254                                     "**PROF: GetFunctionEnter3Info.\n"));
9255
9256     _ASSERTE(g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() != NULL);
9257
9258     if (!CORProfilerELT3SlowPathEnterEnabled())
9259     {
9260         return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9261     }
9262
9263     return ProfilingGetFunctionEnter3Info(functionId, eltInfo, pFrameInfo, pcbArgumentInfo, pArgumentInfo);
9264 }
9265
9266 //---------------------------------------------------------------------------------------
9267 //
9268 // ProfilingGetFunctionLeave3Info provides frame information and return value infomation 
9269 // of the function ELT callback is inspecting.  It is called either by the profiler or the 
9270 // C helper function.
9271 // 
9272 // Arguments:
9273 //      * functionId - [in] FunctionId of the function being inspected by ELT3
9274 //      * eltInfo - [in] The opaque pointer FunctionLeave3WithInfo callback passed to the profiler
9275 //      * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect 
9276 //                     generic types
9277 //      * pRetvalRange - [out] Pointer to COR_PRF_FUNCTION_ARGUMENT_RANGE to store return value
9278 //          
9279 // Return Value:
9280 //    HRESULT indicating success or failure.
9281 //    
9282
9283 HRESULT ProfilingGetFunctionLeave3Info(FunctionID functionId,                              // in
9284                                        COR_PRF_ELT_INFO eltInfo,                           // in
9285                                        COR_PRF_FRAME_INFO * pFrameInfo,                    // out
9286                                        COR_PRF_FUNCTION_ARGUMENT_RANGE * pRetvalRange)     // out
9287 {
9288     CONTRACTL
9289     {
9290         // Yay!
9291         NOTHROW;
9292
9293         // Yay!
9294         GC_NOTRIGGER;
9295
9296         // Yay!
9297         MODE_ANY;
9298
9299         // ProfileArgIterator::ProfileArgIterator may take locks
9300         CAN_TAKE_LOCK;
9301
9302     }
9303     CONTRACTL_END;
9304
9305     if ((pFrameInfo == NULL) || (eltInfo == NULL))
9306     {
9307         return E_INVALIDARG;
9308     }
9309
9310     COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9311     ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9312
9313     // The loader won't trigger a GC or throw for already loaded argument types.
9314     ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9315
9316     //
9317     // Find the method this is referring to, so we can get the signature
9318     //
9319     MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9320     MetaSig metaSig(pMethodDesc);
9321
9322     NewHolder<ProfileArgIterator> pProfileArgIterator;
9323
9324     {
9325         // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9326         FAULT_NOT_FATAL();
9327
9328         pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9329
9330         if (pProfileArgIterator == NULL)
9331         {
9332             return E_UNEXPECTED;
9333         }
9334     }
9335
9336     if (CORProfilerFrameInfoEnabled())
9337     {
9338         if (pFrameInfo == NULL)
9339         {
9340             return E_INVALIDARG;
9341         }
9342
9343         COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9344
9345         //
9346         // Setup the COR_PRF_FRAME_INFO structure first.
9347         //
9348         pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9349         pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9350         pCorPrfFrameInfo->funcID = functionId;
9351         pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9352
9353         // Upon entering Leave hook, the register assigned to store this pointer on function calls may 
9354         // already be reused and is likely not to contain this pointer.
9355         pCorPrfFrameInfo->extraArg = NULL;
9356         pCorPrfFrameInfo->thisArg = NULL;
9357
9358         *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9359     }
9360
9361     //
9362     // Do argument processing if desired.
9363     //
9364     if (CORProfilerFunctionReturnValueEnabled())
9365     {
9366         if (pRetvalRange == NULL)
9367         {
9368             return E_INVALIDARG;
9369         }
9370
9371         if (!metaSig.IsReturnTypeVoid())
9372         {
9373             pRetvalRange->length = metaSig.GetReturnTypeSize();
9374             pRetvalRange->startAddress = (UINT_PTR)pProfileArgIterator->GetReturnBufferAddr();
9375         }
9376         else
9377         {
9378             pRetvalRange->length = 0;
9379             pRetvalRange->startAddress = 0;
9380         }
9381     }
9382
9383     return S_OK;
9384 }
9385
9386
9387 HRESULT ProfToEEInterfaceImpl::GetFunctionLeave3Info(FunctionID functionId,                              // in
9388                                                      COR_PRF_ELT_INFO eltInfo,                           // in
9389                                                      COR_PRF_FRAME_INFO * pFrameInfo,                    // out
9390                                                      COR_PRF_FUNCTION_ARGUMENT_RANGE * pRetvalRange)     // out
9391 {
9392     CONTRACTL
9393     {
9394         // Yay!
9395         NOTHROW;
9396
9397         // Yay!
9398         GC_NOTRIGGER;
9399
9400         // Yay!
9401         MODE_ANY;
9402
9403         // ProfilingGetFunctionLeave3Info may take locks
9404         CAN_TAKE_LOCK;
9405
9406
9407     }
9408     CONTRACTL_END;
9409
9410     PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF, 
9411                                     LL_INFO1000, 
9412                                     "**PROF: GetFunctionLeave3Info.\n"));
9413
9414     _ASSERTE(g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() != NULL);
9415
9416     if (!CORProfilerELT3SlowPathLeaveEnabled())
9417     {
9418         return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9419     }
9420
9421     return ProfilingGetFunctionLeave3Info(functionId, eltInfo, pFrameInfo, pRetvalRange);
9422 }
9423
9424 //---------------------------------------------------------------------------------------
9425 //
9426 // ProfilingGetFunctionTailcall3Info provides frame information of the function ELT callback 
9427 // is inspecting.  It is called either by the profiler or the C helper function.
9428 // 
9429 // Arguments:
9430 //      * functionId - [in] FunctionId of the function being inspected by ELT3
9431 //      * eltInfo - [in] The opaque pointer FunctionTailcall3WithInfo callback passed to the 
9432 //                  profiler
9433 //      * pFrameInfo - [out] Pointer to COR_PRF_FRAME_INFO the profiler later can use to inspect 
9434 //                     generic types
9435 //          
9436 // Return Value:
9437 //    HRESULT indicating success or failure.
9438 //    
9439
9440 HRESULT ProfilingGetFunctionTailcall3Info(FunctionID functionId,                              // in
9441                                           COR_PRF_ELT_INFO eltInfo,                           // in
9442                                           COR_PRF_FRAME_INFO * pFrameInfo)                    // out
9443 {
9444     CONTRACTL
9445     {
9446         // Yay!
9447         NOTHROW;
9448
9449         // Yay!
9450         GC_NOTRIGGER;
9451
9452         // Yay!
9453         MODE_ANY;
9454
9455         // ProfileArgIterator::ProfileArgIterator may take locks
9456         CAN_TAKE_LOCK;
9457
9458
9459     }
9460     CONTRACTL_END;
9461
9462     if ((functionId == NULL) || (eltInfo == NULL) || (pFrameInfo == NULL))
9463     {
9464         return E_INVALIDARG;
9465     }
9466
9467     COR_PRF_ELT_INFO_INTERNAL * pELTInfo = (COR_PRF_ELT_INFO_INTERNAL *)eltInfo;
9468     ProfileSetFunctionIDInPlatformSpecificHandle(pELTInfo->platformSpecificHandle, functionId);
9469
9470     // The loader won't trigger a GC or throw for already loaded argument types.
9471     ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
9472
9473     //
9474     // Find the method this is referring to, so we can get the signature
9475     //
9476     MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
9477     MetaSig metaSig(pMethodDesc);
9478
9479     NewHolder<ProfileArgIterator> pProfileArgIterator;
9480
9481     {
9482         // Can handle E_OUTOFMEMORY from ProfileArgIterator.
9483         FAULT_NOT_FATAL();
9484
9485         pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, pELTInfo->platformSpecificHandle);
9486
9487         if (pProfileArgIterator == NULL)
9488         {
9489             return E_UNEXPECTED;
9490         }
9491     }
9492
9493     COR_PRF_FRAME_INFO_INTERNAL * pCorPrfFrameInfo = &(pELTInfo->frameInfo);
9494
9495     //
9496     // Setup the COR_PRF_FRAME_INFO structure first.
9497     //
9498     pCorPrfFrameInfo->size = sizeof(COR_PRF_FRAME_INFO_INTERNAL);
9499     pCorPrfFrameInfo->version = COR_PRF_FRAME_INFO_INTERNAL_CURRENT_VERSION;
9500     pCorPrfFrameInfo->funcID = functionId;
9501     pCorPrfFrameInfo->IP = ProfileGetIPFromPlatformSpecificHandle(pELTInfo->platformSpecificHandle);
9502
9503     // Tailcall is designed to report the caller, not the callee.  But the taillcall hook is invoked 
9504     // with registers containing parameters passed to the callee before calling into the callee.  
9505     // This pointer we get here is for the callee.  Because of the constraints imposed on tailcall
9506     // optimization, this pointer passed to the callee accidentally happens to be the same this pointer 
9507     // passed to the caller.  
9508     // 
9509     // It is a fragile coincidence we should not depend on because JIT is free to change the 
9510     // implementation details in the future.
9511     pCorPrfFrameInfo->extraArg = NULL;
9512     pCorPrfFrameInfo->thisArg = NULL;
9513
9514     *pFrameInfo = (COR_PRF_FRAME_INFO)pCorPrfFrameInfo;
9515
9516     return S_OK;
9517 }
9518
9519
9520 HRESULT ProfToEEInterfaceImpl::GetFunctionTailcall3Info(FunctionID functionId,                              // in
9521                                                         COR_PRF_ELT_INFO eltInfo,                           // in
9522                                                         COR_PRF_FRAME_INFO * pFrameInfo)                    // out
9523 {
9524     CONTRACTL
9525     {
9526         // Yay!
9527         NOTHROW;
9528
9529         // Yay!
9530         GC_NOTRIGGER;
9531
9532         // Yay!
9533         MODE_ANY;
9534
9535         // ProfilingGetFunctionTailcall3Info may take locks
9536         CAN_TAKE_LOCK;
9537
9538
9539     }
9540     CONTRACTL_END;
9541
9542     PROFILER_TO_CLR_ENTRYPOINT_SYNC((LF_CORPROF, 
9543                                     LL_INFO1000, 
9544                                     "**PROF: GetFunctionTailcall3Info.\n"));
9545
9546     _ASSERTE(g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() != NULL);
9547
9548     if (!CORProfilerELT3SlowPathTailcallEnabled())
9549     {
9550         return CORPROF_E_INCONSISTENT_WITH_FLAGS;
9551     }
9552
9553     return ProfilingGetFunctionTailcall3Info(functionId, eltInfo, pFrameInfo);
9554 }
9555
9556 HRESULT ProfToEEInterfaceImpl::EnumThreads(
9557     /* out */ ICorProfilerThreadEnum ** ppEnum)
9558 {
9559
9560     CONTRACTL
9561     {
9562         // Yay!
9563         NOTHROW;
9564
9565         // Yay!
9566         GC_NOTRIGGER;
9567
9568         // Yay!
9569         MODE_ANY;
9570
9571         // Need to acquire the thread store lock
9572         CAN_TAKE_LOCK;
9573         
9574
9575         PRECONDITION(CheckPointer(ppEnum, NULL_OK));
9576
9577     }
9578     CONTRACTL_END;
9579
9580     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9581         kP2EEAllowableAfterAttach,
9582         (LF_CORPROF, 
9583         LL_INFO10, 
9584         "**PROF: EnumThreads.\n"));
9585
9586     HRESULT hr;
9587
9588     if (ppEnum == NULL)
9589     {
9590         return E_INVALIDARG;
9591     }
9592
9593     *ppEnum = NULL;
9594
9595     NewHolder<ProfilerThreadEnum> pThreadEnum(new (nothrow) ProfilerThreadEnum);
9596     if (pThreadEnum == NULL)
9597     {
9598         return E_OUTOFMEMORY;
9599     }
9600
9601     hr = pThreadEnum->Init();
9602     if (FAILED(hr))
9603     {
9604         return hr;
9605     }
9606
9607     // Ownership transferred to [out] param.  Caller must Release() when done with this.
9608     *ppEnum = (ICorProfilerThreadEnum *) pThreadEnum.Extract();
9609
9610     return S_OK;
9611 }
9612
9613 // This function needs to be called on any thread before making any ICorProfilerInfo* calls and must be 
9614 // made before any thread is suspended by this profiler.
9615 // As you might have already figured out, this is done to avoid deadlocks situation when 
9616 // the suspended thread holds on the loader lock / heap lock while the current thread is trying to obtain
9617 // the same lock.
9618 HRESULT ProfToEEInterfaceImpl::InitializeCurrentThread()
9619 {
9620
9621     CONTRACTL
9622     {
9623         // Yay!
9624         NOTHROW;
9625
9626         // Yay!
9627         GC_NOTRIGGER;
9628
9629         // Yay!
9630         MODE_ANY;
9631
9632         // May take thread store lock and OS APIs may also take locks
9633         CAN_TAKE_LOCK;
9634         
9635     }
9636     CONTRACTL_END;
9637     
9638    
9639     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9640             kP2EEAllowableAfterAttach,
9641             (LF_CORPROF, 
9642             LL_INFO10, 
9643             "**PROF: InitializeCurrentThread.\n"));
9644
9645     HRESULT hr = S_OK;
9646     
9647     EX_TRY
9648     {
9649         CExecutionEngine::SetupTLSForThread(GetThread());
9650     }
9651     EX_CATCH_HRESULT(hr);
9652
9653     if (FAILED(hr))
9654         return hr;
9655     
9656      return S_OK;
9657 }
9658
9659 struct InternalProfilerModuleEnum : public ProfilerModuleEnum
9660 {
9661     CDynArray<ModuleID> *GetRawElementsArray()
9662     {
9663         return &m_elements;
9664     }
9665 };
9666
9667 HRESULT ProfToEEInterfaceImpl::EnumNgenModuleMethodsInliningThisMethod(
9668     ModuleID    inlinersModuleId,
9669     ModuleID    inlineeModuleId,
9670     mdMethodDef inlineeMethodId,
9671     BOOL       *incompleteData,
9672     ICorProfilerMethodEnum** ppEnum)
9673 {
9674     CONTRACTL
9675     {
9676         NOTHROW;
9677         GC_TRIGGERS; 
9678         MODE_ANY;
9679         CAN_TAKE_LOCK;
9680         PRECONDITION(CheckPointer(ppEnum));
9681     }
9682     CONTRACTL_END;
9683
9684     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EETriggers, (LF_CORPROF, LL_INFO1000,  "**PROF: EnumNgenModuleMethodsInliningThisMethod.\n"));
9685
9686     if (ppEnum == NULL)
9687     {
9688         return E_INVALIDARG;
9689     }
9690     *ppEnum = NULL;
9691     HRESULT hr = S_OK;
9692
9693     Module *inlineeOwnerModule = reinterpret_cast<Module *>(inlineeModuleId);
9694     if (inlineeOwnerModule == NULL)
9695     {
9696         return E_INVALIDARG;
9697     }
9698     if (inlineeOwnerModule->IsBeingUnloaded())
9699     {
9700         return CORPROF_E_DATAINCOMPLETE;
9701     }
9702
9703     Module  *inlinersModule = reinterpret_cast<Module *>(inlinersModuleId);
9704     if (inlinersModule == NULL)
9705     {
9706         return E_INVALIDARG;
9707     }
9708     if(inlinersModule->IsBeingUnloaded())
9709     {
9710         return CORPROF_E_DATAINCOMPLETE;
9711     }
9712
9713     if (!inlinersModule->HasNativeOrReadyToRunInlineTrackingMap())
9714     {
9715         return CORPROF_E_DATAINCOMPLETE;
9716     }
9717
9718     CDynArray<COR_PRF_METHOD> results;
9719     const COUNT_T staticBufferSize = 10;
9720     MethodInModule staticBuffer[staticBufferSize];
9721     NewArrayHolder<MethodInModule> dynamicBuffer;
9722     MethodInModule *methodsBuffer = staticBuffer;
9723     EX_TRY
9724     {
9725         // Trying to use static buffer
9726         COUNT_T methodsAvailable = inlinersModule->GetNativeOrReadyToRunInliners(inlineeOwnerModule, inlineeMethodId, staticBufferSize, staticBuffer, incompleteData);
9727
9728         // If static buffer is not enough, allocate an array.
9729         if (methodsAvailable > staticBufferSize)
9730         {
9731             DWORD dynamicBufferSize = methodsAvailable;
9732             dynamicBuffer = methodsBuffer = new MethodInModule[dynamicBufferSize];
9733             methodsAvailable = inlinersModule->GetNativeOrReadyToRunInliners(inlineeOwnerModule, inlineeMethodId, dynamicBufferSize, dynamicBuffer, incompleteData);                
9734             if (methodsAvailable > dynamicBufferSize)
9735             {
9736                 _ASSERTE(!"Ngen image inlining info changed, this shouldn't be possible.");
9737                 methodsAvailable = dynamicBufferSize;
9738             }
9739         }
9740
9741         //Go through all inliners found in the inlinersModule and prepare them to export via results.
9742         results.AllocateBlockThrowing(methodsAvailable);
9743         for (COUNT_T j = 0; j < methodsAvailable; j++)
9744         {
9745             COR_PRF_METHOD *newPrfMethod = &results[j];
9746             newPrfMethod->moduleId = reinterpret_cast<ModuleID>(methodsBuffer[j].m_module);
9747             newPrfMethod->methodId = methodsBuffer[j].m_methodDef;
9748         }
9749         *ppEnum = new ProfilerMethodEnum(&results);
9750     }
9751     EX_CATCH_HRESULT(hr);
9752
9753     return hr;
9754 }
9755
9756 HRESULT ProfToEEInterfaceImpl::GetInMemorySymbolsLength(
9757     ModuleID moduleId,
9758     DWORD* pCountSymbolBytes)
9759 {
9760
9761     CONTRACTL
9762     {
9763         NOTHROW;
9764         GC_NOTRIGGER;
9765         MODE_ANY;
9766     }
9767     CONTRACTL_END;
9768
9769
9770     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9771         kP2EEAllowableAfterAttach,
9772         (LF_CORPROF,
9773             LL_INFO10,
9774             "**PROF: GetInMemorySymbolsLength.\n"));
9775
9776     HRESULT hr = S_OK;
9777     if (pCountSymbolBytes == NULL)
9778     {
9779         return E_INVALIDARG;
9780     }
9781     *pCountSymbolBytes = 0;
9782
9783     Module* pModule = reinterpret_cast< Module* >(moduleId);
9784     if (pModule == NULL)
9785     {
9786         return E_INVALIDARG;
9787     }
9788     if (pModule->IsBeingUnloaded())
9789     {
9790         return CORPROF_E_DATAINCOMPLETE;
9791     }
9792
9793     //This method would work fine on reflection.emit, but there would be no way to know
9794     //if some other thread was changing the size of the symbols before this method returned.
9795     //Adding events or locks to detect/prevent changes would make the scenario workable
9796     if (pModule->IsReflection())
9797     {
9798         return COR_PRF_MODULE_DYNAMIC;
9799     }
9800     
9801     CGrowableStream* pStream = pModule->GetInMemorySymbolStream();
9802     if (pStream == NULL)
9803     {
9804         return S_OK;
9805     }
9806
9807     STATSTG SizeData = { 0 };
9808     hr = pStream->Stat(&SizeData, STATFLAG_NONAME);
9809     if (FAILED(hr))
9810     {
9811         return hr;
9812     }
9813     if (SizeData.cbSize.u.HighPart > 0)
9814     {
9815         return COR_E_OVERFLOW;
9816     }
9817     *pCountSymbolBytes = SizeData.cbSize.u.LowPart;
9818
9819     return S_OK;
9820 }
9821
9822 HRESULT ProfToEEInterfaceImpl::ReadInMemorySymbols(
9823     ModuleID moduleId,
9824     DWORD symbolsReadOffset,
9825     BYTE* pSymbolBytes,
9826     DWORD countSymbolBytes,
9827     DWORD* pCountSymbolBytesRead)
9828 {
9829     CONTRACTL
9830     {
9831         NOTHROW;
9832         GC_NOTRIGGER;
9833         MODE_ANY;
9834     }
9835     CONTRACTL_END;
9836
9837     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(
9838         kP2EEAllowableAfterAttach,
9839         (LF_CORPROF,
9840             LL_INFO10,
9841             "**PROF: ReadInMemorySymbols.\n"));
9842
9843     HRESULT hr = S_OK;
9844     if (pSymbolBytes == NULL)
9845     {
9846         return E_INVALIDARG;
9847     }
9848     if (pCountSymbolBytesRead == NULL)
9849     {
9850         return E_INVALIDARG;
9851     }
9852     *pCountSymbolBytesRead = 0;
9853
9854     Module* pModule = reinterpret_cast< Module* >(moduleId);
9855     if (pModule == NULL)
9856     {
9857         return E_INVALIDARG;
9858     }
9859     if (pModule->IsBeingUnloaded())
9860     {
9861         return CORPROF_E_DATAINCOMPLETE;
9862     }
9863
9864     //This method would work fine on reflection.emit, but there would be no way to know
9865     //if some other thread was changing the size of the symbols before this method returned.
9866     //Adding events or locks to detect/prevent changes would make the scenario workable
9867     if (pModule->IsReflection())
9868     {
9869         return COR_PRF_MODULE_DYNAMIC;
9870     }
9871
9872     CGrowableStream* pStream = pModule->GetInMemorySymbolStream();
9873     if (pStream == NULL)
9874     {
9875         return E_INVALIDARG;
9876     }
9877
9878     STATSTG SizeData = { 0 };
9879     hr = pStream->Stat(&SizeData, STATFLAG_NONAME);
9880     if (FAILED(hr))
9881     {
9882         return hr;
9883     }
9884     if (SizeData.cbSize.u.HighPart > 0)
9885     {
9886         return COR_E_OVERFLOW;
9887     }
9888     DWORD streamSize = SizeData.cbSize.u.LowPart;
9889     if (symbolsReadOffset >= streamSize)
9890     {
9891         return E_INVALIDARG;
9892     }
9893
9894     *pCountSymbolBytesRead = min(streamSize - symbolsReadOffset, countSymbolBytes);
9895     memcpy_s(pSymbolBytes, countSymbolBytes, ((BYTE*)pStream->GetRawBuffer().StartAddress()) + symbolsReadOffset, *pCountSymbolBytesRead);
9896
9897     return S_OK;
9898 }
9899
9900 HRESULT ProfToEEInterfaceImpl::ApplyMetaData(
9901     ModuleID    moduleId)
9902 {
9903     CONTRACTL
9904     {
9905         NOTHROW;
9906         GC_TRIGGERS;
9907         MODE_ANY;
9908     }
9909     CONTRACTL_END;
9910
9911     PROFILER_TO_CLR_ENTRYPOINT_SYNC_EX(kP2EEAllowableAfterAttach | kP2EETriggers, (LF_CORPROF, LL_INFO1000, "**PROF: ApplyMetaData.\n"));
9912
9913     if (moduleId == NULL)
9914     {
9915         return E_INVALIDARG;
9916     }
9917
9918     HRESULT hr = S_OK;
9919     EX_TRY
9920     {
9921         Module *pModule = (Module *)moduleId;
9922         _ASSERTE(pModule != NULL);
9923         if (pModule->IsBeingUnloaded())
9924         {
9925             hr = CORPROF_E_DATAINCOMPLETE;
9926         }
9927        else
9928        {
9929             pModule->ApplyMetaData();
9930        }
9931     }
9932     EX_CATCH_HRESULT(hr);
9933     return hr;
9934 }
9935
9936 //---------------------------------------------------------------------------------------
9937 //
9938 // Simple wrapper around EEToProfInterfaceImpl::ManagedToUnmanagedTransition.  This
9939 // can be called by C++ code and directly by generated stubs.
9940 //
9941 // Arguments:
9942 //      pMD - MethodDesc for the managed function involved in the transition
9943 //      reason - Passed on to profiler to indicate why the transition is occurring
9944 //
9945
9946 void __stdcall ProfilerManagedToUnmanagedTransitionMD(MethodDesc *pMD,
9947                                                       COR_PRF_TRANSITION_REASON reason)
9948 {
9949     CONTRACTL
9950     {
9951         NOTHROW;
9952         GC_TRIGGERS;
9953         MODE_PREEMPTIVE;
9954     }
9955     CONTRACTL_END;
9956
9957     // This function is called within the runtime, not directly from managed code.
9958     // Also, the only case MD is NULL is the calli pinvoke case, and we still
9959     // want to notify the profiler in that case.
9960
9961     // Do not notify the profiler about QCalls
9962     if (pMD == NULL || !pMD->IsQCall())
9963     {
9964         BEGIN_PIN_PROFILER(CORProfilerPresent());
9965         g_profControlBlock.pProfInterface->ManagedToUnmanagedTransition(MethodDescToFunctionID(pMD),
9966                                                                         reason);
9967         END_PIN_PROFILER();
9968     }
9969 }
9970
9971 //---------------------------------------------------------------------------------------
9972 //
9973 // Simple wrapper around EEToProfInterfaceImpl::UnmanagedToManagedTransition.  This
9974 // can be called by C++ code and directly by generated stubs.
9975 //
9976 // Arguments:
9977 //      pMD - MethodDesc for the managed function involved in the transition
9978 //      reason - Passed on to profiler to indicate why the transition is occurring
9979 //
9980
9981 void __stdcall ProfilerUnmanagedToManagedTransitionMD(MethodDesc *pMD,
9982                                                       COR_PRF_TRANSITION_REASON reason)
9983 {
9984     CONTRACTL
9985     {
9986         NOTHROW;
9987         GC_TRIGGERS;
9988         MODE_PREEMPTIVE;
9989     }
9990     CONTRACTL_END;
9991
9992     // This function is called within the runtime, not directly from managed code.
9993     // Also, the only case MD is NULL is the calli pinvoke case, and we still
9994     // want to notify the profiler in that case.
9995
9996     // Do not notify the profiler about QCalls
9997     if (pMD == NULL || !pMD->IsQCall())
9998     {
9999         BEGIN_PIN_PROFILER(CORProfilerPresent());
10000         g_profControlBlock.pProfInterface->UnmanagedToManagedTransition(MethodDescToFunctionID(pMD),
10001                                                                         reason);
10002         END_PIN_PROFILER();
10003     }
10004 }
10005
10006
10007
10008 #endif // PROFILING_SUPPORTED
10009
10010
10011 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemoting)
10012 {
10013     FCALL_CONTRACT;
10014
10015 #ifdef PROFILING_SUPPORTED
10016     FC_RETURN_BOOL(CORProfilerTrackRemoting());
10017 #else // !PROFILING_SUPPORTED
10018     FC_RETURN_BOOL(FALSE);
10019 #endif // !PROFILING_SUPPORTED
10020 }
10021 FCIMPLEND
10022
10023 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemotingCookie)
10024 {
10025     FCALL_CONTRACT;
10026
10027 #ifdef PROFILING_SUPPORTED
10028     FC_RETURN_BOOL(CORProfilerTrackRemotingCookie());
10029 #else // !PROFILING_SUPPORTED
10030     FC_RETURN_BOOL(FALSE);
10031 #endif // !PROFILING_SUPPORTED
10032 }
10033 FCIMPLEND
10034
10035 FCIMPL0(FC_BOOL_RET, ProfilingFCallHelper::FC_TrackRemotingAsync)
10036 {
10037     FCALL_CONTRACT;
10038
10039 #ifdef PROFILING_SUPPORTED
10040     FC_RETURN_BOOL(CORProfilerTrackRemotingAsync());
10041 #else // !PROFILING_SUPPORTED
10042     FC_RETURN_BOOL(FALSE);
10043 #endif // !PROFILING_SUPPORTED
10044 }
10045 FCIMPLEND
10046
10047 FCIMPL2(void, ProfilingFCallHelper::FC_RemotingClientSendingMessage, GUID *pId, CLR_BOOL fIsAsync)
10048 {
10049     FCALL_CONTRACT;
10050
10051 #ifdef PROFILING_SUPPORTED
10052     // Need to erect a GC frame so that GCs can occur without a problem
10053     // within the profiler code.
10054
10055     // Note that we don't need to worry about pId moving around since
10056     // it is a value class declared on the stack and so GC doesn't
10057     // know about it.
10058
10059     _ASSERTE (!GCHeapUtilities::GetGCHeap()->IsHeapPointer(pId));     // should be on the stack, not in the heap
10060     HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10061
10062     {
10063         BEGIN_PIN_PROFILER(CORProfilerPresent());
10064         GCX_PREEMP();
10065         if (CORProfilerTrackRemotingCookie())
10066         {
10067             g_profControlBlock.pProfInterface->GetGUID(pId);
10068             _ASSERTE(pId->Data1);
10069
10070             g_profControlBlock.pProfInterface->RemotingClientSendingMessage(pId, fIsAsync);
10071         }
10072         else
10073         {
10074             g_profControlBlock.pProfInterface->RemotingClientSendingMessage(NULL, fIsAsync);
10075         }
10076         END_PIN_PROFILER();
10077     }
10078     HELPER_METHOD_FRAME_END_POLL();
10079 #endif // PROFILING_SUPPORTED
10080 }
10081 FCIMPLEND
10082
10083
10084 FCIMPL2_VI(void, ProfilingFCallHelper::FC_RemotingClientReceivingReply, GUID id, CLR_BOOL fIsAsync)
10085 {
10086     FCALL_CONTRACT;
10087
10088 #ifdef PROFILING_SUPPORTED
10089     // Need to erect a GC frame so that GCs can occur without a problem
10090     // within the profiler code.
10091
10092     // Note that we don't need to worry about pId moving around since
10093     // it is a value class declared on the stack and so GC doesn't
10094     // know about it.
10095
10096     HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10097
10098
10099     {
10100         BEGIN_PIN_PROFILER(CORProfilerPresent());
10101         GCX_PREEMP();
10102         if (CORProfilerTrackRemotingCookie())
10103         {
10104             g_profControlBlock.pProfInterface->RemotingClientReceivingReply(&id, fIsAsync);
10105         }
10106         else
10107         {
10108             g_profControlBlock.pProfInterface->RemotingClientReceivingReply(NULL, fIsAsync);
10109         }
10110         END_PIN_PROFILER();
10111     }
10112
10113     HELPER_METHOD_FRAME_END_POLL();
10114 #endif // PROFILING_SUPPORTED
10115 }
10116 FCIMPLEND
10117
10118
10119 FCIMPL2_VI(void, ProfilingFCallHelper::FC_RemotingServerReceivingMessage, GUID id, CLR_BOOL fIsAsync)
10120 {
10121     FCALL_CONTRACT;
10122
10123 #ifdef PROFILING_SUPPORTED
10124     // Need to erect a GC frame so that GCs can occur without a problem
10125     // within the profiler code.
10126
10127     // Note that we don't need to worry about pId moving around since
10128     // it is a value class declared on the stack and so GC doesn't
10129     // know about it.
10130
10131     HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10132
10133     {
10134         BEGIN_PIN_PROFILER(CORProfilerPresent());
10135         GCX_PREEMP();
10136         if (CORProfilerTrackRemotingCookie())
10137         {
10138             g_profControlBlock.pProfInterface->RemotingServerReceivingMessage(&id, fIsAsync);
10139         }
10140         else
10141         {
10142             g_profControlBlock.pProfInterface->RemotingServerReceivingMessage(NULL, fIsAsync);
10143         }
10144         END_PIN_PROFILER();
10145     }
10146
10147     HELPER_METHOD_FRAME_END_POLL();
10148 #endif // PROFILING_SUPPORTED
10149 }
10150 FCIMPLEND
10151
10152 FCIMPL2(void, ProfilingFCallHelper::FC_RemotingServerSendingReply, GUID *pId, CLR_BOOL fIsAsync)
10153 {
10154     FCALL_CONTRACT;
10155
10156 #ifdef PROFILING_SUPPORTED
10157     // Need to erect a GC frame so that GCs can occur without a problem
10158     // within the profiler code.
10159
10160     // Note that we don't need to worry about pId moving around since
10161     // it is a value class declared on the stack and so GC doesn't
10162     // know about it.
10163
10164     HELPER_METHOD_FRAME_BEGIN_NOPOLL();
10165
10166     {
10167         BEGIN_PIN_PROFILER(CORProfilerPresent());
10168         GCX_PREEMP();
10169         if (CORProfilerTrackRemotingCookie())
10170         {
10171             g_profControlBlock.pProfInterface->GetGUID(pId);
10172             _ASSERTE(pId->Data1);
10173
10174             g_profControlBlock.pProfInterface->RemotingServerSendingReply(pId, fIsAsync);
10175         }
10176         else
10177         {
10178             g_profControlBlock.pProfInterface->RemotingServerSendingReply(NULL, fIsAsync);
10179         }
10180         END_PIN_PROFILER();
10181     }
10182
10183     HELPER_METHOD_FRAME_END_POLL();
10184 #endif // PROFILING_SUPPORTED
10185 }
10186 FCIMPLEND
10187
10188
10189 //*******************************************************************************************
10190 // These do a lot of work for us, setting up Frames, gathering arg info and resolving generics.
10191   //*******************************************************************************************
10192
10193 HCIMPL2(EXTERN_C void, ProfileEnter, UINT_PTR clientData, void * platformSpecificHandle)
10194 {
10195     FCALL_CONTRACT;
10196
10197 #ifdef PROFILING_SUPPORTED
10198
10199 #ifdef PROF_TEST_ONLY_FORCE_ELT
10200     // If this test-only flag is set, it's possible we might not have a profiler
10201     // attached, or might not have any of the hooks set. See
10202     // code:ProfControlBlock#TestOnlyELT
10203     if (g_profControlBlock.fTestOnlyForceEnterLeave)
10204     {
10205         if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10206             (
10207                 (g_profControlBlock.pProfInterface->GetEnterHook()          == NULL) &&
10208                 (g_profControlBlock.pProfInterface->GetEnter2Hook()         == NULL) &&
10209                 (g_profControlBlock.pProfInterface->GetEnter3Hook()         == NULL) &&
10210                 (g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() == NULL)
10211             )
10212            )
10213         {
10214             return;
10215         }
10216     }       
10217 #endif // PROF_TEST_ONLY_FORCE_ELT
10218
10219     // ELT3 Fast-Path hooks should be NULL when ELT intermediary is used.
10220     _ASSERTE(g_profControlBlock.pProfInterface->GetEnter3Hook() == NULL);
10221     _ASSERTE(GetThread()->PreemptiveGCDisabled());
10222     _ASSERTE(platformSpecificHandle != NULL);
10223
10224     // Set up a frame
10225     HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
10226
10227     // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10228     // frame, like we're about to do.
10229     SetCallbackStateFlagsHolder csf(
10230         COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10231    
10232     COR_PRF_ELT_INFO_INTERNAL eltInfo;
10233     eltInfo.platformSpecificHandle = platformSpecificHandle;
10234
10235     //
10236     // CLR v4 Slow-Path ELT
10237     //
10238     if (g_profControlBlock.pProfInterface->GetEnter3WithInfoHook() != NULL)
10239     {
10240         FunctionIDOrClientID functionIDOrClientID;
10241         functionIDOrClientID.clientID = clientData;
10242         g_profControlBlock.pProfInterface->GetEnter3WithInfoHook()(
10243             functionIDOrClientID, 
10244             (COR_PRF_ELT_INFO)&eltInfo);
10245         goto LExit;
10246     }
10247
10248     if (g_profControlBlock.pProfInterface->GetEnter2Hook() != NULL)
10249     {
10250         // We have run out of heap memory, so the content of the mapping table becomes stale.
10251         // All Whidbey ETL hooks must be turned off.
10252         if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10253         {
10254             goto LExit;
10255         }
10256
10257         // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes 
10258         // instead of using clientID because the profiler may map several functionIDs to a clientID to 
10259         // do things like code coverage analysis.  FunctionID to clientID has the one-on-one relationship, 
10260         // while the reverse may not have this one-on-one mapping.  Therefore, FunctionID is used as the 
10261         // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10262         FunctionID functionId = clientData;
10263         _ASSERTE(functionId != NULL);
10264         clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10265
10266         //
10267         // Whidbey Fast-Path ELT
10268         //
10269         if (CORProfilerELT2FastPathEnterEnabled())
10270         {
10271             g_profControlBlock.pProfInterface->GetEnter2Hook()(
10272                 functionId,
10273                 clientData, 
10274                 NULL,
10275                 NULL);
10276             goto LExit;
10277         }
10278
10279         //
10280         // Whidbey Slow-Path ELT
10281         //
10282         ProfileSetFunctionIDInPlatformSpecificHandle(platformSpecificHandle, functionId);
10283
10284         COR_PRF_FRAME_INFO frameInfo = NULL;
10285         COR_PRF_FUNCTION_ARGUMENT_INFO * pArgumentInfo = NULL;
10286         ULONG ulArgInfoSize = 0;
10287
10288         if (CORProfilerFunctionArgsEnabled())
10289         {
10290             // The loader won't trigger a GC or throw for already loaded argument types.
10291             ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
10292
10293             //
10294             // Find the method this is referring to, so we can get the signature
10295             //
10296             MethodDesc * pMethodDesc = FunctionIdToMethodDesc(functionId);
10297             MetaSig metaSig(pMethodDesc);
10298
10299             NewHolder<ProfileArgIterator> pProfileArgIterator;
10300
10301             {
10302                 // Can handle E_OUTOFMEMORY from ProfileArgIterator.
10303                 FAULT_NOT_FATAL();
10304
10305                 pProfileArgIterator = new (nothrow) ProfileArgIterator(&metaSig, platformSpecificHandle);
10306
10307                 if (pProfileArgIterator == NULL)
10308                 {
10309                     goto LExit;
10310                 }
10311             }
10312
10313             ULONG32 count = pProfileArgIterator->GetNumArgs();
10314
10315             if (metaSig.HasThis())
10316             {
10317                 count++;
10318             }
10319             
10320             ulArgInfoSize = sizeof(COR_PRF_FUNCTION_ARGUMENT_INFO) + count * sizeof(COR_PRF_FUNCTION_ARGUMENT_RANGE);
10321             pArgumentInfo = (COR_PRF_FUNCTION_ARGUMENT_INFO *)_alloca(ulArgInfoSize);
10322         }
10323
10324         HRESULT hr = ProfilingGetFunctionEnter3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo, &ulArgInfoSize, pArgumentInfo);
10325
10326         _ASSERTE(hr == S_OK);
10327         g_profControlBlock.pProfInterface->GetEnter2Hook()(functionId, clientData, frameInfo, pArgumentInfo);
10328
10329         goto LExit;
10330     }
10331
10332
10333     // We will not be here unless the jit'd or ngen'd function we're about to enter
10334     // was backpatched with this wrapper around the profiler's hook, and that
10335     // wouldn't have happened unless the profiler supplied us with a hook
10336     // in the first place.  (Note that SetEnterLeaveFunctionHooks* will return
10337     // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10338     // its mind about where the hooks are.)
10339     _ASSERTE(g_profControlBlock.pProfInterface->GetEnterHook() != NULL);
10340
10341     // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10342     // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10343     // to enable the jitter to add enter/leave callouts independently of whether
10344     // the profiler actually has enter/leave hooks.  (If the profiler has no such hooks,
10345     // the callouts quickly return and do nothing.)
10346
10347     //
10348     // Everett ELT
10349     //
10350     {
10351         g_profControlBlock.pProfInterface->GetEnterHook()((FunctionID)clientData);
10352     }
10353
10354 LExit:
10355     ;
10356
10357     HELPER_METHOD_FRAME_END();      // Un-link the frame
10358
10359 #endif // PROFILING_SUPPORTED
10360 }
10361 HCIMPLEND
10362
10363 HCIMPL2(EXTERN_C void, ProfileLeave, UINT_PTR clientData, void * platformSpecificHandle)
10364 {
10365     FCALL_CONTRACT;
10366
10367     FC_GC_POLL_NOT_NEEDED();            // we pulse GC mode, so we are doing a poll
10368
10369 #ifdef PROFILING_SUPPORTED
10370
10371 #ifdef PROF_TEST_ONLY_FORCE_ELT
10372     // If this test-only flag is set, it's possible we might not have a profiler
10373     // attached, or might not have any of the hooks set. See
10374     // code:ProfControlBlock#TestOnlyELT
10375     if (g_profControlBlock.fTestOnlyForceEnterLeave)
10376     {
10377         if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10378             (
10379                 (g_profControlBlock.pProfInterface->GetLeaveHook()          == NULL) &&
10380                 (g_profControlBlock.pProfInterface->GetLeave2Hook()         == NULL) &&
10381                 (g_profControlBlock.pProfInterface->GetLeave3Hook()         == NULL) &&
10382                 (g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() == NULL)
10383             )
10384            )
10385         {
10386             return;
10387         }
10388     }
10389 #endif // PROF_TEST_ONLY_FORCE_ELT
10390
10391     // ELT3 Fast-Path hooks should be NULL when ELT intermediary is used.
10392     _ASSERTE(g_profControlBlock.pProfInterface->GetLeave3Hook() == NULL);
10393     _ASSERTE(GetThread()->PreemptiveGCDisabled());
10394     _ASSERTE(platformSpecificHandle != NULL);
10395
10396     // Set up a frame
10397     HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2); 
10398
10399     // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10400     // frame, like we're about to do.
10401     SetCallbackStateFlagsHolder csf(
10402         COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10403     
10404     COR_PRF_ELT_INFO_INTERNAL eltInfo;
10405     eltInfo.platformSpecificHandle = platformSpecificHandle;
10406     
10407     //
10408     // CLR v4 Slow-Path ELT
10409     //
10410     if (g_profControlBlock.pProfInterface->GetLeave3WithInfoHook() != NULL)
10411     {
10412         FunctionIDOrClientID functionIDOrClientID;
10413         functionIDOrClientID.clientID = clientData;
10414         g_profControlBlock.pProfInterface->GetLeave3WithInfoHook()(
10415             functionIDOrClientID, 
10416             (COR_PRF_ELT_INFO)&eltInfo);
10417         goto LExit;
10418     }
10419
10420     if (g_profControlBlock.pProfInterface->GetLeave2Hook() != NULL)
10421     {
10422         // We have run out of heap memory, so the content of the mapping table becomes stale.
10423         // All Whidbey ETL hooks must be turned off.
10424         if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10425         {
10426             goto LExit;
10427         }
10428
10429         // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes 
10430         // instead of using clientID because the profiler may map several functionIDs to a clientID to 
10431         // do things like code coverage analysis.  FunctionID to clientID has the one-on-one relationship, 
10432         // while the reverse may not have this one-on-one mapping.  Therefore, FunctionID is used as the 
10433         // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10434         FunctionID functionId = clientData;
10435         _ASSERTE(functionId != NULL);
10436         clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10437
10438         //
10439         // Whidbey Fast-Path ELT
10440         //
10441         if (CORProfilerELT2FastPathLeaveEnabled())
10442         {
10443             g_profControlBlock.pProfInterface->GetLeave2Hook()(
10444                 functionId,
10445                 clientData, 
10446                 NULL,
10447                 NULL);
10448             goto LExit;
10449         }
10450
10451         //
10452         // Whidbey Slow-Path ELT
10453         //
10454         COR_PRF_FRAME_INFO frameInfo = NULL;
10455         COR_PRF_FUNCTION_ARGUMENT_RANGE argumentRange;
10456
10457         HRESULT hr = ProfilingGetFunctionLeave3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo, &argumentRange);
10458         _ASSERTE(hr == S_OK);
10459
10460         g_profControlBlock.pProfInterface->GetLeave2Hook()(functionId, clientData, frameInfo, &argumentRange);
10461         goto LExit;
10462     }
10463
10464     // We will not be here unless the jit'd or ngen'd function we're about to leave
10465     // was backpatched with this wrapper around the profiler's hook, and that
10466     // wouldn't have happened unless the profiler supplied us with a hook
10467     // in the first place.  (Note that SetEnterLeaveFunctionHooks* will return
10468     // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10469     // its mind about where the hooks are.)
10470     _ASSERTE(g_profControlBlock.pProfInterface->GetLeaveHook() != NULL);
10471
10472     // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10473     // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10474     // to enable the jitter to add enter/leave callouts independently of whether
10475     // the profiler actually has enter/leave hooks.  (If the profiler has no such hooks,
10476     // the callouts quickly return and do nothing.)
10477
10478     //
10479     // Everett ELT
10480     //
10481     {
10482         g_profControlBlock.pProfInterface->GetLeaveHook()((FunctionID)clientData);
10483     }
10484
10485 LExit:
10486
10487     ;
10488
10489     HELPER_METHOD_FRAME_END();      // Un-link the frame
10490
10491 #endif // PROFILING_SUPPORTED
10492 }
10493 HCIMPLEND
10494
10495 HCIMPL2(EXTERN_C void, ProfileTailcall, UINT_PTR clientData, void * platformSpecificHandle)
10496 {
10497     FCALL_CONTRACT;
10498
10499     FC_GC_POLL_NOT_NEEDED();            // we pulse GC mode, so we are doing a poll
10500
10501 #ifdef PROFILING_SUPPORTED
10502
10503 #ifdef PROF_TEST_ONLY_FORCE_ELT
10504     // If this test-only flag is set, it's possible we might not have a profiler
10505     // attached, or might not have any of the hooks set. See
10506     // code:ProfControlBlock#TestOnlyELT
10507     if (g_profControlBlock.fTestOnlyForceEnterLeave)
10508     {
10509         if ((g_profControlBlock.pProfInterface.Load() == NULL) ||
10510             (
10511                 (g_profControlBlock.pProfInterface->GetTailcallHook()          == NULL) &&
10512                 (g_profControlBlock.pProfInterface->GetTailcall2Hook()         == NULL) &&
10513                 (g_profControlBlock.pProfInterface->GetTailcall3Hook()         == NULL) &&
10514                 (g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() == NULL)
10515             )
10516            )
10517         {
10518             return;
10519         }
10520     }
10521 #endif // PROF_TEST_ONLY_FORCE_ELT
10522
10523     // ELT3 fast-path hooks should be NULL when ELT intermediary is used.
10524     _ASSERTE(g_profControlBlock.pProfInterface->GetTailcall3Hook() == NULL);
10525     _ASSERTE(GetThread()->PreemptiveGCDisabled());
10526     _ASSERTE(platformSpecificHandle != NULL);
10527
10528     // Set up a frame
10529     HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_CAPTURE_DEPTH_2);
10530
10531     // Our contract is FCALL_CONTRACT, which is considered triggers if you set up a
10532     // frame, like we're about to do.
10533     SetCallbackStateFlagsHolder csf(
10534         COR_PRF_CALLBACKSTATE_INCALLBACK | COR_PRF_CALLBACKSTATE_IN_TRIGGERS_SCOPE);
10535     
10536     COR_PRF_ELT_INFO_INTERNAL eltInfo;
10537     eltInfo.platformSpecificHandle = platformSpecificHandle;
10538
10539     //
10540     // CLR v4 Slow-Path ELT
10541     //
10542     if (g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook() != NULL)
10543     {
10544         FunctionIDOrClientID functionIDOrClientID;
10545         functionIDOrClientID.clientID = clientData;
10546         g_profControlBlock.pProfInterface->GetTailcall3WithInfoHook()(
10547             functionIDOrClientID, 
10548             (COR_PRF_ELT_INFO)&eltInfo);
10549         goto LExit;
10550     }
10551
10552     if (g_profControlBlock.pProfInterface->GetTailcall2Hook() != NULL)
10553     {
10554         // We have run out of heap memory, so the content of the mapping table becomes stale.
10555         // All Whidbey ETL hooks must be turned off.
10556         if (!g_profControlBlock.pProfInterface->IsClientIDToFunctionIDMappingEnabled())
10557         {
10558             goto LExit;
10559         }
10560
10561         // If ELT2 is in use, FunctionID will be returned to the JIT to be embedded into the ELT3 probes 
10562         // instead of using clientID because the profiler may map several functionIDs to a clientID to 
10563         // do things like code coverage analysis.  FunctionID to clientID has the one-on-one relationship, 
10564         // while the reverse may not have this one-on-one mapping.  Therefore, FunctionID is used as the 
10565         // key to retrieve the corresponding clientID from the internal FunctionID hash table.
10566         FunctionID functionId = clientData;
10567         _ASSERTE(functionId != NULL);
10568         clientData = g_profControlBlock.pProfInterface->LookupClientIDFromCache(functionId);
10569
10570         //
10571         // Whidbey Fast-Path ELT
10572         //
10573         if (CORProfilerELT2FastPathTailcallEnabled())
10574         {
10575             g_profControlBlock.pProfInterface->GetTailcall2Hook()(
10576                 functionId,
10577                 clientData, 
10578                 NULL);
10579             goto LExit;
10580         }
10581
10582         //
10583         // Whidbey Slow-Path ELT
10584         //
10585         COR_PRF_FRAME_INFO frameInfo = NULL;
10586
10587         HRESULT hr = ProfilingGetFunctionTailcall3Info(functionId, (COR_PRF_ELT_INFO)&eltInfo, &frameInfo);
10588         _ASSERTE(hr == S_OK);
10589
10590         g_profControlBlock.pProfInterface->GetTailcall2Hook()(functionId, clientData, frameInfo);
10591         goto LExit;
10592     }
10593
10594     // We will not be here unless the jit'd or ngen'd function we're about to tailcall
10595     // was backpatched with this wrapper around the profiler's hook, and that
10596     // wouldn't have happened unless the profiler supplied us with a hook
10597     // in the first place.  (Note that SetEnterLeaveFunctionHooks* will return
10598     // an error unless it's called in the profiler's Initialize(), so a profiler can't change
10599     // its mind about where the hooks are.)
10600     _ASSERTE(g_profControlBlock.pProfInterface->GetTailcallHook() != NULL);
10601
10602     // Note that we cannot assert CORProfilerTrackEnterLeave() (i.e., profiler flag
10603     // COR_PRF_MONITOR_ENTERLEAVE), because the profiler may decide whether
10604     // to enable the jitter to add enter/leave callouts independently of whether
10605     // the profiler actually has enter/leave hooks.  (If the profiler has no such hooks,
10606     // the callouts quickly return and do nothing.)
10607     
10608     //
10609     // Everett ELT
10610     //
10611     g_profControlBlock.pProfInterface->GetTailcallHook()((FunctionID)clientData);
10612
10613 LExit:
10614
10615     ;
10616
10617     HELPER_METHOD_FRAME_END();      // Un-link the frame
10618
10619 #endif // PROFILING_SUPPORTED
10620 }
10621 HCIMPLEND
10622