Lecture 26
COP5556 Progamming Language Principes
Overview of the Java Virtual Machine
References
The Java Virtual Machine Specification
See the module “ASM Bytecode Manipulation Resources” on elearning.
Software
ASM framework
see module on elearning for links
Java compilers start with Java source code and create class files containing Java byte code
When a Java program is executed, the byte code in the class file is
interpreted
or compiled (at load or run time)
or some mixture of the two
Other language also compile to java byte code
Advantages of this approach
architecture independent
stack-based architecture
easier code generation target than register-based
Can use Java to implement some of the runtime support
several public domain tools to create class files
ASM
A java class file is defined as a stream of 8-bit bytes consisting of a single ClassFile structure (where the structure is as in the C programming language):
Tools will take care of most of the details of constructing a classfile, but it is useful to understand the overall structure.
Overview of the class file format
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
These values are fixed. Magic=0xCAFEBABE and indicates that this is a Java class file, the others indicate the classfile version
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
The constant pool contains all the constants in the program. This includes field, method, and interface names, string literals, etc.
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
Indicates if the class is public, final, (super), interface, abstract
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
Indexes for the constant pool entries for this class and its superclass
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
Interfaces that are implemented by this class, also as indexes into constant pool
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
Number of fields, each field_info item provides complete information about a field
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
Number of methods, each method_info item provides complete information about a method, including its byte code, if any
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
attributes are optional and provide descriptive information such as information about the source file, line numbers, deprecated, etc.
The Java virtual machine is stack based.
There are no operand registers—loads and stores are between the stack and memory
arithmetic operations get their operands from the stack, and leave their results on the stack.
A Java virtual machine instruction consists of a
one-byte opcode specifying the operation to be performed
the opcode is followed by zero or more operands supplying arguments or data that are used by the operation.
Many instructions have no operands and consist only of an opcode. (Values read and consumed from the stack are not considered operands—an operand is part of the instruction.)
Instruction Summary
Ignoring some details (such as exceptions), the inner loop of a Java virtual machine interpreter is essentially
do
{ fetch next opcode;
if (this instruction has operands)
{ fetch the operands; }
execute the action for the opcode;
} while (there are more instructions);
The number and size of the operands are determined by the opcode, so once the opcode has been read, the number and size of operands are known.
Variables in the JVM are typed.
Types of variables and method signatures are denoted using a specific syntax.
Primitive types: each has a one-letter type code.
I (int), Z(boolean), V(void), D(double), etc.
Class names used as types:
‘L’
followed by the fully qualified name
where parts of the name are separated by ‘/’ , not ‘.’
terminated with ‘;’.
Arrays: preceding the element type with a ‘[‘.
Types
int I
boolean Z
void V
String Ljava/lang/String;
String[] [Ljava/lang/String;
ArrayList Ljava/util/ArrayList;
Method signatures are indicated by
‘(‘,
followed by
list of the types of parameters of the method
these are NOT separated by white space or punctuation
followed by a ‘)’
followed by the return type.
Method signature as expressed in Java JVM notation
void main(String[] args) ([Ljava/lang/String;)V
int f(int y, boolean b) (IZ)I
String g(int x, int y,
String s) (IILjava/lang/String;)Ljava/lang/String;
boolean a(
HashMap m1,
HashMap m2) (Ljava/util/HashMap;Ljava/util/HashMap;)Z
20
The JVM has three kinds of variables
static members of a class,
non-static members of a class,
local variables in methods.
Each kind is accessed in a different way.
Variables
getstatic
operands: classname, fieldname, type
loads the value in the indicated static field onto the stack
putstatic
operands: classname, fieldname, type
removes the value from the top of the stack and stores it in the indicated static field
Static variables
getfield
operands: classname, fieldname, type
removes an object reference from the stack and loads the value in the indicated field in the referenced object onto the stack
putfield
operands: classname, fieldname, type
removes a value from the top of the stack, then and object reference, and stores the value in the indicated field of the referenced object
Non-static class members
Each method invocation causes the creation of a new frame.
The frame contains
operand stack where most of the work is done.
array of local variables
All values in the local variable array are accessed by their index, or slot number, in the array.
Method’s parameters are first
The values of the actual parameters are automatically copied to the local variable array when a method is called
Then variable declared locally in the method
Load and Store instructions transfer values between local variables and the stack.
Local variables in methods
Several variations depending on type of
For integers
iload
operand: slot number of local variable
loads the int (or boolean) variable from the given slot in the local variable array to the top of the stack.
istore
operand: slot number of local variable
removes the int (or boolean) value on top of the stack and stores it in the local variable in the given slot
For booleans
use iload and istore
Load and Store local variables
For objects
aload
the same as iload, except this loads a reference to an object
astore
the same as astore, except this stores a reference to an object
For double
dload
dstore
etc.
Load and Store local variables (2)
ldc
operand: the constant
loads the indicated constant onto the stack
iconst_0, iconst_1, …iconst_5
no operand
loads the constant which is implicit in instruction onto stack
Load constants
There are separate instructions for the operations on each primitive type.
Examples
iadd add two ints
ladd add two longs
fadd add two floats
dadd add two doubles
All binary operations remove the top two items from the stack, and leave the resulting value on top of the stack.
Arithmetic and logical operations.
Some binary operations
addition: iadd
subtraction: isub
multiplication: imul
integer division : idiv
remainder: irem
bitwise or: ior
bitwise and: iand
bitwise exclusive or: ixor
A unary op
negate: ineg
This removes the top item from the stack, negates it, and leaves the result on top of the stack.
Arithmetic and logical operations (2)
Example
// Compiled from SimpleProgram.java (version 1.8 : 52.0, super bit)
public class jvmExamples.SimpleProgram {
// Field descriptor #6 I
int x;
// Field descriptor #6 I
static int y;
}
package jvmExamples;
public class SimpleProgram {
int x;
static int y;
int sumXY(int val){
x = val;
y = 2;
return x + y;
}
}
30
Example
// Method descriptor #9 ()V
// Stack: 1, Locals: 1
public SimpleProgram();
0 aload_0 [this]
1 invokespecial java.lang.Object() [11]
4 return
Line numbers:
[pc: 0, line: 3]
Local variable table:
[pc: 0, pc: 5] local: this index: 0 type: jvmExamples.SimpleProgram
package jvmExamples;
public class SimpleProgram {
int x;
static int y;
int sumXY(int val){
x = val;
y = 2;
return x + y;
}
}
package jvmExamples;
public class SimpleProgram {
int x;
static int y;
int sumXY(int val){
x = val;
y = 2;
return x + y;
}
}
Example
// Method descriptor #18 (I)I
// Stack: 2, Locals: 2
int sumXY(int val);
0 aload_0 [this]
1 iload_1 [val]
2 putfield jvmExamples.SimpleProgram.x : int [19]
5 iconst_2
6 putstatic jvmExamples.SimpleProgram.y : int [21]
9 aload_0 [this]
10 getfield jvmExamples.SimpleProgram.x : int [19]
13 getstatic jvmExamples.SimpleProgram.y : int [21]
16 iadd
17 ireturn
Line numbers:
[pc: 0, line: 10]
[pc: 5, line: 11]
[pc: 9, line: 12]
Local variable table:
[pc: 0, pc: 18] local: this index: 0 type: jvmExamples.SimpleProgram
[pc: 0, pc: 18] local: val index: 1 type: int
32
static void f(int x, String s)
{ int y = x;
String t = s;
return;
}
What is the signature of f?
static void f(int x, String s)
{ int y = x;
String t = s;
return;
}
What is the signature of f?
(ILjava/lang/String;)V
static void f(int x, String s)
{ int y = x;
String t = s;
return;
}
What does the local variable array contain?
static void f(int x, String s)
{ int y = x;
String t = s;
return;
}
name in source code slot number
x 0
s 1
y 2
t 3
static void f(int x, String s)
{ int y = x;
String t = s;
return;
}
iload 0
istore 2
name in source code slot number
x 0
s 1
y 2
t 3
static void f(int x, String s)
{ int y = x;
String t = s;
return;
}
iload 0
istore 2
aload 1
astore 3
return
name in source code slot number
x 0
s 1
y 2
t 3
class X
{ static int x;
int y;
…
void f(int z, int w)
{ x = z;
y = w;
return
}
…
class X
{ static int x; I
int y; I
…
void f(int z, int w) (II)V
{ x = z;
y = w;
return;
}
…
class X
{ static int x;
int y;
…
void f(int z, int w)
{ x = z;
y = w;
return;
}
…
name in source code slot number in f’s local variable array
this 0
z 1
w 2
The implicit first argument of a non-static method is always “this”.
41
class X
{ static int x;
int y;
…
void f(int z, int w)
{ x = z;
y = w;
return;
}
}
this 0
z 1
w 2
iload 1
putstatic “X”, “x”, “I”
class X
{ static int x;
int y;
…
void f(int z, int w)
{ x = z;
y = w;
return;
}
}
this 0
z 1
w 2
iload 1
putstatic “X”, “x”, “I”
aload 0
iload 2
putfield “X”, “y”, “I”
return
These cause the Java virtual machine to continue execution with an instruction other than the one following the control transfer instruction
ASM allows us to insert labels in the instruction sequence and jump to the label. In the class files, the jumps take a virtual address of the instruction to jump to
Several kinds of control transfer instruction:
conditional compare to zero
compare the top of the stack to zero and depending on the result, continue with the next instruction, or jump to the labeled instruction
conditional compare to null
compare the top of the stack to null and depending on the result, continue with the next instruction or jump to the label
compare the top two elements on the stack
compare the top two elements on the stack and jump depending on the result
unconditional transfer
Control transfer instructions
These instructions take the destination of a jump as operand.
They compare the top of the stack to zero, and depending on the result, jump to the label, or continue with the next instruction.
The value on the top of the stack is consumed.
The value on the top of the stack must be an int (or boolean).
Conditional compare to zero
val is the value on top of the stack
ifeq jump to label if val = 0
iflt jump to label if val < 0
ifle jump to label if val ≤ 0
ifne jump to label if val ≠ 0
ifgt jump to label if val > 0
ifge jump to label if val ≥ 0
Conditional compare to zero (2)
Similar to compare to zero
The value on the top of the stack is consumed and
The value on top of the stack must be a reference to an object
ifnull jump to label if val = null
ifnonnull jump to label if val ≠ null
Conditional compare to null
compare the top two elements of the stack and jump if the indicate relation is satisfied.
The two elements are consumed.
The instructions have one operand, the destination of the jump
Examples
ldc 0; ldc 1 if_icmne L0
would result in a jump to label L0 since the top two elements (0 and 1) of the stack are not equal.
ldc 0; ldc 1; if_icmplt L1
would result in a jump to L1.
Compare top two elements on stack
if_icmpeq
if_icmpne
if_icmplt
if_icmpgt
if_icmple
if_icmpge
if_acmpeq
if_acmpne
Compare top two elements on stack (2)
use int or boolean stack arguments
use reference stack arguments
takes a destination (label) as operand and jumps unconditionally to that location
goto
Unconditional branch
dup
duplicates the top of the stack
swap
swaps the top two elements of the stack
pop
removes element from top of stack
there are more—see JVM spec
Stack manipulation
Three instructions invoke methods.
invokevirtual
for normal methods
invokestatic
for static methods
invokespecial
used during object initialization
Method invocation
invokevirtual
Operands: class name, method name, desciptor
Prior to the instruction, the stack should contain
reference to object whose method is being invoked
parameters of the method
Execution causes a new frame to be created which invokes the indicated method.
Parameters are automatically copied into the appropriate slots of the new frame’s local variable array and removed (along with the object reference) from the stack
If the method returns a value, it will be left on top of the stack after the method terminates.
Method invocation (2)
invokestatic
Operands: class name, static method name, descriptor
Prior to the instruction, the stack should contain the parameters of the method
Execution causes a new frame to be created which invokes the indicated method.
Parameters are automatically copied into the appropriate slots of the new frame’s local variable array and removed from the stack
If the method returns a value, it will be left on top of the stack after the method terminates.
Method invocation (3)
invokespecial
operands: class name, initializer name—always “
Prior to the instruction, the stack should contain
reference to object whose method is being invoked
parameters of the method
Execution causes a new frame to be created which invokes the
Parameters are automatically copied into the appropriate slots of the new frame’s local variable array and removed (along with the object reference) from the stack
This instruction is used to invoke the “
Method invocation (4)
Remarks on parameters and return values
Before a method is invoked, its arguments are placed on the operand stack in the order they appear in the descriptor, and after the reference to the object (if invokespecial or invokevirtual).
The invoke instruction then places these in the local variable array of the frame for the invoked method where they can be accessed as local variables.
The return instruction leaves the result, if any on top of the stack of the caller.
Method invocation (5)
The choice of return instruction depends on the type of result to be returned from the method.
If a value is returned, it is placed on top of the stack before invoking return
return
used to return from methods with void type
ireturn
used to return from methods that return an int
before calling, load the int to be returned on top of the stack
areturn
used to return from methods that return an object reference
before calling, load the reference to be returned on top of the stack
Returning from a method
Instantiate objects using the new instruction.
this leaves the address of the newly created object on top of the stack
This must be immediately followed by an invocation of its init method using invokespecial.
Since invokespecial will consume the reference, we dup it first
new
operand: fully qualified class name
Instantiating objects
Example:
class MyClass
{ static ten;
…
ten = new Integer(10);
…
}
//create an uninitialized Integer object and leave a reference on top of the stack.
new “java/lang/Integer”
//duplicate the reference, since one reference will be consumed in the call to init
dup
//this initializer takes an int parameter, load it onto the stack
ldc 10
//invoke the
invokespecial “java/lang/Integer” ”
//store the remaining reference to the object in the static variable ten
putstatic “MyClass” ”ten” ”Ljava/lang/Integer;”
Example: object instantiation
The JVM verifies the source code before executing it.
This includes type checking and ensuring that the code satisfies certain well-formed conditions.
It is possible that a compiler will generate code that does not pass verification (but conforming Java compilers only generate code that will pass verification)
In some cases, this will be due to programmer errors, in others it will indicate a problem with your code generation.
Example: method without a return statement
JVM verification
Typical verification errors:
“falling off the end of the code”.
problem is a missing return statement
“unequal stack sizes”
problem is that you have branching code where the alternative paths have different effects on the stack. This indicates a problem with code generation
it is likely to come up with if and while statements
javap
comes with the Java distribution
parses a class file
eclipse class file byte code viewer
Tools
comes with the standard java distribution.
javap –c X will decompile the classfile X.class and show the corresponding java code.
javap –c –v X gives a more verbose output.
Two ways to use javap
inspect the byte code that your compiler generates to ensure that it is what you think it is.
find out how to generate code to do something by writing a little java program that does that, compiling it, and then using javap to decompile the classfile.
javap –c X
javap
Compiled from “X.java”
class X extends java.lang.Object{
static int x;
X();
Code:
0: aload_0
1: invokespecial #1;
//Method java/lang/Object.”
4: return
for class X
static int inc(int);
Code:
0: iload_0
1: iconst_2
2: imul
3: istore_1
4: getstatic #2; //Field x:I
7: iload_1
8: iadd
9: ireturn
bytecode for
method inc
#2 is an index in the constant pool The comment tells you what it is. Use the –verbose switch to see the constant pool
public static void main(java.lang.String[]);
Code:
0: iconst_5
1: putstatic #2; //Field x:I
4: iconst_3
5: invokestatic #3; //Method inc:(I)I
8: putstatic #2; //Field x:I
11:getstatic #4;
//Field java/lang/System.out:Ljava/io/PrintStream;
14:getstatic #2; //Field x:I
17:invokevirtual #5; //Method java/io/PrintStream.println:(I)
20:return
}
Example
class ThisClass
{ static int f(int a, int b)
{ return a+b; }
}
Example
class ThisClass
{ static int f(int a, int b)
{ return a+b; }
}
Generated code for f
iload 0;
iload 1;
iadd;
ireturn;
Example
class ThisClass
{ static int f(int a, int b)
{ return a+b; }
}
Generated code for f(3,4)
ldc 3;
ldc 4;
invokestatic (“ThisClass”, “f”,”(II)I”)
// 7 is now on top of the stack
Example
class S
{ static String s;
static String t;
…
}
What code would be generated for S.s.equals(S.t)
(where we just call the method already defined for the Java String class)
class S
{ static String s;
static String t;
…
}
S.s.equals(S.t)
getstatic(“MyClass”,”s”,”Ljava/lang/String;”)
getstatic(“MyClass”,”t”,”Ljava/lang/String;”)
invokevirtual(“Ljava/lang/String;”,”equals”,
”(Ljava/lang/String;)Z”)
//now, the boolean value with the result is left on top of the stack. Both values placed on the stack have been consumed
Example:
class X
{ static int x;
static int inc(int dx)
{ int y = dx*2;
return x+y;
}
public static void main(String[] args)
{ x = 5;
x = inc(3);
System.out.println(x);
}
}
is a java class that includes both static and local variables, and method calls.
Example:
class X
{ static int x;
static int inc(int dx)
{ int y = dx*2;
return x+y;
}
public static void main(String[] args)
{ x = 5;
x = inc(3);
System.out.println(x);
}
}
is a java class that includes both static and local variables, and method calls.
static inc(int) : int
ILOAD 0: dx
ICONST_2
IMUL
ISTORE 1
GETSTATIC X.x : int
ILOAD 1: y
IADD
IRETURN
Example:
class X
{ static int x;
static int inc(int dx)
{ int y = dx*2;
return x+y;
}
public static void
main(String[] args)
{ x = 5;
x = inc(3);
System.out.println(x);
}
}
is a java class that includes both static and local variables, and method calls.
ICONST_5
PUTSTATIC X.x : int
ICONST_3
INVOKESTATIC X.inc(int) : int
PUTSTATIC X.x : int
GETSTATIC System.out : PrintStream
GETSTATIC X.x : int
INVOKEVIRTUAL
PrintStream.println(int) : void
RETURN
Java bytecode manipulation framework
Designed to generate, transform, and analyze Java classes represented as byte arrays
Provides tools to read, write, and transform byte arrays using higher level concepts
Download from http://asm.objectweb.org
ASM
Can be used to statically
generate code
parse and analyze an existing class file
dynamically
read and transform class files at load time
aspect-oriented programming
instrument classes for debugging or performance measurements
generate (and load) new classes at runtime
stubs and proxies
Small and fast
Defines a visitor interface for elements of the bytecode
ClassVisitor
FieldVisitor
MethodVisitor
etc.
Different visitor implementations perform different functions
ClassReader parses existing class files
ClassWriter generates a class file
Visitors
General pattern
Get a visitor object for a construct
Visit its components
There are often constraints on order
invoke visitEnd() method
class Demo
{ static int x;
static String s;
static ArrayList
public static int f(int y, String t)
{ int z;
z = y + x;
a.add(z); //this call also requires wrapping
//the int parameter in an Integer class
return z;
}
Example
public static void main(String[] args)
{ x = 22;
s = “test”;
IO.writeString(s);
a = new ArrayList
x = (f(x,s));
IO.writeInt(x);
x = a.get(0); IO.writeInt(x);
}
}
We will give a program that uses asm to generate Java byte code for this class.
public class IO
{
public static void writeInt(int x)
{System.out.println(x);}
public static void writeString(String s)
{System.out.println(s);}
}
We will compile this with javac and call its methods in our class.
We will also use Java classes to implement certain functionality.
import java.io.FileOutputStream;
/* Download this package from http://asm.objectweb.org */
import org.objectweb.asm.*;
public class CodeGenDemo implements Opcodes
{
public static void main(String[] args)
{
generate and output class file
}
}
The Opcodes interface defines constants used by asm. These constants are available in this class by marking it to implementing the interface
83
Defining constants using an enum rather than putting them in an interface and implementing the interface. ASM predates the addition of enums to Java.
/* Initialize the class to be built by creating and visiting a ClassWriter object */
String className = “Demo”; String superClassName = “java/lang/Object”;
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
cw.visit(V1_6, ACC_PUBLIC | ACC_SUPER, className, null, superClassName, null);
84
Parameters
int version – the class version. We will always use V1_6
int access – the class’s access flags (see Opcodes).
This parameter also indicates if the class is deprecated.
String name – the internal name of the class (see getInternalName).
String signature – the signature of this class. May be null if the
class is not a generic one, and does not extend or implement
generic classes or interfaces.
String superName – the internal of name of the super
class (see getInternalName).
For interfaces, the super class is Object. May be null, but only
for the Object class.
String[] interfaces – the internal names of the class’s interfaces
(see getInternalName). May be null.
//add fields and methods—we’ll come back to this
/*we’re done adding things to the class */
cw.visitEnd();
/* Now write the classfile to a file named “Demo.class”
/*Convert ClassWriter’s data structure to valid class file*/
byte[] bytes = cw.toByteArray();
/*Write the resulting bytes to a file*/
FileOutputStream f;
try
{
System.out.println(“writing class ” +
className + “.class”);
f = new FileOutputStream(className + “.class”);
f.write(bytes);
f.close();
}
catch (Exception e)
{
e.printStackTrace();
}
Or dymically load class and execute a method
/* Dynamically load the class file and execute the main method */
Class demoClass = loadClass(“Demo”, bytes);
/* get the method to be executed, give name and class objects for parameters */
Method mainMethod = demoClass.getMethod(“main”,String[].class);
/*invoke the method */
String[] st = new String[1];
mainMethod.invoke(null,st); //first param is target,
//null for static methods
The following is copied verbatim out of the asm manual
Using generated classes
The previous byte array can be stored in a Comparable.class file for future
use. Alternatively it can be loaded dynamically with a ClassLoader. One
method is to define a ClassLoader subclass whose defineClass method is
public:
class MyClassLoader extends ClassLoader {
public Class defineClass(String name, byte[] b) {
17
2 Classes
return defineClass(name, b, 0, b.length);
}
}
Then the gen