1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | #include "CGCXXABI.h" |
14 | #include "CodeGenFunction.h" |
15 | #include "CodeGenModule.h" |
16 | #include "clang/AST/CXXInheritance.h" |
17 | #include "clang/AST/RecordLayout.h" |
18 | #include "clang/Basic/CodeGenOptions.h" |
19 | #include "clang/CodeGen/CGFunctionInfo.h" |
20 | #include "clang/CodeGen/ConstantInitBuilder.h" |
21 | #include "llvm/IR/IntrinsicInst.h" |
22 | #include "llvm/Support/Format.h" |
23 | #include "llvm/Transforms/Utils/Cloning.h" |
24 | #include <algorithm> |
25 | #include <cstdio> |
26 | |
27 | using namespace clang; |
28 | using namespace CodeGen; |
29 | |
30 | CodeGenVTables::CodeGenVTables(CodeGenModule &CGM) |
31 | : CGM(CGM), VTContext(CGM.getContext().getVTableContext()) {} |
32 | |
33 | llvm::Constant *CodeGenModule::GetAddrOfThunk(StringRef Name, llvm::Type *FnTy, |
34 | GlobalDecl GD) { |
35 | return GetOrCreateLLVMFunction(Name, FnTy, GD, , |
36 | , ); |
37 | } |
38 | |
39 | static void setThunkProperties(CodeGenModule &CGM, const ThunkInfo &Thunk, |
40 | llvm::Function *ThunkFn, bool ForVTable, |
41 | GlobalDecl GD) { |
42 | CGM.setFunctionLinkage(GD, ThunkFn); |
43 | CGM.getCXXABI().setThunkLinkage(ThunkFn, ForVTable, GD, |
44 | !Thunk.Return.isEmpty()); |
45 | |
46 | |
47 | CGM.setGVProperties(ThunkFn, GD); |
48 | |
49 | if (!CGM.getCXXABI().exportThunk()) { |
50 | ThunkFn->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass); |
51 | ThunkFn->setDSOLocal(true); |
52 | } |
53 | |
54 | if (CGM.supportsCOMDAT() && ThunkFn->isWeakForLinker()) |
55 | ThunkFn->setComdat(CGM.getModule().getOrInsertComdat(ThunkFn->getName())); |
56 | } |
57 | |
58 | #ifndef NDEBUG |
59 | static bool similar(const ABIArgInfo &infoL, CanQualType typeL, |
60 | const ABIArgInfo &infoR, CanQualType typeR) { |
61 | return (infoL.getKind() == infoR.getKind() && |
62 | (typeL == typeR || |
63 | (isa<PointerType>(typeL) && isa<PointerType>(typeR)) || |
64 | (isa<ReferenceType>(typeL) && isa<ReferenceType>(typeR)))); |
65 | } |
66 | #endif |
67 | |
68 | static RValue PerformReturnAdjustment(CodeGenFunction &CGF, |
69 | QualType ResultType, RValue RV, |
70 | const ThunkInfo &Thunk) { |
71 | |
72 | bool NullCheckValue = !ResultType->isReferenceType(); |
73 | |
74 | llvm::BasicBlock *AdjustNull = nullptr; |
75 | llvm::BasicBlock *AdjustNotNull = nullptr; |
76 | llvm::BasicBlock *AdjustEnd = nullptr; |
77 | |
78 | llvm::Value *ReturnValue = RV.getScalarVal(); |
79 | |
80 | if (NullCheckValue) { |
81 | AdjustNull = CGF.createBasicBlock("adjust.null"); |
82 | AdjustNotNull = CGF.createBasicBlock("adjust.notnull"); |
83 | AdjustEnd = CGF.createBasicBlock("adjust.end"); |
84 | |
85 | llvm::Value *IsNull = CGF.Builder.CreateIsNull(ReturnValue); |
86 | CGF.Builder.CreateCondBr(IsNull, AdjustNull, AdjustNotNull); |
87 | CGF.EmitBlock(AdjustNotNull); |
88 | } |
89 | |
90 | auto ClassDecl = ResultType->getPointeeType()->getAsCXXRecordDecl(); |
91 | auto ClassAlign = CGF.CGM.getClassPointerAlignment(ClassDecl); |
92 | ReturnValue = CGF.CGM.getCXXABI().performReturnAdjustment(CGF, |
93 | Address(ReturnValue, ClassAlign), |
94 | Thunk.Return); |
95 | |
96 | if (NullCheckValue) { |
97 | CGF.Builder.CreateBr(AdjustEnd); |
98 | CGF.EmitBlock(AdjustNull); |
99 | CGF.Builder.CreateBr(AdjustEnd); |
100 | CGF.EmitBlock(AdjustEnd); |
101 | |
102 | llvm::PHINode *PHI = CGF.Builder.CreatePHI(ReturnValue->getType(), 2); |
103 | PHI->addIncoming(ReturnValue, AdjustNotNull); |
104 | PHI->addIncoming(llvm::Constant::getNullValue(ReturnValue->getType()), |
105 | AdjustNull); |
106 | ReturnValue = PHI; |
107 | } |
108 | |
109 | return RValue::get(ReturnValue); |
110 | } |
111 | |
112 | |
113 | |
114 | |
115 | |
116 | |
117 | static void resolveTopLevelMetadata(llvm::Function *Fn, |
118 | llvm::ValueToValueMapTy &VMap) { |
119 | |
120 | auto *DIS = Fn->getSubprogram(); |
121 | if (!DIS) |
122 | return; |
123 | auto *NewDIS = DIS->replaceWithDistinct(DIS->clone()); |
124 | VMap.MD()[DIS].reset(NewDIS); |
125 | |
126 | |
127 | |
128 | for (auto &BB : Fn->getBasicBlockList()) { |
129 | for (auto &I : BB) { |
130 | if (auto *DII = dyn_cast<llvm::DbgVariableIntrinsic>(&I)) { |
131 | auto *DILocal = DII->getVariable(); |
132 | if (!DILocal->isResolved()) |
133 | DILocal->resolve(); |
134 | } |
135 | } |
136 | } |
137 | } |
138 | |
139 | |
140 | |
141 | |
142 | |
143 | |
144 | |
145 | |
146 | |
147 | |
148 | |
149 | |
150 | |
151 | |
152 | |
153 | |
154 | |
155 | llvm::Function * |
156 | CodeGenFunction::GenerateVarArgsThunk(llvm::Function *Fn, |
157 | const CGFunctionInfo &FnInfo, |
158 | GlobalDecl GD, const ThunkInfo &Thunk) { |
159 | const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); |
160 | const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); |
161 | QualType ResultType = FPT->getReturnType(); |
162 | |
163 | |
164 | assert(FnInfo.isVariadic()); |
165 | llvm::Type *Ty = CGM.getTypes().GetFunctionType(FnInfo); |
166 | llvm::Value *Callee = CGM.GetAddrOfFunction(GD, Ty, ); |
167 | llvm::Function *BaseFn = cast<llvm::Function>(Callee); |
168 | |
169 | |
170 | llvm::ValueToValueMapTy VMap; |
171 | |
172 | |
173 | |
174 | resolveTopLevelMetadata(BaseFn, VMap); |
175 | llvm::Function *NewFn = llvm::CloneFunction(BaseFn, VMap); |
176 | Fn->replaceAllUsesWith(NewFn); |
177 | NewFn->takeName(Fn); |
178 | Fn->eraseFromParent(); |
179 | Fn = NewFn; |
180 | |
181 | |
182 | CurFn = Fn; |
183 | |
184 | |
185 | llvm::Function::arg_iterator AI = Fn->arg_begin(); |
186 | if (CGM.ReturnTypeUsesSRet(FnInfo)) |
187 | ++AI; |
188 | |
189 | |
190 | |
191 | Address ThisPtr(&*AI, CGM.getClassPointerAlignment(MD->getParent())); |
192 | llvm::BasicBlock *EntryBB = &Fn->front(); |
193 | llvm::BasicBlock::iterator ThisStore = |
194 | std::find_if(EntryBB->begin(), EntryBB->end(), [&](llvm::Instruction &I) { |
195 | return isa<llvm::StoreInst>(I) && |
196 | I.getOperand(0) == ThisPtr.getPointer(); |
197 | }); |
198 | (0) . __assert_fail ("ThisStore != EntryBB->end() && \"Store of this should be in entry block?\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 199, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(ThisStore != EntryBB->end() && |
199 | (0) . __assert_fail ("ThisStore != EntryBB->end() && \"Store of this should be in entry block?\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 199, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "Store of this should be in entry block?"); |
200 | |
201 | Builder.SetInsertPoint(&*ThisStore); |
202 | llvm::Value *AdjustedThisPtr = |
203 | CGM.getCXXABI().performThisAdjustment(*this, ThisPtr, Thunk.This); |
204 | ThisStore->setOperand(0, AdjustedThisPtr); |
205 | |
206 | if (!Thunk.Return.isEmpty()) { |
207 | |
208 | for (llvm::BasicBlock &BB : *Fn) { |
209 | llvm::Instruction *T = BB.getTerminator(); |
210 | if (isa<llvm::ReturnInst>(T)) { |
211 | RValue RV = RValue::get(T->getOperand(0)); |
212 | T->eraseFromParent(); |
213 | Builder.SetInsertPoint(&BB); |
214 | RV = PerformReturnAdjustment(*this, ResultType, RV, Thunk); |
215 | Builder.CreateRet(RV.getScalarVal()); |
216 | break; |
217 | } |
218 | } |
219 | } |
220 | |
221 | return Fn; |
222 | } |
223 | |
224 | void CodeGenFunction::StartThunk(llvm::Function *Fn, GlobalDecl GD, |
225 | const CGFunctionInfo &FnInfo, |
226 | bool IsUnprototyped) { |
227 | (0) . __assert_fail ("!CurGD.getDecl() && \"CurGD was already set!\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 227, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(!CurGD.getDecl() && "CurGD was already set!"); |
228 | CurGD = GD; |
229 | CurFuncIsThunk = true; |
230 | |
231 | |
232 | const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); |
233 | QualType ThisType = MD->getThisType(); |
234 | const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); |
235 | QualType ResultType; |
236 | if (IsUnprototyped) |
237 | ResultType = CGM.getContext().VoidTy; |
238 | else if (CGM.getCXXABI().HasThisReturn(GD)) |
239 | ResultType = ThisType; |
240 | else if (CGM.getCXXABI().hasMostDerivedReturn(GD)) |
241 | ResultType = CGM.getContext().VoidPtrTy; |
242 | else |
243 | ResultType = FPT->getReturnType(); |
244 | FunctionArgList FunctionArgs; |
245 | |
246 | |
247 | CGM.getCXXABI().buildThisParam(*this, FunctionArgs); |
248 | |
249 | |
250 | if (!IsUnprototyped) { |
251 | FunctionArgs.append(MD->param_begin(), MD->param_end()); |
252 | |
253 | if (isa<CXXDestructorDecl>(MD)) |
254 | CGM.getCXXABI().addImplicitStructorParams(*this, ResultType, |
255 | FunctionArgs); |
256 | } |
257 | |
258 | |
259 | auto NL = ApplyDebugLocation::CreateEmpty(*this); |
260 | StartFunction(GlobalDecl(), ResultType, Fn, FnInfo, FunctionArgs, |
261 | MD->getLocation()); |
262 | |
263 | auto AL = ApplyDebugLocation::CreateArtificial(*this); |
264 | |
265 | |
266 | CGM.getCXXABI().EmitInstanceFunctionProlog(*this); |
267 | CXXThisValue = CXXABIThisValue; |
268 | CurCodeDecl = MD; |
269 | CurFuncDecl = MD; |
270 | } |
271 | |
272 | void CodeGenFunction::FinishThunk() { |
273 | |
274 | |
275 | CurCodeDecl = nullptr; |
276 | CurFuncDecl = nullptr; |
277 | |
278 | FinishFunction(); |
279 | } |
280 | |
281 | void CodeGenFunction::EmitCallAndReturnForThunk(llvm::FunctionCallee Callee, |
282 | const ThunkInfo *Thunk, |
283 | bool IsUnprototyped) { |
284 | (0) . __assert_fail ("isa(CurGD.getDecl()) && \"Please use a new CGF for this thunk\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 285, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(isa<CXXMethodDecl>(CurGD.getDecl()) && |
285 | (0) . __assert_fail ("isa(CurGD.getDecl()) && \"Please use a new CGF for this thunk\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 285, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "Please use a new CGF for this thunk"); |
286 | const CXXMethodDecl *MD = cast<CXXMethodDecl>(CurGD.getDecl()); |
287 | |
288 | |
289 | llvm::Value *AdjustedThisPtr = |
290 | Thunk ? CGM.getCXXABI().performThisAdjustment( |
291 | *this, LoadCXXThisAddress(), Thunk->This) |
292 | : LoadCXXThis(); |
293 | |
294 | if (CurFnInfo->usesInAlloca() || IsUnprototyped) { |
295 | |
296 | |
297 | |
298 | if (Thunk && !Thunk->Return.isEmpty()) { |
299 | if (IsUnprototyped) |
300 | CGM.ErrorUnsupported( |
301 | MD, "return-adjusting thunk with incomplete parameter type"); |
302 | else |
303 | CGM.ErrorUnsupported( |
304 | MD, "non-trivial argument copy for return-adjusting thunk"); |
305 | } |
306 | EmitMustTailThunk(CurGD, AdjustedThisPtr, Callee); |
307 | return; |
308 | } |
309 | |
310 | |
311 | CallArgList CallArgs; |
312 | QualType ThisType = MD->getThisType(); |
313 | CallArgs.add(RValue::get(AdjustedThisPtr), ThisType); |
314 | |
315 | if (isa<CXXDestructorDecl>(MD)) |
316 | CGM.getCXXABI().adjustCallArgsForDestructorThunk(*this, CurGD, CallArgs); |
317 | |
318 | #ifndef NDEBUG |
319 | unsigned PrefixArgs = CallArgs.size() - 1; |
320 | #endif |
321 | |
322 | for (const ParmVarDecl *PD : MD->parameters()) |
323 | EmitDelegateCallArg(CallArgs, PD, SourceLocation()); |
324 | |
325 | const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); |
326 | |
327 | #ifndef NDEBUG |
328 | const CGFunctionInfo &CallFnInfo = CGM.getTypes().arrangeCXXMethodCall( |
329 | CallArgs, FPT, RequiredArgs::forPrototypePlus(FPT, 1), PrefixArgs); |
330 | getRegParm() && CallFnInfo.isNoReturn() == CurFnInfo->isNoReturn() && CallFnInfo.getCallingConvention() == CurFnInfo->getCallingConvention()", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 332, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(CallFnInfo.getRegParm() == CurFnInfo->getRegParm() && |
331 | getRegParm() && CallFnInfo.isNoReturn() == CurFnInfo->isNoReturn() && CallFnInfo.getCallingConvention() == CurFnInfo->getCallingConvention()", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 332, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> CallFnInfo.isNoReturn() == CurFnInfo->isNoReturn() && |
332 | getRegParm() && CallFnInfo.isNoReturn() == CurFnInfo->isNoReturn() && CallFnInfo.getCallingConvention() == CurFnInfo->getCallingConvention()", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 332, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> CallFnInfo.getCallingConvention() == CurFnInfo->getCallingConvention()); |
333 | (MD) || similar(CallFnInfo.getReturnInfo(), CallFnInfo.getReturnType(), CurFnInfo->getReturnInfo(), CurFnInfo->getReturnType())", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 335, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(isa<CXXDestructorDecl>(MD) || |
334 | (MD) || similar(CallFnInfo.getReturnInfo(), CallFnInfo.getReturnType(), CurFnInfo->getReturnInfo(), CurFnInfo->getReturnType())", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 335, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> similar(CallFnInfo.getReturnInfo(), CallFnInfo.getReturnType(), |
335 | (MD) || similar(CallFnInfo.getReturnInfo(), CallFnInfo.getReturnType(), CurFnInfo->getReturnInfo(), CurFnInfo->getReturnType())", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 335, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> CurFnInfo->getReturnInfo(), CurFnInfo->getReturnType())); |
336 | arg_size()", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 336, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(CallFnInfo.arg_size() == CurFnInfo->arg_size()); |
337 | for (unsigned i = 0, e = CurFnInfo->arg_size(); i != e; ++i) |
338 | arg_begin()[i].info, CurFnInfo->arg_begin()[i].type)", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 341, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(similar(CallFnInfo.arg_begin()[i].info, |
339 | arg_begin()[i].info, CurFnInfo->arg_begin()[i].type)", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 341, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> CallFnInfo.arg_begin()[i].type, |
340 | arg_begin()[i].info, CurFnInfo->arg_begin()[i].type)", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 341, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> CurFnInfo->arg_begin()[i].info, |
341 | arg_begin()[i].info, CurFnInfo->arg_begin()[i].type)", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 341, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> CurFnInfo->arg_begin()[i].type)); |
342 | #endif |
343 | |
344 | |
345 | QualType ResultType = CGM.getCXXABI().HasThisReturn(CurGD) |
346 | ? ThisType |
347 | : CGM.getCXXABI().hasMostDerivedReturn(CurGD) |
348 | ? CGM.getContext().VoidPtrTy |
349 | : FPT->getReturnType(); |
350 | ReturnValueSlot Slot; |
351 | if (!ResultType->isVoidType() && |
352 | CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect) |
353 | Slot = ReturnValueSlot(ReturnValue, ResultType.isVolatileQualified()); |
354 | |
355 | |
356 | llvm::CallBase *CallOrInvoke; |
357 | RValue RV = EmitCall(*CurFnInfo, CGCallee::forDirect(Callee, CurGD), Slot, |
358 | CallArgs, &CallOrInvoke); |
359 | |
360 | |
361 | if (Thunk && !Thunk->Return.isEmpty()) |
362 | RV = PerformReturnAdjustment(*this, ResultType, RV, *Thunk); |
363 | else if (llvm::CallInst* Call = dyn_cast<llvm::CallInst>(CallOrInvoke)) |
364 | Call->setTailCallKind(llvm::CallInst::TCK_Tail); |
365 | |
366 | |
367 | if (!ResultType->isVoidType() && Slot.isNull()) |
368 | CGM.getCXXABI().EmitReturnFromThunk(*this, RV, ResultType); |
369 | |
370 | |
371 | AutoreleaseResult = false; |
372 | |
373 | FinishThunk(); |
374 | } |
375 | |
376 | void CodeGenFunction::EmitMustTailThunk(GlobalDecl GD, |
377 | llvm::Value *AdjustedThisPtr, |
378 | llvm::FunctionCallee Callee) { |
379 | |
380 | |
381 | |
382 | |
383 | SmallVector<llvm::Value *, 8> Args; |
384 | for (llvm::Argument &A : CurFn->args()) |
385 | Args.push_back(&A); |
386 | |
387 | |
388 | const ABIArgInfo &ThisAI = CurFnInfo->arg_begin()->info; |
389 | if (ThisAI.isDirect()) { |
390 | const ABIArgInfo &RetAI = CurFnInfo->getReturnInfo(); |
391 | int ThisArgNo = RetAI.isIndirect() && !RetAI.isSRetAfterThis() ? 1 : 0; |
392 | llvm::Type *ThisType = Args[ThisArgNo]->getType(); |
393 | if (ThisType != AdjustedThisPtr->getType()) |
394 | AdjustedThisPtr = Builder.CreateBitCast(AdjustedThisPtr, ThisType); |
395 | Args[ThisArgNo] = AdjustedThisPtr; |
396 | } else { |
397 | (0) . __assert_fail ("ThisAI.isInAlloca() && \"this is passed directly or inalloca\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 397, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(ThisAI.isInAlloca() && "this is passed directly or inalloca"); |
398 | Address ThisAddr = GetAddrOfLocalVar(CXXABIThisDecl); |
399 | llvm::Type *ThisType = ThisAddr.getElementType(); |
400 | if (ThisType != AdjustedThisPtr->getType()) |
401 | AdjustedThisPtr = Builder.CreateBitCast(AdjustedThisPtr, ThisType); |
402 | Builder.CreateStore(AdjustedThisPtr, ThisAddr); |
403 | } |
404 | |
405 | |
406 | |
407 | llvm::CallInst *Call = Builder.CreateCall(Callee, Args); |
408 | Call->setTailCallKind(llvm::CallInst::TCK_MustTail); |
409 | |
410 | |
411 | unsigned CallingConv; |
412 | llvm::AttributeList Attrs; |
413 | CGM.ConstructAttributeList(Callee.getCallee()->getName(), *CurFnInfo, GD, |
414 | Attrs, CallingConv, ); |
415 | Call->setAttributes(Attrs); |
416 | Call->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv)); |
417 | |
418 | if (Call->getType()->isVoidTy()) |
419 | Builder.CreateRetVoid(); |
420 | else |
421 | Builder.CreateRet(Call); |
422 | |
423 | |
424 | |
425 | EmitBlock(createBasicBlock()); |
426 | FinishFunction(); |
427 | } |
428 | |
429 | void CodeGenFunction::generateThunk(llvm::Function *Fn, |
430 | const CGFunctionInfo &FnInfo, GlobalDecl GD, |
431 | const ThunkInfo &Thunk, |
432 | bool IsUnprototyped) { |
433 | StartThunk(Fn, GD, FnInfo, IsUnprototyped); |
434 | |
435 | auto AL = ApplyDebugLocation::CreateArtificial(*this); |
436 | |
437 | |
438 | |
439 | llvm::Type *Ty; |
440 | if (IsUnprototyped) |
441 | Ty = llvm::StructType::get(getLLVMContext()); |
442 | else |
443 | Ty = CGM.getTypes().GetFunctionType(FnInfo); |
444 | |
445 | llvm::Constant *Callee = CGM.GetAddrOfFunction(GD, Ty, ); |
446 | |
447 | |
448 | if (IsUnprototyped) |
449 | Callee = llvm::ConstantExpr::getBitCast(Callee, Fn->getType()); |
450 | |
451 | |
452 | EmitCallAndReturnForThunk(llvm::FunctionCallee(Fn->getFunctionType(), Callee), |
453 | &Thunk, IsUnprototyped); |
454 | } |
455 | |
456 | static bool shouldEmitVTableThunk(CodeGenModule &CGM, const CXXMethodDecl *MD, |
457 | bool IsUnprototyped, bool ForVTable) { |
458 | |
459 | |
460 | if (CGM.getTarget().getCXXABI().isMicrosoft()) |
461 | return true; |
462 | |
463 | |
464 | |
465 | |
466 | |
467 | if (ForVTable) |
468 | return CGM.getCodeGenOpts().OptimizationLevel && !IsUnprototyped; |
469 | |
470 | |
471 | return true; |
472 | } |
473 | |
474 | llvm::Constant *CodeGenVTables::maybeEmitThunk(GlobalDecl GD, |
475 | const ThunkInfo &TI, |
476 | bool ForVTable) { |
477 | const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); |
478 | |
479 | |
480 | |
481 | |
482 | SmallString<256> Name; |
483 | MangleContext &MCtx = CGM.getCXXABI().getMangleContext(); |
484 | llvm::raw_svector_ostream Out(Name); |
485 | if (const CXXDestructorDecl *DD = dyn_cast<CXXDestructorDecl>(MD)) |
486 | MCtx.mangleCXXDtorThunk(DD, GD.getDtorType(), TI.This, Out); |
487 | else |
488 | MCtx.mangleThunk(MD, TI, Out); |
489 | llvm::Type *ThunkVTableTy = CGM.getTypes().GetFunctionTypeForVTable(GD); |
490 | llvm::Constant *Thunk = CGM.GetAddrOfThunk(Name, ThunkVTableTy, GD); |
491 | |
492 | |
493 | bool IsUnprototyped = !CGM.getTypes().isFuncTypeConvertible( |
494 | MD->getType()->castAs<FunctionType>()); |
495 | if (!shouldEmitVTableThunk(CGM, MD, IsUnprototyped, ForVTable)) |
496 | return Thunk; |
497 | |
498 | |
499 | |
500 | const CGFunctionInfo &FnInfo = |
501 | IsUnprototyped ? CGM.getTypes().arrangeUnprototypedMustTailThunk(MD) |
502 | : CGM.getTypes().arrangeGlobalDeclaration(GD); |
503 | llvm::FunctionType *ThunkFnTy = CGM.getTypes().GetFunctionType(FnInfo); |
504 | |
505 | |
506 | |
507 | llvm::Function *ThunkFn = cast<llvm::Function>(Thunk->stripPointerCasts()); |
508 | if (ThunkFn->getFunctionType() != ThunkFnTy) { |
509 | llvm::GlobalValue *OldThunkFn = ThunkFn; |
510 | |
511 | (0) . __assert_fail ("OldThunkFn->isDeclaration() && \"Shouldn't replace non-declaration\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 511, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(OldThunkFn->isDeclaration() && "Shouldn't replace non-declaration"); |
512 | |
513 | |
514 | OldThunkFn->setName(StringRef()); |
515 | ThunkFn = llvm::Function::Create(ThunkFnTy, llvm::Function::ExternalLinkage, |
516 | Name.str(), &CGM.getModule()); |
517 | CGM.SetLLVMFunctionAttributes(MD, FnInfo, ThunkFn); |
518 | |
519 | |
520 | if (!OldThunkFn->use_empty()) { |
521 | llvm::Constant *NewPtrForOldDecl = |
522 | llvm::ConstantExpr::getBitCast(ThunkFn, OldThunkFn->getType()); |
523 | OldThunkFn->replaceAllUsesWith(NewPtrForOldDecl); |
524 | } |
525 | |
526 | |
527 | OldThunkFn->eraseFromParent(); |
528 | } |
529 | |
530 | bool ABIHasKeyFunctions = CGM.getTarget().getCXXABI().hasKeyFunctions(); |
531 | bool UseAvailableExternallyLinkage = ForVTable && ABIHasKeyFunctions; |
532 | |
533 | if (!ThunkFn->isDeclaration()) { |
534 | if (!ABIHasKeyFunctions || UseAvailableExternallyLinkage) { |
535 | |
536 | return ThunkFn; |
537 | } |
538 | |
539 | setThunkProperties(CGM, TI, ThunkFn, ForVTable, GD); |
540 | return ThunkFn; |
541 | } |
542 | |
543 | |
544 | |
545 | |
546 | |
547 | if (IsUnprototyped) |
548 | ThunkFn->addFnAttr("thunk"); |
549 | |
550 | CGM.SetLLVMFunctionAttributesForDefinition(GD.getDecl(), ThunkFn); |
551 | |
552 | if (!IsUnprototyped && ThunkFn->isVarArg()) { |
553 | |
554 | |
555 | |
556 | |
557 | |
558 | if (UseAvailableExternallyLinkage) |
559 | return ThunkFn; |
560 | ThunkFn = CodeGenFunction(CGM).GenerateVarArgsThunk(ThunkFn, FnInfo, GD, |
561 | TI); |
562 | } else { |
563 | |
564 | CodeGenFunction(CGM).generateThunk(ThunkFn, FnInfo, GD, TI, IsUnprototyped); |
565 | } |
566 | |
567 | setThunkProperties(CGM, TI, ThunkFn, ForVTable, GD); |
568 | return ThunkFn; |
569 | } |
570 | |
571 | void CodeGenVTables::EmitThunks(GlobalDecl GD) { |
572 | const CXXMethodDecl *MD = |
573 | cast<CXXMethodDecl>(GD.getDecl())->getCanonicalDecl(); |
574 | |
575 | |
576 | if (isa<CXXDestructorDecl>(MD) && GD.getDtorType() == Dtor_Base) |
577 | return; |
578 | |
579 | const VTableContextBase::ThunkInfoVectorTy *ThunkInfoVector = |
580 | VTContext->getThunkInfo(GD); |
581 | |
582 | if (!ThunkInfoVector) |
583 | return; |
584 | |
585 | for (const ThunkInfo& Thunk : *ThunkInfoVector) |
586 | maybeEmitThunk(GD, Thunk, ); |
587 | } |
588 | |
589 | void CodeGenVTables::addVTableComponent( |
590 | ConstantArrayBuilder &builder, const VTableLayout &layout, |
591 | unsigned idx, llvm::Constant *rtti, unsigned &nextVTableThunkIndex) { |
592 | auto &component = layout.vtable_components()[idx]; |
593 | |
594 | auto addOffsetConstant = [&](CharUnits offset) { |
595 | builder.add(llvm::ConstantExpr::getIntToPtr( |
596 | llvm::ConstantInt::get(CGM.PtrDiffTy, offset.getQuantity()), |
597 | CGM.Int8PtrTy)); |
598 | }; |
599 | |
600 | switch (component.getKind()) { |
601 | case VTableComponent::CK_VCallOffset: |
602 | return addOffsetConstant(component.getVCallOffset()); |
603 | |
604 | case VTableComponent::CK_VBaseOffset: |
605 | return addOffsetConstant(component.getVBaseOffset()); |
606 | |
607 | case VTableComponent::CK_OffsetToTop: |
608 | return addOffsetConstant(component.getOffsetToTop()); |
609 | |
610 | case VTableComponent::CK_RTTI: |
611 | return builder.add(llvm::ConstantExpr::getBitCast(rtti, CGM.Int8PtrTy)); |
612 | |
613 | case VTableComponent::CK_FunctionPointer: |
614 | case VTableComponent::CK_CompleteDtorPointer: |
615 | case VTableComponent::CK_DeletingDtorPointer: { |
616 | GlobalDecl GD; |
617 | |
618 | |
619 | switch (component.getKind()) { |
620 | default: |
621 | llvm_unreachable("Unexpected vtable component kind"); |
622 | case VTableComponent::CK_FunctionPointer: |
623 | GD = component.getFunctionDecl(); |
624 | break; |
625 | case VTableComponent::CK_CompleteDtorPointer: |
626 | GD = GlobalDecl(component.getDestructorDecl(), Dtor_Complete); |
627 | break; |
628 | case VTableComponent::CK_DeletingDtorPointer: |
629 | GD = GlobalDecl(component.getDestructorDecl(), Dtor_Deleting); |
630 | break; |
631 | } |
632 | |
633 | if (CGM.getLangOpts().CUDA) { |
634 | |
635 | |
636 | |
637 | const CXXMethodDecl *MD = cast<CXXMethodDecl>(GD.getDecl()); |
638 | |
639 | |
640 | bool CanEmitMethod = |
641 | CGM.getLangOpts().CUDAIsDevice |
642 | ? MD->hasAttr<CUDADeviceAttr>() |
643 | : (MD->hasAttr<CUDAHostAttr>() || !MD->hasAttr<CUDADeviceAttr>()); |
644 | if (!CanEmitMethod) |
645 | return builder.addNullPointer(CGM.Int8PtrTy); |
646 | |
647 | } |
648 | |
649 | auto getSpecialVirtualFn = [&](StringRef name) { |
650 | llvm::FunctionType *fnTy = |
651 | llvm::FunctionType::get(CGM.VoidTy, ); |
652 | llvm::Constant *fn = cast<llvm::Constant>( |
653 | CGM.CreateRuntimeFunction(fnTy, name).getCallee()); |
654 | if (auto f = dyn_cast<llvm::Function>(fn)) |
655 | f->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); |
656 | return llvm::ConstantExpr::getBitCast(fn, CGM.Int8PtrTy); |
657 | }; |
658 | |
659 | llvm::Constant *fnPtr; |
660 | |
661 | |
662 | if (cast<CXXMethodDecl>(GD.getDecl())->isPure()) { |
663 | if (!PureVirtualFn) |
664 | PureVirtualFn = |
665 | getSpecialVirtualFn(CGM.getCXXABI().GetPureVirtualCallName()); |
666 | fnPtr = PureVirtualFn; |
667 | |
668 | |
669 | } else if (cast<CXXMethodDecl>(GD.getDecl())->isDeleted()) { |
670 | if (!DeletedVirtualFn) |
671 | DeletedVirtualFn = |
672 | getSpecialVirtualFn(CGM.getCXXABI().GetDeletedVirtualCallName()); |
673 | fnPtr = DeletedVirtualFn; |
674 | |
675 | |
676 | } else if (nextVTableThunkIndex < layout.vtable_thunks().size() && |
677 | layout.vtable_thunks()[nextVTableThunkIndex].first == idx) { |
678 | auto &thunkInfo = layout.vtable_thunks()[nextVTableThunkIndex].second; |
679 | |
680 | nextVTableThunkIndex++; |
681 | fnPtr = maybeEmitThunk(GD, thunkInfo, ); |
682 | |
683 | |
684 | } else { |
685 | llvm::Type *fnTy = CGM.getTypes().GetFunctionTypeForVTable(GD); |
686 | fnPtr = CGM.GetAddrOfFunction(GD, fnTy, ); |
687 | } |
688 | |
689 | fnPtr = llvm::ConstantExpr::getBitCast(fnPtr, CGM.Int8PtrTy); |
690 | builder.add(fnPtr); |
691 | return; |
692 | } |
693 | |
694 | case VTableComponent::CK_UnusedFunctionPointer: |
695 | return builder.addNullPointer(CGM.Int8PtrTy); |
696 | } |
697 | |
698 | llvm_unreachable("Unexpected vtable component kind"); |
699 | } |
700 | |
701 | llvm::Type *CodeGenVTables::getVTableType(const VTableLayout &layout) { |
702 | SmallVector<llvm::Type *, 4> tys; |
703 | for (unsigned i = 0, e = layout.getNumVTables(); i != e; ++i) { |
704 | tys.push_back(llvm::ArrayType::get(CGM.Int8PtrTy, layout.getVTableSize(i))); |
705 | } |
706 | |
707 | return llvm::StructType::get(CGM.getLLVMContext(), tys); |
708 | } |
709 | |
710 | void CodeGenVTables::createVTableInitializer(ConstantStructBuilder &builder, |
711 | const VTableLayout &layout, |
712 | llvm::Constant *rtti) { |
713 | unsigned nextVTableThunkIndex = 0; |
714 | for (unsigned i = 0, e = layout.getNumVTables(); i != e; ++i) { |
715 | auto vtableElem = builder.beginArray(CGM.Int8PtrTy); |
716 | size_t thisIndex = layout.getVTableOffset(i); |
717 | size_t nextIndex = thisIndex + layout.getVTableSize(i); |
718 | for (unsigned i = thisIndex; i != nextIndex; ++i) { |
719 | addVTableComponent(vtableElem, layout, i, rtti, nextVTableThunkIndex); |
720 | } |
721 | vtableElem.finishAndAddTo(builder); |
722 | } |
723 | } |
724 | |
725 | llvm::GlobalVariable * |
726 | CodeGenVTables::GenerateConstructionVTable(const CXXRecordDecl *RD, |
727 | const BaseSubobject &Base, |
728 | bool BaseIsVirtual, |
729 | llvm::GlobalVariable::LinkageTypes Linkage, |
730 | VTableAddressPointsMapTy& AddressPoints) { |
731 | if (CGDebugInfo *DI = CGM.getModuleDebugInfo()) |
732 | DI->completeClassData(Base.getBase()); |
733 | |
734 | std::unique_ptr<VTableLayout> VTLayout( |
735 | getItaniumVTableContext().createConstructionVTableLayout( |
736 | Base.getBase(), Base.getBaseOffset(), BaseIsVirtual, RD)); |
737 | |
738 | |
739 | AddressPoints = VTLayout->getAddressPoints(); |
740 | |
741 | |
742 | SmallString<256> OutName; |
743 | llvm::raw_svector_ostream Out(OutName); |
744 | cast<ItaniumMangleContext>(CGM.getCXXABI().getMangleContext()) |
745 | .mangleCXXCtorVTable(RD, Base.getBaseOffset().getQuantity(), |
746 | Base.getBase(), Out); |
747 | StringRef Name = OutName.str(); |
748 | |
749 | llvm::Type *VTType = getVTableType(*VTLayout); |
750 | |
751 | |
752 | |
753 | |
754 | |
755 | |
756 | if (Linkage == llvm::GlobalVariable::AvailableExternallyLinkage) |
757 | Linkage = llvm::GlobalVariable::InternalLinkage; |
758 | |
759 | unsigned Align = CGM.getDataLayout().getABITypeAlignment(VTType); |
760 | |
761 | |
762 | llvm::GlobalVariable *VTable = |
763 | CGM.CreateOrReplaceCXXRuntimeVariable(Name, VTType, Linkage, Align); |
764 | |
765 | |
766 | VTable->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global); |
767 | |
768 | llvm::Constant *RTTI = CGM.GetAddrOfRTTIDescriptor( |
769 | CGM.getContext().getTagDeclType(Base.getBase())); |
770 | |
771 | |
772 | ConstantInitBuilder builder(CGM); |
773 | auto components = builder.beginStruct(); |
774 | createVTableInitializer(components, *VTLayout, RTTI); |
775 | components.finishAndSetAsInitializer(VTable); |
776 | |
777 | |
778 | |
779 | (0) . __assert_fail ("!VTable->isDeclaration() && \"Shouldn't set properties on declaration\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 779, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(!VTable->isDeclaration() && "Shouldn't set properties on declaration"); |
780 | CGM.setGVProperties(VTable, RD); |
781 | |
782 | CGM.EmitVTableTypeMetadata(VTable, *VTLayout.get()); |
783 | |
784 | return VTable; |
785 | } |
786 | |
787 | static bool shouldEmitAvailableExternallyVTable(const CodeGenModule &CGM, |
788 | const CXXRecordDecl *RD) { |
789 | return CGM.getCodeGenOpts().OptimizationLevel > 0 && |
790 | CGM.getCXXABI().canSpeculativelyEmitVTable(RD); |
791 | } |
792 | |
793 | |
794 | |
795 | |
796 | llvm::GlobalVariable::LinkageTypes |
797 | CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) { |
798 | if (!RD->isExternallyVisible()) |
799 | return llvm::GlobalVariable::InternalLinkage; |
800 | |
801 | |
802 | |
803 | const CXXMethodDecl *keyFunction = Context.getCurrentKeyFunction(RD); |
804 | if (keyFunction && !RD->hasAttr<DLLImportAttr>()) { |
805 | |
806 | |
807 | const FunctionDecl *def = nullptr; |
808 | if (keyFunction->hasBody(def)) |
809 | keyFunction = cast<CXXMethodDecl>(def); |
810 | |
811 | switch (keyFunction->getTemplateSpecializationKind()) { |
812 | case TSK_Undeclared: |
813 | case TSK_ExplicitSpecialization: |
814 | (0) . __assert_fail ("(def || CodeGenOpts.OptimizationLevel > 0 || CodeGenOpts.getDebugInfo() != codegenoptions..NoDebugInfo) && \"Shouldn't query vtable linkage without key function, \" \"optimizations, or debug info\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 817, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert((def || CodeGenOpts.OptimizationLevel > 0 || |
815 | (0) . __assert_fail ("(def || CodeGenOpts.OptimizationLevel > 0 || CodeGenOpts.getDebugInfo() != codegenoptions..NoDebugInfo) && \"Shouldn't query vtable linkage without key function, \" \"optimizations, or debug info\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 817, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> CodeGenOpts.getDebugInfo() != codegenoptions::NoDebugInfo) && |
816 | (0) . __assert_fail ("(def || CodeGenOpts.OptimizationLevel > 0 || CodeGenOpts.getDebugInfo() != codegenoptions..NoDebugInfo) && \"Shouldn't query vtable linkage without key function, \" \"optimizations, or debug info\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 817, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "Shouldn't query vtable linkage without key function, " |
817 | (0) . __assert_fail ("(def || CodeGenOpts.OptimizationLevel > 0 || CodeGenOpts.getDebugInfo() != codegenoptions..NoDebugInfo) && \"Shouldn't query vtable linkage without key function, \" \"optimizations, or debug info\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 817, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "optimizations, or debug info"); |
818 | if (!def && CodeGenOpts.OptimizationLevel > 0) |
819 | return llvm::GlobalVariable::AvailableExternallyLinkage; |
820 | |
821 | if (keyFunction->isInlined()) |
822 | return !Context.getLangOpts().AppleKext ? |
823 | llvm::GlobalVariable::LinkOnceODRLinkage : |
824 | llvm::Function::InternalLinkage; |
825 | |
826 | return llvm::GlobalVariable::ExternalLinkage; |
827 | |
828 | case TSK_ImplicitInstantiation: |
829 | return !Context.getLangOpts().AppleKext ? |
830 | llvm::GlobalVariable::LinkOnceODRLinkage : |
831 | llvm::Function::InternalLinkage; |
832 | |
833 | case TSK_ExplicitInstantiationDefinition: |
834 | return !Context.getLangOpts().AppleKext ? |
835 | llvm::GlobalVariable::WeakODRLinkage : |
836 | llvm::Function::InternalLinkage; |
837 | |
838 | case TSK_ExplicitInstantiationDeclaration: |
839 | llvm_unreachable("Should not have been asked to emit this"); |
840 | } |
841 | } |
842 | |
843 | |
844 | |
845 | if (Context.getLangOpts().AppleKext) |
846 | return llvm::Function::InternalLinkage; |
847 | |
848 | llvm::GlobalVariable::LinkageTypes DiscardableODRLinkage = |
849 | llvm::GlobalValue::LinkOnceODRLinkage; |
850 | llvm::GlobalVariable::LinkageTypes NonDiscardableODRLinkage = |
851 | llvm::GlobalValue::WeakODRLinkage; |
852 | if (RD->hasAttr<DLLExportAttr>()) { |
853 | |
854 | DiscardableODRLinkage = NonDiscardableODRLinkage; |
855 | } else if (RD->hasAttr<DLLImportAttr>()) { |
856 | |
857 | DiscardableODRLinkage = llvm::GlobalVariable::AvailableExternallyLinkage; |
858 | NonDiscardableODRLinkage = llvm::GlobalVariable::AvailableExternallyLinkage; |
859 | } |
860 | |
861 | switch (RD->getTemplateSpecializationKind()) { |
862 | case TSK_Undeclared: |
863 | case TSK_ExplicitSpecialization: |
864 | case TSK_ImplicitInstantiation: |
865 | return DiscardableODRLinkage; |
866 | |
867 | case TSK_ExplicitInstantiationDeclaration: |
868 | |
869 | |
870 | if (getTarget().getCXXABI().isMicrosoft()) |
871 | return DiscardableODRLinkage; |
872 | return shouldEmitAvailableExternallyVTable(*this, RD) |
873 | ? llvm::GlobalVariable::AvailableExternallyLinkage |
874 | : llvm::GlobalVariable::ExternalLinkage; |
875 | |
876 | case TSK_ExplicitInstantiationDefinition: |
877 | return NonDiscardableODRLinkage; |
878 | } |
879 | |
880 | llvm_unreachable("Invalid TemplateSpecializationKind!"); |
881 | } |
882 | |
883 | |
884 | |
885 | |
886 | |
887 | |
888 | |
889 | void CodeGenModule::EmitVTable(CXXRecordDecl *theClass) { |
890 | VTables.GenerateClassData(theClass); |
891 | } |
892 | |
893 | void |
894 | CodeGenVTables::GenerateClassData(const CXXRecordDecl *RD) { |
895 | if (CGDebugInfo *DI = CGM.getModuleDebugInfo()) |
896 | DI->completeClassData(RD); |
897 | |
898 | if (RD->getNumVBases()) |
899 | CGM.getCXXABI().emitVirtualInheritanceTables(RD); |
900 | |
901 | CGM.getCXXABI().emitVTableDefinitions(*this, RD); |
902 | } |
903 | |
904 | |
905 | |
906 | |
907 | |
908 | |
909 | |
910 | |
911 | |
912 | |
913 | |
914 | bool CodeGenVTables::isVTableExternal(const CXXRecordDecl *RD) { |
915 | (0) . __assert_fail ("RD->isDynamicClass() && \"Non-dynamic classes have no VTable.\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 915, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(RD->isDynamicClass() && "Non-dynamic classes have no VTable."); |
916 | |
917 | |
918 | |
919 | if (CGM.getTarget().getCXXABI().isMicrosoft()) |
920 | return false; |
921 | |
922 | |
923 | |
924 | TemplateSpecializationKind TSK = RD->getTemplateSpecializationKind(); |
925 | if (TSK == TSK_ExplicitInstantiationDeclaration) |
926 | return true; |
927 | |
928 | |
929 | |
930 | if (TSK == TSK_ImplicitInstantiation || |
931 | TSK == TSK_ExplicitInstantiationDefinition) |
932 | return false; |
933 | |
934 | |
935 | |
936 | const CXXMethodDecl *keyFunction = CGM.getContext().getCurrentKeyFunction(RD); |
937 | if (!keyFunction) |
938 | return false; |
939 | |
940 | |
941 | |
942 | return !keyFunction->hasBody(); |
943 | } |
944 | |
945 | |
946 | |
947 | |
948 | static bool shouldEmitVTableAtEndOfTranslationUnit(CodeGenModule &CGM, |
949 | const CXXRecordDecl *RD) { |
950 | |
951 | if (!CGM.getVTables().isVTableExternal(RD)) |
952 | return true; |
953 | |
954 | |
955 | return shouldEmitAvailableExternallyVTable(CGM, RD); |
956 | } |
957 | |
958 | |
959 | |
960 | |
961 | void CodeGenModule::EmitDeferredVTables() { |
962 | #ifndef NDEBUG |
963 | |
964 | |
965 | size_t savedSize = DeferredVTables.size(); |
966 | #endif |
967 | |
968 | for (const CXXRecordDecl *RD : DeferredVTables) |
969 | if (shouldEmitVTableAtEndOfTranslationUnit(*this, RD)) |
970 | VTables.GenerateClassData(RD); |
971 | else if (shouldOpportunisticallyEmitVTables()) |
972 | OpportunisticVTables.push_back(RD); |
973 | |
974 | (0) . __assert_fail ("savedSize == DeferredVTables.size() && \"deferred extra vtables during vtable emission?\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 975, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(savedSize == DeferredVTables.size() && |
975 | (0) . __assert_fail ("savedSize == DeferredVTables.size() && \"deferred extra vtables during vtable emission?\"", "/home/seafit/code_projects/clang_source/clang/lib/CodeGen/CGVTables.cpp", 975, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true"> "deferred extra vtables during vtable emission?"); |
976 | DeferredVTables.clear(); |
977 | } |
978 | |
979 | bool CodeGenModule::HasHiddenLTOVisibility(const CXXRecordDecl *RD) { |
980 | LinkageInfo LV = RD->getLinkageAndVisibility(); |
981 | if (!isExternallyVisible(LV.getLinkage())) |
982 | return true; |
983 | |
984 | if (RD->hasAttr<LTOVisibilityPublicAttr>() || RD->hasAttr<UuidAttr>()) |
985 | return false; |
986 | |
987 | if (getTriple().isOSBinFormatCOFF()) { |
988 | if (RD->hasAttr<DLLExportAttr>() || RD->hasAttr<DLLImportAttr>()) |
989 | return false; |
990 | } else { |
991 | if (LV.getVisibility() != HiddenVisibility) |
992 | return false; |
993 | } |
994 | |
995 | if (getCodeGenOpts().LTOVisibilityPublicStd) { |
996 | const DeclContext *DC = RD; |
997 | while (1) { |
998 | auto *D = cast<Decl>(DC); |
999 | DC = DC->getParent(); |
1000 | if (isa<TranslationUnitDecl>(DC->getRedeclContext())) { |
1001 | if (auto *ND = dyn_cast<NamespaceDecl>(D)) |
1002 | if (const IdentifierInfo *II = ND->getIdentifier()) |
1003 | if (II->isStr("std") || II->isStr("stdext")) |
1004 | return false; |
1005 | break; |
1006 | } |
1007 | } |
1008 | } |
1009 | |
1010 | return true; |
1011 | } |
1012 | |
1013 | void CodeGenModule::EmitVTableTypeMetadata(llvm::GlobalVariable *VTable, |
1014 | const VTableLayout &VTLayout) { |
1015 | if (!getCodeGenOpts().LTOUnit) |
1016 | return; |
1017 | |
1018 | CharUnits PointerWidth = |
1019 | Context.toCharUnitsFromBits(Context.getTargetInfo().getPointerWidth(0)); |
1020 | |
1021 | typedef std::pair<const CXXRecordDecl *, unsigned> AddressPoint; |
1022 | std::vector<AddressPoint> AddressPoints; |
1023 | for (auto &&AP : VTLayout.getAddressPoints()) |
1024 | AddressPoints.push_back(std::make_pair( |
1025 | AP.first.getBase(), VTLayout.getVTableOffset(AP.second.VTableIndex) + |
1026 | AP.second.AddressPointIndex)); |
1027 | |
1028 | |
1029 | llvm::sort(AddressPoints, [this](const AddressPoint &AP1, |
1030 | const AddressPoint &AP2) { |
1031 | if (&AP1 == &AP2) |
1032 | return false; |
1033 | |
1034 | std::string S1; |
1035 | llvm::raw_string_ostream O1(S1); |
1036 | getCXXABI().getMangleContext().mangleTypeName( |
1037 | QualType(AP1.first->getTypeForDecl(), 0), O1); |
1038 | O1.flush(); |
1039 | |
1040 | std::string S2; |
1041 | llvm::raw_string_ostream O2(S2); |
1042 | getCXXABI().getMangleContext().mangleTypeName( |
1043 | QualType(AP2.first->getTypeForDecl(), 0), O2); |
1044 | O2.flush(); |
1045 | |
1046 | if (S1 < S2) |
1047 | return true; |
1048 | if (S1 != S2) |
1049 | return false; |
1050 | |
1051 | return AP1.second < AP2.second; |
1052 | }); |
1053 | |
1054 | ArrayRef<VTableComponent> Comps = VTLayout.vtable_components(); |
1055 | for (auto AP : AddressPoints) { |
1056 | |
1057 | AddVTableTypeMetadata(VTable, PointerWidth * AP.second, AP.first); |
1058 | |
1059 | |
1060 | |
1061 | |
1062 | |
1063 | for (unsigned I = 0; I != Comps.size(); ++I) { |
1064 | if (Comps[I].getKind() != VTableComponent::CK_FunctionPointer) |
1065 | continue; |
1066 | llvm::Metadata *MD = CreateMetadataIdentifierForVirtualMemPtrType( |
1067 | Context.getMemberPointerType( |
1068 | Comps[I].getFunctionDecl()->getType(), |
1069 | Context.getRecordType(AP.first).getTypePtr())); |
1070 | VTable->addTypeMetadata((PointerWidth * I).getQuantity(), MD); |
1071 | } |
1072 | } |
1073 | } |
1074 | |