home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc™ Source Code / Utilities / Except.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-08-28  |  18.2 KB  |  820 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        Except.cpp
  3.  
  4.     Contains:    Exception-handling utility
  5.  
  6.     Owned by:    Jens Alfke
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.          <4>     5/31/96    JA        CW68K: 68K support for CHECK_ENV.
  13.          <3>     5/24/96    jpa        1246074: Fixed DoThrow for native
  14.                                     exceptions. 1.1MRD: Disabled gVolatile for
  15.                                     non-Symantec compilers. Implemented
  16.                                     _ASM_XTRY_ optimizations.
  17.          <2>      3/3/96    TJ        Added global gVolatile to help make
  18.                                     ODVolatile realy volatile.
  19.  
  20.     In Progress:
  21.         
  22. */
  23.  
  24. #ifndef _PLATFORM_MACINTOSH_
  25. #define DONT_USE_STACKCRAWL
  26. #endif
  27.  
  28. #ifndef __EXCEPT__
  29. #include "Except.h"
  30. #endif
  31.  
  32. #ifndef _ODDEBUG_
  33. #include "ODDebug.h"
  34. #endif
  35.  
  36. #ifndef SOM_Module_OpenDoc_Errors_defined
  37. #include "ErrorDef.xh"
  38. #endif
  39.  
  40. #ifndef _PLFMDEF_
  41. #include "PlfmDef.h"
  42. #endif
  43.  
  44. #ifndef _UTILERRS_
  45. #include "UtilErrs.h"
  46. #endif
  47.  
  48. #ifndef DONT_USE_STACKCRAWL
  49. #ifndef _CRAWL_
  50. #include <Crawl.h>
  51. #endif
  52. #endif
  53.  
  54. #ifndef __SOM__
  55. #include <som.xh>
  56. #endif
  57.  
  58. #ifndef __RESOURCES__
  59. #include <Resources.h>
  60. #endif
  61.  
  62. #ifndef __STRINGS__
  63. #include <Strings.h>
  64. #endif
  65.  
  66. #ifndef _ODMEMORY_
  67. #include "ODMemory.h"
  68. #endif
  69.  
  70. #include <stdio.h>
  71. #include <stdarg.h>
  72. #include <string.h>
  73.  
  74.  
  75. #ifdef __MWERKS__
  76. #ifdef __cplusplus
  77.     // The _NATIVE_EXCEPTIONS_ flag must match the Exception Support option:
  78.     #if __option(exceptions) && !defined(_NATIVE_EXCEPTIONS_)
  79.         #error Except.h must be compiled w/_NATIVE_EXCEPTIONS_ defined to use native exceptions
  80.     #elif !__option(exceptions) && defined(_NATIVE_EXCEPTIONS_)
  81.         #error CW exception support must be turned on to use _NATIVE_EXCEPTIONS_ in Except
  82.     #endif
  83. #endif
  84. #endif
  85.  
  86.  
  87. extern void BREAK( const char[] );
  88.  
  89. #ifndef _NATIVE_EXCEPTIONS_
  90. void* gVolatile;
  91. #endif
  92.  
  93. static ODBoolean gBreakOnThrow = kODFalse;    // Set to true to break on exceptions
  94.  
  95.  
  96. #define kSpareMemSize 512
  97.  
  98. static void* gSpareMem = kODNULL;
  99. // gSpareMem is a block of memory we keep around to make sure that in an emergency
  100. // we always have enough memory to allocate a SOM exception, by releasing the spare
  101. // block if we have to.
  102.  
  103.  
  104. #pragma segment ODExceptions
  105.  
  106. //=====================================================================================
  107. // Setting BreakOnThrow
  108. //=====================================================================================
  109.  
  110.  
  111. ODBoolean
  112. BreakOnThrow( ODBoolean brk )
  113. {
  114.     ODBoolean oldBrk = gBreakOnThrow;
  115.     gBreakOnThrow = brk;
  116.     return oldBrk;
  117. }
  118.  
  119.  
  120. //=====================================================================================
  121. // Initializing ODException Structures
  122. //=====================================================================================
  123.  
  124.  
  125. static void
  126. InitODException( ODException *x, ODError error, const char *message, ODSLong msgsize )
  127. {
  128.     x->error = error;
  129.     if( message ) {
  130.         ODBlockMove(message,x->message,msgsize);
  131.         x->message[msgsize-1] = '\0';
  132.     } else
  133.         x->message[0] = 0;
  134. }
  135.  
  136.  
  137. static ODException*
  138. NewODException( ODError error, const char *message )
  139. {
  140.     SOMFree(gSpareMem);                            // Get some slack
  141.     
  142.     ODULong size = message ?(strlen(message)+1) :1;
  143.     if( size>256 ) size=256;
  144.     ODException *x = (ODException*) SOMMalloc( sizeof(ODError) + size );
  145.     
  146.     if( x )
  147.         InitODException(x,error,message,size);
  148.     
  149.     gSpareMem = SOMMalloc(kSpareMemSize);        // Tighten up again
  150.     
  151.     return x;
  152. }
  153.  
  154. #ifndef _NATIVE_EXCEPTIONS_
  155.  
  156. //=====================================================================================
  157. // Stack Maintenance
  158. //=====================================================================================
  159.  
  160. static ODExceptionFrame *gTopHandler = kODNULL;
  161.  
  162.  
  163. //=====================================================================================
  164. // ODExceptionFrame
  165. //=====================================================================================
  166.  
  167.  
  168. #define kAlreadyPoppedHandler ((ODExceptionFrame*)0xDEADBEEF)
  169.  
  170.  
  171. #ifdef _ASM_XTRY_
  172.  
  173. extern "C" void __ptr_glue(void);
  174.  
  175. /*    These are optimized assembly functions that are equivalent to calling
  176.     setjmp(_xTry(x)) or setjmp(_xTryEv(x,ev)). They are optimized in that:
  177.         * The caller does not have to call setjmp.
  178.         * A stack frame is allocated & torn down only in the rare case
  179.             that gSpareMem is NULL and needs to be reallocated.
  180. */
  181.  
  182. asm int _setjmp_xTry( register ODExceptionFrame *x /*in r3*/ )
  183. {
  184.     lwz        r0,gSpareMem            // Check whether gSpareMem is NULL
  185.     cmplwi    r0,0
  186.     bne+    setit                    // If not, skip to setit
  187.     
  188.     mflr    r0                        // Allocate stack frame
  189.     stw        r31,-4(sp)
  190.     stw        r0,8(sp)
  191.     stwu    sp,-64(sp)
  192.     mr        r31,r3
  193.     
  194.     lwz        r4,SOMMalloc            // Call SOMMalloc
  195.     li        r3,kSpareMemSize
  196.     lwz        r12,0(r4)
  197.     bl        __ptr_glue
  198.     nop
  199.     stw        r3,gSpareMem
  200.  
  201.     lwz        r0,72(sp)                // Tear down stack frame
  202.     addi    sp,sp,64
  203.     mtlr    r0
  204.     mr        r3,r31                        // and restore r3 (parameter)
  205.     lwz        r31,-4(sp)
  206.  
  207. setit:
  208.     li        r0,0                    // Fill out the fields of the exception frame
  209.     stw        r0,x->fError
  210.     stw        r0,x->fODException
  211.     stw        r0,x->fEv
  212.     stw        r0,x->fDestructoList
  213.     lwz        r0,gTopHandler
  214.     stw        r3,gTopHandler
  215.     stw        r0,x->fPrev
  216.     
  217.     addi    r3,r3,20                // 20 = offsetof(ODExceptionFrame,fBuffer)
  218.     b        __setjmp                // Call setjmp on x->fBuffer.
  219. }
  220.  
  221. asm int _setjmp_xTryEv( register ODExceptionFrame *x /*r3*/, register Environment *ev /*r4*/ )
  222. {
  223.     lwz        r0,gSpareMem            // Check whether gSpareMem is NULL
  224.     cmplwi    r0,0
  225.     bne+    setit                    // If not, skip to setit
  226.     
  227.     mflr    r0                        // Allocate stack frame
  228.     stmw    r30,-8(sp)
  229.     stw        r0,8(sp)
  230.     stwu    sp,-64(sp)
  231.     mr        r30,r3
  232.     mr        r31,r4
  233.     
  234.     lwz        r4,SOMMalloc            // Call SOMMalloc
  235.     li        r3,kSpareMemSize
  236.     lwz        r12,0(r4)
  237.     bl        __ptr_glue
  238.     nop
  239.     stw        r3,gSpareMem
  240.  
  241.     lwz        r0,72(sp)                // Tear down stack frame
  242.     addi    sp,sp,64
  243.     mtlr    r0
  244.     mr        r3,r30                        // and restore r3 & r4 (parameters)
  245.     mr        r4,r31
  246.     lmw        r30,-8(sp)
  247.  
  248. setit:
  249.     li        r0,0                    // Fill out the fields of the exception frame
  250.     stw        r0,x->fError
  251.     stw        r0,x->fODException
  252.     stw        ev,x->fEv                    // store ev in fEv
  253.     stw        r0,x->fDestructoList
  254.     lwz        r0,gTopHandler
  255.     stw        r3,gTopHandler
  256.     stw        r0,x->fPrev
  257.     
  258.     addi    r3,r3,20                // 20 = offsetof(ODExceptionFrame,fBuffer)
  259.     b        __setjmp                // Call setjmp on x->fBuffer.
  260. }
  261.  
  262. #else /*not _ASM_XTRY_*/
  263.  
  264. jmp_buf* _xTry( ODExceptionFrame *x )
  265. {
  266.     if( ! gSpareMem )
  267.         gSpareMem = SOMMalloc(kSpareMemSize);
  268.         
  269.     x->fError = kODNoError;
  270.     x->fODException = kODNULL;
  271.     x->fEv = kODNULL;
  272.     x->fDestructoList = kODNULL;
  273.     x->fPrev = gTopHandler;
  274.     gTopHandler = x;
  275.     return &x->fBuffer;
  276. }
  277.  
  278. jmp_buf* _xTryEv( ODExceptionFrame *x, Environment *ev )
  279. {
  280.     if( ! gSpareMem )
  281.         gSpareMem = SOMMalloc(kSpareMemSize);
  282.         
  283.     x->fError = kODNoError;
  284.     x->fODException = kODNULL;
  285.     x->fEv = ev;
  286.     x->fDestructoList = kODNULL;
  287.     x->fPrev = gTopHandler;
  288.     gTopHandler = x;
  289.     return &x->fBuffer;
  290. }
  291.  
  292. #endif /*_ASM_XTRY_*/
  293.  
  294.  
  295. static void
  296. _xPopCleanUp( ODExceptionFrame *x )
  297. {
  298.     // Subroutine called by _xPop to clean up the rare notrivial cases.
  299.     
  300.     WASSERT(x!=gTopHandler);
  301.     
  302.     if( x->fPrev == kAlreadyPoppedHandler )
  303.         // Do nothing if I was already popped by a THROW.
  304.         ;
  305.     else {
  306.         /*  At this point the astute reader will be wondering how a non-top
  307.             exception handler could be destructed first. Given correct inside-
  308.             out destruction of stack-based objects, this should never happen;
  309.             however, some compilers will mix up the order in certain cases.
  310.             Therefore we roll up our sleeves and prepare to destruct any
  311.             intervening handlers on the stack: */
  312.             
  313.         WARN("Destructing non-top excpt frame %p",x);
  314.         
  315.         ODExceptionFrame *e;
  316.         for( e=gTopHandler; e && e->fPrev!=x; e=e->fPrev )
  317.             ;
  318.         if( e==kODNULL )
  319.             WARN("Excpt frame %p not found on stack!",x);
  320.         else
  321.             e->fPrev = x->fPrev;
  322.     }
  323.     
  324.     /*    If exiting a SOM_TRY handler with an error, store it in the Environment: */
  325.     if( x->fEv ) {
  326.         if( x->fODException ) {
  327.             somSetException(x->fEv,USER_EXCEPTION,ex_ODException,x->fODException);
  328.             x->fODException = kODNULL;
  329.         } else if( x->fError )
  330.             ODSetSOMException(x->fEv,x->fError);
  331.     }
  332. }
  333.  
  334.  
  335. #ifdef _ASM_XTRY_
  336.  
  337. /*    _xPop has been optimized in PPC assembly. In the common case of a normal exit,
  338.     all it has to do is pop the exception stack and return. No stack frame is needed.
  339.     This version allocates a stack frame only for the less common cases.
  340. */
  341.  
  342. const char *const kex_ODException = ex_ODException;
  343.  
  344. asm void _xPop( register ODExceptionFrame *x )
  345. {
  346.     lwz        r0,gTopHandler
  347.     lwz        r4,x->fPrev
  348.     cmplw    r0,x
  349.     bne-    @4                    // Uncommon case, punt to _xPopCleanUp
  350.     
  351.     lwz        r0,x->fEv
  352.     stw        r4,gTopHandler        // Common case: pop top handler
  353.     
  354.     cmpwi    r0,0
  355.     beqlr                        // Just return if no fEv
  356.     lwz        r0,x->fODException
  357.     lwz        r4,x->fError
  358.     cmpwi    r0,0
  359.     bne-    @1
  360.     cmpwi    r4,0
  361.     beqlr                        // Return if no fODException or fError
  362.     
  363. @1:    mflr    r0                    // Otherwise need to call some fns,
  364.     stw        r31,-4(sp)            // so build a stack frame
  365.     stw        r0,8(sp)
  366.     stwu    sp,-64(sp)
  367.     mr        r31,r3                    // not strictly necessary
  368.     
  369.     lwz        r6,x->fODException
  370.     lwz        r3,x->fEv            // Now can no longer use "x" (we've overwritten r3)
  371.     
  372.     cmpwi    r6,0
  373.     beq        @2
  374.     
  375.     lwz        r5,kex_ODException    // This is the "if x->fODException" clause:
  376.     li        r4,1
  377.     bl        somSetException
  378.     nop
  379.     li        r0,0
  380.     stw        r0,4(r31)            // x->fODException = NULL
  381.     b        @3
  382.     
  383. @2:    li        r5,0                // This is the "if x->fError" clause:
  384.     b        ODSetSOMException    // (r4 still contains x->fError)
  385.     
  386. @3:    lwz        r0,72(sp)            // Finally destroy stack frame and return
  387.     addi    sp,sp,64
  388.     mtlr    r0
  389.     lwz        r31,-4(sp)
  390.     blr
  391.  
  392. @4:    b        _xPopCleanUp
  393. }
  394.  
  395. #else /*not _ASM_XTRY_*/
  396.  
  397. void _xPop( ODExceptionFrame *x )
  398. {
  399.     if( gTopHandler == x )
  400.         // Remove myself from the stack if (a) I'm at ENDTRY and no exception was thrown,
  401.         // or (b) someone exited (probably via 'return') from within the TRY block:
  402.         gTopHandler = x->fPrev;
  403.         
  404.     else
  405.         _xPopCleanUp(x);
  406.     
  407.     if( x->fODException ) {
  408.         SOMFree(x->fODException);
  409.         if( ! gSpareMem )
  410.             gSpareMem = SOMMalloc(kSpareMemSize);
  411.     }
  412. }
  413.  
  414. #endif /*_ASM_XTRY_*/
  415.  
  416.  
  417. void
  418. ODExceptionFrame::Throw( ODError err, const char* msg, ODException *x )
  419. {
  420.     if( err == kODNoError ) {
  421.         WARN("Do not call THROW(0)!");
  422.         return;
  423.     }
  424.         
  425.     WASSERT(this==gTopHandler);
  426.  
  427.     // Call the destructor of each of my destructos:
  428.     for( Destructo *d=fDestructoList; d; d=d->EmergencyDestruct() )
  429.         ;
  430.     
  431.     gTopHandler = fPrev;                // Pop the exception handler
  432.     fPrev = kAlreadyPoppedHandler;
  433.     
  434.     // Store error info in this handler. If there's a message, need to copy
  435.     // it into an ODException structure if possible:
  436.     fError = err;
  437.     if( x )
  438.         fODException = x;
  439.     else if( msg && msg[0]!='\0' )
  440.         fODException = NewODException(err,msg);
  441.     else
  442.         fODException = kODNULL;
  443.     
  444.     longjmp(fBuffer,1);                    // SHAZAM!
  445. }
  446.  
  447.  
  448. void
  449. _xReraise( ODExceptionFrame *xf )
  450. {
  451. #if ODDebug
  452.     if( gTopHandler==xf )
  453.         BREAK("Reraise called on active exception handler!");
  454.     // Not fatal but probably a mistaken usage of RERAISE.
  455. #endif
  456.  
  457.     if( xf->fEv ) {
  458.         WARN("RERAISE in SOM_CATCH_ALL block is illegal");
  459.         return;
  460.     }
  461.     
  462.     WASSERTM(xf->fError!=kODNoError,"RERAISE called with no exception");
  463.     
  464.     // Throw the exception, re-using the ODException if possible:
  465.     if( gTopHandler ==kODNULL )
  466.         BREAK("No handler to CATCH exception!!");
  467.     else {
  468.         ODException *x = xf->fODException;
  469.         xf->fODException = kODNULL;
  470.         gTopHandler->Throw(xf->fError,kODNULL,x);
  471.     }
  472. }
  473.  
  474.  
  475. void
  476. _xSetErrorCode( ODExceptionFrame *xf, ODError err )
  477. {
  478.     xf->fError = err;
  479.     if( err ) {
  480.         if( xf->fODException )
  481.             xf->fODException->error = err;
  482.     } else {
  483.         SOMFree(xf->fODException);
  484.         xf->fODException = kODNULL;
  485.     }
  486. }
  487.  
  488.  
  489. void
  490. _xSetErrorMessage( ODExceptionFrame *xf, const char *message )
  491. {
  492.     if( message && message[0]!='\0' ) {
  493.         ODException *x = NewODException(xf->fError,message);
  494.         if( x ) {
  495.             SOMFree(xf->fODException);
  496.             xf->fODException = x;
  497.         }
  498.     } else {
  499.         SOMFree(xf->fODException);
  500.         xf->fODException = kODNULL;
  501.     }
  502. }
  503.  
  504.  
  505. //=================================================================================== 
  506. // Destructo class
  507. //=================================================================================== 
  508.  
  509.  
  510. #define kIWuzDestructed ((Destructo*)0xDEADBEEF)
  511. #define kEmergencyDestructing    ((Destructo*)0xFADEBABE)
  512.  
  513.  
  514. Destructo::Destructo( )
  515. {
  516.     /* Constructor adds me to the current exception frame's destructo list. */
  517.     if( gTopHandler ) {
  518.         fPrevDestructo = gTopHandler->fDestructoList;
  519.         gTopHandler->fDestructoList = this;
  520.     } else
  521.         fPrevDestructo = kODNULL;
  522. }
  523.  
  524.  
  525. Destructo::~Destructo( )
  526. {
  527.     /*    Destructor removes me from the owner's destructo list, except during
  528.         an emergency destruct while an exception is being thrown; in that case
  529.         the exception handler takes care of that bit itself. */
  530.         
  531.     if( fPrevDestructo != kEmergencyDestructing ) {
  532. #if ODDebug
  533.     if( fPrevDestructo==kIWuzDestructed ) {
  534.         WARN("Destructo %p being destructed twice!",this);
  535.         return;
  536.     }
  537. #endif
  538.     if( gTopHandler ) {
  539.         if( gTopHandler->fDestructoList == this )
  540.             gTopHandler->fDestructoList = fPrevDestructo;
  541.         else
  542.             WARN("Destructo %p being destructed is not top of list",this);
  543.     }
  544.     }
  545.     
  546. #if ODDebug
  547.     fPrevDestructo = kIWuzDestructed;
  548. #endif
  549. }
  550.  
  551.  
  552. Destructo*
  553. Destructo::EmergencyDestruct( )
  554. {
  555.     /*    My owner is _not_ the top handler right now, because it's destructing me in
  556.         a nested TRY block. Jam a special marker into fPrevDestructo to tell my
  557.         destructor not to mess with the Destructo chain; then return the next
  558.         destructo in the chain to help the handler walk it. */
  559.     
  560.     Destructo *prev = fPrevDestructo;
  561. #if ODDebug
  562.     if( prev==kIWuzDestructed ) {
  563.         WARN("Destructo %p being emergency-destructed twice!",this);
  564.         return kODNULL;
  565.     }
  566. #endif
  567.  
  568.     fPrevDestructo = kEmergencyDestructing;
  569.     TRY{
  570.         this->~Destructo();
  571.     }CATCH_ALL{
  572.         // Ignore the nested exception.
  573.     }ENDTRY
  574.     return prev;
  575. }
  576.  
  577.  
  578. #endif /*not _NATIVE_EXCEPTIONS_*/
  579.  
  580.  
  581. //=================================================================================== 
  582. // THROW, et al
  583. //=================================================================================== 
  584.  
  585.  
  586. static void
  587. DoThrow( ODError err, const char* msg, ODException *x = kODNULL )
  588. {
  589.     if( err == kODNoError ) {
  590.         WARN("Do not call THROW(0)!");
  591.         return;
  592.     }
  593.             
  594. #if ODDebug
  595.     // Dump useful into to stdout or MacsBug. Ignore AE coercion-failure error
  596.     // (-1700 == errAECoercionFail) since it happens as part of normal operation.
  597.     
  598.     if( (GetOutputMode() != kNoOutput || gBreakOnThrow)
  599.                 && err!=-1700 && err!=-1708 ) {                // Skip noise AE errors
  600.         char caller[256];
  601.         #ifndef DONT_USE_STACKCRAWL
  602.             if( ! ODHaveFreeSpace(1024,1024) )
  603.                 strcpy(caller,"??(low mem)??");
  604.             else {
  605.                 StackCrawl *sc = StackCrawl::New(2,2);
  606.                 sc->GetFrameName(0,caller);
  607.                 delete sc;
  608.             }
  609.         
  610.             if( GetOutputMode() != kNoOutput ) {
  611.                 if( msg )
  612.                     somPrintf("** THROW(%d) called by %s\n", err,caller);
  613.                 else
  614.                     somPrintf("** THROW(%d,%s) called by %s\n", err,msg,caller);
  615.                 if( ODHaveFreeSpace(1024,1024) ) {
  616.                     StackCrawl *s = StackCrawl::New(2,-5);
  617.                     if( s ) {
  618.                         for( long i=0; i<s->CountFrames(); i++ ) {
  619.                             char name[256];
  620.                             s->GetFrameName(i,name);
  621.                             somPrintf("        %s\n",name);
  622.                         }
  623.                         delete s;
  624.                     }
  625.                 }
  626.             }
  627.         #else
  628.             strcpy(caller,"????");
  629.         #endif
  630.         
  631.         if( gBreakOnThrow )
  632.             if( msg )
  633.                 WARN("THROW(%ld,%s) called by %s", err,msg,caller);
  634.             else
  635.                 WARN("THROW(%ld) called by %s", err,caller);
  636.     }
  637. #endif
  638.  
  639. #ifdef _NATIVE_EXCEPTIONS_
  640.     if( x )
  641.         throw(*x);
  642.     else {
  643.         ODException exc;
  644.         InitODException(&exc, err,msg,256);
  645.         throw(exc);
  646.     }
  647. #else
  648.     if( gTopHandler ==kODNULL )
  649.         BREAK("No handler to CATCH exception!!");
  650.     else
  651.         gTopHandler->Throw(err,msg,x);
  652. #endif
  653. }
  654.  
  655.  
  656.  
  657. void
  658. THROW( ODError err )
  659. {
  660.     DoThrow(err,kODNULL);
  661. }
  662.  
  663.  
  664. void
  665. THROW_IF_ERROR( ODError err )
  666. {
  667.     if( err != 0 )
  668.         DoThrow(err,kODNULL);
  669. }
  670.  
  671.  
  672. void
  673. THROW_IF_NULL( void* value )
  674. {
  675.     if( value == kODNULL )
  676.         DoThrow(kODErrOutOfMemory,kODNULL);
  677. }
  678.  
  679.  
  680. #if ODDebug
  681. void
  682. THROW_IF_ERROR_M( ODError err, const char *msg )
  683. {
  684.     if( err != 0 )
  685.         DoThrow(err,msg);
  686. }
  687.  
  688. void
  689. THROW_M( ODError err, const char* msg )
  690. {
  691.     DoThrow(err,msg);
  692. }
  693.  
  694. void
  695. THROW_IF_NULL_M( void* value, const char* msg )
  696. {
  697.     if( value == kODNULL )
  698.         DoThrow(kODErrOutOfMemory,msg);
  699. }
  700. #endif /*ODDebug*/
  701.  
  702.  
  703. //=================================================================================== 
  704. // SOM EXCEPTIONS
  705. //===================================================================================
  706.  
  707.  
  708. void
  709. ODSetSOMException( Environment *ev, ODError error, const char *message /*=NULL*/ )
  710. {
  711.     if( error ) {
  712.         ODException *x = NewODException(error,message);
  713.             SOMFree(gSpareMem);                            // Get some slack
  714.             somSetException(ev,USER_EXCEPTION,ex_ODException,x);
  715.             gSpareMem = SOMMalloc(kSpareMemSize);        // Tighten up
  716.     } else {
  717.         somExceptionFree(ev);
  718.         ev->_major = NO_EXCEPTION;
  719.     }
  720. }
  721.  
  722.  
  723. #ifdef _NATIVE_EXCEPTIONS_
  724. void
  725. ODSetSOMException( Environment *ev, ODException &except )
  726. {
  727.     ODSetSOMException(ev,except.error,except.message);
  728. }
  729.  
  730. EVSetter::~EVSetter( )
  731. {
  732.     ODSetSOMException(fEv,fEx);
  733. }
  734.  
  735. #else
  736.  
  737. void
  738. _xSetSOMException( Environment *ev, ODExceptionFrame *x )
  739. {
  740.     if( !x->fEv ) {                        // Ignore this in a SOM_TRY block
  741.         if( x->fODException ) {
  742.             SOMFree(gSpareMem);                            // Get some slack
  743.             somSetException(x->fEv,USER_EXCEPTION,ex_ODException,x->fODException);
  744.             gSpareMem = SOMMalloc(kSpareMemSize);        // Tighten up
  745.             x->fODException = kODNULL;
  746.         } else if( x->fError )
  747.             ODSetSOMException(x->fEv,x->fError);
  748.     }
  749. }
  750.  
  751. #endif
  752.  
  753.  
  754. ODError
  755. ODGetSOMException( Environment *ev )
  756. {
  757.     if( ev->_major ) {
  758.         const char *excpName = somExceptionId(ev);
  759.         if( strcmp(excpName,ex_ODException) == 0 ) {
  760.             ODException *x = (ODException*)somExceptionValue(ev);
  761.             return x->error;
  762.         } else {
  763.             WARN("Env has non-OpenDoc err: %s",excpName);
  764.             return kODErrSOMException;
  765.         }
  766.     } else
  767.         return kODNoError;
  768. }
  769.  
  770.  
  771. /*    As an optimization, CHECK_ENV does preflighting in assembly if inline assembly
  772.     is available. CHECK_ENV itself is defined as a stub that quickly checks whether
  773.     an error condition is present and returns if all is well. Otherwise it jumps
  774.     to the real CHECK_ENV (which is renamed _do_CHECK_ENV).
  775.     This avoids the overhead of creating & tearing down a stack frame in the
  776.     overwhelmingly common case of no error.
  777. */
  778.  
  779. #if defined(__MWERKS__) && __MWERKS__>0x0800 //&& GENERATINGPOWERPC
  780. static void
  781. _do_CHECK_ENV( Environment *ev )
  782. #else
  783. void
  784. CHECK_ENV( Environment *ev )
  785. #endif
  786. {
  787.     if( ev->_major ) {
  788.         const char *excpName = somExceptionId(ev);
  789.         if( strcmp(excpName,ex_ODException) == 0 ) {
  790.             ODException x = *(ODException*)somExceptionValue(ev);
  791.             somExceptionFree(ev);
  792.             ev->_major = NO_EXCEPTION;
  793.             DoThrow(x.error, x.message);
  794.         } else {
  795.             WARN("Env has non-OpenDoc err: %s",excpName);
  796.             somExceptionFree(ev);
  797.             ev->_major = NO_EXCEPTION;
  798.             DoThrow(kODErrSOMException,kODNULL);
  799.         }
  800.     }
  801. }
  802.  
  803.  
  804. #if defined(__MWERKS__) && __MWERKS__>0x0800 //&& GENERATINGPOWERPC
  805. asm void
  806. CHECK_ENV( register Environment *ev )
  807. {
  808. #if GENERATINGPOWERPC
  809.     lwz        r4, 0(r3)
  810.     cmpwi    r4, 0
  811.     beqlr
  812.     b        _do_CHECK_ENV
  813. #else
  814.     movea.l    4(a7),a0
  815.     tst.l    (a0)
  816.     bne        _do_CHECK_ENV
  817.     rtd        #4
  818. #endif
  819. }
  820. #endif