# HG changeset patch # User Thomas Wuerthinger # Date 1372014274 -7200 # Node ID 3e34b0318de6f20ce0fa38735f409ec2063af752 # Parent 29e9a5d18c70657adc801000d76f9d85dd560478 Experimental decompiler that outputs Java source code from Graal IR for debug purposes. Contributed-by: Matthias Grimmer (mgrimmer) diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler.test/src/com/oracle/graal/java/decompiler/test/BootstrapTest.java --- /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) { + + } +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler.test/src/com/oracle/graal/java/decompiler/test/Test.java --- /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); + } +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler.test/src/com/oracle/graal/java/decompiler/test/TestUtil.java --- /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); + } +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler.test/src/com/oracle/graal/java/decompiler/test/example/Example.java --- /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; + } +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/Decompiler.java --- /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 blocks = new ArrayList<>(); + private List 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 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 getCfgBlocks() { + return cfgBlocks; + } + + public SchedulePhase getSchedule() { + return schedule; + } + + public ControlFlowGraph getCfg() { + return cfg; + } + +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/DecompilerIfSimplify.java --- /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 apply(List decompilerBlocks) { + return detectIfs(decompilerBlocks); + } + + private List detectIfs(List decompilerBlocks) { + List 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 thenBlocks = getReachableDecompilerBlocks(firstThenBlock, decompilerBlocks); + List 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 getReachableDecompilerBlocks(Block b, List decompilerBlocks) { + List result = new ArrayList<>(); + for (DecompilerBlock block : decompilerBlocks) { + if (isReachable(b, block.getBlock(), new ArrayList())) { + result.add(block); + } + } + return result; + } + + private static boolean isReachable(Block from, Block to, ArrayList 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 list1, List list2) { + List list1Copy = new ArrayList<>(list1); + List list2Copy = new ArrayList<>(list2); + + list1.removeAll(list2Copy); + list2.removeAll(list1Copy); + } +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/DecompilerLoopSimplify.java --- /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 apply(List cfgBlocks) { + List 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; + } +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/DecompilerPhiRemover.java --- /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 decompilerBlocks) { + List blocks = collectAllBasicBlocks(decompilerBlocks); + for (DecompilerBasicBlock b : blocks) { + List removedLines = new ArrayList<>(); + Map 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 collectAllBasicBlocks(List blocks) { + List allBasicBlocks = new ArrayList<>(); + for (DecompilerBlock b : blocks) { + allBasicBlocks.addAll(b.getAllBasicBlocks()); + } + return allBasicBlocks; + } + + private static DecompilerBasicBlock getBlock(Node n, ControlFlowGraph cfg, List 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); + } + } +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/block/DecompilerBasicBlock.java --- /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 getSuccessors() { + return block.getSuccessors(); + } + + @Override + public boolean contains(Block b) { + return b == block; + } + + public List getCode() { + return code; + } + + @Override + public List getAllBasicBlocks() { + return Arrays.asList(new DecompilerBasicBlock[]{this}); + } +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/block/DecompilerBlock.java --- /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 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 getAllBasicBlocks(); + + @Override + public abstract String toString(); + + protected void initCode(SchedulePhase schedule) { + List 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); + } +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/block/DecompilerIfBlock.java --- /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 thenBranch; + private List elseBranch; + private final DecompilerBasicBlock head; + private final PrintStream infoStream; + + public DecompilerIfBlock(Block block, Decompiler decompiler, List thenBranch, List 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 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 getAllBasicBlocks() { + List blocks = new ArrayList<>(); + blocks.add(head); + for (DecompilerBlock b : thenBranch) { + blocks.addAll(b.getAllBasicBlocks()); + } + for (DecompilerBlock b : elseBranch) { + blocks.addAll(b.getAllBasicBlocks()); + } + return blocks; + } + +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/block/DecompilerLoopBlock.java --- /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 body; + private List 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 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 getAllBasicBlocks() { + List blocks = new ArrayList<>(); + for (DecompilerBlock b : decompilerBlockBody) { + blocks.addAll(b.getAllBasicBlocks()); + } + return blocks; + } + +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerAssignmentLine.java --- /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(); + } +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerControlSplitLine.java --- /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; + } +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerIfLine.java --- /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; + } +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerPhiLine.java --- /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(); + } +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerPhiResolveLine.java --- /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(); + } + +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerProxyLine.java --- /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); + } + +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerReturnLine.java --- /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); + } + +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.java.decompiler/src/com/oracle/graal/java/decompiler/lines/DecompilerSyntaxLine.java --- /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"; + } + } + +} diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.phases/src/com/oracle/graal/phases/GraalOptions.java --- 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 ExitVMOnException = new OptionValue<>(true); @Option(help = "") public static final OptionValue PrintStackTraceOnException = new OptionValue<>(false); + @Option(help = "Sets a phase after which the decompiler dumps the graph, -G:Dump= required") + public static final OptionValue DecompileAfterPhase = new OptionValue<>(null); // HotSpot command line options @Option(help = "") @@ -308,6 +310,7 @@ public static final OptionValue IntrinsifyInstalledCodeMethods = new OptionValue<>(true); @Option(help = "") public static final OptionValue IntrinsifyCallSiteTarget = new OptionValue<>(true); + /** * Counts the various paths taken through snippets. */ diff -r 29e9a5d18c70 -r 3e34b0318de6 graal/com.oracle.graal.printer/src/com/oracle/graal/printer/DebugEnvironment.java --- 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); } diff -r 29e9a5d18c70 -r 3e34b0318de6 mx/projects --- 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