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
22thread_local struct _Unwind_LandingPadContext __wasm_lpad_context;
23
24_LIBUNWIND_EXPORT struct _Unwind_LandingPadContext *
25_Unwind_GetWasmLPadContext(void) {
26 return &__wasm_lpad_context;
27}
28
29/// Called by __cxa_throw.
30_LIBUNWIND_EXPORT _Unwind_Reason_Code
31_Unwind_RaiseException(_Unwind_Exception *exception_object) {
32 _LIBUNWIND_TRACE_API("_Unwind_RaiseException(exception_object=%p)",
33 (void *)exception_object);
34 // Use Wasm EH's 'throw' instruction.
35 __builtin_wasm_throw(0, exception_object);
36}
37
38// Define the `__cpp_exception` symbol which `__builtin_wasm_throw` above will
39// reference. This is defined here in `libunwind` as the single canonical
40// definition for this API and it's required for users to ensure that there's
41// only one copy of `libunwind` within a wasm module to ensure this is only
42// defined once and exactly once.
43__asm__(".globl __cpp_exception\n"
44#if defined(__wasm32__)
45 ".tagtype __cpp_exception i32\n"
46#elif defined(__wasm64__)
47 ".tagtype __cpp_exception i64\n"
48#else
49#error "Unsupported Wasm architecture"
50#endif
51 "__cpp_exception:\n");
52
53/// Called by __cxa_end_catch.
54_LIBUNWIND_EXPORT void
55_Unwind_DeleteException(_Unwind_Exception *exception_object) {
56 _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",
57 (void *)(exception_object));
58 if (exception_object->exception_cleanup != NULL)
59 (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
60 exception_object);
61}
62
63/// Called by personality handler to alter register values.
64_LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
65 uintptr_t value) {
66 _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, index=%d, value=%lu)",
67 (void *)context, index, value);
68 // We only use this function to set __wasm_lpad_context.selector field, which
69 // is index 1 in the personality function.
70 if (index == 1)
71 ((struct _Unwind_LandingPadContext *)context)->selector = value;
72}
73
74/// Called by personality handler to get instruction pointer.
75_LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
76 // The result will be used as a 1-based index after decrementing 1, so we
77 // increment 2 here
78 uintptr_t result =
79 ((struct _Unwind_LandingPadContext *)context)->lpad_index + 2;
80 _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => %lu", (void *)context,
81 result);
82 return result;
83}
84
85/// Not used in Wasm.
86_LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
87 uintptr_t value) {}
88
89/// Called by personality handler to get LSDA for current frame.
90_LIBUNWIND_EXPORT uintptr_t
91_Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
92 uintptr_t result = ((struct _Unwind_LandingPadContext *)context)->lsda;
93 _LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) => 0x%lx",
94 (void *)context, result);
95 return result;
96}
97
98/// Not used in Wasm.
99_LIBUNWIND_EXPORT uintptr_t
100_Unwind_GetRegionStart(struct _Unwind_Context *context) {
101 return 0;
102}
103
104#endif // defined(__WASM_EXCEPTIONS__)
105