sábado, 21 de junio de 2014

Here are some notes I use to setup my Ubuntu box a gateway to share my phone's data plan:

# Source: http://www.yourownlinux.com/2013/07/how-to-configure-ubuntu-as-router.html

1. Enable IP forwarding
    Enable the following in /etc/sysctl.conf
        net.ipv4.ip_forward=1

2. iptables:
    # To Wifi
    iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
    iptables -A FORWARD -i wlan0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT
    iptables -A FORWARD -i eth1 -o wlan0 -j ACCEPT

    # To USB connection
    iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
    iptables -A FORWARD -i eth1 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
    iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT

3. Possibly persist iptables:
    iptables-save > /etc/iptables.rules

lunes, 15 de noviembre de 2010

Conjunto de instrucciones de la JVM

Una instrucción en la JVM consiste en un opcode de un byte que especifica la operación que se va a realizar, seguida de cero o más operandos que proveen los argumentos para la operación. El número y tamaño de los operandos dependen del opcode.

La mayoría de las instrucciones codifican la información de tipo acerca de los operandos sobre los que aplican. Por ejemplo, la instrucción iload carga el contenido de una variable local, que debe ser un int, en la pila de operandos mientras que la instrucción fload hace lo mismo pero con floats. Es por eso que se dice que la mayoría de instrucciones son tipificadas. Algunas instrucciones como goto, que representa un salto incondicional, no requieren operandos. Las operaciones tipificadas suelen iniciar con la letra del tipo de operando que reciben.

Dado que la mayoría de instrucciones son tipificadas pero no pueden haber más opcodes que los que caben en un byte, las instrucciones proveen más soporte para algunos tipos que para otros, intencionalmente. Es por esto que se proveen instrucciones para cambiar de tipo a un valor. Esta tabla resume el soporte para los distintos tipos dentro del conjunto de instruciones de la JVM.

Es de notar que la mayoría de operaciones no tienen opciones para los tipos byte, char y short. No existen instrucciones que operen sobre boolean. Esta falta de soporte se apoya en el hecho de que, durante la compilación o ejecución, muchos de estos valores simplemente se representan como ints mediante sign-extension. Por tanto, la mayoría de operaciones sobre valores boolean, byte, char y short se llevan a cabo correctamente por instrucciones que operan sobre el tipo int.

A continuación presentamos un breve resumen sobre las instrucciones que consideramos serán de importancia. Los detalles sobre cada instrucción pueden encontrarse, como siempre, en la JVM specification, en el Capítulo 6. The Java Virtual Machine Instruction Set. Hablaremos un poco más en detalle de cada instruccion a medida que empecemos a compilar para la JVM.

Instrucciones de carga y almacenamiento
Las instrucciones de carga (load) y almacenamiento (store) transfieren valores entre el arreglo de variables locales y el stack de operaciones de un frame (para detalles consultar post previo):
  • Cargar una variable local en el stack de operandos: iload (para un int), aload (para una referencia), etc. 
  • Almacenar un valor del stack de operandos en una variable local: istore, astore.
  • Cargar una constante en el stack de operandos: ldc, ldc_w, ldc2_w, aconst_null, iconst_m1, iconst_<i>. 
Las instrucciones que acceden a fields de objetos y elementos de arreglos también transfieren data desde y hacia el stack de operandos.

Instrucciones aritméticas
Las instrucciones aritméticas computan un resultado que usualmente es una función de dos valores en el stack de operandos y hacen push al resultado de vuelta al stack. Existen dos tipos principales de instrucciones aritméticas: aquellas que operan sobre enteros y aquellas que operan sobre valores de punto flotante. Las operaciones también pueden variar en su comportamiento cuando ocurre overflow y durante una división dentro de cero. Nos interesan las siguientes operaciones aritméticas:
  • Suma: iadd
  • Resta: isub
  • Multiplicación: imul
  • División: idiv
  • Residuo (remainder): irem
  • Negación: ineg
  • Incremento de variable local: iinc
  • Comparación: dcmpg, dcmpl, fcmpg, fcmpl, lcmp
  • También se cuenta con operaciones para shift, bitwise OR, bitwise AND, y bitwise exclusive OR.
Operaciones de conversión de tipos
Estas instrucciones permiten la conversión entre los tipos numéricos soportados por la JVM. Pueden utilizarse para implementar conversiones en el código fuente o para mitigar la falta de ortogonalidad en el conjunto de instrucciones de la JVM. Tampoco descenderemos a detalles sobre este tipo de conversiones. Basta con mencionar que la JVM provee tanto conversiones de widening (pasar de un dato con una representación más pequeña a uno con una representación más grande) como de narrowing (lo contrario).

