summaryrefslogtreecommitdiff
path: root/src/inc/holder.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/inc/holder.h')
-rw-r--r--src/inc/holder.h1515
1 files changed, 1515 insertions, 0 deletions
diff --git a/src/inc/holder.h b/src/inc/holder.h
new file mode 100644
index 0000000000..a4d19bbf92
--- /dev/null
+++ b/src/inc/holder.h
@@ -0,0 +1,1515 @@
+// 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 __HOLDER_H_
+#define __HOLDER_H_
+
+#include <wincrypt.h>
+#include "cor.h"
+#include "genericstackprobe.h"
+#include "staticcontract.h"
+#include "volatile.h"
+#include "palclr.h"
+
+#ifdef PAL_STDCPP_COMPAT
+#include <utility>
+#include <type_traits>
+#else
+#include "clr_std/utility"
+#include "clr_std/type_traits"
+#endif
+
+#if defined(FEATURE_COMINTEROP) && !defined(STRIKE)
+#include <Activation.h>
+#include <Inspectable.h>
+#endif
+
+// Note: you can't use CONTRACT's in this file. You can't use dynamic contracts because the impl of dynamic
+// contracts depends on holders. You can't use static contracts because they include the function name as a string,
+// and the template names in this file are just too long, so you get a compiler error.
+//
+// All the functions in this file are pretty basic, so the lack of CONTRACT's isn't a big loss.
+
+#ifdef _MSC_VER
+// Make sure we can recurse deep enough for FORCEINLINE
+#pragma inline_recursion(on)
+#pragma inline_depth(16)
+#pragma warning(disable:4714)
+#endif // _MSC_VER
+
+//------------------------------------------------------------------------------------------------
+// Declare but do not define methods that would normally be automatically generated by the
+// compiler. This will produce a link-time error if they are used. This is involved in object
+// initialization and operator eliding; see
+// http://groups.google.com/group/comp.lang.c++/msg/3cd673ab749bed83?dmode=source
+// for the intricate details.
+
+#ifdef __GNUC__
+// GCC checks accessibility of the copy ctor before performing elision optimization, so
+// it must be declared as public. VC does not, so we can declare it private to give an
+// earlier error message.
+#define HIDE_GENERATED_METHODS(_NAME) \
+ public: \
+ _NAME(_NAME const &); \
+ private: \
+ _NAME & operator=(_NAME const &);
+#else
+#define HIDE_GENERATED_METHODS(_NAME) \
+ private: \
+ _NAME(_NAME const &); \
+ _NAME & operator=(_NAME const &);
+#endif
+
+
+#ifdef _DEBUG
+
+#ifdef FEATURE_FUSION
+namespace NATIVE_BINDER_SPACE
+{
+ class NativeAssembly;
+}
+#endif //FEATURE_FUSION
+
+//------------------------------------------------------------------------------------------------
+// This is used to make Visual Studio autoexp.dat work sensibly with holders again.
+// The problem is that certain codebases (particulary Fusion) implement key data structures
+// using a class but refer to it using a holder to an interface type. This combination prevents
+// autoexp rules from working as desired.
+//
+// Example: Take this useful autoexp rule for CAssemblyName.
+//
+// CAssemblyName=<_rProp._rProp[3].asStr>
+//
+// To get the same rule to fire when your assemblyname is wrapped in a ReleaseHolder,
+// add these companion rules.
+//
+// HolderBase<CAssemblyName *>=<m_value->_rProp._rProp[3].asStr>
+// HolderBase<IAssemblyName *>=<m_pAutoExpVisibleValue->_asCAssemblyName->_rProp._rProp[3].asStr>
+//
+//------------------------------------------------------------------------------------------------
+struct AutoExpVisibleValue
+{
+ private:
+ union
+ {
+ // Only include a class name here if it is customarily referred to through an abstract interface.
+#ifdef FEATURE_FUSION
+ const class CAssemblyName *_asCAssemblyName;
+ const class CAssembly *_asCAssembly;
+ const class CAssemblyManifestImport *_asCAssemblyManifestImport;
+ const class CAssemblyModuleImport *_asCAssemblyModuleImport;
+ const class CHostAssembly *_asCHostAssembly;
+ const class CHostAssemblyModuleImport *_asCHostAssemblyModuleImport;
+ const class BindResult *_asBindResult;
+ const class BindContext *_asBindContext;
+ const class NATIVE_BINDER_SPACE::NativeAssembly *_asNativeAssembly;
+ const class AssemblyLocation *_asAssemblyLocation;
+#endif //FEATURE_FUSION
+
+#if defined(FEATURE_APPX)
+ const class AppXBindResultImpl *_asAppXBindResultImpl;
+#endif
+
+#ifndef FEATURE_CORECLR
+ const class PEFingerprint *_asPEFingerprint;
+#endif //!FEATURE_CORECLR
+ const void *_pPreventEmptyUnion;
+ };
+};
+#endif //_DEBUG
+
+//-----------------------------------------------------------------------------
+// Holder is the base class of all holder objects. Any backout object should derive from it.
+// (Eventually some additional bookeeping and exception handling code will be placed in this
+// base class.)
+//
+// There are several ways to use this class:
+// 1. Derive from HolderBase, and instantiate a Holder or Wrapper around your base. This is necessary
+// if you need to add more state to your holder.
+// 2. Instantiate the Holder template with your type and functions.
+// 3. Instantiate the Wrapper template with your type and functions. The Wrapper adds some additional
+// operator overloads to provide "smart pointer" like behavior
+// 4. Use a prebaked Holder. This is ALWAYS the preferable strategy. It is expected that
+// the general design patter is that Holders will be provided as part of a typical data abstraction.
+// (See Crst for an example of this.)
+//-----------------------------------------------------------------------------
+
+
+
+//-----------------------------------------------------------------------------
+// HolderBase defines the base holder functionality. You can subtype and plug in
+// a different base if you need to add more members for access during
+// acquire & release
+//-----------------------------------------------------------------------------
+template <typename TYPE>
+class HolderBase
+{
+ protected:
+ TYPE m_value;
+
+ HolderBase(TYPE value)
+ : m_value(value)
+ {
+ // TODO: Find a way to enable this check.
+ // We can have a holder in SO tolerant, then probe, then acquire a value. This works
+ // because the dtor is guaranteed to run with enough stack.
+ // EnsureSOIntolerantOK(__FUNCTION__, __FILE__, __LINE__);
+
+#ifdef _DEBUG
+ m_pAutoExpVisibleValue = (const AutoExpVisibleValue *)(&m_value);
+#endif //_DEBUG
+ }
+
+ void DoAcquire()
+ {
+ // Insert any global or thread bookeeping here
+ }
+
+ void DoRelease()
+ {
+ // Insert any global or thread bookeeping here
+ }
+
+#ifdef _DEBUG
+ private:
+ // NOT DEAD CODE: This field is not referenced in the source code but it is not a dead field. See comments above "class AutoExpVisibleValue" for why this field exists.
+ // Note: What we really want is for m_value and m_pAutoExpVisibleValue to be members of a union. But the compiler won't let you build that
+ // since it can't prove that "TYPE" doesn't have a non-trivial constructor.
+ const AutoExpVisibleValue *m_pAutoExpVisibleValue; // This field is to be referenced from individual autoexp.dat files, NOT from the CLR source code.
+#endif //_DEBUG
+
+}; // class HolderBase<>
+
+#ifndef _PREFAST_ // Work around an ICE error in EspX.dll
+
+template <typename TYPE>
+BOOL CompareDefault(TYPE value, TYPE defaultValue)
+{
+ STATIC_CONTRACT_SUPPORTS_DAC;
+ return value == defaultValue;
+}
+
+#else
+
+template <typename TYPE>
+BOOL CompareDefault(TYPE value, TYPE defaultValue)
+{
+ return FALSE;
+}
+
+#endif
+
+
+template <typename TYPE>
+BOOL NoNull(TYPE value, TYPE defaultValue)
+{
+ return FALSE;
+}
+
+// Used e.g. for retail version of code:SyncAccessHolder
+template <typename TYPE>
+class NoOpBaseHolder
+{
+ public:
+ FORCEINLINE NoOpBaseHolder()
+ {
+ }
+ FORCEINLINE NoOpBaseHolder(TYPE value, BOOL take = TRUE)
+ {
+ }
+ FORCEINLINE ~NoOpBaseHolder()
+ {
+ }
+ FORCEINLINE void Assign(TYPE value, BOOL fTake = TRUE)
+ {
+ }
+ FORCEINLINE void Acquire()
+ {
+ }
+ FORCEINLINE void Release()
+ {
+ }
+ FORCEINLINE void Clear()
+ {
+ }
+ FORCEINLINE void SuppressRelease()
+ {
+ }
+ FORCEINLINE TYPE Extract()
+ {
+ }
+ FORCEINLINE TYPE GetValue()
+ {
+ }
+ FORCEINLINE BOOL IsNull() const
+ {
+ return FALSE;
+ }
+
+ private:
+ NoOpBaseHolder& operator=(NoOpBaseHolder const &);
+ NoOpBaseHolder(NoOpBaseHolder const &);
+}; // NoOpBaseHolder<>
+
+
+template
+ <
+ typename TYPE,
+ typename BASE,
+ UINT_PTR DEFAULTVALUE = 0,
+ BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>,
+ HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq
+ >
+class BaseHolder : protected BASE
+{
+ protected:
+ BOOL m_acquired; // Have we acquired the resource?
+
+ static_assert(!std::is_pointer<TYPE>::value || DEFAULTVALUE == 0 || DEFAULTVALUE == UINT_PTR(-1 /*INVALID_HANDLE_VALUE*/),
+ "DEFAULTVALUE must be NULL for pointer holders and wrappers.");
+
+ public:
+ FORCEINLINE BaseHolder()
+ : BASE(TYPE(DEFAULTVALUE)),
+ m_acquired(FALSE)
+ {
+ }
+ FORCEINLINE BaseHolder(TYPE value)
+ : BASE(value),
+ m_acquired(FALSE)
+ {
+ if (!IsNull())
+ Acquire();
+ }
+ FORCEINLINE BaseHolder(TYPE value, BOOL takeOwnership)
+ : BASE(value),
+ m_acquired(FALSE)
+ {
+ if (takeOwnership)
+ Acquire();
+ }
+ FORCEINLINE ~BaseHolder()
+ {
+ Release();
+ }
+ // Sets the value to 'value'. Doesn't call Acquire if value is DEFAULTVALUE.
+ FORCEINLINE void Assign(TYPE value)
+ {
+ Assign(value, !IS_NULL(value, TYPE(DEFAULTVALUE)));
+ }
+ // Sets the value to 'value'. Doesn't call Acquire if fTake is FALSE.
+ FORCEINLINE void Assign(TYPE value, BOOL takeOwnership)
+ {
+ Release();
+ this->m_value = value;
+ if (takeOwnership)
+ Acquire();
+ }
+ FORCEINLINE void Acquire()
+ {
+ STATIC_CONTRACT_WRAPPER;
+ _ASSERTE(!m_acquired);
+
+ if (!IsNull())
+ {
+ this->DoAcquire();
+ m_acquired = TRUE;
+ }
+ }
+ FORCEINLINE void Release()
+ {
+ STATIC_CONTRACT_WRAPPER;
+ if (m_acquired)
+ {
+ _ASSERTE(!IsNull());
+
+ if (VALIDATION_TYPE != HSV_NoValidation)
+ {
+ VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(VALIDATION_TYPE);
+ this->DoRelease();
+ }
+ else
+ {
+ this->DoRelease();
+ }
+ m_acquired = FALSE;
+ }
+ }
+
+ FORCEINLINE void Clear()
+ {
+ STATIC_CONTRACT_WRAPPER;
+ Assign(TYPE(DEFAULTVALUE), FALSE);
+ }
+ FORCEINLINE void SuppressRelease()
+ {
+ STATIC_CONTRACT_LEAF;
+ m_acquired = FALSE;
+ }
+ FORCEINLINE TYPE Extract()
+ {
+ STATIC_CONTRACT_WRAPPER;
+ SuppressRelease();
+ return GetValue();
+ }
+ FORCEINLINE TYPE GetValue()
+ {
+ STATIC_CONTRACT_LEAF;
+ return this->m_value;
+ }
+ FORCEINLINE BOOL IsNull() const
+ {
+ STATIC_CONTRACT_WRAPPER;
+ return IS_NULL(this->m_value, TYPE(DEFAULTVALUE));
+ }
+
+ HIDE_GENERATED_METHODS(BaseHolder)
+}; // BaseHolder<>
+
+template <void (*ACQUIRE)(), void (*RELEASEF)(), HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq>
+class StateHolder
+{
+ private:
+ BOOL m_acquired; // Have we acquired the state?
+
+ public:
+ FORCEINLINE StateHolder(BOOL take = TRUE)
+ : m_acquired(FALSE)
+ {
+ STATIC_CONTRACT_WRAPPER;
+ if (take)
+ Acquire();
+ }
+ FORCEINLINE ~StateHolder()
+ {
+ STATIC_CONTRACT_WRAPPER;
+ Release();
+ }
+ FORCEINLINE void Acquire()
+ {
+ STATIC_CONTRACT_WRAPPER;
+ // Insert any global or thread bookeeping here
+
+ _ASSERTE(!m_acquired);
+
+ ACQUIRE();
+ m_acquired = TRUE;
+ }
+ FORCEINLINE void Release()
+ {
+ STATIC_CONTRACT_WRAPPER;
+ // Insert any global or thread bookeeping here
+
+ if (m_acquired)
+ {
+ if (VALIDATION_TYPE != HSV_NoValidation)
+ {
+ VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(VALIDATION_TYPE);
+ RELEASEF();
+ }
+ else
+ {
+ RELEASEF();
+ }
+ m_acquired = FALSE;
+ }
+ }
+ FORCEINLINE void Clear()
+ {
+ STATIC_CONTRACT_WRAPPER;
+ if (m_acquired)
+ {
+ RELEASEF();
+ }
+
+ m_acquired = FALSE;
+ }
+ FORCEINLINE void SuppressRelease()
+ {
+ STATIC_CONTRACT_LEAF;
+ m_acquired = FALSE;
+ }
+
+ HIDE_GENERATED_METHODS(StateHolder)
+}; // class StateHolder<>
+
+// Holder for the case where the acquire function can fail.
+template <typename VALUE, BOOL (*ACQUIRE)(VALUE value), void (*RELEASEF)(VALUE value), HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq>
+class ConditionalStateHolder
+{
+ private:
+ VALUE m_value;
+ BOOL m_acquired; // Have we acquired the state?
+
+ public:
+ FORCEINLINE ConditionalStateHolder(VALUE value, BOOL take = TRUE)
+ : m_value(value), m_acquired(FALSE)
+ {
+ STATIC_CONTRACT_WRAPPER;
+ if (take)
+ Acquire();
+ }
+ FORCEINLINE ~ConditionalStateHolder()
+ {
+ STATIC_CONTRACT_WRAPPER;
+ Release();
+ }
+ FORCEINLINE BOOL Acquire()
+ {
+ STATIC_CONTRACT_WRAPPER;
+ // Insert any global or thread bookeeping here
+
+ _ASSERTE(!m_acquired);
+
+ m_acquired = ACQUIRE(m_value);
+
+ return m_acquired;
+ }
+ FORCEINLINE void Release()
+ {
+ STATIC_CONTRACT_WRAPPER;
+ // Insert any global or thread bookeeping here
+
+ if (m_acquired)
+ {
+ if (VALIDATION_TYPE != HSV_NoValidation)
+ {
+ VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(VALIDATION_TYPE);
+ RELEASEF(m_value);
+ }
+ else
+ {
+ RELEASEF(m_value);
+ }
+ m_acquired = FALSE;
+ }
+ }
+ FORCEINLINE void Clear()
+ {
+ STATIC_CONTRACT_WRAPPER;
+ if (m_acquired)
+ {
+ RELEASEF(m_value);
+ }
+
+ m_acquired = FALSE;
+ }
+ FORCEINLINE void SuppressRelease()
+ {
+ STATIC_CONTRACT_LEAF;
+ m_acquired = FALSE;
+ }
+ FORCEINLINE BOOL Acquired()
+ {
+ STATIC_CONTRACT_LEAF;
+
+ return m_acquired;
+ }
+
+ HIDE_GENERATED_METHODS(ConditionalStateHolder)
+}; // class ConditionalStateHolder<>
+
+
+// Making the copy constructor private produces a warning about "can't generate copy
+// constructor" on all holders (duh, that's the point.)
+#ifdef _MSC_VER
+#pragma warning(disable:4511)
+#endif // _MSC_VER
+
+//-----------------------------------------------------------------------------
+// BaseWrapper is just Base like a Holder, but it "transparently" proxies the type it contains,
+// using operator overloads. Use this when you want a holder to expose the functionality of
+// the value it contains.
+//-----------------------------------------------------------------------------
+template <typename TYPE, typename BASE,
+ UINT_PTR DEFAULTVALUE = 0, BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>, HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq>
+class BaseWrapper : public BaseHolder<TYPE, BASE, DEFAULTVALUE, IS_NULL, VALIDATION_TYPE>
+{
+ typedef BaseHolder<TYPE, BASE, DEFAULTVALUE, IS_NULL, VALIDATION_TYPE> BaseT;
+
+
+#ifdef __GNUC__
+//#pragma GCC visibility push(hidden)
+#endif // __GNUC__
+ // This temporary object takes care of the case where we are initializing
+ // a holder's contents by passing it as an out parameter. The object is
+ // guaranteed to live longer than the call it is passed to, hence we should
+ // properly acquire the object on return
+ friend class AddressInitHolder;
+ class AddressInitHolder
+ {
+ protected:
+ BaseWrapper<TYPE,BASE,DEFAULTVALUE,IS_NULL> &m_holder;
+
+ public:
+ FORCEINLINE AddressInitHolder(BaseWrapper<TYPE,BASE,DEFAULTVALUE,IS_NULL> &holder)
+ : m_holder(holder)
+ {
+ //
+ // We must clear the value, to avoid the following scenario:
+ //
+ // ReleaseHolder<MyType> pMyType;
+ // hr = MyFunction(&pMyType, ...);
+ // <do something with pMyType>
+ // hr = MyFunction(&pMyType, ...); <- calls Release before call and Acquire on return.
+ //
+ // If the second call to MyFunction were to fail and return without updating the
+ // out parameter, then ~AddressInitHolder will all Acquire, which is a no-op on
+ // the underlying pointer but sets m_acquired to TRUE. Thus, when pMyType goes
+ // out of scope, ReleaseHolder will cause a double-release of pMyType.
+ //
+ // By calling Clear, then the call to Acquire in the dtor will not set m_acquired
+ // to true since IsNull(m_holder.m_value) will return true.
+ //
+ m_holder.Clear();
+ }
+ FORCEINLINE ~AddressInitHolder()
+ {
+ m_holder.Acquire();
+ }
+
+ // It's not optimal to have to declare these casting operators. But if we don't,
+ // people cannot cast the result of &holder to these values. (The C++ compiler won't
+ // automatically use the TYPE * cast as an intermediate value.) So we put them here,
+ // rather than forcing callers to double cast in these common cases.
+
+ FORCEINLINE operator IUnknown **()
+ {
+ IUnknown *unknown;
+ // Typesafe check. This will fail at compile time if
+ // m_holder.m_value can't be converted to an IUnknown *.
+ unknown = static_cast<IUnknown*>(m_holder.m_value);
+ // do the cast with an unsafe cast
+ return (IUnknown **)(&m_holder.m_value);
+ }
+
+#if defined(FEATURE_COMINTEROP) && !defined(STRIKE)
+ FORCEINLINE operator IInspectable **()
+ {
+ IInspectable *inspectable;
+ // Typesafe check. This will fail at compile time if
+ // m_holder.m_value can't be converted to an IInspectable *.
+ inspectable = static_cast<IInspectable *>(m_holder.m_value);
+ return (IInspectable **)(&m_holder.m_value);
+
+ }
+#endif // FEATURE_COMINTEROP
+
+ FORCEINLINE operator void **()
+ {
+ return (void **)(&m_holder.m_value);
+ }
+ FORCEINLINE operator void *()
+ {
+ return (void *)(&m_holder.m_value);
+ }
+ };
+
+ // Separate out method with TYPE * cast operator, since it may clash with IUnknown ** or
+ // void ** cast operator.
+ friend class TypedAddressInitHolder;
+ class TypedAddressInitHolder : public AddressInitHolder
+ {
+ public:
+ FORCEINLINE TypedAddressInitHolder(BaseWrapper & holder)
+ : AddressInitHolder(holder)
+ {
+ }
+
+ FORCEINLINE operator TYPE *()
+ {
+ return static_cast<TYPE *>(&this->m_holder.m_value);
+ }
+ };
+#ifdef __GNUC__
+//#pragma GCC visibility pop
+#endif // __GNUC__
+
+ public:
+ FORCEINLINE BaseWrapper()
+ : BaseT(TYPE(DEFAULTVALUE), FALSE)
+ {
+ }
+ FORCEINLINE BaseWrapper(TYPE value)
+ : BaseT(value)
+ {
+ }
+ FORCEINLINE BaseWrapper(TYPE value, BOOL take)
+ : BaseT(value, take)
+ {
+ }
+ FORCEINLINE BaseWrapper& operator=(TYPE value)
+ {
+ BaseT::Assign(value);
+ return *this;
+ }
+ FORCEINLINE operator TYPE() const
+ {
+ return this->m_value;
+ }
+ FORCEINLINE TypedAddressInitHolder operator&()
+ {
+ return TypedAddressInitHolder(*this);
+ }
+ template <typename T>
+ FORCEINLINE bool operator==(T const & value) const
+ {
+ return !!(this->m_value == TYPE(value));
+ }
+ template <typename T>
+ FORCEINLINE bool operator!=(T const & value) const
+ {
+ return !!(this->m_value != TYPE(value));
+ }
+#ifdef __llvm__
+ // This handles the NULL value that is an int and clang
+ // doesn't want to convert int to a pointer
+ FORCEINLINE bool operator==(int value) const
+ {
+ return !!(this->m_value == TYPE((void*)(SIZE_T)value));
+ }
+ FORCEINLINE bool operator!=(int value) const
+ {
+ return !!(this->m_value != TYPE((void*)(SIZE_T)value));
+ }
+#endif // __llvm__
+ FORCEINLINE const TYPE &operator->() const
+ {
+ return this->m_value;
+ }
+ FORCEINLINE int operator!() const
+ {
+ return this->IsNull();
+ }
+
+ private:
+ HIDE_GENERATED_METHODS(BaseWrapper)
+}; // class BaseWrapper<>
+
+//-----------------------------------------------------------------------------
+// Generic templates to use to wrap up acquire/release functionality for Holder
+//-----------------------------------------------------------------------------
+
+template <typename TYPE>
+FORCEINLINE void DoNothing(TYPE value)
+{
+ // @TODO: Due to prefast template problems, implementations of the DoNothing macro have been changed
+ // Search by prefast, and remove them when prefast is ready
+}
+
+FORCEINLINE void DoNothing()
+{
+}
+
+// Prefast stuff.We should have DoNothing<type*> in the holder declaration, but currently
+// prefast doesnt support, it, so im stuffing all these here so if we need to change the template you can change
+// everything here. When prefast works, remove the following functions
+struct ConnectionCookie;
+FORCEINLINE void ConnectionCookieDoNothing(ConnectionCookie* p)
+{
+}
+
+class ComCallWrapper;
+FORCEINLINE void CCWHolderDoNothing(ComCallWrapper* p)
+{
+}
+
+
+FORCEINLINE void DispParamHolderDoNothing(VARIANT* p)
+{
+}
+
+FORCEINLINE void VariantPtrDoNothing(VARIANT* p)
+{
+}
+
+FORCEINLINE void VariantDoNothing(VARIANT)
+{
+}
+
+FORCEINLINE void ZeroDoNothing(VOID* p)
+{
+}
+
+class CtxEntry;
+FORCEINLINE void CtxEntryDoNothing(CtxEntry* p)
+{
+}
+
+struct RCW;
+FORCEINLINE void NewRCWHolderDoNothing(RCW*)
+{
+}
+
+// Prefast stuff.We should have DoNothing<SafeArray*> in the holder declaration
+FORCEINLINE void SafeArrayDoNothing(SAFEARRAY* p)
+{
+}
+
+
+
+
+//-----------------------------------------------------------------------------
+// Holder/Wrapper are the simplest way to define holders - they synthesizes a base class out of
+// function pointers
+//-----------------------------------------------------------------------------
+
+template <typename TYPE, void (*ACQUIREF)(TYPE), void (*RELEASEF)(TYPE), HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq>
+class FunctionBase : protected HolderBase<TYPE>
+{
+ protected:
+
+ FORCEINLINE FunctionBase(TYPE value)
+ : HolderBase<TYPE>(value)
+ {
+ }
+
+ FORCEINLINE void DoAcquire()
+ {
+ ACQUIREF(this->m_value);
+ }
+
+ void DoRelease()
+ {
+ // <TODO> Consider removing this stack validation since it is redundant with the
+ // one that is already being done in BaseHolder & BaseWrapper. </TODO>
+ if (VALIDATION_TYPE != HSV_NoValidation)
+ {
+ VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(VALIDATION_TYPE);
+ RELEASEF(this->m_value);
+ }
+ else
+ {
+ RELEASEF(this->m_value);
+ }
+ }
+}; // class Function<>
+
+template
+ <
+ typename TYPE,
+ void (*ACQUIREF)(TYPE),
+ void (*RELEASEF)(TYPE),
+ UINT_PTR DEFAULTVALUE = 0,
+ BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>,
+ HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq,
+ // For legacy compat (see EEJitManager::WriterLockHolder), where default ctor
+ // causes ACQUIREF(DEFAULTVALUE), but ACQUIREF ignores the argument and
+ // operates on static or global value instead.
+ bool DEFAULT_CTOR_ACQUIRE = true
+ >
+class Holder : public BaseHolder<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF, VALIDATION_TYPE>,
+ DEFAULTVALUE, IS_NULL, VALIDATION_TYPE>
+{
+ typedef BaseHolder<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF, VALIDATION_TYPE>,
+ DEFAULTVALUE, IS_NULL, VALIDATION_TYPE> BaseT;
+
+ public:
+ FORCEINLINE Holder()
+ : BaseT(TYPE(DEFAULTVALUE), DEFAULT_CTOR_ACQUIRE)
+ {
+ STATIC_CONTRACT_WRAPPER;
+ }
+
+ FORCEINLINE Holder(TYPE value)
+ : BaseT(value)
+ {
+ STATIC_CONTRACT_WRAPPER;
+ }
+
+ FORCEINLINE Holder(TYPE value, BOOL takeOwnership)
+ : BaseT(value, takeOwnership)
+ {
+ STATIC_CONTRACT_WRAPPER;
+ }
+
+ FORCEINLINE Holder& operator=(TYPE p)
+ {
+ STATIC_CONTRACT_WRAPPER;
+ BaseT::operator=(p);
+ return *this;
+ }
+
+ HIDE_GENERATED_METHODS(Holder)
+};
+
+//---------------------------------------------------------------------------------------
+//
+template
+ <
+ typename TYPE,
+ void (*ACQUIREF)(TYPE),
+ void (*RELEASEF)(TYPE),
+ UINT_PTR DEFAULTVALUE = 0,
+ BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>,
+ HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq,
+ // For legacy compat (see EEJitManager::WriterLockHolder), where default ctor
+ // causes ACQUIREF(DEFAULTVALUE), but ACQUIREF ignores the argument and
+ // operates on static or global value instead.
+ bool DEFAULT_CTOR_ACQUIRE = true
+ >
+class Wrapper : public BaseWrapper<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF, VALIDATION_TYPE>,
+ DEFAULTVALUE, IS_NULL, VALIDATION_TYPE>
+{
+ typedef BaseWrapper<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF, VALIDATION_TYPE>,
+ DEFAULTVALUE, IS_NULL, VALIDATION_TYPE> BaseT;
+
+ public:
+ FORCEINLINE Wrapper()
+ : BaseT(TYPE(DEFAULTVALUE), DEFAULT_CTOR_ACQUIRE)
+ {
+ STATIC_CONTRACT_WRAPPER;
+ }
+
+ FORCEINLINE Wrapper(TYPE value)
+ : BaseT(value)
+ {
+ STATIC_CONTRACT_WRAPPER;
+ }
+
+ FORCEINLINE Wrapper(TYPE value, BOOL takeOwnership)
+ : BaseT(value, takeOwnership)
+ {
+ STATIC_CONTRACT_WRAPPER;
+ }
+
+ FORCEINLINE Wrapper& operator=(TYPE const & value)
+ {
+ STATIC_CONTRACT_WRAPPER;
+ BaseT::operator=(value);
+ return *this;
+ }
+
+ HIDE_GENERATED_METHODS(Wrapper)
+}; // Wrapper<>
+
+//---------------------------------------------------------------------------------------
+// - Cannot use the standard INDEBUG macro: holder.h is used in places where INDEBUG is defined in the nonstandard way
+#if defined(_DEBUG)
+#define INDEBUG_AND_WINDOWS_FOR_HOLDERS(x) x
+#else
+#define INDEBUG_AND_WINDOWS_FOR_HOLDERS(x)
+#endif
+
+//---------------------------------------------------------------------------------------
+//
+// New template wrapper type macros. These save some effort when specializing
+// existing holder templates. (We would rather use a construct like:
+//
+// template <P1>
+// typedef Holder<...> NewHolder;
+//
+// But this construct doesn't exist in C++. These macros ease some of the cruft necessary
+// to get similar functionality out of class templates.
+//-----------------------------------------------------------------------------
+
+// Dev10 VC++ has some of the new C++0x language extensions. Of particular interest here:
+// rvalue references, which enables differentiation between named (lvalue) and
+// temporary (rvalue) object references, enabling move semantics and perfect forwarding.
+// See http://msdn.microsoft.com/en-us/library/dd293668.aspx for more information.
+
+// Enable copy construction and assignment from temporary objects. This permits Wrapper objects
+// to be returned from methods, and for move assignment.
+#define NEW_WRAPPER_TEMPLATE_RVALREF_METHODS(_NAME) \
+ public: \
+ FORCEINLINE _NAME(_NAME && other) \
+ : BaseT(NULL, FALSE) \
+ { \
+ STATIC_CONTRACT_WRAPPER; \
+ INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) \
+ *this = std::move(other); \
+ } \
+ FORCEINLINE _NAME& operator=(_NAME && other) \
+ { \
+ std::swap(BaseT::m_value, other.BaseT::m_value); \
+ std::swap(BaseT::m_acquired, other.BaseT::m_acquired); \
+ return *this; \
+ }
+
+#define NEW_WRAPPER_TEMPLATE1(_NAME, _RELEASEF) \
+ template <typename _TYPE> \
+ class _NAME : public Wrapper<_TYPE*, DoNothing<_TYPE*>, _RELEASEF, NULL> \
+ { \
+ typedef Wrapper<_TYPE*, DoNothing<_TYPE*>, _RELEASEF, NULL> BaseT; \
+ public: \
+ FORCEINLINE _NAME() : BaseT(NULL, FALSE) \
+ { \
+ STATIC_CONTRACT_WRAPPER; \
+ INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) \
+ } \
+ FORCEINLINE _NAME(_TYPE* value) : BaseT(value) \
+ { \
+ STATIC_CONTRACT_WRAPPER; \
+ INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) \
+ } \
+ FORCEINLINE _NAME(_TYPE* value, BOOL takeOwnership) : BaseT(value, takeOwnership) \
+ { \
+ STATIC_CONTRACT_WRAPPER; \
+ INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) \
+ } \
+ FORCEINLINE ~_NAME() \
+ { \
+ } \
+ FORCEINLINE _NAME& operator=(_TYPE * value) \
+ { \
+ STATIC_CONTRACT_WRAPPER; \
+ BaseT::operator=(value); \
+ return *this; \
+ } \
+ /* Since operator& is overloaded we need a way to get a type safe this pointer. */ \
+ FORCEINLINE _NAME* GetAddr() \
+ { \
+ STATIC_CONTRACT_LEAF; \
+ return this; \
+ } \
+ NEW_WRAPPER_TEMPLATE_RVALREF_METHODS(_NAME) \
+ HIDE_GENERATED_METHODS(_NAME) \
+ private: \
+ /* m_ppValue: Do not use from source code: Only for convenient use from debugger */ \
+ /* watch windows - saves five mouseclicks when inspecting holders. */ \
+ INDEBUG_AND_WINDOWS_FOR_HOLDERS(_TYPE ** m_pvalue;) \
+ };
+
+//-----------------------------------------------------------------------------
+// NOTE: THIS IS UNSAFE TO USE IN THE VM for interop COM objects!!
+// WE DO NOT CORRECTLY CHANGE TO PREEMPTIVE MODE BEFORE CALLING RELEASE!!
+// USE SafeComHolder
+//
+// ReleaseHolder : COM Interface holder for use outside the VM (or on well known instances
+// which do not need preemptive Relesae)
+//
+// Usage example:
+//
+// {
+// ReleaseHolder<IFoo> foo;
+// hr = FunctionToGetRefOfFoo(&foo);
+// // Note ComHolder doesn't call AddRef - it assumes you already have a ref (if non-0).
+// } // foo->Release() on out of scope (WITHOUT RESPECT FOR GC MODE!!)
+//
+//-----------------------------------------------------------------------------
+
+template <typename TYPE>
+FORCEINLINE void DoTheRelease(TYPE *value)
+{
+ if (value)
+ {
+ VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(HSV_ValidateNormalStackReq);
+ value->Release();
+ }
+}
+
+NEW_WRAPPER_TEMPLATE1(DoNothingHolder, DoNothing<_TYPE*>);
+
+NEW_WRAPPER_TEMPLATE1(ReleaseHolder, DoTheRelease<_TYPE>);
+
+NEW_WRAPPER_TEMPLATE1(NonVMComHolder, DoTheRelease<_TYPE>);
+
+
+//-----------------------------------------------------------------------------
+// StubHolder : holder for stubs
+//
+// Usage example:
+//
+// {
+// StubHolder<Stub> foo;
+// foo = new Stub();
+// foo->AddRef();
+// // Note StubHolder doesn't call AddRef for you.
+// } // foo->DecRef() on out of scope
+//
+//-----------------------------------------------------------------------------
+template <typename TYPE>
+FORCEINLINE void StubRelease(TYPE* value)
+{
+ if (value)
+ value->DecRef();
+}
+
+NEW_WRAPPER_TEMPLATE1(StubHolder, StubRelease<_TYPE>);
+
+//-----------------------------------------------------------------------------
+// CoTaskMemHolder : CoTaskMemAlloc allocated memory holder
+//
+// {
+// CoTaskMemHolder<Foo> foo = (Foo*) CoTaskMemAlloc(sizeof(Foo));
+// } // delete foo on out of scope
+//-----------------------------------------------------------------------------
+
+template <typename TYPE>
+FORCEINLINE void DeleteCoTaskMem(TYPE *value)
+{
+ if (value)
+ CoTaskMemFree(value);
+}
+
+NEW_WRAPPER_TEMPLATE1(CoTaskMemHolder, DeleteCoTaskMem<_TYPE>);
+
+//-----------------------------------------------------------------------------
+// NewHolder : New'ed memory holder
+//
+// {
+// NewHolder<Foo> foo = new Foo ();
+// } // delete foo on out of scope
+//-----------------------------------------------------------------------------
+
+template <typename TYPE>
+FORCEINLINE void Delete(TYPE *value)
+{
+ STATIC_CONTRACT_LEAF;
+
+ static_assert(!std::is_same<typename std::remove_cv<TYPE>::type, WCHAR>::value,
+ "Must use NewArrayHolder (not NewHolder) for strings.");
+ static_assert(!std::is_same<typename std::remove_cv<TYPE>::type, CHAR>::value,
+ "Must use NewArrayHolder (not NewHolder) for strings.");
+
+ delete value;
+}
+
+NEW_WRAPPER_TEMPLATE1(NewHolder, Delete<_TYPE>);
+
+ //-----------------------------------------------------------------------------
+// NewExecutableHolder : New'ed memory holder for executable memory.
+//
+// {
+// NewExecutableHolder<Foo> foo = (Foo*) new (executable) Byte[num];
+// } // delete foo on out of scope
+//-----------------------------------------------------------------------------
+// IJW
+template<class T> void DeleteExecutable(T *p);
+
+NEW_WRAPPER_TEMPLATE1(NewExecutableHolder, DeleteExecutable<_TYPE>);
+
+//-----------------------------------------------------------------------------
+// NewArrayHolder : New []'ed pointer holder
+// {
+// NewArrayHolder<Foo> foo = new Foo [30];
+// } // delete [] foo on out of scope
+//-----------------------------------------------------------------------------
+
+template <typename TYPE>
+FORCEINLINE void DeleteArray(TYPE *value)
+{
+ STATIC_CONTRACT_WRAPPER;
+ delete [] value;
+ value = NULL;
+}
+
+NEW_WRAPPER_TEMPLATE1(NewArrayHolder, DeleteArray<_TYPE>);
+typedef NewArrayHolder<CHAR> AStringHolder;
+typedef NewArrayHolder<WCHAR> WStringHolder;
+
+//-----------------------------------------------------------------------------
+// A special array holder that expects its contents are interface pointers,
+// and will call Release() on them.
+//
+// NOTE: You may ONLY use this if you've determined that it is SAFE to call
+// Release() on the contained interface pointers (e.g., as opposed to SafeRelease)
+//
+template <typename INTERFACE>
+class NewInterfaceArrayHolder : public NewArrayHolder<INTERFACE *>
+{
+public:
+ NewInterfaceArrayHolder() :
+ NewArrayHolder<INTERFACE *>(),
+ m_cElements(0)
+ {
+ STATIC_CONTRACT_WRAPPER;
+ }
+
+ NewInterfaceArrayHolder& operator=(INTERFACE ** value)
+ {
+ STATIC_CONTRACT_WRAPPER;
+ NewArrayHolder<INTERFACE *>::operator=(value);
+ return *this;
+ }
+
+ void SetElementCount(ULONG32 cElements)
+ {
+ STATIC_CONTRACT_LEAF;
+ m_cElements = cElements;
+ }
+
+ ~NewInterfaceArrayHolder()
+ {
+ STATIC_CONTRACT_LEAF;
+ for (ULONG32 i=0; i < m_cElements; i++)
+ {
+ if (this->m_value[i] != NULL)
+ this->m_value[i]->Release();
+ }
+ }
+
+protected:
+ ULONG32 m_cElements;
+};
+
+
+//-----------------------------------------------------------------------------
+// ResetPointerHolder : pointer which needs to be set to NULL
+// {
+// ResetPointerHolder<Foo> holder = &pFoo;
+// } // "*pFoo=NULL" on out of scope
+//-----------------------------------------------------------------------------
+#ifdef __GNUC__
+// With -fvisibility-inlines-hidden, the Invoke methods below
+// get hidden, which causes warnings when visible classes expose them.
+#define VISIBLE __attribute__ ((visibility("default")))
+#else
+#define VISIBLE
+#endif // __GNUC__
+
+namespace detail
+{
+ template <typename T>
+ struct ZeroMem
+ {
+ static VISIBLE void Invoke(T * pVal)
+ {
+ ZeroMemory(pVal, sizeof(T));
+ }
+ };
+
+ template <typename T>
+ struct ZeroMem<T*>
+ {
+ static VISIBLE void Invoke(T ** pVal)
+ {
+ *pVal = NULL;
+ }
+ };
+
+}
+#undef VISIBLE
+
+NEW_WRAPPER_TEMPLATE1(ResetPointerHolder, detail::ZeroMem<_TYPE>::Invoke);
+NEW_WRAPPER_TEMPLATE1(FieldNuller, detail::ZeroMem<_TYPE>::Invoke);
+
+//-----------------------------------------------------------------------------
+// Wrap win32 functions using HANDLE
+//-----------------------------------------------------------------------------
+
+FORCEINLINE void VoidCloseHandle(HANDLE h) { if (h != NULL) CloseHandle(h); }
+// (UINT_PTR) -1 is INVALID_HANDLE_VALUE
+FORCEINLINE void VoidCloseFileHandle(HANDLE h) { if (h != ((HANDLE)((LONG_PTR) -1))) CloseHandle(h); }
+FORCEINLINE void VoidFindClose(HANDLE h) { FindClose(h); }
+FORCEINLINE void VoidUnmapViewOfFile(void *ptr) { UnmapViewOfFile(ptr); }
+
+template <typename TYPE>
+FORCEINLINE void TypeUnmapViewOfFile(TYPE *ptr) { UnmapViewOfFile(ptr); }
+
+// (UINT_PTR) -1 is INVALID_HANDLE_VALUE
+//@TODO: Dangerous default value. Some Win32 functions return INVALID_HANDLE_VALUE, some return NULL (such as CreatEvent).
+typedef Wrapper<HANDLE, DoNothing<HANDLE>, VoidCloseHandle, (UINT_PTR) -1> HandleHolder;
+typedef Wrapper<HANDLE, DoNothing<HANDLE>, VoidCloseFileHandle, (UINT_PTR) -1> FileHandleHolder;
+typedef Wrapper<HANDLE, DoNothing<HANDLE>, VoidFindClose, (UINT_PTR) -1> FindHandleHolder;
+
+typedef Wrapper<void *, DoNothing, VoidUnmapViewOfFile> MapViewHolder;
+
+#ifdef WszDeleteFile
+// Deletes a file with the specified path. Do not use if you care about failures
+// deleting the file, as failures are ignored by VoidDeleteFile.
+FORCEINLINE void VoidDeleteFile(LPCWSTR wszFilePath) { WszDeleteFile(wszFilePath); }
+typedef Wrapper<LPCWSTR, DoNothing<LPCWSTR>, VoidDeleteFile, NULL> DeleteFileHolder;
+#endif // WszDeleteFile
+
+#if !defined(FEATURE_CORECLR) || defined(FEATURE_CRYPTO)
+// Crypto holders
+FORCEINLINE void VoidCryptReleaseContext(HCRYPTPROV h) { CryptReleaseContext(h, 0); }
+FORCEINLINE void VoidCryptDestroyHash(HCRYPTHASH h) { CryptDestroyHash(h); }
+FORCEINLINE void VoidCryptDestroyKey(HCRYPTKEY h) { CryptDestroyKey(h); }
+
+typedef Wrapper<HCRYPTPROV, DoNothing, VoidCryptReleaseContext, 0> HandleCSPHolder;
+typedef Wrapper<HCRYPTHASH, DoNothing, VoidCryptDestroyHash, 0> HandleHashHolder;
+typedef Wrapper<HCRYPTKEY, DoNothing, VoidCryptDestroyKey, 0> HandleKeyHolder;
+#endif // !FEATURE_CORECLR || FEATURE_CRYPTO
+
+//-----------------------------------------------------------------------------
+// Misc holders
+//-----------------------------------------------------------------------------
+
+// A holder for HMODULE.
+FORCEINLINE void HolderFreeLibrary(HMODULE h) { FreeLibrary(h); }
+
+typedef Wrapper<HMODULE, DoNothing<HMODULE>, HolderFreeLibrary, NULL> HModuleHolder;
+
+template <typename T> FORCEINLINE
+void DoLocalFree(T* pMem) { (LocalFree)((HLOCAL)pMem); }
+
+NEW_WRAPPER_TEMPLATE1(LocalAllocHolder, DoLocalFree<_TYPE>);
+
+inline void BoolSet( _Out_ bool * val ) { *val = true; }
+inline void BoolUnset( _Out_ bool * val ) { *val = false; }
+
+typedef Wrapper< bool *, BoolSet, BoolUnset > BoolFlagStateHolder;
+
+//
+// We need the following methods to have volatile arguments, so that they can accept
+// raw pointers in addition to the results of the & operator on Volatile<T>.
+//
+
+FORCEINLINE void CounterIncrease(RAW_KEYWORD(volatile) LONG* p) {InterlockedIncrement(p);};
+FORCEINLINE void CounterDecrease(RAW_KEYWORD(volatile) LONG* p) {InterlockedDecrement(p);};
+
+typedef Wrapper<RAW_KEYWORD(volatile) LONG*, CounterIncrease, CounterDecrease, (UINT_PTR)0, CompareDefault<RAW_KEYWORD(volatile) LONG*>, HSV_NoValidation> CounterHolder;
+
+
+#ifndef FEATURE_PAL
+FORCEINLINE void RegKeyRelease(HKEY k) {RegCloseKey(k);};
+typedef Wrapper<HKEY,DoNothing,RegKeyRelease> RegKeyHolder;
+#endif // !FEATURE_PAL
+
+class ErrorModeHolder
+{
+ UINT m_oldMode;
+public:
+ ErrorModeHolder(UINT newMode){m_oldMode=SetErrorMode(newMode);};
+ ~ErrorModeHolder(){SetErrorMode(m_oldMode);};
+ UINT OldMode() {return m_oldMode;};
+};
+
+#ifndef FEATURE_PAL
+//-----------------------------------------------------------------------------
+// HKEYHolder : HKEY holder, Calls RegCloseKey on scope exit.
+//
+// {
+// HKEYHolder hFoo = NULL;
+// WszRegOpenKeyEx(HKEY_CLASSES_ROOT, L"Interface",0, KEY_READ, hFoo);
+//
+// } // close key on out of scope via RegCloseKey.
+//-----------------------------------------------------------------------------
+
+class HKEYHolder
+{
+public:
+ HKEYHolder()
+ {
+ STATIC_CONTRACT_LEAF;
+ m_value = 0;
+ }
+
+ ~HKEYHolder()
+ {
+ STATIC_CONTRACT_WRAPPER;
+ if (m_value != NULL)
+ ::RegCloseKey(m_value);
+ }
+
+ FORCEINLINE void operator=(HKEY p)
+ {
+ STATIC_CONTRACT_LEAF;
+ if (p != 0)
+ m_value = p;
+ }
+
+ FORCEINLINE operator HKEY()
+ {
+ STATIC_CONTRACT_LEAF;
+ return m_value;
+ }
+
+ FORCEINLINE operator HKEY*()
+ {
+ STATIC_CONTRACT_LEAF;
+ return &m_value;
+ }
+
+ FORCEINLINE HKEY* operator&()
+ {
+ STATIC_CONTRACT_LEAF;
+ return &m_value;
+ }
+
+private:
+ HKEY m_value;
+};
+#endif // !FEATURE_PAL
+
+//-----------------------------------------------------------------------------
+// Wrapper to suppress auto-destructor (UNDER CONSTRUCTION)
+// Usage:
+//
+// BEGIN_MANUAL_HOLDER(NewArrayHolder<Foo>, foo);
+// ... use foo via ->
+// END_MANUAL_HOLDER(foo);
+//
+//-----------------------------------------------------------------------------
+
+template <typename TYPE, SIZE_T SIZE = sizeof(TYPE)>
+class NoAuto__DONTUSEDIRECTLY
+{
+ private:
+ BYTE hiddeninstance[SIZE];
+
+ public:
+ // Unfortunately, you can only use the default constructor
+ NoAuto__DONTUSEDIRECTLY()
+ {
+ new (hiddeninstance) TYPE ();
+ }
+
+ operator TYPE& () { return *(TYPE *)hiddeninstance; }
+ TYPE& operator->() { return *(TYPE *)hiddeninstance; }
+ TYPE& operator*() { return *(TYPE *)hiddeninstance; }
+
+ void Destructor() { (*(TYPE*)hiddeninstance)->TYPE::~TYPE(); }
+};
+
+#define BEGIN_MANUAL_HOLDER(_TYPE, _NAME) \
+ { \
+ NoAuto__DONTUSEDIRECTLY<_TYPE> _NAME; \
+ __try \
+ {
+
+#define END_MANUAL_HOLDER(_NAME) \
+ } \
+ __finally \
+ { \
+ _NAME.Destructor(); \
+ } \
+ }
+
+//----------------------------------------------------------------------------
+//
+// External data access does not want certain holder implementations
+// to be active as locks should not be taken and so on. Provide
+// a no-op in that case.
+//
+//----------------------------------------------------------------------------
+
+#ifndef DACCESS_COMPILE
+
+#define DacHolder Holder
+
+#else
+
+template <typename TYPE, void (*ACQUIRE)(TYPE), void (*RELEASEF)(TYPE), UINT_PTR DEFAULTVALUE = 0, BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>, BOOL VALIDATE_BACKOUT_STACK = TRUE>
+class DacHolder
+{
+ protected:
+ TYPE m_value;
+
+ private:
+ BOOL m_acquired; // Have we acquired the resource?
+
+ public:
+ FORCEINLINE DacHolder()
+ : m_value(TYPE(DEFAULTVALUE)),
+ m_acquired(FALSE)
+ {
+ STATIC_CONTRACT_SUPPORTS_DAC;
+ }
+
+ // construct a new instance of DacHolder
+ // Arguments:
+ // input: value - the resource held
+ // take - indicates whether the lock should be taken--the default is true. See Notes:
+ // Note: In DAC builds, the Acquire function does not actually take the lock, instead
+ // it determines whether the lock is held (by the LS). If it is, the locked data
+ // is assumed to be inconsistent and the Acquire function will throw.
+ FORCEINLINE DacHolder(TYPE value, BOOL take = TRUE)
+ : m_value(value),
+ m_acquired(FALSE)
+ {
+ STATIC_CONTRACT_SUPPORTS_DAC;
+ if (take)
+ Acquire();
+
+ }
+ FORCEINLINE ~DacHolder()
+ {
+ STATIC_CONTRACT_SUPPORTS_DAC;
+ }
+ // Sets the value to 'value'. Doesn't call Acquire/Release if fTake is FALSE.
+ FORCEINLINE void Assign(TYPE value, BOOL fTake = TRUE)
+ {
+ m_value = value;
+ }
+ FORCEINLINE void Acquire()
+ {
+ STATIC_CONTRACT_SUPPORTS_DAC;
+
+ if (!IsNull())
+ {
+ m_acquired = TRUE;
+ // because ACQUIRE is a template argument, if the line m_acquired = TRUE is placed after the call
+ // where it logically belongs, the compiler flags it as "unreachable code."
+ ACQUIRE(this->m_value);
+ }
+ }
+ FORCEINLINE void Release()
+ {
+ // Insert any global or thread bookeeping here
+
+ if (m_acquired)
+ {
+ m_acquired = FALSE;
+ }
+ }
+ FORCEINLINE void Clear()
+ {
+ m_value = TYPE(DEFAULTVALUE);
+ m_acquired = FALSE;
+ }
+ FORCEINLINE void SuppressRelease()
+ {
+ m_acquired = FALSE;
+ }
+ FORCEINLINE TYPE GetValue()
+ {
+ return m_value;
+ }
+ FORCEINLINE BOOL IsNull() const
+ {
+ return IS_NULL(m_value, TYPE(DEFAULTVALUE));
+ }
+
+ private:
+ FORCEINLINE DacHolder& operator=(const Holder<TYPE, ACQUIRE, RELEASEF> &holder)
+ {
+ }
+
+ FORCEINLINE DacHolder(const Holder<TYPE, ACQUIRE, RELEASEF> &holder)
+ {
+ }
+};
+
+#endif // #ifndef DACCESS_COMPILE
+
+// Holder-specific clr::SafeAddRef and clr::SafeRelease helper functions.
+namespace clr
+{
+ template < typename ItfT > __checkReturn
+ ItfT *
+ SafeAddRef(ReleaseHolder<ItfT> & pItf)
+ {
+ STATIC_CONTRACT_LIMITED_METHOD;
+ //@TODO: Would be good to add runtime validation that the return value is used.
+ return SafeAddRef(pItf.GetValue());
+ }
+
+ namespace detail
+ {
+ template <typename T>
+ char IsHolderHelper(HolderBase<T>*);
+ int IsHolderHelper(...);
+
+ template <typename T>
+ struct IsHolder : public std::conditional<
+ sizeof(IsHolderHelper(reinterpret_cast<T*>(NULL))) == sizeof(char),
+ std::true_type,
+ std::false_type>::type
+ {};
+ }
+
+ template < typename T >
+ typename std::enable_if<detail::IsHolder<T>::value, ULONG>::type
+ SafeRelease(T& arg)
+ {
+ STATIC_CONTRACT_LIMITED_METHOD;
+ return arg.Release();
+ }
+}
+
+#endif // __HOLDER_H_