@@ -16,21 +16,21 @@ import rt.util.container.common : xmalloc;
1616
1717// pointers are image relative for Win64 versions
1818version (Win64 )
19- alias ImgPtr (T) = uint ; // offset into image
19+ struct ImgPtr (T) { uint offset; } // offset into image
2020else
21- alias ImgPtr (T) = T;
21+ alias ImgPtr (T) = T* ;
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
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
3636struct PMD
@@ -43,7 +43,7 @@ struct PMD
4343struct 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
5858struct CatchableTypeArray
5959{
6060 int nCatchableTypes;
61- ImgPtr! ( CatchableType* )[ 2 ] arrayOfCatchableTypes;
61+ ImgPtr! CatchableType[ 1 ] arrayOfCatchableTypes; // variable size
6262}
6363
6464struct _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
7272enum TI_IsConst = 0x00000001 ; // thrown object has const qualifier
@@ -87,6 +87,14 @@ enum EXCEPTION_UNWINDING = 0x02;
8787
8888enum 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+
9098extern (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
117128import rt.util.container.hashtab;
118129import 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