Creación y manipulación de objetos
En este punto vale la pena mencionar que los arreglos se consideran en la JVM como objetos con características particulares. En este sentido tanto los arreglos como las instancias de clases son objetos. A pesar de esto la JVM utiliza instrucciones distintas para crear y manipular a cada uno.
  • Crear una nueva instancia de una clase: new
  • Crear un nuevo arreglo: newarray, anewarray, multianewarray
  • Acceder a los fields de instancia: getfield, putfield.
  • Cargar un componente de un array en el stack de operandos: baload (boolean), caload (char), iaload (int), aaload (reference). 
  • Almacenar el valor desde el stack de operandos como un componente de un array: bastore, castore, iastore, aastore
  • Obtener el tamaño de un array: arraylength
  • Revisar las propiedades de una instancia de clase o un arreglo: instanceof, checkcast
Instrucciones de manejo del stack de operandos
Para el manejo directo del contenido del stack de operandos nos interesan las siguientes instrucciones: pop (desechar el primer elemento del stac), dup (duplicar el primer elemento del stack).

Instrucciones de transferencia de control
De este tipo encontramos las instrucciones condicionales y las incondicionales. Estaremos interesados en:
  • Saltos condicionales: ifeq, iflt, ifle, ifne, ifgt, ifge, if_icmpeq, if_icmpne, if_icmplt, if_icmpgt, if_icmple, if_icmpge, if_acmpeq, if_acmpne
  • Saltos incondicionales: goto, goto_w 
Vale la pena hacer mencionar que todas las instrucciones de transferencia de control condicionales que operan sobre int lo hacen mediante comparaciones de signo.

Invocación de métodos e instrucciones return
Existen cuatro instrucciones distintas para invocar un método dependieno de tipo de objeto del destino y del método (instancia, interfaz, estático y especial). Nos interesan únicamente:
  • invokevirtual: invoca un método de instancia de un objeto, este es el tipo de invocación normal en Java. 
  • invokespecial: invoca un método de instancia que requiere un manejo especial, ya sea un método de inicialización o un método de una superclass
De las instrucciones para retornar de un método, que se diferencian por el tipo de retorno, nos interesan: ireturn (usada para retornar valores de tipo boolean, byte, char, short o int) y areturn.  Además contamos con return que se utiliza en caso que el método sea declarado como void.

Una vez explicado todo esto podemos proseguir explicando cómo vamos a generar todo este bytecode. Pero esto en entradas posteriores.

La constant pool, campos, métodos y el atributo code dentro del .class

Continuando con lo que tratábamos anteriormente, hablaremos ahora sobre los cuatro elementos mencionados en el título.

La constant pool
Las instrucciones de la JVM hacen referencia a la información simbólica que se almacena en la constant_pool. Todas las entradas de esta tabla tienen el siguiente formato general:
    cp_info {
     u1 tag;
     u1 info[];
    }
Cada elemento en la constant_pool debe empezar con un tag de un byte que indica el typo de entrada. El contenido del array info variará con el valor de tag. Los valores válidos para el tag y sus respectivos valores se muestran aquí. Las únicas estructuras que nos interesan se describen a continuación:
  • CONSTANT_Class_info: Una estructura de este tipo se usa para representar a una clase o interfaz. Tiene la siguiente forma:
        CONSTANT_Class_info {
          u1 tag; 
          u2 name_index;
        }
    En donde tag tiene el valor 7 y name_index debe ser el índice de una localidad en la constant_pool cuyo contenido sea una estructura CONSTANT_Utf8_info que represente un nombre completo de una clase o interfaz.
  • CONSTANT_Fieldref_info, CONSTANT_Methodref_info: Los campos y métodos son representados por estructuras similares:
        CONSTANT_Fieldref_info {
            u1 tag; 
            u2 class_index;
            u2 name_and_type_index;
        }
        CONSTANT_Methodref_info{
            u1 tag;
            u2 class_index;
            u2 name_and_type_index;
         }
    En donde tag tiene el valor 9 para un Fieldref y 10 para Methodref. class_index debe ser un índice a una posición en la constant_pool cuyo contenido es una estructura CONSTANT_Class_info que representa a la clase que contiene la declaración del método y campo. Finalmente name_and_type_index debe ser el índice de una localidad en la constant_pool cuyo contenido sea una estructura CONSTANT_NameAndType_info que indica el nombre y el descriptor de un campo o méotod. El único caso especial de una estructura CONSTANT_Methodref_info es cuando esta empieza con un signo menor que (<), en cuyo caso el nombre debe ser el nombre especial <init> que representa el método inicializador de un objeto.
  • CONSTANT_String_info: Esta estructura representa constant objects de tipo String.
        CONSTANT_String_info {
          u1 tag; 
          u2 string_index;
        }
    En donde tag tiene el valor 8 y string_index debe apuntar a una localidad de la constant_pool cuyo contenido sesa una estructura CONSTANT_Utf8_info que represente una secuencia de caracteres con las que se inicializará el objeto String.}
  • CONSTANT_Integer_info: Esta estructura representa una constante numérica de 4 bytes:
        CONSTANT_Integer_info {
          u1 tag; 
          u4 bytes;
        }
    En donde tag tiene el valor 3 y bytes representa el valor de la constante.
  • CONSTANT_NameAndType_info: Esta estructura representa un campo o un método sin indicar a qué clase o interface pertenece:
        CONSTANT_NameAndtype_info {
          u1 tag;
          u2 name_index;
          u2 descriptor_index;
        }
    Aquí tag tiene el valor 12 y name_index debe ser el índice válido de una localidad en la constant_pool cuyo contenido sea una estructura CONSTANT_Utf8_info que represente un nombre completo de una clase o interfaz. Por otro lado descriptor_index debe ser el índice válido de una localidad en la constant_pool cuyo contenido sea una estructura CONSTANT_Utf8_info que represente un descriptor.
  • CONSTANT_Utf8_info: Esta estructura se utiliza para representar cadenas de caracteres constantes. La Sección 4.4.7 de la JVM specification habla sobre los detalles de la codificación de caracteres. La estructura consiste en:
        CONSTANT_Utf8_info {     
            u1 tag;
            u2 length 
            u1 bytes[length];     
        }
    En esta estructura el valor de tag es 1, length da el numero de bytes en el arreglo bytes, y bytes contiene los bytes de la cadena.
