001    package serp.bytecode;
002    
003    import java.util.*;
004    
005    import serp.bytecode.lowlevel.*;
006    import serp.util.*;
007    
008    /**
009     * Any typed instruction.
010     *
011     * @author Abe White
012     */
013    public abstract class TypedInstruction extends Instruction {
014        private static final Set _opcodeTypes = new HashSet();
015        static {
016            _opcodeTypes.add(int.class.getName());
017            _opcodeTypes.add(long.class.getName());
018            _opcodeTypes.add(float.class.getName());
019            _opcodeTypes.add(double.class.getName());
020            _opcodeTypes.add(Object.class.getName());
021            _opcodeTypes.add(byte.class.getName());
022            _opcodeTypes.add(char.class.getName());
023            _opcodeTypes.add(short.class.getName());
024            _opcodeTypes.add(boolean.class.getName());
025            _opcodeTypes.add(void.class.getName());
026        }
027    
028        TypedInstruction(Code owner) {
029            super(owner);
030        }
031    
032        TypedInstruction(Code owner, int opcode) {
033            super(owner, opcode);
034        }
035    
036        /**
037         * Return the type for the given name. Takes into account
038         * the given mappings and the demote flag.
039         *
040         * @param mappings mappings of one type to another; for example,
041         * array instruction treat booleans as ints, so
042         * to reflect that there should be an index x of the
043         * array such that mappings[x][0] = boolean.class and
044         * mappings[x][1] = int.class; may be null if no special mappings are needed
045         * @param demote if true, all object types will be demoted to Object.class
046         */
047        String mapType(String type, Class[][] mappings, boolean demote) {
048            if (type == null)
049                return null;
050    
051            type = getProject().getNameCache().getExternalForm(type, false);
052            if (!_opcodeTypes.contains(type) && demote)
053                type = Object.class.getName();
054    
055            if (mappings != null)
056                for (int i = 0; i < mappings.length; i++)
057                    if (mappings[i][0].getName().equals(type))
058                        type = mappings[i][1].getName();
059            return type;
060        }
061    
062        /**
063         * Return the type name for this instruction.
064         * If the type has not been set, this method will return null.
065         */
066        public abstract String getTypeName();
067    
068        /**
069         * Return the type for this instruction.
070         * If the type has not been set, this method will return null.
071         */
072        public Class getType() {
073            String type = getTypeName();
074            if (type == null)
075                return null;
076            return Strings.toClass(type, getClassLoader());
077        }
078    
079        /**
080         * Return the type for this instruction.
081         * If the type has not been set, this method will return null.
082         */
083        public BCClass getTypeBC() {
084            String type = getTypeName();
085            if (type == null)
086                return null;
087            return getProject().loadClass(type, getClassLoader());
088        }
089    
090        /**
091         * Set the type of this instruction. Types that have no direct
092         * support will be converted accordingly.
093         *
094         * @return this instruction, for method chaining
095         */
096        public abstract TypedInstruction setType(String type);
097    
098        /**
099         * Set the type of this instruction. Types that have no direct
100         * support will be converted accordingly.
101         *
102         * @return this instruction, for method chaining
103         */
104        public TypedInstruction setType(Class type) {
105            if (type == null)
106                return setType((String) null);
107            return setType(type.getName());
108        }
109    
110        /**
111         * Set the type of this instruction. Types that have no direct
112         * support will be converted accordingly.
113         *
114         * @return this instruction, for method chaining
115         */
116        public TypedInstruction setType(BCClass type) {
117            if (type == null)
118                return setType((String) null);
119            return setType(type.getName());
120        }
121    }