1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//
8// Implements Wasm exception handling proposal
9// (https://github.com/WebAssembly/exception-handling) based C++ exceptions
10//
11//===----------------------------------------------------------------------===//
12
13#include <stdbool.h>
14
15#include "config.h"
16
17#ifdef __WASM_EXCEPTIONS__
18
19#include "unwind.h"
20#include <threads.h>
21
22_LIBUNWIND_EXPORT thread_local struct _Unwind_LandingPadContext
23 __wasm_lpad_context;
24
25/// Called by __cxa_throw.
26_LIBUNWIND_EXPORT _Unwind_Reason_Code
27_Unwind_RaiseException(_Unwind_Exception *exception_object) {
28 _LIBUNWIND_TRACE_API("_Unwind_RaiseException(exception_object=%p)",
29 (void *)exception_object);
30 // Use Wasm EH's 'throw' instruction.
31 __builtin_wasm_throw(0, exception_object);
32}
33
34// Define the `__cpp_exception` symbol which `__builtin_wasm_throw` above will
35// reference. This is defined here in `libunwind` as the single canonical
36// definition for this API and it's required for users to ensure that there's
37// only one copy of `libunwind` within a wasm module to ensure this is only
38// defined once and exactly once.
39__asm__(".globl __cpp_exception\n"
40#if defined(__wasm32__)
41 ".tagtype __cpp_exception i32\n"
42#elif defined(__wasm64__)
43 ".tagtype __cpp_exception i64\n"
44#else
45#error "Unsupported Wasm architecture"
46#endif
47 "__cpp_exception:\n");
48
49/// Called by __cxa_end_catch.
50_LIBUNWIND_EXPORT void
51_Unwind_DeleteException(_Unwind_Exception *exception_object) {
52 _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",
53 (void *)(exception_object));
54 if (exception_object->exception_cleanup != NULL)
55 (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
56 exception_object);
57}
58
59/// Called by personality handler to alter register values.
60_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
61 uintptr_t value) {
62 _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, index=%d, value=%lu)",
63 (void *)context, index, value);
64 // We only use this function to set __wasm_lpad_context.selector field, which
65 // is index 1 in the personality function.
66 if (index == 1)
67 ((struct _Unwind_LandingPadContext *)context)->selector = value;
68}
69
70/// Called by personality handler to get instruction pointer.
71_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
72 // The result will be used as a 1-based index after decrementing 1, so we
73 // increment 2 here
74 uintptr_t result =
75 ((struct _Unwind_LandingPadContext *)context)->lpad_index + 2;
76 _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => %lu", (void *)context,
77 result);
78 return result;
79}
80
81/// Not used in Wasm.
82_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
83 uintptr_t value) {}
84
85/// Called by personality handler to get LSDA for current frame.
86_LIBUNWIND_EXPORT uintptr_t
87_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
88 uintptr_t result = ((struct _Unwind_LandingPadContext *)context)->lsda;
89 _LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) => 0x%lx",
90 (void *)context, result);
91 return result;
92}
93
94/// Not used in Wasm.
95_LIBUNWIND_EXPORT uintptr_t
96_Unwind_GetRegionStart(struct _Unwind_Context *context) {
97 return 0;
98}
99
100#endif // defined(__WASM_EXCEPTIONS__)
101