home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-11-08 | 14.4 KB | 434 lines | [TEXT/MPS ] |
- //========================================================================================
- //
- // File: FWDelSta.cpp
- // Release Version: $ 1.0d11 $
- //
- // Copyright: (c) 1993, 1995 by Apple Computer, Inc., all rights reserved.
- //
- //========================================================================================
-
- #include "FWFound.hpp"
-
- #ifndef FW_NATIVE_EXCEPTIONS
-
- #ifndef FWENVDEF_H
- #include "FWEnvDef.h"
- #endif
-
- #ifndef FWDELSTA_H
- #include "FWDelSta.h"
- #endif
-
- #ifndef FWEXCRUN_H
- #include "FWExcRun.h"
- #endif
-
- #ifndef FWPRIDEB_H
- #include "FWPriDeb.h"
- #endif
-
- #ifndef FWPRIMEM_H
- #include "FWPriMem.h"
- #endif
-
- #ifndef FWAUTODE_H
- #include "FWAutoDe.h"
- #endif
-
- #ifndef FWTRYBLO_H
- #include "FWTryBlo.h"
- #endif
-
- #ifndef FWSTDDEF_H
- #include "FWStdDef.h"
- #endif
-
- #ifndef FWCLAINF_H
- #include "FWClaInf.h"
- #endif
-
- #if FW_LIB_EXPORT_PRAGMAS
- #pragma lib_export on
- #endif
-
- #ifdef FW_BUILD_MAC
- #pragma segment BEL
- #endif
-
- //========================================================================================
- // CLASS FW_CPrivDeleteStack
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivDeleteStack::Initialize
- //----------------------------------------------------------------------------------------
- void FW_CPrivDeleteStack::Initialize(FW_SPrivExceptionGlobals& globals)
- {
- globals.gCurrentContext = NULL;
- globals.gBaseContext
- = (FW_CPrivTryBlockContext *) ::FW_PrimitiveAllocateBlock(sizeof(FW_CPrivTryBlockContext));
- FW_PRIV_ASSERT(globals.gBaseContext != NULL);
- FW_CPrivTryBlockContext *baseContext
- = new(globals.gBaseContext) FW_CPrivTryBlockContext(globals, 0);
- FW_PRIV_ASSERT(baseContext == globals.gCurrentContext);
-
- #ifdef FW_DEBUG
- globals.gStackBase = (FW_CPrivDeleteEntry *)::FW_PrimitiveAllocateBlock(kStepByteSize+sizeof(FW_CPrivDeleteEntry));
- #else
- globals.gStackBase = (FW_CPrivDeleteEntry *)::FW_PrimitiveAllocateBlock(kStepByteSize);
- #endif
-
- FW_PRIV_ASSERT(globals.gStackBase != NULL);
-
- globals.gCurrentStackSize = kNumberOfObjectsToGrowStack;
- SetStackTop(globals, globals.gStackBase);
- globals.gStackLimit = globals.gStackBase + kNumberOfObjectsToGrowStack;
-
- #ifdef FW_DEBUG
- CheckClassInvariants(globals);
- #endif
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivDeleteStack::Terminate
- //----------------------------------------------------------------------------------------
- void FW_CPrivDeleteStack::Terminate()
- {
- FW_SPrivExceptionGlobals& globals = FW_CExceptionTaskGlobals::GetExceptionGlobals();
- ::FW_PrimitiveFreeBlock(globals.gStackBase);
- ::FW_PrimitiveFreeBlock(globals.gBaseContext);
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivDeleteStack::Push
- //----------------------------------------------------------------------------------------
- // Bottleneck
- void FW_CPrivDeleteStack::Push(void* aGuardOrObject,
- FW_CPrivDeleteEntry::__DeleteType type)
- {
- FW_SPrivExceptionGlobals& globals = FW_CExceptionTaskGlobals::GetExceptionGlobals();
-
- #ifdef FW_DEBUG
- CheckClassInvariants(globals);
- #endif
-
- if (globals.gStackTop == globals.gStackLimit)
- {
- // Must grow stack before pushing next entry
- _FW_StackEntries prevSize = globals.gCurrentStackSize;
- _FW_StackEntries newSize = prevSize + kNumberOfObjectsToGrowStack;
- #ifdef FW_DEBUG
- size_t newByteSize = (newSize+1) * sizeof(FW_CPrivDeleteEntry);
- #else
- size_t newByteSize = newSize * sizeof(FW_CPrivDeleteEntry);
- #endif
-
- void* p = ::FW_PrimitiveResizeBlock((void*)globals.gStackBase, newByteSize);
-
- FW_PRIV_ASSERT(p != NULL);
-
- globals.gStackBase = (FW_CPrivDeleteEntry *)p;
- globals.gStackTop = globals.gStackBase + prevSize;
- globals.gCurrentStackSize = newSize;
- globals.gStackLimit = globals.gStackBase + newSize;
- }
- FW_CPrivDeleteEntry * nextOpening = globals.gStackTop;
-
- nextOpening->fType = type;
- nextOpening->fObject = (_FW_CAutoDestructObject *)aGuardOrObject;
- if (aGuardOrObject != NULL)
- nextOpening->fObjectVTable = *(void**)aGuardOrObject;
-
- SetStackTop(globals, nextOpening + 1);
-
- #ifdef FW_DEBUG
- if (type == FW_CPrivDeleteEntry::__kObject)
- globals.gCurrentContext->fAutomaticsInMyScope++;
- CheckClassInvariants(globals);
- #endif
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivDeleteStack::IsClassExpectedInContext
- //----------------------------------------------------------------------------------------
- int FW_CPrivDeleteStack::IsClassExpectedInContext(FW_CPrivTryBlockContext *context,
- FW_ClassInfoPtr thrownType)
- {
- FW_SPrivExceptionGlobals& globals = FW_CExceptionTaskGlobals::GetExceptionGlobals();
-
- FW_CPrivDeleteEntry * contextLimit = globals.gStackBase + context->fDeleteStackLevel;
- FW_CPrivDeleteEntry * next = globals.gStackTop;
-
- FW_PRIV_ASSERT(globals.gStackBase != NULL);
-
- while (next > contextLimit)
- {
- next--;
-
- if (next->GetType() == FW_CPrivDeleteEntry::__kGuard)
- {
- FW_ClassInfoPtr theGuardClass = next->GetGuard();
- if (!theGuardClass || !thrownType->IsKindOf(theGuardClass))
- {
- return 0;
- }
- }
- }
- return 1;
- }
-
- //----------------------------------------------------------------------------------------
- // __CallDestructorWithNoVirtualBaseDelete (Macintosh version)
- //----------------------------------------------------------------------------------------
- #if defined(FW_BUILD_MAC) && defined(FW_NEED_DELETE_HACK)
- extern "C"
- {
- #pragma parameter __CallDestructorWithNoVirtualBaseDelete(__D1)
- void __CallDestructorWithNoVirtualBaseDelete(void *)
- = {0x7000, 0x2f00, 0x2041, 0x2250, 0xd0e9, 0x0008,
- 0x2f08, 0x2041, 0x2050, 0x2268, 0x000c, 0x4e91, 0x508f};
- }
- /*
- 00000 CallDestructorWithNoVirtualBaseDelete PROC
- 00000 ; D1 has object
- 00000 7000 moveq #0,d0 ; don't delete virtual bases
- 00002 2F00 move.l d0,-(a7) ; arguement to destructor
- 00004 2041 movea.l d1,a0
- 00006 2250 movea.l (a0),a1 ; vtable for object
- 00008 D0E9 0008 adda.w 8(a1),a0 ; get offset to start of object
- 0000C 2F08 move.l a0,-(a7) ; push object address
- 0000E 2041 movea.l d1,a0
- 00010 2050 movea.l (a0),a0 ; vtable
- 00012 2268 000C movea.l 12(a0),a1 ; destructor address
- 00016 4E91 jsr (a1)
- 00018 508F addq.l #8,a7 ; clean stack
- 0001A ENDPROC
- */
- #endif
-
- //----------------------------------------------------------------------------------------
- // __CallDestructorWithNoVirtualBaseDelete (Windows version)
- //----------------------------------------------------------------------------------------
- #if defined(__ZTCWIN__) && defined(FW_NEED_DELETE_HACK)
- void __CallDestructorWithNoVirtualBaseDelete(void * p)
- {
- asm(0xC4, 0x5E, 0x06); // les BX, [BP+6] ; ES:BX <-- pObject
- asm(0x33, 0xC0); // xor AX, AX ; AX <-- 0
- asm(0x50); // push AX ; Push dtor argument
- asm(0x06); // push ES ; Push pObject
- asm(0x53); // push BX
- asm(0x26, 0xC4, 0x1F); // les BX, [ES:BX] ; ES:BX <-- vmtPtr
- asm(0x26, 0xFF, 0x5F, 0x04); // call [DWORD ES:BX+4] ; Call the dtor
- }
- #endif
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivDeleteStack::PopOffAndDeleteObjectsInContext
- //----------------------------------------------------------------------------------------
- void FW_CPrivDeleteStack::PopOffAndDeleteObjectsInContext(FW_SPrivExceptionGlobals& globals,
- FW_CPrivTryBlockContext *context)
- {
- #ifdef FW_DEBUG
- CheckClassInvariants(globals);
- #endif
-
- _FW_StackEntries offset = context->fDeleteStackLevel;
-
- FW_CPrivDeleteEntry * popLimit = globals.gStackBase + offset;
- FW_CPrivDeleteEntry * popMe = globals.gStackTop;
- FW_PRIV_ASSERT(popMe >= popLimit);
-
- globals.gIsThrowing = 1;
-
- while (popMe > popLimit)
- {
- popMe--;
-
- if (popMe->GetType() == FW_CPrivDeleteEntry::__kObject)
- {
- _FW_CAutoDestructObject * lastDeleted = popMe->GetObject();
- FW_PRIV_ASSERT(lastDeleted != NULL);
- *(void**)lastDeleted = popMe->fObjectVTable;
-
- // Global must be set properly before __Delete(), which calls PopIfTopEquals()
- SetStackTop(globals, popMe+1);
- #if defined(FW_NEED_DELETE_HACK)
- // Disabled, but may need to restore this code later.
- __CallDestructorWithNoVirtualBaseDelete((void*)lastDeleted);
- #else
- lastDeleted->__Delete(); // Virtual dispatch to object's destructor
- #endif
-
- // The destructor of the deleted object will have popped one or more objects
- // off the stack so we have to query the stack to find out who to pop next.
- popMe = globals.gStackTop;
- }
- }
-
- FW_PRIV_ASSERT(popMe == popLimit);
- SetStackTop(globals, popLimit);
- globals.gIsThrowing = 0;
-
- #ifdef FW_DEBUG
- CheckClassInvariants(globals);
- #endif
- }
-
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivDeleteStack::PopIfTopEquals
- //----------------------------------------------------------------------------------------
- // Bottleneck
- void FW_CPrivDeleteStack::PopIfTopEquals(_FW_CAutoDestructObject* anObject)
- {
- FW_SPrivExceptionGlobals& globals = FW_CExceptionTaskGlobals::GetExceptionGlobals();
-
- #ifdef FW_DEBUG
- CheckClassInvariants(globals);
- #endif
-
- FW_CPrivTryBlockContext *context = globals.gCurrentContext;
- _FW_StackEntries offset = context->fDeleteStackLevel;
- FW_CPrivDeleteEntry * popLimit = globals.gStackBase + offset;
- FW_CPrivDeleteEntry * popMe = globals.gStackTop;
- FW_PRIV_ASSERT(popMe > popLimit);
-
- // Normally, the top item on the stack will be the entry for anObject.
- // However, we may be deleting out of order, and there may be guards.
- // So, we must clean any gaurds and previously deleted items off the top
- // of the stack. If the first kObject entry is our object, then we clean
- // it off too and exit. If the first kObject entry is not our object, then
- // we need to search through the stack for our object and mark it deleted.
- // During the search, the stack top is not changed.
-
- // Clean off guards and deleted items. Stack top is changed.
- while (popMe > popLimit)
- {
- popMe--;
- if (popMe->GetType() == FW_CPrivDeleteEntry::__kObject)
- break;
- }
-
- // There must still be at list one entry in this context.
- FW_PRIV_ASSERT(popMe >= popLimit);
-
- // And the top one must be an undeleted object entry.
- FW_PRIV_ASSERT(popMe->GetType() == FW_CPrivDeleteEntry::__kObject);
-
- FW_Boolean objectDeleted = FALSE;
- if (popMe->GetObject() == anObject)
- {
- // All is cool. First kObject entry is our object. Pop off entry.
- SetStackTop(globals, popMe);
- objectDeleted = TRUE;
- }
- else
- {
- // Need to remember where the stack top is now located.
- SetStackTop(globals, popMe+1);
-
- // Destroying out of order. Search for our object and mark it destroyed.
- // Do not change stack top.
-
- while (popMe > popLimit)
- {
- popMe--;
- if (popMe->GetType() == FW_CPrivDeleteEntry::__kObject && popMe->GetObject() == anObject)
- {
- popMe->SetType(FW_CPrivDeleteEntry::__kDeleted);
- objectDeleted = TRUE;
- break;
- }
- }
- }
-
- #ifdef FW_DEBUG
- if (objectDeleted)
- context->fAutomaticsInMyScope--;
- CheckClassInvariants(globals);
- #endif
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivDeleteStack::PopGuard
- //----------------------------------------------------------------------------------------
- FW_ClassInfoPtr FW_CPrivDeleteStack::PopGuard()
- {
- FW_SPrivExceptionGlobals& globals = FW_CExceptionTaskGlobals::GetExceptionGlobals();
-
- #ifdef FW_DEBUG
- CheckClassInvariants(globals);
- #endif
-
- FW_CPrivDeleteEntry * popMe = globals.gStackTop - 1;
- FW_ClassInfoPtr result = popMe->GetGuard();
- SetStackTop(globals, popMe);
-
- #ifdef FW_DEBUG
- CheckClassInvariants(globals);
- #endif
-
- return result;
- }
-
- #ifdef FW_DEBUG
- //----------------------------------------------------------------------------------------
- // FW_CPrivDeleteStack::CheckClassInvariants
- //----------------------------------------------------------------------------------------
- void FW_CPrivDeleteStack::CheckClassInvariants(FW_SPrivExceptionGlobals& globals)
- {
- // Ensure class invariants
- FW_PRIV_ASSERT(globals.gStackBase != NULL);
- FW_PRIV_ASSERT(globals.gStackBase <= globals.gStackTop);
- FW_PRIV_ASSERT(globals.gStackTop <= globals.gStackLimit);
- FW_PRIV_ASSERT(globals.gCurrentStackSize >= kNumberOfObjectsToGrowStack);
- FW_PRIV_ASSERT(globals.gStackBase+globals.gCurrentStackSize == globals.gStackLimit);
- FW_PRIV_ASSERT(globals.gStackTop->GetType() == FW_CPrivDeleteEntry::__kInvalid);
-
- FW_CPrivTryBlockContext *context = globals.gCurrentContext;
- if (context != NULL)
- {
- context->CheckClassInvariants(globals);
- FW_PRIV_ASSERT(RelativeTopOfStack(globals) >= context->fDeleteStackLevel);
- FW_PRIV_ASSERT(RelativeTopOfStack(globals)-context->fDeleteStackLevel >= context->fAutomaticsInMyScope);
- }
- }
- #endif
-
- //========================================================================================
- // CLASS FW_CPrivThrowGuard
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivThrowGuard::FW_CPrivThrowGuard
- //----------------------------------------------------------------------------------------
- FW_CPrivThrowGuard::FW_CPrivThrowGuard()
- {
- FW_CPrivDeleteStack::Push((FW_ClassInfoPtr ) NULL);
- #ifdef FW_DEBUG
- fGuardClass = (FW_ClassInfoPtr ) NULL;
- #endif
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivThrowGuard::FW_CPrivThrowGuard
- //----------------------------------------------------------------------------------------
- FW_CPrivThrowGuard::FW_CPrivThrowGuard(FW_ClassInfoPtr guard)
- {
- FW_CPrivDeleteStack::Push(guard);
- #ifdef FW_DEBUG
- fGuardClass = guard;
- #endif
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CPrivThrowGuard::~FW_CPrivThrowGuard
- //----------------------------------------------------------------------------------------
- FW_CPrivThrowGuard::~FW_CPrivThrowGuard()
- {
- FW_ClassInfoPtr aClass = FW_CPrivDeleteStack::PopGuard();
- FW_PRIV_ASSERT(aClass == fGuardClass);
- }
-
- #endif // FW_NATIVE_EXCEPTIONS
-