1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-  */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3  * License, v. 2.0. If a copy of the MPL was not distributed with this
4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 
6 #ifndef _MDB_
7 #  include "mdb.h"
8 #endif
9 
10 #ifndef _MORK_
11 #  include "mork.h"
12 #endif
13 
14 #ifndef _MORKNODE_
15 #  include "morkNode.h"
16 #endif
17 
18 #ifndef _MORKENV_
19 #  include "morkEnv.h"
20 #endif
21 
22 #ifndef _MORKPOOL_
23 #  include "morkPool.h"
24 #endif
25 
26 #ifndef _MORKATOM_
27 #  include "morkAtom.h"
28 #endif
29 
30 #ifndef _MORKHANDLE_
31 #  include "morkHandle.h"
32 #endif
33 
34 #ifndef _MORKCELL_
35 #  include "morkCell.h"
36 #endif
37 
38 #ifndef _MORKROW_
39 #  include "morkRow.h"
40 #endif
41 
42 #ifndef _MORKBLOB_
43 #  include "morkBlob.h"
44 #endif
45 
46 #ifndef _MORKDEQUE_
47 #  include "morkDeque.h"
48 #endif
49 
50 #ifndef _MORKZONE_
51 #  include "morkZone.h"
52 #endif
53 
54 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
55 
56 // ````` ````` ````` ````` `````
57 // { ===== begin morkNode interface =====
58 
CloseMorkNode(morkEnv * ev)59 /*public virtual*/ void morkPool::CloseMorkNode(
60     morkEnv* ev)  // ClosePool() only if open
61 {
62   if (this->IsOpenNode()) {
63     this->MarkClosing();
64     this->ClosePool(ev);
65     this->MarkShut();
66   }
67 }
68 
69 /*public virtual*/
~morkPool()70 morkPool::~morkPool()  // assert ClosePool() executed earlier
71 {
72   MORK_ASSERT(this->IsShutNode());
73 }
74 
75 /*public non-poly*/
morkPool(const morkUsage & inUsage,nsIMdbHeap * ioHeap,nsIMdbHeap * ioSlotHeap)76 morkPool::morkPool(const morkUsage& inUsage, nsIMdbHeap* ioHeap,
77                    nsIMdbHeap* ioSlotHeap)
78     : morkNode(inUsage, ioHeap),
79       mPool_Heap(ioSlotHeap),
80       mPool_UsedFramesCount(0),
81       mPool_FreeFramesCount(0) {
82   // mPool_Heap is NOT refcounted
83   MORK_ASSERT(ioSlotHeap);
84   if (ioSlotHeap) mNode_Derived = morkDerived_kPool;
85 }
86 
87 /*public non-poly*/
morkPool(morkEnv * ev,const morkUsage & inUsage,nsIMdbHeap * ioHeap,nsIMdbHeap * ioSlotHeap)88 morkPool::morkPool(morkEnv* ev, const morkUsage& inUsage, nsIMdbHeap* ioHeap,
89                    nsIMdbHeap* ioSlotHeap)
90     : morkNode(ev, inUsage, ioHeap),
91       mPool_Heap(ioSlotHeap),
92       mPool_UsedFramesCount(0),
93       mPool_FreeFramesCount(0) {
94   if (ioSlotHeap) {
95     // mPool_Heap is NOT refcounted:
96     // nsIMdbHeap_SlotStrongHeap(ioSlotHeap, ev, &mPool_Heap);
97     if (ev->Good()) mNode_Derived = morkDerived_kPool;
98   } else
99     ev->NilPointerError();
100 }
101 
ClosePool(morkEnv * ev)102 /*public non-poly*/ void morkPool::ClosePool(
103     morkEnv* ev)  // called by CloseMorkNode();
104 {
105   if (this->IsNode()) {
106 #ifdef morkZone_CONFIG_ARENA
107 #else  /*morkZone_CONFIG_ARENA*/
108     // MORK_USED_1(ioZone);
109 #endif /*morkZone_CONFIG_ARENA*/
110 
111     nsIMdbHeap* heap = mPool_Heap;
112     nsIMdbEnv* mev = ev->AsMdbEnv();
113     morkLink* aLink;
114     morkDeque* d = &mPool_FreeHandleFrames;
115     while ((aLink = d->RemoveFirst()) != 0) heap->Free(mev, aLink);
116 
117     // if the pool's closed, get rid of the frames in use too.
118     d = &mPool_UsedHandleFrames;
119     while ((aLink = d->RemoveFirst()) != 0) heap->Free(mev, aLink);
120 
121     this->MarkShut();
122   } else
123     this->NonNodeError(ev);
124 }
125 
126 // } ===== end morkNode methods =====
127 // ````` ````` ````` ````` `````
128 
129 // alloc and free individual instances of handles (inside hand frames):
NewHandle(morkEnv * ev,mork_size inSize,morkZone * ioZone)130 morkHandleFace* morkPool::NewHandle(morkEnv* ev, mork_size inSize,
131                                     morkZone* ioZone) {
132   void* newBlock = 0;
133   if (inSize <= sizeof(morkHandleFrame)) {
134     morkLink* firstLink = mPool_FreeHandleFrames.RemoveFirst();
135     if (firstLink) {
136       newBlock = firstLink;
137       if (mPool_FreeFramesCount)
138         --mPool_FreeFramesCount;
139       else
140         ev->NewWarning("mPool_FreeFramesCount underflow");
141     } else
142       mPool_Heap->Alloc(ev->AsMdbEnv(), sizeof(morkHandleFrame),
143                         (void**)&newBlock);
144   } else {
145     ev->NewWarning("inSize > sizeof(morkHandleFrame)");
146     mPool_Heap->Alloc(ev->AsMdbEnv(), inSize, (void**)&newBlock);
147   }
148 #ifdef morkZone_CONFIG_ARENA
149 #else  /*morkZone_CONFIG_ARENA*/
150   MORK_USED_1(ioZone);
151 #endif /*morkZone_CONFIG_ARENA*/
152 
153   return (morkHandleFace*)newBlock;
154 }
155 
ZapHandle(morkEnv * ev,morkHandleFace * ioHandle)156 void morkPool::ZapHandle(morkEnv* ev, morkHandleFace* ioHandle) {
157   if (ioHandle) {
158     morkLink* handleLink = (morkLink*)ioHandle;
159     mPool_FreeHandleFrames.AddLast(handleLink);
160     ++mPool_FreeFramesCount;
161     // lets free all handles to track down leaks
162     // - uncomment out next 3 lines, comment out above 2
163     //      nsIMdbHeap* heap = mPool_Heap;
164     //      nsIMdbEnv* mev = ev->AsMdbEnv();
165     //      heap->Free(mev, handleLink);
166   }
167 }
168 
169 // alloc and free individual instances of rows:
NewRow(morkEnv * ev,morkZone * ioZone)170 morkRow* morkPool::NewRow(morkEnv* ev,
171                           morkZone* ioZone)  // allocate a new row instance
172 {
173   morkRow* newRow = 0;
174 
175 #ifdef morkZone_CONFIG_ARENA
176   // a zone 'chip' remembers no size, and so cannot be deallocated:
177   newRow = (morkRow*)ioZone->ZoneNewChip(ev, sizeof(morkRow));
178 #else  /*morkZone_CONFIG_ARENA*/
179   MORK_USED_1(ioZone);
180   mPool_Heap->Alloc(ev->AsMdbEnv(), sizeof(morkRow), (void**)&newRow);
181 #endif /*morkZone_CONFIG_ARENA*/
182 
183   if (newRow) MORK_MEMSET(newRow, 0, sizeof(morkRow));
184 
185   return newRow;
186 }
187 
ZapRow(morkEnv * ev,morkRow * ioRow,morkZone * ioZone)188 void morkPool::ZapRow(morkEnv* ev, morkRow* ioRow,
189                       morkZone* ioZone)  // free old row instance
190 {
191 #ifdef morkZone_CONFIG_ARENA
192   if (!ioRow) ev->NilPointerWarning();  // a zone 'chip' cannot be freed
193 #else                                   /*morkZone_CONFIG_ARENA*/
194   MORK_USED_1(ioZone);
195   if (ioRow) mPool_Heap->Free(ev->AsMdbEnv(), ioRow);
196 #endif                                  /*morkZone_CONFIG_ARENA*/
197 }
198 
199 // alloc and free entire vectors of cells (not just one cell at a time)
NewCells(morkEnv * ev,mork_size inSize,morkZone * ioZone)200 morkCell* morkPool::NewCells(morkEnv* ev, mork_size inSize, morkZone* ioZone) {
201   morkCell* newCells = 0;
202 
203   mork_size size = inSize * sizeof(morkCell);
204   if (size) {
205 #ifdef morkZone_CONFIG_ARENA
206     // a zone 'run' knows its size, and can indeed be deallocated:
207     newCells = (morkCell*)ioZone->ZoneNewRun(ev, size);
208 #else  /*morkZone_CONFIG_ARENA*/
209     MORK_USED_1(ioZone);
210     mPool_Heap->Alloc(ev->AsMdbEnv(), size, (void**)&newCells);
211 #endif /*morkZone_CONFIG_ARENA*/
212   }
213 
214   // note morkAtom depends on having nil stored in all new mCell_Atom slots:
215   if (newCells) MORK_MEMSET(newCells, 0, size);
216   return newCells;
217 }
218 
ZapCells(morkEnv * ev,morkCell * ioVector,mork_size inSize,morkZone * ioZone)219 void morkPool::ZapCells(morkEnv* ev, morkCell* ioVector, mork_size inSize,
220                         morkZone* ioZone) {
221   MORK_USED_1(inSize);
222 
223   if (ioVector) {
224 #ifdef morkZone_CONFIG_ARENA
225     // a zone 'run' knows its size, and can indeed be deallocated:
226     ioZone->ZoneZapRun(ev, ioVector);
227 #else  /*morkZone_CONFIG_ARENA*/
228     MORK_USED_1(ioZone);
229     mPool_Heap->Free(ev->AsMdbEnv(), ioVector);
230 #endif /*morkZone_CONFIG_ARENA*/
231   }
232 }
233 
234 // resize (grow or trim) cell vectors inside a containing row instance
AddRowCells(morkEnv * ev,morkRow * ioRow,mork_size inNewSize,morkZone * ioZone)235 mork_bool morkPool::AddRowCells(morkEnv* ev, morkRow* ioRow,
236                                 mork_size inNewSize, morkZone* ioZone) {
237   // note strong implementation similarity to morkArray::Grow()
238 
239   MORK_USED_1(ioZone);
240 #ifdef morkZone_CONFIG_ARENA
241 #else  /*morkZone_CONFIG_ARENA*/
242 #endif /*morkZone_CONFIG_ARENA*/
243 
244   mork_fill fill = ioRow->mRow_Length;
245   if (ev->Good() && fill < inNewSize)  // need more cells?
246   {
247     morkCell* newCells = this->NewCells(ev, inNewSize, ioZone);
248     if (newCells) {
249       morkCell* c = newCells;  // for iterating during copy
250       morkCell* oldCells = ioRow->mRow_Cells;
251       morkCell* end = oldCells + fill;  // copy all the old cells
252       while (oldCells < end) {
253         *c++ = *oldCells++;  // bitwise copy each old cell struct
254       }
255       oldCells = ioRow->mRow_Cells;
256       ioRow->mRow_Cells = newCells;
257       ioRow->mRow_Length = (mork_u2)inNewSize;
258       ++ioRow->mRow_Seed;
259 
260       if (oldCells) this->ZapCells(ev, oldCells, fill, ioZone);
261     }
262   }
263   return (ev->Good() && ioRow->mRow_Length >= inNewSize);
264 }
265 
CutRowCells(morkEnv * ev,morkRow * ioRow,mork_size inNewSize,morkZone * ioZone)266 mork_bool morkPool::CutRowCells(morkEnv* ev, morkRow* ioRow,
267                                 mork_size inNewSize, morkZone* ioZone) {
268   MORK_USED_1(ioZone);
269 #ifdef morkZone_CONFIG_ARENA
270 #else  /*morkZone_CONFIG_ARENA*/
271 #endif /*morkZone_CONFIG_ARENA*/
272 
273   mork_fill fill = ioRow->mRow_Length;
274   if (ev->Good() && fill > inNewSize)  // need fewer cells?
275   {
276     if (inNewSize)  // want any row cells at all?
277     {
278       morkCell* newCells = this->NewCells(ev, inNewSize, ioZone);
279       if (newCells) {
280         morkCell* saveNewCells = newCells;  // Keep newcell pos
281         morkCell* oldCells = ioRow->mRow_Cells;
282         morkCell* oldEnd = oldCells + fill;       // one past all old cells
283         morkCell* newEnd = oldCells + inNewSize;  // copy only kept old cells
284         while (oldCells < newEnd) {
285           *newCells++ = *oldCells++;  // bitwise copy each old cell struct
286         }
287         while (oldCells < oldEnd) {
288           if (oldCells->mCell_Atom)  // need to unref old cell atom?
289             oldCells->SetAtom(ev, (morkAtom*)0, this);  // unref cell atom
290           ++oldCells;
291         }
292         oldCells = ioRow->mRow_Cells;
293         ioRow->mRow_Cells = saveNewCells;
294         ioRow->mRow_Length = (mork_u2)inNewSize;
295         ++ioRow->mRow_Seed;
296 
297         if (oldCells) this->ZapCells(ev, oldCells, fill, ioZone);
298       }
299     } else  // get rid of all row cells
300     {
301       morkCell* oldCells = ioRow->mRow_Cells;
302       ioRow->mRow_Cells = 0;
303       ioRow->mRow_Length = 0;
304       ++ioRow->mRow_Seed;
305 
306       if (oldCells) this->ZapCells(ev, oldCells, fill, ioZone);
307     }
308   }
309   return (ev->Good() && ioRow->mRow_Length <= inNewSize);
310 }
311 
312 // alloc & free individual instances of atoms (lots of atom subclasses):
ZapAtom(morkEnv * ev,morkAtom * ioAtom,morkZone * ioZone)313 void morkPool::ZapAtom(morkEnv* ev, morkAtom* ioAtom,
314                        morkZone* ioZone)  // any subclass (by kind)
315 {
316 #ifdef morkZone_CONFIG_ARENA
317   if (!ioAtom) ev->NilPointerWarning();  // a zone 'chip' cannot be freed
318 #else                                    /*morkZone_CONFIG_ARENA*/
319   MORK_USED_1(ioZone);
320   if (ioAtom) mPool_Heap->Free(ev->AsMdbEnv(), ioAtom);
321 #endif                                   /*morkZone_CONFIG_ARENA*/
322 }
323 
NewRowOidAtom(morkEnv * ev,const mdbOid & inOid,morkZone * ioZone)324 morkOidAtom* morkPool::NewRowOidAtom(morkEnv* ev, const mdbOid& inOid,
325                                      morkZone* ioZone) {
326   morkOidAtom* newAtom = 0;
327 
328 #ifdef morkZone_CONFIG_ARENA
329   // a zone 'chip' remembers no size, and so cannot be deallocated:
330   newAtom = (morkOidAtom*)ioZone->ZoneNewChip(ev, sizeof(morkOidAtom));
331 #else  /*morkZone_CONFIG_ARENA*/
332   MORK_USED_1(ioZone);
333   mPool_Heap->Alloc(ev->AsMdbEnv(), sizeof(morkOidAtom), (void**)&newAtom);
334 #endif /*morkZone_CONFIG_ARENA*/
335 
336   if (newAtom) newAtom->InitRowOidAtom(ev, inOid);
337   return newAtom;
338 }
339 
NewTableOidAtom(morkEnv * ev,const mdbOid & inOid,morkZone * ioZone)340 morkOidAtom* morkPool::NewTableOidAtom(morkEnv* ev, const mdbOid& inOid,
341                                        morkZone* ioZone) {
342   morkOidAtom* newAtom = 0;
343 
344 #ifdef morkZone_CONFIG_ARENA
345   // a zone 'chip' remembers no size, and so cannot be deallocated:
346   newAtom = (morkOidAtom*)ioZone->ZoneNewChip(ev, sizeof(morkOidAtom));
347 #else  /*morkZone_CONFIG_ARENA*/
348   MORK_USED_1(ioZone);
349   mPool_Heap->Alloc(ev->AsMdbEnv(), sizeof(morkOidAtom), (void**)&newAtom);
350 #endif /*morkZone_CONFIG_ARENA*/
351   if (newAtom) newAtom->InitTableOidAtom(ev, inOid);
352   return newAtom;
353 }
354 
NewAnonAtom(morkEnv * ev,const morkBuf & inBuf,mork_cscode inForm,morkZone * ioZone)355 morkAtom* morkPool::NewAnonAtom(morkEnv* ev, const morkBuf& inBuf,
356                                 mork_cscode inForm, morkZone* ioZone)
357 // if inForm is zero, and inBuf.mBuf_Fill is less than 256, then a 'wee'
358 // anon atom will be created, and otherwise a 'big' anon atom.
359 {
360   morkAtom* newAtom = 0;
361 
362   mork_bool needBig = (inForm || inBuf.mBuf_Fill > 255);
363   mork_size size = (needBig) ? morkBigAnonAtom::SizeForFill(inBuf.mBuf_Fill)
364                              : morkWeeAnonAtom::SizeForFill(inBuf.mBuf_Fill);
365 
366 #ifdef morkZone_CONFIG_ARENA
367   // a zone 'chip' remembers no size, and so cannot be deallocated:
368   newAtom = (morkAtom*)ioZone->ZoneNewChip(ev, size);
369 #else  /*morkZone_CONFIG_ARENA*/
370   MORK_USED_1(ioZone);
371   mPool_Heap->Alloc(ev->AsMdbEnv(), size, (void**)&newAtom);
372 #endif /*morkZone_CONFIG_ARENA*/
373   if (newAtom) {
374     if (needBig)
375       ((morkBigAnonAtom*)newAtom)->InitBigAnonAtom(ev, inBuf, inForm);
376     else
377       ((morkWeeAnonAtom*)newAtom)->InitWeeAnonAtom(ev, inBuf);
378   }
379   return newAtom;
380 }
381 
NewBookAtom(morkEnv * ev,const morkBuf & inBuf,mork_cscode inForm,morkAtomSpace * ioSpace,mork_aid inAid,morkZone * ioZone)382 morkBookAtom* morkPool::NewBookAtom(morkEnv* ev, const morkBuf& inBuf,
383                                     mork_cscode inForm, morkAtomSpace* ioSpace,
384                                     mork_aid inAid, morkZone* ioZone)
385 // if inForm is zero, and inBuf.mBuf_Fill is less than 256, then a 'wee'
386 // book atom will be created, and otherwise a 'big' book atom.
387 {
388   morkBookAtom* newAtom = 0;
389 
390   mork_bool needBig = (inForm || inBuf.mBuf_Fill > 255);
391   mork_size size = (needBig) ? morkBigBookAtom::SizeForFill(inBuf.mBuf_Fill)
392                              : morkWeeBookAtom::SizeForFill(inBuf.mBuf_Fill);
393 
394 #ifdef morkZone_CONFIG_ARENA
395   // a zone 'chip' remembers no size, and so cannot be deallocated:
396   newAtom = (morkBookAtom*)ioZone->ZoneNewChip(ev, size);
397 #else  /*morkZone_CONFIG_ARENA*/
398   MORK_USED_1(ioZone);
399   mPool_Heap->Alloc(ev->AsMdbEnv(), size, (void**)&newAtom);
400 #endif /*morkZone_CONFIG_ARENA*/
401   if (newAtom) {
402     if (needBig)
403       ((morkBigBookAtom*)newAtom)
404           ->InitBigBookAtom(ev, inBuf, inForm, ioSpace, inAid);
405     else
406       ((morkWeeBookAtom*)newAtom)->InitWeeBookAtom(ev, inBuf, ioSpace, inAid);
407   }
408   return newAtom;
409 }
410 
NewBookAtomCopy(morkEnv * ev,const morkBigBookAtom & inAtom,morkZone * ioZone)411 morkBookAtom* morkPool::NewBookAtomCopy(morkEnv* ev,
412                                         const morkBigBookAtom& inAtom,
413                                         morkZone* ioZone)
414 // make the smallest kind of book atom that can hold content in inAtom.
415 // The inAtom parameter is often expected to be a staged book atom in
416 // the store, which was used to search an atom space for existing atoms.
417 {
418   morkBookAtom* newAtom = 0;
419 
420   mork_cscode form = inAtom.mBigBookAtom_Form;
421   mork_fill fill = inAtom.mBigBookAtom_Size;
422   mork_bool needBig = (form || fill > 255);
423   mork_size size = (needBig) ? morkBigBookAtom::SizeForFill(fill)
424                              : morkWeeBookAtom::SizeForFill(fill);
425 
426 #ifdef morkZone_CONFIG_ARENA
427   // a zone 'chip' remembers no size, and so cannot be deallocated:
428   newAtom = (morkBookAtom*)ioZone->ZoneNewChip(ev, size);
429 #else  /*morkZone_CONFIG_ARENA*/
430   MORK_USED_1(ioZone);
431   mPool_Heap->Alloc(ev->AsMdbEnv(), size, (void**)&newAtom);
432 #endif /*morkZone_CONFIG_ARENA*/
433   if (newAtom) {
434     morkBuf buf(inAtom.mBigBookAtom_Body, fill);
435     if (needBig)
436       ((morkBigBookAtom*)newAtom)
437           ->InitBigBookAtom(ev, buf, form, inAtom.mBookAtom_Space,
438                             inAtom.mBookAtom_Id);
439     else
440       ((morkWeeBookAtom*)newAtom)
441           ->InitWeeBookAtom(ev, buf, inAtom.mBookAtom_Space,
442                             inAtom.mBookAtom_Id);
443   }
444   return newAtom;
445 }
446 
NewFarBookAtomCopy(morkEnv * ev,const morkFarBookAtom & inAtom,morkZone * ioZone)447 morkBookAtom* morkPool::NewFarBookAtomCopy(morkEnv* ev,
448                                            const morkFarBookAtom& inAtom,
449                                            morkZone* ioZone)
450 // make the smallest kind of book atom that can hold content in inAtom.
451 // The inAtom parameter is often expected to be a staged book atom in
452 // the store, which was used to search an atom space for existing atoms.
453 {
454   morkBookAtom* newAtom = 0;
455 
456   mork_cscode form = inAtom.mFarBookAtom_Form;
457   mork_fill fill = inAtom.mFarBookAtom_Size;
458   mork_bool needBig = (form || fill > 255);
459   mork_size size = (needBig) ? morkBigBookAtom::SizeForFill(fill)
460                              : morkWeeBookAtom::SizeForFill(fill);
461 
462 #ifdef morkZone_CONFIG_ARENA
463   // a zone 'chip' remembers no size, and so cannot be deallocated:
464   newAtom = (morkBookAtom*)ioZone->ZoneNewChip(ev, size);
465 #else  /*morkZone_CONFIG_ARENA*/
466   MORK_USED_1(ioZone);
467   mPool_Heap->Alloc(ev->AsMdbEnv(), size, (void**)&newAtom);
468 #endif /*morkZone_CONFIG_ARENA*/
469   if (newAtom) {
470     morkBuf buf(inAtom.mFarBookAtom_Body, fill);
471     if (needBig)
472       ((morkBigBookAtom*)newAtom)
473           ->InitBigBookAtom(ev, buf, form, inAtom.mBookAtom_Space,
474                             inAtom.mBookAtom_Id);
475     else
476       ((morkWeeBookAtom*)newAtom)
477           ->InitWeeBookAtom(ev, buf, inAtom.mBookAtom_Space,
478                             inAtom.mBookAtom_Id);
479   }
480   return newAtom;
481 }
482 
483 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
484