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