[cfe-commits] r55994 - /cfe/trunk/lib/CodeGen/CGObjCMac.cpp

Anders Carlsson andersca at mac.com
Tue Sep 9 10:59:26 PDT 2008


Author: andersca
Date: Tue Sep  9 12:59:25 2008
New Revision: 55994

URL: http://llvm.org/viewvc/llvm-project?rev=55994&view=rev
Log:
Check in half-assed implementation of @try/@catch.

Modified:
    cfe/trunk/lib/CodeGen/CGObjCMac.cpp

Modified: cfe/trunk/lib/CodeGen/CGObjCMac.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGObjCMac.cpp?rev=55994&r1=55993&r2=55994&view=diff

==============================================================================
--- cfe/trunk/lib/CodeGen/CGObjCMac.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGObjCMac.cpp Tue Sep  9 12:59:25 2008
@@ -1423,7 +1423,168 @@
 void CGObjCMac::EmitTryStmt(CodeGen::CodeGenFunction &CGF,
                             const ObjCAtTryStmt &S)
 {
-  CGF.ErrorUnsupported(&S, "@try statement");
+  // Allocate exception data.
+  llvm::Value *ExceptionData = CGF.CreateTempAlloca(ObjCTypes.ExceptionDataTy,
+                                                    "exceptiondata.ptr");
+  
+  // Allocate memory for the rethrow pointer.
+  llvm::Value *RethrowPtr = CGF.CreateTempAlloca(ObjCTypes.ObjectPtrTy);
+  CGF.Builder.CreateStore(llvm::Constant::getNullValue(ObjCTypes.ObjectPtrTy),
+                          RethrowPtr);
+  
+  // Enter a new try block and call setjmp.
+  CGF.Builder.CreateCall(ObjCTypes.ExceptionTryEnterFn, ExceptionData);
+  llvm::Value *JmpBufPtr = CGF.Builder.CreateStructGEP(ExceptionData, 0, 
+                                                       "jmpbufarray");
+  JmpBufPtr = CGF.Builder.CreateStructGEP(JmpBufPtr, 0, "tmp");
+  llvm::Value *SetJmpResult = CGF.Builder.CreateCall(ObjCTypes.SetJmpFn,
+                                                     JmpBufPtr, "result");
+  
+  
+  llvm::BasicBlock *FinallyBlock = llvm::BasicBlock::Create("finally");
+  
+  llvm::BasicBlock *TryBlock = llvm::BasicBlock::Create("try");
+  llvm::BasicBlock *ExceptionInTryBlock = 
+    llvm::BasicBlock::Create("exceptionintry");
+
+  // If setjmp returns 1, there was an exception in the @try block.
+  llvm::Value *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty);
+  llvm::Value *IsZero = CGF.Builder.CreateICmpEQ(SetJmpResult, Zero, "iszero");
+  CGF.Builder.CreateCondBr(IsZero, TryBlock, ExceptionInTryBlock);
+
+  // Emit the @try block.
+  CGF.EmitBlock(TryBlock);
+  CGF.EmitStmt(S.getTryBody());
+  CGF.Builder.CreateBr(FinallyBlock);
+  
+  // Emit the "exception in @try" block.
+  CGF.EmitBlock(ExceptionInTryBlock);
+  
+  if (const ObjCAtCatchStmt* CatchStmt = S.getCatchStmts()) {
+    // Allocate memory for the caught exception and extract it from the 
+    // exception data.
+    llvm::Value *CaughtPtr = CGF.CreateTempAlloca(ObjCTypes.ObjectPtrTy);
+    llvm::Value *Extract = CGF.Builder.CreateCall(ObjCTypes.ExceptionExtractFn,
+                                                  ExceptionData);
+    CGF.Builder.CreateStore(Extract, CaughtPtr);
+    
+    // Enter a new exception try block 
+    // (in case a @catch block throws an exception).
+    CGF.Builder.CreateCall(ObjCTypes.ExceptionTryEnterFn, ExceptionData);
+    
+    llvm::Value *SetJmpResult = CGF.Builder.CreateCall(ObjCTypes.SetJmpFn,
+                                                       JmpBufPtr, "result");
+    
+    
+    llvm::Value *Zero = llvm::Constant::getNullValue(llvm::Type::Int32Ty);
+    llvm::Value *IsZero = CGF.Builder.CreateICmpEQ(SetJmpResult, Zero, 
+                                                   "iszero");
+
+    llvm::BasicBlock *CatchBlock = llvm::BasicBlock::Create("catch");
+    llvm::BasicBlock *ExceptionInCatchBlock = 
+      llvm::BasicBlock::Create("exceptionincatch");
+    CGF.Builder.CreateCondBr(IsZero, CatchBlock, ExceptionInCatchBlock);
+    
+    CGF.EmitBlock(CatchBlock);
+        
+    // Handle catch list
+    for (; CatchStmt; CatchStmt = CatchStmt->getNextCatchStmt()) {
+      llvm::BasicBlock *NextCatchBlock = llvm::BasicBlock::Create("nextcatch");
+
+      QualType T;
+      bool MatchesAll = false;
+      
+      // catch(...) always matches.
+      if (CatchStmt->hasEllipsis())
+        MatchesAll = true;
+      else {
+        const DeclStmt *DS = cast<DeclStmt>(CatchStmt->getCatchParamStmt());
+        QualType PT = cast<ValueDecl>(DS->getDecl())->getType();
+        T = PT->getAsPointerType()->getPointeeType();
+        
+        // catch(id e) always matches.
+        if (CGF.getContext().isObjCIdType(T))
+          MatchesAll = true;
+      }
+      
+      if (MatchesAll) {        
+        CGF.EmitStmt(CatchStmt->getCatchBody());
+        CGF.Builder.CreateBr(FinallyBlock);
+        
+        CGF.EmitBlock(NextCatchBlock);        
+        break;
+      }
+      
+      const ObjCInterfaceType *ObjCType = T->getAsPointerToObjCInterfaceType();
+      assert(ObjCType && "Catch parameter must have Objective-C type!");
+
+      // Check if the @catch block matches the exception object.
+      llvm::Value *Class = EmitClassRef(CGF.Builder, ObjCType->getDecl());
+      
+      llvm::Value *Caught = CGF.Builder.CreateLoad(CaughtPtr, "caught");
+      llvm::Value *Match = CGF.Builder.CreateCall2(ObjCTypes.ExceptionMatchFn,
+                                                   Class, Caught, "match");
+                                                   
+      llvm::Value *DidMatch = CGF.Builder.CreateICmpNE(Match, Zero, "iszero");
+      
+      llvm::BasicBlock *MatchedBlock = llvm::BasicBlock::Create("matched");
+      
+      CGF.Builder.CreateCondBr(DidMatch, MatchedBlock, NextCatchBlock);
+      
+      // Emit the @catch block.
+      CGF.EmitBlock(MatchedBlock);
+      CGF.EmitStmt(CatchStmt->getCatchBody());
+      CGF.Builder.CreateBr(FinallyBlock);
+      
+      CGF.EmitBlock(NextCatchBlock);
+    }
+
+    // None of the handlers caught the exception, so store it and rethrow
+    // it later.
+    llvm::Value *Caught = CGF.Builder.CreateLoad(CaughtPtr, "caught");
+    CGF.Builder.CreateStore(Caught, RethrowPtr);
+    CGF.Builder.CreateCall(ObjCTypes.ExceptionTryExitFn,
+                           ExceptionData);
+    
+    CGF.Builder.CreateBr(FinallyBlock);
+    
+    CGF.EmitBlock(ExceptionInCatchBlock);
+    
+    Extract = CGF.Builder.CreateCall(ObjCTypes.ExceptionExtractFn,
+                                     ExceptionData);
+    CGF.Builder.CreateStore(Extract, RethrowPtr);
+  }
+  
+  // Emit the @finally block.
+  CGF.EmitBlock(FinallyBlock);
+
+  llvm::Value *Rethrow = CGF.Builder.CreateLoad(RethrowPtr);
+  llvm::Value *ZeroPtr = llvm::Constant::getNullValue(ObjCTypes.ObjectPtrTy);
+
+  llvm::Value *RethrowIsZero = CGF.Builder.CreateICmpEQ(Rethrow, ZeroPtr);
+  
+  llvm::BasicBlock *TryExitBlock = llvm::BasicBlock::Create("tryexit");
+  llvm::BasicBlock *AfterTryExitBlock = 
+    llvm::BasicBlock::Create("aftertryexit");
+  
+  CGF.Builder.CreateCondBr(RethrowIsZero, TryExitBlock, AfterTryExitBlock);
+  CGF.EmitBlock(TryExitBlock);  
+  CGF.Builder.CreateCall(ObjCTypes.ExceptionTryExitFn, ExceptionData);
+  CGF.EmitBlock(AfterTryExitBlock);
+  
+  if (const ObjCAtFinallyStmt* FinallyStmt = S.getFinallyStmt())
+    CGF.EmitStmt(FinallyStmt->getFinallyBody());
+
+  llvm::Value *RethrowIsNotZero = CGF.Builder.CreateICmpNE(Rethrow, ZeroPtr);
+  
+  llvm::BasicBlock *RethrowBlock = llvm::BasicBlock::Create("rethrow");  
+  llvm::BasicBlock *FinallyEndBlock = llvm::BasicBlock::Create("finallyend");
+
+  // If necessary, rethrow the exception.
+  CGF.Builder.CreateCondBr(RethrowIsNotZero, RethrowBlock, FinallyEndBlock);
+  CGF.EmitBlock(RethrowBlock);
+  CGF.Builder.CreateCall(ObjCTypes.ExceptionThrowFn, Rethrow);
+  CGF.EmitBlock(FinallyEndBlock);
 }
 
 void CGObjCMac::EmitThrowStmt(CodeGen::CodeGenFunction &CGF,
@@ -1440,7 +1601,8 @@
   }
   
   CGF.Builder.CreateCall(ObjCTypes.ExceptionThrowFn, ExceptionAsObject);
-
+  CGF.Builder.CreateUnreachable();
+  CGF.EmitBlock(llvm::BasicBlock::Create("bb"));
 }
 
 /* *** Private Interface *** */





More information about the cfe-commits mailing list