changeset 7312:46f945023189

Merge.
author Thomas Wuerthinger <thomas.wuerthinger@oracle.com>
date Fri, 21 Dec 2012 15:54:59 +0100
parents 3fda7128589e (diff) a81db08fe930 (current diff)
children 570d8e4c6dfb
files graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java src/share/vm/graal/graalCompilerToVM.cpp
diffstat 26 files changed, 403 insertions(+), 90 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/LineNumberTable.java	Fri Dec 21 15:54:59 2012 +0100
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2011, 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.api.meta;
+
+
+public interface LineNumberTable {
+    int[] getLineNumberEntries();
+    int[] getBciEntries();
+    int getLineNumber(int bci);
+}
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaMethod.java	Fri Dec 21 15:54:59 2012 +0100
@@ -24,6 +24,7 @@
 
 import java.lang.annotation.*;
 import java.lang.reflect.*;
+import java.lang.reflect.Method;
 import java.util.*;
 
 /**
@@ -159,4 +160,10 @@
      * Returns {@code true} if this method can be inlined.
      */
     boolean canBeInlined();
+
+
+    /**
+     * Returns the LineNumberTable of this method.
+     */
+    LineNumberTable getLineNumberTable();
 }
--- a/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.api.meta/src/com/oracle/graal/api/meta/ResolvedJavaType.java	Fri Dec 21 15:54:59 2012 +0100
@@ -241,4 +241,9 @@
      * @return the field with the given offset, or {@code null} if there is no such field.
      */
     ResolvedJavaField findInstanceFieldWithOffset(long offset);
+
+    /**
+     * Returns name of source file of this type.
+     */
+    String getSourceFileName();
 }
--- a/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.compiler/src/com/oracle/graal/compiler/GraalCompiler.java	Fri Dec 21 15:54:59 2012 +0100
@@ -168,7 +168,7 @@
         if (GraalOptions.OptFloatingReads) {
             int mark = graph.getMark();
             new FloatingReadPhase().apply(graph);
-            new CanonicalizerPhase(target, runtime, assumptions, mark).apply(graph);
+            new CanonicalizerPhase(target, runtime, assumptions, mark, null).apply(graph);
             if (GraalOptions.OptReadElimination) {
                 new ReadEliminationPhase().apply(graph);
             }
@@ -228,6 +228,7 @@
 
             }
         });
