Package org.jnode.vm.classmgr

Source Code of org.jnode.vm.classmgr.VmMethod

/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.vm.classmgr;

import java.lang.reflect.Member;
import org.jnode.annotation.MagicPermission;
import org.jnode.annotation.PrivilegedActionPragma;
import org.jnode.vm.InternString;
import org.jnode.vm.LoadCompileService;
import org.jnode.vm.VmAddress;
import org.jnode.vm.facade.VmUtils;
import org.jnode.vm.isolate.VmIsolateLocal;
import org.vmmagic.unboxed.Address;
import sun.reflect.ReflectionFactory;

@MagicPermission
public abstract class VmMethod extends VmMember implements VmSharedStaticsEntry {

    /**
     * Address of native code of this method
     */
    private VmAddress nativeCode;

    /**
     * #Slots taken by arguments of this method (including this pointer)
     */
    private final short argSlotCount;

    /**
     * Resolved types for each argument of this method
     */
    private VmType[] paramTypes;

    /**
     * Resolved return type of this method
     */
    private VmType returnType;

    /**
     * java.lang.reflect.Method for this method
     */
    private VmIsolateLocal<Member> javaMemberHolder;

    /**
     * The bytecode (if any)
     */
    private VmByteCode bytecode;

    /**
     * The compiled code (if any)
     */
    private VmCompiledCode compiledCode;

    /**
     * The exceptions we can throw
     */
    private VmExceptions exceptions;

    /**
     * The selector of this method name&type
     */
    private int selector;

    /**
     * Optimization level of native code
     */
    private short nativeCodeOptLevel = -1;

    /**
     * The index in the statics table
     */
    private final int staticsIndex;

    /**
     * The mangled name of this method
     */
    private String mangledName;

    /**
     * Flags of variour pragma's set to this method
     */
    private char pragmaFlags;

    private Object annotationDefault;
    private byte[] rawAnnotationDefault;
    private byte[] rawParameterAnnotations;

    /**
     * Constructor for VmMethod.
     *
     * @param name
     * @param signature
     * @param modifiers
     * @param declaringClass
     */
    protected VmMethod(String name, String signature, int modifiers,
                       VmType<?> declaringClass) {
        super(
            name,
            signature,
            modifiers | (returnsObject(signature) ? Modifier.ACC_OBJECTREF : 0),
            declaringClass);
        this.argSlotCount = (short) (Signature.getArgSlotCount(declaringClass
            .getLoader().getArchitecture().getTypeSizeInfo(), signature)
            + (isStatic() ? 0 : 1));
        final VmClassLoader cl = declaringClass.getLoader();
        if (isStatic()) {
            this.selector = 0;
        } else {
            this.selector = cl.getSelectorMap().get(name, signature);
        }
        this.staticsIndex = cl.getSharedStatics().allocMethodCode();
    }

    private static final boolean returnsObject(String signature) {
        final char firstReturnSignatureChar = signature.charAt(signature
            .indexOf(')') + 1);
        return (firstReturnSignatureChar == '[' || firstReturnSignatureChar == 'L');
    }

    /**
     * Initialize this instance, copy the given method.
     *
     * @param src The method that is copied.
     */
    protected VmMethod(VmMethod src) {
        super(src.name, src.signature, src.getModifiers(), src.declaringClass);
        this.argSlotCount = src.argSlotCount;
        this.selector = src.selector;
        this.staticsIndex = src.staticsIndex;
    }

    /**
     * Get the currently used byte-code information for this method. This
     * bytecode may have been optimized. This may return null if this is a
     * native or abstract method.
     *
     * @return The current bytecode
     */
    public final VmByteCode getBytecode() {
        return bytecode;
    }

    //todo security review
    /**
     * Sets the bytecode information of this method.
     *
     * @param bc
     */
    public final void setBytecode(VmByteCode bc) {
        this.bytecode = bc;
        bc.lock();
    }

    /**
     * Get the number of bytes in the byte-codes for this method.
     *
     * @return Length of bytecode
     */
    public final int getBytecodeSize() {
        return (bytecode == null) ? 0 : bytecode.getLength();
    }

