domingo, 16 de junio de 2013

Java - Como hacer una JVM | Parte 3

Continuamos con nuestro super tutorial para la creación de una JVM, si no habéis leído las 2 primeras partes hacedlo antes de poneros con esta!

Como hacer una JVM | Parte 1
Como hacer una JVM | Parte 2

Y seguimos donde lo dejamos, creando nuestro area de clases.

ClassArea

El ClassArea contendrá las clases estáticas de nuestra JVM, esa estructura estará implementada como un HashTable, el índice será el nombre de la clase y el dato una clase extra que crearemos llamada JClass, está clase actuará como recubridora de las de BCEL.

Además, como ya hemos mencionado, necesitamos poder leer un .class y añadirlo a nuestra área de clases.

Código ClassArea.java
public class ClassArea {
 private Hashtable<String, JClass> classes;

 
 public ClassArea() {
  classes = new Hashtable<String, JClass>();
 }

 public boolean addClass(JClass jClass) {
  if (jClass == null)
   return false;

  classes.put(jClass.jClassInfo.getClassName(), jClass);
  return true;
 }

 /**
  * Carga una clase del hashtable o desde directorio si se encuentra, en otro
  * caso error, ademas la anyade al classpath
  * 
  * @param name
  *            clase a cargar
  * @return
  */
 public JClass loadClass(String name) {
  JClass jClass = classes.get(name);
  if (jClass != null)
   return jClass;
  try {
   jClass = new JClass(Repository.lookupClass(name));
   addClass(jClass);
  } catch (ClassNotFoundException e) {
   e.printStackTrace();
   return jClass;
  }
  return jClass;
 }
}

Tenemos nuestro HashTable con nombre-clase, y además nuestro método para cargar clases, que usa la librería BCEL, abstrayéndonos completamente de tareas de parseo y demás, el método static lookupClass() de la clase Repository toma el nombre de una clase y devuelve el JavaClass que mencionamos en la primera parte, este lo usamos para crear nuestro propio JClass.

Código JClass.java
public class JClass {

 JavaClass jClassInfo;
 ClassGen jClassGen;
 private JField[] jFields;

 public JClass(JavaClass jClass) {
  jClassInfo = jClass;
  jClassGen = new ClassGen(jClass);
  jFields = new JField[jClass.getFields().length];
  for (int i = 0; i < jFields.length; i++) {
   jFields[i] = new JField(jClass.getFields()[i]);
  }
 }
 
 public JMethod getMainMethod() {
  return getMethod("main",null);
 }
 
 /**
  * Busca un metodo basandose en su nombre y/o signatura
  * 
  * @param methodName
  *            nombre del metodo
  * @param signature
  *            signatura del metodo o null si no se requiere
  * @return instancia del metodo encapsulado en JMethod
  */
 public JMethod getMethod(String methodName, String signature) {
  Method searchedMethod = null;
  for (Method m : jClassInfo.getMethods())
   if (m.getName().equals(methodName)) {
    if (signature != null) {
     if (m.getSignature().equals(signature)) {
      searchedMethod = m;
      break;
     }
    } else {
     searchedMethod = m;
     break;
    }
   }
  return searchedMethod != null ? new JMethod(searchedMethod, jClassGen)
    : null;
 }
  .
  .
  .
}
Podéis ver lo que sería esta clase, las referencias a las clases de BCEL y el constructor iniciando los fields. Además notar que para la creación del ClassGen es necesario usar el JavaClass.
Declaramos un método por defecto para obtener el método principal (main), que posteriormente usaremos en nuestro programa de ejecución.
Pero es importante resaltar la obtención de métodos de una clase, la búsqueda debe ser no solo por nombre, sino por signatura, recordad que java permite sobrecarga de métodos, es decir, métodos con el mismo nombre pero con distintos parámetros/valor de retorno, usando la signatura conseguimos diferenciarlos correctamente, (más sobre sobrecarga).

Código JField .java
public class JField {
 public Field fieldInfo;
 private JValue value;

