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
4  *
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/
9  *
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.
14  *
15  * The Original Code is mozilla.org code.
16  *
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.
21  *
22  * Contributor(s):
23  *
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.
35  *
36  * ***** END LICENSE BLOCK ***** */
37 
38 #ifndef _MORKNODE_
39 #define _MORKNODE_ 1
40 
41 #ifndef _MORK_
42 #  include "mork.h"
43 #endif
44 
45 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
46 
47 #define morkUsage_kHeap 'h'
48 #define morkUsage_kStack 's'
49 #define morkUsage_kMember 'm'
50 #define morkUsage_kGlobal 'g'
51 #define morkUsage_kPool 'p'
52 #define morkUsage_kNone 'n'
53 
54 class morkUsage {
55  public:
56   mork_usage mUsage_Code;  // kHeap, kStack, kMember, or kGhost
57 
58  public:
59   explicit morkUsage(mork_usage inCode);
60 
61   morkUsage();  // does nothing except maybe call EnsureReadyStaticUsage()
InitUsage(mork_usage inCode)62   void InitUsage(mork_usage inCode) { mUsage_Code = inCode; }
63 
~morkUsage()64   ~morkUsage() {}
Code()65   mork_usage Code() const { return mUsage_Code; }
66 
67   static void EnsureReadyStaticUsage();
68 
69  public:
70   static const morkUsage& kHeap;    // morkUsage_kHeap
71   static const morkUsage& kStack;   // morkUsage_kStack
72   static const morkUsage& kMember;  // morkUsage_kMember
73   static const morkUsage& kGlobal;  // morkUsage_kGlobal
74   static const morkUsage& kPool;    // morkUsage_kPool
75   static const morkUsage& kNone;    // morkUsage_kNone
76 
77   static const morkUsage& GetHeap();    // kHeap, safe at static init time
78   static const morkUsage& GetStack();   // kStack, safe at static init time
79   static const morkUsage& GetMember();  // kMember, safe at static init time
80   static const morkUsage& GetGlobal();  // kGlobal, safe at static init time
81   static const morkUsage& GetPool();    // kPool, safe at static init time
82   static const morkUsage& GetNone();    // kNone, safe at static init time
83 };
84 
85 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
86 
87 #define morkNode_kMaxRefCount 0x0FFFF /* count sticks if it hits this */
88 
89 #define morkBase_kNode /*i*/ 0x4E64 /* ascii 'Nd' */
90 
91 /*| morkNode: several groups of two-byte integers that track the basic
92 **| status of an object that can be used to compose in-memory graphs.
93 **| This is the base class for nsIMdbObject (which adds members that fit
94 **| the needs of an nsIMdbObject subclass).  The morkNode class is also used
95 **| as the base class for other Mork db classes with no strong relation to
96 **| the MDB class hierarchy.
97 **|
98 **|| Heap: the heap in which this node was allocated, when the usage equals
99 **| morkUsage_kHeap to show dynamic allocation.  Note this heap is NOT ref-
100 **| counted, because that would be too great and complex a burden for all
101 **| the nodes allocated in that heap.  So heap users should take care to
102 **| understand that nodes allocated in that heap are considered protected
103 **| by some inclusive context in which all those nodes are allocated, and
104 **| that context must maintain at least one strong refcount for the heap.
105 **| Occasionally a node subclass will indeed wish to hold a refcounted
106 **| reference to a heap, and possibly the same heap that is in mNode_Heap,
107 **| but this is always done in a separate slot that explicitly refcounts,
108 **| so we avoid confusing what is meant by the mNode_Heap slot.
109 |*/
110 class morkNode /*: public nsISupports */ {  // base class for constructing Mork
111                                             // object graphs
112 
113  public:  // state is public because the entire Mork system is private
114           //  NS_DECL_ISUPPORTS;
115   nsIMdbHeap* mNode_Heap;  // NON-refcounted heap pointer
116 
117   mork_base mNode_Base;        // must equal morkBase_kNode
118   mork_derived mNode_Derived;  // depends on specific node subclass
119 
120   mork_access mNode_Access;  // kOpen, kClosing, kShut, or kDead
121   mork_usage mNode_Usage;    // kHeap, kStack, kMember, kGlobal, kNone
122   mork_able mNode_Mutable;   // can this node be modified?
123   mork_load mNode_Load;      // is this node clean or dirty?
124 
125   mork_uses mNode_Uses;  // refcount for strong refs
126   mork_refs mNode_Refs;  // refcount for strong refs + weak refs
127 
128  protected:  // special case empty construction for morkHandleFrame
129   friend class morkHandleFrame;
morkNode()130   morkNode() {}
131 
132  public:  // inlines for weird mNode_Mutable and mNode_Load constants
SetFrozen()133   void SetFrozen() { mNode_Mutable = morkAble_kDisabled; }
SetMutable()134   void SetMutable() { mNode_Mutable = morkAble_kEnabled; }
SetAsleep()135   void SetAsleep() { mNode_Mutable = morkAble_kAsleep; }
136 
IsFrozen()137   mork_bool IsFrozen() const { return mNode_Mutable == morkAble_kDisabled; }
IsMutable()138   mork_bool IsMutable() const { return mNode_Mutable == morkAble_kEnabled; }
IsAsleep()139   mork_bool IsAsleep() const { return mNode_Mutable == morkAble_kAsleep; }
140 
SetNodeClean()141   void SetNodeClean() { mNode_Load = morkLoad_kClean; }
SetNodeDirty()142   void SetNodeDirty() { mNode_Load = morkLoad_kDirty; }
143 
IsNodeClean()144   mork_bool IsNodeClean() const { return mNode_Load == morkLoad_kClean; }
IsNodeDirty()145   mork_bool IsNodeDirty() const { return mNode_Load == morkLoad_kDirty; }
146 
147  public:  // morkNode memory management methods
148   static void* MakeNew(size_t inSize, nsIMdbHeap& ioHeap, morkEnv* ev);
149 
150   void ZapOld(morkEnv* ev, nsIMdbHeap* ioHeap);  // replaces operator delete()
151   // this->morkNode::~morkNode(); // first call polymorphic destructor
152   // if ( ioHeap ) // was this node heap allocated?
153   //    ioHeap->Free(ev->AsMdbEnv(), this);
154 
155  public:  // morkNode memory management operators
new(size_t inSize,nsIMdbHeap & ioHeap,morkEnv * ev)156   void* operator new(size_t inSize, nsIMdbHeap& ioHeap,
157                      morkEnv* ev) noexcept(true) {
158     return morkNode::MakeNew(inSize, ioHeap, ev);
159   }
160 
161  protected:  // construction without an anv needed for first env constructed:
162   morkNode(const morkUsage& inUsage, nsIMdbHeap* ioHeap);
163 
164   explicit morkNode(mork_usage inCode);  // usage == inCode, heap == nil
165 
166   // { ===== begin basic node interface =====
167  public:  // morkNode virtual methods
168   // virtual FlushMorkNode(morkEnv* ev, morkStream* ioStream);
169   // virtual WriteMorkNode(morkEnv* ev, morkStream* ioStream);
170 
171   virtual ~morkNode();  // assert that CloseNode() executed earlier
172   virtual void CloseMorkNode(morkEnv* ev);  // CloseNode() only if open
173 
174   // CloseMorkNode() is the polymorphic close method called when uses==0,
175   // which must do NOTHING at all when IsOpenNode() is not true.  Otherwise,
176   // CloseMorkNode() should call a static close method specific to an object.
177   // Each such static close method should either call inherited static close
178   // methods, or else perform the consolidated effect of calling them, where
179   // subclasses should closely track any changes in base classes with care.
180 
181  public:  // morkNode construction
182   morkNode(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap);
183   void CloseNode(morkEnv* ev);  // called by CloseMorkNode();
184   nsresult CloseMdbObject(morkEnv* ev);
185   NS_IMETHOD CloseMdbObject(nsIMdbEnv* ev);
186 
187  private:  // copying is not allowed
188   morkNode(const morkNode& other);
189   morkNode& operator=(const morkNode& other);
190 
191  public:  // dynamic type identification
IsNode()192   mork_bool IsNode() const { return mNode_Base == morkBase_kNode; }
193   // } ===== end basic node methods =====
194 
195  public:  // public error & warning methods
196   void RefsUnderUsesWarning(
197       morkEnv* ev) const;                // call if mNode_Refs < mNode_Uses
198   void NonNodeError(morkEnv* ev) const;  // call when IsNode() is false
199   void NilHeapError(morkEnv* ev) const;  // zero mNode_Heap when usage is kHeap
200   void NonOpenNodeError(morkEnv* ev) const;  // call when IsOpenNode() is false
201 
202   void NonMutableNodeError(morkEnv* ev) const;  // when IsMutable() is false
203 
204   void RefsOverflowWarning(morkEnv* ev) const;   // call on mNode_Refs overflow
205   void UsesOverflowWarning(morkEnv* ev) const;   // call on mNode_Uses overflow
206   void RefsUnderflowWarning(morkEnv* ev) const;  // call on mNode_Refs underflow
207   void UsesUnderflowWarning(morkEnv* ev) const;  // call on mNode_Uses underflow
208 
209  private:                                // private refcounting methods
210   mork_bool cut_use_count(morkEnv* ev);  // just one part of CutStrongRef()
211 
212  public:  // other morkNode methods
GoodRefs()213   mork_bool GoodRefs() const { return mNode_Refs >= mNode_Uses; }
BadRefs()214   mork_bool BadRefs() const { return mNode_Refs < mNode_Uses; }
215 
StrongRefsOnly()216   mork_uses StrongRefsOnly() const { return mNode_Uses; }
WeakRefsOnly()217   mork_refs WeakRefsOnly() const {
218     return (mork_refs)(mNode_Refs - mNode_Uses);
219   }
220 
221   // (this refcounting derives from public domain IronDoc node refcounts)
222   virtual mork_uses AddStrongRef(morkEnv* ev);
223   virtual mork_uses CutStrongRef(morkEnv* ev);
224   mork_refs AddWeakRef(morkEnv* ev);
225   mork_refs CutWeakRef(morkEnv* ev);
226 
227   const char* GetNodeAccessAsString() const;  // e.g. "open", "shut", etc.
228   const char* GetNodeUsageAsString() const;   // e.g. "heap", "stack", etc.
229 
NodeUsage()230   mork_usage NodeUsage() const { return mNode_Usage; }
231 
IsHeapNode()232   mork_bool IsHeapNode() const { return mNode_Usage == morkUsage_kHeap; }
233 
IsOpenNode()234   mork_bool IsOpenNode() const { return mNode_Access == morkAccess_kOpen; }
235 
IsShutNode()236   mork_bool IsShutNode() const { return mNode_Access == morkAccess_kShut; }
237 
IsDeadNode()238   mork_bool IsDeadNode() const { return mNode_Access == morkAccess_kDead; }
239 
IsClosingNode()240   mork_bool IsClosingNode() const {
241     return mNode_Access == morkAccess_kClosing;
242   }
243 
IsOpenOrClosingNode()244   mork_bool IsOpenOrClosingNode() const {
245     return IsOpenNode() || IsClosingNode();
246   }
247 
HasNodeAccess()248   mork_bool HasNodeAccess() const {
249     return (IsOpenNode() || IsShutNode() || IsClosingNode());
250   }
251 
MarkShut()252   void MarkShut() { mNode_Access = morkAccess_kShut; }
MarkClosing()253   void MarkClosing() { mNode_Access = morkAccess_kClosing; }
MarkDead()254   void MarkDead() { mNode_Access = morkAccess_kDead; }
255 
256  public:  // refcounting for typesafe subclass inline methods
257   static void SlotWeakNode(morkNode* me, morkEnv* ev, morkNode** ioSlot);
258   // If *ioSlot is non-nil, that node is released by CutWeakRef() and
259   // then zeroed out.  Then if me is non-nil, this is acquired by
260   // calling AddWeakRef(), and if positive is returned to show success,
261   // then this is put into slot *ioSlot.  Note me can be nil, so we
262   // permit expression '((morkNode*) 0L)->SlotWeakNode(ev, &slot)'.
263 
264   static void SlotStrongNode(morkNode* me, morkEnv* ev, morkNode** ioSlot);
265   // If *ioSlot is non-nil, that node is released by CutStrongRef() and
266   // then zeroed out.  Then if me is non-nil, this is acquired by
267   // calling AddStrongRef(), and if positive is returned to show success,
268   // then me is put into slot *ioSlot.  Note me can be nil, so we take
269   // expression 'morkNode::SlotStrongNode((morkNode*) 0, ev, &slot)'.
270 };
271 
272 extern void  // utility method very similar to morkNode::SlotStrongNode():
273 nsIMdbHeap_SlotStrongHeap(nsIMdbHeap* self, morkEnv* ev, nsIMdbHeap** ioSlot);
274 // If *ioSlot is non-nil, that heap is released by CutStrongRef() and
275 // then zeroed out.  Then if self is non-nil, this is acquired by
276 // calling AddStrongRef(), and if the return value shows success,
277 // then self is put into slot *ioSlot.  Note self can be nil, so we take
278 // expression 'nsIMdbHeap_SlotStrongHeap(0, ev, &slot)'.
279 
280 extern void  // utility method very similar to morkNode::SlotStrongNode():
281 nsIMdbFile_SlotStrongFile(nsIMdbFile* self, morkEnv* ev, nsIMdbFile** ioSlot);
282 // If *ioSlot is non-nil, that file is released by CutStrongRef() and
283 // then zeroed out.  Then if self is non-nil, this is acquired by
284 // calling AddStrongRef(), and if the return value shows success,
285 // then self is put into slot *ioSlot.  Note self can be nil, so we take
286 // expression 'nsIMdbFile_SlotStrongFile(0, ev, &slot)'.
287 
288 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
289 
290 #endif /* _MORKNODE_ */
291