    /**
     * Gets myself as java.lang.reflect.Method or java.lang.reflect.Constructor,
     * depending on isConstructor().
     *
     * @return Method
     */
    @PrivilegedActionPragma
    public final Member asMember() {
        if (javaMemberHolder == null) {
            javaMemberHolder = new VmIsolateLocal<Member>();
        }
        Member javaMember = javaMemberHolder.get();
        if (javaMember == null) {
            //parameter types
            int arg_count = getNoArguments();
            Class[] args = new Class[arg_count];
            for (int i = 0; i < arg_count; i++) {
                args[i] = getArgumentType(i).asClass();
            }
            //checked exceptions
            final VmExceptions exceptions = getExceptions();
            int ce_count = exceptions.getLength();
            final Class[] ces = new Class[ce_count];
            for (int i = 0; i < ce_count; i++) {
                VmConstClass vmConstClass = exceptions.getException(i);
                if (!vmConstClass.isResolved()) {
                    vmConstClass.doResolve(getDeclaringClass().getLoader());
                }
                ces[i] = vmConstClass.getResolvedVmClass().asClass();
            }
            //slot
            VmType decl_type = getDeclaringClass();
            int slot = -1;
            for (int i = 0; i < decl_type.getNoDeclaredMethods(); i++) {
                if (this == decl_type.getDeclaredMethod(i)) {
                    slot = i;
                    break;
                }
            }

            if (isConstructor()) {
                if (slot == -1) {
                    throw new ClassFormatError("Invalid constructor");
                }
                javaMember = ReflectionFactory.getReflectionFactory().newConstructor(getDeclaringClass().asClass(),
                    args, ces, getModifiers(), slot, getSignature(), getRawAnnotations(), getRawParameterAnnotations());
            } else {
                if (slot == -1) {
                    throw new ClassFormatError("Invalid method");
                }
                javaMember = ReflectionFactory.getReflectionFactory().newMethod(getDeclaringClass().asClass(),
                    getName(), args, getReturnType().asClass(), ces, getModifiers(), slot, getSignature(),
                    getRawAnnotations(), getRawParameterAnnotations(), getRawAnnotationDefault());
            }
            javaMemberHolder.set(javaMember);
        }
        return javaMember;
    }

    /**
     * Convert myself into a String representation
     *
     * @return String
     */
    public final String toString() {
        return getMangledName();
    }

    /**
     * Convert myself into a String representation
     *
     * @return The mangled name
     */
    public final String getMangledName() {
        if (mangledName == null) {
            mangledName = InternString.internString(declaringClass.getMangledName()
                + Mangler.mangle('#' + getName() + '.' + getSignature()));
        }
        return mangledName;
    }

    /**
     * Gets the full name of this method consisting of
     * its declaring class, its name and its signature.
     *
     * @return the full name
     */
    public final String getFullName() {
        return declaringClass.getName() + '#' + getName() + '!' + getSignature();
    }

    //todo security review
    public final void resetOptLevel() {
        nativeCodeOptLevel = 0;
    }

    /**
     * Compile this method with n optimization level 1 higher then the current
     * optimization level.
     */
    public final void recompile() {
        final int optLevel = nativeCodeOptLevel + 1;
        if (!declaringClass.isPrepared()) {
            throw new IllegalStateException(
                "Declaring class must have been prepared");
        }
        LoadCompileService.compile(this, optLevel, false);
    }

    /**
     * Recompile a method declaring in the type given by its statics table index
     * and the index of the method within the type.
     *
     * @param typeStaticsIndex
     * @param methodIndex
     */
    static final void recompileMethod(int typeStaticsIndex, int methodIndex) {
        final VmType<?> type = VmUtils.getVm().getSharedStatics().getTypeEntry(
            typeStaticsIndex);
        type.initialize();
        final VmMethod method = type.getDeclaredMethod(methodIndex);
        method.recompile();
    }

    public final boolean isAbstract() {
        return Modifier.isAbstract(getModifiers());
    }

    public final boolean isNative() {
        return Modifier.isNative(getModifiers());
    }

    public final boolean isSpecial() {
        return Modifier.isSpecial(getModifiers());
    }

    public final boolean isSynchronized() {
        return Modifier.isSynchronized(getModifiers());
    }

    public final boolean isConstructor() {
        return Modifier.isConstructor(getModifiers());
    }

    public final boolean isInitializer() {
        return Modifier.isInitializer(getModifiers());
    }

    /*
     * public final boolean isCompiled() { return
     * Modifier.isCompiled(getModifiers());
     */

    /**
     * Resolve the type of this method.
     */
    protected final void resolve() {
        resolveTypes();
    }

    private final void resolveTypes() {
        if (paramTypes == null) {
            try {
                Signature sig = new Signature(getSignature(), declaringClass
                    .getLoader());
                returnType = sig.getReturnType();
                int count = sig.getParamCount();
                final VmType[] types = new VmType[count];
                for (int i = 0; i < count; i++) {
                    types[i] = sig.getParamType(i);
                }
                this.paramTypes = types;
            } catch (ClassNotFoundException ex) {
                throw (Error) new NoClassDefFoundError("In method "
                    + toString()).initCause(ex);
            }
        }
    }

    public final int getNoArguments() {
        resolveTypes();
        return paramTypes.length;
    }

