All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.mirkosertic.bytecoder.classlib.MemoryManager Maven / Gradle / Ivy

There is a newer version: 2024-05-10
Show newest version
/*
 * Copyright 2017 Mirko Sertic
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.mirkosertic.bytecoder.classlib;

import de.mirkosertic.bytecoder.api.Export;

/**
 * A simple Memory Manager.
 *
 * It basically holds two linked lists. One for the free memory blocks,
 * and one for the reserved blocks.
 */
public class MemoryManager {

    @Export("initMemory")
    public static void initNative() {
        initInternal(Address.getMemorySize());
    }

    private static void initInternal(final int aSize) {
        // This is the list of free blocks
        final int heapBase = Address.getHeapBase();
        final int initialFreeBlock = heapBase + 36;

        Address.setIntValue(heapBase, 4, initialFreeBlock);

        // Free memory block
        Address.setIntValue(initialFreeBlock, 0, aSize - 48 - heapBase);
        Address.setIntValue(initialFreeBlock, 4, 0);
        Address.setIntValue(initialFreeBlock, 8, 0);

        // This is the List of reserved blocks
        Address.setIntValue(heapBase, 8, 0);

        // Current work counter for GC resumes
        Address.setIntValue(heapBase, 12, 0);

        // Current counter for GC epochs
        Address.setIntValue(heapBase, 16, 1);
    }

    @Export("GCEpoch")
    public static int getGCEpoch() {

        final int heapBase = Address.getHeapBase();

        return Address.getIntValue(heapBase, 16);
    }

    @Export("freeMem")
    public static int freeMem() {
        int theResult = 0;

        final int heapBase = Address.getHeapBase();

        final int theFreeStartPtr = Address.getIntValue(heapBase, 4);

        int theCurrent = theFreeStartPtr;
        while (theCurrent != 0) {
            theResult += Address.getIntValue(theCurrent, 0);
            theCurrent = Address.getIntValue(theCurrent, 4);
        }
        return theResult;
    }

    @Export("usedMem")
    public static int usedMem() {
        int theResult = 0;

        final int heapBase = Address.getHeapBase();

        int theCurrent = Address.getIntValue(heapBase, 8);
        while (theCurrent != 0) {
            theResult += Address.getIntValue(theCurrent, 0);
            theCurrent = Address.getIntValue(theCurrent, 4);
        }
        return theResult;
    }

    private static void internalFree(final int aPointer) {

        final int heapBase = Address.getHeapBase();

        // Remove the block from the list of allocated blocks
        int theCurrent = Address.getIntValue(heapBase, 8);

        int thePrevious = 0;
        while(theCurrent != 0) {

            final int theNext = Address.getIntValue(theCurrent, 4);

            if (theCurrent == aPointer) {
                // This is the block
                // Remove it from the list of allocated blocks
                if (thePrevious == 0) {
                    Address.setIntValue(8, 0, theNext);
                } else {
                    Address.setIntValue(thePrevious, 4, theNext);
                }

                // Ok, now we prepend it to the list of free blocks
                final int theFreeStartPtr = Address.getIntValue(4, 0);

                Address.setIntValue(theCurrent, 4, theFreeStartPtr);
                Address.setIntValue(4, 0, theCurrent);
                return;
            }

            thePrevious = theCurrent;
            theCurrent = theNext;
        }
    }

    @Export("free")
    public static void free(final int aPointer) {

        int theStart = aPointer;
        theStart-=12;

        internalFree(theStart);
    }

    @Export("malloc")
    public static int malloc(int aSize) {

        // Overhead for header
        aSize+=12;

        final int heapBase = Address.getHeapBase();

        final int theFreeStartPtr = Address.getIntValue(heapBase, 4);

        // We search the free list for a suitable sized block
        int thePrevious = 0;
        int theCurrent = theFreeStartPtr;
        while(theCurrent != 0) {
            final int theSize = Address.getIntValue(theCurrent, 0);
            final int theNext = Address.getIntValue(theCurrent, 4);
            if (theSize >= aSize) {
                final int theRemaining = theSize - aSize;

                if (theRemaining > 12) {
                    Address.setIntValue(theCurrent, 0, aSize);

                    // Block can be safely split
                    final int theNewFreeStart = theCurrent + aSize;
                    final int theNewFreeSize = theSize - aSize;
                    Address.setIntValue(theNewFreeStart, 0, theNewFreeSize);
                    Address.setIntValue(theNewFreeStart, 4, theNext);

                    if (thePrevious == 0) {
                        Address.setIntValue(heapBase, 4, theNewFreeStart);
                    } else {
                        Address.setIntValue(thePrevious, 4, theNewFreeStart);
                    }
                } else {
                    // Remaining size would be too small, be have to completely occupy it
                    Address.setIntValue(theCurrent, 0, theSize);

                    if (thePrevious == 0) {
                        Address.setIntValue(heapBase, 4, theNext);
                    } else {
                        Address.setIntValue(thePrevious, 4, theNext);
                    }
                }

                // Add the current block to the allocated block ist by prepending it to the list
                final int theReservedListPtr = Address.getIntValue(heapBase, 8);

                Address.setIntValue(theCurrent, 4, theReservedListPtr);
                Address.setIntValue(heapBase, 8, theCurrent);

                // Reset survivor count of the block
                Address.setIntValue(theCurrent, 8, 1);

                // Wipeout data
                final int theDataStart = theCurrent + 12;

                for (int i=0;i= blockLimit) {
                    // We have reached the limit for the current run
                    // We save the next block to proceed and exit here
                    Address.setIntValue(heapBase, 12, theNext);
                    return stepCounter;
                }
            }

            theCurrent = theNext;
        }
        // Increment epoch
        Address.setIntValue(heapBase, 16, currentEpoch + 1);

        // The next run starts at the beginning
        Address.setIntValue(heapBase, 12, 0);

        return freeCounter;
    }

    @Export("newArrayINTINTINT")
    public static int newArray(final int aSize, final int aType, final int aVTableIndex) {

        // Arrays are normal objects. Their data are a length field plus n * data
        final int theObject = newObject(16 + 4 + 8 * aSize, aType, aVTableIndex);

        Address.setIntValue(theObject, 16, aSize);
        return theObject;
    }

    @Export("newArrayINTINTINTINT")
    public static int newArray(final int aSize1, final int aSize2, final int aType, final int aVTableIndex) {
        final int theResult = newArray(aSize1, aType, aVTableIndex);
        for (int i=0;i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy