@@ -12,6 +12,7 @@ import core.sys.windows.windows;
1212import core.exception : onOutOfMemoryError, OutOfMemoryError;
1313import core.stdc.stdlib : malloc, free;
1414import core.stdc.string : memcpy;
15+ import rt.util.container.common : xmalloc;
1516
1617// pointers are image relative for Win64 versions
1718version (Win64 )
@@ -173,43 +174,52 @@ CatchableType* getCatchableType(TypeInfo_Class ti)
173174}
174175
175176// /////////////////////////////////////////////////////////////
176- extern (C ) Object _d_eh_enter_catch(void * ptr)
177+ extern (C ) Object _d_eh_enter_catch(void * ptr, ClassInfo catchType )
177178{
178- if (! ptr)
179- return null ; // null for "catch all" in scope(failure), will rethrow
180- Throwable e = * (cast (Throwable* ) ptr);
181-
182- while (exceptionStack.length > 0 )
179+ assert (ptr);
180+
181+ // is this a thrown D exception?
182+ auto e = * (cast (Throwable* ) ptr);
183+ size_t pos = exceptionStack.find(e);
184+ if (pos >= exceptionStack.length())
185+ return null ;
186+
187+ auto caught = e;
188+ // append inner unhandled thrown exceptions
189+ for (size_t p = pos + 1 ; p < exceptionStack.length(); p++ )
190+ e = chainExceptions(e, exceptionStack[p]);
191+ exceptionStack.shrink(pos);
192+
193+ // given the bad semantics of Errors, we are fine with passing
194+ // the test suite with slightly inaccurate behaviour by just
195+ // rethrowing a collateral Error here, though it might need to
196+ // be caught by a catch handler in an inner scope
197+ if (e ! is caught)
183198 {
184- Throwable t = exceptionStack.pop();
185- if (t is e)
186- break ;
199+ if (_d_isbaseof(typeid (e), catchType))
200+ * cast (Throwable* ) ptr = e; // the current catch can also catch this Error
201+ else
202+ _d_throw_exception(e);
203+ }
204+ return e;
205+ }
187206
188- auto err = cast (Error) t;
189- if (err && ! cast (Error)e)
207+ Throwable chainExceptions (Throwable e, Throwable t)
208+ {
209+ if (! cast (Error) e)
210+ if (auto err = cast (Error) t)
190211 {
191- // there is an Error in flight, but we caught an Exception
192- // so we convert it and rethrow the Error
193212 err.bypassedException = e;
194- throw err;
213+ return err;
195214 }
196- t.next = e.next;
197- e.next = t;
198- }
199215
216+ auto pChain = &e.next;
217+ while (* pChain)
218+ pChain = &(pChain.next);
219+ * pChain = t;
200220 return e;
201221}
202222
203- alias terminate_handler = void function ();
204-
205- extern (C ) void ** __current_exception();
206- extern (C ) void ** __current_exception_context();
207- extern (C ) int * __processing_throw();
208-
209- extern (C ) terminate_handler set_terminate(terminate_handler new_handler);
210-
211- terminate_handler old_terminate_handler; // explicitely per thread
212-
213223ExceptionStack exceptionStack;
214224
215225struct ExceptionStack
@@ -233,14 +243,36 @@ nothrow:
233243 return _p[-- _length];
234244 }
235245
246+ void shrink (size_t sz)
247+ {
248+ while (_length > sz)
249+ _p[-- _length] = null ;
250+ }
251+
236252 ref inout (Throwable) opIndex (size_t idx) inout
237253 {
238254 return _p[idx];
239255 }
240256
257+ size_t find (Throwable e)
258+ {
259+ for (size_t i = _length; i > 0 ; )
260+ if (exceptionStack[-- i] is e)
261+ return i;
262+ return ~ 0 ;
263+ }
264+
241265 @property size_t length() const { return _length; }
242266 @property bool empty() const { return ! length; }
243267
268+ void swap (ref ExceptionStack other)
269+ {
270+ static void swapField (T)(ref T a, ref T b) { T o = b; b = a; a = o; }
271+ swapField(_length, other._length);
272+ swapField(_p, other._p);
273+ swapField(_cap, other._cap);
274+ }
275+
244276private :
245277 void grow ()
246278 {
@@ -260,8 +292,13 @@ private:
260292 size_t _cap;
261293}
262294
295+ // /////////////////////////////////////////////////////////////
296+ alias terminate_handler = void function ();
297+ extern (C ) terminate_handler set_terminate(terminate_handler new_handler);
298+ terminate_handler old_terminate_handler; // explicitely per thread
299+
263300// helper to access TLS from naked asm
264- int tlsUncaughtExceptions () nothrow
301+ size_t tlsUncaughtExceptions () nothrow
265302{
266303 return exceptionStack.length;
267304}
@@ -273,41 +310,98 @@ auto tlsOldTerminateHandler() nothrow
273310
274311void msvc_eh_terminate () nothrow
275312{
276- asm nothrow {
277- naked;
278- call tlsUncaughtExceptions;
279- cmp EAX , 0 ;
280- je L_term;
281-
282- // hacking into the call chain to return EXCEPTION_EXECUTE_HANDLER
283- // as the return value of __FrameUnwindFilter so that
284- // __FrameUnwindToState continues with the next unwind block
285-
286- // restore ptd->__ProcessingThrow
287- push EAX ;
288- call __processing_throw;
289- pop [EAX ];
290-
291- // undo one level of exception frames from terminate()
292- mov EAX ,FS :[0 ];
293- mov EAX ,[EAX ];
294- mov FS :[0 ], EAX ;
295-
296- // assume standard stack frames for callers
297- mov EAX ,EBP ; // frame pointer of terminate()
298- mov EAX ,[EAX ]; // frame pointer of __FrameUnwindFilter
299- mov ESP ,EAX ; // restore stack
300- pop EBP ; // and frame pointer
301- mov EAX , 1 ; // return EXCEPTION_EXECUTE_HANDLER
302- ret;
303-
304- L_term:
305- call tlsOldTerminateHandler;
306- cmp EAX , 0 ;
307- je L_ret;
308- jmp EAX ;
309- L_ret:
310- ret;
313+ version (Win32 )
314+ {
315+ asm nothrow
316+ {
317+ naked;
318+ call tlsUncaughtExceptions;
319+ cmp EAX , 1 ;
320+ jle L_term;
321+
322+ // hacking into the call chain to return EXCEPTION_EXECUTE_HANDLER
323+ // as the return value of __FrameUnwindFilter so that
324+ // __FrameUnwindToState continues with the next unwind block
325+
326+ // undo one level of exception frames from terminate()
327+ mov EAX ,FS :[0 ];
328+ mov EAX ,[EAX ];
329+ mov FS :[0 ], EAX ;
330+
331+ // assume standard stack frames for callers
332+ mov EAX ,EBP ; // frame pointer of terminate()
333+ mov EAX ,[EAX ]; // frame pointer of __FrameUnwindFilter
334+ mov ESP ,EAX ; // restore stack
335+ pop EBP ; // and frame pointer
336+ mov EAX , 1 ; // return EXCEPTION_EXECUTE_HANDLER
337+ ret;
338+
339+ L_term:
340+ call tlsOldTerminateHandler;
341+ cmp EAX , 0 ;
342+ je L_ret;
343+ jmp EAX ;
344+ L_ret:
345+ ret;
346+ }
347+ }
348+ }
349+
350+ // /////////////////////////////////////////////////////////////
351+ extern (C ) void ** __current_exception() nothrow ;
352+ extern (C ) void ** __current_exception_context() nothrow ;
353+ extern (C ) int * __processing_throw() nothrow ;
354+
355+ struct FiberContext
356+ {
357+ ExceptionStack exceptionStack;
358+ void * currentException;
359+ void * currentExceptionContext;
360+ int processingContext;
361+ }
362+
363+ FiberContext* fiberContext;
364+
365+ extern (C ) void * _d_eh_swapContext(FiberContext* newContext) nothrow
366+ {
367+ import core.stdc.string : memset;
368+ if (! fiberContext)
369+ {
370+ fiberContext = cast (FiberContext* ) xmalloc(FiberContext.sizeof);
371+ memset(fiberContext, 0 , FiberContext.sizeof);
372+ }
373+ fiberContext.exceptionStack.swap(exceptionStack);
374+ fiberContext.currentException = * __current_exception();
375+ fiberContext.currentExceptionContext = * __current_exception_context();
376+ fiberContext.processingContext = * __processing_throw();
377+
378+ if (newContext)
379+ {
380+ exceptionStack.swap(newContext.exceptionStack);
381+ * __current_exception() = newContext.currentException;
382+ * __current_exception_context() = newContext.currentExceptionContext;
383+ * __processing_throw() = newContext.processingContext;
384+ }
385+ else
386+ {
387+ exceptionStack = ExceptionStack();
388+ * __current_exception() = null ;
389+ * __current_exception_context() = null ;
390+ * __processing_throw() = 0 ;
391+ }
392+
393+ FiberContext* old = fiberContext;
394+ fiberContext = newContext;
395+ return old;
396+ }
397+
398+ static ~this ()
399+ {
400+ import core.stdc.stdlib : free;
401+ if (fiberContext)
402+ {
403+ destroy (* fiberContext);
404+ free(fiberContext);
311405 }
312406}
313407
@@ -318,7 +412,7 @@ extern(C) bool _d_enter_cleanup(void* ptr)
318412 // be inferred to not return, is removed by the LLVM optimizer
319413 //
320414 // TODO: setup an exception handler here (ptr passes the address
321- // of a 16 byte stack area in a parent fuction scope) to deal with
415+ // of a 40 byte stack area in a parent fuction scope) to deal with
322416 // unhandled exceptions during unwinding.
323417 return true ;
324418}
0 commit comments