Skip to content

Commit 3493e19

Browse files
committed
MSVC EH: Partial x64 support
1 parent fd8ed27 commit 3493e19

File tree

2 files changed

+126
-36
lines changed

2 files changed

+126
-36
lines changed

src/ldc/eh/win32.d

Lines changed: 125 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
module ldc.eh.win32;
66

77
version(CRuntime_Microsoft):
8-
version(Win32):
8+
//version(Win32):
99

1010
import ldc.eh.common;
1111
import ldc.attributes;
1212
import core.sys.windows.windows;
1313
import core.exception : onOutOfMemoryError, OutOfMemoryError;
1414
import core.stdc.stdlib : malloc, free;
15-
import core.stdc.string : memcpy;
15+
import core.stdc.string : memcpy, memset;
1616

1717
// pointers are image relative for Win64 versions
1818
version(Win64)
@@ -22,15 +22,17 @@ else
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
29+
else version(Win64)
30+
const void * pVFTable;
2931
else
3032
uint hash; // Hash value computed from type's decorated name
3133

3234
void * spare; // reserved, possible for RTTI
33-
char[N+1] name; // variable size, zero terminated
35+
char[2] name; // variable size, zero terminated
3436
}
3537

3638
struct PMD
@@ -43,7 +45,7 @@ struct PMD
4345
struct CatchableType
4446
{
4547
uint properties; // Catchable Type properties (Bit field)
46-
ImgPtr!(TypeDescriptor!1*) pType; // Pointer to TypeDescriptor
48+
ImgPtr!(TypeDescriptor*) pType; // Pointer to TypeDescriptor
4749
PMD thisDisplacement; // Pointer to instance of catch type within thrown object.
4850
int sizeOrOffset; // Size of simple-type object or offset into buffer of 'this' pointer for catch object
4951
PMFN copyFunction; // Copy constructor or CC-closure
@@ -57,8 +59,8 @@ enum CT_IsStdBadAlloc = 0x00000010; // type is a a std::bad_alloc
5759

5860
struct CatchableTypeArray
5961
{
60-
int nCatchableTypes;
61-
ImgPtr!(CatchableType*)[2] arrayOfCatchableTypes;
62+
int nCatchableTypes;
63+
ImgPtr!(CatchableType*)[2] arrayOfCatchableTypes; // variable size
6264
}
6365

6466
struct _ThrowInfo
@@ -118,12 +120,19 @@ extern(C) void _d_throw_exception(Object e)
118120

119121
exceptionStack.push(cast(Throwable) e);
120122

121-
ULONG_PTR[3] ExceptionInformation;
122-
ExceptionInformation[0] = EH_MAGIC_NUMBER1;
123-
ExceptionInformation[1] = cast(ULONG_PTR) cast(void*) &e;
124-
ExceptionInformation[2] = cast(ULONG_PTR) getThrowInfo(ti);
123+
version(Win64)
124+
enum numArgs = 4;
125+
else
126+
enum numArgs = 3;
127+
128+
ULONG_PTR[numArgs] args;
129+
args[0] = EH_MAGIC_NUMBER1;
130+
args[1] = cast(ULONG_PTR) cast(void*) &e;
131+
args[2] = cast(ULONG_PTR) getThrowInfo(ti);
132+
version(Win64)
133+
args[3] = cast(ULONG_PTR) ehHeap.base;
125134

126-
RaiseException(STATUS_MSC_EXCEPTION, EXCEPTION_NONCONTINUABLE, 3, ExceptionInformation.ptr);
135+
RaiseException(STATUS_MSC_EXCEPTION, EXCEPTION_NONCONTINUABLE, args.length, args.ptr);
127136
}
128137

129138
///////////////////////////////////////////////////////////////
@@ -132,9 +141,89 @@ import rt.util.container.hashtab;
132141
import core.sync.mutex;
133142

134143
__gshared HashTab!(TypeInfo_Class, _ThrowInfo) throwInfoHashtab;
135-
__gshared HashTab!(TypeInfo_Class, CatchableType) catchableHashtab;
144+
__gshared HashTab!(TypeInfo_Class, ImgPtr!(CatchableType*)) catchableHashtab;
136145
__gshared Mutex throwInfoMutex;
137146

