Oops, you're right. I thought I was going to need to use
exception/logicError split in multiple places so I was going to have a
method for it.

Rick

On Tue, Aug 28, 2018 at 11:09 AM Erich Steinböck <erich.steinbo...@gmail.com>
wrote:

> Rick, I think this adds an otherwise unused `void memoryError()`
> declaration in RexxMemory.hpp
>
> On Sun, Aug 26, 2018 at 11:48 PM, bigrixx--- via Oorexx-svn <
> oorexx-...@lists.sourceforge.net> wrote:
>
>> Revision: 11488
>>           http://sourceforge.net/p/oorexx/code-0/11488
>> Author:   bigrixx
>> Date:     2018-08-26 21:48:23 +0000 (Sun, 26 Aug 2018)
>> Log Message:
>> -----------
>> rework liveStack expansion to avoid crashes
>>
>> Modified Paths:
>> --------------
>>     main/trunk/interpreter/behaviour/ClassTypeCodes.h
>>     main/trunk/interpreter/behaviour/PrimitiveBehaviourNames.h
>>     main/trunk/interpreter/behaviour/PrimitiveBehaviours.cpp
>>     main/trunk/interpreter/behaviour/PrimitiveClasses.xml
>>     main/trunk/interpreter/behaviour/VirtualFunctionTable.cpp
>>     main/trunk/interpreter/classes/ArrayClass.cpp
>>     main/trunk/interpreter/classes/support/HashContents.cpp
>>     main/trunk/interpreter/classes/support/ListContents.cpp
>>     main/trunk/interpreter/memory/Envelope.cpp
>>     main/trunk/interpreter/memory/Memory.hpp
>>     main/trunk/interpreter/memory/MemorySegment.cpp
>>     main/trunk/interpreter/memory/MemoryStack.cpp
>>     main/trunk/interpreter/memory/MemoryStack.hpp
>>     main/trunk/interpreter/memory/RexxMemory.cpp
>>     main/trunk/interpreter/memory/RexxMemory.hpp
>>
>> Modified: main/trunk/interpreter/behaviour/ClassTypeCodes.h
>> ===================================================================
>> --- main/trunk/interpreter/behaviour/ClassTypeCodes.h   2018-08-22
>> 21:51:20 UTC (rev 11487)
>> +++ main/trunk/interpreter/behaviour/ClassTypeCodes.h   2018-08-26
>> 21:48:23 UTC (rev 11488)
>> @@ -240,38 +240,37 @@
>>
>>      T_Memory = 174,
>>      T_InternalStack = 175,
>> -    T_LiveStack = 176,
>> -    T_PushThroughStack = 177,
>> -    T_Activity = 178,
>> -    T_Activation = 179,
>> -    T_NativeActivation = 180,
>> -    T_ActivationFrameBuffer = 181,
>> -    T_Envelope = 182,
>> -    T_LanguageParser = 183,
>> -    T_Clause = 184,
>> -    T_Token = 185,
>> -    T_DoBlock = 186,
>> -    T_InterpreterInstance = 187,
>> -    T_SecurityManager = 188,
>> -    T_CommandHandler = 189,
>> -    T_MapBucket = 190,
>> -    T_MapTable = 191,
>> -    T_TrapHandler = 192,
>> -    T_CommandIOContext = 193,
>> -    T_StemOutputTarget = 194,
>> -    T_StreamObjectOutputTarget = 195,
>> -    T_StreamOutputTarget = 196,
>> -    T_CollectionOutputTarget = 197,
>> -    T_BufferingOutputTarget = 198,
>> -    T_StemInputSource = 199,
>> -    T_StreamObjectInputSource = 200,
>> -    T_StreamInputSource = 201,
>> -    T_ArrayInputSource = 202,
>> -    T_RexxQueueOutputTarget = 203,
>> +    T_PushThroughStack = 176,
>> +    T_Activity = 177,
>> +    T_Activation = 178,
>> +    T_NativeActivation = 179,
>> +    T_ActivationFrameBuffer = 180,
>> +    T_Envelope = 181,
>> +    T_LanguageParser = 182,
>> +    T_Clause = 183,
>> +    T_Token = 184,
>> +    T_DoBlock = 185,
>> +    T_InterpreterInstance = 186,
>> +    T_SecurityManager = 187,
>> +    T_CommandHandler = 188,
>> +    T_MapBucket = 189,
>> +    T_MapTable = 190,
>> +    T_TrapHandler = 191,
>> +    T_CommandIOContext = 192,
>> +    T_StemOutputTarget = 193,
>> +    T_StreamObjectOutputTarget = 194,
>> +    T_StreamOutputTarget = 195,
>> +    T_CollectionOutputTarget = 196,
>> +    T_BufferingOutputTarget = 197,
>> +    T_StemInputSource = 198,
>> +    T_StreamObjectInputSource = 199,
>> +    T_StreamInputSource = 200,
>> +    T_ArrayInputSource = 201,
>> +    T_RexxQueueOutputTarget = 202,
>>
>> -    T_Last_Transient_Class = 203,
>> -    T_Last_Primitive_Class = 203,
>> -    T_Last_Class_Type = 203,
>> +    T_Last_Transient_Class = 202,
>> +    T_Last_Primitive_Class = 202,
>> +    T_Last_Class_Type = 202,
>>
>>  } ClassTypeCode;
>>
>>
>> Modified: main/trunk/interpreter/behaviour/PrimitiveBehaviourNames.h
>> ===================================================================
>> --- main/trunk/interpreter/behaviour/PrimitiveBehaviourNames.h
>> 2018-08-22 21:51:20 UTC (rev 11487)
>> +++ main/trunk/interpreter/behaviour/PrimitiveBehaviourNames.h
>> 2018-08-26 21:48:23 UTC (rev 11488)
>> @@ -225,7 +225,6 @@
>>  #define TheAddressWithInstructionBehaviour
>> (&RexxBehaviour::primitiveBehaviours[T_AddressWithInstruction])
>>  #define TheMemoryBehaviour
>> (&RexxBehaviour::primitiveBehaviours[T_Memory])
>>  #define TheInternalStackBehaviour
>> (&RexxBehaviour::primitiveBehaviours[T_InternalStack])
>> -#define TheLiveStackBehaviour
>> (&RexxBehaviour::primitiveBehaviours[T_LiveStack])
>>  #define ThePushThroughStackBehaviour
>> (&RexxBehaviour::primitiveBehaviours[T_PushThroughStack])
>>  #define TheActivityBehaviour
>> (&RexxBehaviour::primitiveBehaviours[T_Activity])
>>  #define TheActivationBehaviour
>> (&RexxBehaviour::primitiveBehaviours[T_Activation])
>>
>> Modified: main/trunk/interpreter/behaviour/PrimitiveBehaviours.cpp
>> ===================================================================
>> --- main/trunk/interpreter/behaviour/PrimitiveBehaviours.cpp
>> 2018-08-22 21:51:20 UTC (rev 11487)
>> +++ main/trunk/interpreter/behaviour/PrimitiveBehaviours.cpp
>> 2018-08-26 21:48:23 UTC (rev 11488)
>> @@ -235,7 +235,6 @@
>>      RexxBehaviour(T_AddressWithInstruction, (PCPPM
>> *)RexxObject::operatorMethods),
>>      RexxBehaviour(T_Memory, (PCPPM *)RexxObject::operatorMethods),
>>      RexxBehaviour(T_InternalStack, (PCPPM *)RexxObject::operatorMethods),
>> -    RexxBehaviour(T_LiveStack, (PCPPM *)RexxObject::operatorMethods),
>>      RexxBehaviour(T_PushThroughStack, (PCPPM
>> *)RexxObject::operatorMethods),
>>      RexxBehaviour(T_Activity, (PCPPM *)RexxObject::operatorMethods),
>>      RexxBehaviour(T_Activation, (PCPPM *)RexxObject::operatorMethods),
>>
>> Modified: main/trunk/interpreter/behaviour/PrimitiveClasses.xml
>> ===================================================================
>> --- main/trunk/interpreter/behaviour/PrimitiveClasses.xml
>>  2018-08-22 21:51:20 UTC (rev 11487)
>> +++ main/trunk/interpreter/behaviour/PrimitiveClasses.xml
>>  2018-08-26 21:48:23 UTC (rev 11488)
>> @@ -226,7 +226,6 @@
>>  <Transient>
>>  <Class id="Memory" class="MemoryObject" include="RexxMemory.hpp"
>> objectvirtual="true"/>
>>  <Class id="InternalStack" class="InternalStack"
>> include="InternalStack.hpp"/>
>> -<Class id="LiveStack" class="LiveStack" include="MemoryStack.hpp"/>
>>  <Class id="PushThroughStack" class="PushThroughStack"
>> include="MemoryStack.hpp"/>
>>  <Class id="Activity" class="Activity" include="Activity.hpp"/>
>>  <Class id="Activation" class="RexxActivation"
>> include="RexxActivation.hpp"/>
>>
>> Modified: main/trunk/interpreter/behaviour/VirtualFunctionTable.cpp
>> ===================================================================
>> --- main/trunk/interpreter/behaviour/VirtualFunctionTable.cpp
>>  2018-08-22 21:51:20 UTC (rev 11487)
>> +++ main/trunk/interpreter/behaviour/VirtualFunctionTable.cpp
>>  2018-08-26 21:48:23 UTC (rev 11488)
>> @@ -734,9 +734,6 @@
>>     objectPtr = ::new (objectLoc) InternalStack(RESTOREIMAGE);
>>     virtualFunctionTable[T_InternalStack] = getVftPointer(objectLoc);
>>
>> -   objectPtr = ::new (objectLoc) LiveStack(RESTOREIMAGE);
>> -   virtualFunctionTable[T_LiveStack] = getVftPointer(objectLoc);
>> -
>>     objectPtr = ::new (objectLoc) PushThroughStack(RESTOREIMAGE);
>>     virtualFunctionTable[T_PushThroughStack] = getVftPointer(objectLoc);
>>
>>
>> Modified: main/trunk/interpreter/classes/ArrayClass.cpp
>> ===================================================================
>> --- main/trunk/interpreter/classes/ArrayClass.cpp       2018-08-22
>> 21:51:20 UTC (rev 11487)
>> +++ main/trunk/interpreter/classes/ArrayClass.cpp       2018-08-26
>> 21:48:23 UTC (rev 11488)
>> @@ -281,8 +281,10 @@
>>      // add in the max size value.  Note that we subtract one since
>>      // the first item is contained in the base object allocation.
>>      bytes += sizeof(RexxInternalObject *) * (maxSize - 1);
>> -    // now allocate the new object with that size.
>> -    ArrayClass *newArray = (ArrayClass *)new_object(bytes, type);
>> +    // now allocate the new object with that size.  We also give a hint
>> to
>> +    // the language process about how many objects we can potentially
>> mark during
>> +    // a garbage collection.
>> +    ArrayClass *newArray = (ArrayClass *)new_object(bytes, type,
>> maxSize);
>>
>>      // now fill in the various control bits.  Ideally, this
>>      // really should be done in the constructor, but that gets really too
>>
>> Modified: main/trunk/interpreter/classes/support/HashContents.cpp
>> ===================================================================
>> --- main/trunk/interpreter/classes/support/HashContents.cpp
>>  2018-08-22 21:51:20 UTC (rev 11487)
>> +++ main/trunk/interpreter/classes/support/HashContents.cpp
>>  2018-08-26 21:48:23 UTC (rev 11488)
>> @@ -1,7 +1,7 @@
>>
>>  
>> /*----------------------------------------------------------------------------*/
>>  /*
>>       */
>>  /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved.
>>      */
>> -/* Copyright (c) 2005-2014 Rexx Language Association. All rights
>> reserved.    */
>> +/* Copyright (c) 2005-2018 Rexx Language Association. All rights
>> reserved.    */
>>  /*
>>       */
>>  /* This program and the accompanying materials are made available under
>>      */
>>  /* the terms of the Common Public License v1.0 which accompanies this
>>      */
>> @@ -62,7 +62,7 @@
>>      size_t bytes = size + (sizeof(ContentEntry) * (capacity - 1));
>>
>>      // now allocate the suggested bucket size
>> -    return new_object(bytes, T_IdentityHashContents);
>> +    return new_object(bytes, T_IdentityHashContents, capacity * 2);
>>  }
>>
>>
>> @@ -79,7 +79,7 @@
>>      size_t bytes = size + (sizeof(ContentEntry) * (capacity - 1));
>>
>>      // now allocate the suggested bucket size
>> -    return new_object(bytes, T_EqualityHashContents);
>> +    return new_object(bytes, T_EqualityHashContents, capacity * 2);
>>  }
>>
>>
>> @@ -96,7 +96,7 @@
>>      size_t bytes = size + (sizeof(ContentEntry) * (capacity - 1));
>>
>>      // now allocate the suggested bucket size
>> -    return new_object(bytes, T_MultiValueContents);
>> +    return new_object(bytes, T_MultiValueContents, capacity * 2);
>>  }
>>
>>
>> @@ -113,7 +113,7 @@
>>      size_t bytes = size + (sizeof(ContentEntry) * (capacity - 1));
>>
>>      // now allocate the suggested bucket size
>> -    return new_object(bytes, T_StringHashContents);
>> +    return new_object(bytes, T_StringHashContents, capacity * 2);
>>  }
>>
>>
>>
>> Modified: main/trunk/interpreter/classes/support/ListContents.cpp
>> ===================================================================
>> --- main/trunk/interpreter/classes/support/ListContents.cpp
>>  2018-08-22 21:51:20 UTC (rev 11487)
>> +++ main/trunk/interpreter/classes/support/ListContents.cpp
>>  2018-08-26 21:48:23 UTC (rev 11488)
>> @@ -1,7 +1,7 @@
>>
>>  
>> /*----------------------------------------------------------------------------*/
>>  /*
>>       */
>>  /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved.
>>      */
>> -/* Copyright (c) 2005-2014 Rexx Language Association. All rights
>> reserved.    */
>> +/* Copyright (c) 2005-2018 Rexx Language Association. All rights
>> reserved.    */
>>  /*
>>       */
>>  /* This program and the accompanying materials are made available under
>>      */
>>  /* the terms of the Common Public License v1.0 which accompanies this
>>      */
>> @@ -60,7 +60,7 @@
>>   */
>>  void *ListContents::operator new(size_t size, size_t initialSize)
>>  {
>> -    return new_object(size + sizeof(ListEntry) * (initialSize - 1),
>> T_ListContents);
>> +    return new_object(size + sizeof(ListEntry) * (initialSize - 1),
>> T_ListContents, initialSize);
>>  }
>>
>>
>>
>> Modified: main/trunk/interpreter/memory/Envelope.cpp
>> ===================================================================
>> --- main/trunk/interpreter/memory/Envelope.cpp  2018-08-22 21:51:20 UTC
>> (rev 11487)
>> +++ main/trunk/interpreter/memory/Envelope.cpp  2018-08-26 21:48:23 UTC
>> (rev 11488)
>> @@ -80,7 +80,6 @@
>>      memory_mark(saveTable);
>>      memory_mark(buffer);
>>      memory_mark(rehashTable);
>> -    memory_mark(flattenStack);
>>  }
>>
>>
>> @@ -87,8 +86,6 @@
>>  /**
>>   * Generalized object marking
>>   *
>> - * NOTE: Do not mark flattenStack
>> - *
>>   * @param reason The reason for the marking call.
>>   */
>>  void Envelope::liveGeneral(MarkReason reason)
>> @@ -99,7 +96,6 @@
>>      memory_mark_general(saveTable);
>>      memory_mark_general(buffer);
>>      memory_mark_general(rehashTable);
>> -    memory_mark_general(flattenStack);
>>  }
>>
>>
>> @@ -202,11 +198,7 @@
>>      dupTable = new MapTable(DefaultDupTableSize);
>>      buffer = new SmartBuffer(DefaultEnvelopeBuffer);
>>      // Allocate a flatten stack
>> -    flattenStack = new (Memory::LiveStackSize, true) LiveStack
>> (Memory::LiveStackSize);
>> -    // we need to mark the flatten stack to protect it from GC, but we're
>> -    // going to be storing offsets in here, not object references, so we
>> don't want
>> -    // this to be marked.
>> -    flattenStack->setHasNoReferences();
>> +    flattenStack = new (Memory::LiveStackSize) LiveStack
>> (Memory::LiveStackSize);
>>      // push unique terminator onto stack
>>      flattenStack->push(OREF_NULL);
>>
>> @@ -244,6 +236,8 @@
>>      // behind it to the size we've written to it.
>>      BufferClass *letter = buffer->getBuffer();
>>      letter->setDataLength(buffer->getDataLength());
>> +    // delete the flatten stack, since that is not allocated from the
>> object heap.
>> +    delete flattenStack;
>>      return letter;
>>  }
>>
>>
>> Modified: main/trunk/interpreter/memory/Memory.hpp
>> ===================================================================
>> --- main/trunk/interpreter/memory/Memory.hpp    2018-08-22 21:51:20 UTC
>> (rev 11487)
>> +++ main/trunk/interpreter/memory/Memory.hpp    2018-08-26 21:48:23 UTC
>> (rev 11488)
>> @@ -94,8 +94,14 @@
>>      // possible size
>>      static const size_t MaximumObjectSize = SIZE_MAX - ObjectGrain;
>>
>> -    // default size for the live stack (in entries)
>> -    static const size_t LiveStackSize = 32 * 1024;
>> +    // default size for the live stack (in entries). We make the initial
>> one
>> +    // much larger if building for 64-bit mode because there is a much
>> higher
>> +    // possibility of getting large complex collections
>> +#ifdef __REXX64__
>> +    static const size_t LiveStackSize = 256 * 1024;
>> +#else
>> +    static const size_t LiveStackSize = 64 * 1024;
>> +#endif
>>      // the number of newly created items to stack in the save stack
>>      static const size_t SaveStackSize = 10;
>>      // the maximum size for the startup image size
>> @@ -102,8 +108,6 @@
>>      static const size_t MaxImageSize = 3000000;
>>      // the size of a page
>>      static const size_t PageSize = 4096;
>> -    // the standard memory pool allocation size.
>> -    static const size_t MemoryAllocationSize = PageSize * 1024;
>>  };
>>
>>  #endif
>>
>> Modified: main/trunk/interpreter/memory/MemorySegment.cpp
>> ===================================================================
>> --- main/trunk/interpreter/memory/MemorySegment.cpp     2018-08-22
>> 21:51:20 UTC (rev 11487)
>> +++ main/trunk/interpreter/memory/MemorySegment.cpp     2018-08-26
>> 21:48:23 UTC (rev 11488)
>> @@ -1166,25 +1166,21 @@
>>              // still no luck?
>>              if (newObject == OREF_NULL)
>>              {
>> -                // absolute last chance to fix this.  We allocated a
>> -                // recovery segment at start up and have been hiding this
>> -                // in our back pocket.  It is now time to bring this into
>> -                // play, because we're running on fumes! */
>> +                // We have a recovery segment in our back pocket, but
>> this
>> +                // is needed to allow us to actually report that we have
>> an
>> +                // out of memory condition. We add this to the segment
>> set, but
>> +                // we will not try to use it to satisfy this request. We
>> need this
>> +                // to keep from crashing.
>>                  if (recoverSegment != NULL)
>>                  {
>>                      addSegment(recoverSegment);
>>                      recoverSegment = NULL;
>> -                    // And try to find it once more
>> -                    newObject = findObject(allocationLength);
>>                  }
>>
>>                  // if we have gone through all of that and still have
>> nothing,
>>                  // this is a real out-of-memory situation.
>> -                if (newObject == OREF_NULL)
>> -                {
>> -                    // can't allocate, report resource error.
>> -                    reportException(Error_System_resources);
>> -                }
>> +                // can't allocate, report resource error.
>> +                reportException(Error_System_resources);
>>              }
>>          }
>>      }
>>
>> Modified: main/trunk/interpreter/memory/MemoryStack.cpp
>> ===================================================================
>> --- main/trunk/interpreter/memory/MemoryStack.cpp       2018-08-22
>> 21:51:20 UTC (rev 11487)
>> +++ main/trunk/interpreter/memory/MemoryStack.cpp       2018-08-26
>> 21:48:23 UTC (rev 11488)
>> @@ -1,7 +1,7 @@
>>
>>  
>> /*----------------------------------------------------------------------------*/
>>  /*
>>       */
>>  /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved.
>>      */
>> -/* Copyright (c) 2005-2014 Rexx Language Association. All rights
>> reserved.    */
>> +/* Copyright (c) 2005-2018 Rexx Language Association. All rights
>> reserved.    */
>>  /*
>>       */
>>  /* This program and the accompanying materials are made available under
>>      */
>>  /* the terms of the Common Public License v1.0 which accompanies this
>>      */
>> @@ -56,81 +56,79 @@
>>   *
>>   * @return A newly allocated stack object.
>>   */
>> -void *LiveStack::operator new(size_t size, size_t stksize, bool
>> temporary)
>> +void *LiveStack::operator new(size_t size, size_t stksize)
>>  {
>>      // This is a special allocation.  We use this if we need to expand
>> the livestack
>>      // during a GC operation, which of course is when we are not able to
>> allocate from
>>      // the Rexx heap.
>> -    RexxInternalObject *newObject = memoryObject.temporaryObject(size +
>> ((stksize-1) * sizeof(RexxObject *)));
>> -    // set the behaviour
>> -    newObject->setBehaviour(TheLiveStackBehaviour);
>> -    return newObject;
>> +    return memoryObject.temporaryObject(size + ((stksize-1) *
>> sizeof(RexxObject *)));
>>  }
>>
>>
>>  /**
>> - * Allocate a live stack with the given number of slots.
>> + * Delete a LiveStack object.
>>   *
>> - * @param _size  The stack size.
>> + * @param storage The pointer to the object storage
>>   */
>> -LiveStack::LiveStack(size_t _size)
>> +void LiveStack::operator delete(void *storage)
>>  {
>> -    // we can get created via means other than normal memory allocation,
>> so
>> -    // ensure we're completely cleared out
>> -    clearObject();
>> -    // set the size and top element
>> -    size = _size;
>> -    top = 0;
>> +    memoryObject.deleteTemporaryObject(storage);
>>  }
>>
>>
>>  /**
>> - * Perform garbage collection on a live object.
>> + * Allocate a live stack with the given number of slots.
>>   *
>> - * @param liveMark The current live mark.
>> + * @param _size  The stack size.
>>   */
>> -void LiveStack::live(size_t liveMark)
>> +LiveStack::LiveStack(size_t _size)
>>  {
>> -    // note, we only mark the array up to (but not including) the top
>> position.
>> -    if (top > 0)
>> -    {
>> -        memory_mark_array(top - 1, stack);
>> -    }
>> +    // set the size and top element
>> +    size = _size;
>> +    top = 0;
>>  }
>>
>>
>>  /**
>> - * Perform generalized live marking on an object.  This is
>> - * used when mark-and-sweep processing is needed for purposes
>> - * other than garbage collection.
>> + * Reallocate the stack to one that is larger by a given multiplier.
>>   *
>> - * @param reason The reason for the marking call.
>> + * @param delta  The size to expand by
>> + *
>> + * @return A newly allocated stack with the entries from this
>> + *         stack copied over to it.
>>   */
>> -void LiveStack::liveGeneral(MarkReason reason)
>> +LiveStack *LiveStack::reallocate(size_t delta)
>>  {
>> -    // note, we only mark the array up to (but not including) the top
>> position.
>> -    if (top > 0)
>> -    {
>> -        memory_mark_general_array(top - 1, stack);
>> -    }
>> +    // create a new stack that is larger by the given multiplier
>> +    LiveStack *newStack = new (size + delta) LiveStack (size + delta);
>> +    // copy the entries over to the new stack
>> +    newStack->copyEntries(this);
>> +    return newStack;
>>  }
>>
>>
>>  /**
>> - * Reallocate the stack to one that is larger by a given multiplier.
>> + * Ensure that the live stack is going to be large enough to fit
>> + * all of the objects that might be marked from a large
>> + * collection. This allows us to proactively expand the stack
>> + * before a GC event is taking place, and potentially raise a
>> + * real Rexx EOM condition before we're at a critical point.
>>   *
>> - * @param multiplier The multiplier value.
>> + * @param needed  The number of live stack slots this object
>> + *                might require. It is assumed that the stack
>> + *                needs to be expanded at this point.
>>   *
>>   * @return A newly allocated stack with the entries from this
>>   *         stack copied over to it.
>>   */
>> -LiveStack *LiveStack::reallocate(size_t multiplier)
>> +LiveStack *LiveStack::ensureSpace(size_t needed)
>>  {
>> -    // create a new stack that is larger by the given multiplier
>> -    LiveStack *newStack = new (size * multiplier, true) LiveStack (size
>> * multiplier);
>> -    // copy the entries over to the new stack
>> -    newStack->copyEntries(this);
>> -    return newStack;
>> +    // NB: we've already determined expansion is needed, so
>> +    // this should be non-zero. We only expand by LiveStackSize
>> increments
>> +    size_t shortFall = Memory::roundUp(needed - size,
>> Memory::LiveStackSize);
>> +
>> +    // now expand by that increment
>> +    return reallocate(shortFall);
>>  }
>>
>>
>>
>> Modified: main/trunk/interpreter/memory/MemoryStack.hpp
>> ===================================================================
>> --- main/trunk/interpreter/memory/MemoryStack.hpp       2018-08-22
>> 21:51:20 UTC (rev 11487)
>> +++ main/trunk/interpreter/memory/MemoryStack.hpp       2018-08-26
>> 21:48:23 UTC (rev 11488)
>> @@ -52,19 +52,14 @@
>>   * the using code needs to perform appropriate "stack is full"
>>   * checks.
>>   */
>> -class LiveStack : public RexxInternalObject
>> +class LiveStack
>>  {
>>   public:
>>      void        *operator new(size_t, size_t);
>> -    void        *operator new(size_t, size_t, bool temporary);
>> -    inline void  operator delete(void *) { };
>> +    void         operator delete(void *);
>>
>> -    inline LiveStack(RESTORETYPE restoreType) { ; };
>>      LiveStack(size_t size);
>>
>> -    virtual void live(size_t);
>> -    virtual void liveGeneral(MarkReason reason);
>> -
>>      // the position is origin zero, relative to the top, which is an
>> empty slot.  So, position 0
>>      // is the top element, 1 is the penultimate elements, etc.
>>      inline RexxInternalObject *get(size_t pos)
>> @@ -115,8 +110,10 @@
>>      }
>>
>>      LiveStack  *reallocate(size_t increment);
>> +    LiveStack  *ensureSpace(size_t needed);
>>
>>      inline bool        checkRoom() { return top < size; }
>> +    inline bool        checkRoom(size_t needed) { return size - top >
>> needed; }
>>      inline size_t      stackSize() { return size; };
>>      inline RexxInternalObject *stackTop() { return top == 0 ? OREF_NULL
>> : stack[top - 1]; };
>>      inline void        copyEntries(LiveStack *other) { memcpy((char
>> *)stack, (char *)other->stack, other->size * sizeof(RexxInternalObject *));
>> top = other->top; }
>>
>> Modified: main/trunk/interpreter/memory/RexxMemory.cpp
>> ===================================================================
>> --- main/trunk/interpreter/memory/RexxMemory.cpp        2018-08-22
>> 21:51:20 UTC (rev 11487)
>> +++ main/trunk/interpreter/memory/RexxMemory.cpp        2018-08-26
>> 21:48:23 UTC (rev 11488)
>> @@ -160,11 +160,9 @@
>>      // before we can allocate our first real object.
>>      buildVirtualFunctionTable();
>>
>> -    // our first object allocation.  This is the live stack used for
>> -    // sweep marking.
>> -    liveStack = (LiveStack
>> *)oldSpaceSegments.allocateObject(MemorySegmentSet::SegmentDeadSpace);
>> -    // remember the original one
>> -    originalLiveStack = liveStack;
>> +    // This is the live stack used for
>> +    // sweep marking (not allocated from the object heap)
>> +    liveStack = new(Memory::LiveStackSize)
>> LiveStack(Memory::LiveStackSize);
>>
>>      // if we're restoring, load everything from the image file.  All of
>> the
>>      // classes will exist then, as well as restoring all of the
>> @@ -233,6 +231,9 @@
>>          return;
>>      }
>>
>> +    // flag that we're in the middle of a mark operation
>> +    markingObjects = true;
>> +
>>      // set up the live marking word passed to the live() routines
>>      // we include the OldSpaceBit here to allow both conditions to be
>> tested
>>      // in one shot.
>> @@ -254,6 +255,9 @@
>>          allocations++;
>>          markObject->live(liveMark);
>>      }
>> +
>> +    // we are done marking, no longer in a critical section
>> +    markingObjects = false;
>>  }
>>
>>
>> @@ -422,13 +426,9 @@
>>      markObjectsMain(uninitTable);
>>
>>      // if we had to expand the live stack previously, we allocated a
>> temporary
>> -    // one from malloc() storage rather than the object heap.  We need to
>> -    // explicitly free this version when that happens.
>> -    if (liveStack != originalLiveStack)
>> -    {
>> -        free((void *)liveStack);
>> -        liveStack = originalLiveStack;
>> -    }
>> +    // one from malloc() storage rather than the object heap.  We will
>> hold on
>> +    // to the expanded one because once we've hit the threshold where we
>> expand,
>> +    // it's likely we'll need to in the future.
>>      verboseMessage("Mark operation completed\n");
>>  }
>>
>> @@ -1064,17 +1064,11 @@
>>   */
>>  void MemoryObject::liveStackFull()
>>  {
>> -    // create a new stack that is double in size
>> -    LiveStack *newLiveStack = liveStack->reallocate(2);
>> +    // create a new stack that a stack increment larger
>> +    LiveStack *newLiveStack =
>> liveStack->reallocate(Memory::LiveStackSize);
>>
>> -    // if we've already been expanded, we need to release the
>> -    // storage for the existing livestack.  When we expand, we create a
>> -    // new object using malloc() storage rather than the object heap, so
>> we
>> -    // use free() to release it.
>> -    if (liveStack != originalLiveStack)
>> -    {
>> -        free((void *)liveStack);
>> -    }
>> +    // delete the existing liveStack
>> +    delete liveStack;
>>      // we can set the new stack
>>      liveStack = newLiveStack;
>>  }
>> @@ -1081,6 +1075,21 @@
>>
>>
>>  /**
>> + * Process a predictive live-stack overflow situation
>> + */
>> +void MemoryObject::liveStackFull(size_t needed)
>> +{
>> +    // create a new stack that a stack increment larger
>> +    LiveStack *newLiveStack = liveStack->ensureSpace(needed);
>> +
>> +    // delete the existing liveStack
>> +    delete liveStack;
>> +    // we can set the new stack
>> +    liveStack = newLiveStack;
>> +}
>> +
>> +
>> +/**
>>   * Perform a memory management mark operation.  This is only
>>   * used during a real garbage collection.
>>   *
>> @@ -1136,22 +1145,48 @@
>>   *
>>   * @return Storage for creating a new object.
>>   */
>> -RexxInternalObject *MemoryObject::temporaryObject(size_t requestLength)
>> +void *MemoryObject::temporaryObject(size_t requestLength)
>>  {
>>      size_t allocationLength = Memory::roundObjectBoundary(requestLength);
>>      // allocate just using malloc()
>> -    RexxInternalObject *newObj = (RexxInternalObject
>> *)malloc(allocationLength);
>> -    if (newObj == OREF_NULL)             /* unable to allocate a new
>> one?     */
>> +    void *newObj = malloc(allocationLength);
>> +    // there are two times where we can get an allocation failure. When
>> +    // collection objects are allocated, we try to predict if we will
>> need a
>> +    // larger live stack to handle large collections. If we get an
>> allocation
>> +    // failure at that point, we can raise this as a normal error. This
>> is not
>> +    // a perfect process, so we might need to expand the live stack
>> during a
>> +    // a marking operation. A failure at that time is fatal, so we can
>> only
>> +    // handle this as a fatal internal error.
>> +    if (newObj == OREF_NULL)
>>      {
>> -        reportException(Error_System_resources);
>> +        // If we're marking, then we can't recover from this.
>> +        if (markingObjects)
>> +        {
>> +            // This is an unrecoverable logic error
>> +            Interpreter::logicError("Unrecoverable out of memory error");
>> +        }
>> +        // a failure during the predictive process, we can raise a real
>> error
>> +        else
>> +        {
>> +            reportException(Error_System_resources);
>> +        }
>>      }
>> -    // initialize the new object
>> -    ((RexxObject *)newObj)->initializeNewObject(allocationLength,
>> markWord, virtualFunctionTable[T_Object], TheObjectBehaviour);
>>      return newObj;
>>  }
>>
>>
>>  /**
>> + * Delete a temporary object.
>> + *
>> + * @param storage The storage pointer to release,
>> + */
>> +void MemoryObject::deleteTemporaryObject(void *storage)
>> +{
>> +    free(storage);
>> +}
>> +
>> +
>> +/**
>>   * When we are doing a general marking operation, all
>>   * objects call markGeneral for all of its object references.
>>   * We perform different functions based on what the
>> @@ -1562,6 +1597,9 @@
>>      {
>>          SystemInterpreter::releaseSegmentMemory(*it);
>>      }
>> +
>> +    // release the livestack also, which is allocated separately.
>> +    delete liveStack;
>>  }
>>
>>
>> @@ -1573,10 +1611,6 @@
>>   */
>>  void MemoryObject::setUpMemoryTables(MapTable *old2newTable)
>>  {
>> -    // fix up the previously allocated live stack to have the correct
>> -    // characteristics...we're almost ready to go on the air.
>> -    liveStack->setBehaviour(TheLiveStackBehaviour);
>> -    liveStack = ::new ((void *)liveStack)
>> LiveStack(Memory::LiveStackSize);
>>      // set up the old 2 new table provided for us
>>      old2new = old2newTable;
>>      // Now get our savestack
>>
>> Modified: main/trunk/interpreter/memory/RexxMemory.hpp
>> ===================================================================
>> --- main/trunk/interpreter/memory/RexxMemory.hpp        2018-08-22
>> 21:51:20 UTC (rev 11487)
>> +++ main/trunk/interpreter/memory/RexxMemory.hpp        2018-08-26
>> 21:48:23 UTC (rev 11488)
>> @@ -111,7 +111,8 @@
>>      RexxInternalObject *oldObject(size_t size);
>>      inline RexxInternalObject *newObject(size_t size) { return
>> newObject(size, T_Object); }
>>      RexxInternalObject *newObject(size_t size, size_t type);
>> -    RexxInternalObject *temporaryObject(size_t size);
>> +    void *temporaryObject(size_t size);
>> +    void  deleteTemporaryObject(void *obj);
>>      ArrayClass *newObjects(size_t size, size_t count, size_t objectType);
>>      void        reSize(RexxInternalObject *, size_t);
>>      void        checkUninit();
>> @@ -134,8 +135,11 @@
>>      void        setOref(RexxInternalObject *variable, RexxInternalObject
>> *value);
>>      void        shutdown();
>>      void        liveStackFull();
>> +    void        liveStackFull(size_t needed);
>>      char *      allocateImageBuffer(size_t size);
>>      void        logVerboseOutput(const char *message, void *sub1, void
>> *sub2, void*sub3);
>> +    void        memoryError();
>> +
>>      inline void verboseMessage(const char *message)
>>      {
>>    #ifdef VERBOSE_GC
>> @@ -208,6 +212,7 @@
>>      void restoreStrings(ArrayClass *stringArray);
>>
>>      inline void checkLiveStack() { if (!liveStack->checkRoom())
>> liveStackFull(); }
>> +    inline void checkLiveStack(size_t needed) { if
>> (!liveStack->checkRoom(needed)) liveStackFull(needed); }
>>      inline void pushLiveStack(RexxInternalObject *obj) {
>> checkLiveStack(); liveStack->push(obj); }
>>      inline RexxInternalObject * popLiveStack() { return
>> liveStack->pop(); }
>>      inline void bumpMarkWord() { markWord ^= ObjectHeader::MarkMask; }
>> @@ -274,6 +279,7 @@
>>
>>      LiveStack  *liveStack;               // stack used for memory marking
>>      PushThroughStack *saveStack;         // our temporary protection
>> stack
>> +    bool              markingObjects;    // a flag to indicate we are
>> marking objects.
>>
>>      MapTable         *old2new;           // the table for tracking
>> old2new references.
>>      IdentityTable    *uninitTable;       // the table of objects with
>> uninit methods
>> @@ -290,7 +296,6 @@
>>      MarkHandler *currentMarkHandler;     // current handler for
>> liveGeneral marking
>>      MarkHandler  defaultMarkHandler;     // the default mark handler
>>
>> -    LiveStack *originalLiveStack;        // original live stack
>> allocation
>>      MemoryStats *imageStats;             // current statistics collector
>>
>>      size_t allocations;                  // number of allocations since
>> last GC
>> @@ -426,6 +431,7 @@
>>
>>  inline RexxInternalObject *new_object(size_t s) { return
>> memoryObject.newObject(s); }
>>  inline RexxInternalObject *new_object(size_t s, size_t t) { return
>> memoryObject.newObject(s, t); }
>> +inline RexxInternalObject *new_object(size_t s, size_t t, size_t i) {
>> memoryObject.checkLiveStack(i); return memoryObject.newObject(s, t); }
>>
>>  inline ArrayClass *new_arrayOfObject(size_t s, size_t c, size_t t)  {
>> return memoryObject.newObjects(s, c, t); }
>>
>>
>>
>>
>> ------------------------------------------------------------------------------
>> Check out the vibrant tech community on one of the world's most
>> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
>> _______________________________________________
>> Oorexx-svn mailing list
>> oorexx-...@lists.sourceforge.net
>> https://lists.sourceforge.net/lists/listinfo/oorexx-svn
>>
>
>
> ------------------------------------------------------------------------------
> Check out the vibrant tech community on one of the world's most
> engaging tech sites, Slashdot.org! http://sdm.link/slashdot
> _______________________________________________
> Oorexx-devel mailing list
> Oorexx-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/oorexx-devel
>
------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
_______________________________________________
Oorexx-devel mailing list
Oorexx-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/oorexx-devel

Reply via email to