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

Commit 85ede16

Browse files
committed
win32 EH: prepare for x64
1 parent 31b30cf commit 85ede16

File tree

1 file changed

+155
-43
lines changed

1 file changed

+155
-43
lines changed

src/ldc/eh/win32.d

Lines changed: 155 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,21 @@ import rt.util.container.common : xmalloc;
1616

1717
// pointers are image relative for Win64 versions
1818
version(Win64)
19-
alias ImgPtr(T) = uint; // offset into image
19+
struct ImgPtr(T) { uint offset; } // offset into image
2020
else
21-
alias ImgPtr(T) = T;
21+
alias ImgPtr(T) = T*;
2222

2323
alias PMFN = ImgPtr!(void function(void*));
2424

25-
struct TypeDescriptor(int N)
25+
struct TypeDescriptor
2626
{
2727
version(_RTTI)
2828
const void * pVFTable; // Field overloaded by RTTI
2929
else
3030
uint hash; // Hash value computed from type's decorated name
3131

3232
void * spare; // reserved, possible for RTTI
33-
char[N+1] name; // variable size, zero terminated
33+
char[1] name; // variable size, zero terminated
3434
}
3535

3636
struct PMD
@@ -43,7 +43,7 @@ struct PMD
4343
struct CatchableType
4444
{
4545
uint properties; // Catchable Type properties (Bit field)
46-
ImgPtr!(TypeDescriptor!1*) pType; // Pointer to TypeDescriptor
46+
ImgPtr!TypeDescriptor pType; // Pointer to TypeDescriptor
4747
PMD thisDisplacement; // Pointer to instance of catch type within thrown object.
4848
int sizeOrOffset; // Size of simple-type object or offset into buffer of 'this' pointer for catch object
4949
PMFN copyFunction; // Copy constructor or CC-closure
@@ -58,15 +58,15 @@ enum CT_IsStdBadAlloc = 0x00000010; // type is a a std::bad_alloc
5858
struct CatchableTypeArray
5959
{
6060
int nCatchableTypes;
61-
ImgPtr!(CatchableType*)[2] arrayOfCatchableTypes;
61+
ImgPtr!CatchableType[1] arrayOfCatchableTypes; // variable size
6262
}
6363

6464
struct _ThrowInfo
6565
{
6666
uint attributes; // Throw Info attributes (Bit field)
6767
PMFN pmfnUnwind; // Destructor to call when exception has been handled or aborted.
6868
PMFN pForwardCompat; // pointer to Forward compatibility frame handler
69-
ImgPtr!(CatchableTypeArray*) pCatchableTypeArray; // pointer to CatchableTypeArray
69+
ImgPtr!CatchableTypeArray pCatchableTypeArray; // pointer to CatchableTypeArray
7070
}
7171

7272
enum TI_IsConst = 0x00000001; // thrown object has const qualifier
@@ -87,6 +87,14 @@ enum EXCEPTION_UNWINDING = 0x02;
8787

8888
enum EH_MAGIC_NUMBER1 = 0x19930520;
8989

90+
struct CxxExceptionInfo
91+
{
92+
size_t Magic;
93+
Throwable* pThrowable; // null for rethrow
94+
_ThrowInfo* ThrowInfo;
95+
version(Win64) void* ImgBase;
96+
}
97+
9098
extern(C) void _d_throw_exception(Object e)
9199
{
92100
if (e is null)
@@ -102,75 +110,76 @@ extern(C) void _d_throw_exception(Object e)
102110
if (!old_terminate_handler)
103111
old_terminate_handler = set_terminate(&msvc_eh_terminate);
104112
}
105-
exceptionStack.push(cast(Throwable) e);
113+
auto t = cast(Throwable) e;
114+
exceptionStack.push(t);
106115

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);
116+
CxxExceptionInfo info;
117+
info.Magic = EH_MAGIC_NUMBER1;
118+
info.pThrowable = &t;
119+
info.ThrowInfo = getThrowInfo(ti).toPointer;
120+
version(Win64) info.ImgBase = ehHeap.base;
111121

112-
RaiseException(STATUS_MSC_EXCEPTION, EXCEPTION_NONCONTINUABLE, 3, ExceptionInformation.ptr);
122+
RaiseException(STATUS_MSC_EXCEPTION, EXCEPTION_NONCONTINUABLE,
123+
info.sizeof / size_t.sizeof, cast(ULONG_PTR*)&info);
113124
}
114125

115126
///////////////////////////////////////////////////////////////
116127

