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 }