 public JField(Field field) {
  fieldInfo = field;
  ConstantValue val = field.getConstantValue();
  ConstantPool cp;
  int index;
  Constant c = null;
  if (val != null) {
   cp = val.getConstantPool();
   index = val.getConstantValueIndex();
   c = cp.getConstant(index);
  }
  switch (field.getType().getType()) {
  case Constants.T_INT:
   if (val != null) {
    ConstantInteger cl = (ConstantInteger) c;
    value = new JInteger(cl.getBytes());
   } else
    value = new JInteger();
   break;
  }
 }
  .
  .
  .
}
También mostramos la clase JField, que representa una propiedad de una clase, recubriendo al Field de BCEL, y conteniendo además el valor propio del campo como un JValue, notar en su creación el uso de la ConstantPool (esta en toas partes la jodia), para permitir la creación del field con un valor por defecto, relativo a propiedades inicializadas previa creación de objeto. Se muestra solo para int pero su obtención para el resto de variables sería similar.

StackFrame

Como dijimos los frames están formados por el contador de programa, el método concreto que se esta ejecutando, y un puntero al frame padre, de nuevo creamos una clase recubridora para los métodos de BCEL, JMethod. Ademas necesitamos métodos para acceder a las instrucciones e información dentro de cada frame.

Código StackFrame.java
public class StackFrame {

 Stack<JValue> operands;
 JValue[] locals;
 private int pc;
 private JMethod method;
 private StackFrame cf;
 public byte error;

 // added
 JClass clase;

 public StackFrame(StackFrame cf, JMethod meth, JClass clase) {
  this(cf, meth, clase, null);
 }
 
 public StackFrame(StackFrame cf, JMethod meth, JClass clase, JValue thisRef) {
  int maxLocals=meth.getMaxLocals();
  if (thisRef != null) {
   locals = new JValue[maxLocals];
   if(maxLocals>0)locals[0] = thisRef;
  } else
   locals = new JValue[maxLocals];
  this.cf = cf;
  operands = new Stack<JValue>();
  pc = 0;
  error=0;
  method = meth;

  this.clase = clase;
 }

 public InstructionHandle nextInstruction() {
  return method.get(pc);
 }
  .
  .
  .
}
Arriba vemos un esquema de nuestro StackFrame, habría más métodos que podemos añadir para facilitar operaciones pero esos son los básicos. Añadimos la clase del método que se esta ejecutando para facilitar obtener información a la hora de ejecución, además notar los dos métodos constructores.
Como dije en la segunda parte de este tutorial, cuando se llama a un método de un objeto, el frame guarda en la primera posición de variables locales una referencia a ese objeto, esto es controlado en nuestra implementación comprobando si thisRef es null, y actuando en consecuencia.

Código JMethod.java
public class JMethod {

 Method methodInfo;
 MethodGen methodGen;

 public JMethod(Method method, ClassGen classGen) {
  methodInfo = method;
  methodGen = new MethodGen(method, classGen.getClassName(),
    classGen.getConstantPool());
 }
 
 public short[] getCode() {
  byte[] code = methodInfo.getCode().getCode();
  short[] codePlus = new short[code.length];
  // convert -opcodes to +opcodes
  for (int i = 0; i < code.length; i++) {
   codePlus[i] = (short) (code[i] < 0 ? code[i] + 256 : code[i]);
  }
  return codePlus;
 }
 
  .
  .
  .
}
De nuevo la clase recubridora usa la librería BCEL, destacar el método getCode() que obtiene el código del método a través de BCEL, y como mencioné lo transforma a valores positivos.

Heap

Nuestro Heap será bastante limitado y sencillo, simplemente será un array de JValue, JValue será el tipo de dato base que nuestra JVM usará, cada tipo de dato concreto deberá heredar de este JValue, por ejemplo JInteger. Además necesitamos un puntero a la siguiente posición libre de memoria.

Código JValue.java
public abstract class JValue{
 public Type type;
}
El Type es una clase de BCEL, que representa a un tipo de la JVM.

JObject será nuestra representación de objeto y como dije será un JValue.

Código JObject.java
public class JObject extends JValue {
 public int heapPtr;
 public JClass jClass;
 // campos de la clase representado para objetos
 public JField[] jFields;

