Back to index

lightning-sunbird  0.9+nobinonly
morkNode.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-  */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #ifndef _MDB_
00039 #include "mdb.h"
00040 #endif
00041 
00042 #ifndef _MORK_
00043 #include "mork.h"
00044 #endif
00045 
00046 #ifndef _MORKNODE_
00047 #include "morkNode.h"
00048 #endif
00049 
00050 #ifndef _MORKPOOL_
00051 #include "morkPool.h"
00052 #endif
00053 
00054 #ifndef _MORKENV_
00055 #include "morkEnv.h"
00056 #endif
00057 
00058 #ifndef _MORKHANDLE_
00059 #include "morkHandle.h"
00060 #endif
00061 
00062 /*3456789_123456789_123456789_123456789_123456789_123456789_123456789_12345678*/
00063 
00064 /* ===== ===== ===== ===== morkUsage ===== ===== ===== ===== */
00065 
00066 static morkUsage morkUsage_gHeap; // ensure EnsureReadyStaticUsage()
00067 const morkUsage& morkUsage::kHeap = morkUsage_gHeap;
00068 
00069 static morkUsage morkUsage_gStack; // ensure EnsureReadyStaticUsage()
00070 const morkUsage& morkUsage::kStack = morkUsage_gStack;
00071 
00072 static morkUsage morkUsage_gMember; // ensure EnsureReadyStaticUsage()
00073 const morkUsage& morkUsage::kMember = morkUsage_gMember;
00074 
00075 static morkUsage morkUsage_gGlobal; // ensure EnsureReadyStaticUsage()
00076 const morkUsage& morkUsage::kGlobal = morkUsage_gGlobal;
00077 
00078 static morkUsage morkUsage_gPool; // ensure EnsureReadyStaticUsage()
00079 const morkUsage& morkUsage::kPool = morkUsage_gPool;
00080 
00081 static morkUsage morkUsage_gNone; // ensure EnsureReadyStaticUsage()
00082 const morkUsage& morkUsage::kNone = morkUsage_gNone;
00083 
00084 // This must be structured to allow for non-zero values in global variables
00085 // just before static init time.  We can only safely check for whether a
00086 // global has the address of some other global.  Please, do not initialize
00087 // either of the variables below to zero, because this could break when a zero
00088 // is assigned at static init time, but after EnsureReadyStaticUsage() runs.
00089 
00090 static mork_u4 morkUsage_g_static_init_target; // only address of this matters
00091 static mork_u4* morkUsage_g_static_init_done; // is address of target above?
00092 
00093 #define morkUsage_do_static_init() \
00094   ( morkUsage_g_static_init_done = &morkUsage_g_static_init_target )
00095 
00096 #define morkUsage_need_static_init() \
00097   ( morkUsage_g_static_init_done != &morkUsage_g_static_init_target )
00098 
00099 /*static*/
00100 void morkUsage::EnsureReadyStaticUsage()
00101 {
00102   if ( morkUsage_need_static_init() )
00103   {
00104     morkUsage_do_static_init();
00105 
00106     morkUsage_gHeap.InitUsage(morkUsage_kHeap);
00107     morkUsage_gStack.InitUsage(morkUsage_kStack);
00108     morkUsage_gMember.InitUsage(morkUsage_kMember);
00109     morkUsage_gGlobal.InitUsage(morkUsage_kGlobal);
00110     morkUsage_gPool.InitUsage(morkUsage_kPool);
00111     morkUsage_gNone.InitUsage(morkUsage_kNone);
00112   }
00113 }
00114 
00115 /*static*/
00116 const morkUsage& morkUsage::GetHeap()   // kHeap safe at static init time
00117 {
00118   EnsureReadyStaticUsage();
00119   return morkUsage_gHeap;
00120 }
00121 
00122 /*static*/
00123 const morkUsage& morkUsage::GetStack()  // kStack safe at static init time
00124 {
00125   EnsureReadyStaticUsage();
00126   return morkUsage_gStack;
00127 }
00128 
00129 /*static*/
00130 const morkUsage& morkUsage::GetMember() // kMember safe at static init time
00131 {
00132   EnsureReadyStaticUsage();
00133   return morkUsage_gMember;
00134 }
00135 
00136 /*static*/
00137 const morkUsage& morkUsage::GetGlobal() // kGlobal safe at static init time
00138 {
00139   EnsureReadyStaticUsage();
00140   return morkUsage_gGlobal;
00141 }
00142 
00143 /*static*/
00144 const morkUsage& morkUsage::GetPool()  // kPool safe at static init time
00145 {
00146   EnsureReadyStaticUsage();
00147   return morkUsage_gPool;
00148 }
00149 
00150 /*static*/
00151 const morkUsage& morkUsage::GetNone()  // kNone safe at static init time
00152 {
00153   EnsureReadyStaticUsage();
00154   return morkUsage_gNone;
00155 }
00156 
00157 morkUsage::morkUsage()
00158 {
00159   if ( morkUsage_need_static_init() )
00160   {
00161     morkUsage::EnsureReadyStaticUsage();
00162   }
00163 }
00164 
00165 morkUsage::morkUsage(mork_usage code)
00166   : mUsage_Code(code)
00167 {
00168   if ( morkUsage_need_static_init() )
00169   {
00170     morkUsage::EnsureReadyStaticUsage();
00171   }
00172 }
00173 
00174 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
00175 
00176 /*static*/ void*
00177 morkNode::MakeNew(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev)
00178 {
00179   void* node = 0;
00180   if ( &ioHeap )
00181   {
00182     ioHeap.Alloc(ev->AsMdbEnv(), inSize, (void **) &node);
00183     if ( !node )
00184       ev->OutOfMemoryError();
00185   }
00186   else
00187     ev->NilPointerError();
00188   
00189   return node;
00190 }
00191 
00192 /*public non-poly*/ void
00193 morkNode::ZapOld(morkEnv* ev, nsIMdbHeap* ioHeap)
00194 {
00195   if ( this )
00196   {
00197     if ( this->IsNode() )
00198     {
00199       mork_usage usage = mNode_Usage; // mNode_Usage before ~morkNode
00200       this->morkNode::~morkNode(); // first call polymorphic destructor
00201       if ( ioHeap ) // was this node heap allocated?
00202         ioHeap->Free(ev->AsMdbEnv(), this);
00203       else if ( usage == morkUsage_kPool ) // mNode_Usage before ~morkNode
00204       {
00205         morkHandle* h = (morkHandle*) this;
00206         if ( h->IsHandle() && h->GoodHandleTag() )
00207         {
00208           if ( h->mHandle_Face )
00209           {
00210             if (ev->mEnv_HandlePool)
00211               ev->mEnv_HandlePool->ZapHandle(ev, h->mHandle_Face);
00212             else if (h->mHandle_Env && h->mHandle_Env->mEnv_HandlePool)
00213               h->mHandle_Env->mEnv_HandlePool->ZapHandle(ev, h->mHandle_Face);
00214           }
00215           else
00216             ev->NilPointerError();
00217         }
00218       }
00219     }
00220     else
00221       this->NonNodeError(ev);
00222   }
00223   else
00224     ev->NilPointerError();
00225 }
00226 
00227 /*public virtual*/ void
00228 morkNode::CloseMorkNode(morkEnv* ev) // CloseNode() only if open
00229 {
00230   if ( this->IsOpenNode() )
00231   {
00232     this->MarkClosing();
00233     this->CloseNode(ev);
00234     this->MarkShut();
00235   }
00236 }
00237 NS_IMETHODIMP
00238 morkNode::CloseMdbObject(nsIMdbEnv* mev)
00239 {
00240   return morkNode::CloseMdbObject((morkEnv *) mev);
00241 }
00242 
00243 mdb_err morkNode::CloseMdbObject(morkEnv *ev)
00244 {
00245   // if only one ref, Handle_CutStrongRef will clean up better.
00246   if (mNode_Uses == 1)
00247     return CutStrongRef(ev);
00248 
00249   mdb_err outErr = 0;
00250   
00251   if ( IsNode() && IsOpenNode() )
00252   {
00253     if ( ev )
00254     {
00255       CloseMorkNode(ev);
00256       outErr = ev->AsErr();
00257     }
00258   }
00259   return outErr;
00260 }
00261 
00262 /*public virtual*/
00263 morkNode::~morkNode() // assert that CloseNode() executed earlier
00264 {
00265   MORK_ASSERT(this->IsShutNode() || IsDeadNode()); // sometimes we call destructor explictly w/o freeing object.
00266   mNode_Access = morkAccess_kDead;
00267   mNode_Usage = morkUsage_kNone;
00268 }
00269 
00270 /*public virtual*/
00271 // void CloseMorkNode(morkEnv* ev) = 0; // CloseNode() only if open
00272   // CloseMorkNode() is the polymorphic close method called when uses==0,
00273   // which must do NOTHING at all when IsOpenNode() is not true.  Otherwise,
00274   // CloseMorkNode() should call a static close method specific to an object.
00275   // Each such static close method should either call inherited static close
00276   // methods, or else perform the consolidated effect of calling them, where
00277   // subclasses should closely track any changes in base classes with care.
00278   
00279 
00280 /*public non-poly*/
00281 morkNode::morkNode( mork_usage inCode )
00282 : mNode_Heap( 0 )
00283 , mNode_Base( morkBase_kNode )
00284 , mNode_Derived ( 0 ) // until subclass sets appropriately
00285 , mNode_Access( morkAccess_kOpen )
00286 , mNode_Usage( inCode )
00287 , mNode_Mutable( morkAble_kEnabled )
00288 , mNode_Load( morkLoad_kClean )
00289 , mNode_Uses( 1 )
00290 , mNode_Refs( 1 )
00291 {
00292 }
00293 
00294 /*public non-poly*/
00295 morkNode::morkNode(const morkUsage& inUsage, nsIMdbHeap* ioHeap)
00296 : mNode_Heap( ioHeap )
00297 , mNode_Base( morkBase_kNode )
00298 , mNode_Derived ( 0 ) // until subclass sets appropriately
00299 , mNode_Access( morkAccess_kOpen )
00300 , mNode_Usage( inUsage.Code() )
00301 , mNode_Mutable( morkAble_kEnabled )
00302 , mNode_Load( morkLoad_kClean )
00303 , mNode_Uses( 1 )
00304 , mNode_Refs( 1 )
00305 {
00306   if ( !ioHeap && mNode_Usage == morkUsage_kHeap )
00307     MORK_ASSERT(ioHeap);
00308 }
00309 
00310 /*public non-poly*/
00311 morkNode::morkNode(morkEnv* ev,
00312   const morkUsage& inUsage, nsIMdbHeap* ioHeap)
00313 : mNode_Heap( ioHeap )
00314 , mNode_Base( morkBase_kNode )
00315 , mNode_Derived ( 0 ) // until subclass sets appropriately
00316 , mNode_Access( morkAccess_kOpen )
00317 , mNode_Usage( inUsage.Code() )
00318 , mNode_Mutable( morkAble_kEnabled )
00319 , mNode_Load( morkLoad_kClean )
00320 , mNode_Uses( 1 )
00321 , mNode_Refs( 1 )
00322 {
00323   if ( !ioHeap && mNode_Usage == morkUsage_kHeap )
00324   {
00325     this->NilHeapError(ev);
00326   }
00327 }
00328 
00329 /*protected non-poly*/ void
00330 morkNode::RefsUnderUsesWarning(morkEnv* ev) const 
00331 {
00332   ev->NewError("mNode_Refs < mNode_Uses");
00333 }
00334 
00335 /*protected non-poly*/ void
00336 morkNode::NonNodeError(morkEnv* ev) const // called when IsNode() is false
00337 {
00338   ev->NewError("non-morkNode");
00339 }
00340 
00341 /*protected non-poly*/ void
00342 morkNode::NonOpenNodeError(morkEnv* ev) const // when IsOpenNode() is false
00343 {
00344   ev->NewError("non-open-morkNode");
00345 }
00346 
00347 /*protected non-poly*/ void
00348 morkNode::NonMutableNodeError(morkEnv* ev) const // when IsMutable() is false
00349 {
00350   ev->NewError("non-mutable-morkNode");
00351 }
00352 
00353 /*protected non-poly*/ void
00354 morkNode::NilHeapError(morkEnv* ev) const // zero mNode_Heap w/ kHeap usage
00355 {
00356   ev->NewError("nil mNode_Heap");
00357 }
00358 
00359 /*protected non-poly*/ void
00360 morkNode::RefsOverflowWarning(morkEnv* ev) const // mNode_Refs overflow
00361 {
00362   ev->NewWarning("mNode_Refs overflow");
00363 }
00364 
00365 /*protected non-poly*/ void
00366 morkNode::UsesOverflowWarning(morkEnv* ev) const // mNode_Uses overflow
00367 {
00368   ev->NewWarning("mNode_Uses overflow");
00369 }
00370 
00371 /*protected non-poly*/ void
00372 morkNode::RefsUnderflowWarning(morkEnv* ev) const // mNode_Refs underflow
00373 {
00374   ev->NewWarning("mNode_Refs underflow");
00375 }
00376 
00377 /*protected non-poly*/ void
00378 morkNode::UsesUnderflowWarning(morkEnv* ev) const // mNode_Uses underflow
00379 {
00380   ev->NewWarning("mNode_Uses underflow");
00381 }
00382 
00383 /*public non-poly*/ void
00384 morkNode::CloseNode(morkEnv* ev) // called by CloseMorkNode();
00385 {
00386   if ( this )
00387   {
00388     if ( this->IsNode() )
00389       this->MarkShut();
00390     else
00391       this->NonNodeError(ev);
00392   }
00393   else
00394     ev->NilPointerError();
00395 }
00396 
00397 
00398 extern void // utility method very similar to morkNode::SlotStrongNode():
00399 nsIMdbCompare_SlotStrongCompare(nsIMdbCompare* self, morkEnv* ev,
00400   nsIMdbCompare** ioSlot)
00401   // If *ioSlot is non-nil, that compare is released by CutStrongRef() and
00402   // then zeroed out.  Then if self is non-nil, this is acquired by
00403   // calling AddStrongRef(), and if the return value shows success,
00404   // then self is put into slot *ioSlot.  Note self can be nil, so we take
00405   // expression 'nsIMdbCompare_SlotStrongCompare(0, ev, &slot)'.
00406 {
00407   nsIMdbEnv* menv = ev->AsMdbEnv();
00408   nsIMdbCompare* compare = *ioSlot;
00409   if ( self != compare )
00410   {
00411     if ( compare )
00412     {
00413       *ioSlot = 0;
00414       compare->CutStrongRef(menv);
00415     }
00416     if ( self && ev->Good() && (self->AddStrongRef(menv)==0) && ev->Good() )
00417       *ioSlot = self;
00418   }
00419 }
00420 
00421 
00422 extern void // utility method very similar to morkNode::SlotStrongNode():
00423 nsIMdbFile_SlotStrongFile(nsIMdbFile* self, morkEnv* ev, nsIMdbFile** ioSlot)
00424   // If *ioSlot is non-nil, that file is released by CutStrongRef() and
00425   // then zeroed out.  Then if self is non-nil, this is acquired by
00426   // calling AddStrongRef(), and if the return value shows success,
00427   // then self is put into slot *ioSlot.  Note self can be nil, so we take
00428   // expression 'nsIMdbFile_SlotStrongFile(0, ev, &slot)'.
00429 {
00430   nsIMdbFile* file = *ioSlot;
00431   if ( self != file )
00432   {
00433     if ( file )
00434     {
00435       *ioSlot = 0;
00436       NS_RELEASE(file);
00437     }
00438     if ( self && ev->Good() && (NS_ADDREF(self)>=0) && ev->Good() )
00439       *ioSlot = self;
00440   }
00441 }
00442   
00443 void // utility method very similar to morkNode::SlotStrongNode():
00444 nsIMdbHeap_SlotStrongHeap(nsIMdbHeap* self, morkEnv* ev, nsIMdbHeap** ioSlot)
00445   // If *ioSlot is non-nil, that heap is released by CutStrongRef() and
00446   // then zeroed out.  Then if self is non-nil, self is acquired by
00447   // calling AddStrongRef(), and if the return value shows success,
00448   // then self is put into slot *ioSlot.  Note self can be nil, so we
00449   // permit expression 'nsIMdbHeap_SlotStrongHeap(0, ev, &slot)'.
00450 {
00451   nsIMdbEnv* menv = ev->AsMdbEnv();
00452   nsIMdbHeap* heap = *ioSlot;
00453   if ( self != heap )
00454   {
00455     if ( heap )
00456     {
00457       *ioSlot = 0;
00458       heap->HeapCutStrongRef(menv);
00459     }
00460     if ( self && ev->Good() && (self->HeapAddStrongRef(menv)==0) && ev->Good() )
00461       *ioSlot = self;
00462   }
00463 }
00464 
00465 /*public static*/ void
00466 morkNode::SlotStrongNode(morkNode* me, morkEnv* ev, morkNode** ioSlot)
00467   // If *ioSlot is non-nil, that node is released by CutStrongRef() and
00468   // then zeroed out.  Then if me is non-nil, this is acquired by
00469   // calling AddStrongRef(), and if positive is returned to show success,
00470   // then me is put into slot *ioSlot.  Note me can be nil, so we take
00471   // expression 'morkNode::SlotStrongNode((morkNode*) 0, ev, &slot)'.
00472 {
00473   morkNode* node = *ioSlot;
00474   if ( me != node )
00475   {
00476     if ( node )
00477     {
00478       // what if this nulls out the ev and causes asserts?
00479       // can we move this after the CutStrongRef()?
00480       *ioSlot = 0;
00481       node->CutStrongRef(ev);
00482     }
00483     if ( me && me->AddStrongRef(ev) )
00484       *ioSlot = me;
00485   }
00486 }
00487 
00488 /*public static*/ void
00489 morkNode::SlotWeakNode(morkNode* me, morkEnv* ev, morkNode** ioSlot)
00490   // If *ioSlot is non-nil, that node is released by CutWeakRef() and
00491   // then zeroed out.  Then if me is non-nil, this is acquired by
00492   // calling AddWeakRef(), and if positive is returned to show success,
00493   // then me is put into slot *ioSlot.  Note me can be nil, so we
00494   // expression 'morkNode::SlotWeakNode((morkNode*) 0, ev, &slot)'.
00495 {
00496   morkNode* node = *ioSlot;
00497   if ( me != node )
00498   {
00499     if ( node )
00500     {
00501       *ioSlot = 0;
00502       node->CutWeakRef(ev);
00503     }
00504     if ( me && me->AddWeakRef(ev) )
00505       *ioSlot = me;
00506   }
00507 }
00508 
00509 /*public non-poly*/ mork_uses
00510 morkNode::AddStrongRef(morkEnv* ev)
00511 {
00512   mork_uses outUses = 0;
00513   if ( this )
00514   {
00515     if ( this->IsNode() )
00516     {
00517       mork_uses uses = mNode_Uses;
00518       mork_refs refs = mNode_Refs;
00519       if ( refs < uses ) // need to fix broken refs/uses relation?
00520       { 
00521         this->RefsUnderUsesWarning(ev);
00522         mNode_Refs = mNode_Uses = refs = uses;
00523       }
00524       if ( refs < morkNode_kMaxRefCount ) // not too great?
00525       {
00526         mNode_Refs = ++refs;
00527         mNode_Uses = ++uses;
00528       }
00529       else
00530         this->RefsOverflowWarning(ev);
00531 
00532       outUses = uses;
00533     }
00534     else
00535       this->NonNodeError(ev);
00536   }
00537   else
00538     ev->NilPointerError();
00539   return outUses;
00540 }
00541 
00542 /*private non-poly*/ mork_bool
00543 morkNode::cut_use_count(morkEnv* ev) // just one part of CutStrongRef()
00544 {
00545   mork_bool didCut = morkBool_kFalse;
00546   if ( this )
00547   {
00548     if ( this->IsNode() )
00549     {
00550       mork_uses uses = mNode_Uses;
00551       if ( uses ) // not yet zero?
00552         mNode_Uses = --uses;
00553       else
00554         this->UsesUnderflowWarning(ev);
00555 
00556       didCut = morkBool_kTrue;
00557       if ( !mNode_Uses ) // last use gone? time to close node?
00558       {
00559         if ( this->IsOpenNode() )
00560         {
00561           if ( !mNode_Refs ) // no outstanding reference?
00562           {
00563             this->RefsUnderflowWarning(ev);
00564             ++mNode_Refs; // prevent potential crash during close
00565           }
00566           this->CloseMorkNode(ev); // polymorphic self close
00567           // (Note CutNode() is not polymorphic -- so don't call that.)
00568         }
00569       }
00570     }
00571     else
00572       this->NonNodeError(ev);
00573   }
00574   else
00575     ev->NilPointerError();
00576   return didCut;
00577 }
00578 
00579 /*public non-poly*/ mork_uses
00580 morkNode::CutStrongRef(morkEnv* ev)
00581 {
00582   mork_refs outRefs = 0;
00583   if ( this )
00584   {
00585     if ( this->IsNode() )
00586     {
00587       if ( this->cut_use_count(ev) )
00588         outRefs = this->CutWeakRef(ev);
00589     }
00590     else
00591       this->NonNodeError(ev);
00592   }
00593   else
00594     ev->NilPointerError();
00595   return outRefs;
00596 }
00597 
00598 /*public non-poly*/ mork_refs
00599 morkNode::AddWeakRef(morkEnv* ev)
00600 {
00601   mork_refs outRefs = 0;
00602   if ( this )
00603   {
00604     if ( this->IsNode() )
00605     {
00606       mork_refs refs = mNode_Refs;
00607       if ( refs < morkNode_kMaxRefCount ) // not too great?
00608         mNode_Refs = ++refs;
00609       else
00610         this->RefsOverflowWarning(ev);
00611         
00612       outRefs = refs;
00613     }
00614     else
00615       this->NonNodeError(ev);
00616   }
00617   else
00618     ev->NilPointerError();
00619   return outRefs;
00620 }
00621 
00622 /*public non-poly*/ mork_refs
00623 morkNode::CutWeakRef(morkEnv* ev)
00624 {
00625   mork_refs outRefs = 0;
00626   if ( this )
00627   {
00628     if ( this->IsNode() )
00629     {
00630       mork_uses uses = mNode_Uses;
00631       mork_refs refs = mNode_Refs;
00632       if ( refs ) // not yet zero?
00633         mNode_Refs = --refs;
00634       else
00635         this->RefsUnderflowWarning(ev);
00636 
00637       if ( refs < uses ) // need to fix broken refs/uses relation?
00638       { 
00639         this->RefsUnderUsesWarning(ev);
00640         mNode_Refs = mNode_Uses = refs = uses;
00641       }
00642         
00643       outRefs = refs;
00644       if ( !refs ) // last reference gone? time to destroy node?
00645         this->ZapOld(ev, mNode_Heap); // self destroy, use this no longer
00646     }
00647     else
00648       this->NonNodeError(ev);
00649   }
00650   else
00651     ev->NilPointerError();
00652   return outRefs;
00653 }
00654 
00655 static const char morkNode_kBroken[] = "broken";
00656 
00657 /*public non-poly*/ const char*
00658 morkNode::GetNodeAccessAsString() const // e.g. "open", "shut", etc.
00659 {
00660   const char* outString = morkNode_kBroken;
00661   switch( mNode_Access )
00662   {
00663     case morkAccess_kOpen: outString = "open"; break;
00664     case morkAccess_kClosing: outString = "closing"; break;
00665     case morkAccess_kShut: outString = "shut"; break;
00666     case morkAccess_kDead: outString = "dead"; break;
00667   }
00668   return outString;
00669 }
00670 
00671 /*public non-poly*/ const char*
00672 morkNode::GetNodeUsageAsString() const // e.g. "heap", "stack", etc.
00673 {
00674   const char* outString = morkNode_kBroken;
00675   switch( mNode_Usage )
00676   {
00677     case morkUsage_kHeap: outString = "heap"; break;
00678     case morkUsage_kStack: outString = "stack"; break;
00679     case morkUsage_kMember: outString = "member"; break;
00680     case morkUsage_kGlobal: outString = "global"; break;
00681     case morkUsage_kPool: outString = "pool"; break;
00682     case morkUsage_kNone: outString = "none"; break;
00683   }
00684   return outString;
00685 }
00686 
00687 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789