Skip to content

Commit 812cb80

Browse files
committed
Restore deleted Emscripten-only files
1 parent 761d896 commit 812cb80

File tree

2 files changed

+282
-0
lines changed

2 files changed

+282
-0
lines changed
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
//===-------------------- cxa_exception_emscripten.cpp --------------------===//
2+
//
3+
// Most code in the file is directly copied from cxa_exception.cpp.
4+
// TODO(sbc): consider merging them
5+
//
6+
// Notable changes:
7+
// __cxa_allocate_exception doesn't add get_cxa_exception_offset
8+
// __cxa_decrement_exception_refcount dosn't call the destructor if rethrown
9+
// Both of these changes are mirrored from the historical JS implemenation of
10+
// thse functions.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifdef __EMSCRIPTEN__
15+
16+
#include "cxxabi.h"
17+
#include "cxa_exception.h"
18+
#include "include/atomic_support.h"
19+
#include "fallback_malloc.h"
20+
#include "private_typeinfo.h"
21+
#include "stdio.h"
22+
#include "assert.h"
23+
24+
#ifdef __WASM_EXCEPTIONS__
25+
#error "This file should only be included when building with emscripten exceptions"
26+
#endif
27+
28+
// Define to enable extra debugging on stderr.
29+
#if EXCEPTIONS_DEBUG
30+
#include "emscripten/console.h"
31+
#define DEBUG emscripten_errf
32+
#else
33+
#define DEBUG(...)
34+
#endif
35+
36+
// Until recently, Rust's `rust_eh_personality` for emscripten referred to this
37+
// symbol. If Emscripten doesn't provide it, there will be errors when linking
38+
// rust. The rust personality function is never called so we can just abort.
39+
// We need this to support old versions of Rust.
40+
// https://github.com/rust-lang/rust/pull/97888
41+
// TODO: Remove this when Rust doesn't need it anymore.
42+
extern "C" _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code
43+
__gxx_personality_v0(int version,
44+
_Unwind_Action actions,
45+
uint64_t exceptionClass,
46+
_Unwind_Exception* unwind_exception,
47+
_Unwind_Context* context) {
48+
abort();
49+
}
50+
51+
namespace __cxxabiv1 {
52+
53+
// Utility routines
54+
static
55+
inline
56+
__cxa_exception*
57+
cxa_exception_from_thrown_object(void* thrown_object)
58+
{
59+
DEBUG("cxa_exception_from_thrown_object %p -> %p",
60+
thrown_object, static_cast<__cxa_exception*>(thrown_object) - 1);
61+
return static_cast<__cxa_exception*>(thrown_object) - 1;
62+
}
63+
64+
// Note: This is never called when exception_header is masquerading as a
65+
// __cxa_dependent_exception.
66+
static
67+
inline
68+
void*
69+
thrown_object_from_cxa_exception(__cxa_exception* exception_header)
70+
{
71+
DEBUG("thrown_object_from_cxa_exception %p -> %p",
72+
exception_header, static_cast<void*>(exception_header + 1));
73+
return static_cast<void*>(exception_header + 1);
74+
}
75+
76+
// Round s up to next multiple of a.
77+
static inline
78+
size_t aligned_allocation_size(size_t s, size_t a) {
79+
return (s + a - 1) & ~(a - 1);
80+
}
81+
82+
static inline
83+
size_t cxa_exception_size_from_exception_thrown_size(size_t size) {
84+
return aligned_allocation_size(size + sizeof (__cxa_exception),
85+
alignof(__cxa_exception));
86+
}
87+
88+
extern "C" {
89+
90+
// Allocate a __cxa_exception object, and zero-fill it.
91+
// Reserve "thrown_size" bytes on the end for the user's exception
92+
// object. Zero-fill the object. If memory can't be allocated, call
93+
// std::terminate. Return a pointer to the memory to be used for the
94+
// user's exception object.
95+
void *__cxa_allocate_exception(size_t thrown_size) throw() {
96+
size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size);
97+
98+
char *raw_buffer =
99+
(char *)__aligned_malloc_with_fallback(actual_size);
100+
if (NULL == raw_buffer)
101+
std::terminate();
102+
__cxa_exception *exception_header =
103+
static_cast<__cxa_exception *>((void *)(raw_buffer));
104+
::memset(exception_header, 0, actual_size);
105+
return thrown_object_from_cxa_exception(exception_header);
106+
}
107+
108+
109+
// Free a __cxa_exception object allocated with __cxa_allocate_exception.
110+
void __cxa_free_exception(void *thrown_object) throw() {
111+
// Compute the size of the padding before the header.
112+
char *raw_buffer =
113+
((char *)cxa_exception_from_thrown_object(thrown_object));
114+
__aligned_free_with_fallback((void *)raw_buffer);
115+
}
116+
117+
/*
118+
If thrown_object is not null, atomically increment the referenceCount field
119+
of the __cxa_exception header associated with the thrown object referred to
120+
by thrown_object.
121+
122+
Requires: If thrown_object is not NULL, it is a native exception.
123+
*/
124+
void
125+
__cxa_increment_exception_refcount(void *thrown_object) throw() {
126+
if (thrown_object != NULL )
127+
{
128+
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
129+
DEBUG("INC: %p refcnt=%zu", thrown_object, exception_header->referenceCount);
130+
std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(1));
131+
}
132+
}
133+
134+
/*
135+
If thrown_object is not null, atomically decrement the referenceCount field
136+
of the __cxa_exception header associated with the thrown object referred to
137+
by thrown_object. If the referenceCount drops to zero, destroy and
138+
deallocate the exception.
139+
140+
Requires: If thrown_object is not NULL, it is a native exception.
141+
*/
142+
_LIBCXXABI_NO_CFI
143+
void __cxa_decrement_exception_refcount(void *thrown_object) throw() {
144+
if (thrown_object != NULL )
145+
{
146+
__cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object);
147+
DEBUG("DEC: %p refcnt=%zu rethrown=%d", thrown_object,
148+
exception_header->referenceCount, exception_header->rethrown);
149+
assert(exception_header->referenceCount > 0);
150+
if (std::__libcpp_atomic_add(&exception_header->referenceCount, size_t(-1)) == 0 && !exception_header->rethrown)
151+
{
152+
DEBUG("DEL: %p (dtor=%p)", thrown_object, exception_header->exceptionDestructor);
153+
if (NULL != exception_header->exceptionDestructor)
154+
exception_header->exceptionDestructor(thrown_object);
155+
__cxa_free_exception(thrown_object);
156+
}
157+
}
158+
}
159+
160+
__cxa_exception* __cxa_init_primary_exception(void* object, std::type_info* tinfo,
161+
void *(_LIBCXXABI_DTOR_FUNC* dest)(void*)) throw() {
162+
__cxa_exception* exception_header = cxa_exception_from_thrown_object(object);
163+
exception_header->referenceCount = 0;
164+
exception_header->exceptionType = tinfo;
165+
exception_header->exceptionDestructor = dest;
166+
return exception_header;
167+
}
168+
169+
} // extern "C"
170+
171+
} // abi
172+
173+
#endif // __EMSCRIPTEN__
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
#ifdef __EMSCRIPTEN__
2+
3+
#include "cxxabi.h"
4+
5+
#include "cxa_exception.h"
6+
#include "private_typeinfo.h"
7+
#include <stdio.h>
8+
// #include <stdint.h>
9+
// #include <stdlib.h>
10+
#include <string.h>
11+
12+
namespace __cxxabiv1 {
13+
14+
// Utility routines
15+
static
16+
inline
17+
__cxa_exception*
18+
cxa_exception_from_thrown_object(void* thrown_object)
19+
{
20+
return static_cast<__cxa_exception*>(thrown_object) - 1;
21+
}
22+
23+
// Note: This is never called when exception_header is masquerading as a
24+
// __cxa_dependent_exception.
25+
static
26+
inline
27+
void*
28+
thrown_object_from_cxa_exception(__cxa_exception* exception_header)
29+
{
30+
return static_cast<void*>(exception_header + 1);
31+
}
32+
33+
// Get the exception object from the unwind pointer.
34+
// Relies on the structure layout, where the unwind pointer is right in
35+
// front of the user's exception object
36+
static inline __cxa_exception* cxa_exception_from_unwind_exception(
37+
_Unwind_Exception* unwind_exception) {
38+
return cxa_exception_from_thrown_object(unwind_exception + 1);
39+
}
40+
41+
extern "C" {
42+
43+
void* __thrown_object_from_unwind_exception(
44+
_Unwind_Exception* unwind_exception) {
45+
__cxa_exception* exception_header =
46+
cxa_exception_from_unwind_exception(unwind_exception);
47+
return thrown_object_from_cxa_exception(exception_header);
48+
}
49+
50+
// Given a thrown_object, puts the information about its type and message into
51+
// 'type' and 'message' output parameters. 'type' will contain the string
52+
// representation of the type of the exception, e.g., 'int'. 'message' will
53+
// contain the result of 'std::exception::what()' method if the type of the
54+
// exception is a subclass of std::exception; otherwise it will be NULL. The
55+
// caller is responsible for freeing 'type' buffer and also 'message' buffer, if
56+
// it is not NULL.
57+
void __get_exception_message(void* thrown_object, char** type, char** message) {
58+
__cxa_exception* exception_header =
59+
cxa_exception_from_thrown_object(thrown_object);
60+
const __shim_type_info* thrown_type =
61+
static_cast<const __shim_type_info*>(exception_header->exceptionType);
62+
const char* type_name = thrown_type->name();
63+
64+
int status = 0;
65+
char* demangled_buf = __cxa_demangle(type_name, 0, 0, &status);
66+
if (status == 0 && demangled_buf) {
67+
*type = demangled_buf;
68+
} else {
69+
if (demangled_buf) {
70+
free(demangled_buf);
71+
}
72+
*type = (char*)malloc(strlen(type_name) + 1);
73+
strcpy(*type, type_name);
74+
}
75+
76+
*message = NULL;
77+
const __shim_type_info* catch_type =
78+
static_cast<const __shim_type_info*>(&typeid(std::exception));
79+
int can_catch = catch_type->can_catch(thrown_type, thrown_object);
80+
if (can_catch) {
81+
const char* what =
82+
static_cast<const std::exception*>(thrown_object)->what();
83+
*message = (char*)malloc(strlen(what) + 1);
84+
strcpy(*message, what);
85+
}
86+
}
87+
88+
// Returns a message saying that execution was terminated due to an exception.
89+
// This message is freshly malloc'd and should be freed.
90+
char* __get_exception_terminate_message(void* thrown_object) {
91+
char* type;
92+
char* message;
93+
__get_exception_message(thrown_object, &type, &message);
94+
char* result;
95+
if (message != NULL) {
96+
asprintf(
97+
&result, "terminating with uncaught exception %s: %s", type, message);
98+
free(message);
99+
} else {
100+
asprintf(&result, "terminating with uncaught exception of type %s", type);
101+
}
102+
free(type);
103+
return result;
104+
}
105+
} // extern "C"
106+
107+
} // namespace __cxxabiv1
108+
109+
#endif // __EMSCRIPTEN__

0 commit comments

Comments
 (0)