DeadObject.hpp
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*/
2 /* */
3 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved. */
4 /* Copyright (c) 2005-2009 Rexx Language Association. All rights reserved. */
5 /* */
6 /* This program and the accompanying materials are made available under */
7 /* the terms of the Common Public License v1.0 which accompanies this */
8 /* distribution. A copy is also available at the following address: */
9 /* http://www.oorexx.org/license.html */
10 /* */
11 /* Redistribution and use in source and binary forms, with or */
12 /* without modification, are permitted provided that the following */
13 /* conditions are met: */
14 /* */
15 /* Redistributions of source code must retain the above copyright */
16 /* notice, this list of conditions and the following disclaimer. */
17 /* Redistributions in binary form must reproduce the above copyright */
18 /* notice, this list of conditions and the following disclaimer in */
19 /* the documentation and/or other materials provided with the distribution. */
20 /* */
21 /* Neither the name of Rexx Language Association nor the names */
22 /* of its contributors may be used to endorse or promote products */
23 /* derived from this software without specific prior written permission. */
24 /* */
25 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
26 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
27 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
28 /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
29 /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
30 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
31 /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
32 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
33 /* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
34 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
35 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36 /* */
37 /*----------------------------------------------------------------------------*/
38 /******************************************************************************/
39 /* REXX Kernel DeadObject.hpp */
40 /* */
41 /* Primitive DeadObject class definitions */
42 /* */
43 /******************************************************************************/
44 
45 #ifndef Included_DeadObject
46 #define Included_DeadObject
47 
48 void FOUND(); void NOTFOUND();
49 /* Dead chains are doubly linked lists. The anchors are in the memoryobj dead */
50 /* arrays. The first element of each dead list is a dead object 3 words long. */
51 /* The first and third words are next and prev pointers, and the second is the */
52 /* header, just like any object. However, the header is set to 0 so that this */
53 /* element will never be used and we can recognize if the chain has useable */
54 /* elements with the expression: element->next->header. */
55 
56 
57 /* DeadObject must be kept in synch with RexxInternalObject size */
58 /* and layout */
59 class DeadObject {
60  friend class DeadObjectPool;
61 
62  public:
63  inline void *operator new(size_t size, void *address) { return address; };
64  inline void operator delete(void *, void *) {;}
65 
66  inline void addEyeCatcher(const char *string) { memcpy(VFT, string, 4); }
67  inline DeadObject(size_t objectSize) {
68  header.setObjectSize(objectSize);
69 #ifdef CHECKOREFS
70  addEyeCatcher("DEAD");
71 #endif
72  }
73 
74  // Following is a static constructor.
75  // Called during RexxMemory initialization
76  inline DeadObject() {
77  addEyeCatcher("HEAD");
79  /* Chain this deadobject to itself. */
80  next = this;
81  previous = this;
82  }
83 
84  inline void setObjectSize(size_t newSize) { header.setObjectSize(newSize); }
85  inline size_t getObjectSize() { return header.getObjectSize(); };
86 
87  inline void insertAfter(DeadObject *newDead) {
88  newDead->next = this->next;
89  newDead->previous = this;
90  this->next->previous = newDead;
91  this->next = newDead;
92  };
93 
94  inline void insertBefore(DeadObject *newDead) {
95  newDead->next = this;
96  newDead->previous = this->previous;
97  this->previous->next = newDead;
98  this->previous = newDead;
99  };
100 
101  inline void remove() {
102  this->next->previous = this->previous;
103  this->previous->next = this->next;
104  }
105 
106  inline bool isReal() { return header.getObjectSize() != 0; }
107  inline bool isHeader() { return header.getObjectSize() == 0; }
108 
109  inline void reset() {
110  /* Chain this deadobject to itself, removing all of the */
111  /* elements from the chain */
112  next = this;
113  previous = this;
114  }
115 
116  inline DeadObject *end() { return (DeadObject *)(((char *)this) + this->getObjectSize()); }
117  inline bool overlaps(DeadObject *o) { return (o >= this && o < end()) || (o->end() >= this && o->end() < this->end()); }
118 
119 
120 protected:
121  char VFT[sizeof(void *)]; /* Place Holder for virtualFuncTable */
122  /* in debug mode, holds string DEAD */
123  ObjectHeader header; /* header info just like any obj */
124  DeadObject *next; /* next dead object on this chain */
125  DeadObject *previous; /* prev dead object on this chain */
126 };
127 
128 /* A pool of dead objects. This is the anchor for a set of dead */
129 /* objects, as well as control and metric information for what is */
130 /* stored in the pool of objects. */
132 {
133  public:
134  inline DeadObjectPool() { init("Generic DeadChain"); }
135 
136  inline DeadObjectPool(const char * poolID) : anchor() {
137  init(poolID);
138  }
139 
140  inline void init(const char * poolID) {
141  this->id = poolID;
142 #ifdef MEMPROFILE /* doing memory profiling */
143  allocationCount = 0;
144  allocationReclaim = 0;
145  allocationHits = 0 ;
146  allocationMisses = 0;
147 #endif
148  }
149 
150  // the threshold for deciding the large object chain is getting fragmented.
151  // this tells us we need to move larger blocks to the front of the chain.
152  #define ReorderThreshold 100
153 
154  inline void setID(const char *poolID) { this->id = poolID; }
155  inline void empty() { anchor.reset(); }
156  inline bool isEmpty() { return anchor.next->isReal(); }
157  inline void emptySingle() { anchor.next = NULL; }
158  inline bool isEmptySingle() { return anchor.next == NULL; }
159  inline
160  void checkObjectGrain(DeadObject *obj);
161  inline void add(DeadObject *obj) {
162 // checkObjectOverlap(obj);
163 // checkObjectGrain(obj);
164  anchor.insertAfter(obj);
165  }
166  void addSortedBySize(DeadObject *obj);
167  void addSortedByLocation(DeadObject *obj);
168  void dumpMemoryProfile(FILE *outfile);
169  void checkObjectOverlap(DeadObject *obj);
170 
172  /******************************************************************************/
173  /* Function: Get the first object from the deal object pool. If the pool */
174  /* is empty, this returns NULL. If a block is returned it is removed from the*/
175  /* pool before return. */
176  /******************************************************************************/
177  {
178  DeadObject *newObject = anchor.next;
179  /* The next item could just be a pointer back to the anchor. */
180  /* If it is not, we have a real block to return. */
181  if (newObject->isReal()) {
182  /* we need to remove the object from the chain before */
183  /* returning it. */
184  newObject->remove();
185  logHit();
186  return newObject;
187  }
188  logMiss();
189  return NULL;
190  }
191  inline DeadObject *lastBlock() { return anchor.previous; }
192  inline DeadObject *firstBlock() { return anchor.next; }
193  inline DeadObject *findFit(size_t length)
194  /******************************************************************************/
195  /* Function: Find first object large enough to satisfy this request. If the */
196  /* pool is empty, this returns NULL. If a block is returned it is removed */
197  /* from the pool before return. */
198  /******************************************************************************/
199  {
200  DeadObject *newObject = anchor.next;
201  size_t newLength;
202  for (newLength = newObject->getObjectSize(); newLength != 0; newLength = newObject->getObjectSize()) {
203  if (newLength >= length) {
204  newObject->remove();
205  logHit();
206  return newObject;
207  }
208  newObject = newObject->next;
209  }
210  logMiss();
211  return NULL;
212  }
213 
214  inline DeadObject *findFit(size_t length, size_t *realLength)
215  /******************************************************************************/
216  /* Function: Find first object large enough to satisfy this request. If the */
217  /* pool is empty, this returns NULL. If a block is returned it is removed */
218  /* from the pool before return. */
219  /******************************************************************************/
220  {
221  DeadObject *newObject = anchor.next;
222  size_t newLength;
223  int probes = 1;
224  for (newLength = newObject->getObjectSize(); newLength != 0; newLength = newObject->getObjectSize()) {
225  if (newLength >= length) {
226  // we had to examine a lot of objects to get a match.
227  // it's worthwhile percolating the larger objects on the rest of the
228  // chain toward the front. We only do this when we're starting to have problems
229  // allocating objects because of fragmentation.
230  DeadObject *tailObject = newObject->next;
231 
232  newObject->remove();
233  logHit();
234  *realLength = newLength;
235  if (probes > ReorderThreshold)
236  {
237  for (size_t tailLength = tailObject->getObjectSize(); tailLength != 0; tailLength = tailObject->getObjectSize())
238  {
239  // the size we just had problems with is a good marker for
240  // selecting candidates to move toward the front. The will guarantee
241  // that a similar request for the same size will succeed faster in the future.
242  DeadObject *nextObject = tailObject->next;
243  if (tailLength > length)
244  {
245  tailObject->remove();
246  add(tailObject);
247  }
248  tailObject = nextObject;
249  }
250  }
251  return newObject;
252  }
253  probes++;
254  newObject = newObject->next;
255  }
256  logMiss();
257  return NULL;
258  }
259  DeadObject *findBestFit(size_t length);
260  DeadObject *findSmallestFit(size_t minSize);
261 
262  inline void addSingle(DeadObject *obj) {
263 // checkObjectOverlap(obj);
264 // checkObjectGrain(obj);
265  obj->next = anchor.next;
266  anchor.next = obj;
267  }
268 
269 
271  /******************************************************************************/
272  /* Function: Get the first object from the deal object pool. If the pool */
273  /* is empty, this returns NULL. If a block is returned it is removed from the*/
274  /* pool before return. */
275  /******************************************************************************/
276  {
277  DeadObject *newObject = anchor.next;
278 
279  /* if we have a real object remove it */
280  if (newObject != NULL) {
281  logHit();
282  anchor.next = newObject->next;
283  return newObject;
284  }
285  logMiss();
286  return NULL;
287  }
288 
289  private:
290 #ifdef MEMPROFILE /* doing memory profiling */
291  inline void logAllocation() { allocationCount++; }
292  inline void logReclaim() { allocationReclaim++; }
293  inline void logHit() { allocationHits++; }
294  inline void logMiss() { allocationMisses; }
295  inline void clearProfile() { allocationCount = 0; allocationReclaim = 0; allocationHits = 0; allocationMisses = 0; }
296 #else
297  inline void logAllocation() { ; }
298  inline void logReclaim() { ; }
299  inline void logHit() { ; }
300  inline void logMiss() { ; }
301  inline void clearProfile();
302 #endif
303 
304  /* the anchor position for our chain */
305  DeadObject anchor; /* the anchor position for our chain */
306  const char *id; /* identifier for the pool */
307 #ifdef MEMPROFILE /* doing memory profiling */
308  size_t allocationCount; /* the number of allocations from this chain */
309  size_t allocationReclaim; /* elements we've split into multiples for reuse */
310  size_t allocationHits; /* successful allocation requests */
311  size_t allocationMisses; /* unsuccessful allocation requests */
312 #endif
313 
314 };
315 
316 #endif
#define ReorderThreshold
Definition: DeadObject.hpp:152
void FOUND()
void NOTFOUND()
void insertAfter(DeadObject *newDead)
Definition: DeadObject.hpp:87
void remove()
Definition: DeadObject.hpp:101
DeadObject * end()
Definition: DeadObject.hpp:116
DeadObject(size_t objectSize)
Definition: DeadObject.hpp:67
bool overlaps(DeadObject *o)
Definition: DeadObject.hpp:117
char VFT[sizeof(void *)]
Definition: DeadObject.hpp:121
void setObjectSize(size_t newSize)
Definition: DeadObject.hpp:84
void reset()
Definition: DeadObject.hpp:109
DeadObject * previous
Definition: DeadObject.hpp:125
void insertBefore(DeadObject *newDead)
Definition: DeadObject.hpp:94
bool isHeader()
Definition: DeadObject.hpp:107
ObjectHeader header
Definition: DeadObject.hpp:123
bool isReal()
Definition: DeadObject.hpp:106
DeadObject * next
Definition: DeadObject.hpp:124
void addEyeCatcher(const char *string)
Definition: DeadObject.hpp:66
size_t getObjectSize()
Definition: DeadObject.hpp:85
void setID(const char *poolID)
Definition: DeadObject.hpp:154
const char * id
Definition: DeadObject.hpp:306
DeadObject * findSmallestFit(size_t minSize)
Definition: DeadObject.cpp:112
DeadObject * firstBlock()
Definition: DeadObject.hpp:192
void dumpMemoryProfile(FILE *outfile)
Definition: DeadObject.cpp:51
void emptySingle()
Definition: DeadObject.hpp:157
void checkObjectGrain(DeadObject *obj)
Definition: DeadObject.cpp:201
DeadObject * findFit(size_t length, size_t *realLength)
Definition: DeadObject.hpp:214
DeadObject * lastBlock()
Definition: DeadObject.hpp:191
void addSortedBySize(DeadObject *obj)
Definition: DeadObject.cpp:148
void logAllocation()
Definition: DeadObject.hpp:297
void checkObjectOverlap(DeadObject *obj)
Definition: DeadObject.cpp:212
void clearProfile()
DeadObject anchor
Definition: DeadObject.hpp:305
void add(DeadObject *obj)
Definition: DeadObject.hpp:161
DeadObject * findBestFit(size_t length)
Definition: DeadObject.cpp:66
DeadObject * getFirst()
Definition: DeadObject.hpp:171
void addSortedByLocation(DeadObject *obj)
Definition: DeadObject.cpp:175
void addSingle(DeadObject *obj)
Definition: DeadObject.hpp:262
DeadObject * findFit(size_t length)
Definition: DeadObject.hpp:193
DeadObjectPool(const char *poolID)
Definition: DeadObject.hpp:136
void init(const char *poolID)
Definition: DeadObject.hpp:140
bool isEmptySingle()
Definition: DeadObject.hpp:158
DeadObject * getFirstSingle()
Definition: DeadObject.hpp:270
size_t getObjectSize()
Definition: ObjectClass.hpp:94
void setObjectSize(size_t l)
Definition: ObjectClass.hpp:95