15f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 25f757f3fSDimitry Andric // 35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 65f757f3fSDimitry Andric // 75f757f3fSDimitry Andric // 85f757f3fSDimitry Andric // Implements Wasm exception handling proposal 95f757f3fSDimitry Andric // (https://github.com/WebAssembly/exception-handling) based C++ exceptions 105f757f3fSDimitry Andric // 115f757f3fSDimitry Andric //===----------------------------------------------------------------------===// 125f757f3fSDimitry Andric 135f757f3fSDimitry Andric #include <stdbool.h> 145f757f3fSDimitry Andric 155f757f3fSDimitry Andric #include "config.h" 165f757f3fSDimitry Andric 17*0fca6ea1SDimitry Andric #ifdef __WASM_EXCEPTIONS__ 185f757f3fSDimitry Andric 195f757f3fSDimitry Andric #include "unwind.h" 205f757f3fSDimitry Andric #include <threads.h> 215f757f3fSDimitry Andric 225f757f3fSDimitry Andric _Unwind_Reason_Code __gxx_personality_wasm0(int version, _Unwind_Action actions, 235f757f3fSDimitry Andric uint64_t exceptionClass, 245f757f3fSDimitry Andric _Unwind_Exception *unwind_exception, 255f757f3fSDimitry Andric _Unwind_Context *context); 265f757f3fSDimitry Andric 275f757f3fSDimitry Andric struct _Unwind_LandingPadContext { 285f757f3fSDimitry Andric // Input information to personality function 295f757f3fSDimitry Andric uintptr_t lpad_index; // landing pad index 305f757f3fSDimitry Andric uintptr_t lsda; // LSDA address 315f757f3fSDimitry Andric 325f757f3fSDimitry Andric // Output information computed by personality function 335f757f3fSDimitry Andric uintptr_t selector; // selector value 345f757f3fSDimitry Andric }; 355f757f3fSDimitry Andric 365f757f3fSDimitry Andric // Communication channel between compiler-generated user code and personality 375f757f3fSDimitry Andric // function 385f757f3fSDimitry Andric thread_local struct _Unwind_LandingPadContext __wasm_lpad_context; 395f757f3fSDimitry Andric 405f757f3fSDimitry Andric /// Calls to this function is in landing pads in compiler-generated user code. 415f757f3fSDimitry Andric /// In other EH schemes, stack unwinding is done by libunwind library, which 425f757f3fSDimitry Andric /// calls the personality function for each each frame it lands. On the other 435f757f3fSDimitry Andric /// hand, WebAssembly stack unwinding process is performed by a VM, and the 445f757f3fSDimitry Andric /// personality function cannot be called from there. So the compiler inserts 455f757f3fSDimitry Andric /// a call to this function in landing pads in the user code, which in turn 465f757f3fSDimitry Andric /// calls the personality function. 475f757f3fSDimitry Andric _Unwind_Reason_Code _Unwind_CallPersonality(void *exception_ptr) { 485f757f3fSDimitry Andric struct _Unwind_Exception *exception_object = 495f757f3fSDimitry Andric (struct _Unwind_Exception *)exception_ptr; 505f757f3fSDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_CallPersonality(exception_object=%p)", 515f757f3fSDimitry Andric (void *)exception_object); 525f757f3fSDimitry Andric 535f757f3fSDimitry Andric // Reset the selector. 545f757f3fSDimitry Andric __wasm_lpad_context.selector = 0; 555f757f3fSDimitry Andric 565f757f3fSDimitry Andric // Call personality function. Wasm does not have two-phase unwinding, so we 575f757f3fSDimitry Andric // only do the cleanup phase. 585f757f3fSDimitry Andric return __gxx_personality_wasm0( 595f757f3fSDimitry Andric 1, _UA_SEARCH_PHASE, exception_object->exception_class, exception_object, 605f757f3fSDimitry Andric (struct _Unwind_Context *)&__wasm_lpad_context); 615f757f3fSDimitry Andric } 625f757f3fSDimitry Andric 635f757f3fSDimitry Andric /// Called by __cxa_throw. 645f757f3fSDimitry Andric _LIBUNWIND_EXPORT _Unwind_Reason_Code 655f757f3fSDimitry Andric _Unwind_RaiseException(_Unwind_Exception *exception_object) { 665f757f3fSDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_RaiseException(exception_object=%p)", 675f757f3fSDimitry Andric (void *)exception_object); 685f757f3fSDimitry Andric // Use Wasm EH's 'throw' instruction. 695f757f3fSDimitry Andric __builtin_wasm_throw(0, exception_object); 705f757f3fSDimitry Andric } 715f757f3fSDimitry Andric 725f757f3fSDimitry Andric /// Called by __cxa_end_catch. 735f757f3fSDimitry Andric _LIBUNWIND_EXPORT void 745f757f3fSDimitry Andric _Unwind_DeleteException(_Unwind_Exception *exception_object) { 755f757f3fSDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_DeleteException(ex_obj=%p)", 765f757f3fSDimitry Andric (void *)(exception_object)); 775f757f3fSDimitry Andric if (exception_object->exception_cleanup != NULL) 785f757f3fSDimitry Andric (*exception_object->exception_cleanup)(_URC_FOREIGN_EXCEPTION_CAUGHT, 795f757f3fSDimitry Andric exception_object); 805f757f3fSDimitry Andric } 815f757f3fSDimitry Andric 825f757f3fSDimitry Andric /// Called by personality handler to alter register values. 835f757f3fSDimitry Andric _LIBUNWIND_EXPORT void _Unwind_SetGR(struct _Unwind_Context *context, int index, 845f757f3fSDimitry Andric uintptr_t value) { 855f757f3fSDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_SetGR(context=%p, index=%d, value=%lu)", 865f757f3fSDimitry Andric (void *)context, index, value); 875f757f3fSDimitry Andric // We only use this function to set __wasm_lpad_context.selector field, which 885f757f3fSDimitry Andric // is index 1 in the personality function. 895f757f3fSDimitry Andric if (index == 1) 905f757f3fSDimitry Andric ((struct _Unwind_LandingPadContext *)context)->selector = value; 915f757f3fSDimitry Andric } 925f757f3fSDimitry Andric 935f757f3fSDimitry Andric /// Called by personality handler to get instruction pointer. 945f757f3fSDimitry Andric _LIBUNWIND_EXPORT uintptr_t _Unwind_GetIP(struct _Unwind_Context *context) { 955f757f3fSDimitry Andric // The result will be used as an 1-based index after decrementing 1, so we 965f757f3fSDimitry Andric // increment 2 here 975f757f3fSDimitry Andric uintptr_t result = 985f757f3fSDimitry Andric ((struct _Unwind_LandingPadContext *)context)->lpad_index + 2; 995f757f3fSDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_GetIP(context=%p) => %lu", (void *)context, 1005f757f3fSDimitry Andric result); 1015f757f3fSDimitry Andric return result; 1025f757f3fSDimitry Andric } 1035f757f3fSDimitry Andric 1045f757f3fSDimitry Andric /// Not used in Wasm. 1055f757f3fSDimitry Andric _LIBUNWIND_EXPORT void _Unwind_SetIP(struct _Unwind_Context *context, 1065f757f3fSDimitry Andric uintptr_t value) {} 1075f757f3fSDimitry Andric 1085f757f3fSDimitry Andric /// Called by personality handler to get LSDA for current frame. 1095f757f3fSDimitry Andric _LIBUNWIND_EXPORT uintptr_t 1105f757f3fSDimitry Andric _Unwind_GetLanguageSpecificData(struct _Unwind_Context *context) { 1115f757f3fSDimitry Andric uintptr_t result = ((struct _Unwind_LandingPadContext *)context)->lsda; 1125f757f3fSDimitry Andric _LIBUNWIND_TRACE_API("_Unwind_GetLanguageSpecificData(context=%p) => 0x%lx", 1135f757f3fSDimitry Andric (void *)context, result); 1145f757f3fSDimitry Andric return result; 1155f757f3fSDimitry Andric } 1165f757f3fSDimitry Andric 1175f757f3fSDimitry Andric /// Not used in Wasm. 1185f757f3fSDimitry Andric _LIBUNWIND_EXPORT uintptr_t 1195f757f3fSDimitry Andric _Unwind_GetRegionStart(struct _Unwind_Context *context) { 1205f757f3fSDimitry Andric return 0; 1215f757f3fSDimitry Andric } 1225f757f3fSDimitry Andric 123*0fca6ea1SDimitry Andric #endif // defined(__WASM_EXCEPTIONS__) 124