// File RTCG7B.java --- measure time to generate (much) code
// sestoft@dina.kvl.dk * 2002-09-17

// Using BCEL from http://jakarta.apache.org/bcel/

import org.apache.bcel.*;		// Constants
import org.apache.bcel.classfile.*;	// JavaClass
import org.apache.bcel.generic.*;	// ClassGen, MethodGen, instructions
import java.io.*;

public class RTCG7B {
  public static void main(String[] args) 
    throws IOException, NoSuchMethodException, IllegalAccessException, 
           java.lang.reflect.InvocationTargetException {
    int count = Integer.parseInt(args[0]);
    int calls = Integer.parseInt(args[1]);
    ClassGen cg = new ClassGen("MyClass", "java.lang.Object",
			       "<generated>", 
			       Constants.ACC_PUBLIC | Constants.ACC_SUPER, 
			       null);
    ConstantPoolGen cp = cg.getConstantPool();
    Timer t = new Timer();
    {
      // Build: public static void MyMethod1(int x) { ... }
      InstructionList il = new InstructionList();
      MethodGen mg = new MethodGen(Constants.ACC_PUBLIC | Constants.ACC_STATIC,
				   Type.VOID,
				   new Type[] { Type.INT },
				   new String[] { "x" },
				   "MyMethod1",
				   "MyClass",
				   il, cp);
      Instruction iload = new ILOAD(0);
      Instruction iadd = new IADD();
      il.append(iload);
      il.append(new ICONST(1));
      il.append(iadd);
      for (int i=count; i>0; i--) {
	il.append(iload);
	il.append(iadd);
      }
      il.append(new RETURN());
      // Compute stack depth and add method to the class
      mg.setMaxStack();
      cg.addMethod(mg.getMethod());
    }
    // Get the generated class
    JavaClass clazz = cg.getJavaClass();
    // Output class file to array:
    byte[] classFile = clazz.getBytes();
    // Load the class file into the JVM 
    Class ty = new ArrayClassLoader().loadClass("MyClass", classFile);
    {
      java.lang.reflect.Method m = 
	ty.getMethod("MyMethod1", new Class[] { int.class }); 
      for (int i=calls; i>0; i--) {
	m.invoke(null, new Object[] { new Integer(count) });
      }
      System.out.println("Generating " + 2*count + " instructions and making " 
			 + calls + " calls: " + t.Check() + " sec");
    }
  }
}

// This is needed because defineClass is protected in java.lang.ClassLoader:

class ArrayClassLoader extends ClassLoader {
  public Class loadClass(String name, byte[] classFile) {
    return defineClass(name, classFile, 0, classFile.length);
  }
}

// Crude timing utility ----------------------------------------
   
class Timer {
  private long start;

  public Timer() {
    start = System.currentTimeMillis();
  }

  public double Check() {
    return (System.currentTimeMillis()-start)/1000.0;
  }
}