Campos
Cada field se describe por un campo field_info con la siguiente estructura:
    field_info {
        u2 access_flags;
        u2 name_index;
        u2 descriptor_index;
        u2 attributes_count;
        attribute_info attributes[attributes_count];
    }
En donde cada elemento se describe como sigue:
  • access_flags: Al igual que las flags para las clases, este elemento es una máscara usada para denotar los permisos de acceso y propiedades de este campo. La descripción de las opciones se encuentra en esta tabla. Para nuestros fines nos basta con que todos los fields sean públicos, por lo que todos nuestros access_flags se estableceran como 0x0001.
  • name_index: el valor de este campo debe ser el índice de una localidad de la constant_pool cuyo valor sea una estructura CONSTANT_Utf8_info que represente el nombre de un field almacenado como un identificador. 
  • descriptor_index: el valor de este campo debe ser un índice cuyo destino sea una CONSTANT_Utf8_info que contenga el descriptor de este campo.
  • attributes_count y attributes[]: similar al caso de los atributos de la clase, estos atributos no son de interés para el compilador que intentamos desarrollar.
Métodos
Cada método, incluyendo a los métodos de inicialización, se describen por una estructura method_info como sigue:
    method_info {
        u2 access_flags;
        u2 name_index;
        u2 descriptor_index;
        u2 atributes_count;
        attribute_info attributes[attributes_count];
    } 
En donde los elementos contiene la siguiente estructura:
  • access_flags: similar que para los campos, nos interesaremos únicamente en métodos públicos, por lo que estableceremos el valor de este campo a 0x0001. Las demás opciones se encuentran aquí.
  • name_index: el contenido de la dirección apuntada por este campo en la constant_pool debe ser una estructura CONSTANT_Utf8_info que represente el nombre de un método en Java o bien los nombres espciales de métodos <init> o <clinit> (no entraremos en detalle).
  • descriptor_index: el valor de este elemento debe ser el índice de una localidad en la constant_pool que contenga una estructura CONSTANT_Utf8_info con el descriptor del método. 
  • attributes_count y attributes[]: Los valores de estos campos son la cantidad de atributos en el método y la tabla con dichos atributos. En el caso de los métodos estamos especialmente interesados en el atributo code, del que hablaremos a continuación.
El atributo code
Este atributo es de tamaño variable y se utiliza en la tabla de attributos de las estructuras method_info. Contiene las instrucciones de la JVM y la información auxiliar para un solo metodo, ya sea de instancia o de inicialización. La estructura de este atributo es la siguiente:
    Code_attribute {
        u2 attribute_name_index;
        u4 attribute_length;
        u2 max_stack;
        u2 max_locals;
        u4 code_length;
        u1 code[code_length];
        u2 exception_table_length;
        {   u2 start_pc
            u2 end_pc;
            u2 handler_pc;
            u2 catch_type;
        }   exception_table[exception_table_length];
        u2 attributes_count;
        attribute_info attributes[attributes_count]; 
    }
Nos interesarán los siguientes elementos:
  • attribute_name_index: Debe ser un apuntador a una estructura CONSTANT_Utf8_info que represente la cadena "Code".
  • attribute_length: Este campo contiene el largo del attribute, excluyendo los seis bytes iniciales.
  • max_stack: este valor indica la profundiad máxima que puede alcanzar el método en cualquier punto durante su ejecución. 
  • max_locals: este valor indica el número de variables locales que deben reservarse en el arreglo de un frame asociado a éste método, incluyendo la svariables usadas para pasar parámetros durante su invocación. 
  • code_length: este valor indica el número de bytes en el arreglo code para éste método. Este arreglo no debe estar vacío.
  • code[]: este arreglo provee los bytes actuales de código de la JVM que implementan el método. Los detalles acerca de las restricciones para el contenido de este arreglo se describen en la Sección 4.8 Constraints on Java Virtual Machine Code de la JVM specification.
