CGException.cpp revision 199990
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(Int8PtrTy, Args, false);
65
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
78// 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
180void CodeGenFunction::EmitCXXThrowExpr(const CXXThrowExpr *E) {
181  if (!E->getSubExpr()) {
182    Builder.CreateCall(getReThrowFn(*this))->setDoesNotReturn();
183    Builder.CreateUnreachable();
184
185    // Clear the insertion point to indicate we are in unreachable code.
186    Builder.ClearInsertionPoint();
187    return;
188  }
189
190  QualType ThrowType = E->getSubExpr()->getType();
191  // FIXME: Handle cleanup.
192  if (!CleanupEntries.empty()){
193    ErrorUnsupported(E, "throw expression with cleanup entries");
194    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
207  CopyObject(*this, E->getSubExpr(), ExceptionPtr);
208
209  // Now throw the exception.
210  const llvm::Type *Int8PtrTy = llvm::Type::getInt8PtrTy(getLLVMContext());
211  llvm::Constant *TypeInfo = CGM.GenerateRtti(ThrowType);
212  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();
221}
222
223void CodeGenFunction::EmitCXXTryStmt(const CXXTryStmt &S) {
224#if 1
225  EmitStmt(S.getTryBlock());
226  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.
234  // 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
242  llvm::BasicBlock *PrevLandingPad = getInvokeDest();
243  llvm::BasicBlock *TryHandler = createBasicBlock("try.handler");
244#if 0
245  llvm::BasicBlock *FinallyBlock = createBasicBlock("finally");
246#endif
247  llvm::BasicBlock *FinallyRethrow = createBasicBlock("finally.throw");
248  llvm::BasicBlock *FinallyEnd = createBasicBlock("finally.end");
249
250#if 0
251  // Push an EH context entry, used for handling rethrows.
252  PushCleanupBlock(FinallyBlock);
253#endif
254
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);
271  llvm::Constant *Null = llvm::ConstantPointerNull::get(PtrToInt8Ty);
272  llvm::SmallVector<llvm::Value*, 8> SelectorArgs;
273  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);
277  llvm::Value *llvm_eh_typeid_for =
278    CGM.getIntrinsic(llvm::Intrinsic::eh_typeid_for);
279  // Exception object
280  llvm::Value *Exc = Builder.CreateCall(llvm_eh_exception, "exc");
281  llvm::Value *RethrowPtr = CreateTempAlloca(Exc->getType(), "_rethrow");
282
283  SelectorArgs.push_back(Exc);
284  SelectorArgs.push_back(Personality);
285
286  bool HasCatchAll = false;
287  for (unsigned i = 0; i<S.getNumHandlers(); ++i) {
288    const CXXCatchStmt *C = S.getHandler(i);
289    VarDecl *CatchParam = C->getExceptionDecl();
290    if (CatchParam) {
291      llvm::Value *EHType = CGM.GenerateRtti(C->getCaughtType().getNonReferenceType());
292      SelectorArgs.push_back(EHType);
293    } else {
294      // null indicates catch all
295      SelectorArgs.push_back(Null);
296      HasCatchAll = true;
297    }
298  }
299
300  // We use a cleanup unless there was already a catch all.
301  if (!HasCatchAll) {
302    SelectorArgs.push_back(Null);
303  }
304
305  // Find which handler was matched.
306  llvm::Value *Selector
307    = Builder.CreateCall(llvm_eh_selector, SelectorArgs.begin(),
308                         SelectorArgs.end(), "selector");
309  for (unsigned i = 0; i<S.getNumHandlers(); ++i) {
310    const CXXCatchStmt *C = S.getHandler(i);
311    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);
411
412  CodeGenFunction::CleanupBlockInfo Info = PopCleanupBlock();
413
414  setInvokeDest(PrevLandingPad);
415
416#if 0
417  EmitBlock(FinallyBlock);
418
419  if (Info.SwitchBlock)
420    EmitBlock(Info.SwitchBlock);
421  if (Info.EndBlock)
422    EmitBlock(Info.EndBlock);
423
424  // Branch around the rethrow code.
425  EmitBranch(FinallyEnd);
426#endif
427
428  EmitBlock(FinallyRethrow);
429  Builder.CreateCall(getUnwindResumeOrRethrowFn(*this),
430                     Builder.CreateLoad(RethrowPtr));
431  Builder.CreateUnreachable();
432
433  EmitBlock(FinallyEnd);
434#endif
435}
436