+
     }
 
     public FrameMap emitLIR(final LIR lir, StructuredGraph graph, final ResolvedJavaMethod method) {
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVM.java	Fri Dec 21 15:54:59 2012 +0100
@@ -200,4 +200,10 @@
     long[] getDeoptedLeafGraphIds();
 
     String decodePC(long pc);
+
+
+    long[] getLineNumberTable(HotSpotResolvedJavaMethod method);
+
+
+    String getFileName(HotSpotResolvedJavaType method);
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/bridge/CompilerToVMImpl.java	Fri Dec 21 15:54:59 2012 +0100
@@ -142,4 +142,10 @@
 
     @Override
     public native String decodePC(long pc);
+
+    @Override
+    public native long[] getLineNumberTable(HotSpotResolvedJavaMethod method);
+
+    @Override
+    public native String getFileName(HotSpotResolvedJavaType method);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/debug/LineNumberTableImpl.java	Fri Dec 21 15:54:59 2012 +0100
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011, 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.hotspot.debug;
+
+import com.oracle.graal.api.meta.*;
+
+
+public class LineNumberTableImpl implements LineNumberTable {
+    private final int[] lineNumbers;
+    private final int[] bci;
+
+    public LineNumberTableImpl(int[] lineNumbers, int[] bci) {
+        this.lineNumbers = lineNumbers;
+        this.bci = bci;
+    }
+
+    @Override
+    public int[] getLineNumberEntries() {
+        return lineNumbers;
+    }
+
+    @Override
+    public int[] getBciEntries() {
+        return bci;
+    }
+
+    @Override
+    public int getLineNumber(@SuppressWarnings("hiding") int bci) {
+        for (int i = 0; i < this.bci.length - 1; i++) {
+            if (this.bci[i] <= bci && bci < this.bci[i + 1]) {
+                return lineNumbers[i];
+            }
+        }
+        return lineNumbers[lineNumbers.length - 1];
+    }
+}
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod.java	Fri Dec 21 15:54:59 2012 +0100
@@ -34,6 +34,7 @@
 import com.oracle.graal.api.meta.ProfilingInfo.ExceptionSeen;
 import com.oracle.graal.bytecode.*;
 import com.oracle.graal.hotspot.*;
+import com.oracle.graal.hotspot.debug.*;
 import com.oracle.graal.phases.*;
 
 /**
@@ -290,6 +291,21 @@
         return HotSpotGraalRuntime.getInstance().getCompilerToVM().isMethodCompilable(metaspaceMethod);
     }
 
+    @Override
+    public LineNumberTable getLineNumberTable() {
+        long[] values = HotSpotGraalRuntime.getInstance().getCompilerToVM().getLineNumberTable(this);
+        assert values.length % 2 == 0;
+        int[] bci = new int[values.length / 2];
+        int[] line = new int[values.length / 2];
+
+        for (int i = 0; i < values.length / 2; i++) {
+            bci[i] = (int) values[i * 2];
+            line[i] = (int) values[i * 2 + 1];
+        }
+
+        return new LineNumberTableImpl(line, bci);
+    }
+
     /**
      * Returns the offset of this method into the v-table.
      * If the holder is not initialized, returns -1
@@ -309,4 +325,5 @@
     public CompilationTask currentTask() {
         return currentTask;
     }
+
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaType.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedJavaType.java	Fri Dec 21 15:54:59 2012 +0100
@@ -23,6 +23,7 @@
 package com.oracle.graal.hotspot.meta;
 
 import com.oracle.graal.api.meta.*;
+import com.oracle.graal.hotspot.*;
 
 
 public abstract class HotSpotResolvedJavaType extends HotSpotJavaType implements ResolvedJavaType {
@@ -33,4 +34,9 @@
     }
 
     public abstract Class<?> mirror();
+
+    @Override
+    public String getSourceFileName() {
+       return HotSpotGraalRuntime.getInstance().getCompilerToVM().getFileName(this);
+    }
 }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedObjectType.java	Fri Dec 21 15:54:59 2012 +0100
@@ -446,6 +446,11 @@
     }
 
     @Override
+    public String getSourceFileName() {
+       return HotSpotGraalRuntime.getInstance().getCompilerToVM().getFileName(this);
+    }
+
+    @Override
     public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
         return javaMirror.getAnnotation(annotationClass);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/meta/HotSpotResolvedPrimitiveType.java	Fri Dec 21 15:54:59 2012 +0100
@@ -181,7 +181,12 @@
     }
 
     @Override
-    public Class<?> mirror() {
+    public String getSourceFileName() {
+        throw GraalInternalError.shouldNotReachHere();
+    }
+
+    @Override
+    public Class< ? > mirror() {
         return javaMirror;
     }
 }
--- a/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.loop/src/com/oracle/graal/loop/LoopTransformations.java	Fri Dec 21 15:54:59 2012 +0100
@@ -60,7 +60,7 @@
         while (!loopBegin.isDeleted()) {
             int mark = graph.getMark();
             peel(loop);
-            new CanonicalizerPhase(null, runtime, assumptions, mark).apply(graph);
+            new CanonicalizerPhase(null, runtime, assumptions, mark, null).apply(graph);
             if (iterations++ > UNROLL_LIMIT || graph.getNodeCount() > GraalOptions.MaximumDesiredSize * 3) {
                 throw new BailoutException("FullUnroll : Graph seems to grow out of proportion");
             }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/extended/BoxNode.java	Fri Dec 21 15:54:59 2012 +0100
@@ -65,6 +65,33 @@
 
     @Override
     public ValueNode canonical(CanonicalizerTool tool) {
+
+        if (source.isConstant()) {
+            Constant sourceConstant = source.asConstant();
+            switch (sourceKind) {
+                case Boolean:
+                    return ConstantNode.forObject(Boolean.valueOf(sourceConstant.asBoolean()), tool.runtime(), graph());
+                case Byte:
+                    return ConstantNode.forObject(Byte.valueOf((byte) sourceConstant.asInt()), tool.runtime(), graph());
+                case Char:
+                    return ConstantNode.forObject(Character.valueOf((char) sourceConstant.asInt()), tool.runtime(), graph());
+                case Short:
+                    return ConstantNode.forObject(Short.valueOf((short) sourceConstant.asInt()), tool.runtime(), graph());
+                case Int:
+                    return ConstantNode.forObject(Integer.valueOf(sourceConstant.asInt()), tool.runtime(), graph());
+                case Long:
+                    return ConstantNode.forObject(Long.valueOf(sourceConstant.asLong()), tool.runtime(), graph());
+                case Float:
+                    return ConstantNode.forObject(Float.valueOf(sourceConstant.asFloat()), tool.runtime(), graph());
+                case Double:
+                    return ConstantNode.forObject(Double.valueOf(sourceConstant.asDouble()), tool.runtime(), graph());
+                default:
+                    assert false : "Unexpected source kind for boxing";
+                    break;
+
+            }
+        }
+
         for (Node usage : usages()) {
             if (usage != stateAfter()) {
                 return this;
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/MethodCallTargetNode.java	Fri Dec 21 15:54:59 2012 +0100
@@ -148,4 +148,13 @@
         }
         return targetMethod().getName();
     }
+
+    public static MethodCallTargetNode find(StructuredGraph graph, ResolvedJavaMethod method) {
+        for (MethodCallTargetNode target : graph.getNodes(MethodCallTargetNode.class)) {
+            if (target.targetMethod == method) {
+                return target;
+            }
+        }
+        return null;
+    }
 }
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/util/GraphUtil.java	Fri Dec 21 15:54:59 2012 +0100
@@ -186,30 +186,67 @@
     /**
      * Gets an approximate source code location for a node if possible.
      *
-     * @return a file name and source line number in stack trace format (e.g. "String.java:32")
-     *          if an approximate source location is found, null otherwise
+     * @return the StackTraceElements if an approximate source location is found, null otherwise
      */
-    public static String approxSourceLocation(Node node) {
+    public static StackTraceElement[] approxSourceStackTraceElement(Node node) {
+        ArrayList<StackTraceElement> elements = new ArrayList<>();
         Node n = node;
         while (n != null) {
             if (n instanceof MethodCallTargetNode) {
+                elements.add(((MethodCallTargetNode) n).targetMethod().asStackTraceElement(-1));
                 n = ((MethodCallTargetNode) n).invoke().node();
             }
 
             if (n instanceof StateSplit) {
-                FrameState stateAfter = ((StateSplit) n).stateAfter();
-                if (stateAfter != null) {
-                    ResolvedJavaMethod method = stateAfter.method();
+                FrameState state = ((StateSplit) n).stateAfter();
+                while (state != null) {
+                    ResolvedJavaMethod method = state.method();
                     if (method != null) {
-                        StackTraceElement stackTraceElement = method.asStackTraceElement(stateAfter.bci);
-                        if (stackTraceElement.getFileName() != null && stackTraceElement.getLineNumber() >= 0) {
-                            return stackTraceElement.getFileName() + ":" + stackTraceElement.getLineNumber();
-                        }
+                        elements.add(method.asStackTraceElement(state.bci - 1));
                     }
+                    state = state.outerFrameState();
                 }
+                break;
             }
             n = n.predecessor();
         }
+        return elements.toArray(new StackTraceElement[elements.size()]);
+    }
+
+
+    /**
+     * Gets an approximate source code location for a node, encoded as an exception, if possible.
+     *
+     * @return the exception with the location
+     */
+    public static RuntimeException approxSourceException(Node node, Throwable cause) {
+        final StackTraceElement[] elements = approxSourceStackTraceElement(node);
+        @SuppressWarnings("serial")
+        RuntimeException exception = new RuntimeException(cause.getMessage(), cause) {
+
+            @Override
+            public synchronized Throwable fillInStackTrace() {
+                setStackTrace(elements);
+                return this;
+            }
+        };
+        return exception;
+    }
+
+    /**
+     * Gets an approximate source code location for a node if possible.
+     *
+     * @return a file name and source line number in stack trace format (e.g. "String.java:32") if an approximate source
+     *         location is found, null otherwise
+     */
+    public static String approxSourceLocation(Node node) {
+        StackTraceElement[] stackTraceElements = approxSourceStackTraceElement(node);
+        if (stackTraceElements != null && stackTraceElements.length > 0) {
+            StackTraceElement top = stackTraceElements[0];
+            if (top.getFileName() != null && top.getLineNumber() >= 0) {
+                return top.getFileName() + ":" + top.getLineNumber();
+            }
+        }
         return null;
     }
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/CanonicalizerPhase.java	Fri Dec 21 15:54:59 2012 +0100
@@ -50,14 +50,19 @@
     private final TargetDescription target;
     private final Assumptions assumptions;
     private final MetaAccessProvider runtime;
+    private final CustomCanonicalizer customCanonicalizer;
     private final Iterable<Node> initWorkingSet;
 
     private NodeWorkList workList;
     private Tool tool;
     private List<Node> snapshotTemp;
 
+    public interface CustomCanonicalizer {
+        ValueNode canonicalize(Node node);
+    }
+
     public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions) {
-        this(target, runtime, assumptions, null, 0);
+        this(target, runtime, assumptions, null, 0, null);
     }
 
     /**
@@ -65,24 +70,26 @@
      * @param runtime
      * @param assumptions
      * @param workingSet the initial working set of nodes on which the canonicalizer works, should be an auto-grow node bitmap
+     * @param customCanonicalizer
      */
-    public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, Iterable<Node> workingSet) {
-        this(target, runtime, assumptions, workingSet, 0);
+    public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, Iterable<Node> workingSet, CustomCanonicalizer customCanonicalizer) {
+        this(target, runtime, assumptions, workingSet, 0, customCanonicalizer);
     }
 
     /**
      * @param newNodesMark only the {@linkplain Graph#getNewNodes(int) new nodes} specified by
      *            this mark are processed otherwise all nodes in the graph are processed
      */
-    public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, int newNodesMark) {
-        this(target, runtime, assumptions, null, newNodesMark);
+    public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, int newNodesMark, CustomCanonicalizer customCanonicalizer) {
+        this(target, runtime, assumptions, null, newNodesMark, customCanonicalizer);
     }
 
