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
21namespace clang {
22
23class CXXMethodDecl;
24class Type;
25
26/// A return adjustment.
27struct ReturnAdjustment {
28 /// The non-virtual adjustment from the derived object to its
29 /// nearest virtual base.
30 int64_t NonVirtual = 0;
31
32 /// Holds the ABI-specific information about the virtual return
33 /// adjustment, if needed.
34 union VirtualAdjustment {
35 // Itanium ABI
36 struct {
37 /// The offset (in bytes), relative to the address point
38 /// of the virtual base class offset.
39 int64_t VBaseOffsetOffset;
40 } Itanium;
41
42 // Microsoft ABI
43 struct {
44 /// The offset (in bytes) of the vbptr, relative to the beginning
45 /// of the derived class.
46 uint32_t VBPtrOffset;
47
48 /// Index of the virtual base in the vbtable.
49 uint32_t VBIndex;
50 } Microsoft;
51
52 VirtualAdjustment() { memset(s: this, c: 0, n: sizeof(*this)); }
53
54 bool Equals(const VirtualAdjustment &Other) const {
55 return memcmp(s1: this, s2: &Other, n: sizeof(Other)) == 0;
56 }
57
58 bool isEmpty() const {
59 VirtualAdjustment Zero;
60 return Equals(Other: Zero);
61 }
62
63 bool Less(const VirtualAdjustment &RHS) const {
64 return memcmp(s1: this, s2: &RHS, n: sizeof(RHS)) < 0;
65 }
66 } Virtual;
67
68 ReturnAdjustment() = default;
69
70 bool isEmpty() const { return !NonVirtual && Virtual.isEmpty(); }
71
72 friend bool operator==(const ReturnAdjustment &LHS,
73 const ReturnAdjustment &RHS) {
74 return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Equals(Other: RHS.Virtual);
75 }
76
77 friend bool operator!=(const ReturnAdjustment &LHS,
78 const ReturnAdjustment &RHS) {
79 return !(LHS == RHS);
80 }
81
82 friend bool operator<(const ReturnAdjustment &LHS,
83 const ReturnAdjustment &RHS) {
84 if (LHS.NonVirtual < RHS.NonVirtual)
85 return true;
86
87 return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Less(RHS: RHS.Virtual);
88 }
89};
90
91/// A \c this pointer adjustment.
92struct ThisAdjustment {
93 /// The non-virtual adjustment from the derived object to its
94 /// nearest virtual base.
95 int64_t NonVirtual = 0;
96
97 /// Holds the ABI-specific information about the virtual this
98 /// adjustment, if needed.
99 union VirtualAdjustment {
100 // Itanium ABI
101 struct {
102 /// The offset (in bytes), relative to the address point,
103 /// of the virtual call offset.
104 int64_t VCallOffsetOffset;
105 } Itanium;
106
107 struct {
108 /// The offset of the vtordisp (in bytes), relative to the ECX.
109 int32_t VtordispOffset;
110
111 /// The offset of the vbptr of the derived class (in bytes),
112 /// relative to the ECX after vtordisp adjustment.
113 int32_t VBPtrOffset;
114
115 /// The offset (in bytes) of the vbase offset in the vbtable.
116 int32_t VBOffsetOffset;
117 } Microsoft;
118
119 VirtualAdjustment() { memset(s: this, c: 0, n: sizeof(*this)); }
120
121 bool Equals(const VirtualAdjustment &Other) const {
122 return memcmp(s1: this, s2: &Other, n: sizeof(Other)) == 0;
123 }
124
125 bool isEmpty() const {
126 VirtualAdjustment Zero;
127 return Equals(Other: Zero);
128 }
129
130 bool Less(const VirtualAdjustment &RHS) const {
131 return memcmp(s1: this, s2: &RHS, n: sizeof(RHS)) < 0;
132 }
133 } Virtual;
134
135 ThisAdjustment() = default;
136
137 bool isEmpty() const { return !NonVirtual && Virtual.isEmpty(); }
138
139 friend bool operator==(const ThisAdjustment &LHS, const ThisAdjustment &RHS) {
140 return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Equals(Other: RHS.Virtual);
141 }
142
143 friend bool operator!=(const ThisAdjustment &LHS, const ThisAdjustment &RHS) {
144 return !(LHS == RHS);
145 }
146
147 friend bool operator<(const ThisAdjustment &LHS, const ThisAdjustment &RHS) {
148 if (LHS.NonVirtual < RHS.NonVirtual)
149 return true;
150
151 return LHS.NonVirtual == RHS.NonVirtual && LHS.Virtual.Less(RHS: RHS.Virtual);
152 }
153};
154
155/// The \c this pointer adjustment as well as an optional return
156/// adjustment for a thunk.
157struct ThunkInfo {
158 /// The \c this pointer adjustment.
159 ThisAdjustment This;
160
161 /// The return adjustment.
162 ReturnAdjustment Return;
163
164 /// Holds a pointer to the overridden method this thunk is for,
165 /// if needed by the ABI to distinguish different thunks with equal
166 /// adjustments.
167 /// In the Itanium ABI, this field can hold the method that created the
168 /// vtable entry for this thunk.
169 /// Otherwise, null.
170 /// CAUTION: In the unlikely event you need to sort ThunkInfos, consider using
171 /// an ABI-specific comparator.
172 const CXXMethodDecl *Method;
173 const Type *ThisType;
174
175 ThunkInfo() : Method(nullptr), ThisType(nullptr) {}
176
177 ThunkInfo(const ThisAdjustment &This, const ReturnAdjustment &Return,
178 const Type *ThisT, const CXXMethodDecl *Method = nullptr)
179 : This(This), Return(Return), Method(Method), ThisType(ThisT) {}
180
181 friend bool operator==(const ThunkInfo &LHS, const ThunkInfo &RHS) {
182 return LHS.This == RHS.This && LHS.Return == RHS.Return &&
183 LHS.Method == RHS.Method && LHS.ThisType == RHS.ThisType;
184 }
185
186 bool isEmpty() const {
187 return This.isEmpty() && Return.isEmpty() && Method == nullptr;
188 }
189};
190
191} // end namespace clang
192
193#endif
194