blob: 0844f52f2b040086a37ed4c2ed24e3b68c567735 [file] [log] [blame]
Anders Carlsson2bb27f52009-10-11 22:13:54 +00001//===--- CGVtable.cpp - Emit LLVM Code for C++ vtables --------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This contains code dealing with C++ code generation of virtual tables.
11//
12//===----------------------------------------------------------------------===//
13
14#include "CodeGenModule.h"
15#include "CodeGenFunction.h"
16
17#include "clang/AST/RecordLayout.h"
18
19using namespace clang;
20using namespace CodeGen;
21
22class VtableBuilder {
23public:
24 /// Index_t - Vtable index type.
25 typedef uint64_t Index_t;
26private:
27 std::vector<llvm::Constant *> &methods;
28 std::vector<llvm::Constant *> submethods;
29 llvm::Type *Ptr8Ty;
30 /// Class - The most derived class that this vtable is being built for.
31 const CXXRecordDecl *Class;
32 /// BLayout - Layout for the most derived class that this vtable is being
33 /// built for.
34 const ASTRecordLayout &BLayout;
35 llvm::SmallSet<const CXXRecordDecl *, 32> IndirectPrimary;
36 llvm::SmallSet<const CXXRecordDecl *, 32> SeenVBase;
37 llvm::Constant *rtti;
38 llvm::LLVMContext &VMContext;
39 CodeGenModule &CGM; // Per-module state.
40 /// Index - Maps a method decl into a vtable index. Useful for virtual
41 /// dispatch codegen.
42 llvm::DenseMap<const CXXMethodDecl *, Index_t> Index;
43 llvm::DenseMap<const CXXMethodDecl *, Index_t> VCall;
44 llvm::DenseMap<const CXXMethodDecl *, Index_t> VCallOffset;
Mike Stumpcd6f9ed2009-11-06 23:27:42 +000045 // This is the offset to the nearest virtual base
46 llvm::DenseMap<const CXXMethodDecl *, Index_t> NonVirtualOffset;
Anders Carlsson2bb27f52009-10-11 22:13:54 +000047 llvm::DenseMap<const CXXRecordDecl *, Index_t> VBIndex;
Mike Stumpbb9ff052009-10-27 23:46:47 +000048
49 typedef llvm::DenseMap<const CXXMethodDecl *, int> Pures_t;
50 Pures_t Pures;
Anders Carlsson2bb27f52009-10-11 22:13:54 +000051 typedef std::pair<Index_t, Index_t> CallOffset;
52 typedef llvm::DenseMap<const CXXMethodDecl *, CallOffset> Thunks_t;
53 Thunks_t Thunks;
54 typedef llvm::DenseMap<const CXXMethodDecl *,
Mike Stump87876a02009-10-13 10:55:21 +000055 std::pair<std::pair<CallOffset, CallOffset>,
56 CanQualType> > CovariantThunks_t;
Anders Carlsson2bb27f52009-10-11 22:13:54 +000057 CovariantThunks_t CovariantThunks;
58 std::vector<Index_t> VCalls;
Mike Stump2cefe382009-11-12 20:47:57 +000059
60 typedef std::pair<const CXXRecordDecl *, uint64_t> CtorVtable_t;
61 // CtorVtable - Used to hold the AddressPoints (offsets) into the built vtable
62 // for use in computing the initializers for the VTT.
63 llvm::DenseMap<CtorVtable_t, int64_t> &AddressPoints;
64
Anders Carlsson2bb27f52009-10-11 22:13:54 +000065 typedef CXXRecordDecl::method_iterator method_iter;
66 // FIXME: Linkage should follow vtable
67 const bool Extern;
68 const uint32_t LLVMPointerWidth;
69 Index_t extra;
Mike Stump37dbe962009-10-15 02:04:03 +000070 typedef std::vector<std::pair<const CXXRecordDecl *, int64_t> > Path_t;
Mike Stumpbb9ff052009-10-27 23:46:47 +000071 llvm::Constant *cxa_pure;
Anders Carlsson2bb27f52009-10-11 22:13:54 +000072public:
73 VtableBuilder(std::vector<llvm::Constant *> &meth,
74 const CXXRecordDecl *c,
75 CodeGenModule &cgm)
76 : methods(meth), Class(c), BLayout(cgm.getContext().getASTRecordLayout(c)),
77 rtti(cgm.GenerateRtti(c)), VMContext(cgm.getModule().getContext()),
Mike Stump2cefe382009-11-12 20:47:57 +000078 CGM(cgm), AddressPoints(*new llvm::DenseMap<CtorVtable_t, int64_t>),
79 Extern(true),
Mike Stumpcd6f9ed2009-11-06 23:27:42 +000080 LLVMPointerWidth(cgm.getContext().Target.getPointerWidth(0)) {
Anders Carlsson2bb27f52009-10-11 22:13:54 +000081 Ptr8Ty = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
Mike Stump375faa82009-10-28 00:35:46 +000082
83 // Calculate pointer for ___cxa_pure_virtual.
84 const llvm::FunctionType *FTy;
85 std::vector<const llvm::Type*> ArgTys;
86 const llvm::Type *ResultType = llvm::Type::getVoidTy(VMContext);
87 FTy = llvm::FunctionType::get(ResultType, ArgTys, false);
88 cxa_pure = wrap(CGM.CreateRuntimeFunction(FTy, "__cxa_pure_virtual"));
Anders Carlsson2bb27f52009-10-11 22:13:54 +000089 }
90
91 llvm::DenseMap<const CXXMethodDecl *, Index_t> &getIndex() { return Index; }
92 llvm::DenseMap<const CXXRecordDecl *, Index_t> &getVBIndex()
93 { return VBIndex; }
94
Mike Stump2cefe382009-11-12 20:47:57 +000095 llvm::DenseMap<CtorVtable_t, int64_t> *getAddressPoints()
96 { return &AddressPoints; }
97
Anders Carlsson2bb27f52009-10-11 22:13:54 +000098 llvm::Constant *wrap(Index_t i) {
99 llvm::Constant *m;
100 m = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext), i);
101 return llvm::ConstantExpr::getIntToPtr(m, Ptr8Ty);
102 }
103
104 llvm::Constant *wrap(llvm::Constant *m) {
105 return llvm::ConstantExpr::getBitCast(m, Ptr8Ty);
106 }
107
Mike Stump75ce5732009-10-31 20:06:59 +0000108#define D1(x)
109//#define D1(X) do { if (getenv("DEBUG")) { X; } } while (0)
110
111 void GenerateVBaseOffsets(const CXXRecordDecl *RD, uint64_t Offset,
Mike Stump28431212009-10-13 22:54:56 +0000112 bool updateVBIndex, Index_t current_vbindex) {
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000113 for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
114 e = RD->bases_end(); i != e; ++i) {
115 const CXXRecordDecl *Base =
116 cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
Mike Stump28431212009-10-13 22:54:56 +0000117 Index_t next_vbindex = current_vbindex;
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000118 if (i->isVirtual() && !SeenVBase.count(Base)) {
119 SeenVBase.insert(Base);
Mike Stump28431212009-10-13 22:54:56 +0000120 if (updateVBIndex) {
Mike Stump75ce5732009-10-31 20:06:59 +0000121 next_vbindex = (ssize_t)(-(VCalls.size()*LLVMPointerWidth/8)
Mike Stump28431212009-10-13 22:54:56 +0000122 - 3*LLVMPointerWidth/8);
123 VBIndex[Base] = next_vbindex;
124 }
Mike Stump75ce5732009-10-31 20:06:59 +0000125 int64_t BaseOffset = -(Offset/8) + BLayout.getVBaseClassOffset(Base)/8;
126 VCalls.push_back((0?700:0) + BaseOffset);
127 D1(printf(" vbase for %s at %d delta %d most derived %s\n",
128 Base->getNameAsCString(),
129 (int)-VCalls.size()-3, (int)BaseOffset,
130 Class->getNameAsCString()));
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000131 }
Mike Stump28431212009-10-13 22:54:56 +0000132 // We also record offsets for non-virtual bases to closest enclosing
133 // virtual base. We do this so that we don't have to search
134 // for the nearst virtual base class when generating thunks.
135 if (updateVBIndex && VBIndex.count(Base) == 0)
136 VBIndex[Base] = next_vbindex;
Mike Stump75ce5732009-10-31 20:06:59 +0000137 GenerateVBaseOffsets(Base, Offset, updateVBIndex, next_vbindex);
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000138 }
139 }
140
141 void StartNewTable() {
142 SeenVBase.clear();
143 }
144
145 Index_t VBlookup(CXXRecordDecl *D, CXXRecordDecl *B);
146
Mike Stump8bccbfd2009-10-15 09:30:16 +0000147 Index_t getNVOffset_1(const CXXRecordDecl *D, const CXXRecordDecl *B,
148 Index_t Offset = 0) {
149
150 if (B == D)
151 return Offset;
152
153 const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(D);
154 for (CXXRecordDecl::base_class_const_iterator i = D->bases_begin(),
155 e = D->bases_end(); i != e; ++i) {
156 const CXXRecordDecl *Base =
157 cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
158 int64_t BaseOffset = 0;
159 if (!i->isVirtual())
160 BaseOffset = Offset + Layout.getBaseClassOffset(Base);
161 int64_t o = getNVOffset_1(Base, B, BaseOffset);
162 if (o >= 0)
163 return o;
164 }
165
166 return -1;
167 }
168
169 /// getNVOffset - Returns the non-virtual offset for the given (B) base of the
170 /// derived class D.
171 Index_t getNVOffset(QualType qB, QualType qD) {
Mike Stump46271322009-11-03 19:03:17 +0000172 qD = qD->getPointeeType();
173 qB = qB->getPointeeType();
Mike Stump8bccbfd2009-10-15 09:30:16 +0000174 CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl());
175 CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl());
176 int64_t o = getNVOffset_1(D, B);
177 if (o >= 0)
178 return o;
179
180 assert(false && "FIXME: non-virtual base not found");
181 return 0;
182 }
183
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000184 /// getVbaseOffset - Returns the index into the vtable for the virtual base
185 /// offset for the given (B) virtual base of the derived class D.
186 Index_t getVbaseOffset(QualType qB, QualType qD) {
Mike Stump46271322009-11-03 19:03:17 +0000187 qD = qD->getPointeeType();
188 qB = qB->getPointeeType();
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000189 CXXRecordDecl *D = cast<CXXRecordDecl>(qD->getAs<RecordType>()->getDecl());
190 CXXRecordDecl *B = cast<CXXRecordDecl>(qB->getAs<RecordType>()->getDecl());
191 if (D != Class)
192 return VBlookup(D, B);
193 llvm::DenseMap<const CXXRecordDecl *, Index_t>::iterator i;
194 i = VBIndex.find(B);
195 if (i != VBIndex.end())
196 return i->second;
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000197
Mike Stump28431212009-10-13 22:54:56 +0000198 assert(false && "FIXME: Base not found");
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000199 return 0;
200 }
201
202 bool OverrideMethod(const CXXMethodDecl *MD, llvm::Constant *m,
Mike Stump8bccbfd2009-10-15 09:30:16 +0000203 bool MorallyVirtual, Index_t OverrideOffset,
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000204 Index_t Offset, int64_t CurrentVBaseOffset) {
Mike Stump375faa82009-10-28 00:35:46 +0000205 const bool isPure = MD->isPure();
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000206 typedef CXXMethodDecl::method_iterator meth_iter;
Mike Stump8bccbfd2009-10-15 09:30:16 +0000207 // FIXME: Should OverrideOffset's be Offset?
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000208
209 // FIXME: Don't like the nested loops. For very large inheritance
210 // heirarchies we could have a table on the side with the final overridder
211 // and just replace each instance of an overridden method once. Would be
212 // nice to measure the cost/benefit on real code.
213
214 for (meth_iter mi = MD->begin_overridden_methods(),
215 e = MD->end_overridden_methods();
216 mi != e; ++mi) {
217 const CXXMethodDecl *OMD = *mi;
218 llvm::Constant *om;
219 om = CGM.GetAddrOfFunction(OMD, Ptr8Ty);
220 om = llvm::ConstantExpr::getBitCast(om, Ptr8Ty);
221
222 for (Index_t i = 0, e = submethods.size();
223 i != e; ++i) {
224 // FIXME: begin_overridden_methods might be too lax, covariance */
225 if (submethods[i] != om)
226 continue;
227 QualType nc_oret = OMD->getType()->getAs<FunctionType>()->getResultType();
228 CanQualType oret = CGM.getContext().getCanonicalType(nc_oret);
229 QualType nc_ret = MD->getType()->getAs<FunctionType>()->getResultType();
230 CanQualType ret = CGM.getContext().getCanonicalType(nc_ret);
231 CallOffset ReturnOffset = std::make_pair(0, 0);
232 if (oret != ret) {
233 // FIXME: calculate offsets for covariance
Mike Stump87876a02009-10-13 10:55:21 +0000234 if (CovariantThunks.count(OMD)) {
235 oret = CovariantThunks[OMD].second;
236 CovariantThunks.erase(OMD);
237 }
Mike Stump8bccbfd2009-10-15 09:30:16 +0000238 // FIXME: Double check oret
239 Index_t nv = getNVOffset(oret, ret)/8;
Mike Stump87876a02009-10-13 10:55:21 +0000240 ReturnOffset = std::make_pair(nv, getVbaseOffset(oret, ret));
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000241 }
242 Index[MD] = i;
243 submethods[i] = m;
Mike Stump375faa82009-10-28 00:35:46 +0000244 if (isPure)
245 Pures[MD] = 1;
246 Pures.erase(OMD);
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000247 Thunks.erase(OMD);
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000248 if (MorallyVirtual || VCall.count(OMD)) {
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000249 Index_t &idx = VCall[OMD];
250 if (idx == 0) {
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000251 NonVirtualOffset[MD] = -OverrideOffset/8 + CurrentVBaseOffset/8;
Mike Stump8bccbfd2009-10-15 09:30:16 +0000252 VCallOffset[MD] = OverrideOffset/8;
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000253 idx = VCalls.size()+1;
254 VCalls.push_back(0);
Mike Stump75ce5732009-10-31 20:06:59 +0000255 D1(printf(" vcall for %s at %d with delta %d most derived %s\n",
Mike Stump72431bd2009-11-06 02:38:24 +0000256 MD->getNameAsCString(), (int)-idx-3, (int)VCalls[idx-1],
Mike Stump75ce5732009-10-31 20:06:59 +0000257 Class->getNameAsCString()));
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000258 } else {
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000259 NonVirtualOffset[MD] = NonVirtualOffset[OMD];
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000260 VCallOffset[MD] = VCallOffset[OMD];
Mike Stump8bccbfd2009-10-15 09:30:16 +0000261 VCalls[idx-1] = -VCallOffset[OMD] + OverrideOffset/8;
Mike Stump75ce5732009-10-31 20:06:59 +0000262 D1(printf(" vcall patch for %s at %d with delta %d most derived %s\n",
Mike Stump72431bd2009-11-06 02:38:24 +0000263 MD->getNameAsCString(), (int)-idx-3, (int)VCalls[idx-1],
Mike Stump75ce5732009-10-31 20:06:59 +0000264 Class->getNameAsCString()));
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000265 }
266 VCall[MD] = idx;
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000267 int64_t O = NonVirtualOffset[MD];
268 int v = -((idx+extra+2)*LLVMPointerWidth/8);
269 // Optimize out virtual adjustments of 0.
270 if (VCalls[idx-1] == 0)
271 v = 0;
272 CallOffset ThisOffset = std::make_pair(O, v);
Mike Stump37dbe962009-10-15 02:04:03 +0000273 // FIXME: Do we always have to build a covariant thunk to save oret,
274 // which is the containing virtual base class?
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000275 if (ReturnOffset.first || ReturnOffset.second)
Mike Stump87876a02009-10-13 10:55:21 +0000276 CovariantThunks[MD] = std::make_pair(std::make_pair(ThisOffset,
277 ReturnOffset),
278 oret);
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000279 else if (!isPure && (ThisOffset.first || ThisOffset.second))
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000280 Thunks[MD] = ThisOffset;
281 return true;
282 }
Mike Stump28431212009-10-13 22:54:56 +0000283
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000284 // FIXME: finish off
Mike Stump8bccbfd2009-10-15 09:30:16 +0000285 int64_t O = VCallOffset[OMD] - OverrideOffset/8;
Mike Stump72431bd2009-11-06 02:38:24 +0000286
Mike Stump28431212009-10-13 22:54:56 +0000287 if (O || ReturnOffset.first || ReturnOffset.second) {
288 CallOffset ThisOffset = std::make_pair(O, 0);
289
290 if (ReturnOffset.first || ReturnOffset.second)
291 CovariantThunks[MD] = std::make_pair(std::make_pair(ThisOffset,
292 ReturnOffset),
293 oret);
Mike Stump375faa82009-10-28 00:35:46 +0000294 else if (!isPure)
Mike Stump28431212009-10-13 22:54:56 +0000295 Thunks[MD] = ThisOffset;
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000296 }
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000297 return true;
298 }
299 }
300
301 return false;
302 }
303
304 void InstallThunks() {
305 for (Thunks_t::iterator i = Thunks.begin(), e = Thunks.end();
306 i != e; ++i) {
307 const CXXMethodDecl *MD = i->first;
Mike Stump375faa82009-10-28 00:35:46 +0000308 assert(!MD->isPure() && "Trying to thunk a pure");
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000309 Index_t idx = Index[MD];
310 Index_t nv_O = i->second.first;
311 Index_t v_O = i->second.second;
312 submethods[idx] = CGM.BuildThunk(MD, Extern, nv_O, v_O);
313 }
314 Thunks.clear();
315 for (CovariantThunks_t::iterator i = CovariantThunks.begin(),
316 e = CovariantThunks.end();
317 i != e; ++i) {
318 const CXXMethodDecl *MD = i->first;
Mike Stump375faa82009-10-28 00:35:46 +0000319 if (MD->isPure())
320 continue;
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000321 Index_t idx = Index[MD];
Mike Stump87876a02009-10-13 10:55:21 +0000322 Index_t nv_t = i->second.first.first.first;
323 Index_t v_t = i->second.first.first.second;
324 Index_t nv_r = i->second.first.second.first;
325 Index_t v_r = i->second.first.second.second;
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000326 submethods[idx] = CGM.BuildCovariantThunk(MD, Extern, nv_t, v_t, nv_r,
327 v_r);
328 }
329 CovariantThunks.clear();
Mike Stumpbb9ff052009-10-27 23:46:47 +0000330 for (Pures_t::iterator i = Pures.begin(), e = Pures.end();
331 i != e; ++i) {
332 const CXXMethodDecl *MD = i->first;
333 Index_t idx = Index[MD];
334 submethods[idx] = cxa_pure;
335 }
336 Pures.clear();
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000337 }
338
Mike Stump18e8b472009-10-27 23:36:26 +0000339 llvm::Constant *WrapAddrOf(const CXXMethodDecl *MD) {
340 if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(MD))
341 return wrap(CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete));
342
343 const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>();
344 const llvm::Type *Ty =
345 CGM.getTypes().GetFunctionType(CGM.getTypes().getFunctionInfo(MD),
346 FPT->isVariadic());
347
348 return wrap(CGM.GetAddrOfFunction(MD, Ty));
349 }
350
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000351 void OverrideMethods(Path_t *Path, bool MorallyVirtual, int64_t Offset,
352 int64_t CurrentVBaseOffset) {
Mike Stump37dbe962009-10-15 02:04:03 +0000353 for (Path_t::reverse_iterator i = Path->rbegin(),
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000354 e = Path->rend(); i != e; ++i) {
355 const CXXRecordDecl *RD = i->first;
Mike Stump8bccbfd2009-10-15 09:30:16 +0000356 int64_t OverrideOffset = i->second;
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000357 for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
358 ++mi) {
359 if (!mi->isVirtual())
360 continue;
361
362 const CXXMethodDecl *MD = *mi;
Mike Stump18e8b472009-10-27 23:36:26 +0000363 llvm::Constant *m = WrapAddrOf(MD);
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000364 OverrideMethod(MD, m, MorallyVirtual, OverrideOffset, Offset,
365 CurrentVBaseOffset);
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000366 }
367 }
368 }
369
Mike Stump75ce5732009-10-31 20:06:59 +0000370 void AddMethod(const CXXMethodDecl *MD, bool MorallyVirtual, Index_t Offset,
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000371 bool ForVirtualBase, int64_t CurrentVBaseOffset) {
Mike Stump18e8b472009-10-27 23:36:26 +0000372 llvm::Constant *m = WrapAddrOf(MD);
373
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000374 // If we can find a previously allocated slot for this, reuse it.
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000375 if (OverrideMethod(MD, m, MorallyVirtual, Offset, Offset,
376 CurrentVBaseOffset))
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000377 return;
378
379 // else allocate a new slot.
380 Index[MD] = submethods.size();
381 submethods.push_back(m);
Mike Stump75ce5732009-10-31 20:06:59 +0000382 D1(printf(" vfn for %s at %d\n", MD->getNameAsCString(), (int)Index[MD]));
Mike Stump375faa82009-10-28 00:35:46 +0000383 if (MD->isPure())
384 Pures[MD] = 1;
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000385 if (MorallyVirtual) {
386 VCallOffset[MD] = Offset/8;
387 Index_t &idx = VCall[MD];
388 // Allocate the first one, after that, we reuse the previous one.
389 if (idx == 0) {
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000390 NonVirtualOffset[MD] = CurrentVBaseOffset/8 - Offset/8;
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000391 idx = VCalls.size()+1;
392 VCalls.push_back(0);
Mike Stump75ce5732009-10-31 20:06:59 +0000393 D1(printf(" vcall for %s at %d with delta %d\n",
Mike Stump72431bd2009-11-06 02:38:24 +0000394 MD->getNameAsCString(), (int)-VCalls.size()-3, 0));
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000395 }
396 }
397 }
398
399 void AddMethods(const CXXRecordDecl *RD, bool MorallyVirtual,
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000400 Index_t Offset, bool RDisVirtualBase,
401 int64_t CurrentVBaseOffset) {
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000402 for (method_iter mi = RD->method_begin(), me = RD->method_end(); mi != me;
403 ++mi)
404 if (mi->isVirtual())
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000405 AddMethod(*mi, MorallyVirtual, Offset, RDisVirtualBase,
406 CurrentVBaseOffset);
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000407 }
408
409 void NonVirtualBases(const CXXRecordDecl *RD, const ASTRecordLayout &Layout,
410 const CXXRecordDecl *PrimaryBase,
411 bool PrimaryBaseWasVirtual, bool MorallyVirtual,
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000412 int64_t Offset, int64_t CurrentVBaseOffset,
413 Path_t *Path) {
Mike Stump37dbe962009-10-15 02:04:03 +0000414 Path->push_back(std::make_pair(RD, Offset));
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000415 for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
416 e = RD->bases_end(); i != e; ++i) {
417 if (i->isVirtual())
418 continue;
419 const CXXRecordDecl *Base =
420 cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
421 if (Base != PrimaryBase || PrimaryBaseWasVirtual) {
422 uint64_t o = Offset + Layout.getBaseClassOffset(Base);
423 StartNewTable();
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000424 GenerateVtableForBase(Base, MorallyVirtual, o, false,
425 CurrentVBaseOffset, Path);
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000426 }
427 }
Mike Stump37dbe962009-10-15 02:04:03 +0000428 Path->pop_back();
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000429 }
430
Mike Stumpb21c4ee2009-10-14 18:14:51 +0000431// #define D(X) do { X; } while (0)
432#define D(X)
433
434 void insertVCalls(int InsertionPoint) {
435 llvm::Constant *e = 0;
Mike Stump75ce5732009-10-31 20:06:59 +0000436 D1(printf("============= combining vbase/vcall\n"));
Mike Stumpb21c4ee2009-10-14 18:14:51 +0000437 D(VCalls.insert(VCalls.begin(), 673));
438 D(VCalls.push_back(672));
Mike Stump8bccbfd2009-10-15 09:30:16 +0000439 methods.insert(methods.begin() + InsertionPoint, VCalls.size(), e);
Mike Stumpb21c4ee2009-10-14 18:14:51 +0000440 // The vcalls come first...
441 for (std::vector<Index_t>::reverse_iterator i = VCalls.rbegin(),
442 e = VCalls.rend();
443 i != e; ++i)
444 methods[InsertionPoint++] = wrap((0?600:0) + *i);
445 VCalls.clear();
Mike Stump9f23a142009-11-10 02:30:51 +0000446 VCall.clear();
Mike Stumpb21c4ee2009-10-14 18:14:51 +0000447 }
448
Mike Stump75ce5732009-10-31 20:06:59 +0000449 Index_t end(const CXXRecordDecl *RD, const ASTRecordLayout &Layout,
450 const CXXRecordDecl *PrimaryBase, bool PrimaryBaseWasVirtual,
451 bool MorallyVirtual, int64_t Offset, bool ForVirtualBase,
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000452 int64_t CurrentVBaseOffset,
Mike Stump75ce5732009-10-31 20:06:59 +0000453 Path_t *Path) {
Mike Stump37dbe962009-10-15 02:04:03 +0000454 bool alloc = false;
455 if (Path == 0) {
456 alloc = true;
457 Path = new Path_t;
458 }
459
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000460 StartNewTable();
461 extra = 0;
Mike Stumpb21c4ee2009-10-14 18:14:51 +0000462 bool DeferVCalls = MorallyVirtual || ForVirtualBase;
463 int VCallInsertionPoint = methods.size();
464 if (!DeferVCalls) {
465 insertVCalls(VCallInsertionPoint);
Mike Stump8bccbfd2009-10-15 09:30:16 +0000466 } else
467 // FIXME: just for extra, or for all uses of VCalls.size post this?
468 extra = -VCalls.size();
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000469
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000470 methods.push_back(wrap(-(Offset/8)));
471 methods.push_back(rtti);
472 Index_t AddressPoint = methods.size();
473
474 InstallThunks();
Mike Stump75ce5732009-10-31 20:06:59 +0000475 D1(printf("============= combining methods\n"));
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000476 methods.insert(methods.end(), submethods.begin(), submethods.end());
477 submethods.clear();
478
479 // and then the non-virtual bases.
480 NonVirtualBases(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual,
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000481 MorallyVirtual, Offset, CurrentVBaseOffset, Path);
Mike Stumpb21c4ee2009-10-14 18:14:51 +0000482
483 if (ForVirtualBase) {
Mike Stump2cefe382009-11-12 20:47:57 +0000484 // FIXME: We're adding to VCalls in callers, we need to do the overrides
485 // in the inner part, so that we know the complete set of vcalls during
486 // the build and don't have to insert into methods. Saving out the
487 // AddressPoint here, would need to be fixed, if we didn't do that. Also
488 // retroactively adding vcalls for overrides later wind up in the wrong
489 // place, the vcall slot has to be alloted during the walk of the base
490 // when the function is first introduces.
Mike Stumpb21c4ee2009-10-14 18:14:51 +0000491 AddressPoint += VCalls.size();
Mike Stump2cefe382009-11-12 20:47:57 +0000492 insertVCalls(VCallInsertionPoint);
Mike Stumpb21c4ee2009-10-14 18:14:51 +0000493 }
494
Mike Stump2cefe382009-11-12 20:47:57 +0000495 if (MorallyVirtual) {
496 D1(printf("XXX address point for %s in %s at offset %d is %d\n",
497 RD->getNameAsCString(), Class->getNameAsCString(),
498 (int)Offset, (int)AddressPoint));
499 AddressPoints[std::make_pair(RD, Offset)] = AddressPoint;
500
501 }
502
Mike Stump37dbe962009-10-15 02:04:03 +0000503 if (alloc) {
504 delete Path;
505 }
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000506 return AddressPoint;
507 }
508
Mike Stump75ce5732009-10-31 20:06:59 +0000509 void Primaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset,
510 bool updateVBIndex, Index_t current_vbindex,
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000511 bool RDisVirtualBase, int64_t CurrentVBaseOffset) {
Mike Stump75ce5732009-10-31 20:06:59 +0000512 if (!RD->isDynamicClass())
513 return;
514
515 const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
516 const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
517 const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
518
519 // vtables are composed from the chain of primaries.
520 if (PrimaryBase) {
521 D1(printf(" doing primaries for %s most derived %s\n",
522 RD->getNameAsCString(), Class->getNameAsCString()));
523
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000524 int BaseCurrentVBaseOffset = CurrentVBaseOffset;
525 if (PrimaryBaseWasVirtual)
526 BaseCurrentVBaseOffset = BLayout.getVBaseClassOffset(PrimaryBase);
527
Mike Stump75ce5732009-10-31 20:06:59 +0000528 if (!PrimaryBaseWasVirtual)
529 Primaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000530 updateVBIndex, current_vbindex, PrimaryBaseWasVirtual,
531 BaseCurrentVBaseOffset);
Mike Stump75ce5732009-10-31 20:06:59 +0000532 }
533
534 D1(printf(" doing vcall entries for %s most derived %s\n",
535 RD->getNameAsCString(), Class->getNameAsCString()));
536
537 // And add the virtuals for the class to the primary vtable.
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000538 AddMethods(RD, MorallyVirtual, Offset, RDisVirtualBase, CurrentVBaseOffset);
Mike Stump75ce5732009-10-31 20:06:59 +0000539 }
540
541 void VBPrimaries(const CXXRecordDecl *RD, bool MorallyVirtual, int64_t Offset,
542 bool updateVBIndex, Index_t current_vbindex,
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000543 bool RDisVirtualBase, int64_t CurrentVBaseOffset,
544 bool bottom=false) {
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000545 if (!RD->isDynamicClass())
546 return;
547
548 const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
549 const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
550 const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
551
552 // vtables are composed from the chain of primaries.
553 if (PrimaryBase) {
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000554 int BaseCurrentVBaseOffset = CurrentVBaseOffset;
555 if (PrimaryBaseWasVirtual) {
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000556 IndirectPrimary.insert(PrimaryBase);
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000557 BaseCurrentVBaseOffset = BLayout.getVBaseClassOffset(PrimaryBase);
558 }
Mike Stump75ce5732009-10-31 20:06:59 +0000559
560 D1(printf(" doing primaries for %s most derived %s\n",
561 RD->getNameAsCString(), Class->getNameAsCString()));
562
563 VBPrimaries(PrimaryBase, PrimaryBaseWasVirtual|MorallyVirtual, Offset,
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000564 updateVBIndex, current_vbindex, PrimaryBaseWasVirtual,
565 BaseCurrentVBaseOffset);
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000566 }
567
Mike Stump75ce5732009-10-31 20:06:59 +0000568 D1(printf(" doing vbase entries for %s most derived %s\n",
569 RD->getNameAsCString(), Class->getNameAsCString()));
570 GenerateVBaseOffsets(RD, Offset, updateVBIndex, current_vbindex);
571
572 if (RDisVirtualBase || bottom) {
573 Primaries(RD, MorallyVirtual, Offset, updateVBIndex, current_vbindex,
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000574 RDisVirtualBase, CurrentVBaseOffset);
Mike Stump75ce5732009-10-31 20:06:59 +0000575 }
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000576 }
577
578 int64_t GenerateVtableForBase(const CXXRecordDecl *RD,
579 bool MorallyVirtual = false, int64_t Offset = 0,
580 bool ForVirtualBase = false,
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000581 int CurrentVBaseOffset = 0,
Mike Stump37dbe962009-10-15 02:04:03 +0000582 Path_t *Path = 0) {
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000583 if (!RD->isDynamicClass())
584 return 0;
585
586 const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
587 const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
588 const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
589
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000590 extra = 0;
Mike Stump75ce5732009-10-31 20:06:59 +0000591 D1(printf("building entries for base %s most derived %s\n",
592 RD->getNameAsCString(), Class->getNameAsCString()));
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000593
Mike Stump75ce5732009-10-31 20:06:59 +0000594 if (ForVirtualBase)
595 extra = VCalls.size();
596
597 VBPrimaries(RD, MorallyVirtual, Offset, !ForVirtualBase, 0, ForVirtualBase,
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000598 CurrentVBaseOffset, true);
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000599
600 if (Path)
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000601 OverrideMethods(Path, MorallyVirtual, Offset, CurrentVBaseOffset);
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000602
Mike Stump75ce5732009-10-31 20:06:59 +0000603 return end(RD, Layout, PrimaryBase, PrimaryBaseWasVirtual, MorallyVirtual,
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000604 Offset, ForVirtualBase, CurrentVBaseOffset, Path);
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000605 }
606
607 void GenerateVtableForVBases(const CXXRecordDecl *RD,
608 int64_t Offset = 0,
Mike Stump37dbe962009-10-15 02:04:03 +0000609 Path_t *Path = 0) {
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000610 bool alloc = false;
611 if (Path == 0) {
612 alloc = true;
Mike Stump37dbe962009-10-15 02:04:03 +0000613 Path = new Path_t;
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000614 }
615 // FIXME: We also need to override using all paths to a virtual base,
616 // right now, we just process the first path
617 Path->push_back(std::make_pair(RD, Offset));
618 for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
619 e = RD->bases_end(); i != e; ++i) {
620 const CXXRecordDecl *Base =
621 cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
622 if (i->isVirtual() && !IndirectPrimary.count(Base)) {
623 // Mark it so we don't output it twice.
624 IndirectPrimary.insert(Base);
625 StartNewTable();
Mike Stumpb21c4ee2009-10-14 18:14:51 +0000626 VCall.clear();
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000627 int64_t BaseOffset = BLayout.getVBaseClassOffset(Base);
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000628 int64_t CurrentVBaseOffset = BaseOffset;
Mike Stump75ce5732009-10-31 20:06:59 +0000629 D1(printf("vtable %s virtual base %s\n",
630 Class->getNameAsCString(), Base->getNameAsCString()));
Mike Stumpcd6f9ed2009-11-06 23:27:42 +0000631 GenerateVtableForBase(Base, true, BaseOffset, true, CurrentVBaseOffset,
632 Path);
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000633 }
Mike Stump2cefe382009-11-12 20:47:57 +0000634 int64_t BaseOffset;
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000635 if (i->isVirtual())
636 BaseOffset = BLayout.getVBaseClassOffset(Base);
Mike Stump2cefe382009-11-12 20:47:57 +0000637 else {
638 const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
639 BaseOffset = Offset + Layout.getBaseClassOffset(Base);
640 }
641
Mike Stump37dbe962009-10-15 02:04:03 +0000642 if (Base->getNumVBases()) {
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000643 GenerateVtableForVBases(Base, BaseOffset, Path);
Mike Stump37dbe962009-10-15 02:04:03 +0000644 }
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000645 }
646 Path->pop_back();
647 if (alloc)
648 delete Path;
649 }
650};
651
652
653VtableBuilder::Index_t VtableBuilder::VBlookup(CXXRecordDecl *D,
654 CXXRecordDecl *B) {
655 return CGM.getVtableInfo().getVirtualBaseOffsetIndex(D, B);
656}
657
658int64_t CGVtableInfo::getMethodVtableIndex(const CXXMethodDecl *MD) {
659 MD = MD->getCanonicalDecl();
660
661 MethodVtableIndicesTy::iterator I = MethodVtableIndices.find(MD);
662 if (I != MethodVtableIndices.end())
663 return I->second;
664
665 const CXXRecordDecl *RD = MD->getParent();
666
667 std::vector<llvm::Constant *> methods;
668 // FIXME: This seems expensive. Can we do a partial job to get
669 // just this data.
670 VtableBuilder b(methods, RD, CGM);
Mike Stump75ce5732009-10-31 20:06:59 +0000671 D1(printf("vtable %s\n", RD->getNameAsCString()));
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000672 b.GenerateVtableForBase(RD);
673 b.GenerateVtableForVBases(RD);
674
675 MethodVtableIndices.insert(b.getIndex().begin(),
676 b.getIndex().end());
677
678 I = MethodVtableIndices.find(MD);
679 assert(I != MethodVtableIndices.end() && "Did not find index!");
680 return I->second;
681}
682
683int64_t CGVtableInfo::getVirtualBaseOffsetIndex(const CXXRecordDecl *RD,
684 const CXXRecordDecl *VBase) {
685 ClassPairTy ClassPair(RD, VBase);
686
687 VirtualBaseClassIndiciesTy::iterator I =
688 VirtualBaseClassIndicies.find(ClassPair);
689 if (I != VirtualBaseClassIndicies.end())
690 return I->second;
691
692 std::vector<llvm::Constant *> methods;
693 // FIXME: This seems expensive. Can we do a partial job to get
694 // just this data.
695 VtableBuilder b(methods, RD, CGM);
Mike Stump75ce5732009-10-31 20:06:59 +0000696 D1(printf("vtable %s\n", RD->getNameAsCString()));
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000697 b.GenerateVtableForBase(RD);
698 b.GenerateVtableForVBases(RD);
699
700 for (llvm::DenseMap<const CXXRecordDecl *, uint64_t>::iterator I =
701 b.getVBIndex().begin(), E = b.getVBIndex().end(); I != E; ++I) {
702 // Insert all types.
703 ClassPairTy ClassPair(RD, I->first);
704
705 VirtualBaseClassIndicies.insert(std::make_pair(ClassPair, I->second));
706 }
707
708 I = VirtualBaseClassIndicies.find(ClassPair);
709 assert(I != VirtualBaseClassIndicies.end() && "Did not find index!");
710
711 return I->second;
712}
713
Mike Stump2cefe382009-11-12 20:47:57 +0000714llvm::Constant *CodeGenModule::GenerateVtable(const CXXRecordDecl *LayoutClass,
715 const CXXRecordDecl *RD,
Mike Stumpeac45592009-11-11 20:26:26 +0000716 uint64_t Offset) {
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000717 llvm::SmallString<256> OutName;
718 llvm::raw_svector_ostream Out(OutName);
Mike Stump2cefe382009-11-12 20:47:57 +0000719 if (LayoutClass != RD)
720 mangleCXXCtorVtable(getMangleContext(), LayoutClass, Offset/8, RD, Out);
Mike Stumpeac45592009-11-11 20:26:26 +0000721 else
722 mangleCXXVtable(getMangleContext(), RD, Out);
Benjamin Kramerbb0a07b2009-10-11 22:57:54 +0000723
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000724 llvm::GlobalVariable::LinkageTypes linktype;
Chandler Carruth6e0df532009-10-26 17:14:14 +0000725 linktype = llvm::GlobalValue::LinkOnceODRLinkage;
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000726 std::vector<llvm::Constant *> methods;
727 llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0);
728 int64_t AddressPoint;
729
Mike Stumpd846d082009-11-10 07:44:33 +0000730 VtableBuilder b(methods, RD, *this);
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000731
Mike Stump75ce5732009-10-31 20:06:59 +0000732 D1(printf("vtable %s\n", RD->getNameAsCString()));
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000733 // First comes the vtables for all the non-virtual bases...
734 AddressPoint = b.GenerateVtableForBase(RD);
735
736 // then the vtables for all the virtual bases.
737 b.GenerateVtableForVBases(RD);
738
Mike Stump2cefe382009-11-12 20:47:57 +0000739 if (LayoutClass == RD)
740 AddressPoints[RD] = b.getAddressPoints();
741
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000742 llvm::Constant *C;
743 llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, methods.size());
744 C = llvm::ConstantArray::get(type, methods);
Mike Stumpd846d082009-11-10 07:44:33 +0000745 llvm::Constant *vtable = new llvm::GlobalVariable(getModule(), type,
746 true, linktype, C,
747 Out.str());
748 vtable = llvm::ConstantExpr::getBitCast(vtable, Ptr8Ty);
749 llvm::Constant *AddressPointC;
750 uint32_t LLVMPointerWidth = getContext().Target.getPointerWidth(0);
751 AddressPointC = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
752 AddressPoint*LLVMPointerWidth/8);
Mike Stump2cefe382009-11-12 20:47:57 +0000753 vtable = llvm::ConstantExpr::getInBoundsGetElementPtr(vtable, &AddressPointC,
754 1);
Mike Stumpd846d082009-11-10 07:44:33 +0000755
Anders Carlsson2bb27f52009-10-11 22:13:54 +0000756 return vtable;
757}
Mike Stump9f23a142009-11-10 02:30:51 +0000758
759class VTTBuilder {
760 /// Inits - The list of values built for the VTT.
761 std::vector<llvm::Constant *> &Inits;
762 /// Class - The most derived class that this vtable is being built for.
763 const CXXRecordDecl *Class;
764 CodeGenModule &CGM; // Per-module state.
Mike Stump8b2d2d02009-11-11 00:35:07 +0000765 llvm::SmallSet<const CXXRecordDecl *, 32> SeenVBase;
Mike Stumpc7b9f5e2009-11-11 03:08:24 +0000766 /// BLayout - Layout for the most derived class that this vtable is being
767 /// built for.
768 const ASTRecordLayout &BLayout;
Mike Stump2cefe382009-11-12 20:47:57 +0000769 // vtbl - A pointer to the vtable for Class.
770 llvm::Constant *ClassVtbl;
771 llvm::LLVMContext &VMContext;
Mike Stump9f23a142009-11-10 02:30:51 +0000772
Mike Stump2cefe382009-11-12 20:47:57 +0000773 /// Secondary - Add the secondary vtable pointers to Inits. Offset is the
774 /// current offset in bits to the object we're working on.
Mike Stumpc7b9f5e2009-11-11 03:08:24 +0000775 void Secondary(const CXXRecordDecl *RD, uint64_t Offset=0,
776 bool MorallyVirtual=false) {
Mike Stump8b2d2d02009-11-11 00:35:07 +0000777 if (RD->getNumVBases() == 0 && ! MorallyVirtual)
778 return;
779
780 for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
781 e = RD->bases_end(); i != e; ++i) {
782 const CXXRecordDecl *Base =
783 cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
784 const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
785 const CXXRecordDecl *PrimaryBase = Layout.getPrimaryBase();
786 const bool PrimaryBaseWasVirtual = Layout.getPrimaryBaseWasVirtual();
787 bool NonVirtualPrimaryBase;
788 NonVirtualPrimaryBase = !PrimaryBaseWasVirtual && Base == PrimaryBase;
789 bool BaseMorallyVirtual = MorallyVirtual | i->isVirtual();
Mike Stumpc7b9f5e2009-11-11 03:08:24 +0000790 uint64_t BaseOffset;
791 if (!i->isVirtual()) {
792 const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
793 BaseOffset = Offset + Layout.getBaseClassOffset(Base);
794 } else
795 BaseOffset = BLayout.getVBaseClassOffset(Base);
Mike Stump8b2d2d02009-11-11 00:35:07 +0000796 if ((Base->getNumVBases() || BaseMorallyVirtual)
797 && !NonVirtualPrimaryBase) {
798 // FIXME: Slightly too many of these for __ZTT8test8_B2
Mike Stumpc7b9f5e2009-11-11 03:08:24 +0000799 llvm::Constant *vtbl;
Mike Stump2cefe382009-11-12 20:47:57 +0000800 vtbl = CGM.getVtableInfo().getCtorVtable(Class, Base, BaseOffset);
Mike Stump8b2d2d02009-11-11 00:35:07 +0000801 Inits.push_back(vtbl);
802 }
Mike Stumpc7b9f5e2009-11-11 03:08:24 +0000803 Secondary(Base, BaseOffset, BaseMorallyVirtual);
Mike Stump8b2d2d02009-11-11 00:35:07 +0000804 }
805 }
806
Mike Stump2cefe382009-11-12 20:47:57 +0000807 /// BuiltVTT - Add the VTT to Inits. Offset is the offset in bits to the
808 /// currnet object we're working on.
809 void BuildVTT(const CXXRecordDecl *RD, uint64_t Offset, bool MorallyVirtual) {
Mike Stump8b2d2d02009-11-11 00:35:07 +0000810 if (RD->getNumVBases() == 0 && !MorallyVirtual)
811 return;
812
Mike Stump2cefe382009-11-12 20:47:57 +0000813 llvm::Constant *init;
Mike Stump8b2d2d02009-11-11 00:35:07 +0000814 // First comes the primary virtual table pointer...
Mike Stump2cefe382009-11-12 20:47:57 +0000815 if (MorallyVirtual) {
816 int64_t AddressPoint;
817 AddressPoint = (*CGM.AddressPoints[Class])[std::make_pair(RD, Offset)];
818 D1(printf("XXX address point for %s in %s at offset %d was %d\n",
819 RD->getNameAsCString(), Class->getNameAsCString(),
820 (int)Offset, (int)AddressPoint));
821 uint32_t LLVMPointerWidth = CGM.getContext().Target.getPointerWidth(0);
822 init = llvm::ConstantInt::get(llvm::Type::getInt64Ty(VMContext),
823 AddressPoint*LLVMPointerWidth/8);
824 init = llvm::ConstantExpr::getInBoundsGetElementPtr(ClassVtbl, &init, 1);
825 } else
826 init = CGM.getVtableInfo().getCtorVtable(Class, RD, Offset);
827 Inits.push_back(init);
Mike Stump8b2d2d02009-11-11 00:35:07 +0000828
829 // then the secondary VTTs....
Mike Stump2cefe382009-11-12 20:47:57 +0000830 SecondaryVTTs(RD, Offset, MorallyVirtual);
Mike Stump8b2d2d02009-11-11 00:35:07 +0000831
832 // and last the secondary vtable pointers.
Mike Stumpc7b9f5e2009-11-11 03:08:24 +0000833 Secondary(RD, MorallyVirtual, Offset);
Mike Stump8b2d2d02009-11-11 00:35:07 +0000834 }
835
836 /// SecondaryVTTs - Add the secondary VTTs to Inits. The secondary VTTs are
837 /// built from each direct non-virtual proper base that requires a VTT in
838 /// declaration order.
Mike Stump2cefe382009-11-12 20:47:57 +0000839 void SecondaryVTTs(const CXXRecordDecl *RD, uint64_t Offset=0,
840 bool MorallyVirtual=false) {
Mike Stump8b2d2d02009-11-11 00:35:07 +0000841 for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
842 e = RD->bases_end(); i != e; ++i) {
843 const CXXRecordDecl *Base =
844 cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
845 if (i->isVirtual())
846 continue;
Mike Stump2cefe382009-11-12 20:47:57 +0000847 const ASTRecordLayout &Layout = CGM.getContext().getASTRecordLayout(RD);
848 uint64_t BaseOffset = Offset + Layout.getBaseClassOffset(Base);
849 BuildVTT(Base, BaseOffset, MorallyVirtual);
Mike Stump8b2d2d02009-11-11 00:35:07 +0000850 }
851 }
852
853 /// VirtualVTTs - Add the VTT for each proper virtual base in inheritance
854 /// graph preorder.
855 void VirtualVTTs(const CXXRecordDecl *RD) {
856 for (CXXRecordDecl::base_class_const_iterator i = RD->bases_begin(),
857 e = RD->bases_end(); i != e; ++i) {
858 const CXXRecordDecl *Base =
859 cast<CXXRecordDecl>(i->getType()->getAs<RecordType>()->getDecl());
860 if (i->isVirtual() && !SeenVBase.count(Base)) {
861 SeenVBase.insert(Base);
Mike Stump2cefe382009-11-12 20:47:57 +0000862 uint64_t BaseOffset = BLayout.getVBaseClassOffset(Base);
863 BuildVTT(Base, BaseOffset, true);
Mike Stump8b2d2d02009-11-11 00:35:07 +0000864 }
865 VirtualVTTs(Base);
866 }
867 }
Mike Stump9f23a142009-11-10 02:30:51 +0000868public:
869 VTTBuilder(std::vector<llvm::Constant *> &inits, const CXXRecordDecl *c,
Mike Stumpc7b9f5e2009-11-11 03:08:24 +0000870 CodeGenModule &cgm)
871 : Inits(inits), Class(c), CGM(cgm),
Mike Stump2cefe382009-11-12 20:47:57 +0000872 BLayout(cgm.getContext().getASTRecordLayout(c)),
873 VMContext(cgm.getModule().getContext()) {
Mike Stumpd846d082009-11-10 07:44:33 +0000874
Mike Stump8b2d2d02009-11-11 00:35:07 +0000875 // First comes the primary virtual table pointer for the complete class...
Mike Stump2cefe382009-11-12 20:47:57 +0000876 ClassVtbl = CGM.getVtableInfo().getVtable(Class);
877 Inits.push_back(ClassVtbl);
878 ClassVtbl = dyn_cast<llvm::Constant>(ClassVtbl->getOperand(0));
879
Mike Stump8b2d2d02009-11-11 00:35:07 +0000880 // then the secondary VTTs...
881 SecondaryVTTs(Class);
882
883 // then the secondary vtable pointers...
884 Secondary(Class);
885
886 // and last, the virtual VTTs.
887 VirtualVTTs(Class);
Mike Stump9f23a142009-11-10 02:30:51 +0000888 }
889};
890
Mike Stumpd846d082009-11-10 07:44:33 +0000891llvm::Constant *CodeGenModule::GenerateVTT(const CXXRecordDecl *RD) {
Mike Stumpb4722212009-11-10 19:13:04 +0000892 // Only classes that have virtual bases need a VTT.
893 if (RD->getNumVBases() == 0)
894 return 0;
895
Mike Stump9f23a142009-11-10 02:30:51 +0000896 llvm::SmallString<256> OutName;
897 llvm::raw_svector_ostream Out(OutName);
Mike Stumpd846d082009-11-10 07:44:33 +0000898 mangleCXXVTT(getMangleContext(), RD, Out);
Mike Stump9f23a142009-11-10 02:30:51 +0000899
900 llvm::GlobalVariable::LinkageTypes linktype;
901 linktype = llvm::GlobalValue::LinkOnceODRLinkage;
902 std::vector<llvm::Constant *> inits;
903 llvm::Type *Ptr8Ty=llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext),0);
904
Mike Stump9f23a142009-11-10 02:30:51 +0000905 D1(printf("vtt %s\n", RD->getNameAsCString()));
906
Mike Stump8b2d2d02009-11-11 00:35:07 +0000907 VTTBuilder b(inits, RD, *this);
908
Mike Stump9f23a142009-11-10 02:30:51 +0000909 llvm::Constant *C;
910 llvm::ArrayType *type = llvm::ArrayType::get(Ptr8Ty, inits.size());
911 C = llvm::ConstantArray::get(type, inits);
Mike Stumpd846d082009-11-10 07:44:33 +0000912 llvm::Constant *vtt = new llvm::GlobalVariable(getModule(), type, true,
913 linktype, C, Out.str());
914 vtt = llvm::ConstantExpr::getBitCast(vtt, Ptr8Ty);
Mike Stump9f23a142009-11-10 02:30:51 +0000915 return vtt;
916}
Mike Stumpd846d082009-11-10 07:44:33 +0000917
Mike Stumpeac45592009-11-11 20:26:26 +0000918llvm::Constant *CGVtableInfo::getVtable(const CXXRecordDecl *RD) {
Mike Stumpd846d082009-11-10 07:44:33 +0000919 llvm::Constant *&vtbl = Vtables[RD];
920 if (vtbl)
921 return vtbl;
Mike Stump2cefe382009-11-12 20:47:57 +0000922 vtbl = CGM.GenerateVtable(RD, RD);
Mike Stumpd846d082009-11-10 07:44:33 +0000923 CGM.GenerateVTT(RD);
924 return vtbl;
925}
Mike Stumpeac45592009-11-11 20:26:26 +0000926
Mike Stump2cefe382009-11-12 20:47:57 +0000927llvm::Constant *CGVtableInfo::getCtorVtable(const CXXRecordDecl *LayoutClass,
928 const CXXRecordDecl *RD,
Mike Stumpeac45592009-11-11 20:26:26 +0000929 uint64_t Offset) {
Mike Stump2cefe382009-11-12 20:47:57 +0000930 return CGM.GenerateVtable(LayoutClass, RD, Offset);
Mike Stumpeac45592009-11-11 20:26:26 +0000931}