Data Types: Data types are handled in JVM by two ways - by having different opcodes for different datatypes, and by using descriptor (as explained in Manipulating Java Class Files with BCEL - Part One : Hello World!. In java, not all types support all operations. For example, there are no opcodes for addition of two byte values or two short values. This is understandable if you notice that all values are promoted to at least an int before any operation. A byte simply cannot exist in the operand stack. This saves the JVM from having to remember the number of bytes to pop from the operand stack for operation. Also, longs have different opcodes so that the JVM knows it has to pop 8 bytes instead of 4 when it is used.
Where to Find Instructions:
All details of all instructions can be found here.
These are alphabetically ordered.
Speaking of operand stack, there is one per thread per method. What is per thread per method? Well each thread has a stack called a method invocation stack (or you may call it by any other sweeter name). Each member of this stack is a frame that stores all local variables including the method parameters. If a method is invoked from another, a new frame is added, whenever a method returns or throws an exception, the corresponding frame is popped and discarded. Each frame is also associated with an operand stack (and instruction pointers etc.).
Compound Instructions: Well they do not really have that official name, but I would prefer to call them that way. JVM opcodes are designed for optimization. Take for example iload 0. This pushes the value of local variable of type int and number 0 into the stack. However, the JVM has another opcode iload_0, which does the same thing, but does not have an operand effectively saving code space. Both of these are correct. However, with BCEL, you do not have to worry about these, as BCEL automatically converts an iload 0 to iload_0. BCEL does not even have a class called ILOAD_0.
Local Variables: The local variables are refered to in the JVM by index numbers instead of there names. First the parameters of the method are assigned indices, starting from 0 and in the order they appear in the method parameter list. More variables can be created by simply storing value into new indices with istore, astore etc. depending on the datatype of the variable.
Method Invocation: There are four kinds of method invocations - InvokeVirtual, InvokeStatic, InvokeInterface and InvokeSpecial. InvokeVirtual is used to call a normal method. JVM automatically handles overriding. Note however that overloading is resolved during compilation. A sister of this is InvokeInterface. It does the same thing for interface methods. InvokeStatic is used for static methods, and lastly, InvokeSpecial is used for constructors.
Jumps: Jumps are used for flow control like conditional execution (if-else) and loops (while, for, do-while etc.). Jumps can be either unconditional (goto) or conditional (if).
The goto statement simply instructs to jump to a given instruction. If statements are of mainly of two types - one that compares one value with another and two, that compares a value with 0. For example, the instruction if_acmp compares to object reference values. if_icmp<cond> instructions compare two integer values. The if<cond> instructions compare an integer value with 0.
If-Else: If else can be implemented using conditional jumps. The following program generates a class that takes a value in it's command line arguments, and compares it with 5.
package com.geekyarticles.bcel;
import java.io.IOException;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.AALOAD;
import org.apache.bcel.generic.ALOAD;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.BIPUSH;
import org.apache.bcel.generic.BranchHandle;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.GETSTATIC;
import org.apache.bcel.generic.GOTO;
import org.apache.bcel.generic.IF_ICMPGE;
import org.apache.bcel.generic.INVOKESTATIC;
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.LDC;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.RETURN;
import org.apache.bcel.generic.Type;
public class SimpleIf {
public static void main(String[] args) {
//Create a ClassGen for our brand new class.
ClassGen classGen=new ClassGen("com.geekyarticles.bcel.SyntheticClass", "java.lang.Object", "SyntheticClass.java", Constants.ACC_PUBLIC, null);
//Get a reference to the constant pool of the class. This will be modified as we add methods, fields etc. Note that it already constains
//a few constants.
ConstantPoolGen constantPoolGen=classGen.getConstantPool();
//The list of instructions for a method.
InstructionList instructionList=new InstructionList();
//Add the appropriate instructions.
//Get the reference to static field out in class java.lang.System.
instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new ALOAD(0));//the argument of the main function
instructionList.append(new BIPUSH((byte)0));//Push 0.
instructionList.append(new AALOAD());//Got value of the variable as a String;
instructionList.append(new INVOKESTATIC(constantPoolGen.addMethodref("java.lang.Integer", "parseInt", "(Ljava/lang/String;)I")));//Now we got the value as int
instructionList.append(new BIPUSH((byte)5));
BranchHandle ifHandle=instructionList.append(new IF_ICMPGE(null)); // We do not yet know the position of the target. Will set it later.
//Push the String to print
instructionList.append(new LDC(constantPoolGen.addString("Less than five")));
//Invoke println. we already have the object ref in the stack
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));
//Not to fall through the else part also. jump to the end
BranchHandle gotoHandle=instructionList.append(new GOTO(null));// We do not yet know the position of the target. Will set it later.
//Push the String to print. This would be the target of the if_icmpge
InstructionHandle matchHandle=instructionList.append(new LDC(constantPoolGen.addString("Greater than or equal to five")));
//Invoke println. we already have the object ref in the stack
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));
//Return from the method. This would be the target of the goto.
InstructionHandle returnHandle=instructionList.append(new RETURN());
ifHandle.setTarget(matchHandle);
gotoHandle.setTarget(returnHandle);
MethodGen methodGen=new MethodGen(Constants.ACC_PUBLIC|Constants.ACC_STATIC, Type.VOID, new Type[]{new ArrayType(Type.STRING, 1)}, new String[]{"args"}, "main", "com.geekyarticles.bcel.SyntheticClass", instructionList, constantPoolGen);
methodGen.setMaxLocals();//Calculate the maximum number of local variables.
methodGen.setMaxStack();//Very important: must calculate the maximum size of the stack.
classGen.addMethod(methodGen.getMethod()); //Add the method to the class
//Print a few things.
System.out.println("********Constant Pool**********");
System.out.println(constantPoolGen.getFinalConstantPool());
System.out.println("********Method**********");
System.out.println(methodGen);
System.out.println("********Instruction List**********");
System.out.println(instructionList);
//Now generate the class
JavaClass javaClass=classGen.getJavaClass();
try {
//Write the class byte code into a file
javaClass.dump("com/geekyarticles/bcel/SyntheticClass.class");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//That's it.
}
}
import java.io.IOException;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.AALOAD;
import org.apache.bcel.generic.ALOAD;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.BIPUSH;
import org.apache.bcel.generic.BranchHandle;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.GETSTATIC;
import org.apache.bcel.generic.GOTO;
import org.apache.bcel.generic.IF_ICMPGE;
import org.apache.bcel.generic.INVOKESTATIC;
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.LDC;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.RETURN;
import org.apache.bcel.generic.Type;
public class SimpleIf {
public static void main(String[] args) {
//Create a ClassGen for our brand new class.
ClassGen classGen=new ClassGen("com.geekyarticles.bcel.SyntheticClass", "java.lang.Object", "SyntheticClass.java", Constants.ACC_PUBLIC, null);
//Get a reference to the constant pool of the class. This will be modified as we add methods, fields etc. Note that it already constains
//a few constants.
ConstantPoolGen constantPoolGen=classGen.getConstantPool();
//The list of instructions for a method.
InstructionList instructionList=new InstructionList();
//Add the appropriate instructions.
//Get the reference to static field out in class java.lang.System.
instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new ALOAD(0));//the argument of the main function
instructionList.append(new BIPUSH((byte)0));//Push 0.
instructionList.append(new AALOAD());//Got value of the variable as a String;
instructionList.append(new INVOKESTATIC(constantPoolGen.addMethodref("java.lang.Integer", "parseInt", "(Ljava/lang/String;)I")));//Now we got the value as int
instructionList.append(new BIPUSH((byte)5));
BranchHandle ifHandle=instructionList.append(new IF_ICMPGE(null)); // We do not yet know the position of the target. Will set it later.
//Push the String to print
instructionList.append(new LDC(constantPoolGen.addString("Less than five")));
//Invoke println. we already have the object ref in the stack
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));
//Not to fall through the else part also. jump to the end
BranchHandle gotoHandle=instructionList.append(new GOTO(null));// We do not yet know the position of the target. Will set it later.
//Push the String to print. This would be the target of the if_icmpge
InstructionHandle matchHandle=instructionList.append(new LDC(constantPoolGen.addString("Greater than or equal to five")));
//Invoke println. we already have the object ref in the stack
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));
//Return from the method. This would be the target of the goto.
InstructionHandle returnHandle=instructionList.append(new RETURN());
ifHandle.setTarget(matchHandle);
gotoHandle.setTarget(returnHandle);
MethodGen methodGen=new MethodGen(Constants.ACC_PUBLIC|Constants.ACC_STATIC, Type.VOID, new Type[]{new ArrayType(Type.STRING, 1)}, new String[]{"args"}, "main", "com.geekyarticles.bcel.SyntheticClass", instructionList, constantPoolGen);
methodGen.setMaxLocals();//Calculate the maximum number of local variables.
methodGen.setMaxStack();//Very important: must calculate the maximum size of the stack.
classGen.addMethod(methodGen.getMethod()); //Add the method to the class
//Print a few things.
System.out.println("********Constant Pool**********");
System.out.println(constantPoolGen.getFinalConstantPool());
System.out.println("********Method**********");
System.out.println(methodGen);
System.out.println("********Instruction List**********");
System.out.println(instructionList);
//Now generate the class
JavaClass javaClass=classGen.getJavaClass();
try {
//Write the class byte code into a file
javaClass.dump("com/geekyarticles/bcel/SyntheticClass.class");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//That's it.
}
}
Notice that the jump instructions take null as a parameter. This is because it is still not known at that point, the correct instruction to jump to. To handle this, BCEL jump instructions are subclasses of BranchInstruction, and adding those to an instruction list returns a BranchHandle. We can set the target of this handle to any other InstructionHandle, which is returned by adding any other instruction to an InstructionList.
The else part normally comes before the if in the bytecode. This is because a jump occurs when the condition is true, which is the if part.
Loop: Loop is very similar to an an if-statement, the only difference is jumping to an instruction that the JVM has already executed. The following example creates a program that takes an integer (let's say n) as an argument and prints 0 to (n-1)
package com.geekyarticles.bcel;
import java.io.IOException;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.AALOAD;
import org.apache.bcel.generic.ALOAD;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.BIPUSH;
import org.apache.bcel.generic.BranchHandle;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.DUP;
import org.apache.bcel.generic.GETSTATIC;
import org.apache.bcel.generic.GOTO;
import org.apache.bcel.generic.IF_ICMPLT;
import org.apache.bcel.generic.IINC;
import org.apache.bcel.generic.ILOAD;
import org.apache.bcel.generic.INVOKESTATIC;
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.ISTORE;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.RETURN;
import org.apache.bcel.generic.Type;
public class SimpleWhile {
/**
* @param args
*/
public static void main(String[] args) {
//Create a ClassGen for our brand new class.
ClassGen classGen=new ClassGen("com.geekyarticles.bcel.SyntheticClass", "java.lang.Object", "SyntheticClass.java", Constants.ACC_PUBLIC, null);
//Get a reference to the constant pool of the class. This will be modified as we add methods, fields etc. Note that it already constains
//a few constants.
ConstantPoolGen constantPoolGen=classGen.getConstantPool();
//The list of instructions for a method.
InstructionList instructionList=new InstructionList();
//Add the appropriate instructions.
instructionList.append(new ALOAD(0));//the argument of the main function
instructionList.append(new BIPUSH((byte)0));//Push 0.
instructionList.append(new DUP());//A simple trick. Just duplicates the top of the stack.
instructionList.append(new ISTORE(1));//local variable 0 is the argument of the main method. So we create a new local variable 1. It will work as loop counter
instructionList.append(new AALOAD());//Got value of the variable as a String;
instructionList.append(new INVOKESTATIC(constantPoolGen.addMethodref("java.lang.Integer", "parseInt", "(Ljava/lang/String;)I")));//Now we got the value as int
instructionList.append(new ISTORE(2));// The limit to the loop counter.
InstructionHandle loopStart=instructionList.append(new ILOAD(1));
instructionList.append(new ILOAD(2));
BranchHandle ifCheck=instructionList.append(new IF_ICMPLT(null));//If less go inside the loop;
//This is when the loop ends
BranchHandle gotoJump=instructionList.append(new GOTO(null));//Goto the return
//Print the loop counter
//Get the reference to static field out in class java.lang.System.
InstructionHandle insideLoop=instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new ILOAD(1));
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(I)V")));
//
// //Increment the counter, the variable number is 1.
instructionList.append(new IINC(1, 1));
//
instructionList.append(new GOTO(loopStart));//In this case, we already know where to go.
InstructionHandle returnHandle=instructionList.append(new RETURN());
//Set the handles
ifCheck.setTarget(insideLoop);
gotoJump.setTarget(returnHandle);
//The usual method generation
MethodGen methodGen=new MethodGen(Constants.ACC_PUBLIC|Constants.ACC_STATIC, Type.VOID, new Type[]{new ArrayType(Type.STRING, 1)}, new String[]{"args"}, "main", "com.geekyarticles.bcel.SyntheticClass", instructionList, constantPoolGen);
methodGen.setMaxLocals();//Calculate the maximum number of local variables.
methodGen.setMaxStack();//Very important: must calculate the maximum size of the stack.
classGen.addMethod(methodGen.getMethod()); //Add the method to the class
//Print a few things.
System.out.println("********Constant Pool**********");
System.out.println(constantPoolGen.getFinalConstantPool());
System.out.println("********Method**********");
System.out.println(methodGen);
System.out.println("********Instruction List**********");
System.out.println(instructionList);
//Now generate the class
JavaClass javaClass=classGen.getJavaClass();
try {
//Write the class byte code into a file
javaClass.dump("com/geekyarticles/bcel/SyntheticClass.class");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//That's it.
}
}
import java.io.IOException;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.AALOAD;
import org.apache.bcel.generic.ALOAD;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.BIPUSH;
import org.apache.bcel.generic.BranchHandle;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.DUP;
import org.apache.bcel.generic.GETSTATIC;
import org.apache.bcel.generic.GOTO;
import org.apache.bcel.generic.IF_ICMPLT;
import org.apache.bcel.generic.IINC;
import org.apache.bcel.generic.ILOAD;
import org.apache.bcel.generic.INVOKESTATIC;
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.ISTORE;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.RETURN;
import org.apache.bcel.generic.Type;
public class SimpleWhile {
/**
* @param args
*/
public static void main(String[] args) {
//Create a ClassGen for our brand new class.
ClassGen classGen=new ClassGen("com.geekyarticles.bcel.SyntheticClass", "java.lang.Object", "SyntheticClass.java", Constants.ACC_PUBLIC, null);
//Get a reference to the constant pool of the class. This will be modified as we add methods, fields etc. Note that it already constains
//a few constants.
ConstantPoolGen constantPoolGen=classGen.getConstantPool();
//The list of instructions for a method.
InstructionList instructionList=new InstructionList();
//Add the appropriate instructions.
instructionList.append(new ALOAD(0));//the argument of the main function
instructionList.append(new BIPUSH((byte)0));//Push 0.
instructionList.append(new DUP());//A simple trick. Just duplicates the top of the stack.
instructionList.append(new ISTORE(1));//local variable 0 is the argument of the main method. So we create a new local variable 1. It will work as loop counter
instructionList.append(new AALOAD());//Got value of the variable as a String;
instructionList.append(new INVOKESTATIC(constantPoolGen.addMethodref("java.lang.Integer", "parseInt", "(Ljava/lang/String;)I")));//Now we got the value as int
instructionList.append(new ISTORE(2));// The limit to the loop counter.
InstructionHandle loopStart=instructionList.append(new ILOAD(1));
instructionList.append(new ILOAD(2));
BranchHandle ifCheck=instructionList.append(new IF_ICMPLT(null));//If less go inside the loop;
//This is when the loop ends
BranchHandle gotoJump=instructionList.append(new GOTO(null));//Goto the return
//Print the loop counter
//Get the reference to static field out in class java.lang.System.
InstructionHandle insideLoop=instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new ILOAD(1));
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(I)V")));
//
// //Increment the counter, the variable number is 1.
instructionList.append(new IINC(1, 1));
//
instructionList.append(new GOTO(loopStart));//In this case, we already know where to go.
InstructionHandle returnHandle=instructionList.append(new RETURN());
//Set the handles
ifCheck.setTarget(insideLoop);
gotoJump.setTarget(returnHandle);
//The usual method generation
MethodGen methodGen=new MethodGen(Constants.ACC_PUBLIC|Constants.ACC_STATIC, Type.VOID, new Type[]{new ArrayType(Type.STRING, 1)}, new String[]{"args"}, "main", "com.geekyarticles.bcel.SyntheticClass", instructionList, constantPoolGen);
methodGen.setMaxLocals();//Calculate the maximum number of local variables.
methodGen.setMaxStack();//Very important: must calculate the maximum size of the stack.
classGen.addMethod(methodGen.getMethod()); //Add the method to the class
//Print a few things.
System.out.println("********Constant Pool**********");
System.out.println(constantPoolGen.getFinalConstantPool());
System.out.println("********Method**********");
System.out.println(methodGen);
System.out.println("********Instruction List**********");
System.out.println(instructionList);
//Now generate the class
JavaClass javaClass=classGen.getJavaClass();
try {
//Write the class byte code into a file
javaClass.dump("com/geekyarticles/bcel/SyntheticClass.class");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//That's it.
}
}
Switch Statements: Switch instructions are of two kinds - Table Switch and Lookup Switch. The difference is that in table switch uses a range for valid values, whereas a lookup switch uses a lookup table for valid values. Both use a lookup table for instruction to jump to in case of a match. Since table switch uses a range for valid values, jump must be specified for all values in that range, which is not the case for lookup switch. Note that a compiler is free to choose a table switch even when the java source code uses sparse values. The compiler in that case provides the jump location to the same location as the default location in case a value in the range does not appear in the source. Its therefore all about optimization. In general, table switches are faster, but takes up lot of space in the code, whereas lookup switches are slower, but take up much less space.
The following example shows two ways to compile the program SwitchSource.java. (The BCEL program output has a different classname (SyntheticClass) for regularity). The tableswitch version is SimpleTableSwitch.java and the lookupswitch version is SimpleLookupSwitch.java. Note that for a BCEL programmer, the only difference is that in case of lookupswitch, the jump location for value 3 need not be provided. [Click on a tab to view code]
package com.geekyarticles.bcel;
public class SwitchSource {
public static void main(String[] args) {
String input=args[0];
int val=Integer.parseInt(input);
switch(val){
case 1:
System.out.println("One");
break;
case 2:
System.out.println("Two");
break;
case 4:
System.out.println("Four");
break;
default:
System.out.println("Other");
}
}
}
public class SwitchSource {
public static void main(String[] args) {
String input=args[0];
int val=Integer.parseInt(input);
switch(val){
case 1:
System.out.println("One");
break;
case 2:
System.out.println("Two");
break;
case 4:
System.out.println("Four");
break;
default:
System.out.println("Other");
}
}
}
package com.geekyarticles.bcel;
import java.io.IOException;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.AALOAD;
import org.apache.bcel.generic.ALOAD;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.BIPUSH;
import org.apache.bcel.generic.BranchHandle;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.GETSTATIC;
import org.apache.bcel.generic.GOTO;
import org.apache.bcel.generic.INVOKESTATIC;
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.LDC;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.RETURN;
import org.apache.bcel.generic.TABLESWITCH;
import org.apache.bcel.generic.Type;
public class SimpleTableSwitch {
public static void main(String[] args) {
//Create a ClassGen for our brand new class.
ClassGen classGen=new ClassGen("com.geekyarticles.bcel.SyntheticClass", "java.lang.Object", "SyntheticClass.java", Constants.ACC_PUBLIC, null);
//Get a reference to the constant pool of the class. This will be modified as we add methods, fields etc. Note that it already constains
//a few constants.
ConstantPoolGen constantPoolGen=classGen.getConstantPool();
//The list of instructions for a method.
InstructionList instructionList=new InstructionList();
//Add the appropriate instructions.
instructionList.append(new ALOAD(0));//the argument of the main function
instructionList.append(new BIPUSH((byte)0));//Push 0.
instructionList.append(new AALOAD());//Got value of the variable as a String;
instructionList.append(new INVOKESTATIC(constantPoolGen.addMethodref("java.lang.Integer", "parseInt", "(Ljava/lang/String;)I")));//Now we got the value as int
InstructionHandle case1=instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new LDC(constantPoolGen.addString("One")));
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));//Print
BranchHandle goto1=instructionList.append(new GOTO(null));
InstructionHandle case2=instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new LDC(constantPoolGen.addString("Two")));
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));//Print
BranchHandle goto2=instructionList.append(new GOTO(null));
InstructionHandle case4=instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new LDC(constantPoolGen.addString("Four")));
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));//Print
BranchHandle goto4=instructionList.append(new GOTO(null));
InstructionHandle caseDefault=instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new LDC(constantPoolGen.addString("Other")));
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));//Print
BranchHandle gotoDefault=instructionList.append(new GOTO(null));
InstructionHandle ret=instructionList.append(new RETURN());
//We did not know the Instructions earlier. So the switch statement must be inserted
instructionList.insert(case1,new TABLESWITCH(new int [] {1,2,3,4}, new InstructionHandle[]{case1,case2,caseDefault, case4}, caseDefault));
goto1.setTarget(ret);
goto2.setTarget(ret);
goto4.setTarget(ret);
gotoDefault.setTarget(ret);
//Now generate the method
MethodGen methodGen=new MethodGen(Constants.ACC_PUBLIC|Constants.ACC_STATIC, Type.VOID, new Type[]{new ArrayType(Type.STRING, 1)}, new String[]{"args"}, "main", "com.geekyarticles.bcel.SyntheticClass", instructionList, constantPoolGen);
methodGen.setMaxLocals();//Calculate the maximum number of local variables.
methodGen.setMaxStack();//Very important: must calculate the maximum size of the stack.
classGen.addMethod(methodGen.getMethod()); //Add the method to the class
//Print a few things.
System.out.println("********Constant Pool**********");
System.out.println(constantPoolGen.getFinalConstantPool());
System.out.println("********Method**********");
System.out.println(methodGen);
System.out.println("********Instruction List**********");
System.out.println(instructionList);
//Now generate the class
JavaClass javaClass=classGen.getJavaClass();
try {
//Write the class byte code into a file
javaClass.dump("com/geekyarticles/bcel/SyntheticClass.class");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//That's it.
}
}
import java.io.IOException;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.AALOAD;
import org.apache.bcel.generic.ALOAD;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.BIPUSH;
import org.apache.bcel.generic.BranchHandle;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.GETSTATIC;
import org.apache.bcel.generic.GOTO;
import org.apache.bcel.generic.INVOKESTATIC;
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.LDC;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.RETURN;
import org.apache.bcel.generic.TABLESWITCH;
import org.apache.bcel.generic.Type;
public class SimpleTableSwitch {
public static void main(String[] args) {
//Create a ClassGen for our brand new class.
ClassGen classGen=new ClassGen("com.geekyarticles.bcel.SyntheticClass", "java.lang.Object", "SyntheticClass.java", Constants.ACC_PUBLIC, null);
//Get a reference to the constant pool of the class. This will be modified as we add methods, fields etc. Note that it already constains
//a few constants.
ConstantPoolGen constantPoolGen=classGen.getConstantPool();
//The list of instructions for a method.
InstructionList instructionList=new InstructionList();
//Add the appropriate instructions.
instructionList.append(new ALOAD(0));//the argument of the main function
instructionList.append(new BIPUSH((byte)0));//Push 0.
instructionList.append(new AALOAD());//Got value of the variable as a String;
instructionList.append(new INVOKESTATIC(constantPoolGen.addMethodref("java.lang.Integer", "parseInt", "(Ljava/lang/String;)I")));//Now we got the value as int
InstructionHandle case1=instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new LDC(constantPoolGen.addString("One")));
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));//Print
BranchHandle goto1=instructionList.append(new GOTO(null));
InstructionHandle case2=instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new LDC(constantPoolGen.addString("Two")));
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));//Print
BranchHandle goto2=instructionList.append(new GOTO(null));
InstructionHandle case4=instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new LDC(constantPoolGen.addString("Four")));
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));//Print
BranchHandle goto4=instructionList.append(new GOTO(null));
InstructionHandle caseDefault=instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new LDC(constantPoolGen.addString("Other")));
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));//Print
BranchHandle gotoDefault=instructionList.append(new GOTO(null));
InstructionHandle ret=instructionList.append(new RETURN());
//We did not know the Instructions earlier. So the switch statement must be inserted
instructionList.insert(case1,new TABLESWITCH(new int [] {1,2,3,4}, new InstructionHandle[]{case1,case2,caseDefault, case4}, caseDefault));
goto1.setTarget(ret);
goto2.setTarget(ret);
goto4.setTarget(ret);
gotoDefault.setTarget(ret);
//Now generate the method
MethodGen methodGen=new MethodGen(Constants.ACC_PUBLIC|Constants.ACC_STATIC, Type.VOID, new Type[]{new ArrayType(Type.STRING, 1)}, new String[]{"args"}, "main", "com.geekyarticles.bcel.SyntheticClass", instructionList, constantPoolGen);
methodGen.setMaxLocals();//Calculate the maximum number of local variables.
methodGen.setMaxStack();//Very important: must calculate the maximum size of the stack.
classGen.addMethod(methodGen.getMethod()); //Add the method to the class
//Print a few things.
System.out.println("********Constant Pool**********");
System.out.println(constantPoolGen.getFinalConstantPool());
System.out.println("********Method**********");
System.out.println(methodGen);
System.out.println("********Instruction List**********");
System.out.println(instructionList);
//Now generate the class
JavaClass javaClass=classGen.getJavaClass();
try {
//Write the class byte code into a file
javaClass.dump("com/geekyarticles/bcel/SyntheticClass.class");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//That's it.
}
}
package com.geekyarticles.bcel;
import java.io.IOException;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.AALOAD;
import org.apache.bcel.generic.ALOAD;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.BIPUSH;
import org.apache.bcel.generic.BranchHandle;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.GETSTATIC;
import org.apache.bcel.generic.GOTO;
import org.apache.bcel.generic.INVOKESTATIC;
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.LDC;
import org.apache.bcel.generic.LOOKUPSWITCH;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.RETURN;
import org.apache.bcel.generic.Type;
public class SimpleLookupSwitch {
public static void main(String[] args) {
//Create a ClassGen for our brand new class.
ClassGen classGen=new ClassGen("com.geekyarticles.bcel.SyntheticClass", "java.lang.Object", "SyntheticClass.java", Constants.ACC_PUBLIC, null);
//Get a reference to the constant pool of the class. This will be modified as we add methods, fields etc. Note that it already constains
//a few constants.
ConstantPoolGen constantPoolGen=classGen.getConstantPool();
//The list of instructions for a method.
InstructionList instructionList=new InstructionList();
//Add the appropriate instructions.
instructionList.append(new ALOAD(0));//the argument of the main function
instructionList.append(new BIPUSH((byte)0));//Push 0.
instructionList.append(new AALOAD());//Got value of the variable as a String;
instructionList.append(new INVOKESTATIC(constantPoolGen.addMethodref("java.lang.Integer", "parseInt", "(Ljava/lang/String;)I")));//Now we got the value as int
InstructionHandle case1=instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new LDC(constantPoolGen.addString("One")));
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));//Print
BranchHandle goto1=instructionList.append(new GOTO(null));
InstructionHandle case2=instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new LDC(constantPoolGen.addString("Two")));
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));//Print
BranchHandle goto2=instructionList.append(new GOTO(null));
InstructionHandle case4=instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new LDC(constantPoolGen.addString("Four")));
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));//Print
BranchHandle goto4=instructionList.append(new GOTO(null));
InstructionHandle caseDefault=instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new LDC(constantPoolGen.addString("Other")));
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));//Print
BranchHandle gotoDefault=instructionList.append(new GOTO(null));
InstructionHandle ret=instructionList.append(new RETURN());
//We did not know the Instructions earlier. So the switch statement must be inserted
instructionList.insert(case1,new LOOKUPSWITCH(new int [] {1,2,4}, new InstructionHandle[]{case1, case2, case4}, caseDefault));
goto1.setTarget(ret);
goto2.setTarget(ret);
goto4.setTarget(ret);
gotoDefault.setTarget(ret);
//Now generate the method
MethodGen methodGen=new MethodGen(Constants.ACC_PUBLIC|Constants.ACC_STATIC, Type.VOID, new Type[]{new ArrayType(Type.STRING, 1)}, new String[]{"args"}, "main", "com.geekyarticles.bcel.SyntheticClass", instructionList, constantPoolGen);
methodGen.setMaxLocals();//Calculate the maximum number of local variables.
methodGen.setMaxStack();//Very important: must calculate the maximum size of the stack.
classGen.addMethod(methodGen.getMethod()); //Add the method to the class
//Print a few things.
System.out.println("********Constant Pool**********");
System.out.println(constantPoolGen.getFinalConstantPool());
System.out.println("********Method**********");
System.out.println(methodGen);
System.out.println("********Instruction List**********");
System.out.println(instructionList);
//Now generate the class
JavaClass javaClass=classGen.getJavaClass();
try {
//Write the class byte code into a file
javaClass.dump("com/geekyarticles/bcel/SyntheticClass.class");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//That's it.
}
}
import java.io.IOException;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.AALOAD;
import org.apache.bcel.generic.ALOAD;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.BIPUSH;
import org.apache.bcel.generic.BranchHandle;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.GETSTATIC;
import org.apache.bcel.generic.GOTO;
import org.apache.bcel.generic.INVOKESTATIC;
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.LDC;
import org.apache.bcel.generic.LOOKUPSWITCH;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.RETURN;
import org.apache.bcel.generic.Type;
public class SimpleLookupSwitch {
public static void main(String[] args) {
//Create a ClassGen for our brand new class.
ClassGen classGen=new ClassGen("com.geekyarticles.bcel.SyntheticClass", "java.lang.Object", "SyntheticClass.java", Constants.ACC_PUBLIC, null);
//Get a reference to the constant pool of the class. This will be modified as we add methods, fields etc. Note that it already constains
//a few constants.
ConstantPoolGen constantPoolGen=classGen.getConstantPool();
//The list of instructions for a method.
InstructionList instructionList=new InstructionList();
//Add the appropriate instructions.
instructionList.append(new ALOAD(0));//the argument of the main function
instructionList.append(new BIPUSH((byte)0));//Push 0.
instructionList.append(new AALOAD());//Got value of the variable as a String;
instructionList.append(new INVOKESTATIC(constantPoolGen.addMethodref("java.lang.Integer", "parseInt", "(Ljava/lang/String;)I")));//Now we got the value as int
InstructionHandle case1=instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new LDC(constantPoolGen.addString("One")));
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));//Print
BranchHandle goto1=instructionList.append(new GOTO(null));
InstructionHandle case2=instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new LDC(constantPoolGen.addString("Two")));
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));//Print
BranchHandle goto2=instructionList.append(new GOTO(null));
InstructionHandle case4=instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new LDC(constantPoolGen.addString("Four")));
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));//Print
BranchHandle goto4=instructionList.append(new GOTO(null));
InstructionHandle caseDefault=instructionList.append(new GETSTATIC(constantPoolGen.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;")));
instructionList.append(new LDC(constantPoolGen.addString("Other")));
instructionList.append(new INVOKEVIRTUAL(constantPoolGen.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V")));//Print
BranchHandle gotoDefault=instructionList.append(new GOTO(null));
InstructionHandle ret=instructionList.append(new RETURN());
//We did not know the Instructions earlier. So the switch statement must be inserted
instructionList.insert(case1,new LOOKUPSWITCH(new int [] {1,2,4}, new InstructionHandle[]{case1, case2, case4}, caseDefault));
goto1.setTarget(ret);
goto2.setTarget(ret);
goto4.setTarget(ret);
gotoDefault.setTarget(ret);
//Now generate the method
MethodGen methodGen=new MethodGen(Constants.ACC_PUBLIC|Constants.ACC_STATIC, Type.VOID, new Type[]{new ArrayType(Type.STRING, 1)}, new String[]{"args"}, "main", "com.geekyarticles.bcel.SyntheticClass", instructionList, constantPoolGen);
methodGen.setMaxLocals();//Calculate the maximum number of local variables.
methodGen.setMaxStack();//Very important: must calculate the maximum size of the stack.
classGen.addMethod(methodGen.getMethod()); //Add the method to the class
//Print a few things.
System.out.println("********Constant Pool**********");
System.out.println(constantPoolGen.getFinalConstantPool());
System.out.println("********Method**********");
System.out.println(methodGen);
System.out.println("********Instruction List**********");
System.out.println(instructionList);
//Now generate the class
JavaClass javaClass=classGen.getJavaClass();
try {
//Write the class byte code into a file
javaClass.dump("com/geekyarticles/bcel/SyntheticClass.class");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//That's it.
}
}
Now you should be able to run like java com.geekyarticles.bcel.SyntheticClass 4, and it should output Four.
No comments:
Post a Comment