Pregunta

he estado trabajando durante algún tiempo en (Java) código de bytes, sin embargo, nunca había ocurrido a mí para preguntar por qué se escriben algunas instrucciones? Entiendo que en una operación de adición, tenemos que distinguir entre una adición de enteros y una adición FP (es por eso que tienen IADD y FADD). Sin embargo, ¿por qué necesitamos distinguir entre istore y FSTORE? Ambos implican la misma operación exacta, que se está moviendo de 32 bits de la pila a una posición variable local?

La única respuesta que se me ocurre es para seguridad de tipos, para evitar esto: (iLoad, iLoad, FADD). Sin embargo, creo que el tipo de seguridad que ya se aplica en el nivel de lenguaje Java. OK, el formato de archivo de clase no se acopla directamente con Java, por lo que se trata de una manera de hacer cumplir seguridad de tipos de lenguajes que no lo soportan? ¿Cualquier pensamiento? Gracias.

EDIT: para dar seguimiento a la respuesta de Reedy. Escribí este programa mínimo:

public static void main(String args[])
{
    int x = 1;
}

que compila a:

iconst_1
istore_1
return

usando un editor de código de bytes, que cambió la segunda instrucción:

iconst_1
fstore_1
return

y devuelve un java.lang.VerifyError:. Esperando encontrar flotador en la pila

Me pregunto, si en la pila no hay información sobre el tipo, los bits solo, ¿cómo la instrucción FSTORE sabía que estaba tratando con un int y no un flotador?

Nota: no pude encontrar un mejor título para esta pregunta. Siéntase libre para mejorarlo.

¿Fue útil?

Solución

Estas instrucciones se escriben a asegurar que el programa es typesafe. Al cargar una clase de la verificación rendimiento de la máquina virtual en el código de bytes para garantizar que, por ejemplo, un flotador no se pasa como argumento a un método esperando un entero. Esta verificación estática requiere que el verificador puede determinar los tipos y el número de valores en la pila para cualquier ruta de ejecución dada. Las instrucciones de carga y almacenamiento necesitan la etiqueta de tipo porque las variables locales en los marcos de pila no se escriben (es decir, se puede istore a una variable local y más tarde fstore a la misma posición). Las etiquetas de tipo en las instrucciones que el verificador pueda saber qué tipo de valor se almacena en cada una variable local.

Las miradas de verificador en cada código de operación en el método y realiza un seguimiento de qué tipo serán en la pila y en las variables locales después de la ejecución de cada uno. Tienes razón en que esta es otra forma de comprobación de tipos y no duplicar algunas de las comprobaciones realizadas por el compilador de Java. El paso de verificación evita la carga de cualquier código que haría que la máquina virtual para ejecutar una instrucción ilegal y asegura las características de seguridad de la plataforma Java, sin incurrir en la gran pena de tiempo de ejecución de comprobación de tipos antes de cada operación. La comprobación de tipos en tiempo de ejecución para cada código de operación sería un impacto de rendimiento cada vez que se ejecuta el método, pero la verificación estática se realiza sólo una vez cuando se carga la clase.

Caso 1:

Instruction             Verification    Stack Types            Local Variable Types 
----------------------- --------------- ---------------------- ----------------------- 
<method entry>          OK              []                     1: none
iconst_1                OK              [int]                  1: none
istore_1                OK              []                     1: int
return                  OK              []                     1: int

Caso 2:

Instruction             Verification    Stack Types            Local Variable Types 
----------------------- --------------- ---------------------- ----------------------- 
<method entry>          OK              []                     1: none
iconst_1                OK              [int]                  1: none
fstore_1                Error: Expecting to find float on stack

Se da el error porque el verificador sabe que fstore_1 espera un flotador en la pila, pero el resultado de la ejecución de las hojas de instrucciones previas un int en la pila.

Esta verificación se realiza sin ejecutar los códigos de operación, sino que se hace mirando a los tipos de la instrucción, al igual que el compilador Java da un error al escribir (Integer)"abcd". El compilador no tiene que ejecutar el programa para saber que "abcd" es una cadena y no se puede convertir a Integer.

Otros consejos

Geoff Reedy explicó en su respuesta lo que el verificador cuando se carga una clase. Sólo quiero añadir que se puede desactivar el verificador utilizando un parámetro de JVM. Esto no es recomendable!

Para su programa de ejemplo (con iconst y fstore), el resultado de ejecutar la verificación con discapacidad es un error de máquina virtual que se detiene la JVM con el mensaje siguiente:

=============== DEBUG MESSAGE: illegal bytecode sequence - method not verified ================

#
# An unexpected error has been detected by HotSpot Virtual Machine:
#
#  EXCEPTION_PRIV_INSTRUCTION (0xc0000096) at pc=0x00a82571, pid=2496, tid=3408
#
# Java VM: Java HotSpot(TM) Client VM (1.5.0_15-b04 mixed mode, sharing)
# Problematic frame:
# j  BytecodeMismatch.main([Ljava/lang/String;)V+0
#
...

Para responder a su primera pregunta con mi mejor conjetura: estos códigos de bytes son diferentes, ya que pueden requerir diferentes implementaciones. Por ejemplo, una arquitectura particular puede mantener número entero operandos en la pila principal, pero operandos en coma flotante en registros de hardware.

Para responder a su segunda pregunta, VerifyError se produce cuando se carga la clase, no cuando es ejecutado. El proceso de verificación se describe aquí ; nota pase # 3.

Todos bytecode debe ser demostrablemente typesafe con unos datos estáticos análisis de flujo como se mencionó anteriormente. Sin embargo, esto realmente no explicar por qué instrucciones como _Store tienen diferentes tipos, ya que el tipo se puede inferir a partir del tipo del valor en la pila. De hecho, hay algunas instrucciones como el pop, el DUP, y de intercambio que hacen exactamente eso y operan en múltiples tipos. ¿Por qué algunas instrucciones se escriben y otros no es algo que sólo puede ser explicado por los desarrolladores originales de Java.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top