<p>What are the most common ways of compiling code of a language with first-class support for exceptions, such as C++? Panics in Rust, which have similar behavior, shouldn't be too different.</p>
<p>From my experience, &quot;local jumps&quot; such as <code>continue</code> or <code>break</code> doesn't seem too hard. The problem with exception appears when one is deep in the call stack. How do common implementations handle this?</p>

<compilers><control-flow><exceptions>
How to compile exceptions?
CC BY-SA 4.0
2023-05-18T01:04:23.440Z
How to compile exceptions is partly dependent on the semantics of exceptions that you want. See, for example, this C++ proposal which seeks to make exceptions as efficient as return codes by compiling them like return codes. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0709r4.pdf
Pseudonym
<h1>As syntax sugar for something else</h1>
<p>Swift uses this to interface with Objective-C's out-param errors. For example, this set of functions:</p>
<pre><code>func foo() throws -&gt; Int {
  if .random() {
    return 0
  } else {
    throw MyError()
  }
}

func bar() throws {
  _ = try foo()
}

func baz() -&gt; Int {
  do {
    return try foo()
  } catch {
    print(error)
    return 2
  }
}
</code></pre>
<p>Would be compiled to something vaguely equivalent to this:</p>
<pre><code>func foo(error: inout Error?) -&gt; Int {
  if .random() {
    return 0
  } else {
    error = MyError()
    return /* some irrelevant value */
  }
}

func bar(error: inout Error?) {
  _ = foo(error: &amp;error)
}

func baz() -&gt; Int {
  var error: Error?
  let result = foo(error: &amp;error)
  if let error {
    print(error)
    return 2
  }
  return result
}
</code></pre>
<p>NB: I don't know if Swift does this in general, or only for <code>@objc</code> methods.</p>
<p>Edit to add: It might be even more straightforward to compile this as a &quot;result&quot; type, if you have one:</p>
<pre><code>func foo() -&gt; Result&lt;Int, Error&gt; {
  if .random() {
    return .success(0)
  } else {
    return .failure(MyError())
  }
}

func bar() -&gt; Result&lt;Void, Error&gt; {
  foo().map { _ in }
}

func baz() -&gt; Int {
  switch foo() {
  case .success(let result):
    return result
  case .failure(let error):
    print(error)
    return 2
  }
}
</code></pre>

CC BY-SA 4.0
2023-05-17T22:25:54.200Z
2023-05-17T22:45:04.043Z
2023-05-17T22:45:04.043Z
Bbrk24
<p>LLVM has a pretty good <a href="https://llvm.org/docs/ExceptionHandling.html#llvm-code-generation" rel="nofollow noreferrer">explanation for exception handling</a>.</p>
<p>Let's start with a simple C++ routine:</p>
<pre><code>int bar() {
  return 1713;
}

int foo() {
  return bar();
}
</code></pre>
<p>Using Clang, we can pass the arguments <code>-emit-llvm -S</code> to see that the first function becomes:</p>
<pre><code>  ret i32 1713, !dbg !16    # return 1713
</code></pre>
<p>and the second function becomes:</p>
<pre><code>  %1 = call noundef i32 @_Z3barv(), !dbg !18    # call bar()
  ret i32 %1, !dbg !19
</code></pre>
<p>I've embedded my own comments above to make the assembly easier to follow.</p>
<hr />
<p>Now let's introduce some exceptions:</p>
<pre><code>int bar() {
  throw(1713);
  return 0;
}

int foo() {
  try {
    return bar();
  }
  catch (...) {
    return 2723;
  }
}
</code></pre>
<p>The critical part of the first function becomes:</p>
<pre><code>  %1 = call ptr @__cxa_allocate_exception(i64 4) #2, !dbg !16
  store i32 1713, ptr %1, align 16, !dbg !16
  call void @__cxa_throw(ptr %1, ptr @_ZTIi, ptr null) #3, !dbg !16
</code></pre>
<p>It allocates an exception structure via <code>__cxa_allocate_exception</code> and then passes this structure to <code>__cxa_throw</code>.</p>
<p>The <code>try</code> block becomes:</p>
<pre><code>  %4 = invoke noundef i32 @_Z3barv() to label %5 unwind label %6, !dbg !18

5:                                                ; preds = %0
  store i32 %4, ptr %1, align 4, !dbg !20
  br label %14, !dbg !20
