Repository navigation
Expand file tree
/
Copy pathobjc_wasm_eh.cc
More file actions
141 lines (126 loc) · 3.64 KB
/
Copy pathobjc_wasm_eh.cc
File metadata and controls
141 lines (126 loc) · 3.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include <cxxabi.h>
#include <typeinfo>
#include "objc/runtime.h"
#include "objc/objc-arc.h"
#include "visibility.h"
/* We build libobjc2 for WebAssembly with emscripten against the libc++abi.
* For now, we do not define a custom personality function and instead let Objective-C
* exceptions piggyback on C++ exceptions.
*
* For WebAssembly clang defaults to `__gxx_wasm_personality_v0` (as of August 2026),
* which redirects to `__gxx_personality_imp` (The C++ unwind phase handler).
* We therefore supply our own RTTI object derived from c++abi's internal
* type info class to override the `can_catch` method and handle unboxing/catching of
* Objective-C Exceptions correctly.
*/
namespace __cxxabiv1
{
// (Re)declare libc++abi's type info class, so we can derive from it.
// This is a private implementation detail of libc++abi, so we need to keep it in sync.
class __shim_type_info : public std::type_info
{
protected:
explicit __shim_type_info(const char *name) : type_info(name) {}
public:
virtual ~__shim_type_info();
virtual void noop1() const;
virtual void noop2() const;
virtual bool can_catch(const __shim_type_info *thrownType,
void *&adjustedPtr) const = 0;
};
}
namespace
{
static BOOL isKindOfClass(Class thrown, Class type)
{
do
{
if (thrown == type)
{
return YES;
}
thrown = class_getSuperclass(thrown);
} while (Nil != thrown);
return NO;
}
static id thrownObject(void *pointer)
{
return *static_cast<id *>(pointer);
}
static void *releaseThrownObject(void *pointer)
{
objc_release(thrownObject(pointer));
return pointer;
}
} // namespace
namespace gnustep {
namespace libobjc {
struct OBJC_PUBLIC __objc_type_info : __cxxabiv1::__shim_type_info
{
explicit __objc_type_info(const char *name) : __shim_type_info(name) {}
};
struct OBJC_PUBLIC __objc_id_type_info : __objc_type_info
{
__objc_id_type_info() : __objc_type_info("@id") {}
bool can_catch(const __cxxabiv1::__shim_type_info *thrownType,
void *&adjustedPtr) const override;
};
struct OBJC_PUBLIC __objc_class_type_info : __objc_type_info
{
using __objc_type_info::__objc_type_info;
bool can_catch(const __cxxabiv1::__shim_type_info *thrownType,
void *&adjustedPtr) const override;
};
bool __objc_id_type_info::can_catch(
const __cxxabiv1::__shim_type_info *thrownType, void *&adjustedPtr) const
{
if (dynamic_cast<const __objc_type_info *>(thrownType) == nullptr)
{
return false;
}
adjustedPtr = thrownObject(adjustedPtr);
return true;
}
bool __objc_class_type_info::can_catch(
const __cxxabiv1::__shim_type_info *thrownType, void *&adjustedPtr) const
{
if (dynamic_cast<const __objc_type_info *>(thrownType) == nullptr)
{
return false;
}
// TODO: Apple compat/non-compat behavior
id thrown = thrownObject(adjustedPtr);
Class caughtClass = (Class)objc_getClass(name());
if (nil == thrown || Nil == caughtClass ||
!isKindOfClass(object_getClass(thrown), caughtClass))
{
return false;
}
adjustedPtr = thrown;
return true;
} // namespace libobjc
} // namespace gnustep
extern "C"
{
OBJC_PUBLIC gnustep::libobjc::__objc_id_type_info __objc_id_type_info;
static bool AppleCompatibleMode = true;
OBJC_PUBLIC int objc_set_apple_compatible_objcxx_exceptions(int newValue)
{
bool oldValue = AppleCompatibleMode;
AppleCompatibleMode = newValue;
return oldValue;
}
OBJC_PUBLIC __attribute__((noreturn)) void objc_exception_throw(id object)
{
objc_retain(object);
id *exception = static_cast<id *>(
__cxxabiv1::__cxa_allocate_exception(sizeof(id)));
*exception = object;
__cxxabiv1::__cxa_throw(exception, &__objc_id_type_info,
releaseThrownObject);
}
OBJC_PUBLIC __attribute__((noreturn)) void objc_exception_rethrow(void)
{
__cxxabiv1::__cxa_rethrow();
}
}