RexxMemory.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 /* Kernel RexxMemory.cpp */
40 /* */
41 /* Memory Object */
42 /* */
43 /******************************************************************************/
44 #include <stdlib.h>
45 #include <string.h>
46 #include "RexxCore.h"
47 #include "RexxMemory.hpp"
48 #include "StackClass.hpp"
49 #include "StringClass.hpp"
50 #include "MutableBufferClass.hpp"
51 #include "DirectoryClass.hpp"
52 #include "RexxActivity.hpp"
53 #include "IntegerClass.hpp"
54 #include "ArrayClass.hpp"
55 #include "TableClass.hpp"
56 #include "RexxActivation.hpp"
57 #include "ActivityManager.hpp"
58 #include "MessageClass.hpp"
59 #include "MethodClass.hpp"
60 #include "RelationClass.hpp"
61 #include "SupplierClass.hpp"
62 #include "PointerClass.hpp"
63 #include "BufferClass.hpp"
64 #include "PackageClass.hpp"
65 #include "WeakReferenceClass.hpp"
66 #include "StackFrameClass.hpp"
67 #include "BlockClass.hpp"
68 #include "Interpreter.hpp"
69 #include "SystemInterpreter.hpp"
70 #include "Interpreter.hpp"
71 #include "PackageManager.hpp"
72 #include "SysFileSystem.hpp"
73 #include "UninitDispatcher.hpp"
75 
76 // restore a class from its
77 // associated primitive behaviour
78 // (already restored by memory_init)
79 #define RESTORE_CLASS(name, className) The##name##Class = (className *)RexxBehaviour::getPrimitiveBehaviour(T_##name)->restoreClass();
80 
81 
83 /* NOTE: There is just a single memory object in global storage. We'll define */
84 /* memobj to be the direct address of this memory object. */
86 
87 #define LiveStackSize 16370 /* live stack size */
88 
89 #define SaveStackSize 10 /* newly created objects to save */
90 #define SaveStackAllocSize 500 /* pre-allocation for save stack */
91 
92 #define MaxImageSize 1800000 /* maximum startup image size */
93 
95 RexxDirectory *RexxMemory::environment = OREF_NULL; // global environment
96 RexxDirectory *RexxMemory::functionsDir = OREF_NULL; // statically defined requires
100 
101 // locks for the memory process access
102 SysMutex RexxMemory::flattenMutex("RexxMemory::flattenMutex");
103 SysMutex RexxMemory::unflattenMutex("RexxMemory::unflattenMutex");
104 SysMutex RexxMemory::envelopeMutex("RexxMemory::envelopeMutex");
105 
106 static void logMemoryCheck(FILE *outfile, const char *message, ...)
107 {
108  va_list args;
109  va_start(args, message);
110  vprintf(message, args);
111  if (outfile != NULL) {
112  vfprintf(outfile, message, args);
113  }
114  va_end(args);
115 }
116 
117 
119 /******************************************************************************/
120 /* Function: Main Constructor for Rexxmemory, called once during main */
121 /* initialization. Will create the initial memory Pool(s), etc. */
122 /******************************************************************************/
123 {
124  /* we need to set a valid size for this object. We round it up */
125  /* to the minimum allocation boundary, even though that might be */
126  /* a lie. Since this never participates in a sweep operation, */
127  /* this works ok in the end. */
129  // our first pool is the current one
131 
132  /* make sure we hand craft memory's */
133  /* header information. */
134 
135  /* See if we want this debug info */
136  /*or not by default, its always */
137  /*setable from OREXX code. */
138 #ifdef CHECKOREFS
139  this->orphanCheck = true; /* default value for OREF checking */
140 #else
141  this->orphanCheck = false; /* default value for OREF checking */
142 #endif
143  /* OR'ed into object headers to */
144  /*mark */
145  this->markWord = 1;
146  /* objects as being alive in mark */
147  /*phase */
148  this->saveStack = NULL;
149  this->saveTable = NULL;
150  this->dumpEnable = false;
151  this->objOffset = 0;
152  this->envelope = NULL;
153 
154  // we always start out with an empty list. WeakReferences that are in the
155  // saved image will (MUST) never be set to a new value, so it's not necessary
156  // to hook those back up again.
158 }
159 
160 
161 /**
162  * Initialize the memory object, including getting the
163  * initial memory pool allocations.
164  *
165  * @param restoringImage
166  * True if we are initializing during an image restore, false
167  * if we need to build the initial image environemnt (i.e., called
168  * via rexximage during a build).
169  * @param imageTarget
170  * The location to store the image if this is a save operation.
171  */
172 void RexxMemory::initialize(bool restoringImage, const char *imageTarget)
173 /******************************************************************************/
174 /* Function: Gain access to all Pools */
175 /******************************************************************************/
176 {
177  /* access 1st pool directly. SysCall */
178  /* Did the pool exist? */
179 
182 
183  disableOrefChecks(); /* Make sure we don't try to validate*/
184  /* OrefSets just yet. */
185  /* Make sure memory is fully */
186  /*constructed, mainlyt a concern on */
187  /*2nd entry and DLL not unloaded. */
188  new (this) RexxMemory;
191 
192  /* and the new/old Space segments */
194 
195  collections = 0;
196  allocations = 0;
199 
200  // get our table of virtual functions setup first thing.
202 
203  /* NOTE: we don't set livestack */
204  /*via the OrefSet macro, since we */
205  /*are so early on in the system, */
206  /*that we can't use it right now, */
207  /*we will fix this all */
209  /* remember the original one */
211 
212  if (restoringImage) /* restoring the image? */
213  {
214  restoreImage(); /* do it now... */
215  }
216 
217  /* set memories behaviour */
219  /* initial marktable value is */
220  /* TheKernel */
221  this->markTable = OREF_NULL; /* fix by CHM/Rick: set initial table*/
222  /* to NULL since TheKernel could */
223  /* point to an invalid memory address*/
224  /* if one OREXX session is started */
225  /* while another one is closed */
226 
227  /* make sure we have an inital segment set to allocate from. */
229 
230  // get the initial uninit table
232 
233  // is this image creation? This will build and save the image, then
234  // terminate
235  if (!restoringImage)
236  {
237  createImage(imageTarget);
238  }
239  restore(); // go restore the state of the memory object
240 }
241 
242 
243 void RexxMemory::logVerboseOutput(const char *message, void *sub1, void *sub2)
244 /******************************************************************************/
245 /* Function: Log verbose output events */
246 /******************************************************************************/
247 {
248  logMemoryCheck(NULL, message, sub1, sub2);
249 }
250 
252 {
253  FILE *outFile; /* memory stat output file */
254 
255  outFile = fopen("memory.prf","wb"); /* open the file */
256  /* have each of the memory segments dump their own profile information */
259  fclose(outFile); /* close the file */
260 }
261 
262 
263 void RexxMemory::dumpObject(RexxObject *objectRef, FILE *outfile)
264 /******************************************************************************/
265 /* Arguments: none, */
266 /* */
267 /* Function: Dump out the contents of an object, to screen and optionally */
268 /* a file. */
269 /******************************************************************************/
270 {
271  void **dmpPtr;
272  void **ObjEnd;
273 
274  ObjEnd = (void **)((char *)objectRef + objectRef->getObjectSize());
275  for (dmpPtr = (void **)objectRef; dmpPtr <= ObjEnd ; dmpPtr++)
276  {
277  logMemoryCheck(outfile, " >Parent Dump -->%p %p %p %p \n", *dmpPtr, *(dmpPtr+1), *(dmpPtr+2), *(dmpPtr+3));
278  }
279 }
280 
282 /******************************************************************************/
283 /* Arguments: Any OREF */
284 /* */
285 /* Returned: true if object is in object storage, else false */
286 /******************************************************************************/
287 {
288  /* 1st Check Old Space. */
289  if (oldSpaceSegments.isInSegmentSet(object))
290  {
291  return true;
292  }
293 
294  /* Now Check New Space. */
296  {
297  return true;
298  }
299 
300  /* Now Check New Space large segments*/
302  {
303  return true;
304  }
305 
306  /* this is bad, definitely very bad... */
307  return false;
308 }
309 
310 
312 /******************************************************************************/
313 /* Arguments: Any OREF */
314 /* */
315 /* Returned: true if object is in object storage, else false */
316 /******************************************************************************/
317 {
318  /* check for a few valid locations in 'C' storage */
320  (object == (RexxObject *)this))
321  {
322  return true;
323  }
324 
325  return inSharedObjectStorage(object);
326 }
327 
328 
329 /* object validation method --used to find and diagnose broken object references */
331 /******************************************************************************/
332 /* Function: Object validation...used to find and diagnose broken object */
333 /* references. */
334 /******************************************************************************/
335 {
336  if (!inObjectStorage(o))
337  {
338  return false;
339  }
341  if (inObjectStorage((RexxObject *)type) && type->getObjectType() == TheBehaviourBehaviour)
342  {
343  return true;
344  }
345  /* these last two checks are for very early checking...we can */
346  /* possibly be testing this before TheBehaviourBehaviour is */
347  /* set up, so we have two additional means of verifying the */
348  /* behaviour object. */
350 }
351 
352 
354 /******************************************************************************/
355 /* Function: Main memory_mark driving loop */
356 /******************************************************************************/
357 {
358  // for some of the root objects, we get called to mark them before they get allocated.
359  // make sure we don't process any null references.
360  if (rootObject == OREF_NULL)
361  {
362  return;
363  }
364 
365  RexxObject *markObject;
366 
367  // set up the live marking word passed to the live() routines
368  size_t liveMark = markWord | OldSpaceBit;
369 
370  allocations = 0;
371  pushLiveStack(OREF_NULL); /* push a unique terminator */
372  mark(rootObject); /* OREF_ENV or old2new */
373  for (markObject = popLiveStack();
374  markObject != OREF_NULL; /* test for unique terminator */
375  markObject = popLiveStack())
376  {
377  /* mark behaviour live */
378  memory_mark((RexxObject *)markObject->behaviour);
379  /* Mark other referenced obj. We can do this without checking */
380  /* the references flag because we only push the object on to */
381  /* the stack if it has references. */
382  allocations++;
383  markObject->live(liveMark);
384  }
385 }
386 
387 
389 /******************************************************************************/
390 /* Function: Garbage collection validity check routine */
391 /******************************************************************************/
392 {
393  // for some of the root objects, we get called to mark them before they get allocated.
394  // make sure we don't process any null references.
395  if (rootObject == OREF_NULL)
396  {
397  return;
398  }
399 
400  RexxObject *mref;
401 
403  /* This is the debugging mark code that traverses the object tree from */
404  /* OREF_ENV, verifying that the objects and their OREFs look OK, specifically */
405  /* that each one is in object storage, and has a behaviour whose behaviour */
406  /* is OREF_BEHAV_B, behaviour's behaviour. */
407 
408  /* push a unique terminator */
410  /*Push an extra marktable */
411  pushLiveStack(rootObject);
412  memory_mark_general(rootObject); /* start from the very tip-top */
413  memory_mark_general(TheNilObject); /* use .nil to mark the stack */
414  /* mark .nil behaviour live */
415  memory_mark_general(TheNilObject->behaviour);
416  /* mark .nil ovds live */
417  memory_mark_general(TheNilObject->objectVariables);
418  for (mref = popLiveStack();
419  mref != OREF_NULL; /* test for unique terminator */
420  /* get the next marked item */
421  mref = popLiveStack())
422  {
423 
424  /* OREF_NIL is used as a marker on the stack. These markers will be used to */
425  /* recreate the ancestry of any broken object found. At this point though, */
426  /* finding one indicates that we've already marked all of the descendants of */
427  /* the object just below the OREF_NIL, so we'll leave the OREF_NIL popped, */
428  /* and pop off the parent object which is no longer of any interest. */
429  if (mref == TheNilObject)
430  { /* found a marker */
431  /* pop off the completed parent */
432  popLiveStack();
433  continue; /* and back to top of loop */
434  }
435  /* mark behaviour live */
437  /* object have any references? */
438  if (mref->hasReferences())
439  {
440  /* Though this guy is already marked, and as far as gc, we're done with him, */
441  /* we'll now push him back onto the livestack followed by an OREF_NIL marker. */
442  /* If we find an invalid object later, we'll be able to find all the ancestors */
443  /* by looking for the OREF_NIL objects on the livestack. */
444  /* push the ancestor object */
445  pushLiveStack(mref);
446  /* push an ancestor marker */
448  mref->liveGeneral(LIVEMARK); /* tell the ancestor to mark his kids*/
449  } /* object have any references? */
450  }
451 }
452 
454 /******************************************************************************/
455 /* */
456 /******************************************************************************/
457 {
458  /* we might not actually have a table yet, so make sure we check */
459  /* before using it. */
460  if (uninitTable == NULL)
461  {
462  return;
463  }
464 
465  RexxObject *uninitObject;
466  /* table and any object is isn't */
467  /* alive, we indicate it should be */
468  /* sent unInit. We indiacte this */
469  /* by setting the value to 1, */
470  /* instead of NIL (the default) */
471  for (HashLink i = uninitTable->first(); (uninitObject = uninitTable->index(i)) != OREF_NULL; i = uninitTable->next(i))
472  {
473  /* is this object now dead? */
474  if (uninitObject->isObjectDead(markWord))
475  {
476  /* yes, indicate object is to be */
477  /* sent uninit. */
479  pendingUninits++;
480  }
481  }
482 }
483 
484 
485 /**
486  * Force a last-gasp garbage collection and running of the
487  * uninits during interpreter instance shutdown. This is an
488  * attempt to ensure that all objects with uninit methods get
489  * a chance to clean up prior to termination.
490  */
491 void RexxMemory::collectAndUninit(bool clearStack)
492 {
493  // clear the save stack if we're working with a single instance
494  if (clearStack)
495  {
496  clearSaveStack();
497  }
498  collect();
499  verboseMessage("Calling runUninits from RexxMemory::collectAndUninit\n");
500  runUninits();
501 }
502 
503 
504 /**
505  * Force a last-gasp garbage collection and running of the
506  * uninits during interpreter instance shutdown. This is an
507  * attempt to ensure that all objects with uninit methods get
508  * a chance to clean up prior to termination.
509  */
511 {
512  // collect and run any uninits still pending
513  collectAndUninit(true);
514  // we're about to start releasing libraries, so it is critical
515  // we don't run any more uninits after this
516  uninitTable->empty();
517 }
518 
519 
521 /******************************************************************************/
522 /* Function: Run any UNINIT methods for this activity */
523 /******************************************************************************/
524 /* NOTE: The routine to iterate across uninit Table isn't quite right, since */
525 /* the removal of zombieObj may move another zombieObj and then doing */
526 /* the next will skip this zombie, we should however catch it next time */
527 /* through. */
528 /* */
529 /******************************************************************************/
530 {
531  RexxObject * zombieObj; /* obj that needs uninit run. */
532  HashLink iterTable; /* iterator for table. */
533 
534  verboseMessage("Entering runUninits\n");
535  /* if we're already processing this, don't try to do this */
536  /* recursively. */
537  if (processingUninits)
538  {
539  verboseMessage("Leaving runUninits immediatly because recursive call\n");
540  return;
541  }
542 
543  /* turn on the recursion flag, and also zero out the count of */
544  /* pending uninits to run */
545  processingUninits = true;
546  size_t pendingUninits_onEntry = pendingUninits; // for verbose message when leaving
547  pendingUninits = 0;
548 
549  // get the current activity for running the uninits
551 
552  /* uninitTabe exists, run UNINIT */
553  for (iterTable = uninitTable->first();
554  (zombieObj = uninitTable->index(iterTable)) != OREF_NULL;)
555  {
556  // TODO: Ther's a bug here. Removing the object can cause the
557  // iterator to skip over an entry....something should be done to
558  // prevent this.
559 
560  /* is this object readyfor UNINIT? */
561  if (uninitTable->value(iterTable) == TheTrueObject)
562  {
563  /* make sure we don't recurse */
564  uninitTable->put(TheFalseObject, zombieObj);
565  {
566  // run this method with appropriate error trapping
567  verboseMessage("Calling uninit for object %s:%u\n",
568  zombieObj->classObject()->getId()->getStringData(),
569  zombieObj->identityHash());
570  UninitDispatcher dispatcher(zombieObj);
571  activity->run(dispatcher);
572  }
573  /* remove zombie from uninit table */
574  uninitTable->remove(zombieObj);
575 
576 
577  // because we just did a remove operation, this will effect the iteration
578  // process. There are two possibilities here. Either A) we were at the end of the
579  // chain and this is now an empty slot or B) the removal process moved an new item
580  // into this slot. If it is case A), then we need to search for the next item. If
581  // it is case B) we'll just leave the index alone and process this position again.
582  if (uninitTable->index(iterTable) == OREF_NULL)
583  {
584  iterTable = uninitTable->next(iterTable);
585  }
586  }
587  else
588  {
589  iterTable = uninitTable->next(iterTable);
590  }
591  } /* now go check next object in table */
592  /* make sure we remove the recursion protection */
593  processingUninits = false;
594  verboseMessage("Leaving runUninits (was called when pendingUninits=%d)\n", pendingUninits_onEntry);
595 }
596 
597 
599  RexxObject *obj) /* object to remove */
600 /******************************************************************************/
601 /* Function: Remove an object from the uninit tables */
602 /******************************************************************************/
603 {
604  // just remove this object from the table
605  uninitTable->remove(obj);
606 }
607 
608 
610  RexxObject *obj) /* object to add */
611 /******************************************************************************/
612 /* Function: Add an object with an uninit method to the uninit table for */
613 /* a process */
614 /******************************************************************************/
615 {
616  /* is object already in table? */
617  if (uninitTable->get(obj) == OREF_NULL)
618  {
619  /* nope, add obj to uninitTable, */
620  /* initial value is NIL */
622  }
623 
624 }
625 
627 /******************************************************************************/
628 /* Function: Test if an object is going to require its uninit method run. */
629 /******************************************************************************/
630 {
631  return uninitTable->get(obj) != OREF_NULL;
632 }
633 
634 
636 /******************************************************************************/
637 /* Function: Main mark routine for garbage collection. This reoutine */
638 /* Determines which mark routine to call and does all additional processing */
639 /******************************************************************************/
640 {
641  verboseMessage("Beginning mark operation\n");
642 
643  if (this->orphanCheck)
644  { /* debugging bad OREF's? */
645  /* yup, call debugging mark */
646  this->killOrphans((RexxObject *)this);
647  // now process the weak reference queue...We check this before the
648  // uninit list is processed so that the uninit list doesn't mark any of the
649  // weakly referenced items. We don't want an object placed on the uninit queue
650  // to end up strongly referenced later.
652  this->checkUninit(); /* flag all objects about to be dead */
653  this->killOrphans(uninitTable); /* the uninit table */
654  }
655  else
656  {
657  /* call normal,speedy,efficient mark */
658  this->markObjectsMain((RexxObject *)this);
659  // now process the weak reference queue...We check this before the
660  // uninit list is processed so that the uninit list doesn't mark any of the
661  // weakly referenced items. We don't want an object placed on the uninit queue
662  // to end up strongly referenced later.
664  this->checkUninit(); /* flag all objects about to be dead */
665  /* now mark the unInit table and the */
667  }
668  /* have to expand the live stack? */
669  if (this->liveStack != this->originalLiveStack)
670  {
671  free((void *)this->liveStack); /* release the old one */
672  /* and set back to the original */
673  this->liveStack = this->originalLiveStack;
674  }
675  verboseMessage("Mark operation completed\n");
676 }
677 
678 
679 /******************************************************************************/
680 /* Function: Scan the weak reference queue looking for either dead weak */
681 /* objects or weak references that refer to objects that have gone out of */
682 /* scope. Objects with registered notification objects (that are still in */
683 /* scope) will be moved to a notification queue, which is processed after */
684 /* everything is scanned. */
685 /******************************************************************************/
687 {
688  WeakReference *current = weakReferenceList;
689  // list of "live" weak references...built while scanning
690  WeakReference *newList = OREF_NULL;
691 
692  // loop through the list
693  while (current != OREF_NULL)
694  {
695  // we have to save the next one in the list
696  WeakReference *next = current->nextReferenceList;
697  // this reference still in scope?
698  if (current->isObjectLive(markWord))
699  {
700  // keep this one in the list
701  current->nextReferenceList = newList;
702  newList = current;
703  // have a reference?
704  if (current->referentObject != OREF_NULL)
705  {
706  // if the object is not alive, null out the reference
707  if (!current->referentObject->isObjectLive(markWord))
708  {
709  current->referentObject = OREF_NULL;
710  }
711  }
712  }
713  // step to the new nest item
714  current = next;
715  }
716 
717  // update the list
718  weakReferenceList = newList;
719 }
720 
721 
723 /******************************************************************************/
724 /* Function: Add a new weak reference to the tracking table */
725 /******************************************************************************/
726 {
727  // just add this to the front of the list
729  weakReferenceList = ref;
730 }
731 
732 
733 MemorySegment *RexxMemory::newSegment(size_t requestedBytes, size_t minBytes)
734 /******************************************************************************/
735 /* Function: Allocate a segment of the requested size. The requested size */
736 /* is the desired size, while the minimum is the absolute minimum we can */
737 /* handle. This takes care of the overhead accounting and additional */
738 /* rounding. The requested size is assumed to have been rounded up to the */
739 /* next "appropriate" boundary already, and the segment overhead will be */
740 /* allocated from that part, if possible. Otherwise, and additional page is */
741 /* added. */
742 /******************************************************************************/
743 {
744  MemorySegment *segment;
745 
746 #ifdef MEMPROFILE
747  printf("Allocating a new segment of %d bytes\n", requestedBytes);
748 #endif
749  /* first make sure we've got enough space for the control */
750  /* information, and round this to a proper boundary */
751  requestedBytes = roundSegmentBoundary(requestedBytes + MemorySegmentOverhead);
752 #ifdef MEMPROFILE
753  printf("Allocating boundary a new segment of %d bytes\n", requestedBytes);
754 #endif
755  /*Get a new segment */
756  segment = currentPool->newSegment(requestedBytes);
757  /* Did we get a segment */
758  if (segment == NULL)
759  {
760  /* Segmentsize is the minimum size request we handle. If */
761  /* minbytes is small, then we're just adding a segment to the */
762  /* small pool. Reduce the request to SegmentSize and try again. */
763  /* For all other requests, try once more with the minimum. */
764  minBytes = roundSegmentBoundary(minBytes + MemorySegmentOverhead);
765  /* try to allocate once more...if this fails, the caller will */
766  /* have to handle it. */
767  segment = currentPool->newSegment(minBytes);
768  }
769  return segment; /* return the allocated segment */
770 }
771 
772 
773 MemorySegment *RexxMemory::newLargeSegment(size_t requestedBytes, size_t minBytes)
774 /******************************************************************************/
775 /* Function: Allocate a segment of the requested size. The requested size */
776 /* is the desired size, while the minimum is the absolute minimum we can */
777 /* handle. This takes care of the overhead accounting and additional */
778 /* rounding. The requested size is assumed to have been rounded up to the */
779 /* next "appropriate" boundary already, and the segment overhead will be */
780 /* allocated from that part, if possible. Otherwise, and additional page is */
781 /* added. */
782 /******************************************************************************/
783 {
784  MemorySegment *segment;
785 
786  /* first make sure we've got enough space for the control */
787  /* information, and round this to a proper boundary */
788  size_t allocationBytes = roundSegmentBoundary(requestedBytes + MemorySegmentOverhead);
789 #ifdef MEMPROFILE
790  printf("Allocating large boundary new segment of %d bytes for request of %d\n", allocationBytes, requestedBytes);
791 #endif
792  /*Get a new segment */
793  segment = currentPool->newLargeSegment(allocationBytes);
794  /* Did we get a segment */
795  if (segment == NULL)
796  {
797  /* Segmentsize is the minimum size request we handle. If */
798  /* minbytes is small, then we're just adding a segment to the */
799  /* small pool. Reduce the request to SegmentSize and try again. */
800  /* For all other requests, try once more with the minimum. */
801  minBytes = roundSegmentBoundary(minBytes + MemorySegmentOverhead);
802  /* try to allocate once more...if this fails, the caller will */
803  /* have to handle it. */
804  segment = currentPool->newLargeSegment(minBytes);
805  }
806  return segment; /* return the allocated segment */
807 }
808 
809 
811 /******************************************************************************/
812 /* Function: Restore a saved image to usefulness. */
813 /******************************************************************************/
814 {
815  // Nothing to restore if we have a buffer already
816  if (image_buffer != NULL)
817  {
818  return;
819  }
820 
821  markReason = RESTORINGIMAGE; // we're doing an image restore
822 
823  size_t imagesize; /* size of the image */
824  char *objectPointer, *endPointer;
825  RexxBehaviour *imageBehav; /*behaviour of OP object in image */
826  RexxArray *primitiveBehaviours; /* saved array of behaviours */
827  size_t primitiveTypeNum;
828  int i;
829 
830  /* go load the image */
832  /* get the relocation factor */
833  relocation = (size_t)image_buffer - sizeof(size_t);
834  objectPointer = image_buffer; /* address the start of the image */
835  /* and the ending location */
836  endPointer = image_buffer + imagesize;
837  /* the save Array is the 1st object */
838  RexxArray *saveArray = (RexxArray *)image_buffer;
839  restoreimage = true; /* we are now restoring */
840  /* loop through the image buffer */
841  while (objectPointer < endPointer)
842  {
843 
844  /*Fixup Behaviour pointer for obj. */
845  /* We don't do an OrefSet here, since*/
846  /* too early, and we don't need to be*/
847  /* concerned about object in pbehav */
848 
849  /* Retrieve the behaviour obj */
850  /* or a copy? */
851  if (((RexxObject *)objectPointer)->isNonPrimitive())
852  {
853  /* Working with a copy, don't use */
854  /* PBEHAV version. */
855  /* Make sure static behaviour inf */
856  /* is resolved before using the */
857  /* Behaviour. */
858  imageBehav = (RexxBehaviour *)(relocation + (uintptr_t)((RexxObject *)objectPointer)->behaviour);
859  /* give this object it behaviour. */
860  ((RexxObject *)objectPointer)->behaviour = (RexxBehaviour *)imageBehav;
861  primitiveTypeNum = imageBehav->getClassType();
862  }
863  else
864  {
865  // the original behaviour pointer has been encoded as a type number and class
866  // category to allow us to convert back to the appropriate type.
867  ((RexxObject *)objectPointer)->behaviour = RexxBehaviour::restoreSavedPrimitiveBehaviour(((RexxObject *)objectPointer)->behaviour);
868  primitiveTypeNum = ((RexxObject *)objectPointer)->behaviour->getClassType();
869  }
870  /* This will be an OldSpace object. We delay setting this */
871  /* until now, because the oldspace bit is overloaded with the */
872  /* NonPrimitive bit. Since the we are done with the */
873  /* non-primitive bit now, we can use this for the oldspace */
874  /* flag too. */
875  ((RexxObject *)objectPointer)->setOldSpace();
876  /* Force fix-up of */
877  /*VirtualFunctionTable, */
878  ((RexxObject *)objectPointer)->setVirtualFunctions(virtualFunctionTable[primitiveTypeNum]);
879 
880  /* Do this object have any */
881  /*references? */
882  if (((RexxObject *)objectPointer)->hasReferences())
883  /* Yes, mark other referenced objs */
884  ((RexxObject *)objectPointer)->liveGeneral(RESTORINGIMAGE);
885  /* Point to next object in image.. */
886  objectPointer += ((RexxObject *)objectPointer)->getObjectSize();
887 
888  }
889 
890  restoreimage = false;
891  /* OREF_ENV is the first element of */
892  /*array */
894  /* get the primitive behaviours */
895  primitiveBehaviours = (RexxArray *)saveArray->get(saveArray_PBEHAV);
896  /* restore all of the saved primitive*/
897  for (i = 0; i <= T_Last_Exported_Class; i++)
898  {
899  /* behaviours into this array */
900  RexxBehaviour::primitiveBehaviours[i].restore((RexxBehaviour *)primitiveBehaviours->get(i + 1));
901  }
902 
903  TheKernel = (RexxDirectory *)saveArray->get(saveArray_KERNEL);
904  TheSystem = (RexxDirectory *)saveArray->get(saveArray_SYSTEM);
906  TheTrueObject = (RexxInteger *)saveArray->get(saveArray_TRUE);
908  TheNilObject = saveArray->get(saveArray_NIL);
909  TheNullArray = (RexxArray *)saveArray->get(saveArray_NULLA);
911  TheClassClass = (RexxClass *)saveArray->get(saveArray_CLASS);
913 
914  /* restore the global strings */
916  // make sure we have a working thread context
919 }
920 
921 
922 void RexxMemory::live(size_t liveMark)
923 /******************************************************************************/
924 /* Arguments: None */
925 /* */
926 /* Returned: Nothing */
927 /* */
928 /******************************************************************************/
929 {
930  /* Mark the save stack first, since it will be pulled off of */
931  /* the stack after everything else. This will give other */
932  /* objects a chance to be marked before we remove them from */
933  /* the savestack. */
934  memory_mark(this->saveStack);
935  memory_mark(this->saveTable);
936  memory_mark(this->old2new);
937  memory_mark(this->envelope);
938  memory_mark(this->variableCache);
939  memory_mark(this->markTable);
941  // now call the various subsystem managers to mark their references
942  Interpreter::live(liveMark);
943  SystemInterpreter::live(liveMark);
944  ActivityManager::live(liveMark);
945  PackageManager::live(liveMark);
946  // mark any protected objects we've been watching over
947 
949  while (p != NULL)
950  {
952  p = p->next;
953  }
954 }
955 
956 void RexxMemory::liveGeneral(int reason)
957 /******************************************************************************/
958 /* Arguments: None */
959 /* */
960 /* Returned: Nothing */
961 /* */
962 /******************************************************************************/
963 {
964  memory_mark_general(this->saveStack);/* Mark the save stack last, to give it a chance to clear out entries */
971  // now call the various subsystem managers to mark their references
972  Interpreter::liveGeneral(reason);
976 }
977 
979 /******************************************************************************/
980 /* Arguments: None */
981 /* */
982 /* Returned: OREF NULL, */
983 /******************************************************************************/
984 {
985 
986 }
987 
989 /******************************************************************************/
990 /* Arguments: None */
991 /* */
992 /* Returned: OREF NULL, */
993 /******************************************************************************/
994 {
995  /* Memory Obj doesn't get moved, */
996  /*create a proxy object to */
997  /*re-establish on other system. */
998 
999 
1000  /* Generate a new proxy object to */
1001  /*represent this object, and then */
1002  /*send flatten to this proxy. We */
1003  /*then return the result from the */
1004  /*proxt flatten method. */
1005  return (RexxObject *)new_proxy("MEMORY");
1006 }
1007 
1008 
1010 /******************************************************************************/
1011 /* Function: Interface method for external control of garbage collection. */
1012 /* This forces a GC cycle. */
1013 /******************************************************************************/
1014 {
1015  /* just drive the GC operation */
1016  collect();
1017  return OREF_NULL;
1018 }
1019 
1020 
1022 /******************************************************************************/
1023 /* Function: Collect all dead memory in the Rexx object space. The */
1024 /* collection process performs a mark operation to mark all of the live */
1025 /* objects, followed by sweep of each of the segment sets. */
1026 /******************************************************************************/
1027 {
1028  collections++;
1029  verboseMessage("Begin collecting memory, cycle #%d after %d allocations.\n", collections, allocations);
1030  allocations = 0;
1031 
1032  /* change our marker to the next value so we can distinguish */
1033  /* between objects marked on this cycle from the objects marked */
1034  /* in the pervious cycles. */
1035  bumpMarkWord();
1036 
1037  /* do the object marking now...followed by a sweep of all of the */
1038  /* segments. */
1039  markObjects();
1042 
1043  /* The space segments are now in a known, completely clean state. */
1044  /* Now based on the context that caused garbage collection to be */
1045  /* initiated, the segment sets may be expanded to add additional */
1046  /* free memory. The decision to expand the object space requires */
1047  /* the usage statistics collected by the mark-and-sweep */
1048  /* operation. */
1049 
1050  verboseMessage("End collecting memory\n");
1051  verboseMessage("Object save table contains %d objects\n", this->saveTable->items());
1052 }
1053 
1054 RexxObject *RexxMemory::oldObject(size_t requestLength)
1055 /******************************************************************************/
1056 /* Arguments: Requested length */
1057 /* */
1058 /* Returned: New object, or OREF_NULL if requested length was too large */
1059 /******************************************************************************/
1060 {
1061  /* Compute size of new object and determine where we should */
1062  /* allocate from */
1063  requestLength = roundObjectBoundary(requestLength);
1064  RexxObject *newObj = oldSpaceSegments.allocateObject(requestLength);
1065 
1066  /* if we got a new object, then perform the final setup steps. */
1067  /* Since the oldspace objects are special, we don't push them on */
1068  /* to the save stack. Also, we don't set the oldspace flag, as */
1069  /* those are a separate category of object. */
1070  if (newObj != OREF_NULL)
1071  {
1072  // initialize the hash table object
1074  }
1075 
1076  /* return the newly allocated object to our caller */
1077  return newObj;
1078 }
1079 
1080 char *RexxMemory::allocateImageBuffer(size_t imageSize)
1081 /******************************************************************************/
1082 /* Function: Allocate an image buffer for the system code. The image buffer */
1083 /* is allocated in the oldspace segment set. We create an object from that */
1084 /* space, then return this object as a character pointer. We eventually will */
1085 /* get that pointer passed back to us as the image address. */
1086 /******************************************************************************/
1087 {
1088  return (char *)oldObject(imageSize);
1089 }
1090 
1091 
1092 RexxObject *RexxMemory::newObject(size_t requestLength, size_t type)
1093 /******************************************************************************/
1094 /* Arguments: Requested length */
1095 /* */
1096 /* Returned: New object, or OREF_NULL if requested length was too large */
1097 /******************************************************************************/
1098 {
1099  RexxObject *newObj;
1100 
1101  allocations++;
1102 
1103  /* Compute size of new object and determine where we should */
1104  /* allocate from */
1105  requestLength = roundObjectBoundary(requestLength);
1106 
1107  /* is this a typical small object? */
1108  if (requestLength <= LargeBlockThreshold)
1109  {
1110  /* make sure we don't go below our minimum size. */
1111  if (requestLength < MinimumObjectSize)
1112  {
1113  requestLength = MinimumObjectSize;
1114  }
1115  newObj = newSpaceNormalSegments.allocateObject(requestLength);
1116  /* feat. 1061 moves the handleAllocationFailure code into the initial */
1117  /* allocation parts; this way an "if" instruction can be saved. */
1118  if (newObj == NULL)
1119  {
1120  newObj = newSpaceNormalSegments.handleAllocationFailure(requestLength);
1121  }
1122  }
1123  /* we keep the big objects in a separate cage */
1124  else
1125  {
1126  /* round this allocation up to the appropriate large boundary */
1127  requestLength = roundLargeObjectAllocation(requestLength);
1128  newObj = newSpaceLargeSegments.allocateObject(requestLength);
1129  if (newObj == NULL)
1130  {
1131  newObj = newSpaceLargeSegments.handleAllocationFailure(requestLength);
1132  }
1133  }
1134 
1136 
1137  if (this->saveStack != OREF_NULL)
1138  {
1139  /* saveobj doesn't get turned on */
1140  /*until the system is initialized */
1141  /*far enough but once its on, push */
1142  /*this new obj on the save stack to */
1143  /*keep him from being garbage */
1144  /*collected, before it can be used */
1145  /*and safely anchored by caller. */
1146  pushSaveStack(newObj);
1147  }
1148  /* return the newly allocated object to our caller */
1149  return newObj;
1150 }
1151 
1152 
1154  size_t size,
1155  size_t count,
1156  size_t objectType)
1157 /******************************************************************************/
1158 /* Arguments: size of individual objects, */
1159 /* number of objects to get */
1160 /* behaviour of the new objects. */
1161 /* */
1162 /* Function : Return an Array of count objects of size size, with the given */
1163 /* behaviour. Each objects will be cleared */
1164 /* Returned: Array object */
1165 /* */
1166 /******************************************************************************/
1167 {
1168  size_t i;
1169  size_t objSize = roundObjectBoundary(size);
1170  size_t totalSize; /* total size allocated */
1171  RexxObject *prototype; /* our first prototype object */
1172 
1173  RexxArray *arrayOfObjects;
1174  RexxObject *largeObject;
1175 
1176  /* Get array object to contain all the objects.. */
1177  arrayOfObjects = (RexxArray *)new_array(count);
1178 
1179  /* Get one LARGE object, that we will parcel up into the smaller */
1180  /* objects over allocate by the size of one minimum object so we */
1181  /* can handle any potential overallocations */
1182  totalSize = objSize * count; /* first get the total object size */
1183  /* We make the decision on which heap this should be allocated */
1184  /* from based on the size of the object request rather than the */
1185  /* total size of the aggregate object. Since our normal usage of */
1186  /* this is for allocating large collections of small objects, we */
1187  /* don't want those objects coming from the large block heap, */
1188  /* even if the aggregate size would suggest this should happen. */
1189  if (objSize <= LargeBlockThreshold)
1190  {
1191  largeObject = newSpaceNormalSegments.allocateObject(totalSize);
1192  if (largeObject == OREF_NULL)
1193  {
1194  largeObject = newSpaceNormalSegments.handleAllocationFailure(totalSize);
1195  }
1196  }
1197  /* we keep the big objects in a separate cage */
1198  else
1199  {
1200  largeObject = newSpaceLargeSegments.allocateObject(totalSize);
1201  if (largeObject == OREF_NULL)
1202  {
1203  largeObject = newSpaceLargeSegments.handleAllocationFailure(totalSize);
1204  }
1205  }
1206 
1208 
1209  if (this->saveStack != OREF_NULL)
1210  {
1211  /* saveobj doesn't get turned on */
1212  /*until the system is initialized */
1213  /*far enough but once its on, push */
1214  /*this new obj on the save stack to */
1215  /*keep him from being garbage */
1216  /*collected, before it can be used */
1217  /*and safely anchored by caller. */
1218  pushSaveStack(largeObject);
1219  }
1220 
1221  /* Description of defect 318: IH:
1222 
1223  The problem is caused by the constructor of RexxClause which is calling newObjects.
1224  NewObjects allocates one large Object. Immediately after this large Object is allocated,
1225  an array is allocated as well. It then can happen that while allocating the array
1226  the largeObject shall be marked. This causes a trap when objectVariables is != NULL.
1227 
1228  Solution: Set objectVariables to NULL before allocating the array. In order to make
1229  OrefOK (called if CHECKOREF is defined) work properly, the largeObject has to be
1230  set to a valid object state before calling new_array. Therefore the behaviour assignement
1231  and the virtual functions assignement has to be done in advance. */
1232 
1233  /* get the remainder object size...this is used to manage the */
1234  /* dangling piece on the end of the allocation. */
1235  totalSize = largeObject->getObjectSize() - totalSize;
1236 
1237  /* Clear out the entire object... */
1238  largeObject->clearObject();
1239 
1240  prototype = largeObject;
1241 
1242  /* IH: Object gets a valid state for the mark and sweep process. */
1243  /* Otherwise OrefOK (CHECKOREFS) will fail */
1244 
1245  // initialize the hash table object
1246  largeObject->initializeNewObject(objSize, markWord, virtualFunctionTable[objectType], RexxBehaviour::getPrimitiveBehaviour(objectType));
1247 
1248  for (i=1 ;i < count ; i++ )
1249  {
1250  /* IH: Loop one time less than before because first object is initialized
1251  outside of the loop. I had to move the following 2 statements
1252  in front of the object initialization */
1253  /* add this object to the array of objs */
1254  arrayOfObjects->put(largeObject, i);
1255  /* point to the next object space. */
1256  largeObject = (RexxObject *)((char *)largeObject + objSize);
1257  /* copy the information from the prototype */
1258  memcpy((void *)largeObject, (void *)prototype, sizeof(RexxInternalObject));
1259  }
1260  arrayOfObjects->put(largeObject, i); /* put the last Object */
1261 
1262  /* adjust the size of the last one to account for any remainder */
1263  largeObject->setObjectSize(totalSize + objSize);
1264 
1265  return arrayOfObjects; /* Return our array of objects. */
1266 }
1267 
1268 
1269 void RexxMemory::reSize(RexxObject *shrinkObj, size_t requestSize)
1270 /******************************************************************************/
1271 /* Function: The object shrinkObj only needs to be the size of newSize */
1272 /* If the left over space is big enough to become a dead object */
1273 /* we will shrink the object to the specified size. */
1274 /* NOTE: Since memory knows nothing about any objects that are */
1275 /* in the extra space, it cannot do anything about them if this */
1276 /* is an OldSpace objetc, therefore the caller must have already */
1277 /* take care of this. */
1278 /* */
1279 /******************************************************************************/
1280 {
1281  DeadObject *newDeadObj;
1282 
1283  size_t newSize = roundObjectResize(requestSize);
1284 
1285  /* is the rounded size smaller and is remainder at least the size */
1286  /* of the smallest OBJ MINOBJSIZE */
1287  if (newSize < requestSize && (shrinkObj->getObjectSize() - newSize) >= MinimumObjectSize)
1288  {
1289  size_t deadObjectSize = shrinkObj->getObjectSize() - newSize;
1290  /* Yes, then we can shrink the object. Get starting point of */
1291  /* the extra, this will be the new Dead obj */
1292  newDeadObj = new ((void *)((char *)shrinkObj + newSize)) DeadObject (deadObjectSize);
1293  /* if an object is larger than 16 MB, the last 8 bits (256) are */
1294  /* truncated and therefore the object must have a size */
1295  /* dividable by 256 and the rest must be put to the dead chain. */
1296  /* If the resulting dead object is smaller than the size we */
1297  /* gave, then we've got a truncated remainder we need to turn */
1298  /* into a dead object. */
1299  deadObjectSize -= newDeadObj->getObjectSize();
1300  if (deadObjectSize != 0)
1301  {
1302  /* create difference object. Note: We don't bother */
1303  /* putting this back on the dead chain. It will be */
1304  /* picked up during the next GC cycle. */
1305  new ((char *)newDeadObj + newDeadObj->getObjectSize()) DeadObject (deadObjectSize);
1306  }
1307  /* Adjust size of original object */
1308  shrinkObj->setObjectSize(newSize);
1309  }
1310 }
1311 
1312 
1314  MemorySegmentSet *requestor, /* the requesting segment set */
1315  size_t allocationLength) /* the size required */
1316 /******************************************************************************/
1317 /* Function: Orchestrate sharing of sharing of storage between the segment */
1318 /* sets in low storage conditions. We do this only as a last ditch, as we'll */
1319 /* end up fragmenting the large heap with small blocks, messing up the */
1320 /* benefits of keeping the heaps separate. We first look a set to donate a */
1321 /* segment to the requesting set. If that doesn't work, we'll borrow a block */
1322 /* of storage from the other set so that we can satisfy this request. */
1323 /******************************************************************************/
1324 {
1325  MemorySegmentSet *donor;
1326 
1327  /* first determine the donor/requester relationships. */
1328  if (requestor->is(MemorySegmentSet::SET_NORMAL))
1329  {
1330  donor = &newSpaceLargeSegments;
1331  }
1332  else
1333  {
1334  donor = &newSpaceNormalSegments;
1335  }
1336 
1337  /* first look for an unused segment. We might be able to steal */
1338  /* one and just move it over. */
1339  MemorySegment *newSeg = donor->donateSegment(allocationLength);
1340  if (newSeg != NULL)
1341  {
1342  requestor->addSegment(newSeg);
1343  return;
1344  }
1345 
1346  /* we can't just move a segment over. Find the smallest block */
1347  /* we can find that will satisfy this allocation. If found, we */
1348  /* can insert it into the normal deadchains. */
1349  DeadObject *largeObject = donor->donateObject(allocationLength);
1350  if (largeObject != NULL)
1351  {
1352  /* we need to insert this into the normal dead chain */
1353  /* locations. */
1354  requestor->addDeadObject(largeObject);
1355  }
1356 }
1357 
1358 
1360 /******************************************************************************/
1361 /* Function: Process a live-stack overflow situation */
1362 /******************************************************************************/
1363 {
1364  /* create a temporary stack */
1365  RexxStack *newLiveStack = new (this->liveStack->size * 2, true) RexxStack (this->liveStack->size * 2);
1366  /* copy the live stack entries */
1367  newLiveStack->copyEntries(this->liveStack);
1368  /* has this already been expanded? */
1369  if (this->liveStack != this->originalLiveStack)
1370  {
1371  free((void *)this->liveStack); /* release the old one */
1372  }
1373  this->liveStack = newLiveStack; /* and set the new stack */
1374 }
1375 
1376 void RexxMemory::mark(RexxObject *markObject)
1377 /******************************************************************************/
1378 /* Function: Perform a memory management mark operation */
1379 /******************************************************************************/
1380 {
1381  size_t liveMark = markWord | OldSpaceBit;
1382 
1383  markObject->setObjectLive(markWord); /* Then Mark this object as live. */
1384  /* object have any references? */
1385  /* if there are no references, we don't */
1386  /* need to push this on the stack, but */
1387  /* we might need to push the behavior */
1388  /* on the stack. Since behaviors are */
1389  /* we can frequently skip that step as well */
1390  if (markObject->hasNoReferences())
1391  {
1392  if (ObjectNeedsMarking(markObject->behaviour))
1393  {
1394  /* mark the behaviour now to keep us from processing this */
1395  /* more than once. */
1396  markObject->behaviour->setObjectLive(markWord);
1397  /* push him to livestack, to mark */
1398  /* later. */
1399  pushLiveStack((RexxObject *)markObject->behaviour);
1400  }
1401  }
1402  else
1403  {
1404  /* push him to livestack, to mark */
1405  /* later. */
1406  pushLiveStack(markObject);
1407  }
1408 }
1409 
1411 /******************************************************************************/
1412 /* Function: Allocate and setup a temporary object obtained via malloc */
1413 /* storage. This is used currently only by the mark routine to */
1414 /* expand the size of the live stack during a garbage collection. */
1415 /******************************************************************************/
1416 {
1417  /* get the rounded size of the object*/
1418  size_t allocationLength = roundObjectBoundary(requestLength);
1419  /* allocate a new object */
1420  RexxObject *newObj = (RexxObject *)malloc(allocationLength);
1421  if (newObj == OREF_NULL) /* unable to allocate a new one? */
1422  {
1423  /* can't allocate, report resource */
1424  /* error. */
1426  }
1427  /* setup the new object header for */
1428  /*use */
1429  // initialize the hash table object
1431  return newObj; /* and return it */
1432 }
1433 
1435 /******************************************************************************/
1436 /* Function: Perform various general marking functions such as image save, */
1437 /* image restore, object unflatten, and debug garbage collection */
1438 /******************************************************************************/
1439 {
1440  RexxObject **pMarkObject = (RexxObject **)obj;
1441  RexxObject *markObject = *pMarkObject;
1442 
1443 
1444  if (markObject == OREF_NULL) /* is this a null reference? */
1445  {
1446  return; /* always return immediately */
1447  }
1448 
1449  /* If its a restore image mark */
1450  if (restoreimage)
1451  {
1452  /* we update the object's location */
1453  restoreMark(markObject, pMarkObject);
1454  return; /* finished */
1455  }
1456 
1457  if (objOffset != 0)
1458  { /* restoring an object? */
1459  /* we update the object's location */
1460  restoreObjectMark(markObject, pMarkObject);
1461  return; /* finished */
1462  }
1463 
1464  if (this->envelope)
1465  { /* processing an envelope? */
1466  /* do the unflatten */
1467  unflattenMark(markObject, pMarkObject);
1468  return; /* and out */
1469  }
1470 
1471 
1472  /* The OrphanCheck code is complete mark from OREF_ENV, which checks the */
1473  /* validity of each object in the entire object tree. Any invalid objects will be */
1474  /* cause the mark to terminate and output information about the invalid object and */
1475  /* its ancestry. */
1476  if ((this->orphanCheck) && !saveimage)
1477  {
1478  /* do the special validity check mark. */
1479  orphanCheckMark(markObject, pMarkObject);
1480  /* all done here, so return */
1481  return;
1482  }
1483 
1484 
1485  if (!saveimage)
1486  {
1487  Interpreter::logicError("Wrong mark routine called");
1488  }
1489 
1490  /* we're doing the image construction work */
1491  saveImageMark(markObject, pMarkObject);
1492 }
1493 
1494 
1495 void RexxMemory::saveImageMark(RexxObject *markObject, RexxObject **pMarkObject)
1496 /******************************************************************************/
1497 /* Function: Perform marking during a save image operation */
1498 /******************************************************************************/
1499 {
1500  RexxObject *bufferReference;
1501  size_t size;
1502  /* Regular GC or Saveimage processing. if a REAL object and not */
1503  /* already marked and not in Old Space. */
1504  if (markObject != OREF_NULL && !markObject->isObjectLive(markWord) && markObject->isNewSpace())
1505  {
1506  /* Then Mark this object as live. */
1507  markObject->setObjectLive(markWord);
1508  /* push him to livestack, so we can mark (at a later time) his */
1509  /* references. */
1510  pushLiveStack(markObject);
1511  /* Get size of this object. */
1512  size = markObject->getObjectSize();
1513  /* add this to our image statistics */
1514  logObjectStats(markObject);
1515 
1516  /* address the copy in the image */
1517  bufferReference = (RexxObject *)(image_buffer + image_offset);
1518  // we allocated a hard coded buffer, so we need to make sure we don't blow
1519  // the buffer size.
1520  if (image_offset + size> MaxImageSize)
1521  {
1522  Interpreter::logicError("Rexx saved image exceeds expected maximum");
1523  }
1524  /* Copy object to image buffer. */
1525  memcpy((void *)bufferReference, (void *)markObject, size);
1526  /* clear the mark in the copy */
1527  bufferReference->clearObjectMark();
1528  /* Retrieve the behaviour obj */
1529  behaviour = bufferReference->behaviour;
1530  /* Working with a primitive behaviour or a copy? */
1531  if (behaviour->isNonPrimitive())
1532  {
1533  /* tag this as a non-primitive behav */
1534  bufferReference->setNonPrimitive();
1535  }
1536  else
1537  {
1538  if (behaviour->isTransientClass())
1539  {
1540  Interpreter::logicError("Transient class included in image buffer");
1541  }
1542  /* clear this out, as this is overloaded with the oldspace */
1543  /* flag. */
1544  bufferReference->setPrimitive();
1545  // replace behaviour with normalized type number
1546  bufferReference->behaviour = behaviour->getSavedPrimitiveBehaviour();
1547  }
1548 
1549  /* we are saving image at this point, no need to keep track of */
1550  /* Remembered set so don't use OrefSet here. */
1551  markObject->behaviour = (RexxBehaviour *)image_offset;
1552  /* update image_offset to point to where next object is to be */
1553  /* placed in image */
1554  image_offset += size;
1555  }
1556 
1557  /* If its a saveimage, modify object referencing this "moved" obj */
1558  /* with it location within the image Buffer */
1559  *pMarkObject = (RexxObject *)markObject->behaviour;
1560 }
1561 
1562 
1563 void RexxMemory::orphanCheckMark(RexxObject *markObject, RexxObject **pMarkObject)
1564 /******************************************************************************/
1565 /* Function: Perform orphan check marking on an object */
1566 /******************************************************************************/
1567 {
1568  const char *outFileName;
1569  FILE *outfile;
1570  bool firstnode;
1571  RexxString *className;
1572  const char *objectClassName;
1573 
1574  /* check for invalid objects */
1575  if (!objectReferenceOK(markObject))
1576  {
1577  /* Get a temporary file name for out */
1578  outFileName = SysFileSystem::getTempFileName();
1579  /* Open the temp file for the dump. */
1580  outfile = fopen(outFileName,"wb");
1581  logMemoryCheck(outfile, "Found non Object at %p, being marked from %p\n",markObject, pMarkObject);
1582  /* Let the traversal know we want */
1583  /* more info about first guy... */
1584  firstnode = true;
1585  /* If the object is in object storage*/
1586  if (inObjectStorage(markObject))
1587  {
1588  /* DIsplay a few words of the object's storage. */
1589  logMemoryCheck(outfile, " non-Object dump -->%8.8X %8.8X %8.8X %8.8X \n", *(int32_t *)markObject, *((int32_t *)markObject+1) , *((int32_t *)markObject+2) , *((int32_t *)markObject+3));
1590  logMemoryCheck(outfile, " non-Object dump -->%8.8X %8.8X %8.8X %8.8X \n", *((int32_t *)markObject+4) , *((int32_t *)markObject+5) , *((int32_t *)markObject+6) , *((int32_t *)markObject+7));
1591  logMemoryCheck(outfile, " non-Object dump -->%8.8X %8.8X %8.8X %8.8X \n", *((int32_t *)markObject+8) , *((int32_t *)markObject+9) , *((int32_t *)markObject+10), *((int32_t *)markObject+11));
1592  logMemoryCheck(outfile, " non-Object dump -->%8.8X %8.8X %8.8X %8.8X \n", *((int32_t *)markObject+12), *((int32_t *)markObject+13), *((int32_t *)markObject+14), *((int32_t *)markObject+15));
1593 
1594  }
1595  /* Time to traverse the livestack and get this guy's ancestry--very useful */
1596  /* information for debugging this type of problem. */
1597  for (markObject = popLiveStack();
1598  markObject != OREF_NULL; /* test for unique terminator */
1599  markObject = popLiveStack())
1600  {
1601 
1602  /* OREF_NIL marks an ancestor */
1603  if (markObject == TheNilObject)
1604  {
1605  /* pop the ancestor */
1606  markObject = popLiveStack();
1607  className = markObject->id();
1608  if (className == OREF_NULL)
1609  objectClassName = "";
1610  else
1611  objectClassName = className->getStringData();
1612  if (firstnode)
1613  { /* is this the first node?? */
1614  printf("-->Parent node was marking offset '%ld'x \n", (char *)pMarkObject - (char *)markObject);
1615  dumpObject(markObject, outfile);
1616  firstnode = false;
1617  logMemoryCheck(outfile, "Parent node is at %p, of type %s(%d) \n",
1618  markObject, objectClassName, markObject->behaviour->getClassType());
1619  }
1620  else
1621  {
1622  logMemoryCheck(outfile, "Next node is at %p, of type %s(%d) \n",
1623  markObject, objectClassName, markObject->behaviour->getClassType());
1624  }
1625  }
1626  }
1627  /* reached the OREF_NULL sentinel */
1628  logMemoryCheck(outfile, "Finished popping stack !!\n");
1629  printf("All data has been captured in file %s \n", outFileName);
1630  fclose(outfile); /* Close the file, all with it. */
1631  /* Make sure we exit the GC critical */
1632  /* otherwise the cleanup from logic */
1633  /* error will hang !!! */
1634  /* we would have crashed soon anyway!*/
1635  Interpreter::logicError("Bad Object found during GC !\n");
1636  }
1637 
1638  if (!markObject->isObjectLive(markWord) && markObject->isNewSpace())
1639  {
1640  markObject->setObjectLive(markWord); /* Mark this object as live */
1641  /* push him to livestack, so we can */
1642  /*mark (at a later time) his */
1643  /*references. */
1644  pushLiveStack(markObject);
1645  }
1646 }
1647 
1648 
1650 {
1651  /* Remove object form savetable */
1652  saveTable->remove((RexxObject *)obj);
1653  /* no memory section needed */
1654  saveStack->push((RexxObject *)obj);
1655 }
1656 
1657 
1659 /******************************************************************************/
1660 /* Function: Place an object on the hold stack */
1661 /******************************************************************************/
1662 {
1663  /* Push object onto saveStack */
1664  saveStack->push((RexxObject *)obj);
1665  /* return held object */
1666  return (RexxObject *)obj;
1667 }
1668 
1670 /******************************************************************************/
1671 /* Arguments: Maximum and minimum allocations between reclamations */
1672 /******************************************************************************/
1673 {
1674  return OREF_NULL;
1675 }
1676 
1677 /**
1678  * Save the memory image as part of the interpreter
1679  * build.
1680  */
1681 void RexxMemory::saveImage(const char *imageTarget)
1682 /******************************************************************************/
1683 /* Function: Save the memory image as part of interpreter build */
1684 /******************************************************************************/
1685 {
1686  FILE *image;
1687  RexxObject *markObject;
1688  MemoryStats _imageStats;
1689  /* array of objects needed at front */
1690  /*of image for faster restore. */
1691  int i; /* loop counter */
1692  RexxArray *primitive_behaviours; /* saved array of behaviours */
1693  RexxArray *saveArray; /* array of objects needed at front */
1694 
1695  this->imageStats = &_imageStats; /* set the pointer to the current collector */
1696  /* of image for faster restore. */
1697  _imageStats.clear(); /* clear out image counters */
1698 
1699  markReason = SAVINGIMAGE; // this is an image save
1700 
1702  /* memory Object not saved */
1703  TheKernel->remove(getGlobalName(CHAR_MEMORY));
1704 
1705  // this has been protecting every thing critical
1706  // from GC events thus far, but now we remove it because
1707  // it contains things we don't want to save in the image.
1708  TheEnvironment->remove(getGlobalName(CHAR_KERNEL));
1709 
1710  /* remove any programs left over in */
1711  /* Get an array to hold all special */
1712  /*objs */
1713  saveArray = new_array(saveArray_highest);
1714  // Note: A this point, we don't have an activity we can use ProtectedObject to save
1715  // this with, so we need to use saveObject();
1716  saveObject(saveArray);
1717  /* Add all elements needed in */
1718  /*saveArray */
1719  saveArray->put((RexxObject *)TheEnvironment, saveArray_ENV);
1720  saveArray->put((RexxObject *)TheKernel, saveArray_KERNEL);
1721  saveArray->put((RexxObject *)TheTrueObject, saveArray_TRUE);
1722  saveArray->put((RexxObject *)TheFalseObject, saveArray_FALSE);
1723  saveArray->put((RexxObject *)TheNilObject, saveArray_NIL);
1724  saveArray->put((RexxObject *)TheNullArray, saveArray_NULLA);
1726  saveArray->put((RexxObject *)TheClassClass, saveArray_CLASS);
1728  saveArray->put((RexxObject *)TheSystem, saveArray_SYSTEM);
1732 
1733  /* create the behaviour array */
1734  primitive_behaviours= (RexxArray *)new_array(T_Last_Exported_Class + 1);
1735  /* copy all of the primitive */
1736  for (i = 0; i <= T_Last_Exported_Class; i++)
1737  {
1738  /* behaviours into this array */
1739  primitive_behaviours->put((RexxObject *)RexxBehaviour::getPrimitiveBehaviour(i), i + 1);
1740  }
1741  /* add to the save array */
1742  saveArray->put(primitive_behaviours, saveArray_PBEHAV);
1743 
1744  image_buffer = (char *)malloc(MaxImageSize);
1745  image_offset = sizeof(size_t);
1746  saveimage = true;
1747  disableOrefChecks(); /* Don't try to check OrefSets now. */
1748  bumpMarkWord();
1749  /* push a unique terminator */
1751  /* don't want to save */
1752  /*savestack/savetabl */
1753  saveStack = OREF_NULL;
1754  /* or any of there references in the */
1755  saveTable = OREF_NULL;
1756  /* image, which will become OldSpace */
1758 
1759  pushLiveStack(OREF_NULL); /* push a unique terminator */
1760  memory_mark_general(saveArray); /* push live root */
1761 
1762  for (markObject = popLiveStack();
1763  markObject != OREF_NULL; /* test for unique terminator */
1764  markObject = popLiveStack())
1765  {
1766  /* The mark of this object moved it */
1767  /*to the image, its behaviour now */
1768  /*contains its offset in the image */
1769  /* so point to the object in the */
1770  /*image. */
1771  /* the buffer copy */
1772  RexxObject *copyObject = (RexxObject *)(image_buffer+(uintptr_t)markObject->behaviour);
1773 
1774  copyObject->liveGeneral(SAVINGIMAGE); /* mark other referenced objs */
1775  /* non-primitive behaviour? */
1776  if (copyObject->isNonPrimitive())
1777  /* mark/move behaviour live */
1778  memory_mark_general(copyObject->behaviour);
1779  }
1780 
1781  image = fopen(imageTarget == NULL ? BASEIMAGE : imageTarget,"wb");
1782 // image.open(imageTarget == NULL ? BASEIMAGE : imageTarget, RX_O_CREAT | RX_O_TRUNC | RX_O_WRONLY, RX_S_IREAD | RX_S_IWRITE, RX_SH_DENYRW);
1783  /* PLace actual size at beginning of buffer*/
1784  memcpy(image_buffer, &image_offset, sizeof(size_t));
1785  /* Write out buffer (image) */
1786  fwrite(image_buffer, 1, image_offset, image);
1787  fclose(image);
1788  free(image_buffer);
1789 
1790  printf("Object stats for this image save are \n");
1791  _imageStats.printSavedImageStats();
1792  printf("\n\n Total bytes for this image %lu bytes \n", image_offset);
1793 }
1794 
1795 
1797 /******************************************************************************/
1798 /* Function: Dump the memory tables */
1799 /******************************************************************************/
1800 {
1801 #ifdef _DEBUG
1802  FILE *dumpfile;
1803  FILE *keyfile;
1805  int i;
1806 
1807  if (dumpEnable)
1808  {
1809  /* don't allow another dump unless */
1810  /*reset by user */
1811  memoryObject.dumpEnable = false;
1812  /* first generate the dump by writing*/
1813  /* each segment to the dumpfile */
1814  printf("Dumping object memory to orexdump.dmp\n");
1815  /* open for binary write */
1816  dumpfile = fopen("orexdump.dmp","wb");
1817  /* now generate the key file which */
1818  /*is a series of REXX statements */
1819  printf("Creating dump key file in orexdump.key\n");
1820  /* open for text write */
1821  keyfile = fopen("orexdump.key","w");
1822  fprintf(keyfile, "/* Object REXX dump key file */\n");
1823  fprintf(keyfile, "memoryaddr = %p\n", this);
1824  fprintf(keyfile, "marker = %d\n", markWord);
1825  /* dump the oldspace segments */
1826  oldSpaceSegments.dumpSegments(keyfile, dumpfile);
1827  /* followed by the newer allocations */
1828  newSpaceNormalSegments.dumpSegments(keyfile, dumpfile);
1829  newSpaceLargeSegments.dumpSegments(keyfile, dumpfile);
1830 
1831  i = 0;
1832  while (currentPool)
1833  {
1834  i++;
1835  fprintf(keyfile, "Pool addr.%d = %p\n", i, currentPool);
1836  fprintf(keyfile, "Pool size.%d = %d\n", i, currentPool->reserved);
1838  }
1839 
1840  for (i = 0; i <= T_Last_Exported_Class; i++)
1841  {
1842  fprintf(keyfile, "Behaviour type %d = %p\n", i, RexxBehaviour::getPrimitiveBehaviour(i));
1843  }
1844 
1845  /* now close actual dump and key file*/
1846  fclose(dumpfile);
1847  fclose(keyfile);
1848  }
1849 #endif
1850  return OREF_NULL;
1851 }
1852 
1853 
1855 /******************************************************************************/
1856 /* Arguments: selection, 0 for no, anything else for yes */
1857 /* */
1858 /* Returned: Nothing */
1859 /******************************************************************************/
1860 {
1861  if (selection != OREF_NULL)
1862  {
1864  }
1865  return selection;
1866 }
1867 
1869 /******************************************************************************/
1870 /* Arguments: None */
1871 /* */
1872 /* Returned: Nothing */
1873 /******************************************************************************/
1874 {
1875  wholenumber_t count, testcount;
1876  HashLink j;
1877  bool restoreimagesave;
1878  RexxInteger *value;
1879  RexxInteger *testValue;
1880  RexxObject *index;
1881  /* temp OREF used to hold original */
1882  /*and test versions */
1883  RexxIdentityTable *tempold2new;
1884 
1885  printf("Comparing old2new with the current system.\n");
1886 
1887  /* build a test remembered set */
1888  tempold2new = new_identity_table();
1889  restoreimagesave = restoreimage;
1890  restoreimage = true; /* setting both of these to true will*/
1891  /* traverse System OldSpace and live */
1892  /*mark all objects */
1894 
1895  restoreimage = restoreimagesave; /* all done building remembered set */
1896  /* For all object in old2new table */
1897  for (j = old2new->first();
1898  (index = (RexxObject *)old2new->index(j)) != OREF_NULL;
1899  j = old2new->next(j))
1900  {
1901  /* Get refCount for this obj old2new */
1902  value = (RexxInteger *)this->old2new->get(index);
1903  /* new refcount for obj in newly */
1904  /*build old2new table */
1905  testValue = (RexxInteger *)tempold2new->get(index);
1906  /* Was object found in new table? */
1907  if (testValue == OREF_NULL)
1908  {
1909  /* nope, extra stuff in orig. */
1910  printf("object: %p, type: %lu, is extra in old2new.\n\n",
1911  index, index->behaviour->getClassType());
1912  }
1913  else
1914  {
1915  /* now make sure both refCounts are */
1916  /* the same. */
1917  count = value->getValue();
1918  testcount = testValue->getValue();
1919  if (count != testcount)
1920  {
1921  printf("object: %p, type: %lu, has an incorrect refcount.\n",
1922  index, index->behaviour->getClassType());
1923  printf("Refcount for object is %ld, should be %ld.\n\n", count, testcount);
1924  }
1925  /* now remove object from new table */
1926  tempold2new->remove(index);
1927  }
1928  }
1929  /* Anything left in new table was */
1930  /* missing from original old2new */
1931  /* so iterate through it and report */
1932  /* the missing objects */
1933  for (j = tempold2new->first();
1934  (index = (RexxObject *)tempold2new->index(j)) != OREF_NULL;
1935  j = tempold2new->next(j))
1936  {
1937  printf("object: %p, type: %lu, is missing from old2new.\n\n",
1938  index,index->behaviour->getClassType());
1939  }
1940 
1941  /* now take a dump so that we can */
1942  /* diagnose any problems we just */
1943  /*uncovered */
1944  printf("Dumping object memory.\n"); /* tell the user what's happening */
1945  this->dumpEnable = true; /* turn dumps on */
1946  this->dump(); /* take the dump */
1947 
1948  return OREF_NULL;
1949 }
1950 
1951 
1952 void RexxMemory::setObjectOffset(size_t offset)
1953 /******************************************************************************/
1954 /* Arguments: offset, the length to add to references within arriving objects*/
1955 /* since only one unflattem can happen at a time, we need to ensure */
1956 /* serialization, so if already have an objOffset, wait unto done. */
1957 /* */
1958 /* Returned: Nothing */
1959 /******************************************************************************/
1960 {
1961  /* Starting or ending? */
1962  if (offset != 0)
1963  {
1964 
1965  /* have a value, starting unflatten. See if we can get MUTEX */
1966  /* immed */
1967  if (!unflattenMutex.requestImmediate("RexxMemory::setObjectOffset", 0))
1968  {
1969  {
1970  UnsafeBlock releaser;
1971  /* wait for current unflatten to end */
1972  unflattenMutex.request("RexxMemory::setObjectOffset", 0);
1973  }
1974  }
1975  }
1976  else
1977  {
1978  /* no value, ending an unflatten */
1979  /* Release the MUTEX. */
1980  unflattenMutex.release("RexxMemory::setObjectOffset", 0);
1981  }
1982 
1983  /* setup offSet value. */
1984  this->objOffset = offset;
1985 }
1986 
1988 /******************************************************************************/
1989 /* Arguments: envelope object, */
1990 /* since only one unflattem can happen at a time, we need to ensure */
1991 /* serialization, so if already have an envelope, wait unto done. */
1992 /* */
1993 /* Returned: Nothing */
1994 /******************************************************************************/
1995 {
1996  /* Starting or ending? */
1997  if (_envelope != OREF_NULL)
1998  {
1999  /* have a value, starting unflatt */
2000  /* See if we can get MUTEX immed */
2001  if (!envelopeMutex.requestImmediate("RexxMemory::setEnvelope", 0))
2002  {
2003  /* Nope, have to wait for it. */
2004  /* release kernel access. */
2005  {
2006  UnsafeBlock releaser;
2007  envelopeMutex.request("RexxMemory::setEnvelope", 0); /* wait for current unflat to end */
2008  }
2009  }
2010  }
2011  else
2012  {
2013  /* no value, ending an unflatten */
2014  envelopeMutex.release("RexxMemory::setEnvelope", 0); /* Release the MUTEX. */
2015  }
2016 
2017  this->envelope = _envelope; /* set the envelope object */
2018 }
2019 
2020 
2022 /******************************************************************************/
2023 /* Arguments: index-- OREF to set; value--OREF to which objr is set */
2024 /* */
2025 /* Returned: nothing */
2026 /* */
2027 /******************************************************************************/
2028 {
2029  RexxInteger *refcount;
2030  RexxObject **oldValueLoc = (RexxObject **)oldValue;
2031  RexxObject *index = *oldValueLoc;
2032 
2033  if (old2new != OREF_NULL)
2034  {
2035  if (index != OREF_NULL && index->isNewSpace())
2036  {
2037  /* decrement reference count for */
2038  /**index */
2039  refcount = (RexxInteger *)this->old2new->get(index);
2040  if (refcount != OREF_NULL)
2041  {
2042  /* found a value for refcount, now */
2043  /*decrement the count */
2044  refcount->decrementValue();
2045  /* if the new value is 0, *index is */
2046  /*no longer ref'ed from oldspace */
2047  if (refcount->getValue() == 0)
2048  {
2049  /* delete the entry for *index */
2050  this->old2new->remove(index);
2051  }
2052  }
2053  else
2054  {
2055  /* naughty, naughty, someone didn't use SetOref */
2056  printf("******** error in memory_setoref, unable to decrement refcount\n");
2057  printf("Naughty object reference is from: %p\n", oldValueLoc);
2058  printf("Naughty object reference is at: %p\n", index);
2059  printf("Naughty object reference type is: %lu\n", (index)->behaviour->getClassType());
2060  }
2061  }
2062  if (value != OREF_NULL && value->isNewSpace())
2063  {
2064  /* increment reference count for */
2065  /*value */
2066  refcount = (RexxInteger *)this->old2new->get(value);
2067  /* was there a reference here */
2068  /*already? */
2069  if (refcount)
2070  {
2071  /* yep, found one, so just increment */
2072  /*it */
2073  refcount->incrementValue();
2074  }
2075  else
2076  {
2077  /* nope, this is the first, so set */
2078  /*the refcount to 1 */
2079  // NOTE: We don't use new_integer here because we need a mutable
2080  // integer and can't use the one out of the cache.
2081  this->old2new->put(new RexxInteger(1), value);
2082  }
2083  }
2084  }
2085  /* now make the assignment, just */
2086  /*like all this stuff never happened!*/
2087  return *oldValueLoc = value;
2088 }
2089 
2090 
2092  RexxObject *setter,
2093  RexxObject **index,
2094  RexxObject *value,
2095  const char *fileName,
2096  int lineNum)
2097 /******************************************************************************/
2098 /* Arguments: index-- OREF to set; value--OREF to which objr is set */
2099 /* */
2100 /* Returned: nothing */
2101 /* */
2102 /******************************************************************************/
2103 {
2104  bool allOK = true;
2105  const char *outFileName;
2106  FILE *outfile;
2107  /* Skip all checks during saveimage */
2108  if (checkSetOK)
2109  { /* and initial part of restore Image */
2110  if (!inObjectStorage(setter))
2111  { /* Is the setter object invalid */
2112  allOK = false; /* No, just put out setters addr. */
2113  outFileName = SysFileSystem::getTempFileName();/* Get a temporary file name for out */
2114  outfile = fopen(outFileName,"wb");
2115  logMemoryCheck(outfile, "The Setter object at %p is invalid...\n");
2116 
2117  /* Is the new value a real object? */
2118  }
2120  {
2121  allOK = false; /* No, put out the info */
2122  outFileName = SysFileSystem::getTempFileName();/* Get a temporary file name for out */
2123  outfile = fopen(outFileName,"wb");
2124  logMemoryCheck(outfile, "The Setter object at %p attempted to put a non object %p, at offset %p\n",setter, value, (char *)index - (char *)setter);
2125  logMemoryCheck(outfile, " A dump of the Setting object follows: \n");
2126  dumpObject(setter, outfile);
2127 
2128  }
2129  else if (index >= (RexxObject **)((char *)setter + setter->getObjectSize()))
2130  {
2131  allOK = false; /* Yes, let them know */
2132  outFileName = SysFileSystem::getTempFileName();/* Get a temporary file name for out */
2133  outfile = fopen(outFileName,"wb");
2134  logMemoryCheck(outfile, "The Setter object at %p has tried to store at offset, which is outside his object range\n",setter, (char *)index - (char *)setter);
2135  logMemoryCheck(outfile, " A dump of the Setting object follows: \n");
2136  dumpObject(setter, outfile);
2137  }
2138 
2139 
2140  }
2141 
2142  if (!allOK)
2143  {
2144  logMemoryCheck(outfile, " The error occurred in line %u of file %s\n", lineNum, fileName);
2145  printf("The dump data has been written to file %s \n",outFileName);
2146  fclose(outfile);
2147  Interpreter::logicError("Something went really wrong in SetOref ...\n");
2148  }
2149  /* now do the normal SetOref() stuff */
2150  return(setter->isOldSpace() ? (this->setOref(index, value)) : (*index = value));
2151 
2152 }
2153 
2155 /******************************************************************************/
2156 /* Function: Allocate and lock the flatten stack capability. */
2157 /******************************************************************************/
2158 {
2159  if (!flattenMutex.requestImmediate("RexxMemory::getFlattenStack", 0))
2160  {
2161  /* Nope, have to wait for it. */
2162  /* release kernel access. */
2163  {
2164  UnsafeBlock releaser;
2165  flattenMutex.request("RexxMemory::getFlattenStack", 0); /* wait for current flattento end */
2166  }
2167  }
2168  /* create a temporary stack */
2169  this->flattenStack = new (LiveStackSize, true) RexxStack (LiveStackSize);
2170  return this->flattenStack; /* return flatten Stack */
2171 }
2172 
2174 /******************************************************************************/
2175 /* Function: Release the flatten stack */
2176 /******************************************************************************/
2177 {
2178  free((void *)this->flattenStack); /* release the flatten stack */
2179  this->flattenMutex.release("RexxMemory::returnFlattenStack", 0); /* and release the semaphore */
2180 }
2181 
2183 /******************************************************************************/
2184 /* */
2185 /******************************************************************************/
2186 {
2187  MemoryStats _imageStats;
2188 
2189  /* clear all of the statistics */
2190  _imageStats.clear();
2191  /* gather a fresh set of stats for all of the segments */
2192  newSpaceNormalSegments.gatherStats(&_imageStats, &_imageStats.normalStats);
2193  newSpaceLargeSegments.gatherStats(&_imageStats, &_imageStats.largeStats);
2194 
2195  /* print out the memory statistics */
2196  _imageStats.printMemoryStats();
2197  return TheNilObject;
2198 }
2199 
2200 
2201 /**
2202  *
2203  * Add a new pool to the memory set.
2204  *
2205  * @param pool The new pool.
2206  */
2208 {
2209  currentPool = pool;
2210 }
2211 
2212 
2214 /******************************************************************************/
2215 /* Function: Free all the memory pools currently accessed by this process */
2216 /* If not already released. Then set process Pool to NULL, indicate */
2217 /* pools have been released. */
2218 /******************************************************************************/
2219 {
2220  MemorySegmentPool *pool = firstPool;
2221  while (pool != NULL)
2222  {
2223  // save the one we're about to release, and get the next one.
2224  MemorySegmentPool *releasedPool = pool;
2225  pool = pool->nextPool();
2226  // go free this pool up
2227  releasedPool->freePool();
2228  }
2229  // clear out the memory pool information
2230  firstPool = NULL;
2231  currentPool = NULL;
2232 }
2233 
2234 
2236 /******************************************************************************/
2237 /* Function: Set up the initial memory table. */
2238 /******************************************************************************/
2239 {
2240  /* fix up the previously allocated live stack to have the correct */
2241  /* characteristics...we're almost ready to go on the air. */
2244  /* set up the old 2 new table provided for us */
2245  old2new = old2newTable;
2246  /* if we have a table (this is NULL if we're not running from a */
2247  /* restored image), then add the first entry to the table. */
2248  if (old2new != NULL)
2249  {
2250  /* now add old2new itself to the old2new table! */
2251  // NOTE: We don't use new_integer here because we need a mutable
2252  // integer and can't use the one out of the cache.
2253  old2new->put(new RexxInteger(1), old2new);
2254  }
2255  /* first official OrefSet!! */
2256  OrefSet(this, markTable, old2new);
2257  /* Now get our savestack and savetable */
2258  /* allocate savestack with usable and allocated size */
2259  /* NOTE: We do not use OREF_SET here. We want to control the */
2260  /* order in which these two are marked in the live(size_t) method of */
2261  /* RexxMemory. If these are added to the mark table, they'll be */
2262  /* processed earlier than we'd like. */
2264  /* from this point on, we push things on to the save stack */
2266 }
2267 
2269 /******************************************************************************/
2270 /* Function: Do the initial lock creation for memory setup. */
2271 /******************************************************************************/
2272 {
2273  /* Create/Open Shared MUTEX */
2274  /* Semophores used to serialize */
2275  /* the flatten/unflatten process */
2276  flattenMutex.create();
2279 }
2280 
2282 /******************************************************************************/
2283 /* Function: Do the initial lock creation for memory setup. */
2284 /******************************************************************************/
2285 {
2286  /* Create/Open Shared MUTEX */
2287  /* Semophores used to serialize */
2288  /* the flatten/unflatten process */
2289  flattenMutex.close();
2291  envelopeMutex.close();
2292 }
2293 
2294 
2295 /**
2296  * Add a string to the global name table.
2297  *
2298  * @param value The new value to add.
2299  *
2300  * @return The single instance of this string.
2301  */
2303 {
2304  // see if we have a global table. If not collecting currently,
2305  // just return the non-unique value
2306 
2307  RexxString *stringValue = new_string(value);
2308  if (globalStrings == OREF_NULL)
2309  {
2310  return stringValue; /* just return the string */
2311  }
2312 
2313  // now see if we have this string in the table already
2315  if (result != OREF_NULL)
2316  {
2317  return result; // return the previously created one
2318  }
2319  /* add this to the table */
2321  return stringValue; // return the newly created one
2322 }
2323 
2324 
2326 /******************************************************************************/
2327 /* Function: Initial memory setup during image build */
2328 /******************************************************************************/
2329 {
2330  RexxClass::createInstance(); /* get the CLASS class created */
2332  /* Now get our savestack and */
2333  /*savetable */
2335  /* Create/Open Shared MUTEX */
2336  /* Semophores used to serialize */
2337  /* the flatten/unflatten process */
2339 }
2340 
2341 
2343 /******************************************************************************/
2344 /* Function: Memory management image restore functions */
2345 /******************************************************************************/
2346 {
2347  /* Retrieve special saved objects */
2348  /* OREF_ENV and primitive behaviours */
2349  /* are already restored */
2350  /* start restoring class OREF_s */
2351  RESTORE_CLASS(Object, RexxClass);
2352  RESTORE_CLASS(Class, RexxClass);
2353  /* (CLASS is already restored) */
2354  RESTORE_CLASS(String, RexxClass);
2355  RESTORE_CLASS(Array, RexxClass);
2356  RESTORE_CLASS(Directory, RexxClass);
2357  RESTORE_CLASS(Integer, RexxIntegerClass);
2358  RESTORE_CLASS(List, RexxClass);
2359  RESTORE_CLASS(Message, RexxClass);
2360  RESTORE_CLASS(Method, RexxClass);
2361  RESTORE_CLASS(Routine, RexxClass);
2362  RESTORE_CLASS(Package, RexxClass);
2364  RESTORE_CLASS(NumberString, RexxClass);
2365  RESTORE_CLASS(Queue, RexxClass);
2366  RESTORE_CLASS(Stem, RexxClass);
2367  RESTORE_CLASS(Supplier, RexxClass);
2368  RESTORE_CLASS(Table, RexxClass);
2369  RESTORE_CLASS(IdentityTable, RexxClass);
2370  RESTORE_CLASS(Relation, RexxClass);
2371  RESTORE_CLASS(MutableBuffer, RexxMutableBufferClass);
2372  RESTORE_CLASS(Pointer, RexxClass);
2373  RESTORE_CLASS(Buffer, RexxClass);
2375  RESTORE_CLASS(StackFrame, RexxClass);
2378 
2379  memoryObject.setOldSpace(); /* Mark Memory Object as OldSpace */
2380  /* initialize the tables used for garbage collection. */
2382  /* If first one through, generate all*/
2383  IntegerZero = new_integer(0); /* static integers we want to use...*/
2384  IntegerOne = new_integer(1); /* This will allow us to use static */
2385  IntegerTwo = new_integer(2); /* integers instead of having to do a*/
2386  IntegerThree = new_integer(3); /* new_integer evrytime.... */
2387  IntegerFour = new_integer(4);
2388  IntegerFive = new_integer(5);
2389  IntegerSix = new_integer(6);
2392  IntegerNine = new_integer(9);
2394 
2395  // the activity manager will create the local server, which will use the
2396  // stream classes. We need to get the external libraries reloaded before
2397  // that happens.
2399  ActivityManager::init(); /* do activity restores */
2400  PackageManager::restore(); // finish restoration of the packages.
2401  memoryObject.enableOrefChecks(); /* enable setCheckOrefs... */
2402 }
2403 
void reportException(wholenumber_t error)
RexxArray * new_array(size_t s)
Definition: ArrayClass.hpp:259
@ T_Last_Class_Type
@ T_Last_Exported_Class
@ T_Behaviour
@ T_Object
RexxIdentityTable * new_identity_table()
RexxInteger * new_integer(wholenumber_t v)
#define MemorySegmentOverhead
size_t roundSegmentBoundary(size_t n)
#define LargeBlockThreshold
#define SegmentDeadSpace
@ OldSpaceBit
Definition: ObjectClass.hpp:74
#define TheMemoryBehaviour
#define TheBehaviourBehaviour
#define TheStackBehaviour
#define TheObjectBehaviour
#define OREF_NULL
Definition: RexxCore.h:60
#define IntegerThree
Definition: RexxCore.h:192
#define IntegerSeven
Definition: RexxCore.h:196
#define TheSystem
Definition: RexxCore.h:179
#define TheKernel
Definition: RexxCore.h:178
#define IntegerFour
Definition: RexxCore.h:193
#define IntegerFive
Definition: RexxCore.h:194
#define TheNullArray
Definition: RexxCore.h:183
#define IntegerOne
Definition: RexxCore.h:190
#define TheEnvironment
Definition: RexxCore.h:174
#define TheClassClass
Definition: RexxCore.h:148
#define IntegerEight
Definition: RexxCore.h:197
#define OrefSet(o, r, v)
Definition: RexxCore.h:94
#define TheCommonRetrievers
Definition: RexxCore.h:177
#define TheTrueObject
Definition: RexxCore.h:186
#define TheNullPointer
Definition: RexxCore.h:187
#define TheFunctionsDirectory
Definition: RexxCore.h:176
#define IntegerTwo
Definition: RexxCore.h:191
#define IntegerSix
Definition: RexxCore.h:195
#define TheNilObject
Definition: RexxCore.h:181
#define TheFalseObject
Definition: RexxCore.h:185
#define IntegerNine
Definition: RexxCore.h:198
#define IntegerZero
Definition: RexxCore.h:189
#define IntegerMinusOne
Definition: RexxCore.h:199
#define Error_Logical_value_method
#define Error_System_resources
size_t HashLink
#define SaveStackSize
Definition: RexxMemory.cpp:89
bool SysAccessPool(MemorySegmentPool **pool)
#define MaxImageSize
Definition: RexxMemory.cpp:92
RexxMemory memoryObject
Definition: RexxMemory.cpp:85
#define SaveStackAllocSize
Definition: RexxMemory.cpp:90
static void logMemoryCheck(FILE *outfile, const char *message,...)
Definition: RexxMemory.cpp:106
#define RESTORE_CLASS(name, className)
Definition: RexxMemory.cpp:79
#define LiveStackSize
Definition: RexxMemory.cpp:87
#define memory_mark(oref)
Definition: RexxMemory.hpp:445
size_t roundObjectBoundary(size_t n)
Definition: RexxMemory.hpp:95
#define ObjectNeedsMarking(oref)
Definition: RexxMemory.hpp:444
size_t roundLargeObjectAllocation(size_t n)
Definition: RexxMemory.hpp:96
#define MinimumObjectSize
Definition: RexxMemory.hpp:85
#define memory_mark_general(oref)
Definition: RexxMemory.hpp:446
@ SAVINGIMAGE
Definition: RexxMemory.hpp:117
@ RESTORINGIMAGE
Definition: RexxMemory.hpp:116
@ LIVEMARK
Definition: RexxMemory.hpp:115
size_t roundObjectResize(size_t n)
Definition: RexxMemory.hpp:97
RexxString * new_proxy(const char *name)
RexxString * new_string(const char *s, stringsizeB_t bl, sizeC_t cl=-1)
static void init()
static void live(size_t)
static void liveGeneral(int reason)
static RexxActivity *volatile currentActivity
size_t getObjectSize()
Definition: DeadObject.hpp:85
GlobalProtectedObject * next
static void live(size_t)
Definition: Interpreter.cpp:83
static void logicError(const char *desc)
static void init()
Definition: Interpreter.cpp:77
static void liveGeneral(int reason)
Definition: Interpreter.cpp:90
RexxObject * allocateObject(size_t allocationLength)
virtual void dumpMemoryProfile(FILE *outfile)
RexxObject * handleAllocationFailure(size_t allocationLength)
MemorySegment * newLargeSegment(size_t minSize)
MemorySegment * newSegment(size_t minSize)
static MemorySegmentPool * createPool()
MemorySegmentPool * nextPool()
Definition: RexxMemory.hpp:159
void dumpSegments(FILE *keyfile, FILE *dumpfile)
bool isInSegmentSet(RexxObject *object)
void addSegment(MemorySegment *segment, bool createDeadObject=1)
bool is(SegmentSetID id)
void gatherStats(MemoryStats *memStats, SegmentStats *stats)
virtual DeadObject * donateObject(size_t allocationLength)
virtual MemorySegment * donateSegment(size_t allocationLength)
virtual void addDeadObject(DeadObject *object)
SegmentStats normalStats
void printSavedImageStats()
Definition: MemoryStats.cpp:90
void printMemoryStats()
SegmentStats largeStats
virtual void dumpMemoryProfile(FILE *outfile)
RexxObject * handleAllocationFailure(size_t allocationLength)
RexxObject * allocateObject(size_t allocationLength)
RexxObject * allocateObject(size_t allocationLength)
static void liveGeneral(int reason)
static void live(size_t liveMark)
static RexxArray * getImageData()
static void restore()
static void initializeThreadContext()
void put(RexxObject *eref, size_t pos)
Definition: ArrayClass.cpp:208
RexxObject * get(size_t pos)
Definition: ArrayClass.hpp:203
static RexxBehaviour * restoreSavedPrimitiveBehaviour(RexxBehaviour *b)
void restore(RexxBehaviour *)
void setNonPrimitive()
RexxBehaviour * getSavedPrimitiveBehaviour()
static RexxBehaviour * getPrimitiveBehaviour(size_t index)
bool isTransientClass()
static RexxBehaviour primitiveBehaviours[]
size_t getClassType()
static void createInstance()
RexxString * getId()
Definition: ClassClass.cpp:254
RexxObject * at(RexxString *)
RexxObject * put(RexxObject *, RexxString *)
RexxObject * value(HashLink pos)
HashLink next(HashLink pos)
RexxObject * index(HashLink pos)
virtual RexxObject * put(RexxObject *, RexxObject *)
virtual RexxObject * get(RexxObject *key)
virtual RexxObject * remove(RexxObject *key)
static void createInstance()
wholenumber_t incrementValue()
RexxObject * getValue(RexxActivation *)
wholenumber_t decrementValue()
void setBehaviour(RexxBehaviour *b)
void setObjectSize(size_t s)
void setObjectLive(size_t markword)
bool isObjectLive(size_t mark)
virtual RexxString * stringValue()
bool isObjectDead(size_t mark)
RexxBehaviour * behaviour
HashCode identityHash()
RexxBehaviour * getObjectType()
static RexxDirectory * functionsDir
Definition: RexxMemory.hpp:307
char * image_buffer
Definition: RexxMemory.hpp:392
void setEnvelope(RexxEnvelope *)
void mark(RexxObject *)
void markObjectsMain(RexxObject *)
Definition: RexxMemory.cpp:353
void collect()
void addWeakReference(WeakReference *ref)
Definition: RexxMemory.cpp:722
RexxIdentityTable * old2new
Definition: RexxMemory.hpp:382
static RexxDirectory * environment
Definition: RexxMemory.hpp:306
void saveImageMark(RexxObject *markObject, RexxObject **pMarkObject)
void discardHoldObject(RexxInternalObject *obj)
RexxSaveStack * saveStack
Definition: RexxMemory.hpp:377
MemorySegmentPool * firstPool
Definition: RexxMemory.hpp:387
void removeUninitObject(RexxObject *obj)
Definition: RexxMemory.cpp:598
RexxTable * markTable
Definition: RexxMemory.hpp:379
void orphanCheckMark(RexxObject *markObject, RexxObject **pMarkObject)
size_t pendingUninits
Definition: RexxMemory.hpp:384
void restoreImage()
Definition: RexxMemory.cpp:810
bool objectReferenceOK(RexxObject *o)
Definition: RexxMemory.cpp:330
void liveStackFull()
RexxObject * dump()
@ saveArray_FUNCTIONS
Definition: RexxMemory.hpp:334
@ saveArray_NAME_STRINGS
Definition: RexxMemory.hpp:323
@ saveArray_NULLPOINTER
Definition: RexxMemory.hpp:332
@ saveArray_PACKAGES
Definition: RexxMemory.hpp:330
@ saveArray_COMMON_RETRIEVERS
Definition: RexxMemory.hpp:335
void initialize(bool restoringImage, const char *imageTarget)
Definition: RexxMemory.cpp:172
void memoryPoolAdded(MemorySegmentPool *)
RexxObject * setParms(RexxObject *, RexxObject *)
void shutdown()
void saveImage(const char *imageTarget)
RexxIdentityTable * uninitTable
Definition: RexxMemory.hpp:383
void restoreObjectMark(RexxObject *markObject, RexxObject **pMarkObject)
Definition: RexxMemory.hpp:354
WeakReference * weakReferenceList
Definition: RexxMemory.hpp:411
static RexxDirectory * globalStrings
Definition: RexxMemory.hpp:413
RexxObject * saveObject(RexxInternalObject *saveObj)
Definition: RexxMemory.hpp:211
static void createImage(const char *imageTarget)
Definition: Setup.cpp:146
RexxObject * newObject(size_t size)
Definition: RexxMemory.hpp:190
static SysMutex unflattenMutex
Definition: RexxMemory.hpp:415
bool processingUninits
Definition: RexxMemory.hpp:385
size_t image_offset
Definition: RexxMemory.hpp:393
NormalSegmentSet newSpaceNormalSegments
Definition: RexxMemory.hpp:390
bool orphanCheck
Definition: RexxMemory.hpp:401
MemorySegment * newSegment(size_t requestLength, size_t minLength)
Definition: RexxMemory.cpp:733
bool restoringImage()
Definition: RexxMemory.hpp:218
static void * virtualFunctionTable[]
Definition: RexxMemory.hpp:298
void killOrphans(RexxObject *)
Definition: RexxMemory.cpp:388
bool inSharedObjectStorage(RexxObject *obj)
Definition: RexxMemory.cpp:281
RexxObject * setDump(RexxObject *)
RexxObject * makeProxy(RexxEnvelope *)
Definition: RexxMemory.cpp:988
static RexxArray * saveStrings()
Definition: GlobalNames.cpp:64
MemorySegment * newLargeSegment(size_t requestLength, size_t minLength)
Definition: RexxMemory.cpp:773
bool isPendingUninit(RexxObject *obj)
Definition: RexxMemory.cpp:626
void live(size_t)
Definition: RexxMemory.cpp:922
RexxArray * newObjects(size_t size, size_t count, size_t objectType)
void markGeneral(void *)
void dumpMemoryProfile()
Definition: RexxMemory.cpp:251
RexxVariable * variableCache
Definition: RexxMemory.hpp:303
RexxStack * getFlattenStack()
void addUninitObject(RexxObject *obj)
Definition: RexxMemory.cpp:609
RexxObject * popLiveStack()
Definition: RexxMemory.hpp:342
void markObjects(void)
Definition: RexxMemory.cpp:635
static void createLocks()
static RexxDirectory * system
Definition: RexxMemory.hpp:310
void restoreMark(RexxObject *markObject, RexxObject **pMarkObject)
Definition: RexxMemory.hpp:344
bool dumpEnable
Definition: RexxMemory.hpp:395
OldSpaceSegmentSet oldSpaceSegments
Definition: RexxMemory.hpp:389
static void restoreStrings(RexxArray *stringArray)
Definition: GlobalNames.cpp:92
size_t markWord
Definition: RexxMemory.hpp:301
void setUpMemoryTables(RexxIdentityTable *old2newTable)
void collectAndUninit(bool clearStack)
Definition: RexxMemory.cpp:491
RexxObject * holdObject(RexxInternalObject *obj)
bool saveimage
Definition: RexxMemory.hpp:396
void pushLiveStack(RexxObject *obj)
Definition: RexxMemory.hpp:341
RexxObject * dumpImageStats()
size_t collections
Definition: RexxMemory.hpp:410
GlobalProtectedObject * protectedObjects
Definition: RexxMemory.hpp:304
static SysMutex envelopeMutex
Definition: RexxMemory.hpp:416
static void buildVirtualFunctionTable()
void liveGeneral(int reason)
Definition: RexxMemory.cpp:956
bool inObjectStorage(RexxObject *obj)
Definition: RexxMemory.cpp:311
RexxStack * liveStack
Definition: RexxMemory.hpp:375
LargeSegmentSet newSpaceLargeSegments
Definition: RexxMemory.hpp:391
size_t objOffset
Definition: RexxMemory.hpp:402
void runUninits()
Definition: RexxMemory.cpp:520
void logObjectStats(RexxObject *obj)
Definition: RexxMemory.hpp:264
static RexxString * getGlobalName(const char *value)
void returnFlattenStack()
RexxObject * checkSetOref(RexxObject *, RexxObject **, RexxObject *, const char *, int)
char * allocateImageBuffer(size_t size)
size_t allocations
Definition: RexxMemory.hpp:409
RexxEnvelope * envelope
Definition: RexxMemory.hpp:405
static void closeLocks()
void unflattenMark(RexxObject *markObject, RexxObject **pMarkObject)
Definition: RexxMemory.hpp:349
static RexxDirectory * commonRetrievers
Definition: RexxMemory.hpp:308
RexxIdentityTable * saveTable
Definition: RexxMemory.hpp:378
void clearSaveStack()
Definition: RexxMemory.hpp:269
bool checkSetOK
Definition: RexxMemory.hpp:398
void setObjectOffset(size_t offset)
RexxStack * flattenStack
Definition: RexxMemory.hpp:376
RexxObject * gutCheck()
static void restore()
void disableOrefChecks()
Definition: RexxMemory.hpp:267
RexxObject * oldObject(size_t size)
void verboseMessage(const char *message)
Definition: RexxMemory.hpp:240
void dumpObject(RexxObject *objectRef, FILE *outfile)
Definition: RexxMemory.cpp:263
void checkWeakReferences()
Definition: RexxMemory.cpp:686
static RexxDirectory * kernel
Definition: RexxMemory.hpp:309
void enableOrefChecks()
Definition: RexxMemory.hpp:268
static SysMutex flattenMutex
Definition: RexxMemory.hpp:414
RexxObject * setOref(void *index, RexxObject *value)
void lastChanceUninit()
Definition: RexxMemory.cpp:510
RexxObject * temporaryObject(size_t size)
RexxStack * originalLiveStack
Definition: RexxMemory.hpp:406
void reSize(RexxObject *, size_t)
MemoryStats * imageStats
Definition: RexxMemory.hpp:407
RexxObject * reclaim()
MemorySegmentPool * currentPool
Definition: RexxMemory.hpp:388
void pushSaveStack(RexxObject *obj)
Definition: RexxMemory.hpp:265
size_t relocation
Definition: RexxMemory.hpp:394
void checkUninit()
Definition: RexxMemory.cpp:453
void bumpMarkWord()
Definition: RexxMemory.hpp:343
bool restoreimage
Definition: RexxMemory.hpp:397
static void create()
void flatten(RexxEnvelope *)
Definition: RexxMemory.cpp:978
void scavengeSegmentSets(MemorySegmentSet *requester, size_t allocationLength)
void logVerboseOutput(const char *message, void *sub1, void *sub2)
Definition: RexxMemory.cpp:243
void initializeNewObject(size_t size, size_t mark, void *vft, RexxBehaviour *b)
void live(size_t)
Definition: ObjectClass.cpp:78
void liveGeneral(int reason)
Definition: ObjectClass.cpp:86
bool truthValue(int)
RexxString * id()
RexxClass * classObject()
void init(size_t)
Definition: StackClass.cpp:60
void copyEntries(RexxStack *other)
Definition: StackClass.hpp:78
size_t size
Definition: StackClass.hpp:80
RexxObject * push(RexxObject *obj)
Definition: StackClass.hpp:63
const char * getStringData()
RexxObject * replace(RexxObject *newValue, HashLink pos)
Definition: TableClass.hpp:62
static const char * getTempFileName()
void release(const char *ds, int di)
bool requestImmediate(const char *ds, int di)
void request(const char *ds, int di)
static void liveGeneral(int reason)
static void loadImage(char **imageBuffer, size_t *imageSize)
static void live(size_t)
RexxObject * referentObject
WeakReference * nextReferenceList
int type
Definition: cmdparse.cpp:383
ssize_t wholenumber_t
Definition: rexx.h:230
#define BASEIMAGE
UINT_PTR uintptr_t
int int32_t