package alt.jiapi.reflect;
import java.lang.reflect.Modifier;
import java.util.List;
import alt.jiapi.file.ConstantPool;
import alt.jiapi.file.ConstantPool.ClassInfo;
import alt.jiapi.file.Field;
import alt.jiapi.file.Method;
import alt.jiapi.reflect.instruction.CPInstruction;
import alt.jiapi.reflect.instruction.FieldAccess;
import alt.jiapi.reflect.instruction.Invocation;
import alt.jiapi.reflect.instruction.Opcodes;
/**
* Class InstructionFactory.
*
* @author Mika Riekkinen
*/
public class InstructionFactory {
private ConstantPool cp;
public InstructionFactory() {
this.cp = new ConstantPool();
}
/**
*/
InstructionFactory(ConstantPool cp) {
this.cp = cp;
}
/**
* Parse bytecode and create a List of Instructions out
* of it.
*
* @return a List of Instructions.
* @exception
*/
List createInstructionList(byte[] byteCode) {
InstructionParser ip = new InstructionParser();
return ip.createInstructionList(byteCode, cp);
}
public Instruction pushConstant(float constant) {
short index = cp.addFloatInfo((int)constant).getEntryIndex();
byte[] bytes = createLDC(index);
return new CPInstruction(bytes, cp);//new Constant.StringConstant(bytes, index, clazz);
}
public Instruction pushConstant(int constant) {
switch(constant) {
case 0:
return new Instruction(new byte[] {Opcodes.ICONST_0});
case 1:
return new Instruction(new byte[] {Opcodes.ICONST_1});
case 2:
return new Instruction(new byte[] {Opcodes.ICONST_2});
case 3:
return new Instruction(new byte[] {Opcodes.ICONST_3});
case 4:
return new Instruction(new byte[] {Opcodes.ICONST_4});
case 5:
return new Instruction(new byte[] {Opcodes.ICONST_5});
}
short index = cp.addIntegerInfo(constant).getEntryIndex();
byte[] bytes = createLDC(index);
return new CPInstruction(bytes, cp);
}
public Instruction pushConstant(String constant) {
short index = cp.addStringInfo(constant).getEntryIndex();
byte[] bytes = createLDC(index);
return new CPInstruction(bytes, cp);//new Constant.StringConstant(bytes, index, clazz);
}
public Instruction newClass(String className) {
short index = cp.addClassInfo(className).getEntryIndex();
byte[] bytes = new byte[3];
bytes[0] = Opcodes.NEW;
bytes[1] = (byte) (index >> 8);
bytes[2] = (byte) (index & 255);
//return new Instruction(bytes);
return new CPInstruction(bytes, cp);
}
/**
* Creates a cast.
* It will create an InstructionList containing:
* <blockquote>
* <i>checkcast</i> #ref
* </blockquote>
*
* @param type type of the cast
* @return an InstructionList
*/
public Instruction cast(String type) {
ClassInfo ci = cp.addClassInfo(type);
short index = ci.getEntryIndex();
byte[] bytes = new byte[3];
bytes[0] = Opcodes.CHECKCAST;
bytes[1] = (byte) (index >> 8);
bytes[2] = (byte) (index & 255);
return new CPInstruction(bytes, cp);
}
public Instruction pushNull() {
return new Instruction(new byte[] { Opcodes.ACONST_NULL });
}
public Instruction pushThis() {
return new Instruction(new byte[] { Opcodes.ALOAD_0 });
}
public Instruction returnMethod(JiapiMethod jm) {
String retType = jm.getSignature().getReturnType();
Instruction ins = null;
if ("void".equals(retType)) {
ins = new Instruction(new byte[] { Opcodes.RETURN });
}
else if ("boolean".equals(retType) ||
"int".equals(retType) ||
"short".equals(retType) ||
"byte".equals(retType)) {
ins = new Instruction(new byte[] { Opcodes.IRETURN });
}
else if ("long".equals(retType)) {
ins = new Instruction(new byte[] { Opcodes.LRETURN });
}
else if ("float".equals(retType)) {
ins = new Instruction(new byte[] { Opcodes.FRETURN });
}
else if ("double".equals(retType)) {
ins = new Instruction(new byte[] { Opcodes.DRETURN });
}
else {
ins = new Instruction(new byte[] { Opcodes.ARETURN });
}
return ins;
}
public Instruction invoke(int mods, String className, String methodName,
Signature s) {
short index = ConstantPoolHelper.addMethodReference(cp, className,
methodName, s);
byte[] bytes;
if (Modifier.isStatic(mods)) {
bytes = new byte[3];
bytes[0] = Opcodes.INVOKESTATIC;
bytes[1] = (byte) (index >> 8);
bytes[2] = (byte) (index & 255);
}
else if (Modifier.isInterface(mods)) {
bytes = new byte[5];
bytes[0] = Opcodes.INVOKEINTERFACE;
bytes[1] = (byte) (index >> 8);
bytes[2] = (byte) (index & 255);
bytes[3] = (byte) s.getParameters().length;
bytes[4] = (byte) 0;
}
else if ("<init>".equals(methodName)) {
bytes = new byte[3];
bytes[0] = Opcodes.INVOKESPECIAL;
bytes[1] = (byte) (index >> 8);
bytes[2] = (byte) (index & 255);
}
else {
bytes = new byte[3];
bytes[0] = Opcodes.INVOKEVIRTUAL;
bytes[1] = (byte) (index >> 8);
bytes[2] = (byte) (index & 255);
}
Instruction instruction = new Invocation(bytes, cp);
return instruction;
}
public Instruction invoke(JiapiMethod jm) {
String[] params = jm.getParameterTypeNames();
short index = ConstantPoolHelper.addReference(cp, jm);
byte[] bytes;
int stackUsage = 1 + params.length; // object ref + params
if (Modifier.isStatic(jm.getModifiers())) {
bytes = new byte[3];
bytes[0] = Opcodes.INVOKESTATIC;
bytes[1] = (byte) (index >> 8);
bytes[2] = (byte) (index & 255);
}
else if (Modifier.isInterface(jm.getModifiers())) {
bytes = new byte[5];
bytes[0] = Opcodes.INVOKEINTERFACE;
bytes[1] = (byte) (index >> 8);
bytes[2] = (byte) (index & 255);
bytes[3] = (byte) params.length;
bytes[4] = (byte) 0;
}
else if ("<init>".equals(jm.getName())) {
bytes = new byte[3];
bytes[0] = Opcodes.INVOKESPECIAL;
bytes[1] = (byte) (index >> 8);
bytes[2] = (byte) (index & 255);
}
else {
bytes = new byte[3];
bytes[0] = Opcodes.INVOKEVIRTUAL;
bytes[1] = (byte) (index >> 8);
bytes[2] = (byte) (index & 255);
}
Instruction instruction = new Invocation(bytes, cp); // new Instruction(bytes);
return instruction;
}
private byte[] createLDC(short index) {
byte[] bytes;
if (index > 255) {
bytes = new byte[3];
bytes[0] = Opcodes.LDC_W;
bytes[1] = (byte) (index >> 8);
bytes[2] = (byte) (index & 255);
}
else {
bytes = new byte[2];
bytes[0] = Opcodes.LDC;
bytes[1] = (byte)index;
}
return bytes;
}
private byte[] createLDC_longDouble(short index) {
byte[] bytes = new byte[3];
bytes[0] = Opcodes.LDC2_W;
bytes[1] = (byte) (index >> 8);
bytes[2] = (byte) (index & 255);
return bytes;
}
public Instruction getField(int modifiers, String className,
String fieldName,
String fieldType) {
ConstantPool.ClassInfo ci =
cp.addClassInfo(className);
ConstantPool.FieldRefInfo fri =
cp.addFieldRefInfo(ci, fieldName, fieldType);
int index = fri.getEntryIndex();
byte[] bytes = new byte[3];
if (Modifier.isStatic(modifiers)) {
bytes[0] = Opcodes.GETSTATIC;
bytes[1] = (byte) (index >> 8);
bytes[2] = (byte) (index & 255);
}
else {
bytes[0] = Opcodes.GETFIELD;
bytes[1] = (byte) (index >> 8);
bytes[2] = (byte) (index & 255);
}
Instruction instruction = new FieldAccess(bytes, cp);
return instruction;
}
public Instruction getField(JiapiField field) {
ConstantPool cp =
field.getDeclaringClass().getConstantPool();
ConstantPool.ClassInfo ci =
cp.addClassInfo(field.getDeclaringClass().getName());
ConstantPool.FieldRefInfo fri =
cp.addFieldRefInfo(ci, field.getName(), field.getDescriptor());
int index = fri.getEntryIndex();
int modifiers = field.getModifiers();
byte[] bytes = new byte[3];
if (Modifier.isStatic(modifiers)) {
bytes[0] = Opcodes.GETSTATIC;
bytes[1] = (byte) (index >> 8);
bytes[2] = (byte) (index & 255);
}
else {
bytes[0] = Opcodes.GETFIELD;
bytes[1] = (byte) (index >> 8);
bytes[2] = (byte) (index & 255);
}
Instruction instruction = new FieldAccess(bytes, cp);
return instruction;
}
/**
* Sets a field reference to stack.
* It will create an InstructionList containing:
*
* <blockquote>
* <i>putstatic</i> #ref
* </blockquote>
*
* if the field is static field or:
*
* <blockquote>
* <i>putfield</i> #ref
* </blockquote>
*
* if the field is an instance field.
*
* @param field a JiapiField which will be set
* @return an InstructionList
*/
public Instruction setField(JiapiField field) {
// NOTE: We could return InstructionList
// and do a checkcast before putfield or pustatic
ConstantPool cp =
field.getDeclaringClass().getConstantPool();
ConstantPool.ClassInfo ci =
cp.addClassInfo(field.getDeclaringClass().getName());
ConstantPool.FieldRefInfo fri =
cp.addFieldRefInfo(ci, field.getName(), field.getDescriptor());
int index = fri.getEntryIndex();
int modifiers = field.getModifiers();
byte[] bytes = new byte[3];
if (Modifier.isStatic(modifiers)) {
bytes[0] = Opcodes.PUTSTATIC;
bytes[1] = (byte) (index >> 8);
bytes[2] = (byte) (index & 255);
}
else {
bytes[0] = Opcodes.PUTFIELD;
bytes[1] = (byte) (index >> 8);
bytes[2] = (byte) (index & 255);
}
Instruction instruction = new FieldAccess(bytes, cp);
return instruction;
}
public Instruction aload(int idx) {
// NOTE: <wide> support missing
switch(idx) {
case 0:
return new Instruction(new byte[] {Opcodes.ALOAD_0});
case 1:
return new Instruction(new byte[] {Opcodes.ALOAD_1});
case 2:
return new Instruction(new byte[] {Opcodes.ALOAD_2});
case 3:
return new Instruction(new byte[] {Opcodes.ALOAD_3});
default:
return new Instruction(new byte[] {Opcodes.ALOAD, (byte)idx});
}
}
public Instruction iload(int idx) {
// NOTE: <wide> support missing
switch(idx) {
case 0:
return new Instruction(new byte[] {Opcodes.ILOAD_0});
case 1:
return new Instruction(new byte[] {Opcodes.ILOAD_1});
case 2:
return new Instruction(new byte[] {Opcodes.ILOAD_2});
case 3:
return new Instruction(new byte[] {Opcodes.ILOAD_3});
default:
return new Instruction(new byte[] {Opcodes.ILOAD, (byte)idx});
}
}
public Instruction lload(int idx) {
// NOTE: <wide> support missing
switch(idx) {
case 0:
return new Instruction(new byte[] {Opcodes.LLOAD_0});
case 1:
return new Instruction(new byte[] {Opcodes.LLOAD_1});
case 2:
return new Instruction(new byte[] {Opcodes.LLOAD_2});
case 3:
return new Instruction(new byte[] {Opcodes.LLOAD_3});
default:
return new Instruction(new byte[] {Opcodes.LLOAD, (byte)idx});
}
}
public Instruction dload(int idx) {
// NOTE: <wide> support missing
switch(idx) {
case 0:
return new Instruction(new byte[] {Opcodes.DLOAD_0});
case 1:
return new Instruction(new byte[] {Opcodes.DLOAD_1});
case 2:
return new Instruction(new byte[] {Opcodes.DLOAD_2});
case 3:
return new Instruction(new byte[] {Opcodes.DLOAD_3});
default:
return new Instruction(new byte[] {Opcodes.DLOAD, (byte)idx});
}
}
public Instruction fload(int idx) {
// NOTE: <wide> support missing
switch(idx) {
case 0:
return new Instruction(new byte[] {Opcodes.FLOAD_0});
case 1:
return new Instruction(new byte[] {Opcodes.FLOAD_1});
case 2:
return new Instruction(new byte[] {Opcodes.FLOAD_2});
case 3:
return new Instruction(new byte[] {Opcodes.FLOAD_3});
default:
return new Instruction(new byte[] {Opcodes.FLOAD, (byte)idx});
}
}
public Instruction astore(int idx) {
// NOTE: <wide> support missing
switch(idx) {
case 0:
return new Instruction(new byte[] {Opcodes.ASTORE_0});
case 1:
return new Instruction(new byte[] {Opcodes.ASTORE_1});
case 2:
return new Instruction(new byte[] {Opcodes.ASTORE_2});
case 3:
return new Instruction(new byte[] {Opcodes.ASTORE_3});
default:
return new Instruction(new byte[] {Opcodes.ASTORE, (byte)idx});
}
}
public Instruction istore(int idx) {
// NOTE: <wide> support missing
switch(idx) {
case 0:
return new Instruction(new byte[] {Opcodes.ISTORE_0});
case 1:
return new Instruction(new byte[] {Opcodes.ISTORE_1});
case 2:
return new Instruction(new byte[] {Opcodes.ISTORE_2});
case 3:
return new Instruction(new byte[] {Opcodes.ISTORE_3});
default:
return new Instruction(new byte[] {Opcodes.ISTORE, (byte)idx});
}
}
public Instruction lstore(int idx) {
// NOTE: <wide> support missing
switch(idx) {
case 0:
return new Instruction(new byte[] {Opcodes.LSTORE_0});
case 1:
return new Instruction(new byte[] {Opcodes.LSTORE_1});
case 2:
return new Instruction(new byte[] {Opcodes.LSTORE_2});
case 3:
return new Instruction(new byte[] {Opcodes.LSTORE_3});
default:
return new Instruction(new byte[] {Opcodes.LSTORE, (byte)idx});
}
}
public Instruction fstore(int idx) {
// NOTE: <wide> support missing
switch(idx) {
case 0:
return new Instruction(new byte[] {Opcodes.FSTORE_0});
case 1:
return new Instruction(new byte[] {Opcodes.FSTORE_1});
case 2:
return new Instruction(new byte[] {Opcodes.FSTORE_2});
case 3:
return new Instruction(new byte[] {Opcodes.FSTORE_3});
default:
return new Instruction(new byte[] {Opcodes.FSTORE, (byte)idx});
}
}
public Instruction dstore(int idx) {
// NOTE: <wide> support missing
switch(idx) {
case 0:
return new Instruction(new byte[] {Opcodes.DSTORE_0});
case 1:
return new Instruction(new byte[] {Opcodes.DSTORE_1});
case 2:
return new Instruction(new byte[] {Opcodes.DSTORE_2});
case 3:
return new Instruction(new byte[] {Opcodes.DSTORE_3});
default:
return new Instruction(new byte[] {Opcodes.DSTORE, (byte)idx});
}
}
public Instruction aastore() {
return new Instruction(new byte[] {Opcodes.AASTORE});
}
public Instruction dup() {
return new Instruction(new byte[] {Opcodes.DUP});
}
public Instruction dup2() {
return new Instruction(new byte[] {Opcodes.DUP2});
}
public InstructionList newArray(String type, int size) {
InstructionList il = new InstructionList(cp);
il.add(pushConstant(size));
if (SignatureUtil.isPrimitive(type)) {
throw new RuntimeException("NOT implemented: new array for primitive types");
}
else {
ClassInfo ci = cp.addClassInfo("java.lang.Object");
short idx = ci.getEntryIndex();
il.add(new CPInstruction(new byte[] {Opcodes.ANEWARRAY,
(byte)(idx >> 8),
(byte)(idx& 0xff)},
cp));
}
return il;
}
// public Instruction objectArrayStore(int idx) {
// }
// /**
// * Swap the top two values on the operand stack.
// */
// public Instruction swap() {
// return new Instruction(new byte[] {Opcodes.SWAP});
// }
}