xref: /freebsd/contrib/llvm-project/libunwind/src/Unwind-wasm.c (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
2*5f757f3fSDimitry Andric //
3*5f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*5f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*5f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*5f757f3fSDimitry Andric //
7*5f757f3fSDimitry Andric //
8*5f757f3fSDimitry Andric //  Implements Wasm exception handling proposal
9*5f757f3fSDimitry Andric //  (https://github.com/WebAssembly/exception-handling) based C++ exceptions
10*5f757f3fSDimitry Andric //
11*5f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
12*5f757f3fSDimitry Andric 
13*5f757f3fSDimitry Andric #include <stdbool.h>
14*5f757f3fSDimitry Andric 
15*5f757f3fSDimitry Andric #include "config.h"
16*5f757f3fSDimitry Andric 
17*5f757f3fSDimitry Andric #ifdef __USING_WASM_EXCEPTIONS__
18*5f757f3fSDimitry Andric 
19*5f757f3fSDimitry Andric #include "unwind.h"
20*5f757f3fSDimitry Andric #include <threads.h>
21*5f757f3fSDimitry Andric 
22*5f757f3fSDimitry Andric _Unwind_Reason_Code __gxx_personality_wasm0(int version, _Unwind_Action actions,
23*5f757f3fSDimitry Andric                                             uint64_t exceptionClass,
24*5f757f3fSDimitry Andric                                             _Unwind_Exception *unwind_exception,
25*5f757f3fSDimitry Andric                                             _Unwind_Context *context);
26*5f757f3fSDimitry Andric 
27*5f757f3fSDimitry Andric struct _Unwind_LandingPadContext {
28*5f757f3fSDimitry Andric   // Input information to personality function
29*5f757f3fSDimitry Andric   uintptr_t lpad_index; // landing pad index
30*5f757f3fSDimitry Andric   uintptr_t lsda;       // LSDA address
31*5f757f3fSDimitry Andric 
32*5f757f3fSDimitry Andric   // Output information computed by personality function
33*5f757f3fSDimitry Andric   uintptr_t selector; // selector value
34*5f757f3fSDimitry Andric };
35*5f757f3fSDimitry Andric 
36*5f757f3fSDimitry Andric // Communication channel between compiler-generated user code and personality
37*5f757f3fSDimitry Andric // function
38*5f757f3fSDimitry Andric thread_local struct _Unwind_LandingPadContext __wasm_lpad_context;
39*5f757f3fSDimitry Andric 
40*5f757f3fSDimitry Andric /// Calls to this function is in landing pads in compiler-generated user code.
41*5f757f3fSDimitry Andric /// In other EH schemes, stack unwinding is done by libunwind library, which
42*5f757f3fSDimitry Andric /// calls the personality function for each each frame it lands. On the other
43*5f757f3fSDimitry Andric /// hand, WebAssembly stack unwinding process is performed by a VM, and the
44*5f757f3fSDimitry Andric /// personality function cannot be called from there. So the compiler inserts
45*5f757f3fSDimitry Andric /// a call to this function in landing pads in the user code, which in turn
46*5f757f3fSDimitry Andric /// calls the personality function.
47*5f757f3fSDimitry Andric _Unwind_Reason_Code _Unwind_CallPersonality(void *exception_ptr) {
48*5f757f3fSDimitry Andric   struct _Unwind_Exception *exception_object =
49*5f757f3fSDimitry Andric       (struct _Unwind_Exception *)exception_ptr;
50*5f757f3fSDimitry Andric   _LIBUNWIND_TRACE_API("_Unwind_CallPersonality(exception_object=%p)",
51*5f757f3fSDimitry Andric                        (void *)exception_object);
52*5f757f3fSDimitry Andric 
53*5f757f3fSDimitry Andric   // Reset the selector.
54*5f757f3fSDimitry Andric   __wasm_lpad_context.selector = 0;
55*5f757f3fSDimitry Andric 
56*5f757f3fSDimitry Andric   // Call personality function. Wasm does not have two-phase unwinding, so we
57*5f757f3fSDimitry Andric   // only do the cleanup phase.
58*5f757f3fSDimitry Andric   return __gxx_personality_wasm0(
59*5f757f3fSDimitry Andric       1, _UA_SEARCH_PHASE, exception_object->exception_class, exception_object,
60*5f757f3fSDimitry Andric       (struct _Unwind_Context *)&__wasm_lpad_context);
61*5f757f3fSDimitry Andric }
62*5f757f3fSDimitry Andric 
63*5f757f3fSDimitry Andric /// Called by __cxa_throw.
64*5f757f3fSDimitry Andric _LIBUNWIND_EXPORT _Unwind_Reason_Code
65*5f757f3fSDimitry Andric _Unwind_RaiseException(_Unwind_Exception *exception_object) {
66*5f757f3fSDimitry Andric   _LIBUNWIND_TRACE_API("_Unwind_RaiseException(exception_object=%p)",
67*5f757f3fSDimitry Andric                        (void *)exception_object);
68*5f757f3fSDimitry Andric   // Use Wasm EH's 'throw' instruction.
69*5f757f3fSDimitry Andric   __builtin_wasm_throw(0, exception_object);
70*5f757f3fSDimitry Andric }
71*5f757f3fSDimitry Andric 
72*5f757f3fSDimitry Andric /// Called by __cxa_end_catch.
73*5f757f3fSDimitry Andric _LIBUNWIND_EXPORT void
74*5f757f3fSDimitry Andric _Unwind_DeleteException(_Unwind_Exception *exception_object) {
75*5f757f3fSDimitry Andric   _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)",
76*5f757f3fSDimitry Andric                        (void *)(exception_object));
77*5f757f3fSDimitry Andric   if (exception_object->exception_cleanup != NULL)
78*5f757f3fSDimitry Andric     (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT,
79*5f757f3fSDimitry Andric                                            exception_object);
80*5f757f3fSDimitry Andric }
81*5f757f3fSDimitry Andric 
82*5f757f3fSDimitry Andric /// Called by personality handler to alter register values.
83*5f757f3fSDimitry Andric _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index,
84*5f757f3fSDimitry Andric                                      uintptr_t value) {
85*5f757f3fSDimitry Andric   _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, index=%d, value=%lu)",
86*5f757f3fSDimitry Andric                        (void *)context, index, value);
87*5f757f3fSDimitry Andric   // We only use this function to set __wasm_lpad_context.selector field, which
88*5f757f3fSDimitry Andric   // is index 1 in the personality function.
89*5f757f3fSDimitry Andric   if (index == 1)
90*5f757f3fSDimitry Andric     ((struct _Unwind_LandingPadContext *)context)->selector = value;
91*5f757f3fSDimitry Andric }
92*5f757f3fSDimitry Andric 
93*5f757f3fSDimitry Andric /// Called by personality handler to get instruction pointer.
94*5f757f3fSDimitry Andric _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) {
95*5f757f3fSDimitry Andric   // The result will be used as an 1-based index after decrementing 1, so we
96*5f757f3fSDimitry Andric   // increment 2 here
97*5f757f3fSDimitry Andric   uintptr_t result =
98*5f757f3fSDimitry Andric       ((struct _Unwind_LandingPadContext *)context)->lpad_index + 2;
99*5f757f3fSDimitry Andric   _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => %lu", (void *)context,
100*5f757f3fSDimitry Andric                        result);
101*5f757f3fSDimitry Andric   return result;
102*5f757f3fSDimitry Andric }
103*5f757f3fSDimitry Andric 
104*5f757f3fSDimitry Andric /// Not used in Wasm.
105*5f757f3fSDimitry Andric _LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context,
106*5f757f3fSDimitry Andric                                      uintptr_t value) {}
107*5f757f3fSDimitry Andric 
108*5f757f3fSDimitry Andric /// Called by personality handler to get LSDA for current frame.
109*5f757f3fSDimitry Andric _LIBUNWIND_EXPORT uintptr_t
110*5f757f3fSDimitry Andric _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) {
111*5f757f3fSDimitry Andric   uintptr_t result = ((struct _Unwind_LandingPadContext *)context)->lsda;
112*5f757f3fSDimitry Andric   _LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) => 0x%lx",
113*5f757f3fSDimitry Andric                        (void *)context, result);
114*5f757f3fSDimitry Andric   return result;
115*5f757f3fSDimitry Andric }
116*5f757f3fSDimitry Andric 
117*5f757f3fSDimitry Andric /// Not used in Wasm.
118*5f757f3fSDimitry Andric _LIBUNWIND_EXPORT uintptr_t
119*5f757f3fSDimitry Andric _Unwind_GetRegionStart(struct _Unwind_Context *context) {
120*5f757f3fSDimitry Andric   return 0;
121*5f757f3fSDimitry Andric }
122*5f757f3fSDimitry Andric 
123*5f757f3fSDimitry Andric #endif // defined(__USING_WASM_EXCEPTIONS__)
124