00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 #include "CodeGenRoutine.h"
00010 #include "CommaRT.h"
00011 #include "HandlerEmitter.h"
00012 #include "comma/ast/ExceptionRef.h"
00013 #include "comma/ast/Stmt.h"
00014 
00015 using namespace comma;
00016 
00017 HandlerEmitter::HandlerEmitter(CodeGenRoutine &CGR)
00018     : CGR(CGR), CG(CGR.getCodeGen()), RT(CG.getRuntime()) { }
00019 
00020 SRFrame *HandlerEmitter::frame() { return CGR.getSRFrame(); }
00021 
00022 llvm::Value *HandlerEmitter::emitSelector(llvm::Value *exception,
00023                                           StmtSequence *seq)
00024 {
00025     typedef StmtSequence::handler_iter handler_iter;
00026     typedef HandlerStmt::choice_iterator choice_iter;
00027     llvm::SmallVector<llvm::Value*, 8> args;
00028 
00029     
00030     args.push_back(exception);
00031     args.push_back(RT.getEHPersonality());
00032 
00033     
00034     for (handler_iter H = seq->handler_begin(); H != seq->handler_end(); ++H) {
00035         HandlerStmt *handler = *H;
00036         choice_iter C = handler->choice_begin();
00037         choice_iter E = handler->choice_end();
00038         for ( ; C != E; ++C) {
00039             ExceptionDecl *target = (*C)->getException();
00040             args.push_back(RT.registerException(target));
00041         }
00042     }
00043 
00044     
00045     
00046     args.push_back(CG.getNullPointer(CG.getInt8PtrTy()));
00047 
00048     return frame()->getIRBuilder().CreateCall(
00049         CG.getEHSelectorIntrinsic(), args.begin(), args.end());
00050 }
00051 
00052 void HandlerEmitter::emitHandlers(StmtSequence *seq, llvm::BasicBlock *mergeBB)
00053 {
00054     if (mergeBB == 0)
00055         mergeBB = frame()->makeBasicBlock("landingpad.merge");
00056 
00057     llvm::IRBuilder<> &Builder = frame()->getIRBuilder();
00058     llvm::BasicBlock *landingPad = frame()->getLandingPad();
00059 
00060     
00061     
00062     
00063     frame()->removeLandingPad();
00064 
00065     
00066     Builder.SetInsertPoint(landingPad);
00067     llvm::Value *exception = Builder.CreateCall(CG.getEHExceptionIntrinsic());
00068     llvm::Value *infoIdx = emitSelector(exception, seq);
00069     llvm::Value *eh_typeid = CG.getEHTypeidIntrinsic();
00070     llvm::BasicBlock *lpadBB = frame()->makeBasicBlock("lpad");
00071     Builder.CreateBr(lpadBB);
00072     Builder.SetInsertPoint(lpadBB);
00073 
00074     for (StmtSequence::handler_iter H = seq->handler_begin();
00075          H != seq->handler_end(); ++H) {
00076         HandlerStmt *handler = *H;
00077         llvm::BasicBlock *bodyBB = frame()->makeBasicBlock("lpad.body");
00078 
00079         
00080         if (handler->isCatchAll())
00081             Builder.CreateBr(bodyBB);
00082         else {
00083             for (HandlerStmt::choice_iterator C = handler->choice_begin();
00084                  C != handler->choice_end(); ++C) {
00085                 ExceptionDecl *target = (*C)->getException();
00086                 llvm::Value *exinfo = RT.registerException(target);
00087                 llvm::Value *targetIdx = Builder.CreateCall(eh_typeid, exinfo);
00088                 llvm::Value *pred = Builder.CreateICmpEQ(infoIdx, targetIdx);
00089                 lpadBB = frame()->makeBasicBlock("lpad");
00090                 Builder.CreateCondBr(pred, bodyBB, lpadBB);
00091                 Builder.SetInsertPoint(lpadBB);
00092             }
00093         }
00094 
00095         
00096         
00097         Builder.SetInsertPoint(bodyBB);
00098         for (StmtSequence::stmt_iter I = handler->stmt_begin();
00099              I != handler->stmt_end(); ++I)
00100             CGR.emitStmt(*I);
00101         if (!Builder.GetInsertBlock()->getTerminator())
00102             Builder.CreateBr(mergeBB);
00103         Builder.SetInsertPoint(lpadBB);
00104     }
00105 
00106     
00107     
00108     
00109     if (!seq->hasCatchAll())
00110         RT.reraise(frame(), exception);
00111 
00112     Builder.SetInsertPoint(mergeBB);
00113 }
00114 
00115 
00116