0

I'm building a class that gathers some of the possible JVM opcodes. I found out how to generate DUP2_X2 and DUP_X2 but not DUP2, DUP2_X1, SWAP.

Below the code sample in which I starting gathering some of the jvm opcodes :

public class JvmOpCodes {

    long dup2x2(long[] array, int i, long l) {
        return array[i] = l;
    }

    int dupx2(int[] array, int i, int l) {
        return array[i] = l;
    }
    
    long lneg(long a) {
        return -a;
    }

    long lor(long a, long b) {
        return a | b;
    }

    long land(long a, long b) {
        return a & b;
    }

    long lushr(long a, long b) {
        return a >>> b;
    }

    int iushr(int a, int b) {
        return a >>> b;
    }

    long lshl(long a, long b) {
        return a << b;
    }

    float fsub(float a, float b) {
        return a - b;
    }

    float fadd(float a, float b) {
        return a + b;
    }

    float frem(float a, float b) {
        return a % b;
    }

    float fneg(float a) {
        return -a;
    }

    double drem(double a, double b) {
        return a % b;
    }
    
    double dneg(double a) {
        return -a;
    }
    
    void pop() {
        Math.round(0.5f);
    }
    
    void pop2() {
        Math.round(0.5d);
    }
}

After compiling with javac command and running javap -p -c, I'm able to identify the produced JVM opcodes inside the output :

Compiled from "JvmOpCodes.java"
public class org.apache.bcel.verifier.tests.JvmOpCodes {
  public org.apache.bcel.verifier.tests.JvmOpCodes();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  long dup2x2(long[], int, long);
    Code:
       0: aload_1
       1: iload_2
       2: lload_3
       3: dup2_x2
       4: lastore
       5: lreturn

  int dupx2(int[], int, int);
    Code:
       0: aload_1
       1: iload_2
       2: iload_3
       3: dup_x2
       4: iastore
       5: ireturn

  long lneg(long);
    Code:
       0: lload_1
       1: lneg
       2: lreturn

  long lor(long, long);
    Code:
       0: lload_1
       1: lload_3
       2: lor
       3: lreturn

  long land(long, long);
    Code:
       0: lload_1
       1: lload_3
       2: land
       3: lreturn

  long lushr(long, long);
    Code:
       0: lload_1
       1: lload_3
       2: l2i
       3: lushr
       4: lreturn

  int iushr(int, int);
    Code:
       0: iload_1
       1: iload_2
       2: iushr
       3: ireturn

  long lshl(long, long);
    Code:
       0: lload_1
       1: lload_3
       2: l2i
       3: lshl
       4: lreturn

  float fsub(float, float);
    Code:
       0: fload_1
       1: fload_2
       2: fsub
       3: freturn

  float fadd(float, float);
    Code:
       0: fload_1
       1: fload_2
       2: fadd
       3: freturn

  float frem(float, float);
    Code:
       0: fload_1
       1: fload_2
       2: frem
       3: freturn

  float fneg(float);
    Code:
       0: fload_1
       1: fneg
       2: freturn

  double drem(double, double);
    Code:
       0: dload_1
       1: dload_3
       2: drem
       3: dreturn

  double dneg(double);
    Code:
       0: dload_1
       1: dneg
       2: dreturn

  void pop();
    Code:
       0: ldc           #7                  // float 0.5f
       2: invokestatic  #8                  // Method java/lang/Math.round:(F)I
       5: pop
       6: return

  void pop2();
    Code:
       0: ldc2_w        #14                 // double 0.5d
       3: invokestatic  #16                 // Method java/lang/Math.round:(D)J
       6: pop2
       7: return
}

However, what piece of code in Java will generate the JVM instructions DUP2, DUP2_X1, SWAP ?

Also, an interesting related answer with demo here : https://stackoverflow.com/a/72131218/8315843

Sybuser
  • 735
  • 10
  • 27
  • Reread the comments on the "interesting" question you linked. Look at the OpenJDK code, and remember that Java may not use all the JVM opcodes. I'm tempted to mark this as a dup of the question you linked... – Jim Garrison Nov 27 '22 at 19:04
  • I'm sorry, I've just re-read the comments from that answer again, and the answer is not there. If you were able to infer the answer from that other answer, I believe it needs a bit of explanation. – Sybuser Nov 27 '22 at 19:10
  • 2
    I don't believe there is an "answer". The comments were pretty explicit: If you want to find out what opcodes are generated, read the OpenJDK source code, remembering that the JVM is designed for more than just Java. There may be opcodes that Java does not use but are used by other languages. – Jim Garrison Nov 27 '22 at 19:12
  • There may be opcodes that Java does not use but are used by other languages? – Sybuser Nov 27 '22 at 21:33
  • `invokedynamic` was added specifically to support other languages. – Boann Nov 28 '22 at 06:00
  • 2
    @Boann that was the case for Java 7, but since Java 8, `invokedynamic` is used by Java (for lambda expressions and method references) and since Java 9, it’s even more widely used, for string concatenation (at least, when compiling with javac). – Holger Nov 28 '22 at 08:23

