blob: 420e275becd119201ce945ff4a0361ddbadf7db2 [file] [log] [blame]
Anders Carlsson756b5c42009-10-30 01:42:31 +00001//===--- CGException.cpp - Emit LLVM Code for C++ exceptions --------------===//
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++ exception related code generation.
11//
12//===----------------------------------------------------------------------===//
13
Mike Stump2bf701e2009-11-20 23:44:51 +000014#include "clang/AST/StmtCXX.h"
15
16#include "llvm/Intrinsics.h"
17
Anders Carlsson756b5c42009-10-30 01:42:31 +000018#include "CodeGenFunction.h"
19using namespace clang;
20using namespace CodeGen;
21
Anders Carlssond3379292009-10-30 02:27:02 +000022static llvm::Constant *getAllocateExceptionFn(CodeGenFunction &CGF) {
23 // void *__cxa_allocate_exception(size_t thrown_size);
24 const llvm::Type *SizeTy = CGF.ConvertType(CGF.getContext().getSizeType());
25 std::vector<const llvm::Type*> Args(1, SizeTy);
26
27 const llvm::FunctionType *FTy =
28 llvm::FunctionType::get(llvm::Type::getInt8PtrTy(CGF.getLLVMContext()),
29 Args, false);
30
31 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_allocate_exception");
32}
33
34static llvm::Constant *getThrowFn(CodeGenFunction &CGF) {
35 // void __cxa_throw (void *thrown_exception, std::type_info *tinfo,
36 // void (*dest) (void *) );
37
38 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
39 std::vector<const llvm::Type*> Args(3, Int8PtrTy);
40
41 const llvm::FunctionType *FTy =
Mike Stumpb4eea692009-11-20 00:56:31 +000042 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
43 Args, false);
Anders Carlssond3379292009-10-30 02:27:02 +000044
45 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw");
46}
47
Mike Stumpb4eea692009-11-20 00:56:31 +000048static llvm::Constant *getReThrowFn(CodeGenFunction &CGF) {
49 // void __cxa_rethrow ();
50
51 const llvm::FunctionType *FTy =
52 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
53
54 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_rethrow");
55}
56
Mike Stump2bf701e2009-11-20 23:44:51 +000057static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) {
Mike Stump0f590be2009-12-01 03:41:18 +000058 // void* __cxa_begin_catch ();
Mike Stump2bf701e2009-11-20 23:44:51 +000059
60 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
61 std::vector<const llvm::Type*> Args(1, Int8PtrTy);
62
63 const llvm::FunctionType *FTy =
Mike Stump0f590be2009-12-01 03:41:18 +000064 llvm::FunctionType::get(Int8PtrTy, Args, false);
Mike Stump2bf701e2009-11-20 23:44:51 +000065
66 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
67}
68
69static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) {
70 // void __cxa_end_catch ();
71
72 const llvm::FunctionType *FTy =
73 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
74
75 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
76}
77
Mike Stump0f590be2009-12-01 03:41:18 +000078// FIXME: Eventually this will all go into the backend. Set from the target for
79// now.
80static int using_sjlj_exceptions = 0;
81
82static llvm::Constant *getUnwindResumeOrRethrowFn(CodeGenFunction &CGF) {
83 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(CGF.getLLVMContext());
84 std::vector<const llvm::Type*> Args(1, Int8PtrTy);
85
86 const llvm::FunctionType *FTy =
87 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args,
88 false);
89
90 if (using_sjlj_exceptions)
91 return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_SjLj_Resume");
92 return CGF.CGM.CreateRuntimeFunction(FTy, "_Unwind_Resume_or_Rethrow");
93}
94
95// CopyObject - Utility to copy an object. Calls copy constructor as necessary.
96// N is casted to the right type.
97static void CopyObject(CodeGenFunction &CGF, const Expr *E, llvm::Value *N) {
98 QualType ObjectType = E->getType();
99
100 // Store the throw exception in the exception object.
101 if (!CGF.hasAggregateLLVMType(ObjectType)) {
102 llvm::Value *Value = CGF.EmitScalarExpr(E);
103 const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0);
104
105 CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy));
106 } else {
107 const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0);
108 const CXXRecordDecl *RD;
109 RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl());
110 llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty);
111 if (RD->hasTrivialCopyConstructor()) {
112 CGF.EmitAggExpr(E, This, false);
113 } else if (CXXConstructorDecl *CopyCtor
114 = RD->getCopyConstructor(CGF.getContext(), 0)) {
115 // FIXME: region management
116 llvm::Value *Src = CGF.EmitLValue(E).getAddress();
117
118 // Stolen from EmitClassAggrMemberwiseCopy
119 llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor,
120 Ctor_Complete);
121 CallArgList CallArgs;
122 CallArgs.push_back(std::make_pair(RValue::get(This),
123 CopyCtor->getThisType(CGF.getContext())));
124
125 // Push the Src ptr.
126 CallArgs.push_back(std::make_pair(RValue::get(Src),
127 CopyCtor->getParamDecl(0)->getType()));
128 QualType ResultType =
129 CopyCtor->getType()->getAs<FunctionType>()->getResultType();
130 CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
131 Callee, CallArgs, CopyCtor);
132 // FIXME: region management
133 } else
134 CGF.ErrorUnsupported(E, "uncopyable object");
135 }
136}
137
138// CopyObject - Utility to copy an object. Calls copy constructor as necessary.
139// N is casted to the right type.
140static void CopyObject(CodeGenFunction &CGF, QualType ObjectType,
141 llvm::Value *E, llvm::Value *N) {
142 // Store the throw exception in the exception object.
143 if (!CGF.hasAggregateLLVMType(ObjectType)) {
144 llvm::Value *Value = E;
145 const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0);
146
147 CGF.Builder.CreateStore(Value, CGF.Builder.CreateBitCast(N, ValuePtrTy));
148 } else {
149 const llvm::Type *Ty = CGF.ConvertType(ObjectType)->getPointerTo(0);
150 const CXXRecordDecl *RD;
151 RD = cast<CXXRecordDecl>(ObjectType->getAs<RecordType>()->getDecl());
152 llvm::Value *This = CGF.Builder.CreateBitCast(N, Ty);
153 if (RD->hasTrivialCopyConstructor()) {
154 CGF.EmitAggregateCopy(This, E, ObjectType);
155 } else if (CXXConstructorDecl *CopyCtor
156 = RD->getCopyConstructor(CGF.getContext(), 0)) {
157 // FIXME: region management
158 llvm::Value *Src = E;
159
160 // Stolen from EmitClassAggrMemberwiseCopy
161 llvm::Value *Callee = CGF.CGM.GetAddrOfCXXConstructor(CopyCtor,
162 Ctor_Complete);
163 CallArgList CallArgs;
164 CallArgs.push_back(std::make_pair(RValue::get(This),
165 CopyCtor->getThisType(CGF.getContext())));
166
167 // Push the Src ptr.
168 CallArgs.push_back(std::make_pair(RValue::get(Src),
169 CopyCtor->getParamDecl(0)->getType()));
170 QualType ResultType =
171 CopyCtor->getType()->getAs<FunctionType>()->getResultType();
172 CGF.EmitCall(CGF.CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
173 Callee, CallArgs, CopyCtor);
174 // FIXME: region management
175 } else
176 llvm::llvm_unreachable("uncopyable object");
177 }
178}
179
Anders Carlsson756b5c42009-10-30 01:42:31 +0000180void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
Anders Carlssond3379292009-10-30 02:27:02 +0000181 if (!E->getSubExpr()) {
Mike Stumpb4eea692009-11-20 00:56:31 +0000182 Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn();
183 Builder.CreateUnreachable();
184
185 // Clear the insertion point to indicate we are in unreachable code.
186 Builder.ClearInsertionPoint();
Anders Carlssond3379292009-10-30 02:27:02 +0000187 return;
188 }
189
190 QualType ThrowType = E->getSubExpr()->getType();
Anders Carlssond3379292009-10-30 02:27:02 +0000191 // FIXME: Handle cleanup.
192 if (!CleanupEntries.empty()){
Mike Stump2bf701e2009-11-20 23:44:51 +0000193 ErrorUnsupported(E, "throw expression with cleanup entries");
Anders Carlssond3379292009-10-30 02:27:02 +0000194 return;
195 }
196
197 // Now allocate the exception object.
198 const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
199 uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8;
200
201 llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this);
202 llvm::Value *ExceptionPtr =
203 Builder.CreateCall(AllocExceptionFn,
204 llvm::ConstantInt::get(SizeTy, TypeSize),
205 "exception");
206
Mike Stump0f590be2009-12-01 03:41:18 +0000207 CopyObject(*this, E->getSubExpr(), ExceptionPtr);
Anders Carlssond3379292009-10-30 02:27:02 +0000208
209 // Now throw the exception.
210 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
Mike Stump23886d02009-11-20 00:43:57 +0000211 llvm::Constant *TypeInfo = CGM.GenerateRtti(ThrowType);
Anders Carlssond3379292009-10-30 02:27:02 +0000212 llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy);
213
214 llvm::CallInst *ThrowCall =
215 Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor);
216 ThrowCall->setDoesNotReturn();
217 Builder.CreateUnreachable();
218
219 // Clear the insertion point to indicate we are in unreachable code.
220 Builder.ClearInsertionPoint();
Anders Carlsson756b5c42009-10-30 01:42:31 +0000221}
Mike Stump2bf701e2009-11-20 23:44:51 +0000222
223void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
Mike Stump0f590be2009-12-01 03:41:18 +0000224#if 1
Mike Stump2bf701e2009-11-20 23:44:51 +0000225 EmitStmt(S.getTryBlock());
Mike Stump0f590be2009-12-01 03:41:18 +0000226 if (0) {
227 getBeginCatchFn(*this);
228 getEndCatchFn(*this);
229 getUnwindResumeOrRethrowFn(*this);
230 CopyObject(*this, QualType(), 0, 0);
231 }
232#else
233 // FIXME: The below is still just a sketch of the code we need.
Mike Stump2bf701e2009-11-20 23:44:51 +0000234 // Pointer to the personality function
235 llvm::Constant *Personality =
236 CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
237 (VMContext),
238 true),
239 "__gxx_personality_v0");
240 Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
241
Mike Stump2bf701e2009-11-20 23:44:51 +0000242 llvm::BasicBlock *PrevLandingPad = getInvokeDest();
243 llvm::BasicBlock *TryHandler = createBasicBlock("try.handler");
Mike Stump0f590be2009-12-01 03:41:18 +0000244#if 0
Mike Stump2bf701e2009-11-20 23:44:51 +0000245 llvm::BasicBlock *FinallyBlock = createBasicBlock("finally");
Mike Stump0f590be2009-12-01 03:41:18 +0000246#endif
247 llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw");
Mike Stump2bf701e2009-11-20 23:44:51 +0000248 llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end");
249
Mike Stump0f590be2009-12-01 03:41:18 +0000250#if 0
Mike Stump2bf701e2009-11-20 23:44:51 +0000251 // Push an EH context entry, used for handling rethrows.
252 PushCleanupBlock(FinallyBlock);
Mike Stump0f590be2009-12-01 03:41:18 +0000253#endif
Mike Stump2bf701e2009-11-20 23:44:51 +0000254
255 // Emit the statements in the try {} block
256 setInvokeDest(TryHandler);
257
258 EmitStmt(S.getTryBlock());
259
260 // Jump to end if there is no exception
261 EmitBranchThroughCleanup(FinallyEnd);
262
263 // Emit the handlers
264 EmitBlock(TryHandler);
265
266 const llvm::IntegerType *Int8Ty;
267 const llvm::PointerType *PtrToInt8Ty;
268 Int8Ty = llvm::Type::getInt8Ty(VMContext);
269 // C string type. Used in lots of places.
270 PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
Mike Stump0f590be2009-12-01 03:41:18 +0000271 llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
272 llvm::SmallVector<llvm::Value*, 8> SelectorArgs;
Mike Stump2bf701e2009-11-20 23:44:51 +0000273 llvm::Value *llvm_eh_exception =
274 CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
275 llvm::Value *llvm_eh_selector =
276 CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
Mike Stump0f590be2009-12-01 03:41:18 +0000277 llvm::Value *llvm_eh_typeid_for =
278 CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for);
Mike Stump2bf701e2009-11-20 23:44:51 +0000279 // Exception object
280 llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
Mike Stump0f590be2009-12-01 03:41:18 +0000281 llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow");
Mike Stump2bf701e2009-11-20 23:44:51 +0000282
Mike Stump0f590be2009-12-01 03:41:18 +0000283 SelectorArgs.push_back(Exc);
284 SelectorArgs.push_back(Personality);
Mike Stump2bf701e2009-11-20 23:44:51 +0000285
Mike Stump0f590be2009-12-01 03:41:18 +0000286 bool HasCatchAll = false;
Mike Stump2bf701e2009-11-20 23:44:51 +0000287 for (unsigned i = 0; i<S.getNumHandlers(); ++i) {
288 const CXXCatchStmt *C = S.getHandler(i);
Mike Stump0f590be2009-12-01 03:41:18 +0000289 VarDecl *CatchParam = C->getExceptionDecl();
290 if (CatchParam) {
291 llvm::Value *EHType = CGM.GenerateRtti(C->getCaughtType().getNonReferenceType());
292 SelectorArgs.push_back(EHType);
Mike Stump2bf701e2009-11-20 23:44:51 +0000293 } else {
294 // null indicates catch all
Mike Stump0f590be2009-12-01 03:41:18 +0000295 SelectorArgs.push_back(Null);
296 HasCatchAll = true;
Mike Stump2bf701e2009-11-20 23:44:51 +0000297 }
298 }
299
Mike Stump0f590be2009-12-01 03:41:18 +0000300 // We use a cleanup unless there was already a catch all.
301 if (!HasCatchAll) {
302 SelectorArgs.push_back(Null);
303 }
Mike Stump2bf701e2009-11-20 23:44:51 +0000304
Mike Stump0f590be2009-12-01 03:41:18 +0000305 // Find which handler was matched.
306 llvm::Value *Selector
307 = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(),
308 SelectorArgs.end(), "selector");
Mike Stump2bf701e2009-11-20 23:44:51 +0000309 for (unsigned i = 0; i<S.getNumHandlers(); ++i) {
310 const CXXCatchStmt *C = S.getHandler(i);
Mike Stump0f590be2009-12-01 03:41:18 +0000311 VarDecl *CatchParam = C->getExceptionDecl();
312 Stmt *CatchBody = C->getHandlerBlock();
313
314 llvm::BasicBlock *Next = 0;
315
316 if (SelectorArgs[i+2] != Null) {
317 llvm::BasicBlock *Match = createBasicBlock("match");
318 Next = createBasicBlock("catch.next");
319 const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
320 llvm::Value *Id
321 = Builder.CreateCall(llvm_eh_typeid_for,
322 Builder.CreateBitCast(SelectorArgs[i+2],
323 Int8PtrTy));
324 Builder.CreateCondBr(Builder.CreateICmpEQ(Selector, Id),
325 Match, Next);
326 EmitBlock(Match);
327 }
328
329 llvm::BasicBlock *MatchEnd = createBasicBlock("match.end");
330 llvm::BasicBlock *MatchHandler = createBasicBlock("match.handler");
331
332 PushCleanupBlock(MatchEnd);
333 setInvokeDest(MatchHandler);
334
335 llvm::Value *ExcObject = Builder.CreateCall(getBeginCatchFn(*this), Exc);
336
337 // Bind the catch parameter if it exists.
338 if (CatchParam) {
339 QualType CatchType = CatchParam->getType().getNonReferenceType();
340 if (!CatchType.getTypePtr()->isPointerType())
341 CatchType = getContext().getPointerType(CatchType);
342 ExcObject =
343 Builder.CreateBitCast(ExcObject, ConvertType(CatchType));
344 // CatchParam is a ParmVarDecl because of the grammar
345 // construction used to handle this, but for codegen purposes
346 // we treat this as a local decl.
347 EmitLocalBlockVarDecl(*CatchParam);
348#if 0
349 // FIXME: objects with ctors, references
350 Builder.CreateStore(ExcObject, GetAddrOfLocalVar(CatchParam));
351#else
352 CopyObject(*this, CatchParam->getType().getNonReferenceType(),
353 ExcObject, GetAddrOfLocalVar(CatchParam));
354#endif
355 }
356
357 EmitStmt(CatchBody);
358 EmitBranchThroughCleanup(FinallyEnd);
359
360 EmitBlock(MatchHandler);
361
362 llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
363 // We are required to emit this call to satisfy LLVM, even
364 // though we don't use the result.
365 llvm::SmallVector<llvm::Value*, 8> Args;
366 Args.push_back(Exc);
367 Args.push_back(Personality);
368 Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
369 0));
370 Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
371 Builder.CreateStore(Exc, RethrowPtr);
372 EmitBranchThroughCleanup(FinallyRethrow);
373
374 CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock();
375
376 EmitBlock(MatchEnd);
377
378 // Unfortunately, we also have to generate another EH frame here
379 // in case this throws.
380 llvm::BasicBlock *MatchEndHandler =
381 createBasicBlock("match.end.handler");
382 llvm::BasicBlock *Cont = createBasicBlock("myinvoke.cont");
383 Builder.CreateInvoke(getEndCatchFn(*this),
384 Cont, MatchEndHandler,
385 Args.begin(), Args.begin());
386
387 EmitBlock(Cont);
388 if (Info.SwitchBlock)
389 EmitBlock(Info.SwitchBlock);
390 if (Info.EndBlock)
391 EmitBlock(Info.EndBlock);
392
393 EmitBlock(MatchEndHandler);
394 Exc = Builder.CreateCall(llvm_eh_exception, "exc");
395 // We are required to emit this call to satisfy LLVM, even
396 // though we don't use the result.
397 Args.clear();
398 Args.push_back(Exc);
399 Args.push_back(Personality);
400 Args.push_back(llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext),
401 0));
402 Builder.CreateCall(llvm_eh_selector, Args.begin(), Args.end());
403 Builder.CreateStore(Exc, RethrowPtr);
404 EmitBranchThroughCleanup(FinallyRethrow);
405
406 if (Next)
407 EmitBlock(Next);
408 }
409 if (!HasCatchAll)
410 EmitBranchThroughCleanup(FinallyRethrow);
Mike Stump2bf701e2009-11-20 23:44:51 +0000411
412 CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock();
413
414 setInvokeDest(PrevLandingPad);
415
Mike Stump0f590be2009-12-01 03:41:18 +0000416#if 0
Mike Stump2bf701e2009-11-20 23:44:51 +0000417 EmitBlock(FinallyBlock);
418
Mike Stump0f590be2009-12-01 03:41:18 +0000419 if (Info.SwitchBlock)
420 EmitBlock(Info.SwitchBlock);
421 if (Info.EndBlock)
422 EmitBlock(Info.EndBlock);
423
Mike Stump2bf701e2009-11-20 23:44:51 +0000424 // Branch around the rethrow code.
425 EmitBranch(FinallyEnd);
Mike Stump0f590be2009-12-01 03:41:18 +0000426#endif
Mike Stump2bf701e2009-11-20 23:44:51 +0000427
428 EmitBlock(FinallyRethrow);
Mike Stump0f590be2009-12-01 03:41:18 +0000429 Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),
430 Builder.CreateLoad(RethrowPtr));
Mike Stump2bf701e2009-11-20 23:44:51 +0000431 Builder.CreateUnreachable();
Mike Stump2bf701e2009-11-20 23:44:51 +0000432
433 EmitBlock(FinallyEnd);
434#endif
435}