Package javassist.bytecode.stackmap

Source Code of javassist.bytecode.stackmap.TypeData$ArrayElement

/*
* Javassist, a Java-bytecode translator toolkit.
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License.  Alternatively, the contents of this file may be used under
* the terms of the GNU Lesser General Public License Version 2.1 or later,
* or the Apache License Version 2.0.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*/

package javassist.bytecode.stackmap;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
import javassist.bytecode.ConstPool;
import javassist.bytecode.StackMapTable;
import javassist.bytecode.BadBytecode;
import java.util.ArrayList;

public abstract class TypeData {
    /* Memo:
     * array type is a subtype of Cloneable and Serializable
     */

    protected TypeData() {}

    public abstract void merge(TypeData neighbor);

    /**
     * Sets the type name of this object type.  If the given type name is
     * a subclass of the current type name, then the given name becomes
     * the name of this object type.
     *
     * @param className     dot-separated name unless the type is an array type.
     */
    static void setType(TypeData td, String className, ClassPool cp) throws BadBytecode {
        if (td == TypeTag.TOP)
            throw new BadBytecode("unset variable");
        else
            td.setType(className, cp);
    }

    public abstract boolean equals(Object obj);

    public abstract int getTypeTag();
    public abstract int getTypeData(ConstPool cp);

    /*
     * See UninitData.getSelf().
     */
    public TypeData getSelf() { return this; }

    /* An operand value is copied when it is stored in a
     * local variable.
     */
    public abstract TypeData copy();

    public abstract boolean isObjectType();
    public boolean is2WordType() { return false; }
    public boolean isNullType() { return false; }

    public abstract String getName() throws BadBytecode;
    protected abstract void setType(String s, ClassPool cp) throws BadBytecode;
    public abstract void evalExpectedType(ClassPool cp) throws BadBytecode;
    public abstract String getExpected() throws BadBytecode;

    /**
     * Primitive types.
     */
    protected static class BasicType extends TypeData {
        private String name;
        private int typeTag;

        public BasicType(String type, int tag) {
            name = type;
            typeTag = tag;
        }

        public void merge(TypeData neighbor) {}

        public boolean equals(Object obj) {
            return this == obj;
        }

        public int getTypeTag() { return typeTag; }
        public int getTypeData(ConstPool cp) { return 0; }

        public boolean isObjectType() { return false; }

        public boolean is2WordType() {
            return typeTag == StackMapTable.LONG
                    || typeTag == StackMapTable.DOUBLE;
        }

        public TypeData copy() {
            return this;
        }

        public void evalExpectedType(ClassPool cp) throws BadBytecode {}

        public String getExpected() throws BadBytecode {
            return name;
        }

        public String getName() {
            return name;
        }

        protected void setType(String s, ClassPool cp) throws BadBytecode {
            throw new BadBytecode("conflict: " + name + " and " + s);
        }

        public String toString() { return name; }
    }

    protected static abstract class TypeName extends TypeData {
        protected ArrayList equivalences;

        protected String expectedName;
        private CtClass cache;
        private boolean evalDone;

        protected TypeName() {
            equivalences = new ArrayList();
            equivalences.add(this);
            expectedName = null;
            cache = null;
            evalDone = false;
        }

        public void merge(TypeData neighbor) {
            if (this == neighbor)
                return;

            if (!(neighbor instanceof TypeName))
                return;     // neighbor might be UninitData

            TypeName neighbor2 = (TypeName)neighbor;
            ArrayList list = equivalences;
            ArrayList list2 = neighbor2.equivalences;
            if (list == list2)
                return;

            int n = list2.size();
            for (int i = 0; i < n; i++) {
                TypeName tn = (TypeName)list2.get(i);
                add(list, tn);
                tn.equivalences = list;
            }
        }

        private static void add(ArrayList list, TypeData td) {
            int n = list.size();
            for (int i = 0; i < n; i++)
                if (list.get(i) == td)
                    return;

            list.add(td);
        }

        /* NullType overrides this method.
         */
        public int getTypeTag() { return StackMapTable.OBJECT; }

        public int getTypeData(ConstPool cp) {
            String type;
            try {
                type = getExpected();
            } catch (BadBytecode e) {
                throw new RuntimeException("fatal error: ", e);
            }

            return getTypeData2(cp, type);
        }

