File 0159-compiler-Document-exception-handling-at-the-BEAM-SSA.patch of Package erlang
From 476baa9b2ce73dbb7e56036b56935b0e17c9d346 Mon Sep 17 00:00:00 2001
From: Frej Drejhammar <frej.drejhammar@gmail.com>
Date: Fri, 28 May 2021 10:43:53 +0200
Subject: [PATCH] compiler: Document exception handling at the BEAM SSA level
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Document how exception handlers are structured at the the BEAM SSA
level. The material in this patch is based on an email conversation
between the author and Björn Gustavsson <bjorn@erlang.org>.
---
lib/compiler/internal_doc/beam_ssa.md | 107 ++++++++++++++++++++++++++
1 file changed, 107 insertions(+)
diff --git a/lib/compiler/internal_doc/beam_ssa.md b/lib/compiler/internal_doc/beam_ssa.md
index 29ad019194..d32431ecff 100644
--- a/lib/compiler/internal_doc/beam_ssa.md
+++ b/lib/compiler/internal_doc/beam_ssa.md
@@ -1,6 +1,113 @@
Invariants on the Structure and Format of BEAM SSA
==================================================
+Exception Handling
+------------------
+
+The translation of a `try`-`catch` expression into BEAM SSA has the
+following structure:
+
+ @tag = new_try_tag `try`
+ br @tag, ^protected_block0, ^landing_pad_block
+
+ protected_block0:
+ @success0 = ... % Something that could raise an exception
+ br @success0, ^protected_block1, ^landing_pad_block
+
+ ...
+
+ protected_blockN:
+ % The end of the protected code
+ @ignored0 = kill_try_tag @tag
+ br ^after_try_catch
+
+ landing_pad_block:
+ @aggregate = landingpad try, @tag
+ @class = extract @aggregate, `0` % The error class
+ @reason = extract @aggregate, `1` % The reason
+ @stk = extract @aggregate, `2` % The stack trace
+ @ignored1 = kill_try_tag @tag
+ %% Pattern matching on @class, @reason, and @stk is done here
+ %% to send control to the appropriate catch clause
+ br ^after_try_catch
+
+ after_try_catch:
+ % Normal execution continues
+
+The following invariants must hold for the SSA:
+
+ * All code that can cause an exception in one of the protected blocks
+ must have explicit control flow edges to the landing pad block. If
+ there are no edges to the landing pad block except from the block
+ containing the `new_try_tag`, the compiler will remove the
+ redundant exception handler.
+ * The extraction of the class, reason and stack trace from the result
+ of the `landingpad` instruction must be done in that
+ order. Omitting the extraction of elements which are unused is
+ allowed.
+ * Both the landing pad block and the final protected block must end
+ with a `kill_try_tag` instruction. Trying to share the
+ `kill_try_tag` epilogue between the last protected block and the
+ landing pad is unlikely to work.
+
+The translation of an old-style `catch` expression into BEAM SSA has
+the following structure:
+
+ @tag = new_try_tag `try`
+ br @tag, ^protected_block0, ^landing_pad_block
+
+ protected_block0:
+ @success0 = ... % Something that could raise an exception
+ br @success0, ^protected_block1, ^landing_pad_block
+
+ ...
+
+ protected_blockN:
+ % The end of the protected code
+ @successful_result = .... % The result of a successful computation
+ br ^common_end_of_catch
+
+ landing_pad_block:
+ @aggregate = landingpad catch, @tag
+ @catched_val = extract @ssa_agg, `0`
+ br ^common_end_of_catch
+
+ common_end_of_catch:
+ @tmp = phi { @catched_val, ^landing_pad_block },
+ { @successful_result, ^protected_blockN }
+ @result_of_catch_expr = catch_end @tag, @tmp
+
+Just as for a `try`-`catch` expression all code that can cause an
+exception in one of the protected blocks must have explicit control
+flow edges to the landing pad block.
+
+Exception Re-issuing
+--------------------
+
+A typical user-written `try`-`catch` expression will catch a subset of
+all possible exception classes and reasons and leave unhandled
+exceptions to a handler further up the call stack. Re-issuing an
+exception is done with the `resume` instruction. The `resume` must
+come after the `kill_try_tag` instruction in the program flow. For
+example, if the [example in the Exception Handling Section](#exception-handling)
+was to only handle user `throws`, the relevant blocks would look like this:
+
+ landing_pad_block:
+ @aggregate = landingpad `try`, @tag
+ @class = extract @aggregate, `0` % The error class
+ @reason = extract @aggregate, `1` % The reason
+ @stk = extract @aggregate, `2` % The stack trace
+ @ignored1 = kill_try_tag @tag
+ @is_throw = bif:'=:=' @class, `throw`
+ br @is_throw ^first_block_of_throw_handler, ^reissue
+
+ first_block_of_throw_handler:
+ %% Handle the user-defined throw
+
+ reissue:
+ @tmp = resume @stk, @reason
+ ret @tmp
+
Function Calls
--------------
--
2.26.2