TEMA 7: Jamaica, macroensamblador de JVM Contenido 1. Arquitectura de la JVM .........................................................................................................2 2. Reglas léxico-sintácticas de Jamaica .....................................................................................2 3. Paquetes y clases .................................................................................................................3 4. Métodos ...............................................................................................................................3 5. Instrucciones ........................................................................................................................4 5.1 Runtime de la JVM (Cuando un método invoca a otro) .....................................................4 6. 5.2 Notación de las instrucciones .......................................................................................4 5.3 Carga de constantes .....................................................................................................4 5.4 Acceso a variables y parámetros ..................................................................................4 5.5 Operaciones con arrays ................................................................................................5 5.6 Acceso a atributos ........................................................................................................5 5.7 Instrucciones de tipos de datos ....................................................................................6 5.8 Creación de objetos y arrays ........................................................................................6 5.9 Instrucciones aritméticas y lógicas ...............................................................................6 5.10 Manipulación de la pila ................................................................................................7 5.11 Llamadas a métodos .....................................................................................................7 5.12 Instrucciones de saltos incondicionales ........................................................................7 5.13 Instrucciones de saltos condicionales ...........................................................................8 Macros .................................................................................................................................8 1. Arquitectura de la JVM TAREA 1 TAREA N Frame 1.k Frame N.k . . . . . . … Frame 1.1 Frame N.1 !!!"!#$%&'!!( !!!"!#$%&'!!( PC Zona de código y constantes Contador de PROGRAMA 1 . . . PC TAREA N PC !!!!!!"!#$%&'!!!!!!( FRAME PILA DE OPERANDOS MEMORIA DINÁMICA INSTANCIAS SP VARIABLES LOCALES PARÁMETROS - OBJETOS - ARRAYS !!!!!!"!#$%&'!!!!!!( DIREC. OBJETO PROPIO (this) !!!!!!!!!!!!"!#$%&'!!!!!!!!!!( JVM está basada en pila, no en registro. Para cada tarea hay una pila de frames y un contador de programa Los frames almacena información de los métodos que se están ejecutando. El frame activo es el que estará en la cima de la pila. El main será el FRAME 1.k (es el primero que se llama). L-0 va a trabajar con una sola pila de frames. 2. Reglas léxico-sintácticas de Jamaica Comentarios (Línea y bloque): igual que en Java Identificadores: igual que en Java Palabras reservadas: igual que en Java además de las instrucciones bytecode de la JVM Tipos de datos: igual que en Java o Primitivos: byte(1), short(2), int(4), long(8), char(2), float(4), double(8) y boolean (Jamaica los trata como enteros 0 ó 1) . o Referencia: objeto y array. Los macros comienzan por “%”. Las instrucciones bytecode y los macros no terminan en “;”. Ejemplo: int i; iconst_1 %println “hola” //instrucción bytecode //macro 3. Paquetes y clases Se definen con la misma sintaxis que Java. Cada clase se coloca en un fichero “.ja” package x; //Nombre del módulo que contiene a la clase (import y;)* //Paquetes/Clases importadas [public/private] class nombreClase { //atributos y métodos } Los atributos se declaran igual que en Java, pero NO se pueden inicializar (para inicializarlos se usa un constructor o un bloque estático). Hay tres paquetes que son autoimportados: java.lang.*, java.io.* y java.util.*. Existe una macro a nivel de clase que invoca al constructor de la clase padre: %default_constructor <public> 4. Métodos Cabecera/Prototipo: igual que en Java Cuerpo del método: (Declaración de variables | [Etiqueta] | Instrucción)* (cláusula CATCH)* Declaración de variables: igual que en Java Las variables hay que declararlas antes de usarlas Las instrucciones son bytecode o macros Se usa la cláusula CATCH para capturar/manipular excepciones: catch [className] (et_inicio, et_fin) et_manipulacion - Si no especificamos el className se captura java.lang.Throwables - et_inicio y et_fin son las etiquetas de comienzo (inclusive) y fin (exclusive) del bloque de captura. - et_manipulacion es la posición donde se salta si hay excepción 5. Instrucciones 5.1 Runtime de la JVM (Cuando un método invoca a otro) Cuando se invoca a un método: - Se apila la dirección del objeto - Se apilan los parámetros reales - Se reserva espacio para las variables locales - Se posiciona la pila de operandos - Se activa el nuevo frame m1{ … m2(2,5) … Nuevo Frame (frame de m2) } “manualmente” Llamada al método Variables locales Parámetros (2, 5) Dirección del objeto (m2) Frame ACTIVO Frame activo hasta la llamada al método (frame de m1) 5.2 Notación de las instrucciones (estado de la pila antes => estado de la pila después) Cargar colocar un valor en la cima de la pila Almacenar extraer un valor de la cima de la pila 5.3 Carga de constantes aconst_null: carga de referencia nula bipush número: carga un número de tipo byte sipush número: carga un número de tipo short iconst_m1: carga el valor -1 iconst_0(1…5): carga un entero de 0 a 5 lconst_0(1): carga un long 0 ó 1 fconst_0(1,2): carga un float 0,1 ó 2 dconst_0(1): carga un doublé 0 ó 1 ldc valor: carga un valor de cualquier tipo ldc 5.1 //double ldc (float) 5.1 //float (… =>…, null) (…=>…, número) (…=>…, número) (…=>…, -1) (…=>…, 0(1…5)) (…=>…, 0(1)) (…=>…, 0(1,2)) (…=>…, 0(1)) (…=>…, valor) 5.4 Acceso a variables y parámetros <tipo>load variable: carga el valor de la variable (…=>…, variable) <tipo>store variable: almacena el valor de la variable (…, variable=>…) <tipo> es: b (byte), s (short), i (int), l (long), c (char), f (float), d (double), a (referencia) aload this: carga la referencia al objeto actual. Ejemplo: var (variable local entera), par (parámetro entero) var = par iload par (…=>…, par) istore var (…, par=>…) 5.5 Operaciones con arrays Requieren que esté cargada la referencia al array: <tipo>aload: carga un elemento de un array (…, ref_array, índice=>…, ref_array[índice]) <tipo>astore: almacena el valor de la cima en un array (ref_array[índice] = valor) (…, ref_array, índice, valor=>…) arraylength: carga el número de elementos que tiene un array (…, ref_array=>…, num_elem) Ejemplo 1: iarr[3] = iarr[1] aload iarr iconst_3 aload iarr iconst_1 iaload iastore (…=>…, iarr) (…, iarr=>…, iarr, 3) (…, iarr, 3=>…, iarr, 3, iarr) (…, iarr, 3, iarr=>…, iarr, 3, iarr, 1) (…, iarr, 3, iarr, 1=>…, iarr, 3, iarr[1]) (…, iarr, 3, iarr[1]=>…) Ejemplo 2: i[2,3] aload i iconst_2 aaload iconst_3 iaload (…=>…, i) (…, i=>…, i, 2) (…, i, 2=>…, i[2]) (…,i[2]=>…, i[2], 3) (…,i[2], 3=>…, i[2,3]) 5.6 Acceso a atributos Atributos no estáticos (objetos en L-0) - Cargar el valor del atributo en la pila: getfield nombre_atrib tipo_atrib - Almacena el valor de la cima en el atributo: putfield nombre_atrib tipo_atrib (…,ref_objeto=>…,valor) (…,ref_objeto, valor=>…) Ejemplo: aload this getfield iarr int[] Atributos estáticos (clases no instanciables en L-0) - Cargar el valor del atributo en la pila: getstatic [NombreClase.] nombre_atrib tipo_atrib - Almacena el valor de la cima en el atributo: putstatic [NombreClase.] nombre_atrib tipo_atrib (…,=>…,valor) (…, valor=>…) Ejemplo: ClaseNoInst1.atr1 := objeto1.atr2; aload objeto1 (…=>…, objeto1) getfield atr2 int (…, objeto1=>…,objeto1.atr2) putstatic ClaseNoInst1.atr1 int (…,objeto1.atr2=>…) 5.7 Instrucciones de tipos de datos Convertir el tipo del element de la cima de la pila i2l (int to long) l2i (long to int) f2i (float to int) d2i (double to int) i2f (int to float) l2f (long to float) f2l (float to long) d2l (double to long) i2d (int to double) l2d (long to double) f2d (float to double) d2f (double to float) i2b (int to byte) i2s (int to short) En todos los casos tenemos que (…, valor(tipo)=>…,valor(tipo_nuevo)) Comprobar si la referencia de la cima (objeto) es de un tipo instanceof nombreClase (…, ref_objeto=>…, 0 ó 1) Devuelve 0 si el objeto es de nombreClase Devuelve 1 si el objeto NO es de nombreClase 5.8 Creación de objetos y arrays Crear objetos: crea una instancia nombreClase y apila la referencia. NO invoca al constructor (habría que hacerlo explícitamente). new nombreClase (…=>…, ref_objeto) Crear arrays unidimensionales: newarray tipo_primitivo anewarray nombreClase (…, num_componentes=>…, ref_array) (…, num_componentes=>…, ref_array) Ejemplo: formación 9 entero a; bipush 9 newarray entero astore a Ejemplo: formación 8 String s; bipush 8 anewarray String astore s Crear arrays multidimensionales: multianewarray tipo_dato ([])+ num_dimensiones (…, num_componentes dim1, num_componentes dim2, …=> …, ref_array) Ejemplo: formación 10,8 entero b; bipush 10 bipush 8 multianewarray entero [][] 2 astore b 5.9 Instrucciones aritméticas y lógicas Instrucciones aritméticas: <tipo>add (…, op1, op2=>…, op1+op2) <tipo>sub (…, op1, op2=>…, op1-op2) <tipo>mul <tipo>div <tipo>neg (…, op1, op2=>…, op1*op2) (…, op1, op2=>…, op1/op2) (…, op=>…, - op) Instrucciones lógicas: and (…, op1, op2=>…, op1&&op2) or (…, op1, op2=>…, op1||op2) xor (…, op1, op2=>…, op1 xor op2) Instrucción de incremento: (un elemento de un array no se puede incrementar usando esta instrucción) iinc variable (o atributo) cte_entera a:=a+2 iinc a 2 5.10 Manipulación de la pila pop: desapila la cima dup: duplica la cima swap: intercambia la cima (…, x=>…) (…, x=>…, x, x) (…, x, y=>…, y, x) 5.11 Llamadas a métodos Método no estático (pertenece a un objeto en L-0): invokevirtual [NombreClase.]NombreMetodo Signatura Ejemplo: invokevirtual Elemento.modificar(int) void Frame del método llamador: (…, ref_objeto, param_real1,…, param_realN => Frame del método llamado: =>…, ref_objeto, param_real1,…, param_realN, variables_locales) Método estático (pertenece a una clase no instanciable en L-0): invokestatic [NombreClase.]NombreMetodo Signatura Constructores o superclase: invokespecial [NombreClase.]NombreMetodo Signatura Ejemplo: m(3, a+2); aload this bipush 3 iload a iconst_2 iadd invokevirtual m(int, int) void 5.12 Instrucciones de saltos incondicionales goto etiqueta: salto incondicional return: vuelta de un método procedural (…, ref_objeto, par_real1,…, par_realN, var_locales =>…) <tipo>return: vuelta de un método funcional (…, ref_objeto, par_real1,…, par_realN, var_locales, valor =>…, valor) jsr etiqueta: salto a una subrutina dentro de un método ret: vuelta de una subrutina 5.13 Instrucciones de saltos condicionales Comparaciones de entero y salto if_icmp<comp> etiqueta <cmp> = eq, ne, gt, lt, le, ge (…, valor1, valor2 =>…) Comparación de objetos y salto (también vale para arrays) Dos objetos son iguales si apuntan al mismo sitio if_acmp[eq|ne] etiqueta (…,ref_objeto1, ref_objeto2=>…) ifnull etiqueta: salta si la cima es una referencia nula (…,ref_objeto=>…) ifnonnull etiqueta: salta si la cima no es una referencia nula Comparación de long, float y double lcmp: compara dos long (…, valor1, valor2=>…,1(0,-1)) fcmpg: compara dos float dcmpg: compara dos doublé Los tres métodos devuelven: 1 si valor1 > valor2 0 si valor1 = valor2 -1 si valor1 < valor2 Salto condicional if<cmp> etiqueta (…,1|0|-1=>…) Instrucción de selección switch (cte_entera : etiqueta)* default: etiqueta Ejemplo: (…, valor=>…) iload a switch 1: et_1 2: et_2 default: et_d 6. Macros Las macros deben estar dentro de los métodos %print [out|err] parámetro (, parámetro)*: parámetro puede ser una constante, variable, atributo o un elemento de un array. %println [out|err] parámetro (, parámetro)* Ejemplo: %println a, “ “, b %load parámetro: carga en la pila %set par = parámetro: asignación (par no puede ser una constante evidentemente) %object nombreClase: crea un objeto de tipo nombreClase (llama al constructor) %array tipo ([num_elementos])+ : creación de un array. %array_iterate nombreArray índice %end_iterate: iterador para un array Ejemplo: int a[]; %set a = %array int[] {9,8,7} int i; %array_iterate a i %println “a[“, i, “]=”, a[i] %end_iterate