home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 August: Tool Chest / Dev.CD Aug 94.toast / New System Software Extensions / OpenDoc A6 / OpenDoc Parts Framework / OPF / Found / FWExcLib / Sources / FWDelSta.cpp < prev    next >
Encoding:
Text File  |  1994-04-21  |  13.9 KB  |  423 lines  |  [TEXT/MPS ]

  1. //========================================================================================
  2. //
  3. //    File:                FWDelSta.cpp
  4. //    Release Version:    $ 1.0d1 $
  5. //
  6. //    Creation Date:        3/28/94
  7. //
  8. //    Copyright:    © 1994 by Apple Computer, Inc., all rights reserved.
  9. //
  10. //========================================================================================
  11.  
  12. #ifndef   FWDELSTA_H
  13. #include "FWDelSta.h"
  14. #endif
  15.  
  16. #ifndef   FWEXCRUN_H
  17. #include "FWExcRun.h"
  18. #endif
  19.  
  20. #ifndef   FWPRIDEB_H
  21. #include "FWPriDeb.h"
  22. #endif
  23.  
  24. #ifndef   FWPRIMEM_H
  25. #include "FWPriMem.h"
  26. #endif
  27.  
  28. #ifndef   FWAUTODE_H
  29. #include "FWAutoDe.h"
  30. #endif
  31.  
  32. #ifndef   FWTRYBLO_H
  33. #include "FWTryBlo.h"
  34. #endif
  35.  
  36. #ifndef   FWSTDDEF_H
  37. #include "FWStdDef.h"
  38. #endif
  39.  
  40. #ifndef   FWCLAINF_H
  41. #include "FWClaInf.h"
  42. #endif
  43.  
  44. #ifdef FW_BUILD_MAC
  45. #pragma segment BEL
  46. #endif
  47.  
  48. //========================================================================================
  49. // CLASS _FW_CDeleteStack
  50. //========================================================================================
  51.  
  52. //----------------------------------------------------------------------------------------
  53. // _FW_CDeleteStack::Initialize
  54. //----------------------------------------------------------------------------------------
  55. void _FW_CDeleteStack::Initialize(FW_SPrivExceptionGlobals& globals)
  56. {
  57.     globals.gCurrentContext = NULL;
  58.     globals.gBaseContext
  59.         = (_FW_CTryBlockContext *) ::FW_PrimitiveAllocateBlock(sizeof(_FW_CTryBlockContext));
  60.     FW_PRIV_ASSERT(globals.gBaseContext != NULL);
  61.     _FW_CTryBlockContext *baseContext
  62.         = new(globals.gBaseContext) _FW_CTryBlockContext(globals, 0);
  63.     FW_PRIV_ASSERT(baseContext == globals.gCurrentContext);
  64.     
  65. #ifdef FW_DEBUG
  66.     globals.gStackBase = (_FW_CDeleteEntry *)::FW_PrimitiveAllocateBlock(kStepByteSize+sizeof(_FW_CDeleteEntry));
  67. #else
  68.     globals.gStackBase = (_FW_CDeleteEntry *)::FW_PrimitiveAllocateBlock(kStepByteSize);
  69. #endif
  70.  
  71.     FW_PRIV_ASSERT(globals.gStackBase != NULL);
  72.  
  73.     globals.gCurrentStackSize = kNumberOfObjectsToGrowStack;
  74.     SetStackTop(globals, globals.gStackBase);
  75.     globals.gStackLimit = globals.gStackBase + kNumberOfObjectsToGrowStack;
  76.     
  77. #ifdef FW_DEBUG
  78.     CheckClassInvariants(globals);
  79. #endif
  80. }
  81.  
  82. //----------------------------------------------------------------------------------------
  83. // _FW_CDeleteStack::Terminate
  84. //----------------------------------------------------------------------------------------
  85. void _FW_CDeleteStack::Terminate()
  86. {
  87.     FW_SPrivExceptionGlobals& globals = FW_CExceptionTaskGlobals::GetExceptionGlobals();
  88.     ::FW_PrimitiveFreeBlock(globals.gStackBase);
  89.     ::FW_PrimitiveFreeBlock(globals.gBaseContext);
  90. }
  91.  
  92. //----------------------------------------------------------------------------------------
  93. // _FW_CDeleteStack::Push
  94. //----------------------------------------------------------------------------------------
  95. // Bottleneck
  96. void _FW_CDeleteStack::Push(void* aGuardOrObject,
  97.                             _FW_CDeleteEntry::__DeleteType type)
  98. {
  99.     FW_SPrivExceptionGlobals& globals = FW_CExceptionTaskGlobals::GetExceptionGlobals();
  100.  
  101. #ifdef FW_DEBUG
  102.     CheckClassInvariants(globals);
  103. #endif
  104.  
  105.     if (globals.gStackTop == globals.gStackLimit)
  106.     {
  107.         // Must grow stack before pushing next entry
  108.         _FW_StackEntries prevSize = globals.gCurrentStackSize;
  109.         _FW_StackEntries newSize = prevSize + kNumberOfObjectsToGrowStack;
  110. #ifdef FW_DEBUG
  111.         size_t newByteSize = (newSize+1) * sizeof(_FW_CDeleteEntry);
  112. #else
  113.         size_t newByteSize = newSize * sizeof(_FW_CDeleteEntry);
  114. #endif
  115.  
  116.         void* p = ::FW_PrimitiveResizeBlock((void*)globals.gStackBase, newByteSize);
  117.  
  118.         FW_PRIV_ASSERT(p != NULL);
  119.  
  120.         globals.gStackBase = (_FW_CDeleteEntry *)p;
  121.         globals.gStackTop = globals.gStackBase + prevSize;
  122.         globals.gCurrentStackSize = newSize;
  123.         globals.gStackLimit = globals.gStackBase + newSize;
  124.     }
  125.     _FW_CDeleteEntry * nextOpening = globals.gStackTop;
  126.  
  127.     nextOpening->fType = type;
  128.     nextOpening->fObject = (_FW_CAutoDestructObject *)aGuardOrObject;
  129.     if (aGuardOrObject != NULL)
  130.         nextOpening->fObjectVTable = *(void**)aGuardOrObject;
  131.  
  132.     SetStackTop(globals, nextOpening + 1);
  133.  
  134. #ifdef FW_DEBUG
  135.     if (type == _FW_CDeleteEntry::__kObject)
  136.         globals.gCurrentContext->fAutomaticsInMyScope++;
  137.     CheckClassInvariants(globals);
  138. #endif
  139. }
  140.  
  141. //----------------------------------------------------------------------------------------
  142. // _FW_CDeleteStack::IsClassExpectedInContext
  143. //----------------------------------------------------------------------------------------
  144. int _FW_CDeleteStack::IsClassExpectedInContext(_FW_CTryBlockContext *context,
  145.                                                FW_ClassReference  thrownType)
  146. {
  147.     FW_SPrivExceptionGlobals& globals = FW_CExceptionTaskGlobals::GetExceptionGlobals();
  148.  
  149.     _FW_CDeleteEntry * contextLimit = globals.gStackBase + context->fDeleteStackLevel;
  150.     _FW_CDeleteEntry * next = globals.gStackTop;
  151.  
  152.     FW_PRIV_ASSERT(globals.gStackBase != NULL);
  153.  
  154.     while (next > contextLimit)
  155.     {
  156.         next--;
  157.  
  158.         if (next->GetType() == _FW_CDeleteEntry::__kGuard)
  159.         {
  160.             FW_ClassReference  theGuardClass = next->GetGuard();
  161.             if (!theGuardClass || !thrownType->IsKindOf(theGuardClass))
  162.             {
  163.                 return 0;
  164.             }
  165.         }
  166.     }
  167.     return 1;
  168. }
  169.  
  170. //----------------------------------------------------------------------------------------
  171. // __CallDestructorWithNoVirtualBaseDelete (Macintosh version)
  172. //----------------------------------------------------------------------------------------
  173. #ifdef FW_BUILD_MAC
  174. extern "C"
  175. {
  176.     #pragma parameter __CallDestructorWithNoVirtualBaseDelete(__D1)
  177.     void __CallDestructorWithNoVirtualBaseDelete(void *)
  178.         = {0x7000, 0x2f00, 0x2041, 0x2250, 0xd0e9, 0x0008,
  179.             0x2f08, 0x2041, 0x2050, 0x2268, 0x000c, 0x4e91, 0x508f};
  180. }
  181. /*
  182. 00000                              CallDestructorWithNoVirtualBaseDelete PROC
  183. 00000                                      ; D1 has object
  184. 00000   7000                               moveq    #0,d0                ; don't delete virtual bases
  185. 00002   2F00                               move.l    d0,-(a7)            ; arguement to destructor
  186. 00004   2041                               movea.l    d1,a0
  187. 00006   2250                               movea.l    (a0),a1                ; vtable for object
  188. 00008   D0E9 0008                          adda.w    8(a1),a0            ; get offset to start of object
  189. 0000C   2F08                               move.l    a0,-(a7)            ; push object address
  190. 0000E   2041                               movea.l    d1,a0
  191. 00010   2050                               movea.l    (a0),a0                ; vtable
  192. 00012   2268 000C                          movea.l    12(a0),a1            ; destructor address
  193. 00016   4E91                               jsr        (a1)
  194. 00018    508F                            addq.l    #8,a7                ; clean stack
  195. 0001A                                  ENDPROC
  196. */
  197. #endif
  198.  
  199. //----------------------------------------------------------------------------------------
  200. // __CallDestructorWithNoVirtualBaseDelete (Windows version)
  201. //----------------------------------------------------------------------------------------
  202. #ifdef __ZTCWIN__
  203. void __CallDestructorWithNoVirtualBaseDelete(void * p)
  204. {
  205.     asm(0xC4, 0x5E, 0x06);          //  les     BX, [BP+6]      ; ES:BX <-- pObject
  206.     asm(0x33, 0xC0);                //  xor     AX, AX          ; AX    <-- 0
  207.     asm(0x50);                      //  push    AX              ; Push dtor argument
  208.     asm(0x06);                      //  push    ES              ; Push pObject
  209.     asm(0x53);                      //  push    BX
  210.     asm(0x26, 0xC4, 0x1F);          //  les     BX, [ES:BX]     ; ES:BX <-- vmtPtr
  211.     asm(0x26, 0xFF, 0x5F, 0x04);    //  call    [DWORD ES:BX+4] ; Call the dtor
  212. }
  213. #endif
  214.  
  215. //----------------------------------------------------------------------------------------
  216. // _FW_CDeleteStack::PopOffAndDeleteObjectsInContext
  217. //----------------------------------------------------------------------------------------
  218. void _FW_CDeleteStack::PopOffAndDeleteObjectsInContext(FW_SPrivExceptionGlobals& globals,
  219.                                                         _FW_CTryBlockContext *context)
  220. {
  221. #ifdef FW_DEBUG
  222.     CheckClassInvariants(globals);
  223. #endif
  224.  
  225.     _FW_StackEntries offset = context->fDeleteStackLevel;
  226.  
  227.     _FW_CDeleteEntry * popLimit = globals.gStackBase + offset;
  228.     _FW_CDeleteEntry * popMe = globals.gStackTop;
  229.     FW_PRIV_ASSERT(popMe >= popLimit);
  230.     
  231.     globals.gIsThrowing = 1;
  232.  
  233.     while (popMe > popLimit)
  234.     {
  235.         popMe--;
  236.  
  237.         if (popMe->GetType() == _FW_CDeleteEntry::__kObject)
  238.         {
  239.             _FW_CAutoDestructObject * lastDeleted = popMe->GetObject();
  240.             FW_PRIV_ASSERT(lastDeleted != NULL);
  241.             *(void**)lastDeleted = popMe->fObjectVTable;
  242.     
  243.             // Global must be set properly before __Delete(), which calls PopIfTopEquals()
  244.             SetStackTop(globals, popMe+1);
  245. #if 0
  246.             // Disabled, but may need to restore this code later.
  247.             __CallDestructorWithNoVirtualBaseDelete((void*)lastDeleted);
  248. #else
  249.             lastDeleted->__Delete();    // Virtual dispatch to object's destructor
  250. #endif
  251.     
  252.             // The destructor of the deleted object will have popped one or more objects 
  253.             // off the stack so we have to query the stack to find out who to pop next.
  254.             popMe = globals.gStackTop;
  255.         }
  256.     }
  257.  
  258.     FW_PRIV_ASSERT(popMe == popLimit);
  259.     SetStackTop(globals, popLimit);
  260.     globals.gIsThrowing = 0;
  261.  
  262. #ifdef FW_DEBUG
  263.     CheckClassInvariants(globals);
  264. #endif
  265. }
  266.  
  267.  
  268. //----------------------------------------------------------------------------------------
  269. // _FW_CDeleteStack::PopIfTopEquals
  270. //----------------------------------------------------------------------------------------
  271. // Bottleneck
  272. void _FW_CDeleteStack::PopIfTopEquals(_FW_CAutoDestructObject* anObject)
  273. {
  274.     FW_SPrivExceptionGlobals& globals = FW_CExceptionTaskGlobals::GetExceptionGlobals();
  275.  
  276. #ifdef FW_DEBUG
  277.     CheckClassInvariants(globals);
  278. #endif
  279.  
  280.     _FW_CTryBlockContext *context = globals.gCurrentContext;
  281.     _FW_StackEntries offset = context->fDeleteStackLevel;
  282.     _FW_CDeleteEntry * popLimit = globals.gStackBase + offset;
  283.     _FW_CDeleteEntry * popMe = globals.gStackTop;
  284.     FW_PRIV_ASSERT(popMe > popLimit);
  285.  
  286.     // Normally, the top item on the stack will be the entry for anObject.
  287.     // However, we may be deleting out of order, and there may be guards.
  288.     // So, we must clean any gaurds and previously deleted items off the top
  289.     // of the stack.  If the first kObject entry is our object, then we clean
  290.     // it off too and exit.  If the first kObject entry is not our object, then
  291.     // we need to search through the stack for our object and mark it deleted.
  292.     // During the search, the stack top is not changed.
  293.  
  294.     // Clean off guards and deleted items.  Stack top is changed.
  295.     while (popMe > popLimit)
  296.     {
  297.         popMe--;
  298.         if (popMe->GetType() == _FW_CDeleteEntry::__kObject)
  299.             break;
  300.     }
  301.     
  302.     // There must still be at list one entry in this context.
  303.     FW_PRIV_ASSERT(popMe >= popLimit);
  304.     
  305.     // And the top one must be an undeleted object entry.
  306.     FW_PRIV_ASSERT(popMe->GetType() == _FW_CDeleteEntry::__kObject);
  307.  
  308.     FW_Boolean objectDeleted = FALSE;
  309.     if (popMe->GetObject() == anObject)
  310.     {
  311.         // All is cool.  First kObject entry is our object.  Pop off entry.
  312.         SetStackTop(globals, popMe);
  313.         objectDeleted = TRUE;
  314.     }
  315.     else
  316.     {
  317.         // Need to remember where the stack top is now located.
  318.         SetStackTop(globals, popMe+1);
  319.  
  320.         // Destroying out of order.  Search for our object and mark it destroyed.
  321.         // Do not change stack top.
  322.  
  323.         while (popMe > popLimit)
  324.         {
  325.             popMe--;
  326.             if (popMe->GetType() == _FW_CDeleteEntry::__kObject && popMe->GetObject() == anObject)
  327.             {
  328.                 popMe->SetType(_FW_CDeleteEntry::__kDeleted);
  329.                 objectDeleted = TRUE;
  330.                 break;
  331.             }
  332.         }
  333.     }
  334.  
  335. #ifdef FW_DEBUG
  336.     if (objectDeleted)
  337.         context->fAutomaticsInMyScope--;
  338.     CheckClassInvariants(globals);
  339. #endif
  340. }
  341.  
  342. //----------------------------------------------------------------------------------------
  343. // _FW_CDeleteStack::PopGuard
  344. //----------------------------------------------------------------------------------------
  345. FW_ClassReference  _FW_CDeleteStack::PopGuard()
  346. {
  347.     FW_SPrivExceptionGlobals& globals = FW_CExceptionTaskGlobals::GetExceptionGlobals();
  348.  
  349. #ifdef FW_DEBUG
  350.     CheckClassInvariants(globals);
  351. #endif
  352.  
  353.     _FW_CDeleteEntry * popMe = globals.gStackTop - 1;
  354.     FW_ClassReference result = popMe->GetGuard();
  355.     SetStackTop(globals, popMe);
  356.  
  357. #ifdef FW_DEBUG
  358.     CheckClassInvariants(globals);
  359. #endif
  360.  
  361.     return result;
  362. }
  363.  
  364. #ifdef FW_DEBUG
  365. //----------------------------------------------------------------------------------------
  366. // _FW_CDeleteStack::CheckClassInvariants
  367. //----------------------------------------------------------------------------------------
  368. void _FW_CDeleteStack::CheckClassInvariants(FW_SPrivExceptionGlobals& globals)
  369. {
  370.     // Ensure class invariants
  371.     FW_PRIV_ASSERT(globals.gStackBase != NULL);
  372.     FW_PRIV_ASSERT(globals.gStackBase <= globals.gStackTop);
  373.     FW_PRIV_ASSERT(globals.gStackTop <= globals.gStackLimit);
  374.     FW_PRIV_ASSERT(globals.gCurrentStackSize >= kNumberOfObjectsToGrowStack);
  375.     FW_PRIV_ASSERT(globals.gStackBase+globals.gCurrentStackSize == globals.gStackLimit);
  376.     FW_PRIV_ASSERT(globals.gStackTop->GetType() == _FW_CDeleteEntry::__kInvalid);
  377.  
  378.     _FW_CTryBlockContext *context = globals.gCurrentContext;
  379.     if (context != NULL)
  380.     {
  381.         context->CheckClassInvariants(globals);
  382.         FW_PRIV_ASSERT(RelativeTopOfStack(globals) >= context->fDeleteStackLevel);
  383.         FW_PRIV_ASSERT(RelativeTopOfStack(globals)-context->fDeleteStackLevel >= context->fAutomaticsInMyScope);
  384.     }
  385. }
  386. #endif
  387.  
  388. //========================================================================================
  389. // CLASS _FW_SThrowGuard
  390. //========================================================================================
  391.  
  392. //----------------------------------------------------------------------------------------
  393. // _FW_SThrowGuard::_FW_SThrowGuard
  394. //----------------------------------------------------------------------------------------
  395. _FW_SThrowGuard::_FW_SThrowGuard()
  396. {
  397.     _FW_CDeleteStack::Push((FW_ClassReference ) NULL);
  398. #ifdef FW_DEBUG
  399.     fGuardClass = (FW_ClassReference ) NULL;
  400. #endif
  401. }
  402.  
  403. //----------------------------------------------------------------------------------------
  404. // _FW_SThrowGuard::_FW_SThrowGuard
  405. //----------------------------------------------------------------------------------------
  406. _FW_SThrowGuard::_FW_SThrowGuard(FW_ClassReference  guard)
  407. {
  408.     _FW_CDeleteStack::Push(guard);
  409. #ifdef FW_DEBUG
  410.     fGuardClass = guard;
  411. #endif
  412. }
  413.  
  414. //----------------------------------------------------------------------------------------
  415. // _FW_SThrowGuard::~_FW_SThrowGuard
  416. //----------------------------------------------------------------------------------------
  417. _FW_SThrowGuard::~_FW_SThrowGuard()
  418. {
  419.     FW_ClassReference  aClass = _FW_CDeleteStack::PopGuard();
  420.     FW_PRIV_ASSERT(aClass == fGuardClass);
  421. }
  422.  
  423.