55module ldc.eh.win32 ;
66
77version (CRuntime_Microsoft ):
8- version (Win32 ):
8+ // version(Win32):
99
1010import ldc.eh.common;
1111import ldc.attributes;
1212import core.sys.windows.windows ;
1313import core.exception : onOutOfMemoryError, OutOfMemoryError;
1414import 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
1818version (Win64 )
2222
2323alias 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
3638struct PMD
@@ -43,7 +45,7 @@ struct PMD
4345struct 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
5860struct CatchableTypeArray
5961{
60- int nCatchableTypes;
61- ImgPtr! (CatchableType* )[2 ] arrayOfCatchableTypes;
62+ int nCatchableTypes;
63+ ImgPtr! (CatchableType* )[2 ] arrayOfCatchableTypes; // variable size
6264}
6365
6466struct _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;
132141import 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:
0 commit comments