 //creacion a null
 public JObject() {
  jClass=null;
  jFields=null;
 }

 /**
  * Crea un objeto con posicion heapPtr de tipo jClass. Se reserva espacio
  * para sus fields en base a los fields de jClass
  * 
  * @param heapPtr
  *            posicion en el heap
  * @param jClass
  *            clase instanciada
  */
 public JObject(int heapPtr, JClass jClass) {
  int count = jClass.GetObjectFieldCount();
  this.heapPtr = heapPtr;
  type = Type.OBJECT;
  this.jClass = jClass;
  if (jClass != null) {
   jFields = new JField[count];
   for (int i = 0; i < jFields.length; i++) {
    jFields[i] = new JField(jClass.getFields()[i]);
   }
  }
 }

 public void setFieldValue(int i, JValue val) {
  jFields[i].setValue(val);
 }

 public void setFieldValue(String name, JValue val) {
  for (int i = 0; i < jFields.length; i++) {
   if (jFields[i].getName().equals(name))
    jFields[i].setValue(val);
  }
 }

 public JField getField(int i) {
  return jFields[i];
 }

 public JField getField(String name) {
  for (int i = 0; i < jFields.length; i++) {
   if (jFields[i].getName().equals(name))
    return jFields[i];
  }
  return null;
 }
}
En la creación del objeto establecemos su tipo y creamos sus fields, en base a los que nos ofrece su clase, además añadimos una serie de métodos de utilidad para trabajar con sus propiedades.

Código Heap.java
public class Heap {

 private int nextObjectID;
 private JValue[] heap;

 public Heap(int size) {
  nextObjectID = 0;
  heap = new JValue[size];
 }
 
 /**
  * Crea un objeto de tipo mainClass y lo guarda en el heap
  * 
  * @param mainClass
  *            tipo de objeto a crear
  * @return la referencia al objeto
  */
 public JObject createObject(JClass mainClass) {
  JObject object = new JObject(nextObjectID++, mainClass);
  heap[object.heapPtr] = object;
  return object;
 }
 
 
 /**
  * Crea un objeto de tipo String y lo guarda en el heap
  * 
  * @param strValue
  *            valor del JString a crear
  * @param classes
  *            ClassArea a usar
  * @return
  */
 public JObject createStringObject(String strValue, ClassArea classes) {
  JClass stringClass = classes.loadClass("java.lang.String");

  JObject object = (JObject) createObject(stringClass);

  JArray arrayString = new JArray(nextObjectID, strValue.length(),
    Type.CHAR);
  arrayString.setStr(strValue);
  object.setFieldValue(0, arrayString);
  object.setFieldValue("count", new JInteger(arrayString.nElems));

  return object;
 }
  .
  .
  .
}

He dejado fuera la creación de arrays por simplificar algo e ir directo a los objetos que es más interesante. El constructor no tiene mucho misterio y la creación de objetos en Heap tampoco, gracias al uso del constructor de JObject, tras crearlo se añade al heap y se devuelve la referencia a la JVM para que lo añada en la pila.

Tenemos un método especial de creación de objetos String debido a la instrucción LDC, que permite la creación directa de un String y su carga en la pila, los String los hemos codificado como un JArray, (cada array se toma como otro objeto, internamente tiene un array de JValue para permitir arrays de cualquier tipo soportado por nuestra JVM), y tras la creación modificamos 2 de sus fields, el que guarda el propio String (en nuestro caso el JArray), y el que guarda su tamaño llamado count, existen otros, pero estos dos son los básicos para que nuestros objetos String puedan ser utilizados.

Ejecución

Todo esto está muy bonito pero... ¿Cómo cojones lo pongo a funcionar?, tiene algo de miga aunque no demasiado (gracias a nuestro desarrollo POO!), así que tenemos que crearnos otra clase, por ejemplo Exec, que será la que usará la JVM para ponerla a trabajar.

Código Exec.java
public class Exec {

 public static void main(String[] args) {
  execute(args[0], args[1]);
 }
 
