Skip to content

Commit

Permalink
replace stub init with modify, rework try/catch logging
Browse files Browse the repository at this point in the history
  • Loading branch information
wagyourtail committed May 13, 2024
1 parent 3b6eea3 commit b37f1b8
Show file tree
Hide file tree
Showing 13 changed files with 315 additions and 97 deletions.
4 changes: 3 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,14 @@ tasks.compileTestJava {
}

tasks.test {
outputs.upToDateWhen { false }
useJUnitPlatform()

dependsOn(
project(":downgradetest").tasks.build,
project(":java-api").tasks.build
)
jvmArgs("-Djvmdg.debug=true")
// jvmArgs("-Djvmdg.debug=true")
javaLauncher = javaToolchains.launcherFor {
languageVersion.set(JavaLanguageVersion.of(testVersion.toInt()))
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,52 @@
package xyz.wagyourtail.jvmdg.j10.stub.java_base;


import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;
import xyz.wagyourtail.jvmdg.version.Modify;
import xyz.wagyourtail.jvmdg.version.Ref;
import xyz.wagyourtail.jvmdg.version.Stub;

import java.io.BufferedWriter;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.nio.charset.Charset;

public class J_I_PrintWriter {

@Stub(ref = @Ref(value = "Ljava/io/PrintWriter;", member = "<init>"))
public static PrintWriter init(OutputStream out, boolean autoFlush, Charset encoding) {
return new PrintWriter(new BufferedWriter(new OutputStreamWriter(out, encoding)), autoFlush);
@Modify(ref = @Ref(value = "Ljava/io/PrintWriter;", member = "<init>", desc = "(Ljava/io/OutputStream;ZLjava/nio/charset/Charset;)V"))
public static void init(MethodNode mnode, int i) {
AbstractInsnNode node = mnode.instructions.get(i);
InsnList list = new InsnList();
// stack: PrintWriter, OutputStream, boolean, Charset
list.add(new InsnNode(Opcodes.DUP2_X1));
// stack: PrintWriter, boolean, Charset, OutputStream, boolean, Charset
list.add(new InsnNode(Opcodes.SWAP));
// stack: PrintWriter, boolean, Charset, OutputStream, Charset, boolean
list.add(new InsnNode(Opcodes.POP));
// stack: PrintWriter, boolean, Charset, OutputStream, Charset
list.add(new TypeInsnNode(Opcodes.NEW, "java/io/OutputStreamWriter"));
// stack: PrintWriter, boolean, Charset, OutputStream, Charset, (U) OutputStreamWriter
list.add(new InsnNode(Opcodes.DUP_X2));
// stack: PrintWriter, boolean, Charset, (U) OutputStreamWriter, OutputStream, Charset, (U) OutputStreamWriter
list.add(new InsnNode(Opcodes.DUP_X2));
// stack: PrintWriter, boolean, Charset, (U) OutputStreamWriter, (U) OutputStreamWriter, OutputStream, Charset, (U) OutputStreamWriter
list.add(new InsnNode(Opcodes.POP));
// stack: PrintWriter, boolean, Charset, (U) OutputStreamWriter, (U) OutputStreamWriter, OutputStream, Charset
list.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/io/OutputStreamWriter", "<init>", "(Ljava/io/OutputStream;Ljava/nio/charset/Charset;)V", false));
// stack: PrintWriter, boolean, Charset, OutputStreamWriter
list.add(new InsnNode(Opcodes.SWAP));
// stack: PrintWriter, boolean, OutputStreamWriter, Charset
list.add(new InsnNode(Opcodes.POP));
// stack: PrintWriter, boolean, OutputStreamWriter
list.add(new TypeInsnNode(Opcodes.NEW, "java/io/BufferedWriter"));
// stack: PrintWriter, boolean, OutputStreamWriter, (U) BufferedWriter
list.add(new InsnNode(Opcodes.DUP_X2));
// stack: PrintWriter, boolean, (U) BufferedWriter, OutputStreamWriter, (U) BufferedWriter
list.add(new InsnNode(Opcodes.SWAP));
// stack: PrintWriter, boolean, (U) BufferedWriter, (U) BufferedWriter, OutputStreamWriter
list.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/io/BufferedWriter", "<init>", "(Ljava/io/Writer;)V", false));
// stack: PrintWriter, boolean, BufferedWriter
list.add(new InsnNode(Opcodes.SWAP));
// stack: PrintWriter, BufferedWriter, boolean
list.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/io/PrintWriter", "<init>", "(Ljava/io/Writer;Z)V", false));

mnode.instructions.insert(node, list);
mnode.instructions.remove(node);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package xyz.wagyourtail.jvmdg.j10.stub.java_base;

import xyz.wagyourtail.jvmdg.version.Ref;
import xyz.wagyourtail.jvmdg.version.Stub;

import java.io.Reader;
import java.io.Writer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.nio.charset.Charset;
import java.util.Objects;

public class J_N_C_Channels {

@Stub(ref = @Ref("java/nio/channels/Channels"))
public static Reader newReader(ReadableByteChannel channel, Charset charset) {
Objects.requireNonNull(charset, "charset");
return Channels.newReader(channel, charset.newDecoder(), -1);
}

@Stub(ref = @Ref("java/nio/channels/Channels"))
public static Writer newWriter(WritableByteChannel channel, Charset charset) {
Objects.requireNonNull(charset, "charset");
return Channels.newWriter(channel, charset.newEncoder(), -1);
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package xyz.wagyourtail.jvmdg.j10.stub.java_base;


import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.*;
import xyz.wagyourtail.jvmdg.version.Modify;
import xyz.wagyourtail.jvmdg.version.Ref;
import xyz.wagyourtail.jvmdg.version.Stub;

Expand All @@ -10,9 +14,23 @@

public class J_U_Scanner {

@Stub(ref = @Ref(value = "Ljava/util/Scanner;", member = "<init>"))
public static Scanner init(ReadableByteChannel source, Charset charset) {
return new Scanner(source, charset.name());
// @Stub(ref = @Ref(value = "Ljava/util/Scanner;", member = "<init>"))
// public static Scanner init(ReadableByteChannel source, Charset charset) {
// return new Scanner(source, charset.name());
// }

@Modify(ref = @Ref(value = "Ljava/util/Scanner;", member = "<init>", desc = "(Ljava/nio/channels/ReadableByteChannel;Ljava/nio/charset/Charset;)V"))
public static void init(MethodNode mnode, int i) {
AbstractInsnNode node = mnode.instructions.get(i);
InsnList list = new InsnList();
// stack: Scanner, ReadableByteChannel, Charset
// call:J_N_C_Channels.newReader(ReadableByteChannel, Charset)
list.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Type.getType(J_N_C_Channels.class).getInternalName(), "newReader", "(Ljava/nio/channels/ReadableByteChannel;Ljava/nio/charset/Charset;)Ljava/io/Reader;", false));
// stack: Scanner, Reader
list.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/util/Scanner", "<init>", "(Ljava/lang/Readable;)V", false));

mnode.instructions.insert(node, list);
mnode.instructions.remove(node);
}

}
Original file line number Diff line number Diff line change
@@ -1,25 +1,62 @@
package xyz.wagyourtail.jvmdg.j15.stub.java_base;


import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;
import xyz.wagyourtail.jvmdg.version.Modify;
import xyz.wagyourtail.jvmdg.version.Ref;
import xyz.wagyourtail.jvmdg.version.Stub;

import java.util.NoSuchElementException;

public class J_U_NoSuchElementException {

@Stub(ref = @Ref(value = "Ljava/util/NoSuchElementException;", member = "<init>"))
public static NoSuchElementException create(String s, Throwable cause) throws NoSuchMethodException {
var nse = new NoSuchElementException(s);
nse.initCause(cause);
return nse;
@Modify(ref = @Ref(value = "Ljava/util/NoSuchElementException;", member = "<init>", desc = "(Ljava/lang/String;Ljava/lang/Throwable;)V"))
public static void init(MethodNode mnode, int i) {
AbstractInsnNode node = mnode.instructions.get(i);
InsnList list = new InsnList();
// stack: NoSuchElementException, String, Throwable
list.add(new InsnNode(Opcodes.DUP_X2));
// stack: Throwable, NoSuchElementException, String, Throwable
list.add(new InsnNode(Opcodes.POP));
// stack: Throwable, NoSuchElementException, String
list.add(new InsnNode(Opcodes.DUP2));
// stack: Throwable, NoSuchElementException, String, NoSuchElementException, String
// call init
list.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/util/NoSuchElementException", "<init>", "(Ljava/lang/String;)V", false));
// stack: Throwable, NoSuchElementException, String
list.add(new InsnNode(Opcodes.POP));
// stack: Throwable, NoSuchElementException
list.add(new InsnNode(Opcodes.SWAP));
// stack: NoSuchElementException, Throwable
// call initCause
list.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/util/NoSuchElementException", "initCause", "(Ljava/lang/Throwable;)Ljava/lang/Throwable;", false));
// stack: NoSuchElementException
list.add(new InsnNode(Opcodes.POP));

mnode.instructions.insert(node, list);
mnode.instructions.remove(node);
}

@Stub(ref = @Ref(value = "Ljava/util/NoSuchElementException;", member = "<init>"))
public static NoSuchElementException create(Throwable cause) throws NoSuchMethodException {
var nse = new NoSuchElementException(cause == null ? null : cause.toString());
nse.initCause(cause);
return nse;
@Modify(ref = @Ref(value = "java/util/NoSuchElementException", member = "<init>", desc = "(Ljava/lang/Throwable;)V"))
public static void init2(MethodNode mNode, int i) {
AbstractInsnNode node = mNode.instructions.get(i);
InsnList list = new InsnList();
// stack: NoSuchElementException, Throwable
list.add(new InsnNode(Opcodes.DUP2));
// stack: NoSuchElementException, Throwable, NoSuchElementException, Throwable
list.add(new InsnNode(Opcodes.POP));
// stack: NoSuchElementException, Throwable, NoSuchElementException
// call init
list.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/util/NoSuchElementException", "<init>", "()V", false));
// stack: NoSuchElementException, Throwable
// call initCause
list.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/util/NoSuchElementException", "initCause", "(Ljava/lang/Throwable;)Ljava/lang/Throwable;", false));
// stack: NoSuchElementException
list.add(new InsnNode(Opcodes.POP));

mNode.instructions.insert(node, list);
mNode.instructions.remove(node);
}

}
Original file line number Diff line number Diff line change
@@ -1,13 +1,36 @@
package xyz.wagyourtail.jvmdg.j16.stub.java_base;


import org.objectweb.asm.Handle;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;
import xyz.wagyourtail.jvmdg.version.Modify;
import xyz.wagyourtail.jvmdg.version.Ref;
import xyz.wagyourtail.jvmdg.version.Stub;

public class J_L_IndexOutOfBoundsException {
@Stub(ref = @Ref(value = "java/lang/IndexOutOfBoundsException", member = "<init>"))
public static IndexOutOfBoundsException init(long i) {
return new IndexOutOfBoundsException("Index out of range: " + i);

@Modify(ref = @Ref(value = "java/lang/IndexOutOfBoundsException", member = "<init>", desc = "(J)V"))
public static void init(MethodNode mNode, int i) {
AbstractInsnNode node = mNode.instructions.get(i);
InsnList list = new InsnList();
// string concat factory, "Index out of range: \u0001"
list.add(new InvokeDynamicInsnNode(
"makeConcatWithConstants",
"(J)Ljava/lang/String;",
new Handle(
Opcodes.H_INVOKESTATIC,
"java/lang/invoke/StringConcatFactory",
"makeConcatWithConstants",
"(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;"
),
"Index out of range: \u0001"
));
// call init
list.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/lang/IndexOutOfBoundsException", "<init>", "(Ljava/lang/String;)V", false));

mNode.instructions.insert(node, list);
mNode.instructions.remove(node);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ public static Stream<J_U_R_RandomGenerator.SplittableGenerator> splits(Splittabl
}

@Stub
public Stream<J_U_R_RandomGenerator> rngs() {
return new SplittableRandomGeneratorImpl(new SplittableRandom()).rngs();
public Stream<J_U_R_RandomGenerator> rngs(SplittableRandom random) {
return new SplittableRandomGeneratorImpl(random).rngs();
}

@Stub
public Stream<J_U_R_RandomGenerator> rngs(long size) {
return new SplittableRandomGeneratorImpl(new SplittableRandom()).rngs(size);
public Stream<J_U_R_RandomGenerator> rngs(SplittableRandom random, long size) {
return new SplittableRandomGeneratorImpl(random).rngs(size);
}

@Stub
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
package xyz.wagyourtail.jvmdg.j9.stub.java_base;


import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;
import xyz.wagyourtail.jvmdg.version.Modify;
import xyz.wagyourtail.jvmdg.version.Ref;
import xyz.wagyourtail.jvmdg.version.Stub;

public class J_L_IndexOutOfBoundsException {

@Stub(ref = @Ref(value = "Ljava/lang/IndexOutOfBoundsException;", member = "<init>"))
public static IndexOutOfBoundsException init(int index) {
return new IndexOutOfBoundsException("Index out of range: " + index);
@Modify(ref = @Ref(value = "java/lang/IndexOutOfBoundsException", member = "<init>", desc = "(I)V"))
public static void init(MethodNode mnode, int i) {
AbstractInsnNode node = mnode.instructions.get(i);
InsnList list = new InsnList();

// stack: IndexOutOfBoundsException, int
// new StringBuilder("Index out of range: ").append(index)
list.add(new TypeInsnNode(Opcodes.NEW, "java/lang/StringBuilder"));
list.add(new InsnNode(Opcodes.DUP));
list.add(new LdcInsnNode("Index out of range: "));
list.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V", false));
// stack: IndexOutOfBoundsException, int, StringBuilder
list.add(new InsnNode(Opcodes.SWAP));
// stack: IndexOutOfBoundsException, StringBuilder, int
list.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;", false));
// stack: IndexOutOfBoundsException, StringBuilder
list.add(new MethodInsnNode(Opcodes.INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false));
// stack: IndexOutOfBoundsException, String
// call init
list.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/lang/IndexOutOfBoundsException", "<init>", "(Ljava/lang/String;)V", false));

mnode.instructions.insert(node, list);
mnode.instructions.remove(node);
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package xyz.wagyourtail.jvmdg.j9.stub.java_base;


import org.objectweb.asm.Opcodes;
import org.objectweb.asm.tree.*;
import xyz.wagyourtail.jvmdg.version.Modify;
import xyz.wagyourtail.jvmdg.version.Ref;
import xyz.wagyourtail.jvmdg.version.Stub;

Expand All @@ -15,14 +18,48 @@ public class J_M_BigInteger {
public static final BigInteger TWO = BigInteger.valueOf(2);
static final long LONG_MASK = 0xffffffffL;

@Stub(ref = @Ref(value = "Ljava/math/BigInteger;", member = "<init>"))
public static BigInteger init(byte[] val, int off, int len) {
return new BigInteger(Arrays.copyOfRange(val, off, off + len));
@Modify(ref = @Ref(value = "Ljava/math/BigInteger;", member = "<init>", desc = "([BII)V"))
public static void init(MethodNode mnode, int i) {
AbstractInsnNode node = mnode.instructions.get(i);
InsnList list = new InsnList();

// stack: BigInteger, byte[], (start) int, (len) int
list.add(new InsnNode(Opcodes.DUP2));
// stack: BigInteger, byte[], (start) int, (len) int, (start) int, (len) int
list.add(new InsnNode(Opcodes.IADD));
// stack: BigInteger, byte[],(start) int, (len) int, (start+len) int
list.add(new InsnNode(Opcodes.SWAP));
// stack: BigInteger, byte[], (start) int, (start+len) int, (len) int
list.add(new InsnNode(Opcodes.POP));
// stack: BigInteger, byte[], (start) int, (start+len) int
list.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/util/Arrays", "copyOfRange", "([BII)[B", false));
// stack: BigInteger, byte[]
list.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/math/BigInteger", "<init>", "([B)V", false));

mnode.instructions.insert(node, list);
mnode.instructions.remove(node);
}

@Stub(ref = @Ref(value = "Ljava/math/BigInteger;", member = "<init>"))
public static BigInteger init(int signum, byte[] magnitude, int off, int len) {
return new BigInteger(signum, Arrays.copyOfRange(magnitude, off, off + len));
@Modify(ref = @Ref(value = "Ljava/math/BigInteger;", member = "<init>", desc = "(I[BII)V"))
public static void init2(MethodNode mnode, int i) {
AbstractInsnNode node = mnode.instructions.get(i);
InsnList list = new InsnList();

// stack: BigInteger, int, byte[], (start) int, (len) int
list.add(new InsnNode(Opcodes.DUP2));
// stack: BigInteger, int, byte[], (start) int, (len) int, (start) int, (len) int
list.add(new InsnNode(Opcodes.IADD));
// stack: BigInteger, int, byte[], (start) int, (len) int, (start+len) int
list.add(new InsnNode(Opcodes.SWAP));
// stack: BigInteger, int, byte[], (start) int, (start+len) int, (len) int
list.add(new InsnNode(Opcodes.POP));
// stack: BigInteger, int, byte[], (start) int, (start+len) int
list.add(new MethodInsnNode(Opcodes.INVOKESTATIC, "java/util/Arrays", "copyOfRange", "([BII)[B", false));
// stack: BigInteger, int, byte[]
list.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/math/BigInteger", "<init>", "(I[B)V", false));

mnode.instructions.insert(node, list);
mnode.instructions.remove(node);
}

@Stub
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public void init() {
stub(J_L_Runtime$Version.class);
// StackWalker
stub(J_L_I_MethodType.class);
stub(J_N_C_Channels.class);
stub(J_N_URLDecoder.class);
stub(J_N_URLEncoder.class);
// FileStore
Expand Down
2 changes: 0 additions & 2 deletions src/main/java/xyz/wagyourtail/jvmdg/ClassDowngrader.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@
import java.util.concurrent.atomic.AtomicReference;

public class ClassDowngrader {
public static final boolean QUIET = Boolean.getBoolean("jvmdg.quiet");

public static final ClassDowngrader currentVersionDowngrader = new ClassDowngrader(Utils.getCurrentClassVersion());

// because parent is null, this is (essentially) a wrapper around the bootstrap classloader
Expand Down
Loading

0 comments on commit b37f1b8

Please sign in to comment.