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

s.java.lang.Class Maven / Gradle / Ivy

There is a newer version: 0.9.6
Show newest version
package s.java.lang;

import org.aion.avm.ClassNameExtractor;
import a.ObjectArray;
import i.AvmThrowable;
import i.ConstantToken;
import i.IInstrumentation;
import i.IObject;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.aion.avm.RuntimeMethodFeeSchedule;
import s.java.io.Serializable;

/**
 * Note that the shadow Class wraps the instance of the actual class being used for all cases.
 * While this seems clear for user-defined classes, JDK and API classes allow for some confusion, as there are original and shadow variants
 * of their classes.
 * To be clear, the shadow Class will always wrap an instance of the SHADOW VARIANT (that is, "s.java.lang.Byte", not "java.lang.Byte"), as
 * that is the type actually being instantiated.
 * The ONLY exception to this is primitive pseudo-classes, such as "Byte.TYPE", where the underlying JDK Class instance is wrapped, directly.
 * This is because these types cannot be instantiated so they would be a special-case, either way.
 */
public final class Class extends Object implements Serializable {
    static {
        // Shadow classes MUST be loaded during bootstrap phase.
        IInstrumentation.attachedThreadInstrumentation.get().bootstrapOnly();
    }

    public String avm_getName() {
        IInstrumentation.attachedThreadInstrumentation.get().chargeEnergy(RuntimeMethodFeeSchedule.Class_avm_getName);
        // Note that we actively try not to give the same instance of the name wrapper back (since the user could see implementation details of our
        // contract life-cycle or the underlying JVM/ClassLoader.
        return getName();
    }

    public String avm_toString() {
        IInstrumentation.attachedThreadInstrumentation.get().chargeEnergy(RuntimeMethodFeeSchedule.Class_avm_toString);
        return new String((this.v.isInterface() ? "interface " : (this.v.isPrimitive() ? "" : "class "))
                + getName());
    }

    public IObject avm_cast(IObject obj) {
        IInstrumentation.attachedThreadInstrumentation.get().chargeEnergy(RuntimeMethodFeeSchedule.Class_avm_cast);
        return (IObject)this.v.cast(obj);
    }

    public java.lang.Class getRealClass(){return this.v;}

    @SuppressWarnings("unchecked")
    public Class avm_getSuperclass() {
        IInstrumentation.attachedThreadInstrumentation.get().chargeEnergy(RuntimeMethodFeeSchedule.Class_avm_getSuperclass);
        // Note that we need to return null if the underlying is the shadow object root.
        Class toReturn = null;
        if (s.java.lang.Object.class != this.v) {
            toReturn = (Class) IInstrumentation.attachedThreadInstrumentation.get().wrapAsClass(this.v.getSuperclass());
        }
        return toReturn;
    }

    public boolean avm_desiredAssertionStatus() {
        IInstrumentation.attachedThreadInstrumentation.get().chargeEnergy(RuntimeMethodFeeSchedule.Class_avm_desiredAssertionStatus);
        // Note that we currently handle assertions as always-enabled.
        // Internally, these will result in throwing AssertionError which, unless caught by the user's code, results in a FAILED_EXCEPTION status.
        // See issue-72 for more details on our thought process and future interpretations of this we may want to entertain.
        return true;
    }

    //=======================================================
    // Methods below are used by Enum
    //========================================================
    Map enumConstantDirectory() {
        Map directory = enumConstantDirectory;
        if (directory == null) {
            ObjectArray universe = getEnumConstantsShared();
            if (universe == null)
                throw new IllegalArgumentException(
                        getName() + " is not an enum type");
            directory = new HashMap<>(2 * universe.length());
            for (int i = 0; i < universe.length(); i++){
                @SuppressWarnings("unchecked")
                T constant = (T) universe.get(i);
                directory.put(((Enum)constant).getName(), constant);
            }
            enumConstantDirectory = directory;
        }
        return directory;
    }
    private transient volatile Map enumConstantDirectory;



    ObjectArray getEnumConstantsShared() {
        ObjectArray constants = enumConstants;
        if (constants == null) {
            try {
                Method m = v.getDeclaredMethod("avm_values");
                java.lang.Object value = m.invoke(null);

                constants = (ObjectArray) value;
                enumConstants = constants;
            } catch (InvocationTargetException e) {
                // This can happen as a result of an out-of-energy exception - throw back any of our types.
                if (e.getCause() instanceof AvmThrowable) {
                    throw (AvmThrowable) e.getCause();
                } else {
                    // This is unexpected, but the user should be able to craft an attempt to call this so just log it, in case this is a cause for concern.
                    e.printStackTrace();
                    constants = null;
                }
            } catch (NoSuchMethodException | IllegalAccessException e) {
                // This is unexpected, but the user should be able to craft an attempt to call this so just log it, in case this is a cause for concern.
                e.printStackTrace();
                constants = null;
            }
        }
        return constants;
    }
    private transient volatile ObjectArray enumConstants;


    //=======================================================
    // Methods below are used by runtime and test code only!
    //========================================================

    public Class(java.lang.Class v) {
        // We will base our hashcode on the original class name.
        super(null, null, ClassNameExtractor.getOriginalClassName(v.getName()).hashCode());
        this.v = v;
    }

    protected Class(java.lang.Class v, ConstantToken constantToken) {
        super(constantToken);
        this.v = v;
    }
    private final java.lang.Class v;

    @Override
    public java.lang.String toString() {
        return this.v.toString();
    }

    public String getName() {
        return new s.java.lang.String(ClassNameExtractor.getOriginalClassName(v.getName()));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy