What is the NOP in JVM bytecode used for?
Asked Answered
C

3

22

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.

Cove answered 2/5, 2012 at 21:36 Comment(4)
Usually it is used in debug code to allow breakpoints on something that doesn't translate into bytecode, like {.Fennel
Do you mean this would appear in bytecode when a Java file is compiled with javac -g?Cove
I don't believe javac will do that. But other compilers and debuggers could make use of that functionality.Fennel
As an example, using soot to generate Jimple code with some if statements results in NOPs.Macswan
D
12

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.

Democratic answered 3/5, 2012 at 14:19 Comment(0)
H
1

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.

Happenstance answered 22/10, 2015 at 18:56 Comment(2)
There are no nops, it’s just a bug in the Bytecode Visualizer you have used. The invokedynamic instruction consists of five bytes, the last two being zero per specification. Apparently, the Bytecode Visualizer doesn’t know that and assumes the invokedynamic instruction to have three bytes only and misinterprets the two zero bytes as nop instructions. See JVM Spec invokedynamic.Christianize
I guess that makes sense. I'm waiting for an update to Bytecode Visualizer for Eclipse Neon. Maybe we should tell the developer.Happenstance
G
-1

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.

Gutter answered 2/5, 2012 at 22:19 Comment(2)
This makes sense in a physical machine opcode, but what would be the use of such a thing for a virtual machine opcode?Giveandtake
I appreciate the answer, but this question is very specifically about the JVM.Cove

© 2022 - 2024 — McMap. All rights reserved.