changeset 10482:3e34b0318de6

Experimental decompiler that outputs Java source code from Graal IR for debug purposes. Contributed-by: Matthias Grimmer (mgrimmer)
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Sun, 23 Jun 2013 21:04:34 +0200
parents 29e9a5d18c70
children 3e6f538829ce
files graal/com.oracle.graal.java.decompiler.test/src/com/oracle/graal/java/decompiler/test/BootstrapTest.java graal/com.oracle.graal.java.decompiler.test/src/com/oracle/graal/java/decompiler/test/Test.java graal/com.oracle.graal.java.decompiler.test/src/com/oracle/graal/java/decompiler/test/TestUtil.java graal/com.oracle.graal.java.decompiler.test/src/com/oracle/graal/java/decompiler/test/example/Example.java graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/Decompiler.java graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/DecompilerIfSimplify.java graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/DecompilerLoopSimplify.java graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/DecompilerPhiRemover.java graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/block/DecompilerBasicBlock.java graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/block/DecompilerBlock.java graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/block/DecompilerIfBlock.java graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/block/DecompilerLoopBlock.java graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerAssignmentLine.java graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerControlSplitLine.java graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerIfLine.java graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerPhiLine.java graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerPhiResolveLine.java graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerProxyLine.java graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerReturnLine.java graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerSyntaxLine.java graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java graal/com.oracle.graal.printer/src/com/oracle/graal/printer/DebugEnvironment.java mx/projects
diffstat 23 files changed, 1684 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler.test/src/com/oracle/graal/java/decompiler/test/BootstrapTest.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler.test;
+
+public class BootstrapTest {
+
+    public static void main(String[] args) {
+
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler.test/src/com/oracle/graal/java/decompiler/test/Test.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler.test;
+
+import java.lang.reflect.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.java.decompiler.test.example.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.printer.*;
+
+public class Test {
+
+    /**
+     * @param args
+     * @throws SecurityException
+     * @throws NoSuchMethodException
+     */
+    public static void main(String[] args) throws NoSuchMethodException, SecurityException {
+        DebugEnvironment.initialize(System.out);
+        GraalCodeCacheProvider runtime = Graal.getRequiredCapability(GraalCodeCacheProvider.class);
+        Method method = Example.class.getDeclaredMethod("loop7", new Class[]{int.class, int.class});
+        final ResolvedJavaMethod javaMethod = runtime.lookupJavaMethod(method);
+        TestUtil.compileMethod(javaMethod);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler.test/src/com/oracle/graal/java/decompiler/test/TestUtil.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler.test;
+
+import static com.oracle.graal.api.code.CodeUtil.*;
+
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.code.CallingConvention.Type;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.api.runtime.*;
+import com.oracle.graal.compiler.*;
+import com.oracle.graal.compiler.target.*;
+import com.oracle.graal.java.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.PhasePlan.PhasePosition;
+import com.oracle.graal.phases.tiers.*;
+
+public class TestUtil {
+
+    public static void compileMethod(ResolvedJavaMethod method) {
+        GraalCodeCacheProvider runtime = Graal.getRequiredCapability(GraalCodeCacheProvider.class);
+        Replacements replacements = Graal.getRequiredCapability(Replacements.class);
+        Suites suites = Graal.getRequiredCapability(SuitesProvider.class).createSuites();
+        StructuredGraph graph = new StructuredGraph(method);
+        new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getEagerDefault(), OptimisticOptimizations.ALL).apply(graph);
+        PhasePlan phasePlan = new PhasePlan();
+        GraphBuilderPhase graphBuilderPhase = new GraphBuilderPhase(runtime, GraphBuilderConfiguration.getDefault(), OptimisticOptimizations.ALL);
+        phasePlan.addPhase(PhasePosition.AFTER_PARSING, graphBuilderPhase);
+        CallingConvention cc = getCallingConvention(runtime, Type.JavaCallee, graph.method(), false);
+        Backend backend = Graal.getRequiredCapability(Backend.class);
+        GraalCompiler.compileGraph(graph, cc, method, runtime, replacements, backend, runtime.getTarget(), null, phasePlan, OptimisticOptimizations.ALL, new SpeculationLog(), suites);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler.test/src/com/oracle/graal/java/decompiler/test/example/Example.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler.test.example;
+
+public class Example {
+
+    static int if0(int a, int b) {
+        if (a > b) {
+            return a - b;
+        }
+        return 0;
+
+    }
+
+    static int if1(int a, int b) {
+        if (a > b) {
+            return a - b;
+        } else {
+            return a + b;
+        }
+    }
+
+    static int if2(int a, int b) {
+        int c;
+        if (a > b) {
+            c = 1;
+        } else {
+            c = 2;
+        }
+        return c;
+    }
+
+    static int if3(int a, int b) {
+        int c = 0;
+        int s = 3;
+        if (a > b) {
+            if (a == 4) {
+                c = 2 + b;
+            } else {
+                c = 4 + b;
+            }
+            s = a + b;
+        } else {
+            c = 2;
+            s = a - b;
+        }
+        return c + s;
+    }
+
+    static int if4(int a, @SuppressWarnings("unused") int b) {
+        if (a > 10) {
+            if (a > 100) {
+                if (a > 1000) {
+                    return 1;
+                }
+                return 2;
+            }
+            return 3;
+        }
+        return 4;
+    }
+
+    static int loop(int a, int b) {
+        int i = 0;
+        int s = 0;
+
+        while (i < a) {
+            s += b;
+            i++;
+        }
+        return s;
+    }
+
+    static int loop2(int a, int b) {
+        int i = 0;
+        int s = 0;
+
+        while (i < a) {
+            if (a > b) {
+                s += a;
+            } else {
+                s += b;
+            }
+            i++;
+        }
+        return s;
+    }
+
+    static int loop3(int a, int b) {
+        int i = 0;
+        int s = 0;
+
+        while (i < a) {
+            if (a > b) {
+                s += a;
+            } else {
+                s += b;
+            }
+            i++;
+        }
+        if (s > 1000) {
+            return -1;
+        } else {
+            return s;
+        }
+    }
+
+    static int loop4(int a, int b) {
+        int s = 0;
+
+        if (a < 1000) {
+            int i = 0;
+            while (i < 123) {
+                if (a > b) {
+                    s += a;
+                } else {
+                    s += b;
+                }
+                i = i + ret1(i);
+            }
+            return -1;
+        } else {
+            return s;
+        }
+    }
+
+    static int ret1(int i) {
+        if (i % 2 == 0) {
+            return 1;
+        } else {
+            return 3;
+        }
+    }
+
+    static int loop5(int a, int b) {
+        int i = 0;
+        int sum = 0;
+        while (i < 1000) {
+            if (a < b) {
+                sum = sum + a;
+            }
+            sum = sum + i;
+            if (sum < a) {
+                sum = sum + b;
+            }
+            i++;
+        }
+        if (sum < a + b) {
+            sum = sum * 2;
+        }
+        return sum;
+    }
+
+    static int loop6(int a, int b) {
+        int s = 0;
+        for (int i = 0; i < a; i++) {
+            s += b;
+        }
+        return s;
+    }
+
+    static int loop7(int a, int b) {
+        int s = 0;
+        for (int i = 0; i < a; i++) {
+            for (int j = 0; j < b; j++) {
+                if (a > 400) {
+                    for (int k = 0; k < a + b; k++) {
+                        s += if4(a, b);
+                    }
+                } else {
+                    for (int k = 0; k < a - b; k++) {
+                        s += b;
+                    }
+                }
+            }
+            s += b;
+        }
+        return s;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/Decompiler.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.graal.java.decompiler.block.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.phases.schedule.*;
+
+public class Decompiler {
+
+    private List<DecompilerBlock> blocks = new ArrayList<>();
+    private List<Block> cfgBlocks = new ArrayList<>();
+    private SchedulePhase schedule;
+    private ControlFlowGraph cfg;
+
+    private final PrintStream stream;
+    private final PrintStream infoStream;
+
+    private static final String IDENT = "  ";
+    private String curIdent = "";
+
+    public final String contexInformation;
+
+    public Decompiler(StructuredGraph graph, SchedulePhase schedulePhase, PrintStream stream, PrintStream infoPrintStream, String contextInformation) {
+        this.stream = stream;
+        this.infoStream = infoPrintStream;
+        this.contexInformation = contextInformation;
+        schedule = schedulePhase;
+        if (schedule == null) {
+            try {
+                schedule = new SchedulePhase();
+                schedule.apply(graph);
+            } catch (Throwable t) {
+            }
+        }
+
+        cfg = schedule.getCFG();
+    }
+
+    public void decompile() {
+
+        for (Block b : getCfg().getBlocks()) {
+            cfgBlocks.add(b);
+        }
+
+        for (int i = 0; i < getCfg().getBlocks().length - 1; i++) {
+            if (cfg.getBlocks()[i].getId() >= cfg.getBlocks()[i + 1].getId()) {
+                throw new AssertionError();
+            }
+        }
+
+        blocks = new DecompilerLoopSimplify(this, infoStream).apply(cfgBlocks);
+        blocks = new DecompilerIfSimplify(this, infoStream).apply(blocks);
+
+        DecompilerPhiRemover.apply(cfg, blocks);
+
+        printDebugOutput();
+    }
+
+    private void printDebugOutput() {
+        for (int i = 0; i < blocks.size(); i++) {
+            if (i < blocks.size() - 1) {
+                blocks.get(i).printBlock(stream, blocks.get(i + 1).getBlock());
+            } else {
+                blocks.get(i).printBlock(stream, null);
+            }
+        }
+    }
+
+    public List<DecompilerBlock> getBlocks() {
+        return blocks;
+    }
+
+    public void ident() {
+        curIdent += IDENT;
+    }
+
+    public void undent() {
+        curIdent = curIdent.substring(0, curIdent.length() - IDENT.length());
+    }
+
+    public String getIdent() {
+        return curIdent;
+    }
+
+    public List<Block> getCfgBlocks() {
+        return cfgBlocks;
+    }
+
+    public SchedulePhase getSchedule() {
+        return schedule;
+    }
+
+    public ControlFlowGraph getCfg() {
+        return cfg;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/DecompilerIfSimplify.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.graal.java.decompiler.block.*;
+import com.oracle.graal.java.decompiler.lines.*;
+import com.oracle.graal.nodes.cfg.*;
+
+public class DecompilerIfSimplify {
+
+    private final Decompiler decompiler;
+    private final PrintStream infoStream;
+
+    public DecompilerIfSimplify(Decompiler decompiler, PrintStream infoStream) {
+        this.decompiler = decompiler;
+        this.infoStream = infoStream;
+    }
+
+    public List<DecompilerBlock> apply(List<DecompilerBlock> decompilerBlocks) {
+        return detectIfs(decompilerBlocks);
+    }
+
+    private List<DecompilerBlock> detectIfs(List<DecompilerBlock> decompilerBlocks) {
+        List<DecompilerBlock> blocks = new ArrayList<>();
+        while (!decompilerBlocks.isEmpty()) {
+            if (decompilerBlocks.get(0) instanceof DecompilerBasicBlock) {
+                DecompilerBasicBlock block = (DecompilerBasicBlock) decompilerBlocks.remove(0);
+                if (block.getSuccessorCount() <= 1) {
+                    blocks.add(block);
+                } else if (block.getSuccessorCount() == 2 && block.getCode().get(block.getCode().size() - 1) instanceof DecompilerIfLine) {
+                    Block firstThenBlock = block.getBlock().getSuccessors().get(0);
+                    Block firstElseBlock = block.getBlock().getSuccessors().get(1);
+                    List<DecompilerBlock> thenBlocks = getReachableDecompilerBlocks(firstThenBlock, decompilerBlocks);
+                    List<DecompilerBlock> elseBlocks = getReachableDecompilerBlocks(firstElseBlock, decompilerBlocks);
+                    removeIntersection(thenBlocks, elseBlocks);
+                    if (thenBlocks.size() == 0 && elseBlocks.size() == 0) {
+                        blocks.add(block);
+                    } else {
+                        for (DecompilerBlock b : thenBlocks) {
+                            decompilerBlocks.remove(b);
+                        }
+                        for (DecompilerBlock b : elseBlocks) {
+                            decompilerBlocks.remove(b);
+                        }
+                        // TODO(mg)
+                        // thenBlocks and elseBlocks can be both empty --> causes an AssertionError
+                        DecompilerIfBlock ifBlock = new DecompilerIfBlock(block.getBlock(), decompiler, thenBlocks, elseBlocks, infoStream);
+                        if (thenBlocks.contains(block.getBlock()) || elseBlocks.contains(block.getBlock())) {
+                            throw new AssertionError();
+                        }
+                        blocks.add(ifBlock);
+                        ifBlock.detectIfs();
+                    }
+                } else {
+                    blocks.add(block);
+                }
+            } else {
+                if (decompilerBlocks.get(0) instanceof DecompilerLoopBlock) {
+                    DecompilerLoopBlock loop = (DecompilerLoopBlock) decompilerBlocks.get(0);
+                    loop.detectIfs();
+                }
+                blocks.add(decompilerBlocks.remove(0));
+            }
+        }
+
+        return blocks;
+    }
+
+    private static List<DecompilerBlock> getReachableDecompilerBlocks(Block b, List<DecompilerBlock> decompilerBlocks) {
+        List<DecompilerBlock> result = new ArrayList<>();
+        for (DecompilerBlock block : decompilerBlocks) {
+            if (isReachable(b, block.getBlock(), new ArrayList<Block>())) {
+                result.add(block);
+            }
+        }
+        return result;
+    }
+
+    private static boolean isReachable(Block from, Block to, ArrayList<Block> visited) {
+        if (from == to) {
+            return true;
+        }
+        for (Block b : from.getSuccessors()) {
+            if (b != from && visited.contains(b) == false && b.getId() > from.getId()) {
+                visited.add(b);
+                if (isReachable(b, to, visited)) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    private static void removeIntersection(List<DecompilerBlock> list1, List<DecompilerBlock> list2) {
+        List<DecompilerBlock> list1Copy = new ArrayList<>(list1);
+        List<DecompilerBlock> list2Copy = new ArrayList<>(list2);
+
+        list1.removeAll(list2Copy);
+        list2.removeAll(list1Copy);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/DecompilerLoopSimplify.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.graal.java.decompiler.block.*;
+import com.oracle.graal.nodes.cfg.*;
+
+public class DecompilerLoopSimplify {
+
+    private final Decompiler decompiler;
+    private final PrintStream infoStream;
+
+    public DecompilerLoopSimplify(Decompiler decompiler, PrintStream infoStream) {
+        this.decompiler = decompiler;
+        this.infoStream = infoStream;
+    }
+
+    public List<DecompilerBlock> apply(List<Block> cfgBlocks) {
+        List<DecompilerBlock> blocks = new ArrayList<>();
+
+        while (!cfgBlocks.isEmpty()) {
+            Block firstBlock = cfgBlocks.get(0);
+            cfgBlocks.remove(0);
+            if (firstBlock.isLoopHeader()) {
+                DecompilerLoopBlock loopBlock = new DecompilerLoopBlock(firstBlock, decompiler, decompiler.getSchedule(), infoStream);
+                Loop loop = firstBlock.getLoop();
+
+                for (int i = 0; i < cfgBlocks.size(); i++) {
+                    if (loop.blocks.contains(cfgBlocks.get(i)) && cfgBlocks.get(i) != firstBlock) {
+                        loopBlock.addBodyBlock(cfgBlocks.get(i));
+                    }
+                }
+
+                // Asserting:
+                for (Block b : loopBlock.getBody()) {
+                    if (!loop.blocks.contains(b)) {
+                        throw new AssertionError();
+                    }
+                }
+                for (Block b : loop.blocks) {
+                    if (b != firstBlock && !loopBlock.getBody().contains(b)) {
+                        throw new AssertionError();
+                    }
+                }
+
+                for (Block b : loopBlock.getBody()) {
+                    cfgBlocks.remove(b);
+                }
+
+                blocks.add(loopBlock);
+                loopBlock.detectLoops();
+            } else {
+                DecompilerBasicBlock wrappedBlock = new DecompilerBasicBlock(firstBlock, decompiler, decompiler.getSchedule());
+                blocks.add(wrappedBlock);
+            }
+        }
+        return blocks;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/DecompilerPhiRemover.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler;
+
+import java.util.*;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.java.decompiler.block.*;
+import com.oracle.graal.java.decompiler.lines.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
+
+public class DecompilerPhiRemover {
+
+    public static void apply(ControlFlowGraph cfg, List<DecompilerBlock> decompilerBlocks) {
+        List<DecompilerBasicBlock> blocks = collectAllBasicBlocks(decompilerBlocks);
+        for (DecompilerBasicBlock b : blocks) {
+            List<DecompilerSyntaxLine> removedLines = new ArrayList<>();
+            Map<DecompilerSyntaxLine, DecompilerBasicBlock> addedLines = new HashMap<>();
+            for (DecompilerSyntaxLine l : b.getCode()) {
+                if (l instanceof DecompilerPhiLine) {
+                    DecompilerPhiLine phi = (DecompilerPhiLine) l;
+                    removedLines.add(phi);
+                    PhiNode phiNode = (PhiNode) phi.getNode();
+                    for (int i = 0; i < phiNode.merge().phiPredecessorCount(); i++) {
+                        Node n = phiNode.merge().phiPredecessorAt(i);
+                        DecompilerBasicBlock targetBlock = getBlock(n, cfg, blocks);
+                        DecompilerPhiResolveLine assignment = new DecompilerPhiResolveLine(targetBlock, phiNode, n);
+                        addedLines.put(assignment, targetBlock);
+                    }
+                }
+            }
+            for (DecompilerSyntaxLine l : addedLines.keySet()) {
+                addAssignment(addedLines.get(l), l);
+            }
+            b.getCode().removeAll(removedLines);
+        }
+    }
+
+    private static List<DecompilerBasicBlock> collectAllBasicBlocks(List<DecompilerBlock> blocks) {
+        List<DecompilerBasicBlock> allBasicBlocks = new ArrayList<>();
+        for (DecompilerBlock b : blocks) {
+            allBasicBlocks.addAll(b.getAllBasicBlocks());
+        }
+        return allBasicBlocks;
+    }
+
+    private static DecompilerBasicBlock getBlock(Node n, ControlFlowGraph cfg, List<DecompilerBasicBlock> blocks) {
+        Block b = cfg.blockFor(n);
+        for (DecompilerBasicBlock basicBlock : blocks) {
+            if (basicBlock.getBlock() == b) {
+                return basicBlock;
+            }
+        }
+        throw new IllegalStateException("Block not found");
+    }
+
+    private static void addAssignment(DecompilerBasicBlock block, DecompilerSyntaxLine line) {
+        if (block.getCode().isEmpty()) {
+            block.getCode().add(line);
+            return;
+        }
+        DecompilerSyntaxLine lastLine = block.getCode().get(block.getCode().size() - 1);
+        if (lastLine instanceof DecompilerIfLine || lastLine instanceof DecompilerControlSplitLine) {
+            block.getCode().remove(lastLine);
+            block.getCode().add(line);
+            block.getCode().add(lastLine);
+        } else {
+            block.getCode().add(line);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/block/DecompilerBasicBlock.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler.block;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.graal.java.decompiler.*;
+import com.oracle.graal.java.decompiler.lines.*;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.phases.schedule.*;
+
+public class DecompilerBasicBlock extends DecompilerBlock {
+
+    public DecompilerBasicBlock(Block block, Decompiler decompiler, SchedulePhase schedule) {
+        super(block, decompiler);
+        initCode(schedule);
+    }
+
+    @Override
+    public void printBlock(PrintStream stream, Block codeSuccessor) {
+        stream.println(decompiler.getIdent() + block);
+        for (DecompilerSyntaxLine l : code) {
+            if (l != null) {
+                String line = l.getAsString();
+                stream.println(decompiler.getIdent() + line);
+            }
+        }
+        if (!(block.getSuccessorCount() == 0 || (block.getSuccessorCount() == 1 && block.getFirstSuccessor() == codeSuccessor))) {
+            stream.println(decompiler.getIdent() + "GOTO " + Arrays.toString(block.getSuccessors().toArray()));
+        }
+    }
+
+    @Override
+    public String toString() {
+        return block.toString();
+    }
+
+    @Override
+    public int getSuccessorCount() {
+        return block.getSuccessorCount();
+    }
+
+    public List<Block> getSuccessors() {
+        return block.getSuccessors();
+    }
+
+    @Override
+    public boolean contains(Block b) {
+        return b == block;
+    }
+
+    public List<DecompilerSyntaxLine> getCode() {
+        return code;
+    }
+
+    @Override
+    public List<DecompilerBasicBlock> getAllBasicBlocks() {
+        return Arrays.asList(new DecompilerBasicBlock[]{this});
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/block/DecompilerBlock.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler.block;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.java.decompiler.*;
+import com.oracle.graal.java.decompiler.lines.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.phases.schedule.*;
+
+public abstract class DecompilerBlock {
+
+    protected final Block block;
+    protected final Decompiler decompiler;
+    protected final List<DecompilerSyntaxLine> code;
+
+    public DecompilerBlock(Block block, Decompiler decompiler) {
+        this.block = block;
+        this.decompiler = decompiler;
+        this.code = new ArrayList<>();
+    }
+
+    public Block getBlock() {
+        return block;
+    }
+
+    public abstract void printBlock(PrintStream stream, Block codeSuccessor);
+
+    public final int getPredecessorCount() {
+        return block.getPredecessorCount();
+    }
+
+    public abstract int getSuccessorCount();
+
+    public abstract boolean contains(Block b);
+
+    public abstract List<DecompilerBasicBlock> getAllBasicBlocks();
+
+    @Override
+    public abstract String toString();
+
+    protected void initCode(SchedulePhase schedule) {
+        List<ScheduledNode> instructions = schedule.nodesFor(block);
+        for (ScheduledNode n : instructions) {
+            if (n instanceof MergeNode) {
+                MergeNode merge = (MergeNode) n;
+                for (PhiNode phi : merge.phis()) {
+                    addLine(new DecompilerPhiLine(this, phi));
+                }
+            } else if (n instanceof StartNode || n instanceof BeginNode || n instanceof EndNode || n instanceof LoopEndNode || n instanceof LoopExitNode) {
+                // do nothing
+            } else if (n instanceof ConstantNode) {
+                // do nothing
+            } else if (n instanceof IfNode) {
+                assert n.inputs().count() == 1;
+                addLine(new DecompilerIfLine(this, n, ((IfNode) n).condition()));
+            } else if (n instanceof ReturnNode) {
+                addLine(new DecompilerReturnLine(this, n.inputs().first()));
+            } else if (n instanceof ControlSplitNode) {
+                addLine(new DecompilerControlSplitLine(this, n));
+            } else if (n instanceof ProxyNode) {
+                ProxyNode proxy = (ProxyNode) n;
+                addLine(new DecompilerProxyLine(this, proxy, proxy.value()));
+            } else if (n instanceof ValueNode) {
+                addLine(new DecompilerAssignmentLine(this, n));
+            } else {
+                throw new IllegalStateException(n.toString(Verbosity.All) + " " + n.getClass());
+            }
+        }
+        simplifyCode();
+    }
+
+    private void simplifyCode() {
+        for (int i = 0; i < code.size(); i++) {
+            if (code.get(i) instanceof DecompilerAssignmentLine) {
+                if (i + 1 < code.size()) {
+                    if (code.get(i + 1) instanceof DecompilerIfLine) {
+                        if (code.get(i).getNode().usages().count() == 1) {
+                            if (((DecompilerIfLine) code.get(i + 1)).getCondition() == code.get(i).getNode()) {
+                                ((DecompilerIfLine) code.get(i + 1)).setMergedCondition((DecompilerAssignmentLine) code.get(i));
+                                code.set(i, null);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    protected void addLine(DecompilerSyntaxLine line) {
+        code.add(line);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/block/DecompilerIfBlock.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler.block;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.graal.java.decompiler.*;
+import com.oracle.graal.java.decompiler.lines.*;
+import com.oracle.graal.nodes.cfg.*;
+
+public class DecompilerIfBlock extends DecompilerBlock {
+
+    private List<DecompilerBlock> thenBranch;
+    private List<DecompilerBlock> elseBranch;
+    private final DecompilerBasicBlock head;
+    private final PrintStream infoStream;
+
+    public DecompilerIfBlock(Block block, Decompiler decompiler, List<DecompilerBlock> thenBranch, List<DecompilerBlock> elseBranch, PrintStream infoStream) {
+        super(block, decompiler);
+        this.thenBranch = thenBranch;
+        this.elseBranch = elseBranch;
+        this.infoStream = infoStream;
+        this.head = new DecompilerBasicBlock(block, decompiler, decompiler.getSchedule());
+
+        if (!(thenBranch.isEmpty() == false && head.getBlock().getSuccessors().contains(thenBranch.get(0).getBlock()) || (elseBranch.isEmpty() == false && head.getBlock().getSuccessors().contains(
+                        elseBranch.get(0).getBlock())))) {
+            // first block of then / else MUST be a successor of the head!
+            throw new AssertionError(decompiler.contexInformation);
+        }
+    }
+
+    @Override
+    public void printBlock(PrintStream stream, Block codeSuccessor) {
+        List<DecompilerSyntaxLine> lines = head.getCode();
+        for (int i = 0; i < lines.size() - 1; i++) {
+            if (lines.get(i) != null) {
+                String line = lines.get(i).getAsString();
+                stream.println(decompiler.getIdent() + line);
+            }
+        }
+        DecompilerIfLine ifLine = (DecompilerIfLine) lines.get(lines.size() - 1);
+        if (!thenBranch.isEmpty() && block.getSuccessors().contains(thenBranch.get(0).getBlock())) {
+            if (elseBranch.isEmpty()) {
+                // while break:
+                stream.println(decompiler.getIdent() + ifLine.getIfNegStatement());
+                decompiler.ident();
+                stream.println(decompiler.getIdent() + "BREAK TO " + block.getSuccessors().get(1));
+                decompiler.undent();
+                for (int i = 0; i < thenBranch.size(); i++) {
+                    if (i < thenBranch.size() - 1) {
+                        thenBranch.get(i).printBlock(stream, thenBranch.get(i + 1).getBlock());
+                    } else {
+                        thenBranch.get(i).printBlock(stream, codeSuccessor);
+                    }
+                }
+            } else {
+                stream.println(decompiler.getIdent() + ifLine.getIfStatement() + " {");
+                decompiler.ident();
+                for (int i = 0; i < thenBranch.size(); i++) {
+                    if (i < thenBranch.size() - 1) {
+                        thenBranch.get(i).printBlock(stream, thenBranch.get(i + 1).getBlock());
+                    } else {
+                        thenBranch.get(i).printBlock(stream, codeSuccessor);
+                    }
+                }
+                decompiler.undent();
+                stream.println(decompiler.getIdent() + "} ELSE {");
+                decompiler.ident();
+                for (int i = 0; i < elseBranch.size(); i++) {
+                    if (i < elseBranch.size() - 1) {
+                        elseBranch.get(i).printBlock(stream, elseBranch.get(i + 1).getBlock());
+                    } else {
+                        elseBranch.get(i).printBlock(stream, codeSuccessor);
+                    }
+                }
+                decompiler.undent();
+                stream.println(decompiler.getIdent() + "}");
+            }
+        } else if (!elseBranch.isEmpty() && block.getSuccessors().contains(elseBranch.get(0).getBlock())) {
+            if (thenBranch.isEmpty()) {
+                // while break:
+                stream.println(decompiler.getIdent() + ifLine.getIfStatement());
+                decompiler.ident();
+                stream.println(decompiler.getIdent() + "BREAK TO " + block.getSuccessors().get(0));
+                decompiler.undent();
+                for (int i = 0; i < elseBranch.size(); i++) {
+                    if (i < elseBranch.size() - 1) {
+                        elseBranch.get(i).printBlock(stream, elseBranch.get(i + 1).getBlock());
+                    } else {
+                        elseBranch.get(i).printBlock(stream, codeSuccessor);
+                    }
+                }
+            } else {
+                stream.println(decompiler.getIdent() + ifLine.getIfNegStatement() + " {");
+                decompiler.ident();
+                for (int i = 0; i < elseBranch.size(); i++) {
+                    if (i < elseBranch.size() - 1) {
+                        elseBranch.get(i).printBlock(stream, elseBranch.get(i + 1).getBlock());
+                    } else {
+                        elseBranch.get(i).printBlock(stream, codeSuccessor);
+                    }
+                }
+                decompiler.undent();
+                stream.println(decompiler.getIdent() + "} ELSE {");
+                decompiler.ident();
+
+                for (int i = 0; i < thenBranch.size(); i++) {
+                    if (i < thenBranch.size() - 1) {
+                        thenBranch.get(i).printBlock(stream, thenBranch.get(i + 1).getBlock());
+                    } else {
+                        thenBranch.get(i).printBlock(stream, codeSuccessor);
+                    }
+                }
+
+                decompiler.undent();
+                stream.println(decompiler.getIdent() + "}");
+            }
+        } else {
+            throw new AssertionError();
+        }
+    }
+
+    public void detectIfs() {
+        thenBranch = new DecompilerIfSimplify(decompiler, infoStream).apply(thenBranch);
+        elseBranch = new DecompilerIfSimplify(decompiler, infoStream).apply(elseBranch);
+    }
+
+    @Override
+    public int getSuccessorCount() {
+        return 1;
+    }
+
+    @Override
+    public String toString() {
+        return "IF" + block.toString();
+    }
+
+    @Override
+    public boolean contains(Block b) {
+        return b == block || thenBranch.contains(b) || elseBranch.contains(b);
+    }
+
+    @Override
+    public List<DecompilerBasicBlock> getAllBasicBlocks() {
+        List<DecompilerBasicBlock> blocks = new ArrayList<>();
+        blocks.add(head);
+        for (DecompilerBlock b : thenBranch) {
+            blocks.addAll(b.getAllBasicBlocks());
+        }
+        for (DecompilerBlock b : elseBranch) {
+            blocks.addAll(b.getAllBasicBlocks());
+        }
+        return blocks;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/block/DecompilerLoopBlock.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler.block;
+
+import java.io.*;
+import java.util.*;
+
+import com.oracle.graal.java.decompiler.*;
+import com.oracle.graal.nodes.cfg.*;
+import com.oracle.graal.phases.schedule.*;
+
+public class DecompilerLoopBlock extends DecompilerBlock {
+
+    private final List<Block> body;
+    private List<DecompilerBlock> decompilerBlockBody;
+    private final PrintStream infoStream;
+
+    public DecompilerLoopBlock(Block block, Decompiler decompiler, SchedulePhase schedule, PrintStream infoStream) {
+        super(block, decompiler);
+        this.infoStream = infoStream;
+        this.body = new ArrayList<>();
+        decompilerBlockBody = new ArrayList<>();
+        decompilerBlockBody.add(new DecompilerBasicBlock(block, decompiler, schedule));
+    }
+
+    public void addBodyBlock(Block bodyBlock) {
+        body.add(bodyBlock);
+    }
+
+    public List<Block> getBody() {
+        return body;
+    }
+
+    public void detectLoops() {
+        decompilerBlockBody.addAll(new DecompilerLoopSimplify(decompiler, infoStream).apply(body));
+    }
+
+    public void detectIfs() {
+        decompilerBlockBody = new DecompilerIfSimplify(decompiler, infoStream).apply(decompilerBlockBody);
+    }
+
+    @Override
+    public void printBlock(PrintStream stream, Block codeSuccessor) {
+        stream.println(decompiler.getIdent() + block);
+        stream.println(decompiler.getIdent() + "while {");
+        decompiler.ident();
+        for (int i = 0; i < decompilerBlockBody.size(); i++) {
+            if (i < decompilerBlockBody.size() - 1) {
+                decompilerBlockBody.get(i).printBlock(stream, decompilerBlockBody.get(i + 1).getBlock());
+            } else {
+                decompilerBlockBody.get(i).printBlock(stream, block);
+            }
+        }
+        decompiler.undent();
+        stream.println(decompiler.getIdent() + "}");
+    }
+
+    @Override
+    public String toString() {
+        return "LOOP " + block.toString();
+    }
+
+    @Override
+    public int getSuccessorCount() {
+        return block.getLoop().exits.size();
+    }
+
+    @Override
+    public boolean contains(Block b) {
+        if (b == block) {
+            return true;
+        }
+        for (Block bodyBlock : body) {
+            if (bodyBlock == b) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public List<DecompilerBasicBlock> getAllBasicBlocks() {
+        List<DecompilerBasicBlock> blocks = new ArrayList<>();
+        for (DecompilerBlock b : decompilerBlockBody) {
+            blocks.addAll(b.getAllBasicBlocks());
+        }
+        return blocks;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerAssignmentLine.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler.lines;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.java.decompiler.block.*;
+import com.oracle.graal.nodes.*;
+
+public class DecompilerAssignmentLine extends DecompilerSyntaxLine {
+
+    private final NodeClassIterable inputs;
+
+    public DecompilerAssignmentLine(DecompilerBlock block, Node node) {
+        super(block, node);
+        this.inputs = node.inputs();
+    }
+
+    @Override
+    public String getAsString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getStringRepresentation(node));
+        sb.append(" = ");
+        sb.append(getStatement());
+        return sb.toString();
+    }
+
+    public String getStatement() {
+        StringBuilder sb = new StringBuilder();
+        if (node instanceof CallTargetNode) {
+            CallTargetNode callTarget = (CallTargetNode) node;
+            sb.append(callTarget.targetName());
+        } else {
+            sb.append(node.toString(Verbosity.Name));
+            sb.append(" ");
+            for (Node n : inputs) {
+                sb.append(getStringRepresentation(n));
+                sb.append(", ");
+            }
+        }
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerControlSplitLine.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler.lines;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.graph.Node.Verbosity;
+import com.oracle.graal.java.decompiler.block.*;
+import com.oracle.graal.nodes.cfg.*;
+
+public class DecompilerControlSplitLine extends DecompilerSyntaxLine {
+
+    public DecompilerControlSplitLine(DecompilerBlock block, Node node) {
+        super(block, node);
+    }
+
+    @Override
+    public String getAsString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(node.toString(Verbosity.Name));
+        sb.append(": ");
+        for (Block b : block.getBlock().getSuccessors()) {
+            sb.append(b);
+            sb.append(" ");
+        }
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerIfLine.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler.lines;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.java.decompiler.block.*;
+
+public class DecompilerIfLine extends DecompilerSyntaxLine {
+
+    private final Node condition;
+    private DecompilerAssignmentLine mergedCondition;
+
+    public DecompilerIfLine(DecompilerBlock block, Node node, Node condition) {
+        super(block, node);
+        this.condition = condition;
+    }
+
+    public void setMergedCondition(DecompilerAssignmentLine mergedCondition) {
+        this.mergedCondition = mergedCondition;
+    }
+
+    @Override
+    public String getAsString() {
+        if (mergedCondition == null) {
+            return "IF (" + getStringRepresentation(condition) + ") " + block.getBlock().getSuccessors().get(0) + ":" + block.getBlock().getSuccessors().get(1);
+        } else {
+            return "IF (" + mergedCondition.getStatement() + ") " + block.getBlock().getSuccessors().get(0) + ":" + block.getBlock().getSuccessors().get(1);
+        }
+    }
+
+    public String getIfStatement() {
+        if (mergedCondition == null) {
+            return "IF (" + getStringRepresentation(condition) + ")";
+        } else {
+            return "IF (" + mergedCondition.getStatement() + ")";
+        }
+
+    }
+
+    public String getIfNegStatement() {
+        if (mergedCondition == null) {
+            return "IF (!(" + getStringRepresentation(condition) + "))";
+        } else {
+            return "IF (!(" + mergedCondition.getStatement() + "))";
+        }
+    }
+
+    public Node getCondition() {
+        return condition;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerPhiLine.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler.lines;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.java.decompiler.block.*;
+import com.oracle.graal.nodes.*;
+
+public class DecompilerPhiLine extends DecompilerSyntaxLine {
+
+    public DecompilerPhiLine(DecompilerBlock block, Node node) {
+        super(block, node);
+    }
+
+    @Override
+    public String getAsString() {
+        PhiNode phi = (PhiNode) node;
+        StringBuilder sb = new StringBuilder();
+        sb.append(getStringRepresentation(phi));
+        sb.append(" = Phi {");
+        for (Node n : phi.values()) {
+            sb.append(getStringRepresentation(n));
+            sb.append(",");
+        }
+        sb.append("}");
+
+        return sb.toString();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerPhiResolveLine.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler.lines;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.java.decompiler.block.*;
+
+public class DecompilerPhiResolveLine extends DecompilerSyntaxLine {
+
+    private final Node value;
+
+    public DecompilerPhiResolveLine(DecompilerBlock block, Node node, Node value) {
+        super(block, node);
+        this.value = value;
+    }
+
+    @Override
+    public String getAsString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getStringRepresentation(node));
+        sb.append(" = ");
+        sb.append(getStringRepresentation(value));
+        return sb.toString();
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerProxyLine.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler.lines;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.java.decompiler.block.*;
+
+public class DecompilerProxyLine extends DecompilerSyntaxLine {
+
+    private final Node proxy;
+
+    public DecompilerProxyLine(DecompilerBlock block, Node node, Node proxy) {
+        super(block, node);
+        this.proxy = proxy;
+    }
+
+    @Override
+    public String getAsString() {
+        return getVariable(node) + " = " + getStringRepresentation(proxy);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerReturnLine.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler.lines;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.java.decompiler.block.*;
+
+public class DecompilerReturnLine extends DecompilerSyntaxLine {
+
+    public DecompilerReturnLine(DecompilerBlock block, Node node) {
+        super(block, node);
+    }
+
+    @Override
+    public String getAsString() {
+        return "return " + getStringRepresentation(node);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerSyntaxLine.java	Sun Jun 23 21:04:34 2013 +0200
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.java.decompiler.lines;
+
+import com.oracle.graal.graph.*;
+import com.oracle.graal.java.decompiler.block.*;
+import com.oracle.graal.nodes.*;
+
+public abstract class DecompilerSyntaxLine {
+
+    protected final Node node;
+    protected final DecompilerBlock block;
+
+    protected DecompilerSyntaxLine(DecompilerBlock block, Node node) {
+        this.node = node;
+        this.block = block;
+    }
+
+    public Node getNode() {
+        return node;
+    }
+
+    public abstract String getAsString();
+
+    public DecompilerBlock getBlock() {
+        return block;
+    }
+
+    protected static String getStringRepresentation(Node node) {
+        if (node instanceof ConstantNode) {
+            return String.valueOf(((ConstantNode) node).asConstant().asBoxedValue());
+        } else if (node instanceof LocalNode) {
+            return "local_" + ((LocalNode) node).index();
+        } else {
+            return getVariable(node);
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+    protected static String getVariable(Node node) {
+        if (node != null) {
+            return "var_" + node.getId();
+        } else {
+            return "null";
+        }
+    }
+
+}
--- a/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Sun Jun 23 20:50:18 2013 +0200
+++ b/graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java	Sun Jun 23 21:04:34 2013 +0200
@@ -183,6 +183,8 @@
     public static final OptionValue<Boolean> ExitVMOnException = new OptionValue<>(true);
     @Option(help = "")
     public static final OptionValue<Boolean> PrintStackTraceOnException = new OptionValue<>(false);
+    @Option(help = "Sets a phase after which the decompiler dumps the graph, -G:Dump= required")
+    public static final OptionValue<String> DecompileAfterPhase = new OptionValue<>(null);
 
     // HotSpot command line options
     @Option(help = "")
@@ -308,6 +310,7 @@
     public static final OptionValue<Boolean> IntrinsifyInstalledCodeMethods = new OptionValue<>(true);
     @Option(help = "")
     public static final OptionValue<Boolean> IntrinsifyCallSiteTarget = new OptionValue<>(true);
+
     /**
      * Counts the various paths taken through snippets.
      */
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/DebugEnvironment.java	Sun Jun 23 20:50:18 2013 +0200
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/DebugEnvironment.java	Sun Jun 23 21:04:34 2013 +0200
@@ -43,6 +43,9 @@
             }
             dumpHandlers.add(new CFGPrinterObserver());
         }
+        if (DecompileAfterPhase.getValue() != null) {
+            dumpHandlers.add(new DecompilerDebugDumpHandler());
+        }
         GraalDebugConfig hotspotDebugConfig = new GraalDebugConfig(Log.getValue(), Meter.getValue(), Time.getValue(), Dump.getValue(), MethodFilter.getValue(), log, dumpHandlers);
         Debug.setConfig(hotspotDebugConfig);
     }
--- a/mx/projects	Sun Jun 23 20:50:18 2013 +0200
+++ b/mx/projects	Sun Jun 23 21:04:34 2013 +0200
@@ -385,6 +385,22 @@
 project@com.oracle.graal.java@javaCompliance=1.7
 project@com.oracle.graal.java@workingSets=Graal,Java
 
+# graal.java.decompiler
+project@com.oracle.graal.java.decompiler@subDir=graal
+project@com.oracle.graal.java.decompiler@sourceDirs=src
+project@com.oracle.graal.java.decompiler@dependencies=com.oracle.graal.java
+project@com.oracle.graal.java.decompiler@checkstyle=com.oracle.graal.graph
+project@com.oracle.graal.java.decompiler@javaCompliance=1.7
+project@com.oracle.graal.java.decompiler@workingSets=Graal
+
+# graal.java.decompiler.test
+project@com.oracle.graal.java.decompiler.test@subDir=graal
+project@com.oracle.graal.java.decompiler.test@sourceDirs=src
+project@com.oracle.graal.java.decompiler.test@dependencies=com.oracle.graal.printer
+project@com.oracle.graal.java.decompiler.test@checkstyle=com.oracle.graal.graph
+project@com.oracle.graal.java.decompiler.test@javaCompliance=1.7
+project@com.oracle.graal.java.decompiler.test@workingSets=Graal,Test
+
 # graal.printer
 project@com.oracle.graal.printer@subDir=graal
 project@com.oracle.graal.printer@sourceDirs=src