summaryrefslogtreecommitdiff
path: root/src/vm/contexts.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/contexts.cpp')
-rw-r--r--src/vm/contexts.cpp939
1 files changed, 939 insertions, 0 deletions
diff --git a/src/vm/contexts.cpp b/src/vm/contexts.cpp
new file mode 100644
index 0000000000..eb957570ea
--- /dev/null
+++ b/src/vm/contexts.cpp
@@ -0,0 +1,939 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// Contexts.CPP
+//
+
+//
+// Implementation for class Context
+//
+
+
+#include "common.h"
+
+#ifdef FEATURE_REMOTING
+
+#include "context.h"
+#include "excep.h"
+#include "field.h"
+#include "remoting.h"
+#include "perfcounters.h"
+#include "specialstatics.h"
+#include "appdomain.inl"
+
+#ifdef FEATURE_COMINTEROP
+#include "runtimecallablewrapper.h"
+#endif // FEATURE_COMINTEROP
+
+#ifndef DACCESS_COMPILE
+
+#define CONTEXT_SIGNATURE (0x2b585443) // CTX+
+#define CONTEXT_DESTROYED (0x2d585443) // CTX-
+
+// Lock for safe operations
+CrstStatic Context::s_ContextCrst;
+
+
+Context::Context(AppDomain *pDomain)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pDomain));
+ }
+ CONTRACTL_END;
+
+ m_pDomain = pDomain;
+ m_Signature = CONTEXT_SIGNATURE;
+
+ // This needs to be a LongWeakHandle since we want to be able
+ // to run finalizers on Proxies while the Context itself
+ // unreachable. When running the finalizer we will have to
+ // transition into the context like a regular remote call.
+ // If this is a short weak handle, it ceases being updated
+ // as soon as the context is unreachable. By making it a strong
+ // handle, it is updated till the context::finalize is run.
+
+ m_ExposedObjectHandle = pDomain->CreateLongWeakHandle(NULL);
+
+ // Set the pointers to the static data storage
+ m_pUnsharedStaticData = NULL;
+ m_pSharedStaticData = NULL;
+
+ COUNTER_ONLY(GetPerfCounters().m_Context.cContexts++);
+}
+
+Context::~Context()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ BOOL fADUnloaded = m_pDomain->NoAccessToHandleTable();
+ if (!fADUnloaded)
+ {
+ DestroyLongWeakHandle(m_ExposedObjectHandle);
+ }
+
+ m_pDomain = NULL;
+ m_Signature = CONTEXT_DESTROYED;
+
+ // Cleanup the static data storage
+ if(m_pUnsharedStaticData)
+ {
+ for(WORD i = 0; i < m_pUnsharedStaticData->cElem; i++)
+ {
+ delete [] (BYTE *) (m_pUnsharedStaticData->dataPtr[i]);
+ }
+ delete [] m_pUnsharedStaticData;
+ m_pUnsharedStaticData = NULL;
+ }
+
+ if(m_pSharedStaticData)
+ {
+ for(WORD i = 0; i < m_pSharedStaticData->cElem; i++)
+ {
+ delete [] (BYTE *) (m_pSharedStaticData->dataPtr[i]);
+ }
+ delete [] m_pSharedStaticData;
+ m_pSharedStaticData = NULL;
+ }
+
+ // Destroy pinning handles associated with this context
+ ObjectHandleList::NodeType* pHandleNode;
+ while ((pHandleNode = m_PinnedContextStatics.UnlinkHead() ) != NULL)
+ {
+ if (!fADUnloaded)
+ {
+ DestroyPinningHandle(pHandleNode->data);
+ }
+ delete pHandleNode;
+ }
+
+ COUNTER_ONLY(GetPerfCounters().m_Context.cContexts--);
+}
+
+Context* Context::CreateNewContext(AppDomain *pDomain)
+{
+ CONTRACT (Context*)
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pDomain));
+ }
+ CONTRACT_END;
+
+ Context *p = new Context(pDomain);
+ RETURN p;
+}
+
+void Context::Initialize()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ // Initialize the context critical section
+ s_ContextCrst.Init(CrstContexts, (CrstFlags)(CRST_REENTRANCY|CRST_HOST_BREAKABLE));
+}
+
+BOOL Context::ValidateContext(Context *pCtx)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ SO_TOLERANT;
+ PRECONDITION(CheckPointer(pCtx));
+ }
+ CONTRACTL_END;
+
+ BOOL bRet = FALSE;
+
+ EX_TRY
+ {
+ if (pCtx->m_Signature == CONTEXT_SIGNATURE)
+ bRet = TRUE;
+ }
+ EX_CATCH
+ {
+ // Swallow exceptions - if not a valid ctx, just return false.
+ }
+ EX_END_CATCH(RethrowTerminalExceptions);
+
+ return bRet;
+}
+
+// if the object we are creating is a proxy to another appdomain, want to create the wrapper for the
+// new object in the appdomain of the proxy target
+Context* Context::GetExecutionContext(OBJECTREF pObj)
+{
+ CONTRACT (Context*)
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(pObj != NULL);
+ POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+ }
+ CONTRACT_END;
+
+ Context *pContext = NULL;
+ if (pObj->IsTransparentProxy())
+ pContext = CRemotingServices::GetServerContextForProxy(pObj);
+ if (pContext == NULL)
+ pContext = GetAppDomain()->GetDefaultContext();
+
+ RETURN pContext;
+}
+
+OBJECTREF Context::GetExposedObject()
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ if (ObjectFromHandle(m_ExposedObjectHandle) == NULL)
+ {
+ // This call should fault in the managed context for the thread
+ MethodDescCallSite getCurrentContext(METHOD__THREAD__GET_CURRENT_CONTEXT);
+ CONTEXTBASEREF ctx = (CONTEXTBASEREF) getCurrentContext.Call_RetOBJECTREF((ARG_SLOT*)NULL);
+
+ GCPROTECT_BEGIN(ctx);
+ {
+ // Take a lock to make sure that only one thread creates the object.
+ // This locking may be too severe!
+ CrstHolder ch(&s_ContextCrst);
+
+ // Check to see if another thread has not already created the exposed object.
+ if (ObjectFromHandle(m_ExposedObjectHandle) == NULL)
+ {
+ // Keep a weak reference to the exposed object.
+ StoreObjectInHandle(m_ExposedObjectHandle, (OBJECTREF) ctx);
+
+ ctx->SetInternalContext(this);
+ }
+ }
+ GCPROTECT_END();
+
+ }
+ return ObjectFromHandle(m_ExposedObjectHandle);
+}
+
+void Context::SetExposedObject(OBJECTREF exposed)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(exposed != NULL);
+ PRECONDITION(ObjectFromHandle(m_ExposedObjectHandle) == NULL);
+ }
+ CONTRACTL_END;
+
+ StoreObjectInHandle(m_ExposedObjectHandle, exposed);
+}
+
+// This is called by EE to transition into a context(possibly in
+// another appdomain) and execute the method Context::ExecuteCallBack
+// with the private data provided to this method
+void Context::RequestCallBack(ADID appDomainID, Context* targetCtxID, void* privateData)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(targetCtxID));
+ PRECONDITION(CheckPointer(privateData));
+ PRECONDITION(ValidateContext((Context*)targetCtxID));
+ }
+ CONTRACTL_END;
+ // a warning: don't touch targetCtxID until you verified appDomainID,
+ // unless the latter is CURRENT_APPDOMAIN_ID
+
+ // Get the current context of the thread. This is assumed as
+ // the context where the request originated
+ Context *pCurrCtx;
+ pCurrCtx = GetCurrentContext();
+
+ // Check that the target context is not the same (presumably the caller has checked for it).
+ _ASSERTE(pCurrCtx != targetCtxID);
+
+ // Check if we might be going to a context in another appDomain.
+ ADID targetDomainID;
+
+ if (appDomainID == CURRENT_APPDOMAIN_ID)
+ {
+ targetDomainID = (ADID)0;
+ _ASSERTE(targetCtxID->GetDomain()==::GetAppDomain());
+ }
+ else
+ {
+ targetDomainID=appDomainID;
+#ifdef _DEBUG
+ AppDomainFromIDHolder ad(appDomainID, FALSE);
+ if (!ad.IsUnloaded())
+ _ASSERTE(targetCtxID->GetDomain()->GetId()==appDomainID);
+#endif
+ }
+
+ // we need to be co-operative mode for jitting
+ GCX_COOP();
+
+ MethodDescCallSite callback(METHOD__CONTEXT__CALLBACK);
+
+ ARG_SLOT args[3];
+ args[0] = PtrToArgSlot(targetCtxID);
+ args[1] = PtrToArgSlot(privateData);
+ args[2] = (ARG_SLOT) (size_t)targetDomainID.m_dwId;
+
+ callback.Call(args);
+}
+
+/*** Definitions of callback executions for the various callbacks that are known to EE ***/
+
+// Callback for waits on waithandle
+void Context::ExecuteWaitCallback(WaitArgs* waitArgs)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(waitArgs));
+ }
+ CONTRACTL_END;
+
+ Thread* pCurThread = GetThread();
+ _ASSERTE(pCurThread != NULL);
+
+ // DoAppropriateWait switches to preemptive GC before entering the wait
+ *(waitArgs->pResult) = pCurThread->DoAppropriateWait( waitArgs->numWaiters,
+ waitArgs->waitHandles,
+ waitArgs->waitAll,
+ waitArgs->millis,
+ waitArgs->alertable?WaitMode_Alertable:WaitMode_None);
+}
+
+// Callback for monitor wait on objects
+void Context::ExecuteMonitorWaitCallback(MonitorWaitArgs* waitArgs)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(waitArgs));
+ }
+ CONTRACTL_END;
+
+ Thread* pCurThread = GetThread();
+ _ASSERTE(pCurThread != NULL);
+
+ GCX_PREEMP();
+
+ *(waitArgs->pResult) = pCurThread->Block(waitArgs->millis,
+ waitArgs->syncState);
+}
+
+// Callback for signalandwait on waithandles
+void Context::ExecuteSignalAndWaitCallback(SignalAndWaitArgs* signalAndWaitArgs)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(signalAndWaitArgs));
+ }
+ CONTRACTL_END;
+
+ Thread* pCurThread = GetThread();
+ _ASSERTE(pCurThread != NULL);
+
+ // DoAppropriateWait switches to preemptive GC before entering the wait
+ *(signalAndWaitArgs->pResult) = pCurThread->DoSignalAndWait( signalAndWaitArgs->waitHandles,
+ signalAndWaitArgs->millis,
+ signalAndWaitArgs->alertable);
+}
+
+//+----------------------------------------------------------------------------
+//
+// Method: Context::GetStaticFieldAddress private
+//
+// Synopsis: Get the address of the field relative to the current context.
+// If an address has not been assigned yet then create one.
+//
+
+//
+//+----------------------------------------------------------------------------
+LPVOID Context::GetStaticFieldAddress(FieldDesc *pFD)
+{
+ CONTRACT (LPVOID)
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pFD));
+ PRECONDITION(!s_ContextCrst.OwnedByCurrentThread());
+ POSTCONDITION(CheckPointer(RETVAL));
+ }
+ CONTRACT_END;
+
+ LPVOID pvAddress = NULL;
+ Context* pCtx = NULL;
+ // for static field the MethodTable is exact even for generic classes
+ MethodTable* pMT = pFD->GetEnclosingMethodTable();
+ BOOL fIsShared = pMT->IsDomainNeutral();
+ DWORD dwClassOffset = pMT->GetContextStaticsOffset();
+ DWORD currElem = 0;
+ STATIC_DATA* pData;
+
+ // NOTE: if you change this method, you must also change
+ // GetStaticFieldAddrNoCreate below.
+
+ if (dwClassOffset == (DWORD)-1)
+ {
+ dwClassOffset = pMT->AllocateContextStaticsOffset();
+ }
+
+ // Retrieve the current context
+ pCtx = GetCurrentContext();
+ _ASSERTE(NULL != pCtx);
+
+ // Acquire the context lock before accessing the static data pointer
+ {
+ CrstHolder ch(&s_ContextCrst);
+
+ if(!fIsShared)
+ pData = pCtx->m_pUnsharedStaticData;
+ else
+ pData = pCtx->m_pSharedStaticData;
+
+ if(NULL != pData)
+ currElem = pData->cElem;
+
+ // Check whether we have allocated space for storing a pointer to
+ // this class' context static store
+ if(dwClassOffset >= currElem)
+ {
+ // Allocate space for storing pointers
+ DWORD dwNewElem = (currElem == 0 ? 4 : currElem*2);
+
+ // Ensure that we grow to a size larger than the index we intend to use
+ while (dwNewElem <= dwClassOffset)
+ dwNewElem = 2*dwNewElem;
+
+ STATIC_DATA *pNew = (STATIC_DATA *)new BYTE[sizeof(STATIC_DATA) + dwNewElem*sizeof(LPVOID)];
+
+ // Set the new count.
+ pNew->cElem = dwNewElem;
+
+ if(NULL != pData)
+ {
+ // Copy the old data into the new data
+ memcpy(&pNew->dataPtr[0], &pData->dataPtr[0], currElem*sizeof(LPVOID));
+
+ // Delete the old data
+ delete [] (BYTE*) pData;
+ }
+
+ // Zero init any new elements.
+ ZeroMemory(&pNew->dataPtr[currElem], (dwNewElem - currElem)* sizeof(LPVOID));
+
+ // Update the locals
+ pData = pNew;
+
+ // Reset the pointers in the context object to point to the
+ // new memory
+ if(!fIsShared)
+ pCtx->m_pUnsharedStaticData = pData;
+ else
+ pCtx->m_pSharedStaticData = pData;
+ }
+
+ _ASSERTE(NULL != pData);
+
+ // Check whether we have to allocate space for
+ // the context local statics of this class
+ if(NULL == pData->dataPtr[dwClassOffset])
+ {
+ DWORD dwSize = pMT->GetContextStaticsSize();
+
+ // Allocate memory for context static fields
+ LPBYTE pFields = new BYTE[dwSize];
+
+ // Initialize the memory allocated for the fields
+ ZeroMemory(pFields, dwSize);
+
+ pData->dataPtr[dwClassOffset] = pFields;
+ }
+
+ _ASSERTE(NULL != pData->dataPtr[dwClassOffset]);
+
+ pvAddress = (LPVOID)((LPBYTE)pData->dataPtr[dwClassOffset] + pFD->GetOffset());
+
+ // For object and value class fields we have to allocate storage in the
+ // __StaticContainer class in the managed heap
+ if(pFD->IsObjRef() || pFD->IsByValue())
+ {
+ // in this case *pvAddress == bucket|index
+ int *pSlot = (int*)pvAddress;
+ pvAddress = NULL;
+ pCtx->GetStaticFieldAddressSpecial(pFD, pMT, pSlot, &pvAddress);
+
+ if (pFD->IsByValue())
+ {
+ _ASSERTE(pvAddress != NULL);
+ pvAddress = (*((OBJECTREF*)pvAddress))->GetData();
+ }
+ // ************************************************
+ // ************** WARNING *************************
+ // Do not provoke GC from here to the point JIT gets
+ // pvAddress back
+ // ************************************************
+ _ASSERTE(*pSlot > 0);
+ }
+ }
+
+ RETURN pvAddress;
+}
+
+
+//+----------------------------------------------------------------------------
+//
+// Method: Context::GetStaticFieldAddressSpecial private
+//
+// Synopsis: Allocate an entry in the __StaticContainer class in the
+// managed heap for static objects and value classes
+//
+
+//
+//+----------------------------------------------------------------------------
+
+// NOTE: At one point we used to allocate these in the long lived handle table
+// which is per-appdomain. However, that causes them to get rooted and not
+// cleaned up until the appdomain gets unloaded. This is not very desirable
+// since a context static object may hold a reference to the context itself or
+// to a proxy in the context causing a whole lot of garbage to float around.
+// Now (2/13/01) these are allocated from a managed structure rooted in each
+// managed context.
+
+void Context::GetStaticFieldAddressSpecial(FieldDesc *pFD, MethodTable *pMT, int *pSlot, LPVOID *ppvAddress)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(pFD));
+ PRECONDITION(CheckPointer(pMT));
+ PRECONDITION(CheckPointer(pSlot));
+ PRECONDITION(CheckPointer(ppvAddress));
+ }
+ CONTRACTL_END;
+
+ OBJECTREF *pObjRef = NULL;
+ BOOL bNewSlot = (*pSlot == 0);
+
+ if (bNewSlot)
+ {
+ // ! this line will trigger a GC, don't move it down
+ // ! without protecting the args[] and other OBJECTREFS
+ OBJECTREF orThis = GetExposedObject();;
+ GCPROTECT_BEGIN(orThis);
+
+ MethodDescCallSite reserveSlot(METHOD__CONTEXT__RESERVE_SLOT, &orThis);
+
+ // We need to assign a location for this static field.
+ // Call the managed helper
+ ARG_SLOT args[1] =
+ {
+ ObjToArgSlot(orThis)
+ };
+
+ // The managed ReserveSlot methods counts on this!
+ _ASSERTE(s_ContextCrst.OwnedByCurrentThread());
+ _ASSERTE(args[0] != 0);
+
+ *pSlot = reserveSlot.Call_RetI4(args);
+
+ _ASSERTE(*pSlot>0);
+
+ GCPROTECT_END();
+
+
+ // to a boxed version of the value class.This allows the standard GC
+ // algorithm to take care of internal pointers in the value class.
+ if (pFD->IsByValue())
+ {
+ // Extract the type of the field
+ TypeHandle th = pFD->GetFieldTypeHandleThrowing();
+
+ OBJECTHANDLE oh;
+ OBJECTREF obj = MethodTable::AllocateStaticBox(th.GetMethodTable(), pMT->HasFixedAddressVTStatics(), &oh);
+ pObjRef = (OBJECTREF*)CalculateAddressForManagedStatic(*pSlot);
+
+ if (oh != NULL)
+ {
+ ObjectHandleList::NodeType* pNewNode = new ObjectHandleList::NodeType(oh);
+ m_PinnedContextStatics.LinkHead(pNewNode);
+ }
+
+ SetObjectReference( pObjRef, obj, GetAppDomain() );
+ }
+ else
+ {
+ pObjRef = (OBJECTREF*)CalculateAddressForManagedStatic(*pSlot);
+ }
+ }
+ else
+ {
+ // If the field already has a location assigned we go through here
+ pObjRef = (OBJECTREF*)CalculateAddressForManagedStatic(*pSlot);
+ }
+
+ *(ULONG_PTR *)ppvAddress = (ULONG_PTR)pObjRef;
+}
+
+// This is called by the managed context constructor
+FCIMPL2(void, Context::SetupInternalContext, ContextBaseObject* pThisUNSAFE, CLR_BOOL bDefault)
+{
+ CONTRACTL
+ {
+ FCALL_CHECK;
+ PRECONDITION(pThisUNSAFE != NULL);
+ PRECONDITION(pThisUNSAFE->m_internalContext == NULL);
+ }
+ CONTRACTL_END;
+
+ CONTEXTBASEREF pThis = (CONTEXTBASEREF) pThisUNSAFE;
+ HELPER_METHOD_FRAME_BEGIN_1(pThis);
+
+ Context *pCtx;
+
+ if (bDefault)
+ {
+ // We have to hook this up with the internal default
+ // context for the current appDomain
+ pCtx = GetThread()->GetDomain()->GetDefaultContext();
+ }
+ else
+ {
+ // Create the unmanaged backing context object
+ pCtx = Context::CreateNewContext(GetThread()->GetDomain());
+ }
+
+ // Set the managed & unmanaged objects to point at each other.
+ pThis->SetInternalContext(pCtx);
+ pCtx->SetExposedObject((OBJECTREF)pThis);
+
+ // Set the AppDomain field in the Managed context object
+ pThis->SetExposedDomain(GetThread()->GetDomain()->GetExposedObject());
+
+ if(bDefault)
+ ((APPDOMAINREF)GetThread()->GetDomain()->GetExposedObject())->SetDefaultContext(pThis);
+
+ COUNTER_ONLY(GetPerfCounters().m_Context.cContexts++);
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+// This is called by the managed context finalizer
+FCIMPL1(void, Context::CleanupInternalContext, ContextBaseObject* pThisUNSAFE)
+{
+ CONTRACTL
+ {
+ FCALL_CHECK;
+ PRECONDITION(pThisUNSAFE != NULL);
+ }
+ CONTRACTL_END;
+
+ CONTEXTBASEREF pThis = (CONTEXTBASEREF) pThisUNSAFE;
+ HELPER_METHOD_FRAME_BEGIN_1(pThis);
+
+ CONTEXTBASEREF refCtx = pThis;
+
+ Context *pCtx = refCtx->m_internalContext;
+ _ASSERTE(pCtx != NULL);
+
+ if (ValidateContext(pCtx))
+ {
+ LOG((LF_APPDOMAIN, LL_INFO1000, "Context::CleanupInternalContext: %8.8x, %8.8x\n", OBJECTREFToObject(refCtx), pCtx));
+ Context::FreeContext(pCtx);
+ }
+
+ COUNTER_ONLY(GetPerfCounters().m_Context.cContexts--);
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+
+// This is where a call back request made by EE in Context::RequestCallBack
+// actually gets "executed".
+// At this point we have done a real context transition from the threads
+// context when RequestCallBack was called to the destination context.
+FCIMPL1(void, Context::ExecuteCallBack, LPVOID privateData)
+{
+ CONTRACTL
+ {
+ FCALL_CHECK;
+ PRECONDITION(CheckPointer(privateData));
+ }
+ CONTRACTL_END;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ switch (((CallBackInfo*) privateData)->callbackId)
+ {
+ case Wait_callback:
+ {
+ WaitArgs* waitArgs;
+ waitArgs = (WaitArgs*) ((CallBackInfo*) privateData)->callbackData;
+ ExecuteWaitCallback(waitArgs);
+ break;
+ }
+
+ case MonitorWait_callback:
+ {
+ MonitorWaitArgs* waitArgs;
+ waitArgs = (MonitorWaitArgs*) ((CallBackInfo*) privateData)->callbackData;
+ ExecuteMonitorWaitCallback(waitArgs);
+ break;
+ }
+
+ case ADTransition_callback:
+ {
+ ADCallBackArgs* pCallArgs = (ADCallBackArgs*)(((CallBackInfo*) privateData)->callbackData);
+ pCallArgs->pTarget(pCallArgs->pArguments);
+ break;
+ }
+
+ case SignalAndWait_callback:
+ {
+ SignalAndWaitArgs* signalAndWaitArgs;
+ signalAndWaitArgs = (SignalAndWaitArgs*)((CallBackInfo*)privateData)->callbackData;
+ ExecuteSignalAndWaitCallback(signalAndWaitArgs);
+ break;
+ }
+ // Add other callback types here
+ default:
+ _ASSERTE(!"Invalid callback type");
+ break;
+ }
+
+ // This is EE's entry point to do whatever it wanted to do in
+ // the targetContext. This will return back into the managed
+ // world and transition back into the original context.
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+
+
+#ifdef ENABLE_PERF_COUNTERS
+
+FCIMPL0(LPVOID, GetPrivateContextsPerfCountersEx)
+{
+ FCALL_CONTRACT;
+
+ return (LPVOID)GetPrivateContextsPerfCounters();
+}
+FCIMPLEND
+
+
+#else
+FCIMPL0(LPVOID, GetPrivateContextsPerfCountersEx)
+{
+ FCALL_CONTRACT;
+
+ return NULL;
+}
+FCIMPLEND
+
+#endif // ENABLE_PERF_COUNTERS
+
+#endif // DACCESS_COMPILE
+
+// This will NOT create the exposed object if there isn't one!
+OBJECTREF Context::GetExposedObjectRaw()
+{
+ WRAPPER_NO_CONTRACT;
+
+ return ObjectFromHandle(m_ExposedObjectHandle);
+}
+
+
+PTR_Object Context::GetExposedObjectRawUnchecked()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return *PTR_PTR_Object(m_ExposedObjectHandle);
+}
+
+PTR_PTR_Object Context::GetExposedObjectRawUncheckedPtr()
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return PTR_PTR_Object(m_ExposedObjectHandle);
+}
+
+//+----------------------------------------------------------------------------
+//
+// Method: Context::GetStaticFieldAddrNoCreate private
+//
+// Synopsis: Get the address of the field relative to the context given a thread.
+// If an address has not been assigned, return NULL.
+// No creating is allowed.
+//
+
+//
+//+----------------------------------------------------------------------------
+PTR_VOID Context::GetStaticFieldAddrNoCreate(FieldDesc *pFD)
+{
+ CONTRACT (PTR_VOID)
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(pFD));
+ POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
+ SUPPORTS_DAC;
+ }
+ CONTRACT_END;
+
+ PTR_VOID pvAddress = NULL;
+ // for static field the MethodTable is exact even for generic classes
+ MethodTable* pMT = pFD->GetEnclosingMethodTable();
+ BOOL fIsShared = pMT->IsDomainNeutral();
+ DWORD dwClassOffset = pMT->GetContextStaticsOffset();
+ DWORD currElem = 0;
+ STATIC_DATA* pData;
+
+ if (dwClassOffset == (DWORD)-1)
+ RETURN NULL;
+
+ if(!fIsShared)
+ pData = m_pUnsharedStaticData;
+ else
+ pData = m_pSharedStaticData;
+
+ if (NULL == pData)
+ RETURN NULL;
+
+ currElem = pData->cElem;
+
+ // Check whether we have allocated space for storing a pointer to
+ // this class' context static store
+ if(dwClassOffset >= currElem || pData->dataPtr[dwClassOffset] == NULL)
+ RETURN NULL;
+
+ _ASSERTE(pData->dataPtr[dwClassOffset] != NULL);
+
+ // We have allocated static storage for this data
+ // Just return the address by getting the offset into the data
+ pvAddress = PTR_VOID(dac_cast<PTR_BYTE>(pData->dataPtr[dwClassOffset]) + pFD->GetOffset());
+
+ if(pFD->IsObjRef() || pFD->IsByValue())
+ {
+ if (*dac_cast<PTR_BYTE>(pvAddress) == NULL)
+ {
+ pvAddress = NULL;
+ LOG((LF_SYNC, LL_ALWAYS, "dbgr: pvAddress = NULL"));
+ }
+ else
+ {
+ pvAddress = CalculateAddressForManagedStatic(*(PTR_int(pvAddress)));
+ LOG((LF_SYNC, LL_ALWAYS, "dbgr: pvAddress = %lx", pvAddress));
+ if (pFD->IsByValue())
+ {
+ _ASSERTE(pvAddress != NULL);
+ pvAddress = (*(PTR_OBJECTREF(pvAddress)))->GetData();
+ }
+ }
+ }
+
+ RETURN pvAddress;
+}
+
+
+// This is used for context relative statics that are object refs
+// These are stored in a structure in the managed context. The first
+// time over an index and a bucket are determined and subsequently
+// remembered in the location for the field in the per-context-per-class
+// data structure.
+// Here we map back from the index to the address of the object ref.
+PTR_VOID Context::CalculateAddressForManagedStatic(int slot)
+{
+ CONTRACT (PTR_VOID)
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ PRECONDITION(CheckPointer(this));
+ POSTCONDITION(CheckPointer(RETVAL));
+ SUPPORTS_DAC;
+ }
+ CONTRACT_END;
+
+ PTR_OBJECTREF pObjRef;
+ int bucket = (slot>>16);
+ int index = (0x0000ffff&slot);
+
+ // Now determine the address of the static field
+ PTRARRAYREF bucketRef = NULL;
+
+ bucketRef = ((CONTEXTBASEREF)GetExposedObjectRaw())->GetContextStaticsHolder();
+
+ // walk the chain to our bucket
+ while (bucket--)
+ bucketRef = (PTRARRAYREF) bucketRef->GetAt(0);
+
+ // Index 0 is used to point to the next bucket!
+ _ASSERTE(index > 0);
+ pObjRef = PTR_OBJECTREF(bucketRef->GetDataPtr())+index;
+
+ RETURN (PTR_VOID(pObjRef));
+}
+
+#endif // FEATURE_REMOTING
+
+#ifdef DACCESS_COMPILE
+
+void
+Context::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
+{
+ SUPPORTS_DAC;
+ DAC_ENUM_DTHIS();
+
+ if (m_pDomain.IsValid())
+ {
+ m_pDomain->EnumMemoryRegions(flags, true);
+ }
+}
+#endif // #ifdef DACCESS_COMPILE