</code></pre>
<p>Instead of <code>call</code>, we now have <code>invoke</code>, which includes the goto label for success (<code>%5</code> above) and the goto label for failure (<code>%6</code> below).</p>
<p>Finally, the <code>catch</code> becomes:</p>
<pre><code>6:                                                ; preds = %0
  %7 = landingpad { ptr, i32 } catch ptr null, !dbg !21
  %8 = extractvalue { ptr, i32 } %7, 0, !dbg !21
  store ptr %8, ptr %2, align 8, !dbg !21
  %9 = extractvalue { ptr, i32 } %7, 1, !dbg !21
  store i32 %9, ptr %3, align 4, !dbg !21
  br label %10, !dbg !21

10:                                               ; preds = %6
  %11 = load ptr, ptr %2, align 8, !dbg !22
  %12 = call ptr @__cxa_begin_catch(ptr %11) #2, !dbg !22
  store i32 2723, ptr %1, align 4, !dbg !23    # return 2723
  call void @__cxa_end_catch(), !dbg !25
  br label %14
</code></pre>
<p>The &quot;landing pad&quot; is similar to a function entry point. It must select which <code>catch</code> block to invoke based on the type of the exception. The actual code of the handler is between <code>__cxa_begin_catch</code> and <code>__cxa_end_catch</code>.</p>

CC BY-SA 4.0
2023-05-17T23:24:05.123Z
2023-05-18T00:07:41.940Z
2023-05-18T00:07:41.940Z
chrisaycock
<p><a href="https://en.wikipedia.org/wiki/Setjmp.h" rel="nofollow noreferrer"><code>setjmp</code> and <code>longjmp</code></a> are two C standard library functions for non-local jumps like this. <code>setjmp</code> saves the current environment into a buffer, including the stack and program counter, and <code>longjmp</code> takes the program back to the corresponding setjmp call at a later time. <code>setjmp</code> returns zero the first time, and something else when you <code>longjmp</code> back to it, so the code can branch how it handles the two cases just like a <code>fork</code>.</p>
<p>These functions are available in the C standard library, and consequently for many native-code compilation targets on common platforms, regardless of whether C itself is involved in the implementation. Each try-catch calls <code>setjmp</code> and puts the buffer on a stack, and when an exception is thrown <code>longjmp</code> is called to jump to the nearest exception handler.</p>
<p>The exception-handling code needs to deal with any cleanup required by the stack frames jumped over, re-jumping to the next handler if the exception doesn't match, and maintaining the stack of jump buffers whether an exception was thrown or not. In many cases, however, these two functions do exactly all of the hard work of exception handling and come free with the platform.</p>
<p>I have <a href="https://github.com/mwh/minigrace/blob/master/gracelib.c#L3350" rel="nofollow noreferrer">used these</a> for exception handlers in the past. They're not the most efficient mechanism if you're expecting a large amount of exception handling, but they work very well for fairly little complication in your program. In the first instance this is likely to be the most common mechanism used for a language compiler targetting just the local C ABI.</p>
<hr />
<p>Formally, you can only <code>longjmp</code> <em>up</em> the stack and not down, so this approach doesn't help if you want to have &quot;resumable&quot; exceptions that can continue from the original throw site. In practice, you may be able to get away with it on common platforms, though I wouldn't want to rely on that. If you want to have a more unusual sort of exception like that, this probably won't be the reliable approach for you.</p>

CC BY-SA 4.0
2023-05-18T00:02:55.540Z
2023-05-18T00:02:55.540Z
Michael Homer
# How to compile exceptions?
Posted by: username_0 on 2023-05-17
What are the most common ways of compiling code of a language with first-class support for exceptions, such as C++? Panics in Rust, which have similar behavior, shouldn't be too different.

From my experience, "local jumps" such as `continue` or `break` doesn't seem too hard. The problem with exception appears when one is deep in the call stack. How do common implementations handle this?
**Tags:** compilers control-flow exceptions
> **Comments:**
> **username_1**: How to compile exceptions is partly dependent on the semantics of exceptions that you want. See, for example, this C++ proposal which seeks to make exceptions as efficient as return codes by compiling them like return codes. https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0709r4.pdf  
---
## 3 answers
### Answer by username_2 on 2023-05-17. Score: 6
As syntax sugar for something else
Swift uses this to interface with Objective-C's out-param errors. For example, this set of functions:
func foo() throws -> Int {
  if .random() {
    return 0
  } else {
    throw MyError()
  }
}

func bar() throws {
  _ = try foo()
}

func baz() -> Int {
  do {
    return try foo()
  } catch {
    print(error)
    return 2
  }
}

Would be compiled to something vaguely equivalent to this:
func foo(error: inout Error?) -> Int {
  if .random() {
    return 0
  } else {
    error = MyError()
    return /* some irrelevant value */
  }
}

func bar(error: inout Error?) {
  _ = foo(error: &error)
}

func baz() -> Int {
  var error: Error?
  let result = foo(error: &error)
  if let error {
    print(error)
    return 2
  }
  return result
}

