Chris Lattner | 7b3092d | 2003-08-30 23:31:08 +0000 | [diff] [blame] | 1 | //===- SJLJ-Exception.cpp - SetJmp/LongJmp Exception Handling -------------===// |
Misha Brukman | fd93908 | 2005-04-21 23:48:37 +0000 | [diff] [blame] | 2 | // |
Chris Lattner | 45872bf | 2004-08-05 00:20:51 +0000 | [diff] [blame] | 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file was developed by the LLVM research group and is distributed under |
| 6 | // the University of Illinois Open Source License. See LICENSE.TXT for details. |
Misha Brukman | fd93908 | 2005-04-21 23:48:37 +0000 | [diff] [blame] | 7 | // |
Chris Lattner | 45872bf | 2004-08-05 00:20:51 +0000 | [diff] [blame] | 8 | //===----------------------------------------------------------------------===// |
Chris Lattner | 7b3092d | 2003-08-30 23:31:08 +0000 | [diff] [blame] | 9 | // |
| 10 | // This file implements the API used by the Setjmp/Longjmp exception handling |
| 11 | // runtime library. |
| 12 | // |
| 13 | //===----------------------------------------------------------------------===// |
Chris Lattner | 214191f | 2003-08-30 23:29:22 +0000 | [diff] [blame] | 14 | |
| 15 | #include "SJLJ-Exception.h" |
| 16 | #include <cstdlib> |
| 17 | #include <cassert> |
| 18 | |
Chris Lattner | d338a23 | 2003-11-09 00:29:51 +0000 | [diff] [blame] | 19 | // Assert should only be used for debugging the runtime library. Enabling it in |
| 20 | // CVS will break some platforms! |
| 21 | #undef assert |
| 22 | #define assert(X) |
| 23 | |
Chris Lattner | 7b3092d | 2003-08-30 23:31:08 +0000 | [diff] [blame] | 24 | // get_sjlj_exception - Adjust the llvm_exception pointer to be an appropriate |
| 25 | // llvm_sjlj_exception pointer. |
Chris Lattner | 214191f | 2003-08-30 23:29:22 +0000 | [diff] [blame] | 26 | inline llvm_sjlj_exception *get_sjlj_exception(llvm_exception *E) { |
| 27 | assert(E->ExceptionType == SJLJException); |
| 28 | return (llvm_sjlj_exception*)(E+1) - 1; |
| 29 | } |
| 30 | |
| 31 | // SetJmpMapEntry - One entry in a linked list of setjmps for the current |
| 32 | // function. |
| 33 | struct SetJmpMapEntry { |
| 34 | void *JmpBuf; |
| 35 | unsigned SetJmpID; |
| 36 | SetJmpMapEntry *Next; |
| 37 | }; |
| 38 | |
Chris Lattner | 7b3092d | 2003-08-30 23:31:08 +0000 | [diff] [blame] | 39 | // SJLJDestructor - This function is used to free the exception when |
| 40 | // language-indent code needs to destroy the exception without knowing exactly |
| 41 | // what type it is. |
Chris Lattner | 214191f | 2003-08-30 23:29:22 +0000 | [diff] [blame] | 42 | static void SJLJDestructor(llvm_exception *E) { |
| 43 | free(get_sjlj_exception(E)); |
| 44 | } |
| 45 | |
| 46 | |
| 47 | // __llvm_sjljeh_throw_longjmp - This function creates the longjmp exception and |
| 48 | // returns. It takes care of mapping the longjmp value from 0 -> 1 as |
| 49 | // appropriate. The caller should immediately call llvm.unwind after this |
| 50 | // function call. |
| 51 | void __llvm_sjljeh_throw_longjmp(void *JmpBuffer, int Val) throw() { |
| 52 | llvm_sjlj_exception *E = |
| 53 | (llvm_sjlj_exception *)malloc(sizeof(llvm_sjlj_exception)); |
| 54 | E->BaseException.ExceptionDestructor = SJLJDestructor; |
| 55 | E->BaseException.ExceptionType = SJLJException; |
| 56 | E->BaseException.HandlerCount = 0; |
| 57 | E->BaseException.isRethrown = 0; |
| 58 | E->JmpBuffer = JmpBuffer; |
| 59 | E->LongJmpValue = Val ? Val : 1; |
| 60 | |
| 61 | __llvm_eh_add_uncaught_exception(&E->BaseException); |
| 62 | } |
| 63 | |
| 64 | // __llvm_sjljeh_init_setjmpmap - This funciton initializes the pointer provided |
| 65 | // to an empty setjmp map, and should be called on entry to a function which |
| 66 | // calls setjmp. |
| 67 | void __llvm_sjljeh_init_setjmpmap(void **SetJmpMap) throw() { |
| 68 | *SetJmpMap = 0; |
| 69 | } |
| 70 | |
| 71 | // __llvm_sjljeh_destroy_setjmpmap - This function frees all memory associated |
| 72 | // with the specified setjmpmap structure. It should be called on all exits |
| 73 | // (returns or unwinds) from the function which calls ...init_setjmpmap. |
| 74 | void __llvm_sjljeh_destroy_setjmpmap(void **SetJmpMap) throw() { |
| 75 | SetJmpMapEntry *Next; |
| 76 | for (SetJmpMapEntry *SJE = *(SetJmpMapEntry**)SetJmpMap; SJE; SJE = Next) { |
| 77 | Next = SJE->Next; |
| 78 | free(SJE); |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | // __llvm_sjljeh_add_setjmp_to_map - This function adds or updates an entry to |
| 83 | // the map, to indicate which setjmp should be returned to if a longjmp happens. |
| 84 | void __llvm_sjljeh_add_setjmp_to_map(void **SetJmpMap, void *JmpBuf, |
| 85 | unsigned SetJmpID) throw() { |
| 86 | SetJmpMapEntry **SJE = (SetJmpMapEntry**)SetJmpMap; |
| 87 | |
| 88 | // Scan for a pre-existing entry... |
| 89 | for (; *SJE; SJE = &(*SJE)->Next) |
| 90 | if ((*SJE)->JmpBuf == JmpBuf) { |
| 91 | (*SJE)->SetJmpID = SetJmpID; |
| 92 | return; |
| 93 | } |
| 94 | |
| 95 | // No prexisting entry found, append to the end of the list... |
| 96 | SetJmpMapEntry *New = (SetJmpMapEntry *)malloc(sizeof(SetJmpMapEntry)); |
| 97 | *SJE = New; |
| 98 | New->JmpBuf = JmpBuf; |
| 99 | New->SetJmpID = SetJmpID; |
| 100 | New->Next = 0; |
| 101 | } |
| 102 | |
| 103 | // __llvm_sjljeh_is_longjmp_exception - This function returns true if the |
| 104 | // current uncaught exception is a longjmp exception. This is the first step of |
| 105 | // catching a sjlj exception. |
| 106 | bool __llvm_sjljeh_is_longjmp_exception() throw() { |
| 107 | return __llvm_eh_current_uncaught_exception_type(SJLJException) != 0; |
| 108 | } |
Misha Brukman | fd93908 | 2005-04-21 23:48:37 +0000 | [diff] [blame] | 109 | |
Chris Lattner | 214191f | 2003-08-30 23:29:22 +0000 | [diff] [blame] | 110 | // __llvm_sjljeh_get_longjmp_value - This function returns the value that the |
| 111 | // setjmp call should "return". This requires that the current uncaught |
| 112 | // exception be a sjlj exception, though it does not require the exception to be |
| 113 | // caught by this function. |
| 114 | int __llvm_sjljeh_get_longjmp_value() throw() { |
| 115 | llvm_sjlj_exception *E = |
| 116 | get_sjlj_exception(__llvm_eh_get_uncaught_exception()); |
| 117 | return E->LongJmpValue; |
| 118 | } |
| 119 | |
| 120 | // __llvm_sjljeh_try_catching_longjmp_exception - This function checks to see if |
| 121 | // the current uncaught longjmp exception matches any of the setjmps collected |
| 122 | // in the setjmpmap structure. If so, it catches and destroys the exception, |
| 123 | // returning the index of the setjmp which caught the exception. If not, it |
| 124 | // leaves the exception uncaught and returns a value of ~0. |
| 125 | unsigned __llvm_sjljeh_try_catching_longjmp_exception(void **SetJmpMap) throw(){ |
| 126 | llvm_sjlj_exception *E = |
| 127 | get_sjlj_exception(__llvm_eh_get_uncaught_exception()); |
Misha Brukman | fd93908 | 2005-04-21 23:48:37 +0000 | [diff] [blame] | 128 | |
Chris Lattner | 214191f | 2003-08-30 23:29:22 +0000 | [diff] [blame] | 129 | // Scan for a matching entry in the SetJmpMap... |
| 130 | SetJmpMapEntry *SJE = *(SetJmpMapEntry**)SetJmpMap; |
| 131 | for (; SJE; SJE = SJE->Next) |
| 132 | if (SJE->JmpBuf == E->JmpBuffer) { |
| 133 | // "Catch" and destroy the exception... |
| 134 | __llvm_eh_pop_from_uncaught_stack(); |
| 135 | |
| 136 | // We know it's a longjmp exception, so we can just free it instead of |
| 137 | // calling the destructor. |
| 138 | free(E); |
| 139 | |
| 140 | // Return the setjmp ID which we should branch to... |
| 141 | return SJE->SetJmpID; |
| 142 | } |
Misha Brukman | fd93908 | 2005-04-21 23:48:37 +0000 | [diff] [blame] | 143 | |
Chris Lattner | 214191f | 2003-08-30 23:29:22 +0000 | [diff] [blame] | 144 | // No setjmp in this function catches the exception! |
| 145 | return ~0; |
| 146 | } |