 private static void execute(String strClass, String size) {

  // creamos heap
  Heap heap = new Heap(Integer.parseInt(size));
  // creamos area de clases
  ClassArea ca = new ClassArea();
  // leemos clase y buscamos metodo principal
  JClass mainClass = ca.loadClass(strClass);
  JMethod mainMethod = mainClass.getMainMethod();
  // creamos frame principal
  StackFrame mainFrame = new StackFrame(null, mainMethod, mainClass);

  // creamos jvm
  JVM jvm = new JVM(mainFrame, heap, ca);

  // ejecucion
  jvm.run();
 }
}

En este programa principal se toman dos argumentos, el nombre de la clase y el tamaño del heap. Cuando tenemos creadas nuestras 3 estructuras se las pasamos a la JVM y a ejecutar, (recordar que no veremos nada porque no hemos puesto ningún tipo de salida por pantalla), además si cogéis cualquier .class probablemente falle porque hay cantidad de instrucciones que no están implementadas.

El método que se ejecutará será el método main, que se obtiene mediante el método getMainMethod().

Notar que el nombre de una clase no es solo su nombre, sino que incluye el paquete en el que esta, por ejemplo si cogéis una clase llamada A.java que esta en com.prueba.tests, su nombre en realidad es com.prueba.tests.A.

Conclusión

Bueno, hasta aquí hemos llegado, hay algunas cosas que han quedado en el aire (excepciones, propiedades static, recolector de basura, threads) pero para un tema tan denso como es la máquina virtual de java creo que se ha presentado información bastante útil para cualquiera que quiera empezar a indagar en este mundillo, nada más.

Un saludo!

jueves, 13 de junio de 2013

Ghost Tits - Olivia Munn

La nueva época del terror esta aquí, tras Paranormal Activity o Insidious, llega... Ghost Tits!



Sin palabras... ajajja

miércoles, 12 de junio de 2013

E3 - This is how Sony trolls Microsoft

Shu Yoshida y Adam Voyes explican como se comparten los juegos en la nueva PS4.



Sin comentarios xD

domingo, 9 de junio de 2013

Java - Como hacer una JVM | Parte 2

Continuamos este tutorial para realizar nuestra home made virtual machine, la primera parte la podéis encontrar en este enlace.

Habíamos preparado la mente para saber como empezar a programar, así que vamos allá, y empezaremos pasando a código lo que ya sabemos, como está estructurada nuestra JVM.

JVM.java

Ya dijimos que la JVM esta formada por 3 partes, la zona de clases, el heap y los frames, además sabemos que tendrá que ir leyendo instrucciones de los archivos .class y ejecutarlas en función de cual sea dicha instrucción, bien, pues pondremos eso en código. He decidido ir descomponiéndolo porque meterlo todo del tirón puede ser demasiao lioso.

Primero definimos las 3 estructuras tal y como ya sabemos, son clases que deberemos crear más adelante y establecemos un constructor para la JVM, además hacemos que implemente Runnable y por tanto el método run().
Dentro de este método run() podríamos tener distintos tipos de ejecución como se mencionó en la primera parte pero para no complicar el tema tomaremos solo la ejecución directa con OPCODE.

Código Base
public class JVM implements Runnable {

 private StackFrame topFrame;
 private Heap heap;
 private ClassArea classes;
 
 public JVM(StackFrame topFrame, Heap heap, ClassArea classes) {
  this.topFrame = topFrame;
  this.heap = heap;
  this.classes = classes;
 }
 
 public void run() {
  runOPCODE();
 }
}

Para esta ejecución tenemos un método runOPCODE(), que declara 2 variables, un array de short y un short, cada uno representará el código completo del método y el código de operación actual.

Y podréis preguntaros ¿Por qué son short si te has hartado de decir que la información en los .class esta en forma de bytes? Primero, con 8 bits tenemos 256 combinaciones, suficientes para los 212 opcodes, pero internamente los byte en Java están en complemento a 2, osea que van desde -2^7 a 2^7-1, así que bcel guarda la codificación de los opcodes superior a 2^7-1 como negativos, pero a la hora de la verdad son positivos, por lo que hacemos esa transformación de byte a short para permitir valores superior a 2^7-1, en la clase JMethod lo veremos.