    public final VmType<?> getArgumentType(int index) {
        resolveTypes();
        return paramTypes[index];
    }

    /**
     * Does the given array of types match my argument types?
     *
     * @param argTypes
     * @return boolean
     */
    protected final boolean matchArgumentTypes(VmType[] argTypes) {
        resolveTypes();
        int argTypesLength = (argTypes == null) ? 0 : argTypes.length;
        if (paramTypes.length != argTypesLength) {
            return false;
        }
        for (int i = 0; i < argTypesLength; i++) {
            if (argTypes[i] != paramTypes[i]) {
                return false;
            }
        }
        return true;
    }

    /**
     * @return VmClass
     */
    public final VmType<?> getReturnType() {
        resolveTypes();
        return returnType;
    }

    /**
     * Does this method return void?
     *
     * @return boolean
     */
    public final boolean isReturnVoid() {
        return (signature.charAt(signature.length() - 1) == 'V');
    }

    /**
     * Does this method return long or double?
     *
     * @return boolean
     */
    public final boolean isReturnWide() {
        return ((this.getModifiers() & Modifier.ACC_WIDE) != 0);
    }

    /**
     * Does this method return an object reference.
     *
     * @return boolean
     */
    public final boolean isReturnObject() {
        return ((this.getModifiers() & Modifier.ACC_OBJECTREF) != 0);
    }

    /**
     * Gets the exceptions this method has declared to throw
     *
     * @return The exceptions this method has declared to throw, never null.
     */
    public final VmExceptions getExceptions() {
        if (exceptions == null) {
            exceptions = new VmExceptions();
        }
        return exceptions;
    }

    /**
     * Sets the exceptions this method has declared to throw
     *
     * @param exceptions
     * @throws ClassFormatError
     */
    final void setExceptions(VmExceptions exceptions) throws ClassFormatError {
        if (this.exceptions == null) {
            this.exceptions = exceptions;
            this.pragmaFlags |= exceptions.getPragmaFlags();
        } else {
            throw new ClassFormatError(
                "Cannot have more then 1 Exceptions attribute");
        }
    }

    /**
     * Add the given pragma flags to my flags.
     */
    final void addPragmaFlags(int flags) {
        this.pragmaFlags |= flags;

        // KernelSpace implies uninterruptible
        if ((flags & MethodPragmaFlags.KERNELSPACE) != 0) {
            this.pragmaFlags |= MethodPragmaFlags.UNINTERRUPTIBLE;
        }
    }

    /**
     * Gets the compiled code information of this method (if any)
     *
     * @return The compiled code, or null if no compiled code has been set.
     */
    public final VmCompiledCode getDefaultCompiledCode() {
        return compiledCode;
    }

    /**
     * Gets the compiled code for a given magic value (if any)
     *
     * @return The compiled code, or null if no compiled code with the given
     *         magic has been set.
     */
    public final VmCompiledCode getCompiledCode(int magic) {
        final VmCompiledCode c = compiledCode;
        if (c != null) {
            return c.lookup(magic);
        } else {
            return null;
        }
    }

    /**
     * Install the generated code.
     *
     * @param code
     * @param optLevel The optimization level of the generated code.
     */
    public final void addCompiledCode(VmCompiledCode code, int optLevel) {
        if ((this.nativeCode == null) || (optLevel > nativeCodeOptLevel)) {
            synchronized (this) {
                code.setNext(this.compiledCode);
                this.compiledCode = code;
                this.nativeCode = code.getNativeCode();
                VmUtils.getVm().getSharedStatics().setMethodCode(
                    getSharedStaticsIndex(), code.getNativeCode());
                this.nativeCodeOptLevel = (short) optLevel;
            }
        }
    }

    /**
     * Gets the global unique selector if this method name&amp;type.
     *
     * @return The selector
     */
    public final int getSelector() {
        return selector;
    }

    /**
     * Gets the number of stack slots used by the arguments of this method. This
     * number included the slot for "this" on non-static fields.
     *
     * @return int
     */
    public final int getArgSlotCount() {
        return this.argSlotCount;
    }

    /**
     * Is this method uninterruptible.
     *
     * @return {@code true} if the pragma flag is set, otherwise {@code false}.
     */
    public final boolean isUninterruptible() {
        return ((pragmaFlags & MethodPragmaFlags.UNINTERRUPTIBLE) != 0);
    }

    /**
     * Is the checkpermission pragma set for this method.
     *
     * @return {@code true} if the pragma flag is set, otherwise {@code false}.
     */
    public final boolean hasCheckPermissionPragma() {
        return ((pragmaFlags & MethodPragmaFlags.CHECKPERMISSION) != 0);
    }

