Changeset 503
- Timestamp:
- 01/11/11 20:50:01 (14 years ago)
- Files:
-
- trunk/src/rt/deh.d (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/src/rt/deh.d
r489 r503 155 155 } 156 156 alias EXCEPTION_RECORD* PEXCEPTION_RECORD, LPEXCEPTION_RECORD; 157 157 158 158 struct EXCEPTION_POINTERS { 159 159 PEXCEPTION_RECORD ExceptionRecord; 160 160 PCONTEXT ContextRecord; 161 161 } 162 162 alias EXCEPTION_POINTERS* PEXCEPTION_POINTERS, LPEXCEPTION_POINTERS; 163 163 164 164 enum EXCEPTION_UNWIND = 6; // Flag to indicate if the system is unwinding 165 /+ Values used by Microsoft for Itanium and Win64 are: 166 #define EXCEPTION_NONCONTINUABLE 0x0001 167 #define EXCEPTION_UNWINDING 0x0002 168 #define EXCEPTION_EXIT_UNWIND 0x0004 169 #define EXCEPTION_STACK_INVALID 0x0008 170 #define EXCEPTION_NESTED_CALL 0x0010 171 #define EXCEPTION_TARGET_UNWIND 0x0020 172 #define EXCEPTION_COLLIDED_UNWIND 0x0040 173 #define EXCEPTION_UNWIND 0x0066 174 175 @@@ BUG @@@ 176 We don't have any guarantee that this bit will remain available. Unfortunately, 177 it seems impossible to implement exception handling at all, without relying on 178 undocumented behaviour in several places. 179 +/ 180 enum EXCEPTION_COLLATERAL = 0x100; // Flag used to implement TDPL exception chaining 165 181 166 182 /* Windows Kernel function to initiate a system unwind. 167 183 168 184 Documentation for this function is severely lacking. 169 185 http://www.nynaeve.net/?p=99 states that the MSDN documentation is incorrect, 170 186 and gives a corrected form, but it's for x86_64 only. 171 187 http://www.microsoft.com/msj/0197/exception/exception.aspx says that it was 172 188 undocumented in 1997. 173 189 The pExceptRec is what will be passed to the language specific handler. 174 190 According to MSJ, the targetIp value is unused on Win32. … … 297 313 DHandlerInfo handler_info[1]; 298 314 }; 299 315 300 316 struct DCatchBlock 301 317 { 302 318 ClassInfo type; // catch type 303 319 uint bpoffset; // EBP offset of catch var 304 320 void *code; // catch handler code 305 321 }; 306 322 307 // Create one of thesefor each try-catch323 // One of these is created for each try-catch 308 324 struct DCatchInfo 309 325 { 310 326 uint ncatches; // number of catch blocks 311 327 DCatchBlock catch_block[1]; // data for each catch block 312 328 }; 313 329 314 330 // Macro to make our own exception code 315 331 template MAKE_EXCEPTION_CODE(int severity, int facility, int exception) 316 332 { 317 333 enum int MAKE_EXCEPTION_CODE = (((severity) << 30) | (1 << 29) | (0 << 28) | ((facility) << 16) | (exception)); 318 334 } 319 335 enum int STATUS_DIGITAL_MARS_D_EXCEPTION = MAKE_EXCEPTION_CODE!(3,'D',1); 336 337 /* Head of a linked list of all exceptions which are in flight. 338 * This is used to implement exception chaining as described in TDPL. 339 * Central to making chaining work correctly is that chaining must only occur 340 * when a collision occurs (not merely when two exceptions are in flight, 341 * because one may be caught before it has any effect on the other). 342 * 343 * The 'ExceptionRecord' member of the EXCEPTION_RECORD struct is used to 344 * store a link to the earlier member on the list. 345 * All exceptions which have found their catch handler are linked into this 346 * list. The exceptions which collided are marked by setting a bit in the 347 * ExceptionFlags. I've called this bit EXCEPTION_COLLATERAL. It has never 348 * been used by Microsoft. 349 * 350 * Every member of the list will either eventually collide with the next earlier 351 * exception, having its EXCEPTION_COLLATERAL bit set, or else will be caught. 352 * If it is caught, a D exception object is created, containing all of the 353 * collateral exceptions, 354 * 355 * There are many subtleties in this design: 356 * (1) The exception records are all on the stack, so it's not possible to 357 * modify them very much. In particular, we have very little choice about how 358 * unwinding works, so we have to leave all the exception records essentially 359 * intact. 360 * (2) The length of an exception record is not constant. System exceptions 361 * are shorter than D exceptions, for example. 362 * (3) System exceptions don't have any space for a pointer to a D object. 363 * So we cannot store the collision information in the exception record. 364 * (4) it's important that this list is thread-local. 365 * 366 * Every member of this list will suffer one of two fates: 367 * (1) it will be caught successfully. 368 * In this case it is popped from the list. 369 * The previous head of the list, and the previous Throwable chain, are restored. 370 * (2) it will collide with the previous exception. 371 * In this case, it gets added to the active Throwable chain, and then discarded. 372 * (in which case its Throwable chain will be added to the Throwable chain of 373 * the previous exception, and then this exception will be popped from the list). 374 * 375 * Note: 376 */ 377 378 EXCEPTION_RECORD * inflightExceptionList = null; 379 380 /*********************************** 381 * Find the first non-collateral exception in the list. If the last 382 * entry in the list has the EXCEPTION_COLLATERAL bit set, it means 383 * that this fragment will collide with the top exception in the 384 * inflightException list. 385 */ 386 EXCEPTION_RECORD *skipCollateralExceptions(EXCEPTION_RECORD *n) 387 { 388 while ( n.ExceptionRecord && n.ExceptionFlags & EXCEPTION_COLLATERAL ) 389 { 390 n = n.ExceptionRecord; 391 } 392 return n; 393 } 394 320 395 321 396 /*********************************** 322 397 * The frame handler, this is called for each frame that has been registered 323 398 * in the OS except_list. 324 399 * Input: 325 400 * EAX the handler table for the frame 326 401 */ 327 402 extern(C) 328 403 EXCEPTION_DISPOSITION _d_framehandler( 329 404 EXCEPTION_RECORD *exceptionRecord, … … 360 435 phi = &handlerTable.handler_info[ndx]; 361 436 prev_ndx = phi.prev_index; 362 437 if (phi.cioffset) 363 438 { 364 439 // this is a catch handler (no finally) 365 440 pci = cast(DCatchInfo *)(cast(ubyte *)handlerTable + phi.cioffset); 366 441 ncatches = pci.ncatches; 367 442 for (i = 0; i < ncatches; i++) 368 443 { 369 444 pcb = &pci.catch_block[i]; 370 371 if (!ci) 445 // If there are collided unwinds, they must ALL match the translation code 446 int match = 0; 447 EXCEPTION_RECORD * er = exceptionRecord; 448 do 372 449 { 373 // This code must match the translation code 374 if (exceptionRecord.ExceptionCode == STATUS_DIGITAL_MARS_D_EXCEPTION) 450 if (!ci) 375 451 { 376 // printf("ei[0] = %p\n", exceptionRecord.ExceptionInformation[0]); 377 ci = (**(cast(ClassInfo **)(exceptionRecord.ExceptionInformation[0]))); 452 // This code must match the translation code 453 if (er.ExceptionCode == STATUS_DIGITAL_MARS_D_EXCEPTION) 454 { 455 // printf("ei[0] = %p\n", exceptionRecord.ExceptionInformation[0]); 456 ci = (**(cast(ClassInfo **)(er.ExceptionInformation[0]))); 457 } 458 else 459 ci = Throwable.typeinfo; 378 460 } 379 else 380 ci = Throwable.typeinfo; 381 } 382 if (_d_isbaseof(ci, pcb.type)) 461 match = _d_isbaseof(ci, pcb.type); 462 // We need to check all the collateral exceptions 463 if (er.ExceptionFlags & EXCEPTION_COLLATERAL) { 464 // Walk to the next collateral exception. 465 if (er.ExceptionRecord) 466 er = er.ExceptionRecord; 467 else // It is collateral for an existing exception chain 468 // for which we've already found the catch{}. It is 469 // possible that the new collateral makes the old catch 470 // invalid. 471 er = inflightExceptionList; 472 ci = null; 473 } 474 else break; // if no collateral exceptions, we're done. 475 } while(match); 476 477 if (match) 383 478 { 384 // Matched the catch type, so we've found the handler. 479 // Matched the catch type, so we've found the catch handler 480 // for this exception. 481 // We need to add this exception to the list of in-flight 482 // exceptions, in case something collides with it. 483 EXCEPTION_RECORD * originalException = skipCollateralExceptions(exceptionRecord); 484 if (originalException.ExceptionRecord is null 485 && !(exceptionRecord is inflightExceptionList)) 486 { 487 originalException.ExceptionRecord = inflightExceptionList; 488 } 489 490 inflightExceptionList = exceptionRecord; 491 492 // Have system call all finally blocks in intervening frames 493 _d_global_unwind(frame, exceptionRecord); 494 495 // Call all the finally blocks skipped in this frame 496 _d_local_unwind(handlerTable, frame, ndx, &searchCollisionExceptionHandler); 497 498 frame.table_index = prev_ndx; // we are out of this handler 499 500 // Now create the D exception from the SEH exception record chain. 501 // Note that since non-Throwables are throwable(!), the chain might be incomplete. 502 EXCEPTION_RECORD * z = exceptionRecord; 503 Throwable prev = null; 504 while (z && (z.ExceptionFlags & EXCEPTION_COLLATERAL)) 505 { 506 Throwable w = cast(Throwable)_d_translate_se_to_d_exception(z); 507 if (w) // if throwable 508 { 509 w.next = prev; 510 prev = w; 511 } 512 z = z.ExceptionRecord; 513 } 514 pti = _d_translate_se_to_d_exception(z); 515 if (cast(Throwable)pti) 516 (cast(Throwable)pti).next = prev; 517 // else it wasn't throwable. (This happens in the test suite eh2.d, test1) 518 519 // Pop the exception from the list of in-flight exceptions 520 inflightExceptionList = z.ExceptionRecord; 521 385 522 int regebp; 386 387 pti = _d_translate_se_to_d_exception(exceptionRecord);388 389 523 // Initialize catch variable 390 524 regebp = cast(int)&frame.ebp; // EBP for this frame 391 525 *cast(Object *)(regebp + (pcb.bpoffset)) = pti; 392 393 _d_setUnhandled(pti);394 395 // Have system call all finally blocks in intervening frames396 _d_global_unwind(frame, exceptionRecord);397 398 // Call all the finally blocks skipped in this frame399 _d_local_unwind(handlerTable, frame, ndx, &searchCollisionExceptionHandler);400 401 _d_setUnhandled(null);402 403 frame.table_index = prev_ndx; // we are out of this handler404 526 405 527 // Jump to catch block. Does not return. 406 528 { 407 529 uint catch_esp; 408 530 alias void function() fp_t; // generic function pointer 409 531 fp_t catch_addr = cast(fp_t)(pcb.code); 410 532 catch_esp = regebp - handlerTable.espoffset - fp_t.sizeof; 411 533 asm 412 534 { 413 535 mov EAX,catch_esp; … … 576 698 So, we need to restart from 'frame.prev'. 577 699 */ 578 700 579 701 extern (C) 580 702 EXCEPTION_DISPOSITION searchCollisionExceptionHandler( 581 703 EXCEPTION_RECORD *exceptionRecord, 582 704 DEstablisherFrame *frame, 583 705 CONTEXT *context, 584 706 void *dispatcherContext) 585 707 { 586 if (!(exceptionRecord.ExceptionFlags & EXCEPTION_UNWIND)) 708 if (!(exceptionRecord.ExceptionFlags & EXCEPTION_UNWIND)) 709 { 710 // Mark this as a collateral exception 711 EXCEPTION_RECORD * n = skipCollateralExceptions(exceptionRecord); 712 n.ExceptionFlags |= EXCEPTION_COLLATERAL; 713 587 714 return EXCEPTION_DISPOSITION.ExceptionContinueSearch; 588 715 } 716 589 717 // An exception has been thrown during unwinding. 590 718 // It happened during the SEARCH phase. 591 719 // We need to cancel the original search pass, so we'll restart from 'frame'. 592 720 *(cast(void **)dispatcherContext) = frame; 593 721 return EXCEPTION_DISPOSITION.ExceptionCollidedUnwind; 594 722 } 595 723 596 724 extern(C) 597 725 EXCEPTION_DISPOSITION unwindCollisionExceptionHandler( 598 726 EXCEPTION_RECORD *exceptionRecord, 599 727 DEstablisherFrame *frame, 600 728 CONTEXT *context, 601 729 void *dispatcherContext) 602 730 { 603 if (!(exceptionRecord.ExceptionFlags & EXCEPTION_UNWIND)) 731 if (!(exceptionRecord.ExceptionFlags & EXCEPTION_UNWIND)) 732 { 733 // Mark this as a collateral exception 734 EXCEPTION_RECORD * n = skipCollateralExceptions(exceptionRecord); 735 n.ExceptionFlags |= EXCEPTION_COLLATERAL; 604 736 return EXCEPTION_DISPOSITION.ExceptionContinueSearch; 605 737 } 606 738 // An exception has been thrown during unwinding. 607 739 // It happened during the UNWIND phase. 608 740 // We need to cancel the unwind pass, AND we need to cancel the search 609 741 // pass that initiated the unwind. So, we need to restart from 'frame.prev'. 610 742 *(cast(void **)dispatcherContext) = frame.prev; 611 743 return EXCEPTION_DISPOSITION.ExceptionCollidedUnwind; 612 744 } 613 745 614 746 /************************************** 615 747 * Call finally blocks in the current stack frame until stop_index.
