Question

Are there any practical uses of the Java Virtual Machine's NOP opcode in today's JVM? If so, what are some scenarios in which NOPs would be generated in bytecode?

I would even be interested to see an example of Java code that compiles into bytecode with NOPs.


Update

BCEL's MethodGen class says,

While generating code it may be necessary to insert NOP operations.

I am guessing other Bytecode generation libraries are in the same boat, as was pointed out in the accepted answer.

Was it helpful?

Solution

Some NOP bytecode use cases are for class file transformations, optimizations and static analysis performed by tools such as Apache BCEL, ASM, FindBugs, PMD, etc. The Apache BCEL manual touches on some uses of NOP for analysis and optimization purposes.

A JVM may use NOP bytecodes for JIT optimizations to ensure code blocks that are at synchronization safepoints are properly aligned to avoid false sharing.

As for some sample code compiled using the JDK javac compiler that contains NOP bytecodes, that's an interesting challenge. However, I doubt the compiler will generate any class file containing NOP bytecodes since the bytecode instruction stream is only single-byte aligned. I would be curious to see such an example, but I can't think of any myself.

OTHER TIPS

Here is an example from some code I've been working on where nop instructions where placed into the byte code (as viewed by Bytecode Visualizer for Eclipse)

The original code

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)));
  }
}

The translated byte code for the equals(Object) method

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;
}

I am not sure why those would be inserted. I just hope they don't adversely affect performance.

No ops are often added for processor pipeline optimizations. I'm not sure of what extent Java currently uses them.

From Wikipedia:

A NOP is most commonly used for timing purposes, to force memory alignment, to prevent hazards, to occupy a branch delay slot, or as a place-holder to be replaced by active instructions later on in program development (or to replace removed instructions when refactoring would be problematic or time-consuming). In some cases, a NOP can have minor side effects; for example, on the Motorola 68000 series of processors, the NOP opcode causes a synchronization of the pipeline.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top