Reenable test.
[wine-gecko.git] / db / mork / src / morkNode.cpp
bloba58986e0c21f6d9f21e80ebbd2928056b237effb
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
13 * License.
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.
22 * Contributor(s):
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 ***** */
38 #ifndef _MDB_
39 #include "mdb.h"
40 #endif
42 #ifndef _MORK_
43 #include "mork.h"
44 #endif
46 #ifndef _MORKNODE_
47 #include "morkNode.h"
48 #endif
50 #ifndef _MORKPOOL_
51 #include "morkPool.h"
52 #endif
54 #ifndef _MORKENV_
55 #include "morkEnv.h"
56 #endif
58 #ifndef _MORKHANDLE_
59 #include "morkHandle.h"
60 #endif
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 )
99 /*static*/
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);
115 /*static*/
116 const morkUsage& morkUsage::GetHeap() // kHeap safe at static init time
118 EnsureReadyStaticUsage();
119 return morkUsage_gHeap;
122 /*static*/
123 const morkUsage& morkUsage::GetStack() // kStack safe at static init time
125 EnsureReadyStaticUsage();
126 return morkUsage_gStack;
129 /*static*/
130 const morkUsage& morkUsage::GetMember() // kMember safe at static init time
132 EnsureReadyStaticUsage();
133 return morkUsage_gMember;
136 /*static*/
137 const morkUsage& morkUsage::GetGlobal() // kGlobal safe at static init time
139 EnsureReadyStaticUsage();
140 return morkUsage_gGlobal;
143 /*static*/
144 const morkUsage& morkUsage::GetPool() // kPool safe at static init time
146 EnsureReadyStaticUsage();
147 return morkUsage_gPool;
150 /*static*/
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)
166 : mUsage_Code(code)
168 if ( morkUsage_need_static_init() )
170 morkUsage::EnsureReadyStaticUsage();
174 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
176 /*static*/ void*
177 morkNode::MakeNew(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev)
179 void* node = 0;
180 if ( &ioHeap )
182 ioHeap.Alloc(ev->AsMdbEnv(), inSize, (void **) &node);
183 if ( !node )
184 ev->OutOfMemoryError();
186 else
187 ev->NilPointerError();
189 return node;
192 /*public non-poly*/ void
193 morkNode::ZapOld(morkEnv* ev, nsIMdbHeap* ioHeap)
195 if ( this )
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);
215 else
216 ev->NilPointerError();
220 else
221 this->NonNodeError(ev);
223 else
224 ev->NilPointerError();
227 /*public virtual*/ void
228 morkNode::CloseMorkNode(morkEnv* ev) // CloseNode() only if open
230 if ( this->IsOpenNode() )
232 this->MarkClosing();
233 this->CloseNode(ev);
234 this->MarkShut();
237 NS_IMETHODIMP
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.
246 if (mNode_Uses == 1)
247 return CutStrongRef(ev);
249 mdb_err outErr = 0;
251 if ( IsNode() && IsOpenNode() )
253 if ( ev )
255 CloseMorkNode(ev);
256 outErr = ev->AsErr();
259 return outErr;
262 /*public virtual*/
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;
270 /*public virtual*/
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.
280 /*public non-poly*/
281 morkNode::morkNode( mork_usage inCode )
282 : mNode_Heap( 0 )
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 )
289 , mNode_Uses( 1 )
290 , mNode_Refs( 1 )
294 /*public non-poly*/
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 )
303 , mNode_Uses( 1 )
304 , mNode_Refs( 1 )
306 if ( !ioHeap && mNode_Usage == morkUsage_kHeap )
307 MORK_ASSERT(ioHeap);
310 /*public non-poly*/
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 )
320 , mNode_Uses( 1 )
321 , mNode_Refs( 1 )
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();
386 if ( this )
388 if ( this->IsNode() )
389 this->MarkShut();
390 else
391 this->NonNodeError(ev);
393 else
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 )
411 if ( compare )
413 *ioSlot = 0;
414 compare->CutStrongRef(menv);
416 if ( self && ev->Good() && (self->AddStrongRef(menv)==0) && ev->Good() )
417 *ioSlot = self;
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;
431 if ( self != file )
433 if ( file )
435 *ioSlot = 0;
436 NS_RELEASE(file);
438 if ( self && ev->Good() && (NS_ADDREF(self)>=0) && ev->Good() )
439 *ioSlot = self;
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;
453 if ( self != heap )
455 if ( heap )
457 *ioSlot = 0;
458 heap->HeapCutStrongRef(menv);
460 if ( self && ev->Good() && (self->HeapAddStrongRef(menv)==0) && ev->Good() )
461 *ioSlot = self;
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;
474 if ( me != node )
476 if ( node )
478 // what if this nulls out the ev and causes asserts?
479 // can we move this after the CutStrongRef()?
480 *ioSlot = 0;
481 node->CutStrongRef(ev);
483 if ( me && me->AddStrongRef(ev) )
484 *ioSlot = me;
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;
497 if ( me != node )
499 if ( node )
501 *ioSlot = 0;
502 node->CutWeakRef(ev);
504 if ( me && me->AddWeakRef(ev) )
505 *ioSlot = me;
509 /*public non-poly*/ mork_uses
510 morkNode::AddStrongRef(morkEnv* ev)
512 mork_uses outUses = 0;
513 if ( this )
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?
526 mNode_Refs = ++refs;
527 mNode_Uses = ++uses;
529 else
530 this->RefsOverflowWarning(ev);
532 outUses = uses;
534 else
535 this->NonNodeError(ev);
537 else
538 ev->NilPointerError();
539 return outUses;
542 /*private non-poly*/ mork_bool
543 morkNode::cut_use_count(morkEnv* ev) // just one part of CutStrongRef()
545 mork_bool didCut = morkBool_kFalse;
546 if ( this )
548 if ( this->IsNode() )
550 mork_uses uses = mNode_Uses;
551 if ( uses ) // not yet zero?
552 mNode_Uses = --uses;
553 else
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.)
571 else
572 this->NonNodeError(ev);
574 else
575 ev->NilPointerError();
576 return didCut;
579 /*public non-poly*/ mork_uses
580 morkNode::CutStrongRef(morkEnv* ev)
582 mork_refs outRefs = 0;
583 if ( this )
585 if ( this->IsNode() )
587 if ( this->cut_use_count(ev) )
588 outRefs = this->CutWeakRef(ev);
590 else
591 this->NonNodeError(ev);
593 else
594 ev->NilPointerError();
595 return outRefs;
598 /*public non-poly*/ mork_refs
599 morkNode::AddWeakRef(morkEnv* ev)
601 mork_refs outRefs = 0;
602 if ( this )
604 if ( this->IsNode() )
606 mork_refs refs = mNode_Refs;
607 if ( refs < morkNode_kMaxRefCount ) // not too great?
608 mNode_Refs = ++refs;
609 else
610 this->RefsOverflowWarning(ev);
612 outRefs = refs;
614 else
615 this->NonNodeError(ev);
617 else
618 ev->NilPointerError();
619 return outRefs;
622 /*public non-poly*/ mork_refs
623 morkNode::CutWeakRef(morkEnv* ev)
625 mork_refs outRefs = 0;
626 if ( this )
628 if ( this->IsNode() )
630 mork_uses uses = mNode_Uses;
631 mork_refs refs = mNode_Refs;
632 if ( refs ) // not yet zero?
633 mNode_Refs = --refs;
634 else
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;
643 outRefs = refs;
644 if ( !refs ) // last reference gone? time to destroy node?
645 this->ZapOld(ev, mNode_Heap); // self destroy, use this no longer
647 else
648 this->NonNodeError(ev);
650 else
651 ev->NilPointerError();
652 return outRefs;
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;
668 return outString;
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;
684 return outString;
687 //3456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789