    /**
     * Is the doprivileged pragma set for this method.
     *
     * @return {@code true} if the pragma flag is set, otherwise {@code false}.
     */
    public final boolean hasDoPrivilegedPragma() {
        return ((pragmaFlags & MethodPragmaFlags.DOPRIVILEGED) != 0);
    }

    /**
     * Is the inline pragma set for this method.
     *
     * @return {@code true} if the pragma flag is set, otherwise {@code false}.
     */
    public final boolean hasInlinePragma() {
        return ((pragmaFlags & MethodPragmaFlags.INLINE) != 0);
    }

    /**
     * Is the loadstatics pragma set for this method.
     *
     * @return {@code true} if the pragma flag is set, otherwise {@code false}.
     */
    public final boolean hasLoadStaticsPragma() {
        return ((pragmaFlags & MethodPragmaFlags.LOADSTATICS) != 0);
    }

    /**
     * Is the noinline pragma set for this method.
     *
     * @return {@code true} if the pragma flag is set, otherwise {@code false}.
     */
    public final boolean hasNoInlinePragma() {
        return ((pragmaFlags & MethodPragmaFlags.NOINLINE) != 0);
    }

    /**
     * Is the noreadbarrier pragma set for this method.
     *
     * @return {@code true} if the pragma flag is set, otherwise {@code false}.
     */
    public final boolean hasNoReadBarrierPragma() {
        return ((pragmaFlags & MethodPragmaFlags.NOREADBARRIER) != 0);
    }

    /**
     * Is the nowritebarrier pragma set for this method.
     *
     * @return {@code true} if the pragma flag is set, otherwise {@code false}.
     */
    public final boolean hasNoWriteBarrierPragma() {
        return ((pragmaFlags & MethodPragmaFlags.NOWRITEBARRIER) != 0);
    }

    /**
     * Is the privilegedaction pragma set for this method.
     *
     * @return {@code true} if the pragma flag is set, otherwise {@code false}.
     */
    public final boolean hasPrivilegedActionPragma() {
        return ((pragmaFlags & MethodPragmaFlags.PRIVILEGEDACTION) != 0);
    }

    /**
     * Is the KernelSpace pragma set for this method.
     *
     * @return {@code true} if the pragma flag is set, otherwise {@code false}.
     */
    public final boolean hasKernelSpacePragma() {
        return ((pragmaFlags & MethodPragmaFlags.KERNELSPACE) != 0);
    }

    /**
     * Mark this method as uninterruptable.
     */
    final void setUninterruptible() {
        pragmaFlags |= MethodPragmaFlags.UNINTERRUPTIBLE;
    }

    /**
     * Gets the optimization level of the native code. A value of -1 means not
     * compiled yet.
     *
     * @return Returns the nativeCodeOptLevel.
     */
    public final int getNativeCodeOptLevel() {
        return this.nativeCodeOptLevel;
    }

    /**
     * Gets the index of this field in the shared statics table.
     *
     * @return Returns the staticsIndex.
     */
    public final int getSharedStaticsIndex() {
        return this.staticsIndex;
    }

    public boolean hasNativeCode() {
        if (nativeCode == null) {
            return false;
        } else {
            return true;
        }
    }

    public void testNativeCode() {
        if (declaringClass.isInterface()) {
            return;
        }
        if (nativeCode == null) {
            System.err.println("nativeCode == null in " + this);
        } else {
            final int ptr = Address.fromAddress(nativeCode).toInt();
            if ((ptr < 0) || (Math.abs(ptr) < 4096)) {
                System.err.println("nativeCode has low address " + ptr + " in "
                    + this);
            }
        }
    }

    /**
     * @see org.jnode.vm.objects.VmSystemObject#verifyBeforeEmit()
     */
    public void verifyBeforeEmit() {
        super.verifyBeforeEmit();
        if (nativeCode == null) {
            if (!declaringClass.isInterface()) {
                throw new RuntimeException("nativeCode of " + this
                    + " is null; declaringclass compiled? "
                    + getDeclaringClass().isCompiled());
            }
        }
    }

    public Object getAnnotationDefault() {
        return annotationDefault;
    }

    public void setAnnotationDefault(Object annotationDefault) {
        this.annotationDefault = annotationDefault;
    }

    public byte[] getRawAnnotationDefault() {
        return rawAnnotationDefault;
    }

    public void setRawAnnotationDefault(byte[] rawAnnotationDefault) {
        this.rawAnnotationDefault = rawAnnotationDefault;
    }

    public byte[] getRawParameterAnnotations() {
        return rawParameterAnnotations;
    }

    public void setRawParameterAnnotations(byte[] rawParameterAnnotations) {
        this.rawParameterAnnotations = rawParameterAnnotations;
    }
}
TOP

Related Classes of org.jnode.vm.classmgr.VmMethod

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.