aboutsummaryrefslogtreecommitdiff
path: root/tools/driver
diff options
context:
space:
mode:
author_ov4 <ov4@ov4.org>2026-10-13 14:52:57 +0000
committer_ov4 <ov4@ov4.org>2026-10-13 14:52:57 +0000
commita484f314b719aec5ed7bdc6f08403342b2125561 (patch)
tree531e331cf823517eae4c350d37bca6a500b2de9f /tools/driver
parent4297086c86f4d11e8a14b76b50705b419d6b7f13 (diff)
feat(compiler)!: add try-catch with C++ stack unwinding
Add TRY/CATCH/ENDTRY and anonymous THROW statements. Use LLVM exception handling and the C++ ABI to propagate exceptions across function calls, clean up catch state, and handle uncaught exceptions at the program boundary. Register exception runtime symbols for the statically linked embedded runner. Verify runtime checks, nested catches, returns, loops, and invalid syntax with smoke programs; exercise unwinding with MCJIT, lli, and native binaries. BREAKING CHANGE: Runtime check failures now throw anonymous exceptions and print only a generic message when uncaught. Native binaries require linking the C++ runtime. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Diffstat (limited to 'tools/driver')
-rw-r--r--tools/driver/EmbeddedRunner.cc34
1 files changed, 34 insertions, 0 deletions
diff --git a/tools/driver/EmbeddedRunner.cc b/tools/driver/EmbeddedRunner.cc
index 83489b1..56e3195 100644
--- a/tools/driver/EmbeddedRunner.cc
+++ b/tools/driver/EmbeddedRunner.cc
@@ -7,6 +7,39 @@
#include "llvm/Support/TargetSelect.h"
#include "llvm/TargetParser/Host.h"
#include "llvm/Transforms/Utils/Cloning.h"
+#include <cxxabi.h>
+#include <typeinfo>
+#include <unwind.h>
+
+// Static C++ runtime symbols are not available through dlsym. Register their
+// actual addresses so the JIT and its unwind tables use the host's runtime.
+extern "C" int
+#if defined(__SEH__)
+__gxx_personality_seh0
+#elif defined(__USING_SJLJ_EXCEPTIONS__)
+__gxx_personality_sj0
+#else
+__gxx_personality_v0
+#endif
+(int, _Unwind_Action, _Unwind_Exception_Class, _Unwind_Exception *, _Unwind_Context *);
+
+static void registerExceptionSymbols() {
+ using llvm::sys::DynamicLibrary;
+ DynamicLibrary::AddSymbol("__cxa_allocate_exception", reinterpret_cast<void *>(&__cxxabiv1::__cxa_allocate_exception));
+ DynamicLibrary::AddSymbol("__cxa_throw", reinterpret_cast<void *>(&__cxxabiv1::__cxa_throw));
+ DynamicLibrary::AddSymbol("__cxa_begin_catch", reinterpret_cast<void *>(&__cxxabiv1::__cxa_begin_catch));
+ DynamicLibrary::AddSymbol("__cxa_end_catch", reinterpret_cast<void *>(&__cxxabiv1::__cxa_end_catch));
+ DynamicLibrary::AddSymbol("_ZTIi", const_cast<std::type_info *>(&typeid(int)));
+#if defined(__SEH__)
+ DynamicLibrary::AddSymbol("__gxx_personality_seh0", reinterpret_cast<void *>(&__gxx_personality_seh0));
+#elif defined(__USING_SJLJ_EXCEPTIONS__)
+ DynamicLibrary::AddSymbol("__gxx_personality_sj0", reinterpret_cast<void *>(&__gxx_personality_sj0));
+ DynamicLibrary::AddSymbol("_Unwind_SjLj_Resume", reinterpret_cast<void *>(&_Unwind_SjLj_Resume));
+#else
+ DynamicLibrary::AddSymbol("__gxx_personality_v0", reinterpret_cast<void *>(&__gxx_personality_v0));
+#endif
+ DynamicLibrary::AddSymbol("_Unwind_Resume", reinterpret_cast<void *>(&_Unwind_Resume));
+}
int runEmbedded(const cps::CodeGen &CG) {
if (llvm::InitializeNativeTarget() || llvm::InitializeNativeTargetAsmPrinter()) {
@@ -18,6 +51,7 @@ int runEmbedded(const cps::CodeGen &CG) {
llvm::errs() << "error: cannot load process symbols: " << Error << "\n";
return 1;
}
+ registerExceptionSymbols();
// Keep CodeGen's module and context alive while the engine owns its clone.
auto Module = llvm::CloneModule(CG.getModule());
Module->setTargetTriple(llvm::sys::getProcessTriple());