Después de eso tenemos el bucle de ejecución, que debe seguir funcionando mientras tengamos algo que ejecutar (el frame actual no sea null), y no tengamos ningún error. Hacemos una distinción a la hora de ejecutar por si el método es nativo o no, si lo es el control pasa al método especial ejecutarNative(), sino, obtenemos el código del método, la instrucción a ejecutar y usamos el método ejecutarOPCODE(), todo esto haciendo uso de los métodos de StackFrame y de la clase JMethod, que todavía no hemos visto, pero que es fácil intuir que hacen.

Código runOPCODE()
private void runOPCODE() {
  short[] code;
  short opcode;
  
  while (topFrame != null && topFrame.error == 0) {
   if (topFrame.getMethod().isNative())
    ejecutarNative();
   else {
    // ejecucion acceso directo bytecode
    code = topFrame.getMethod().getCode();
    opcode = code[topFrame.getPC()];
    ejecutarOPCODE(code, opcode);
   }
  }
 }

Para el método de ejecución usamos una estructura switch-case, en función de qué tipo de opcode tengamos se realizará una ejecución u otra, he puesto solo algunas instrucciones aunque como digo son muchas más, pero para haceros una idea esta bien. Para saber como implementar cada una nada mejor que primero revisar la lista básica:

http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings

Y después revisar la ayuda de Jasmin (un ensamblador para la JVM algo más simple), por ejemplo el siguiente enlace es para putfield:

http://www.vmth.ucdavis.edu/incoming/Jasmin/ref-putfield.html

Código ejecutarOPCODE()
private void ejecutarOPCODE(short[] code, short opcode) {
  short pos, parteA, parteB, cons, type;
  // segun opcode exec instruccion
  switch (opcode) {
  case Constants.NOP:
   ejecutarNOP();
   break;
  // /////////////// Stack Operations ////////////////
  // Instructions that push a constant onto the stack
  case Constants.ICONST_M1:
  case Constants.ICONST_0:
  case Constants.ICONST_1:
  case Constants.ICONST_2:
  case Constants.ICONST_3:
  case Constants.ICONST_4:
  case Constants.ICONST_5:
   ejecutarICONST(Integer.valueOf(opcode - Constants.ICONST_0));
   break;
  // Instructions that load a local variable onto the stack
  case Constants.ILOAD:
   pos = code[topFrame.getPC() + 1];
   ejecutarILOAD((byte) pos);
   topFrame.incPC();// saltar index
   break;
  // Instructions that load a local variable onto the stack
  case Constants.ILOAD:
   pos = code[topFrame.getPC() + 1];
   ejecutarILOAD((byte) pos);
   topFrame.incPC();// saltar index
   break;
  case Constants.ISTORE:
   pos = code[topFrame.getPC() + 1];
   ejecutarISTORE(pos);
   topFrame.incPC();// saltar index
   break;
  // Integer arithmetic
  case Constants.IADD:
   ejecutarIADD();
   break;
  // ///////////// Objects and Arrays ////////////
  // Instructions that deal with objects
  case Constants.NEW:
   parteA = code[topFrame.getPC() + 1];
   parteB = code[topFrame.getPC() + 2];
   ejecutarNEW(getIndex(parteA, parteB));
   break;
  case Constants.GETFIELD:
   parteA = code[topFrame.getPC() + 1];
   parteB = code[topFrame.getPC() + 2];
   ejecutarGETFIELD(getIndex(parteA, parteB), lastDec);
   break;
  // ////////////Control Flow /////////////////////
  // Conditional branch instructions
  case Constants.IFEQ:
   parteA = code[topFrame.getPC() + 1];
   parteB = code[topFrame.getPC() + 2];
   ejecutarIFEQ(getIndex(parteA, parteB), lastDec);
   break;
  // ////////////////////// Method Invocation and Return ////////
  // Method return instructions
  case Constants.RETURN:
   ejecutarRETURN();
   break;
  case Constants.IRETURN:
   ejecutarIRETURN();
   break;
  // Method invocation instructions
  case Constants.INVOKESPECIAL:
   ejecutarINVOKEBC(null, code);
   break;
  case Constants.INVOKESTATIC:
   ejecutarINVOKEBC(Constants.INVOKESTATIC, code);
   break;
  case Constants.INVOKEVIRTUAL:
   ejecutarINVOKEBC(null, code);
   break;
  default:
   error(topFrame, "opcode no reconocido");
   break;
  }
 }

