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