summaryrefslogtreecommitdiff
path: root/src/inc/eexcp.h
blob: b91522b4d80d36726148434885efb714c86cb72d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// 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 __eexcp_h__
#define __eexcp_h__

#include "corhlpr.h"
#include "daccess.h"

struct EE_ILEXCEPTION_CLAUSE;
typedef DPTR(EE_ILEXCEPTION_CLAUSE) PTR_EE_ILEXCEPTION_CLAUSE;

// The exception handling sub-system needs to keep track of EH clause that is handling given exception.
// PTR_EXCEPTION_CLAUSE_TOKEN is opaque pointer that uniquely identifies
// exception handling clause. It abstracts away encoding differences of EH clauses between JIT and NGen.
typedef PTR_VOID PTR_EXCEPTION_CLAUSE_TOKEN;

struct EE_ILEXCEPTION_CLAUSE  {
    //Flags is not marked as volatile since it is always accessed
    //    from within a critical section
    CorExceptionFlag    Flags;  
    DWORD               TryStartPC;    
    DWORD               TryEndPC;
    DWORD               HandlerStartPC;  
    DWORD               HandlerEndPC;  
    union {
        void*           TypeHandle; 
        mdToken         ClassToken;
        DWORD           FilterOffset;
    };  
};

struct EE_ILEXCEPTION;
typedef DPTR(EE_ILEXCEPTION) PTR_EE_ILEXCEPTION;

struct EE_ILEXCEPTION : public COR_ILMETHOD_SECT_FAT 
{
    EE_ILEXCEPTION_CLAUSE Clauses[1];     // actually variable size

    void Init(unsigned ehCount) 
    {
        LIMITED_METHOD_CONTRACT;

        SetKind(CorILMethod_Sect_FatFormat);
        SetDataSize((unsigned)sizeof(EE_ILEXCEPTION_CLAUSE) * ehCount); 
    }

    unsigned EHCount() const 
    {
        LIMITED_METHOD_CONTRACT;

        return GetDataSize() / (DWORD) sizeof(EE_ILEXCEPTION_CLAUSE);
    }

    static unsigned Size(unsigned ehCount)
    {
        LIMITED_METHOD_CONTRACT;

        _ASSERTE(ehCount > 0);

        return (offsetof(EE_ILEXCEPTION, Clauses) + sizeof(EE_ILEXCEPTION_CLAUSE) * ehCount);
    }
    EE_ILEXCEPTION_CLAUSE *EHClause(unsigned i) 
    {
        LIMITED_METHOD_DAC_CONTRACT;
        return &(PTR_EE_ILEXCEPTION_CLAUSE(PTR_HOST_MEMBER_TADDR(EE_ILEXCEPTION,this,Clauses))[i]);
    }
};

#define COR_ILEXCEPTION_CLAUSE_CACHED_CLASS     0x10000000

inline BOOL HasCachedTypeHandle(EE_ILEXCEPTION_CLAUSE *EHClause)
{
    _ASSERTE(sizeof(EHClause->Flags) == sizeof(DWORD));
    return (EHClause->Flags & COR_ILEXCEPTION_CLAUSE_CACHED_CLASS);
}

inline void SetHasCachedTypeHandle(EE_ILEXCEPTION_CLAUSE *EHClause)
{
    _ASSERTE(! HasCachedTypeHandle(EHClause));
    EHClause->Flags = (CorExceptionFlag)(EHClause->Flags | COR_ILEXCEPTION_CLAUSE_CACHED_CLASS);
}

inline BOOL IsFinally(EE_ILEXCEPTION_CLAUSE *EHClause)
{
    LIMITED_METHOD_CONTRACT;

    return (EHClause->Flags & COR_ILEXCEPTION_CLAUSE_FINALLY);
}

inline BOOL IsFault(EE_ILEXCEPTION_CLAUSE *EHClause)
{
    LIMITED_METHOD_CONTRACT;

    return (EHClause->Flags & COR_ILEXCEPTION_CLAUSE_FAULT);
}

inline BOOL IsFaultOrFinally(EE_ILEXCEPTION_CLAUSE *EHClause)
{
    return IsFault(EHClause) || IsFinally(EHClause);
}

inline BOOL IsFilterHandler(EE_ILEXCEPTION_CLAUSE *EHClause)
{
    LIMITED_METHOD_CONTRACT;

    return EHClause->Flags & COR_ILEXCEPTION_CLAUSE_FILTER;
}

inline BOOL IsTypedHandler(EE_ILEXCEPTION_CLAUSE *EHClause)
{
    return ! (IsFilterHandler(EHClause) || IsFaultOrFinally(EHClause));
}

inline BOOL IsDuplicateClause(EE_ILEXCEPTION_CLAUSE* pEHClause)
{
    return pEHClause->Flags & COR_ILEXCEPTION_CLAUSE_DUPLICATED;
}

#if defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)
// Finally is the only EH construct that can be part of the execution as being fall-through.
//
// "Cloned" finally is a contruct that represents a finally block that is used as
// fall through for normal try-block execution. Such a "cloned" finally will:
// 
// 1) Have its try-clause's Start and End PC the same as its handler's start PC (i.e. will have
//    zero length try block), AND
// 2) Is marked duplicate
//
// Because of their fall-through nature, JIT guarantees that only finally constructs can be cloned,
// and not catch or fault (since they cannot be fallen through but are invoked as funclets).
// 
// The cloned finally construct is also used to mark "call to finally" thunks that are not within
// the EH region protected by the finally, and also not within the enclosing region. This is done
// to prevent ThreadAbortException from creating an infinite loop of calling the same finally.
inline BOOL IsClonedFinally(EE_ILEXCEPTION_CLAUSE* pEHClause)
{
    return ((pEHClause->TryStartPC == pEHClause->TryEndPC) &&
            (pEHClause->TryStartPC == pEHClause->HandlerStartPC) &&
            IsFinally(pEHClause) && IsDuplicateClause(pEHClause));
}
#endif // defined(_TARGET_AMD64_) || defined(_TARGET_ARM64_)

#endif // __eexcp_h__