NB: I don't know if Swift does this in general, or only for @objc methods.
Edit to add: It might be even more straightforward to compile this as a "result" type, if you have one:
func foo() -> Result {
  if .random() {
    return .success(0)
  } else {
    return .failure(MyError())
  }
}

func bar() -> Result {
  foo().map { _ in }
}

func baz() -> Int {
  switch foo() {
  case .success(let result):
    return result
  case .failure(let error):
    print(error)
    return 2
  }
}
---
### Answer by username_3 on 2023-05-17. Score: 5
LLVM has a pretty good explanation for exception handling.
Let's start with a simple C++ routine:
int bar() {
  return 1713;
}

int foo() {
  return bar();
}

Using Clang, we can pass the arguments -emit-llvm -S to see that the first function becomes:
  ret i32 1713, !dbg !16    # return 1713

and the second function becomes:
  %1 = call noundef i32 @_Z3barv(), !dbg !18    # call bar()
  ret i32 %1, !dbg !19

I've embedded my own comments above to make the assembly easier to follow.

Now let's introduce some exceptions:
int bar() {
  throw(1713);
  return 0;
}

int foo() {
  try {
    return bar();
  }
  catch (...) {
    return 2723;
  }
}

The critical part of the first function becomes:
  %1 = call ptr @__cxa_allocate_exception(i64 4) #2, !dbg !16
  store i32 1713, ptr %1, align 16, !dbg !16
  call void @__cxa_throw(ptr %1, ptr @_ZTIi, ptr null) #3, !dbg !16

It allocates an exception structure via __cxa_allocate_exception and then passes this structure to __cxa_throw.
The try block becomes:
  %4 = invoke noundef i32 @_Z3barv() to label %5 unwind label %6, !dbg !18

5:                                                ; preds = %0
  store i32 %4, ptr %1, align 4, !dbg !20
  br label %14, !dbg !20

Instead of call, we now have invoke, which includes the goto label for success (%5 above) and the goto label for failure (%6 below).
Finally, the catch becomes:
6:                                                ; preds = %0
  %7 = landingpad { ptr, i32 } catch ptr null, !dbg !21
  %8 = extractvalue { ptr, i32 } %7, 0, !dbg !21
  store ptr %8, ptr %2, align 8, !dbg !21
  %9 = extractvalue { ptr, i32 } %7, 1, !dbg !21
  store i32 %9, ptr %3, align 4, !dbg !21
  br label %10, !dbg !21

10:                                               ; preds = %6
  %11 = load ptr, ptr %2, align 8, !dbg !22
  %12 = call ptr @__cxa_begin_catch(ptr %11) #2, !dbg !22
  store i32 2723, ptr %1, align 4, !dbg !23    # return 2723
  call void @__cxa_end_catch(), !dbg !25
  br label %14

The "landing pad" is similar to a function entry point. It must select which catch block to invoke based on the type of the exception. The actual code of the handler is between __cxa_begin_catch and __cxa_end_catch.
---
### Answer by username_4 on 2023-05-18. Score: 4
[`setjmp` and `longjmp`](https://en.wikipedia.org/wiki/Setjmp.h) are two C standard library functions for non-local jumps like this. `setjmp` saves the current environment into a buffer, including the stack and program counter, and `longjmp` takes the program back to the corresponding setjmp call at a later time. `setjmp` returns zero the first time, and something else when you `longjmp` back to it, so the code can branch how it handles the two cases just like a `fork`.

These functions are available in the C standard library, and consequently for many native-code compilation targets on common platforms, regardless of whether C itself is involved in the implementation. Each try-catch calls `setjmp` and puts the buffer on a stack, and when an exception is thrown `longjmp` is called to jump to the nearest exception handler.

The exception-handling code needs to deal with any cleanup required by the stack frames jumped over, re-jumping to the next handler if the exception doesn't match, and maintaining the stack of jump buffers whether an exception was thrown or not. In many cases, however, these two functions do exactly all of the hard work of exception handling and come free with the platform.

I have [used these](https://github.com/mwh/minigrace/blob/master/gracelib.c#L3350) for exception handlers in the past. They're not the most efficient mechanism if you're expecting a large amount of exception handling, but they work very well for fairly little complication in your program. In the first instance this is likely to be the most common mechanism used for a language compiler targetting just the local C ABI.

---

Formally, you can only `longjmp` *up* the stack and not down, so this approach doesn't help if you want to have "resumable" exceptions that can continue from the original throw site. In practice, you may be able to get away with it on common platforms, though I wouldn't want to rely on that. If you want to have a more unusual sort of exception like that, this probably won't be the reliable approach for you.
---