-    public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, Iterable<Node> workingSet, int newNodesMark) {
+    public CanonicalizerPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, Iterable<Node> workingSet, int newNodesMark, CustomCanonicalizer customCanonicalizer) {
         this.newNodesMark = newNodesMark;
         this.target = target;
         this.assumptions = assumptions;
         this.runtime = runtime;
+        this.customCanonicalizer = customCanonicalizer;
         this.initWorkingSet = workingSet;
         this.snapshotTemp = new ArrayList<>();
     }
@@ -111,13 +118,15 @@
         });
 
         for (Node n : workList) {
-            processNode(n, graph);
+            if (n instanceof ValueNode) {
+                processNode((ValueNode) n, graph);
+            }
         }
 
         graph.stopTrackingInputChange();
     }
 
-    private void processNode(Node node, StructuredGraph graph) {
+    private void processNode(ValueNode node, StructuredGraph graph) {
         if (node.isAlive()) {
             METRIC_PROCESSED_NODES.increment();
 
@@ -127,7 +136,7 @@
             int mark = graph.getMark();
             if (!tryKillUnused(node)) {
                 node.inputs().filter(GraphUtil.isFloatingNode()).snapshotTo(snapshotTemp);
-                if (!tryCanonicalize(node, graph, tool)) {
+                if (!tryCanonicalize(node, graph)) {
                     tryInferStamp(node, graph);
                 } else {
                     for (Node in : snapshotTemp) {
@@ -168,7 +177,19 @@
         return false;
     }
 
-    public static boolean tryCanonicalize(final Node node, final StructuredGraph graph, final SimplifierTool tool) {
+    public boolean tryCanonicalize(final ValueNode node, final StructuredGraph graph) {
+        boolean result = baseTryCanonicalize(node, graph);
+        if (!result && customCanonicalizer != null) {
+            ValueNode canonical = customCanonicalizer.canonicalize(node);
+            if (canonical == node && customCanonicalizer != null) {
+                canonical = customCanonicalizer.canonicalize(node);
+            }
+            result = performReplacement(node, graph, canonical);
+        }
+        return result;
+    }
+
+    public boolean baseTryCanonicalize(final Node node, final StructuredGraph graph) {
         if (node instanceof Canonicalizable) {
             assert !(node instanceof Simplifiable);
             METRIC_CANONICALIZATION_CONSIDERED_NODES.increment();
@@ -187,52 +208,9 @@
 //                          Fixed-connected|   2    |        X        |       6       |
 //                                         --------------------------------------------
 //       X: must not happen (checked with assertions)
-                    if (canonical == node) {
-                        Debug.log("Canonicalizer: work on %s", node);
-                        return false;
-                    } else {
-                        Debug.log("Canonicalizer: replacing %s with %s", node, canonical);
-                        METRIC_CANONICALIZED_NODES.increment();
-                        if (node instanceof FloatingNode) {
-                            if (canonical == null) {
-                                // case 1
-                                graph.removeFloating((FloatingNode) node);
-                            } else {
-                                // case 2
-                                assert !(canonical instanceof FixedNode) || (canonical.predecessor() != null || canonical instanceof StartNode || canonical instanceof MergeNode) : node + " -> " + canonical +
-                                                " : replacement should be floating or fixed and connected";
-                                graph.replaceFloating((FloatingNode) node, canonical);
-                            }
-                        } else {
-                            assert node instanceof FixedWithNextNode && node.predecessor() != null : node + " -> " + canonical + " : node should be fixed & connected (" + node.predecessor() + ")";
-                            FixedWithNextNode fixedWithNext = (FixedWithNextNode) node;
+
 
-                            // When removing a fixed node, new canonicalization opportunities for its successor may arise
-                            assert fixedWithNext.next() != null;
-                            tool.addToWorkList(fixedWithNext.next());
-
-                            if (canonical == null) {
-                                // case 3
-                                graph.removeFixed(fixedWithNext);
-                            } else if (canonical instanceof FloatingNode) {
-                                // case 4
-                                graph.replaceFixedWithFloating(fixedWithNext, (FloatingNode) canonical);
-                            } else {
-                                assert canonical instanceof FixedNode;
-                                if (canonical.predecessor() == null) {
-                                    assert !canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " shouldn't have successors";
-                                    // case 5
-                                    graph.replaceFixedWithFixed(fixedWithNext, (FixedWithNextNode) canonical);
-                                } else {
-                                    assert canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " should have successors";
-                                    // case 6
-                                    node.replaceAtUsages(canonical);
-                                    graph.removeFixed(fixedWithNext);
-                                }
-                            }
-                        }
-                        return true;
-                    }
+                    return performReplacement(node, graph, canonical);
                 }
             });
         } else if (node instanceof Simplifiable) {
@@ -247,6 +225,55 @@
         return node.isDeleted();
     }
 
+    private boolean performReplacement(final Node node, final StructuredGraph graph, ValueNode canonical) {
+        if (canonical == node) {
+            Debug.log("Canonicalizer: work on %s", node);
+            return false;
+        } else {
+            Debug.log("Canonicalizer: replacing %s with %s", node, canonical);
+            METRIC_CANONICALIZED_NODES.increment();
+            if (node instanceof FloatingNode) {
+                if (canonical == null) {
+                    // case 1
+                    graph.removeFloating((FloatingNode) node);
+                } else {
+                    // case 2
+                    assert !(canonical instanceof FixedNode) || (canonical.predecessor() != null || canonical instanceof StartNode || canonical instanceof MergeNode) : node + " -> " + canonical +
+                                    " : replacement should be floating or fixed and connected";
+                    graph.replaceFloating((FloatingNode) node, canonical);
+                }
+            } else {
+                assert node instanceof FixedWithNextNode && node.predecessor() != null : node + " -> " + canonical + " : node should be fixed & connected (" + node.predecessor() + ")";
+                FixedWithNextNode fixedWithNext = (FixedWithNextNode) node;
+
+                // When removing a fixed node, new canonicalization opportunities for its successor may arise
+                assert fixedWithNext.next() != null;
+                tool.addToWorkList(fixedWithNext.next());
+
+                if (canonical == null) {
+                    // case 3
+                    graph.removeFixed(fixedWithNext);
+                } else if (canonical instanceof FloatingNode) {
+                    // case 4
+                    graph.replaceFixedWithFloating(fixedWithNext, (FloatingNode) canonical);
+                } else {
+                    assert canonical instanceof FixedNode;
+                    if (canonical.predecessor() == null) {
+                        assert !canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " shouldn't have successors";
+                        // case 5
+                        graph.replaceFixedWithFixed(fixedWithNext, (FixedWithNextNode) canonical);
+                    } else {
+                        assert canonical.cfgSuccessors().iterator().hasNext() : "replacement " + canonical + " should have successors";
+                        // case 6
+                        node.replaceAtUsages(canonical);
+                        graph.removeFixed(fixedWithNext);
+                    }
+                }
+            }
+            return true;
+        }
+    }
+
     /**
      * Calls {@link ValueNode#inferStamp()} on the node and, if it returns true (which means that the stamp has
      * changed), re-queues the node's usages . If the stamp has changed then this method also checks if the stamp
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningPhase.java	Fri Dec 21 15:54:59 2012 +0100
@@ -32,11 +32,9 @@
 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.common.InliningUtil.InlineInfo;
-import com.oracle.graal.phases.common.InliningUtil.InliningCallback;
-import com.oracle.graal.phases.common.InliningUtil.InliningPolicy;
-import com.oracle.graal.phases.common.InliningUtil.WeightComputationPolicy;
+import com.oracle.graal.phases.PhasePlan.*;
+import com.oracle.graal.phases.common.CanonicalizerPhase.CustomCanonicalizer;
+import com.oracle.graal.phases.common.InliningUtil.*;
 
 public class InliningPhase extends Phase implements InliningCallback {
     /*
@@ -52,6 +50,7 @@
     private final Assumptions assumptions;
     private final GraphCache cache;
     private final InliningPolicy inliningPolicy;
+    private CustomCanonicalizer customCanonicalizer;
 
     // Metrics
     private static final DebugMetric metricInliningPerformed = Debug.metric("InliningPerformed");
@@ -63,6 +62,10 @@
         this(target, runtime, assumptions, cache, plan, createInliningPolicy(assumptions, optimisticOpts, hints));
     }
 
+    public void setCustomCanonicalizer(CustomCanonicalizer customCanonicalizer) {
+        this.customCanonicalizer = customCanonicalizer;
+    }
+
     public InliningPhase(TargetDescription target, GraalCodeCacheProvider runtime, Assumptions assumptions, GraphCache cache, PhasePlan plan, InliningPolicy inliningPolicy) {
         this.target = target;
         this.runtime = runtime;
@@ -90,7 +93,7 @@
                         Debug.dump(graph, "after %s", candidate);
                         Iterable<Node> newNodes = graph.getNewNodes(mark);
                         if (GraalOptions.OptCanonicalizer) {
-                            new CanonicalizerPhase(target, runtime, assumptions, invokeUsages, mark).apply(graph);
+                            new CanonicalizerPhase(target, runtime, assumptions, invokeUsages, mark, customCanonicalizer).apply(graph);
                         }
                         metricInliningPerformed.increment();
 
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/InliningUtil.java	Fri Dec 21 15:54:59 2012 +0100
@@ -886,7 +886,7 @@
      * @param inlineGraph the graph that the invoke will be replaced with
      * @param receiverNullCheck true if a null check needs to be generated for non-static inlinings, false if no such check is required
      */
-    public static void inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
+    public static Map<Node, Node> inline(Invoke invoke, StructuredGraph inlineGraph, boolean receiverNullCheck) {
         NodeInputList<ValueNode> parameters = invoke.callTarget().arguments();
         StructuredGraph graph = (StructuredGraph) invoke.node().graph();
 
@@ -915,7 +915,7 @@
                 }
             }
         }
-        replacements.put(entryPointNode, BeginNode.prevBegin(invoke.node())); // ensure proper anchoring of things that where anchored to the StartNode
+        replacements.put(entryPointNode, BeginNode.prevBegin(invoke.node())); // ensure proper anchoring of things that were anchored to the StartNode
 
         assert invoke.node().successors().first() != null : invoke;
         assert invoke.node().predecessor() != null;
@@ -1018,6 +1018,8 @@
 
         invoke.node().replaceAtUsages(null);
         GraphUtil.killCFG(invoke.node());
+
+        return duplicates;
     }
 
     public static void receiverNullCheck(Invoke invoke) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/IterativeConditionalEliminationPhase.java	Fri Dec 21 15:54:59 2012 +0100
@@ -55,7 +55,7 @@
             if (canonicalizationRoots.isEmpty()) {
                 break;
             }
-            new CanonicalizerPhase(target, runtime, assumptions, canonicalizationRoots).apply(graph);
+            new CanonicalizerPhase(target, runtime, assumptions, canonicalizationRoots, null).apply(graph);
             canonicalizationRoots.clear();
         }
     }
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/LoweringPhase.java	Fri Dec 21 15:54:59 2012 +0100
@@ -132,7 +132,7 @@
             deferred = false;
             processBlock(schedule.getCFG().getStartBlock(), graph.createNodeBitMap(), null, schedule, processed);
             Debug.dump(graph, "Lowering iteration %d", i++);