        /* NullType overrides this method.
         */
        protected int getTypeData2(ConstPool cp, String type) {
            return cp.addClassInfo(type);
        }

        public boolean equals(Object obj) {
            if (obj instanceof TypeName) {
                try {
                    TypeName tn = (TypeName)obj;
                    return getExpected().equals(tn.getExpected());
                }
                catch (BadBytecode e) {}
            }

            return false;
        }

        public boolean isObjectType() { return true; }

        protected void setType(String typeName, ClassPool cp) throws BadBytecode {
            if (update(cp, expectedName, typeName))
                expectedName = typeName;
        }

        public void evalExpectedType(ClassPool cp) throws BadBytecode {
            if (this.evalDone)
                return;

            ArrayList equiv = this.equivalences;
            int n = equiv.size();
            String name = evalExpectedType2(equiv, n);
            if (name == null) {
                name = this.expectedName;
                for (int i = 0; i < n; i++) {
                    TypeData td = (TypeData)equiv.get(i);
                    if (td instanceof TypeName) {
                        TypeName tn = (TypeName)td;
                        if (update(cp, name, tn.expectedName))
                            name = tn.expectedName;
                    }
                }
            }

            for (int i = 0; i < n; i++) {
                TypeData td = (TypeData)equiv.get(i);
                if (td instanceof TypeName) {
                    TypeName tn = (TypeName)td;
                    tn.expectedName = name;
                    tn.cache = null;
                    tn.evalDone = true;
                }
            }
        }

        private String evalExpectedType2(ArrayList equiv, int n) throws BadBytecode {
            String origName = null;
            for (int i = 0; i < n; i++) {
                TypeData td = (TypeData)equiv.get(i);
                if (!td.isNullType())
                    if (origName == null)
                        origName = td.getName();
                    else if (!origName.equals(td.getName()))
                        return null;
            }

            return origName;
        }

        protected boolean isTypeName() { return true; }

        private boolean update(ClassPool cp, String oldName, String typeName) throws BadBytecode {
            if (typeName == null)
                return false;
            else if (oldName == null)
                return true;
            else if (oldName.equals(typeName))
                return false;
            else if (typeName.charAt(0) == '['
                     && oldName.equals("[Ljava.lang.Object;")) {
                /* this rule is not correct but Tracer class sets the type
                   of the operand of arraylength to java.lang.Object[].
                   Thus, int[] etc. must be a subtype of java.lang.Object[].
                 */
                return true;
            }

            try {
                if (cache == null)
                    cache = cp.get(oldName);
   
                CtClass cache2 = cp.get(typeName);
                if (cache2.subtypeOf(cache)) {
                    cache = cache2;
                    return true;
                }
                else
                    return false;
            }
            catch (NotFoundException e) {
                throw new BadBytecode("cannot find " + e.getMessage());
            }
        }

        /* See also {NullType,ArrayElement}.getExpected().
         */
        public String getExpected() throws BadBytecode {
            ArrayList equiv = equivalences;
            if (equiv.size() == 1)
                return getName();
            else {
                String en = expectedName;
                if (en == null)
                    return "java.lang.Object";
                else
                    return en;
            }
        }

        public String toString() {
            try {
                String en = expectedName;
                if (en != null)
                    return en;

                String name = getName();
                if (equivalences.size() == 1)
                    return name;
                else
                    return name + "?";
            }
            catch (BadBytecode e) {
                return "<" + e.getMessage() + ">";
            }
        }
    }

    /**
     * Type data for OBJECT.
     */
    public static class ClassName extends TypeName {
        private String name;    // dot separated.  null if this object is a copy of another.
   
        public ClassName(String n) {
            name = n;
        }

        public TypeData copy() {
            return new ClassName(name);
        }

        public String getName() {   // never returns null.
            return name;
        }
    }

    /**
     * Type data for NULL or OBJECT.
     * The types represented by the instances of this class are
     * initially NULL but will be OBJECT.
     */
    public static class NullType extends ClassName {
        public NullType() {
            super("null");      // type name
        }

        public TypeData copy() {
            return new NullType();
        }

        public boolean isNullType() { return true; }

