MemorySegment.cpp
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 */
40 /* */
41 /* Primitive Memory segment management */
42 /* */
43 /******************************************************************************/
44 #include "RexxCore.h"
45 #include "ActivityManager.hpp"
46 
47 
48 void MemorySegment::dump(const char *owner, size_t counter, FILE *keyfile, FILE *dumpfile)
49 /******************************************************************************/
50 /* Function: Dump information about an individual segment */
51 /******************************************************************************/
52 {
53  /* print header for segment */
54  fprintf(stderr,"Dumping %s Segment %zu from %p for %zu\n", owner, counter, &segmentStart, segmentSize);
55  /* now dump the segment */
56  fprintf(keyfile, "%s addr.%zu = %p\n", owner, counter, &segmentStart);
57  fprintf(keyfile, "%s size.%zu = %zu\n", owner, counter, segmentSize);
58  fwrite(&segmentStart, 1, segmentSize, dumpfile);
59 }
60 
61 
63 /******************************************************************************/
64 /* Function: return a pointer to the last object in a segment if, and only if*/
65 /* the object is a dead one. This is used to check the trailing deadspace */
66 /* in the segment for purposes of combining the segments. */
67 /******************************************************************************/
68 {
69  char *objectPtr, *endPtr;
70  char *lastObjectPtr = NULL;
71 
72  /* just scan all of the objects until we've reached the end of */
73  /* the segment */
74  for (objectPtr = start(), endPtr = end();
75  objectPtr < endPtr;
76  objectPtr += ((RexxObject *)objectPtr)->getObjectSize())
77  {
78  lastObjectPtr = objectPtr;
79  }
80 
81  if (!((RexxObject *)lastObjectPtr)->isObjectLive(memoryObject.markWord))
82  {
83  return(DeadObject *)lastObjectPtr;
84  }
85  return NULL;
86 }
87 
88 
90 /******************************************************************************/
91 /* Function: return a pointer to the first object in a segment if, and only */
92 /* if the object is a dead one. This is used to check the leading deadspace */
93 /* in the segment for purposes of combining the segments. */
94 /******************************************************************************/
95 {
96  if (!((RexxObject *)start())->isObjectLive(memoryObject.markWord))
97  {
98  return(DeadObject *)start();
99  }
100  return NULL;
101 }
102 
103 
105 /******************************************************************************/
106 /* Function: Accumulate memory statistics for a segment */
107 /******************************************************************************/
108 {
109  char *op;
110  char *ep;
111  /* for all objects in this segment */
112  for (op = start(), ep = end(); op < ep; op += ((RexxObject *)op)->getObjectSize())
113  {
114  /* record the information about this object */
115  stats->recordObject(memStats, op);
116  }
117 }
118 
119 
120 void MemorySegmentSet::dumpSegments(FILE *keyfile, FILE *dumpfile)
121 /******************************************************************************/
122 /* Function: Dump information about the each of the segments */
123 /******************************************************************************/
124 {
125  MemorySegment *segment;
126  size_t counter = 0;
127 
128  for (segment = first(); segment != NULL; segment = next(segment))
129  {
130  segment->dump(name, ++counter, keyfile, dumpfile);
131  }
132 }
133 
135 /******************************************************************************/
136 /* Function: Dump profile informaton about a segment set (empty for base */
137 /* class) */
138 /******************************************************************************/
139 {
140 }
141 
143 /******************************************************************************/
144 /* Function: Dump profile informaton about the large allocation segment set */
145 /******************************************************************************/
146 {
147  fprintf(outfile, "Memory profile for large object allocations\n\n");
148  /* all the work is done by the dead caches */
149  deadCache.dumpMemoryProfile(outfile);
150 }
151 
152 
154 /******************************************************************************/
155 /* Function: Dump profile informaton about the normal allocation segment set */
156 /******************************************************************************/
157 {
158  int i;
159 
160  fprintf(outfile, "Memory profile for normal object allocations\n\n");
161  /* all the work is done by the dead caches */
162  largeDead.dumpMemoryProfile(outfile);
163 
164  for (i = FirstDeadPool; i < DeadPools; i++) {
165  subpools[i].dumpMemoryProfile(outfile);
166  }
167 }
168 
169 
171 /******************************************************************************/
172 /* Function: do dead object overlap validation checking. */
173 /******************************************************************************/
174 {
175  /* all the work is done by the dead caches */
177 
178  for (int i = FirstDeadPool - 1; i < DeadPools; i++)
179  {
181  }
182 }
183 
184 
185 /******************************************************************************/
186 /* Function: Constructor for the large segment pool. */
187 /******************************************************************************/
189  MemorySegmentSet(mem, SET_NORMAL, "Large Allocation Segments"),
190  deadCache("Large Block Allocation Pool"), requests(0), smallestObject(0), largestObject(0) { }
191 
192 
193 /******************************************************************************/
194 /* Function: Constructor for the large segment pool. */
195 /******************************************************************************/
197  MemorySegmentSet(mem, SET_OLDSPACE, "Old Space Segments"),
198  deadCache("Old Space Allocation Pool")
199 {
200 
201 }
202 
203 
204 /******************************************************************************/
205 /* Function: Constructor for the normal segment pool. */
206 /******************************************************************************/
208  MemorySegmentSet(mem, SET_NORMAL, "Normal Allocation Segments"),
209  largeDead("Large Normal Allocation Pool")
210 {
211  /* finish setting up the allocation subpools. We set up one */
212  /* additional one, to act as a guard pool to redirect things to */
213  /* the large pool. */
214  int i;
215  for (i = 0; i < DeadPools; i++)
216  { /* there are only */
217  /* DeadPools subpools! (<, not <=) */
218  char buffer[100];
219  snprintf(buffer, sizeof buffer, "Normal allocation subpool %d for blocks of size %d", i, DeadPoolToLength(i));
220  subpools[i].setID(buffer);
221  /* make sure these are properly set up as single size */
222  /* keepers */
223  subpools[i].emptySingle();
224  /* initially, all subpools are empty, so have them skip */
225  /* directly to the dead chains. */
227  }
228  lastUsedSubpool[i] = DeadPools; /* add the final entry in */
229  /* the lastUsedSubpool table (extra) */
230 
231  /* This must be the first seg created*/
232  /* Create a segment for recovery */
233  /* doesn't need to be a full segment */
234  /* worth, 1/2 should do */
236 }
237 
238 
240 /******************************************************************************/
241 /* Function: Set up the intial normal memory allocation. */
242 /******************************************************************************/
243 {
244  /* get our first set of segments */
246 }
247 
248 
249 MemorySegment *MemorySegmentSet::allocateSegment(size_t requestLength, size_t minimumLength)
250 /******************************************************************************/
251 /* Function: Allocate a segment...designed for subclass overrides */
252 /******************************************************************************/
253 {
254  return memory->newSegment(requestLength, minimumLength);
255 }
256 
257 
258 MemorySegment *LargeSegmentSet::allocateSegment(size_t requestLength, size_t minimumLength)
259 /******************************************************************************/
260 /* Function: Allocate a segment...designed for subclass overrides */
261 /******************************************************************************/
262 {
263  return memory->newLargeSegment(requestLength, minimumLength);
264 }
265 
266 
267 MemorySegment *MemorySegmentSet::getSegment(size_t requestLength, size_t minimumLength)
268 /******************************************************************************/
269 /* Function: Locate a for a request. We try to allocate one first from */
270 /* the pool of empty segments, then go to the memory pool manager if we don't */
271 /* have one in reserve. */
272 /******************************************************************************/
273 {
274  /* see if we have an empty segment available for the full size */
275  MemorySegment *segment = findEmptySegment(requestLength);
276  /* if we can't find one, check for the minimum size first, */
277  /* before we go to the memory pool manager to get more. */
278  if (segment == NULL) {
279  segment = findEmptySegment(minimumLength);
280  /* No luck, go get a real thing to add to this. */
281  if (segment == NULL) {
282  segment = allocateSegment(requestLength, minimumLength);
283  }
284  }
285  return segment;
286 }
287 
288 
290 /******************************************************************************/
291 /* Function: Find a segment in our empty segment cache. */
292 /******************************************************************************/
293 {
294  /* scan the empty segments list */
295  MemorySegment *segment = emptySegments.next;
296  while (segment->isReal())
297  {
298  /* if this one is large enough, use it. */
299  if (segment->size() > requestLength)
300  {
301  segment->remove();
302  return segment;
303  }
304  segment = segment->next;
305  }
306  return NULL;
307 }
308 
309 
311 /******************************************************************************/
312 /* Function: Move all of our active segments back into the active cache. We */
313 /* do this because we want to try to merge segments to create larger blocks. */
314 /******************************************************************************/
315 {
316  /* scan the empty segments list */
317  MemorySegment *segment = emptySegments.next;
318  while (segment->isReal())
319  {
320  /* grab the next segment in the chain */
321  MemorySegment *nextSeg = segment->next;
322 
323  /* remove the current one from the chain */
324  segment->remove();
325  /* insert back into the active list */
326  addSegment(segment);
327  segment = nextSeg;
328  }
329 }
330 
331 
332 bool MemorySegmentSet::newSegment(size_t requestLength, size_t minimumLength)
333 /******************************************************************************/
334 /* Function: Allocate a segment and add it to the segment pool */
335 /******************************************************************************/
336 {
337  /* try to allocate a segment, and add it to the list if */
338  /* successful. This also adds the space to our dead object */
339  /* pool. */
340  MemorySegment *segment = allocateSegment(requestLength, minimumLength);
341  if (segment != NULL)
342  {
343  addSegment(segment);
344  return true;
345  }
346  return false;
347 }
348 
349 
351 /******************************************************************************/
352 /* Function: Add a dead object to the segment set. */
353 /******************************************************************************/
354 {
355  // The base class doesn't maintain a dead object pool, so this is a nop
356 }
357 
358 
360 /******************************************************************************/
361 /* Function: Add a dead object to the segment set. */
362 /******************************************************************************/
363 {
364  /* we want to keep our cache sorted by the size. */
365  deadCache.addSortedBySize(object);
366 }
367 
368 
370 /******************************************************************************/
371 /* Function: Add a dead object to the segment set. */
372 /******************************************************************************/
373 {
374  /* we want to keep our cache sorted by the size. */
375  deadCache.addSortedBySize(object);
376 }
377 
378 
380 /******************************************************************************/
381 /* Function: Add a dead object to the segment set. */
382 /******************************************************************************/
383 {
384 // checkObjectOverlap(object);
385  size_t length = object->getObjectSize();
386 
387  /* if the length is larger than the biggest subpool we */
388  /* maintain, we add this to the large block list. */
389  if (length > LargestSubpool)
390  {
391  /* ideally, we'd like to add this sorted by size, but */
392  /* this is called so frequently, attempting to sort */
393  /* degrades performance by about 10%. */
394  largeDead.add(object);
395  }
396  else
397  {
398  /* calculate the dead chain */
399  /* and add that to the appropriate chain */
400  size_t deadChain = LengthToDeadPool(length);
401  subpools[deadChain].addSingle(object);
402  /* we can mark this subpool as having items again */
403  lastUsedSubpool[deadChain] = deadChain;
404  }
405 }
406 
407 
408 void MemorySegmentSet::addDeadObject(char *object, size_t length)
409 /******************************************************************************/
410 /* Function: Add a dead object to the segment set. */
411 /******************************************************************************/
412 {
413  // The base class doesn't maintain a dead object pool, so this is a nop
414 }
415 
416 
417 void LargeSegmentSet::addDeadObject(char *object, size_t length)
418 /******************************************************************************/
419 /* Function: Add a dead object to the segment set. */
420 /******************************************************************************/
421 {
422 #ifdef VERBOSE_GC
423  if (length > largestObject)
424  {
425  largestObject = length;
426  }
427  if (length < smallestObject)
428  {
429  smallestObject = length;
430  }
431 #endif
432  /* we want to keep our cache sorted by the size. */
433  deadCache.addSortedBySize(new (object) DeadObject(length));
434 }
435 
436 
437 void OldSpaceSegmentSet::addDeadObject(char *object, size_t length)
438 /******************************************************************************/
439 /* Function: Add a dead object to the segment set. */
440 /******************************************************************************/
441 {
442  /* we want to keep our cache sorted by the size. */
443  deadCache.addSortedBySize(new (object) DeadObject(length));
444 }
445 
446 
447 void NormalSegmentSet::addDeadObject(char *object, size_t length)
448 /******************************************************************************/
449 /* Function: Add a dead object to the segment set. */
450 /******************************************************************************/
451 {
452  /* if the length is larger than the biggest subpool we */
453  /* maintain, we add this to the large block list. */
454  if (length > LargestSubpool)
455  {
456  /* ideally, we'd like to add this sorted by size, but */
457  /* this is called so frequently, attempting to sort */
458  /* degrades performance by about 10%. */
459  largeDead.add(new (object) DeadObject(length));
460  }
461  else
462  {
463  /* calculate the dead chain */
464  /* and add that to the appropriate chain */
465  size_t deadChain = LengthToDeadPool(length);
466  subpools[deadChain].addSingle(new (object) DeadObject(length));
467  /* we can mark this subpool as having items again */
468  lastUsedSubpool[deadChain] = deadChain;
469  }
470 }
471 
472 
473 void MemorySegmentSet::addSegment(MemorySegment *segment, bool createDeadObject)
474 /******************************************************************************/
475 /* Function: Add a segment to the segment pool. */
476 /******************************************************************************/
477 {
478  /* we want to keep these segments ordered by address so we can */
479  /* potentially combine them later. */
480  MemorySegment *insertPosition = anchor.next;
481  while (insertPosition->isReal())
482  {
483  /* we want to insert these in sorted order, by address. */
484  /* This allows us to merge segments later, if necessary. */
485  if (segment < insertPosition)
486  {
487  break;
488  }
489  insertPosition = insertPosition->next;
490  }
491 
492  /* first check to see if we can merge this with the previous */
493  /* segment. This will give us larger segment sections for reuse. */
494  MemorySegment *previous = insertPosition->previous;
495  if (previous->isReal() && previous->isAdjacentTo(segment))
496  {
497  /* just combine this with the previous segment and add the */
498  /* entire block as a dead object. */
499  size_t deadLength = segment->realSize();
500  previous->combine(segment);
501  memory->verboseMessage("Combining newly allocated segment of %d bytes to create new segment of %d bytes\n", deadLength, previous->size());
502  addDeadObject((char *)segment, deadLength);
503  }
504  else
505  {
506  /* insert this into position */
507  insertPosition->insertBefore(segment);
508  /* Insert the segment's dead space into the proper chain */
509  if (createDeadObject)
510  {
511  DeadObject *ptr = segment->createDeadObject();
512  addDeadObject(ptr);
513  }
514  }
515 }
516 
517 
519 /******************************************************************************/
520 /* Function: Search the cache of dead objects for an object of sufficient */
521 /* size to fulfill this request. For the default implementation, we always */
522 /* return NULL. Different segment sets may have different strategies for */
523 /* determining which block is most suitable for donation. */
524 /******************************************************************************/
525 {
526  return NULL;
527 }
528 
529 
531 /******************************************************************************/
532 /* Function: Search the cache of dead objects for an object of sufficient */
533 /* size to fulfill this request. This just uses normal large block */
534 /* allocation strategy to decide on the block to donate, give a best fit */
535 /* for the allocation. */
536 /******************************************************************************/
537 {
538  /* find a large object and return it */
539  return (DeadObject *)findLargeDeadObject(allocationLength);
540 }
541 
542 
543 DeadObject *LargeSegmentSet::donateObject(size_t allocationLength)
544 /******************************************************************************/
545 /* Function: Search the cache of dead objects for an object of sufficient */
546 /* size to fulfill this request. This just uses normal large block */
547 /* allocation strategy to decide on the block to donate, give a best fit */
548 /* for the allocation. */
549 /******************************************************************************/
550 {
551  /* find an object in the cache return it. This will likely be */
552  /* larger than the request, as we shouldn't have may small */
553  /* objects in the dead chains. */
554  return deadCache.findSmallestFit(allocationLength);
555 }
556 
557 
559 /******************************************************************************/
560 /* Function: Search the set of segments to see if it is possible to donate */
561 /* a segment to another segment set. Our preference is to give up an empty */
562 /* segment. If we don't have an empty one of sufficient size, then we'll */
563 /* see if we can split one of our segments to create a new one. */
564 /******************************************************************************/
565 {
566  /* first check for the empty one... */
567  MemorySegment *segment = findEmptySegment(allocationLength);
568  /* if no empties available, we might still be able to split off */
569  /* an empty bit. */
570  if (segment == NULL)
571  {
572  segment = splitSegment(allocationLength);
573  }
574  return segment;
575 }
576 
577 
579 /******************************************************************************/
580 /* Function: Search the set of large segments looking for a dead block large */
581 /* enough that we can split the segment and give part to the normal */
582 /* allocation heap. Our preference is a block that is at the start or end */
583 /* of a segment, but since we're in a critical memory situation right now, */
584 /* any block of sufficient size will do. NOTE: This routine can */
585 /* only be called immediately after a complete mark and sweep operation has */
586 /* been performed. We are dependent on there having been no object */
587 /* allocations since the segment information was updated. */
588 /******************************************************************************/
589 {
590  typedef enum
591  {
592  NO_SEGMENT, SPLIT_FRONT, SPLIT_REAR, SPLIT_MIDDLE
593  } SplitType;
594 
595  SplitType split = NO_SEGMENT;
596  MemorySegment *candidateSegment = NULL;
597  char *splitBlock = NULL;
598  size_t splitLength = MaximumObjectSize;
599 
600  char *objectPtr;
601 
602  /* We're basically going to perform a sweep operation on the */
603  /* large heap segment looking for a candidate segment to split. */
604  /* Our preference is for an empty block at the end of a */
605  /* segment. Second choice is an empty block at the beginning */
606  /* of the segment. Failing either of these, we'll split in the */
607  /* middle to create 3 segments. */
608  MemorySegment *segment = first();
609  while (segment != NULL)
610  {
611  char *endPtr;
612  size_t deadLength;
613  /* ok, sweep all of the objects in this segment, looking */
614  /* for one large enough. */
615  for (objectPtr = segment->start(), endPtr = segment->end(), deadLength = ((RexxObject *)objectPtr)->getObjectSize();
616  objectPtr < endPtr;
617  objectPtr += deadLength, deadLength = ((RexxObject *)objectPtr)->getObjectSize())
618  {
619  /* We're only interested in the dead objects. Note */
620  /* that since we've just finished a GC operation, we */
621  /* shouldn't see any adjacent dead objects. */
622  if (!((RexxObject *)objectPtr)->isObjectLive(memoryObject.markWord))
623  {
624  /* have we found an empty part large enough to */
625  /* convert into a segment? */
626  if (deadLength >= allocationLength && deadLength>= MinimumSegmentSize)
627  {
628  /* is this at the end of the segment? This is a */
629  /* perfect candidate. we'll remember this for */
630  /* later. */
631  if (segment->isLastBlock(objectPtr, deadLength))
632  {
633  /* we might already have a rear split candidate. */
634  /* Take the smaller of the possibilities. */
635  if (split == SPLIT_REAR)
636  {
637  /* already have a smaller one? We'll just skip this */
638  if (splitLength < deadLength)
639  {
640  break;
641  }
642  }
643  /* record the information, and skip to the next */
644  /* segment. */
645  split = SPLIT_REAR;
646  candidateSegment = segment;
647  splitBlock = objectPtr;
648  splitLength = deadLength;
649  break;
650  }
651  /* This might be at the beginning of the */
652  /* segment. We only use this if we don't have */
653  /* something more suitable already. */
654  else if (segment->isFirstBlock(objectPtr))
655  {
656  /* if we've already found a rear split, we */
657  /* don't want this one. */
658  if (split == SPLIT_REAR)
659  {
660  continue;
661  }
662  /* we'll also ignore this if we've found a shorter front block */
663  if (split == SPLIT_FRONT && splitLength < deadLength)
664  {
665  continue;
666  }
667  split = SPLIT_FRONT;
668  candidateSegment = segment;
669  splitBlock = objectPtr;
670  splitLength = deadLength;
671  /* we continue rather than break here, */
672  /* because this segment might have a better */
673  /* candidate on the end. */
674  continue;
675  }
676  /* we've found a block on the middle. This is */
677  /* our last choice, so we only use this if we */
678  /* haven't found anything better. */
679  else
680  {
681  /* we'll also ignore this if we've found a */
682  /* shorter front block */
683  if ((split == SPLIT_MIDDLE && splitLength < deadLength))
684  {
685  continue;
686  }
687  /* have we found any of the other options? Skip it also. */
688  if (split != NO_SEGMENT)
689  {
690  continue;
691  }
692  split = SPLIT_MIDDLE;
693  candidateSegment = segment;
694  splitBlock = objectPtr;
695  splitLength = deadLength;
696  /* we continue rather than break here, */
697  /* because this segment might have a better */
698  /* candidate on the end. */
699  continue;
700  }
701  }
702  }
703  }
704  segment = next(segment);
705  }
706 
707  /* now we need to process the "best" split candidate block. */
708  switch (split)
709  {
710  /* no block found that we can convert into a segment. */
711  /* We'll just have to steal a dead block off of the chain. */
712  case NO_SEGMENT: {
713  return NULL;
714  }
715  /* The preferred (and easiest split). Just remove the */
716  /* block from the dead chain, adjust the original segment */
717  /* size, and make a new one from this block. */
718  case SPLIT_REAR: {
719  DeadObject *deadObject = (DeadObject *)splitBlock;
720  /* remove this from the dead chain. */
721  deadObject->remove();
722  /* And turn this into a segment */
723  MemorySegment *newSeg = new (splitBlock) MemorySegment(splitLength - MemorySegmentOverhead);
724  /* reduce the length of the segment we took this from */
725  candidateSegment->shrink(splitLength);
726  return newSeg;
727  }
728  /* split a segment in the front. We need to create two */
729  /* segments for this one. */
730  case SPLIT_FRONT: {
731  DeadObject *deadObject = (DeadObject *)splitBlock;
732  /* remove this from the dead chain. */
733  deadObject->remove();
734  /* remove the existing segment from the chain. */
735  removeSegment(candidateSegment);
736  /* calculate the adjusted length of this */
737  size_t tailLength = candidateSegment->realSize() - splitLength;
738  /* go to the start of the tail end segment we're */
739  /* leaving behind. Note that since we increment the */
740  /* length of the starting block from the front of the */
741  /* segment, we end up leaving a header space at the */
742  /* front of the created tail portion. */
743  MemorySegment *tailSegment = (MemorySegment *)( ((char*) candidateSegment) + splitLength);
744  /* create two segments out of this */
745  MemorySegment *newSeg = new (candidateSegment) MemorySegment(splitLength);
746  tailSegment = new (tailSegment) MemorySegment(tailLength);
747  /* Anchor new segment at end of list */
748  addSegment(tailSegment, false);
749  return newSeg;
750  }
751  /* we're taking a block from the middle of the segment. We */
752  /* need to create segments in front, and back. */
753  case SPLIT_MIDDLE: {
754  DeadObject *deadObject = (DeadObject *)splitBlock;
755  /* remove this from the dead chain. */
756  deadObject->remove();
757  /* remove the existing segment from the chain. */
758  removeSegment(candidateSegment);
759  /* get the length of data in the front segment part */
760  size_t frontLength = splitBlock - candidateSegment->start();
761  /* calculate the size of the data in the tail end piece */
762  size_t tailLength = candidateSegment->size() - (frontLength + splitLength);
763  /* address the start of the tail segment, accounting */
764  /* for the segment header we're adding on to the front */
765  /* of it (which comes from the end of the segment block */
766  /* we're stealing) */
767  MemorySegment *tailSegment = (MemorySegment *)(splitBlock + splitLength - MemorySegmentOverhead);
768  /* we need to reduce this by two segment headers...one */
769  /* for the segment we're stealing, and one for the */
770  /* trailing segment */
771  splitLength -= (2 * MemorySegmentOverhead);
772  /* create two segments out of this */
773  MemorySegment *newSeg = new (splitBlock) MemorySegment(splitLength);
774  tailSegment = new (tailSegment) MemorySegment(tailLength);
775  candidateSegment = new (candidateSegment) MemorySegment(frontLength);
776  /* Anchor the original pieces on the segment chain */
777  addSegment(tailSegment, false);
778  addSegment(candidateSegment, false);
779  return newSeg;
780  }
781  }
782  return NULL;
783 }
784 
785 
787 /******************************************************************************/
788 /* Function: Decide if we should add additional segments to the normal heap */
789 /* based on the amount of free space we have after a garbage collection. If */
790 /* we're starting to run full, then we should expand the heap to prevent */
791 /* recycling the garbage collector to reclaim minimal amounts of storage that */
792 /* is immediately reused, causing another GC cycle. */
793 /******************************************************************************/
794 {
795  float freePercent = freeMemoryPercentage();
796 
797  memory->verboseMessage("Normal segment set free memory percentage is %d\n", (int)(freePercent * 100.0));
798 
799  /* if we are less than 30% full, we should try to expand to the */
800  /* 30% mark. */
801  if (freePercent < NormalMemoryExpansionThreshold)
802  {
803  /* get a recommendation on how large the heap should be */
804  size_t recommendedSize = recommendedMemorySize();
805  size_t newDeadBytes = recommendedSize - liveObjectBytes;
806  /* calculate the number of new bytes we need to add reach */
807  /* our memory threshold. It will be the job of others to */
808  /* translate this into segment sized units. */
809  size_t expansionSize = newDeadBytes - deadObjectBytes;
810  return expansionSize;
811  }
812  /* no expansion required yet. */
813  return 0;
814 }
815 
816 
818 /******************************************************************************/
819 /* Function: Decide if we should add additional segments to the normal heap */
820 /* based on the amount of free space we have after a garbage collection. If */
821 /* we're starting to run full, then we should expand the heap to prevent */
822 /* recycling the garbage collector to reclaim minimal amounts of storage that */
823 /* is immediately reused, causing another GC cycle. */
824 /******************************************************************************/
825 {
826  /* the base memory set has no expansion algorithm...always return 0 */
827  return 0;
828 }
829 
830 
832 /******************************************************************************/
833 /* Function: Decide if we should add try to remove memory from a segment set.*/
834 /* The value returned is the suggested number of bytes we should try to. */
835 /* This is only a suggestion based on a best guess, and we'll only remove */
836 /* things in full segment units. */
837 /******************************************************************************/
838 {
839  /* the base memory set has no contraction algorithm...always return 0 */
840  return 0;
841 }
842 
843 
845 /******************************************************************************/
846 /* Function: Decide if we should add try to remove memory from a segment set.*/
847 /* The value returned is the suggested number of bytes we should try to. */
848 /* This is only a suggestion based on a best guess, and we'll only remove */
849 /* things in full segment units. */
850 /******************************************************************************/
851 {
852  float freePercent = freeMemoryPercentage();
853 
854  /* if we have predominately free space in the heap, we should try to give some back */
855  if (freePercent > NormalMemoryContractionThreshold)
856  {
857  /* if we're still working on our initial allocation set, we */
858  /* don't want to try to shrink that. */
860  {
861  return 0;
862  }
863  /* Calculate an amount to shrink this by. If it ends up */
864  /* being a small amount, we'll live with the overage. */
866  }
867  /* no expansion required yet. */
868  return 0;
869 }
870 
871 
873 /******************************************************************************/
874 /* Function: Decide if we should add or removed segments from the segment */
875 /* set based on the current state of the heap immediately following a sweep. */
876 /* We want to avoid thrashing the garbage collector because of chronic low */
877 /* memory conditions. If we wait until we get an actual allocation failure, */
878 /* we will end up in a state where we're constantly running a mark-and-sweep */
879 /*to reclaim just a tiny amount of storage, and then repeat. We will try to */
880 /* keep the heap with appropriate free space limits. */
881 /* */
882 /* Conversely, if we find ourselves with a lot of empty space, we'll see if */
883 /* we can remove segments from the segment set. For the small allocation */
884 /* pools, it is not likley we'd be able to do this, but since we try to */
885 /* maintain large blocks whenever possible, it can happen. For the larger */
886 /* allocation pool, we are more likely to end up with empty segments we can */
887 /* give back. */
888 /******************************************************************************/
889 {
890  /* see if a proactive expansion is advised, based on our */
891  /* current state. */
892  size_t suggestedExpansion = suggestMemoryExpansion();
893  /* if we've decided we need to expand, */
894  if (suggestedExpansion > 0)
895  {
896  /* go add as many segments as are required to reach that */
897  /* level. */
898  memory->verboseMessage("Expanding normal segment set by %d\n", suggestedExpansion);
899  addSegments(suggestedExpansion);
900  }
901 #if 0
902 // else {
903  /* get a suggested contraction amount. There is no sense */
904  /* in trying to release less than a segment. */
905 // size_t suggestedContraction = suggestMemoryContraction();
906 // if (suggestedContraction >= SegmentDeadSpace) {
907  /* see if we can't release some of the space we have. */
908 // releaseEmptySegments(suggestedContraction);
909 // }
910 // }
911 #endif
912 }
913 
914 
916 /******************************************************************************/
917 /* Function: Scan the loaded segments, searching for empty segments that */
918 /* can be released. We will release up to the maximum recommended amount. */
919 /******************************************************************************/
920 {
921  /* round this up to the next segment boundary. We're already at */
922  /* a pretty good overage point, so we can afford to round this */
923  /* up. */
924  releaseSize = roundSegmentBoundary(releaseSize);
925  MemorySegment *segment = first();
926  for (;segment != NULL; segment = next(segment))
927  {
928  /* is this an empty segment that fits within our criteria? */
929  if (segment->isEmpty() && segment->size() <= releaseSize)
930  {
931  /* we need to step back one segment for the looping, as */
932  /* we're going to cut this segment out from the herd. */
933  MemorySegment *previous = segment->previous;
934  /* remove this from the pool */
935  removeSegmentAndStorage(segment);
936  /* return this segment to the memory pool */
937  releaseSegment(segment);
938  /* pick up the loop with the previous segment (which */
939  /* will immediately step to the segment following the */
940  /* one we just released). */
941  segment = previous;
942  }
943  }
944 }
945 
946 
948 {
949  /* just move this to the empty segment chain */
950  emptySegments.insertBefore(segment);
951  /* the count is only of the active segments */
952  count--;
953 }
954 
955 
956 void MemorySegmentSet::addSegments(size_t requiredSpace)
957 /******************************************************************************/
958 /* Function: Add segments to the segment set until the required space is */
959 /* achieved or we've had a real memory failure. Our preference is to add this*/
960 /* in one chunk, but we'll subdivide down to smaller units as long as we're */
961 /* still getting the segments we require. */
962 /******************************************************************************/
963 {
964  /* this may take several passes to achieve */
965  for (;;)
966  {
967  /* figure out how large this should be */
968  size_t segmentSize = calculateSegmentAllocation(requiredSpace);
969  size_t minSize = segmentSize >= LargeSegmentDeadSpace ? LargeSegmentDeadSpace : SegmentDeadSpace;
970  /* try to allocate a new segment */
971  MemorySegment *newSeg = allocateSegment(segmentSize, minSize);
972  if (newSeg == NULL)
973  {
974  /* if we already failed to get our "minimum minimum", just quit now. */
975  if (minSize == SegmentDeadSpace)
976  {
977  return;
978  }
979  /* try for a single segment allocation. If that */
980  /* fails...we have nothing else we can do. */
982  if (newSeg == NULL)
983  {
984  return;
985  }
986  }
987 
988  /* we have a segment. Add this to the segment pool */
989  /* (and add the dead space to the available memory). */
990  addSegment(newSeg);
991  segmentSize = newSeg->size();
992  /* if we've got what's needed, we're out of here. */
993  if (segmentSize >= requiredSpace)
994  {
995  return;
996  }
997  /* reduce the size and try for some more */
998  requiredSpace -= segmentSize;
999  }
1000 }
1001 
1002 
1004 /******************************************************************************/
1005 /* Function: Handle all segment set pre-sweep initialization. */
1006 /******************************************************************************/
1007 {
1008  liveObjectBytes = 0;
1009  deadObjectBytes = 0;
1010 }
1011 
1012 
1014 /******************************************************************************/
1015 /* Function: Handle all segment set pre-sweep initialization. */
1016 /******************************************************************************/
1017 {
1019 
1020  /* we're about to rebuild the dead chains during the sweep, so */
1021  /* initialize all of these now. */
1022  largeDead.empty();
1023  for (int i = FirstDeadPool; i < DeadPools; i++)
1024  {
1025  subpools[i].emptySingle();
1026  }
1027 }
1028 
1029 
1031 /******************************************************************************/
1032 /* Function: Handle all segment set pre-sweep initialization. */
1033 /******************************************************************************/
1034 {
1036 
1037  /* we're about to rebuild the dead chains during the sweep, so */
1038  /* initialize all of these now. */
1039  deadCache.empty();
1040  requests = 0;
1041  largestObject = 0;
1042  smallestObject = 999999999;
1043 }
1044 
1045 
1047 /******************************************************************************/
1048 /* Function: Handle all segment set post sweep activities. */
1049 /******************************************************************************/
1050 {
1051 }
1052 
1053 
1055 /******************************************************************************/
1056 /* Function: Handle all segment set post sweep activities. */
1057 /******************************************************************************/
1058 {
1059  /* Now we can optimize the look-aside entries for the small */
1060  /* dead chains. By checking to see which chains have blocks in */
1061  /* them, we can potentially skip a lot of check/searching on an */
1062  /* allocation request. */
1063  for (int i = FirstDeadPool; i < DeadPools; i++)
1064  {
1065  if (!subpools[i].isEmptySingle())
1066  {
1067  /* point this back at itself */
1068  lastUsedSubpool[i] = i;
1069  }
1070  else
1071  {
1072  /* default to the "skip to the end" location */
1073  int usePool = DeadPools;
1074  int j;
1075  /* scan all of the higher pools looking for the first hit */
1076  for (j = i + 1; j < DeadPools; j++)
1077  {
1078  if (!subpools[i].isEmptySingle())
1079  {
1080  usePool = j;
1081  break;
1082  }
1083  }
1084 
1085  /* this will now be guaranteed to go to the correct */
1086  /* location on each request. */
1087  lastUsedSubpool[i] = usePool;
1088  }
1089  }
1090 }
1091 
1092 
1094 /******************************************************************************/
1095 /* Function: Handle all segment set post sweep activities. */
1096 /******************************************************************************/
1097 {
1098 #ifdef VERBOSE_GC
1099  memory->verboseMessage("Large segment sweep complete. Largest block is %d, smallest block is %d\n", largestObject, smallestObject);
1100 #endif
1101 }
1102 
1103 inline bool objectIsLive(char *obj, size_t mark) {return ((RexxObject *)obj)->isObjectLive(mark); }
1104 inline bool objectIsNotLive(char *obj, size_t mark) {return ((RexxObject *)obj)->isObjectDead(mark); }
1105 
1107 /******************************************************************************/
1108 /* */
1109 /* This routine does a sweep of all segments devoted to "normal" size storage */
1110 /* allocations. */
1111 /******************************************************************************/
1112 {
1113  MemorySegment *sweepSegment;
1114  char *objectPtr, *endPtr, *nextObjectPtr;
1115  size_t deadLength;
1116  size_t bytes;
1117  size_t mark = memoryObject.markWord;
1118 
1119  /* do the sweep preparation (this differs for particular segment */
1120  /* set implemenation) */
1121  prepareForSweep();
1122  /* go through the segments in order, until we've swept the */
1123  /* entire set */
1124  sweepSegment = first();
1125  while (sweepSegment != NULL)
1126  {
1127  /* clear our live objects counter */
1128  sweepSegment->liveObjects = 0;
1129  /* for all objects in segment */
1130  for (objectPtr = sweepSegment->start(), endPtr = sweepSegment->end(); objectPtr < endPtr; )
1131  {
1132  /* this a live object? */
1133  if (objectIsLive(objectPtr, mark))
1134  {
1135  /* Get size of object for stats and */
1136  bytes = ((RexxObject *)objectPtr)->getObjectSize();
1137  /* do any reference checking */
1138  validateObject(bytes);
1139  /* update our tracking counters */
1140  liveObjectBytes += bytes;
1141  /* point to next object in segment. */
1142  objectPtr += bytes;
1143  /* bump the live object counter */
1144  sweepSegment->liveObjects++;
1145  }
1146 
1147  else
1148  {
1149  /* get the object's size */
1150  deadLength = ((RexxObject *)objectPtr)->getObjectSize();
1151  /* do any reference checking */
1152  validateObject(deadLength);
1153 
1154  for (nextObjectPtr = objectPtr + deadLength;
1155  (nextObjectPtr < endPtr) && objectIsNotLive(nextObjectPtr, mark);
1156  nextObjectPtr += bytes)
1157  {
1158  /* get the object size */
1159  bytes = ((RexxObject *)nextObjectPtr)->getObjectSize();
1160  /* do any reference checking */
1161  validateObject(bytes);
1162  /* add in the size of this dead body */
1163  deadLength += bytes;
1164  }
1165  /* add this to the dead counters */
1166  deadObjectBytes += deadLength;
1167  /* now add to the dead chain */
1168  addDeadObject((char *)objectPtr, deadLength);
1169  /* update object Pointers. */
1170  objectPtr += deadLength;
1171  }
1172  }
1173  /* go to the next segment in the pool*/
1174  sweepSegment = next(sweepSegment);
1175  }
1176  /* now do any of the sweep post-processing. */
1178 }
1179 
1180 
1182 /******************************************************************************/
1183 /* Function: Scan a segment set after a sweep operation, collecting */
1184 /* any empty segments. This is a nop for the base MemorySegmentSet class. */
1185 /******************************************************************************/
1186 {
1187 }
1188 
1189 
1191  DeadObject *object, /* the object we're splitting */
1192  size_t allocationLength, /* the request length, already rounded to an appropriate boundary */
1193  size_t splitMinimum) /* the minimum size we're willing to split */
1194 /******************************************************************************/
1195 /* Function: Process a dead object and potentially split the object into */
1196 /* an allocated object and a second dead object that will be added back into */
1197 /* the appropriate pool of dead objects. */
1198 /******************************************************************************/
1199 {
1200  size_t deadLength = object->getObjectSize() - allocationLength;
1201  /* we need to keep all of these sizes as ObjectGrain multiples, */
1202  /* so round it down...the allocation will get all of the extra. */
1203  /* deadLength = rounddown(deadLength, ObjectGrain); */
1204 
1205  /* remainder too small or this is a very large request */
1206  /* is the remainder two small to reuse? */
1207  if (deadLength < splitMinimum)
1208  {
1209  /* over allocate this object */
1210  allocationLength += deadLength;
1211  }
1212  else
1213  {
1214  /* Yes, so pull new object out of the front of the dead */
1215  /* object, adjust the size of the Dead object. We want */
1216  /* to use the front rather than the back so that if we */
1217  /* hit the need to split a segment because of low memory */
1218  /* conditions, we increase the probability that we'll be */
1219  /* able to use the end of the segment. */
1220  DeadObject *largeObject = (DeadObject *)(((char *)object) + allocationLength);
1221  /* and reinsert into the the dead object pool */
1222  addDeadObject((char *)largeObject, deadLength);
1223  }
1224  /* Adjust the size of this object to the requested allocation length */
1225  ((RexxObject *)object)->setObjectSize(allocationLength);
1226  return(RexxObject *)object;
1227 }
1228 
1229 
1231  size_t allocationLength) /* the request length, already rounded to an appropriate boundary */
1232 /******************************************************************************/
1233 /* Function: Search the segment set for a block of the requested length. */
1234 /* If a block is found, the block will be subdivided if necessary, with the */
1235 /* remainder portion placed back on the proper chain. */
1236 /******************************************************************************/
1237 {
1238  /* Go through the LARGEDEAD object looking for the 1st */
1239  /* one we can use either our object is too big for all the */
1240  /* small chains, or the small chains are depleted.... */
1241  DeadObject *largeObject = largeDead.findFit(allocationLength);
1242  if (largeObject != NULL)
1243  { /* did we find an object? */
1244  /* potentially split this object into a smaller unit so we */
1245  /* can reuse the remainder. */
1246  return splitDeadObject(largeObject, allocationLength, MinimumObjectSize);
1247  }
1248  return OREF_NULL;
1249 }
1250 
1251 
1252 RexxObject *NormalSegmentSet::findObject(size_t allocationLength)
1253 /******************************************************************************/
1254 /* Function: Find a dead object in the caches for the NormalSegmentSet. */
1255 /******************************************************************************/
1256 {
1257  /* this is just a non-inline version of the allocation routine */
1258  /* routine to be used during low memory situations. */
1259  return allocateObject(allocationLength);
1260 }
1261 
1262 
1264 /******************************************************************************/
1265 /* Function: Allocate an object from the normal object segment pool. */
1266 /******************************************************************************/
1267 {
1268  /* Step 2, force a GC */
1269  memory->collect();
1270  /* now that we have good GC data, decide if we need to adjust */
1271  /* the heap size. */
1272  adjustMemorySize();
1273  /* Step 3, see if can allocate now */
1274  RexxObject *newObject = findObject(allocationLength);
1275  /* still no luck? */
1276  if (newObject == OREF_NULL)
1277  {
1278  /* it is possible that the adjustment routines did not add */
1279  /* anything because, yet we were unable to allocate a block */
1280  /* because we're highly fragmented. Try adding a new segment */
1281  /* now, before going to the extreme methods. */
1283  /* see if can allocate now */
1284  newObject = findObject(allocationLength);
1285  /* still no luck? */
1286  if (newObject == OREF_NULL)
1287  {
1288  /* We might be able to steal something from the */
1289  /* large allocations. This will also steal the recovery */
1290  /* segment as a last ditch effort */
1291  memory->scavengeSegmentSets(this, allocationLength);
1292  /* see if can allocate now */
1293  newObject = findObject(allocationLength);
1294  /* still no luck? */
1295  if (newObject == OREF_NULL)
1296  {
1297  /* absolute last chance to fix this. We allocated a */
1298  /* recovery segment at start up and have been hiding this */
1299  /* in our back pocket. It is now time to bring this into */
1300  /* play, because we're running on fumes! */
1301  if (recoverSegment != NULL)
1302  {
1304  recoverSegment = NULL;
1305  /* And try to find it once more */
1306  newObject = findObject(allocationLength);
1307  }
1308  if (newObject == OREF_NULL)
1309  {
1310  /* can't allocate, report resource error. */
1312  }
1313  }
1314  }
1315  }
1316  return newObject;
1317 }
1318 
1319 
1320 RexxObject *LargeSegmentSet::findObject(size_t allocationLength)
1321 /******************************************************************************/
1322 /* Function: Locate an object is the dead object cache maintained for large */
1323 /* object allocations. */
1324 /******************************************************************************/
1325 {
1326  /* this is just a space-saving non-inline version of allocateObject */
1327  return allocateObject(allocationLength);
1328 }
1329 
1330 
1332 /******************************************************************************/
1333 /* Function: Allocate a large block of memory. This will manage allocation */
1334 /* of larger memory requests. This will search our large block allocation */
1335 /* chains, and if a block is not found, will decide whether to immediately */
1336 /* allocate additional memory for large allocations or force a garbage */
1337 /* collection cycle. As a last gasp effort, we'll also try to "borrow" a */
1338 /* block of memory from the pool reserved for smaller allocations. */
1339 /******************************************************************************/
1340 {
1341  /* Step 2, decide to expand the heap or GC, or both */
1342  expandOrCollect(allocationLength);
1343  /* Step 3, see if can allocate now */
1344  RexxObject *newObject = findObject(allocationLength);
1345  if (newObject == OREF_NULL)
1346  { /* still no luck? */
1347  /* Step 4, force a heap expansion, if we can */
1348  expandSegmentSet(allocationLength);
1349  /* merge the expanded segments into our current set. */
1350  /* This could potentially prolong the interval between */
1351  /* collection cycles. */
1352  mergeSegments(allocationLength);
1353  /* Step 5, see if can allocate now */
1354  newObject = findObject(allocationLength);
1355  /* still no luck? */
1356  if (newObject == OREF_NULL)
1357  {
1358  /* We'll take one last chance. We don't really like */
1359  /* to do this, but we might be able to steal a block */
1360  /* off of the normal allocation chain. */
1361  memory->scavengeSegmentSets(this, allocationLength);
1362  /* Last chance, see if can allocate now */
1363  newObject = findObject(allocationLength);
1364  if (newObject == OREF_NULL)
1365  {/* still no luck? */
1366  /* can't allocate, report resource error. */
1368  }
1369  }
1370  }
1371  /* if we got a real object, count this.... */
1372  if (newObject != OREF_NULL)
1373  {
1374  requests++;
1375  }
1376  /* return our allocated object */
1377  return newObject;
1378 }
1379 
1380 
1382 /******************************************************************************/
1383 /* Function: Locate an object is the dead object cache maintained for large */
1384 /* object allocations. */
1385 /******************************************************************************/
1386 {
1387  /* go through the LARGEDEAD object looking for the 1st one we can */
1388  /* use either our object is too big for all the small chains, or */
1389  /* the small chain are depleted.... */
1390  DeadObject *largeObject = deadCache.findFit(allocationLength);
1391  /* did we find an object? */
1392  if (largeObject != NULL)
1393  {
1394  /* split and prepare this object for use */
1395  return splitDeadObject(largeObject, allocationLength, LargeAllocationUnit);
1396  }
1397  return OREF_NULL; /* we couldn't get this */
1398 }
1399 
1400 
1402 /******************************************************************************/
1403 /* Function: Allocate an object from the old space. This is a very simple */
1404 /* management strategy, with no heroic efforts made to locate memory. Since */
1405 /* objects here can only come from the OldSpace area, there is no garbage */
1406 /* collection forced for failures. */
1407 /******************************************************************************/
1408 {
1409  /* round this allocation up to the appropriate large boundary */
1410  size_t allocationLength = roundLargeObjectAllocation(requestLength);
1411  /* Step 1, try to find an object in the current heap. We don't */
1412  /* try to round the object size up at all. This will take place */
1413  /* once we've found a fit. The allocations will be rounded up to */
1414  /* the next appropriate boundary. */
1415  RexxObject *newObject = findObject(allocationLength);
1416  /* can't allocate one? */
1417  if (newObject == OREF_NULL)
1418  {
1419  /* add space to this and try again */
1420  newSegment(allocationLength, allocationLength);
1421  /* Step 3, see if can allocate now */
1422  newObject = findObject(allocationLength);
1423  }
1424  /* return our allocated object */
1425  return newObject;
1426 }
1427 
1428 
1430 /******************************************************************************/
1431 /* Function: Find the largest segment in the segment set. */
1432 /******************************************************************************/
1433 {
1434  MemorySegment *largest = &anchor;
1435  MemorySegment *segment;
1436 
1437  for (segment = anchor.next; segment->isReal(); segment = segment->next)
1438  {
1439  if (segment->size() > largest->size())
1440  {
1441  largest = segment;
1442  }
1443  }
1444 
1445  /* we return this unconditionally, as our anchor segment will */
1446  /* report a size of zero. */
1447  return largest;
1448 }
1449 
1450 
1452 /******************************************************************************/
1453 /* Function: Find the largest empty segment in the segment set. */
1454 /******************************************************************************/
1455 {
1456  MemorySegment *largest = &emptySegments;
1457  MemorySegment *segment;
1458 
1459  for (segment = emptySegments.next; segment->isReal(); segment = segment->next)
1460  {
1461  if (segment->size() > largest->size())
1462  {
1463  largest = segment;
1464  }
1465  }
1466 
1467  /* we return this unconditionally, as our anchor segment will */
1468  /* report a size of zero. */
1469  return largest;
1470 }
1471 
1472 
1474  size_t allocationLength)
1475 /******************************************************************************/
1476 /* Function: Handle the decision process for a failed large block allocation.*/
1477 /* This function will decide whether to force a garbage collection, or add */
1478 /* additional segments to the heap. The cheaper alternative is to avoid */
1479 /* forcing the mark and sweep operations, so we see if we can predict if a */
1480 /* garbage collection is likely to fail to find a block large enough. */
1481 /******************************************************************************/
1482 {
1483  /* first check our set of empty segments. If we have an empty */
1484  /* in our list big enough for this, we'll just reactivate it, */
1485  /* and go on. We don't need to (and shouldn't) force a garbage */
1486  /* collection yet. */
1487  MemorySegment *largestEmpty = largestEmptySegment();
1488  if (largestEmpty->size() > allocationLength)
1489  {
1490  /* just move this over, and get out of here...we should be */
1491  /* able to satisfy this request now. */
1492  MemorySegment *segment = findEmptySegment(allocationLength);
1493  addSegment(segment);
1494  return;
1495  }
1496 
1497  MemorySegment *largestActive = largestActiveSegment();
1498 
1499  /* if our largest segment can't hold this block, then this is a */
1500  /* certain failure. It is time to add more segments for large */
1501  /* allocations. */
1502  if (largestActive->size() < allocationLength)
1503  {
1504  expandSegmentSet(allocationLength);
1505  return;
1506  }
1507  /* we can get into a situation where we need to expand */
1508  /* frequently. If we've reached that point, just add */
1509  /* additional memorhy. */
1511  {
1512  expandSegmentSet(allocationLength);
1513  /* we only do the expansion once per cycle for this. Bump */
1514  /* the requests count up so we don't keep expanding without */
1515  /* a collection. */
1517  return;
1518  }
1519  else
1520  {
1521  /* make sure all of our empty segments are included. This */
1522  /* will allow us to merge these into larger blocks. */
1524  /* go ahead and try to reclaim everything. We may still */
1525  /* end up expanding after this is done. */
1526  memory->collect();
1527  /* see if we can merge segments together to create a block large enough to satisfy this request. */
1528  mergeSegments(allocationLength);
1529  }
1530 }
1531 
1532 
1533 void MemorySegmentSet::mergeSegments(size_t allocationLength)
1534 /******************************************************************************/
1535 /* Function: Attempt to merge the set of large segments to create a dead */
1536 /* block of at least the requested size. This process can only be done */
1537 /* immediately after a complete GC cycle has been performed, as we need to */
1538 /* have accurate information about the live and dead blocks within the */
1539 /* segments. */
1540 /* */
1541 /* We'll attempt the merger in multiple passes to see if we can create a */
1542 /* block large enough. If we already have a block of at least this size on */
1543 /* the chains, then we'll do nothing. */
1544 /* */
1545 /* For the first pass, we'll combine adjacent empty segments to create a */
1546 /* larger block. If the first pass fails, then we'll try to find adjacent */
1547 /* segments with trailing and leading deadblocks we can combine into a larger */
1548 /* unit (possibly including intervening empty segments). */
1549 /******************************************************************************/
1550 {
1551  /* check our largest block. If we can allocate something of */
1552  /* this length, we don't combine empties now. Deferring this */
1553  /* makes it easier for use to give segments back. */
1554  MemorySegment *largestEmpty = largestActiveSegment();
1555  if (largestEmpty->size() > allocationLength)
1556  {
1557  return;
1558  }
1559 
1560  /* the segments are sorted in ascending order, so we can easily */
1561  /* find the adjacent segments. */
1562  MemorySegment *segment;
1563  /* scan the entire list */
1564  for (segment = anchor.next; segment->isReal(); segment = segment->next)
1565  {
1566  if (segment->isEmpty())
1567  {
1568  MemorySegment *nextSeg = segment->next;
1569  /* loop until we we've collapsed all of the adjacent */
1570  /* empty segments */
1571  for (;segment->isAdjacentTo(nextSeg) && nextSeg->isEmpty(); nextSeg = segment->next)
1572  {
1573  memory->verboseMessage("Combining two empty segments\n");
1574  /* combine these segments */
1575  combineEmptySegments(segment, nextSeg);
1576  }
1577  }
1578  }
1579 
1580  /* Check our largest block again. If combining the empty */
1581  /* segments created a new large block, we're finished. If not, */
1582  /* then we've got a hard job ahead of us */
1583  largestEmpty = largestActiveSegment();
1584  if (largestEmpty->size() > allocationLength)
1585  {
1586  return;
1587  }
1588 
1589 
1590  /* scan the entire list again, looking for opportunities to */
1591  /* combine partially empty segments. This could potentially */
1592  /* create a contiguous block large enough for our purposes. */
1593  for (segment = anchor.next; segment->isReal(); segment = segment->next)
1594  {
1595  /* this segment is only a candidate for merging if it has a */
1596  /* dead object on the end (fairly common, since we allocate */
1597  /* from the front) */
1598  DeadObject *lastBlock = segment->lastDeadObject();
1599  MemorySegment *emptySegment = NULL;
1600  MemorySegment *tailSegment = NULL;
1601  if (lastBlock != NULL)
1602  {
1603  /* we only do this if we can get a block of sufficient */
1604  /* size for the request we've received. So see how */
1605  /* much we can reclaim first. */
1606  size_t deadLength = lastBlock->getObjectSize();
1607  /* now go to the next segment, but only continue if */
1608  /* they abutt */
1609  MemorySegment *nextSeg = segment->next;
1610  if (!segment->isAdjacentTo(nextSeg) || !nextSeg->isReal())
1611  {
1612  continue;
1613  }
1614  /* we could have a single empty segment after us, as */
1615  /* we've already merged multiples. */
1616  if (nextSeg->isEmpty())
1617  {
1618  /* add the size in and continue */
1619  deadLength += nextSeg->realSize();
1620  emptySegment = nextSeg;
1621  nextSeg = nextSeg->next;
1622  }
1623  /* we should now be looking at a potential merger */
1624  /* candidate. */
1625  if (segment->isAdjacentTo(nextSeg) && nextSeg->isReal())
1626  {
1627  /* see if we have an empty block at the front of this */
1628  DeadObject *firstBlock = nextSeg->firstDeadObject();
1629  if (firstBlock != NULL)
1630  {
1631  deadLength += firstBlock->getObjectSize() + MemorySegmentOverhead;
1632  tailSegment = nextSeg;
1633  }
1634  }
1635  /* start by removing the last block from the deadchain. */
1636  lastBlock->remove();
1637  /* if there is an intervening empty segment, merge this */
1638  /* into this segment. */
1639  if (emptySegment != NULL)
1640  {
1641  /* remove all of the dead blocks from the chain */
1642  emptySegment->removeAll();
1643  /* remove the segment, and combine with this one. */
1644  removeSegment(emptySegment);
1645  segment->combine(emptySegment);
1646  }
1647  /* we may be able to combine the front block */
1648  if (tailSegment != NULL)
1649  {
1650  /* remove the first dead block from the chain */
1651  tailSegment->firstDeadObject()->remove();
1652  /* merge these two segments together. */
1653  removeSegment(tailSegment);
1654  segment->combine(tailSegment);
1655  memory->verboseMessage("Non-empty segments combined to create segment of %d bytes\n", segment->size());
1656  /* Now that this has been combined with one or more */
1657  /* segments, the merged segment may still be a */
1658  /* candidate for one more level of merge. Step to the */
1659  /* previous one so we take a second look at this. */
1660  segment = segment->previous;
1661  }
1662 
1663  /* finally resize this block to the combined size. */
1664  lastBlock->setObjectSize(deadLength);
1665  /* add this back into the chain as appropriate. */
1666  addDeadObject(lastBlock);
1667  }
1668  }
1669 }
1670 
1671 
1673  MemorySegment *front,
1674  MemorySegment *back)
1675 /******************************************************************************/
1676 /* Function: Merge two empty segments into a single segment and add the block*/
1677 /* create to the dead object cache. */
1678 /******************************************************************************/
1679 {
1680  DeadObject *frontObject = front->firstObject();
1681  DeadObject *backObject = back->firstObject();
1682 
1683  /* remove the dead space for these two objects from the cache */
1684  frontObject->remove();
1685  backObject->remove();
1686 
1687  /* remove the back segment */
1688  removeSegment(back);
1689 
1690  /* add the space to the front segment */
1691  front->combine(back);
1692 
1693  memory->verboseMessage("Two segments combined to create segment of %d bytes\n", front->size());
1694  /* and add the resulting dead object to the cache */
1695  DeadObject *ptr = front->createDeadObject();
1696  addDeadObject(ptr);
1697 }
1698 
1699 
1701  size_t allocationLength)
1702 /******************************************************************************/
1703 /* Function: Expand the size of the large allocation heap by adding an */
1704 /* additional segment. We'll employ three different strategies for adding */
1705 /* a segment to the heap. For "really, really big" requests, we'll just */
1706 /* round to the a page boundary and allocate. */
1707 /* */
1708 /* For requests larger than a single segment, but not large enough to qualify*/
1709 /* "really, really big", we'll round up to the next "convenient segment" to */
1710 /* add some additional usable storage. The convenience factor will */
1711 /* over allocate by at least SEGMENT/2 bytes. If the overallocation request */
1712 /* fails, then we'll just round up to the page boundary and try again. */
1713 /* */
1714 /* For the smaller allocations, we'll add this heap space in LARGESEGMENT */
1715 /* increments so we can get more suballocations before needing to force */
1716 /* another GC cycle. If the attempt to allocate a LARGESEGMENT fails, we'll */
1717 /* try again with just a single SEGMENT size allocation. */
1718 /******************************************************************************/
1719 {
1720  /* do we have a really big request? */
1721  if (allocationLength > LargeSegmentDeadSpace)
1722  {
1723  /* we allocate this as the size we need. No sense in */
1724  /* trying to over allocate here, as we'd like to free */
1725  /* this up as soon as we can. */
1726  memory->verboseMessage("Expanding large segment set by %d\n", allocationLength);
1727  newSegment(allocationLength, allocationLength);
1728  }
1729  /* for the smaller of the large blocks, we expand by a full */
1730  /* LargeSegment so we can fit more allocations in a segment. */
1731  /* If we can't get a full real on, then fall back to the */
1732  /* smaller size segment. */
1733  else if (allocationLength < SegmentDeadSpace)
1734  {
1735  memory->verboseMessage("Expanding large segment set by %d\n", LargeSegmentDeadSpace);
1737  }
1738  /* we've got a "tweener" block. We'll round up to the next */
1739  /* segment boundary to give a little extra. If the extra is */
1740  /* less than half a segment in size, add one more segment unit */
1741  /* to the allocation to increase the probability we'd be able */
1742  /* to use the extra. */
1743  else
1744  {
1745  size_t requestLength = roundSegmentBoundary(allocationLength);
1746  if ((requestLength - allocationLength) < MinimumSegmentSize)
1747  {
1748  requestLength += SegmentDeadSpace;
1749  }
1750  memory->verboseMessage("Expanding large segment set by %d\n", requestLength);
1751  newSegment(requestLength, allocationLength);
1752  }
1753 }
1754 
1755 
1757 /******************************************************************************/
1758 /* Function: Accumulate memory statistics for a segment */
1759 /******************************************************************************/
1760 {
1761  stats->count = count;
1762 
1763  MemorySegment *seg;
1764  for (seg = first(); seg != NULL; seg = next(seg))
1765  {
1766  seg->gatherObjectStats(memStats, stats);
1767  stats->largestSegment = Numerics::maxVal(stats->largestSegment, seg->size());
1768  stats->smallestSegment = Numerics::maxVal(stats->smallestSegment, seg->size());
1769  }
1770 }
1771 
1772 
1774 /******************************************************************************/
1775 /* Function: Perform a marking operation on all objects in a segment */
1776 /******************************************************************************/
1777 {
1778  char *op, *ep;
1779  for (op = start(), ep = end(); op < ep; )
1780  {
1781  /* mark behaviour live */
1782  memory_mark_general(((RexxObject *)op)->behaviour);
1783 
1784  /* Does this object have other Obj */
1785  /*refs? */
1786  if (((RexxObject *)op)->hasReferences())
1787  {
1788  /* yes, Then lets mark them */
1789  ((RexxObject *)op)->liveGeneral(RESTORINGIMAGE);
1790  }
1791  op += ((RexxObject *)op)->getObjectSize(); /* move to next object */
1792  }
1793 }
1794 
1795 
1797 /******************************************************************************/
1798 /* Function: Perform a marking operation on all OldSpace objects */
1799 /******************************************************************************/
1800 {
1801  /* mark the restored image segment */
1802  MemorySegment *segment;
1803  for (segment = first(); segment != NULL; segment = next(segment))
1804  {
1805  segment->markAllObjects();
1806  }
1807 }
1808 
1809 
1810 #ifdef CHECKOREFS
1811 void MemorySegmentSet::validateObject(size_t bytes)
1812 {
1813  /* is object invalid size? */
1814  if (!IsValidSize(bytes)) {
1815  /* Yes, this is not good. Exit */
1816  /* Critical Section and report */
1817  /* unrecoverable error. */
1818  Interpreter::logicError("Bad object detected during Garbage Collection, unable to continue");
1819  }
1820 }
1821 #endif
1822 
void reportException(wholenumber_t error)
bool objectIsNotLive(char *obj, size_t mark)
bool objectIsLive(char *obj, size_t mark)
#define InitialNormalSegmentSpace
#define LengthToDeadPool(l)
#define DeadPools
#define RecoverSegmentSize
#define NormalMemoryExpansionThreshold
#define MemorySegmentOverhead
#define MemoryThrashingThreshold
size_t roundSegmentBoundary(size_t n)
#define NormalMemoryContractionThreshold
#define FirstDeadPool
#define LargeSegmentDeadSpace
#define LargestSubpool
#define DeadPoolToLength(d)
#define SegmentSize
#define SegmentDeadSpace
#define MinimumSegmentSize
#define OREF_NULL
Definition: RexxCore.h:61
#define Error_System_resources
RexxMemory memoryObject
Definition: RexxMemory.cpp:86
#define LargeAllocationUnit
Definition: RexxMemory.hpp:76
size_t roundLargeObjectAllocation(size_t n)
Definition: RexxMemory.hpp:96
#define IsValidSize(s)
Definition: RexxMemory.hpp:93
#define MinimumObjectSize
Definition: RexxMemory.hpp:85
#define MaximumObjectSize
Definition: RexxMemory.hpp:86
#define memory_mark_general(oref)
Definition: RexxMemory.hpp:451
@ RESTORINGIMAGE
Definition: RexxMemory.hpp:116
void remove()
Definition: DeadObject.hpp:101
void setObjectSize(size_t newSize)
Definition: DeadObject.hpp:84
size_t getObjectSize()
Definition: DeadObject.hpp:85
void setID(const char *poolID)
Definition: DeadObject.hpp:154
DeadObject * findSmallestFit(size_t minSize)
Definition: DeadObject.cpp:112
void dumpMemoryProfile(FILE *outfile)
Definition: DeadObject.cpp:51
void emptySingle()
Definition: DeadObject.hpp:157
void addSortedBySize(DeadObject *obj)
Definition: DeadObject.cpp:148
void checkObjectOverlap(DeadObject *obj)
Definition: DeadObject.cpp:212
void add(DeadObject *obj)
Definition: DeadObject.hpp:161
void addSingle(DeadObject *obj)
Definition: DeadObject.hpp:262
DeadObject * findFit(size_t length)
Definition: DeadObject.hpp:193
static void logicError(const char *desc, const char *info1=NULL, size_t info2=0)
DeadObjectPool deadCache
RexxObject * findObject(size_t allocationLength)
virtual void prepareForSweep()
RexxObject * allocateObject(size_t allocationLength)
virtual void dumpMemoryProfile(FILE *outfile)
virtual DeadObject * donateObject(size_t allocationLength)
RexxObject * handleAllocationFailure(size_t allocationLength)
virtual MemorySegment * allocateSegment(size_t requestLength, size_t minimumLength)
void expandOrCollect(size_t allocationLength)
void expandSegmentSet(size_t allocationLength)
void completeSweepOperation()
virtual void addDeadObject(DeadObject *object)
MemorySegment * next
MemorySegment * previous
void gatherObjectStats(MemoryStats *memStats, SegmentStats *stats)
bool isFirstBlock(char *addr)
bool isLastBlock(char *addr, size_t length)
void shrink(size_t delta)
void combine(MemorySegment *nextSegment)
DeadObject * lastDeadObject()
char segmentStart[8]
DeadObject * firstDeadObject()
void dump(const char *owner, size_t counter, FILE *keyfile, FILE *dumpfile)
DeadObject * createDeadObject()
bool isAdjacentTo(MemorySegment *seg)
DeadObject * firstObject()
void insertBefore(MemorySegment *newSegment)
void dumpSegments(FILE *keyfile, FILE *dumpfile)
void activateEmptySegments()
MemorySegment anchor
const char * name
MemorySegment * findEmptySegment(size_t allocationLength)
void addSegment(MemorySegment *segment, bool createDeadObject=1)
void removeSegmentAndStorage(MemorySegment *segment)
virtual size_t suggestMemoryContraction()
size_t calculateSegmentAllocation(size_t n)
void releaseEmptySegments(size_t releaseSize)
MemorySegment emptySegments
RexxObject * splitDeadObject(DeadObject *object, size_t allocationLength, size_t splitMinimum)
size_t totalFreeMemory()
MemorySegment * first()
void mergeSegments(size_t allocationLength)
MemorySegment * largestEmptySegment()
void combineEmptySegments(MemorySegment *front, MemorySegment *back)
void addSegments(size_t requiredSpace)
virtual MemorySegment * allocateSegment(size_t requestLength, size_t minimumLength)
virtual void completeSweepOperation()
virtual size_t suggestMemoryExpansion()
RexxMemory * memory
void releaseSegment(MemorySegment *segment)
virtual void prepareForSweep()
virtual void collectEmptySegments()
MemorySegment * getSegment(size_t requestLength, size_t minimumLength)
float freeMemoryPercentage()
void gatherStats(MemoryStats *memStats, SegmentStats *stats)
MemorySegment * splitSegment(size_t allocationLength)
void removeSegment(MemorySegment *segment)
virtual DeadObject * donateObject(size_t allocationLength)
virtual void dumpMemoryProfile(FILE *outfile)
MemorySegment * next(MemorySegment *segment)
bool newSegment(size_t requestLength, size_t minimumLength)
void validateObject(size_t bytes)
MemorySegment * largestActiveSegment()
virtual MemorySegment * donateSegment(size_t allocationLength)
virtual void addDeadObject(DeadObject *object)
size_t recommendedMaximumMemorySize()
virtual void addDeadObject(DeadObject *object)
virtual size_t suggestMemoryContraction()
RexxObject * findObject(size_t allocationLength)
MemorySegment * recoverSegment
virtual DeadObject * donateObject(size_t allocationLength)
virtual void dumpMemoryProfile(FILE *outfile)
DeadObjectPool subpools[DeadPools]
virtual void prepareForSweep()
DeadObjectPool largeDead
RexxObject * handleAllocationFailure(size_t allocationLength)
RexxObject * findLargeDeadObject(size_t allocationLength)
void checkObjectOverlap(DeadObject *obj)
size_t lastUsedSubpool[DeadPools+1]
size_t recommendedMemorySize()
virtual size_t suggestMemoryExpansion()
RexxObject * allocateObject(size_t allocationLength)
static wholenumber_t maxVal(wholenumber_t n1, wholenumber_t n2)
Definition: Numerics.hpp:118
RexxObject * allocateObject(size_t allocationLength)
virtual void addDeadObject(DeadObject *object)
RexxObject * findObject(size_t allocationLength)
DeadObjectPool deadCache
void collect()
MemorySegment * newSegment(size_t requestLength, size_t minLength)
Definition: RexxMemory.cpp:740
MemorySegment * newLargeSegment(size_t requestLength, size_t minLength)
Definition: RexxMemory.cpp:780
size_t markWord
Definition: RexxMemory.hpp:304
void verboseMessage(const char *message)
Definition: RexxMemory.hpp:240
void scavengeSegmentSets(MemorySegmentSet *requester, size_t allocationLength)
size_t smallestSegment
Definition: MemoryStats.hpp:87
size_t largestSegment
Definition: MemoryStats.hpp:86
void recordObject(MemoryStats *memStats, char *obj)
Definition: MemoryStats.cpp:63