Con los elementos anteriormente descritos podemos ya tomar un programa un poco más complejo en Java tal como:
//StructA.java
public class StructA{
    public int A = 3;
    public int getA(){
        return A; 
    }
}
Y analizar los distintos elementos que obtenemos al decompilarlo, ya sea utilizando las herramientas de oolong o javap:
//StructA.class.Dump
000000 cafebabe          magic = ca fe ba be 
000004 0000              minor version = 0
000006 0032              major version = 50
000008 0013              19 constants
00000a 0a0004000f           1. Methodref class #4 name-and-type #15
00000f 0900030010           2. Fieldref class #3 name-and-type #16
000014 070011               3. Class name #17
000017 070012               4. Class name #18
00001a 010001               5. UTF length=1
00001d 41                                 A
00001e 010001               6. UTF length=1
000021 49                                 I
000022 010006               7. UTF length=6
000025 3c696e69743e                       <init>
00002b 010003               8. UTF length=3
00002e 282956                             ()V
000031 010004               9. UTF length=4
000034 436f6465                           Code
000038 01000f               10. UTF length=15
00003b 4c696e654e756d6265725461626c65     LineNumberTable
00004a 010004               11. UTF length=4
00004d 67657441                           getA
000051 010003               12. UTF length=3
000054 282949                             ()I
000057 01000a               13. UTF length=10
00005a 536f7572636546696c65               SourceFile
000064 01000c               14. UTF length=12
000067 537472756374412e6a617661           StructA.java
000073 0c00070008           15. NameAndType name #7 descriptor #8
000078 0c00050006           16. NameAndType name #5 descriptor #6
00007d 010007               17. UTF length=7
000080 53747275637441                     StructA
000087 010010               18. UTF length=16
00008a 6a6176612f6c616e672f4f626a656374   java/lang/Object
00009a 0021              access_flags = 33
00009c 0003              this = #3
00009e 0004              super = #4
0000a0 0000              0 interfaces
0000a2 0001              1 fields
                         Field 0:
0000a4 0001                 access flags = 1
0000a6 0005                 name = #5<A>
0000a8 0006                 descriptor = #6<I>
0000aa 0000                 0 field/method attributes:
0000ac 0002              2 methods
                         Method 0:
0000ae 0001                 access flags = 1
0000b0 0007                 name = #7<<init>>
0000b2 0008                 descriptor = #8<()V>
0000b4 0001                 1 field/method attributes:
                            field/method attribute 0
0000b6 0009                    name = #9<Code>
0000b8 00000026                length = 38
0000bc 0002                    max stack: 2
0000be 0001                    max locals: 1
0000c0 0000000a                code length: 10
0000c4 2a                      0 aload_0
0000c5 b70001                  1 invokespecial #1
0000c8 2a                      4 aload_0
0000c9 06                      5 iconst_3
0000ca b50002                  6 putfield #2
0000cd b1                      9 return
0000ce 0000                    0 exception table entries:
0000d0 0001                    1 code attributes:
                               code attribute 0:
0000d2 000a                       name = #10<LineNumberTable>
0000d4 0000000a                   length = 10
                                  Line number table:
0000d8 0002                       length = 2
0000da 00000001                      start pc: 0 line number: 1
0000de 00040002                      start pc: 4 line number: 2
                         Method 1:
0000e2 0001                 access flags = 1
0000e4 000b                 name = #11<getA>
0000e6 000c                 descriptor = #12<()I>
0000e8 0001                 1 field/method attributes:
                            field/method attribute 0
0000ea 0009                    name = #9<Code>
0000ec 0000001d                length = 29
0000f0 0001                    max stack: 1
0000f2 0001                    max locals: 1
0000f4 00000005                code length: 5
0000f8 2a                      0 aload_0
0000f9 b40002                  1 getfield #2
0000fc ac                      4 ireturn
0000fd 0000                    0 exception table entries:
0000ff 0001                    1 code attributes:
                               code attribute 0:
000101 000a                       name = #10<LineNumberTable>
000103 00000006                   length = 6
                                  Line number table:
000107 0001                       length = 1
000109 00000004                      start pc: 0 line number: 4
00010d 0001              1 classfile attributes
                         Attribute 0:
00010f 000d                 name = #13<SourceFile>
000111 00000002             length = 2
000115 000e                 sourcefile index = #14
Done.
Por ejemplo, vemos que la declaración de la variable de instancia public int A se tradujo en el campo Fieldref_class de la línea 6, que asocia este campo a la clase descrita en la línea 3 (cuyo nombre está en la posición 17, StructA) y al NameAndType de la posición 16 (que relaciona el nombre A con el descriptor I, el nombre y descripción de este campo).

