Skip to content
This repository was archived by the owner on Feb 8, 2024. It is now read-only.

Commit decbd3d

Browse files
committed
add msvc/x86 EH implementation
1 parent cca7774 commit decbd3d

File tree

1 file changed

+232
-0
lines changed

1 file changed

+232
-0
lines changed

src/ldc/eh/win32.d

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
/**
2+
* This module implements the runtime-part of LDC exceptions
3+
* on Windows win32.
4+
*/
5+
module ldc.eh.win32;
6+
7+
version(CRuntime_Microsoft):
8+
version(Win32):
9+
10+
import ldc.eh.common;
11+
import core.sys.windows.windows;
12+
import core.exception : onOutOfMemoryError;
13+
import core.stdc.stdlib : malloc;
14+
import core.stdc.string : memcpy;
15+
16+
// pointers are image relative for Win64 versions
17+
version(Win64)
18+
alias ImgPtr(T) = uint; // offset into image
19+
else
20+
alias ImgPtr(T) = T;
21+
22+
alias PMFN = ImgPtr!(void function(void*));
23+
24+
struct TypeDescriptor(int N)
25+
{
26+
version(_RTTI)
27+
const void * pVFTable; // Field overloaded by RTTI
28+
else
29+
uint hash; // Hash value computed from type's decorated name
30+
31+
void * spare; // reserved, possible for RTTI
32+
char[N+1] name; // variable size, zero terminated
33+
}
34+
35+
struct PMD
36+
{
37+
int mdisp; // Offset of intended data within base
38+
int pdisp; // Displacement to virtual base pointer
39+
int vdisp; // Index within vbTable to offset of base
40+
}
41+
42+
struct CatchableType
43+
{
44+
uint properties; // Catchable Type properties (Bit field)
45+
ImgPtr!(TypeDescriptor!1*) pType; // Pointer to TypeDescriptor
46+
PMD thisDisplacement; // Pointer to instance of catch type within thrown object.
47+
int sizeOrOffset; // Size of simple-type object or offset into buffer of 'this' pointer for catch object
48+
PMFN copyFunction; // Copy constructor or CC-closure
49+
}
50+
51+
enum CT_IsSimpleType = 0x00000001; // type is a simple type (includes pointers)
52+
enum CT_ByReferenceOnly = 0x00000002; // type must be caught by reference
53+
enum CT_HasVirtualBase = 0x00000004; // type is a class with virtual bases
54+
enum CT_IsWinRTHandle = 0x00000008; // type is a winrt handle
55+
enum CT_IsStdBadAlloc = 0x00000010; // type is a a std::bad_alloc
56+
57+
struct CatchableTypeArray
58+
{
59+
int nCatchableTypes;
60+
ImgPtr!(CatchableType*)[2] arrayOfCatchableTypes;
61+
}
62+
63+
struct _ThrowInfo
64+
{
65+
uint attributes; // Throw Info attributes (Bit field)
66+
PMFN pmfnUnwind; // Destructor to call when exception has been handled or aborted.
67+
PMFN pForwardCompat; // pointer to Forward compatibility frame handler
68+
ImgPtr!(CatchableTypeArray*) pCatchableTypeArray;// pointer to CatchableTypeArray
69+
}
70+
71+
enum TI_IsConst = 0x00000001; // thrown object has const qualifier
72+
enum TI_IsVolatile = 0x00000002; // thrown object has volatile qualifier
73+
enum TI_IsUnaligned = 0x00000004; // thrown object has unaligned qualifier
74+
enum TI_IsPure = 0x00000008; // object thrown from a pure module
75+
enum TI_IsWinRT = 0x00000010; // object thrown is a WinRT Exception
76+
77+
extern(Windows) void RaiseException(DWORD dwExceptionCode,
78+
DWORD dwExceptionFlags,
79+
DWORD nNumberOfArguments,
80+
ULONG_PTR* lpArguments);
81+
82+
__gshared TypeDescriptor!16 tdObject = { 0, null, "_D6object6Object\0" };
83+
__gshared TypeDescriptor!20 tdThrowable = { 0, null, "_D6object9Throwable\0" };
84+
__gshared TypeDescriptor!12 tdException = { 0, null, "_D9Exception\0" };
85+
version(none) {
86+
__gshared CatchableType ctThrowable = { CT_IsSimpleType, cast(TypeDescriptor!1*) &tdThrowable, { 0, -1, 0 }, 4, null };
87+
__gshared CatchableType ctException = { CT_IsSimpleType, cast(TypeDescriptor!1*) &tdException, { 0, -1, 0 }, 4, null };
88+
__gshared CatchableTypeArray ctArray = { 2, [ &ctThrowable, &ctException ] };
89+
__gshared _ThrowInfo objectThrowInfo = { 0, null, null, &ctArray };
90+
}
91+
92+
enum int STATUS_MSC_EXCEPTION = 0xe0000000 | ('m' << 16) | ('s' << 8) | ('c' << 0);
93+
94+
enum EXCEPTION_NONCONTINUABLE = 0x01;
95+
enum EXCEPTION_UNWINDING = 0x02;
96+
97+
enum EH_MAGIC_NUMBER1 = 0x19930520;
98+
99+
extern(C) void _d_throw_exception(Object e)
100+
{
101+
if (e is null)
102+
fatalerror("Cannot throw null exception");
103+
auto ti = typeid(e);
104+
if (ti is null)
105+
fatalerror("Cannot throw corrupt exception object with null classinfo");
106+
107+
ULONG_PTR[3] ExceptionInformation;
108+
ExceptionInformation[0] = EH_MAGIC_NUMBER1;
109+
ExceptionInformation[1] = cast(ULONG_PTR) cast(void*) &e;
110+
ExceptionInformation[2] = cast(ULONG_PTR) getThrowInfo(ti);
111+
112+
RaiseException(STATUS_MSC_EXCEPTION, EXCEPTION_NONCONTINUABLE, 3, ExceptionInformation.ptr);
113+
}
114+
115+
import rt.util.container.hashtab;
116+
import core.sync.mutex;
117+
118+
__gshared HashTab!(TypeInfo_Class, _ThrowInfo) throwInfoHashtab;
119+
__gshared HashTab!(TypeInfo_Class, CatchableType) catchableHashtab;
120+
__gshared Mutex throwInfoMutex;
121+
122+
// create and cache throwinfo for ti
123+
_ThrowInfo* getThrowInfo(TypeInfo_Class ti)
124+
{
125+
throwInfoMutex.lock();
126+
if (auto p = ti in throwInfoHashtab)
127+
{
128+
throwInfoMutex.unlock();
129+
return p;
130+
}
131+
132+
size_t classes = 0;
133+
for (TypeInfo_Class tic = ti; tic; tic = tic.base)
134+
classes++;
135+
136+
size_t sz = int.sizeof + classes * ImgPtr!(CatchableType*).sizeof;
137+
auto cta = cast(CatchableTypeArray*) malloc(sz);
138+
if (!cta)
139+
onOutOfMemoryError();
140+
cta.nCatchableTypes = classes;
141+
142+
size_t c = 0;
143+
for (TypeInfo_Class tic = ti; tic; tic = tic.base)
144+
cta.arrayOfCatchableTypes.ptr[c++] = getCatchableType(tic);
145+
146+
_ThrowInfo tinf = { 0, null, null, cta };
147+
throwInfoHashtab[ti] = tinf;
148+
auto pti = ti in throwInfoHashtab;
149+
throwInfoMutex.unlock();
150+
return pti;
151+
}
152+
153+
CatchableType* getCatchableType(TypeInfo_Class ti)
154+
{
155+
if (auto p = ti in catchableHashtab)
156+
return p;
157+
158+
static size_t mangledNameLength(string s)
159+
{
160+
size_t len = 2 + s.length; // "_D" + identifier + 1 digit per dot
161+
for (size_t q = 0; q < s.length; )
162+
{
163+
size_t p = q;
164+
while (p < s.length && s.ptr[p] != '.')
165+
p++;
166+
for (size_t r = p - q; r >= 10; r /= 10) // add digits for length >= 10
167+
len++;
168+
q = p + 1;
169+
}
170+
return len;
171+
}
172+
173+
static void mangleName(string s, char* buf)
174+
{
175+
*buf++ = '_';
176+
*buf++ = 'D';
177+
for (size_t q = 0; q < s.length; )
178+
{
179+
size_t p = q;
180+
while (p < s.length && s.ptr[p] != '.')
181+
p++;
182+
size_t digits = 10;
183+
size_t len = p - q;
184+
for ( ; len >= digits; digits *= 10) {}
185+
for (digits /= 10; digits > 1; digits /= 10)
186+
{
187+
size_t dig = len / digits;
188+
*buf++ = cast(char)('0' + dig);
189+
len -= dig * digits;
190+
}
191+
*buf++ = cast(char)('0' + len);
192+
memcpy(buf, s.ptr + q, p - q);
193+
buf += p - q;
194+
q = p + 1;
195+
}
196+
*buf = 0;
197+
}
198+
199+
size_t mangledLength = mangledNameLength(ti.name) + 1;
200+
size_t sz = TypeDescriptor!1.sizeof + mangledLength;
201+
auto td = cast(TypeDescriptor!1*) malloc(sz);
202+
if (!td)
203+
onOutOfMemoryError();
204+
205+
td.hash = 0;
206+
td.spare = null;
207+
mangleName(ti.name, td.name.ptr);
208+
209+
CatchableType ct = { CT_IsSimpleType, td, { 0, -1, 0 }, 4, null };
210+
catchableHashtab[ti] = ct;
211+
return ti in catchableHashtab;
212+
}
213+
214+
void msvc_eh_init()
215+
{
216+
throwInfoMutex = new Mutex;
217+
218+
// Exception has a special mangling that's not reflected in the name
219+
220+
CatchableType ctObject = { CT_IsSimpleType, cast(TypeDescriptor!1*) &tdObject, { 0, -1, 0 }, 4, null };
221+
catchableHashtab[typeid(Object)] = ctObject;
222+
CatchableType ctThrowable = { CT_IsSimpleType, cast(TypeDescriptor!1*) &tdThrowable, { 0, -1, 0 }, 4, null };
223+
catchableHashtab[typeid(Throwable)] = ctThrowable;
224+
CatchableType ctException = { CT_IsSimpleType, cast(TypeDescriptor!1*) &tdException, { 0, -1, 0 }, 4, null };
225+
catchableHashtab[typeid(Exception)] = ctException;
226+
}
227+
228+
shared static this()
229+
{
230+
// should be called from rt_init
231+
msvc_eh_init();
232+
}

0 commit comments

Comments
 (0)