CGException.cpp revision 2bf701ee4babb5c4a9ea99ca4675c5ef040bd402
1//===--- 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
14#include "clang/AST/StmtCXX.h"
15
16#include "llvm/Intrinsics.h"
17
18#include "CodeGenFunction.h"
19using namespace clang;
20using namespace CodeGen;
21
22static 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 =
42    llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()),
43                            Args, false);
44
45  return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_throw");
46}
47
48static 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
57static llvm::Constant *getBeginCatchFn(CodeGenFunction &CGF) {
58  // void __cxa_begin_catch ();
59
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 =
64    llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), Args,
65                            false);
66
67  return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_begin_catch");
68}
69
70static llvm::Constant *getEndCatchFn(CodeGenFunction &CGF) {
71  // void __cxa_end_catch ();
72
73  const llvm::FunctionType *FTy =
74    llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), false);
75
76  return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_end_catch");
77}
78
79void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
80  if (!E->getSubExpr()) {
81    Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn();
82    Builder.CreateUnreachable();
83
84    // Clear the insertion point to indicate we are in unreachable code.
85    Builder.ClearInsertionPoint();
86    return;
87  }
88
89  QualType ThrowType = E->getSubExpr()->getType();
90  // FIXME: Handle cleanup.
91  if (!CleanupEntries.empty()){
92    ErrorUnsupported(E, "throw expression with cleanup entries");
93    return;
94  }
95
96  // Now allocate the exception object.
97  const llvm::Type *SizeTy = ConvertType(getContext().getSizeType());
98  uint64_t TypeSize = getContext().getTypeSize(ThrowType) / 8;
99
100  llvm::Constant *AllocExceptionFn = getAllocateExceptionFn(*this);
101  llvm::Value *ExceptionPtr =
102    Builder.CreateCall(AllocExceptionFn,
103                       llvm::ConstantInt::get(SizeTy, TypeSize),
104                       "exception");
105
106  // Store the throw exception in the exception object.
107  if (!hasAggregateLLVMType(ThrowType)) {
108    llvm::Value *Value = EmitScalarExpr(E->getSubExpr());
109    const llvm::Type *ValuePtrTy = Value->getType()->getPointerTo(0);
110
111    Builder.CreateStore(Value, Builder.CreateBitCast(ExceptionPtr, ValuePtrTy));
112  } else {
113    const llvm::Type *Ty = ConvertType(ThrowType)->getPointerTo(0);
114    const CXXRecordDecl *RD;
115    RD = cast<CXXRecordDecl>(ThrowType->getAs<RecordType>()->getDecl());
116    llvm::Value *This = Builder.CreateBitCast(ExceptionPtr, Ty);
117    if (RD->hasTrivialCopyConstructor()) {
118      EmitAggExpr(E->getSubExpr(), This, false);
119    } else if (CXXConstructorDecl *CopyCtor
120               = RD->getCopyConstructor(getContext(), 0)) {
121      // FIXME: region management
122      llvm::Value *Src = EmitLValue(E->getSubExpr()).getAddress();
123
124      // Stolen from EmitClassAggrMemberwiseCopy
125      llvm::Value *Callee = CGM.GetAddrOfCXXConstructor(CopyCtor,
126                                                        Ctor_Complete);
127      CallArgList CallArgs;
128      CallArgs.push_back(std::make_pair(RValue::get(This),
129                                        CopyCtor->getThisType(getContext())));
130
131      // Push the Src ptr.
132      CallArgs.push_back(std::make_pair(RValue::get(Src),
133                                        CopyCtor->getParamDecl(0)->getType()));
134      QualType ResultType =
135        CopyCtor->getType()->getAs<FunctionType>()->getResultType();
136      EmitCall(CGM.getTypes().getFunctionInfo(ResultType, CallArgs),
137               Callee, CallArgs, CopyCtor);
138      // FIXME: region management
139    } else
140      ErrorUnsupported(E, "throw expression with copy ctor");
141  }
142
143  // Now throw the exception.
144  const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
145  llvm::Constant *TypeInfo = CGM.GenerateRtti(ThrowType);
146  llvm::Constant *Dtor = llvm::Constant::getNullValue(Int8PtrTy);
147
148  llvm::CallInst *ThrowCall =
149    Builder.CreateCall3(getThrowFn(*this), ExceptionPtr, TypeInfo, Dtor);
150  ThrowCall->setDoesNotReturn();
151  Builder.CreateUnreachable();
152
153  // Clear the insertion point to indicate we are in unreachable code.
154  Builder.ClearInsertionPoint();
155}
156
157void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
158  // FIXME: We need to do more here.
159  EmitStmt(S.getTryBlock());
160  getBeginCatchFn(*this);
161  getEndCatchFn(*this);
162
163#if 0
164  // WIP.  Can't enable until the basic structure is correct.
165  // Pointer to the personality function
166  llvm::Constant *Personality =
167    CGM.CreateRuntimeFunction(llvm::FunctionType::get(llvm::Type::getInt32Ty
168                                                      (VMContext),
169                                                      true),
170                              "__gxx_personality_v0");
171  Personality = llvm::ConstantExpr::getBitCast(Personality, PtrToInt8Ty);
172
173  llvm::BasicBlock *TryBlock = createBasicBlock("try");
174  llvm::BasicBlock *PrevLandingPad = getInvokeDest();
175  llvm::BasicBlock *TryHandler = createBasicBlock("try.handler");
176  llvm::BasicBlock *CatchInCatch = createBasicBlock("catch.rethrow");
177  llvm::BasicBlock *FinallyBlock = createBasicBlock("finally");
178  llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end");
179
180  // Push an EH context entry, used for handling rethrows.
181  PushCleanupBlock(FinallyBlock);
182
183  // Emit the statements in the try {} block
184  setInvokeDest(TryHandler);
185
186  EmitStmt(S.getTryBlock());
187
188  // Jump to end if there is no exception
189  EmitBranchThroughCleanup(FinallyEnd);
190
191  // Emit the handlers
192  EmitBlock(TryHandler);
193
194  const llvm::IntegerType *Int8Ty;
195  const llvm::PointerType *PtrToInt8Ty;
196  Int8Ty = llvm::Type::getInt8Ty(VMContext);
197  // C string type.  Used in lots of places.
198  PtrToInt8Ty = llvm::PointerType::getUnqual(Int8Ty);
199  llvm::Constant *NULLPtr = llvm::ConstantPointerNull::get(PtrToInt8Ty);
200  llvm::SmallVector<llvm::Value*, 8> ESelArgs;
201  llvm::Value *llvm_eh_exception =
202    CGM.getIntrinsic(llvm::Intrinsic::eh_exception);
203  llvm::Value *llvm_eh_selector =
204    CGM.getIntrinsic(llvm::Intrinsic::eh_selector);
205  // Exception object
206  llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
207
208  ESelArgs.push_back(Exc);
209  ESelArgs.push_back(Personality);
210
211  for (unsigned i = 0; i<S.getNumHandlers(); ++i) {
212    const CXXCatchStmt *C = S.getHandler(i);
213    VarDecl *VD = C->getExceptionDecl();
214    if (VD) {
215#if 0
216      // FIXME: Handle type matching.
217      llvm::Value *EHType = 0;
218      ESelArgs.push_back(EHType);
219#endif
220    } else {
221      // null indicates catch all
222      ESelArgs.push_back(NULLPtr);
223    }
224  }
225
226  // Find which handler was matched.
227  llvm::Value *ESelector
228    = Builder.CreateCall(llvm_eh_selector, ESelArgs.begin(), ESelArgs.end(),
229                         "selector");
230
231  for (unsigned i = 0; i<S.getNumHandlers(); ++i) {
232    const CXXCatchStmt *C = S.getHandler(i);
233    getBeginCatchFn(*this);
234    getEndCatchFn(*this);
235  }
236
237  CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock();
238
239  setInvokeDest(PrevLandingPad);
240
241  EmitBlock(FinallyBlock);
242
243#if 0
244  // Branch around the rethrow code.
245  EmitBranch(FinallyEnd);
246
247  EmitBlock(FinallyRethrow);
248  Builder.CreateCall(RethrowFn, Builder.CreateLoad(RethrowPtr));
249  Builder.CreateUnreachable();
250#endif
251
252  EmitBlock(FinallyEnd);
253#endif
254}
255