También podemos notar, aunque todavía no sepamos los detalles sobre el set de instrucciones de la JVM, que la asignación para la variable de instancia A se lleva a cabo en las líneas 60 y 61 que se encuentran dentro del método <init>, a saber el constructor de esta clase.

Y hablando de métodos podemos también notar la diferencia entre los descriptores para el método constructor (()V) y para el método getA() definido por nosotros (()I).

Lo que sigue es entrar en detalle sobre el set de instrucciones de la JVM. Hasta aquí por el momento.

    La estructura de un .class

    Oolong
    Para la investigación de la estructura de un .class, además de la herramienta javap de la que se habló un poco en nuestro primer post, utilizaremos una nueva herramienta llamada oolong, un lenguaje ensamblador para la JVM basado en jasmin. Este es el ensamblador que se utiliza en el libro Programming for the Java virtual machine. Esta diseñado para no tener que involucrarnos con los bytes directamente aunque es casi equivalente al bytecode que se generará finalmente.

    La mejor herramienta que he podido encontrar para jugar con él es un plugin para jedit con el que podemos decompilar un .class y que, además de una descripción similar a la provista por javap, nos da la dirección y el contenido en hex de los bytes.

    Por ejemplo, para la misma entrada que anteriormente:
    //StructA.java
    public class StructA{}
    
    Compilamos y utilizamos la opción dump class y obtenemos el la siguiente información:
    //StructA.class.Dump
    000000 cafebabe          magic = ca fe ba be 
    000004 0000              minor version = 0
    000006 0032              major version = 50
    000008 000d              13 constants
    00000a 0a0003000a           1. Methodref class #3 name-and-type #10
    00000f 07000b               2. Class name #11
    000012 07000c               3. Class name #12
    000015 010006               4. UTF length=6
    000018 3c696e69743e                       <init>
    00001e 010003               5. UTF length=3
    000021 282956                             ()V
    000024 010004               6. UTF length=4
    000027 436f6465                           Code
    00002b 01000f               7. UTF length=15
    00002e 4c696e654e756d6265725461626c65     LineNumberTable
    00003d 01000a               8. UTF length=10
    000040 536f7572636546696c65               SourceFile
    00004a 01000c               9. UTF length=12
    00004d 537472756374412e6a617661           StructA.java
    000059 0c00040005           10. NameAndType name #4 descriptor #5
    00005e 010007               11. UTF length=7
    000061 53747275637441                     StructA
    000068 010010               12. UTF length=16
    00006b 6a6176612f6c616e672f4f626a656374   java/lang/Object
    00007b 0021              access_flags = 33
    00007d 0002              this = #2
    00007f 0003              super = #3
    000081 0000              0 interfaces
    000083 0000              0 fields
    000085 0001              1 methods
                             Method 0:
    000087 0001                 access flags = 1
    000089 0004                 name = #4<<init>>
    00008b 0005                 descriptor = #5<()V>
    00008d 0001                 1 field/method attributes:
                                field/method attribute 0
    00008f 0006                    name = #6<Code>
    000091 0000001d                length = 29
    000095 0001                    max stack: 1
    000097 0001                    max locals: 1
    000099 00000005                code length: 5
    00009d 2a                      0 aload_0
    00009e b70001                  1 invokespecial #1
    0000a1 b1                      4 return
    0000a2 0000                    0 exception table entries:
    0000a4 0001                    1 code attributes:
                                   code attribute 0:
    0000a6 0007                       name = #7<LineNumberTable>
    0000a8 00000006                   length = 6
                                      Line number table:
    0000ac 0001                       length = 1
    0000ae 00000001                      start pc: 0 line number: 1
    0000b2 0001              1 classfile attributes
                             Attribute 0:
    0000b4 0008                 name = #8<SourceFile>
    0000b6 00000002             length = 2
    0000ba 0009                 sourcefile index = #9
    Done. 

    El formato .class
    A continuación se provee una descripción relativamente rápida del formato utilizado por la JVM. La descripción completa y avanzada se encuentra en el Capítulo 4 de la JVM specification. Una tabla un tanto más accesible la podemos encontrar en wikipedia.

    Un archivo class consiste de una sola estructura ClassFile como sigue:
        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];
        
     
    En donde u2 o u4 hacen referencia al número de bytes que requiere cada elemento. Los elementos se detallan como sigue:
    • magic: provee el número mágico que identifica a un formato class; tiene el valor 0xCAFEBABE.
    • minor_version, major_version: Estos números detallan la versión del formato class. Para efectos prácticos mantendremos como 0 y 50 respectivamente.
    • constant_pool_count: este valor es igual al número de entradas en la constant_pool más uno. 
    • constant_pool[]: es una tabla de estructuras que representan varias constantes string, nombre de clases, y campos (fields) y otras constantes referidas dentro de la estructura ClassFile y sus subestructuras. El formato de cada entrada en esta tabla es indicado por su byte tag en la estructura cp_info. Esta tabla se indexa desde 1 hasta constant_pool_count-1.
    • access_flags: estos valores conforman una máscara de banderas que denotan los permisos y propiedades de esta clase. Los detalles de cada bandera pueden encontrarse aquí. De nuevo, para efectos prácticos todas nuestras clases serán públicas herderas de la clase Object, por lo que el valor de access_flags siempre será 0x0021.
    • this_class y super_class: los valores de estos elementos deben ser índices de la constant_pool cuyo contenido sea una estructura CONSTANT_Class_info que represente a la clase definida por este archivo class y su clase super, respectivamente. Detalles sobre esta estructura más adelante.
    • interfaces_count y interfaces[]: Dado que el compilador que queremos desarrollar no involucra ninguna clase de herencia, estos elementos no nos son relevantes. Solo nos interesa saber que el valor de interfaces_count puede ser cero, y la estructura interfaces[] estar vacía.
    • fields_count: da la cantidad de estructuras field_info en la tabla fields. Las estructuras field_info representan a cualquier campo (ya sea variable de instancia o de clase), declarado por esta clase o interfaz.
    • fields[]: cada entrada en esta tabla debe ser una estructura field_info que describa completamente a cada campo declarado en esta clase o interfaz (no incluye campos heredados). 
    • methods_count y methods[]: de manera similar a las estructuras anteriores, el primer campo da la cantidad de entradas en el segundo. El segundo consiste en una tabla de estructuras de tipo method_info. Nuevamente, por cuestiones prácticas no nos interesarán los métodos de tipo abstracto, aunque la JVM los soporten. Es necesario aclarar que esta tabla incluye también los métodos inicializadores (constructures) de la clase, mas no a los métodos heredados de superclasses o superinterfaces.
    • attributes_count y attributes[]: los atributos ayudan a definir información sobre las estructuras. En el caso de los atributos de una estructura ClassFile, la JVM specification solo define dos: SourceFile y Deprecated, ambos opcionales. Tampoco entraremos en detalle sobre estos atributos, aunque vale la pena hacer notar que la especificación deja las puertas abiertas para definir y trabajar con atributos personalizados, si bien no esta permitido que estos atributos afecten la semántica de un archivo class.
    Casi todos estos elementos podemos observaros en el fragmento anterior de código: La constant_pool que abarca de la línea 6 a la 25, los access_flags en la línea 26, la definición del único método constructor de la línea 33 a la 53, etc.

    Lo siguiente es entrar en detalle sobre algunas estructuras que son de especial importancia para nuestro objetivo. Esto lo dejaremos para la próxima entrada. Sin embargo, antes de terminar es necesario hablar sobre otro tema importante: descriptores.

    Descriptores
    Un descriptor (o bien, descriptor) es una cadena que representa el tipo de un campo o de un método. Los descriptores se representan en el formato de un archivo class utilizando cadenas UTF-8 y se especifican mediante las siguiente gramáticas.

    Descriptores de campos
    Representa el tipo de una variable de instancia, de clase o local.
    FieldDescriptor -> FieldType
    ComponentType -> FieldType
    FieldType -> BaseType | ObjectType | ArrayType
    BaseType -> B | C | D | F | I | J | S | Z
    ObjectType -> L<classname>;
    ArrayType -> [ ComponentType
    Donde los símbolos en negrita son caracteres ASCII y <classname> representa el nombre completo de una clase.
    La interpretación de los tipos de campos se muestra en esta tabla.
    De aquí que, por ejemplo, el descriptor de una variable de tipo int sea simplemente I, el de una variable de instancia de tipo Object sea Ljava/lang/Object; y el de un arreglo tridimensional de double de la forma double d[][][]; sea [[[D.

    Descriptores de métodos
    Un descriptor de método representa los parámetros que toma el método y el valor que retorna:
    MethodDescriptor -> ( ParameterDescriptor* ) ReturnDescriptor
    ParameterDescriptor -> FieldType
    ReturnDescriptor -> FieldType | V
    Donde V indica que el método retorna void. De esta gramática que el descriptor para un método como
       Object mimetodo(int i,double d, Thread t) 
    sea
       (IDLjava/lang/Thread;)Ljava/lang/Object;.

    Un ejemplo práctico de estos descriptores lo vemos en la línea 12 del código anterior, en donde se especifica el descriptor del método constructor para nuestra clase StructA.java.

    Organización de la JVM

    Para comenzar, la demora en las últimas entradas se debió a dos libros, de más interesantes, con los que me topé: Programming for the Java virtual machine, de Joshua Engel (1999) y Modern compiler implementation in Java, Second Edition de Andrew W. Appel (2002). Luego de dedicar un tiempo a su lectura, espero poder organizar de mejor manera los temas a exponer en esta secuencia.

    Una máquina de pila
    Vale la pena iniciar aclarando que la JVM, a diferencia por ejemplo de la arquitectura x86, sigue el concepto de las máquinas basadas en pilas (stack machines). Citando al libro del dragón:
    En una máquina basada en pila, las operaciones se realizan metiendo operandos en una pila y después llevando a cabo las operaciones con los operandos en la parte superior de la pila. (...) Estas máquinas desaparecieron casi por completo, ya que se creía que la organización de la pila era demasiado limitante y requería demasiadas operaciones de intercambio y copiado. No obstante, las arquitecturas basadas en pila revivieron con la introducción de la Máquina virtual de Java (JVM).
    El hecho de que la estructura de la JVM no sea diseñado hacia ninguna arquitectura en particular provee una visión más abstracta de la memoria. En lugar de dar acceso al nivel de bits y bytes de la memoria, la JVM trata la memoria como una colleción de objetos.

    Esto permite un mejor control sobre qué programas pueden acceder a qué partes de la memoria. Los desarrolladores de la JVM crearon un conjunto de reglas que deben aplicar a todos los programas que se ejecuten y que aseguran a los usuarios que los programas no intentarán dañar el sistema. El algoritmo que lleva a cabo todo este control recibe el nombre de verificación y se ejecuta antes que el mismo programa por seguridad.

     Organización de la JVM
    Conceptualmente la JVM se divide en cuatro espacios diferentes:
    • Class area: que almacena las constantes y el código.
    • Java stack: que mantiene registro de qué invocaciones a métodos se han hecho y la data asociada a cada método. 
    • Heap: donde se almacenan los objetos.
    • Native method stack: consultar aquí.
    Nos compete únicamente la información relacionada las primeras dos áreas.

    Class area
    Esta área almacena las clases que se cargan en el sistema. Las implementaciones de los métodos se mantienen en un method area y las constantes en una runtime constant pool. Para cada clase se almacena propiedades como:
    • Superclass
    • Lista de interfaces
    • Lista de campos (fields)
    • Lista de métodos y de constantes
    La runtime constant pool es una representación de la tabla constant_pool en un archivo class (detalles en entradas posteriores) que contiene varios tipos de constantes, desde literales numéricas que se conocen durante la compilación hasta referencias a métodos y campos que deben resolverse durante la ejecución.

    La runtime constant pool para cada clase se asigna de la method area y se construye cuando la clase es creada por la JVM

    Java stack
    Cada vez que se invoca un método, un nuevo espacio de datos llamado stack frame es creado. Colectivamente, el conjunto de stack frames se les llama java stack y existe uno de estos por cada thread de la JVM.

    El frame hasta arriba de la java stack muestra el lugar actual de ejecución y se llama el frame activo. Cuando un método termina su ejecución y retorna, el frame activo desaparece y el frame por debajo de ese vuelve a ser activo.

    Cada stack frame tiene una pila de operandos, un arreglo de variables locales, una referencia a la runtime constant pool de la clase a la que pertenece y un puntero a la instrucción que se está ejecutando (PC), que se encuentra en la method area. Es de notar que todos los threads de la JVM comparten la method area, aunque cada uno mantenga su propia pila de frames, es decir que un frame solo puede ser referenciado por un thread. Estos frames se utilizan para almacenar datos y resultados parciales, retornar valores de métodos y disparar las excepciones.

    El tamaño del arreglo de variables locales y la pila de operandos para un frame deben determinarse en tiempo de compilación y proveerse junto con el código para el método asociado a cada frame. Por lo mismo, el tamaño del frame como estructura de datos puede ser variable para cada método.
      

    Arreglo de variables locales
    El tamaño de este arreglo para cada frame debe proveerse en la representación binaria de una clase o interfaz, además del código asociado con el frame. Una sola localidad puede almacenar valores de tipo boolean, byte, char, short, int, float, reference o returnAddress (punteros a opcodes de instrucciones JVM, utilizados por las instrucciones de bifurcación a subrutinas). Un par de variables locales pueden almacenar un valor de tipo long o double. En este punto el lector habrá notado que nos referimos a tipos dentro de la JVM. Esta es otra característica que diferencia a la JVM de otras arquitecturas: las instrucciones (con dos excepciones) estan asociadas a tipos particulares de datos.

    Las posiciones en este arreglo están indexadas, siendo 0 la posición de la primera variable local. Un valor de tipo long o double ocupa dos posiciones consecutivas, aunque solo puede ser direccionado usando el valor más pequeño (esto, entre otras cosas, lo garantiza el algoritmo de verificación).

    Durante la invocación a un método, los parametros se reciben en este arreglo. En el caso particular de la invocación a un método de instancia (el único de interés aquí) la variable local 0 recibe siempre una referencia del objeto sobre el que se está invocando el método (this en el lenguaje Java). 

    Pilas de operandos (operand stacks)
    Cada frame contiene una pila cuyo tamaño máximo debe determinarse en tiempo de compilación, similar al arreglo de variables locales.

    La pila de operandos esta vacía cuando el frame que la contiene se crea. La JVM provee instrucciones para cargar constantes o variables locales o de instancia en este stack. Otras instrucciones toman operandos de esta pila, operan sobre ellos y regresan el resultado a la pila. Esta pila también se utiliza para preparar parámetros que deban ser pasados a métodos, y recibir los valores de retorno de los métodos.

    Cada entrada en esta pila puede contener un valor de cualquier tipo de la JVM, incluyendo long o double.

    Es importante observar que la estructura del Java stack dentro de la JVM implementa hasta cierto punto y simplifica las nociones que se tratan en el capítulo 7.2 'Asignación de espacio en la pila' del libro del dragón: en concreto el tema de los registros de activación por cada invocación a un método. El que la JVM se encargue de crear y manipular frames por cada invocación a método, además de las estructuras internas a cada frame que permiten almacenar y trabajar con los datos locales, implica un gran cambio con respecto a arquitecturas en donde la memoria se ve como una gran arreglo de bytes direccionables.

    martes, 26 de octubre de 2010

    Compilando para la JVM

    Este es el inicio de una serie de entradas sobre la aventura de compilar para la Java Virtual Machine (JVM) como parte de un curso de compiladores en la universidad. Por tanto, se asume que el lector conocerá elementos básicos del lenguaje de programación Java (primer, más no único, usuario de la JVM): Data types, primitivos, referencias, objetos, clases, métodos.

    Para entrar en contexto, la idea es convertir programas escritos en una gramática libre de contexto similar a esta y unas reglas semánticas muy básicas, a bytecode con la estructura de un .class de la JVM.

    De entrada les recomiendo echar un vistaso a tres links fundamentales (todos en inglés): esteeste y la especificación de la JVM. Nada que google no pueda revelar, pero resulta bastante útil tenerlos a la mano. 

    ¿Qué es la JVM?
    La respuesta a esta pregunta se encuentra, al menos oficialmente, en The Java Virtual Machine Specification, que define tres cosas:
    • Un conjunto de instrucciones (bytecodes) con su respectivo significado.
    • Un formato de archivos llamado class, que se usa para transmitir bytecodes y demás estructura de una forma independiente de plataforma. 
    • Un algoritmo para verificar que los programas no comprometan la integridad de la JVM: verificación
    Hablaremos a detalle sobre los primeros dos elementos de esta especificación más adelante.

    javap - The Java Class File Diassembler
    Una herramienta que será de mucha utilidad para analizar los .class generados por el compilador de java es javap. Su descripción en man javap. Los flags a utilizar:
    •  -l: 'Prints out line and local variable tables'
    • -c: 'Prints out diassembled code (...) for each of the methods in the class'
    • -s: 'Prints internal type signatures'
    • -verbose: 'Prints stack size, number of locals and args for methods'
    Es de interés esta herramienta pues lo que nos urge es la generación de JVM bytecode similar a la que lleva a cabo javac.

    Los flags anteriores nos dan una idea de los elementos a investigar: local variable tables, stack size, number of args, etc.

    Comenzando con algo sencillo:
    //StructA.java
    public class StructA{}
    
    Compilando y luego utilizando javap:
    $ javac StructA.class
    $ javap -c -l -s -verbose StructA
    Compiled from "StructA.java"
    public class StructA extends java.lang.Object
      SourceFile: "StructA.java"
      minor version: 0
      major version: 50
      Constant pool:
    const #1 = Method #3.#10; //  java/lang/Object."<init>":()V
    const #2 = class #11; //  StructA
    const #3 = class #12; //  java/lang/Object
    const #4 = Asciz <init>;
    const #5 = Asciz ()V;
    const #6 = Asciz Code;
    const #7 = Asciz LineNumberTable;
    const #8 = Asciz SourceFile;
    const #9 = Asciz StructA.java;
    const #10 = NameAndType #4:#5;//  "<init>":()V
    const #11 = Asciz StructA;
    const #12 = Asciz java/lang/Object;
    {
    public StructA();
      Signature: ()V
      LineNumberTable: 
       line 1: 0
      Code:
       Stack=1, Locals=1, Args_size=1
       0: aload_0
       1: invokespecial #1; //Method java/lang/Object."<init>":()V
       4: return
      LineNumberTable: 
       line 1: 0
    }
    
    Primeras cosas a observar:
    • La existencia de una constant pool de aspecto similar a una tabla de símbolos.
    • La definición de un método StructA con signature ()V. Además, la definición de un segmento code dentro de éste método, con variables Stack, Locals y Args_size.
    • Las instrucciones aload_0, invokespecial y return numeradas dentro del segmento de code. Descripciones para estas instrucciones aquí.
    Vale la pena también notar que esta representación podría servir como código intermedio en una de las fases del compilador.