-            new CanonicalizerPhase(null, runtime, assumptions, mark).apply(graph);
+            new CanonicalizerPhase(null, runtime, assumptions, mark, null).apply(graph);
 
             if (!deferred && !containsLowerable(graph.getNewNodes(mark))) {
                 // No new lowerable nodes - done!
--- a/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.snippets/src/com/oracle/graal/snippets/SnippetTemplate.java	Fri Dec 21 15:54:59 2012 +0100
@@ -280,7 +280,7 @@
             new SnippetIntrinsificationPhase(runtime, new BoxingMethodPool(runtime), false).apply(snippetCopy);
             new WordTypeRewriterPhase(target.wordKind).apply(snippetCopy);
 
-            new CanonicalizerPhase(null, runtime, assumptions, 0).apply(snippetCopy);
+            new CanonicalizerPhase(null, runtime, assumptions, 0, null).apply(snippetCopy);
         }
 
         // Gather the template parameters
@@ -338,7 +338,7 @@
                     LoopEx loop = new LoopsData(snippetCopy).loop(loopBegin);
                     int mark = snippetCopy.getMark();
                     LoopTransformations.fullUnroll(loop, runtime, null);
-                    new CanonicalizerPhase(null, runtime, assumptions, mark).apply(snippetCopy);
+                    new CanonicalizerPhase(null, runtime, assumptions, mark, null).apply(snippetCopy);
                 }
                 FixedNode explodeLoopNext = explodeLoop.next();
                 explodeLoop.clearSuccessors();
