Search code examples
javajvmbytecodejvm-bytecode

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


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


Solution

    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
    }