117128
import rt.util.container.hashtab;
118129
import core.sync.mutex;
119130

120-
__gshared HashTab!(TypeInfo_Class, _ThrowInfo) throwInfoHashtab;
121-
__gshared HashTab!(TypeInfo_Class, CatchableType) catchableHashtab;
131+
__gshared HashTab!(TypeInfo_Class, ImgPtr!_ThrowInfo) throwInfoHashtab;
132+
__gshared HashTab!(TypeInfo_Class, ImgPtr!CatchableType) catchableHashtab;
122133
__gshared Mutex throwInfoMutex;
123134

124135
// create and cache throwinfo for ti
125-
_ThrowInfo* getThrowInfo(TypeInfo_Class ti)
136+
ImgPtr!_ThrowInfo getThrowInfo(TypeInfo_Class ti)
126137
{
127138
throwInfoMutex.lock();
128139
if (auto p = ti in throwInfoHashtab)
129140
{
130141
throwInfoMutex.unlock();
131-
return p;
142+
return *p;
132143
}
133144

134-
size_t classes = 0;
145+
int classes = 0;
135146
for (TypeInfo_Class tic = ti; tic; tic = tic.base)
136147
classes++;
137148

138-
size_t sz = int.sizeof + classes * ImgPtr!(CatchableType*).sizeof;
139-
auto cta = cast(CatchableTypeArray*) malloc(sz);
140-
if (!cta)
141-
onOutOfMemoryError();
142-
cta.nCatchableTypes = classes;
149+
size_t sz = int.sizeof + classes * ImgPtr!(CatchableType).sizeof;
150+
ImgPtr!CatchableTypeArray cta = eh_malloc!CatchableTypeArray(sz);
151+
toPointer(cta).nCatchableTypes = classes;
143152

144153
size_t c = 0;
145154
for (TypeInfo_Class tic = ti; tic; tic = tic.base)
146-
cta.arrayOfCatchableTypes.ptr[c++] = getCatchableType(tic);
155+
cta.toPointer.arrayOfCatchableTypes.ptr[c++] = getCatchableType(tic);
147156

148-
_ThrowInfo tinf = { 0, null, null, cta };
157+
auto tinf = eh_malloc!_ThrowInfo();
158+
*(tinf.toPointer) = _ThrowInfo(0, PMFN(), PMFN(), cta);
149159
throwInfoHashtab[ti] = tinf;
150-
auto pti = ti in throwInfoHashtab;
151160
throwInfoMutex.unlock();
152-
return pti;
161+
return tinf;
153162
}
154163

155-
CatchableType* getCatchableType(TypeInfo_Class ti)
164+
ImgPtr!CatchableType getCatchableType(TypeInfo_Class ti)
156165
{
157166
if (auto p = ti in catchableHashtab)
158-
return p;
167+
return *p;
159168

160-
size_t sz = TypeDescriptor!1.sizeof + ti.name.length;
161-
auto td = cast(TypeDescriptor!1*) malloc(sz);
162-
if (!td)
163-
onOutOfMemoryError();
169+
size_t sz = TypeDescriptor.sizeof + ti.name.length;
170+
auto td = eh_malloc!TypeDescriptor(sz);
171+
auto ptd = td.toPointer;
164172

165-
td.hash = 0;
166-
td.spare = null;
167-
td.name.ptr[0] = 'D';
168-
memcpy(td.name.ptr + 1, ti.name.ptr, ti.name.length);
169-
td.name.ptr[ti.name.length + 1] = 0;
173+
ptd.hash = 0;
174+
ptd.spare = null;
175+
ptd.name.ptr[0] = 'D';
176+
memcpy(ptd.name.ptr + 1, ti.name.ptr, ti.name.length);
177+
ptd.name.ptr[ti.name.length + 1] = 0;
170178

171-
CatchableType ct = { CT_IsSimpleType, td, { 0, -1, 0 }, 4, null };
179+
auto ct = eh_malloc!CatchableType();
180+
ct.toPointer[0] = CatchableType(CT_IsSimpleType, td, PMD(0, -1, 0), 4, PMFN());
172181
catchableHashtab[ti] = ct;
173-
return ti in catchableHashtab;
182+
return ct;
174183
}
175184