Mencionar el método getIndex(), cada opcode de la JVM ocupa un byte, y si usa parámetros van codificados a continuación usando otros byte, el tema esta que los índices a la ConstantPool van codificados como 16 bits, pero separados en 2 bytes (uno con los 8 bits más significados y otro con los 8 menos), asi que para formar el índice completo hay que coger cada byte por separado y generar el short (de 16bits), para ello hacemos uso de la clase ByteBuffer (probé distintas formas ésta es la que me funcionó).

Código getIndex()
/**
  * Construye un indice de 16 bits separado en 2 bytes
  * 
  * @param subi1
  *            primera parte indice
  * @param subi2
  *            segunda parte indice
  * @return el indice completo
  */
 private int getIndex(short subi1, short subi2) {
  ByteBuffer bb = ByteBuffer.allocate(2);
  bb.order(ByteOrder.BIG_ENDIAN);
  bb.put((byte) subi1);
  bb.put((byte) subi2);
  short index = bb.getShort(0);

  return index;
 }

Para la ejecución de métodos nativos, según leí hay distintas formas de abordarlo, yo elegí la más simple, cuando detectamos el método nativo, obtenemos cual es, mirando su signatura y nombre, y usando una clase de ayuda llamada Natives hacemos su ejecución utilizando código Java, aunque podría hacerse de otras formas. Por ejemplo nuestro método print() escribe por pantalla, y para ello usa el método System.out.print().

Código ejecutarNative()
private int ejecutarNative() {
  JValue val = null;
  String sig = topFrame.getMethod().getFullNameAndSig();
  if (sig.equals(Natives.SIGS[0])) {
   val = Natives.fillInStackTrace(this);
  } else if (sig.equals(Natives.SIGS[1])) {
   val = Natives.print(this);
  } else if (sig.equals(Natives.SIGS[2])) {
   val = Natives.println(this);
  } else if (sig.equals(Natives.SIGS[3])) {
   val = Natives.getIntFromStr(this);
  }
  if (val != null) {
   topFrame.push(val);
   ejecutarXRETURN();
  } else
   ejecutarRETURN();
  return 0;
 }

Código print() en Natives.java
public static JValue print(JVM jvm) {
  JObject ostr = (JObject) jvm.topFrame.locals[0];
  JArray arraystr = (JArray) ostr.getField(0).getValue();
  StringBuffer sb = new StringBuffer();
  for (int i = 0; i < arraystr.nElems; i++) {
   sb.append(arraystr.get(i));
  }
  System.out.print(sb);
  return null;
 }
También os dejo la implementación de algunas de las instrucciones, he comentado el código para que quede más claro y más o menos creo que debería entenderse.