2 Answers2

1

dup2:

  public static long example(long a) {
      return a = a + 1;
  }

I doubt that javac ever emits SWAP considering that there's missing variants like SWAP1_2, SWAP2_1, and SWAP2_2. As for DUP2_X1, I'm stumped.

boneill
  • 1,478
  • 1
  • 11
  • 18
  • 1
    See also [Use cases of jvm dup instruction](https://stackoverflow.com/q/54781284/2711488), [What Java code will force javac 1.6 to use the 'swap' and 'nop' opcodes?](https://stackoverflow.com/q/9722421/2711488) – Holger Nov 28 '22 at 08:19
  • https://stackoverflow.com/a/25746587/8315843 "javac indeed never uses swap even where appropriate." – Sybuser Nov 29 '22 at 20:28
0
  1. An example for DUP2_X1
    long l1;
    long l2;
    
    void test(String[] s) {
        s[0] += "s"; // Form 1 
        l2 = l1 = 1; // Form 2 
    }

and javap output when compiled in JDK8 :

  void test(java.lang.String[]);
    Code:
       0: new           #2                  // class java/lang/StringBuilder
       3: dup
       4: invokespecial #3                  // Method java/lang/StringBuilder."<init>":()V
       7: aload_1
       8: iconst_0
       9: dup2_x1
      10: aaload
      11: invokevirtual #4                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      14: ldc           #5                  // String s
      16: invokevirtual #4                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      19: invokevirtual #6                  // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      22: aastore
      23: aload_0
      24: aload_0
      25: lconst_1
      26: dup2_x1
      27: putfield      #7                  // Field l1:J
      30: putfield      #8                  // Field l2:J
      33: return
}

When compiled with JDK9+, the pattern of makeConcatWithConstants is activated so no DUP2_X1 for Form 1 :

  void test(java.lang.String[]);
    Code:
       0: aload_1
       1: iconst_0
       2: dup2
       3: aaload
       4: invokedynamic #3,  0              // InvokeDynamic #0:makeConcatWithConstants:(Ljava/lang/String;)Ljava/lang/String;
       9: aastore
      10: aload_0
      11: aload_0
      12: lconst_1
      13: dup2_x1
      14: putfield      #4                  // Field l1:J
      17: putfield      #5                  // Field l2:J
      20: return
  1. An example for SWAP with ecj :
import java.lang.reflect.*;

public class TestSWAP {
    public static Constructor getTestConstructor(Class theClass) throws NoSuchMethodException {
        Class[] args = { String.class };
        try {
            return theClass.getConstructor(args);
        } catch (NoSuchMethodException e) {}
        return theClass.getConstructor(new Class[0]);
    }
}

Compiling with ecj with source/target 1.4 :

java -jar ecj-3.32.0.jar -g -source 1.4 -target 1.4 TestSWAP.java

Checking output of javap with command javap -p -c TestSWAP :

Compiled from "TestSWAP.java"
public class TestSWAP {
  static java.lang.Class class$0;

  public TestSWAP();
    Code:
       0: aload_0
       1: invokespecial #11                 // Method java/lang/Object."<init>":()V
       4: return

  public static java.lang.reflect.Constructor getTestConstructor(java.lang.Class) throws java.lang.NoSuchMethodException;
    Code:
       0: iconst_1
       1: anewarray     #22                 // class java/lang/Class
       4: dup
       5: iconst_0
       6: getstatic     #24                 // Field class$0:Ljava/lang/Class;
       9: dup
      10: ifnonnull     38
      13: pop
      14: ldc           #26                 // String java.lang.String
      16: invokestatic  #28                 // Method java/lang/Class.forName:(Ljava/lang/String;)Ljava/lang/Class;
      19: dup
      20: putstatic     #24                 // Field class$0:Ljava/lang/Class;
      23: goto          38
      26: new           #32                 // class java/lang/NoClassDefFoundError
      29: dup_x1
      30: swap
      31: invokevirtual #34                 // Method java/lang/Throwable.getMessage:()Ljava/lang/String;
      34: invokespecial #40                 // Method java/lang/NoClassDefFoundError."<init>":(Ljava/lang/String;)V
      37: athrow
      38: aastore
      39: astore_1
      40: aload_0
      41: aload_1
      42: invokevirtual #43                 // Method java/lang/Class.getConstructor:([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
      45: areturn
      46: pop
      47: aload_0
      48: iconst_0
      49: anewarray     #22                 // class java/lang/Class
      52: invokevirtual #43                 // Method java/lang/Class.getConstructor:([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;
      55: areturn
    Exception table:
       from    to  target type
          14    19    26   Class java/lang/ClassNotFoundException
          40    45    46   Class java/lang/NoSuchMethodException
}
Sybuser
  • 735
  • 10
  • 27