[EH] Handle dependent exceptions in refcounting

In libcxxabi used in Wasm EH, `__cxa_exception` is used to represent a
normal primary exception, and `__cxa_dependent_exception` is to a
dependent exception created by `std::rethrow_exception`.
`std::rethrow_exception` allocates and throws a
`__cxa_dependent_exception` whose `primaryException` field points to its
primary exception.

`__cxa_exception` and `__cxa_dependent_exception`'s layouts are
identical except where `referenceCount` is in `__cxa_exception`, there
is `primaryException` in `__cxa_dependent_exception`:
https://github.com/emscripten-core/emscripten/blob/30bbb45939d0136eae1637dd17146cc02ee1658f/system/lib/libcxxabi/src/cxa_exception.h#L100-L101

But `__cxa_in/decrementExceptionRefcount` assumes all it gets is primary
exceptions, and tries to increment the `referenceCount` field, which
ends up incrementing `primaryException` pointer in
`__cxa_dependent_exception`.

This is not a problem within libcxxabi because all callers to those
methods extract a primary exception from a dependent exception before
calling. But these methods are also called from JS
`in/decrementExceptionRefcount`, which doesn't know about dependent
exceptions:
https://github.com/emscripten-core/emscripten/blob/30bbb45939d0136eae1637dd17146cc02ee1658f/src/lib/libexceptions.js#L381-L391

This checks whether an exception is a dependent exception, and if it is,
extracts the primary exception from it, and in/decrement its refcount.
And if it reaches 0, also frees the dependent exception in addition to
the primary one.

We also have similar code to handle dependent exceptions in
`__get_exception_message`:
https://github.com/emscripten-core/emscripten/blob/30bbb45939d0136eae1637dd17146cc02ee1658f/system/lib/libcxxabi/src/cxa_exception_js_utils.cpp#L89-L95

This is a part of fixes for #27705.
diff --git a/system/lib/libcxxabi/src/cxa_exception.cpp b/system/lib/libcxxabi/src/cxa_exception.cpp
index 443ac28..b06112d 100644
--- a/system/lib/libcxxabi/src/cxa_exception.cpp
+++ b/system/lib/libcxxabi/src/cxa_exception.cpp
@@ -689,6 +689,15 @@
     if (thrown_object != NULL )
     {
         __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
+#ifdef __WASM_EXCEPTIONS__
+        if (isDependentException(&exception_header->unwindHeader))
+        {
+            __cxa_dependent_exception* dep_exception_header =
+                reinterpret_cast<__cxa_dependent_exception*>(exception_header);
+            thrown_object = dep_exception_header->primaryException;
+            exception_header = cxa_exception_from_thrown_object(thrown_object);
+        }
+#endif
         std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1));
     }
 }
@@ -706,11 +715,25 @@
     if (thrown_object != NULL )
     {
         __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
+#ifdef __WASM_EXCEPTIONS__
+        __cxa_dependent_exception* dep_exception_header = NULL;
+        if (isDependentException(&exception_header->unwindHeader))
+        {
+            dep_exception_header =
+                reinterpret_cast<__cxa_dependent_exception*>(exception_header);
+            thrown_object = dep_exception_header->primaryException;
+            exception_header = cxa_exception_from_thrown_object(thrown_object);
+        }
+#endif
         if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0)
         {
             if (NULL != exception_header->exceptionDestructor)
                 exception_header->exceptionDestructor(thrown_object);
             __cxa_free_exception(thrown_object);
+#ifdef __WASM_EXCEPTIONS__
+            if (NULL != dep_exception_header)
+                __cxa_free_dependent_exception(dep_exception_header);
+#endif
         }
     }
 }
diff --git a/test/core/test_exceptions_refcount_2.cpp b/test/core/test_exceptions_refcount_2.cpp
index 80836f0..9aeab09 100644
--- a/test/core/test_exceptions_refcount_2.cpp
+++ b/test/core/test_exceptions_refcount_2.cpp
@@ -15,12 +15,24 @@
   }
 }
 
+EMSCRIPTEN_KEEPALIVE extern "C" void rethrow_ptr() {
+  try {
+    throw MyException();
+  } catch (...) {
+    std::rethrow_exception(std::current_exception());
+  }
+}
+
 int main() {
   EM_ASM({
-    try {
-      _rethrow();
-    } catch (e) {
-      decrementExceptionRefcount(e);
+    for (let fn of [_rethrow, _rethrow_ptr]) {
+      try {
+        fn();
+      } catch (e) {
+        incrementExceptionRefcount(e);
+        decrementExceptionRefcount(e);
+        decrementExceptionRefcount(e);
+      }
     }
   });
 }
diff --git a/test/core/test_exceptions_refcount_2.out b/test/core/test_exceptions_refcount_2.out
index 328c373..514bfd7 100644
--- a/test/core/test_exceptions_refcount_2.out
+++ b/test/core/test_exceptions_refcount_2.out
@@ -1 +1,2 @@
 ~MyException()
+~MyException()