Código implementación algunas instrucciones
private void ejecutarNEW(int index) {
  JObject object;
  //usamos constant pool para obtener nombre de clase en base a su indice
  ConstantPool cp = topFrame.getConstantPool();
  ConstantClass cc = (ConstantClass) cp.getConstant(index,
    Constants.CONSTANT_Class);
  String className = cc.getBytes(cp);
  //cargamos clase y creamos objeto a traves de heap
  JClass jClass = classes.loadClass(className);
  object = heap.createObject(jClass);

  //añadimos objeto a la pila y saltamos parametros
  topFrame.push(object);
  topFrame.incPC(3);
 }
 
 private void ejecutarRETURN() {
  //return sin valor, simplemente volvemos al frame padre
  setTopFrame(topFrame.getCf());
 }
 
 private void ejecutarIRETURN() {
  if (topFrame.size() != 1)
   error(topFrame, "Tamaño de pila para return distinto de 1");
  JValue val = topFrame.pop();
  StackFrame previous = topFrame.getCf();
  if (previous == null) {
   error(topFrame, "No hay frame previo para return");
  } else {
   previous.push(val);
   setTopFrame(previous);
  }
 }
 
 //para este metodo usamos un truco a la hora de llamarlo,
 //las instrucciones const estan codificadas de manera consecutiva, 
 //asi obtenemos el valor correcto restando cada una a la primera
 private void ejecutarICONST(int n) {
  topFrame.push(new JInteger(n));
  topFrame.incPC();
 }
 private void ejecutarILOAD(byte pos) {
  topFrame.push(topFrame.locals[pos]);
  topFrame.incPC();
 }
 
 private void ejecutarISTORE(int pos) {
  JValue val = topFrame.operands.pop();
  topFrame.locals[pos] = val;
  topFrame.incPC();
 }
 
 private void ejecutarIADD() {
  //cada tipo tiene su clase concreta, así para sumar 
  //dos enteros usamos el metodo de clase y add a la pila
  JInteger op1 = (JInteger) topFrame.operands.pop();
  JInteger op2 = (JInteger) topFrame.operands.pop();
  topFrame.push(op1.add(op2));
  topFrame.incPC();
 }
 
 private void ejecutarIFEQ(int index) {
  //en base al valor en la pila saltamos a index o no
  JInteger val = (JInteger) topFrame.pop();
  if (val.getValue() == 0) {
   topFrame.incPC(index);
  } else {
   topFrame.incPC(3);
  }
 }

Por último la invocación de métodos, el mismo método lo usamos para los 3 tipos de invocación.

Código invocación de métodos
private void ejecutarINVOKEBC(Short stat, short[] code) {
  // get clase y method info a partir de BC
  ConstantPool cp = topFrame.getConstantPool();
  ConstantMethodref methodIndex = (ConstantMethodref) cp
    .getConstant(
      getIndex(code[topFrame.getPC() + 1],
        code[topFrame.getPC() + 2]),
      Constants.CONSTANT_Methodref);
  // get clase
  // modo largo, siguiendo cadena referencias
  // ConstantClass classIndex =(ConstantClass)
  // cp.getConstant(methodIndex.getClassIndex(),Constants.CONSTANT_Class);
  // ConstantString stringClassIndex=(ConstantString)
  // cp.getConstant(classIndex.getNameIndex(),Constants.CONSTANT_String);
  // ConstantUtf8 utf8ClassIndex=(ConstantUtf8)
  // cp.getConstant(stringClassIndex.getStringIndex(),Constants.CONSTANT_Utf8);
  // String className =utf8ClassIndex.toString();

  // USANDO ATAJO
  String className = methodIndex.getClass(cp);

  // get method
  ConstantNameAndType nameAndTypeIndex = (ConstantNameAndType) cp
    .getConstant(methodIndex.getNameAndTypeIndex());
  String methodName = nameAndTypeIndex.getName(cp);
  String signature = nameAndTypeIndex.getSignature(cp);

  JClass jClass = classes.loadClass(className);
  JMethod jMethod = jClass.getMethod(methodName, signature);

  // maximo argumentos
  int maxArgs = jMethod.getMaxArgs() + 1;

  // si es estatico disminuyo params
  if (stat != null)
   maxArgs--;
  // get pila en orden para parametros
  Stack<JValue> stack = topFrame.getParamsReverse(maxArgs);
  topFrame.clearParams(maxArgs);

  StackFrame newTopFrame;
  int desp = 0;
  if (stat != null) {
   newTopFrame = new StackFrame(topFrame, jMethod, jClass);
  } else {
   // si no es estatico, meto referencia en locals[0]
   desp = 1;
   JObject ref = (JObject) stack.pop();
   newTopFrame = new StackFrame(topFrame, jMethod, jClass, ref);
  }
  // paso parametros tras que se ha creado la estructura
  for (int j = 0; j < maxArgs - desp && !stack.empty(); j++) {
   JValue val = stack.pop();
   // si no es el primero y el anterior ocupa 2 espacios, lo desplazo
   if (j != 0
     && (newTopFrame.getLocals()[j - 1].type == Type.LONG || newTopFrame
       .getLocals()[j - 1].type == Type.DOUBLE)) {
    newTopFrame.getLocals()[j + desp + 1] = val;
   } else
    newTopFrame.getLocals()[j + desp] = val;
  }
  topFrame.incPC(3);
  setTopFrame(newTopFrame);
 }

