From 4adbd6765d79c25dbae8bce48083c8a4e81934f6 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Sun, 12 Feb 2017 19:55:22 -0800 Subject: Remove dead appdomainhelper* files --- src/vm/appdomain.cpp | 1 - src/vm/appdomainhelper.cpp | 546 --------------------------------------- src/vm/appdomainhelper.h | 371 -------------------------- src/vm/appdomainnative.cpp | 1 - src/vm/assembly.cpp | 1 - src/vm/assemblynative.cpp | 1 - src/vm/cominterfacemarshaler.cpp | 1 - src/vm/comsynchronizable.cpp | 1 - src/vm/i386/excepx86.cpp | 1 - src/vm/securitymeta.cpp | 1 - src/vm/securitystackwalk.h | 1 - src/vm/threads.cpp | 1 - 12 files changed, 927 deletions(-) delete mode 100644 src/vm/appdomainhelper.cpp delete mode 100644 src/vm/appdomainhelper.h diff --git a/src/vm/appdomain.cpp b/src/vm/appdomain.cpp index e6d4ed1b4b..e13c7dbe2a 100644 --- a/src/vm/appdomain.cpp +++ b/src/vm/appdomain.cpp @@ -37,7 +37,6 @@ #include "comdelegate.h" #include "siginfo.hpp" #ifdef FEATURE_REMOTING -#include "appdomainhelper.h" #include "objectclone.h" #endif #include "typekey.h" diff --git a/src/vm/appdomainhelper.cpp b/src/vm/appdomainhelper.cpp deleted file mode 100644 index 2c0531648f..0000000000 --- a/src/vm/appdomainhelper.cpp +++ /dev/null @@ -1,546 +0,0 @@ -// 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. - - -// - -#include "common.h" - -#ifdef FEATURE_REMOTING - -#include "appdomainhelper.h" -#include "appdomain.inl" - -void AppDomainHelper::CopyEncodingToByteArray(IN PBYTE pbData, - IN DWORD cbData, - OUT OBJECTREF* pArray) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(cbData==0 || pbData!=NULL); - PRECONDITION(CheckPointer(pArray)); - } - CONTRACTL_END; - PREFIX_ASSUME(pArray != NULL); - - U1ARRAYREF pObj; - - if(cbData) { - pObj = (U1ARRAYREF)AllocatePrimitiveArray(ELEMENT_TYPE_U1,cbData); - memcpyNoGCRefs(pObj->m_Array, pbData, cbData); - *pArray = (OBJECTREF) pObj; - } else - *pArray = NULL; - - VALIDATEOBJECTREF(*pArray); -} - - -void AppDomainHelper::CopyByteArrayToEncoding(IN U1ARRAYREF* pArray, - OUT PBYTE* ppbData, - OUT DWORD* pcbData) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_COOPERATIVE; - PRECONDITION(pArray!=NULL); - PRECONDITION(ppbData!=NULL); - PRECONDITION(pcbData!=NULL); - } - CONTRACTL_END; - - VALIDATEOBJECTREF(*pArray); - - if (*pArray == NULL) { - *ppbData = NULL; - *pcbData = 0; - return; - } - - DWORD size = (*pArray)->GetNumComponents(); - if(size) { - *ppbData = new BYTE[size]; - *pcbData = size; - - CopyMemory(*ppbData, (*pArray)->GetDirectPointerToNonObjectElements(), size); - } -} - - -struct MarshalObjectArgs : public CtxTransitionBaseArgs -{ - OBJECTREF* orObject; - U1ARRAYREF* porBlob; -}; - -void MarshalObjectADCallback(MarshalObjectArgs * args) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; - MethodDescCallSite marshalObject(METHOD__APP_DOMAIN__MARSHAL_OBJECT); - - ARG_SLOT argsCall[] = { - ObjToArgSlot(*(args->orObject)) - }; - - *(args->porBlob) = (U1ARRAYREF) marshalObject.Call_RetOBJECTREF(argsCall); -} - - -// Marshal a single object into a serialized blob. -void AppDomainHelper::MarshalObject(ADID appDomain, - IN OBJECTREF *orObject, // Object must be GC protected - OUT U1ARRAYREF *porBlob) -{ - - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(orObject!=NULL); - PRECONDITION(porBlob!=NULL); - PRECONDITION(IsProtectedByGCFrame(orObject)); - } - CONTRACTL_END; - - VALIDATEOBJECTREF(*orObject); - - MarshalObjectArgs args; - args.orObject = orObject; - args.porBlob = porBlob; - - MakeCallWithPossibleAppDomainTransition(appDomain, (FPAPPDOMAINCALLBACK) MarshalObjectADCallback, &args); - - VALIDATEOBJECTREF(*porBlob); - -} - -void AppDomainHelper::MarshalObject(IN OBJECTREF *orObject, // Object must be GC protected - OUT U1ARRAYREF *porBlob) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(orObject!=NULL); - PRECONDITION(porBlob!=NULL); - PRECONDITION(IsProtectedByGCFrame(orObject)); - } - CONTRACTL_END; - - VALIDATEOBJECTREF(*orObject); - - MethodDescCallSite marshalObject(METHOD__APP_DOMAIN__MARSHAL_OBJECT); - - ARG_SLOT argsCall[] = { - ObjToArgSlot(*orObject) - }; - - *porBlob = (U1ARRAYREF) marshalObject.Call_RetOBJECTREF(argsCall); - - VALIDATEOBJECTREF(*porBlob); -} - -// Marshal a single object into a serialized blob. -void AppDomainHelper::MarshalObject(IN AppDomain *pDomain, - IN OBJECTREF *orObject, // Object must be GC protected - OUT BYTE **ppbBlob, - OUT DWORD *pcbBlob) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(pDomain!=NULL); - PRECONDITION(orObject!=NULL); - PRECONDITION(ppbBlob!=NULL); - PRECONDITION(pcbBlob!=NULL); - PRECONDITION(IsProtectedByGCFrame(orObject)); - } - CONTRACTL_END; - - VALIDATEOBJECTREF(*orObject); - - U1ARRAYREF orBlob = NULL; - - GCPROTECT_BEGIN(orBlob); - - MethodDescCallSite marshalObject(METHOD__APP_DOMAIN__MARSHAL_OBJECT); - - ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN) - { - ARG_SLOT args[] = - { - ObjToArgSlot(*orObject) - }; - - orBlob = (U1ARRAYREF) marshalObject.Call_RetOBJECTREF(args); - } - END_DOMAIN_TRANSITION; - - if (orBlob != NULL) - CopyByteArrayToEncoding(&orBlob, - ppbBlob, - pcbBlob); - GCPROTECT_END(); -} - -// Marshal two objects into serialized blobs. -void AppDomainHelper::MarshalObjects(IN AppDomain *pDomain, - IN OBJECTREF *orObject1, - IN OBJECTREF *orObject2, - OUT BYTE **ppbBlob1, - OUT DWORD *pcbBlob1, - OUT BYTE **ppbBlob2, - OUT DWORD *pcbBlob2) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(pDomain!=NULL); - PRECONDITION(orObject1!=NULL); - PRECONDITION(ppbBlob1!=NULL); - PRECONDITION(pcbBlob1!=NULL); - PRECONDITION(orObject2!=NULL); - PRECONDITION(ppbBlob2!=NULL); - PRECONDITION(pcbBlob2!=NULL); - PRECONDITION(IsProtectedByGCFrame(orObject1)); - PRECONDITION(IsProtectedByGCFrame(orObject2)); - } - CONTRACTL_END; - - VALIDATEOBJECTREF(*orObject1); - VALIDATEOBJECTREF(*orObject2); - - struct _gc { - U1ARRAYREF orBlob1; - U1ARRAYREF orBlob2; - } gc; - ZeroMemory(&gc, sizeof(gc)); - - GCPROTECT_BEGIN(gc); - - MethodDescCallSite marshalObjects(METHOD__APP_DOMAIN__MARSHAL_OBJECTS); - - ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN) - { - ARG_SLOT args[] = - { - ObjToArgSlot(*orObject1), - ObjToArgSlot(*orObject2), - PtrToArgSlot(&gc.orBlob2), - }; - - gc.orBlob1 = (U1ARRAYREF) marshalObjects.Call_RetOBJECTREF(args); - } - END_DOMAIN_TRANSITION; - - if (gc.orBlob1 != NULL) - { - CopyByteArrayToEncoding(&gc.orBlob1, - ppbBlob1, - pcbBlob1); - } - - if (gc.orBlob2 != NULL) - { - CopyByteArrayToEncoding(&gc.orBlob2, - ppbBlob2, - pcbBlob2); - } - - GCPROTECT_END(); -} - -// Unmarshal a single object from a serialized blob. -// Callers must GC protect both porBlob and porObject. -void AppDomainHelper::UnmarshalObject(IN AppDomain *pDomain, - IN U1ARRAYREF *porBlob, // Object must be GC protected - OUT OBJECTREF *porObject) // Object must be GC protected -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(pDomain!=NULL); - PRECONDITION(porBlob!=NULL); - PRECONDITION(porObject!=NULL); - PRECONDITION(IsProtectedByGCFrame(porBlob)); - PRECONDITION(IsProtectedByGCFrame(porObject)); - } - CONTRACTL_END; - - VALIDATEOBJECTREF(*porBlob); - - MethodDescCallSite unmarshalObject(METHOD__APP_DOMAIN__UNMARSHAL_OBJECT); - - ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN) - { - ARG_SLOT args[] = - { - ObjToArgSlot(*porBlob) - }; - - *porObject = unmarshalObject.Call_RetOBJECTREF(args); - } - END_DOMAIN_TRANSITION; - - VALIDATEOBJECTREF(*porObject); -} - -// Unmarshal a single object from a serialized blob. -void AppDomainHelper::UnmarshalObject(IN AppDomain *pDomain, - IN BYTE *pbBlob, - IN DWORD cbBlob, - OUT OBJECTREF *porObject) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(pDomain!=NULL); - PRECONDITION(porObject!=NULL); - PRECONDITION(IsProtectedByGCFrame(porObject)); - } - CONTRACTL_END; - - OBJECTREF orBlob = NULL; - - MethodDescCallSite unmarshalObject(METHOD__APP_DOMAIN__UNMARSHAL_OBJECT); - - ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN) - { - GCPROTECT_BEGIN(orBlob); - - AppDomainHelper::CopyEncodingToByteArray(pbBlob, - cbBlob, - &orBlob); - - ARG_SLOT args[] = - { - ObjToArgSlot(orBlob) - }; - - *porObject = unmarshalObject.Call_RetOBJECTREF(args); - - GCPROTECT_END(); - } - END_DOMAIN_TRANSITION; - - VALIDATEOBJECTREF(*porObject); -} - -// Unmarshal two objects from serialized blobs. -void AppDomainHelper::UnmarshalObjects(IN AppDomain *pDomain, - IN BYTE *pbBlob1, - IN DWORD cbBlob1, - IN BYTE *pbBlob2, - IN DWORD cbBlob2, - OUT OBJECTREF *porObject1, - OUT OBJECTREF *porObject2) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(pDomain!=NULL); - PRECONDITION(porObject1!=NULL); - PRECONDITION(porObject2!=NULL); - PRECONDITION(IsProtectedByGCFrame(porObject1)); - PRECONDITION(IsProtectedByGCFrame(porObject2)); - } - CONTRACTL_END; - - MethodDescCallSite unmarshalObjects(METHOD__APP_DOMAIN__UNMARSHAL_OBJECTS); - - struct _gc { - OBJECTREF orBlob1; - OBJECTREF orBlob2; - OBJECTREF orObject2; - } gc; - ZeroMemory(&gc, sizeof(gc)); - - ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN) - { - - GCPROTECT_BEGIN(gc); - - AppDomainHelper::CopyEncodingToByteArray(pbBlob1, - cbBlob1, - &gc.orBlob1); - - AppDomainHelper::CopyEncodingToByteArray(pbBlob2, - cbBlob2, - &gc.orBlob2); - - ARG_SLOT args[] = - { - ObjToArgSlot(gc.orBlob1), - ObjToArgSlot(gc.orBlob2), - PtrToArgSlot(&gc.orObject2), - }; - - *porObject1 = unmarshalObjects.Call_RetOBJECTREF(args); - *porObject2 = gc.orObject2; - - GCPROTECT_END(); - } - END_DOMAIN_TRANSITION; - - VALIDATEOBJECTREF(*porObject1); - VALIDATEOBJECTREF(*porObject2); -} - -// Copy an object from the given appdomain into the current appdomain. -OBJECTREF AppDomainHelper::CrossContextCopyFrom(IN ADID dwDomainId, - IN OBJECTREF *orObject) // Object must be GC protected -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(orObject!=NULL); - PRECONDITION(IsProtectedByGCFrame(orObject)); - } - CONTRACTL_END; - - struct _gc - { - U1ARRAYREF orBlob; - OBJECTREF pResult; - } gc; - ZeroMemory(&gc, sizeof(gc)); - - GCPROTECT_BEGIN(gc); - AppDomainHelper::MarshalObject(dwDomainId, orObject, &gc.orBlob); - AppDomainHelper::UnmarshalObject(GetAppDomain(), &gc.orBlob, &gc.pResult); - GCPROTECT_END(); - VALIDATEOBJECTREF(gc.pResult); - return gc.pResult; -} - -// Copy an object from the given appdomain into the current appdomain. -OBJECTREF AppDomainHelper::CrossContextCopyTo(IN ADID dwDomainId, - IN OBJECTREF *orObject) // Object must be GC protected -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(orObject!=NULL); - PRECONDITION(IsProtectedByGCFrame(orObject)); - } - CONTRACTL_END; - - - struct _gc - { - U1ARRAYREF orBlob; - OBJECTREF pResult; - } gc; - ZeroMemory(&gc, sizeof(gc)); - - GCPROTECT_BEGIN(gc); - AppDomainHelper::MarshalObject(orObject, &gc.orBlob); - ENTER_DOMAIN_ID(dwDomainId); - AppDomainHelper::UnmarshalObject(GetAppDomain(),&gc.orBlob, &gc.pResult); - END_DOMAIN_TRANSITION; - GCPROTECT_END(); - VALIDATEOBJECTREF(gc.pResult); - return gc.pResult; - -} - -// Copy an object from the given appdomain into the current appdomain. -OBJECTREF AppDomainHelper::CrossContextCopyFrom(IN AppDomain *pDomain, - IN OBJECTREF *orObject) // Object must be GC protected -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(orObject!=NULL); - PRECONDITION(IsProtectedByGCFrame(orObject)); - PRECONDITION(pDomain!=NULL); - PRECONDITION(pDomain != GetAppDomain()); - } - CONTRACTL_END; - - VALIDATEOBJECTREF(*orObject); - - struct _gc { - U1ARRAYREF orBlob; - OBJECTREF result; - } gc; - ZeroMemory(&gc, sizeof(gc)); - - GCPROTECT_BEGIN(gc); - ENTER_DOMAIN_PTR(pDomain, ADV_RUNNINGIN); - AppDomainHelper::MarshalObject(orObject, &gc.orBlob); - END_DOMAIN_TRANSITION; - AppDomainHelper::UnmarshalObject(GetAppDomain(),&gc.orBlob, &gc.result); - GCPROTECT_END(); - - VALIDATEOBJECTREF(gc.result); - - return gc.result; -} - -// Copy an object to the given appdomain from the current appdomain. -OBJECTREF AppDomainHelper::CrossContextCopyTo(IN AppDomain *pDomain, - IN OBJECTREF *orObject) // Object must be GC protected -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(orObject!=NULL); - PRECONDITION(IsProtectedByGCFrame(orObject)); - PRECONDITION(pDomain!=NULL); - PRECONDITION(pDomain != GetAppDomain()); - } - CONTRACTL_END; - - VALIDATEOBJECTREF(*orObject); - - struct _gc { - U1ARRAYREF orBlob; - OBJECTREF result; - } gc; - ZeroMemory(&gc, sizeof(gc)); - - GCPROTECT_BEGIN(gc); - AppDomainHelper::MarshalObject(orObject, &gc.orBlob); - AppDomainHelper::UnmarshalObject(pDomain, &gc.orBlob, &gc.result); - GCPROTECT_END(); - - VALIDATEOBJECTREF(gc.result); - - return gc.result; -} - -#endif // FEATURE_REMOTING - diff --git a/src/vm/appdomainhelper.h b/src/vm/appdomainhelper.h deleted file mode 100644 index e331555292..0000000000 --- a/src/vm/appdomainhelper.h +++ /dev/null @@ -1,371 +0,0 @@ -// 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. - - -#ifndef _APPDOMAIN_HELPER_H_ -#define _APPDOMAIN_HELPER_H_ - -#ifndef FEATURE_REMOTING -#error FEATURE_REMOTING is not set, please do not include appdomainhelper.h -#endif - -// Marshal a single object into a serialized blob. -// -// - -class AppDomainHelper { - - friend class MarshalCache; - - // A pair of helper to move serialization info between managed byte-array and - // unmanaged blob. - static void AppDomainHelper::CopyEncodingToByteArray(IN PBYTE pbData, - IN DWORD cbData, - OUT OBJECTREF* pArray); - - static void AppDomainHelper::CopyByteArrayToEncoding(IN U1ARRAYREF* pArray, - OUT PBYTE* ppbData, - OUT DWORD* pcbData); - -public: - // Marshal a single object into a serialized blob. - static void AppDomainHelper::MarshalObject(IN OBJECTREF *orObject, - OUT U1ARRAYREF *porBlob); - - static void AppDomainHelper::MarshalObject(IN ADID pDomain, - IN OBJECTREF *orObject, - OUT U1ARRAYREF *porBlob); - // Marshal one object into a seraialized blob. - static void AppDomainHelper::MarshalObject(IN AppDomain *pDomain, - IN OBJECTREF *orObject, - OUT BYTE **ppbBlob, - OUT DWORD *pcbBlob); - - // Marshal two objects into serialized blobs. - static void AppDomainHelper::MarshalObjects(IN AppDomain *pDomain, - IN OBJECTREF *orObject1, - IN OBJECTREF *orObject2, - OUT BYTE **ppbBlob1, - OUT DWORD *pcbBlob1, - OUT BYTE **ppbBlob2, - OUT DWORD *pcbBlob2); - - // Unmarshal a single object from a serialized blob. - static void AppDomainHelper::UnmarshalObject(IN AppDomain *pDomain, - IN U1ARRAYREF *porBlob, - OUT OBJECTREF *porObject); - - // Unmarshal a single object from a serialized blob. - static void AppDomainHelper::UnmarshalObject(IN AppDomain *pDomain, - IN BYTE *pbBlob, - IN DWORD cbBlob, - OUT OBJECTREF *porObject); - - // Unmarshal two objects from serialized blobs. - static void AppDomainHelper::UnmarshalObjects(IN AppDomain *pDomain, - IN BYTE *pbBlob1, - IN DWORD cbBlob1, - IN BYTE *pbBlob2, - IN DWORD cbBlob2, - OUT OBJECTREF *porObject1, - OUT OBJECTREF *porObject2); - - // Copy an object from the given appdomain into the current appdomain. - static OBJECTREF AppDomainHelper::CrossContextCopyFrom(IN AppDomain *pAppDomain, - IN OBJECTREF *orObject); - // Copy an object to the given appdomain from the current appdomain. - static OBJECTREF AppDomainHelper::CrossContextCopyTo(IN AppDomain *pAppDomain, - IN OBJECTREF *orObject); - // Copy an object from the given appdomain into the current appdomain. - static OBJECTREF AppDomainHelper::CrossContextCopyFrom(IN ADID dwDomainId, - IN OBJECTREF *orObject); - // Copy an object to the given appdomain from the current appdomain. - static OBJECTREF AppDomainHelper::CrossContextCopyTo(IN ADID dwDomainId, - IN OBJECTREF *orObject); - -}; - -// Cache the bits needed to serialize/deserialize managed objects that will be -// passed across appdomain boundaries during a stackwalk. The serialization is -// performed lazily the first time it's needed and remains valid throughout the -// stackwalk. The last deserialized object is cached and tagged with its -// appdomain context. It's valid as long as we're walking frames within the same -// appdomain. -// -class MarshalCache -{ -public: - MarshalCache() - { - LIMITED_METHOD_CONTRACT; - ZeroMemory(this, sizeof(*this)); - } - - ~MarshalCache() - { - LIMITED_METHOD_CONTRACT; - if (m_pbObj1) - delete [] m_pbObj1; - if (m_pbObj2) - delete [] m_pbObj2; - } - - void EnsureSerializationOK() - { - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; - if ((m_sGC.m_orInput1 != NULL && (m_pbObj1 == NULL || m_cbObj1 == 0)) || - (m_sGC.m_orInput2 != NULL && (m_pbObj2 == NULL || m_cbObj2 == 0))) - { - // Serialization went bad -> Throw exception indicating so. - COMPlusThrow(kSecurityException, IDS_UNMARSHALABLE_DEMAND_OBJECT); - } - } - - void EnsureDeserializationOK() - { - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; - if ((m_pbObj1 != NULL && m_sGC.m_orOutput1 == NULL ) || - (m_pbObj2 != NULL && m_sGC.m_orOutput2 == NULL ) ) - { - // DeSerialization went bad -> Throw exception indicating so. - COMPlusThrow(kSecurityException, IDS_UNMARSHALABLE_DEMAND_OBJECT); - } - } - -#ifndef DACCESS_COMPILE - - // Set the original value of the first cached object. - void SetObject(OBJECTREF orObject) - { - LIMITED_METHOD_CONTRACT; - m_pOriginalDomain = ::GetAppDomain(); - m_sGC.m_orInput1 = orObject; - } - - // Set the original values of both cached objects. - void SetObjects(OBJECTREF orObject1, OBJECTREF orObject2) - { - LIMITED_METHOD_CONTRACT; - m_pOriginalDomain = ::GetAppDomain(); - m_sGC.m_orInput1 = orObject1; - m_sGC.m_orInput2 = orObject2; - } - -#endif //!DACCESS_COMPILE - - // Get a copy of the first object suitable for use in the given appdomain. - OBJECTREF GetObject(AppDomain *pDomain) - { - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; - CheckADValidity(pDomain, ADV_RUNNINGIN); - - // No transition -- just return original object. - if (pDomain == m_pOriginalDomain) { - if (m_fObjectUpdated) - UpdateObjectFinish(); - return m_sGC.m_orInput1; - } - - // We've already deserialized the object into the correct context. - if (pDomain == m_pCachedDomain) - return m_sGC.m_orOutput1; - - // If we've updated the object in a different appdomain from the one we - // originally started in, the cached object will be more up to date than - // the original. Resync the objects. - if (m_fObjectUpdated) - UpdateObjectFinish(); - - // Check whether we've serialized the original input object yet. - if (m_pbObj1 == NULL && m_sGC.m_orInput1 != NULL) - { - AppDomainHelper::MarshalObject(m_pOriginalDomain, - &m_sGC.m_orInput1, - &m_pbObj1, - &m_cbObj1); - EnsureSerializationOK(); - } - - // Deserialize into the correct context. - if (m_pbObj1 != NULL) - { - AppDomainHelper::UnmarshalObject(pDomain, - m_pbObj1, - m_cbObj1, - &m_sGC.m_orOutput1); - EnsureDeserializationOK(); - } - m_pCachedDomain = pDomain; - - return m_sGC.m_orOutput1; - } - - // As above, but retrieve both objects. - OBJECTREF GetObjects(AppDomain *pDomain, OBJECTREF *porObject2) - { - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; - CheckADValidity(pDomain, ADV_RUNNINGIN); - // No transition -- just return original objects. - if (pDomain == m_pOriginalDomain) { - if (m_fObjectUpdated) - UpdateObjectFinish(); - *porObject2 = m_sGC.m_orInput2; - return m_sGC.m_orInput1; - } - - // We've already deserialized the objects into the correct context. - if (pDomain == m_pCachedDomain) { - *porObject2 = m_sGC.m_orOutput2; - return m_sGC.m_orOutput1; - } - - // If we've updated the object in a different appdomain from the one we - // originally started in, the cached object will be more up to date than - // the original. Resync the objects. - if (m_fObjectUpdated) - UpdateObjectFinish(); - - // Check whether we've serialized the original input objects yet. - if ((m_pbObj1 == NULL && m_sGC.m_orInput1 != NULL) || - (m_pbObj2 == NULL && m_sGC.m_orInput2 != NULL)) - { - AppDomainHelper::MarshalObjects(m_pOriginalDomain, - &m_sGC.m_orInput1, - &m_sGC.m_orInput2, - &m_pbObj1, - &m_cbObj1, - &m_pbObj2, - &m_cbObj2); - EnsureSerializationOK(); - - } - if (m_pbObj1 != NULL || m_pbObj2 != NULL) - { - // Deserialize into the correct context. - AppDomainHelper::UnmarshalObjects(pDomain, - m_pbObj1, - m_cbObj1, - m_pbObj2, - m_cbObj2, - &m_sGC.m_orOutput1, - &m_sGC.m_orOutput2); - EnsureDeserializationOK(); - } - m_pCachedDomain = pDomain; - - *porObject2 = m_sGC.m_orOutput2; - return m_sGC.m_orOutput1; - } - - // Change the first object (updating the cacheing information - // appropriately). - void UpdateObject(AppDomain *pDomain, OBJECTREF orObject) - { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - // The cached serialized blob is now useless. - CheckADValidity(pDomain, ADV_RUNNINGIN); - if (m_pbObj1) - delete [] m_pbObj1; - m_pbObj1 = NULL; - m_cbObj1 = 0; - - // The object we have now is valid in it's own appdomain, so place that - // in the object cache. - m_pCachedDomain = pDomain; - m_sGC.m_orOutput1 = orObject; - - // If the object is updated in the original context, just use the new - // value as is. In this case we have the data to re-marshal the updated - // object as normal, so we can consider the cache fully updated and exit - // now. - if (pDomain == m_pOriginalDomain) { - m_sGC.m_orInput1 = orObject; - m_fObjectUpdated = false; - return; - } - - // We want to avoid re-marshaling the updated value as long as possible - // (it might be updated again before we need its value in a different - // context). So set a flag to indicate that the object must be - // re-marshaled when the value is queried in a new context. - m_fObjectUpdated = true; - } - - // This structure is public only so that it can be GC protected. Do not - // access the fields directly, they change in an unpredictable fashion due - // to the lazy cacheing algorithm. - struct _gc { - OBJECTREF m_orInput1; - OBJECTREF m_orInput2; - OBJECTREF m_orOutput1; - OBJECTREF m_orOutput2; - } m_sGC; - -private: - - // Called after one or more calls to UpdateObject to marshal the updated - // object back into its original context (it's assumed we're called in this - // context). - void UpdateObjectFinish() - { - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(m_fObjectUpdated && m_pbObj1 == NULL); - } - CONTRACTL_END; - AppDomainHelper::MarshalObject(m_pCachedDomain, - &m_sGC.m_orOutput1, - &m_pbObj1, - &m_cbObj1); - AppDomainHelper::UnmarshalObject(m_pOriginalDomain, - m_pbObj1, - m_cbObj1, - &m_sGC.m_orInput1); - m_fObjectUpdated = false; - } - - BYTE *m_pbObj1; - DWORD m_cbObj1; - BYTE *m_pbObj2; - DWORD m_cbObj2; - AppDomain *m_pCachedDomain; - AppDomain *m_pOriginalDomain; - bool m_fObjectUpdated; -}; - -#endif diff --git a/src/vm/appdomainnative.cpp b/src/vm/appdomainnative.cpp index 47509d731f..dd46add6ee 100644 --- a/src/vm/appdomainnative.cpp +++ b/src/vm/appdomainnative.cpp @@ -9,7 +9,6 @@ #include "appdomainnative.hpp" #ifdef FEATURE_REMOTING #include "remoting.h" -#include "appdomainhelper.h" #endif #include "security.h" #include "vars.hpp" diff --git a/src/vm/assembly.cpp b/src/vm/assembly.cpp index 3e1745b23d..fc9ce7189c 100644 --- a/src/vm/assembly.cpp +++ b/src/vm/assembly.cpp @@ -46,7 +46,6 @@ #include "appdomainnative.hpp" #ifdef FEATURE_REMOTING #include "remoting.h" -#include "appdomainhelper.h" #endif #include "customattribute.h" #include "winnls.h" diff --git a/src/vm/assemblynative.cpp b/src/vm/assemblynative.cpp index 7175b156f0..8daa851c74 100644 --- a/src/vm/assemblynative.cpp +++ b/src/vm/assemblynative.cpp @@ -29,7 +29,6 @@ #include "frames.h" #include "typeparse.h" #ifdef FEATURE_REMOTING -#include "appdomainhelper.h" #endif #include "stackprobe.h" diff --git a/src/vm/cominterfacemarshaler.cpp b/src/vm/cominterfacemarshaler.cpp index 0bd22a028b..58dd504d6a 100644 --- a/src/vm/cominterfacemarshaler.cpp +++ b/src/vm/cominterfacemarshaler.cpp @@ -20,7 +20,6 @@ #include "interopconverter.h" #ifdef FEATURE_REMOTING #include "remoting.h" -#include "appdomainhelper.h" #include "crossdomaincalls.h" #endif #include "notifyexternals.h" diff --git a/src/vm/comsynchronizable.cpp b/src/vm/comsynchronizable.cpp index e042c8effe..3a395235e6 100644 --- a/src/vm/comsynchronizable.cpp +++ b/src/vm/comsynchronizable.cpp @@ -29,7 +29,6 @@ #endif #include "eeconfig.h" #ifdef FEATURE_REMOTING -#include "appdomainhelper.h" #include "objectclone.h" #else #include "callhelpers.h" diff --git a/src/vm/i386/excepx86.cpp b/src/vm/i386/excepx86.cpp index 10f68a9fbf..2997c5784f 100644 --- a/src/vm/i386/excepx86.cpp +++ b/src/vm/i386/excepx86.cpp @@ -28,7 +28,6 @@ #include "dllimportcallback.h" #include "threads.h" #ifdef FEATURE_REMOTING -#include "appdomainhelper.h" #endif #include "eeconfig.h" #include "vars.hpp" diff --git a/src/vm/securitymeta.cpp b/src/vm/securitymeta.cpp index 7027c47c83..7cc8b65426 100644 --- a/src/vm/securitymeta.cpp +++ b/src/vm/securitymeta.cpp @@ -29,7 +29,6 @@ #include "threads.h" #include "eventtrace.h" #ifdef FEATURE_REMOTING -#include "appdomainhelper.h" #include "objectclone.h" #endif //FEATURE_REMOTING #include "typestring.h" diff --git a/src/vm/securitystackwalk.h b/src/vm/securitystackwalk.h index 3aaf9b5084..f59c958145 100644 --- a/src/vm/securitystackwalk.h +++ b/src/vm/securitystackwalk.h @@ -19,7 +19,6 @@ #include "security.h" #include "holder.h" #ifdef FEATURE_REMOTING -#include "appdomainhelper.h" #endif class ApplicationSecurityDescriptor; diff --git a/src/vm/threads.cpp b/src/vm/threads.cpp index 791a09fc42..81bf023568 100644 --- a/src/vm/threads.cpp +++ b/src/vm/threads.cpp @@ -31,7 +31,6 @@ #include "appdomainstack.inl" #include "eventtrace.h" #ifdef FEATURE_REMOTING -#include "appdomainhelper.h" #endif #include "comutilnative.h" #include "finalizerthread.h" -- cgit v1.2.3 From 57aaf669076c1fb4c756251192f301b7b6db22dc Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Sun, 12 Feb 2017 19:55:22 -0800 Subject: Remove dead assemblynamesconfigfactory etc files --- src/vm/assemblynamesconfigfactory.cpp | 264 ---------------------- src/vm/assemblynamesconfigfactory.h | 72 ------ src/vm/eeconfigfactory.cpp | 398 ---------------------------------- src/vm/eeconfigfactory.h | 149 ------------- src/vm/mda.cpp | 11 +- src/vm/mda.h | 1 - src/vm/ngenoptout.cpp | 12 - src/vm/ngenoptout.h | 34 --- 8 files changed, 10 insertions(+), 931 deletions(-) delete mode 100644 src/vm/assemblynamesconfigfactory.cpp delete mode 100644 src/vm/assemblynamesconfigfactory.h delete mode 100644 src/vm/eeconfigfactory.cpp delete mode 100644 src/vm/eeconfigfactory.h delete mode 100644 src/vm/ngenoptout.cpp delete mode 100644 src/vm/ngenoptout.h diff --git a/src/vm/assemblynamesconfigfactory.cpp b/src/vm/assemblynamesconfigfactory.cpp deleted file mode 100644 index ed5da9679b..0000000000 --- a/src/vm/assemblynamesconfigfactory.cpp +++ /dev/null @@ -1,264 +0,0 @@ -// 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. -// AssemblyNamesConfigFactory.cpp -// - -// -// -// Parses XML files and adding runtime entries to assembly list -// Abstract, derived classes need to override AddAssemblyName -#include "common.h" -#include "common.h" -#include -#include -#include "parse.h" -#include "assemblynamesconfigfactory.h" - - -#define ISWHITE(ch) ((ch) >= 0x09 && (ch) <= 0x0D || (ch) == 0x20) - -#define CONST_STRING_AND_LEN(str) str, NumItems(str)-1 - -extern int EEXMLStringCompare(const WCHAR *pStr1, - DWORD cchStr1, - const WCHAR *pStr2, - DWORD cchStr2); -extern HRESULT VersionFromString(LPCWSTR wzVersion, WORD *pwVerMajor, WORD *pwVerMinor, - WORD *pwVerBld, WORD *pwVerRev); -extern HRESULT MapProcessorArchitectureToPEKIND(LPCWSTR pwzProcArch, PEKIND *pe); - -AssemblyNamesConfigFactory::AssemblyNamesConfigFactory() -{ - LIMITED_METHOD_CONTRACT; - m_pAssemblyName = NULL; - m_bCurrentEntryInvalid = TRUE; - m_dwCurrentElementDepth = 0; - m_dwProperty = ASM_NAME_MAX_PARAMS; -} - -AssemblyNamesConfigFactory::~AssemblyNamesConfigFactory() -{ - LIMITED_METHOD_CONTRACT; -} - - -HRESULT STDMETHODCALLTYPE AssemblyNamesConfigFactory::NotifyEvent( - /* [in] */ IXMLNodeSource __RPC_FAR *pSource, - /* [in] */ XML_NODEFACTORY_EVENT iEvt) -{ - LIMITED_METHOD_CONTRACT; - - return S_OK; -} - -HRESULT STDMETHODCALLTYPE AssemblyNamesConfigFactory::BeginChildren( - /* [in] */ IXMLNodeSource __RPC_FAR *pSource, - /* [in] */ XML_NODE_INFO __RPC_FAR *pNodeInfo) -{ - LIMITED_METHOD_CONTRACT; - m_dwCurrentElementDepth ++; - - return S_OK; -} - -//--------------------------------------------------------------------------- -HRESULT STDMETHODCALLTYPE AssemblyNamesConfigFactory::EndChildren( - /* [in] */ IXMLNodeSource __RPC_FAR *pSource, - /* [in] */ BOOL fEmptyNode, - /* [in] */ XML_NODE_INFO __RPC_FAR *pNodeInfo) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - INJECT_FAULT(return E_OUTOFMEMORY;); - } - CONTRACTL_END; - - HRESULT hr = S_OK; - EX_TRY - { - if (m_dwCurrentElementDepth == 1 && m_pAssemblyName != NULL) - { - if (!m_bCurrentEntryInvalid) - { - // publish - AddAssemblyName(m_pAssemblyName); - }; - m_pAssemblyName->Release(); - m_pAssemblyName = NULL; - } - - if (!fEmptyNode) - m_dwCurrentElementDepth --; - } - EX_CATCH_HRESULT(hr); - return hr; -} - - - -HRESULT STDMETHODCALLTYPE AssemblyNamesConfigFactory::CreateNode( - /* [in] */ IXMLNodeSource __RPC_FAR *pSource, - /* [in] */ PVOID pNode, - /* [in] */ USHORT cNumRecs, - /* [in] */ XML_NODE_INFO* __RPC_FAR * __RPC_FAR apNodeInfo) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - INJECT_FAULT(return E_OUTOFMEMORY;); - } - CONTRACTL_END; - - if(m_dwCurrentElementDepth > 1) - return S_OK; - - HRESULT hr = S_OK; - - for(DWORD i = 0; i < cNumRecs; i++) { - CONTRACT_VIOLATION(ThrowsViolation); // Lots of stuff in here throws! - - if(apNodeInfo[i]->dwType == XML_ELEMENT || - apNodeInfo[i]->dwType == XML_ATTRIBUTE || - apNodeInfo[i]->dwType == XML_PCDATA) - { - - DWORD dwStringSize = apNodeInfo[i]->ulLen; - LPWSTR pszString = (WCHAR*) apNodeInfo[i]->pwcText; - // Trim the value - - // we should never decrement lgth if it's 0, because it's unsigned - - for(;*pszString && ISWHITE(*pszString) && dwStringSize>0; pszString++, dwStringSize--); - while( dwStringSize > 0 && ISWHITE(pszString[dwStringSize-1])) - dwStringSize--; - switch(apNodeInfo[i]->dwType) - { - case XML_ELEMENT : - if(EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("assemblyIdentity"))) == 0) - { - // new entry - _ASSERTE(m_pAssemblyName == NULL); - IfFailRet(CreateAssemblyNameObject(&m_pAssemblyName, NULL,0,NULL)); - m_bCurrentEntryInvalid = FALSE; - } - else - { - m_bCurrentEntryInvalid = TRUE; - } - - break; - - - case XML_ATTRIBUTE : - if(m_bCurrentEntryInvalid) - break; - - if(EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("name"))) == 0) - { - m_dwProperty = ASM_NAME_NAME; - } - else - if(EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("version"))) == 0) - { - m_dwProperty = ASM_NAME_MAJOR_VERSION; - } - else - if(EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("publicKeyToken"))) == 0) - { - m_dwProperty = ASM_NAME_PUBLIC_KEY_TOKEN; - } - else - if(EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("processorArchitecture"))) == 0) - { - m_dwProperty = ASM_NAME_ARCHITECTURE; - } - else - { - m_bCurrentEntryInvalid = TRUE; - } - break; - - - case XML_PCDATA : - if(m_bCurrentEntryInvalid) - break; - - _ASSERTE(m_pAssemblyName!= NULL); // can only be null if m_bCurrentEntryInvalid - switch(m_dwProperty) - { - case ASM_NAME_NAME: - { - StackSString s(pszString,dwStringSize); - // takes number of bytes, thus *2 - IfFailRet(m_pAssemblyName->SetProperty(ASM_NAME_NAME, LPCWSTR(s), (dwStringSize+1)*sizeof(WCHAR))); - } - break; - case ASM_NAME_MAJOR_VERSION: - { - StackSString s(pszString,dwStringSize); - WORD wVerMajor = 0; - WORD wVerMinor = 0; - WORD wVerBld = 0; - WORD wVerRev = 0; - if (SUCCEEDED(VersionFromString(s, &wVerMajor, &wVerMinor, &wVerBld, &wVerRev))) - { - IfFailRet(m_pAssemblyName->SetProperty(ASM_NAME_MAJOR_VERSION, &wVerMajor, sizeof(WORD))); - IfFailRet(m_pAssemblyName->SetProperty(ASM_NAME_MINOR_VERSION, &wVerMinor, sizeof(WORD))); - IfFailRet(m_pAssemblyName->SetProperty(ASM_NAME_BUILD_NUMBER, &wVerBld, sizeof(WORD))); - IfFailRet(m_pAssemblyName->SetProperty(ASM_NAME_REVISION_NUMBER, &wVerRev, sizeof(WORD))); - } - else - m_bCurrentEntryInvalid = TRUE; - - } - break; - case ASM_NAME_ARCHITECTURE: - { - StackSString s(pszString,dwStringSize); - PEKIND PeKind = peNone; - if(SUCCEEDED(MapProcessorArchitectureToPEKIND(s, &PeKind))) - { - IfFailRet(m_pAssemblyName->SetProperty(ASM_NAME_ARCHITECTURE, (LPBYTE) &PeKind, sizeof(PeKind))); - } - else - { - m_bCurrentEntryInvalid = TRUE; - } - - } - break; - case ASM_NAME_PUBLIC_KEY_TOKEN: - { - if(EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("null"))) == 0) - { - IfFailRet(m_pAssemblyName->SetProperty(ASM_NAME_NULL_PUBLIC_KEY_TOKEN, NULL, 0)); - } - else - { - if (dwStringSize % 2 != 0) - return FUSION_E_INVALID_NAME; - - DWORD cbProp = dwStringSize / 2; - NewHolder pbProp = new BYTE[cbProp]; - CParseUtils::UnicodeHexToBin(pszString, dwStringSize, pbProp); //???? - IfFailRet(m_pAssemblyName->SetProperty(ASM_NAME_PUBLIC_KEY_TOKEN, pbProp, cbProp)); - } - break; - } - - default: - _ASSERTE(!"Invalid format"); - m_bCurrentEntryInvalid = TRUE; - break; - } - break; - } - - } - } - return S_OK; -} diff --git a/src/vm/assemblynamesconfigfactory.h b/src/vm/assemblynamesconfigfactory.h deleted file mode 100644 index 234adb9208..0000000000 --- a/src/vm/assemblynamesconfigfactory.h +++ /dev/null @@ -1,72 +0,0 @@ -// 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. -// AssemblyNamesConfigFactory.h -// - -// -// -// Parses XML files and adding runtime entries to assembly list -// Abstract, derived classes need to override AddAssemblyName - - -#ifndef ASSEMBLYNAMESCONFIGFACTORY_H -#define ASSEMBLYNAMESCONFIGFACTORY_H - -#include "unknwn.h" -#include "../xmlparser/_reference.h" -#include "../xmlparser/_unknown.h" - - -class AssemblyNamesConfigFactory : public _unknown -{ - -public: - AssemblyNamesConfigFactory (); - ~AssemblyNamesConfigFactory (); - HRESULT STDMETHODCALLTYPE NotifyEvent( - /* [in] */ IXMLNodeSource __RPC_FAR *pSource, - /* [in] */ XML_NODEFACTORY_EVENT iEvt); - - HRESULT STDMETHODCALLTYPE BeginChildren( - /* [in] */ IXMLNodeSource __RPC_FAR *pSource, - /* [in] */ XML_NODE_INFO* __RPC_FAR pNodeInfo); - - HRESULT STDMETHODCALLTYPE EndChildren( - /* [in] */ IXMLNodeSource __RPC_FAR *pSource, - /* [in] */ BOOL fEmptyNode, - /* [in] */ XML_NODE_INFO* __RPC_FAR pNodeInfo); - - HRESULT STDMETHODCALLTYPE Error( - /* [in] */ IXMLNodeSource __RPC_FAR *pSource, - /* [in] */ HRESULT hrErrorCode, - /* [in] */ USHORT cNumRecs, - /* [in] */ XML_NODE_INFO* __RPC_FAR * __RPC_FAR apNodeInfo) - { - LIMITED_METHOD_CONTRACT; - /* - UNUSED(pSource); - UNUSED(hrErrorCode); - UNUSED(cNumRecs); - UNUSED(apNodeInfo); - */ - return hrErrorCode; - } - - HRESULT STDMETHODCALLTYPE CreateNode( - /* [in] */ IXMLNodeSource __RPC_FAR *pSource, - /* [in] */ PVOID pNodeParent, - /* [in] */ USHORT cNumRecs, - /* [in] */ XML_NODE_INFO* __RPC_FAR * __RPC_FAR apNodeInfo); - - virtual void AddAssemblyName(IAssemblyName*) = 0; -protected: - IAssemblyName* m_pAssemblyName; - BOOL m_bCurrentEntryInvalid; - DWORD m_dwCurrentElementDepth; - DWORD m_dwProperty; - -}; - - -#endif diff --git a/src/vm/eeconfigfactory.cpp b/src/vm/eeconfigfactory.cpp deleted file mode 100644 index a0eb927ce9..0000000000 --- a/src/vm/eeconfigfactory.cpp +++ /dev/null @@ -1,398 +0,0 @@ -// 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. -// EEConfigFactory.cpp -// - -// -// Factory used to with the XML parser to read configuration files -// - -#include "common.h" -#include "ngenoptout.h" -#include "eeconfigfactory.h" - - -#define ISWHITE(ch) ((ch) >= 0x09 && (ch) <= 0x0D || (ch) == 0x20) - -#define CONST_STRING_AND_LEN(str) str, NumItems(str)-1 - - -int EEXMLStringCompare(const WCHAR *pStr1, - DWORD cchStr1, - const WCHAR *pStr2, - DWORD cchStr2) -{ - LIMITED_METHOD_CONTRACT; - if (cchStr1 != cchStr2) - return -1; - - return wcsncmp(pStr1, pStr2, cchStr1); -}// EEXMLStringCompare - - -int EEXMLStringComparei(const WCHAR *pStr1, - DWORD cchStr1, - const WCHAR *pStr2, - DWORD cchStr2) -{ - WRAPPER_NO_CONTRACT; - if (cchStr1 != cchStr2) - return -1; - - return SString::_wcsnicmp(pStr1, pStr2, cchStr1); -}// EEXMLStringCompare - - - -EEConfigFactory::EEConfigFactory( - ConfigStringHashtable* pTable, - LPCWSTR pString, - ParseCtl parseCtl) -{ - LIMITED_METHOD_CONTRACT; - m_pTable = pTable; - m_pVersion = pString; - m_dwDepth = 0; - m_fUnderRuntimeElement = FALSE; - m_fDeveloperSettings = FALSE; - m_fVersionedRuntime= FALSE; - m_fOnEnabledAttribute = FALSE; - m_fOnValueAttribute = FALSE; - m_pCurrentRuntimeElement = m_pBuffer; - m_dwCurrentRuntimeElement = 0; - m_dwSize = CONFIG_KEY_SIZE; - m_parseCtl = parseCtl; - m_pActiveFactory = NULL; -} - -EEConfigFactory::~EEConfigFactory() -{ - LIMITED_METHOD_CONTRACT; - DeleteKey(); -} - -HRESULT STDMETHODCALLTYPE EEConfigFactory::NotifyEvent( - /* [in] */ IXMLNodeSource __RPC_FAR *pSource, - /* [in] */ XML_NODEFACTORY_EVENT iEvt) -{ - LIMITED_METHOD_CONTRACT; - if(iEvt == XMLNF_ENDDOCUMENT) { - // add error handling. - } - if(m_pActiveFactory != NULL) - return m_pActiveFactory->NotifyEvent(pSource, iEvt); - - return S_OK; -} -//--------------------------------------------------------------------------- -HRESULT STDMETHODCALLTYPE EEConfigFactory::BeginChildren( - /* [in] */ IXMLNodeSource __RPC_FAR *pSource, - /* [in] */ XML_NODE_INFO __RPC_FAR *pNodeInfo) -{ - LIMITED_METHOD_CONTRACT; - - m_dwDepth++; - if(m_pActiveFactory != NULL) - return m_pActiveFactory->BeginChildren(pSource, pNodeInfo); - return S_OK; - -} -//--------------------------------------------------------------------------- -HRESULT STDMETHODCALLTYPE EEConfigFactory::EndChildren( - /* [in] */ IXMLNodeSource __RPC_FAR *pSource, - /* [in] */ BOOL fEmptyNode, - /* [in] */ XML_NODE_INFO __RPC_FAR *pNodeInfo) -{ - LIMITED_METHOD_CONTRACT; - if ( fEmptyNode ) { - m_fDeveloperSettings = FALSE; - } - else { - m_dwDepth--; - } - - if (m_pActiveFactory != NULL) - { - HRESULT hr = S_OK; - IfFailRet(m_pActiveFactory->EndChildren(pSource, fEmptyNode, pNodeInfo)); - - - if(m_dwDepth == 2) // when generalizing: use the current active factory depth - { - m_pActiveFactory = NULL; - } - - } - - if (m_fUnderRuntimeElement && wcscmp(pNodeInfo->pwcText, W("runtime")) == 0) { - m_fUnderRuntimeElement = FALSE; - m_fVersionedRuntime = FALSE; - ClearKey(); - // CLR_STARTUP_OPT: - // Early out if we only need to read section. - // - if (m_parseCtl == stopAfterRuntimeSection) - pSource->Abort(NULL/*unused*/); - } - - return S_OK; -} -//--------------------------------------------------------------------------- -HRESULT STDMETHODCALLTYPE EEConfigFactory::CreateNode( - /* [in] */ IXMLNodeSource __RPC_FAR *pSource, - /* [in] */ PVOID pNode, - /* [in] */ USHORT cNumRecs, - /* [in] */ XML_NODE_INFO* __RPC_FAR * __RPC_FAR apNodeInfo) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - INJECT_FAULT(return E_OUTOFMEMORY;); - } - CONTRACTL_END; - - if(m_pActiveFactory != NULL) - return m_pActiveFactory->CreateNode(pSource, pNode, cNumRecs, apNodeInfo); - - if(m_dwDepth > 3) - { - - return S_OK; - } - - HRESULT hr = S_OK; - DWORD dwStringSize = 0; - WCHAR* pszString = NULL; - DWORD i; - BOOL fRuntimeKey = FALSE; - BOOL fVersion = FALSE; - - for( i = 0; i < cNumRecs; i++) { - CONTRACT_VIOLATION(ThrowsViolation); // Lots of stuff in here throws! - - if(apNodeInfo[i]->dwType == XML_ELEMENT || - apNodeInfo[i]->dwType == XML_ATTRIBUTE || - apNodeInfo[i]->dwType == XML_PCDATA) { - - dwStringSize = apNodeInfo[i]->ulLen; - pszString = (WCHAR*) apNodeInfo[i]->pwcText; - // Trim the value - - // we should never decrement lgth if it's 0, because it's unsigned - - for(;*pszString && ISWHITE(*pszString) && dwStringSize>0; pszString++, dwStringSize--); - while( dwStringSize > 0 && ISWHITE(pszString[dwStringSize-1])) - dwStringSize--; - - // NOTE: pszString is not guaranteed to be null terminated. Use EEXMLStringCompare to do - // string comparisions on it - - switch(apNodeInfo[i]->dwType) { - case XML_ELEMENT : - fRuntimeKey = FALSE; - ClearKey(); - - if (m_dwDepth == 1 && EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("runtime"))) == 0) { - m_fUnderRuntimeElement = TRUE; - fRuntimeKey = TRUE; - } - - if(m_dwDepth == 2 && m_fUnderRuntimeElement) { - - // Developer settings can look like - // - // - // - // or - // - // - // - // Neither one is your standard config setting. - if (!EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("developerSettings"))) || - !EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("developmentMode")))) - { - m_fDeveloperSettings = TRUE; - } - else - // when generalizing: use map of (string, depth) -> class - if (!EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("disableNativeImageLoad")))) - { - m_pActiveFactory = new NativeImageOptOutConfigFactory(); - m_pActiveFactory->AddRef(); - } - else - { - // This is a standard element under the runtime node.... it could look like this - // - // - - hr = CopyToKey(pszString, dwStringSize); - if(FAILED(hr)) return hr; - } - } - // If our depth isn't 2, and we're not under the runtime element.... - else - ClearKey(); - - break ; - - case XML_ATTRIBUTE : - if(fRuntimeKey && EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("version"))) == 0) { - fVersion = TRUE; - } - else - { - if (m_dwDepth == 2 && m_fUnderRuntimeElement) - { - if (!m_fDeveloperSettings) - { - _ASSERTE(m_dwCurrentRuntimeElement > 0); - - // The standard model for runtime config settings is as follows - // - // - // - // or - // - // or - // - - m_fOnEnabledAttribute = (EEXMLStringComparei(pszString, dwStringSize, CONST_STRING_AND_LEN(W("enabled"))) == 0); - m_fOnValueAttribute = (EEXMLStringComparei(pszString, dwStringSize, CONST_STRING_AND_LEN(W("value"))) == 0); - } - else // We're looking at developer settings - { - // Developer settings look like - // - // - // or - // - // - // - - // The key name will actually be the attribute name - - hr = CopyToKey(pszString, dwStringSize); - if(FAILED(hr)) return hr; - m_fOnEnabledAttribute = FALSE; - m_fOnValueAttribute = FALSE; - } - } - } - break; - case XML_PCDATA: - if(fVersion) { - // if this is not the right version - // then we are not interested - if(EEXMLStringCompare(pszString, dwStringSize, m_pVersion, (DWORD)wcslen(m_pVersion))) { - m_fUnderRuntimeElement = FALSE; - } - else { - // if it is the right version then overwrite - // all entries that exist in the hash table - m_fVersionedRuntime = TRUE; - } - - fVersion = FALSE; - } - else if(fRuntimeKey) { - break; // Ignore all other attributes on - } - - // m_dwCurrentRuntimeElement is set when we called CopyToKey in the XML_ELEMENT case - // section above. - else if(m_dwCurrentRuntimeElement > 0 && (m_fDeveloperSettings || m_fOnEnabledAttribute || m_fOnValueAttribute)) { - - // This means that, either we are working on attribute values for the developer settings, - // or we've got what "enabled" is equal to, or we're reading a string for a value setting. - // - // - // - - if (m_fOnEnabledAttribute) { - // For the enabled settings, let's convert all trues to 1s and the falses to 0s - if (EEXMLStringComparei(pszString, dwStringSize, CONST_STRING_AND_LEN(W("false"))) == 0) { - pszString = W("0"); - dwStringSize = 1; - } - else if (EEXMLStringComparei(pszString, dwStringSize, CONST_STRING_AND_LEN(W("true"))) == 0) { - pszString = W("1"); - dwStringSize = 1; - } - - // Right now, if pString isn't 0 or 1, then the XML schema is bad. - // If we were to ever do schema validation, this would be a place to put it. - // - } - - hr = AddKeyValuePair(pszString, dwStringSize, m_pCurrentRuntimeElement, m_dwCurrentRuntimeElement); - if(FAILED(hr)) { return hr; } - } - - break ; - default: - ; - } // end of switch - } - } - return hr; -} - -HRESULT STDMETHODCALLTYPE EEConfigFactory::AddKeyValuePair( - __in_ecount(dwStringSize) WCHAR * pszString, - /* [in] */ DWORD dwStringSize, - __in_ecount(m_dwCurrentRuntimeElement) WCHAR * m_pCurrentRuntimeElement, - /* [in] */ DWORD m_dwCurrentRuntimeElement - ) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - INJECT_FAULT(return E_OUTOFMEMORY;); - } - CONTRACTL_END; - - HRESULT hr = S_OK; - - // verify we the size fields don't overflow - if (dwStringSize + 1 < dwStringSize) { return E_FAIL; } - if (m_dwCurrentRuntimeElement < m_dwCurrentRuntimeElement - 1) { return E_FAIL; } - - EX_TRY - { - // Allocate memory that can store this setting - NewArrayHolder pStringToKeep(new WCHAR[dwStringSize+1]); - wcsncpy_s(pStringToKeep, dwStringSize + 1, pszString, dwStringSize); - - // See if we've already picked up a value for this setting - ConfigStringKeyValuePair * pair = m_pTable->Lookup(m_pCurrentRuntimeElement); - if(pair != NULL) { - // If this is a config section for this runtime version, then it's allowed to overwrite - // previous settings that we've picked up - if(m_fVersionedRuntime) { - delete[] pair->value; - pair->value = pStringToKeep; - pStringToKeep.SuppressRelease(); - } - } - else { - // We're adding a new config item - NewArrayHolder pKeyToKeep (new WCHAR[m_dwCurrentRuntimeElement]); - wcsncpy_s(pKeyToKeep, m_dwCurrentRuntimeElement, m_pCurrentRuntimeElement, m_dwCurrentRuntimeElement - 1); - - ConfigStringKeyValuePair * newPair = new ConfigStringKeyValuePair(); - newPair->key = pKeyToKeep; - newPair->value = pStringToKeep; - m_pTable->Add(newPair); - pKeyToKeep.SuppressRelease(); - pStringToKeep.SuppressRelease(); - } - } - EX_CATCH_HRESULT(hr); - - return hr; -} - diff --git a/src/vm/eeconfigfactory.h b/src/vm/eeconfigfactory.h deleted file mode 100644 index 2554295268..0000000000 --- a/src/vm/eeconfigfactory.h +++ /dev/null @@ -1,149 +0,0 @@ -// 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. -// EEConfigFactory.h -// - -// -// Parses XML files and adding runtime entries to the EEConfig list -// - - -#ifndef EECONFIGFACTORY_H -#define EECONFIGFACTORY_H - -#include -#include -#include "unknwn.h" -#include "../xmlparser/_reference.h" -#include "../xmlparser/_unknown.h" -#include "eehash.h" -#include "eeconfig.h" - -#define CONFIG_KEY_SIZE 128 - -class EEConfigFactory : public _unknown -{ - -public: - EEConfigFactory( - ConfigStringHashtable* pTable, - LPCWSTR, - ParseCtl parseCtl = parseAll); - ~EEConfigFactory(); - HRESULT STDMETHODCALLTYPE NotifyEvent( - /* [in] */ IXMLNodeSource __RPC_FAR *pSource, - /* [in] */ XML_NODEFACTORY_EVENT iEvt); - - HRESULT STDMETHODCALLTYPE BeginChildren( - /* [in] */ IXMLNodeSource __RPC_FAR *pSource, - /* [in] */ XML_NODE_INFO* __RPC_FAR pNodeInfo); - - HRESULT STDMETHODCALLTYPE EndChildren( - /* [in] */ IXMLNodeSource __RPC_FAR *pSource, - /* [in] */ BOOL fEmptyNode, - /* [in] */ XML_NODE_INFO* __RPC_FAR pNodeInfo); - - HRESULT STDMETHODCALLTYPE Error( - /* [in] */ IXMLNodeSource __RPC_FAR *pSource, - /* [in] */ HRESULT hrErrorCode, - /* [in] */ USHORT cNumRecs, - /* [in] */ XML_NODE_INFO* __RPC_FAR * __RPC_FAR apNodeInfo) - { - LIMITED_METHOD_CONTRACT; - /* - UNUSED(pSource); - UNUSED(hrErrorCode); - UNUSED(cNumRecs); - UNUSED(apNodeInfo); - */ - return hrErrorCode; - } - - HRESULT STDMETHODCALLTYPE CreateNode( - /* [in] */ IXMLNodeSource __RPC_FAR *pSource, - /* [in] */ PVOID pNodeParent, - /* [in] */ USHORT cNumRecs, - /* [in] */ XML_NODE_INFO* __RPC_FAR * __RPC_FAR apNodeInfo); - -private: - - HRESULT GrowKey(DWORD dwSize) - { - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - INJECT_FAULT(return E_OUTOFMEMORY); - } - CONTRACTL_END; - - if(dwSize > m_dwSize) { - DeleteKey(); - m_pCurrentRuntimeElement = new(nothrow) WCHAR[dwSize]; - if(m_pCurrentRuntimeElement == NULL) return E_OUTOFMEMORY; - m_dwSize = dwSize; - } - return S_OK; - } - - void ClearKey() - { - LIMITED_METHOD_CONTRACT; - - *m_pCurrentRuntimeElement = 0; - m_dwCurrentRuntimeElement = 0; - } - - void DeleteKey() - { - WRAPPER_NO_CONTRACT; - if(m_pCurrentRuntimeElement != NULL && m_pCurrentRuntimeElement != m_pBuffer) - delete [] m_pCurrentRuntimeElement; - m_dwSize = 0; - m_dwCurrentRuntimeElement = 0; - } - - HRESULT CopyToKey(__in_z LPCWSTR pString, DWORD dwString) - { - WRAPPER_NO_CONTRACT; - dwString++; // add in the null - HRESULT hr = GrowKey(dwString); - if(FAILED(hr)) return hr; - wcsncpy_s(m_pCurrentRuntimeElement, m_dwSize, pString, dwString-1); - - m_dwCurrentRuntimeElement = dwString; - return S_OK; - } - - HRESULT STDMETHODCALLTYPE AddKeyValuePair( - __in_ecount(dwStringSize) WCHAR * pszString, - /* [in] */ DWORD dwStringSize, - __in_ecount(m_dwCurrentRuntimeElement) WCHAR * m_pCurrentRuntimeElement, - /* [in] */ DWORD m_dwCurrentRuntimeElement); - - HRESULT CopyVersion(LPCWSTR version, DWORD dwVersion); - - ConfigStringHashtable* m_pTable; - BOOL m_fUnderRuntimeElement; - BOOL m_fOnEnabledAttribute; - BOOL m_fOnValueAttribute; - BOOL m_fVersionedRuntime; - BOOL m_fDeveloperSettings; - - LPCWSTR m_pVersion; - LPWSTR m_pCurrentRuntimeElement; - DWORD m_dwCurrentRuntimeElement; - - WCHAR m_pBuffer[CONFIG_KEY_SIZE]; - DWORD m_dwSize; - - DWORD m_dwDepth; - - bool m_bSafeMode; // If true, will ignore any settings that may compromise security - ParseCtl m_parseCtl; // usually parseAll, sometimes stopAfterRuntimeSection - - ReleaseHolder m_pActiveFactory; // hold a factory responsible for parsing subnode -}; - -#endif diff --git a/src/vm/mda.cpp b/src/vm/mda.cpp index 77c26a993e..bea222a0c6 100644 --- a/src/vm/mda.cpp +++ b/src/vm/mda.cpp @@ -5,7 +5,16 @@ #include "common.h" #include "eeconfig.h" -#include "eeconfigfactory.h" + +#include +#include +#include "unknwn.h" +#include "../xmlparser/_reference.h" +#include "../xmlparser/_unknown.h" +#include "eehash.h" +#include "eeconfig.h" + +#define CONFIG_KEY_SIZE 128 #include "corhlpr.h" #include #include diff --git a/src/vm/mda.h b/src/vm/mda.h index b52bd00d42..c711e8ae7f 100644 --- a/src/vm/mda.h +++ b/src/vm/mda.h @@ -295,7 +295,6 @@ private: friend class MdaXmlMessage; friend class MdaXmlIndustry; friend class MdaConfigFactory; - friend class EEConfigFactory; friend class MdaFramework; friend void EEStartupHelper(COINITIEE fFlags); diff --git a/src/vm/ngenoptout.cpp b/src/vm/ngenoptout.cpp deleted file mode 100644 index 50b47782a9..0000000000 --- a/src/vm/ngenoptout.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// 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. -// ngenoptout.cpp -// - -// -// -// Contains functionality to reject native images at runtime - - -#include "common.h" diff --git a/src/vm/ngenoptout.h b/src/vm/ngenoptout.h deleted file mode 100644 index dbcc9b1f90..0000000000 --- a/src/vm/ngenoptout.h +++ /dev/null @@ -1,34 +0,0 @@ -// 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. -// ngenoptout.h -// - -// -// -// Contains functionality to reject native images at runtime - - -#ifndef NGENOPTOUT_H -#define NGENOPTOUT_H - -#include "assemblynamesconfigfactory.h" - -// throwing -BOOL IsNativeImageOptedOut(IAssemblyName* pName); -void AddNativeImageOptOut(IAssemblyName* pName); - -// HRESULT -HRESULT RuntimeIsNativeImageOptedOut(IAssemblyName* pName); - - -class NativeImageOptOutConfigFactory : public AssemblyNamesConfigFactory -{ - virtual void AddAssemblyName(IAssemblyName* pName) - { - WRAPPER_NO_CONTRACT; - AddNativeImageOptOut(pName); - } -}; - -#endif // NGENOPTOUT_H -- cgit v1.2.3 From 4a252cee944e66e7ad709bc11a31037c78fcdfe9 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Sun, 12 Feb 2017 20:21:08 -0800 Subject: Remove clrpriv* dead code --- src/inc/clrprivbinderutil.h | 3 - src/vm/clrprivbinderfusion.cpp | 819 ------------------------- src/vm/clrprivbinderfusion.h | 228 ------- src/vm/clrprivbinderreflectiononlywinrt.cpp | 497 --------------- src/vm/clrprivbinderreflectiononlywinrt.h | 295 --------- src/vm/clrprivtypecachereflectiononlywinrt.cpp | 260 -------- src/vm/clrprivtypecachereflectiononlywinrt.h | 58 -- src/vm/pefile.h | 2 - 8 files changed, 2162 deletions(-) delete mode 100644 src/vm/clrprivbinderfusion.cpp delete mode 100644 src/vm/clrprivbinderfusion.h delete mode 100644 src/vm/clrprivbinderreflectiononlywinrt.cpp delete mode 100644 src/vm/clrprivbinderreflectiononlywinrt.h delete mode 100644 src/vm/clrprivtypecachereflectiononlywinrt.cpp delete mode 100644 src/vm/clrprivtypecachereflectiononlywinrt.h diff --git a/src/inc/clrprivbinderutil.h b/src/inc/clrprivbinderutil.h index 1a645dccc0..d42f2b8d66 100644 --- a/src/inc/clrprivbinderutil.h +++ b/src/inc/clrprivbinderutil.h @@ -737,9 +737,6 @@ namespace CLRPrivBinderUtil /** probably should be exposed on an instance (of something) method rather that magically calling GetAppDomain() **/ ICLRPrivAssembly* RaiseAssemblyResolveEvent(IAssemblyName *pAssemblyName, ICLRPrivAssembly* pRequestingAssembly); - /** PLACEHOLDER - CLRPRivBinderFusion::BindAssemblyByName throws, despite being an HRESULT function, - most presumably because returning HRESULT is too lossy **/ - /** Ultimately, only the binder can do ref-def matching, and it should be opaque to CLR. This is not trivial to do, however, since we cannot do data conversion as the function is nofault **/ BOOL CompareHostBinderSpecs(AssemblySpec* a1, AssemblySpec* a2); diff --git a/src/vm/clrprivbinderfusion.cpp b/src/vm/clrprivbinderfusion.cpp deleted file mode 100644 index d31774f7b2..0000000000 --- a/src/vm/clrprivbinderfusion.cpp +++ /dev/null @@ -1,819 +0,0 @@ -// 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. - - - -#include "common.h" // precompiled header - -#ifndef DACCESS_COMPILE - -//===================================================================================================================== -#include "assemblyspec.hpp" -#include "corhdr.h" -#include "domainfile.h" -#include "fusion.h" -#include "policy.h" -#include "sstring.h" -#include "stackingallocator.h" -#include "threads.h" -#include "clrprivbinderfusion.h" -#include "clrprivbinderutil.h" -#include "fusionlogging.h" - -using namespace CLRPrivBinderUtil; - -//================================================================================================= -#define STDMETHOD_NOTIMPL(...) \ - STDMETHOD(__VA_ARGS__) \ - { \ - WRAPPER_NO_CONTRACT; \ - _ASSERTE_MSG(false, "Method not implemented."); \ - return E_NOTIMPL; \ - } - -//================================================================================================= -static HRESULT PropagateOutStringArgument( - __in LPCSTR pszValue, - __out_ecount_opt(*pcchArg) LPWSTR pwzArg, - __in DWORD cchArg, - __out DWORD * pcchArg) -{ - LIMITED_METHOD_CONTRACT; - - VALIDATE_PTR_RET(pszValue); - VALIDATE_CONDITION((pwzArg == nullptr || cchArg > 0), return E_INVALIDARG); - - HRESULT hr = S_OK; - - if (pwzArg != nullptr) - { - DWORD cchWritten = WszMultiByteToWideChar( - CP_UTF8, 0 /*flags*/, pszValue, -1, pwzArg, cchArg); - - if (cchWritten == 0) - { - hr = HRESULT_FROM_GetLastError(); - } - else if (pcchArg != nullptr) - { - *pcchArg = cchWritten; - } - } - - if (pcchArg != nullptr && (pwzArg == nullptr || hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))) - { - *pcchArg = WszMultiByteToWideChar( - CP_UTF8, 0 /*flags*/, pszValue, -1, nullptr, 0); - - if (*pcchArg == 0) - { - hr = HRESULT_FROM_GetLastError(); - } - } - - return hr; -} - -//================================================================================================= -// This is needed to allow calls to IsAnyFrameworkAssembly in GC_NOTRIGGER/NO_FAULT regions (i.e., -// GC stack walking). CAssemblyName (which implements IAssemblyName in most other uses) allocates -// during construction and so cannot be used in this scenario. - -class AssemblySpecAsIAssemblyName - : public IAssemblyName -{ -public: - AssemblySpecAsIAssemblyName( - AssemblySpec * pSpec) - : m_pSpec(pSpec) - { LIMITED_METHOD_CONTRACT; } - - //============================================================================================= - // IUnknown methods - - // Not used by IsAnyFrameworkAssembly - STDMETHOD_(ULONG, AddRef()) - { - WRAPPER_NO_CONTRACT; - _ASSERTE_MSG(false, "Method not implemented."); - return E_NOTIMPL; - } - - // Not used by IsAnyFrameworkAssembly - STDMETHOD_(ULONG, Release()) - { - WRAPPER_NO_CONTRACT; - _ASSERTE_MSG(false, "Method not implemented."); - return E_NOTIMPL; - } - - // Not used by IsAnyFrameworkAssembly - STDMETHOD_NOTIMPL(QueryInterface( - REFIID riid, - void **ppvObject)); - - //============================================================================================= - // IAssemblyName methods - - STDMETHOD_NOTIMPL(SetProperty( - DWORD PropertyId, - void const * pvProperty, - DWORD cbProperty)); - -#define ASSURE_SUFFICIENT_BUFFER(SRCSIZE) \ - do { \ - if ((pvProperty == nullptr) || (*pcbProperty < SRCSIZE)) { \ - *pcbProperty = SRCSIZE; \ - return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); \ - } \ - } while (false) - - STDMETHOD(GetProperty)( - DWORD PropertyId, - LPVOID pvProperty, - LPDWORD pcbProperty) - { - LIMITED_METHOD_CONTRACT; - - VALIDATE_PTR_RET(pcbProperty); - VALIDATE_CONDITION((pvProperty == nullptr) == (*pcbProperty == 0), return E_INVALIDARG); - - HRESULT hr = S_OK; - - switch (PropertyId) - { - case ASM_NAME_NAME: - return PropagateOutStringArgument(m_pSpec->GetName(), (LPWSTR) pvProperty, - *pcbProperty / sizeof(WCHAR), pcbProperty); - - case ASM_NAME_MAJOR_VERSION: - ASSURE_SUFFICIENT_BUFFER(sizeof(USHORT)); - *reinterpret_cast(pvProperty) = m_pSpec->GetContext()->usMajorVersion; - *pcbProperty = sizeof(USHORT); - return S_OK; - - case ASM_NAME_MINOR_VERSION: - ASSURE_SUFFICIENT_BUFFER(sizeof(USHORT)); - *reinterpret_cast(pvProperty) = m_pSpec->GetContext()->usMinorVersion; - *pcbProperty = sizeof(USHORT); - return S_OK; - - case ASM_NAME_BUILD_NUMBER: - ASSURE_SUFFICIENT_BUFFER(sizeof(USHORT)); - *reinterpret_cast(pvProperty) = m_pSpec->GetContext()->usBuildNumber; - *pcbProperty = sizeof(USHORT); - return S_OK; - - case ASM_NAME_REVISION_NUMBER: - ASSURE_SUFFICIENT_BUFFER(sizeof(USHORT)); - *reinterpret_cast(pvProperty) = m_pSpec->GetContext()->usRevisionNumber; - *pcbProperty = sizeof(USHORT); - return S_OK; - - case ASM_NAME_CULTURE: - if (m_pSpec->GetContext()->szLocale == nullptr) - { - return FUSION_E_INVALID_NAME; - } - return PropagateOutStringArgument(m_pSpec->GetContext()->szLocale, (LPWSTR) pvProperty, - *pcbProperty / sizeof(WCHAR), pcbProperty); - - case ASM_NAME_PUBLIC_KEY_TOKEN: - { - if (!m_pSpec->HasPublicKeyToken()) - { - return FUSION_E_INVALID_NAME; - } - - PBYTE pbSN; - DWORD cbSN; - m_pSpec->GetPublicKeyToken(&pbSN, &cbSN); - ASSURE_SUFFICIENT_BUFFER(cbSN); - memcpy_s(pvProperty, *pcbProperty, pbSN, cbSN); - *pcbProperty = cbSN; - } - return S_OK; - - case ASM_NAME_RETARGET: - ASSURE_SUFFICIENT_BUFFER(sizeof(BOOL)); - *reinterpret_cast(pvProperty) = m_pSpec->IsRetargetable(); - *pcbProperty = sizeof(BOOL); - return S_OK; - - default: - _ASSERTE_MSG(false, "Unexpected property requested."); - return E_INVALIDARG; - } - } - -#undef ASSURE_SUFFICIENT_BUFFER - - // Not used by IsAnyFrameworkAssembly - STDMETHOD_NOTIMPL(Finalize()); - - // Not used by IsAnyFrameworkAssembly - STDMETHOD_NOTIMPL(GetDisplayName( - __out_ecount_opt(*pccDisplayName) LPOLESTR szDisplayName, - __inout LPDWORD pccDisplayName, - DWORD dwDisplayFlags)); - - // Not used by IsAnyFrameworkAssembly - STDMETHOD_NOTIMPL(Reserved( - REFIID refIID, - IUnknown *pUnkReserved1, - IUnknown *pUnkReserved2, - LPCOLESTR szReserved, - LONGLONG llReserved, - LPVOID pvReserved, - DWORD cbReserved, - LPVOID *ppReserved)); - - - STDMETHOD(GetName)( - __inout LPDWORD lpcwBuffer, - __out_ecount_opt(*lpcwBuffer) WCHAR *pwzName) - { - LIMITED_METHOD_CONTRACT; - - VALIDATE_PTR_RET(lpcwBuffer); - return PropagateOutStringArgument( - m_pSpec->GetName(), pwzName, *lpcwBuffer, lpcwBuffer); - } - - STDMETHOD(GetVersion)( - LPDWORD pdwVersionHi, - LPDWORD pdwVersionLow) - { - LIMITED_METHOD_CONTRACT; - - HRESULT hr = S_OK; - - VALIDATE_PTR_RET(pdwVersionHi); - VALIDATE_PTR_RET(pdwVersionLow); - - AssemblyMetaDataInternal * pAMDI = m_pSpec->GetContext(); - - *pdwVersionHi = MAKELONG(pAMDI->usMinorVersion, pAMDI->usMajorVersion); - *pdwVersionLow = MAKELONG(pAMDI->usRevisionNumber, pAMDI->usBuildNumber); - - return S_OK; - } - - - // Exists exclusively to support fusion's IsSystem helper, which compares against 'mscorlib'. - STDMETHOD(IsEqual)( - IAssemblyName *pName, - DWORD dwCmpFlags) - { - LIMITED_METHOD_CONTRACT; - - HRESULT hr = S_OK; - - VALIDATE_PTR_RET(pName); - - // This function is here just to support checks against the name 'mscorlib'. - if ((dwCmpFlags & ASM_CMPF_NAME) != ASM_CMPF_NAME) - { - return E_NOTIMPL; - } - - DWORD cchName1 = 0; - WCHAR wzName1[_MAX_PATH]; - IfFailRet(pName->GetName(&cchName1, wzName1)); - _ASSERTE(SString::_wcsicmp(wzName1, W("mscorlib")) == 0); - - WCHAR wzName2[_MAX_PATH]; - DWORD cchName2 = WszMultiByteToWideChar( - CP_UTF8, 0 /*flags*/, m_pSpec->GetName(), -1, wzName2, (int) (sizeof(wzName2) / sizeof(wzName2[0]))); - - if (0 == cchName2) - { - _ASSERTE(HRESULT_FROM_GetLastError() != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)); - return HRESULT_FROM_GetLastError(); - } - - if (cchName1 != cchName2) - { - return S_FALSE; - } - - return SString::_wcsnicmp(wzName1, wzName2, cchName1) == 0 - ? S_OK - : S_FALSE; - } - - STDMETHOD_NOTIMPL(Clone( - IAssemblyName **pName)); - -private: - AssemblySpec * m_pSpec; -}; - -//===================================================================================================================== -HRESULT CLRPrivBinderFusion::FindFusionAssemblyBySpec( - LPVOID pvAppDomain, - LPVOID pvAssemblySpec, - BindingScope kBindingScope, - HRESULT * pResult, - ICLRPrivAssembly ** ppAssembly) -{ - LIMITED_METHOD_CONTRACT;; - HRESULT hr = S_OK; - - AppDomain* pAppDomain = reinterpret_cast(pvAppDomain); - AssemblySpec* pAssemblySpec = reinterpret_cast(pvAssemblySpec); - VALIDATE_PTR_RET(pAppDomain); - VALIDATE_PTR_RET(pAssemblySpec); - VALIDATE_PTR_RET(pResult); - VALIDATE_PTR_RET(ppAssembly); - - if (pAssemblySpec->IsContentType_WindowsRuntime()) - { - return CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT; - } - - BOOL fIsSupportedInAppX; - { - AssemblySpecAsIAssemblyName asName(pAssemblySpec); - - if (Fusion::Util::IsAnyFrameworkAssembly(&asName, &fIsSupportedInAppX) != S_OK) - { // Not a framework assembly identity. - IfFailRet(CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT); - } - } - - if (kBindingScope == kBindingScope_FrameworkSubset) - { // We should allow only some framework assemblies to load - - // DevMode has to allow all FX assemblies, not just a subset - see code:PreBind for more info - { - // Disabling for now, as it causes too many violations. - //CONTRACT_VIOLATION(GCViolation | FaultViolation | ModeViolation); - //_ASSERTE(!AppX::IsAppXDesignMode()); - } - - if (!fIsSupportedInAppX) - { // Assembly is blocked for AppX, fail the load - *pResult = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); - *ppAssembly = nullptr; - return S_OK; - } - } - - return FindAssemblyBySpec(pvAppDomain, pvAssemblySpec, pResult, ppAssembly); -} - -//===================================================================================================================== -static -PEAssembly * FindCachedFile(AppDomain * pDomain, AssemblySpec * pSpec) -{ - // Look for cached bind result. Prefer a cached DomainAssembly, as it takes priority over a - // cached PEAssembly (which can be different from the one associated with the DomainAssembly). - DomainAssembly * pDomainAssembly = pDomain->FindCachedAssembly(pSpec, FALSE); - return (pDomainAssembly != nullptr) - ? (pDomainAssembly->GetFile()) - : (pDomain->FindCachedFile(pSpec, FALSE)); -} - -//===================================================================================================================== -// There is no need to create a separate binding record, since we can always just look in the AppDomain's -// AssemblySpecBindingCache for an answer (which is precisely what this function does). - -HRESULT CLRPrivBinderFusion::FindAssemblyBySpec( - LPVOID pvAppDomain, - LPVOID pvAssemblySpec, - HRESULT * pResult, - ICLRPrivAssembly ** ppAssembly) -{ - LIMITED_METHOD_CONTRACT;; - HRESULT hr = S_OK; - - AppDomain* pAppDomain = reinterpret_cast(pvAppDomain); - AssemblySpec* pAssemblySpec = reinterpret_cast(pvAssemblySpec); - VALIDATE_PTR_RET(pAppDomain); - VALIDATE_PTR_RET(pAssemblySpec); - VALIDATE_PTR_RET(pResult); - VALIDATE_PTR_RET(ppAssembly); - - // For the Architecture property, canonicalize peMSIL to peNone (which are considered equivalent), - // to ensure consistent lookups in the AssemblySpecBindingCache for the CLRPrivBinderFusion binder. - if (pAssemblySpec->GetPEKIND() == peMSIL) - { - pAssemblySpec->SetPEKIND(peNone); - } - - PEAssembly * pPEAssembly = FindCachedFile(pAppDomain, pAssemblySpec); - if (pPEAssembly == nullptr) - { - return E_FAIL; - } - - // Could be racing with another thread that has just added the PEAssembly to the binding cache - // but not yet allocated and assigned a host assembly. - if (!pPEAssembly->HasHostAssembly()) - { - return E_FAIL; - } - - *pResult = S_OK; - *ppAssembly = clr::SafeAddRef(pPEAssembly->GetHostAssembly()); - - return S_OK; -} - -//===================================================================================================================== -HRESULT CLRPrivBinderFusion::BindAssemblyByNameWorker( - IAssemblyName * pAssemblyName, - ICLRPrivAssembly ** ppAssembly) -{ - STANDARD_VM_CONTRACT; - PRECONDITION(CheckPointer(pAssemblyName)); - PRECONDITION(CheckPointer(ppAssembly)); - - HRESULT hr = S_OK; - - AppDomain * pCurDomain = AppDomain::GetCurrentDomain(); - if (pCurDomain == nullptr) - ThrowHR(E_UNEXPECTED); - - AssemblySpec prePolicySpec; - AssemblySpec postPolicySpec; - - prePolicySpec.InitializeSpec(pAssemblyName); - - // For the Architecture property, canonicalize peMSIL to peNone (which are considered equivalent), - // to ensure consistent lookups in the AssemblySpecBindingCache for the CLRPrivBinderFusion binder. - if (prePolicySpec.GetPEKIND() == peMSIL) - { - prePolicySpec.SetPEKIND(peNone); - } - - AssemblySpec * pBindSpec = &prePolicySpec; - PEAssemblyHolder pPEAssembly = clr::SafeAddRef(FindCachedFile(pCurDomain, pBindSpec)); - - if (pPEAssembly == nullptr) - { - // Early on in domain setup there may not be a fusion context, so skip ApplyPolicy then. - _ASSERTE(pCurDomain->GetFusionContext() != nullptr || prePolicySpec.IsMscorlib()); - if (pCurDomain->GetFusionContext() != nullptr) - { - ReleaseHolder pPolicyAssemblyName; - DWORD dwPolicyApplied = 0; - ApplyPolicy(pAssemblyName, pCurDomain->GetFusionContext(), nullptr, &pPolicyAssemblyName, nullptr, nullptr, &dwPolicyApplied); - - if (dwPolicyApplied != 0) - { - postPolicySpec.InitializeSpec(pPolicyAssemblyName); - pBindSpec = &postPolicySpec; - pPEAssembly = clr::SafeAddRef(FindCachedFile(pCurDomain, pBindSpec)); - } - } - - if (pPEAssembly == nullptr) - { - // Trigger a load. - pPEAssembly = pCurDomain->BindAssemblySpec( - pBindSpec, // AssemblySpec - TRUE, // ThrowOnFileNotFound - FALSE, // RaisePrebindEvents - nullptr, // CallerStackMark - nullptr, // AssemblyLoadSecurity - FALSE); // fUseHostBinderIfAvailable - to avoid infinite recursion - _ASSERTE(FindCachedFile(pCurDomain, pBindSpec) == pPEAssembly || pBindSpec->IsMscorlib()); - } - - // If a post-policy spec was used, add the pre-policy spec to the binding cache - // so that it can be found by FindAssemblyBySpec. - if (&prePolicySpec != pBindSpec) - { - // Failure to add simply means someone else beat us to it. In that case - // the FindCachedFile call below (after catch block) will update result - // to the cached value. - INDEBUG(BOOL fRes =) pCurDomain->AddFileToCache(&prePolicySpec, pPEAssembly, TRUE /* fAllowFailure */); - _ASSERTE(!fRes || prePolicySpec.IsMscorlib() || FindCachedFile(pCurDomain, &prePolicySpec) == pPEAssembly); - } - - // Ensure that the assembly is discoverable through a consistent assembly name (the assembly def name of the assembly) - AssemblySpec specAssemblyDef; - specAssemblyDef.InitializeSpec(pPEAssembly); - - // It is expected that all assemlbies found here will be unified assemblies, and therefore have a public key. - _ASSERTE(specAssemblyDef.IsStrongNamed()); - - // Convert public key into the format that matches the garaunteed cache in the AssemblySpecBindingCache ... see the extended logic - // in Module::GetAssemblyIfLoaded. - if (specAssemblyDef.IsStrongNamed() && specAssemblyDef.HasPublicKey()) - { - specAssemblyDef.ConvertPublicKeyToToken(); - } - pCurDomain->AddFileToCache(&specAssemblyDef, pPEAssembly, TRUE); - } - - if (!pPEAssembly->HasHostAssembly()) - { - // This can happen if we just loaded the PEAssembly with BindAssemblySpec above, or if the PEAssembly - // Was not loaded through this binder. (NGEN Case) - - // Note: There can be multiple PEAssembly objects for the same file, however we have to create unique - // CLRPrivAssemblyFusion object, otherwise code:AppDomain::FindAssembly will not recognize the duplicates which - // will lead to creation of multiple code:DomainAssembly objects for the same file in the same AppDomain. - - InlineSString<128> ssPEAssemblyName; - FusionBind::GetAssemblyNameDisplayName(pPEAssembly->GetFusionAssemblyName(), ssPEAssemblyName, ASM_DISPLAYF_FULL); - NewHolder pAssemblyObj = new CLRPrivAssemblyFusion(ssPEAssemblyName.GetUnicode(), this); - - { - CrstHolder lock(&m_SetHostAssemblyLock); - if (!pPEAssembly->HasHostAssembly()) - { - // Add the host assembly to the PEAssembly. - pPEAssembly->SetHostAssembly(pAssemblyObj.Extract()); - } - } - } - - // Trigger a load so that a DomainAssembly is associated with the ICLRPrivAssembly created above. - pPEAssembly = clr::SafeAddRef(pCurDomain->LoadDomainAssembly(pBindSpec, pPEAssembly, FILE_LOADED)->GetFile()); - - _ASSERTE(pPEAssembly != nullptr); - _ASSERTE(pPEAssembly->HasHostAssembly()); - _ASSERTE(pCurDomain->FindAssembly(pPEAssembly->GetHostAssembly()) != nullptr); - - fusion::logging::LogMessage(0, ID_FUSLOG_BINDING_STATUS_FOUND, pPEAssembly->GetPath().GetUnicode()); - - *ppAssembly = clr::SafeAddRef(pPEAssembly->GetHostAssembly()); - - return hr; -} - -//===================================================================================================================== -void CLRPrivBinderFusion::BindMscorlib( - PEAssembly * pPEAssembly) -{ - STANDARD_VM_CONTRACT; - -#ifdef _DEBUG - NewArrayHolder dbg_wszAssemblySimpleName; - _ASSERTE(SUCCEEDED(fusion::util::GetProperty(pPEAssembly->GetFusionAssemblyName(), ASM_NAME_NAME, &dbg_wszAssemblySimpleName))); - - _ASSERTE(wcscmp(dbg_wszAssemblySimpleName, W("mscorlib")) == 0); -#endif //_DEBUG - - NewHolder pPrivAssembly = new CLRPrivAssemblyFusion(W("mscorlib"), this); - - pPEAssembly->SetHostAssembly(pPrivAssembly.Extract()); -} - -//===================================================================================================================== -HRESULT CLRPrivBinderFusion::BindFusionAssemblyByName( - IAssemblyName * pAssemblyName, - BindingScope kBindingScope, - ICLRPrivAssembly ** ppAssembly) -{ - STANDARD_VM_CONTRACT; - HRESULT hr = S_OK; - - fusion::logging::StatusScope logStatus(0, ID_FUSLOG_BINDING_STATUS_FRAMEWORK, &hr); - - DWORD dwContentType = AssemblyContentType_Default; - IfFailRet(fusion::util::GetProperty(pAssemblyName, ASM_NAME_CONTENT_TYPE, &dwContentType)); - if ((hr == S_OK) && (dwContentType != AssemblyContentType_Default)) - { // Not a NetFX content type. - IfFailRet(CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT); - } - - BOOL fIsSupportedInAppX; - if (Fusion::Util::IsAnyFrameworkAssembly(pAssemblyName, &fIsSupportedInAppX) != S_OK) - { // Not a framework assembly identity. - IfFailRet(CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT); - } - if (kBindingScope == kBindingScope_FrameworkSubset) - { // We should allow only some framework assemblies to load - - // DevMode has to allow all FX assemblies, not just a subset - see code:PreBind for more info - _ASSERTE(!AppX::IsAppXDesignMode()); - - if (!fIsSupportedInAppX) - { // Assembly is blocked for AppX, fail the load - fusion::logging::LogMessage(0, ID_FUSLOG_BINDING_STATUS_FX_ASSEMBLY_BLOCKED); - - IfFailRet(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); - } - } - - return (hr = BindAssemblyByNameWorker(pAssemblyName, ppAssembly)); -} - -//===================================================================================================================== -// Implements code:ICLRPrivBinder::BindAssemblyByName -HRESULT CLRPrivBinderFusion::BindAssemblyByName( - IAssemblyName * pAssemblyName, - ICLRPrivAssembly ** ppAssembly) -{ - WRAPPER_NO_CONTRACT; - return BindAssemblyByNameWorker( - pAssemblyName, - ppAssembly); -} - -//===================================================================================================================== -// Implements code:ICLRPrivBinder::GetBinderID -HRESULT CLRPrivBinderFusion::GetBinderID( - UINT_PTR *pBinderId) -{ - LIMITED_METHOD_CONTRACT; - - *pBinderId = (UINT_PTR)this; - return S_OK; -} - -//===================================================================================================================== -// Implements code:IBindContext::PreBind -HRESULT CLRPrivBinderFusion::PreBind( - IAssemblyName * pIAssemblyName, - DWORD dwPreBindFlags, - IBindResult ** ppIBindResult) -{ - STANDARD_BIND_CONTRACT; - PRECONDITION(CheckPointer(pIAssemblyName)); - PRECONDITION(CheckPointer(ppIBindResult)); - - HRESULT hr = S_OK; - - BOOL fIsSupportedInAppX; - if (Fusion::Util::IsAnyFrameworkAssembly(pIAssemblyName, &fIsSupportedInAppX) != S_OK) - { // Not a framework assembly identity. - return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); - } - - EX_TRY - { - // Create new IL binding scope. - fusion::logging::BindingScope defaultScope(pIAssemblyName, FUSION_BIND_LOG_CATEGORY_DEFAULT); - - // Ideally the caller would give us arg kBindingContext like in code:BindFusionAssemblyByName, so we can give the same answer. - // That is not easy, so we will make the decision here: - // - DevMode will allow all FX assemblies (that covers designer binding context scenario for designers that need to - // load WPF with ngen images for perf reasons). - // We know that the real bind via code:BindFusionAssemblyByName will succeed for the assemblies (because we are in DevMode). - // - Normal mode (non-DevMode) we will allow only subset of FX assemblies. - // It implies that designer binding context (used by debuggers) will not use ngen images for blocked FX assemblies - // (transitively). That is acceptable performance trade-off. - if (!AppX::IsAppXDesignMode()) - { // We should allow only some framework assemblies to load - if (!fIsSupportedInAppX) - { // Assembly is blocked for AppX, fail the load - fusion::logging::LogMessage(0, ID_FUSLOG_BINDING_STATUS_FX_ASSEMBLY_BLOCKED); - - hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); - } - } - - if (SUCCEEDED(hr)) - { - AppDomain * pDomain = AppDomain::GetCurrentDomain(); - ReleaseHolder pIBindContext; - if (SUCCEEDED(hr = GetBindContextFromApplicationContext(pDomain->CreateFusionContext(), &pIBindContext))) - { - hr = pIBindContext->PreBind(pIAssemblyName, dwPreBindFlags, ppIBindResult); - } - } - } - EX_CATCH_HRESULT(hr); - - return hr; -} - -//===================================================================================================================== -HRESULT CLRPrivBinderFusion::PreBindFusionAssemblyByName( - IAssemblyName *pIAssemblyName, - DWORD dwPreBindFlags, - IBindResult **ppIBindResult) -{ - STANDARD_VM_CONTRACT; - HRESULT hr = S_OK; - - DWORD dwContentType = AssemblyContentType_Default; - IfFailRet(fusion::util::GetProperty(pIAssemblyName, ASM_NAME_CONTENT_TYPE, &dwContentType)); - if ((hr == S_OK) && (dwContentType != AssemblyContentType_Default)) - { // Not a NetFX content type. - IfFailRet(CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT); - } - - IfFailRet(PreBind(pIAssemblyName, dwPreBindFlags, ppIBindResult)); - _ASSERTE(*ppIBindResult != nullptr); - - if (*ppIBindResult == nullptr) - IfFailRet(E_UNEXPECTED); - - return S_OK; -} - -//===================================================================================================================== -// Implements code:IBindContext::IsDefaultContext -HRESULT CLRPrivBinderFusion::IsDefaultContext() -{ - STANDARD_BIND_CONTRACT; - return S_OK; -} - -//===================================================================================================================== -CLRPrivBinderFusion::~CLRPrivBinderFusion() -{ - WRAPPER_NO_CONTRACT; -} - -//===================================================================================================================== -CLRPrivAssemblyFusion::CLRPrivAssemblyFusion( - LPCWSTR wszName, - CLRPrivBinderFusion * pBinder) - : m_pBinder(clr::SafeAddRef(pBinder)), - m_wszName(DuplicateStringThrowing(wszName)) -{ - STANDARD_VM_CONTRACT; -} - -//===================================================================================================================== -LPCWSTR CLRPrivAssemblyFusion::GetName() const -{ - LIMITED_METHOD_CONTRACT; - - return m_wszName; -} - -//===================================================================================================================== -// Implements code:IUnknown::Release -ULONG CLRPrivAssemblyFusion::Release() -{ - LIMITED_METHOD_CONTRACT; - STATIC_CONTRACT_CAN_TAKE_LOCK; - _ASSERTE(m_cRef > 0); - - ULONG cRef = InterlockedDecrement(&m_cRef); - - if (cRef == 0) - { - delete this; - } - - return cRef; -} - -//===================================================================================================================== -// Implements code:ICLRPrivBinder::BindAssemblyByName -HRESULT CLRPrivAssemblyFusion::BindAssemblyByName( - IAssemblyName * pAssemblyName, - ICLRPrivAssembly ** ppAssembly) -{ - WRAPPER_NO_CONTRACT; - return m_pBinder->BindAssemblyByName( - pAssemblyName, - ppAssembly); -} - -//===================================================================================================================== -// Implements code:ICLRPrivBinder::GetBinderID -HRESULT CLRPrivAssemblyFusion::GetBinderID( - UINT_PTR *pBinderId) -{ - LIMITED_METHOD_CONTRACT; - - *pBinderId = reinterpret_cast(m_pBinder.GetValue()); - return S_OK; -} - -//===================================================================================================================== -// Implements code:ICLRPrivAssembly::IsShareable -HRESULT CLRPrivAssemblyFusion::IsShareable( - BOOL * pbIsShareable) -{ - LIMITED_METHOD_CONTRACT; - *pbIsShareable = TRUE; // These things are only used in the AppX scenario, where all fusion assemblies are unified, shareable assemblies. - return S_OK; -} - -//===================================================================================================================== -// Implements code:ICLRPrivAssembly::GetAvailableImageTypes -HRESULT CLRPrivAssemblyFusion::GetAvailableImageTypes( - LPDWORD pdwImageTypes) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"CLRPrivAssemblyFusion::GetAvailableImageTypes"); - return E_NOTIMPL; -} - -//===================================================================================================================== -// Implements code:ICLRPrivAssembly::GetImageResource -HRESULT CLRPrivAssemblyFusion::GetImageResource( - DWORD dwImageType, - DWORD *pdwImageType, - ICLRPrivResource ** ppIResource) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(!"CLRPrivAssemblyFusion::GetImageResource"); - return E_NOTIMPL; -} - -#endif // !DACCESS_COMPILE - diff --git a/src/vm/clrprivbinderfusion.h b/src/vm/clrprivbinderfusion.h deleted file mode 100644 index 3cf3694e4f..0000000000 --- a/src/vm/clrprivbinderfusion.h +++ /dev/null @@ -1,228 +0,0 @@ -// 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. - - - -#pragma once - -#include "holder.h" -#include "internalunknownimpl.h" -#include "shash.h" -#include "clrprivbinding.h" -#include "clrprivruntimebinders.h" - -//===================================================================================================================== -// Forward declarations -class CLRPrivBinderFusion; -class CLRPrivAssemblyFusion; - -class PEAssembly; -class DomainAssembly; -struct IMDInternalImport; - -//===================================================================================================================== -class CLRPrivBinderFusion : - public IUnknownCommon -{ - friend class CLRPrivAssemblyFusion; - -public: - // Scope for the bind operation - enum BindingScope - { - // Binds only to subset of framework that is not on the black list (non-FX assemblies bindings are rejected) - kBindingScope_FrameworkSubset, - // Binds to all framework assemblies (incl. those on the black list) (non-FX assemblies bindings are rejected) - // Used by designer binding context and in DevMode - kBindingScope_FrameworkAll - }; - -public: - //============================================================================================= - // ICLRPrivBinder methods - - //--------------------------------------------------------------------------------------------- - // Implements code:ICLRPrivBinder::BindAssemblyByName - STDMETHOD(BindAssemblyByName( - IAssemblyName * pAssemblyName, - ICLRPrivAssembly ** ppAssembly)); - - //--------------------------------------------------------------------------------------------- - // Implements code:ICLRPrivBinder::VerifyBind - STDMETHOD(VerifyBind)( - IAssemblyName *pAssemblyName, - ICLRPrivAssembly *pAssembly, - ICLRPrivAssemblyInfo *pAssemblyInfo) - { - LIMITED_METHOD_CONTRACT; - if (pAssemblyName == nullptr || pAssembly == nullptr || pAssemblyInfo == nullptr) - return E_INVALIDARG; - return S_OK; - } - - //--------------------------------------------------------------------------------------------- - // Implements code:ICLRPrivBinder::GetBinderFlags - STDMETHOD(GetBinderFlags)( - DWORD *pBinderFlags) - { - LIMITED_METHOD_CONTRACT; - *pBinderFlags = BINDER_FINDASSEMBLYBYSPEC_REQUIRES_EXACT_MATCH; - return S_OK; - } - - //--------------------------------------------------------------------------------------------- - // Implements code:ICLRPrivBinder::GetBinderID - STDMETHOD(GetBinderID)( - UINT_PTR *pBinderId); - - STDMETHOD(FindAssemblyBySpec)( - LPVOID pvAppDomain, - LPVOID pvAssemblySpec, - HRESULT * pResult, - ICLRPrivAssembly ** ppAssembly); - - //============================================================================================= - // IBindContext methods - - // Implements code:IBindContext::PreBind - STDMETHOD(PreBind)( - IAssemblyName *pIAssemblyName, - DWORD dwPreBindFlags, - IBindResult **ppIBindResult); - - // Implements code:IBindContext::IsDefaultContext - STDMETHOD(IsDefaultContext)(); - - //============================================================================================= - // Class methods - - //--------------------------------------------------------------------------------------------- - CLRPrivBinderFusion() - : m_SetHostAssemblyLock(CrstLeafLock) - { STANDARD_VM_CONTRACT; } - - //--------------------------------------------------------------------------------------------- - ~CLRPrivBinderFusion(); - - //--------------------------------------------------------------------------------------------- - HRESULT FindFusionAssemblyBySpec( - LPVOID pvAppDomain, - LPVOID pvAssemblySpec, - BindingScope kBindingScope, - HRESULT * pResult, - ICLRPrivAssembly ** ppAssembly); - - //--------------------------------------------------------------------------------------------- - HRESULT BindFusionAssemblyByName( - IAssemblyName * pAssemblyName, - BindingScope kBindingScope, - ICLRPrivAssembly ** ppAssembly); - - //--------------------------------------------------------------------------------------------- - HRESULT PreBindFusionAssemblyByName( - IAssemblyName * pIAssemblyName, - DWORD dwPreBindFlags, - IBindResult ** ppIBindResult); - - //--------------------------------------------------------------------------------------------- - // Binds mscorlib.dll - void BindMscorlib( - PEAssembly * pPEAssembly); - -private: - //--------------------------------------------------------------------------------------------- - HRESULT BindAssemblyByNameWorker( - IAssemblyName * pAssemblyName, - ICLRPrivAssembly ** ppAssembly); - -private: - //--------------------------------------------------------------------------------------------- - // This lock is used to serialize assigning ICLRPrivAssembly instances to PEAssembly objects. - Crst m_SetHostAssemblyLock; - -}; // class CLRPrivBinderFusion - -//===================================================================================================================== -class CLRPrivAssemblyFusion : - public IUnknownCommon -{ -public: - //--------------------------------------------------------------------------------------------- - CLRPrivAssemblyFusion( - LPCWSTR wszName, - CLRPrivBinderFusion * pBinder); - - //--------------------------------------------------------------------------------------------- - LPCWSTR GetName() const; - - //--------------------------------------------------------------------------------------------- - // Implements code:IUnknown::Release - STDMETHOD_(ULONG, Release)(); - - //--------------------------------------------------------------------------------------------- - // Implements code:ICLRPrivBinder::BindAssemblyByName - STDMETHOD(BindAssemblyByName)( - IAssemblyName * pAssemblyName, - ICLRPrivAssembly ** ppAssembly); - - //--------------------------------------------------------------------------------------------- - // Implements code:ICLRPrivAssembly::IsShareable - STDMETHOD(IsShareable)( - BOOL * pbIsShareable); - - //--------------------------------------------------------------------------------------------- - // Implements code:ICLRPrivAssembly::GetAvailableImageTypes - STDMETHOD(GetAvailableImageTypes)( - LPDWORD pdwImageTypes); - - //--------------------------------------------------------------------------------------------- - // Implements code:ICLRPrivAssembly::GetImageResource - STDMETHOD(GetImageResource)( - DWORD dwImageType, - DWORD *pdwImageType, - ICLRPrivResource ** ppIResource); - - //--------------------------------------------------------------------------------------------- - // Implements code:ICLRPrivBinder::VerifyBind - STDMETHOD(VerifyBind)( - IAssemblyName *pAssemblyName, - ICLRPrivAssembly *pAssembly, - ICLRPrivAssemblyInfo *pAssemblyInfo) - { - WRAPPER_NO_CONTRACT; - return m_pBinder->VerifyBind(pAssemblyName, pAssembly, pAssemblyInfo); - } - - //--------------------------------------------------------------------------------------------- - // Implements code:ICLRPrivBinder::GetBinderFlags - STDMETHOD(GetBinderFlags)( - DWORD *pBinderFlags) - { - LIMITED_METHOD_CONTRACT; - return m_pBinder->GetBinderFlags(pBinderFlags); - } - - //--------------------------------------------------------------------------------------------- - // Implements code:ICLRPrivBinder::GetBinderID - STDMETHOD(GetBinderID)( - UINT_PTR *pBinderId); - - //--------------------------------------------------------------------------------------------- - // Implements code:ICLRPrivBinder::FindAssemblyBySpec - STDMETHOD(FindAssemblyBySpec)( - LPVOID pvAppDomain, - LPVOID pvAssemblySpec, - HRESULT * pResult, - ICLRPrivAssembly ** ppAssembly) - { STATIC_CONTRACT_WRAPPER; return m_pBinder->FindAssemblyBySpec(pvAppDomain, pvAssemblySpec, pResult, ppAssembly); } - -protected: - //--------------------------------------------------------------------------------------------- - // The fusion binder. Need to keep it around as long as this object is around. - ReleaseHolder m_pBinder; - - // Full display name of the assembly - used to avoid duplicate CLRPrivAssemblyFusion objects - NewArrayHolder m_wszName; - -}; // class CLRPrivAssemblyFusion diff --git a/src/vm/clrprivbinderreflectiononlywinrt.cpp b/src/vm/clrprivbinderreflectiononlywinrt.cpp deleted file mode 100644 index ad46511e81..0000000000 --- a/src/vm/clrprivbinderreflectiononlywinrt.cpp +++ /dev/null @@ -1,497 +0,0 @@ -// 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. -// - -// -// Contains the types that implement code:ICLRPrivBinder and code:ICLRPrivAssembly for WinRT ReflectionOnly (aka introspection) binding. -// -//===================================================================================================================== - -#include "common.h" // precompiled header - -#ifndef DACCESS_COMPILE -#ifdef FEATURE_REFLECTION_ONLY_LOAD - -//===================================================================================================================== -#include "sstring.h" -#include "policy.h" -#include "clrprivbinderreflectiononlywinrt.h" -#include "appxutil.h" -#include "clrprivbinderutil.h" -#include "imprthelpers.h" // in fusion/inc - -#include -#include - -using namespace CLRPrivBinderUtil; - -//===================================================================================================================== - -//===================================================================================================================== -CLRPrivBinderReflectionOnlyWinRT::CLRPrivBinderReflectionOnlyWinRT( - CLRPrivTypeCacheReflectionOnlyWinRT * pTypeCache) - : m_MapsLock(CrstLeafLock, CRST_REENTRANCY) // Reentracy is needed for code:CLRPrivAssemblyReflectionOnlyWinRT::Release -{ - STANDARD_VM_CONTRACT; - - // This binder is not supported in AppX scenario. - _ASSERTE(!AppX::IsAppXProcess()); - - _ASSERTE(pTypeCache != nullptr); - m_pTypeCache = clr::SafeAddRef(pTypeCache); -} - -//===================================================================================================================== -CLRPrivBinderReflectionOnlyWinRT::~CLRPrivBinderReflectionOnlyWinRT() -{ - WRAPPER_NO_CONTRACT; - - if (m_pTypeCache != nullptr) - { - m_pTypeCache->Release(); - } -} - -//===================================================================================================================== -HRESULT -CLRPrivBinderReflectionOnlyWinRT::BindWinRtType_Internal( - LPCSTR szTypeNamespace, - LPCSTR szTypeClassName, - DomainAssembly * pParentAssembly, - CLRPrivAssemblyReflectionOnlyWinRT ** ppAssembly) -{ - STANDARD_VM_CONTRACT; - - HRESULT hr = S_OK; - - VALIDATE_ARG_RET(ppAssembly != nullptr); - - CLRPrivBinderUtil::WStringList * pFileNameList = nullptr; - - StackSString ssTypeNamespace(SString::Utf8, szTypeNamespace); - - GetFileNameListForNamespace(ssTypeNamespace.GetUnicode(), pParentAssembly, &pFileNameList); - - if (pFileNameList == nullptr) - { // There are no files associated with the namespace - return CLR_E_BIND_TYPE_NOT_FOUND; - } - - StackSString ssTypeName(ssTypeNamespace); - ssTypeName.Append(W('.')); - ssTypeName.AppendUTF8(szTypeClassName); - - CLRPrivBinderUtil::WStringListElem * pFileNameElem = pFileNameList->GetHead(); - while (pFileNameElem != nullptr) - { - const WCHAR * wszFileName = pFileNameElem->GetValue(); - ReleaseHolder pAssembly = FindOrCreateAssemblyByFileName(wszFileName); - _ASSERTE(pAssembly != NULL); - - IfFailRet(hr = m_pTypeCache->ContainsType(pAssembly, ssTypeName.GetUnicode())); - if (hr == S_OK) - { // The type we are looking for has been found in this assembly - *ppAssembly = pAssembly.Extract(); - return S_OK; - } - _ASSERTE(hr == S_FALSE); - - // Try next file name for this namespace - pFileNameElem = CLRPrivBinderUtil::WStringList::GetNext(pFileNameElem); - } - - // The type has not been found in any of the files from the type's namespace - return CLR_E_BIND_TYPE_NOT_FOUND; -} // CLRPrivBinderReflectionOnlyWinRT::BindWinRtType_Internal - -//===================================================================================================================== -HRESULT -CLRPrivBinderReflectionOnlyWinRT::BindWinRtType( - LPCSTR szTypeNamespace, - LPCSTR szTypeClassName, - DomainAssembly * pParentAssembly, - ICLRPrivAssembly ** ppPrivAssembly) -{ - STANDARD_VM_CONTRACT; - - HRESULT hr = S_OK; - - ReleaseHolder pWinRTAssembly; - IfFailRet(BindWinRtType_Internal(szTypeNamespace, szTypeClassName, pParentAssembly, &pWinRTAssembly)); - IfFailRet(pWinRTAssembly->QueryInterface(__uuidof(ICLRPrivAssembly), (LPVOID *)ppPrivAssembly)); - - return hr; -} - -//===================================================================================================================== -// Implements interface method code:ICLRPrivBinder::BindAssemblyByName. -// -HRESULT CLRPrivBinderReflectionOnlyWinRT::BindAssemblyByName( - IAssemblyName * pAssemblyName, - ICLRPrivAssembly ** ppAssembly) -{ - LIMITED_METHOD_CONTRACT; - - _ASSERTE_MSG(false, "Unexpected call to CLRPrivBinderReflectionOnlyWinRT::BindAssemblyByName"); - return E_UNEXPECTED; -} - -//===================================================================================================================== -ReleaseHolder -CLRPrivBinderReflectionOnlyWinRT::FindAssemblyByFileName( - LPCWSTR wszFileName) -{ - LIMITED_METHOD_CONTRACT; - STATIC_CONTRACT_CAN_TAKE_LOCK; - - CrstHolder lock(&m_MapsLock); - const FileNameToAssemblyMapEntry * pEntry = m_FileNameToAssemblyMap.LookupPtr(wszFileName); - return (pEntry == nullptr) ? nullptr : clr::SafeAddRef(pEntry->m_pAssembly); -} - -//===================================================================================================================== -// Add FileName -> CLRPrivAssemblyReflectionOnlyWinRT * mapping to the map (multi-thread safe). -ReleaseHolder -CLRPrivBinderReflectionOnlyWinRT::AddFileNameToAssemblyMapping( - LPCWSTR wszFileName, - CLRPrivAssemblyReflectionOnlyWinRT * pAssembly) -{ - STANDARD_VM_CONTRACT; - - _ASSERTE(pAssembly != nullptr); - - CrstHolder lock(&m_MapsLock); - - const FileNameToAssemblyMapEntry * pEntry = m_FileNameToAssemblyMap.LookupPtr(wszFileName); - CLRPrivAssemblyReflectionOnlyWinRT * pResultAssembly = nullptr; - if (pEntry != nullptr) - { - pResultAssembly = pEntry->m_pAssembly; - } - else - { - FileNameToAssemblyMapEntry e; - e.m_wszFileName = wszFileName; - e.m_pAssembly = pAssembly; - m_FileNameToAssemblyMap.Add(e); - - pResultAssembly = pAssembly; - } - return clr::SafeAddRef(pResultAssembly); -} - -//===================================================================================================================== -void -CLRPrivBinderReflectionOnlyWinRT::RemoveFileNameToAssemblyMapping( - LPCWSTR wszFileName) -{ - LIMITED_METHOD_CONTRACT; - STATIC_CONTRACT_CAN_TAKE_LOCK; - - CrstHolder lock(&m_MapsLock); - m_FileNameToAssemblyMap.Remove(wszFileName); -} - -//===================================================================================================================== -ReleaseHolder -CLRPrivBinderReflectionOnlyWinRT::FindOrCreateAssemblyByFileName( - LPCWSTR wszFileName) -{ - STANDARD_VM_CONTRACT; - - ReleaseHolder pAssembly = FindAssemblyByFileName(wszFileName); - - if (pAssembly == nullptr) - { - NewHolder pResource( - new CLRPrivResourcePathImpl(wszFileName)); - - NewHolder pNewAssembly( - new CLRPrivAssemblyReflectionOnlyWinRT(wszFileName, this, pResource)); - - // pNewAssembly holds reference to this now - pResource.SuppressRelease(); - - // Add the assembly into cache (multi-thread aware) - pAssembly = AddFileNameToAssemblyMapping(pResource->GetPath(), pNewAssembly); - - if (pAssembly == pNewAssembly) - { // We did not find an existing assembly in the cache and are using the newly created pNewAssembly. - // Stop it from being deleted when we go out of scope. - pNewAssembly.SuppressRelease(); - } - } - return pAssembly.Extract(); -} - -//===================================================================================================================== -// Returns list of file names from code:m_NamespaceToFileNameListMap for the namespace. -// -void -CLRPrivBinderReflectionOnlyWinRT::GetFileNameListForNamespace( - LPCWSTR wszNamespace, - DomainAssembly * pParentAssembly, - CLRPrivBinderUtil::WStringList ** ppFileNameList) -{ - STANDARD_VM_CONTRACT; - - CLRPrivBinderUtil::WStringList * pFileNameList = nullptr; - { - CrstHolder lock(&m_MapsLock); - - const NamespaceToFileNameListMapEntry * pEntry = m_NamespaceToFileNameListMap.LookupPtr(wszNamespace); - if (pEntry != nullptr) - { - // Entries from the map are never removed, so we do not have to protect the file name list with a lock - pFileNameList = pEntry->m_pFileNameList; - } - } - - if (pFileNameList != nullptr) - { - *ppFileNameList = pFileNameList; - } - else - { - CLRPrivBinderUtil::WStringListHolder hFileNameList; - - EX_TRY - { - m_pTypeCache->RaiseNamespaceResolveEvent(wszNamespace, pParentAssembly, &hFileNameList); - } - EX_CATCH - { - Exception * ex = GET_EXCEPTION(); - if (!ex->IsTransient()) - { // Exception was caused by user code - // Cache empty file name list for this namespace - (void)AddFileNameListForNamespace(wszNamespace, nullptr, ppFileNameList); - } - EX_RETHROW; - } - EX_END_CATCH_UNREACHABLE - - if (AddFileNameListForNamespace(wszNamespace, hFileNameList.GetValue(), ppFileNameList)) - { // The file name list was added to the cache - do not delete it - _ASSERTE(*ppFileNameList == hFileNameList.GetValue()); - (void)hFileNameList.Extract(); - } - } -} // CLRPrivBinderReflectionOnlyWinRT::GetFileNameListForNamespace - -//===================================================================================================================== -// Adds (thread-safe) list of file names to code:m_NamespaceToFileNameListMap for the namespace - returns the cached value. -// Returns TRUE, if pFileNameList was added to the cache and caller should NOT delete it. -// Returns FALSE, if pFileNameList was not added to the cache and caller should delete it. -// -BOOL -CLRPrivBinderReflectionOnlyWinRT::AddFileNameListForNamespace( - LPCWSTR wszNamespace, - CLRPrivBinderUtil::WStringList * pFileNameList, - CLRPrivBinderUtil::WStringList ** ppFileNameList) -{ - STANDARD_VM_CONTRACT; - - NewArrayHolder wszEntryNamespace = DuplicateStringThrowing(wszNamespace); - - NamespaceToFileNameListMapEntry entry; - entry.m_wszNamespace = wszEntryNamespace; - entry.m_pFileNameList = pFileNameList; - - { - CrstHolder lock(&m_MapsLock); - - const NamespaceToFileNameListMapEntry * pEntry = m_NamespaceToFileNameListMap.LookupPtr(wszEntryNamespace); - if (pEntry == nullptr) - { - m_NamespaceToFileNameListMap.Add(entry); - - // These values are now owned by the hash table element - wszEntryNamespace.SuppressRelease(); - *ppFileNameList = pFileNameList; - return TRUE; - } - else - { // Another thread beat us adding this entry to the hash table - *ppFileNameList = pEntry->m_pFileNameList; - return FALSE; - } - } -} // CLRPrivBinderReflectionOnlyWinRT::AddFileNameListForNamespace - -//===================================================================================================================== -HRESULT -CLRPrivBinderReflectionOnlyWinRT::BindAssemblyExplicit( - const WCHAR * wszFileName, - ICLRPrivAssembly ** ppAssembly) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - HRESULT hr; - - GCX_PREEMP(); - - ReleaseHolder pAssembly = FindOrCreateAssemblyByFileName(wszFileName); - _ASSERTE(pAssembly != NULL); - - IfFailRet(pAssembly->QueryInterface(__uuidof(ICLRPrivAssembly), (LPVOID *)ppAssembly)); - - return S_OK; -} - -//===================================================================================================================== -CLRPrivAssemblyReflectionOnlyWinRT::CLRPrivAssemblyReflectionOnlyWinRT( - LPCWSTR wzSimpleName, - CLRPrivBinderReflectionOnlyWinRT * pBinder, - CLRPrivResourcePathImpl * pResourceIL) -{ - STANDARD_VM_CONTRACT; - VALIDATE_ARG_THROW((wzSimpleName != nullptr) && (pBinder != nullptr) && (pResourceIL != nullptr)); - - m_pBinder = clr::SafeAddRef(pBinder); - m_pResourceIL = clr::SafeAddRef(pResourceIL); -} - -//===================================================================================================================== -ULONG CLRPrivAssemblyReflectionOnlyWinRT::Release() -{ - LIMITED_METHOD_CONTRACT; - STATIC_CONTRACT_CAN_TAKE_LOCK; - _ASSERTE(m_cRef > 0); - - ULONG cRef; - - { - // To achieve proper lifetime semantics, the name to assembly map elements' CLRPrivAssemblyReflectionOnlyWinRT - // instances are not ref counted. We cannot allow discovery of the object via m_FileNameToAssemblyMap - // when the ref count is 0 (to prevent another thread to AddRef and Release it back to 0 in parallel). - // All uses of the map are guarded by the map lock, so we have to decrease the ref count under that - // lock (to avoid the chance that 2 threads are running Release to ref count 0 at once). - CrstHolder lock(&m_pBinder->m_MapsLock); - - cRef = InterlockedDecrement(&m_cRef); - if (cRef == 0) - { - m_pBinder->RemoveFileNameToAssemblyMapping(m_pResourceIL->GetPath()); - } - } - - if (cRef == 0) - { - delete this; - } - return cRef; -} - -//===================================================================================================================== -// Implements interface method code:ICLRPrivAssembly::IsShareable. -// -HRESULT CLRPrivAssemblyReflectionOnlyWinRT::IsShareable( - BOOL * pbIsShareable) -{ - LIMITED_METHOD_CONTRACT; - - VALIDATE_ARG_RET(pbIsShareable != nullptr); - - *pbIsShareable = FALSE; - return S_OK; -} - -//===================================================================================================================== -// Implements interface method code:ICLRPrivAssembly::GetAvailableImageTypes. -// -HRESULT CLRPrivAssemblyReflectionOnlyWinRT::GetAvailableImageTypes( - LPDWORD pdwImageTypes) -{ - LIMITED_METHOD_CONTRACT; - - VALIDATE_ARG_RET(pdwImageTypes != nullptr); - - *pdwImageTypes = 0; - - if (m_pResourceIL != nullptr) - *pdwImageTypes |= ASSEMBLY_IMAGE_TYPE_IL; - - return S_OK; -} - -//===================================================================================================================== -// Implements interface method code:ICLRPrivAssembly::GetImageResource. -// -HRESULT CLRPrivAssemblyReflectionOnlyWinRT::GetImageResource( - DWORD dwImageType, - DWORD * pdwImageType, - ICLRPrivResource ** ppIResource) -{ - STANDARD_BIND_CONTRACT; - HRESULT hr = S_OK; - - VALIDATE_ARG_RET(ppIResource != nullptr); - - EX_TRY - { - DWORD _dwImageType; - if (pdwImageType == nullptr) - { - pdwImageType = &_dwImageType; - } - - if ((dwImageType & ASSEMBLY_IMAGE_TYPE_IL) == ASSEMBLY_IMAGE_TYPE_IL) - { - *ppIResource = clr::SafeAddRef(m_pResourceIL); - *pdwImageType = ASSEMBLY_IMAGE_TYPE_IL; - } - else - { // Native image is not supported by this binder - hr = CLR_E_BIND_IMAGE_UNAVAILABLE; - } - } - EX_CATCH_HRESULT(hr); - - return hr; -} - -//===================================================================================================================== -// Implements interface method code:ICLRPrivBinder::VerifyBind. -// -HRESULT CLRPrivBinderReflectionOnlyWinRT::VerifyBind( - IAssemblyName * pAssemblyName, - ICLRPrivAssembly * pAssembly, - ICLRPrivAssemblyInfo * pAssemblyInfo) -{ - STANDARD_BIND_CONTRACT; - HRESULT hr = S_OK; - - UINT_PTR binderID; - IfFailRet(pAssembly->GetBinderID(&binderID)); - if (binderID != reinterpret_cast(this)) - { - return pAssembly->VerifyBind(pAssemblyName, pAssembly, pAssemblyInfo); - } - - // Since WinRT types are bound by type name and not assembly name, assembly-level version validation - // does not make sense here. Just return S_OK. - return S_OK; -} - -//===================================================================================================================== -// Implements interface method code:ICLRPrivBinder::GetBinderID. -// -HRESULT CLRPrivBinderReflectionOnlyWinRT::GetBinderID( - UINT_PTR * pBinderId) -{ - LIMITED_METHOD_CONTRACT; - - *pBinderId = reinterpret_cast(this); - return S_OK; -} - -#endif //FEATURE_REFLECTION_ONLY_LOAD -#endif //!DACCESS_COMPILE diff --git a/src/vm/clrprivbinderreflectiononlywinrt.h b/src/vm/clrprivbinderreflectiononlywinrt.h deleted file mode 100644 index 5f8ef46773..0000000000 --- a/src/vm/clrprivbinderreflectiononlywinrt.h +++ /dev/null @@ -1,295 +0,0 @@ -// 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. -// - -// -// Contains the types that implement code:ICLRPrivBinder and code:ICLRPrivAssembly for WinRT ReflectionOnly (aka introspection) binding. -// -//===================================================================================================================== - -#ifdef FEATURE_REFLECTION_ONLY_LOAD - -#pragma once - -#include "holder.h" -#include "internalunknownimpl.h" -#include "clrprivbinding.h" -#include "clrprivruntimebinders.h" -#include "clrprivbinderutil.h" -#include "clr_std/utility" - -//===================================================================================================================== -// Forward declarations -class CLRPrivBinderReflectionOnlyWinRT; -class CLRPrivAssemblyReflectionOnlyWinRT; -class CLRPrivTypeCacheReflectionOnlyWinRT; -class DomainAssembly; - -//===================================================================================================================== -//===================================================================================================================== -//===================================================================================================================== -class CLRPrivBinderReflectionOnlyWinRT : - public IUnknownCommon -{ - friend class CLRPrivAssemblyReflectionOnlyWinRT; - -private: - //============================================================================================= - // Data structures for Namespace -> FileNameList hash (as returned by RoResolveNamespace API) - - // Entry in SHash table that maps namespace to list of files - struct NamespaceToFileNameListMapEntry - { - PWSTR m_wszNamespace; - CLRPrivBinderUtil::WStringList * m_pFileNameList; - }; - - // SHash traits for Namespace -> FileNameList hash - class NamespaceToFileNameListMapTraits : public NoRemoveSHashTraits< DefaultSHashTraits< NamespaceToFileNameListMapEntry > > - { - public: - typedef PCWSTR key_t; - static const NamespaceToFileNameListMapEntry Null() { NamespaceToFileNameListMapEntry e; e.m_wszNamespace = nullptr; return e; } - static bool IsNull(const NamespaceToFileNameListMapEntry & e) { return e.m_wszNamespace == nullptr; } - static PCWSTR GetKey(const NamespaceToFileNameListMapEntry & e) { return e.m_wszNamespace; } - static count_t Hash(PCWSTR str) { return HashString(str); } - static BOOL Equals(PCWSTR lhs, PCWSTR rhs) { LIMITED_METHOD_CONTRACT; return (wcscmp(lhs, rhs) == 0); } - - void OnDestructPerEntryCleanupAction(const NamespaceToFileNameListMapEntry & e) - { - delete [] e.m_wszNamespace; - CLRPrivBinderUtil::WStringList_Delete(e.m_pFileNameList); - } - static const bool s_DestructPerEntryCleanupAction = true; - }; - - typedef SHash NamespaceToFileNameListMap; - - //============================================================================================= - // Data structure for FileName -> CLRPrivAssemblyReflectionOnlyWinRT * map - - struct FileNameToAssemblyMapEntry - { - PCWSTR m_wszFileName; // File name (owned by m_pAssembly) - CLRPrivAssemblyReflectionOnlyWinRT * m_pAssembly; - }; - - class FileNameToAssemblyMapTraits : public DefaultSHashTraits - { - public: - typedef PCWSTR key_t; - static const FileNameToAssemblyMapEntry Null() { FileNameToAssemblyMapEntry e; e.m_wszFileName = NULL; return e; } - static bool IsNull(const FileNameToAssemblyMapEntry &e) { return e.m_wszFileName == NULL; } - static const FileNameToAssemblyMapEntry Deleted() { FileNameToAssemblyMapEntry e; e.m_wszFileName = (PCWSTR)-1; return e; } - static bool IsDeleted(const FileNameToAssemblyMapEntry & e) { return e.m_wszFileName == (PCWSTR)-1; } - static PCWSTR GetKey(const FileNameToAssemblyMapEntry & e) { return e.m_wszFileName; } - static count_t Hash(PCWSTR str) { return HashString(str); } - static BOOL Equals(PCWSTR lhs, PCWSTR rhs) { LIMITED_METHOD_CONTRACT; return (wcscmp(lhs, rhs) == 0); } - }; - - typedef SHash FileNameToAssemblyMap; - -public: - //============================================================================================= - // ICLRPrivBinder interface methods - - STDMETHOD(BindAssemblyByName)( - IAssemblyName * pAssemblyName, - ICLRPrivAssembly ** ppAssembly); - - // Implements interface method code:ICLRPrivBinder::VerifyBind. - STDMETHOD(VerifyBind)( - IAssemblyName * pAssemblyName, - ICLRPrivAssembly * pAssembly, - ICLRPrivAssemblyInfo * pAssemblyInfo); - - // Implements interface method code:ICLRPrivBinder::GetBinderFlags - STDMETHOD(GetBinderFlags)( - DWORD *pBinderFlags) - { - LIMITED_METHOD_CONTRACT; - *pBinderFlags = BINDER_NONE; - return S_OK; - } - - // Implements interface method code:ICLRPrivBinder::GetBinderID. - STDMETHOD(GetBinderID)( - UINT_PTR * pBinderId); - - // FindAssemblyBySpec is not supported by this binder. - STDMETHOD(FindAssemblyBySpec)( - LPVOID pvAppDomain, - LPVOID pvAssemblySpec, - HRESULT * pResult, - ICLRPrivAssembly ** ppAssembly) - { STATIC_CONTRACT_WRAPPER; return E_FAIL; } - - //============================================================================================= - // Class methods - - CLRPrivBinderReflectionOnlyWinRT( - CLRPrivTypeCacheReflectionOnlyWinRT * pTypeCache); - - ~CLRPrivBinderReflectionOnlyWinRT(); - - HRESULT BindAssemblyExplicit( - const WCHAR * wszFileName, - ICLRPrivAssembly ** ppAssembly); - - HRESULT BindWinRtType( - LPCSTR szTypeNamespace, - LPCSTR szTypeClassName, - DomainAssembly * pParentAssembly, - ICLRPrivAssembly ** ppPrivAssembly); - -private: - //============================================================================================= - // Accessors for FileName -> CLRPrivAssemblyReflectionOnlyWinRT * map - - ReleaseHolder FindAssemblyByFileName( - LPCWSTR wzsFileName); - - ReleaseHolder AddFileNameToAssemblyMapping( - LPCWSTR wszFileName, - CLRPrivAssemblyReflectionOnlyWinRT * pAssembly); - - void RemoveFileNameToAssemblyMapping( - LPCWSTR wszFileName); - - ReleaseHolder FindOrCreateAssemblyByFileName( - LPCWSTR wzsFileName); - - //============================================================================================= - // Internal methods - - // Returns list of file names from code:m_NamespaceToFileNameListMap for the namespace. - void GetFileNameListForNamespace( - LPCWSTR wszNamespace, - DomainAssembly * pParentAssembly, - CLRPrivBinderUtil::WStringList ** ppFileNameList); - - // Adds (thread-safe) list of file names to code:m_NamespaceToFileNameListMap for the namespace - returns the cached value. - BOOL AddFileNameListForNamespace( - LPCWSTR wszNamespace, - CLRPrivBinderUtil::WStringList * pFileNameList, - CLRPrivBinderUtil::WStringList ** ppFileNameList); - - HRESULT BindWinRtType_Internal( - LPCSTR szTypeNamespace, - LPCSTR szTypeClassName, - DomainAssembly * pParentAssembly, - CLRPrivAssemblyReflectionOnlyWinRT ** ppAssembly); - -private: - //============================================================================================= - - // Namespace -> FileName list map ... items are never removed - NamespaceToFileNameListMap m_NamespaceToFileNameListMap; - // FileName -> CLRPrivAssemblyReflectionOnlyWinRT * map ... items can be removed when CLRPrivAssemblyReflectionOnlyWinRT dies - FileNameToAssemblyMap m_FileNameToAssemblyMap; - - // Lock for the above maps - Crst m_MapsLock; - - //============================================================================================= - CLRPrivTypeCacheReflectionOnlyWinRT * m_pTypeCache; - -}; // class CLRPrivBinderReflectionOnlyWinRT - - -//===================================================================================================================== -//===================================================================================================================== -//===================================================================================================================== -class CLRPrivAssemblyReflectionOnlyWinRT : - public IUnknownCommon -{ - friend class CLRPrivBinderReflectionOnlyWinRT; - -public: - //============================================================================================= - // Class methods - - CLRPrivAssemblyReflectionOnlyWinRT( - LPCWSTR wzFullTypeName, - CLRPrivBinderReflectionOnlyWinRT * pBinder, - CLRPrivBinderUtil::CLRPrivResourcePathImpl * pResourceIL); - - //============================================================================================= - // IUnknown interface methods - - // Overridden to implement self-removal from assembly map code:CLRPrivBinderReflectionOnlyWinRT::m_FileNameToAssemblyMap. - STDMETHOD_(ULONG, Release)(); - - //============================================================================================= - // ICLRPrivBinder interface methods - - STDMETHOD(BindAssemblyByName)( - IAssemblyName * pAssemblyName, - ICLRPrivAssembly ** ppAssembly) - { - STATIC_CONTRACT_WRAPPER; - return m_pBinder->BindAssemblyByName(pAssemblyName, ppAssembly); - } - - // Implements interface method code:ICLRPrivBinder::VerifyBind. - STDMETHOD(VerifyBind)( - IAssemblyName * pAssemblyName, - ICLRPrivAssembly * pAssembly, - ICLRPrivAssemblyInfo * pAssemblyInfo) - { - STATIC_CONTRACT_WRAPPER; - return m_pBinder->VerifyBind(pAssemblyName, pAssembly, pAssemblyInfo); - } - - //--------------------------------------------------------------------------------------------- - // Implements interface method code:ICLRPrivBinder::GetBinderFlags - STDMETHOD(GetBinderFlags)( - DWORD *pBinderFlags) - { - STATIC_CONTRACT_WRAPPER; - return m_pBinder->GetBinderFlags(pBinderFlags); - } - - // Implements interface method code:ICLRPrivBinder::GetBinderID. - STDMETHOD(GetBinderID)( - UINT_PTR * pBinderId) - { - STATIC_CONTRACT_WRAPPER; - return m_pBinder->GetBinderID(pBinderId); - } - - //============================================================================================= - // ICLRPrivAssembly interface methods - - // Implements interface method code:ICLRPrivAssembly::IsShareable. - STDMETHOD(IsShareable)( - BOOL * pbIsShareable); - - // Implements interface method code:ICLRPrivAssembly::GetAvailableImageTypes. - STDMETHOD(GetAvailableImageTypes)( - LPDWORD pdwImageTypes); - - // Implements interface method code:ICLRPrivAssembly::GetImageResource. - STDMETHOD(GetImageResource)( - DWORD dwImageType, - DWORD * pdwImageType, - ICLRPrivResource ** ppIResource); - - // Implements code:ICLRPrivBinder::FindAssemblyBySpec - STDMETHOD(FindAssemblyBySpec)( - LPVOID pvAppDomain, - LPVOID pvAssemblySpec, - HRESULT * pResult, - ICLRPrivAssembly ** ppAssembly) - { STATIC_CONTRACT_WRAPPER; return m_pBinder->FindAssemblyBySpec(pvAppDomain, pvAssemblySpec, pResult, ppAssembly); } - -private: - //============================================================================================= - - ReleaseHolder m_pBinder; - ReleaseHolder m_pResourceIL; - -}; // class CLRPrivAssemblyReflectionOnlyWinRT - -#endif //FEATURE_REFLECTION_ONLY_LOAD diff --git a/src/vm/clrprivtypecachereflectiononlywinrt.cpp b/src/vm/clrprivtypecachereflectiononlywinrt.cpp deleted file mode 100644 index 40f90dfe3f..0000000000 --- a/src/vm/clrprivtypecachereflectiononlywinrt.cpp +++ /dev/null @@ -1,260 +0,0 @@ -// 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. -// - -// -// Contains VM implementation of WinRT type cache for code:CLRPrivBinderReflectionOnlyWinRT binder. -// -//===================================================================================================================== - -#include "common.h" // precompiled header - -#ifndef DACCESS_COMPILE -#ifdef FEATURE_REFLECTION_ONLY_LOAD - -#include "clrprivtypecachereflectiononlywinrt.h" -#include - -//===================================================================================================================== -// S_OK - pAssembly contains type wszTypeName -// S_FALSE - pAssembly does not contain type wszTypeName -// -HRESULT -CLRPrivTypeCacheReflectionOnlyWinRT::ContainsType( - ICLRPrivAssembly * pPrivAssembly, - LPCWSTR wszTypeName) -{ - STANDARD_VM_CONTRACT; - - HRESULT hr = S_OK; - - AppDomain * pAppDomain = AppDomain::GetCurrentDomain(); - - ReleaseHolder pPEAssembly; - IfFailGo(pAppDomain->BindHostedPrivAssembly(nullptr, pPrivAssembly, nullptr, &pPEAssembly, TRUE)); - _ASSERTE(pPEAssembly != nullptr); - - { - // Find DomainAssembly * (can be cached if this is too slow to call always) - DomainAssembly * pDomainAssembly = pAppDomain->LoadDomainAssembly( - nullptr, // pIdentity - pPEAssembly, - FILE_LOADED, - nullptr); // pLoadSecurity - - // Convert the type name into namespace and type names in UTF8 - StackSString ssTypeNameWCHAR(wszTypeName); - - StackSString ssTypeName; - ssTypeNameWCHAR.ConvertToUTF8(ssTypeName); - LPUTF8 szTypeName = (LPUTF8)ssTypeName.GetUTF8NoConvert(); - - LPCUTF8 szNamespace; - LPCUTF8 szClassName; - ns::SplitInline(szTypeName, szNamespace, szClassName); - - NameHandle typeName(szNamespace, szClassName); - - // Find the type in the assembly (use existing hash of all type names defined in the assembly) - TypeHandle thType; - mdToken tkType; - Module * pTypeModule; - mdToken tkExportedType; - if (pDomainAssembly->GetAssembly()->GetLoader()->FindClassModuleThrowing( - &typeName, - &thType, - &tkType, - &pTypeModule, - &tkExportedType, - nullptr, // ppClassHashEntry - nullptr, // pLookInThisModuleOnly - Loader::DontLoad)) - { // The type is present in the assembly - hr = S_OK; - } - else - { // The type is not present in the assembly - hr = S_FALSE; - } - } - -ErrExit: - return hr; -} // CLRPrivTypeCacheReflectionOnlyWinRT::ContainsType - -//===================================================================================================================== -// Raises user event NamespaceResolveEvent to get a list of files for this namespace. -// -void -CLRPrivTypeCacheReflectionOnlyWinRT::RaiseNamespaceResolveEvent( - LPCWSTR wszNamespace, - DomainAssembly * pParentAssembly, - CLRPrivBinderUtil::WStringListHolder * pFileNameList) -{ - STANDARD_VM_CONTRACT; - - _ASSERTE(pFileNameList != nullptr); - - AppDomain * pAppDomain = AppDomain::GetCurrentDomain(); - - GCX_COOP(); - - struct _gc { - OBJECTREF AppDomainRef; - OBJECTREF AssemblyRef; - STRINGREF str; - } gc; - ZeroMemory(&gc, sizeof(gc)); - - GCPROTECT_BEGIN(gc); - if ((gc.AppDomainRef = pAppDomain->GetRawExposedObject()) != NULL) - { - if (pParentAssembly != nullptr) - { - gc.AssemblyRef = pParentAssembly->GetExposedAssemblyObject(); - } - - MethodDescCallSite onNamespaceResolve(METHOD__APP_DOMAIN__ON_REFLECTION_ONLY_NAMESPACE_RESOLVE, &gc.AppDomainRef); - gc.str = StringObject::NewString(wszNamespace); - ARG_SLOT args[3] = - { - ObjToArgSlot(gc.AppDomainRef), - ObjToArgSlot(gc.AssemblyRef), - ObjToArgSlot(gc.str) - }; - PTRARRAYREF ResultingAssemblyArrayRef = (PTRARRAYREF) onNamespaceResolve.Call_RetOBJECTREF(args); - if (ResultingAssemblyArrayRef != NULL) - { - for (DWORD i = 0; i < ResultingAssemblyArrayRef->GetNumComponents(); i++) - { - ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) ResultingAssemblyArrayRef->GetAt(i); - Assembly * pAssembly = ResultingAssemblyRef->GetAssembly(); - - if (pAssembly->IsCollectible()) - { - COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve")); - } - - PEAssembly * pPEAssembly = pAssembly->GetManifestFile(); - - ICLRPrivAssembly * pPrivAssembly = pPEAssembly->GetHostAssembly(); - if ((pPrivAssembly == NULL) || !IsAfContentType_WindowsRuntime(pPEAssembly->GetFlags())) - { - COMPlusThrow(kNotSupportedException, IDS_EE_REFLECTIONONLY_WINRT_INVALIDASSEMBLY); - } - - pFileNameList->InsertTail(pPEAssembly->GetILimage()->GetPath()); - } - } - } - GCPROTECT_END(); -} // CLRPrivTypeCacheReflectionOnlyWinRT::RaiseNamespaceResolveEvent - -//===================================================================================================================== -// Implementation of QCall System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMetadata.nResolveNamespace -// It's basically a PInvoke wrapper into Win8 API RoResolveNamespace -// -void -QCALLTYPE -CLRPrivTypeCacheReflectionOnlyWinRT::ResolveNamespace( - LPCWSTR wszNamespace, - LPCWSTR wszWindowsSdkPath, - LPCWSTR * rgPackageGraphPaths, - INT32 cPackageGraphPaths, - QCall::ObjectHandleOnStack retFileNames) -{ - QCALL_CONTRACT; - - _ASSERTE(wszNamespace != nullptr); - - BEGIN_QCALL; - - CoTaskMemHSTRINGArrayHolder hFileNames; - - if (!WinRTSupported()) - { - IfFailThrow(COR_E_PLATFORMNOTSUPPORTED); - } - - { - CLRPrivBinderUtil::HSTRINGArrayHolder rgPackageGraph; - rgPackageGraph.Allocate(cPackageGraphPaths); - - LPCWSTR wszNamespaceRoResolve = wszNamespace; - - for (INT32 i = 0; i < cPackageGraphPaths; i++) - { - _ASSERTE(rgPackageGraph.GetRawArray()[i] == nullptr); - WinRtString hsPackageGraphPath; - IfFailThrow(hsPackageGraphPath.Initialize(rgPackageGraphPaths[i])); - hsPackageGraphPath.Detach(&rgPackageGraph.GetRawArray()[i]); - } - - UINT32 cchNamespace, cchWindowsSdkPath; - IfFailThrow(StringCchLength(wszNamespace, &cchNamespace)); - IfFailThrow(StringCchLength(wszWindowsSdkPath, &cchWindowsSdkPath)); - - DWORD cFileNames = 0; - HSTRING * rgFileNames = nullptr; - HRESULT hr = RoResolveNamespace( - WinRtStringRef(wszNamespace, cchNamespace), - WinRtStringRef(wszWindowsSdkPath, cchWindowsSdkPath), - rgPackageGraph.GetCount(), - rgPackageGraph.GetRawArray(), - &cFileNames, - &rgFileNames, - nullptr, // pcDirectNamespaceChildren - nullptr); // rgDirectNamespaceChildren - hFileNames.Init(rgFileNames, cFileNames); - - if (hr == HRESULT_FROM_WIN32(APPMODEL_ERROR_NO_PACKAGE)) - { // User tried to resolve 3rd party namespace without passing package graph - throw InvalidOperationException with custom message - _ASSERTE(cPackageGraphPaths == 0); - COMPlusThrow(kInvalidOperationException, IDS_EE_REFLECTIONONLY_WINRT_LOADFAILURE_THIRDPARTY); - } - IfFailThrow(hr); - if (hr != S_OK) - { - IfFailThrow(E_UNEXPECTED); - } - } - - { - GCX_COOP(); - - PTRARRAYREF orFileNames = NULL; - GCPROTECT_BEGIN(orFileNames); - - orFileNames = (PTRARRAYREF) AllocateObjectArray(hFileNames.GetCount(), g_pStringClass); - - for (DWORD i = 0; i < hFileNames.GetCount(); i++) - { - UINT32 cchFileName = 0; - - HSTRING hsFileName = hFileNames.GetAt(i); - LPCWSTR wszFileName; - - if (hsFileName != nullptr) - { - wszFileName = WindowsGetStringRawBuffer( - hsFileName, - &cchFileName); - - STRINGREF str = StringObject::NewString(wszFileName); - orFileNames->SetAt(i, str); - } - } - - retFileNames.Set(orFileNames); - - GCPROTECT_END(); - } - - END_QCALL; -} // CLRPrivTypeCacheReflectionOnlyWinRT::ResolveNamespace - -//===================================================================================================================== - -#endif //FEATURE_REFLECTION_ONLY_LOAD -#endif //!DACCESS_COMPILE diff --git a/src/vm/clrprivtypecachereflectiononlywinrt.h b/src/vm/clrprivtypecachereflectiononlywinrt.h deleted file mode 100644 index a605c3dc2e..0000000000 --- a/src/vm/clrprivtypecachereflectiononlywinrt.h +++ /dev/null @@ -1,58 +0,0 @@ -// 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. -// - -// -// Contains VM implementation of code:ICLRPrivTypeCacheReflectionOnlyWinRT for code:CLRPrivBinderReflectionOnlyWinRT binder. -// -//===================================================================================================================== - -#ifdef FEATURE_REFLECTION_ONLY_LOAD - -#pragma once - -#include "internalunknownimpl.h" -#include "clrprivbinding.h" - -//===================================================================================================================== -// Forward declarations -class DomainAssembly; - -//===================================================================================================================== -class CLRPrivTypeCacheReflectionOnlyWinRT : - public IUnknownCommon -{ -public: - //============================================================================================= - // Class methods - - // S_OK - pAssembly contains type wszTypeName - // S_FALSE - pAssembly does not contain type wszTypeName - STDMETHOD(ContainsType)( - ICLRPrivAssembly * pAssembly, - LPCWSTR wszTypeName); - -#ifndef DACCESS_COMPILE - - // Raises user event NamespaceResolveEvent to get a list of files for this namespace. - void RaiseNamespaceResolveEvent( - LPCWSTR wszNamespace, - DomainAssembly * pParentAssembly, - CLRPrivBinderUtil::WStringListHolder * pFileNameList); - -#endif //!DACCESS_COMPILE - - // Implementation of QCall System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMetadata.nResolveNamespace - // It's basically a PInvoke wrapper into Win8 API RoResolveNamespace - static - void QCALLTYPE ResolveNamespace( - LPCWSTR wszNamespace, - LPCWSTR wszWindowsSdkPath, - LPCWSTR * rgPackageGraphPaths, - INT32 cPackageGraphPaths, - QCall::ObjectHandleOnStack retFileNames); - -}; // class CLRPrivTypeCaheReflectionOnlyWinRT - -#endif //FEATURE_REFLECTION_ONLY_LOAD diff --git a/src/vm/pefile.h b/src/vm/pefile.h index 2f244732e9..697ce03749 100644 --- a/src/vm/pefile.h +++ b/src/vm/pefile.h @@ -642,9 +642,7 @@ protected: protected: - friend class CLRPrivBinderFusion; #ifndef DACCESS_COMPILE - // CLRPrivBinderFusion calls this for Fusion-bound assemblies in AppX processes. void SetHostAssembly(ICLRPrivAssembly * pHostAssembly) { LIMITED_METHOD_CONTRACT; m_pHostAssembly = clr::SafeAddRef(pHostAssembly); } #endif //DACCESS_COMPILE -- cgit v1.2.3 From 54a687af2ab167060392ea95dd2f8fac643c6880 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Sun, 12 Feb 2017 20:25:22 -0800 Subject: Remove commethodrental --- src/vm/commethodrental.cpp | 120 --------------------------------------------- src/vm/commethodrental.h | 29 ----------- src/vm/mscorlib.cpp | 3 +- 3 files changed, 2 insertions(+), 150 deletions(-) delete mode 100644 src/vm/commethodrental.cpp delete mode 100644 src/vm/commethodrental.h diff --git a/src/vm/commethodrental.cpp b/src/vm/commethodrental.cpp deleted file mode 100644 index 0a5c011270..0000000000 --- a/src/vm/commethodrental.cpp +++ /dev/null @@ -1,120 +0,0 @@ -// 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. -//////////////////////////////////////////////////////////////////////////////// - - - -#include "common.h" -#include "commethodrental.h" -#include "corerror.h" - -#ifdef FEATURE_METHOD_RENTAL -// SwapMethodBody -// This method will take the rgMethod as the new function body for a given method. -// - -void QCALLTYPE COMMethodRental::SwapMethodBody(EnregisteredTypeHandle cls, INT32 tkMethod, LPVOID rgMethod, INT32 iSize, INT32 flags, QCall::StackCrawlMarkHandle stackMark) -{ - QCALL_CONTRACT; - - BEGIN_QCALL; - - BYTE *pNewCode = NULL; - MethodDesc *pMethodDesc; - ReflectionModule *module; - ICeeGen* pGen; - ULONG methodRVA; - HRESULT hr; - - if ( cls == NULL) - { - COMPlusThrowArgumentNull(W("cls")); - } - - MethodTable *pMethodTable = TypeHandle::FromPtr(cls).GetMethodTable(); - PREFIX_ASSUME(pMethodTable != NULL); - module = (ReflectionModule *) pMethodTable->GetModule(); - pGen = module->GetCeeGen(); - - Assembly* caller = SystemDomain::GetCallersAssembly( stackMark ); - - _ASSERTE( caller != NULL && "Unable to get calling assembly" ); - _ASSERTE( module->GetCreatingAssembly() != NULL && "ReflectionModule must have a creating assembly to be used with method rental" ); - - if (module->GetCreatingAssembly() != caller) - { - COMPlusThrow(kSecurityException); - } - - // Find the methoddesc given the method token - pMethodDesc = MemberLoader::FindMethod(pMethodTable, tkMethod); - if (pMethodDesc == NULL) - { - COMPlusThrowArgumentException(W("methodtoken"), NULL); - } - if (pMethodDesc->GetMethodTable() != pMethodTable || pMethodDesc->GetNumGenericClassArgs() != 0 || pMethodDesc->GetNumGenericMethodArgs() != 0) - { - COMPlusThrowArgumentException(W("methodtoken"), W("Argument_TypeDoesNotContainMethod")); - } - hr = pGen->AllocateMethodBuffer(iSize, &pNewCode, &methodRVA); - if (FAILED(hr)) - COMPlusThrowHR(hr); - - if (pNewCode == NULL) - { - COMPlusThrowOM(); - } - - // - // if method desc is pointing to the post-jitted native code block, - // we want to recycle this code block - - // @todo: SEH handling. Will we need to support a method that can throw exception - // If not, add an assertion to make sure that there is no SEH contains in the method header. - - // @todo: figure out a way not to copy the code block. - - // @todo: add link time security check. This function can be executed only if fully trusted. - - // copy the new function body to the buffer - memcpy(pNewCode, (void *) rgMethod, iSize); - - // add the starting address of the il blob to the il blob hash table - // we need to find this information from out of process for debugger inspection - // APIs so we have to store this information where we can get it later - module->SetDynamicIL(mdToken(tkMethod), TADDR(pNewCode), FALSE); - - // Reset the methoddesc back to unjited state - pMethodDesc->Reset(); - - if (flags) - { - // JITImmediate -#if _DEBUG - COR_ILMETHOD* ilHeader = pMethodDesc->GetILHeader(TRUE); - _ASSERTE(((BYTE *)ilHeader) == pNewCode); -#endif - COR_ILMETHOD_DECODER header((COR_ILMETHOD *)pNewCode, pMethodDesc->GetMDImport(), NULL); - - // minimum validation on the correctness of method header - if (header.GetCode() == NULL) - COMPlusThrowHR(VLDTR_E_MD_BADHEADER); - -#ifdef FEATURE_INTERPRETER - pMethodDesc->MakeJitWorker(&header, CORJIT_FLAGS(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE)); -#else // !FEATURE_INTERPRETER - pMethodDesc->MakeJitWorker(&header, CORJIT_FLAGS()); -#endif // !FEATURE_INTERPRETER - } - - // add feature:: - // If SQL is generating class with inheritance hierarchy, we may need to - // check the whole vtable to find duplicate entries. - - END_QCALL; - -} // COMMethodRental::SwapMethodBody - - -#endif // FEATURE_METHOD_RENTAL diff --git a/src/vm/commethodrental.h b/src/vm/commethodrental.h deleted file mode 100644 index 0523af274e..0000000000 --- a/src/vm/commethodrental.h +++ /dev/null @@ -1,29 +0,0 @@ -// 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. -//////////////////////////////////////////////////////////////////////////////// - - - -#ifndef _COMMETHODRENTAL_H_ -#define _COMMETHODRENTAL_H_ - -#include "excep.h" -#include "fcall.h" - -#ifdef FEATURE_METHOD_RENTAL -// COMMethodRental -// This class implements SwapMethodBody for our MethodRenting story -class COMMethodRental -{ -public: - - // COMMethodRental.SwapMethodBody -- this function will swap an existing method body with - // a new method body - // - static - void QCALLTYPE SwapMethodBody(EnregisteredTypeHandle cls, INT32 tkMethod, LPVOID rgMethod, INT32 iSize, INT32 flags, QCall::StackCrawlMarkHandle stackMark); -}; -#endif // FEATURE_METHOD_RENTAL - -#endif //_COMMETHODRENTAL_H_ diff --git a/src/vm/mscorlib.cpp b/src/vm/mscorlib.cpp index 5d8531ec56..608cacdf1a 100644 --- a/src/vm/mscorlib.cpp +++ b/src/vm/mscorlib.cpp @@ -31,7 +31,8 @@ #include "comdelegate.h" #include "customattribute.h" #include "comdynamic.h" -#include "commethodrental.h" +#include "excep.h" +#include "fcall.h" #include "nlsinfo.h" #include "calendardata.h" #include "commodule.h" -- cgit v1.2.3 From 6f05c7c8d283345b811cfe7abe1c2ad416301a12 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Sun, 12 Feb 2017 20:42:42 -0800 Subject: Remove constrainedexecutionregion.cpp --- src/inc/clrconfigvalues.h | 1 - .../Reliability/ReliabilityContractAttribute.cs | 7 - src/vm/constrainedexecutionregion.cpp | 2264 -------------------- 3 files changed, 2272 deletions(-) delete mode 100644 src/vm/constrainedexecutionregion.cpp diff --git a/src/inc/clrconfigvalues.h b/src/inc/clrconfigvalues.h index 347cdd0c34..6a30af16db 100644 --- a/src/inc/clrconfigvalues.h +++ b/src/inc/clrconfigvalues.h @@ -1058,7 +1058,6 @@ CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_AlwaysUseMetadataInterfaceMapLayout, W( CONFIG_DWORD_INFO(INTERNAL_AssertOnUnneededThis, W("AssertOnUnneededThis"), 0, "While the ConfigDWORD is unnecessary, the contained ASSERT should be kept. This may result in some work tracking down violating MethodDescCallSites.") CONFIG_DWORD_INFO_EX(INTERNAL_AssertStacktrace, W("AssertStacktrace"), 1, "", CLRConfig::REGUTIL_default) RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(UNSUPPORTED_BuildFlavor, W("BuildFlavor"), "Choice of build flavor (wks or svr) of CLR") -CONFIG_DWORD_INFO(INTERNAL_CerLogging, W("CerLogging"), 0, "In vm\\ConstrainedExecutionRegion.cpp. Debug-only logging when we prepare methods, find reliability contract problems, restore stuff from ngen images, etc.") CONFIG_DWORD_INFO_EX(INTERNAL_clearNativeImageStress, W("clearNativeImageStress"), 0, "", CLRConfig::REGUTIL_default) RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(INTERNAL_CLRLoadLogDir, W("CLRLoadLogDir"), "Enable logging of CLR selection") RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_CONFIG, W("CONFIG"), "Used to specify an XML config file for EEConfig", CLRConfig::REGUTIL_default) diff --git a/src/mscorlib/src/System/Runtime/Reliability/ReliabilityContractAttribute.cs b/src/mscorlib/src/System/Runtime/Reliability/ReliabilityContractAttribute.cs index 4a14e5733c..a889f1559c 100644 --- a/src/mscorlib/src/System/Runtime/Reliability/ReliabilityContractAttribute.cs +++ b/src/mscorlib/src/System/Runtime/Reliability/ReliabilityContractAttribute.cs @@ -20,13 +20,6 @@ namespace System.Runtime.ConstrainedExecution { using System.Runtime.InteropServices; using System; - // ************************************************************************************************************************** - // - // Note that if you change either of the enums below or the constructors, fields or properties of the custom attribute itself - // you must also change the logic and definitions in vm\ConstrainedExecutionRegion.cpp to match. - // - // ************************************************************************************************************************** - [Serializable] public enum Consistency : int { diff --git a/src/vm/constrainedexecutionregion.cpp b/src/vm/constrainedexecutionregion.cpp deleted file mode 100644 index 0745bd5e1b..0000000000 --- a/src/vm/constrainedexecutionregion.cpp +++ /dev/null @@ -1,2264 +0,0 @@ -// 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. -// -// Methods to support the implementation of Constrained Execution Regions (CERs). This includes logic to walk the IL of methods to -// determine the statically determinable call graph and prepare each submethod (jit, prepopulate generic dictionaries etc., -// everything needed to ensure that the runtime won't generate implicit failure points during the execution of said call graph). -// - -// - - -#include "common.h" -#include -#include -#include -#include -#include - -#ifdef FEATURE_PREJIT -#include -#endif - - -// Internal debugging support. Would be nice to use the common logging code but we've run out of unique facility codes and the debug -// info we spew out is of interest to a limited audience anyhow. -#ifdef _DEBUG - -#define CER_NOISY_PREPARE 0x00000001 -#define CER_NOISY_RESTORE 0x00000002 -#define CER_NOISY_CONTRACTS 0x00000004 -#define CER_NOISY_WARNINGS 0x00000008 -#define CER_NOISY_NGEN_STATS 0x00000010 - -DWORD g_dwCerLogActions = 0xffffffff; -DWORD GetCerLoggingOptions() -{ - WRAPPER_NO_CONTRACT; - if (g_dwCerLogActions != 0xffffffff) - return g_dwCerLogActions; - return g_dwCerLogActions = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_CerLogging); -} - -#define CER_LOG(_reason, _msg) do { if (GetCerLoggingOptions() & CER_NOISY_##_reason) printf _msg; } while (false) -#else -#define CER_LOG(_reason, _msg) -#endif - - -// Enumeration used to determine the number of inline data bytes included inside a given IL instruction (except for the case of a -// SWITCH instruction, where a dynamic calculation is required). -enum -{ - ArgBytes_InlineNone = 0, // no inline args - ArgBytes_InlineVar = 2, // local variable (U2 (U1 if Short on)) - ArgBytes_InlineI = 4, // an signed integer (I4 (I1 if Short on)) - ArgBytes_InlineR = 8, // a real number (R8 (R4 if Short on)) - ArgBytes_InlineBrTarget = 4, // branch target (I4 (I1 if Short on)) - ArgBytes_InlineI8 = 8, - ArgBytes_InlineMethod = 4, // method token (U4) - ArgBytes_InlineField = 4, // field token (U4) - ArgBytes_InlineType = 4, // type token (U4) - ArgBytes_InlineString = 4, // string TOKEN (U4) - ArgBytes_InlineSig = 4, // signature tok (U4) - ArgBytes_InlineRVA = 4, // ldptr token (U4) - ArgBytes_InlineTok = 4, // a meta-data token of unknown type (U4) - ArgBytes_InlineSwitch = 4, // count (U4), pcrel1 (U4) .... pcrelN (U4) - ArgBytes_ShortInlineVar = 1, - ArgBytes_ShortInlineI = 1, - ArgBytes_ShortInlineR = 4, - ArgBytes_ShortInlineBrTarget = 1 -}; - -// Build an array of argument byte counts as described above by extracting the 'args' field of each entry in opcode.def. -#define OPDEF(c, s, pop, push, args, type, l, s1, s2, ctrl) ArgBytes_##args, -const BYTE g_rOpArgs[] = { -#include -}; -#undef OPDEF - - -// Global cache of methods and their reliability contract state. -PtrHashCache *g_pMethodContractCache = NULL; - - -// Private method forward references. -bool IsPcrReference(Module *pModule, mdToken tkMethod); -MethodContext *TokenToMethodDesc(Module *pModule, mdToken tokMethod, SigTypeContext *pTypeContext); -TypeHandle GetTypeFromMemberDefOrRefOrSpecThrowing(Module *pModule, - mdToken tokMethod, - SigTypeContext *pTypeContext); - -bool MethodCallGraphPreparer::ShouldGatherExplicitCERCallInfo() -{ - LIMITED_METHOD_CONTRACT; - - // If we're partially processing a method body (at the top of the call graph), we need to fetch exception handling - // information to determine possible ranges of interesting IL (potentially each finally and catch clause). - // - // And if we are probing for stack overflow, we need to know if the explicit CER region contains any calls out, in - // which case we want to probe in the call to PrepareConstrainedExecutionRegions. This will ensure that we don't - // take an SO in boundary code and not be able to call the CER. When stack probing is disabled, we rip the process - // if we take an SO anywhere but managed, or if we take an SO with a CER on the stack. For NGEN images, we need - // to always probe because stack probing may be enabled in the runtime, but if we haven't probed in the NGEN image - // then we could take an SO in boundary code and not be able to crawl the stack to know that we've skipped a CER and - // need to tear the process. - // - // Additionally, if the MDA for illegal PrepareConstrainedRegions call positioning is enabled we gather this information for - // all methods in the graph. - return !m_fEntireMethod -#ifdef MDA_SUPPORTED - || MDA_GET_ASSISTANT(IllegalPrepareConstrainedRegion) -#endif -#ifdef FEATURE_NATIVE_IMAGE_GENERATION - || m_fNgen -#endif - || g_pConfig->ProbeForStackOverflow(); -} - -MethodCallGraphPreparer::MethodCallGraphPreparer(MethodDesc *pRootMD, SigTypeContext *pRootTypeContext, bool fEntireMethod, bool fExactTypeContext, bool fIgnoreVirtualCERCallMDA) -{ - CONTRACTL { - STANDARD_VM_CHECK; - PRECONDITION(CheckPointer(pRootMD)); - PRECONDITION(CheckPointer(pRootTypeContext)); - } CONTRACTL_END; - - // Canonicalize value type unboxing stubs into their underlying method desc. - if (pRootMD->IsUnboxingStub()) - pRootMD = pRootMD->GetWrappedMethodDesc(); - - m_pRootMD = pRootMD; - m_pRootTypeContext = pRootTypeContext; - m_fEntireMethod = fEntireMethod; - m_fExactTypeContext = fExactTypeContext; - m_fIgnoreVirtualCERCallMDA = fIgnoreVirtualCERCallMDA; - - m_pEHClauses = NULL; - m_cEHClauses = 0; - m_pCerPrepInfo = NULL; - m_pMethodDecoder = NULL; - -#ifdef FEATURE_NATIVE_IMAGE_GENERATION - m_fNgen = false; -#endif - - m_pThread = GetThread(); - m_fPartialPreparation = false; - m_fMethodHasCallsWithinExplicitCer = false; -} - -// Walk the call graph of the method given by pRootMD (and type context in pRootTypeContext which provides instantiation information -// for generic methods/classes). -// -// If fEntireMethod is true then the entire body of pRootMD is scanned for callsites, otherwise we assume that one or more CER -// exception handlers exist in the method and only the finally and catch blocks of such handlers are scanned for graph roots. -// -// Each method we come across in the call graph (excluding late bound invocation destinations precipitated by virtual or interface -// calls) is jitted and has any generic dictionary information we can determine at jit time prepopulated. This includes implicit -// cctor invocations. If this method is called at ngen time we will attach extra fixup information to the affected method to ensure -// that fixing up the root method of the graph will cause all methods in the graph to be fixed up at that point also. -// -// Some generic dictionary entries may not be prepopulated if unbound type variables exist at the root of the call tree. Such cases -// will be ignored (as for the virtual/interface dispatch case we assume the caller will use an out-of-band mechanism to pre-prepare -// these entries explicitly). -bool MethodCallGraphPreparer::Run() -{ - STANDARD_VM_CONTRACT; - - // Avoid recursion while jitting methods for another preparation. - if (!m_pThread->GetCerPreparationState()->CanPreparationProceed(m_pRootMD, m_pRootTypeContext)) - return TRUE; // Assume the worst - -#ifdef FEATURE_NATIVE_IMAGE_GENERATION - // Determine if we're being called in order to provide an ngen image. This impacts whether we actually prepare methods and the - // type of tracking data we produce. Ideally we'd call GetAppDomain()->IsCompilationDomain() here, but we have to deal with the - // problem of ngen'ing mscorlib. Mscorlib code is always shared and some of it is run before the compilation domain is fully - // created (so we'd end up with some methods being prepared without saving any ngen metadata to that effect). So instead we - // check to see whether this is an ngen process. This will catch those first few mscorlib methods. - m_fNgen = IsCompilationProcess() != FALSE; - - // We keep a hash table of CERs we've processed on the module object of the root method. See if any work has been done on this - // CER before. We store different data for ngen and non-ngen cases. - if (m_fNgen) { - - // Pretty simple in ngen case -- if we've stored a context record for this method at all then we've already processed it. - if (m_pRootMD->GetModule()->IsNgenCerRootMethod(m_pRootMD)) { - m_pCerPrepInfo = m_pRootMD->GetModule()->GetCerPrepInfo(m_pRootMD); - - // We always store CerPrepInfo if the method has calls, so if we haven't stored - // anything then we know it doesn't have any calls - return (m_pCerPrepInfo && m_pCerPrepInfo->m_fMethodHasCallsWithinExplicitCer); - } - } else -#endif - { - // The non-ngen case (normal jit, call to PrepareMethod etc). - m_pCerPrepInfo = m_pRootMD->GetModule()->GetCerPrepInfo(m_pRootMD); - if (m_pCerPrepInfo) { - - // Check for the "everything's done" case. - if (m_pCerPrepInfo->m_fFullyPrepared) - return m_pCerPrepInfo->m_fMethodHasCallsWithinExplicitCer; - - // Check for the "we can't do anything" case (see below for descriptions of that). - if (m_pCerPrepInfo->m_fRequiresInstantiation && !m_fExactTypeContext) - return m_pCerPrepInfo->m_fMethodHasCallsWithinExplicitCer; - - // Check for the "need to prepare per-instantiation, but we've already done this one" case. - if (m_pCerPrepInfo->m_fRequiresInstantiation) { - HashDatum sDatum; - if (m_pCerPrepInfo->m_sIsInitAtInstHash.GetValue(m_pRootTypeContext, &sDatum)) - return m_pCerPrepInfo->m_fMethodHasCallsWithinExplicitCer; - } - } - } - - // We can't deal with generic methods or methods on generic types that may have some representative type parameters in their - // instantiation (i.e. some reference types indicated by Object rather than the exact type). The jit will tend to pass us these - // since it shares code between instantiations over reference types. We can't prepare methods like these completely -- even - // though we can jit all the method bodies the code might require generic dictionary information at the class or method level - // that is populated at runtime and can introduce failure points. So we reject such methods immediately (they will need to be - // prepared at non-jit time by an explicit call to PrepareMethod with a fully instantiated method). - // - // In the case where the type context is marked as suspect (m_fExactTypeContext == false) there are a number of possibilites for - // bad methods the jit will pass us: - // 1) We're passed a MethodDesc that shared between instantiations (bogus because exact method descs are never shared). - // 2) We're passed a MethodDesc that's an instantiating stub (bogus because non-shared methods don't need this). - // 3) We're passed a MethodDesc that has generic variables in its instantiations (I've seen this during ngen). - // - // Technically we could do a little better than this -- we could determine whether any of the representative type parameters are - // actually used within the CER call graph itself. But this would require us to understand the IL at a much deeper level (i.e. - // parse every instruction that could take a type or member spec and pull apart those specs to see if a type var is used). Plus - // we couldn't make this determination until we've prepared the entire region and the result is rather brittle from the code - // author's point of view (i.e. we might prepare a CER automatically one day but stop doing after some relatively subtle changes - // in the source code). - m_fPartialPreparation = m_pRootMD->IsSharedByGenericInstantiations() || m_pRootMD->IsInstantiatingStub() || m_pRootMD->ContainsGenericVariables(); - if (!m_fExactTypeContext && m_fPartialPreparation) { -#ifdef MDA_SUPPORTED - MDA_TRIGGER_ASSISTANT(OpenGenericCERCall, ReportViolation(m_pRootMD)); -#endif - CER_LOG(WARNINGS, ("CER: %s has open type parameters and can't be pre-prepared\n", m_pRootMD->m_pszDebugMethodName)); - - -#ifdef FEATURE_NATIVE_IMAGE_GENERATION - if (!m_fNgen) -#endif - { - // Set up a prep info structure for this method if it's not there already (the create method takes care of races). - if (m_pCerPrepInfo == NULL) - m_pCerPrepInfo = m_pRootMD->GetModule()->CreateCerPrepInfo(m_pRootMD); - - // We may be racing to update the structure at this point but that's OK since the flag we're setting is never cleared once - // it's set and is always guaranteed to be set before we rely on its value (setting it here is just a performance thing, - // letting us early-out on multiple attempts to prepare this CER from the jit). - m_pCerPrepInfo->m_fRequiresInstantiation = true; - } - - if (! g_pConfig->ProbeForStackOverflow()) - { - return FALSE; - } - m_pCerPrepInfo = m_pRootMD->GetModule()->GetCerPrepInfo(m_pRootMD); - - // We always store CerPrepInfo if the method has calls, so if we haven't stored - // anything then we know it doesn't have any calls - return (m_pCerPrepInfo && m_pCerPrepInfo->m_fMethodHasCallsWithinExplicitCer); - - } - -#ifdef FEATURE_NATIVE_IMAGE_GENERATION - // If we've been called for a shared generic root method and the exact instantiation (this can happen because ngen lets code - // execute under some circumstances) we don't currently support saving this information in the ngen image (we don't have a - // format for the instantiation info). We just ignore the preparation in this case (it will be prepared at runtime). - if (m_fNgen && m_fPartialPreparation) - return TRUE; -#endif - - // Prevent inlining of the root method (otherwise it's hard to tell where ThreadAbort exceptions should be delayed). Note that - // MethodDesc::SetNotInline is thread safe. - m_pRootMD->SetNotInline(true); - - // Remember the checkpoint for all of our allocations. Keep it in a holder so they'll be unwound if we throw an exception past - // here. - CheckPointHolder sCheckpoint(m_pThread->m_MarshalAlloc.GetCheckpoint()); - - // Push the current method as the one and only method to process so far. - m_sLeftToProcess.Push(MethodContext::PerThreadAllocate(m_pRootMD, m_pRootTypeContext)); - - MethodContext *pContext = NULL; // The current MethodContext we're processing - - // Iterate until we run out of methods to process. - while ((pContext = m_sLeftToProcess.Pop()) != NULL) { - - // Restore the MD if necessary. In particular, if this is an instantiating stub and the wrapped MethodDesc could - // not be hard bound, then we'll need to restore that pointer before getting it. - pContext->m_pMethodDesc->CheckRestore(); - - // Transfer the method to the already seen stack immediately (we don't want to loop infinitely in the case of method - // recursion). - m_sAlreadySeen.Push(pContext); - - // Check if the enclosing class requires a static class constructor to be run. If so, we need to prepare that method as - // though it were any other call. - if (pContext->m_pMethodDesc->GetMethodTable()->HasClassConstructor()) { - - // Decode target method into MethodDesc and new SigTypeContext. - // The type context is easy to derive here : .cctors never have any method type parameters and the class instantiations - // are those of the method we're currently parsing, so can be simply copied down. - MethodDesc *pCctor = pContext->m_pMethodDesc->GetCanonicalMethodTable()->GetClassConstructor(); - SigTypeContext sCctorTypeContext(pCctor, pContext->m_sTypeContext.m_classInst, Instantiation()); - MethodContext *pCctorContext = MethodContext::PerThreadAllocate(pCctor, &sCctorTypeContext); - - // Only process this cctor the first time we find it in this call graph. - if (!m_sAlreadySeen.IsInStack(pCctorContext) && !m_sLeftToProcess.IsInStack(pCctorContext)) - m_sLeftToProcess.Push(pCctorContext); - } - - // Skip further processing if this method doesn't have an IL body (note that we assume the method we entered with was IL, so - // we don't need to bother with partial method processing). - if (!pContext->m_pMethodDesc->IsIL()) { - _ASSERTE(m_fEntireMethod); - continue; - } - - // Locate the IL body of the current method. May have to account for the fact that the current method desc is an - // instantiating stub and burrow down for the real method desc. - MethodDesc *pRealMethod = pContext->m_pMethodDesc; - if (pRealMethod->IsInstantiatingStub()) { - _ASSERTE(!pRealMethod->ContainsGenericVariables()); - pRealMethod = pRealMethod->GetWrappedMethodDesc(); - } - - COR_ILMETHOD* pILHeader = pRealMethod->GetILHeader(); - - // Skip malformed methods. (We should always have method with IL for well-formed images here.) - if (pILHeader == NULL) { - continue; - } - - COR_ILMETHOD_DECODER method(pILHeader); - m_pMethodDecoder = &method; - - // We want to reget the EH clauses for the current method so that we can scan its handlers - GetEHClauses(); - - LookForInterestingCallsites(pContext); - - // Whatever we've done, we're definitely not processing the top-level method at this point (so we'll be processing full - // method bodies from now on). - m_fEntireMethod = true; - } - -#ifdef FEATURE_NATIVE_IMAGE_GENERATION - if (!m_fNgen) -#endif - { - // Set up a prep info structure for this method if it's not there already (the create method takes care of races). - // This needs to happen before we start JITing the methods as part of preparation. The JIT needs to know - // about the CER root in CEEInfo::canTailCall. - if (m_pCerPrepInfo == NULL) - m_pCerPrepInfo = m_pRootMD->GetModule()->CreateCerPrepInfo(m_pRootMD); - } - - // Prevent infinite recursion by recording on the thread which roots we're currently preparing. - ThreadPreparingCerHolder sCerHolder(this); - - // Once we get here we've run out of methods to process and have recorded each method we visited in the m_sAlreadySeen stack. Now - // it's time to prepare each of these methods (jit, prepopulate generic dictionaries etc.). - PrepareMethods(); - - return RecordResults(); -} - - -// Determine whether a CER preparation for the given root method (with type context for generic instantiation -// if necessary) can go ahead given any current preparation already being performed on the current thread. -BOOL MethodCallGraphPreparer::CanPreparationProceed(MethodDesc * pMD, SigTypeContext * pTypeContext) -{ - WRAPPER_NO_CONTRACT; - MethodCallGraphPreparer * pCurrPrep = this; - while (pCurrPrep) - { - // Is the prepartion request for the root method of the current preparer? - if (pMD == pCurrPrep->m_pRootMD && SigTypeContext::Equal(pTypeContext, pCurrPrep->m_pRootTypeContext)) - { - // We're already preparing this root, return FALSE to turn the request into a no-op and avoid - // infinite recursion. - return FALSE; - } - - pCurrPrep = pCurrPrep->m_pNext; - } - - // We found no previous preparation for the same root, so the request can proceed. - return TRUE; -} - -// Methods that push and pop thread local state used to determine if a re-entrant preparation request should -// complete immediately as a no-op (because it would lead to an infinite recursion) or should proceed -// recursively. - -//static -void MethodCallGraphPreparer::BeginPrepareCerForHolder(MethodCallGraphPreparer * pPrepState) -{ - LIMITED_METHOD_CONTRACT; - - Thread * pThread = pPrepState->m_pThread; - pPrepState->m_pNext = pThread->GetCerPreparationState(); - pThread->SetCerPreparationState(pPrepState); -} - -//static -void MethodCallGraphPreparer::EndPrepareCerForHolder(MethodCallGraphPreparer * pPrepState) -{ - LIMITED_METHOD_CONTRACT; - - Thread * pThread = pPrepState->m_pThread; - _ASSERTE(pThread && pThread->GetCerPreparationState() == pPrepState); - pThread->SetCerPreparationState(pPrepState->m_pNext); -} - - -void MethodCallGraphPreparer::GetEHClauses() -{ - STANDARD_VM_CONTRACT; - - if (! ShouldGatherExplicitCERCallInfo()) - { - return; - } - - m_cEHClauses = 0; - m_pEHClauses = NULL; // we use the StackingAllocator, so don't have to delete the previous storage - - COR_ILMETHOD_SECT_EH const * pEH = m_pMethodDecoder->EH; - if (pEH == NULL ||pEH->EHCount() == 0) - { - return; - } - - m_cEHClauses = pEH->EHCount(); - m_pEHClauses = new (&m_pThread->m_MarshalAlloc) EHClauseRange[m_cEHClauses]; - - for (DWORD i = 0; i < m_cEHClauses; i++) - { - COR_ILMETHOD_SECT_EH_CLAUSE_FAT sEHClauseBuffer; - const COR_ILMETHOD_SECT_EH_CLAUSE_FAT *pEHClause; - - pEHClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)pEH->EHClause(i, &sEHClauseBuffer); - - // The algorithm below assumes handlers are located after their associated try blocks. If this turns out to be a - // false assumption we need to move to a two pass technique (or defer callsite handling in some other fashion until - // we've scanned the IL for all calls to our preparation marker method). - if (!(pEHClause->GetTryOffset() < pEHClause->GetHandlerOffset())) - { - COMPlusThrowHR(COR_E_NOTSUPPORTED, IDS_EE_NOTSUPPORTED_CATCHBEFORETRY); - } - - m_pEHClauses[i].m_dwTryOffset = pEHClause->GetTryOffset(); - m_pEHClauses[i].m_dwHandlerOffset = pEHClause->GetHandlerOffset(); - m_pEHClauses[i].m_dwHandlerLength = pEHClause->GetHandlerLength(); - m_pEHClauses[i].m_fActive = false; - - //printf("Try: %u Handler: %u -> %u\n", pEHClause->GetTryOffset(), pEHClause->GetHandlerOffset(), pEHClause->GetHandlerOffset() + pEHClause->GetHandlerLength() - 1); - } - -} - -void MethodCallGraphPreparer::MarkEHClauseActivatedByCERCall(MethodContext *pContext, BYTE *pbIL, DWORD cbIL) -{ - STANDARD_VM_CONTRACT; - - DWORD dwOffset = (DWORD)(SIZE_T)((pbIL + ArgBytes_InlineTok) - (BYTE*)m_pMethodDecoder->Code); - - // Additionally we need to cope with the fact that VB and C# (for debug builds) can generate NOP instructions - // between the PCR call and the beginning of the try block. So we're potentially looking for the - // intersection of the try with a range of instructions. Count the number of consecutive NOP instructions - // which follow the call. - DWORD dwLength = 0; - BYTE *pbTmpIL = pbIL + ArgBytes_InlineTok; - while (pbTmpIL < (pbIL + cbIL) && *pbTmpIL++ == CEE_NOP) - { - dwLength++; - } - - bool fMatched = false; - for (DWORD i = 0; i < m_cEHClauses; i++) - { - if (m_pEHClauses[i].m_dwTryOffset >= dwOffset && - m_pEHClauses[i].m_dwTryOffset <= (dwOffset + dwLength)) - { - fMatched = true; - m_pEHClauses[i].m_fActive = true; - } - } - if (!fMatched) - { -#if defined(_DEBUG) || defined(MDA_SUPPORTED) - DWORD dwPCROffset = (DWORD)(SIZE_T)((pbIL - 1) - (BYTE*)m_pMethodDecoder->Code); -#endif // defined(_DEBUG) || defined(MDA_SUPPORTED) -#ifdef MDA_SUPPORTED - MDA_TRIGGER_ASSISTANT(IllegalPrepareConstrainedRegion, ReportViolation(pContext->m_pMethodDesc, dwPCROffset)); -#endif - CER_LOG(WARNINGS, ("CER: %s: Invalid call to PrepareConstrainedRegions() at IL +%04X\n", - pContext->m_pMethodDesc->m_pszDebugMethodName, dwPCROffset)); - } -} - -bool MethodCallGraphPreparer::CheckIfCallsiteWithinCER(DWORD dwOffset) -{ - STANDARD_VM_CONTRACT; - - //printf("Found: %s at %u\n", pCallTarget->m_pMethodDesc->m_pszDebugMethodName, dwOffset); - - // Search all the EH regions we know about. - for (DWORD i = 0; i < m_cEHClauses; i++) - { - bool fCallsiteWithinCER = false; - if (! m_pEHClauses[i].m_fActive) - { - // clause not CER-active so skip it - continue; - } - if (dwOffset >= (m_pEHClauses[i].m_dwHandlerOffset + m_pEHClauses[i].m_dwHandlerLength)) - { - // offset beyond clause, so skip it - continue; - } - if (dwOffset >= m_pEHClauses[i].m_dwTryOffset) - { - // For stack probing optimization, we care if either the try or the handler has a call. If neither - // does, then we can optimize the probe out. - m_fMethodHasCallsWithinExplicitCer = true; - if (dwOffset >= m_pEHClauses[i].m_dwHandlerOffset) - { - fCallsiteWithinCER = true; - } - } - // Only terminate if we got a positive result (i.e. the calliste is within a hardened clause). - // We can't terminate early in the negative case because the callsite could be nested - // in another EH region which may be hardened. - if (fCallsiteWithinCER == true) - { - return true; - } - } - - return false; -} - - -// Iterate through the body of the method looking for interesting call sites. -void MethodCallGraphPreparer::LookForInterestingCallsites(MethodContext *pContext) -{ - STANDARD_VM_CONTRACT; - - BYTE *pbIL = (BYTE*)m_pMethodDecoder->Code; - DWORD cbIL = m_pMethodDecoder->GetCodeSize(); - - while (cbIL) { - - // Read the IL op. - DWORD dwOp = *pbIL++; cbIL--; - - // Handle prefix codes (only CEE_PREFIX1 is legal so far). - if (dwOp == CEE_PREFIX1) { - if (!cbIL) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT); - dwOp = 256 + *pbIL++; cbIL--; - } else if (dwOp >= CEE_PREFIX7) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT); - - // We're interested in NEWOBJ, JMP, CALL and CALLVIRT (can't trace through CALLI). We include CALLVIRT becase C# - // routinely calls non-virtual instance methods this way in order to get this pointer null checking. We prepare NEWOBJ - // because that covers the corner case of value types which can be constructed with no failure path. - if (dwOp == CEE_CALL || dwOp == CEE_CALLVIRT || dwOp == CEE_NEWOBJ || dwOp == CEE_JMP) { - - if (cbIL < sizeof(DWORD)) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT); - - // Decode target method into MethodDesc and new SigTypeContext. - mdToken tkCallTarget = (mdToken)GET_UNALIGNED_VAL32(pbIL); - MethodContext *pCallTarget = TokenToMethodDesc(pContext->m_pMethodDesc->GetModule(), tkCallTarget, &pContext->m_sTypeContext); - - // Check whether we've found a call to our own preparation marker method. - if (pCallTarget->m_pMethodDesc == g_pPrepareConstrainedRegionsMethod) { - - if (ShouldGatherExplicitCERCallInfo()) { - // If we're preparing a partial method these callsites are significant (we mark which EH clauses are now - // 'activated' by proximity to this marker method call). Look for EH regions that are 'activated' by the call to - // PrepareConstrainedRegions by comparing the IL offset of the start of the try to the offset immediately after - // the callsite (remember to account for the rest of the CALLVIRT instruction we haven't skipped yet). - MarkEHClauseActivatedByCERCall(pContext, pbIL, cbIL); - } - - // Record the fact that we found a method in the CER which is the root of a sub-CER. This is important since the - // rude thread abort protection algorithm relies on root CER methods being marked as such. - pContext->m_fRoot = true; - } - - // Determine if this was really a virtual call (we discard those since we can't reliably determine the call target). - bool fNonVirtualCall = dwOp == CEE_CALL || !pCallTarget->m_pMethodDesc->IsVirtual() || pCallTarget->m_pMethodDesc->IsFinal(); - - // When we're only processing qualified catch / finally handlers then we need to compute whether this call site - // lands in one of them. The callsite is always within a cer if we are processing the full method. - // If we have stackoverflow probing on, also call to determine if the CER try or finally makes any calls - bool fCallsiteWithinCerInThisFunction = false; - if (!m_fEntireMethod || g_pConfig->ProbeForStackOverflow()) { - DWORD dwOffset = (DWORD)(SIZE_T)((pbIL - 1) - (BYTE*)m_pMethodDecoder->Code); - fCallsiteWithinCerInThisFunction = CheckIfCallsiteWithinCER(dwOffset); - } - bool fCallsiteWithinCer = m_fEntireMethod || fCallsiteWithinCerInThisFunction; - - // Check for the presence of some sort of reliability contract (on the method, class or assembly). This will - // determine whether we log an error, ignore the method or treat it as part of the prepared call graph. - ReliabilityContractLevel eLevel = RCL_UNKNOWN; - if (fNonVirtualCall && // Ignore virtual calls - fCallsiteWithinCer && // And calls outside CERs - !m_sAlreadySeen.IsInStack(pCallTarget) && // And methods we've seen before - !m_sLeftToProcess.IsInStack(pCallTarget) && // And methods we've already queued for processing - (eLevel = CheckForReliabilityContract(pCallTarget->m_pMethodDesc)) >= RCL_PREPARE_CONTRACT) // And unreliable methods - m_sLeftToProcess.Push(pCallTarget); // Otherwise add this method to the list to process - else if (fCallsiteWithinCer) { -#if defined(_DEBUG) || defined(MDA_SUPPORTED) - DWORD dwOffset = (DWORD)(SIZE_T)((pbIL - 1) - (BYTE*)m_pMethodDecoder->Code); -#endif // defined(_DEBUG) || defined(MDA_SUPPORTED) - if (eLevel == RCL_NO_CONTRACT) { - // Method was sufficiently unreliable for us to warn interested users that something may be amiss. Do this - // through MDA logging. -#ifdef MDA_SUPPORTED - MDA_TRIGGER_ASSISTANT(InvalidCERCall, ReportViolation(pContext->m_pMethodDesc, pCallTarget->m_pMethodDesc, dwOffset)); -#endif - CER_LOG(WARNINGS, ("CER: %s +%04X -> %s: weak contract\n", pContext->ToString(), dwOffset, pCallTarget->ToString())); - } else if (!fNonVirtualCall && !m_fIgnoreVirtualCERCallMDA) { - // Warn users about virtual calls in CERs (so they can go back and consider which target methods need to be - // prepared ahead of time). -#ifdef MDA_SUPPORTED - MDA_TRIGGER_ASSISTANT(VirtualCERCall, ReportViolation(pContext->m_pMethodDesc, pCallTarget->m_pMethodDesc, dwOffset)); -#endif - CER_LOG(WARNINGS, ("CER: %s +%04X -> %s: virtual call\n", pContext->ToString(), dwOffset, pCallTarget->ToString())); - } - } - } - - // Skip the rest of the current IL instruction. Look up the table built statically at the top of this module for most - // instructions, but CEE_SWITCH requires special processing (the length of that instruction depends on a count DWORD - // embedded right after the opcode). - if (dwOp == CEE_SWITCH) { - DWORD dwTargets = GET_UNALIGNED_VAL32(pbIL); - if (dwTargets >= (MAXDWORD / sizeof(DWORD))) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT); // multiplication below would overflow - DWORD cbSwitch = (1 + dwTargets) * sizeof(DWORD); - if (cbIL < cbSwitch) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT); - pbIL += cbSwitch; - cbIL -= cbSwitch; - } else { - if (dwOp >= _countof(g_rOpArgs)) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT); - DWORD cbOp = g_rOpArgs[dwOp]; - if (cbIL < cbOp) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT); - pbIL += cbOp; - cbIL -= cbOp; - } - - } // End of IL parsing loop -} - -void MethodCallGraphPreparer::PrepareMethods() -{ - STANDARD_VM_CONTRACT; - -#ifdef _DEBUG - DWORD dwCount = 0; - if (GetCerLoggingOptions()) - { - CER_LOG(PREPARE, ("---------------------------------------------------------------\n")); - SString ssMethod; - TypeString::AppendMethodInternal(ssMethod, m_pRootMD, TypeString::FormatNamespace | TypeString::FormatStubInfo); - CER_LOG(PREPARE, ("Preparing from %S\n", ssMethod.GetUnicode())); - } -#endif - - MethodContext *pContext; // The current MethodContext we're processing - - while ((pContext = m_sAlreadySeen.Pop()) != NULL) { - MethodDesc *pMD = pContext->m_pMethodDesc; - -#ifndef CROSSGEN_COMPILE - // Jitting. Don't need to do this for the ngen case. -#ifdef FEATURE_NATIVE_IMAGE_GENERATION - if (!m_fNgen) -#endif - { - // Also skip the jit for the root method in the activated from jit case (where this would result in a recursive - // jit). We'd cope with this just fine, the main reason for this logic is to avoid unbalancing some profiler event - // counts that upset some of our test cases. This is safe in the face of multiple instantiations of the same method - // because in the jit activated case (where we're told the root type context is not exact) we early exit if the root - // method desc isn't 'unique' (i.e. independent of the type context). - if (m_fExactTypeContext || pMD != m_pRootMD) { - - // Jit the method we traced. - if (pMD->IsPointingToPrestub()) - { - pMD->EnsureActive(); - pMD->DoPrestub(NULL); - } - - // If we traced an instantiating stub we need to jit the wrapped (real) method as well. - if (pMD->IsInstantiatingStub()) { - _ASSERTE(!pMD->ContainsGenericVariables()); - MethodDesc *pRealMD = pMD->GetWrappedMethodDesc(); - if (pRealMD->IsPointingToPrestub()) - { - pMD->EnsureActive(); - pRealMD->DoPrestub(NULL); - } - } - } - - // Remember sub-CER root methods for further processing in RecordResults. We need to build CerPrepInfo structures for - // these just the same as top-level CERs since we may wander in to them by a route that doesn't include the top-level CER - // and the thread abort deflection algorithm relies on each CER root method being marked by a CerPrepInfo. Defer this - // processing to RecordResults since we aren't guaranteed to have prepared all the methods of the sub-graph at this - // point. - if (pContext->m_fRoot && pMD != m_pRootMD) - m_sPersist.Push(pContext); - } -#endif // CROSSGEN_COMPILE - - // Prepare generic dictionaries (both class and method as needed). We do this even in the ngen scenario, trying to get - // as many slots filled as possible. By the looks of it, it's possible that not all of these entries will make it across - // to runtime (the fixup code seems to give up on some of the more complex entries, not sure of the details). But we'll - // do as best we can here to hopefully minimize any real work on the other side. - - // Don't use the direct PrepopulateDictionary method on MethodTable here, it takes binding considerations into account - // (which we don't care about). - DictionaryLayout *pClassDictLayout = pMD->GetClass()->GetDictionaryLayout(); - if (pClassDictLayout) { - // Translate the representative method table we can find from our method desc into an exact instantiation using the - // type context we have. - MethodTable *pMT = TypeHandle(pMD->GetMethodTable()).Instantiate(pContext->m_sTypeContext.m_classInst).AsMethodTable(); - - pMT->GetDictionary()->PrepopulateDictionary(NULL, pMT, false); - - // The dictionary may have overflowed in which case we need to prepopulate the jit's lookup cache as well. - PrepopulateGenericHandleCache(pClassDictLayout, NULL, pMT); - } - - // Don't use the direct PrepopulateDictionary method on MethodDesc here, it appears to use a representative class - // instantiation (and we have the exact one handy). - DictionaryLayout *pMethDictLayout = pMD->GetDictionaryLayout(); - if (pMethDictLayout) { - pMD->GetMethodDictionary()->PrepopulateDictionary(pMD, NULL, false); - - // The dictionary may have overflowed in which case we need to prepopulate the jit's lookup cache as well. - PrepopulateGenericHandleCache(pMethDictLayout, pMD, NULL); - } - -#ifdef FEATURE_NATIVE_IMAGE_GENERATION - // Keep some of the method contexts around for the ngen case (the ones that might still need fixup at runtime). We'll - // write them into a persisted data structure in the next step. - // @todo: We use a horrible workaround here to get round the fact that while ngen'ing mscorlib we may prepare some of its - // methods before we've had a chance to start up the compilation domain (mscorlib code is shared and used by the ngen - // process itself). So we can't blindly call NeedsRestore() on an mscorlib method since that code asserts we're in the - // compilation domain. Instead, if we're in the ngen process and we're outside the compilation domain we're going to - // assume that the method doesn't need restoration. This only affects a handful of methods (six at last count, all to do - // with security safe handles or some CERs in remoting). - if (m_fNgen) { - if (GetAppDomain() == NULL || - !GetAppDomain()->IsCompilationDomain() || - !(GetAppDomain()->ToCompilationDomain()->canCallNeedsRestore()) || - !(GetAppDomain()->ToCompilationDomain()->GetTargetImage()->CanPrerestoreEagerBindToMethodDesc(pMD, NULL))|| - pMD->HasClassOrMethodInstantiation() || - pMD->IsNDirect() || - pMD->IsComPlusCall() || - pMD->IsFCall() || - pContext->m_fRoot) - m_sPersist.Push(pContext); - } -#endif - -#ifdef _DEBUG - CER_LOG(PREPARE, (" %s\n", pContext->ToString())); - dwCount++; -#endif - } - -#ifdef _DEBUG - CER_LOG(PREPARE, ("Prepared a total of %u methods\n", dwCount)); -#ifdef FEATURE_NATIVE_IMAGE_GENERATION - if (m_fNgen) - CER_LOG(PREPARE, ("Saved data for %u of them in the ngen image\n", m_sPersist.GetCount())); -#endif - CER_LOG(PREPARE, ("---------------------------------------------------------------\n")); -#endif -} - -// Common code used in creating/looking up a CerPrepInfo and initializing/updating it. -void InitPrepInfo(MethodDesc *pMD, SigTypeContext *pTypeContext, bool fMethodHasCallsWithinExplicitCer) -{ - CONTRACTL { - STANDARD_VM_CHECK; - PRECONDITION(CheckPointer(pMD)); - } CONTRACTL_END; - - // Lookup or allocate the CerPrepInfo. - CerPrepInfo *pInfo = pMD->GetModule()->CreateCerPrepInfo(pMD); - - pInfo->m_fMethodHasCallsWithinExplicitCer = fMethodHasCallsWithinExplicitCer; - - // Work out if this was a partial preparation. - bool fPartialPreparation = pMD->IsSharedByGenericInstantiations() || - pMD->IsInstantiatingStub() || - pMD->ContainsGenericVariables(); - - // Simple case first: if this isn't a partial preparation (no pesky unbound type vars to worry about), then the method is - // now fully prepared. - if (!fPartialPreparation) { - pInfo->m_fFullyPrepared = true; - return; - } - - // Else we know we require per-instantiation initialization. We need to update a hash table to record the preparation we did - // in this case, and that requires taking a mutex. We could check that nobody beat us to it first, but that will hardly ever - // happen, so it's not really worth it. So just acquire the mutex right away. - CrstHolder sHolder(pMD->GetModule()->GetCerCrst()); - - pInfo->m_fRequiresInstantiation = true; - - // Add an entry to a hash that records which instantiations we've prep'd for (again, only if someone hasn't beaten us). - HashDatum sDatum; - if (!pInfo->m_sIsInitAtInstHash.GetValue(pTypeContext, &sDatum)) - { - pInfo->m_sIsInitAtInstHash.InsertKeyAsValue(pTypeContext); - } -} - -bool MethodCallGraphPreparer::RecordResults() -{ - STANDARD_VM_CONTRACT; - - // Preparation has been successful, record what we've done in a manner consistent with whether we're ngen'ing or running for - // real. - -#ifdef FEATURE_NATIVE_IMAGE_GENERATION - // If we're ngen'ing an image we save our progess as a list of method contexts that might need restoration at runtime (since - // even with prejitting there are some things that need to be prepared at runtime). This list goes into a per module table (the - // module in question being that of the root method in the CER). - if (m_fNgen) { - - // We have the list of MethodContexts ready, but they're in cheap storage that will go away once we exit this method. - // Not only do we have to copy them to heap memory, but we also know exactly how many there are. So we can allocate a - // single array with a more compact form of MethodContext for each element. We allocate an extra sentinel value for the end - // of the list. This means we can store just a pointer to the list without a count (the code that accesses this list cares - // about keeping the list heads compact and densely packed and doesn't care about counting the elements in the list). - DWORD cContexts = m_sPersist.GetCount(); - LoaderHeap *pHeap = m_pRootMD->GetAssembly()->GetLowFrequencyHeap(); - MethodContextElement *pContexts = (MethodContextElement*)(void*)pHeap->AllocMem(S_SIZE_T(sizeof(MethodContextElement)) * (S_SIZE_T(cContexts) + S_SIZE_T(1))); - DWORD i = 0; - - MethodContext *pContext; // The current MethodContext we're processing - while ((pContext = m_sPersist.Pop()) != NULL) { - pContexts[i].m_pMethodDesc.SetValue(pContext->m_pMethodDesc); - - MethodTable * pExactMT = NULL; - if (!pContext->m_sTypeContext.m_classInst.IsEmpty()) - { - pExactMT = TypeHandle(pContext->m_pMethodDesc->GetMethodTable()).Instantiate(pContext->m_sTypeContext.m_classInst).AsMethodTable(); - _ASSERTE(pExactMT->HasInstantiation()); - } - else - { - _ASSERTE(!pContext->m_pMethodDesc->GetMethodTable()->HasInstantiation()); - } - pContexts[i].m_pExactMT.SetValue(pExactMT); - - i++; - - // Keep the context round for a little longer if the method in question was the root of a sub-CER. - if (pContext->m_fRoot) - m_sRootMethods.Push(pContext); - } - - // Write sentinel entry terminating list. - _ASSERTE(i == cContexts); - - // Add list representing this CER to the per-module table (keyed by root method desc). - m_pRootMD->GetModule()->AddCerListToRootTable(m_pRootMD, pContexts); - - // If this did have an call from an explicit PCER range, create a PrepInfo for it so that we can - // quickly grab that information later when we jit that method. This allows us to optimize the probe - // away if there are no calls from the PCER range. This is an issue when we've prepared a method - // as part of a CER call from another method, but haven't ngened that method yet. When we get - // around to finally ngening that method, we want to be able to optimize the CER probe out if - // we can, but don't want to reprepare the method. - if (g_pConfig->ProbeForStackOverflow() && m_fMethodHasCallsWithinExplicitCer) - { - if (m_pCerPrepInfo == NULL) - m_pCerPrepInfo = m_pRootMD->GetModule()->CreateCerPrepInfo(m_pRootMD); - m_pCerPrepInfo->m_fMethodHasCallsWithinExplicitCer = TRUE; - } - - - // We need to be careful with sub-CERs in the ngen case. In the jit case they're dealt with automatically (preparing a - // super-CER always completely prepares a sub-CER). But in the ngen case we potentially need to run further preparation - // steps at the point that a CER root is executed for the first time. If the sub-root is encountered before the super-root - // then the sub-CER won't have been prepared correctly. - // We solve this simply by recursively running this routine over the methods we noted were sub-roots earlier (this list - // doesn't include the main root). We could potentially do a little better than this given that we've calculated the - // super-graph, but this is complicated somewhat by the fact that we don't retain the graph structure (i.e. we can't extract - // sub-graphs easily) and the effort seems wasted just to avoid a little CPU time and stack space just for the ngen creation - // scenario. - while ((pContext = m_sRootMethods.Pop()) != NULL) - { - MethodCallGraphPreparer mgcp(pContext->m_pMethodDesc, &pContext->m_sTypeContext, false, false); - mgcp.Run(); - } - - return m_fMethodHasCallsWithinExplicitCer; - } -#endif // FEATURE_NATIVE_IMAGE_GENERATION - - // This is the runtime (non-ngen case). Record our progress in an info structure placed in a hash table hung off the module - // which owns the root method desc in the CER. The methods which create this info structure handle race conditions (to - // ensure we don't leak memory or data), but the updates to the info structure itself might not require any serialization - // (the values are 'latched' -- recomputation should yield the same result). The exception is any update to a more complex - // data fields (lists and hash tables) that require serialization to prevent corruption of the basic data structure. - - // Process sub-CER roots first. We need to build CerPrepInfo structures for these just as same as top-level CERs since we may - // wander in to them by a route that doesn't include the top-level CER and the thread abort deflection algorithm relies on each - // CER root method being marked by a CerPrepInfo. - MethodContext *pContext; - while ((pContext = m_sPersist.Pop()) != NULL) { - _ASSERTE(pContext->m_fRoot); - - // @todo: need to flow fMethodHasCallsWithinExplicitCer information through method contexts. For now just make a - // conservative, safe choice. - InitPrepInfo(pContext->m_pMethodDesc, &pContext->m_sTypeContext, true); - } - - // Now process the top-level CER. - InitPrepInfo(m_pRootMD, m_pRootTypeContext, m_fMethodHasCallsWithinExplicitCer); - - return m_fMethodHasCallsWithinExplicitCer; -} - -// Determines whether the given method contains a CER root that can be pre-prepared (i.e. prepared at jit time). -bool ContainsPrePreparableCerRoot(MethodDesc *pMD) -{ - CONTRACTL { - STANDARD_VM_CHECK; - PRECONDITION(CheckPointer(pMD)); - } CONTRACTL_END; - - // Deal with exotic cases (non-IL methods and the like). - if (!pMD->IsIL() || pMD->IsAbstract()) - return false; - - // And cases where we can't jit prepare (because the code is shared between instantiations). - if (pMD->IsSharedByGenericInstantiations() || pMD->IsInstantiatingStub() || pMD->ContainsGenericVariables()) - return false; - - // Otherwise we have a trickier calculation. We don't want to force the jit of the method at this point (may cause infinite - // recursion problems when we're called from the jit in the presence of call cycles). Instead we walk the top-level of the - // method IL using the same algorithm as PrepareMethodCallGraph. - - // Locate the IL body of the current method. May have to account for the fact that the current method desc is an - // instantiating stub and burrow down for the real method desc. - MethodDesc *pRealMethod = pMD; - if (pRealMethod->IsInstantiatingStub()) { - _ASSERTE(!pRealMethod->ContainsGenericVariables()); - pRealMethod = pRealMethod->GetWrappedMethodDesc(); - } - COR_ILMETHOD_DECODER method(pRealMethod->GetILHeader()); - BYTE *pbIL = (BYTE*)method.Code; - DWORD cbIL = method.GetCodeSize(); - - // Look for exception handling information for the method. If there isn't any then we know there can't be a CER rooted here. - COR_ILMETHOD_SECT_EH const * pEH = method.EH; - if (pEH == NULL || pEH->EHCount() == 0) - return false; - - // Iterate through the body of the method looking for interesting call sites. - while (cbIL) { - - // Read the IL op. - DWORD dwOp = *pbIL++; cbIL--; - - // Handle prefix codes (only CEE_PREFIX1 is legal so far). - if (dwOp == CEE_PREFIX1) { - if (!cbIL) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT); - dwOp = 256 + *pbIL++; cbIL--; - if (dwOp >= CEE_ILLEGAL) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT); - } else if (dwOp >= CEE_PREFIX7) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT); - - // We'll only ever see CALL instructions targeting PrepareConstrainedRegions (well those are the ones we're interested in - // anyway). - if (dwOp == CEE_CALL) - { - if (cbIL < sizeof(DWORD)) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT); - if (IsPcrReference(pMD->GetModule(), (mdToken)GET_UNALIGNED_VAL32(pbIL))) - return true; - } - - // Skip the rest of the current IL instruction. Look up the table built statically at the top of this module for most - // instructions, but CEE_SWITCH requires special processing (the length of that instruction depends on a count DWORD - // embedded right after the opcode). - if (dwOp == CEE_SWITCH) { - if (cbIL < sizeof(DWORD)) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT); - DWORD dwTargets = GET_UNALIGNED_VAL32(pbIL); - if (dwTargets >= (MAXDWORD / sizeof(DWORD))) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT); // multiplication below would overflow - DWORD cbSwitch = (1 + dwTargets) * sizeof(DWORD); - if (cbIL < cbSwitch) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT); - pbIL += cbSwitch; - cbIL -= cbSwitch; - } else { - if (dwOp >= _countof(g_rOpArgs)) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT); - DWORD cbOp = g_rOpArgs[dwOp]; - if (cbIL < cbOp) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT); - pbIL += cbOp; - cbIL -= cbOp; - } - - } // End of IL parsing loop - - // If we get here then there was no CER-root. - return false; -} - -// The name of the PrepareConstrainedRegions method, broken down into its components (the code below scans for these directly in the -// metadata). -#define PCR_METHOD "PrepareConstrainedRegions" -#define PCR_TYPE "RuntimeHelpers" -#define PCR_NAMESPACE "System.Runtime.CompilerServices" - -// Given a token and a module scoping it, determine if that token is a reference to PrepareConstrainedRegions. We want to do this -// without loading any random types since we're called in a context where type loading is prohibited. -bool IsPcrReference(Module *pModule, mdToken tkMethod) -{ - CONTRACTL { - STANDARD_VM_CHECK; - PRECONDITION(CheckPointer(pModule)); - } CONTRACTL_END; - - IMDInternalImport *pImport = pModule->GetMDImport(); - - // Validate that the token is one that we can handle. - if (!pImport->IsValidToken(tkMethod) || (TypeFromToken(tkMethod) != mdtMethodDef && - TypeFromToken(tkMethod) != mdtMethodSpec && - TypeFromToken(tkMethod) != mdtMemberRef)) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_METHOD_TOKEN); - - // No reason to see a method spec for a call to something as simple as PrepareConstrainedRegions. - if (TypeFromToken(tkMethod) == mdtMethodSpec) - return false; - - // If it's a method def then the module had better be mscorlib. - if (TypeFromToken(tkMethod) == mdtMethodDef) { - if (pModule->GetAssembly()->GetManifestModule() == SystemDomain::SystemAssembly()->GetManifestModule()) - return tkMethod == g_pPrepareConstrainedRegionsMethod->GetMemberDef(); - else - return false; - } - - // That leaves the cross module reference case. - _ASSERTE(TypeFromToken(tkMethod) == mdtMemberRef); - - // First get the method name and signature and validate it. - PCCOR_SIGNATURE pSig; - DWORD cbSig; - LPCSTR szMethod; - IfFailThrow(pImport->GetNameAndSigOfMemberRef(tkMethod, &pSig, &cbSig, &szMethod)); - - { - SigParser sig(pSig, cbSig); - ULONG nCallingConvention; - ULONG nArgumentsCount; - BYTE bReturnType; - - // Signature is easy: void PCR(). - // Must be a static method signature. - if (FAILED(sig.GetCallingConvInfo(&nCallingConvention))) - return false; - if (nCallingConvention != IMAGE_CEE_CS_CALLCONV_DEFAULT) - return false; - // With no arguments. - if (FAILED(sig.GetData(&nArgumentsCount))) - return false; - if (nArgumentsCount != 0) - return false; - // And a void return type. - if (FAILED(sig.GetByte(&bReturnType))) - return false; - if (bReturnType != (BYTE)ELEMENT_TYPE_VOID) - return false; - } - - // Validate the name. - if (strcmp(szMethod, PCR_METHOD) != 0) - return false; - - // The method looks OK, move up to the type and validate that. - mdToken tkType; - IfFailThrow(pImport->GetParentOfMemberRef(tkMethod, &tkType)); - - if (!pImport->IsValidToken(tkType)) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN); - - // If the parent is not a type ref then this isn't our target (we assume that mscorlib never uses a member ref to target - // PrepareConstrainedRegions, check that with the assert below, if it ever fails we need to add some additional logic below). - _ASSERTE(TypeFromToken(tkType) != mdtTypeDef || - pModule->GetAssembly()->GetManifestModule() != SystemDomain::SystemAssembly()->GetManifestModule()); - if (TypeFromToken(tkType) != mdtTypeRef) - return false; - - // Get the type name and validate it. - LPCSTR szNamespace; - LPCSTR szType; - IfFailThrow(pImport->GetNameOfTypeRef(tkType, &szNamespace, &szType)); - - if (strcmp(szType, PCR_TYPE) != 0) - return false; - if (strcmp(szNamespace, PCR_NAMESPACE) != 0) - return false; - - // Type is OK as well. Check the assembly reference. - mdToken tkScope; - IfFailThrow(pImport->GetResolutionScopeOfTypeRef(tkType, &tkScope)); - - if (TypeFromToken(tkScope) != mdtAssemblyRef) - return false; - if (!pImport->IsValidToken(tkScope)) - { - COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN); - } - - // Fetch the name and public key or public key token. - BYTE *pbPublicKeyOrToken; - DWORD cbPublicKeyOrToken; - LPCSTR szAssembly; - DWORD dwAssemblyFlags; - IfFailThrow(pImport->GetAssemblyRefProps( - tkScope, - (const void**)&pbPublicKeyOrToken, - &cbPublicKeyOrToken, - &szAssembly, - NULL, // AssemblyMetaDataInternal: we don't care about version, culture etc. - NULL, // Hash value pointer, obsolete information - NULL, // Byte count for above - &dwAssemblyFlags)); - - // Validate the name. - if (stricmpUTF8(szAssembly, g_psBaseLibraryName) != 0) - return false; - - // And the public key or token, which ever was burned into the reference by the compiler. For mscorlib this is the ECMA key or - // token. - if (IsAfPublicKeyToken(dwAssemblyFlags)) { - if (cbPublicKeyOrToken != sizeof(g_rbNeutralPublicKeyToken) || - memcmp(pbPublicKeyOrToken, g_rbNeutralPublicKeyToken, cbPublicKeyOrToken) != 0) - return false; - } else { - if (cbPublicKeyOrToken != sizeof(g_rbNeutralPublicKey) || - memcmp(pbPublicKeyOrToken, g_rbNeutralPublicKey, cbPublicKeyOrToken) != 0) - return false; - } - - // If we get here we've finally proved the call target was indeed PrepareConstrainedRegions. Whew. - return true; -} - -// Prepares a method as a CER root. In some scenarios we set -// fIgnoreVirtualCERCallMDA=TRUE, this happens when we want to ignore firing a -// VirtualCERCall MDA because we know for sure that the virtual methods are -// already prepared. A good example of this case is preparing -// g_pExecuteBackoutCodeHelperMethod method. -void PrepareMethodDesc(MethodDesc* pMD, Instantiation classInst, Instantiation methodInst, BOOL onlyContractedMethod, BOOL fIgnoreVirtualCERCallMDA) -{ - CONTRACTL - { - THROWS; - DISABLED(GC_TRIGGERS); - MODE_ANY; - } - CONTRACTL_END; - - GCX_PREEMP(); - -#ifdef FEATURE_PREJIT - // This method may have some ngen fixup information provided, in which case we just check that it's been restored and can - // dispense with the preparation altogether. - Module *pModule = pMD->GetModule(); - if (pModule->IsNgenCerRootMethod(pMD)) - { - pMD->CheckRestore(); - pModule->RestoreCer(pMD); - return; - } -#endif - - // If we are only going to prepare contracted methods and this method does - // not have a contract then we just return. - if (onlyContractedMethod && CheckForReliabilityContract(pMD) < RCL_BASIC_CONTRACT) - { - return; - } - - SigTypeContext sTypeContext(pMD, classInst, methodInst); - MethodCallGraphPreparer mcgp(pMD, &sTypeContext, true, true, fIgnoreVirtualCERCallMDA == TRUE); - mcgp.Run(); -} - -// Prepares the critical finalizer call graph for the given object type (which -// must derive from CriticalFinalizerObject). This involves preparing at least -// the finalizer method and possibly some others (for SafeHandle and -// CriticalHandle derivations). If a module pointer is supplied then only the -// critical methods introduced in that module are prepared (this is used at -// ngen time to ensure that we're only generating ngen preparation info for the -// targetted module). -void PrepareCriticalFinalizerObject(MethodTable *pMT, Module *pModule) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(CheckPointer(pMT)); - } CONTRACTL_END; - - // Have we prepared this type before? - if (pMT->CriticalTypeHasBeenPrepared()) - return; - - GCX_PREEMP(); - - // Restore the method table if necessary. - pMT->CheckRestore(); - - // Determine the interesting parent class (either SafeHandle, CriticalHandle or CriticalFinalizerObject). - MethodTable *pSafeHandleClass = MscorlibBinder::GetClass(CLASS__SAFE_HANDLE); - MethodTable *pCriticalHandleClass = MscorlibBinder::GetClass(CLASS__CRITICAL_HANDLE); - MethodTable *pParent = pMT; - while (pParent) { - if (pParent == g_pCriticalFinalizerObjectClass || - pParent == pSafeHandleClass || - pParent == pCriticalHandleClass) { - break; - } - pParent = pParent->GetParentMethodTable(); - } - _ASSERTE(pParent != NULL); - - BinderMethodID rgMethods[5]; - int nMethods; - - // Prepare the method or methods based on the parent class. - if (pParent == pSafeHandleClass) { - rgMethods[0] = METHOD__CRITICAL_FINALIZER_OBJECT__FINALIZE; - rgMethods[1] = METHOD__SAFE_HANDLE__RELEASE_HANDLE; - rgMethods[2] = METHOD__SAFE_HANDLE__GET_IS_INVALID; - rgMethods[3] = METHOD__SAFE_HANDLE__DISPOSE; - rgMethods[4] = METHOD__SAFE_HANDLE__DISPOSE_BOOL; - nMethods = 5; - } else if (pParent == pCriticalHandleClass) { - rgMethods[0] = METHOD__CRITICAL_FINALIZER_OBJECT__FINALIZE; - rgMethods[1] = METHOD__CRITICAL_HANDLE__RELEASE_HANDLE; - rgMethods[2] = METHOD__CRITICAL_HANDLE__GET_IS_INVALID; - rgMethods[3] = METHOD__CRITICAL_HANDLE__DISPOSE; - rgMethods[4] = METHOD__CRITICAL_HANDLE__DISPOSE_BOOL; - nMethods = 5; - } else { - _ASSERTE(pParent == g_pCriticalFinalizerObjectClass); - rgMethods[0] = METHOD__CRITICAL_FINALIZER_OBJECT__FINALIZE; - nMethods = 1; - } - - for (int iMethod = 0; iMethod < nMethods; iMethod++) - { - // Prepare a (possibly virtual) method on an instance. The method is identified via a binder ID, so the initial - // declaration of the method must reside within mscorlib. We might have ngen fixup information for the method and can avoid direct - // preparation as well. - - MethodDesc *pPrepMethod = pMT->GetMethodDescForSlot(MscorlibBinder::GetMethod(rgMethods[iMethod])->GetSlot()); -#ifdef FEATURE_PREJIT - if (pPrepMethod->GetModule()->IsNgenCerRootMethod(pPrepMethod)) { - pPrepMethod->GetModule()->RestoreCer(pPrepMethod); - } - else - if (IsCompilationProcess() && pPrepMethod->IsAbstract()) { - // Skip abstract methods during NGen (we should not ever get abstract methods here at runtime) - } - else -#endif - { - if (pModule == NULL || pPrepMethod->GetModule() == pModule) { - SigTypeContext _sTypeContext(pPrepMethod, TypeHandle(pMT)); - MethodCallGraphPreparer mcgp(pPrepMethod, &_sTypeContext, true, true); - mcgp.Run(); - } - } - } - - // Note the fact that we've prepared this type before to prevent repetition of the work above. (Though repetition is harmless in - // all other respects, so there's no need to worry about the race setting this flag). - pMT->SetCriticalTypeHasBeenPrepared(); -} - -#ifdef _DEBUG - -static const char * const g_rszContractNames[] = { "RCL_NO_CONTRACT", "RCL_BASIC_CONTRACT", "RCL_PREPARE_CONTRACT" }; -static DWORD g_dwContractChecks = 0; - -#define ReturnContractLevel(_level) do { \ - g_dwContractChecks++; \ - if ((g_dwContractChecks % 100) == 0 && g_pMethodContractCache) \ - g_pMethodContractCache->DbgDumpStats(); \ - ReliabilityContractLevel __level = (_level); \ - CER_LOG(CONTRACTS, ("%s -- %s\n", pMD->m_pszDebugMethodName, g_rszContractNames[__level])); \ - return __level; \ -} while (false) -#else -#define ReturnContractLevel(_level) return (_level) -#endif - -// Look for reliability contracts at the method, class and assembly level and parse them to extract the information we're interested -// in from a runtime preparation viewpoint. This information is abstracted in the form of the ReliabilityContractLevel enumeration. -ReliabilityContractLevel CheckForReliabilityContract(MethodDesc *pMD) -{ - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(CheckPointer(pMD)); - } CONTRACTL_END; - - // We are attempting to abstract reliability contracts for the given method into three different buckets: those methods that - // will cause an error (or a MDA report at least) during preparation (RCL_NO_CONTRACT), those we allow but don't prepare - // (RCL_BASIC_CONTRACT) and those we allow and prepare (RCL_PREPARE_CONTRACT). - // - // We place methods into the first bucket below that matches: - // RCL_NO_CONTRACT -- Methods with no consistency or whose consistency states they may corrupt the appdomain or process. - // RCL_BASIC_CONTRACT -- Methods that state CER.None (or don't specify a CER attribute) - // RCL_PREPARE_CONTRACT -- Methods that state CER.MayFail or CER.Success - // - // We look for reliability contracts at three levels: method, class and assembly. Definitions found at the method level override - // those at the class and assembly level and those at the class level override assembly settings. - // - // In the interests of efficiency we cache contract information in a number of ways. Firstly we look at a hash of recently - // queried MethodDescs. This contains authoritative answers (assembly/class/method information has already been composed so on a - // hit we don't need to look anywhere else). This cache is allocated lazily, never grows (newer items eventually displace older - // ones), is global, requires no locks and is never freed. The idea is to limit the amount of working set we ever occupy while - // keeping the CPU usage as low as possible. Typical usages of this method involve querying a small number of methods in a stack - // walk, possibly multiple times, so a small hash cache should work reasonably well here. - // - // On a miss we're going to have to bite the bullet and look at the assembly, class and method. The assembly and class cache - // this information at load (ngen) time though, so they're not so expensive (class level data is cached on the EEClass, so it's - // cold data, but the most performance sensitive scenario in which we're called here, ThreadAbort, isn't all that hot). - - // Check the cache first, it contains a raw contract level. - ReliabilityContractLevel eLevel; - if (g_pMethodContractCache && g_pMethodContractCache->Lookup(pMD, (DWORD*)&eLevel)) - ReturnContractLevel(eLevel); - - // Start at the method level and work up until we've found enough information to make a decision. The contract level is composed - // in an encoded DWORD form that lets us track both parts of the state (consistency and cer) and whether each has been supplied - // yet. See the RC_* macros for encoding details. - DWORD dwMethodContractInfo = GetReliabilityContract(pMD->GetMDImport(), pMD->GetMemberDef()); - if (RC_INCOMPLETE(dwMethodContractInfo)) { - DWORD dwClassContractInfo = pMD->GetClass()->GetReliabilityContract(); - dwMethodContractInfo = RC_MERGE(dwMethodContractInfo, dwClassContractInfo); - if (RC_INCOMPLETE(dwMethodContractInfo)) { - DWORD dwAssemblyContractInfo = pMD->GetModule()->GetReliabilityContract(); - dwMethodContractInfo = RC_MERGE(dwMethodContractInfo, dwAssemblyContractInfo); - } - } - - // We've got an answer, so attempt to cache it for the next time. - - // First check we have a cache (we allocate it lazily). - if (g_pMethodContractCache == NULL) { - PtrHashCache *pCache = new (nothrow) PtrHashCache(); - if (pCache) - if (FastInterlockCompareExchangePointer(&g_pMethodContractCache, pCache, NULL) != NULL) - delete pCache; - } - - // We still might not have a cache in low memory situations. That's OK. - if (g_pMethodContractCache) - g_pMethodContractCache->Add(pMD, RC_ENCODED_TO_LEVEL(dwMethodContractInfo)); - - ReturnContractLevel(RC_ENCODED_TO_LEVEL(dwMethodContractInfo)); -} - - -// Macro used to handle failures in the routine below. -#define IfFailRetRcNull(_hr) do { if (FAILED(_hr)) return RC_NULL; } while (false) - -// Look for a reliability contract attached to the given metadata token in the given scope. Return the result as an encoded DWORD -// (see the RC_ENCODE macro). -DWORD GetReliabilityContract(IMDInternalImport *pImport, mdToken tkParent) -{ - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(CheckPointer(pImport)); - } CONTRACTL_END; - - HRESULT hr; - DWORD dwResult = RC_NULL; - - // Sadly we only have two unmanaged APIs available to us for looking at custom attributes. One looks up attributes by name but - // only returns the byte blob, not the attribute ctor information (which we need to parse the blob) while the other returns - // everything but requires us to enumerate all attributes on a given token looking for the one we're interested in. To keep the - // cost down we probe for the existence of the attribute using the first API and then use the enumeration method if we get a - // hit. - hr = pImport->GetCustomAttributeByName(tkParent, RELIABILITY_CONTRACT_NAME, NULL, NULL); - if (hr == S_FALSE) - return RC_NULL; - - IfFailRetRcNull(hr); - - // Got at least one contract against this parent. Enumerate them all (filtering by name). - MDEnumHolder hEnum(pImport); - hr = pImport->SafeAndSlowEnumCustomAttributeByNameInit(tkParent, RELIABILITY_CONTRACT_NAME, &hEnum); - _ASSERTE(hr != S_FALSE); - IfFailRetRcNull(hr); - - // Enumerate over all the contracts. - mdToken tkContract; - while (S_OK == pImport->SafeAndSlowEnumCustomAttributeByNameNext(tkParent, RELIABILITY_CONTRACT_NAME, &hEnum, &tkContract)) { - - // Get the attribute type (token of the ctor used) since we need this information in order to parse the blob we'll find - // next. - mdToken tkAttrType; - IfFailRetRcNull(pImport->GetCustomAttributeProps(tkContract, &tkAttrType)); - if (!pImport->IsValidToken(tkAttrType)) - continue; - - // The token should be a member ref or method def. - // Get the signature of the ctor so we know which version has been called. - PCCOR_SIGNATURE pSig; - DWORD cbSig; - LPCSTR szName_Ignore; - if (TypeFromToken(tkAttrType) == mdtMemberRef) - { - IfFailRetRcNull(pImport->GetNameAndSigOfMemberRef(tkAttrType, &pSig, &cbSig, &szName_Ignore)); - } - else - { - if (TypeFromToken(tkAttrType) != mdtMethodDef) - continue; - IfFailRetRcNull(pImport->GetNameAndSigOfMethodDef(tkAttrType, &pSig, &cbSig, &szName_Ignore)); - } - - // Only two signatures are supported: the null sig '()' and the full sig '(Consistency, CER)'. - // Set a boolean based on which one was provided. - bool fNullCtor; - ULONG eCallConv; - - SigPointer sig(pSig, cbSig); - - // Check the calling convention is what we expect (default convention on an instance method). - IfFailRetRcNull(sig.GetCallingConvInfo(&eCallConv)); - _ASSERTE(eCallConv == (IMAGE_CEE_CS_CALLCONV_DEFAULT | IMAGE_CEE_CS_CALLCONV_HASTHIS)); - if (eCallConv != (IMAGE_CEE_CS_CALLCONV_DEFAULT | IMAGE_CEE_CS_CALLCONV_HASTHIS)) - IfFailRetRcNull(COR_E_BADIMAGEFORMAT); - - // If so, the next datum is the count of arguments, and this is all we need to determine which ctor has been used. - ULONG dwArgs; - IfFailRetRcNull(sig.GetData(&dwArgs)); - _ASSERTE(dwArgs == 0 || dwArgs == 2); - if (dwArgs != 0 && dwArgs != 2) - IfFailRetRcNull(COR_E_BADIMAGEFORMAT); - - fNullCtor = dwArgs == 0; - - // Now we know how to parse the blob, let's fetch a pointer to it. - BYTE const *pbData; - DWORD cbData; - IfFailRetRcNull(pImport->GetCustomAttributeAsBlob(tkContract, (const void **)&pbData, &cbData)); - - // Check serialization format (we support version 1 only). - if (cbData < sizeof(WORD) || GET_UNALIGNED_VAL16(pbData) != 1) - IfFailRetRcNull(COR_E_BADIMAGEFORMAT); - pbData += sizeof(WORD); - cbData -= sizeof(WORD); - - // Parse ctor arguments if we have any. - if (!fNullCtor) { - - // We assume the enums are based on DWORDS. - if (cbData < (sizeof(DWORD) * 2)) - IfFailRetRcNull(COR_E_BADIMAGEFORMAT); - - // Consistency first. - DWORD dwConsistency = GET_UNALIGNED_VAL32(pbData); - pbData += sizeof(DWORD); - cbData -= sizeof(DWORD); - if (dwConsistency > RC_CONSISTENCY_CORRUPT_NOTHING) - IfFailRetRcNull(COR_E_BADIMAGEFORMAT); - - // Followed by Cer. - DWORD dwCer = GET_UNALIGNED_VAL32(pbData); - pbData += sizeof(DWORD); - cbData -= sizeof(DWORD); - if (dwCer > RC_CER_SUCCESS) - IfFailRetRcNull(COR_E_BADIMAGEFORMAT); - - dwResult = RC_MERGE(dwResult, RC_ENCODE(dwConsistency, dwCer)); - } - - // Get the count of field/property, value pairs. - if (cbData < sizeof(WORD)) - IfFailRetRcNull(COR_E_BADIMAGEFORMAT); - WORD cPairs = GET_UNALIGNED_VAL16(pbData); - pbData += sizeof(WORD); - cbData -= sizeof(WORD); - - // Iterate over any such pairs, looking for values we haven't picked up yet. - for (DWORD i = 0 ; i < cPairs; i++) { - - // First is a field vs property selector. We expect only properties. - if (cbData < sizeof(BYTE) || *(BYTE*)pbData != SERIALIZATION_TYPE_PROPERTY) - IfFailRetRcNull(COR_E_BADIMAGEFORMAT); - pbData += sizeof(BYTE); - cbData -= sizeof(BYTE); - - // Next is the type of the property. It had better be an enum. - if (cbData < sizeof(BYTE) || *(BYTE*)pbData != SERIALIZATION_TYPE_ENUM) - IfFailRetRcNull(COR_E_BADIMAGEFORMAT); - pbData += sizeof(BYTE); - cbData -= sizeof(BYTE); - - // Next we have the assembly qualified enum type name. This is preceded by a metadata style packed byte length (the - // string itself is 8-bit and not null terminated). Ignore it (just skip across) and we'll key off the property name - // (coming up) instead. - DWORD cbName; - BYTE const * pbPostEncodedLength; - IfFailRetRcNull(CPackedLen::SafeGetData(pbData, cbData, &cbName, &pbPostEncodedLength)); - DWORD cbEncodedLength = static_cast(pbPostEncodedLength - pbData); - pbData += cbEncodedLength + cbName; - cbData -= cbEncodedLength + cbName; - - // Now we have the name of the property (in a similar format to above). - IfFailRetRcNull(CPackedLen::SafeGetData(pbData, cbData, &cbName, &pbPostEncodedLength)); - cbEncodedLength = static_cast(pbPostEncodedLength - pbData); - pbData += cbEncodedLength; - cbData -= cbEncodedLength; - - bool fConsistencyProp = false; - if (cbName == strlen(RC_CONSISTENCY_PROP_NAME) && strncmp((const char*)pbData, RC_CONSISTENCY_PROP_NAME, cbName) == 0) - fConsistencyProp = true; - else if (cbName == strlen(RC_CER_PROP_NAME) && strncmp((const char*)pbData, RC_CER_PROP_NAME, cbName) == 0) - fConsistencyProp = false; - else - IfFailRetRcNull(COR_E_BADIMAGEFORMAT); - pbData += cbName; - cbData -= cbName; - - // And finally the actual enum value (again, we assume the underlying type is a DWORD). - if (cbData < sizeof(DWORD)) - IfFailRetRcNull(COR_E_BADIMAGEFORMAT); - DWORD dwValue = GET_UNALIGNED_VAL32(pbData); - pbData += sizeof(DWORD); - cbData -= sizeof(DWORD); - - if (fConsistencyProp) { - if (dwValue > RC_CONSISTENCY_CORRUPT_NOTHING) - IfFailRetRcNull(COR_E_BADIMAGEFORMAT); - dwResult = RC_MERGE(dwResult, RC_ENCODE(dwValue, RC_CER_UNDEFINED)); - } else { - if (dwValue > RC_CER_SUCCESS) - IfFailRetRcNull(COR_E_BADIMAGEFORMAT); - dwResult = RC_MERGE(dwResult, RC_ENCODE(RC_CONSISTENCY_UNDEFINED, dwValue)); - } - } - - // Shouldn't have any bytes left in the blob at this stage. - _ASSERTE(cbData == 0); - } - - // Return the result encoded and packed into the 2 low order bits of a DWORD. - return dwResult; -} - -// Given a metadata token, a scoping module and a type context, look up the appropriate MethodDesc (and recomputed accompanying type -// context). -MethodContext *TokenToMethodDesc(Module *pModule, mdToken tokMethod, SigTypeContext *pTypeContext) -{ - STANDARD_VM_CONTRACT; - - // Validate that the token is one that we can handle. - if (!pModule->GetMDImport()->IsValidToken(tokMethod) || (TypeFromToken(tokMethod) != mdtMethodDef && - TypeFromToken(tokMethod) != mdtMethodSpec && - TypeFromToken(tokMethod) != mdtMemberRef)) { - COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_METHOD_TOKEN); - } - - // Look up the MethodDesc based on the token and type context. - MethodDesc *pMD = MemberLoader::GetMethodDescFromMemberDefOrRefOrSpec(pModule, - tokMethod, - pTypeContext, - TRUE, - FALSE); - - // The MethodDesc we get might be shared between several types. If so we'll need to do extra work to locate the exact - // class instantiation instead of the default representative one. - SigTypeContext sNewTypeContext; - if (pMD->IsSharedByGenericInstantiations()) { - TypeHandle th = GetTypeFromMemberDefOrRefOrSpecThrowing(pModule, - tokMethod, - pTypeContext); - SigTypeContext::InitTypeContext(pMD, th,&sNewTypeContext); - } else - SigTypeContext::InitTypeContext(pMD, pMD->GetClassInstantiation(), pMD->GetMethodInstantiation(),&sNewTypeContext); - - return MethodContext::PerThreadAllocate(pMD, &sNewTypeContext); -} - -// Locate an exact type definition given a method token and the type context in which it can be resolved. -TypeHandle GetTypeFromMemberDefOrRefOrSpecThrowing(Module *pModule, - mdToken tokMethod, - SigTypeContext *pTypeContext) -{ - STANDARD_VM_CONTRACT; - - IMDInternalImport *pImport = pModule->GetMDImport(); - - // Convert method specs into the underlying member ref. - if (TypeFromToken(tokMethod) == mdtMethodSpec) - { - PCCOR_SIGNATURE pSig; - ULONG cSig; - mdMemberRef tkGenericMemberRef; - - IfFailThrow(pImport->GetMethodSpecProps(tokMethod, &tkGenericMemberRef, &pSig, &cSig)); - - if (!pImport->IsValidToken(tkGenericMemberRef) || - (TypeFromToken(tkGenericMemberRef) != mdtMethodDef && - TypeFromToken(tkGenericMemberRef) != mdtMemberRef)) - { - COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN_TYPE); - } - - tokMethod = tkGenericMemberRef; - } - - // Follow the member ref/def back up to the type def/ref/spec or module (for global methods). - if (TypeFromToken(tokMethod) == mdtMemberRef) - { - IfFailThrow(pImport->GetParentOfMemberRef(tokMethod, &tokMethod)); - - // For varargs, a memberref can point to a methodDef - if (TypeFromToken(tokMethod) == mdtMethodDef) - { - if (!pImport->IsValidToken(tokMethod)) - { - COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN); - } - IfFailThrow(pImport->GetParentToken(tokMethod, &tokMethod)); - } - } - else if (TypeFromToken(tokMethod) == mdtMethodDef) - { - IfFailThrow(pImport->GetParentToken(tokMethod, &tokMethod)); - } - - if (!pImport->IsValidToken(tokMethod) || (TypeFromToken(tokMethod) != mdtTypeDef && - TypeFromToken(tokMethod) != mdtTypeRef && - TypeFromToken(tokMethod) != mdtTypeSpec && - TypeFromToken(tokMethod) != mdtModuleRef)) - { - COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN); - } - - // Load the type in question, using a type context if necessary to get an exact representation. - TypeHandle th; - if (TypeFromToken(tokMethod) == mdtModuleRef) { - DomainFile *pNewModule = pModule->LoadModule(GetAppDomain(), tokMethod, FALSE); - if (pNewModule != NULL) - th = TypeHandle(pNewModule->GetModule()->GetGlobalMethodTable()); - } else { - th = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pModule, - tokMethod, - pTypeContext); - } - - if (th.IsNull()) - COMPlusThrowHR(COR_E_BADIMAGEFORMAT); - - return th; -} - -// Determine whether the method given as a parameter is the root of a CER. -// @todo: Need an x86 offset as well and logic to determine whether we're actually in a root-CER portion of the method (if the whole -// thing isn't the root). -bool IsCerRootMethod(MethodDesc *pMD) -{ - CONTRACTL { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(CheckPointer(pMD)); - SO_TOLERANT; - } CONTRACTL_END; - - // Treat IL stubs as CER roots (marshaling code needs to string together operations without being interruped by thread aborts). - if (pMD->IsILStub()) - return true; - - // There are some well defined root methods defined by the system. - if (pMD == g_pExecuteBackoutCodeHelperMethod) - return true; - - // For now we just look to see whether there is some prep or fixup info stored for this method. - Module *pModule = pMD->GetModule(); - - if (pModule->GetCerPrepInfo(pMD) != NULL) - return true; - -#ifdef FEATURE_PREJIT - if (pModule->IsNgenCerRootMethod(pMD)) - return true; -#endif - - return false; -} - -// Fill the cache of overflowed generic dictionary entries that the jit maintains with all the overflow slots stored so far in the -// dictionary layout. -void PrepopulateGenericHandleCache(DictionaryLayout *pDictionaryLayout, - MethodDesc *pMD, - MethodTable *pMT) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - // Dictionary overflow entries are recorded starting in the second bucket of the dictionary layout. - DictionaryLayout *pOverflows = pDictionaryLayout->GetNextLayout(); - - while (pOverflows) { - for (DWORD i = 0; i < pOverflows->GetMaxSlots(); i++) { - DictionaryEntryLayout *pEntry = pOverflows->GetEntryLayout(i); - - // We've finished as soon as we find the first unused slot. - if (!pEntry->m_signature) - return; - - // We have a valid overflow entry. Determine the handle value given the type context we have and push it into the JIT's - // cache. - JIT_GenericHandleWorker(pMD, pMT, pEntry->m_signature); - } - pOverflows = pOverflows->GetNextLayout(); - } -} - -#ifdef FEATURE_PREJIT - -// Prepare the CER rooted at the given method (it's OK to pass a MethodDesc* that doesn't root a CER, in which case the method -// is a no-op). -void CerNgenRootTable::Restore(MethodDesc *pRootMD) -{ -#ifndef CROSSGEN_COMPILE - STANDARD_VM_CONTRACT; - - // We don't have a restoration bitmap at ngen time. No matter, we just always claim everything is restored. - if (m_pRestoreBitmap == NULL) - return; - - // Locate the root index from the table. Failure indicates there's no work to do. - DWORD dwIndex = FindIndex(pRootMD); - if (dwIndex == NoSuchRoot) - return; - - _ASSERTE(m_pRoots[dwIndex].m_pRootMD == pRootMD); - - // Check then mark the fact that we're preparing (to prevent potential recursion). - SigTypeContext typeContext; - if (!GetThread()->GetCerPreparationState()->CanPreparationProceed(pRootMD, &typeContext)) - return; - - MethodCallGraphPreparer sPrep(pRootMD, &typeContext, true, true); - MethodCallGraphPreparer::ThreadPreparingCerHolder sCerHolder(&sPrep); - -#ifdef _DEBUG - if (GetCerLoggingOptions()) - { - CER_LOG(RESTORE, ("---------------------------------------------------------------\n")); - SString ssRootMethod; - TypeString::AppendMethodInternal(ssRootMethod, pRootMD, TypeString::FormatNamespace | TypeString::FormatStubInfo); - CER_LOG(RESTORE, ("Restoring CER graph from %S\n", ssRootMethod.GetUnicode())); - } -#endif - - g_IBCLogger.LogCerMethodListReadAccess(pRootMD); - - // Retrieve the CerRoot structure. - CerRoot *pRoot = &m_pRoots[dwIndex]; - _ASSERTE(pRoot->m_pRootMD == pRootMD); - - // Scan the list of methods in the CER (the last one is a sentinel with a NULL MethodDesc*). Restore each method as we go. - MethodContextElement *pEntry = pRoot->m_pList; - while (pEntry->GetMethodDesc()) - { - // Method desc and type handle pointers may still be tokenized at this point. - Module::RestoreMethodDescPointer(&pEntry->m_pMethodDesc); - Module::RestoreMethodTablePointer(&pEntry->m_pExactMT); - - g_IBCLogger.LogCerMethodListReadAccess(pEntry->GetMethodDesc()); - - MethodDesc * pMD = pEntry->GetMethodDesc(); - - // Check whether there are generic dictionaries that need to be pre-populated. - - // Don't use the direct PrepopulateDictionary method here for MethodTable/MethodDesc - // - MethodTable: Takes binding considerations into account (which we don't care about) - // - MethodDesc: Appears to use a representative class instantiation (and we have the exact one handy) - // - // Additionally, avoid touching EE Class if we don't need to - MethodTable * pMT = pEntry->GetExactMT(); - if (pMT != NULL) - { - // MethodTable - DictionaryLayout *pClassDictLayout = pMT->GetClass()->GetDictionaryLayout(); - if (pClassDictLayout) - { - pMT->GetDictionary()->PrepopulateDictionary(NULL, pMT, false); - - // The dictionary may have overflowed in which case we need to prepopulate the jit's lookup cache as well. - PrepopulateGenericHandleCache(pClassDictLayout, NULL, pMT); - } - - // MethodDesc - DictionaryLayout *pMethDictLayout = pMD->GetDictionaryLayout(); - if (pMethDictLayout) - { - pMD->GetMethodDictionary()->PrepopulateDictionary(pMD, NULL, false); - - // The dictionary may have overflowed in which case we need to prepopulate the jit's lookup cache as well. - PrepopulateGenericHandleCache(pMethDictLayout, pMD, NULL); - } - } - - // Recreate stubs used by P/Invoke, COM calls, or FCalls by exercising the prestub. - if (pMD->IsPointingToPrestub() && (pMD->IsNDirect() || pMD->IsComPlusCall() || pMD->IsFCall())) - { - pMD->EnsureActive(); - pMD->DoPrestub(NULL); - } - -#ifdef _DEBUG - if (GetCerLoggingOptions()) - { - SString ssMethod; - TypeString::AppendMethodInternal(ssMethod, pMD, TypeString::FormatNamespace | TypeString::FormatStubInfo); - CER_LOG(RESTORE, (" %S\n", ssMethod.GetUnicode())); - } -#endif - - // Move to next entry. - pEntry++; - } - - CER_LOG(RESTORE, ("---------------------------------------------------------------\n")); - - // Mark this whole CER region as fixed up by setting a flag in the restore bitmap (kept separate so we can cluster all our page - // writes). - // Compute the DWORD offset into the flag array and then the mask for the specific bit in that DWORD. - DWORD dwOffset = dwIndex / (sizeof(DWORD) * 8); - DWORD dwMask = 1 << (dwIndex % (sizeof(DWORD) * 8)); - EnsureWritablePages(m_pRestoreBitmap, sizeof(DWORD) * SizeOfRestoreBitmap()); - FastInterlockOr(&m_pRestoreBitmap[dwOffset], dwMask); - - // If we fixed up any methods with their own CERs then we will have implicitly fixed up those too. Mark their fixup records as - // completed as well to avoid further unecessary work. - pEntry = pRoot->m_pList; - while (pEntry->GetMethodDesc()) { - dwIndex = FindIndex(pEntry->GetMethodDesc()); - if (dwIndex != NoSuchRoot) { - dwOffset = dwIndex / (sizeof(DWORD) * 8); - dwMask = 1 << (dwIndex % (sizeof(DWORD) * 8)); - FastInterlockOr(&m_pRestoreBitmap[dwOffset], dwMask); - } - pEntry++; - } -#endif // CROSSGEN_COMPILE -} - -#ifdef FEATURE_NATIVE_IMAGE_GENERATION -// Add a new root to the table, expanding it as necessary. Note that this method must be called with the CerCrst already held. -void CerNgenRootTable::AddRoot(MethodDesc *pRootMD, MethodContextElement *pList) -{ - CONTRACTL { - STANDARD_VM_CHECK; - PRECONDITION(IsOwnerOfCrst(pRootMD->GetModule()->GetCerCrst())); - } CONTRACTL_END; - - // Ensure we have enough space first. - if (m_cRoots == m_cSlots) { - DWORD cNewSize = m_cSlots + 16; - CerRoot *pNewArray = new CerRoot[cNewSize]; - memcpyNoGCRefs(pNewArray, m_pRoots, m_cRoots * sizeof(CerRoot)); - MethodContextElement **pNewRootsInCompilationOrder = new MethodContextElement*[cNewSize]; - memcpyNoGCRefs(pNewRootsInCompilationOrder, m_pRootsInCompilationOrder, m_cRoots * sizeof(MethodContextElement*) ); - m_cSlots = cNewSize; - delete m_pRoots; - m_pRoots = pNewArray; - delete m_pRootsInCompilationOrder; - m_pRootsInCompilationOrder = pNewRootsInCompilationOrder; - } - - // Fill in the new entry in sorted order. - DWORD i; - for (i = 0; i < m_cRoots; i++) - if ((UPTR) m_pRoots[i].m_pRootMD > (UPTR) pRootMD) - break; - if (i < m_cRoots) - memmove(&m_pRoots[i + 1], &m_pRoots[i], (m_cRoots - i) * sizeof(CerRoot)); - m_pRoots[i].m_pRootMD = pRootMD; - m_pRoots[i].m_pList = pList; - - m_pRootsInCompilationOrder[m_cRoots] = pList; - - m_cRoots++; -} - -// Ngen callouts to help serialize this structure and its children to storage. -void CerNgenRootTable::Save(DataImage *image, CorProfileData *profileData) -{ - STANDARD_VM_CONTRACT; - -#ifdef _DEBUG - DWORD dwMaxEntries = 0; - DWORD dwTotalEntries = 0; -#endif - - image->StoreStructure(this, sizeof(CerNgenRootTable), DataImage::ITEM_CER_ROOT_TABLE); - image->StoreStructure(m_pRoots, m_cRoots * sizeof(CerRoot), DataImage::ITEM_CER_ROOT_TABLE); - - // Create a bitmap of boolean flags (1 bit per flag) indicating whether the CER at a given index in the array has been restored. - // This is initially all zero and only filled in at runtime (keep all the flags together this way because they're the only - // things we have to write at runtime and we want to keep them as dense as possible). - _ASSERTE((SizeOfRestoreBitmap() % sizeof(DWORD)) == 0); - m_pRestoreBitmap = new DWORD[SizeOfRestoreBitmap() / sizeof(DWORD)]; - memset(m_pRestoreBitmap, 0xff, SizeOfRestoreBitmap()); - - image->StoreStructure(m_pRestoreBitmap, - SizeOfRestoreBitmap(), - DataImage::ITEM_CER_RESTORE_FLAGS); - - // Next save off the list of MethodContextElements associated with each root. - for (DWORD i = 0; i < m_cRoots; i++) { - MethodContextElement *pEntry = m_pRootsInCompilationOrder[i]; - - // Count entries in list. - DWORD cEntries = 0; - while (pEntry->GetMethodDesc()) { - cEntries++; - pEntry++; - } - - // Plus one for the sentinel value. - cEntries++; - -#ifdef _DEBUG - dwTotalEntries += cEntries; - if (cEntries > dwMaxEntries) - dwMaxEntries = cEntries; -#endif - - // Store this list. - image->StoreStructure(m_pRootsInCompilationOrder[i], - cEntries * sizeof(MethodContextElement), - DataImage::ITEM_CER_METHOD_LIST); - } - -#ifdef _DEBUG - if (m_cRoots > 0) { - CER_LOG(NGEN_STATS, ("Saving %u CER roots in ngen image\n", m_cRoots)); - CER_LOG(NGEN_STATS, (" Max methods in CER: %u\n", dwMaxEntries)); - CER_LOG(NGEN_STATS, (" Avg methods in CER: %.1f\n", (float)((float)dwTotalEntries / (float)m_cRoots))); - } else - CER_LOG(NGEN_STATS, ("No CER roots in ngen image\n")); -#endif -} - -void CerNgenRootTable::Fixup(DataImage *image) -{ - STANDARD_VM_CONTRACT; - - DWORD i; - - // We still use the point to the root array even though at runtime the two structures will be adjacent. - image->FixupPointerField(this, offsetof(CerNgenRootTable, m_pRoots)); - - // Restoration flags are used only at runtime and must start off zeroed. - image->FixupPointerField(this, offsetof(CerNgenRootTable, m_pRestoreBitmap)); - image->ZeroField(m_pRestoreBitmap, 0, SizeOfRestoreBitmap()); - - // The root list in compilation order is only used at ngen time, and is not written into native image. - image->ZeroPointerField(this, offsetof(CerNgenRootTable, m_pRootsInCompilationOrder)); - - // Fixup all the pointers in the individual CERs. - for (i = 0; i < m_cRoots; i++) { - - // For each MethodContextElement in the list we need to fixup a pointer to a MethodDesc and two array pointers (one for any - // class instantiation and one for any method instantiation). The actual MethodDescs and TypeHandles themselves are already - // fixed up as are the instantiation arrays we point to (they're the ones inside the generic dictionaries of the class/method - // concerned). - MethodContextElement *pList = m_pRootsInCompilationOrder[i]; - MethodContextElement *pEntry = pList; - while (pEntry->GetMethodDesc()) { - image->FixupMethodDescPointer(pList, &pEntry->m_pMethodDesc); - image->FixupMethodTablePointer(pList, &pEntry->m_pExactMT); - pEntry++; - } - } -} - -void CerNgenRootTable::FixupRVAs(DataImage *image) -{ - STANDARD_VM_CONTRACT; - - DWORD i, j; - - // Now we go back through the root table and sort the entries based on the locations of the root method descs in the new image - // (they may be rearranged due to IBC profiling). - CerRoot *pNewRoots = (CerRoot*)image->GetImagePointer(m_pRoots); - PREFIX_ASSUME(pNewRoots != NULL); - - // Simple insertion sort. Starting at the second element insert a candidate into its correct location in the sub-list - // preceding it (which by definition will already be sorted). - for (i = 1; i < m_cRoots; i++) - { - // Look at all of the preceding elements for the first that is larger than the candidate (i.e. should succeed the - // candidate in sorted order). If we don't find one then the candidate is already in place and we can proceed to the - // next candidate. - for (j = 0; j < i; j++) - if (image->GetRVA(pNewRoots[j].m_pRootMD) > image->GetRVA(pNewRoots[i].m_pRootMD)) { - - // Need to move candidate element up. Cache its value because we're about to overwrite it. - MethodDesc *pTmpRootMD = pNewRoots[i].m_pRootMD; - MethodContextElement *pTmpList = pNewRoots[i].m_pList; - - // Shuffle the sorted list one up to make room for the candidate. - memmove(&pNewRoots[j + 1], &pNewRoots[j], (i - j) * sizeof(CerRoot)); - - // Insert the candidate into position. - pNewRoots[j].m_pRootMD = pTmpRootMD; - pNewRoots[j].m_pList = pTmpList; - - // Sorted the candidate, move onto the next. - break; - } - } - - // Fixup all the pointers in the individual CERs. - for (i = 0; i < m_cRoots; i++) { - // Fix up the pointer to the root method and the list of methods in the CER. - image->FixupField(m_pRoots, sizeof(CerRoot) * i + offsetof(CerRoot, m_pRootMD), - pNewRoots[i].m_pRootMD); - image->FixupField(m_pRoots, sizeof(CerRoot) * i + offsetof(CerRoot, m_pList), - pNewRoots[i].m_pList); - } -} -#endif // FEATURE_NATIVE_IMAGE_GENERATION - -// Locate the index of a given CerRoot record in the array given the root method. This is used to access the array and to locate the -// restored flag for the entry in the restored bitmap. NoSuchRoot is returned if the root cannot be found. -DWORD CerNgenRootTable::FindIndex(MethodDesc *pRootMD) -{ - CONTRACTL { - NOTHROW; - MODE_ANY; - GC_NOTRIGGER; - PRECONDITION(CheckPointer(pRootMD)); - SO_TOLERANT; - } CONTRACTL_END; - - // The table is guaranteed to be sorted, so we can lookup our target with a binary search. - DWORD dwLow = 0; - DWORD dwHigh = m_cRoots - 1; - while (true) { - - // Take out the simple cases first. - - // The range has only one entry. - if (dwLow == dwHigh) { - if (m_pRoots[dwLow].m_pRootMD == pRootMD) - return dwLow; -#ifdef _DEBUG - for (DWORD i = 0; i < m_cRoots; i++) - _ASSERTE(m_pRoots[i].m_pRootMD != pRootMD); -#endif - return NoSuchRoot; - } - - // The range has only two entries. - if (dwLow == dwHigh - 1) { - if (m_pRoots[dwLow].m_pRootMD == pRootMD) - return dwLow; - if (m_pRoots[dwHigh].m_pRootMD == pRootMD) - return dwHigh; -#ifdef _DEBUG - for (DWORD i = 0; i < m_cRoots; i++) - _ASSERTE(m_pRoots[i].m_pRootMD != pRootMD); -#endif - return NoSuchRoot; - } - - // Now we can compute a midpoint that is definitely distinct and in-between the endpoints. - DWORD dwMid = dwLow + ((dwHigh - dwLow) / 2); - - // Did we nail it? - if (m_pRoots[dwMid].m_pRootMD == pRootMD) - return dwMid; - - // Otherwise adjust our range to be the bit we haven't looked at and iterate. - if ((UPTR)m_pRoots[dwMid].m_pRootMD < (UPTR)pRootMD) - dwLow = dwMid + 1; - else - dwHigh = dwMid - 1; - } -} - -// Prepare the class if it is derived from CriticalFinalizerObject. This is used at ngen time since such classes are normally -// prepared at runtime (at instantiation) and would therefore miss the ngen image. -void PrepareCriticalType(MethodTable * pMT) -{ - STANDARD_VM_CONTRACT; - - // Prepare any class that satisfies the criteria. Pass a pointer to this module so that we'll only prepare any overrides of - // the critical methods that were actually introduced here. - if (pMT->HasCriticalFinalizer()) - PrepareCriticalFinalizerObject(pMT, pMT->GetLoaderModule()); -} - -// Prepare a method and its statically determinable call graph if a hint attribute has been applied. This is only called at ngen -// time to save additional preparation information into the ngen image that wouldn't normally be there (and thus lower runtime -// overheads). -void PrePrepareMethodIfNecessary(CORINFO_METHOD_HANDLE hMethod) -{ - STANDARD_VM_CONTRACT; - - EX_TRY { - - // Translate jit-style method handle into method desc. - MethodDesc *pMD = GetMethod(hMethod); - - // Check for the existance of the attribute. - IMDInternalImport *pImport = pMD->GetMDImport(); - mdToken tkMethod = pMD->GetMemberDef(); - HRESULT hr = pImport->GetCustomAttributeByName(tkMethod, - "System.Runtime.ConstrainedExecution.PrePrepareMethodAttribute", - NULL, NULL); - - // TODO: We should add IBC probes which indicate that methods need to be preprepared - // which can then be reflected in the IBC data, we can add an additional check - // here to cover that case, then we can get around this problem with profiling - // instead of manual programmer effort. - - // Only prepare if we definitely saw the attribute. - if (hr == S_OK) { - // Prepare the method and its graph. There should never be any open type parameters (we can't do much at ngen time with these), - // so we can pass a null type context. - SigTypeContext sTypeContext; - MethodCallGraphPreparer mcgp(pMD, &sTypeContext, true, true); - mcgp.Run(); - } - - } EX_CATCH { - } EX_END_CATCH(SwallowAllExceptions); -} - -#endif // FEATURE_PREJIT - -PtrHashCache::PtrHashCache() -{ - LIMITED_METHOD_CONTRACT; - ZeroMemory(this, sizeof(*this)); - - // First entry in each bucket is a chain index used to evenly distribute inserts within a bucket. - _ASSERTE(PHC_CHAIN > 1); -} - -bool PtrHashCache::Lookup(void *pKey, DWORD *pdwValue) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(((UINT_PTR)pKey & PHC_DATA_MASK) == 0); - - DWORD dwBucket = GetHash(pKey); - - // Skip first entry in bucket, it's a sequence number used for insertions. - for (DWORD i = 1; i < PHC_CHAIN; i++) { - UINT_PTR uipEntry = VolatileLoad(&m_rEntries[(dwBucket * PHC_CHAIN) + i]); - if ((uipEntry & ~PHC_DATA_MASK) == (UINT_PTR)pKey) { -#ifdef _DEBUG - FastInterlockIncrement((LONG*)&m_dwHits); -#endif - *pdwValue = uipEntry & PHC_DATA_MASK; - return true; - } - } - -#ifdef _DEBUG - FastInterlockIncrement((LONG*)&m_dwMisses); -#endif - return false; -} - -void PtrHashCache::Add(void *pKey, DWORD dwValue) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(((UINT_PTR)pKey & PHC_DATA_MASK) == 0); - _ASSERTE((dwValue & ~PHC_DATA_MASK) == 0); - - DWORD dwBucket = GetHash(pKey); - - // We keep a sequence number in the first entry of the bucket so that we distribute insertions within the bucket evenly. We're - // racing when we update this value, but it doesn't matter if we lose an update (we're a cache after all). We don't bother being - // careful to avoid overflowing the value here (we just keep incrementing); we'll do the modulo logic when we insert our value - // instead. - DWORD dwIndex = static_cast(m_rEntries[dwBucket * PHC_CHAIN]++); - dwIndex = (dwIndex % (PHC_CHAIN - 1)) + 1; - m_rEntries[(dwBucket * PHC_CHAIN) + dwIndex] = ((UINT_PTR)pKey & ~PHC_DATA_MASK) | dwValue; -} - -DWORD PtrHashCache::GetHash(void *pKey) -{ - LIMITED_METHOD_CONTRACT; - - return (DWORD)(((UINT_PTR)pKey >> 4) % PHC_BUCKETS); -} - -#ifdef _DEBUG -void PtrHashCache::DbgDumpStats() -{ -#if 0 - if ((m_dwHits + m_dwMisses) == 0) - return; - - printf("Dumping stats for PtrHashCache %08X\n", this); - printf(" %u hits, %u misses (%u%% hit rate)\n", m_dwHits, m_dwMisses, (m_dwHits * 100) / (m_dwHits + m_dwMisses)); - for (DWORD i = 0; i < PHC_BUCKETS; i++) - printf(" [%2u] : %u insertions\n", i, m_rEntries[i * PHC_CHAIN]); - printf("\n"); -#endif -} -#endif -- cgit v1.2.3 From 41a53ba525c708b229d1c545249bf95c40c10a38 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Sun, 12 Feb 2017 20:51:31 -0800 Subject: Remove dead crossdomaincalls.cpp --- src/debug/daccess/nidump.cpp | 4 +- src/vm/crossdomaincalls.cpp | 2587 ------------------------------------------ 2 files changed, 1 insertion(+), 2590 deletions(-) delete mode 100644 src/vm/crossdomaincalls.cpp diff --git a/src/debug/daccess/nidump.cpp b/src/debug/daccess/nidump.cpp index 2b46da2fe0..c300e6fa01 100644 --- a/src/debug/daccess/nidump.cpp +++ b/src/debug/daccess/nidump.cpp @@ -7519,9 +7519,7 @@ NativeImageDumper::DumpMethodTable( PTR_MethodTable mt, const char * name, else { _ASSERTE(mt->GetNumVtableSlots() > 0 ); - /* REVISIT_TODO Tue 12/13/2005 - * One liner copied from CrossDomainCalls.cpp - */ + unsigned size = sizeof(RemotableMethodInfo) * mt->GetNumVtableSlots(); //one remotable method info for each method. m_display->StartStructureWithOffset( "OptionalMember_RemotableMethodInfo", diff --git a/src/vm/crossdomaincalls.cpp b/src/vm/crossdomaincalls.cpp deleted file mode 100644 index b528915a54..0000000000 --- a/src/vm/crossdomaincalls.cpp +++ /dev/null @@ -1,2587 +0,0 @@ -// 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. -// -// File: CrossDomainCalls.cpp -// - -// -// The CrossDomainCall class provides a fast path of execution for qualifying -// cross domain calls. Asynch calls, one way calls, calls on context bound objects -// etc dont qualify. -// - - -#include "common.h" - -#ifdef FEATURE_REMOTING - -#include "crossdomaincalls.h" -#include "callhelpers.h" -#include "remoting.h" -#include "objectclone.h" -#include "dbginterface.h" -#include "stackprobe.h" -#include "virtualcallstub.h" -#include "typeparse.h" -#include "typestring.h" -#include "appdomain.inl" -#include "callingconvention.h" - -// See explanation of flags in crossdomaincalls.h -RemotableMethodInfo::XADOptimizationType -RemotableMethodInfo::IsCrossAppDomainOptimizable(MethodDesc *pMeth, DWORD *pNumStackSlotsToCopy) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; - - // This method table might be representative, but that's OK for the kinds of analysis we're about to do. - MethodTable *pMT = pMeth->GetMethodTable()->GetCanonicalMethodTable(); - - _ASSERTE(pMT->HasRemotableMethodInfo()); - _ASSERTE(pMT->GetRemotableMethodInfo()); - - if (pMT->IsContextful()) - return XAD_NOT_OPTIMIZABLE; - - DWORD flags; - - // If this method is generic then we can't used cached analysis data stored on the method table and keyed by slot -- the same - // slot is shared by methods with very different characteristics (such as whether the return type is a GC ref etc.). - if (pMeth->GetNumGenericMethodArgs() > 0) - { - flags = DoStaticAnalysis(pMeth); - } - else - { - _ASSERTE(pMeth->GetSlot() < pMeth->GetMethodTable()->GetNumVtableSlots()); - RemotableMethodInfo *pRMI = &(pMT->GetRemotableMethodInfo()->GetRemotableMethodInfo()[pMeth->GetSlot()]); - flags = pRMI->m_OptFlags; - - if (!(flags & XAD_FLAGS_INITIALIZED)) - { - flags = DoStaticAnalysis(pMeth); - pRMI->m_OptFlags = flags; - } - } - - *pNumStackSlotsToCopy = flags & XAD_ARG_COUNT_MASK; - - return (XADOptimizationType) (flags & XAD_FLAG_MASK); -} - -// This method is not synchronized because the operation is idempotent -DWORD -RemotableMethodInfo::DoStaticAnalysis(MethodDesc *pMeth) -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - PRECONDITION(CheckPointer(pMeth)); - } - CONTRACTL_END - - BOOL bCallArgsBlittable = TRUE; - BOOL bRetArgBlittable = TRUE; - BOOL bOptimizable = TRUE; - BOOL bMethodIsVirtual = FALSE; - BOOL bArgsHaveAFloat = FALSE; - - DWORD numStackBytes = 0; - DWORD numStackSlots = 0; - DWORD returnTypeFlags = 0; - - if (pMeth->ContainsGenericVariables()) - { - bOptimizable = FALSE; - } - else - { - MetaSig mSig(pMeth); - ArgIterator argit(&mSig); - - SigPointer spRet; - CorElementType retElem; - - IMDInternalImport *pMDImport = pMeth->GetModule()->GetMDImport(); - MDEnumHolder ePm(pMDImport); // For enumerating params. - mdParamDef tkPm; // A param token. - DWORD dwFlags; // Param flags. - USHORT usSeq; // Sequence of a parameter. - - if (pMeth->IsOneWay()) - { - bOptimizable = FALSE; - goto SetFlags; - } - - if (pMeth->IsVirtual()) - { - bMethodIsVirtual = TRUE; - } - - numStackBytes = argit.SizeOfFrameArgumentArray(); - - _ASSERTE(numStackBytes % sizeof(SIZE_T) == 0); - numStackSlots = numStackBytes / sizeof(SIZE_T); - - if (numStackSlots > XAD_ARG_COUNT_MASK) - { - bOptimizable = FALSE; - goto SetFlags; - } - - // Check if there are any [Out] args. If there are, skip the fast path - IfFailThrow(pMDImport->EnumInit(mdtParamDef, pMeth->GetMemberDef(), &ePm)); - - // Enumerate through the params and check the flags. - while (pMDImport->EnumNext(&ePm, &tkPm)) - { - LPCSTR szParamName_Ignore; - IfFailThrow(pMDImport->GetParamDefProps(tkPm, &usSeq, &dwFlags, &szParamName_Ignore)); - if (usSeq == 0) // Skip return type flags. - continue; - // If the param has Out attribute, do not use fast path for this method - if (IsPdOut(dwFlags)) - { - bOptimizable = FALSE; - goto SetFlags; - } - } - - // We're getting SigPointer first because this way we can differentiate E_T_STRING and E_T_CLASS - spRet = mSig.GetReturnProps(); - IfFailThrow(spRet.GetElemType(&retElem)); - if (retElem > ELEMENT_TYPE_PTR && - retElem != ELEMENT_TYPE_I && - retElem != ELEMENT_TYPE_U && - retElem != ELEMENT_TYPE_FNPTR) - { - bRetArgBlittable = FALSE; - } - - // Now we can normalize the return type so as to get rid of any generic type variables and the like. - retElem = mSig.GetReturnType(); - - if (retElem == ELEMENT_TYPE_VALUETYPE) - { - // Make a note that we have a struct in the signature. This way we wont blit the contents - // and end up in a situation where we have data, but the type isnt loaded yet - bCallArgsBlittable = FALSE; - - // Do some further inspection - TypeHandle retTypeHandle = mSig.GetRetTypeHandleThrowing(); - - // Currently we don't handle the special unbox handling for ret values of Nullable in MarshalAndCall - if (Nullable::IsNullableType(retTypeHandle)) - { - bOptimizable = FALSE; - } - - retElem = retTypeHandle.GetInternalCorElementType(); - if ((retElem <= ELEMENT_TYPE_PTR || retElem == ELEMENT_TYPE_I || retElem == ELEMENT_TYPE_U) && - !retTypeHandle.AsMethodTable()->CannotBeBlittedByObjectCloner()) - bRetArgBlittable = TRUE; - } - - // Check if the return type is a GC ref - if (gElementTypeInfo[retElem].m_gc == TYPE_GC_REF) - { - returnTypeFlags = XAD_RET_GC_REF; - } - else - { - returnTypeFlags = GetRetTypeFlagsFromFPReturnSize(argit.GetFPReturnSize()); - } - - CorElementType currType; - while ((currType = mSig.NextArg()) != ELEMENT_TYPE_END) - { - SigPointer sp = mSig.GetArgProps(); - CorElementType retTy; - IfFailThrow(sp.GetElemType(&retTy)); - if (retTy > ELEMENT_TYPE_PTR && - retTy != ELEMENT_TYPE_VALUETYPE && - retTy != ELEMENT_TYPE_I && - retTy != ELEMENT_TYPE_U && - retTy != ELEMENT_TYPE_FNPTR) - { - bCallArgsBlittable = FALSE; - } - - // Currently we don't handle the special unbox handling for Nullable for byrefs in MarshalAndCall - if (currType == ELEMENT_TYPE_BYREF) - { - TypeHandle refType; - if (mSig.GetByRefType(&refType) == ELEMENT_TYPE_VALUETYPE) - if (Nullable::IsNullableType(refType)) - { - bOptimizable = FALSE; - } - } - else if (currType == ELEMENT_TYPE_VALUETYPE) - { -#if ENREGISTERED_PARAMTYPE_MAXSIZE - // Since we also do implict ByRef in some cases, we also have to probit the optimization there too - TypeHandle argType = mSig.GetLastTypeHandleThrowing(); - if (Nullable::IsNullableType(argType)) - { - if (ArgIterator::IsArgPassedByRef(argType)) - bOptimizable = FALSE; - } -#endif - bCallArgsBlittable = FALSE; - } - else if (currType == ELEMENT_TYPE_R4 || currType == ELEMENT_TYPE_R8) - { - bArgsHaveAFloat = TRUE; - } - } - } - -SetFlags: - DWORD optimizationFlags = 0; - if (!bOptimizable) - { - optimizationFlags |= XAD_NOT_OPTIMIZABLE; - } - else - { - optimizationFlags |= returnTypeFlags; - - if (bCallArgsBlittable) - { - optimizationFlags |= XAD_BLITTABLE_ARGS; - } - if (bRetArgBlittable) - { - optimizationFlags |= XAD_BLITTABLE_RET; - } - if (bMethodIsVirtual) - { - optimizationFlags |= XAD_METHOD_IS_VIRTUAL; - } - if (bArgsHaveAFloat) - { - optimizationFlags |= XAD_ARGS_HAVE_A_FLOAT; - } - } - optimizationFlags |= numStackSlots; - optimizationFlags |= XAD_FLAGS_INITIALIZED; - - return optimizationFlags; -} - -#ifndef CROSSGEN_COMPILE - -BOOL RemotableMethodInfo::TypeIsConduciveToBlitting(MethodTable *pFromMT, MethodTable *pToMT) -{ - LIMITED_METHOD_CONTRACT; - // Presence of GC fields or certain atributes, rules out blittability - if (pFromMT->CannotBeBlittedByObjectCloner() || - pToMT->CannotBeBlittedByObjectCloner()) - return FALSE; - - // Shared types are okay to blit - if (pFromMT == pToMT) - return TRUE; - - if (pFromMT->IsEnum() && pToMT->IsEnum() - && pFromMT->GetBaseSize() == pToMT->GetBaseSize()) - return TRUE; - - return FALSE; -} - -PtrHashMap *CrossDomainTypeMap::s_crossDomainMTMap = NULL; -SimpleRWLock *CrossDomainTypeMap::s_MTMapLock = NULL; - -BOOL CrossDomainTypeMap::CompareMTMapEntry (UPTR val1, UPTR val2) -{ - CONTRACTL { - MODE_ANY; - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; - } - CONTRACTL_END; - - CrossDomainTypeMap::MTMapEntry *entry1 = (CrossDomainTypeMap::MTMapEntry *)(val1 << 1); - CrossDomainTypeMap::MTMapEntry *entry2 = (CrossDomainTypeMap::MTMapEntry *)val2; - - if (entry1->m_pFromMT == entry2->m_pFromMT && - entry1->m_dwFromDomain == entry2->m_dwFromDomain && - entry1->m_dwToDomain == entry2->m_dwToDomain) - return TRUE; - - return FALSE; -} - -CrossDomainTypeMap::MTMapEntry::MTMapEntry(AppDomain *pFromDomain, MethodTable *pFromMT, AppDomain *pToDomain, MethodTable *pToMT) -{ - WRAPPER_NO_CONTRACT; - - m_dwFromDomain = pFromDomain->GetId(); - m_dwToDomain = pToDomain->GetId(); - m_pFromMT = pFromMT; - m_pToMT = pToMT; -} - -static BOOL IsOwnerOfRWLock(LPVOID lock) -{ - // @TODO - SimpleRWLock does not have knowledge of which thread gets the writer - // lock, so no way to verify - return TRUE; -} - -/*static*/ -PtrHashMap *CrossDomainTypeMap::GetTypeMap() -{ - CONTRACTL - { - GC_NOTRIGGER; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END - - if (s_MTMapLock == NULL) - { - void *tempLockSpace = SystemDomain::GetGlobalLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(SimpleRWLock))); - SimpleRWLock *tempLock = new (tempLockSpace) SimpleRWLock(COOPERATIVE_OR_PREEMPTIVE, LOCK_TYPE_DEFAULT); - - if (FastInterlockCompareExchangePointer(&s_MTMapLock, - tempLock, - NULL) != NULL) - { - // We lost the race - SystemDomain::GetGlobalLoaderAllocator()->GetLowFrequencyHeap()->BackoutMem(tempLockSpace, sizeof(SimpleRWLock)); - } - } - - // Now we have a Crst we can use to synchronize the remainder of the init. - if (s_crossDomainMTMap == NULL) - { - SimpleWriteLockHolder swlh(s_MTMapLock); - - if (s_crossDomainMTMap == NULL) - { - PtrHashMap *map = new (SystemDomain::GetGlobalLoaderAllocator()->GetLowFrequencyHeap()) PtrHashMap (); - LockOwner lock = {s_MTMapLock, IsOwnerOfRWLock}; - map->Init (32, CompareMTMapEntry, TRUE, &lock); - s_crossDomainMTMap = map; - } - } - - return s_crossDomainMTMap; -} - -MethodTable * -CrossDomainTypeMap::GetMethodTableForDomain(MethodTable *pMT, AppDomain *pFromDomain, AppDomain *pToDomain) -{ - CONTRACTL - { - GC_NOTRIGGER; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END - PtrHashMap *map = GetTypeMap(); - - MTMapEntry admt(pFromDomain, pMT, pToDomain, NULL); - - SimpleReadLockHolder srlh(s_MTMapLock); - MTMapEntry *pFound = (MTMapEntry *) map->LookupValue(admt.GetHash(), (LPVOID) &admt); - if ((MTMapEntry *)INVALIDENTRY == pFound) - return NULL; - - return pFound->m_pToMT; -} - -void -CrossDomainTypeMap::SetMethodTableForDomain(MethodTable *pFromMT, AppDomain *pFromDomain, MethodTable *pToMT, AppDomain *pToDomain) -{ - CONTRACTL - { - GC_NOTRIGGER; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END - PtrHashMap *map = GetTypeMap(); - - NewHolder admt(new MTMapEntry(pFromDomain, pFromMT, pToDomain, pToMT)); - PREFIX_ASSUME(admt != NULL); - - SimpleWriteLockHolder swlh(s_MTMapLock); - - UPTR key = admt->GetHash(); - - MTMapEntry *pFound = (MTMapEntry *) map->LookupValue(key, (LPVOID) admt); - if ((MTMapEntry *)INVALIDENTRY == pFound) - { - map->InsertValue(key, (LPVOID) admt); - admt.SuppressRelease(); - } -} - -// Remove any entries in the table that refer to an appdomain that is no longer live. -void CrossDomainTypeMap::FlushStaleEntries() -{ - CONTRACTL - { - GC_NOTRIGGER; - MODE_COOPERATIVE; - NOTHROW; - } - CONTRACTL_END - - if (s_MTMapLock == NULL || s_crossDomainMTMap == NULL) - return; - - SimpleWriteLockHolder swlh(s_MTMapLock); - - bool fDeletedEntry = false; - PtrHashMap::PtrIterator iter = s_crossDomainMTMap->begin(); - while (!iter.end()) - { - MTMapEntry *pEntry = (MTMapEntry *)iter.GetValue(); - AppDomainFromIDHolder adFrom(pEntry->m_dwFromDomain, TRUE); - AppDomainFromIDHolder adTo(pEntry->m_dwToDomain, TRUE); - if (adFrom.IsUnloaded() || - adTo.IsUnloaded()) - { -#ifdef _DEBUG - LPVOID pDeletedEntry = -#endif - s_crossDomainMTMap->DeleteValue(pEntry->GetHash(), pEntry); - _ASSERTE(pDeletedEntry == pEntry); - delete pEntry; - fDeletedEntry = true; - } - ++iter; - } - - if (fDeletedEntry) - s_crossDomainMTMap->Compact(); -} - - - -// Before a cross appdomain call, we read the principal on the thread and set it aside, so that it can -// be restored when the call returns. -// In addition, we let the principal flow thru to the called appdomain, if the principal is serializable -OBJECTREF CrossDomainChannel::ReadPrincipal() -{ - CONTRACTL - { - GC_NOTRIGGER; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END - - THREADBASEREF ref = (THREADBASEREF) GetThread()->GetExposedObjectRaw(); - _ASSERTE(ref != NULL); - - EXECUTIONCONTEXTREF refExecCtx = (EXECUTIONCONTEXTREF )ref->GetExecutionContext(); - if (refExecCtx == NULL) - return NULL; - - LOGICALCALLCONTEXTREF refCallContext = refExecCtx->GetLogicalCallContext(); - if (refCallContext == NULL) - return NULL; - - CCSECURITYDATAREF refSecurityData = refCallContext->GetSecurityData(); - if (refSecurityData == NULL) - return NULL; - - OBJECTREF refPrincipal = refSecurityData->GetPrincipal(); - if (refPrincipal != NULL) - { - MethodTable *pPrincipalType = refPrincipal->GetMethodTable(); - if (!pPrincipalType->IsSerializable()) - { - refSecurityData->SetPrincipal(NULL); - } - } - - return refPrincipal; -} - -// Principal never flows from called appdomain back to caller domain. -VOID CrossDomainChannel::ResetPrincipal() -{ - CONTRACTL - { - GC_NOTRIGGER; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END - - THREADBASEREF ref = (THREADBASEREF) GetThread()->GetExposedObjectRaw(); - _ASSERTE(ref != NULL); - - EXECUTIONCONTEXTREF refExecCtx = (EXECUTIONCONTEXTREF )ref->GetExecutionContext(); - if (refExecCtx == NULL) - return; - - LOGICALCALLCONTEXTREF refCallContext = refExecCtx->GetLogicalCallContext(); - if (refCallContext == NULL) - return; - - CCSECURITYDATAREF refSecurityData = refCallContext->GetSecurityData(); - if (refSecurityData == NULL) - return; - - refSecurityData->SetPrincipal(NULL); - -} - -// At the end of a cross-appdomain call, we restore whatever principal was on the thread at the beginning of the call -VOID CrossDomainChannel::RestorePrincipal(OBJECTREF *prefPrincipal) -{ - CONTRACTL - { - GC_NOTRIGGER; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END - - THREADBASEREF ref = (THREADBASEREF) GetThread()->GetExposedObjectRaw(); - if (ref == NULL) - return; - - EXECUTIONCONTEXTREF refExecCtx = (EXECUTIONCONTEXTREF )ref->GetExecutionContext(); - _ASSERTE(*prefPrincipal == NULL || refExecCtx != NULL); - - if (refExecCtx == NULL) - return; - - LOGICALCALLCONTEXTREF refCallContext = refExecCtx->GetLogicalCallContext(); - if (refCallContext == NULL) - return; - - CCSECURITYDATAREF refSecurityData = refCallContext->GetSecurityData(); - _ASSERTE(*prefPrincipal == NULL || refSecurityData != NULL); - - if (refSecurityData == NULL) - return; - - refSecurityData->SetPrincipal(*prefPrincipal); - -} - -// This method mimics the Lease renewal mechanism of the managed CrossDomainChannel -// The lease object for the server can be accessed via its ServerIdentity. -VOID CrossDomainChannel::RenewLease() -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END - // Check if lease needs to be renewed - OBJECTREF refSrvIdentity = ObjectFromHandle(m_refSrvIdentity); - if (refSrvIdentity == NULL) - return; - - OBJECTREF refLease = ObjectToOBJECTREF((Object *)refSrvIdentity->GetPtrOffset(CRemotingServices::GetOffsetOfLeaseInIdentity())); - if (refLease != NULL) - { - GCPROTECT_BEGIN(refLease); - MethodDesc *pLeaseMeth = CRemotingServices::MDofRenewLeaseOnCall(); - PCODE pCode = (PCODE)pLeaseMeth->GetCallTarget(&refLease); - - PREPARE_NONVIRTUAL_CALLSITE_USING_CODE(pCode); - - DECLARE_ARGHOLDER_ARRAY(args, 2); - - args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(refLease); - args[ARGNUM_1] = NULL; - - CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE; - CALL_MANAGED_METHOD_NORET(args); - - GCPROTECT_END(); - } -} - -// Given a client side instantiated method desc and a server side generic definition method desc extract the instantiation, -// translate all the types involved into the server domain and return the fully instantiated server method desc. Note that the -// client and server method descs might not represent the same type -- the client method might be from an interface, whereas the -// server method will always be on the real class. -MethodDesc *InstantiateMethod(MethodDesc *pClientMD, MethodDesc *pServerMD, MethodTable *pServerMT) -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - PRECONDITION(CheckPointer(pClientMD)); - PRECONDITION(pClientMD->HasMethodInstantiation()); - PRECONDITION(CheckPointer(pServerMD)); - PRECONDITION(pServerMD->HasMethodInstantiation()); - PRECONDITION(pClientMD->GetNumGenericMethodArgs() == pServerMD->GetNumGenericMethodArgs()); - } - CONTRACTL_END; - - Instantiation clientInst = pClientMD->GetMethodInstantiation(); - - DWORD dwAllocaSize; - if (!ClrSafeInt::multiply(clientInst.GetNumArgs(), sizeof(TypeHandle), dwAllocaSize)) - COMPlusThrowHR(COR_E_OVERFLOW); - - CQuickBytes qbServerInst; - TypeHandle *pServerInst = reinterpret_cast(qbServerInst.AllocThrows(dwAllocaSize)); - - for (DWORD dwArgNum = 0; dwArgNum < clientInst.GetNumArgs(); dwArgNum++) - { - SString thName; - TypeString::AppendType(thName, clientInst[dwArgNum], TypeString::FormatNamespace|TypeString::FormatFullInst|TypeString::FormatAssembly); - - pServerInst[dwArgNum] = TypeName::GetTypeFromAsmQualifiedName(thName.GetUnicode(), pClientMD->IsIntrospectionOnly()); - - _ASSERTE(!pServerInst[dwArgNum].IsNull()); - - // Check that the type is actually visible on the server side. This prevents a malicious client from luring a trusted server - // into manipulating types that would be normally invisible to it. - if (!pServerInst[dwArgNum].IsExternallyVisible()) - COMPlusThrow(kRemotingException, W("Remoting_NonPublicOrStaticCantBeCalledRemotely")); - } - - // Find or create the method will the full instantiation. - return MethodDesc::FindOrCreateAssociatedMethodDesc(pServerMD, - pServerMT, - FALSE, - Instantiation(pServerInst, clientInst.GetNumArgs()), - FALSE); -} - -BOOL CrossDomainChannel::GetGenericMethodAddress(MethodTable *pServerType) -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END; - - m_pSrvMD = InstantiateMethod(m_pCliMD, pServerType->GetMethodDescForSlot(m_pCliMD->GetSlot()), pServerType); - - OBJECTREF thisObj = GetServerObject(); - m_pTargetAddress = m_pSrvMD->GetCallTarget(&thisObj); - - return TRUE; -} - -// We use this method to find the target address when we are convinced that the most derived type the proxy is cast -// to on the client side is equivalent to the corresponding type on the server side, in the sense the method table -// layouts are similar. This fact can be used to look up method addresses faster -BOOL CrossDomainChannel::GetTargetAddressFast(DWORD optFlags, MethodTable *pSrvMT, BOOL bFindServerMD) -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END - _ASSERTE(m_pCliMD); - _ASSERTE(m_pSrvDomain == SystemDomain::GetCurrentDomain()->GetId()); - - MethodTable *pCliMT = m_pCliMD->GetMethodTable(); - _ASSERTE(!pCliMT->IsInterface()); - - m_pSrvMD = NULL; - - DWORD dwMethodSlot = m_pCliMD->GetSlot(); - if (!RemotableMethodInfo::IsMethodVirtual(m_xret)) - { - // This is a non-virtual method. Find the matching MT on the - // server side, dereference the slot and get the method address - - MethodTable *pSrvSideMT = pSrvMT; - - // We now need to walk the server type hierarchy till we find the type that - // declared the method we're going to call - - // First find how far is the type declaring the called method, from System.Object - DWORD cliDepth = 0; - MethodTable *pCurrLevel = pCliMT; - while (pCurrLevel != NULL) - { - _ASSERTE(pCurrLevel); - pCurrLevel = pCurrLevel->GetParentMethodTable(); - cliDepth++; - }; - - // Next find how deep is the server type from System.Object - DWORD srvDepth = 0; - pCurrLevel = pSrvMT; - while (pCurrLevel != NULL) - { - _ASSERTE(pCurrLevel); - pCurrLevel = pCurrLevel->GetParentMethodTable(); - srvDepth++; - }; - - _ASSERTE(srvDepth >= cliDepth); - - while (srvDepth > cliDepth) - { - _ASSERTE(pSrvSideMT); - _ASSERTE(srvDepth != 0); - pSrvSideMT = pSrvSideMT->GetParentMethodTable(); - srvDepth--; - }; - - if (m_pCliMD->HasMethodInstantiation()) - { - GetGenericMethodAddress(pSrvSideMT); - } - else - { - m_pTargetAddress = pSrvSideMT->GetRestoredSlot(dwMethodSlot); - -#ifndef _DEBUG - if (bFindServerMD) -#endif - m_pSrvMD = pSrvSideMT->GetMethodDescForSlot(dwMethodSlot); - } - } - else - { - if (m_pCliMD->HasMethodInstantiation()) - GetGenericMethodAddress(pSrvMT); - else - { - m_pTargetAddress = pSrvMT->GetRestoredSlot(dwMethodSlot); - -#ifndef _DEBUG - if (bFindServerMD) -#endif - m_pSrvMD = pSrvMT->GetMethodDescForSlot(dwMethodSlot); - } - } - - _ASSERTE(m_pTargetAddress); -#ifdef _DEBUG - _ASSERTE(!strcmp(m_pSrvMD->GetName(), m_pCliMD->GetName())); - DefineFullyQualifiedNameForClass(); - LPCUTF8 szSrvTypeName = GetFullyQualifiedNameForClassNestedAware(pSrvMT); - LPCUTF8 pszMethodName = m_pCliMD->GetName(); - LOG((LF_REMOTING, LL_INFO100, "GetTargetAddressFast. Address of %s::%s is 0x%x\n", &szSrvTypeName[0], pszMethodName, m_pTargetAddress)); -#endif // _DEBUG - return TRUE; -} - -BOOL -CrossDomainChannel::GetInterfaceMethodAddressFast(DWORD optFlags, MethodTable *pSrvMT, BOOL bFindServerMD) -{ - CONTRACTL - { - THROWS; - MODE_COOPERATIVE; - GC_TRIGGERS; - } - CONTRACTL_END; - - _ASSERTE(m_pCliMD); - - MethodTable *pCliItfMT = m_pCliMD->GetMethodTable(); - _ASSERTE(pCliItfMT->IsInterface()); - - // Only use the fast path if the interface is shared. If the interface isnt shared, then we'll have to search the - // interface map on server type using name as key and then deref the slot # etc. I think shared interfaces will - // be the common pattern. If not they should be. - // Note that it's not enough to check that the client interface is shared, it must also be loaded in the server appdomain (since - // it's now possible to have more than one instance of a shared assembly in a process). - _ASSERTE(pCliItfMT->IsDomainNeutral()); - AppDomain* ad = SystemDomain::GetAppDomainFromId(m_pSrvDomain,ADV_RUNNINGIN); - if (ad->FindDomainAssembly(pCliItfMT->GetAssembly()) == NULL) - return FALSE; - - m_pSrvMD = NULL; - - OBJECTREF thisObj = GetServerObject(); - -#ifdef FEATURE_COMINTEROP - // Check for a COM interop server. - if (thisObj->GetMethodTable()->IsComObjectType()) - { -#if 0 - // We don't have all the logic in place to deal with COM interop yet. The following code is taken from the regular remoting - // invocation path in CStackBuilderSink::PrivateProcessMessage, but I think we still need some work on the actual invocation - // itself (leastways we didn't end up invoking the method correctly when I tried it). - // For now we'll just bail back to the regular remoting path for COM interop. - m_pSrvMD = thisObj->GetMethodTable()->GetMethodDescForComInterfaceMethod(m_pCliMD, false); - if (m_pSrvMD == NULL) - return FALSE; -#endif - return FALSE; - } -#endif // FEATURE_COMINTEROP - - GCPROTECT_BEGIN(thisObj); - - DispatchSlot impl(pSrvMT->FindDispatchSlotForInterfaceMD(m_pCliMD)); - CONSISTENCY_CHECK(!impl.IsNull()); - m_pSrvMD = impl.GetMethodDesc(); - - _ASSERTE(m_pSrvMD); - - // If the method called has a generic instantiation then the server method desc we've just received doesn't contain that - // information (generic method slots are filled with generic definition method descs). We need to build the exact method desc by - // copying the instantiation from the client method (translating each type into the new domain of course). - if (m_pSrvMD->HasMethodInstantiation()) - m_pSrvMD = InstantiateMethod(m_pCliMD, m_pSrvMD, pSrvMT); - - m_pTargetAddress = m_pSrvMD->GetCallTarget(&thisObj); - - GCPROTECT_END(); - - return TRUE; -} - - -// Here we check whether the remote call is a cross domain call, if so, does it qualify -BOOL -CrossDomainChannel::CheckCrossDomainCall(TPMethodFrame *pFrame) -{ - CONTRACTL - { - THROWS; - MODE_COOPERATIVE; - GC_TRIGGERS; - } - CONTRACTL_END; - - m_pFrame = pFrame; - m_pCliMD = m_pFrame->GetFunction(); - - MethodTable *pCliMT = m_pCliMD->GetMethodTable(); - - // Check if this is an async delegate call - if (pCliMT->IsDelegate()) - return FALSE; - - // Only use the fast path if the interface is shared. If the interface isnt shared, then we'll have to search the - // interface map on server type using name as key and then deref the slot # etc. I think shared interfaces will - // be the common pattern. - if (pCliMT->IsInterface() && !pCliMT->IsDomainNeutral()) - return FALSE; - - OBJECTREF refTP = pFrame->GetThis(); - REALPROXYREF refRP = CTPMethodTable::GetRP(refTP); - - // Check if this is a x-domain call - DWORD domainID = refRP->GetDomainID(); - if (domainID == 0) - return FALSE; // Not x-appdomain call, or proxy not initted for optimization - - // Check if we are in a context different from default. If so, we may need to run context - // policies etc. Use regular path. - if (GetThread()->GetContext() != SystemDomain::GetCurrentDomain()->GetDefaultContext()) - return FALSE; - - // Check if method call args can be blitted (or not optimizable at all) - m_xret = RemotableMethodInfo::IsCrossAppDomainOptimizable(m_pCliMD, &m_numStackSlotsToCopy); - if (RemotableMethodInfo::IsCallNotOptimizable(m_xret)) - { -#ifdef _DEBUG - DefineFullyQualifiedNameForClass(); - LPCUTF8 szSrvTypeName = GetFullyQualifiedNameForClassNestedAware(m_pCliMD->GetMethodTable()); - LOG((LF_REMOTING, LL_INFO100, "CheckCrossDomainCall. Call to %s::%s is not optimizable\n", - &szSrvTypeName[0], m_pCliMD->GetName())); -#endif // _DEBUG - return FALSE; - } - - m_pCliDomain = SystemDomain::GetCurrentDomain(); - m_pSrvDomain = ADID(domainID); - - return ExecuteCrossDomainCall(); -} - -// Dereference the server identity handle, to reach the server object -// If the handle is null, someone either called Disconnect on the server -// or the server's lease ran out -OBJECTREF CrossDomainChannel::GetServerObject() -{ - CONTRACTL - { - MODE_COOPERATIVE; - THROWS; - GC_TRIGGERS; - } - CONTRACTL_END - - _ASSERTE(m_pSrvDomain == SystemDomain::GetCurrentDomain()->GetId()); - - OBJECTREF refSrvIdentity = ObjectFromHandle(m_refSrvIdentity); - if (refSrvIdentity == NULL) - { - OBJECTREF refTP = m_pFrame->GetThis(); - REALPROXYREF refRP = CTPMethodTable::GetRP(refTP); - OBJECTREF refIdentity = ObjectToOBJECTREF((Object *)refRP->GetPtrOffset(CRemotingServices::GetOffsetOfCliIdentityInRP())); - STRINGREF refURI = (STRINGREF)ObjectToOBJECTREF((Object *)refIdentity->GetPtrOffset(CRemotingServices::GetOffsetOfURIInIdentity())); - SString sURI; - refURI->GetSString(sURI); - - COMPlusThrow(kRemotingException, - IDS_REMOTING_SERVER_DISCONNECTED, - sURI.GetUnicode()); - } - OBJECTREF srvObject = ObjectToOBJECTREF((Object *)refSrvIdentity->GetPtrOffset(CRemotingServices::GetOffsetOfTPOrObjInIdentity())); - return srvObject; -} - -// Here the we find the target method address, make a decision whether to -// execute the call locally, if remote whether to blit the arguments or to marshal them, -BOOL CrossDomainChannel::ExecuteCrossDomainCall() -{ - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_MODE_COOPERATIVE; - - BOOL bOptimizable = TRUE; - - { - ProfilerRemotingClientCallbackHolder profilerHolder; - - // Short circuit calls to Object::GetType and run them locally - if (m_pCliMD == CRemotingServices::MDofObjectGetType()) - { - LOG((LF_REMOTING, LL_INFO100, "ExecuteCrossDomainCall. Short circuiting call to Object::GetType and running it locally.\n")); - OBJECTREF refTP = m_pFrame->GetThis(); - OBJECTREF refType = CRemotingServices::GetClass(refTP); - LPVOID pReturnValuePtr = m_pFrame->GetReturnValuePtr(); - *(Object **)pReturnValuePtr = OBJECTREFToObject(refType); - } - else if (RemotableMethodInfo::AreArgsBlittable(m_xret)) - { - bOptimizable = BlitAndCall(); - } - else - { - bOptimizable = MarshalAndCall(); - } - } - - if (!bOptimizable) - return FALSE; - - // Check for the need to trip thread - if (GetThread()->CatchAtSafePointOpportunistic()) - { - // There is no need to GC protect the return object as - // TPFrame is GC protecting it - CommonTripThread(); - } - -#ifdef _TARGET_X86_ - // Set the number of bytes to pop for x86 - m_pFrame->SetCbStackPop(m_numStackSlotsToCopy * sizeof(SIZE_T)); -#endif // _TARGET_X86_ - - return TRUE; -} - -BOOL -CrossDomainChannel::InitServerInfo() -{ - CONTRACTL - { - MODE_COOPERATIVE; - THROWS; - GC_TRIGGERS; - } - CONTRACTL_END - - _ASSERTE(m_pFrame); - _ASSERTE(m_pSrvDomain == SystemDomain::GetCurrentDomain()->GetId()); - - // Get the server object - OBJECTREF refTP = m_pFrame->GetThis(); - REALPROXYREF refRP = CTPMethodTable::GetRP(refTP); - m_refSrvIdentity = (OBJECTHANDLE)refRP->GetPtrOffset(CRemotingServices::GetOffsetOfSrvIdentityInRP()); - OBJECTREF srvObject = GetServerObject(); - - MethodTable *pSrvMT = srvObject->GetMethodTable(); - - // Find the target address - DWORD optFlag = refRP->GetOptFlags(); - - // If we are cloning some arguments to server domain, we want to do a type check - // on the cloned objects against the expected type. To find the expected type, we need to - // know the method signature on the server side, which in turn is obtainable if we know - // the server MethodDesc. Finding MethodDesc from a slot isnt cheap, so we do it only if we need it - BOOL bFindServerMD = (RemotableMethodInfo::AreArgsBlittable(m_xret)) ? FALSE : TRUE; - BOOL bResultOfAddressLookup = FALSE; - - if (m_pCliMD->GetMethodTable()->IsInterface()) - { - bResultOfAddressLookup = GetInterfaceMethodAddressFast(optFlag, pSrvMT, bFindServerMD); - } - else if ((optFlag & OPTIMIZATION_FLAG_INITTED) && (optFlag & OPTIMIZATION_FLAG_PROXY_EQUIVALENT)) - { - bResultOfAddressLookup = GetTargetAddressFast(optFlag, pSrvMT, bFindServerMD); - } - else - { - // If the proxy is not cast to an equivalent type, do not perform any optimizations - bResultOfAddressLookup = FALSE; - } - -#ifdef _DEBUG - if (!bResultOfAddressLookup) - LOG((LF_REMOTING, LL_INFO100, "InitServerInfo. Skipping fast path because failed to find target address.\n")); -#endif // _DEBUG - - _ASSERTE(!bResultOfAddressLookup || !bFindServerMD || m_pSrvMD); - return bResultOfAddressLookup; -} - -// A macro used to help calculate the exact declaring type of a method (this may not be as simple as calling GetMethodTable on the -// method desc if the type is generic and not an interface). We get the additional information from the instance (which provides an -// exact method table, though not necessarily the one the method is actually _declared_ on). We don't compute the instance or the -// method table from that instance in this macro since the logic varies greatly from client to server (the client has to adjust for -// the fact that the instance is a TP). -// We assume a variable called thDeclaringType has already been declared in the current scope. -#define CDC_DETERMINE_DECLARING_TYPE(_pMD, _thInst) \ - if (!(_pMD)->HasClassInstantiation() || (_pMD)->IsInterface()) \ - { \ - thDeclaringType = TypeHandle((_pMD)->GetMethodTable()); \ - } \ - else \ - { \ - Instantiation inst = (_pMD)->GetExactClassInstantiation(_thInst); \ - MethodTable *pApproxDeclaringMT = (_pMD)->GetMethodTable(); \ - thDeclaringType = ClassLoader::LoadGenericInstantiationThrowing(pApproxDeclaringMT->GetModule(), \ - pApproxDeclaringMT->GetCl(), \ - inst); \ - } - -// We have decided the arguments are blittable. We may still need to marshal -// call context if any. -BOOL -CrossDomainChannel::BlitAndCall() -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END - - SIZE_T *pRegArgs = NULL; - SIZE_T *pStackArgs = NULL; -#ifdef CALLDESCR_ARGREGS - ArgumentRegisters RegArgs = {0}; - pRegArgs = (SIZE_T*)&RegArgs; -#endif -#ifdef CALLDESCR_FPARGREGS - FloatArgumentRegisters *pFloatArgumentRegisters = NULL; -#endif - - BOOL bOptimizable = TRUE; - BOOL bHasObjRefReturnVal = FALSE; - - Thread *pCurThread = GetThread(); - -#ifdef _DEBUG - LPCUTF8 pszMethodName; - pszMethodName = m_pCliMD->GetName(); - LOG((LF_REMOTING, LL_INFO100, "BlitAndCall. Blitting arguments to method %s\n", pszMethodName)); -#endif // _DEBUG - - // Collect all client domain GC references together in a single GC frame. - // refReturnValue contains the returned object. - // It can also contain a boxed object when the return is a value type and needs marshalling - struct _gc { - OBJECTREF refReturnValue; - OBJECTREF refException; - OBJECTREF refExecutionContext; - OBJECTREF refPrincipal; - } ClientGC; - ZeroMemory(&ClientGC, sizeof(ClientGC)); - GCPROTECT_BEGIN(ClientGC); - - _ASSERTE(RemotableMethodInfo::IsReturnBlittable(m_xret)); - - // Check for any logical call context that contains data - BOOL bMarshalCallContext = FALSE; - BOOL bMarshalReturnCallContext = FALSE; - if (pCurThread->IsExposedObjectSet()) - { - THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw(); - _ASSERTE(ref != NULL); - - EXECUTIONCONTEXTREF refExecCtx = (EXECUTIONCONTEXTREF) ref->GetExecutionContext(); - if (refExecCtx != NULL) - { - ClientGC.refExecutionContext = refExecCtx; - ClientGC.refPrincipal = ReadPrincipal(); - - LOGICALCALLCONTEXTREF refLogCallCtx = refExecCtx->GetLogicalCallContext(); - if (refLogCallCtx != NULL) - { - if (refLogCallCtx->ContainsDataForSerialization()) - { - bMarshalCallContext = TRUE; - } - } - } - } - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // Assume that exception at server was NotCorrupting - CorruptionSeverity severity = NotCorrupting; -#endif // FEATURE_CORRUPTING_EXCEPTIONS - - // Push the frame - ENTER_DOMAIN_ID(m_pSrvDomain); - - // Now create a server domain GC frame for all server side GC references. - struct _gc { - OBJECTREF refReturnValue; - OBJECTREF refException; - OBJECTREF refExecutionContext; - } ServerGC; - ZeroMemory(&ServerGC, sizeof(ServerGC)); - GCPROTECT_BEGIN(ServerGC); - - // Initialize server side info, such as method address etc - bOptimizable = InitServerInfo(); - - if (!bOptimizable) - goto LeaveDomain; - - RenewLease(); - - if (bMarshalCallContext) - { - LOG((LF_REMOTING, LL_INFO100, "BlitAndCall. Marshalling call context\n", pszMethodName)); - CrossAppDomainClonerCallback cadcc; - ObjectClone Marshaller(&cadcc, CrossAppDomain, FALSE); - ServerGC.refExecutionContext = Marshaller.Clone(ClientGC.refExecutionContext, - m_pCliDomain, - GetAppDomain(), - ClientGC.refExecutionContext); - THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw(); - _ASSERTE(ref != NULL); - - ref->SetExecutionContext(ServerGC.refExecutionContext); - - Marshaller.RemoveGCFrames(); - } - else if (pCurThread->IsExposedObjectSet()) - { - THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw(); - _ASSERTE(ref != NULL); - - ref->SetExecutionContext(NULL); - } - -#ifdef PROFILING_SUPPORTED - // If we're profiling, notify the profiler that we're about to invoke the remoting target - { - BEGIN_PIN_PROFILER(CORProfilerTrackRemoting()); - GCX_PREEMP(); - g_profControlBlock.pProfInterface->RemotingServerInvocationStarted(); - END_PIN_PROFILER(); - } -#endif // PROFILING_SUPPORTED - - { - GCX_COOP(); - UINT64 uRegTypeMap = 0; - pStackArgs = (SIZE_T *)(m_pFrame->GetTransitionBlock() + TransitionBlock::GetOffsetOfArgs()); - - // Get the 'this' object - OBJECTREF srvObject = GetServerObject(); - -#if defined(_TARGET_X86_) - pRegArgs[0] = *((SIZE_T*)(m_pFrame->GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters())); - pRegArgs[1] = (SIZE_T) OBJECTREFToObject(srvObject); -#elif defined(CALLDESCR_ARGREGS) - // Have to buffer argument registers since we're going to overwrite the this object with the server - // version and the frame owning the registers is in the wrong domain to report that object. - pRegArgs[0] = (SIZE_T) OBJECTREFToObject(srvObject); - memcpy(pRegArgs + 1, - (SIZE_T*)(m_pFrame->GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters()) + 1, - sizeof(ArgumentRegisters) - sizeof(SIZE_T)); - -#ifdef CALLDESCR_FPARGREGS - // Only provide a pointer to the floating point area of the stack frame if there any any floating - // point arguments (passing NULL optimizes the CallDescr thunk by omitting the initialization of - // floating point argument registers). - if (RemotableMethodInfo::DoArgsContainAFloat(m_xret)) - pFloatArgumentRegisters = (FloatArgumentRegisters*)(m_pFrame->GetTransitionBlock() + TransitionBlock::GetOffsetOfFloatArgumentRegisters()); -#endif // CALLDESCR_FPARGREGS - -#else // CALLDESCR_ARGREGS - - // It's a pity that we have to allocate a buffer for the arguments on the stack even in BlitAndCall(). - // The problem is we can't use the portion of the stack protected by m_pFrame to store the srvObject, - // since the srvObject is in the server domain and the TPMethodFrame m_pFrame is in the client domain. - // I don't think we need to protect the srvOjbect in this case, since it's reachable from the transparent - // proxy, which is protected by the TPMethodFrame. - SIZE_T* pTmpStackArgs = (SIZE_T*)_alloca(m_numStackSlotsToCopy * sizeof(SIZE_T)); - memcpy(pTmpStackArgs, pStackArgs, m_numStackSlotsToCopy * sizeof(SIZE_T)); - pStackArgs = pTmpStackArgs; - - pStackArgs[0] = (SIZE_T)OBJECTREFToObject(srvObject); -#endif // CALLDESCR_ARGREGS - -#if defined(CALLDESCR_REGTYPEMAP) || defined(COM_STUBS_SEPARATE_FP_LOCATIONS) - // We have to copy the floating point registers from a different stack location to the portion of - // the stack used to save the general registers. Since this is expensive, we only do this if - // we have some floating point arguments. - if (RemotableMethodInfo::DoArgsContainAFloat(m_xret)) - { - // When computing the method signature we need to take special care if the call is on a non-interface class with a - // generic instantiation (since in that case we may have a representative method with a non-concrete signature). - TypeHandle thDeclaringType; - CDC_DETERMINE_DECLARING_TYPE(m_pCliMD, TypeHandle(CTPMethodTable::GetMethodTableBeingProxied(m_pFrame->GetThis()))); - MetaSig mSig(m_pCliMD, thDeclaringType); - ArgIterator argit(&mSig); - - int offset; - while (TransitionBlock::InvalidOffset != (offset = argit.GetNextOffset())) - { - int regArgNum = TransitionBlock::GetArgumentIndexFromOffset(offset); - - if (regArgNum >= NUM_ARGUMENT_REGISTERS) - break; - - CorElementType argTyp = argit.GetArgType(); - -#ifdef CALLDESCR_REGTYPEMAP - FillInRegTypeMap(offset, argTyp, (BYTE*)&uRegTypeMap); -#endif - -#ifdef COM_STUBS_SEPARATE_FP_LOCATIONS - if (argTyp == ELEMENT_TYPE_R4 || argTyp == ELEMENT_TYPE_R8) - { - PVOID pSrc = (PVOID)(m_pFrame->GetTransitionBlock() + m_pFrame->GetFPArgOffset(regArgNum)); - - ARG_SLOT val; - if (argTyp == ELEMENT_TYPE_R4) - val = FPSpillToR4(pSrc); - else - val = FPSpillToR8(pSrc); - - *(ARG_SLOT*)(&pStackArgs[regArgNum]) = val; - } -#endif - } - } -#endif // CALLDESCR_REGTYPEMAP || COM_STUBS_SEPARATE_FP_LOCATIONS - - CallDescrData callDescrData; - - callDescrData.pSrc = pStackArgs; - callDescrData.numStackSlots = m_numStackSlotsToCopy, -#ifdef CALLDESCR_ARGREGS - callDescrData.pArgumentRegisters = (ArgumentRegisters *)pRegArgs; -#endif -#ifdef CALLDESCR_FPARGREGS - callDescrData.pFloatArgumentRegisters = pFloatArgumentRegisters; -#endif -#ifdef CALLDESCR_REGTYPEMAP - callDescrData.dwRegTypeMap = uRegTypeMap; -#endif - callDescrData.fpReturnSize = GetFPReturnSize(); - callDescrData.pTarget = m_pTargetAddress; - - DispatchCall( - &callDescrData, - &ServerGC.refException, - GET_CTX_TRANSITION_FRAME() - COMMA_CORRUPTING_EXCEPTIONS_ONLY(&severity) - ); - - // If the return value is a GC ref, store it in a protected place - if (ServerGC.refException != NULL) - { - // Return value is invalid if there was exception thrown - } - else - if (RemotableMethodInfo::IsReturnGCRef(m_xret)) - { - ServerGC.refReturnValue = ObjectToOBJECTREF(*(Object **)(&callDescrData.returnValue)); - bHasObjRefReturnVal = TRUE; - } - else - { - memcpyNoGCRefs(m_pFrame->GetReturnValuePtr(), &callDescrData.returnValue, sizeof(callDescrData.returnValue)); - } - } - -#ifdef PROFILING_SUPPORTED - { - BEGIN_PIN_PROFILER(CORProfilerTrackRemoting()); - GCX_PREEMP(); - g_profControlBlock.pProfInterface->RemotingServerInvocationReturned(); - END_PIN_PROFILER(); - } -#endif // PROFILING_SUPPORTED - - // Propagate any logical call context changes except those to the principal - if (pCurThread->IsExposedObjectSet()) - { - THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw(); - _ASSERTE(ref != NULL); - - EXECUTIONCONTEXTREF refExecCtx = (EXECUTIONCONTEXTREF) ref->GetExecutionContext(); - if (refExecCtx != NULL) - { - LOGICALCALLCONTEXTREF refLogCallCtx = refExecCtx->GetLogicalCallContext(); - if (bMarshalCallContext || - (refLogCallCtx != NULL && refLogCallCtx->ContainsNonSecurityDataForSerialization())) - { - ServerGC.refExecutionContext = ref->GetExecutionContext(); - bMarshalReturnCallContext = TRUE; - LOG((LF_REMOTING, LL_INFO100, "BlitAndCall. Marshalling return call context\n", pszMethodName)); - CrossAppDomainClonerCallback cadcc; - ObjectClone Marshaller(&cadcc, CrossAppDomain, FALSE); - - ResetPrincipal(); - - EXECUTIONCONTEXTREF ecref = (EXECUTIONCONTEXTREF)Marshaller.Clone(ServerGC.refExecutionContext, - GetAppDomain(), - m_pCliDomain, - ServerGC.refExecutionContext); - if (ClientGC.refExecutionContext != NULL) - ((EXECUTIONCONTEXTREF)ClientGC.refExecutionContext)->SetLogicalCallContext(ecref->GetLogicalCallContext()); - else - ClientGC.refExecutionContext = (OBJECTREF)ecref; - - Marshaller.RemoveGCFrames(); - } - } - } - - if (ServerGC.refException != NULL) - { - LOG((LF_REMOTING, LL_INFO100, "BlitAndCall. Exception thrown ! Marshalling exception. \n", pszMethodName)); - - // Save Watson buckets before the exception object is changed - if (GetThread() != NULL) - { - // Ensure that we have the buckets for the exception in question. - // For preallocated exceptions, we capture the buckets in the - // UE WatsonBucket Tracker in AppDomainTransitionExceptionFilter. - // - // When the exception is reraised in the returning AppDomain, - // StackTraceInfo::AppendElement will copy over the buckets - // to the EHtracker corresponding to the raised exception. - if (!CLRException::IsPreallocatedExceptionObject(ServerGC.refException)) - { - // For non-preallocated exception objects, the throwable - // is expected have the buckets in it, assuming that - // CLR's personality routine for managed code was notified - // of the exception before returning from the AD transition. - // - // There are scenarios where few managed frames, post AD transition, - // may get optimized away by the JIT. If a managed exception is - // thrown from within the VM at a later time, the personality routine - // for managed will not be invoked if there are no managed frames present - // between the AD Transition frame and the frame where VM raised the managed - // exception. - // - // When such an exception comes back to the calling AppDomain, we will - // come here and look for watson buckets and may not find them. In such - // a case, simply log it. - if(!((EXCEPTIONREF)ServerGC.refException)->AreWatsonBucketsPresent()) - { - LOG((LF_EH, LL_INFO100, "CrossDomainChannel::BlitAndCall: Watson buckets not found in regular exception object. Exception likely raised in native code.\n")); - } - } - } - - CrossAppDomainClonerCallback cadcc; - ObjectClone Marshaller(&cadcc, CrossAppDomain, FALSE); - ClientGC.refException = Marshaller.Clone(ServerGC.refException, GetAppDomain(), m_pCliDomain, ServerGC.refExecutionContext); - - Marshaller.RemoveGCFrames(); - - // We have to be in the right domain before we throw the exception - goto LeaveDomain; - } - - if (bHasObjRefReturnVal) - { - // Must be a domain agile GC ref. We can just copy the reference into the client GC frame. - ClientGC.refReturnValue = ServerGC.refReturnValue; - } - -LeaveDomain: ; - - GCPROTECT_END(); // ServerGC - - END_DOMAIN_TRANSITION; - - if (ClientGC.refException != NULL) - { - RestorePrincipal(&ClientGC.refPrincipal); - COMPlusThrow(ClientGC.refException - COMMA_CORRUPTING_EXCEPTIONS_ONLY(severity) - ); - } - - if (pCurThread->IsExposedObjectSet()) - { - THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw(); - _ASSERTE(ref != NULL); - - ref->SetExecutionContext(ClientGC.refExecutionContext); - } - - RestorePrincipal(&ClientGC.refPrincipal); - - // If the return type is an object, take it out of the protected ref - if (bHasObjRefReturnVal) - { - *(Object **)m_pFrame->GetReturnValuePtr() = OBJECTREFToObject(ClientGC.refReturnValue); - } - - GCPROTECT_END(); // ClientGC - - return bOptimizable; -} - -// Argument attributes -#define ARG_NEEDS_UNBOX 0x80000000 -#define ARG_GOES_IN_EDX 0x40000000 -#define ARG_IS_BYREF 0x20000000 -#define ARG_OFFSET_MASK 0x00FFFFFF - -// Structure to hold arguments for MarshalAndCall -struct MarshalAndCallArgs : public CtxTransitionBaseArgs -{ - MarshalAndCallArgs() : Marshaller(&cadcc, CrossAppDomain, FALSE) - { - STATIC_CONTRACT_SO_INTOLERANT; - } - - CrossDomainChannel * pThis; - - struct _gc { - OBJECTREF refReturnValue; - OBJECTREF refException; - OBJECTREF refExecutionContext; - OBJECTREF refPrincipal; - } ClientGC; - - BOOL bOptimizable; - - ObjectClone Marshaller; - CrossAppDomainClonerCallback cadcc; - - MetaSig *mSig; - ArgIterator *argit; - - DWORD dwNumArgs; -#ifdef CALLDESCR_ARGREGS - SIZE_T *pRegArgs; -#endif -#ifdef CALLDESCR_FPARGREGS - FloatArgumentRegisters *pFloatArgumentRegisters; -#endif - SIZE_T *pStackArgs; - DWORD *pArgAttribs; - - DWORD dwNumObjectsMarshalled; - BOOL *bMarshalledArgs; - OBJECTREF *pClientArgArray; - - BOOL bHasByRefArgsToMarshal; - int *pByRefArgAttribs; - TypeHandle *pThByRefs; - - TypeHandle retTh; - BOOL bHasObjRefReturnVal; - BOOL bHasRetBuffArg; - BOOL bHasValueTypeReturnValToMarshal; - - BOOL bMarshalCallContext; - BOOL bMarshalReturnCallContext; - -#ifdef CALLDESCR_REGTYPEMAP - UINT64 uRegTypeMap; -#endif - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - CorruptionSeverity severity; -#endif // FEATURE_CORRUPTING_EXCEPTIONS -}; - -// Simple wrapper to go from C to C++. -void MarshalAndCall_Wrapper2(MarshalAndCallArgs * pArgs) -{ - WRAPPER_NO_CONTRACT; - - pArgs->pThis->MarshalAndCall_Wrapper(pArgs); -} - -void CrossDomainChannel::MarshalAndCall_Wrapper(MarshalAndCallArgs * pArgs) -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END; - - // Set up a rip-cord that will immediately stop us reporting GC references we're keeping alive in the Marshaller that was passed - // to us in the event that this appdomain is unloaded underneath our feet. This avoids us keeping any server objects alive after - // their domain has unloaded. - ReportClonerRefsHolder sHolder(&pArgs->Marshaller); - - Thread* pCurThread = GetThread(); - AppDomain* pCurAppDomain = GetAppDomain(); - - // Now create a server domain GC frame for all non-arg server side GC references. - struct _gc { - OBJECTREF refReturnValue; - OBJECTREF refException; - OBJECTREF refExecutionContext; - } ServerGC; - ZeroMemory(&ServerGC, sizeof(ServerGC)); - GCPROTECT_BEGIN(ServerGC); - - // And a variable sized array and frame of marshaled arg GC references. - OBJECTREF *pServerArgArray = NULL; - pServerArgArray = (OBJECTREF *) _alloca(pArgs->dwNumObjectsMarshalled * sizeof(OBJECTREF)); - ZeroMemory(pServerArgArray, sizeof(OBJECTREF) * pArgs->dwNumObjectsMarshalled); - - TypeHandle* pServerArgTH = (TypeHandle *) _alloca(pArgs->dwNumObjectsMarshalled * sizeof(TypeHandle)); - GCPROTECT_ARRAY_BEGIN(pServerArgArray[0], pArgs->dwNumObjectsMarshalled); - - // Initialize server side info, such as method address etc - pArgs->bOptimizable = InitServerInfo(); - - if (!pArgs->bOptimizable) - goto LeaveDomain; - - RenewLease(); - - // First clone objref arguments into the called domain - if (!RemotableMethodInfo::AreArgsBlittable(m_xret)) - { - // When computing the method signature we need to take special care if the call is on a non-interface class with a - // generic instantiation (since in that case we may have a representative method with a non-concrete signature). - TypeHandle thDeclaringType; - CDC_DETERMINE_DECLARING_TYPE(m_pSrvMD, TypeHandle(GetServerObject()->GetTypeHandle())); - MetaSig mSrvSideSig(m_pSrvMD, thDeclaringType); - DWORD dwMarshalledArg = 0; - for (DWORD i = 0; i < pArgs->dwNumArgs; i++) - { - CorElementType cType = mSrvSideSig.NextArg(); - if (pArgs->bMarshalledArgs[i] != TRUE) - { - // Make sure argument type is loaded - if (cType == ELEMENT_TYPE_VALUETYPE) - { - mSrvSideSig.GetLastTypeHandleThrowing(); - } - continue; - } - - TypeHandle argTh; - if (cType == ELEMENT_TYPE_BYREF) - mSrvSideSig.GetByRefType(&argTh); - else - argTh = mSrvSideSig.GetLastTypeHandleThrowing(); - - pServerArgTH[dwMarshalledArg] = argTh; - pServerArgArray[dwMarshalledArg] = pArgs->Marshaller.Clone(pArgs->pClientArgArray[dwMarshalledArg], - argTh, - m_pCliDomain, - pCurAppDomain, - pArgs->ClientGC.refExecutionContext); - dwMarshalledArg++; - } - - // Make sure return type is loaded - TypeHandle thReturn = mSrvSideSig.GetRetTypeHandleThrowing(); - _ASSERTE(!thReturn.IsNull()); - - if (pArgs->bHasValueTypeReturnValToMarshal) - { - // The return is a value type which could have GC ref fields. Allocate a boxed value type so that the - // return value goes into that. During return from call we'll clone it and copy it onto the stack - ServerGC.refReturnValue = thReturn.AsMethodTable()->Allocate(); - } - } - - // Then clone the call context if any - if (pArgs->bMarshalCallContext) - { -#ifdef _DEBUG - LOG((LF_REMOTING, LL_INFO100, "MarshalAndCall. Marshalling call context\n")); -#endif - ServerGC.refExecutionContext = pArgs->Marshaller.Clone(pArgs->ClientGC.refExecutionContext, - m_pCliDomain, - pCurAppDomain, - pArgs->ClientGC.refExecutionContext); - THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw(); - _ASSERTE(ref != NULL); - - ref->SetExecutionContext(ServerGC.refExecutionContext); - } - else if (pCurThread->IsExposedObjectSet()) - { - THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw(); - _ASSERTE(ref != NULL); - - ref->SetExecutionContext(NULL); - } - -#ifdef PROFILING_SUPPORTED - // If we're profiling, notify the profiler that we're about to invoke the remoting target - { - BEGIN_PIN_PROFILER(CORProfilerTrackRemoting()); - GCX_PREEMP(); - g_profControlBlock.pProfInterface->RemotingServerInvocationStarted(); - END_PIN_PROFILER(); - } -#endif // PROFILING_SUPPORTED - - { - GCX_COOP(); - if (!RemotableMethodInfo::AreArgsBlittable(m_xret)) - { - // Next place arguments into the destination array - // No GC should occur between now and call dispatch - for (DWORD i = 0 ; i < pArgs->dwNumObjectsMarshalled; i++) - { - BOOL bNeedUnbox = pArgs->pArgAttribs[i] & ARG_NEEDS_UNBOX; - BOOL bGoesInEDX = pArgs->pArgAttribs[i] & ARG_GOES_IN_EDX; - BOOL bIsByRef = pArgs->pArgAttribs[i] & ARG_IS_BYREF; - DWORD dwOffset = pArgs->pArgAttribs[i] & ARG_OFFSET_MASK; - - SIZE_T *pDest = NULL; - -#if defined(_TARGET_X86_) - if (bGoesInEDX) - { - // This has to be EDX for this platform. - pDest = pArgs->pRegArgs; - } - else - { - pDest = (SIZE_T *)((BYTE *)(pArgs->pStackArgs) + dwOffset); - } -#elif defined(CALLDESCR_ARGREGS) - // To help deal with the fact that a single argument can span both registers and stack - // we've ensured that the register and stack buffers are contiguous and encoded all offsets - // from the beginning of the register buffer. - pDest = (SIZE_T *)((BYTE *)(pArgs->pRegArgs) + dwOffset); -#else - pDest = (SIZE_T *)((BYTE *)(pArgs->pStackArgs) + dwOffset); -#endif - - if (bNeedUnbox && !bIsByRef) - { - pServerArgTH[i].GetMethodTable()->UnBoxIntoUnchecked(pDest, pServerArgArray[i]); - } - else if (bIsByRef) - { - if (bNeedUnbox) - { - // We don't use the fast path for byref nullables, so UnBox() can be used - *pDest = (SIZE_T)pServerArgArray[i]->UnBox(); - } - else - { - // Point to the OBJECTREF - *pDest = (SIZE_T)&pServerArgArray[i]; - } - } - else - { - *pDest = (SIZE_T)OBJECTREFToObject(pServerArgArray[i]); - } - } - } - - // Get the 'this' object - OBJECTREF srvObject = GetServerObject(); - LPVOID pvRetBuff = NULL; - - FrameWithCookie* pProtectValueClassFrame = NULL; - ValueClassInfo* pValueClasses = NULL; - - if (pArgs->bHasRetBuffArg) - { - // Need some sort of check here that retTH has been initialized? - MethodTable* pMT = pArgs->retTh.GetMethodTable(); - _ASSERTE_MSG(pMT != NULL, "GetRetType failed?"); - if (pMT->IsStructRequiringStackAllocRetBuf()) - { - SIZE_T sz = pMT->GetNumInstanceFieldBytes(); - pvRetBuff = _alloca(sz); - memset(pvRetBuff, 0, sz); - pValueClasses = new (_alloca(sizeof(ValueClassInfo))) ValueClassInfo(pvRetBuff, pMT, pValueClasses); - } - else - { - // We don't use the fast path for values that return nullables, so UnBox() can be used - pvRetBuff = (PVOID)ServerGC.refReturnValue->UnBox(); - } - } -#if defined(_TARGET_X86_) - // Check if EDX should point to a return buffer (either stack- or heap-allocated). - if (pArgs->bHasValueTypeReturnValToMarshal && pArgs->bHasRetBuffArg) - { - *(pArgs->pRegArgs) = (SIZE_T)pvRetBuff; - } - (pArgs->pRegArgs)[1] = (SIZE_T)OBJECTREFToObject(srvObject); -#elif defined(CALLDESCR_ARGREGS) - // On ARM the this pointer goes in r0 and any return buffer argument pointer in r1. - pArgs->pRegArgs[0] = (SIZE_T)OBJECTREFToObject(srvObject); - if (pArgs->bHasRetBuffArg) - { - pArgs->pRegArgs[1] = (SIZE_T)pvRetBuff; - } -#else // CALLDESCR_ARGREGS - - if (pArgs->bHasRetBuffArg) - { - (pArgs->pStackArgs)[0] = (SIZE_T)OBJECTREFToObject(srvObject); - (pArgs->pStackArgs)[1] = (SIZE_T)pvRetBuff; - } - else - { - (pArgs->pStackArgs)[0] = (SIZE_T)OBJECTREFToObject(srvObject); - } - -#endif // CALLDESCR_ARGREGS - - CallDescrData callDescrData; - - - callDescrData.pSrc = pArgs->pStackArgs; - callDescrData.numStackSlots = m_numStackSlotsToCopy, -#ifdef CALLDESCR_ARGREGS - callDescrData.pArgumentRegisters = (ArgumentRegisters *)pArgs->pRegArgs; -#endif -#ifdef CALLDESCR_FPARGREGS - callDescrData.pFloatArgumentRegisters = pArgs->pFloatArgumentRegisters; -#endif -#ifdef CALLDESCR_REGTYPEMAP - callDescrData.dwRegTypeMap = pArgs->uRegTypeMap; -#endif - callDescrData.fpReturnSize = GetFPReturnSize(); - callDescrData.pTarget = m_pTargetAddress; - - if (pValueClasses != NULL) - { - pProtectValueClassFrame = new (_alloca (sizeof (FrameWithCookie))) - FrameWithCookie(pCurThread, pValueClasses); - } - - DispatchCall(&callDescrData, - &ServerGC.refException, - pArgs->GetCtxTransitionFrame() - COMMA_CORRUPTING_EXCEPTIONS_ONLY(&(pArgs->severity)) - ); - - // If the return value is a GC ref, store it in a protected place - if (ServerGC.refException != NULL) - { - // Return value is invalid if there was exception thrown - } - else - if (RemotableMethodInfo::IsReturnGCRef(m_xret)) - { - ServerGC.refReturnValue = ObjectToOBJECTREF(*(Object **)(&callDescrData.returnValue)); - pArgs->bHasObjRefReturnVal = TRUE; - } - else - if (pArgs->bHasValueTypeReturnValToMarshal) - { - if (!pArgs->bHasRetBuffArg) - { - // - // The value type return value is returned by value in this case. - // We have to copy it back into our server object. - // - // We don't use the fast path for values that return nullables, so UnBox() can be used - // - CopyValueClass(ServerGC.refReturnValue->UnBox(), &callDescrData.returnValue, ServerGC.refReturnValue->GetMethodTable(), pCurAppDomain); - } - else if (pValueClasses != NULL) - { - // We passed a stack allocated ret buff. Copy back into the allocated server object. - // We don't use the fast path for values that return nullables, so UnBox() can be used - CopyValueClass(ServerGC.refReturnValue->UnBox(), pvRetBuff, ServerGC.refReturnValue->GetMethodTable(), pCurAppDomain); - } - // In all other cases, the return value should be in the server object already. - } - else - { - memcpyNoGCRefs(m_pFrame->GetReturnValuePtr(), &callDescrData.returnValue, sizeof(callDescrData.returnValue)); - } - - if (pProtectValueClassFrame != NULL) - pProtectValueClassFrame->Pop(pCurThread); - } - -#ifdef PROFILING_SUPPORTED - { - BEGIN_PIN_PROFILER(CORProfilerTrackRemoting()); - GCX_PREEMP(); - g_profControlBlock.pProfInterface->RemotingServerInvocationReturned(); - END_PIN_PROFILER(); - } -#endif // PROFILING_SUPPORTED - - if (pCurThread->IsExposedObjectSet()) - { - THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw(); - _ASSERTE(ref != NULL); - - EXECUTIONCONTEXTREF refExecCtx = (EXECUTIONCONTEXTREF) ref->GetExecutionContext(); - if (refExecCtx != NULL) - { - LOGICALCALLCONTEXTREF refLogCallCtx = refExecCtx->GetLogicalCallContext(); - if (pArgs->bMarshalCallContext || - (refLogCallCtx != NULL && refLogCallCtx->ContainsNonSecurityDataForSerialization())) - { - ServerGC.refExecutionContext = ref->GetExecutionContext(); - pArgs->bMarshalReturnCallContext = TRUE; -#ifdef _DEBUG - LOG((LF_REMOTING, LL_INFO100, "MarshalAndCall. Marshalling return call context\n")); -#endif - ResetPrincipal(); - EXECUTIONCONTEXTREF ecref = (EXECUTIONCONTEXTREF)pArgs->Marshaller.Clone(ServerGC.refExecutionContext, - pCurAppDomain, - m_pCliDomain, - ServerGC.refExecutionContext); - if (pArgs->ClientGC.refExecutionContext != NULL) - { - ((EXECUTIONCONTEXTREF)pArgs->ClientGC.refExecutionContext)->SetLogicalCallContext(ecref->GetLogicalCallContext()); - } - else - { - pArgs->ClientGC.refExecutionContext = (OBJECTREF)ecref; - } - } - } - } - - - if (ServerGC.refException != NULL) - { -#ifdef _DEBUG - LOG((LF_REMOTING, LL_INFO100, "MarshalAndCall. Exception thrown ! Marshalling exception. \n")); -#endif - - // Save Watson buckets before the exception object is changed - if (GetThread() != NULL) - { - // Ensure that we have the buckets for the exception in question. - // For preallocated exceptions, we capture the buckets in the - // UE WatsonBucket Tracker in AppDomainTransitionExceptionFilter. - // - // When the exception is reraised in the returning AppDomain, - // StackTraceInfo::AppendElement will copy over the buckets - // to the EHtracker corresponding to the raised exception. - if (!CLRException::IsPreallocatedExceptionObject(ServerGC.refException)) - { - // For non-preallocated exception objects, the throwable - // should already have the buckets in it, unless it was raised in VM native code - // and reached here before CLR's managed code exception handler could see it. - if(!((EXCEPTIONREF)ServerGC.refException)->AreWatsonBucketsPresent()) - { - LOG((LF_EH, LL_INFO1000, "MarshalAndCall - Regular exception object received (%p) does not contain watson buckets.\n", - OBJECTREFToObject(ServerGC.refException))); - } - } - } - - pArgs->ClientGC.refException = pArgs->Marshaller.Clone(ServerGC.refException, - pCurAppDomain, - m_pCliDomain, - ServerGC.refExecutionContext); - goto LeaveDomain; - } - - if (!RemotableMethodInfo::IsReturnBlittable(m_xret)) - { - LOG((LF_REMOTING, LL_INFO100, "MarshalAndCall. Marshalling return object\n")); - // Need to marshal the return object - - pArgs->ClientGC.refReturnValue = pArgs->Marshaller.Clone(ServerGC.refReturnValue, - pArgs->retTh, - pCurAppDomain, - m_pCliDomain, - ServerGC.refExecutionContext); - - if (pArgs->bHasValueTypeReturnValToMarshal) - { - // Need to copy contents from temp return buffer to the original return buffer - void *pDest; - if (!pArgs->bHasRetBuffArg) - { - pDest = m_pFrame->GetReturnValuePtr(); - } - else - { - pDest = *(void **)(m_pFrame->GetTransitionBlock() + pArgs->argit->GetRetBuffArgOffset()); - } - // We don't use the fast path for values that return nullables, so UnBox() can be used - CopyValueClass(pDest, pArgs->ClientGC.refReturnValue->UnBox(), pArgs->ClientGC.refReturnValue->GetMethodTable(), m_pCliDomain); - } - } - else if (pArgs->bHasObjRefReturnVal) - { - // Must be a domain agile GC ref. We can just copy the reference into the client GC frame. - pArgs->ClientGC.refReturnValue = ServerGC.refReturnValue; - } - - // Marshal any by-ref args into calling domain - if (pArgs->bHasByRefArgsToMarshal) - { -#ifdef _DEBUG - LOG((LF_REMOTING, LL_INFO100, "MarshalAndCall. Marshalling by-ref args\n")); -#endif - int iMarshalledArg = -1; - // Look for by ref args - for (DWORD i = 0; i < pArgs->dwNumArgs; i++) - { - if (pArgs->bMarshalledArgs[i] != TRUE) - continue; - - iMarshalledArg++; - - BOOL bNeedUnbox = pArgs->pArgAttribs[iMarshalledArg] & ARG_NEEDS_UNBOX; - BOOL bIsByRef = pArgs->pArgAttribs[iMarshalledArg] & ARG_IS_BYREF; - - if (!bIsByRef) - continue; - - TypeHandle argTh = pArgs->pThByRefs[iMarshalledArg]; - int offset = pArgs->pByRefArgAttribs[iMarshalledArg]; - OBJECTREF refReturn = pServerArgArray[iMarshalledArg]; - GCPROTECT_BEGIN(refReturn); - - refReturn = pArgs->Marshaller.Clone(refReturn, - argTh, - pCurAppDomain, - m_pCliDomain, - ServerGC.refExecutionContext); - if (bNeedUnbox) - { - // We don't use the fast path for byref nullables, so UnBox() can be used - BYTE *pTargetAddress = *((BYTE **)(m_pFrame->GetTransitionBlock() + offset)); - CopyValueClass(pTargetAddress, refReturn->UnBox(), refReturn->GetMethodTable(), m_pCliDomain); - } - else - { - SetObjectReference(*((OBJECTREF **)(m_pFrame->GetTransitionBlock() + offset)), refReturn, m_pCliDomain); - } - GCPROTECT_END(); - } - } - - LeaveDomain:; - - GCPROTECT_END(); // pServerArgArray - GCPROTECT_END(); // ServerGC -} - - -// Arguments need to be marshalled before dispatch. We walk thru each argument, -// inspect its type, make a list of objects that need to be marshalled, cross over to the new domain, -// marshal the objects and dispatch the call. Upon return, we marshal the return object if any and -// by ref objects if any. Call contexts flows either way -#ifdef _PREFAST_ -#pragma warning(push) -#pragma warning(disable:21000) // Suppress PREFast warning about overly large function -#endif -BOOL -CrossDomainChannel::MarshalAndCall() -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END - - MarshalAndCallArgs args; - - args.bHasByRefArgsToMarshal = FALSE; - - args.bHasObjRefReturnVal = FALSE; - args.bHasRetBuffArg = FALSE; - args.bHasValueTypeReturnValToMarshal = FALSE; - - DWORD dwNumArgs = 0; - DWORD dwNumObjectsMarshalled = 0; - - DWORD *pArgAttribs = NULL; - BOOL *bMarshalledArgs = NULL; - int *pByRefArgAttribs = NULL; - TypeHandle *pThByRefs = NULL; - - Thread *pCurThread = GetThread(); - -#ifdef _DEBUG - LPCUTF8 pszMethodName; - pszMethodName = m_pCliMD->GetName(); - LOG((LF_REMOTING, LL_INFO100, "MarshalAndCall. Marshalling arguments to method %s\n", pszMethodName)); -#endif // _DEBUG - - // Collect all client domain GC references together in a single GC frame. - // refReturnValue contains the returned object when its a value type and needs marshalling - ZeroMemory(&args.ClientGC, sizeof(args.ClientGC)); - GCPROTECT_BEGIN(args.ClientGC); - - // When computing the method signature we need to take special care if the call is on a non-interface class with a - // generic instantiation (since in that case we may have a representative method with a non-concrete signature). - TypeHandle thDeclaringType; - CDC_DETERMINE_DECLARING_TYPE(m_pCliMD, TypeHandle(CTPMethodTable::GetMethodTableBeingProxied(m_pFrame->GetThis()))); - MetaSig mSig(m_pCliMD, thDeclaringType); - ArgIterator argit(&mSig); - int ofs; - - // NumFixedArgs() doesn't count the "this" object, but SizeOfFrameArgumentArray() does. - dwNumArgs = mSig.NumFixedArgs(); - m_numStackSlotsToCopy = argit.SizeOfFrameArgumentArray() / sizeof(SIZE_T); - - // Ensure none of the following _alloca's are subject to integer overflow problems. - DWORD dwMaxEntries = dwNumArgs > m_numStackSlotsToCopy ? dwNumArgs : m_numStackSlotsToCopy; - DWORD dwResult; - if (!ClrSafeInt::multiply(dwMaxEntries, sizeof(SIZE_T), dwResult)) - COMPlusThrowOM(); -#ifdef _PREFAST_ -#pragma warning(push) -#pragma warning(disable:26000) // "Suppress PREFast warning about integer overflow (we're doing an umbrella check)" -#endif - - args.bHasRetBuffArg = argit.HasRetBuffArg(); - -#ifdef _TARGET_X86_ - BOOL bArgumentRegisterUsed = FALSE; - if (args.bHasRetBuffArg) - { - bArgumentRegisterUsed = TRUE; - } -#endif // _TARGET_X86_ - - // pArgAttribs tell where the marshalled objects should go, where they need unboxing etc - pArgAttribs = (DWORD*) _alloca(dwNumArgs * sizeof(DWORD)); - ZeroMemory(pArgAttribs, sizeof(DWORD) * dwNumArgs); - // pThByRefs has the typehandles of the by-ref args - pThByRefs = (TypeHandle *)_alloca(dwNumArgs * sizeof(TypeHandle)); - ZeroMemory(pThByRefs, sizeof(TypeHandle) *dwNumArgs); - // pByRefArgAttribs tell where the by-ref args should go, after the call - pByRefArgAttribs = (int*) _alloca(dwNumArgs * sizeof(int)); - ZeroMemory(pByRefArgAttribs, sizeof(int) * dwNumArgs); - // bMarshalledArgs is a bunch of flags that tell which args were marshalled - bMarshalledArgs = (BOOL*) _alloca(dwNumArgs * sizeof(BOOL)); - ZeroMemory(bMarshalledArgs, sizeof(BOOL) * dwNumArgs); - - // pArgArray contains marshalled objects on the client side - OBJECTREF *pClientArgArray = NULL; - pClientArgArray = (OBJECTREF *) _alloca(dwNumArgs * sizeof(OBJECTREF)); - ZeroMemory(pClientArgArray, sizeof(OBJECTREF) * dwNumArgs); - GCPROTECT_ARRAY_BEGIN(pClientArgArray[0], dwNumArgs); - - // pStackArgs will finally contain the arguments that'll be fed to Dispatch call. The Marshalled objects - // are not placed directly into pStackArgs because its not possible to GCPROTECT an array that can contain - // both GC refs and primitives. - DWORD cbStackArgs = m_numStackSlotsToCopy * sizeof (SIZE_T); -#ifdef CALLDESCR_ARGREGS - // Allocate enough space to put ArgumentRegisters at the front of the buffer so we can ensure - // register and stack arguments are stored contiguously and simply the case of unboxing a value type that - // spans registers and the stack. - cbStackArgs += sizeof(ArgumentRegisters); -#endif - SIZE_T *pStackArgs = (SIZE_T*)_alloca(cbStackArgs); - ZeroMemory(pStackArgs, cbStackArgs); -#ifdef CALLDESCR_ARGREGS - SIZE_T *pRegArgs = pStackArgs; - pStackArgs += sizeof(ArgumentRegisters) / sizeof(SIZE_T); -#endif -#ifdef CALLDESCR_FPARGREGS - FloatArgumentRegisters *pFloatArgumentRegisters = NULL; -#endif - -#if defined(CALLDESCR_REGTYPEMAP) - UINT64 uRegTypeMap = 0; - BYTE* pMap = (BYTE*)&uRegTypeMap; -#endif - - TADDR pTransitionBlock = m_pFrame->GetTransitionBlock(); - - for (int argNum = 0; - TransitionBlock::InvalidOffset != (ofs = argit.GetNextOffset()); - argNum++ - ) - { - DWORD dwOffsetOfArg = 0; - -#if defined(CALLDESCR_REGTYPEMAP) - int regArgNum = TransitionBlock::GetArgumentIndexFromOffset(ofs); - - FillInRegTypeMap(ofs, argit.GetArgType(), pMap); -#endif // defined(CALLDESCR_REGTYPEMAP) - - SIZE_T *pDestToCopy = NULL; - -#if defined(_TARGET_ARM_) - - // On ARM there are ranges of offset that can be returned from ArgIterator::GetNextOffset() (where R - // == TransitionBlock::GetOffsetOfArgumentRegisters() and S == sizeof(TransitionBlock)): - // - // * ofs < 0 : arg is in a floating point register - // * ofs >= R && ofs < S : arg is in a general register - // * ofs >= S : arg is on the stack at offset (ofs - X) - // - // Arguments can be split between general registers and the stack on ARM and as a result both - // FramedMethodFrame and this method ensure the storage for register and stack locations is - // contiguous. - int iInitialRegOffset = TransitionBlock::GetOffsetOfArgumentRegisters(); - int iInitialStackOffset = sizeof(TransitionBlock); - _ASSERTE(iInitialStackOffset == (iInitialRegOffset + sizeof(ArgumentRegisters))); - if (ofs < 0) - { - // Floating point register case. Since these registers can never hold a GC reference we can just - // pass through a pointer to the spilled FP reg area in the frame. But we don't do this unless we - // see at least one FP arg: passing NULL for pFloatArgumentRegisters enables an optimization in - // the call thunk. - if (pFloatArgumentRegisters == NULL) - pFloatArgumentRegisters = (FloatArgumentRegisters*) (pTransitionBlock + TransitionBlock::GetOffsetOfFloatArgumentRegisters()); - - // No arg to copy in this case. - continue; - } - - _ASSERTE(ofs >= iInitialRegOffset); - - // We've ensured our registers and stack locations are contiguous so treat both types of arguments - // identically (i.e. compute a destination offset from the base of the register save area and it will - // work for arguments that span from registers to stack or live entirely on the stack). - dwOffsetOfArg = ofs - TransitionBlock::GetOffsetOfArgumentRegisters(); - pDestToCopy = (SIZE_T*)((BYTE *)pRegArgs + dwOffsetOfArg); - -#else // _TARGET_ARM_ - - dwOffsetOfArg = ofs - TransitionBlock::GetOffsetOfArgs(); - -#ifdef _TARGET_X86_ - if (!bArgumentRegisterUsed && gElementTypeInfo[argit.GetArgType()].m_enregister) - { - pDestToCopy = pRegArgs; - bArgumentRegisterUsed = TRUE; - } - else -#endif // _TARGET_X86_ - { - _ASSERTE(dwOffsetOfArg < (m_numStackSlotsToCopy * sizeof(SIZE_T))); - pDestToCopy = (SIZE_T*)((BYTE *)pStackArgs + dwOffsetOfArg); - } - -#endif // _TARGET_ARM_ - - CorElementType origTyp = argit.GetArgType(); - - // Get the signature type of the argument (For ex. enum will be E_T_VT, not E_T_I4 etc) - SigPointer sp = mSig.GetArgProps(); - CorElementType typ; - IfFailThrow(sp.GetElemType(&typ)); - - if (typ == ELEMENT_TYPE_VAR || - typ == ELEMENT_TYPE_MVAR || - typ == ELEMENT_TYPE_GENERICINST) - { - typ = origTyp; - } - - switch (typ) - { - case ELEMENT_TYPE_BOOLEAN: - case ELEMENT_TYPE_I1: - case ELEMENT_TYPE_U1: - case ELEMENT_TYPE_I2: - case ELEMENT_TYPE_U2: - case ELEMENT_TYPE_CHAR: - case ELEMENT_TYPE_I4: - case ELEMENT_TYPE_U4: -#if !defined(COM_STUBS_SEPARATE_FP_LOCATIONS) - case ELEMENT_TYPE_R4: -#endif - -#if defined(_TARGET_X86_) || defined(_TARGET_ARM_) - *(pDestToCopy) = *((SIZE_T*) (pTransitionBlock + ofs)); -#elif defined(_WIN64) - switch (GetSizeForCorElementType((CorElementType)typ)) - { - case 1: - *(BYTE*)(pDestToCopy) = *(BYTE*)(pTransitionBlock + ofs); - break; - - case 2: - *(USHORT*)(pDestToCopy) = *(USHORT*)(pTransitionBlock + ofs); - break; - - case 4: - *(UINT*)(pDestToCopy) = *(UINT*)(pTransitionBlock + ofs); - break; - - case 8: - *(SIZE_T*)(pDestToCopy) = *(SIZE_T*)(pTransitionBlock + ofs); - break; - - default: - _ASSERTE(!"MarshalAndCall() - unexpected size"); - } -#else // !defined(_WIN64) - PORTABILITY_ASSERT("MarshalAndCall() - NYI on this platform"); -#endif // !defined(_WIN64) - break; - - case ELEMENT_TYPE_I: - case ELEMENT_TYPE_U: - case ELEMENT_TYPE_PTR: - case ELEMENT_TYPE_FNPTR: - - *((SIZE_T*)((BYTE *)pDestToCopy)) = *((SIZE_T*)(pTransitionBlock + ofs)); - break; - - case ELEMENT_TYPE_I8: - case ELEMENT_TYPE_U8: -#if !defined(COM_STUBS_SEPARATE_FP_LOCATIONS) - case ELEMENT_TYPE_R8: -#endif - - *((INT64*)((BYTE *)pDestToCopy)) = *((INT64 *)(pTransitionBlock + ofs)); - break; - -#if defined(COM_STUBS_SEPARATE_FP_LOCATIONS) - case ELEMENT_TYPE_R4: - - if (regArgNum < NUM_ARGUMENT_REGISTERS) - { - *(ARG_SLOT*)pDestToCopy = FPSpillToR4( (LPVOID)(pTransitionBlock + m_pFrame->GetFPArgOffset(regArgNum)) ); - } - else - { - *(UINT*)(pDestToCopy) = *(UINT*)(pTransitionBlock + ofs); - } - break; - - case ELEMENT_TYPE_R8: - - if (regArgNum < NUM_ARGUMENT_REGISTERS) - { - *(ARG_SLOT*)pDestToCopy = FPSpillToR8( (LPVOID)(pTransitionBlock + m_pFrame->GetFPArgOffset(regArgNum)) ); - } - else - { - *(SIZE_T*)(pDestToCopy) = *(SIZE_T*)(pTransitionBlock + ofs); - } - break; -#endif // defined(COM_STUBS_SEPARATE_FP_LOCATIONS) - - case ELEMENT_TYPE_BYREF: - { - // Check if this is a by-ref primitive - OBJECTREF refTmpBox = NULL; - TypeHandle ty = TypeHandle(); - CorElementType brType = mSig.GetByRefType(&ty); - if (CorIsPrimitiveType(brType) || ty.IsValueType()) - { - - // Needs marshalling - MethodTable *pMT = NULL; - if (CorIsPrimitiveType(brType)) - pMT = MscorlibBinder::GetElementType(brType); - else - pMT = ty.GetMethodTable(); - refTmpBox = pMT->Box(*((SIZE_T**)(pTransitionBlock + ofs))); - pArgAttribs[dwNumObjectsMarshalled] |= ARG_NEEDS_UNBOX; - } - else - { - OBJECTREF *refRefObj = *((OBJECTREF **)(pTransitionBlock + ofs)); - refTmpBox = (refRefObj == NULL ? NULL : *refRefObj); - } - - pByRefArgAttribs[dwNumObjectsMarshalled] = ofs; - pThByRefs[dwNumObjectsMarshalled] = ty; - - // we should have stopped nullables before we got here in DoStaticAnalysis - _ASSERTE(ty.IsNull() || !Nullable::IsNullableType(ty)); - pArgAttribs[dwNumObjectsMarshalled] |= ARG_IS_BYREF; - - args.bHasByRefArgsToMarshal = TRUE; - - pClientArgArray[dwNumObjectsMarshalled] = refTmpBox; - bMarshalledArgs[argNum] = TRUE; - -#if defined(_TARGET_X86_) - if (pDestToCopy == pRegArgs) - { - pArgAttribs[dwNumObjectsMarshalled] |= ARG_GOES_IN_EDX; // Indicate that this goes in EDX - } - else -#endif // _TARGET_X86_ - { - // @TODO - Use QWORD for attribs - _ASSERTE(dwOffsetOfArg < ARG_OFFSET_MASK); - pArgAttribs[dwNumObjectsMarshalled] |= dwOffsetOfArg; - } - dwNumObjectsMarshalled++; - } - break; - - case ELEMENT_TYPE_VALUETYPE: - { -#if defined(COM_STUBS_SEPARATE_FP_LOCATIONS) - if (regArgNum < NUM_ARGUMENT_REGISTERS) - { - - // We have to copy the floating point registers from a different stack location to the portion of - // the stack used to save the general registers. - if (origTyp == ELEMENT_TYPE_R4) - { - LPVOID pDest = (LPVOID)(pTransitionBlock + ofs); - *(ARG_SLOT*)pDest = FPSpillToR4( (LPVOID)(pTransitionBlock + m_pFrame->GetFPArgOffset(regArgNum)) ); - } - else if (origTyp == ELEMENT_TYPE_R8) - { - LPVOID pDest = (LPVOID)(pTransitionBlock + ofs); - *(ARG_SLOT*)pDest = FPSpillToR8( (LPVOID)(pTransitionBlock + m_pFrame->GetFPArgOffset(regArgNum)) ); - } - } -#endif // defined(COM_STUBS_SEPARATE_FP_LOCATIONS) - - TypeHandle th = mSig.GetLastTypeHandleThrowing(); - -#ifdef _DEBUG - { - DefineFullyQualifiedNameForClass() - LPCUTF8 szTypeName = GetFullyQualifiedNameForClassNestedAware(th.GetMethodTable()); - LOG((LF_REMOTING, LL_INFO100, "MarshalAndCall. Boxing a value type argument of type %s.\n", &szTypeName[0])); - } -#endif // _DEBUG - - OBJECTREF refTmpBox; -#if defined(ENREGISTERED_PARAMTYPE_MAXSIZE) - if (argit.IsArgPassedByRef()) - { - refTmpBox = th.GetMethodTable()->Box(*(LPVOID*)(pTransitionBlock + ofs)); - - // we should have stopped nullables before we got here in DoStaticAnalysis - _ASSERTE(!Nullable::IsNullableType(th)); - pArgAttribs[dwNumObjectsMarshalled] |= ARG_IS_BYREF; - - pByRefArgAttribs[dwNumObjectsMarshalled] = ofs; - pThByRefs[dwNumObjectsMarshalled] = th; - } - else -#endif // defined(ENREGISTERED_PARAMTYPE_MAXSIZE) - { - refTmpBox = th.GetMethodTable()->Box((void *)(pTransitionBlock + ofs)); - } - pClientArgArray[dwNumObjectsMarshalled] = refTmpBox; - bMarshalledArgs[argNum] = TRUE; - -#if defined(_TARGET_X86_) - if (pDestToCopy == pRegArgs) - { - pArgAttribs[dwNumObjectsMarshalled] |= ARG_GOES_IN_EDX; // Indicate that this goes in EDX - } - else -#endif // _TARGET_X86_ - { - // @TODO - Use QWORD for attribs - _ASSERTE(dwOffsetOfArg < ARG_OFFSET_MASK); - pArgAttribs[dwNumObjectsMarshalled] |= dwOffsetOfArg; - } - pArgAttribs[dwNumObjectsMarshalled] |= ARG_NEEDS_UNBOX; // Indicate that an unboxing is required - dwNumObjectsMarshalled++; - } - break; - - case ELEMENT_TYPE_SZARRAY: // Single Dim - case ELEMENT_TYPE_ARRAY: // General Array - case ELEMENT_TYPE_CLASS: // Class - case ELEMENT_TYPE_OBJECT: - case ELEMENT_TYPE_STRING: // System.String - case ELEMENT_TYPE_VAR: - { - OBJECTREF *refRefObj = (OBJECTREF *)(pTransitionBlock + ofs); - // The frame does protect this object, so mark it as such to avoid asserts - INDEBUG(Thread::ObjectRefNew(refRefObj);) - INDEBUG(Thread::ObjectRefProtected(refRefObj);) - - pClientArgArray[dwNumObjectsMarshalled] = *refRefObj; - bMarshalledArgs[argNum] = TRUE; - -#ifdef _TARGET_X86_ - if (pDestToCopy == pRegArgs) - { - pArgAttribs[dwNumObjectsMarshalled] |= ARG_GOES_IN_EDX; // Indicate that this goes in EDX - } - else -#endif // _TARGET_X86_ - { - // @TODO - Use QWORD for attribs - _ASSERTE(dwOffsetOfArg < ARG_OFFSET_MASK); - pArgAttribs[dwNumObjectsMarshalled] |= dwOffsetOfArg; - } - dwNumObjectsMarshalled++; - } - break; - - default: - _ASSERTE(!"Unknown Element type in MarshalAndCall" ); - } - } - - if (!RemotableMethodInfo::IsReturnBlittable(m_xret)) - { - CorElementType retType = mSig.GetReturnType(); - if (retType == ELEMENT_TYPE_VALUETYPE) - { - args.retTh = mSig.GetRetTypeHandleThrowing(); - args.bHasValueTypeReturnValToMarshal = TRUE; - } - else - { - args.retTh = mSig.GetRetTypeHandleThrowing(); - } - } - - // Check for any call context - BOOL bMarshalCallContext = FALSE; - args.bMarshalReturnCallContext = FALSE; - if (pCurThread->IsExposedObjectSet()) - { - THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw(); - _ASSERTE(ref != NULL); - - EXECUTIONCONTEXTREF refExecCtx = (EXECUTIONCONTEXTREF) ref->GetExecutionContext(); - if (refExecCtx != NULL) - { - args.ClientGC.refExecutionContext = refExecCtx; - args.ClientGC.refPrincipal = ReadPrincipal(); - - LOGICALCALLCONTEXTREF refLogCallCtx = refExecCtx->GetLogicalCallContext(); - if (refLogCallCtx != NULL) - { - if (refLogCallCtx->ContainsDataForSerialization()) - { - bMarshalCallContext = TRUE; - } - } - } - } - -#ifdef _PREFAST_ -#pragma warning(pop) -#endif - - // Make the Cross-AppDomain call - { - args.pThis = this; - - args.bOptimizable = TRUE; - - args.mSig = &mSig; - args.argit = &argit; - - args.dwNumArgs = dwNumArgs; - args.pStackArgs = pStackArgs; -#ifdef CALLDESCR_ARGREGS - args.pRegArgs = pRegArgs; -#endif -#ifdef CALLDESCR_FPARGREGS - args.pFloatArgumentRegisters = pFloatArgumentRegisters; -#endif - args.pArgAttribs = pArgAttribs; - - args.dwNumObjectsMarshalled = dwNumObjectsMarshalled; - args.bMarshalledArgs = bMarshalledArgs; - args.pClientArgArray = pClientArgArray; - - args.pByRefArgAttribs = pByRefArgAttribs; - args.pThByRefs = pThByRefs; - - args.bMarshalCallContext = bMarshalCallContext; - -#ifdef CALLDESCR_REGTYPEMAP - args.uRegTypeMap = *(UINT64*)pMap; -#endif - -#ifdef FEATURE_CORRUPTING_EXCEPTIONS - // By default assume that exception thrown across the cross-AD call is NotCorrupting. - args.severity = NotCorrupting; -#endif // FEATURE_CORRUPTING_EXCEPTIONS - - MakeCallWithPossibleAppDomainTransition(m_pSrvDomain, (FPAPPDOMAINCALLBACK) MarshalAndCall_Wrapper2, &args); - } - - if (args.ClientGC.refException != NULL) - { - RestorePrincipal(&args.ClientGC.refPrincipal); - COMPlusThrow(args.ClientGC.refException - COMMA_CORRUPTING_EXCEPTIONS_ONLY(args.severity) - ); - } - - if (pCurThread->IsExposedObjectSet()) - { - THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw(); - _ASSERTE(ref != NULL); - - ref->SetExecutionContext(args.ClientGC.refExecutionContext); - } - - RestorePrincipal(&args.ClientGC.refPrincipal); - - // If the return type is an object, take it out of the protected ref - if (args.bHasObjRefReturnVal) - { - *(Object **)m_pFrame->GetReturnValuePtr() = OBJECTREFToObject(args.ClientGC.refReturnValue); - } - - GCPROTECT_END(); // pClientArgArray - GCPROTECT_END(); // args.ClientGC - - args.Marshaller.RemoveGCFrames(); - - return args.bOptimizable; -} -#ifdef _PREFAST_ -#pragma warning(pop) -#endif - -#endif // CROSSGEN_COMPILE - -#endif // FEATURE_REMOTING -- cgit v1.2.3 From 85443510ce834866f2bc899e8512c2b7b90ee3ed Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Sun, 12 Feb 2017 20:52:42 -0800 Subject: Remove dead gchost.cpp --- src/vm/gchost.cpp | 28 ---------------------------- 1 file changed, 28 deletions(-) delete mode 100644 src/vm/gchost.cpp diff --git a/src/vm/gchost.cpp b/src/vm/gchost.cpp deleted file mode 100644 index af213c27be..0000000000 --- a/src/vm/gchost.cpp +++ /dev/null @@ -1,28 +0,0 @@ -// 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. -//***************************************************************************** -// gchost.cpp -// -// This module contains the implementation for the IGCController interface. -// This interface is published through the gchost.idl file. It allows a host -// environment to set config values for the GC. -// - -// -//***************************************************************************** - -//********** Includes ********************************************************* - -#include "common.h" -#include "vars.hpp" -#include "eeconfig.h" -#include "perfcounters.h" -#include "gchost.h" -#include "corhost.h" -#include "excep.h" -#include "field.h" -#include "gcheaputilities.h" - - - -- cgit v1.2.3 From b15fd281c15c39d26418e94d422e6eee148046a8 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Sun, 12 Feb 2017 20:53:44 -0800 Subject: Remove dead mda.cpp --- src/vm/mda.cpp | 4026 -------------------------------------------------------- 1 file changed, 4026 deletions(-) delete mode 100644 src/vm/mda.cpp diff --git a/src/vm/mda.cpp b/src/vm/mda.cpp deleted file mode 100644 index bea222a0c6..0000000000 --- a/src/vm/mda.cpp +++ /dev/null @@ -1,4026 +0,0 @@ -// 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. - - -#include "common.h" -#include "eeconfig.h" - -#include -#include -#include "unknwn.h" -#include "../xmlparser/_reference.h" -#include "../xmlparser/_unknown.h" -#include "eehash.h" -#include "eeconfig.h" - -#define CONFIG_KEY_SIZE 128 -#include "corhlpr.h" -#include -#include -#include -#include -#include "wrappers.h" -#include "mda.h" -#include "mdaassistants.h" -#include "sstring.h" -#include "util.hpp" -#include "debugdebugger.h" - -#ifdef MDA_SUPPORTED - -// -// MdaHashtable -// - -BOOL MdaLockOwner(LPVOID) { LIMITED_METHOD_CONTRACT; return TRUE; } - -BOOL IsJustMyCode(MethodDesc* pMethodDesc) -{ - CONTRACT(BOOL) - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACT_END; - - if (!ManagedDebuggingAssistants::IsManagedDebuggerAttached()) - return TRUE; - - BOOL bIsJMC = FALSE; - - EX_TRY - { - if (g_pDebugInterface && g_pDebugInterface->IsJMCMethod(pMethodDesc->GetModule(), pMethodDesc->GetMemberDef())) - bIsJMC = TRUE; - } - EX_CATCH - { - } - EX_END_CATCH(SwallowAllExceptions); - - RETURN bIsJMC; -} - - -// -// ManagedDebuggingAssistants -// - -const bool g_mdaAssistantIsSwitch[] = -{ -#define MDA_ASSISTANT_IS_SWITCH -#include "mdaschema.inl" -#undef MDA_ASSISTANT_IS_SWITCH - false -}; - -void ManagedDebuggingAssistants::Initialize() -{ - CONTRACT_VOID - { - NOTHROW; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACT_END; - - EX_TRY - { - // - // Initialize - // - m_pSwitchActivationXml = NULL; - m_pMdaXmlIndustry = new MdaXmlIndustry(); - - MdaSchema::Initialize(); - - // - // Create AssistantSchema - // - m_pAssistantSchema = new MdaAssistantSchema(); - - // - // Create AssistantMsgSchema - // - m_pAssistantMsgSchema = new MdaAssistantMsgSchema(); - - // - // Create SchemaSchema - // - m_pSchemaSchema = new MdaSchemaSchema(); - - // - // InvalidConfigFile - // - g_mdaStaticHeap.m_mdaInvalidConfigFile.Enable(); - -#ifdef _DEBUG - StackSString sszValidateFramework(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MDAValidateFramework)); - if (!sszValidateFramework.IsEmpty() && sszValidateFramework.Equals(W("1"))) - DebugInitialize(); -#endif - } - EX_CATCH - { - // MDA State corrupted, unable to initialize, runtime still OK - } - EX_END_CATCH(SwallowAllExceptions); - - RETURN; -} - -MdaEnvironment::~MdaEnvironment() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (m_pStringFactory) - delete m_pStringFactory; - - if (m_pGroups) - delete m_pGroups; - - if (m_szMda) - delete m_szMda; -} - -MdaEnvironment::MdaEnvironment() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - m_bDisable = TRUE; - m_szMda = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_MDA); - m_pStringFactory = NULL; - m_pGroups = NULL; - - if (ManagedDebuggingAssistants::IsManagedDebuggerAttached()) - { - if (m_pStringFactory == NULL) - m_pStringFactory = new MdaFactory(); - - if (m_pGroups == NULL) - m_pGroups = new SArray(); - - SString* pStr = m_pStringFactory->Create(); - pStr->Set(W("managedDebugger")); - m_pGroups->Append(pStr); - m_bDisable = FALSE; - } - - if (ManagedDebuggingAssistants::IsUnmanagedDebuggerAttached()) - { - if (m_pStringFactory == NULL) - m_pStringFactory = new MdaFactory(); - - if (m_pGroups == NULL) - m_pGroups = new SArray(); - - SString* pStr = m_pStringFactory->Create(); - pStr->Set(W("unmanagedDebugger")); - m_pGroups->Append(pStr); - m_bDisable = FALSE; - } - - if (m_szMda) - { - if (m_pStringFactory == NULL) - m_pStringFactory = new MdaFactory(); - - if (m_pGroups == NULL) - m_pGroups = new SArray(); - - StackSString sszMda(m_szMda); - SString::Iterator s = sszMda.Begin(); - SString::Iterator e = s; - - while (true) - { - if (!sszMda.Find(e, W(';'))) - e = sszMda.End(); - SString* psszGroup = m_pStringFactory->Create(); - psszGroup->Set(sszMda, s, e); - - if (psszGroup->Equals(W("0"))) - { - m_pGroups->Clear(); - m_bDisable = TRUE; - } - else - { - m_pGroups->Append(psszGroup); - - m_bDisable = FALSE; - } - - if (e == sszMda.End()) - break; - s = ++e; - } - } - - if (m_bDisable == FALSE) - { - // If we get here, m_pStringFactory should already have been created. - _ASSERTE(m_pStringFactory != NULL); - - WCHAR szExe[_MAX_PATH]; - if (!WszGetModuleFileName(NULL, szExe, _MAX_PATH)) - return; - - // Construct file name of the config file - m_psszConfigFile = m_pStringFactory->Create(); - m_psszConfigFile->Set(szExe); - m_psszConfigFile->Append(W(".config")); - - // Construct file name of mda config file - m_psszMdaConfigFile = m_pStringFactory->Create(); - m_psszMdaConfigFile->Set(szExe); - m_psszMdaConfigFile->Append(W(".mda.config")); - } -} - -void ManagedDebuggingAssistants::EEStartupActivation() -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - // - // Read environment variable, then registry settings - // - MdaEnvironment env; - - if (env.IsDisabled()) - return; - - AllocateManagedDebuggingAssistants(); - - // - // ConfigFile Activation - // - g_mdaStaticHeap.m_pMda->EnvironmentActivation(&env); -} - -#ifdef _DEBUG -void ManagedDebuggingAssistants::DebugInitialize() -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - SO_INTOLERANT; - MODE_ANY; - } - CONTRACTL_END; - - // - // Validate MDA output on Debug builds - // - m_bValidateOutput = TRUE; - - // - // XmlValidationError - // - g_mdaStaticHeap.m_mdaXmlValidationError.Enable(); - - MdaSchema::ValidationResult validationResult; - - // - // Validate SchemaScheam - // - MdaXmlElement* pXmlSchemaSchema = m_pSchemaSchema->ToXml(m_pMdaXmlIndustry); - if (m_pSchemaSchema->Validate(pXmlSchemaSchema, &validationResult)->ValidationFailed()) - { - MDA_TRIGGER_ASSISTANT(XmlValidationError, ReportError(&validationResult)); - UNREACHABLE(); - } - - // - // Validate AssistantSchema - // - MdaXmlElement* pXmlAssistantSchema = m_pAssistantSchema->ToXml(m_pMdaXmlIndustry); - if (m_pSchemaSchema->Validate(pXmlAssistantSchema, &validationResult)->ValidationFailed()) - { - MDA_TRIGGER_ASSISTANT(XmlValidationError, ReportError(&validationResult)); - ASSERT(!W("You're modifications to MdaAssistantSchema for assistant input don't conform to XSD")); - } - - // - // Validate AssistantMsgSchema - // - MdaXmlElement* pXmlAssistantMsgSchema = m_pAssistantMsgSchema->ToXml(m_pMdaXmlIndustry); - if (m_pSchemaSchema->Validate(pXmlAssistantMsgSchema, &validationResult)->ValidationFailed()) - { - MDA_TRIGGER_ASSISTANT(XmlValidationError, ReportError(&validationResult)); - ASSERT(!W("You're modifications to MdaAssistantSchema for assistant output don't conform to XSD")); - } -} -#endif - -void ManagedDebuggingAssistants::ConfigFileActivation(LPCWSTR szConfigFile, MdaXmlIndustry* pXmlIndustry, MdaHashtable* pMdaXmlPairs) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - // Parse - MdaSchema::ValidationResult validationResult; - MdaXmlElement* pMdaConfig = MdaConfigFactory::ParseXmlStream(pXmlIndustry, szConfigFile); - if (!pMdaConfig) - return; - - // Validate - if (m_pAssistantSchema->Validate(pMdaConfig, &validationResult)->ValidationFailed()) - { - MDA_TRIGGER_ASSISTANT(InvalidConfigFile, ReportError(MdaElemDef(MdaConfig))); - g_mdaStaticHeap.DisableAll(); - return; - } - - // Activate - InlineSArray xmlMdaConfigs; - MdaXPath::FindElements(pMdaConfig, W("/mdaConfig/assistants/*"), &xmlMdaConfigs); - for(COUNT_T i = 0; i < xmlMdaConfigs.GetCount(); i ++) - { - MdaXmlElement* pXmlMdaConfig = xmlMdaConfigs[i]; - if (pXmlMdaConfig->GetAttribute(MdaAttrDecl(Enable))->GetValueAsBool()) - { - pMdaXmlPairs->Set(pXmlMdaConfig->GetName(), xmlMdaConfigs[i]); - } - else - { - if (pMdaXmlPairs->HasKey(pXmlMdaConfig->GetName())) - pMdaXmlPairs->DeleteValue(pXmlMdaConfig->GetName()); - } - } -} - -MdaXmlElement* ManagedDebuggingAssistants::GetSwitchActivationXml(MdaElemDeclDef mda) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (g_mdaAssistantIsSwitch[mda]) - { - MdaXmlElement* pXml = m_pMdaXmlIndustry->CreateElement()->SetDeclDef(mda); - pXml->AddAttributeBool(MdaAttrDecl(Enable), TRUE); - return pXml; - } - else - { - if (!m_pSwitchActivationXml) - { - MdaXmlElement* pXmlMdaConfig = m_pMdaXmlIndustry->CreateElement()->SetDeclDef(MdaElemDef(MdaConfig)); - m_pSwitchActivationXml = pXmlMdaConfig->AddChild(MdaElemDecl(Assistants)); - - for (COUNT_T i = 0; i < MdaElemDef(AssistantMax); i ++) - m_pSwitchActivationXml->AddChild((MdaElemDeclDef)i); - - MdaSchema::ValidationResult validationResult; - - // Validating the schema has the side-effect of initializing the default XML attributes - if (m_pAssistantSchema->Validate(pXmlMdaConfig, &validationResult)->ValidationFailed()) - ASSERT(!W("MDA Assistant must allow form.")); - } - - return m_pSwitchActivationXml->GetChild(mda); - } -} - -void ManagedDebuggingAssistants::ActivateGroup(LPCWSTR groupName, SArray* pGroupMdaXmlParis, MdaHashtable* pActivationMdaXmlPairs) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - StackSString sszGroupName(groupName); - BOOL bIsManagedDebuggerSet = sszGroupName.EqualsCaseInsensitive(W("managedDebugger")); - - SArray& groupMdaXmlParis = *pGroupMdaXmlParis; - - for (COUNT_T i = 0; i < groupMdaXmlParis.GetCount(); i++) - { - MdaElemDeclDef mda = groupMdaXmlParis[i]; - MdaXmlElement* pSwitchActivationXml = GetSwitchActivationXml(mda); - - PREFIX_ASSUME(pSwitchActivationXml != NULL); - - pSwitchActivationXml->AddAttributeBool(MdaAttrDecl(SuppressDialog), bIsManagedDebuggerSet); - - pActivationMdaXmlPairs->Set(MdaSchema::g_arElementNames[mda], pSwitchActivationXml); - } -} - -LPCWSTR ToLowerFirstChar(LPCWSTR name, MdaFactory* pSstringFactory) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - ASSERT(*name >= 'A' && *name <= 'Z'); - - SString* pOutput = pSstringFactory->Create(); - pOutput->Clear(); - pOutput->Append(*name - W('A') + W('a')); - pOutput->Append(&name[1]); - return pOutput->GetUnicode(); -} - -void ManagedDebuggingAssistants::EnvironmentActivation(MdaEnvironment* pEnvironment) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - if (pEnvironment->GetActivationMechanisms().GetCount() == 0) - return; - - MdaFactory > arrayFactory; - MdaFactory sstringFactory; - MdaHashtable mdaXmlPairs; - - // Activate - SArray& aActivationMechanisms = pEnvironment->GetActivationMechanisms(); - SArray* pGroup = NULL; - StackSArray* > aGroups; - -#define MDA_DEFINE_GROUPS -#include "mdaschema.inl" -#undef MDA_DEFINE_GROUPS - - // Match COMPlus_MDA env var to group - for (COUNT_T i = 0; i < aActivationMechanisms.GetCount(); i++) - { - SString& sszActivationMechanism = *aActivationMechanisms[i]; - - if (sszActivationMechanism.EqualsCaseInsensitive(W("ConfigFile")) || sszActivationMechanism.EqualsCaseInsensitive(W("1"))) - { - ConfigFileActivation(pEnvironment->GetMdaConfigFile(), m_pMdaXmlIndustry, &mdaXmlPairs); - } - else - { - COUNT_T cGroup = 0; - -#define MDA_ACTIVATE_GROUPS -#include "mdaschema.inl" -#undef MDA_ACTIVATE_GROUPS - -#define MDA_ACTIVATE_SINGLTON_GROUPS -#include "mdaschema.inl" -#undef MDA_ACTIVATE_SINGLTON_GROUPS - - } - } - - if (mdaXmlPairs.GetCount() == 0) - return; - - // Create - MdaXmlElement* pXmlAssistant = NULL; - -#define MDA_ASSISTANT_CREATION -#include "mdaschema.inl" -#undef MDA_ASSISTANT_CREATION -} - -typedef enum -{ - MDA_MSGBOX_NONE = 0, - MDA_MSGBOX_RETRY = 4, - MDA_MSGBOX_CANCLE = 2, -} MsgBoxResult; - -BOOL ManagedDebuggingAssistants::IsUnmanagedDebuggerAttached() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (IsDebuggerPresent()) - return TRUE; - - return FALSE; -} - -BOOL ManagedDebuggingAssistants::IsManagedDebuggerAttached() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - -#if DEBUGGING_SUPPORTED - if (CORDebuggerAttached()) - return TRUE; -#endif - - return FALSE; -} - -BOOL ManagedDebuggingAssistants::IsDebuggerAttached() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - return IsUnmanagedDebuggerAttached() || IsManagedDebuggerAttached(); -} - -MdaXmlElement* ManagedDebuggingAssistants::GetRootElement(MdaXmlElement* pMdaXmlRoot) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - pMdaXmlRoot->SetDeclDef(MdaElemDef(Msg)); - pMdaXmlRoot->AddAttributeSz(MdaAttrDecl(Xmlns), MDA_TARGET_NAMESPACE)->SetNs(W("mda")); - return pMdaXmlRoot; -} - - - -// -// MdaXmlMessage -// -BOOL IsFormatChar(WCHAR c) { LIMITED_METHOD_CONTRACT; return (c == W('\\') || c == W('!') || c == W('+') || c == W('.') || c == W(':') || c == W('-')); } - -// Logic copied from /fx/src/Xml/System/Xml/Core/XmlRawTextWriterGenerator.cxx::WriteAttributeTextBlock -SString& MdaXmlEscape(SString& sszBuffer, const SString& sszXml, BOOL bEscapeComment = FALSE) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - sszBuffer.Clear(); - - SString::CIterator itr = sszXml.Begin(); - SString::CIterator end = sszXml.End(); - - while (itr != end) - { - WCHAR c = *itr; - - switch(c) - { - case W('-'): - if (*(itr+1) == W('-') && bEscapeComment) - sszBuffer.Append(W("- ")); - else - sszBuffer.Append(W("-")); - break; - case W('&'): - sszBuffer.Append(W("&")); - break; - case W('<'): - sszBuffer.Append(W("<")); - break; - case W('>'): - sszBuffer.Append(W(">")); - break; - case W('"'): - sszBuffer.Append(W(""e;")); - break; - default: - sszBuffer.Append(c); - } - - itr++; - } - - return sszBuffer; -} - -SString* WrapString(SString& buffer, SString& sszString, SCOUNT_T cWidth, SCOUNT_T cIndent = 0, SCOUNT_T cPostIndent = 0) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - StackSString sszEscapedString; - MdaXmlEscape(sszEscapedString, sszString, TRUE); - - StackSString sszIndent; - for (SCOUNT_T i = 0; i < cIndent; i ++) - sszIndent.Append(W(" ")); - - StackSString sszPostIndent; - for (SCOUNT_T i = 0; i < cPostIndent; i ++) - sszPostIndent.Append(W(" ")); - - buffer.Append(sszIndent); - - SString::CIterator itr = sszEscapedString.Begin(); - SString::CIterator lineStart = sszEscapedString.Begin(); - SString::CIterator lineEnd = sszEscapedString.Begin(); - SString::CIterator lastFormatChar = sszEscapedString.Begin(); - SString::CIterator end = sszEscapedString.End(); - - while (itr != end) - { - if (*itr == W(' ')) - lineEnd = itr; - - // Keep track of reasonable breaks in member and file names... - if (IsFormatChar(*itr) && itr - lineStart < cWidth) - lastFormatChar = itr; - - if (itr - lineStart >= cWidth || *itr == W('\n')) - { - if (*itr == W('\n')) - lineEnd = itr; - - // If we didn't find a space or wrapping at found space wraps less than 3/5 of the line... - else if (lineEnd == end || itr - lineEnd > cWidth * 3 / 5) - { - // ...then if we found a format char, start the wrap there... - if (lastFormatChar != end) - lineEnd = lastFormatChar + 1; - // ...else just do a simple wrap... - else - lineEnd = itr; - } - - SString sszLine(sszEscapedString, lineStart, lineEnd); - buffer.Append(sszLine); - buffer.Append(sszPostIndent); - buffer.Append(W("\n")); - buffer.Append(sszIndent); - - lineStart = lineEnd; - - // If we wrapped on a space or a return than skip over that character as we already replaced it with a \n. - if (*lineEnd == W(' ') || *lineEnd == W('\n')) - lineStart++; - - lineEnd = end; - lastFormatChar = end; - } - - itr++; - } - - SString sszLine(sszEscapedString, lineStart, itr); - buffer.Append(sszLine); - - return &buffer; -} - -LPCWSTR ToUpperFirstChar(SString& buffer, LPCWSTR name) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - ASSERT(*name >= 'a' && *name <= 'z'); - - buffer.Clear(); - buffer.Append(*name - W('a') + W('A')); - buffer.Append(&name[1]); - return buffer.GetUnicode(); -} - -MdaXmlMessage::MdaXmlMessage(MdaAssistant* pAssistant, BOOL bBreak, MdaXmlElement** ppMdaXmlRoot) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(CheckPointer(g_mdaStaticHeap.m_pMda)); - } - CONTRACTL_END; - - m_pMdaAssistant = pAssistant; - m_bBreak = (pAssistant->GetSuppressDialog()) ? FALSE : bBreak; - m_pMdaXmlRoot = g_mdaStaticHeap.m_pMda->GetRootElement(m_mdaXmlIndustry.CreateElement()); - *ppMdaXmlRoot = m_pAssistantXmlRoot = pAssistant->GetRootElement(m_mdaXmlIndustry.CreateElement(), bBreak); -} - -MdaXmlMessage::MdaXmlMessage(MdaXmlElement** ppMdaXmlRoot) : m_bBreak(FALSE) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(CheckPointer(g_mdaStaticHeap.m_pMda)); - } - CONTRACTL_END; - - *ppMdaXmlRoot = m_pMdaXmlRoot = g_mdaStaticHeap.m_pMda->GetRootElement(m_mdaXmlIndustry.CreateElement()); -} - -BOOL MdaXmlMessage::ShouldLogToManagedDebugger() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - BOOL bUnmanagedDebuggerAttached = FALSE; - BOOL bManagedDebuggerAttached = FALSE; - BOOL bManagedDebugLoggingEnabled = FALSE; - - bUnmanagedDebuggerAttached = IsUnmanagedDebuggerAttached(); - -#if DEBUGGING_SUPPORTED - bManagedDebuggerAttached = IsManagedDebuggerAttached(); - bManagedDebugLoggingEnabled = (g_pDebugInterface && g_pDebugInterface->IsLoggingEnabled()); -#endif - - return (!bUnmanagedDebuggerAttached && bManagedDebuggerAttached && bManagedDebugLoggingEnabled); -} - -// Send an event for this MDA. -void MdaXmlMessage::SendEvent() -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - if (IsHostRegisteredForEvent(Event_MDAFired)) - { - // A host is registered for the MDA fired event so let's start by notifying the - // debugger is on is attached. - if (IsManagedDebuggerAttached() || IsUnmanagedDebuggerAttached()) - { - SendDebugEvent(); - } - - // Now that the debugger has been notified and continued, let's notify the host - // so it can take any action it deems neccessary based on the MDA that fired. - SendHostEvent(); - } - else - { - // We aren't hosted or no host registered for the MDA fired event so let's simply - // send the MDA to the debubber. Note that as opposed to the hosted case, we - // will force a JIT attach if no debugger is present. - SendDebugEvent(); - } -} - -// Send an event for this MDA. -void MdaXmlMessage::SendHostEvent() -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - MDAInfo info; - SString strStackTrace; - - EX_TRY - { - // Retrieve the textual representation of the managed stack trace and add it to - // the MDA information we give the host. - GetManagedStackTraceString(TRUE, strStackTrace); - } - EX_CATCH - { - // We failed to get the stack trace string. This isn't fatal, we will simply not be - // able to provide this information as part of the notification. - } - EX_END_CATCH(SwallowAllExceptions); - - // Set up the information and invoke the host to process the MDA fired event. - info.lpMDACaption = m_pMdaAssistant->GetName(); - info.lpStackTrace = strStackTrace; - info.lpMDAMessage = m_localizedMessage; - ProcessEventForHost(Event_MDAFired, &info); - - // If the host initiated a thread abort, we want to raise it immediatly to - // prevent any further code inside the VM from running and potentially - // crashing the process. - Thread *pThread = GetThread(); - TESTHOOKCALL(AppDomainCanBeUnloaded(pThread->GetDomain()->GetId().m_dwId,FALSE)); - - if (pThread && pThread->IsAbortInitiated()) - pThread->HandleThreadAbort(TRUE); -} - -// Send a managed debug event for this MDA. -// This will block until the debugger continues us. This means the debugger could to things like run callstacks -// and change debuggee state. -void MdaXmlMessage::SendDebugEvent() -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(CheckPointer(g_mdaStaticHeap.m_pMda)); - } - CONTRACTL_END; - - // Simple check to avoid getting XML string if we're not going to actually use it. - if (!IsManagedDebuggerAttached() && !IsUnmanagedDebuggerAttached() && !m_bBreak) - { - return; - } - - EX_TRY - { - StackSString sszXml; - LPCWSTR ns = NULL; - - MdaSchema * pSchema = g_mdaStaticHeap.m_pMda->m_pAssistantSchema; - ns = pSchema->SetRootAttributes(m_pMdaXmlRoot); - m_pMdaXmlRoot->ToXml(&sszXml, ns); - - // For managed + interop cases, send a managed debug event. - // If m_bBreak is true and no unmanaged debugger is attached trigger a jit-attach. - if (IsManagedDebuggerAttached() || (m_bBreak && !IsUnmanagedDebuggerAttached())) - { - // Get MDA name (this is the type) - StackSString sszMdaName; - ToUpperFirstChar(sszMdaName, m_pMdaAssistant->GetName()); - // SendMDANotification needs to be called in preemptive GC mode. - GCX_PREEMP(); - - // This will do two things: - // 1. If a managed debugger is attached, it will send the managed debug event for the MDA. - // 2. If it's a m_bBreak, we'll try to do a managed jit-attach. - // This blocks until continued. Since we're not slipping, we don't need the MDA_FLAG_SLIP flag. - g_pDebugInterface->SendMDANotification( - GetThread(), - &sszMdaName, - &m_localizedMessage, - &sszXml, - ((CorDebugMDAFlags) 0 ), - RunningInteractive() ? m_bBreak : FALSE); - } - - if (IsUnmanagedDebuggerAttached() && !IsManagedDebuggerAttached()) - { - // For native case, sent native debug event for logging. - WszOutputDebugString(sszXml.GetUnicode()); - - if (m_bBreak) - RetailBreak(); - } - } - EX_CATCH - { - // No global MDA state modified in TRY - } - EX_END_CATCH(SwallowAllExceptions); -} - -void MdaXmlMessage::SendMessagef(int resourceID, ...) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - StackSString sszResourcef; - sszResourcef.LoadResource(CCompRC::DesktopCLR, resourceID ); - ASSERT(!sszResourcef.IsEmpty()); - - va_list argItr; - va_start(argItr, resourceID); - m_localizedMessage.PVPrintf(sszResourcef, argItr); - va_end(argItr); - - SendMessage(); -} - - -void MdaXmlMessage::SendMessage(int resourceID) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - SendMessagef(resourceID); -} - -void MdaXmlMessage::SendMessage(LPCWSTR szMessage) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - m_localizedMessage.Set(szMessage); - - SendMessage(); -} - -void MdaXmlMessage::SendMessage() -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(CheckPointer(g_mdaStaticHeap.m_pMda)); - } - CONTRACTL_END; - -#if _DEBUG - if (g_mdaStaticHeap.m_pMda->m_bValidateOutput) - { - MdaSchema::ValidationResult validationResult; - if (g_mdaStaticHeap.m_pMda->m_pAssistantMsgSchema->Validate(m_pAssistantXmlRoot, &validationResult)->ValidationFailed()) - { - MDA_TRIGGER_ASSISTANT(XmlValidationError, ReportError(&validationResult)); - ASSERT(W("Your MDA assistant's output did not match its output schema.")); - } - } -#endif - - if (!m_localizedMessage.IsEmpty()) - { - StackSString sszComment(m_localizedMessage); - StackSString sszWrappedComment(W("\n")); - WrapString(sszWrappedComment, sszComment, 80, 7); - sszWrappedComment.Append(W("\n ")); - m_pMdaXmlRoot->AddChildComment(sszWrappedComment.GetUnicode()); - } - - m_pMdaXmlRoot->AddChild(m_pAssistantXmlRoot); - - // Send applicable debug event (managed, native, interop) for this MDA. - // If this is a severe probe, it may trigger a jit-attach - SendEvent(); -} - - -// -// MdaXPath::FindXXX -// - -void MdaXPath::Find(SArray& args, SString* pWildCard, va_list argItr) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - for (COUNT_T i = 0; i < GetArgCount(); i ++) - { - XPathVarType varType = m_argTypes[i]; - - if (varType == XPathVarElemDeclDef) - args[i].m_u.m_elemDeclDef = va_arg(argItr, MdaElemDeclDef); - - else if (varType == XPathVarAttrDeclDef) - args[i].m_u.m_attrDeclDef = va_arg(argItr, MdaAttrDeclDef); - - else if (varType == XPathVarAttrBool) - args[i].m_u.m_bool = va_arg(argItr, BOOL); - - else if (varType == XPathVarAttrINT32) - args[i].m_u.m_int32 = va_arg(argItr, INT32); - - else if (varType == XPathVarAttrSString) - { - SString* pSString = va_arg(argItr, SString*); - ASSERT(CheckPointer(pSString, NULL_OK)); - if (!pSString) - pSString = pWildCard; - args[i].m_u.m_pSstr = pSString; - } - - else { UNREACHABLE(); } - } -} - -MdaXmlElement* MdaXPath::FindElement(MdaXmlElement* pRoot, ...) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (!pRoot) - return NULL; - - va_list argItr; - va_start(argItr, pRoot); - - SString wildCard; - InlineSArray args; - Find(args, &wildCard, argItr); - - MdaXPathResult result(&args); - m_pCompiledQuery->Run(pRoot, &result); - - va_end(argItr); - return result.GetXmlElement(); -} - -MdaXmlAttribute* MdaXPath::FindAttribute(MdaXmlElement* pRoot, ...) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (!pRoot) - return NULL; - - va_list argItr; - va_start(argItr, pRoot); - - SString wildCard; - InlineSArray args; - Find(args, &wildCard, argItr); - - MdaXPathResult result(&args); - m_pCompiledQuery->Run(pRoot, &result); - - va_end(argItr); - return result.GetXmlAttribute(); -} - -SArray* MdaXPath::FindElements(MdaXmlElement* pRoot, SArray* pResult, ...) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (!pRoot) - return NULL; - - va_list argItr; - va_start(argItr, pResult); - - SString wildCard; - InlineSArray args; - Find(args, &wildCard, argItr); - - MdaXPathResult result(pResult, &args); - m_pCompiledQuery->Run(pRoot, &result); - - va_end(argItr); - return pResult; -} - -SArray* MdaXPath::FindAttributes(MdaXmlElement* pRoot, SArray* pResult, ...) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (!pRoot) - return NULL; - - va_list argItr; - va_start(argItr, pResult); - - SString wildCard; - InlineSArray args; - Find(args, &wildCard, argItr); - - MdaXPathResult result(pResult, &args); - m_pCompiledQuery->Run(pRoot, &result); - - va_end(argItr); - return pResult; -} - - -// -// MdaXPath::MdaXPathCompiler -- Lexifier -// - -#define ISWHITE(ch) (ch == W(' ') || ch == W('\t') || ch == W('\n')) -#define ISRESERVED(ch) (wcschr(W("./()[]&|=@*?':"), ch) != NULL) -#define ISMDAID(ch) (!ISWHITE(ch) && !ISRESERVED(ch)) - -MdaXPath::MdaXPathCompiler::MdaXPathTokens MdaXPath::MdaXPathCompiler::LexAToken() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (*m_itr == W('\0')) - return MdaXPathEnd; - - if (ISWHITE(*m_itr)) - { - m_itr++; - return LexAToken(); - } - - if (ISMDAID(*m_itr)) - { - m_identifier.Clear(); - - do - { - m_identifier.Append(*m_itr); - m_itr++; - } - while(ISMDAID(*m_itr)); - - m_identifier.Append(W("\0")); - return MdaXPathIdentifier; - } - - if (*m_itr == W('\'')) - { - m_identifier.Clear(); - - m_itr++; - - while(*m_itr != W('\'')) - { - m_identifier.Append(*m_itr); - m_itr++; - } - - m_identifier.Append(W("\0")); - - m_itr++; - return MdaXPathQuotedString; - } - - WCHAR c = *m_itr; - m_itr++; - switch(c) - { - case W('.'): return MdaXPathDot; - case W('/'): return MdaXPathSlash; - case W('('): return MdaXPathOpenParen; - case W(')'): return MdaXPathCloseParen; - case W('['): return MdaXPathOpenSqBracket; - case W(']'): return MdaXPathCloseSqBracket; - case W('&'): return MdaXPathLogicalAnd; - case W('|'): return MdaXPathLogicalOr; - case W('='): return MdaXPathEquals; - case W('@'): return MdaXPathAtSign; - case W('*'): return MdaXPathAstrix; - case W('?'): return MdaXPathQMark; - } - - UNREACHABLE(); -} - - -// -// MdaXPath::MdaXPathCompiler -- Parser -// - -// XPATH -// '/' ELEMENT_EXPR end -// '/' ELEMENT_EXPR XPATH -// '/' ATTRIBUTE end -MdaXPath::MdaXPathBase* MdaXPath::MdaXPathCompiler::XPATH() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - PRECONDITION(TokenIs(MdaXPathXPATH)); - - MdaXPathElement* pElementExpr = NULL; - - NextToken(); - if (TokenIs(MdaXPathELEMENT_EXPR)) - pElementExpr = ELEMENT_EXPR(); - - else if (TokenIs(MdaXPathATTRIBUTE)) - { - MdaXPathAttribute* pAttr = ATTRIBUTE(); - pAttr->MarkAsTarget(); - NextToken(); - ASSERT(TokenIs(MdaXPathEnd)); - return pAttr; - } - - else { UNREACHABLE(); } - - - if (TokenIs(MdaXPathEnd)) - return pElementExpr->MarkAsTarget(); - - else if (TokenIs(MdaXPathXPATH)) - return pElementExpr->SetChild(XPATH()); - - else { UNREACHABLE(); } -} - -// ATTRIBUTE -// '@' id -// '@' '?' -MdaXPath::MdaXPathAttribute* MdaXPath::MdaXPathCompiler::ATTRIBUTE() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - PRECONDITION(TokenIs(MdaXPathATTRIBUTE)); - - MdaXPathAttribute* pAttr = NULL; - - NextToken(); - if (TokenIs(MdaXPathQMark)) - { - pAttr = m_pXPath->m_attrFactory.Create()->SetName(++m_pXPath->m_cArgs); - *m_pXPath->m_argTypes.Append() = XPathVarAttrDeclDef; - } - - else if (TokenIs(MdaXPathIdentifier)) - { - pAttr = m_pXPath->m_attrFactory.Create()->SetName(MdaSchema::GetAttributeType(GetIdentifier())); - } - - else { UNREACHABLE(); } - - NextToken(); - return pAttr; -} - -// ELEMENT_EXPR -// ELEMENT '[' FILTER_EXPR ']' -// ELEMENT -MdaXPath::MdaXPathElement* MdaXPath::MdaXPathCompiler::ELEMENT_EXPR() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - PRECONDITION(TokenIs(MdaXPathELEMENT_EXPR)); - - MdaXPathElement* pElement = ELEMENT(); - - if (TokenIs(MdaXPathOpenSqBracket)) - { - NextToken(); - pElement->SetQualifier(FILTER_EXPR()); - ASSERT(TokenIs(MdaXPathCloseSqBracket)); - - NextToken(); - } - - return pElement; -} - -// FILTER_EXPR -// FILTER -// '(' FILTER ')' -// FILTER '&' FILTER -// FILTER '|' FILTER -MdaXPath::MdaXPathBase* MdaXPath::MdaXPathCompiler::FILTER_EXPR() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - PRECONDITION(TokenIs(MdaXPathFILTER_EXPR)); - - // '(' FILTER ')' - if (TokenIs(MdaXPathOpenParen)) - { - MdaXPath::MdaXPathBase* pFilter = FILTER(); - ASSERT(TokenIs(MdaXPathCloseParen)); - - NextToken(); - return pFilter; - } - - if (TokenIs(MdaXPathFILTER)) - { - MdaXPath::MdaXPathBase* pFilter = FILTER(); - - // FILTER '&' FILTER - if (TokenIs(MdaXPathLogicalAnd)) - { - NextToken(); - return m_pXPath->m_logicalOpFactory.Create()->Initialize(TRUE, pFilter, FILTER()); - } - - // FILTER '|' FILTER - if (TokenIs(MdaXPathLogicalOr)) - { - NextToken(); - return m_pXPath->m_logicalOpFactory.Create()->Initialize(FALSE, pFilter, FILTER()); - } - - // FILTER - return pFilter; - } - - UNREACHABLE(); -} - -// FILTER -// ELEMENT_EXPR -// ATTRIBUTE_FILTER -// ELEMENT_EXPR ATTRIBUTE_FILTER -MdaXPath::MdaXPathBase* MdaXPath::MdaXPathCompiler::FILTER() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - PRECONDITION(TokenIs(MdaXPathFILTER)); - - if (TokenIs(MdaXPathELEMENT_EXPR)) - { - MdaXPathElement* pElementExpr = ELEMENT_EXPR(); - - if (TokenIs(MdaXPathATTRIBUTE_FILTER)) - pElementExpr->SetQualifier(ATTRIBUTE_FILTER()); - - return pElementExpr; - } - - if (TokenIs(MdaXPathATTRIBUTE_FILTER)) - return ATTRIBUTE_FILTER(); - - UNREACHABLE(); -} - -// ELEMENT -// id -// '*' -// '?' -MdaXPath::MdaXPathElement* MdaXPath::MdaXPathCompiler::ELEMENT() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - PRECONDITION(TokenIs(MdaXPathELEMENT)); - - MdaXPathElement* pElement = m_pXPath->m_elementFactory.Create(); - - if (TokenIs(MdaXPathAstrix)) - pElement->Initialize(); - - else if (TokenIs(MdaXPathIdentifier)) - pElement->Initialize(MdaSchema::GetElementType(GetIdentifier())); - - else if (TokenIs(MdaXPathQMark)) - { - pElement->Initialize(++m_pXPath->m_cArgs); - *m_pXPath->m_argTypes.Append() = XPathVarElemDeclDef; - } - - else { UNREACHABLE(); } - - NextToken(); - return pElement; -} - -// ATTRIBUTE_FILTER(); -// ATTRIBUTE -// ATTRIBUTE '=' ''' id ''' -// ATTRIBUTE '=' '?' -MdaXPath::MdaXPathAttribute* MdaXPath::MdaXPathCompiler::ATTRIBUTE_FILTER() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - PRECONDITION(TokenIs(MdaXPathATTRIBUTE_FILTER)); - - MdaXPathAttribute* pAttr = ATTRIBUTE(); - - if (TokenIs(MdaXPathEquals)) - { - NextToken(); - - if (TokenIs(MdaXPathQuotedString)) - { - NextToken(); - pAttr->SetValue(GetIdentifier()); - - NextToken(); - ASSERT(TokenIs(MdaXPathQuotedString)); - } - else if (TokenIs(MdaXPathQMark)) - { - pAttr->SetValue(++m_pXPath->m_cArgs); - *m_pXPath->m_argTypes.Append() = XPathVarAttrSString; - } - else { UNREACHABLE(); } - } - - NextToken(); - return pAttr; -} - - -// -// MdaXPath::Elements::Run() -- The search engine -// - -BOOL MdaXPath::MdaXPathElement::Run(MdaXmlElement* pElement, MdaXPathResult* pResult) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - BOOL bAnyPass = FALSE; - if (pResult->IsRoot()) - { - bAnyPass |= RunOnChild(pElement, pResult); - } - else - { - SArray& children = pElement->GetChildren(); - - for (UINT32 i = 0; i < children.GetCount(); i ++) - { - bAnyPass |= RunOnChild(children[i], pResult); - } - } - - return bAnyPass; -} - -BOOL MdaXPath::MdaXPathElement::RunOnChild(MdaXmlElement* pElement, MdaXPathResult* pResult) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - MdaElemDeclDef name = m_nameArg == NOT_VARIABLE ? m_name : pResult->GetArgs()[m_nameArg].m_u.m_elemDeclDef; - - if (name != MdaElemUndefined && name != pElement->GetDeclDef()) - return FALSE; - - if (m_pQualifier && !m_pQualifier->Run(pElement, pResult)) - return FALSE; - - if (m_pChild && !m_pChild->Run(pElement, pResult)) - return FALSE; - - if (m_bIsTarget) - { - ASSERT(!m_pChild); - pResult->AddMatch(pElement); - } - - return TRUE; -} - -BOOL MdaXPath::MdaXPathAttribute::Run(MdaXmlElement* pElement, MdaXPathResult* pResult) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - MdaAttrDeclDef name = m_nameArg == NOT_VARIABLE ? m_name : pResult->GetArgs()[m_nameArg].m_u.m_attrDeclDef; - SString& value = m_valueArg == NOT_VARIABLE ? m_value : *pResult->GetArgs()[m_valueArg].m_u.m_pSstr; - - MdaXmlAttribute* pAttr = pElement->GetAttribute(name); - if (!pAttr) - return FALSE; - - LPCWSTR szAttrValue = pAttr->GetValue(); - if (!value.IsEmpty() && *szAttrValue != W('*') && !value.Equals(szAttrValue)) - return FALSE; - - if (m_bIsTarget) - pResult->AddMatch(pElement); - - return TRUE; -} - -BOOL MdaXPath::MdaXPathLogicalOp::Run(MdaXmlElement* pParent, MdaXPathResult* pResult) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (m_andOp) - return m_pLhs->Run(pParent, pResult) && m_pRhs->Run(pParent, pResult); - - return m_pLhs->Run(pParent, pResult) || m_pRhs->Run(pParent, pResult); -} - - -// -// MdaSchema -// - -MdaHashtable* MdaSchema::g_pHtElementType; -MdaHashtable* MdaSchema::g_pHtAttributeType; -LPCWSTR MdaSchema::g_arElementNames[MdaElemEnd]; -LPCWSTR MdaSchema::g_arAttributeNames[MdaAttrEnd]; -MdaFactory* MdaSchema::g_pSstringFactory; -MdaElemDeclDef MdaSchema::MdaSchemaTypeToElemDef[MdaSchema::MdaSchemaTypeEnd]; -MdaSchema::MdaSchemaMetaType MdaSchema::MdaSchemaTypeToMetaType[MdaSchema::MdaSchemaTypeEnd]; - -LPCWSTR MdaSchema::ToLowerFirstChar(LPCWSTR name) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - return ::ToLowerFirstChar(name, g_pSstringFactory); -} - -void MdaSchema::Initialize() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - g_pHtElementType = new MdaHashtable(); - g_pHtAttributeType = new MdaHashtable(); - g_pSstringFactory = new MdaFactory(); - - COUNT_T i = 0; - MdaSchemaTypeToElemDef[i++] = MdaElemDef(Sequence); // MdaSchemaSequenceType - MdaSchemaTypeToElemDef[i++] = MdaElemDef(Choice); // MdaSchemaChoiceType - MdaSchemaTypeToElemDef[i++] = MdaElemDef(Group); // MdaSchemaGroupType - MdaSchemaTypeToElemDef[i++] = MdaElemDef(Group); // MdaSchemaGroupRefType - MdaSchemaTypeToElemDef[i++] = MdaElemDef(Schema); // MdaSchemaRootType - MdaSchemaTypeToElemDef[i++] = MdaElemDef(Attribute); // MdaSchemaAttributeType - MdaSchemaTypeToElemDef[i++] = MdaElemDef(Element); // MdaSchemaElementType - MdaSchemaTypeToElemDef[i++] = MdaElemDef(ComplexType); // MdaSchemaComplexTypeType - MdaSchemaTypeToElemDef[i++] = MdaElemDef(ComplexType); // MdaSchemaComplexTypeDefType - MdaSchemaTypeToElemDef[i++] = MdaElemDef(Element); // MdaSchemaElementRefTyp - MdaSchemaTypeToElemDef[i++] = MdaElemDef(Extension); // MdaSchemaExtensionType - MdaSchemaTypeToElemDef[i++] = MdaElemDef(Element); // MdaSchemaElementRefTypeType - MdaSchemaTypeToElemDef[i++] = MdaElemDef(ComplexContent); // MdaSchemaComplexContentType - MdaSchemaTypeToElemDef[i++] = MdaElemDef(Element); // MdaSchemaElementAnyType - - i = 0; - MdaSchemaTypeToMetaType[i++] = MdaSchemaMataTypePattern; // MdaSchemaSequenceType - MdaSchemaTypeToMetaType[i++] = MdaSchemaMataTypePattern; // MdaSchemaChoiceType - MdaSchemaTypeToMetaType[i++] = (MdaSchemaMetaType)(MdaSchemaMataTypePattern | MdaSchemaMataTypeDeclDef); // MdaSchemaGroupType - MdaSchemaTypeToMetaType[i++] = (MdaSchemaMetaType)(MdaSchemaMataTypePattern | MdaSchemaMataTypeRef); // MdaSchemaGroupRefType - MdaSchemaTypeToMetaType[i++] = MdaSchemaMataNone; // MdaSchemaRootType - MdaSchemaTypeToMetaType[i++] = MdaSchemaMataNone; // MdaSchemaAttributeType - MdaSchemaTypeToMetaType[i++] = MdaSchemaMataTypeDeclDef; // MdaSchemaElementType - MdaSchemaTypeToMetaType[i++] = (MdaSchemaMetaType)(MdaSchemaMataNone | MdaSchemaMataMayHaveAttributes); // MdaSchemaComplexTypeType - MdaSchemaTypeToMetaType[i++] = (MdaSchemaMetaType)(MdaSchemaMataTypeDeclDef | MdaSchemaMataMayHaveAttributes); // MdaSchemaComplexTypeDefType - MdaSchemaTypeToMetaType[i++] = MdaSchemaMataTypeRef; // MdaSchemaElementRefTyp - MdaSchemaTypeToMetaType[i++] = (MdaSchemaMetaType)(MdaSchemaMataTypeRef | MdaSchemaMataMayHaveAttributes); // MdaSchemaExtensionType - MdaSchemaTypeToMetaType[i++] = (MdaSchemaMetaType)(MdaSchemaMataTypeDeclDef | MdaSchemaMataTypeRef); // MdaSchemaElementRefTypeType - MdaSchemaTypeToMetaType[i++] = MdaSchemaMataNone; // MdaSchemaComplexContentType - MdaSchemaTypeToMetaType[i++] = MdaSchemaMataTypeDeclDef; // MdaSchemaElementAnyType - - i = 0; -#define MDA_MAP_ASSISTANT_DEFINITION_TO_NAME -#include "mdaschema.inl" -#undef MDA_MAP_ASSISTANT_DEFINITION_TO_NAME - g_arElementNames[i++] = NULL; -#define MDA_MAP_ELEMENT_DEFINITION_TO_NAME -#include "mdaschema.inl" -#undef MDA_MAP_ELEMENT_DEFINITION_TO_NAME - g_arElementNames[i++] = NULL; -#define MDA_MAP_ELEMENT_DECLARATION_TO_NAME -#include "mdaschema.inl" -#undef MDA_MAP_ELEMENT_DECLARATION_TO_NAME - g_arElementNames[i++] = NULL; // Max - g_arElementNames[i++] = W("!--"); // Comment - g_arElementNames[i++] = NULL; // Undefined - - i = 0; -#define MDA_MAP_ATTRIBUTE_DECLARATION_TO_NAME -#include "mdaschema.inl" -#undef MDA_MAP_ATTRIBUTE_DECLARATION_TO_NAME - -#define MDA_MAP_ASSISTANT_NAME_TO_DEFINITION -#include "mdaschema.inl" -#undef MDA_MAP_ASSISTANT_NAME_TO_DEFINITION - -#define MDA_MAP_ELEMENT_NAME_TO_DEFINITION -#include "mdaschema.inl" -#undef MDA_MAP_ELEMENT_NAME_TO_DEFINITION - -#define MDA_MAP_ELEMENT_NAME_TO_DECLARATION -#include "mdaschema.inl" -#undef MDA_MAP_ELEMENT_NAME_TO_DECLARATION - -#define MDA_MAP_ATTRIBUTE_NAME_TO_DECLARATION -#include "mdaschema.inl" -#undef MDA_MAP_ATTRIBUTE_NAME_TO_DECLARATION -} - -MdaElemDeclDef MdaSchema::GetElementType(LPCWSTR name, BOOL bAssertDefined) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - MdaElemDeclDef type; - - if (!g_pHtElementType->Get(name, &type)) - { - ASSERT(!bAssertDefined); - return MdaElemUndefined; - } - - return type; -} - -LPCWSTR MdaSchema::GetElementName(MdaElemDeclDef type) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - PRECONDITION(type >= 0 && type < MdaElemUndefined); - return g_arElementNames[type]; -} - -MdaAttrDeclDef MdaSchema::GetAttributeType(LPCWSTR name, BOOL bAssertDefined) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - MdaAttrDeclDef type; - - if (!g_pHtAttributeType->Get(name, &type)) - { - ASSERT(!bAssertDefined); - return MdaAttrUndefined; - } - - return type; -} - -LPCWSTR MdaSchema::GetAttributeName(MdaAttrDeclDef type) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - return g_arAttributeNames[type]; -} - -// TODO: Validation error reporting needs work -MdaSchema::ValidationResult* MdaSchema::Validate(MdaXmlElement* pRoot, ValidationResult* pResult) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - pResult->Initialize(this, pRoot); - - MdaSchemaBase* pXsd = *GetDef(pRoot->GetDeclDef()); - ASSERT((CheckPointer(pXsd) || (pRoot->GetDeclDef() > MdaElemDecl(Max))) && W("You likley did not include a MDA_DEFINE_OUTPUT section in your schema!")); - - BOOL bValidationSucceeded = pXsd ? pXsd->Validate(pRoot, pResult) : FALSE; - - if (bValidationSucceeded) - pResult->ResetResult(); - else - pResult->SetError(); - - ASSERT(pResult->ValidationFailed() == !bValidationSucceeded); - return pResult; -} - -MdaSchema::MdaSchema() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - for(COUNT_T i = 0; i < MdaElemEnd; i ++) - m_definitions[i] = NULL; -} - - -// -// MdaAssistantSchema -// - -MdaAssistantSchema::MdaAssistantSchema() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - -#define MDA_DEFINE_ASSISTANT_SCHEMA -#include "mdaschema.inl" -#undef MDA_DEFINE_ASSISTANT_SCHEMA - -#define MDA_DEFINE_MDA_ASSISTANT_CONFIG_GROUP -#include "mdaschema.inl" -#undef MDA_DEFINE_MDA_ASSISTANT_CONFIG_GROUP -} - -LPCWSTR MdaAssistantSchema::SetRootAttributes(MdaXmlElement* pXml) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - //pXml->AddAttribute(W("xmlns:") MDA_SCHEMA_PREFIX, MDA_TARGET_NAMESPACE); - //pXml->AddAttribute(W("xmlns:xsi"), W("http://www.w3.org/2001/XMLSchema-instance")); - return MDA_SCHEMA_PREFIX; -} - - -// -// MdaAssistantMsgSchema -// - -MdaAssistantMsgSchema::MdaAssistantMsgSchema() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - -#define MDA_DEFINE_ASSISTANT_MSG_SCHEMA -#include "mdaschema.inl" -#undef MDA_DEFINE_ASSISTANT_MSG_SCHEMA - -#define MDA_DEFINE_MDA_ASSISTANT_MSG_GROUP -#include "mdaschema.inl" -#undef MDA_DEFINE_MDA_ASSISTANT_MSG_GROUP -} - -LPCWSTR MdaAssistantMsgSchema::SetRootAttributes(MdaXmlElement* pXml) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - //pXml->AddAttribute(W("xmlns:") MDA_SCHEMA_PREFIX, MDA_TARGET_NAMESPACE); - //pXml->AddAttribute(W("xmlns:xsi"), W("http://www.w3.org/2001/XMLSchema-instance")); - return MDA_SCHEMA_PREFIX; -} - - -// -// MdaSchemaSchema -// - -MdaSchemaSchema::MdaSchemaSchema() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - -#define MDA_DEFINE_SCHEMA_SCHEMA -#include "mdaschema.inl" -#undef MDA_DEFINE_SCHEMA_SCHEMA -} - -LPCWSTR MdaSchemaSchema::SetRootAttributes(MdaXmlElement* pXml) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - pXml->AddAttributeSz(MdaAttrDecl(TargetNamespace), MDA_TARGET_NAMESPACE); - pXml->AddAttributeSz(MdaAttrDecl(Xmlns), W("http://www.w3.org/2001/XMLSchema"))->SetNs(W("xs")); - pXml->AddAttributeSz(MdaAttrDecl(Xmlns), MDA_TARGET_NAMESPACE); - return W("xs"); -} - - -// -// MdaSchema::MdaSchemaXXX -// -MdaXmlElement* MdaSchema::MdaSchemaBase::ToXml(MdaXmlIndustry* pMdaXmlIndustry, MdaSchemaBase* pViolation) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - return ToXml(pMdaXmlIndustry->CreateElement(), pViolation); -} - -MdaXmlElement* MdaSchema::MdaSchemaBase::ToXml(MdaXmlElement* pXmlRoot, MdaSchemaBase* pViolation) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - LPCWSTR debugName = GetName(); - - MdaXmlElement* pXml = pXmlRoot->AddChild(GetSchemaDeclDef()); - SetAttributes(pXml); - -// if (this == pViolation) -// pXml->AddAttributeSz(MdaAttrDecl(Violated), W("---- THIS XSD ELEMENT VIOLATED -----")); - - if (m_children.GetCount() == 1 && - m_children[0]->GetSchemaDeclDef() == MdaElemDef(ComplexType) && - m_children[0]->m_children.GetCount() == 0 && - (!MayHaveAttr(m_children[0]) || - m_children[0]->GetAttributes().GetCount() == 0)) - { - // Convert to - return pXml; - } - - for(COUNT_T i = 0; i < m_children.GetCount(); i ++) - { - debugName = m_children[i]->GetName(); - m_children[i]->ToXml(pXml, pViolation); - } - - if (MayHaveAttr(this)) - { - SArray& attributes = GetAttributes(); - for(COUNT_T j = 0; j < attributes.GetCount(); j ++) - { - debugName = attributes[j]->GetName(); - attributes[j]->ToXml(pXml, pViolation); - } - } - - return pXml; -} - - -void MdaSchema::MdaSchemaBase::AddChild(MdaSchemaBase* pElement) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (pElement->GetSchemaDeclDef() == MdaElemDef(Attribute)) - *GetAttributes().Append() = (MdaSchemaAttribute*)pElement; - else - *m_children.Append() = pElement; -} - -// -// Validation -// - -#define CpdXsdIfFailGo(EXPR) do { if (!(EXPR)) { goto Fail; } } while (0) -#define CpdXsdTest(EXPR) do { if (!(EXPR)) { pResult->SetError(this, pElement); goto Fail; } } while (0) -#define MDA_XSD_VERIFY_OK return TRUE; -#define MDA_XSD_VERIFY_FAIL Fail: return FALSE; - -BOOL MdaSchema::MdaSchemaElement::Validate(MdaXmlElement* pElement, ValidationResult* pResult) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - StackSString buffer; - LPCWSTR debug = pElement->DebugToString(&buffer); - - CpdXsdTest(pElement->GetDeclDef() == GetDeclDef()); - - for(COUNT_T i = 0; i < m_children.GetCount(); i++) - CpdXsdIfFailGo(m_children[i]->Validate(pElement, pResult)); - - MDA_XSD_VERIFY_OK; - MDA_XSD_VERIFY_FAIL; -} - -BOOL MdaSchema::MdaSchemaSequence::ValidatePattern(MdaXmlElement* pElement, ValidationResult* pResult, COUNT_T* pCount) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - StackSString buffer; - LPCWSTR debug = pElement->DebugToString(&buffer); - - COUNT_T cPeriod = m_children.GetCount(); - COUNT_T cChildren = pElement->GetChildren().GetCount(); - COUNT_T cCurrent = *pCount; - COUNT_T cCount = cCurrent; - COUNT_T cMatches = 0; - - if (cPeriod == 0) - return TRUE; - - while(cCurrent <= cChildren) - { - MdaSchemaBase* pXsd = m_children[cMatches % cPeriod]; - if (pXsd->GetSchemaDeclDef() == MdaElemDef(Element)) - { - if (cCurrent == cChildren) - break; - - if (!pXsd->Validate(pElement->GetChildren()[cCurrent], pResult)) - break; - - cCurrent++; - } - else - { - ASSERT(IsPattern(pXsd)); - if (!pXsd->ValidatePattern(pElement, pResult, &cCurrent)) - break; - } - - cMatches++; - - // One period matched - if (cMatches % cPeriod == 0) - cCount = cCurrent; - - // Maximum periods matcheds - if (cMatches / cPeriod == m_max) - break; - } - - // Test if the minumum number periods have been matched - if (cMatches / cPeriod < m_min) - return FALSE; - - // Update the position past the matched elements - *pCount = cCount; - - return TRUE; -} - -BOOL MdaSchema::MdaSchemaChoice::ValidatePattern(MdaXmlElement* pElement, ValidationResult* pResult, COUNT_T* pCount) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - StackSString buffer; - LPCWSTR debug = pElement->DebugToString(&buffer); - - BOOL bFound = FALSE; - COUNT_T cCurrent = *pCount; - COUNT_T cChildren = pElement->GetChildren().GetCount(); - - for(COUNT_T cXsd = 0; cXsd < m_children.GetCount(); cXsd++) - { - MdaSchemaBase* pXsd = m_children[cXsd]; - - if (IsPattern(pXsd)) - { - COUNT_T cOldCurrent = cCurrent; - if (pXsd->ValidatePattern(pElement, pResult, &cCurrent)) - { - // "Empty matches" only allowed in choice pattern if there are no children to match - if (cOldCurrent != cCurrent || cChildren == 0) - { - bFound = TRUE; - break; - } - } - } - else - { - if (cCurrent == cChildren) - break; - - if (pXsd->Validate(pElement->GetChildren()[cCurrent], pResult)) - { - cCurrent++; - bFound = TRUE; - break; - } - } - } - - CpdXsdIfFailGo(bFound); - - *pCount = cCurrent; - - MDA_XSD_VERIFY_OK; - MDA_XSD_VERIFY_FAIL; -} - -#define this pThis -BOOL MdaSchema::Validate(MdaSchemaAttribute* pThis, MdaXmlElement* pElement, ValidationResult* pResult) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - StackSString sszValue; - MdaXmlAttribute* pAttr = (MdaXmlAttribute*)pElement->GetAttribute(pThis->m_declDef); - - if (!pAttr && !pThis->m_szDefault.IsEmpty()) - { - pAttr = pElement->AddDefaultAttribute(pThis->m_declDef, pThis->m_szDefault.GetUnicode()); - } - - if (!pAttr) - { - CpdXsdTest(!pThis->m_bRequired); - return TRUE; - } - -#ifdef _DEBUG - // Only necessary for validation of assistant output - if (pAttr->m_type != MdaSchemaPrimitiveUnknown) - { - CpdXsdTest(pAttr->m_type == pThis->m_type); - return TRUE; - } -#endif - - LPCWSTR szValue = pAttr->GetValue(); - sszValue.Set(szValue); - - if (pThis->m_type == MdaSchemaPrimitiveSString) - { - /* accept all strings? */ - } - else if (pThis->m_type == MdaSchemaPrimitiveINT32) - { - CpdXsdTest(!sszValue.IsEmpty() && sszValue.GetCount() != 0); - - for (COUNT_T i = 0; i < sszValue.GetCount(); i ++) - { - if (i == 0 && *szValue == W('-') && sszValue.GetCount() > 1) - continue; - - CpdXsdTest(IS_DIGIT(szValue[i])); - } - - pAttr->SetINT32(_wtoi(szValue)); - } - else if (pThis->m_type == MdaSchemaPrimitiveBOOL) - { - CpdXsdTest(!sszValue.IsEmpty() && sszValue.GetCount() != 0); - - if (sszValue.Equals(W("true"))) - pAttr->SetBOOL(true); - else if (sszValue.Equals(W("false"))) - pAttr->SetBOOL(false); - else - CpdXsdTest(FALSE); - } - - MDA_XSD_VERIFY_OK; - MDA_XSD_VERIFY_FAIL; -} -#undef this - -BOOL MdaSchema::MdaSchemaBase::Validate(MdaXmlElement* pElement, ValidationResult* pResult) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - COUNT_T count = 0; - - CpdXsdTest(ValidatePattern(pElement, pResult, &count)); - - CpdXsdTest(count == pElement->GetChildren().GetCount()); - - MDA_XSD_VERIFY_OK; - MDA_XSD_VERIFY_FAIL; -} - -BOOL MdaSchema::MdaSchemaRoot::Validate(MdaXmlElement* pElement, ValidationResult* pResult) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - for(COUNT_T i = 0; i < m_children.GetCount(); i++) - CpdXsdIfFailGo(m_children[i]->Validate(pElement, pResult)); - - MDA_XSD_VERIFY_OK; - MDA_XSD_VERIFY_FAIL; -} - -BOOL MdaSchema::MdaSchemaComplexType::Validate(MdaXmlElement* pElement, ValidationResult* pResult) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - for(COUNT_T i = 0; i < m_children.GetCount(); i++) - CpdXsdIfFailGo(m_children[i]->Validate(pElement, pResult)); - - for(COUNT_T i = 0; i < m_attributes.GetCount(); i++) - CpdXsdIfFailGo(m_attributes[i]->Validate(pElement, pResult)); - - MDA_XSD_VERIFY_OK; - MDA_XSD_VERIFY_FAIL; -} - -BOOL MdaSchema::MdaSchemaComplexTypeDef::Validate(MdaXmlElement* pElement, ValidationResult* pResult) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - for(COUNT_T i = 0; i < m_children.GetCount(); i++) - CpdXsdIfFailGo(m_children[i]->Validate(pElement, pResult)); - - for(COUNT_T i = 0; i < m_attributes.GetCount(); i++) - CpdXsdIfFailGo(m_attributes[i]->Validate(pElement, pResult)); - - MDA_XSD_VERIFY_OK; - MDA_XSD_VERIFY_FAIL; -} - -BOOL MdaSchema::MdaSchemaComplexContent::Validate(MdaXmlElement* pElement, ValidationResult* pResult) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - for(COUNT_T i = 0; i < m_children.GetCount(); i++) - CpdXsdIfFailGo(m_children[i]->Validate(pElement, pResult)); - - MDA_XSD_VERIFY_OK; - MDA_XSD_VERIFY_FAIL; -} - -BOOL MdaSchema::MdaSchemaGroup::ValidatePattern(MdaXmlElement* pElement, ValidationResult* pResult, COUNT_T* pCount) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - for(COUNT_T i = 0; i < m_children.GetCount(); i++) - { - ASSERT(IsPattern(m_children[i])); - CpdXsdIfFailGo(m_children[i]->ValidatePattern(pElement, pResult, pCount)); - } - - MDA_XSD_VERIFY_OK; - MDA_XSD_VERIFY_FAIL; -} - -BOOL MdaSchema::MdaSchemaGroupRef::ValidatePattern(MdaXmlElement* pElement, ValidationResult* pResult, COUNT_T* pCount) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - MdaSchemaBase* pReference = GetRef(); - LPCWSTR debug = GetRefName(); - ASSERT(IsPattern(this)); - return pReference->ValidatePattern(pElement, pResult, pCount); -} - -BOOL MdaSchema::MdaSchemaExtension::Validate(MdaXmlElement* pElement, ValidationResult* pResult) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - ASSERT(GetRef()->GetSchemaType() == MdaSchemaComplexTypeDefType); - MdaSchemaComplexTypeDef* pReference = (MdaSchemaComplexTypeDef*)GetRef(); - - MdaSchemaSequence sequence; - sequence.Initialize(1, 1); - - MdaSchemaBase* pXsd = pReference; - while(true) - { - if (MayHaveAttr(pXsd)) - { - for(COUNT_T i = 0; i < pXsd->GetAttributes().GetCount(); i++) - CpdXsdIfFailGo(pXsd->GetAttributes()[i]->Validate(pElement, pResult)); - } - - if (pXsd->GetSchemaType() == MdaSchemaExtensionType) - { - pXsd = ((MdaSchemaComplexTypeDef*)pXsd)->GetRef(); - continue; - } - - if (pXsd->m_children.GetCount() == 0) - break; - - pXsd = pXsd->m_children[0]; - - if (IsPattern(pXsd)) - { - sequence.AddChild(pXsd); - break; - } - } - - if (m_children.GetCount() == 1) - { - ASSERT(IsPattern(m_children[0])); - sequence.AddChild(m_children[0]); - } - - CpdXsdIfFailGo(sequence.Validate(pElement, pResult)); - - for(COUNT_T i = 0; i < m_attributes.GetCount(); i++) - CpdXsdIfFailGo(m_attributes[i]->Validate(pElement, pResult)); - - MDA_XSD_VERIFY_OK; - MDA_XSD_VERIFY_FAIL; -} - -BOOL MdaSchema::MdaSchemaElementRefType::Validate(MdaXmlElement* pElement, ValidationResult* pResult) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - CpdXsdIfFailGo(GetRef()->Validate(pElement, pResult)); - - MDA_XSD_VERIFY_OK; - MDA_XSD_VERIFY_FAIL; -} - -BOOL MdaSchema::MdaSchemaElementAny::Validate(MdaXmlElement* pElement, ValidationResult* pResult) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - StackSString buffer; - LPCWSTR debug = pElement->DebugToString(&buffer); - - CpdXsdTest(pElement->GetDeclDef() == GetDeclDef()); - - MDA_XSD_VERIFY_OK; - MDA_XSD_VERIFY_FAIL; -} - -BOOL MdaSchema::MdaSchemaElementRef::Validate(MdaXmlElement* pElement, ValidationResult* pResult) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - LPCWSTR debug = GetRefName(); - CpdXsdIfFailGo(GetRef()->Validate(pElement, pResult)); - - MDA_XSD_VERIFY_OK; - MDA_XSD_VERIFY_FAIL; -} - - -// -// MdaSchema::XXX::SetAttributes() -// - -void MdaSchema::MdaSchemaSequence::SetAttributes(MdaXmlElement* pXml) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - SmallStackSString ssBound; - - ssBound.Printf(W("%d"), m_min); - pXml->AddAttributeSz(MdaAttrDecl(MinOccurs), ssBound.GetUnicode()); - - if (m_max == -1) - { - pXml->AddAttributeSz(MdaAttrDecl(MaxOccurs), W("unbounded")); - } - else - { - ssBound.Printf(W("%d"), m_max); - pXml->AddAttributeSz(MdaAttrDecl(MaxOccurs), ssBound.GetUnicode()); - } -} - -void MdaSchema::MdaSchemaAttribute::SetAttributes(MdaXmlElement* pXml) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - pXml->AddAttributeSz(MdaAttrDecl(Name), GetAttributeName(m_declDef)); - - LPCWSTR szType = NULL; - if (m_type == MdaSchemaPrimitiveBOOL) - szType = W("xs:boolean"); - else if (m_type == MdaSchemaPrimitiveINT32) - szType = W("xs:int"); - else if (m_type == MdaSchemaPrimitiveSString) - szType = W("xs:string"); - else { UNREACHABLE(); } - - pXml->AddAttributeSz(MdaAttrDecl(Type), szType); - pXml->AddAttributeSz(MdaAttrDecl(Use), m_bRequired ? W("required") : W("optional")); - - if (!m_szDefault.IsEmpty()) - pXml->AddAttributeSz(MdaAttrDecl(Default), m_szDefault); -} - -void MdaSchema::MdaSchemaDeclDefRef::SetAttributes(MdaXmlElement* pXml) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - LPCWSTR szDeclDef = NULL; - LPCWSTR szRef = NULL; - - if (IsDeclDef(this)) - szDeclDef = GetDeclDefName(); - - if (IsRef(this)) - szRef = GetRefName(); - - switch (GetSchemaType()) - { - case MdaSchemaGroupRefType: - case MdaSchemaElementRefTyp: - pXml->AddAttributeSz(MdaAttrDecl(Ref), szRef); - break; - - case MdaSchemaExtensionType: - pXml->AddAttributeSz(MdaAttrDecl(Base), szRef); - break; - - case MdaSchemaElementRefTypeType: - pXml->AddAttributeSz(MdaAttrDecl(Name), szDeclDef); - pXml->AddAttributeSz(MdaAttrDecl(Type), szRef); - break; - - case MdaSchemaElementAnyType: - pXml->AddAttributeSz(MdaAttrDecl(Name), szDeclDef); - pXml->AddAttributeSz(MdaAttrDecl(Type), W("xs:anyType")); - break; - - case MdaSchemaGroupType: - case MdaSchemaElementType: - case MdaSchemaComplexTypeDefType: - pXml->AddAttributeSz(MdaAttrDecl(Name), szDeclDef); - break; - - default: - UNREACHABLE(); - } -} - -// -// MdaAssistant -// -void MdaAssistant::Initialize(MdaXmlElement* pXmlInput) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (pXmlInput->GetAttribute(MdaAttrDecl(SuppressDialog))) - m_bSuppressDialog = !!pXmlInput->GetAttributeValueAsBool(MdaAttrDecl(SuppressDialog)); -} - -LPCWSTR MdaAssistant::GetName() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - return MdaSchema::GetElementName(m_assistantDeclDef); -} - -MdaXmlElement* MdaAssistant::GetRootElement(MdaXmlElement* pRoot, BOOL bBreak) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - MdaXmlElement* pXmlAssistant = pRoot->AddChild(GetAssistantMsgDeclDef()); - - if (bBreak) - pXmlAssistant->AddAttributeSz(MdaAttrDecl(Break), W("true")); - - return pXmlAssistant; -} - -BOOL MdaAssistant::IsAssistantActive(MdaXmlElement* pXml) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - return TRUE; -} - -MdaXmlElement* MdaAssistant::OutputThread(Thread* pThread, MdaXmlElement* pXml) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - _ASSERTE(pThread); - pXml->AddAttributeInt(MdaAttrDecl(OsId), pThread->GetOSThreadId()); - pXml->AddAttributeInt(MdaAttrDecl(ManagedId), pThread->GetThreadId()); - - return pXml; -} - -MdaXmlElement* MdaAssistant::OutputMethodTable(MethodTable* pMT, MdaXmlElement* pXml) -{ - CONTRACT (MdaXmlElement*) - { - NOTHROW; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(CheckPointer(pMT)); - PRECONDITION(CheckPointer(pXml)); - POSTCONDITION(CheckPointer(RETVAL)); - } - CONTRACT_END; - - static WCHAR szTemplateMsg[] = {W("Failed to QI for interface %s because it does not have a COM proxy stub registered.")}; - - DefineFullyQualifiedNameForClassWOnStack(); - pXml->AddAttributeSz(MdaAttrDecl(Name), GetFullyQualifiedNameForClassW(pMT)); - - RETURN pXml; -} - -void MdaAssistant::ToString(TypeHandle typeHandle, SString* psszFullname, SString* psszNamespace) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - StackSString ssz;; - - psszFullname->Clear(); - - LPCSTR szDeclTypeName, szNamespace; - InlineSArray nesting; - - mdTypeDef tkTypeDef = typeHandle.GetCl(); - Module* pModule = typeHandle.GetModule(); - IMDInternalImport* pImport = pModule->GetMDImport(); - - // Get tkTypeDef tokens for declaring type and its nested classes - nesting.Append(tkTypeDef); - while (S_OK == pImport->GetNestedClassProps(tkTypeDef, &tkTypeDef)) - nesting.Append(tkTypeDef); - - // Append the namespace - COUNT_T i = nesting.GetCount() - 1; - if (FAILED(pImport->GetNameOfTypeDef(nesting[i], &szDeclTypeName, &szNamespace))) - { - szNamespace = NULL; - szDeclTypeName = NULL; - } - if (szNamespace && *szNamespace != W('\0')) - { - if (psszNamespace) - psszNamespace->SetUTF8(szNamespace); - - psszFullname->SetUTF8(szNamespace); - psszFullname->Append(W(".")); - } - - // Append the nested classes - for(; i > 0; i --) - { - IfFailThrow(pImport->GetNameOfTypeDef(nesting[i], &szDeclTypeName, &szNamespace)); - ssz.SetUTF8(szDeclTypeName); - psszFullname->Append(ssz); - psszFullname->Append(W("+")); - } - - // Append the declaring type name - IfFailThrow(pImport->GetNameOfTypeDef(nesting[i], &szDeclTypeName, &szNamespace)); - ssz.SetUTF8(szDeclTypeName); - psszFullname->Append(ssz); -} - -SString& MdaAssistant::ToString(SString& sszBuffer, Module* pModule) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - sszBuffer.AppendUTF8(pModule->GetSimpleName()); - return sszBuffer; -} - -SString& MdaAssistant::ToString(SString& sszBuffer, TypeHandle typeHandle) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - StackSString sszScratch; - ToString(sszBuffer, typeHandle.GetModule()).GetUnicode(); - sszBuffer.Append(W("!")); - ToString(typeHandle, &sszScratch, NULL); - sszBuffer.Append(sszScratch); - return sszBuffer; -} - -SString& MdaAssistant::ToString(SString& sszBuffer, MethodDesc* pMethodDesc) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - ToString(sszBuffer, pMethodDesc->GetMethodTable()).GetUnicode(); - sszBuffer.Append(W("::")); - StackSString ssz; - ssz.SetUTF8(pMethodDesc->GetName()); - sszBuffer.Append(ssz); - return sszBuffer; -} - -SString& MdaAssistant::ToString(SString& sszBuffer, FieldDesc* pFieldDesc) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - ToString(sszBuffer, pFieldDesc->GetEnclosingMethodTable()).GetUnicode(); - sszBuffer.Append(W("::")); - StackSString ssz; - ssz.SetUTF8(pFieldDesc->GetName()); - sszBuffer.Append(ssz); - return sszBuffer; -} - -MdaXmlElement* MdaAssistant::OutputParameter(SString parameterName, USHORT sequence, MethodDesc* pMethodDesc, MdaXmlElement* pXml) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - TypeHandle declType(pMethodDesc->GetMethodTable()); - Module* pDeclModule = declType.GetModule(); - - pXml->AddAttributeSz(MdaAttrDecl(Name), parameterName); - pXml->AddAttributeInt(MdaAttrDecl(Index), sequence); - - OutputMethodDesc(pMethodDesc, pXml->AddChild(MdaElemDecl(DeclaringMethod))); - - return pXml; -} - -MdaXmlElement* MdaAssistant::OutputMethodDesc(MethodDesc* pMethodDesc, MdaXmlElement* pXml) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - TypeHandle declType(pMethodDesc->GetMethodTable()); - Module* pDeclModule = declType.GetModule(); - - StackSString sszMethod; - - pXml->AddAttributeSz(MdaAttrDecl(Name), ToString(sszMethod, pMethodDesc).GetUnicode()); - - return pXml; -} - -MdaXmlElement* MdaAssistant::OutputFieldDesc(FieldDesc* pFieldDesc, MdaXmlElement* pXml) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - StackSString sszField; - - pXml->AddAttributeSz(MdaAttrDecl(Name), ToString(sszField, pFieldDesc).GetUnicode()); - - return pXml; -} - -MdaXmlElement* MdaAssistant::OutputTypeHandle(TypeHandle typeHandle, MdaXmlElement* pXml) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - StackSString sszTypeName; - - // Set Attribute - pXml->AddAttributeSz(MdaAttrDecl(Name), ToString(sszTypeName, typeHandle.GetMethodTable()).GetUnicode()); - - return pXml; -} - -MdaXmlElement* MdaAssistant::OutputModule(Module* pModule, MdaXmlElement* pXml) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - pXml->AddAttributeSz(MdaAttrDecl(Name), pModule->GetSimpleName()); - - return pXml; -} - -MdaXmlElement* MdaAssistant::OutputCallsite(MethodDesc *pMethodDesc, DWORD dwOffset, MdaXmlElement* pXml) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - StackSString sszMethod; - pXml->AddAttributeSz(MdaAttrDecl(Name), ToString(sszMethod, pMethodDesc).GetUnicode()); - - StackSString sszOffset; - sszOffset.Printf(W("0x%04X"), dwOffset); - pXml->AddAttributeSz(MdaAttrDecl(Offset), sszOffset.GetUnicode()); - - return pXml; -} - -MdaXmlElement* MdaAssistant::OutputException(OBJECTREF *pExceptionObj, MdaXmlElement* pXml) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - OutputTypeHandle((*pExceptionObj)->GetTypeHandle(), pXml->AddChild(MdaElemDecl(Type))); - - StackSString message; - GetExceptionMessage(*pExceptionObj, message); - - pXml->AddAttributeSz(MdaAttrDecl(Message), message); - - return pXml; -} - -// -// MdaQuery::CompiledQueries -// -BOOL MdaQuery::CompiledQueries::Test(MethodDesc* pMethodDesc) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - for (COUNT_T i = 0; i < m_queries.GetCount(); i ++) - { - if (m_queries[i]->Test(pMethodDesc)) - return TRUE; - } - - return FALSE; -} - -BOOL MdaQuery::CompiledQueries::Test(FieldDesc* pFieldDesc) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - for (COUNT_T i = 0; i < m_queries.GetCount(); i ++) - { - if (m_queries[i]->Test(pFieldDesc)) - return TRUE; - } - - return FALSE; -} - -BOOL MdaQuery::CompiledQueries::Test(MethodTable* pMethodTable) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - for (COUNT_T i = 0; i < m_queries.GetCount(); i ++) - { - if (m_queries[i]->Test(pMethodTable)) - return TRUE; - } - - return FALSE; -} - -MdaQuery::CompiledQuery* MdaQuery::CompiledQueries::AddQuery() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - CompiledQuery* pQuery = m_factory.Create(); - m_queries.Append(pQuery); - return pQuery; -} - - -// -// MdaQuery::CompiledQuery -// -void MdaQuery::Compile(MdaXmlElement* pXmlFilters, CompiledQueries* pCompiledQueries) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - SArray& children = pXmlFilters->GetChildren(); - BOOL bJmc = pXmlFilters->GetAttribute(MdaAttrDecl(JustMyCode))->GetValueAsBool(); - - for (COUNT_T i = 0; i < children.GetCount(); i ++) - { - MdaXmlElement* pXmlFilter = children[i]; - SString* psszName = pXmlFilter->GetAttribute(MdaAttrDecl(Name))->GetValueAsCSString(); - MdaXmlAttribute* pJmcOptAttr = pXmlFilter->GetAttribute(MdaAttrDecl(JustMyCode)); - if (pJmcOptAttr) - bJmc = pJmcOptAttr->GetValueAsBool(); - Compiler compiler; - CompiledQuery* pQuery = pCompiledQueries->AddQuery(); - compiler.Compile(psszName, pQuery); - if (bJmc) - pQuery->SetJustMyCode(); - } -} - -MdaQuery::CompiledQuery::CompiledQuery() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - m_bJustMyCode = FALSE; - m_bAnyMember = FALSE; - m_bAnyType = FALSE; - m_sszFullname.Clear(); - m_sszMember.Clear(); -} - -BOOL StartsWith(SString* psszString, SString* psszSubstring) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - StackSString sszString(*psszString); - if (psszString->GetCount() < psszSubstring->GetCount()) - return FALSE; - sszString.Truncate(sszString.Begin() + psszSubstring->GetCount()); - return sszString.Equals(*psszSubstring); -} - -BOOL MdaQuery::CompiledQuery::Test(MethodDesc* pMethodDesc) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - StackSString sszName(SString::Utf8, pMethodDesc->GetName()); - - if (pMethodDesc->IsLCGMethod() || pMethodDesc->IsILStub()) - return FALSE; - - if (!Test(&sszName, pMethodDesc->GetMethodTable())) - return FALSE; - - if (!m_bJustMyCode) - return TRUE; - - if (IsJustMyCode(pMethodDesc)) - return TRUE; - - return FALSE; -} - -BOOL MdaQuery::CompiledQuery::Test(FieldDesc* pFieldDesc) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - StackSString sszName(SString::Utf8, pFieldDesc->GetName()); - if (!Test(&sszName, pFieldDesc->GetApproxEnclosingMethodTable())) - return FALSE; - - if (!m_bJustMyCode) - return TRUE; - - return TRUE; -} - -BOOL MdaQuery::CompiledQuery::Test(SString* psszName, MethodTable* pMethodTable) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (!m_sszMember.IsEmpty()) - { - if (!m_sszMember.Equals(*psszName)) - return FALSE; - - if (m_sszMember.GetCount() == m_sszFullname.GetCount()) - return TRUE; - } - else if (!m_bAnyMember) - return FALSE; - - return Test(pMethodTable); -} - -BOOL MdaQuery::CompiledQuery::Test(MethodTable* pMethodTable) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (!pMethodTable) - return FALSE; - - if (m_sszFullname.IsEmpty()) - return TRUE; - - StackSString sszNamespace, sszFullName; - MdaAssistant::ToString(pMethodTable, &sszFullName, &sszNamespace); - - if (m_bAnyType && StartsWith(&m_sszFullname, &sszNamespace)) - return TRUE; - - if (m_bAnyMember && StartsWith(&m_sszFullname, &sszFullName)) - return TRUE; - - return m_sszFullname.Equals(sszFullName); -} - -void MdaQuery::CompiledQuery::SetName(LPCWSTR name) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (!m_sszFullname.IsEmpty()) - { - m_sszFullname.Append(W(".")); - m_sszMember.Clear(); - } - else - { - m_sszMember.Set(name); - } - - m_sszFullname.Append(name); - -} - -void MdaQuery::CompiledQuery::SetNestedTypeName(LPCWSTR name) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - m_sszMember.Clear(); - - if (!m_sszFullname.IsEmpty()) - m_sszFullname.Append(W("+")); - - m_sszFullname.Append(name); -} - -void MdaQuery::CompiledQuery::SetAnyMember() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - m_bAnyMember = TRUE; - m_sszMember.Clear(); -} - -void MdaQuery::CompiledQuery::SetAnyType() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - m_bAnyType = TRUE; - m_sszMember.Clear(); - - if (m_sszFullname.IsEmpty()) - m_bAnyMember = TRUE; -} - - -// -// MdaQuery::CompiledQuery -// - -MdaQuery::Compiler::Token MdaQuery::Compiler::LexAToken() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (*m_itr == W('\0')) - return MdaFilterEnd; - - if (ISWHITE(*m_itr)) - { - m_itr++; - return LexAToken(); - } - - if (ISMDAID(*m_itr)) - { - m_identifier.Clear(); - - do - { - m_identifier.Append(*m_itr); - m_itr++; - } - while(ISMDAID(*m_itr)); - - m_identifier.Append(W("\0")); - return MdaFilterIdentifier; - } - - WCHAR c = *m_itr; - m_itr++; - switch(c) - { - case W('.'): return MdaFilterDot; - case W(':'): return MdaFilterColon; - case W('*'): return MdaFilterAstrix; - case W('+'): return MdaFilterPlus; - } - - return MdaFilterEnd; -} - -// -// MdaXPath::MdaXPathCompiler -- Parser -// -BOOL MdaQuery::Compiler::Compile(SString* sszQuery, CompiledQuery* pAst) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - m_itr = sszQuery->Begin(); - - NextToken(); - BOOL bResult = NAME(pAst); - - return bResult; -} - -// NAME -// '*' -// id -// id '.' NAME -// id '+' NESTNAME -// id ':' ':' NESTNAME -BOOL MdaQuery::Compiler::NAME(CompiledQuery* pAst) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (TokenIs(MdaFilterIdentifier)) - { - pAst->SetName(GetIdentifier()); - - NextToken(); - if (TokenIs(MdaFilterDot)) - { - NextToken(); - return NAME(pAst); - } - else if (TokenIs(MdaFilterPlus)) - { - NextToken(); - return NESTNAME(pAst); - } - else if (TokenIs(MdaFilterColon)) - { - NextToken(); - if (!TokenIs(MdaFilterColon)) - return FALSE; - - NextToken(); - return MEMBERNAME(pAst); - } - } - else if (TokenIs(MdaFilterAstrix)) - { - pAst->SetAnyType(); - NextToken(); - } - else return FALSE; - - return TRUE; -} - -// NESTNAME -// id '+' NESTNAME -// id ':' ':' NESTNAME -BOOL MdaQuery::Compiler::NESTNAME(CompiledQuery* pAst) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (!TokenIs(MdaFilterIdentifier)) - return FALSE; - - pAst->SetNestedTypeName(GetIdentifier()); - - NextToken(); - - if (TokenIs(MdaFilterPlus)) - { - NextToken(); - return NESTNAME(pAst); - } - else if (TokenIs(MdaFilterColon)) - { - NextToken(); - if (!TokenIs(MdaFilterColon)) - return FALSE; - - NextToken(); - return MEMBERNAME(pAst); - } - else return FALSE; -} - -// MEMBERNAME -// '*' -// id -BOOL MdaQuery::Compiler::MEMBERNAME(CompiledQuery* pAst) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (TokenIs(MdaFilterIdentifier)) - pAst->SetMemberName(GetIdentifier()); - - else if (TokenIs(MdaFilterAstrix)) - pAst->SetAnyMember(); - - else return FALSE; - - NextToken(); - return TRUE; -} - - -// -// MdaXmlElement -// -MdaXmlElement* MdaXmlElement::GetChild(MdaElemDeclDef declDef) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - for(COUNT_T i = 0; i < m_children.GetCount(); i ++) - { - if (m_children[i]->GetDeclDef() == declDef) - return m_children[i]; - } - - return NULL; -} - -SString* MdaXmlElement::ToXml(SString* pXml, LPCWSTR ns, INT32 depth) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(depth < 60); // Trap for recursion - } - CONTRACTL_END; - - // Indent - for (INT32 i = 0; i < depth; i ++) - pXml->Append(W(" ")); - - pXml->Append(W("<")); - if (ns && IsDefinition()) { pXml->Append(ns); pXml->Append(W(":")); } - pXml->Append(GetName()); - - if (m_attributes.GetCount() != 0) - { - for (COUNT_T i = 0; i < m_defaultAttrIndex && i < m_attributes.GetCount(); i ++) - { - pXml->Append(W(" ")); - m_attributes[i]->ToXml(pXml); - } - } - - if (m_children.GetCount() == 0) - { - if (GetDeclDef() == MdaElemComment) - { - pXml->Append(W(" ")); - pXml->Append(m_szName.GetUnicode()); - pXml->Append(W(" -->\n")); - } - else - pXml->Append(W("/>\n")); - } - else - { - pXml->Append(W(">")); - - SArray::Iterator itr = m_children.Begin(); - SArray::Iterator end = m_children.End(); - - pXml->Append(W("\n")); - while (itr != end) - { - (*itr)->ToXml(pXml, ns, depth + 1); - itr++; - } - - // Indent - for (INT32 i = 0; i < depth; i ++) - pXml->Append(W(" ")); - - pXml->Append(W("Append(ns); pXml->Append(W(":")); } - pXml->Append(GetName()); - pXml->Append(W(">\n")); - } - - - return pXml; -} - -LPCWSTR MdaXmlElement::DebugToString(SString* pBuffer) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - pBuffer->Append(W("<")); - pBuffer->Append(GetName()); - - for(COUNT_T i = 0; i < GetAttributes().GetCount(); i++) - { - pBuffer->Append(W(" ")); - GetAttributes()[i]->ToXml(pBuffer); - } - - pBuffer->Append(W("/>")); - return pBuffer->GetUnicode(); -} - -MdaXmlElement* MdaXmlElement::SetName(LPCWSTR name, BOOL bAssertDefined) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - SetDeclDef(MdaSchema::GetElementType(name, bAssertDefined)); - - if (GetDeclDef() == MdaElemUndefined) - m_szName.Set(name); - - return this; -} - -MdaXmlAttribute* MdaXmlElement::AddAttribute(MdaAttrDeclDef declDef) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - return AddAttribute(m_pXmlIndustry->CreateAttribute()->SetDeclDef(declDef)); -} - -MdaXmlAttribute* MdaXmlElement::AddAttribute(LPCWSTR szName, LPCWSTR szValue) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - return AddAttribute(m_pXmlIndustry->CreateAttribute()->Initialize(szName, szValue)); -} - -MdaXmlAttribute* MdaXmlElement::AddDefaultAttribute(MdaAttrDeclDef attrDeclDef, LPCWSTR szValue) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (m_defaultAttrIndex == -1) - m_defaultAttrIndex = m_attributes.GetCount(); - MdaXmlAttribute* pAttr = AddAttribute(attrDeclDef)->SetSString(szValue); - pAttr->m_type = MdaSchemaPrimitiveUnknown; - return pAttr; -} - -MdaXmlElement* MdaXmlElement::AddChild(MdaXmlElement* pChild) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - //PRECONDITION(m_elemDeclDef != MdaElemUndefined); - PRECONDITION(CheckPointer(pChild)); - PRECONDITION(CheckPointer(pChild->m_pXmlIndustry)); - - *m_children.Append() = pChild; - return pChild; -} - -MdaXmlElement* MdaXmlElement::AddChild(LPCWSTR name, BOOL bAssertDefined) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - return AddChild(m_pXmlIndustry->CreateElement())->SetName(name, bAssertDefined); -} - -MdaXmlElement* MdaXmlElement::AddChild(MdaElemDeclDef type) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - return AddChild(m_pXmlIndustry->CreateElement()->SetDeclDef(type)); -} - -LPCWSTR MdaXmlElement::GetName() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (GetDeclDef() == MdaElemUndefined) - return m_szName.GetUnicode(); - - return MdaSchema::GetElementName(m_elemDeclDef); -} - -MdaXmlAttribute* MdaXmlElement::GetAttribute(MdaAttrDeclDef attrDeclDef) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - - for(UINT32 i = 0; i < m_attributes.GetCount(); i++) - { - if (attrDeclDef == m_attributes[i]->GetDeclDef()) - return m_attributes[i]; - } - - return NULL; -} - -BOOL MdaXmlElement::GetAttributeValueAsBool(MdaAttrDeclDef attrDeclDef, BOOL bDefault) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - MdaXmlAttribute* pAttr = GetAttribute(attrDeclDef); - - if (!pAttr) - return bDefault; - - return pAttr->GetValueAsBool(); -} - -BOOL MdaXmlElement::GetAttributeValueAsBool(MdaAttrDeclDef attrDeclDef) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - MdaXmlAttribute* pAttr = GetAttribute(attrDeclDef); - PREFIX_ASSUME(pAttr != NULL); - ASSERT(pAttr); - return pAttr->GetValueAsBool(); -} - -// -// MdaXmlAttribute -// - -SString* MdaXmlAttribute::ToXml(SString* xml) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - SString sszBuffer; - - xml->Append(GetName()); - if (!m_szNs.IsEmpty()) - { - xml->Append(W(":")); - xml->Append(m_szNs.GetUnicode()); - } - - xml->Append(W("=\"")); - if (m_type == MdaSchemaPrimitiveSString) - xml->Append(MdaXmlEscape(sszBuffer, m_value)); - else if (m_type == MdaSchemaPrimitiveBOOL) - xml->Append(m_bool ? W("true") : W("false")); - else if (m_type == MdaSchemaPrimitiveINT32) - { - StackSString sszOutput; - sszOutput.Printf(W("%d"), m_int); - xml->Append(sszOutput); - } - xml->Append(W("\"")); - return xml; -} - -LPCWSTR MdaXmlAttribute::GetName() -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - if (m_declDef != MdaAttrUndefined) - return MdaSchema::GetAttributeName(m_declDef); - - return m_szName.GetUnicode(); -} - -MdaXmlAttribute* MdaXmlAttribute::Initialize(LPCWSTR szName, LPCWSTR szValue) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - m_type = MdaSchemaPrimitiveUnknown; - m_value.Set(szValue); - - SetDeclDef(MdaSchema::GetAttributeType(szName, FALSE)); - if (m_declDef == MdaAttrUndefined) - m_szName.Set(szName); - - return this; -} - - -// -// MdaConfigFactory -// -STDAPI GetXMLObjectEx(IXMLParser **ppv); - -MdaXmlElement* MdaConfigFactory::ParseXmlStream(MdaXmlIndustry* pXmlIndustry, LPCWSTR pszFileName) -{ - CONTRACT(MdaXmlElement*) - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACT_END; - - HRESULT hr = S_OK; - MdaXmlElement* pRoot = NULL; - - EX_TRY - { - { - if (!pszFileName) - goto Exit; - - NonVMComHolder pIXMLParser(NULL); - NonVMComHolder pFile(NULL); - - hr = CreateConfigStream(pszFileName, &pFile); - if(FAILED(hr)) goto Exit; - - hr = GetXMLObjectEx(&pIXMLParser); - if(FAILED(hr)) goto Exit; - - hr = pIXMLParser->SetInput(pFile); // filestream's RefCount=2 - if ( ! SUCCEEDED(hr)) - goto Exit; - - pRoot = pXmlIndustry->CreateElement()->SetDeclDef(MdaElemDef(Dummy)); - MdaConfigFactory mdaConfigFactory(pRoot); - - hr = pIXMLParser->SetFactory(&mdaConfigFactory); // factory's RefCount=2 - if (!SUCCEEDED(hr)) - goto Exit; - - hr = pIXMLParser->Run(-1); - - if (pRoot->GetChildren().GetCount() == 1) - pRoot = pRoot->GetChildren()[0]; - else - pRoot = NULL; - } - Exit: ; - } - EX_CATCH - { - } - EX_END_CATCH(SwallowAllExceptions); - - if (hr == (HRESULT)XML_E_MISSINGROOT) - hr = S_OK; - else if (Assembly::FileNotFound(hr)) - hr = S_FALSE; - - RETURN pRoot; -} - -HRESULT STDMETHODCALLTYPE MdaConfigFactory::CreateNode( - IXMLNodeSource* pSource, - PVOID pNodeParent, - USHORT cNumRecs, - XML_NODE_INFO** apNodeInfo) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - m_pMdaXmlElement = NULL; - - for(INT32 i = 0; i < cNumRecs; i++) - { - DWORD dwType = apNodeInfo[i]->dwType; - - if(dwType == XML_ELEMENT || dwType == XML_ATTRIBUTE) - { - StackSString sszName((WCHAR*)apNodeInfo[i]->pwcText, apNodeInfo[i]->ulLen); - - if (dwType == XML_ELEMENT) - { - m_pMdaXmlElement = m_stack.Tos()->AddChild(sszName, FALSE); - } - else if (dwType == XML_ATTRIBUTE) - { - i++; - InlineSString szValue((WCHAR*)apNodeInfo[i]->pwcText, apNodeInfo[i]->ulLen); - - if (m_pMdaXmlElement) - m_pMdaXmlElement->AddAttribute(sszName.GetUnicode(), szValue); - } - } - } - - return S_OK; -} - -HRESULT STDMETHODCALLTYPE MdaConfigFactory::BeginChildren( - IXMLNodeSource* pSource, - XML_NODE_INFO* pNodeInfo) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - m_stack.Push(m_pMdaXmlElement); - - return S_OK; -} - -HRESULT STDMETHODCALLTYPE MdaConfigFactory::EndChildren( - IXMLNodeSource* pSource, - BOOL fEmptyNode, - XML_NODE_INFO* pNodeInfo) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - - if (fEmptyNode) - return S_OK; - - m_stack.Pop(); - - return S_OK; -} - -HRESULT STDMETHODCALLTYPE MdaConfigFactory::NotifyEvent( - IXMLNodeSource* pSource, - XML_NODEFACTORY_EVENT iEvt) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - return S_OK; -} - -HRESULT STDMETHODCALLTYPE MdaConfigFactory::Error( - IXMLNodeSource* pSource, - HRESULT hrErrorCode, - USHORT cNumRecs, - XML_NODE_INFO** apNodeInfo) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - return E_FAIL; -} - -#endif -- cgit v1.2.3 From 01cd52961742f595ca710027fd3b0714ad594262 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Sun, 12 Feb 2017 20:54:30 -0800 Subject: Remove dead mdadac.cpp --- src/vm/mdadac.cpp | 48 ------------------------------------------------ 1 file changed, 48 deletions(-) delete mode 100644 src/vm/mdadac.cpp diff --git a/src/vm/mdadac.cpp b/src/vm/mdadac.cpp deleted file mode 100644 index 95be6bff60..0000000000 --- a/src/vm/mdadac.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// 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. - - -#include "common.h" -#include "mda.h" -#include "mdaassistants.h" -#include "sstring.h" -#include "daccess.h" - -#ifdef MDA_SUPPORTED -MdaStaticHeap g_mdaStaticHeap = -{ - { 0 }, // m_assistants[] - 0, // m_pMda - { 0 }, // m_mda[] - -#define MDA_ASSISTANT_STATIC_INIT -#include "mdaschema.inl" -#undef MDA_ASSISTANT_STATIC_INIT -}; - - -// -// MdaManagedDebuggingAssistants -// -void ManagedDebuggingAssistants::AllocateManagedDebuggingAssistants() -{ - WRAPPER_NO_CONTRACT; - g_mdaStaticHeap.m_pMda = new (&g_mdaStaticHeap.m_mda) ManagedDebuggingAssistants(); -} - -ManagedDebuggingAssistants::ManagedDebuggingAssistants() -{ - WRAPPER_NO_CONTRACT; - -#ifndef DACCESS_COMPILE - Initialize(); -#endif -} -#endif // MDA_SUPPORTED - - - - - - -- cgit v1.2.3 From 0226a2eb0c600d06d43ad54514b595a7d7a3f751 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Sun, 12 Feb 2017 20:57:29 -0800 Subject: Remove dead message.cpp --- src/vm/message.cpp | 1171 --------------------------------------------------- src/vm/remoting.cpp | 2 +- 2 files changed, 1 insertion(+), 1172 deletions(-) delete mode 100644 src/vm/message.cpp diff --git a/src/vm/message.cpp b/src/vm/message.cpp deleted file mode 100644 index 093f9a2629..0000000000 --- a/src/vm/message.cpp +++ /dev/null @@ -1,1171 +0,0 @@ -// 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. - -/*============================================================ -** -** File: message.cpp -** -** Purpose: Encapsulates a function call frame into a message -** object with an interface that can enumerate the -** arguments of the message -** -** - -===========================================================*/ -#include "common.h" - -#ifdef FEATURE_REMOTING - -#include "comdelegate.h" -#include "excep.h" -#include "message.h" -#include "remoting.h" -#include "field.h" -#include "eeconfig.h" -#include "invokeutil.h" -#include "callingconvention.h" - -//+---------------------------------------------------------------------------- -// -// Method: CMessage::GetArgCount public -// -// Synopsis: Returns number of arguments in the method call -// -//+---------------------------------------------------------------------------- -FCIMPL1(INT32, CMessage::GetArgCount, MessageObject * pMessage) -{ - CONTRACTL - { - FCALL_CHECK; - PRECONDITION(CheckPointer(pMessage)); - } - CONTRACTL_END; - - LOG((LF_REMOTING, LL_INFO10, "CMessage::GetArgCount IN pMsg:0x%x\n", pMessage)); - - // Get the frame pointer from the object - MetaSig *pSig = pMessage->GetResetMetaSig(); - - // scan the sig for the argument count - INT32 ret = pSig->NumFixedArgs(); - - if (pMessage->GetDelegateMD()) - ret -= 2; - - LOG((LF_REMOTING, LL_INFO10, "CMessage::GetArgCount OUT ret:0x%x\n", ret)); - return ret; -} -FCIMPLEND - -//+---------------------------------------------------------------------------- -// -// Method: CMessage::GetArg public -// -// Synopsis: Use to enumerate a call's arguments -// -//+---------------------------------------------------------------------------- -FCIMPL2(Object*, CMessage::GetArg, MessageObject* pMessageUNSAFE, INT32 argNum) -{ - CONTRACTL - { - FCALL_CHECK; - PRECONDITION(pMessageUNSAFE != NULL); - } - CONTRACTL_END; - - struct _gc { - OBJECTREF refRetVal; - MESSAGEREF pMessage; - } gc; - - gc.refRetVal = NULL; - gc.pMessage = (MESSAGEREF) pMessageUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); - - LOG((LF_REMOTING, LL_INFO10, "CMessage::GetArgCount IN\n")); - - MetaSig *pSig = gc.pMessage->GetResetMetaSig(); - - if ((UINT)argNum >= pSig->NumFixedArgs()) - COMPlusThrow(kTargetParameterCountException); - - for (INT32 i = 0; i < argNum; i++) - pSig->NextArg(); - - BOOL fIsByRef = FALSE; - CorElementType eType = pSig->NextArg(); - TypeHandle ty = TypeHandle(); - if (eType == ELEMENT_TYPE_BYREF) - { - fIsByRef = TRUE; - TypeHandle tycopy; - eType = pSig->GetByRefType(&tycopy); - if (eType == ELEMENT_TYPE_VALUETYPE) - ty = tycopy; - } - else - { - if (eType == ELEMENT_TYPE_VALUETYPE) - { - ty = pSig->GetLastTypeHandleThrowing(); - -#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE - if (ArgIterator::IsArgPassedByRef(ty)) - fIsByRef = TRUE; -#endif - } - } - - if (eType == ELEMENT_TYPE_PTR) - COMPlusThrow(kRemotingException, W("Remoting_CantRemotePointerType")); - - GetObjectFromStack(&gc.refRetVal, - GetStackPtr(argNum, gc.pMessage->GetFrame(), gc.pMessage->GetResetMetaSig()), - eType, - ty, - fIsByRef, - gc.pMessage->GetFrame()); - - LOG((LF_REMOTING, LL_INFO10, "CMessage::GetArg OUT\n")); - - HELPER_METHOD_FRAME_END(); - return OBJECTREFToObject(gc.refRetVal); -} -FCIMPLEND - -FCIMPL1(Object*, CMessage::GetArgs, MessageObject* pMessageUNSAFE) -{ - CONTRACTL - { - FCALL_CHECK; - PRECONDITION(pMessageUNSAFE != NULL); - } - CONTRACTL_END; - - struct _gc { - PTRARRAYREF refRetVal; - MESSAGEREF pMessage; - OBJECTREF arg; - } gc; - - gc.refRetVal = NULL; - gc.pMessage = (MESSAGEREF) pMessageUNSAFE; - gc.arg = NULL; - - HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); - - LOG((LF_REMOTING, LL_INFO10, "CMessage::GetArgCount IN\n")); - - MetaSig *pSig = gc.pMessage->GetResetMetaSig(); - - // scan the sig for the argument count - INT32 numArgs = pSig->NumFixedArgs(); - if (gc.pMessage->GetDelegateMD()) - numArgs -= 2; - - // Allocate an object array - gc.refRetVal = (PTRARRAYREF) AllocateObjectArray(numArgs, g_pObjectClass); - - ArgIterator iter(pSig); - - for (int index = 0; index < numArgs; index++) - { - BOOL fIsByRef = FALSE; - CorElementType eType; - PVOID addr; - eType = pSig->PeekArg(); - addr = (LPBYTE) gc.pMessage->GetFrame()->GetTransitionBlock() + GetStackOffset(gc.pMessage->GetFrame(), &iter, pSig); - - TypeHandle ty = TypeHandle(); - if (eType == ELEMENT_TYPE_BYREF) - { - fIsByRef = TRUE; - TypeHandle tycopy; - // If this is a by-ref arg, GetObjectFromStack() will dereference "addr" to - // get the real argument address. Dereferencing now will open a gc hole if "addr" - // points into the gc heap, and we trigger gc between here and the point where - // we return the arguments. - //addr = *((PVOID *) addr); - eType = pSig->GetByRefType(&tycopy); - if (eType == ELEMENT_TYPE_VALUETYPE) - ty = tycopy; - } - else - { - if (eType == ELEMENT_TYPE_VALUETYPE) - { - ty = pSig->GetLastTypeHandleThrowing(); - -#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE - if (ArgIterator::IsArgPassedByRef(ty)) - fIsByRef = TRUE; -#endif - } - } - - if (eType == ELEMENT_TYPE_PTR) - COMPlusThrow(kRemotingException, W("Remoting_CantRemotePointerType")); - - GetObjectFromStack(&gc.arg, - addr, - eType, - ty, - fIsByRef, - gc.pMessage->GetFrame()); - - gc.refRetVal->SetAt(index, gc.arg); - } - - LOG((LF_REMOTING, LL_INFO10, "CMessage::GetArgs OUT\n")); - - HELPER_METHOD_FRAME_END(); - return OBJECTREFToObject(gc.refRetVal); -} -FCIMPLEND - -//static -void CMessage::GetObjectFromStack(OBJECTREF* ppDest, PVOID val, const CorElementType eType, TypeHandle ty, BOOL fIsByRef, FramedMethodFrame *pFrame) -{ - CONTRACT_VOID - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM()); - PRECONDITION(CheckPointer(ppDest)); - PRECONDITION(CheckPointer(val)); - } - CONTRACT_END; - - // Value types like Nullable have special unboxing semantics, - // - if (eType == ELEMENT_TYPE_VALUETYPE) - { - // - // box the value class - // - - _ASSERTE(ty.GetMethodTable()->IsValueType() || ty.GetMethodTable()->IsEnum()); - - _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsHeapPointer((BYTE *) ppDest) || - !"(pDest) can not point to GC Heap"); - MethodTable* pMT = ty.GetMethodTable(); - - if (pMT->IsByRefLike()) - COMPlusThrow(kRemotingException, W("Remoting_TypeCantBeRemoted")); - - PVOID* pVal; - if (fIsByRef) - pVal = (PVOID *)val; - else { - val = StackElemEndianessFixup(val, pMT->GetNumInstanceFieldBytes()); - pVal = &val; - } - - *ppDest = pMT->FastBox(pVal); - RETURN; - } - - switch (CorTypeInfo::GetGCType(eType)) - { - case TYPE_GC_NONE: - { - if(ELEMENT_TYPE_PTR == eType) - { - COMPlusThrow(kNotSupportedException); - } - - MethodTable *pMT = MscorlibBinder::GetElementType(eType); - - OBJECTREF pObj = pMT->Allocate(); - if (fIsByRef) - val = *((PVOID *)val); - else - val = StackElemEndianessFixup(val, CorTypeInfo::Size(eType)); - - void *pDest = pObj->UnBox(); - -#ifdef COM_STUBS_SEPARATE_FP_LOCATIONS - if ( !fIsByRef - && ( ELEMENT_TYPE_R4 == eType - || ELEMENT_TYPE_R8 == eType) - && pFrame - && !TransitionBlock::IsStackArgumentOffset(static_cast((TADDR) val - pFrame->GetTransitionBlock()))) - { - if (ELEMENT_TYPE_R4 == eType) - *(UINT32*)pDest = (UINT32)FPSpillToR4(val); - else - *(UINT64*)pDest = (UINT64)FPSpillToR8(val); - } - else -#endif // COM_STUBS_SEPARATE_FP_LOCATIONS - { - memcpyNoGCRefs(pDest, val, CorTypeInfo::Size(eType)); - } - - *ppDest = pObj; - } - break; - case TYPE_GC_REF: - if (fIsByRef) - val = *((PVOID *)val); - *ppDest = ObjectToOBJECTREF(*(Object **)val); - break; - default: - COMPlusThrow(kRemotingException, W("Remoting_TypeCantBeRemoted")); - } - - RETURN; -} - -//+---------------------------------------------------------------------------- -// -// Method: CMessage::PropagateOutParameters private -// -// Synopsis: Copy back data for in/out parameters and the return value -// -//+---------------------------------------------------------------------------- -FCIMPL3(void, CMessage::PropagateOutParameters, MessageObject* pMessageUNSAFE, ArrayBase* pOutPrmsUNSAFE, Object* RetValUNSAFE) -{ - CONTRACTL - { - FCALL_CHECK; - PRECONDITION(pMessageUNSAFE != NULL); - } - CONTRACTL_END; - - struct _gc - { - MESSAGEREF pMessage; - BASEARRAYREF pOutPrms; - OBJECTREF RetVal; - OBJECTREF param; - } gc; - gc.pMessage = (MESSAGEREF) pMessageUNSAFE; - gc.pOutPrms = (BASEARRAYREF) pOutPrmsUNSAFE; - gc.RetVal = (OBJECTREF) RetValUNSAFE; - gc.param = NULL; - HELPER_METHOD_FRAME_BEGIN_PROTECT(gc); - - LOG((LF_REMOTING, LL_INFO10, "CMessage::PropogateOutParameters IN\n")); - - // Retrieve the message's flags. - INT32 flags = gc.pMessage->GetFlags(); - - // Construct an ArgIterator from the message's frame and sig. - MetaSig *pSig = gc.pMessage->GetResetMetaSig(); - FramedMethodFrame *pFrame = gc.pMessage->GetFrame(); - ArgIterator argit(pSig); - - // move into object to return to client - - // Propagate the return value only if the pMsg is not a Ctor message - // Check if the return type has a return buffer associated with it - if ((flags& MSGFLG_CTOR) == 0 && pSig->GetReturnType() != ELEMENT_TYPE_VOID) - { - if (argit.HasRetBuffArg()) - { - // Copy from RetVal into the retBuff. - INT64 retVal = CopyOBJECTREFToStack( - *(void**)(pFrame->GetTransitionBlock() + argit.GetRetBuffArgOffset()), - &gc.RetVal, - pSig->GetReturnType(), - TypeHandle(), - pSig, - TRUE); // copy class contents - - // Copy the return value - *(ARG_SLOT *)(gc.pMessage->GetFrame()->GetReturnValuePtr()) = retVal; - } - else - { -#ifdef ENREGISTERED_RETURNTYPE_MAXSIZE - if (argit.HasNonStandardByvalReturn()) - { - // - // in these cases, we put the pointer to the return buffer into the frame's - // return value slot - // - CopyOBJECTREFToStack(gc.pMessage->GetFrame()->GetReturnValuePtr(), - &gc.RetVal, - pSig->GetReturnType(), - TypeHandle(), - pSig, - TRUE); // copy class contents - } - else -#endif // ENREGISTERED_RETURNTYPE_MAXSIZE - { - // There is no separate return buffer, the retVal should fit in - // an INT64. - INT64 retVal = CopyOBJECTREFToStack( - NULL, //no return buff - &gc.RetVal, - pSig->GetReturnType(), - TypeHandle(), - pSig, - FALSE); //don't copy class contents - - // Copy the return value - *(ARG_SLOT *)(gc.pMessage->GetFrame()->GetReturnValuePtr()) = retVal; - } - } - } - - // Refetch all the variables as GC could have happened after call to - // CopyOBJECTREFToStack - UINT32 cOutParams = (gc.pOutPrms != NULL) ? gc.pOutPrms->GetNumComponents() : 0; - if (cOutParams > 0) - { - PVOID *argAddr; - UINT32 i = 0; - MetaSig syncSig(gc.pMessage->GetMethodDesc()); - MetaSig *pSyncSig = NULL; - - if (flags & MSGFLG_ENDINVOKE) - { - pSyncSig = &syncSig; - } - - for (i=0; iNextArg(); - if (typ == ELEMENT_TYPE_END) - { - break; - } - - if (typ != ELEMENT_TYPE_BYREF) - { - continue; - } - - argAddr = (PVOID *)(pFrame->GetTransitionBlock() + argit.GetNextOffset()); - } - else - { - int ofs = argit.GetNextOffset(); - if (ofs == TransitionBlock::InvalidOffset) - { - break; - } - - if (argit.GetArgType() != ELEMENT_TYPE_BYREF) - { - continue; - } - - argAddr = (PVOID *)(pFrame->GetTransitionBlock() + ofs); - } - - TypeHandle ty = TypeHandle(); - CorElementType brType = pSig->GetByRefType(&ty); - - gc.param = ((OBJECTREF *) gc.pOutPrms->GetDataPtr())[i]; - - CopyOBJECTREFToStack( - *argAddr, - &gc.param, - brType, - ty, - pSig, - ty.IsNull() ? FALSE : ty.IsValueType()); - } - - } - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - -INT64 CMessage::CopyOBJECTREFToStack(PVOID pvDest, OBJECTREF *pSrc, CorElementType typ, TypeHandle ty, MetaSig *pSig, BOOL fCopyClassContents) -{ - INT64 ret = 0; - - CONTRACT(INT64) - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM()); - PRECONDITION(CheckPointer(pvDest, NULL_OK)); - PRECONDITION(CheckPointer(pSrc)); - PRECONDITION(typ != ELEMENT_TYPE_VOID); - PRECONDITION(CheckPointer(pSig)); - } - CONTRACT_END; - - if (fCopyClassContents) - { - // We have to copy the contents of a value class to pvDest - - // write unboxed version back to memory provided by the client - if (pvDest) - { - if (ty.IsNull()) - ty = pSig->GetRetTypeHandleThrowing(); - - if (*pSrc == NULL && !Nullable::IsNullableType(ty)) - COMPlusThrow(kRemotingException, W("Remoting_Message_BadRetValOrOutArg")); - - ty.GetMethodTable()->UnBoxIntoUnchecked(pvDest, *pSrc); - - // return the object so it can be stored in the frame and - // propagated to the root set - // pSrc may not be doubleword aligned! - *(OBJECTREF*)&ret = *pSrc; - } - } - else - { - // We have either a real OBJECTREF or something that does not have - // a return buffer associated - - // Check if it is an ObjectRef (from the GC heap) - if (CorTypeInfo::IsObjRef(typ)) - { - if ((*pSrc!=NULL) && ((*pSrc)->IsTransparentProxy())) - { - if (ty.IsNull()) - ty = pSig->GetRetTypeHandleThrowing(); - - // CheckCast ensures that the returned object (proxy) gets - // refined to the level expected by the caller of the method - if (!CRemotingServices::CheckCast(*pSrc, ty)) - COMPlusThrow(kInvalidCastException, W("Arg_ObjObj")); - } - if (pvDest) - SetObjectReferenceUnchecked((OBJECTREF *)pvDest, *pSrc); - - // pSrc may not be double-word aligned! - *(OBJECTREF*)&ret = *pSrc; - } - else - { - // Note: this assert includes VALUETYPE because for Enums - // HasRetBuffArg() returns false since the normalized type is I4 - // so we end up here ... but GetReturnType() returns VALUETYPE - // Almost all VALUETYPEs will go through the fCopyClassContents - // codepath instead of here. - // Also, IsPrimitiveType() does not check for IntPtr, UIntPtr etc - // there is a note in siginfo.hpp about that ... hence we have - // ELEMENT_TYPE_I, ELEMENT_TYPE_U. - _ASSERTE( - CorTypeInfo::IsPrimitiveType(typ) - || (typ == ELEMENT_TYPE_VALUETYPE) - || (typ == ELEMENT_TYPE_I) - || (typ == ELEMENT_TYPE_U) - || (typ == ELEMENT_TYPE_FNPTR) - ); - - // REVIEW: For a "ref int" arg, if a nasty sink replaces the boxed - // int with a null OBJECTREF, this is where we check. We need to be - // uniform in our policy w.r.t. this (throw v/s ignore) - // The 'if' block above throws, CallFieldAccessor also has this - // problem. - if (*pSrc != NULL) - { - PVOID pvSrcData = (*pSrc)->GetData(); - int cbsize = gElementTypeInfo[typ].m_cbSize; - INT64 retBuff; - - // ElementTypeInfo.m_cbSize can be less that zero for cases that need - // special handling (e.g. value types) to be sure of size (see - // siginfo.cpp). Luckily, the type handle has the actual byte count, - // so we look there for such cases. - if (cbsize < 0) - { - if (ty.IsNull()) - ty = pSig->GetRetTypeHandleThrowing(); - - _ASSERTE(!ty.IsNull()); - cbsize = ty.GetSize(); - - // we are returning this value class in an INT64 so it better be small enough - _ASSERTE(cbsize <= (int) sizeof(INT64)); - // Unbox it into a local buffer, This coveres the Nullable case - // then do the endianness morph below - ty.GetMethodTable()->UnBoxIntoUnchecked(&retBuff, *pSrc); - - pvSrcData = &retBuff; - } - - if (pvDest) - { - memcpyNoGCRefs(pvDest, pvSrcData, cbsize); - } - - // need to sign-extend signed types - bool fEndianessFixup = false; - switch (typ) { - case ELEMENT_TYPE_I1: - ret = *(INT8*)pvSrcData; - fEndianessFixup = true; - break; - case ELEMENT_TYPE_I2: - ret = *(INT16*)pvSrcData; - fEndianessFixup = true; - break; - case ELEMENT_TYPE_I4: - ret = *(INT32*)pvSrcData; - fEndianessFixup = true; - break; - default: - memcpyNoGCRefs(StackElemEndianessFixup(&ret, cbsize), pvSrcData, cbsize); - break; - } - -#if !defined(_WIN64) && BIGENDIAN - if (fEndianessFixup) - ret <<= 32; -#endif - } - } - } - - RETURN(ret); -} - -//+---------------------------------------------------------------------------- -// -// Method: CMessage::GetReturnValue -// -// Synopsis: Pull return value off the stack -// -//+---------------------------------------------------------------------------- -FCIMPL1(Object*, CMessage::GetReturnValue, MessageObject* pMessageUNSAFE) -{ - CONTRACTL - { - FCALL_CHECK; - PRECONDITION(pMessageUNSAFE != NULL); - } - CONTRACTL_END; - - struct _gc { - OBJECTREF refRetVal; - MESSAGEREF pMessage; - } gc; - - gc.refRetVal = NULL; - gc.pMessage = (MESSAGEREF) pMessageUNSAFE; - - HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); - - MetaSig* pSig = gc.pMessage->GetResetMetaSig(); - FramedMethodFrame* pFrame = gc.pMessage->GetFrame(); - - ArgIterator argit(pSig); - - PVOID pvRet; - if (argit.HasRetBuffArg()) - { - pvRet = *(PVOID *)(pFrame->GetTransitionBlock() + argit.GetRetBuffArgOffset()); - } - else - { - pvRet = pFrame->GetReturnValuePtr(); - } - - CorElementType eType = pSig->GetReturnType(); - TypeHandle ty; - if (eType == ELEMENT_TYPE_VALUETYPE) - { - ty = pSig->GetRetTypeHandleThrowing(); - } - else - { - ty = TypeHandle(); - } - - GetObjectFromStack(&gc.refRetVal, - pvRet, - eType, - ty); - - HELPER_METHOD_FRAME_END(); - return OBJECTREFToObject(gc.refRetVal); -} -FCIMPLEND - - - -FCIMPL2(FC_BOOL_RET, CMessage::Dispatch, MessageObject* pMessageUNSAFE, Object* pServerUNSAFE) -{ - CONTRACTL - { - FCALL_CHECK; - PRECONDITION(pMessageUNSAFE != NULL); - PRECONDITION(pServerUNSAFE != NULL); - } - CONTRACTL_END; - - BOOL fDispatched = FALSE; - MESSAGEREF pMessage = (MESSAGEREF) pMessageUNSAFE; - OBJECTREF pServer = (OBJECTREF) pServerUNSAFE; - HELPER_METHOD_FRAME_BEGIN_RET_2(pMessage, pServer); - - MetaSig *pSig = pMessage->GetResetMetaSig(); - - if (pMessage->GetFlags() & (MSGFLG_BEGININVOKE | MSGFLG_ENDINVOKE | MSGFLG_ONEWAY)) - { - fDispatched = FALSE; - goto lExit; - } - - { - ArgIterator argit(pSig); - - UINT nStackBytes; - MethodDesc *pMD; - PCODE pTarget; - - nStackBytes = argit.SizeOfFrameArgumentArray(); - pMD = pMessage->GetMethodDesc(); - - // Get the address of the code - pTarget = pMD->GetCallTarget(&(pServer)); - -#ifdef PROFILING_SUPPORTED - // If we're profiling, notify the profiler that we're about to invoke the remoting target - { - BEGIN_PIN_PROFILER(CORProfilerTrackRemoting()); - GCX_PREEMP(); - g_profControlBlock.pProfInterface->RemotingServerInvocationStarted(); - END_PIN_PROFILER(); - } -#endif // PROFILING_SUPPORTED - -#ifdef CALLDESCR_FPARGREGS - // @TODO: This code badly needs refactorization. It's largely shared with MethodDesc::CallDescr in - // method.cpp and CallDescrWithObjectArray in stackbuildersync.cpp. - - FloatArgumentRegisters *pFloatArgumentRegisters = NULL; - - // Iterate through all the args looking for floating point values that will be passed in (FP) argument - // registers. - int ofs; - while ((ofs = argit.GetNextOffset()) != TransitionBlock::InvalidOffset) - { - if (TransitionBlock::HasFloatRegister(ofs, argit.GetArgLocDescForStructInRegs())) - { - // Found a floating point argument register. The first time we find this we point - // pFloatArgumentRegisters to the part of the frame where these values were spilled (we don't do - // this unconditionally since the call worker can optimize out the copy of the floating point - // registers if none are involved at all. - pFloatArgumentRegisters = (FloatArgumentRegisters*)(pMessage->GetFrame()->GetTransitionBlock() + - TransitionBlock::GetOffsetOfFloatArgumentRegisters()); - - // That's all we need to do, CallDescrWorkerWithHandler will automatically pick up all the - // floating point argument values now. - break; - } - } -#endif // CALLDESCR_FPARGREGS - -#if defined(CALLDESCR_REGTYPEMAP) || defined(COM_STUBS_SEPARATE_FP_LOCATIONS) - DWORD_PTR dwRegTypeMap = 0; - - { - int ofs; - while ((ofs = argit.GetNextOffset()) != TransitionBlock::InvalidOffset) - { - int regArgNum = TransitionBlock::GetArgumentIndexFromOffset(ofs); - - if (regArgNum >= NUM_ARGUMENT_REGISTERS) - break; - - CorElementType argTyp = argit.GetArgType(); - -#ifdef CALLDESCR_REGTYPEMAP - FillInRegTypeMap(ofs, argTyp, (BYTE*)&dwRegTypeMap); -#endif - -#ifdef COM_STUBS_SEPARATE_FP_LOCATIONS - // If this is a floating point argument, it was stored in a - // separate area of the frame. Copy it into the argument array. - if (ELEMENT_TYPE_R4 == argTyp || ELEMENT_TYPE_R8 == argTyp) - { - TADDR pTransitionBlock = pMessage->GetFrame()->GetTransitionBlock(); - - PVOID pDest = (PVOID)(pTransitionBlock + ofs); - PVOID pSrc = (PVOID)(pTransitionBlock + pMessage->GetFrame()->GetFPArgOffset(regArgNum)); - - ARG_SLOT val; - if (ELEMENT_TYPE_R4 == argTyp) - val = FPSpillToR4(pSrc); - else - val = FPSpillToR8(pSrc); - - *(ARG_SLOT*)pDest = val; - } -#endif - } - } -#endif // CALLDESCR_REGTYPEMAP || COM_STUBS_SEPARATE_FP_LOCATIONS - - CallDescrData callDescrData; - - callDescrData.pSrc = (BYTE*)pMessage->GetFrame()->GetTransitionBlock() + sizeof(TransitionBlock); - callDescrData.numStackSlots = nStackBytes / STACK_ELEM_SIZE; -#ifdef CALLDESCR_ARGREGS - callDescrData.pArgumentRegisters = (ArgumentRegisters*)(pMessage->GetFrame()->GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters()); -#endif -#ifdef CALLDESCR_FPARGREGS - callDescrData.pFloatArgumentRegisters = pFloatArgumentRegisters; -#endif -#ifdef CALLDESCR_REGTYPEMAP - callDescrData.dwRegTypeMap = dwRegTypeMap; -#endif - callDescrData.fpReturnSize = argit.GetFPReturnSize(); - callDescrData.pTarget = pTarget; - - CallDescrWorkerWithHandler(&callDescrData); - -#ifdef PROFILING_SUPPORTED - // If we're profiling, notify the profiler that we're about to invoke the remoting target - { - BEGIN_PIN_PROFILER(CORProfilerTrackRemoting()); - GCX_PREEMP(); - g_profControlBlock.pProfInterface->RemotingServerInvocationReturned(); - END_PIN_PROFILER(); - } -#endif // PROFILING_SUPPORTED - - memcpyNoGCRefs(pMessage->GetFrame()->GetReturnValuePtr(), &callDescrData.returnValue, sizeof(callDescrData.returnValue)); - - fDispatched = TRUE; - } - -lExit: ; - HELPER_METHOD_FRAME_END(); - FC_RETURN_BOOL(fDispatched); -} -FCIMPLEND - -void CMessage::AppendAssemblyName(CQuickBytes &out, const CHAR* str) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - INJECT_FAULT(COMPlusThrowOM()); - PRECONDITION(CheckPointer(str)); - } - CONTRACTL_END; - - SIZE_T len = strlen(str) * sizeof(CHAR); - SIZE_T oldSize = out.Size(); - out.ReSizeThrows(oldSize + len + 2); - CHAR * cur = (CHAR *) ((BYTE *) out.Ptr() + oldSize - 1); - if (*cur) - cur++; - - *cur = ASSEMBLY_SEPARATOR_CHAR; - memcpy(cur + 1, str, len); - cur += (len + 1); - *cur = '\0'; -} - -//+---------------------------------------------------------------------------- -// -// Method: CMessage::GetAsyncBeginInfo -// -// Synopsis: Pull the AsyncBeginInfo object from an async call -// -//+---------------------------------------------------------------------------- -FCIMPL3(void, CMessage::GetAsyncBeginInfo, MessageObject* pMessageUNSAFE, OBJECTREF* ppACBD, OBJECTREF* ppState) -{ - CONTRACTL - { - FCALL_CHECK; - PRECONDITION(pMessageUNSAFE != NULL); - } - CONTRACTL_END; - - MESSAGEREF pMessage = (MESSAGEREF) pMessageUNSAFE; - _ASSERTE(pMessage->GetFlags() & MSGFLG_BEGININVOKE); - - HELPER_METHOD_FRAME_BEGIN_1(pMessage); - - LOG((LF_REMOTING, LL_INFO10, "CMessage::GetAsyncBeginInfo IN\n")); - - if (pMessage == NULL) - COMPlusThrow(kNullReferenceException, W("NullReference_This")); - - MetaSig *pSig = pMessage->GetResetMetaSig(); - - FramedMethodFrame * pFrame = pMessage->GetFrame(); - ArgIterator argit(pSig); - - if ((ppACBD != NULL) || (ppState != NULL)) - { - int ofs; - int last = TransitionBlock::InvalidOffset, secondtolast = TransitionBlock::InvalidOffset; - while ((ofs = argit.GetNextOffset()) != TransitionBlock::InvalidOffset) - { - secondtolast = last; - last = ofs; - } - _ASSERTE(secondtolast != TransitionBlock::InvalidOffset); - if (secondtolast != TransitionBlock::InvalidOffset && ppACBD != NULL) - SetObjectReferenceUnchecked(ppACBD, ObjectToOBJECTREF(*(Object **)(pFrame->GetTransitionBlock() + secondtolast))); - PREFIX_ASSUME(last != TransitionBlock::InvalidOffset); - if (ppState != NULL) - SetObjectReferenceUnchecked(ppState, ObjectToOBJECTREF(*(Object **)(pFrame->GetTransitionBlock() + last))); - } - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - -//+---------------------------------------------------------------------------- -// -// Method: CMessage::GetAsyncResult -// -// Synopsis: Pull the AsyncResult from an async call -// -//+---------------------------------------------------------------------------- -FCIMPL1(LPVOID, CMessage::GetAsyncResult, MessageObject* pMessageUNSAFE) -{ - CONTRACTL - { - FCALL_CHECK; - PRECONDITION(pMessageUNSAFE != NULL); - } - CONTRACTL_END; - - LPVOID retVal = NULL; - MESSAGEREF pMessage = (MESSAGEREF) pMessageUNSAFE; - _ASSERTE(pMessage->GetFlags() & MSGFLG_ENDINVOKE); - - HELPER_METHOD_FRAME_BEGIN_RET_1(pMessage); - - LOG((LF_REMOTING, LL_INFO10, "CMessage::GetAsyncResult IN\n")); - - retVal = GetLastArgument(&pMessage); - - HELPER_METHOD_FRAME_END(); - return retVal; -} -FCIMPLEND - -//+---------------------------------------------------------------------------- -// -// Method: CMessage::GetAsyncObject -// -// Synopsis: Pull the AsyncObject from an async call -// -//+---------------------------------------------------------------------------- -FCIMPL1(Object*, CMessage::GetAsyncObject, MessageObject* pMessageUNSAFE) -{ - CONTRACTL - { - FCALL_CHECK; - PRECONDITION(pMessageUNSAFE != NULL); - } - CONTRACTL_END; - - Object* pobjRetVal = NULL; - MESSAGEREF pMessage = (MESSAGEREF) pMessageUNSAFE; - HELPER_METHOD_FRAME_BEGIN_RET_1(pMessage); - - LOG((LF_REMOTING, LL_INFO10, "CMessage::GetAsyncObject IN\n")); - - FramedMethodFrame *pFrame = pMessage->GetFrame(); - MetaSig *pSig = pMessage->GetResetMetaSig(); - ArgIterator argit(pSig); - - pobjRetVal = *(Object**)(pFrame->GetTransitionBlock() + argit.GetThisOffset()); - - HELPER_METHOD_FRAME_END(); - return pobjRetVal; -} -FCIMPLEND - -//+---------------------------------------------------------------------------- -// -// Method: CMessage::GetLastArgument private -// -// Synopsis: Pull the last argument of 4 bytes off the stack -// -//+---------------------------------------------------------------------------- -LPVOID CMessage::GetLastArgument(MESSAGEREF *pMsg) -{ - CONTRACT(LPVOID) - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pMsg)); - POSTCONDITION(*pMsg != NULL); // CheckPointer doesn't seem to work here. - POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); - } - CONTRACT_END; - - FramedMethodFrame *pFrame = (*pMsg)->GetFrame(); - MetaSig *pSig = (*pMsg)->GetResetMetaSig(); - - ArgIterator argit(pSig); - int arg; - int backadder = TransitionBlock::InvalidOffset; - while ((arg = argit.GetNextOffset()) != TransitionBlock::InvalidOffset) - backadder = arg; - - _ASSERTE(backadder != TransitionBlock::InvalidOffset); - - RETURN *(LPVOID *)(pFrame->GetTransitionBlock() + backadder); -} - -//+---------------------------------------------------------------------------- -// -// Method: CMessage::DebugOut public -// -// Synopsis: temp Debug out until the classlibs have one. -// -//+---------------------------------------------------------------------------- -FCIMPL1(void, CMessage::DebugOut, StringObject* pOutUNSAFE) -{ - CONTRACTL - { - FCALL_CHECK; - PRECONDITION(pOutUNSAFE != NULL); - } - CONTRACTL_END; - -#ifdef _DEBUG - STRINGREF pOut = (STRINGREF) pOutUNSAFE; - HELPER_METHOD_FRAME_BEGIN_1(pOut); - - static int fMessageDebugOut = 0; - - if (fMessageDebugOut == 0) - fMessageDebugOut = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MessageDebugOut) ? 1 : -1; - - if (fMessageDebugOut == 1) - WszOutputDebugString(pOut->GetBuffer()); - - HELPER_METHOD_FRAME_END(); -#endif - - FCUnique(0x76); -} -FCIMPLEND - -//+---------------------------------------------------------------------------- -// -// Method: CMessage::HasVarArgs public -// -// Synopsis: Return TRUE if the method is a VarArgs Method -// -//+---------------------------------------------------------------------------- -FCIMPL1(FC_BOOL_RET, CMessage::HasVarArgs, MessageObject * pMessage) -{ - CONTRACTL - { - FCALL_CHECK; - PRECONDITION(CheckPointer(pMessage)); - } - CONTRACTL_END; - - BOOL result; - - // Need entire path to be SO_TOLERANT or put a Hard SO probe here as - // no failure path. - CONTRACT_VIOLATION(SOToleranceViolation); - - result = pMessage->GetMethodDesc()->IsVarArg(); - - FC_RETURN_BOOL(result); -} -FCIMPLEND - - -//static -int CMessage::GetStackOffset (FramedMethodFrame *pFrame, ArgIterator *pArgIter, MetaSig *pSig) -{ - CONTRACT(int) - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - INJECT_FAULT(COMPlusThrowOM()); - PRECONDITION(CheckPointer(pFrame)); - PRECONDITION(CheckPointer(pArgIter)); - PRECONDITION(CheckPointer(pSig)); - } - CONTRACT_END; - - LOG((LF_REMOTING, LL_INFO100, - "CMessage::GetStackOffset pFrame:0x%x, pArgIter:0x%x\n", - pFrame, pArgIter)); - - int ret = pArgIter->GetNextOffset(); - -#ifdef COM_STUBS_SEPARATE_FP_LOCATIONS - int typ = pArgIter->GetArgType(); - // REVISIT_TODO do we need to handle this? - if ((ELEMENT_TYPE_R4 == typ || ELEMENT_TYPE_R8 == typ) && - TransitionBlock::IsArgumentRegisterOffset(ret)) - { - int iFPArg = TransitionBlock::GetArgumentIndexFromOffset(ret); - - ret = static_cast(pFrame->GetFPArgOffset(iFPArg)); - } -#endif // COM_STUBS_SEPARATE_FP_LOCATIONS - - RETURN ret; -} - - -//+---------------------------------------------------------------------------- -// -// Method: CMessage::GetStackPtr private -// -// Synopsis: Figure out where on the stack a parameter is stored -// -// Parameters: ndx - the parameter index (zero-based) -// pFrame - stack frame pointer (FramedMethodFrame) -// pSig - method signature, used to determine parameter sizes -// -// -// -// CODEWORK: Currently we assume all parameters to be 32-bit intrinsics -// or 32-bit pointers. Value classes are not handled correctly. -// -//+---------------------------------------------------------------------------- -PVOID CMessage::GetStackPtr(INT32 ndx, FramedMethodFrame *pFrame, MetaSig *pSig) -{ - CONTRACT(PVOID) - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - INJECT_FAULT(COMPlusThrowOM()); - PRECONDITION(CheckPointer(pFrame)); - PRECONDITION(CheckPointer(pSig)); - POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); - } - CONTRACT_END; - - LOG((LF_REMOTING, LL_INFO100, - "CMessage::GetStackPtr IN ndx:0x%x, pFrame:0x%x, pSig:0x%x\n", - ndx, pFrame, pSig)); - - ArgIterator iter(pSig); - PVOID ret = NULL; - - // CODEWORK:: detect and optimize for sequential access - _ASSERTE((UINT)ndx < pSig->NumFixedArgs()); - for (int i=0; i<=ndx; i++) - ret = (BYTE*)pFrame->GetTransitionBlock() + GetStackOffset(pFrame, &iter, pSig); - - RETURN ret; -} - -#endif //FEATURE_REMOTING diff --git a/src/vm/remoting.cpp b/src/vm/remoting.cpp index 1b65323bb6..ee7d2cb021 100644 --- a/src/vm/remoting.cpp +++ b/src/vm/remoting.cpp @@ -381,7 +381,7 @@ VOID CRemotingServices::InitRemotingServicesClass() s_pCheckCast = MscorlibBinder::GetMethod(METHOD__REMOTING_SERVICES__CHECK_CAST); - // Need these to call wrap/unwrap from the VM (message.cpp). + // Need these to call wrap/unwrap from the VM. // Also used by JIT helpers to wrap/unwrap s_pWrapMethodDesc = MscorlibBinder::GetMethod(METHOD__REMOTING_SERVICES__WRAP); s_pProxyForDomainDesc = MscorlibBinder::GetMethod(METHOD__REMOTING_SERVICES__CREATE_PROXY_FOR_DOMAIN); -- cgit v1.2.3 From aac8c16336872daae128ad531720dcbafe7a98f5 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Sun, 12 Feb 2017 20:58:49 -0800 Subject: Remove dead mixedmode.cpp --- src/vm/mixedmode.cpp | 236 --------------------------------------------------- src/vm/mixedmode.hpp | 4 +- 2 files changed, 2 insertions(+), 238 deletions(-) delete mode 100644 src/vm/mixedmode.cpp diff --git a/src/vm/mixedmode.cpp b/src/vm/mixedmode.cpp deleted file mode 100644 index 32d4368363..0000000000 --- a/src/vm/mixedmode.cpp +++ /dev/null @@ -1,236 +0,0 @@ -// 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. -// =========================================================================== -// File: MIXEDMODE.CPP -// - -// - -// MIXEDMODE deals with mixed-mode binaries support -// =========================================================================== - - - -#include "common.h" - -#include "mixedmode.hpp" - -#include "dllimportcallback.h" - -#ifdef FEATURE_MIXEDMODE - - -IJWNOADThunk::IJWNOADThunk(HMODULE pModulebase, DWORD dwIndex, mdToken Token) -{ - LIMITED_METHOD_CONTRACT; - m_pModulebase=pModulebase; - m_dwIndex=dwIndex; - m_Token=Token; - m_fAccessingCache = 0; - - for (int i=0; i < IJWNOADThunkStubCacheSize; i++) - { - m_cache[i].m_AppDomainID = (ADID)-1; - m_cache[i].m_CodeAddr = 0; - } - -#ifdef _TARGET_X86_ - m_code.Encode((BYTE*)GetEEFuncEntryPoint(IJWNOADThunkJumpTarget), this); -#else // !_TARGET_X86_ - m_code.Encode((BYTE*)GetEEFuncEntryPoint(MakeCall), this); -#endif // !_TARGET_X86_ -}; - -#define E_PROCESS_SHUTDOWN_REENTRY HRESULT_FROM_WIN32(ERROR_PROCESS_ABORTED) - - -#ifdef _TARGET_X86_ -// Slow path lookup...called from stub -extern "C" LPCVOID __stdcall IJWNOADThunkJumpTargetHelper(IJWNOADThunk* pThunk) -{ - WRAPPER_NO_CONTRACT; - - return pThunk->FindThunkTarget(); -} -#endif // _TARGET_X86_ - -LPCVOID IJWNOADThunk::FindThunkTarget() -{ - CONTRACT(LPCVOID) - { - INSTANCE_CHECK; - NOTHROW; - GC_TRIGGERS; - MODE_ANY; - SO_TOLERANT; - POSTCONDITION(CheckPointer(RETVAL)); - } - CONTRACT_END; - - // We don't plan on fixing this in Whidbey...the IJW scenario has always assumed throwing is "ok" here. - CONTRACT_VIOLATION(ThrowsViolation); - - LPCVOID pvTargetCode = NULL; - - AppDomain* pDomain; - - Thread* pThread = SetupThread(); - - // Ensure that we're in preemptive mode. - // We only need this check for a newly created - // CLR thread - it defaults to COOP mode from here. - GCX_PREEMP_NO_DTOR(); - - pDomain = GetAppDomain(); - - if (NULL == pDomain) - { - _ASSERTE(!"Appdomain should've been set up by SetupThread"); - pDomain = SystemDomain::System()->DefaultDomain(); - } - - - if (NULL != pDomain) - { - // Get a local copy so we don't have to deal with a race condition. - LPCVOID pCacheTarget = NULL; - GetCachedInfo(pDomain->GetId(), &pvTargetCode); - - // Cache miss. - if (pvTargetCode==NULL) - { - INSTALL_UNWIND_AND_CONTINUE_HANDLER; - BEGIN_SO_INTOLERANT_CODE(pThread); - { - Module* pModule; - - pModule = pDomain->GetIJWModule(m_pModulebase); - if (NULL == pModule) - { - // New for Whidbey: In V1.1, we just gave up and raised an exception if the target assembly wasn't already loaded - // into the current appdomain. We now force-inject the assembly. - - PEAssemblyHolder pFile(pDomain->BindExplicitAssembly(m_pModulebase, FALSE)); - pDomain->LoadAssembly(NULL, pFile, FILE_ACTIVE); - - // Now, try the lookup again. The LoadAssembly() either worked or it didn't. If it didn't, it is probably - // due to lack of memory and all we can do is raise an exception and hope the IJW caller does something reasonable. - // Otherwise, we should now succeed in finding the current domain's instantiation of the target module. - pModule = pDomain->GetIJWModule(m_pModulebase); - } - - if (NULL != pModule) - { - pModule->EnsureActive(); - - UMEntryThunk* pThunkTable; - - pThunkTable = pModule->GetADThunkTable(); - pvTargetCode = (LPVOID)GetEEFuncEntryPoint((LPVOID)pThunkTable[m_dwIndex].GetCode()); - - // Populate the cache with our latest info. - SetCachedInfo(pDomain->GetId(), pvTargetCode); - } - } - END_SO_INTOLERANT_CODE; - UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; - } - } - - if(pvTargetCode==NULL) - pvTargetCode=(LPVOID)GetEEFuncEntryPoint(SafeNoModule); - - RETURN (LPCVOID)pvTargetCode; -} - -#ifdef _TARGET_X86_ - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning (disable : 4740) // There is inline asm code in this function, which disables - // global optimizations. -#endif // _MSC_VER - -__declspec(naked) void _cdecl IJWNOADThunk::MakeCall() -{ - WRAPPER_NO_CONTRACT; - struct - { - LPVOID This; - LPCVOID RetAddr; - } Vars; - #define LocalsSize 8 - - _asm enter LocalsSize+4,0; - _asm push ebx; - _asm push ecx; - _asm push edx; - _asm push esi; - _asm push edi; - - _asm mov Vars.This, eax; - - //careful above this point - _ASSERTE(sizeof(Vars)<=LocalsSize); - - Vars.RetAddr = ((IJWNOADThunk*)Vars.This)->FindThunkTarget(); - - _ASSERTE(NULL != Vars.RetAddr); - - _asm pop edi; - _asm pop esi; - _asm pop edx; - _asm pop ecx; - _asm pop ebx; - _asm mov eax,Vars.RetAddr; - _asm leave; - _asm jmp eax; -}; - -#if defined(_MSC_VER) -#pragma warning(pop) -#endif - -#elif defined(_TARGET_AMD64_) -// Implemented in AMD64\UMThunkStub.asm -#elif defined(_TARGET_ARM_) -// Implemented in Arm\asmhelpers.asm -#else -void __cdecl IJWNOADThunk::MakeCall() -{ - LIMITED_METHOD_CONTRACT; - PORTABILITY_ASSERT("IJWNOADThunk::MakeCall"); -} -#endif - -void IJWNOADThunk::SafeNoModule() -{ - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - - if (!CanRunManagedCode()) - { - Thread* pThread=GetThread(); - - // DO NOT IMPROVE THIS EXCEPTION! It cannot be a managed exception. It - // cannot be a real exception object because we cannot execute any managed - // code here. - if(pThread) - pThread->m_fPreemptiveGCDisabled = 0; - COMPlusThrowBoot(E_PROCESS_SHUTDOWN_REENTRY); - } - NoModule(); -} - -void IJWNOADThunk::NoModule() -{ - WRAPPER_NO_CONTRACT; - INSTALL_UNWIND_AND_CONTINUE_HANDLER; - //This should give the file name as part of the exception message! - COMPlusThrowHR(COR_E_DLLNOTFOUND); - UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; -} - -#endif // FEATURE_MIXEDMODE - diff --git a/src/vm/mixedmode.hpp b/src/vm/mixedmode.hpp index 9d5037af8d..0010410f36 100644 --- a/src/vm/mixedmode.hpp +++ b/src/vm/mixedmode.hpp @@ -2,11 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. // =========================================================================== -// File: mixedmode.H +// File: mixedmode.hpp // // -// MIXEDMODE.H defines classes to support mixed mode dlls +// MIXEDMODE.HPP defines classes to support mixed mode dlls // =========================================================================== -- cgit v1.2.3 From 0627527ec3b9921928e7ed3ba9f7d1c34cbdb627 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Sun, 12 Feb 2017 21:00:22 -0800 Subject: Remove dead objectclone.cpp --- src/vm/objectclone.cpp | 3861 ------------------------------------------------ 1 file changed, 3861 deletions(-) delete mode 100644 src/vm/objectclone.cpp diff --git a/src/vm/objectclone.cpp b/src/vm/objectclone.cpp deleted file mode 100644 index 93c9d3c30f..0000000000 --- a/src/vm/objectclone.cpp +++ /dev/null @@ -1,3861 +0,0 @@ -// 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. -// -// File: ObjectClone.cpp -// - -// - - -#include "common.h" - -#ifdef FEATURE_REMOTING -#include "objectclone.h" -#include "frames.h" -#include "assembly.hpp" -#include "field.h" -#include "security.h" -#include "virtualcallstub.h" -#include "crossdomaincalls.h" -#include "callhelpers.h" -#include "jitinterface.h" -#include "typestring.h" -#include "typeparse.h" -#include "runtimehandles.h" -#include "appdomain.inl" - -// Define the following to re-enable object cloner strict mode (where we require source fields for non-optional destination fields -// and don't attempt to load assemblies we can't find via display via partial names instead). -//#define OBJECT_CLONER_STRICT_MODE - -void MakeIDeserializationCallback(OBJECTREF refTarget); - -MethodDesc *GetInterfaceMethodImpl(MethodTable *pMT, MethodTable *pItfMT, WORD wSlot) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - } CONTRACTL_END; - - MethodDesc *pMeth = NULL; - DispatchSlot slot(pMT->FindDispatchSlot(pItfMT->GetTypeID(), (UINT32)wSlot)); - CONSISTENCY_CHECK(!slot.IsNull()); - pMeth = slot.GetMethodDesc(); - return pMeth; -} - -// Given a FieldDesc which may be representative and an object which contains said field, return the actual type of the field. This -// works even when called from a different appdomain from which the type was loaded (though naturally it is the caller's -// responsbility to ensure such an appdomain cannot be unloaded during the processing of this method). -TypeHandle LoadExactFieldType(FieldDesc *pFD, OBJECTREF orefParent, AppDomain *pDomain) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - MethodTable *pEnclosingMT = orefParent->GetMethodTable(); - - // Set up a field signature with the owning type providing a type context for any type variables. - MetaSig sig(pFD, TypeHandle(pEnclosingMT)); - sig.NextArg(); - - // If the enclosing type is resident to this domain or domain neutral and loaded in this domain then we can simply go get it. - // The logic is trickier (and more expensive to calculate) for generic types, so skip the optimization there. - if (pEnclosingMT->GetDomain() == GetAppDomain() || - (pEnclosingMT->IsDomainNeutral() && - !pEnclosingMT->HasInstantiation() && - pEnclosingMT->GetAssembly()->FindDomainAssembly(GetAppDomain()))) - return sig.GetLastTypeHandleThrowing(); - - TypeHandle retTH; - - // Otherwise we have to do this the expensive way -- switch to the home domain for the type lookup. - ENTER_DOMAIN_PTR(pDomain, ADV_RUNNINGIN); - retTH = sig.GetLastTypeHandleThrowing(); - END_DOMAIN_TRANSITION; - - return retTH; -} - -extern TypeHandle GetTypeByName( _In_opt_z_ LPUTF8 szFullClassName, - BOOL bThrowOnError, - BOOL bIgnoreCase, - StackCrawlMark *stackMark, - BOOL *pbAssemblyIsLoading); - -#ifndef DACCESS_COMPILE -#define CUSTOM_GCPROTECT_BEGIN(context) do { \ - FrameWithCookie __gcframe(context); \ - /* work around unreachable code warning */ \ - if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT) - -#define CUSTOM_GCPROTECT_END() \ - DEBUG_ASSURE_NO_RETURN_END(GCPROTECT) } \ - __gcframe.Pop(); } while(0) - -#else // #ifndef DACCESS_COMPILE - -#define CUSTOM_GCPROTECT_BEGIN(context) -#define CUSTOM_GCPROTECT_END() - -#endif // #ifndef DACCESS_COMPILE - -int GCSafeObjectHashTable::HasID(OBJECTREF refObj, OBJECTREF *newObj) -{ - CONTRACTL - { - MODE_COOPERATIVE; - THROWS; - GC_NOTRIGGER; - } - CONTRACTL_END - - BOOL seenBefore = FALSE; - *newObj = NULL; - int index = FindElement(refObj, seenBefore); - - if (seenBefore) - { - _ASSERTE(index < (int)m_currArraySize); - *newObj = m_newObjects[index]; - return m_ids[index]; - } - - return -1; -} - -// returns the object id -int GCSafeObjectHashTable::AddObject(OBJECTREF refObj, OBJECTREF newObj) -{ - CONTRACTL - { - MODE_COOPERATIVE; - THROWS; - GC_NOTRIGGER; - } - CONTRACTL_END - - int index = -1; - GCPROTECT_BEGIN(refObj); - GCPROTECT_BEGIN(newObj); - - if (m_count > m_currArraySize / 2) - { - Resize(); - } - - BOOL seenBefore = FALSE; - index = FindElement(refObj, seenBefore); - - _ASSERTE(index >= 0 && index < (int)m_currArraySize); - if (seenBefore) - { - _ASSERTE(!"Adding an object thats already present"); - } - else - { - m_objects[index] = refObj; - m_newObjects[index] = newObj; - m_ids[index] = ++m_count; - } - - GCPROTECT_END(); - GCPROTECT_END(); - - return m_ids[index]; -} - -// returns the object id -int GCSafeObjectHashTable::UpdateObject(OBJECTREF refObj, OBJECTREF newObj) -{ - CONTRACTL - { - MODE_COOPERATIVE; - THROWS; - GC_NOTRIGGER; - } - CONTRACTL_END - - int index = -1; - GCPROTECT_BEGIN(refObj); - GCPROTECT_BEGIN(newObj); - - BOOL seenBefore = FALSE; - index = FindElement(refObj, seenBefore); - - _ASSERTE(index >= 0 && index < (int)m_currArraySize); - if (!seenBefore) - { - _ASSERTE(!"An object has to exist in the table, to update it"); - } - else - { - _ASSERTE(m_objects[index] == refObj); - m_newObjects[index] = newObj; - } - - GCPROTECT_END(); - GCPROTECT_END(); - - return m_ids[index]; -} - -// returns index into array where obj was found or will fit in -int GCSafeObjectHashTable::FindElement(OBJECTREF refObj, BOOL &seenBefore) -{ - CONTRACTL - { - MODE_COOPERATIVE; - THROWS; - GC_NOTRIGGER; - } - CONTRACTL_END - - int currentNumBuckets = m_currArraySize / NUM_SLOTS_PER_BUCKET; - int hashcode = 0; - GCPROTECT_BEGIN(refObj); - hashcode = refObj->GetHashCodeEx(); - GCPROTECT_END(); - - hashcode &= 0x7FFFFFFF; // ignore sign bit - int hashIncrement = (1+((hashcode)%(currentNumBuckets-2))); -#ifdef _DEBUG - int numLoops = 0; -#endif - - do - { - int index = ((unsigned)hashcode % currentNumBuckets) * NUM_SLOTS_PER_BUCKET; - _ASSERTE(index >= 0 && index < (int)m_currArraySize); - for (int i = index; i < index + NUM_SLOTS_PER_BUCKET; i++) - { - if (m_objects[i] == refObj) - { - seenBefore = TRUE; - return i; - } - - if (m_objects[i] == NULL) - { - seenBefore = FALSE; - return i; - } - } - hashcode += hashIncrement; -#ifdef _DEBUG - if (++numLoops > currentNumBuckets) - _ASSERTE(!"Looped too many times, trying to find object in hashtable. If hitting ignore doesnt seem to help, then contact Ashok"); -#endif - }while (true); - - _ASSERTE(!"Not expected to reach here in GCSafeObjectHashTable::FindElement"); - return -1; -} - -void GCSafeObjectHashTable::Resize() -{ - CONTRACTL - { - MODE_COOPERATIVE; - THROWS; - GC_NOTRIGGER; - } - CONTRACTL_END - // Allocate new space - DWORD newSize = m_currArraySize * 2; - for (int i = 0; (DWORD) i < sizeof(g_rgPrimes)/sizeof(DWORD); i++) - { - if (g_rgPrimes[i] > newSize) - { - newSize = g_rgPrimes[i]; - break; - } - } - - newSize *= NUM_SLOTS_PER_BUCKET; - NewArrayHolder refTemp (new OBJECTREF[newSize]); - ZeroMemory((void *)refTemp, sizeof(OBJECTREF) * newSize); - - NewArrayHolder refTempNewObj (new OBJECTREF[newSize]); -#ifdef USE_CHECKED_OBJECTREFS - ZeroMemory((void *)refTempNewObj, sizeof(OBJECTREF) * newSize); -#endif - - NewArrayHolder bTemp (new int[newSize]); - ZeroMemory((void *)bTemp, sizeof(int) * newSize); - - // Copy over objects and data - NewArrayHolder refOldObj (m_objects); - NewArrayHolder refOldNewObj (m_newObjects); - NewArrayHolder oldIds (m_ids); - DWORD oldArrSize = m_currArraySize; - - if (oldIds == (int *)&m_dataOnStack[0]) - { - refOldObj.SuppressRelease(); - refOldNewObj.SuppressRelease(); - oldIds.SuppressRelease(); - } - - refTemp.SuppressRelease(); - refTempNewObj.SuppressRelease(); - bTemp.SuppressRelease(); - - m_ids = bTemp; - m_objects = refTemp; - m_newObjects = refTempNewObj; - m_currArraySize = newSize; - - for (DWORD i = 0; i < oldArrSize; i++) - { - if (refOldObj[i] == NULL) - continue; - - BOOL seenBefore = FALSE; - int newIndex = FindElement(refOldObj[i], seenBefore); - - if (!seenBefore) - { - _ASSERTE(newIndex < (int)m_currArraySize); - m_objects[newIndex] = refOldObj[i]; - m_newObjects[newIndex] = refOldNewObj[i]; - m_ids[newIndex] = oldIds[i]; - } - else - _ASSERTE(!"Object seen twice while rehashing"); - } - -#ifdef USE_CHECKED_OBJECTREFS - for(DWORD i = 0; i < m_currArraySize; i++) - Thread::ObjectRefProtected(&m_objects[i]); - for(DWORD i = 0; i < m_currArraySize; i++) - Thread::ObjectRefProtected(&m_newObjects[i]); -#endif - -} - -void GCSafeObjectTable::Push(OBJECTREF refObj, OBJECTREF refParent, OBJECTREF refAux, QueuedObjectInfo * pQOI) -{ - CONTRACTL - { - THROWS; - MODE_COOPERATIVE; - GC_NOTRIGGER; - } - CONTRACTL_END - _ASSERTE(refObj != NULL); - _ASSERTE(m_QueueType == LIFO_QUEUE); - _ASSERTE(m_head == 0 && m_dataHead == 0); - - // First find the size of the object info - DWORD size = pQOI->GetSize(); - - // Check if resize is needed - EnsureSize(size); - - // Push on the stack, first the objects - DWORD index = m_count; - if (m_Objects1) - m_Objects1[index] = refObj; -#ifdef _DEBUG - else - _ASSERTE(refObj == NULL); -#endif - if (m_Objects2) - m_Objects2[index] = refParent; -#ifdef _DEBUG - else - _ASSERTE(refParent == NULL); -#endif - if (m_Objects3) - m_Objects3[index] = refAux; -#ifdef _DEBUG - else - _ASSERTE(refAux == NULL); -#endif - - // then the info - if (m_dataIndices) - m_dataIndices[index] = m_numDataBytes; - BYTE *pData = &m_data[m_numDataBytes]; - memcpy(pData, (VOID*)pQOI, size); - - m_numDataBytes += size; - m_count++; -} - -OBJECTREF GCSafeObjectTable::Pop(OBJECTREF *refParent, OBJECTREF *refAux, QueuedObjectInfo ** pQOI) -{ - LIMITED_METHOD_CONTRACT; - _ASSERTE(m_QueueType == LIFO_QUEUE); - _ASSERTE(m_head == 0 && m_dataHead == 0); - _ASSERTE(m_dataIndices != NULL); - - *pQOI = NULL; - OBJECTREF refRet = NULL; - *refParent = NULL; - *refAux = NULL; - if (m_count == 0) - return NULL; - - m_count--; - refRet = m_Objects1[m_count]; - if (m_Objects2) - *refParent = m_Objects2[m_count]; - if (m_Objects3) - *refAux = m_Objects3[m_count]; - *pQOI = (QueuedObjectInfo *) &m_data[m_dataIndices[m_count]]; - - m_numDataBytes -= (*pQOI)->GetSize(); - return refRet; -} - -void GCSafeObjectTable::SetAt(DWORD index, OBJECTREF refObj, OBJECTREF refParent, OBJECTREF refAux, QueuedObjectInfo * pQOI) -{ - CONTRACTL - { - THROWS; - MODE_COOPERATIVE; - GC_NOTRIGGER; - } - CONTRACTL_END - _ASSERTE(refObj != NULL); -#ifdef _DEBUG - if (m_QueueType == LIFO_QUEUE) - _ASSERTE(index >= 0 && index < m_count); - else - _ASSERTE(index < m_currArraySize); -#endif - - // First find the size of the object info - DWORD size = pQOI->GetSize(); - - // Push on the stack, first the objects - m_Objects1[index] = refObj; - if (m_Objects2) - m_Objects2[index] = refParent; - if (m_Objects3) - m_Objects3[index] = refAux; - - // then the info - _ASSERTE(m_dataIndices != NULL); - - QueuedObjectInfo *pData = (QueuedObjectInfo *)&m_data[m_dataIndices[index]]; - _ASSERTE(pData->GetSize() == size); - - memcpy(pData, (VOID*)pQOI, size); -} - -OBJECTREF GCSafeObjectTable::GetAt(DWORD index, OBJECTREF *refParent, OBJECTREF *refAux, QueuedObjectInfo ** pQOI) -{ - LIMITED_METHOD_CONTRACT; -#ifdef _DEBUG - if (m_QueueType == LIFO_QUEUE) - _ASSERTE(index >= 0 && index < m_count); - else - _ASSERTE(index < m_currArraySize); -#endif - - OBJECTREF refRet = m_Objects1[index]; - if (m_Objects2) - *refParent = m_Objects2[index]; - else - *refParent = NULL; - if (m_Objects3) - *refAux = m_Objects3[index]; - else - *refAux = NULL; - - _ASSERTE(m_dataIndices != NULL); - - *pQOI = (QueuedObjectInfo *) &m_data[m_dataIndices[index]]; - - return refRet; -} - -void GCSafeObjectTable::Enqueue(OBJECTREF refObj, OBJECTREF refParent, OBJECTREF refAux, QueuedObjectInfo *pQOI) -{ - CONTRACTL - { - THROWS; - MODE_COOPERATIVE; - GC_NOTRIGGER; - } - CONTRACTL_END - - _ASSERTE(refObj != NULL); - _ASSERTE(m_QueueType == FIFO_QUEUE); - - // First find the size of the object info - DWORD size = pQOI ? pQOI->GetSize() : 0; - - // Check if resize is needed - EnsureSize(size); - - // Append to queue, first the objects - DWORD index = (m_head + m_count) % m_currArraySize; - m_Objects1[index] = refObj; - if (m_Objects2) - m_Objects2[index] = refParent; - if (m_Objects3) - m_Objects3[index] = refAux; - - // then the info - if (pQOI) - { - DWORD dataIndex = (m_dataHead + m_numDataBytes) % (m_currArraySize * MAGIC_FACTOR); - BYTE *pData = &m_data[dataIndex]; - memcpy(pData, (VOID*)pQOI, size); - - if (m_dataIndices) - m_dataIndices[index] = dataIndex; - m_numDataBytes += size; - } - - m_count++; -} - -OBJECTREF GCSafeObjectTable::Dequeue(OBJECTREF *refParent, OBJECTREF *refAux, QueuedObjectInfo ** pQOI) -{ - LIMITED_METHOD_CONTRACT; - - _ASSERTE(m_QueueType == FIFO_QUEUE); - - if (pQOI) - *pQOI = NULL; - OBJECTREF refRet = NULL; - *refParent = NULL; - *refAux = NULL; - if (m_count == 0) - return NULL; - - refRet = m_Objects1[m_head]; - if (m_Objects2) - *refParent = m_Objects2[m_head]; - if (m_Objects3) - *refAux = m_Objects3[m_head]; - - if (pQOI) - { - *pQOI = (QueuedObjectInfo *) &m_data[m_dataHead]; - - m_dataHead = (m_dataHead + (*pQOI)->GetSize()) % (m_currArraySize * MAGIC_FACTOR); - - m_numDataBytes -= (*pQOI)->GetSize(); - } - - m_head = (m_head + 1) % m_currArraySize; - m_count--; - return refRet; -} - -OBJECTREF GCSafeObjectTable::Peek(OBJECTREF *refParent, OBJECTREF *refAux, QueuedObjectInfo **pQOI) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; - MODE_COOPERATIVE; - } - CONTRACTL_END; - - *pQOI = NULL; - *refParent = NULL; - *refAux = NULL; - if (m_count == 0) - return NULL; - - DWORD indexToPeek; - if (m_QueueType == LIFO_QUEUE) - { - indexToPeek = m_count; - return GetAt(indexToPeek, refParent, refAux, pQOI); - } - else - { - indexToPeek = m_head; - if (m_Objects2) - *refParent = m_Objects2[m_head]; - if (m_Objects3) - *refParent = m_Objects3[m_head]; - *pQOI = (QueuedObjectInfo *) &m_data[m_dataHead]; - return m_Objects1[m_head]; - } - -} - -void GCSafeObjectTable::EnsureSize(DWORD requiredDataSize) -{ - CONTRACTL - { - THROWS; - MODE_COOPERATIVE; - GC_NOTRIGGER; - } - CONTRACTL_END - // Check if the object queue is sized enough - if (m_count == m_currArraySize) - { - Resize(); - return; - } - - // Check if the data array size is enough - if (m_numDataBytes + requiredDataSize > m_currArraySize * MAGIC_FACTOR) - { - Resize(); - return; - } - - if (m_QueueType == FIFO_QUEUE) - { - // Will current QueuedObjectInfo go beyond the edge of the array ? - if (m_dataHead + m_numDataBytes + requiredDataSize > m_currArraySize * MAGIC_FACTOR) - { - Resize(); - return; - } - } -} - -void GCSafeObjectTable::Resize() -{ - CONTRACTL - { - THROWS; - MODE_COOPERATIVE; - GC_NOTRIGGER; - } - CONTRACTL_END - // Allocate new space - DWORD newSize = m_currArraySize * 2; - NewArrayHolder refTemp (NULL); - NewArrayHolder refParentTemp (NULL); - NewArrayHolder refAuxTemp (NULL); - - refTemp = new OBJECTREF[newSize]; - if (m_Objects2) - refParentTemp = new OBJECTREF[newSize]; - if (m_Objects3) - refAuxTemp = new OBJECTREF[newSize]; - -#ifdef USE_CHECKED_OBJECTREFS - ZeroMemory((void *)refTemp, sizeof(OBJECTREF) * newSize); - if (m_Objects2) - ZeroMemory((void *)refParentTemp, sizeof(OBJECTREF) * newSize); - if (m_Objects3) - ZeroMemory((void *)refAuxTemp, sizeof(OBJECTREF) * newSize); -#endif - - NewArrayHolder bTemp (NULL); - NewArrayHolder dwIndicesTemp (NULL); - - bTemp = new BYTE[newSize * MAGIC_FACTOR]; - if (m_dataIndices) - dwIndicesTemp = new DWORD[newSize]; - - // Copy over objects and data - if (m_QueueType == LIFO_QUEUE || (m_QueueType == FIFO_QUEUE && m_head == 0)) - { - void *pSrc = (void *)&m_Objects1[0]; - void *pDest = (void *)&refTemp[0]; - memcpyUnsafe(pDest, pSrc, m_count * sizeof(OBJECTREF)); - - if (m_Objects2) - { - pSrc = (void *)&m_Objects2[0]; - pDest = (void *)&refParentTemp[0]; - memcpyUnsafe(pDest, pSrc, m_count * sizeof(OBJECTREF)); - } - - if (m_Objects3) - { - pSrc = (void *)&m_Objects3[0]; - pDest = (void *)&refAuxTemp[0]; - memcpyUnsafe(pDest, pSrc, m_count * sizeof(OBJECTREF)); - } - - pSrc = (void *)&m_data[0]; - pDest = (void *)&bTemp[0]; - memcpyNoGCRefs(pDest, pSrc, m_numDataBytes); - - if (m_dataIndices) - { - pSrc = (void *)&m_dataIndices[0]; - pDest = (void *)&dwIndicesTemp[0]; - memcpyNoGCRefs(pDest, pSrc, m_count * sizeof(DWORD)); - } - - } - else - { - _ASSERTE(m_QueueType == FIFO_QUEUE && m_head != 0); - _ASSERTE(m_currArraySize > m_head); - DWORD numObjRefsToCopy = (m_count > m_currArraySize - m_head ? m_currArraySize - m_head : m_count); - - void *pSrc = (void *)&m_Objects1[m_head]; - void *pDest = (void *)&refTemp[0]; - memcpyUnsafe(pDest, pSrc, numObjRefsToCopy * sizeof(OBJECTREF)); - pSrc = (void *)&m_Objects1[0]; - pDest = (void *)&refTemp[numObjRefsToCopy]; - memcpyUnsafe(pDest, pSrc, (m_count - numObjRefsToCopy) * sizeof(OBJECTREF)); - - if (m_Objects2) - { - pSrc = (void *)&m_Objects2[m_head]; - pDest = (void *)&refParentTemp[0]; - memcpyUnsafe(pDest, pSrc, numObjRefsToCopy * sizeof(OBJECTREF)); - pSrc = (void *)&m_Objects2[0]; - pDest = (void *)&refParentTemp[numObjRefsToCopy]; - memcpyUnsafe(pDest, pSrc, (m_count - numObjRefsToCopy) * sizeof(OBJECTREF)); - } - - if (m_Objects3) - { - pSrc = (void *)&m_Objects3[m_head]; - pDest = (void *)&refAuxTemp[0]; - memcpyUnsafe(pDest, pSrc, numObjRefsToCopy * sizeof(OBJECTREF)); - pSrc = (void *)&m_Objects3[0]; - pDest = (void *)&refAuxTemp[numObjRefsToCopy]; - memcpyUnsafe(pDest, pSrc, (m_count - numObjRefsToCopy) * sizeof(OBJECTREF)); - } - - if (m_dataIndices) - { - pSrc = (void *)&m_dataIndices[m_head]; - pDest = (void *)&dwIndicesTemp[0]; - memcpyUnsafe(pDest, pSrc, numObjRefsToCopy * sizeof(DWORD)); - pSrc = (void *)&m_dataIndices[0]; - pDest = (void *)&dwIndicesTemp[numObjRefsToCopy]; - memcpyUnsafe(pDest, pSrc, (m_count - numObjRefsToCopy) * sizeof(DWORD)); - } - - DWORD numBytesToCopy = (m_numDataBytes > ((m_currArraySize * MAGIC_FACTOR) - m_dataHead) ? ((m_currArraySize * MAGIC_FACTOR) - m_dataHead) : m_numDataBytes);//(m_currArraySize * MAGIC_FACTOR) - m_dataHead; - memcpyNoGCRefs((void *)bTemp, (void *) &m_data[m_dataHead], numBytesToCopy); - memcpyNoGCRefs((void *) &bTemp[numBytesToCopy], (void *)m_data, (m_numDataBytes - numBytesToCopy)); - } - - // Delete old allocation - if (m_usingHeap) - { - delete[] m_data; - delete[] m_Objects1; - delete[] m_Objects2; - delete[] m_Objects3; - delete[] m_dataIndices; - } - - refTemp.SuppressRelease(); - refParentTemp.SuppressRelease(); - refAuxTemp.SuppressRelease(); - dwIndicesTemp.SuppressRelease(); - bTemp.SuppressRelease(); - - m_currArraySize = newSize; - m_Objects1 = refTemp; - m_Objects2 = refParentTemp; - m_Objects3 = refAuxTemp; - m_dataIndices = dwIndicesTemp; - m_data = bTemp; - m_head = 0; - m_dataHead = 0; - - m_usingHeap = TRUE; -#ifdef USE_CHECKED_OBJECTREFS - for(DWORD i = 0; i < m_currArraySize; i++) - { - Thread::ObjectRefProtected(&m_Objects1[i]); - if (m_Objects2) - Thread::ObjectRefProtected(&m_Objects2[i]); - if (m_Objects3) - Thread::ObjectRefProtected(&m_Objects3[i]); - } -#endif -} - - -VOID GCScanRootsInCollection(promote_func *fn, ScanContext* sc, void *context) -{ - STATIC_CONTRACT_SO_TOLERANT; - GCSafeCollection *pObjCollection = (GCSafeCollection *)context; - pObjCollection->ReportGCRefs(fn, sc); -} - -VOID -BeginCloning(ObjectClone *pOC) -{ - pOC->Init(FALSE); -} - -VOID -EndCloning(ObjectClone *pOC) -{ - pOC->Cleanup(FALSE); -} - -typedef Holder ObjectCloneHolder; - - -OBJECTREF ObjectClone::Clone(OBJECTREF refObj, TypeHandle expectedType, AppDomain* fromDomain, AppDomain* toDomain, OBJECTREF refExecutionContext) -{ - CONTRACTL - { - MODE_COOPERATIVE; - THROWS; - GC_TRIGGERS; - } - CONTRACTL_END - - if (refObj == NULL) - return NULL; - - if (m_context != ObjectFreezer && refObj->GetMethodTable() == g_pStringClass) - return refObj; - - ObjectCloneHolder ocHolder(this); - - m_fromDomain = fromDomain; - m_toDomain = toDomain; - - m_currObject = refObj; - GCPROTECT_BEGIN(m_currObject); - m_topObject = NULL; - GCPROTECT_BEGIN(m_topObject); - m_fromExecutionContext = refExecutionContext; - GCPROTECT_BEGIN(m_fromExecutionContext); - - // Enter the domain we're cloning into, if we're not already there - ENTER_DOMAIN_PTR(toDomain,ADV_RUNNINGIN); - - if (!m_securityChecked) - { - Security::SpecialDemand(SSWT_DEMAND_FROM_NATIVE, SECURITY_SERIALIZATION); - m_securityChecked = TRUE; - } - -#ifdef _DEBUG - DefineFullyQualifiedNameForClass(); - LOG((LF_REMOTING, LL_INFO100, "Clone. Cloning instance of type %s.\n", - GetFullyQualifiedNameForClassNestedAware(m_currObject->GetMethodTable()))); -#endif - - m_newObject = NULL; - GCPROTECT_BEGIN(m_newObject); - PTRARRAYREF refValues = NULL; - GCPROTECT_BEGIN(refValues); - OBJECTREF refParent = NULL; - GCPROTECT_BEGIN(refParent); - - QueuedObjectInfo *currObjFixupInfo = NULL; - // For some dynamically sized stack objects - void *pTempStackSpace = NULL; - DWORD dwCurrStackSpaceSize = 0; - - // Initialize QOM - QueuedObjectInfo topObj; - OBJECTREF dummy1, dummy2; - QOM.Enqueue(m_currObject, NULL, NULL, (QueuedObjectInfo *)&topObj); - - while ((m_currObject = QOM.Dequeue(&dummy1, &dummy2, &currObjFixupInfo)) != NULL) - { - m_newObject = NULL; - MethodTable *newMT = NULL; - - BOOL repeatObject = FALSE; - BOOL isISerializable = FALSE, isIObjRef = FALSE, isBoxed = FALSE; - DWORD ISerializableTSOIndex = (DWORD) -1; - DWORD IObjRefTSOIndex = (DWORD) -1; - DWORD BoxedValTSOIndex = (DWORD) -1; - m_skipFieldScan = FALSE; - - // ALLOCATE PHASE - - // Was currObject seen before ? - int currID = TOS.HasID(m_currObject, &m_newObject); - if (currID != -1) - { - // Yes - repeatObject = TRUE; - m_skipFieldScan = TRUE; - newMT = m_newObject->GetMethodTable(); - - if (m_cbInterface->IsISerializableType(newMT)) - { - currObjFixupInfo->SetIsISerializableInstance(); - isISerializable = TRUE; - ISerializableTSOIndex = FindObjectInTSO(currID, ISerializable); - } - -#ifdef _DEBUG - LOG((LF_REMOTING, LL_INFO1000, "Clone. Object of type %s with id %d seen before.\n", - GetFullyQualifiedNameForClassNestedAware(m_currObject->GetMethodTable()), currID)); -#endif - } - else - { -#ifdef _DEBUG - LOG((LF_REMOTING, LL_INFO1000, "Clone. Object of type %s not seen before.\n", - GetFullyQualifiedNameForClassNestedAware(m_currObject->GetMethodTable()))); -#endif - // No - MethodTable *currMT = m_currObject->GetMethodTable(); - - // Check whether object is serializable - m_cbInterface->ValidateFromType(currMT); - - // Add current object to table of seen objects and get an id - currID = TOS.AddObject(m_currObject, m_newObject); - LOG((LF_REMOTING, LL_INFO1000, "Clone. Current object added to Table of Objects Seen. Given id %d.\n", currID)); - - if ( m_cbInterface->IsRemotedType(currMT, m_fromDomain, m_toDomain)) - { - refValues = AllocateISerializable(currID, TRUE); - isISerializable = TRUE; - ISerializableTSOIndex = TSO.GetCount() - 1; - currObjFixupInfo->SetIsISerializableInstance(); - if (refValues == NULL) - { - // We found a smugglable objref. No field scanning needed - m_skipFieldScan = TRUE; - } - } - else if( m_cbInterface->IsISerializableType(currMT)) - { - InvokeVtsCallbacks(m_currObject, RemotingVtsInfo::VTS_CALLBACK_ON_SERIALIZING, fromDomain); - if (HasVtsCallbacks(m_currObject->GetMethodTable(), RemotingVtsInfo::VTS_CALLBACK_ON_SERIALIZED)) - VSC.Enqueue(m_currObject, NULL, NULL, NULL); - - refValues = AllocateISerializable(currID, FALSE); - isISerializable = TRUE; - ISerializableTSOIndex = TSO.GetCount() - 1; - currObjFixupInfo->SetIsISerializableInstance(); - } - else if (currMT->IsArray()) - { - AllocateArray(); - } - else - { - // This is a regular object - InvokeVtsCallbacks(m_currObject, RemotingVtsInfo::VTS_CALLBACK_ON_SERIALIZING, fromDomain); - if (HasVtsCallbacks(m_currObject->GetMethodTable(), RemotingVtsInfo::VTS_CALLBACK_ON_SERIALIZED)) - VSC.Enqueue(m_currObject, NULL, NULL, NULL); - - AllocateObject(); - - if (m_cbInterface->IsISerializableType(m_newObject->GetMethodTable())) - { - // We have a situation where the serialized instnce was not ISerializable, - // but the target instance is. So we make the from object look like a ISerializable - refValues = MakeObjectLookLikeISerializable(currID); - isISerializable = TRUE; - ISerializableTSOIndex = TSO.GetCount() - 1; - currObjFixupInfo->SetIsISerializableInstance(); - } - } - - _ASSERTE(m_newObject != NULL); - newMT = m_newObject->GetMethodTable(); - - // Check whether new object is serializable - m_cbInterface->ValidateToType(newMT); - - // Update the TOS, to include the new object - int retId; - retId = TOS.UpdateObject(m_currObject, m_newObject); - _ASSERTE(retId == currID); - } - _ASSERTE(m_newObject != NULL); - - // FIXUP PHASE - // Get parent to be fixed up - ParentInfo *parentInfo; - refParent = QOF.Peek(&dummy1, &dummy2, (QueuedObjectInfo **)&parentInfo); - MethodTable *pParentMT = NULL; - - if (refParent == NULL) - { - LOG((LF_REMOTING, LL_INFO1000, "Clone. No parent found. This is the top object.\n")); - // This is the top object - _ASSERTE(m_topObject == NULL); - m_topObject = m_newObject; - } - else - { -#ifdef _DEBUG - LOG((LF_REMOTING, LL_INFO1000, "Clone. Parent is of type %s.\n", - GetFullyQualifiedNameForClassNestedAware(m_currObject->GetMethodTable()))); -#endif - pParentMT = refParent->GetMethodTable(); - } - - if (IsDelayedFixup(newMT, currObjFixupInfo)) - { - // New object is IObjRef or a boxed object - if (m_cbInterface->IsIObjectReferenceType(newMT)) - { - LOG((LF_REMOTING, LL_INFO1000, "Clone. This is an IObjectReference. Delaying fixup.\n")); - DWORD size = sizeof(IObjRefInstanceInfo) + (currObjFixupInfo ? currObjFixupInfo->GetSize() : 0); - if (size > dwCurrStackSpaceSize) - { - pTempStackSpace = _alloca(size); - dwCurrStackSpaceSize = size; - } - IObjRefInstanceInfo *pIORInfo = new (pTempStackSpace) IObjRefInstanceInfo(currID, 0, 0); - if (currObjFixupInfo) - pIORInfo->SetFixupInfo(currObjFixupInfo); - // Check if this instance is ISerializable also - if (isISerializable) - { - LOG((LF_REMOTING, LL_INFO1000, "Clone. This is also an ISerializable type at index %d in TSO.\n", ISerializableTSOIndex)); - _ASSERTE(ISerializableTSOIndex != (DWORD) -1); - pIORInfo->SetISerTSOIndex(ISerializableTSOIndex); - } - - if (repeatObject) - pIORInfo->SetIsRepeatObject(); - - // Add to TSO - TSO.Push(m_newObject, m_currObject, refParent, pIORInfo); - - isIObjRef = TRUE; - IObjRefTSOIndex = TSO.GetCount() - 1; - - LOG((LF_REMOTING, LL_INFO1000, "Clone. Added to TSO at index %d.\n", IObjRefTSOIndex)); - // Any special object parent, would wait till the current object is resolved - if (parentInfo) - { - parentInfo->IncrementSpecialMembers(); - TMappings.Add(IObjRefTSOIndex); - } - - } - if (currObjFixupInfo->NeedsUnboxing()) - { - LOG((LF_REMOTING, LL_INFO1000, "Clone. This is a boxed value type. Delaying fixup.\n")); - DWORD size = sizeof(ValueTypeInfo) + currObjFixupInfo->GetSize(); - if (size > dwCurrStackSpaceSize) - { - pTempStackSpace = _alloca(size); - dwCurrStackSpaceSize = size; - } - ValueTypeInfo *valInfo = new (pTempStackSpace) ValueTypeInfo(currID, currObjFixupInfo); - // If the value type is also ISer or IObj, then it has to wait till those interfaces are addressed - if (isISerializable) - { - LOG((LF_REMOTING, LL_INFO1000, "Clone. This is also an ISerializable type at index %d in TSO.\n", ISerializableTSOIndex)); - valInfo->SetISerTSOIndex(ISerializableTSOIndex); - } - if (isIObjRef) - { - LOG((LF_REMOTING, LL_INFO1000, "Clone. This is also an IObjectReference type at index %d in TSO.\n", IObjRefTSOIndex)); - valInfo->SetIObjRefTSOIndex(IObjRefTSOIndex); - } - - // Add to TSO - TSO.Push(m_newObject, refParent, NULL, valInfo); - - isBoxed = TRUE; - BoxedValTSOIndex = TSO.GetCount() - 1; - - LOG((LF_REMOTING, LL_INFO1000, "Clone. Added to TSO at index %d.\n", BoxedValTSOIndex)); - // An IObjRef parent, or a parent itself boxed, would wait till the current object is resolved - if (parentInfo && (parentInfo->NeedsUnboxing() || parentInfo->IsIObjRefInstance())) - { - parentInfo->IncrementSpecialMembers(); - TMappings.Add(BoxedValTSOIndex); - } - } - } - - if (refParent != NULL) - { - if (!IsDelayedFixup(newMT, currObjFixupInfo)) - Fixup(m_newObject, refParent, currObjFixupInfo); - - // If currObj is ISer, then an IObjRef parent would wait till the current object is resolved - if (currObjFixupInfo->IsISerializableInstance() && - parentInfo->IsIObjRefInstance()) - { - parentInfo->IncrementSpecialMembers(); - TMappings.Add(ISerializableTSOIndex); - } - } - - // If we are done with this parent, remove it from QOF - if (parentInfo && parentInfo->DecrementFixupCount() == 0) - { - LOG((LF_REMOTING, LL_INFO1000, "Clone. All children fixed up. Removing parent from QOF.\n", BoxedValTSOIndex)); - LOG((LF_REMOTING, LL_INFO1000, "Clone. Parent has %d special member objects.\n", parentInfo->GetNumSpecialMembers())); - OBJECTREF refTemp; - ParentInfo *pFITemp; - refTemp = QOF.Dequeue(&dummy1, &dummy2, (QueuedObjectInfo **)&pFITemp); - _ASSERTE(refTemp == refParent); - _ASSERTE(pFITemp == parentInfo); - - // If parent is a special object, then we need to know how many special members it has - if ((parentInfo->IsIObjRefInstance() || - parentInfo->IsISerializableInstance() || - parentInfo->NeedsUnboxing()) - && parentInfo->GetNumSpecialMembers() > 0) - { - // Make a note in TSO that this parent has non-zero special members - DWORD index[3]; - index[0] = parentInfo->GetIObjRefIndexIntoTSO(); - index[1] = parentInfo->GetISerIndexIntoTSO(); - index[2] = parentInfo->GetBoxedValIndexIntoTSO(); - - for (DWORD count = 0; count < 3; count++) - { - OBJECTREF refIser, refNames, refValuesTemp; - SpecialObjectInfo *pISerInfo; - - if (index[count] == (DWORD) -1) - continue; - - refIser = TSO.GetAt(index[count], &refNames, &refValuesTemp, (QueuedObjectInfo **)&pISerInfo); - _ASSERTE(refIser == refParent); - - DWORD numSpecialObjects = parentInfo->GetNumSpecialMembers(); - pISerInfo->SetNumSpecialMembers(numSpecialObjects); - - _ASSERTE(TMappings.GetCount() >= numSpecialObjects); - pISerInfo->SetMappingTableIndex(TMappings.GetCount() - numSpecialObjects); - } - } - } - - // FIELD SCAN PHASE - if (!m_skipFieldScan) - { - if (m_currObject->GetMethodTable()->IsArray()) - ScanArrayMembers(); - else if (isISerializable) - ScanISerializableMembers(IObjRefTSOIndex, ISerializableTSOIndex, BoxedValTSOIndex, refValues); - else - ScanMemberFields(IObjRefTSOIndex, BoxedValTSOIndex); - } - - } // While there are objects in QOM - - // OBJECT COMPLETION PHASE - CompleteSpecialObjects(); - - // Deliver VTS OnDeserialized callbacks. - CompleteVtsOnDeserializedCallbacks(); - - CompleteIDeserializationCallbacks(); - - _ASSERTE(m_topObject != NULL); - // If a type check was requested, see if the returned object is of the expected type - if (!expectedType.IsNull() - && !ObjIsInstanceOf(OBJECTREFToObject(m_topObject), expectedType)) - COMPlusThrow(kArgumentException,W("Arg_ObjObj")); - - GCPROTECT_END(); // refParent - GCPROTECT_END(); // refValues - - GCPROTECT_END(); // m_newObject - - END_DOMAIN_TRANSITION; - - // Deliver VTS OnSerialized callbacks. - CompleteVtsOnSerializedCallbacks(); - - GCPROTECT_END(); // m_fromExecutionContext - GCPROTECT_END(); // m_topObject - GCPROTECT_END(); // m_currObject - - return m_topObject; -} - -// IObjRef and value types boxed by us, need to be fixed up towards the end -BOOL ObjectClone::IsDelayedFixup(MethodTable *newMT, QueuedObjectInfo *pCurrInfo) -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END - if (m_cbInterface->IsIObjectReferenceType(newMT) || - pCurrInfo->NeedsUnboxing()) - return TRUE; - else - return FALSE; -} - -void ObjectClone::Fixup(OBJECTREF newObj, OBJECTREF refParent, QueuedObjectInfo *pFixupInfo) -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END - MethodTable *pParentMT = refParent->GetMethodTable(); - - if (pFixupInfo->IsISerializableMember()) - { - HandleISerializableFixup(refParent, pFixupInfo); - } - else if (pParentMT->IsArray()) - { - HandleArrayFixup(refParent, pFixupInfo); - } - else - { - HandleObjectFixup(refParent, pFixupInfo); - } -} - -PTRARRAYREF ObjectClone::MakeObjectLookLikeISerializable(int objectId) -{ - CONTRACTL - { - GC_TRIGGERS; - THROWS; - MODE_COOPERATIVE; - } - CONTRACTL_END - - _ASSERTE(m_context != ObjectFreezer); - - LOG((LF_REMOTING, LL_INFO1000, "MakeObjectLookLikeISerializable. Target object is ISerializable, so making from object look ISerializable\n")); - MethodTable *pCurrMT = m_currObject->GetMethodTable(); - DWORD numFields = pCurrMT->GetNumInstanceFields(); - - PTRARRAYREF fieldNames = NULL; - PTRARRAYREF fieldValues = NULL; - - GCPROTECT_BEGIN(fieldNames); - GCPROTECT_BEGIN(fieldValues); - - // Go back to from domain - ENTER_DOMAIN_PTR(m_fromDomain,ADV_RUNNINGIN); - - // Reset the execution context to the original state it was in when we first - // left the from domain (this will automatically be popped once we return - // from this domain again). - Thread *pThread = GetThread(); - if (pThread->IsExposedObjectSet()) - { - THREADBASEREF refThread = (THREADBASEREF)pThread->GetExposedObjectRaw(); - refThread->SetExecutionContext(m_fromExecutionContext); - } - - fieldNames = (PTRARRAYREF)AllocateObjectArray(numFields, g_pStringClass, FALSE); - fieldValues = (PTRARRAYREF)AllocateObjectArray(numFields, g_pObjectClass, FALSE); - - DWORD fieldIndex = 0; - while (pCurrMT) - { - - DWORD numInstanceFields = pCurrMT->GetNumIntroducedInstanceFields(); - - FieldDesc *pFields = pCurrMT->GetApproxFieldDescListRaw(); - - for (DWORD i = 0; i < numInstanceFields; i++) - { - if (pFields[i].IsNotSerialized()) - { - LOG((LF_REMOTING, LL_INFO1000, "MakeObjectLookLikeISerializable. Field %s is marked NonSerialized. Skipping.\n", pFields[i].GetName())); - continue; - } - - CorElementType typ = pFields[i].GetFieldType(); - DWORD offset = pFields[i].GetOffset(); - - LPCUTF8 szFieldName = pFields[i].GetName(); - STRINGREF refName = StringObject::NewString(szFieldName); - _ASSERTE(refName != NULL); - - fieldNames->SetAt(fieldIndex, refName); - - switch (typ) - { - case ELEMENT_TYPE_BOOLEAN: - case ELEMENT_TYPE_I1: - case ELEMENT_TYPE_U1: - case ELEMENT_TYPE_I2: - case ELEMENT_TYPE_U2: - case ELEMENT_TYPE_CHAR: - case ELEMENT_TYPE_I4: - case ELEMENT_TYPE_U4: - case ELEMENT_TYPE_I8: - case ELEMENT_TYPE_U8: - case ELEMENT_TYPE_I: - case ELEMENT_TYPE_U: - case ELEMENT_TYPE_R4: - case ELEMENT_TYPE_R8: - { - MethodTable *pFldMT = MscorlibBinder::GetElementType(typ); - void *pData = m_currObject->GetData() + offset; - OBJECTREF refBoxed = pFldMT->Box(pData); - - fieldValues->SetAt(fieldIndex, refBoxed); - break; - } - case ELEMENT_TYPE_VALUETYPE: - case ELEMENT_TYPE_PTR: - case ELEMENT_TYPE_FNPTR: - { - TypeHandle th = LoadExactFieldType(&pFields[i], m_currObject, m_fromDomain); - _ASSERTE(!th.AsMethodTable()->IsByRefLike() && "Field types cannot contain stack pointers."); - - OBJECTREF refBoxed = BoxValueTypeInWrongDomain(m_currObject, offset, th.AsMethodTable()); - - fieldValues->SetAt(fieldIndex, refBoxed); - break; - } - case ELEMENT_TYPE_SZARRAY: // Single Dim - case ELEMENT_TYPE_ARRAY: // General Array - case ELEMENT_TYPE_CLASS: // Class - case ELEMENT_TYPE_OBJECT: - case ELEMENT_TYPE_STRING: // System.String - case ELEMENT_TYPE_VAR: - { - OBJECTREF refField = *((OBJECTREF *) m_currObject->GetData() + offset); - fieldValues->SetAt(fieldIndex, refField); - break; - } - default: - _ASSERTE(!"Unknown element type in MakeObjectLookLikeISerializalbe"); - } - - fieldIndex++; - } - - pCurrMT = pCurrMT->GetParentMethodTable(); - } - - // Back to original domain - END_DOMAIN_TRANSITION; - - // Add object to TSO - ISerializableInstanceInfo iserInfo(objectId, 0); - TSO.Push(m_newObject, fieldNames, NULL, (QueuedObjectInfo *)&iserInfo); - - LOG((LF_REMOTING, LL_INFO1000, "MakeObjectLookLikeISerializable. Added to TSO at index %d.\n", TSO.GetCount() - 1)); - GCPROTECT_END(); - GCPROTECT_END(); - - return fieldValues; -} - -PTRARRAYREF ObjectClone::AllocateISerializable(int objectId, BOOL bIsRemotingObject) -{ - CONTRACTL - { - GC_TRIGGERS; - THROWS; - MODE_COOPERATIVE; - } - CONTRACTL_END - - _ASSERTE(m_context != ObjectFreezer); - - // Go back to from domain - StackSString ssAssemName; - StackSString ssTypeName; - - struct _gc { - STRINGREF typeName; - STRINGREF assemblyName; - PTRARRAYREF fieldNames; - PTRARRAYREF fieldValues; - OBJECTREF refObjRef; - } gc; - ZeroMemory(&gc, sizeof(gc)); - - GCPROTECT_BEGIN(gc); - - ENTER_DOMAIN_PTR(m_fromDomain,ADV_RUNNINGIN); - - // Reset the execution context to the original state it was in when we first - // left the from domain (this will automatically be popped once we return - // from this domain again). - Thread *pThread = GetThread(); - if (pThread->IsExposedObjectSet()) - { - THREADBASEREF refThread = (THREADBASEREF)pThread->GetExposedObjectRaw(); - refThread->SetExecutionContext(m_fromExecutionContext); - } - - // Call GetObjectData on the interface - - LOG((LF_REMOTING, LL_INFO1000, "AllocateISerializable. Instance is ISerializable type. Calling GetObjectData.\n")); - - PREPARE_NONVIRTUAL_CALLSITE(METHOD__OBJECTCLONEHELPER__GET_OBJECT_DATA); - - DECLARE_ARGHOLDER_ARRAY(args, 5); - - args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(m_currObject); - args[ARGNUM_1] = PTR_TO_ARGHOLDER(&gc.typeName); - args[ARGNUM_2] = PTR_TO_ARGHOLDER(&gc.assemblyName); - args[ARGNUM_3] = PTR_TO_ARGHOLDER(&gc.fieldNames); - args[ARGNUM_4] = PTR_TO_ARGHOLDER(&gc.fieldValues); - - CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE; - CALL_MANAGED_METHOD_RETREF(gc.refObjRef, OBJECTREF, args); - - if (!bIsRemotingObject || gc.refObjRef == NULL) - { - ssAssemName.Set(gc.assemblyName->GetBuffer()); - ssTypeName.Set(gc.typeName->GetBuffer()); - } - - // Back to original domain - END_DOMAIN_TRANSITION; - - // if its a remoting object we are dealing with, we may already have the smugglable objref - if (bIsRemotingObject && gc.refObjRef != NULL) - { - m_newObject = gc.refObjRef; - // Add object to TSO. We dont need a ISerializable record, because we are smuggling the ObjRef - // and so, technically the ISerializable ctor can be considered already called. But we still make an entry in - // TSO and mark it "processed", so repeat references to the same remoting object work correctly - ISerializableInstanceInfo iserInfo(objectId, 0); - iserInfo.SetHasBeenProcessed(); - TSO.Push(m_newObject, NULL, NULL, (QueuedObjectInfo *)&iserInfo); - - LOG((LF_REMOTING, LL_INFO1000, "AllocateISerializable. GetObjectData returned smugglable ObjRef. Added dummy record to TSO at index %d.\n", TSO.GetCount() - 1)); - } - else - { - // Find the type (and choke on any exotics such as arrays, function pointers or generic type definitions). - TypeHandle th = GetType(ssTypeName, ssAssemName); - if (th.IsTypeDesc() || th.ContainsGenericVariables()) - { - StackSString ssBeforeTypeName, ssAfterTypeName; - TypeString::AppendType(ssBeforeTypeName, m_currObject->GetTypeHandle(), TypeString::FormatNamespace | TypeString::FormatFullInst); - TypeString::AppendType(ssAfterTypeName, th, TypeString::FormatNamespace | TypeString::FormatFullInst); - COMPlusThrow(kSerializationException, IDS_SERIALIZATION_BAD_ISER_TYPE, ssBeforeTypeName.GetUnicode(), ssAfterTypeName.GetUnicode()); - } - MethodTable *pSrvMT = th.AsMethodTable(); - _ASSERTE(pSrvMT); - -#ifdef _DEBUG - { - DefineFullyQualifiedNameForClass(); - LPCUTF8 __szTypeName = GetFullyQualifiedNameForClassNestedAware(pSrvMT); - LOG((LF_REMOTING, LL_INFO1000, "AllocateISerializable. Allocating instance of type %s.\n", &__szTypeName[0])); - } -#endif - // Allocate the object - m_newObject = m_cbInterface->AllocateObject(m_currObject, pSrvMT); - - // Add object to TSO - ISerializableInstanceInfo iserInfo(objectId, 0); - - // Check if the target object is ISerializable. If not, we need to treat construction of this object differently - if (!m_cbInterface->IsISerializableType(pSrvMT)) - { - iserInfo.SetTargetNotISerializable(); - } - TSO.Push(m_newObject, gc.fieldNames, NULL, (QueuedObjectInfo *)&iserInfo); - - LOG((LF_REMOTING, LL_INFO1000, "AllocateISerializable. Added to TSO at index %d.\n", TSO.GetCount() - 1)); - } - GCPROTECT_END(); - - return gc.fieldValues; -} - -void ObjectClone::AllocateArray() -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_TRIGGERS; - THROWS; - } - CONTRACTL_END - - LOG((LF_REMOTING, LL_INFO1000, "AllocateArray. Instance is an array type.\n")); - MethodTable *pCurrMT = m_currObject->GetMethodTable(); - _ASSERTE(pCurrMT->IsArray()); - - BASEARRAYREF refArray = (BASEARRAYREF)m_currObject; - GCPROTECT_BEGIN(refArray); - - TypeHandle elemTh = refArray->GetArrayElementTypeHandle(); - CorElementType elemType = refArray->GetArrayElementType(); - DWORD numComponents = refArray->GetNumComponents(); - - TypeHandle __elemTh = GetCorrespondingTypeForTargetDomain(elemTh); - _ASSERTE(!__elemTh.IsNull()); - - unsigned __rank = pCurrMT->GetRank(); - TypeHandle __arrayTh = ClassLoader::LoadArrayTypeThrowing(__elemTh, __rank == 1 ? ELEMENT_TYPE_SZARRAY : ELEMENT_TYPE_ARRAY, __rank); - - DWORD __numArgs = __rank*2; - INT32* __args = (INT32*) _alloca(sizeof(INT32)*__numArgs); - - if (__arrayTh.AsArray()->GetInternalCorElementType() == ELEMENT_TYPE_ARRAY) - { - const INT32* bounds = refArray->GetBoundsPtr(); - const INT32* lowerBounds = refArray->GetLowerBoundsPtr(); - for(unsigned int i=0; i < __rank; i++) - { - __args[2*i] = lowerBounds[i]; - __args[2*i+1] = bounds[i]; - } - } - else - { - __numArgs = 1; - __args[0] = numComponents; - } - m_newObject = m_cbInterface->AllocateArray(m_currObject, __arrayTh, __args, __numArgs, FALSE); - - // Treat pointer as a primitive type (we shallow copy the bits). - if (CorTypeInfo::IsPrimitiveType(elemType) || elemType == ELEMENT_TYPE_PTR) - { - LOG((LF_REMOTING, LL_INFO1000, "AllocateArray. Instance is an array of primitive type. Copying contents.\n")); - // Copy contents. - SIZE_T numBytesToCopy = refArray->GetComponentSize() * numComponents; - I1ARRAYREF refI1Arr = (I1ARRAYREF)m_newObject; - BYTE *pDest = (BYTE *)refI1Arr->GetDirectPointerToNonObjectElements(); - I1ARRAYREF refFromArr = (I1ARRAYREF)refArray; - BYTE *pSrc = (BYTE *)refFromArr->GetDirectPointerToNonObjectElements(); - - memcpyNoGCRefs(pDest, pSrc, numBytesToCopy); - m_skipFieldScan = TRUE; - } - else if (elemType == ELEMENT_TYPE_VALUETYPE) - { - if (!__elemTh.GetMethodTable()->HasFieldsWhichMustBeInited() && RemotableMethodInfo::TypeIsConduciveToBlitting(elemTh.AsMethodTable(), __elemTh.GetMethodTable())) - { - LOG((LF_REMOTING, LL_INFO1000, "AllocateArray. Instance is an array of value type with no embedded GC type. Copying contents.\n")); - // Copy contents. - SIZE_T numBytesToCopy = refArray->GetComponentSize() * numComponents; - I1ARRAYREF refI1Arr = (I1ARRAYREF)m_newObject; - BYTE *pDest = (BYTE *)refI1Arr->GetDirectPointerToNonObjectElements(); - I1ARRAYREF refFromArr = (I1ARRAYREF)refArray; - BYTE *pSrc = (BYTE *)refFromArr->GetDirectPointerToNonObjectElements(); - - memcpyNoGCRefs(pDest, pSrc, numBytesToCopy); - m_skipFieldScan = TRUE; - } - } - GCPROTECT_END(); -} - -void ObjectClone::AllocateObject() -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_TRIGGERS; - THROWS; - } - CONTRACTL_END - - LOG((LF_REMOTING, LL_INFO1000, "AllocateObject. Instance is a regular object.\n")); - MethodTable *pCurrMT = m_currObject->GetMethodTable(); - _ASSERTE(!pCurrMT->IsArray()); - _ASSERTE(!pCurrMT->IsMarshaledByRef() && !pCurrMT->IsTransparentProxy()); - _ASSERTE(!m_cbInterface->IsISerializableType(pCurrMT)); - - MethodTable *pCorrespondingMT = GetCorrespondingTypeForTargetDomain(pCurrMT); - _ASSERTE(pCorrespondingMT); - - pCorrespondingMT->EnsureInstanceActive(); - - m_newObject = m_cbInterface->AllocateObject(m_currObject, pCorrespondingMT); - - InvokeVtsCallbacks(m_newObject, RemotingVtsInfo::VTS_CALLBACK_ON_DESERIALIZING, m_toDomain); -} - -// Use this wrapper when the type handle can't be represented as a raw MethodTable (i.e. it's a pointer or array type). -TypeHandle ObjectClone::GetCorrespondingTypeForTargetDomain(TypeHandle thCli) -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_TRIGGERS; - THROWS; - } - CONTRACTL_END - - TypeHandle thBaseType = thCli; - TypeHandle thSrvType; - - // Strip off any pointer information (and record the depth). We'll put this back later (when we've translated the base type). - DWORD dwPointerDepth = 0; - while (thBaseType.IsPointer()) - { - dwPointerDepth++; - thBaseType = thBaseType.AsTypeDesc()->GetTypeParam(); - } - - // If we hit an array then we'll recursively translate the element type then build an array type out of it. - if (thBaseType.IsArray()) - { - ArrayTypeDesc *atd = (ArrayTypeDesc *)thBaseType.AsTypeDesc(); - thSrvType = GetCorrespondingTypeForTargetDomain(atd->GetArrayElementTypeHandle()); - - thSrvType = ClassLoader::LoadArrayTypeThrowing(thSrvType, atd->GetInternalCorElementType(), atd->GetRank()); - } - else - { - // We should have only unshared types if we get here. - _ASSERTE(!thBaseType.IsTypeDesc()); - thSrvType = GetCorrespondingTypeForTargetDomain(thBaseType.AsMethodTable()); - } - - // Match the level of pointer indirection from the original client type. - while (dwPointerDepth--) - { - thSrvType = thSrvType.MakePointer(); - } - - return thSrvType; -} - -MethodTable * ObjectClone::GetCorrespondingTypeForTargetDomain(MethodTable *pCliMT) -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_TRIGGERS; - THROWS; - } - CONTRACTL_END - - MethodTable *pSrvMT = NULL; - if (m_fromDomain == m_toDomain) - return pCliMT; - - _ASSERTE(m_context != ObjectFreezer); -#ifdef _DEBUG - SString __ssTypeName; - StackScratchBuffer __scratchBuf; - if (pCliMT->IsArray()) - pCliMT->_GetFullyQualifiedNameForClass(__ssTypeName); - else - pCliMT->_GetFullyQualifiedNameForClassNestedAware(__ssTypeName); -#endif - - // Take benefit of shared types. If a type is shared, and its assembly has been loaded - // in the target domain, go ahead and use the same MT ptr. - // The logic is trickier (and more expensive to calculate) for generic types, so skip the optimization there. - if (pCliMT->IsDomainNeutral() && !pCliMT->HasInstantiation()) - { - if (pCliMT->GetAssembly()->FindDomainAssembly(m_toDomain)) - { - LOG((LF_REMOTING, LL_INFO1000, - "GetCorrespondingTypeForTargetDomain. Type %s is shared. Using same MethodTable.\n", __ssTypeName.GetUTF8(__scratchBuf))); - return pCliMT; - } - } - - pSrvMT = CrossDomainTypeMap::GetMethodTableForDomain(pCliMT, m_fromDomain, m_toDomain); - if (pSrvMT) - { - LOG((LF_REMOTING, LL_INFO1000, - "GetCorrespondingTypeForTargetDomain. Found matching type for %s in domain %d from cache.\n", __ssTypeName.GetUTF8(__scratchBuf), m_toDomain)); - return pSrvMT; - } - - // Need to find the name and lookup in target domain - SString ssCliTypeName; - if (pCliMT->IsArray()) - { - pCliMT->_GetFullyQualifiedNameForClass(ssCliTypeName); - } - else if (pCliMT->HasInstantiation()) - { - TypeString::AppendType(ssCliTypeName, TypeHandle(pCliMT), TypeString::FormatNamespace | TypeString::FormatFullInst); - } - else - { - pCliMT->_GetFullyQualifiedNameForClassNestedAware(ssCliTypeName); - } - - - SString ssAssemblyName; - pCliMT->GetAssembly()->GetDisplayName(ssAssemblyName); - - // Get the assembly - TypeHandle th = GetType(ssCliTypeName, ssAssemblyName); - - if (!pCliMT->IsArray()) - { - pSrvMT = th.AsMethodTable(); - } - else - { - _ASSERTE(th.IsArray()); - TypeDesc *td = th.AsTypeDesc(); - pSrvMT = td->GetMethodTable(); - } - CrossDomainTypeMap::SetMethodTableForDomain(pCliMT, m_fromDomain, pSrvMT, m_toDomain); - LOG((LF_REMOTING, LL_INFO1000, - "GetCorrespondingTypeForTargetDomain. Loaded matching type for %s in domain %d. Added to cache.\n", __ssTypeName.GetUTF8(__scratchBuf), m_toDomain)); - return pSrvMT; -} - -TypeHandle ObjectClone::GetType(const SString &ssTypeName, const SString &ssAssemName) -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END; - - Assembly *pAssembly = NULL; - -#ifndef OBJECT_CLONER_STRICT_MODE - EX_TRY -#endif - { - AssemblySpec spec; - StackScratchBuffer scratchBuf; - HRESULT hr = spec.Init(ssAssemName.GetUTF8(scratchBuf)); - if (SUCCEEDED(hr)) - { - pAssembly = spec.LoadAssembly(FILE_ACTIVE); - } - else - { - COMPlusThrowHR(hr); - } - } -#ifndef OBJECT_CLONER_STRICT_MODE - EX_CATCH - { - if (GET_EXCEPTION()->IsTransient()) - { - EX_RETHROW; - } - - DomainAssembly *pDomainAssembly = NULL; - if (pDomainAssembly == NULL) - COMPlusThrow(kSerializationException, IDS_SERIALIZATION_UNRESOLVED_TYPE, - ssTypeName.GetUnicode(), ssAssemName.GetUnicode()); - else - pAssembly = pDomainAssembly->GetAssembly(); - } - EX_END_CATCH(SwallowAllExceptions); -#endif - - _ASSERTE(pAssembly); - - TypeHandle th = TypeName::GetTypeFromAssembly(ssTypeName.GetUnicode(), pAssembly); - - if (th.IsNull()) - { - COMPlusThrow(kSerializationException, IDS_SERIALIZATION_UNRESOLVED_TYPE, - ssTypeName.GetUnicode(), ssAssemName.GetUnicode()); - } - - LOG((LF_REMOTING, LL_INFO1000, "GetType. Loaded type %S from assembly %S in domain %d. \n", - ssTypeName.GetUnicode(), ssAssemName.GetUnicode(), m_toDomain->GetId().m_dwId)); - - return th; -} - -void ObjectClone::HandleISerializableFixup(OBJECTREF refParent, QueuedObjectInfo *currObjFixupInfo) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; - MODE_COOPERATIVE; - } - CONTRACTL_END; - - _ASSERTE(m_context != ObjectFreezer); - - ISerializableMemberInfo *pIsInfo = (ISerializableMemberInfo *)currObjFixupInfo; - OBJECTREF refNames, refValues; - ISerializableInstanceInfo *dummy; - OBJECTREF parent; - parent = TSO.GetAt(pIsInfo->GetTableIndex(), &refNames, &refValues, (QueuedObjectInfo **)&dummy); - _ASSERTE(parent == refParent); - _ASSERTE(dummy->IsISerializableInstance()); - - PTRARRAYREF refFields = (PTRARRAYREF)refValues; - _ASSERTE(pIsInfo->GetFieldIndex() < refFields->GetNumComponents()); - refFields->SetAt(pIsInfo->GetFieldIndex(), m_newObject); - - LOG((LF_REMOTING, LL_INFO1000, "HandleISerializableFixup. Parent is ISerializable. Added field #%d to TSO record at index %d\n", pIsInfo->GetFieldIndex(), pIsInfo->GetTableIndex())); -} - -void ObjectClone::HandleArrayFixup(OBJECTREF refParent, QueuedObjectInfo *currObjFixupInfo) -{ - CONTRACTL - { - MODE_COOPERATIVE; - THROWS; - GC_TRIGGERS; - } - CONTRACTL_END - - _ASSERTE(refParent->GetMethodTable()->IsArray()); - BASEARRAYREF refParentArray = (BASEARRAYREF) refParent; - GCPROTECT_BEGIN(refParentArray); - - NDimArrayMemberInfo *pArrInfo = (NDimArrayMemberInfo *)currObjFixupInfo; - DWORD *pIndices = pArrInfo->GetIndices(); - - TypeHandle arrayElementType = refParentArray->GetArrayElementTypeHandle(); - MethodTable *pArrayMT = refParentArray->GetMethodTable(); - - DWORD Rank = pArrayMT->GetRank(); - SIZE_T Offset = 0; - SIZE_T Multiplier = 1; - - _ASSERTE(Rank == pArrInfo->GetNumDimensions()); - - for (int i = Rank-1; i >= 0; i--) { - INT32 curIndex = pIndices[i]; - const INT32 *pBoundsPtr = refParentArray->GetBoundsPtr(); - - // Bounds check each index - // Casting to unsigned allows us to use one compare for [0..limit-1] - _ASSERTE((UINT32) curIndex < (UINT32) pBoundsPtr[i]); - - Offset += curIndex * Multiplier; - Multiplier *= pBoundsPtr[i]; - } - - // The follwing code is loosely based on COMArrayInfo::SetValue - - if (!arrayElementType.IsValueType()) - { - if (!ObjIsInstanceOf(OBJECTREFToObject(m_newObject), arrayElementType)) - COMPlusThrow(kInvalidCastException,W("InvalidCast_StoreArrayElement")); - - OBJECTREF* pElem = (OBJECTREF*)(refParentArray->GetDataPtr() + (Offset * pArrayMT->GetComponentSize())); - SetObjectReference(pElem,m_newObject,GetAppDomain()); - } - else - { - // value class or primitive type - OBJECTREF* pElem = (OBJECTREF*)(refParentArray->GetDataPtr() + (Offset * pArrayMT->GetComponentSize())); - if (!arrayElementType.GetMethodTable()->UnBoxInto(pElem, m_newObject)) - COMPlusThrow(kInvalidCastException, W("InvalidCast_StoreArrayElement")); - } - - LOG((LF_REMOTING, LL_INFO1000, "HandleArrayFixup. Parent is an array. Added element at offset %d\n", Offset)); - GCPROTECT_END(); -} - -void ObjectClone::HandleObjectFixup(OBJECTREF refParent, QueuedObjectInfo *currObjFixupInfo) -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_TRIGGERS; - THROWS; - } - CONTRACTL_END - ObjectMemberInfo *pObjInfo = (ObjectMemberInfo *)currObjFixupInfo; - FieldDesc *pTargetField = pObjInfo->GetFieldDesc(); - DWORD offset = pTargetField->GetOffset(); - -#ifdef _DEBUG - MethodTable *pTemp = refParent->GetMethodTable(); - _ASSERTE(offset < pTemp->GetBaseSize()); -#endif - - GCPROTECT_BEGIN(refParent); - - TypeHandle fldType = LoadExactFieldType(pTargetField, refParent, m_toDomain); - - if (!ObjIsInstanceOf(OBJECTREFToObject(m_newObject), fldType)) - COMPlusThrow(kArgumentException,W("Arg_ObjObj")); - - OBJECTREF *pDest = (OBJECTREF *) (refParent->GetData() + offset); - _ASSERTE(GetAppDomain()==m_toDomain); - SetObjectReference(pDest, m_newObject, GetAppDomain()); - - GCPROTECT_END(); - - LOG((LF_REMOTING, LL_INFO1000, "HandleObjectFixup. Parent is a regular object. Added field at offset %d\n", offset)); -} - -#ifdef OBJECT_CLONER_STRICT_MODE -static void DECLSPEC_NORETURN ThrowMissingFieldException(FieldDesc *pFD) -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_TRIGGERS; - THROWS; - } - CONTRACTL_END; - - StackSString szField(SString::Utf8, pFD->GetName()); - - StackSString szType; - TypeString::AppendType(szType, TypeHandle(pFD->GetApproxEnclosingMethodTable())); - - COMPlusThrow(kSerializationException, - IDS_SERIALIZATION_MISSING_FIELD, - szField.GetUnicode(), - szType.GetUnicode()); -} -#endif - -void ObjectClone::ScanMemberFields(DWORD IObjRefTSOIndex, DWORD BoxedValTSOIndex) -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_TRIGGERS; - THROWS; - } - CONTRACTL_END - _ASSERTE(m_currObject != NULL); - _ASSERTE(m_newObject != NULL); - - MethodTable *pMT = m_currObject->GetMethodTable(); - _ASSERTE(!pMT->IsMarshaledByRef() && !pMT->IsTransparentProxy()); - _ASSERTE(!pMT->IsArray()); - MethodTable *pTargetMT = m_newObject->GetMethodTable(); - - DWORD numFixupsNeeded = 0; - - if (RemotableMethodInfo::TypeIsConduciveToBlitting(pMT, pTargetMT)) - { - _ASSERTE(pMT->GetAlignedNumInstanceFieldBytes() == pTargetMT->GetAlignedNumInstanceFieldBytes()); - DWORD numBytes = pMT->GetNumInstanceFieldBytes(); - BYTE *pFrom = m_currObject->GetData(); - BYTE *pTo = m_newObject->GetData(); - memcpyNoGCRefs(pTo, pFrom, numBytes); - LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Object has no reference type fields. Blitting contents.\n")); - } - else if (AreTypesEmittedIdentically(pMT, pTargetMT)) - { - LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Object not blittable but types are layed out for easy cloning .\n")); - MethodTable *pCurrMT = pMT; - MethodTable *pCurrTargetMT = pTargetMT; - while (pCurrMT) - { - DWORD numInstanceFields = pCurrMT->GetNumIntroducedInstanceFields(); - _ASSERTE(pCurrTargetMT->GetNumIntroducedInstanceFields() == numInstanceFields); - - FieldDesc *pFields = pCurrMT->GetApproxFieldDescListRaw(); - FieldDesc *pTargetFields = pCurrTargetMT->GetApproxFieldDescListRaw(); - - for (DWORD i = 0; i < numInstanceFields; i++) - { - if (pFields[i].IsNotSerialized()) - { - LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Field %s is marked NonSerialized. Skipping.\n", pFields[i].GetName())); - continue; - } - - numFixupsNeeded += CloneField(&pFields[i], &pTargetFields[i]); - } - - pCurrMT = pCurrMT->GetParentMethodTable(); - pCurrTargetMT = pCurrTargetMT->GetParentMethodTable(); - } - } - else - { - LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Object type layout is different.\n")); - - // The object types between source and destination have significant differences (some fields may be added, removed or - // re-ordered, the type hierarchy may have had layers added or removed). We can still clone the object if every non-optional - // field in the destination object can be found and serialized in a type with the same name in the source object. We ignore - // fields and entire type layers that have been added in the source object and also any fields or layers that have been - // removed as long as they don't include any fields that are mandatory in the destination object. We allow the fields within - // a type layer to move around (we key the field by name only, the latter stage of cloning will check type equivalency and - // as above we will widen primitive types if necessary). Since it requires significant effort to calculate whether the - // objects can be cloned (and then locate corresponding fields in order to do so) we cache a mapping of source object fields - // to destination object fields. - - // The following call will return such a mapping (it's an array where each entry is a pointer to a source object field desc - // and the entries are in destination field index order, most derived type first, followed by second most derived type - // etc.). If a mapping is impossible the method will throw. - FieldDesc **pFieldMap = CrossDomainFieldMap::LookupOrCreateFieldMapping(pTargetMT, pMT); - DWORD dwMapIndex = 0; - - MethodTable *pDstMT = pTargetMT; - while (pDstMT) - { - FieldDesc *pDstFields = pDstMT->GetApproxFieldDescListRaw(); - DWORD numInstanceFields = pDstMT->GetNumIntroducedInstanceFields(); - - for (DWORD i = 0; i < numInstanceFields; i++) - { - FieldDesc *pSrcField = pFieldMap[dwMapIndex++]; - - // Non-serialized fields in the destination type (or optional fields where the source type doesn't have an - // equivalent) don't have a source field desc. - if (pSrcField == NULL) - continue; - - numFixupsNeeded += CloneField(pSrcField, &pDstFields[i]); - } - - pDstMT = pDstMT->GetParentMethodTable(); - } - - _ASSERTE(dwMapIndex == pTargetMT->GetNumInstanceFields()); - } - - if (numFixupsNeeded > 0) - { - ParentInfo fxInfo(numFixupsNeeded); - if (IObjRefTSOIndex != (DWORD) -1) - { - _ASSERTE(m_cbInterface->IsIObjectReferenceType(pMT)); - fxInfo.SetIsIObjRefInstance(); - fxInfo.SetIObjRefIndexIntoTSO(IObjRefTSOIndex); - } - if (BoxedValTSOIndex != (DWORD) -1) - { - _ASSERTE(pMT->IsValueType()); - fxInfo.SetNeedsUnboxing(); - fxInfo.SetBoxedValIndexIntoTSO(BoxedValTSOIndex); - } - QOF.Enqueue(m_newObject, NULL, NULL, (QueuedObjectInfo *)&fxInfo); - LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Current object had total of %d reference type fields. Adding to QOF.\n", numFixupsNeeded)); - // Delay calling any OnDeserialized callbacks until the end of the cloning operation (it's difficult to tell when all the - // children have been deserialized). - if (HasVtsCallbacks(m_newObject->GetMethodTable(), RemotingVtsInfo::VTS_CALLBACK_ON_DESERIALIZED)) - VDC.Enqueue(m_newObject, NULL, NULL, NULL); - if (m_cbInterface->RequiresDeserializationCallback(m_newObject->GetMethodTable())) - { - LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Adding object to Table of IDeserialization Callbacks\n")); - QueuedObjectInfo noInfo; - TDC.Enqueue(m_newObject, NULL, NULL, &noInfo); - } - } - else - { - // This is effectively a leaf node (no complex children) so if the type has a callback for OnDeserialized we'll deliver it - // now. This fixes callback ordering for a few more edge cases (e.g. VSW 415611) and is reasonably cheap. We can never do a - // perfect job (in the presence of object graph cycles) and a near perfect job (intuitively ordered callbacks for acyclic - // object graphs) is prohibitively expensive; so we're stuck with workarounds like this. - InvokeVtsCallbacks(m_newObject, RemotingVtsInfo::VTS_CALLBACK_ON_DESERIALIZED, m_toDomain); - if (m_cbInterface->RequiresDeserializationCallback(m_newObject->GetMethodTable())) - MakeIDeserializationCallback(m_newObject); - } -} - -DWORD ObjectClone::CloneField(FieldDesc *pSrcField, FieldDesc *pDstField) -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_TRIGGERS; - THROWS; - } - CONTRACTL_END; - - BOOL bFixupNeeded = FALSE; - - CorElementType srcType = pSrcField->GetFieldType(); - CorElementType dstType = pDstField->GetFieldType(); - DWORD srcOffset = pSrcField->GetOffset(); - DWORD dstOffset = pDstField->GetOffset(); - - BOOL bUseWidenedValue = FALSE; - ARG_SLOT fieldData = 0; - if (srcType != dstType) - { - void *pData = m_currObject->GetData() + srcOffset; - - MethodTable *pSrcFieldMT = NULL; - if (CorTypeInfo::IsPrimitiveType(srcType)) - pSrcFieldMT = MscorlibBinder::GetElementType(srcType); - else - pSrcFieldMT = LoadExactFieldType(pSrcField, m_currObject, m_fromDomain).AsMethodTable(); - - LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Field %s has differing types at source and destination. Will try to convert.\n", pSrcField->GetName())); - fieldData = HandleFieldTypeMismatch(dstType, srcType, pData, pSrcFieldMT); - bUseWidenedValue = TRUE; - } - - switch (dstType) - { - case ELEMENT_TYPE_I1: - case ELEMENT_TYPE_U1: - case ELEMENT_TYPE_BOOLEAN: - { - BYTE *pDest = m_newObject->GetData() + dstOffset; - if (bUseWidenedValue) - *pDest = (unsigned char) fieldData; - else - { - BYTE *pByte = m_currObject->GetData() + srcOffset; - *pDest = *pByte; - } - } - break; - case ELEMENT_TYPE_I2: - case ELEMENT_TYPE_U2: - case ELEMENT_TYPE_CHAR: - { - WORD *pDest = (WORD*)(m_newObject->GetData() + dstOffset); - if (bUseWidenedValue) - *pDest = (short) fieldData; - else - { - WORD *pWord = (WORD*)(m_currObject->GetData() + srcOffset); - *(pDest) = *pWord; - } - } - break; - case ELEMENT_TYPE_I4: - case ELEMENT_TYPE_U4: - case ELEMENT_TYPE_R4: - IN_WIN32(case ELEMENT_TYPE_FNPTR:) - IN_WIN32(case ELEMENT_TYPE_I:) - IN_WIN32(case ELEMENT_TYPE_U:) - { - DWORD *pDest = (DWORD*)(m_newObject->GetData() + dstOffset); - if (bUseWidenedValue) - *pDest = (int) fieldData; - else - { - DWORD *pDword = (DWORD*)(m_currObject->GetData() + srcOffset); - *(pDest) = *pDword; - } - } - break; - case ELEMENT_TYPE_R8: - case ELEMENT_TYPE_I8: - case ELEMENT_TYPE_U8: - IN_WIN64(case ELEMENT_TYPE_FNPTR:) - IN_WIN64(case ELEMENT_TYPE_I:) - IN_WIN64(case ELEMENT_TYPE_U:) - { - INT64 *pDest = (INT64*)(m_newObject->GetData() + dstOffset); - if (bUseWidenedValue) - *pDest = fieldData; - else - { - INT64 *pLong = (INT64*)(m_currObject->GetData() + srcOffset); - *(pDest) = *pLong; - } - } - break; - case ELEMENT_TYPE_PTR: - { - void **pDest = (void**)(m_newObject->GetData() + dstOffset); - void **pPtr = (void**)(m_currObject->GetData() + srcOffset); - *(pDest) = *pPtr; - } - break; - case ELEMENT_TYPE_STRING: - case ELEMENT_TYPE_CLASS: // objectrefs - case ELEMENT_TYPE_OBJECT: - case ELEMENT_TYPE_SZARRAY: // single dim, zero - case ELEMENT_TYPE_ARRAY: // all other arrays - { - OBJECTREF *pSrc = (OBJECTREF *)(m_currObject->GetData() + srcOffset); - OBJECTREF *pDest = (OBJECTREF *)(m_newObject->GetData() + dstOffset); - - if ((*pSrc) == NULL) - break; - - // If no deep copy is required, just copy the reference - if (!m_cbInterface->RequiresDeepCopy(*pSrc)) - { - _ASSERTE(GetAppDomain()==m_toDomain); - SetObjectReference(pDest, *pSrc, GetAppDomain()); - break; - } - - // Special case String - if ((*pSrc)->GetMethodTable() == g_pStringClass) - { - // Better check the destination really expects a string (or maybe an object). - TypeHandle thDstField = LoadExactFieldType(pDstField, m_newObject, m_toDomain); - if (thDstField != TypeHandle(g_pStringClass) && thDstField != TypeHandle(g_pObjectClass)) - COMPlusThrow(kArgumentException, W("Arg_ObjObj")); - - STRINGREF refStr = (STRINGREF) *pSrc; - refStr = m_cbInterface->AllocateString(refStr); - // Get dest addr again, as a GC might have occurred - pDest = (OBJECTREF *)(m_newObject->GetData() + dstOffset); - _ASSERTE(GetAppDomain()==m_toDomain); - SetObjectReference(pDest, refStr, GetAppDomain()); - - break; - } - - // Add the object to QOM - LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Adding object in field %s to Queue of Objects to be Marshalled.\n", pSrcField->GetName())); - ObjectMemberInfo objInfo(pDstField); - bFixupNeeded = TRUE; - QOM.Enqueue(*pSrc, NULL, NULL, (QueuedObjectInfo *)&objInfo); - } - break; - - case ELEMENT_TYPE_VALUETYPE: - { - TypeHandle th = LoadExactFieldType(pSrcField, m_currObject, m_fromDomain); - _ASSERTE(!th.AsMethodTable()->IsByRefLike() && "Field types cannot contain stack pointers."); - - TypeHandle thTarget = LoadExactFieldType(pDstField, m_newObject, m_toDomain); - - MethodTable *pValueClassMT = th.AsMethodTable(); - MethodTable *pValueClassTargetMT = thTarget.AsMethodTable(); - if (!RemotableMethodInfo::TypeIsConduciveToBlitting(pValueClassMT, pValueClassTargetMT)) - { - // Needs marshalling - // We're allocating an object in the "to" domain - // using a type from the "from" domain. - OBJECTREF refTmpBox = BoxValueTypeInWrongDomain(m_currObject, srcOffset, pValueClassMT); - - // Nullable might return null here. In that case we don't need to do anything - // and the null value otherwise confuxes the fixup queue. - if (refTmpBox != NULL) - { - // Add the object to QOM - ObjectMemberInfo objInfo(pDstField); - objInfo.SetNeedsUnboxing(); - bFixupNeeded = TRUE; - QOM.Enqueue(refTmpBox, NULL, NULL, (QueuedObjectInfo *)&objInfo); - LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Value type field %s has reference type contents. Boxing and adding to QOM.\n", pSrcField->GetName())); - } - } - else - { - DWORD numBytesToCopy = th.AsMethodTable()->GetNumInstanceFieldBytes(); - BYTE *pByte = m_currObject->GetData() + srcOffset; - BYTE *pDest = m_newObject->GetData() + dstOffset; - memcpyNoGCRefs(pDest, pByte, numBytesToCopy); - LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Value type field %s has no reference type contents. Blitting.\n", pSrcField->GetName())); - } - } - break; - default: - _ASSERTE(!"Unknown element type seen in ObjectClone::ScanMemberFields"); - break; - } - - return bFixupNeeded ? 1 : 0; -} - -BOOL ObjectClone::AreTypesEmittedIdentically(MethodTable *pMT1, MethodTable *pMT2) -{ - LIMITED_METHOD_CONTRACT; - - // Identical here means that both types have the same hierarchy (depth and names match) and that each level of the hierarchy has - // the same fields (by name) at the same index. - // We're going to be called quite frequently (once per call to ScanMemberFields) so until we're convinced that caching this - // information is worth it we'll just compute the fast cases here and let the rest fall through to the slower technique. The - // fast check is that the types are shared and identical or that they're loaded from the same file (in which case we have to be - // a little more paranoid and check up the hierarchy). - if (pMT1 == pMT2) - return TRUE; - - // While the current level of the type is loaded from the same file... - // Note that we used to check that the assemblies were the same; now we're more paranoid and check the actual modules scoping - // the type are identical. This closes a security hole where identically named types in different modules of the same assembly - // could cause the wrong type to be loaded in the server context allowing violation of the type system. - while (pMT1->GetModule()->GetFile()->Equals(pMT2->GetModule()->GetFile())) - { - // Inspect the parents. - pMT1 = pMT1->GetParentMethodTable(); - pMT2 = pMT2->GetParentMethodTable(); - - // If the parents are the same shared type (e.g. Object), then we've found a match. - if (pMT1 == pMT2) - return TRUE; - - // Else check if one of the hierarchies has run out before the other (and therefore can't be equivalent). - if (pMT1 == NULL || pMT2 == NULL) - return FALSE; - } - - return FALSE; -} - -BOOL AreTypesEquivalent(MethodTable *pMT1, MethodTable *pMT2) -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_TRIGGERS; - THROWS; - } - CONTRACTL_END; - - // Equivalent here is quite a weak predicate. All it means is that the types have the same (fully assembly qualified) name. The - // derivation hierarchy is not inspected at all. - StackSString szType1; - StackSString szType2; - - TypeString::AppendType(szType1, TypeHandle(pMT1), TypeString::FormatNamespace | - TypeString::FormatFullInst | - TypeString::FormatAssembly | - TypeString::FormatNoVersion); - TypeString::AppendType(szType2, TypeHandle(pMT2), TypeString::FormatNamespace | - TypeString::FormatFullInst | - TypeString::FormatAssembly | - TypeString::FormatNoVersion); - - return szType1.Equals(szType2); -} - -PtrHashMap *CrossDomainFieldMap::s_pFieldMap = NULL; -SimpleRWLock *CrossDomainFieldMap::s_pFieldMapLock = NULL; - -BOOL CrossDomainFieldMap::CompareFieldMapEntry(UPTR val1, UPTR val2) -{ - CONTRACTL { - MODE_ANY; - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; - } - CONTRACTL_END; - - CrossDomainFieldMap::FieldMapEntry *pEntry1 = (CrossDomainFieldMap::FieldMapEntry *)(val1 << 1); - CrossDomainFieldMap::FieldMapEntry *pEntry2 = (CrossDomainFieldMap::FieldMapEntry *)val2; - - if (pEntry1->m_pSrcMT == pEntry2->m_pSrcMT && - pEntry1->m_pDstMT == pEntry2->m_pDstMT) - return TRUE; - - return FALSE; -} - -CrossDomainFieldMap::FieldMapEntry::FieldMapEntry(MethodTable *pSrcMT, MethodTable *pDstMT, FieldDesc **pFieldMap) -{ - WRAPPER_NO_CONTRACT; - - m_pSrcMT = pSrcMT; - m_pDstMT = pDstMT; - m_pFieldMap = pFieldMap; - BaseDomain *pSrcDomain = pSrcMT->GetDomain(); - m_dwSrcDomain = pSrcDomain->IsAppDomain() ? ((AppDomain*)pSrcDomain)->GetId() : ADID(0); - BaseDomain *pDstDomain = pDstMT->GetDomain(); - m_dwDstDomain = pDstDomain->IsAppDomain() ? ((AppDomain*)pDstDomain)->GetId() : ADID(0); -} - -static BOOL IsOwnerOfRWLock(LPVOID lock) -{ - // @TODO - SimpleRWLock does not have knowledge of which thread gets the writer - // lock, so no way to verify - return TRUE; -} - -// Remove any entries in the table that refer to an appdomain that is no longer live. -void CrossDomainFieldMap::FlushStaleEntries() -{ - if (s_pFieldMapLock == NULL || s_pFieldMap == NULL) - return; - - SimpleWriteLockHolder swlh(s_pFieldMapLock); - - bool fDeletedEntry = false; - PtrHashMap::PtrIterator iter = s_pFieldMap->begin(); - while (!iter.end()) - { - FieldMapEntry *pEntry = (FieldMapEntry *)iter.GetValue(); - AppDomainFromIDHolder adFrom(pEntry->m_dwSrcDomain, TRUE); - AppDomainFromIDHolder adTo(pEntry->m_dwDstDomain, TRUE); - if (adFrom.IsUnloaded() || - adTo.IsUnloaded()) //we do not use ptr for anything - { -#ifdef _DEBUG - LPVOID pDeletedEntry = -#endif - s_pFieldMap->DeleteValue(pEntry->GetHash(), pEntry); - _ASSERTE(pDeletedEntry == pEntry); - delete pEntry; - fDeletedEntry = true; - } - ++iter; - } - - if (fDeletedEntry) - s_pFieldMap->Compact(); -} - -FieldDesc **CrossDomainFieldMap::LookupOrCreateFieldMapping(MethodTable *pDstMT, MethodTable *pSrcMT) -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_TRIGGERS; - THROWS; - } - CONTRACTL_END; - - // We lazily allocate the reader/writer lock we synchronize access to the hash with. - if (s_pFieldMapLock == NULL) - { - void *pLockSpace = SystemDomain::GetGlobalLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(SimpleRWLock))); - SimpleRWLock *pLock = new (pLockSpace) SimpleRWLock(COOPERATIVE_OR_PREEMPTIVE, LOCK_TYPE_DEFAULT); - - if (FastInterlockCompareExchangePointer(&s_pFieldMapLock, pLock, NULL) != NULL) - // We lost the race, give up our copy. - SystemDomain::GetGlobalLoaderAllocator()->GetLowFrequencyHeap()->BackoutMem(pLockSpace, sizeof(SimpleRWLock)); - } - - // Now we have a lock we can use to synchronize the remainder of the init. - if (s_pFieldMap == NULL) - { - SimpleWriteLockHolder swlh(s_pFieldMapLock); - - if (s_pFieldMap == NULL) - { - PtrHashMap *pMap = new (SystemDomain::GetGlobalLoaderAllocator()->GetLowFrequencyHeap()) PtrHashMap(); - LockOwner lock = {s_pFieldMapLock, IsOwnerOfRWLock}; - pMap->Init(32, CompareFieldMapEntry, TRUE, &lock); - s_pFieldMap = pMap; - } - } - else - { - // Try getting an existing value first. - - FieldMapEntry sEntry(pSrcMT, pDstMT, NULL); - - SimpleReadLockHolder srlh(s_pFieldMapLock); - FieldMapEntry *pFound = (FieldMapEntry *)s_pFieldMap->LookupValue(sEntry.GetHash(), (LPVOID)&sEntry); - if (pFound != (FieldMapEntry *)INVALIDENTRY) - return pFound->m_pFieldMap; - } - - // We couldn't find an existing entry in the hash. Now we must go through the painstaking process of matching fields in the - // destination object to their counterparts in the source object. We build an array of pointers to source field descs ordered by - // destination type field index (all the fields for the most derived type first, then all the fields for the second most derived - // type etc.). - NewArrayHolder pFieldMap(new FieldDesc*[pDstMT->GetNumInstanceFields()]); - DWORD dwMapIndex = 0; - - // We start with the source and destination types for the object (which we know are equivalent at least in type name). For each - // layer of the type hierarchy for the destination object (from the instance type through to Object) we attempt to locate the - // corresponding source type in the hierarchy. This is non-trivial since either source or destination type hierarchies may have - // added or removed layers. We ignore extra type layers in the source hierarchy and just concentrate on destination type layers - // that introduce instance fields that are not marked NotSerializable. For each such layer we first locate the corresponding - // source layer (via fully qualified type name) and then map each serialized (and possibly optional) destination field to the - // corresponding source field (again by name). We don't allow a field to move around the type hierarchy (i.e. a field defined in - // the base class in one version can't move to a derived type in later versions and be recognized as the original field). - // Allowing this would introduce all sorts of ambiguity problems (consider the case of private fields all with the same name - // implemented at every layer of the type hierarchy). - - bool fFirstPass = true; - MethodTable *pCurrDstMT = pDstMT; - MethodTable *pCurrSrcMT = pSrcMT; - while (pCurrDstMT) - { - DWORD numInstanceFields = pCurrDstMT->GetNumIntroducedInstanceFields(); - - // Skip destination types with no instance fields to clone. - if (numInstanceFields == 0) - { - pCurrDstMT = pCurrDstMT->GetParentMethodTable(); - // Only safe to skip the source type as well on the first pass (the source version may have eliminated this level of - // the type hierarchy). - if (fFirstPass) - pCurrSrcMT = pCurrSrcMT->GetParentMethodTable(); - fFirstPass = false; - continue; - } - - // We need to synchronize the source type with the destination type. This means skipping any source types in the - // hierarchy that the destination doesn't know about. - MethodTable *pCandidateMT = pCurrSrcMT; - while (pCandidateMT) - { - if (fFirstPass || pCandidateMT == pCurrDstMT || AreTypesEquivalent(pCandidateMT, pCurrDstMT)) - { - // Skip intermediate source types (the destination type didn't know anything about them, so they're surplus - // to requirements). - pCurrSrcMT = pCandidateMT; - break; - } - - pCandidateMT = pCandidateMT->GetParentMethodTable(); - } - -#ifdef OBJECT_CLONER_STRICT_MODE - // If there's no candidate source type equivalent to the current destination type we need to prove that the destination - // type has no mandatory instance fields or throw an exception (since there's no place to fetch the field values from). - if (pCandidateMT == NULL) - { - FieldDesc *pFields = pCurrDstMT->GetApproxFieldDescListRaw(); - - for (DWORD i = 0; i < numInstanceFields; i++) - { - if (pFields[i].IsNotSerialized() || pFields[i].IsOptionallySerialized()) - { - pFieldMap[dwMapIndex++] = NULL; - continue; - } - - // We've found a field that must be cloned but have no corresponding source-side type to clone it from. Raise an - // exception. - ThrowMissingFieldException(&pFields[i]); - } - - // If we get here we know the current destination type level was effectively a no-op. Move onto the next level. - pCurrDstMT = pCurrDstMT->GetParentMethodTable(); - fFirstPass = false; - continue; - } -#else - // In lax matching mode we can ignore all fields, even those not marked optional. So the lack of an equivalent type in the - // source hierarchy doesn't bother us. Mark all fields as having a default value and then move onto the next level in the - // type hierarchy. - if (pCandidateMT == NULL) - { - for (DWORD i = 0; i < numInstanceFields; i++) - pFieldMap[dwMapIndex++] = NULL; - - pCurrDstMT = pCurrDstMT->GetParentMethodTable(); - fFirstPass = false; - continue; - } -#endif - - // If we get here we have equivalent types in pCurrDstMT and pCurrSrcMT. Now we need to locate the source field desc - // corresponding to every mandatory (and possibly optional) field in the destination type and record it in the field map. - DWORD numSrcFields = pCurrSrcMT->GetNumIntroducedInstanceFields(); - DWORD numDstFields = pCurrDstMT->GetNumIntroducedInstanceFields(); - - FieldDesc *pDstFields = pCurrDstMT->GetApproxFieldDescListRaw(); - FieldDesc *pSrcFields = pCurrSrcMT->GetApproxFieldDescListRaw(); - - for (DWORD i = 0; i < numDstFields; i++) - { - // Non-serialized destination fields aren't filled in from source types. - if (pDstFields[i].IsNotSerialized()) - { - pFieldMap[dwMapIndex++] = NULL; - continue; - } - - // Go look for a field in the source type with the same name. - LPCUTF8 szDstFieldName = pDstFields[i].GetName(); - DWORD j; - for (j = 0; j < numSrcFields; j++) - { - LPCUTF8 szSrcFieldName = pSrcFields[j].GetName(); - if (strcmp(szDstFieldName, szSrcFieldName) == 0) - { - // Check that the field isn't marked NotSerialized (if it is then it's invisible to the cloner). - if (pSrcFields[j].IsNotSerialized()) - j = numSrcFields; - break; - } - } - -#ifdef OBJECT_CLONER_STRICT_MODE - // If we didn't find a corresponding field it might not be fatal; the field could be optionally serializable from the - // destination type's point of view. - if (j == numSrcFields) - { - if (pDstFields[i].IsOptionallySerialized()) - { - pFieldMap[dwMapIndex++] = NULL; - continue; - } - // The field was required. Throw an exception. - ThrowMissingFieldException(&pDstFields[i]); - } -#else - // In lax matching mode we can ignore all fields, even those not marked optional. Simply mark this field as having the - // default value. - if (j == numSrcFields) - { - pFieldMap[dwMapIndex++] = NULL; - continue; - } -#endif - - // Otherwise we found matching fields (in name at least, type processing is done later). - pFieldMap[dwMapIndex++] = &pSrcFields[j]; - } - - pCurrDstMT = pCurrDstMT->GetParentMethodTable(); - pCurrSrcMT = pCurrSrcMT->GetParentMethodTable(); - fFirstPass = false; - } - - _ASSERTE(dwMapIndex == pDstMT->GetNumInstanceFields()); - - // Now we have a field map we should insert it into the hash. - NewHolder pEntry(new FieldMapEntry(pSrcMT, pDstMT, pFieldMap)); - PREFIX_ASSUME(pEntry != NULL); - pFieldMap.SuppressRelease(); - - SimpleWriteLockHolder swlh(s_pFieldMapLock); - - UPTR key = pEntry->GetHash(); - - FieldMapEntry *pFound = (FieldMapEntry *)s_pFieldMap->LookupValue(key, (LPVOID)pEntry); - if (pFound == (FieldMapEntry *)INVALIDENTRY) - { - s_pFieldMap->InsertValue(key, (LPVOID)pEntry); - pEntry.SuppressRelease(); - return pFieldMap; - } - else - return pFound->m_pFieldMap; -} - -ARG_SLOT ObjectClone::HandleFieldTypeMismatch(CorElementType dstType, CorElementType srcType, void *pData, MethodTable *pSrcMT) -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_TRIGGERS; - THROWS; - } - CONTRACTL_END - _ASSERTE(m_context != ObjectFreezer); - ARG_SLOT data = 0; - InvokeUtil::CreatePrimitiveValue(dstType, srcType, pData, pSrcMT, &data); - return data; -} - -void ObjectClone::ScanISerializableMembers(DWORD IObjRefTSOIndex, DWORD ISerTSOIndex, DWORD BoxedValTSOIndex, PTRARRAYREF refValues) -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_TRIGGERS; - THROWS; - } - CONTRACTL_END - - _ASSERTE(m_context != ObjectFreezer); - // Queue the non-primitive types - DWORD numFieldsToBeMarshalled = 0; - PTRARRAYREF refNewValues = NULL; - - LOG((LF_REMOTING, LL_INFO1000, "ScanISerializableMembers. Scanning members of ISerializable type object.\n")); - GCPROTECT_BEGIN(refValues); - - refNewValues = (PTRARRAYREF) AllocateObjectArray(refValues->GetNumComponents(), g_pObjectClass, FALSE); - - _ASSERTE(refNewValues != NULL); - - for (DWORD index = 0; index < refValues->GetNumComponents(); index++) - { - OBJECTREF refField = refValues->GetAt(index); - if (refField == NULL) - continue; - - if (CorTypeInfo::IsPrimitiveType(refField->GetTypeHandle().GetSignatureCorElementType()) || - refField->GetMethodTable() == g_pStringClass) - { - refNewValues->SetAt(index, refField); - continue; - } - - ISerializableMemberInfo isInfo(ISerTSOIndex, index); - QOM.Enqueue(refField, NULL, NULL, (QueuedObjectInfo *) &isInfo); - numFieldsToBeMarshalled++; - refNewValues->SetAt(index, NULL); - LOG((LF_REMOTING, LL_INFO1000, "ScanISerializableMembers. Member at index %d is reference type. Adding to QOM.\n", index)); - } - GCPROTECT_END(); - - // Update TSO - OBJECTREF refNames = NULL, refFields = NULL; - QueuedObjectInfo *pDummy; - OBJECTREF newObj; - newObj = TSO.GetAt(ISerTSOIndex, &refNames, &refFields, &pDummy); - _ASSERTE(newObj == m_newObject); - - TSO.SetAt(ISerTSOIndex, m_newObject, refNames, refNewValues, pDummy); - - if (numFieldsToBeMarshalled > 0) - { - ParentInfo fxInfo(numFieldsToBeMarshalled); - fxInfo.SetIsISerializableInstance(); - fxInfo.SetIObjRefIndexIntoTSO(IObjRefTSOIndex); - fxInfo.SetISerIndexIntoTSO(ISerTSOIndex); - fxInfo.SetBoxedValIndexIntoTSO(BoxedValTSOIndex); - QOF.Enqueue(m_newObject, NULL, NULL, (QueuedObjectInfo *) &fxInfo); - LOG((LF_REMOTING, LL_INFO1000, "ScanISerializableMembers. Current object had total of %d reference type fields. Adding to QOF.\n", numFieldsToBeMarshalled)); - // Delay calling any OnDeserialized callbacks until the end of the cloning operation (it's difficult to tell when all the - // children have been deserialized). - if (HasVtsCallbacks(m_newObject->GetMethodTable(), RemotingVtsInfo::VTS_CALLBACK_ON_DESERIALIZED)) - VDC.Enqueue(m_newObject, NULL, NULL, NULL); - if (m_cbInterface->RequiresDeserializationCallback(m_newObject->GetMethodTable())) - { - LOG((LF_REMOTING, LL_INFO1000, "ScanISerializableMembers. Adding object to Table of IDeserialization Callbacks\n")); - QueuedObjectInfo noInfo; - TDC.Enqueue(m_newObject, NULL, NULL, &noInfo); - } - } - else - { - // This is effectively a leaf node (no complex children) so if the type has a callback for OnDeserialized we'll deliver it - // now. This fixes callback ordering for a few more edge cases (e.g. VSW 415611) and is reasonably cheap. We can never do a - // perfect job (in the presence of object graph cycles) and a near perfect job (intuitively ordered callbacks for acyclic - // object graphs) is prohibitively expensive; so we're stuck with workarounds like this. - InvokeVtsCallbacks(m_newObject, RemotingVtsInfo::VTS_CALLBACK_ON_DESERIALIZED, m_toDomain); - if (m_cbInterface->RequiresDeserializationCallback(m_newObject->GetMethodTable())) - MakeIDeserializationCallback(m_newObject); - } -} - -void ObjectClone::ScanArrayMembers() -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_TRIGGERS; - THROWS; - } - CONTRACTL_END -#ifdef _DEBUG - MethodTable *pCurrMT = m_currObject->GetMethodTable(); - _ASSERTE(pCurrMT && pCurrMT->IsArray()); - MethodTable *pNewMT = m_newObject->GetMethodTable(); - _ASSERTE(pNewMT && pNewMT->IsArray()); -#endif - - LOG((LF_REMOTING, LL_INFO1000, "ScanArrayMembers. Scanning members of array object.\n")); - BASEARRAYREF refFromArray = (BASEARRAYREF) m_currObject; - BASEARRAYREF refToArray = (BASEARRAYREF) m_newObject; - - GCPROTECT_BEGIN(refFromArray); - GCPROTECT_BEGIN(refToArray); - - TypeHandle toArrayElementType = refToArray->GetArrayElementTypeHandle(); - DWORD numComponents = refFromArray->GetNumComponents(); - MethodTable *pArrayMT = refFromArray->GetMethodTable(); - - DWORD rank = pArrayMT->GetRank(); - DWORD dwOffset = 0; - - DWORD *pIndices = (DWORD*) _alloca(sizeof(DWORD) * rank); - VOID *pTemp = _alloca(sizeof(NDimArrayMemberInfo) + rank * sizeof(DWORD)); - NDimArrayMemberInfo *pArrInfo = new (pTemp) NDimArrayMemberInfo(rank); - - bool boxingObjects = (pArrayMT->GetArrayElementType() == ELEMENT_TYPE_VALUETYPE); - - // Must enter the from domain if we are going to be allocating any non-agile boxes - ENTER_DOMAIN_PTR_PREDICATED(m_fromDomain,ADV_RUNNINGIN,boxingObjects); - - if (boxingObjects) - { - pArrInfo->SetNeedsUnboxing(); - - // We may be required to activate value types of array elements, since we - // are going to box them. Hoist out the required domain transition and - // activation. - - MethodTable *pMT = ((BASEARRAYREF)m_currObject)->GetArrayElementTypeHandle().GetMethodTable(); - pMT->EnsureInstanceActive(); - } - - DWORD numFixupsNeeded = 0; - for (DWORD i = 0; i < numComponents; i++) - { - // The array could be huge. To avoid keeping a pending GC waiting (and maybe timing out) we're going to pulse the GC mode - // every so often. Do this more freqeuntly in debug builds, where each iteration through this loop takes considerably - // longer. -#ifdef _DEBUG -#define COPY_CYCLES 1024 -#else -#define COPY_CYCLES 8192 -#endif - if ((i % COPY_CYCLES) == (COPY_CYCLES - 1)) - GetThread()->PulseGCMode(); - - const INT32 *pBoundsPtr = refFromArray->GetBoundsPtr(); - DWORD findIndices = i; - for (DWORD rankIndex = rank; rankIndex > 0; rankIndex--) - { - DWORD numElementsInDimension = pBoundsPtr[rankIndex - 1]; - DWORD quotient = findIndices / numElementsInDimension; - DWORD remainder = findIndices % numElementsInDimension; - pIndices[rankIndex - 1] = remainder; - findIndices = quotient; - } - - pArrInfo->SetIndices(pIndices); - - Object *rv = GetObjectFromArray((BASEARRAYREF *)&m_currObject, dwOffset); - if (rv != NULL) - { - OBJECTREF oRef = ObjectToOBJECTREF(rv); - - if (oRef->GetMethodTable() == g_pStringClass && m_context != ObjectFreezer) - { - OBJECTREF* pElem = (OBJECTREF*)(refToArray->GetDataPtr() + (dwOffset * pArrayMT->GetComponentSize())); - SetObjectReference(pElem,oRef,GetAppDomain()); - } - else - { - // Add the object to QOM - numFixupsNeeded++; - QOM.Enqueue(oRef, NULL, NULL, pArrInfo); - LOG((LF_REMOTING, LL_INFO1000, "ScanArrayMembers. Element at offset %d is reference type. Adding to QOM.\n", dwOffset)); - } - } - dwOffset ++; - } - - if (numFixupsNeeded > 0) - { - ParentInfo fxInfo(numFixupsNeeded); - QOF.Enqueue(m_newObject, NULL, NULL, (QueuedObjectInfo *)&fxInfo); - LOG((LF_REMOTING, LL_INFO1000, "ScanArrayMembers. Current object had total of %d reference type fields. Adding to QOF.\n", numFixupsNeeded)); - } - - END_DOMAIN_TRANSITION; - - GCPROTECT_END(); - GCPROTECT_END(); -} - -#ifdef _MSC_VER -#pragma warning(push) -#pragma warning(disable:4244) -#endif // _MSC_VER -Object *ObjectClone::GetObjectFromArray(BASEARRAYREF* arrObj, DWORD dwOffset) -{ - CONTRACTL { - THROWS; - if ((*arrObj)->GetArrayElementTypeHandle().GetMethodTable()->IsValueType()) GC_TRIGGERS; else GC_NOTRIGGER; - } CONTRACTL_END; - - // Get the type of the element... - switch ((*arrObj)->GetArrayElementType()) { - - case ELEMENT_TYPE_VOID: - return NULL; - - case ELEMENT_TYPE_CLASS: // Class - case ELEMENT_TYPE_SZARRAY: // Single Dim, Zero - case ELEMENT_TYPE_ARRAY: // General Array - case ELEMENT_TYPE_STRING: - case ELEMENT_TYPE_OBJECT: - { - _ASSERTE((*arrObj)->GetComponentSize() == sizeof(OBJECTREF)); - BYTE* pData = ((BYTE*)(*arrObj)->GetDataPtr()) + (dwOffset * sizeof(OBJECTREF)); - return *(Object **)pData; - } - - case ELEMENT_TYPE_VALUETYPE: - { - MethodTable *pMT = (*arrObj)->GetArrayElementTypeHandle().GetMethodTable(); - WORD wComponentSize = (*arrObj)->GetComponentSize(); - BYTE* pData = ((BYTE*)(*arrObj)->GetDataPtr()) + (dwOffset * wComponentSize); - return OBJECTREFToObject(pMT->Box(pData)); - } - case ELEMENT_TYPE_BOOLEAN: // boolean - case ELEMENT_TYPE_I1: // sbyte - case ELEMENT_TYPE_U1: - case ELEMENT_TYPE_I2: // short - case ELEMENT_TYPE_U2: - case ELEMENT_TYPE_CHAR: // char - case ELEMENT_TYPE_I4: // int - case ELEMENT_TYPE_I: - case ELEMENT_TYPE_U: - case ELEMENT_TYPE_U4: - case ELEMENT_TYPE_I8: // long - case ELEMENT_TYPE_U8: - case ELEMENT_TYPE_R4: // float - case ELEMENT_TYPE_R8: // double - case ELEMENT_TYPE_PTR: - { - // Note that this is a cloned version of the value class case above for performance - - // Watch for GC here. We allocate the object and then - // grab the void* to the data we are going to copy. - MethodTable *pMT = (*arrObj)->GetArrayElementTypeHandle().GetMethodTable(); - OBJECTREF obj = ::AllocateObject(pMT); - WORD wComponentSize = (*arrObj)->GetComponentSize(); - BYTE* pData = ((BYTE*)(*arrObj)->GetDataPtr()) + (dwOffset * wComponentSize); - CopyValueClassUnchecked(obj->UnBox(), pData, (*arrObj)->GetArrayElementTypeHandle().GetMethodTable()); - return OBJECTREFToObject(obj); - } - - case ELEMENT_TYPE_END: - default: - _ASSERTE(!"Unknown array element type"); - } - - _ASSERTE(!"Should never get here"); - return NULL; -} -#ifdef _MSC_VER -#pragma warning(pop) -#endif // _MSC_VER: warning C4244 - - -void ObjectClone::CompleteValueTypeFields(OBJECTREF newObj, OBJECTREF refParent, QueuedObjectInfo *objInfo) -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_TRIGGERS; - THROWS; - } - CONTRACTL_END - -#ifdef _DEBUG - { - SString ssTypeName; - SString ssParentTypeName; - newObj->GetMethodTable()->_GetFullyQualifiedNameForClassNestedAware(ssTypeName); - refParent->GetMethodTable()->_GetFullyQualifiedNameForClassNestedAware(ssParentTypeName); - LOG((LF_REMOTING, LL_INFO1000, "CompleteValueTypeFields. Fixing up value type field of type %S into parent of type %S.\n", - ssTypeName.GetUnicode(), ssParentTypeName.GetUnicode())); - } -#endif - - ValueTypeInfo *pValTypeInfo = (ValueTypeInfo *)objInfo; - QueuedObjectInfo *pFixupInfo = pValTypeInfo->GetFixupInfo(); - PREFIX_ASSUME(pFixupInfo != NULL); - - _ASSERTE(pFixupInfo->NeedsUnboxing()); - if (pFixupInfo->IsArray()) - { - m_newObject = newObj; - HandleArrayFixup(refParent, pFixupInfo); - } - else - { - GCPROTECT_BEGIN(refParent); - GCPROTECT_BEGIN(newObj); - ObjectMemberInfo *pObjInfo = (ObjectMemberInfo *)pFixupInfo; - FieldDesc *pTargetField = pObjInfo->GetFieldDesc(); - - TypeHandle fldType = LoadExactFieldType(pTargetField, refParent, m_toDomain); - void *pDest = refParent->GetData() + pTargetField->GetOffset(); - _ASSERTE(GetAppDomain()==m_toDomain); - - if (!fldType.GetMethodTable()->UnBoxInto(pDest, newObj)) - COMPlusThrow(kArgumentException,W("Arg_ObjObj")); - - GCPROTECT_END(); - GCPROTECT_END(); - } - pValTypeInfo->SetHasBeenProcessed(); -} - -void ObjectClone::CompleteSpecialObjects() -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; - - OBJECTREF nextObj = NULL; - OBJECTREF refNames = NULL; - OBJECTREF refValues = NULL; - SpecialObjectInfo *pObjInfo = NULL; - - GCPROTECT_BEGIN(refNames); - GCPROTECT_BEGIN(refValues); - - DWORD skippedObjects = 0; - DWORD numLoops = 0; - - if (TSO.GetCount() == 0) - goto EarlyExit; - - LOG((LF_REMOTING, LL_INFO1000, "CompleteSpecialObjects. Beginning.\n")); - do - { - skippedObjects = 0; - numLoops++; - DWORD index = 0; - TSO.BeginEnumeration(&index); - while((nextObj = TSO.GetNext(&index, &refNames, &refValues, (QueuedObjectInfo **)&pObjInfo)) != NULL) - { - if (pObjInfo->HasBeenProcessed()) - continue; - - if (pObjInfo->IsISerializableInstance()) - { - _ASSERTE(m_context != ObjectFreezer); - - LOG((LF_REMOTING, LL_INFO1000, "CompleteSpecialObjects. ISerializable instance at index %d.\n", index)); - ISerializableInstanceInfo *iserInfo = (ISerializableInstanceInfo *)pObjInfo; - if (iserInfo->GetNumSpecialMembers() > 0) - { - if (CheckForUnresolvedMembers(iserInfo)) - { - LOG((LF_REMOTING, LL_INFO1000, "CompleteSpecialObjects. Skipping ISerializable instance due to unresolved members.\n")); - skippedObjects++; - continue; - } - } - CompleteISerializableObject(nextObj, refNames, refValues, iserInfo); - } - else if (pObjInfo->IsIObjRefInstance()) - { - _ASSERTE(m_context != ObjectFreezer); - - LOG((LF_REMOTING, LL_INFO1000, "CompleteSpecialObjects. IObjectReference instance at index %d.\n", index)); - IObjRefInstanceInfo *iorInfo = (IObjRefInstanceInfo *)pObjInfo; - if (iorInfo->GetNumSpecialMembers() > 0 || - iorInfo->GetISerTSOIndex() != (DWORD) -1) - { - if (CheckForUnresolvedMembers(iorInfo)) - { - LOG((LF_REMOTING, LL_INFO1000, "CompleteSpecialObjects. Skipping IObjectReference instance due to unresolved members.\n")); - skippedObjects++; - continue; - } - } - if (!CompleteIObjRefObject(nextObj, index, iorInfo)) - skippedObjects++; - } - else - { - _ASSERTE(pObjInfo->IsBoxedObject()); - LOG((LF_REMOTING, LL_INFO1000, "CompleteSpecialObjects. Boxed valuetype instance at index %d.\n", index)); - ValueTypeInfo *valTypeInfo = (ValueTypeInfo *)pObjInfo; - if (valTypeInfo->GetNumSpecialMembers() > 0 || - valTypeInfo->GetISerTSOIndex() != (DWORD) -1 || - valTypeInfo->GetIObjRefTSOIndex() != (DWORD) -1) - { - if (CheckForUnresolvedMembers(valTypeInfo)) - { - LOG((LF_REMOTING, LL_INFO1000, "CompleteSpecialObjects. Skipping boxed value instance due to unresolved members.\n")); - skippedObjects++; - continue; - } - } - // If we were waiting on an IObjRef fixup then the target object will have changed. - if (valTypeInfo->GetIObjRefTSOIndex() != (DWORD) -1) - { - OBJECTREF dummy1, dummy2; - QueuedObjectInfo *dummy3; - nextObj = TSO.GetAt(valTypeInfo->GetIObjRefTSOIndex(), &dummy1, &dummy2, &dummy3); - } - CompleteValueTypeFields(nextObj, refNames, valTypeInfo); - } - - }; - } while (skippedObjects > 0 && numLoops < 100); - - if (skippedObjects > 0 && numLoops >= 100) - { - COMPlusThrow(kSerializationException, IDS_SERIALIZATION_UNRESOLVED_SPECIAL_OBJECT); - } -EarlyExit: ; - GCPROTECT_END(); - GCPROTECT_END(); -} - -BOOL ObjectClone::CheckForUnresolvedMembers(SpecialObjectInfo *splInfo) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; - MODE_COOPERATIVE; - } - CONTRACTL_END; - - BOOL foundUnresolvedMember = FALSE; - - DWORD mappingIndex = splInfo->GetMappingTableIndex(); - for (DWORD count = 0; count < splInfo->GetNumSpecialMembers(); count++) - { - DWORD memberIndex = TMappings.GetAt(mappingIndex++); - SpecialObjectInfo *pMemberInfo; - OBJECTREF dummy1, dummy2, dummy3; - dummy1 = TSO.GetAt(memberIndex, &dummy2, &dummy3, (QueuedObjectInfo **)&pMemberInfo); - // An unresolved IObjRef member is a blocker for any special object parent - if (pMemberInfo->IsIObjRefInstance() && !pMemberInfo->HasBeenProcessed()) - { - LOG((LF_REMOTING, LL_INFO1000, "CheckForUnresolvedMembers. Found unresolved IObjectReference member at index %d.\n", memberIndex)); - foundUnresolvedMember = TRUE; - break; - } - - // An unresolved ISer member is a blocker for IObjRef parent - if (pMemberInfo->IsISerializableInstance() && - !pMemberInfo->HasBeenProcessed() && - splInfo->IsIObjRefInstance()) - { - LOG((LF_REMOTING, LL_INFO1000, "CheckForUnresolvedMembers. Found unresolved ISerializable member at index %d.\n", memberIndex)); - foundUnresolvedMember = TRUE; - break; - } - - // An unresolved boxed object is a blocker for a boxed parent or an IObjRef parent - if (pMemberInfo->IsBoxedObject() && - !pMemberInfo->HasBeenProcessed() && - (splInfo->IsIObjRefInstance() || splInfo->IsBoxedObject())) - { - LOG((LF_REMOTING, LL_INFO1000, "CheckForUnresolvedMembers. Found unresolved boxed valuetype member at index %d.\n", memberIndex)); - foundUnresolvedMember = TRUE; - break; - } - } - - // Done checking members. Now check if this instance itself needs some processing - // If an instance is both ISer and IObj, then ISer should be processed before IObjRef - if (!foundUnresolvedMember && splInfo->IsIObjRefInstance()) - { - IObjRefInstanceInfo *pObjRefInfo = (IObjRefInstanceInfo *)splInfo; - if (pObjRefInfo->GetISerTSOIndex() != (DWORD) -1) - { - // Check if the ISer requirements have been met - SpecialObjectInfo *pMemberInfo; - OBJECTREF dummy1, dummy2, dummy3; - dummy1 = TSO.GetAt(pObjRefInfo->GetISerTSOIndex(), &dummy2, &dummy3, (QueuedObjectInfo **)&pMemberInfo); - if (!pMemberInfo->HasBeenProcessed()) - { - LOG((LF_REMOTING, LL_INFO1000, "CheckForUnresolvedMembers. This instance is also ISerializable at index %d. Not resolved yet.\n", pObjRefInfo->GetISerTSOIndex())); - foundUnresolvedMember = TRUE; - } - } - } - - // If an instance is ISer, IObj and a boxed value type, then ISer,IObj should be processed before unboxing - if (!foundUnresolvedMember && splInfo->IsBoxedObject()) - { - ValueTypeInfo *pValTypeInfo = (ValueTypeInfo *)splInfo; - if (pValTypeInfo->GetISerTSOIndex() != (DWORD) -1) - { - // Check if the ISer requirements have been met - SpecialObjectInfo *pMemberInfo; - OBJECTREF dummy1, dummy2, dummy3; - dummy1 = TSO.GetAt(pValTypeInfo->GetISerTSOIndex(), &dummy2, &dummy3, (QueuedObjectInfo **)&pMemberInfo); - if (!pMemberInfo->HasBeenProcessed()) - { - LOG((LF_REMOTING, LL_INFO1000, "CheckForUnresolvedMembers. This instance is also ISerializable at index %d. Not resolved yet.\n", pValTypeInfo->GetISerTSOIndex())); - foundUnresolvedMember = TRUE; - } - } - if (!foundUnresolvedMember && pValTypeInfo->GetIObjRefTSOIndex() != (DWORD) -1) - { - // Check if the ISer requirements have been met - SpecialObjectInfo *pMemberInfo; - OBJECTREF dummy1, dummy2, dummy3; - dummy1 = TSO.GetAt(pValTypeInfo->GetIObjRefTSOIndex(), &dummy2, &dummy3, (QueuedObjectInfo **)&pMemberInfo); - if (!pMemberInfo->HasBeenProcessed()) - { - LOG((LF_REMOTING, LL_INFO1000, "CheckForUnresolvedMembers. This instance is also IObjectReference at index %d. Not resolved yet.\n", pValTypeInfo->GetIObjRefTSOIndex())); - foundUnresolvedMember = TRUE; - } - } - } - return foundUnresolvedMember; -} - -void ObjectClone::CompleteISerializableObject(OBJECTREF IserObj, OBJECTREF refNames, OBJECTREF refValues, ISerializableInstanceInfo *iserInfo) -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END - - _ASSERTE(m_context != ObjectFreezer); - - struct _gc { - OBJECTREF IserObj; - OBJECTREF refNames; - OBJECTREF refValues; - OBJECTREF refSerInfo; - } gc; - - gc.IserObj = IserObj; - gc.refNames = refNames; - gc.refValues = refValues; - gc.refSerInfo = NULL; - - GCPROTECT_BEGIN(gc); - -#ifdef _DEBUG - { - DefineFullyQualifiedNameForClass(); - LOG((LF_REMOTING, LL_INFO1000, "CompleteISerializableObject. Completing ISerializable object of type %s.\n", - GetFullyQualifiedNameForClassNestedAware(gc.IserObj->GetMethodTable()))); - } -#endif - - BOOL bIsBoxed = gc.IserObj->GetMethodTable()->IsValueType(); - - // StreamingContextData is an out parameter of the managed callback, so it's passed by reference on all platforms. - RuntimeMethodHandle::StreamingContextData context = {0}; - - PREPARE_NONVIRTUAL_CALLSITE(METHOD__OBJECTCLONEHELPER__PREPARE_DATA); - - DECLARE_ARGHOLDER_ARRAY(args, 4); - - args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(gc.IserObj); - args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc.refNames); - args[ARGNUM_2] = OBJECTREF_TO_ARGHOLDER(gc.refValues); - args[ARGNUM_3] = PTR_TO_ARGHOLDER(&context); - - CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE; - CALL_MANAGED_METHOD_RETREF(gc.refSerInfo, OBJECTREF, args); - - if (iserInfo->IsTargetNotISerializable()) - { - // Prepare data would have constructed the object already - _ASSERTE(gc.refSerInfo == NULL); - } - else - { - _ASSERTE(gc.refSerInfo != NULL); - MethodTable *pMT = gc.IserObj->GetMethodTable(); - _ASSERTE(pMT); - - MethodDesc * pCtor; - -#ifdef FEATURE_IMPERSONATION - // Deal with the WindowsIdentity class specially by calling an internal - // serialization constructor; the public one has a security demand that - // breaks partial trust scenarios and is too expensive to assert for. - if (MscorlibBinder::IsClass(pMT, CLASS__WINDOWS_IDENTITY)) - pCtor = MscorlibBinder::GetMethod(METHOD__WINDOWS_IDENTITY__SERIALIZATION_CTOR); - else -#endif - pCtor = MemberLoader::FindConstructor(pMT, &gsig_IM_SerInfo_StrContext_RetVoid); - - if (pCtor == NULL) - { - DefineFullyQualifiedNameForClassW(); - COMPlusThrow(kSerializationException, IDS_SERIALIZATION_CTOR_NOT_FOUND, - GetFullyQualifiedNameForClassNestedAwareW(pMT)); - } - - MethodDescCallSite ctor(pCtor); - - ARG_SLOT argSlots[3]; - // Nullable does not implement ISerializable. - _ASSERTE(!Nullable::IsNullableType(gc.IserObj->GetMethodTable())); - argSlots[0] = (bIsBoxed ? (ARG_SLOT)(SIZE_T)(gc.IserObj->UnBox()) : ObjToArgSlot(gc.IserObj)); - argSlots[1] = ObjToArgSlot(gc.refSerInfo); -#if defined(_TARGET_X86_) || defined(_TARGET_ARM_) - static_assert_no_msg(sizeof(context) == sizeof(ARG_SLOT)); - argSlots[2] = *(ARG_SLOT*)(&context); // StreamingContext is passed by value on x86 and ARM -#elif defined(_WIN64) - static_assert_no_msg(sizeof(context) > sizeof(ARG_SLOT)); - argSlots[2] = PtrToArgSlot(&context); // StreamingContext is passed by reference on WIN64 -#else // !_TARGET_X86_ && !_WIN64 && !_TARGET_ARM_ - PORTABILITY_ASSERT("ObjectClone::CompleteISerializableObject() - NYI on this platform"); -#endif // !_TARGET_X86_ && !_WIN64 && !_TARGET_ARM_ - ctor.CallWithValueTypes(&argSlots[0]); - } - iserInfo->SetHasBeenProcessed(); - - GCPROTECT_END(); - -} - -// FALSE means the object could not be resolved and need to perform more iterations -BOOL ObjectClone::CompleteIObjRefObject(OBJECTREF IObjRef, DWORD tsoIndex, IObjRefInstanceInfo *iorInfo) -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END - - BOOL bResult = FALSE; - - struct _gc { - OBJECTREF IObjRef; - OBJECTREF newObj; - OBJECTREF refParent; - OBJECTREF refFromObj; - OBJECTREF resolvedObject; - } gc; - - gc.IObjRef = IObjRef; - gc.newObj = NULL; - gc.refParent = NULL; - gc.refFromObj = NULL; - gc.resolvedObject = NULL; - - GCPROTECT_BEGIN(gc); - - _ASSERTE(m_context != ObjectFreezer); - // First check if this is a repeat object - if (iorInfo->IsRepeatObject()) - { - OBJECTREF dummy; - dummy = TSO.GetAt(tsoIndex, &gc.refFromObj, &gc.refParent, (QueuedObjectInfo **)&iorInfo); - PREFIX_ASSUME(gc.refFromObj != NULL); - - // Look in the Table of Seen objects whether this IObjRef has been resolved - int currId; - currId = TOS.HasID(gc.refFromObj, &gc.resolvedObject); - _ASSERTE(currId != -1); - - MethodTable *pResolvedMT = gc.resolvedObject->GetMethodTable(); - if (!pResolvedMT->IsTransparentProxy() && - m_cbInterface->IsIObjectReferenceType(pResolvedMT)) - { - bResult = FALSE; - } - else - { -#ifdef _DEBUG - { - DefineFullyQualifiedNameForClass(); - LOG((LF_REMOTING, LL_INFO1000, "CompleteIObjRefObject. Found IObjectReference object of type %s already resolved.\n", - GetFullyQualifiedNameForClassNestedAware(gc.IObjRef->GetMethodTable()))); - } -#endif - - // Yes, its been resolved. - // Fix the object into its parent (unless it requires unboxing, in which case there's another entry in the TSO ready to - // do that). - QueuedObjectInfo *pFixupInfo = (QueuedObjectInfo *)iorInfo->GetFixupInfo(); - PREFIX_ASSUME(pFixupInfo != NULL); - if (pFixupInfo->NeedsUnboxing()) - { - TSO.SetAt(tsoIndex, gc.resolvedObject, gc.refFromObj, gc.refParent, iorInfo); - iorInfo->SetHasBeenProcessed(); - bResult = TRUE; - } - else - { - if (gc.refParent == NULL) - m_topObject = gc.resolvedObject; - else - { - m_newObject = gc.resolvedObject; - if (pFixupInfo->NeedsUnboxing()) - CompleteValueTypeFields(gc.resolvedObject, gc.refParent, pFixupInfo); - else - Fixup(gc.resolvedObject, gc.refParent, pFixupInfo); - } - iorInfo->SetHasBeenProcessed(); - bResult = TRUE; - } - } - } - else - { - MethodTable *pMT = gc.IObjRef->GetMethodTable(); - _ASSERTE(pMT); - - MethodTable *pItf = MscorlibBinder::GetClass(CLASS__IOBJECTREFERENCE); - MethodDesc *pMeth = GetInterfaceMethodImpl(pMT, pItf, 0); - MethodDescCallSite method(pMeth, &gc.IObjRef); - - // Ensure Streamingcontext type is loaded. Do not delete this line - MethodTable *pMTStreamingContext; - pMTStreamingContext = MscorlibBinder::GetClass(CLASS__STREAMING_CONTEXT); - _ASSERTE(pMTStreamingContext); - - ARG_SLOT arg[2]; - arg[0] = ObjToArgSlot(gc.IObjRef); - - RuntimeMethodHandle::StreamingContextData context = { NULL, GetStreamingContextState() }; -#ifdef _WIN64 - static_assert_no_msg(sizeof(context) > sizeof(ARG_SLOT)); - arg[1] = PtrToArgSlot(&context); -#else - static_assert_no_msg(sizeof(context) <= sizeof(ARG_SLOT)); - arg[1] = *(ARG_SLOT*)(&context); -#endif - - gc.newObj = method.CallWithValueTypes_RetOBJECTREF(&arg[0]); - - INDEBUG(DefineFullyQualifiedNameForClass();) - - _ASSERTE(gc.newObj != NULL); - MethodTable *pNewMT = gc.newObj->GetMethodTable(); - if (!pNewMT->IsTransparentProxy() && - gc.newObj != gc.IObjRef && - m_cbInterface->IsIObjectReferenceType(pNewMT)) - { -#ifdef _DEBUG - LOG((LF_REMOTING, LL_INFO1000, - "CompleteIObjRefObject. GetRealObject on object of type %s returned another IObjectReference. Adding back to TSO.\n", - GetFullyQualifiedNameForClassNestedAware(gc.IObjRef->GetMethodTable()))); -#endif - - // Put this back into the table - OBJECTREF dummy; - dummy = TSO.GetAt(tsoIndex, &gc.refFromObj, &gc.refParent, (QueuedObjectInfo **)&iorInfo); - TSO.SetAt(tsoIndex, gc.newObj, gc.refFromObj, gc.refParent, iorInfo); - bResult = FALSE; - } - else - { -#ifdef _DEBUG - LOG((LF_REMOTING, LL_INFO1000, - "CompleteIObjRefObject. Called GetRealObject on object of type %s. Fixing it up into its parent.\n", - GetFullyQualifiedNameForClassNestedAware(gc.IObjRef->GetMethodTable()))); -#endif - // Fix the object into its parent (unless it requires unboxing, in which case there's another entry in the TSO ready to - // do that). - QueuedObjectInfo *pFixupInfo = (QueuedObjectInfo *)iorInfo->GetFixupInfo(); - OBJECTREF dummy; - dummy = TSO.GetAt(tsoIndex, &gc.refFromObj, &gc.refParent, (QueuedObjectInfo **)&iorInfo); - if (pFixupInfo->NeedsUnboxing()) - { - TSO.SetAt(tsoIndex, gc.newObj, gc.refFromObj, gc.refParent, iorInfo); - iorInfo->SetHasBeenProcessed(); - bResult = TRUE; - } - else - { - if (gc.refParent == NULL) - m_topObject = gc.newObj; - else - { - m_newObject = gc.newObj; - Fixup(gc.newObj, gc.refParent, pFixupInfo); - } - - // Update Table of Seen objects, so that any repeat objects can be updated too - TOS.UpdateObject(gc.refFromObj, gc.newObj); - iorInfo->SetHasBeenProcessed(); - bResult = TRUE; - } - } - } - - GCPROTECT_END(); - return bResult; -} - -void MakeIDeserializationCallback(OBJECTREF refTarget) -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END; - - struct _gc { - OBJECTREF refTarget; - } gc; - gc.refTarget = refTarget; - - GCPROTECT_BEGIN(gc); - - MethodTable *pMT = gc.refTarget->GetMethodTable(); - _ASSERTE(pMT); - - MethodTable *pItf = MscorlibBinder::GetClass(CLASS__IDESERIALIZATIONCB); - MethodDesc *pMeth = GetInterfaceMethodImpl(pMT, pItf, 0); - PCODE pCode = pMeth->GetSingleCallableAddrOfCode(); - - PREPARE_NONVIRTUAL_CALLSITE_USING_CODE(pCode); - - DECLARE_ARGHOLDER_ARRAY(args, 2); - - args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(gc.refTarget); - args[ARGNUM_1] = NULL; - - CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE; - CALL_MANAGED_METHOD_NORET(args); - - GCPROTECT_END(); -} - -void ObjectClone::CompleteIDeserializationCallbacks() -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END - OBJECTREF Dummy1 = NULL, Dummy2 = NULL; - QueuedObjectInfo *pObjInfo = NULL; - - if (TDC.GetCount() == 0) - return; - - LOG((LF_REMOTING, LL_INFO1000, "CompleteIDeserializationCallbacks. Beginning.\n")); - - OBJECTREF nextObj; - while ((nextObj = TDC.Dequeue(&Dummy1, &Dummy2, &pObjInfo)) != NULL) - { - MakeIDeserializationCallback(nextObj); - } -} - -void ObjectClone::CompleteVtsOnDeserializedCallbacks() -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END; - - OBJECTREF nextObj = NULL, Dummy1 = NULL, Dummy2 = NULL; - - if (VDC.GetCount() == 0) - return; - - LOG((LF_REMOTING, LL_INFO1000, "CompleteVtsOnDeserializedCallbacks. Beginning.\n")); - - GCPROTECT_BEGIN(nextObj); - - while ((nextObj = VDC.Dequeue(&Dummy1, &Dummy2, NULL)) != NULL) - InvokeVtsCallbacks(nextObj, RemotingVtsInfo::VTS_CALLBACK_ON_DESERIALIZED, m_toDomain); - - GCPROTECT_END(); -} - -void ObjectClone::CompleteVtsOnSerializedCallbacks() -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END; - - OBJECTREF nextObj = NULL, Dummy1 = NULL, Dummy2 = NULL; - - if (VSC.GetCount() == 0) - return; - - LOG((LF_REMOTING, LL_INFO1000, "CompleteVtsOnSerializedCallbacks. Beginning.\n")); - - GCPROTECT_BEGIN(nextObj); - - while ((nextObj = VSC.Dequeue(&Dummy1, &Dummy2, NULL)) != NULL) - InvokeVtsCallbacks(nextObj, RemotingVtsInfo::VTS_CALLBACK_ON_SERIALIZED, m_fromDomain); - - GCPROTECT_END(); -} - -// Does a binary search to find the object with given id, and record of given kind -DWORD ObjectClone::FindObjectInTSO(int objId, SpecialObjects kind) -{ - CONTRACTL - { - MODE_COOPERATIVE; - GC_NOTRIGGER; - NOTHROW; - } - CONTRACTL_END - - DWORD lowIndex = 0; - DWORD highIndex = TSO.GetCount(); - DWORD midIndex = highIndex / 2; - DWORD firstMatch; - - if (highIndex == 0) - { - _ASSERTE(!"Special Object unexpectedly not found for given object id\n"); - return 0; // throw ? - } - - SpecialObjectInfo *splInfo = NULL; - while (true) - { - OBJECTREF refParent, refFromObj; - OBJECTREF dummy; - dummy = TSO.GetAt(midIndex, &refFromObj, &refParent, (QueuedObjectInfo **)&splInfo); - - if (objId < splInfo->GetObjectId()) - { - highIndex = midIndex; - } - else - { - if (objId == splInfo->GetObjectId()) - break; - lowIndex = midIndex; - } - - DWORD oldIndex = midIndex; - midIndex = lowIndex + (highIndex - lowIndex)/2; - if (oldIndex == midIndex) - { - // Binary search failed. See comments below - goto LinearSearch; - } - } - - // Found match at midIndex - // Find the first record for this obj id - firstMatch = midIndex; - while(midIndex != 0) - { - midIndex -= 1; - SpecialObjectInfo *pTemp; - OBJECTREF refParent, refFromObj; - OBJECTREF dummy; - dummy = TSO.GetAt(midIndex, &refFromObj, &refParent, (QueuedObjectInfo **)&pTemp); - if (pTemp->GetObjectId() != objId) - break; - else - firstMatch = midIndex; - }; - - // Now look for the right kind of record - do - { - OBJECTREF refParent, refFromObj; - OBJECTREF dummy; - dummy = TSO.GetAt(firstMatch, &refFromObj, &refParent, (QueuedObjectInfo **)&splInfo); - - if (splInfo->GetObjectId() == objId) - { - switch(kind) - { - case ISerializable: - if (splInfo->IsISerializableInstance()) - return firstMatch; - break; - case IObjectReference: - if (splInfo->IsIObjRefInstance()) - return firstMatch; - break; - case BoxedValueType: - if (splInfo->IsBoxedObject()) - return firstMatch; - break; - default: - _ASSERTE(!"Unknown enum value in FindObjectInTSO"); - }; - } - - firstMatch++; - - }while(firstMatch < TSO.GetCount()); - -LinearSearch: - // If there are multiple objects that are ISer/IObj, and some of them repeat in a certain fashion, - // then the entries in TSO are not in sorted order. In such a case binary search will fail. Lets do a linear search - // in such a case for now. This is probably reasonable since the TSO should usually be short and in-order (and presumably - // cheaper than trying to keep the list in sorted order at all times). - DWORD currIndex = 0; - for (; currIndex < TSO.GetCount(); currIndex++) - { - OBJECTREF refParent, refFromObj; - OBJECTREF dummy; - dummy = TSO.GetAt(currIndex, &refFromObj, &refParent, (QueuedObjectInfo **)&splInfo); - - SpecialObjects foundKind = ISerializable; - if (splInfo->IsIObjRefInstance()) - foundKind = IObjectReference; - else if (splInfo->IsBoxedObject()) - foundKind = BoxedValueType; - else - _ASSERTE(splInfo->IsISerializableInstance()); - - if (objId == splInfo->GetObjectId() - && kind == foundKind) - return currIndex; - } - - - _ASSERTE(!"Special Object unexpectedly not found for given object id\n"); - return 0; // throw ? -} - -// This function is effectively a replica of MethodTable::Box. Its replicated to avoid "GCPROTECT_INTERIOR" that Box uses -// and causes some leak detection asserts to go off. This is a controlled leak situation, where we know we're leaking stuff -// and dont want the asserts. -OBJECTREF ObjectClone::BoxValueTypeInWrongDomain(OBJECTREF refParent, DWORD offset, MethodTable *pValueTypeMT) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(pValueTypeMT->IsValueType()); - PRECONDITION(!pValueTypeMT->IsByRefLike()); - } - CONTRACTL_END; - - OBJECTREF ref = NULL; - void* pSrc = refParent->GetData() + offset; - GCPROTECT_BEGININTERIOR(pSrc); - - // We must enter the target domain if we are boxing a non-agile type. This of course has some overhead - // so we want to avoid it if possible. GetLoaderModule() == mscorlib && CanBeBlittedByObjectCloner is a - // conservative first approximation of agile types. - ENTER_DOMAIN_PTR_PREDICATED(m_fromDomain, ADV_RUNNINGIN, - !pValueTypeMT->GetLoaderModule()->IsSystem() || pValueTypeMT->GetClass()->CannotBeBlittedByObjectCloner()); - - ref = pValueTypeMT->FastBox(&pSrc); - - END_DOMAIN_TRANSITION; - - GCPROTECT_END(); - return ref; -} - -// Returns whether or not a given type requires VTS callbacks of the specified kind. -BOOL ObjectClone::HasVtsCallbacks(MethodTable *pMT, RemotingVtsInfo::VtsCallbackType eCallbackType) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - - while (pMT) - { - if (pMT->HasRemotingVtsInfo()) - { - PTR_RemotingVtsInfo pVtsInfo = pMT->GetRemotingVtsInfo(); - _ASSERTE(pVtsInfo != NULL); - - if (!pVtsInfo->m_pCallbacks[eCallbackType].IsNull()) - return TRUE; - } - pMT = pMT->GetParentMethodTable(); - } - - return FALSE; -} - -// Calls all of the VTS event methods for a given callback type on the object instance provided (starting at the base class). -void ObjectClone::InvokeVtsCallbacks(OBJECTREF refTarget, RemotingVtsInfo::VtsCallbackType eCallbackType, AppDomain* pDomain) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; - - GCPROTECT_BEGIN(refTarget); - - // Quickly walk the target's type hierarchy and determine the number of methods we'll need to call. - DWORD cMethods = 0; - MethodDesc *pLastCallback; - MethodTable *pMT = refTarget->GetMethodTable(); - while (pMT) - { - if (pMT->HasRemotingVtsInfo()) - { - PTR_RemotingVtsInfo pVtsInfo = pMT->GetRemotingVtsInfo(); - _ASSERTE(pVtsInfo != NULL); - - if (!pVtsInfo->m_pCallbacks[eCallbackType].IsNull()) - { - cMethods++; - -#ifdef FEATURE_PREJIT - // Might have to restore cross module method pointers. - Module::RestoreMethodDescPointer(&pVtsInfo->m_pCallbacks[eCallbackType]); -#endif - - pLastCallback = pVtsInfo->m_pCallbacks[eCallbackType].GetValue(); - } - } - pMT = pMT->GetParentMethodTable(); - } - - // Maybe there's no work to do. - if (cMethods == 0) - goto Done; - - // Allocate an array to hold the methods to invoke (we do this because the invocation order is the opposite way round from the - // way we can easily scan for the methods). We can easily optimize this for the single callback case though. - MethodDesc **pCallbacks = cMethods == 1 ? &pLastCallback : (MethodDesc**)_alloca(cMethods * sizeof(MethodDesc*)); - - if (cMethods > 1) - { - // Walk the type hierarchy again, and this time fill in the methods to call in the correct slot of our callback table. - DWORD dwSlotIndex = cMethods; - pMT = refTarget->GetMethodTable(); - while (pMT) - { - if (pMT->HasRemotingVtsInfo()) - { - PTR_RemotingVtsInfo pVtsInfo = pMT->GetRemotingVtsInfo(); - _ASSERTE(pVtsInfo != NULL); - - if (!pVtsInfo->m_pCallbacks[eCallbackType].IsNull()) - pCallbacks[--dwSlotIndex] = pVtsInfo->m_pCallbacks[eCallbackType].GetValue(); - } - pMT = pMT->GetParentMethodTable(); - } - _ASSERTE(dwSlotIndex == 0); - } - - bool fSwitchDomains = pDomain != GetAppDomain(); - - ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN); - - // If we're calling back into the from domain then reset the execution context to its original state (this will automatically be - // popped once we return from this domain again). - if (pDomain == m_fromDomain && fSwitchDomains) - { - Thread *pThread = GetThread(); - if (pThread->IsExposedObjectSet()) - { - THREADBASEREF refThread = (THREADBASEREF)pThread->GetExposedObjectRaw(); - refThread->SetExecutionContext(m_fromExecutionContext); - } - } - - // Remember to adjust this pointer for boxed value types. - BOOL bIsBoxed = refTarget->GetMethodTable()->IsValueType(); - - RuntimeMethodHandle::StreamingContextData sContext = { NULL, GetStreamingContextState() }; - - // Ensure Streamingcontext type is loaded. Do not delete this line - MethodTable *pMTStreamingContext; - pMTStreamingContext = MscorlibBinder::GetClass(CLASS__STREAMING_CONTEXT); - _ASSERTE(pMTStreamingContext); - - // Now go and call each method in order. - for (DWORD i = 0; i < cMethods; i++) - { - MethodDescCallSite callback(pCallbacks[i], &refTarget); - - ARG_SLOT argSlots[2]; - - // Nullable does not have any VTS functions - _ASSERTE(!Nullable::IsNullableType(refTarget->GetMethodTable())); - - argSlots[0] = (bIsBoxed ? (ARG_SLOT)(SIZE_T)(refTarget->UnBox()) : ObjToArgSlot(refTarget)); -#if defined(_TARGET_X86_) || defined(_TARGET_ARM_) - static_assert_no_msg(sizeof(sContext) == sizeof(ARG_SLOT)); - argSlots[1] = *(ARG_SLOT*)(&sContext); // StreamingContext is passed by value on x86 and ARM -#elif defined(_WIN64) - static_assert_no_msg(sizeof(sContext) > sizeof(ARG_SLOT)); - argSlots[1] = PtrToArgSlot(&sContext); // StreamingContext is passed by reference on WIN64 -#else // !_TARGET_X86_ && !_WIN64 && !_TARGET_ARM_ - PORTABILITY_ASSERT("ObjectClone::InvokeVtsCallbacks() - NYI on this platform"); -#endif // !_TARGET_X86_ && !_WIN64 && !_TARGET_ARM_ - - callback.CallWithValueTypes(&argSlots[0]); - } - - END_DOMAIN_TRANSITION; - -Done: ; - GCPROTECT_END(); -} - -#endif // FEATURE_REMOTING -- cgit v1.2.3 From c3eb35629731e40bf4ee826db88311f636f9ad36 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Sun, 12 Feb 2017 21:01:16 -0800 Subject: Remove dead remoting.cpp --- src/vm/amd64/remotingamd64.cpp | 672 ------- src/vm/i386/remotingx86.cpp | 225 --- src/vm/remoting.cpp | 3773 ---------------------------------------- 3 files changed, 4670 deletions(-) delete mode 100644 src/vm/amd64/remotingamd64.cpp delete mode 100644 src/vm/i386/remotingx86.cpp delete mode 100644 src/vm/remoting.cpp diff --git a/src/vm/amd64/remotingamd64.cpp b/src/vm/amd64/remotingamd64.cpp deleted file mode 100644 index 587afae124..0000000000 --- a/src/vm/amd64/remotingamd64.cpp +++ /dev/null @@ -1,672 +0,0 @@ -// 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. -/*=========================================================================== -** -** File: RemotingCpu.cpp -** -** -** -** Purpose: Defines various remoting related functions for the AMD64 architecture -** -** -** See code:EEStartup#TableOfContents for EE overview -** -=============================================================================*/ - -#include "common.h" - -#ifdef FEATURE_REMOTING - -#include "excep.h" -#include "comdelegate.h" -#include "remoting.h" -#include "field.h" -#include "siginfo.hpp" -#include "stackbuildersink.h" -#include "threads.h" -#include "method.hpp" - -#include "asmconstants.h" - -// External variables -extern DWORD g_dwNonVirtualThunkRemotingLabelOffset; -extern DWORD g_dwNonVirtualThunkReCheckLabelOffset; - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::CheckForContextMatch public -// -// Synopsis: This code generates a check to see if the current context and -// the context of the proxy match. -// -//+---------------------------------------------------------------------------- -// -// returns zero if contexts match -// returns non-zero if contexts don't match -// -extern "C" UINT_PTR __stdcall CRemotingServices__CheckForContextMatch(Object* pStubData) -{ - // This method cannot have a contract because CreateStubForNonVirtualMethod assumes - // it won't trash XMM registers. The code generated for contracts by recent compilers - // is trashing XMM registers. - STATIC_CONTRACT_NOTHROW; - STATIC_CONTRACT_GC_NOTRIGGER; - STATIC_CONTRACT_MODE_COOPERATIVE; // due to the Object parameter - STATIC_CONTRACT_SO_TOLERANT; - - UINT_PTR contextID = *(UINT_PTR*)pStubData->UnBox(); - UINT_PTR contextCur = (UINT_PTR)GetThread()->m_Context; - return (contextCur != contextID); // chosen to match x86 convention -} - - -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::CreateThunkForVirtualMethod private -// -// Synopsis: Creates the thunk that pushes the supplied slot number and jumps -// to TP Stub -// -//+---------------------------------------------------------------------------- -PCODE CTPMethodTable::CreateThunkForVirtualMethod(DWORD dwSlot, BYTE* pbCode) -{ - LIMITED_METHOD_CONTRACT; - - BYTE *pbCodeStart = pbCode; - - // NOTE: if you change the code generated here, update - // CVirtualThunkMgr::IsThunkByASM, CVirtualThunkMgr::GetMethodDescByASM - - // - // mov r10, - // mov rax, TransparentProxyStub - // jmp rax - // - *pbCode++ = 0x49; - *pbCode++ = 0xc7; - *pbCode++ = 0xc2; - *((DWORD*)pbCode) = dwSlot; - pbCode += sizeof(DWORD); - *pbCode++ = 0x48; - *pbCode++ = 0xB8; - *((UINT64*)pbCode) = (UINT64)(TransparentProxyStub); - pbCode += sizeof(UINT64); - *pbCode++ = 0xFF; - *pbCode++ = 0xE0; - - _ASSERTE(pbCode - pbCodeStart == ConstVirtualThunkSize); - _ASSERTE(CVirtualThunkMgr::IsThunkByASM((PCODE)pbCodeStart)); - - return (PCODE)pbCodeStart; -} - - -#ifdef HAS_REMOTING_PRECODE - -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::ActivatePrecodeRemotingThunk private -// -// Synopsis: Patch the precode remoting thunk to begin interception -// -//+---------------------------------------------------------------------------- -void CTPMethodTable::ActivatePrecodeRemotingThunk() -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - PORTABILITY_WARNING("CTPMethodTable::ActivatePrecodeRemotingThunk"); -} - -#else // HAS_REMOTING_PRECODE - -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::CreateStubForNonVirtualMethod public -// -// Synopsis: Create a stub for a non virtual method -// -//+---------------------------------------------------------------------------- -Stub* CTPMethodTable::CreateStubForNonVirtualMethod(MethodDesc* pMD, CPUSTUBLINKER* psl, - LPVOID pvAddrOfCode, Stub* pInnerStub) -{ - STANDARD_VM_CONTRACT; - - // Sanity check - - Stub *pStub = NULL; - - // we need a hash table only for virtual methods - _ASSERTE(!pMD->IsVirtual()); - - // Ensure the TP MethodTable's fields have been initialized. - EnsureFieldsInitialized(); - - /* - NonVirtualMethodStub - { - ;; thisReg: this - - sub rsp, 0x28 - - test thisReg, thisReg - je JmpAddrLabel - - mov rax, [thisReg] - mov r10, - cmp rax, r10 - jne JmpAddrLabel - - mov [rsp+0x30], rcx ;| - mov [rsp+0x38], rdx ;| - mov [rsp+0x40], r8 ;| - mov [rsp+0x48], r9 ;| - ;| - mov rax, [thisReg + TransparentProxyObject___stubData] ;| - call [thisReg + TransparentProxyObject___stub] ;| EmitCallToStub - ;| - mov rcx, [rsp+0x30] ;| - mov rdx, [rsp+0x38] ;| - mov r8, [rsp+0x40] ;| - mov r9, [rsp+0x48] ;| - ;| - test rax, rax ;| - jnz RemotingLabel ;| - - JmpAddrLabel: - mov rax, - add rsp, 0x28 - jmp rax - - RemotingLabel: - mov r10, - mov rax, - add rsp, 0x20 - jmp rax - } - */ - - X86Reg thisReg = kRCX; - void* pvTPStub = TransparentProxyStub_CrossContext; - - // Generate label where a null reference exception will be thrown - CodeLabel *pJmpAddrLabel = psl->NewCodeLabel(); - // Generate label where remoting code will execute - CodeLabel *pRemotingLabel = psl->NewCodeLabel(); - - // NOTE: if you change any of this code, you must update - // CNonVirtualThunkMgr::IsThunkByASM. - - // Allocate callee scratch area - // sub rsp, 0x28 - psl->X86EmitSubEsp(0x28); - - // test thisReg, thisReg - psl->X86EmitR2ROp(0x85, thisReg, thisReg); - // je JmpAddrLabel - psl->X86EmitCondJump(pJmpAddrLabel, X86CondCode::kJE); - - // Emit a label here for the debugger. A breakpoint will - // be set at the next instruction and the debugger will - // call CNonVirtualThunkMgr::TraceManager when the - // breakpoint is hit with the thread's context. - CodeLabel *pRecheckLabel = psl->NewCodeLabel(); - psl->EmitLabel(pRecheckLabel); - - // mov rax, [thisReg] - psl->X86EmitIndexRegLoad(kRAX, thisReg, 0); - - // mov r10, CTPMethodTable::GetMethodTable() - psl->X86EmitRegLoad(kR10, (UINT_PTR)CTPMethodTable::GetMethodTable()); - // cmp rax, r10 - psl->X86EmitR2ROp(0x3B, kRAX, kR10); - - // jne JmpAddrLabel - psl->X86EmitCondJump(pJmpAddrLabel, X86CondCode::kJNE); - - // CONSIDER: write all possible stubs in asm to ensure param registers are not trashed - - // mov [rsp+0x30], rcx - // mov [rsp+0x38], rdx - // mov [rsp+0x40], r8 - // mov [rsp+0x48], r9 - psl->X86EmitRegSave(kRCX, 0x30); - psl->X86EmitRegSave(kRDX, 0x38); - psl->X86EmitRegSave(kR8, 0x40); - psl->X86EmitRegSave(kR9, 0x48); - - // mov rax, [thisReg + TransparentProxyObject___stub] - psl->X86EmitIndexRegLoad(kRAX, thisReg, TransparentProxyObject___stub); - - // mov rcx, [thisReg + TransparentProxyObject___stubData] - psl->X86EmitIndexRegLoad(kRCX, thisReg, TransparentProxyObject___stubData); - - // call rax - psl->Emit16(0xd0ff); - - // mov rcx, [rsp+0x30] - // mov rdx, [rsp+0x38] - // mov r8, [rsp+0x40] - // mov r9, [rsp+0x48] - psl->X86EmitEspOffset(0x8b, kRCX, 0x30); - psl->X86EmitEspOffset(0x8b, kRDX, 0x38); - psl->X86EmitEspOffset(0x8b, kR8, 0x40); - psl->X86EmitEspOffset(0x8b, kR9, 0x48); - - // test rax, rax - psl->X86EmitR2ROp(0x85, kRAX, kRAX); - // jnz RemotingLabel - psl->X86EmitCondJump(pRemotingLabel, X86CondCode::kJNZ); - -// pJmpAddrLabel: - psl->EmitLabel(pJmpAddrLabel); - - // Make sure that the actual code does not require MethodDesc in r10 - _ASSERTE(!pMD->RequiresMethodDescCallingConvention()); - - // mov rax, - // add rsp, 0x28 - // REX.W jmp rax - psl->X86EmitTailcallWithESPAdjust(psl->NewExternalCodeLabel(pvAddrOfCode), 0x28); - -// pRemotingLabel: - psl->EmitLabel(pRemotingLabel); - - // mov r10, - psl->X86EmitRegLoad(kR10, (UINT_PTR)pMD); - - // mov rax, - // add rsp, 0x28 - // REX.W jmp rax - psl->X86EmitTailcallWithESPAdjust(psl->NewExternalCodeLabel(pvTPStub), 0x28); - - // Link and produce the stub - pStub = psl->LinkInterceptor(pMD->GetLoaderAllocator()->GetStubHeap(), - pInnerStub, pvAddrOfCode); - - return pStub; -} - - -//+---------------------------------------------------------------------------- -// -// Synopsis: Find an existing thunk or create a new one for the given -// method descriptor. NOTE: This is used for the methods that do -// not go through the vtable such as constructors, private and -// final methods. -// -//+---------------------------------------------------------------------------- -PCODE CTPMethodTable::CreateNonVirtualThunkForVirtualMethod(MethodDesc* pMD) -{ - CONTRACTL - { - STANDARD_VM_CHECK; - PRECONDITION(CheckPointer(pMD)); - } - CONTRACTL_END; - - CPUSTUBLINKER sl; - CPUSTUBLINKER* psl = &sl; - - Stub *pStub = NULL; - - // The thunk has not been created yet. Go ahead and create it. - // Compute the address of the slot - LPVOID pvEntryPoint = (LPVOID)pMD->GetMethodEntryPoint(); - - X86Reg thisReg = kRCX; - void* pvStub = CRemotingServices__DispatchInterfaceCall; - - // Generate label where a null reference exception will be thrown - CodeLabel *pExceptionLabel = psl->NewCodeLabel(); - - // !!! WARNING WARNING WARNING WARNING WARNING !!! - // - // DO NOT CHANGE this code without changing the thunk recognition - // code in CNonVirtualThunkMgr::IsThunkByASM - // & CNonVirtualThunkMgr::GetMethodDescByASM - // - // !!! WARNING WARNING WARNING WARNING WARNING !!! - - // NOTE: constant mov's should use an extended register to force a REX - // prefix and the full 64-bit immediate value, so that - // g_dwNonVirtualThunkRemotingLabelOffset and - // g_dwNonVirtualThunkReCheckLabelOffset are the same for all - // generated code. - - // if this == NULL throw NullReferenceException - // test rcx, rcx - psl->X86EmitR2ROp(0x85, thisReg, thisReg); - - // je ExceptionLabel - psl->X86EmitCondJump(pExceptionLabel, X86CondCode::kJE); - - // Generate label where remoting code will execute - CodeLabel *pRemotingLabel = psl->NewCodeLabel(); - - // Emit a label here for the debugger. A breakpoint will - // be set at the next instruction and the debugger will - // call CNonVirtualThunkMgr::TraceManager when the - // breakpoint is hit with the thread's context. - CodeLabel *pRecheckLabel = psl->NewCodeLabel(); - psl->EmitLabel(pRecheckLabel); - - // If this.MethodTable == TPMethodTable then do RemotingCall - // mov rax, [thisReg] - psl->X86EmitIndexRegLoad(kRAX, thisReg, 0); - // mov r10, CTPMethodTable::GetMethodTable() - psl->X86EmitRegLoad(kR10, (UINT_PTR)CTPMethodTable::GetMethodTable()); - // cmp rax, r10 - psl->X86EmitR2ROp(0x3B, kRAX, kR10); - // je RemotingLabel - psl->X86EmitCondJump(pRemotingLabel, X86CondCode::kJE); - - // Exception handling and non-remoting share the - // same codepath - psl->EmitLabel(pExceptionLabel); - - // Non-RemotingCode - // Jump to the vtable slot of the method - // mov rax, pvEntryPoint - // Encoded the mov manually so that it always uses the 64-bit form. - //psl->X86EmitRegLoad(kRAX, (UINT_PTR)pvEntryPoint); - psl->Emit8(REX_PREFIX_BASE | REX_OPERAND_SIZE_64BIT); - psl->Emit8(0xb8); - psl->EmitBytes((BYTE*)&pvEntryPoint, 8); - // jmp rax - psl->Emit8(0xff); - psl->Emit8(0xe0); - - // Remoting code. Note: CNonVirtualThunkMgr::TraceManager - // relies on this label being right after the jmp pvEntryPoint - // instruction above. If you move this label, update - // CNonVirtualThunkMgr::DoTraceStub. - psl->EmitLabel(pRemotingLabel); - - // Save the MethodDesc and goto TPStub - // push MethodDesc - psl->X86EmitRegLoad(kR10, (UINT_PTR)pMD); - - // jmp TPStub - psl->X86EmitNearJump(psl->NewExternalCodeLabel(pvStub)); - - // Link and produce the stub - // FUTURE: Do we have to provide the loader heap ? - pStub = psl->Link(SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()); - - // Grab the offset of the RemotingLabel and RecheckLabel - // for use in CNonVirtualThunkMgr::DoTraceStub and - // TraceManager. - DWORD dwOffset; - - dwOffset = psl->GetLabelOffset(pRemotingLabel); - ASSERT(!g_dwNonVirtualThunkRemotingLabelOffset || g_dwNonVirtualThunkRemotingLabelOffset == dwOffset); - g_dwNonVirtualThunkRemotingLabelOffset = dwOffset; - - dwOffset = psl->GetLabelOffset(pRecheckLabel); - ASSERT(!g_dwNonVirtualThunkReCheckLabelOffset || g_dwNonVirtualThunkReCheckLabelOffset == dwOffset); - g_dwNonVirtualThunkReCheckLabelOffset = dwOffset; - - return (pStub->GetEntryPoint()); -} - -#endif // HAS_REMOTING_PRECODE - -//+---------------------------------------------------------------------------- -// -// Method: CVirtualThunkMgr::DoTraceStub public -// -// Synopsis: Traces the stub given the starting address -// -//+---------------------------------------------------------------------------- -BOOL CVirtualThunkMgr::DoTraceStub(PCODE stubStartAddress, TraceDestination *trace) -{ - LIMITED_METHOD_CONTRACT; - - // implement this - return FALSE; -} - -//+---------------------------------------------------------------------------- -// -// Method: CVirtualThunkMgr::IsThunkByASM public -// -// Synopsis: Check assembly to see if this one of our thunks -// -//+---------------------------------------------------------------------------- -BOOL CVirtualThunkMgr::IsThunkByASM(PCODE startaddr) -{ - LIMITED_METHOD_CONTRACT; - - PTR_BYTE pbCode = PTR_BYTE(startaddr); - - // NOTE: this depends on the code generated by - // CTPMethodTable::CreateThunkForVirtualMethod. - - // mov r10, - return 0x49 == pbCode[0] - && 0xc7 == pbCode[1] - && 0xc2 == pbCode[2] - // mov rax, TransparentProxyStub - && 0x48 == pbCode[7] - && 0xb8 == pbCode[8] - && (TADDR)TransparentProxyStub == *PTR_TADDR(pbCode+9) - // jmp rax - && 0xff == pbCode[17] - && 0xe0 == pbCode[18]; -} - -//+---------------------------------------------------------------------------- -// -// Method: CVirtualThunkMgr::GetMethodDescByASM public -// -// Synopsis: Parses MethodDesc out of assembly code -// -//+---------------------------------------------------------------------------- -MethodDesc *CVirtualThunkMgr::GetMethodDescByASM(PCODE pbThunkCode, MethodTable *pMT) -{ - LIMITED_METHOD_CONTRACT; - - // NOTE: this depends on the code generated by - // CTPMethodTable::CreateThunkForVirtualMethod. - - return pMT->GetMethodDescForSlot(*((DWORD *) (pbThunkCode + 3))); -} - - -#ifndef HAS_REMOTING_PRECODE - -//+---------------------------------------------------------------------------- -// -// Method: CNonVirtualThunkMgr::TraceManager public -// -// Synopsis: Traces the stub given the current context -// -//+---------------------------------------------------------------------------- -BOOL CNonVirtualThunkMgr::TraceManager(Thread* thread, - TraceDestination* trace, - CONTEXT* pContext, - BYTE** pRetAddr) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(CheckPointer(thread, NULL_OK)); - PRECONDITION(CheckPointer(trace)); - PRECONDITION(CheckPointer(pContext)); - PRECONDITION(CheckPointer(pRetAddr)); - } - CONTRACTL_END; - - BOOL bRet = FALSE; - - MethodDesc * pMD = GetMethodDescByASM(GetIP(pContext) - g_dwNonVirtualThunkReCheckLabelOffset); - - LPBYTE pThis = (LPBYTE)pContext->Rcx; - - if ((pThis != NULL) && - (*(LPBYTE*)(SIZE_T)pThis == (LPBYTE)(SIZE_T)CTPMethodTable::GetMethodTable())) - { - // We know that we've got a proxy - // in the way. If the proxy is to a remote call, with no - // managed code in between, then the debugger doesn't care and - // we should just be able to return FALSE. - // - // - bRet = FALSE; - } - else - { - // No proxy in the way, so figure out where we're really going - // to and let the stub manager try to pickup the trace from - // there. - LPBYTE stubStartAddress = (LPBYTE)GetIP(pContext) - - g_dwNonVirtualThunkReCheckLabelOffset; - - // Extract the address of the destination - BYTE* pbAddr = (BYTE *)(SIZE_T)(stubStartAddress + - g_dwNonVirtualThunkRemotingLabelOffset - 2 - sizeof(void *)); - - SIZE_T destAddress = *(SIZE_T *)pbAddr; - - // Ask the stub manager to trace the destination address - bRet = StubManager::TraceStub((PCODE)(BYTE *)(size_t)destAddress, trace); - } - - // While we may have made it this far, further tracing may reveal - // that the debugger can't continue on. Therefore, since there is - // no frame currently pushed, we need to tell the debugger where - // we're returning to just in case it hits such a situtation. We - // know that the return address is on the top of the thread's - // stack. - (*pRetAddr) = *((BYTE**)(size_t)(GetSP(pContext))); - - return bRet; -} - -//+---------------------------------------------------------------------------- -// -// Method: CNonVirtualThunkMgr::DoTraceStub public -// -// Synopsis: Traces the stub given the starting address -// -//+---------------------------------------------------------------------------- -BOOL CNonVirtualThunkMgr::DoTraceStub(PCODE stubStartAddress, - TraceDestination* trace) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(stubStartAddress != NULL); - PRECONDITION(CheckPointer(trace)); - } - CONTRACTL_END; - - BOOL bRet = FALSE; - - if (!IsThunkByASM(stubStartAddress)) - return FALSE; - - CNonVirtualThunk* pThunk = FindThunk((const BYTE *)stubStartAddress); - - if(NULL != pThunk) - { - // We can either jump to - // (1) a slot in the transparent proxy table (UNMANAGED) - // (2) a slot in the non virtual part of the vtable - // ... so, we need to return TRACE_MGR_PUSH with the address - // at which we want to be called back with the thread's context - // so we can figure out which way we're gonna go. - if((const BYTE *)stubStartAddress == pThunk->GetThunkCode()) - { - trace->InitForManagerPush( - (PCODE) (stubStartAddress + g_dwNonVirtualThunkReCheckLabelOffset), - this); - bRet = TRUE; - } - } - - return bRet; -} - -//+---------------------------------------------------------------------------- -// -// Method: CNonVirtualThunkMgr::IsThunkByASM public -// -// Synopsis: Check assembly to see if this one of our thunks -// -//+---------------------------------------------------------------------------- -BOOL CNonVirtualThunkMgr::IsThunkByASM(PCODE startaddr) -{ - LIMITED_METHOD_CONTRACT; - - PTR_BYTE pbCode = PTR_BYTE(startaddr); - - // test rcx, rcx ; 3 bytes - return 0x48 == pbCode[0] - && 0x85 == pbCode[1] - && 0xc9 == pbCode[2] - // je ... ; 2 bytes - && 0x74 == pbCode[3] - // mov rax, [rcx] ; 3 bytes - // mov r10, CTPMethodTable::GetMethodTable() ; 2 bytes + MethodTable* - && (TADDR)CTPMethodTable::GetMethodTable() == *PTR_TADDR(pbCode + 10); -} - -//+---------------------------------------------------------------------------- -// -// Method: CNonVirtualThunkMgr::GetMethodDescByASM public -// -// Synopsis: Parses MethodDesc out of assembly code -// -//+---------------------------------------------------------------------------- -MethodDesc* CNonVirtualThunkMgr::GetMethodDescByASM(PCODE pbThunkCode) -{ - LIMITED_METHOD_CONTRACT; - - return *((MethodDesc **) (pbThunkCode + g_dwNonVirtualThunkRemotingLabelOffset + 2)); -} - -#endif // HAS_REMOTING_PRECODE - - -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::GenericCheckForContextMatch private -// -// Synopsis: Calls the stub in the TP & returns TRUE if the contexts -// match, FALSE otherwise. -// -// Note: 1. Called during FieldSet/Get, used for proxy extensibility -// -//+---------------------------------------------------------------------------- -BOOL __stdcall CTPMethodTable__GenericCheckForContextMatch(Object* orTP) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_COOPERATIVE; // due to the Object parameter - SO_TOLERANT; - } - CONTRACTL_END; - - Object *StubData = OBJECTREFToObject(((TransparentProxyObject*)orTP)->GetStubData()); - CTPMethodTable::CheckContextCrossingProc *pfnCheckContextCrossing = - (CTPMethodTable::CheckContextCrossingProc*)(((TransparentProxyObject*)orTP)->GetStub()); - return pfnCheckContextCrossing(StubData) == 0; -} - -#endif // FEATURE_REMOTING - - diff --git a/src/vm/i386/remotingx86.cpp b/src/vm/i386/remotingx86.cpp deleted file mode 100644 index 3a9e891267..0000000000 --- a/src/vm/i386/remotingx86.cpp +++ /dev/null @@ -1,225 +0,0 @@ -// 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. -// -// -// -// File: remotingx86.cpp -// - -// -// -// Purpose: Defines various remoting related functions for the x86 architecture -// - -// -// - -// - -#include "common.h" - -#ifdef FEATURE_REMOTING - -#include "excep.h" -#include "comdelegate.h" -#include "remoting.h" -#include "field.h" -#include "siginfo.hpp" -#include "stackbuildersink.h" -#include "threads.h" -#include "method.hpp" -#include "asmconstants.h" -#include "interoputil.h" -#include "virtualcallstub.h" - -#ifdef FEATURE_COMINTEROP -#include "comcallablewrapper.h" -#include "comcache.h" -#endif // FEATURE_COMINTEROP - -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::CreateThunkForVirtualMethod private -// -// Synopsis: Creates the thunk that pushes the supplied slot number and jumps -// to TP Stub -// -//+---------------------------------------------------------------------------- -PCODE CTPMethodTable::CreateThunkForVirtualMethod(DWORD dwSlot, BYTE *startaddr) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(CheckPointer(startaddr)); - } - CONTRACTL_END; - - BYTE *pCode = startaddr; - - // 0000 B8 67 45 23 01 MOV EAX, dwSlot - // 0005 E9 ?? ?? ?? ?? JMP TransparentProxyStub - *pCode++ = 0xB8; - *((DWORD *) pCode) = dwSlot; - pCode += sizeof(DWORD); - *pCode++ = 0xE9; - // self-relative call, based on the start of the next instruction. - *((LONG *) pCode) = (LONG)((size_t)GetTPStubEntryPoint() - (size_t) (pCode + sizeof(LONG))); - - _ASSERTE(CVirtualThunkMgr::IsThunkByASM((PCODE)startaddr)); - - return (PCODE)startaddr; -} - - -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::ActivatePrecodeRemotingThunk private -// -// Synopsis: Patch the precode remoting thunk to begin interception -// -//+---------------------------------------------------------------------------- -void CTPMethodTable::ActivatePrecodeRemotingThunk() -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - // Before activation: - // 0000 C3 ret - // 0001 90 nop - - // After activation: - // 0000 85 C9 test ecx,ecx - - // 0002 74 XX je RemotingDone - // 0004 81 39 XX XX XX XX cmp dword ptr [ecx],11111111h - // 000A 74 XX je RemotingCheck - - // Switch offset and size of patch based on the jump opcode used. - BYTE* pCode = (BYTE*)PrecodeRemotingThunk; - - SIZE_T mtOffset = 0x0006; - SIZE_T size = 0x000A; - - // Patch "ret + nop" to "test ecx,ecx" - *(UINT16 *)pCode = 0xC985; - - // Replace placeholder value with the actual address of TP method table - _ASSERTE(*(PVOID*)(pCode+mtOffset) == (PVOID*)0x11111111); - *(PVOID*)(pCode+mtOffset) = GetMethodTable(); - - FlushInstructionCache(GetCurrentProcess(), pCode, size); -} - -//+---------------------------------------------------------------------------- -// -// Method: CVirtualThunkMgr::DoTraceStub public -// -// Synopsis: Traces the stub given the starting address -// -//+---------------------------------------------------------------------------- -BOOL CVirtualThunkMgr::DoTraceStub(PCODE stubStartAddress, TraceDestination *trace) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(stubStartAddress != NULL); - PRECONDITION(CheckPointer(trace)); - } - CONTRACTL_END; - - BOOL bIsStub = FALSE; - - // Find a thunk whose code address matching the starting address - LPBYTE pThunk = FindThunk((LPBYTE)stubStartAddress); - if(NULL != pThunk) - { - LPBYTE pbAddr = NULL; - LONG destAddress = 0; - if((LPBYTE)stubStartAddress == pThunk) - { - - // Extract the long which gives the self relative address - // of the destination - pbAddr = pThunk + sizeof(BYTE) + sizeof(DWORD) + sizeof(BYTE); - destAddress = *(LONG *)pbAddr; - - // Calculate the absolute address by adding the offset of the next - // instruction after the call instruction - destAddress += (LONG)(size_t)(pbAddr + sizeof(LONG)); - - } - - // We cannot tell where the stub will end up until OnCall is reached. - // So we tell the debugger to run till OnCall is reached and then - // come back and ask us again for the actual destination address of - // the call - - Stub *stub = Stub::RecoverStub((TADDR)destAddress); - - trace->InitForFramePush(stub->GetPatchAddress()); - bIsStub = TRUE; - } - - return bIsStub; -} - -//+---------------------------------------------------------------------------- -// -// Method: CVirtualThunkMgr::IsThunkByASM public -// -// Synopsis: Check assembly to see if this one of our thunks -// -//+---------------------------------------------------------------------------- -BOOL CVirtualThunkMgr::IsThunkByASM(PCODE startaddr) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(startaddr != NULL); - } - CONTRACTL_END; - - PTR_BYTE pbCode = PTR_BYTE(startaddr); - - return ((pbCode[0] == 0xB8) && - (pbCode[5] == 0xe9) && - (rel32Decode((TADDR)(pbCode + 6)) == CTPMethodTable::GetTPStubEntryPoint())); -} - -//+---------------------------------------------------------------------------- -// -// Method: CVirtualThunkMgr::GetMethodDescByASM public -// -// Synopsis: Parses MethodDesc out of assembly code -// -//+---------------------------------------------------------------------------- -MethodDesc *CVirtualThunkMgr::GetMethodDescByASM(PCODE startaddr, MethodTable *pMT) -{ - CONTRACT (MethodDesc*) - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(startaddr != NULL); - PRECONDITION(CheckPointer(pMT)); - POSTCONDITION(CheckPointer(RETVAL)); - } - CONTRACT_END; - - RETURN (pMT->GetMethodDescForSlot(*((DWORD *) (startaddr + 1)))); -} - -#endif// FEATURE_REMOTING - diff --git a/src/vm/remoting.cpp b/src/vm/remoting.cpp deleted file mode 100644 index ee7d2cb021..0000000000 --- a/src/vm/remoting.cpp +++ /dev/null @@ -1,3773 +0,0 @@ -// 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. -// -// File: remoting.cpp -// - -// -// Purpose: Defines various remoting related objects such as -// proxies -// - -// - - -#include "common.h" - -#ifdef FEATURE_REMOTING -#include "virtualcallstub.h" -#include "excep.h" -#include "comdelegate.h" -#include "remoting.h" -#include "field.h" -#include "siginfo.hpp" -#include "stackbuildersink.h" -#include "eehash.h" -#include "profilepriv.h" -#include "message.h" -#include "eeconfig.h" -#include "comcallablewrapper.h" -#include "interopconverter.h" -#include "asmconstants.h" -#include "crossdomaincalls.h" -#include "contractimpl.h" -#include "typestring.h" -#include "generics.h" -#include "appdomain.inl" -#include "dbginterface.h" - -#ifndef DACCESS_COMPILE - -// These hold label offsets into non-virtual thunks. They are used by -// CNonVirtualThunkMgr::DoTraceStub and ::TraceManager to help the -// debugger figure out where the thunk is going to go. -DWORD g_dwNonVirtualThunkRemotingLabelOffset = 0; -DWORD g_dwNonVirtualThunkReCheckLabelOffset = 0; - -// Statics - -MethodTable *CRemotingServices::s_pMarshalByRefObjectClass; -MethodTable *CRemotingServices::s_pServerIdentityClass; - -MethodDesc *CRemotingServices::s_pRPPrivateInvoke; -MethodDesc *CRemotingServices::s_pRPInvokeStatic; -MethodDesc *CRemotingServices::s_pWrapMethodDesc; -MethodDesc *CRemotingServices::s_pIsCurrentContextOK; -MethodDesc *CRemotingServices::s_pCheckCast; -MethodDesc *CRemotingServices::s_pFieldSetterDesc; -MethodDesc *CRemotingServices::s_pFieldGetterDesc; -MethodDesc *CRemotingServices::s_pObjectGetTypeDesc; -MethodDesc *CRemotingServices::s_pGetTypeDesc; -MethodDesc *CRemotingServices::s_pProxyForDomainDesc; -MethodDesc *CRemotingServices::s_pServerContextForProxyDesc; -MethodDesc *CRemotingServices::s_pServerDomainIdForProxyDesc; -DWORD CRemotingServices::s_dwServerOffsetInRealProxy; -DWORD CRemotingServices::s_dwSrvIdentityOffsetInRealProxy; -DWORD CRemotingServices::s_dwIdOffset; -DWORD CRemotingServices::s_dwTPOrObjOffsetInIdentity; -DWORD CRemotingServices::s_dwMBRIDOffset; -DWORD CRemotingServices::s_dwLeaseOffsetInIdentity; -DWORD CRemotingServices::s_dwURIOffsetInIdentity; -CrstStatic CRemotingServices::s_RemotingCrst; -BOOL CRemotingServices::s_fRemotingStarted; -MethodDesc *CRemotingServices::s_pRenewLeaseOnCallDesc; - - -#ifdef FEATURE_COMINTEROP -MethodDesc *CRemotingServices::s_pCreateObjectForCom; -#endif - -// CTPMethodTable Statics -DWORD CTPMethodTable::s_dwCommitedTPSlots; -DWORD CTPMethodTable::s_dwReservedTPSlots; -DWORD CTPMethodTable::s_dwReservedTPIndirectionSlotSize; -DWORD CTPMethodTable::s_dwGCInfoBytes; -DWORD CTPMethodTable::s_dwMTDataSlots; -MethodTable *CTPMethodTable::s_pRemotingProxyClass; -CrstStatic CTPMethodTable::s_TPMethodTableCrst; -EEThunkHashTable *CTPMethodTable::s_pThunkHashTable; -BOOL CTPMethodTable::s_fTPTableFieldsInitialized; - -#endif // !DACCESS_COMPILE - - -SPTR_IMPL(MethodTable, CTPMethodTable, s_pThunkTable); - -#ifndef DACCESS_COMPILE - -// CVirtualThunks statics -CVirtualThunks *CVirtualThunks::s_pVirtualThunks; - -// CVirtualThunkMgr statics -CVirtualThunkMgr *CVirtualThunkMgr::s_pVirtualThunkMgr; - -#ifndef HAS_REMOTING_PRECODE -// CNonVirtualThunk statics -CNonVirtualThunk *CNonVirtualThunk::s_pNonVirtualThunks; -SimpleRWLock* CNonVirtualThunk::s_pNonVirtualThunksListLock; - -// CNonVirtualThunkMgr statics -CNonVirtualThunkMgr *CNonVirtualThunkMgr::s_pNonVirtualThunkMgr; -#endif - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::Initialize public -// -// Synopsis: Initialized remoting state -// -//+---------------------------------------------------------------------------- -VOID CRemotingServices::Initialize() -{ - STANDARD_VM_CONTRACT; - - // Initialize the remoting services critical section - s_RemotingCrst.Init(CrstRemoting, CrstFlags(CRST_REENTRANCY|CRST_HOST_BREAKABLE)); - - CTPMethodTable::Initialize(); -} - -INT32 CRemotingServices::IsTransparentProxy(Object* orTP) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_COOPERATIVE; - SO_TOLERANT; - } - CONTRACTL_END; - - INT32 fIsTPMT = FALSE; - - if(orTP != NULL) - { - // Check if the supplied object has transparent proxy method table - MethodTable *pMT = orTP->GetMethodTable(); - fIsTPMT = pMT->IsTransparentProxy() ? TRUE : FALSE; - } - - LOG((LF_REMOTING, LL_EVERYTHING, "!IsTransparentProxyEx(0x%x) returning %s", - orTP, fIsTPMT ? "TRUE" : "FALSE")); - - return(fIsTPMT); -} - - -Object* CRemotingServices::GetRealProxy(Object* objTP) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_COOPERATIVE; - SO_TOLERANT; - } - CONTRACTL_END; - - OBJECTREF rv = NULL; - - if ((objTP != NULL) && (IsTransparentProxy(objTP))) - { - _ASSERTE(s_fRemotingStarted); - rv = CTPMethodTable::GetRP(OBJECTREF(objTP)); - } - - LOG((LF_REMOTING, LL_INFO100, "!GetRealProxy(0x%x) returning 0x%x\n", objTP, OBJECTREFToObject(rv))); - - return OBJECTREFToObject(rv); -} - - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::EnsureRemotingStarted -// -// Synopsis: Startup the remoting services. -// -// -//+---------------------------------------------------------------------------- -VOID CRemotingServices::EnsureRemotingStarted() -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - if (!CRemotingServices::s_fRemotingStarted) - CRemotingServices::StartRemoting(); - - if (!CTPMethodTable::s_fTPTableFieldsInitialized) - CTPMethodTable::EnsureFieldsInitialized(); -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::StartRemoting private -// -// Synopsis: Initialize the static fields of CRemotingServices class -// -// -//+---------------------------------------------------------------------------- -VOID CRemotingServices::StartRemoting() -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - } - CONTRACTL_END; - - // Acquire the remoting lock before initializing fields - GCX_PREEMP(); - - CrstHolder ch(&s_RemotingCrst); - - // Make sure that no other thread has initialized the fields - if (!s_fRemotingStarted) - { - InitActivationServicesClass(); - InitRealProxyClass(); - InitRemotingProxyClass(); - InitIdentityClass(); - InitServerIdentityClass(); - InitMarshalByRefObjectClass(); - InitRemotingServicesClass(); - InitObjectClass(); - InitLeaseClass(); - - // ********* NOTE ************ - // This must always be the last statement in this block to prevent races - // - VolatileStore(&s_fRemotingStarted, TRUE); - // ********* END NOTE ************ - } -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::InitActivationServicesClass private -// -// Synopsis: Extract the method descriptors and fields of ActivationServices class -// -// -//+---------------------------------------------------------------------------- -VOID CRemotingServices::InitActivationServicesClass() -{ - STANDARD_VM_CONTRACT; - - s_pIsCurrentContextOK = MscorlibBinder::GetMethod(METHOD__ACTIVATION_SERVICES__IS_CURRENT_CONTEXT_OK); -#ifdef FEATURE_COMINTEROP - s_pCreateObjectForCom = MscorlibBinder::GetMethod(METHOD__ACTIVATION_SERVICES__CREATE_OBJECT_FOR_COM); -#endif -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::InitRealProxyClass private -// -// Synopsis: Extract the method descriptors and fields of Real Proxy class -// -// -//+---------------------------------------------------------------------------- -VOID CRemotingServices::InitRealProxyClass() -{ - STANDARD_VM_CONTRACT; - - // Now store the methoddesc of the PrivateInvoke method on the RealProxy class - s_pRPPrivateInvoke = MscorlibBinder::GetMethod(METHOD__REAL_PROXY__PRIVATE_INVOKE); - - // Now find the offset to the _identity field inside the - // RealProxy class - s_dwIdOffset = RealProxyObject::GetOffsetOfIdentity() - Object::GetOffsetOfFirstField(); - - s_dwServerOffsetInRealProxy = RealProxyObject::GetOffsetOfServerObject() - Object::GetOffsetOfFirstField(); - - s_dwSrvIdentityOffsetInRealProxy = RealProxyObject::GetOffsetOfServerIdentity() - Object::GetOffsetOfFirstField(); - - return; -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::InitRemotingProxyClass private -// -// Synopsis: Extract the method descriptors and fields of RemotingProxy class -// -// -//+---------------------------------------------------------------------------- -VOID CRemotingServices::InitRemotingProxyClass() -{ - STANDARD_VM_CONTRACT; - - s_pRPInvokeStatic = MscorlibBinder::GetMethod(METHOD__REMOTING_PROXY__INVOKE); - - // Note: We cannot do this inside TPMethodTable::InitializeFields .. - // that causes recursions if in some situation only the latter is called - // If you do this you will see Asserts when running any process under CorDbg - // This is because jitting of NV methods on MBR objects calls - // InitializeFields and when actually doing that we should not need to - // JIT another NV method on some MBR object. - CTPMethodTable::s_pRemotingProxyClass = MscorlibBinder::GetClass(CLASS__REMOTING_PROXY); - _ASSERTE(CTPMethodTable::s_pRemotingProxyClass); -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::InitServerIdentityClass private -// -// Synopsis: Extract the method descriptors and fields of ServerIdentity class -// -// -//+---------------------------------------------------------------------------- -VOID CRemotingServices::InitServerIdentityClass() -{ - STANDARD_VM_CONTRACT; - - s_pServerIdentityClass = MscorlibBinder::GetClass(CLASS__SERVER_IDENTITY); -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::InitIdentityClass private -// -// Synopsis: Extract the method descriptors and fields of Identity class -// -// -//+---------------------------------------------------------------------------- -VOID CRemotingServices::InitIdentityClass() -{ - STANDARD_VM_CONTRACT; - - s_dwTPOrObjOffsetInIdentity = MscorlibBinder::GetFieldOffset(FIELD__IDENTITY__TP_OR_OBJECT); - - s_dwLeaseOffsetInIdentity = MscorlibBinder::GetFieldOffset(FIELD__IDENTITY__LEASE); - - s_dwURIOffsetInIdentity = MscorlibBinder::GetFieldOffset(FIELD__IDENTITY__OBJURI); -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::InitMarshalByRefObjectClass private -// -// Synopsis: Extract the method descriptors and fields of MarshalByRefObject class -// -// -//+---------------------------------------------------------------------------- -VOID CRemotingServices::InitMarshalByRefObjectClass() -{ - STANDARD_VM_CONTRACT; - - s_pMarshalByRefObjectClass = MscorlibBinder::GetClass(CLASS__MARSHAL_BY_REF_OBJECT); - s_dwMBRIDOffset = MarshalByRefObjectBaseObject::GetOffsetOfServerIdentity() - Object::GetOffsetOfFirstField(); -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::InitRemotingServicesClass private -// -// Synopsis: Extract the method descriptors and fields of RemotingServices class -// -// -//+---------------------------------------------------------------------------- -VOID CRemotingServices::InitRemotingServicesClass() -{ - STANDARD_VM_CONTRACT; - - s_pCheckCast = MscorlibBinder::GetMethod(METHOD__REMOTING_SERVICES__CHECK_CAST); - - // Need these to call wrap/unwrap from the VM. - // Also used by JIT helpers to wrap/unwrap - s_pWrapMethodDesc = MscorlibBinder::GetMethod(METHOD__REMOTING_SERVICES__WRAP); - s_pProxyForDomainDesc = MscorlibBinder::GetMethod(METHOD__REMOTING_SERVICES__CREATE_PROXY_FOR_DOMAIN); - s_pServerContextForProxyDesc = MscorlibBinder::GetMethod(METHOD__REMOTING_SERVICES__GET_SERVER_CONTEXT_FOR_PROXY); - s_pServerDomainIdForProxyDesc = MscorlibBinder::GetMethod(METHOD__REMOTING_SERVICES__GET_SERVER_DOMAIN_ID_FOR_PROXY); - s_pGetTypeDesc = MscorlibBinder::GetMethod(METHOD__REMOTING_SERVICES__GET_TYPE); -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::InitObjectClass private -// -// Synopsis: Extract the method descriptors and fields of Object class -// -// -//+---------------------------------------------------------------------------- -VOID CRemotingServices::InitObjectClass() -{ - STANDARD_VM_CONTRACT; - - s_pFieldSetterDesc = MscorlibBinder::GetMethod(METHOD__OBJECT__FIELD_SETTER); - s_pFieldGetterDesc = MscorlibBinder::GetMethod(METHOD__OBJECT__FIELD_GETTER); - s_pObjectGetTypeDesc = MscorlibBinder::GetMethod(METHOD__OBJECT__GET_TYPE); -} - -VOID CRemotingServices::InitLeaseClass() -{ - STANDARD_VM_CONTRACT; - - s_pRenewLeaseOnCallDesc = MscorlibBinder::GetMethod(METHOD__LEASE__RENEW_ON_CALL); -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::RequiresManagedActivation private -// -// Synopsis: Determine if a config file has been parsed or if there -// are any attributes on the class that would require us -// to go into the managed activation codepath. -// -// -// Note: Called by CreateProxyOrObject (JIT_NewCrossContext) -// -//+---------------------------------------------------------------------------- -ManagedActivationType __stdcall CRemotingServices::RequiresManagedActivation(TypeHandle ty) -{ - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - SO_TOLERANT; - PRECONDITION(!ty.IsNull()); - } - CONTRACTL_END; - - MethodTable* pMT = ty.GetMethodTable(); - - PREFIX_ASSUME(pMT != NULL); - if (!pMT->MayRequireManagedActivation()) - return NoManagedActivation; - -#ifdef _DEBUG - - ManagedActivationType bManaged = NoManagedActivation; - if (pMT->IsRemotingConfigChecked()) - { - // We have done work to figure this out in the past ... - // use the cached result - bManaged = pMT->RequiresManagedActivation() ? ManagedActivation : NoManagedActivation; - } - else if (pMT->IsContextful() || pMT->GetClass()->HasRemotingProxyAttribute()) - { - // Contextful and classes that have a remoting proxy attribute - // (whether they are MarshalByRef or ContextFul) always take the slow - // path of managed activation - bManaged = ManagedActivation; - } - else - { - // If we have parsed a config file that might have configured - // this Type to be activated remotely - if (GetAppDomain()->IsRemotingConfigured()) - { - bManaged = ManagedActivation; - // We will remember if the activation is actually going - // remote based on if the managed call to IsContextOK returned us - // a proxy or not - } - -#ifdef FEATURE_COMINTEROP - else if (pMT->IsComObjectType()) - { - bManaged = ComObjectType; - } -#endif // FEATURE_COMINTEROP - - } - -#endif // _DEBUG - - if (pMT->RequiresManagedActivation()) - { - // Contextful and classes that have a remoting proxy attribute - // (whether they are MarshalByRef or ContextFul) always take the slow - // path of managed activation - _ASSERTE(bManaged == ManagedActivation); - return ManagedActivation; - } - - ManagedActivationType bMng = NoManagedActivation; - if (!pMT->IsRemotingConfigChecked()) - { - g_IBCLogger.LogMethodTableAccess(pMT); - - // If we have parsed a config file that might have configured - // this Type to be activated remotely - if (GetAppDomain()->IsRemotingConfigured()) - { - bMng = ManagedActivation; - // We will remember if the activation is actually going - // remote based on if the managed call to IsContextOK returned us - // a proxy or not - } - -#ifdef FEATURE_COMINTEROP - else if (pMT->IsComObjectType()) - { - bMng = ComObjectType; - } -#endif // FEATURE_COMINTEROP - - if (bMng == NoManagedActivation) - { - pMT->TrySetRemotingConfigChecked(); - } - } - - _ASSERTE(bManaged == bMng); - return bMng; -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::CreateProxyOrObject public -// -// Synopsis: Determine if the current context is appropriate -// for activation. If the current context is OK then it creates -// an object else it creates a proxy. -// -// -// Note: Called by JIT_NewCrossContext -// -//+---------------------------------------------------------------------------- -OBJECTREF CRemotingServices::CreateProxyOrObject(MethodTable* pMT, - BOOL fIsCom /*default:FALSE*/, BOOL fIsNewObj /*default:FALSE*/) - /* fIsCom == Did we come here through CoCreateInstance */ - /* fIsNewObj == Did we come here through Jit_NewCrossContext (newObj) */ -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pMT)); - PRECONDITION(!pMT->IsTransparentProxy()); - - // By the time we reach here, we have already checked that the class may require - // managed activation. This check is made either through the JIT_NewCrossContext helper - // or Activator.CreateInstance codepath. - PRECONDITION(pMT->MayRequireManagedActivation()); - } - CONTRACTL_END; - - // Ensure remoting has been started. - EnsureRemotingStarted(); - - // Get the address of IsCurrentContextOK in managed code - MethodDesc* pTargetMD = NULL; - Object *pServer = NULL; - -#ifdef FEATURE_COMINTEROP - if(fIsCom) - { - pTargetMD = CRemotingServices::MDofCreateObjectForCom(); - } - else -#endif // FEATURE_COMINTEROP - { - pTargetMD = CRemotingServices::MDofIsCurrentContextOK(); - } - - // Arrays are not created by JIT_NewCrossContext - _ASSERTE(!pMT->IsArray()); - - // Get the type seen by reflection - REFLECTCLASSBASEREF reflectType = (REFLECTCLASSBASEREF) pMT->GetManagedClassObject(); - LPVOID pvType = NULL; - *(REFLECTCLASSBASEREF *)&pvType = reflectType; - - // This will return either an uninitialized object or a proxy - pServer = (Object *)CTPMethodTable::CallTarget(pTargetMD, pvType, NULL, (LPVOID)(size_t)(fIsNewObj?1:0)); - - if (!pMT->IsContextful() && !pMT->IsComObjectType()) - { - // Cache the result of the activation attempt ... - // if a strictly MBR class is not configured for remote - // activation we will not go - // through this slow path next time! - // (see RequiresManagedActivation) - if (IsTransparentProxy(pServer)) - { - // Set the flag that this class is remote activate - // which means activation will go to managed code. - pMT->SetRequiresManagedActivation(); - } - else - { - // Set only the flag that no managed checks are required - // for this class next time. - pMT->SetRemotingConfigChecked(); - } - } - - LOG((LF_REMOTING, LL_INFO1000, "CreateProxyOrObject returning 0x%p\n", pServer)); - if (pMT->IsContextful()) - { - COUNTER_ONLY(GetPerfCounters().m_Context.cObjAlloc++); - } - return ObjectToOBJECTREF(pServer); -} - - -#ifndef HAS_REMOTING_PRECODE -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::GetStubForNonVirtualMethod public -// -// Synopsis: Get a stub for a non virtual method. -// -// -//+---------------------------------------------------------------------------- -Stub* CRemotingServices::GetStubForNonVirtualMethod(MethodDesc* pMD, LPVOID pvAddrOfCode, Stub* pInnerStub) -{ - CONTRACT (Stub*) - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(CheckPointer(pMD)); - PRECONDITION(CheckPointer(pvAddrOfCode)); - PRECONDITION(CheckPointer(pInnerStub, NULL_OK)); - POSTCONDITION(CheckPointer(RETVAL)); - } - CONTRACT_END; - - CPUSTUBLINKER sl; - Stub* pStub = CTPMethodTable::CreateStubForNonVirtualMethod(pMD, &sl, pvAddrOfCode, pInnerStub); - - RETURN pStub; -} -#endif // HAS_REMOTING_PRECODE - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::GetNonVirtualEntryPointForVirtualMethod public -// -// Synopsis: Get a thunk for a non-virtual call to a virtual method. -// Virtual methods do not normally get thunked in the vtable. This -// is because virtual calls use the object's vtable, and proxied objects -// would use the proxy's vtable. Hence local object (which would -// have the real vtable) can make virtual calls without going through -// the thunk. -// However, if the virtual function is called non-virtually, we have -// a problem (since this would bypass the proxy's vtable). Since this -// is not a common case, we fix it by using a stub in such cases. -// -// -//+---------------------------------------------------------------------------- -PCODE CRemotingServices::GetNonVirtualEntryPointForVirtualMethod(MethodDesc* pMD) -{ - CONTRACT (PCODE) - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(CheckPointer(pMD)); - PRECONDITION(pMD->IsRemotingInterceptedViaVirtualDispatch()); - POSTCONDITION(RETVAL != NULL); - } - CONTRACT_END; - -#ifdef HAS_REMOTING_PRECODE - RETURN pMD->GetLoaderAllocator()->GetFuncPtrStubs()->GetFuncPtrStub(pMD, PRECODE_REMOTING); -#else - GCX_PREEMP(); - RETURN *CTPMethodTable::GetOrCreateNonVirtualSlotForVirtualMethod(pMD); -#endif -} - -#ifndef HAS_REMOTING_PRECODE -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::DestroyThunk public -// -// Synopsis: Destroy the thunk for the non virtual method. -// -// -//+---------------------------------------------------------------------------- -void CRemotingServices::DestroyThunk(MethodDesc* pMD) -{ - WRAPPER_NO_CONTRACT; - - // Delegate to a helper routine - CTPMethodTable::DestroyThunk(pMD); -} -#endif // HAS_REMOTING_PRECODE - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::GetDispatchInterfaceHelper public -// -// Synopsis: Returns helper for dispatching interface call into the remoting system -// with exact MethodDesc. Used for remoting of calls on generic interfaces. -// The returned helper has MethodDesc calling convention -//+---------------------------------------------------------------------------- -PCODE CRemotingServices::GetDispatchInterfaceHelper(MethodDesc* pMD) -{ - WRAPPER_NO_CONTRACT; - - return GetEEFuncEntryPoint(CRemotingServices__DispatchInterfaceCall); -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::CheckCast public -// -// Synopsis: Checks either -// (1) If the object type supports the given interface OR -// (2) If the given type is present in the hierarchy of the -// object type -// -//+---------------------------------------------------------------------------- -BOOL CRemotingServices::CheckCast(OBJECTREF orTP, TypeHandle objTy, TypeHandle ty) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(orTP != NULL); - PRECONDITION(!objTy.IsNull()); - PRECONDITION(!ty.IsNull()); - - // Object class can never be an interface. We use a separate cached - // entry for storing interfaces that the proxy supports. - PRECONDITION(!objTy.IsInterface()); - } - CONTRACTL_END; - - // Early out if someone's trying to cast us to a type desc (such as a byref, - // array or function pointer). - if (ty.IsTypeDesc()) - return FALSE; - - BOOL fCastOK = FALSE; - - // (1) We are trying to cast to an interface - if (ty.IsInterface()) - { - // Do a quick check for interface cast by comparing it against the - // cached entry - MethodTable *pItfMT = ((TRANSPARENTPROXYREF)orTP)->GetInterfaceMethodTable(); - if (NULL != pItfMT) - { - if(pItfMT == ty.GetMethodTable()) - fCastOK = TRUE; - else - fCastOK = pItfMT->CanCastToInterface(ty.GetMethodTable()); - } - - if(!fCastOK) - fCastOK = objTy.GetMethodTable()->CanCastToInterface(ty.GetMethodTable()); - } - // (2) Everything else... - else - { - // Walk up the class hierarchy and find a matching class - while (ty != objTy) - { - if (objTy.IsNull()) - { - // Oh-oh, the cast did not succeed. Maybe we have to refine - // the proxy to match the clients view - break; - } - - // Continue searching - objTy = objTy.GetParent(); - } - - if(objTy == ty) - fCastOK = TRUE; - } - - return fCastOK; -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::CheckCast public -// -// Synopsis: Refine the type hierarchy that the proxy represents to match -// the client view. If the client is trying to cast the proxy -// to a type not supported by the server object then we -// return NULL -// -// -//+---------------------------------------------------------------------------- -BOOL CRemotingServices::CheckCast(OBJECTREF orTP, TypeHandle ty) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(orTP != NULL); - PRECONDITION(!ty.IsNull()); - } - CONTRACTL_END; - - BOOL fCastOK = FALSE; - - GCPROTECT_BEGIN(orTP); - - // Make sure the type being cast to has been restored. - ty.CheckRestore(); - - MethodTable *pMT = orTP->GetMethodTable(); - - // Make sure that we have a transparent proxy - _ASSERTE(pMT->IsTransparentProxy()); - - pMT = orTP->GetTrueMethodTable(); - - // Do a cast check without taking a lock - fCastOK = CheckCast(orTP, TypeHandle(pMT), ty); - - if (!fCastOK && !ty.IsTypeDesc()) - { - // We reach here only if any of the types in the current type hierarchy - // represented by the proxy does not match the given type. - // Call a helper routine in managed RemotingServices to find out - // whether the server object supports the given type - MethodDesc* pTargetMD = MDofCheckCast(); - fCastOK = CTPMethodTable::CheckCast(pTargetMD, (TRANSPARENTPROXYREF)orTP, ty); - } - - if (fCastOK) - { - // Do the type equivalence tests - CRealProxy::UpdateOptFlags(orTP); - } - - GCPROTECT_END(); - - LOG((LF_REMOTING, LL_INFO100, "CheckCast returning %s for object 0x%x and class 0x%x \n", (fCastOK ? "TRUE" : "FALSE"))); - - return (fCastOK); -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::FieldAccessor public -// -// Synopsis: Sets/Gets the value of the field given an instance or a proxy -// -//+---------------------------------------------------------------------------- -void CRemotingServices::FieldAccessor(FieldDesc* pFD, OBJECTREF o, LPVOID pVal, BOOL fIsGetter) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pFD)); - PRECONDITION(o != NULL); - PRECONDITION(CheckPointer(pVal, NULL_OK)); - PRECONDITION(o->IsTransparentProxy() || o->GetMethodTable()->IsMarshaledByRef()); - } - CONTRACTL_END; - - MethodTable *pMT = o->GetMethodTable(); - TypeHandle fldClass; - TypeHandle thRealObjectType; - - GCPROTECT_BEGIN(o); - GCPROTECT_BEGININTERIOR(pVal); - - // If the field descriptor type is not exact (i.e. it's a representative - // descriptor for a generic field) then we need to be more careful - // determining the properties of the field. - if (pFD->IsSharedByGenericInstantiations()) - { - // We need to resolve the field type in the context of the actual object - // it belongs to. If we've been handed a proxy we have to go grab the - // proxied type for this to work. - thRealObjectType = o->GetTrueTypeHandle(); - - // Evaluate the field signature in the type context of the parent object. - MetaSig sig(pFD, thRealObjectType); - sig.NextArg(); - fldClass = sig.GetLastTypeHandleThrowing(); - } - else - { - fldClass = pFD->GetFieldTypeHandleThrowing(); - } - - GCPROTECT_END(); - GCPROTECT_END(); - - CorElementType fieldType = fldClass.GetSignatureCorElementType(); - UINT cbSize = GetSizeForCorElementType(fieldType); - BOOL fIsGCRef = CorTypeInfo::IsObjRef(fieldType); - BOOL fIsByValue = fieldType == ELEMENT_TYPE_VALUETYPE; - - if(pMT->IsMarshaledByRef()) - { - GCX_FORBID(); - - _ASSERTE(!o->IsTransparentProxy()); - - // This is a reference to a real object. Get/Set the field value - // and return - LPVOID pFieldAddress = pFD->GetAddress((LPVOID)OBJECTREFToObject(o)); - LPVOID pDest = (fIsGetter ? pVal : pFieldAddress); - LPVOID pSrc = (fIsGetter ? pFieldAddress : pVal); - if(fIsGCRef && !fIsGetter) - { - SetObjectReference((OBJECTREF*)pDest, ObjectToOBJECTREF(*(Object **)pSrc), o->GetAppDomain()); - } - else if(fIsByValue) - { - CopyValueClass(pDest, pSrc, fldClass.AsMethodTable(), o->GetAppDomain()); - } - else - { - CopyDestToSrc(pDest, pSrc, cbSize); - } - } - else - { - // Call the managed code to start the field access call - CallFieldAccessor(pFD, o, pVal, fIsGetter, fIsByValue, fIsGCRef, thRealObjectType, fldClass, fieldType, cbSize); - } -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::CopyDestToSrc private -// -// Synopsis: Copies the specified number of bytes from the src to dest -// -// -//+---------------------------------------------------------------------------- -VOID CRemotingServices::CopyDestToSrc(LPVOID pDest, LPVOID pSrc, UINT cbSize) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(CheckPointer(pDest)); - PRECONDITION(CheckPointer(pSrc)); - } - CONTRACTL_END; - - switch (cbSize) - { - case 1: - VolatileStore((INT8*)pDest, *(INT8*)pSrc); - break; - - case 2: - VolatileStore((INT16*)pDest, *(INT16*)pSrc); - break; - - case 4: - VolatileStore((INT32*)pDest, *(INT32*)pSrc); - break; - - case 8: - VolatileStore((INT64*)pDest, *(INT64*)pSrc); - break; - - default: - UNREACHABLE(); - break; - } -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::CallFieldAccessor private -// -// Synopsis: Sets up the arguments and calls RealProxy::FieldAccessor -// -// -//+---------------------------------------------------------------------------- -VOID CRemotingServices::CallFieldAccessor(FieldDesc* pFD, - OBJECTREF o, - VOID* pVal, - BOOL fIsGetter, - BOOL fIsByValue, - BOOL fIsGCRef, - TypeHandle ty, - TypeHandle fldTy, - CorElementType fieldType, - UINT cbSize) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pFD)); - PRECONDITION(o != NULL); - PRECONDITION(CheckPointer(pVal)); - } - CONTRACTL_END; - - //****************************WARNING****************************** - // GC Protect all non-primitive variables - //***************************************************************** - - FieldArgs fieldArgs; - fieldArgs.obj = NULL; - fieldArgs.val = NULL; - fieldArgs.typeName = NULL; - fieldArgs.fieldName = NULL; - - GCPROTECT_BEGIN(fieldArgs); - GCPROTECT_BEGININTERIOR(pVal); - - fieldArgs.obj = o; - - // protect the field value if it is a gc-ref type - if(fIsGCRef) - fieldArgs.val = ObjectToOBJECTREF(*(Object **)pVal); - - - // Set up the arguments - - // Argument 1: String typeName - // Argument 2: String fieldName - // Get the type name and field name strings - GetTypeAndFieldName(&fieldArgs, pFD, ty); - - // Argument 3: Object val - OBJECTREF val = NULL; - if(!fIsGetter) - { - // If we are setting a field value then we create a variant data - // structure to hold the field value - // Extract the field from the gc protected structure if it is an object - // else use the value passed to the function - LPVOID pvFieldVal = (fIsGCRef ? (LPVOID)&(fieldArgs.val) : pVal); - // : This can cause a GC. We need some way to protect the variant - // data - OBJECTREF *lpVal = &val; - GCPROTECT_BEGININTERIOR (pvFieldVal); - CMessage::GetObjectFromStack(lpVal, &pvFieldVal, fieldType, fldTy, TRUE); - GCPROTECT_END (); - } - - // Get the method descriptor of the call - MethodDesc *pMD = (fIsGetter ? MDofFieldGetter() : MDofFieldSetter()); - - // Call the field accessor function - //////////////////////////////// GETTER /////////////////////////////////// - if(fIsGetter) - { - // Set up the return value - OBJECTREF oRet = NULL; - - GCPROTECT_BEGIN (oRet); - CRemotingServices__CallFieldGetter(pMD, - (LPVOID)OBJECTREFToObject(fieldArgs.obj), - (LPVOID)OBJECTREFToObject(fieldArgs.typeName), - (LPVOID)OBJECTREFToObject(fieldArgs.fieldName), - (LPVOID)&(oRet)); - - // If we are getting a field value then extract the field value - // based on the type of the field - if(fIsGCRef) - { - // Do a check cast to ensure that the field type and the - // return value are compatible - OBJECTREF orRet = oRet; - OBJECTREF orSaved = orRet; - if(IsTransparentProxy(OBJECTREFToObject(orRet))) - { - GCPROTECT_BEGIN(orRet); - - if(!CheckCast(orRet, fldTy)) - COMPlusThrow(kInvalidCastException, W("Arg_ObjObj")); - - orSaved = orRet; - - GCPROTECT_END(); - } - - *(OBJECTREF *)pVal = orSaved; - } - else if (fIsByValue) - { - // Copy from the source to the destination - if (oRet != NULL) - { - fldTy.GetMethodTable()->UnBoxIntoUnchecked(pVal, oRet); - } - } - else - { - if (oRet != NULL) - CopyDestToSrc(pVal, oRet->UnBox(), cbSize); - } - GCPROTECT_END (); - } - ///////////////////////// SETTER ////////////////////////////////////////// - else - { - CRemotingServices__CallFieldSetter(pMD, - (LPVOID)OBJECTREFToObject(fieldArgs.obj), - (LPVOID)OBJECTREFToObject(fieldArgs.typeName), - (LPVOID)OBJECTREFToObject(fieldArgs.fieldName), - (LPVOID)OBJECTREFToObject(val)); - } - - GCPROTECT_END(); // pVal - GCPROTECT_END(); // fieldArgs -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::GetTypeAndFieldName private -// -// Synopsis: Get the type name and field name of the -// -// -//+---------------------------------------------------------------------------- -VOID CRemotingServices::GetTypeAndFieldName(FieldArgs *pArgs, FieldDesc *pFD, TypeHandle thEnclosingClass) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pArgs)); - PRECONDITION(CheckPointer(pFD)); - } - CONTRACTL_END; - - TypeHandle thDeclaringType = !thEnclosingClass.IsNull() ? - pFD->GetExactDeclaringType(thEnclosingClass.AsMethodTable()) : pFD->GetEnclosingMethodTable(); - _ASSERTE(!thDeclaringType.IsNull()); - - // Extract the type name and field name string - // FUTURE: Put this in the reflection data structure cache TarunA 11/26/00 - StackSString ss; - TypeString::AppendType(ss, thDeclaringType, TypeString::FormatNamespace | TypeString::FormatFullInst); - pArgs->typeName = StringObject::NewString(ss); - - pArgs->fieldName = StringObject::NewString(pFD->GetName()); -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::MatchField private -// -// Synopsis: Find out whether the given field name is the same as the name -// of the field descriptor field name. -// -// -//+---------------------------------------------------------------------------- -BOOL CRemotingServices::MatchField(FieldDesc* pCurField, LPCUTF8 szFieldName) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(CheckPointer(pCurField)); - PRECONDITION(CheckPointer(szFieldName)); - } - CONTRACTL_END; - - // Get the name of the field - LPCUTF8 szCurFieldName; - if (FAILED(pCurField->GetName_NoThrow(&szCurFieldName))) - { - return FALSE; - } - - return strcmp(szCurFieldName, szFieldName) == 0; -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::Wrap public -// -// Synopsis: Wrap a contextful object to create a proxy -// Delegates to a helper method to do the actual work -// -// -//+---------------------------------------------------------------------------- -OBJECTREF CRemotingServices::Wrap(OBJECTREF obj) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } - CONTRACTL_END; - - // Basic sanity check - VALIDATEOBJECTREF(obj); - - // ******************* WARNING ******************************************** - // Do not throw any exceptions or provoke GC without setting up a frame. - // At present its the callers responsibility to setup a frame that can - // handle exceptions. - // ************************************************************************ - OBJECTREF orProxy = obj; - if(obj != NULL && (obj->GetMethodTable()->IsContextful())) - { - if(!IsTransparentProxy(OBJECTREFToObject(obj))) - { - // See if we can extract the proxy from the object - orProxy = GetProxyFromObject(obj); - if(orProxy == NULL) - { - // ask the remoting services to wrap the object - orProxy = CRemotingServices::WrapHelper(obj); - } - } - } - - return orProxy; -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::WrapHelper public -// -// Synopsis: Wrap an object to return a proxy. This function assumes that -// a fcall frame is already setup. -// -//+---------------------------------------------------------------------------- -OBJECTREF CRemotingServices::WrapHelper(OBJECTREF obj) -{ - // Basic sanity check - VALIDATEOBJECTREF(obj); - - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(obj != NULL); - PRECONDITION(!IsTransparentProxy(OBJECTREFToObject(obj))); - PRECONDITION(obj->GetMethodTable()->IsContextful()); - } - CONTRACTL_END; - - - // Default return value indicates an error - OBJECTREF newobj = NULL; - MethodDesc* pTargetMD = NULL; - - // Ensure remoting has been started. - EnsureRemotingStarted(); - - // Get the address of wrap in managed code - pTargetMD = CRemotingServices::MDofWrap(); - - // call the managed method to wrap - newobj = ObjectToOBJECTREF( (Object *)CTPMethodTable::CallTarget(pTargetMD, - (LPVOID)OBJECTREFToObject(obj), - NULL)); - - return newobj; -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::GetProxyFromObject public -// -// Synopsis: Extract the proxy from the field in the -// ContextBoundObject class -// -// -//+---------------------------------------------------------------------------- -OBJECTREF CRemotingServices::GetProxyFromObject(OBJECTREF obj) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_COOPERATIVE; - PRECONDITION(obj != NULL); - } - CONTRACTL_END; - - // Basic sanity check - VALIDATEOBJECTREF(obj); - - // We can derive a proxy for contextful types only. - _ASSERTE(obj->GetMethodTable()->IsContextful()); - - OBJECTREF srvID = (OBJECTREF)(Object*)obj->GetPtrOffset(s_dwMBRIDOffset); - OBJECTREF orProxy = NULL; - - if (srvID != NULL) - orProxy = (OBJECTREF)(Object*)srvID->GetPtrOffset(s_dwTPOrObjOffsetInIdentity); - - // This should either be null or a proxy type - _ASSERTE((orProxy == NULL) || IsTransparentProxy(OBJECTREFToObject(orProxy))); - - return orProxy; -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::IsProxyToRemoteObject public -// -// Synopsis: Check if the proxy is to a remote object -// (1) TRUE : if object is non local (ie outside this PROCESS) otherwise -// (2) FALSE -// -//+---------------------------------------------------------------------------- -BOOL CRemotingServices::IsProxyToRemoteObject(OBJECTREF obj) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(obj != NULL); - } - CONTRACTL_END; - - // Basic sanity check - VALIDATEOBJECTREF(obj); - - // If remoting is not started, for now let us just return FALSE - if(!s_fRemotingStarted) - return FALSE; - - if(!obj->IsTransparentProxy()) - return FALSE; - - // so it is a transparent proxy - AppDomain *pDomain = GetServerDomainForProxy(obj); - if(pDomain != NULL) - return TRUE; - - return FALSE; -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::GetObjectFromProxy public -// -// Synopsis: Extract the object given a proxy. -// -// -//+---------------------------------------------------------------------------- -OBJECTREF CRemotingServices::GetObjectFromProxy(OBJECTREF obj) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_COOPERATIVE; - PRECONDITION(obj != NULL); - PRECONDITION(s_fRemotingStarted); - PRECONDITION(IsTransparentProxy(OBJECTREFToObject(obj))); - SO_TOLERANT; - } - CONTRACTL_END; - - // Basic sanity check - VALIDATEOBJECTREF(obj); - - OBJECTREF oref = NULL; - if (CTPMethodTable__GenericCheckForContextMatch(OBJECTREFToObject(obj))) - { - OBJECTREF objRef = ObjectToOBJECTREF(GetRealProxy(OBJECTREFToObject(obj))); - oref = (OBJECTREF)(Object*)objRef->GetPtrOffset(s_dwServerOffsetInRealProxy); - if (oref != NULL) - obj = oref; - } - - return obj; -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::GetServerIdentityFromProxy private -// -// Synopsis: Gets the server identity (if one exists) from a proxy -// -// -// -// -//+---------------------------------------------------------------------------- -OBJECTREF CRemotingServices::GetServerIdentityFromProxy(OBJECTREF obj) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(obj != NULL); - PRECONDITION(IsTransparentProxy(OBJECTREFToObject(obj))); - } - CONTRACTL_END; - - - // Extract the real proxy underlying the transparent proxy - OBJECTREF pObj = ObjectToOBJECTREF(GetRealProxy(OBJECTREFToObject(obj))); - - OBJECTREF id = NULL; - - // Extract the identity object - pObj = (OBJECTREF)(Object*)pObj->GetPtrOffset(s_dwIdOffset); - - // Extract the _identity from the real proxy only if it is an instance of - // remoting proxy - if((pObj != NULL) && IsInstanceOfServerIdentity(pObj->GetMethodTable())) - id = pObj; - - return id; -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::GetServerDomainForProxy public -// -// Synopsis: Returns the AppDomain corresponding to the server -// if the proxy and the server are in the same process. -// -// -//+---------------------------------------------------------------------------- -AppDomain *CRemotingServices::GetServerDomainForProxy(OBJECTREF proxy) -{ - CONTRACT (AppDomain*) - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(proxy != NULL); - POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); - } - CONTRACT_END; - - // call the managed method - Context *pContext = (Context *)GetServerContextForProxy(proxy); - if (pContext) - RETURN pContext->GetDomain(); - else - RETURN NULL; -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::GetServerDomainIdForProxy public -// -// Synopsis: Returns the AppDomain ID corresponding to the server -// if the proxy and the server are in the same process. -// Returns 0 if it cannot determine. -// -// -//+---------------------------------------------------------------------------- -int CRemotingServices::GetServerDomainIdForProxy(OBJECTREF proxy) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(proxy != NULL); - PRECONDITION(IsTransparentProxy(OBJECTREFToObject(proxy))); - } - CONTRACTL_END; - - // Get the address of GetDomainIdForProxy in managed code - MethodDesc* pTargetMD = CRemotingServices::MDofGetServerDomainIdForProxy(); - - // This will just read the appDomain ID from the marshaled data - // for the proxy. It returns 0 if the proxy is to a server in another - // process. It may also return 0 if it cannot determine the server - // domain ID (eg. for Well Known Object proxies). - - // call the managed method - // This cast to Int32 actually causes a potential loss - // of data. - return (int)(INT_PTR)CTPMethodTable::CallTarget( - pTargetMD, - (LPVOID)OBJECTREFToObject(proxy), - NULL); -} - - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::GetServerContextForProxy public -// -// Synopsis: Returns the AppDomain corresponding to the server -// if the proxy and the server are in the same process. -// -// -//+---------------------------------------------------------------------------- -Context *CRemotingServices::GetServerContextForProxy(OBJECTREF proxy) -{ - CONTRACT (Context*) - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(proxy != NULL); - PRECONDITION(IsTransparentProxy(OBJECTREFToObject(proxy))); - POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); - } - CONTRACT_END; - - // Get the address of GetAppDomainForProxy in managed code - MethodDesc* pTargetMD = CRemotingServices::MDofGetServerContextForProxy(); - - // This will return the correct VM Context object for the server if - // the proxy is true cross domain proxy to a server in another domain - // in the same process. The managed method will Assert if called on a proxy - // which is either half-built or does not have an ObjRef ... which may - // happen for eg. if the proxy and the server are in the same appdomain. - - // we return NULL if the server object for the proxy is in another - // process or if the appDomain for the server is invalid or if we cannot - // determine the context (eg. well known object proxies). - - // call the managed method - RETURN (Context *)CTPMethodTable::CallTarget( - pTargetMD, - (LPVOID)OBJECTREFToObject(proxy), - NULL); -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::CreateProxyForDomain public -// -// Synopsis: Create a proxy for the app domain object by calling marshal -// inside the newly created domain and unmarshaling in the old -// domain -// -// -//+---------------------------------------------------------------------------- -OBJECTREF CRemotingServices::CreateProxyForDomain(AppDomain* pDomain) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pDomain)); - } - CONTRACTL_END; - - // Ensure remoting has been started. - EnsureRemotingStarted(); - - MethodDesc* pTargetMD = MDOfCreateProxyForDomain(); - - // Call the managed method which will marshal and unmarshal the - // appdomain object to create the proxy - - // We pass the ContextID of the default context of the new appDomain - // object. This helps the boot-strapping! (i.e. entering the new domain - // to marshal itself out). - - Object *proxy = (Object *)CTPMethodTable::CallTarget( - pTargetMD, - (LPVOID)(DWORD_PTR)pDomain->GetId().m_dwId, - (LPVOID)pDomain->GetDefaultContext()); - return ObjectToOBJECTREF(proxy); -} - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::GetClass public -// -// Synopsis: Extract the true class of the object whose proxy is given. -// -// -// -//+---------------------------------------------------------------------------- -REFLECTCLASSBASEREF CRemotingServices::GetClass(OBJECTREF pThis) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM()); - PRECONDITION(pThis != NULL); - } - CONTRACTL_END; - - REFLECTCLASSBASEREF refClass = NULL; - MethodTable *pMT = NULL; - - GCPROTECT_BEGIN(pThis); - - // For proxies to objects in the same appdomain, we always know the - // correct type - if(GetServerIdentityFromProxy(pThis) != NULL) - { - pMT = pThis->GetTrueMethodTable(); - } - else - { - // For everything else either we have refined the proxy to its correct type - // or we have to consult the objref to get the true type - - MethodDesc* pTargetMD = CRemotingServices::MDofGetType(); - - refClass = (REFLECTCLASSBASEREF)(ObjectToOBJECTREF((Object *)CTPMethodTable::CallTarget(pTargetMD, - (LPVOID)OBJECTREFToObject(pThis), NULL))); - - if(refClass == NULL) - { - // There was no objref associated with the proxy or it is a proxy - // that we do not understand. - // In this case, we return the class that is stored in the proxy - pMT = pThis->GetTrueMethodTable(); - } - - _ASSERTE(refClass != NULL || pMT != NULL); - - // Refine the proxy to the class just retrieved - if(refClass != NULL) - { - CTPMethodTable::RefineProxy((TRANSPARENTPROXYREF)pThis, refClass->GetType()); - } - } - - if (refClass == NULL) - { - PREFIX_ASSUME(pMT != NULL); - refClass = (REFLECTCLASSBASEREF)pMT->GetManagedClassObject(); - } - - GCPROTECT_END(); - - _ASSERTE(refClass != NULL); - return refClass; -} - -//+---------------------------------------------------------------------------- -// -// Method: CRealProxy::SetStubData public -// -// Synopsis: Set the stub data in the transparent proxy -// -//+---------------------------------------------------------------------------- -FCIMPL2(VOID, CRealProxy::SetStubData, Object* orRPUNSAFE, Object* orStubDataUNSAFE) -{ - CONTRACTL - { - FCALL_CHECK; - } - CONTRACTL_END; - - BOOL fThrow = FALSE; - REALPROXYREF orRP = (REALPROXYREF)ObjectToOBJECTREF(orRPUNSAFE); - OBJECTREF orStubData = ObjectToOBJECTREF(orStubDataUNSAFE); - - if (orRP != NULL && orStubData != NULL) - { - TRANSPARENTPROXYREF orTP = orRP->GetTransparentProxy(); - if (orTP != NULL) - { - orTP->SetStubData(orStubData); - } - else - { - fThrow = TRUE; - } - } - else - { - fThrow = TRUE; - } - - if(fThrow) - FCThrowVoid(kArgumentNullException); -} -FCIMPLEND - -//+---------------------------------------------------------------------------- -// -// Method: CRealProxy::GetStubData public -// -// Synopsis: Get the stub data in the transparent proxy -// -//+---------------------------------------------------------------------------- -FCIMPL1(Object*, CRealProxy::GetStubData, Object* orRPUNSAFE) -{ - CONTRACTL - { - FCALL_CHECK; - } - CONTRACTL_END; - - BOOL fThrow = FALSE; - REALPROXYREF orRP = (REALPROXYREF)ObjectToOBJECTREF(orRPUNSAFE); - OBJECTREF orRet = NULL; - - if (orRP != NULL) - { - TRANSPARENTPROXYREF orTP = orRP->GetTransparentProxy(); - if (orTP != NULL) - orRet = orTP->GetStubData(); - else - fThrow = TRUE; - } - else - { - fThrow = TRUE; - } - - if(fThrow) - FCThrow(kArgumentNullException); - - return OBJECTREFToObject(orRet); -} -FCIMPLEND - -//+---------------------------------------------------------------------------- -// -// Method: CRealProxy::GetDefaultStub public -// -// Synopsis: Get the default stub implemented by us which matches contexts -// -//+---------------------------------------------------------------------------- -FCIMPL0(LPVOID, CRealProxy::GetDefaultStub) -{ - FCALL_CONTRACT; - - return (LPVOID)CRemotingServices__CheckForContextMatch; -} -FCIMPLEND - -//+---------------------------------------------------------------------------- -// -// Method: CRealProxy::GetStub public -// -// Synopsis: Get the stub pointer in the transparent proxy -// -//+---------------------------------------------------------------------------- -FCIMPL1(LPVOID, CRealProxy::GetStub, Object* orRPUNSAFE) -{ - CONTRACTL - { - FCALL_CHECK; - PRECONDITION(CheckPointer(orRPUNSAFE)); - } - CONTRACTL_END; - - REALPROXYREF orRP = (REALPROXYREF)ObjectToOBJECTREF(orRPUNSAFE); - TRANSPARENTPROXYREF orTP = orRP->GetTransparentProxy(); - - return orTP->GetStub(); -} -FCIMPLEND - -//+---------------------------------------------------------------------------- -// -// Method: CRealProxy::GetProxiedType public -// -// Synopsis: Get the type that is represented by the transparent proxy -// -//+---------------------------------------------------------------------------- -FCIMPL1(Object*, CRealProxy::GetProxiedType, Object* orRPUNSAFE) -{ - FCALL_CONTRACT; - - REFLECTCLASSBASEREF refClass = NULL; - REALPROXYREF orRP = (REALPROXYREF)ObjectToOBJECTREF(orRPUNSAFE); - HELPER_METHOD_FRAME_BEGIN_RET_1(orRP); - - TRANSPARENTPROXYREF orTP = orRP->GetTransparentProxy(); - - refClass = CRemotingServices::GetClass(orTP); - _ASSERTE(refClass != NULL); - - HELPER_METHOD_FRAME_END(); - return OBJECTREFToObject(refClass); -} -FCIMPLEND - -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::Initialize public -// -// Synopsis: Initialized data structures needed for managing tranparent -// proxies -// -//+---------------------------------------------------------------------------- -VOID CTPMethodTable::Initialize() -{ - STANDARD_VM_CONTRACT; - - s_TPMethodTableCrst.Init(CrstTPMethodTable); -} - -//+---------------------------------------------------------------------------- - -PCODE CTPMethodTable::GetTPStubEntryPoint() -{ - LIMITED_METHOD_CONTRACT; - return GetEEFuncEntryPoint(TransparentProxyStub); -} - -PCODE CTPMethodTable::GetDelegateStubEntryPoint() -{ - LIMITED_METHOD_CONTRACT; - return GetEEFuncEntryPoint(TransparentProxyStub_CrossContext); -} - -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::EnsureFieldsInitialized private -// -// Synopsis: Initialize the static fields of CTPMethodTable class -// and the thunk manager classes -// -// -//+---------------------------------------------------------------------------- -void CTPMethodTable::EnsureFieldsInitialized() -{ - CONTRACT_VOID - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - POSTCONDITION(s_fTPTableFieldsInitialized); - } - CONTRACT_END; - - if (!s_fTPTableFieldsInitialized) - { - GCX_PREEMP(); - - // Load Tranparent proxy class (do this before we enter the critical section) - MethodTable* pTPMT = MscorlibBinder::GetClass(CLASS__TRANSPARENT_PROXY); - _ASSERTE(pTPMT->IsTransparentProxy()); - - CrstHolder ch(&s_TPMethodTableCrst); - - if(!s_fTPTableFieldsInitialized) - { - // Obtain size of GCInfo stored above the method table - CGCDesc *pGCDesc = CGCDesc::GetCGCDescFromMT(pTPMT); - BYTE *pGCTop = (BYTE *) pGCDesc->GetLowestSeries(); - s_dwGCInfoBytes = (DWORD)(((BYTE *) pTPMT) - pGCTop); - _ASSERTE((s_dwGCInfoBytes & 3) == 0); - - // Obtain the number of bytes to be copied for creating the TP - // method tables containing thunks - _ASSERTE(((s_dwGCInfoBytes + sizeof(MethodTable)) & (sizeof(PCODE)-1)) == 0); - s_dwMTDataSlots = ((s_dwGCInfoBytes + sizeof(MethodTable)) / sizeof(PCODE)); - _ASSERTE(sizeof(MethodTable) == MethodTable::GetVtableOffset()); - - // We rely on the number of interfaces implemented by the - // Transparent proxy being 0, so that InterfaceInvoke hints - // fail and trap to InnerFailStub which also fails and - // in turn traps to FailStubWorker. In FailStubWorker, we - // determine the class being proxied and return correct slot. - _ASSERTE(pTPMT->GetNumInterfaces() == 0); - - CVirtualThunkMgr::InitVirtualThunkManager(); - - // Create the global thunk table and set the cycle between - // the transparent proxy class and the global thunk table - CreateTPMethodTable(pTPMT); - -#ifdef HAS_REMOTING_PRECODE - // Activate the remoting precode helper - ActivatePrecodeRemotingThunk(); -#endif // HAS_REMOTING_PRECODE - - // NOTE: This must always be the last statement in this block - // to prevent races - // Load Tranparent proxy class - s_fTPTableFieldsInitialized = TRUE; - } - } - - RETURN; -} - -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::GetRP public -// -// Synopsis: Get the real proxy backing the transparent proxy -// -//+---------------------------------------------------------------------------- -REALPROXYREF CTPMethodTable::GetRP(OBJECTREF orTP) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_COOPERATIVE; - PRECONDITION(orTP != NULL); - PRECONDITION(orTP->IsTransparentProxy()); - SO_TOLERANT; - } - CONTRACTL_END; - - return (REALPROXYREF)(((TRANSPARENTPROXYREF)orTP)->GetRealProxy()); -} - -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::GetMethodTableBeingProxied public -// -// Synopsis: Get the real type backing the transparent proxy -// -//+---------------------------------------------------------------------------- -MethodTable * CTPMethodTable::GetMethodTableBeingProxied(OBJECTREF orTP) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_COOPERATIVE; - SO_TOLERANT; - PRECONDITION(orTP != NULL); - PRECONDITION(orTP->IsTransparentProxy()); - } - CONTRACTL_END; - - return ((TRANSPARENTPROXYREF)orTP)->GetMethodTableBeingProxied(); -} - -#define PAGE_ROUND_UP(cb) (((cb) + g_SystemInfo.dwAllocationGranularity) & ~(g_SystemInfo.dwAllocationGranularity - 1)) - -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::CreateTPMethodTable private -// -// Synopsis: (1) Reserves a transparent proxy method table that is large -// enough to support the largest vtable -// (2) Commits memory for the GC info of the global thunk table and -// sets the cycle between the transparent proxy class and the -// globale thunk table. -// -//+---------------------------------------------------------------------------- - -void CTPMethodTable::CreateTPMethodTable(MethodTable* pTPMT) -{ - CONTRACT_VOID { - THROWS; - GC_NOTRIGGER; - MODE_ANY; - POSTCONDITION(CheckPointer(s_pThunkTable)); - } CONTRACT_END; - - // The largest possible vtable size 64K - DWORD dwMaxSlots = 64*1024; - - // Allocate virtual memory that is big enough to hold a method table - // of the maximum possible size - DWORD dwReserveSize = 0; - DWORD dwMethodTableReserveSize = (DWORD)(s_dwMTDataSlots * sizeof(PCODE)); - s_dwReservedTPIndirectionSlotSize = MethodTable::GetNumVtableIndirections(dwMaxSlots) * sizeof(PTR_PCODE); - dwMethodTableReserveSize += s_dwReservedTPIndirectionSlotSize; - - dwMethodTableReserveSize += (DWORD)(dwMaxSlots * sizeof(PCODE)); - dwReserveSize = PAGE_ROUND_UP(dwMethodTableReserveSize); - - void *pAlloc = ::ClrVirtualAlloc(0, dwReserveSize, MEM_RESERVE | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE); - - if (pAlloc) - { - BOOL bFailed = TRUE; - - // Make sure that we have not created the one and only - // transparent proxy method table before - _ASSERTE(NULL == s_pThunkTable); - - // Commit the required amount of memory - DWORD dwCommitSize = 0; - - // MethodTable memory - DWORD dwMethodTableCommitSize = (s_dwMTDataSlots) * sizeof(PCODE); - if (!ClrSafeInt::addition(0, dwMethodTableCommitSize, dwCommitSize)) - { - COMPlusThrowHR(COR_E_OVERFLOW); - } - - if (::ClrVirtualAlloc(pAlloc, dwCommitSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) - { - // Copy the fixed portion from the true TP Method Table - memcpy(pAlloc,MTToAlloc(pTPMT, s_dwGCInfoBytes), (dwMethodTableCommitSize)); - - // Initialize the transparent proxy method table - InitThunkTable(0, dwMaxSlots, AllocToMT((BYTE *) pAlloc, s_dwGCInfoBytes)); - - // At this point the transparent proxy class points to the - // the true TP Method Table and not the transparent - // proxy method table. We do not use the true method table - // any more. Instead we use the transparent proxy method table - // for allocating transparent proxies. So, we have to make the - // transparent proxy class point to the one and only transparent - // proxy method table - pTPMT->GetClass()->SetMethodTableForTransparentProxy(s_pThunkTable); - - // Allocate the slots of the Object class method table because - // we can reflect on the __Transparent proxy class even though - // we never intend to use remoting. - _ASSERTE(NULL != g_pObjectClass); - _ASSERTE(0 == GetCommitedTPSlots()); - if(ExtendCommitedSlots(g_pObjectClass->GetNumMethods())) - bFailed = FALSE; - } - else - { - ClrVirtualFree(pAlloc, 0, MEM_RELEASE); - } - - if(bFailed) - DestroyThunkTable(); - } - else { - if (pAlloc != NULL) - ::ClrVirtualFree(pAlloc, 0, MEM_RELEASE); - } - - // Note that the thunk table is set to null on any failure path - // via DestroyThunkTable - if (!s_pThunkTable) - COMPlusThrowOM(); - - RETURN; -} - -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::ExtendCommitedSlots private -// -// Synopsis: Extends the commited slots of transparent proxy method table to -// the desired number -// -//+---------------------------------------------------------------------------- -BOOL CTPMethodTable::ExtendCommitedSlots(_In_range_(1,64*1024) DWORD dwSlots) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - INJECT_FAULT(return FALSE); - PRECONDITION(s_dwCommitedTPSlots <= dwSlots); - PRECONDITION(dwSlots <= s_dwReservedTPSlots); - PRECONDITION((CVirtualThunks::GetVirtualThunks() == NULL) || - (s_dwCommitedTPSlots == CVirtualThunks::GetVirtualThunks()->_dwCurrentThunk)); - - // Either we have initialized everything or we are asked to allocate - // some slots during initialization - PRECONDITION(s_fTPTableFieldsInitialized || (0 == s_dwCommitedTPSlots)); - } - CONTRACTL_END; - - // Commit memory for TPMethodTable - BOOL bAlloc = FALSE; - void *pAlloc = MTToAlloc(s_pThunkTable, s_dwGCInfoBytes); - ClrSafeInt dwCommitSize; - dwCommitSize += s_dwMTDataSlots * sizeof(PCODE); - dwCommitSize += MethodTable::GetNumVtableIndirections(dwSlots) * sizeof(PTR_PCODE); - - DWORD dwLastIndirectionSlot = s_pThunkTable->GetIndexOfVtableIndirection(s_pThunkTable->GetNumVirtuals() - 1); - DWORD dwSlotsCommitSize = dwSlots * sizeof(PCODE); - PCODE *pAllocSlots = (PCODE*)(((BYTE*)s_pThunkTable) + s_dwMTDataSlots * sizeof(PCODE) + s_dwReservedTPIndirectionSlotSize); - - if (dwCommitSize.IsOverflow()) - { - return FALSE; // error condition - } - - if (::ClrVirtualAlloc(pAlloc, dwCommitSize.Value(), MEM_COMMIT, PAGE_EXECUTE_READWRITE) && - ::ClrVirtualAlloc(pAllocSlots, dwSlotsCommitSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) - { - _ASSERTE(FitsIn(dwSlots)); - s_pThunkTable->SetNumVirtuals((WORD)dwSlots); - - MethodTable::VtableIndirectionSlotIterator it = s_pThunkTable->IterateVtableIndirectionSlotsFrom(dwLastIndirectionSlot); - do - { - it.SetIndirectionSlot(&pAllocSlots[it.GetStartSlot()]); - } - while (it.Next()); - - bAlloc = AllocateThunks(dwSlots, dwCommitSize.Value()); - } - - return bAlloc; -} - -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::AllocateThunks private -// -// Synopsis: Allocates the desired number of thunks for virtual methods -// -//+---------------------------------------------------------------------------- -BOOL CTPMethodTable::AllocateThunks(DWORD dwSlots, DWORD dwCommitSize) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - } - CONTRACTL_END; - // Check for existing thunks - DWORD dwCommitThunks = 0; - DWORD dwAllocThunks = dwSlots; - MethodTable *pThunkTable = s_pThunkTable; - - CVirtualThunks* pThunks = CVirtualThunks::GetVirtualThunks(); - if (pThunks) - { - // Compute the sizes of memory to be commited and allocated - BOOL fCommit; - if (dwSlots < pThunks->_dwReservedThunks) - { - fCommit = TRUE; - dwCommitThunks = dwSlots; - dwAllocThunks = 0; - } - else - { - fCommit = (pThunks->_dwCurrentThunk != pThunks->_dwReservedThunks); - dwCommitThunks = pThunks->_dwReservedThunks; - dwAllocThunks = dwSlots - pThunks->_dwReservedThunks; - } - - // Commit memory if needed - if (fCommit) - { - DWORD dwCommitSizeTmp = (sizeof(CVirtualThunks) - ConstVirtualThunkSize) + - ((dwCommitThunks - pThunks->_dwStartThunk) * ConstVirtualThunkSize); - - if (!::ClrVirtualAlloc(pThunks, dwCommitSizeTmp, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) - return(NULL); - - // Generate thunks that push slot number and jump to TP stub - DWORD dwStartSlot = pThunks->_dwStartThunk; - DWORD dwCurrentSlot = pThunks->_dwCurrentThunk; - while (dwCurrentSlot < dwCommitThunks) - { - PCODE pCode = CreateThunkForVirtualMethod(dwCurrentSlot, (BYTE *)&pThunks->ThunkCode[dwCurrentSlot-dwStartSlot]); - pThunkTable->SetSlot(dwCurrentSlot, pCode); - ++dwCurrentSlot; - } - - ClrFlushInstructionCache(&pThunks->ThunkCode[pThunks->_dwCurrentThunk-dwStartSlot], - (dwCommitThunks-pThunks->_dwCurrentThunk)*ConstVirtualThunkSize); - - s_dwCommitedTPSlots = dwCommitThunks; - pThunks->_dwCurrentThunk = dwCommitThunks; - } - } - - // - // Check for the avialability of a TP method table that is no longer being - // reused - - // Allocate memory if necessary - if (dwAllocThunks) - { - DWORD dwReserveSize = ((sizeof(CVirtualThunks) - ConstVirtualThunkSize) + - ((dwAllocThunks << 1) * ConstVirtualThunkSize) + - g_SystemInfo.dwAllocationGranularity) & ~((size_t) g_SystemInfo.dwAllocationGranularity - 1); - - void *pAlloc = ::ClrVirtualAlloc(0, dwReserveSize, - MEM_RESERVE | MEM_TOP_DOWN, - PAGE_EXECUTE_READWRITE); - if (pAlloc) - { - // Commit the required amount of memory - DWORD dwCommitSizeTmp = (sizeof(CVirtualThunks) - ConstVirtualThunkSize) + - (dwAllocThunks * ConstVirtualThunkSize); - - if (::ClrVirtualAlloc(pAlloc, dwCommitSizeTmp, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) - { - ((CVirtualThunks *) pAlloc)->_pNext = pThunks; - pThunks = CVirtualThunks::SetVirtualThunks((CVirtualThunks *) pAlloc); - pThunks->_dwReservedThunks = (dwReserveSize - - (sizeof(CVirtualThunks) - ConstVirtualThunkSize)) / - ConstVirtualThunkSize; - pThunks->_dwStartThunk = dwCommitThunks; - pThunks->_dwCurrentThunk = dwCommitThunks; - - // Generate thunks that push slot number and jump to TP stub - DWORD dwStartSlot = pThunks->_dwStartThunk; - DWORD dwCurrentSlot = pThunks->_dwCurrentThunk; - while (dwCurrentSlot < dwSlots) - { - PCODE pCode = CreateThunkForVirtualMethod(dwCurrentSlot, (BYTE *)&pThunks->ThunkCode[dwCurrentSlot-dwStartSlot]); - pThunkTable->SetSlot(dwCurrentSlot, pCode); - ++dwCurrentSlot; - } - - ClrFlushInstructionCache(&pThunks->ThunkCode[pThunks->_dwCurrentThunk-dwStartSlot], - (dwSlots-pThunks->_dwCurrentThunk)*ConstVirtualThunkSize); - - s_dwCommitedTPSlots = dwSlots; - pThunks->_dwCurrentThunk = dwSlots; - } - else - { - ::ClrVirtualFree(pAlloc, 0, MEM_RELEASE); - return FALSE; - } - } - else - { - return FALSE; - } - } - - return TRUE; -} - -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::CreateTPOfClassForRP private -// -// Synopsis: Creates a transparent proxy that behaves as an object of the -// supplied class -// -//+---------------------------------------------------------------------------- -void CTPMethodTable::CreateTPOfClassForRP(TypeHandle ty, REALPROXYREF *pRP, TRANSPARENTPROXYREF *pTP) -{ - CONTRACT_VOID - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM()); - PRECONDITION(!ty.IsNull()); - PRECONDITION(pRP != NULL); - PRECONDITION(*pRP != NULL); - PRECONDITION(pTP != NULL); - POSTCONDITION(*pTP != NULL); - } - CONTRACT_END; - - // Ensure remoting is started. - EnsureFieldsInitialized(); - - MethodTable * pMT = ty.GetMethodTable(); - - // Get the size of the VTable for the class to proxy - DWORD dwSlots = pMT->GetNumVirtuals(); - - if (dwSlots == 0) - dwSlots = 1; - - // The global thunk table must have been initialized - _ASSERTE(s_pThunkTable != NULL); - - // Check for the need to extend existing TP method table - if (dwSlots > GetCommitedTPSlots()) - { - CrstHolder ch(&s_TPMethodTableCrst); - - if (dwSlots > GetCommitedTPSlots()) - { - if (!ExtendCommitedSlots(dwSlots)) - COMPlusThrowOM(); - } - } - - // Create a TP Object - IfNullThrow(*pTP = (TRANSPARENTPROXYREF) AllocateObject(GetMethodTable())); - - // Create the cycle between TP and RP - (*pRP)->SetTransparentProxy(*pTP); - - // Make the TP behave as an object of supplied class - (*pTP)->SetRealProxy(*pRP); - - // If we are creating a proxy for an interface then the class - // is the object class else it is the class supplied - if (pMT->IsInterface()) - { - _ASSERTE(NULL != g_pObjectClass); - - (*pTP)->SetMethodTableBeingProxied(CRemotingServices::GetMarshalByRefClass()); - - // Set the cached interface method table to the given interface - // method table - (*pTP)->SetInterfaceMethodTable(pMT); - } - else - { - (*pTP)->SetMethodTableBeingProxied(pMT); - } - - RETURN; -} - -Signature InitMessageData(messageData *msgData, - FramedMethodFrame *pFrame, - Module **ppModule, - SigTypeContext *pTypeContext) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(msgData)); - PRECONDITION(CheckPointer(pFrame)); - PRECONDITION(CheckPointer(ppModule)); - PRECONDITION(CheckPointer(pTypeContext)); - } - CONTRACTL_END; - - msgData->pFrame = pFrame; - msgData->iFlags = 0; - - MethodDesc *pMD = pFrame->GetFunction(); - _ASSERTE(!pMD->ContainsGenericVariables()); - _ASSERTE(pMD->IsRuntimeMethodHandle()); - - TypeHandle thGoverningType; - BOOL fIsDelegate = pMD->GetMethodTable()->IsDelegate(); - - // We want to calculate and store a governing type for the method since - // sometimes the parent method table might be representative. We get the - // exact type context from the this reference we're calling on (adjusting - // for the fact it's a TP). - - // But cope with the common cases first for speed: - // * If the method is not on a generic type and this is not the async - // delegate case (which requires us to unwrap the delegate and have a - // look) then we know the method desc's parent method table will be exact. - // * We require method descs to be exact for the interface case as well (since - // the target object doesn't help us resolve the interface type at all). - // * COM interop can use this code path, but that doesn't support generics so - // we can use the quick logic for that too. - if ((!pMD->HasClassInstantiation() && !fIsDelegate) || - pMD->IsInterface() || - pMD->IsComPlusCall()) - { - thGoverningType = TypeHandle(pMD->GetMethodTable()); - } - else - { - MethodDesc *pTargetMD; - MethodTable *pTargetMT; - if (fIsDelegate) - { - // Async delegates are also handled differently in that the method and the - // this are delegate wrappers round the real method and target. - pTargetMD = COMDelegate::GetMethodDesc(pFrame->GetThis()); - - // Delegates on static methods don't have a useful target instance. - // But in that case the target method is guaranteed to have exact - // type information. - if (pTargetMD->IsStatic()) - pTargetMT = pTargetMD->GetMethodTable(); - else - { - OBJECTREF refDelegateTarget = COMDelegate::GetTargetObject(pFrame->GetThis()); - pTargetMT = refDelegateTarget->GetTrueMethodTable(); - } - } - else - { - pTargetMD = pMD; - pTargetMT = CTPMethodTable::GetMethodTableBeingProxied(pFrame->GetThis()); - } - - // One last check to see if we can optimize the delegate case now we've - // unwrapped it. - if (fIsDelegate && !pTargetMD->HasClassInstantiation() && !pTargetMT->IsDelegate()) - { - thGoverningType = TypeHandle(pTargetMD->GetMethodTable()); - } - else - { - // Not quite done yet, we need to get the type that declares the method, - // which may be a superclass of the type we're calling on. - MethodTable *pDeclaringMT = pTargetMD->GetMethodTable(); - thGoverningType = ClassLoader::LoadGenericInstantiationThrowing(pDeclaringMT->GetModule(), - pDeclaringMT->GetCl(), - pTargetMD->GetExactClassInstantiation(TypeHandle(pTargetMT))); - } - } - - msgData->thGoverningType = thGoverningType; - - if (fIsDelegate) - { - DelegateEEClass* delegateCls = (DelegateEEClass*) pMD->GetMethodTable()->GetClass(); - - _ASSERTE(pFrame->GetThis()->GetMethodTable()->IsDelegate()); - - msgData->pDelegateMD = pMD; - msgData->pMethodDesc = COMDelegate::GetMethodDesc(pFrame->GetThis()); - - _ASSERTE(msgData->pMethodDesc != NULL); - _ASSERTE(!msgData->pMethodDesc->ContainsGenericVariables()); - _ASSERTE(msgData->pMethodDesc->IsRuntimeMethodHandle()); - - if (pMD == delegateCls->m_pBeginInvokeMethod) - { - msgData->iFlags |= MSGFLG_BEGININVOKE; - } - else - { - _ASSERTE(pMD == delegateCls->m_pEndInvokeMethod); - msgData->iFlags |= MSGFLG_ENDINVOKE; - } - } - else - { - msgData->pDelegateMD = NULL; - msgData->pMethodDesc = pMD; - _ASSERTE(msgData->pMethodDesc->IsRuntimeMethodHandle()); - } - - if (msgData->pMethodDesc->IsOneWay()) - { - msgData->iFlags |= MSGFLG_ONEWAY; - } - - if (msgData->pMethodDesc->IsCtor()) - { - msgData->iFlags |= MSGFLG_CTOR; - } - - Signature signature; - Module *pModule; - - if (msgData->pDelegateMD) - { - signature = msgData->pDelegateMD->GetSignature(); - pModule = msgData->pDelegateMD->GetModule(); - - // If the delegate is generic, pDelegateMD may not represent the exact instantiation so we recover it from 'this'. - SigTypeContext::InitTypeContext(pFrame->GetThis()->GetMethodTable()->GetInstantiation(), Instantiation(), pTypeContext); - } - else if (msgData->pMethodDesc->IsVarArg()) - { - VASigCookie *pVACookie = pFrame->GetVASigCookie(); - signature = pVACookie->signature; - pModule = pVACookie->pModule; - SigTypeContext::InitTypeContext(pTypeContext); - - } - else - { - signature = msgData->pMethodDesc->GetSignature(); - pModule = msgData->pMethodDesc->GetModule(); - SigTypeContext::InitTypeContext(msgData->pMethodDesc, thGoverningType, pTypeContext); - } - - *ppModule = pModule; - return signature; -} - -VOID CRealProxy::UpdateOptFlags(OBJECTREF refTP) -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END - - DWORD hierarchyDepth = 0; - REALPROXYREF refRP = CTPMethodTable::GetRP(refTP); - - OBJECTHANDLE hServerIdentity = (OBJECTHANDLE)refRP->GetPtrOffset(CRemotingServices::GetOffsetOfSrvIdentityInRP()); - if (hServerIdentity == NULL) - return; - - // Check if the proxy has already been marked as not equivalent. - // In which case, it can never get marked as anything else - RealProxyObject *rpTemp = (RealProxyObject *)OBJECTREFToObject(refRP); - - DWORD domainID = rpTemp->GetDomainID(); - AppDomainFromIDHolder ad((ADID)domainID, TRUE); - if (domainID == 0 || ad.IsUnloaded()) //we do not use ptr - return; // The appdomain the server belongs to, has been unloaded - ad.Release(); - DWORD optFlag = rpTemp->GetOptFlags(); - if ((optFlag & OPTIMIZATION_FLAG_INITTED) && - !(optFlag & OPTIMIZATION_FLAG_PROXY_EQUIVALENT)) - return; - - OBJECTREF refSrvIdentity = ObjectFromHandle(hServerIdentity); - // Is this a disconnected proxy ? - if (refSrvIdentity == NULL) - return; - - OBJECTREF refSrvObject = ObjectToOBJECTREF((Object *)refSrvIdentity->GetPtrOffset(CRemotingServices::GetOffsetOfTPOrObjInIdentity())); - - MethodTable *pCliMT = CTPMethodTable::GetMethodTableBeingProxied(refTP); - - BOOL bProxyQualifies = FALSE; - BOOL bCastToSharedType = FALSE; - - // Check if modules are physically the same - - // Check the inheritance hierarchy of the server object, to find the type - // that corresponds to the type the proxy is being cast to - // @TODO - If being cast to an interface, currently the proxy doesnt get marked equivalent - // @TODO - Need to check equivalency of the interface being cast to, and then reuse interface slot # on other side - LPCUTF8 szCliTypeName, szCliNameSpace; - szCliTypeName = pCliMT->GetFullyQualifiedNameInfo(&szCliNameSpace); - PREFIX_ASSUME(szCliTypeName != NULL); - - MethodTable *pSrvHierarchy = refSrvObject->GetMethodTable(); - - GCPROTECT_BEGIN(refRP); - while (pSrvHierarchy) - { - LPCUTF8 szSrvTypeName, szSrvNameSpace; - szSrvTypeName = pSrvHierarchy->GetFullyQualifiedNameInfo(&szSrvNameSpace); - PREFIX_ASSUME(szSrvNameSpace != NULL); - - if (!strcmp(szCliTypeName, szSrvTypeName) && !strcmp(szCliNameSpace, szSrvNameSpace)) - { - // Check if the types are shared. If they are, no further check neccesary - if (pSrvHierarchy == pCliMT) - { - bProxyQualifies = TRUE; - bCastToSharedType = TRUE; - } - else - { - bProxyQualifies = CRealProxy::ProxyTypeIdentityCheck(pCliMT, pSrvHierarchy); - } - break; - } - - pSrvHierarchy = pSrvHierarchy->GetParentMethodTable(); - hierarchyDepth++; - } - GCPROTECT_END(); - - optFlag = 0; - if (bProxyQualifies && hierarchyDepth < OPTIMIZATION_FLAG_DEPTH_MASK) - { - optFlag = OPTIMIZATION_FLAG_INITTED | OPTIMIZATION_FLAG_PROXY_EQUIVALENT; - if (bCastToSharedType) - optFlag |= OPTIMIZATION_FLAG_PROXY_SHARED_TYPE; - optFlag |= (hierarchyDepth & OPTIMIZATION_FLAG_DEPTH_MASK); - } - else - optFlag = OPTIMIZATION_FLAG_INITTED; - - RealProxyObject *rpUNSAFE = (RealProxyObject *)OBJECTREFToObject(refRP); - rpUNSAFE->SetOptFlags(optFlag); -} - -BOOL CRealProxy::ProxyTypeIdentityCheck(MethodTable *pCliHierarchy, MethodTable *pSrvHierarchy) -{ - CONTRACTL - { - GC_TRIGGERS; - MODE_COOPERATIVE; - THROWS; - } - CONTRACTL_END - // We have found the server side type that corresponds to the most derived type - // on client side, that the proxy is cast to - // Now do identity check on the server type hierarchy to see if there is an exact match - - BOOL bProxyQualifies = FALSE; - do - { - LPCUTF8 szCliTypeName, szCliNameSpace; - LPCUTF8 szSrvTypeName, szSrvNameSpace; - szCliTypeName = pCliHierarchy->GetFullyQualifiedNameInfo(&szCliNameSpace); - szSrvTypeName = pSrvHierarchy->GetFullyQualifiedNameInfo(&szSrvNameSpace); - PREFIX_ASSUME(szCliTypeName != NULL); - PREFIX_ASSUME(szSrvNameSpace != NULL); - - // If type names are different, there is no match - if (strcmp(szCliTypeName, szSrvTypeName) || - strcmp(szCliNameSpace, szSrvNameSpace)) - { - bProxyQualifies = FALSE; - return bProxyQualifies; - } - - PEAssembly *pClientPE = pCliHierarchy->GetAssembly()->GetManifestFile(); - PEAssembly *pServerPE = pSrvHierarchy->GetAssembly()->GetManifestFile(); - // If the PE files are different, there is no match - if (!pClientPE->Equals(pServerPE)) - { - bProxyQualifies = FALSE; - return bProxyQualifies; - } - - // If the number of interfaces implemented are different, there is no match - if (pSrvHierarchy->GetNumInterfaces() != pCliHierarchy->GetNumInterfaces()) - { - bProxyQualifies = FALSE; - return bProxyQualifies; - } - - MethodTable::InterfaceMapIterator srvItfIt = pSrvHierarchy->IterateInterfaceMap(); - MethodTable::InterfaceMapIterator cliItfIt = pCliHierarchy->IterateInterfaceMap(); - while (srvItfIt.Next()) - { - BOOL succeeded; - succeeded = cliItfIt.Next(); - CONSISTENCY_CHECK(succeeded); - if (!ProxyTypeIdentityCheck(srvItfIt.GetInterface(), cliItfIt.GetInterface())) - { - bProxyQualifies = FALSE; - return bProxyQualifies; - } - } - - pSrvHierarchy = pSrvHierarchy->GetParentMethodTable(); - pCliHierarchy = pCliHierarchy->GetParentMethodTable(); - } - while (pSrvHierarchy && pCliHierarchy); - - if (pSrvHierarchy || pCliHierarchy) - { - bProxyQualifies = FALSE; - return bProxyQualifies; - } - - bProxyQualifies = TRUE; - return bProxyQualifies; - -} - -ProfilerRemotingClientCallbackHolder::ProfilerRemotingClientCallbackHolder() -{ -#ifdef PROFILING_SUPPORTED - // If profiling is active, notify it that remoting stuff is kicking in - BEGIN_PIN_PROFILER(CORProfilerTrackRemoting()); - GCX_PREEMP(); - g_profControlBlock.pProfInterface->RemotingClientInvocationStarted(); - END_PIN_PROFILER(); -#endif // PROFILING_SUPPORTED -} - -ProfilerRemotingClientCallbackHolder::~ProfilerRemotingClientCallbackHolder() -{ -#ifdef PROFILING_SUPPORTED - // If profiling is active, tell profiler we've made the call, received the - // return value, done any processing necessary, and now remoting is done. - BEGIN_PIN_PROFILER(CORProfilerTrackRemoting()); - GCX_PREEMP(); - g_profControlBlock.pProfInterface->RemotingClientInvocationFinished(); - END_PIN_PROFILER(); -#endif // PROFILING_SUPPORTED -} - -enum -{ - CALLTYPE_INVALIDCALL = 0x0, // Important:: sync this with RealProxy.cs - CALLTYPE_METHODCALL = 0x1, // Important:: sync this with RealProxy.cs - CALLTYPE_CONSTRUCTORCALL = 0x2 // Important:: sync this with RealProxy.cs -}; - -extern "C" void STDCALL TransparentProxyStubPatch(); - -//+---------------------------------------------------------------------------- -// -// Method: TransparentProxyStubWorker -// -// Synopsis: This function gets control in two situations -// (1) When a call is made on the transparent proxy it delegates to -// PrivateInvoke method on the real proxy -// (2) When a call is made on the constructor it again delegates to the -// PrivateInvoke method on the real proxy. -// -// -//+---------------------------------------------------------------------------- -extern "C" UINT32 STDCALL TransparentProxyStubWorker(TransitionBlock * pTransitionBlock, TADDR pMethodDescOrSlot) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - ENTRY_POINT; - PRECONDITION(CheckPointer(pTransitionBlock)); - } - CONTRACTL_END; - - UINT fpRetSize = 0; - - FrameWithCookie frame(pTransitionBlock); - TPMethodFrame * pFrame = &frame; - - //we need to zero out the return value buffer because we will report it during GC -#ifdef ENREGISTERED_RETURNTYPE_MAXSIZE - ZeroMemory (pFrame->GetReturnValuePtr(), ENREGISTERED_RETURNTYPE_MAXSIZE); -#else - *(ARG_SLOT *)pFrame->GetReturnValuePtr() = 0; -#endif - - // For virtual calls the slot number is pushed but for - // non virtual calls/interface invoke the method descriptor is already - // pushed - MethodDesc * pMD; - if ((pMethodDescOrSlot >> 16) == 0) - { - // The frame is not completly setup at this point. - // Do not throw exceptions or provoke GC - MethodTable* pMT = CTPMethodTable::GetMethodTableBeingProxied(pFrame->GetThis()); - _ASSERTE(pMT); - - // Replace the slot number with the method descriptor on the stack - pMD = pMT->GetMethodDescForSlot((WORD)pMethodDescOrSlot); - } - else - { - pMD = dac_cast(pMethodDescOrSlot); - } - pFrame->SetFunction(pMD); - - pFrame->Push(); - - // Give debugger opportunity to stop here now that we know the MethodDesc * - TransparentProxyStubPatch(); - - INSTALL_UNWIND_AND_CONTINUE_HANDLER; - - if (g_pConfig->UseNewCrossDomainRemoting()) - { - BOOL bOptSuccess = FALSE; - CrossDomainChannel cdc; - bOptSuccess = cdc.CheckCrossDomainCall(pFrame); - if (bOptSuccess) - { - fpRetSize = cdc.GetFPReturnSize(); - goto Done; - } - } - - { - messageData msgData; - Module *pModule = NULL; - SigTypeContext inst; - Signature signature = InitMessageData(&msgData, pFrame, &pModule, &inst); - - _ASSERTE(!signature.IsEmpty() && pModule); - - // Allocate metasig on the stack - MetaSig mSig(signature, pModule, &inst); - msgData.pSig = &mSig; - - MethodDesc *pMD = pFrame->GetFunction(); - if (pMD->GetMethodTable()->IsDelegate()) - { - // check that there is only one target - if (COMDelegate::IsTrueMulticastDelegate(pFrame->GetThis())) - { - COMPlusThrow(kArgumentException, W("Remoting_Delegate_TooManyTargets")); - } - } - - { - ProfilerRemotingClientCallbackHolder profilerHolder; - - OBJECTREF pThisPointer = NULL; - - if (pMD->GetMethodTable()->IsDelegate()) - { - // this is an async call - _ASSERTE(pFrame->GetThis()->GetMethodTable()->IsDelegate()); - - pThisPointer = COMDelegate::GetTargetObject(pFrame->GetThis()); - } - else - { - pThisPointer = pFrame->GetThis(); - } - - OBJECTREF firstParameter; - MethodDesc* pTargetMD = NULL; - size_t callType = CALLTYPE_INVALIDCALL; - - // We are invoking either the constructor or a method on the object - if(pMD->IsCtor()) - { - // Get the address of PrivateInvoke in managed code - pTargetMD = CRemotingServices::MDofPrivateInvoke(); - _ASSERTE(pThisPointer->IsTransparentProxy()); - - firstParameter = CTPMethodTable::GetRP(pThisPointer); - - // Set a field to indicate that it is a constructor call - callType = CALLTYPE_CONSTRUCTORCALL; - } - else - { - // Set a field to indicate that it is a method call - callType = CALLTYPE_METHODCALL; - - if (pThisPointer->IsTransparentProxy()) - { - // Extract the real proxy underlying the transparent proxy - firstParameter = CTPMethodTable::GetRP(pThisPointer); - - // Get the address of PrivateInvoke in managed code - pTargetMD = CRemotingServices::MDofPrivateInvoke(); - _ASSERTE(pTargetMD); - } - else - { - // must be async if this is not a TP - _ASSERTE(pMD->GetMethodTable()->IsDelegate()); - firstParameter = NULL; - - // Get the address of PrivateInvoke in managed code - pTargetMD = CRemotingServices::MDofInvokeStatic(); - } - - // Go ahead and call PrivateInvoke on Real proxy. There is no need to - // catch exceptions thrown by it - // See RealProxy.cs - } - - _ASSERTE(pTargetMD); - - // Call the appropriate target - CTPMethodTable::CallTarget(pTargetMD, (LPVOID)OBJECTREFToObject(firstParameter), (LPVOID)&msgData, (LPVOID)callType); - - // Check for the need to trip thread - if (GetThread()->CatchAtSafePointOpportunistic()) - { - // There is no need to GC protect the return object as - // TPFrame is GC protecting it - CommonTripThread(); - } - } // ProfilerClientCallbackHolder - - { - mSig.Reset(); - - ArgIterator argit(&mSig); - -#ifdef _TARGET_X86_ - // Set the number of bytes to pop for x86 - pFrame->SetCbStackPop(argit.CbStackPop()); -#endif // _TARGET_X86_ - - fpRetSize = argit.GetFPReturnSize(); - } - } - -Done: ; - - pFrame->Pop(); - - UNINSTALL_UNWIND_AND_CONTINUE_HANDLER; - - return fpRetSize; -} - - -// Helper due to inability to combine SEH with anything interesting. -BOOL CTPMethodTable::CheckCastHelper(MethodDesc* pTargetMD, LPVOID pFirst, LPVOID pSecond) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pTargetMD)); - PRECONDITION(CheckPointer(pFirst, NULL_OK)); - PRECONDITION(CheckPointer(pSecond, NULL_OK)); - } - CONTRACTL_END; - - // Actual return type is a managed 'bool', so only look at a CLR_BOOL-sized - // result. The high bits are undefined on AMD64. (Note that a narrowing - // cast to CLR_BOOL will not work since it is the same as checking the - // size_t result != 0.) - LPVOID ret = CallTarget(pTargetMD, pFirst, pSecond); - return *(CLR_BOOL*)StackElemEndianessFixup(&ret, sizeof(CLR_BOOL)); -} - - - -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::CheckCast private -// -// Synopsis: Call the managed checkcast method to determine whether the -// server type can be cast to the given type -// -// -// -//+---------------------------------------------------------------------------- -BOOL CTPMethodTable::CheckCast(MethodDesc* pTargetMD, TRANSPARENTPROXYREF orTP, TypeHandle ty) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pTargetMD)); - PRECONDITION(orTP != NULL); - PRECONDITION(!ty.IsNull()); - } - CONTRACTL_END; - - REFLECTCLASSBASEREF reflectType = NULL; - LPVOID pvType = NULL; - BOOL fCastOK = FALSE; - - typedef struct _GCStruct - { - TRANSPARENTPROXYREF orTP; - REALPROXYREF orRP; - } GCStruct; - - GCStruct gcValues; - gcValues.orTP = orTP; - gcValues.orRP = GetRP(orTP); - - GCPROTECT_BEGIN (gcValues); - - reflectType = (REFLECTCLASSBASEREF) ty.GetMethodTable()->GetManagedClassObject(); - *(REFLECTCLASSBASEREF *)&pvType = reflectType; - - fCastOK = CheckCastHelper(pTargetMD, - (LPVOID)OBJECTREFToObject(gcValues.orRP), - pvType); - - if (fCastOK) - { - _ASSERTE(s_fTPTableFieldsInitialized); - - // The cast succeeded. Replace the current type in the proxy - // with the given type. - - CrstHolder ch(&s_TPMethodTableCrst); - - if (ty.IsInterface()) - { - // We replace the cached interface method table with the interface - // method table that we are trying to cast to. This will ensure that - // casts to this interface, which are likely to happen, will succeed. - gcValues.orTP->SetInterfaceMethodTable(ty.GetMethodTable()); - } - else - { - MethodTable *pCurrent = gcValues.orTP->GetMethodTableBeingProxied(); - - BOOL fDerivedClass = FALSE; - // Check whether this class derives from the current class - fDerivedClass = CRemotingServices::CheckCast(gcValues.orTP, ty, - TypeHandle(pCurrent)); - // We replace the current method table only if we cast to a more - // derived class - if (fDerivedClass) - { - // Set the method table in the proxy to the given method table - RefineProxy(gcValues.orTP, ty); - } - } - } - - GCPROTECT_END(); - return fCastOK; -} - -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::RefineProxy public -// -// Synopsis: Set the method table in the proxy to the given class' method table. -// Additionally, expand the TP method table to the required number of slots. -// -// -//+---------------------------------------------------------------------------- -void CTPMethodTable::RefineProxy(TRANSPARENTPROXYREF orTP, TypeHandle ty) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM()); - PRECONDITION(orTP != NULL); - PRECONDITION(!ty.IsNull()); - } - CONTRACTL_END; - - // Do the expansion only if necessary - MethodTable *pMT = ty.GetMethodTable(); - - if (pMT != orTP->GetMethodTableBeingProxied()) - { - orTP->SetMethodTableBeingProxied(pMT); - - // Extend the vtable if necessary - DWORD dwSlots = pMT->GetNumVirtuals(); - - if (dwSlots == 0) - dwSlots = 1; - - if((dwSlots > GetCommitedTPSlots()) && !ExtendCommitedSlots(dwSlots)) - { - // We failed to extend the committed slots. Out of memory. - COMPlusThrowOM(); - } - - } -} - -#ifndef HAS_REMOTING_PRECODE -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::GetOrCreateNonVirtualSlotForVirtualMethod private -// -// Synopsis: Get a slot for a non-virtual call to a virtual method. -// -//+---------------------------------------------------------------------------- -PTR_PCODE CTPMethodTable::GetOrCreateNonVirtualSlotForVirtualMethod(MethodDesc* pMD) -{ - CONTRACT (PTR_PCODE) - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(CheckPointer(pMD)); - PRECONDITION(pMD->IsRemotingInterceptedViaVirtualDispatch()); - POSTCONDITION(CheckPointer(RETVAL)); - } - CONTRACT_END; - - // Ensure the TP MethodTable's fields have been initialized. - EnsureFieldsInitialized(); - - PTR_PCODE pSlot; - - { - // Create the thunk in a thread safe manner - CrstHolder ch(&s_TPMethodTableCrst); - - // NOTE: CNonVirtualThunk::SetNonVirtualThunks() depends on the lock being initialized - CNonVirtualThunk::InitializeListLock(); - - // Create hash table if we do not have one yet - if (s_pThunkHashTable == NULL) - { - NewHolder pTempHash(new EEThunkHashTable()); - - LockOwner lock = {&s_TPMethodTableCrst, IsOwnerOfCrst}; - IfNullThrow(pTempHash->Init(23,&lock)); - - s_pThunkHashTable = pTempHash.Extract(); - } - - if (!s_pThunkHashTable->GetValue(pMD, (HashDatum *)&pSlot)) - { - PCODE pThunkCode = CreateNonVirtualThunkForVirtualMethod(pMD); - - _ASSERTE(CNonVirtualThunkMgr::IsThunkByASM(pThunkCode)); - _ASSERTE(CNonVirtualThunkMgr::GetMethodDescByASM(pThunkCode)); - - // Set the generated thunk once and for all.. - CNonVirtualThunk *pThunk = CNonVirtualThunk::SetNonVirtualThunks((BYTE*)pThunkCode); - - // Remember the thunk address in a hash table - // so that we dont generate it again - pSlot = (PTR_PCODE)pThunk->GetAddrOfCode(); - s_pThunkHashTable->InsertValue(pMD, (HashDatum)pSlot); - } - } - - RETURN pSlot; -} - -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::DestroyThunk public -// -// Synopsis: Destroy the thunk for the non virtual method. -// -// -//+---------------------------------------------------------------------------- -void CTPMethodTable::DestroyThunk(MethodDesc* pMD) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(CheckPointer(pMD)); - } - CONTRACTL_END; - - if(s_pThunkHashTable) - { - CrstHolder ch(&s_TPMethodTableCrst); - - LPVOID pvCode = NULL; - s_pThunkHashTable->GetValue(pMD, (HashDatum *)&pvCode); - CNonVirtualThunk *pThunk = NULL; - if(NULL != pvCode) - { - pThunk = CNonVirtualThunk::AddrToThunk(pvCode); - delete pThunk; - s_pThunkHashTable->DeleteValue(pMD); - } - } -} -#endif // HAS_REMOTING_PRECODE - -static LPVOID CallTargetWorker1(MethodDesc* pTargetMD, - LPVOID pvFirst, - LPVOID pvSecond) -{ - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_MODE_COOPERATIVE; - STATIC_CONTRACT_SO_INTOLERANT; - - LPVOID ret = NULL; - PCODE pTarget = pTargetMD->GetSingleCallableAddrOfCode(); - -#if defined(DEBUGGING_SUPPORTED) - if (CORDebuggerTraceCall()) - { - g_pDebugInterface->TraceCall((const BYTE*)pTarget); - } -#endif // DEBUGGING_SUPPORTED - - - BEGIN_CALL_TO_MANAGED(); - - ret = CTPMethodTable__CallTargetHelper2((const BYTE*)pTarget, pvFirst, pvSecond); - - END_CALL_TO_MANAGED(); - - return ret; -} - - -//+---------------------------------------------------------------------------- -// -// Method: CTPMethodTable::CallTarget private -// -// Synopsis: Calls the target method on the given object -// -//+---------------------------------------------------------------------------- -LPVOID __stdcall CTPMethodTable::CallTarget (MethodDesc* pTargetMD, - LPVOID pvFirst, - LPVOID pvSecond) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - SO_INTOLERANT; - PRECONDITION(CheckPointer(pTargetMD)); - PRECONDITION(CheckPointer(pvFirst, NULL_OK)); - PRECONDITION(CheckPointer(pvSecond, NULL_OK)); - } - CONTRACTL_END; - -#ifdef _DEBUG - - Thread* curThread = GetThread(); - - Object* ObjRefTable[OBJREF_TABSIZE]; - - if (curThread) - memcpy(ObjRefTable, curThread->dangerousObjRefs, sizeof(curThread->dangerousObjRefs)); - -#endif // _DEBUG - - LPVOID ret = CallTargetWorker1(pTargetMD, pvFirst, pvSecond); - -#ifdef _DEBUG - // Restore dangerousObjRefs when we return back to EE after call - if (curThread) - memcpy(curThread->dangerousObjRefs, ObjRefTable, sizeof(curThread->dangerousObjRefs)); - - ENABLESTRESSHEAP (); -#endif // _DEBUG - - return ret; -} - - -static LPVOID CallTargetWorker2(MethodDesc* pTargetMD, - LPVOID pvFirst, - LPVOID pvSecond, - LPVOID pvThird) -{ - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_MODE_COOPERATIVE; - STATIC_CONTRACT_SO_INTOLERANT; - - LPVOID ret = NULL; - PCODE pTarget = pTargetMD->GetSingleCallableAddrOfCode(); - -#if defined(DEBUGGING_SUPPORTED) - if (CORDebuggerTraceCall()) - { - g_pDebugInterface->TraceCall((const BYTE*)pTarget); - } -#endif // DEBUGGING_SUPPORTED - - BEGIN_CALL_TO_MANAGED(); - - ret = CTPMethodTable__CallTargetHelper3((const BYTE*)pTarget, pvFirst, pvSecond, pvThird); - - END_CALL_TO_MANAGED(); - return ret; - -} - -LPVOID __stdcall CTPMethodTable::CallTarget (MethodDesc* pTargetMD, - LPVOID pvFirst, - LPVOID pvSecond, - LPVOID pvThird) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - SO_INTOLERANT; - PRECONDITION(CheckPointer(pTargetMD)); - PRECONDITION(CheckPointer(pvFirst, NULL_OK)); - PRECONDITION(CheckPointer(pvSecond, NULL_OK)); - PRECONDITION(CheckPointer(pvThird, NULL_OK)); - } - CONTRACTL_END; - -#ifdef _DEBUG - Thread* curThread = GetThread(); - - Object* ObjRefTable[OBJREF_TABSIZE]; - if (curThread) - memcpy(ObjRefTable, curThread->dangerousObjRefs, sizeof(curThread->dangerousObjRefs)); - -#endif // _DEBUG - - LPVOID ret = CallTargetWorker2(pTargetMD, pvFirst, pvSecond, pvThird); - -#ifdef _DEBUG - // Restore dangerousObjRefs when we return back to EE after call - if (curThread) - memcpy(curThread->dangerousObjRefs, ObjRefTable, sizeof(curThread->dangerousObjRefs)); - - ENABLESTRESSHEAP (); -#endif // _DEBUG - - return ret; -} - - -#ifndef HAS_REMOTING_PRECODE -//+---------------------------------------------------------------------------- -// -// Method: CNonVirtualThunk::SetNextThunk public -// -// Synopsis: Creates a thunk for the given address and adds it to the global -// list -// -//+---------------------------------------------------------------------------- -CNonVirtualThunk* CNonVirtualThunk::SetNonVirtualThunks(const BYTE* pbCode) -{ - CONTRACT (CNonVirtualThunk*) - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - INJECT_FAULT(COMPlusThrowOM()); - PRECONDITION(CheckPointer(pbCode)); - POSTCONDITION(CheckPointer(RETVAL)); - } - CONTRACT_END; - - CNonVirtualThunk *pThunk = new CNonVirtualThunk(pbCode); - - // Put the generated thunk in a global list - // Note: this is called when a NV thunk is being created .. - // The TPMethodTable critsec is held at this point - pThunk->SetNextThunk(); - - // Set up the stub manager if necessary - CNonVirtualThunkMgr::InitNonVirtualThunkManager(); - - RETURN pThunk; -} - -//+---------------------------------------------------------------------------- -// -// Method: CNonVirtualThunk::~CNonVirtualThunk public -// -// Synopsis: Deletes the thunk from the global list of thunks -// -// -//+---------------------------------------------------------------------------- -CNonVirtualThunk::~CNonVirtualThunk() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(CheckPointer(s_pNonVirtualThunks)); - } - CONTRACTL_END; - - CNonVirtualThunk* pCurr = s_pNonVirtualThunks; - CNonVirtualThunk* pPrev = NULL; - BOOL found = FALSE; - - // Note: This is called with the TPMethodTable critsec held - while(!found && (NULL != pCurr)) - { - if(pCurr == this) - { - found = TRUE; - SimpleRWLock::SimpleWriteLockHolder swlh(s_pNonVirtualThunksListLock); - - // Unlink from the chain - if(NULL != pPrev) - { - pPrev->_pNext = pCurr->_pNext; - } - else - { - // First entry needs to be deleted - s_pNonVirtualThunks = pCurr->_pNext; - } - } - pPrev = pCurr; - pCurr = pCurr->_pNext; - } - - _ASSERTE(found); -} -#endif // HAS_REMOTING_PRECODE - -//+---------------------------------------------------------------------------- -// -// Method: CVirtualThunkMgr::InitVirtualThunkManager public -// -// Synopsis: Adds the stub manager to aid debugger in stepping into calls -// -// -//+---------------------------------------------------------------------------- -void CVirtualThunkMgr::InitVirtualThunkManager() -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - INJECT_FAULT(COMPlusThrowOM()); - } - CONTRACTL_END; - - // This is function is already threadsafe since this method is called from within a - // critical section - if(NULL == s_pVirtualThunkMgr) - { - // Add the stub manager for vtable calls - s_pVirtualThunkMgr = new CVirtualThunkMgr(); - - StubManager::AddStubManager(s_pVirtualThunkMgr); - } - -} - -#endif // !DACCESS_COMPILE - -//+---------------------------------------------------------------------------- -// -// Method: CVirtualThunkMgr::CheckIsStub_Internal public -// -// Synopsis: Returns TRUE if the given address is the starting address of -// the transparent proxy stub -// -//+---------------------------------------------------------------------------- -BOOL CVirtualThunkMgr::CheckIsStub_Internal(PCODE stubStartAddress) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - SUPPORTS_DAC; - } - CONTRACTL_END; - - BOOL bIsStub = FALSE; - -#ifndef DACCESS_COMPILE - if (!IsThunkByASM(stubStartAddress)) - return FALSE; - if(NULL != FindThunk((const BYTE *) stubStartAddress)) - bIsStub = TRUE; -#endif // !DACCESS_COMPILE - - return bIsStub; -} - -#ifndef DACCESS_COMPILE - -//+---------------------------------------------------------------------------- -// -// Method: CVirtualThunkMgr::Entry2MethodDesc public -// -// Synopsis: Convert a starting address to a MethodDesc -// -//+---------------------------------------------------------------------------- -MethodDesc *CVirtualThunkMgr::Entry2MethodDesc(PCODE StubStartAddress, MethodTable *pMT) -{ - CONTRACT (MethodDesc*) - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(CheckPointer(pMT, NULL_OK)); - POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); - } - CONTRACT_END; - - if (s_pVirtualThunkMgr == NULL) - RETURN NULL; - - if (!pMT) - RETURN NULL; - - if (!s_pVirtualThunkMgr->CheckIsStub_Internal(StubStartAddress)) - RETURN NULL; - - RETURN GetMethodDescByASM(StubStartAddress, pMT); -} - -//+---------------------------------------------------------------------------- -// -// Method: CVirtualThunkMgr::FindThunk private -// -// Synopsis: Finds a thunk that matches the given starting address -// -//+---------------------------------------------------------------------------- -LPBYTE CVirtualThunkMgr::FindThunk(const BYTE *stubStartAddress) -{ - CONTRACT (LPBYTE) - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(CheckPointer(stubStartAddress, NULL_OK)); - POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); - SO_TOLERANT; - } - CONTRACT_END; - - CVirtualThunks* pThunks = CVirtualThunks::GetVirtualThunks(); - LPBYTE pThunkAddr = NULL; - - while(NULL != pThunks) - { - DWORD dwStartSlot = pThunks->_dwStartThunk; - DWORD dwCurrSlot = pThunks->_dwStartThunk; - DWORD dwMaxSlot = pThunks->_dwCurrentThunk; - while (dwCurrSlot < dwMaxSlot) - { - LPBYTE pStartAddr = pThunks->ThunkCode[dwCurrSlot-dwStartSlot].pCode; - if((stubStartAddress >= pStartAddr) && - (stubStartAddress < (pStartAddr + ConstVirtualThunkSize))) - { - pThunkAddr = pStartAddr; - break; - } - ++dwCurrSlot; - } - - pThunks = pThunks->GetNextThunk(); - } - - RETURN pThunkAddr; -} - -#endif // !DACCESS_COMPILE - -#ifndef HAS_REMOTING_PRECODE - -#ifndef DACCESS_COMPILE - -//+---------------------------------------------------------------------------- -// -// Method: CNonVirtualThunkMgr::InitNonVirtualThunkManager public -// -// Synopsis: Adds the stub manager to aid debugger in stepping into calls -// -// -//+---------------------------------------------------------------------------- -void CNonVirtualThunkMgr::InitNonVirtualThunkManager() -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - INJECT_FAULT(COMPlusThrowOM()); - } - CONTRACTL_END; - - // This function is already thread safe since this method is called from within a - // critical section - if(NULL == s_pNonVirtualThunkMgr) - { - // Add the stub manager for non vtable calls - s_pNonVirtualThunkMgr = new CNonVirtualThunkMgr(); - - StubManager::AddStubManager(s_pNonVirtualThunkMgr); - } -} - -#endif // !DACCESS_COMPILE - -//+---------------------------------------------------------------------------- -// -// Method: CNonVirtualThunkMgr::CheckIsStub_Internal public -// -// Synopsis: Returns TRUE if the given address is the starting address of -// one of our thunks -// -//+---------------------------------------------------------------------------- -BOOL CNonVirtualThunkMgr::CheckIsStub_Internal(PCODE stubStartAddress) -{ - WRAPPER_NO_CONTRACT; - - BOOL bIsStub = FALSE; - -#ifndef DACCESS_COMPILE - if (!IsThunkByASM(stubStartAddress)) - return FALSE; - if(NULL != FindThunk((const BYTE *) stubStartAddress)) - bIsStub = TRUE; -#endif // !DACCESS_COMPILE - - return bIsStub; -} - -#ifndef DACCESS_COMPILE - -//+---------------------------------------------------------------------------- -// -// Method: CNonVirtualThunkMgr::Entry2MethodDesc public -// -// Synopsis: Convert a starting address to a MethodDesc -// -//+---------------------------------------------------------------------------- -MethodDesc *CNonVirtualThunkMgr::Entry2MethodDesc(PCODE StubStartAddress, MethodTable *pMT) -{ - CONTRACT (MethodDesc*) - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(CheckPointer(pMT, NULL_OK)); - POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); - } - CONTRACT_END; - - if (s_pNonVirtualThunkMgr == NULL) - RETURN NULL; - - if (!s_pNonVirtualThunkMgr->CheckIsStub_Internal(StubStartAddress)) - RETURN NULL; - - RETURN GetMethodDescByASM(StubStartAddress); -} - -//+---------------------------------------------------------------------------- -// -// Method: CNonVirtualThunkMgr::FindThunk private -// -// Synopsis: Finds a thunk that matches the given starting address -// -//+---------------------------------------------------------------------------- -CNonVirtualThunk* CNonVirtualThunkMgr::FindThunk(const BYTE *stubStartAddress) -{ - CONTRACT (CNonVirtualThunk*) - { - NOTHROW; - GC_NOTRIGGER; - MODE_ANY; - PRECONDITION(CheckPointer(stubStartAddress, NULL_OK)); - POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); - SO_TOLERANT; - } - CONTRACT_END; - - SimpleRWLock::SimpleReadLockHolder srlh(CNonVirtualThunk::GetThunksListLock()); - CNonVirtualThunk* pThunk = CNonVirtualThunk::GetNonVirtualThunks(); - - while(NULL != pThunk) - { - if(stubStartAddress == pThunk->GetThunkCode()) - break; - - pThunk = pThunk->GetNextThunk(); - } - - RETURN pThunk; -} - -#endif // !DACCESS_COMPILE - -#endif // HAS_REMOTING_PRECODE - - -#ifndef DACCESS_COMPILE - -//+---------------------------------------------------------------------------- -//+- HRESULT MethodDescDispatchHelper(MethodDesc* pMD, ARG_SLOT[] args, ARG_SLOT *pret) -//+---------------------------------------------------------------------------- -HRESULT MethodDescDispatchHelper(MethodDescCallSite* pMethodCallSite, ARG_SLOT args[], ARG_SLOT *pret) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(CheckPointer(pMethodCallSite)); - PRECONDITION(CheckPointer(args)); - PRECONDITION(CheckPointer(pret)); - } - CONTRACTL_END; - - HRESULT hr = S_OK; - EX_TRY - { - *pret = pMethodCallSite->Call_RetArgSlot(args); - } - EX_CATCH_HRESULT(hr); - - return hr; -} - - -#ifdef FEATURE_COMINTEROP - -//+---------------------------------------------------------------------------- -// -// Method: VOID CRemotingServices::CallSetDCOMProxy(OBJECTREF realProxy, IUnknown* pUnk) -// -//+---------------------------------------------------------------------------- - -VOID CRemotingServices::CallSetDCOMProxy(OBJECTREF realProxy, IUnknown* pUnk) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(realProxy != NULL); - PRECONDITION(CheckPointer(pUnk, NULL_OK)); - } - CONTRACTL_END; - - GCPROTECT_BEGIN(realProxy); - - MethodDescCallSite setDCOMProxy(METHOD__REAL_PROXY__SETDCOMPROXY, &realProxy); - - ARG_SLOT args[] = - { - ObjToArgSlot(realProxy), - (ARG_SLOT)pUnk - }; - - ARG_SLOT ret; - MethodDescDispatchHelper(&setDCOMProxy, args, &ret); - - GCPROTECT_END(); -} - - -BOOL CRemotingServices::CallSupportsInterface(OBJECTREF realProxy, REFIID iid, ARG_SLOT* pret) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - PRECONDITION(realProxy != NULL); - PRECONDITION(CheckPointer(pret)); - } - CONTRACTL_END; - - BOOL fResult = TRUE; - - GCPROTECT_BEGIN(realProxy); - - MethodDescCallSite supportsInterface(METHOD__REAL_PROXY__SUPPORTSINTERFACE, &realProxy); - - ARG_SLOT args[] = - { - ObjToArgSlot(realProxy), - (ARG_SLOT)&iid - }; - - HRESULT hr = MethodDescDispatchHelper(&supportsInterface, args, pret); - - // It is allowed for the managed code to return a NULL interface pointer without returning - // a failure HRESULT. This is done for performance to avoid having to throw an exception. - // If this occurs, we need to return E_NOINTERFACE. - if ((*(IUnknown**)pret) == NULL) - hr = E_NOINTERFACE; - - if (FAILED(hr)) - fResult = FALSE; - - GCPROTECT_END(); - return fResult; -} -#endif // FEATURE_COMINTEROP - -//+---------------------------------------------------------------------------- -// -// Method: CRemotingServices::GetStubForInterfaceMethod -// -// Synopsis: Given the exact interface method we wish to invoke on, return -// the entry point of a stub that will correctly transition into -// the remoting system passing it this method. -// The stubs is just another kind of precode. They are cached -// in per appdomain hash. -// -// -//+---------------------------------------------------------------------------- -PCODE CRemotingServices::GetStubForInterfaceMethod(MethodDesc *pItfMD) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(CheckPointer(pItfMD)); - PRECONDITION(pItfMD->IsInterface() && !pItfMD->IsStatic()); - } - CONTRACTL_END; - - return pItfMD->GetLoaderAllocator()->GetFuncPtrStubs()->GetFuncPtrStub(pItfMD, PRECODE_STUB); -} - -#endif // !DACCESS_COMPILE -#endif // FEATURE_REMOTING -- cgit v1.2.3 From 457ee7bbf1ce194cf2260ca202eae6aa1bcd445a Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Sun, 12 Feb 2017 21:04:15 -0800 Subject: Remove dead rwlock.cpp --- src/vm/rwlock.cpp | 2952 ----------------------------------------------------- src/vm/rwlock.h | 214 ---- 2 files changed, 3166 deletions(-) delete mode 100644 src/vm/rwlock.cpp diff --git a/src/vm/rwlock.cpp b/src/vm/rwlock.cpp deleted file mode 100644 index 9d8233d140..0000000000 --- a/src/vm/rwlock.cpp +++ /dev/null @@ -1,2952 +0,0 @@ -// 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. -// - -// -//+------------------------------------------------------------------- -// -// File: RWLock.cpp -// -// Contents: Reader writer lock implementation that supports the -// following features -// 1. Cheap enough to be used in large numbers -// such as per object synchronization. -// 2. Supports timeout. This is a valuable feature -// to detect deadlocks -// 3. Supports caching of events. This allows -// the events to be moved from least contentious -// regions to the most contentious regions. -// In other words, the number of events needed by -// Reader-Writer lockls is bounded by the number -// of threads in the process. -// 4. Supports nested locks by readers and writers -// 5. Supports spin counts for avoiding context switches -// on multi processor machines. -// 6. Supports functionality for upgrading to a writer -// lock with a return argument that indicates -// intermediate writes. Downgrading from a writer -// lock restores the state of the lock. -// 7. Supports functionality to Release Lock for calling -// app code. RestoreLock restores the lock state and -// indicates intermediate writes. -// 8. Recovers from most common failures such as creation of -// events. In other words, the lock mainitains consistent -// internal state and remains usable -// -// -// Classes: CRWLock -// -//-------------------------------------------------------------------- - - -#include "common.h" -#include "rwlock.h" -#include "corhost.h" - -#ifdef FEATURE_RWLOCK - -// Reader increment -#define READER 0x00000001 -// Max number of readers -#define READERS_MASK 0x000003FF -// Reader being signaled -#define READER_SIGNALED 0x00000400 -// Writer being signaled -#define WRITER_SIGNALED 0x00000800 -#define WRITER 0x00001000 -// Waiting reader increment -#define WAITING_READER 0x00002000 -// Note size of waiting readers must be less -// than or equal to size of readers -#define WAITING_READERS_MASK 0x007FE000 -#define WAITING_READERS_SHIFT 13 -// Waiting writer increment -#define WAITING_WRITER 0x00800000 -// Max number of waiting writers -#define WAITING_WRITERS_MASK 0xFF800000 -// Events are being cached -#define CACHING_EVENTS (READER_SIGNALED | WRITER_SIGNALED) - -// Cookie flags -#define UPGRADE_COOKIE 0x02000 -#define RELEASE_COOKIE 0x04000 -#define COOKIE_NONE 0x10000 -#define COOKIE_WRITER 0x20000 -#define COOKIE_READER 0x40000 -#define INVALID_COOKIE (~(UPGRADE_COOKIE | RELEASE_COOKIE | \ - COOKIE_NONE | COOKIE_WRITER | COOKIE_READER)) -#define RWLOCK_MAX_ACQUIRE_COUNT 0xFFFF - -// globals -Volatile CRWLock::s_mostRecentLockID = 0; -CrstStatic CRWLock::s_RWLockCrst; - -// Default values -#ifdef _DEBUG -DWORD gdwDefaultTimeout = 120000; -#else //!_DEBUG -DWORD gdwDefaultTimeout = INFINITE; -#endif //_DEBUG -const DWORD gdwReasonableTimeout = 120000; -DWORD gdwDefaultSpinCount = 0; -BOOL fBreakOnErrors = FALSE; // Temporarily break on errors - -// REVISIT_TODO: Bad practise -#define HEAP_SERIALIZE 0 -#define RWLOCK_RECOVERY_FAILURE (0xC0000227L) - -// Catch GC holes -#if _DEBUG -#define VALIDATE_LOCK(pRWLock) ((Object *) (pRWLock))->Validate(); -#else // !_DEBUG -#define VALIDATE_LOCK(pRWLock) -#endif // _DEBUG - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::ProcessInit public -// -// Synopsis: Reads default values from registry and intializes -// process wide data structures -// -//+------------------------------------------------------------------- -void CRWLock::ProcessInit() -{ - CONTRACTL - { - THROWS; // From Crst.Init() - GC_NOTRIGGER; - PRECONDITION((g_SystemInfo.dwNumberOfProcessors != 0)); - } - CONTRACTL_END; - - gdwDefaultSpinCount = (g_SystemInfo.dwNumberOfProcessors != 1) ? 500 : 0; - - PPEB peb = (PPEB) ClrTeb::GetProcessEnvironmentBlock(); - DWORD dwTimeout = (DWORD)(peb->CriticalSectionTimeout.QuadPart/-10000000); - if (dwTimeout) - { - gdwDefaultTimeout = dwTimeout; - } - - // Initialize the critical section used by the lock - // Can throw out of memory here. - s_RWLockCrst.Init(CrstRWLock, CRST_UNSAFE_ANYMODE); -} - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::CRWLock public -// -// Synopsis: Constructor -// -//+------------------------------------------------------------------- -CRWLock::CRWLock() -: _hWriterEvent(NULL), - _hReaderEvent(NULL), - _dwState(0), - _dwWriterID(0), - _dwWriterSeqNum(1), - _wWriterLevel(0) -#ifdef RWLOCK_STATISTICS - , - _dwReaderEntryCount(0), - _dwReaderContentionCount(0), - _dwWriterEntryCount(0), - _dwWriterContentionCount(0), - _dwEventsReleasedCount(0) -#endif -{ - - CONTRACT_VOID - { - NOTHROW; - GC_NOTRIGGER; - POSTCONDITION((_dwLLockID > 0)); - } - CONTRACT_END; - - LONGLONG qwLockID = s_mostRecentLockID; - while (true) - { - LONGLONG qwNextLockID = qwLockID + 1; - if (static_cast(qwNextLockID) == 0) - { - // A value of zero for the lower half of the ID is reserved to identify that a thread does not own any RW locks, - // regardless of the upper half of the ID - ++qwNextLockID; - } - - LONGLONG qwLockIDBeforeExchange = RWInterlockedCompareExchange64(&s_mostRecentLockID, qwNextLockID, qwLockID); - if (qwLockIDBeforeExchange == qwLockID) - { - qwLockID = qwNextLockID; - break; - } - - qwLockID = qwLockIDBeforeExchange; - } - - _dwLLockID = static_cast(qwLockID); - _dwULockID = static_cast(qwLockID >> 32); - - RETURN; -} - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::Cleanup public -// -// Synopsis: Cleansup state -// -//+------------------------------------------------------------------- -void CRWLock::Cleanup() -{ - - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - PRECONDITION((_dwState == 0)); // sanity checks - PRECONDITION((_dwWriterID == 0)); - PRECONDITION((_wWriterLevel == 0)); - } - CONTRACTL_END; - - if(_hWriterEvent) { - delete _hWriterEvent; - _hWriterEvent = NULL; - } - if(_hReaderEvent) { - delete _hReaderEvent; - _hReaderEvent = NULL; - } - - return; -} - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::ChainEntry private -// -// Synopsis: Chains the given lock entry into the chain -// -//+------------------------------------------------------------------- -inline void CRWLock::ChainEntry(Thread *pThread, LockEntry *pLockEntry) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - // This is to synchronize with finalizer thread and deadlock detection. - CrstHolder rwl(&s_RWLockCrst); - LockEntry *pHeadEntry = pThread->m_pHead; - pLockEntry->pNext = pHeadEntry; - pLockEntry->pPrev = pHeadEntry->pPrev; - pLockEntry->pPrev->pNext = pLockEntry; - pHeadEntry->pPrev = pLockEntry; - - return; -} - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::GetLockEntry private -// -// Synopsis: Gets lock entry from TLS -// -//+------------------------------------------------------------------- -inline LockEntry *CRWLock::GetLockEntry(Thread* pThread) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; - } - CONTRACTL_END; - - if (pThread == NULL) { - pThread = GetThread(); - } - LockEntry *pHeadEntry = pThread->m_pHead; - LockEntry *pLockEntry = pHeadEntry; - do - { - if((pLockEntry->dwLLockID == _dwLLockID) && (pLockEntry->dwULockID == _dwULockID)) - return(pLockEntry); - pLockEntry = pLockEntry->pNext; - } while(pLockEntry != pHeadEntry); - - return(NULL); -} - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::FastGetOrCreateLockEntry private -// -// Synopsis: The fast path for getting a lock entry from TLS -// -//+------------------------------------------------------------------- -inline LockEntry *CRWLock::FastGetOrCreateLockEntry() -{ - - CONTRACTL - { - THROWS; // SlowGetOrCreateLockEntry can throw out of memory exception - GC_NOTRIGGER; - } - CONTRACTL_END; - - Thread *pThread = GetThread(); - _ASSERTE(pThread); - LockEntry *pLockEntry = pThread->m_pHead; - if(pLockEntry->dwLLockID == 0) - { - _ASSERTE(pLockEntry->wReaderLevel == 0); - pLockEntry->dwLLockID = _dwLLockID; - pLockEntry->dwULockID = _dwULockID; - return(pLockEntry); - } - else if((pLockEntry->dwLLockID == _dwLLockID) && (pLockEntry->dwULockID == _dwULockID)) - { - // Note, StaticAcquireReaderLock can have reentry via pumping while it's blocking - // so no assertions about pLockEntry->wReaderLevel's state - return(pLockEntry); - } - - return(SlowGetOrCreateLockEntry(pThread)); -} - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::SlowGetorCreateLockEntry private -// -// Synopsis: The slow path for getting a lock entry from TLS -// -//+------------------------------------------------------------------- -LockEntry *CRWLock::SlowGetOrCreateLockEntry(Thread *pThread) -{ - - CONTRACTL - { - THROWS; // memory allocation can throw out of memory exception - GC_NOTRIGGER; - } - CONTRACTL_END; - - LockEntry *pFreeEntry = NULL; - LockEntry *pHeadEntry = pThread->m_pHead; - - // Search for an empty entry or an entry belonging to this lock - LockEntry *pLockEntry = pHeadEntry->pNext; - while(pLockEntry != pHeadEntry) - { - if(pLockEntry->dwLLockID && - ((pLockEntry->dwLLockID != _dwLLockID) || (pLockEntry->dwULockID != _dwULockID))) - { - // Move to the next entry - pLockEntry = pLockEntry->pNext; - } - else - { - // Prepare to move it to the head - pFreeEntry = pLockEntry; - pLockEntry->pPrev->pNext = pLockEntry->pNext; - pLockEntry->pNext->pPrev = pLockEntry->pPrev; - - break; - } - } - - if(pFreeEntry == NULL) - { - pFreeEntry = new LockEntry; - pFreeEntry->wReaderLevel = 0; - } - - if(pFreeEntry) - { - _ASSERTE((pFreeEntry->dwLLockID != 0) || (pFreeEntry->wReaderLevel == 0)); - _ASSERTE((pFreeEntry->wReaderLevel == 0) || - ((pFreeEntry->dwLLockID == _dwLLockID) && (pFreeEntry->dwULockID == _dwULockID))); - - // Chain back the entry - ChainEntry(pThread, pFreeEntry); - - // Move this entry to the head - pThread->m_pHead = pFreeEntry; - - // Mark the entry as belonging to this lock - pFreeEntry->dwLLockID = _dwLLockID; - pFreeEntry->dwULockID = _dwULockID; - } - - return pFreeEntry; -} - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::FastRecycleLockEntry private -// -// Synopsis: Fast path for recycling the lock entry that is used -// when the thread is the next few instructions is going -// to call FastGetOrCreateLockEntry again -// -//+------------------------------------------------------------------- -inline void CRWLock::FastRecycleLockEntry(LockEntry *pLockEntry) -{ - - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - - // Sanity checks - PRECONDITION(pLockEntry->wReaderLevel == 0); - PRECONDITION((pLockEntry->dwLLockID == _dwLLockID) && (pLockEntry->dwULockID == _dwULockID)); - PRECONDITION(pLockEntry == GetThread()->m_pHead); - } - CONTRACTL_END; - - - pLockEntry->dwLLockID = 0; -} - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::RecycleLockEntry private -// -// Synopsis: Fast path for recycling the lock entry -// -//+------------------------------------------------------------------- -inline void CRWLock::RecycleLockEntry(LockEntry *pLockEntry) -{ - - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - - // Sanity check - PRECONDITION(pLockEntry->wReaderLevel == 0); - } - CONTRACTL_END; - - // Move the entry to tail - Thread *pThread = GetThread(); - LockEntry *pHeadEntry = pThread->m_pHead; - if(pLockEntry == pHeadEntry) - { - pThread->m_pHead = pHeadEntry->pNext; - } - else if(pLockEntry->pNext->dwLLockID) - { - // Prepare to move the entry to tail - pLockEntry->pPrev->pNext = pLockEntry->pNext; - pLockEntry->pNext->pPrev = pLockEntry->pPrev; - - // Chain back the entry - ChainEntry(pThread, pLockEntry); - } - - // The entry does not belong to this lock anymore - pLockEntry->dwLLockID = 0; - return; -} - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::StaticIsWriterLockHeld public -// -// Synopsis: Return TRUE if writer lock is held -// -//+------------------------------------------------------------------- -FCIMPL1(FC_BOOL_RET, CRWLock::StaticIsWriterLockHeld, CRWLock *pRWLock) -{ - FCALL_CONTRACT; - - if (pRWLock == NULL) - { - FCThrow(kNullReferenceException); - } - - if(pRWLock->_dwWriterID == GetThread()->GetThreadId()) - FC_RETURN_BOOL(TRUE); - - FC_RETURN_BOOL(FALSE); -} -FCIMPLEND - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::StaticIsReaderLockHeld public -// -// Synopsis: Return TRUE if reader lock is held -// -//+------------------------------------------------------------------- -FCIMPL1(FC_BOOL_RET, CRWLock::StaticIsReaderLockHeld, CRWLock *pRWLock) -{ - FCALL_CONTRACT; - - if (pRWLock == NULL) - { - FCThrow(kNullReferenceException); - } - - LockEntry *pLockEntry = pRWLock->GetLockEntry(); - if(pLockEntry) - { - FC_RETURN_BOOL(pLockEntry->wReaderLevel > 0); - } - - FC_RETURN_BOOL(FALSE); -} -FCIMPLEND - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::AssertWriterLockHeld public -// -// Synopsis: Asserts that writer lock is held -// -//+------------------------------------------------------------------- -#ifdef _DEBUG -BOOL CRWLock::AssertWriterLockHeld() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; - } - CONTRACTL_END; - - if(_dwWriterID == GetThread()->GetThreadId()) - return(TRUE); - - _ASSERTE(!"Writer lock not held by the current thread"); - return(FALSE); -} -#endif - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::AssertWriterLockNotHeld public -// -// Synopsis: Asserts that writer lock is not held -// -//+------------------------------------------------------------------- -#ifdef _DEBUG -BOOL CRWLock::AssertWriterLockNotHeld() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; - } - CONTRACTL_END; - - if(_dwWriterID != GetThread()->GetThreadId()) - return(TRUE); - - _ASSERTE(!"Writer lock held by the current thread"); - return(FALSE); -} -#endif - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::AssertReaderLockHeld public -// -// Synopsis: Asserts that reader lock is held -// -//+------------------------------------------------------------------- -#ifdef _DEBUG -BOOL CRWLock::AssertReaderLockHeld() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; - } - CONTRACTL_END; - - LockEntry *pLockEntry = GetLockEntry(); - if(pLockEntry) - { - _ASSERTE(pLockEntry->wReaderLevel); - return(TRUE); - } - - _ASSERTE(!"Reader lock not held by the current thread"); - return(FALSE); -} -#endif - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::AssertReaderLockNotHeld public -// -// Synopsis: Asserts that writer lock is not held -// -//+------------------------------------------------------------------- -#ifdef _DEBUG -BOOL CRWLock::AssertReaderLockNotHeld() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; - } - CONTRACTL_END; - - LockEntry *pLockEntry = GetLockEntry(); - if(pLockEntry == NULL) - return(TRUE); - - _ASSERTE(pLockEntry->wReaderLevel); - _ASSERTE(!"Reader lock held by the current thread"); - - return(FALSE); -} -#endif - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::AssertReaderOrWriterLockHeld public -// -// Synopsis: Asserts that writer lock is not held -// -//+------------------------------------------------------------------- -#ifdef _DEBUG -BOOL CRWLock::AssertReaderOrWriterLockHeld() -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; - } - CONTRACTL_END; - - if(_dwWriterID == GetThread()->GetThreadId()) - { - return(TRUE); - } - else - { - LockEntry *pLockEntry = GetLockEntry(); - if(pLockEntry) - { - _ASSERTE(pLockEntry->wReaderLevel); - return(TRUE); - } - } - - _ASSERTE(!"Neither Reader nor Writer lock held"); - return(FALSE); -} -#endif - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::RWSetEvent private -// -// Synopsis: Helper function for setting an event -// -//+------------------------------------------------------------------- -inline void CRWLock::RWSetEvent(CLREvent* event) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - } - CONTRACTL_END; - - if(!event->Set()) - { - _ASSERTE(!"SetEvent failed"); - if(fBreakOnErrors) // fBreakOnErrors == FALSE so will be optimized out. - DebugBreak(); - COMPlusThrowWin32(E_UNEXPECTED); - } -} - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::RWResetEvent private -// -// Synopsis: Helper function for resetting an event -// -//+------------------------------------------------------------------- -inline void CRWLock::RWResetEvent(CLREvent* event) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - } - CONTRACTL_END; - - if(!event->Reset()) - { - _ASSERTE(!"ResetEvent failed"); - if(fBreakOnErrors) // fBreakOnErrors == FALSE so will be optimized out. - DebugBreak(); - COMPlusThrowWin32(E_UNEXPECTED); - } -} - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::RWWaitForSingleObject public -// -// Synopsis: Helper function for waiting on an event -// -//+------------------------------------------------------------------- -inline DWORD CRWLock::RWWaitForSingleObject(CLREvent* event, DWORD dwTimeout) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - } - CONTRACTL_END; - - DWORD status = WAIT_FAILED; - EX_TRY - { - status = event->Wait(dwTimeout,TRUE); - } - EX_CATCH - { - status = GET_EXCEPTION()->GetHR(); - if (status == S_OK) - { - status = WAIT_FAILED; - } - } - EX_END_CATCH(SwallowAllExceptions); // The caller will rethrow the exception - - return status; -} - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::RWSleep public -// -// Synopsis: Helper function for calling Sleep -// -//+------------------------------------------------------------------- -inline void CRWLock::RWSleep(DWORD dwTime) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - ClrSleepEx(dwTime, TRUE); -} - - -#undef volatile - -//+------------------------------------------------------------------- -// -// Method: CRWLock::RWInterlockedCompareExchange public -// -// Synopsis: Helper function for calling intelockedCompareExchange -// -//+------------------------------------------------------------------- -inline LONG CRWLock::RWInterlockedCompareExchange(LONG volatile *pvDestination, - LONG dwExchange, - LONG dwComparand) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - return FastInterlockCompareExchange(pvDestination, - dwExchange, - dwComparand); -} - -inline LONGLONG CRWLock::RWInterlockedCompareExchange64(LONGLONG volatile *pvDestination, - LONGLONG qwExchange, - LONGLONG qwComparand) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - return FastInterlockCompareExchangeLong(pvDestination, qwExchange, qwComparand); -} - -inline void* CRWLock::RWInterlockedCompareExchangePointer(PVOID volatile *pvDestination, - void* pExchange, - void* pComparand) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - return FastInterlockCompareExchangePointer(pvDestination, - pExchange, - pComparand); -} - -//+------------------------------------------------------------------- -// -// Method: CRWLock::RWInterlockedExchangeAdd public -// -// Synopsis: Helper function for adding state -// -//+------------------------------------------------------------------- -inline LONG CRWLock::RWInterlockedExchangeAdd(LONG volatile *pvDestination, - LONG dwAddToState) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - return FastInterlockExchangeAdd(pvDestination, dwAddToState); -} - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::RWInterlockedIncrement public -// -// Synopsis: Helper function for incrementing a pointer -// -//+------------------------------------------------------------------- -inline LONG CRWLock::RWInterlockedIncrement(LONG volatile *pdwState) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - return FastInterlockIncrement(pdwState); -} - -#define volatile DoNotUserVolatileKeyword - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::ReleaseEvents public -// -// Synopsis: Helper function for caching events -// -//+------------------------------------------------------------------- -void CRWLock::ReleaseEvents() -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - PRECONDITION(((_dwState & CACHING_EVENTS) == CACHING_EVENTS)); // Ensure that reader and writers have been stalled - - } - CONTRACTL_END; - - // Save writer event - CLREvent *hWriterEvent = _hWriterEvent; - _hWriterEvent = NULL; - - // Save reader event - CLREvent *hReaderEvent = _hReaderEvent; - _hReaderEvent = NULL; - - // Allow readers and writers to continue - RWInterlockedExchangeAdd(&_dwState, -(CACHING_EVENTS)); - - // Cache events - // : - // I am closing events for now. What is needed - // is an event cache to which the events are - // released using InterlockedCompareExchange64 - if(hWriterEvent) - { - LOG((LF_SYNC, LL_INFO10, "Releasing writer event\n")); - delete hWriterEvent; - } - if(hReaderEvent) - { - LOG((LF_SYNC, LL_INFO10, "Releasing reader event\n")); - delete hReaderEvent; - } -#ifdef RWLOCK_STATISTICS - RWInterlockedIncrement(&_dwEventsReleasedCount); -#endif - - return; -} - -//+------------------------------------------------------------------- -// -// Method: CRWLock::GetWriterEvent public -// -// Synopsis: Helper function for obtaining a auto reset event used -// for serializing writers. It utilizes event cache -// -//+------------------------------------------------------------------- -CLREvent* CRWLock::GetWriterEvent(HRESULT *pHR) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - } - CONTRACTL_END; - - *pHR = S_OK; - //GC could happen in ~CLREvent or EH. "this" is a GC object so it could be moved - //during GC. So we need to cache the field before GC could happen - CLREvent * result = _hWriterEvent; - - if(_hWriterEvent == NULL) - { - EX_TRY - { - CLREvent *pEvent = new CLREvent(); - NewHolder hWriterEvent (pEvent); - hWriterEvent->CreateRWLockWriterEvent(FALSE,this); - if(hWriterEvent) - { - if(RWInterlockedCompareExchangePointer((PVOID*) &_hWriterEvent, - hWriterEvent.GetValue(), - NULL) == NULL) - { - hWriterEvent.SuppressRelease(); - } - //GC could happen in ~CLREvent or EH. "this" is a GC object so it could be moved - //during GC. So we need to cache the field before GC could happen. - result = _hWriterEvent; - } - } - EX_CATCH - { - *pHR = GET_EXCEPTION()->GetHR(); - } - EX_END_CATCH(SwallowAllExceptions); - } - - return(result); -} - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::GetReaderEvent public -// -// Synopsis: Helper function for obtaining a manula reset event used -// by readers to wait when a writer holds the lock. -// It utilizes event cache -// -//+------------------------------------------------------------------- -CLREvent* CRWLock::GetReaderEvent(HRESULT *pHR) -{ - CONTRACTL - { - NOTHROW; - GC_TRIGGERS; - } - CONTRACTL_END; - - *pHR = S_OK; - //GC could happen in ~CLREvent or EH. "this" is a GC object so it could be moved - //during GC. So we need to cache the field before GC could happen - CLREvent * result = _hReaderEvent; - - if(_hReaderEvent == NULL) - { - EX_TRY - { - CLREvent *pEvent = new CLREvent(); - NewHolder hReaderEvent (pEvent); - hReaderEvent->CreateRWLockReaderEvent(FALSE, this); - if(hReaderEvent) - { - if(RWInterlockedCompareExchangePointer((PVOID*) &_hReaderEvent, - hReaderEvent.GetValue(), - NULL) == NULL) - { - hReaderEvent.SuppressRelease(); - } - //GC could happen in ~CLREvent or EH. "this" is a GC object so it could be moved - //during GC. So we need to cache the field before GC could happen - result = _hReaderEvent; - } - } - EX_CATCH - { - *pHR = GET_EXCEPTION()->GetHR(); - } - EX_END_CATCH(SwallowAllExceptions); - } - - return(result); -} - -//+------------------------------------------------------------------- -// -// Method: CRWLock::StaticRecoverLock public -// -// Synopsis: Helper function to restore the lock to -// the original state -// - -// -//+------------------------------------------------------------------- -void CRWLock::StaticRecoverLock( - CRWLock **ppRWLock, - LockCookie *pLockCookie, - DWORD dwFlags) -{ - CONTRACTL - { - THROWS; // StaticAcquireWriterLock can throw exception - GC_TRIGGERS; - CAN_TAKE_LOCK; - } - CONTRACTL_END; - - DWORD dwTimeout = (gdwDefaultTimeout > gdwReasonableTimeout) - ? gdwDefaultTimeout - : gdwReasonableTimeout; - - Thread *pThread = GetThread(); - _ASSERTE (pThread); - - EX_TRY - { - // Check if the thread was a writer - if(dwFlags & COOKIE_WRITER) - { - // Acquire writer lock - StaticAcquireWriterLock(ppRWLock, dwTimeout); - _ASSERTE (pThread->m_dwLockCount >= (*ppRWLock)->_wWriterLevel); - ASSERT_UNLESS_NO_DEBUG_STATE(__pClrDebugState->GetLockCount(kDbgStateLockType_User) >= (*ppRWLock)->_wWriterLevel); - pThread->m_dwLockCount -= (*ppRWLock)->_wWriterLevel; - USER_LOCK_RELEASED_MULTIPLE((*ppRWLock)->_wWriterLevel, GetPtrForLockContract(ppRWLock)); - (*ppRWLock)->_wWriterLevel = pLockCookie->wWriterLevel; - pThread->m_dwLockCount += (*ppRWLock)->_wWriterLevel; - USER_LOCK_TAKEN_MULTIPLE((*ppRWLock)->_wWriterLevel, GetPtrForLockContract(ppRWLock)); - } - // Check if the thread was a reader - else if(dwFlags & COOKIE_READER) - { - StaticAcquireReaderLock(ppRWLock, dwTimeout); - LockEntry *pLockEntry = (*ppRWLock)->GetLockEntry(); - _ASSERTE(pLockEntry); - _ASSERTE (pThread->m_dwLockCount >= pLockEntry->wReaderLevel); - ASSERT_UNLESS_NO_DEBUG_STATE(__pClrDebugState->GetLockCount(kDbgStateLockType_User) >= pLockEntry->wReaderLevel); - pThread->m_dwLockCount -= pLockEntry->wReaderLevel; - USER_LOCK_RELEASED_MULTIPLE(pLockEntry->wReaderLevel, GetPtrForLockContract(ppRWLock)); - pLockEntry->wReaderLevel = pLockCookie->wReaderLevel; - pThread->m_dwLockCount += pLockEntry->wReaderLevel; - USER_LOCK_TAKEN_MULTIPLE(pLockEntry->wReaderLevel, GetPtrForLockContract(ppRWLock)); - } - } - EX_CATCH - { - // Removed an assert here. This error is expected in case of - // ThreadAbort. - COMPlusThrowWin32(RWLOCK_RECOVERY_FAILURE); - } - EX_END_CATCH_UNREACHABLE -} - -//+------------------------------------------------------------------- -// -// Method: CRWLock::StaticAcquireReaderLockPublic public -// -// Synopsis: Public access to StaticAcquireReaderLock -// -//+------------------------------------------------------------------- -FCIMPL2(void, CRWLock::StaticAcquireReaderLockPublic, CRWLock *pRWLockUNSAFE, DWORD dwDesiredTimeout) -{ - FCALL_CONTRACT; - - if (pRWLockUNSAFE == NULL) - { - FCThrowVoid(kNullReferenceException); - } - - OBJECTREF pRWLock = ObjectToOBJECTREF((Object*)pRWLockUNSAFE); - HELPER_METHOD_FRAME_BEGIN_1(pRWLock); - - StaticAcquireReaderLock((CRWLock**)&pRWLock, dwDesiredTimeout); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::StaticAcquireReaderLock private -// -// Synopsis: Makes the thread a reader. Supports nested reader locks. -// -//+------------------------------------------------------------------- - -void CRWLock::StaticAcquireReaderLock( - CRWLock **ppRWLock, - DWORD dwDesiredTimeout) -{ - - CONTRACTL - { - THROWS; - GC_TRIGGERS; // CLREvent::Wait is GC_TRIGGERS - CAN_TAKE_LOCK; - PRECONDITION(CheckPointer(ppRWLock)); - PRECONDITION(CheckPointer(*ppRWLock)); - } - CONTRACTL_END; - - TESTHOOKCALL(AppDomainCanBeUnloaded(GetThread()->GetDomain()->GetId().m_dwId,FALSE)); - - if (GetThread()->IsAbortRequested()) { - GetThread()->HandleThreadAbort(); - } - - LockEntry *pLockEntry = (*ppRWLock)->FastGetOrCreateLockEntry(); - if (pLockEntry == NULL) - { - COMPlusThrowWin32(STATUS_NO_MEMORY); - } - - DWORD dwStatus = WAIT_OBJECT_0; - // Check for the fast path - if(RWInterlockedCompareExchange(&(*ppRWLock)->_dwState, READER, 0) == 0) - { - _ASSERTE(pLockEntry->wReaderLevel == 0); - } - // Check for nested reader - else if(pLockEntry->wReaderLevel != 0) - { - _ASSERTE((*ppRWLock)->_dwState & READERS_MASK); - - if (pLockEntry->wReaderLevel == RWLOCK_MAX_ACQUIRE_COUNT) { - COMPlusThrow(kOverflowException, W("Overflow_UInt16")); - } - ++pLockEntry->wReaderLevel; - INCTHREADLOCKCOUNT(); - USER_LOCK_TAKEN(GetPtrForLockContract(ppRWLock)); - return; - } - // Check if the thread already has writer lock - else if((*ppRWLock)->_dwWriterID == GetThread()->GetThreadId()) - { - StaticAcquireWriterLock(ppRWLock, dwDesiredTimeout); - (*ppRWLock)->FastRecycleLockEntry(pLockEntry); - return; - } - else - { - DWORD dwSpinCount; - DWORD dwCurrentState, dwKnownState; - - // Initialize - dwSpinCount = 0; - dwCurrentState = (*ppRWLock)->_dwState; - do - { - dwKnownState = dwCurrentState; - - // Reader need not wait if there are only readers and no writer - if((dwKnownState < READERS_MASK) || - (((dwKnownState & READER_SIGNALED) && ((dwKnownState & WRITER) == 0)) && - (((dwKnownState & READERS_MASK) + - ((dwKnownState & WAITING_READERS_MASK) >> WAITING_READERS_SHIFT)) <= - (READERS_MASK - 2)))) - { - // Add to readers - dwCurrentState = RWInterlockedCompareExchange(&(*ppRWLock)->_dwState, - (dwKnownState + READER), - dwKnownState); - if(dwCurrentState == dwKnownState) - { - // One more reader - break; - } - } - // Check for too many Readers or waiting readers or signaling in progress - else if(((dwKnownState & READERS_MASK) == READERS_MASK) || - ((dwKnownState & WAITING_READERS_MASK) == WAITING_READERS_MASK) || - ((dwKnownState & CACHING_EVENTS) == READER_SIGNALED)) - { - // Sleep - GetThread()->UserSleep(1000); - - // Update to latest state - dwSpinCount = 0; - dwCurrentState = (*ppRWLock)->_dwState; - } - // Check if events are being cached - else if((dwKnownState & CACHING_EVENTS) == CACHING_EVENTS) - { - if(++dwSpinCount > gdwDefaultSpinCount) - { - RWSleep(1); - dwSpinCount = 0; - } - dwCurrentState = (*ppRWLock)->_dwState; - } - // Check spin count - else if(++dwSpinCount <= gdwDefaultSpinCount) - { - dwCurrentState = (*ppRWLock)->_dwState; - } - else - { - // Add to waiting readers - dwCurrentState = RWInterlockedCompareExchange(&(*ppRWLock)->_dwState, - (dwKnownState + WAITING_READER), - dwKnownState); - if(dwCurrentState == dwKnownState) - { - CLREvent* hReaderEvent; - DWORD dwModifyState; - - // One more waiting reader -#ifdef RWLOCK_STATISTICS - RWInterlockedIncrement(&(*ppRWLock)->_dwReaderContentionCount); -#endif - HRESULT hr; - hReaderEvent = (*ppRWLock)->GetReaderEvent(&hr); - if(hReaderEvent) - { - dwStatus = RWWaitForSingleObject(hReaderEvent, dwDesiredTimeout); - VALIDATE_LOCK(*ppRWLock); - - // StaticAcquireReaderLock can have reentry via pumping while waiting for - // hReaderEvent, which may change pLockEntry's state from underneath us. - if ((pLockEntry->dwLLockID != (*ppRWLock)->_dwLLockID) || - (pLockEntry->dwULockID != (*ppRWLock)->_dwULockID)) - { - pLockEntry = (*ppRWLock)->FastGetOrCreateLockEntry(); - if (pLockEntry == NULL) - { - COMPlusThrowWin32(STATUS_NO_MEMORY); - } - } - } - else - { - LOG((LF_SYNC, LL_WARNING, - "AcquireReaderLock failed to create reader " - "event for RWLock 0x%x\n", *ppRWLock)); - dwStatus = E_FAIL; - } - - if(dwStatus == WAIT_OBJECT_0) - { - _ASSERTE((*ppRWLock)->_dwState & READER_SIGNALED); - _ASSERTE(((*ppRWLock)->_dwState & READERS_MASK) < READERS_MASK); - dwModifyState = READER - WAITING_READER; - } - else - { - dwModifyState = (DWORD) -WAITING_READER; - if(dwStatus == WAIT_TIMEOUT) - { - LOG((LF_SYNC, LL_WARNING, - "Timed out trying to acquire reader lock " - "for RWLock 0x%x\n", *ppRWLock)); - hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT); - } - else if(dwStatus == WAIT_IO_COMPLETION) - { - LOG((LF_SYNC, LL_WARNING, - "Thread interrupted while trying to acquire reader lock " - "for RWLock 0x%x\n", *ppRWLock)); - hr = COR_E_THREADINTERRUPTED; - } - else if (dwStatus == WAIT_FAILED) - { - if (SUCCEEDED(hr)) - { - dwStatus = GetLastError(); - if (dwStatus == WAIT_OBJECT_0) - { - dwStatus = WAIT_FAILED; - } - hr = HRESULT_FROM_WIN32(dwStatus); - LOG((LF_SYNC, LL_WARNING, - "WaitForSingleObject on Event 0x%x failed for " - "RWLock 0x%x with status code 0x%x\n", - hReaderEvent, *ppRWLock, dwStatus)); - } - } - } - - // One less waiting reader and he may have become a reader - dwKnownState = RWInterlockedExchangeAdd(&(*ppRWLock)->_dwState, dwModifyState); - - // Check for last signaled waiting reader - if(dwStatus == WAIT_OBJECT_0) - { - _ASSERTE(dwKnownState & READER_SIGNALED); - _ASSERTE((dwKnownState & READERS_MASK) < READERS_MASK); - if((dwKnownState & WAITING_READERS_MASK) == WAITING_READER) - { - // Reset the event and lower reader signaled flag - RWResetEvent(hReaderEvent); - RWInterlockedExchangeAdd(&(*ppRWLock)->_dwState, -READER_SIGNALED); - } - } - else - { - if(((dwKnownState & WAITING_READERS_MASK) == WAITING_READER) && - (dwKnownState & READER_SIGNALED)) - { - HRESULT hr1; - if(hReaderEvent == NULL) - hReaderEvent = (*ppRWLock)->GetReaderEvent(&hr1); - _ASSERTE(hReaderEvent); - - // Ensure the event is signalled before resetting it. - DWORD dwTemp; - dwTemp = hReaderEvent->Wait(INFINITE, FALSE); - _ASSERTE(dwTemp == WAIT_OBJECT_0); - _ASSERTE(((*ppRWLock)->_dwState & READERS_MASK) < READERS_MASK); - - // Reset the event and lower reader signaled flag - RWResetEvent(hReaderEvent); - RWInterlockedExchangeAdd(&(*ppRWLock)->_dwState, (READER - READER_SIGNALED)); - - // Honor the orginal status - ++pLockEntry->wReaderLevel; - INCTHREADLOCKCOUNT(); - USER_LOCK_TAKEN(GetPtrForLockContract(ppRWLock)); - StaticReleaseReaderLock(ppRWLock); - } - else - { - (*ppRWLock)->FastRecycleLockEntry(pLockEntry); - } - - _ASSERTE((pLockEntry == NULL) || - ((pLockEntry->dwLLockID == 0) && - (pLockEntry->wReaderLevel == 0))); - if(fBreakOnErrors) // fBreakOnErrors == FALSE so will be optimized out. - { - _ASSERTE(!"Failed to acquire reader lock"); - DebugBreak(); - } - - // Prepare the frame for throwing an exception - if ((DWORD)HOST_E_DEADLOCK == dwStatus) - { - // So that the error message is in the exception. - RaiseDeadLockException(); - } else if ((DWORD)COR_E_THREADINTERRUPTED == dwStatus) { - COMPlusThrow(kThreadInterruptedException); - } - else - { - COMPlusThrowWin32 (hr); - } - } - - // Sanity check - _ASSERTE(dwStatus == WAIT_OBJECT_0); - break; - } - } - YieldProcessor(); // Indicate to the processor that we are spining - } while(TRUE); - } - - // Success - _ASSERTE(dwStatus == WAIT_OBJECT_0); - _ASSERTE(((*ppRWLock)->_dwState & WRITER) == 0); - _ASSERTE((*ppRWLock)->_dwState & READERS_MASK); - ++pLockEntry->wReaderLevel; - INCTHREADLOCKCOUNT(); - USER_LOCK_TAKEN(GetPtrForLockContract(ppRWLock)); -#ifdef RWLOCK_STATISTICS - RWInterlockedIncrement(&(*ppRWLock)->_dwReaderEntryCount); -#endif - return; -} - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::StaticAcquireWriterLockPublic public -// -// Synopsis: Public access to StaticAcquireWriterLock -// -//+------------------------------------------------------------------- -FCIMPL2(void, CRWLock::StaticAcquireWriterLockPublic, CRWLock *pRWLockUNSAFE, DWORD dwDesiredTimeout) -{ - FCALL_CONTRACT; - - if (pRWLockUNSAFE == NULL) - { - FCThrowVoid(kNullReferenceException); - } - - OBJECTREF pRWLock = ObjectToOBJECTREF((Object*)pRWLockUNSAFE); - HELPER_METHOD_FRAME_BEGIN_1(pRWLock); - - StaticAcquireWriterLock((CRWLock**)&pRWLock, dwDesiredTimeout); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::StaticAcquireWriterLock private -// -// Synopsis: Makes the thread a writer. Supports nested writer -// locks -// -//+------------------------------------------------------------------- - -void CRWLock::StaticAcquireWriterLock( - CRWLock **ppRWLock, - DWORD dwDesiredTimeout) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; // CLREvent::Wait can trigger GC - CAN_TAKE_LOCK; - PRECONDITION((CheckPointer(ppRWLock))); - PRECONDITION((CheckPointer(*ppRWLock))); - } - CONTRACTL_END; - - TESTHOOKCALL(AppDomainCanBeUnloaded(GetThread()->GetDomain()->GetId().m_dwId,FALSE)); - if (GetThread()->IsAbortRequested()) { - GetThread()->HandleThreadAbort(); - } - - // Declare locals needed for setting up frame - DWORD dwThreadID = GetThread()->GetThreadId(); - DWORD dwStatus; - - // Check for the fast path - if(RWInterlockedCompareExchange(&(*ppRWLock)->_dwState, WRITER, 0) == 0) - { - _ASSERTE(((*ppRWLock)->_dwState & READERS_MASK) == 0); - } - // Check if the thread already has writer lock - else if((*ppRWLock)->_dwWriterID == dwThreadID) - { - if ((*ppRWLock)->_wWriterLevel == RWLOCK_MAX_ACQUIRE_COUNT) { - COMPlusThrow(kOverflowException, W("Overflow_UInt16")); - } - ++(*ppRWLock)->_wWriterLevel; - INCTHREADLOCKCOUNT(); - USER_LOCK_TAKEN(GetPtrForLockContract(ppRWLock)); - return; - } - else - { - DWORD dwCurrentState, dwKnownState; - DWORD dwSpinCount; - - // Initialize - dwSpinCount = 0; - dwCurrentState = (*ppRWLock)->_dwState; - do - { - dwKnownState = dwCurrentState; - - // Writer need not wait if there are no readers and writer - if((dwKnownState == 0) || (dwKnownState == CACHING_EVENTS)) - { - // Can be a writer - dwCurrentState = RWInterlockedCompareExchange(&(*ppRWLock)->_dwState, - (dwKnownState + WRITER), - dwKnownState); - if(dwCurrentState == dwKnownState) - { - // Only writer - break; - } - } - // Check for too many waiting writers - else if(((dwKnownState & WAITING_WRITERS_MASK) == WAITING_WRITERS_MASK)) - { - // Sleep - GetThread()->UserSleep(1000); - - // Update to latest state - dwSpinCount = 0; - dwCurrentState = (*ppRWLock)->_dwState; - } - // Check if events are being cached - else if((dwKnownState & CACHING_EVENTS) == CACHING_EVENTS) - { - if(++dwSpinCount > gdwDefaultSpinCount) - { - RWSleep(1); - dwSpinCount = 0; - } - dwCurrentState = (*ppRWLock)->_dwState; - } - // Check spin count - else if(++dwSpinCount <= gdwDefaultSpinCount) - { - dwCurrentState = (*ppRWLock)->_dwState; - } - else - { - // Add to waiting writers - dwCurrentState = RWInterlockedCompareExchange(&(*ppRWLock)->_dwState, - (dwKnownState + WAITING_WRITER), - dwKnownState); - if(dwCurrentState == dwKnownState) - { - CLREvent* hWriterEvent; - DWORD dwModifyState; - - // One more waiting writer -#ifdef RWLOCK_STATISTICS - RWInterlockedIncrement(&(*ppRWLock)->_dwWriterContentionCount); -#endif - HRESULT hr; - hWriterEvent = (*ppRWLock)->GetWriterEvent(&hr); - if(hWriterEvent) - { - dwStatus = RWWaitForSingleObject(hWriterEvent, dwDesiredTimeout); - VALIDATE_LOCK(*ppRWLock); - } - else - { - LOG((LF_SYNC, LL_WARNING, - "AcquireWriterLock failed to create writer " - "event for RWLock 0x%x\n", *ppRWLock)); - dwStatus = WAIT_FAILED; - } - - if(dwStatus == WAIT_OBJECT_0) - { - _ASSERTE((*ppRWLock)->_dwState & WRITER_SIGNALED); - dwModifyState = WRITER - WAITING_WRITER - WRITER_SIGNALED; - } - else - { - dwModifyState = (DWORD) -WAITING_WRITER; - if(dwStatus == WAIT_TIMEOUT) - { - LOG((LF_SYNC, LL_WARNING, - "Timed out trying to acquire writer " - "lock for RWLock 0x%x\n", *ppRWLock)); - hr = HRESULT_FROM_WIN32 (ERROR_TIMEOUT); - } - else if(dwStatus == WAIT_IO_COMPLETION) - { - LOG((LF_SYNC, LL_WARNING, - "Thread interrupted while trying to acquire writer lock " - "for RWLock 0x%x\n", *ppRWLock)); - hr = COR_E_THREADINTERRUPTED; - } - else if (dwStatus == WAIT_FAILED) - { - if (SUCCEEDED(hr)) - { - dwStatus = GetLastError(); - if (dwStatus == WAIT_OBJECT_0) - { - dwStatus = WAIT_FAILED; - } - hr = HRESULT_FROM_WIN32(dwStatus); - LOG((LF_SYNC, LL_WARNING, - "WaitForSingleObject on Event 0x%x failed for " - "RWLock 0x%x with status code 0x%x", - hWriterEvent, *ppRWLock, dwStatus)); - } - } - } - - // One less waiting writer and he may have become a writer - dwKnownState = RWInterlockedExchangeAdd(&(*ppRWLock)->_dwState, dwModifyState); - - // Check for last timing out signaled waiting writer - if(dwStatus == WAIT_OBJECT_0) - { - // Common case - } - else - { - if((dwKnownState & WRITER_SIGNALED) && - ((dwKnownState & WAITING_WRITERS_MASK) == WAITING_WRITER)) - { - HRESULT hr1; - if(hWriterEvent == NULL) - hWriterEvent = (*ppRWLock)->GetWriterEvent(&hr1); - _ASSERTE(hWriterEvent); - do - { - dwKnownState = (*ppRWLock)->_dwState; - if((dwKnownState & WRITER_SIGNALED) && - ((dwKnownState & WAITING_WRITERS_MASK) == 0)) - { - DWORD dwTemp = hWriterEvent->Wait(10, FALSE); - if(dwTemp == WAIT_OBJECT_0) - { - dwKnownState = RWInterlockedExchangeAdd(&(*ppRWLock)->_dwState, (WRITER - WRITER_SIGNALED)); - _ASSERTE(dwKnownState & WRITER_SIGNALED); - _ASSERTE((dwKnownState & WRITER) == 0); - - // Honor the orginal status - (*ppRWLock)->_dwWriterID = dwThreadID; - Thread *pThread = GetThread(); - _ASSERTE (pThread); - _ASSERTE ((*ppRWLock)->_wWriterLevel == 0); - pThread->m_dwLockCount ++; - USER_LOCK_TAKEN(GetPtrForLockContract(ppRWLock)); - (*ppRWLock)->_wWriterLevel = 1; - StaticReleaseWriterLock(ppRWLock); - break; - } - // else continue; - } - else - break; - }while(TRUE); - } - - if(fBreakOnErrors) // fBreakOnErrors == FALSE so will be optimized out. - { - _ASSERTE(!"Failed to acquire writer lock"); - DebugBreak(); - } - - // Prepare the frame for throwing an exception - if ((DWORD)HOST_E_DEADLOCK == dwStatus) - { - // So that the error message is in the exception. - RaiseDeadLockException(); - } else if ((DWORD)COR_E_THREADINTERRUPTED == dwStatus) { - COMPlusThrow(kThreadInterruptedException); - } - else - { - COMPlusThrowWin32(hr); - } - } - - // Sanity check - _ASSERTE(dwStatus == WAIT_OBJECT_0); - break; - } - } - YieldProcessor(); // indicate to the processor that we are spinning - } while(TRUE); - } - - // Success - _ASSERTE((*ppRWLock)->_dwState & WRITER); - _ASSERTE(((*ppRWLock)->_dwState & READERS_MASK) == 0); - _ASSERTE((*ppRWLock)->_dwWriterID == 0); - - // Save threadid of the writer - (*ppRWLock)->_dwWriterID = dwThreadID; - (*ppRWLock)->_wWriterLevel = 1; - INCTHREADLOCKCOUNT(); - USER_LOCK_TAKEN(GetPtrForLockContract(ppRWLock)); - ++(*ppRWLock)->_dwWriterSeqNum; -#ifdef RWLOCK_STATISTICS - ++(*ppRWLock)->_dwWriterEntryCount; -#endif - return; -} - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::StaticReleaseWriterLockPublic public -// -// Synopsis: Public access to StaticReleaseWriterLock -// -//+------------------------------------------------------------------- -FCIMPL1(void, CRWLock::StaticReleaseWriterLockPublic, CRWLock *pRWLockUNSAFE) -{ - FCALL_CONTRACT; - - if (pRWLockUNSAFE == NULL) - { - FCThrowVoid(kNullReferenceException); - } - - OBJECTREF pRWLock = ObjectToOBJECTREF((Object*)pRWLockUNSAFE); - - HELPER_METHOD_FRAME_BEGIN_ATTRIB_1(Frame::FRAME_ATTR_NO_THREAD_ABORT, pRWLock); - - // We don't want to block thread abort when we need to construct exception in - // unwind-continue handler. - // note that we cannot use this holder in FCALLs outside our HMF since it breaks the epilog walker on x86! - ThreadPreventAbortHolder preventAbortIn; - - StaticReleaseWriterLock((CRWLock**)&pRWLock); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::StaticReleaseWriterLock private -// -// Synopsis: Removes the thread as a writer if not a nested -// call to release the lock -// -//+------------------------------------------------------------------- -void CRWLock::StaticReleaseWriterLock( - CRWLock **ppRWLock) -{ - - CONTRACTL - { - THROWS; - GC_TRIGGERS; - PRECONDITION((CheckPointer(ppRWLock))); - PRECONDITION((CheckPointer(*ppRWLock))); - } - CONTRACTL_END; - - DWORD dwThreadID = GetThread()->GetThreadId(); - - // Check validity of caller - if((*ppRWLock)->_dwWriterID == dwThreadID) - { - DECTHREADLOCKCOUNT(); - USER_LOCK_RELEASED(GetPtrForLockContract(ppRWLock)); - // Check for nested release - if(--(*ppRWLock)->_wWriterLevel == 0) - { - DWORD dwCurrentState, dwKnownState, dwModifyState; - BOOL fCacheEvents; - CLREvent* hReaderEvent = NULL, *hWriterEvent = NULL; - - // Not a writer any more - (*ppRWLock)->_dwWriterID = 0; - dwCurrentState = (*ppRWLock)->_dwState; - do - { - dwKnownState = dwCurrentState; - dwModifyState = (DWORD) -WRITER; - fCacheEvents = FALSE; - if(dwKnownState & WAITING_READERS_MASK) - { - HRESULT hr; - hReaderEvent = (*ppRWLock)->GetReaderEvent(&hr); - if(hReaderEvent == NULL) - { - LOG((LF_SYNC, LL_WARNING, - "ReleaseWriterLock failed to create " - "reader event for RWLock 0x%x\n", *ppRWLock)); - RWSleep(100); - dwCurrentState = (*ppRWLock)->_dwState; - dwKnownState = 0; - _ASSERTE(dwCurrentState != dwKnownState); - continue; - } - dwModifyState += READER_SIGNALED; - } - else if(dwKnownState & WAITING_WRITERS_MASK) - { - HRESULT hr; - hWriterEvent = (*ppRWLock)->GetWriterEvent(&hr); - if(hWriterEvent == NULL) - { - LOG((LF_SYNC, LL_WARNING, - "ReleaseWriterLock failed to create " - "writer event for RWLock 0x%x\n", *ppRWLock)); - RWSleep(100); - dwCurrentState = (*ppRWLock)->_dwState; - dwKnownState = 0; - _ASSERTE(dwCurrentState != dwKnownState); - continue; - } - dwModifyState += WRITER_SIGNALED; - } - else if(((*ppRWLock)->_hReaderEvent || (*ppRWLock)->_hWriterEvent) && - (dwKnownState == WRITER)) - { - fCacheEvents = TRUE; - dwModifyState += CACHING_EVENTS; - } - - // Sanity checks - _ASSERTE((dwKnownState & READERS_MASK) == 0); - - dwCurrentState = RWInterlockedCompareExchange(&(*ppRWLock)->_dwState, - (dwKnownState + dwModifyState), - dwKnownState); - } while(dwCurrentState != dwKnownState); - - // Check for waiting readers - if(dwKnownState & WAITING_READERS_MASK) - { - _ASSERTE((*ppRWLock)->_dwState & READER_SIGNALED); - _ASSERTE(hReaderEvent); - RWSetEvent(hReaderEvent); - } - // Check for waiting writers - else if(dwKnownState & WAITING_WRITERS_MASK) - { - _ASSERTE((*ppRWLock)->_dwState & WRITER_SIGNALED); - _ASSERTE(hWriterEvent); - RWSetEvent(hWriterEvent); - } - // Check for the need to release events - else if(fCacheEvents) - { - (*ppRWLock)->ReleaseEvents(); - } - - Thread *pThread = GetThread(); - TESTHOOKCALL(AppDomainCanBeUnloaded(pThread->GetDomain()->GetId().m_dwId,FALSE)); - if (pThread->IsAbortRequested()) { - pThread->HandleThreadAbort(); - } - - } - } - else - { - if(fBreakOnErrors) // fBreakOnErrors == FALSE so will be optimized out. - { - _ASSERTE(!"Attempt to release writer lock on a wrong thread"); - DebugBreak(); - } - COMPlusThrowWin32(ERROR_NOT_OWNER); - } - - return; -} - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::StaticReleaseReaderLockPublic public -// -// Synopsis: Public access to StaticReleaseReaderLock -// -//+------------------------------------------------------------------- -FCIMPL1(void, CRWLock::StaticReleaseReaderLockPublic, CRWLock *pRWLockUNSAFE) -{ - FCALL_CONTRACT; - - if (pRWLockUNSAFE == NULL) - { - FCThrowVoid(kNullReferenceException); - } - - OBJECTREF pRWLock = ObjectToOBJECTREF((Object*)pRWLockUNSAFE); - - HELPER_METHOD_FRAME_BEGIN_ATTRIB_1(Frame::FRAME_ATTR_NO_THREAD_ABORT, pRWLock); - - // note that we cannot use this holder in FCALLs outside our HMF since it breaks the epilog walker on x86! - ThreadPreventAbortHolder preventAbortIn; - - StaticReleaseReaderLock((CRWLock**)&pRWLock); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::StaticReleaseReaderLock private -// -// Synopsis: Removes the thread as a reader -// -//+------------------------------------------------------------------- - -void CRWLock::StaticReleaseReaderLock( - CRWLock **ppRWLock) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - PRECONDITION((CheckPointer(ppRWLock))); - PRECONDITION((CheckPointer(*ppRWLock))); - } - CONTRACTL_END; - - // Check if the thread has writer lock - if((*ppRWLock)->_dwWriterID == GetThread()->GetThreadId()) - { - StaticReleaseWriterLock(ppRWLock); - } - else - { - LockEntry *pLockEntry = (*ppRWLock)->GetLockEntry(); - if(pLockEntry) - { - --pLockEntry->wReaderLevel; - DECTHREADLOCKCOUNT(); - USER_LOCK_RELEASED(GetPtrForLockContract(ppRWLock)); - if(pLockEntry->wReaderLevel == 0) - { - DWORD dwCurrentState, dwKnownState, dwModifyState; - BOOL fLastReader, fCacheEvents = FALSE; - CLREvent* hReaderEvent = NULL, *hWriterEvent = NULL; - - // Sanity checks - _ASSERTE(((*ppRWLock)->_dwState & WRITER) == 0); - _ASSERTE((*ppRWLock)->_dwState & READERS_MASK); - - // Not a reader any more - dwCurrentState = (*ppRWLock)->_dwState; - do - { - dwKnownState = dwCurrentState; - dwModifyState = (DWORD) -READER; - if((dwKnownState & (READERS_MASK | READER_SIGNALED)) == READER) - { - fLastReader = TRUE; - fCacheEvents = FALSE; - if(dwKnownState & WAITING_WRITERS_MASK) - { - HRESULT hr; - hWriterEvent = (*ppRWLock)->GetWriterEvent(&hr); - if(hWriterEvent == NULL) - { - LOG((LF_SYNC, LL_WARNING, - "ReleaseReaderLock failed to create " - "writer event for RWLock 0x%x\n", *ppRWLock)); - RWSleep(100); - dwCurrentState = (*ppRWLock)->_dwState; - dwKnownState = 0; - _ASSERTE(dwCurrentState != dwKnownState); - continue; - } - dwModifyState += WRITER_SIGNALED; - } - else if(dwKnownState & WAITING_READERS_MASK) - { - HRESULT hr; - hReaderEvent = (*ppRWLock)->GetReaderEvent(&hr); - if(hReaderEvent == NULL) - { - LOG((LF_SYNC, LL_WARNING, - "ReleaseReaderLock failed to create " - "reader event\n", *ppRWLock)); - RWSleep(100); - dwCurrentState = (*ppRWLock)->_dwState; - dwKnownState = 0; - _ASSERTE(dwCurrentState != dwKnownState); - continue; - } - dwModifyState += READER_SIGNALED; - } - else if(((*ppRWLock)->_hReaderEvent || (*ppRWLock)->_hWriterEvent) && - (dwKnownState == READER)) - { - fCacheEvents = TRUE; - dwModifyState += CACHING_EVENTS; - } - } - else - { - fLastReader = FALSE; - } - - // Sanity checks - _ASSERTE((dwKnownState & WRITER) == 0); - _ASSERTE(dwKnownState & READERS_MASK); - - dwCurrentState = RWInterlockedCompareExchange(&(*ppRWLock)->_dwState, - (dwKnownState + dwModifyState), - dwKnownState); - } while(dwCurrentState != dwKnownState); - - // Check for last reader - if(fLastReader) - { - // Check for waiting writers - if(dwKnownState & WAITING_WRITERS_MASK) - { - _ASSERTE((*ppRWLock)->_dwState & WRITER_SIGNALED); - _ASSERTE(hWriterEvent); - RWSetEvent(hWriterEvent); - } - // Check for waiting readers - else if(dwKnownState & WAITING_READERS_MASK) - { - _ASSERTE((*ppRWLock)->_dwState & READER_SIGNALED); - _ASSERTE(hReaderEvent); - RWSetEvent(hReaderEvent); - } - // Check for the need to release events - else if(fCacheEvents) - { - (*ppRWLock)->ReleaseEvents(); - } - } - - // Recycle lock entry - RecycleLockEntry(pLockEntry); - - Thread *pThread = GetThread(); - TESTHOOKCALL(AppDomainCanBeUnloaded(pThread->GetDomain()->GetId().m_dwId,FALSE)); - - if (pThread->IsAbortRequested()) { - pThread->HandleThreadAbort(); - } - } - } - else - { - if(fBreakOnErrors) // fBreakOnErrors == FALSE so will be optimized out. - { - _ASSERTE(!"Attempt to release reader lock on a wrong thread"); - DebugBreak(); - } - COMPlusThrowWin32(ERROR_NOT_OWNER); - } - } - - return; -} - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::StaticDoUpgradeToWriterLockPublic private -// -// Synopsis: Public Access to StaticUpgradeToWriterLockPublic -// -// -//+------------------------------------------------------------------- -FCIMPL3(void, CRWLock::StaticDoUpgradeToWriterLockPublic, CRWLock *pRWLockUNSAFE, LockCookie * pLockCookie, DWORD dwDesiredTimeout) -{ - FCALL_CONTRACT; - - if (pRWLockUNSAFE == NULL) - { - FCThrowVoid(kNullReferenceException); - } - - OBJECTREF pRWLock = ObjectToOBJECTREF((Object*)pRWLockUNSAFE); - HELPER_METHOD_FRAME_BEGIN_1(pRWLock); - GCPROTECT_BEGININTERIOR (pLockCookie) - - StaticUpgradeToWriterLock((CRWLock**)&pRWLock, pLockCookie, dwDesiredTimeout); - - GCPROTECT_END (); - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - -//+------------------------------------------------------------------- -// -// Method: CRWLock::StaticUpgradeToWriterLock Private -// -// Synopsis: Upgrades to a writer lock. It returns a BOOL that -// indicates intervening writes. -// - -// -//+------------------------------------------------------------------- - -void CRWLock::StaticUpgradeToWriterLock( - CRWLock **ppRWLock, - LockCookie *pLockCookie, - DWORD dwDesiredTimeout) - -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - CAN_TAKE_LOCK; - } - CONTRACTL_END; - - DWORD dwThreadID = GetThread()->GetThreadId(); - - // Check if the thread is already a writer - if((*ppRWLock)->_dwWriterID == dwThreadID) - { - // Update cookie state - pLockCookie->dwFlags = UPGRADE_COOKIE | COOKIE_WRITER; - pLockCookie->wWriterLevel = (*ppRWLock)->_wWriterLevel; - - // Acquire the writer lock again - StaticAcquireWriterLock(ppRWLock, dwDesiredTimeout); - } - else - { - BOOL fAcquireWriterLock; - LockEntry *pLockEntry = (*ppRWLock)->GetLockEntry(); - if(pLockEntry == NULL) - { - fAcquireWriterLock = TRUE; - pLockCookie->dwFlags = UPGRADE_COOKIE | COOKIE_NONE; - } - else - { - // Sanity check - _ASSERTE((*ppRWLock)->_dwState & READERS_MASK); - _ASSERTE(pLockEntry->wReaderLevel); - - // Save lock state in the cookie - pLockCookie->dwFlags = UPGRADE_COOKIE | COOKIE_READER; - pLockCookie->wReaderLevel = pLockEntry->wReaderLevel; - pLockCookie->dwWriterSeqNum = (*ppRWLock)->_dwWriterSeqNum; - - // If there is only one reader, try to convert reader to a writer - DWORD dwKnownState = RWInterlockedCompareExchange(&(*ppRWLock)->_dwState, - WRITER, - READER); - if(dwKnownState == READER) - { - // Thread is no longer a reader - Thread* pThread = GetThread(); - _ASSERTE (pThread); - _ASSERTE (pThread->m_dwLockCount >= pLockEntry->wReaderLevel); - ASSERT_UNLESS_NO_DEBUG_STATE(__pClrDebugState->GetLockCount(kDbgStateLockType_User) >= pLockEntry->wReaderLevel); - pThread->m_dwLockCount -= pLockEntry->wReaderLevel; - USER_LOCK_RELEASED_MULTIPLE(pLockEntry->wReaderLevel, GetPtrForLockContract(ppRWLock)); - pLockEntry->wReaderLevel = 0; - RecycleLockEntry(pLockEntry); - - // Thread is a writer - (*ppRWLock)->_dwWriterID = dwThreadID; - (*ppRWLock)->_wWriterLevel = 1; - INCTHREADLOCKCOUNT(); - USER_LOCK_TAKEN(GetPtrForLockContract(ppRWLock)); - ++(*ppRWLock)->_dwWriterSeqNum; - fAcquireWriterLock = FALSE; - - // No intevening writes -#if RWLOCK_STATISTICS - ++(*ppRWLock)->_dwWriterEntryCount; -#endif - } - else - { - // Release the reader lock - Thread *pThread = GetThread(); - _ASSERTE (pThread); - _ASSERTE (pThread->m_dwLockCount >= (DWORD)(pLockEntry->wReaderLevel - 1)); - ASSERT_UNLESS_NO_DEBUG_STATE(__pClrDebugState->GetLockCount(kDbgStateLockType_User) >= - (DWORD)(pLockEntry->wReaderLevel - 1)); - pThread->m_dwLockCount -= (pLockEntry->wReaderLevel - 1); - USER_LOCK_RELEASED_MULTIPLE(pLockEntry->wReaderLevel - 1, GetPtrForLockContract(ppRWLock)); - pLockEntry->wReaderLevel = 1; - StaticReleaseReaderLock(ppRWLock); - fAcquireWriterLock = TRUE; - } - } - - // Check for the need to acquire the writer lock - if(fAcquireWriterLock) - { - - // Declare and Setup the frame as we are aware of the contention - // on the lock and the thread will most probably block - // to acquire writer lock - - EX_TRY - { - StaticAcquireWriterLock(ppRWLock, dwDesiredTimeout); - } - EX_CATCH - { - // Invalidate cookie - DWORD dwFlags = pLockCookie->dwFlags; - pLockCookie->dwFlags = INVALID_COOKIE; - - StaticRecoverLock(ppRWLock, pLockCookie, dwFlags & COOKIE_READER); - - EX_RETHROW; - } - EX_END_CATCH_UNREACHABLE - } - } - - - // Update the validation fields of the cookie - pLockCookie->dwThreadID = dwThreadID; - - return; -} - -//+------------------------------------------------------------------- -// -// Method: CRWLock::StaticDowngradeFromWriterLock public -// -// Synopsis: Downgrades from a writer lock. -// -//+------------------------------------------------------------------- - -inline CRWLock* GetLock(OBJECTREF orLock) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - return (CRWLock*)OBJECTREFToObject(orLock); -} - -FCIMPL2(void, CRWLock::StaticDowngradeFromWriterLock, CRWLock *pRWLockUNSAFE, LockCookie* pLockCookie) -{ - FCALL_CONTRACT; - STATIC_CONTRACT_CAN_TAKE_LOCK; - - DWORD dwThreadID = GetThread()->GetThreadId(); - - if (pRWLockUNSAFE == NULL) - { - FCThrowVoid(kNullReferenceException); - } - - if( NULL == pLockCookie) { - FCThrowVoid(kNullReferenceException); - } - - OBJECTREF pRWLock = ObjectToOBJECTREF((Object*)pRWLockUNSAFE); - HELPER_METHOD_FRAME_BEGIN_1(pRWLock); - - if (GetLock(pRWLock)->_dwWriterID != dwThreadID) - { - COMPlusThrowWin32(ERROR_NOT_OWNER); - } - - // Validate cookie - DWORD dwStatus; - if(((pLockCookie->dwFlags & INVALID_COOKIE) == 0) && - (pLockCookie->dwThreadID == dwThreadID)) - { - DWORD dwFlags = pLockCookie->dwFlags; - pLockCookie->dwFlags = INVALID_COOKIE; - - // Check if the thread was a reader - if(dwFlags & COOKIE_READER) - { - // Sanity checks - _ASSERTE(GetLock(pRWLock)->_wWriterLevel == 1); - - LockEntry *pLockEntry = GetLock(pRWLock)->FastGetOrCreateLockEntry(); - if(pLockEntry) - { - DWORD dwCurrentState, dwKnownState, dwModifyState; - CLREvent* hReaderEvent = NULL; - - // Downgrade to a reader - GetLock(pRWLock)->_dwWriterID = 0; - GetLock(pRWLock)->_wWriterLevel = 0; - DECTHREADLOCKCOUNT (); - USER_LOCK_RELEASED(GetPtrForLockContract((CRWLock**)&pRWLock)); - dwCurrentState = GetLock(pRWLock)->_dwState; - do - { - dwKnownState = dwCurrentState; - dwModifyState = READER - WRITER; - if(dwKnownState & WAITING_READERS_MASK) - { - HRESULT hr; - hReaderEvent = GetLock(pRWLock)->GetReaderEvent(&hr); - if(hReaderEvent == NULL) - { - LOG((LF_SYNC, LL_WARNING, - "DowngradeFromWriterLock failed to create " - "reader event for RWLock 0x%x\n", GetLock(pRWLock))); - RWSleep(100); - dwCurrentState = GetLock(pRWLock)->_dwState; - dwKnownState = 0; - _ASSERTE(dwCurrentState != dwKnownState); - continue; - } - dwModifyState += READER_SIGNALED; - } - - // Sanity checks - _ASSERTE((dwKnownState & READERS_MASK) == 0); - - dwCurrentState = RWInterlockedCompareExchange(&GetLock(pRWLock)->_dwState, - (dwKnownState + dwModifyState), - dwKnownState); - } while(dwCurrentState != dwKnownState); - - // Check for waiting readers - if(dwKnownState & WAITING_READERS_MASK) - { - _ASSERTE(GetLock(pRWLock)->_dwState & READER_SIGNALED); - _ASSERTE(hReaderEvent); - RWSetEvent(hReaderEvent); - } - - // Restore reader nesting level - Thread *pThread = GetThread(); - _ASSERTE (pThread); - _ASSERTE (pThread->m_dwLockCount >= pLockEntry->wReaderLevel); - ASSERT_UNLESS_NO_DEBUG_STATE(__pClrDebugState->GetLockCount(kDbgStateLockType_User) >= - pLockEntry->wReaderLevel); - pThread->m_dwLockCount -= pLockEntry->wReaderLevel; - USER_LOCK_RELEASED_MULTIPLE(pLockEntry->wReaderLevel, GetPtrForLockContract((CRWLock**)&pRWLock)); - pLockEntry->wReaderLevel = pLockCookie->wReaderLevel; - pThread->m_dwLockCount += pLockEntry->wReaderLevel; - USER_LOCK_TAKEN_MULTIPLE(pLockEntry->wReaderLevel, GetPtrForLockContract((CRWLock**)&pRWLock)); - #ifdef RWLOCK_STATISTICS - RWInterlockedIncrement(&GetLock(pRWLock)->_dwReaderEntryCount); - #endif - } - else - { - // Removed assert, as thread abort can occur normally - dwStatus = RWLOCK_RECOVERY_FAILURE; - goto ThrowException; - } - } - else if(dwFlags & (COOKIE_WRITER | COOKIE_NONE)) - { - // Release the writer lock - StaticReleaseWriterLock((CRWLock**)&pRWLock); - _ASSERTE((GetLock(pRWLock)->_dwWriterID != GetThread()->GetThreadId()) || - (dwFlags & COOKIE_WRITER)); - } - } - else - { - dwStatus = E_INVALIDARG; -ThrowException: - COMPlusThrowWin32(dwStatus); - } - - HELPER_METHOD_FRAME_END(); - - // Update the validation fields of the cookie - pLockCookie->dwThreadID = dwThreadID; - -} -FCIMPLEND - - -//+------------------------------------------------------------------- -// -// Method: CRWLock::StaticDoReleaseLock private -// -// Synopsis: Releases the lock held by the current thread -// -//+------------------------------------------------------------------- - -FCIMPL2(void, CRWLock::StaticDoReleaseLock, CRWLock *pRWLockUNSAFE, LockCookie * pLockCookie) -{ - FCALL_CONTRACT; - - if (pRWLockUNSAFE == NULL) - { - FCThrowVoid(kNullReferenceException); - } - - DWORD dwThreadID = GetThread()->GetThreadId(); - - OBJECTREF pRWLock = ObjectToOBJECTREF((Object*)pRWLockUNSAFE); - - HELPER_METHOD_FRAME_BEGIN_ATTRIB_1(Frame::FRAME_ATTR_NO_THREAD_ABORT, pRWLock); - - // note that we cannot use this holder in FCALLs outside our HMF since it breaks the epilog walker on x86! - ThreadPreventAbortHolder preventAbortIn; - - GCPROTECT_BEGININTERIOR (pLockCookie) - - // Check if the thread is a writer - if(GetLock(pRWLock)->_dwWriterID == dwThreadID) - { - // Save lock state in the cookie - pLockCookie->dwFlags = RELEASE_COOKIE | COOKIE_WRITER; - pLockCookie->dwWriterSeqNum = GetLock(pRWLock)->_dwWriterSeqNum; - pLockCookie->wWriterLevel = GetLock(pRWLock)->_wWriterLevel; - - // Release the writer lock - Thread *pThread = GetThread(); - _ASSERTE (pThread); - _ASSERTE (pThread->m_dwLockCount >= (DWORD)(GetLock(pRWLock)->_wWriterLevel - 1)); - ASSERT_UNLESS_NO_DEBUG_STATE(__pClrDebugState->GetLockCount(kDbgStateLockType_User) >= - (DWORD)(GetLock(pRWLock)->_wWriterLevel - 1)); - pThread->m_dwLockCount -= (GetLock(pRWLock)->_wWriterLevel - 1); - USER_LOCK_RELEASED_MULTIPLE(GetLock(pRWLock)->_wWriterLevel - 1, GetPtrForLockContract((CRWLock**)&pRWLock)); - GetLock(pRWLock)->_wWriterLevel = 1; - StaticReleaseWriterLock((CRWLock**)&pRWLock); - } - else - { - LockEntry *pLockEntry = GetLock(pRWLock)->GetLockEntry(); - if(pLockEntry) - { - // Sanity check - _ASSERTE(GetLock(pRWLock)->_dwState & READERS_MASK); - _ASSERTE(pLockEntry->wReaderLevel); - - // Save lock state in the cookie - pLockCookie->dwFlags = RELEASE_COOKIE | COOKIE_READER; - pLockCookie->wReaderLevel = pLockEntry->wReaderLevel; - pLockCookie->dwWriterSeqNum = GetLock(pRWLock)->_dwWriterSeqNum; - - // Release the reader lock - Thread *pThread = GetThread(); - _ASSERTE (pThread); - _ASSERTE (pThread->m_dwLockCount >= (DWORD)(pLockEntry->wReaderLevel - 1)); - ASSERT_UNLESS_NO_DEBUG_STATE(__pClrDebugState->GetLockCount(kDbgStateLockType_User) >= - (DWORD)(pLockEntry->wReaderLevel - 1)); - pThread->m_dwLockCount -= (pLockEntry->wReaderLevel - 1); - USER_LOCK_RELEASED_MULTIPLE(pLockEntry->wReaderLevel - 1, GetPtrForLockContract((CRWLock**)&pRWLock)); - pLockEntry->wReaderLevel = 1; - StaticReleaseReaderLock((CRWLock**)&pRWLock); - } - else - { - pLockCookie->dwFlags = RELEASE_COOKIE | COOKIE_NONE; - } - } - - GCPROTECT_END (); - - HELPER_METHOD_FRAME_END(); - - // Update the validation fields of the cookie - pLockCookie->dwThreadID = dwThreadID; -} -FCIMPLEND - -//+------------------------------------------------------------------- -// -// Method: CRWLock::StaticRestoreLockPublic public -// -// Synopsis: Public Access to StaticRestoreLock -// -// -//+------------------------------------------------------------------- - -FCIMPL2(void, CRWLock::StaticRestoreLockPublic, CRWLock *pRWLockUNSAFE, LockCookie* pLockCookie) -{ - FCALL_CONTRACT; - - if (pRWLockUNSAFE == NULL) { - FCThrowVoid(kNullReferenceException); - } - - if( NULL == pLockCookie) { - FCThrowVoid(kNullReferenceException); - } - - OBJECTREF pRWLock = ObjectToOBJECTREF((Object*)pRWLockUNSAFE); - HELPER_METHOD_FRAME_BEGIN_1(pRWLock); - - StaticRestoreLock((CRWLock**)&pRWLock, pLockCookie); - - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - -//+------------------------------------------------------------------- -// -// Method: CRWLock::StaticRestoreLock Private -// -// Synopsis: Restore the lock held by the current thread -// - -// -//+------------------------------------------------------------------- - -void CRWLock::StaticRestoreLock( - CRWLock **ppRWLock, - LockCookie *pLockCookie) -{ - CONTRACTL - { - THROWS; - CAN_TAKE_LOCK; - GC_TRIGGERS; // CRWLock::StaticAquireWriterLock can trigger GC - } - CONTRACTL_END; - - // Validate cookie - DWORD dwThreadID = GetThread()->GetThreadId(); - DWORD dwFlags = pLockCookie->dwFlags; - if(pLockCookie->dwThreadID == dwThreadID) - { - if (((*ppRWLock)->_dwWriterID == dwThreadID) || ((*ppRWLock)->GetLockEntry() != NULL)) - { - COMPlusThrow(kSynchronizationLockException, W("Arg_RWLockRestoreException")); - } - - // Check for the no contention case - pLockCookie->dwFlags = INVALID_COOKIE; - if(dwFlags & COOKIE_WRITER) - { - if(RWInterlockedCompareExchange(&(*ppRWLock)->_dwState, WRITER, 0) == 0) - { - // Restore writer nesting level - (*ppRWLock)->_dwWriterID = dwThreadID; - Thread *pThread = GetThread(); - _ASSERTE (pThread); - _ASSERTE (pThread->m_dwLockCount >= (*ppRWLock)->_wWriterLevel); - ASSERT_UNLESS_NO_DEBUG_STATE(__pClrDebugState->GetLockCount(kDbgStateLockType_User) >= - (*ppRWLock)->_wWriterLevel); - pThread->m_dwLockCount -= (*ppRWLock)->_wWriterLevel; - USER_LOCK_RELEASED_MULTIPLE((*ppRWLock)->_wWriterLevel, GetPtrForLockContract(ppRWLock)); - (*ppRWLock)->_wWriterLevel = pLockCookie->wWriterLevel; - pThread->m_dwLockCount += (*ppRWLock)->_wWriterLevel; - USER_LOCK_TAKEN_MULTIPLE((*ppRWLock)->_wWriterLevel, GetPtrForLockContract(ppRWLock)); - ++(*ppRWLock)->_dwWriterSeqNum; -#ifdef RWLOCK_STATISTICS - ++(*ppRWLock)->_dwWriterEntryCount; -#endif - goto LNormalReturn; - } - } - else if(dwFlags & COOKIE_READER) - { - LockEntry *pLockEntry = (*ppRWLock)->FastGetOrCreateLockEntry(); - if(pLockEntry) - { - // This thread should not already be a reader - // else bad things can happen - _ASSERTE(pLockEntry->wReaderLevel == 0); - DWORD dwKnownState = (*ppRWLock)->_dwState; - if(dwKnownState < READERS_MASK) - { - DWORD dwCurrentState = RWInterlockedCompareExchange(&(*ppRWLock)->_dwState, - (dwKnownState + READER), - dwKnownState); - if(dwCurrentState == dwKnownState) - { - // Restore reader nesting level - Thread *pThread = GetThread(); - _ASSERTE (pThread); - pLockEntry->wReaderLevel = pLockCookie->wReaderLevel; - pThread->m_dwLockCount += pLockEntry->wReaderLevel; - USER_LOCK_TAKEN_MULTIPLE(pLockEntry->wReaderLevel, GetPtrForLockContract(ppRWLock)); -#ifdef RWLOCK_STATISTICS - RWInterlockedIncrement(&(*ppRWLock)->_dwReaderEntryCount); -#endif - goto LNormalReturn; - } - } - - // Recycle the lock entry for the slow case - (*ppRWLock)->FastRecycleLockEntry(pLockEntry); - } - else - { - // Ignore the error and try again below. May be thread will luck - // out the second time - } - } - else if(dwFlags & COOKIE_NONE) - { - goto LNormalReturn; - } - - // Declare and Setup the frame as we are aware of the contention - // on the lock and the thread will most probably block - // to acquire lock below -ThrowException: - if((dwFlags & INVALID_COOKIE) == 0) - { - StaticRecoverLock(ppRWLock, pLockCookie, dwFlags); - } - else - { - COMPlusThrowWin32(E_INVALIDARG); - } - - goto LNormalReturn; - } - else - { - dwFlags = INVALID_COOKIE; - goto ThrowException; - } - -LNormalReturn: - return; -} - - -//+------------------------------------------------------------------- -// -// Class: CRWLock::StaticPrivateInitialize -// -// Synopsis: Initialize lock -// -//+------------------------------------------------------------------- -FCIMPL1(void, CRWLock::StaticPrivateInitialize, CRWLock *pRWLock) -{ - FCALL_CONTRACT; - - HELPER_METHOD_FRAME_BEGIN_1(pRWLock); - - // Run the constructor on the GC allocated space - // CRWLock's constructor can throw exception -#ifndef _PREFAST_ - // Prefast falsely complains of memory leak. - CRWLock *pTemp; - pTemp = new (pRWLock) CRWLock(); - _ASSERTE(pTemp == pRWLock); -#endif - - // Catch GC holes - VALIDATE_LOCK(pRWLock); - - HELPER_METHOD_FRAME_END(); - return; -} -FCIMPLEND - - -//+------------------------------------------------------------------- -// -// Class: CRWLock::StaticPrivateDestruct -// -// Synopsis: Destruct lock -//+------------------------------------------------------------------- -FCIMPL1(void, CRWLock::StaticPrivateDestruct, CRWLock *pRWLock) -{ - FCALL_CONTRACT; - - HELPER_METHOD_FRAME_BEGIN_ATTRIB_1(Frame::FRAME_ATTR_NO_THREAD_ABORT, pRWLock); - - // Fixing one handle recycling security hole by - // ensuring we don't delete the events more than once. - // After deletion (for now, assuming ONE FINALIZER THREAD) - // make the object essentially unusable by setting handle to - // INVALID_HANDLE_VALUE (unusable) versus NULL (uninitialized) - - if ((pRWLock->_hWriterEvent != INVALID_HANDLE_VALUE) && (pRWLock->_hReaderEvent != INVALID_HANDLE_VALUE)) - { - // Note, this still allows concurrent event consumers (such as StaticAcquireReaderLock) - // to Set and/or Wait on non-events. There still exists a security hole here. - if(pRWLock->_hWriterEvent) - { - CLREvent *h = (CLREvent *) FastInterlockExchangePointer((PVOID *)&(pRWLock->_hWriterEvent), INVALID_HANDLE_VALUE); - delete h; - } - if(pRWLock->_hReaderEvent) - { - CLREvent *h = (CLREvent *) FastInterlockExchangePointer((PVOID *)&(pRWLock->_hReaderEvent), INVALID_HANDLE_VALUE); - delete h; - } - - // There is no LockEntry for this lock. - if (pRWLock->_dwState != 0) - { - // Recycle LockEntry on threads - ThreadStoreLockHolder tsl; - - // Take ThreadStore lock and walk over every thread in the process - Thread *thread = NULL; - while ((thread = ThreadStore::s_pThreadStore->GetAllThreadList(thread, - Thread::TS_Unstarted|Thread::TS_Dead|Thread::TS_Detached, 0)) - != NULL) - { - LockEntry *pLockEntry; - { - CrstHolder rwl(&s_RWLockCrst); - pLockEntry = pRWLock->GetLockEntry(thread); - } - if (pLockEntry) - { - // The entry does not belong to this lock anymore - pLockEntry->dwLLockID = 0; - pLockEntry->wReaderLevel = 0; - } - } - } - } - HELPER_METHOD_FRAME_END(); -} -FCIMPLEND - - -//+------------------------------------------------------------------- -// -// Class: CRWLock::StaticGetWriterSeqNum -// -// Synopsis: Returns the current sequence number -// -//+------------------------------------------------------------------- -FCIMPL1(INT32, CRWLock::StaticGetWriterSeqNum, CRWLock *pRWLock) -{ - FCALL_CONTRACT; - - if (pRWLock == NULL) - { - FCThrow(kNullReferenceException); - } - - return(pRWLock->_dwWriterSeqNum); -} -FCIMPLEND - - -//+------------------------------------------------------------------- -// -// Class: CRWLock::StaticAnyWritersSince -// -// Synopsis: Returns TRUE if there were writers since the given -// sequence number -// -//+------------------------------------------------------------------- -FCIMPL2(FC_BOOL_RET, CRWLock::StaticAnyWritersSince, CRWLock *pRWLock, DWORD dwSeqNum) -{ - FCALL_CONTRACT; - - if (pRWLock == NULL) - { - FCThrow(kNullReferenceException); - } - - - if(pRWLock->_dwWriterID == GetThread()->GetThreadId()) - ++dwSeqNum; - - FC_RETURN_BOOL(pRWLock->_dwWriterSeqNum > dwSeqNum); -} -FCIMPLEND - -struct RWLockIterator -{ - IHostTask **m_Owner; - DWORD m_Capacity; - DWORD m_index; -}; - -OBJECTHANDLE CRWLock::GetObjectHandle() -{ - CONTRACTL - { - THROWS; - MODE_COOPERATIVE; - GC_NOTRIGGER; - } - CONTRACTL_END; - - if (_hObjectHandle == NULL) - { - OBJECTREF obj = ObjectToOBJECTREF((Object*)this); - OBJECTHANDLE handle = GetAppDomain()->CreateLongWeakHandle(obj); - if (RWInterlockedCompareExchangePointer((PVOID*)&_hObjectHandle, handle, NULL) != NULL) - { - DestroyLongWeakHandle(handle); - } - } - return _hObjectHandle; -} - -// CRWLock::CreateOwnerIterator can return E_OUTOFMEMORY -// -HRESULT CRWLock::CreateOwnerIterator(SIZE_T *pIterator) -{ - CONTRACTL - { - NOTHROW; - MODE_PREEMPTIVE; - GC_NOTRIGGER; - SO_INTOLERANT; - } - CONTRACTL_END; - - *pIterator = 0; - if (_dwState == 0) { - return S_OK; - } - NewHolder IteratorHolder(new (nothrow) RWLockIterator); - RWLockIterator *pRWLockIterator = IteratorHolder; - if (pRWLockIterator == NULL) { - return E_OUTOFMEMORY; - } - // Writer can be handled fast - if (_dwState & WRITER) { - DWORD writerID = _dwWriterID; - if (writerID != 0) - { - pRWLockIterator->m_Capacity = 1; - pRWLockIterator->m_index = 0; - pRWLockIterator->m_Owner = new (nothrow) IHostTask*[1]; - if (pRWLockIterator->m_Owner == NULL) { - return E_OUTOFMEMORY; - } - Thread *pThread = g_pThinLockThreadIdDispenser->IdToThreadWithValidation(writerID); - if (pThread == NULL) - { - return S_OK; - } - IteratorHolder.SuppressRelease(); - pRWLockIterator->m_Owner[0] = pThread->GetHostTaskWithAddRef(); - *pIterator = (SIZE_T)pRWLockIterator; - return S_OK; - } - } - if (_dwState == 0) { - return S_OK; - } - pRWLockIterator->m_Capacity = 4; - pRWLockIterator->m_index = 0; - pRWLockIterator->m_Owner = new (nothrow) IHostTask*[pRWLockIterator->m_Capacity]; - if (pRWLockIterator->m_Owner == NULL) { - return E_OUTOFMEMORY; - } - - HRESULT hr = S_OK; - - NewArrayHolder OwnerHolder(pRWLockIterator->m_Owner); - - // Take ThreadStore lock and walk over every thread in the process - Thread *thread = NULL; - while ((thread = ThreadStore::s_pThreadStore->GetAllThreadList(thread, - Thread::TS_Unstarted|Thread::TS_Dead|Thread::TS_Detached, 0)) - != NULL) - { - LockEntry *pLockEntry; - { - CrstHolder rwl(&s_RWLockCrst); - pLockEntry = GetLockEntry(thread); - } - if (pLockEntry && pLockEntry->wReaderLevel >= 1) { - if (pRWLockIterator->m_index == pRWLockIterator->m_Capacity) { - IHostTask** newArray = new (nothrow) IHostTask*[2*pRWLockIterator->m_Capacity]; - if (newArray == NULL) { - hr = E_OUTOFMEMORY; - break; - } - memcpy (newArray,pRWLockIterator->m_Owner,pRWLockIterator->m_Capacity*sizeof(IHostTask*)); - pRWLockIterator->m_Owner = newArray; - pRWLockIterator->m_Capacity *= 2; - OwnerHolder = pRWLockIterator->m_Owner; - } - IHostTask *pHostTask = thread->GetHostTaskWithAddRef(); - if (pHostTask) - { - pRWLockIterator->m_Owner[pRWLockIterator->m_index++] = pHostTask; - } - } - } - if (FAILED(hr)) - { - for (DWORD i = 0; i < pRWLockIterator->m_index; i ++) - { - if (pRWLockIterator->m_Owner[i]) - { - pRWLockIterator->m_Owner[i]->Release(); - } - } - } - if (SUCCEEDED(hr)) { - IteratorHolder.SuppressRelease(); - OwnerHolder.SuppressRelease(); - pRWLockIterator->m_Capacity = pRWLockIterator->m_index; - pRWLockIterator->m_index = 0; - *pIterator = (SIZE_T)pRWLockIterator; - } - - return hr; -} - -void CRWLock::GetNextOwner(SIZE_T Iterator, IHostTask **ppOwnerHostTask) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; - } - CONTRACTL_END; - - *ppOwnerHostTask = NULL; - if (Iterator) { - RWLockIterator* tmp = (RWLockIterator*)Iterator; - if (tmp->m_index < tmp->m_Capacity) { - *ppOwnerHostTask = tmp->m_Owner[tmp->m_index]; - tmp->m_index ++; - } - } -} - -void CRWLock::DeleteOwnerIterator(SIZE_T Iterator) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - SO_TOLERANT; - } - CONTRACTL_END; - - - if (Iterator) { - RWLockIterator* pIterator = (RWLockIterator*)Iterator; - while (pIterator->m_index < pIterator->m_Capacity) { - IHostTask *pHostTask = pIterator->m_Owner[pIterator->m_index]; - if (pHostTask) - { - pHostTask->Release(); - } - pIterator->m_index ++; - } - delete[] pIterator->m_Owner; - delete pIterator; - } -} -#endif // FEATURE_RWLOCK diff --git a/src/vm/rwlock.h b/src/vm/rwlock.h index dc8e67e6fb..908e007169 100644 --- a/src/vm/rwlock.h +++ b/src/vm/rwlock.h @@ -67,220 +67,6 @@ typedef struct { DWORD dwThreadID; } LockCookie; -//+------------------------------------------------------------------- -// -// Class: CRWLock -// -// Synopsis: Class the implements the reader writer locks. -// -//+------------------------------------------------------------------- -class CRWLock : public Object -{ - friend class MscorlibBinder; - -public: - // Constuctor - CRWLock(); - - // Cleanup - void Cleanup(); - - OBJECTHANDLE GetObjectHandle(); - HRESULT CreateOwnerIterator(SIZE_T *pIterator); - static void GetNextOwner(SIZE_T Iterator, IHostTask **ppOwnerHostTask); - static void DeleteOwnerIterator(SIZE_T Iterator); - - // Statics that do the core work - static FCDECL1 (void, StaticPrivateInitialize, CRWLock *pRWLock); - static FCDECL1 (void, StaticPrivateDestruct, CRWLock *pRWLock); - static FCDECL2 (void, StaticAcquireReaderLockPublic, CRWLock *pRWLock, DWORD dwDesiredTimeout); - static FCDECL2 (void, StaticAcquireWriterLockPublic, CRWLock *pRWLock, DWORD dwDesiredTimeout); - static FCDECL1 (void, StaticReleaseReaderLockPublic, CRWLock *pRWLock); - static FCDECL1 (void, StaticReleaseWriterLockPublic, CRWLock *pRWLock); - static FCDECL3 (void, StaticDoUpgradeToWriterLockPublic, CRWLock *pRWLock, LockCookie * pLockCookie, DWORD dwDesiredTimeout); - static FCDECL2 (void, StaticDowngradeFromWriterLock, CRWLock *pRWLock, LockCookie* pLockCookie); - static FCDECL2 (void, StaticDoReleaseLock, CRWLock *pRWLock, LockCookie * pLockCookie); - static FCDECL2 (void, StaticRestoreLockPublic, CRWLock *pRWLock, LockCookie* pLockCookie); - static FCDECL1 (FC_BOOL_RET, StaticIsReaderLockHeld, CRWLock *pRWLock); - static FCDECL1 (FC_BOOL_RET, StaticIsWriterLockHeld, CRWLock *pRWLock); - static FCDECL1 (INT32, StaticGetWriterSeqNum, CRWLock *pRWLock); - static FCDECL2 (FC_BOOL_RET, StaticAnyWritersSince, CRWLock *pRWLock, DWORD dwSeqNum); -private: - static void StaticAcquireReaderLock(CRWLock **ppRWLock, DWORD dwDesiredTimeout); - static void StaticAcquireWriterLock(CRWLock **ppRWLock, DWORD dwDesiredTimeout); - static void StaticReleaseReaderLock(CRWLock **ppRWLock); - static void StaticReleaseWriterLock(CRWLock **ppRWLock); - static void StaticRecoverLock(CRWLock **ppRWLock, LockCookie *pLockCookie, DWORD dwFlags); - static void StaticRestoreLock(CRWLock **ppRWLock, LockCookie *pLockCookie); - static void StaticUpgradeToWriterLock(CRWLock **ppRWLock, LockCookie *pLockCookie, DWORD dwDesiredTimeout); -public: - // Assert functions -#ifdef _DEBUG - BOOL AssertWriterLockHeld(); - BOOL AssertWriterLockNotHeld(); - BOOL AssertReaderLockHeld(); - BOOL AssertReaderLockNotHeld(); - BOOL AssertReaderOrWriterLockHeld(); - void AssertHeld() - { - WRAPPER_NO_CONTRACT; - AssertWriterLockHeld(); - } - void AssertNotHeld() - { - WRAPPER_NO_CONTRACT; - AssertWriterLockNotHeld(); - AssertReaderLockNotHeld(); - } -#else - void AssertWriterLockHeld() { LIMITED_METHOD_CONTRACT; } - void AssertWriterLockNotHeld() { LIMITED_METHOD_CONTRACT; } - void AssertReaderLockHeld() { LIMITED_METHOD_CONTRACT; } - void AssertReaderLockNotHeld() { LIMITED_METHOD_CONTRACT; } - void AssertReaderOrWriterLockHeld() { LIMITED_METHOD_CONTRACT; } - void AssertHeld() { LIMITED_METHOD_CONTRACT; } - void AssertNotHeld() { LIMITED_METHOD_CONTRACT; } -#endif - - // Helper functions -#ifdef RWLOCK_STATISTICS - DWORD GetReaderEntryCount() - { - LIMITED_METHOD_CONTRACT; - return(_dwReaderEntryCount); - } - DWORD GetReaderContentionCount() { LIMITED_METHOD_CONTRACT; return(_dwReaderContentionCount); } - DWORD GetWriterEntryCount() { LIMITED_METHOD_CONTRACT; return(_dwWriterEntryCount); } - DWORD GetWriterContentionCount() { LIMITED_METHOD_CONTRACT; return(_dwWriterContentionCount); } -#endif - // Static functions - static void *operator new(size_t size) - { - CONTRACTL - { - THROWS; - GC_NOTRIGGER; - } - CONTRACTL_END; - - return ::operator new(size); - } - static void ProcessInit(); - - static void SetTimeout(DWORD dwTimeout) - { - LIMITED_METHOD_CONTRACT; - - gdwDefaultTimeout = dwTimeout; - } - static DWORD GetTimeout() - { - LIMITED_METHOD_CONTRACT; - return(gdwDefaultTimeout); - } - static void SetSpinCount(DWORD dwSpinCount) - { - LIMITED_METHOD_CONTRACT; - - gdwDefaultSpinCount = g_SystemInfo.dwNumberOfProcessors > 1 - ? dwSpinCount - : 0; - } - static DWORD GetSpinCount() { LIMITED_METHOD_CONTRACT; return(gdwDefaultSpinCount); } - -private: - // Private helpers - static void ChainEntry(Thread *pThread, LockEntry *pLockEntry); - LockEntry *GetLockEntry(Thread *pThread = NULL); - LockEntry *FastGetOrCreateLockEntry(); - LockEntry *SlowGetOrCreateLockEntry(Thread *pThread); - void FastRecycleLockEntry(LockEntry *pLockEntry); - static void RecycleLockEntry(LockEntry *pLockEntry); - - CLREvent* GetReaderEvent(HRESULT *pHR); - CLREvent* GetWriterEvent(HRESULT *pHR); - void ReleaseEvents(); - - static LONG RWInterlockedCompareExchange(LONG RAW_KEYWORD(volatile) *pvDestination, - LONG dwExchange, - LONG dwComperand); - static LONGLONG RWInterlockedCompareExchange64(LONGLONG RAW_KEYWORD(volatile) *pvDestination, - LONGLONG qwExchange, - LONGLONG qwComparand); - static void* RWInterlockedCompareExchangePointer(PVOID RAW_KEYWORD(volatile) *pvDestination, - PVOID pExchange, - PVOID pComparand); - static LONG RWInterlockedExchangeAdd(LONG RAW_KEYWORD(volatile) *pvDestination, LONG dwAddState); - static LONG RWInterlockedIncrement(LONG RAW_KEYWORD(volatile) *pdwState); - - static DWORD RWWaitForSingleObject(CLREvent* event, DWORD dwTimeout); - static void RWSetEvent(CLREvent* event); - static void RWResetEvent(CLREvent* event); - static void RWSleep(DWORD dwTime); - -#if defined(ENABLE_CONTRACTS_IMPL) - // The LOCK_TAKEN/RELEASED macros need a "pointer" to the lock object to do - // comparisons between takes & releases (and to provide debugging info to the - // developer). We can't use "this" (*ppRWLock), because CRWLock is an Object and thus - // can move. So we use _dwLLockID instead. It's not exactly unique, but it's - // good enough--worst that can happen is if a thread takes RWLock A and erroneously - // releases RWLock B (instead of A), we'll fail to catch that if their _dwLLockID's - // are the same. On 64 bits, we can use both _dwULockID & _dwLLockID and be unique - static void * GetPtrForLockContract(CRWLock ** ppRWLock) - { -#if defined(_WIN64) - return (void *) - ( - ( - ((__int64) ((*ppRWLock)->_dwULockID)) << 32 - ) - | - ( - (__int64) ((*ppRWLock)->_dwLLockID) - ) - ); -#else //defined(_WIN64) - return LongToPtr((*ppRWLock)->_dwLLockID); -#endif //defined(_WIN64) - } -#endif //defined(ENABLE_CONTRACTS_IMPL) - - // private new - static void *operator new(size_t size, void *pv) { LIMITED_METHOD_CONTRACT; return(pv); } - - // Private data - CLREvent *_hWriterEvent; - CLREvent *_hReaderEvent; - OBJECTHANDLE _hObjectHandle; - Volatile _dwState; - LONG _dwULockID; - LONG _dwLLockID; - DWORD _dwWriterID; - DWORD _dwWriterSeqNum; - WORD _wWriterLevel; -#ifdef RWLOCK_STATISTICS - // WARNING: You must explicitly #define RWLOCK_STATISTICS when you build - // in both the VM and BCL directories, as the managed class must also - // contain these fields! - Volatile _dwReaderEntryCount; - Volatile _dwReaderContentionCount; - Volatile _dwWriterEntryCount; - Volatile _dwWriterContentionCount; - Volatile _dwEventsReleasedCount; -#endif - - // Static data - static Volatile s_mostRecentLockID; - static CrstStatic s_RWLockCrst; -}; - -#ifdef USE_CHECKED_OBJECTREFS -typedef REF RWLOCKREF; - -#else -typedef CRWLock* RWLOCKREF; -#endif - #endif // _RWLOCK_H_ #endif // FEATURE_RWLOCK -- cgit v1.2.3 From a79fee3b99fe8d6f171c7b26dae4fb1a51590d90 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Sun, 12 Feb 2017 21:05:29 -0800 Subject: Remove dead stackbuildersink.cpp --- src/vm/stackbuildersink.cpp | 702 -------------------------------------------- 1 file changed, 702 deletions(-) delete mode 100644 src/vm/stackbuildersink.cpp diff --git a/src/vm/stackbuildersink.cpp b/src/vm/stackbuildersink.cpp deleted file mode 100644 index 2e363f2802..0000000000 --- a/src/vm/stackbuildersink.cpp +++ /dev/null @@ -1,702 +0,0 @@ -// 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. -// -// File: StackBuilderSink.cpp -// - -// -// Purpose: Native implementation for System.Runtime.Remoting.Messaging.StackBuilderSink -// - - -#include "common.h" - -#ifdef FEATURE_REMOTING - -#include "excep.h" -#include "message.h" -#include "stackbuildersink.h" -#include "dbginterface.h" -#include "remoting.h" -#include "profilepriv.h" -#include "class.h" - -struct ArgInfo -{ - PBYTE dataLocation; - INT32 dataSize; - TypeHandle dataTypeHandle; - BYTE dataType; - BYTE byref; -}; - - -//+---------------------------------------------------------------------------- -// -// Method: CStackBuilderSink::PrivateProcessMessage, public -// -// Synopsis: Builds the stack and calls an object -// -// -//+---------------------------------------------------------------------------- -FCIMPL5(Object*, CStackBuilderSink::PrivateProcessMessage, - Object* pSBSinkUNSAFE, - MethodDesc* pMD, - PTRArray* pArgsUNSAFE, - Object* pServerUNSAFE, - PTRARRAYREF* ppVarOutParams) -{ - CONTRACTL - { - FCALL_CHECK; - PRECONDITION(CheckPointer(pMD)); - PRECONDITION(!pMD->IsGenericMethodDefinition()); - PRECONDITION(pMD->IsRuntimeMethodHandle()); - } - CONTRACTL_END; - - struct _gc - { - PTRARRAYREF pArgs; - OBJECTREF pServer; - OBJECTREF pSBSink; - OBJECTREF ret; - } gc; - gc.pArgs = (PTRARRAYREF) pArgsUNSAFE; - gc.pServer = (OBJECTREF) pServerUNSAFE; - gc.pSBSink = (OBJECTREF) pSBSinkUNSAFE; - gc.ret = NULL; - - HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc); - - // pMD->IsStatic() is SO_INTOLERANT. - // Either pServer is non-null or the method is static (but not both) - _ASSERTE( (pServerUNSAFE!=NULL) == !(pMD->IsStatic()) ); - - LOG((LF_REMOTING, LL_INFO10, "CStackBuilderSink::PrivateProcessMessage\n")); - - MethodDesc *pResolvedMD = pMD; - // Check if this is an interface invoke, if yes, then we have to find the - // real method descriptor on the class of the server object. - if(pMD->GetMethodTable()->IsInterface()) - { - _ASSERTE(gc.pServer != NULL); - - // NOTE: This method can trigger GC - // The last parameter (true) causes the method to take into account that - // the object passed in is a TP and try to resolve the interface MD into - // a server MD anyway (normally the call short circuits thunking objects - // and just returns the interface MD unchanged). - MethodTable *pRealMT = gc.pServer->GetTrueMethodTable(); - -#ifdef FEATURE_COMINTEROP - if (pRealMT->IsComObjectType()) - pResolvedMD = pRealMT->GetMethodDescForComInterfaceMethod(pMD, true); - else -#endif // FEATURE_COMINTEROP - { - if (pRealMT->ImplementsInterface(pMD->GetMethodTable())) - { - pResolvedMD = pRealMT->GetMethodDescForInterfaceMethod(TypeHandle(pMD->GetMethodTable()), pMD); - - // If the method is generic then we have more work to do -- - // we'll get back the generic method descriptor and we'll have - // to load the version with the right instantiation (get the - // instantiation from the interface method). - if (pResolvedMD->HasMethodInstantiation()) - { - _ASSERTE(pResolvedMD->IsGenericMethodDefinition()); - _ASSERTE(pMD->GetNumGenericMethodArgs() == pResolvedMD->GetNumGenericMethodArgs()); - - pResolvedMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pResolvedMD, - pRealMT, - FALSE, - pMD->GetMethodInstantiation(), - FALSE); - - _ASSERTE(!pResolvedMD->ContainsGenericVariables()); - } - } - else - pResolvedMD = NULL; - } - - if(!pResolvedMD) - { - MAKE_WIDEPTR_FROMUTF8(wName, pMD->GetName()); - COMPlusThrow(kMissingMethodException, IDS_EE_MISSING_METHOD, wName); - } - } - - // This looks a little dodgy for generics: pResolvedMD has been interface-resolved but not - // virtual-resolved. So we seem to be taking the signature of a - // half-resolved-virtual-call. But the MetaSig - // is only used for GC purposes, and thus is probably OK: although the - // metadata for the signature of a call may be different - // as we move to base classes, the instantiated version - // of the signature will still be the same - // at both the callsite and the target). - MetaSig mSig(pResolvedMD); - - // get the target depending on whether the method is virtual or non-virtual - // like a constructor, private or final method - PCODE pTarget = pResolvedMD->GetCallTarget(&(gc.pServer)); - - VASigCookie *pCookie = NULL; - _ASSERTE(NULL != pTarget); - - // this function does the work - ::CallDescrWithObjectArray( - gc.pServer, - pResolvedMD, - //pRM, - pTarget, - &mSig, - pCookie, - gc.pArgs, - &gc.ret, - ppVarOutParams); - - LOG((LF_REMOTING, LL_INFO10, "CStackBuilderSink::PrivateProcessMessage OUT\n")); - - HELPER_METHOD_FRAME_END(); - - return OBJECTREFToObject(gc.ret); -} -FCIMPLEND - -class ProfilerServerCallbackHolder -{ -public: - ProfilerServerCallbackHolder(Thread* pThread) : m_pThread(pThread) - { -#ifdef PROFILING_SUPPORTED - // If we're profiling, notify the profiler that we're about to invoke the remoting target - { - BEGIN_PIN_PROFILER(CORProfilerTrackRemoting()); - GCX_PREEMP(); - g_profControlBlock.pProfInterface->RemotingServerInvocationStarted(); - END_PIN_PROFILER(); - } -#endif // PROFILING_SUPPORTED - } - - ~ProfilerServerCallbackHolder() - { -#ifdef PROFILING_SUPPORTED - // If profiling is active, tell profiler we've made the call, received the - // return value, done any processing necessary, and now remoting is done. - { - BEGIN_PIN_PROFILER(CORProfilerTrackRemoting()); - GCX_PREEMP(); - g_profControlBlock.pProfInterface->RemotingServerInvocationReturned(); - END_PIN_PROFILER(); - } -#endif // PROFILING_SUPPORTED - } - -private: - Thread* m_pThread; -}; - -//+---------------------------------------------------------------------------- -// -// Function: CallDescrWithObjectArray, private -// -// Synopsis: Builds the stack from a object array and call the object -// -// -// Note this function triggers GC and assumes that pServer, pArguments, pVarRet, and ppVarOutParams are -// all already protected!! -//+---------------------------------------------------------------------------- -void CallDescrWithObjectArray(OBJECTREF& pServer, - //ReflectMethod *pRM, - MethodDesc *pMeth, - PCODE pTarget, - MetaSig* sig, - VASigCookie *pCookie, - PTRARRAYREF& pArgArray, - OBJECTREF *pVarRet, - PTRARRAYREF *ppVarOutParams) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - INJECT_FAULT(COMPlusThrowOM()); - } - CONTRACTL_END; - - LOG((LF_REMOTING, LL_INFO10, "CallDescrWithObjectArray IN\n")); - -#ifdef _PREFAST_ -#pragma warning(push) -#pragma warning(disable:6263) // "Suppress PREFast warning about _alloca in a loop" - // _alloca is called within a loop in a number of places within this method - // (as an ultra fast means of acquiring temporary storage). This can be a - // problem in some scenarios (swiftly drive us to stack overflow). But in - // this case the allocations are tightly bounded (by the number of arguments - // in the target method) and the allocations themselves are small (no worse - // really than calling the method an extra time). -#endif - - ByRefInfo *pByRefs = NULL; - FrameWithCookie *pProtectValueClassFrame = NULL; - FrameWithCookie *pProtectionFrame = NULL; - UINT nStackBytes = 0; - LPBYTE pAlloc = 0; - LPBYTE pTransitionBlock = 0; - UINT32 numByRef = 0; - //DWORD attr = pRM->dwFlags; -#ifdef _DEBUG - //MethodDesc *pMD = pRM->pMethod; -#endif - ValueClassInfo *pValueClasses = NULL; - - // check the calling convention - - BYTE callingconvention = sig->GetCallingConvention(); - if (!isCallConv(callingconvention, IMAGE_CEE_CS_CALLCONV_DEFAULT)) - { - _ASSERTE(!"This calling convention is not supported."); - COMPlusThrow(kInvalidProgramException); - } - - // Make sure we are properly loaded - CONSISTENCY_CHECK(GetAppDomain()->CheckCanExecuteManagedCode(pMeth)); - - // Note this is redundant with the above but we do it anyway for safety - pMeth->EnsureActive(); - -#ifdef DEBUGGING_SUPPORTED - // debugger goo What does this do? can someone put a comment here? - if (CORDebuggerTraceCall()) - { - g_pDebugInterface->TraceCall((const BYTE *)pTarget); - } -#endif // DEBUGGING_SUPPORTED - - Thread * pThread = GetThread(); - - { - ProfilerServerCallbackHolder profilerHolder(pThread); - - ArgIterator argit(sig); - - // Create a fake FramedMethodFrame on the stack. - nStackBytes = argit.SizeOfFrameArgumentArray(); - - UINT32 cbAlloc = 0; - if (!ClrSafeInt::addition(TransitionBlock::GetNegSpaceSize(), sizeof(TransitionBlock), cbAlloc)) - COMPlusThrow(kArgumentException); - if (!ClrSafeInt::addition(cbAlloc, nStackBytes, cbAlloc)) - COMPlusThrow(kArgumentException); - - pAlloc = (LPBYTE)_alloca(cbAlloc); - pTransitionBlock = pAlloc + TransitionBlock::GetNegSpaceSize(); - - // cycle through the parameters and see if there are byrefs - BOOL fHasByRefs = FALSE; - - //if (attr & RM_ATTR_BYREF_FLAG_SET) - // fHasByRefs = attr & RM_ATTR_HAS_BYREF_ARG; - //else - { - sig->Reset(); - CorElementType typ; - while ((typ = sig->NextArg()) != ELEMENT_TYPE_END) - { - if (typ == ELEMENT_TYPE_BYREF) - { - fHasByRefs = TRUE; - //attr |= RM_ATTR_HAS_BYREF_ARG; - break; - } - } - //attr |= RM_ATTR_BYREF_FLAG_SET; - //pRM->dwFlags = attr; - sig->Reset(); - } - - UINT32 nFixedArgs = sig->NumFixedArgs(); - // To avoid any security problems with integer overflow/underflow we're - // going to validate the number of args here (we're about to _alloca an - // array of ArgInfo structures and maybe a managed object array as well - // based on this count). - _ASSERTE(sizeof(Object*) <= sizeof(ArgInfo)); - UINT32 nMaxArgs = UINT32_MAX / sizeof(ArgInfo); - if (nFixedArgs > nMaxArgs) - COMPlusThrow(kArgumentException); - - // if there are byrefs allocate and array for the out parameters - if (fHasByRefs) - { - *ppVarOutParams = PTRARRAYREF(AllocateObjectArray(sig->NumFixedArgs(), g_pObjectClass)); - - // Null out the array - memset(&(*ppVarOutParams)->m_Array, 0, sizeof(OBJECTREF) * sig->NumFixedArgs()); - } - - OBJECTREF *ppThis = NULL; - - if (sig->HasThis()) - { - ppThis = (OBJECTREF*)(pTransitionBlock + argit.GetThisOffset()); - - // *ppThis is not GC protected. It will be set to the right value - // after all object allocations are made. - *ppThis = NULL; - } - - // if we have the Value Class return, we need to allocate that class and place a pointer to it on the stack. - - *pVarRet = NULL; - TypeHandle retType = sig->GetRetTypeHandleThrowing(); - // Note that we want the unnormalized (signature) type because GetStackObject - // boxes as the element type, which if we normalized it would loose information. - CorElementType retElemType = sig->GetReturnType(); - - // The MethodTable pointer of the return type, if that's a struct - MethodTable* pStructRetTypeMT = NULL; - - // Allocate a boxed struct instance to hold the return value in any case. - if (retElemType == ELEMENT_TYPE_VALUETYPE) - { - pStructRetTypeMT = retType.GetMethodTable(); - *pVarRet = pStructRetTypeMT->Allocate(); - } - else { - _ASSERTE(!argit.HasRetBuffArg()); - } - -#ifdef CALLDESCR_REGTYPEMAP - UINT64 dwRegTypeMap = 0; - BYTE* pMap = (BYTE*)&dwRegTypeMap; -#endif // CALLDESCR_REGTYPEMAP - -#ifdef CALLDESCR_FPARGREGS - FloatArgumentRegisters *pFloatArgumentRegisters = NULL; -#endif // CALLDESCR_FPARGREGS - - // gather data about the parameters by iterating over the sig: - UINT32 arg = 0; - int ofs = 0; - - // REVIEW: need to use actual arg count if VarArgs are supported - ArgInfo* pArgInfoStart = (ArgInfo*) _alloca(nFixedArgs*sizeof(ArgInfo)); - -#ifdef _DEBUG - // We expect to write useful data over every part of this so need - // not do this in retail! - memset((void *)pArgInfoStart, 0, sizeof(ArgInfo)*nFixedArgs); -#endif - - for (; TransitionBlock::InvalidOffset != (ofs = argit.GetNextOffset()); arg++) - { - CONSISTENCY_CHECK(arg < nFixedArgs); - ArgInfo* pArgInfo = pArgInfoStart + arg; - -#ifdef CALLDESCR_REGTYPEMAP - FillInRegTypeMap(ofs, argit.GetArgType(), pMap); -#endif - -#ifdef CALLDESCR_FPARGREGS - // Under CALLDESCR_FPARGREGS we can have arguments in floating point registers. If we have at - // least one such argument we point the call worker at the floating point area of the frame (we leave - // it null otherwise since the worker can perform a useful optimization if it knows no floating point - // registers need to be set up). - if (TransitionBlock::HasFloatRegister(ofs, argit.GetArgLocDescForStructInRegs()) && - (pFloatArgumentRegisters == NULL)) - { - pFloatArgumentRegisters = (FloatArgumentRegisters*)(pTransitionBlock + - TransitionBlock::GetOffsetOfFloatArgumentRegisters()); - } -#endif - - if (argit.GetArgType() == ELEMENT_TYPE_BYREF) - { - TypeHandle ty = TypeHandle(); - CorElementType brType = sig->GetByRefType(&ty); - if (CorIsPrimitiveType(brType)) - { - pArgInfo->dataSize = gElementTypeInfo[brType].m_cbSize; - } - else if (ty.IsValueType()) - { - pArgInfo->dataSize = ty.GetMethodTable()->GetNumInstanceFieldBytes(); - numByRef ++; - } - else - { - pArgInfo->dataSize = sizeof(Object *); - numByRef ++; - } - - ByRefInfo *brInfo = (ByRefInfo *) _alloca(offsetof(ByRefInfo,data) + pArgInfo->dataSize); - brInfo->argIndex = arg; - brInfo->typ = brType; - brInfo->typeHandle = ty; - brInfo->pNext = pByRefs; - pByRefs = brInfo; - pArgInfo->dataLocation = (BYTE*)brInfo->data; - *((void**)(pTransitionBlock + ofs)) = (void*)pArgInfo->dataLocation; - pArgInfo->dataTypeHandle = ty; - pArgInfo->dataType = static_cast(brType); - pArgInfo->byref = TRUE; - } - else - { - pArgInfo->dataLocation = pTransitionBlock + ofs; - pArgInfo->dataSize = argit.GetArgSize(); - pArgInfo->dataTypeHandle = sig->GetLastTypeHandleThrowing(); // this may cause GC! - pArgInfo->dataType = (BYTE)argit.GetArgType(); - pArgInfo->byref = FALSE; - } - } - - - if (ppThis) - { - // If this isn't a value class, verify the objectref -#ifdef _DEBUG - //if (pMD->GetMethodTable()->IsValueType() == FALSE) - //{ - // VALIDATEOBJECTREF(pServer); - //} -#endif //_DEBUG - *ppThis = pServer; - } - - PVOID pRetBufStackData = NULL; - - if (argit.HasRetBuffArg()) - { - // If the return buffer *must* be a stack-allocated object, allocate it. - PVOID pRetBufData = NULL; - if (pStructRetTypeMT->IsStructRequiringStackAllocRetBuf()) - { - SIZE_T sz = pStructRetTypeMT->GetNumInstanceFieldBytes(); - pRetBufData = pRetBufStackData = _alloca(sz); - memset(pRetBufData, 0, sz); - pValueClasses = new (_alloca(sizeof(ValueClassInfo))) ValueClassInfo(pRetBufStackData, pStructRetTypeMT, pValueClasses); - } - else - { - pRetBufData = (*pVarRet)->GetData(); - } - *((LPVOID*) (pTransitionBlock + argit.GetRetBuffArgOffset())) = pRetBufData; - } - - // There should be no GC when we fill up the stack with parameters, as we don't protect them - // Assignment of "*ppThis" above triggers the point where we become unprotected. - { - GCX_FORBID(); - - PBYTE dataLocation; - INT32 dataSize; - TypeHandle dataTypeHandle; - BYTE dataType; - - OBJECTREF* pArguments = pArgArray->m_Array; - UINT32 i; - for (i=0; idataSize; - dataLocation = pArgInfo->dataLocation; - dataTypeHandle = pArgInfo->dataTypeHandle; - dataType = pArgInfo->dataType; - - // Nullable needs special treatment, even if it is 1, 2, 4, or 8 bytes - if (dataType == ELEMENT_TYPE_VALUETYPE) - goto DEFAULT_CASE; - - switch (dataSize) - { - case 1: - // This "if" statement is necessary to make the assignement big-endian aware - if (pArgInfo->byref) - *((INT8*)dataLocation) = *((INT8*)pArguments[i]->GetData()); - else - *(StackElemType*)dataLocation = (StackElemType)*((INT8*)pArguments[i]->GetData()); - break; - case 2: - // This "if" statement is necessary to make the assignement big-endian aware - if (pArgInfo->byref) - *((INT16*)dataLocation) = *((INT16*)pArguments[i]->GetData()); - else - *(StackElemType*)dataLocation = (StackElemType)*((INT16*)pArguments[i]->GetData()); - break; - case 4: -#ifndef _WIN64 - if ((dataType == ELEMENT_TYPE_STRING) || - (dataType == ELEMENT_TYPE_OBJECT) || - (dataType == ELEMENT_TYPE_CLASS) || - (dataType == ELEMENT_TYPE_SZARRAY) || - (dataType == ELEMENT_TYPE_ARRAY)) - { - *(OBJECTREF *)dataLocation = pArguments[i]; - } - else - { - *(StackElemType*)dataLocation = (StackElemType)*((INT32*)pArguments[i]->GetData()); - } -#else // !_WIN64 - // This "if" statement is necessary to make the assignement big-endian aware - if (pArgInfo->byref) - *(INT32*)dataLocation = *((INT32*)pArguments[i]->GetData()); - else - *(StackElemType*)dataLocation = (StackElemType)*((INT32*)pArguments[i]->GetData()); -#endif // !_WIN64 - break; - - case 8: -#ifdef _WIN64 - if ((dataType == ELEMENT_TYPE_STRING) || - (dataType == ELEMENT_TYPE_OBJECT) || - (dataType == ELEMENT_TYPE_CLASS) || - (dataType == ELEMENT_TYPE_SZARRAY) || - (dataType == ELEMENT_TYPE_ARRAY)) - { - *(OBJECTREF *)dataLocation = pArguments[i]; - } - else - { - *((INT64*)dataLocation) = *((INT64*)pArguments[i]->GetData()); - } -#else // _WIN64 - *((INT64*)dataLocation) = *((INT64*)pArguments[i]->GetData()); -#endif // _WIN64 - break; - - default: - { - DEFAULT_CASE: - MethodTable * pMT = dataTypeHandle.GetMethodTable(); - -#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE - // We do not need to allocate a buffer if the argument is already passed by reference. - if (!pArgInfo->byref && ArgIterator::IsArgPassedByRef(dataTypeHandle)) - { - PVOID pvArg = _alloca(dataSize); - pMT->UnBoxIntoUnchecked(pvArg, pArguments[i]); - *(PVOID*)dataLocation = pvArg; - - pValueClasses = new (_alloca(sizeof(ValueClassInfo))) ValueClassInfo(pvArg, pMT, pValueClasses); - } - else -#endif - { - pMT->UnBoxIntoUnchecked(dataLocation, pArguments[i]); - } - } - } - } - -#ifdef _DEBUG - // Should not be using this any more - memset((void *)pArgInfoStart, 0, sizeof(ArgInfo)*nFixedArgs); -#endif - - // if there were byrefs, push a protection frame - if (pByRefs && numByRef > 0) - { - char *pBuffer = (char*)_alloca (sizeof (FrameWithCookie)); - pProtectionFrame = new (pBuffer) FrameWithCookie(pThread, pByRefs); - } - - // If there were any value classes that must be protected by the - // caller, push a ProtectValueClassFrame. - if (pValueClasses) - { - char *pBuffer = (char*)_alloca (sizeof (FrameWithCookie)); - pProtectValueClassFrame = new (pBuffer) FrameWithCookie(pThread, pValueClasses); - } - - } // GCX_FORBID - - UINT fpReturnSize = argit.GetFPReturnSize(); - - CallDescrData callDescrData; - - callDescrData.pSrc = pTransitionBlock + sizeof(TransitionBlock); - callDescrData.numStackSlots = nStackBytes / STACK_ELEM_SIZE; -#ifdef CALLDESCR_ARGREGS - callDescrData.pArgumentRegisters = (ArgumentRegisters*)(pTransitionBlock + TransitionBlock::GetOffsetOfArgumentRegisters()); -#endif -#ifdef CALLDESCR_FPARGREGS - callDescrData.pFloatArgumentRegisters = pFloatArgumentRegisters; -#endif -#ifdef CALLDESCR_REGTYPEMAP - callDescrData.dwRegTypeMap = dwRegTypeMap; -#endif - callDescrData.fpReturnSize = fpReturnSize; - callDescrData.pTarget = pTarget; - - CallDescrWorkerWithHandler(&callDescrData); - - // It is still illegal to do a GC here. The return type might have/contain GC pointers. - if (retElemType == ELEMENT_TYPE_VALUETYPE) - { - _ASSERTE(*pVarRet != NULL); // we have already allocated a return object - PVOID pVarRetData = (*pVarRet)->GetData(); - - // If the return result was passed back in registers, then copy it into the return object - if (!argit.HasRetBuffArg()) - { - CopyValueClass(pVarRetData, &callDescrData.returnValue, (*pVarRet)->GetMethodTable(), (*pVarRet)->GetAppDomain()); - } - else if (pRetBufStackData != NULL) - { - // Copy the stack-allocated ret buff to the heap-allocated one. - CopyValueClass(pVarRetData, pRetBufStackData, (*pVarRet)->GetMethodTable(), (*pVarRet)->GetAppDomain()); - } - - // If the return is a Nullable, box it using Nullable conventions. - // TODO: this double allocates on constructions which is wasteful - if (!retType.IsNull()) - *pVarRet = Nullable::NormalizeBox(*pVarRet); - } - else - CMessage::GetObjectFromStack(pVarRet, &callDescrData.returnValue, retElemType, retType); - - // You can now do GCs if you want to - - if (pProtectValueClassFrame) - pProtectValueClassFrame->Pop(pThread); - - // extract the out args from the byrefs - if (pByRefs) - { - do - { - // Always extract the data ptr every time we enter this loop because - // calls to GetObjectFromStack below can cause a GC. - // Even this is not enough, because that we are passing a pointer to GC heap - // to GetObjectFromStack . If GC happens, nobody is protecting the passed in pointer. - - OBJECTREF pTmp = NULL; - void* dataLocation = pByRefs->data; - CMessage::GetObjectFromStack(&pTmp, &dataLocation, pByRefs->typ, pByRefs->typeHandle, TRUE); - (*ppVarOutParams)->SetAt(pByRefs->argIndex, pTmp); - pByRefs = pByRefs->pNext; - } - while (pByRefs); - - if (pProtectionFrame) - pProtectionFrame->Pop(pThread); - } - - } // ProfilerServerCallbackHolder - -#ifdef _PREFAST_ -#pragma warning(pop) -#endif - - LOG((LF_REMOTING, LL_INFO10, "CallDescrWithObjectArray OUT\n")); -} - -#endif // FEATURE_REMOTING -- cgit v1.2.3 From d1cfc9625334f7a64daf713335e997c1c8a8eaa7 Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Sun, 12 Feb 2017 21:08:46 -0800 Subject: Remove dead validator.cpp --- src/vm/ceeload.cpp | 3 - src/vm/validator.cpp | 946 --------------------------------------------------- 2 files changed, 949 deletions(-) delete mode 100644 src/vm/validator.cpp diff --git a/src/vm/ceeload.cpp b/src/vm/ceeload.cpp index 4a03927ee4..f6317f03aa 100644 --- a/src/vm/ceeload.cpp +++ b/src/vm/ceeload.cpp @@ -15368,9 +15368,6 @@ void Module::VerifyAllMethods() }; //Verify all methods in a module eagerly, forcing them to get loaded. - /* XXX Thu 4/26/2007 - * This code is lifted mostly from Validator.cpp - */ IMDInternalImport * pMDI = GetMDImport(); HENUMTypeDefInternalHolder hEnum(pMDI); mdTypeDef td; diff --git a/src/vm/validator.cpp b/src/vm/validator.cpp deleted file mode 100644 index 54f6ecdb2b..0000000000 --- a/src/vm/validator.cpp +++ /dev/null @@ -1,946 +0,0 @@ -// 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. - - -/* - * - * Purpose: Provide IValidate implementation. - * IValidate is used to validate PE stub, Metadata and IL. - * - */ - -#include "common.h" - -#include "corerror.h" -#include "vererror.h" -#include "ivalidator.h" -#include "securityattributes.h" -#include "corhost.h" -#include "verifier.hpp" -#include "pedecoder.h" -#include "comcallablewrapper.h" -#include "../dlls/mscorrc/resource.h" -#include "posterror.h" -#include "comcallablewrapper.h" -#include "eeconfig.h" -#include "corhost.h" -#include "security.h" -#include "appdomain.inl" - -typedef void (*VerifyErrorHandler)(void* pThis, HRESULT hrError, struct VerErrorStruct* pError); - -// Declare global variables -#define DECLARE_DATA -#include "veropcodes.hpp" -#undef DECLARE_DATA - -class CValidator -{ -public: - CValidator(IVEHandler *veh) : m_veh(veh) - { - LIMITED_METHOD_CONTRACT; - } - HRESULT VerifyAllMethodsForClass(Module *pModule, mdTypeDef cl, ValidateWorkerArgs* pArgs); - HRESULT VerifyAllGlobalFunctions(Module *pModule, ValidateWorkerArgs* pArgs); - HRESULT VerifyAssembly(Assembly *pAssembly, ValidateWorkerArgs* pArgs); - HRESULT VerifyModule(Module* pModule, ValidateWorkerArgs* pArgs); - HRESULT ReportError(HRESULT hr, ValidateWorkerArgs* pArgs, mdToken tok=0); - HRESULT VerifyMethod(COR_ILMETHOD_DECODER* pILHeader, IVEHandler* pVEHandler, WORD wFlags, ValidateWorkerArgs* pArgs); - HRESULT VerifyExportedType( - Module * pModule, - mdToken tkExportedType, - ValidateWorkerArgs * pArgs); - void HandleError(HRESULT hrError, struct VerErrorStruct* pError); - -private: - IVEHandler *m_veh; - ValidateWorkerArgs* m_pArgs; -}; // class CValidator - -HRESULT CValidator::ReportError(HRESULT hr, ValidateWorkerArgs* pArgs, mdToken tok /* = 0 */) -{ - CONTRACTL { - NOTHROW; - GC_TRIGGERS; - MODE_ANY; - } CONTRACTL_END; - - if (m_veh == NULL) - return hr; - - HRESULT hr2 = E_FAIL; - BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), return COR_E_STACKOVERFLOW); - VEContext vec; - - memset(&vec, 0, sizeof(VEContext)); - - if (tok != 0) - { - vec.flags = VER_ERR_TOKEN; - vec.Token = tok; - } - - hr2 = Verifier::ReportError(m_veh, hr, &vec, pArgs); - END_SO_INTOLERANT_CODE; - return hr2; -} // CValidator::ReportError - -// Separate method since EX_TRY uses _alloca and is in a loop below. -COR_ILMETHOD* GetILHeader(MethodDesc *pMD) -{ - STANDARD_VM_CONTRACT; - - COR_ILMETHOD *pILHeader = NULL; - - EX_TRY - { - pILHeader = pMD->GetILHeader(); - } - EX_CATCH - { - } - EX_END_CATCH(SwallowAllExceptions); - - return pILHeader; -} - -HRESULT CValidator::VerifyAllMethodsForClass(Module *pModule, mdTypeDef cl, ValidateWorkerArgs* pArgs) -{ - STANDARD_VM_CONTRACT; - - HRESULT hr = S_OK; - MethodTable *pMT = NULL; - - // In the case of COR_GLOBAL_PARENT_TOKEN (i.e. global functions), it is guaranteed - // that the module has a method table or our caller will have skipped this step. - TypeHandle th; - { - // - // Although there's no assert to disable here, we need to improve OOM reliability here. We are ignoring the HRESULT from the loader here. - // That could cause an OOM failure to be disguised as something else. OOM's - // need to be handled or propagated up to the caller. - // - CONTRACT_VIOLATION(0); - - EX_TRY { - th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, cl, - ClassLoader::ReturnNullIfNotFound, - ClassLoader::PermitUninstDefOrRef); - } - EX_CATCH_HRESULT(hr); - - if (FAILED(hr)) { - if ((hr==COR_E_TYPELOAD) || (hr==VER_E_TYPELOAD)) { - hr = ReportError(hr, pArgs,cl); - } else { - hr = ReportError(hr, pArgs); - } - goto Exit; - } - } - - pMT = th.GetMethodTable(); - if (pMT == NULL) - { - hr = ReportError(VER_E_TYPELOAD, pArgs, cl); - goto Exit; - } - - g_fVerifierOff = false; - - { - // Verify all methods in class - excluding inherited methods - MethodTable::MethodIterator it(pMT); - for (; it.IsValid(); it.Next()) - { - pArgs->pMethodDesc = it.GetMethodDesc(); - - bool fVerifyTransparentMethod = true; - if (pArgs->fTransparentMethodsOnly) - { - MethodSecurityDescriptor msd(pArgs->pMethodDesc); - fVerifyTransparentMethod = !msd.IsCritical(); - } - - if (pArgs->pMethodDesc && - pArgs->pMethodDesc->GetMethodTable() == pMT && - pArgs->pMethodDesc->IsIL() && - !pArgs->pMethodDesc->IsAbstract() && - !pArgs->pMethodDesc->IsUnboxingStub() && - fVerifyTransparentMethod) - { - COR_ILMETHOD* pILHeader = GetILHeader(pArgs->pMethodDesc); - - if (pILHeader != NULL) - { - COR_ILMETHOD_DECODER::DecoderStatus status; - COR_ILMETHOD_DECODER ILHeader(pILHeader, - pArgs->pMethodDesc->GetMDImport(), &status); - - if (status == COR_ILMETHOD_DECODER::SUCCESS) - { - hr = VerifyMethod(&ILHeader, m_veh, VER_FORCE_VERIFY, pArgs); - if (hr == VER_E_INTERNAL) // this probably means peverify.dll was missing - { - goto Exit; - } - } - else if (status == COR_ILMETHOD_DECODER::VERIFICATION_ERROR) - { - hr = COR_E_VERIFICATION; - } - else if (status == COR_ILMETHOD_DECODER::FORMAT_ERROR) - { - hr = COR_E_BADIMAGEFORMAT; - } - else - { - _ASSERTE(!"Unhandled status from COR_ILMETHOD_DECODER"); - } - } - else - { - hr = COR_E_BADIMAGEFORMAT; - } - - if (FAILED(hr)) - hr = ReportError(hr, pArgs); - - if (FAILED(hr)) - goto Exit; - } - // We should ideally have an API to yield to the host, - // but this is not critical for Whidbey. - if (CLRTaskHosted()) - ClrSleepEx(0, FALSE); - } - } - -Exit: - pArgs->pMethodDesc = NULL; - return hr; -} // CValidator::VerifyAllMethodsForClass - -//--------------------------------------------------------------------------------------- -// -void -MethodDescAndCorILMethodDecoderToCorInfoMethodInfo( - MethodDesc * ftn, - COR_ILMETHOD_DECODER * ILHeader, - CORINFO_METHOD_INFO * pMethodInfo) -{ - STANDARD_VM_CONTRACT; - - pMethodInfo->ftn = CORINFO_METHOD_HANDLE(ftn); - pMethodInfo->scope = CORINFO_MODULE_HANDLE(ftn->GetModule()); - pMethodInfo->ILCode = const_cast(ILHeader->Code); - pMethodInfo->ILCodeSize = ILHeader->GetCodeSize(); - pMethodInfo->maxStack = ILHeader->GetMaxStack(); - pMethodInfo->EHcount = ILHeader->EHCount(); - pMethodInfo->options = - (CorInfoOptions) - (((ILHeader->GetFlags() & CorILMethod_InitLocals) ? CORINFO_OPT_INIT_LOCALS : 0) | - (ftn->AcquiresInstMethodTableFromThis() ? CORINFO_GENERICS_CTXT_FROM_THIS : 0) | - (ftn->RequiresInstMethodTableArg() ? CORINFO_GENERICS_CTXT_FROM_METHODTABLE : 0) | - (ftn->RequiresInstMethodDescArg() ? CORINFO_GENERICS_CTXT_FROM_METHODDESC : 0)); - - PCCOR_SIGNATURE pSigToConvert; - DWORD cbSigToConvert; - ftn->GetSig(&pSigToConvert, &cbSigToConvert); - CONSISTENCY_CHECK(NULL != pSigToConvert); - // fetch the method signature - CEEInfo::ConvToJitSig( - pSigToConvert, - cbSigToConvert, - pMethodInfo->scope, - mdTokenNil, - &pMethodInfo->args, - ftn, - false); - - //@GENERICS: - // Shared generic methods and shared methods on generic structs take an extra argument representing their instantiation - if (ftn->RequiresInstArg()) - pMethodInfo->args.callConv = (CorInfoCallConv) (pMethodInfo->args.callConv | CORINFO_CALLCONV_PARAMTYPE); - - // method attributes and signature are consistant - _ASSERTE(!!ftn->IsStatic() == ((pMethodInfo->args.callConv & CORINFO_CALLCONV_HASTHIS) == 0)); - - // And its local variables - CEEInfo::ConvToJitSig( - ILHeader->LocalVarSig, - ILHeader->cbLocalVarSig, - pMethodInfo->scope, - mdTokenNil, - &pMethodInfo->locals, - ftn, - true); -} // MethodDescAndCorILMethodDecoderToCorInfoMethodInfo - -//--------------------------------------------------------------------------------------- -// -void PEVerifyErrorHandler(void* pThis, HRESULT hrError, struct VerErrorStruct* pError) -{ - WRAPPER_NO_CONTRACT; - STATIC_CONTRACT_SO_TOLERANT; - ((CValidator*)pThis)->HandleError(hrError, pError); -} - -void CValidator::HandleError(HRESULT hrError, struct VerErrorStruct* pError) -{ - CONTRACTL - { - THROWS; - GC_TRIGGERS; - MODE_ANY; - SO_TOLERANT; - } - CONTRACTL_END; - - BEGIN_SO_INTOLERANT_CODE(GetThread()); - _ASSERTE(sizeof(VEContext) == sizeof(struct VerErrorStruct)); - Verifier::ReportError(m_veh, hrError, (VEContext*)pError, m_pArgs); - END_SO_INTOLERANT_CODE; -} -typedef void (__stdcall* VerifyFunc)(ICorJitInfo* pJitInfo, CORINFO_METHOD_INFO* pMethodInfo, VerifyErrorHandler pErrorHandler, void* pThis); -static void VerifyMethodHelper(VerifyFunc pVerFunc, CEEJitInfo* pJI, CORINFO_METHOD_INFO* pMethodInfo, void* pThis) -{ - // Helper method to allow us to use SO_TOLERANT_CODE macro - STATIC_CONTRACT_SO_INTOLERANT; - WRAPPER_NO_CONTRACT; - - BEGIN_SO_TOLERANT_CODE(GetThread()); - // Verify the method - pVerFunc(pJI, pMethodInfo, PEVerifyErrorHandler, pThis); - END_SO_TOLERANT_CODE; - -} - -static Volatile g_pVerFunc = NULL; - -HRESULT CValidator::VerifyMethod(COR_ILMETHOD_DECODER* pILHeader, IVEHandler* pVEHandler, WORD wFlags, ValidateWorkerArgs* pArgs) -{ - STANDARD_VM_CONTRACT; - - HRESULT hr = S_OK; - EX_TRY - { - // Find the DLL entrypoint - m_pArgs = pArgs; - if (g_pVerFunc.Load() == NULL) - { - HINSTANCE hJit64 = NULL; - if (SUCCEEDED(g_pCLRRuntime->LoadLibrary(W("peverify.dll"), &hJit64))) - { - typedef void (__stdcall* psxsPeVerifyStartup) (CoreClrCallbacks); - psxsPeVerifyStartup sxsPeVerifyStartup = (psxsPeVerifyStartup) GetProcAddress(hJit64, "sxsPeVerifyStartup"); - - if(sxsPeVerifyStartup) - { - CoreClrCallbacks cccallbacks = GetClrCallbacks(); - (*sxsPeVerifyStartup) (cccallbacks); - g_pVerFunc = (VerifyFunc)GetProcAddress(hJit64, "VerifyMethod"); - } - } - } - - if(!g_pVerFunc) - { - _ASSERTE(!"Failed to load peverify.dll or find VerifyMethod proc address"); - hr = VER_E_INTERNAL; - } - else - { - Thread *pThread = GetThread(); - if (pThread->IsAbortRequested()) - { - pThread->HandleThreadAbort(); - } - // Prepare the args - MethodDesc* ftn = pArgs->pMethodDesc; - CEEJitInfo ji(pArgs->pMethodDesc, pILHeader, NULL, true /* verify only */); - CORINFO_METHOD_INFO methodInfo; - MethodDescAndCorILMethodDecoderToCorInfoMethodInfo(ftn, pILHeader, &methodInfo); - - // Verify the method - VerifyMethodHelper(g_pVerFunc, &ji, &methodInfo, this); - } - } - EX_CATCH - { - // Catch and report any errors that peverify.dll lets fall through (ideally that should never happen) - hr = GET_EXCEPTION()->GetHR(); - hr = ReportError(hr, pArgs); - } - EX_END_CATCH(RethrowTerminalExceptions) - - return hr; -} // CValidator::VerifyMethod - -// Helper function to verify the global functions -HRESULT CValidator::VerifyAllGlobalFunctions(Module *pModule, ValidateWorkerArgs* pArgs) -{ - STANDARD_VM_CONTRACT; - - HRESULT hr = S_OK; - // Is there anything worth verifying? - if (pModule->GetGlobalMethodTable()) - hr = VerifyAllMethodsForClass(pModule, COR_GLOBAL_PARENT_TOKEN, pArgs); - return hr; -} // CValidator::VerifyAllGlobalFunctions - -HRESULT CValidator::VerifyModule(Module* pModule, ValidateWorkerArgs* pArgs) -{ - STANDARD_VM_CONTRACT; - - // Get a count of all the classdefs and enumerate them. - HRESULT hr = S_OK; - IMDInternalImport * pMDI = NULL; - - if (pModule == NULL) - { - IfFailGo(VER_E_BAD_MD); - } - - pMDI = pModule->GetMDImport(); - if (pMDI == NULL) - { - IfFailGo(VER_E_BAD_MD); - } - - // First verify all global functions - if there are any - IfFailGoto( - VerifyAllGlobalFunctions(pModule, pArgs), - ErrExit_SkipReportError); - - { - HENUMTypeDefInternalHolder hTypeDefEnum(pMDI); - - IfFailGo(hTypeDefEnum.EnumTypeDefInitNoThrow()); - - // Verify all TypeDefs - mdTypeDef tkTypeDef; - while (pMDI->EnumTypeDefNext(&hTypeDefEnum, &tkTypeDef)) - { - IfFailGoto( - VerifyAllMethodsForClass(pModule, tkTypeDef, pArgs), - ErrExit_SkipReportError); - } - } - - { - HENUMInternalHolder hExportedTypeEnum(pMDI); - - IfFailGo(hExportedTypeEnum.EnumInitNoThrow( - mdtExportedType, - mdTokenNil)); - - // Verify all ExportedTypes - mdToken tkExportedType; - while (pMDI->EnumNext(&hExportedTypeEnum, &tkExportedType)) - { - IfFailGoto( - VerifyExportedType(pModule, tkExportedType, pArgs), - ErrExit_SkipReportError); - } - } - -ErrExit: - if (FAILED(hr)) - { - hr = ReportError(hr, pArgs); - } - -ErrExit_SkipReportError: - return hr; -} // CValidator::VerifyModule - -HRESULT CValidator::VerifyAssembly(Assembly *pAssembly, ValidateWorkerArgs* pArgs) -{ - STANDARD_VM_CONTRACT; - - HRESULT hr; - - _ASSERTE(pAssembly->GetManifestImport()); - - // Verify the module containing the manifest. There is no - // FileRefence so will no show up in the list. - hr = VerifyModule(pAssembly->GetManifestModule(), pArgs); - if (FAILED(hr)) - goto Exit; - - { - IMDInternalImport* pManifestImport = pAssembly->GetManifestImport(); - - HENUMInternalHolder hEnum(pManifestImport); - - mdToken mdFile; - hr = hEnum.EnumInitNoThrow(mdtFile, mdTokenNil); - if (FAILED(hr)) - { - hr = ReportError(hr, pArgs); - goto Exit; - } - - while(pManifestImport->EnumNext(&hEnum, &mdFile)) - { - DomainFile* pModule = pAssembly->GetManifestModule()->LoadModule(GetAppDomain(), mdFile, FALSE); - - if (pModule != NULL) - { - hr = VerifyModule(pModule->GetModule(), pArgs); - if (FAILED(hr)) - goto Exit; - } - } - } - -Exit: - return hr; -} // CValidator::VerifyAssembly - -HRESULT -CValidator::VerifyExportedType( - Module * pModule, - mdToken tkExportedType, - ValidateWorkerArgs * pArgs) -{ - STANDARD_VM_CONTRACT; - - HRESULT hr; - TypeHandle th; - NameHandle nameHandle(pModule, tkExportedType); - - LPCSTR szNamespace; - LPCSTR szName; - IfFailGo(pModule->GetMDImport()->GetExportedTypeProps( - tkExportedType, - &szNamespace, - &szName, - NULL, // tkImplementation - NULL, // tkTypeDefId - NULL)); // dwExportedTypeFlags - - nameHandle.SetName(szNamespace, szName); - - EX_TRY - { - th = pModule->GetClassLoader()->LoadTypeHandleThrowing( - &nameHandle, - CLASS_LOADED, - pModule); - hr = S_OK; - } - EX_CATCH - { - hr = GET_EXCEPTION()->GetHR(); - } - EX_END_CATCH(SwallowAllExceptions); - - IfFailGo(hr); - if (th.GetMethodTable() == NULL) - { - IfFailGo(VER_E_TYPELOAD); - } - -ErrExit: - if (FAILED(hr)) - { - hr = ReportError(hr, pArgs, tkExportedType); - } - - return hr; -} // CValidator::VerifyExportedType - -static void ValidateWorker(LPVOID /* ValidateWorker_Args */ ptr) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - ValidateWorkerArgs *args = (ValidateWorkerArgs *) ptr; - AppDomain *pDomain = GetThread()->GetDomain(); - - StackSString ssFile(args->wszFileName); - StackSString ssFileDir; - StackSString ssDirectory; - - // Fill ssDirectory with just drive of the file (e.g. 'C:') - SplitPath(ssFile, &ssDirectory, &ssFileDir, NULL, NULL); - // Now apped directory from the file name (incl. leading and trailing '/' or '\') - ssDirectory.Append(ssFileDir); - - { - // Set up the domain to resolve all dependency assemblies for introspection - struct _gc { - OBJECTREF orAppDomain; - STRINGREF refDirectory; - } gc; - ZeroMemory(&gc, sizeof(gc)); - - GCPROTECT_BEGIN(gc); - - gc.orAppDomain = pDomain->GetExposedObject(); - if (!ssDirectory.IsEmpty()) - { - gc.refDirectory = StringObject::NewString(ssDirectory); - } - - MethodDescCallSite meth(METHOD__APP_DOMAIN__ENABLE_RESOLVE_ASSEMBLIES_FOR_INTROSPECTION, &gc.orAppDomain); - ARG_SLOT args[2] = - { - ObjToArgSlot(gc.orAppDomain), - ObjToArgSlot(gc.refDirectory) - }; - meth.Call(args); - - GCPROTECT_END(); - } - - GCX_PREEMP(); - - Assembly *pAssembly; - if (args->wszFileName) - { - // Load the primary assembly for introspection - AssemblySpec spec; - spec.SetCodeBase(args->wszFileName); - spec.SetIntrospectionOnly(TRUE); - pAssembly = spec.LoadAssembly(FILE_LOADED); - } - else - { - // TODO: This is a workaround to get SQLCLR running. - // Our loader requires that a parent assembly is specified in order to load an - // assembly from byte array. But here we do not know the parent. - PEAssemblyHolder pFile(PEAssembly::OpenMemory(SystemDomain::System()->SystemFile(), - args->pe, args->size, TRUE)); - pAssembly = pDomain->LoadAssembly(NULL, pFile, FILE_LOADED); - } - - // Verify the assembly - args->hr = args->val->VerifyAssembly(pAssembly, args); -} - - -static HRESULT ValidateHelper( - IVEHandler *veh, - IUnknown *pAppDomain, - DWORD ulAppDomainId, - BOOL UseId, - unsigned long ulFlags, - unsigned long ulMaxError, - unsigned long token, - __in_z LPWSTR fileName, - BYTE *pe, - unsigned long ulSize) -{ - CONTRACTL { - NOTHROW; - GC_TRIGGERS; - MODE_ANY; - SO_TOLERANT; - } CONTRACTL_END; - - Thread *pThread = GetThread(); - - if (pe == NULL) - return E_POINTER; - - HRESULT hr = S_OK; - BEGIN_SO_INTOLERANT_CODE_NOTHROW(pThread, return COR_E_STACKOVERFLOW); - ADID pDomain; - ValidateWorkerArgs args; - CValidator val(veh); - AppDomainFromIDHolder ad; - - BOOL Chk = FALSE; - BOOL UnloadDomain = FALSE; - - GCX_COOP(); - - EX_TRY { - PEDecoder pev(pe, (COUNT_T)ulSize); - - args.wszFileName = fileName; - args.fVerbose = (ulFlags & VALIDATOR_EXTRA_VERBOSE) ? true : false; - args.fShowSourceLines = (ulFlags & VALIDATOR_SHOW_SOURCE_LINES) ? true : false; - args.fTransparentMethodsOnly = (ulFlags & VALIDATOR_TRANSPARENT_ONLY) ? true : false; - args.val = &val; - args.pe = pe; - args.size = ulSize; - - if((ulFlags & VALIDATOR_NOCHECK_PEFORMAT) == 0) - { - // Verify the PE header / native stubs first - // This validation is not performed on non-manifest modules. - Chk = ((ulFlags & VALIDATOR_CHECK_ILONLY) != 0) ? (BOOL) pev.CheckILOnlyFormat() : - (BOOL) pev.CheckILFormat(); - if (!Chk) - { - hr = val.ReportError(VER_E_BAD_PE, &args); - - if (FAILED(hr)) - goto End; - } - } - if((ulFlags & VALIDATOR_CHECK_PEFORMAT_ONLY) != 0) - goto End; - - if (fileName) - { - AppDomain* pAD = AppDomain::CreateDomainContext(fileName); - UnloadDomain = TRUE; - pAD->SetPassiveDomain(); - pDomain=pAD->GetId(); - } - else if (UseId) - { - pDomain = (ADID)ulAppDomainId; - } - else - { - SystemDomain::LockHolder lh; - ComCallWrapper* pWrap = GetCCWFromIUnknown(pAppDomain, FALSE); - if (pWrap == NULL) - { - hr = COR_E_APPDOMAINUNLOADED; - goto End; - } - pDomain = pWrap->GetDomainID(); - } - - if (FAILED(hr)) - { - hr = val.ReportError(hr, &args); - goto End; - } - - ad.Assign(pDomain, TRUE); - if (ad.IsUnloaded()) - COMPlusThrow(kAppDomainUnloadedException); - if (ad->IsIllegalVerificationDomain()) - COMPlusThrow(kFileLoadException, IDS_LOADINTROSPECTION_DISALLOWED); - ad->SetVerificationDomain(); - ad.Release(); - - args.val = &val; - - // We need a file path here. This is to do a fusion bind, and also - // to make sure we can find any modules in the assembly. We assume - // that the path points to the same place the bytes came from, which is true - // with PEVerify, but perhaps not with other clients. - - if (pDomain != pThread->GetDomain()->GetId()) - { - pThread->DoADCallBack( - pDomain, ValidateWorker, &args); - } - else - { - ValidateWorker(&args); - } - - if (FAILED(args.hr)) - hr = val.ReportError(args.hr, &args); - - // Only Unload the domain if we created it. - if (UnloadDomain) - AppDomain::UnloadById(pDomain,TRUE); -End:; - - } - EX_CATCH - { - hr = GET_EXCEPTION()->GetHR(); - hr = val.ReportError(hr, &args); - } - EX_END_CATCH(RethrowSOExceptions) - - END_SO_INTOLERANT_CODE; - return hr; -} - -void GetFormattingErrorMsg(__out_ecount(ulMaxLength) __out_z LPWSTR msg, unsigned int ulMaxLength) -{ - CONTRACTL { - NOTHROW; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(ulMaxLength >= 30); - } CONTRACTL_END; - - EX_TRY - { - SString s; - s.LoadResource(CCompRC::Debugging, IDS_VER_E_FORMATTING); - wcsncpy_s(msg, ulMaxLength, s.GetUnicode(), _TRUNCATE); - } - EX_CATCH - { - wcscpy_s(msg, ulMaxLength, W("Error loading resource string")); - } - EX_END_CATCH(SwallowAllExceptions) -} - -static HRESULT FormatEventInfoHelper( - HRESULT hVECode, - VEContext Context, - __out_ecount(ulMaxLength) __out_z LPWSTR msg, - unsigned int ulMaxLength, - SAFEARRAY *psa) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_ANY; - PRECONDITION(ulMaxLength >= 30); - SO_TOLERANT; - } CONTRACTL_END; - - BEGIN_SO_INTOLERANT_CODE(GetThread()); - - VerError err; - memcpy(&err, &Context, sizeof(VerError)); - - ValidateWorkerArgs argsDefault; - ValidateWorkerArgs* pArgs = &argsDefault; - - // We passed a pointer to the ValidateWorkerArgs object through - // the SAFEARRAY casted as a UINT because there was no room left in the - // interface to pass information through it. - { - UINT dim; - LONG l; -#ifdef _WIN64 - VARTYPE vt; -#endif // _WIN64 - VARIANT var; - - if(!psa) { - goto lDone; - } - - dim = SafeArrayGetDim(psa); - if (dim != 1) { - _ASSERTE(!"There should be one element in the SafeArray"); - goto lDone; - } - - if (FAILED(SafeArrayGetLBound(psa, 1, &l))) { - _ASSERTE(false); - goto lDone; - } - if (l != 0) { - _ASSERTE(!"expected the lower bound to be zero"); - goto lDone; - } - - if (FAILED(SafeArrayGetUBound(psa, 1, &l))) { - _ASSERTE(false); - goto lDone; - } - if (l != 0) { - _ASSERTE(!"expected the upper bound to be zero"); - goto lDone; - } -#ifdef _WIN64 - // This check fails on Win2K when it should pass - SafeArrayGetVartype(psa, &vt); - if(vt != VT_VARIANT) { - _ASSERTE(!"expected the ElementType to be a VT_VARIANT"); - goto lDone; - } -#endif // _WIN64 - l = 0; - SafeArrayGetElement(psa, &l, &var); - -#ifdef _WIN64 - if (V_VT(&var) != VT_UI8) { // We expect the VarType to be a VT_UI8 (VT_UI8 is not supported on Windows 2000) - _ASSERTE(false); - goto lDone; - } - - pArgs = (ValidateWorkerArgs*)(size_t)V_UI8(&var); -#else - // We don't check that the type is V_UINT here because that check fails on Win2K when it should pass - pArgs = (ValidateWorkerArgs*)(size_t)V_UINT(&var); -#endif - - } -lDone: ; - - EX_TRY - { - Verifier::GetErrorMsg(hVECode, err, msg, ulMaxLength, pArgs); - } - EX_CATCH - { - GetFormattingErrorMsg(msg, ulMaxLength); - } - EX_END_CATCH(SwallowAllExceptions) - - END_SO_INTOLERANT_CODE; - return S_OK; -} - -HRESULT CorValidator::Validate( - IVEHandler *veh, - IUnknown *pAppDomain, - unsigned long ulFlags, - unsigned long ulMaxError, - unsigned long token, - __in_z LPWSTR fileName, - BYTE *pe, - unsigned long ulSize) -{ - WRAPPER_NO_CONTRACT; - STATIC_CONTRACT_SO_TOLERANT; - return ValidateHelper(veh, pAppDomain, 0, FALSE, ulFlags, ulMaxError, - token, fileName, pe, ulSize); -} - -HRESULT CLRValidator::Validate( - IVEHandler *veh, - unsigned long ulAppDomainId, - unsigned long ulFlags, - unsigned long ulMaxError, - unsigned long token, - __in_z LPWSTR fileName, - BYTE *pe, - unsigned long ulSize) -{ - WRAPPER_NO_CONTRACT; - STATIC_CONTRACT_SO_TOLERANT; - return ValidateHelper(veh, NULL, ulAppDomainId, TRUE, ulFlags, ulMaxError, - token, fileName, pe, ulSize); -} - -HRESULT CorValidator::FormatEventInfo( - HRESULT hVECode, - VEContext Context, - __out_ecount(ulMaxLength) LPWSTR msg, - unsigned long ulMaxLength, - SAFEARRAY *psa) -{ - WRAPPER_NO_CONTRACT; - return FormatEventInfoHelper(hVECode, Context, msg, ulMaxLength, psa); -} - -HRESULT CLRValidator::FormatEventInfo( - HRESULT hVECode, - VEContext Context, - __out_ecount(ulMaxLength) LPWSTR msg, - unsigned long ulMaxLength, - SAFEARRAY *psa) -{ - WRAPPER_NO_CONTRACT; - STATIC_CONTRACT_SO_TOLERANT; - return FormatEventInfoHelper(hVECode, Context, msg, ulMaxLength, psa); -} - - -- cgit v1.2.3 From 01656a9802c4885058a9da831f6e819688a799ed Mon Sep 17 00:00:00 2001 From: danmosemsft Date: Mon, 13 Feb 2017 15:03:15 -0800 Subject: Fix build break --- src/vm/mscorlib.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/vm/mscorlib.cpp b/src/vm/mscorlib.cpp index 608cacdf1a..53a9ec6fc1 100644 --- a/src/vm/mscorlib.cpp +++ b/src/vm/mscorlib.cpp @@ -96,7 +96,7 @@ #include "multicorejit.h" #endif -#ifdef FEATURE_COMINTEROP +#if defined(FEATURE_COMINTEROP) && defined(FEATURE_REFLECTION_ONLY_LOAD) #include "clrprivtypecachereflectiononlywinrt.h" #endif -- cgit v1.2.3