SquirrelJME/SquirrelJME

View on GitHub
emulators/springcoat-vm/src/main/java/cc/squirreljme/vm/springcoat/MLEReference.java

Summary

Maintainability
A
0 mins
Test Coverage
// -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
// ---------------------------------------------------------------------------
// SquirrelJME
//     Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
// ---------------------------------------------------------------------------
// SquirrelJME is under the Mozilla Public License Version 2.0.
// See license.mkd for licensing and copyright information.
// ---------------------------------------------------------------------------

package cc.squirreljme.vm.springcoat;

import cc.squirreljme.jvm.mle.ReferenceShelf;
import cc.squirreljme.jvm.mle.brackets.RefLinkBracket;
import cc.squirreljme.runtime.cldc.debug.Debugging;
import cc.squirreljme.vm.springcoat.brackets.RefLinkHolder;
import cc.squirreljme.vm.springcoat.brackets.RefLinkObject;
import cc.squirreljme.vm.springcoat.exceptions.SpringMLECallError;

/**
 * Functions for {@link ReferenceShelf}.
 *
 * @since 2020/06/18
 */
public enum MLEReference
    implements MLEFunction
{
    /** {@link ReferenceShelf#deleteLink(RefLinkBracket)}. */
    DELETE_LINK("deleteLink:(Lcc/squirreljme/jvm/mle/brackets/" +
        "RefLinkBracket;)V")
    {
        /**
         * {@inheritDoc}
         * @since 2020/06/29
         */
        @Override
        public Object handle(SpringThreadWorker __thread, Object... __args)
        {
            synchronized (GlobalState.class)
            {
                // Check it, but otherwise do nothing
                MLEReference.__refLink(__args[0]);
            }
            
            return null;
        }
    },
    
    /** {@link ReferenceShelf#linkChain(RefLinkBracket, Object)}. */
    LINK_CHAIN("linkChain:(Lcc/squirreljme/jvm/mle/brackets/" +
        "RefLinkBracket;Ljava/lang/Object;)V")
    {
        /**
         * {@inheritDoc}
         * @since 2022/09/01
         */
        @Override
        public Object handle(SpringThreadWorker __thread, Object... __args)
        {
            RefLinkObject link = MLEReference.__refLink(__args[0]);
            
            if (__args[1] == null)
                throw new SpringMLECallError("Null object.");
            if (!(__args[1] instanceof SpringSimpleObject))
                throw new SpringMLECallError("Invalid object");
            
            SpringSimpleObject object = (SpringSimpleObject)__args[1];
            RefLinkHolder objRefLink = object.refLink();
            
            synchronized (GlobalState.class)
            {
                // If the object has an existing link, then we need to chain
                // links
                synchronized (objRefLink)
                {
                    RefLinkObject oldLink = objRefLink.get();
                    if (oldLink != null)
                    {
                        // New link -> Old link
                        link.setNext(oldLink);
                        
                        // New link <- Old link
                        oldLink.setPrev(link);
                    }
                    
                    // The object uses the current link as the head now
                    objRefLink.set(link);
                }
            }
            
            return null;
        }
    },
    
    /** {@link ReferenceShelf#linkGetNext(RefLinkBracket)}. */
    LINK_GET_NEXT("linkGetNext:(Lcc/squirreljme/jvm/mle/brackets/" +
        "RefLinkBracket;)Lcc/squirreljme/jvm/mle/brackets/RefLinkBracket;")
    {
        /**
         * {@inheritDoc}
         * @since 2020/06/29
         */
        @Override
        public Object handle(SpringThreadWorker __thread, Object... __args)
        {
            synchronized (GlobalState.class)
            {
                return MLEReference.__refLink(__args[0]).getNext();
            }
        }
    },
    
    /** {@link ReferenceShelf#linkGetObject(RefLinkBracket)}. */
    LINK_GET_OBJECT("linkGetObject:(Lcc/squirreljme/jvm/mle/brackets/" +
        "RefLinkBracket;)Ljava/lang/Object;")
    {
        /**
         * {@inheritDoc}
         * @since 2020/06/18
         */
        @Override
        public Object handle(SpringThreadWorker __thread, Object... __args)
        {
            synchronized (GlobalState.class)
            {
                return MLEReference.__refLink(__args[0]).getObject();
            }
        }
    },
    
    /** {@link ReferenceShelf#linkGetPrev(RefLinkBracket)}. */
    LINK_GET_PREV("linkGetPrev:(Lcc/squirreljme/jvm/mle/brackets/" +
        "RefLinkBracket;)Lcc/squirreljme/jvm/mle/brackets/RefLinkBracket;")
    {
        /**
         * {@inheritDoc}
         * @since 2020/06/29
         */
        @Override
        public Object handle(SpringThreadWorker __thread, Object... __args)
        {
            synchronized (GlobalState.class)
            {
                return MLEReference.__refLink(__args[0]).getPrev();
            }
        }
    },
    
    /** {@link ReferenceShelf#linkSetNext(RefLinkBracket, RefLinkBracket)}. */
    LINK_SET_NEXT("linkSetNext:(Lcc/squirreljme/jvm/mle/brackets/" +
        "RefLinkBracket;Lcc/squirreljme/jvm/mle/brackets/RefLinkBracket;)V")
    {
        /**
         * {@inheritDoc}
         * @since 2020/06/29
         */
        @Override
        public Object handle(SpringThreadWorker __thread, Object... __args)
        {
            synchronized (GlobalState.class)
            {
                MLEReference.__refLink(__args[0]).setNext(
                    MLEReference.__refLink(__args[1]));
            }
            
            return null;
        }
    },
    
    /** {@link ReferenceShelf#linkSetObject(RefLinkBracket, Object)}. */
    LINK_SET_OBJECT("linkSetObject:(Lcc/squirreljme/jvm/mle/brackets/" +
        "RefLinkBracket;Ljava/lang/Object;)V")
    {
        /**
         * {@inheritDoc}
         * @since 2020/06/18
         */
        @Override
        public Object handle(SpringThreadWorker __thread, Object... __args)
        {
            synchronized (GlobalState.class)
            {
                MLEReference.__refLink(__args[0])
                    .setObject((SpringObject)__args[1]);
            }
            
            return null;
        }
    },
    
    /** {@link ReferenceShelf#linkSetPrev(RefLinkBracket, RefLinkBracket)}. */
    LINK_SET_PREV("linkSetPrev:(Lcc/squirreljme/jvm/mle/brackets/" +
        "RefLinkBracket;Lcc/squirreljme/jvm/mle/brackets/RefLinkBracket;)V")
    {
        /**
         * {@inheritDoc}
         * @since 2020/06/29
         */
        @Override
        public Object handle(SpringThreadWorker __thread, Object... __args)
        {
            synchronized (GlobalState.class)
            {
                MLEReference.__refLink(__args[0]).setPrev(
                    MLEReference.__refLink(__args[1]));
            }
            
            return null;
        }
    },
    
    /** {@link ReferenceShelf#linkUnchain(RefLinkBracket)}. */
    LINK_UNCHAIN("linkUnchain:(Lcc/squirreljme/jvm/mle/brackets/" +
        "RefLinkBracket;Lcc/squirreljme/jvm/mle/brackets/RefLinkBracket;)V")
    {
        /**
         * {@inheritDoc}
         * @since 2022/09/01
         */
        @Override
        public Object handle(SpringThreadWorker __thread, Object... __args)
        {
            RefLinkObject thisLink = MLEReference.__refLink(__args[0]);
            
            synchronized (GlobalState.class)
            {
                // Get the previous and next links to re-chain
                RefLinkObject prev = thisLink.getPrev();
                RefLinkObject next = thisLink.getNext();
                
                // Have the previous link point to our next
                if (prev != null)
                    prev.setNext(next);
                
                // Have the next link point to our previous
                if (next != null)
                    next.setPrev(prev);
                
                // Clear our links because they are no longer valid
                thisLink.setPrev(null);
                thisLink.setNext(null);
            }
            
            return null;
        }
    },
    
    /** {@link ReferenceShelf#linkUnlinkAndClear(RefLinkBracket)}. */ 
    LINK_UNLINK_AND_CLEAR("linkUnlinkAndClear:(Lcc/squirreljme/jvm/" +
        "mle/brackets/RefLinkBracket;)V")
    {
        @Override
        public Object handle(SpringThreadWorker __thread, Object... __args)
        {
            RefLinkObject thisLink = MLEReference.__refLink(__args[0]);
            
            synchronized (GlobalState.class)
            {
                synchronized (thisLink)
                {
                    // Unchain all the connected links atomically
                    MLEReference.LINK_UNCHAIN.handle(__thread, __args[0]);
                    
                    // Clear the object this links to
                    MLEReference.LINK_SET_OBJECT.handle(__thread, __args[0],
                        SpringNullObject.NULL);
                    
                    // We can delete our link now and free any associated
                    // memory because it is dangling and serves no purpose
                    // otherwise
                    MLEReference.DELETE_LINK.handle(__thread, __args[0]);
                }
            }
            
            return null;
        }
    },
    
    /** {@link ReferenceShelf#newLink()}. */
    NEW_LINK("newLink:()Lcc/squirreljme/jvm/mle/brackets/" +
        "RefLinkBracket;")
    {
        /**
         * {@inheritDoc}
         * @since 2020/06/18
         */
        @Override
        public Object handle(SpringThreadWorker __thread, Object... __args)
        {
            return new RefLinkObject(__thread.machine);
        }
    },
    
    /** {@link ReferenceShelf#objectGet(Object)}. */
    OBJECT_GET("objectGet:(Ljava/lang/Object;)" +
        "Lcc/squirreljme/jvm/mle/brackets/RefLinkBracket;")
    {
        /**
         * {@inheritDoc}
         * @since 2020/06/18
         */
        @Override
        public Object handle(SpringThreadWorker __thread, Object... __args)
        {
            synchronized (GlobalState.class)
            {
                SpringObject object = (SpringObject)__args[0];
                if (!(object instanceof SpringSimpleObject))
                    throw new SpringMLECallError("Invalid object"); 
                
                return object.refLink().get();
            }
        }
    },
    
    /** {@link ReferenceShelf#objectSet(Object, RefLinkBracket)}. */
    OBJECT_SET("objectSet:(Ljava/lang/Object;" +
        "Lcc/squirreljme/jvm/mle/brackets/RefLinkBracket;)V")
    {
        /**
         * {@inheritDoc}
         * @since 2020/06/18
         */
        @Override
        public Object handle(SpringThreadWorker __thread, Object... __args)
        {
            synchronized (GlobalState.class)
            {
                SpringObject object = (SpringObject)__args[0];
                if (!(object instanceof SpringSimpleObject))
                    throw new SpringMLECallError("Invalid object"); 
                
                object.refLink().set(MLEReference.__refLink(__args[1]));
            }
            
            return null;
        }
    }
    
    /* End. */
    ;
    
    /** The dispatch key. */
    protected final String key;
    
    /**
     * Initializes the dispatcher info.
     *
     * @param __key The key.
     * @throws NullPointerException On null arguments.
     * @since 2020/06/18
     */
    MLEReference(String __key)
        throws NullPointerException
    {
        if (__key == null)
            throw new NullPointerException("NARG");
        
        this.key = __key;
    }
    
    /**
     * {@inheritDoc}
     * @since 2020/06/18
     */
    @Override
    public String key()
    {
        return this.key;
    }
    
    /**
     * Checks if this is a {@link RefLinkObject}.
     * 
     * @param __object The object to check.
     * @return As a {@link RefLinkObject} if this is one.
     * @throws SpringMLECallError If this is not a {@link RefLinkObject}.
     * @since 2020/06/28
     */
    static RefLinkObject __refLink(Object __object)
        throws SpringMLECallError
    {
        if (!(__object instanceof RefLinkObject))
            throw new SpringMLECallError("Not a RefLinkObject.");
        
        return (RefLinkObject)__object; 
    }
}