        public int getTypeTag() {
            try {
                if ("null".equals(getExpected()))
                    return StackMapTable.NULL;
                else
                    return super.getTypeTag();
            }
            catch (BadBytecode e) {
                throw new RuntimeException("fatal error: ", e);
            }
        }

        protected int getTypeData2(ConstPool cp, String type) {
            if ("null".equals(type))
                return 0;
            else
                return super.getTypeData2(cp, type);
        }

        public String getExpected() throws BadBytecode {
            String en = expectedName;
            if (en == null) {
              // ArrayList equiv = equivalences;
              // if (equiv.size() == 1)
              //    return getName();
              // else
                    return "java.lang.Object";
            }
            else
                return en;
        }
    }

    /**
     * Type data for OBJECT if the type is an object type and is
     * derived as an element type from an array type by AALOAD.
     */
    public static class ArrayElement extends TypeName {
        TypeData array;
   
        public ArrayElement(TypeData a) {   // a is never null
            array = a;
        }

        public TypeData copy() {
            return new ArrayElement(array);
        }

        public boolean isNullType() {
            return array.isNullType();
        }

        protected void setType(String typeName, ClassPool cp) throws BadBytecode {
            super.setType(typeName, cp);
            array.setType(getArrayType(typeName), cp);
        }

        public String getName() throws BadBytecode {
            return getName2(array.getName());
        }

        private String getName2(String name) throws BadBytecode {
            if (name.length() > 1 && name.charAt(0) == '[') {
                char c = name.charAt(1);
                if (c == 'L')
                    return name.substring(2, name.length() - 1).replace('/', '.');
                else if (c == '[')
                    return name.substring(1);
            }

            if (array.isNullType())
                return "java.lang.Object";
            else
                throw new BadBytecode("bad array type for AALOAD: "
                                  + name);
        }

        public String getExpected() throws BadBytecode {
            ArrayList equiv = equivalences;
            if (equiv.size() == 1)
                return getName2(array.getExpected());     // not getName();
            else {
                String en = expectedName;
                if (en == null)
                    return "java.lang.Object";
                else
                    return en;
            }
        }

        public static String getArrayType(String elementType) {
            if (elementType.charAt(0) == '[')
                return "[" + elementType;
            else
                return "[L" + elementType.replace('.', '/') + ";";
        }

        public static String getElementType(String arrayType) {
            char c = arrayType.charAt(1);
            if (c == 'L')
                return arrayType.substring(2, arrayType.length() - 1).replace('/', '.');                   
            else if (c == '[')
                return arrayType.substring(1);
            else
                return arrayType;
        }
    }

    /**
     * Type data for UNINIT.
     */
    public static class UninitData extends TypeData {
        String className;
        int offset;
        boolean initialized;

        UninitData(int offset, String className) {
            this.className = className;
            this.offset = offset;
            this.initialized = false;
        }

        public void merge(TypeData neighbor) {}

        public int getTypeTag() { return StackMapTable.UNINIT; }
        public int getTypeData(ConstPool cp) { return offset; }

        public boolean equals(Object obj) {
            if (obj instanceof UninitData) {
                UninitData ud = (UninitData)obj;
                return offset == ud.offset && className.equals(ud.className);
            }
            else
                return false;
        }

        public TypeData getSelf() {
            if (initialized)
                return copy();
            else
                return this;
        }

        public TypeData copy() {
            return new ClassName(className);
        }

        public boolean isObjectType() { return true; }

        protected void setType(String typeName, ClassPool cp) throws BadBytecode {
            initialized = true;
        }

        public void evalExpectedType(ClassPool cp) throws BadBytecode {}

        public String getName() {
            return className;
        }

        public String getExpected() { return className; }

        public String toString() { return "uninit:" + className + "@" + offset; }
    }

    public static class UninitThis extends UninitData {
        UninitThis(String className) {
            super(-1, className);
        }

        public int getTypeTag() { return StackMapTable.THIS; }
        public int getTypeData(ConstPool cp) { return 0; }

        public boolean equals(Object obj) {
            return obj instanceof UninitThis;
        }

        public String toString() { return "uninit:this"; }
    }
}
TOP

Related Classes of javassist.bytecode.stackmap.TypeData$ArrayElement

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.