1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1999
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
59 #include "morkHandle.h"
62 /*3456789_123456789_123456789_123456789_123456789_123456789_123456789_12345678*/
64 /* ===== ===== ===== ===== morkUsage ===== ===== ===== ===== */
66 static morkUsage morkUsage_gHeap
; // ensure EnsureReadyStaticUsage()
67 const morkUsage
& morkUsage::kHeap
= morkUsage_gHeap
;
69 static morkUsage morkUsage_gStack
; // ensure EnsureReadyStaticUsage()
70 const morkUsage
& morkUsage::kStack
= morkUsage_gStack
;
72 static morkUsage morkUsage_gMember
; // ensure EnsureReadyStaticUsage()
73 const morkUsage
& morkUsage::kMember
= morkUsage_gMember
;
75 static morkUsage morkUsage_gGlobal
; // ensure EnsureReadyStaticUsage()
76 const morkUsage
& morkUsage::kGlobal
= morkUsage_gGlobal
;
78 static morkUsage morkUsage_gPool
; // ensure EnsureReadyStaticUsage()
79 const morkUsage
& morkUsage::kPool
= morkUsage_gPool
;
81 static morkUsage morkUsage_gNone
; // ensure EnsureReadyStaticUsage()
82 const morkUsage
& morkUsage::kNone
= morkUsage_gNone
;
84 // This must be structured to allow for non-zero values in global variables
85 // just before static init time. We can only safely check for whether a
86 // global has the address of some other global. Please, do not initialize
87 // either of the variables below to zero, because this could break when a zero
88 // is assigned at static init time, but after EnsureReadyStaticUsage() runs.
90 static mork_u4 morkUsage_g_static_init_target
; // only address of this matters
91 static mork_u4
* morkUsage_g_static_init_done
; // is address of target above?
93 #define morkUsage_do_static_init() \
94 ( morkUsage_g_static_init_done = &morkUsage_g_static_init_target )
96 #define morkUsage_need_static_init() \
97 ( morkUsage_g_static_init_done != &morkUsage_g_static_init_target )
100 void morkUsage::EnsureReadyStaticUsage()
102 if ( morkUsage_need_static_init() )
104 morkUsage_do_static_init();
106 morkUsage_gHeap
.InitUsage(morkUsage_kHeap
);
107 morkUsage_gStack
.InitUsage(morkUsage_kStack
);
108 morkUsage_gMember
.InitUsage(morkUsage_kMember
);
109 morkUsage_gGlobal
.InitUsage(morkUsage_kGlobal
);
110 morkUsage_gPool
.InitUsage(morkUsage_kPool
);
111 morkUsage_gNone
.InitUsage(morkUsage_kNone
);
116 const morkUsage
& morkUsage::GetHeap() // kHeap safe at static init time
118 EnsureReadyStaticUsage();
119 return morkUsage_gHeap
;
123 const morkUsage
& morkUsage::GetStack() // kStack safe at static init time
125 EnsureReadyStaticUsage();
126 return morkUsage_gStack
;
130 const morkUsage
& morkUsage::GetMember() // kMember safe at static init time
132 EnsureReadyStaticUsage();
133 return morkUsage_gMember
;
137 const morkUsage
& morkUsage::GetGlobal() // kGlobal safe at static init time
139 EnsureReadyStaticUsage();
140 return morkUsage_gGlobal
;
144 const morkUsage
& morkUsage::GetPool() // kPool safe at static init time
146 EnsureReadyStaticUsage();
147 return morkUsage_gPool
;
151 const morkUsage
& morkUsage::GetNone() // kNone safe at static init time
153 EnsureReadyStaticUsage();
154 return morkUsage_gNone
;
157 morkUsage::morkUsage()
159 if ( morkUsage_need_static_init() )
161 morkUsage::EnsureReadyStaticUsage();
165 morkUsage::morkUsage(mork_usage code
)
168 if ( morkUsage_need_static_init() )
170 morkUsage::EnsureReadyStaticUsage();
174 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
177 morkNode::MakeNew(size_t inSize
, nsIMdbHeap
& ioHeap
, morkEnv
* ev
)
182 ioHeap
.Alloc(ev
->AsMdbEnv(), inSize
, (void **) &node
);
184 ev
->OutOfMemoryError();
187 ev
->NilPointerError();
192 /*public non-poly*/ void
193 morkNode::ZapOld(morkEnv
* ev
, nsIMdbHeap
* ioHeap
)
197 if ( this->IsNode() )
199 mork_usage usage
= mNode_Usage
; // mNode_Usage before ~morkNode
200 this->morkNode::~morkNode(); // first call polymorphic destructor
201 if ( ioHeap
) // was this node heap allocated?
202 ioHeap
->Free(ev
->AsMdbEnv(), this);
203 else if ( usage
== morkUsage_kPool
) // mNode_Usage before ~morkNode
205 morkHandle
* h
= (morkHandle
*) this;
206 if ( h
->IsHandle() && h
->GoodHandleTag() )
208 if ( h
->mHandle_Face
)
210 if (ev
->mEnv_HandlePool
)
211 ev
->mEnv_HandlePool
->ZapHandle(ev
, h
->mHandle_Face
);
212 else if (h
->mHandle_Env
&& h
->mHandle_Env
->mEnv_HandlePool
)
213 h
->mHandle_Env
->mEnv_HandlePool
->ZapHandle(ev
, h
->mHandle_Face
);
216 ev
->NilPointerError();
221 this->NonNodeError(ev
);
224 ev
->NilPointerError();
227 /*public virtual*/ void
228 morkNode::CloseMorkNode(morkEnv
* ev
) // CloseNode() only if open
230 if ( this->IsOpenNode() )
238 morkNode::CloseMdbObject(nsIMdbEnv
* mev
)
240 return morkNode::CloseMdbObject((morkEnv
*) mev
);
243 mdb_err
morkNode::CloseMdbObject(morkEnv
*ev
)
245 // if only one ref, Handle_CutStrongRef will clean up better.
247 return CutStrongRef(ev
);
251 if ( IsNode() && IsOpenNode() )
256 outErr
= ev
->AsErr();
263 morkNode::~morkNode() // assert that CloseNode() executed earlier
265 MORK_ASSERT(this->IsShutNode() || IsDeadNode()); // sometimes we call destructor explictly w/o freeing object.
266 mNode_Access
= morkAccess_kDead
;
267 mNode_Usage
= morkUsage_kNone
;
271 // void CloseMorkNode(morkEnv* ev) = 0; // CloseNode() only if open
272 // CloseMorkNode() is the polymorphic close method called when uses==0,
273 // which must do NOTHING at all when IsOpenNode() is not true. Otherwise,
274 // CloseMorkNode() should call a static close method specific to an object.
275 // Each such static close method should either call inherited static close
276 // methods, or else perform the consolidated effect of calling them, where
277 // subclasses should closely track any changes in base classes with care.
281 morkNode::morkNode( mork_usage inCode
)
283 , mNode_Base( morkBase_kNode
)
284 , mNode_Derived ( 0 ) // until subclass sets appropriately
285 , mNode_Access( morkAccess_kOpen
)
286 , mNode_Usage( inCode
)
287 , mNode_Mutable( morkAble_kEnabled
)
288 , mNode_Load( morkLoad_kClean
)
295 morkNode::morkNode(const morkUsage
& inUsage
, nsIMdbHeap
* ioHeap
)
296 : mNode_Heap( ioHeap
)
297 , mNode_Base( morkBase_kNode
)
298 , mNode_Derived ( 0 ) // until subclass sets appropriately
299 , mNode_Access( morkAccess_kOpen
)
300 , mNode_Usage( inUsage
.Code() )
301 , mNode_Mutable( morkAble_kEnabled
)
302 , mNode_Load( morkLoad_kClean
)
306 if ( !ioHeap
&& mNode_Usage
== morkUsage_kHeap
)
311 morkNode::morkNode(morkEnv
* ev
,
312 const morkUsage
& inUsage
, nsIMdbHeap
* ioHeap
)
313 : mNode_Heap( ioHeap
)
314 , mNode_Base( morkBase_kNode
)
315 , mNode_Derived ( 0 ) // until subclass sets appropriately
316 , mNode_Access( morkAccess_kOpen
)
317 , mNode_Usage( inUsage
.Code() )
318 , mNode_Mutable( morkAble_kEnabled
)
319 , mNode_Load( morkLoad_kClean
)
323 if ( !ioHeap
&& mNode_Usage
== morkUsage_kHeap
)
325 this->NilHeapError(ev
);
329 /*protected non-poly*/ void
330 morkNode::RefsUnderUsesWarning(morkEnv
* ev
) const
332 ev
->NewError("mNode_Refs < mNode_Uses");
335 /*protected non-poly*/ void
336 morkNode::NonNodeError(morkEnv
* ev
) const // called when IsNode() is false
338 ev
->NewError("non-morkNode");
341 /*protected non-poly*/ void
342 morkNode::NonOpenNodeError(morkEnv
* ev
) const // when IsOpenNode() is false
344 ev
->NewError("non-open-morkNode");
347 /*protected non-poly*/ void
348 morkNode::NonMutableNodeError(morkEnv
* ev
) const // when IsMutable() is false
350 ev
->NewError("non-mutable-morkNode");
353 /*protected non-poly*/ void
354 morkNode::NilHeapError(morkEnv
* ev
) const // zero mNode_Heap w/ kHeap usage
356 ev
->NewError("nil mNode_Heap");
359 /*protected non-poly*/ void
360 morkNode::RefsOverflowWarning(morkEnv
* ev
) const // mNode_Refs overflow
362 ev
->NewWarning("mNode_Refs overflow");
365 /*protected non-poly*/ void
366 morkNode::UsesOverflowWarning(morkEnv
* ev
) const // mNode_Uses overflow
368 ev
->NewWarning("mNode_Uses overflow");
371 /*protected non-poly*/ void
372 morkNode::RefsUnderflowWarning(morkEnv
* ev
) const // mNode_Refs underflow
374 ev
->NewWarning("mNode_Refs underflow");
377 /*protected non-poly*/ void
378 morkNode::UsesUnderflowWarning(morkEnv
* ev
) const // mNode_Uses underflow
380 ev
->NewWarning("mNode_Uses underflow");
383 /*public non-poly*/ void
384 morkNode::CloseNode(morkEnv
* ev
) // called by CloseMorkNode();
388 if ( this->IsNode() )
391 this->NonNodeError(ev
);
394 ev
->NilPointerError();
398 extern void // utility method very similar to morkNode::SlotStrongNode():
399 nsIMdbCompare_SlotStrongCompare(nsIMdbCompare
* self
, morkEnv
* ev
,
400 nsIMdbCompare
** ioSlot
)
401 // If *ioSlot is non-nil, that compare is released by CutStrongRef() and
402 // then zeroed out. Then if self is non-nil, this is acquired by
403 // calling AddStrongRef(), and if the return value shows success,
404 // then self is put into slot *ioSlot. Note self can be nil, so we take
405 // expression 'nsIMdbCompare_SlotStrongCompare(0, ev, &slot)'.
407 nsIMdbEnv
* menv
= ev
->AsMdbEnv();
408 nsIMdbCompare
* compare
= *ioSlot
;
409 if ( self
!= compare
)
414 compare
->CutStrongRef(menv
);
416 if ( self
&& ev
->Good() && (self
->AddStrongRef(menv
)==0) && ev
->Good() )
422 extern void // utility method very similar to morkNode::SlotStrongNode():
423 nsIMdbFile_SlotStrongFile(nsIMdbFile
* self
, morkEnv
* ev
, nsIMdbFile
** ioSlot
)
424 // If *ioSlot is non-nil, that file is released by CutStrongRef() and
425 // then zeroed out. Then if self is non-nil, this is acquired by
426 // calling AddStrongRef(), and if the return value shows success,
427 // then self is put into slot *ioSlot. Note self can be nil, so we take
428 // expression 'nsIMdbFile_SlotStrongFile(0, ev, &slot)'.
430 nsIMdbFile
* file
= *ioSlot
;
438 if ( self
&& ev
->Good() && (NS_ADDREF(self
)>=0) && ev
->Good() )
443 void // utility method very similar to morkNode::SlotStrongNode():
444 nsIMdbHeap_SlotStrongHeap(nsIMdbHeap
* self
, morkEnv
* ev
, nsIMdbHeap
** ioSlot
)
445 // If *ioSlot is non-nil, that heap is released by CutStrongRef() and
446 // then zeroed out. Then if self is non-nil, self is acquired by
447 // calling AddStrongRef(), and if the return value shows success,
448 // then self is put into slot *ioSlot. Note self can be nil, so we
449 // permit expression 'nsIMdbHeap_SlotStrongHeap(0, ev, &slot)'.
451 nsIMdbEnv
* menv
= ev
->AsMdbEnv();
452 nsIMdbHeap
* heap
= *ioSlot
;
458 heap
->HeapCutStrongRef(menv
);
460 if ( self
&& ev
->Good() && (self
->HeapAddStrongRef(menv
)==0) && ev
->Good() )
465 /*public static*/ void
466 morkNode::SlotStrongNode(morkNode
* me
, morkEnv
* ev
, morkNode
** ioSlot
)
467 // If *ioSlot is non-nil, that node is released by CutStrongRef() and
468 // then zeroed out. Then if me is non-nil, this is acquired by
469 // calling AddStrongRef(), and if positive is returned to show success,
470 // then me is put into slot *ioSlot. Note me can be nil, so we take
471 // expression 'morkNode::SlotStrongNode((morkNode*) 0, ev, &slot)'.
473 morkNode
* node
= *ioSlot
;
478 // what if this nulls out the ev and causes asserts?
479 // can we move this after the CutStrongRef()?
481 node
->CutStrongRef(ev
);
483 if ( me
&& me
->AddStrongRef(ev
) )
488 /*public static*/ void
489 morkNode::SlotWeakNode(morkNode
* me
, morkEnv
* ev
, morkNode
** ioSlot
)
490 // If *ioSlot is non-nil, that node is released by CutWeakRef() and
491 // then zeroed out. Then if me is non-nil, this is acquired by
492 // calling AddWeakRef(), and if positive is returned to show success,
493 // then me is put into slot *ioSlot. Note me can be nil, so we
494 // expression 'morkNode::SlotWeakNode((morkNode*) 0, ev, &slot)'.
496 morkNode
* node
= *ioSlot
;
502 node
->CutWeakRef(ev
);
504 if ( me
&& me
->AddWeakRef(ev
) )
509 /*public non-poly*/ mork_uses
510 morkNode::AddStrongRef(morkEnv
* ev
)
512 mork_uses outUses
= 0;
515 if ( this->IsNode() )
517 mork_uses uses
= mNode_Uses
;
518 mork_refs refs
= mNode_Refs
;
519 if ( refs
< uses
) // need to fix broken refs/uses relation?
521 this->RefsUnderUsesWarning(ev
);
522 mNode_Refs
= mNode_Uses
= refs
= uses
;
524 if ( refs
< morkNode_kMaxRefCount
) // not too great?
530 this->RefsOverflowWarning(ev
);
535 this->NonNodeError(ev
);
538 ev
->NilPointerError();
542 /*private non-poly*/ mork_bool
543 morkNode::cut_use_count(morkEnv
* ev
) // just one part of CutStrongRef()
545 mork_bool didCut
= morkBool_kFalse
;
548 if ( this->IsNode() )
550 mork_uses uses
= mNode_Uses
;
551 if ( uses
) // not yet zero?
554 this->UsesUnderflowWarning(ev
);
556 didCut
= morkBool_kTrue
;
557 if ( !mNode_Uses
) // last use gone? time to close node?
559 if ( this->IsOpenNode() )
561 if ( !mNode_Refs
) // no outstanding reference?
563 this->RefsUnderflowWarning(ev
);
564 ++mNode_Refs
; // prevent potential crash during close
566 this->CloseMorkNode(ev
); // polymorphic self close
567 // (Note CutNode() is not polymorphic -- so don't call that.)
572 this->NonNodeError(ev
);
575 ev
->NilPointerError();
579 /*public non-poly*/ mork_uses
580 morkNode::CutStrongRef(morkEnv
* ev
)
582 mork_refs outRefs
= 0;
585 if ( this->IsNode() )
587 if ( this->cut_use_count(ev
) )
588 outRefs
= this->CutWeakRef(ev
);
591 this->NonNodeError(ev
);
594 ev
->NilPointerError();
598 /*public non-poly*/ mork_refs
599 morkNode::AddWeakRef(morkEnv
* ev
)
601 mork_refs outRefs
= 0;
604 if ( this->IsNode() )
606 mork_refs refs
= mNode_Refs
;
607 if ( refs
< morkNode_kMaxRefCount
) // not too great?
610 this->RefsOverflowWarning(ev
);
615 this->NonNodeError(ev
);
618 ev
->NilPointerError();
622 /*public non-poly*/ mork_refs
623 morkNode::CutWeakRef(morkEnv
* ev
)
625 mork_refs outRefs
= 0;
628 if ( this->IsNode() )
630 mork_uses uses
= mNode_Uses
;
631 mork_refs refs
= mNode_Refs
;
632 if ( refs
) // not yet zero?
635 this->RefsUnderflowWarning(ev
);
637 if ( refs
< uses
) // need to fix broken refs/uses relation?
639 this->RefsUnderUsesWarning(ev
);
640 mNode_Refs
= mNode_Uses
= refs
= uses
;
644 if ( !refs
) // last reference gone? time to destroy node?
645 this->ZapOld(ev
, mNode_Heap
); // self destroy, use this no longer
648 this->NonNodeError(ev
);
651 ev
->NilPointerError();
655 static const char morkNode_kBroken
[] = "broken";
657 /*public non-poly*/ const char*
658 morkNode::GetNodeAccessAsString() const // e.g. "open", "shut", etc.
660 const char* outString
= morkNode_kBroken
;
661 switch( mNode_Access
)
663 case morkAccess_kOpen
: outString
= "open"; break;
664 case morkAccess_kClosing
: outString
= "closing"; break;
665 case morkAccess_kShut
: outString
= "shut"; break;
666 case morkAccess_kDead
: outString
= "dead"; break;
671 /*public non-poly*/ const char*
672 morkNode::GetNodeUsageAsString() const // e.g. "heap", "stack", etc.
674 const char* outString
= morkNode_kBroken
;
675 switch( mNode_Usage
)
677 case morkUsage_kHeap
: outString
= "heap"; break;
678 case morkUsage_kStack
: outString
= "stack"; break;
679 case morkUsage_kMember
: outString
= "member"; break;
680 case morkUsage_kGlobal
: outString
= "global"; break;
681 case morkUsage_kPool
: outString
= "pool"; break;
682 case morkUsage_kNone
: outString
= "none"; break;
687 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789