From 09cd6436b9d57f40dd92a8a0f489725d0d04436a Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Tue, 7 Nov 2023 14:21:05 +0300 Subject: [PATCH 1/8] feat(#234): add conditional statement for optimization integration test --- src/it/optimization/pom.xml | 7 ++++++- .../src/main/java/org/eolang/jeo/Application.java | 13 ++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/it/optimization/pom.xml b/src/it/optimization/pom.xml index d52a4a59a..e044e492e 100644 --- a/src/it/optimization/pom.xml +++ b/src/it/optimization/pom.xml @@ -28,7 +28,12 @@ SOFTWARE. jeo-it @project.version@ jar - Integration test + Integration test that tries to transform simple java program + into XMIR and back. The integration test also checks that program can run + successfully and the plugin didn't break anything. + If you need to run only this test, use the following command: + "mvn clean integration-test invoker:run -Dinvoker.test=optimization -DskipTests" + UTF-8 1.8 diff --git a/src/it/optimization/src/main/java/org/eolang/jeo/Application.java b/src/it/optimization/src/main/java/org/eolang/jeo/Application.java index 94ed6e37b..df7a52457 100644 --- a/src/it/optimization/src/main/java/org/eolang/jeo/Application.java +++ b/src/it/optimization/src/main/java/org/eolang/jeo/Application.java @@ -2,6 +2,17 @@ public class Application { public static void main(String[] args) { - System.out.println("Hello, World!"); + if (bar(1.0d) > 7) { + System.out.println("Hello, World!"); + } else { + System.out.println("Wake up, Neo..."); + } + } + + private static int bar(double x) { + if (x > 0.0d) { + return 5; + } + return 8; } } From 7c42df59c439f72794584cf097ff15b9ed318773 Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Tue, 7 Nov 2023 16:05:39 +0300 Subject: [PATCH 2/8] feat(#234): add a bit more bytecode instructions --- .../bytecode/CommandInstruction.java | 32 ++++++++++++++++++- .../jeo/representation/xmir/HexString.java | 17 +++++++--- .../representation/xmir/XmlInstruction.java | 3 ++ 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/eolang/jeo/representation/bytecode/CommandInstruction.java b/src/main/java/org/eolang/jeo/representation/bytecode/CommandInstruction.java index 9d0eaa480..85bb484e7 100644 --- a/src/main/java/org/eolang/jeo/representation/bytecode/CommandInstruction.java +++ b/src/main/java/org/eolang/jeo/representation/bytecode/CommandInstruction.java @@ -130,6 +130,13 @@ private enum Instruction { visitor.visitInsn(Opcodes.DCONST_0) ), + /** + * Load the double value 1 onto the stack. + */ + DCONST_1(Opcodes.DCONST_1, (visitor, arguments) -> + visitor.visitInsn(Opcodes.DCONST_1) + ), + /** * Push a byte onto the stack as an integer value. */ @@ -228,6 +235,16 @@ private enum Instruction { ) ), + /** + * If value1 is less than or equal to value2, branch to instruction at branchoffset. + */ + IF_ICMPLE(Opcodes.IF_ICMPLE, (visitor, arguments) -> + visitor.visitJumpInsn( + Opcodes.IF_ICMPLE, + (org.objectweb.asm.Label) arguments.get(0) + ) + ), + /** * Return an integer from a method. */ @@ -303,7 +320,7 @@ private enum Instruction { * Invoke instance method on object objectref and puts the result on the stack. * Might be void. The method is identified by method reference index in constant pool. */ - INCOKESPECIAL(Opcodes.INVOKESPECIAL, (visitor, arguments) -> + INVOKESPECIAL(Opcodes.INVOKESPECIAL, (visitor, arguments) -> visitor.visitMethodInsn( Opcodes.INVOKESPECIAL, String.valueOf(arguments.get(0)), @@ -313,6 +330,19 @@ private enum Instruction { ) ), + /** + * Invoke a class (static) method. + */ + INVOKESTATIC(Opcodes.INVOKESTATIC, (visitor, arguments) -> + visitor.visitMethodInsn( + Opcodes.INVOKESTATIC, + String.valueOf(arguments.get(0)), + String.valueOf(arguments.get(1)), + String.valueOf(arguments.get(2)), + false + ) + ), + /** * Create new object of type identified by class reference in constant pool index. */ diff --git a/src/main/java/org/eolang/jeo/representation/xmir/HexString.java b/src/main/java/org/eolang/jeo/representation/xmir/HexString.java index 1ba7aea63..a5edf7939 100644 --- a/src/main/java/org/eolang/jeo/representation/xmir/HexString.java +++ b/src/main/java/org/eolang/jeo/representation/xmir/HexString.java @@ -59,10 +59,19 @@ final class HexString { * @return Human-readable string. */ String decode() { - return Arrays.stream(this.hex.split(" ")) - .map(ch -> (char) Integer.parseInt(ch, HexString.RADIX)) - .map(String::valueOf) - .collect(Collectors.joining()); + try { + return Arrays.stream(this.hex.split(" ")) + .filter(s -> !s.isBlank()) + .filter(s -> !s.isEmpty()) + .map(ch -> (char) Integer.parseInt(ch, HexString.RADIX)) + .map(String::valueOf) + .collect(Collectors.joining()); + } catch (final NumberFormatException exception) { + throw new IllegalArgumentException( + String.format("Invalid hex string: %s", this.hex), + exception + ); + } } /** diff --git a/src/main/java/org/eolang/jeo/representation/xmir/XmlInstruction.java b/src/main/java/org/eolang/jeo/representation/xmir/XmlInstruction.java index 91cfc6d41..c816af16f 100644 --- a/src/main/java/org/eolang/jeo/representation/xmir/XmlInstruction.java +++ b/src/main/java/org/eolang/jeo/representation/xmir/XmlInstruction.java @@ -31,6 +31,7 @@ import java.util.stream.IntStream; import org.eolang.jeo.representation.HexData; import org.eolang.jeo.representation.bytecode.BytecodeMethod; +import org.objectweb.asm.Label; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -157,6 +158,8 @@ private static Object[] arguments(final Node node) { final NamedNodeMap attributes = child.getAttributes(); if (attributes.getNamedItem("base").getNodeValue().equals("int")) { res.add(new HexString(child.getTextContent()).decodeAsInt()); + } else if (attributes.getNamedItem("base").getNodeValue().equals("label")) { + res.add(new XmlLabel(new XmlNode(child))); } else { res.add(new HexString(child.getTextContent()).decode()); } From 6656478d44042af14aca9f17c7993c95c326d7d8 Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Tue, 7 Nov 2023 16:39:28 +0300 Subject: [PATCH 3/8] feat(#234): make integration test work --- .../main/java/org/eolang/jeo/Application.java | 2 +- .../bytecode/CommandInstruction.java | 20 +++++++++++++++ .../representation/xmir/XmlInstruction.java | 25 ++++++++++++++++++- .../jeo/representation/xmir/XmlLabel.java | 2 +- 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/src/it/optimization/src/main/java/org/eolang/jeo/Application.java b/src/it/optimization/src/main/java/org/eolang/jeo/Application.java index df7a52457..873301149 100644 --- a/src/it/optimization/src/main/java/org/eolang/jeo/Application.java +++ b/src/it/optimization/src/main/java/org/eolang/jeo/Application.java @@ -2,7 +2,7 @@ public class Application { public static void main(String[] args) { - if (bar(1.0d) > 7) { + if (bar(1.0d) < 7) { System.out.println("Hello, World!"); } else { System.out.println("Wake up, Neo..."); diff --git a/src/main/java/org/eolang/jeo/representation/bytecode/CommandInstruction.java b/src/main/java/org/eolang/jeo/representation/bytecode/CommandInstruction.java index 85bb484e7..953f789b6 100644 --- a/src/main/java/org/eolang/jeo/representation/bytecode/CommandInstruction.java +++ b/src/main/java/org/eolang/jeo/representation/bytecode/CommandInstruction.java @@ -235,6 +235,16 @@ private enum Instruction { ) ), + /** + * If value1 is greater than or equal to value2, branch to instruction at branchoffset. + */ + IF_ICMPGE(Opcodes.IF_ICMPGE, (visitor, arguments) -> + visitor.visitJumpInsn( + Opcodes.IF_ICMPGE, + (org.objectweb.asm.Label) arguments.get(0) + ) + ), + /** * If value1 is less than or equal to value2, branch to instruction at branchoffset. */ @@ -245,6 +255,16 @@ private enum Instruction { ) ), + /** + * Goes to another instruction at branchoffset. + */ + GOTO(Opcodes.GOTO, (visitor, arguments) -> + visitor.visitJumpInsn( + Opcodes.GOTO, + (org.objectweb.asm.Label) arguments.get(0) + ) + ), + /** * Return an integer from a method. */ diff --git a/src/main/java/org/eolang/jeo/representation/xmir/XmlInstruction.java b/src/main/java/org/eolang/jeo/representation/xmir/XmlInstruction.java index c816af16f..cb67a9ec4 100644 --- a/src/main/java/org/eolang/jeo/representation/xmir/XmlInstruction.java +++ b/src/main/java/org/eolang/jeo/representation/xmir/XmlInstruction.java @@ -23,6 +23,7 @@ */ package org.eolang.jeo.representation.xmir; +import com.jcabi.log.Logger; import com.jcabi.xml.XMLDocument; import java.util.ArrayList; import java.util.Collection; @@ -159,7 +160,29 @@ private static Object[] arguments(final Node node) { if (attributes.getNamedItem("base").getNodeValue().equals("int")) { res.add(new HexString(child.getTextContent()).decodeAsInt()); } else if (attributes.getNamedItem("base").getNodeValue().equals("label")) { - res.add(new XmlLabel(new XmlNode(child))); + final String strip = child.getTextContent().strip().replace("\n",""); +// Logger.info(XmlInstruction.class, "Label raw: %s", strip); +// final String decoded = new HexString(strip).decode(); +// Logger.info(XmlInstruction.class, "Label decoded: %s", decoded); +// if (XmlLabel.LABELS.containsKey(decoded)) { +// Logger.info(XmlInstruction.class, "Label found: %s", decoded); +// res.add(XmlLabel.LABELS.get(decoded)); +// } else { +// Logger.info(XmlInstruction.class, "This label we will create: %s", decoded); +// final Label value = new Label(); +// XmlLabel.LABELS.put(decoded, value); +// res.add(value); +// } + Logger.info(XmlInstruction.class, "Label raw: %s", strip); + if (XmlLabel.LABELS.containsKey(strip)) { + Logger.info(XmlInstruction.class, "Label found: %s", strip); + res.add(XmlLabel.LABELS.get(strip)); + } else { + Logger.info(XmlInstruction.class, "This label we will create: %s", strip); + final Label value = new Label(); + XmlLabel.LABELS.put(strip, value); + res.add(value); + } } else { res.add(new HexString(child.getTextContent()).decode()); } diff --git a/src/main/java/org/eolang/jeo/representation/xmir/XmlLabel.java b/src/main/java/org/eolang/jeo/representation/xmir/XmlLabel.java index 1c28b39c4..0b19bbb33 100644 --- a/src/main/java/org/eolang/jeo/representation/xmir/XmlLabel.java +++ b/src/main/java/org/eolang/jeo/representation/xmir/XmlLabel.java @@ -43,7 +43,7 @@ public final class XmlLabel implements XmlCommand { * Moreover, we have to remove static field LABELS and use different approach to find labels. * @checkstyle StaticVariableNameCheck (3 lines) */ - private static final Map LABELS = new ConcurrentHashMap<>(); + public static final Map LABELS = new ConcurrentHashMap<>(); /** * Label node. From 8f963613fae2d4b0db827eec8acae0071f6568e6 Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Tue, 7 Nov 2023 16:45:09 +0300 Subject: [PATCH 4/8] feat(#234): add one more puzzle for the arguments method --- .../representation/xmir/XmlInstruction.java | 28 ++++++------------- 1 file changed, 9 insertions(+), 19 deletions(-) diff --git a/src/main/java/org/eolang/jeo/representation/xmir/XmlInstruction.java b/src/main/java/org/eolang/jeo/representation/xmir/XmlInstruction.java index cb67a9ec4..f68c1cc52 100644 --- a/src/main/java/org/eolang/jeo/representation/xmir/XmlInstruction.java +++ b/src/main/java/org/eolang/jeo/representation/xmir/XmlInstruction.java @@ -149,6 +149,11 @@ Node node() { * Get opcode arguments. * @param node Node. * @return Arguments. + * @todo #234:90min Refactor XmlInstruction#arguments method. + * This method is too complex and has too many responsibilities. + * Moreover, it uses static field LABELS. We have to refactor this method in order + * to avoid all that problems. Don't forget to remove PMD and checkstyle comments about + * suppressed warnings. */ private static Object[] arguments(final Node node) { final NodeList children = node.getChildNodes(); @@ -160,27 +165,12 @@ private static Object[] arguments(final Node node) { if (attributes.getNamedItem("base").getNodeValue().equals("int")) { res.add(new HexString(child.getTextContent()).decodeAsInt()); } else if (attributes.getNamedItem("base").getNodeValue().equals("label")) { - final String strip = child.getTextContent().strip().replace("\n",""); -// Logger.info(XmlInstruction.class, "Label raw: %s", strip); -// final String decoded = new HexString(strip).decode(); -// Logger.info(XmlInstruction.class, "Label decoded: %s", decoded); -// if (XmlLabel.LABELS.containsKey(decoded)) { -// Logger.info(XmlInstruction.class, "Label found: %s", decoded); -// res.add(XmlLabel.LABELS.get(decoded)); -// } else { -// Logger.info(XmlInstruction.class, "This label we will create: %s", decoded); -// final Label value = new Label(); -// XmlLabel.LABELS.put(decoded, value); -// res.add(value); -// } - Logger.info(XmlInstruction.class, "Label raw: %s", strip); - if (XmlLabel.LABELS.containsKey(strip)) { - Logger.info(XmlInstruction.class, "Label found: %s", strip); - res.add(XmlLabel.LABELS.get(strip)); + final String uid = child.getTextContent().strip().replace("\n", ""); + if (XmlLabel.LABELS.containsKey(uid)) { + res.add(XmlLabel.LABELS.get(uid)); } else { - Logger.info(XmlInstruction.class, "This label we will create: %s", strip); final Label value = new Label(); - XmlLabel.LABELS.put(strip, value); + XmlLabel.LABELS.put(uid, value); res.add(value); } } else { From 25e8e5a18539ba5838e71980abe70e6e58613f4c Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Tue, 7 Nov 2023 16:47:42 +0300 Subject: [PATCH 5/8] feat(#234): fix all qulice suggestions --- .../java/org/eolang/jeo/representation/xmir/XmlInstruction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/eolang/jeo/representation/xmir/XmlInstruction.java b/src/main/java/org/eolang/jeo/representation/xmir/XmlInstruction.java index f68c1cc52..69e11892b 100644 --- a/src/main/java/org/eolang/jeo/representation/xmir/XmlInstruction.java +++ b/src/main/java/org/eolang/jeo/representation/xmir/XmlInstruction.java @@ -23,7 +23,6 @@ */ package org.eolang.jeo.representation.xmir; -import com.jcabi.log.Logger; import com.jcabi.xml.XMLDocument; import java.util.ArrayList; import java.util.Collection; @@ -154,6 +153,7 @@ Node node() { * Moreover, it uses static field LABELS. We have to refactor this method in order * to avoid all that problems. Don't forget to remove PMD and checkstyle comments about * suppressed warnings. + * @checkstyle NestedIfDepthCheck (100 lines) */ private static Object[] arguments(final Node node) { final NodeList children = node.getChildNodes(); From 8a982cd8045657e9c8ce39f922bd228788967305 Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Tue, 7 Nov 2023 16:51:09 +0300 Subject: [PATCH 6/8] feat(#234): remove the puzzle for 234 issue --- .../java/org/eolang/jeo/representation/xmir/XmlLabel.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/org/eolang/jeo/representation/xmir/XmlLabel.java b/src/main/java/org/eolang/jeo/representation/xmir/XmlLabel.java index 0b19bbb33..045a40e14 100644 --- a/src/main/java/org/eolang/jeo/representation/xmir/XmlLabel.java +++ b/src/main/java/org/eolang/jeo/representation/xmir/XmlLabel.java @@ -36,11 +36,6 @@ public final class XmlLabel implements XmlCommand { /** * All Labels. - * @todo #226:90min Continue implementation of conditional instructions transformation. - * Currently we parse bytecode and correctly save all labels into XMIR. Although the back - * transformation is not implemented yet. We need to implement it and add or change integration - * tests to check that conditional instructions are correctly transformed. - * Moreover, we have to remove static field LABELS and use different approach to find labels. * @checkstyle StaticVariableNameCheck (3 lines) */ public static final Map LABELS = new ConcurrentHashMap<>(); From 5ce01a1df10ae109a1ef1367de405af24843fdb1 Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Tue, 7 Nov 2023 16:55:31 +0300 Subject: [PATCH 7/8] feat(#234): remove redundant code --- src/main/java/org/eolang/jeo/representation/xmir/HexString.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/org/eolang/jeo/representation/xmir/HexString.java b/src/main/java/org/eolang/jeo/representation/xmir/HexString.java index a5edf7939..bd4772c79 100644 --- a/src/main/java/org/eolang/jeo/representation/xmir/HexString.java +++ b/src/main/java/org/eolang/jeo/representation/xmir/HexString.java @@ -61,8 +61,6 @@ final class HexString { String decode() { try { return Arrays.stream(this.hex.split(" ")) - .filter(s -> !s.isBlank()) - .filter(s -> !s.isEmpty()) .map(ch -> (char) Integer.parseInt(ch, HexString.RADIX)) .map(String::valueOf) .collect(Collectors.joining()); From 39b27a7e61209ff8db56f359346baf2dfaea8e3a Mon Sep 17 00:00:00 2001 From: volodya-lombrozo Date: Tue, 7 Nov 2023 16:59:39 +0300 Subject: [PATCH 8/8] feat(#234): add one more puzzle --- .../java/org/eolang/jeo/representation/xmir/XmlLabel.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/eolang/jeo/representation/xmir/XmlLabel.java b/src/main/java/org/eolang/jeo/representation/xmir/XmlLabel.java index 045a40e14..6bf0afece 100644 --- a/src/main/java/org/eolang/jeo/representation/xmir/XmlLabel.java +++ b/src/main/java/org/eolang/jeo/representation/xmir/XmlLabel.java @@ -36,6 +36,10 @@ public final class XmlLabel implements XmlCommand { /** * All Labels. + * @todo #234:90min Hide LABELS Public Static Variable. + * It is not a good idea to expose LABELS and use static variable in general. + * We definitely have to hide this variable or, what is even better, get rid of it and create + * one more class that will encapsulate the LABELS logic. * @checkstyle StaticVariableNameCheck (3 lines) */ public static final Map LABELS = new ConcurrentHashMap<>();