1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5
6#ifndef __HOLDER_H_
7#define __HOLDER_H_
8
9#include <wincrypt.h>
10#include "cor.h"
11#include "genericstackprobe.h"
12#include "staticcontract.h"
13#include "volatile.h"
14#include "palclr.h"
15
16#ifdef PAL_STDCPP_COMPAT
17#include <utility>
18#include <type_traits>
19#else
20#include "clr_std/utility"
21#include "clr_std/type_traits"
22#endif
23
24#if defined(FEATURE_COMINTEROP) && !defined(STRIKE)
25#include <Activation.h>
26#include <Inspectable.h>
27#endif
28
29// Note: you can't use CONTRACT's in this file. You can't use dynamic contracts because the impl of dynamic
30// contracts depends on holders. You can't use static contracts because they include the function name as a string,
31// and the template names in this file are just too long, so you get a compiler error.
32//
33// All the functions in this file are pretty basic, so the lack of CONTRACT's isn't a big loss.
34
35#ifdef _MSC_VER
36// Make sure we can recurse deep enough for FORCEINLINE
37#pragma inline_recursion(on)
38#pragma inline_depth(16)
39#pragma warning(disable:4714)
40#endif // _MSC_VER
41
42//------------------------------------------------------------------------------------------------
43// Declare but do not define methods that would normally be automatically generated by the
44// compiler. This will produce a link-time error if they are used. This is involved in object
45// initialization and operator eliding; see
46// http://groups.google.com/group/comp.lang.c++/msg/3cd673ab749bed83?dmode=source
47// for the intricate details.
48
49#ifdef __GNUC__
50// GCC checks accessibility of the copy ctor before performing elision optimization, so
51// it must be declared as public. VC does not, so we can declare it private to give an
52// earlier error message.
53#define HIDE_GENERATED_METHODS(_NAME) \
54 public: \
55 _NAME(_NAME const &); \
56 private: \
57 _NAME & operator=(_NAME const &);
58#else
59#define HIDE_GENERATED_METHODS(_NAME) \
60 private: \
61 _NAME(_NAME const &); \
62 _NAME & operator=(_NAME const &);
63#endif
64
65
66#ifdef _DEBUG
67
68
69//------------------------------------------------------------------------------------------------
70// This is used to make Visual Studio autoexp.dat work sensibly with holders again.
71// The problem is that certain codebases (particulary Fusion) implement key data structures
72// using a class but refer to it using a holder to an interface type. This combination prevents
73// autoexp rules from working as desired.
74//
75// Example: Take this useful autoexp rule for CAssemblyName.
76//
77// CAssemblyName=<_rProp._rProp[3].asStr>
78//
79// To get the same rule to fire when your assemblyname is wrapped in a ReleaseHolder,
80// add these companion rules.
81//
82// HolderBase<CAssemblyName *>=<m_value->_rProp._rProp[3].asStr>
83// HolderBase<IAssemblyName *>=<m_pAutoExpVisibleValue->_asCAssemblyName->_rProp._rProp[3].asStr>
84//
85//------------------------------------------------------------------------------------------------
86struct AutoExpVisibleValue
87{
88 private:
89 union
90 {
91 // Only include a class name here if it is customarily referred to through an abstract interface.
92
93#if defined(FEATURE_APPX)
94 const class AppXBindResultImpl *_asAppXBindResultImpl;
95#endif
96
97 const void *_pPreventEmptyUnion;
98 };
99};
100#endif //_DEBUG
101
102//-----------------------------------------------------------------------------
103// Holder is the base class of all holder objects. Any backout object should derive from it.
104// (Eventually some additional bookeeping and exception handling code will be placed in this
105// base class.)
106//
107// There are several ways to use this class:
108// 1. Derive from HolderBase, and instantiate a Holder or Wrapper around your base. This is necessary
109// if you need to add more state to your holder.
110// 2. Instantiate the Holder template with your type and functions.
111// 3. Instantiate the Wrapper template with your type and functions. The Wrapper adds some additional
112// operator overloads to provide "smart pointer" like behavior
113// 4. Use a prebaked Holder. This is ALWAYS the preferable strategy. It is expected that
114// the general design patter is that Holders will be provided as part of a typical data abstraction.
115// (See Crst for an example of this.)
116//-----------------------------------------------------------------------------
117
118
119
120//-----------------------------------------------------------------------------
121// HolderBase defines the base holder functionality. You can subtype and plug in
122// a different base if you need to add more members for access during
123// acquire & release
124//-----------------------------------------------------------------------------
125template <typename TYPE>
126class HolderBase
127{
128 protected:
129 TYPE m_value;
130
131 HolderBase(TYPE value)
132 : m_value(value)
133 {
134 // TODO: Find a way to enable this check.
135 // We can have a holder in SO tolerant, then probe, then acquire a value. This works
136 // because the dtor is guaranteed to run with enough stack.
137 // EnsureSOIntolerantOK(__FUNCTION__, __FILE__, __LINE__);
138
139#ifdef _DEBUG
140 m_pAutoExpVisibleValue = (const AutoExpVisibleValue *)(&m_value);
141#endif //_DEBUG
142 }
143
144 void DoAcquire()
145 {
146 // Insert any global or thread bookeeping here
147 }
148
149 void DoRelease()
150 {
151 // Insert any global or thread bookeeping here
152 }
153
154#ifdef _DEBUG
155 private:
156 // 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.
157 // 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
158 // since it can't prove that "TYPE" doesn't have a non-trivial constructor.
159 const AutoExpVisibleValue *m_pAutoExpVisibleValue; // This field is to be referenced from individual autoexp.dat files, NOT from the CLR source code.
160#endif //_DEBUG
161
162}; // class HolderBase<>
163
164#ifndef _PREFAST_ // Work around an ICE error in EspX.dll
165
166template <typename TYPE>
167BOOL CompareDefault(TYPE value, TYPE defaultValue)
168{
169 STATIC_CONTRACT_SUPPORTS_DAC;
170 return value == defaultValue;
171}
172
173#else
174
175template <typename TYPE>
176BOOL CompareDefault(TYPE value, TYPE defaultValue)
177{
178 return FALSE;
179}
180
181#endif
182
183
184template <typename TYPE>
185BOOL NoNull(TYPE value, TYPE defaultValue)
186{
187 return FALSE;
188}
189
190// Used e.g. for retail version of code:SyncAccessHolder
191template <typename TYPE>
192class NoOpBaseHolder
193{
194 public:
195 FORCEINLINE NoOpBaseHolder()
196 {
197 }
198 FORCEINLINE NoOpBaseHolder(TYPE value, BOOL take = TRUE)
199 {
200 }
201 FORCEINLINE ~NoOpBaseHolder()
202 {
203 }
204 FORCEINLINE void Assign(TYPE value, BOOL fTake = TRUE)
205 {
206 }
207 FORCEINLINE void Acquire()
208 {
209 }
210 FORCEINLINE void Release()
211 {
212 }
213 FORCEINLINE void Clear()
214 {
215 }
216 FORCEINLINE void SuppressRelease()
217 {
218 }
219 FORCEINLINE TYPE Extract()
220 {
221 }
222 FORCEINLINE TYPE GetValue()
223 {
224 }
225 FORCEINLINE BOOL IsNull() const
226 {
227 return FALSE;
228 }
229
230 private:
231 NoOpBaseHolder& operator=(NoOpBaseHolder const &);
232 NoOpBaseHolder(NoOpBaseHolder const &);
233}; // NoOpBaseHolder<>
234
235
236template
237 <
238 typename TYPE,
239 typename BASE,
240 UINT_PTR DEFAULTVALUE = 0,
241 BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>,
242 HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq
243 >
244class BaseHolder : protected BASE
245{
246 protected:
247 BOOL m_acquired; // Have we acquired the resource?
248
249 static_assert(!std::is_pointer<TYPE>::value || DEFAULTVALUE == 0 || DEFAULTVALUE == UINT_PTR(-1 /*INVALID_HANDLE_VALUE*/),
250 "DEFAULTVALUE must be NULL for pointer holders and wrappers.");
251
252 public:
253 FORCEINLINE BaseHolder()
254 : BASE(TYPE(DEFAULTVALUE)),
255 m_acquired(FALSE)
256 {
257 }
258 FORCEINLINE BaseHolder(TYPE value)
259 : BASE(value),
260 m_acquired(FALSE)
261 {
262 if (!IsNull())
263 Acquire();
264 }
265 FORCEINLINE BaseHolder(TYPE value, BOOL takeOwnership)
266 : BASE(value),
267 m_acquired(FALSE)
268 {
269 if (takeOwnership)
270 Acquire();
271 }
272 FORCEINLINE ~BaseHolder()
273 {
274 Release();
275 }
276 // Sets the value to 'value'. Doesn't call Acquire if value is DEFAULTVALUE.
277 FORCEINLINE void Assign(TYPE value)
278 {
279 Assign(value, !IS_NULL(value, TYPE(DEFAULTVALUE)));
280 }
281 // Sets the value to 'value'. Doesn't call Acquire if fTake is FALSE.
282 FORCEINLINE void Assign(TYPE value, BOOL takeOwnership)
283 {
284 Release();
285 this->m_value = value;
286 if (takeOwnership)
287 Acquire();
288 }
289 FORCEINLINE void Acquire()
290 {
291 STATIC_CONTRACT_WRAPPER;
292 _ASSERTE(!m_acquired);
293
294 if (!IsNull())
295 {
296 this->DoAcquire();
297 m_acquired = TRUE;
298 }
299 }
300 FORCEINLINE void Release()
301 {
302 STATIC_CONTRACT_WRAPPER;
303 if (m_acquired)
304 {
305 _ASSERTE(!IsNull());
306
307 if (VALIDATION_TYPE != HSV_NoValidation)
308 {
309 VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(VALIDATION_TYPE);
310 this->DoRelease();
311 }
312 else
313 {
314 this->DoRelease();
315 }
316 m_acquired = FALSE;
317 }
318 }
319
320 FORCEINLINE void Clear()
321 {
322 STATIC_CONTRACT_WRAPPER;
323 Assign(TYPE(DEFAULTVALUE), FALSE);
324 }
325 FORCEINLINE void SuppressRelease()
326 {
327 STATIC_CONTRACT_LEAF;
328 m_acquired = FALSE;
329 }
330 FORCEINLINE TYPE Extract()
331 {
332 STATIC_CONTRACT_WRAPPER;
333 SuppressRelease();
334 return GetValue();
335 }
336 FORCEINLINE TYPE GetValue()
337 {
338 STATIC_CONTRACT_LEAF;
339 return this->m_value;
340 }
341 FORCEINLINE BOOL IsNull() const
342 {
343 STATIC_CONTRACT_WRAPPER;
344 return IS_NULL(this->m_value, TYPE(DEFAULTVALUE));
345 }
346
347 HIDE_GENERATED_METHODS(BaseHolder)
348}; // BaseHolder<>
349
350template <void (*ACQUIRE)(), void (*RELEASEF)(), HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq>
351class StateHolder
352{
353 private:
354 BOOL m_acquired; // Have we acquired the state?
355
356 public:
357 FORCEINLINE StateHolder(BOOL take = TRUE)
358 : m_acquired(FALSE)
359 {
360 STATIC_CONTRACT_WRAPPER;
361 if (take)
362 Acquire();
363 }
364 FORCEINLINE ~StateHolder()
365 {
366 STATIC_CONTRACT_WRAPPER;
367 Release();
368 }
369 FORCEINLINE void Acquire()
370 {
371 STATIC_CONTRACT_WRAPPER;
372 // Insert any global or thread bookeeping here
373
374 _ASSERTE(!m_acquired);
375
376 ACQUIRE();
377 m_acquired = TRUE;
378 }
379 FORCEINLINE void Release()
380 {
381 STATIC_CONTRACT_WRAPPER;
382 // Insert any global or thread bookeeping here
383
384 if (m_acquired)
385 {
386 if (VALIDATION_TYPE != HSV_NoValidation)
387 {
388 VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(VALIDATION_TYPE);
389 RELEASEF();
390 }
391 else
392 {
393 RELEASEF();
394 }
395 m_acquired = FALSE;
396 }
397 }
398 FORCEINLINE void Clear()
399 {
400 STATIC_CONTRACT_WRAPPER;
401 if (m_acquired)
402 {
403 RELEASEF();
404 }
405
406 m_acquired = FALSE;
407 }
408 FORCEINLINE void SuppressRelease()
409 {
410 STATIC_CONTRACT_LEAF;
411 m_acquired = FALSE;
412 }
413
414 HIDE_GENERATED_METHODS(StateHolder)
415}; // class StateHolder<>
416
417// Holder for the case where the acquire function can fail.
418template <typename VALUE, BOOL (*ACQUIRE)(VALUE value), void (*RELEASEF)(VALUE value), HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq>
419class ConditionalStateHolder
420{
421 private:
422 VALUE m_value;
423 BOOL m_acquired; // Have we acquired the state?
424
425 public:
426 FORCEINLINE ConditionalStateHolder(VALUE value, BOOL take = TRUE)
427 : m_value(value), m_acquired(FALSE)
428 {
429 STATIC_CONTRACT_WRAPPER;
430 if (take)
431 Acquire();
432 }
433 FORCEINLINE ~ConditionalStateHolder()
434 {
435 STATIC_CONTRACT_WRAPPER;
436 Release();
437 }
438 FORCEINLINE BOOL Acquire()
439 {
440 STATIC_CONTRACT_WRAPPER;
441 // Insert any global or thread bookeeping here
442
443 _ASSERTE(!m_acquired);
444
445 m_acquired = ACQUIRE(m_value);
446
447 return m_acquired;
448 }
449 FORCEINLINE void Release()
450 {
451 STATIC_CONTRACT_WRAPPER;
452 // Insert any global or thread bookeeping here
453
454 if (m_acquired)
455 {
456 if (VALIDATION_TYPE != HSV_NoValidation)
457 {
458 VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(VALIDATION_TYPE);
459 RELEASEF(m_value);
460 }
461 else
462 {
463 RELEASEF(m_value);
464 }
465 m_acquired = FALSE;
466 }
467 }
468 FORCEINLINE void Clear()
469 {
470 STATIC_CONTRACT_WRAPPER;
471 if (m_acquired)
472 {
473 RELEASEF(m_value);
474 }
475
476 m_acquired = FALSE;
477 }
478 FORCEINLINE void SuppressRelease()
479 {
480 STATIC_CONTRACT_LEAF;
481 m_acquired = FALSE;
482 }
483 FORCEINLINE BOOL Acquired()
484 {
485 STATIC_CONTRACT_LEAF;
486
487 return m_acquired;
488 }
489
490 HIDE_GENERATED_METHODS(ConditionalStateHolder)
491}; // class ConditionalStateHolder<>
492
493
494// Making the copy constructor private produces a warning about "can't generate copy
495// constructor" on all holders (duh, that's the point.)
496#ifdef _MSC_VER
497#pragma warning(disable:4511)
498#endif // _MSC_VER
499
500//-----------------------------------------------------------------------------
501// BaseWrapper is just Base like a Holder, but it "transparently" proxies the type it contains,
502// using operator overloads. Use this when you want a holder to expose the functionality of
503// the value it contains.
504//-----------------------------------------------------------------------------
505template <typename TYPE, typename BASE,
506 UINT_PTR DEFAULTVALUE = 0, BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>, HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq>
507class BaseWrapper : public BaseHolder<TYPE, BASE, DEFAULTVALUE, IS_NULL, VALIDATION_TYPE>
508{
509 typedef BaseHolder<TYPE, BASE, DEFAULTVALUE, IS_NULL, VALIDATION_TYPE> BaseT;
510
511
512#ifdef __GNUC__
513//#pragma GCC visibility push(hidden)
514#endif // __GNUC__
515 // This temporary object takes care of the case where we are initializing
516 // a holder's contents by passing it as an out parameter. The object is
517 // guaranteed to live longer than the call it is passed to, hence we should
518 // properly acquire the object on return
519 friend class AddressInitHolder;
520 class AddressInitHolder
521 {
522 protected:
523 BaseWrapper<TYPE,BASE,DEFAULTVALUE,IS_NULL> &m_holder;
524
525 public:
526 FORCEINLINE AddressInitHolder(BaseWrapper<TYPE,BASE,DEFAULTVALUE,IS_NULL> &holder)
527 : m_holder(holder)
528 {
529 //
530 // We must clear the value, to avoid the following scenario:
531 //
532 // ReleaseHolder<MyType> pMyType;
533 // hr = MyFunction(&pMyType, ...);
534 // <do something with pMyType>
535 // hr = MyFunction(&pMyType, ...); <- calls Release before call and Acquire on return.
536 //
537 // If the second call to MyFunction were to fail and return without updating the
538 // out parameter, then ~AddressInitHolder will all Acquire, which is a no-op on
539 // the underlying pointer but sets m_acquired to TRUE. Thus, when pMyType goes
540 // out of scope, ReleaseHolder will cause a double-release of pMyType.
541 //
542 // By calling Clear, then the call to Acquire in the dtor will not set m_acquired
543 // to true since IsNull(m_holder.m_value) will return true.
544 //
545 m_holder.Clear();
546 }
547 FORCEINLINE ~AddressInitHolder()
548 {
549 m_holder.Acquire();
550 }
551
552 // It's not optimal to have to declare these casting operators. But if we don't,
553 // people cannot cast the result of &holder to these values. (The C++ compiler won't
554 // automatically use the TYPE * cast as an intermediate value.) So we put them here,
555 // rather than forcing callers to double cast in these common cases.
556
557 FORCEINLINE operator IUnknown **()
558 {
559 IUnknown *unknown;
560 // Typesafe check. This will fail at compile time if
561 // m_holder.m_value can't be converted to an IUnknown *.
562 unknown = static_cast<IUnknown*>(m_holder.m_value);
563 // do the cast with an unsafe cast
564 return (IUnknown **)(&m_holder.m_value);
565 }
566
567#if defined(FEATURE_COMINTEROP) && !defined(STRIKE)
568 FORCEINLINE operator IInspectable **()
569 {
570 IInspectable *inspectable;
571 // Typesafe check. This will fail at compile time if
572 // m_holder.m_value can't be converted to an IInspectable *.
573 inspectable = static_cast<IInspectable *>(m_holder.m_value);
574 return (IInspectable **)(&m_holder.m_value);
575
576 }
577#endif // FEATURE_COMINTEROP
578
579 FORCEINLINE operator void **()
580 {
581 return (void **)(&m_holder.m_value);
582 }
583 FORCEINLINE operator void *()
584 {
585 return (void *)(&m_holder.m_value);
586 }
587 };
588
589 // Separate out method with TYPE * cast operator, since it may clash with IUnknown ** or
590 // void ** cast operator.
591 friend class TypedAddressInitHolder;
592 class TypedAddressInitHolder : public AddressInitHolder
593 {
594 public:
595 FORCEINLINE TypedAddressInitHolder(BaseWrapper & holder)
596 : AddressInitHolder(holder)
597 {
598 }
599
600 FORCEINLINE operator TYPE *()
601 {
602 return static_cast<TYPE *>(&this->m_holder.m_value);
603 }
604 };
605#ifdef __GNUC__
606//#pragma GCC visibility pop
607#endif // __GNUC__
608
609 public:
610 FORCEINLINE BaseWrapper()
611 : BaseT(TYPE(DEFAULTVALUE), FALSE)
612 {
613 }
614 FORCEINLINE BaseWrapper(TYPE value)
615 : BaseT(value)
616 {
617 }
618 FORCEINLINE BaseWrapper(TYPE value, BOOL take)
619 : BaseT(value, take)
620 {
621 }
622 FORCEINLINE BaseWrapper& operator=(TYPE value)
623 {
624 BaseT::Assign(value);
625 return *this;
626 }
627 FORCEINLINE operator TYPE() const
628 {
629 return this->m_value;
630 }
631 FORCEINLINE TypedAddressInitHolder operator&()
632 {
633 return TypedAddressInitHolder(*this);
634 }
635 template <typename T>
636 FORCEINLINE bool operator==(T const & value) const
637 {
638 return !!(this->m_value == TYPE(value));
639 }
640 template <typename T>
641 FORCEINLINE bool operator!=(T const & value) const
642 {
643 return !!(this->m_value != TYPE(value));
644 }
645#ifdef __llvm__
646 // This handles the NULL value that is an int and clang
647 // doesn't want to convert int to a pointer
648 FORCEINLINE bool operator==(int value) const
649 {
650 return !!(this->m_value == TYPE((void*)(SIZE_T)value));
651 }
652 FORCEINLINE bool operator!=(int value) const
653 {
654 return !!(this->m_value != TYPE((void*)(SIZE_T)value));
655 }
656#endif // __llvm__
657 FORCEINLINE const TYPE &operator->() const
658 {
659 return this->m_value;
660 }
661 FORCEINLINE int operator!() const
662 {
663 return this->IsNull();
664 }
665
666 private:
667 HIDE_GENERATED_METHODS(BaseWrapper)
668}; // class BaseWrapper<>
669
670//-----------------------------------------------------------------------------
671// Generic templates to use to wrap up acquire/release functionality for Holder
672//-----------------------------------------------------------------------------
673
674template <typename TYPE>
675FORCEINLINE void DoNothing(TYPE value)
676{
677 // @TODO: Due to prefast template problems, implementations of the DoNothing macro have been changed
678 // Search by prefast, and remove them when prefast is ready
679}
680
681FORCEINLINE void DoNothing()
682{
683}
684
685// Prefast stuff.We should have DoNothing<type*> in the holder declaration, but currently
686// prefast doesnt support, it, so im stuffing all these here so if we need to change the template you can change
687// everything here. When prefast works, remove the following functions
688struct ConnectionCookie;
689FORCEINLINE void ConnectionCookieDoNothing(ConnectionCookie* p)
690{
691}
692
693class ComCallWrapper;
694FORCEINLINE void CCWHolderDoNothing(ComCallWrapper* p)
695{
696}
697
698
699FORCEINLINE void DispParamHolderDoNothing(VARIANT* p)
700{
701}
702
703FORCEINLINE void VariantPtrDoNothing(VARIANT* p)
704{
705}
706
707FORCEINLINE void VariantDoNothing(VARIANT)
708{
709}
710
711FORCEINLINE void ZeroDoNothing(VOID* p)
712{
713}
714
715class CtxEntry;
716FORCEINLINE void CtxEntryDoNothing(CtxEntry* p)
717{
718}
719
720struct RCW;
721FORCEINLINE void NewRCWHolderDoNothing(RCW*)
722{
723}
724
725// Prefast stuff.We should have DoNothing<SafeArray*> in the holder declaration
726FORCEINLINE void SafeArrayDoNothing(SAFEARRAY* p)
727{
728}
729
730
731
732
733//-----------------------------------------------------------------------------
734// Holder/Wrapper are the simplest way to define holders - they synthesizes a base class out of
735// function pointers
736//-----------------------------------------------------------------------------
737
738template <typename TYPE, void (*ACQUIREF)(TYPE), void (*RELEASEF)(TYPE), HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq>
739class FunctionBase : protected HolderBase<TYPE>
740{
741 protected:
742
743 FORCEINLINE FunctionBase(TYPE value)
744 : HolderBase<TYPE>(value)
745 {
746 }
747
748 FORCEINLINE void DoAcquire()
749 {
750 ACQUIREF(this->m_value);
751 }
752
753 void DoRelease()
754 {
755 // <TODO> Consider removing this stack validation since it is redundant with the
756 // one that is already being done in BaseHolder & BaseWrapper. </TODO>
757 if (VALIDATION_TYPE != HSV_NoValidation)
758 {
759 VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(VALIDATION_TYPE);
760 RELEASEF(this->m_value);
761 }
762 else
763 {
764 RELEASEF(this->m_value);
765 }
766 }
767}; // class Function<>
768
769template
770 <
771 typename TYPE,
772 void (*ACQUIREF)(TYPE),
773 void (*RELEASEF)(TYPE),
774 UINT_PTR DEFAULTVALUE = 0,
775 BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>,
776 HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq,
777 // For legacy compat (see EEJitManager::WriterLockHolder), where default ctor
778 // causes ACQUIREF(DEFAULTVALUE), but ACQUIREF ignores the argument and
779 // operates on static or global value instead.
780 bool DEFAULT_CTOR_ACQUIRE = true
781 >
782class Holder : public BaseHolder<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF, VALIDATION_TYPE>,
783 DEFAULTVALUE, IS_NULL, VALIDATION_TYPE>
784{
785 typedef BaseHolder<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF, VALIDATION_TYPE>,
786 DEFAULTVALUE, IS_NULL, VALIDATION_TYPE> BaseT;
787
788 public:
789 FORCEINLINE Holder()
790 : BaseT(TYPE(DEFAULTVALUE), DEFAULT_CTOR_ACQUIRE)
791 {
792 STATIC_CONTRACT_WRAPPER;
793 }
794
795 FORCEINLINE Holder(TYPE value)
796 : BaseT(value)
797 {
798 STATIC_CONTRACT_WRAPPER;
799 }
800
801 FORCEINLINE Holder(TYPE value, BOOL takeOwnership)
802 : BaseT(value, takeOwnership)
803 {
804 STATIC_CONTRACT_WRAPPER;
805 }
806
807 FORCEINLINE Holder& operator=(TYPE p)
808 {
809 STATIC_CONTRACT_WRAPPER;
810 BaseT::operator=(p);
811 return *this;
812 }
813
814 HIDE_GENERATED_METHODS(Holder)
815};
816
817//---------------------------------------------------------------------------------------
818//
819template
820 <
821 typename TYPE,
822 void (*ACQUIREF)(TYPE),
823 void (*RELEASEF)(TYPE),
824 UINT_PTR DEFAULTVALUE = 0,
825 BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>,
826 HolderStackValidation VALIDATION_TYPE = HSV_ValidateNormalStackReq,
827 // For legacy compat (see EEJitManager::WriterLockHolder), where default ctor
828 // causes ACQUIREF(DEFAULTVALUE), but ACQUIREF ignores the argument and
829 // operates on static or global value instead.
830 bool DEFAULT_CTOR_ACQUIRE = true
831 >
832class Wrapper : public BaseWrapper<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF, VALIDATION_TYPE>,
833 DEFAULTVALUE, IS_NULL, VALIDATION_TYPE>
834{
835 typedef BaseWrapper<TYPE, FunctionBase<TYPE, ACQUIREF, RELEASEF, VALIDATION_TYPE>,
836 DEFAULTVALUE, IS_NULL, VALIDATION_TYPE> BaseT;
837
838 public:
839 FORCEINLINE Wrapper()
840 : BaseT(TYPE(DEFAULTVALUE), DEFAULT_CTOR_ACQUIRE)
841 {
842 STATIC_CONTRACT_WRAPPER;
843 }
844
845 FORCEINLINE Wrapper(TYPE value)
846 : BaseT(value)
847 {
848 STATIC_CONTRACT_WRAPPER;
849 }
850
851 FORCEINLINE Wrapper(TYPE value, BOOL takeOwnership)
852 : BaseT(value, takeOwnership)
853 {
854 STATIC_CONTRACT_WRAPPER;
855 }
856
857 FORCEINLINE Wrapper& operator=(TYPE const & value)
858 {
859 STATIC_CONTRACT_WRAPPER;
860 BaseT::operator=(value);
861 return *this;
862 }
863
864 HIDE_GENERATED_METHODS(Wrapper)
865}; // Wrapper<>
866
867//---------------------------------------------------------------------------------------
868// - Cannot use the standard INDEBUG macro: holder.h is used in places where INDEBUG is defined in the nonstandard way
869#if defined(_DEBUG)
870#define INDEBUG_AND_WINDOWS_FOR_HOLDERS(x) x
871#else
872#define INDEBUG_AND_WINDOWS_FOR_HOLDERS(x)
873#endif
874
875//---------------------------------------------------------------------------------------
876//
877// New template wrapper type macros. These save some effort when specializing
878// existing holder templates. (We would rather use a construct like:
879//
880// template <P1>
881// typedef Holder<...> NewHolder;
882//
883// But this construct doesn't exist in C++. These macros ease some of the cruft necessary
884// to get similar functionality out of class templates.
885//-----------------------------------------------------------------------------
886
887// Dev10 VC++ has some of the new C++0x language extensions. Of particular interest here:
888// rvalue references, which enables differentiation between named (lvalue) and
889// temporary (rvalue) object references, enabling move semantics and perfect forwarding.
890// See http://msdn.microsoft.com/en-us/library/dd293668.aspx for more information.
891
892// Enable copy construction and assignment from temporary objects. This permits Wrapper objects
893// to be returned from methods, and for move assignment.
894#define NEW_WRAPPER_TEMPLATE_RVALREF_METHODS(_NAME) \
895 public: \
896 FORCEINLINE _NAME(_NAME && other) \
897 : BaseT(NULL, FALSE) \
898 { \
899 STATIC_CONTRACT_WRAPPER; \
900 INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) \
901 *this = std::move(other); \
902 } \
903 FORCEINLINE _NAME& operator=(_NAME && other) \
904 { \
905 std::swap(BaseT::m_value, other.BaseT::m_value); \
906 std::swap(BaseT::m_acquired, other.BaseT::m_acquired); \
907 return *this; \
908 }
909
910#define NEW_WRAPPER_TEMPLATE1(_NAME, _RELEASEF) \
911 template <typename _TYPE> \
912 class _NAME : public Wrapper<_TYPE*, DoNothing<_TYPE*>, _RELEASEF, NULL> \
913 { \
914 typedef Wrapper<_TYPE*, DoNothing<_TYPE*>, _RELEASEF, NULL> BaseT; \
915 public: \
916 FORCEINLINE _NAME() : BaseT(NULL, FALSE) \
917 { \
918 STATIC_CONTRACT_WRAPPER; \
919 INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) \
920 } \
921 FORCEINLINE _NAME(_TYPE* value) : BaseT(value) \
922 { \
923 STATIC_CONTRACT_WRAPPER; \
924 INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) \
925 } \
926 FORCEINLINE _NAME(_TYPE* value, BOOL takeOwnership) : BaseT(value, takeOwnership) \
927 { \
928 STATIC_CONTRACT_WRAPPER; \
929 INDEBUG_AND_WINDOWS_FOR_HOLDERS(m_pvalue = &this->m_value;) \
930 } \
931 FORCEINLINE ~_NAME() \
932 { \
933 } \
934 FORCEINLINE _NAME& operator=(_TYPE * value) \
935 { \
936 STATIC_CONTRACT_WRAPPER; \
937 BaseT::operator=(value); \
938 return *this; \
939 } \
940 /* Since operator& is overloaded we need a way to get a type safe this pointer. */ \
941 FORCEINLINE _NAME* GetAddr() \
942 { \
943 STATIC_CONTRACT_LEAF; \
944 return this; \
945 } \
946 NEW_WRAPPER_TEMPLATE_RVALREF_METHODS(_NAME) \
947 HIDE_GENERATED_METHODS(_NAME) \
948 private: \
949 /* m_ppValue: Do not use from source code: Only for convenient use from debugger */ \
950 /* watch windows - saves five mouseclicks when inspecting holders. */ \
951 INDEBUG_AND_WINDOWS_FOR_HOLDERS(_TYPE ** m_pvalue;) \
952 };
953
954//-----------------------------------------------------------------------------
955// NOTE: THIS IS UNSAFE TO USE IN THE VM for interop COM objects!!
956// WE DO NOT CORRECTLY CHANGE TO PREEMPTIVE MODE BEFORE CALLING RELEASE!!
957// USE SafeComHolder
958//
959// ReleaseHolder : COM Interface holder for use outside the VM (or on well known instances
960// which do not need preemptive Relesae)
961//
962// Usage example:
963//
964// {
965// ReleaseHolder<IFoo> foo;
966// hr = FunctionToGetRefOfFoo(&foo);
967// // Note ComHolder doesn't call AddRef - it assumes you already have a ref (if non-0).
968// } // foo->Release() on out of scope (WITHOUT RESPECT FOR GC MODE!!)
969//
970//-----------------------------------------------------------------------------
971
972template <typename TYPE>
973FORCEINLINE void DoTheRelease(TYPE *value)
974{
975 if (value)
976 {
977 VALIDATE_HOLDER_STACK_CONSUMPTION_FOR_TYPE(HSV_ValidateNormalStackReq);
978 value->Release();
979 }
980}
981
982NEW_WRAPPER_TEMPLATE1(DoNothingHolder, DoNothing<_TYPE*>);
983
984NEW_WRAPPER_TEMPLATE1(ReleaseHolder, DoTheRelease<_TYPE>);
985
986NEW_WRAPPER_TEMPLATE1(NonVMComHolder, DoTheRelease<_TYPE>);
987
988
989//-----------------------------------------------------------------------------
990// StubHolder : holder for stubs
991//
992// Usage example:
993//
994// {
995// StubHolder<Stub> foo;
996// foo = new Stub();
997// foo->AddRef();
998// // Note StubHolder doesn't call AddRef for you.
999// } // foo->DecRef() on out of scope
1000//
1001//-----------------------------------------------------------------------------
1002template <typename TYPE>
1003FORCEINLINE void StubRelease(TYPE* value)
1004{
1005 if (value)
1006 value->DecRef();
1007}
1008
1009NEW_WRAPPER_TEMPLATE1(StubHolder, StubRelease<_TYPE>);
1010
1011//-----------------------------------------------------------------------------
1012// CoTaskMemHolder : CoTaskMemAlloc allocated memory holder
1013//
1014// {
1015// CoTaskMemHolder<Foo> foo = (Foo*) CoTaskMemAlloc(sizeof(Foo));
1016// } // delete foo on out of scope
1017//-----------------------------------------------------------------------------
1018
1019template <typename TYPE>
1020FORCEINLINE void DeleteCoTaskMem(TYPE *value)
1021{
1022 if (value)
1023 CoTaskMemFree(value);
1024}
1025
1026NEW_WRAPPER_TEMPLATE1(CoTaskMemHolder, DeleteCoTaskMem<_TYPE>);
1027
1028//-----------------------------------------------------------------------------
1029// NewHolder : New'ed memory holder
1030//
1031// {
1032// NewHolder<Foo> foo = new Foo ();
1033// } // delete foo on out of scope
1034//-----------------------------------------------------------------------------
1035
1036template <typename TYPE>
1037FORCEINLINE void Delete(TYPE *value)
1038{
1039 STATIC_CONTRACT_LEAF;
1040
1041 static_assert(!std::is_same<typename std::remove_cv<TYPE>::type, WCHAR>::value,
1042 "Must use NewArrayHolder (not NewHolder) for strings.");
1043 static_assert(!std::is_same<typename std::remove_cv<TYPE>::type, CHAR>::value,
1044 "Must use NewArrayHolder (not NewHolder) for strings.");
1045
1046 delete value;
1047}
1048
1049NEW_WRAPPER_TEMPLATE1(NewHolder, Delete<_TYPE>);
1050
1051 //-----------------------------------------------------------------------------
1052// NewExecutableHolder : New'ed memory holder for executable memory.
1053//
1054// {
1055// NewExecutableHolder<Foo> foo = (Foo*) new (executable) Byte[num];
1056// } // delete foo on out of scope
1057//-----------------------------------------------------------------------------
1058// IJW
1059template<class T> void DeleteExecutable(T *p);
1060
1061NEW_WRAPPER_TEMPLATE1(NewExecutableHolder, DeleteExecutable<_TYPE>);
1062
1063//-----------------------------------------------------------------------------
1064// NewArrayHolder : New []'ed pointer holder
1065// {
1066// NewArrayHolder<Foo> foo = new Foo [30];
1067// } // delete [] foo on out of scope
1068//-----------------------------------------------------------------------------
1069
1070template <typename TYPE>
1071FORCEINLINE void DeleteArray(TYPE *value)
1072{
1073 STATIC_CONTRACT_WRAPPER;
1074 delete [] value;
1075 value = NULL;
1076}
1077
1078NEW_WRAPPER_TEMPLATE1(NewArrayHolder, DeleteArray<_TYPE>);
1079typedef NewArrayHolder<CHAR> AStringHolder;
1080typedef NewArrayHolder<WCHAR> WStringHolder;
1081
1082//-----------------------------------------------------------------------------
1083// A special array holder that expects its contents are interface pointers,
1084// and will call Release() on them.
1085//
1086// NOTE: You may ONLY use this if you've determined that it is SAFE to call
1087// Release() on the contained interface pointers (e.g., as opposed to SafeRelease)
1088//
1089template <typename INTERFACE>
1090class NewInterfaceArrayHolder : public NewArrayHolder<INTERFACE *>
1091{
1092public:
1093 NewInterfaceArrayHolder() :
1094 NewArrayHolder<INTERFACE *>(),
1095 m_cElements(0)
1096 {
1097 STATIC_CONTRACT_WRAPPER;
1098 }
1099
1100 NewInterfaceArrayHolder& operator=(INTERFACE ** value)
1101 {
1102 STATIC_CONTRACT_WRAPPER;
1103 NewArrayHolder<INTERFACE *>::operator=(value);
1104 return *this;
1105 }
1106
1107 void SetElementCount(ULONG32 cElements)
1108 {
1109 STATIC_CONTRACT_LEAF;
1110 m_cElements = cElements;
1111 }
1112
1113 ~NewInterfaceArrayHolder()
1114 {
1115 STATIC_CONTRACT_LEAF;
1116 for (ULONG32 i=0; i < m_cElements; i++)
1117 {
1118 if (this->m_value[i] != NULL)
1119 this->m_value[i]->Release();
1120 }
1121 }
1122
1123protected:
1124 ULONG32 m_cElements;
1125};
1126
1127
1128//-----------------------------------------------------------------------------
1129// ResetPointerHolder : pointer which needs to be set to NULL
1130// {
1131// ResetPointerHolder<Foo> holder = &pFoo;
1132// } // "*pFoo=NULL" on out of scope
1133//-----------------------------------------------------------------------------
1134#ifdef __GNUC__
1135// With -fvisibility-inlines-hidden, the Invoke methods below
1136// get hidden, which causes warnings when visible classes expose them.
1137#define VISIBLE __attribute__ ((visibility("default")))
1138#else
1139#define VISIBLE
1140#endif // __GNUC__
1141
1142namespace detail
1143{
1144 template <typename T>
1145 struct ZeroMem
1146 {
1147 static VISIBLE void Invoke(T * pVal)
1148 {
1149 ZeroMemory(pVal, sizeof(T));
1150 }
1151 };
1152
1153 template <typename T>
1154 struct ZeroMem<T*>
1155 {
1156 static VISIBLE void Invoke(T ** pVal)
1157 {
1158 *pVal = NULL;
1159 }
1160 };
1161
1162}
1163#undef VISIBLE
1164
1165NEW_WRAPPER_TEMPLATE1(ResetPointerHolder, detail::ZeroMem<_TYPE>::Invoke);
1166NEW_WRAPPER_TEMPLATE1(FieldNuller, detail::ZeroMem<_TYPE>::Invoke);
1167
1168//-----------------------------------------------------------------------------
1169// Wrap win32 functions using HANDLE
1170//-----------------------------------------------------------------------------
1171
1172FORCEINLINE void VoidCloseHandle(HANDLE h) { if (h != NULL) CloseHandle(h); }
1173// (UINT_PTR) -1 is INVALID_HANDLE_VALUE
1174FORCEINLINE void VoidCloseFileHandle(HANDLE h) { if (h != ((HANDLE)((LONG_PTR) -1))) CloseHandle(h); }
1175FORCEINLINE void VoidFindClose(HANDLE h) { FindClose(h); }
1176FORCEINLINE void VoidUnmapViewOfFile(void *ptr) { UnmapViewOfFile(ptr); }
1177
1178template <typename TYPE>
1179FORCEINLINE void TypeUnmapViewOfFile(TYPE *ptr) { UnmapViewOfFile(ptr); }
1180
1181// (UINT_PTR) -1 is INVALID_HANDLE_VALUE
1182//@TODO: Dangerous default value. Some Win32 functions return INVALID_HANDLE_VALUE, some return NULL (such as CreatEvent).
1183typedef Wrapper<HANDLE, DoNothing<HANDLE>, VoidCloseHandle, (UINT_PTR) -1> HandleHolder;
1184typedef Wrapper<HANDLE, DoNothing<HANDLE>, VoidCloseFileHandle, (UINT_PTR) -1> FileHandleHolder;
1185typedef Wrapper<HANDLE, DoNothing<HANDLE>, VoidFindClose, (UINT_PTR) -1> FindHandleHolder;
1186
1187typedef Wrapper<void *, DoNothing, VoidUnmapViewOfFile> MapViewHolder;
1188
1189#ifdef WszDeleteFile
1190// Deletes a file with the specified path. Do not use if you care about failures
1191// deleting the file, as failures are ignored by VoidDeleteFile.
1192FORCEINLINE void VoidDeleteFile(LPCWSTR wszFilePath) { WszDeleteFile(wszFilePath); }
1193typedef Wrapper<LPCWSTR, DoNothing<LPCWSTR>, VoidDeleteFile, NULL> DeleteFileHolder;
1194#endif // WszDeleteFile
1195
1196
1197//-----------------------------------------------------------------------------
1198// Misc holders
1199//-----------------------------------------------------------------------------
1200
1201// A holder for HMODULE.
1202FORCEINLINE void HolderFreeLibrary(HMODULE h) { FreeLibrary(h); }
1203
1204typedef Wrapper<HMODULE, DoNothing<HMODULE>, HolderFreeLibrary, NULL> HModuleHolder;
1205
1206template <typename T> FORCEINLINE
1207void DoLocalFree(T* pMem) { (LocalFree)((HLOCAL)pMem); }
1208
1209NEW_WRAPPER_TEMPLATE1(LocalAllocHolder, DoLocalFree<_TYPE>);
1210
1211inline void BoolSet( _Out_ bool * val ) { *val = true; }
1212inline void BoolUnset( _Out_ bool * val ) { *val = false; }
1213
1214typedef Wrapper< bool *, BoolSet, BoolUnset > BoolFlagStateHolder;
1215
1216//
1217// We need the following methods to have volatile arguments, so that they can accept
1218// raw pointers in addition to the results of the & operator on Volatile<T>.
1219//
1220
1221FORCEINLINE void CounterIncrease(RAW_KEYWORD(volatile) LONG* p) {InterlockedIncrement(p);};
1222FORCEINLINE void CounterDecrease(RAW_KEYWORD(volatile) LONG* p) {InterlockedDecrement(p);};
1223
1224typedef Wrapper<RAW_KEYWORD(volatile) LONG*, CounterIncrease, CounterDecrease, (UINT_PTR)0, CompareDefault<RAW_KEYWORD(volatile) LONG*>, HSV_NoValidation> CounterHolder;
1225
1226
1227#ifndef FEATURE_PAL
1228FORCEINLINE void RegKeyRelease(HKEY k) {RegCloseKey(k);};
1229typedef Wrapper<HKEY,DoNothing,RegKeyRelease> RegKeyHolder;
1230#endif // !FEATURE_PAL
1231
1232class ErrorModeHolder
1233{
1234 UINT m_oldMode;
1235public:
1236 ErrorModeHolder(UINT newMode){m_oldMode=SetErrorMode(newMode);};
1237 ~ErrorModeHolder(){SetErrorMode(m_oldMode);};
1238 UINT OldMode() {return m_oldMode;};
1239};
1240
1241#ifndef FEATURE_PAL
1242//-----------------------------------------------------------------------------
1243// HKEYHolder : HKEY holder, Calls RegCloseKey on scope exit.
1244//
1245// {
1246// HKEYHolder hFoo = NULL;
1247// WszRegOpenKeyEx(HKEY_CLASSES_ROOT, L"Interface",0, KEY_READ, hFoo);
1248//
1249// } // close key on out of scope via RegCloseKey.
1250//-----------------------------------------------------------------------------
1251
1252class HKEYHolder
1253{
1254public:
1255 HKEYHolder()
1256 {
1257 STATIC_CONTRACT_LEAF;
1258 m_value = 0;
1259 }
1260
1261 ~HKEYHolder()
1262 {
1263 STATIC_CONTRACT_WRAPPER;
1264 if (m_value != NULL)
1265 ::RegCloseKey(m_value);
1266 }
1267
1268 FORCEINLINE void operator=(HKEY p)
1269 {
1270 STATIC_CONTRACT_LEAF;
1271 if (p != 0)
1272 m_value = p;
1273 }
1274
1275 FORCEINLINE operator HKEY()
1276 {
1277 STATIC_CONTRACT_LEAF;
1278 return m_value;
1279 }
1280
1281 FORCEINLINE operator HKEY*()
1282 {
1283 STATIC_CONTRACT_LEAF;
1284 return &m_value;
1285 }
1286
1287 FORCEINLINE HKEY* operator&()
1288 {
1289 STATIC_CONTRACT_LEAF;
1290 return &m_value;
1291 }
1292
1293private:
1294 HKEY m_value;
1295};
1296#endif // !FEATURE_PAL
1297
1298//----------------------------------------------------------------------------
1299//
1300// External data access does not want certain holder implementations
1301// to be active as locks should not be taken and so on. Provide
1302// a no-op in that case.
1303//
1304//----------------------------------------------------------------------------
1305
1306#ifndef DACCESS_COMPILE
1307
1308#define DacHolder Holder
1309
1310#else
1311
1312template <typename TYPE, void (*ACQUIRE)(TYPE), void (*RELEASEF)(TYPE), UINT_PTR DEFAULTVALUE = 0, BOOL IS_NULL(TYPE, TYPE) = CompareDefault<TYPE>, BOOL VALIDATE_BACKOUT_STACK = TRUE>
1313class DacHolder
1314{
1315 protected:
1316 TYPE m_value;
1317
1318 private:
1319 BOOL m_acquired; // Have we acquired the resource?
1320
1321 public:
1322 FORCEINLINE DacHolder()
1323 : m_value(TYPE(DEFAULTVALUE)),
1324 m_acquired(FALSE)
1325 {
1326 STATIC_CONTRACT_SUPPORTS_DAC;
1327 }
1328
1329 // construct a new instance of DacHolder
1330 // Arguments:
1331 // input: value - the resource held
1332 // take - indicates whether the lock should be taken--the default is true. See Notes:
1333 // Note: In DAC builds, the Acquire function does not actually take the lock, instead
1334 // it determines whether the lock is held (by the LS). If it is, the locked data
1335 // is assumed to be inconsistent and the Acquire function will throw.
1336 FORCEINLINE DacHolder(TYPE value, BOOL take = TRUE)
1337 : m_value(value),
1338 m_acquired(FALSE)
1339 {
1340 STATIC_CONTRACT_SUPPORTS_DAC;
1341 if (take)
1342 Acquire();
1343
1344 }
1345 FORCEINLINE ~DacHolder()
1346 {
1347 STATIC_CONTRACT_SUPPORTS_DAC;
1348 }
1349 // Sets the value to 'value'. Doesn't call Acquire/Release if fTake is FALSE.
1350 FORCEINLINE void Assign(TYPE value, BOOL fTake = TRUE)
1351 {
1352 m_value = value;
1353 }
1354 FORCEINLINE void Acquire()
1355 {
1356 STATIC_CONTRACT_SUPPORTS_DAC;
1357
1358 if (!IsNull())
1359 {
1360 m_acquired = TRUE;
1361 // because ACQUIRE is a template argument, if the line m_acquired = TRUE is placed after the call
1362 // where it logically belongs, the compiler flags it as "unreachable code."
1363 ACQUIRE(this->m_value);
1364 }
1365 }
1366 FORCEINLINE void Release()
1367 {
1368 // Insert any global or thread bookeeping here
1369
1370 if (m_acquired)
1371 {
1372 m_acquired = FALSE;
1373 }
1374 }
1375 FORCEINLINE void Clear()
1376 {
1377 m_value = TYPE(DEFAULTVALUE);
1378 m_acquired = FALSE;
1379 }
1380 FORCEINLINE void SuppressRelease()
1381 {
1382 m_acquired = FALSE;
1383 }
1384 FORCEINLINE TYPE GetValue()
1385 {
1386 return m_value;
1387 }
1388 FORCEINLINE BOOL IsNull() const
1389 {
1390 return IS_NULL(m_value, TYPE(DEFAULTVALUE));
1391 }
1392
1393 private:
1394 FORCEINLINE DacHolder& operator=(const Holder<TYPE, ACQUIRE, RELEASEF> &holder)
1395 {
1396 }
1397
1398 FORCEINLINE DacHolder(const Holder<TYPE, ACQUIRE, RELEASEF> &holder)
1399 {
1400 }
1401};
1402
1403#endif // #ifndef DACCESS_COMPILE
1404
1405// Holder-specific clr::SafeAddRef and clr::SafeRelease helper functions.
1406namespace clr
1407{
1408 // Copied from utilcode.h. We can't include the header directly because there
1409 // is circular reference.
1410 // Forward declare the overload which is used by 'SafeAddRef' below.
1411 template <typename ItfT>
1412 static inline
1413 typename std::enable_if< std::is_pointer<ItfT>::value, ItfT >::type
1414 SafeAddRef(ItfT pItf);
1415
1416 template < typename ItfT > __checkReturn
1417 ItfT *
1418 SafeAddRef(ReleaseHolder<ItfT> & pItf)
1419 {
1420 STATIC_CONTRACT_LIMITED_METHOD;
1421 //@TODO: Would be good to add runtime validation that the return value is used.
1422 return SafeAddRef(pItf.GetValue());
1423 }
1424
1425 namespace detail
1426 {
1427 template <typename T>
1428 char IsHolderHelper(HolderBase<T>*);
1429 int IsHolderHelper(...);
1430
1431 template <typename T>
1432 struct IsHolder : public std::conditional<
1433 sizeof(IsHolderHelper(reinterpret_cast<T*>(NULL))) == sizeof(char),
1434 std::true_type,
1435 std::false_type>::type
1436 {};
1437 }
1438
1439 template < typename T >
1440 typename std::enable_if<detail::IsHolder<T>::value, ULONG>::type
1441 SafeRelease(T& arg)
1442 {
1443 STATIC_CONTRACT_LIMITED_METHOD;
1444 return arg.Release();
1445 }
1446}
1447
1448#endif // __HOLDER_H_
1449