--- a/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.graal.virtual/src/com/oracle/graal/virtual/phases/ea/PartialEscapeAnalysisPhase.java	Fri Dec 21 15:54:59 2012 +0100
@@ -33,6 +33,7 @@
 import com.oracle.graal.nodes.spi.*;
 import com.oracle.graal.phases.*;
 import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.CanonicalizerPhase.*;
 import com.oracle.graal.phases.graph.*;
 import com.oracle.graal.phases.schedule.*;
 import com.oracle.graal.virtual.phases.ea.EffectList.Effect;
@@ -42,6 +43,7 @@
     private final TargetDescription target;
     private final MetaAccessProvider runtime;
     private final Assumptions assumptions;
+    private CustomCanonicalizer customCanonicalizer;
     private final boolean iterative;
 
     public PartialEscapeAnalysisPhase(TargetDescription target, MetaAccessProvider runtime, Assumptions assumptions, boolean iterative) {
@@ -51,6 +53,10 @@
         this.iterative = iterative;
     }
 
+    public void setCustomCanonicalizer(CustomCanonicalizer customCanonicalizer) {
+        this.customCanonicalizer = customCanonicalizer;
+    }
+
     public static final void trace(String format, Object... obj) {
         if (GraalOptions.TraceEscapeAnalysis) {
             Debug.log(format, obj);
@@ -108,7 +114,7 @@
                         return false;
                     }
                     if (GraalOptions.OptCanonicalizer) {
-                        new CanonicalizerPhase(target, runtime, assumptions).apply(graph);
+                        new CanonicalizerPhase(target, runtime, assumptions, null, customCanonicalizer).apply(graph);
                     }
                     return true;
                 }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultCallTarget.java	Fri Dec 21 15:54:59 2012 +0100
