Skip to content
This repository was archived by the owner on May 12, 2024. It is now read-only.

Commit e741f28

Browse files
committed
Remove need for RandomSupport runtime
1 parent 6422960 commit e741f28

5 files changed

Lines changed: 199 additions & 31 deletions

File tree

runtime-dep/src/main/java/net/raphimc/javadowngrader/runtime/jdk/internal/util/random/RandomSupport.java renamed to RandomNextLongTest.java

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import java.util.Random;
2+
13
/*
24
* This file is part of JavaDowngrader - https://github.com/RaphiMC/JavaDowngrader
35
* Copyright (C) 2023 RK_01/RaphiMC and contributors
@@ -15,31 +17,9 @@
1517
* You should have received a copy of the GNU General Public License
1618
* along with this program. If not, see <http://www.gnu.org/licenses/>.
1719
*/
18-
package net.raphimc.javadowngrader.runtime.jdk.internal.util.random;
19-
20-
import java.util.Random;
21-
22-
public class RandomSupport {
23-
public static final String BAD_BOUND = "bound must be positive";
24-
25-
public static void checkBound(long bound) {
26-
if (bound <= 0) {
27-
throw new IllegalArgumentException(BAD_BOUND);
28-
}
29-
}
30-
31-
public static long boundedNextLong(Random rng, long bound) {
32-
final long m = bound - 1;
33-
long r = rng.nextLong();
34-
if ((bound & m) == 0L) {
35-
r &= m;
36-
} else {
37-
//noinspection StatementWithEmptyBody
38-
for (long u = r >>> 1;
39-
u + m - (r = u % bound) < 0L;
40-
u = rng.nextLong() >>> 1)
41-
;
42-
}
43-
return r;
20+
public class RandomNextLongTest {
21+
public static void main(String[] args) {
22+
final Random random = new Random();
23+
System.out.println(random.nextLong(25L));
4424
}
4525
}

src/main/java/net/raphimc/javadowngrader/transformer/j16/Java17ToJava16.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222
import org.objectweb.asm.Opcodes;
2323

2424
public class Java17ToJava16 extends DowngradingTransformer {
25-
public static final String RANDOM_SUPPORT = "net/raphimc/javadowngrader/runtime/jdk/internal/util/random/RandomSupport";
26-
2725
public Java17ToJava16() {
2826
super(Opcodes.V17, Opcodes.V16);
2927

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
/*
2+
* This file is part of JavaDowngrader - https://github.com/RaphiMC/JavaDowngrader
3+
* Copyright (C) 2023 RK_01/RaphiMC and contributors
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 3 of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
package net.raphimc.javadowngrader.transformer.j16;
19+
20+
import net.raphimc.javadowngrader.util.ASMUtil;
21+
import org.objectweb.asm.Label;
22+
import org.objectweb.asm.MethodVisitor;
23+
import org.objectweb.asm.Opcodes;
24+
import org.objectweb.asm.tree.ClassNode;
25+
26+
public class RandomSupportBoundedNextLongCreator {
27+
public static final String BOUNDEDNEXTLONG_NAME = "javadowngrader-boundedNextLong";
28+
public static final String BOUNDEDNEXTLONG_DESC = "(Ljava/util/Random;J)J";
29+
30+
public static void ensureHasMethod(final ClassNode classNode) {
31+
if (ASMUtil.hasMethod(classNode, BOUNDEDNEXTLONG_NAME, BOUNDEDNEXTLONG_DESC)) return;
32+
33+
final MethodVisitor boundedNextLong = classNode.visitMethod(
34+
Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC,
35+
BOUNDEDNEXTLONG_NAME, BOUNDEDNEXTLONG_DESC, null, null
36+
);
37+
boundedNextLong.visitCode();
38+
39+
// final long m = bound - 1;
40+
boundedNextLong.visitVarInsn(Opcodes.LLOAD, 1);
41+
boundedNextLong.visitInsn(Opcodes.LCONST_1);
42+
boundedNextLong.visitInsn(Opcodes.LSUB);
43+
boundedNextLong.visitVarInsn(Opcodes.LSTORE, 3);
44+
45+
// long r = rng.nextLong();
46+
boundedNextLong.visitVarInsn(Opcodes.ALOAD, 0);
47+
boundedNextLong.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/util/Random", "nextLong", "()J", false);
48+
boundedNextLong.visitVarInsn(Opcodes.LSTORE, 5);
49+
50+
// if ((bound & m) == 0L) {
51+
final Label elseStart = new Label();
52+
boundedNextLong.visitVarInsn(Opcodes.LLOAD, 1);
53+
boundedNextLong.visitVarInsn(Opcodes.LLOAD, 3);
54+
boundedNextLong.visitInsn(Opcodes.LAND);
55+
boundedNextLong.visitInsn(Opcodes.LCONST_0);
56+
boundedNextLong.visitInsn(Opcodes.LCMP);
57+
boundedNextLong.visitJumpInsn(Opcodes.IFNE, elseStart);
58+
59+
// r &= m;
60+
boundedNextLong.visitVarInsn(Opcodes.LLOAD, 5);
61+
boundedNextLong.visitVarInsn(Opcodes.LLOAD, 3);
62+
boundedNextLong.visitInsn(Opcodes.LAND);
63+
boundedNextLong.visitVarInsn(Opcodes.LSTORE, 5);
64+
65+
// } else {
66+
final Label elseEnd = new Label();
67+
boundedNextLong.visitJumpInsn(Opcodes.GOTO, elseEnd);
68+
boundedNextLong.visitLabel(elseStart);
69+
70+
// long u = r >>> 1;
71+
boundedNextLong.visitVarInsn(Opcodes.LLOAD, 5);
72+
boundedNextLong.visitInsn(Opcodes.ICONST_1);
73+
boundedNextLong.visitInsn(Opcodes.LUSHR);
74+
boundedNextLong.visitVarInsn(Opcodes.LSTORE, 7);
75+
76+
// while (u + m - (r = u % bound) < 0L) {
77+
final Label whileStart = new Label();
78+
final Label whileEnd = new Label();
79+
boundedNextLong.visitLabel(whileStart);
80+
boundedNextLong.visitVarInsn(Opcodes.LLOAD, 7);
81+
boundedNextLong.visitVarInsn(Opcodes.LLOAD, 3);
82+
boundedNextLong.visitInsn(Opcodes.LADD);
83+
boundedNextLong.visitVarInsn(Opcodes.LLOAD, 7);
84+
boundedNextLong.visitVarInsn(Opcodes.LLOAD, 1);
85+
boundedNextLong.visitInsn(Opcodes.LREM);
86+
boundedNextLong.visitInsn(Opcodes.DUP2);
87+
boundedNextLong.visitVarInsn(Opcodes.LSTORE, 5);
88+
boundedNextLong.visitInsn(Opcodes.LSUB);
89+
boundedNextLong.visitInsn(Opcodes.LCONST_0);
90+
boundedNextLong.visitInsn(Opcodes.LCMP);
91+
boundedNextLong.visitJumpInsn(Opcodes.IFGE, whileEnd);
92+
93+
// u = rng.nextLong() >>> 1;
94+
boundedNextLong.visitVarInsn(Opcodes.ALOAD, 0);
95+
boundedNextLong.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/util/Random", "nextLong", "()J", false);
96+
boundedNextLong.visitInsn(Opcodes.ICONST_1);
97+
boundedNextLong.visitInsn(Opcodes.LUSHR);
98+
boundedNextLong.visitVarInsn(Opcodes.LSTORE, 7);
99+
100+
// }
101+
boundedNextLong.visitJumpInsn(Opcodes.GOTO, whileStart);
102+
boundedNextLong.visitLabel(whileEnd);
103+
104+
// }
105+
boundedNextLong.visitLabel(elseEnd);
106+
107+
// return r;
108+
boundedNextLong.visitVarInsn(Opcodes.LLOAD, 5);
109+
boundedNextLong.visitInsn(Opcodes.LRETURN);
110+
111+
boundedNextLong.visitEnd();
112+
}
113+
}
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
* This file is part of JavaDowngrader - https://github.com/RaphiMC/JavaDowngrader
3+
* Copyright (C) 2023 RK_01/RaphiMC and contributors
4+
*
5+
* This program is free software; you can redistribute it and/or
6+
* modify it under the terms of the GNU Lesser General Public
7+
* License as published by the Free Software Foundation; either
8+
* version 3 of the License, or (at your option) any later version.
9+
*
10+
* This program is distributed in the hope that it will be useful,
11+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
*/
18+
package net.raphimc.javadowngrader.transformer.j16;
19+
20+
import net.raphimc.javadowngrader.util.ASMUtil;
21+
import org.objectweb.asm.Label;
22+
import org.objectweb.asm.MethodVisitor;
23+
import org.objectweb.asm.Opcodes;
24+
import org.objectweb.asm.tree.ClassNode;
25+
26+
public class RandomSupportCheckBoundCreator {
27+
private static final String BAD_BOUND = "bound must be positive";
28+
29+
public static final String CHECKBOUND_NAME = "javadowngrader-checkBound";
30+
public static final String CHECKBOUND_DESC = "(J)V";
31+
32+
public static void ensureHasMethod(final ClassNode classNode) {
33+
if (ASMUtil.hasMethod(classNode, CHECKBOUND_NAME, CHECKBOUND_DESC)) return;
34+
35+
final MethodVisitor checkBound = classNode.visitMethod(
36+
Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC | Opcodes.ACC_SYNTHETIC,
37+
CHECKBOUND_NAME, CHECKBOUND_DESC, null, null
38+
);
39+
checkBound.visitCode();
40+
41+
// if (bound <= 0) {
42+
final Label ifEnd = new Label();
43+
checkBound.visitVarInsn(Opcodes.LLOAD, 0);
44+
checkBound.visitInsn(Opcodes.LCONST_0);
45+
checkBound.visitInsn(Opcodes.LCMP);
46+
checkBound.visitJumpInsn(Opcodes.IFGT, ifEnd);
47+
48+
// throw new IllegalArgumentException(BAD_BOUND);
49+
checkBound.visitTypeInsn(Opcodes.NEW, "java/lang/IllegalArgumentException");
50+
checkBound.visitInsn(Opcodes.DUP);
51+
checkBound.visitLdcInsn(BAD_BOUND);
52+
checkBound.visitMethodInsn(
53+
Opcodes.INVOKESPECIAL,
54+
"java/lang/IllegalArgumentException",
55+
"<init>",
56+
"(Ljava/lang/String;)V",
57+
false
58+
);
59+
checkBound.visitInsn(Opcodes.ATHROW);
60+
61+
// }
62+
checkBound.visitLabel(ifEnd);
63+
64+
// }
65+
checkBound.visitInsn(Opcodes.RETURN);
66+
67+
checkBound.visitEnd();
68+
}
69+
}

src/main/java/net/raphimc/javadowngrader/transformer/j16/methodcallreplacer/RandomGeneratorNextLongMCR.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,30 @@
1818
package net.raphimc.javadowngrader.transformer.j16.methodcallreplacer;
1919

2020
import net.raphimc.javadowngrader.transformer.MethodCallReplacer;
21+
import net.raphimc.javadowngrader.transformer.j16.RandomSupportBoundedNextLongCreator;
22+
import net.raphimc.javadowngrader.transformer.j16.RandomSupportCheckBoundCreator;
2123
import org.objectweb.asm.Opcodes;
2224
import org.objectweb.asm.tree.*;
2325

24-
import static net.raphimc.javadowngrader.transformer.j16.Java17ToJava16.RANDOM_SUPPORT;
26+
import static net.raphimc.javadowngrader.transformer.j16.RandomSupportBoundedNextLongCreator.BOUNDEDNEXTLONG_DESC;
27+
import static net.raphimc.javadowngrader.transformer.j16.RandomSupportBoundedNextLongCreator.BOUNDEDNEXTLONG_NAME;
28+
import static net.raphimc.javadowngrader.transformer.j16.RandomSupportCheckBoundCreator.CHECKBOUND_DESC;
29+
import static net.raphimc.javadowngrader.transformer.j16.RandomSupportCheckBoundCreator.CHECKBOUND_NAME;
2530

2631
public class RandomGeneratorNextLongMCR implements MethodCallReplacer {
2732
@Override
2833
public InsnList getReplacement(ClassNode classNode, MethodNode method, String originalName, String originalDesc) {
2934
final InsnList replacement = new InsnList();
3035

36+
RandomSupportCheckBoundCreator.ensureHasMethod(classNode);
37+
RandomSupportBoundedNextLongCreator.ensureHasMethod(classNode);
38+
3139
// Random long1 long2
3240
replacement.add(new InsnNode(Opcodes.DUP2));
3341
// Random long1 long2 long1 long2
34-
replacement.add(new MethodInsnNode(Opcodes.INVOKESTATIC, RANDOM_SUPPORT, "checkBound", "(J)V"));
42+
replacement.add(new MethodInsnNode(Opcodes.INVOKESTATIC, classNode.name, CHECKBOUND_NAME, CHECKBOUND_DESC));
3543
// Random long1 long2
36-
replacement.add(new MethodInsnNode(Opcodes.INVOKESTATIC, RANDOM_SUPPORT, "boundedNextLong", "(Ljava/util/Random;J)J"));
44+
replacement.add(new MethodInsnNode(Opcodes.INVOKESTATIC, classNode.name, BOUNDEDNEXTLONG_NAME, BOUNDEDNEXTLONG_DESC));
3745
// long1 long2
3846

3947
return replacement;

0 commit comments

Comments
 (0)