1 //===----- Thunk.h - Declarations related to VTable Thunks ------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// Enums/classes describing THUNK related information about constructors,
11 /// destructors and thunks.
12 ///
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_CLANG_BASIC_THUNK_H
16 #define LLVM_CLANG_BASIC_THUNK_H
17 
18 #include <cstdint>
19 #include <cstring>
20 
21 namespace clang {
22 
23 class CXXMethodDecl;
24 
25 /// A return adjustment.
26 struct ReturnAdjustment {
27   /// The non-virtual adjustment from the derived object to its
28   /// nearest virtual base.
29   int64_t NonVirtual;
30 
31   /// Holds the ABI-specific information about the virtual return
32   /// adjustment, if needed.
33   union VirtualAdjustment {
34     // Itanium ABI
35     struct {
36       /// The offset (in bytes), relative to the address point
37       /// of the virtual base class offset.
38       int64_t VBaseOffsetOffset;
39     } Itanium;
40 
41     // Microsoft ABI
42     struct {
43       /// The offset (in bytes) of the vbptr, relative to the beginning
44       /// of the derived class.
45       uint32_t VBPtrOffset;
46 
47       /// Index of the virtual base in the vbtable.
48       uint32_t VBIndex;
49     } Microsoft;
50 
51     VirtualAdjustment() { memset(this, 0, sizeof(*this)); }
52 
53     bool Equals(const VirtualAdjustment &Other) const {
54       return memcmp(this, &Other, sizeof(Other)) == 0;
55     }
56 
57     bool isEmpty() const {
58       VirtualAdjustment Zero;
59       return Equals(Zero);
60     }
61 
62     bool Less(const VirtualAdjustment &RHS) const {
63       return memcmp(this, &RHS, sizeof(RHS)) < 0;
64     }
65   } Virtual;
66 
67   ReturnAdjustment() : NonVirtual(0) {}
68 
69   bool isEmpty() const { return !NonVirtual && Virtual.isEmpty(); }
70 
71   friend bool operator==(const ReturnAdjustment &LHS,
72                          const ReturnAdjustment &RHS) {
73     return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Equals(RHS.Virtual);
74   }
75 
76   friend bool operator!=(const ReturnAdjustment &LHS,
77                          const ReturnAdjustment &RHS) {
78     return !(LHS == RHS);
79   }
80 
81   friend bool operator<(const ReturnAdjustment &LHS,
82                         const ReturnAdjustment &RHS) {
83     if (LHS.NonVirtual < RHS.NonVirtual)
84       return true;
85 
86     return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Less(RHS.Virtual);
87   }
88 };
89 
90 /// A \c this pointer adjustment.
91 struct ThisAdjustment {
92   /// The non-virtual adjustment from the derived object to its
93   /// nearest virtual base.
94   int64_t NonVirtual;
95 
96   /// Holds the ABI-specific information about the virtual this
97   /// adjustment, if needed.
98   union VirtualAdjustment {
99     // Itanium ABI
100     struct {
101       /// The offset (in bytes), relative to the address point,
102       /// of the virtual call offset.
103       int64_t VCallOffsetOffset;
104     } Itanium;
105 
106     struct {
107       /// The offset of the vtordisp (in bytes), relative to the ECX.
108       int32_t VtordispOffset;
109 
110       /// The offset of the vbptr of the derived class (in bytes),
111       /// relative to the ECX after vtordisp adjustment.
112       int32_t VBPtrOffset;
113 
114       /// The offset (in bytes) of the vbase offset in the vbtable.
115       int32_t VBOffsetOffset;
116     } Microsoft;
117 
118     VirtualAdjustment() { memset(this, 0, sizeof(*this)); }
119 
120     bool Equals(const VirtualAdjustment &Other) const {
121       return memcmp(this, &Other, sizeof(Other)) == 0;
122     }
123 
124     bool isEmpty() const {
125       VirtualAdjustment Zero;
126       return Equals(Zero);
127     }
128 
129     bool Less(const VirtualAdjustment &RHS) const {
130       return memcmp(this, &RHS, sizeof(RHS)) < 0;
131     }
132   } Virtual;
133 
134   ThisAdjustment() : NonVirtual(0) {}
135 
136   bool isEmpty() const { return !NonVirtual && Virtual.isEmpty(); }
137 
138   friend bool operator==(const ThisAdjustment &LHS, const ThisAdjustment &RHS) {
139     return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Equals(RHS.Virtual);
140   }
141 
142   friend bool operator!=(const ThisAdjustment &LHS, const ThisAdjustment &RHS) {
143     return !(LHS == RHS);
144   }
145 
146   friend bool operator<(const ThisAdjustment &LHS, const ThisAdjustment &RHS) {
147     if (LHS.NonVirtual < RHS.NonVirtual)
148       return true;
149 
150     return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Less(RHS.Virtual);
151   }
152 };
153 
154 /// The \c this pointer adjustment as well as an optional return
155 /// adjustment for a thunk.
156 struct ThunkInfo {
157   /// The \c this pointer adjustment.
158   ThisAdjustment This;
159 
160   /// The return adjustment.
161   ReturnAdjustment Return;
162 
163   /// Holds a pointer to the overridden method this thunk is for,
164   /// if needed by the ABI to distinguish different thunks with equal
165   /// adjustments. Otherwise, null.
166   /// CAUTION: In the unlikely event you need to sort ThunkInfos, consider using
167   /// an ABI-specific comparator.
168   const CXXMethodDecl *Method;
169 
170   ThunkInfo() : Method(nullptr) {}
171 
172   ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return,
173             const CXXMethodDecl *Method = nullptr)
174       : This(This), Return(Return), Method(Method) {}
175 
176   friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) {
177     return LHS.This == RHS.This && LHS.Return == RHS.Return &&
178            LHS.Method == RHS.Method;
179   }
180 
181   bool isEmpty() const {
182     return This.isEmpty() && Return.isEmpty() && Method == nullptr;
183   }
184 };
185 
186 } // end namespace clang
187 
188 #endif
189