From 781d464658ef2b512ff55bfc7d8eef29d2de3ee7 Mon Sep 17 00:00:00 2001 From: Nils Brugger Date: Thu, 1 Jun 2023 21:43:59 +0200 Subject: [PATCH 1/6] fix(core): System.arraycopy with objects (not arrays) ref: #928 --- .../core/parser/JavaLangSystemIntrinsics.java | 101 +++++++++--------- 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/parser/JavaLangSystemIntrinsics.java b/core/src/main/java/de/mirkosertic/bytecoder/core/parser/JavaLangSystemIntrinsics.java index 522f8f7d5..0aa13b98b 100644 --- a/core/src/main/java/de/mirkosertic/bytecoder/core/parser/JavaLangSystemIntrinsics.java +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/parser/JavaLangSystemIntrinsics.java @@ -15,13 +15,7 @@ */ package de.mirkosertic.bytecoder.core.parser; -import de.mirkosertic.bytecoder.core.ir.AnalysisStack; -import de.mirkosertic.bytecoder.core.ir.ControlTokenConsumer; -import de.mirkosertic.bytecoder.core.ir.Graph; -import de.mirkosertic.bytecoder.core.ir.InvocationType; -import de.mirkosertic.bytecoder.core.ir.ResolvedClass; -import de.mirkosertic.bytecoder.core.ir.ResolvedMethod; -import de.mirkosertic.bytecoder.core.ir.Value; +import de.mirkosertic.bytecoder.core.ir.*; import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.tree.MethodInsnNode; @@ -35,54 +29,63 @@ public ControlTokenConsumer intrinsifyMethodInvocation(final CompileUnit compile if (System.class.getName().equals(targetClass.getClassName())) { if ("arraycopy".equals(node.name)) { final Value source = incomingData[1]; + final Type methodType; + final ResolvedClass systemClass = compileUnit.resolveClass(Type.getType(System.class), analysisStack); - if (source.type.getSort() != Type.ARRAY) { - throw new IllegalArgumentException("Expected array type for arrayCopy, got " + source.type); - } - final ResolvedClass systemClass = compileUnit.resolveClass(Type.getType(System.class), analysisStack); - final Type methodType; - switch (source.type.getElementType().getSort()) { - case Type.CHAR: { - methodType = Type.getMethodType("([CI[CII)V"); - break; - } - case Type.BYTE: { - methodType = Type.getMethodType("([BI[BII)V"); - break; - } - case Type.DOUBLE: { - methodType = Type.getMethodType("([DI[DII)V"); - break; - } - case Type.FLOAT: { - methodType = Type.getMethodType("([FI[FII)V"); - break; - } - case Type.INT: { - methodType = Type.getMethodType("([II[III)V"); - break; - } - case Type.LONG: { - methodType = Type.getMethodType("([JI[JII)V"); - break; - } - case Type.SHORT: { - methodType = Type.getMethodType("([SI[SII)V"); - break; - } - case Type.BOOLEAN: { - methodType = Type.getMethodType("([ZI[ZII)V"); - break; - } - default: { - // (Ljava/lang/Object;ILjava/lang/Object;II)V - methodType = Type.getMethodType(node.desc); - break; + if (source.type.getClassName().contentEquals(Object.class.getName())) { + // (Ljava/lang/Object;ILjava/lang/Object;II)V + methodType = Type.getMethodType(node.desc); + } else if (source.type.getSort() == Type.ARRAY) { + switch (source.type.getElementType().getSort()) { + case Type.CHAR: { + methodType = Type.getMethodType("([CI[CII)V"); + break; + } + case Type.BYTE: { + methodType = Type.getMethodType("([BI[BII)V"); + break; + } + case Type.DOUBLE: { + methodType = Type.getMethodType("([DI[DII)V"); + break; + } + case Type.FLOAT: { + methodType = Type.getMethodType("([FI[FII)V"); + break; + } + case Type.INT: { + methodType = Type.getMethodType("([II[III)V"); + break; + } + case Type.LONG: { + methodType = Type.getMethodType("([JI[JII)V"); + break; + } + case Type.SHORT: { + methodType = Type.getMethodType("([SI[SII)V"); + break; + } + case Type.BOOLEAN: { + methodType = Type.getMethodType("([ZI[ZII)V"); + break; + } + case Type.OBJECT: { + // (Ljava/lang/Object;ILjava/lang/Object;II)V + methodType = Type.getMethodType(node.desc); + break; + } + default: { + throw new IllegalArgumentException(source.type.getElementType().getSort()+" is not a valid type for an array in System.arraycopy() !"); + } } + } else { + throw new IllegalArgumentException("Expected array type or "+Object.class.getName()+" for arrayCopy, got " + source.type); } + + final ResolvedMethod rm = systemClass.resolveMethod(node.name, methodType, analysisStack); final ControlTokenConsumer n = graph.newMethodInvocation(InvocationType.STATIC, node, rm); From 9b4c93b0f9710b575d241a9cd0d32fbc3f121c45 Mon Sep 17 00:00:00 2001 From: Nils Brugger Date: Thu, 1 Jun 2023 21:46:38 +0200 Subject: [PATCH 2/6] fix(core): Method references with unmatching return type ref: #926 --- .../core/backend/js/JSStructuredControlflowCodeGenerator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/backend/js/JSStructuredControlflowCodeGenerator.java b/core/src/main/java/de/mirkosertic/bytecoder/core/backend/js/JSStructuredControlflowCodeGenerator.java index cb3e65e91..b59a91f6b 100644 --- a/core/src/main/java/de/mirkosertic/bytecoder/core/backend/js/JSStructuredControlflowCodeGenerator.java +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/backend/js/JSStructuredControlflowCodeGenerator.java @@ -682,11 +682,11 @@ private void generateInvokeDynamicLambdaMetaFactoryInvocation(final InvokeDynami } } } - if (source.getSort() == Type.OBJECT && target.getSort() != Type.OBJECT) { + if (source.getSort() == Type.OBJECT && target.getSort() != Type.OBJECT && target.getSort() != Type.VOID) { // Object to primitive switch (source.getSort()) { default: { - throw new IllegalStateException("No converter from " + source + " to " + target + " implemented!"); + throw new IllegalStateException("No converter from " + source + " to " + target + " implemented! (" + argMethodName +")"); } } } From b3f96db26256ffbd3fd16f0ce01d46fd80bda2ce Mon Sep 17 00:00:00 2001 From: Nils Brugger Date: Thu, 1 Jun 2023 21:47:35 +0200 Subject: [PATCH 3/6] fix(core): Jump labels contain invalid - ref: #927 --- .../backend/js/JSStructuredControlflowCodeGenerator.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/de/mirkosertic/bytecoder/core/backend/js/JSStructuredControlflowCodeGenerator.java b/core/src/main/java/de/mirkosertic/bytecoder/core/backend/js/JSStructuredControlflowCodeGenerator.java index b59a91f6b..4e8787885 100644 --- a/core/src/main/java/de/mirkosertic/bytecoder/core/backend/js/JSStructuredControlflowCodeGenerator.java +++ b/core/src/main/java/de/mirkosertic/bytecoder/core/backend/js/JSStructuredControlflowCodeGenerator.java @@ -1988,7 +1988,7 @@ public void finishIfBlock() { @Override public void startBlock(final Sequencer.Block block) { writeIndent(); - pw.print(block.label); + pw.print(block.label.replace("-","")); pw.print(": "); if (block.type == Sequencer.Block.Type.LOOP) { pw.print("while(true) "); @@ -2066,7 +2066,7 @@ public void write(final ReturnValue node) { public void writeBreakTo(final String label) { writeIndent(); pw.print("break "); - pw.print(label); + pw.print(label.replace("-","")); pw.println(";"); } @@ -2074,7 +2074,7 @@ public void writeBreakTo(final String label) { public void writeContinueTo(final String label) { writeIndent(); pw.print("continue "); - pw.print(label); + pw.print(label.replace("-","")); pw.println(";"); } From 5dc59f1eac214df7e26a14b3f2b2c160bf89e57e Mon Sep 17 00:00:00 2001 From: Nils Brugger Date: Fri, 2 Jun 2023 11:45:22 +0200 Subject: [PATCH 4/6] test: System.arraycopy --- .../bytecoder/classlib/java/util/TArrays.java | 58 +++++++++++++++ .../classlib/java/lang/SystemTest.java | 72 +++++++++++++++++++ 2 files changed, 130 insertions(+) diff --git a/classlib/java.base/src/main/java/de/mirkosertic/bytecoder/classlib/java/util/TArrays.java b/classlib/java.base/src/main/java/de/mirkosertic/bytecoder/classlib/java/util/TArrays.java index 276f8fa6b..52dc3a4e5 100644 --- a/classlib/java.base/src/main/java/de/mirkosertic/bytecoder/classlib/java/util/TArrays.java +++ b/classlib/java.base/src/main/java/de/mirkosertic/bytecoder/classlib/java/util/TArrays.java @@ -206,6 +206,20 @@ public static boolean equals(final byte[] a, final byte[] b) { } return true; } + public static boolean equals(final short[] a, final short[] b) { + if (a == b) { + return true; + } + if (a.length != b.length) { + return false; + } + for (int i=0;i Date: Fri, 2 Jun 2023 14:55:20 +0200 Subject: [PATCH 5/6] test: non-matching return type method reference --- .../bytecoder/core/MethodReferenceTest.java | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 core/src/test/java/de/mirkosertic/bytecoder/core/MethodReferenceTest.java diff --git a/core/src/test/java/de/mirkosertic/bytecoder/core/MethodReferenceTest.java b/core/src/test/java/de/mirkosertic/bytecoder/core/MethodReferenceTest.java new file mode 100644 index 000000000..ba32459d1 --- /dev/null +++ b/core/src/test/java/de/mirkosertic/bytecoder/core/MethodReferenceTest.java @@ -0,0 +1,38 @@ +package de.mirkosertic.bytecoder.core; + +import de.mirkosertic.bytecoder.core.test.UnitTestRunner; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.function.Consumer; + +@RunWith(UnitTestRunner.class) +public class MethodReferenceTest { + public static String transform(String input){ + consumed = input+input; + return input+input; + } + static String consumed; + public static void consume(String input){ + consumed = input; + } + + @Test + public void passMatchingReference(){ + consumed = ""; + useConsumer(MethodReferenceTest::consume); + Assert.assertEquals(consumed,"test"); + } + + @Test + public void passUnmatchingReturnType(){ + consumed = ""; + useConsumer(MethodReferenceTest::transform); + Assert.assertEquals(consumed,"testtest"); + } + + public static void useConsumer(Consumer consumer){ + consumer.accept("test"); + } +} From f0e01a523c5f71e1ac551bbd14734760c023f50f Mon Sep 17 00:00:00 2001 From: Nils Brugger Date: Mon, 5 Jun 2023 15:53:41 +0200 Subject: [PATCH 6/6] style: fix typo --- .../bytecoder/classlib/java/lang/SystemTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/test/java/de/mirkosertic/bytecoder/classlib/java/lang/SystemTest.java b/core/src/test/java/de/mirkosertic/bytecoder/classlib/java/lang/SystemTest.java index aa2efe8a2..c3941c44d 100644 --- a/core/src/test/java/de/mirkosertic/bytecoder/classlib/java/lang/SystemTest.java +++ b/core/src/test/java/de/mirkosertic/bytecoder/classlib/java/lang/SystemTest.java @@ -104,14 +104,14 @@ public void arraycopyObjects(){ Assert.assertArrayEquals(targetStringArr, new String[]{"b","c"}); Object concealedArray = new Object[]{"A","b","c"}; - Object conclealedTargetArray = new Object[2]; - System.arraycopy(concealedArray,1,conclealedTargetArray,0,2); - Assert.assertArrayEquals((Object[]) conclealedTargetArray, new Object[]{"b","c"}); + Object concealedTargetArray = new Object[2]; + System.arraycopy(concealedArray,1,concealedTargetArray,0,2); + Assert.assertArrayEquals((Object[]) concealedTargetArray, new Object[]{"b","c"}); Object concealedStringArray = new String[]{"A","b","c"}; - Object conclealedTargetStringArray = new String[2]; - System.arraycopy(concealedStringArray,1,conclealedTargetStringArray,0,2); - Assert.assertArrayEquals((String[]) conclealedTargetStringArray, new String[]{"b","c"}); + Object concealedTargetStringArray = new String[2]; + System.arraycopy(concealedStringArray,1,concealedTargetStringArray,0,2); + Assert.assertArrayEquals((String[]) concealedTargetStringArray, new String[]{"b","c"}); } }