2012-05-02 18 views
16

¿Hay algún uso práctico del código de operación NOP de la máquina virtual de Java en la JVM de hoy? En caso afirmativo, ¿cuáles son algunos escenarios en los que se generarían NOP s en bytecode?¿Para qué se utiliza el NOP en el bytecode de JVM?

yo incluso estar interesado en ver un ejemplo de código Java que compila en bytecode con NOP s.


actualización

clase de BCEL MethodGen dice,

mientras que la generación de código puede ser necesario insertar operaciones NOP.

Supongo que otras bibliotecas de generación Bytecode están en el mismo barco, como se señaló en la respuesta aceptada.

+0

Normalmente se usa en el código de depuración para permitir puntos de interrupción en algo que no se traduce en bytecode, como '{'. – vcsjones

+0

¿Quiere decir que esto aparecerá en bytecode cuando un archivo Java se compila con 'javac -g'? – jbranchaud

+0

No creo que 'javac' haga eso. Pero otros compiladores y depuradores podrían hacer uso de esa funcionalidad. – vcsjones

Respuesta

12

Algunos casos de uso NOP código de bytes son para las transformaciones class de archivos, optimizaciones y análisis estático realizado por herramientas como Apache BCEL, ASM, FindBugs, PMD, etc. Los Apache BCEL manual toques en algunos usos de NOP para fines de análisis y optimización .

Una JVM puede utilizar NOP bytecodes para optimizaciones JIT para garantizar que los bloques de código que están en los puntos de seguridad de sincronización estén alineados correctamente para evitar false sharing.

En cuanto a un ejemplo de código compilado utilizando el compilador JDK javac que contiene NOP bytecodes, es un desafío interesante. Sin embargo, dudo que el compilador genere ningún archivo class que contenga NOP bytecodes desde the bytecode instruction stream is only single-byte aligned. Sentiría curiosidad por ver ese ejemplo, pero no puedo pensar en ninguno.

1

No ops se agregan a menudo para optimizaciones de tuberías procesador. No estoy seguro de en qué medida Java los usa actualmente.

De Wikipedia:

A NOP es más comúnmente utilizado para los propósitos de temporización, para forzar la alineación de memoria , para evitar riesgos, para ocupar un hueco de retardo rama, o como un lugar titular para ser sustituido por instrucciones de activos más adelante en el programa de desarrollo (o para reemplazar las instrucciones eliminados al refactorizar sería ser problemático o tiempo). En algunos casos, un NOP puede tener efectos secundarios menores ; por ejemplo, en la serie de procesadores Motorola 68000, , el código de operación NOP causa una sincronización de la tubería.

+6

Esto tiene sentido en un código de operación de máquina física, pero ¿cuál sería el uso de tal cosa para un opcode de máquina * virtual *? –

+0

Agradezco la respuesta, pero esta pregunta es muy específica sobre la JVM. – jbranchaud

2

Aquí se muestra un ejemplo de un código que he estado trabajando en donde las instrucciones nop donde colocan en el código de bytes (como se ve por el código de bytes visualizador para Eclipse)

El código original

public abstract class Wrapper<T extends Wrapper<T,E>,E> 
    implements Supplier<Optional<E>>, Consumer<E> 
{ 
    /** The wrapped object. */ 
    protected Optional<E> inner; 

    /* 
    * (non-Javadoc) 
    * @see java.lang.Object#equals(java.lang.Object) 
    */ 
    /** 
    * A basic equals method that will compare the wrapped object to 
    * whatever you throw at it, whether it is wrapped or not. 
    */ 
    @Override 
    public boolean equals(final Object that) 
    { 
    return this==that 
     ||LambdaUtils.castAndMap(that,Wrapper.class,afterCast 
      -> inner.equals(afterCast.inner)) 
     .orElseGet(() 
      -> LambdaUtils.castAndMap(that,Optional.class,afterCast 
       -> inner.equals(afterCast)) 
      .orElseGet(() 
       -> Optional.ofNullable(that).map(thatobj 
        -> that.equals(inner.get())) 
       .orElseGet(() 
        -> false))); 
    } 
} 

El código de bytes traducido para el método de igualdad (Objeto)

public boolean equals(java.lang.Object arg0) { 
    /* L27 */ 
    0 aload_0;    /* this */ 
    1 aload_1;    /* that */ 
    2 if_acmpeq 36; 
    /* L28 */ 
    5 aload_1;    /* that */ 
    6 ldc 1; 
    8 aload_0;    /* this */ 
    9 invokedynamic 29;  /* java.util.function.Function apply(ext.cat.wcutils.collections.Wrapper arg0) */ 
    12 nop; 
    13 nop; 
    14 invokestatic 30;  /* java.util.Optional ext.cat.wcutils.util.LambdaUtils.castAndMap(java.lang.Object arg0, java.lang.Class arg1, java.util.function.Function arg2) */ 
    /* L30 */ 
    17 aload_0;    /* this */ 
    18 aload_1;    /* that */ 
    19 invokedynamic 39;  /* java.util.function.Supplier get(ext.cat.wcutils.collections.Wrapper arg0, java.lang.Object arg1) */ 
    22 nop; 
    23 nop; 
    24 invokevirtual 40;  /* java.lang.Object orElseGet(java.util.function.Supplier arg0) */ 
    27 checkcast 46;   /* java.lang.Boolean */ 
    30 invokevirtual 48;  /* boolean booleanValue() */ 
    /* L37 */ 
    33 ifne 5; 
    /* L27 */ 
    36 iconst_0; 
    37 ireturn; 
    38 iconst_1; 
    39 ireturn; 
} 

No estoy seguro de por qué se insertarán. Solo espero que no afecten negativamente el rendimiento.

+3

No hay 'nop's, es solo un error en Bytecode Visualizer que ha usado. La instrucción 'invokedynamic' consta de cinco bytes, los dos últimos son cero por especificación. Aparentemente, Bytecode Visualizer no lo sabe y asume que la instrucción 'invokedynamic' tiene solo tres bytes y malinterpreta los dos bytes cero como instrucciones' nop'. Consulte [JVM Spec invoinedynamic] (https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokedynamic). – Holger

+0

Supongo que tiene sentido. Estoy esperando una actualización de Bytecode Visualizer para Eclipse Neon. Tal vez deberíamos decirle al desarrollador. – HesNotTheStig

Cuestiones relacionadas