blob: 6a3e4724ae8446121e5816707a8c4041c02a1210 [file] [log] [blame]
Chris Lattner7b3092d2003-08-30 23:31:08 +00001//===- SJLJ-Exception.cpp - SetJmp/LongJmp Exception Handling -------------===//
Misha Brukmanfd939082005-04-21 23:48:37 +00002//
Chris Lattner45872bf2004-08-05 00:20:51 +00003// 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 Brukmanfd939082005-04-21 23:48:37 +00007//
Chris Lattner45872bf2004-08-05 00:20:51 +00008//===----------------------------------------------------------------------===//
Chris Lattner7b3092d2003-08-30 23:31:08 +00009//
10// This file implements the API used by the Setjmp/Longjmp exception handling
11// runtime library.
12//
13//===----------------------------------------------------------------------===//
Chris Lattner214191f2003-08-30 23:29:22 +000014
15#include "SJLJ-Exception.h"
16#include <cstdlib>
17#include <cassert>
18
Chris Lattnerd338a232003-11-09 00:29:51 +000019// 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 Lattner7b3092d2003-08-30 23:31:08 +000024// get_sjlj_exception - Adjust the llvm_exception pointer to be an appropriate
25// llvm_sjlj_exception pointer.
Chris Lattner214191f2003-08-30 23:29:22 +000026inline 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.
33struct SetJmpMapEntry {
34 void *JmpBuf;
35 unsigned SetJmpID;
36 SetJmpMapEntry *Next;
37};
38
Chris Lattner7b3092d2003-08-30 23:31:08 +000039// 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 Lattner214191f2003-08-30 23:29:22 +000042static 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.
51void __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.
67void __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.
74void __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.
84void __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.
106bool __llvm_sjljeh_is_longjmp_exception() throw() {
107 return __llvm_eh_current_uncaught_exception_type(SJLJException) != 0;
108}
Misha Brukmanfd939082005-04-21 23:48:37 +0000109
Chris Lattner214191f2003-08-30 23:29:22 +0000110// __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.
114int __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.
125unsigned __llvm_sjljeh_try_catching_longjmp_exception(void **SetJmpMap) throw(){
126 llvm_sjlj_exception *E =
127 get_sjlj_exception(__llvm_eh_get_uncaught_exception());
Misha Brukmanfd939082005-04-21 23:48:37 +0000128
Chris Lattner214191f2003-08-30 23:29:22 +0000129 // 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 Brukmanfd939082005-04-21 23:48:37 +0000143
Chris Lattner214191f2003-08-30 23:29:22 +0000144 // No setjmp in this function catches the exception!
145 return ~0;
146}