2011-12-12 7 views
6

Estoy tratando de hacer un manejo de errores en bytecode java. La primera vez que traté de poner en práctica algunas subrutinas de captura similar, en los que me gustaría comprobar la condición de error, y salta a la subrutina apropiada, un poco como:¿Tratando con Try/Catch Exceptions en Java bytecode? ("altura de la pila inconsistente")

iconst_1 
    iconst_0 
    dup 
    ifeq calldiverr 
    goto enddivtest 
calldiverr: 
    jsr divError 
enddivtest: 
    idiv 

...More instructions... 

divError: 
    getstatic java/lang/System/out Ljava/io/PrintStream; 
    ldc "Oh dear you divided by 0!" 
    invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V 

El problema con lo anterior es que cuando tengo varias instrucciones que salta a esta subrutina, recibo un mensaje de error cuando ejecuto el bytecode, diciendo que la altura de la pila es inconsistente.

Quizás usar excepciones es la mejor manera de evitar esto?

De algunas google he encontrado que se pueden crear instancias de clases de excepción y se inician con algo como:

new java/lang/Exception 
dup 
ldc "exception message!" 
invokespecial java/lang/Exception/<init>(Ljava/lang/String;)V 

También he descubierto que se puede tirar con athrow y esto parece bien.

Lo que me confunde es exactamente cómo se atrapan las excepciones. Parece que hay una "Tabla de excepciones" mágica que combina arrojar y capturar excepciones, pero no sé cómo definir una de ellas al escribir bytecode desde cero (y ensamblar usando Jasmin). ¿Puede alguien decirme el secreto de crear una tabla de excepciones? ¿Y posiblemente me dé un ejemplo de manejo de excepciones que se ensamblará con jasmin?

Respuesta

2

Al final se me ocurrió ab solución de etter que jsr - definir un método usando .method en Jasmin. Acabo de utilizar invokestatic para llamar a mi controlador de errores una vez que había detectado el error.

Para aquellos que buscan un manejo de excepciones real: creo que la definición de la tabla de excepciones en Jasmin se puede hacer usando .catch, pero no lo he visto porque la definición del método resolvió mi problema.

Editar:

Yo tengo que mirar .catch al final, y nos pareció que es muy fácil de usar. Está documentado here.

0

En primer lugar, vale la pena señalar que los archivos de clase de la versión 51.0 pueden no contener la instrucción jsr. Repite el código o usa un método.

En cada punto del bytecode, se debe conocer el tipo estático de cada elemento del marco. Cada fotograma no es una pila de llamadas.

Generalmente no querrás jugar con grandes cantidades de fichas. Almacene los temporales en variables locales para mantener las cosas simples.

Si se lanza una excepción, obviamente el marco podría haber tenido los contenidos de cualquier lugar que la excepción podría haber arrojado. Entonces los contenidos son descartados y reemplazados por la excepción. No podría regresar y reanudar para usar el contenido del marco de todos modos.

0

Las reglas para verificar jsr son bastante complicadas, y como Tom indicó que el opcode está en desuso. Por lo tanto, es mejor evitarlo.

Mi memoria en jsr es un poco borrosa, pero ...

(Actualizado) Hay una regla en la verificación de código de bytes de Java que donde dos flujos de control se unen la profundidad de la pila debe ser idéntica a lo largo de las dos ramas. jsr subrutinas están exentas de esta regla a un punto: múltiples puntos de excepción con diferentes profundidades de pila pueden "alcanzar" la misma rutina jsr, pero el cambio neto en profundidad de pila desde jsr entrada de rutina a ret posterior debe ser cero (o en realidad menos 1 , ya que la causa de excepción siempre se presiona al ingresar a la rutina).

Además, aunque una rutina jsr puede "escapar" y rama de nuevo al flujo de control regular, si lo hace la jsr no esté exenta de la regla de profundidad de la pila para unirse a puntos. Esto limita severamente las situaciones en las que puede hacer esto, ya que una rutina jsr se puede ingresar con diferentes profundidades de pila.

(Y he sin duda todavía tengo algo de ese mal, pero es lo mejor que puedo hacer.)

(yo no entiendo muy bien cómo se está planeando "moverse" de su jsr problema con excepciones.)

(Además, Sun hizo bytecode escribiendo mucho más complicado con 4 o 5 (no puedo recordar cuál), lo que hace que sea casi imposible codificar byte códigos a mano. Lo hicieron porque no lo hicieron Saber cómo hacer la verificación lo suficientemente rápido para vencer el verificador de IBM de lo contrario, pero eso es otro asunto).

+0

En realidad, es perfectamente legal tener un 'jsr' que nunca' ret's. Las restricciones en las subrutinas son 1) cada subrutina puede contener un solo ret (por lo que no puede ret en ambas ramas de un si sin unirse a ellos, por ejemplo). 2) las llamadas de subrutina deben formar un árbol. Aparte de eso, no hay restricciones además de las impuestas por la verificación de tipos. – Antimony

+0

La parte realmente complicada es la definición precisa de lo que se considera el cuerpo de la subrutina, ya que esto depende de los detalles del algoritmo de verificación de tipo. Afortunadamente, Hotspot es de código abierto y puedes determinarlo tú mismo como yo si estás interesado. Aquí está el archivo relevante http://hg.openjdk.java.net/jdk7/jdk7/jdk/file/tip/src/share/native/common/check_code.c. Obviamente, esto depende de la implementación, por lo que si le importan los vms que no son Hotspot, debe asegurarse de que sus subrutinas estén bien estructuradas para evitar dichas ambigüedades. – Antimony

+0

@Antimony: como dije, mi memoria de las reglas para jsr es confusa: no he estado molesto con el verificador durante 5-6 años. IIRC, sin embargo, las reglas para lo que está dentro de una subrutina son bastante sencillas: para estar en subrutina, un punto debe ser accesible desde el punto de entrada, y un ret debe ser accesible desde el punto en cuestión. No debería haber ninguna ambigüedad en eso. –