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 }