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

Reply via email to