Alaaaa, sí, todo esto para invocación de métodos, primero tenemos que obtener que método vamos a llamar, esa información esta en una constante MethodRef de la ConstantPool así que lo obtenemos usando el índice de su posición que viene codificado en los dos siguientes bytes de la instrucción. El método getConstant() de BCEL nos facilita realizar esta operación, el segundo parámetro sirve para especificar que tipo de constante queremos obtener, saltando una excepción si no es ese (útil para debug).

Tras eso ya tenemos la referencia al método pero necesitamos su clase! He dejado comentado la manera "larga", la que sigue la cadena de referencias de la ConstantPool, pero por suerte BCEL nos proporciona un método llamado getClass() para obtener directamente ese valor.

Como dije tenemos la referencia al método pero ni su nombre ni su signatura, esa información esta en una constante NameAndType, de nuevo usamos la ConstantPool y voila, ya podemos crear nuestro JClass y JMethod. Además necesitamos saber el número de parámetros del método.

El tratamiento de métodos static lo hacemos ahora, cuando no es static, una referencia al objeto que lo llama se guarda en la primera posición de variables locales, si lo es, simplemente disminuimos el valor. Otro punto que hay que notar es que el paso de parámetros se hace en orden contrario al de la pila, de ahí el uso del método auxiliar getParamsReverse(), que nos da la pila de parámetros en orden para luego meterlos en el array de variables locales.

Luego creamos el frame en función de si es static o no, y por último el paso de parámetros en sí. Básicamente va sacando elementos de nuestra pila de argumentos y los mete en el array de locales, pero hay que resaltar varias cosas. Primero si es static o no, de ahí el valor desp para no sobreescribir la referencia al objeto, y además los valores long y double, que en la JVM ocupan dos "espacios". En esta implementación ocupa 1 pues todo son JValue, pero de todos modos tenemos que hacer que ocupen dos pues las referencias en el bytecode serán a su posición real.

UFF, bueno todo eso sería para nuestra clase JVM, mucho curro y todavía solo hemos empezado porque... ¿Cómo implementamos las 3 partes que no tenemos? ¿Dónde se hace la lectura de los .class? Adelanto que de eso se ocupará nuestra clase ClassArea.

Bueno, de esa clase y del resto de nuestra JVM hablaré en la tercera parte y final (espero) de este tutorial.

Un saludo.


Tercera parte ya disponible!

jueves, 6 de junio de 2013

iPhone - Eliminar cifrado de una copia de seguridad de iPhone

Primero, si la copia esta cifrada no se puede descifrar, solo puedes tener acceso a ella teniendo la contraseña, pero si lo que te interesa es desactivar el cifrado para posteriores copias y por algún motivo no puedes deseleccionar la casilla de verificación para el cifrado de copias de seguridad de iPhone aun sabiendo la contraseña, el problema es que tienes que borrar los perfiles que tengas guardados en el iPhone.

Accedemos a ajustes->general->perfiles y vamos borrándolos, una vez hecho esto conectamos de nuevo el móvil y ya debería dejarnos, Apple siempre complicándonos la vida xD.

miércoles, 5 de junio de 2013

Webs que molan - Recommended Games

Alguna vez te has visto sin saber a que jugar, tanto juego y por donde empiezo? seguro que sí, pues bien os traigo la solución!


En esta web tienes organizados por consolas/plataformas una gran cantidad de juegos. Además para compatibles en Windows los tienes organizados por épocas!

Un sueño para todo jugón, sin más os dejo el enlace, ala!


martes, 4 de junio de 2013

Parodia Mago David Blaine

No sé porque hace unos días me vino a la cabeza esta parodia del mago David Blaine que cuando la vi me escojoné ampliamente, os la dejo por aquí mientras preparo la segunda parte de lo de la JVM.

Esta es la primera parte, hay unos cuantas más igual de buenas!



Un saludoo!