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