176185
///////////////////////////////////////////////////////////////
@@ -278,9 +287,7 @@ private:
278287
{
279288
// alloc from GC? add array as a GC range?
280289
immutable ncap = _cap ? 2 * _cap : 64;
281-
auto p = cast(Throwable*)malloc(ncap * Throwable.sizeof);
282-
if (p is null)
283-
onOutOfMemoryError();
290+
auto p = cast(Throwable*)xmalloc(ncap * Throwable.sizeof);
284291
p[0 .. _length] = _p[0 .. _length];
285292
free(_p);
286293
_p = p;
@@ -345,6 +352,35 @@ void msvc_eh_terminate() nothrow
345352
ret;
346353
}
347354
}
355+
else
356+
{
357+
asm nothrow
358+
{
359+
naked;
360+
push RBX; // align stack
361+
call tlsUncaughtExceptions;
362+
cmp RAX, 1;
363+
jle L_term;
364+
365+
// update stack so we just continue in __FrameUnwindToState$filt$0
366+
// return address and 0x20 bytes inside terminate
367+
// RBX pushed
368+
// return address and 0x28 bytes inside __FrameUnwindFilter
369+
mov RBX,[RSP+0x30];
370+
add RSP,0x68; // TODO: needs to be verified for different CRT builds
371+
mov RAX,1;
372+
ret; // return to __FrameUnwindToState$filt$0
373+
374+
L_term:
375+
call tlsOldTerminateHandler;
376+
pop RBX;
377+
cmp RAX, 0;
378+
je L_ret;
379+
jmp RAX;
380+
L_ret:
381+
ret;
382+
}
383+
}
348384
}
349385

350386
///////////////////////////////////////////////////////////////
@@ -426,6 +462,8 @@ void msvc_eh_init()
426462
{
427463
throwInfoMutex = new Mutex;
428464

465+
version(Win64) ehHeap.initialize(0x10000);
466+
429467
// preallocate type descriptors likely to be needed
430468
getThrowInfo(typeid(Exception));
431469
// better not have to allocate when this is thrown:
@@ -437,3 +475,77 @@ shared static this()
437475
// should be called from rt_init
438476
msvc_eh_init();
439477
}
478+
479+
///////////////////////////////////////////////////////////////
480+
version(Win32)
481+
{
482+
ImgPtr!T eh_malloc(T)(size_t size = T.sizeof)
483+
{
484+
return cast(T*) xmalloc(size);
485+
}
486+
487+
T* toPointer(T)(T* imgPtr)
488+
{
489+
return imgPtr;
490+
}
491+
}
492+
else
493+
{
494+
/**
495+
* Heap dedicated for CatchableTypeArray/CatchableType/TypeDescriptor
496+
* structs of cached _ThrowInfos.
497+
* The heap is used to keep these structs tightly together, as they are
498+
* referenced via 32-bit offsets from a common base. We simply use the
499+
* heap's start as base (instead of the actual image base), and malloc()
500+
* returns an offset.
501+
* The allocated structs are all cached and never released, so this heap
502+
* can only grow. The offsets remain constant after a grow, so it's only
503+
* the base which may change.
504+
*/
505+
struct EHHeap
506+
{
507+
void* base;
508+
size_t capacity;
509+
size_t length;
510+
511+
void initialize(size_t initialCapacity)
512+
{
513+
base = xmalloc(initialCapacity);
514+
capacity = initialCapacity;
515+
length = size_t.sizeof; // don't use offset 0, it has a special meaning
516+
}
517+
518+
size_t malloc(size_t size)
519+
{
520+
auto offset = length;
521+
enum alignmentMask = size_t.sizeof - 1;
522+
auto newLength = (length + size + alignmentMask) & ~alignmentMask;
523+
auto newCapacity = capacity;
524+
while (newLength > newCapacity)
525+
newCapacity *= 2;
526+
if (newCapacity != capacity)
527+
{
528+
auto newBase = xmalloc(newCapacity);
529+
newBase[0 .. length] = base[0 .. length];
530+
// old base just leaks, could be used by exceptions still in flight
531+
base = newBase;
532+
capacity = newCapacity;
533+
}
534+
length = newLength;
535+
return offset;
536+
}
537+
}
538+
539+
__gshared EHHeap ehHeap;
540+
541+
ImgPtr!T eh_malloc(T)(size_t size = T.sizeof)
542+
{
543+
return ImgPtr!T(cast(uint) ehHeap.malloc(size));
544+
}
545+
546+
// NB: The returned pointer may be invalidated by a consequent grow of ehHeap!
547+
T* toPointer(T)(ImgPtr!T imgPtr)
548+
{
549+
return cast(T*) (ehHeap.base + imgPtr.offset);
550+
}
551+
}

0 commit comments

Comments
 (0)