// File RTCG4.java --- the power example
// sestoft@dina.kvl.dk * 2002-09

// Using the gnu.bytecode package from http://www.gnu.org/software/kawa

import gnu.bytecode.*;
import java.io.*;

public class RTCG4 {
  public static void main(String[] args) 
    throws IOException, NoSuchMethodException, IllegalAccessException, 
           java.lang.reflect.InvocationTargetException {
    int count = Integer.parseInt(args[0]);
    int n = 16;
    ClassType co = new ClassType("MyClass");
    co.setSuper("java.lang.Object");
    co.setModifiers(Access.PUBLIC);
    {
      // Build: public static int MyPower(int x) { ... }
      Method mo = co.addMethod("MyPower");
      mo.setSignature("(I)I");
      mo.setModifiers(Access.PUBLIC | Access.STATIC);
      mo.initCode();
      PowerGen(mo, n);
    }
    // Output class file in human-readable format:
    ClassTypeWriter.print(co, System.out, 0);
    // Output class file to array:
    byte[] classFile = co.writeToArray();
    // Load the class file from byte array into the JVM 
    Class ty = new ArrayClassLoader().loadClass("MyClass", classFile);
    // Get the MyMethod(int):
    java.lang.reflect.Method m = 
      ty.getMethod("MyPower", new Class[] { int.class }); 
    // Call the method:    
    System.out.println(m.invoke(null, new Object[] { new Integer(3) }));
  }

  public static int Power(int n, int x) {
    int p;
    p = 1;
    while (n > 0) {
      if (n % 2 == 0) 
        { x = x * x; n = n / 2; }
      else 
        { p = p * x; n = n - 1; }
    }
    return p;
  }

  public static void PowerGen(Method mo, int n) {
    CodeAttr jvmg = mo.getCode();
    Scope scope = mo.pushScope();
    Variable varx = 
      scope.addVariable(jvmg, Type.int_type, "x");
    Variable varp = 
      scope.addVariable(jvmg, Type.int_type, "p");
    jvmg.emitPushInt(1);
    jvmg.emitStore(varp);               // p = 1;
    while (n > 0) {
      if (n % 2 == 0) { 
	jvmg.emitLoad(varx);            // x is arg_0
	jvmg.emitLoad(varx);
	jvmg.emitMul();
	jvmg.emitStore(varx);           // x = x * x
        n = n / 2; 
      } else { 
	jvmg.emitLoad(varp);            // load p
	jvmg.emitLoad(varx);		// load x (arg_0)
	jvmg.emitMul();
	jvmg.emitStore(varp);           // p = p * x
        n = n - 1; 
      }
    }
    jvmg.emitLoad(varp); 
    jvmg.emitReturn();                  // return p;
    mo.popScope();
  }
}

// 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);
  }
}

