Skip to content

Commit

Permalink
refactor FileWriter stubs, fix some statics
Browse files Browse the repository at this point in the history
  • Loading branch information
wagyourtail committed Jun 3, 2024
1 parent 88c60e3 commit 8042d3b
Show file tree
Hide file tree
Showing 7 changed files with 137 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,13 @@ public class TestFile {

public static void main(String[] args) throws IOException {
FileWriter writer = new FileWriter("build/test/test.txt", StandardCharsets.UTF_8);
writer.write("Hello World!");
writer.write("Hello World!\n");
writer.close();

FileWriter writer2 = new FileWriter(new File("build/test/test.txt"), StandardCharsets.UTF_8, true);
writer2.write("Goodbye World!");
writer2.close();

FileReader reader = new FileReader(new File("build/test/test.txt"), StandardCharsets.UTF_8);
StringBuilder sb = new StringBuilder();
int c;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,48 +1,130 @@
package xyz.wagyourtail.jvmdg.j11.stub.java_base;


import xyz.wagyourtail.jvmdg.version.Adapter;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.InsnList;
import org.objectweb.asm.tree.InsnNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import xyz.wagyourtail.jvmdg.util.Utils;
import xyz.wagyourtail.jvmdg.version.Modify;
import xyz.wagyourtail.jvmdg.version.Ref;

import java.io.*;
import java.io.FileWriter;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CodingErrorAction;

@Adapter("Ljava/io/FileWriter;")
public class J_I_FileWriter extends OutputStreamWriter {

public J_I_FileWriter(String fileName) throws FileNotFoundException {
super(new FileOutputStream(fileName));
//@Adapter("Ljava/io/FileWriter;")
public class J_I_FileWriter {
private static final MethodHandles.Lookup IMPL_LOOKUP = Utils.getImplLookup();
private static final MethodHandle seGetter;
private static final MethodHandle encSetter;
static {
MethodHandle seGet = null;
MethodHandle encSet = null;
try {
Class<?> se = Class.forName("sun.nio.cs.StreamEncoder");
seGet = IMPL_LOOKUP.findGetter(FileWriter.class, "se", se);
encSet = IMPL_LOOKUP.findSetter(se, "encoder", CharsetEncoder.class);
} catch (Throwable t) {
t.printStackTrace();
}
seGetter = seGet;
encSetter = encSet;
}

public J_I_FileWriter(String fileName, boolean append) throws FileNotFoundException {
super(new FileOutputStream(fileName, append));
public static void setCharset(FileWriter fw, Charset charset) {
try {
Object se = seGetter.invoke(fw);
encSetter.invoke(se, charset.newEncoder().onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE));
} catch (Throwable t) {
Utils.sneakyThrow(t);
}
}

public J_I_FileWriter(File file) throws FileNotFoundException {
super(new FileOutputStream(file));
}
// public J_I_FileWriter(File file, Charset charset) throws IOException {
// super(new FileOutputStream(file), charset);
// }
//
// public J_I_FileWriter(File file, Charset charset, boolean append) throws IOException {
// super(new FileOutputStream(file, append), charset);
// }

public J_I_FileWriter(File file, boolean append) throws FileNotFoundException {
super(new FileOutputStream(file, append));
}

public J_I_FileWriter(FileDescriptor fd) {
super(new FileOutputStream(fd));
}
@Modify(ref = @Ref(value = "java/io/FileWriter", member = "<init>", desc = "(Ljava/lang/String;Ljava/nio/charset/Charset;)V"))
public static void init1(MethodNode mnode, int i) {
MethodInsnNode node = (MethodInsnNode) mnode.instructions.get(i);
Type firstArgType = Type.getArgumentTypes(node.desc)[0];
InsnList list = new InsnList();
// stack: (U) FileWriter, String, Charset
list.add(new InsnNode(Opcodes.DUP_X2));
// stack: Charset, (U) FileWriter, String, Charset
list.add(new InsnNode(Opcodes.POP));
// stack: Charset, (U) FileWriter, String
list.add(new InsnNode(Opcodes.DUP2));
// stack: Charset, (U) FileWriter, String, (U) FileWriter, String
// call init
list.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/io/FileWriter", "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, firstArgType), false));
// stack: Charset, FileWriter, String
list.add(new InsnNode(Opcodes.POP));
// stack: Charset, FileWriter
list.add(new InsnNode(Opcodes.SWAP));
// stack: FileWriter, Charset
list.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Type.getType(J_I_FileWriter.class).getInternalName(), "setCharset", "(Ljava/io/FileWriter;Ljava/nio/charset/Charset;)V", false));

public J_I_FileWriter(String fileName, Charset charset) throws IOException {
super(new FileOutputStream(fileName), charset);
mnode.instructions.insert(node, list);
mnode.instructions.remove(node);
}

public J_I_FileWriter(String fileName, Charset charset, boolean append) throws IOException {
super(new FileOutputStream(fileName, append), charset);
@Modify(ref = @Ref(value = "java/io/FileWriter", member = "<init>", desc = "(Ljava/lang/String;Ljava/nio/charset/Charset;Z)V"))
public static void init2(MethodNode mnode, int i) {
MethodInsnNode node = (MethodInsnNode) mnode.instructions.get(i);
Type firstArgType = Type.getArgumentTypes(node.desc)[0];
InsnList list = new InsnList();
// stack: (U) FileWriter, String, Charset, boolean
list.add(new InsnNode(Opcodes.DUP2_X2));
// stack: Charset, boolean, (U) FileWriter, String, Charset, boolean
list.add(new InsnNode(Opcodes.SWAP));
// stack: Charset, boolean, (U) FileWriter, String, boolean, Charset
list.add(new InsnNode(Opcodes.POP));
// stack: Charset, boolean, (U) FileWriter, String, boolean
list.add(new InsnNode(Opcodes.DUP2_X1));
// stack: Charset, boolean, String, boolean, (U) FileWriter, String, boolean
list.add(new InsnNode(Opcodes.POP2));
// stack: Charset, boolean, String, boolean, (U) FileWriter
list.add(new InsnNode(Opcodes.DUP_X2));
// stack: Charset, boolean, (U) FileWriter, String, boolean, (U) FileWriter
list.add(new InsnNode(Opcodes.DUP_X2));
// stack: Charset, boolean, (U) FileWriter, (U) FileWriter, String, boolean, (U) FileWriter
list.add(new InsnNode(Opcodes.POP));
// stack: Charset, boolean, (U) FileWriter, (U) FileWriter, String, boolean
// call init
list.add(new MethodInsnNode(Opcodes.INVOKESPECIAL, "java/io/FileWriter", "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, firstArgType, Type.BOOLEAN_TYPE), false));
// stack: Charset, boolean, FileWriter
list.add(new InsnNode(Opcodes.SWAP));
// stack: Charset, FileWriter, boolean
list.add(new InsnNode(Opcodes.POP));
// stack: Charset, FileWriter
list.add(new InsnNode(Opcodes.SWAP));
// stack: FileWriter, Charset
list.add(new MethodInsnNode(Opcodes.INVOKESTATIC, Type.getType(J_I_FileWriter.class).getInternalName(), "setCharset", "(Ljava/io/FileWriter;Ljava/nio/charset/Charset;)V", false));

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

public J_I_FileWriter(File file, Charset charset) throws IOException {
super(new FileOutputStream(file), charset);
@Modify(ref = @Ref(value = "java/io/FileWriter", member = "<init>", desc = "(Ljava/io/File;Ljava/nio/charset/Charset;)V"))
public static void init3(MethodNode mnode, int i) {
init1(mnode, i);
}

public J_I_FileWriter(File file, Charset charset, boolean append) throws IOException {
super(new FileOutputStream(file, append), charset);
@Modify(ref = @Ref(value = "java/io/FileWriter", member = "<init>", desc = "(Ljava/io/File;Ljava/nio/charset/Charset;Z)V"))
public static void init4(MethodNode mnode, int i) {
init2(mnode, i);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public static double nextExponential(Random random) {
}

@Stub
public double nextGaussian(Random random, double mean, double stdDev) {
public static double nextGaussian(Random random, double mean, double stdDev) {
return new BasicRandomGeneratorImpl(random).nextGaussian(mean, stdDev);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,12 @@ public static double nextExponential(SplittableRandom random) {
}

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

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public static boolean exists(FileSystemProvider provider, Path path, LinkOption.
}

@Stub
public <A extends BasicFileAttributes> A readAttributesIfExists(FileSystemProvider provider, Path path, Class<A> type, LinkOption... options) throws IOException {
public static <A extends BasicFileAttributes> A readAttributesIfExists(FileSystemProvider provider, Path path, Class<A> type, LinkOption... options) throws IOException {
try {
return provider.readAttributes(path, type, options);
} catch (NoSuchFileException ignored) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,18 @@ protected Map<MemberNameAndDesc, Pair<Boolean, Type>> init() {
}

public void addStub(MemberNameAndDesc member, Method method, Stub stub) {
int modifiers = method.getModifiers();
if (!Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {
throw new RuntimeException("@Stub " + method + " must be public static");
}
methodStub.put(member, new Pair<>(method, stub));
}

public void addModify(MemberNameAndDesc member, Method method, Modify modify) {
int modifiers = method.getModifiers();
if (!Modifier.isStatic(modifiers) || !Modifier.isPublic(modifiers)) {
throw new RuntimeException("@Modify " + method + " must be public static");
}
methodModify.put(member, new Pair<>(method, modify));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,18 @@ private void testDowngrade(String mainClass, boolean eq) throws Exception {
System.out.println();
System.out.println("Downgraded: ");

Set<Path> classpath = new HashSet<>(Stream.of(System.getProperty("java.class.path").split(":"))
.map(Path::of)
.toList());
classpath.add(downgradedJavaApi);
classpath.add(mainClasses);

StringBuilder downgradedLog = new StringBuilder();
Integer ret = JavaRunner.runJarInSubprocess(
downgraded,
new String[]{},
mainClass,
Set.of(downgradedJavaApi, mainClasses),
classpath,
Path.of("."),
Map.of(),
true,
Expand Down Expand Up @@ -305,4 +311,9 @@ public void testRandom() throws Exception {
testDowngrade("xyz.wagyourtail.downgradetest.TestRandom");
}

@Test
public void testFile() throws Exception {
testDowngrade("xyz.wagyourtail.downgradetest.TestFile");
}

}

0 comments on commit 8042d3b

Please sign in to comment.