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?
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
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
@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. –