| 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 | // EEContract.h |
| 7 | // |
| 8 | |
| 9 | // ! I am the owner for issues in the contract *infrastructure*, not for every |
| 10 | // ! CONTRACT_VIOLATION dialog that comes up. If you interrupt my work for a routine |
| 11 | // ! CONTRACT_VIOLATION, you will become the new owner of this file. |
| 12 | // --------------------------------------------------------------------------- |
| 13 | |
| 14 | |
| 15 | #ifndef EECONTRACT_H_ |
| 16 | #define EECONTRACT_H_ |
| 17 | |
| 18 | #include "contract.h" |
| 19 | #include "stackprobe.h" |
| 20 | |
| 21 | // -------------------------------------------------------------------------------- |
| 22 | // EECONTRACT is an extension of the lower level CONTRACT macros to include some |
| 23 | // EE specific stuff like GC mode checking. See check.h for more info on CONTRACT. |
| 24 | // -------------------------------------------------------------------------------- |
| 25 | |
| 26 | #undef GC_TRIGGERS |
| 27 | #undef GC_NOTRIGGER |
| 28 | |
| 29 | #ifdef ENABLE_CONTRACTS_IMPL |
| 30 | |
| 31 | class EEContract : public BaseContract |
| 32 | { |
| 33 | private: |
| 34 | Thread *m_pThread; // Current thread pointer |
| 35 | // Have to override this function in any derived class to indicate that a valid destructor is defined for this class |
| 36 | virtual void DestructorDefinedThatCallsRestore(){} |
| 37 | |
| 38 | public: |
| 39 | __declspec(nothrow) ~EEContract() |
| 40 | { |
| 41 | Restore(); |
| 42 | } |
| 43 | |
| 44 | void Disable(); |
| 45 | void DoChecks(UINT testmask, __in_z const char *szFunction, __in_z const char *szFile, int lineNum); |
| 46 | }; |
| 47 | |
| 48 | |
| 49 | |
| 50 | #define MODE_COOPERATIVE do { STATIC_CONTRACT_MODE_COOPERATIVE; REQUEST_TEST(Contract::MODE_Coop, Contract::MODE_Disabled); } while(0) |
| 51 | #define MODE_PREEMPTIVE do { STATIC_CONTRACT_MODE_PREEMPTIVE; REQUEST_TEST(Contract::MODE_Preempt, Contract::MODE_Disabled); } while(0) |
| 52 | #define MODE_ANY do { STATIC_CONTRACT_MODE_ANY; REQUEST_TEST(Contract::MODE_Disabled, Contract::MODE_Disabled); } while(0) |
| 53 | |
| 54 | #define GC_TRIGGERS do { STATIC_CONTRACT_GC_TRIGGERS; REQUEST_TEST(Contract::GC_Triggers, Contract::GC_Disabled); } while(0) |
| 55 | #define GC_NOTRIGGER do { STATIC_CONTRACT_GC_NOTRIGGER; REQUEST_TEST(Contract::GC_NoTrigger, Contract::GC_Disabled); } while(0) |
| 56 | |
| 57 | // Notice there's no static contract component to this. It's |
| 58 | // perfectly reasonable to find EE_THREAD_REQUIRED inside the scope of |
| 59 | // EE_THREAD_NOT_REQUIRED (e.g., an EE_THREAD_NOT_REQUIRED scope can have two |
| 60 | // possible code paths--one with an EE Thread and one without). So we can't do |
| 61 | // any meaningful testing statically. It's all gotta be done at runtime. |
| 62 | #define EE_THREAD_NOT_REQUIRED \ |
| 63 | do { REQUEST_TEST(Contract::EE_THREAD_Not_Required, Contract::EE_THREAD_Disabled); } while(0) |
| 64 | |
| 65 | #define EE_THREAD_REQUIRED do { REQUEST_TEST(Contract::EE_THREAD_Required, Contract::EE_THREAD_Disabled); } while(0) |
| 66 | |
| 67 | #define HOST_NOCALLS do { STATIC_CONTRACT_HOST_NOCALLS; REQUEST_TEST(Contract::HOST_NoCalls, Contract::HOST_Disabled); } while(0) |
| 68 | #define HOST_CALLS do { STATIC_CONTRACT_HOST_CALLS; REQUEST_TEST(Contract::HOST_Calls, Contract::HOST_Disabled); } while(0) |
| 69 | |
| 70 | #else // ENABLE_CONTRACTS_IMPL |
| 71 | |
| 72 | #define MODE_COOPERATIVE |
| 73 | #define MODE_PREEMPTIVE |
| 74 | #define MODE_ANY |
| 75 | #define GC_TRIGGERS |
| 76 | #define GC_NOTRIGGER |
| 77 | #define HOST_NOCALLS |
| 78 | #define HOST_CALLS |
| 79 | #define EE_THREAD_NOT_REQUIRED |
| 80 | #define EE_THREAD_REQUIRED |
| 81 | |
| 82 | |
| 83 | #endif // ENABLE_CONTRACTS_IMPL |
| 84 | |
| 85 | // Replace the CONTRACT macro with the EE version |
| 86 | #undef CONTRACT |
| 87 | #define CONTRACT(_returntype) CUSTOM_CONTRACT(EEContract, _returntype) |
| 88 | |
| 89 | #undef CONTRACT_VOID |
| 90 | #define CONTRACT_VOID CUSTOM_CONTRACT_VOID(EEContract) |
| 91 | |
| 92 | #undef CONTRACTL |
| 93 | #define CONTRACTL CUSTOM_CONTRACTL(EEContract) |
| 94 | |
| 95 | #undef LIMITED_METHOD_CONTRACT |
| 96 | #define LIMITED_METHOD_CONTRACT CUSTOM_LIMITED_METHOD_CONTRACT(EEContract) |
| 97 | |
| 98 | #undef WRAPPER_NO_CONTRACT |
| 99 | #define WRAPPER_NO_CONTRACT CUSTOM_WRAPPER_NO_CONTRACT(EEContract) |
| 100 | |
| 101 | // |
| 102 | // The default contract is the recommended contract for ordinary EE code. |
| 103 | // The ordinary EE code can throw or trigger GC any time, does not operate |
| 104 | // on raw object refs, etc. |
| 105 | // |
| 106 | |
| 107 | #undef STANDARD_VM_CHECK |
| 108 | #define STANDARD_VM_CHECK \ |
| 109 | THROWS; \ |
| 110 | GC_TRIGGERS; \ |
| 111 | MODE_PREEMPTIVE; \ |
| 112 | SO_INTOLERANT; \ |
| 113 | INJECT_FAULT(COMPlusThrowOM();); \ |
| 114 | |
| 115 | #endif // EECONTRACT_H_ |
| 116 | |