@@ -26,12 +26,12 @@
 import com.oracle.truffle.api.frame.*;
 import com.oracle.truffle.api.nodes.*;
 
-final class DefaultCallTarget extends CallTarget {
+public class DefaultCallTarget extends CallTarget {
 
     protected final RootNode rootNode;
     protected final FrameDescriptor frameDescriptor;
 
-    DefaultCallTarget(RootNode function, FrameDescriptor frameDescriptor) {
+    protected DefaultCallTarget(RootNode function, FrameDescriptor frameDescriptor) {
         this.rootNode = function;
         this.frameDescriptor = frameDescriptor;
     }
--- a/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java	Fri Dec 21 10:21:24 2012 +0100
+++ b/graal/com.oracle.truffle.api/src/com/oracle/truffle/api/impl/DefaultVirtualFrame.java	Fri Dec 21 15:54:59 2012 +0100
@@ -27,7 +27,7 @@
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.frame.*;
 
-final class DefaultVirtualFrame implements VirtualFrame {
+public final class DefaultVirtualFrame implements VirtualFrame {
 
     private static final Object UNDEFINED_OBJECT = null;
     private static final Boolean UNDEFINED_BOOLEAN = false;
@@ -43,7 +43,7 @@
     protected Object[] locals;
     protected Class[] tags;
 
-    DefaultVirtualFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments arguments) {
+    public DefaultVirtualFrame(FrameDescriptor descriptor, PackedFrame caller, Arguments arguments) {
         this.descriptor = descriptor;
         this.caller = caller;
         this.arguments = arguments;
--- a/src/cpu/x86/vm/jniTypes_x86.hpp	Fri Dec 21 10:21:24 2012 +0100
+++ b/src/cpu/x86/vm/jniTypes_x86.hpp	Fri Dec 21 15:54:59 2012 +0100
@@ -128,11 +128,25 @@
   static inline jfloat  get_float (intptr_t *from) { return *(jfloat *) from; }
   static inline jdouble get_double(intptr_t *from) { return *(jdouble *)(from + _JNI_SLOT_OFFSET); }
 
-  static inline jint    get_int   (intptr_t *from, int& pos) { return get_int(from + pos++); }
-  static inline jlong   get_long  (intptr_t *from, int& pos) { return get_long(from + pos); pos += 2; }
-  static inline oop     get_obj   (intptr_t *from, int& pos) { return get_obj(from + pos++); }
-  static inline jfloat  get_float (intptr_t *from, int& pos) { return get_float(from + pos++); }
-  static inline jdouble get_double(intptr_t *from, int& pos) { return get_double(from + pos); pos += 2; }
+  static inline jint    get_int   (intptr_t *from, int& pos) {
+    return get_int(from + pos++);
+  }
+  static inline jlong   get_long  (intptr_t *from, int& pos) {
+    jlong result = get_long(from + pos);
+    pos += 2;
+    return result;
+  }
+  static inline oop     get_obj   (intptr_t *from, int& pos) {
+    return get_obj(from + pos++);
+  }
+  static inline jfloat  get_float (intptr_t *from, int& pos) {
+    return get_float(from + pos++);
+  }
+  static inline jdouble get_double(intptr_t *from, int& pos) {
+    jdouble result = get_double(from + pos);
+    pos += 2;
+    return result;
+  }
 #undef _JNI_SLOT_OFFSET
 };
 
--- a/src/share/vm/graal/graalCompilerToVM.cpp	Fri Dec 21 10:21:24 2012 +0100
+++ b/src/share/vm/graal/graalCompilerToVM.cpp	Fri Dec 21 15:54:59 2012 +0100
@@ -938,6 +938,47 @@
   return JNIHandles::make_local(result());
 C2V_END
 
+C2V_ENTRY(jlongArray, getLineNumberTable, (JNIEnv *env, jobject, jobject hotspot_method))
+// XXX: Attention: it seEms that the line number table of a method just contains lines that are important, means that
+// empty lines are left out or lines that can't have a breakpoint on it; eg int a; or try {
+  Method* method = getMethodFromHotSpotMethod(JNIHandles::resolve(hotspot_method));
+  if(!method->has_linenumber_table()) {
+    return NULL;
+  }
+  u2 num_entries = 0;
+  CompressedLineNumberReadStream streamForSize(method->compressed_linenumber_table());
+  while (streamForSize.read_pair()) {
+    num_entries++;
+  }
+
+  CompressedLineNumberReadStream stream(method->compressed_linenumber_table());
+  jlongArray result = env->NewLongArray(2 * num_entries);
+
+  int i = 0;
+  jlong value;
+  while (stream.read_pair()) {
+    value = ((long) stream.bci());
+    env->SetLongArrayRegion(result,i,1,&value);
+    value = ((long) stream.line());
+    env->SetLongArrayRegion(result,i + 1,1,&value);
+    i += 2;
+  }
+
+  return result;
+C2V_END
+
+
+C2V_VMENTRY(jobject, getFileName, (JNIEnv *, jobject, jobject klass))
+  ResourceMark rm;
+  InstanceKlass* k = (InstanceKlass*) asKlass(HotSpotResolvedObjectType::metaspaceKlass(klass));
+  Symbol *s = k->source_file_name();
+  int length;
+  jchar *name = s->as_unicode(length);
+
+  Handle result = java_lang_String::create_from_unicode(name, length, CHECK_NULL);
+  return JNIHandles::make_local(result());
+
+C2V_END
 
 #define CC (char*)  /*cast a literal from (const char*)*/
 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f))
@@ -960,6 +1001,7 @@
 #define CLASS                 "Ljava/lang/Class;"
 #define STACK_TRACE_ELEMENT   "Ljava/lang/StackTraceElement;"
 #define HS_RESOLVED_TYPE      "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedObjectType;"
+#define HS_RESOLVED_JAVA_TYPE "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaType;"
 #define HS_RESOLVED_METHOD    "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaMethod;"
 #define HS_RESOLVED_FIELD     "Lcom/oracle/graal/hotspot/meta/HotSpotResolvedJavaField;"
 #define HS_COMP_RESULT        "Lcom/oracle/graal/hotspot/HotSpotCompilationResult;"
@@ -1008,6 +1050,8 @@
   {CC"executeCompiledMethodVarargs",  CC"("METASPACE_METHOD NMETHOD "["OBJECT")"OBJECT,                 FN_PTR(executeCompiledMethodVarargs)},
   {CC"getDeoptedLeafGraphIds",        CC"()[J",                                                         FN_PTR(getDeoptedLeafGraphIds)},
   {CC"decodePC",                      CC"(J)"STRING,                                                    FN_PTR(decodePC)},
+  {CC"getLineNumberTable",            CC"("HS_RESOLVED_METHOD")[J",                                     FN_PTR(getLineNumberTable)},
+  {CC"getFileName",                   CC"("HS_RESOLVED_JAVA_TYPE")"STRING,                              FN_PTR(getFileName)},
 };
 
 int CompilerToVM_methods_count() {