147+
void* safeMalloc(size_t size)
148+
{
149+
if (auto ptr = malloc(size))
150+
return ptr;
151+
onOutOfMemoryError();
152+
return null;
153+
}
154+
155+
version(Win32)
156+
{
157+
ImgPtr!(T*) eh_malloc(T)(size_t size = T.sizeof)
158+
{
159+
return cast(T*) safeMalloc(size);
160+
}
161+
162+
T* toPointer(T)(ImgPtr!(T*) imgPtr)
163+
{
164+
return imgPtr;
165+
}
166+
}
167+
else
168+
{
169+
/**
170+
* Heap dedicated for CatchableTypeArray/CatchableType/TypeDescriptor
171+
* structs of cached _ThrowInfos.
172+
* The heap is used to keep these structs tightly together, as they are
173+
* referenced via 32-bit offsets from a common base. We simply use the
174+
* heap's start as base (instead of the actual image base), and malloc()
175+
* returns an offset.
176+
* The allocated structs are all cached and never released, so this heap
177+
* can only grow. The offsets remain constant after a grow, so it's only
178+
* the base which may change.
179+
*/
180+
struct EHHeap
181+
{
182+
void* base;
183+
size_t capacity;
184+
size_t length;
185+
186+
this(size_t initialCapacity)
187+
{
188+
base = safeMalloc(initialCapacity);
189+
capacity = initialCapacity;
190+
}
191+
192+
size_t malloc(size_t size)
193+
{
194+
auto offset = length;
195+
enum alignmentMask = size_t.sizeof - 1;
196+
auto newLength = (length + size + alignmentMask) & ~alignmentMask;
197+
auto newCapacity = capacity;
198+
while (newLength > newCapacity)
199+
newCapacity *= 2;
200+
if (newCapacity != capacity)
201+
{
202+
auto newBase = safeMalloc(newCapacity);
203+
newBase[0 .. length] = base[0 .. length];
204+
free(base);
205+
base = newBase;
206+
capacity = newCapacity;
207+
}
208+
length = newLength;
209+
return offset;
210+
}
211+
}
212+
213+
__gshared EHHeap ehHeap;
214+
215+
ImgPtr!(T*) eh_malloc(T)(size_t size = T.sizeof)
216+
{
217+
return cast(uint) ehHeap.malloc(size);
218+
}
219+
220+
// NB: The returned pointer may be invalidated by a consequent grow of ehHeap!
221+
T* toPointer(T)(ImgPtr!(T*) imgPtr)
222+
{
223+
return cast(T*) (ehHeap.base + imgPtr);
224+
}
225+
}
226+
138227
// create and cache throwinfo for ti
139228
_ThrowInfo* getThrowInfo(TypeInfo_Class ti)
140229
{
@@ -145,46 +234,44 @@ _ThrowInfo* getThrowInfo(TypeInfo_Class ti)
145234
return p;
146235
}
147236

148-
size_t classes = 0;
237+
int classes = 0;
149238
for (TypeInfo_Class tic = ti; tic; tic = tic.base)
150239
classes++;
151240

152241
size_t sz = int.sizeof + classes * ImgPtr!(CatchableType*).sizeof;
153-
auto cta = cast(CatchableTypeArray*) malloc(sz);
154-
if (!cta)
155-
onOutOfMemoryError();
156-
cta.nCatchableTypes = classes;
157-
242+
auto cta = eh_malloc!CatchableTypeArray(sz);
243+
toPointer!CatchableTypeArray(cta).nCatchableTypes = classes;
158244
size_t c = 0;
159245
for (TypeInfo_Class tic = ti; tic; tic = tic.base)
160-
cta.arrayOfCatchableTypes.ptr[c++] = getCatchableType(tic);
246+
{
247+
auto ct = getCatchableType(tic);
248+
toPointer!CatchableTypeArray(cta).arrayOfCatchableTypes.ptr[c++] = ct;
249+
}
161250

162-
_ThrowInfo tinf = { 0, null, null, cta };
163-
throwInfoHashtab[ti] = tinf;
251+
throwInfoHashtab[ti] = _ThrowInfo(0, PMFN(), PMFN(), cta);
164252
auto pti = ti in throwInfoHashtab;
165253
throwInfoMutex.unlock();
166254
return pti;
167255
}
168256

169-
CatchableType* getCatchableType(TypeInfo_Class ti)
257+
ImgPtr!(CatchableType*) getCatchableType(TypeInfo_Class ti)
170258
{
171259
if (auto p = ti in catchableHashtab)
172-
return p;
260+
return *p;
173261

174-
size_t sz = TypeDescriptor!1.sizeof + ti.name.length;
175-
auto td = cast(TypeDescriptor!1*) malloc(sz);
176-
if (!td)
177-
onOutOfMemoryError();
262+
size_t sz = TypeDescriptor.sizeof + ti.name.length;
263+
auto td = eh_malloc!TypeDescriptor(sz);
264+
auto ptd = toPointer!TypeDescriptor(td);
265+
memset(ptd, 0, sz);
266+
ptd.name.ptr[0] = 'D';
267+
memcpy(ptd.name.ptr + 1, ti.name.ptr, ti.name.length);
178268

179-
td.hash = 0;
180-
td.spare = null;
181-
td.name.ptr[0] = 'D';
182-
memcpy(td.name.ptr + 1, ti.name.ptr, ti.name.length);
183-
td.name.ptr[ti.name.length + 1] = 0;
269+
auto ct = eh_malloc!CatchableType();
270+
auto pct = toPointer!CatchableType(ct);
271+
*pct = CatchableType(CT_IsSimpleType, td, PMD(0, -1, 0), ULONG_PTR.sizeof, PMFN());
184272

185-
CatchableType ct = { CT_IsSimpleType, td, { 0, -1, 0 }, 4, null };
186273
catchableHashtab[ti] = ct;
187-
return ti in catchableHashtab;
274+
return ct;
188275
}
189276

190277
///////////////////////////////////////////////////////////////
@@ -464,6 +551,9 @@ void msvc_eh_init()
464551
{
465552
throwInfoMutex = new Mutex;
466553

554+
version(Win64)
555+
ehHeap = EHHeap(65536);
556+
467557
// preallocate type descriptors likely to be needed
468558
getThrowInfo(typeid(Exception));
469559
// better not have to allocate when this is thrown:

src/ldc/eh/win64.d

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
module ldc.eh.win64;
66

77
version (CRuntime_Microsoft):
8-
version (Win64):
8+
version (none /*Win64*/):
99

1010
// debug = EH_personality;
1111
// debug = EH_personality_verbose;

0 commit comments

Comments
 (0)